pax_global_header00006660000000000000000000000064121621423250014510gustar00rootroot0000000000000052 comment=eddc1f1ed78898a4ca41480045b1d0d5b075e773 libgit2-0.19.0/000077500000000000000000000000001216214232500131335ustar00rootroot00000000000000libgit2-0.19.0/.HEADER000066400000000000000000000022211216214232500140610ustar00rootroot00000000000000/* * 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. */ libgit2-0.19.0/.gitattributes000066400000000000000000000000261216214232500160240ustar00rootroot00000000000000*.c eol=lf *.h eol=lf libgit2-0.19.0/.gitignore000066400000000000000000000005201216214232500151200ustar00rootroot00000000000000/tests-clar/clar.suite /tests-clar/clar.suite.rule /tests-clar/.clarcache /apidocs /trash-*.exe /libgit2.pc /config.mak *.o *.a *.exe *.gcda *.gcno *.gcov .lock-wafbuild .waf* build/ build-amiga/ tests/tmp/ msvc/Debug/ msvc/Release/ *.sln *.suo *.vc*proj* *.sdf *.opensdf *.aps *.cmake !cmake/Modules/*.cmake .DS_Store *~ tags mkmf.log libgit2-0.19.0/.mailmap000066400000000000000000000020511216214232500145520ustar00rootroot00000000000000Vicent Martí Vicent Marti Vicent Martí Vicent Martí Michael Schubert schu Ben Straub Ben Straub Ben Straub Ben Straub Carlos Martín Nieto Carlos Martín Nieto nulltoken Scott J. Goldman Martin Woodward Peter Drahoš Adam Roben Adam Roben Xavier L. Xavier L. Sascha Cunz Authmillenon Authmillenon libgit2-0.19.0/.travis.yml000066400000000000000000000030131216214232500152410ustar00rootroot00000000000000# Travis-CI Build for libgit2 # see travis-ci.org for details # As CMake is not officially supported we use erlang VMs language: c compiler: - gcc - clang # Settings to try env: - OPTIONS="-DTHREADSAFE=ON -DCMAKE_BUILD_TYPE=Release" - OPTIONS="-DBUILD_CLAR=ON -DBUILD_EXAMPLES=ON" matrix: include: - compiler: i586-mingw32msvc-gcc env: OPTIONS="-DBUILD_CLAR=OFF -DWIN32=ON -DMINGW=ON" # Make sure CMake is installed install: - sudo apt-get update >/dev/null - sudo apt-get -q install cmake valgrind # Run the Build script script: - mkdir _temp - git init --bare _temp/test.git - git daemon --listen=localhost --export-all --enable=receive-pack --base-path=_temp _temp 2>/dev/null & - export GITTEST_REMOTE_URL="git://localhost/test.git" - mkdir _build - cd _build - cmake .. -DCMAKE_INSTALL_PREFIX=../_install $OPTIONS - cmake --build . --target install - ctest -V . # Run Tests after_success: - valgrind --leak-check=full --show-reachable=yes --suppressions=../libgit2_clar.supp ./libgit2_clar -ionline # Only watch the development branch branches: only: - development # Notify development list when needed notifications: irc: channels: - irc.freenode.net#libgit2 on_success: change on_failure: always use_notice: true skip_join: true campfire: on_success: always on_failure: always rooms: - secure: "sH0dpPWMirbEe7AvLddZ2yOp8rzHalGmv0bYL/LIhVw3JDI589HCYckeLMSB\n3e/FeXw4bn0EqXWEXijVa4ijbilVY6d8oprdqMdWHEodng4KvY5vID3iZSGT\nxylhahO1XHmRynKQLOAvxlc93IlpVW38vQfby8giIY1nkpspb2w=" libgit2-0.19.0/AUTHORS000066400000000000000000000022371216214232500142070ustar00rootroot00000000000000The following people contribute or have contributed to the libgit2 project (sorted alphabetically): Alex Budovski Alexei Sholik Andreas Ericsson Anton "antong" Gyllenberg Ankur Sethi Ben Noordhuis Ben Straub Benjamin C Meyer Brian Downing Brian Lopez Carlos Martín Nieto Colin Timmermans Daniel Huckstep Dave Borowitz David Boyce David Glesser Dmitry Kakurin Dmitry Kovega Emeric Fermas Emmanuel Rodriguez Florian Forster Holger Weiss Ingmar Vanhassel J. David Ibáñez Jakob Pfender Jason Penny Jason R. McNeil Jerome Lambourg Johan 't Hart John Wiegley Jonathan "Duke" Leto Julien Miotte Julio Espinoza-Sokal Justin Love Kelly "kelly.leahy" Leahy Kirill A. Shutemov Lambert CLARA Luc Bertrand Marc Pegon Marcel Groothuis Marco Villegas Michael "schu" Schubert Microsoft Corporation Olivier Ramonat Peter Drahoš Pierre Habouzit Przemyslaw Pawelczyk Ramsay Jones Robert G. Jakabosky Romain Geissler Romain Muller Russell Belfer Sakari Jokinen Samuel Charles "Sam" Day Sarath Lakshman Sascha Cunz Sascha Peilicke Scott Chacon Sebastian Schuberth Sergey Nikishin Shawn O. Pearce Shuhei Tanuma Steve Frécinaux Sven Strickroth Tim Branyen Tim Clem Tim Harder Trent Mick Vicent Marti libgit2-0.19.0/CMakeLists.txt000066400000000000000000000342661216214232500157060ustar00rootroot00000000000000# CMake build script for the libgit2 project # # Building (out of source build): # > mkdir build && cd build # > cmake .. [-DSETTINGS=VALUE] # > cmake --build . # # Testing: # > ctest -V # # Install: # > cmake --build . --target install PROJECT(libgit2 C) CMAKE_MINIMUM_REQUIRED(VERSION 2.6) # Add find modules to the path SET(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/Modules/") # Build options # OPTION( SONAME "Set the (SO)VERSION of the target" ON ) OPTION( BUILD_SHARED_LIBS "Build Shared Library (OFF for Static)" ON ) OPTION( THREADSAFE "Build libgit2 as threadsafe" OFF ) OPTION( BUILD_CLAR "Build Tests using the Clar suite" ON ) OPTION( BUILD_EXAMPLES "Build library usage example apps" OFF ) OPTION( TAGS "Generate tags" OFF ) OPTION( PROFILE "Generate profiling information" OFF ) OPTION( ENABLE_TRACE "Enables tracing support" OFF ) OPTION( LIBGIT2_FILENAME "Name of the produced binary" OFF ) IF(MSVC) # This option is only availalbe when building with MSVC. By default, # libgit2 is build using the stdcall calling convention, as that's what # the CLR expects by default and how the Windows API is built. # # If you are writing a C or C++ program and want to link to libgit2, you # have to either: # - Add /Gz to the compiler options of _your_ program / library. # - Turn this off by invoking CMake with the "-DSTDCALL=Off" argument. # OPTION( STDCALL "Build libgit2 with the __stdcall convention" ON ) # This option must match the settings used in your program, in particular if you # are linking statically OPTION( STATIC_CRT "Link the static CRT libraries" ON ) ENDIF() # Installation paths # SET(BIN_INSTALL_DIR bin CACHE PATH "Where to install binaries to.") SET(LIB_INSTALL_DIR lib CACHE PATH "Where to install libraries to.") SET(INCLUDE_INSTALL_DIR include CACHE PATH "Where to install headers to.") FUNCTION(TARGET_OS_LIBRARIES target) IF(WIN32) TARGET_LINK_LIBRARIES(${target} ws2_32) ELSEIF(CMAKE_SYSTEM_NAME MATCHES "(Solaris|SunOS)") TARGET_LINK_LIBRARIES(${target} socket nsl) ENDIF () IF(THREADSAFE) TARGET_LINK_LIBRARIES(${target} ${CMAKE_THREAD_LIBS_INIT}) ENDIF() ENDFUNCTION() # For the MSVC IDE, this function splits up the source files like windows # explorer does. This is esp. useful with the libgit2_clar project, were # usually 2 or more files share the same name. Sadly, this file grouping # is a per-directory option in cmake and not per-target, resulting in # empty virtual folders "tests-clar" for the git2.dll FUNCTION(MSVC_SPLIT_SOURCES target) IF(MSVC_IDE) GET_TARGET_PROPERTY(sources ${target} SOURCES) FOREACH(source ${sources}) IF(source MATCHES ".*/") STRING(REPLACE ${CMAKE_CURRENT_SOURCE_DIR}/ "" rel ${source}) IF(rel) STRING(REGEX REPLACE "/([^/]*)$" "" rel ${rel}) IF(rel) STRING(REPLACE "/" "\\\\" rel ${rel}) SOURCE_GROUP(${rel} FILES ${source}) ENDIF() ENDIF() ENDIF() ENDFOREACH() ENDIF() ENDFUNCTION() FILE(STRINGS "include/git2/version.h" GIT2_HEADER REGEX "^#define LIBGIT2_VERSION \"[^\"]*\"$") STRING(REGEX REPLACE "^.*LIBGIT2_VERSION \"([0-9]+).*$" "\\1" LIBGIT2_VERSION_MAJOR "${GIT2_HEADER}") STRING(REGEX REPLACE "^.*LIBGIT2_VERSION \"[0-9]+\\.([0-9]+).*$" "\\1" LIBGIT2_VERSION_MINOR "${GIT2_HEADER}") STRING(REGEX REPLACE "^.*LIBGIT2_VERSION \"[0-9]+\\.[0-9]+\\.([0-9]+).*$" "\\1" LIBGIT2_VERSION_REV "${GIT2_HEADER}") SET(LIBGIT2_VERSION_STRING "${LIBGIT2_VERSION_MAJOR}.${LIBGIT2_VERSION_MINOR}.${LIBGIT2_VERSION_REV}") # Find required dependencies INCLUDE_DIRECTORIES(src include) IF (WIN32 AND NOT MINGW) ADD_DEFINITIONS(-DGIT_WINHTTP) ELSE () IF (NOT AMIGA) FIND_PACKAGE(OpenSSL) ENDIF () FIND_PACKAGE(HTTP_Parser QUIET) IF (HTTP_PARSER_FOUND AND HTTP_PARSER_VERSION_MAJOR EQUAL 2) INCLUDE_DIRECTORIES(${HTTP_PARSER_INCLUDE_DIRS}) LINK_LIBRARIES(${HTTP_PARSER_LIBRARIES}) ELSE() MESSAGE("http-parser was not found or is too old; using bundled 3rd-party sources.") INCLUDE_DIRECTORIES(deps/http-parser) FILE(GLOB SRC_HTTP deps/http-parser/*.c) ENDIF() ENDIF() # Specify sha1 implementation IF (WIN32 AND NOT MINGW AND NOT SHA1_TYPE STREQUAL "builtin") ADD_DEFINITIONS(-DWIN32_SHA1) FILE(GLOB SRC_SHA1 src/hash/hash_win32.c) ELSEIF (OPENSSL_FOUND AND NOT SHA1_TYPE STREQUAL "builtin") ADD_DEFINITIONS(-DOPENSSL_SHA1) ELSE() FILE(GLOB SRC_SHA1 src/hash/hash_generic.c) ENDIF() # Enable tracing IF (ENABLE_TRACE STREQUAL "ON") ADD_DEFINITIONS(-DGIT_TRACE) ENDIF() # Include POSIX regex when it is required IF(WIN32 OR AMIGA) INCLUDE_DIRECTORIES(deps/regex) SET(SRC_REGEX deps/regex/regex.c) ENDIF() # Optional external dependency: zlib # It's optional, but FIND_PACKAGE gives a warning that looks more like an # error. FIND_PACKAGE(ZLIB QUIET) IF (ZLIB_FOUND) INCLUDE_DIRECTORIES(${ZLIB_INCLUDE_DIRS}) LINK_LIBRARIES(${ZLIB_LIBRARIES}) # Fake the message CMake would have shown MESSAGE("-- Found zlib: ${ZLIB_LIBRARY}") ELSE() MESSAGE( "zlib was not found; using bundled 3rd-party sources." ) INCLUDE_DIRECTORIES(deps/zlib) ADD_DEFINITIONS(-DNO_VIZ -DSTDC -DNO_GZIP) FILE(GLOB SRC_ZLIB deps/zlib/*.c) ENDIF() IF(NOT LIBSSH2_LIBRARY) FIND_PACKAGE(LIBSSH2 QUIET) ENDIF() IF (LIBSSH2_FOUND) ADD_DEFINITIONS(-DGIT_SSH) INCLUDE_DIRECTORIES(${LIBSSH2_INCLUDE_DIR}) SET(SSH_LIBRARIES ${LIBSSH2_LIBRARIES}) ENDIF() # Platform specific compilation flags IF (MSVC) STRING(REPLACE "/Zm1000" " " CMAKE_C_FLAGS "${CMAKE_C_FLAGS}") # /GF - String pooling # /MP - Parallel build SET(CMAKE_C_FLAGS "/GF /MP /nologo ${CMAKE_C_FLAGS}") IF (STDCALL) # /Gz - stdcall calling convention SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /Gz") ENDIF () IF (STATIC_CRT) SET(CRT_FLAG_DEBUG "/MTd") SET(CRT_FLAG_RELEASE "/MT") ELSE() SET(CRT_FLAG_DEBUG "/MDd") SET(CRT_FLAG_RELEASE "/MD") ENDIF() # /Zi - Create debugging information # /Od - Disable optimization # /D_DEBUG - #define _DEBUG # /MTd - Statically link the multithreaded debug version of the CRT # /MDd - Dynamically link the multithreaded debug version of the CRT # /RTC1 - Run time checks SET(CMAKE_C_FLAGS_DEBUG "/Zi /Od /D_DEBUG /RTC1 ${CRT_FLAG_DEBUG}") # /DNDEBUG - Disables asserts # /MT - Statically link the multithreaded release version of the CRT # /MD - Dynamically link the multithreaded release version of the CRT # /O2 - Optimize for speed # /Oy - Enable frame pointer omission (FPO) (otherwise CMake will automatically turn it off) # /GL - Link time code generation (whole program optimization) # /Gy - Function-level linking SET(CMAKE_C_FLAGS_RELEASE "/DNDEBUG /O2 /Oy /GL /Gy ${CRT_FLAG_RELEASE}") # /Oy- - Disable frame pointer omission (FPO) SET(CMAKE_C_FLAGS_RELWITHDEBINFO "/DNDEBUG /Zi /O2 /Oy- /GL /Gy ${CRT_FLAG_RELEASE}") # /O1 - Optimize for size SET(CMAKE_C_FLAGS_MINSIZEREL "/DNDEBUG /O1 /Oy /GL /Gy ${CRT_FLAG_RELEASE}") # /DYNAMICBASE - Address space load randomization (ASLR) # /NXCOMPAT - Data execution prevention (DEP) # /LARGEADDRESSAWARE - >2GB user address space on x86 # /VERSION - Embed version information in PE header SET(CMAKE_EXE_LINKER_FLAGS "/DYNAMICBASE /NXCOMPAT /LARGEADDRESSAWARE /VERSION:${LIBGIT2_VERSION_MAJOR}.${LIBGIT2_VERSION_MINOR}") # /DEBUG - Create a PDB # /LTCG - Link time code generation (whole program optimization) # /OPT:REF /OPT:ICF - Fold out duplicate code at link step # /INCREMENTAL:NO - Required to use /LTCG # /DEBUGTYPE:cv,fixup - Additional data embedded in the PDB (requires /INCREMENTAL:NO, so not on for Debug) SET(CMAKE_EXE_LINKER_FLAGS_DEBUG "/DEBUG") SET(CMAKE_EXE_LINKER_FLAGS_RELEASE "/RELEASE /LTCG /OPT:REF /OPT:ICF /INCREMENTAL:NO") SET(CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO "/DEBUG /RELEASE /LTCG /OPT:REF /OPT:ICF /INCREMENTAL:NO /DEBUGTYPE:cv,fixup") SET(CMAKE_EXE_LINKER_FLAGS_MINSIZEREL "/RELEASE /LTCG /OPT:REF /OPT:ICF /INCREMENTAL:NO") # Same linker settings for DLL as EXE SET(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS}") SET(CMAKE_SHARED_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG}") SET(CMAKE_SHARED_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE}") SET(CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO "${CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO}") SET(CMAKE_SHARED_LINKER_FLAGS_MINSIZEREL "${CMAKE_EXE_LINKER_FLAGS_MINSIZEREL}") SET(WIN_RC "src/win32/git2.rc") # Precompiled headers ELSE () SET(CMAKE_C_FLAGS "-D_GNU_SOURCE -Wall -Wextra -Wno-missing-field-initializers -Wstrict-aliasing=2 -Wstrict-prototypes ${CMAKE_C_FLAGS}") IF (WIN32 AND NOT CYGWIN) SET(CMAKE_C_FLAGS_DEBUG "-D_DEBUG") ENDIF () IF (MINGW) # MinGW always does PIC and complains if we tell it to STRING(REGEX REPLACE "-fPIC" "" CMAKE_SHARED_LIBRARY_C_FLAGS "${CMAKE_SHARED_LIBRARY_C_FLAGS}") # MinGW >= 3.14 uses the C99-style stdio functions # automatically, but forks like mingw-w64 still want # us to define this in order to use them ADD_DEFINITIONS(-D__USE_MINGW_ANSI_STDIO=1) ELSEIF (BUILD_SHARED_LIBS) SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fvisibility=hidden -fPIC") ENDIF () IF (APPLE) # Apple deprecated OpenSSL SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-deprecated-declarations") ENDIF () IF (PROFILE) SET(CMAKE_C_FLAGS "-pg ${CMAKE_C_FLAGS}") SET(CMAKE_EXE_LINKER_FLAGS "-pg ${CMAKE_EXE_LINKER_FLAGS}") ENDIF () ENDIF() IF( NOT CMAKE_CONFIGURATION_TYPES ) # Build Debug by default IF (NOT CMAKE_BUILD_TYPE) SET(CMAKE_BUILD_TYPE "Debug" CACHE STRING "Choose the type of build, options are: Debug Release RelWithDebInfo MinSizeRel." FORCE) ENDIF () ELSE() # Using a multi-configuration generator eg MSVC or Xcode # that uses CMAKE_CONFIGURATION_TYPES and not CMAKE_BUILD_TYPE ENDIF() IF (OPENSSL_FOUND) ADD_DEFINITIONS(-DGIT_SSL) INCLUDE_DIRECTORIES(${OPENSSL_INCLUDE_DIR}) SET(SSL_LIBRARIES ${OPENSSL_LIBRARIES}) ENDIF() IF (THREADSAFE) IF (NOT WIN32) find_package(Threads REQUIRED) ENDIF() ADD_DEFINITIONS(-DGIT_THREADS) ENDIF() ADD_DEFINITIONS(-D_FILE_OFFSET_BITS=64) # Collect sourcefiles FILE(GLOB SRC_H include/git2/*.h) # On Windows use specific platform sources IF (WIN32 AND NOT CYGWIN) ADD_DEFINITIONS(-DWIN32 -D_WIN32_WINNT=0x0501) FILE(GLOB SRC_OS src/win32/*.c) ELSEIF (AMIGA) ADD_DEFINITIONS(-DNO_ADDRINFO -DNO_READDIR_R) FILE(GLOB SRC_OS src/amiga/*.c) ELSE() FILE(GLOB SRC_OS src/unix/*.c) ENDIF() FILE(GLOB SRC_GIT2 src/*.c src/transports/*.c src/xdiff/*.c) # Determine architecture of the machine IF (CMAKE_SIZEOF_VOID_P EQUAL 8) ADD_DEFINITIONS(-DGIT_ARCH_64) ELSEIF (CMAKE_SIZEOF_VOID_P EQUAL 4) ADD_DEFINITIONS(-DGIT_ARCH_32) ELSE() message(FATAL_ERROR "Unsupported architecture") ENDIF() # Compile and link libgit2 ADD_LIBRARY(git2 ${SRC_GIT2} ${SRC_OS} ${SRC_ZLIB} ${SRC_HTTP} ${SRC_REGEX} ${SRC_SHA1} ${WIN_RC}) TARGET_LINK_LIBRARIES(git2 ${SSL_LIBRARIES}) TARGET_LINK_LIBRARIES(git2 ${SSH_LIBRARIES}) TARGET_OS_LIBRARIES(git2) # Workaround for Cmake bug #0011240 (see http://public.kitware.com/Bug/view.php?id=11240) # Win64+MSVC+static libs = linker error IF(MSVC AND GIT_ARCH_64 AND NOT BUILD_SHARED_LIBS) SET_TARGET_PROPERTIES(git2 PROPERTIES STATIC_LIBRARY_FLAGS "/MACHINE:x64") ENDIF() MSVC_SPLIT_SOURCES(git2) IF (SONAME) SET_TARGET_PROPERTIES(git2 PROPERTIES VERSION ${LIBGIT2_VERSION_STRING}) SET_TARGET_PROPERTIES(git2 PROPERTIES SOVERSION ${LIBGIT2_VERSION_MAJOR}) IF (LIBGIT2_FILENAME) ADD_DEFINITIONS(-DLIBGIT2_FILENAME=\"${LIBGIT2_FILENAME}\") SET_TARGET_PROPERTIES(git2 PROPERTIES OUTPUT_NAME ${LIBGIT2_FILENAME}) ENDIF() ENDIF() CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/libgit2.pc.in ${CMAKE_CURRENT_BINARY_DIR}/libgit2.pc @ONLY) IF (MSVC_IDE) # Precompiled headers SET_TARGET_PROPERTIES(git2 PROPERTIES COMPILE_FLAGS "/Yuprecompiled.h /FIprecompiled.h") SET_SOURCE_FILES_PROPERTIES(src/win32/precompiled.c COMPILE_FLAGS "/Ycprecompiled.h") ENDIF () # Install INSTALL(TARGETS git2 RUNTIME DESTINATION ${BIN_INSTALL_DIR} LIBRARY DESTINATION ${LIB_INSTALL_DIR} ARCHIVE DESTINATION ${LIB_INSTALL_DIR} ) INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/libgit2.pc DESTINATION ${LIB_INSTALL_DIR}/pkgconfig ) INSTALL(DIRECTORY include/git2 DESTINATION ${INCLUDE_INSTALL_DIR} ) INSTALL(FILES include/git2.h DESTINATION ${INCLUDE_INSTALL_DIR} ) # Tests IF (BUILD_CLAR) FIND_PACKAGE(PythonInterp REQUIRED) SET(CLAR_FIXTURES "${CMAKE_CURRENT_SOURCE_DIR}/tests-clar/resources/") SET(CLAR_PATH "${CMAKE_CURRENT_SOURCE_DIR}/tests-clar") SET(CLAR_RESOURCES "${CMAKE_CURRENT_SOURCE_DIR}/tests-clar/resources" CACHE PATH "Path to test resources.") ADD_DEFINITIONS(-DCLAR_FIXTURE_PATH=\"${CLAR_FIXTURES}\") ADD_DEFINITIONS(-DCLAR_RESOURCES=\"${TEST_RESOURCES}\") INCLUDE_DIRECTORIES(${CLAR_PATH}) FILE(GLOB_RECURSE SRC_TEST ${CLAR_PATH}/*/*.c) SET(SRC_CLAR "${CLAR_PATH}/main.c" "${CLAR_PATH}/clar_libgit2.c" "${CLAR_PATH}/clar.c") ADD_CUSTOM_COMMAND( OUTPUT ${CLAR_PATH}/clar.suite COMMAND ${PYTHON_EXECUTABLE} generate.py -f -xonline . DEPENDS ${SRC_TEST} WORKING_DIRECTORY ${CLAR_PATH} ) SET_SOURCE_FILES_PROPERTIES( ${CLAR_PATH}/clar.c PROPERTIES OBJECT_DEPENDS ${CLAR_PATH}/clar.suite) ADD_EXECUTABLE(libgit2_clar ${SRC_GIT2} ${SRC_OS} ${SRC_CLAR} ${SRC_TEST} ${SRC_ZLIB} ${SRC_HTTP} ${SRC_REGEX} ${SRC_SHA1}) TARGET_LINK_LIBRARIES(libgit2_clar ${SSL_LIBRARIES}) TARGET_LINK_LIBRARIES(libgit2_clar ${SSH_LIBRARIES}) TARGET_OS_LIBRARIES(libgit2_clar) MSVC_SPLIT_SOURCES(libgit2_clar) IF (MSVC_IDE) # Precompiled headers SET_TARGET_PROPERTIES(libgit2_clar PROPERTIES COMPILE_FLAGS "/Yuprecompiled.h /FIprecompiled.h") ENDIF () ENABLE_TESTING() ADD_TEST(libgit2_clar libgit2_clar -ionline) ENDIF () IF (TAGS) FIND_PROGRAM(CTAGS ctags) IF (NOT CTAGS) message(FATAL_ERROR "Could not find ctags command") ENDIF () FILE(GLOB_RECURSE SRC_ALL *.[ch]) ADD_CUSTOM_COMMAND( OUTPUT tags COMMAND ${CTAGS} -a ${SRC_ALL} DEPENDS ${SRC_ALL} ) ADD_CUSTOM_TARGET( do_tags ALL DEPENDS tags ) ENDIF () IF (BUILD_EXAMPLES) FILE(GLOB_RECURSE EXAMPLE_SRC examples/network/*.c) ADD_EXECUTABLE(cgit2 ${EXAMPLE_SRC}) IF(WIN32) TARGET_LINK_LIBRARIES(cgit2 git2) ELSE() TARGET_LINK_LIBRARIES(cgit2 git2 pthread) ENDIF() ADD_EXECUTABLE(git-diff examples/diff.c) TARGET_LINK_LIBRARIES(git-diff git2) ADD_EXECUTABLE(git-general examples/general.c) TARGET_LINK_LIBRARIES(git-general git2) ADD_EXECUTABLE(git-showindex examples/showindex.c) TARGET_LINK_LIBRARIES(git-showindex git2) ADD_EXECUTABLE(git-rev-list examples/rev-list.c) TARGET_LINK_LIBRARIES(git-rev-list git2) ENDIF () libgit2-0.19.0/CONTRIBUTING.md000066400000000000000000000104331216214232500153650ustar00rootroot00000000000000# Welcome to libgit2! We're making it easy to do interesting things with git, and we'd love to have your help. ## Discussion & Chat We hang out in the #libgit2 channel on irc.freenode.net. Also, feel free to open an [Issue](https://github.com/libgit2/libgit2/issues/new) to start a discussion about any concerns you have. We like to use Issues for that so there is an easily accessible permanent record of the conversation. ## Reporting Bugs First, know which version of libgit2 your problem is in and include it in your bug report. This can either be a tag (e.g. [v0.17.0](https://github.com/libgit2/libgit2/tree/v0.17.0) ) or a commit SHA (e.g. [01be7863](https://github.com/libgit2/libgit2/commit/01be786319238fd6507a08316d1c265c1a89407f) ). Using [`git describe`](http://git-scm.com/docs/git-describe) is a great way to tell us what version you're working with. If you're not running against the latest `development` branch version, please compile and test against that to avoid re-reporting an issue that's already been fixed. It's *incredibly* helpful to be able to reproduce the problem. Please include a list of steps, a bit of code, and/or a zipped repository (if possible). Note that some of the libgit2 developers are employees of GitHub, so if your repository is private, find us on IRC and we'll figure out a way to help you. ## Pull Requests Our work flow is a typical GitHub flow, where contributors fork the [libgit2 repository](https://github.com/libgit2/libgit2), make their changes on branch, and submit a [Pull Request](https://help.github.com/articles/using-pull-requests) (a.k.a. "PR"). Life will be a lot easier for you (and us) if you follow this pattern (i.e. fork, named branch, submit PR). If you use your fork's `development` branch, things can get messy. Please include a nice description of your changes with your PR; if we have to read the whole diff to figure out why you're contributing in the first place, you're less likely to get feedback and have your change merged in. ## Porting Code From Other Open-Source Projects `libgit2` is licensed under the terms of the GPL v2 with a linking exception. Any code brought in must be compatible with those terms. The most common case is porting code from core Git. Git is a pure GPL project, which means that in order to port code to this project, we need the explicit permission of the author. Check the [`git.git-authors`](https://github.com/libgit2/libgit2/blob/development/git.git-authors) file for authors who have already consented; feel free to add someone if you've obtained their consent. Other licenses have other requirements; check the license of the library you're porting code *from* to see what you need to do. As a general rule, MIT and BSD (3-clause) licenses are typically no problem. Apache 2.0 license typically doesn't work due to GPL incompatibility. ## Style Guide `libgit2` is written in [ANSI C](http://en.wikipedia.org/wiki/ANSI_C) (a.k.a. C89) with some specific conventions for function and type naming, code formatting, and testing. We like to keep the source code consistent and easy to read. Maintaining this takes some discipline, but it's been more than worth it. Take a look at the [conventions file](https://github.com/libgit2/libgit2/blob/development/CONVENTIONS.md). ## Starter Projects So, you want to start helping out with `libgit2`? That's fantastic? We welcome contributions and we promise we'll try to be nice. If you want to jump in, you can look at our issues list to see if there are any unresolved issues to jump in on. Also, here is a list of some smaller project ideas that could help you become familiar with the code base and make a nice first step: * Convert a `git_*modulename*_foreach()` callback-based iteration API into a `git_*modulename*_iterator` object with a create/advance style of API. This helps folks writing language bindings and usually isn't too complicated. * Write a new `examples/` program that mirrors a particular core git command. (See `examples/diff.c` for example.) This lets you (and us) easily exercise a particular facet of the API and measure compatability and feature parity with core git. * Submit a PR to clarify documentation! While we do try to document all of the APIs, your fresh eyes on the documentation will find areas that are confusing much more easily. libgit2-0.19.0/CONVENTIONS.md000066400000000000000000000164021216214232500152650ustar00rootroot00000000000000# Libgit2 Conventions We like to keep the source consistent and readable. Herein are some guidelines that should help with that. ## Compatibility `libgit2` runs on many different platforms with many different compilers. It is written in [ANSI C](http://en.wikipedia.org/wiki/ANSI_C) (a.k.a. C89) with some specific standards for function and type naming, code formatting, and testing. We try to avoid more recent extensions to maximize portability. We also, to the greatest extent possible, try to avoid lots of `#ifdef`s inside the core code base. This is somewhat unavoidable, but since it can really hamper maintainability, we keep it to a minimum. ## Match Surrounding Code If there is one rule to take away from this document, it is *new code should match the surrounding code in a way that makes it impossible to distinguish the new from the old.* Consistency is more important to us than anyone's personal opinion about where braces should be placed or spaces vs. tabs. If a section of code is being completely rewritten, it is okay to bring it in line with the standards that are laid out here, but we will not accept submissions that contain a large number of changes that are merely reformatting. ## Naming Things All external types and functions start with `git_` and all `#define` macros start with `GIT_`. The `libgit2` API is mostly broken into related functional modules each with a corresponding header. All functions in a module should be named like `git_modulename_functioname()` (e.g. `git_repository_open()`). Functions with a single output parameter should name that parameter `out`. Multiple outputs should be named `foo_out`, `bar_out`, etc. Parameters of type `git_oid` should be named `id`, or `foo_id`. Calls that return an OID should be named `git_foo_id`. Where a callback function is used, the function should also include a user-supplied extra input that is a `void *` named "payload" that will be passed through to the callback at each invocation. ## Typedefs Wherever possible, use `typedef`. In some cases, if a structure is just a collection of function pointers, the pointer types don't need to be separately typedef'd, but loose function pointer types should be. ## Exports All exported functions must be declared as: ```c GIT_EXTERN(result_type) git_modulename_functionname(arg_list); ``` ## Internals Functions whose *modulename* is followed by two underscores, for example `git_odb__read_packed`, are semi-private functions. They are primarily intended for use within the library itself, and may disappear or change their signature in a future release. ## Parameters Out parameters come first. Whenever possible, pass argument pointers as `const`. Some structures (such as `git_repository` and `git_index`) have mutable internal structure that prevents this. Callbacks should always take a `void *` payload as their last parameter. Callback pointers are grouped with their payloads, and typically come last when passed as arguments: ```c int git_foo(git_repository *repo, git_foo_cb callback, void *payload); ``` ## Memory Ownership Some APIs allocate memory which the caller is responsible for freeing; others return a pointer into a buffer that's owned by some other object. Make this explicit in the documentation. ## Return codes Most public APIs should return an `int` error code. As is typical with most C library functions, a zero value indicates success and a negative value indicates failure. Some bindings will transform these returned error codes into exception types, so returning a semantically appropriate error code is important. Check [`include/git2/errors.h`](https://github.com/libgit2/libgit2/blob/development/include/git2/errors.h) for the return codes already defined. In your implementation, use `giterr_set()` to provide extended error information to callers. If a `libgit2` function internally invokes another function that reports an error, but the error is not propagated up, use `giterr_clear()` to prevent callers from getting the wrong error message later on. ## Structs Most public types should be opaque, e.g.: ```C typedef struct git_odb git_odb; ``` ...with allocation functions returning an "instance" created within the library, and not within the application. This allows the type to grow (or shrink) in size without rebuilding client code. To preserve ABI compatibility, include an `int version` field in all opaque structures, and initialize to the latest version in the construction call. Increment the "latest" version whenever the structure changes, and try to only append to the end of the structure. ## Option Structures If a function's parameter count is too high, it may be desirable to package up the options in a structure. Make them transparent, include a version field, and provide an initializer constant or constructor. Using these structures should be this easy: ```C git_foo_options opts = GIT_FOO_OPTIONS_INIT; opts.baz = BAZ_OPTION_ONE; git_foo(&opts); ``` ## Enumerations Typedef all enumerated types. If each option stands alone, use the enum type for passing them as parameters; if they are flags to be OR'ed together, pass them as `unsigned int` or `uint32_t` or some appropriate type. ## Code Layout Try to keep lines less than 80 characters long. This is a loose requirement, but going significantly over 80 columns is not nice. Use common sense to wrap most code lines; public function declarations can use a couple of different styles: ```c /** All on one line is okay if it fits */ GIT_EXTERN(int) git_foo_simple(git_oid *id); /** Otherwise one argument per line is a good next step */ GIT_EXTERN(int) git_foo_id( git_oid **out, int a, int b); ``` Indent with tabs; set your editor's tab width to 4 for best effect. Avoid trailing whitespace and only commit Unix-style newlines (i.e. no CRLF in the repository - just set `core.autocrlf` to true if you are writing code on a Windows machine). ## Documentation All comments should conform to Doxygen "javadoc" style conventions for formatting the public API documentation. Try to document every parameter, and keep the comments up to date if you change the parameter list. ## Public Header Template Use this template when creating a new public header. ```C #ifndef INCLUDE_git_${filename}_h__ #define INCLUDE_git_${filename}_h__ #include "git/common.h" /** * @file git/${filename}.h * @brief Git some description * @defgroup git_${filename} some description routines * @ingroup Git * @{ */ GIT_BEGIN_DECL /* ... definitions ... */ /** @} */ GIT_END_DECL #endif ``` ## Inlined functions All inlined functions must be declared as: ```C GIT_INLINE(result_type) git_modulename_functionname(arg_list); ``` ## Tests `libgit2` uses the [clar](https://github.com/vmg/clar) testing framework. All PRs should have corresponding tests. * If the PR fixes an existing issue, the test should fail prior to applying the PR and succeed after applying it. * If the PR is for new functionality, then the tests should exercise that new functionality to a certain extent. We don't require 100% coverage right now (although we are getting stricter over time). When adding new tests, we prefer if you attempt to reuse existing test data (in `tests-clar/resources/`) if possible. If you are going to add new test repositories, please try to strip them of unnecessary files (e.g. sample hooks, etc). libgit2-0.19.0/COPYING000066400000000000000000001362771216214232500142060ustar00rootroot00000000000000 libgit2 is Copyright (C) the libgit2 contributors, unless otherwise stated. See the AUTHORS file for details. Note that the only valid version of the GPL as far as this project is concerned is _this_ particular version of the license (ie v2, not v2.2 or v3.x or whatever), unless explicitly otherwise stated. ---------------------------------------------------------------------- LINKING EXCEPTION In addition to the permissions in the GNU General Public License, the authors give you unlimited permission to link the compiled version of this library 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.) ---------------------------------------------------------------------- GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program 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; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. ---------------------------------------------------------------------- The bundled ZLib code is licensed under the ZLib license: Copyright (C) 1995-2010 Jean-loup Gailly and Mark Adler This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. Jean-loup Gailly Mark Adler jloup@gzip.org madler@alumni.caltech.edu ---------------------------------------------------------------------- The priority queue implementation is based on code licensed under the Apache 2.0 license: Copyright 2010 Volkan Yazıcı Copyright 2006-2010 The Apache Software Foundation The full text of the Apache 2.0 license is available at: http://www.apache.org/licenses/LICENSE-2.0 ---------------------------------------------------------------------- The Clay framework is licensed under the MIT license: Copyright (C) 2011 by Vicent Marti Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ---------------------------------------------------------------------- The regex library (deps/regex/) is licensed under the GNU LGPL GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 Copyright (C) 1991, 1999 Free Software Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. [This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. When we speak of free software, we are referring to freedom of use, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish); that you receive source code or can get it if you want it; that you can change the software and use pieces of it in new free programs; and that you are informed that you can do these things. To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties with this License. 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 13. The Free Software Foundation may publish revised and/or new versions of the Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. , 1 April 1990 Ty Coon, President of Vice That's all there is to it! libgit2-0.19.0/Makefile.embed000066400000000000000000000016501216214232500156500ustar00rootroot00000000000000PLATFORM=$(shell uname -o) rm=rm -f AR=ar cq RANLIB=ranlib LIBNAME=libgit2.a ifeq ($(PLATFORM),Msys) CC=gcc else CC=cc endif INCLUDES= -I. -Isrc -Iinclude -Ideps/http-parser -Ideps/zlib DEFINES= $(INCLUDES) -DNO_VIZ -DSTDC -DNO_GZIP -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE $(EXTRA_DEFINES) CFLAGS= -g $(DEFINES) -Wall -Wextra -O2 $(EXTRA_CFLAGS) SRCS = $(wildcard src/*.c) $(wildcard src/transports/*.c) $(wildcard src/xdiff/*.c) $(wildcard deps/http-parser/*.c) $(wildcard deps/zlib/*.c) src/hash/hash_generic.c ifeq ($(PLATFORM),Msys) SRCS += $(wildcard src/win32/*.c) $(wildcard src/compat/*.c) deps/regex/regex.c INCLUDES += -Ideps/regex DEFINES += -DWIN32 -D_WIN32_WINNT=0x0501 else SRCS += $(wildcard src/unix/*.c) CFLAGS += -fPIC endif OBJS = $(patsubst %.c,%.o,$(SRCS)) %.c.o: $(CC) $(CFLAGS) -c $*.c all: $(LIBNAME) $(LIBNAME): $(OBJS) $(rm) $@ $(AR) $@ $(OBJS) $(RANLIB) $@ clean: $(rm) $(OBJS) $(LIBNAME) libgit2-0.19.0/README.md000066400000000000000000000140611216214232500144140ustar00rootroot00000000000000libgit2 - the Git linkable library ====================== [![Build Status](https://secure.travis-ci.org/libgit2/libgit2.png?branch=development)](http://travis-ci.org/libgit2/libgit2) libgit2 is a portable, pure C implementation of the Git core methods provided as a re-entrant linkable library with a solid API, allowing you to write native speed custom Git applications in any language with bindings. libgit2 is licensed under a **very permissive license** (GPLv2 with a special Linking Exception). This basically means that you can link it (unmodified) with any kind of software without having to release its source code. * Mailing list: ~~~~ The libgit2 mailing list has traditionally been hosted in Librelist, but Librelist is and has always been a shitshow. We encourage you to [open an issue](https://github.com/libgit2/libgit2/issues) on GitHub instead for any questions regarding the library. * Archives: * Website: * API documentation: * IRC: #libgit2 on irc.freenode.net. What It Can Do ================================== libgit2 is already very usable. * SHA conversions, formatting and shortening * abstracted ODB backend system * commit, tag, tree and blob parsing, editing, and write-back * tree traversal * revision walking * index file (staging area) manipulation * reference management (including packed references) * config file management * high level repository management * thread safety and reentrancy * descriptive and detailed error messages * ...and more (over 175 different API calls) Building libgit2 - Using CMake ============================== 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. The libgit2 library is built using CMake 2.6+ () on all platforms. On most systems you can build the library using the following commands $ mkdir build && cd build $ cmake .. $ cmake --build . Alternatively you can point the CMake GUI tool to the CMakeLists.txt file and generate platform specific build project or IDE workspace. To install the library you can specify the install prefix by setting: $ cmake .. -DCMAKE_INSTALL_PREFIX=/install/prefix $ cmake --build . --target install For more advanced use or questions about CMake please read . The following CMake variables are declared: - `BIN_INSTALL_DIR`: Where to install binaries to. - `LIB_INSTALL_DIR`: Where to install libraries to. - `INCLUDE_INSTALL_DIR`: Where to install headers to. - `BUILD_SHARED_LIBS`: Build libgit2 as a Shared Library (defaults to ON) - `BUILD_CLAR`: Build [Clar](https://github.com/vmg/clar)-based test suite (defaults to ON) - `THREADSAFE`: Build libgit2 with threading support (defaults to OFF) - `STDCALL`: Build libgit2 as `stdcall`. Turn off for `cdecl` (Windows; defaults to ON) Compiler and linker options --------------------------- CMake lets you specify a few variables to control the behavior of the compiler and linker. These flags are rarely used but can be useful for 64-bit to 32-bit cross-compilation. - `CMAKE_C_FLAGS`: Set your own compiler flags - `CMAKE_FIND_ROOT_PATH`: Override the search path for libraries - `ZLIB_LIBRARY`, `OPENSSL_SSL_LIBRARY` AND `OPENSSL_CRYPTO_LIBRARY`: Tell CMake where to find those specific libraries MacOS X ------- If you want to build a universal binary for Mac OS X, CMake sets it all up for you if you use `-DCMAKE_OSX_ARCHITECTURES="i386;x86_64"` when configuring. Windows ------- You need to run the CMake commands from the Visual Studio command prompt, not the regular or Windows SDK one. Select the right generator for your version with the `-G "Visual Studio X" option. See [the wiki] (https://github.com/libgit2/libgit2/wiki/Building-libgit2-on-Windows) for more detailed instructions. Language Bindings ================================== Here are the bindings to libgit2 that are currently available: * C++ * libqgit2, Qt bindings * Chicken Scheme * chicken-git * D * dlibgit * Delphi * GitForDelphi * Erlang * Geef * Go * go-git * GObject * libgit2-glib * Haskell * hgit2 * Lua * luagit2 * .NET * libgit2net, low level bindings * libgit2sharp * Node.js * node-gitteh * nodegit * Objective-C * objective-git * OCaml * libgit2-ocaml * Parrot Virtual Machine * parrot-libgit2 * Perl * Git-Raw * PHP * php-git * Python * pygit2 * Ruby * Rugged * Vala * libgit2.vapi If you start another language binding to libgit2, please let us know so we can add it to the list. How Can I Contribute? ================================== Check the [contribution guidelines](CONTRIBUTING.md). License ================================== libgit2 is under GPL2 **with linking exemption**. This means you can link to the library with any program, commercial, open source or other. However, you cannot modify libgit2 and distribute it without supplying the source. See the COPYING file for the full license text. libgit2-0.19.0/api.docurium000066400000000000000000000004201216214232500154510ustar00rootroot00000000000000{ "name": "libgit2", "github": "libgit2/libgit2", "input": "include/git2", "prefix": "git_", "output": "docs", "branch": "gh-pages", "examples": "examples", "legacy": { "input": {"src/git": ["v0.1.0"], "src/git2": ["v0.2.0", "v0.3.0"]} } } libgit2-0.19.0/cmake/000077500000000000000000000000001216214232500142135ustar00rootroot00000000000000libgit2-0.19.0/cmake/Modules/000077500000000000000000000000001216214232500156235ustar00rootroot00000000000000libgit2-0.19.0/cmake/Modules/FindHTTP_Parser.cmake000066400000000000000000000031671216214232500215300ustar00rootroot00000000000000# - Try to find http-parser # # Defines the following variables: # # HTTP_PARSER_FOUND - system has http-parser # HTTP_PARSER_INCLUDE_DIR - the http-parser include directory # HTTP_PARSER_LIBRARIES - Link these to use http-parser # HTTP_PARSER_VERSION_MAJOR - major version # HTTP_PARSER_VERSION_MINOR - minor version # HTTP_PARSER_VERSION_STRING - the version of http-parser found # Find the header and library FIND_PATH(HTTP_PARSER_INCLUDE_DIR NAMES http_parser.h) FIND_LIBRARY(HTTP_PARSER_LIBRARY NAMES http_parser libhttp_parser) # Found the header, read version if (HTTP_PARSER_INCLUDE_DIR AND EXISTS "${HTTP_PARSER_INCLUDE_DIR}/http_parser.h") FILE(READ "${HTTP_PARSER_INCLUDE_DIR}/http_parser.h" HTTP_PARSER_H) IF (HTTP_PARSER_H) STRING(REGEX REPLACE ".*#define[\t ]+HTTP_PARSER_VERSION_MAJOR[\t ]+([0-9]+).*" "\\1" HTTP_PARSER_VERSION_MAJOR "${HTTP_PARSER_H}") STRING(REGEX REPLACE ".*#define[\t ]+HTTP_PARSER_VERSION_MINOR[\t ]+([0-9]+).*" "\\1" HTTP_PARSER_VERSION_MINOR "${HTTP_PARSER_H}") SET(HTTP_PARSER_VERSION_STRING "${HTTP_PARSER_VERSION_MAJOR}.${HTTP_PARSER_VERSION_MINOR}") ENDIF() UNSET(HTTP_PARSER_H) ENDIF() # Handle the QUIETLY and REQUIRED arguments and set HTTP_PARSER_FOUND # to TRUE if all listed variables are TRUE INCLUDE(FindPackageHandleStandardArgs) FIND_PACKAGE_HANDLE_STANDARD_ARGS(HTTP_Parser REQUIRED_VARS HTTP_PARSER_INCLUDE_DIR HTTP_PARSER_LIBRARY) # Hide advanced variables MARK_AS_ADVANCED(HTTP_PARSER_INCLUDE_DIR HTTP_PARSER_LIBRARY) # Set standard variables IF (HTTP_PARSER_FOUND) SET(HTTP_PARSER_LIBRARIES ${HTTP_PARSER_LIBRARY}) set(HTTP_PARSER_INCLUDE_DIRS ${HTTP_PARSER_INCLUDE_DIR}) ENDIF() libgit2-0.19.0/cmake/Modules/FindLIBSSH2.cmake000066400000000000000000000016521216214232500205000ustar00rootroot00000000000000if (LIBSSH2_LIBRARIES AND LIBSSH2_INCLUDE_DIRS) set(LIBSSH2_FOUND TRUE) else (LIBSSH2_LIBRARIES AND LIBSSH2_INCLUDE_DIRS) find_path(LIBSSH2_INCLUDE_DIR NAMES libssh2.h PATHS /usr/include /usr/local/include /opt/local/include /sw/include ${CMAKE_INCLUDE_PATH} ${CMAKE_INSTALL_PREFIX}/include ) find_library(LIBSSH2_LIBRARY NAMES ssh2 libssh2 PATHS /usr/lib /usr/local/lib /opt/local/lib /sw/lib ${CMAKE_LIBRARY_PATH} ${CMAKE_INSTALL_PREFIX}/lib ) if (LIBSSH2_INCLUDE_DIR AND LIBSSH2_LIBRARY) set(LIBSSH2_FOUND TRUE) endif (LIBSSH2_INCLUDE_DIR AND LIBSSH2_LIBRARY) if (LIBSSH2_FOUND) set(LIBSSH2_INCLUDE_DIRS ${LIBSSH2_INCLUDE_DIR} ) set(LIBSSH2_LIBRARIES ${LIBSSH2_LIBRARIES} ${LIBSSH2_LIBRARY} ) endif (LIBSSH2_FOUND) endif (LIBSSH2_LIBRARIES AND LIBSSH2_INCLUDE_DIRS) libgit2-0.19.0/deps/000077500000000000000000000000001216214232500140665ustar00rootroot00000000000000libgit2-0.19.0/deps/http-parser/000077500000000000000000000000001216214232500163375ustar00rootroot00000000000000libgit2-0.19.0/deps/http-parser/LICENSE-MIT000066400000000000000000000023431216214232500177750ustar00rootroot00000000000000http_parser.c is based on src/http/ngx_http_parse.c from NGINX copyright Igor Sysoev. Additional changes are licensed under the same terms as NGINX and copyright Joyent, Inc. and other Node contributors. All rights reserved. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. libgit2-0.19.0/deps/http-parser/http_parser.c000066400000000000000000001673711216214232500210550ustar00rootroot00000000000000/* Based on src/http/ngx_http_parse.c from NGINX copyright Igor Sysoev * * Additional changes are licensed under the same terms as NGINX and * copyright Joyent, Inc. and other Node contributors. All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. */ #include "http_parser.h" #include #include #include #include #include #include #ifndef ULLONG_MAX # define ULLONG_MAX ((uint64_t) -1) /* 2^64-1 */ #endif #ifndef MIN # define MIN(a,b) ((a) < (b) ? (a) : (b)) #endif #ifndef ARRAY_SIZE # define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) #endif #ifndef BIT_AT # define BIT_AT(a, i) \ (!!((unsigned int) (a)[(unsigned int) (i) >> 3] & \ (1 << ((unsigned int) (i) & 7)))) #endif #ifndef ELEM_AT # define ELEM_AT(a, i, v) ((unsigned int) (i) < ARRAY_SIZE(a) ? (a)[(i)] : (v)) #endif #define SET_ERRNO(e) \ do { \ parser->http_errno = (e); \ } while(0) /* Run the notify callback FOR, returning ER if it fails */ #define CALLBACK_NOTIFY_(FOR, ER) \ do { \ assert(HTTP_PARSER_ERRNO(parser) == HPE_OK); \ \ if (settings->on_##FOR) { \ if (0 != settings->on_##FOR(parser)) { \ SET_ERRNO(HPE_CB_##FOR); \ } \ \ /* We either errored above or got paused; get out */ \ if (HTTP_PARSER_ERRNO(parser) != HPE_OK) { \ return (ER); \ } \ } \ } while (0) /* Run the notify callback FOR and consume the current byte */ #define CALLBACK_NOTIFY(FOR) CALLBACK_NOTIFY_(FOR, p - data + 1) /* Run the notify callback FOR and don't consume the current byte */ #define CALLBACK_NOTIFY_NOADVANCE(FOR) CALLBACK_NOTIFY_(FOR, p - data) /* Run data callback FOR with LEN bytes, returning ER if it fails */ #define CALLBACK_DATA_(FOR, LEN, ER) \ do { \ assert(HTTP_PARSER_ERRNO(parser) == HPE_OK); \ \ if (FOR##_mark) { \ if (settings->on_##FOR) { \ if (0 != settings->on_##FOR(parser, FOR##_mark, (LEN))) { \ SET_ERRNO(HPE_CB_##FOR); \ } \ \ /* We either errored above or got paused; get out */ \ if (HTTP_PARSER_ERRNO(parser) != HPE_OK) { \ return (ER); \ } \ } \ FOR##_mark = NULL; \ } \ } while (0) /* Run the data callback FOR and consume the current byte */ #define CALLBACK_DATA(FOR) \ CALLBACK_DATA_(FOR, p - FOR##_mark, p - data + 1) /* Run the data callback FOR and don't consume the current byte */ #define CALLBACK_DATA_NOADVANCE(FOR) \ CALLBACK_DATA_(FOR, p - FOR##_mark, p - data) /* Set the mark FOR; non-destructive if mark is already set */ #define MARK(FOR) \ do { \ if (!FOR##_mark) { \ FOR##_mark = p; \ } \ } while (0) #define PROXY_CONNECTION "proxy-connection" #define CONNECTION "connection" #define CONTENT_LENGTH "content-length" #define TRANSFER_ENCODING "transfer-encoding" #define UPGRADE "upgrade" #define CHUNKED "chunked" #define KEEP_ALIVE "keep-alive" #define CLOSE "close" static const char *method_strings[] = { #define XX(num, name, string) #string, HTTP_METHOD_MAP(XX) #undef XX }; /* Tokens as defined by rfc 2616. Also lowercases them. * token = 1* * separators = "(" | ")" | "<" | ">" | "@" * | "," | ";" | ":" | "\" | <"> * | "/" | "[" | "]" | "?" | "=" * | "{" | "}" | SP | HT */ static const char tokens[256] = { /* 0 nul 1 soh 2 stx 3 etx 4 eot 5 enq 6 ack 7 bel */ 0, 0, 0, 0, 0, 0, 0, 0, /* 8 bs 9 ht 10 nl 11 vt 12 np 13 cr 14 so 15 si */ 0, 0, 0, 0, 0, 0, 0, 0, /* 16 dle 17 dc1 18 dc2 19 dc3 20 dc4 21 nak 22 syn 23 etb */ 0, 0, 0, 0, 0, 0, 0, 0, /* 24 can 25 em 26 sub 27 esc 28 fs 29 gs 30 rs 31 us */ 0, 0, 0, 0, 0, 0, 0, 0, /* 32 sp 33 ! 34 " 35 # 36 $ 37 % 38 & 39 ' */ 0, '!', 0, '#', '$', '%', '&', '\'', /* 40 ( 41 ) 42 * 43 + 44 , 45 - 46 . 47 / */ 0, 0, '*', '+', 0, '-', '.', 0, /* 48 0 49 1 50 2 51 3 52 4 53 5 54 6 55 7 */ '0', '1', '2', '3', '4', '5', '6', '7', /* 56 8 57 9 58 : 59 ; 60 < 61 = 62 > 63 ? */ '8', '9', 0, 0, 0, 0, 0, 0, /* 64 @ 65 A 66 B 67 C 68 D 69 E 70 F 71 G */ 0, 'a', 'b', 'c', 'd', 'e', 'f', 'g', /* 72 H 73 I 74 J 75 K 76 L 77 M 78 N 79 O */ 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', /* 80 P 81 Q 82 R 83 S 84 T 85 U 86 V 87 W */ 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', /* 88 X 89 Y 90 Z 91 [ 92 \ 93 ] 94 ^ 95 _ */ 'x', 'y', 'z', 0, 0, 0, '^', '_', /* 96 ` 97 a 98 b 99 c 100 d 101 e 102 f 103 g */ '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', /* 104 h 105 i 106 j 107 k 108 l 109 m 110 n 111 o */ 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', /* 112 p 113 q 114 r 115 s 116 t 117 u 118 v 119 w */ 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', /* 120 x 121 y 122 z 123 { 124 | 125 } 126 ~ 127 del */ 'x', 'y', 'z', 0, '|', 0, '~', 0 }; static const int8_t unhex[256] = {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 , 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,-1,-1,-1,-1,-1,-1 ,-1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1 ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 ,-1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1 ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 }; #if HTTP_PARSER_STRICT # define T(v) 0 #else # define T(v) v #endif static const uint8_t normal_url_char[32] = { /* 0 nul 1 soh 2 stx 3 etx 4 eot 5 enq 6 ack 7 bel */ 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0, /* 8 bs 9 ht 10 nl 11 vt 12 np 13 cr 14 so 15 si */ 0 | T(2) | 0 | 0 | T(16) | 0 | 0 | 0, /* 16 dle 17 dc1 18 dc2 19 dc3 20 dc4 21 nak 22 syn 23 etb */ 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0, /* 24 can 25 em 26 sub 27 esc 28 fs 29 gs 30 rs 31 us */ 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0, /* 32 sp 33 ! 34 " 35 # 36 $ 37 % 38 & 39 ' */ 0 | 2 | 4 | 0 | 16 | 32 | 64 | 128, /* 40 ( 41 ) 42 * 43 + 44 , 45 - 46 . 47 / */ 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, /* 48 0 49 1 50 2 51 3 52 4 53 5 54 6 55 7 */ 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, /* 56 8 57 9 58 : 59 ; 60 < 61 = 62 > 63 ? */ 1 | 2 | 4 | 8 | 16 | 32 | 64 | 0, /* 64 @ 65 A 66 B 67 C 68 D 69 E 70 F 71 G */ 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, /* 72 H 73 I 74 J 75 K 76 L 77 M 78 N 79 O */ 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, /* 80 P 81 Q 82 R 83 S 84 T 85 U 86 V 87 W */ 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, /* 88 X 89 Y 90 Z 91 [ 92 \ 93 ] 94 ^ 95 _ */ 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, /* 96 ` 97 a 98 b 99 c 100 d 101 e 102 f 103 g */ 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, /* 104 h 105 i 106 j 107 k 108 l 109 m 110 n 111 o */ 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, /* 112 p 113 q 114 r 115 s 116 t 117 u 118 v 119 w */ 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, /* 120 x 121 y 122 z 123 { 124 | 125 } 126 ~ 127 del */ 1 | 2 | 4 | 8 | 16 | 32 | 64 | 0, }; #undef T enum state { s_dead = 1 /* important that this is > 0 */ , s_start_req_or_res , s_res_or_resp_H , s_start_res , s_res_H , s_res_HT , s_res_HTT , s_res_HTTP , s_res_first_http_major , s_res_http_major , s_res_first_http_minor , s_res_http_minor , s_res_first_status_code , s_res_status_code , s_res_status , s_res_line_almost_done , s_start_req , s_req_method , s_req_spaces_before_url , s_req_schema , s_req_schema_slash , s_req_schema_slash_slash , s_req_server_start , s_req_server , s_req_server_with_at , s_req_path , s_req_query_string_start , s_req_query_string , s_req_fragment_start , s_req_fragment , s_req_http_start , s_req_http_H , s_req_http_HT , s_req_http_HTT , s_req_http_HTTP , s_req_first_http_major , s_req_http_major , s_req_first_http_minor , s_req_http_minor , s_req_line_almost_done , s_header_field_start , s_header_field , s_header_value_start , s_header_value , s_header_value_lws , s_header_almost_done , s_chunk_size_start , s_chunk_size , s_chunk_parameters , s_chunk_size_almost_done , s_headers_almost_done , s_headers_done /* Important: 's_headers_done' must be the last 'header' state. All * states beyond this must be 'body' states. It is used for overflow * checking. See the PARSING_HEADER() macro. */ , s_chunk_data , s_chunk_data_almost_done , s_chunk_data_done , s_body_identity , s_body_identity_eof , s_message_done }; #define PARSING_HEADER(state) (state <= s_headers_done) enum header_states { h_general = 0 , h_C , h_CO , h_CON , h_matching_connection , h_matching_proxy_connection , h_matching_content_length , h_matching_transfer_encoding , h_matching_upgrade , h_connection , h_content_length , h_transfer_encoding , h_upgrade , h_matching_transfer_encoding_chunked , h_matching_connection_keep_alive , h_matching_connection_close , h_transfer_encoding_chunked , h_connection_keep_alive , h_connection_close }; enum http_host_state { s_http_host_dead = 1 , s_http_userinfo_start , s_http_userinfo , s_http_host_start , s_http_host_v6_start , s_http_host , s_http_host_v6 , s_http_host_v6_end , s_http_host_port_start , s_http_host_port }; /* Macros for character classes; depends on strict-mode */ #define CR '\r' #define LF '\n' #define LOWER(c) (unsigned char)(c | 0x20) #define IS_ALPHA(c) (LOWER(c) >= 'a' && LOWER(c) <= 'z') #define IS_NUM(c) ((c) >= '0' && (c) <= '9') #define IS_ALPHANUM(c) (IS_ALPHA(c) || IS_NUM(c)) #define IS_HEX(c) (IS_NUM(c) || (LOWER(c) >= 'a' && LOWER(c) <= 'f')) #define IS_MARK(c) ((c) == '-' || (c) == '_' || (c) == '.' || \ (c) == '!' || (c) == '~' || (c) == '*' || (c) == '\'' || (c) == '(' || \ (c) == ')') #define IS_USERINFO_CHAR(c) (IS_ALPHANUM(c) || IS_MARK(c) || (c) == '%' || \ (c) == ';' || (c) == ':' || (c) == '&' || (c) == '=' || (c) == '+' || \ (c) == '$' || (c) == ',') #if HTTP_PARSER_STRICT #define TOKEN(c) (tokens[(unsigned char)c]) #define IS_URL_CHAR(c) (BIT_AT(normal_url_char, (unsigned char)c)) #define IS_HOST_CHAR(c) (IS_ALPHANUM(c) || (c) == '.' || (c) == '-') #else #define TOKEN(c) ((c == ' ') ? ' ' : tokens[(unsigned char)c]) #define IS_URL_CHAR(c) \ (BIT_AT(normal_url_char, (unsigned char)c) || ((c) & 0x80)) #define IS_HOST_CHAR(c) \ (IS_ALPHANUM(c) || (c) == '.' || (c) == '-' || (c) == '_') #endif #define start_state (parser->type == HTTP_REQUEST ? s_start_req : s_start_res) #if HTTP_PARSER_STRICT # define STRICT_CHECK(cond) \ do { \ if (cond) { \ SET_ERRNO(HPE_STRICT); \ goto error; \ } \ } while (0) # define NEW_MESSAGE() (http_should_keep_alive(parser) ? start_state : s_dead) #else # define STRICT_CHECK(cond) # define NEW_MESSAGE() start_state #endif /* Map errno values to strings for human-readable output */ #define HTTP_STRERROR_GEN(n, s) { "HPE_" #n, s }, static struct { const char *name; const char *description; } http_strerror_tab[] = { HTTP_ERRNO_MAP(HTTP_STRERROR_GEN) }; #undef HTTP_STRERROR_GEN int http_message_needs_eof(const http_parser *parser); /* Our URL parser. * * This is designed to be shared by http_parser_execute() for URL validation, * hence it has a state transition + byte-for-byte interface. In addition, it * is meant to be embedded in http_parser_parse_url(), which does the dirty * work of turning state transitions URL components for its API. * * This function should only be invoked with non-space characters. It is * assumed that the caller cares about (and can detect) the transition between * URL and non-URL states by looking for these. */ static enum state parse_url_char(enum state s, const char ch) { if (ch == ' ' || ch == '\r' || ch == '\n') { return s_dead; } #if HTTP_PARSER_STRICT if (ch == '\t' || ch == '\f') { return s_dead; } #endif switch (s) { case s_req_spaces_before_url: /* Proxied requests are followed by scheme of an absolute URI (alpha). * All methods except CONNECT are followed by '/' or '*'. */ if (ch == '/' || ch == '*') { return s_req_path; } if (IS_ALPHA(ch)) { return s_req_schema; } break; case s_req_schema: if (IS_ALPHA(ch)) { return s; } if (ch == ':') { return s_req_schema_slash; } break; case s_req_schema_slash: if (ch == '/') { return s_req_schema_slash_slash; } break; case s_req_schema_slash_slash: if (ch == '/') { return s_req_server_start; } break; case s_req_server_with_at: if (ch == '@') { return s_dead; } /* FALLTHROUGH */ case s_req_server_start: case s_req_server: if (ch == '/') { return s_req_path; } if (ch == '?') { return s_req_query_string_start; } if (ch == '@') { return s_req_server_with_at; } if (IS_USERINFO_CHAR(ch) || ch == '[' || ch == ']') { return s_req_server; } break; case s_req_path: if (IS_URL_CHAR(ch)) { return s; } switch (ch) { case '?': return s_req_query_string_start; case '#': return s_req_fragment_start; } break; case s_req_query_string_start: case s_req_query_string: if (IS_URL_CHAR(ch)) { return s_req_query_string; } switch (ch) { case '?': /* allow extra '?' in query string */ return s_req_query_string; case '#': return s_req_fragment_start; } break; case s_req_fragment_start: if (IS_URL_CHAR(ch)) { return s_req_fragment; } switch (ch) { case '?': return s_req_fragment; case '#': return s; } break; case s_req_fragment: if (IS_URL_CHAR(ch)) { return s; } switch (ch) { case '?': case '#': return s; } break; default: break; } /* We should never fall out of the switch above unless there's an error */ return s_dead; } size_t http_parser_execute (http_parser *parser, const http_parser_settings *settings, const char *data, size_t len) { char c, ch; int8_t unhex_val; const char *p = data; const char *header_field_mark = 0; const char *header_value_mark = 0; const char *url_mark = 0; const char *body_mark = 0; /* We're in an error state. Don't bother doing anything. */ if (HTTP_PARSER_ERRNO(parser) != HPE_OK) { return 0; } if (len == 0) { switch (parser->state) { case s_body_identity_eof: /* Use of CALLBACK_NOTIFY() here would erroneously return 1 byte read if * we got paused. */ CALLBACK_NOTIFY_NOADVANCE(message_complete); return 0; case s_dead: case s_start_req_or_res: case s_start_res: case s_start_req: return 0; default: SET_ERRNO(HPE_INVALID_EOF_STATE); return 1; } } if (parser->state == s_header_field) header_field_mark = data; if (parser->state == s_header_value) header_value_mark = data; switch (parser->state) { case s_req_path: case s_req_schema: case s_req_schema_slash: case s_req_schema_slash_slash: case s_req_server_start: case s_req_server: case s_req_server_with_at: case s_req_query_string_start: case s_req_query_string: case s_req_fragment_start: case s_req_fragment: url_mark = data; break; } for (p=data; p != data + len; p++) { ch = *p; if (PARSING_HEADER(parser->state)) { ++parser->nread; /* Buffer overflow attack */ if (parser->nread > HTTP_MAX_HEADER_SIZE) { SET_ERRNO(HPE_HEADER_OVERFLOW); goto error; } } reexecute_byte: switch (parser->state) { case s_dead: /* this state is used after a 'Connection: close' message * the parser will error out if it reads another message */ if (ch == CR || ch == LF) break; SET_ERRNO(HPE_CLOSED_CONNECTION); goto error; case s_start_req_or_res: { if (ch == CR || ch == LF) break; parser->flags = 0; parser->content_length = ULLONG_MAX; if (ch == 'H') { parser->state = s_res_or_resp_H; CALLBACK_NOTIFY(message_begin); } else { parser->type = HTTP_REQUEST; parser->state = s_start_req; goto reexecute_byte; } break; } case s_res_or_resp_H: if (ch == 'T') { parser->type = HTTP_RESPONSE; parser->state = s_res_HT; } else { if (ch != 'E') { SET_ERRNO(HPE_INVALID_CONSTANT); goto error; } parser->type = HTTP_REQUEST; parser->method = HTTP_HEAD; parser->index = 2; parser->state = s_req_method; } break; case s_start_res: { parser->flags = 0; parser->content_length = ULLONG_MAX; switch (ch) { case 'H': parser->state = s_res_H; break; case CR: case LF: break; default: SET_ERRNO(HPE_INVALID_CONSTANT); goto error; } CALLBACK_NOTIFY(message_begin); break; } case s_res_H: STRICT_CHECK(ch != 'T'); parser->state = s_res_HT; break; case s_res_HT: STRICT_CHECK(ch != 'T'); parser->state = s_res_HTT; break; case s_res_HTT: STRICT_CHECK(ch != 'P'); parser->state = s_res_HTTP; break; case s_res_HTTP: STRICT_CHECK(ch != '/'); parser->state = s_res_first_http_major; break; case s_res_first_http_major: if (ch < '0' || ch > '9') { SET_ERRNO(HPE_INVALID_VERSION); goto error; } parser->http_major = ch - '0'; parser->state = s_res_http_major; break; /* major HTTP version or dot */ case s_res_http_major: { if (ch == '.') { parser->state = s_res_first_http_minor; break; } if (!IS_NUM(ch)) { SET_ERRNO(HPE_INVALID_VERSION); goto error; } parser->http_major *= 10; parser->http_major += ch - '0'; if (parser->http_major > 999) { SET_ERRNO(HPE_INVALID_VERSION); goto error; } break; } /* first digit of minor HTTP version */ case s_res_first_http_minor: if (!IS_NUM(ch)) { SET_ERRNO(HPE_INVALID_VERSION); goto error; } parser->http_minor = ch - '0'; parser->state = s_res_http_minor; break; /* minor HTTP version or end of request line */ case s_res_http_minor: { if (ch == ' ') { parser->state = s_res_first_status_code; break; } if (!IS_NUM(ch)) { SET_ERRNO(HPE_INVALID_VERSION); goto error; } parser->http_minor *= 10; parser->http_minor += ch - '0'; if (parser->http_minor > 999) { SET_ERRNO(HPE_INVALID_VERSION); goto error; } break; } case s_res_first_status_code: { if (!IS_NUM(ch)) { if (ch == ' ') { break; } SET_ERRNO(HPE_INVALID_STATUS); goto error; } parser->status_code = ch - '0'; parser->state = s_res_status_code; break; } case s_res_status_code: { if (!IS_NUM(ch)) { switch (ch) { case ' ': parser->state = s_res_status; break; case CR: parser->state = s_res_line_almost_done; break; case LF: parser->state = s_header_field_start; break; default: SET_ERRNO(HPE_INVALID_STATUS); goto error; } break; } parser->status_code *= 10; parser->status_code += ch - '0'; if (parser->status_code > 999) { SET_ERRNO(HPE_INVALID_STATUS); goto error; } break; } case s_res_status: /* the human readable status. e.g. "NOT FOUND" * we are not humans so just ignore this */ if (ch == CR) { parser->state = s_res_line_almost_done; break; } if (ch == LF) { parser->state = s_header_field_start; break; } break; case s_res_line_almost_done: STRICT_CHECK(ch != LF); parser->state = s_header_field_start; break; case s_start_req: { if (ch == CR || ch == LF) break; parser->flags = 0; parser->content_length = ULLONG_MAX; if (!IS_ALPHA(ch)) { SET_ERRNO(HPE_INVALID_METHOD); goto error; } parser->method = (enum http_method) 0; parser->index = 1; switch (ch) { case 'C': parser->method = HTTP_CONNECT; /* or COPY, CHECKOUT */ break; case 'D': parser->method = HTTP_DELETE; break; case 'G': parser->method = HTTP_GET; break; case 'H': parser->method = HTTP_HEAD; break; case 'L': parser->method = HTTP_LOCK; break; case 'M': parser->method = HTTP_MKCOL; /* or MOVE, MKACTIVITY, MERGE, M-SEARCH */ break; case 'N': parser->method = HTTP_NOTIFY; break; case 'O': parser->method = HTTP_OPTIONS; break; case 'P': parser->method = HTTP_POST; /* or PROPFIND|PROPPATCH|PUT|PATCH|PURGE */ break; case 'R': parser->method = HTTP_REPORT; break; case 'S': parser->method = HTTP_SUBSCRIBE; /* or SEARCH */ break; case 'T': parser->method = HTTP_TRACE; break; case 'U': parser->method = HTTP_UNLOCK; /* or UNSUBSCRIBE */ break; default: SET_ERRNO(HPE_INVALID_METHOD); goto error; } parser->state = s_req_method; CALLBACK_NOTIFY(message_begin); break; } case s_req_method: { const char *matcher; if (ch == '\0') { SET_ERRNO(HPE_INVALID_METHOD); goto error; } matcher = method_strings[parser->method]; if (ch == ' ' && matcher[parser->index] == '\0') { parser->state = s_req_spaces_before_url; } else if (ch == matcher[parser->index]) { ; /* nada */ } else if (parser->method == HTTP_CONNECT) { if (parser->index == 1 && ch == 'H') { parser->method = HTTP_CHECKOUT; } else if (parser->index == 2 && ch == 'P') { parser->method = HTTP_COPY; } else { goto error; } } else if (parser->method == HTTP_MKCOL) { if (parser->index == 1 && ch == 'O') { parser->method = HTTP_MOVE; } else if (parser->index == 1 && ch == 'E') { parser->method = HTTP_MERGE; } else if (parser->index == 1 && ch == '-') { parser->method = HTTP_MSEARCH; } else if (parser->index == 2 && ch == 'A') { parser->method = HTTP_MKACTIVITY; } else { goto error; } } else if (parser->method == HTTP_SUBSCRIBE) { if (parser->index == 1 && ch == 'E') { parser->method = HTTP_SEARCH; } else { goto error; } } else if (parser->index == 1 && parser->method == HTTP_POST) { if (ch == 'R') { parser->method = HTTP_PROPFIND; /* or HTTP_PROPPATCH */ } else if (ch == 'U') { parser->method = HTTP_PUT; /* or HTTP_PURGE */ } else if (ch == 'A') { parser->method = HTTP_PATCH; } else { goto error; } } else if (parser->index == 2) { if (parser->method == HTTP_PUT) { if (ch == 'R') parser->method = HTTP_PURGE; } else if (parser->method == HTTP_UNLOCK) { if (ch == 'S') parser->method = HTTP_UNSUBSCRIBE; } } else if (parser->index == 4 && parser->method == HTTP_PROPFIND && ch == 'P') { parser->method = HTTP_PROPPATCH; } else { SET_ERRNO(HPE_INVALID_METHOD); goto error; } ++parser->index; break; } case s_req_spaces_before_url: { if (ch == ' ') break; MARK(url); if (parser->method == HTTP_CONNECT) { parser->state = s_req_server_start; } parser->state = parse_url_char((enum state)parser->state, ch); if (parser->state == s_dead) { SET_ERRNO(HPE_INVALID_URL); goto error; } break; } case s_req_schema: case s_req_schema_slash: case s_req_schema_slash_slash: case s_req_server_start: { switch (ch) { /* No whitespace allowed here */ case ' ': case CR: case LF: SET_ERRNO(HPE_INVALID_URL); goto error; default: parser->state = parse_url_char((enum state)parser->state, ch); if (parser->state == s_dead) { SET_ERRNO(HPE_INVALID_URL); goto error; } } break; } case s_req_server: case s_req_server_with_at: case s_req_path: case s_req_query_string_start: case s_req_query_string: case s_req_fragment_start: case s_req_fragment: { switch (ch) { case ' ': parser->state = s_req_http_start; CALLBACK_DATA(url); break; case CR: case LF: parser->http_major = 0; parser->http_minor = 9; parser->state = (ch == CR) ? s_req_line_almost_done : s_header_field_start; CALLBACK_DATA(url); break; default: parser->state = parse_url_char((enum state)parser->state, ch); if (parser->state == s_dead) { SET_ERRNO(HPE_INVALID_URL); goto error; } } break; } case s_req_http_start: switch (ch) { case 'H': parser->state = s_req_http_H; break; case ' ': break; default: SET_ERRNO(HPE_INVALID_CONSTANT); goto error; } break; case s_req_http_H: STRICT_CHECK(ch != 'T'); parser->state = s_req_http_HT; break; case s_req_http_HT: STRICT_CHECK(ch != 'T'); parser->state = s_req_http_HTT; break; case s_req_http_HTT: STRICT_CHECK(ch != 'P'); parser->state = s_req_http_HTTP; break; case s_req_http_HTTP: STRICT_CHECK(ch != '/'); parser->state = s_req_first_http_major; break; /* first digit of major HTTP version */ case s_req_first_http_major: if (ch < '1' || ch > '9') { SET_ERRNO(HPE_INVALID_VERSION); goto error; } parser->http_major = ch - '0'; parser->state = s_req_http_major; break; /* major HTTP version or dot */ case s_req_http_major: { if (ch == '.') { parser->state = s_req_first_http_minor; break; } if (!IS_NUM(ch)) { SET_ERRNO(HPE_INVALID_VERSION); goto error; } parser->http_major *= 10; parser->http_major += ch - '0'; if (parser->http_major > 999) { SET_ERRNO(HPE_INVALID_VERSION); goto error; } break; } /* first digit of minor HTTP version */ case s_req_first_http_minor: if (!IS_NUM(ch)) { SET_ERRNO(HPE_INVALID_VERSION); goto error; } parser->http_minor = ch - '0'; parser->state = s_req_http_minor; break; /* minor HTTP version or end of request line */ case s_req_http_minor: { if (ch == CR) { parser->state = s_req_line_almost_done; break; } if (ch == LF) { parser->state = s_header_field_start; break; } /* XXX allow spaces after digit? */ if (!IS_NUM(ch)) { SET_ERRNO(HPE_INVALID_VERSION); goto error; } parser->http_minor *= 10; parser->http_minor += ch - '0'; if (parser->http_minor > 999) { SET_ERRNO(HPE_INVALID_VERSION); goto error; } break; } /* end of request line */ case s_req_line_almost_done: { if (ch != LF) { SET_ERRNO(HPE_LF_EXPECTED); goto error; } parser->state = s_header_field_start; break; } case s_header_field_start: { if (ch == CR) { parser->state = s_headers_almost_done; break; } if (ch == LF) { /* they might be just sending \n instead of \r\n so this would be * the second \n to denote the end of headers*/ parser->state = s_headers_almost_done; goto reexecute_byte; } c = TOKEN(ch); if (!c) { SET_ERRNO(HPE_INVALID_HEADER_TOKEN); goto error; } MARK(header_field); parser->index = 0; parser->state = s_header_field; switch (c) { case 'c': parser->header_state = h_C; break; case 'p': parser->header_state = h_matching_proxy_connection; break; case 't': parser->header_state = h_matching_transfer_encoding; break; case 'u': parser->header_state = h_matching_upgrade; break; default: parser->header_state = h_general; break; } break; } case s_header_field: { c = TOKEN(ch); if (c) { switch (parser->header_state) { case h_general: break; case h_C: parser->index++; parser->header_state = (c == 'o' ? h_CO : h_general); break; case h_CO: parser->index++; parser->header_state = (c == 'n' ? h_CON : h_general); break; case h_CON: parser->index++; switch (c) { case 'n': parser->header_state = h_matching_connection; break; case 't': parser->header_state = h_matching_content_length; break; default: parser->header_state = h_general; break; } break; /* connection */ case h_matching_connection: parser->index++; if (parser->index > sizeof(CONNECTION)-1 || c != CONNECTION[parser->index]) { parser->header_state = h_general; } else if (parser->index == sizeof(CONNECTION)-2) { parser->header_state = h_connection; } break; /* proxy-connection */ case h_matching_proxy_connection: parser->index++; if (parser->index > sizeof(PROXY_CONNECTION)-1 || c != PROXY_CONNECTION[parser->index]) { parser->header_state = h_general; } else if (parser->index == sizeof(PROXY_CONNECTION)-2) { parser->header_state = h_connection; } break; /* content-length */ case h_matching_content_length: parser->index++; if (parser->index > sizeof(CONTENT_LENGTH)-1 || c != CONTENT_LENGTH[parser->index]) { parser->header_state = h_general; } else if (parser->index == sizeof(CONTENT_LENGTH)-2) { parser->header_state = h_content_length; } break; /* transfer-encoding */ case h_matching_transfer_encoding: parser->index++; if (parser->index > sizeof(TRANSFER_ENCODING)-1 || c != TRANSFER_ENCODING[parser->index]) { parser->header_state = h_general; } else if (parser->index == sizeof(TRANSFER_ENCODING)-2) { parser->header_state = h_transfer_encoding; } break; /* upgrade */ case h_matching_upgrade: parser->index++; if (parser->index > sizeof(UPGRADE)-1 || c != UPGRADE[parser->index]) { parser->header_state = h_general; } else if (parser->index == sizeof(UPGRADE)-2) { parser->header_state = h_upgrade; } break; case h_connection: case h_content_length: case h_transfer_encoding: case h_upgrade: if (ch != ' ') parser->header_state = h_general; break; default: assert(0 && "Unknown header_state"); break; } break; } if (ch == ':') { parser->state = s_header_value_start; CALLBACK_DATA(header_field); break; } if (ch == CR) { parser->state = s_header_almost_done; CALLBACK_DATA(header_field); break; } if (ch == LF) { parser->state = s_header_field_start; CALLBACK_DATA(header_field); break; } SET_ERRNO(HPE_INVALID_HEADER_TOKEN); goto error; } case s_header_value_start: { if (ch == ' ' || ch == '\t') break; MARK(header_value); parser->state = s_header_value; parser->index = 0; if (ch == CR) { parser->header_state = h_general; parser->state = s_header_almost_done; CALLBACK_DATA(header_value); break; } if (ch == LF) { parser->state = s_header_field_start; CALLBACK_DATA(header_value); break; } c = LOWER(ch); switch (parser->header_state) { case h_upgrade: parser->flags |= F_UPGRADE; parser->header_state = h_general; break; case h_transfer_encoding: /* looking for 'Transfer-Encoding: chunked' */ if ('c' == c) { parser->header_state = h_matching_transfer_encoding_chunked; } else { parser->header_state = h_general; } break; case h_content_length: if (!IS_NUM(ch)) { SET_ERRNO(HPE_INVALID_CONTENT_LENGTH); goto error; } parser->content_length = ch - '0'; break; case h_connection: /* looking for 'Connection: keep-alive' */ if (c == 'k') { parser->header_state = h_matching_connection_keep_alive; /* looking for 'Connection: close' */ } else if (c == 'c') { parser->header_state = h_matching_connection_close; } else { parser->header_state = h_general; } break; default: parser->header_state = h_general; break; } break; } case s_header_value: { if (ch == CR) { parser->state = s_header_almost_done; CALLBACK_DATA(header_value); break; } if (ch == LF) { parser->state = s_header_almost_done; CALLBACK_DATA_NOADVANCE(header_value); goto reexecute_byte; } c = LOWER(ch); switch (parser->header_state) { case h_general: break; case h_connection: case h_transfer_encoding: assert(0 && "Shouldn't get here."); break; case h_content_length: { uint64_t t; if (ch == ' ') break; if (!IS_NUM(ch)) { SET_ERRNO(HPE_INVALID_CONTENT_LENGTH); goto error; } t = parser->content_length; t *= 10; t += ch - '0'; /* Overflow? */ if (t < parser->content_length || t == ULLONG_MAX) { SET_ERRNO(HPE_INVALID_CONTENT_LENGTH); goto error; } parser->content_length = t; break; } /* Transfer-Encoding: chunked */ case h_matching_transfer_encoding_chunked: parser->index++; if (parser->index > sizeof(CHUNKED)-1 || c != CHUNKED[parser->index]) { parser->header_state = h_general; } else if (parser->index == sizeof(CHUNKED)-2) { parser->header_state = h_transfer_encoding_chunked; } break; /* looking for 'Connection: keep-alive' */ case h_matching_connection_keep_alive: parser->index++; if (parser->index > sizeof(KEEP_ALIVE)-1 || c != KEEP_ALIVE[parser->index]) { parser->header_state = h_general; } else if (parser->index == sizeof(KEEP_ALIVE)-2) { parser->header_state = h_connection_keep_alive; } break; /* looking for 'Connection: close' */ case h_matching_connection_close: parser->index++; if (parser->index > sizeof(CLOSE)-1 || c != CLOSE[parser->index]) { parser->header_state = h_general; } else if (parser->index == sizeof(CLOSE)-2) { parser->header_state = h_connection_close; } break; case h_transfer_encoding_chunked: case h_connection_keep_alive: case h_connection_close: if (ch != ' ') parser->header_state = h_general; break; default: parser->state = s_header_value; parser->header_state = h_general; break; } break; } case s_header_almost_done: { STRICT_CHECK(ch != LF); parser->state = s_header_value_lws; switch (parser->header_state) { case h_connection_keep_alive: parser->flags |= F_CONNECTION_KEEP_ALIVE; break; case h_connection_close: parser->flags |= F_CONNECTION_CLOSE; break; case h_transfer_encoding_chunked: parser->flags |= F_CHUNKED; break; default: break; } break; } case s_header_value_lws: { if (ch == ' ' || ch == '\t') parser->state = s_header_value_start; else { parser->state = s_header_field_start; goto reexecute_byte; } break; } case s_headers_almost_done: { STRICT_CHECK(ch != LF); if (parser->flags & F_TRAILING) { /* End of a chunked request */ parser->state = NEW_MESSAGE(); CALLBACK_NOTIFY(message_complete); break; } parser->state = s_headers_done; /* Set this here so that on_headers_complete() callbacks can see it */ parser->upgrade = (parser->flags & F_UPGRADE || parser->method == HTTP_CONNECT); /* Here we call the headers_complete callback. This is somewhat * different than other callbacks because if the user returns 1, we * will interpret that as saying that this message has no body. This * is needed for the annoying case of recieving a response to a HEAD * request. * * We'd like to use CALLBACK_NOTIFY_NOADVANCE() here but we cannot, so * we have to simulate it by handling a change in errno below. */ if (settings->on_headers_complete) { switch (settings->on_headers_complete(parser)) { case 0: break; case 1: parser->flags |= F_SKIPBODY; break; default: SET_ERRNO(HPE_CB_headers_complete); return p - data; /* Error */ } } if (HTTP_PARSER_ERRNO(parser) != HPE_OK) { return p - data; } goto reexecute_byte; } case s_headers_done: { STRICT_CHECK(ch != LF); parser->nread = 0; /* Exit, the rest of the connect is in a different protocol. */ if (parser->upgrade) { parser->state = NEW_MESSAGE(); CALLBACK_NOTIFY(message_complete); return (p - data) + 1; } if (parser->flags & F_SKIPBODY) { parser->state = NEW_MESSAGE(); CALLBACK_NOTIFY(message_complete); } else if (parser->flags & F_CHUNKED) { /* chunked encoding - ignore Content-Length header */ parser->state = s_chunk_size_start; } else { if (parser->content_length == 0) { /* Content-Length header given but zero: Content-Length: 0\r\n */ parser->state = NEW_MESSAGE(); CALLBACK_NOTIFY(message_complete); } else if (parser->content_length != ULLONG_MAX) { /* Content-Length header given and non-zero */ parser->state = s_body_identity; } else { if (parser->type == HTTP_REQUEST || !http_message_needs_eof(parser)) { /* Assume content-length 0 - read the next */ parser->state = NEW_MESSAGE(); CALLBACK_NOTIFY(message_complete); } else { /* Read body until EOF */ parser->state = s_body_identity_eof; } } } break; } case s_body_identity: { uint64_t to_read = MIN(parser->content_length, (uint64_t) ((data + len) - p)); assert(parser->content_length != 0 && parser->content_length != ULLONG_MAX); /* The difference between advancing content_length and p is because * the latter will automaticaly advance on the next loop iteration. * Further, if content_length ends up at 0, we want to see the last * byte again for our message complete callback. */ MARK(body); parser->content_length -= to_read; p += to_read - 1; if (parser->content_length == 0) { parser->state = s_message_done; /* Mimic CALLBACK_DATA_NOADVANCE() but with one extra byte. * * The alternative to doing this is to wait for the next byte to * trigger the data callback, just as in every other case. The * problem with this is that this makes it difficult for the test * harness to distinguish between complete-on-EOF and * complete-on-length. It's not clear that this distinction is * important for applications, but let's keep it for now. */ CALLBACK_DATA_(body, p - body_mark + 1, p - data); goto reexecute_byte; } break; } /* read until EOF */ case s_body_identity_eof: MARK(body); p = data + len - 1; break; case s_message_done: parser->state = NEW_MESSAGE(); CALLBACK_NOTIFY(message_complete); break; case s_chunk_size_start: { assert(parser->nread == 1); assert(parser->flags & F_CHUNKED); unhex_val = unhex[(unsigned char)ch]; if (unhex_val == -1) { SET_ERRNO(HPE_INVALID_CHUNK_SIZE); goto error; } parser->content_length = unhex_val; parser->state = s_chunk_size; break; } case s_chunk_size: { uint64_t t; assert(parser->flags & F_CHUNKED); if (ch == CR) { parser->state = s_chunk_size_almost_done; break; } unhex_val = unhex[(unsigned char)ch]; if (unhex_val == -1) { if (ch == ';' || ch == ' ') { parser->state = s_chunk_parameters; break; } SET_ERRNO(HPE_INVALID_CHUNK_SIZE); goto error; } t = parser->content_length; t *= 16; t += unhex_val; /* Overflow? */ if (t < parser->content_length || t == ULLONG_MAX) { SET_ERRNO(HPE_INVALID_CONTENT_LENGTH); goto error; } parser->content_length = t; break; } case s_chunk_parameters: { assert(parser->flags & F_CHUNKED); /* just ignore this. TODO check for overflow */ if (ch == CR) { parser->state = s_chunk_size_almost_done; break; } break; } case s_chunk_size_almost_done: { assert(parser->flags & F_CHUNKED); STRICT_CHECK(ch != LF); parser->nread = 0; if (parser->content_length == 0) { parser->flags |= F_TRAILING; parser->state = s_header_field_start; } else { parser->state = s_chunk_data; } break; } case s_chunk_data: { uint64_t to_read = MIN(parser->content_length, (uint64_t) ((data + len) - p)); assert(parser->flags & F_CHUNKED); assert(parser->content_length != 0 && parser->content_length != ULLONG_MAX); /* See the explanation in s_body_identity for why the content * length and data pointers are managed this way. */ MARK(body); parser->content_length -= to_read; p += to_read - 1; if (parser->content_length == 0) { parser->state = s_chunk_data_almost_done; } break; } case s_chunk_data_almost_done: assert(parser->flags & F_CHUNKED); assert(parser->content_length == 0); STRICT_CHECK(ch != CR); parser->state = s_chunk_data_done; CALLBACK_DATA(body); break; case s_chunk_data_done: assert(parser->flags & F_CHUNKED); STRICT_CHECK(ch != LF); parser->nread = 0; parser->state = s_chunk_size_start; break; default: assert(0 && "unhandled state"); SET_ERRNO(HPE_INVALID_INTERNAL_STATE); goto error; } } /* Run callbacks for any marks that we have leftover after we ran our of * bytes. There should be at most one of these set, so it's OK to invoke * them in series (unset marks will not result in callbacks). * * We use the NOADVANCE() variety of callbacks here because 'p' has already * overflowed 'data' and this allows us to correct for the off-by-one that * we'd otherwise have (since CALLBACK_DATA() is meant to be run with a 'p' * value that's in-bounds). */ assert(((header_field_mark ? 1 : 0) + (header_value_mark ? 1 : 0) + (url_mark ? 1 : 0) + (body_mark ? 1 : 0)) <= 1); CALLBACK_DATA_NOADVANCE(header_field); CALLBACK_DATA_NOADVANCE(header_value); CALLBACK_DATA_NOADVANCE(url); CALLBACK_DATA_NOADVANCE(body); return len; error: if (HTTP_PARSER_ERRNO(parser) == HPE_OK) { SET_ERRNO(HPE_UNKNOWN); } return (p - data); } /* Does the parser need to see an EOF to find the end of the message? */ int http_message_needs_eof (const http_parser *parser) { if (parser->type == HTTP_REQUEST) { return 0; } /* See RFC 2616 section 4.4 */ if (parser->status_code / 100 == 1 || /* 1xx e.g. Continue */ parser->status_code == 204 || /* No Content */ parser->status_code == 304 || /* Not Modified */ parser->flags & F_SKIPBODY) { /* response to a HEAD request */ return 0; } if ((parser->flags & F_CHUNKED) || parser->content_length != ULLONG_MAX) { return 0; } return 1; } int http_should_keep_alive (const http_parser *parser) { if (parser->http_major > 0 && parser->http_minor > 0) { /* HTTP/1.1 */ if (parser->flags & F_CONNECTION_CLOSE) { return 0; } } else { /* HTTP/1.0 or earlier */ if (!(parser->flags & F_CONNECTION_KEEP_ALIVE)) { return 0; } } return !http_message_needs_eof(parser); } const char * http_method_str (enum http_method m) { return ELEM_AT(method_strings, m, ""); } void http_parser_init (http_parser *parser, enum http_parser_type t) { void *data = parser->data; /* preserve application data */ memset(parser, 0, sizeof(*parser)); parser->data = data; parser->type = t; parser->state = (t == HTTP_REQUEST ? s_start_req : (t == HTTP_RESPONSE ? s_start_res : s_start_req_or_res)); parser->http_errno = HPE_OK; } const char * http_errno_name(enum http_errno err) { assert(err < (sizeof(http_strerror_tab)/sizeof(http_strerror_tab[0]))); return http_strerror_tab[err].name; } const char * http_errno_description(enum http_errno err) { assert(err < (sizeof(http_strerror_tab)/sizeof(http_strerror_tab[0]))); return http_strerror_tab[err].description; } static enum http_host_state http_parse_host_char(enum http_host_state s, const char ch) { switch(s) { case s_http_userinfo: case s_http_userinfo_start: if (ch == '@') { return s_http_host_start; } if (IS_USERINFO_CHAR(ch)) { return s_http_userinfo; } break; case s_http_host_start: if (ch == '[') { return s_http_host_v6_start; } if (IS_HOST_CHAR(ch)) { return s_http_host; } break; case s_http_host: if (IS_HOST_CHAR(ch)) { return s_http_host; } /* FALLTHROUGH */ case s_http_host_v6_end: if (ch == ':') { return s_http_host_port_start; } break; case s_http_host_v6: if (ch == ']') { return s_http_host_v6_end; } /* FALLTHROUGH */ case s_http_host_v6_start: if (IS_HEX(ch) || ch == ':') { return s_http_host_v6; } break; case s_http_host_port: case s_http_host_port_start: if (IS_NUM(ch)) { return s_http_host_port; } break; default: break; } return s_http_host_dead; } static int http_parse_host(const char * buf, struct http_parser_url *u, int found_at) { enum http_host_state s; const char *p; size_t buflen = u->field_data[UF_HOST].off + u->field_data[UF_HOST].len; u->field_data[UF_HOST].len = 0; s = found_at ? s_http_userinfo_start : s_http_host_start; for (p = buf + u->field_data[UF_HOST].off; p < buf + buflen; p++) { enum http_host_state new_s = http_parse_host_char(s, *p); if (new_s == s_http_host_dead) { return 1; } switch(new_s) { case s_http_host: if (s != s_http_host) { u->field_data[UF_HOST].off = p - buf; } u->field_data[UF_HOST].len++; break; case s_http_host_v6: if (s != s_http_host_v6) { u->field_data[UF_HOST].off = p - buf; } u->field_data[UF_HOST].len++; break; case s_http_host_port: if (s != s_http_host_port) { u->field_data[UF_PORT].off = p - buf; u->field_data[UF_PORT].len = 0; u->field_set |= (1 << UF_PORT); } u->field_data[UF_PORT].len++; break; case s_http_userinfo: if (s != s_http_userinfo) { u->field_data[UF_USERINFO].off = p - buf ; u->field_data[UF_USERINFO].len = 0; u->field_set |= (1 << UF_USERINFO); } u->field_data[UF_USERINFO].len++; break; default: break; } s = new_s; } /* Make sure we don't end somewhere unexpected */ switch (s) { case s_http_host_start: case s_http_host_v6_start: case s_http_host_v6: case s_http_host_port_start: case s_http_userinfo: case s_http_userinfo_start: return 1; default: break; } return 0; } int http_parser_parse_url(const char *buf, size_t buflen, int is_connect, struct http_parser_url *u) { enum state s; const char *p; enum http_parser_url_fields uf, old_uf; int found_at = 0; u->port = u->field_set = 0; s = is_connect ? s_req_server_start : s_req_spaces_before_url; uf = old_uf = UF_MAX; for (p = buf; p < buf + buflen; p++) { s = parse_url_char(s, *p); /* Figure out the next field that we're operating on */ switch (s) { case s_dead: return 1; /* Skip delimeters */ case s_req_schema_slash: case s_req_schema_slash_slash: case s_req_server_start: case s_req_query_string_start: case s_req_fragment_start: continue; case s_req_schema: uf = UF_SCHEMA; break; case s_req_server_with_at: found_at = 1; /* FALLTROUGH */ case s_req_server: uf = UF_HOST; break; case s_req_path: uf = UF_PATH; break; case s_req_query_string: uf = UF_QUERY; break; case s_req_fragment: uf = UF_FRAGMENT; break; default: assert(!"Unexpected state"); return 1; } /* Nothing's changed; soldier on */ if (uf == old_uf) { u->field_data[uf].len++; continue; } u->field_data[uf].off = p - buf; u->field_data[uf].len = 1; u->field_set |= (1 << uf); old_uf = uf; } /* host must be present if there is a schema */ /* parsing http:///toto will fail */ if ((u->field_set & ((1 << UF_SCHEMA) | (1 << UF_HOST))) != 0) { if (http_parse_host(buf, u, found_at) != 0) { return 1; } } /* CONNECT requests can only contain "hostname:port" */ if (is_connect && u->field_set != ((1 << UF_HOST)|(1 << UF_PORT))) { return 1; } if (u->field_set & (1 << UF_PORT)) { /* Don't bother with endp; we've already validated the string */ unsigned long v = strtoul(buf + u->field_data[UF_PORT].off, NULL, 10); /* Ports have a max value of 2^16 */ if (v > 0xffff) { return 1; } u->port = (uint16_t) v; } return 0; } void http_parser_pause(http_parser *parser, int paused) { /* Users should only be pausing/unpausing a parser that is not in an error * state. In non-debug builds, there's not much that we can do about this * other than ignore it. */ if (HTTP_PARSER_ERRNO(parser) == HPE_OK || HTTP_PARSER_ERRNO(parser) == HPE_PAUSED) { SET_ERRNO((paused) ? HPE_PAUSED : HPE_OK); } else { assert(0 && "Attempting to pause parser in error state"); } } int http_body_is_final(const struct http_parser *parser) { return parser->state == s_message_done; } libgit2-0.19.0/deps/http-parser/http_parser.h000066400000000000000000000260561216214232500210540ustar00rootroot00000000000000/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. */ #ifndef http_parser_h #define http_parser_h #ifdef __cplusplus extern "C" { #endif #define HTTP_PARSER_VERSION_MAJOR 2 #define HTTP_PARSER_VERSION_MINOR 0 #include #if defined(_WIN32) && !defined(__MINGW32__) && (!defined(_MSC_VER) || _MSC_VER<1600) #include typedef __int8 int8_t; typedef unsigned __int8 uint8_t; typedef __int16 int16_t; typedef unsigned __int16 uint16_t; typedef __int32 int32_t; typedef unsigned __int32 uint32_t; typedef __int64 int64_t; typedef unsigned __int64 uint64_t; typedef SIZE_T size_t; typedef SSIZE_T ssize_t; #else #include #endif /* Compile with -DHTTP_PARSER_STRICT=0 to make less checks, but run * faster */ #ifndef HTTP_PARSER_STRICT # define HTTP_PARSER_STRICT 1 #endif /* Maximium header size allowed */ #define HTTP_MAX_HEADER_SIZE (80*1024) typedef struct http_parser http_parser; typedef struct http_parser_settings http_parser_settings; /* Callbacks should return non-zero to indicate an error. The parser will * then halt execution. * * The one exception is on_headers_complete. In a HTTP_RESPONSE parser * returning '1' from on_headers_complete will tell the parser that it * should not expect a body. This is used when receiving a response to a * HEAD request which may contain 'Content-Length' or 'Transfer-Encoding: * chunked' headers that indicate the presence of a body. * * http_data_cb does not return data chunks. It will be call arbitrarally * many times for each string. E.G. you might get 10 callbacks for "on_url" * each providing just a few characters more data. */ typedef int (*http_data_cb) (http_parser*, const char *at, size_t length); typedef int (*http_cb) (http_parser*); /* Request Methods */ #define HTTP_METHOD_MAP(XX) \ XX(0, DELETE, DELETE) \ XX(1, GET, GET) \ XX(2, HEAD, HEAD) \ XX(3, POST, POST) \ XX(4, PUT, PUT) \ /* pathological */ \ XX(5, CONNECT, CONNECT) \ XX(6, OPTIONS, OPTIONS) \ XX(7, TRACE, TRACE) \ /* webdav */ \ XX(8, COPY, COPY) \ XX(9, LOCK, LOCK) \ XX(10, MKCOL, MKCOL) \ XX(11, MOVE, MOVE) \ XX(12, PROPFIND, PROPFIND) \ XX(13, PROPPATCH, PROPPATCH) \ XX(14, SEARCH, SEARCH) \ XX(15, UNLOCK, UNLOCK) \ /* subversion */ \ XX(16, REPORT, REPORT) \ XX(17, MKACTIVITY, MKACTIVITY) \ XX(18, CHECKOUT, CHECKOUT) \ XX(19, MERGE, MERGE) \ /* upnp */ \ XX(20, MSEARCH, M-SEARCH) \ XX(21, NOTIFY, NOTIFY) \ XX(22, SUBSCRIBE, SUBSCRIBE) \ XX(23, UNSUBSCRIBE, UNSUBSCRIBE) \ /* RFC-5789 */ \ XX(24, PATCH, PATCH) \ XX(25, PURGE, PURGE) \ enum http_method { #define XX(num, name, string) HTTP_##name = num, HTTP_METHOD_MAP(XX) #undef XX }; enum http_parser_type { HTTP_REQUEST, HTTP_RESPONSE, HTTP_BOTH }; /* Flag values for http_parser.flags field */ enum flags { F_CHUNKED = 1 << 0 , F_CONNECTION_KEEP_ALIVE = 1 << 1 , F_CONNECTION_CLOSE = 1 << 2 , F_TRAILING = 1 << 3 , F_UPGRADE = 1 << 4 , F_SKIPBODY = 1 << 5 }; /* Map for errno-related constants * * The provided argument should be a macro that takes 2 arguments. */ #define HTTP_ERRNO_MAP(XX) \ /* No error */ \ XX(OK, "success") \ \ /* Callback-related errors */ \ XX(CB_message_begin, "the on_message_begin callback failed") \ XX(CB_url, "the on_url callback failed") \ XX(CB_header_field, "the on_header_field callback failed") \ XX(CB_header_value, "the on_header_value callback failed") \ XX(CB_headers_complete, "the on_headers_complete callback failed") \ XX(CB_body, "the on_body callback failed") \ XX(CB_message_complete, "the on_message_complete callback failed") \ \ /* Parsing-related errors */ \ XX(INVALID_EOF_STATE, "stream ended at an unexpected time") \ XX(HEADER_OVERFLOW, \ "too many header bytes seen; overflow detected") \ XX(CLOSED_CONNECTION, \ "data received after completed connection: close message") \ XX(INVALID_VERSION, "invalid HTTP version") \ XX(INVALID_STATUS, "invalid HTTP status code") \ XX(INVALID_METHOD, "invalid HTTP method") \ XX(INVALID_URL, "invalid URL") \ XX(INVALID_HOST, "invalid host") \ XX(INVALID_PORT, "invalid port") \ XX(INVALID_PATH, "invalid path") \ XX(INVALID_QUERY_STRING, "invalid query string") \ XX(INVALID_FRAGMENT, "invalid fragment") \ XX(LF_EXPECTED, "LF character expected") \ XX(INVALID_HEADER_TOKEN, "invalid character in header") \ XX(INVALID_CONTENT_LENGTH, \ "invalid character in content-length header") \ XX(INVALID_CHUNK_SIZE, \ "invalid character in chunk size header") \ XX(INVALID_CONSTANT, "invalid constant string") \ XX(INVALID_INTERNAL_STATE, "encountered unexpected internal state")\ XX(STRICT, "strict mode assertion failed") \ XX(PAUSED, "parser is paused") \ XX(UNKNOWN, "an unknown error occurred") /* Define HPE_* values for each errno value above */ #define HTTP_ERRNO_GEN(n, s) HPE_##n, enum http_errno { HTTP_ERRNO_MAP(HTTP_ERRNO_GEN) }; #undef HTTP_ERRNO_GEN /* Get an http_errno value from an http_parser */ #define HTTP_PARSER_ERRNO(p) ((enum http_errno) (p)->http_errno) struct http_parser { /** PRIVATE **/ unsigned char type : 2; /* enum http_parser_type */ unsigned char flags : 6; /* F_* values from 'flags' enum; semi-public */ unsigned char state; /* enum state from http_parser.c */ unsigned char header_state; /* enum header_state from http_parser.c */ unsigned char index; /* index into current matcher */ uint32_t nread; /* # bytes read in various scenarios */ uint64_t content_length; /* # bytes in body (0 if no Content-Length header) */ /** READ-ONLY **/ unsigned short http_major; unsigned short http_minor; unsigned short status_code; /* responses only */ unsigned char method; /* requests only */ unsigned char http_errno : 7; /* 1 = Upgrade header was present and the parser has exited because of that. * 0 = No upgrade header present. * Should be checked when http_parser_execute() returns in addition to * error checking. */ unsigned char upgrade : 1; /** PUBLIC **/ void *data; /* A pointer to get hook to the "connection" or "socket" object */ }; struct http_parser_settings { http_cb on_message_begin; http_data_cb on_url; http_data_cb on_header_field; http_data_cb on_header_value; http_cb on_headers_complete; http_data_cb on_body; http_cb on_message_complete; }; enum http_parser_url_fields { UF_SCHEMA = 0 , UF_HOST = 1 , UF_PORT = 2 , UF_PATH = 3 , UF_QUERY = 4 , UF_FRAGMENT = 5 , UF_USERINFO = 6 , UF_MAX = 7 }; /* Result structure for http_parser_parse_url(). * * Callers should index into field_data[] with UF_* values iff field_set * has the relevant (1 << UF_*) bit set. As a courtesy to clients (and * because we probably have padding left over), we convert any port to * a uint16_t. */ struct http_parser_url { uint16_t field_set; /* Bitmask of (1 << UF_*) values */ uint16_t port; /* Converted UF_PORT string */ struct { uint16_t off; /* Offset into buffer in which field starts */ uint16_t len; /* Length of run in buffer */ } field_data[UF_MAX]; }; void http_parser_init(http_parser *parser, enum http_parser_type type); size_t http_parser_execute(http_parser *parser, const http_parser_settings *settings, const char *data, size_t len); /* If http_should_keep_alive() in the on_headers_complete or * on_message_complete callback returns 0, then this should be * the last message on the connection. * If you are the server, respond with the "Connection: close" header. * If you are the client, close the connection. */ int http_should_keep_alive(const http_parser *parser); /* Returns a string version of the HTTP method. */ const char *http_method_str(enum http_method m); /* Return a string name of the given error */ const char *http_errno_name(enum http_errno err); /* Return a string description of the given error */ const char *http_errno_description(enum http_errno err); /* Parse a URL; return nonzero on failure */ int http_parser_parse_url(const char *buf, size_t buflen, int is_connect, struct http_parser_url *u); /* Pause or un-pause the parser; a nonzero value pauses */ void http_parser_pause(http_parser *parser, int paused); /* Checks if this is the final chunk of the body. */ int http_body_is_final(const http_parser *parser); #ifdef __cplusplus } #endif #endif libgit2-0.19.0/deps/regex/000077500000000000000000000000001216214232500152005ustar00rootroot00000000000000libgit2-0.19.0/deps/regex/config.h000066400000000000000000000001371216214232500166170ustar00rootroot00000000000000#ifndef _REGEX_CONFIG_H_ #define _REGEX_CONFIG_H_ # define GAWK # define NO_MBSUPPORT #endif libgit2-0.19.0/deps/regex/regcomp.c000066400000000000000000003310121216214232500170000ustar00rootroot00000000000000/* Extended regular expression matching and search library. Copyright (C) 2002-2007,2009,2010 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Isamu Hasegawa . The GNU C Library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. The GNU C Library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with the GNU C Library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ static reg_errcode_t re_compile_internal (regex_t *preg, const char * pattern, size_t length, reg_syntax_t syntax); static void re_compile_fastmap_iter (regex_t *bufp, const re_dfastate_t *init_state, char *fastmap); static reg_errcode_t init_dfa (re_dfa_t *dfa, size_t pat_len); #ifdef RE_ENABLE_I18N static void free_charset (re_charset_t *cset); #endif /* RE_ENABLE_I18N */ static void free_workarea_compile (regex_t *preg); static reg_errcode_t create_initial_state (re_dfa_t *dfa); #ifdef RE_ENABLE_I18N static void optimize_utf8 (re_dfa_t *dfa); #endif static reg_errcode_t analyze (regex_t *preg); static reg_errcode_t preorder (bin_tree_t *root, reg_errcode_t (fn (void *, bin_tree_t *)), void *extra); static reg_errcode_t postorder (bin_tree_t *root, reg_errcode_t (fn (void *, bin_tree_t *)), void *extra); static reg_errcode_t optimize_subexps (void *extra, bin_tree_t *node); static reg_errcode_t lower_subexps (void *extra, bin_tree_t *node); static bin_tree_t *lower_subexp (reg_errcode_t *err, regex_t *preg, bin_tree_t *node); static reg_errcode_t calc_first (void *extra, bin_tree_t *node); static reg_errcode_t calc_next (void *extra, bin_tree_t *node); static reg_errcode_t link_nfa_nodes (void *extra, bin_tree_t *node); static int duplicate_node (re_dfa_t *dfa, int org_idx, unsigned int constraint); static int search_duplicated_node (const re_dfa_t *dfa, int org_node, unsigned int constraint); static reg_errcode_t calc_eclosure (re_dfa_t *dfa); static reg_errcode_t calc_eclosure_iter (re_node_set *new_set, re_dfa_t *dfa, int node, int root); static reg_errcode_t calc_inveclosure (re_dfa_t *dfa); static int fetch_number (re_string_t *input, re_token_t *token, reg_syntax_t syntax); static int peek_token (re_token_t *token, re_string_t *input, reg_syntax_t syntax) internal_function; static bin_tree_t *parse (re_string_t *regexp, regex_t *preg, reg_syntax_t syntax, reg_errcode_t *err); static bin_tree_t *parse_reg_exp (re_string_t *regexp, regex_t *preg, re_token_t *token, reg_syntax_t syntax, int nest, reg_errcode_t *err); static bin_tree_t *parse_branch (re_string_t *regexp, regex_t *preg, re_token_t *token, reg_syntax_t syntax, int nest, reg_errcode_t *err); static bin_tree_t *parse_expression (re_string_t *regexp, regex_t *preg, re_token_t *token, reg_syntax_t syntax, int nest, reg_errcode_t *err); static bin_tree_t *parse_sub_exp (re_string_t *regexp, regex_t *preg, re_token_t *token, reg_syntax_t syntax, int nest, reg_errcode_t *err); static bin_tree_t *parse_dup_op (bin_tree_t *dup_elem, re_string_t *regexp, re_dfa_t *dfa, re_token_t *token, reg_syntax_t syntax, reg_errcode_t *err); static bin_tree_t *parse_bracket_exp (re_string_t *regexp, re_dfa_t *dfa, re_token_t *token, reg_syntax_t syntax, reg_errcode_t *err); static reg_errcode_t parse_bracket_element (bracket_elem_t *elem, re_string_t *regexp, re_token_t *token, int token_len, re_dfa_t *dfa, reg_syntax_t syntax, int accept_hyphen); static reg_errcode_t parse_bracket_symbol (bracket_elem_t *elem, re_string_t *regexp, re_token_t *token); #ifdef RE_ENABLE_I18N static reg_errcode_t build_equiv_class (bitset_t sbcset, re_charset_t *mbcset, int *equiv_class_alloc, const unsigned char *name); static reg_errcode_t build_charclass (RE_TRANSLATE_TYPE trans, bitset_t sbcset, re_charset_t *mbcset, int *char_class_alloc, const char *class_name, reg_syntax_t syntax); #else /* not RE_ENABLE_I18N */ static reg_errcode_t build_equiv_class (bitset_t sbcset, const unsigned char *name); static reg_errcode_t build_charclass (RE_TRANSLATE_TYPE trans, bitset_t sbcset, const char *class_name, reg_syntax_t syntax); #endif /* not RE_ENABLE_I18N */ static bin_tree_t *build_charclass_op (re_dfa_t *dfa, RE_TRANSLATE_TYPE trans, const char *class_name, const char *extra, int non_match, reg_errcode_t *err); static bin_tree_t *create_tree (re_dfa_t *dfa, bin_tree_t *left, bin_tree_t *right, re_token_type_t type); static bin_tree_t *create_token_tree (re_dfa_t *dfa, bin_tree_t *left, bin_tree_t *right, const re_token_t *token); static bin_tree_t *duplicate_tree (const bin_tree_t *src, re_dfa_t *dfa); static void free_token (re_token_t *node); static reg_errcode_t free_tree (void *extra, bin_tree_t *node); static reg_errcode_t mark_opt_subexp (void *extra, bin_tree_t *node); /* This table gives an error message for each of the error codes listed in regex.h. Obviously the order here has to be same as there. POSIX doesn't require that we do anything for REG_NOERROR, but why not be nice? */ const char __re_error_msgid[] attribute_hidden = { #define REG_NOERROR_IDX 0 gettext_noop ("Success") /* REG_NOERROR */ "\0" #define REG_NOMATCH_IDX (REG_NOERROR_IDX + sizeof "Success") gettext_noop ("No match") /* REG_NOMATCH */ "\0" #define REG_BADPAT_IDX (REG_NOMATCH_IDX + sizeof "No match") gettext_noop ("Invalid regular expression") /* REG_BADPAT */ "\0" #define REG_ECOLLATE_IDX (REG_BADPAT_IDX + sizeof "Invalid regular expression") gettext_noop ("Invalid collation character") /* REG_ECOLLATE */ "\0" #define REG_ECTYPE_IDX (REG_ECOLLATE_IDX + sizeof "Invalid collation character") gettext_noop ("Invalid character class name") /* REG_ECTYPE */ "\0" #define REG_EESCAPE_IDX (REG_ECTYPE_IDX + sizeof "Invalid character class name") gettext_noop ("Trailing backslash") /* REG_EESCAPE */ "\0" #define REG_ESUBREG_IDX (REG_EESCAPE_IDX + sizeof "Trailing backslash") gettext_noop ("Invalid back reference") /* REG_ESUBREG */ "\0" #define REG_EBRACK_IDX (REG_ESUBREG_IDX + sizeof "Invalid back reference") gettext_noop ("Unmatched [ or [^") /* REG_EBRACK */ "\0" #define REG_EPAREN_IDX (REG_EBRACK_IDX + sizeof "Unmatched [ or [^") gettext_noop ("Unmatched ( or \\(") /* REG_EPAREN */ "\0" #define REG_EBRACE_IDX (REG_EPAREN_IDX + sizeof "Unmatched ( or \\(") gettext_noop ("Unmatched \\{") /* REG_EBRACE */ "\0" #define REG_BADBR_IDX (REG_EBRACE_IDX + sizeof "Unmatched \\{") gettext_noop ("Invalid content of \\{\\}") /* REG_BADBR */ "\0" #define REG_ERANGE_IDX (REG_BADBR_IDX + sizeof "Invalid content of \\{\\}") gettext_noop ("Invalid range end") /* REG_ERANGE */ "\0" #define REG_ESPACE_IDX (REG_ERANGE_IDX + sizeof "Invalid range end") gettext_noop ("Memory exhausted") /* REG_ESPACE */ "\0" #define REG_BADRPT_IDX (REG_ESPACE_IDX + sizeof "Memory exhausted") gettext_noop ("Invalid preceding regular expression") /* REG_BADRPT */ "\0" #define REG_EEND_IDX (REG_BADRPT_IDX + sizeof "Invalid preceding regular expression") gettext_noop ("Premature end of regular expression") /* REG_EEND */ "\0" #define REG_ESIZE_IDX (REG_EEND_IDX + sizeof "Premature end of regular expression") gettext_noop ("Regular expression too big") /* REG_ESIZE */ "\0" #define REG_ERPAREN_IDX (REG_ESIZE_IDX + sizeof "Regular expression too big") gettext_noop ("Unmatched ) or \\)") /* REG_ERPAREN */ }; const size_t __re_error_msgid_idx[] attribute_hidden = { REG_NOERROR_IDX, REG_NOMATCH_IDX, REG_BADPAT_IDX, REG_ECOLLATE_IDX, REG_ECTYPE_IDX, REG_EESCAPE_IDX, REG_ESUBREG_IDX, REG_EBRACK_IDX, REG_EPAREN_IDX, REG_EBRACE_IDX, REG_BADBR_IDX, REG_ERANGE_IDX, REG_ESPACE_IDX, REG_BADRPT_IDX, REG_EEND_IDX, REG_ESIZE_IDX, REG_ERPAREN_IDX }; /* Entry points for GNU code. */ #ifdef ZOS_USS /* For ZOS USS we must define btowc */ wchar_t btowc (int c) { wchar_t wtmp[2]; char tmp[2]; tmp[0] = c; tmp[1] = 0; mbtowc (wtmp, tmp, 1); return wtmp[0]; } #endif /* re_compile_pattern is the GNU regular expression compiler: it compiles PATTERN (of length LENGTH) and puts the result in BUFP. Returns 0 if the pattern was valid, otherwise an error string. Assumes the `allocated' (and perhaps `buffer') and `translate' fields are set in BUFP on entry. */ const char * re_compile_pattern (const char *pattern, size_t length, struct re_pattern_buffer *bufp) { reg_errcode_t ret; /* And GNU code determines whether or not to get register information by passing null for the REGS argument to re_match, etc., not by setting no_sub, unless RE_NO_SUB is set. */ bufp->no_sub = !!(re_syntax_options & RE_NO_SUB); /* Match anchors at newline. */ bufp->newline_anchor = 1; ret = re_compile_internal (bufp, pattern, length, re_syntax_options); if (!ret) return NULL; return gettext (__re_error_msgid + __re_error_msgid_idx[(int) ret]); } #ifdef _LIBC weak_alias (__re_compile_pattern, re_compile_pattern) #endif /* Set by `re_set_syntax' to the current regexp syntax to recognize. Can also be assigned to arbitrarily: each pattern buffer stores its own syntax, so it can be changed between regex compilations. */ /* This has no initializer because initialized variables in Emacs become read-only after dumping. */ reg_syntax_t re_syntax_options; /* Specify the precise syntax of regexps for compilation. This provides for compatibility for various utilities which historically have different, incompatible syntaxes. The argument SYNTAX is a bit mask comprised of the various bits defined in regex.h. We return the old syntax. */ reg_syntax_t re_set_syntax (reg_syntax_t syntax) { reg_syntax_t ret = re_syntax_options; re_syntax_options = syntax; return ret; } #ifdef _LIBC weak_alias (__re_set_syntax, re_set_syntax) #endif int re_compile_fastmap (struct re_pattern_buffer *bufp) { re_dfa_t *dfa = (re_dfa_t *) bufp->buffer; char *fastmap = bufp->fastmap; memset (fastmap, '\0', sizeof (char) * SBC_MAX); re_compile_fastmap_iter (bufp, dfa->init_state, fastmap); if (dfa->init_state != dfa->init_state_word) re_compile_fastmap_iter (bufp, dfa->init_state_word, fastmap); if (dfa->init_state != dfa->init_state_nl) re_compile_fastmap_iter (bufp, dfa->init_state_nl, fastmap); if (dfa->init_state != dfa->init_state_begbuf) re_compile_fastmap_iter (bufp, dfa->init_state_begbuf, fastmap); bufp->fastmap_accurate = 1; return 0; } #ifdef _LIBC weak_alias (__re_compile_fastmap, re_compile_fastmap) #endif static inline void __attribute ((always_inline)) re_set_fastmap (char *fastmap, int icase, int ch) { fastmap[ch] = 1; if (icase) fastmap[tolower (ch)] = 1; } /* Helper function for re_compile_fastmap. Compile fastmap for the initial_state INIT_STATE. */ static void re_compile_fastmap_iter (regex_t *bufp, const re_dfastate_t *init_state, char *fastmap) { volatile re_dfa_t *dfa = (re_dfa_t *) bufp->buffer; int node_cnt; int icase = (dfa->mb_cur_max == 1 && (bufp->syntax & RE_ICASE)); for (node_cnt = 0; node_cnt < init_state->nodes.nelem; ++node_cnt) { int node = init_state->nodes.elems[node_cnt]; re_token_type_t type = dfa->nodes[node].type; if (type == CHARACTER) { re_set_fastmap (fastmap, icase, dfa->nodes[node].opr.c); #ifdef RE_ENABLE_I18N if ((bufp->syntax & RE_ICASE) && dfa->mb_cur_max > 1) { unsigned char *buf = re_malloc (unsigned char, dfa->mb_cur_max), *p; wchar_t wc; mbstate_t state; p = buf; *p++ = dfa->nodes[node].opr.c; while (++node < dfa->nodes_len && dfa->nodes[node].type == CHARACTER && dfa->nodes[node].mb_partial) *p++ = dfa->nodes[node].opr.c; memset (&state, '\0', sizeof (state)); if (__mbrtowc (&wc, (const char *) buf, p - buf, &state) == p - buf && (__wcrtomb ((char *) buf, towlower (wc), &state) != (size_t) -1)) re_set_fastmap (fastmap, 0, buf[0]); re_free (buf); } #endif } else if (type == SIMPLE_BRACKET) { int i, ch; for (i = 0, ch = 0; i < BITSET_WORDS; ++i) { int j; bitset_word_t w = dfa->nodes[node].opr.sbcset[i]; for (j = 0; j < BITSET_WORD_BITS; ++j, ++ch) if (w & ((bitset_word_t) 1 << j)) re_set_fastmap (fastmap, icase, ch); } } #ifdef RE_ENABLE_I18N else if (type == COMPLEX_BRACKET) { re_charset_t *cset = dfa->nodes[node].opr.mbcset; int i; # ifdef _LIBC /* See if we have to try all bytes which start multiple collation elements. e.g. In da_DK, we want to catch 'a' since "aa" is a valid collation element, and don't catch 'b' since 'b' is the only collation element which starts from 'b' (and it is caught by SIMPLE_BRACKET). */ if (_NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES) != 0 && (cset->ncoll_syms || cset->nranges)) { const int32_t *table = (const int32_t *) _NL_CURRENT (LC_COLLATE, _NL_COLLATE_TABLEMB); for (i = 0; i < SBC_MAX; ++i) if (table[i] < 0) re_set_fastmap (fastmap, icase, i); } # endif /* _LIBC */ /* See if we have to start the match at all multibyte characters, i.e. where we would not find an invalid sequence. This only applies to multibyte character sets; for single byte character sets, the SIMPLE_BRACKET again suffices. */ if (dfa->mb_cur_max > 1 && (cset->nchar_classes || cset->non_match || cset->nranges # ifdef _LIBC || cset->nequiv_classes # endif /* _LIBC */ )) { unsigned char c = 0; do { mbstate_t mbs; memset (&mbs, 0, sizeof (mbs)); if (__mbrtowc (NULL, (char *) &c, 1, &mbs) == (size_t) -2) re_set_fastmap (fastmap, false, (int) c); } while (++c != 0); } else { /* ... Else catch all bytes which can start the mbchars. */ for (i = 0; i < cset->nmbchars; ++i) { char buf[256]; mbstate_t state; memset (&state, '\0', sizeof (state)); if (__wcrtomb (buf, cset->mbchars[i], &state) != (size_t) -1) re_set_fastmap (fastmap, icase, *(unsigned char *) buf); if ((bufp->syntax & RE_ICASE) && dfa->mb_cur_max > 1) { if (__wcrtomb (buf, towlower (cset->mbchars[i]), &state) != (size_t) -1) re_set_fastmap (fastmap, false, *(unsigned char *) buf); } } } } #endif /* RE_ENABLE_I18N */ else if (type == OP_PERIOD #ifdef RE_ENABLE_I18N || type == OP_UTF8_PERIOD #endif /* RE_ENABLE_I18N */ || type == END_OF_RE) { memset (fastmap, '\1', sizeof (char) * SBC_MAX); if (type == END_OF_RE) bufp->can_be_null = 1; return; } } } /* Entry point for POSIX code. */ /* regcomp takes a regular expression as a string and compiles it. PREG is a regex_t *. We do not expect any fields to be initialized, since POSIX says we shouldn't. Thus, we set `buffer' to the compiled pattern; `used' to the length of the compiled pattern; `syntax' to RE_SYNTAX_POSIX_EXTENDED if the REG_EXTENDED bit in CFLAGS is set; otherwise, to RE_SYNTAX_POSIX_BASIC; `newline_anchor' to REG_NEWLINE being set in CFLAGS; `fastmap' to an allocated space for the fastmap; `fastmap_accurate' to zero; `re_nsub' to the number of subexpressions in PATTERN. PATTERN is the address of the pattern string. CFLAGS is a series of bits which affect compilation. If REG_EXTENDED is set, we use POSIX extended syntax; otherwise, we use POSIX basic syntax. If REG_NEWLINE is set, then . and [^...] don't match newline. Also, regexec will try a match beginning after every newline. If REG_ICASE is set, then we considers upper- and lowercase versions of letters to be equivalent when matching. If REG_NOSUB is set, then when PREG is passed to regexec, that routine will report only success or failure, and nothing about the registers. It returns 0 if it succeeds, nonzero if it doesn't. (See regex.h for the return codes and their meanings.) */ int regcomp (regex_t *__restrict preg, const char *__restrict pattern, int cflags) { reg_errcode_t ret; reg_syntax_t syntax = ((cflags & REG_EXTENDED) ? RE_SYNTAX_POSIX_EXTENDED : RE_SYNTAX_POSIX_BASIC); preg->buffer = NULL; preg->allocated = 0; preg->used = 0; /* Try to allocate space for the fastmap. */ preg->fastmap = re_malloc (char, SBC_MAX); if (BE (preg->fastmap == NULL, 0)) return REG_ESPACE; syntax |= (cflags & REG_ICASE) ? RE_ICASE : 0; /* If REG_NEWLINE is set, newlines are treated differently. */ if (cflags & REG_NEWLINE) { /* REG_NEWLINE implies neither . nor [^...] match newline. */ syntax &= ~RE_DOT_NEWLINE; syntax |= RE_HAT_LISTS_NOT_NEWLINE; /* It also changes the matching behavior. */ preg->newline_anchor = 1; } else preg->newline_anchor = 0; preg->no_sub = !!(cflags & REG_NOSUB); preg->translate = NULL; ret = re_compile_internal (preg, pattern, strlen (pattern), syntax); /* POSIX doesn't distinguish between an unmatched open-group and an unmatched close-group: both are REG_EPAREN. */ if (ret == REG_ERPAREN) ret = REG_EPAREN; /* We have already checked preg->fastmap != NULL. */ if (BE (ret == REG_NOERROR, 1)) /* Compute the fastmap now, since regexec cannot modify the pattern buffer. This function never fails in this implementation. */ (void) re_compile_fastmap (preg); else { /* Some error occurred while compiling the expression. */ re_free (preg->fastmap); preg->fastmap = NULL; } return (int) ret; } #ifdef _LIBC weak_alias (__regcomp, regcomp) #endif /* Returns a message corresponding to an error code, ERRCODE, returned from either regcomp or regexec. We don't use PREG here. */ size_t regerror(int errcode, UNUSED const regex_t *__restrict preg, char *__restrict errbuf, size_t errbuf_size) { const char *msg; size_t msg_size; if (BE (errcode < 0 || errcode >= (int) (sizeof (__re_error_msgid_idx) / sizeof (__re_error_msgid_idx[0])), 0)) /* Only error codes returned by the rest of the code should be passed to this routine. If we are given anything else, or if other regex code generates an invalid error code, then the program has a bug. Dump core so we can fix it. */ abort (); msg = gettext (__re_error_msgid + __re_error_msgid_idx[errcode]); msg_size = strlen (msg) + 1; /* Includes the null. */ if (BE (errbuf_size != 0, 1)) { if (BE (msg_size > errbuf_size, 0)) { memcpy (errbuf, msg, errbuf_size - 1); errbuf[errbuf_size - 1] = 0; } else memcpy (errbuf, msg, msg_size); } return msg_size; } #ifdef _LIBC weak_alias (__regerror, regerror) #endif #ifdef RE_ENABLE_I18N /* This static array is used for the map to single-byte characters when UTF-8 is used. Otherwise we would allocate memory just to initialize it the same all the time. UTF-8 is the preferred encoding so this is a worthwhile optimization. */ #if __GNUC__ >= 3 static const bitset_t utf8_sb_map = { /* Set the first 128 bits. */ [0 ... 0x80 / BITSET_WORD_BITS - 1] = BITSET_WORD_MAX }; #else /* ! (__GNUC__ >= 3) */ static bitset_t utf8_sb_map; #endif /* __GNUC__ >= 3 */ #endif /* RE_ENABLE_I18N */ static void free_dfa_content (re_dfa_t *dfa) { unsigned int i; int j; if (dfa->nodes) for (i = 0; i < dfa->nodes_len; ++i) free_token (dfa->nodes + i); re_free (dfa->nexts); for (i = 0; i < dfa->nodes_len; ++i) { if (dfa->eclosures != NULL) re_node_set_free (dfa->eclosures + i); if (dfa->inveclosures != NULL) re_node_set_free (dfa->inveclosures + i); if (dfa->edests != NULL) re_node_set_free (dfa->edests + i); } re_free (dfa->edests); re_free (dfa->eclosures); re_free (dfa->inveclosures); re_free (dfa->nodes); if (dfa->state_table) for (i = 0; i <= dfa->state_hash_mask; ++i) { struct re_state_table_entry *entry = dfa->state_table + i; for (j = 0; j < entry->num; ++j) { re_dfastate_t *state = entry->array[j]; free_state (state); } re_free (entry->array); } re_free (dfa->state_table); #ifdef RE_ENABLE_I18N if (dfa->sb_char != utf8_sb_map) re_free (dfa->sb_char); #endif re_free (dfa->subexp_map); #ifdef DEBUG re_free (dfa->re_str); #endif re_free (dfa); } /* Free dynamically allocated space used by PREG. */ void regfree (regex_t *preg) { re_dfa_t *dfa = (re_dfa_t *) preg->buffer; if (BE (dfa != NULL, 1)) free_dfa_content (dfa); preg->buffer = NULL; preg->allocated = 0; re_free (preg->fastmap); preg->fastmap = NULL; re_free (preg->translate); preg->translate = NULL; } #ifdef _LIBC weak_alias (__regfree, regfree) #endif /* Entry points compatible with 4.2 BSD regex library. We don't define them unless specifically requested. */ #if defined _REGEX_RE_COMP || defined _LIBC /* BSD has one and only one pattern buffer. */ static struct re_pattern_buffer re_comp_buf; char * # ifdef _LIBC /* Make these definitions weak in libc, so POSIX programs can redefine these names if they don't use our functions, and still use regcomp/regexec above without link errors. */ weak_function # endif re_comp (s) const char *s; { reg_errcode_t ret; char *fastmap; if (!s) { if (!re_comp_buf.buffer) return gettext ("No previous regular expression"); return 0; } if (re_comp_buf.buffer) { fastmap = re_comp_buf.fastmap; re_comp_buf.fastmap = NULL; __regfree (&re_comp_buf); memset (&re_comp_buf, '\0', sizeof (re_comp_buf)); re_comp_buf.fastmap = fastmap; } if (re_comp_buf.fastmap == NULL) { re_comp_buf.fastmap = (char *) malloc (SBC_MAX); if (re_comp_buf.fastmap == NULL) return (char *) gettext (__re_error_msgid + __re_error_msgid_idx[(int) REG_ESPACE]); } /* Since `re_exec' always passes NULL for the `regs' argument, we don't need to initialize the pattern buffer fields which affect it. */ /* Match anchors at newlines. */ re_comp_buf.newline_anchor = 1; ret = re_compile_internal (&re_comp_buf, s, strlen (s), re_syntax_options); if (!ret) return NULL; /* Yes, we're discarding `const' here if !HAVE_LIBINTL. */ return (char *) gettext (__re_error_msgid + __re_error_msgid_idx[(int) ret]); } #ifdef _LIBC libc_freeres_fn (free_mem) { __regfree (&re_comp_buf); } #endif #endif /* _REGEX_RE_COMP */ /* Internal entry point. Compile the regular expression PATTERN, whose length is LENGTH. SYNTAX indicate regular expression's syntax. */ static reg_errcode_t re_compile_internal (regex_t *preg, const char * pattern, size_t length, reg_syntax_t syntax) { reg_errcode_t err = REG_NOERROR; re_dfa_t *dfa; re_string_t regexp; /* Initialize the pattern buffer. */ preg->fastmap_accurate = 0; preg->syntax = syntax; preg->not_bol = preg->not_eol = 0; preg->used = 0; preg->re_nsub = 0; preg->can_be_null = 0; preg->regs_allocated = REGS_UNALLOCATED; /* Initialize the dfa. */ dfa = (re_dfa_t *) preg->buffer; if (BE (preg->allocated < sizeof (re_dfa_t), 0)) { /* If zero allocated, but buffer is non-null, try to realloc enough space. This loses if buffer's address is bogus, but that is the user's responsibility. If ->buffer is NULL this is a simple allocation. */ dfa = re_realloc (preg->buffer, re_dfa_t, 1); if (dfa == NULL) return REG_ESPACE; preg->allocated = sizeof (re_dfa_t); preg->buffer = (unsigned char *) dfa; } preg->used = sizeof (re_dfa_t); err = init_dfa (dfa, length); if (BE (err != REG_NOERROR, 0)) { free_dfa_content (dfa); preg->buffer = NULL; preg->allocated = 0; return err; } #ifdef DEBUG /* Note: length+1 will not overflow since it is checked in init_dfa. */ dfa->re_str = re_malloc (char, length + 1); strncpy (dfa->re_str, pattern, length + 1); #endif __libc_lock_init (dfa->lock); err = re_string_construct (®exp, pattern, length, preg->translate, syntax & RE_ICASE, dfa); if (BE (err != REG_NOERROR, 0)) { re_compile_internal_free_return: free_workarea_compile (preg); re_string_destruct (®exp); free_dfa_content (dfa); preg->buffer = NULL; preg->allocated = 0; return err; } /* Parse the regular expression, and build a structure tree. */ preg->re_nsub = 0; dfa->str_tree = parse (®exp, preg, syntax, &err); if (BE (dfa->str_tree == NULL, 0)) goto re_compile_internal_free_return; /* Analyze the tree and create the nfa. */ err = analyze (preg); if (BE (err != REG_NOERROR, 0)) goto re_compile_internal_free_return; #ifdef RE_ENABLE_I18N /* If possible, do searching in single byte encoding to speed things up. */ if (dfa->is_utf8 && !(syntax & RE_ICASE) && preg->translate == NULL) optimize_utf8 (dfa); #endif /* Then create the initial state of the dfa. */ err = create_initial_state (dfa); /* Release work areas. */ free_workarea_compile (preg); re_string_destruct (®exp); if (BE (err != REG_NOERROR, 0)) { free_dfa_content (dfa); preg->buffer = NULL; preg->allocated = 0; } return err; } /* Initialize DFA. We use the length of the regular expression PAT_LEN as the initial length of some arrays. */ static reg_errcode_t init_dfa (re_dfa_t *dfa, size_t pat_len) { unsigned int table_size; memset (dfa, '\0', sizeof (re_dfa_t)); /* Force allocation of str_tree_storage the first time. */ dfa->str_tree_storage_idx = BIN_TREE_STORAGE_SIZE; /* Avoid overflows. */ if (pat_len == SIZE_MAX) return REG_ESPACE; dfa->nodes_alloc = pat_len + 1; dfa->nodes = re_malloc (re_token_t, dfa->nodes_alloc); /* table_size = 2 ^ ceil(log pat_len) */ for (table_size = 1; ; table_size <<= 1) if (table_size > pat_len) break; dfa->state_table = calloc (sizeof (struct re_state_table_entry), table_size); dfa->state_hash_mask = table_size - 1; dfa->mb_cur_max = MB_CUR_MAX; #ifdef _LIBC if (dfa->mb_cur_max == 6 && strcmp (_NL_CURRENT (LC_CTYPE, _NL_CTYPE_CODESET_NAME), "UTF-8") == 0) dfa->is_utf8 = 1; dfa->map_notascii = (_NL_CURRENT_WORD (LC_CTYPE, _NL_CTYPE_MAP_TO_NONASCII) != 0); #else dfa->is_utf8 = 1; /* We check exhaustively in the loop below if this charset is a superset of ASCII. */ dfa->map_notascii = 0; #endif #ifdef RE_ENABLE_I18N if (dfa->mb_cur_max > 1) { if (dfa->is_utf8) { #if !defined(__GNUC__) || __GNUC__ < 3 static short utf8_sb_map_inited = 0; if (! utf8_sb_map_inited) { int i; utf8_sb_map_inited = 0; for (i = 0; i <= 0x80 / BITSET_WORD_BITS - 1; i++) utf8_sb_map[i] = BITSET_WORD_MAX; } #endif dfa->sb_char = (re_bitset_ptr_t) utf8_sb_map; } else { int i, j, ch; dfa->sb_char = (re_bitset_ptr_t) calloc (sizeof (bitset_t), 1); if (BE (dfa->sb_char == NULL, 0)) return REG_ESPACE; /* Set the bits corresponding to single byte chars. */ for (i = 0, ch = 0; i < BITSET_WORDS; ++i) for (j = 0; j < BITSET_WORD_BITS; ++j, ++ch) { wint_t wch = __btowc (ch); if (wch != WEOF) dfa->sb_char[i] |= (bitset_word_t) 1 << j; # ifndef _LIBC if (isascii (ch) && wch != ch) dfa->map_notascii = 1; # endif } } } #endif if (BE (dfa->nodes == NULL || dfa->state_table == NULL, 0)) return REG_ESPACE; return REG_NOERROR; } /* Initialize WORD_CHAR table, which indicate which character is "word". In this case "word" means that it is the word construction character used by some operators like "\<", "\>", etc. */ static void internal_function init_word_char (re_dfa_t *dfa) { int i, j, ch; dfa->word_ops_used = 1; for (i = 0, ch = 0; i < BITSET_WORDS; ++i) for (j = 0; j < BITSET_WORD_BITS; ++j, ++ch) if (isalnum (ch) || ch == '_') dfa->word_char[i] |= (bitset_word_t) 1 << j; } /* Free the work area which are only used while compiling. */ static void free_workarea_compile (regex_t *preg) { re_dfa_t *dfa = (re_dfa_t *) preg->buffer; bin_tree_storage_t *storage, *next; for (storage = dfa->str_tree_storage; storage; storage = next) { next = storage->next; re_free (storage); } dfa->str_tree_storage = NULL; dfa->str_tree_storage_idx = BIN_TREE_STORAGE_SIZE; dfa->str_tree = NULL; re_free (dfa->org_indices); dfa->org_indices = NULL; } /* Create initial states for all contexts. */ static reg_errcode_t create_initial_state (re_dfa_t *dfa) { int first, i; reg_errcode_t err; re_node_set init_nodes; /* Initial states have the epsilon closure of the node which is the first node of the regular expression. */ first = dfa->str_tree->first->node_idx; dfa->init_node = first; err = re_node_set_init_copy (&init_nodes, dfa->eclosures + first); if (BE (err != REG_NOERROR, 0)) return err; /* The back-references which are in initial states can epsilon transit, since in this case all of the subexpressions can be null. Then we add epsilon closures of the nodes which are the next nodes of the back-references. */ if (dfa->nbackref > 0) for (i = 0; i < init_nodes.nelem; ++i) { int node_idx = init_nodes.elems[i]; re_token_type_t type = dfa->nodes[node_idx].type; int clexp_idx; if (type != OP_BACK_REF) continue; for (clexp_idx = 0; clexp_idx < init_nodes.nelem; ++clexp_idx) { re_token_t *clexp_node; clexp_node = dfa->nodes + init_nodes.elems[clexp_idx]; if (clexp_node->type == OP_CLOSE_SUBEXP && clexp_node->opr.idx == dfa->nodes[node_idx].opr.idx) break; } if (clexp_idx == init_nodes.nelem) continue; if (type == OP_BACK_REF) { int dest_idx = dfa->edests[node_idx].elems[0]; if (!re_node_set_contains (&init_nodes, dest_idx)) { reg_errcode_t err = re_node_set_merge (&init_nodes, dfa->eclosures + dest_idx); if (err != REG_NOERROR) return err; i = 0; } } } /* It must be the first time to invoke acquire_state. */ dfa->init_state = re_acquire_state_context (&err, dfa, &init_nodes, 0); /* We don't check ERR here, since the initial state must not be NULL. */ if (BE (dfa->init_state == NULL, 0)) return err; if (dfa->init_state->has_constraint) { dfa->init_state_word = re_acquire_state_context (&err, dfa, &init_nodes, CONTEXT_WORD); dfa->init_state_nl = re_acquire_state_context (&err, dfa, &init_nodes, CONTEXT_NEWLINE); dfa->init_state_begbuf = re_acquire_state_context (&err, dfa, &init_nodes, CONTEXT_NEWLINE | CONTEXT_BEGBUF); if (BE (dfa->init_state_word == NULL || dfa->init_state_nl == NULL || dfa->init_state_begbuf == NULL, 0)) return err; } else dfa->init_state_word = dfa->init_state_nl = dfa->init_state_begbuf = dfa->init_state; re_node_set_free (&init_nodes); return REG_NOERROR; } #ifdef RE_ENABLE_I18N /* If it is possible to do searching in single byte encoding instead of UTF-8 to speed things up, set dfa->mb_cur_max to 1, clear is_utf8 and change DFA nodes where needed. */ static void optimize_utf8 (re_dfa_t *dfa) { int node, i, mb_chars = 0, has_period = 0; for (node = 0; node < dfa->nodes_len; ++node) switch (dfa->nodes[node].type) { case CHARACTER: if (dfa->nodes[node].opr.c >= 0x80) mb_chars = 1; break; case ANCHOR: switch (dfa->nodes[node].opr.ctx_type) { case LINE_FIRST: case LINE_LAST: case BUF_FIRST: case BUF_LAST: break; default: /* Word anchors etc. cannot be handled. It's okay to test opr.ctx_type since constraints (for all DFA nodes) are created by ORing one or more opr.ctx_type values. */ return; } break; case OP_PERIOD: has_period = 1; break; case OP_BACK_REF: case OP_ALT: case END_OF_RE: case OP_DUP_ASTERISK: case OP_OPEN_SUBEXP: case OP_CLOSE_SUBEXP: break; case COMPLEX_BRACKET: return; case SIMPLE_BRACKET: /* Just double check. The non-ASCII range starts at 0x80. */ assert (0x80 % BITSET_WORD_BITS == 0); for (i = 0x80 / BITSET_WORD_BITS; i < BITSET_WORDS; ++i) if (dfa->nodes[node].opr.sbcset[i]) return; break; default: abort (); } if (mb_chars || has_period) for (node = 0; node < dfa->nodes_len; ++node) { if (dfa->nodes[node].type == CHARACTER && dfa->nodes[node].opr.c >= 0x80) dfa->nodes[node].mb_partial = 0; else if (dfa->nodes[node].type == OP_PERIOD) dfa->nodes[node].type = OP_UTF8_PERIOD; } /* The search can be in single byte locale. */ dfa->mb_cur_max = 1; dfa->is_utf8 = 0; dfa->has_mb_node = dfa->nbackref > 0 || has_period; } #endif /* Analyze the structure tree, and calculate "first", "next", "edest", "eclosure", and "inveclosure". */ static reg_errcode_t analyze (regex_t *preg) { re_dfa_t *dfa = (re_dfa_t *) preg->buffer; reg_errcode_t ret; /* Allocate arrays. */ dfa->nexts = re_malloc (int, dfa->nodes_alloc); dfa->org_indices = re_malloc (int, dfa->nodes_alloc); dfa->edests = re_malloc (re_node_set, dfa->nodes_alloc); dfa->eclosures = re_malloc (re_node_set, dfa->nodes_alloc); if (BE (dfa->nexts == NULL || dfa->org_indices == NULL || dfa->edests == NULL || dfa->eclosures == NULL, 0)) return REG_ESPACE; dfa->subexp_map = re_malloc (int, preg->re_nsub); if (dfa->subexp_map != NULL) { unsigned int i; for (i = 0; i < preg->re_nsub; i++) dfa->subexp_map[i] = i; preorder (dfa->str_tree, optimize_subexps, dfa); for (i = 0; i < preg->re_nsub; i++) if (dfa->subexp_map[i] != (int)i) break; if (i == preg->re_nsub) { free (dfa->subexp_map); dfa->subexp_map = NULL; } } ret = postorder (dfa->str_tree, lower_subexps, preg); if (BE (ret != REG_NOERROR, 0)) return ret; ret = postorder (dfa->str_tree, calc_first, dfa); if (BE (ret != REG_NOERROR, 0)) return ret; preorder (dfa->str_tree, calc_next, dfa); ret = preorder (dfa->str_tree, link_nfa_nodes, dfa); if (BE (ret != REG_NOERROR, 0)) return ret; ret = calc_eclosure (dfa); if (BE (ret != REG_NOERROR, 0)) return ret; /* We only need this during the prune_impossible_nodes pass in regexec.c; skip it if p_i_n will not run, as calc_inveclosure can be quadratic. */ if ((!preg->no_sub && preg->re_nsub > 0 && dfa->has_plural_match) || dfa->nbackref) { dfa->inveclosures = re_malloc (re_node_set, dfa->nodes_len); if (BE (dfa->inveclosures == NULL, 0)) return REG_ESPACE; ret = calc_inveclosure (dfa); } return ret; } /* Our parse trees are very unbalanced, so we cannot use a stack to implement parse tree visits. Instead, we use parent pointers and some hairy code in these two functions. */ static reg_errcode_t postorder (bin_tree_t *root, reg_errcode_t (fn (void *, bin_tree_t *)), void *extra) { bin_tree_t *node, *prev; for (node = root; ; ) { /* Descend down the tree, preferably to the left (or to the right if that's the only child). */ while (node->left || node->right) if (node->left) node = node->left; else node = node->right; do { reg_errcode_t err = fn (extra, node); if (BE (err != REG_NOERROR, 0)) return err; if (node->parent == NULL) return REG_NOERROR; prev = node; node = node->parent; } /* Go up while we have a node that is reached from the right. */ while (node->right == prev || node->right == NULL); node = node->right; } } static reg_errcode_t preorder (bin_tree_t *root, reg_errcode_t (fn (void *, bin_tree_t *)), void *extra) { bin_tree_t *node; for (node = root; ; ) { reg_errcode_t err = fn (extra, node); if (BE (err != REG_NOERROR, 0)) return err; /* Go to the left node, or up and to the right. */ if (node->left) node = node->left; else { bin_tree_t *prev = NULL; while (node->right == prev || node->right == NULL) { prev = node; node = node->parent; if (!node) return REG_NOERROR; } node = node->right; } } } /* Optimization pass: if a SUBEXP is entirely contained, strip it and tell re_search_internal to map the inner one's opr.idx to this one's. Adjust backreferences as well. Requires a preorder visit. */ static reg_errcode_t optimize_subexps (void *extra, bin_tree_t *node) { re_dfa_t *dfa = (re_dfa_t *) extra; if (node->token.type == OP_BACK_REF && dfa->subexp_map) { int idx = node->token.opr.idx; node->token.opr.idx = dfa->subexp_map[idx]; dfa->used_bkref_map |= 1 << node->token.opr.idx; } else if (node->token.type == SUBEXP && node->left && node->left->token.type == SUBEXP) { int other_idx = node->left->token.opr.idx; node->left = node->left->left; if (node->left) node->left->parent = node; dfa->subexp_map[other_idx] = dfa->subexp_map[node->token.opr.idx]; if (other_idx < BITSET_WORD_BITS) dfa->used_bkref_map &= ~((bitset_word_t) 1 << other_idx); } return REG_NOERROR; } /* Lowering pass: Turn each SUBEXP node into the appropriate concatenation of OP_OPEN_SUBEXP, the body of the SUBEXP (if any) and OP_CLOSE_SUBEXP. */ static reg_errcode_t lower_subexps (void *extra, bin_tree_t *node) { regex_t *preg = (regex_t *) extra; reg_errcode_t err = REG_NOERROR; if (node->left && node->left->token.type == SUBEXP) { node->left = lower_subexp (&err, preg, node->left); if (node->left) node->left->parent = node; } if (node->right && node->right->token.type == SUBEXP) { node->right = lower_subexp (&err, preg, node->right); if (node->right) node->right->parent = node; } return err; } static bin_tree_t * lower_subexp (reg_errcode_t *err, regex_t *preg, bin_tree_t *node) { re_dfa_t *dfa = (re_dfa_t *) preg->buffer; bin_tree_t *body = node->left; bin_tree_t *op, *cls, *tree1, *tree; if (preg->no_sub /* We do not optimize empty subexpressions, because otherwise we may have bad CONCAT nodes with NULL children. This is obviously not very common, so we do not lose much. An example that triggers this case is the sed "script" /\(\)/x. */ && node->left != NULL && (node->token.opr.idx >= BITSET_WORD_BITS || !(dfa->used_bkref_map & ((bitset_word_t) 1 << node->token.opr.idx)))) return node->left; /* Convert the SUBEXP node to the concatenation of an OP_OPEN_SUBEXP, the contents, and an OP_CLOSE_SUBEXP. */ op = create_tree (dfa, NULL, NULL, OP_OPEN_SUBEXP); cls = create_tree (dfa, NULL, NULL, OP_CLOSE_SUBEXP); tree1 = body ? create_tree (dfa, body, cls, CONCAT) : cls; tree = create_tree (dfa, op, tree1, CONCAT); if (BE (tree == NULL || tree1 == NULL || op == NULL || cls == NULL, 0)) { *err = REG_ESPACE; return NULL; } op->token.opr.idx = cls->token.opr.idx = node->token.opr.idx; op->token.opt_subexp = cls->token.opt_subexp = node->token.opt_subexp; return tree; } /* Pass 1 in building the NFA: compute FIRST and create unlinked automaton nodes. Requires a postorder visit. */ static reg_errcode_t calc_first (void *extra, bin_tree_t *node) { re_dfa_t *dfa = (re_dfa_t *) extra; if (node->token.type == CONCAT) { node->first = node->left->first; node->node_idx = node->left->node_idx; } else { node->first = node; node->node_idx = re_dfa_add_node (dfa, node->token); if (BE (node->node_idx == -1, 0)) return REG_ESPACE; if (node->token.type == ANCHOR) dfa->nodes[node->node_idx].constraint = node->token.opr.ctx_type; } return REG_NOERROR; } /* Pass 2: compute NEXT on the tree. Preorder visit. */ static reg_errcode_t calc_next (UNUSED void *extra, bin_tree_t *node) { switch (node->token.type) { case OP_DUP_ASTERISK: node->left->next = node; break; case CONCAT: node->left->next = node->right->first; node->right->next = node->next; break; default: if (node->left) node->left->next = node->next; if (node->right) node->right->next = node->next; break; } return REG_NOERROR; } /* Pass 3: link all DFA nodes to their NEXT node (any order will do). */ static reg_errcode_t link_nfa_nodes (void *extra, bin_tree_t *node) { re_dfa_t *dfa = (re_dfa_t *) extra; int idx = node->node_idx; reg_errcode_t err = REG_NOERROR; switch (node->token.type) { case CONCAT: break; case END_OF_RE: assert (node->next == NULL); break; case OP_DUP_ASTERISK: case OP_ALT: { int left, right; dfa->has_plural_match = 1; if (node->left != NULL) left = node->left->first->node_idx; else left = node->next->node_idx; if (node->right != NULL) right = node->right->first->node_idx; else right = node->next->node_idx; assert (left > -1); assert (right > -1); err = re_node_set_init_2 (dfa->edests + idx, left, right); } break; case ANCHOR: case OP_OPEN_SUBEXP: case OP_CLOSE_SUBEXP: err = re_node_set_init_1 (dfa->edests + idx, node->next->node_idx); break; case OP_BACK_REF: dfa->nexts[idx] = node->next->node_idx; if (node->token.type == OP_BACK_REF) err = re_node_set_init_1 (dfa->edests + idx, dfa->nexts[idx]); break; default: assert (!IS_EPSILON_NODE (node->token.type)); dfa->nexts[idx] = node->next->node_idx; break; } return err; } /* Duplicate the epsilon closure of the node ROOT_NODE. Note that duplicated nodes have constraint INIT_CONSTRAINT in addition to their own constraint. */ static reg_errcode_t internal_function duplicate_node_closure (re_dfa_t *dfa, int top_org_node, int top_clone_node, int root_node, unsigned int init_constraint) { int org_node, clone_node, ret; unsigned int constraint = init_constraint; for (org_node = top_org_node, clone_node = top_clone_node;;) { int org_dest, clone_dest; if (dfa->nodes[org_node].type == OP_BACK_REF) { /* If the back reference epsilon-transit, its destination must also have the constraint. Then duplicate the epsilon closure of the destination of the back reference, and store it in edests of the back reference. */ org_dest = dfa->nexts[org_node]; re_node_set_empty (dfa->edests + clone_node); clone_dest = duplicate_node (dfa, org_dest, constraint); if (BE (clone_dest == -1, 0)) return REG_ESPACE; dfa->nexts[clone_node] = dfa->nexts[org_node]; ret = re_node_set_insert (dfa->edests + clone_node, clone_dest); if (BE (ret < 0, 0)) return REG_ESPACE; } else if (dfa->edests[org_node].nelem == 0) { /* In case of the node can't epsilon-transit, don't duplicate the destination and store the original destination as the destination of the node. */ dfa->nexts[clone_node] = dfa->nexts[org_node]; break; } else if (dfa->edests[org_node].nelem == 1) { /* In case of the node can epsilon-transit, and it has only one destination. */ org_dest = dfa->edests[org_node].elems[0]; re_node_set_empty (dfa->edests + clone_node); /* If the node is root_node itself, it means the epsilon clsoure has a loop. Then tie it to the destination of the root_node. */ if (org_node == root_node && clone_node != org_node) { ret = re_node_set_insert (dfa->edests + clone_node, org_dest); if (BE (ret < 0, 0)) return REG_ESPACE; break; } /* In case of the node has another constraint, add it. */ constraint |= dfa->nodes[org_node].constraint; clone_dest = duplicate_node (dfa, org_dest, constraint); if (BE (clone_dest == -1, 0)) return REG_ESPACE; ret = re_node_set_insert (dfa->edests + clone_node, clone_dest); if (BE (ret < 0, 0)) return REG_ESPACE; } else /* dfa->edests[org_node].nelem == 2 */ { /* In case of the node can epsilon-transit, and it has two destinations. In the bin_tree_t and DFA, that's '|' and '*'. */ org_dest = dfa->edests[org_node].elems[0]; re_node_set_empty (dfa->edests + clone_node); /* Search for a duplicated node which satisfies the constraint. */ clone_dest = search_duplicated_node (dfa, org_dest, constraint); if (clone_dest == -1) { /* There is no such duplicated node, create a new one. */ reg_errcode_t err; clone_dest = duplicate_node (dfa, org_dest, constraint); if (BE (clone_dest == -1, 0)) return REG_ESPACE; ret = re_node_set_insert (dfa->edests + clone_node, clone_dest); if (BE (ret < 0, 0)) return REG_ESPACE; err = duplicate_node_closure (dfa, org_dest, clone_dest, root_node, constraint); if (BE (err != REG_NOERROR, 0)) return err; } else { /* There is a duplicated node which satisfies the constraint, use it to avoid infinite loop. */ ret = re_node_set_insert (dfa->edests + clone_node, clone_dest); if (BE (ret < 0, 0)) return REG_ESPACE; } org_dest = dfa->edests[org_node].elems[1]; clone_dest = duplicate_node (dfa, org_dest, constraint); if (BE (clone_dest == -1, 0)) return REG_ESPACE; ret = re_node_set_insert (dfa->edests + clone_node, clone_dest); if (BE (ret < 0, 0)) return REG_ESPACE; } org_node = org_dest; clone_node = clone_dest; } return REG_NOERROR; } /* Search for a node which is duplicated from the node ORG_NODE, and satisfies the constraint CONSTRAINT. */ static int search_duplicated_node (const re_dfa_t *dfa, int org_node, unsigned int constraint) { int idx; for (idx = dfa->nodes_len - 1; dfa->nodes[idx].duplicated && idx > 0; --idx) { if (org_node == dfa->org_indices[idx] && constraint == dfa->nodes[idx].constraint) return idx; /* Found. */ } return -1; /* Not found. */ } /* Duplicate the node whose index is ORG_IDX and set the constraint CONSTRAINT. Return the index of the new node, or -1 if insufficient storage is available. */ static int duplicate_node (re_dfa_t *dfa, int org_idx, unsigned int constraint) { int dup_idx = re_dfa_add_node (dfa, dfa->nodes[org_idx]); if (BE (dup_idx != -1, 1)) { dfa->nodes[dup_idx].constraint = constraint; dfa->nodes[dup_idx].constraint |= dfa->nodes[org_idx].constraint; dfa->nodes[dup_idx].duplicated = 1; /* Store the index of the original node. */ dfa->org_indices[dup_idx] = org_idx; } return dup_idx; } static reg_errcode_t calc_inveclosure (re_dfa_t *dfa) { int ret; unsigned int src, idx; for (idx = 0; idx < dfa->nodes_len; ++idx) re_node_set_init_empty (dfa->inveclosures + idx); for (src = 0; src < dfa->nodes_len; ++src) { int *elems = dfa->eclosures[src].elems; int idx; for (idx = 0; idx < dfa->eclosures[src].nelem; ++idx) { ret = re_node_set_insert_last (dfa->inveclosures + elems[idx], src); if (BE (ret == -1, 0)) return REG_ESPACE; } } return REG_NOERROR; } /* Calculate "eclosure" for all the node in DFA. */ static reg_errcode_t calc_eclosure (re_dfa_t *dfa) { size_t node_idx; int incomplete; #ifdef DEBUG assert (dfa->nodes_len > 0); #endif incomplete = 0; /* For each nodes, calculate epsilon closure. */ for (node_idx = 0; ; ++node_idx) { reg_errcode_t err; re_node_set eclosure_elem; if (node_idx == dfa->nodes_len) { if (!incomplete) break; incomplete = 0; node_idx = 0; } #ifdef DEBUG assert (dfa->eclosures[node_idx].nelem != -1); #endif /* If we have already calculated, skip it. */ if (dfa->eclosures[node_idx].nelem != 0) continue; /* Calculate epsilon closure of `node_idx'. */ err = calc_eclosure_iter (&eclosure_elem, dfa, node_idx, 1); if (BE (err != REG_NOERROR, 0)) return err; if (dfa->eclosures[node_idx].nelem == 0) { incomplete = 1; re_node_set_free (&eclosure_elem); } } return REG_NOERROR; } /* Calculate epsilon closure of NODE. */ static reg_errcode_t calc_eclosure_iter (re_node_set *new_set, re_dfa_t *dfa, int node, int root) { reg_errcode_t err; int i; re_node_set eclosure; int ret; int incomplete = 0; err = re_node_set_alloc (&eclosure, dfa->edests[node].nelem + 1); if (BE (err != REG_NOERROR, 0)) return err; /* This indicates that we are calculating this node now. We reference this value to avoid infinite loop. */ dfa->eclosures[node].nelem = -1; /* If the current node has constraints, duplicate all nodes since they must inherit the constraints. */ if (dfa->nodes[node].constraint && dfa->edests[node].nelem && !dfa->nodes[dfa->edests[node].elems[0]].duplicated) { err = duplicate_node_closure (dfa, node, node, node, dfa->nodes[node].constraint); if (BE (err != REG_NOERROR, 0)) return err; } /* Expand each epsilon destination nodes. */ if (IS_EPSILON_NODE(dfa->nodes[node].type)) for (i = 0; i < dfa->edests[node].nelem; ++i) { re_node_set eclosure_elem; int edest = dfa->edests[node].elems[i]; /* If calculating the epsilon closure of `edest' is in progress, return intermediate result. */ if (dfa->eclosures[edest].nelem == -1) { incomplete = 1; continue; } /* If we haven't calculated the epsilon closure of `edest' yet, calculate now. Otherwise use calculated epsilon closure. */ if (dfa->eclosures[edest].nelem == 0) { err = calc_eclosure_iter (&eclosure_elem, dfa, edest, 0); if (BE (err != REG_NOERROR, 0)) return err; } else eclosure_elem = dfa->eclosures[edest]; /* Merge the epsilon closure of `edest'. */ err = re_node_set_merge (&eclosure, &eclosure_elem); if (BE (err != REG_NOERROR, 0)) return err; /* If the epsilon closure of `edest' is incomplete, the epsilon closure of this node is also incomplete. */ if (dfa->eclosures[edest].nelem == 0) { incomplete = 1; re_node_set_free (&eclosure_elem); } } /* An epsilon closure includes itself. */ ret = re_node_set_insert (&eclosure, node); if (BE (ret < 0, 0)) return REG_ESPACE; if (incomplete && !root) dfa->eclosures[node].nelem = 0; else dfa->eclosures[node] = eclosure; *new_set = eclosure; return REG_NOERROR; } /* Functions for token which are used in the parser. */ /* Fetch a token from INPUT. We must not use this function inside bracket expressions. */ static void internal_function fetch_token (re_token_t *result, re_string_t *input, reg_syntax_t syntax) { re_string_skip_bytes (input, peek_token (result, input, syntax)); } /* Peek a token from INPUT, and return the length of the token. We must not use this function inside bracket expressions. */ static int internal_function peek_token (re_token_t *token, re_string_t *input, reg_syntax_t syntax) { unsigned char c; if (re_string_eoi (input)) { token->type = END_OF_RE; return 0; } c = re_string_peek_byte (input, 0); token->opr.c = c; token->word_char = 0; #ifdef RE_ENABLE_I18N token->mb_partial = 0; if (input->mb_cur_max > 1 && !re_string_first_byte (input, re_string_cur_idx (input))) { token->type = CHARACTER; token->mb_partial = 1; return 1; } #endif if (c == '\\') { unsigned char c2; if (re_string_cur_idx (input) + 1 >= re_string_length (input)) { token->type = BACK_SLASH; return 1; } c2 = re_string_peek_byte_case (input, 1); token->opr.c = c2; token->type = CHARACTER; #ifdef RE_ENABLE_I18N if (input->mb_cur_max > 1) { wint_t wc = re_string_wchar_at (input, re_string_cur_idx (input) + 1); token->word_char = IS_WIDE_WORD_CHAR (wc) != 0; } else #endif token->word_char = IS_WORD_CHAR (c2) != 0; switch (c2) { case '|': if (!(syntax & RE_LIMITED_OPS) && !(syntax & RE_NO_BK_VBAR)) token->type = OP_ALT; break; case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': if (!(syntax & RE_NO_BK_REFS)) { token->type = OP_BACK_REF; token->opr.idx = c2 - '1'; } break; case '<': if (!(syntax & RE_NO_GNU_OPS)) { token->type = ANCHOR; token->opr.ctx_type = WORD_FIRST; } break; case '>': if (!(syntax & RE_NO_GNU_OPS)) { token->type = ANCHOR; token->opr.ctx_type = WORD_LAST; } break; case 'b': if (!(syntax & RE_NO_GNU_OPS)) { token->type = ANCHOR; token->opr.ctx_type = WORD_DELIM; } break; case 'B': if (!(syntax & RE_NO_GNU_OPS)) { token->type = ANCHOR; token->opr.ctx_type = NOT_WORD_DELIM; } break; case 'w': if (!(syntax & RE_NO_GNU_OPS)) token->type = OP_WORD; break; case 'W': if (!(syntax & RE_NO_GNU_OPS)) token->type = OP_NOTWORD; break; case 's': if (!(syntax & RE_NO_GNU_OPS)) token->type = OP_SPACE; break; case 'S': if (!(syntax & RE_NO_GNU_OPS)) token->type = OP_NOTSPACE; break; case '`': if (!(syntax & RE_NO_GNU_OPS)) { token->type = ANCHOR; token->opr.ctx_type = BUF_FIRST; } break; case '\'': if (!(syntax & RE_NO_GNU_OPS)) { token->type = ANCHOR; token->opr.ctx_type = BUF_LAST; } break; case '(': if (!(syntax & RE_NO_BK_PARENS)) token->type = OP_OPEN_SUBEXP; break; case ')': if (!(syntax & RE_NO_BK_PARENS)) token->type = OP_CLOSE_SUBEXP; break; case '+': if (!(syntax & RE_LIMITED_OPS) && (syntax & RE_BK_PLUS_QM)) token->type = OP_DUP_PLUS; break; case '?': if (!(syntax & RE_LIMITED_OPS) && (syntax & RE_BK_PLUS_QM)) token->type = OP_DUP_QUESTION; break; case '{': if ((syntax & RE_INTERVALS) && (!(syntax & RE_NO_BK_BRACES))) token->type = OP_OPEN_DUP_NUM; break; case '}': if ((syntax & RE_INTERVALS) && (!(syntax & RE_NO_BK_BRACES))) token->type = OP_CLOSE_DUP_NUM; break; default: break; } return 2; } token->type = CHARACTER; #ifdef RE_ENABLE_I18N if (input->mb_cur_max > 1) { wint_t wc = re_string_wchar_at (input, re_string_cur_idx (input)); token->word_char = IS_WIDE_WORD_CHAR (wc) != 0; } else #endif token->word_char = IS_WORD_CHAR (token->opr.c); switch (c) { case '\n': if (syntax & RE_NEWLINE_ALT) token->type = OP_ALT; break; case '|': if (!(syntax & RE_LIMITED_OPS) && (syntax & RE_NO_BK_VBAR)) token->type = OP_ALT; break; case '*': token->type = OP_DUP_ASTERISK; break; case '+': if (!(syntax & RE_LIMITED_OPS) && !(syntax & RE_BK_PLUS_QM)) token->type = OP_DUP_PLUS; break; case '?': if (!(syntax & RE_LIMITED_OPS) && !(syntax & RE_BK_PLUS_QM)) token->type = OP_DUP_QUESTION; break; case '{': if ((syntax & RE_INTERVALS) && (syntax & RE_NO_BK_BRACES)) token->type = OP_OPEN_DUP_NUM; break; case '}': if ((syntax & RE_INTERVALS) && (syntax & RE_NO_BK_BRACES)) token->type = OP_CLOSE_DUP_NUM; break; case '(': if (syntax & RE_NO_BK_PARENS) token->type = OP_OPEN_SUBEXP; break; case ')': if (syntax & RE_NO_BK_PARENS) token->type = OP_CLOSE_SUBEXP; break; case '[': token->type = OP_OPEN_BRACKET; break; case '.': token->type = OP_PERIOD; break; case '^': if (!(syntax & (RE_CONTEXT_INDEP_ANCHORS | RE_CARET_ANCHORS_HERE)) && re_string_cur_idx (input) != 0) { char prev = re_string_peek_byte (input, -1); if (!(syntax & RE_NEWLINE_ALT) || prev != '\n') break; } token->type = ANCHOR; token->opr.ctx_type = LINE_FIRST; break; case '$': if (!(syntax & RE_CONTEXT_INDEP_ANCHORS) && re_string_cur_idx (input) + 1 != re_string_length (input)) { re_token_t next; re_string_skip_bytes (input, 1); peek_token (&next, input, syntax); re_string_skip_bytes (input, -1); if (next.type != OP_ALT && next.type != OP_CLOSE_SUBEXP) break; } token->type = ANCHOR; token->opr.ctx_type = LINE_LAST; break; default: break; } return 1; } /* Peek a token from INPUT, and return the length of the token. We must not use this function out of bracket expressions. */ static int internal_function peek_token_bracket (re_token_t *token, re_string_t *input, reg_syntax_t syntax) { unsigned char c; if (re_string_eoi (input)) { token->type = END_OF_RE; return 0; } c = re_string_peek_byte (input, 0); token->opr.c = c; #ifdef RE_ENABLE_I18N if (input->mb_cur_max > 1 && !re_string_first_byte (input, re_string_cur_idx (input))) { token->type = CHARACTER; return 1; } #endif /* RE_ENABLE_I18N */ if (c == '\\' && (syntax & RE_BACKSLASH_ESCAPE_IN_LISTS) && re_string_cur_idx (input) + 1 < re_string_length (input)) { /* In this case, '\' escape a character. */ unsigned char c2; re_string_skip_bytes (input, 1); c2 = re_string_peek_byte (input, 0); token->opr.c = c2; token->type = CHARACTER; return 1; } if (c == '[') /* '[' is a special char in a bracket exps. */ { unsigned char c2; int token_len; if (re_string_cur_idx (input) + 1 < re_string_length (input)) c2 = re_string_peek_byte (input, 1); else c2 = 0; token->opr.c = c2; token_len = 2; switch (c2) { case '.': token->type = OP_OPEN_COLL_ELEM; break; case '=': token->type = OP_OPEN_EQUIV_CLASS; break; case ':': if (syntax & RE_CHAR_CLASSES) { token->type = OP_OPEN_CHAR_CLASS; break; } /* else fall through. */ default: token->type = CHARACTER; token->opr.c = c; token_len = 1; break; } return token_len; } switch (c) { case '-': token->type = OP_CHARSET_RANGE; break; case ']': token->type = OP_CLOSE_BRACKET; break; case '^': token->type = OP_NON_MATCH_LIST; break; default: token->type = CHARACTER; } return 1; } /* Functions for parser. */ /* Entry point of the parser. Parse the regular expression REGEXP and return the structure tree. If an error is occured, ERR is set by error code, and return NULL. This function build the following tree, from regular expression : CAT / \ / \ EOR CAT means concatenation. EOR means end of regular expression. */ static bin_tree_t * parse (re_string_t *regexp, regex_t *preg, reg_syntax_t syntax, reg_errcode_t *err) { re_dfa_t *dfa = (re_dfa_t *) preg->buffer; bin_tree_t *tree, *eor, *root; re_token_t current_token; dfa->syntax = syntax; fetch_token (¤t_token, regexp, syntax | RE_CARET_ANCHORS_HERE); tree = parse_reg_exp (regexp, preg, ¤t_token, syntax, 0, err); if (BE (*err != REG_NOERROR && tree == NULL, 0)) return NULL; eor = create_tree (dfa, NULL, NULL, END_OF_RE); if (tree != NULL) root = create_tree (dfa, tree, eor, CONCAT); else root = eor; if (BE (eor == NULL || root == NULL, 0)) { *err = REG_ESPACE; return NULL; } return root; } /* This function build the following tree, from regular expression |: ALT / \ / \ ALT means alternative, which represents the operator `|'. */ static bin_tree_t * parse_reg_exp (re_string_t *regexp, regex_t *preg, re_token_t *token, reg_syntax_t syntax, int nest, reg_errcode_t *err) { re_dfa_t *dfa = (re_dfa_t *) preg->buffer; bin_tree_t *tree, *branch = NULL; tree = parse_branch (regexp, preg, token, syntax, nest, err); if (BE (*err != REG_NOERROR && tree == NULL, 0)) return NULL; while (token->type == OP_ALT) { fetch_token (token, regexp, syntax | RE_CARET_ANCHORS_HERE); if (token->type != OP_ALT && token->type != END_OF_RE && (nest == 0 || token->type != OP_CLOSE_SUBEXP)) { branch = parse_branch (regexp, preg, token, syntax, nest, err); if (BE (*err != REG_NOERROR && branch == NULL, 0)) return NULL; } else branch = NULL; tree = create_tree (dfa, tree, branch, OP_ALT); if (BE (tree == NULL, 0)) { *err = REG_ESPACE; return NULL; } } return tree; } /* This function build the following tree, from regular expression : CAT / \ / \ CAT means concatenation. */ static bin_tree_t * parse_branch (re_string_t *regexp, regex_t *preg, re_token_t *token, reg_syntax_t syntax, int nest, reg_errcode_t *err) { bin_tree_t *tree, *exp; re_dfa_t *dfa = (re_dfa_t *) preg->buffer; tree = parse_expression (regexp, preg, token, syntax, nest, err); if (BE (*err != REG_NOERROR && tree == NULL, 0)) return NULL; while (token->type != OP_ALT && token->type != END_OF_RE && (nest == 0 || token->type != OP_CLOSE_SUBEXP)) { exp = parse_expression (regexp, preg, token, syntax, nest, err); if (BE (*err != REG_NOERROR && exp == NULL, 0)) { return NULL; } if (tree != NULL && exp != NULL) { tree = create_tree (dfa, tree, exp, CONCAT); if (tree == NULL) { *err = REG_ESPACE; return NULL; } } else if (tree == NULL) tree = exp; /* Otherwise exp == NULL, we don't need to create new tree. */ } return tree; } /* This function build the following tree, from regular expression a*: * | a */ static bin_tree_t * parse_expression (re_string_t *regexp, regex_t *preg, re_token_t *token, reg_syntax_t syntax, int nest, reg_errcode_t *err) { re_dfa_t *dfa = (re_dfa_t *) preg->buffer; bin_tree_t *tree; switch (token->type) { case CHARACTER: tree = create_token_tree (dfa, NULL, NULL, token); if (BE (tree == NULL, 0)) { *err = REG_ESPACE; return NULL; } #ifdef RE_ENABLE_I18N if (dfa->mb_cur_max > 1) { while (!re_string_eoi (regexp) && !re_string_first_byte (regexp, re_string_cur_idx (regexp))) { bin_tree_t *mbc_remain; fetch_token (token, regexp, syntax); mbc_remain = create_token_tree (dfa, NULL, NULL, token); tree = create_tree (dfa, tree, mbc_remain, CONCAT); if (BE (mbc_remain == NULL || tree == NULL, 0)) { *err = REG_ESPACE; return NULL; } } } #endif break; case OP_OPEN_SUBEXP: tree = parse_sub_exp (regexp, preg, token, syntax, nest + 1, err); if (BE (*err != REG_NOERROR && tree == NULL, 0)) return NULL; break; case OP_OPEN_BRACKET: tree = parse_bracket_exp (regexp, dfa, token, syntax, err); if (BE (*err != REG_NOERROR && tree == NULL, 0)) return NULL; break; case OP_BACK_REF: if (!BE (dfa->completed_bkref_map & (1 << token->opr.idx), 1)) { *err = REG_ESUBREG; return NULL; } dfa->used_bkref_map |= 1 << token->opr.idx; tree = create_token_tree (dfa, NULL, NULL, token); if (BE (tree == NULL, 0)) { *err = REG_ESPACE; return NULL; } ++dfa->nbackref; dfa->has_mb_node = 1; break; case OP_OPEN_DUP_NUM: if (syntax & RE_CONTEXT_INVALID_DUP) { *err = REG_BADRPT; return NULL; } /* FALLTHROUGH */ case OP_DUP_ASTERISK: case OP_DUP_PLUS: case OP_DUP_QUESTION: if (syntax & RE_CONTEXT_INVALID_OPS) { *err = REG_BADRPT; return NULL; } else if (syntax & RE_CONTEXT_INDEP_OPS) { fetch_token (token, regexp, syntax); return parse_expression (regexp, preg, token, syntax, nest, err); } /* else fall through */ case OP_CLOSE_SUBEXP: if ((token->type == OP_CLOSE_SUBEXP) && !(syntax & RE_UNMATCHED_RIGHT_PAREN_ORD)) { *err = REG_ERPAREN; return NULL; } /* else fall through */ case OP_CLOSE_DUP_NUM: /* We treat it as a normal character. */ /* Then we can these characters as normal characters. */ token->type = CHARACTER; /* mb_partial and word_char bits should be initialized already by peek_token. */ tree = create_token_tree (dfa, NULL, NULL, token); if (BE (tree == NULL, 0)) { *err = REG_ESPACE; return NULL; } break; case ANCHOR: if ((token->opr.ctx_type & (WORD_DELIM | NOT_WORD_DELIM | WORD_FIRST | WORD_LAST)) && dfa->word_ops_used == 0) init_word_char (dfa); if (token->opr.ctx_type == WORD_DELIM || token->opr.ctx_type == NOT_WORD_DELIM) { bin_tree_t *tree_first, *tree_last; if (token->opr.ctx_type == WORD_DELIM) { token->opr.ctx_type = WORD_FIRST; tree_first = create_token_tree (dfa, NULL, NULL, token); token->opr.ctx_type = WORD_LAST; } else { token->opr.ctx_type = INSIDE_WORD; tree_first = create_token_tree (dfa, NULL, NULL, token); token->opr.ctx_type = INSIDE_NOTWORD; } tree_last = create_token_tree (dfa, NULL, NULL, token); tree = create_tree (dfa, tree_first, tree_last, OP_ALT); if (BE (tree_first == NULL || tree_last == NULL || tree == NULL, 0)) { *err = REG_ESPACE; return NULL; } } else { tree = create_token_tree (dfa, NULL, NULL, token); if (BE (tree == NULL, 0)) { *err = REG_ESPACE; return NULL; } } /* We must return here, since ANCHORs can't be followed by repetition operators. eg. RE"^*" is invalid or "", it must not be "". */ fetch_token (token, regexp, syntax); return tree; case OP_PERIOD: tree = create_token_tree (dfa, NULL, NULL, token); if (BE (tree == NULL, 0)) { *err = REG_ESPACE; return NULL; } if (dfa->mb_cur_max > 1) dfa->has_mb_node = 1; break; case OP_WORD: case OP_NOTWORD: tree = build_charclass_op (dfa, regexp->trans, "alnum", "_", token->type == OP_NOTWORD, err); if (BE (*err != REG_NOERROR && tree == NULL, 0)) return NULL; break; case OP_SPACE: case OP_NOTSPACE: tree = build_charclass_op (dfa, regexp->trans, "space", "", token->type == OP_NOTSPACE, err); if (BE (*err != REG_NOERROR && tree == NULL, 0)) return NULL; break; case OP_ALT: case END_OF_RE: return NULL; case BACK_SLASH: *err = REG_EESCAPE; return NULL; default: /* Must not happen? */ #ifdef DEBUG assert (0); #endif return NULL; } fetch_token (token, regexp, syntax); while (token->type == OP_DUP_ASTERISK || token->type == OP_DUP_PLUS || token->type == OP_DUP_QUESTION || token->type == OP_OPEN_DUP_NUM) { tree = parse_dup_op (tree, regexp, dfa, token, syntax, err); if (BE (*err != REG_NOERROR && tree == NULL, 0)) return NULL; /* In BRE consecutive duplications are not allowed. */ if ((syntax & RE_CONTEXT_INVALID_DUP) && (token->type == OP_DUP_ASTERISK || token->type == OP_OPEN_DUP_NUM)) { *err = REG_BADRPT; return NULL; } } return tree; } /* This function build the following tree, from regular expression (): SUBEXP | */ static bin_tree_t * parse_sub_exp (re_string_t *regexp, regex_t *preg, re_token_t *token, reg_syntax_t syntax, int nest, reg_errcode_t *err) { re_dfa_t *dfa = (re_dfa_t *) preg->buffer; bin_tree_t *tree; size_t cur_nsub; cur_nsub = preg->re_nsub++; fetch_token (token, regexp, syntax | RE_CARET_ANCHORS_HERE); /* The subexpression may be a null string. */ if (token->type == OP_CLOSE_SUBEXP) tree = NULL; else { tree = parse_reg_exp (regexp, preg, token, syntax, nest, err); if (BE (*err == REG_NOERROR && token->type != OP_CLOSE_SUBEXP, 0)) *err = REG_EPAREN; if (BE (*err != REG_NOERROR, 0)) return NULL; } if (cur_nsub <= '9' - '1') dfa->completed_bkref_map |= 1 << cur_nsub; tree = create_tree (dfa, tree, NULL, SUBEXP); if (BE (tree == NULL, 0)) { *err = REG_ESPACE; return NULL; } tree->token.opr.idx = cur_nsub; return tree; } /* This function parse repetition operators like "*", "+", "{1,3}" etc. */ static bin_tree_t * parse_dup_op (bin_tree_t *elem, re_string_t *regexp, re_dfa_t *dfa, re_token_t *token, reg_syntax_t syntax, reg_errcode_t *err) { bin_tree_t *tree = NULL, *old_tree = NULL; int i, start, end, start_idx = re_string_cur_idx (regexp); #ifndef RE_TOKEN_INIT_BUG re_token_t start_token = *token; #else re_token_t start_token; memcpy ((void *) &start_token, (void *) token, sizeof start_token); #endif if (token->type == OP_OPEN_DUP_NUM) { end = 0; start = fetch_number (regexp, token, syntax); if (start == -1) { if (token->type == CHARACTER && token->opr.c == ',') start = 0; /* We treat "{,m}" as "{0,m}". */ else { *err = REG_BADBR; /* {} is invalid. */ return NULL; } } if (BE (start != -2, 1)) { /* We treat "{n}" as "{n,n}". */ end = ((token->type == OP_CLOSE_DUP_NUM) ? start : ((token->type == CHARACTER && token->opr.c == ',') ? fetch_number (regexp, token, syntax) : -2)); } if (BE (start == -2 || end == -2, 0)) { /* Invalid sequence. */ if (BE (!(syntax & RE_INVALID_INTERVAL_ORD), 0)) { if (token->type == END_OF_RE) *err = REG_EBRACE; else *err = REG_BADBR; return NULL; } /* If the syntax bit is set, rollback. */ re_string_set_index (regexp, start_idx); *token = start_token; token->type = CHARACTER; /* mb_partial and word_char bits should be already initialized by peek_token. */ return elem; } if (BE ((end != -1 && start > end) || token->type != OP_CLOSE_DUP_NUM, 0)) { /* First number greater than second. */ *err = REG_BADBR; return NULL; } } else { start = (token->type == OP_DUP_PLUS) ? 1 : 0; end = (token->type == OP_DUP_QUESTION) ? 1 : -1; } fetch_token (token, regexp, syntax); if (BE (elem == NULL, 0)) return NULL; if (BE (start == 0 && end == 0, 0)) { postorder (elem, free_tree, NULL); return NULL; } /* Extract "{n,m}" to "...{0,}". */ if (BE (start > 0, 0)) { tree = elem; for (i = 2; i <= start; ++i) { elem = duplicate_tree (elem, dfa); tree = create_tree (dfa, tree, elem, CONCAT); if (BE (elem == NULL || tree == NULL, 0)) goto parse_dup_op_espace; } if (start == end) return tree; /* Duplicate ELEM before it is marked optional. */ elem = duplicate_tree (elem, dfa); old_tree = tree; } else old_tree = NULL; if (elem->token.type == SUBEXP) postorder (elem, mark_opt_subexp, (void *) (long) elem->token.opr.idx); tree = create_tree (dfa, elem, NULL, (end == -1 ? OP_DUP_ASTERISK : OP_ALT)); if (BE (tree == NULL, 0)) goto parse_dup_op_espace; /* This loop is actually executed only when end != -1, to rewrite {0,n} as ((...?)?)?... We have already created the start+1-th copy. */ for (i = start + 2; i <= end; ++i) { elem = duplicate_tree (elem, dfa); tree = create_tree (dfa, tree, elem, CONCAT); if (BE (elem == NULL || tree == NULL, 0)) goto parse_dup_op_espace; tree = create_tree (dfa, tree, NULL, OP_ALT); if (BE (tree == NULL, 0)) goto parse_dup_op_espace; } if (old_tree) tree = create_tree (dfa, old_tree, tree, CONCAT); return tree; parse_dup_op_espace: *err = REG_ESPACE; return NULL; } /* Size of the names for collating symbol/equivalence_class/character_class. I'm not sure, but maybe enough. */ #define BRACKET_NAME_BUF_SIZE 32 #ifndef _LIBC /* Local function for parse_bracket_exp only used in case of NOT _LIBC. Build the range expression which starts from START_ELEM, and ends at END_ELEM. The result are written to MBCSET and SBCSET. RANGE_ALLOC is the allocated size of mbcset->range_starts, and mbcset->range_ends, is a pointer argument sinse we may update it. */ static reg_errcode_t internal_function # ifdef RE_ENABLE_I18N build_range_exp (bitset_t sbcset, re_charset_t *mbcset, int *range_alloc, bracket_elem_t *start_elem, bracket_elem_t *end_elem) # else /* not RE_ENABLE_I18N */ build_range_exp (bitset_t sbcset, bracket_elem_t *start_elem, bracket_elem_t *end_elem) # endif /* not RE_ENABLE_I18N */ { unsigned int start_ch, end_ch; /* Equivalence Classes and Character Classes can't be a range start/end. */ if (BE (start_elem->type == EQUIV_CLASS || start_elem->type == CHAR_CLASS || end_elem->type == EQUIV_CLASS || end_elem->type == CHAR_CLASS, 0)) return REG_ERANGE; /* We can handle no multi character collating elements without libc support. */ if (BE ((start_elem->type == COLL_SYM && strlen ((char *) start_elem->opr.name) > 1) || (end_elem->type == COLL_SYM && strlen ((char *) end_elem->opr.name) > 1), 0)) return REG_ECOLLATE; # ifdef RE_ENABLE_I18N { wchar_t wc; wint_t start_wc; wint_t end_wc; wchar_t cmp_buf[6] = {L'\0', L'\0', L'\0', L'\0', L'\0', L'\0'}; start_ch = ((start_elem->type == SB_CHAR) ? start_elem->opr.ch : ((start_elem->type == COLL_SYM) ? start_elem->opr.name[0] : 0)); end_ch = ((end_elem->type == SB_CHAR) ? end_elem->opr.ch : ((end_elem->type == COLL_SYM) ? end_elem->opr.name[0] : 0)); #ifdef GAWK /* * Fedora Core 2, maybe others, have broken `btowc' that returns -1 * for any value > 127. Sigh. Note that `start_ch' and `end_ch' are * unsigned, so we don't have sign extension problems. */ start_wc = ((start_elem->type == SB_CHAR || start_elem->type == COLL_SYM) ? start_ch : start_elem->opr.wch); end_wc = ((end_elem->type == SB_CHAR || end_elem->type == COLL_SYM) ? end_ch : end_elem->opr.wch); #else start_wc = ((start_elem->type == SB_CHAR || start_elem->type == COLL_SYM) ? __btowc (start_ch) : start_elem->opr.wch); end_wc = ((end_elem->type == SB_CHAR || end_elem->type == COLL_SYM) ? __btowc (end_ch) : end_elem->opr.wch); #endif if (start_wc == WEOF || end_wc == WEOF) return REG_ECOLLATE; cmp_buf[0] = start_wc; cmp_buf[4] = end_wc; if (wcscoll (cmp_buf, cmp_buf + 4) > 0) return REG_ERANGE; /* Got valid collation sequence values, add them as a new entry. However, for !_LIBC we have no collation elements: if the character set is single byte, the single byte character set that we build below suffices. parse_bracket_exp passes no MBCSET if dfa->mb_cur_max == 1. */ if (mbcset) { /* Check the space of the arrays. */ if (BE (*range_alloc == mbcset->nranges, 0)) { /* There is not enough space, need realloc. */ wchar_t *new_array_start, *new_array_end; int new_nranges; /* +1 in case of mbcset->nranges is 0. */ new_nranges = 2 * mbcset->nranges + 1; /* Use realloc since mbcset->range_starts and mbcset->range_ends are NULL if *range_alloc == 0. */ new_array_start = re_realloc (mbcset->range_starts, wchar_t, new_nranges); new_array_end = re_realloc (mbcset->range_ends, wchar_t, new_nranges); if (BE (new_array_start == NULL || new_array_end == NULL, 0)) return REG_ESPACE; mbcset->range_starts = new_array_start; mbcset->range_ends = new_array_end; *range_alloc = new_nranges; } mbcset->range_starts[mbcset->nranges] = start_wc; mbcset->range_ends[mbcset->nranges++] = end_wc; } /* Build the table for single byte characters. */ for (wc = 0; wc < SBC_MAX; ++wc) { cmp_buf[2] = wc; if (wcscoll (cmp_buf, cmp_buf + 2) <= 0 && wcscoll (cmp_buf + 2, cmp_buf + 4) <= 0) bitset_set (sbcset, wc); } } # else /* not RE_ENABLE_I18N */ { unsigned int ch; start_ch = ((start_elem->type == SB_CHAR ) ? start_elem->opr.ch : ((start_elem->type == COLL_SYM) ? start_elem->opr.name[0] : 0)); end_ch = ((end_elem->type == SB_CHAR ) ? end_elem->opr.ch : ((end_elem->type == COLL_SYM) ? end_elem->opr.name[0] : 0)); if (start_ch > end_ch) return REG_ERANGE; /* Build the table for single byte characters. */ for (ch = 0; ch < SBC_MAX; ++ch) if (start_ch <= ch && ch <= end_ch) bitset_set (sbcset, ch); } # endif /* not RE_ENABLE_I18N */ return REG_NOERROR; } #endif /* not _LIBC */ #ifndef _LIBC /* Helper function for parse_bracket_exp only used in case of NOT _LIBC.. Build the collating element which is represented by NAME. The result are written to MBCSET and SBCSET. COLL_SYM_ALLOC is the allocated size of mbcset->coll_sym, is a pointer argument since we may update it. */ static reg_errcode_t internal_function # ifdef RE_ENABLE_I18N build_collating_symbol (bitset_t sbcset, re_charset_t *mbcset, int *coll_sym_alloc, const unsigned char *name) # else /* not RE_ENABLE_I18N */ build_collating_symbol (bitset_t sbcset, const unsigned char *name) # endif /* not RE_ENABLE_I18N */ { size_t name_len = strlen ((const char *) name); if (BE (name_len != 1, 0)) return REG_ECOLLATE; else { bitset_set (sbcset, name[0]); return REG_NOERROR; } } #endif /* not _LIBC */ /* This function parse bracket expression like "[abc]", "[a-c]", "[[.a-a.]]" etc. */ static bin_tree_t * parse_bracket_exp (re_string_t *regexp, re_dfa_t *dfa, re_token_t *token, reg_syntax_t syntax, reg_errcode_t *err) { #ifdef _LIBC const unsigned char *collseqmb; const char *collseqwc; uint32_t nrules; int32_t table_size; const int32_t *symb_table; const unsigned char *extra; /* Local function for parse_bracket_exp used in _LIBC environement. Seek the collating symbol entry correspondings to NAME. Return the index of the symbol in the SYMB_TABLE. */ auto inline int32_t __attribute ((always_inline)) seek_collating_symbol_entry (name, name_len) const unsigned char *name; size_t name_len; { int32_t hash = elem_hash ((const char *) name, name_len); int32_t elem = hash % table_size; if (symb_table[2 * elem] != 0) { int32_t second = hash % (table_size - 2) + 1; do { /* First compare the hashing value. */ if (symb_table[2 * elem] == hash /* Compare the length of the name. */ && name_len == extra[symb_table[2 * elem + 1]] /* Compare the name. */ && memcmp (name, &extra[symb_table[2 * elem + 1] + 1], name_len) == 0) { /* Yep, this is the entry. */ break; } /* Next entry. */ elem += second; } while (symb_table[2 * elem] != 0); } return elem; } /* Local function for parse_bracket_exp used in _LIBC environment. Look up the collation sequence value of BR_ELEM. Return the value if succeeded, UINT_MAX otherwise. */ auto inline unsigned int __attribute ((always_inline)) lookup_collation_sequence_value (br_elem) bracket_elem_t *br_elem; { if (br_elem->type == SB_CHAR) { /* if (MB_CUR_MAX == 1) */ if (nrules == 0) return collseqmb[br_elem->opr.ch]; else { wint_t wc = __btowc (br_elem->opr.ch); return __collseq_table_lookup (collseqwc, wc); } } else if (br_elem->type == MB_CHAR) { if (nrules != 0) return __collseq_table_lookup (collseqwc, br_elem->opr.wch); } else if (br_elem->type == COLL_SYM) { size_t sym_name_len = strlen ((char *) br_elem->opr.name); if (nrules != 0) { int32_t elem, idx; elem = seek_collating_symbol_entry (br_elem->opr.name, sym_name_len); if (symb_table[2 * elem] != 0) { /* We found the entry. */ idx = symb_table[2 * elem + 1]; /* Skip the name of collating element name. */ idx += 1 + extra[idx]; /* Skip the byte sequence of the collating element. */ idx += 1 + extra[idx]; /* Adjust for the alignment. */ idx = (idx + 3) & ~3; /* Skip the multibyte collation sequence value. */ idx += sizeof (unsigned int); /* Skip the wide char sequence of the collating element. */ idx += sizeof (unsigned int) * (1 + *(unsigned int *) (extra + idx)); /* Return the collation sequence value. */ return *(unsigned int *) (extra + idx); } else if (symb_table[2 * elem] == 0 && sym_name_len == 1) { /* No valid character. Match it as a single byte character. */ return collseqmb[br_elem->opr.name[0]]; } } else if (sym_name_len == 1) return collseqmb[br_elem->opr.name[0]]; } return UINT_MAX; } /* Local function for parse_bracket_exp used in _LIBC environement. Build the range expression which starts from START_ELEM, and ends at END_ELEM. The result are written to MBCSET and SBCSET. RANGE_ALLOC is the allocated size of mbcset->range_starts, and mbcset->range_ends, is a pointer argument sinse we may update it. */ auto inline reg_errcode_t __attribute ((always_inline)) build_range_exp (sbcset, mbcset, range_alloc, start_elem, end_elem) re_charset_t *mbcset; int *range_alloc; bitset_t sbcset; bracket_elem_t *start_elem, *end_elem; { unsigned int ch; uint32_t start_collseq; uint32_t end_collseq; /* Equivalence Classes and Character Classes can't be a range start/end. */ if (BE (start_elem->type == EQUIV_CLASS || start_elem->type == CHAR_CLASS || end_elem->type == EQUIV_CLASS || end_elem->type == CHAR_CLASS, 0)) return REG_ERANGE; start_collseq = lookup_collation_sequence_value (start_elem); end_collseq = lookup_collation_sequence_value (end_elem); /* Check start/end collation sequence values. */ if (BE (start_collseq == UINT_MAX || end_collseq == UINT_MAX, 0)) return REG_ECOLLATE; if (BE ((syntax & RE_NO_EMPTY_RANGES) && start_collseq > end_collseq, 0)) return REG_ERANGE; /* Got valid collation sequence values, add them as a new entry. However, if we have no collation elements, and the character set is single byte, the single byte character set that we build below suffices. */ if (nrules > 0 || dfa->mb_cur_max > 1) { /* Check the space of the arrays. */ if (BE (*range_alloc == mbcset->nranges, 0)) { /* There is not enough space, need realloc. */ uint32_t *new_array_start; uint32_t *new_array_end; int new_nranges; /* +1 in case of mbcset->nranges is 0. */ new_nranges = 2 * mbcset->nranges + 1; new_array_start = re_realloc (mbcset->range_starts, uint32_t, new_nranges); new_array_end = re_realloc (mbcset->range_ends, uint32_t, new_nranges); if (BE (new_array_start == NULL || new_array_end == NULL, 0)) return REG_ESPACE; mbcset->range_starts = new_array_start; mbcset->range_ends = new_array_end; *range_alloc = new_nranges; } mbcset->range_starts[mbcset->nranges] = start_collseq; mbcset->range_ends[mbcset->nranges++] = end_collseq; } /* Build the table for single byte characters. */ for (ch = 0; ch < SBC_MAX; ch++) { uint32_t ch_collseq; /* if (MB_CUR_MAX == 1) */ if (nrules == 0) ch_collseq = collseqmb[ch]; else ch_collseq = __collseq_table_lookup (collseqwc, __btowc (ch)); if (start_collseq <= ch_collseq && ch_collseq <= end_collseq) bitset_set (sbcset, ch); } return REG_NOERROR; } /* Local function for parse_bracket_exp used in _LIBC environement. Build the collating element which is represented by NAME. The result are written to MBCSET and SBCSET. COLL_SYM_ALLOC is the allocated size of mbcset->coll_sym, is a pointer argument sinse we may update it. */ auto inline reg_errcode_t __attribute ((always_inline)) build_collating_symbol (sbcset, mbcset, coll_sym_alloc, name) re_charset_t *mbcset; int *coll_sym_alloc; bitset_t sbcset; const unsigned char *name; { int32_t elem, idx; size_t name_len = strlen ((const char *) name); if (nrules != 0) { elem = seek_collating_symbol_entry (name, name_len); if (symb_table[2 * elem] != 0) { /* We found the entry. */ idx = symb_table[2 * elem + 1]; /* Skip the name of collating element name. */ idx += 1 + extra[idx]; } else if (symb_table[2 * elem] == 0 && name_len == 1) { /* No valid character, treat it as a normal character. */ bitset_set (sbcset, name[0]); return REG_NOERROR; } else return REG_ECOLLATE; /* Got valid collation sequence, add it as a new entry. */ /* Check the space of the arrays. */ if (BE (*coll_sym_alloc == mbcset->ncoll_syms, 0)) { /* Not enough, realloc it. */ /* +1 in case of mbcset->ncoll_syms is 0. */ int new_coll_sym_alloc = 2 * mbcset->ncoll_syms + 1; /* Use realloc since mbcset->coll_syms is NULL if *alloc == 0. */ int32_t *new_coll_syms = re_realloc (mbcset->coll_syms, int32_t, new_coll_sym_alloc); if (BE (new_coll_syms == NULL, 0)) return REG_ESPACE; mbcset->coll_syms = new_coll_syms; *coll_sym_alloc = new_coll_sym_alloc; } mbcset->coll_syms[mbcset->ncoll_syms++] = idx; return REG_NOERROR; } else { if (BE (name_len != 1, 0)) return REG_ECOLLATE; else { bitset_set (sbcset, name[0]); return REG_NOERROR; } } } #endif re_token_t br_token; re_bitset_ptr_t sbcset; #ifdef RE_ENABLE_I18N re_charset_t *mbcset; int coll_sym_alloc = 0, range_alloc = 0, mbchar_alloc = 0; int equiv_class_alloc = 0, char_class_alloc = 0; #endif /* not RE_ENABLE_I18N */ int non_match = 0; bin_tree_t *work_tree; int token_len; int first_round = 1; #ifdef _LIBC collseqmb = (const unsigned char *) _NL_CURRENT (LC_COLLATE, _NL_COLLATE_COLLSEQMB); nrules = _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES); if (nrules) { /* if (MB_CUR_MAX > 1) */ collseqwc = _NL_CURRENT (LC_COLLATE, _NL_COLLATE_COLLSEQWC); table_size = _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_SYMB_HASH_SIZEMB); symb_table = (const int32_t *) _NL_CURRENT (LC_COLLATE, _NL_COLLATE_SYMB_TABLEMB); extra = (const unsigned char *) _NL_CURRENT (LC_COLLATE, _NL_COLLATE_SYMB_EXTRAMB); } #endif sbcset = (re_bitset_ptr_t) calloc (sizeof (bitset_t), 1); #ifdef RE_ENABLE_I18N mbcset = (re_charset_t *) calloc (sizeof (re_charset_t), 1); #endif /* RE_ENABLE_I18N */ #ifdef RE_ENABLE_I18N if (BE (sbcset == NULL || mbcset == NULL, 0)) #else if (BE (sbcset == NULL, 0)) #endif /* RE_ENABLE_I18N */ { *err = REG_ESPACE; return NULL; } token_len = peek_token_bracket (token, regexp, syntax); if (BE (token->type == END_OF_RE, 0)) { *err = REG_BADPAT; goto parse_bracket_exp_free_return; } if (token->type == OP_NON_MATCH_LIST) { #ifdef RE_ENABLE_I18N mbcset->non_match = 1; #endif /* not RE_ENABLE_I18N */ non_match = 1; if (syntax & RE_HAT_LISTS_NOT_NEWLINE) bitset_set (sbcset, '\n'); re_string_skip_bytes (regexp, token_len); /* Skip a token. */ token_len = peek_token_bracket (token, regexp, syntax); if (BE (token->type == END_OF_RE, 0)) { *err = REG_BADPAT; goto parse_bracket_exp_free_return; } } /* We treat the first ']' as a normal character. */ if (token->type == OP_CLOSE_BRACKET) token->type = CHARACTER; while (1) { bracket_elem_t start_elem, end_elem; unsigned char start_name_buf[BRACKET_NAME_BUF_SIZE]; unsigned char end_name_buf[BRACKET_NAME_BUF_SIZE]; reg_errcode_t ret; int token_len2 = 0, is_range_exp = 0; re_token_t token2; start_elem.opr.name = start_name_buf; ret = parse_bracket_element (&start_elem, regexp, token, token_len, dfa, syntax, first_round); if (BE (ret != REG_NOERROR, 0)) { *err = ret; goto parse_bracket_exp_free_return; } first_round = 0; /* Get information about the next token. We need it in any case. */ token_len = peek_token_bracket (token, regexp, syntax); /* Do not check for ranges if we know they are not allowed. */ if (start_elem.type != CHAR_CLASS && start_elem.type != EQUIV_CLASS) { if (BE (token->type == END_OF_RE, 0)) { *err = REG_EBRACK; goto parse_bracket_exp_free_return; } if (token->type == OP_CHARSET_RANGE) { re_string_skip_bytes (regexp, token_len); /* Skip '-'. */ token_len2 = peek_token_bracket (&token2, regexp, syntax); if (BE (token2.type == END_OF_RE, 0)) { *err = REG_EBRACK; goto parse_bracket_exp_free_return; } if (token2.type == OP_CLOSE_BRACKET) { /* We treat the last '-' as a normal character. */ re_string_skip_bytes (regexp, -token_len); token->type = CHARACTER; } else is_range_exp = 1; } } if (is_range_exp == 1) { end_elem.opr.name = end_name_buf; ret = parse_bracket_element (&end_elem, regexp, &token2, token_len2, dfa, syntax, 1); if (BE (ret != REG_NOERROR, 0)) { *err = ret; goto parse_bracket_exp_free_return; } token_len = peek_token_bracket (token, regexp, syntax); #ifdef _LIBC *err = build_range_exp (sbcset, mbcset, &range_alloc, &start_elem, &end_elem); #else # ifdef RE_ENABLE_I18N *err = build_range_exp (sbcset, dfa->mb_cur_max > 1 ? mbcset : NULL, &range_alloc, &start_elem, &end_elem); # else *err = build_range_exp (sbcset, &start_elem, &end_elem); # endif #endif /* RE_ENABLE_I18N */ if (BE (*err != REG_NOERROR, 0)) goto parse_bracket_exp_free_return; } else { switch (start_elem.type) { case SB_CHAR: bitset_set (sbcset, start_elem.opr.ch); break; #ifdef RE_ENABLE_I18N case MB_CHAR: /* Check whether the array has enough space. */ if (BE (mbchar_alloc == mbcset->nmbchars, 0)) { wchar_t *new_mbchars; /* Not enough, realloc it. */ /* +1 in case of mbcset->nmbchars is 0. */ mbchar_alloc = 2 * mbcset->nmbchars + 1; /* Use realloc since array is NULL if *alloc == 0. */ new_mbchars = re_realloc (mbcset->mbchars, wchar_t, mbchar_alloc); if (BE (new_mbchars == NULL, 0)) goto parse_bracket_exp_espace; mbcset->mbchars = new_mbchars; } mbcset->mbchars[mbcset->nmbchars++] = start_elem.opr.wch; break; #endif /* RE_ENABLE_I18N */ case EQUIV_CLASS: *err = build_equiv_class (sbcset, #ifdef RE_ENABLE_I18N mbcset, &equiv_class_alloc, #endif /* RE_ENABLE_I18N */ start_elem.opr.name); if (BE (*err != REG_NOERROR, 0)) goto parse_bracket_exp_free_return; break; case COLL_SYM: *err = build_collating_symbol (sbcset, #ifdef RE_ENABLE_I18N mbcset, &coll_sym_alloc, #endif /* RE_ENABLE_I18N */ start_elem.opr.name); if (BE (*err != REG_NOERROR, 0)) goto parse_bracket_exp_free_return; break; case CHAR_CLASS: *err = build_charclass (regexp->trans, sbcset, #ifdef RE_ENABLE_I18N mbcset, &char_class_alloc, #endif /* RE_ENABLE_I18N */ (const char *) start_elem.opr.name, syntax); if (BE (*err != REG_NOERROR, 0)) goto parse_bracket_exp_free_return; break; default: assert (0); break; } } if (BE (token->type == END_OF_RE, 0)) { *err = REG_EBRACK; goto parse_bracket_exp_free_return; } if (token->type == OP_CLOSE_BRACKET) break; } re_string_skip_bytes (regexp, token_len); /* Skip a token. */ /* If it is non-matching list. */ if (non_match) bitset_not (sbcset); #ifdef RE_ENABLE_I18N /* Ensure only single byte characters are set. */ if (dfa->mb_cur_max > 1) bitset_mask (sbcset, dfa->sb_char); if (mbcset->nmbchars || mbcset->ncoll_syms || mbcset->nequiv_classes || mbcset->nranges || (dfa->mb_cur_max > 1 && (mbcset->nchar_classes || mbcset->non_match))) { bin_tree_t *mbc_tree; int sbc_idx; /* Build a tree for complex bracket. */ dfa->has_mb_node = 1; br_token.type = COMPLEX_BRACKET; br_token.opr.mbcset = mbcset; mbc_tree = create_token_tree (dfa, NULL, NULL, &br_token); if (BE (mbc_tree == NULL, 0)) goto parse_bracket_exp_espace; for (sbc_idx = 0; sbc_idx < BITSET_WORDS; ++sbc_idx) if (sbcset[sbc_idx]) break; /* If there are no bits set in sbcset, there is no point of having both SIMPLE_BRACKET and COMPLEX_BRACKET. */ if (sbc_idx < BITSET_WORDS) { /* Build a tree for simple bracket. */ br_token.type = SIMPLE_BRACKET; br_token.opr.sbcset = sbcset; work_tree = create_token_tree (dfa, NULL, NULL, &br_token); if (BE (work_tree == NULL, 0)) goto parse_bracket_exp_espace; /* Then join them by ALT node. */ work_tree = create_tree (dfa, work_tree, mbc_tree, OP_ALT); if (BE (work_tree == NULL, 0)) goto parse_bracket_exp_espace; } else { re_free (sbcset); work_tree = mbc_tree; } } else #endif /* not RE_ENABLE_I18N */ { #ifdef RE_ENABLE_I18N free_charset (mbcset); #endif /* Build a tree for simple bracket. */ br_token.type = SIMPLE_BRACKET; br_token.opr.sbcset = sbcset; work_tree = create_token_tree (dfa, NULL, NULL, &br_token); if (BE (work_tree == NULL, 0)) goto parse_bracket_exp_espace; } return work_tree; parse_bracket_exp_espace: *err = REG_ESPACE; parse_bracket_exp_free_return: re_free (sbcset); #ifdef RE_ENABLE_I18N free_charset (mbcset); #endif /* RE_ENABLE_I18N */ return NULL; } /* Parse an element in the bracket expression. */ static reg_errcode_t parse_bracket_element (bracket_elem_t *elem, re_string_t *regexp, re_token_t *token, int token_len, UNUSED re_dfa_t *dfa, reg_syntax_t syntax, int accept_hyphen) { #ifdef RE_ENABLE_I18N int cur_char_size; cur_char_size = re_string_char_size_at (regexp, re_string_cur_idx (regexp)); if (cur_char_size > 1) { elem->type = MB_CHAR; elem->opr.wch = re_string_wchar_at (regexp, re_string_cur_idx (regexp)); re_string_skip_bytes (regexp, cur_char_size); return REG_NOERROR; } #endif /* RE_ENABLE_I18N */ re_string_skip_bytes (regexp, token_len); /* Skip a token. */ if (token->type == OP_OPEN_COLL_ELEM || token->type == OP_OPEN_CHAR_CLASS || token->type == OP_OPEN_EQUIV_CLASS) return parse_bracket_symbol (elem, regexp, token); if (BE (token->type == OP_CHARSET_RANGE, 0) && !accept_hyphen) { /* A '-' must only appear as anything but a range indicator before the closing bracket. Everything else is an error. */ re_token_t token2; (void) peek_token_bracket (&token2, regexp, syntax); if (token2.type != OP_CLOSE_BRACKET) /* The actual error value is not standardized since this whole case is undefined. But ERANGE makes good sense. */ return REG_ERANGE; } elem->type = SB_CHAR; elem->opr.ch = token->opr.c; return REG_NOERROR; } /* Parse a bracket symbol in the bracket expression. Bracket symbols are such as [::], [..], and [==]. */ static reg_errcode_t parse_bracket_symbol (bracket_elem_t *elem, re_string_t *regexp, re_token_t *token) { unsigned char ch, delim = token->opr.c; int i = 0; if (re_string_eoi(regexp)) return REG_EBRACK; for (;; ++i) { if (i >= BRACKET_NAME_BUF_SIZE) return REG_EBRACK; if (token->type == OP_OPEN_CHAR_CLASS) ch = re_string_fetch_byte_case (regexp); else ch = re_string_fetch_byte (regexp); if (re_string_eoi(regexp)) return REG_EBRACK; if (ch == delim && re_string_peek_byte (regexp, 0) == ']') break; elem->opr.name[i] = ch; } re_string_skip_bytes (regexp, 1); elem->opr.name[i] = '\0'; switch (token->type) { case OP_OPEN_COLL_ELEM: elem->type = COLL_SYM; break; case OP_OPEN_EQUIV_CLASS: elem->type = EQUIV_CLASS; break; case OP_OPEN_CHAR_CLASS: elem->type = CHAR_CLASS; break; default: break; } return REG_NOERROR; } /* Helper function for parse_bracket_exp. Build the equivalence class which is represented by NAME. The result are written to MBCSET and SBCSET. EQUIV_CLASS_ALLOC is the allocated size of mbcset->equiv_classes, is a pointer argument sinse we may update it. */ static reg_errcode_t #ifdef RE_ENABLE_I18N build_equiv_class (bitset_t sbcset, re_charset_t *mbcset, int *equiv_class_alloc, const unsigned char *name) #else /* not RE_ENABLE_I18N */ build_equiv_class (bitset_t sbcset, const unsigned char *name) #endif /* not RE_ENABLE_I18N */ { #ifdef _LIBC uint32_t nrules = _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES); if (nrules != 0) { const int32_t *table, *indirect; const unsigned char *weights, *extra, *cp; unsigned char char_buf[2]; int32_t idx1, idx2; unsigned int ch; size_t len; /* This #include defines a local function! */ # include /* Calculate the index for equivalence class. */ cp = name; table = (const int32_t *) _NL_CURRENT (LC_COLLATE, _NL_COLLATE_TABLEMB); weights = (const unsigned char *) _NL_CURRENT (LC_COLLATE, _NL_COLLATE_WEIGHTMB); extra = (const unsigned char *) _NL_CURRENT (LC_COLLATE, _NL_COLLATE_EXTRAMB); indirect = (const int32_t *) _NL_CURRENT (LC_COLLATE, _NL_COLLATE_INDIRECTMB); idx1 = findidx (&cp); if (BE (idx1 == 0 || cp < name + strlen ((const char *) name), 0)) /* This isn't a valid character. */ return REG_ECOLLATE; /* Build single byte matcing table for this equivalence class. */ char_buf[1] = (unsigned char) '\0'; len = weights[idx1 & 0xffffff]; for (ch = 0; ch < SBC_MAX; ++ch) { char_buf[0] = ch; cp = char_buf; idx2 = findidx (&cp); /* idx2 = table[ch]; */ if (idx2 == 0) /* This isn't a valid character. */ continue; /* Compare only if the length matches and the collation rule index is the same. */ if (len == weights[idx2 & 0xffffff] && (idx1 >> 24) == (idx2 >> 24)) { int cnt = 0; while (cnt <= len && weights[(idx1 & 0xffffff) + 1 + cnt] == weights[(idx2 & 0xffffff) + 1 + cnt]) ++cnt; if (cnt > len) bitset_set (sbcset, ch); } } /* Check whether the array has enough space. */ if (BE (*equiv_class_alloc == mbcset->nequiv_classes, 0)) { /* Not enough, realloc it. */ /* +1 in case of mbcset->nequiv_classes is 0. */ int new_equiv_class_alloc = 2 * mbcset->nequiv_classes + 1; /* Use realloc since the array is NULL if *alloc == 0. */ int32_t *new_equiv_classes = re_realloc (mbcset->equiv_classes, int32_t, new_equiv_class_alloc); if (BE (new_equiv_classes == NULL, 0)) return REG_ESPACE; mbcset->equiv_classes = new_equiv_classes; *equiv_class_alloc = new_equiv_class_alloc; } mbcset->equiv_classes[mbcset->nequiv_classes++] = idx1; } else #endif /* _LIBC */ { if (BE (strlen ((const char *) name) != 1, 0)) return REG_ECOLLATE; bitset_set (sbcset, *name); } return REG_NOERROR; } /* Helper function for parse_bracket_exp. Build the character class which is represented by NAME. The result are written to MBCSET and SBCSET. CHAR_CLASS_ALLOC is the allocated size of mbcset->char_classes, is a pointer argument sinse we may update it. */ static reg_errcode_t #ifdef RE_ENABLE_I18N build_charclass (RE_TRANSLATE_TYPE trans, bitset_t sbcset, re_charset_t *mbcset, int *char_class_alloc, const char *class_name, reg_syntax_t syntax) #else /* not RE_ENABLE_I18N */ build_charclass (RE_TRANSLATE_TYPE trans, bitset_t sbcset, const char *class_name, reg_syntax_t syntax) #endif /* not RE_ENABLE_I18N */ { int i; /* In case of REG_ICASE "upper" and "lower" match the both of upper and lower cases. */ if ((syntax & RE_ICASE) && (strcmp (class_name, "upper") == 0 || strcmp (class_name, "lower") == 0)) class_name = "alpha"; #ifdef RE_ENABLE_I18N /* Check the space of the arrays. */ if (BE (*char_class_alloc == mbcset->nchar_classes, 0)) { /* Not enough, realloc it. */ /* +1 in case of mbcset->nchar_classes is 0. */ int new_char_class_alloc = 2 * mbcset->nchar_classes + 1; /* Use realloc since array is NULL if *alloc == 0. */ wctype_t *new_char_classes = re_realloc (mbcset->char_classes, wctype_t, new_char_class_alloc); if (BE (new_char_classes == NULL, 0)) return REG_ESPACE; mbcset->char_classes = new_char_classes; *char_class_alloc = new_char_class_alloc; } mbcset->char_classes[mbcset->nchar_classes++] = __wctype (class_name); #endif /* RE_ENABLE_I18N */ #define BUILD_CHARCLASS_LOOP(ctype_func) \ do { \ if (BE (trans != NULL, 0)) \ { \ for (i = 0; i < SBC_MAX; ++i) \ if (ctype_func (i)) \ bitset_set (sbcset, trans[i]); \ } \ else \ { \ for (i = 0; i < SBC_MAX; ++i) \ if (ctype_func (i)) \ bitset_set (sbcset, i); \ } \ } while (0) if (strcmp (class_name, "alnum") == 0) BUILD_CHARCLASS_LOOP (isalnum); else if (strcmp (class_name, "cntrl") == 0) BUILD_CHARCLASS_LOOP (iscntrl); else if (strcmp (class_name, "lower") == 0) BUILD_CHARCLASS_LOOP (islower); else if (strcmp (class_name, "space") == 0) BUILD_CHARCLASS_LOOP (isspace); else if (strcmp (class_name, "alpha") == 0) BUILD_CHARCLASS_LOOP (isalpha); else if (strcmp (class_name, "digit") == 0) BUILD_CHARCLASS_LOOP (isdigit); else if (strcmp (class_name, "print") == 0) BUILD_CHARCLASS_LOOP (isprint); else if (strcmp (class_name, "upper") == 0) BUILD_CHARCLASS_LOOP (isupper); else if (strcmp (class_name, "blank") == 0) #ifndef GAWK BUILD_CHARCLASS_LOOP (isblank); #else /* see comments above */ BUILD_CHARCLASS_LOOP (is_blank); #endif else if (strcmp (class_name, "graph") == 0) BUILD_CHARCLASS_LOOP (isgraph); else if (strcmp (class_name, "punct") == 0) BUILD_CHARCLASS_LOOP (ispunct); else if (strcmp (class_name, "xdigit") == 0) BUILD_CHARCLASS_LOOP (isxdigit); else return REG_ECTYPE; return REG_NOERROR; } static bin_tree_t * build_charclass_op (re_dfa_t *dfa, RE_TRANSLATE_TYPE trans, const char *class_name, const char *extra, int non_match, reg_errcode_t *err) { re_bitset_ptr_t sbcset; #ifdef RE_ENABLE_I18N re_charset_t *mbcset; int alloc = 0; #endif /* not RE_ENABLE_I18N */ reg_errcode_t ret; re_token_t br_token; bin_tree_t *tree; sbcset = (re_bitset_ptr_t) calloc (sizeof (bitset_t), 1); #ifdef RE_ENABLE_I18N mbcset = (re_charset_t *) calloc (sizeof (re_charset_t), 1); #endif /* RE_ENABLE_I18N */ #ifdef RE_ENABLE_I18N if (BE (sbcset == NULL || mbcset == NULL, 0)) #else /* not RE_ENABLE_I18N */ if (BE (sbcset == NULL, 0)) #endif /* not RE_ENABLE_I18N */ { *err = REG_ESPACE; return NULL; } if (non_match) { #ifdef RE_ENABLE_I18N mbcset->non_match = 1; #endif /* not RE_ENABLE_I18N */ } /* We don't care the syntax in this case. */ ret = build_charclass (trans, sbcset, #ifdef RE_ENABLE_I18N mbcset, &alloc, #endif /* RE_ENABLE_I18N */ class_name, 0); if (BE (ret != REG_NOERROR, 0)) { re_free (sbcset); #ifdef RE_ENABLE_I18N free_charset (mbcset); #endif /* RE_ENABLE_I18N */ *err = ret; return NULL; } /* \w match '_' also. */ for (; *extra; extra++) bitset_set (sbcset, *extra); /* If it is non-matching list. */ if (non_match) bitset_not (sbcset); #ifdef RE_ENABLE_I18N /* Ensure only single byte characters are set. */ if (dfa->mb_cur_max > 1) bitset_mask (sbcset, dfa->sb_char); #endif /* Build a tree for simple bracket. */ br_token.type = SIMPLE_BRACKET; br_token.opr.sbcset = sbcset; tree = create_token_tree (dfa, NULL, NULL, &br_token); if (BE (tree == NULL, 0)) goto build_word_op_espace; #ifdef RE_ENABLE_I18N if (dfa->mb_cur_max > 1) { bin_tree_t *mbc_tree; /* Build a tree for complex bracket. */ br_token.type = COMPLEX_BRACKET; br_token.opr.mbcset = mbcset; dfa->has_mb_node = 1; mbc_tree = create_token_tree (dfa, NULL, NULL, &br_token); if (BE (mbc_tree == NULL, 0)) goto build_word_op_espace; /* Then join them by ALT node. */ tree = create_tree (dfa, tree, mbc_tree, OP_ALT); if (BE (mbc_tree != NULL, 1)) return tree; } else { free_charset (mbcset); return tree; } #else /* not RE_ENABLE_I18N */ return tree; #endif /* not RE_ENABLE_I18N */ build_word_op_espace: re_free (sbcset); #ifdef RE_ENABLE_I18N free_charset (mbcset); #endif /* RE_ENABLE_I18N */ *err = REG_ESPACE; return NULL; } /* This is intended for the expressions like "a{1,3}". Fetch a number from `input', and return the number. Return -1, if the number field is empty like "{,1}". Return -2, If an error is occured. */ static int fetch_number (re_string_t *input, re_token_t *token, reg_syntax_t syntax) { int num = -1; unsigned char c; while (1) { fetch_token (token, input, syntax); c = token->opr.c; if (BE (token->type == END_OF_RE, 0)) return -2; if (token->type == OP_CLOSE_DUP_NUM || c == ',') break; num = ((token->type != CHARACTER || c < '0' || '9' < c || num == -2) ? -2 : ((num == -1) ? c - '0' : num * 10 + c - '0')); num = (num > RE_DUP_MAX) ? -2 : num; } return num; } #ifdef RE_ENABLE_I18N static void free_charset (re_charset_t *cset) { re_free (cset->mbchars); # ifdef _LIBC re_free (cset->coll_syms); re_free (cset->equiv_classes); re_free (cset->range_starts); re_free (cset->range_ends); # endif re_free (cset->char_classes); re_free (cset); } #endif /* RE_ENABLE_I18N */ /* Functions for binary tree operation. */ /* Create a tree node. */ static bin_tree_t * create_tree (re_dfa_t *dfa, bin_tree_t *left, bin_tree_t *right, re_token_type_t type) { re_token_t t; t.type = type; return create_token_tree (dfa, left, right, &t); } static bin_tree_t * create_token_tree (re_dfa_t *dfa, bin_tree_t *left, bin_tree_t *right, const re_token_t *token) { bin_tree_t *tree; if (BE (dfa->str_tree_storage_idx == BIN_TREE_STORAGE_SIZE, 0)) { bin_tree_storage_t *storage = re_malloc (bin_tree_storage_t, 1); if (storage == NULL) return NULL; storage->next = dfa->str_tree_storage; dfa->str_tree_storage = storage; dfa->str_tree_storage_idx = 0; } tree = &dfa->str_tree_storage->data[dfa->str_tree_storage_idx++]; tree->parent = NULL; tree->left = left; tree->right = right; tree->token = *token; tree->token.duplicated = 0; tree->token.opt_subexp = 0; tree->first = NULL; tree->next = NULL; tree->node_idx = -1; if (left != NULL) left->parent = tree; if (right != NULL) right->parent = tree; return tree; } /* Mark the tree SRC as an optional subexpression. To be called from preorder or postorder. */ static reg_errcode_t mark_opt_subexp (void *extra, bin_tree_t *node) { int idx = (int) (long) extra; if (node->token.type == SUBEXP && node->token.opr.idx == idx) node->token.opt_subexp = 1; return REG_NOERROR; } /* Free the allocated memory inside NODE. */ static void free_token (re_token_t *node) { #ifdef RE_ENABLE_I18N if (node->type == COMPLEX_BRACKET && node->duplicated == 0) free_charset (node->opr.mbcset); else #endif /* RE_ENABLE_I18N */ if (node->type == SIMPLE_BRACKET && node->duplicated == 0) re_free (node->opr.sbcset); } /* Worker function for tree walking. Free the allocated memory inside NODE and its children. */ static reg_errcode_t free_tree (UNUSED void *extra, bin_tree_t *node) { free_token (&node->token); return REG_NOERROR; } /* Duplicate the node SRC, and return new node. This is a preorder visit similar to the one implemented by the generic visitor, but we need more infrastructure to maintain two parallel trees --- so, it's easier to duplicate. */ static bin_tree_t * duplicate_tree (const bin_tree_t *root, re_dfa_t *dfa) { const bin_tree_t *node; bin_tree_t *dup_root; bin_tree_t **p_new = &dup_root, *dup_node = root->parent; for (node = root; ; ) { /* Create a new tree and link it back to the current parent. */ *p_new = create_token_tree (dfa, NULL, NULL, &node->token); if (*p_new == NULL) return NULL; (*p_new)->parent = dup_node; (*p_new)->token.duplicated = 1; dup_node = *p_new; /* Go to the left node, or up and to the right. */ if (node->left) { node = node->left; p_new = &dup_node->left; } else { const bin_tree_t *prev = NULL; while (node->right == prev || node->right == NULL) { prev = node; node = node->parent; dup_node = dup_node->parent; if (!node) return dup_root; } node = node->right; p_new = &dup_node->right; } } } libgit2-0.19.0/deps/regex/regex.c000066400000000000000000000061241216214232500164610ustar00rootroot00000000000000/* Extended regular expression matching and search library. Copyright (C) 2002, 2003, 2005 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Isamu Hasegawa . The GNU C Library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. The GNU C Library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with the GNU C Library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "config.h" /* Make sure noone compiles this code with a C++ compiler. */ #ifdef __cplusplus # error "This is C code, use a C compiler" #endif #ifdef _LIBC /* We have to keep the namespace clean. */ # define regfree(preg) __regfree (preg) # define regexec(pr, st, nm, pm, ef) __regexec (pr, st, nm, pm, ef) # define regcomp(preg, pattern, cflags) __regcomp (preg, pattern, cflags) # define regerror(errcode, preg, errbuf, errbuf_size) \ __regerror(errcode, preg, errbuf, errbuf_size) # define re_set_registers(bu, re, nu, st, en) \ __re_set_registers (bu, re, nu, st, en) # define re_match_2(bufp, string1, size1, string2, size2, pos, regs, stop) \ __re_match_2 (bufp, string1, size1, string2, size2, pos, regs, stop) # define re_match(bufp, string, size, pos, regs) \ __re_match (bufp, string, size, pos, regs) # define re_search(bufp, string, size, startpos, range, regs) \ __re_search (bufp, string, size, startpos, range, regs) # define re_compile_pattern(pattern, length, bufp) \ __re_compile_pattern (pattern, length, bufp) # define re_set_syntax(syntax) __re_set_syntax (syntax) # define re_search_2(bufp, st1, s1, st2, s2, startpos, range, regs, stop) \ __re_search_2 (bufp, st1, s1, st2, s2, startpos, range, regs, stop) # define re_compile_fastmap(bufp) __re_compile_fastmap (bufp) # include "../locale/localeinfo.h" #endif #if defined (_MSC_VER) #include /* for size_t */ #endif /* On some systems, limits.h sets RE_DUP_MAX to a lower value than GNU regex allows. Include it before , which correctly #undefs RE_DUP_MAX and sets it to the right value. */ #include #ifdef GAWK #undef alloca #define alloca alloca_is_bad_you_should_never_use_it #endif #include #include "regex_internal.h" #include "regex_internal.c" #ifdef GAWK #define bool int #define true (1) #define false (0) #endif #include "regcomp.c" #include "regexec.c" /* Binary backward compatibility. */ #if _LIBC # include # if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_3) link_warning (re_max_failures, "the 're_max_failures' variable is obsolete and will go away.") int re_max_failures = 2000; # endif #endif libgit2-0.19.0/deps/regex/regex.h000066400000000000000000000522671216214232500164770ustar00rootroot00000000000000#include #include /* Definitions for data structures and routines for the regular expression library. Copyright (C) 1985,1989-93,1995-98,2000,2001,2002,2003,2005,2006,2008 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. The GNU C Library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with the GNU C Library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #ifndef _REGEX_H #define _REGEX_H 1 #ifdef HAVE_STDDEF_H #include #endif #ifdef HAVE_SYS_TYPES_H #include #endif #ifndef _LIBC #define __USE_GNU 1 #endif /* Allow the use in C++ code. */ #ifdef __cplusplus extern "C" { #endif /* The following two types have to be signed and unsigned integer type wide enough to hold a value of a pointer. For most ANSI compilers ptrdiff_t and size_t should be likely OK. Still size of these two types is 2 for Microsoft C. Ugh... */ typedef long int s_reg_t; typedef unsigned long int active_reg_t; /* The following bits are used to determine the regexp syntax we recognize. The set/not-set meanings are chosen so that Emacs syntax remains the value 0. The bits are given in alphabetical order, and the definitions shifted by one from the previous bit; thus, when we add or remove a bit, only one other definition need change. */ typedef unsigned long int reg_syntax_t; #ifdef __USE_GNU /* If this bit is not set, then \ inside a bracket expression is literal. If set, then such a \ quotes the following character. */ # define RE_BACKSLASH_ESCAPE_IN_LISTS ((unsigned long int) 1) /* If this bit is not set, then + and ? are operators, and \+ and \? are literals. If set, then \+ and \? are operators and + and ? are literals. */ # define RE_BK_PLUS_QM (RE_BACKSLASH_ESCAPE_IN_LISTS << 1) /* If this bit is set, then character classes are supported. They are: [:alpha:], [:upper:], [:lower:], [:digit:], [:alnum:], [:xdigit:], [:space:], [:print:], [:punct:], [:graph:], and [:cntrl:]. If not set, then character classes are not supported. */ # define RE_CHAR_CLASSES (RE_BK_PLUS_QM << 1) /* If this bit is set, then ^ and $ are always anchors (outside bracket expressions, of course). If this bit is not set, then it depends: ^ is an anchor if it is at the beginning of a regular expression or after an open-group or an alternation operator; $ is an anchor if it is at the end of a regular expression, or before a close-group or an alternation operator. This bit could be (re)combined with RE_CONTEXT_INDEP_OPS, because POSIX draft 11.2 says that * etc. in leading positions is undefined. We already implemented a previous draft which made those constructs invalid, though, so we haven't changed the code back. */ # define RE_CONTEXT_INDEP_ANCHORS (RE_CHAR_CLASSES << 1) /* If this bit is set, then special characters are always special regardless of where they are in the pattern. If this bit is not set, then special characters are special only in some contexts; otherwise they are ordinary. Specifically, * + ? and intervals are only special when not after the beginning, open-group, or alternation operator. */ # define RE_CONTEXT_INDEP_OPS (RE_CONTEXT_INDEP_ANCHORS << 1) /* If this bit is set, then *, +, ?, and { cannot be first in an re or immediately after an alternation or begin-group operator. */ # define RE_CONTEXT_INVALID_OPS (RE_CONTEXT_INDEP_OPS << 1) /* If this bit is set, then . matches newline. If not set, then it doesn't. */ # define RE_DOT_NEWLINE (RE_CONTEXT_INVALID_OPS << 1) /* If this bit is set, then . doesn't match NUL. If not set, then it does. */ # define RE_DOT_NOT_NULL (RE_DOT_NEWLINE << 1) /* If this bit is set, nonmatching lists [^...] do not match newline. If not set, they do. */ # define RE_HAT_LISTS_NOT_NEWLINE (RE_DOT_NOT_NULL << 1) /* If this bit is set, either \{...\} or {...} defines an interval, depending on RE_NO_BK_BRACES. If not set, \{, \}, {, and } are literals. */ # define RE_INTERVALS (RE_HAT_LISTS_NOT_NEWLINE << 1) /* If this bit is set, +, ? and | aren't recognized as operators. If not set, they are. */ # define RE_LIMITED_OPS (RE_INTERVALS << 1) /* If this bit is set, newline is an alternation operator. If not set, newline is literal. */ # define RE_NEWLINE_ALT (RE_LIMITED_OPS << 1) /* If this bit is set, then `{...}' defines an interval, and \{ and \} are literals. If not set, then `\{...\}' defines an interval. */ # define RE_NO_BK_BRACES (RE_NEWLINE_ALT << 1) /* If this bit is set, (...) defines a group, and \( and \) are literals. If not set, \(...\) defines a group, and ( and ) are literals. */ # define RE_NO_BK_PARENS (RE_NO_BK_BRACES << 1) /* If this bit is set, then \ matches . If not set, then \ is a back-reference. */ # define RE_NO_BK_REFS (RE_NO_BK_PARENS << 1) /* If this bit is set, then | is an alternation operator, and \| is literal. If not set, then \| is an alternation operator, and | is literal. */ # define RE_NO_BK_VBAR (RE_NO_BK_REFS << 1) /* If this bit is set, then an ending range point collating higher than the starting range point, as in [z-a], is invalid. If not set, then when ending range point collates higher than the starting range point, the range is ignored. */ # define RE_NO_EMPTY_RANGES (RE_NO_BK_VBAR << 1) /* If this bit is set, then an unmatched ) is ordinary. If not set, then an unmatched ) is invalid. */ # define RE_UNMATCHED_RIGHT_PAREN_ORD (RE_NO_EMPTY_RANGES << 1) /* If this bit is set, succeed as soon as we match the whole pattern, without further backtracking. */ # define RE_NO_POSIX_BACKTRACKING (RE_UNMATCHED_RIGHT_PAREN_ORD << 1) /* If this bit is set, do not process the GNU regex operators. If not set, then the GNU regex operators are recognized. */ # define RE_NO_GNU_OPS (RE_NO_POSIX_BACKTRACKING << 1) /* If this bit is set, a syntactically invalid interval is treated as a string of ordinary characters. For example, the ERE 'a{1' is treated as 'a\{1'. */ # define RE_INVALID_INTERVAL_ORD (RE_NO_GNU_OPS << 1) /* If this bit is set, then ignore case when matching. If not set, then case is significant. */ # define RE_ICASE (RE_INVALID_INTERVAL_ORD << 1) /* This bit is used internally like RE_CONTEXT_INDEP_ANCHORS but only for ^, because it is difficult to scan the regex backwards to find whether ^ should be special. */ # define RE_CARET_ANCHORS_HERE (RE_ICASE << 1) /* If this bit is set, then \{ cannot be first in an bre or immediately after an alternation or begin-group operator. */ # define RE_CONTEXT_INVALID_DUP (RE_CARET_ANCHORS_HERE << 1) /* If this bit is set, then no_sub will be set to 1 during re_compile_pattern. */ #define RE_NO_SUB (RE_CONTEXT_INVALID_DUP << 1) #endif /* This global variable defines the particular regexp syntax to use (for some interfaces). When a regexp is compiled, the syntax used is stored in the pattern buffer, so changing this does not affect already-compiled regexps. */ extern reg_syntax_t re_syntax_options; #ifdef __USE_GNU /* Define combinations of the above bits for the standard possibilities. (The [[[ comments delimit what gets put into the Texinfo file, so don't delete them!) */ /* [[[begin syntaxes]]] */ #define RE_SYNTAX_EMACS 0 #define RE_SYNTAX_AWK \ (RE_BACKSLASH_ESCAPE_IN_LISTS | RE_DOT_NOT_NULL \ | RE_NO_BK_PARENS | RE_NO_BK_REFS \ | RE_NO_BK_VBAR | RE_NO_EMPTY_RANGES \ | RE_DOT_NEWLINE | RE_CONTEXT_INDEP_ANCHORS \ | RE_UNMATCHED_RIGHT_PAREN_ORD | RE_NO_GNU_OPS) #define RE_SYNTAX_GNU_AWK \ ((RE_SYNTAX_POSIX_EXTENDED | RE_BACKSLASH_ESCAPE_IN_LISTS \ | RE_INVALID_INTERVAL_ORD) \ & ~(RE_DOT_NOT_NULL | RE_CONTEXT_INDEP_OPS \ | RE_CONTEXT_INVALID_OPS )) #define RE_SYNTAX_POSIX_AWK \ (RE_SYNTAX_POSIX_EXTENDED | RE_BACKSLASH_ESCAPE_IN_LISTS \ | RE_INTERVALS | RE_NO_GNU_OPS \ | RE_INVALID_INTERVAL_ORD) #define RE_SYNTAX_GREP \ (RE_BK_PLUS_QM | RE_CHAR_CLASSES \ | RE_HAT_LISTS_NOT_NEWLINE | RE_INTERVALS \ | RE_NEWLINE_ALT) #define RE_SYNTAX_EGREP \ (RE_CHAR_CLASSES | RE_CONTEXT_INDEP_ANCHORS \ | RE_CONTEXT_INDEP_OPS | RE_HAT_LISTS_NOT_NEWLINE \ | RE_NEWLINE_ALT | RE_NO_BK_PARENS \ | RE_NO_BK_VBAR) #define RE_SYNTAX_POSIX_EGREP \ (RE_SYNTAX_EGREP | RE_INTERVALS | RE_NO_BK_BRACES \ | RE_INVALID_INTERVAL_ORD) /* P1003.2/D11.2, section 4.20.7.1, lines 5078ff. */ #define RE_SYNTAX_ED RE_SYNTAX_POSIX_BASIC #define RE_SYNTAX_SED RE_SYNTAX_POSIX_BASIC /* Syntax bits common to both basic and extended POSIX regex syntax. */ #define _RE_SYNTAX_POSIX_COMMON \ (RE_CHAR_CLASSES | RE_DOT_NEWLINE | RE_DOT_NOT_NULL \ | RE_INTERVALS | RE_NO_EMPTY_RANGES) #define RE_SYNTAX_POSIX_BASIC \ (_RE_SYNTAX_POSIX_COMMON | RE_BK_PLUS_QM | RE_CONTEXT_INVALID_DUP) /* Differs from ..._POSIX_BASIC only in that RE_BK_PLUS_QM becomes RE_LIMITED_OPS, i.e., \? \+ \| are not recognized. Actually, this isn't minimal, since other operators, such as \`, aren't disabled. */ #define RE_SYNTAX_POSIX_MINIMAL_BASIC \ (_RE_SYNTAX_POSIX_COMMON | RE_LIMITED_OPS) #define RE_SYNTAX_POSIX_EXTENDED \ (_RE_SYNTAX_POSIX_COMMON | RE_CONTEXT_INDEP_ANCHORS \ | RE_CONTEXT_INDEP_OPS | RE_NO_BK_BRACES \ | RE_NO_BK_PARENS | RE_NO_BK_VBAR \ | RE_CONTEXT_INVALID_OPS | RE_UNMATCHED_RIGHT_PAREN_ORD) /* Differs from ..._POSIX_EXTENDED in that RE_CONTEXT_INDEP_OPS is removed and RE_NO_BK_REFS is added. */ #define RE_SYNTAX_POSIX_MINIMAL_EXTENDED \ (_RE_SYNTAX_POSIX_COMMON | RE_CONTEXT_INDEP_ANCHORS \ | RE_CONTEXT_INVALID_OPS | RE_NO_BK_BRACES \ | RE_NO_BK_PARENS | RE_NO_BK_REFS \ | RE_NO_BK_VBAR | RE_UNMATCHED_RIGHT_PAREN_ORD) /* [[[end syntaxes]]] */ /* Maximum number of duplicates an interval can allow. Some systems (erroneously) define this in other header files, but we want our value, so remove any previous define. */ # ifdef RE_DUP_MAX # undef RE_DUP_MAX # endif /* If sizeof(int) == 2, then ((1 << 15) - 1) overflows. */ # define RE_DUP_MAX (0x7fff) #endif /* POSIX `cflags' bits (i.e., information for `regcomp'). */ /* If this bit is set, then use extended regular expression syntax. If not set, then use basic regular expression syntax. */ #define REG_EXTENDED 1 /* If this bit is set, then ignore case when matching. If not set, then case is significant. */ #define REG_ICASE (REG_EXTENDED << 1) /* If this bit is set, then anchors do not match at newline characters in the string. If not set, then anchors do match at newlines. */ #define REG_NEWLINE (REG_ICASE << 1) /* If this bit is set, then report only success or fail in regexec. If not set, then returns differ between not matching and errors. */ #define REG_NOSUB (REG_NEWLINE << 1) /* POSIX `eflags' bits (i.e., information for regexec). */ /* If this bit is set, then the beginning-of-line operator doesn't match the beginning of the string (presumably because it's not the beginning of a line). If not set, then the beginning-of-line operator does match the beginning of the string. */ #define REG_NOTBOL 1 /* Like REG_NOTBOL, except for the end-of-line. */ #define REG_NOTEOL (1 << 1) /* Use PMATCH[0] to delimit the start and end of the search in the buffer. */ #define REG_STARTEND (1 << 2) /* If any error codes are removed, changed, or added, update the `re_error_msg' table in regex.c. */ typedef enum { #if defined _XOPEN_SOURCE || defined __USE_XOPEN2K REG_ENOSYS = -1, /* This will never happen for this implementation. */ #endif REG_NOERROR = 0, /* Success. */ REG_NOMATCH, /* Didn't find a match (for regexec). */ /* POSIX regcomp return error codes. (In the order listed in the standard.) */ REG_BADPAT, /* Invalid pattern. */ REG_ECOLLATE, /* Inalid collating element. */ REG_ECTYPE, /* Invalid character class name. */ REG_EESCAPE, /* Trailing backslash. */ REG_ESUBREG, /* Invalid back reference. */ REG_EBRACK, /* Unmatched left bracket. */ REG_EPAREN, /* Parenthesis imbalance. */ REG_EBRACE, /* Unmatched \{. */ REG_BADBR, /* Invalid contents of \{\}. */ REG_ERANGE, /* Invalid range end. */ REG_ESPACE, /* Ran out of memory. */ REG_BADRPT, /* No preceding re for repetition op. */ /* Error codes we've added. */ REG_EEND, /* Premature end. */ REG_ESIZE, /* Compiled pattern bigger than 2^16 bytes. */ REG_ERPAREN /* Unmatched ) or \); not returned from regcomp. */ } reg_errcode_t; /* This data structure represents a compiled pattern. Before calling the pattern compiler, the fields `buffer', `allocated', `fastmap', `translate', and `no_sub' can be set. After the pattern has been compiled, the `re_nsub' field is available. All other fields are private to the regex routines. */ #ifndef RE_TRANSLATE_TYPE # define __RE_TRANSLATE_TYPE unsigned char * # ifdef __USE_GNU # define RE_TRANSLATE_TYPE __RE_TRANSLATE_TYPE # endif #endif #ifdef __USE_GNU # define __REPB_PREFIX(name) name #else # define __REPB_PREFIX(name) __##name #endif struct re_pattern_buffer { /* Space that holds the compiled pattern. It is declared as `unsigned char *' because its elements are sometimes used as array indexes. */ unsigned char *__REPB_PREFIX(buffer); /* Number of bytes to which `buffer' points. */ unsigned long int __REPB_PREFIX(allocated); /* Number of bytes actually used in `buffer'. */ unsigned long int __REPB_PREFIX(used); /* Syntax setting with which the pattern was compiled. */ reg_syntax_t __REPB_PREFIX(syntax); /* Pointer to a fastmap, if any, otherwise zero. re_search uses the fastmap, if there is one, to skip over impossible starting points for matches. */ char *__REPB_PREFIX(fastmap); /* Either a translate table to apply to all characters before comparing them, or zero for no translation. The translation is applied to a pattern when it is compiled and to a string when it is matched. */ __RE_TRANSLATE_TYPE __REPB_PREFIX(translate); /* Number of subexpressions found by the compiler. */ size_t re_nsub; /* Zero if this pattern cannot match the empty string, one else. Well, in truth it's used only in `re_search_2', to see whether or not we should use the fastmap, so we don't set this absolutely perfectly; see `re_compile_fastmap' (the `duplicate' case). */ unsigned __REPB_PREFIX(can_be_null) : 1; /* If REGS_UNALLOCATED, allocate space in the `regs' structure for `max (RE_NREGS, re_nsub + 1)' groups. If REGS_REALLOCATE, reallocate space if necessary. If REGS_FIXED, use what's there. */ #ifdef __USE_GNU # define REGS_UNALLOCATED 0 # define REGS_REALLOCATE 1 # define REGS_FIXED 2 #endif unsigned __REPB_PREFIX(regs_allocated) : 2; /* Set to zero when `regex_compile' compiles a pattern; set to one by `re_compile_fastmap' if it updates the fastmap. */ unsigned __REPB_PREFIX(fastmap_accurate) : 1; /* If set, `re_match_2' does not return information about subexpressions. */ unsigned __REPB_PREFIX(no_sub) : 1; /* If set, a beginning-of-line anchor doesn't match at the beginning of the string. */ unsigned __REPB_PREFIX(not_bol) : 1; /* Similarly for an end-of-line anchor. */ unsigned __REPB_PREFIX(not_eol) : 1; /* If true, an anchor at a newline matches. */ unsigned __REPB_PREFIX(newline_anchor) : 1; }; typedef struct re_pattern_buffer regex_t; /* Type for byte offsets within the string. POSIX mandates this. */ typedef int regoff_t; #ifdef __USE_GNU /* This is the structure we store register match data in. See regex.texinfo for a full description of what registers match. */ struct re_registers { unsigned num_regs; regoff_t *start; regoff_t *end; }; /* If `regs_allocated' is REGS_UNALLOCATED in the pattern buffer, `re_match_2' returns information about at least this many registers the first time a `regs' structure is passed. */ # ifndef RE_NREGS # define RE_NREGS 30 # endif #endif /* POSIX specification for registers. Aside from the different names than `re_registers', POSIX uses an array of structures, instead of a structure of arrays. */ typedef struct { regoff_t rm_so; /* Byte offset from string's start to substring's start. */ regoff_t rm_eo; /* Byte offset from string's start to substring's end. */ } regmatch_t; /* Declarations for routines. */ #ifdef __USE_GNU /* Sets the current default syntax to SYNTAX, and return the old syntax. You can also simply assign to the `re_syntax_options' variable. */ extern reg_syntax_t re_set_syntax (reg_syntax_t __syntax); /* Compile the regular expression PATTERN, with length LENGTH and syntax given by the global `re_syntax_options', into the buffer BUFFER. Return NULL if successful, and an error string if not. */ extern const char *re_compile_pattern (const char *__pattern, size_t __length, struct re_pattern_buffer *__buffer); /* Compile a fastmap for the compiled pattern in BUFFER; used to accelerate searches. Return 0 if successful and -2 if was an internal error. */ extern int re_compile_fastmap (struct re_pattern_buffer *__buffer); /* Search in the string STRING (with length LENGTH) for the pattern compiled into BUFFER. Start searching at position START, for RANGE characters. Return the starting position of the match, -1 for no match, or -2 for an internal error. Also return register information in REGS (if REGS and BUFFER->no_sub are nonzero). */ extern int re_search (struct re_pattern_buffer *__buffer, const char *__cstring, int __length, int __start, int __range, struct re_registers *__regs); /* Like `re_search', but search in the concatenation of STRING1 and STRING2. Also, stop searching at index START + STOP. */ extern int re_search_2 (struct re_pattern_buffer *__buffer, const char *__string1, int __length1, const char *__string2, int __length2, int __start, int __range, struct re_registers *__regs, int __stop); /* Like `re_search', but return how many characters in STRING the regexp in BUFFER matched, starting at position START. */ extern int re_match (struct re_pattern_buffer *__buffer, const char *__cstring, int __length, int __start, struct re_registers *__regs); /* Relates to `re_match' as `re_search_2' relates to `re_search'. */ extern int re_match_2 (struct re_pattern_buffer *__buffer, const char *__string1, int __length1, const char *__string2, int __length2, int __start, struct re_registers *__regs, int __stop); /* Set REGS to hold NUM_REGS registers, storing them in STARTS and ENDS. Subsequent matches using BUFFER and REGS will use this memory for recording register information. STARTS and ENDS must be allocated with malloc, and must each be at least `NUM_REGS * sizeof (regoff_t)' bytes long. If NUM_REGS == 0, then subsequent matches should allocate their own register data. Unless this function is called, the first search or match using PATTERN_BUFFER will allocate its own register data, without freeing the old data. */ extern void re_set_registers (struct re_pattern_buffer *__buffer, struct re_registers *__regs, unsigned int __num_regs, regoff_t *__starts, regoff_t *__ends); #endif /* Use GNU */ #if defined _REGEX_RE_COMP || (defined _LIBC && defined __USE_BSD) # ifndef _CRAY /* 4.2 bsd compatibility. */ extern char *re_comp (const char *); extern int re_exec (const char *); # endif #endif /* GCC 2.95 and later have "__restrict"; C99 compilers have "restrict", and "configure" may have defined "restrict". */ #ifndef __restrict # if ! (2 < __GNUC__ || (2 == __GNUC__ && 95 <= __GNUC_MINOR__)) # if defined restrict || 199901L <= __STDC_VERSION__ # define __restrict restrict # else # define __restrict # endif # endif #endif /* gcc 3.1 and up support the [restrict] syntax. */ #ifndef __restrict_arr # if (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1)) \ && !defined __GNUG__ # define __restrict_arr __restrict # else # define __restrict_arr # endif #endif /* POSIX compatibility. */ extern int regcomp (regex_t *__restrict __preg, const char *__restrict __pattern, int __cflags); extern int regexec (const regex_t *__restrict __preg, const char *__restrict __cstring, size_t __nmatch, regmatch_t __pmatch[__restrict_arr], int __eflags); extern size_t regerror (int __errcode, const regex_t *__restrict __preg, char *__restrict __errbuf, size_t __errbuf_size); extern void regfree (regex_t *__preg); #ifdef __cplusplus } #endif /* C++ */ #endif /* regex.h */ libgit2-0.19.0/deps/regex/regex_internal.c000066400000000000000000001350631216214232500203620ustar00rootroot00000000000000/* Extended regular expression matching and search library. Copyright (C) 2002-2006, 2010 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Isamu Hasegawa . The GNU C Library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. The GNU C Library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with the GNU C Library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ static void re_string_construct_common (const char *str, int len, re_string_t *pstr, RE_TRANSLATE_TYPE trans, int icase, const re_dfa_t *dfa) internal_function; static re_dfastate_t *create_ci_newstate (const re_dfa_t *dfa, const re_node_set *nodes, unsigned int hash) internal_function; static re_dfastate_t *create_cd_newstate (const re_dfa_t *dfa, const re_node_set *nodes, unsigned int context, unsigned int hash) internal_function; #ifdef GAWK #undef MAX /* safety */ static size_t MAX(size_t a, size_t b) { return (a > b ? a : b); } #endif /* Functions for string operation. */ /* This function allocate the buffers. It is necessary to call re_string_reconstruct before using the object. */ static reg_errcode_t internal_function re_string_allocate (re_string_t *pstr, const char *str, int len, int init_len, RE_TRANSLATE_TYPE trans, int icase, const re_dfa_t *dfa) { reg_errcode_t ret; int init_buf_len; /* Ensure at least one character fits into the buffers. */ if (init_len < dfa->mb_cur_max) init_len = dfa->mb_cur_max; init_buf_len = (len + 1 < init_len) ? len + 1: init_len; re_string_construct_common (str, len, pstr, trans, icase, dfa); ret = re_string_realloc_buffers (pstr, init_buf_len); if (BE (ret != REG_NOERROR, 0)) return ret; pstr->word_char = dfa->word_char; pstr->word_ops_used = dfa->word_ops_used; pstr->mbs = pstr->mbs_allocated ? pstr->mbs : (unsigned char *) str; pstr->valid_len = (pstr->mbs_allocated || dfa->mb_cur_max > 1) ? 0 : len; pstr->valid_raw_len = pstr->valid_len; return REG_NOERROR; } /* This function allocate the buffers, and initialize them. */ static reg_errcode_t internal_function re_string_construct (re_string_t *pstr, const char *str, int len, RE_TRANSLATE_TYPE trans, int icase, const re_dfa_t *dfa) { reg_errcode_t ret; memset (pstr, '\0', sizeof (re_string_t)); re_string_construct_common (str, len, pstr, trans, icase, dfa); if (len > 0) { ret = re_string_realloc_buffers (pstr, len + 1); if (BE (ret != REG_NOERROR, 0)) return ret; } pstr->mbs = pstr->mbs_allocated ? pstr->mbs : (unsigned char *) str; if (icase) { #ifdef RE_ENABLE_I18N if (dfa->mb_cur_max > 1) { while (1) { ret = build_wcs_upper_buffer (pstr); if (BE (ret != REG_NOERROR, 0)) return ret; if (pstr->valid_raw_len >= len) break; if (pstr->bufs_len > pstr->valid_len + dfa->mb_cur_max) break; ret = re_string_realloc_buffers (pstr, pstr->bufs_len * 2); if (BE (ret != REG_NOERROR, 0)) return ret; } } else #endif /* RE_ENABLE_I18N */ build_upper_buffer (pstr); } else { #ifdef RE_ENABLE_I18N if (dfa->mb_cur_max > 1) build_wcs_buffer (pstr); else #endif /* RE_ENABLE_I18N */ { if (trans != NULL) re_string_translate_buffer (pstr); else { pstr->valid_len = pstr->bufs_len; pstr->valid_raw_len = pstr->bufs_len; } } } return REG_NOERROR; } /* Helper functions for re_string_allocate, and re_string_construct. */ static reg_errcode_t internal_function re_string_realloc_buffers (re_string_t *pstr, int new_buf_len) { #ifdef RE_ENABLE_I18N if (pstr->mb_cur_max > 1) { wint_t *new_wcs; /* Avoid overflow in realloc. */ const size_t max_object_size = MAX (sizeof (wint_t), sizeof (int)); if (BE (SIZE_MAX / max_object_size < new_buf_len, 0)) return REG_ESPACE; new_wcs = re_realloc (pstr->wcs, wint_t, new_buf_len); if (BE (new_wcs == NULL, 0)) return REG_ESPACE; pstr->wcs = new_wcs; if (pstr->offsets != NULL) { int *new_offsets = re_realloc (pstr->offsets, int, new_buf_len); if (BE (new_offsets == NULL, 0)) return REG_ESPACE; pstr->offsets = new_offsets; } } #endif /* RE_ENABLE_I18N */ if (pstr->mbs_allocated) { unsigned char *new_mbs = re_realloc (pstr->mbs, unsigned char, new_buf_len); if (BE (new_mbs == NULL, 0)) return REG_ESPACE; pstr->mbs = new_mbs; } pstr->bufs_len = new_buf_len; return REG_NOERROR; } static void internal_function re_string_construct_common (const char *str, int len, re_string_t *pstr, RE_TRANSLATE_TYPE trans, int icase, const re_dfa_t *dfa) { pstr->raw_mbs = (const unsigned char *) str; pstr->len = len; pstr->raw_len = len; pstr->trans = trans; pstr->icase = icase ? 1 : 0; pstr->mbs_allocated = (trans != NULL || icase); pstr->mb_cur_max = dfa->mb_cur_max; pstr->is_utf8 = dfa->is_utf8; pstr->map_notascii = dfa->map_notascii; pstr->stop = pstr->len; pstr->raw_stop = pstr->stop; } #ifdef RE_ENABLE_I18N /* Build wide character buffer PSTR->WCS. If the byte sequence of the string are: (0), (1), (0), (1), Then wide character buffer will be: , WEOF , , WEOF , We use WEOF for padding, they indicate that the position isn't a first byte of a multibyte character. Note that this function assumes PSTR->VALID_LEN elements are already built and starts from PSTR->VALID_LEN. */ static void internal_function build_wcs_buffer (re_string_t *pstr) { #ifdef _LIBC unsigned char buf[MB_LEN_MAX]; assert (MB_LEN_MAX >= pstr->mb_cur_max); #else unsigned char buf[64]; #endif mbstate_t prev_st; int byte_idx, end_idx, remain_len; size_t mbclen; /* Build the buffers from pstr->valid_len to either pstr->len or pstr->bufs_len. */ end_idx = (pstr->bufs_len > pstr->len) ? pstr->len : pstr->bufs_len; for (byte_idx = pstr->valid_len; byte_idx < end_idx;) { wchar_t wc; const char *p; remain_len = end_idx - byte_idx; prev_st = pstr->cur_state; /* Apply the translation if we need. */ if (BE (pstr->trans != NULL, 0)) { int i, ch; for (i = 0; i < pstr->mb_cur_max && i < remain_len; ++i) { ch = pstr->raw_mbs [pstr->raw_mbs_idx + byte_idx + i]; buf[i] = pstr->mbs[byte_idx + i] = pstr->trans[ch]; } p = (const char *) buf; } else p = (const char *) pstr->raw_mbs + pstr->raw_mbs_idx + byte_idx; mbclen = __mbrtowc (&wc, p, remain_len, &pstr->cur_state); if (BE (mbclen == (size_t) -2, 0)) { /* The buffer doesn't have enough space, finish to build. */ pstr->cur_state = prev_st; break; } else if (BE (mbclen == (size_t) -1 || mbclen == 0, 0)) { /* We treat these cases as a singlebyte character. */ mbclen = 1; wc = (wchar_t) pstr->raw_mbs[pstr->raw_mbs_idx + byte_idx]; if (BE (pstr->trans != NULL, 0)) wc = pstr->trans[wc]; pstr->cur_state = prev_st; } /* Write wide character and padding. */ pstr->wcs[byte_idx++] = wc; /* Write paddings. */ for (remain_len = byte_idx + mbclen - 1; byte_idx < remain_len ;) pstr->wcs[byte_idx++] = WEOF; } pstr->valid_len = byte_idx; pstr->valid_raw_len = byte_idx; } /* Build wide character buffer PSTR->WCS like build_wcs_buffer, but for REG_ICASE. */ static reg_errcode_t internal_function build_wcs_upper_buffer (re_string_t *pstr) { mbstate_t prev_st; int src_idx, byte_idx, end_idx, remain_len; size_t mbclen; #ifdef _LIBC char buf[MB_LEN_MAX]; assert (MB_LEN_MAX >= pstr->mb_cur_max); #else char buf[64]; #endif byte_idx = pstr->valid_len; end_idx = (pstr->bufs_len > pstr->len) ? pstr->len : pstr->bufs_len; /* The following optimization assumes that ASCII characters can be mapped to wide characters with a simple cast. */ if (! pstr->map_notascii && pstr->trans == NULL && !pstr->offsets_needed) { while (byte_idx < end_idx) { wchar_t wc; if (isascii (pstr->raw_mbs[pstr->raw_mbs_idx + byte_idx]) && mbsinit (&pstr->cur_state)) { /* In case of a singlebyte character. */ pstr->mbs[byte_idx] = toupper (pstr->raw_mbs[pstr->raw_mbs_idx + byte_idx]); /* The next step uses the assumption that wchar_t is encoded ASCII-safe: all ASCII values can be converted like this. */ pstr->wcs[byte_idx] = (wchar_t) pstr->mbs[byte_idx]; ++byte_idx; continue; } remain_len = end_idx - byte_idx; prev_st = pstr->cur_state; mbclen = __mbrtowc (&wc, ((const char *) pstr->raw_mbs + pstr->raw_mbs_idx + byte_idx), remain_len, &pstr->cur_state); if (BE (mbclen + 2 > 2, 1)) { wchar_t wcu = wc; if (iswlower (wc)) { size_t mbcdlen; wcu = towupper (wc); mbcdlen = wcrtomb (buf, wcu, &prev_st); if (BE (mbclen == mbcdlen, 1)) memcpy (pstr->mbs + byte_idx, buf, mbclen); else { src_idx = byte_idx; goto offsets_needed; } } else memcpy (pstr->mbs + byte_idx, pstr->raw_mbs + pstr->raw_mbs_idx + byte_idx, mbclen); pstr->wcs[byte_idx++] = wcu; /* Write paddings. */ for (remain_len = byte_idx + mbclen - 1; byte_idx < remain_len ;) pstr->wcs[byte_idx++] = WEOF; } else if (mbclen == (size_t) -1 || mbclen == 0) { /* It is an invalid character or '\0'. Just use the byte. */ int ch = pstr->raw_mbs[pstr->raw_mbs_idx + byte_idx]; pstr->mbs[byte_idx] = ch; /* And also cast it to wide char. */ pstr->wcs[byte_idx++] = (wchar_t) ch; if (BE (mbclen == (size_t) -1, 0)) pstr->cur_state = prev_st; } else { /* The buffer doesn't have enough space, finish to build. */ pstr->cur_state = prev_st; break; } } pstr->valid_len = byte_idx; pstr->valid_raw_len = byte_idx; return REG_NOERROR; } else for (src_idx = pstr->valid_raw_len; byte_idx < end_idx;) { wchar_t wc; const char *p; offsets_needed: remain_len = end_idx - byte_idx; prev_st = pstr->cur_state; if (BE (pstr->trans != NULL, 0)) { int i, ch; for (i = 0; i < pstr->mb_cur_max && i < remain_len; ++i) { ch = pstr->raw_mbs [pstr->raw_mbs_idx + src_idx + i]; buf[i] = pstr->trans[ch]; } p = (const char *) buf; } else p = (const char *) pstr->raw_mbs + pstr->raw_mbs_idx + src_idx; mbclen = __mbrtowc (&wc, p, remain_len, &pstr->cur_state); if (BE (mbclen + 2 > 2, 1)) { wchar_t wcu = wc; if (iswlower (wc)) { size_t mbcdlen; wcu = towupper (wc); mbcdlen = wcrtomb ((char *) buf, wcu, &prev_st); if (BE (mbclen == mbcdlen, 1)) memcpy (pstr->mbs + byte_idx, buf, mbclen); else if (mbcdlen != (size_t) -1) { size_t i; if (byte_idx + mbcdlen > pstr->bufs_len) { pstr->cur_state = prev_st; break; } if (pstr->offsets == NULL) { pstr->offsets = re_malloc (int, pstr->bufs_len); if (pstr->offsets == NULL) return REG_ESPACE; } if (!pstr->offsets_needed) { for (i = 0; i < (size_t) byte_idx; ++i) pstr->offsets[i] = i; pstr->offsets_needed = 1; } memcpy (pstr->mbs + byte_idx, buf, mbcdlen); pstr->wcs[byte_idx] = wcu; pstr->offsets[byte_idx] = src_idx; for (i = 1; i < mbcdlen; ++i) { pstr->offsets[byte_idx + i] = src_idx + (i < mbclen ? i : mbclen - 1); pstr->wcs[byte_idx + i] = WEOF; } pstr->len += mbcdlen - mbclen; if (pstr->raw_stop > src_idx) pstr->stop += mbcdlen - mbclen; end_idx = (pstr->bufs_len > pstr->len) ? pstr->len : pstr->bufs_len; byte_idx += mbcdlen; src_idx += mbclen; continue; } else memcpy (pstr->mbs + byte_idx, p, mbclen); } else memcpy (pstr->mbs + byte_idx, p, mbclen); if (BE (pstr->offsets_needed != 0, 0)) { size_t i; for (i = 0; i < mbclen; ++i) pstr->offsets[byte_idx + i] = src_idx + i; } src_idx += mbclen; pstr->wcs[byte_idx++] = wcu; /* Write paddings. */ for (remain_len = byte_idx + mbclen - 1; byte_idx < remain_len ;) pstr->wcs[byte_idx++] = WEOF; } else if (mbclen == (size_t) -1 || mbclen == 0) { /* It is an invalid character or '\0'. Just use the byte. */ int ch = pstr->raw_mbs[pstr->raw_mbs_idx + src_idx]; if (BE (pstr->trans != NULL, 0)) ch = pstr->trans [ch]; pstr->mbs[byte_idx] = ch; if (BE (pstr->offsets_needed != 0, 0)) pstr->offsets[byte_idx] = src_idx; ++src_idx; /* And also cast it to wide char. */ pstr->wcs[byte_idx++] = (wchar_t) ch; if (BE (mbclen == (size_t) -1, 0)) pstr->cur_state = prev_st; } else { /* The buffer doesn't have enough space, finish to build. */ pstr->cur_state = prev_st; break; } } pstr->valid_len = byte_idx; pstr->valid_raw_len = src_idx; return REG_NOERROR; } /* Skip characters until the index becomes greater than NEW_RAW_IDX. Return the index. */ static int internal_function re_string_skip_chars (re_string_t *pstr, int new_raw_idx, wint_t *last_wc) { mbstate_t prev_st; int rawbuf_idx; size_t mbclen; wint_t wc = WEOF; /* Skip the characters which are not necessary to check. */ for (rawbuf_idx = pstr->raw_mbs_idx + pstr->valid_raw_len; rawbuf_idx < new_raw_idx;) { wchar_t wc2; int remain_len = pstr->len - rawbuf_idx; prev_st = pstr->cur_state; mbclen = __mbrtowc (&wc2, (const char *) pstr->raw_mbs + rawbuf_idx, remain_len, &pstr->cur_state); if (BE (mbclen == (size_t) -2 || mbclen == (size_t) -1 || mbclen == 0, 0)) { /* We treat these cases as a single byte character. */ if (mbclen == 0 || remain_len == 0) wc = L'\0'; else wc = *(unsigned char *) (pstr->raw_mbs + rawbuf_idx); mbclen = 1; pstr->cur_state = prev_st; } else wc = (wint_t) wc2; /* Then proceed the next character. */ rawbuf_idx += mbclen; } *last_wc = (wint_t) wc; return rawbuf_idx; } #endif /* RE_ENABLE_I18N */ /* Build the buffer PSTR->MBS, and apply the translation if we need. This function is used in case of REG_ICASE. */ static void internal_function build_upper_buffer (re_string_t *pstr) { int char_idx, end_idx; end_idx = (pstr->bufs_len > pstr->len) ? pstr->len : pstr->bufs_len; for (char_idx = pstr->valid_len; char_idx < end_idx; ++char_idx) { int ch = pstr->raw_mbs[pstr->raw_mbs_idx + char_idx]; if (BE (pstr->trans != NULL, 0)) ch = pstr->trans[ch]; if (islower (ch)) pstr->mbs[char_idx] = toupper (ch); else pstr->mbs[char_idx] = ch; } pstr->valid_len = char_idx; pstr->valid_raw_len = char_idx; } /* Apply TRANS to the buffer in PSTR. */ static void internal_function re_string_translate_buffer (re_string_t *pstr) { int buf_idx, end_idx; end_idx = (pstr->bufs_len > pstr->len) ? pstr->len : pstr->bufs_len; for (buf_idx = pstr->valid_len; buf_idx < end_idx; ++buf_idx) { int ch = pstr->raw_mbs[pstr->raw_mbs_idx + buf_idx]; pstr->mbs[buf_idx] = pstr->trans[ch]; } pstr->valid_len = buf_idx; pstr->valid_raw_len = buf_idx; } /* This function re-construct the buffers. Concretely, convert to wide character in case of pstr->mb_cur_max > 1, convert to upper case in case of REG_ICASE, apply translation. */ static reg_errcode_t internal_function re_string_reconstruct (re_string_t *pstr, int idx, int eflags) { int offset = idx - pstr->raw_mbs_idx; if (BE (offset < 0, 0)) { /* Reset buffer. */ #ifdef RE_ENABLE_I18N if (pstr->mb_cur_max > 1) memset (&pstr->cur_state, '\0', sizeof (mbstate_t)); #endif /* RE_ENABLE_I18N */ pstr->len = pstr->raw_len; pstr->stop = pstr->raw_stop; pstr->valid_len = 0; pstr->raw_mbs_idx = 0; pstr->valid_raw_len = 0; pstr->offsets_needed = 0; pstr->tip_context = ((eflags & REG_NOTBOL) ? CONTEXT_BEGBUF : CONTEXT_NEWLINE | CONTEXT_BEGBUF); if (!pstr->mbs_allocated) pstr->mbs = (unsigned char *) pstr->raw_mbs; offset = idx; } if (BE (offset != 0, 1)) { /* Should the already checked characters be kept? */ if (BE (offset < pstr->valid_raw_len, 1)) { /* Yes, move them to the front of the buffer. */ #ifdef RE_ENABLE_I18N if (BE (pstr->offsets_needed, 0)) { int low = 0, high = pstr->valid_len, mid; do { mid = (high + low) / 2; if (pstr->offsets[mid] > offset) high = mid; else if (pstr->offsets[mid] < offset) low = mid + 1; else break; } while (low < high); if (pstr->offsets[mid] < offset) ++mid; pstr->tip_context = re_string_context_at (pstr, mid - 1, eflags); /* This can be quite complicated, so handle specially only the common and easy case where the character with different length representation of lower and upper case is present at or after offset. */ if (pstr->valid_len > offset && mid == offset && pstr->offsets[mid] == offset) { memmove (pstr->wcs, pstr->wcs + offset, (pstr->valid_len - offset) * sizeof (wint_t)); memmove (pstr->mbs, pstr->mbs + offset, pstr->valid_len - offset); pstr->valid_len -= offset; pstr->valid_raw_len -= offset; for (low = 0; low < pstr->valid_len; low++) pstr->offsets[low] = pstr->offsets[low + offset] - offset; } else { /* Otherwise, just find out how long the partial multibyte character at offset is and fill it with WEOF/255. */ pstr->len = pstr->raw_len - idx + offset; pstr->stop = pstr->raw_stop - idx + offset; pstr->offsets_needed = 0; while (mid > 0 && pstr->offsets[mid - 1] == offset) --mid; while (mid < pstr->valid_len) if (pstr->wcs[mid] != WEOF) break; else ++mid; if (mid == pstr->valid_len) pstr->valid_len = 0; else { pstr->valid_len = pstr->offsets[mid] - offset; if (pstr->valid_len) { for (low = 0; low < pstr->valid_len; ++low) pstr->wcs[low] = WEOF; memset (pstr->mbs, 255, pstr->valid_len); } } pstr->valid_raw_len = pstr->valid_len; } } else #endif { pstr->tip_context = re_string_context_at (pstr, offset - 1, eflags); #ifdef RE_ENABLE_I18N if (pstr->mb_cur_max > 1) memmove (pstr->wcs, pstr->wcs + offset, (pstr->valid_len - offset) * sizeof (wint_t)); #endif /* RE_ENABLE_I18N */ if (BE (pstr->mbs_allocated, 0)) memmove (pstr->mbs, pstr->mbs + offset, pstr->valid_len - offset); pstr->valid_len -= offset; pstr->valid_raw_len -= offset; #if DEBUG assert (pstr->valid_len > 0); #endif } } else { #ifdef RE_ENABLE_I18N /* No, skip all characters until IDX. */ int prev_valid_len = pstr->valid_len; if (BE (pstr->offsets_needed, 0)) { pstr->len = pstr->raw_len - idx + offset; pstr->stop = pstr->raw_stop - idx + offset; pstr->offsets_needed = 0; } #endif pstr->valid_len = 0; #ifdef RE_ENABLE_I18N if (pstr->mb_cur_max > 1) { int wcs_idx; wint_t wc = WEOF; if (pstr->is_utf8) { const unsigned char *raw, *p, *end; /* Special case UTF-8. Multi-byte chars start with any byte other than 0x80 - 0xbf. */ raw = pstr->raw_mbs + pstr->raw_mbs_idx; end = raw + (offset - pstr->mb_cur_max); if (end < pstr->raw_mbs) end = pstr->raw_mbs; p = raw + offset - 1; #ifdef _LIBC /* We know the wchar_t encoding is UCS4, so for the simple case, ASCII characters, skip the conversion step. */ if (isascii (*p) && BE (pstr->trans == NULL, 1)) { memset (&pstr->cur_state, '\0', sizeof (mbstate_t)); /* pstr->valid_len = 0; */ wc = (wchar_t) *p; } else #endif for (; p >= end; --p) if ((*p & 0xc0) != 0x80) { mbstate_t cur_state; wchar_t wc2; int mlen = raw + pstr->len - p; unsigned char buf[6]; size_t mbclen; if (BE (pstr->trans != NULL, 0)) { int i = mlen < 6 ? mlen : 6; while (--i >= 0) buf[i] = pstr->trans[p[i]]; } /* XXX Don't use mbrtowc, we know which conversion to use (UTF-8 -> UCS4). */ memset (&cur_state, 0, sizeof (cur_state)); mbclen = __mbrtowc (&wc2, (const char *) p, mlen, &cur_state); if (raw + offset - p <= mbclen && mbclen < (size_t) -2) { memset (&pstr->cur_state, '\0', sizeof (mbstate_t)); pstr->valid_len = mbclen - (raw + offset - p); wc = wc2; } break; } } if (wc == WEOF) pstr->valid_len = re_string_skip_chars (pstr, idx, &wc) - idx; if (wc == WEOF) pstr->tip_context = re_string_context_at (pstr, prev_valid_len - 1, eflags); else pstr->tip_context = ((BE (pstr->word_ops_used != 0, 0) && IS_WIDE_WORD_CHAR (wc)) ? CONTEXT_WORD : ((IS_WIDE_NEWLINE (wc) && pstr->newline_anchor) ? CONTEXT_NEWLINE : 0)); if (BE (pstr->valid_len, 0)) { for (wcs_idx = 0; wcs_idx < pstr->valid_len; ++wcs_idx) pstr->wcs[wcs_idx] = WEOF; if (pstr->mbs_allocated) memset (pstr->mbs, 255, pstr->valid_len); } pstr->valid_raw_len = pstr->valid_len; } else #endif /* RE_ENABLE_I18N */ { int c = pstr->raw_mbs[pstr->raw_mbs_idx + offset - 1]; pstr->valid_raw_len = 0; if (pstr->trans) c = pstr->trans[c]; pstr->tip_context = (bitset_contain (pstr->word_char, c) ? CONTEXT_WORD : ((IS_NEWLINE (c) && pstr->newline_anchor) ? CONTEXT_NEWLINE : 0)); } } if (!BE (pstr->mbs_allocated, 0)) pstr->mbs += offset; } pstr->raw_mbs_idx = idx; pstr->len -= offset; pstr->stop -= offset; /* Then build the buffers. */ #ifdef RE_ENABLE_I18N if (pstr->mb_cur_max > 1) { if (pstr->icase) { reg_errcode_t ret = build_wcs_upper_buffer (pstr); if (BE (ret != REG_NOERROR, 0)) return ret; } else build_wcs_buffer (pstr); } else #endif /* RE_ENABLE_I18N */ if (BE (pstr->mbs_allocated, 0)) { if (pstr->icase) build_upper_buffer (pstr); else if (pstr->trans != NULL) re_string_translate_buffer (pstr); } else pstr->valid_len = pstr->len; pstr->cur_idx = 0; return REG_NOERROR; } static unsigned char internal_function __attribute ((pure)) re_string_peek_byte_case (const re_string_t *pstr, int idx) { int ch, off; /* Handle the common (easiest) cases first. */ if (BE (!pstr->mbs_allocated, 1)) return re_string_peek_byte (pstr, idx); #ifdef RE_ENABLE_I18N if (pstr->mb_cur_max > 1 && ! re_string_is_single_byte_char (pstr, pstr->cur_idx + idx)) return re_string_peek_byte (pstr, idx); #endif off = pstr->cur_idx + idx; #ifdef RE_ENABLE_I18N if (pstr->offsets_needed) off = pstr->offsets[off]; #endif ch = pstr->raw_mbs[pstr->raw_mbs_idx + off]; #ifdef RE_ENABLE_I18N /* Ensure that e.g. for tr_TR.UTF-8 BACKSLASH DOTLESS SMALL LETTER I this function returns CAPITAL LETTER I instead of first byte of DOTLESS SMALL LETTER I. The latter would confuse the parser, since peek_byte_case doesn't advance cur_idx in any way. */ if (pstr->offsets_needed && !isascii (ch)) return re_string_peek_byte (pstr, idx); #endif return ch; } static unsigned char internal_function __attribute ((pure)) re_string_fetch_byte_case (re_string_t *pstr) { if (BE (!pstr->mbs_allocated, 1)) return re_string_fetch_byte (pstr); #ifdef RE_ENABLE_I18N if (pstr->offsets_needed) { int off, ch; /* For tr_TR.UTF-8 [[:islower:]] there is [[: CAPITAL LETTER I WITH DOT lower:]] in mbs. Skip in that case the whole multi-byte character and return the original letter. On the other side, with [[: DOTLESS SMALL LETTER I return [[:I, as doing anything else would complicate things too much. */ if (!re_string_first_byte (pstr, pstr->cur_idx)) return re_string_fetch_byte (pstr); off = pstr->offsets[pstr->cur_idx]; ch = pstr->raw_mbs[pstr->raw_mbs_idx + off]; if (! isascii (ch)) return re_string_fetch_byte (pstr); re_string_skip_bytes (pstr, re_string_char_size_at (pstr, pstr->cur_idx)); return ch; } #endif return pstr->raw_mbs[pstr->raw_mbs_idx + pstr->cur_idx++]; } static void internal_function re_string_destruct (re_string_t *pstr) { #ifdef RE_ENABLE_I18N re_free (pstr->wcs); re_free (pstr->offsets); #endif /* RE_ENABLE_I18N */ if (pstr->mbs_allocated) re_free (pstr->mbs); } /* Return the context at IDX in INPUT. */ static unsigned int internal_function re_string_context_at (const re_string_t *input, int idx, int eflags) { int c; if (BE (idx < 0, 0)) /* In this case, we use the value stored in input->tip_context, since we can't know the character in input->mbs[-1] here. */ return input->tip_context; if (BE (idx == input->len, 0)) return ((eflags & REG_NOTEOL) ? CONTEXT_ENDBUF : CONTEXT_NEWLINE | CONTEXT_ENDBUF); #ifdef RE_ENABLE_I18N if (input->mb_cur_max > 1) { wint_t wc; int wc_idx = idx; while(input->wcs[wc_idx] == WEOF) { #ifdef DEBUG /* It must not happen. */ assert (wc_idx >= 0); #endif --wc_idx; if (wc_idx < 0) return input->tip_context; } wc = input->wcs[wc_idx]; if (BE (input->word_ops_used != 0, 0) && IS_WIDE_WORD_CHAR (wc)) return CONTEXT_WORD; return (IS_WIDE_NEWLINE (wc) && input->newline_anchor ? CONTEXT_NEWLINE : 0); } else #endif { c = re_string_byte_at (input, idx); if (bitset_contain (input->word_char, c)) return CONTEXT_WORD; return IS_NEWLINE (c) && input->newline_anchor ? CONTEXT_NEWLINE : 0; } } /* Functions for set operation. */ static reg_errcode_t internal_function re_node_set_alloc (re_node_set *set, int size) { /* * ADR: valgrind says size can be 0, which then doesn't * free the block of size 0. Harumph. This seems * to work ok, though. */ if (size == 0) { memset(set, 0, sizeof(*set)); return REG_NOERROR; } set->alloc = size; set->nelem = 0; set->elems = re_malloc (int, size); if (BE (set->elems == NULL, 0)) return REG_ESPACE; return REG_NOERROR; } static reg_errcode_t internal_function re_node_set_init_1 (re_node_set *set, int elem) { set->alloc = 1; set->nelem = 1; set->elems = re_malloc (int, 1); if (BE (set->elems == NULL, 0)) { set->alloc = set->nelem = 0; return REG_ESPACE; } set->elems[0] = elem; return REG_NOERROR; } static reg_errcode_t internal_function re_node_set_init_2 (re_node_set *set, int elem1, int elem2) { set->alloc = 2; set->elems = re_malloc (int, 2); if (BE (set->elems == NULL, 0)) return REG_ESPACE; if (elem1 == elem2) { set->nelem = 1; set->elems[0] = elem1; } else { set->nelem = 2; if (elem1 < elem2) { set->elems[0] = elem1; set->elems[1] = elem2; } else { set->elems[0] = elem2; set->elems[1] = elem1; } } return REG_NOERROR; } static reg_errcode_t internal_function re_node_set_init_copy (re_node_set *dest, const re_node_set *src) { dest->nelem = src->nelem; if (src->nelem > 0) { dest->alloc = dest->nelem; dest->elems = re_malloc (int, dest->alloc); if (BE (dest->elems == NULL, 0)) { dest->alloc = dest->nelem = 0; return REG_ESPACE; } memcpy (dest->elems, src->elems, src->nelem * sizeof (int)); } else re_node_set_init_empty (dest); return REG_NOERROR; } /* Calculate the intersection of the sets SRC1 and SRC2. And merge it to DEST. Return value indicate the error code or REG_NOERROR if succeeded. Note: We assume dest->elems is NULL, when dest->alloc is 0. */ static reg_errcode_t internal_function re_node_set_add_intersect (re_node_set *dest, const re_node_set *src1, const re_node_set *src2) { int i1, i2, is, id, delta, sbase; if (src1->nelem == 0 || src2->nelem == 0) return REG_NOERROR; /* We need dest->nelem + 2 * elems_in_intersection; this is a conservative estimate. */ if (src1->nelem + src2->nelem + dest->nelem > dest->alloc) { int new_alloc = src1->nelem + src2->nelem + dest->alloc; int *new_elems = re_realloc (dest->elems, int, new_alloc); if (BE (new_elems == NULL, 0)) return REG_ESPACE; dest->elems = new_elems; dest->alloc = new_alloc; } /* Find the items in the intersection of SRC1 and SRC2, and copy into the top of DEST those that are not already in DEST itself. */ sbase = dest->nelem + src1->nelem + src2->nelem; i1 = src1->nelem - 1; i2 = src2->nelem - 1; id = dest->nelem - 1; for (;;) { if (src1->elems[i1] == src2->elems[i2]) { /* Try to find the item in DEST. Maybe we could binary search? */ while (id >= 0 && dest->elems[id] > src1->elems[i1]) --id; if (id < 0 || dest->elems[id] != src1->elems[i1]) dest->elems[--sbase] = src1->elems[i1]; if (--i1 < 0 || --i2 < 0) break; } /* Lower the highest of the two items. */ else if (src1->elems[i1] < src2->elems[i2]) { if (--i2 < 0) break; } else { if (--i1 < 0) break; } } id = dest->nelem - 1; is = dest->nelem + src1->nelem + src2->nelem - 1; delta = is - sbase + 1; /* Now copy. When DELTA becomes zero, the remaining DEST elements are already in place; this is more or less the same loop that is in re_node_set_merge. */ dest->nelem += delta; if (delta > 0 && id >= 0) for (;;) { if (dest->elems[is] > dest->elems[id]) { /* Copy from the top. */ dest->elems[id + delta--] = dest->elems[is--]; if (delta == 0) break; } else { /* Slide from the bottom. */ dest->elems[id + delta] = dest->elems[id]; if (--id < 0) break; } } /* Copy remaining SRC elements. */ memcpy (dest->elems, dest->elems + sbase, delta * sizeof (int)); return REG_NOERROR; } /* Calculate the union set of the sets SRC1 and SRC2. And store it to DEST. Return value indicate the error code or REG_NOERROR if succeeded. */ static reg_errcode_t internal_function re_node_set_init_union (re_node_set *dest, const re_node_set *src1, const re_node_set *src2) { int i1, i2, id; if (src1 != NULL && src1->nelem > 0 && src2 != NULL && src2->nelem > 0) { dest->alloc = src1->nelem + src2->nelem; dest->elems = re_malloc (int, dest->alloc); if (BE (dest->elems == NULL, 0)) return REG_ESPACE; } else { if (src1 != NULL && src1->nelem > 0) return re_node_set_init_copy (dest, src1); else if (src2 != NULL && src2->nelem > 0) return re_node_set_init_copy (dest, src2); else re_node_set_init_empty (dest); return REG_NOERROR; } for (i1 = i2 = id = 0 ; i1 < src1->nelem && i2 < src2->nelem ;) { if (src1->elems[i1] > src2->elems[i2]) { dest->elems[id++] = src2->elems[i2++]; continue; } if (src1->elems[i1] == src2->elems[i2]) ++i2; dest->elems[id++] = src1->elems[i1++]; } if (i1 < src1->nelem) { memcpy (dest->elems + id, src1->elems + i1, (src1->nelem - i1) * sizeof (int)); id += src1->nelem - i1; } else if (i2 < src2->nelem) { memcpy (dest->elems + id, src2->elems + i2, (src2->nelem - i2) * sizeof (int)); id += src2->nelem - i2; } dest->nelem = id; return REG_NOERROR; } /* Calculate the union set of the sets DEST and SRC. And store it to DEST. Return value indicate the error code or REG_NOERROR if succeeded. */ static reg_errcode_t internal_function re_node_set_merge (re_node_set *dest, const re_node_set *src) { int is, id, sbase, delta; if (src == NULL || src->nelem == 0) return REG_NOERROR; if (dest->alloc < 2 * src->nelem + dest->nelem) { int new_alloc = 2 * (src->nelem + dest->alloc); int *new_buffer = re_realloc (dest->elems, int, new_alloc); if (BE (new_buffer == NULL, 0)) return REG_ESPACE; dest->elems = new_buffer; dest->alloc = new_alloc; } if (BE (dest->nelem == 0, 0)) { dest->nelem = src->nelem; memcpy (dest->elems, src->elems, src->nelem * sizeof (int)); return REG_NOERROR; } /* Copy into the top of DEST the items of SRC that are not found in DEST. Maybe we could binary search in DEST? */ for (sbase = dest->nelem + 2 * src->nelem, is = src->nelem - 1, id = dest->nelem - 1; is >= 0 && id >= 0; ) { if (dest->elems[id] == src->elems[is]) is--, id--; else if (dest->elems[id] < src->elems[is]) dest->elems[--sbase] = src->elems[is--]; else /* if (dest->elems[id] > src->elems[is]) */ --id; } if (is >= 0) { /* If DEST is exhausted, the remaining items of SRC must be unique. */ sbase -= is + 1; memcpy (dest->elems + sbase, src->elems, (is + 1) * sizeof (int)); } id = dest->nelem - 1; is = dest->nelem + 2 * src->nelem - 1; delta = is - sbase + 1; if (delta == 0) return REG_NOERROR; /* Now copy. When DELTA becomes zero, the remaining DEST elements are already in place. */ dest->nelem += delta; for (;;) { if (dest->elems[is] > dest->elems[id]) { /* Copy from the top. */ dest->elems[id + delta--] = dest->elems[is--]; if (delta == 0) break; } else { /* Slide from the bottom. */ dest->elems[id + delta] = dest->elems[id]; if (--id < 0) { /* Copy remaining SRC elements. */ memcpy (dest->elems, dest->elems + sbase, delta * sizeof (int)); break; } } } return REG_NOERROR; } /* Insert the new element ELEM to the re_node_set* SET. SET should not already have ELEM. return -1 if an error is occured, return 1 otherwise. */ static int internal_function re_node_set_insert (re_node_set *set, int elem) { int idx; /* In case the set is empty. */ if (set->alloc == 0) { if (BE (re_node_set_init_1 (set, elem) == REG_NOERROR, 1)) return 1; else return -1; } if (BE (set->nelem, 0) == 0) { /* We already guaranteed above that set->alloc != 0. */ set->elems[0] = elem; ++set->nelem; return 1; } /* Realloc if we need. */ if (set->alloc == set->nelem) { int *new_elems; set->alloc = set->alloc * 2; new_elems = re_realloc (set->elems, int, set->alloc); if (BE (new_elems == NULL, 0)) return -1; set->elems = new_elems; } /* Move the elements which follows the new element. Test the first element separately to skip a check in the inner loop. */ if (elem < set->elems[0]) { idx = 0; for (idx = set->nelem; idx > 0; idx--) set->elems[idx] = set->elems[idx - 1]; } else { for (idx = set->nelem; set->elems[idx - 1] > elem; idx--) set->elems[idx] = set->elems[idx - 1]; } /* Insert the new element. */ set->elems[idx] = elem; ++set->nelem; return 1; } /* Insert the new element ELEM to the re_node_set* SET. SET should not already have any element greater than or equal to ELEM. Return -1 if an error is occured, return 1 otherwise. */ static int internal_function re_node_set_insert_last (re_node_set *set, int elem) { /* Realloc if we need. */ if (set->alloc == set->nelem) { int *new_elems; set->alloc = (set->alloc + 1) * 2; new_elems = re_realloc (set->elems, int, set->alloc); if (BE (new_elems == NULL, 0)) return -1; set->elems = new_elems; } /* Insert the new element. */ set->elems[set->nelem++] = elem; return 1; } /* Compare two node sets SET1 and SET2. return 1 if SET1 and SET2 are equivalent, return 0 otherwise. */ static int internal_function __attribute ((pure)) re_node_set_compare (const re_node_set *set1, const re_node_set *set2) { int i; if (set1 == NULL || set2 == NULL || set1->nelem != set2->nelem) return 0; for (i = set1->nelem ; --i >= 0 ; ) if (set1->elems[i] != set2->elems[i]) return 0; return 1; } /* Return (idx + 1) if SET contains the element ELEM, return 0 otherwise. */ static int internal_function __attribute ((pure)) re_node_set_contains (const re_node_set *set, int elem) { unsigned int idx, right, mid; if (set->nelem <= 0) return 0; /* Binary search the element. */ idx = 0; right = set->nelem - 1; while (idx < right) { mid = (idx + right) / 2; if (set->elems[mid] < elem) idx = mid + 1; else right = mid; } return set->elems[idx] == elem ? idx + 1 : 0; } static void internal_function re_node_set_remove_at (re_node_set *set, int idx) { if (idx < 0 || idx >= set->nelem) return; --set->nelem; for (; idx < set->nelem; idx++) set->elems[idx] = set->elems[idx + 1]; } /* Add the token TOKEN to dfa->nodes, and return the index of the token. Or return -1, if an error will be occured. */ static int internal_function re_dfa_add_node (re_dfa_t *dfa, re_token_t token) { if (BE (dfa->nodes_len >= dfa->nodes_alloc, 0)) { size_t new_nodes_alloc = dfa->nodes_alloc * 2; int *new_nexts, *new_indices; re_node_set *new_edests, *new_eclosures; re_token_t *new_nodes; /* Avoid overflows in realloc. */ const size_t max_object_size = MAX (sizeof (re_token_t), MAX (sizeof (re_node_set), sizeof (int))); if (BE (SIZE_MAX / max_object_size < new_nodes_alloc, 0)) return -1; new_nodes = re_realloc (dfa->nodes, re_token_t, new_nodes_alloc); if (BE (new_nodes == NULL, 0)) return -1; dfa->nodes = new_nodes; new_nexts = re_realloc (dfa->nexts, int, new_nodes_alloc); new_indices = re_realloc (dfa->org_indices, int, new_nodes_alloc); new_edests = re_realloc (dfa->edests, re_node_set, new_nodes_alloc); new_eclosures = re_realloc (dfa->eclosures, re_node_set, new_nodes_alloc); if (BE (new_nexts == NULL || new_indices == NULL || new_edests == NULL || new_eclosures == NULL, 0)) return -1; dfa->nexts = new_nexts; dfa->org_indices = new_indices; dfa->edests = new_edests; dfa->eclosures = new_eclosures; dfa->nodes_alloc = new_nodes_alloc; } dfa->nodes[dfa->nodes_len] = token; dfa->nodes[dfa->nodes_len].constraint = 0; #ifdef RE_ENABLE_I18N dfa->nodes[dfa->nodes_len].accept_mb = (token.type == OP_PERIOD && dfa->mb_cur_max > 1) || token.type == COMPLEX_BRACKET; #endif dfa->nexts[dfa->nodes_len] = -1; re_node_set_init_empty (dfa->edests + dfa->nodes_len); re_node_set_init_empty (dfa->eclosures + dfa->nodes_len); return dfa->nodes_len++; } static inline unsigned int internal_function calc_state_hash (const re_node_set *nodes, unsigned int context) { unsigned int hash = nodes->nelem + context; int i; for (i = 0 ; i < nodes->nelem ; i++) hash += nodes->elems[i]; return hash; } /* Search for the state whose node_set is equivalent to NODES. Return the pointer to the state, if we found it in the DFA. Otherwise create the new one and return it. In case of an error return NULL and set the error code in ERR. Note: - We assume NULL as the invalid state, then it is possible that return value is NULL and ERR is REG_NOERROR. - We never return non-NULL value in case of any errors, it is for optimization. */ static re_dfastate_t * internal_function re_acquire_state (reg_errcode_t *err, const re_dfa_t *dfa, const re_node_set *nodes) { unsigned int hash; re_dfastate_t *new_state; struct re_state_table_entry *spot; int i; if (BE (nodes->nelem == 0, 0)) { *err = REG_NOERROR; return NULL; } hash = calc_state_hash (nodes, 0); spot = dfa->state_table + (hash & dfa->state_hash_mask); for (i = 0 ; i < spot->num ; i++) { re_dfastate_t *state = spot->array[i]; if (hash != state->hash) continue; if (re_node_set_compare (&state->nodes, nodes)) return state; } /* There are no appropriate state in the dfa, create the new one. */ new_state = create_ci_newstate (dfa, nodes, hash); if (BE (new_state == NULL, 0)) *err = REG_ESPACE; return new_state; } /* Search for the state whose node_set is equivalent to NODES and whose context is equivalent to CONTEXT. Return the pointer to the state, if we found it in the DFA. Otherwise create the new one and return it. In case of an error return NULL and set the error code in ERR. Note: - We assume NULL as the invalid state, then it is possible that return value is NULL and ERR is REG_NOERROR. - We never return non-NULL value in case of any errors, it is for optimization. */ static re_dfastate_t * internal_function re_acquire_state_context (reg_errcode_t *err, const re_dfa_t *dfa, const re_node_set *nodes, unsigned int context) { unsigned int hash; re_dfastate_t *new_state; struct re_state_table_entry *spot; int i; if (nodes->nelem == 0) { *err = REG_NOERROR; return NULL; } hash = calc_state_hash (nodes, context); spot = dfa->state_table + (hash & dfa->state_hash_mask); for (i = 0 ; i < spot->num ; i++) { re_dfastate_t *state = spot->array[i]; if (state->hash == hash && state->context == context && re_node_set_compare (state->entrance_nodes, nodes)) return state; } /* There are no appropriate state in `dfa', create the new one. */ new_state = create_cd_newstate (dfa, nodes, context, hash); if (BE (new_state == NULL, 0)) *err = REG_ESPACE; return new_state; } /* Finish initialization of the new state NEWSTATE, and using its hash value HASH put in the appropriate bucket of DFA's state table. Return value indicates the error code if failed. */ static reg_errcode_t register_state (const re_dfa_t *dfa, re_dfastate_t *newstate, unsigned int hash) { struct re_state_table_entry *spot; reg_errcode_t err; int i; newstate->hash = hash; err = re_node_set_alloc (&newstate->non_eps_nodes, newstate->nodes.nelem); if (BE (err != REG_NOERROR, 0)) return REG_ESPACE; for (i = 0; i < newstate->nodes.nelem; i++) { int elem = newstate->nodes.elems[i]; if (!IS_EPSILON_NODE (dfa->nodes[elem].type)) if (re_node_set_insert_last (&newstate->non_eps_nodes, elem) < 0) return REG_ESPACE; } spot = dfa->state_table + (hash & dfa->state_hash_mask); if (BE (spot->alloc <= spot->num, 0)) { int new_alloc = 2 * spot->num + 2; re_dfastate_t **new_array = re_realloc (spot->array, re_dfastate_t *, new_alloc); if (BE (new_array == NULL, 0)) return REG_ESPACE; spot->array = new_array; spot->alloc = new_alloc; } spot->array[spot->num++] = newstate; return REG_NOERROR; } static void free_state (re_dfastate_t *state) { re_node_set_free (&state->non_eps_nodes); re_node_set_free (&state->inveclosure); if (state->entrance_nodes != &state->nodes) { re_node_set_free (state->entrance_nodes); re_free (state->entrance_nodes); } re_node_set_free (&state->nodes); re_free (state->word_trtable); re_free (state->trtable); re_free (state); } /* Create the new state which is independ of contexts. Return the new state if succeeded, otherwise return NULL. */ static re_dfastate_t * internal_function create_ci_newstate (const re_dfa_t *dfa, const re_node_set *nodes, unsigned int hash) { int i; reg_errcode_t err; re_dfastate_t *newstate; newstate = (re_dfastate_t *) calloc (sizeof (re_dfastate_t), 1); if (BE (newstate == NULL, 0)) return NULL; err = re_node_set_init_copy (&newstate->nodes, nodes); if (BE (err != REG_NOERROR, 0)) { re_free (newstate); return NULL; } newstate->entrance_nodes = &newstate->nodes; for (i = 0 ; i < nodes->nelem ; i++) { re_token_t *node = dfa->nodes + nodes->elems[i]; re_token_type_t type = node->type; if (type == CHARACTER && !node->constraint) continue; #ifdef RE_ENABLE_I18N newstate->accept_mb |= node->accept_mb; #endif /* RE_ENABLE_I18N */ /* If the state has the halt node, the state is a halt state. */ if (type == END_OF_RE) newstate->halt = 1; else if (type == OP_BACK_REF) newstate->has_backref = 1; else if (type == ANCHOR || node->constraint) newstate->has_constraint = 1; } err = register_state (dfa, newstate, hash); if (BE (err != REG_NOERROR, 0)) { free_state (newstate); newstate = NULL; } return newstate; } /* Create the new state which is depend on the context CONTEXT. Return the new state if succeeded, otherwise return NULL. */ static re_dfastate_t * internal_function create_cd_newstate (const re_dfa_t *dfa, const re_node_set *nodes, unsigned int context, unsigned int hash) { int i, nctx_nodes = 0; reg_errcode_t err; re_dfastate_t *newstate; newstate = (re_dfastate_t *) calloc (sizeof (re_dfastate_t), 1); if (BE (newstate == NULL, 0)) return NULL; err = re_node_set_init_copy (&newstate->nodes, nodes); if (BE (err != REG_NOERROR, 0)) { re_free (newstate); return NULL; } newstate->context = context; newstate->entrance_nodes = &newstate->nodes; for (i = 0 ; i < nodes->nelem ; i++) { re_token_t *node = dfa->nodes + nodes->elems[i]; re_token_type_t type = node->type; unsigned int constraint = node->constraint; if (type == CHARACTER && !constraint) continue; #ifdef RE_ENABLE_I18N newstate->accept_mb |= node->accept_mb; #endif /* RE_ENABLE_I18N */ /* If the state has the halt node, the state is a halt state. */ if (type == END_OF_RE) newstate->halt = 1; else if (type == OP_BACK_REF) newstate->has_backref = 1; if (constraint) { if (newstate->entrance_nodes == &newstate->nodes) { newstate->entrance_nodes = re_malloc (re_node_set, 1); if (BE (newstate->entrance_nodes == NULL, 0)) { free_state (newstate); return NULL; } if (re_node_set_init_copy (newstate->entrance_nodes, nodes) != REG_NOERROR) return NULL; nctx_nodes = 0; newstate->has_constraint = 1; } if (NOT_SATISFY_PREV_CONSTRAINT (constraint,context)) { re_node_set_remove_at (&newstate->nodes, i - nctx_nodes); ++nctx_nodes; } } } err = register_state (dfa, newstate, hash); if (BE (err != REG_NOERROR, 0)) { free_state (newstate); newstate = NULL; } return newstate; } libgit2-0.19.0/deps/regex/regex_internal.h000066400000000000000000000541141216214232500203640ustar00rootroot00000000000000/* Extended regular expression matching and search library. Copyright (C) 2002-2005, 2007, 2008, 2010 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Isamu Hasegawa . The GNU C Library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. The GNU C Library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with the GNU C Library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ #ifndef _REGEX_INTERNAL_H #define _REGEX_INTERNAL_H 1 #include #include #include #include #include #ifndef UNUSED # ifdef __GNUC__ # define UNUSED __attribute__((unused)) # else # define UNUSED # endif #endif #if defined HAVE_LANGINFO_H || defined HAVE_LANGINFO_CODESET || defined _LIBC # include #endif #if defined HAVE_LOCALE_H || defined _LIBC # include #endif #if defined HAVE_WCHAR_H || defined _LIBC # include #endif /* HAVE_WCHAR_H || _LIBC */ #if defined HAVE_WCTYPE_H || defined _LIBC # include #endif /* HAVE_WCTYPE_H || _LIBC */ #if defined HAVE_STDBOOL_H || defined _LIBC # include #endif /* HAVE_STDBOOL_H || _LIBC */ #if !defined(ZOS_USS) #if defined HAVE_STDINT_H || defined _LIBC # include #endif /* HAVE_STDINT_H || _LIBC */ #endif /* !ZOS_USS */ #if defined _LIBC # include #else # define __libc_lock_define(CLASS,NAME) # define __libc_lock_init(NAME) do { } while (0) # define __libc_lock_lock(NAME) do { } while (0) # define __libc_lock_unlock(NAME) do { } while (0) #endif #ifndef GAWK /* In case that the system doesn't have isblank(). */ #if !defined _LIBC && !defined HAVE_ISBLANK && !defined isblank # define isblank(ch) ((ch) == ' ' || (ch) == '\t') #endif #else /* GAWK */ /* * This is a mess. On glibc systems you have to define * a magic constant to get isblank() out of , since it's * a C99 function. To heck with all that and borrow a page from * dfa.c's book. */ static int is_blank (int c) { return (c == ' ' || c == '\t'); } #endif /* GAWK */ #ifdef _LIBC # ifndef _RE_DEFINE_LOCALE_FUNCTIONS # define _RE_DEFINE_LOCALE_FUNCTIONS 1 # include # include # include # endif #endif /* This is for other GNU distributions with internationalized messages. */ #if (HAVE_LIBINTL_H && ENABLE_NLS) || defined _LIBC # include # ifdef _LIBC # undef gettext # define gettext(msgid) \ INTUSE(__dcgettext) (_libc_intl_domainname, msgid, LC_MESSAGES) # endif #else # define gettext(msgid) (msgid) #endif #ifndef gettext_noop /* This define is so xgettext can find the internationalizable strings. */ # define gettext_noop(String) String #endif /* For loser systems without the definition. */ #ifndef SIZE_MAX # define SIZE_MAX ((size_t) -1) #endif #ifndef NO_MBSUPPORT #include "mbsupport.h" /* gawk */ #endif #ifndef MB_CUR_MAX #define MB_CUR_MAX 1 #endif #if (defined MBS_SUPPORT) || _LIBC # define RE_ENABLE_I18N #endif #if __GNUC__ >= 3 # define BE(expr, val) __builtin_expect (expr, val) #else # define BE(expr, val) (expr) # ifdef inline # undef inline # endif # define inline #endif /* Number of single byte character. */ #define SBC_MAX 256 #define COLL_ELEM_LEN_MAX 8 /* The character which represents newline. */ #define NEWLINE_CHAR '\n' #define WIDE_NEWLINE_CHAR L'\n' /* Rename to standard API for using out of glibc. */ #ifndef _LIBC # ifdef __wctype # undef __wctype # endif # define __wctype wctype # ifdef __iswctype # undef __iswctype # endif # define __iswctype iswctype # define __btowc btowc # define __mbrtowc mbrtowc #undef __mempcpy /* GAWK */ # define __mempcpy mempcpy # define __wcrtomb wcrtomb # define __regfree regfree # define attribute_hidden #endif /* not _LIBC */ #ifdef __GNUC__ # define __attribute(arg) __attribute__ (arg) #else # define __attribute(arg) #endif extern const char __re_error_msgid[] attribute_hidden; extern const size_t __re_error_msgid_idx[] attribute_hidden; /* An integer used to represent a set of bits. It must be unsigned, and must be at least as wide as unsigned int. */ typedef unsigned long int bitset_word_t; /* All bits set in a bitset_word_t. */ #define BITSET_WORD_MAX ULONG_MAX /* Number of bits in a bitset_word_t. Cast to int as most code use it * like that for counting */ #define BITSET_WORD_BITS ((int)(sizeof (bitset_word_t) * CHAR_BIT)) /* Number of bitset_word_t in a bit_set. */ #define BITSET_WORDS (SBC_MAX / BITSET_WORD_BITS) typedef bitset_word_t bitset_t[BITSET_WORDS]; typedef bitset_word_t *re_bitset_ptr_t; typedef const bitset_word_t *re_const_bitset_ptr_t; #define bitset_set(set,i) \ (set[i / BITSET_WORD_BITS] |= (bitset_word_t) 1 << i % BITSET_WORD_BITS) #define bitset_clear(set,i) \ (set[i / BITSET_WORD_BITS] &= ~((bitset_word_t) 1 << i % BITSET_WORD_BITS)) #define bitset_contain(set,i) \ (set[i / BITSET_WORD_BITS] & ((bitset_word_t) 1 << i % BITSET_WORD_BITS)) #define bitset_empty(set) memset (set, '\0', sizeof (bitset_t)) #define bitset_set_all(set) memset (set, '\xff', sizeof (bitset_t)) #define bitset_copy(dest,src) memcpy (dest, src, sizeof (bitset_t)) #define PREV_WORD_CONSTRAINT 0x0001 #define PREV_NOTWORD_CONSTRAINT 0x0002 #define NEXT_WORD_CONSTRAINT 0x0004 #define NEXT_NOTWORD_CONSTRAINT 0x0008 #define PREV_NEWLINE_CONSTRAINT 0x0010 #define NEXT_NEWLINE_CONSTRAINT 0x0020 #define PREV_BEGBUF_CONSTRAINT 0x0040 #define NEXT_ENDBUF_CONSTRAINT 0x0080 #define WORD_DELIM_CONSTRAINT 0x0100 #define NOT_WORD_DELIM_CONSTRAINT 0x0200 typedef enum { INSIDE_WORD = PREV_WORD_CONSTRAINT | NEXT_WORD_CONSTRAINT, WORD_FIRST = PREV_NOTWORD_CONSTRAINT | NEXT_WORD_CONSTRAINT, WORD_LAST = PREV_WORD_CONSTRAINT | NEXT_NOTWORD_CONSTRAINT, INSIDE_NOTWORD = PREV_NOTWORD_CONSTRAINT | NEXT_NOTWORD_CONSTRAINT, LINE_FIRST = PREV_NEWLINE_CONSTRAINT, LINE_LAST = NEXT_NEWLINE_CONSTRAINT, BUF_FIRST = PREV_BEGBUF_CONSTRAINT, BUF_LAST = NEXT_ENDBUF_CONSTRAINT, WORD_DELIM = WORD_DELIM_CONSTRAINT, NOT_WORD_DELIM = NOT_WORD_DELIM_CONSTRAINT } re_context_type; typedef struct { int alloc; int nelem; int *elems; } re_node_set; typedef enum { NON_TYPE = 0, /* Node type, These are used by token, node, tree. */ CHARACTER = 1, END_OF_RE = 2, SIMPLE_BRACKET = 3, OP_BACK_REF = 4, OP_PERIOD = 5, #ifdef RE_ENABLE_I18N COMPLEX_BRACKET = 6, OP_UTF8_PERIOD = 7, #endif /* RE_ENABLE_I18N */ /* We define EPSILON_BIT as a macro so that OP_OPEN_SUBEXP is used when the debugger shows values of this enum type. */ #define EPSILON_BIT 8 OP_OPEN_SUBEXP = EPSILON_BIT | 0, OP_CLOSE_SUBEXP = EPSILON_BIT | 1, OP_ALT = EPSILON_BIT | 2, OP_DUP_ASTERISK = EPSILON_BIT | 3, ANCHOR = EPSILON_BIT | 4, /* Tree type, these are used only by tree. */ CONCAT = 16, SUBEXP = 17, /* Token type, these are used only by token. */ OP_DUP_PLUS = 18, OP_DUP_QUESTION, OP_OPEN_BRACKET, OP_CLOSE_BRACKET, OP_CHARSET_RANGE, OP_OPEN_DUP_NUM, OP_CLOSE_DUP_NUM, OP_NON_MATCH_LIST, OP_OPEN_COLL_ELEM, OP_CLOSE_COLL_ELEM, OP_OPEN_EQUIV_CLASS, OP_CLOSE_EQUIV_CLASS, OP_OPEN_CHAR_CLASS, OP_CLOSE_CHAR_CLASS, OP_WORD, OP_NOTWORD, OP_SPACE, OP_NOTSPACE, BACK_SLASH } re_token_type_t; #ifdef RE_ENABLE_I18N typedef struct { /* Multibyte characters. */ wchar_t *mbchars; /* Collating symbols. */ # ifdef _LIBC int32_t *coll_syms; # endif /* Equivalence classes. */ # ifdef _LIBC int32_t *equiv_classes; # endif /* Range expressions. */ # ifdef _LIBC uint32_t *range_starts; uint32_t *range_ends; # else /* not _LIBC */ wchar_t *range_starts; wchar_t *range_ends; # endif /* not _LIBC */ /* Character classes. */ wctype_t *char_classes; /* If this character set is the non-matching list. */ unsigned int non_match : 1; /* # of multibyte characters. */ int nmbchars; /* # of collating symbols. */ int ncoll_syms; /* # of equivalence classes. */ int nequiv_classes; /* # of range expressions. */ int nranges; /* # of character classes. */ int nchar_classes; } re_charset_t; #endif /* RE_ENABLE_I18N */ typedef struct { union { unsigned char c; /* for CHARACTER */ re_bitset_ptr_t sbcset; /* for SIMPLE_BRACKET */ #ifdef RE_ENABLE_I18N re_charset_t *mbcset; /* for COMPLEX_BRACKET */ #endif /* RE_ENABLE_I18N */ int idx; /* for BACK_REF */ re_context_type ctx_type; /* for ANCHOR */ } opr; #if __GNUC__ >= 2 re_token_type_t type : 8; #else re_token_type_t type; #endif unsigned int constraint : 10; /* context constraint */ unsigned int duplicated : 1; unsigned int opt_subexp : 1; #ifdef RE_ENABLE_I18N unsigned int accept_mb : 1; /* These 2 bits can be moved into the union if needed (e.g. if running out of bits; move opr.c to opr.c.c and move the flags to opr.c.flags). */ unsigned int mb_partial : 1; #endif unsigned int word_char : 1; } re_token_t; #define IS_EPSILON_NODE(type) ((type) & EPSILON_BIT) struct re_string_t { /* Indicate the raw buffer which is the original string passed as an argument of regexec(), re_search(), etc.. */ const unsigned char *raw_mbs; /* Store the multibyte string. In case of "case insensitive mode" like REG_ICASE, upper cases of the string are stored, otherwise MBS points the same address that RAW_MBS points. */ unsigned char *mbs; #ifdef RE_ENABLE_I18N /* Store the wide character string which is corresponding to MBS. */ wint_t *wcs; int *offsets; mbstate_t cur_state; #endif /* Index in RAW_MBS. Each character mbs[i] corresponds to raw_mbs[raw_mbs_idx + i]. */ int raw_mbs_idx; /* The length of the valid characters in the buffers. */ int valid_len; /* The corresponding number of bytes in raw_mbs array. */ int valid_raw_len; /* The length of the buffers MBS and WCS. */ int bufs_len; /* The index in MBS, which is updated by re_string_fetch_byte. */ int cur_idx; /* length of RAW_MBS array. */ int raw_len; /* This is RAW_LEN - RAW_MBS_IDX + VALID_LEN - VALID_RAW_LEN. */ int len; /* End of the buffer may be shorter than its length in the cases such as re_match_2, re_search_2. Then, we use STOP for end of the buffer instead of LEN. */ int raw_stop; /* This is RAW_STOP - RAW_MBS_IDX adjusted through OFFSETS. */ int stop; /* The context of mbs[0]. We store the context independently, since the context of mbs[0] may be different from raw_mbs[0], which is the beginning of the input string. */ unsigned int tip_context; /* The translation passed as a part of an argument of re_compile_pattern. */ RE_TRANSLATE_TYPE trans; /* Copy of re_dfa_t's word_char. */ re_const_bitset_ptr_t word_char; /* 1 if REG_ICASE. */ unsigned char icase; unsigned char is_utf8; unsigned char map_notascii; unsigned char mbs_allocated; unsigned char offsets_needed; unsigned char newline_anchor; unsigned char word_ops_used; int mb_cur_max; }; typedef struct re_string_t re_string_t; struct re_dfa_t; typedef struct re_dfa_t re_dfa_t; #ifndef _LIBC # ifdef __i386__ # define internal_function __attribute ((regparm (3), stdcall)) # else # define internal_function # endif #endif #ifndef NOT_IN_libc static reg_errcode_t re_string_realloc_buffers (re_string_t *pstr, int new_buf_len) internal_function; # ifdef RE_ENABLE_I18N static void build_wcs_buffer (re_string_t *pstr) internal_function; static reg_errcode_t build_wcs_upper_buffer (re_string_t *pstr) internal_function; # endif /* RE_ENABLE_I18N */ static void build_upper_buffer (re_string_t *pstr) internal_function; static void re_string_translate_buffer (re_string_t *pstr) internal_function; static unsigned int re_string_context_at (const re_string_t *input, int idx, int eflags) internal_function __attribute ((pure)); #endif #define re_string_peek_byte(pstr, offset) \ ((pstr)->mbs[(pstr)->cur_idx + offset]) #define re_string_fetch_byte(pstr) \ ((pstr)->mbs[(pstr)->cur_idx++]) #define re_string_first_byte(pstr, idx) \ ((idx) == (pstr)->valid_len || (pstr)->wcs[idx] != WEOF) #define re_string_is_single_byte_char(pstr, idx) \ ((pstr)->wcs[idx] != WEOF && ((pstr)->valid_len == (idx) + 1 \ || (pstr)->wcs[(idx) + 1] != WEOF)) #define re_string_eoi(pstr) ((pstr)->stop <= (pstr)->cur_idx) #define re_string_cur_idx(pstr) ((pstr)->cur_idx) #define re_string_get_buffer(pstr) ((pstr)->mbs) #define re_string_length(pstr) ((pstr)->len) #define re_string_byte_at(pstr,idx) ((pstr)->mbs[idx]) #define re_string_skip_bytes(pstr,idx) ((pstr)->cur_idx += (idx)) #define re_string_set_index(pstr,idx) ((pstr)->cur_idx = (idx)) #ifndef _LIBC # if HAVE_ALLOCA # if (_MSC_VER) # include # define __libc_use_alloca(n) 0 # else # include /* The OS usually guarantees only one guard page at the bottom of the stack, and a page size can be as small as 4096 bytes. So we cannot safely allocate anything larger than 4096 bytes. Also care for the possibility of a few compiler-allocated temporary stack slots. */ # define __libc_use_alloca(n) ((n) < 4032) # endif # else /* alloca is implemented with malloc, so just use malloc. */ # define __libc_use_alloca(n) 0 # endif #endif #define re_malloc(t,n) ((t *) malloc ((n) * sizeof (t))) /* SunOS 4.1.x realloc doesn't accept null pointers: pre-Standard C. Sigh. */ #define re_realloc(p,t,n) ((p != NULL) ? (t *) realloc (p,(n)*sizeof(t)) : (t *) calloc(n,sizeof(t))) #define re_free(p) free (p) struct bin_tree_t { struct bin_tree_t *parent; struct bin_tree_t *left; struct bin_tree_t *right; struct bin_tree_t *first; struct bin_tree_t *next; re_token_t token; /* `node_idx' is the index in dfa->nodes, if `type' == 0. Otherwise `type' indicate the type of this node. */ int node_idx; }; typedef struct bin_tree_t bin_tree_t; #define BIN_TREE_STORAGE_SIZE \ ((1024 - sizeof (void *)) / sizeof (bin_tree_t)) struct bin_tree_storage_t { struct bin_tree_storage_t *next; bin_tree_t data[BIN_TREE_STORAGE_SIZE]; }; typedef struct bin_tree_storage_t bin_tree_storage_t; #define CONTEXT_WORD 1 #define CONTEXT_NEWLINE (CONTEXT_WORD << 1) #define CONTEXT_BEGBUF (CONTEXT_NEWLINE << 1) #define CONTEXT_ENDBUF (CONTEXT_BEGBUF << 1) #define IS_WORD_CONTEXT(c) ((c) & CONTEXT_WORD) #define IS_NEWLINE_CONTEXT(c) ((c) & CONTEXT_NEWLINE) #define IS_BEGBUF_CONTEXT(c) ((c) & CONTEXT_BEGBUF) #define IS_ENDBUF_CONTEXT(c) ((c) & CONTEXT_ENDBUF) #define IS_ORDINARY_CONTEXT(c) ((c) == 0) #define IS_WORD_CHAR(ch) (isalnum (ch) || (ch) == '_') #define IS_NEWLINE(ch) ((ch) == NEWLINE_CHAR) #define IS_WIDE_WORD_CHAR(ch) (iswalnum (ch) || (ch) == L'_') #define IS_WIDE_NEWLINE(ch) ((ch) == WIDE_NEWLINE_CHAR) #define NOT_SATISFY_PREV_CONSTRAINT(constraint,context) \ ((((constraint) & PREV_WORD_CONSTRAINT) && !IS_WORD_CONTEXT (context)) \ || ((constraint & PREV_NOTWORD_CONSTRAINT) && IS_WORD_CONTEXT (context)) \ || ((constraint & PREV_NEWLINE_CONSTRAINT) && !IS_NEWLINE_CONTEXT (context))\ || ((constraint & PREV_BEGBUF_CONSTRAINT) && !IS_BEGBUF_CONTEXT (context))) #define NOT_SATISFY_NEXT_CONSTRAINT(constraint,context) \ ((((constraint) & NEXT_WORD_CONSTRAINT) && !IS_WORD_CONTEXT (context)) \ || (((constraint) & NEXT_NOTWORD_CONSTRAINT) && IS_WORD_CONTEXT (context)) \ || (((constraint) & NEXT_NEWLINE_CONSTRAINT) && !IS_NEWLINE_CONTEXT (context)) \ || (((constraint) & NEXT_ENDBUF_CONSTRAINT) && !IS_ENDBUF_CONTEXT (context))) struct re_dfastate_t { unsigned int hash; re_node_set nodes; re_node_set non_eps_nodes; re_node_set inveclosure; re_node_set *entrance_nodes; struct re_dfastate_t **trtable, **word_trtable; unsigned int context : 4; unsigned int halt : 1; /* If this state can accept `multi byte'. Note that we refer to multibyte characters, and multi character collating elements as `multi byte'. */ unsigned int accept_mb : 1; /* If this state has backreference node(s). */ unsigned int has_backref : 1; unsigned int has_constraint : 1; }; typedef struct re_dfastate_t re_dfastate_t; struct re_state_table_entry { int num; int alloc; re_dfastate_t **array; }; /* Array type used in re_sub_match_last_t and re_sub_match_top_t. */ typedef struct { int next_idx; int alloc; re_dfastate_t **array; } state_array_t; /* Store information about the node NODE whose type is OP_CLOSE_SUBEXP. */ typedef struct { int node; int str_idx; /* The position NODE match at. */ state_array_t path; } re_sub_match_last_t; /* Store information about the node NODE whose type is OP_OPEN_SUBEXP. And information about the node, whose type is OP_CLOSE_SUBEXP, corresponding to NODE is stored in LASTS. */ typedef struct { int str_idx; int node; state_array_t *path; int alasts; /* Allocation size of LASTS. */ int nlasts; /* The number of LASTS. */ re_sub_match_last_t **lasts; } re_sub_match_top_t; struct re_backref_cache_entry { int node; int str_idx; int subexp_from; int subexp_to; char more; char unused; unsigned short int eps_reachable_subexps_map; }; typedef struct { /* The string object corresponding to the input string. */ re_string_t input; #if defined _LIBC || (defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L) const re_dfa_t *const dfa; #else const re_dfa_t *dfa; #endif /* EFLAGS of the argument of regexec. */ int eflags; /* Where the matching ends. */ int match_last; int last_node; /* The state log used by the matcher. */ re_dfastate_t **state_log; int state_log_top; /* Back reference cache. */ int nbkref_ents; int abkref_ents; struct re_backref_cache_entry *bkref_ents; int max_mb_elem_len; int nsub_tops; int asub_tops; re_sub_match_top_t **sub_tops; } re_match_context_t; typedef struct { re_dfastate_t **sifted_states; re_dfastate_t **limited_states; int last_node; int last_str_idx; re_node_set limits; } re_sift_context_t; struct re_fail_stack_ent_t { int idx; int node; regmatch_t *regs; re_node_set eps_via_nodes; }; struct re_fail_stack_t { int num; int alloc; struct re_fail_stack_ent_t *stack; }; struct re_dfa_t { re_token_t *nodes; size_t nodes_alloc; size_t nodes_len; int *nexts; int *org_indices; re_node_set *edests; re_node_set *eclosures; re_node_set *inveclosures; struct re_state_table_entry *state_table; re_dfastate_t *init_state; re_dfastate_t *init_state_word; re_dfastate_t *init_state_nl; re_dfastate_t *init_state_begbuf; bin_tree_t *str_tree; bin_tree_storage_t *str_tree_storage; re_bitset_ptr_t sb_char; int str_tree_storage_idx; /* number of subexpressions `re_nsub' is in regex_t. */ unsigned int state_hash_mask; int init_node; int nbackref; /* The number of backreference in this dfa. */ /* Bitmap expressing which backreference is used. */ bitset_word_t used_bkref_map; bitset_word_t completed_bkref_map; unsigned int has_plural_match : 1; /* If this dfa has "multibyte node", which is a backreference or a node which can accept multibyte character or multi character collating element. */ unsigned int has_mb_node : 1; unsigned int is_utf8 : 1; unsigned int map_notascii : 1; unsigned int word_ops_used : 1; int mb_cur_max; bitset_t word_char; reg_syntax_t syntax; int *subexp_map; #ifdef DEBUG char* re_str; #endif #if defined _LIBC __libc_lock_define (, lock) #endif }; #define re_node_set_init_empty(set) memset (set, '\0', sizeof (re_node_set)) #define re_node_set_remove(set,id) \ (re_node_set_remove_at (set, re_node_set_contains (set, id) - 1)) #define re_node_set_empty(p) ((p)->nelem = 0) #define re_node_set_free(set) re_free ((set)->elems) typedef enum { SB_CHAR, MB_CHAR, EQUIV_CLASS, COLL_SYM, CHAR_CLASS } bracket_elem_type; typedef struct { bracket_elem_type type; union { unsigned char ch; unsigned char *name; wchar_t wch; } opr; } bracket_elem_t; /* Inline functions for bitset operation. */ static inline void bitset_not (bitset_t set) { int bitset_i; for (bitset_i = 0; bitset_i < BITSET_WORDS; ++bitset_i) set[bitset_i] = ~set[bitset_i]; } static inline void bitset_merge (bitset_t dest, const bitset_t src) { int bitset_i; for (bitset_i = 0; bitset_i < BITSET_WORDS; ++bitset_i) dest[bitset_i] |= src[bitset_i]; } static inline void bitset_mask (bitset_t dest, const bitset_t src) { int bitset_i; for (bitset_i = 0; bitset_i < BITSET_WORDS; ++bitset_i) dest[bitset_i] &= src[bitset_i]; } #ifdef RE_ENABLE_I18N /* Inline functions for re_string. */ static inline int internal_function __attribute ((pure)) re_string_char_size_at (const re_string_t *pstr, int idx) { int byte_idx; if (pstr->mb_cur_max == 1) return 1; for (byte_idx = 1; idx + byte_idx < pstr->valid_len; ++byte_idx) if (pstr->wcs[idx + byte_idx] != WEOF) break; return byte_idx; } static inline wint_t internal_function __attribute ((pure)) re_string_wchar_at (const re_string_t *pstr, int idx) { if (pstr->mb_cur_max == 1) return (wint_t) pstr->mbs[idx]; return (wint_t) pstr->wcs[idx]; } # ifndef NOT_IN_libc static int internal_function __attribute ((pure)) re_string_elem_size_at (const re_string_t *pstr, int idx) { # ifdef _LIBC const unsigned char *p, *extra; const int32_t *table, *indirect; int32_t tmp; # include uint_fast32_t nrules = _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES); if (nrules != 0) { table = (const int32_t *) _NL_CURRENT (LC_COLLATE, _NL_COLLATE_TABLEMB); extra = (const unsigned char *) _NL_CURRENT (LC_COLLATE, _NL_COLLATE_EXTRAMB); indirect = (const int32_t *) _NL_CURRENT (LC_COLLATE, _NL_COLLATE_INDIRECTMB); p = pstr->mbs + idx; tmp = findidx (&p); return p - pstr->mbs - idx; } else # endif /* _LIBC */ return 1; } # endif #endif /* RE_ENABLE_I18N */ #endif /* _REGEX_INTERNAL_H */ libgit2-0.19.0/deps/regex/regexec.c000066400000000000000000003727561216214232500170120ustar00rootroot00000000000000/* Extended regular expression matching and search library. Copyright (C) 2002-2005, 2007, 2009, 2010 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Isamu Hasegawa . The GNU C Library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. The GNU C Library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with the GNU C Library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ static reg_errcode_t match_ctx_init (re_match_context_t *cache, int eflags, int n) internal_function; static void match_ctx_clean (re_match_context_t *mctx) internal_function; static void match_ctx_free (re_match_context_t *cache) internal_function; static reg_errcode_t match_ctx_add_entry (re_match_context_t *cache, int node, int str_idx, int from, int to) internal_function; static int search_cur_bkref_entry (const re_match_context_t *mctx, int str_idx) internal_function; static reg_errcode_t match_ctx_add_subtop (re_match_context_t *mctx, int node, int str_idx) internal_function; static re_sub_match_last_t * match_ctx_add_sublast (re_sub_match_top_t *subtop, int node, int str_idx) internal_function; static void sift_ctx_init (re_sift_context_t *sctx, re_dfastate_t **sifted_sts, re_dfastate_t **limited_sts, int last_node, int last_str_idx) internal_function; static reg_errcode_t re_search_internal (const regex_t *preg, const char *string, int length, int start, int range, int stop, size_t nmatch, regmatch_t pmatch[], int eflags); static int re_search_2_stub (struct re_pattern_buffer *bufp, const char *string1, int length1, const char *string2, int length2, int start, int range, struct re_registers *regs, int stop, int ret_len); static int re_search_stub (struct re_pattern_buffer *bufp, const char *string, int length, int start, int range, int stop, struct re_registers *regs, int ret_len); static unsigned re_copy_regs (struct re_registers *regs, regmatch_t *pmatch, unsigned int nregs, int regs_allocated); static reg_errcode_t prune_impossible_nodes (re_match_context_t *mctx); static int check_matching (re_match_context_t *mctx, int fl_longest_match, int *p_match_first) internal_function; static int check_halt_state_context (const re_match_context_t *mctx, const re_dfastate_t *state, int idx) internal_function; static void update_regs (const re_dfa_t *dfa, regmatch_t *pmatch, regmatch_t *prev_idx_match, int cur_node, int cur_idx, int nmatch) internal_function; static reg_errcode_t push_fail_stack (struct re_fail_stack_t *fs, int str_idx, int dest_node, int nregs, regmatch_t *regs, re_node_set *eps_via_nodes) internal_function; static reg_errcode_t set_regs (const regex_t *preg, const re_match_context_t *mctx, size_t nmatch, regmatch_t *pmatch, int fl_backtrack) internal_function; static reg_errcode_t free_fail_stack_return (struct re_fail_stack_t *fs) internal_function; #ifdef RE_ENABLE_I18N static int sift_states_iter_mb (const re_match_context_t *mctx, re_sift_context_t *sctx, int node_idx, int str_idx, int max_str_idx) internal_function; #endif /* RE_ENABLE_I18N */ static reg_errcode_t sift_states_backward (const re_match_context_t *mctx, re_sift_context_t *sctx) internal_function; static reg_errcode_t build_sifted_states (const re_match_context_t *mctx, re_sift_context_t *sctx, int str_idx, re_node_set *cur_dest) internal_function; static reg_errcode_t update_cur_sifted_state (const re_match_context_t *mctx, re_sift_context_t *sctx, int str_idx, re_node_set *dest_nodes) internal_function; static reg_errcode_t add_epsilon_src_nodes (const re_dfa_t *dfa, re_node_set *dest_nodes, const re_node_set *candidates) internal_function; static int check_dst_limits (const re_match_context_t *mctx, re_node_set *limits, int dst_node, int dst_idx, int src_node, int src_idx) internal_function; static int check_dst_limits_calc_pos_1 (const re_match_context_t *mctx, int boundaries, int subexp_idx, int from_node, int bkref_idx) internal_function; static int check_dst_limits_calc_pos (const re_match_context_t *mctx, int limit, int subexp_idx, int node, int str_idx, int bkref_idx) internal_function; static reg_errcode_t check_subexp_limits (const re_dfa_t *dfa, re_node_set *dest_nodes, const re_node_set *candidates, re_node_set *limits, struct re_backref_cache_entry *bkref_ents, int str_idx) internal_function; static reg_errcode_t sift_states_bkref (const re_match_context_t *mctx, re_sift_context_t *sctx, int str_idx, const re_node_set *candidates) internal_function; static reg_errcode_t merge_state_array (const re_dfa_t *dfa, re_dfastate_t **dst, re_dfastate_t **src, int num) internal_function; static re_dfastate_t *find_recover_state (reg_errcode_t *err, re_match_context_t *mctx) internal_function; static re_dfastate_t *transit_state (reg_errcode_t *err, re_match_context_t *mctx, re_dfastate_t *state) internal_function; static re_dfastate_t *merge_state_with_log (reg_errcode_t *err, re_match_context_t *mctx, re_dfastate_t *next_state) internal_function; static reg_errcode_t check_subexp_matching_top (re_match_context_t *mctx, re_node_set *cur_nodes, int str_idx) internal_function; #if 0 static re_dfastate_t *transit_state_sb (reg_errcode_t *err, re_match_context_t *mctx, re_dfastate_t *pstate) internal_function; #endif #ifdef RE_ENABLE_I18N static reg_errcode_t transit_state_mb (re_match_context_t *mctx, re_dfastate_t *pstate) internal_function; #endif /* RE_ENABLE_I18N */ static reg_errcode_t transit_state_bkref (re_match_context_t *mctx, const re_node_set *nodes) internal_function; static reg_errcode_t get_subexp (re_match_context_t *mctx, int bkref_node, int bkref_str_idx) internal_function; static reg_errcode_t get_subexp_sub (re_match_context_t *mctx, const re_sub_match_top_t *sub_top, re_sub_match_last_t *sub_last, int bkref_node, int bkref_str) internal_function; static int find_subexp_node (const re_dfa_t *dfa, const re_node_set *nodes, int subexp_idx, int type) internal_function; static reg_errcode_t check_arrival (re_match_context_t *mctx, state_array_t *path, int top_node, int top_str, int last_node, int last_str, int type) internal_function; static reg_errcode_t check_arrival_add_next_nodes (re_match_context_t *mctx, int str_idx, re_node_set *cur_nodes, re_node_set *next_nodes) internal_function; static reg_errcode_t check_arrival_expand_ecl (const re_dfa_t *dfa, re_node_set *cur_nodes, int ex_subexp, int type) internal_function; static reg_errcode_t check_arrival_expand_ecl_sub (const re_dfa_t *dfa, re_node_set *dst_nodes, int target, int ex_subexp, int type) internal_function; static reg_errcode_t expand_bkref_cache (re_match_context_t *mctx, re_node_set *cur_nodes, int cur_str, int subexp_num, int type) internal_function; static int build_trtable (const re_dfa_t *dfa, re_dfastate_t *state) internal_function; #ifdef RE_ENABLE_I18N static int check_node_accept_bytes (const re_dfa_t *dfa, int node_idx, const re_string_t *input, int idx) internal_function; # ifdef _LIBC static unsigned int find_collation_sequence_value (const unsigned char *mbs, size_t name_len) internal_function; # endif /* _LIBC */ #endif /* RE_ENABLE_I18N */ static int group_nodes_into_DFAstates (const re_dfa_t *dfa, const re_dfastate_t *state, re_node_set *states_node, bitset_t *states_ch) internal_function; static int check_node_accept (const re_match_context_t *mctx, const re_token_t *node, int idx) internal_function; static reg_errcode_t extend_buffers (re_match_context_t *mctx) internal_function; /* Entry point for POSIX code. */ /* regexec searches for a given pattern, specified by PREG, in the string STRING. If NMATCH is zero or REG_NOSUB was set in the cflags argument to `regcomp', we ignore PMATCH. Otherwise, we assume PMATCH has at least NMATCH elements, and we set them to the offsets of the corresponding matched substrings. EFLAGS specifies `execution flags' which affect matching: if REG_NOTBOL is set, then ^ does not match at the beginning of the string; if REG_NOTEOL is set, then $ does not match at the end. We return 0 if we find a match and REG_NOMATCH if not. */ int regexec ( const regex_t *__restrict preg, const char *__restrict string, size_t nmatch, regmatch_t pmatch[], int eflags) { reg_errcode_t err; int start, length; if (eflags & ~(REG_NOTBOL | REG_NOTEOL | REG_STARTEND)) return REG_BADPAT; if (eflags & REG_STARTEND) { start = pmatch[0].rm_so; length = pmatch[0].rm_eo; } else { start = 0; length = strlen (string); } __libc_lock_lock (dfa->lock); if (preg->no_sub) err = re_search_internal (preg, string, length, start, length - start, length, 0, NULL, eflags); else err = re_search_internal (preg, string, length, start, length - start, length, nmatch, pmatch, eflags); __libc_lock_unlock (dfa->lock); return err != REG_NOERROR; } #ifdef _LIBC # include versioned_symbol (libc, __regexec, regexec, GLIBC_2_3_4); # if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_3_4) __typeof__ (__regexec) __compat_regexec; int attribute_compat_text_section __compat_regexec (const regex_t *__restrict preg, const char *__restrict string, size_t nmatch, regmatch_t pmatch[], int eflags) { return regexec (preg, string, nmatch, pmatch, eflags & (REG_NOTBOL | REG_NOTEOL)); } compat_symbol (libc, __compat_regexec, regexec, GLIBC_2_0); # endif #endif /* Entry points for GNU code. */ /* re_match, re_search, re_match_2, re_search_2 The former two functions operate on STRING with length LENGTH, while the later two operate on concatenation of STRING1 and STRING2 with lengths LENGTH1 and LENGTH2, respectively. re_match() matches the compiled pattern in BUFP against the string, starting at index START. re_search() first tries matching at index START, then it tries to match starting from index START + 1, and so on. The last start position tried is START + RANGE. (Thus RANGE = 0 forces re_search to operate the same way as re_match().) The parameter STOP of re_{match,search}_2 specifies that no match exceeding the first STOP characters of the concatenation of the strings should be concerned. If REGS is not NULL, and BUFP->no_sub is not set, the offsets of the match and all groups is stroed in REGS. (For the "_2" variants, the offsets are computed relative to the concatenation, not relative to the individual strings.) On success, re_match* functions return the length of the match, re_search* return the position of the start of the match. Return value -1 means no match was found and -2 indicates an internal error. */ int re_match (struct re_pattern_buffer *bufp, const char *string, int length, int start, struct re_registers *regs) { return re_search_stub (bufp, string, length, start, 0, length, regs, 1); } #ifdef _LIBC weak_alias (__re_match, re_match) #endif int re_search (struct re_pattern_buffer *bufp, const char *string, int length, int start, int range, struct re_registers *regs) { return re_search_stub (bufp, string, length, start, range, length, regs, 0); } #ifdef _LIBC weak_alias (__re_search, re_search) #endif int re_match_2 (struct re_pattern_buffer *bufp, const char *string1, int length1, const char *string2, int length2, int start, struct re_registers *regs, int stop) { return re_search_2_stub (bufp, string1, length1, string2, length2, start, 0, regs, stop, 1); } #ifdef _LIBC weak_alias (__re_match_2, re_match_2) #endif int re_search_2 (struct re_pattern_buffer *bufp, const char *string1, int length1, const char *string2, int length2, int start, int range, struct re_registers *regs, int stop) { return re_search_2_stub (bufp, string1, length1, string2, length2, start, range, regs, stop, 0); } #ifdef _LIBC weak_alias (__re_search_2, re_search_2) #endif static int re_search_2_stub (struct re_pattern_buffer *bufp, const char *string1, int length1, const char *string2, int length2, int start, int range, struct re_registers *regs, int stop, int ret_len) { const char *str; int rval; int len = length1 + length2; int free_str = 0; if (BE (length1 < 0 || length2 < 0 || stop < 0, 0)) return -2; /* Concatenate the strings. */ if (length2 > 0) if (length1 > 0) { char *s = re_malloc (char, len); if (BE (s == NULL, 0)) return -2; memcpy (s, string1, length1); memcpy (s + length1, string2, length2); str = s; free_str = 1; } else str = string2; else str = string1; rval = re_search_stub (bufp, str, len, start, range, stop, regs, ret_len); if (free_str) re_free ((char *) str); return rval; } /* The parameters have the same meaning as those of re_search. Additional parameters: If RET_LEN is nonzero the length of the match is returned (re_match style); otherwise the position of the match is returned. */ static int re_search_stub (struct re_pattern_buffer *bufp, const char *string, int length, int start, int range, int stop, struct re_registers *regs, int ret_len) { reg_errcode_t result; regmatch_t *pmatch; int nregs, rval; int eflags = 0; /* Check for out-of-range. */ if (BE (start < 0 || start > length, 0)) return -1; if (BE (start + range > length, 0)) range = length - start; else if (BE (start + range < 0, 0)) range = -start; __libc_lock_lock (dfa->lock); eflags |= (bufp->not_bol) ? REG_NOTBOL : 0; eflags |= (bufp->not_eol) ? REG_NOTEOL : 0; /* Compile fastmap if we haven't yet. */ if (range > 0 && bufp->fastmap != NULL && !bufp->fastmap_accurate) re_compile_fastmap (bufp); if (BE (bufp->no_sub, 0)) regs = NULL; /* We need at least 1 register. */ if (regs == NULL) nregs = 1; else if (BE (bufp->regs_allocated == REGS_FIXED && regs->num_regs < bufp->re_nsub + 1, 0)) { nregs = regs->num_regs; if (BE (nregs < 1, 0)) { /* Nothing can be copied to regs. */ regs = NULL; nregs = 1; } } else nregs = bufp->re_nsub + 1; pmatch = re_malloc (regmatch_t, nregs); if (BE (pmatch == NULL, 0)) { rval = -2; goto out; } result = re_search_internal (bufp, string, length, start, range, stop, nregs, pmatch, eflags); rval = 0; /* I hope we needn't fill ther regs with -1's when no match was found. */ if (result != REG_NOERROR) rval = -1; else if (regs != NULL) { /* If caller wants register contents data back, copy them. */ bufp->regs_allocated = re_copy_regs (regs, pmatch, nregs, bufp->regs_allocated); if (BE (bufp->regs_allocated == REGS_UNALLOCATED, 0)) rval = -2; } if (BE (rval == 0, 1)) { if (ret_len) { assert (pmatch[0].rm_so == start); rval = pmatch[0].rm_eo - start; } else rval = pmatch[0].rm_so; } re_free (pmatch); out: __libc_lock_unlock (dfa->lock); return rval; } static unsigned re_copy_regs (struct re_registers *regs, regmatch_t *pmatch, unsigned int nregs, int regs_allocated) { int rval = REGS_REALLOCATE; unsigned int i; unsigned int need_regs = nregs + 1; /* We need one extra element beyond `num_regs' for the `-1' marker GNU code uses. */ /* Have the register data arrays been allocated? */ if (regs_allocated == REGS_UNALLOCATED) { /* No. So allocate them with malloc. */ regs->start = re_malloc (regoff_t, need_regs); if (BE (regs->start == NULL, 0)) return REGS_UNALLOCATED; regs->end = re_malloc (regoff_t, need_regs); if (BE (regs->end == NULL, 0)) { re_free (regs->start); return REGS_UNALLOCATED; } regs->num_regs = need_regs; } else if (regs_allocated == REGS_REALLOCATE) { /* Yes. If we need more elements than were already allocated, reallocate them. If we need fewer, just leave it alone. */ if (BE (need_regs > regs->num_regs, 0)) { regoff_t *new_start = re_realloc (regs->start, regoff_t, need_regs); regoff_t *new_end; if (BE (new_start == NULL, 0)) return REGS_UNALLOCATED; new_end = re_realloc (regs->end, regoff_t, need_regs); if (BE (new_end == NULL, 0)) { re_free (new_start); return REGS_UNALLOCATED; } regs->start = new_start; regs->end = new_end; regs->num_regs = need_regs; } } else { assert (regs_allocated == REGS_FIXED); /* This function may not be called with REGS_FIXED and nregs too big. */ assert (regs->num_regs >= nregs); rval = REGS_FIXED; } /* Copy the regs. */ for (i = 0; i < nregs; ++i) { regs->start[i] = pmatch[i].rm_so; regs->end[i] = pmatch[i].rm_eo; } for ( ; i < regs->num_regs; ++i) regs->start[i] = regs->end[i] = -1; return rval; } /* Set REGS to hold NUM_REGS registers, storing them in STARTS and ENDS. Subsequent matches using PATTERN_BUFFER and REGS will use this memory for recording register information. STARTS and ENDS must be allocated using the malloc library routine, and must each be at least NUM_REGS * sizeof (regoff_t) bytes long. If NUM_REGS == 0, then subsequent matches should allocate their own register data. Unless this function is called, the first search or match using PATTERN_BUFFER will allocate its own register data, without freeing the old data. */ void re_set_registers (struct re_pattern_buffer *bufp, struct re_registers *regs, unsigned num_regs, regoff_t *starts, regoff_t *ends) { if (num_regs) { bufp->regs_allocated = REGS_REALLOCATE; regs->num_regs = num_regs; regs->start = starts; regs->end = ends; } else { bufp->regs_allocated = REGS_UNALLOCATED; regs->num_regs = 0; regs->start = regs->end = (regoff_t *) 0; } } #ifdef _LIBC weak_alias (__re_set_registers, re_set_registers) #endif /* Entry points compatible with 4.2 BSD regex library. We don't define them unless specifically requested. */ #if defined _REGEX_RE_COMP || defined _LIBC int # ifdef _LIBC weak_function # endif re_exec (s) const char *s; { return 0 == regexec (&re_comp_buf, s, 0, NULL, 0); } #endif /* _REGEX_RE_COMP */ /* Internal entry point. */ /* Searches for a compiled pattern PREG in the string STRING, whose length is LENGTH. NMATCH, PMATCH, and EFLAGS have the same mingings with regexec. START, and RANGE have the same meanings with re_search. Return REG_NOERROR if we find a match, and REG_NOMATCH if not, otherwise return the error code. Note: We assume front end functions already check ranges. (START + RANGE >= 0 && START + RANGE <= LENGTH) */ static reg_errcode_t re_search_internal (const regex_t *preg, const char *string, int length, int start, int range, int stop, size_t nmatch, regmatch_t pmatch[], int eflags) { reg_errcode_t err; const re_dfa_t *dfa = (const re_dfa_t *) preg->buffer; int left_lim, right_lim, incr; int fl_longest_match, match_first, match_kind, match_last = -1; unsigned int extra_nmatch; int sb, ch; #if defined _LIBC || (defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L) re_match_context_t mctx = { .dfa = dfa }; #else re_match_context_t mctx; #endif char *fastmap = (preg->fastmap != NULL && preg->fastmap_accurate && range && !preg->can_be_null) ? preg->fastmap : NULL; RE_TRANSLATE_TYPE t = preg->translate; #if !(defined _LIBC || (defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L)) memset (&mctx, '\0', sizeof (re_match_context_t)); mctx.dfa = dfa; #endif extra_nmatch = (nmatch > preg->re_nsub) ? nmatch - (preg->re_nsub + 1) : 0; nmatch -= extra_nmatch; /* Check if the DFA haven't been compiled. */ if (BE (preg->used == 0 || dfa->init_state == NULL || dfa->init_state_word == NULL || dfa->init_state_nl == NULL || dfa->init_state_begbuf == NULL, 0)) return REG_NOMATCH; #ifdef DEBUG /* We assume front-end functions already check them. */ assert (start + range >= 0 && start + range <= length); #endif /* If initial states with non-begbuf contexts have no elements, the regex must be anchored. If preg->newline_anchor is set, we'll never use init_state_nl, so do not check it. */ if (dfa->init_state->nodes.nelem == 0 && dfa->init_state_word->nodes.nelem == 0 && (dfa->init_state_nl->nodes.nelem == 0 || !preg->newline_anchor)) { if (start != 0 && start + range != 0) return REG_NOMATCH; start = range = 0; } /* We must check the longest matching, if nmatch > 0. */ fl_longest_match = (nmatch != 0 || dfa->nbackref); err = re_string_allocate (&mctx.input, string, length, dfa->nodes_len + 1, preg->translate, preg->syntax & RE_ICASE, dfa); if (BE (err != REG_NOERROR, 0)) goto free_return; mctx.input.stop = stop; mctx.input.raw_stop = stop; mctx.input.newline_anchor = preg->newline_anchor; err = match_ctx_init (&mctx, eflags, dfa->nbackref * 2); if (BE (err != REG_NOERROR, 0)) goto free_return; /* We will log all the DFA states through which the dfa pass, if nmatch > 1, or this dfa has "multibyte node", which is a back-reference or a node which can accept multibyte character or multi character collating element. */ if (nmatch > 1 || dfa->has_mb_node) { /* Avoid overflow. */ if (BE (SIZE_MAX / sizeof (re_dfastate_t *) <= (size_t)mctx.input.bufs_len, 0)) { err = REG_ESPACE; goto free_return; } mctx.state_log = re_malloc (re_dfastate_t *, mctx.input.bufs_len + 1); if (BE (mctx.state_log == NULL, 0)) { err = REG_ESPACE; goto free_return; } } else mctx.state_log = NULL; match_first = start; mctx.input.tip_context = (eflags & REG_NOTBOL) ? CONTEXT_BEGBUF : CONTEXT_NEWLINE | CONTEXT_BEGBUF; /* Check incrementally whether of not the input string match. */ incr = (range < 0) ? -1 : 1; left_lim = (range < 0) ? start + range : start; right_lim = (range < 0) ? start : start + range; sb = dfa->mb_cur_max == 1; match_kind = (fastmap ? ((sb || !(preg->syntax & RE_ICASE || t) ? 4 : 0) | (range >= 0 ? 2 : 0) | (t != NULL ? 1 : 0)) : 8); for (;; match_first += incr) { err = REG_NOMATCH; if (match_first < left_lim || right_lim < match_first) goto free_return; /* Advance as rapidly as possible through the string, until we find a plausible place to start matching. This may be done with varying efficiency, so there are various possibilities: only the most common of them are specialized, in order to save on code size. We use a switch statement for speed. */ switch (match_kind) { case 8: /* No fastmap. */ break; case 7: /* Fastmap with single-byte translation, match forward. */ while (BE (match_first < right_lim, 1) && !fastmap[t[(unsigned char) string[match_first]]]) ++match_first; goto forward_match_found_start_or_reached_end; case 6: /* Fastmap without translation, match forward. */ while (BE (match_first < right_lim, 1) && !fastmap[(unsigned char) string[match_first]]) ++match_first; forward_match_found_start_or_reached_end: if (BE (match_first == right_lim, 0)) { ch = match_first >= length ? 0 : (unsigned char) string[match_first]; if (!fastmap[t ? t[ch] : ch]) goto free_return; } break; case 4: case 5: /* Fastmap without multi-byte translation, match backwards. */ while (match_first >= left_lim) { ch = match_first >= length ? 0 : (unsigned char) string[match_first]; if (fastmap[t ? t[ch] : ch]) break; --match_first; } if (match_first < left_lim) goto free_return; break; default: /* In this case, we can't determine easily the current byte, since it might be a component byte of a multibyte character. Then we use the constructed buffer instead. */ for (;;) { /* If MATCH_FIRST is out of the valid range, reconstruct the buffers. */ unsigned int offset = match_first - mctx.input.raw_mbs_idx; if (BE (offset >= (unsigned int) mctx.input.valid_raw_len, 0)) { err = re_string_reconstruct (&mctx.input, match_first, eflags); if (BE (err != REG_NOERROR, 0)) goto free_return; offset = match_first - mctx.input.raw_mbs_idx; } /* If MATCH_FIRST is out of the buffer, leave it as '\0'. Note that MATCH_FIRST must not be smaller than 0. */ ch = (match_first >= length ? 0 : re_string_byte_at (&mctx.input, offset)); if (fastmap[ch]) break; match_first += incr; if (match_first < left_lim || match_first > right_lim) { err = REG_NOMATCH; goto free_return; } } break; } /* Reconstruct the buffers so that the matcher can assume that the matching starts from the beginning of the buffer. */ err = re_string_reconstruct (&mctx.input, match_first, eflags); if (BE (err != REG_NOERROR, 0)) goto free_return; #ifdef RE_ENABLE_I18N /* Don't consider this char as a possible match start if it part, yet isn't the head, of a multibyte character. */ if (!sb && !re_string_first_byte (&mctx.input, 0)) continue; #endif /* It seems to be appropriate one, then use the matcher. */ /* We assume that the matching starts from 0. */ mctx.state_log_top = mctx.nbkref_ents = mctx.max_mb_elem_len = 0; match_last = check_matching (&mctx, fl_longest_match, range >= 0 ? &match_first : NULL); if (match_last != -1) { if (BE (match_last == -2, 0)) { err = REG_ESPACE; goto free_return; } else { mctx.match_last = match_last; if ((!preg->no_sub && nmatch > 1) || dfa->nbackref) { re_dfastate_t *pstate = mctx.state_log[match_last]; mctx.last_node = check_halt_state_context (&mctx, pstate, match_last); } if ((!preg->no_sub && nmatch > 1 && dfa->has_plural_match) || dfa->nbackref) { err = prune_impossible_nodes (&mctx); if (err == REG_NOERROR) break; if (BE (err != REG_NOMATCH, 0)) goto free_return; match_last = -1; } else break; /* We found a match. */ } } match_ctx_clean (&mctx); } #ifdef DEBUG assert (match_last != -1); assert (err == REG_NOERROR); #endif /* Set pmatch[] if we need. */ if (nmatch > 0) { unsigned int reg_idx; /* Initialize registers. */ for (reg_idx = 1; reg_idx < nmatch; ++reg_idx) pmatch[reg_idx].rm_so = pmatch[reg_idx].rm_eo = -1; /* Set the points where matching start/end. */ pmatch[0].rm_so = 0; pmatch[0].rm_eo = mctx.match_last; if (!preg->no_sub && nmatch > 1) { err = set_regs (preg, &mctx, nmatch, pmatch, dfa->has_plural_match && dfa->nbackref > 0); if (BE (err != REG_NOERROR, 0)) goto free_return; } /* At last, add the offset to the each registers, since we slided the buffers so that we could assume that the matching starts from 0. */ for (reg_idx = 0; reg_idx < nmatch; ++reg_idx) if (pmatch[reg_idx].rm_so != -1) { #ifdef RE_ENABLE_I18N if (BE (mctx.input.offsets_needed != 0, 0)) { pmatch[reg_idx].rm_so = (pmatch[reg_idx].rm_so == mctx.input.valid_len ? mctx.input.valid_raw_len : mctx.input.offsets[pmatch[reg_idx].rm_so]); pmatch[reg_idx].rm_eo = (pmatch[reg_idx].rm_eo == mctx.input.valid_len ? mctx.input.valid_raw_len : mctx.input.offsets[pmatch[reg_idx].rm_eo]); } #else assert (mctx.input.offsets_needed == 0); #endif pmatch[reg_idx].rm_so += match_first; pmatch[reg_idx].rm_eo += match_first; } for (reg_idx = 0; reg_idx < extra_nmatch; ++reg_idx) { pmatch[nmatch + reg_idx].rm_so = -1; pmatch[nmatch + reg_idx].rm_eo = -1; } if (dfa->subexp_map) for (reg_idx = 0; reg_idx + 1 < nmatch; reg_idx++) if (dfa->subexp_map[reg_idx] != (int)reg_idx) { pmatch[reg_idx + 1].rm_so = pmatch[dfa->subexp_map[reg_idx] + 1].rm_so; pmatch[reg_idx + 1].rm_eo = pmatch[dfa->subexp_map[reg_idx] + 1].rm_eo; } } free_return: re_free (mctx.state_log); if (dfa->nbackref) match_ctx_free (&mctx); re_string_destruct (&mctx.input); return err; } static reg_errcode_t prune_impossible_nodes (re_match_context_t *mctx) { const re_dfa_t *const dfa = mctx->dfa; int halt_node, match_last; reg_errcode_t ret; re_dfastate_t **sifted_states; re_dfastate_t **lim_states = NULL; re_sift_context_t sctx; #ifdef DEBUG assert (mctx->state_log != NULL); #endif match_last = mctx->match_last; halt_node = mctx->last_node; /* Avoid overflow. */ if (BE (SIZE_MAX / sizeof (re_dfastate_t *) <= (size_t)match_last, 0)) return REG_ESPACE; sifted_states = re_malloc (re_dfastate_t *, match_last + 1); if (BE (sifted_states == NULL, 0)) { ret = REG_ESPACE; goto free_return; } if (dfa->nbackref) { lim_states = re_malloc (re_dfastate_t *, match_last + 1); if (BE (lim_states == NULL, 0)) { ret = REG_ESPACE; goto free_return; } while (1) { memset (lim_states, '\0', sizeof (re_dfastate_t *) * (match_last + 1)); sift_ctx_init (&sctx, sifted_states, lim_states, halt_node, match_last); ret = sift_states_backward (mctx, &sctx); re_node_set_free (&sctx.limits); if (BE (ret != REG_NOERROR, 0)) goto free_return; if (sifted_states[0] != NULL || lim_states[0] != NULL) break; do { --match_last; if (match_last < 0) { ret = REG_NOMATCH; goto free_return; } } while (mctx->state_log[match_last] == NULL || !mctx->state_log[match_last]->halt); halt_node = check_halt_state_context (mctx, mctx->state_log[match_last], match_last); } ret = merge_state_array (dfa, sifted_states, lim_states, match_last + 1); re_free (lim_states); lim_states = NULL; if (BE (ret != REG_NOERROR, 0)) goto free_return; } else { sift_ctx_init (&sctx, sifted_states, lim_states, halt_node, match_last); ret = sift_states_backward (mctx, &sctx); re_node_set_free (&sctx.limits); if (BE (ret != REG_NOERROR, 0)) goto free_return; if (sifted_states[0] == NULL) { ret = REG_NOMATCH; goto free_return; } } re_free (mctx->state_log); mctx->state_log = sifted_states; sifted_states = NULL; mctx->last_node = halt_node; mctx->match_last = match_last; ret = REG_NOERROR; free_return: re_free (sifted_states); re_free (lim_states); return ret; } /* Acquire an initial state and return it. We must select appropriate initial state depending on the context, since initial states may have constraints like "\<", "^", etc.. */ static inline re_dfastate_t * __attribute ((always_inline)) internal_function acquire_init_state_context (reg_errcode_t *err, const re_match_context_t *mctx, int idx) { const re_dfa_t *const dfa = mctx->dfa; if (dfa->init_state->has_constraint) { unsigned int context; context = re_string_context_at (&mctx->input, idx - 1, mctx->eflags); if (IS_WORD_CONTEXT (context)) return dfa->init_state_word; else if (IS_ORDINARY_CONTEXT (context)) return dfa->init_state; else if (IS_BEGBUF_CONTEXT (context) && IS_NEWLINE_CONTEXT (context)) return dfa->init_state_begbuf; else if (IS_NEWLINE_CONTEXT (context)) return dfa->init_state_nl; else if (IS_BEGBUF_CONTEXT (context)) { /* It is relatively rare case, then calculate on demand. */ return re_acquire_state_context (err, dfa, dfa->init_state->entrance_nodes, context); } else /* Must not happen? */ return dfa->init_state; } else return dfa->init_state; } /* Check whether the regular expression match input string INPUT or not, and return the index where the matching end, return -1 if not match, or return -2 in case of an error. FL_LONGEST_MATCH means we want the POSIX longest matching. If P_MATCH_FIRST is not NULL, and the match fails, it is set to the next place where we may want to try matching. Note that the matcher assume that the maching starts from the current index of the buffer. */ static int internal_function check_matching (re_match_context_t *mctx, int fl_longest_match, int *p_match_first) { const re_dfa_t *const dfa = mctx->dfa; reg_errcode_t err; int match = 0; int match_last = -1; int cur_str_idx = re_string_cur_idx (&mctx->input); re_dfastate_t *cur_state; int at_init_state = p_match_first != NULL; int next_start_idx = cur_str_idx; err = REG_NOERROR; cur_state = acquire_init_state_context (&err, mctx, cur_str_idx); /* An initial state must not be NULL (invalid). */ if (BE (cur_state == NULL, 0)) { assert (err == REG_ESPACE); return -2; } if (mctx->state_log != NULL) { mctx->state_log[cur_str_idx] = cur_state; /* Check OP_OPEN_SUBEXP in the initial state in case that we use them later. E.g. Processing back references. */ if (BE (dfa->nbackref, 0)) { at_init_state = 0; err = check_subexp_matching_top (mctx, &cur_state->nodes, 0); if (BE (err != REG_NOERROR, 0)) return err; if (cur_state->has_backref) { err = transit_state_bkref (mctx, &cur_state->nodes); if (BE (err != REG_NOERROR, 0)) return err; } } } /* If the RE accepts NULL string. */ if (BE (cur_state->halt, 0)) { if (!cur_state->has_constraint || check_halt_state_context (mctx, cur_state, cur_str_idx)) { if (!fl_longest_match) return cur_str_idx; else { match_last = cur_str_idx; match = 1; } } } while (!re_string_eoi (&mctx->input)) { re_dfastate_t *old_state = cur_state; int next_char_idx = re_string_cur_idx (&mctx->input) + 1; if (BE (next_char_idx >= mctx->input.bufs_len, 0) || (BE (next_char_idx >= mctx->input.valid_len, 0) && mctx->input.valid_len < mctx->input.len)) { err = extend_buffers (mctx); if (BE (err != REG_NOERROR, 0)) { assert (err == REG_ESPACE); return -2; } } cur_state = transit_state (&err, mctx, cur_state); if (mctx->state_log != NULL) cur_state = merge_state_with_log (&err, mctx, cur_state); if (cur_state == NULL) { /* Reached the invalid state or an error. Try to recover a valid state using the state log, if available and if we have not already found a valid (even if not the longest) match. */ if (BE (err != REG_NOERROR, 0)) return -2; if (mctx->state_log == NULL || (match && !fl_longest_match) || (cur_state = find_recover_state (&err, mctx)) == NULL) break; } if (BE (at_init_state, 0)) { if (old_state == cur_state) next_start_idx = next_char_idx; else at_init_state = 0; } if (cur_state->halt) { /* Reached a halt state. Check the halt state can satisfy the current context. */ if (!cur_state->has_constraint || check_halt_state_context (mctx, cur_state, re_string_cur_idx (&mctx->input))) { /* We found an appropriate halt state. */ match_last = re_string_cur_idx (&mctx->input); match = 1; /* We found a match, do not modify match_first below. */ p_match_first = NULL; if (!fl_longest_match) break; } } } if (p_match_first) *p_match_first += next_start_idx; return match_last; } /* Check NODE match the current context. */ static int internal_function check_halt_node_context (const re_dfa_t *dfa, int node, unsigned int context) { re_token_type_t type = dfa->nodes[node].type; unsigned int constraint = dfa->nodes[node].constraint; if (type != END_OF_RE) return 0; if (!constraint) return 1; if (NOT_SATISFY_NEXT_CONSTRAINT (constraint, context)) return 0; return 1; } /* Check the halt state STATE match the current context. Return 0 if not match, if the node, STATE has, is a halt node and match the context, return the node. */ static int internal_function check_halt_state_context (const re_match_context_t *mctx, const re_dfastate_t *state, int idx) { int i; unsigned int context; #ifdef DEBUG assert (state->halt); #endif context = re_string_context_at (&mctx->input, idx, mctx->eflags); for (i = 0; i < state->nodes.nelem; ++i) if (check_halt_node_context (mctx->dfa, state->nodes.elems[i], context)) return state->nodes.elems[i]; return 0; } /* Compute the next node to which "NFA" transit from NODE("NFA" is a NFA corresponding to the DFA). Return the destination node, and update EPS_VIA_NODES, return -1 in case of errors. */ static int internal_function proceed_next_node (const re_match_context_t *mctx, int nregs, regmatch_t *regs, int *pidx, int node, re_node_set *eps_via_nodes, struct re_fail_stack_t *fs) { const re_dfa_t *const dfa = mctx->dfa; int i, err; if (IS_EPSILON_NODE (dfa->nodes[node].type)) { re_node_set *cur_nodes = &mctx->state_log[*pidx]->nodes; re_node_set *edests = &dfa->edests[node]; int dest_node; err = re_node_set_insert (eps_via_nodes, node); if (BE (err < 0, 0)) return -2; /* Pick up a valid destination, or return -1 if none is found. */ for (dest_node = -1, i = 0; i < edests->nelem; ++i) { int candidate = edests->elems[i]; if (!re_node_set_contains (cur_nodes, candidate)) continue; if (dest_node == -1) dest_node = candidate; else { /* In order to avoid infinite loop like "(a*)*", return the second epsilon-transition if the first was already considered. */ if (re_node_set_contains (eps_via_nodes, dest_node)) return candidate; /* Otherwise, push the second epsilon-transition on the fail stack. */ else if (fs != NULL && push_fail_stack (fs, *pidx, candidate, nregs, regs, eps_via_nodes)) return -2; /* We know we are going to exit. */ break; } } return dest_node; } else { int naccepted = 0; re_token_type_t type = dfa->nodes[node].type; #ifdef RE_ENABLE_I18N if (dfa->nodes[node].accept_mb) naccepted = check_node_accept_bytes (dfa, node, &mctx->input, *pidx); else #endif /* RE_ENABLE_I18N */ if (type == OP_BACK_REF) { int subexp_idx = dfa->nodes[node].opr.idx + 1; naccepted = regs[subexp_idx].rm_eo - regs[subexp_idx].rm_so; if (fs != NULL) { if (regs[subexp_idx].rm_so == -1 || regs[subexp_idx].rm_eo == -1) return -1; else if (naccepted) { char *buf = (char *) re_string_get_buffer (&mctx->input); if (memcmp (buf + regs[subexp_idx].rm_so, buf + *pidx, naccepted) != 0) return -1; } } if (naccepted == 0) { int dest_node; err = re_node_set_insert (eps_via_nodes, node); if (BE (err < 0, 0)) return -2; dest_node = dfa->edests[node].elems[0]; if (re_node_set_contains (&mctx->state_log[*pidx]->nodes, dest_node)) return dest_node; } } if (naccepted != 0 || check_node_accept (mctx, dfa->nodes + node, *pidx)) { int dest_node = dfa->nexts[node]; *pidx = (naccepted == 0) ? *pidx + 1 : *pidx + naccepted; if (fs && (*pidx > mctx->match_last || mctx->state_log[*pidx] == NULL || !re_node_set_contains (&mctx->state_log[*pidx]->nodes, dest_node))) return -1; re_node_set_empty (eps_via_nodes); return dest_node; } } return -1; } static reg_errcode_t internal_function push_fail_stack (struct re_fail_stack_t *fs, int str_idx, int dest_node, int nregs, regmatch_t *regs, re_node_set *eps_via_nodes) { reg_errcode_t err; int num = fs->num++; if (fs->num == fs->alloc) { struct re_fail_stack_ent_t *new_array; new_array = realloc (fs->stack, (sizeof (struct re_fail_stack_ent_t) * fs->alloc * 2)); if (new_array == NULL) return REG_ESPACE; fs->alloc *= 2; fs->stack = new_array; } fs->stack[num].idx = str_idx; fs->stack[num].node = dest_node; fs->stack[num].regs = re_malloc (regmatch_t, nregs); if (fs->stack[num].regs == NULL) return REG_ESPACE; memcpy (fs->stack[num].regs, regs, sizeof (regmatch_t) * nregs); err = re_node_set_init_copy (&fs->stack[num].eps_via_nodes, eps_via_nodes); return err; } static int internal_function pop_fail_stack (struct re_fail_stack_t *fs, int *pidx, int nregs, regmatch_t *regs, re_node_set *eps_via_nodes) { int num = --fs->num; assert (num >= 0); *pidx = fs->stack[num].idx; memcpy (regs, fs->stack[num].regs, sizeof (regmatch_t) * nregs); re_node_set_free (eps_via_nodes); re_free (fs->stack[num].regs); *eps_via_nodes = fs->stack[num].eps_via_nodes; return fs->stack[num].node; } /* Set the positions where the subexpressions are starts/ends to registers PMATCH. Note: We assume that pmatch[0] is already set, and pmatch[i].rm_so == pmatch[i].rm_eo == -1 for 0 < i < nmatch. */ static reg_errcode_t internal_function set_regs (const regex_t *preg, const re_match_context_t *mctx, size_t nmatch, regmatch_t *pmatch, int fl_backtrack) { const re_dfa_t *dfa = (const re_dfa_t *) preg->buffer; int idx, cur_node; re_node_set eps_via_nodes; struct re_fail_stack_t *fs; struct re_fail_stack_t fs_body = { 0, 2, NULL }; regmatch_t *prev_idx_match; int prev_idx_match_malloced = 0; #ifdef DEBUG assert (nmatch > 1); assert (mctx->state_log != NULL); #endif if (fl_backtrack) { fs = &fs_body; fs->stack = re_malloc (struct re_fail_stack_ent_t, fs->alloc); if (fs->stack == NULL) return REG_ESPACE; } else fs = NULL; cur_node = dfa->init_node; re_node_set_init_empty (&eps_via_nodes); #ifdef HAVE_ALLOCA if (__libc_use_alloca (nmatch * sizeof (regmatch_t))) prev_idx_match = (regmatch_t *) alloca (nmatch * sizeof (regmatch_t)); else #endif { prev_idx_match = re_malloc (regmatch_t, nmatch); if (prev_idx_match == NULL) { free_fail_stack_return (fs); return REG_ESPACE; } prev_idx_match_malloced = 1; } memcpy (prev_idx_match, pmatch, sizeof (regmatch_t) * nmatch); for (idx = pmatch[0].rm_so; idx <= pmatch[0].rm_eo ;) { update_regs (dfa, pmatch, prev_idx_match, cur_node, idx, nmatch); if (idx == pmatch[0].rm_eo && cur_node == mctx->last_node) { unsigned int reg_idx; if (fs) { for (reg_idx = 0; reg_idx < nmatch; ++reg_idx) if (pmatch[reg_idx].rm_so > -1 && pmatch[reg_idx].rm_eo == -1) break; if (reg_idx == nmatch) { re_node_set_free (&eps_via_nodes); if (prev_idx_match_malloced) re_free (prev_idx_match); return free_fail_stack_return (fs); } cur_node = pop_fail_stack (fs, &idx, nmatch, pmatch, &eps_via_nodes); } else { re_node_set_free (&eps_via_nodes); if (prev_idx_match_malloced) re_free (prev_idx_match); return REG_NOERROR; } } /* Proceed to next node. */ cur_node = proceed_next_node (mctx, nmatch, pmatch, &idx, cur_node, &eps_via_nodes, fs); if (BE (cur_node < 0, 0)) { if (BE (cur_node == -2, 0)) { re_node_set_free (&eps_via_nodes); if (prev_idx_match_malloced) re_free (prev_idx_match); free_fail_stack_return (fs); return REG_ESPACE; } if (fs) cur_node = pop_fail_stack (fs, &idx, nmatch, pmatch, &eps_via_nodes); else { re_node_set_free (&eps_via_nodes); if (prev_idx_match_malloced) re_free (prev_idx_match); return REG_NOMATCH; } } } re_node_set_free (&eps_via_nodes); if (prev_idx_match_malloced) re_free (prev_idx_match); return free_fail_stack_return (fs); } static reg_errcode_t internal_function free_fail_stack_return (struct re_fail_stack_t *fs) { if (fs) { int fs_idx; for (fs_idx = 0; fs_idx < fs->num; ++fs_idx) { re_node_set_free (&fs->stack[fs_idx].eps_via_nodes); re_free (fs->stack[fs_idx].regs); } re_free (fs->stack); } return REG_NOERROR; } static void internal_function update_regs (const re_dfa_t *dfa, regmatch_t *pmatch, regmatch_t *prev_idx_match, int cur_node, int cur_idx, int nmatch) { int type = dfa->nodes[cur_node].type; if (type == OP_OPEN_SUBEXP) { int reg_num = dfa->nodes[cur_node].opr.idx + 1; /* We are at the first node of this sub expression. */ if (reg_num < nmatch) { pmatch[reg_num].rm_so = cur_idx; pmatch[reg_num].rm_eo = -1; } } else if (type == OP_CLOSE_SUBEXP) { int reg_num = dfa->nodes[cur_node].opr.idx + 1; if (reg_num < nmatch) { /* We are at the last node of this sub expression. */ if (pmatch[reg_num].rm_so < cur_idx) { pmatch[reg_num].rm_eo = cur_idx; /* This is a non-empty match or we are not inside an optional subexpression. Accept this right away. */ memcpy (prev_idx_match, pmatch, sizeof (regmatch_t) * nmatch); } else { if (dfa->nodes[cur_node].opt_subexp && prev_idx_match[reg_num].rm_so != -1) /* We transited through an empty match for an optional subexpression, like (a?)*, and this is not the subexp's first match. Copy back the old content of the registers so that matches of an inner subexpression are undone as well, like in ((a?))*. */ memcpy (pmatch, prev_idx_match, sizeof (regmatch_t) * nmatch); else /* We completed a subexpression, but it may be part of an optional one, so do not update PREV_IDX_MATCH. */ pmatch[reg_num].rm_eo = cur_idx; } } } } /* This function checks the STATE_LOG from the SCTX->last_str_idx to 0 and sift the nodes in each states according to the following rules. Updated state_log will be wrote to STATE_LOG. Rules: We throw away the Node `a' in the STATE_LOG[STR_IDX] if... 1. When STR_IDX == MATCH_LAST(the last index in the state_log): If `a' isn't the LAST_NODE and `a' can't epsilon transit to the LAST_NODE, we throw away the node `a'. 2. When 0 <= STR_IDX < MATCH_LAST and `a' accepts string `s' and transit to `b': i. If 'b' isn't in the STATE_LOG[STR_IDX+strlen('s')], we throw away the node `a'. ii. If 'b' is in the STATE_LOG[STR_IDX+strlen('s')] but 'b' is thrown away, we throw away the node `a'. 3. When 0 <= STR_IDX < MATCH_LAST and 'a' epsilon transit to 'b': i. If 'b' isn't in the STATE_LOG[STR_IDX], we throw away the node `a'. ii. If 'b' is in the STATE_LOG[STR_IDX] but 'b' is thrown away, we throw away the node `a'. */ #define STATE_NODE_CONTAINS(state,node) \ ((state) != NULL && re_node_set_contains (&(state)->nodes, node)) static reg_errcode_t internal_function sift_states_backward (const re_match_context_t *mctx, re_sift_context_t *sctx) { reg_errcode_t err; int null_cnt = 0; int str_idx = sctx->last_str_idx; re_node_set cur_dest; #ifdef DEBUG assert (mctx->state_log != NULL && mctx->state_log[str_idx] != NULL); #endif /* Build sifted state_log[str_idx]. It has the nodes which can epsilon transit to the last_node and the last_node itself. */ err = re_node_set_init_1 (&cur_dest, sctx->last_node); if (BE (err != REG_NOERROR, 0)) return err; err = update_cur_sifted_state (mctx, sctx, str_idx, &cur_dest); if (BE (err != REG_NOERROR, 0)) goto free_return; /* Then check each states in the state_log. */ while (str_idx > 0) { /* Update counters. */ null_cnt = (sctx->sifted_states[str_idx] == NULL) ? null_cnt + 1 : 0; if (null_cnt > mctx->max_mb_elem_len) { memset (sctx->sifted_states, '\0', sizeof (re_dfastate_t *) * str_idx); re_node_set_free (&cur_dest); return REG_NOERROR; } re_node_set_empty (&cur_dest); --str_idx; if (mctx->state_log[str_idx]) { err = build_sifted_states (mctx, sctx, str_idx, &cur_dest); if (BE (err != REG_NOERROR, 0)) goto free_return; } /* Add all the nodes which satisfy the following conditions: - It can epsilon transit to a node in CUR_DEST. - It is in CUR_SRC. And update state_log. */ err = update_cur_sifted_state (mctx, sctx, str_idx, &cur_dest); if (BE (err != REG_NOERROR, 0)) goto free_return; } err = REG_NOERROR; free_return: re_node_set_free (&cur_dest); return err; } static reg_errcode_t internal_function build_sifted_states (const re_match_context_t *mctx, re_sift_context_t *sctx, int str_idx, re_node_set *cur_dest) { const re_dfa_t *const dfa = mctx->dfa; const re_node_set *cur_src = &mctx->state_log[str_idx]->non_eps_nodes; int i; /* Then build the next sifted state. We build the next sifted state on `cur_dest', and update `sifted_states[str_idx]' with `cur_dest'. Note: `cur_dest' is the sifted state from `state_log[str_idx + 1]'. `cur_src' points the node_set of the old `state_log[str_idx]' (with the epsilon nodes pre-filtered out). */ for (i = 0; i < cur_src->nelem; i++) { int prev_node = cur_src->elems[i]; int naccepted = 0; int ret; #ifdef DEBUG re_token_type_t type = dfa->nodes[prev_node].type; assert (!IS_EPSILON_NODE (type)); #endif #ifdef RE_ENABLE_I18N /* If the node may accept `multi byte'. */ if (dfa->nodes[prev_node].accept_mb) naccepted = sift_states_iter_mb (mctx, sctx, prev_node, str_idx, sctx->last_str_idx); #endif /* RE_ENABLE_I18N */ /* We don't check backreferences here. See update_cur_sifted_state(). */ if (!naccepted && check_node_accept (mctx, dfa->nodes + prev_node, str_idx) && STATE_NODE_CONTAINS (sctx->sifted_states[str_idx + 1], dfa->nexts[prev_node])) naccepted = 1; if (naccepted == 0) continue; if (sctx->limits.nelem) { int to_idx = str_idx + naccepted; if (check_dst_limits (mctx, &sctx->limits, dfa->nexts[prev_node], to_idx, prev_node, str_idx)) continue; } ret = re_node_set_insert (cur_dest, prev_node); if (BE (ret == -1, 0)) return REG_ESPACE; } return REG_NOERROR; } /* Helper functions. */ static reg_errcode_t internal_function clean_state_log_if_needed (re_match_context_t *mctx, int next_state_log_idx) { int top = mctx->state_log_top; if (next_state_log_idx >= mctx->input.bufs_len || (next_state_log_idx >= mctx->input.valid_len && mctx->input.valid_len < mctx->input.len)) { reg_errcode_t err; err = extend_buffers (mctx); if (BE (err != REG_NOERROR, 0)) return err; } if (top < next_state_log_idx) { memset (mctx->state_log + top + 1, '\0', sizeof (re_dfastate_t *) * (next_state_log_idx - top)); mctx->state_log_top = next_state_log_idx; } return REG_NOERROR; } static reg_errcode_t internal_function merge_state_array (const re_dfa_t *dfa, re_dfastate_t **dst, re_dfastate_t **src, int num) { int st_idx; reg_errcode_t err; for (st_idx = 0; st_idx < num; ++st_idx) { if (dst[st_idx] == NULL) dst[st_idx] = src[st_idx]; else if (src[st_idx] != NULL) { re_node_set merged_set; err = re_node_set_init_union (&merged_set, &dst[st_idx]->nodes, &src[st_idx]->nodes); if (BE (err != REG_NOERROR, 0)) return err; dst[st_idx] = re_acquire_state (&err, dfa, &merged_set); re_node_set_free (&merged_set); if (BE (err != REG_NOERROR, 0)) return err; } } return REG_NOERROR; } static reg_errcode_t internal_function update_cur_sifted_state (const re_match_context_t *mctx, re_sift_context_t *sctx, int str_idx, re_node_set *dest_nodes) { const re_dfa_t *const dfa = mctx->dfa; reg_errcode_t err = REG_NOERROR; const re_node_set *candidates; candidates = ((mctx->state_log[str_idx] == NULL) ? NULL : &mctx->state_log[str_idx]->nodes); if (dest_nodes->nelem == 0) sctx->sifted_states[str_idx] = NULL; else { if (candidates) { /* At first, add the nodes which can epsilon transit to a node in DEST_NODE. */ err = add_epsilon_src_nodes (dfa, dest_nodes, candidates); if (BE (err != REG_NOERROR, 0)) return err; /* Then, check the limitations in the current sift_context. */ if (sctx->limits.nelem) { err = check_subexp_limits (dfa, dest_nodes, candidates, &sctx->limits, mctx->bkref_ents, str_idx); if (BE (err != REG_NOERROR, 0)) return err; } } sctx->sifted_states[str_idx] = re_acquire_state (&err, dfa, dest_nodes); if (BE (err != REG_NOERROR, 0)) return err; } if (candidates && mctx->state_log[str_idx]->has_backref) { err = sift_states_bkref (mctx, sctx, str_idx, candidates); if (BE (err != REG_NOERROR, 0)) return err; } return REG_NOERROR; } static reg_errcode_t internal_function add_epsilon_src_nodes (const re_dfa_t *dfa, re_node_set *dest_nodes, const re_node_set *candidates) { reg_errcode_t err = REG_NOERROR; int i; re_dfastate_t *state = re_acquire_state (&err, dfa, dest_nodes); if (BE (err != REG_NOERROR, 0)) return err; if (!state->inveclosure.alloc) { err = re_node_set_alloc (&state->inveclosure, dest_nodes->nelem); if (BE (err != REG_NOERROR, 0)) return REG_ESPACE; for (i = 0; i < dest_nodes->nelem; i++) { err = re_node_set_merge (&state->inveclosure, dfa->inveclosures + dest_nodes->elems[i]); if (BE (err != REG_NOERROR, 0)) return REG_ESPACE; } } return re_node_set_add_intersect (dest_nodes, candidates, &state->inveclosure); } static reg_errcode_t internal_function sub_epsilon_src_nodes (const re_dfa_t *dfa, int node, re_node_set *dest_nodes, const re_node_set *candidates) { int ecl_idx; reg_errcode_t err; re_node_set *inv_eclosure = dfa->inveclosures + node; re_node_set except_nodes; re_node_set_init_empty (&except_nodes); for (ecl_idx = 0; ecl_idx < inv_eclosure->nelem; ++ecl_idx) { int cur_node = inv_eclosure->elems[ecl_idx]; if (cur_node == node) continue; if (IS_EPSILON_NODE (dfa->nodes[cur_node].type)) { int edst1 = dfa->edests[cur_node].elems[0]; int edst2 = ((dfa->edests[cur_node].nelem > 1) ? dfa->edests[cur_node].elems[1] : -1); if ((!re_node_set_contains (inv_eclosure, edst1) && re_node_set_contains (dest_nodes, edst1)) || (edst2 > 0 && !re_node_set_contains (inv_eclosure, edst2) && re_node_set_contains (dest_nodes, edst2))) { err = re_node_set_add_intersect (&except_nodes, candidates, dfa->inveclosures + cur_node); if (BE (err != REG_NOERROR, 0)) { re_node_set_free (&except_nodes); return err; } } } } for (ecl_idx = 0; ecl_idx < inv_eclosure->nelem; ++ecl_idx) { int cur_node = inv_eclosure->elems[ecl_idx]; if (!re_node_set_contains (&except_nodes, cur_node)) { int idx = re_node_set_contains (dest_nodes, cur_node) - 1; re_node_set_remove_at (dest_nodes, idx); } } re_node_set_free (&except_nodes); return REG_NOERROR; } static int internal_function check_dst_limits (const re_match_context_t *mctx, re_node_set *limits, int dst_node, int dst_idx, int src_node, int src_idx) { const re_dfa_t *const dfa = mctx->dfa; int lim_idx, src_pos, dst_pos; int dst_bkref_idx = search_cur_bkref_entry (mctx, dst_idx); int src_bkref_idx = search_cur_bkref_entry (mctx, src_idx); for (lim_idx = 0; lim_idx < limits->nelem; ++lim_idx) { int subexp_idx; struct re_backref_cache_entry *ent; ent = mctx->bkref_ents + limits->elems[lim_idx]; subexp_idx = dfa->nodes[ent->node].opr.idx; dst_pos = check_dst_limits_calc_pos (mctx, limits->elems[lim_idx], subexp_idx, dst_node, dst_idx, dst_bkref_idx); src_pos = check_dst_limits_calc_pos (mctx, limits->elems[lim_idx], subexp_idx, src_node, src_idx, src_bkref_idx); /* In case of: ( ) ( ) ( ) */ if (src_pos == dst_pos) continue; /* This is unrelated limitation. */ else return 1; } return 0; } static int internal_function check_dst_limits_calc_pos_1 (const re_match_context_t *mctx, int boundaries, int subexp_idx, int from_node, int bkref_idx) { const re_dfa_t *const dfa = mctx->dfa; const re_node_set *eclosures = dfa->eclosures + from_node; int node_idx; /* Else, we are on the boundary: examine the nodes on the epsilon closure. */ for (node_idx = 0; node_idx < eclosures->nelem; ++node_idx) { int node = eclosures->elems[node_idx]; switch (dfa->nodes[node].type) { case OP_BACK_REF: if (bkref_idx != -1) { struct re_backref_cache_entry *ent = mctx->bkref_ents + bkref_idx; do { int dst, cpos; if (ent->node != node) continue; if (subexp_idx < BITSET_WORD_BITS && !(ent->eps_reachable_subexps_map & ((bitset_word_t) 1 << subexp_idx))) continue; /* Recurse trying to reach the OP_OPEN_SUBEXP and OP_CLOSE_SUBEXP cases below. But, if the destination node is the same node as the source node, don't recurse because it would cause an infinite loop: a regex that exhibits this behavior is ()\1*\1* */ dst = dfa->edests[node].elems[0]; if (dst == from_node) { if (boundaries & 1) return -1; else /* if (boundaries & 2) */ return 0; } cpos = check_dst_limits_calc_pos_1 (mctx, boundaries, subexp_idx, dst, bkref_idx); if (cpos == -1 /* && (boundaries & 1) */) return -1; if (cpos == 0 && (boundaries & 2)) return 0; if (subexp_idx < BITSET_WORD_BITS) ent->eps_reachable_subexps_map &= ~((bitset_word_t) 1 << subexp_idx); } while (ent++->more); } break; case OP_OPEN_SUBEXP: if ((boundaries & 1) && subexp_idx == dfa->nodes[node].opr.idx) return -1; break; case OP_CLOSE_SUBEXP: if ((boundaries & 2) && subexp_idx == dfa->nodes[node].opr.idx) return 0; break; default: break; } } return (boundaries & 2) ? 1 : 0; } static int internal_function check_dst_limits_calc_pos (const re_match_context_t *mctx, int limit, int subexp_idx, int from_node, int str_idx, int bkref_idx) { struct re_backref_cache_entry *lim = mctx->bkref_ents + limit; int boundaries; /* If we are outside the range of the subexpression, return -1 or 1. */ if (str_idx < lim->subexp_from) return -1; if (lim->subexp_to < str_idx) return 1; /* If we are within the subexpression, return 0. */ boundaries = (str_idx == lim->subexp_from); boundaries |= (str_idx == lim->subexp_to) << 1; if (boundaries == 0) return 0; /* Else, examine epsilon closure. */ return check_dst_limits_calc_pos_1 (mctx, boundaries, subexp_idx, from_node, bkref_idx); } /* Check the limitations of sub expressions LIMITS, and remove the nodes which are against limitations from DEST_NODES. */ static reg_errcode_t internal_function check_subexp_limits (const re_dfa_t *dfa, re_node_set *dest_nodes, const re_node_set *candidates, re_node_set *limits, struct re_backref_cache_entry *bkref_ents, int str_idx) { reg_errcode_t err; int node_idx, lim_idx; for (lim_idx = 0; lim_idx < limits->nelem; ++lim_idx) { int subexp_idx; struct re_backref_cache_entry *ent; ent = bkref_ents + limits->elems[lim_idx]; if (str_idx <= ent->subexp_from || ent->str_idx < str_idx) continue; /* This is unrelated limitation. */ subexp_idx = dfa->nodes[ent->node].opr.idx; if (ent->subexp_to == str_idx) { int ops_node = -1; int cls_node = -1; for (node_idx = 0; node_idx < dest_nodes->nelem; ++node_idx) { int node = dest_nodes->elems[node_idx]; re_token_type_t type = dfa->nodes[node].type; if (type == OP_OPEN_SUBEXP && subexp_idx == dfa->nodes[node].opr.idx) ops_node = node; else if (type == OP_CLOSE_SUBEXP && subexp_idx == dfa->nodes[node].opr.idx) cls_node = node; } /* Check the limitation of the open subexpression. */ /* Note that (ent->subexp_to = str_idx != ent->subexp_from). */ if (ops_node >= 0) { err = sub_epsilon_src_nodes (dfa, ops_node, dest_nodes, candidates); if (BE (err != REG_NOERROR, 0)) return err; } /* Check the limitation of the close subexpression. */ if (cls_node >= 0) for (node_idx = 0; node_idx < dest_nodes->nelem; ++node_idx) { int node = dest_nodes->elems[node_idx]; if (!re_node_set_contains (dfa->inveclosures + node, cls_node) && !re_node_set_contains (dfa->eclosures + node, cls_node)) { /* It is against this limitation. Remove it form the current sifted state. */ err = sub_epsilon_src_nodes (dfa, node, dest_nodes, candidates); if (BE (err != REG_NOERROR, 0)) return err; --node_idx; } } } else /* (ent->subexp_to != str_idx) */ { for (node_idx = 0; node_idx < dest_nodes->nelem; ++node_idx) { int node = dest_nodes->elems[node_idx]; re_token_type_t type = dfa->nodes[node].type; if (type == OP_CLOSE_SUBEXP || type == OP_OPEN_SUBEXP) { if (subexp_idx != dfa->nodes[node].opr.idx) continue; /* It is against this limitation. Remove it form the current sifted state. */ err = sub_epsilon_src_nodes (dfa, node, dest_nodes, candidates); if (BE (err != REG_NOERROR, 0)) return err; } } } } return REG_NOERROR; } static reg_errcode_t internal_function sift_states_bkref (const re_match_context_t *mctx, re_sift_context_t *sctx, int str_idx, const re_node_set *candidates) { const re_dfa_t *const dfa = mctx->dfa; reg_errcode_t err; int node_idx, node; re_sift_context_t local_sctx; int first_idx = search_cur_bkref_entry (mctx, str_idx); if (first_idx == -1) return REG_NOERROR; local_sctx.sifted_states = NULL; /* Mark that it hasn't been initialized. */ for (node_idx = 0; node_idx < candidates->nelem; ++node_idx) { int enabled_idx; re_token_type_t type; struct re_backref_cache_entry *entry; node = candidates->elems[node_idx]; type = dfa->nodes[node].type; /* Avoid infinite loop for the REs like "()\1+". */ if (node == sctx->last_node && str_idx == sctx->last_str_idx) continue; if (type != OP_BACK_REF) continue; entry = mctx->bkref_ents + first_idx; enabled_idx = first_idx; do { int subexp_len; int to_idx; int dst_node; int ret; re_dfastate_t *cur_state; if (entry->node != node) continue; subexp_len = entry->subexp_to - entry->subexp_from; to_idx = str_idx + subexp_len; dst_node = (subexp_len ? dfa->nexts[node] : dfa->edests[node].elems[0]); if (to_idx > sctx->last_str_idx || sctx->sifted_states[to_idx] == NULL || !STATE_NODE_CONTAINS (sctx->sifted_states[to_idx], dst_node) || check_dst_limits (mctx, &sctx->limits, node, str_idx, dst_node, to_idx)) continue; if (local_sctx.sifted_states == NULL) { local_sctx = *sctx; err = re_node_set_init_copy (&local_sctx.limits, &sctx->limits); if (BE (err != REG_NOERROR, 0)) goto free_return; } local_sctx.last_node = node; local_sctx.last_str_idx = str_idx; ret = re_node_set_insert (&local_sctx.limits, enabled_idx); if (BE (ret < 0, 0)) { err = REG_ESPACE; goto free_return; } cur_state = local_sctx.sifted_states[str_idx]; err = sift_states_backward (mctx, &local_sctx); if (BE (err != REG_NOERROR, 0)) goto free_return; if (sctx->limited_states != NULL) { err = merge_state_array (dfa, sctx->limited_states, local_sctx.sifted_states, str_idx + 1); if (BE (err != REG_NOERROR, 0)) goto free_return; } local_sctx.sifted_states[str_idx] = cur_state; re_node_set_remove (&local_sctx.limits, enabled_idx); /* mctx->bkref_ents may have changed, reload the pointer. */ entry = mctx->bkref_ents + enabled_idx; } while (enabled_idx++, entry++->more); } err = REG_NOERROR; free_return: if (local_sctx.sifted_states != NULL) { re_node_set_free (&local_sctx.limits); } return err; } #ifdef RE_ENABLE_I18N static int internal_function sift_states_iter_mb (const re_match_context_t *mctx, re_sift_context_t *sctx, int node_idx, int str_idx, int max_str_idx) { const re_dfa_t *const dfa = mctx->dfa; int naccepted; /* Check the node can accept `multi byte'. */ naccepted = check_node_accept_bytes (dfa, node_idx, &mctx->input, str_idx); if (naccepted > 0 && str_idx + naccepted <= max_str_idx && !STATE_NODE_CONTAINS (sctx->sifted_states[str_idx + naccepted], dfa->nexts[node_idx])) /* The node can't accept the `multi byte', or the destination was already thrown away, then the node could't accept the current input `multi byte'. */ naccepted = 0; /* Otherwise, it is sure that the node could accept `naccepted' bytes input. */ return naccepted; } #endif /* RE_ENABLE_I18N */ /* Functions for state transition. */ /* Return the next state to which the current state STATE will transit by accepting the current input byte, and update STATE_LOG if necessary. If STATE can accept a multibyte char/collating element/back reference update the destination of STATE_LOG. */ static re_dfastate_t * internal_function transit_state (reg_errcode_t *err, re_match_context_t *mctx, re_dfastate_t *state) { re_dfastate_t **trtable; unsigned char ch; #ifdef RE_ENABLE_I18N /* If the current state can accept multibyte. */ if (BE (state->accept_mb, 0)) { *err = transit_state_mb (mctx, state); if (BE (*err != REG_NOERROR, 0)) return NULL; } #endif /* RE_ENABLE_I18N */ /* Then decide the next state with the single byte. */ #if 0 if (0) /* don't use transition table */ return transit_state_sb (err, mctx, state); #endif /* Use transition table */ ch = re_string_fetch_byte (&mctx->input); for (;;) { trtable = state->trtable; if (BE (trtable != NULL, 1)) return trtable[ch]; trtable = state->word_trtable; if (BE (trtable != NULL, 1)) { unsigned int context; context = re_string_context_at (&mctx->input, re_string_cur_idx (&mctx->input) - 1, mctx->eflags); if (IS_WORD_CONTEXT (context)) return trtable[ch + SBC_MAX]; else return trtable[ch]; } if (!build_trtable (mctx->dfa, state)) { *err = REG_ESPACE; return NULL; } /* Retry, we now have a transition table. */ } } /* Update the state_log if we need */ re_dfastate_t * internal_function merge_state_with_log (reg_errcode_t *err, re_match_context_t *mctx, re_dfastate_t *next_state) { const re_dfa_t *const dfa = mctx->dfa; int cur_idx = re_string_cur_idx (&mctx->input); if (cur_idx > mctx->state_log_top) { mctx->state_log[cur_idx] = next_state; mctx->state_log_top = cur_idx; } else if (mctx->state_log[cur_idx] == 0) { mctx->state_log[cur_idx] = next_state; } else { re_dfastate_t *pstate; unsigned int context; re_node_set next_nodes, *log_nodes, *table_nodes = NULL; /* If (state_log[cur_idx] != 0), it implies that cur_idx is the destination of a multibyte char/collating element/ back reference. Then the next state is the union set of these destinations and the results of the transition table. */ pstate = mctx->state_log[cur_idx]; log_nodes = pstate->entrance_nodes; if (next_state != NULL) { table_nodes = next_state->entrance_nodes; *err = re_node_set_init_union (&next_nodes, table_nodes, log_nodes); if (BE (*err != REG_NOERROR, 0)) return NULL; } else next_nodes = *log_nodes; /* Note: We already add the nodes of the initial state, then we don't need to add them here. */ context = re_string_context_at (&mctx->input, re_string_cur_idx (&mctx->input) - 1, mctx->eflags); next_state = mctx->state_log[cur_idx] = re_acquire_state_context (err, dfa, &next_nodes, context); /* We don't need to check errors here, since the return value of this function is next_state and ERR is already set. */ if (table_nodes != NULL) re_node_set_free (&next_nodes); } if (BE (dfa->nbackref, 0) && next_state != NULL) { /* Check OP_OPEN_SUBEXP in the current state in case that we use them later. We must check them here, since the back references in the next state might use them. */ *err = check_subexp_matching_top (mctx, &next_state->nodes, cur_idx); if (BE (*err != REG_NOERROR, 0)) return NULL; /* If the next state has back references. */ if (next_state->has_backref) { *err = transit_state_bkref (mctx, &next_state->nodes); if (BE (*err != REG_NOERROR, 0)) return NULL; next_state = mctx->state_log[cur_idx]; } } return next_state; } /* Skip bytes in the input that correspond to part of a multi-byte match, then look in the log for a state from which to restart matching. */ re_dfastate_t * internal_function find_recover_state (reg_errcode_t *err, re_match_context_t *mctx) { re_dfastate_t *cur_state; do { int max = mctx->state_log_top; int cur_str_idx = re_string_cur_idx (&mctx->input); do { if (++cur_str_idx > max) return NULL; re_string_skip_bytes (&mctx->input, 1); } while (mctx->state_log[cur_str_idx] == NULL); cur_state = merge_state_with_log (err, mctx, NULL); } while (*err == REG_NOERROR && cur_state == NULL); return cur_state; } /* Helper functions for transit_state. */ /* From the node set CUR_NODES, pick up the nodes whose types are OP_OPEN_SUBEXP and which have corresponding back references in the regular expression. And register them to use them later for evaluating the correspoding back references. */ static reg_errcode_t internal_function check_subexp_matching_top (re_match_context_t *mctx, re_node_set *cur_nodes, int str_idx) { const re_dfa_t *const dfa = mctx->dfa; int node_idx; reg_errcode_t err; /* TODO: This isn't efficient. Because there might be more than one nodes whose types are OP_OPEN_SUBEXP and whose index is SUBEXP_IDX, we must check all nodes. E.g. RE: (a){2} */ for (node_idx = 0; node_idx < cur_nodes->nelem; ++node_idx) { int node = cur_nodes->elems[node_idx]; if (dfa->nodes[node].type == OP_OPEN_SUBEXP && dfa->nodes[node].opr.idx < BITSET_WORD_BITS && (dfa->used_bkref_map & ((bitset_word_t) 1 << dfa->nodes[node].opr.idx))) { err = match_ctx_add_subtop (mctx, node, str_idx); if (BE (err != REG_NOERROR, 0)) return err; } } return REG_NOERROR; } #if 0 /* Return the next state to which the current state STATE will transit by accepting the current input byte. */ static re_dfastate_t * transit_state_sb (reg_errcode_t *err, re_match_context_t *mctx, re_dfastate_t *state) { const re_dfa_t *const dfa = mctx->dfa; re_node_set next_nodes; re_dfastate_t *next_state; int node_cnt, cur_str_idx = re_string_cur_idx (&mctx->input); unsigned int context; *err = re_node_set_alloc (&next_nodes, state->nodes.nelem + 1); if (BE (*err != REG_NOERROR, 0)) return NULL; for (node_cnt = 0; node_cnt < state->nodes.nelem; ++node_cnt) { int cur_node = state->nodes.elems[node_cnt]; if (check_node_accept (mctx, dfa->nodes + cur_node, cur_str_idx)) { *err = re_node_set_merge (&next_nodes, dfa->eclosures + dfa->nexts[cur_node]); if (BE (*err != REG_NOERROR, 0)) { re_node_set_free (&next_nodes); return NULL; } } } context = re_string_context_at (&mctx->input, cur_str_idx, mctx->eflags); next_state = re_acquire_state_context (err, dfa, &next_nodes, context); /* We don't need to check errors here, since the return value of this function is next_state and ERR is already set. */ re_node_set_free (&next_nodes); re_string_skip_bytes (&mctx->input, 1); return next_state; } #endif #ifdef RE_ENABLE_I18N static reg_errcode_t internal_function transit_state_mb (re_match_context_t *mctx, re_dfastate_t *pstate) { const re_dfa_t *const dfa = mctx->dfa; reg_errcode_t err; int i; for (i = 0; i < pstate->nodes.nelem; ++i) { re_node_set dest_nodes, *new_nodes; int cur_node_idx = pstate->nodes.elems[i]; int naccepted, dest_idx; unsigned int context; re_dfastate_t *dest_state; if (!dfa->nodes[cur_node_idx].accept_mb) continue; if (dfa->nodes[cur_node_idx].constraint) { context = re_string_context_at (&mctx->input, re_string_cur_idx (&mctx->input), mctx->eflags); if (NOT_SATISFY_NEXT_CONSTRAINT (dfa->nodes[cur_node_idx].constraint, context)) continue; } /* How many bytes the node can accept? */ naccepted = check_node_accept_bytes (dfa, cur_node_idx, &mctx->input, re_string_cur_idx (&mctx->input)); if (naccepted == 0) continue; /* The node can accepts `naccepted' bytes. */ dest_idx = re_string_cur_idx (&mctx->input) + naccepted; mctx->max_mb_elem_len = ((mctx->max_mb_elem_len < naccepted) ? naccepted : mctx->max_mb_elem_len); err = clean_state_log_if_needed (mctx, dest_idx); if (BE (err != REG_NOERROR, 0)) return err; #ifdef DEBUG assert (dfa->nexts[cur_node_idx] != -1); #endif new_nodes = dfa->eclosures + dfa->nexts[cur_node_idx]; dest_state = mctx->state_log[dest_idx]; if (dest_state == NULL) dest_nodes = *new_nodes; else { err = re_node_set_init_union (&dest_nodes, dest_state->entrance_nodes, new_nodes); if (BE (err != REG_NOERROR, 0)) return err; } context = re_string_context_at (&mctx->input, dest_idx - 1, mctx->eflags); mctx->state_log[dest_idx] = re_acquire_state_context (&err, dfa, &dest_nodes, context); if (dest_state != NULL) re_node_set_free (&dest_nodes); if (BE (mctx->state_log[dest_idx] == NULL && err != REG_NOERROR, 0)) return err; } return REG_NOERROR; } #endif /* RE_ENABLE_I18N */ static reg_errcode_t internal_function transit_state_bkref (re_match_context_t *mctx, const re_node_set *nodes) { const re_dfa_t *const dfa = mctx->dfa; reg_errcode_t err; int i; int cur_str_idx = re_string_cur_idx (&mctx->input); for (i = 0; i < nodes->nelem; ++i) { int dest_str_idx, prev_nelem, bkc_idx; int node_idx = nodes->elems[i]; unsigned int context; const re_token_t *node = dfa->nodes + node_idx; re_node_set *new_dest_nodes; /* Check whether `node' is a backreference or not. */ if (node->type != OP_BACK_REF) continue; if (node->constraint) { context = re_string_context_at (&mctx->input, cur_str_idx, mctx->eflags); if (NOT_SATISFY_NEXT_CONSTRAINT (node->constraint, context)) continue; } /* `node' is a backreference. Check the substring which the substring matched. */ bkc_idx = mctx->nbkref_ents; err = get_subexp (mctx, node_idx, cur_str_idx); if (BE (err != REG_NOERROR, 0)) goto free_return; /* And add the epsilon closures (which is `new_dest_nodes') of the backreference to appropriate state_log. */ #ifdef DEBUG assert (dfa->nexts[node_idx] != -1); #endif for (; bkc_idx < mctx->nbkref_ents; ++bkc_idx) { int subexp_len; re_dfastate_t *dest_state; struct re_backref_cache_entry *bkref_ent; bkref_ent = mctx->bkref_ents + bkc_idx; if (bkref_ent->node != node_idx || bkref_ent->str_idx != cur_str_idx) continue; subexp_len = bkref_ent->subexp_to - bkref_ent->subexp_from; new_dest_nodes = (subexp_len == 0 ? dfa->eclosures + dfa->edests[node_idx].elems[0] : dfa->eclosures + dfa->nexts[node_idx]); dest_str_idx = (cur_str_idx + bkref_ent->subexp_to - bkref_ent->subexp_from); context = re_string_context_at (&mctx->input, dest_str_idx - 1, mctx->eflags); dest_state = mctx->state_log[dest_str_idx]; prev_nelem = ((mctx->state_log[cur_str_idx] == NULL) ? 0 : mctx->state_log[cur_str_idx]->nodes.nelem); /* Add `new_dest_node' to state_log. */ if (dest_state == NULL) { mctx->state_log[dest_str_idx] = re_acquire_state_context (&err, dfa, new_dest_nodes, context); if (BE (mctx->state_log[dest_str_idx] == NULL && err != REG_NOERROR, 0)) goto free_return; } else { re_node_set dest_nodes; err = re_node_set_init_union (&dest_nodes, dest_state->entrance_nodes, new_dest_nodes); if (BE (err != REG_NOERROR, 0)) { re_node_set_free (&dest_nodes); goto free_return; } mctx->state_log[dest_str_idx] = re_acquire_state_context (&err, dfa, &dest_nodes, context); re_node_set_free (&dest_nodes); if (BE (mctx->state_log[dest_str_idx] == NULL && err != REG_NOERROR, 0)) goto free_return; } /* We need to check recursively if the backreference can epsilon transit. */ if (subexp_len == 0 && mctx->state_log[cur_str_idx]->nodes.nelem > prev_nelem) { err = check_subexp_matching_top (mctx, new_dest_nodes, cur_str_idx); if (BE (err != REG_NOERROR, 0)) goto free_return; err = transit_state_bkref (mctx, new_dest_nodes); if (BE (err != REG_NOERROR, 0)) goto free_return; } } } err = REG_NOERROR; free_return: return err; } /* Enumerate all the candidates which the backreference BKREF_NODE can match at BKREF_STR_IDX, and register them by match_ctx_add_entry(). Note that we might collect inappropriate candidates here. However, the cost of checking them strictly here is too high, then we delay these checking for prune_impossible_nodes(). */ static reg_errcode_t internal_function get_subexp (re_match_context_t *mctx, int bkref_node, int bkref_str_idx) { const re_dfa_t *const dfa = mctx->dfa; int subexp_num, sub_top_idx; const char *buf = (const char *) re_string_get_buffer (&mctx->input); /* Return if we have already checked BKREF_NODE at BKREF_STR_IDX. */ int cache_idx = search_cur_bkref_entry (mctx, bkref_str_idx); if (cache_idx != -1) { const struct re_backref_cache_entry *entry = mctx->bkref_ents + cache_idx; do if (entry->node == bkref_node) return REG_NOERROR; /* We already checked it. */ while (entry++->more); } subexp_num = dfa->nodes[bkref_node].opr.idx; /* For each sub expression */ for (sub_top_idx = 0; sub_top_idx < mctx->nsub_tops; ++sub_top_idx) { reg_errcode_t err; re_sub_match_top_t *sub_top = mctx->sub_tops[sub_top_idx]; re_sub_match_last_t *sub_last; int sub_last_idx, sl_str, bkref_str_off; if (dfa->nodes[sub_top->node].opr.idx != subexp_num) continue; /* It isn't related. */ sl_str = sub_top->str_idx; bkref_str_off = bkref_str_idx; /* At first, check the last node of sub expressions we already evaluated. */ for (sub_last_idx = 0; sub_last_idx < sub_top->nlasts; ++sub_last_idx) { int sl_str_diff; sub_last = sub_top->lasts[sub_last_idx]; sl_str_diff = sub_last->str_idx - sl_str; /* The matched string by the sub expression match with the substring at the back reference? */ if (sl_str_diff > 0) { if (BE (bkref_str_off + sl_str_diff > mctx->input.valid_len, 0)) { /* Not enough chars for a successful match. */ if (bkref_str_off + sl_str_diff > mctx->input.len) break; err = clean_state_log_if_needed (mctx, bkref_str_off + sl_str_diff); if (BE (err != REG_NOERROR, 0)) return err; buf = (const char *) re_string_get_buffer (&mctx->input); } if (memcmp (buf + bkref_str_off, buf + sl_str, sl_str_diff) != 0) /* We don't need to search this sub expression any more. */ break; } bkref_str_off += sl_str_diff; sl_str += sl_str_diff; err = get_subexp_sub (mctx, sub_top, sub_last, bkref_node, bkref_str_idx); /* Reload buf, since the preceding call might have reallocated the buffer. */ buf = (const char *) re_string_get_buffer (&mctx->input); if (err == REG_NOMATCH) continue; if (BE (err != REG_NOERROR, 0)) return err; } if (sub_last_idx < sub_top->nlasts) continue; if (sub_last_idx > 0) ++sl_str; /* Then, search for the other last nodes of the sub expression. */ for (; sl_str <= bkref_str_idx; ++sl_str) { int cls_node, sl_str_off; const re_node_set *nodes; sl_str_off = sl_str - sub_top->str_idx; /* The matched string by the sub expression match with the substring at the back reference? */ if (sl_str_off > 0) { if (BE (bkref_str_off >= mctx->input.valid_len, 0)) { /* If we are at the end of the input, we cannot match. */ if (bkref_str_off >= mctx->input.len) break; err = extend_buffers (mctx); if (BE (err != REG_NOERROR, 0)) return err; buf = (const char *) re_string_get_buffer (&mctx->input); } if (buf [bkref_str_off++] != buf[sl_str - 1]) break; /* We don't need to search this sub expression any more. */ } if (mctx->state_log[sl_str] == NULL) continue; /* Does this state have a ')' of the sub expression? */ nodes = &mctx->state_log[sl_str]->nodes; cls_node = find_subexp_node (dfa, nodes, subexp_num, OP_CLOSE_SUBEXP); if (cls_node == -1) continue; /* No. */ if (sub_top->path == NULL) { sub_top->path = calloc (sizeof (state_array_t), sl_str - sub_top->str_idx + 1); if (sub_top->path == NULL) return REG_ESPACE; } /* Can the OP_OPEN_SUBEXP node arrive the OP_CLOSE_SUBEXP node in the current context? */ err = check_arrival (mctx, sub_top->path, sub_top->node, sub_top->str_idx, cls_node, sl_str, OP_CLOSE_SUBEXP); if (err == REG_NOMATCH) continue; if (BE (err != REG_NOERROR, 0)) return err; sub_last = match_ctx_add_sublast (sub_top, cls_node, sl_str); if (BE (sub_last == NULL, 0)) return REG_ESPACE; err = get_subexp_sub (mctx, sub_top, sub_last, bkref_node, bkref_str_idx); if (err == REG_NOMATCH) continue; } } return REG_NOERROR; } /* Helper functions for get_subexp(). */ /* Check SUB_LAST can arrive to the back reference BKREF_NODE at BKREF_STR. If it can arrive, register the sub expression expressed with SUB_TOP and SUB_LAST. */ static reg_errcode_t internal_function get_subexp_sub (re_match_context_t *mctx, const re_sub_match_top_t *sub_top, re_sub_match_last_t *sub_last, int bkref_node, int bkref_str) { reg_errcode_t err; int to_idx; /* Can the subexpression arrive the back reference? */ err = check_arrival (mctx, &sub_last->path, sub_last->node, sub_last->str_idx, bkref_node, bkref_str, OP_OPEN_SUBEXP); if (err != REG_NOERROR) return err; err = match_ctx_add_entry (mctx, bkref_node, bkref_str, sub_top->str_idx, sub_last->str_idx); if (BE (err != REG_NOERROR, 0)) return err; to_idx = bkref_str + sub_last->str_idx - sub_top->str_idx; return clean_state_log_if_needed (mctx, to_idx); } /* Find the first node which is '(' or ')' and whose index is SUBEXP_IDX. Search '(' if FL_OPEN, or search ')' otherwise. TODO: This function isn't efficient... Because there might be more than one nodes whose types are OP_OPEN_SUBEXP and whose index is SUBEXP_IDX, we must check all nodes. E.g. RE: (a){2} */ static int internal_function find_subexp_node (const re_dfa_t *dfa, const re_node_set *nodes, int subexp_idx, int type) { int cls_idx; for (cls_idx = 0; cls_idx < nodes->nelem; ++cls_idx) { int cls_node = nodes->elems[cls_idx]; const re_token_t *node = dfa->nodes + cls_node; if (node->type == type && node->opr.idx == subexp_idx) return cls_node; } return -1; } /* Check whether the node TOP_NODE at TOP_STR can arrive to the node LAST_NODE at LAST_STR. We record the path onto PATH since it will be heavily reused. Return REG_NOERROR if it can arrive, or REG_NOMATCH otherwise. */ static reg_errcode_t internal_function check_arrival (re_match_context_t *mctx, state_array_t *path, int top_node, int top_str, int last_node, int last_str, int type) { const re_dfa_t *const dfa = mctx->dfa; reg_errcode_t err = REG_NOERROR; int subexp_num, backup_cur_idx, str_idx, null_cnt; re_dfastate_t *cur_state = NULL; re_node_set *cur_nodes, next_nodes; re_dfastate_t **backup_state_log; unsigned int context; subexp_num = dfa->nodes[top_node].opr.idx; /* Extend the buffer if we need. */ if (BE (path->alloc < last_str + mctx->max_mb_elem_len + 1, 0)) { re_dfastate_t **new_array; int old_alloc = path->alloc; path->alloc += last_str + mctx->max_mb_elem_len + 1; new_array = re_realloc (path->array, re_dfastate_t *, path->alloc); if (BE (new_array == NULL, 0)) { path->alloc = old_alloc; return REG_ESPACE; } path->array = new_array; memset (new_array + old_alloc, '\0', sizeof (re_dfastate_t *) * (path->alloc - old_alloc)); } str_idx = path->next_idx ? path->next_idx : top_str; /* Temporary modify MCTX. */ backup_state_log = mctx->state_log; backup_cur_idx = mctx->input.cur_idx; mctx->state_log = path->array; mctx->input.cur_idx = str_idx; /* Setup initial node set. */ context = re_string_context_at (&mctx->input, str_idx - 1, mctx->eflags); if (str_idx == top_str) { err = re_node_set_init_1 (&next_nodes, top_node); if (BE (err != REG_NOERROR, 0)) return err; err = check_arrival_expand_ecl (dfa, &next_nodes, subexp_num, type); if (BE (err != REG_NOERROR, 0)) { re_node_set_free (&next_nodes); return err; } } else { cur_state = mctx->state_log[str_idx]; if (cur_state && cur_state->has_backref) { err = re_node_set_init_copy (&next_nodes, &cur_state->nodes); if (BE (err != REG_NOERROR, 0)) return err; } else re_node_set_init_empty (&next_nodes); } if (str_idx == top_str || (cur_state && cur_state->has_backref)) { if (next_nodes.nelem) { err = expand_bkref_cache (mctx, &next_nodes, str_idx, subexp_num, type); if (BE (err != REG_NOERROR, 0)) { re_node_set_free (&next_nodes); return err; } } cur_state = re_acquire_state_context (&err, dfa, &next_nodes, context); if (BE (cur_state == NULL && err != REG_NOERROR, 0)) { re_node_set_free (&next_nodes); return err; } mctx->state_log[str_idx] = cur_state; } for (null_cnt = 0; str_idx < last_str && null_cnt <= mctx->max_mb_elem_len;) { re_node_set_empty (&next_nodes); if (mctx->state_log[str_idx + 1]) { err = re_node_set_merge (&next_nodes, &mctx->state_log[str_idx + 1]->nodes); if (BE (err != REG_NOERROR, 0)) { re_node_set_free (&next_nodes); return err; } } if (cur_state) { err = check_arrival_add_next_nodes (mctx, str_idx, &cur_state->non_eps_nodes, &next_nodes); if (BE (err != REG_NOERROR, 0)) { re_node_set_free (&next_nodes); return err; } } ++str_idx; if (next_nodes.nelem) { err = check_arrival_expand_ecl (dfa, &next_nodes, subexp_num, type); if (BE (err != REG_NOERROR, 0)) { re_node_set_free (&next_nodes); return err; } err = expand_bkref_cache (mctx, &next_nodes, str_idx, subexp_num, type); if (BE (err != REG_NOERROR, 0)) { re_node_set_free (&next_nodes); return err; } } context = re_string_context_at (&mctx->input, str_idx - 1, mctx->eflags); cur_state = re_acquire_state_context (&err, dfa, &next_nodes, context); if (BE (cur_state == NULL && err != REG_NOERROR, 0)) { re_node_set_free (&next_nodes); return err; } mctx->state_log[str_idx] = cur_state; null_cnt = cur_state == NULL ? null_cnt + 1 : 0; } re_node_set_free (&next_nodes); cur_nodes = (mctx->state_log[last_str] == NULL ? NULL : &mctx->state_log[last_str]->nodes); path->next_idx = str_idx; /* Fix MCTX. */ mctx->state_log = backup_state_log; mctx->input.cur_idx = backup_cur_idx; /* Then check the current node set has the node LAST_NODE. */ if (cur_nodes != NULL && re_node_set_contains (cur_nodes, last_node)) return REG_NOERROR; return REG_NOMATCH; } /* Helper functions for check_arrival. */ /* Calculate the destination nodes of CUR_NODES at STR_IDX, and append them to NEXT_NODES. TODO: This function is similar to the functions transit_state*(), however this function has many additional works. Can't we unify them? */ static reg_errcode_t internal_function check_arrival_add_next_nodes (re_match_context_t *mctx, int str_idx, re_node_set *cur_nodes, re_node_set *next_nodes) { const re_dfa_t *const dfa = mctx->dfa; int result; int cur_idx; #ifdef RE_ENABLE_I18N reg_errcode_t err = REG_NOERROR; #endif re_node_set union_set; re_node_set_init_empty (&union_set); for (cur_idx = 0; cur_idx < cur_nodes->nelem; ++cur_idx) { int naccepted = 0; int cur_node = cur_nodes->elems[cur_idx]; #ifdef DEBUG re_token_type_t type = dfa->nodes[cur_node].type; assert (!IS_EPSILON_NODE (type)); #endif #ifdef RE_ENABLE_I18N /* If the node may accept `multi byte'. */ if (dfa->nodes[cur_node].accept_mb) { naccepted = check_node_accept_bytes (dfa, cur_node, &mctx->input, str_idx); if (naccepted > 1) { re_dfastate_t *dest_state; int next_node = dfa->nexts[cur_node]; int next_idx = str_idx + naccepted; dest_state = mctx->state_log[next_idx]; re_node_set_empty (&union_set); if (dest_state) { err = re_node_set_merge (&union_set, &dest_state->nodes); if (BE (err != REG_NOERROR, 0)) { re_node_set_free (&union_set); return err; } } result = re_node_set_insert (&union_set, next_node); if (BE (result < 0, 0)) { re_node_set_free (&union_set); return REG_ESPACE; } mctx->state_log[next_idx] = re_acquire_state (&err, dfa, &union_set); if (BE (mctx->state_log[next_idx] == NULL && err != REG_NOERROR, 0)) { re_node_set_free (&union_set); return err; } } } #endif /* RE_ENABLE_I18N */ if (naccepted || check_node_accept (mctx, dfa->nodes + cur_node, str_idx)) { result = re_node_set_insert (next_nodes, dfa->nexts[cur_node]); if (BE (result < 0, 0)) { re_node_set_free (&union_set); return REG_ESPACE; } } } re_node_set_free (&union_set); return REG_NOERROR; } /* For all the nodes in CUR_NODES, add the epsilon closures of them to CUR_NODES, however exclude the nodes which are: - inside the sub expression whose number is EX_SUBEXP, if FL_OPEN. - out of the sub expression whose number is EX_SUBEXP, if !FL_OPEN. */ static reg_errcode_t internal_function check_arrival_expand_ecl (const re_dfa_t *dfa, re_node_set *cur_nodes, int ex_subexp, int type) { reg_errcode_t err; int idx, outside_node; re_node_set new_nodes; #ifdef DEBUG assert (cur_nodes->nelem); #endif err = re_node_set_alloc (&new_nodes, cur_nodes->nelem); if (BE (err != REG_NOERROR, 0)) return err; /* Create a new node set NEW_NODES with the nodes which are epsilon closures of the node in CUR_NODES. */ for (idx = 0; idx < cur_nodes->nelem; ++idx) { int cur_node = cur_nodes->elems[idx]; const re_node_set *eclosure = dfa->eclosures + cur_node; outside_node = find_subexp_node (dfa, eclosure, ex_subexp, type); if (outside_node == -1) { /* There are no problematic nodes, just merge them. */ err = re_node_set_merge (&new_nodes, eclosure); if (BE (err != REG_NOERROR, 0)) { re_node_set_free (&new_nodes); return err; } } else { /* There are problematic nodes, re-calculate incrementally. */ err = check_arrival_expand_ecl_sub (dfa, &new_nodes, cur_node, ex_subexp, type); if (BE (err != REG_NOERROR, 0)) { re_node_set_free (&new_nodes); return err; } } } re_node_set_free (cur_nodes); *cur_nodes = new_nodes; return REG_NOERROR; } /* Helper function for check_arrival_expand_ecl. Check incrementally the epsilon closure of TARGET, and if it isn't problematic append it to DST_NODES. */ static reg_errcode_t internal_function check_arrival_expand_ecl_sub (const re_dfa_t *dfa, re_node_set *dst_nodes, int target, int ex_subexp, int type) { int cur_node; for (cur_node = target; !re_node_set_contains (dst_nodes, cur_node);) { int err; if (dfa->nodes[cur_node].type == type && dfa->nodes[cur_node].opr.idx == ex_subexp) { if (type == OP_CLOSE_SUBEXP) { err = re_node_set_insert (dst_nodes, cur_node); if (BE (err == -1, 0)) return REG_ESPACE; } break; } err = re_node_set_insert (dst_nodes, cur_node); if (BE (err == -1, 0)) return REG_ESPACE; if (dfa->edests[cur_node].nelem == 0) break; if (dfa->edests[cur_node].nelem == 2) { err = check_arrival_expand_ecl_sub (dfa, dst_nodes, dfa->edests[cur_node].elems[1], ex_subexp, type); if (BE (err != REG_NOERROR, 0)) return err; } cur_node = dfa->edests[cur_node].elems[0]; } return REG_NOERROR; } /* For all the back references in the current state, calculate the destination of the back references by the appropriate entry in MCTX->BKREF_ENTS. */ static reg_errcode_t internal_function expand_bkref_cache (re_match_context_t *mctx, re_node_set *cur_nodes, int cur_str, int subexp_num, int type) { const re_dfa_t *const dfa = mctx->dfa; reg_errcode_t err; int cache_idx_start = search_cur_bkref_entry (mctx, cur_str); struct re_backref_cache_entry *ent; if (cache_idx_start == -1) return REG_NOERROR; restart: ent = mctx->bkref_ents + cache_idx_start; do { int to_idx, next_node; /* Is this entry ENT is appropriate? */ if (!re_node_set_contains (cur_nodes, ent->node)) continue; /* No. */ to_idx = cur_str + ent->subexp_to - ent->subexp_from; /* Calculate the destination of the back reference, and append it to MCTX->STATE_LOG. */ if (to_idx == cur_str) { /* The backreference did epsilon transit, we must re-check all the node in the current state. */ re_node_set new_dests; reg_errcode_t err2, err3; next_node = dfa->edests[ent->node].elems[0]; if (re_node_set_contains (cur_nodes, next_node)) continue; err = re_node_set_init_1 (&new_dests, next_node); err2 = check_arrival_expand_ecl (dfa, &new_dests, subexp_num, type); err3 = re_node_set_merge (cur_nodes, &new_dests); re_node_set_free (&new_dests); if (BE (err != REG_NOERROR || err2 != REG_NOERROR || err3 != REG_NOERROR, 0)) { err = (err != REG_NOERROR ? err : (err2 != REG_NOERROR ? err2 : err3)); return err; } /* TODO: It is still inefficient... */ goto restart; } else { re_node_set union_set; next_node = dfa->nexts[ent->node]; if (mctx->state_log[to_idx]) { int ret; if (re_node_set_contains (&mctx->state_log[to_idx]->nodes, next_node)) continue; err = re_node_set_init_copy (&union_set, &mctx->state_log[to_idx]->nodes); ret = re_node_set_insert (&union_set, next_node); if (BE (err != REG_NOERROR || ret < 0, 0)) { re_node_set_free (&union_set); err = err != REG_NOERROR ? err : REG_ESPACE; return err; } } else { err = re_node_set_init_1 (&union_set, next_node); if (BE (err != REG_NOERROR, 0)) return err; } mctx->state_log[to_idx] = re_acquire_state (&err, dfa, &union_set); re_node_set_free (&union_set); if (BE (mctx->state_log[to_idx] == NULL && err != REG_NOERROR, 0)) return err; } } while (ent++->more); return REG_NOERROR; } /* Build transition table for the state. Return 1 if succeeded, otherwise return NULL. */ static int internal_function build_trtable (const re_dfa_t *dfa, re_dfastate_t *state) { reg_errcode_t err; int i, j, ch, need_word_trtable = 0; bitset_word_t elem, mask; bool dests_node_malloced = false; bool dest_states_malloced = false; int ndests; /* Number of the destination states from `state'. */ re_dfastate_t **trtable; re_dfastate_t **dest_states = NULL, **dest_states_word, **dest_states_nl; re_node_set follows, *dests_node; bitset_t *dests_ch; bitset_t acceptable; struct dests_alloc { re_node_set dests_node[SBC_MAX]; bitset_t dests_ch[SBC_MAX]; } *dests_alloc; /* We build DFA states which corresponds to the destination nodes from `state'. `dests_node[i]' represents the nodes which i-th destination state contains, and `dests_ch[i]' represents the characters which i-th destination state accepts. */ #ifdef HAVE_ALLOCA if (__libc_use_alloca (sizeof (struct dests_alloc))) dests_alloc = (struct dests_alloc *) alloca (sizeof (struct dests_alloc)); else #endif { dests_alloc = re_malloc (struct dests_alloc, 1); if (BE (dests_alloc == NULL, 0)) return 0; dests_node_malloced = true; } dests_node = dests_alloc->dests_node; dests_ch = dests_alloc->dests_ch; /* Initialize transiton table. */ state->word_trtable = state->trtable = NULL; /* At first, group all nodes belonging to `state' into several destinations. */ ndests = group_nodes_into_DFAstates (dfa, state, dests_node, dests_ch); if (BE (ndests <= 0, 0)) { if (dests_node_malloced) free (dests_alloc); /* Return 0 in case of an error, 1 otherwise. */ if (ndests == 0) { state->trtable = (re_dfastate_t **) calloc (sizeof (re_dfastate_t *), SBC_MAX); return 1; } return 0; } err = re_node_set_alloc (&follows, ndests + 1); if (BE (err != REG_NOERROR, 0)) goto out_free; /* Avoid arithmetic overflow in size calculation. */ if (BE ((((SIZE_MAX - (sizeof (re_node_set) + sizeof (bitset_t)) * SBC_MAX) / (3 * sizeof (re_dfastate_t *))) < (size_t)ndests), 0)) goto out_free; #ifdef HAVE_ALLOCA if (__libc_use_alloca ((sizeof (re_node_set) + sizeof (bitset_t)) * SBC_MAX + ndests * 3 * sizeof (re_dfastate_t *))) dest_states = (re_dfastate_t **) alloca (ndests * 3 * sizeof (re_dfastate_t *)); else #endif { dest_states = (re_dfastate_t **) malloc (ndests * 3 * sizeof (re_dfastate_t *)); if (BE (dest_states == NULL, 0)) { out_free: if (dest_states_malloced) free (dest_states); re_node_set_free (&follows); for (i = 0; i < ndests; ++i) re_node_set_free (dests_node + i); if (dests_node_malloced) free (dests_alloc); return 0; } dest_states_malloced = true; } dest_states_word = dest_states + ndests; dest_states_nl = dest_states_word + ndests; bitset_empty (acceptable); /* Then build the states for all destinations. */ for (i = 0; i < ndests; ++i) { int next_node; re_node_set_empty (&follows); /* Merge the follows of this destination states. */ for (j = 0; j < dests_node[i].nelem; ++j) { next_node = dfa->nexts[dests_node[i].elems[j]]; if (next_node != -1) { err = re_node_set_merge (&follows, dfa->eclosures + next_node); if (BE (err != REG_NOERROR, 0)) goto out_free; } } dest_states[i] = re_acquire_state_context (&err, dfa, &follows, 0); if (BE (dest_states[i] == NULL && err != REG_NOERROR, 0)) goto out_free; /* If the new state has context constraint, build appropriate states for these contexts. */ if (dest_states[i]->has_constraint) { dest_states_word[i] = re_acquire_state_context (&err, dfa, &follows, CONTEXT_WORD); if (BE (dest_states_word[i] == NULL && err != REG_NOERROR, 0)) goto out_free; if (dest_states[i] != dest_states_word[i] && dfa->mb_cur_max > 1) need_word_trtable = 1; dest_states_nl[i] = re_acquire_state_context (&err, dfa, &follows, CONTEXT_NEWLINE); if (BE (dest_states_nl[i] == NULL && err != REG_NOERROR, 0)) goto out_free; } else { dest_states_word[i] = dest_states[i]; dest_states_nl[i] = dest_states[i]; } bitset_merge (acceptable, dests_ch[i]); } if (!BE (need_word_trtable, 0)) { /* We don't care about whether the following character is a word character, or we are in a single-byte character set so we can discern by looking at the character code: allocate a 256-entry transition table. */ trtable = state->trtable = (re_dfastate_t **) calloc (sizeof (re_dfastate_t *), SBC_MAX); if (BE (trtable == NULL, 0)) goto out_free; /* For all characters ch...: */ for (i = 0; i < BITSET_WORDS; ++i) for (ch = i * BITSET_WORD_BITS, elem = acceptable[i], mask = 1; elem; mask <<= 1, elem >>= 1, ++ch) if (BE (elem & 1, 0)) { /* There must be exactly one destination which accepts character ch. See group_nodes_into_DFAstates. */ for (j = 0; (dests_ch[j][i] & mask) == 0; ++j) ; /* j-th destination accepts the word character ch. */ if (dfa->word_char[i] & mask) trtable[ch] = dest_states_word[j]; else trtable[ch] = dest_states[j]; } } else { /* We care about whether the following character is a word character, and we are in a multi-byte character set: discern by looking at the character code: build two 256-entry transition tables, one starting at trtable[0] and one starting at trtable[SBC_MAX]. */ trtable = state->word_trtable = (re_dfastate_t **) calloc (sizeof (re_dfastate_t *), 2 * SBC_MAX); if (BE (trtable == NULL, 0)) goto out_free; /* For all characters ch...: */ for (i = 0; i < BITSET_WORDS; ++i) for (ch = i * BITSET_WORD_BITS, elem = acceptable[i], mask = 1; elem; mask <<= 1, elem >>= 1, ++ch) if (BE (elem & 1, 0)) { /* There must be exactly one destination which accepts character ch. See group_nodes_into_DFAstates. */ for (j = 0; (dests_ch[j][i] & mask) == 0; ++j) ; /* j-th destination accepts the word character ch. */ trtable[ch] = dest_states[j]; trtable[ch + SBC_MAX] = dest_states_word[j]; } } /* new line */ if (bitset_contain (acceptable, NEWLINE_CHAR)) { /* The current state accepts newline character. */ for (j = 0; j < ndests; ++j) if (bitset_contain (dests_ch[j], NEWLINE_CHAR)) { /* k-th destination accepts newline character. */ trtable[NEWLINE_CHAR] = dest_states_nl[j]; if (need_word_trtable) trtable[NEWLINE_CHAR + SBC_MAX] = dest_states_nl[j]; /* There must be only one destination which accepts newline. See group_nodes_into_DFAstates. */ break; } } if (dest_states_malloced) free (dest_states); re_node_set_free (&follows); for (i = 0; i < ndests; ++i) re_node_set_free (dests_node + i); if (dests_node_malloced) free (dests_alloc); return 1; } /* Group all nodes belonging to STATE into several destinations. Then for all destinations, set the nodes belonging to the destination to DESTS_NODE[i] and set the characters accepted by the destination to DEST_CH[i]. This function return the number of destinations. */ static int internal_function group_nodes_into_DFAstates (const re_dfa_t *dfa, const re_dfastate_t *state, re_node_set *dests_node, bitset_t *dests_ch) { reg_errcode_t err; int result; int i, j, k; int ndests; /* Number of the destinations from `state'. */ bitset_t accepts; /* Characters a node can accept. */ const re_node_set *cur_nodes = &state->nodes; bitset_empty (accepts); ndests = 0; /* For all the nodes belonging to `state', */ for (i = 0; i < cur_nodes->nelem; ++i) { re_token_t *node = &dfa->nodes[cur_nodes->elems[i]]; re_token_type_t type = node->type; unsigned int constraint = node->constraint; /* Enumerate all single byte character this node can accept. */ if (type == CHARACTER) bitset_set (accepts, node->opr.c); else if (type == SIMPLE_BRACKET) { bitset_merge (accepts, node->opr.sbcset); } else if (type == OP_PERIOD) { #ifdef RE_ENABLE_I18N if (dfa->mb_cur_max > 1) bitset_merge (accepts, dfa->sb_char); else #endif bitset_set_all (accepts); if (!(dfa->syntax & RE_DOT_NEWLINE)) bitset_clear (accepts, '\n'); if (dfa->syntax & RE_DOT_NOT_NULL) bitset_clear (accepts, '\0'); } #ifdef RE_ENABLE_I18N else if (type == OP_UTF8_PERIOD) { memset (accepts, '\xff', sizeof (bitset_t) / 2); if (!(dfa->syntax & RE_DOT_NEWLINE)) bitset_clear (accepts, '\n'); if (dfa->syntax & RE_DOT_NOT_NULL) bitset_clear (accepts, '\0'); } #endif else continue; /* Check the `accepts' and sift the characters which are not match it the context. */ if (constraint) { if (constraint & NEXT_NEWLINE_CONSTRAINT) { bool accepts_newline = bitset_contain (accepts, NEWLINE_CHAR); bitset_empty (accepts); if (accepts_newline) bitset_set (accepts, NEWLINE_CHAR); else continue; } if (constraint & NEXT_ENDBUF_CONSTRAINT) { bitset_empty (accepts); continue; } if (constraint & NEXT_WORD_CONSTRAINT) { bitset_word_t any_set = 0; if (type == CHARACTER && !node->word_char) { bitset_empty (accepts); continue; } #ifdef RE_ENABLE_I18N if (dfa->mb_cur_max > 1) for (j = 0; j < BITSET_WORDS; ++j) any_set |= (accepts[j] &= (dfa->word_char[j] | ~dfa->sb_char[j])); else #endif for (j = 0; j < BITSET_WORDS; ++j) any_set |= (accepts[j] &= dfa->word_char[j]); if (!any_set) continue; } if (constraint & NEXT_NOTWORD_CONSTRAINT) { bitset_word_t any_set = 0; if (type == CHARACTER && node->word_char) { bitset_empty (accepts); continue; } #ifdef RE_ENABLE_I18N if (dfa->mb_cur_max > 1) for (j = 0; j < BITSET_WORDS; ++j) any_set |= (accepts[j] &= ~(dfa->word_char[j] & dfa->sb_char[j])); else #endif for (j = 0; j < BITSET_WORDS; ++j) any_set |= (accepts[j] &= ~dfa->word_char[j]); if (!any_set) continue; } } /* Then divide `accepts' into DFA states, or create a new state. Above, we make sure that accepts is not empty. */ for (j = 0; j < ndests; ++j) { bitset_t intersec; /* Intersection sets, see below. */ bitset_t remains; /* Flags, see below. */ bitset_word_t has_intersec, not_subset, not_consumed; /* Optimization, skip if this state doesn't accept the character. */ if (type == CHARACTER && !bitset_contain (dests_ch[j], node->opr.c)) continue; /* Enumerate the intersection set of this state and `accepts'. */ has_intersec = 0; for (k = 0; k < BITSET_WORDS; ++k) has_intersec |= intersec[k] = accepts[k] & dests_ch[j][k]; /* And skip if the intersection set is empty. */ if (!has_intersec) continue; /* Then check if this state is a subset of `accepts'. */ not_subset = not_consumed = 0; for (k = 0; k < BITSET_WORDS; ++k) { not_subset |= remains[k] = ~accepts[k] & dests_ch[j][k]; not_consumed |= accepts[k] = accepts[k] & ~dests_ch[j][k]; } /* If this state isn't a subset of `accepts', create a new group state, which has the `remains'. */ if (not_subset) { bitset_copy (dests_ch[ndests], remains); bitset_copy (dests_ch[j], intersec); err = re_node_set_init_copy (dests_node + ndests, &dests_node[j]); if (BE (err != REG_NOERROR, 0)) goto error_return; ++ndests; } /* Put the position in the current group. */ result = re_node_set_insert (&dests_node[j], cur_nodes->elems[i]); if (BE (result < 0, 0)) goto error_return; /* If all characters are consumed, go to next node. */ if (!not_consumed) break; } /* Some characters remain, create a new group. */ if (j == ndests) { bitset_copy (dests_ch[ndests], accepts); err = re_node_set_init_1 (dests_node + ndests, cur_nodes->elems[i]); if (BE (err != REG_NOERROR, 0)) goto error_return; ++ndests; bitset_empty (accepts); } } return ndests; error_return: for (j = 0; j < ndests; ++j) re_node_set_free (dests_node + j); return -1; } #ifdef RE_ENABLE_I18N /* Check how many bytes the node `dfa->nodes[node_idx]' accepts. Return the number of the bytes the node accepts. STR_IDX is the current index of the input string. This function handles the nodes which can accept one character, or one collating element like '.', '[a-z]', opposite to the other nodes can only accept one byte. */ static int internal_function check_node_accept_bytes (const re_dfa_t *dfa, int node_idx, const re_string_t *input, int str_idx) { const re_token_t *node = dfa->nodes + node_idx; int char_len, elem_len; int i; wint_t wc; if (BE (node->type == OP_UTF8_PERIOD, 0)) { unsigned char c = re_string_byte_at (input, str_idx), d; if (BE (c < 0xc2, 1)) return 0; if (str_idx + 2 > input->len) return 0; d = re_string_byte_at (input, str_idx + 1); if (c < 0xe0) return (d < 0x80 || d > 0xbf) ? 0 : 2; else if (c < 0xf0) { char_len = 3; if (c == 0xe0 && d < 0xa0) return 0; } else if (c < 0xf8) { char_len = 4; if (c == 0xf0 && d < 0x90) return 0; } else if (c < 0xfc) { char_len = 5; if (c == 0xf8 && d < 0x88) return 0; } else if (c < 0xfe) { char_len = 6; if (c == 0xfc && d < 0x84) return 0; } else return 0; if (str_idx + char_len > input->len) return 0; for (i = 1; i < char_len; ++i) { d = re_string_byte_at (input, str_idx + i); if (d < 0x80 || d > 0xbf) return 0; } return char_len; } char_len = re_string_char_size_at (input, str_idx); if (node->type == OP_PERIOD) { if (char_len <= 1) return 0; /* FIXME: I don't think this if is needed, as both '\n' and '\0' are char_len == 1. */ /* '.' accepts any one character except the following two cases. */ if ((!(dfa->syntax & RE_DOT_NEWLINE) && re_string_byte_at (input, str_idx) == '\n') || ((dfa->syntax & RE_DOT_NOT_NULL) && re_string_byte_at (input, str_idx) == '\0')) return 0; return char_len; } elem_len = re_string_elem_size_at (input, str_idx); wc = __btowc(*(input->mbs+str_idx)); if (((elem_len <= 1 && char_len <= 1) || char_len == 0) && (wc != WEOF && wc < SBC_MAX)) return 0; if (node->type == COMPLEX_BRACKET) { const re_charset_t *cset = node->opr.mbcset; # ifdef _LIBC const unsigned char *pin = ((const unsigned char *) re_string_get_buffer (input) + str_idx); int j; uint32_t nrules; # endif /* _LIBC */ int match_len = 0; wchar_t wc = ((cset->nranges || cset->nchar_classes || cset->nmbchars) ? re_string_wchar_at (input, str_idx) : 0); /* match with multibyte character? */ for (i = 0; i < cset->nmbchars; ++i) if (wc == cset->mbchars[i]) { match_len = char_len; goto check_node_accept_bytes_match; } /* match with character_class? */ for (i = 0; i < cset->nchar_classes; ++i) { wctype_t wt = cset->char_classes[i]; if (__iswctype (wc, wt)) { match_len = char_len; goto check_node_accept_bytes_match; } } # ifdef _LIBC nrules = _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES); if (nrules != 0) { unsigned int in_collseq = 0; const int32_t *table, *indirect; const unsigned char *weights, *extra; const char *collseqwc; /* This #include defines a local function! */ # include /* match with collating_symbol? */ if (cset->ncoll_syms) extra = (const unsigned char *) _NL_CURRENT (LC_COLLATE, _NL_COLLATE_SYMB_EXTRAMB); for (i = 0; i < cset->ncoll_syms; ++i) { const unsigned char *coll_sym = extra + cset->coll_syms[i]; /* Compare the length of input collating element and the length of current collating element. */ if (*coll_sym != elem_len) continue; /* Compare each bytes. */ for (j = 0; j < *coll_sym; j++) if (pin[j] != coll_sym[1 + j]) break; if (j == *coll_sym) { /* Match if every bytes is equal. */ match_len = j; goto check_node_accept_bytes_match; } } if (cset->nranges) { if (elem_len <= char_len) { collseqwc = _NL_CURRENT (LC_COLLATE, _NL_COLLATE_COLLSEQWC); in_collseq = __collseq_table_lookup (collseqwc, wc); } else in_collseq = find_collation_sequence_value (pin, elem_len); } /* match with range expression? */ for (i = 0; i < cset->nranges; ++i) if (cset->range_starts[i] <= in_collseq && in_collseq <= cset->range_ends[i]) { match_len = elem_len; goto check_node_accept_bytes_match; } /* match with equivalence_class? */ if (cset->nequiv_classes) { const unsigned char *cp = pin; table = (const int32_t *) _NL_CURRENT (LC_COLLATE, _NL_COLLATE_TABLEMB); weights = (const unsigned char *) _NL_CURRENT (LC_COLLATE, _NL_COLLATE_WEIGHTMB); extra = (const unsigned char *) _NL_CURRENT (LC_COLLATE, _NL_COLLATE_EXTRAMB); indirect = (const int32_t *) _NL_CURRENT (LC_COLLATE, _NL_COLLATE_INDIRECTMB); int32_t idx = findidx (&cp); if (idx > 0) for (i = 0; i < cset->nequiv_classes; ++i) { int32_t equiv_class_idx = cset->equiv_classes[i]; size_t weight_len = weights[idx & 0xffffff]; if (weight_len == weights[equiv_class_idx & 0xffffff] && (idx >> 24) == (equiv_class_idx >> 24)) { int cnt = 0; idx &= 0xffffff; equiv_class_idx &= 0xffffff; while (cnt <= weight_len && (weights[equiv_class_idx + 1 + cnt] == weights[idx + 1 + cnt])) ++cnt; if (cnt > weight_len) { match_len = elem_len; goto check_node_accept_bytes_match; } } } } } else # endif /* _LIBC */ { /* match with range expression? */ #if __GNUC__ >= 2 wchar_t cmp_buf[] = {L'\0', L'\0', wc, L'\0', L'\0', L'\0'}; #else wchar_t cmp_buf[] = {L'\0', L'\0', L'\0', L'\0', L'\0', L'\0'}; cmp_buf[2] = wc; #endif for (i = 0; i < cset->nranges; ++i) { cmp_buf[0] = cset->range_starts[i]; cmp_buf[4] = cset->range_ends[i]; if (wcscoll (cmp_buf, cmp_buf + 2) <= 0 && wcscoll (cmp_buf + 2, cmp_buf + 4) <= 0) { match_len = char_len; goto check_node_accept_bytes_match; } } } check_node_accept_bytes_match: if (!cset->non_match) return match_len; else { if (match_len > 0) return 0; else return (elem_len > char_len) ? elem_len : char_len; } } return 0; } # ifdef _LIBC static unsigned int internal_function find_collation_sequence_value (const unsigned char *mbs, size_t mbs_len) { uint32_t nrules = _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES); if (nrules == 0) { if (mbs_len == 1) { /* No valid character. Match it as a single byte character. */ const unsigned char *collseq = (const unsigned char *) _NL_CURRENT (LC_COLLATE, _NL_COLLATE_COLLSEQMB); return collseq[mbs[0]]; } return UINT_MAX; } else { int32_t idx; const unsigned char *extra = (const unsigned char *) _NL_CURRENT (LC_COLLATE, _NL_COLLATE_SYMB_EXTRAMB); int32_t extrasize = (const unsigned char *) _NL_CURRENT (LC_COLLATE, _NL_COLLATE_SYMB_EXTRAMB + 1) - extra; for (idx = 0; idx < extrasize;) { int mbs_cnt, found = 0; int32_t elem_mbs_len; /* Skip the name of collating element name. */ idx = idx + extra[idx] + 1; elem_mbs_len = extra[idx++]; if (mbs_len == elem_mbs_len) { for (mbs_cnt = 0; mbs_cnt < elem_mbs_len; ++mbs_cnt) if (extra[idx + mbs_cnt] != mbs[mbs_cnt]) break; if (mbs_cnt == elem_mbs_len) /* Found the entry. */ found = 1; } /* Skip the byte sequence of the collating element. */ idx += elem_mbs_len; /* Adjust for the alignment. */ idx = (idx + 3) & ~3; /* Skip the collation sequence value. */ idx += sizeof (uint32_t); /* Skip the wide char sequence of the collating element. */ idx = idx + sizeof (uint32_t) * (extra[idx] + 1); /* If we found the entry, return the sequence value. */ if (found) return *(uint32_t *) (extra + idx); /* Skip the collation sequence value. */ idx += sizeof (uint32_t); } return UINT_MAX; } } # endif /* _LIBC */ #endif /* RE_ENABLE_I18N */ /* Check whether the node accepts the byte which is IDX-th byte of the INPUT. */ static int internal_function check_node_accept (const re_match_context_t *mctx, const re_token_t *node, int idx) { unsigned char ch; ch = re_string_byte_at (&mctx->input, idx); switch (node->type) { case CHARACTER: if (node->opr.c != ch) return 0; break; case SIMPLE_BRACKET: if (!bitset_contain (node->opr.sbcset, ch)) return 0; break; #ifdef RE_ENABLE_I18N case OP_UTF8_PERIOD: if (ch >= 0x80) return 0; /* FALLTHROUGH */ #endif case OP_PERIOD: if ((ch == '\n' && !(mctx->dfa->syntax & RE_DOT_NEWLINE)) || (ch == '\0' && (mctx->dfa->syntax & RE_DOT_NOT_NULL))) return 0; break; default: return 0; } if (node->constraint) { /* The node has constraints. Check whether the current context satisfies the constraints. */ unsigned int context = re_string_context_at (&mctx->input, idx, mctx->eflags); if (NOT_SATISFY_NEXT_CONSTRAINT (node->constraint, context)) return 0; } return 1; } /* Extend the buffers, if the buffers have run out. */ static reg_errcode_t internal_function extend_buffers (re_match_context_t *mctx) { reg_errcode_t ret; re_string_t *pstr = &mctx->input; /* Avoid overflow. */ if (BE (INT_MAX / 2 / sizeof (re_dfastate_t *) <= (size_t)pstr->bufs_len, 0)) return REG_ESPACE; /* Double the lengthes of the buffers. */ ret = re_string_realloc_buffers (pstr, pstr->bufs_len * 2); if (BE (ret != REG_NOERROR, 0)) return ret; if (mctx->state_log != NULL) { /* And double the length of state_log. */ /* XXX We have no indication of the size of this buffer. If this allocation fail we have no indication that the state_log array does not have the right size. */ re_dfastate_t **new_array = re_realloc (mctx->state_log, re_dfastate_t *, pstr->bufs_len + 1); if (BE (new_array == NULL, 0)) return REG_ESPACE; mctx->state_log = new_array; } /* Then reconstruct the buffers. */ if (pstr->icase) { #ifdef RE_ENABLE_I18N if (pstr->mb_cur_max > 1) { ret = build_wcs_upper_buffer (pstr); if (BE (ret != REG_NOERROR, 0)) return ret; } else #endif /* RE_ENABLE_I18N */ build_upper_buffer (pstr); } else { #ifdef RE_ENABLE_I18N if (pstr->mb_cur_max > 1) build_wcs_buffer (pstr); else #endif /* RE_ENABLE_I18N */ { if (pstr->trans != NULL) re_string_translate_buffer (pstr); } } return REG_NOERROR; } /* Functions for matching context. */ /* Initialize MCTX. */ static reg_errcode_t internal_function match_ctx_init (re_match_context_t *mctx, int eflags, int n) { mctx->eflags = eflags; mctx->match_last = -1; if (n > 0) { mctx->bkref_ents = re_malloc (struct re_backref_cache_entry, n); mctx->sub_tops = re_malloc (re_sub_match_top_t *, n); if (BE (mctx->bkref_ents == NULL || mctx->sub_tops == NULL, 0)) return REG_ESPACE; } /* Already zero-ed by the caller. else mctx->bkref_ents = NULL; mctx->nbkref_ents = 0; mctx->nsub_tops = 0; */ mctx->abkref_ents = n; mctx->max_mb_elem_len = 1; mctx->asub_tops = n; return REG_NOERROR; } /* Clean the entries which depend on the current input in MCTX. This function must be invoked when the matcher changes the start index of the input, or changes the input string. */ static void internal_function match_ctx_clean (re_match_context_t *mctx) { int st_idx; for (st_idx = 0; st_idx < mctx->nsub_tops; ++st_idx) { int sl_idx; re_sub_match_top_t *top = mctx->sub_tops[st_idx]; for (sl_idx = 0; sl_idx < top->nlasts; ++sl_idx) { re_sub_match_last_t *last = top->lasts[sl_idx]; re_free (last->path.array); re_free (last); } re_free (top->lasts); if (top->path) { re_free (top->path->array); re_free (top->path); } free (top); } mctx->nsub_tops = 0; mctx->nbkref_ents = 0; } /* Free all the memory associated with MCTX. */ static void internal_function match_ctx_free (re_match_context_t *mctx) { /* First, free all the memory associated with MCTX->SUB_TOPS. */ match_ctx_clean (mctx); re_free (mctx->sub_tops); re_free (mctx->bkref_ents); } /* Add a new backreference entry to MCTX. Note that we assume that caller never call this function with duplicate entry, and call with STR_IDX which isn't smaller than any existing entry. */ static reg_errcode_t internal_function match_ctx_add_entry (re_match_context_t *mctx, int node, int str_idx, int from, int to) { if (mctx->nbkref_ents >= mctx->abkref_ents) { struct re_backref_cache_entry* new_entry; new_entry = re_realloc (mctx->bkref_ents, struct re_backref_cache_entry, mctx->abkref_ents * 2); if (BE (new_entry == NULL, 0)) { re_free (mctx->bkref_ents); return REG_ESPACE; } mctx->bkref_ents = new_entry; memset (mctx->bkref_ents + mctx->nbkref_ents, '\0', sizeof (struct re_backref_cache_entry) * mctx->abkref_ents); mctx->abkref_ents *= 2; } if (mctx->nbkref_ents > 0 && mctx->bkref_ents[mctx->nbkref_ents - 1].str_idx == str_idx) mctx->bkref_ents[mctx->nbkref_ents - 1].more = 1; mctx->bkref_ents[mctx->nbkref_ents].node = node; mctx->bkref_ents[mctx->nbkref_ents].str_idx = str_idx; mctx->bkref_ents[mctx->nbkref_ents].subexp_from = from; mctx->bkref_ents[mctx->nbkref_ents].subexp_to = to; /* This is a cache that saves negative results of check_dst_limits_calc_pos. If bit N is clear, means that this entry won't epsilon-transition to an OP_OPEN_SUBEXP or OP_CLOSE_SUBEXP for the N+1-th subexpression. If it is set, check_dst_limits_calc_pos_1 will recurse and try to find one such node. A backreference does not epsilon-transition unless it is empty, so set to all zeros if FROM != TO. */ mctx->bkref_ents[mctx->nbkref_ents].eps_reachable_subexps_map = (from == to ? ~0 : 0); mctx->bkref_ents[mctx->nbkref_ents++].more = 0; if (mctx->max_mb_elem_len < to - from) mctx->max_mb_elem_len = to - from; return REG_NOERROR; } /* Search for the first entry which has the same str_idx, or -1 if none is found. Note that MCTX->BKREF_ENTS is already sorted by MCTX->STR_IDX. */ static int internal_function search_cur_bkref_entry (const re_match_context_t *mctx, int str_idx) { int left, right, mid, last; last = right = mctx->nbkref_ents; for (left = 0; left < right;) { mid = (left + right) / 2; if (mctx->bkref_ents[mid].str_idx < str_idx) left = mid + 1; else right = mid; } if (left < last && mctx->bkref_ents[left].str_idx == str_idx) return left; else return -1; } /* Register the node NODE, whose type is OP_OPEN_SUBEXP, and which matches at STR_IDX. */ static reg_errcode_t internal_function match_ctx_add_subtop (re_match_context_t *mctx, int node, int str_idx) { #ifdef DEBUG assert (mctx->sub_tops != NULL); assert (mctx->asub_tops > 0); #endif if (BE (mctx->nsub_tops == mctx->asub_tops, 0)) { int new_asub_tops = mctx->asub_tops * 2; re_sub_match_top_t **new_array = re_realloc (mctx->sub_tops, re_sub_match_top_t *, new_asub_tops); if (BE (new_array == NULL, 0)) return REG_ESPACE; mctx->sub_tops = new_array; mctx->asub_tops = new_asub_tops; } mctx->sub_tops[mctx->nsub_tops] = calloc (1, sizeof (re_sub_match_top_t)); if (BE (mctx->sub_tops[mctx->nsub_tops] == NULL, 0)) return REG_ESPACE; mctx->sub_tops[mctx->nsub_tops]->node = node; mctx->sub_tops[mctx->nsub_tops++]->str_idx = str_idx; return REG_NOERROR; } /* Register the node NODE, whose type is OP_CLOSE_SUBEXP, and which matches at STR_IDX, whose corresponding OP_OPEN_SUBEXP is SUB_TOP. */ static re_sub_match_last_t * internal_function match_ctx_add_sublast (re_sub_match_top_t *subtop, int node, int str_idx) { re_sub_match_last_t *new_entry; if (BE (subtop->nlasts == subtop->alasts, 0)) { int new_alasts = 2 * subtop->alasts + 1; re_sub_match_last_t **new_array = re_realloc (subtop->lasts, re_sub_match_last_t *, new_alasts); if (BE (new_array == NULL, 0)) return NULL; subtop->lasts = new_array; subtop->alasts = new_alasts; } new_entry = calloc (1, sizeof (re_sub_match_last_t)); if (BE (new_entry != NULL, 1)) { subtop->lasts[subtop->nlasts] = new_entry; new_entry->node = node; new_entry->str_idx = str_idx; ++subtop->nlasts; } return new_entry; } static void internal_function sift_ctx_init (re_sift_context_t *sctx, re_dfastate_t **sifted_sts, re_dfastate_t **limited_sts, int last_node, int last_str_idx) { sctx->sifted_states = sifted_sts; sctx->limited_states = limited_sts; sctx->last_node = last_node; sctx->last_str_idx = last_str_idx; re_node_set_init_empty (&sctx->limits); } libgit2-0.19.0/deps/zlib/000077500000000000000000000000001216214232500150265ustar00rootroot00000000000000libgit2-0.19.0/deps/zlib/adler32.c000066400000000000000000000116701216214232500164330ustar00rootroot00000000000000/* 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); } libgit2-0.19.0/deps/zlib/crc32.c000066400000000000000000000325611216214232500161150ustar00rootroot00000000000000/* crc32.c -- compute the CRC-32 of a data stream * Copyright (C) 1995-2006, 2010 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h * * Thanks to Rodney Brown for his contribution of faster * CRC methods: exclusive-oring 32 bits of data at a time, and pre-computing * tables for updating the shift register in one step with three exclusive-ors * instead of four steps with four exclusive-ors. This results in about a * factor of two increase in speed on a Power PC G4 (PPC7455) using gcc -O3. */ /* @(#) $Id$ */ /* Note on the use of DYNAMIC_CRC_TABLE: there is no mutex or semaphore protection on the static variables used to control the first-use generation of the crc tables. Therefore, if you #define DYNAMIC_CRC_TABLE, you should first call get_crc_table() to initialize the tables before allowing more than one thread to use crc32(). */ #ifdef MAKECRCH # include # ifndef DYNAMIC_CRC_TABLE # define DYNAMIC_CRC_TABLE # endif /* !DYNAMIC_CRC_TABLE */ #endif /* MAKECRCH */ #include "zutil.h" /* for STDC and FAR definitions */ #define local static /* Find a four-byte integer type for crc32_little() and crc32_big(). */ #ifndef NOBYFOUR # ifdef STDC /* need ANSI C limits.h to determine sizes */ # include # define BYFOUR # if (UINT_MAX == 0xffffffffUL) typedef unsigned int u4; # else # if (ULONG_MAX == 0xffffffffUL) typedef unsigned long u4; # else # if (USHRT_MAX == 0xffffffffUL) typedef unsigned short u4; # else # undef BYFOUR /* can't find a four-byte integer type! */ # endif # endif # endif # endif /* STDC */ #endif /* !NOBYFOUR */ /* Definitions for doing the crc four data bytes at a time. */ #ifdef BYFOUR # define REV(w) ((((w)>>24)&0xff)+(((w)>>8)&0xff00)+ \ (((w)&0xff00)<<8)+(((w)&0xff)<<24)) local unsigned long crc32_little OF((unsigned long, const unsigned char FAR *, unsigned)); local unsigned long crc32_big OF((unsigned long, const unsigned char FAR *, unsigned)); # define TBLS 8 #else # define TBLS 1 #endif /* BYFOUR */ /* Local functions for crc concatenation */ local unsigned long gf2_matrix_times OF((unsigned long *mat, unsigned long vec)); local void gf2_matrix_square OF((unsigned long *square, unsigned long *mat)); local uLong crc32_combine_(uLong crc1, uLong crc2, z_off64_t len2); #ifdef DYNAMIC_CRC_TABLE local volatile int crc_table_empty = 1; local unsigned long FAR crc_table[TBLS][256]; local void make_crc_table OF((void)); #ifdef MAKECRCH local void write_table OF((FILE *, const unsigned long FAR *)); #endif /* MAKECRCH */ /* Generate tables for a byte-wise 32-bit CRC calculation on the polynomial: x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1. Polynomials over GF(2) are represented in binary, one bit per coefficient, with the lowest powers in the most significant bit. Then adding polynomials is just exclusive-or, and multiplying a polynomial by x is a right shift by one. If we call the above polynomial p, and represent a byte as the polynomial q, also with the lowest power in the most significant bit (so the byte 0xb1 is the polynomial x^7+x^3+x+1), then the CRC is (q*x^32) mod p, where a mod b means the remainder after dividing a by b. This calculation is done using the shift-register method of multiplying and taking the remainder. The register is initialized to zero, and for each incoming bit, x^32 is added mod p to the register if the bit is a one (where x^32 mod p is p+x^32 = x^26+...+1), and the register is multiplied mod p by x (which is shifting right by one and adding x^32 mod p if the bit shifted out is a one). We start with the highest power (least significant bit) of q and repeat for all eight bits of q. The first table is simply the CRC of all possible eight bit values. This is all the information needed to generate CRCs on data a byte at a time for all combinations of CRC register values and incoming bytes. The remaining tables allow for word-at-a-time CRC calculation for both big-endian and little- endian machines, where a word is four bytes. */ local void make_crc_table() { unsigned long c; int n, k; unsigned long poly; /* polynomial exclusive-or pattern */ /* terms of polynomial defining this crc (except x^32): */ static volatile int first = 1; /* flag to limit concurrent making */ static const unsigned char p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26}; /* See if another task is already doing this (not thread-safe, but better than nothing -- significantly reduces duration of vulnerability in case the advice about DYNAMIC_CRC_TABLE is ignored) */ if (first) { first = 0; /* make exclusive-or pattern from polynomial (0xedb88320UL) */ poly = 0UL; for (n = 0; n < sizeof(p)/sizeof(unsigned char); n++) poly |= 1UL << (31 - p[n]); /* generate a crc for every 8-bit value */ for (n = 0; n < 256; n++) { c = (unsigned long)n; for (k = 0; k < 8; k++) c = c & 1 ? poly ^ (c >> 1) : c >> 1; crc_table[0][n] = c; } #ifdef BYFOUR /* generate crc for each value followed by one, two, and three zeros, and then the byte reversal of those as well as the first table */ for (n = 0; n < 256; n++) { c = crc_table[0][n]; crc_table[4][n] = REV(c); for (k = 1; k < 4; k++) { c = crc_table[0][c & 0xff] ^ (c >> 8); crc_table[k][n] = c; crc_table[k + 4][n] = REV(c); } } #endif /* BYFOUR */ crc_table_empty = 0; } else { /* not first */ /* wait for the other guy to finish (not efficient, but rare) */ while (crc_table_empty) ; } #ifdef MAKECRCH /* write out CRC tables to crc32.h */ { FILE *out; out = fopen("crc32.h", "w"); if (out == NULL) return; fprintf(out, "/* crc32.h -- tables for rapid CRC calculation\n"); fprintf(out, " * Generated automatically by crc32.c\n */\n\n"); fprintf(out, "local const unsigned long FAR "); fprintf(out, "crc_table[TBLS][256] =\n{\n {\n"); write_table(out, crc_table[0]); # ifdef BYFOUR fprintf(out, "#ifdef BYFOUR\n"); for (k = 1; k < 8; k++) { fprintf(out, " },\n {\n"); write_table(out, crc_table[k]); } fprintf(out, "#endif\n"); # endif /* BYFOUR */ fprintf(out, " }\n};\n"); fclose(out); } #endif /* MAKECRCH */ } #ifdef MAKECRCH local void write_table(out, table) FILE *out; const unsigned long FAR *table; { int n; for (n = 0; n < 256; n++) fprintf(out, "%s0x%08lxUL%s", n % 5 ? "" : " ", table[n], n == 255 ? "\n" : (n % 5 == 4 ? ",\n" : ", ")); } #endif /* MAKECRCH */ #else /* !DYNAMIC_CRC_TABLE */ /* ======================================================================== * Tables of CRC-32s of all single-byte values, made by make_crc_table(). */ #include "crc32.h" #endif /* DYNAMIC_CRC_TABLE */ /* ========================================================================= * This function can be used by asm versions of crc32() */ const unsigned long FAR * ZEXPORT get_crc_table() { #ifdef DYNAMIC_CRC_TABLE if (crc_table_empty) make_crc_table(); #endif /* DYNAMIC_CRC_TABLE */ return (const unsigned long FAR *)crc_table; } /* ========================================================================= */ #define DO1 crc = crc_table[0][((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8) #define DO8 DO1; DO1; DO1; DO1; DO1; DO1; DO1; DO1 /* ========================================================================= */ unsigned long ZEXPORT crc32(crc, buf, len) unsigned long crc; const unsigned char FAR *buf; uInt len; { if (buf == Z_NULL) return 0UL; #ifdef DYNAMIC_CRC_TABLE if (crc_table_empty) make_crc_table(); #endif /* DYNAMIC_CRC_TABLE */ #ifdef BYFOUR if (sizeof(void *) == sizeof(ptrdiff_t)) { u4 endian; endian = 1; if (*((unsigned char *)(&endian))) return crc32_little(crc, buf, len); else return crc32_big(crc, buf, len); } #endif /* BYFOUR */ crc = crc ^ 0xffffffffUL; while (len >= 8) { DO8; len -= 8; } if (len) do { DO1; } while (--len); return crc ^ 0xffffffffUL; } #ifdef BYFOUR /* ========================================================================= */ #define DOLIT4 c ^= *buf4++; \ c = crc_table[3][c & 0xff] ^ crc_table[2][(c >> 8) & 0xff] ^ \ crc_table[1][(c >> 16) & 0xff] ^ crc_table[0][c >> 24] #define DOLIT32 DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4 /* ========================================================================= */ local unsigned long crc32_little(crc, buf, len) unsigned long crc; const unsigned char FAR *buf; unsigned len; { register u4 c; register const u4 FAR *buf4; c = (u4)crc; c = ~c; while (len && ((ptrdiff_t)buf & 3)) { c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8); len--; } buf4 = (const u4 FAR *)(const void FAR *)buf; while (len >= 32) { DOLIT32; len -= 32; } while (len >= 4) { DOLIT4; len -= 4; } buf = (const unsigned char FAR *)buf4; if (len) do { c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8); } while (--len); c = ~c; return (unsigned long)c; } /* ========================================================================= */ #define DOBIG4 c ^= *++buf4; \ c = crc_table[4][c & 0xff] ^ crc_table[5][(c >> 8) & 0xff] ^ \ crc_table[6][(c >> 16) & 0xff] ^ crc_table[7][c >> 24] #define DOBIG32 DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4 /* ========================================================================= */ local unsigned long crc32_big(crc, buf, len) unsigned long crc; const unsigned char FAR *buf; unsigned len; { register u4 c; register const u4 FAR *buf4; c = REV((u4)crc); c = ~c; while (len && ((ptrdiff_t)buf & 3)) { c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8); len--; } buf4 = (const u4 FAR *)(const void FAR *)buf; buf4--; while (len >= 32) { DOBIG32; len -= 32; } while (len >= 4) { DOBIG4; len -= 4; } buf4++; buf = (const unsigned char FAR *)buf4; if (len) do { c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8); } while (--len); c = ~c; return (unsigned long)(REV(c)); } #endif /* BYFOUR */ #define GF2_DIM 32 /* dimension of GF(2) vectors (length of CRC) */ /* ========================================================================= */ local unsigned long gf2_matrix_times(mat, vec) unsigned long *mat; unsigned long vec; { unsigned long sum; sum = 0; while (vec) { if (vec & 1) sum ^= *mat; vec >>= 1; mat++; } return sum; } /* ========================================================================= */ local void gf2_matrix_square(square, mat) unsigned long *square; unsigned long *mat; { int n; for (n = 0; n < GF2_DIM; n++) square[n] = gf2_matrix_times(mat, mat[n]); } /* ========================================================================= */ local uLong crc32_combine_(crc1, crc2, len2) uLong crc1; uLong crc2; z_off64_t len2; { int n; unsigned long row; unsigned long even[GF2_DIM]; /* even-power-of-two zeros operator */ unsigned long odd[GF2_DIM]; /* odd-power-of-two zeros operator */ /* degenerate case (also disallow negative lengths) */ if (len2 <= 0) return crc1; /* put operator for one zero bit in odd */ odd[0] = 0xedb88320UL; /* CRC-32 polynomial */ row = 1; for (n = 1; n < GF2_DIM; n++) { odd[n] = row; row <<= 1; } /* put operator for two zero bits in even */ gf2_matrix_square(even, odd); /* put operator for four zero bits in odd */ gf2_matrix_square(odd, even); /* apply len2 zeros to crc1 (first square will put the operator for one zero byte, eight zero bits, in even) */ do { /* apply zeros operator for this bit of len2 */ gf2_matrix_square(even, odd); if (len2 & 1) crc1 = gf2_matrix_times(even, crc1); len2 >>= 1; /* if no more bits set, then done */ if (len2 == 0) break; /* another iteration of the loop with odd and even swapped */ gf2_matrix_square(odd, even); if (len2 & 1) crc1 = gf2_matrix_times(odd, crc1); len2 >>= 1; /* if no more bits set, then done */ } while (len2 != 0); /* return combined crc */ crc1 ^= crc2; return crc1; } /* ========================================================================= */ uLong ZEXPORT crc32_combine(crc1, crc2, len2) uLong crc1; uLong crc2; z_off_t len2; { return crc32_combine_(crc1, crc2, len2); } uLong ZEXPORT crc32_combine64(crc1, crc2, len2) uLong crc1; uLong crc2; z_off64_t len2; { return crc32_combine_(crc1, crc2, len2); } libgit2-0.19.0/deps/zlib/crc32.h000066400000000000000000000735501216214232500161250ustar00rootroot00000000000000/* crc32.h -- tables for rapid CRC calculation * Generated automatically by crc32.c */ local const unsigned long FAR crc_table[TBLS][256] = { { 0x00000000UL, 0x77073096UL, 0xee0e612cUL, 0x990951baUL, 0x076dc419UL, 0x706af48fUL, 0xe963a535UL, 0x9e6495a3UL, 0x0edb8832UL, 0x79dcb8a4UL, 0xe0d5e91eUL, 0x97d2d988UL, 0x09b64c2bUL, 0x7eb17cbdUL, 0xe7b82d07UL, 0x90bf1d91UL, 0x1db71064UL, 0x6ab020f2UL, 0xf3b97148UL, 0x84be41deUL, 0x1adad47dUL, 0x6ddde4ebUL, 0xf4d4b551UL, 0x83d385c7UL, 0x136c9856UL, 0x646ba8c0UL, 0xfd62f97aUL, 0x8a65c9ecUL, 0x14015c4fUL, 0x63066cd9UL, 0xfa0f3d63UL, 0x8d080df5UL, 0x3b6e20c8UL, 0x4c69105eUL, 0xd56041e4UL, 0xa2677172UL, 0x3c03e4d1UL, 0x4b04d447UL, 0xd20d85fdUL, 0xa50ab56bUL, 0x35b5a8faUL, 0x42b2986cUL, 0xdbbbc9d6UL, 0xacbcf940UL, 0x32d86ce3UL, 0x45df5c75UL, 0xdcd60dcfUL, 0xabd13d59UL, 0x26d930acUL, 0x51de003aUL, 0xc8d75180UL, 0xbfd06116UL, 0x21b4f4b5UL, 0x56b3c423UL, 0xcfba9599UL, 0xb8bda50fUL, 0x2802b89eUL, 0x5f058808UL, 0xc60cd9b2UL, 0xb10be924UL, 0x2f6f7c87UL, 0x58684c11UL, 0xc1611dabUL, 0xb6662d3dUL, 0x76dc4190UL, 0x01db7106UL, 0x98d220bcUL, 0xefd5102aUL, 0x71b18589UL, 0x06b6b51fUL, 0x9fbfe4a5UL, 0xe8b8d433UL, 0x7807c9a2UL, 0x0f00f934UL, 0x9609a88eUL, 0xe10e9818UL, 0x7f6a0dbbUL, 0x086d3d2dUL, 0x91646c97UL, 0xe6635c01UL, 0x6b6b51f4UL, 0x1c6c6162UL, 0x856530d8UL, 0xf262004eUL, 0x6c0695edUL, 0x1b01a57bUL, 0x8208f4c1UL, 0xf50fc457UL, 0x65b0d9c6UL, 0x12b7e950UL, 0x8bbeb8eaUL, 0xfcb9887cUL, 0x62dd1ddfUL, 0x15da2d49UL, 0x8cd37cf3UL, 0xfbd44c65UL, 0x4db26158UL, 0x3ab551ceUL, 0xa3bc0074UL, 0xd4bb30e2UL, 0x4adfa541UL, 0x3dd895d7UL, 0xa4d1c46dUL, 0xd3d6f4fbUL, 0x4369e96aUL, 0x346ed9fcUL, 0xad678846UL, 0xda60b8d0UL, 0x44042d73UL, 0x33031de5UL, 0xaa0a4c5fUL, 0xdd0d7cc9UL, 0x5005713cUL, 0x270241aaUL, 0xbe0b1010UL, 0xc90c2086UL, 0x5768b525UL, 0x206f85b3UL, 0xb966d409UL, 0xce61e49fUL, 0x5edef90eUL, 0x29d9c998UL, 0xb0d09822UL, 0xc7d7a8b4UL, 0x59b33d17UL, 0x2eb40d81UL, 0xb7bd5c3bUL, 0xc0ba6cadUL, 0xedb88320UL, 0x9abfb3b6UL, 0x03b6e20cUL, 0x74b1d29aUL, 0xead54739UL, 0x9dd277afUL, 0x04db2615UL, 0x73dc1683UL, 0xe3630b12UL, 0x94643b84UL, 0x0d6d6a3eUL, 0x7a6a5aa8UL, 0xe40ecf0bUL, 0x9309ff9dUL, 0x0a00ae27UL, 0x7d079eb1UL, 0xf00f9344UL, 0x8708a3d2UL, 0x1e01f268UL, 0x6906c2feUL, 0xf762575dUL, 0x806567cbUL, 0x196c3671UL, 0x6e6b06e7UL, 0xfed41b76UL, 0x89d32be0UL, 0x10da7a5aUL, 0x67dd4accUL, 0xf9b9df6fUL, 0x8ebeeff9UL, 0x17b7be43UL, 0x60b08ed5UL, 0xd6d6a3e8UL, 0xa1d1937eUL, 0x38d8c2c4UL, 0x4fdff252UL, 0xd1bb67f1UL, 0xa6bc5767UL, 0x3fb506ddUL, 0x48b2364bUL, 0xd80d2bdaUL, 0xaf0a1b4cUL, 0x36034af6UL, 0x41047a60UL, 0xdf60efc3UL, 0xa867df55UL, 0x316e8eefUL, 0x4669be79UL, 0xcb61b38cUL, 0xbc66831aUL, 0x256fd2a0UL, 0x5268e236UL, 0xcc0c7795UL, 0xbb0b4703UL, 0x220216b9UL, 0x5505262fUL, 0xc5ba3bbeUL, 0xb2bd0b28UL, 0x2bb45a92UL, 0x5cb36a04UL, 0xc2d7ffa7UL, 0xb5d0cf31UL, 0x2cd99e8bUL, 0x5bdeae1dUL, 0x9b64c2b0UL, 0xec63f226UL, 0x756aa39cUL, 0x026d930aUL, 0x9c0906a9UL, 0xeb0e363fUL, 0x72076785UL, 0x05005713UL, 0x95bf4a82UL, 0xe2b87a14UL, 0x7bb12baeUL, 0x0cb61b38UL, 0x92d28e9bUL, 0xe5d5be0dUL, 0x7cdcefb7UL, 0x0bdbdf21UL, 0x86d3d2d4UL, 0xf1d4e242UL, 0x68ddb3f8UL, 0x1fda836eUL, 0x81be16cdUL, 0xf6b9265bUL, 0x6fb077e1UL, 0x18b74777UL, 0x88085ae6UL, 0xff0f6a70UL, 0x66063bcaUL, 0x11010b5cUL, 0x8f659effUL, 0xf862ae69UL, 0x616bffd3UL, 0x166ccf45UL, 0xa00ae278UL, 0xd70dd2eeUL, 0x4e048354UL, 0x3903b3c2UL, 0xa7672661UL, 0xd06016f7UL, 0x4969474dUL, 0x3e6e77dbUL, 0xaed16a4aUL, 0xd9d65adcUL, 0x40df0b66UL, 0x37d83bf0UL, 0xa9bcae53UL, 0xdebb9ec5UL, 0x47b2cf7fUL, 0x30b5ffe9UL, 0xbdbdf21cUL, 0xcabac28aUL, 0x53b39330UL, 0x24b4a3a6UL, 0xbad03605UL, 0xcdd70693UL, 0x54de5729UL, 0x23d967bfUL, 0xb3667a2eUL, 0xc4614ab8UL, 0x5d681b02UL, 0x2a6f2b94UL, 0xb40bbe37UL, 0xc30c8ea1UL, 0x5a05df1bUL, 0x2d02ef8dUL #ifdef BYFOUR }, { 0x00000000UL, 0x191b3141UL, 0x32366282UL, 0x2b2d53c3UL, 0x646cc504UL, 0x7d77f445UL, 0x565aa786UL, 0x4f4196c7UL, 0xc8d98a08UL, 0xd1c2bb49UL, 0xfaefe88aUL, 0xe3f4d9cbUL, 0xacb54f0cUL, 0xb5ae7e4dUL, 0x9e832d8eUL, 0x87981ccfUL, 0x4ac21251UL, 0x53d92310UL, 0x78f470d3UL, 0x61ef4192UL, 0x2eaed755UL, 0x37b5e614UL, 0x1c98b5d7UL, 0x05838496UL, 0x821b9859UL, 0x9b00a918UL, 0xb02dfadbUL, 0xa936cb9aUL, 0xe6775d5dUL, 0xff6c6c1cUL, 0xd4413fdfUL, 0xcd5a0e9eUL, 0x958424a2UL, 0x8c9f15e3UL, 0xa7b24620UL, 0xbea97761UL, 0xf1e8e1a6UL, 0xe8f3d0e7UL, 0xc3de8324UL, 0xdac5b265UL, 0x5d5daeaaUL, 0x44469febUL, 0x6f6bcc28UL, 0x7670fd69UL, 0x39316baeUL, 0x202a5aefUL, 0x0b07092cUL, 0x121c386dUL, 0xdf4636f3UL, 0xc65d07b2UL, 0xed705471UL, 0xf46b6530UL, 0xbb2af3f7UL, 0xa231c2b6UL, 0x891c9175UL, 0x9007a034UL, 0x179fbcfbUL, 0x0e848dbaUL, 0x25a9de79UL, 0x3cb2ef38UL, 0x73f379ffUL, 0x6ae848beUL, 0x41c51b7dUL, 0x58de2a3cUL, 0xf0794f05UL, 0xe9627e44UL, 0xc24f2d87UL, 0xdb541cc6UL, 0x94158a01UL, 0x8d0ebb40UL, 0xa623e883UL, 0xbf38d9c2UL, 0x38a0c50dUL, 0x21bbf44cUL, 0x0a96a78fUL, 0x138d96ceUL, 0x5ccc0009UL, 0x45d73148UL, 0x6efa628bUL, 0x77e153caUL, 0xbabb5d54UL, 0xa3a06c15UL, 0x888d3fd6UL, 0x91960e97UL, 0xded79850UL, 0xc7cca911UL, 0xece1fad2UL, 0xf5facb93UL, 0x7262d75cUL, 0x6b79e61dUL, 0x4054b5deUL, 0x594f849fUL, 0x160e1258UL, 0x0f152319UL, 0x243870daUL, 0x3d23419bUL, 0x65fd6ba7UL, 0x7ce65ae6UL, 0x57cb0925UL, 0x4ed03864UL, 0x0191aea3UL, 0x188a9fe2UL, 0x33a7cc21UL, 0x2abcfd60UL, 0xad24e1afUL, 0xb43fd0eeUL, 0x9f12832dUL, 0x8609b26cUL, 0xc94824abUL, 0xd05315eaUL, 0xfb7e4629UL, 0xe2657768UL, 0x2f3f79f6UL, 0x362448b7UL, 0x1d091b74UL, 0x04122a35UL, 0x4b53bcf2UL, 0x52488db3UL, 0x7965de70UL, 0x607eef31UL, 0xe7e6f3feUL, 0xfefdc2bfUL, 0xd5d0917cUL, 0xcccba03dUL, 0x838a36faUL, 0x9a9107bbUL, 0xb1bc5478UL, 0xa8a76539UL, 0x3b83984bUL, 0x2298a90aUL, 0x09b5fac9UL, 0x10aecb88UL, 0x5fef5d4fUL, 0x46f46c0eUL, 0x6dd93fcdUL, 0x74c20e8cUL, 0xf35a1243UL, 0xea412302UL, 0xc16c70c1UL, 0xd8774180UL, 0x9736d747UL, 0x8e2de606UL, 0xa500b5c5UL, 0xbc1b8484UL, 0x71418a1aUL, 0x685abb5bUL, 0x4377e898UL, 0x5a6cd9d9UL, 0x152d4f1eUL, 0x0c367e5fUL, 0x271b2d9cUL, 0x3e001cddUL, 0xb9980012UL, 0xa0833153UL, 0x8bae6290UL, 0x92b553d1UL, 0xddf4c516UL, 0xc4eff457UL, 0xefc2a794UL, 0xf6d996d5UL, 0xae07bce9UL, 0xb71c8da8UL, 0x9c31de6bUL, 0x852aef2aUL, 0xca6b79edUL, 0xd37048acUL, 0xf85d1b6fUL, 0xe1462a2eUL, 0x66de36e1UL, 0x7fc507a0UL, 0x54e85463UL, 0x4df36522UL, 0x02b2f3e5UL, 0x1ba9c2a4UL, 0x30849167UL, 0x299fa026UL, 0xe4c5aeb8UL, 0xfdde9ff9UL, 0xd6f3cc3aUL, 0xcfe8fd7bUL, 0x80a96bbcUL, 0x99b25afdUL, 0xb29f093eUL, 0xab84387fUL, 0x2c1c24b0UL, 0x350715f1UL, 0x1e2a4632UL, 0x07317773UL, 0x4870e1b4UL, 0x516bd0f5UL, 0x7a468336UL, 0x635db277UL, 0xcbfad74eUL, 0xd2e1e60fUL, 0xf9ccb5ccUL, 0xe0d7848dUL, 0xaf96124aUL, 0xb68d230bUL, 0x9da070c8UL, 0x84bb4189UL, 0x03235d46UL, 0x1a386c07UL, 0x31153fc4UL, 0x280e0e85UL, 0x674f9842UL, 0x7e54a903UL, 0x5579fac0UL, 0x4c62cb81UL, 0x8138c51fUL, 0x9823f45eUL, 0xb30ea79dUL, 0xaa1596dcUL, 0xe554001bUL, 0xfc4f315aUL, 0xd7626299UL, 0xce7953d8UL, 0x49e14f17UL, 0x50fa7e56UL, 0x7bd72d95UL, 0x62cc1cd4UL, 0x2d8d8a13UL, 0x3496bb52UL, 0x1fbbe891UL, 0x06a0d9d0UL, 0x5e7ef3ecUL, 0x4765c2adUL, 0x6c48916eUL, 0x7553a02fUL, 0x3a1236e8UL, 0x230907a9UL, 0x0824546aUL, 0x113f652bUL, 0x96a779e4UL, 0x8fbc48a5UL, 0xa4911b66UL, 0xbd8a2a27UL, 0xf2cbbce0UL, 0xebd08da1UL, 0xc0fdde62UL, 0xd9e6ef23UL, 0x14bce1bdUL, 0x0da7d0fcUL, 0x268a833fUL, 0x3f91b27eUL, 0x70d024b9UL, 0x69cb15f8UL, 0x42e6463bUL, 0x5bfd777aUL, 0xdc656bb5UL, 0xc57e5af4UL, 0xee530937UL, 0xf7483876UL, 0xb809aeb1UL, 0xa1129ff0UL, 0x8a3fcc33UL, 0x9324fd72UL }, { 0x00000000UL, 0x01c26a37UL, 0x0384d46eUL, 0x0246be59UL, 0x0709a8dcUL, 0x06cbc2ebUL, 0x048d7cb2UL, 0x054f1685UL, 0x0e1351b8UL, 0x0fd13b8fUL, 0x0d9785d6UL, 0x0c55efe1UL, 0x091af964UL, 0x08d89353UL, 0x0a9e2d0aUL, 0x0b5c473dUL, 0x1c26a370UL, 0x1de4c947UL, 0x1fa2771eUL, 0x1e601d29UL, 0x1b2f0bacUL, 0x1aed619bUL, 0x18abdfc2UL, 0x1969b5f5UL, 0x1235f2c8UL, 0x13f798ffUL, 0x11b126a6UL, 0x10734c91UL, 0x153c5a14UL, 0x14fe3023UL, 0x16b88e7aUL, 0x177ae44dUL, 0x384d46e0UL, 0x398f2cd7UL, 0x3bc9928eUL, 0x3a0bf8b9UL, 0x3f44ee3cUL, 0x3e86840bUL, 0x3cc03a52UL, 0x3d025065UL, 0x365e1758UL, 0x379c7d6fUL, 0x35dac336UL, 0x3418a901UL, 0x3157bf84UL, 0x3095d5b3UL, 0x32d36beaUL, 0x331101ddUL, 0x246be590UL, 0x25a98fa7UL, 0x27ef31feUL, 0x262d5bc9UL, 0x23624d4cUL, 0x22a0277bUL, 0x20e69922UL, 0x2124f315UL, 0x2a78b428UL, 0x2bbade1fUL, 0x29fc6046UL, 0x283e0a71UL, 0x2d711cf4UL, 0x2cb376c3UL, 0x2ef5c89aUL, 0x2f37a2adUL, 0x709a8dc0UL, 0x7158e7f7UL, 0x731e59aeUL, 0x72dc3399UL, 0x7793251cUL, 0x76514f2bUL, 0x7417f172UL, 0x75d59b45UL, 0x7e89dc78UL, 0x7f4bb64fUL, 0x7d0d0816UL, 0x7ccf6221UL, 0x798074a4UL, 0x78421e93UL, 0x7a04a0caUL, 0x7bc6cafdUL, 0x6cbc2eb0UL, 0x6d7e4487UL, 0x6f38fadeUL, 0x6efa90e9UL, 0x6bb5866cUL, 0x6a77ec5bUL, 0x68315202UL, 0x69f33835UL, 0x62af7f08UL, 0x636d153fUL, 0x612bab66UL, 0x60e9c151UL, 0x65a6d7d4UL, 0x6464bde3UL, 0x662203baUL, 0x67e0698dUL, 0x48d7cb20UL, 0x4915a117UL, 0x4b531f4eUL, 0x4a917579UL, 0x4fde63fcUL, 0x4e1c09cbUL, 0x4c5ab792UL, 0x4d98dda5UL, 0x46c49a98UL, 0x4706f0afUL, 0x45404ef6UL, 0x448224c1UL, 0x41cd3244UL, 0x400f5873UL, 0x4249e62aUL, 0x438b8c1dUL, 0x54f16850UL, 0x55330267UL, 0x5775bc3eUL, 0x56b7d609UL, 0x53f8c08cUL, 0x523aaabbUL, 0x507c14e2UL, 0x51be7ed5UL, 0x5ae239e8UL, 0x5b2053dfUL, 0x5966ed86UL, 0x58a487b1UL, 0x5deb9134UL, 0x5c29fb03UL, 0x5e6f455aUL, 0x5fad2f6dUL, 0xe1351b80UL, 0xe0f771b7UL, 0xe2b1cfeeUL, 0xe373a5d9UL, 0xe63cb35cUL, 0xe7fed96bUL, 0xe5b86732UL, 0xe47a0d05UL, 0xef264a38UL, 0xeee4200fUL, 0xeca29e56UL, 0xed60f461UL, 0xe82fe2e4UL, 0xe9ed88d3UL, 0xebab368aUL, 0xea695cbdUL, 0xfd13b8f0UL, 0xfcd1d2c7UL, 0xfe976c9eUL, 0xff5506a9UL, 0xfa1a102cUL, 0xfbd87a1bUL, 0xf99ec442UL, 0xf85cae75UL, 0xf300e948UL, 0xf2c2837fUL, 0xf0843d26UL, 0xf1465711UL, 0xf4094194UL, 0xf5cb2ba3UL, 0xf78d95faUL, 0xf64fffcdUL, 0xd9785d60UL, 0xd8ba3757UL, 0xdafc890eUL, 0xdb3ee339UL, 0xde71f5bcUL, 0xdfb39f8bUL, 0xddf521d2UL, 0xdc374be5UL, 0xd76b0cd8UL, 0xd6a966efUL, 0xd4efd8b6UL, 0xd52db281UL, 0xd062a404UL, 0xd1a0ce33UL, 0xd3e6706aUL, 0xd2241a5dUL, 0xc55efe10UL, 0xc49c9427UL, 0xc6da2a7eUL, 0xc7184049UL, 0xc25756ccUL, 0xc3953cfbUL, 0xc1d382a2UL, 0xc011e895UL, 0xcb4dafa8UL, 0xca8fc59fUL, 0xc8c97bc6UL, 0xc90b11f1UL, 0xcc440774UL, 0xcd866d43UL, 0xcfc0d31aUL, 0xce02b92dUL, 0x91af9640UL, 0x906dfc77UL, 0x922b422eUL, 0x93e92819UL, 0x96a63e9cUL, 0x976454abUL, 0x9522eaf2UL, 0x94e080c5UL, 0x9fbcc7f8UL, 0x9e7eadcfUL, 0x9c381396UL, 0x9dfa79a1UL, 0x98b56f24UL, 0x99770513UL, 0x9b31bb4aUL, 0x9af3d17dUL, 0x8d893530UL, 0x8c4b5f07UL, 0x8e0de15eUL, 0x8fcf8b69UL, 0x8a809decUL, 0x8b42f7dbUL, 0x89044982UL, 0x88c623b5UL, 0x839a6488UL, 0x82580ebfUL, 0x801eb0e6UL, 0x81dcdad1UL, 0x8493cc54UL, 0x8551a663UL, 0x8717183aUL, 0x86d5720dUL, 0xa9e2d0a0UL, 0xa820ba97UL, 0xaa6604ceUL, 0xaba46ef9UL, 0xaeeb787cUL, 0xaf29124bUL, 0xad6fac12UL, 0xacadc625UL, 0xa7f18118UL, 0xa633eb2fUL, 0xa4755576UL, 0xa5b73f41UL, 0xa0f829c4UL, 0xa13a43f3UL, 0xa37cfdaaUL, 0xa2be979dUL, 0xb5c473d0UL, 0xb40619e7UL, 0xb640a7beUL, 0xb782cd89UL, 0xb2cddb0cUL, 0xb30fb13bUL, 0xb1490f62UL, 0xb08b6555UL, 0xbbd72268UL, 0xba15485fUL, 0xb853f606UL, 0xb9919c31UL, 0xbcde8ab4UL, 0xbd1ce083UL, 0xbf5a5edaUL, 0xbe9834edUL }, { 0x00000000UL, 0xb8bc6765UL, 0xaa09c88bUL, 0x12b5afeeUL, 0x8f629757UL, 0x37def032UL, 0x256b5fdcUL, 0x9dd738b9UL, 0xc5b428efUL, 0x7d084f8aUL, 0x6fbde064UL, 0xd7018701UL, 0x4ad6bfb8UL, 0xf26ad8ddUL, 0xe0df7733UL, 0x58631056UL, 0x5019579fUL, 0xe8a530faUL, 0xfa109f14UL, 0x42acf871UL, 0xdf7bc0c8UL, 0x67c7a7adUL, 0x75720843UL, 0xcdce6f26UL, 0x95ad7f70UL, 0x2d111815UL, 0x3fa4b7fbUL, 0x8718d09eUL, 0x1acfe827UL, 0xa2738f42UL, 0xb0c620acUL, 0x087a47c9UL, 0xa032af3eUL, 0x188ec85bUL, 0x0a3b67b5UL, 0xb28700d0UL, 0x2f503869UL, 0x97ec5f0cUL, 0x8559f0e2UL, 0x3de59787UL, 0x658687d1UL, 0xdd3ae0b4UL, 0xcf8f4f5aUL, 0x7733283fUL, 0xeae41086UL, 0x525877e3UL, 0x40edd80dUL, 0xf851bf68UL, 0xf02bf8a1UL, 0x48979fc4UL, 0x5a22302aUL, 0xe29e574fUL, 0x7f496ff6UL, 0xc7f50893UL, 0xd540a77dUL, 0x6dfcc018UL, 0x359fd04eUL, 0x8d23b72bUL, 0x9f9618c5UL, 0x272a7fa0UL, 0xbafd4719UL, 0x0241207cUL, 0x10f48f92UL, 0xa848e8f7UL, 0x9b14583dUL, 0x23a83f58UL, 0x311d90b6UL, 0x89a1f7d3UL, 0x1476cf6aUL, 0xaccaa80fUL, 0xbe7f07e1UL, 0x06c36084UL, 0x5ea070d2UL, 0xe61c17b7UL, 0xf4a9b859UL, 0x4c15df3cUL, 0xd1c2e785UL, 0x697e80e0UL, 0x7bcb2f0eUL, 0xc377486bUL, 0xcb0d0fa2UL, 0x73b168c7UL, 0x6104c729UL, 0xd9b8a04cUL, 0x446f98f5UL, 0xfcd3ff90UL, 0xee66507eUL, 0x56da371bUL, 0x0eb9274dUL, 0xb6054028UL, 0xa4b0efc6UL, 0x1c0c88a3UL, 0x81dbb01aUL, 0x3967d77fUL, 0x2bd27891UL, 0x936e1ff4UL, 0x3b26f703UL, 0x839a9066UL, 0x912f3f88UL, 0x299358edUL, 0xb4446054UL, 0x0cf80731UL, 0x1e4da8dfUL, 0xa6f1cfbaUL, 0xfe92dfecUL, 0x462eb889UL, 0x549b1767UL, 0xec277002UL, 0x71f048bbUL, 0xc94c2fdeUL, 0xdbf98030UL, 0x6345e755UL, 0x6b3fa09cUL, 0xd383c7f9UL, 0xc1366817UL, 0x798a0f72UL, 0xe45d37cbUL, 0x5ce150aeUL, 0x4e54ff40UL, 0xf6e89825UL, 0xae8b8873UL, 0x1637ef16UL, 0x048240f8UL, 0xbc3e279dUL, 0x21e91f24UL, 0x99557841UL, 0x8be0d7afUL, 0x335cb0caUL, 0xed59b63bUL, 0x55e5d15eUL, 0x47507eb0UL, 0xffec19d5UL, 0x623b216cUL, 0xda874609UL, 0xc832e9e7UL, 0x708e8e82UL, 0x28ed9ed4UL, 0x9051f9b1UL, 0x82e4565fUL, 0x3a58313aUL, 0xa78f0983UL, 0x1f336ee6UL, 0x0d86c108UL, 0xb53aa66dUL, 0xbd40e1a4UL, 0x05fc86c1UL, 0x1749292fUL, 0xaff54e4aUL, 0x322276f3UL, 0x8a9e1196UL, 0x982bbe78UL, 0x2097d91dUL, 0x78f4c94bUL, 0xc048ae2eUL, 0xd2fd01c0UL, 0x6a4166a5UL, 0xf7965e1cUL, 0x4f2a3979UL, 0x5d9f9697UL, 0xe523f1f2UL, 0x4d6b1905UL, 0xf5d77e60UL, 0xe762d18eUL, 0x5fdeb6ebUL, 0xc2098e52UL, 0x7ab5e937UL, 0x680046d9UL, 0xd0bc21bcUL, 0x88df31eaUL, 0x3063568fUL, 0x22d6f961UL, 0x9a6a9e04UL, 0x07bda6bdUL, 0xbf01c1d8UL, 0xadb46e36UL, 0x15080953UL, 0x1d724e9aUL, 0xa5ce29ffUL, 0xb77b8611UL, 0x0fc7e174UL, 0x9210d9cdUL, 0x2aacbea8UL, 0x38191146UL, 0x80a57623UL, 0xd8c66675UL, 0x607a0110UL, 0x72cfaefeUL, 0xca73c99bUL, 0x57a4f122UL, 0xef189647UL, 0xfdad39a9UL, 0x45115eccUL, 0x764dee06UL, 0xcef18963UL, 0xdc44268dUL, 0x64f841e8UL, 0xf92f7951UL, 0x41931e34UL, 0x5326b1daUL, 0xeb9ad6bfUL, 0xb3f9c6e9UL, 0x0b45a18cUL, 0x19f00e62UL, 0xa14c6907UL, 0x3c9b51beUL, 0x842736dbUL, 0x96929935UL, 0x2e2efe50UL, 0x2654b999UL, 0x9ee8defcUL, 0x8c5d7112UL, 0x34e11677UL, 0xa9362eceUL, 0x118a49abUL, 0x033fe645UL, 0xbb838120UL, 0xe3e09176UL, 0x5b5cf613UL, 0x49e959fdUL, 0xf1553e98UL, 0x6c820621UL, 0xd43e6144UL, 0xc68bceaaUL, 0x7e37a9cfUL, 0xd67f4138UL, 0x6ec3265dUL, 0x7c7689b3UL, 0xc4caeed6UL, 0x591dd66fUL, 0xe1a1b10aUL, 0xf3141ee4UL, 0x4ba87981UL, 0x13cb69d7UL, 0xab770eb2UL, 0xb9c2a15cUL, 0x017ec639UL, 0x9ca9fe80UL, 0x241599e5UL, 0x36a0360bUL, 0x8e1c516eUL, 0x866616a7UL, 0x3eda71c2UL, 0x2c6fde2cUL, 0x94d3b949UL, 0x090481f0UL, 0xb1b8e695UL, 0xa30d497bUL, 0x1bb12e1eUL, 0x43d23e48UL, 0xfb6e592dUL, 0xe9dbf6c3UL, 0x516791a6UL, 0xccb0a91fUL, 0x740cce7aUL, 0x66b96194UL, 0xde0506f1UL }, { 0x00000000UL, 0x96300777UL, 0x2c610eeeUL, 0xba510999UL, 0x19c46d07UL, 0x8ff46a70UL, 0x35a563e9UL, 0xa395649eUL, 0x3288db0eUL, 0xa4b8dc79UL, 0x1ee9d5e0UL, 0x88d9d297UL, 0x2b4cb609UL, 0xbd7cb17eUL, 0x072db8e7UL, 0x911dbf90UL, 0x6410b71dUL, 0xf220b06aUL, 0x4871b9f3UL, 0xde41be84UL, 0x7dd4da1aUL, 0xebe4dd6dUL, 0x51b5d4f4UL, 0xc785d383UL, 0x56986c13UL, 0xc0a86b64UL, 0x7af962fdUL, 0xecc9658aUL, 0x4f5c0114UL, 0xd96c0663UL, 0x633d0ffaUL, 0xf50d088dUL, 0xc8206e3bUL, 0x5e10694cUL, 0xe44160d5UL, 0x727167a2UL, 0xd1e4033cUL, 0x47d4044bUL, 0xfd850dd2UL, 0x6bb50aa5UL, 0xfaa8b535UL, 0x6c98b242UL, 0xd6c9bbdbUL, 0x40f9bcacUL, 0xe36cd832UL, 0x755cdf45UL, 0xcf0dd6dcUL, 0x593dd1abUL, 0xac30d926UL, 0x3a00de51UL, 0x8051d7c8UL, 0x1661d0bfUL, 0xb5f4b421UL, 0x23c4b356UL, 0x9995bacfUL, 0x0fa5bdb8UL, 0x9eb80228UL, 0x0888055fUL, 0xb2d90cc6UL, 0x24e90bb1UL, 0x877c6f2fUL, 0x114c6858UL, 0xab1d61c1UL, 0x3d2d66b6UL, 0x9041dc76UL, 0x0671db01UL, 0xbc20d298UL, 0x2a10d5efUL, 0x8985b171UL, 0x1fb5b606UL, 0xa5e4bf9fUL, 0x33d4b8e8UL, 0xa2c90778UL, 0x34f9000fUL, 0x8ea80996UL, 0x18980ee1UL, 0xbb0d6a7fUL, 0x2d3d6d08UL, 0x976c6491UL, 0x015c63e6UL, 0xf4516b6bUL, 0x62616c1cUL, 0xd8306585UL, 0x4e0062f2UL, 0xed95066cUL, 0x7ba5011bUL, 0xc1f40882UL, 0x57c40ff5UL, 0xc6d9b065UL, 0x50e9b712UL, 0xeab8be8bUL, 0x7c88b9fcUL, 0xdf1ddd62UL, 0x492dda15UL, 0xf37cd38cUL, 0x654cd4fbUL, 0x5861b24dUL, 0xce51b53aUL, 0x7400bca3UL, 0xe230bbd4UL, 0x41a5df4aUL, 0xd795d83dUL, 0x6dc4d1a4UL, 0xfbf4d6d3UL, 0x6ae96943UL, 0xfcd96e34UL, 0x468867adUL, 0xd0b860daUL, 0x732d0444UL, 0xe51d0333UL, 0x5f4c0aaaUL, 0xc97c0dddUL, 0x3c710550UL, 0xaa410227UL, 0x10100bbeUL, 0x86200cc9UL, 0x25b56857UL, 0xb3856f20UL, 0x09d466b9UL, 0x9fe461ceUL, 0x0ef9de5eUL, 0x98c9d929UL, 0x2298d0b0UL, 0xb4a8d7c7UL, 0x173db359UL, 0x810db42eUL, 0x3b5cbdb7UL, 0xad6cbac0UL, 0x2083b8edUL, 0xb6b3bf9aUL, 0x0ce2b603UL, 0x9ad2b174UL, 0x3947d5eaUL, 0xaf77d29dUL, 0x1526db04UL, 0x8316dc73UL, 0x120b63e3UL, 0x843b6494UL, 0x3e6a6d0dUL, 0xa85a6a7aUL, 0x0bcf0ee4UL, 0x9dff0993UL, 0x27ae000aUL, 0xb19e077dUL, 0x44930ff0UL, 0xd2a30887UL, 0x68f2011eUL, 0xfec20669UL, 0x5d5762f7UL, 0xcb676580UL, 0x71366c19UL, 0xe7066b6eUL, 0x761bd4feUL, 0xe02bd389UL, 0x5a7ada10UL, 0xcc4add67UL, 0x6fdfb9f9UL, 0xf9efbe8eUL, 0x43beb717UL, 0xd58eb060UL, 0xe8a3d6d6UL, 0x7e93d1a1UL, 0xc4c2d838UL, 0x52f2df4fUL, 0xf167bbd1UL, 0x6757bca6UL, 0xdd06b53fUL, 0x4b36b248UL, 0xda2b0dd8UL, 0x4c1b0aafUL, 0xf64a0336UL, 0x607a0441UL, 0xc3ef60dfUL, 0x55df67a8UL, 0xef8e6e31UL, 0x79be6946UL, 0x8cb361cbUL, 0x1a8366bcUL, 0xa0d26f25UL, 0x36e26852UL, 0x95770cccUL, 0x03470bbbUL, 0xb9160222UL, 0x2f260555UL, 0xbe3bbac5UL, 0x280bbdb2UL, 0x925ab42bUL, 0x046ab35cUL, 0xa7ffd7c2UL, 0x31cfd0b5UL, 0x8b9ed92cUL, 0x1daede5bUL, 0xb0c2649bUL, 0x26f263ecUL, 0x9ca36a75UL, 0x0a936d02UL, 0xa906099cUL, 0x3f360eebUL, 0x85670772UL, 0x13570005UL, 0x824abf95UL, 0x147ab8e2UL, 0xae2bb17bUL, 0x381bb60cUL, 0x9b8ed292UL, 0x0dbed5e5UL, 0xb7efdc7cUL, 0x21dfdb0bUL, 0xd4d2d386UL, 0x42e2d4f1UL, 0xf8b3dd68UL, 0x6e83da1fUL, 0xcd16be81UL, 0x5b26b9f6UL, 0xe177b06fUL, 0x7747b718UL, 0xe65a0888UL, 0x706a0fffUL, 0xca3b0666UL, 0x5c0b0111UL, 0xff9e658fUL, 0x69ae62f8UL, 0xd3ff6b61UL, 0x45cf6c16UL, 0x78e20aa0UL, 0xeed20dd7UL, 0x5483044eUL, 0xc2b30339UL, 0x612667a7UL, 0xf71660d0UL, 0x4d476949UL, 0xdb776e3eUL, 0x4a6ad1aeUL, 0xdc5ad6d9UL, 0x660bdf40UL, 0xf03bd837UL, 0x53aebca9UL, 0xc59ebbdeUL, 0x7fcfb247UL, 0xe9ffb530UL, 0x1cf2bdbdUL, 0x8ac2bacaUL, 0x3093b353UL, 0xa6a3b424UL, 0x0536d0baUL, 0x9306d7cdUL, 0x2957de54UL, 0xbf67d923UL, 0x2e7a66b3UL, 0xb84a61c4UL, 0x021b685dUL, 0x942b6f2aUL, 0x37be0bb4UL, 0xa18e0cc3UL, 0x1bdf055aUL, 0x8def022dUL }, { 0x00000000UL, 0x41311b19UL, 0x82623632UL, 0xc3532d2bUL, 0x04c56c64UL, 0x45f4777dUL, 0x86a75a56UL, 0xc796414fUL, 0x088ad9c8UL, 0x49bbc2d1UL, 0x8ae8effaUL, 0xcbd9f4e3UL, 0x0c4fb5acUL, 0x4d7eaeb5UL, 0x8e2d839eUL, 0xcf1c9887UL, 0x5112c24aUL, 0x1023d953UL, 0xd370f478UL, 0x9241ef61UL, 0x55d7ae2eUL, 0x14e6b537UL, 0xd7b5981cUL, 0x96848305UL, 0x59981b82UL, 0x18a9009bUL, 0xdbfa2db0UL, 0x9acb36a9UL, 0x5d5d77e6UL, 0x1c6c6cffUL, 0xdf3f41d4UL, 0x9e0e5acdUL, 0xa2248495UL, 0xe3159f8cUL, 0x2046b2a7UL, 0x6177a9beUL, 0xa6e1e8f1UL, 0xe7d0f3e8UL, 0x2483dec3UL, 0x65b2c5daUL, 0xaaae5d5dUL, 0xeb9f4644UL, 0x28cc6b6fUL, 0x69fd7076UL, 0xae6b3139UL, 0xef5a2a20UL, 0x2c09070bUL, 0x6d381c12UL, 0xf33646dfUL, 0xb2075dc6UL, 0x715470edUL, 0x30656bf4UL, 0xf7f32abbUL, 0xb6c231a2UL, 0x75911c89UL, 0x34a00790UL, 0xfbbc9f17UL, 0xba8d840eUL, 0x79dea925UL, 0x38efb23cUL, 0xff79f373UL, 0xbe48e86aUL, 0x7d1bc541UL, 0x3c2ade58UL, 0x054f79f0UL, 0x447e62e9UL, 0x872d4fc2UL, 0xc61c54dbUL, 0x018a1594UL, 0x40bb0e8dUL, 0x83e823a6UL, 0xc2d938bfUL, 0x0dc5a038UL, 0x4cf4bb21UL, 0x8fa7960aUL, 0xce968d13UL, 0x0900cc5cUL, 0x4831d745UL, 0x8b62fa6eUL, 0xca53e177UL, 0x545dbbbaUL, 0x156ca0a3UL, 0xd63f8d88UL, 0x970e9691UL, 0x5098d7deUL, 0x11a9ccc7UL, 0xd2fae1ecUL, 0x93cbfaf5UL, 0x5cd76272UL, 0x1de6796bUL, 0xdeb55440UL, 0x9f844f59UL, 0x58120e16UL, 0x1923150fUL, 0xda703824UL, 0x9b41233dUL, 0xa76bfd65UL, 0xe65ae67cUL, 0x2509cb57UL, 0x6438d04eUL, 0xa3ae9101UL, 0xe29f8a18UL, 0x21cca733UL, 0x60fdbc2aUL, 0xafe124adUL, 0xeed03fb4UL, 0x2d83129fUL, 0x6cb20986UL, 0xab2448c9UL, 0xea1553d0UL, 0x29467efbUL, 0x687765e2UL, 0xf6793f2fUL, 0xb7482436UL, 0x741b091dUL, 0x352a1204UL, 0xf2bc534bUL, 0xb38d4852UL, 0x70de6579UL, 0x31ef7e60UL, 0xfef3e6e7UL, 0xbfc2fdfeUL, 0x7c91d0d5UL, 0x3da0cbccUL, 0xfa368a83UL, 0xbb07919aUL, 0x7854bcb1UL, 0x3965a7a8UL, 0x4b98833bUL, 0x0aa99822UL, 0xc9fab509UL, 0x88cbae10UL, 0x4f5def5fUL, 0x0e6cf446UL, 0xcd3fd96dUL, 0x8c0ec274UL, 0x43125af3UL, 0x022341eaUL, 0xc1706cc1UL, 0x804177d8UL, 0x47d73697UL, 0x06e62d8eUL, 0xc5b500a5UL, 0x84841bbcUL, 0x1a8a4171UL, 0x5bbb5a68UL, 0x98e87743UL, 0xd9d96c5aUL, 0x1e4f2d15UL, 0x5f7e360cUL, 0x9c2d1b27UL, 0xdd1c003eUL, 0x120098b9UL, 0x533183a0UL, 0x9062ae8bUL, 0xd153b592UL, 0x16c5f4ddUL, 0x57f4efc4UL, 0x94a7c2efUL, 0xd596d9f6UL, 0xe9bc07aeUL, 0xa88d1cb7UL, 0x6bde319cUL, 0x2aef2a85UL, 0xed796bcaUL, 0xac4870d3UL, 0x6f1b5df8UL, 0x2e2a46e1UL, 0xe136de66UL, 0xa007c57fUL, 0x6354e854UL, 0x2265f34dUL, 0xe5f3b202UL, 0xa4c2a91bUL, 0x67918430UL, 0x26a09f29UL, 0xb8aec5e4UL, 0xf99fdefdUL, 0x3accf3d6UL, 0x7bfde8cfUL, 0xbc6ba980UL, 0xfd5ab299UL, 0x3e099fb2UL, 0x7f3884abUL, 0xb0241c2cUL, 0xf1150735UL, 0x32462a1eUL, 0x73773107UL, 0xb4e17048UL, 0xf5d06b51UL, 0x3683467aUL, 0x77b25d63UL, 0x4ed7facbUL, 0x0fe6e1d2UL, 0xccb5ccf9UL, 0x8d84d7e0UL, 0x4a1296afUL, 0x0b238db6UL, 0xc870a09dUL, 0x8941bb84UL, 0x465d2303UL, 0x076c381aUL, 0xc43f1531UL, 0x850e0e28UL, 0x42984f67UL, 0x03a9547eUL, 0xc0fa7955UL, 0x81cb624cUL, 0x1fc53881UL, 0x5ef42398UL, 0x9da70eb3UL, 0xdc9615aaUL, 0x1b0054e5UL, 0x5a314ffcUL, 0x996262d7UL, 0xd85379ceUL, 0x174fe149UL, 0x567efa50UL, 0x952dd77bUL, 0xd41ccc62UL, 0x138a8d2dUL, 0x52bb9634UL, 0x91e8bb1fUL, 0xd0d9a006UL, 0xecf37e5eUL, 0xadc26547UL, 0x6e91486cUL, 0x2fa05375UL, 0xe836123aUL, 0xa9070923UL, 0x6a542408UL, 0x2b653f11UL, 0xe479a796UL, 0xa548bc8fUL, 0x661b91a4UL, 0x272a8abdUL, 0xe0bccbf2UL, 0xa18dd0ebUL, 0x62defdc0UL, 0x23efe6d9UL, 0xbde1bc14UL, 0xfcd0a70dUL, 0x3f838a26UL, 0x7eb2913fUL, 0xb924d070UL, 0xf815cb69UL, 0x3b46e642UL, 0x7a77fd5bUL, 0xb56b65dcUL, 0xf45a7ec5UL, 0x370953eeUL, 0x763848f7UL, 0xb1ae09b8UL, 0xf09f12a1UL, 0x33cc3f8aUL, 0x72fd2493UL }, { 0x00000000UL, 0x376ac201UL, 0x6ed48403UL, 0x59be4602UL, 0xdca80907UL, 0xebc2cb06UL, 0xb27c8d04UL, 0x85164f05UL, 0xb851130eUL, 0x8f3bd10fUL, 0xd685970dUL, 0xe1ef550cUL, 0x64f91a09UL, 0x5393d808UL, 0x0a2d9e0aUL, 0x3d475c0bUL, 0x70a3261cUL, 0x47c9e41dUL, 0x1e77a21fUL, 0x291d601eUL, 0xac0b2f1bUL, 0x9b61ed1aUL, 0xc2dfab18UL, 0xf5b56919UL, 0xc8f23512UL, 0xff98f713UL, 0xa626b111UL, 0x914c7310UL, 0x145a3c15UL, 0x2330fe14UL, 0x7a8eb816UL, 0x4de47a17UL, 0xe0464d38UL, 0xd72c8f39UL, 0x8e92c93bUL, 0xb9f80b3aUL, 0x3cee443fUL, 0x0b84863eUL, 0x523ac03cUL, 0x6550023dUL, 0x58175e36UL, 0x6f7d9c37UL, 0x36c3da35UL, 0x01a91834UL, 0x84bf5731UL, 0xb3d59530UL, 0xea6bd332UL, 0xdd011133UL, 0x90e56b24UL, 0xa78fa925UL, 0xfe31ef27UL, 0xc95b2d26UL, 0x4c4d6223UL, 0x7b27a022UL, 0x2299e620UL, 0x15f32421UL, 0x28b4782aUL, 0x1fdeba2bUL, 0x4660fc29UL, 0x710a3e28UL, 0xf41c712dUL, 0xc376b32cUL, 0x9ac8f52eUL, 0xada2372fUL, 0xc08d9a70UL, 0xf7e75871UL, 0xae591e73UL, 0x9933dc72UL, 0x1c259377UL, 0x2b4f5176UL, 0x72f11774UL, 0x459bd575UL, 0x78dc897eUL, 0x4fb64b7fUL, 0x16080d7dUL, 0x2162cf7cUL, 0xa4748079UL, 0x931e4278UL, 0xcaa0047aUL, 0xfdcac67bUL, 0xb02ebc6cUL, 0x87447e6dUL, 0xdefa386fUL, 0xe990fa6eUL, 0x6c86b56bUL, 0x5bec776aUL, 0x02523168UL, 0x3538f369UL, 0x087faf62UL, 0x3f156d63UL, 0x66ab2b61UL, 0x51c1e960UL, 0xd4d7a665UL, 0xe3bd6464UL, 0xba032266UL, 0x8d69e067UL, 0x20cbd748UL, 0x17a11549UL, 0x4e1f534bUL, 0x7975914aUL, 0xfc63de4fUL, 0xcb091c4eUL, 0x92b75a4cUL, 0xa5dd984dUL, 0x989ac446UL, 0xaff00647UL, 0xf64e4045UL, 0xc1248244UL, 0x4432cd41UL, 0x73580f40UL, 0x2ae64942UL, 0x1d8c8b43UL, 0x5068f154UL, 0x67023355UL, 0x3ebc7557UL, 0x09d6b756UL, 0x8cc0f853UL, 0xbbaa3a52UL, 0xe2147c50UL, 0xd57ebe51UL, 0xe839e25aUL, 0xdf53205bUL, 0x86ed6659UL, 0xb187a458UL, 0x3491eb5dUL, 0x03fb295cUL, 0x5a456f5eUL, 0x6d2fad5fUL, 0x801b35e1UL, 0xb771f7e0UL, 0xeecfb1e2UL, 0xd9a573e3UL, 0x5cb33ce6UL, 0x6bd9fee7UL, 0x3267b8e5UL, 0x050d7ae4UL, 0x384a26efUL, 0x0f20e4eeUL, 0x569ea2ecUL, 0x61f460edUL, 0xe4e22fe8UL, 0xd388ede9UL, 0x8a36abebUL, 0xbd5c69eaUL, 0xf0b813fdUL, 0xc7d2d1fcUL, 0x9e6c97feUL, 0xa90655ffUL, 0x2c101afaUL, 0x1b7ad8fbUL, 0x42c49ef9UL, 0x75ae5cf8UL, 0x48e900f3UL, 0x7f83c2f2UL, 0x263d84f0UL, 0x115746f1UL, 0x944109f4UL, 0xa32bcbf5UL, 0xfa958df7UL, 0xcdff4ff6UL, 0x605d78d9UL, 0x5737bad8UL, 0x0e89fcdaUL, 0x39e33edbUL, 0xbcf571deUL, 0x8b9fb3dfUL, 0xd221f5ddUL, 0xe54b37dcUL, 0xd80c6bd7UL, 0xef66a9d6UL, 0xb6d8efd4UL, 0x81b22dd5UL, 0x04a462d0UL, 0x33cea0d1UL, 0x6a70e6d3UL, 0x5d1a24d2UL, 0x10fe5ec5UL, 0x27949cc4UL, 0x7e2adac6UL, 0x494018c7UL, 0xcc5657c2UL, 0xfb3c95c3UL, 0xa282d3c1UL, 0x95e811c0UL, 0xa8af4dcbUL, 0x9fc58fcaUL, 0xc67bc9c8UL, 0xf1110bc9UL, 0x740744ccUL, 0x436d86cdUL, 0x1ad3c0cfUL, 0x2db902ceUL, 0x4096af91UL, 0x77fc6d90UL, 0x2e422b92UL, 0x1928e993UL, 0x9c3ea696UL, 0xab546497UL, 0xf2ea2295UL, 0xc580e094UL, 0xf8c7bc9fUL, 0xcfad7e9eUL, 0x9613389cUL, 0xa179fa9dUL, 0x246fb598UL, 0x13057799UL, 0x4abb319bUL, 0x7dd1f39aUL, 0x3035898dUL, 0x075f4b8cUL, 0x5ee10d8eUL, 0x698bcf8fUL, 0xec9d808aUL, 0xdbf7428bUL, 0x82490489UL, 0xb523c688UL, 0x88649a83UL, 0xbf0e5882UL, 0xe6b01e80UL, 0xd1dadc81UL, 0x54cc9384UL, 0x63a65185UL, 0x3a181787UL, 0x0d72d586UL, 0xa0d0e2a9UL, 0x97ba20a8UL, 0xce0466aaUL, 0xf96ea4abUL, 0x7c78ebaeUL, 0x4b1229afUL, 0x12ac6fadUL, 0x25c6adacUL, 0x1881f1a7UL, 0x2feb33a6UL, 0x765575a4UL, 0x413fb7a5UL, 0xc429f8a0UL, 0xf3433aa1UL, 0xaafd7ca3UL, 0x9d97bea2UL, 0xd073c4b5UL, 0xe71906b4UL, 0xbea740b6UL, 0x89cd82b7UL, 0x0cdbcdb2UL, 0x3bb10fb3UL, 0x620f49b1UL, 0x55658bb0UL, 0x6822d7bbUL, 0x5f4815baUL, 0x06f653b8UL, 0x319c91b9UL, 0xb48adebcUL, 0x83e01cbdUL, 0xda5e5abfUL, 0xed3498beUL }, { 0x00000000UL, 0x6567bcb8UL, 0x8bc809aaUL, 0xeeafb512UL, 0x5797628fUL, 0x32f0de37UL, 0xdc5f6b25UL, 0xb938d79dUL, 0xef28b4c5UL, 0x8a4f087dUL, 0x64e0bd6fUL, 0x018701d7UL, 0xb8bfd64aUL, 0xddd86af2UL, 0x3377dfe0UL, 0x56106358UL, 0x9f571950UL, 0xfa30a5e8UL, 0x149f10faUL, 0x71f8ac42UL, 0xc8c07bdfUL, 0xada7c767UL, 0x43087275UL, 0x266fcecdUL, 0x707fad95UL, 0x1518112dUL, 0xfbb7a43fUL, 0x9ed01887UL, 0x27e8cf1aUL, 0x428f73a2UL, 0xac20c6b0UL, 0xc9477a08UL, 0x3eaf32a0UL, 0x5bc88e18UL, 0xb5673b0aUL, 0xd00087b2UL, 0x6938502fUL, 0x0c5fec97UL, 0xe2f05985UL, 0x8797e53dUL, 0xd1878665UL, 0xb4e03addUL, 0x5a4f8fcfUL, 0x3f283377UL, 0x8610e4eaUL, 0xe3775852UL, 0x0dd8ed40UL, 0x68bf51f8UL, 0xa1f82bf0UL, 0xc49f9748UL, 0x2a30225aUL, 0x4f579ee2UL, 0xf66f497fUL, 0x9308f5c7UL, 0x7da740d5UL, 0x18c0fc6dUL, 0x4ed09f35UL, 0x2bb7238dUL, 0xc518969fUL, 0xa07f2a27UL, 0x1947fdbaUL, 0x7c204102UL, 0x928ff410UL, 0xf7e848a8UL, 0x3d58149bUL, 0x583fa823UL, 0xb6901d31UL, 0xd3f7a189UL, 0x6acf7614UL, 0x0fa8caacUL, 0xe1077fbeUL, 0x8460c306UL, 0xd270a05eUL, 0xb7171ce6UL, 0x59b8a9f4UL, 0x3cdf154cUL, 0x85e7c2d1UL, 0xe0807e69UL, 0x0e2fcb7bUL, 0x6b4877c3UL, 0xa20f0dcbUL, 0xc768b173UL, 0x29c70461UL, 0x4ca0b8d9UL, 0xf5986f44UL, 0x90ffd3fcUL, 0x7e5066eeUL, 0x1b37da56UL, 0x4d27b90eUL, 0x284005b6UL, 0xc6efb0a4UL, 0xa3880c1cUL, 0x1ab0db81UL, 0x7fd76739UL, 0x9178d22bUL, 0xf41f6e93UL, 0x03f7263bUL, 0x66909a83UL, 0x883f2f91UL, 0xed589329UL, 0x546044b4UL, 0x3107f80cUL, 0xdfa84d1eUL, 0xbacff1a6UL, 0xecdf92feUL, 0x89b82e46UL, 0x67179b54UL, 0x027027ecUL, 0xbb48f071UL, 0xde2f4cc9UL, 0x3080f9dbUL, 0x55e74563UL, 0x9ca03f6bUL, 0xf9c783d3UL, 0x176836c1UL, 0x720f8a79UL, 0xcb375de4UL, 0xae50e15cUL, 0x40ff544eUL, 0x2598e8f6UL, 0x73888baeUL, 0x16ef3716UL, 0xf8408204UL, 0x9d273ebcUL, 0x241fe921UL, 0x41785599UL, 0xafd7e08bUL, 0xcab05c33UL, 0x3bb659edUL, 0x5ed1e555UL, 0xb07e5047UL, 0xd519ecffUL, 0x6c213b62UL, 0x094687daUL, 0xe7e932c8UL, 0x828e8e70UL, 0xd49eed28UL, 0xb1f95190UL, 0x5f56e482UL, 0x3a31583aUL, 0x83098fa7UL, 0xe66e331fUL, 0x08c1860dUL, 0x6da63ab5UL, 0xa4e140bdUL, 0xc186fc05UL, 0x2f294917UL, 0x4a4ef5afUL, 0xf3762232UL, 0x96119e8aUL, 0x78be2b98UL, 0x1dd99720UL, 0x4bc9f478UL, 0x2eae48c0UL, 0xc001fdd2UL, 0xa566416aUL, 0x1c5e96f7UL, 0x79392a4fUL, 0x97969f5dUL, 0xf2f123e5UL, 0x05196b4dUL, 0x607ed7f5UL, 0x8ed162e7UL, 0xebb6de5fUL, 0x528e09c2UL, 0x37e9b57aUL, 0xd9460068UL, 0xbc21bcd0UL, 0xea31df88UL, 0x8f566330UL, 0x61f9d622UL, 0x049e6a9aUL, 0xbda6bd07UL, 0xd8c101bfUL, 0x366eb4adUL, 0x53090815UL, 0x9a4e721dUL, 0xff29cea5UL, 0x11867bb7UL, 0x74e1c70fUL, 0xcdd91092UL, 0xa8beac2aUL, 0x46111938UL, 0x2376a580UL, 0x7566c6d8UL, 0x10017a60UL, 0xfeaecf72UL, 0x9bc973caUL, 0x22f1a457UL, 0x479618efUL, 0xa939adfdUL, 0xcc5e1145UL, 0x06ee4d76UL, 0x6389f1ceUL, 0x8d2644dcUL, 0xe841f864UL, 0x51792ff9UL, 0x341e9341UL, 0xdab12653UL, 0xbfd69aebUL, 0xe9c6f9b3UL, 0x8ca1450bUL, 0x620ef019UL, 0x07694ca1UL, 0xbe519b3cUL, 0xdb362784UL, 0x35999296UL, 0x50fe2e2eUL, 0x99b95426UL, 0xfcdee89eUL, 0x12715d8cUL, 0x7716e134UL, 0xce2e36a9UL, 0xab498a11UL, 0x45e63f03UL, 0x208183bbUL, 0x7691e0e3UL, 0x13f65c5bUL, 0xfd59e949UL, 0x983e55f1UL, 0x2106826cUL, 0x44613ed4UL, 0xaace8bc6UL, 0xcfa9377eUL, 0x38417fd6UL, 0x5d26c36eUL, 0xb389767cUL, 0xd6eecac4UL, 0x6fd61d59UL, 0x0ab1a1e1UL, 0xe41e14f3UL, 0x8179a84bUL, 0xd769cb13UL, 0xb20e77abUL, 0x5ca1c2b9UL, 0x39c67e01UL, 0x80fea99cUL, 0xe5991524UL, 0x0b36a036UL, 0x6e511c8eUL, 0xa7166686UL, 0xc271da3eUL, 0x2cde6f2cUL, 0x49b9d394UL, 0xf0810409UL, 0x95e6b8b1UL, 0x7b490da3UL, 0x1e2eb11bUL, 0x483ed243UL, 0x2d596efbUL, 0xc3f6dbe9UL, 0xa6916751UL, 0x1fa9b0ccUL, 0x7ace0c74UL, 0x9461b966UL, 0xf10605deUL #endif } }; libgit2-0.19.0/deps/zlib/deflate.c000066400000000000000000002046301216214232500166030ustar00rootroot00000000000000/* deflate.c -- compress data using the deflation algorithm * Copyright (C) 1995-2010 Jean-loup Gailly and Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ /* * ALGORITHM * * The "deflation" process depends on being able to identify portions * of the input text which are identical to earlier input (within a * sliding window trailing behind the input currently being processed). * * The most straightforward technique turns out to be the fastest for * most input files: try all possible matches and select the longest. * The key feature of this algorithm is that insertions into the string * dictionary are very simple and thus fast, and deletions are avoided * completely. Insertions are performed at each input character, whereas * string matches are performed only when the previous match ends. So it * is preferable to spend more time in matches to allow very fast string * insertions and avoid deletions. The matching algorithm for small * strings is inspired from that of Rabin & Karp. A brute force approach * is used to find longer strings when a small match has been found. * A similar algorithm is used in comic (by Jan-Mark Wams) and freeze * (by Leonid Broukhis). * A previous version of this file used a more sophisticated algorithm * (by Fiala and Greene) which is guaranteed to run in linear amortized * time, but has a larger average cost, uses more memory and is patented. * However the F&G algorithm may be faster for some highly redundant * files if the parameter max_chain_length (described below) is too large. * * ACKNOWLEDGEMENTS * * The idea of lazy evaluation of matches is due to Jan-Mark Wams, and * I found it in 'freeze' written by Leonid Broukhis. * Thanks to many people for bug reports and testing. * * REFERENCES * * Deutsch, L.P.,"DEFLATE Compressed Data Format Specification". * Available in http://www.ietf.org/rfc/rfc1951.txt * * A description of the Rabin and Karp algorithm is given in the book * "Algorithms" by R. Sedgewick, Addison-Wesley, p252. * * Fiala,E.R., and Greene,D.H. * Data Compression with Finite Windows, Comm.ACM, 32,4 (1989) 490-595 * */ /* @(#) $Id$ */ #include "deflate.h" const char deflate_copyright[] = " deflate 1.2.5 Copyright 1995-2010 Jean-loup Gailly and Mark Adler "; /* If you use the zlib library in a product, an acknowledgment is welcome in the documentation of your product. If for some reason you cannot include such an acknowledgment, I would appreciate that you keep this copyright string in the executable of your product. */ /* =========================================================================== * Function prototypes. */ typedef enum { need_more, /* block not completed, need more input or more output */ block_done, /* block flush performed */ finish_started, /* finish started, need only more output at next deflate */ finish_done /* finish done, accept no more input or output */ } block_state; typedef block_state (*compress_func) OF((deflate_state *s, int flush)); /* Compression function. Returns the block state after the call. */ local void fill_window OF((deflate_state *s)); local block_state deflate_stored OF((deflate_state *s, int flush)); local block_state deflate_fast OF((deflate_state *s, int flush)); #ifndef FASTEST local block_state deflate_slow OF((deflate_state *s, int flush)); #endif local block_state deflate_rle OF((deflate_state *s, int flush)); local block_state deflate_huff OF((deflate_state *s, int flush)); local void lm_init OF((deflate_state *s)); local void putShortMSB OF((deflate_state *s, uInt b)); local void flush_pending OF((z_streamp strm)); local int read_buf OF((z_streamp strm, Bytef *buf, unsigned size)); #ifdef ASMV void match_init OF((void)); /* asm code initialization */ uInt longest_match OF((deflate_state *s, IPos cur_match)); #else local uInt longest_match OF((deflate_state *s, IPos cur_match)); #endif #ifdef DEBUG local void check_match OF((deflate_state *s, IPos start, IPos match, int length)); #endif /* =========================================================================== * Local data */ #define NIL 0 /* Tail of hash chains */ #ifndef TOO_FAR # define TOO_FAR 4096 #endif /* Matches of length 3 are discarded if their distance exceeds TOO_FAR */ /* Values for max_lazy_match, good_match and max_chain_length, depending on * the desired pack level (0..9). The values given below have been tuned to * exclude worst case performance for pathological files. Better values may be * found for specific files. */ typedef struct config_s { ush good_length; /* reduce lazy search above this match length */ ush max_lazy; /* do not perform lazy search above this match length */ ush nice_length; /* quit search above this match length */ ush max_chain; compress_func func; } config; #ifdef FASTEST local const config configuration_table[2] = { /* good lazy nice chain */ /* 0 */ {0, 0, 0, 0, deflate_stored}, /* store only */ /* 1 */ {4, 4, 8, 4, deflate_fast}}; /* max speed, no lazy matches */ #else local const config configuration_table[10] = { /* good lazy nice chain */ /* 0 */ {0, 0, 0, 0, deflate_stored}, /* store only */ /* 1 */ {4, 4, 8, 4, deflate_fast}, /* max speed, no lazy matches */ /* 2 */ {4, 5, 16, 8, deflate_fast}, /* 3 */ {4, 6, 32, 32, deflate_fast}, /* 4 */ {4, 4, 16, 16, deflate_slow}, /* lazy matches */ /* 5 */ {8, 16, 32, 32, deflate_slow}, /* 6 */ {8, 16, 128, 128, deflate_slow}, /* 7 */ {8, 32, 128, 256, deflate_slow}, /* 8 */ {32, 128, 258, 1024, deflate_slow}, /* 9 */ {32, 258, 258, 4096, deflate_slow}}; /* max compression */ #endif /* Note: the deflate() code requires max_lazy >= MIN_MATCH and max_chain >= 4 * For deflate_fast() (levels <= 3) good is ignored and lazy has a different * meaning. */ #define EQUAL 0 /* result of memcmp for equal strings */ #ifndef NO_DUMMY_DECL struct static_tree_desc_s {int dummy;}; /* for buggy compilers */ #endif /* =========================================================================== * Update a hash value with the given input byte * IN assertion: all calls to to UPDATE_HASH are made with consecutive * input characters, so that a running hash key can be computed from the * previous key instead of complete recalculation each time. */ #define UPDATE_HASH(s,h,c) (h = (((h)<hash_shift) ^ (c)) & s->hash_mask) /* =========================================================================== * Insert string str in the dictionary and set match_head to the previous head * of the hash chain (the most recent string with same hash key). Return * the previous length of the hash chain. * If this file is compiled with -DFASTEST, the compression level is forced * to 1, and no hash chains are maintained. * IN assertion: all calls to to INSERT_STRING are made with consecutive * input characters and the first MIN_MATCH bytes of str are valid * (except for the last MIN_MATCH-1 bytes of the input file). */ #ifdef FASTEST #define INSERT_STRING(s, str, match_head) \ (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \ match_head = s->head[s->ins_h], \ s->head[s->ins_h] = (Pos)(str)) #else #define INSERT_STRING(s, str, match_head) \ (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \ match_head = s->prev[(str) & s->w_mask] = s->head[s->ins_h], \ s->head[s->ins_h] = (Pos)(str)) #endif /* =========================================================================== * Initialize the hash table (avoiding 64K overflow for 16 bit systems). * prev[] will be initialized on the fly. */ #define CLEAR_HASH(s) \ s->head[s->hash_size-1] = NIL; \ zmemzero((Bytef *)s->head, (unsigned)(s->hash_size-1)*sizeof(*s->head)); /* ========================================================================= */ int ZEXPORT deflateInit_(strm, level, version, stream_size) z_streamp strm; int level; const char *version; int stream_size; { return deflateInit2_(strm, level, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, version, stream_size); /* To do: ignore strm->next_in if we use it as window */ } /* ========================================================================= */ int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy, version, stream_size) z_streamp strm; int level; int method; int windowBits; int memLevel; int strategy; const char *version; int stream_size; { deflate_state *s; int wrap = 1; static const char my_version[] = ZLIB_VERSION; ushf *overlay; /* We overlay pending_buf and d_buf+l_buf. This works since the average * output size for (length,distance) codes is <= 24 bits. */ if (version == Z_NULL || version[0] != my_version[0] || stream_size != sizeof(z_stream)) { return Z_VERSION_ERROR; } if (strm == Z_NULL) return Z_STREAM_ERROR; strm->msg = Z_NULL; if (strm->zalloc == (alloc_func)0) { strm->zalloc = zcalloc; strm->opaque = (voidpf)0; } if (strm->zfree == (free_func)0) strm->zfree = zcfree; #ifdef FASTEST if (level != 0) level = 1; #else if (level == Z_DEFAULT_COMPRESSION) level = 6; #endif if (windowBits < 0) { /* suppress zlib wrapper */ wrap = 0; windowBits = -windowBits; } #ifdef GZIP else if (windowBits > 15) { wrap = 2; /* write gzip wrapper instead */ windowBits -= 16; } #endif if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method != Z_DEFLATED || windowBits < 8 || windowBits > 15 || level < 0 || level > 9 || strategy < 0 || strategy > Z_FIXED) { return Z_STREAM_ERROR; } if (windowBits == 8) windowBits = 9; /* until 256-byte window bug fixed */ s = (deflate_state *) ZALLOC(strm, 1, sizeof(deflate_state)); if (s == Z_NULL) return Z_MEM_ERROR; strm->state = (struct internal_state FAR *)s; s->strm = strm; s->wrap = wrap; s->gzhead = Z_NULL; s->w_bits = windowBits; s->w_size = 1 << s->w_bits; s->w_mask = s->w_size - 1; s->hash_bits = memLevel + 7; s->hash_size = 1 << s->hash_bits; s->hash_mask = s->hash_size - 1; s->hash_shift = ((s->hash_bits+MIN_MATCH-1)/MIN_MATCH); s->window = (Bytef *) ZALLOC(strm, s->w_size, 2*sizeof(Byte)); s->prev = (Posf *) ZALLOC(strm, s->w_size, sizeof(Pos)); s->head = (Posf *) ZALLOC(strm, s->hash_size, sizeof(Pos)); s->high_water = 0; /* nothing written to s->window yet */ s->lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */ overlay = (ushf *) ZALLOC(strm, s->lit_bufsize, sizeof(ush)+2); s->pending_buf = (uchf *) overlay; s->pending_buf_size = (ulg)s->lit_bufsize * (sizeof(ush)+2L); if (s->window == Z_NULL || s->prev == Z_NULL || s->head == Z_NULL || s->pending_buf == Z_NULL) { s->status = FINISH_STATE; strm->msg = (char*)ERR_MSG(Z_MEM_ERROR); deflateEnd (strm); return Z_MEM_ERROR; } s->d_buf = overlay + s->lit_bufsize/sizeof(ush); s->l_buf = s->pending_buf + (1+sizeof(ush))*s->lit_bufsize; s->level = level; s->strategy = strategy; s->method = (Byte)method; return deflateReset(strm); } /* ========================================================================= */ int ZEXPORT deflateSetDictionary (strm, dictionary, dictLength) z_streamp strm; const Bytef *dictionary; uInt dictLength; { deflate_state *s; uInt length = dictLength; uInt n; IPos hash_head = 0; if (strm == Z_NULL || strm->state == Z_NULL || dictionary == Z_NULL || strm->state->wrap == 2 || (strm->state->wrap == 1 && strm->state->status != INIT_STATE)) return Z_STREAM_ERROR; s = strm->state; if (s->wrap) strm->adler = adler32(strm->adler, dictionary, dictLength); if (length < MIN_MATCH) return Z_OK; if (length > s->w_size) { length = s->w_size; dictionary += dictLength - length; /* use the tail of the dictionary */ } zmemcpy(s->window, dictionary, length); s->strstart = length; s->block_start = (long)length; /* Insert all strings in the hash table (except for the last two bytes). * s->lookahead stays null, so s->ins_h will be recomputed at the next * call of fill_window. */ s->ins_h = s->window[0]; UPDATE_HASH(s, s->ins_h, s->window[1]); for (n = 0; n <= length - MIN_MATCH; n++) { INSERT_STRING(s, n, hash_head); } if (hash_head) hash_head = 0; /* to make compiler happy */ return Z_OK; } /* ========================================================================= */ int ZEXPORT deflateReset (strm) z_streamp strm; { deflate_state *s; if (strm == Z_NULL || strm->state == Z_NULL || strm->zalloc == (alloc_func)0 || strm->zfree == (free_func)0) { return Z_STREAM_ERROR; } strm->total_in = strm->total_out = 0; strm->msg = Z_NULL; /* use zfree if we ever allocate msg dynamically */ strm->data_type = Z_UNKNOWN; s = (deflate_state *)strm->state; s->pending = 0; s->pending_out = s->pending_buf; if (s->wrap < 0) { s->wrap = -s->wrap; /* was made negative by deflate(..., Z_FINISH); */ } s->status = s->wrap ? INIT_STATE : BUSY_STATE; strm->adler = #ifdef GZIP s->wrap == 2 ? crc32(0L, Z_NULL, 0) : #endif adler32(0L, Z_NULL, 0); s->last_flush = Z_NO_FLUSH; _tr_init(s); lm_init(s); return Z_OK; } /* ========================================================================= */ int ZEXPORT deflateSetHeader (strm, head) z_streamp strm; gz_headerp head; { if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; if (strm->state->wrap != 2) return Z_STREAM_ERROR; strm->state->gzhead = head; return Z_OK; } /* ========================================================================= */ int ZEXPORT deflatePrime (strm, bits, value) z_streamp strm; int bits; int value; { if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; strm->state->bi_valid = bits; strm->state->bi_buf = (ush)(value & ((1 << bits) - 1)); return Z_OK; } /* ========================================================================= */ int ZEXPORT deflateParams(strm, level, strategy) z_streamp strm; int level; int strategy; { deflate_state *s; compress_func func; int err = Z_OK; if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; s = strm->state; #ifdef FASTEST if (level != 0) level = 1; #else if (level == Z_DEFAULT_COMPRESSION) level = 6; #endif if (level < 0 || level > 9 || strategy < 0 || strategy > Z_FIXED) { return Z_STREAM_ERROR; } func = configuration_table[s->level].func; if ((strategy != s->strategy || func != configuration_table[level].func) && strm->total_in != 0) { /* Flush the last buffer: */ err = deflate(strm, Z_BLOCK); } if (s->level != level) { s->level = level; s->max_lazy_match = configuration_table[level].max_lazy; s->good_match = configuration_table[level].good_length; s->nice_match = configuration_table[level].nice_length; s->max_chain_length = configuration_table[level].max_chain; } s->strategy = strategy; return err; } /* ========================================================================= */ int ZEXPORT deflateTune(strm, good_length, max_lazy, nice_length, max_chain) z_streamp strm; int good_length; int max_lazy; int nice_length; int max_chain; { deflate_state *s; if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; s = strm->state; s->good_match = good_length; s->max_lazy_match = max_lazy; s->nice_match = nice_length; s->max_chain_length = max_chain; return Z_OK; } /* ========================================================================= * For the default windowBits of 15 and memLevel of 8, this function returns * a close to exact, as well as small, upper bound on the compressed size. * They are coded as constants here for a reason--if the #define's are * changed, then this function needs to be changed as well. The return * value for 15 and 8 only works for those exact settings. * * For any setting other than those defaults for windowBits and memLevel, * the value returned is a conservative worst case for the maximum expansion * resulting from using fixed blocks instead of stored blocks, which deflate * can emit on compressed data for some combinations of the parameters. * * This function could be more sophisticated to provide closer upper bounds for * every combination of windowBits and memLevel. But even the conservative * upper bound of about 14% expansion does not seem onerous for output buffer * allocation. */ uLong ZEXPORT deflateBound(strm, sourceLen) z_streamp strm; uLong sourceLen; { deflate_state *s; uLong complen, wraplen; Bytef *str; /* conservative upper bound for compressed data */ complen = sourceLen + ((sourceLen + 7) >> 3) + ((sourceLen + 63) >> 6) + 5; /* if can't get parameters, return conservative bound plus zlib wrapper */ if (strm == Z_NULL || strm->state == Z_NULL) return complen + 6; /* compute wrapper length */ s = strm->state; switch (s->wrap) { case 0: /* raw deflate */ wraplen = 0; break; case 1: /* zlib wrapper */ wraplen = 6 + (s->strstart ? 4 : 0); break; case 2: /* gzip wrapper */ wraplen = 18; if (s->gzhead != Z_NULL) { /* user-supplied gzip header */ if (s->gzhead->extra != Z_NULL) wraplen += 2 + s->gzhead->extra_len; str = s->gzhead->name; if (str != Z_NULL) do { wraplen++; } while (*str++); str = s->gzhead->comment; if (str != Z_NULL) do { wraplen++; } while (*str++); if (s->gzhead->hcrc) wraplen += 2; } break; default: /* for compiler happiness */ wraplen = 6; } /* if not default parameters, return conservative bound */ if (s->w_bits != 15 || s->hash_bits != 8 + 7) return complen + wraplen; /* default settings: return tight bound for that case */ return sourceLen + (sourceLen >> 12) + (sourceLen >> 14) + (sourceLen >> 25) + 13 - 6 + wraplen; } /* ========================================================================= * Put a short in the pending buffer. The 16-bit value is put in MSB order. * IN assertion: the stream state is correct and there is enough room in * pending_buf. */ local void putShortMSB (s, b) deflate_state *s; uInt b; { put_byte(s, (Byte)(b >> 8)); put_byte(s, (Byte)(b & 0xff)); } /* ========================================================================= * Flush as much pending output as possible. All deflate() output goes * through this function so some applications may wish to modify it * to avoid allocating a large strm->next_out buffer and copying into it. * (See also read_buf()). */ local void flush_pending(strm) z_streamp strm; { unsigned len = strm->state->pending; if (len > strm->avail_out) len = strm->avail_out; if (len == 0) return; zmemcpy(strm->next_out, strm->state->pending_out, len); strm->next_out += len; strm->state->pending_out += len; strm->total_out += len; strm->avail_out -= len; strm->state->pending -= len; if (strm->state->pending == 0) { strm->state->pending_out = strm->state->pending_buf; } } /* ========================================================================= */ int ZEXPORT deflate (strm, flush) z_streamp strm; int flush; { int old_flush; /* value of flush param for previous deflate call */ deflate_state *s; if (strm == Z_NULL || strm->state == Z_NULL || flush > Z_BLOCK || flush < 0) { return Z_STREAM_ERROR; } s = strm->state; if (strm->next_out == Z_NULL || (strm->next_in == Z_NULL && strm->avail_in != 0) || (s->status == FINISH_STATE && flush != Z_FINISH)) { ERR_RETURN(strm, Z_STREAM_ERROR); } if (strm->avail_out == 0) ERR_RETURN(strm, Z_BUF_ERROR); s->strm = strm; /* just in case */ old_flush = s->last_flush; s->last_flush = flush; /* Write the header */ if (s->status == INIT_STATE) { #ifdef GZIP if (s->wrap == 2) { strm->adler = crc32(0L, Z_NULL, 0); put_byte(s, 31); put_byte(s, 139); put_byte(s, 8); if (s->gzhead == Z_NULL) { put_byte(s, 0); put_byte(s, 0); put_byte(s, 0); put_byte(s, 0); put_byte(s, 0); put_byte(s, s->level == 9 ? 2 : (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ? 4 : 0)); put_byte(s, OS_CODE); s->status = BUSY_STATE; } else { put_byte(s, (s->gzhead->text ? 1 : 0) + (s->gzhead->hcrc ? 2 : 0) + (s->gzhead->extra == Z_NULL ? 0 : 4) + (s->gzhead->name == Z_NULL ? 0 : 8) + (s->gzhead->comment == Z_NULL ? 0 : 16) ); put_byte(s, (Byte)(s->gzhead->time & 0xff)); put_byte(s, (Byte)((s->gzhead->time >> 8) & 0xff)); put_byte(s, (Byte)((s->gzhead->time >> 16) & 0xff)); put_byte(s, (Byte)((s->gzhead->time >> 24) & 0xff)); put_byte(s, s->level == 9 ? 2 : (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ? 4 : 0)); put_byte(s, s->gzhead->os & 0xff); if (s->gzhead->extra != Z_NULL) { put_byte(s, s->gzhead->extra_len & 0xff); put_byte(s, (s->gzhead->extra_len >> 8) & 0xff); } if (s->gzhead->hcrc) strm->adler = crc32(strm->adler, s->pending_buf, s->pending); s->gzindex = 0; s->status = EXTRA_STATE; } } else #endif { uInt header = (Z_DEFLATED + ((s->w_bits-8)<<4)) << 8; uInt level_flags; if (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2) level_flags = 0; else if (s->level < 6) level_flags = 1; else if (s->level == 6) level_flags = 2; else level_flags = 3; header |= (level_flags << 6); if (s->strstart != 0) header |= PRESET_DICT; header += 31 - (header % 31); s->status = BUSY_STATE; putShortMSB(s, header); /* Save the adler32 of the preset dictionary: */ if (s->strstart != 0) { putShortMSB(s, (uInt)(strm->adler >> 16)); putShortMSB(s, (uInt)(strm->adler & 0xffff)); } strm->adler = adler32(0L, Z_NULL, 0); } } #ifdef GZIP if (s->status == EXTRA_STATE) { if (s->gzhead->extra != Z_NULL) { uInt beg = s->pending; /* start of bytes to update crc */ while (s->gzindex < (s->gzhead->extra_len & 0xffff)) { if (s->pending == s->pending_buf_size) { if (s->gzhead->hcrc && s->pending > beg) strm->adler = crc32(strm->adler, s->pending_buf + beg, s->pending - beg); flush_pending(strm); beg = s->pending; if (s->pending == s->pending_buf_size) break; } put_byte(s, s->gzhead->extra[s->gzindex]); s->gzindex++; } if (s->gzhead->hcrc && s->pending > beg) strm->adler = crc32(strm->adler, s->pending_buf + beg, s->pending - beg); if (s->gzindex == s->gzhead->extra_len) { s->gzindex = 0; s->status = NAME_STATE; } } else s->status = NAME_STATE; } if (s->status == NAME_STATE) { if (s->gzhead->name != Z_NULL) { uInt beg = s->pending; /* start of bytes to update crc */ int val; do { if (s->pending == s->pending_buf_size) { if (s->gzhead->hcrc && s->pending > beg) strm->adler = crc32(strm->adler, s->pending_buf + beg, s->pending - beg); flush_pending(strm); beg = s->pending; if (s->pending == s->pending_buf_size) { val = 1; break; } } val = s->gzhead->name[s->gzindex++]; put_byte(s, val); } while (val != 0); if (s->gzhead->hcrc && s->pending > beg) strm->adler = crc32(strm->adler, s->pending_buf + beg, s->pending - beg); if (val == 0) { s->gzindex = 0; s->status = COMMENT_STATE; } } else s->status = COMMENT_STATE; } if (s->status == COMMENT_STATE) { if (s->gzhead->comment != Z_NULL) { uInt beg = s->pending; /* start of bytes to update crc */ int val; do { if (s->pending == s->pending_buf_size) { if (s->gzhead->hcrc && s->pending > beg) strm->adler = crc32(strm->adler, s->pending_buf + beg, s->pending - beg); flush_pending(strm); beg = s->pending; if (s->pending == s->pending_buf_size) { val = 1; break; } } val = s->gzhead->comment[s->gzindex++]; put_byte(s, val); } while (val != 0); if (s->gzhead->hcrc && s->pending > beg) strm->adler = crc32(strm->adler, s->pending_buf + beg, s->pending - beg); if (val == 0) s->status = HCRC_STATE; } else s->status = HCRC_STATE; } if (s->status == HCRC_STATE) { if (s->gzhead->hcrc) { if (s->pending + 2 > s->pending_buf_size) flush_pending(strm); if (s->pending + 2 <= s->pending_buf_size) { put_byte(s, (Byte)(strm->adler & 0xff)); put_byte(s, (Byte)((strm->adler >> 8) & 0xff)); strm->adler = crc32(0L, Z_NULL, 0); s->status = BUSY_STATE; } } else s->status = BUSY_STATE; } #endif /* Flush as much pending output as possible */ if (s->pending != 0) { flush_pending(strm); if (strm->avail_out == 0) { /* Since avail_out is 0, deflate will be called again with * more output space, but possibly with both pending and * avail_in equal to zero. There won't be anything to do, * but this is not an error situation so make sure we * return OK instead of BUF_ERROR at next call of deflate: */ s->last_flush = -1; return Z_OK; } /* Make sure there is something to do and avoid duplicate consecutive * flushes. For repeated and useless calls with Z_FINISH, we keep * returning Z_STREAM_END instead of Z_BUF_ERROR. */ } else if (strm->avail_in == 0 && flush <= old_flush && flush != Z_FINISH) { ERR_RETURN(strm, Z_BUF_ERROR); } /* User must not provide more input after the first FINISH: */ if (s->status == FINISH_STATE && strm->avail_in != 0) { ERR_RETURN(strm, Z_BUF_ERROR); } /* Start a new block or continue the current one. */ if (strm->avail_in != 0 || s->lookahead != 0 || (flush != Z_NO_FLUSH && s->status != FINISH_STATE)) { block_state bstate; bstate = s->strategy == Z_HUFFMAN_ONLY ? deflate_huff(s, flush) : (s->strategy == Z_RLE ? deflate_rle(s, flush) : (*(configuration_table[s->level].func))(s, flush)); if (bstate == finish_started || bstate == finish_done) { s->status = FINISH_STATE; } if (bstate == need_more || bstate == finish_started) { if (strm->avail_out == 0) { s->last_flush = -1; /* avoid BUF_ERROR next call, see above */ } return Z_OK; /* If flush != Z_NO_FLUSH && avail_out == 0, the next call * of deflate should use the same flush parameter to make sure * that the flush is complete. So we don't have to output an * empty block here, this will be done at next call. This also * ensures that for a very small output buffer, we emit at most * one empty block. */ } if (bstate == block_done) { if (flush == Z_PARTIAL_FLUSH) { _tr_align(s); } else if (flush != Z_BLOCK) { /* FULL_FLUSH or SYNC_FLUSH */ _tr_stored_block(s, (char*)0, 0L, 0); /* For a full flush, this empty block will be recognized * as a special marker by inflate_sync(). */ if (flush == Z_FULL_FLUSH) { CLEAR_HASH(s); /* forget history */ if (s->lookahead == 0) { s->strstart = 0; s->block_start = 0L; } } } flush_pending(strm); if (strm->avail_out == 0) { s->last_flush = -1; /* avoid BUF_ERROR at next call, see above */ return Z_OK; } } } Assert(strm->avail_out > 0, "bug2"); if (flush != Z_FINISH) return Z_OK; if (s->wrap <= 0) return Z_STREAM_END; /* Write the trailer */ #ifdef GZIP if (s->wrap == 2) { put_byte(s, (Byte)(strm->adler & 0xff)); put_byte(s, (Byte)((strm->adler >> 8) & 0xff)); put_byte(s, (Byte)((strm->adler >> 16) & 0xff)); put_byte(s, (Byte)((strm->adler >> 24) & 0xff)); put_byte(s, (Byte)(strm->total_in & 0xff)); put_byte(s, (Byte)((strm->total_in >> 8) & 0xff)); put_byte(s, (Byte)((strm->total_in >> 16) & 0xff)); put_byte(s, (Byte)((strm->total_in >> 24) & 0xff)); } else #endif { putShortMSB(s, (uInt)(strm->adler >> 16)); putShortMSB(s, (uInt)(strm->adler & 0xffff)); } flush_pending(strm); /* If avail_out is zero, the application will call deflate again * to flush the rest. */ if (s->wrap > 0) s->wrap = -s->wrap; /* write the trailer only once! */ return s->pending != 0 ? Z_OK : Z_STREAM_END; } /* ========================================================================= */ int ZEXPORT deflateEnd (strm) z_streamp strm; { int status; if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; status = strm->state->status; if (status != INIT_STATE && status != EXTRA_STATE && status != NAME_STATE && status != COMMENT_STATE && status != HCRC_STATE && status != BUSY_STATE && status != FINISH_STATE) { return Z_STREAM_ERROR; } /* Deallocate in reverse order of allocations: */ TRY_FREE(strm, strm->state->pending_buf); TRY_FREE(strm, strm->state->head); TRY_FREE(strm, strm->state->prev); TRY_FREE(strm, strm->state->window); ZFREE(strm, strm->state); strm->state = Z_NULL; return status == BUSY_STATE ? Z_DATA_ERROR : Z_OK; } /* ========================================================================= * Copy the source state to the destination state. * To simplify the source, this is not supported for 16-bit MSDOS (which * doesn't have enough memory anyway to duplicate compression states). */ int ZEXPORT deflateCopy (dest, source) z_streamp dest; z_streamp source; { #ifdef MAXSEG_64K return Z_STREAM_ERROR; #else deflate_state *ds; deflate_state *ss; ushf *overlay; if (source == Z_NULL || dest == Z_NULL || source->state == Z_NULL) { return Z_STREAM_ERROR; } ss = source->state; zmemcpy(dest, source, sizeof(z_stream)); ds = (deflate_state *) ZALLOC(dest, 1, sizeof(deflate_state)); if (ds == Z_NULL) return Z_MEM_ERROR; dest->state = (struct internal_state FAR *) ds; zmemcpy(ds, ss, sizeof(deflate_state)); ds->strm = dest; ds->window = (Bytef *) ZALLOC(dest, ds->w_size, 2*sizeof(Byte)); ds->prev = (Posf *) ZALLOC(dest, ds->w_size, sizeof(Pos)); ds->head = (Posf *) ZALLOC(dest, ds->hash_size, sizeof(Pos)); overlay = (ushf *) ZALLOC(dest, ds->lit_bufsize, sizeof(ush)+2); ds->pending_buf = (uchf *) overlay; if (ds->window == Z_NULL || ds->prev == Z_NULL || ds->head == Z_NULL || ds->pending_buf == Z_NULL) { deflateEnd (dest); return Z_MEM_ERROR; } /* following zmemcpy do not work for 16-bit MSDOS */ zmemcpy(ds->window, ss->window, ds->w_size * 2 * sizeof(Byte)); zmemcpy(ds->prev, ss->prev, ds->w_size * sizeof(Pos)); zmemcpy(ds->head, ss->head, ds->hash_size * sizeof(Pos)); zmemcpy(ds->pending_buf, ss->pending_buf, (uInt)ds->pending_buf_size); ds->pending_out = ds->pending_buf + (ss->pending_out - ss->pending_buf); ds->d_buf = overlay + ds->lit_bufsize/sizeof(ush); ds->l_buf = ds->pending_buf + (1+sizeof(ush))*ds->lit_bufsize; ds->l_desc.dyn_tree = ds->dyn_ltree; ds->d_desc.dyn_tree = ds->dyn_dtree; ds->bl_desc.dyn_tree = ds->bl_tree; return Z_OK; #endif /* MAXSEG_64K */ } /* =========================================================================== * Read a new buffer from the current input stream, update the adler32 * and total number of bytes read. All deflate() input goes through * this function so some applications may wish to modify it to avoid * allocating a large strm->next_in buffer and copying from it. * (See also flush_pending()). */ local int read_buf(strm, buf, size) z_streamp strm; Bytef *buf; unsigned size; { unsigned len = strm->avail_in; if (len > size) len = size; if (len == 0) return 0; strm->avail_in -= len; if (strm->state->wrap == 1) { strm->adler = adler32(strm->adler, strm->next_in, len); } #ifdef GZIP else if (strm->state->wrap == 2) { strm->adler = crc32(strm->adler, strm->next_in, len); } #endif zmemcpy(buf, strm->next_in, len); strm->next_in += len; strm->total_in += len; return (int)len; } /* =========================================================================== * Initialize the "longest match" routines for a new zlib stream */ local void lm_init (s) deflate_state *s; { s->window_size = (ulg)2L*s->w_size; CLEAR_HASH(s); /* Set the default configuration parameters: */ s->max_lazy_match = configuration_table[s->level].max_lazy; s->good_match = configuration_table[s->level].good_length; s->nice_match = configuration_table[s->level].nice_length; s->max_chain_length = configuration_table[s->level].max_chain; s->strstart = 0; s->block_start = 0L; s->lookahead = 0; s->match_length = s->prev_length = MIN_MATCH-1; s->match_available = 0; s->ins_h = 0; #ifndef FASTEST #ifdef ASMV match_init(); /* initialize the asm code */ #endif #endif } #ifndef FASTEST /* =========================================================================== * Set match_start to the longest match starting at the given string and * return its length. Matches shorter or equal to prev_length are discarded, * in which case the result is equal to prev_length and match_start is * garbage. * IN assertions: cur_match is the head of the hash chain for the current * string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1 * OUT assertion: the match length is not greater than s->lookahead. */ #ifndef ASMV /* For 80x86 and 680x0, an optimized version will be provided in match.asm or * match.S. The code will be functionally equivalent. */ local uInt longest_match(s, cur_match) deflate_state *s; IPos cur_match; /* current match */ { unsigned chain_length = s->max_chain_length;/* max hash chain length */ register Bytef *scan = s->window + s->strstart; /* current string */ register Bytef *match; /* matched string */ register int len; /* length of current match */ int best_len = s->prev_length; /* best match length so far */ int nice_match = s->nice_match; /* stop if match long enough */ IPos limit = s->strstart > (IPos)MAX_DIST(s) ? s->strstart - (IPos)MAX_DIST(s) : NIL; /* Stop when cur_match becomes <= limit. To simplify the code, * we prevent matches with the string of window index 0. */ Posf *prev = s->prev; uInt wmask = s->w_mask; #ifdef UNALIGNED_OK /* Compare two bytes at a time. Note: this is not always beneficial. * Try with and without -DUNALIGNED_OK to check. */ register Bytef *strend = s->window + s->strstart + MAX_MATCH - 1; register ush scan_start = *(ushf*)scan; register ush scan_end = *(ushf*)(scan+best_len-1); #else register Bytef *strend = s->window + s->strstart + MAX_MATCH; register Byte scan_end1 = scan[best_len-1]; register Byte scan_end = scan[best_len]; #endif /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. * It is easy to get rid of this optimization if necessary. */ Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever"); /* Do not waste too much time if we already have a good match: */ if (s->prev_length >= s->good_match) { chain_length >>= 2; } /* Do not look for matches beyond the end of the input. This is necessary * to make deflate deterministic. */ if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead; Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead"); do { Assert(cur_match < s->strstart, "no future"); match = s->window + cur_match; /* Skip to next match if the match length cannot increase * or if the match length is less than 2. Note that the checks below * for insufficient lookahead only occur occasionally for performance * reasons. Therefore uninitialized memory will be accessed, and * conditional jumps will be made that depend on those values. * However the length of the match is limited to the lookahead, so * the output of deflate is not affected by the uninitialized values. */ #if (defined(UNALIGNED_OK) && MAX_MATCH == 258) /* This code assumes sizeof(unsigned short) == 2. Do not use * UNALIGNED_OK if your compiler uses a different size. */ if (*(ushf*)(match+best_len-1) != scan_end || *(ushf*)match != scan_start) continue; /* It is not necessary to compare scan[2] and match[2] since they are * always equal when the other bytes match, given that the hash keys * are equal and that HASH_BITS >= 8. Compare 2 bytes at a time at * strstart+3, +5, ... up to strstart+257. We check for insufficient * lookahead only every 4th comparison; the 128th check will be made * at strstart+257. If MAX_MATCH-2 is not a multiple of 8, it is * necessary to put more guard bytes at the end of the window, or * to check more often for insufficient lookahead. */ Assert(scan[2] == match[2], "scan[2]?"); scan++, match++; do { } while (*(ushf*)(scan+=2) == *(ushf*)(match+=2) && *(ushf*)(scan+=2) == *(ushf*)(match+=2) && *(ushf*)(scan+=2) == *(ushf*)(match+=2) && *(ushf*)(scan+=2) == *(ushf*)(match+=2) && scan < strend); /* The funny "do {}" generates better code on most compilers */ /* Here, scan <= window+strstart+257 */ Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); if (*scan == *match) scan++; len = (MAX_MATCH - 1) - (int)(strend-scan); scan = strend - (MAX_MATCH-1); #else /* UNALIGNED_OK */ if (match[best_len] != scan_end || match[best_len-1] != scan_end1 || *match != *scan || *++match != scan[1]) continue; /* The check at best_len-1 can be removed because it will be made * again later. (This heuristic is not always a win.) * It is not necessary to compare scan[2] and match[2] since they * are always equal when the other bytes match, given that * the hash keys are equal and that HASH_BITS >= 8. */ scan += 2, match++; Assert(*scan == *match, "match[2]?"); /* We check for insufficient lookahead only every 8th comparison; * the 256th check will be made at strstart+258. */ do { } while (*++scan == *++match && *++scan == *++match && *++scan == *++match && *++scan == *++match && *++scan == *++match && *++scan == *++match && *++scan == *++match && *++scan == *++match && scan < strend); Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); len = MAX_MATCH - (int)(strend - scan); scan = strend - MAX_MATCH; #endif /* UNALIGNED_OK */ if (len > best_len) { s->match_start = cur_match; best_len = len; if (len >= nice_match) break; #ifdef UNALIGNED_OK scan_end = *(ushf*)(scan+best_len-1); #else scan_end1 = scan[best_len-1]; scan_end = scan[best_len]; #endif } } while ((cur_match = prev[cur_match & wmask]) > limit && --chain_length != 0); if ((uInt)best_len <= s->lookahead) return (uInt)best_len; return s->lookahead; } #endif /* ASMV */ #else /* FASTEST */ /* --------------------------------------------------------------------------- * Optimized version for FASTEST only */ local uInt longest_match(s, cur_match) deflate_state *s; IPos cur_match; /* current match */ { register Bytef *scan = s->window + s->strstart; /* current string */ register Bytef *match; /* matched string */ register int len; /* length of current match */ register Bytef *strend = s->window + s->strstart + MAX_MATCH; /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. * It is easy to get rid of this optimization if necessary. */ Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever"); Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead"); Assert(cur_match < s->strstart, "no future"); match = s->window + cur_match; /* Return failure if the match length is less than 2: */ if (match[0] != scan[0] || match[1] != scan[1]) return MIN_MATCH-1; /* The check at best_len-1 can be removed because it will be made * again later. (This heuristic is not always a win.) * It is not necessary to compare scan[2] and match[2] since they * are always equal when the other bytes match, given that * the hash keys are equal and that HASH_BITS >= 8. */ scan += 2, match += 2; Assert(*scan == *match, "match[2]?"); /* We check for insufficient lookahead only every 8th comparison; * the 256th check will be made at strstart+258. */ do { } while (*++scan == *++match && *++scan == *++match && *++scan == *++match && *++scan == *++match && *++scan == *++match && *++scan == *++match && *++scan == *++match && *++scan == *++match && scan < strend); Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); len = MAX_MATCH - (int)(strend - scan); if (len < MIN_MATCH) return MIN_MATCH - 1; s->match_start = cur_match; return (uInt)len <= s->lookahead ? (uInt)len : s->lookahead; } #endif /* FASTEST */ #ifdef DEBUG /* =========================================================================== * Check that the match at match_start is indeed a match. */ local void check_match(s, start, match, length) deflate_state *s; IPos start, match; int length; { /* check that the match is indeed a match */ if (zmemcmp(s->window + match, s->window + start, length) != EQUAL) { fprintf(stderr, " start %u, match %u, length %d\n", start, match, length); do { fprintf(stderr, "%c%c", s->window[match++], s->window[start++]); } while (--length != 0); z_error("invalid match"); } if (z_verbose > 1) { fprintf(stderr,"\\[%d,%d]", start-match, length); do { putc(s->window[start++], stderr); } while (--length != 0); } } #else # define check_match(s, start, match, length) #endif /* DEBUG */ /* =========================================================================== * Fill the window when the lookahead becomes insufficient. * Updates strstart and lookahead. * * IN assertion: lookahead < MIN_LOOKAHEAD * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD * At least one byte has been read, or avail_in == 0; reads are * performed for at least two bytes (required for the zip translate_eol * option -- not supported here). */ local void fill_window(s) deflate_state *s; { register unsigned n, m; register Posf *p; unsigned more; /* Amount of free space at the end of the window. */ uInt wsize = s->w_size; do { more = (unsigned)(s->window_size -(ulg)s->lookahead -(ulg)s->strstart); /* Deal with !@#$% 64K limit: */ if (sizeof(int) <= 2) { if (more == 0 && s->strstart == 0 && s->lookahead == 0) { more = wsize; } else if (more == (unsigned)(-1)) { /* Very unlikely, but possible on 16 bit machine if * strstart == 0 && lookahead == 1 (input done a byte at time) */ more--; } } /* If the window is almost full and there is insufficient lookahead, * move the upper half to the lower one to make room in the upper half. */ if (s->strstart >= wsize+MAX_DIST(s)) { zmemcpy(s->window, s->window+wsize, (unsigned)wsize); s->match_start -= wsize; s->strstart -= wsize; /* we now have strstart >= MAX_DIST */ s->block_start -= (long) wsize; /* Slide the hash table (could be avoided with 32 bit values at the expense of memory usage). We slide even when level == 0 to keep the hash table consistent if we switch back to level > 0 later. (Using level 0 permanently is not an optimal usage of zlib, so we don't care about this pathological case.) */ n = s->hash_size; p = &s->head[n]; do { m = *--p; *p = (Pos)(m >= wsize ? m-wsize : NIL); } while (--n); n = wsize; #ifndef FASTEST p = &s->prev[n]; do { m = *--p; *p = (Pos)(m >= wsize ? m-wsize : NIL); /* If n is not on any hash chain, prev[n] is garbage but * its value will never be used. */ } while (--n); #endif more += wsize; } if (s->strm->avail_in == 0) return; /* If there was no sliding: * strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 && * more == window_size - lookahead - strstart * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1) * => more >= window_size - 2*WSIZE + 2 * In the BIG_MEM or MMAP case (not yet supported), * window_size == input_size + MIN_LOOKAHEAD && * strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD. * Otherwise, window_size == 2*WSIZE so more >= 2. * If there was sliding, more >= WSIZE. So in all cases, more >= 2. */ Assert(more >= 2, "more < 2"); n = read_buf(s->strm, s->window + s->strstart + s->lookahead, more); s->lookahead += n; /* Initialize the hash value now that we have some input: */ if (s->lookahead >= MIN_MATCH) { s->ins_h = s->window[s->strstart]; UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]); #if MIN_MATCH != 3 Call UPDATE_HASH() MIN_MATCH-3 more times #endif } /* If the whole input has less than MIN_MATCH bytes, ins_h is garbage, * but this is not important since only literal bytes will be emitted. */ } while (s->lookahead < MIN_LOOKAHEAD && s->strm->avail_in != 0); /* If the WIN_INIT bytes after the end of the current data have never been * written, then zero those bytes in order to avoid memory check reports of * the use of uninitialized (or uninitialised as Julian writes) bytes by * the longest match routines. Update the high water mark for the next * time through here. WIN_INIT is set to MAX_MATCH since the longest match * routines allow scanning to strstart + MAX_MATCH, ignoring lookahead. */ if (s->high_water < s->window_size) { ulg curr = s->strstart + (ulg)(s->lookahead); ulg init; if (s->high_water < curr) { /* Previous high water mark below current data -- zero WIN_INIT * bytes or up to end of window, whichever is less. */ init = s->window_size - curr; if (init > WIN_INIT) init = WIN_INIT; zmemzero(s->window + curr, (unsigned)init); s->high_water = curr + init; } else if (s->high_water < (ulg)curr + WIN_INIT) { /* High water mark at or above current data, but below current data * plus WIN_INIT -- zero out to current data plus WIN_INIT, or up * to end of window, whichever is less. */ init = (ulg)curr + WIN_INIT - s->high_water; if (init > s->window_size - s->high_water) init = s->window_size - s->high_water; zmemzero(s->window + s->high_water, (unsigned)init); s->high_water += init; } } } /* =========================================================================== * Flush the current block, with given end-of-file flag. * IN assertion: strstart is set to the end of the current match. */ #define FLUSH_BLOCK_ONLY(s, last) { \ _tr_flush_block(s, (s->block_start >= 0L ? \ (charf *)&s->window[(unsigned)s->block_start] : \ (charf *)Z_NULL), \ (ulg)((long)s->strstart - s->block_start), \ (last)); \ s->block_start = s->strstart; \ flush_pending(s->strm); \ Tracev((stderr,"[FLUSH]")); \ } /* Same but force premature exit if necessary. */ #define FLUSH_BLOCK(s, last) { \ FLUSH_BLOCK_ONLY(s, last); \ if (s->strm->avail_out == 0) return (last) ? finish_started : need_more; \ } /* =========================================================================== * Copy without compression as much as possible from the input stream, return * the current block state. * This function does not insert new strings in the dictionary since * uncompressible data is probably not useful. This function is used * only for the level=0 compression option. * NOTE: this function should be optimized to avoid extra copying from * window to pending_buf. */ local block_state deflate_stored(s, flush) deflate_state *s; int flush; { /* Stored blocks are limited to 0xffff bytes, pending_buf is limited * to pending_buf_size, and each stored block has a 5 byte header: */ ulg max_block_size = 0xffff; ulg max_start; if (max_block_size > s->pending_buf_size - 5) { max_block_size = s->pending_buf_size - 5; } /* Copy as much as possible from input to output: */ for (;;) { /* Fill the window as much as possible: */ if (s->lookahead <= 1) { Assert(s->strstart < s->w_size+MAX_DIST(s) || s->block_start >= (long)s->w_size, "slide too late"); fill_window(s); if (s->lookahead == 0 && flush == Z_NO_FLUSH) return need_more; if (s->lookahead == 0) break; /* flush the current block */ } Assert(s->block_start >= 0L, "block gone"); s->strstart += s->lookahead; s->lookahead = 0; /* Emit a stored block if pending_buf will be full: */ max_start = s->block_start + max_block_size; if (s->strstart == 0 || (ulg)s->strstart >= max_start) { /* strstart == 0 is possible when wraparound on 16-bit machine */ s->lookahead = (uInt)(s->strstart - max_start); s->strstart = (uInt)max_start; FLUSH_BLOCK(s, 0); } /* Flush if we may have to slide, otherwise block_start may become * negative and the data will be gone: */ if (s->strstart - (uInt)s->block_start >= MAX_DIST(s)) { FLUSH_BLOCK(s, 0); } } FLUSH_BLOCK(s, flush == Z_FINISH); return flush == Z_FINISH ? finish_done : block_done; } /* =========================================================================== * Compress as much as possible from the input stream, return the current * block state. * This function does not perform lazy evaluation of matches and inserts * new strings in the dictionary only for unmatched strings or for short * matches. It is used only for the fast compression options. */ local block_state deflate_fast(s, flush) deflate_state *s; int flush; { IPos hash_head; /* head of the hash chain */ int bflush; /* set if current block must be flushed */ for (;;) { /* Make sure that we always have enough lookahead, except * at the end of the input file. We need MAX_MATCH bytes * for the next match, plus MIN_MATCH bytes to insert the * string following the next match. */ if (s->lookahead < MIN_LOOKAHEAD) { fill_window(s); if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) { return need_more; } if (s->lookahead == 0) break; /* flush the current block */ } /* Insert the string window[strstart .. strstart+2] in the * dictionary, and set hash_head to the head of the hash chain: */ hash_head = NIL; if (s->lookahead >= MIN_MATCH) { INSERT_STRING(s, s->strstart, hash_head); } /* Find the longest match, discarding those <= prev_length. * At this point we have always match_length < MIN_MATCH */ if (hash_head != NIL && s->strstart - hash_head <= MAX_DIST(s)) { /* To simplify the code, we prevent matches with the string * of window index 0 (in particular we have to avoid a match * of the string with itself at the start of the input file). */ s->match_length = longest_match (s, hash_head); /* longest_match() sets match_start */ } if (s->match_length >= MIN_MATCH) { check_match(s, s->strstart, s->match_start, s->match_length); _tr_tally_dist(s, s->strstart - s->match_start, s->match_length - MIN_MATCH, bflush); s->lookahead -= s->match_length; /* Insert new strings in the hash table only if the match length * is not too large. This saves time but degrades compression. */ #ifndef FASTEST if (s->match_length <= s->max_insert_length && s->lookahead >= MIN_MATCH) { s->match_length--; /* string at strstart already in table */ do { s->strstart++; INSERT_STRING(s, s->strstart, hash_head); /* strstart never exceeds WSIZE-MAX_MATCH, so there are * always MIN_MATCH bytes ahead. */ } while (--s->match_length != 0); s->strstart++; } else #endif { s->strstart += s->match_length; s->match_length = 0; s->ins_h = s->window[s->strstart]; UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]); #if MIN_MATCH != 3 Call UPDATE_HASH() MIN_MATCH-3 more times #endif /* If lookahead < MIN_MATCH, ins_h is garbage, but it does not * matter since it will be recomputed at next deflate call. */ } } else { /* No match, output a literal byte */ Tracevv((stderr,"%c", s->window[s->strstart])); _tr_tally_lit (s, s->window[s->strstart], bflush); s->lookahead--; s->strstart++; } if (bflush) FLUSH_BLOCK(s, 0); } FLUSH_BLOCK(s, flush == Z_FINISH); return flush == Z_FINISH ? finish_done : block_done; } #ifndef FASTEST /* =========================================================================== * Same as above, but achieves better compression. We use a lazy * evaluation for matches: a match is finally adopted only if there is * no better match at the next window position. */ local block_state deflate_slow(s, flush) deflate_state *s; int flush; { IPos hash_head; /* head of hash chain */ int bflush; /* set if current block must be flushed */ /* Process the input block. */ for (;;) { /* Make sure that we always have enough lookahead, except * at the end of the input file. We need MAX_MATCH bytes * for the next match, plus MIN_MATCH bytes to insert the * string following the next match. */ if (s->lookahead < MIN_LOOKAHEAD) { fill_window(s); if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) { return need_more; } if (s->lookahead == 0) break; /* flush the current block */ } /* Insert the string window[strstart .. strstart+2] in the * dictionary, and set hash_head to the head of the hash chain: */ hash_head = NIL; if (s->lookahead >= MIN_MATCH) { INSERT_STRING(s, s->strstart, hash_head); } /* Find the longest match, discarding those <= prev_length. */ s->prev_length = s->match_length, s->prev_match = s->match_start; s->match_length = MIN_MATCH-1; if (hash_head != NIL && s->prev_length < s->max_lazy_match && s->strstart - hash_head <= MAX_DIST(s)) { /* To simplify the code, we prevent matches with the string * of window index 0 (in particular we have to avoid a match * of the string with itself at the start of the input file). */ s->match_length = longest_match (s, hash_head); /* longest_match() sets match_start */ if (s->match_length <= 5 && (s->strategy == Z_FILTERED #if TOO_FAR <= 32767 || (s->match_length == MIN_MATCH && s->strstart - s->match_start > TOO_FAR) #endif )) { /* If prev_match is also MIN_MATCH, match_start is garbage * but we will ignore the current match anyway. */ s->match_length = MIN_MATCH-1; } } /* If there was a match at the previous step and the current * match is not better, output the previous match: */ if (s->prev_length >= MIN_MATCH && s->match_length <= s->prev_length) { uInt max_insert = s->strstart + s->lookahead - MIN_MATCH; /* Do not insert strings in hash table beyond this. */ check_match(s, s->strstart-1, s->prev_match, s->prev_length); _tr_tally_dist(s, s->strstart -1 - s->prev_match, s->prev_length - MIN_MATCH, bflush); /* Insert in hash table all strings up to the end of the match. * strstart-1 and strstart are already inserted. If there is not * enough lookahead, the last two strings are not inserted in * the hash table. */ s->lookahead -= s->prev_length-1; s->prev_length -= 2; do { if (++s->strstart <= max_insert) { INSERT_STRING(s, s->strstart, hash_head); } } while (--s->prev_length != 0); s->match_available = 0; s->match_length = MIN_MATCH-1; s->strstart++; if (bflush) FLUSH_BLOCK(s, 0); } else if (s->match_available) { /* If there was no match at the previous position, output a * single literal. If there was a match but the current match * is longer, truncate the previous match to a single literal. */ Tracevv((stderr,"%c", s->window[s->strstart-1])); _tr_tally_lit(s, s->window[s->strstart-1], bflush); if (bflush) { FLUSH_BLOCK_ONLY(s, 0); } s->strstart++; s->lookahead--; if (s->strm->avail_out == 0) return need_more; } else { /* There is no previous match to compare with, wait for * the next step to decide. */ s->match_available = 1; s->strstart++; s->lookahead--; } } Assert (flush != Z_NO_FLUSH, "no flush?"); if (s->match_available) { Tracevv((stderr,"%c", s->window[s->strstart-1])); _tr_tally_lit(s, s->window[s->strstart-1], bflush); s->match_available = 0; } FLUSH_BLOCK(s, flush == Z_FINISH); return flush == Z_FINISH ? finish_done : block_done; } #endif /* FASTEST */ /* =========================================================================== * For Z_RLE, simply look for runs of bytes, generate matches only of distance * one. Do not maintain a hash table. (It will be regenerated if this run of * deflate switches away from Z_RLE.) */ local block_state deflate_rle(s, flush) deflate_state *s; int flush; { int bflush; /* set if current block must be flushed */ uInt prev; /* byte at distance one to match */ Bytef *scan, *strend; /* scan goes up to strend for length of run */ for (;;) { /* Make sure that we always have enough lookahead, except * at the end of the input file. We need MAX_MATCH bytes * for the longest encodable run. */ if (s->lookahead < MAX_MATCH) { fill_window(s); if (s->lookahead < MAX_MATCH && flush == Z_NO_FLUSH) { return need_more; } if (s->lookahead == 0) break; /* flush the current block */ } /* See how many times the previous byte repeats */ s->match_length = 0; if (s->lookahead >= MIN_MATCH && s->strstart > 0) { scan = s->window + s->strstart - 1; prev = *scan; if (prev == *++scan && prev == *++scan && prev == *++scan) { strend = s->window + s->strstart + MAX_MATCH; do { } while (prev == *++scan && prev == *++scan && prev == *++scan && prev == *++scan && prev == *++scan && prev == *++scan && prev == *++scan && prev == *++scan && scan < strend); s->match_length = MAX_MATCH - (int)(strend - scan); if (s->match_length > s->lookahead) s->match_length = s->lookahead; } } /* Emit match if have run of MIN_MATCH or longer, else emit literal */ if (s->match_length >= MIN_MATCH) { check_match(s, s->strstart, s->strstart - 1, s->match_length); _tr_tally_dist(s, 1, s->match_length - MIN_MATCH, bflush); s->lookahead -= s->match_length; s->strstart += s->match_length; s->match_length = 0; } else { /* No match, output a literal byte */ Tracevv((stderr,"%c", s->window[s->strstart])); _tr_tally_lit (s, s->window[s->strstart], bflush); s->lookahead--; s->strstart++; } if (bflush) FLUSH_BLOCK(s, 0); } FLUSH_BLOCK(s, flush == Z_FINISH); return flush == Z_FINISH ? finish_done : block_done; } /* =========================================================================== * For Z_HUFFMAN_ONLY, do not look for matches. Do not maintain a hash table. * (It will be regenerated if this run of deflate switches away from Huffman.) */ local block_state deflate_huff(s, flush) deflate_state *s; int flush; { int bflush; /* set if current block must be flushed */ for (;;) { /* Make sure that we have a literal to write. */ if (s->lookahead == 0) { fill_window(s); if (s->lookahead == 0) { if (flush == Z_NO_FLUSH) return need_more; break; /* flush the current block */ } } /* Output a literal byte */ s->match_length = 0; Tracevv((stderr,"%c", s->window[s->strstart])); _tr_tally_lit (s, s->window[s->strstart], bflush); s->lookahead--; s->strstart++; if (bflush) FLUSH_BLOCK(s, 0); } FLUSH_BLOCK(s, flush == Z_FINISH); return flush == Z_FINISH ? finish_done : block_done; } libgit2-0.19.0/deps/zlib/deflate.h000066400000000000000000000306171216214232500166120ustar00rootroot00000000000000/* deflate.h -- internal compression state * Copyright (C) 1995-2010 Jean-loup Gailly * For conditions of distribution and use, see copyright notice in zlib.h */ /* WARNING: this file should *not* be used by applications. It is part of the implementation of the compression library and is subject to change. Applications should only use zlib.h. */ /* @(#) $Id$ */ #ifndef DEFLATE_H #define DEFLATE_H #include "zutil.h" /* define NO_GZIP when compiling if you want to disable gzip header and trailer creation by deflate(). NO_GZIP would be used to avoid linking in the crc code when it is not needed. For shared libraries, gzip encoding should be left enabled. */ #ifndef NO_GZIP # define GZIP #endif /* =========================================================================== * Internal compression state. */ #define LENGTH_CODES 29 /* number of length codes, not counting the special END_BLOCK code */ #define LITERALS 256 /* number of literal bytes 0..255 */ #define L_CODES (LITERALS+1+LENGTH_CODES) /* number of Literal or Length codes, including the END_BLOCK code */ #define D_CODES 30 /* number of distance codes */ #define BL_CODES 19 /* number of codes used to transfer the bit lengths */ #define HEAP_SIZE (2*L_CODES+1) /* maximum heap size */ #define MAX_BITS 15 /* All codes must not exceed MAX_BITS bits */ #define INIT_STATE 42 #define EXTRA_STATE 69 #define NAME_STATE 73 #define COMMENT_STATE 91 #define HCRC_STATE 103 #define BUSY_STATE 113 #define FINISH_STATE 666 /* Stream status */ /* Data structure describing a single value and its code string. */ typedef struct ct_data_s { union { ush freq; /* frequency count */ ush code; /* bit string */ } fc; union { ush dad; /* father node in Huffman tree */ ush len; /* length of bit string */ } dl; } FAR ct_data; #define Freq fc.freq #define Code fc.code #define Dad dl.dad #define Len dl.len typedef struct static_tree_desc_s static_tree_desc; typedef struct tree_desc_s { ct_data *dyn_tree; /* the dynamic tree */ int max_code; /* largest code with non zero frequency */ static_tree_desc *stat_desc; /* the corresponding static tree */ } FAR tree_desc; typedef ush Pos; typedef Pos FAR Posf; typedef unsigned IPos; /* A Pos is an index in the character window. We use short instead of int to * save space in the various tables. IPos is used only for parameter passing. */ typedef struct internal_state { z_streamp strm; /* pointer back to this zlib stream */ int status; /* as the name implies */ Bytef *pending_buf; /* output still pending */ ulg pending_buf_size; /* size of pending_buf */ Bytef *pending_out; /* next pending byte to output to the stream */ uInt pending; /* nb of bytes in the pending buffer */ int wrap; /* bit 0 true for zlib, bit 1 true for gzip */ gz_headerp gzhead; /* gzip header information to write */ uInt gzindex; /* where in extra, name, or comment */ Byte method; /* STORED (for zip only) or DEFLATED */ int last_flush; /* value of flush param for previous deflate call */ /* used by deflate.c: */ uInt w_size; /* LZ77 window size (32K by default) */ uInt w_bits; /* log2(w_size) (8..16) */ uInt w_mask; /* w_size - 1 */ Bytef *window; /* Sliding window. Input bytes are read into the second half of the window, * and move to the first half later to keep a dictionary of at least wSize * bytes. With this organization, matches are limited to a distance of * wSize-MAX_MATCH bytes, but this ensures that IO is always * performed with a length multiple of the block size. Also, it limits * the window size to 64K, which is quite useful on MSDOS. * To do: use the user input buffer as sliding window. */ ulg window_size; /* Actual size of window: 2*wSize, except when the user input buffer * is directly used as sliding window. */ Posf *prev; /* Link to older string with same hash index. To limit the size of this * array to 64K, this link is maintained only for the last 32K strings. * An index in this array is thus a window index modulo 32K. */ Posf *head; /* Heads of the hash chains or NIL. */ uInt ins_h; /* hash index of string to be inserted */ uInt hash_size; /* number of elements in hash table */ uInt hash_bits; /* log2(hash_size) */ uInt hash_mask; /* hash_size-1 */ uInt hash_shift; /* Number of bits by which ins_h must be shifted at each input * step. It must be such that after MIN_MATCH steps, the oldest * byte no longer takes part in the hash key, that is: * hash_shift * MIN_MATCH >= hash_bits */ long block_start; /* Window position at the beginning of the current output block. Gets * negative when the window is moved backwards. */ uInt match_length; /* length of best match */ IPos prev_match; /* previous match */ int match_available; /* set if previous match exists */ uInt strstart; /* start of string to insert */ uInt match_start; /* start of matching string */ uInt lookahead; /* number of valid bytes ahead in window */ uInt prev_length; /* Length of the best match at previous step. Matches not greater than this * are discarded. This is used in the lazy match evaluation. */ uInt max_chain_length; /* To speed up deflation, hash chains are never searched beyond this * length. A higher limit improves compression ratio but degrades the * speed. */ uInt max_lazy_match; /* Attempt to find a better match only when the current match is strictly * smaller than this value. This mechanism is used only for compression * levels >= 4. */ # define max_insert_length max_lazy_match /* Insert new strings in the hash table only if the match length is not * greater than this length. This saves time but degrades compression. * max_insert_length is used only for compression levels <= 3. */ int level; /* compression level (1..9) */ int strategy; /* favor or force Huffman coding*/ uInt good_match; /* Use a faster search when the previous match is longer than this */ int nice_match; /* Stop searching when current match exceeds this */ /* used by trees.c: */ /* Didn't use ct_data typedef below to supress compiler warning */ struct ct_data_s dyn_ltree[HEAP_SIZE]; /* literal and length tree */ struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */ struct ct_data_s bl_tree[2*BL_CODES+1]; /* Huffman tree for bit lengths */ struct tree_desc_s l_desc; /* desc. for literal tree */ struct tree_desc_s d_desc; /* desc. for distance tree */ struct tree_desc_s bl_desc; /* desc. for bit length tree */ ush bl_count[MAX_BITS+1]; /* number of codes at each bit length for an optimal tree */ int heap[2*L_CODES+1]; /* heap used to build the Huffman trees */ int heap_len; /* number of elements in the heap */ int heap_max; /* element of largest frequency */ /* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used. * The same heap array is used to build all trees. */ uch depth[2*L_CODES+1]; /* Depth of each subtree used as tie breaker for trees of equal frequency */ uchf *l_buf; /* buffer for literals or lengths */ uInt lit_bufsize; /* Size of match buffer for literals/lengths. There are 4 reasons for * limiting lit_bufsize to 64K: * - frequencies can be kept in 16 bit counters * - if compression is not successful for the first block, all input * data is still in the window so we can still emit a stored block even * when input comes from standard input. (This can also be done for * all blocks if lit_bufsize is not greater than 32K.) * - if compression is not successful for a file smaller than 64K, we can * even emit a stored file instead of a stored block (saving 5 bytes). * This is applicable only for zip (not gzip or zlib). * - creating new Huffman trees less frequently may not provide fast * adaptation to changes in the input data statistics. (Take for * example a binary file with poorly compressible code followed by * a highly compressible string table.) Smaller buffer sizes give * fast adaptation but have of course the overhead of transmitting * trees more frequently. * - I can't count above 4 */ uInt last_lit; /* running index in l_buf */ ushf *d_buf; /* Buffer for distances. To simplify the code, d_buf and l_buf have * the same number of elements. To use different lengths, an extra flag * array would be necessary. */ ulg opt_len; /* bit length of current block with optimal trees */ ulg static_len; /* bit length of current block with static trees */ uInt matches; /* number of string matches in current block */ int last_eob_len; /* bit length of EOB code for last block */ #ifdef DEBUG ulg compressed_len; /* total bit length of compressed file mod 2^32 */ ulg bits_sent; /* bit length of compressed data sent mod 2^32 */ #endif ush bi_buf; /* Output buffer. bits are inserted starting at the bottom (least * significant bits). */ int bi_valid; /* Number of valid bits in bi_buf. All bits above the last valid bit * are always zero. */ ulg high_water; /* High water mark offset in window for initialized bytes -- bytes above * this are set to zero in order to avoid memory check warnings when * longest match routines access bytes past the input. This is then * updated to the new high water mark. */ } FAR deflate_state; /* Output a byte on the stream. * IN assertion: there is enough room in pending_buf. */ #define put_byte(s, c) {s->pending_buf[s->pending++] = (c);} #define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1) /* Minimum amount of lookahead, except at the end of the input file. * See deflate.c for comments about the MIN_MATCH+1. */ #define MAX_DIST(s) ((s)->w_size-MIN_LOOKAHEAD) /* In order to simplify the code, particularly on 16 bit machines, match * distances are limited to MAX_DIST instead of WSIZE. */ #define WIN_INIT MAX_MATCH /* Number of bytes after end of data in window to initialize in order to avoid memory checker errors from longest match routines */ /* in trees.c */ void ZLIB_INTERNAL _tr_init OF((deflate_state *s)); int ZLIB_INTERNAL _tr_tally OF((deflate_state *s, unsigned dist, unsigned lc)); void ZLIB_INTERNAL _tr_flush_block OF((deflate_state *s, charf *buf, ulg stored_len, int last)); void ZLIB_INTERNAL _tr_align OF((deflate_state *s)); void ZLIB_INTERNAL _tr_stored_block OF((deflate_state *s, charf *buf, ulg stored_len, int last)); #define d_code(dist) \ ((dist) < 256 ? _dist_code[dist] : _dist_code[256+((dist)>>7)]) /* Mapping from a distance to a distance code. dist is the distance - 1 and * must not have side effects. _dist_code[256] and _dist_code[257] are never * used. */ #ifndef DEBUG /* Inline versions of _tr_tally for speed: */ #if defined(GEN_TREES_H) || !defined(STDC) extern uch ZLIB_INTERNAL _length_code[]; extern uch ZLIB_INTERNAL _dist_code[]; #else extern const uch ZLIB_INTERNAL _length_code[]; extern const uch ZLIB_INTERNAL _dist_code[]; #endif # define _tr_tally_lit(s, c, flush) \ { uch cc = (uch)(c); \ s->d_buf[s->last_lit] = 0; \ s->l_buf[s->last_lit++] = cc; \ s->dyn_ltree[cc].Freq++; \ flush = (s->last_lit == s->lit_bufsize-1); \ } # define _tr_tally_dist(s, distance, length, flush) \ { uch len = (uch)(length); \ ush dist = (ush)(distance); \ s->d_buf[s->last_lit] = dist; \ s->l_buf[s->last_lit++] = len; \ dist--; \ s->dyn_ltree[_length_code[len]+LITERALS+1].Freq++; \ s->dyn_dtree[d_code(dist)].Freq++; \ flush = (s->last_lit == s->lit_bufsize-1); \ } #else # define _tr_tally_lit(s, c, flush) flush = _tr_tally(s, 0, c) # define _tr_tally_dist(s, distance, length, flush) \ flush = _tr_tally(s, distance, length) #endif #endif /* DEFLATE_H */ libgit2-0.19.0/deps/zlib/inffast.c000066400000000000000000000321771216214232500166360ustar00rootroot00000000000000/* inffast.c -- fast decoding * Copyright (C) 1995-2008, 2010 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ #include "zutil.h" #include "inftrees.h" #include "inflate.h" #include "inffast.h" #ifndef ASMINF /* Allow machine dependent optimization for post-increment or pre-increment. Based on testing to date, Pre-increment preferred for: - PowerPC G3 (Adler) - MIPS R5000 (Randers-Pehrson) Post-increment preferred for: - none No measurable difference: - Pentium III (Anderson) - M68060 (Nikl) */ #ifdef POSTINC # define OFF 0 # define PUP(a) *(a)++ #else # define OFF 1 # define PUP(a) *++(a) #endif /* Decode literal, length, and distance codes and write out the resulting literal and match bytes until either not enough input or output is available, an end-of-block is encountered, or a data error is encountered. When large enough input and output buffers are supplied to inflate(), for example, a 16K input buffer and a 64K output buffer, more than 95% of the inflate execution time is spent in this routine. Entry assumptions: state->mode == LEN strm->avail_in >= 6 strm->avail_out >= 258 start >= strm->avail_out state->bits < 8 On return, state->mode is one of: LEN -- ran out of enough output space or enough available input TYPE -- reached end of block code, inflate() to interpret next block BAD -- error in block data Notes: - The maximum input bits used by a length/distance pair is 15 bits for the length code, 5 bits for the length extra, 15 bits for the distance code, and 13 bits for the distance extra. This totals 48 bits, or six bytes. Therefore if strm->avail_in >= 6, then there is enough input to avoid checking for available input while decoding. - The maximum bytes that a single length/distance pair can output is 258 bytes, which is the maximum length that can be coded. inflate_fast() requires strm->avail_out >= 258 for each loop to avoid checking for output space. */ void ZLIB_INTERNAL inflate_fast(strm, start) z_streamp strm; unsigned start; /* inflate()'s starting value for strm->avail_out */ { struct inflate_state FAR *state; unsigned char FAR *in; /* local strm->next_in */ unsigned char FAR *last; /* while in < last, enough input available */ unsigned char FAR *out; /* local strm->next_out */ unsigned char FAR *beg; /* inflate()'s initial strm->next_out */ unsigned char FAR *end; /* while out < end, enough space available */ #ifdef INFLATE_STRICT unsigned dmax; /* maximum distance from zlib header */ #endif unsigned wsize; /* window size or zero if not using window */ unsigned whave; /* valid bytes in the window */ unsigned wnext; /* window write index */ unsigned char FAR *window; /* allocated sliding window, if wsize != 0 */ unsigned long hold; /* local strm->hold */ unsigned bits; /* local strm->bits */ code const FAR *lcode; /* local strm->lencode */ code const FAR *dcode; /* local strm->distcode */ unsigned lmask; /* mask for first level of length codes */ unsigned dmask; /* mask for first level of distance codes */ code here; /* retrieved table entry */ unsigned op; /* code bits, operation, extra bits, or */ /* window position, window bytes to copy */ unsigned len; /* match length, unused bytes */ unsigned dist; /* match distance */ unsigned char FAR *from; /* where to copy match from */ /* copy state to local variables */ state = (struct inflate_state FAR *)strm->state; in = strm->next_in - OFF; last = in + (strm->avail_in - 5); out = strm->next_out - OFF; beg = out - (start - strm->avail_out); end = out + (strm->avail_out - 257); #ifdef INFLATE_STRICT dmax = state->dmax; #endif wsize = state->wsize; whave = state->whave; wnext = state->wnext; window = state->window; hold = state->hold; bits = state->bits; lcode = state->lencode; dcode = state->distcode; lmask = (1U << state->lenbits) - 1; dmask = (1U << state->distbits) - 1; /* decode literals and length/distances until end-of-block or not enough input data or output space */ do { if (bits < 15) { hold += (unsigned long)(PUP(in)) << bits; bits += 8; hold += (unsigned long)(PUP(in)) << bits; bits += 8; } here = lcode[hold & lmask]; dolen: op = (unsigned)(here.bits); hold >>= op; bits -= op; op = (unsigned)(here.op); if (op == 0) { /* literal */ Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ? "inflate: literal '%c'\n" : "inflate: literal 0x%02x\n", here.val)); PUP(out) = (unsigned char)(here.val); } else if (op & 16) { /* length base */ len = (unsigned)(here.val); op &= 15; /* number of extra bits */ if (op) { if (bits < op) { hold += (unsigned long)(PUP(in)) << bits; bits += 8; } len += (unsigned)hold & ((1U << op) - 1); hold >>= op; bits -= op; } Tracevv((stderr, "inflate: length %u\n", len)); if (bits < 15) { hold += (unsigned long)(PUP(in)) << bits; bits += 8; hold += (unsigned long)(PUP(in)) << bits; bits += 8; } here = dcode[hold & dmask]; dodist: op = (unsigned)(here.bits); hold >>= op; bits -= op; op = (unsigned)(here.op); if (op & 16) { /* distance base */ dist = (unsigned)(here.val); op &= 15; /* number of extra bits */ if (bits < op) { hold += (unsigned long)(PUP(in)) << bits; bits += 8; if (bits < op) { hold += (unsigned long)(PUP(in)) << bits; bits += 8; } } dist += (unsigned)hold & ((1U << op) - 1); #ifdef INFLATE_STRICT if (dist > dmax) { strm->msg = (char *)"invalid distance too far back"; state->mode = BAD; break; } #endif hold >>= op; bits -= op; Tracevv((stderr, "inflate: distance %u\n", dist)); op = (unsigned)(out - beg); /* max distance in output */ if (dist > op) { /* see if copy from window */ op = dist - op; /* distance back in window */ if (op > whave) { if (state->sane) { strm->msg = (char *)"invalid distance too far back"; state->mode = BAD; break; } #ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR if (len <= op - whave) { do { PUP(out) = 0; } while (--len); continue; } len -= op - whave; do { PUP(out) = 0; } while (--op > whave); if (op == 0) { from = out - dist; do { PUP(out) = PUP(from); } while (--len); continue; } #endif } from = window - OFF; if (wnext == 0) { /* very common case */ from += wsize - op; if (op < len) { /* some from window */ len -= op; do { PUP(out) = PUP(from); } while (--op); from = out - dist; /* rest from output */ } } else if (wnext < op) { /* wrap around window */ from += wsize + wnext - op; op -= wnext; if (op < len) { /* some from end of window */ len -= op; do { PUP(out) = PUP(from); } while (--op); from = window - OFF; if (wnext < len) { /* some from start of window */ op = wnext; len -= op; do { PUP(out) = PUP(from); } while (--op); from = out - dist; /* rest from output */ } } } else { /* contiguous in window */ from += wnext - op; if (op < len) { /* some from window */ len -= op; do { PUP(out) = PUP(from); } while (--op); from = out - dist; /* rest from output */ } } while (len > 2) { PUP(out) = PUP(from); PUP(out) = PUP(from); PUP(out) = PUP(from); len -= 3; } if (len) { PUP(out) = PUP(from); if (len > 1) PUP(out) = PUP(from); } } else { from = out - dist; /* copy direct from output */ do { /* minimum length is three */ PUP(out) = PUP(from); PUP(out) = PUP(from); PUP(out) = PUP(from); len -= 3; } while (len > 2); if (len) { PUP(out) = PUP(from); if (len > 1) PUP(out) = PUP(from); } } } else if ((op & 64) == 0) { /* 2nd level distance code */ here = dcode[here.val + (hold & ((1U << op) - 1))]; goto dodist; } else { strm->msg = (char *)"invalid distance code"; state->mode = BAD; break; } } else if ((op & 64) == 0) { /* 2nd level length code */ here = lcode[here.val + (hold & ((1U << op) - 1))]; goto dolen; } else if (op & 32) { /* end-of-block */ Tracevv((stderr, "inflate: end of block\n")); state->mode = TYPE; break; } else { strm->msg = (char *)"invalid literal/length code"; state->mode = BAD; break; } } while (in < last && out < end); /* return unused bytes (on entry, bits < 8, so in won't go too far back) */ len = bits >> 3; in -= len; bits -= len << 3; hold &= (1U << bits) - 1; /* update state and return */ strm->next_in = in + OFF; strm->next_out = out + OFF; strm->avail_in = (unsigned)(in < last ? 5 + (last - in) : 5 - (in - last)); strm->avail_out = (unsigned)(out < end ? 257 + (end - out) : 257 - (out - end)); state->hold = hold; state->bits = bits; return; } /* inflate_fast() speedups that turned out slower (on a PowerPC G3 750CXe): - Using bit fields for code structure - Different op definition to avoid & for extra bits (do & for table bits) - Three separate decoding do-loops for direct, window, and wnext == 0 - Special case for distance > 1 copies to do overlapped load and store copy - Explicit branch predictions (based on measured branch probabilities) - Deferring match copy and interspersed it with decoding subsequent codes - Swapping literal/length else - Swapping window/direct else - Larger unrolled copy loops (three is about right) - Moving len -= 3 statement into middle of loop */ #endif /* !ASMINF */ libgit2-0.19.0/deps/zlib/inffast.h000066400000000000000000000006531216214232500166350ustar00rootroot00000000000000/* 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)); libgit2-0.19.0/deps/zlib/inffixed.h000066400000000000000000000143071216214232500170000ustar00rootroot00000000000000 /* 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} }; libgit2-0.19.0/deps/zlib/inflate.c000066400000000000000000001466171216214232500166330ustar00rootroot00000000000000/* inflate.c -- zlib decompression * Copyright (C) 1995-2010 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ /* * Change history: * * 1.2.beta0 24 Nov 2002 * - First version -- complete rewrite of inflate to simplify code, avoid * creation of window when not needed, minimize use of window when it is * needed, make inffast.c even faster, implement gzip decoding, and to * improve code readability and style over the previous zlib inflate code * * 1.2.beta1 25 Nov 2002 * - Use pointers for available input and output checking in inffast.c * - Remove input and output counters in inffast.c * - Change inffast.c entry and loop from avail_in >= 7 to >= 6 * - Remove unnecessary second byte pull from length extra in inffast.c * - Unroll direct copy to three copies per loop in inffast.c * * 1.2.beta2 4 Dec 2002 * - Change external routine names to reduce potential conflicts * - Correct filename to inffixed.h for fixed tables in inflate.c * - Make hbuf[] unsigned char to match parameter type in inflate.c * - Change strm->next_out[-state->offset] to *(strm->next_out - state->offset) * to avoid negation problem on Alphas (64 bit) in inflate.c * * 1.2.beta3 22 Dec 2002 * - Add comments on state->bits assertion in inffast.c * - Add comments on op field in inftrees.h * - Fix bug in reuse of allocated window after inflateReset() * - Remove bit fields--back to byte structure for speed * - Remove distance extra == 0 check in inflate_fast()--only helps for lengths * - Change post-increments to pre-increments in inflate_fast(), PPC biased? * - Add compile time option, POSTINC, to use post-increments instead (Intel?) * - Make MATCH copy in inflate() much faster for when inflate_fast() not used * - Use local copies of stream next and avail values, as well as local bit * buffer and bit count in inflate()--for speed when inflate_fast() not used * * 1.2.beta4 1 Jan 2003 * - Split ptr - 257 statements in inflate_table() to avoid compiler warnings * - Move a comment on output buffer sizes from inffast.c to inflate.c * - Add comments in inffast.c to introduce the inflate_fast() routine * - Rearrange window copies in inflate_fast() for speed and simplification * - Unroll last copy for window match in inflate_fast() * - Use local copies of window variables in inflate_fast() for speed * - Pull out common wnext == 0 case for speed in inflate_fast() * - Make op and len in inflate_fast() unsigned for consistency * - Add FAR to lcode and dcode declarations in inflate_fast() * - Simplified bad distance check in inflate_fast() * - Added inflateBackInit(), inflateBack(), and inflateBackEnd() in new * source file infback.c to provide a call-back interface to inflate for * programs like gzip and unzip -- uses window as output buffer to avoid * window copying * * 1.2.beta5 1 Jan 2003 * - Improved inflateBack() interface to allow the caller to provide initial * input in strm. * - Fixed stored blocks bug in inflateBack() * * 1.2.beta6 4 Jan 2003 * - Added comments in inffast.c on effectiveness of POSTINC * - Typecasting all around to reduce compiler warnings * - Changed loops from while (1) or do {} while (1) to for (;;), again to * make compilers happy * - Changed type of window in inflateBackInit() to unsigned char * * * 1.2.beta7 27 Jan 2003 * - Changed many types to unsigned or unsigned short to avoid warnings * - Added inflateCopy() function * * 1.2.0 9 Mar 2003 * - Changed inflateBack() interface to provide separate opaque descriptors * for the in() and out() functions * - Changed inflateBack() argument and in_func typedef to swap the length * and buffer address return values for the input function * - Check next_in and next_out for Z_NULL on entry to inflate() * * The history for versions after 1.2.0 are in ChangeLog in zlib distribution. */ #include "zutil.h" #include "inftrees.h" #include "inflate.h" #include "inffast.h" #ifdef MAKEFIXED # ifndef BUILDFIXED # define BUILDFIXED # endif #endif /* function prototypes */ local void fixedtables OF((struct inflate_state FAR *state)); local int updatewindow OF((z_streamp strm, unsigned out)); #ifdef BUILDFIXED void makefixed OF((void)); #endif local unsigned syncsearch OF((unsigned FAR *have, unsigned char FAR *buf, unsigned len)); int ZEXPORT inflateReset(strm) z_streamp strm; { struct inflate_state FAR *state; if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)strm->state; strm->total_in = strm->total_out = state->total = 0; strm->msg = Z_NULL; strm->adler = 1; /* to support ill-conceived Java test suite */ state->mode = HEAD; state->last = 0; state->havedict = 0; state->dmax = 32768U; state->head = Z_NULL; state->wsize = 0; state->whave = 0; state->wnext = 0; state->hold = 0; state->bits = 0; state->lencode = state->distcode = state->next = state->codes; state->sane = 1; state->back = -1; Tracev((stderr, "inflate: reset\n")); return Z_OK; } int ZEXPORT inflateReset2(strm, windowBits) z_streamp strm; int windowBits; { int wrap; struct inflate_state FAR *state; /* get the state */ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)strm->state; /* extract wrap request from windowBits parameter */ if (windowBits < 0) { wrap = 0; windowBits = -windowBits; } else { wrap = (windowBits >> 4) + 1; #ifdef GUNZIP if (windowBits < 48) windowBits &= 15; #endif } /* set number of window bits, free window if different */ if (windowBits && (windowBits < 8 || windowBits > 15)) return Z_STREAM_ERROR; if (state->window != Z_NULL && state->wbits != (unsigned)windowBits) { ZFREE(strm, state->window); state->window = Z_NULL; } /* update state and reset the rest of it */ state->wrap = wrap; state->wbits = (unsigned)windowBits; return inflateReset(strm); } int ZEXPORT inflateInit2_(strm, windowBits, version, stream_size) z_streamp strm; int windowBits; const char *version; int stream_size; { int ret; struct inflate_state FAR *state; if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || stream_size != (int)(sizeof(z_stream))) return Z_VERSION_ERROR; if (strm == Z_NULL) return Z_STREAM_ERROR; strm->msg = Z_NULL; /* in case we return an error */ if (strm->zalloc == (alloc_func)0) { strm->zalloc = zcalloc; strm->opaque = (voidpf)0; } if (strm->zfree == (free_func)0) strm->zfree = zcfree; state = (struct inflate_state FAR *) ZALLOC(strm, 1, sizeof(struct inflate_state)); if (state == Z_NULL) return Z_MEM_ERROR; Tracev((stderr, "inflate: allocated\n")); strm->state = (struct internal_state FAR *)state; state->window = Z_NULL; ret = inflateReset2(strm, windowBits); if (ret != Z_OK) { ZFREE(strm, state); strm->state = Z_NULL; } return ret; } int ZEXPORT inflateInit_(strm, version, stream_size) z_streamp strm; const char *version; int stream_size; { return inflateInit2_(strm, DEF_WBITS, version, stream_size); } int ZEXPORT inflatePrime(strm, bits, value) z_streamp strm; int bits; int value; { struct inflate_state FAR *state; if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)strm->state; if (bits < 0) { state->hold = 0; state->bits = 0; return Z_OK; } if (bits > 16 || state->bits + bits > 32) return Z_STREAM_ERROR; value &= (1L << bits) - 1; state->hold += value << state->bits; state->bits += bits; return Z_OK; } /* Return state with length and distance decoding tables and index sizes set to fixed code decoding. Normally this returns fixed tables from inffixed.h. If BUILDFIXED is defined, then instead this routine builds the tables the first time it's called, and returns those tables the first time and thereafter. This reduces the size of the code by about 2K bytes, in exchange for a little execution time. However, BUILDFIXED should not be used for threaded applications, since the rewriting of the tables and virgin may not be thread-safe. */ local void fixedtables(state) struct inflate_state FAR *state; { #ifdef BUILDFIXED static int virgin = 1; static code *lenfix, *distfix; static code fixed[544]; /* build fixed huffman tables if first call (may not be thread safe) */ if (virgin) { unsigned sym, bits; static code *next; /* literal/length table */ sym = 0; while (sym < 144) state->lens[sym++] = 8; while (sym < 256) state->lens[sym++] = 9; while (sym < 280) state->lens[sym++] = 7; while (sym < 288) state->lens[sym++] = 8; next = fixed; lenfix = next; bits = 9; inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work); /* distance table */ sym = 0; while (sym < 32) state->lens[sym++] = 5; distfix = next; bits = 5; inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work); /* do this just once */ virgin = 0; } #else /* !BUILDFIXED */ # include "inffixed.h" #endif /* BUILDFIXED */ state->lencode = lenfix; state->lenbits = 9; state->distcode = distfix; state->distbits = 5; } #ifdef MAKEFIXED #include /* Write out the inffixed.h that is #include'd above. Defining MAKEFIXED also defines BUILDFIXED, so the tables are built on the fly. makefixed() writes those tables to stdout, which would be piped to inffixed.h. A small program can simply call makefixed to do this: void makefixed(void); int main(void) { makefixed(); return 0; } Then that can be linked with zlib built with MAKEFIXED defined and run: a.out > inffixed.h */ void makefixed() { unsigned low, size; struct inflate_state state; fixedtables(&state); puts(" /* inffixed.h -- table for decoding fixed codes"); puts(" * Generated automatically by makefixed()."); puts(" */"); puts(""); puts(" /* WARNING: this file should *not* be used by applications."); puts(" It is part of the implementation of this library and is"); puts(" subject to change. Applications should only use zlib.h."); puts(" */"); puts(""); size = 1U << 9; printf(" static const code lenfix[%u] = {", size); low = 0; for (;;) { if ((low % 7) == 0) printf("\n "); printf("{%u,%u,%d}", state.lencode[low].op, state.lencode[low].bits, state.lencode[low].val); if (++low == size) break; putchar(','); } puts("\n };"); size = 1U << 5; printf("\n static const code distfix[%u] = {", size); low = 0; for (;;) { if ((low % 6) == 0) printf("\n "); printf("{%u,%u,%d}", state.distcode[low].op, state.distcode[low].bits, state.distcode[low].val); if (++low == size) break; putchar(','); } puts("\n };"); } #endif /* MAKEFIXED */ /* Update the window with the last wsize (normally 32K) bytes written before returning. If window does not exist yet, create it. This is only called when a window is already in use, or when output has been written during this inflate call, but the end of the deflate stream has not been reached yet. It is also called to create a window for dictionary data when a dictionary is loaded. Providing output buffers larger than 32K to inflate() should provide a speed advantage, since only the last 32K of output is copied to the sliding window upon return from inflate(), and since all distances after the first 32K of output will fall in the output data, making match copies simpler and faster. The advantage may be dependent on the size of the processor's data caches. */ local int updatewindow(strm, out) z_streamp strm; unsigned out; { struct inflate_state FAR *state; unsigned copy, dist; state = (struct inflate_state FAR *)strm->state; /* if it hasn't been done already, allocate space for the window */ if (state->window == Z_NULL) { state->window = (unsigned char FAR *) ZALLOC(strm, 1U << state->wbits, sizeof(unsigned char)); if (state->window == Z_NULL) return 1; } /* if window not in use yet, initialize */ if (state->wsize == 0) { state->wsize = 1U << state->wbits; state->wnext = 0; state->whave = 0; } /* copy state->wsize or less output bytes into the circular window */ copy = out - strm->avail_out; if (copy >= state->wsize) { zmemcpy(state->window, strm->next_out - state->wsize, state->wsize); state->wnext = 0; state->whave = state->wsize; } else { dist = state->wsize - state->wnext; if (dist > copy) dist = copy; zmemcpy(state->window + state->wnext, strm->next_out - copy, dist); copy -= dist; if (copy) { zmemcpy(state->window, strm->next_out - copy, copy); state->wnext = copy; state->whave = state->wsize; } else { state->wnext += dist; if (state->wnext == state->wsize) state->wnext = 0; if (state->whave < state->wsize) state->whave += dist; } } return 0; } /* Macros for inflate(): */ /* check function to use adler32() for zlib or crc32() for gzip */ #ifdef GUNZIP # define UPDATE(check, buf, len) \ (state->flags ? crc32(check, buf, len) : adler32(check, buf, len)) #else # define UPDATE(check, buf, len) adler32(check, buf, len) #endif /* check macros for header crc */ #ifdef GUNZIP # define CRC2(check, word) \ do { \ hbuf[0] = (unsigned char)(word); \ hbuf[1] = (unsigned char)((word) >> 8); \ check = crc32(check, hbuf, 2); \ } while (0) # define CRC4(check, word) \ do { \ hbuf[0] = (unsigned char)(word); \ hbuf[1] = (unsigned char)((word) >> 8); \ hbuf[2] = (unsigned char)((word) >> 16); \ hbuf[3] = (unsigned char)((word) >> 24); \ check = crc32(check, hbuf, 4); \ } while (0) #endif /* Load registers with state in inflate() for speed */ #define LOAD() \ do { \ put = strm->next_out; \ left = strm->avail_out; \ next = strm->next_in; \ have = strm->avail_in; \ hold = state->hold; \ bits = state->bits; \ } while (0) /* Restore state from registers in inflate() */ #define RESTORE() \ do { \ strm->next_out = put; \ strm->avail_out = left; \ strm->next_in = next; \ strm->avail_in = have; \ state->hold = hold; \ state->bits = bits; \ } while (0) /* Clear the input bit accumulator */ #define INITBITS() \ do { \ hold = 0; \ bits = 0; \ } while (0) /* Get a byte of input into the bit accumulator, or return from inflate() if there is no input available. */ #define PULLBYTE() \ do { \ if (have == 0) goto inf_leave; \ have--; \ hold += (unsigned long)(*next++) << bits; \ bits += 8; \ } while (0) /* Assure that there are at least n bits in the bit accumulator. If there is not enough available input to do that, then return from inflate(). */ #define NEEDBITS(n) \ do { \ while (bits < (unsigned)(n)) \ PULLBYTE(); \ } while (0) /* Return the low n bits of the bit accumulator (n < 16) */ #define BITS(n) \ ((unsigned)hold & ((1U << (n)) - 1)) /* Remove n bits from the bit accumulator */ #define DROPBITS(n) \ do { \ hold >>= (n); \ bits -= (unsigned)(n); \ } while (0) /* Remove zero to seven bits as needed to go to a byte boundary */ #define BYTEBITS() \ do { \ hold >>= bits & 7; \ bits -= bits & 7; \ } while (0) /* Reverse the bytes in a 32-bit value */ #define REVERSE(q) \ ((((q) >> 24) & 0xff) + (((q) >> 8) & 0xff00) + \ (((q) & 0xff00) << 8) + (((q) & 0xff) << 24)) /* inflate() uses a state machine to process as much input data and generate as much output data as possible before returning. The state machine is structured roughly as follows: for (;;) switch (state) { ... case STATEn: if (not enough input data or output space to make progress) return; ... make progress ... state = STATEm; break; ... } so when inflate() is called again, the same case is attempted again, and if the appropriate resources are provided, the machine proceeds to the next state. The NEEDBITS() macro is usually the way the state evaluates whether it can proceed or should return. NEEDBITS() does the return if the requested bits are not available. The typical use of the BITS macros is: NEEDBITS(n); ... do something with BITS(n) ... DROPBITS(n); where NEEDBITS(n) either returns from inflate() if there isn't enough input left to load n bits into the accumulator, or it continues. BITS(n) gives the low n bits in the accumulator. When done, DROPBITS(n) drops the low n bits off the accumulator. INITBITS() clears the accumulator and sets the number of available bits to zero. BYTEBITS() discards just enough bits to put the accumulator on a byte boundary. After BYTEBITS() and a NEEDBITS(8), then BITS(8) would return the next byte in the stream. NEEDBITS(n) uses PULLBYTE() to get an available byte of input, or to return if there is no input available. The decoding of variable length codes uses PULLBYTE() directly in order to pull just enough bytes to decode the next code, and no more. Some states loop until they get enough input, making sure that enough state information is maintained to continue the loop where it left off if NEEDBITS() returns in the loop. For example, want, need, and keep would all have to actually be part of the saved state in case NEEDBITS() returns: case STATEw: while (want < need) { NEEDBITS(n); keep[want++] = BITS(n); DROPBITS(n); } state = STATEx; case STATEx: As shown above, if the next state is also the next case, then the break is omitted. A state may also return if there is not enough output space available to complete that state. Those states are copying stored data, writing a literal byte, and copying a matching string. When returning, a "goto inf_leave" is used to update the total counters, update the check value, and determine whether any progress has been made during that inflate() call in order to return the proper return code. Progress is defined as a change in either strm->avail_in or strm->avail_out. When there is a window, goto inf_leave will update the window with the last output written. If a goto inf_leave occurs in the middle of decompression and there is no window currently, goto inf_leave will create one and copy output to the window for the next call of inflate(). In this implementation, the flush parameter of inflate() only affects the return code (per zlib.h). inflate() always writes as much as possible to strm->next_out, given the space available and the provided input--the effect documented in zlib.h of Z_SYNC_FLUSH. Furthermore, inflate() always defers the allocation of and copying into a sliding window until necessary, which provides the effect documented in zlib.h for Z_FINISH when the entire input stream available. So the only thing the flush parameter actually does is: when flush is set to Z_FINISH, inflate() cannot return Z_OK. Instead it will return Z_BUF_ERROR if it has not reached the end of the stream. */ int ZEXPORT inflate(strm, flush) z_streamp strm; int flush; { struct inflate_state FAR *state; unsigned char FAR *next; /* next input */ unsigned char FAR *put; /* next output */ unsigned have, left; /* available input and output */ unsigned long hold; /* bit buffer */ unsigned bits; /* bits in bit buffer */ unsigned in, out; /* save starting available input and output */ unsigned copy; /* number of stored or match bytes to copy */ unsigned char FAR *from; /* where to copy match bytes from */ code here; /* current decoding table entry */ code last; /* parent table entry */ unsigned len; /* length to copy for repeats, bits to drop */ int ret; /* return code */ #ifdef GUNZIP unsigned char hbuf[4]; /* buffer for gzip header crc calculation */ #endif static const unsigned short order[19] = /* permutation of code lengths */ {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; if (strm == Z_NULL || strm->state == Z_NULL || strm->next_out == Z_NULL || (strm->next_in == Z_NULL && strm->avail_in != 0)) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)strm->state; if (state->mode == TYPE) state->mode = TYPEDO; /* skip check */ LOAD(); in = have; out = left; ret = Z_OK; for (;;) switch (state->mode) { case HEAD: if (state->wrap == 0) { state->mode = TYPEDO; break; } NEEDBITS(16); #ifdef GUNZIP if ((state->wrap & 2) && hold == 0x8b1f) { /* gzip header */ state->check = crc32(0L, Z_NULL, 0); CRC2(state->check, hold); INITBITS(); state->mode = FLAGS; break; } state->flags = 0; /* expect zlib header */ if (state->head != Z_NULL) state->head->done = -1; if (!(state->wrap & 1) || /* check if zlib header allowed */ #else if ( #endif ((BITS(8) << 8) + (hold >> 8)) % 31) { strm->msg = (char *)"incorrect header check"; state->mode = BAD; break; } if (BITS(4) != Z_DEFLATED) { strm->msg = (char *)"unknown compression method"; state->mode = BAD; break; } DROPBITS(4); len = BITS(4) + 8; if (state->wbits == 0) state->wbits = len; else if (len > state->wbits) { strm->msg = (char *)"invalid window size"; state->mode = BAD; break; } state->dmax = 1U << len; Tracev((stderr, "inflate: zlib header ok\n")); strm->adler = state->check = adler32(0L, Z_NULL, 0); state->mode = hold & 0x200 ? DICTID : TYPE; INITBITS(); break; #ifdef GUNZIP case FLAGS: NEEDBITS(16); state->flags = (int)(hold); if ((state->flags & 0xff) != Z_DEFLATED) { strm->msg = (char *)"unknown compression method"; state->mode = BAD; break; } if (state->flags & 0xe000) { strm->msg = (char *)"unknown header flags set"; state->mode = BAD; break; } if (state->head != Z_NULL) state->head->text = (int)((hold >> 8) & 1); if (state->flags & 0x0200) CRC2(state->check, hold); INITBITS(); state->mode = TIME; case TIME: NEEDBITS(32); if (state->head != Z_NULL) state->head->time = hold; if (state->flags & 0x0200) CRC4(state->check, hold); INITBITS(); state->mode = OS; case OS: NEEDBITS(16); if (state->head != Z_NULL) { state->head->xflags = (int)(hold & 0xff); state->head->os = (int)(hold >> 8); } if (state->flags & 0x0200) CRC2(state->check, hold); INITBITS(); state->mode = EXLEN; case EXLEN: if (state->flags & 0x0400) { NEEDBITS(16); state->length = (unsigned)(hold); if (state->head != Z_NULL) state->head->extra_len = (unsigned)hold; if (state->flags & 0x0200) CRC2(state->check, hold); INITBITS(); } else if (state->head != Z_NULL) state->head->extra = Z_NULL; state->mode = EXTRA; case EXTRA: if (state->flags & 0x0400) { copy = state->length; if (copy > have) copy = have; if (copy) { if (state->head != Z_NULL && state->head->extra != Z_NULL) { len = state->head->extra_len - state->length; zmemcpy(state->head->extra + len, next, len + copy > state->head->extra_max ? state->head->extra_max - len : copy); } if (state->flags & 0x0200) state->check = crc32(state->check, next, copy); have -= copy; next += copy; state->length -= copy; } if (state->length) goto inf_leave; } state->length = 0; state->mode = NAME; case NAME: if (state->flags & 0x0800) { if (have == 0) goto inf_leave; copy = 0; do { len = (unsigned)(next[copy++]); if (state->head != Z_NULL && state->head->name != Z_NULL && state->length < state->head->name_max) state->head->name[state->length++] = len; } while (len && copy < have); if (state->flags & 0x0200) state->check = crc32(state->check, next, copy); have -= copy; next += copy; if (len) goto inf_leave; } else if (state->head != Z_NULL) state->head->name = Z_NULL; state->length = 0; state->mode = COMMENT; case COMMENT: if (state->flags & 0x1000) { if (have == 0) goto inf_leave; copy = 0; do { len = (unsigned)(next[copy++]); if (state->head != Z_NULL && state->head->comment != Z_NULL && state->length < state->head->comm_max) state->head->comment[state->length++] = len; } while (len && copy < have); if (state->flags & 0x0200) state->check = crc32(state->check, next, copy); have -= copy; next += copy; if (len) goto inf_leave; } else if (state->head != Z_NULL) state->head->comment = Z_NULL; state->mode = HCRC; case HCRC: if (state->flags & 0x0200) { NEEDBITS(16); if (hold != (state->check & 0xffff)) { strm->msg = (char *)"header crc mismatch"; state->mode = BAD; break; } INITBITS(); } if (state->head != Z_NULL) { state->head->hcrc = (int)((state->flags >> 9) & 1); state->head->done = 1; } strm->adler = state->check = crc32(0L, Z_NULL, 0); state->mode = TYPE; break; #endif case DICTID: NEEDBITS(32); strm->adler = state->check = REVERSE(hold); INITBITS(); state->mode = DICT; case DICT: if (state->havedict == 0) { RESTORE(); return Z_NEED_DICT; } strm->adler = state->check = adler32(0L, Z_NULL, 0); state->mode = TYPE; case TYPE: if (flush == Z_BLOCK || flush == Z_TREES) goto inf_leave; case TYPEDO: if (state->last) { BYTEBITS(); state->mode = CHECK; break; } NEEDBITS(3); state->last = BITS(1); DROPBITS(1); switch (BITS(2)) { case 0: /* stored block */ Tracev((stderr, "inflate: stored block%s\n", state->last ? " (last)" : "")); state->mode = STORED; break; case 1: /* fixed block */ fixedtables(state); Tracev((stderr, "inflate: fixed codes block%s\n", state->last ? " (last)" : "")); state->mode = LEN_; /* decode codes */ if (flush == Z_TREES) { DROPBITS(2); goto inf_leave; } break; case 2: /* dynamic block */ Tracev((stderr, "inflate: dynamic codes block%s\n", state->last ? " (last)" : "")); state->mode = TABLE; break; case 3: strm->msg = (char *)"invalid block type"; state->mode = BAD; } DROPBITS(2); break; case STORED: BYTEBITS(); /* go to byte boundary */ NEEDBITS(32); if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) { strm->msg = (char *)"invalid stored block lengths"; state->mode = BAD; break; } state->length = (unsigned)hold & 0xffff; Tracev((stderr, "inflate: stored length %u\n", state->length)); INITBITS(); state->mode = COPY_; if (flush == Z_TREES) goto inf_leave; case COPY_: state->mode = COPY; case COPY: copy = state->length; if (copy) { if (copy > have) copy = have; if (copy > left) copy = left; if (copy == 0) goto inf_leave; zmemcpy(put, next, copy); have -= copy; next += copy; left -= copy; put += copy; state->length -= copy; break; } Tracev((stderr, "inflate: stored end\n")); state->mode = TYPE; break; case TABLE: NEEDBITS(14); state->nlen = BITS(5) + 257; DROPBITS(5); state->ndist = BITS(5) + 1; DROPBITS(5); state->ncode = BITS(4) + 4; DROPBITS(4); #ifndef PKZIP_BUG_WORKAROUND if (state->nlen > 286 || state->ndist > 30) { strm->msg = (char *)"too many length or distance symbols"; state->mode = BAD; break; } #endif Tracev((stderr, "inflate: table sizes ok\n")); state->have = 0; state->mode = LENLENS; case LENLENS: while (state->have < state->ncode) { NEEDBITS(3); state->lens[order[state->have++]] = (unsigned short)BITS(3); DROPBITS(3); } while (state->have < 19) state->lens[order[state->have++]] = 0; state->next = state->codes; state->lencode = (code const FAR *)(state->next); state->lenbits = 7; ret = inflate_table(CODES, state->lens, 19, &(state->next), &(state->lenbits), state->work); if (ret) { strm->msg = (char *)"invalid code lengths set"; state->mode = BAD; break; } Tracev((stderr, "inflate: code lengths ok\n")); state->have = 0; state->mode = CODELENS; case CODELENS: while (state->have < state->nlen + state->ndist) { for (;;) { here = state->lencode[BITS(state->lenbits)]; if ((unsigned)(here.bits) <= bits) break; PULLBYTE(); } if (here.val < 16) { NEEDBITS(here.bits); DROPBITS(here.bits); state->lens[state->have++] = here.val; } else { if (here.val == 16) { NEEDBITS(here.bits + 2); DROPBITS(here.bits); if (state->have == 0) { strm->msg = (char *)"invalid bit length repeat"; state->mode = BAD; break; } len = state->lens[state->have - 1]; copy = 3 + BITS(2); DROPBITS(2); } else if (here.val == 17) { NEEDBITS(here.bits + 3); DROPBITS(here.bits); len = 0; copy = 3 + BITS(3); DROPBITS(3); } else { NEEDBITS(here.bits + 7); DROPBITS(here.bits); len = 0; copy = 11 + BITS(7); DROPBITS(7); } if (state->have + copy > state->nlen + state->ndist) { strm->msg = (char *)"invalid bit length repeat"; state->mode = BAD; break; } while (copy--) state->lens[state->have++] = (unsigned short)len; } } /* handle error breaks in while */ if (state->mode == BAD) break; /* check for end-of-block code (better have one) */ if (state->lens[256] == 0) { strm->msg = (char *)"invalid code -- missing end-of-block"; state->mode = BAD; break; } /* build code tables -- note: do not change the lenbits or distbits values here (9 and 6) without reading the comments in inftrees.h concerning the ENOUGH constants, which depend on those values */ state->next = state->codes; state->lencode = (code const FAR *)(state->next); state->lenbits = 9; ret = inflate_table(LENS, state->lens, state->nlen, &(state->next), &(state->lenbits), state->work); if (ret) { strm->msg = (char *)"invalid literal/lengths set"; state->mode = BAD; break; } state->distcode = (code const FAR *)(state->next); state->distbits = 6; ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist, &(state->next), &(state->distbits), state->work); if (ret) { strm->msg = (char *)"invalid distances set"; state->mode = BAD; break; } Tracev((stderr, "inflate: codes ok\n")); state->mode = LEN_; if (flush == Z_TREES) goto inf_leave; case LEN_: state->mode = LEN; case LEN: if (have >= 6 && left >= 258) { RESTORE(); inflate_fast(strm, out); LOAD(); if (state->mode == TYPE) state->back = -1; break; } state->back = 0; for (;;) { here = state->lencode[BITS(state->lenbits)]; if ((unsigned)(here.bits) <= bits) break; PULLBYTE(); } if (here.op && (here.op & 0xf0) == 0) { last = here; for (;;) { here = state->lencode[last.val + (BITS(last.bits + last.op) >> last.bits)]; if ((unsigned)(last.bits + here.bits) <= bits) break; PULLBYTE(); } DROPBITS(last.bits); state->back += last.bits; } DROPBITS(here.bits); state->back += here.bits; state->length = (unsigned)here.val; if ((int)(here.op) == 0) { Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ? "inflate: literal '%c'\n" : "inflate: literal 0x%02x\n", here.val)); state->mode = LIT; break; } if (here.op & 32) { Tracevv((stderr, "inflate: end of block\n")); state->back = -1; state->mode = TYPE; break; } if (here.op & 64) { strm->msg = (char *)"invalid literal/length code"; state->mode = BAD; break; } state->extra = (unsigned)(here.op) & 15; state->mode = LENEXT; case LENEXT: if (state->extra) { NEEDBITS(state->extra); state->length += BITS(state->extra); DROPBITS(state->extra); state->back += state->extra; } Tracevv((stderr, "inflate: length %u\n", state->length)); state->was = state->length; state->mode = DIST; case DIST: for (;;) { here = state->distcode[BITS(state->distbits)]; if ((unsigned)(here.bits) <= bits) break; PULLBYTE(); } if ((here.op & 0xf0) == 0) { last = here; for (;;) { here = state->distcode[last.val + (BITS(last.bits + last.op) >> last.bits)]; if ((unsigned)(last.bits + here.bits) <= bits) break; PULLBYTE(); } DROPBITS(last.bits); state->back += last.bits; } DROPBITS(here.bits); state->back += here.bits; if (here.op & 64) { strm->msg = (char *)"invalid distance code"; state->mode = BAD; break; } state->offset = (unsigned)here.val; state->extra = (unsigned)(here.op) & 15; state->mode = DISTEXT; case DISTEXT: if (state->extra) { NEEDBITS(state->extra); state->offset += BITS(state->extra); DROPBITS(state->extra); state->back += state->extra; } #ifdef INFLATE_STRICT if (state->offset > state->dmax) { strm->msg = (char *)"invalid distance too far back"; state->mode = BAD; break; } #endif Tracevv((stderr, "inflate: distance %u\n", state->offset)); state->mode = MATCH; case MATCH: if (left == 0) goto inf_leave; copy = out - left; if (state->offset > copy) { /* copy from window */ copy = state->offset - copy; if (copy > state->whave) { if (state->sane) { strm->msg = (char *)"invalid distance too far back"; state->mode = BAD; break; } #ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR Trace((stderr, "inflate.c too far\n")); copy -= state->whave; if (copy > state->length) copy = state->length; if (copy > left) copy = left; left -= copy; state->length -= copy; do { *put++ = 0; } while (--copy); if (state->length == 0) state->mode = LEN; break; #endif } if (copy > state->wnext) { copy -= state->wnext; from = state->window + (state->wsize - copy); } else from = state->window + (state->wnext - copy); if (copy > state->length) copy = state->length; } else { /* copy from output */ from = put - state->offset; copy = state->length; } if (copy > left) copy = left; left -= copy; state->length -= copy; do { *put++ = *from++; } while (--copy); if (state->length == 0) state->mode = LEN; break; case LIT: if (left == 0) goto inf_leave; *put++ = (unsigned char)(state->length); left--; state->mode = LEN; break; case CHECK: if (state->wrap) { NEEDBITS(32); out -= left; strm->total_out += out; state->total += out; if (out) strm->adler = state->check = UPDATE(state->check, put - out, out); out = left; if (( #ifdef GUNZIP state->flags ? hold : #endif REVERSE(hold)) != state->check) { strm->msg = (char *)"incorrect data check"; state->mode = BAD; break; } INITBITS(); Tracev((stderr, "inflate: check matches trailer\n")); } #ifdef GUNZIP state->mode = LENGTH; case LENGTH: if (state->wrap && state->flags) { NEEDBITS(32); if (hold != (state->total & 0xffffffffUL)) { strm->msg = (char *)"incorrect length check"; state->mode = BAD; break; } INITBITS(); Tracev((stderr, "inflate: length matches trailer\n")); } #endif state->mode = DONE; case DONE: ret = Z_STREAM_END; goto inf_leave; case BAD: ret = Z_DATA_ERROR; goto inf_leave; case MEM: return Z_MEM_ERROR; case SYNC: default: return Z_STREAM_ERROR; } /* Return from inflate(), updating the total counts and the check value. If there was no progress during the inflate() call, return a buffer error. Call updatewindow() to create and/or update the window state. Note: a memory error from inflate() is non-recoverable. */ inf_leave: RESTORE(); if (state->wsize || (state->mode < CHECK && out != strm->avail_out)) if (updatewindow(strm, out)) { state->mode = MEM; return Z_MEM_ERROR; } in -= strm->avail_in; out -= strm->avail_out; strm->total_in += in; strm->total_out += out; state->total += out; if (state->wrap && out) strm->adler = state->check = UPDATE(state->check, strm->next_out - out, out); strm->data_type = state->bits + (state->last ? 64 : 0) + (state->mode == TYPE ? 128 : 0) + (state->mode == LEN_ || state->mode == COPY_ ? 256 : 0); if (((in == 0 && out == 0) || flush == Z_FINISH) && ret == Z_OK) ret = Z_BUF_ERROR; return ret; } int ZEXPORT inflateEnd(strm) z_streamp strm; { struct inflate_state FAR *state; if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)strm->state; if (state->window != Z_NULL) ZFREE(strm, state->window); ZFREE(strm, strm->state); strm->state = Z_NULL; Tracev((stderr, "inflate: end\n")); return Z_OK; } int ZEXPORT inflateSetDictionary(strm, dictionary, dictLength) z_streamp strm; const Bytef *dictionary; uInt dictLength; { struct inflate_state FAR *state; unsigned long id; /* check state */ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)strm->state; if (state->wrap != 0 && state->mode != DICT) return Z_STREAM_ERROR; /* check for correct dictionary id */ if (state->mode == DICT) { id = adler32(0L, Z_NULL, 0); id = adler32(id, dictionary, dictLength); if (id != state->check) return Z_DATA_ERROR; } /* copy dictionary to window */ if (updatewindow(strm, strm->avail_out)) { state->mode = MEM; return Z_MEM_ERROR; } if (dictLength > state->wsize) { zmemcpy(state->window, dictionary + dictLength - state->wsize, state->wsize); state->whave = state->wsize; } else { zmemcpy(state->window + state->wsize - dictLength, dictionary, dictLength); state->whave = dictLength; } state->havedict = 1; Tracev((stderr, "inflate: dictionary set\n")); return Z_OK; } int ZEXPORT inflateGetHeader(strm, head) z_streamp strm; gz_headerp head; { struct inflate_state FAR *state; /* check state */ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)strm->state; if ((state->wrap & 2) == 0) return Z_STREAM_ERROR; /* save header structure */ state->head = head; head->done = 0; return Z_OK; } /* Search buf[0..len-1] for the pattern: 0, 0, 0xff, 0xff. Return when found or when out of input. When called, *have is the number of pattern bytes found in order so far, in 0..3. On return *have is updated to the new state. If on return *have equals four, then the pattern was found and the return value is how many bytes were read including the last byte of the pattern. If *have is less than four, then the pattern has not been found yet and the return value is len. In the latter case, syncsearch() can be called again with more data and the *have state. *have is initialized to zero for the first call. */ local unsigned syncsearch(have, buf, len) unsigned FAR *have; unsigned char FAR *buf; unsigned len; { unsigned got; unsigned next; got = *have; next = 0; while (next < len && got < 4) { if ((int)(buf[next]) == (got < 2 ? 0 : 0xff)) got++; else if (buf[next]) got = 0; else got = 4 - got; next++; } *have = got; return next; } int ZEXPORT inflateSync(strm) z_streamp strm; { unsigned len; /* number of bytes to look at or looked at */ unsigned long in, out; /* temporary to save total_in and total_out */ unsigned char buf[4]; /* to restore bit buffer to byte string */ struct inflate_state FAR *state; /* check parameters */ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)strm->state; if (strm->avail_in == 0 && state->bits < 8) return Z_BUF_ERROR; /* if first time, start search in bit buffer */ if (state->mode != SYNC) { state->mode = SYNC; state->hold <<= state->bits & 7; state->bits -= state->bits & 7; len = 0; while (state->bits >= 8) { buf[len++] = (unsigned char)(state->hold); state->hold >>= 8; state->bits -= 8; } state->have = 0; syncsearch(&(state->have), buf, len); } /* search available input */ len = syncsearch(&(state->have), strm->next_in, strm->avail_in); strm->avail_in -= len; strm->next_in += len; strm->total_in += len; /* return no joy or set up to restart inflate() on a new block */ if (state->have != 4) return Z_DATA_ERROR; in = strm->total_in; out = strm->total_out; inflateReset(strm); strm->total_in = in; strm->total_out = out; state->mode = TYPE; return Z_OK; } /* Returns true if inflate is currently at the end of a block generated by Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP implementation to provide an additional safety check. PPP uses Z_SYNC_FLUSH but removes the length bytes of the resulting empty stored block. When decompressing, PPP checks that at the end of input packet, inflate is waiting for these length bytes. */ int ZEXPORT inflateSyncPoint(strm) z_streamp strm; { struct inflate_state FAR *state; if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)strm->state; return state->mode == STORED && state->bits == 0; } int ZEXPORT inflateCopy(dest, source) z_streamp dest; z_streamp source; { struct inflate_state FAR *state; struct inflate_state FAR *copy; unsigned char FAR *window; unsigned wsize; /* check input */ if (dest == Z_NULL || source == Z_NULL || source->state == Z_NULL || source->zalloc == (alloc_func)0 || source->zfree == (free_func)0) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)source->state; /* allocate space */ copy = (struct inflate_state FAR *) ZALLOC(source, 1, sizeof(struct inflate_state)); if (copy == Z_NULL) return Z_MEM_ERROR; window = Z_NULL; if (state->window != Z_NULL) { window = (unsigned char FAR *) ZALLOC(source, 1U << state->wbits, sizeof(unsigned char)); if (window == Z_NULL) { ZFREE(source, copy); return Z_MEM_ERROR; } } /* copy state */ zmemcpy(dest, source, sizeof(z_stream)); zmemcpy(copy, state, sizeof(struct inflate_state)); if (state->lencode >= state->codes && state->lencode <= state->codes + ENOUGH - 1) { copy->lencode = copy->codes + (state->lencode - state->codes); copy->distcode = copy->codes + (state->distcode - state->codes); } copy->next = copy->codes + (state->next - state->codes); if (window != Z_NULL) { wsize = 1U << state->wbits; zmemcpy(window, state->window, wsize); } copy->window = window; dest->state = (struct internal_state FAR *)copy; return Z_OK; } int ZEXPORT inflateUndermine(strm, subvert) z_streamp strm; int subvert; { struct inflate_state FAR *state; if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)strm->state; state->sane = !subvert; #ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR return Z_OK; #else state->sane = 1; return Z_DATA_ERROR; #endif } long ZEXPORT inflateMark(strm) z_streamp strm; { struct inflate_state FAR *state; if (strm == Z_NULL || strm->state == Z_NULL) return -1L << 16; state = (struct inflate_state FAR *)strm->state; return ((long)(state->back) << 16) + (state->mode == COPY ? state->length : (state->mode == MATCH ? state->was - state->length : 0)); } libgit2-0.19.0/deps/zlib/inflate.h000066400000000000000000000143771216214232500166350ustar00rootroot00000000000000/* 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 */ }; libgit2-0.19.0/deps/zlib/inftrees.c000066400000000000000000000327111216214232500170150ustar00rootroot00000000000000/* inftrees.c -- generate Huffman trees for efficient decoding * Copyright (C) 1995-2010 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ #include "zutil.h" #include "inftrees.h" #define MAXBITS 15 const char inflate_copyright[] = " inflate 1.2.5 Copyright 1995-2010 Mark Adler "; /* If you use the zlib library in a product, an acknowledgment is welcome in the documentation of your product. If for some reason you cannot include such an acknowledgment, I would appreciate that you keep this copyright string in the executable of your product. */ /* Build a set of tables to decode the provided canonical Huffman code. The code lengths are lens[0..codes-1]. The result starts at *table, whose indices are 0..2^bits-1. work is a writable array of at least lens shorts, which is used as a work area. type is the type of code to be generated, CODES, LENS, or DISTS. On return, zero is success, -1 is an invalid code, and +1 means that ENOUGH isn't enough. table on return points to the next available entry's address. bits is the requested root table index bits, and on return it is the actual root table index bits. It will differ if the request is greater than the longest code or if it is less than the shortest code. */ int ZLIB_INTERNAL inflate_table(type, lens, codes, table, bits, work) codetype type; unsigned short FAR *lens; unsigned codes; code FAR * FAR *table; unsigned FAR *bits; unsigned short FAR *work; { unsigned len; /* a code's length in bits */ unsigned sym; /* index of code symbols */ unsigned min, max; /* minimum and maximum code lengths */ unsigned root; /* number of index bits for root table */ unsigned curr; /* number of index bits for current table */ unsigned drop; /* code bits to drop for sub-table */ int left; /* number of prefix codes available */ unsigned used; /* code entries in table used */ unsigned huff; /* Huffman code */ unsigned incr; /* for incrementing code, index */ unsigned fill; /* index for replicating entries */ unsigned low; /* low bits for current root entry */ unsigned mask; /* mask for low root bits */ code here; /* table entry for duplication */ code FAR *next; /* next available space in table */ const unsigned short FAR *base; /* base value table to use */ const unsigned short FAR *extra; /* extra bits table to use */ int end; /* use base and extra for symbol > end */ unsigned short count[MAXBITS+1]; /* number of codes of each length */ unsigned short offs[MAXBITS+1]; /* offsets in table for each length */ static const unsigned short lbase[31] = { /* Length codes 257..285 base */ 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0}; static const unsigned short lext[31] = { /* Length codes 257..285 extra */ 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 73, 195}; static const unsigned short dbase[32] = { /* Distance codes 0..29 base */ 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577, 0, 0}; static const unsigned short dext[32] = { /* Distance codes 0..29 extra */ 16, 16, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, 23, 23, 24, 24, 25, 25, 26, 26, 27, 27, 28, 28, 29, 29, 64, 64}; /* Process a set of code lengths to create a canonical Huffman code. The code lengths are lens[0..codes-1]. Each length corresponds to the symbols 0..codes-1. The Huffman code is generated by first sorting the symbols by length from short to long, and retaining the symbol order for codes with equal lengths. Then the code starts with all zero bits for the first code of the shortest length, and the codes are integer increments for the same length, and zeros are appended as the length increases. For the deflate format, these bits are stored backwards from their more natural integer increment ordering, and so when the decoding tables are built in the large loop below, the integer codes are incremented backwards. This routine assumes, but does not check, that all of the entries in lens[] are in the range 0..MAXBITS. The caller must assure this. 1..MAXBITS is interpreted as that code length. zero means that that symbol does not occur in this code. The codes are sorted by computing a count of codes for each length, creating from that a table of starting indices for each length in the sorted table, and then entering the symbols in order in the sorted table. The sorted table is work[], with that space being provided by the caller. The length counts are used for other purposes as well, i.e. finding the minimum and maximum length codes, determining if there are any codes at all, checking for a valid set of lengths, and looking ahead at length counts to determine sub-table sizes when building the decoding tables. */ /* accumulate lengths for codes (assumes lens[] all in 0..MAXBITS) */ for (len = 0; len <= MAXBITS; len++) count[len] = 0; for (sym = 0; sym < codes; sym++) count[lens[sym]]++; /* bound code lengths, force root to be within code lengths */ root = *bits; for (max = MAXBITS; max >= 1; max--) if (count[max] != 0) break; if (root > max) root = max; if (max == 0) { /* no symbols to code at all */ here.op = (unsigned char)64; /* invalid code marker */ here.bits = (unsigned char)1; here.val = (unsigned short)0; *(*table)++ = here; /* make a table to force an error */ *(*table)++ = here; *bits = 1; return 0; /* no symbols, but wait for decoding to report error */ } for (min = 1; min < max; min++) if (count[min] != 0) break; if (root < min) root = min; /* check for an over-subscribed or incomplete set of lengths */ left = 1; for (len = 1; len <= MAXBITS; len++) { left <<= 1; left -= count[len]; if (left < 0) return -1; /* over-subscribed */ } if (left > 0 && (type == CODES || max != 1)) return -1; /* incomplete set */ /* generate offsets into symbol table for each length for sorting */ offs[1] = 0; for (len = 1; len < MAXBITS; len++) offs[len + 1] = offs[len] + count[len]; /* sort symbols by length, by symbol order within each length */ for (sym = 0; sym < codes; sym++) if (lens[sym] != 0) work[offs[lens[sym]]++] = (unsigned short)sym; /* Create and fill in decoding tables. In this loop, the table being filled is at next and has curr index bits. The code being used is huff with length len. That code is converted to an index by dropping drop bits off of the bottom. For codes where len is less than drop + curr, those top drop + curr - len bits are incremented through all values to fill the table with replicated entries. root is the number of index bits for the root table. When len exceeds root, sub-tables are created pointed to by the root entry with an index of the low root bits of huff. This is saved in low to check for when a new sub-table should be started. drop is zero when the root table is being filled, and drop is root when sub-tables are being filled. When a new sub-table is needed, it is necessary to look ahead in the code lengths to determine what size sub-table is needed. The length counts are used for this, and so count[] is decremented as codes are entered in the tables. used keeps track of how many table entries have been allocated from the provided *table space. It is checked for LENS and DIST tables against the constants ENOUGH_LENS and ENOUGH_DISTS to guard against changes in the initial root table size constants. See the comments in inftrees.h for more information. sym increments through all symbols, and the loop terminates when all codes of length max, i.e. all codes, have been processed. This routine permits incomplete codes, so another loop after this one fills in the rest of the decoding tables with invalid code markers. */ /* set up for code type */ switch (type) { case CODES: base = extra = work; /* dummy value--not used */ end = 19; break; case LENS: base = lbase; base -= 257; extra = lext; extra -= 257; end = 256; break; default: /* DISTS */ base = dbase; extra = dext; end = -1; } /* initialize state for loop */ huff = 0; /* starting code */ sym = 0; /* starting code symbol */ len = min; /* starting code length */ next = *table; /* current table to fill in */ curr = root; /* current table index bits */ drop = 0; /* current bits to drop from code for index */ low = (unsigned)(-1); /* trigger new sub-table when len > root */ used = 1U << root; /* use root table entries */ mask = used - 1; /* mask for comparing low */ /* check available table space */ if ((type == LENS && used >= ENOUGH_LENS) || (type == DISTS && used >= ENOUGH_DISTS)) return 1; /* process all codes and make table entries */ for (;;) { /* create table entry */ here.bits = (unsigned char)(len - drop); if ((int)(work[sym]) < end) { here.op = (unsigned char)0; here.val = work[sym]; } else if ((int)(work[sym]) > end) { here.op = (unsigned char)(extra[work[sym]]); here.val = base[work[sym]]; } else { here.op = (unsigned char)(32 + 64); /* end of block */ here.val = 0; } /* replicate for those indices with low len bits equal to huff */ incr = 1U << (len - drop); fill = 1U << curr; min = fill; /* save offset to next table */ do { fill -= incr; next[(huff >> drop) + fill] = here; } while (fill != 0); /* backwards increment the len-bit code huff */ incr = 1U << (len - 1); while (huff & incr) incr >>= 1; if (incr != 0) { huff &= incr - 1; huff += incr; } else huff = 0; /* go to next symbol, update count, len */ sym++; if (--(count[len]) == 0) { if (len == max) break; len = lens[work[sym]]; } /* create new sub-table if needed */ if (len > root && (huff & mask) != low) { /* if first time, transition to sub-tables */ if (drop == 0) drop = root; /* increment past last table */ next += min; /* here min is 1 << curr */ /* determine length of next table */ curr = len - drop; left = (int)(1 << curr); while (curr + drop < max) { left -= count[curr + drop]; if (left <= 0) break; curr++; left <<= 1; } /* check for enough space */ used += 1U << curr; if ((type == LENS && used >= ENOUGH_LENS) || (type == DISTS && used >= ENOUGH_DISTS)) return 1; /* point entry in root table to sub-table */ low = huff & mask; (*table)[low].op = (unsigned char)curr; (*table)[low].bits = (unsigned char)root; (*table)[low].val = (unsigned short)(next - *table); } } /* Fill in rest of table for incomplete codes. This loop is similar to the loop above in incrementing huff for table indices. It is assumed that len is equal to curr + drop, so there is no loop needed to increment through high index bits. When the current sub-table is filled, the loop drops back to the root table to fill in any remaining entries there. */ here.op = (unsigned char)64; /* invalid code marker */ here.bits = (unsigned char)(len - drop); here.val = (unsigned short)0; while (huff != 0) { /* when done with sub-table, drop back to root table */ if (drop != 0 && (huff & mask) != low) { drop = 0; len = root; next = *table; here.bits = (unsigned char)len; } /* put invalid code marker in table */ next[huff >> drop] = here; /* backwards increment the len-bit code huff */ incr = 1U << (len - 1); while (huff & incr) incr >>= 1; if (incr != 0) { huff &= incr - 1; huff += incr; } else huff = 0; } /* set return parameters */ *table += used; *bits = root; return 0; } libgit2-0.19.0/deps/zlib/inftrees.h000066400000000000000000000055601216214232500170240ustar00rootroot00000000000000/* 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)); libgit2-0.19.0/deps/zlib/trees.c000066400000000000000000001303041216214232500163150ustar00rootroot00000000000000/* trees.c -- output deflated data using Huffman coding * Copyright (C) 1995-2010 Jean-loup Gailly * detect_data_type() function provided freely by Cosmin Truta, 2006 * For conditions of distribution and use, see copyright notice in zlib.h */ /* * ALGORITHM * * The "deflation" process uses several Huffman trees. The more * common source values are represented by shorter bit sequences. * * Each code tree is stored in a compressed form which is itself * a Huffman encoding of the lengths of all the code strings (in * ascending order by source values). The actual code strings are * reconstructed from the lengths in the inflate process, as described * in the deflate specification. * * REFERENCES * * Deutsch, L.P.,"'Deflate' Compressed Data Format Specification". * Available in ftp.uu.net:/pub/archiving/zip/doc/deflate-1.1.doc * * Storer, James A. * Data Compression: Methods and Theory, pp. 49-50. * Computer Science Press, 1988. ISBN 0-7167-8156-5. * * Sedgewick, R. * Algorithms, p290. * Addison-Wesley, 1983. ISBN 0-201-06672-6. */ /* @(#) $Id$ */ /* #define GEN_TREES_H */ #include "deflate.h" #ifdef DEBUG # include #endif /* =========================================================================== * Constants */ #define MAX_BL_BITS 7 /* Bit length codes must not exceed MAX_BL_BITS bits */ #define END_BLOCK 256 /* end of block literal code */ #define REP_3_6 16 /* repeat previous bit length 3-6 times (2 bits of repeat count) */ #define REPZ_3_10 17 /* repeat a zero length 3-10 times (3 bits of repeat count) */ #define REPZ_11_138 18 /* repeat a zero length 11-138 times (7 bits of repeat count) */ local const int extra_lbits[LENGTH_CODES] /* extra bits for each length code */ = {0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0}; local const int extra_dbits[D_CODES] /* extra bits for each distance code */ = {0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13}; local const int extra_blbits[BL_CODES]/* extra bits for each bit length code */ = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7}; local const uch bl_order[BL_CODES] = {16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15}; /* The lengths of the bit length codes are sent in order of decreasing * probability, to avoid transmitting the lengths for unused bit length codes. */ #define Buf_size (8 * 2*sizeof(char)) /* Number of bits used within bi_buf. (bi_buf might be implemented on * more than 16 bits on some systems.) */ /* =========================================================================== * Local data. These are initialized only once. */ #define DIST_CODE_LEN 512 /* see definition of array dist_code below */ #if defined(GEN_TREES_H) || !defined(STDC) /* non ANSI compilers may not accept trees.h */ local ct_data static_ltree[L_CODES+2]; /* The static literal tree. Since the bit lengths are imposed, there is no * need for the L_CODES extra codes used during heap construction. However * The codes 286 and 287 are needed to build a canonical tree (see _tr_init * below). */ local ct_data static_dtree[D_CODES]; /* The static distance tree. (Actually a trivial tree since all codes use * 5 bits.) */ uch _dist_code[DIST_CODE_LEN]; /* Distance codes. The first 256 values correspond to the distances * 3 .. 258, the last 256 values correspond to the top 8 bits of * the 15 bit distances. */ uch _length_code[MAX_MATCH-MIN_MATCH+1]; /* length code for each normalized match length (0 == MIN_MATCH) */ local int base_length[LENGTH_CODES]; /* First normalized length for each code (0 = MIN_MATCH) */ local int base_dist[D_CODES]; /* First normalized distance for each code (0 = distance of 1) */ #else # include "trees.h" #endif /* GEN_TREES_H */ struct static_tree_desc_s { const ct_data *static_tree; /* static tree or NULL */ const intf *extra_bits; /* extra bits for each code or NULL */ int extra_base; /* base index for extra_bits */ int elems; /* max number of elements in the tree */ int max_length; /* max bit length for the codes */ }; local static_tree_desc static_l_desc = {static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS}; local static_tree_desc static_d_desc = {static_dtree, extra_dbits, 0, D_CODES, MAX_BITS}; local static_tree_desc static_bl_desc = {(const ct_data *)0, extra_blbits, 0, BL_CODES, MAX_BL_BITS}; /* =========================================================================== * Local (static) routines in this file. */ local void tr_static_init OF((void)); local void init_block OF((deflate_state *s)); local void pqdownheap OF((deflate_state *s, ct_data *tree, int k)); local void gen_bitlen OF((deflate_state *s, tree_desc *desc)); local void gen_codes OF((ct_data *tree, int max_code, ushf *bl_count)); local void build_tree OF((deflate_state *s, tree_desc *desc)); local void scan_tree OF((deflate_state *s, ct_data *tree, int max_code)); local void send_tree OF((deflate_state *s, ct_data *tree, int max_code)); local int build_bl_tree OF((deflate_state *s)); local void send_all_trees OF((deflate_state *s, int lcodes, int dcodes, int blcodes)); local void compress_block OF((deflate_state *s, ct_data *ltree, ct_data *dtree)); local int detect_data_type OF((deflate_state *s)); local unsigned bi_reverse OF((unsigned value, int length)); local void bi_windup OF((deflate_state *s)); local void bi_flush OF((deflate_state *s)); local void copy_block OF((deflate_state *s, charf *buf, unsigned len, int header)); #ifdef GEN_TREES_H local void gen_trees_header OF((void)); #endif #ifndef DEBUG # define send_code(s, c, tree) send_bits(s, tree[c].Code, tree[c].Len) /* Send a code of the given tree. c and tree must not have side effects */ #else /* DEBUG */ # define send_code(s, c, tree) \ { if (z_verbose>2) fprintf(stderr,"\ncd %3d ",(c)); \ send_bits(s, tree[c].Code, tree[c].Len); } #endif /* =========================================================================== * Output a short LSB first on the stream. * IN assertion: there is enough room in pendingBuf. */ #define put_short(s, w) { \ put_byte(s, (uch)((w) & 0xff)); \ put_byte(s, (uch)((ush)(w) >> 8)); \ } /* =========================================================================== * Send a value on a given number of bits. * IN assertion: length <= 16 and value fits in length bits. */ #ifdef DEBUG local void send_bits OF((deflate_state *s, int value, int length)); local void send_bits(s, value, length) deflate_state *s; int value; /* value to send */ int length; /* number of bits */ { Tracevv((stderr," l %2d v %4x ", length, value)); Assert(length > 0 && length <= 15, "invalid length"); s->bits_sent += (ulg)length; /* If not enough room in bi_buf, use (valid) bits from bi_buf and * (16 - bi_valid) bits from value, leaving (width - (16-bi_valid)) * unused bits in value. */ if (s->bi_valid > (int)Buf_size - length) { s->bi_buf |= (ush)value << s->bi_valid; put_short(s, s->bi_buf); s->bi_buf = (ush)value >> (Buf_size - s->bi_valid); s->bi_valid += length - Buf_size; } else { s->bi_buf |= (ush)value << s->bi_valid; s->bi_valid += length; } } #else /* !DEBUG */ #define send_bits(s, value, length) \ { int len = length;\ if (s->bi_valid > (int)Buf_size - len) {\ int val = value;\ s->bi_buf |= (ush)val << s->bi_valid;\ put_short(s, s->bi_buf);\ s->bi_buf = (ush)val >> (Buf_size - s->bi_valid);\ s->bi_valid += len - Buf_size;\ } else {\ s->bi_buf |= (ush)(value) << s->bi_valid;\ s->bi_valid += len;\ }\ } #endif /* DEBUG */ /* the arguments must not have side effects */ /* =========================================================================== * Initialize the various 'constant' tables. */ local void tr_static_init() { #if defined(GEN_TREES_H) || !defined(STDC) static int static_init_done = 0; int n; /* iterates over tree elements */ int bits; /* bit counter */ int length; /* length value */ int code; /* code value */ int dist; /* distance index */ ush bl_count[MAX_BITS+1]; /* number of codes at each bit length for an optimal tree */ if (static_init_done) return; /* For some embedded targets, global variables are not initialized: */ #ifdef NO_INIT_GLOBAL_POINTERS static_l_desc.static_tree = static_ltree; static_l_desc.extra_bits = extra_lbits; static_d_desc.static_tree = static_dtree; static_d_desc.extra_bits = extra_dbits; static_bl_desc.extra_bits = extra_blbits; #endif /* Initialize the mapping length (0..255) -> length code (0..28) */ length = 0; for (code = 0; code < LENGTH_CODES-1; code++) { base_length[code] = length; for (n = 0; n < (1< dist code (0..29) */ dist = 0; for (code = 0 ; code < 16; code++) { base_dist[code] = dist; for (n = 0; n < (1<>= 7; /* from now on, all distances are divided by 128 */ for ( ; code < D_CODES; code++) { base_dist[code] = dist << 7; for (n = 0; n < (1<<(extra_dbits[code]-7)); n++) { _dist_code[256 + dist++] = (uch)code; } } Assert (dist == 256, "tr_static_init: 256+dist != 512"); /* Construct the codes of the static literal tree */ for (bits = 0; bits <= MAX_BITS; bits++) bl_count[bits] = 0; n = 0; while (n <= 143) static_ltree[n++].Len = 8, bl_count[8]++; while (n <= 255) static_ltree[n++].Len = 9, bl_count[9]++; while (n <= 279) static_ltree[n++].Len = 7, bl_count[7]++; while (n <= 287) static_ltree[n++].Len = 8, bl_count[8]++; /* Codes 286 and 287 do not exist, but we must include them in the * tree construction to get a canonical Huffman tree (longest code * all ones) */ gen_codes((ct_data *)static_ltree, L_CODES+1, bl_count); /* The static distance tree is trivial: */ for (n = 0; n < D_CODES; n++) { static_dtree[n].Len = 5; static_dtree[n].Code = bi_reverse((unsigned)n, 5); } static_init_done = 1; # ifdef GEN_TREES_H gen_trees_header(); # endif #endif /* defined(GEN_TREES_H) || !defined(STDC) */ } /* =========================================================================== * Genererate the file trees.h describing the static trees. */ #ifdef GEN_TREES_H # ifndef DEBUG # include # endif # define SEPARATOR(i, last, width) \ ((i) == (last)? "\n};\n\n" : \ ((i) % (width) == (width)-1 ? ",\n" : ", ")) void gen_trees_header() { FILE *header = fopen("trees.h", "w"); int i; Assert (header != NULL, "Can't open trees.h"); fprintf(header, "/* header created automatically with -DGEN_TREES_H */\n\n"); fprintf(header, "local const ct_data static_ltree[L_CODES+2] = {\n"); for (i = 0; i < L_CODES+2; i++) { fprintf(header, "{{%3u},{%3u}}%s", static_ltree[i].Code, static_ltree[i].Len, SEPARATOR(i, L_CODES+1, 5)); } fprintf(header, "local const ct_data static_dtree[D_CODES] = {\n"); for (i = 0; i < D_CODES; i++) { fprintf(header, "{{%2u},{%2u}}%s", static_dtree[i].Code, static_dtree[i].Len, SEPARATOR(i, D_CODES-1, 5)); } fprintf(header, "const uch ZLIB_INTERNAL _dist_code[DIST_CODE_LEN] = {\n"); for (i = 0; i < DIST_CODE_LEN; i++) { fprintf(header, "%2u%s", _dist_code[i], SEPARATOR(i, DIST_CODE_LEN-1, 20)); } fprintf(header, "const uch ZLIB_INTERNAL _length_code[MAX_MATCH-MIN_MATCH+1]= {\n"); for (i = 0; i < MAX_MATCH-MIN_MATCH+1; i++) { fprintf(header, "%2u%s", _length_code[i], SEPARATOR(i, MAX_MATCH-MIN_MATCH, 20)); } fprintf(header, "local const int base_length[LENGTH_CODES] = {\n"); for (i = 0; i < LENGTH_CODES; i++) { fprintf(header, "%1u%s", base_length[i], SEPARATOR(i, LENGTH_CODES-1, 20)); } fprintf(header, "local const int base_dist[D_CODES] = {\n"); for (i = 0; i < D_CODES; i++) { fprintf(header, "%5u%s", base_dist[i], SEPARATOR(i, D_CODES-1, 10)); } fclose(header); } #endif /* GEN_TREES_H */ /* =========================================================================== * Initialize the tree data structures for a new zlib stream. */ void ZLIB_INTERNAL _tr_init(s) deflate_state *s; { tr_static_init(); s->l_desc.dyn_tree = s->dyn_ltree; s->l_desc.stat_desc = &static_l_desc; s->d_desc.dyn_tree = s->dyn_dtree; s->d_desc.stat_desc = &static_d_desc; s->bl_desc.dyn_tree = s->bl_tree; s->bl_desc.stat_desc = &static_bl_desc; s->bi_buf = 0; s->bi_valid = 0; s->last_eob_len = 8; /* enough lookahead for inflate */ #ifdef DEBUG s->compressed_len = 0L; s->bits_sent = 0L; #endif /* Initialize the first block of the first file: */ init_block(s); } /* =========================================================================== * Initialize a new block. */ local void init_block(s) deflate_state *s; { int n; /* iterates over tree elements */ /* Initialize the trees. */ for (n = 0; n < L_CODES; n++) s->dyn_ltree[n].Freq = 0; for (n = 0; n < D_CODES; n++) s->dyn_dtree[n].Freq = 0; for (n = 0; n < BL_CODES; n++) s->bl_tree[n].Freq = 0; s->dyn_ltree[END_BLOCK].Freq = 1; s->opt_len = s->static_len = 0L; s->last_lit = s->matches = 0; } #define SMALLEST 1 /* Index within the heap array of least frequent node in the Huffman tree */ /* =========================================================================== * Remove the smallest element from the heap and recreate the heap with * one less element. Updates heap and heap_len. */ #define pqremove(s, tree, top) \ {\ top = s->heap[SMALLEST]; \ s->heap[SMALLEST] = s->heap[s->heap_len--]; \ pqdownheap(s, tree, SMALLEST); \ } /* =========================================================================== * Compares to subtrees, using the tree depth as tie breaker when * the subtrees have equal frequency. This minimizes the worst case length. */ #define smaller(tree, n, m, depth) \ (tree[n].Freq < tree[m].Freq || \ (tree[n].Freq == tree[m].Freq && depth[n] <= depth[m])) /* =========================================================================== * Restore the heap property by moving down the tree starting at node k, * exchanging a node with the smallest of its two sons if necessary, stopping * when the heap property is re-established (each father smaller than its * two sons). */ local void pqdownheap(s, tree, k) deflate_state *s; ct_data *tree; /* the tree to restore */ int k; /* node to move down */ { int v = s->heap[k]; int j = k << 1; /* left son of k */ while (j <= s->heap_len) { /* Set j to the smallest of the two sons: */ if (j < s->heap_len && smaller(tree, s->heap[j+1], s->heap[j], s->depth)) { j++; } /* Exit if v is smaller than both sons */ if (smaller(tree, v, s->heap[j], s->depth)) break; /* Exchange v with the smallest son */ s->heap[k] = s->heap[j]; k = j; /* And continue down the tree, setting j to the left son of k */ j <<= 1; } s->heap[k] = v; } /* =========================================================================== * Compute the optimal bit lengths for a tree and update the total bit length * for the current block. * IN assertion: the fields freq and dad are set, heap[heap_max] and * above are the tree nodes sorted by increasing frequency. * OUT assertions: the field len is set to the optimal bit length, the * array bl_count contains the frequencies for each bit length. * The length opt_len is updated; static_len is also updated if stree is * not null. */ local void gen_bitlen(s, desc) deflate_state *s; tree_desc *desc; /* the tree descriptor */ { ct_data *tree = desc->dyn_tree; int max_code = desc->max_code; const ct_data *stree = desc->stat_desc->static_tree; const intf *extra = desc->stat_desc->extra_bits; int base = desc->stat_desc->extra_base; int max_length = desc->stat_desc->max_length; int h; /* heap index */ int n, m; /* iterate over the tree elements */ int bits; /* bit length */ int xbits; /* extra bits */ ush f; /* frequency */ int overflow = 0; /* number of elements with bit length too large */ for (bits = 0; bits <= MAX_BITS; bits++) s->bl_count[bits] = 0; /* In a first pass, compute the optimal bit lengths (which may * overflow in the case of the bit length tree). */ tree[s->heap[s->heap_max]].Len = 0; /* root of the heap */ for (h = s->heap_max+1; h < HEAP_SIZE; h++) { n = s->heap[h]; bits = tree[tree[n].Dad].Len + 1; if (bits > max_length) bits = max_length, overflow++; tree[n].Len = (ush)bits; /* We overwrite tree[n].Dad which is no longer needed */ if (n > max_code) continue; /* not a leaf node */ s->bl_count[bits]++; xbits = 0; if (n >= base) xbits = extra[n-base]; f = tree[n].Freq; s->opt_len += (ulg)f * (bits + xbits); if (stree) s->static_len += (ulg)f * (stree[n].Len + xbits); } if (overflow == 0) return; Trace((stderr,"\nbit length overflow\n")); /* This happens for example on obj2 and pic of the Calgary corpus */ /* Find the first bit length which could increase: */ do { bits = max_length-1; while (s->bl_count[bits] == 0) bits--; s->bl_count[bits]--; /* move one leaf down the tree */ s->bl_count[bits+1] += 2; /* move one overflow item as its brother */ s->bl_count[max_length]--; /* The brother of the overflow item also moves one step up, * but this does not affect bl_count[max_length] */ overflow -= 2; } while (overflow > 0); /* Now recompute all bit lengths, scanning in increasing frequency. * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all * lengths instead of fixing only the wrong ones. This idea is taken * from 'ar' written by Haruhiko Okumura.) */ for (bits = max_length; bits != 0; bits--) { n = s->bl_count[bits]; while (n != 0) { m = s->heap[--h]; if (m > max_code) continue; if ((unsigned) tree[m].Len != (unsigned) bits) { Trace((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits)); s->opt_len += ((long)bits - (long)tree[m].Len) *(long)tree[m].Freq; tree[m].Len = (ush)bits; } n--; } } } /* =========================================================================== * Generate the codes for a given tree and bit counts (which need not be * optimal). * IN assertion: the array bl_count contains the bit length statistics for * the given tree and the field len is set for all tree elements. * OUT assertion: the field code is set for all tree elements of non * zero code length. */ local void gen_codes (tree, max_code, bl_count) ct_data *tree; /* the tree to decorate */ int max_code; /* largest code with non zero frequency */ ushf *bl_count; /* number of codes at each bit length */ { ush next_code[MAX_BITS+1]; /* next code value for each bit length */ ush code = 0; /* running code value */ int bits; /* bit index */ int n; /* code index */ /* The distribution counts are first used to generate the code values * without bit reversal. */ for (bits = 1; bits <= MAX_BITS; bits++) { next_code[bits] = code = (code + bl_count[bits-1]) << 1; } /* Check that the bit counts in bl_count are consistent. The last code * must be all ones. */ Assert (code + bl_count[MAX_BITS]-1 == (1<dyn_tree; const ct_data *stree = desc->stat_desc->static_tree; int elems = desc->stat_desc->elems; int n, m; /* iterate over heap elements */ int max_code = -1; /* largest code with non zero frequency */ int node; /* new node being created */ /* Construct the initial heap, with least frequent element in * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1]. * heap[0] is not used. */ s->heap_len = 0, s->heap_max = HEAP_SIZE; for (n = 0; n < elems; n++) { if (tree[n].Freq != 0) { s->heap[++(s->heap_len)] = max_code = n; s->depth[n] = 0; } else { tree[n].Len = 0; } } /* The pkzip format requires that at least one distance code exists, * and that at least one bit should be sent even if there is only one * possible code. So to avoid special checks later on we force at least * two codes of non zero frequency. */ while (s->heap_len < 2) { node = s->heap[++(s->heap_len)] = (max_code < 2 ? ++max_code : 0); tree[node].Freq = 1; s->depth[node] = 0; s->opt_len--; if (stree) s->static_len -= stree[node].Len; /* node is 0 or 1 so it does not have extra bits */ } desc->max_code = max_code; /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree, * establish sub-heaps of increasing lengths: */ for (n = s->heap_len/2; n >= 1; n--) pqdownheap(s, tree, n); /* Construct the Huffman tree by repeatedly combining the least two * frequent nodes. */ node = elems; /* next internal node of the tree */ do { pqremove(s, tree, n); /* n = node of least frequency */ m = s->heap[SMALLEST]; /* m = node of next least frequency */ s->heap[--(s->heap_max)] = n; /* keep the nodes sorted by frequency */ s->heap[--(s->heap_max)] = m; /* Create a new node father of n and m */ tree[node].Freq = tree[n].Freq + tree[m].Freq; s->depth[node] = (uch)((s->depth[n] >= s->depth[m] ? s->depth[n] : s->depth[m]) + 1); tree[n].Dad = tree[m].Dad = (ush)node; #ifdef DUMP_BL_TREE if (tree == s->bl_tree) { fprintf(stderr,"\nnode %d(%d), sons %d(%d) %d(%d)", node, tree[node].Freq, n, tree[n].Freq, m, tree[m].Freq); } #endif /* and insert the new node in the heap */ s->heap[SMALLEST] = node++; pqdownheap(s, tree, SMALLEST); } while (s->heap_len >= 2); s->heap[--(s->heap_max)] = s->heap[SMALLEST]; /* At this point, the fields freq and dad are set. We can now * generate the bit lengths. */ gen_bitlen(s, (tree_desc *)desc); /* The field len is now set, we can generate the bit codes */ gen_codes ((ct_data *)tree, max_code, s->bl_count); } /* =========================================================================== * Scan a literal or distance tree to determine the frequencies of the codes * in the bit length tree. */ local void scan_tree (s, tree, max_code) deflate_state *s; ct_data *tree; /* the tree to be scanned */ int max_code; /* and its largest code of non zero frequency */ { int n; /* iterates over all tree elements */ int prevlen = -1; /* last emitted length */ int curlen; /* length of current code */ int nextlen = tree[0].Len; /* length of next code */ int count = 0; /* repeat count of the current code */ int max_count = 7; /* max repeat count */ int min_count = 4; /* min repeat count */ if (nextlen == 0) max_count = 138, min_count = 3; tree[max_code+1].Len = (ush)0xffff; /* guard */ for (n = 0; n <= max_code; n++) { curlen = nextlen; nextlen = tree[n+1].Len; if (++count < max_count && curlen == nextlen) { continue; } else if (count < min_count) { s->bl_tree[curlen].Freq += (ush)count; } else if (curlen != 0) { if (curlen != prevlen) s->bl_tree[curlen].Freq++; s->bl_tree[REP_3_6].Freq++; } else if (count <= 10) { s->bl_tree[REPZ_3_10].Freq++; } else { s->bl_tree[REPZ_11_138].Freq++; } count = 0; prevlen = curlen; if (nextlen == 0) { max_count = 138, min_count = 3; } else if (curlen == nextlen) { max_count = 6, min_count = 3; } else { max_count = 7, min_count = 4; } } } /* =========================================================================== * Send a literal or distance tree in compressed form, using the codes in * bl_tree. */ local void send_tree (s, tree, max_code) deflate_state *s; ct_data *tree; /* the tree to be scanned */ int max_code; /* and its largest code of non zero frequency */ { int n; /* iterates over all tree elements */ int prevlen = -1; /* last emitted length */ int curlen; /* length of current code */ int nextlen = tree[0].Len; /* length of next code */ int count = 0; /* repeat count of the current code */ int max_count = 7; /* max repeat count */ int min_count = 4; /* min repeat count */ /* tree[max_code+1].Len = -1; */ /* guard already set */ if (nextlen == 0) max_count = 138, min_count = 3; for (n = 0; n <= max_code; n++) { curlen = nextlen; nextlen = tree[n+1].Len; if (++count < max_count && curlen == nextlen) { continue; } else if (count < min_count) { do { send_code(s, curlen, s->bl_tree); } while (--count != 0); } else if (curlen != 0) { if (curlen != prevlen) { send_code(s, curlen, s->bl_tree); count--; } Assert(count >= 3 && count <= 6, " 3_6?"); send_code(s, REP_3_6, s->bl_tree); send_bits(s, count-3, 2); } else if (count <= 10) { send_code(s, REPZ_3_10, s->bl_tree); send_bits(s, count-3, 3); } else { send_code(s, REPZ_11_138, s->bl_tree); send_bits(s, count-11, 7); } count = 0; prevlen = curlen; if (nextlen == 0) { max_count = 138, min_count = 3; } else if (curlen == nextlen) { max_count = 6, min_count = 3; } else { max_count = 7, min_count = 4; } } } /* =========================================================================== * Construct the Huffman tree for the bit lengths and return the index in * bl_order of the last bit length code to send. */ local int build_bl_tree(s) deflate_state *s; { int max_blindex; /* index of last bit length code of non zero freq */ /* Determine the bit length frequencies for literal and distance trees */ scan_tree(s, (ct_data *)s->dyn_ltree, s->l_desc.max_code); scan_tree(s, (ct_data *)s->dyn_dtree, s->d_desc.max_code); /* Build the bit length tree: */ build_tree(s, (tree_desc *)(&(s->bl_desc))); /* opt_len now includes the length of the tree representations, except * the lengths of the bit lengths codes and the 5+5+4 bits for the counts. */ /* Determine the number of bit length codes to send. The pkzip format * requires that at least 4 bit length codes be sent. (appnote.txt says * 3 but the actual value used is 4.) */ for (max_blindex = BL_CODES-1; max_blindex >= 3; max_blindex--) { if (s->bl_tree[bl_order[max_blindex]].Len != 0) break; } /* Update opt_len to include the bit length tree and counts */ s->opt_len += 3*(max_blindex+1) + 5+5+4; Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld", s->opt_len, s->static_len)); return max_blindex; } /* =========================================================================== * Send the header for a block using dynamic Huffman trees: the counts, the * lengths of the bit length codes, the literal tree and the distance tree. * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4. */ local void send_all_trees(s, lcodes, dcodes, blcodes) deflate_state *s; int lcodes, dcodes, blcodes; /* number of codes for each tree */ { int rank; /* index in bl_order */ Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes"); Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES, "too many codes"); Tracev((stderr, "\nbl counts: ")); send_bits(s, lcodes-257, 5); /* not +255 as stated in appnote.txt */ send_bits(s, dcodes-1, 5); send_bits(s, blcodes-4, 4); /* not -3 as stated in appnote.txt */ for (rank = 0; rank < blcodes; rank++) { Tracev((stderr, "\nbl code %2d ", bl_order[rank])); send_bits(s, s->bl_tree[bl_order[rank]].Len, 3); } Tracev((stderr, "\nbl tree: sent %ld", s->bits_sent)); send_tree(s, (ct_data *)s->dyn_ltree, lcodes-1); /* literal tree */ Tracev((stderr, "\nlit tree: sent %ld", s->bits_sent)); send_tree(s, (ct_data *)s->dyn_dtree, dcodes-1); /* distance tree */ Tracev((stderr, "\ndist tree: sent %ld", s->bits_sent)); } /* =========================================================================== * Send a stored block */ void ZLIB_INTERNAL _tr_stored_block(s, buf, stored_len, last) deflate_state *s; charf *buf; /* input block */ ulg stored_len; /* length of input block */ int last; /* one if this is the last block for a file */ { send_bits(s, (STORED_BLOCK<<1)+last, 3); /* send block type */ #ifdef DEBUG s->compressed_len = (s->compressed_len + 3 + 7) & (ulg)~7L; s->compressed_len += (stored_len + 4) << 3; #endif copy_block(s, buf, (unsigned)stored_len, 1); /* with header */ } /* =========================================================================== * Send one empty static block to give enough lookahead for inflate. * This takes 10 bits, of which 7 may remain in the bit buffer. * The current inflate code requires 9 bits of lookahead. If the * last two codes for the previous block (real code plus EOB) were coded * on 5 bits or less, inflate may have only 5+3 bits of lookahead to decode * the last real code. In this case we send two empty static blocks instead * of one. (There are no problems if the previous block is stored or fixed.) * To simplify the code, we assume the worst case of last real code encoded * on one bit only. */ void ZLIB_INTERNAL _tr_align(s) deflate_state *s; { send_bits(s, STATIC_TREES<<1, 3); send_code(s, END_BLOCK, static_ltree); #ifdef DEBUG s->compressed_len += 10L; /* 3 for block type, 7 for EOB */ #endif bi_flush(s); /* Of the 10 bits for the empty block, we have already sent * (10 - bi_valid) bits. The lookahead for the last real code (before * the EOB of the previous block) was thus at least one plus the length * of the EOB plus what we have just sent of the empty static block. */ if (1 + s->last_eob_len + 10 - s->bi_valid < 9) { send_bits(s, STATIC_TREES<<1, 3); send_code(s, END_BLOCK, static_ltree); #ifdef DEBUG s->compressed_len += 10L; #endif bi_flush(s); } s->last_eob_len = 7; } /* =========================================================================== * Determine the best encoding for the current block: dynamic trees, static * trees or store, and output the encoded block to the zip file. */ void ZLIB_INTERNAL _tr_flush_block(s, buf, stored_len, last) deflate_state *s; charf *buf; /* input block, or NULL if too old */ ulg stored_len; /* length of input block */ int last; /* one if this is the last block for a file */ { ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */ int max_blindex = 0; /* index of last bit length code of non zero freq */ /* Build the Huffman trees unless a stored block is forced */ if (s->level > 0) { /* Check if the file is binary or text */ if (s->strm->data_type == Z_UNKNOWN) s->strm->data_type = detect_data_type(s); /* Construct the literal and distance trees */ build_tree(s, (tree_desc *)(&(s->l_desc))); Tracev((stderr, "\nlit data: dyn %ld, stat %ld", s->opt_len, s->static_len)); build_tree(s, (tree_desc *)(&(s->d_desc))); Tracev((stderr, "\ndist data: dyn %ld, stat %ld", s->opt_len, s->static_len)); /* At this point, opt_len and static_len are the total bit lengths of * the compressed block data, excluding the tree representations. */ /* Build the bit length tree for the above two trees, and get the index * in bl_order of the last bit length code to send. */ max_blindex = build_bl_tree(s); /* Determine the best encoding. Compute the block lengths in bytes. */ opt_lenb = (s->opt_len+3+7)>>3; static_lenb = (s->static_len+3+7)>>3; Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ", opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len, s->last_lit)); if (static_lenb <= opt_lenb) opt_lenb = static_lenb; } else { Assert(buf != (char*)0, "lost buf"); opt_lenb = static_lenb = stored_len + 5; /* force a stored block */ } #ifdef FORCE_STORED if (buf != (char*)0) { /* force stored block */ #else if (stored_len+4 <= opt_lenb && buf != (char*)0) { /* 4: two words for the lengths */ #endif /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE. * Otherwise we can't have processed more than WSIZE input bytes since * the last block flush, because compression would have been * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to * transform a block into a stored block. */ _tr_stored_block(s, buf, stored_len, last); #ifdef FORCE_STATIC } else if (static_lenb >= 0) { /* force static trees */ #else } else if (s->strategy == Z_FIXED || static_lenb == opt_lenb) { #endif send_bits(s, (STATIC_TREES<<1)+last, 3); compress_block(s, (ct_data *)static_ltree, (ct_data *)static_dtree); #ifdef DEBUG s->compressed_len += 3 + s->static_len; #endif } else { send_bits(s, (DYN_TREES<<1)+last, 3); send_all_trees(s, s->l_desc.max_code+1, s->d_desc.max_code+1, max_blindex+1); compress_block(s, (ct_data *)s->dyn_ltree, (ct_data *)s->dyn_dtree); #ifdef DEBUG s->compressed_len += 3 + s->opt_len; #endif } Assert (s->compressed_len == s->bits_sent, "bad compressed size"); /* The above check is made mod 2^32, for files larger than 512 MB * and uLong implemented on 32 bits. */ init_block(s); if (last) { bi_windup(s); #ifdef DEBUG s->compressed_len += 7; /* align on byte boundary */ #endif } Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len>>3, s->compressed_len-7*last)); } /* =========================================================================== * Save the match info and tally the frequency counts. Return true if * the current block must be flushed. */ int ZLIB_INTERNAL _tr_tally (s, dist, lc) deflate_state *s; unsigned dist; /* distance of matched string */ unsigned lc; /* match length-MIN_MATCH or unmatched char (if dist==0) */ { s->d_buf[s->last_lit] = (ush)dist; s->l_buf[s->last_lit++] = (uch)lc; if (dist == 0) { /* lc is the unmatched char */ s->dyn_ltree[lc].Freq++; } else { s->matches++; /* Here, lc is the match length - MIN_MATCH */ dist--; /* dist = match distance - 1 */ Assert((ush)dist < (ush)MAX_DIST(s) && (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) && (ush)d_code(dist) < (ush)D_CODES, "_tr_tally: bad match"); s->dyn_ltree[_length_code[lc]+LITERALS+1].Freq++; s->dyn_dtree[d_code(dist)].Freq++; } #ifdef TRUNCATE_BLOCK /* Try to guess if it is profitable to stop the current block here */ if ((s->last_lit & 0x1fff) == 0 && s->level > 2) { /* Compute an upper bound for the compressed length */ ulg out_length = (ulg)s->last_lit*8L; ulg in_length = (ulg)((long)s->strstart - s->block_start); int dcode; for (dcode = 0; dcode < D_CODES; dcode++) { out_length += (ulg)s->dyn_dtree[dcode].Freq * (5L+extra_dbits[dcode]); } out_length >>= 3; Tracev((stderr,"\nlast_lit %u, in %ld, out ~%ld(%ld%%) ", s->last_lit, in_length, out_length, 100L - out_length*100L/in_length)); if (s->matches < s->last_lit/2 && out_length < in_length/2) return 1; } #endif return (s->last_lit == s->lit_bufsize-1); /* We avoid equality with lit_bufsize because of wraparound at 64K * on 16 bit machines and because stored blocks are restricted to * 64K-1 bytes. */ } /* =========================================================================== * Send the block data compressed using the given Huffman trees */ local void compress_block(s, ltree, dtree) deflate_state *s; ct_data *ltree; /* literal tree */ ct_data *dtree; /* distance tree */ { unsigned dist; /* distance of matched string */ int lc; /* match length or unmatched char (if dist == 0) */ unsigned lx = 0; /* running index in l_buf */ unsigned code; /* the code to send */ int extra; /* number of extra bits to send */ if (s->last_lit != 0) do { dist = s->d_buf[lx]; lc = s->l_buf[lx++]; if (dist == 0) { send_code(s, lc, ltree); /* send a literal byte */ Tracecv(isgraph(lc), (stderr," '%c' ", lc)); } else { /* Here, lc is the match length - MIN_MATCH */ code = _length_code[lc]; send_code(s, code+LITERALS+1, ltree); /* send the length code */ extra = extra_lbits[code]; if (extra != 0) { lc -= base_length[code]; send_bits(s, lc, extra); /* send the extra length bits */ } dist--; /* dist is now the match distance - 1 */ code = d_code(dist); Assert (code < D_CODES, "bad d_code"); send_code(s, code, dtree); /* send the distance code */ extra = extra_dbits[code]; if (extra != 0) { dist -= base_dist[code]; send_bits(s, dist, extra); /* send the extra distance bits */ } } /* literal or match pair ? */ /* Check that the overlay between pending_buf and d_buf+l_buf is ok: */ Assert((uInt)(s->pending) < s->lit_bufsize + 2*lx, "pendingBuf overflow"); } while (lx < s->last_lit); send_code(s, END_BLOCK, ltree); s->last_eob_len = ltree[END_BLOCK].Len; } /* =========================================================================== * Check if the data type is TEXT or BINARY, using the following algorithm: * - TEXT if the two conditions below are satisfied: * a) There are no non-portable control characters belonging to the * "black list" (0..6, 14..25, 28..31). * b) There is at least one printable character belonging to the * "white list" (9 {TAB}, 10 {LF}, 13 {CR}, 32..255). * - BINARY otherwise. * - The following partially-portable control characters form a * "gray list" that is ignored in this detection algorithm: * (7 {BEL}, 8 {BS}, 11 {VT}, 12 {FF}, 26 {SUB}, 27 {ESC}). * IN assertion: the fields Freq of dyn_ltree are set. */ local int detect_data_type(s) deflate_state *s; { /* black_mask is the bit mask of black-listed bytes * set bits 0..6, 14..25, and 28..31 * 0xf3ffc07f = binary 11110011111111111100000001111111 */ unsigned long black_mask = 0xf3ffc07fUL; int n; /* Check for non-textual ("black-listed") bytes. */ for (n = 0; n <= 31; n++, black_mask >>= 1) if ((black_mask & 1) && (s->dyn_ltree[n].Freq != 0)) return Z_BINARY; /* Check for textual ("white-listed") bytes. */ if (s->dyn_ltree[9].Freq != 0 || s->dyn_ltree[10].Freq != 0 || s->dyn_ltree[13].Freq != 0) return Z_TEXT; for (n = 32; n < LITERALS; n++) if (s->dyn_ltree[n].Freq != 0) return Z_TEXT; /* There are no "black-listed" or "white-listed" bytes: * this stream either is empty or has tolerated ("gray-listed") bytes only. */ return Z_BINARY; } /* =========================================================================== * Reverse the first len bits of a code, using straightforward code (a faster * method would use a table) * IN assertion: 1 <= len <= 15 */ local unsigned bi_reverse(code, len) unsigned code; /* the value to invert */ int len; /* its bit length */ { register unsigned res = 0; do { res |= code & 1; code >>= 1, res <<= 1; } while (--len > 0); return res >> 1; } /* =========================================================================== * Flush the bit buffer, keeping at most 7 bits in it. */ local void bi_flush(s) deflate_state *s; { if (s->bi_valid == 16) { put_short(s, s->bi_buf); s->bi_buf = 0; s->bi_valid = 0; } else if (s->bi_valid >= 8) { put_byte(s, (Byte)s->bi_buf); s->bi_buf >>= 8; s->bi_valid -= 8; } } /* =========================================================================== * Flush the bit buffer and align the output on a byte boundary */ local void bi_windup(s) deflate_state *s; { if (s->bi_valid > 8) { put_short(s, s->bi_buf); } else if (s->bi_valid > 0) { put_byte(s, (Byte)s->bi_buf); } s->bi_buf = 0; s->bi_valid = 0; #ifdef DEBUG s->bits_sent = (s->bits_sent+7) & ~7; #endif } /* =========================================================================== * Copy a stored block, storing first the length and its * one's complement if requested. */ local void copy_block(s, buf, len, header) deflate_state *s; charf *buf; /* the input data */ unsigned len; /* its length */ int header; /* true if block header must be written */ { bi_windup(s); /* align on byte boundary */ s->last_eob_len = 8; /* enough lookahead for inflate */ if (header) { put_short(s, (ush)len); put_short(s, (ush)~len); #ifdef DEBUG s->bits_sent += 2*16; #endif } #ifdef DEBUG s->bits_sent += (ulg)len<<3; #endif while (len--) { put_byte(s, *buf++); } } libgit2-0.19.0/deps/zlib/trees.h000066400000000000000000000204301216214232500163200ustar00rootroot00000000000000/* 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 }; libgit2-0.19.0/deps/zlib/zconf.h000066400000000000000000000024241216214232500163200ustar00rootroot00000000000000/* 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" /* 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 */ libgit2-0.19.0/deps/zlib/zlib.h000066400000000000000000002333141216214232500161450ustar00rootroot00000000000000/* zlib.h -- interface of the 'zlib' general purpose compression library version 1.2.5, April 19th, 2010 Copyright (C) 1995-2010 Jean-loup Gailly and Mark Adler This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. Jean-loup Gailly Mark Adler jloup@gzip.org madler@alumni.caltech.edu The data format used by the zlib library is described by RFCs (Request for Comments) 1950 to 1952 in the files http://www.ietf.org/rfc/rfc1950.txt (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format). */ #ifndef ZLIB_H #define ZLIB_H #include "zconf.h" #ifdef __cplusplus extern "C" { #endif #define ZLIB_VERSION "1.2.5" #define ZLIB_VERNUM 0x1250 #define ZLIB_VER_MAJOR 1 #define ZLIB_VER_MINOR 2 #define ZLIB_VER_REVISION 5 #define ZLIB_VER_SUBREVISION 0 /* The 'zlib' compression library provides in-memory compression and decompression functions, including integrity checks of the uncompressed data. This version of the library supports only one compression method (deflation) but other algorithms will be added later and will have the same stream interface. Compression can be done in a single step if the buffers are large enough, or can be done by repeated calls of the compression function. In the latter case, the application must provide more input and/or consume the output (providing more output space) before each call. The compressed data format used by default by the in-memory functions is the zlib format, which is a zlib wrapper documented in RFC 1950, wrapped around a deflate stream, which is itself documented in RFC 1951. The library also supports reading and writing files in gzip (.gz) format with an interface similar to that of stdio using the functions that start with "gz". The gzip format is different from the zlib format. gzip is a gzip wrapper, documented in RFC 1952, wrapped around a deflate stream. This library can optionally read and write gzip streams in memory as well. The zlib format was designed to be compact and fast for use in memory and on communications channels. The gzip format was designed for single- file compression on file systems, has a larger header than zlib to maintain directory information, and uses a different, slower check method than zlib. The library does not install any signal handler. The decoder checks the consistency of the compressed data, so the library should never crash even in case of corrupted input. */ typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size)); typedef void (*free_func) OF((voidpf opaque, voidpf address)); struct internal_state; typedef struct z_stream_s { Bytef *next_in; /* next input byte */ uInt avail_in; /* number of bytes available at next_in */ uLong total_in; /* total nb of input bytes read so far */ Bytef *next_out; /* next output byte should be put there */ uInt avail_out; /* remaining free space at next_out */ uLong total_out; /* total nb of bytes output so far */ char *msg; /* last error message, NULL if no error */ struct internal_state FAR *state; /* not visible by applications */ alloc_func zalloc; /* used to allocate the internal state */ free_func zfree; /* used to free the internal state */ voidpf opaque; /* private data object passed to zalloc and zfree */ int data_type; /* best guess about the data type: binary or text */ uLong adler; /* adler32 value of the uncompressed data */ uLong reserved; /* reserved for future use */ } z_stream; typedef z_stream FAR *z_streamp; /* gzip header information passed to and from zlib routines. See RFC 1952 for more details on the meanings of these fields. */ typedef struct gz_header_s { int text; /* true if compressed data believed to be text */ uLong time; /* modification time */ int xflags; /* extra flags (not used when writing a gzip file) */ int os; /* operating system */ Bytef *extra; /* pointer to extra field or Z_NULL if none */ uInt extra_len; /* extra field length (valid if extra != Z_NULL) */ uInt extra_max; /* space at extra (only when reading header) */ Bytef *name; /* pointer to zero-terminated file name or Z_NULL */ uInt name_max; /* space at name (only when reading header) */ Bytef *comment; /* pointer to zero-terminated comment or Z_NULL */ uInt comm_max; /* space at comment (only when reading header) */ int hcrc; /* true if there was or will be a header crc */ int done; /* true when done reading gzip header (not used when writing a gzip file) */ } gz_header; typedef gz_header FAR *gz_headerp; /* The application must update next_in and avail_in when avail_in has dropped to zero. It must update next_out and avail_out when avail_out has dropped to zero. The application must initialize zalloc, zfree and opaque before calling the init function. All other fields are set by the compression library and must not be updated by the application. The opaque value provided by the application will be passed as the first parameter for calls of zalloc and zfree. This can be useful for custom memory management. The compression library attaches no meaning to the opaque value. zalloc must return Z_NULL if there is not enough memory for the object. If zlib is used in a multi-threaded application, zalloc and zfree must be thread safe. On 16-bit systems, the functions zalloc and zfree must be able to allocate exactly 65536 bytes, but will not be required to allocate more than this if the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS, pointers returned by zalloc for objects of exactly 65536 bytes *must* have their offset normalized to zero. The default allocation function provided by this library ensures this (see zutil.c). To reduce memory requirements and avoid any allocation of 64K objects, at the expense of compression ratio, compile the library with -DMAX_WBITS=14 (see zconf.h). The fields total_in and total_out can be used for statistics or progress reports. After compression, total_in holds the total size of the uncompressed data and may be saved for use in the decompressor (particularly if the decompressor wants to decompress everything in a single step). */ /* constants */ #define Z_NO_FLUSH 0 #define Z_PARTIAL_FLUSH 1 #define Z_SYNC_FLUSH 2 #define Z_FULL_FLUSH 3 #define Z_FINISH 4 #define Z_BLOCK 5 #define Z_TREES 6 /* Allowed flush values; see deflate() and inflate() below for details */ #define Z_OK 0 #define Z_STREAM_END 1 #define Z_NEED_DICT 2 #define Z_ERRNO (-1) #define Z_STREAM_ERROR (-2) #define Z_DATA_ERROR (-3) #define Z_MEM_ERROR (-4) #define Z_BUF_ERROR (-5) #define Z_VERSION_ERROR (-6) /* Return codes for the compression/decompression functions. Negative values * are errors, positive values are used for special but normal events. */ #define Z_NO_COMPRESSION 0 #define Z_BEST_SPEED 1 #define Z_BEST_COMPRESSION 9 #define Z_DEFAULT_COMPRESSION (-1) /* compression levels */ #define Z_FILTERED 1 #define Z_HUFFMAN_ONLY 2 #define Z_RLE 3 #define Z_FIXED 4 #define Z_DEFAULT_STRATEGY 0 /* compression strategy; see deflateInit2() below for details */ #define Z_BINARY 0 #define Z_TEXT 1 #define Z_ASCII Z_TEXT /* for compatibility with 1.2.2 and earlier */ #define Z_UNKNOWN 2 /* Possible values of the data_type field (though see inflate()) */ #define Z_DEFLATED 8 /* The deflate compression method (the only one supported in this version) */ #define Z_NULL 0 /* for initializing zalloc, zfree, opaque */ #define zlib_version zlibVersion() /* for compatibility with versions < 1.0.2 */ /* basic functions */ ZEXTERN const char * ZEXPORT zlibVersion OF((void)); /* The application can compare zlibVersion and ZLIB_VERSION for consistency. If the first character differs, the library code actually used is not compatible with the zlib.h header file used by the application. This check is automatically made by deflateInit and inflateInit. */ /* ZEXTERN int ZEXPORT deflateInit OF((z_streamp strm, int level)); Initializes the internal stream state for compression. The fields zalloc, zfree and opaque must be initialized before by the caller. If zalloc and zfree are set to Z_NULL, deflateInit updates them to use default allocation functions. The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9: 1 gives best speed, 9 gives best compression, 0 gives no compression at all (the input data is simply copied a block at a time). Z_DEFAULT_COMPRESSION requests a default compromise between speed and compression (currently equivalent to level 6). deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_STREAM_ERROR if level is not a valid compression level, or Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible with the version assumed by the caller (ZLIB_VERSION). msg is set to null if there is no error message. deflateInit does not perform any compression: this will be done by deflate(). */ ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush)); /* deflate compresses as much data as possible, and stops when the input buffer becomes empty or the output buffer becomes full. It may introduce some output latency (reading input without producing any output) except when forced to flush. The detailed semantics are as follows. deflate performs one or both of the following actions: - Compress more input starting at next_in and update next_in and avail_in accordingly. If not all input can be processed (because there is not enough room in the output buffer), next_in and avail_in are updated and processing will resume at this point for the next call of deflate(). - Provide more output starting at next_out and update next_out and avail_out accordingly. This action is forced if the parameter flush is non zero. Forcing flush frequently degrades the compression ratio, so this parameter should be set only when necessary (in interactive applications). Some output may be provided even if flush is not set. Before the call of deflate(), the application should ensure that at least one of the actions is possible, by providing more input and/or consuming more output, and updating avail_in or avail_out accordingly; avail_out should never be zero before the call. The application can consume the compressed output when it wants, for example when the output buffer is full (avail_out == 0), or after each call of deflate(). If deflate returns Z_OK and with zero avail_out, it must be called again after making room in the output buffer because there might be more output pending. Normally the parameter flush is set to Z_NO_FLUSH, which allows deflate to decide how much data to accumulate before producing output, in order to maximize compression. If the parameter flush is set to Z_SYNC_FLUSH, all pending output is flushed to the output buffer and the output is aligned on a byte boundary, so that the decompressor can get all input data available so far. (In particular avail_in is zero after the call if enough output space has been provided before the call.) Flushing may degrade compression for some compression algorithms and so it should be used only when necessary. This completes the current deflate block and follows it with an empty stored block that is three bits plus filler bits to the next byte, followed by four bytes (00 00 ff ff). If flush is set to Z_PARTIAL_FLUSH, all pending output is flushed to the output buffer, but the output is not aligned to a byte boundary. All of the input data so far will be available to the decompressor, as for Z_SYNC_FLUSH. This completes the current deflate block and follows it with an empty fixed codes block that is 10 bits long. This assures that enough bytes are output in order for the decompressor to finish the block before the empty fixed code block. If flush is set to Z_BLOCK, a deflate block is completed and emitted, as for Z_SYNC_FLUSH, but the output is not aligned on a byte boundary, and up to seven bits of the current block are held to be written as the next byte after the next deflate block is completed. In this case, the decompressor may not be provided enough bits at this point in order to complete decompression of the data provided so far to the compressor. It may need to wait for the next block to be emitted. This is for advanced applications that need to control the emission of deflate blocks. If flush is set to Z_FULL_FLUSH, all output is flushed as with Z_SYNC_FLUSH, and the compression state is reset so that decompression can restart from this point if previous compressed data has been damaged or if random access is desired. Using Z_FULL_FLUSH too often can seriously degrade compression. If deflate returns with avail_out == 0, this function must be called again with the same value of the flush parameter and more output space (updated avail_out), until the flush is complete (deflate returns with non-zero avail_out). In the case of a Z_FULL_FLUSH or Z_SYNC_FLUSH, make sure that avail_out is greater than six to avoid repeated flush markers due to avail_out == 0 on return. If the parameter flush is set to Z_FINISH, pending input is processed, pending output is flushed and deflate returns with Z_STREAM_END if there was enough output space; if deflate returns with Z_OK, this function must be called again with Z_FINISH and more output space (updated avail_out) but no more input data, until it returns with Z_STREAM_END or an error. After deflate has returned Z_STREAM_END, the only possible operations on the stream are deflateReset or deflateEnd. Z_FINISH can be used immediately after deflateInit if all the compression is to be done in a single step. In this case, avail_out must be at least the value returned by deflateBound (see below). If deflate does not return Z_STREAM_END, then it must be called again as described above. deflate() sets strm->adler to the adler32 checksum of all input read so far (that is, total_in bytes). deflate() may update strm->data_type if it can make a good guess about the input data type (Z_BINARY or Z_TEXT). In doubt, the data is considered binary. This field is only for information purposes and does not affect the compression algorithm in any manner. deflate() returns Z_OK if some progress has been made (more input processed or more output produced), Z_STREAM_END if all input has been consumed and all output has been produced (only when flush is set to Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example if next_in or next_out was Z_NULL), Z_BUF_ERROR if no progress is possible (for example avail_in or avail_out was zero). Note that Z_BUF_ERROR is not fatal, and deflate() can be called again with more input and more output space to continue compressing. */ ZEXTERN int ZEXPORT deflateEnd OF((z_streamp strm)); /* All dynamically allocated data structures for this stream are freed. This function discards any unprocessed input and does not flush any pending output. deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state was inconsistent, Z_DATA_ERROR if the stream was freed prematurely (some input or output was discarded). In the error case, msg may be set but then points to a static string (which must not be deallocated). */ /* ZEXTERN int ZEXPORT inflateInit OF((z_streamp strm)); Initializes the internal stream state for decompression. The fields next_in, avail_in, zalloc, zfree and opaque must be initialized before by the caller. If next_in is not Z_NULL and avail_in is large enough (the exact value depends on the compression method), inflateInit determines the compression method from the zlib header and allocates all data structures accordingly; otherwise the allocation will be deferred to the first call of inflate. If zalloc and zfree are set to Z_NULL, inflateInit updates them to use default allocation functions. inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_VERSION_ERROR if the zlib library version is incompatible with the version assumed by the caller, or Z_STREAM_ERROR if the parameters are invalid, such as a null pointer to the structure. msg is set to null if there is no error message. inflateInit does not perform any decompression apart from possibly reading the zlib header if present: actual decompression will be done by inflate(). (So next_in and avail_in may be modified, but next_out and avail_out are unused and unchanged.) The current implementation of inflateInit() does not process any header information -- that is deferred until inflate() is called. */ ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush)); /* inflate decompresses as much data as possible, and stops when the input buffer becomes empty or the output buffer becomes full. It may introduce some output latency (reading input without producing any output) except when forced to flush. The detailed semantics are as follows. inflate performs one or both of the following actions: - Decompress more input starting at next_in and update next_in and avail_in accordingly. If not all input can be processed (because there is not enough room in the output buffer), next_in is updated and processing will resume at this point for the next call of inflate(). - Provide more output starting at next_out and update next_out and avail_out accordingly. inflate() provides as much output as possible, until there is no more input data or no more space in the output buffer (see below about the flush parameter). Before the call of inflate(), the application should ensure that at least one of the actions is possible, by providing more input and/or consuming more output, and updating the next_* and avail_* values accordingly. The application can consume the uncompressed output when it wants, for example when the output buffer is full (avail_out == 0), or after each call of inflate(). If inflate returns Z_OK and with zero avail_out, it must be called again after making room in the output buffer because there might be more output pending. The flush parameter of inflate() can be Z_NO_FLUSH, Z_SYNC_FLUSH, Z_FINISH, Z_BLOCK, or Z_TREES. Z_SYNC_FLUSH requests that inflate() flush as much output as possible to the output buffer. Z_BLOCK requests that inflate() stop if and when it gets to the next deflate block boundary. When decoding the zlib or gzip format, this will cause inflate() to return immediately after the header and before the first block. When doing a raw inflate, inflate() will go ahead and process the first block, and will return when it gets to the end of that block, or when it runs out of data. The Z_BLOCK option assists in appending to or combining deflate streams. Also to assist in this, on return inflate() will set strm->data_type to the number of unused bits in the last byte taken from strm->next_in, plus 64 if inflate() is currently decoding the last block in the deflate stream, plus 128 if inflate() returned immediately after decoding an end-of-block code or decoding the complete header up to just before the first byte of the deflate stream. The end-of-block will not be indicated until all of the uncompressed data from that block has been written to strm->next_out. The number of unused bits may in general be greater than seven, except when bit 7 of data_type is set, in which case the number of unused bits will be less than eight. data_type is set as noted here every time inflate() returns for all flush options, and so can be used to determine the amount of currently consumed input in bits. The Z_TREES option behaves as Z_BLOCK does, but it also returns when the end of each deflate block header is reached, before any actual data in that block is decoded. This allows the caller to determine the length of the deflate block header for later use in random access within a deflate block. 256 is added to the value of strm->data_type when inflate() returns immediately after reaching the end of the deflate block header. inflate() should normally be called until it returns Z_STREAM_END or an error. However if all decompression is to be performed in a single step (a single call of inflate), the parameter flush should be set to Z_FINISH. In this case all pending input is processed and all pending output is flushed; avail_out must be large enough to hold all the uncompressed data. (The size of the uncompressed data may have been saved by the compressor for this purpose.) The next operation on this stream must be inflateEnd to deallocate the decompression state. The use of Z_FINISH is never required, but can be used to inform inflate that a faster approach may be used for the single inflate() call. In this implementation, inflate() always flushes as much output as possible to the output buffer, and always uses the faster approach on the first call. So the only effect of the flush parameter in this implementation is on the return value of inflate(), as noted below, or when it returns early because Z_BLOCK or Z_TREES is used. If a preset dictionary is needed after this call (see inflateSetDictionary below), inflate sets strm->adler to the adler32 checksum of the dictionary chosen by the compressor and returns Z_NEED_DICT; otherwise it sets strm->adler to the adler32 checksum of all output produced so far (that is, total_out bytes) and returns Z_OK, Z_STREAM_END or an error code as described below. At the end of the stream, inflate() checks that its computed adler32 checksum is equal to that saved by the compressor and returns Z_STREAM_END only if the checksum is correct. inflate() can decompress and check either zlib-wrapped or gzip-wrapped deflate data. The header type is detected automatically, if requested when initializing with inflateInit2(). Any information contained in the gzip header is not retained, so applications that need that information should instead use raw inflate, see inflateInit2() below, or inflateBack() and perform their own processing of the gzip header and trailer. inflate() returns Z_OK if some progress has been made (more input processed or more output produced), Z_STREAM_END if the end of the compressed data has been reached and all uncompressed output has been produced, Z_NEED_DICT if a preset dictionary is needed at this point, Z_DATA_ERROR if the input data was corrupted (input stream not conforming to the zlib format or incorrect check value), Z_STREAM_ERROR if the stream structure was inconsistent (for example next_in or next_out was Z_NULL), Z_MEM_ERROR if there was not enough memory, Z_BUF_ERROR if no progress is possible or if there was not enough room in the output buffer when Z_FINISH is used. Note that Z_BUF_ERROR is not fatal, and inflate() can be called again with more input and more output space to continue decompressing. If Z_DATA_ERROR is returned, the application may then call inflateSync() to look for a good compression block if a partial recovery of the data is desired. */ ZEXTERN int ZEXPORT inflateEnd OF((z_streamp strm)); /* All dynamically allocated data structures for this stream are freed. This function discards any unprocessed input and does not flush any pending output. inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state was inconsistent. In the error case, msg may be set but then points to a static string (which must not be deallocated). */ /* Advanced functions */ /* The following functions are needed only in some special applications. */ /* ZEXTERN int ZEXPORT deflateInit2 OF((z_streamp strm, int level, int method, int windowBits, int memLevel, int strategy)); This is another version of deflateInit with more compression options. The fields next_in, zalloc, zfree and opaque must be initialized before by the caller. The method parameter is the compression method. It must be Z_DEFLATED in this version of the library. The windowBits parameter is the base two logarithm of the window size (the size of the history buffer). It should be in the range 8..15 for this version of the library. Larger values of this parameter result in better compression at the expense of memory usage. The default value is 15 if deflateInit is used instead. windowBits can also be -8..-15 for raw deflate. In this case, -windowBits determines the window size. deflate() will then generate raw deflate data with no zlib header or trailer, and will not compute an adler32 check value. windowBits can also be greater than 15 for optional gzip encoding. Add 16 to windowBits to write a simple gzip header and trailer around the compressed data instead of a zlib wrapper. The gzip header will have no file name, no extra data, no comment, no modification time (set to zero), no header crc, and the operating system will be set to 255 (unknown). If a gzip stream is being written, strm->adler is a crc32 instead of an adler32. The memLevel parameter specifies how much memory should be allocated for the internal compression state. memLevel=1 uses minimum memory but is slow and reduces compression ratio; memLevel=9 uses maximum memory for optimal speed. The default value is 8. See zconf.h for total memory usage as a function of windowBits and memLevel. The strategy parameter is used to tune the compression algorithm. Use the value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a filter (or predictor), Z_HUFFMAN_ONLY to force Huffman encoding only (no string match), or Z_RLE to limit match distances to one (run-length encoding). Filtered data consists mostly of small values with a somewhat random distribution. In this case, the compression algorithm is tuned to compress them better. The effect of Z_FILTERED is to force more Huffman coding and less string matching; it is somewhat intermediate between Z_DEFAULT_STRATEGY and Z_HUFFMAN_ONLY. Z_RLE is designed to be almost as fast as Z_HUFFMAN_ONLY, but give better compression for PNG image data. The strategy parameter only affects the compression ratio but not the correctness of the compressed output even if it is not set appropriately. Z_FIXED prevents the use of dynamic Huffman codes, allowing for a simpler decoder for special applications. deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_STREAM_ERROR if any parameter is invalid (such as an invalid method), or Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible with the version assumed by the caller (ZLIB_VERSION). msg is set to null if there is no error message. deflateInit2 does not perform any compression: this will be done by deflate(). */ ZEXTERN int ZEXPORT deflateSetDictionary OF((z_streamp strm, const Bytef *dictionary, uInt dictLength)); /* Initializes the compression dictionary from the given byte sequence without producing any compressed output. This function must be called immediately after deflateInit, deflateInit2 or deflateReset, before any call of deflate. The compressor and decompressor must use exactly the same dictionary (see inflateSetDictionary). The dictionary should consist of strings (byte sequences) that are likely to be encountered later in the data to be compressed, with the most commonly used strings preferably put towards the end of the dictionary. Using a dictionary is most useful when the data to be compressed is short and can be predicted with good accuracy; the data can then be compressed better than with the default empty dictionary. Depending on the size of the compression data structures selected by deflateInit or deflateInit2, a part of the dictionary may in effect be discarded, for example if the dictionary is larger than the window size provided in deflateInit or deflateInit2. Thus the strings most likely to be useful should be put at the end of the dictionary, not at the front. In addition, the current implementation of deflate will use at most the window size minus 262 bytes of the provided dictionary. Upon return of this function, strm->adler is set to the adler32 value of the dictionary; the decompressor may later use this value to determine which dictionary has been used by the compressor. (The adler32 value applies to the whole dictionary even if only a subset of the dictionary is actually used by the compressor.) If a raw deflate was requested, then the adler32 value is not computed and strm->adler is not set. deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a parameter is invalid (e.g. dictionary being Z_NULL) or the stream state is inconsistent (for example if deflate has already been called for this stream or if the compression method is bsort). deflateSetDictionary does not perform any compression: this will be done by deflate(). */ ZEXTERN int ZEXPORT deflateCopy OF((z_streamp dest, z_streamp source)); /* Sets the destination stream as a complete copy of the source stream. This function can be useful when several compression strategies will be tried, for example when there are several ways of pre-processing the input data with a filter. The streams that will be discarded should then be freed by calling deflateEnd. Note that deflateCopy duplicates the internal compression state which can be quite large, so this strategy is slow and can consume lots of memory. deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_STREAM_ERROR if the source stream state was inconsistent (such as zalloc being Z_NULL). msg is left unchanged in both source and destination. */ ZEXTERN int ZEXPORT deflateReset OF((z_streamp strm)); /* This function is equivalent to deflateEnd followed by deflateInit, but does not free and reallocate all the internal compression state. The stream will keep the same compression level and any other attributes that may have been set by deflateInit2. deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source stream state was inconsistent (such as zalloc or state being Z_NULL). */ ZEXTERN int ZEXPORT deflateParams OF((z_streamp strm, int level, int strategy)); /* Dynamically update the compression level and compression strategy. The interpretation of level and strategy is as in deflateInit2. This can be used to switch between compression and straight copy of the input data, or to switch to a different kind of input data requiring a different strategy. If the compression level is changed, the input available so far is compressed with the old level (and may be flushed); the new level will take effect only at the next call of deflate(). Before the call of deflateParams, the stream state must be set as for a call of deflate(), since the currently available input may have to be compressed and flushed. In particular, strm->avail_out must be non-zero. deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR if strm->avail_out was zero. */ ZEXTERN int ZEXPORT deflateTune OF((z_streamp strm, int good_length, int max_lazy, int nice_length, int max_chain)); /* Fine tune deflate's internal compression parameters. This should only be used by someone who understands the algorithm used by zlib's deflate for searching for the best matching string, and even then only by the most fanatic optimizer trying to squeeze out the last compressed bit for their specific input data. Read the deflate.c source code for the meaning of the max_lazy, good_length, nice_length, and max_chain parameters. deflateTune() can be called after deflateInit() or deflateInit2(), and returns Z_OK on success, or Z_STREAM_ERROR for an invalid deflate stream. */ ZEXTERN uLong ZEXPORT deflateBound OF((z_streamp strm, uLong sourceLen)); /* deflateBound() returns an upper bound on the compressed size after deflation of sourceLen bytes. It must be called after deflateInit() or deflateInit2(), and after deflateSetHeader(), if used. This would be used to allocate an output buffer for deflation in a single pass, and so would be called before deflate(). */ ZEXTERN int ZEXPORT deflatePrime OF((z_streamp strm, int bits, int value)); /* deflatePrime() inserts bits in the deflate output stream. The intent is that this function is used to start off the deflate output with the bits leftover from a previous deflate stream when appending to it. As such, this function can only be used for raw deflate, and must be used before the first deflate() call after a deflateInit2() or deflateReset(). bits must be less than or equal to 16, and that many of the least significant bits of value will be inserted in the output. deflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source stream state was inconsistent. */ ZEXTERN int ZEXPORT deflateSetHeader OF((z_streamp strm, gz_headerp head)); /* deflateSetHeader() provides gzip header information for when a gzip stream is requested by deflateInit2(). deflateSetHeader() may be called after deflateInit2() or deflateReset() and before the first call of deflate(). The text, time, os, extra field, name, and comment information in the provided gz_header structure are written to the gzip header (xflag is ignored -- the extra flags are set according to the compression level). The caller must assure that, if not Z_NULL, name and comment are terminated with a zero byte, and that if extra is not Z_NULL, that extra_len bytes are available there. If hcrc is true, a gzip header crc is included. Note that the current versions of the command-line version of gzip (up through version 1.3.x) do not support header crc's, and will report that it is a "multi-part gzip file" and give up. If deflateSetHeader is not used, the default gzip header has text false, the time set to zero, and os set to 255, with no extra, name, or comment fields. The gzip header is returned to the default state by deflateReset(). deflateSetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source stream state was inconsistent. */ /* ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm, int windowBits)); This is another version of inflateInit with an extra parameter. The fields next_in, avail_in, zalloc, zfree and opaque must be initialized before by the caller. The windowBits parameter is the base two logarithm of the maximum window size (the size of the history buffer). It should be in the range 8..15 for this version of the library. The default value is 15 if inflateInit is used instead. windowBits must be greater than or equal to the windowBits value provided to deflateInit2() while compressing, or it must be equal to 15 if deflateInit2() was not used. If a compressed stream with a larger window size is given as input, inflate() will return with the error code Z_DATA_ERROR instead of trying to allocate a larger window. windowBits can also be zero to request that inflate use the window size in the zlib header of the compressed stream. windowBits can also be -8..-15 for raw inflate. In this case, -windowBits determines the window size. inflate() will then process raw deflate data, not looking for a zlib or gzip header, not generating a check value, and not looking for any check values for comparison at the end of the stream. This is for use with other formats that use the deflate compressed data format such as zip. Those formats provide their own check values. If a custom format is developed using the raw deflate format for compressed data, it is recommended that a check value such as an adler32 or a crc32 be applied to the uncompressed data as is done in the zlib, gzip, and zip formats. For most applications, the zlib format should be used as is. Note that comments above on the use in deflateInit2() applies to the magnitude of windowBits. windowBits can also be greater than 15 for optional gzip decoding. Add 32 to windowBits to enable zlib and gzip decoding with automatic header detection, or add 16 to decode only the gzip format (the zlib format will return a Z_DATA_ERROR). If a gzip stream is being decoded, strm->adler is a crc32 instead of an adler32. inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_VERSION_ERROR if the zlib library version is incompatible with the version assumed by the caller, or Z_STREAM_ERROR if the parameters are invalid, such as a null pointer to the structure. msg is set to null if there is no error message. inflateInit2 does not perform any decompression apart from possibly reading the zlib header if present: actual decompression will be done by inflate(). (So next_in and avail_in may be modified, but next_out and avail_out are unused and unchanged.) The current implementation of inflateInit2() does not process any header information -- that is deferred until inflate() is called. */ ZEXTERN int ZEXPORT inflateSetDictionary OF((z_streamp strm, const Bytef *dictionary, uInt dictLength)); /* Initializes the decompression dictionary from the given uncompressed byte sequence. This function must be called immediately after a call of inflate, if that call returned Z_NEED_DICT. The dictionary chosen by the compressor can be determined from the adler32 value returned by that call of inflate. The compressor and decompressor must use exactly the same dictionary (see deflateSetDictionary). For raw inflate, this function can be called immediately after inflateInit2() or inflateReset() and before any call of inflate() to set the dictionary. The application must insure that the dictionary that was used for compression is provided. inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a parameter is invalid (e.g. dictionary being Z_NULL) or the stream state is inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the expected one (incorrect adler32 value). inflateSetDictionary does not perform any decompression: this will be done by subsequent calls of inflate(). */ ZEXTERN int ZEXPORT inflateSync OF((z_streamp strm)); /* Skips invalid compressed data until a full flush point (see above the description of deflate with Z_FULL_FLUSH) can be found, or until all available input is skipped. No output is provided. inflateSync returns Z_OK if a full flush point has been found, Z_BUF_ERROR if no more input was provided, Z_DATA_ERROR if no flush point has been found, or Z_STREAM_ERROR if the stream structure was inconsistent. In the success case, the application may save the current current value of total_in which indicates where valid compressed data was found. In the error case, the application may repeatedly call inflateSync, providing more input each time, until success or end of the input data. */ ZEXTERN int ZEXPORT inflateCopy OF((z_streamp dest, z_streamp source)); /* Sets the destination stream as a complete copy of the source stream. This function can be useful when randomly accessing a large stream. The first pass through the stream can periodically record the inflate state, allowing restarting inflate at those points when randomly accessing the stream. inflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_STREAM_ERROR if the source stream state was inconsistent (such as zalloc being Z_NULL). msg is left unchanged in both source and destination. */ ZEXTERN int ZEXPORT inflateReset OF((z_streamp strm)); /* This function is equivalent to inflateEnd followed by inflateInit, but does not free and reallocate all the internal decompression state. The stream will keep attributes that may have been set by inflateInit2. inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source stream state was inconsistent (such as zalloc or state being Z_NULL). */ ZEXTERN int ZEXPORT inflateReset2 OF((z_streamp strm, int windowBits)); /* This function is the same as inflateReset, but it also permits changing the wrap and window size requests. The windowBits parameter is interpreted the same as it is for inflateInit2. inflateReset2 returns Z_OK if success, or Z_STREAM_ERROR if the source stream state was inconsistent (such as zalloc or state being Z_NULL), or if the windowBits parameter is invalid. */ ZEXTERN int ZEXPORT inflatePrime OF((z_streamp strm, int bits, int value)); /* This function inserts bits in the inflate input stream. The intent is that this function is used to start inflating at a bit position in the middle of a byte. The provided bits will be used before any bytes are used from next_in. This function should only be used with raw inflate, and should be used before the first inflate() call after inflateInit2() or inflateReset(). bits must be less than or equal to 16, and that many of the least significant bits of value will be inserted in the input. If bits is negative, then the input stream bit buffer is emptied. Then inflatePrime() can be called again to put bits in the buffer. This is used to clear out bits leftover after feeding inflate a block description prior to feeding inflate codes. inflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source stream state was inconsistent. */ ZEXTERN long ZEXPORT inflateMark OF((z_streamp strm)); /* This function returns two values, one in the lower 16 bits of the return value, and the other in the remaining upper bits, obtained by shifting the return value down 16 bits. If the upper value is -1 and the lower value is zero, then inflate() is currently decoding information outside of a block. If the upper value is -1 and the lower value is non-zero, then inflate is in the middle of a stored block, with the lower value equaling the number of bytes from the input remaining to copy. If the upper value is not -1, then it is the number of bits back from the current bit position in the input of the code (literal or length/distance pair) currently being processed. In that case the lower value is the number of bytes already emitted for that code. A code is being processed if inflate is waiting for more input to complete decoding of the code, or if it has completed decoding but is waiting for more output space to write the literal or match data. inflateMark() is used to mark locations in the input data for random access, which may be at bit positions, and to note those cases where the output of a code may span boundaries of random access blocks. The current location in the input stream can be determined from avail_in and data_type as noted in the description for the Z_BLOCK flush parameter for inflate. inflateMark returns the value noted above or -1 << 16 if the provided source stream state was inconsistent. */ ZEXTERN int ZEXPORT inflateGetHeader OF((z_streamp strm, gz_headerp head)); /* inflateGetHeader() requests that gzip header information be stored in the provided gz_header structure. inflateGetHeader() may be called after inflateInit2() or inflateReset(), and before the first call of inflate(). As inflate() processes the gzip stream, head->done is zero until the header is completed, at which time head->done is set to one. If a zlib stream is being decoded, then head->done is set to -1 to indicate that there will be no gzip header information forthcoming. Note that Z_BLOCK or Z_TREES can be used to force inflate() to return immediately after header processing is complete and before any actual data is decompressed. The text, time, xflags, and os fields are filled in with the gzip header contents. hcrc is set to true if there is a header CRC. (The header CRC was valid if done is set to one.) If extra is not Z_NULL, then extra_max contains the maximum number of bytes to write to extra. Once done is true, extra_len contains the actual extra field length, and extra contains the extra field, or that field truncated if extra_max is less than extra_len. If name is not Z_NULL, then up to name_max characters are written there, terminated with a zero unless the length is greater than name_max. If comment is not Z_NULL, then up to comm_max characters are written there, terminated with a zero unless the length is greater than comm_max. When any of extra, name, or comment are not Z_NULL and the respective field is not present in the header, then that field is set to Z_NULL to signal its absence. This allows the use of deflateSetHeader() with the returned structure to duplicate the header. However if those fields are set to allocated memory, then the application will need to save those pointers elsewhere so that they can be eventually freed. If inflateGetHeader is not used, then the header information is simply discarded. The header is always checked for validity, including the header CRC if present. inflateReset() will reset the process to discard the header information. The application would need to call inflateGetHeader() again to retrieve the header from the next gzip stream. inflateGetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source stream state was inconsistent. */ /* ZEXTERN int ZEXPORT inflateBackInit OF((z_streamp strm, int windowBits, unsigned char FAR *window)); Initialize the internal stream state for decompression using inflateBack() calls. The fields zalloc, zfree and opaque in strm must be initialized before the call. If zalloc and zfree are Z_NULL, then the default library- derived memory allocation routines are used. windowBits is the base two logarithm of the window size, in the range 8..15. window is a caller supplied buffer of that size. Except for special applications where it is assured that deflate was used with small window sizes, windowBits must be 15 and a 32K byte window must be supplied to be able to decompress general deflate streams. See inflateBack() for the usage of these routines. inflateBackInit will return Z_OK on success, Z_STREAM_ERROR if any of the paramaters are invalid, Z_MEM_ERROR if the internal state could not be allocated, or Z_VERSION_ERROR if the version of the library does not match the version of the header file. */ typedef unsigned (*in_func) OF((void FAR *, unsigned char FAR * FAR *)); typedef int (*out_func) OF((void FAR *, unsigned char FAR *, unsigned)); ZEXTERN int ZEXPORT inflateBack OF((z_streamp strm, in_func in, void FAR *in_desc, out_func out, void FAR *out_desc)); /* inflateBack() does a raw inflate with a single call using a call-back interface for input and output. This is more efficient than inflate() for file i/o applications in that it avoids copying between the output and the sliding window by simply making the window itself the output buffer. This function trusts the application to not change the output buffer passed by the output function, at least until inflateBack() returns. inflateBackInit() must be called first to allocate the internal state and to initialize the state with the user-provided window buffer. inflateBack() may then be used multiple times to inflate a complete, raw deflate stream with each call. inflateBackEnd() is then called to free the allocated state. A raw deflate stream is one with no zlib or gzip header or trailer. This routine would normally be used in a utility that reads zip or gzip files and writes out uncompressed files. The utility would decode the header and process the trailer on its own, hence this routine expects only the raw deflate stream to decompress. This is different from the normal behavior of inflate(), which expects either a zlib or gzip header and trailer around the deflate stream. inflateBack() uses two subroutines supplied by the caller that are then called by inflateBack() for input and output. inflateBack() calls those routines until it reads a complete deflate stream and writes out all of the uncompressed data, or until it encounters an error. The function's parameters and return types are defined above in the in_func and out_func typedefs. inflateBack() will call in(in_desc, &buf) which should return the number of bytes of provided input, and a pointer to that input in buf. If there is no input available, in() must return zero--buf is ignored in that case--and inflateBack() will return a buffer error. inflateBack() will call out(out_desc, buf, len) to write the uncompressed data buf[0..len-1]. out() should return zero on success, or non-zero on failure. If out() returns non-zero, inflateBack() will return with an error. Neither in() nor out() are permitted to change the contents of the window provided to inflateBackInit(), which is also the buffer that out() uses to write from. The length written by out() will be at most the window size. Any non-zero amount of input may be provided by in(). For convenience, inflateBack() can be provided input on the first call by setting strm->next_in and strm->avail_in. If that input is exhausted, then in() will be called. Therefore strm->next_in must be initialized before calling inflateBack(). If strm->next_in is Z_NULL, then in() will be called immediately for input. If strm->next_in is not Z_NULL, then strm->avail_in must also be initialized, and then if strm->avail_in is not zero, input will initially be taken from strm->next_in[0 .. strm->avail_in - 1]. The in_desc and out_desc parameters of inflateBack() is passed as the first parameter of in() and out() respectively when they are called. These descriptors can be optionally used to pass any information that the caller- supplied in() and out() functions need to do their job. On return, inflateBack() will set strm->next_in and strm->avail_in to pass back any unused input that was provided by the last in() call. The return values of inflateBack() can be Z_STREAM_END on success, Z_BUF_ERROR if in() or out() returned an error, Z_DATA_ERROR if there was a format error in the deflate stream (in which case strm->msg is set to indicate the nature of the error), or Z_STREAM_ERROR if the stream was not properly initialized. In the case of Z_BUF_ERROR, an input or output error can be distinguished using strm->next_in which will be Z_NULL only if in() returned an error. If strm->next_in is not Z_NULL, then the Z_BUF_ERROR was due to out() returning non-zero. (in() will always be called before out(), so strm->next_in is assured to be defined if out() returns non-zero.) Note that inflateBack() cannot return Z_OK. */ ZEXTERN int ZEXPORT inflateBackEnd OF((z_streamp strm)); /* All memory allocated by inflateBackInit() is freed. inflateBackEnd() returns Z_OK on success, or Z_STREAM_ERROR if the stream state was inconsistent. */ ZEXTERN uLong ZEXPORT zlibCompileFlags OF((void)); /* Return flags indicating compile-time options. Type sizes, two bits each, 00 = 16 bits, 01 = 32, 10 = 64, 11 = other: 1.0: size of uInt 3.2: size of uLong 5.4: size of voidpf (pointer) 7.6: size of z_off_t Compiler, assembler, and debug options: 8: DEBUG 9: ASMV or ASMINF -- use ASM code 10: ZLIB_WINAPI -- exported functions use the WINAPI calling convention 11: 0 (reserved) One-time table building (smaller code, but not thread-safe if true): 12: BUILDFIXED -- build static block decoding tables when needed 13: DYNAMIC_CRC_TABLE -- build CRC calculation tables when needed 14,15: 0 (reserved) Library content (indicates missing functionality): 16: NO_GZCOMPRESS -- gz* functions cannot compress (to avoid linking deflate code when not needed) 17: NO_GZIP -- deflate can't write gzip streams, and inflate can't detect and decode gzip streams (to avoid linking crc code) 18-19: 0 (reserved) Operation variations (changes in library functionality): 20: PKZIP_BUG_WORKAROUND -- slightly more permissive inflate 21: FASTEST -- deflate algorithm with only one, lowest compression level 22,23: 0 (reserved) The sprintf variant used by gzprintf (zero is best): 24: 0 = vs*, 1 = s* -- 1 means limited to 20 arguments after the format 25: 0 = *nprintf, 1 = *printf -- 1 means gzprintf() not secure! 26: 0 = returns value, 1 = void -- 1 means inferred string length returned Remainder: 27-31: 0 (reserved) */ /* utility functions */ /* The following utility functions are implemented on top of the basic stream-oriented functions. To simplify the interface, some default options are assumed (compression level and memory usage, standard memory allocation functions). The source code of these utility functions can be modified if you need special options. */ ZEXTERN int ZEXPORT compress OF((Bytef *dest, uLongf *destLen, const Bytef *source, uLong sourceLen)); /* Compresses the source buffer into the destination buffer. sourceLen is the byte length of the source buffer. Upon entry, destLen is the total size of the destination buffer, which must be at least the value returned by compressBound(sourceLen). Upon exit, destLen is the actual size of the compressed buffer. compress returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_BUF_ERROR if there was not enough room in the output buffer. */ ZEXTERN int ZEXPORT compress2 OF((Bytef *dest, uLongf *destLen, const Bytef *source, uLong sourceLen, int level)); /* Compresses the source buffer into the destination buffer. The level parameter has the same meaning as in deflateInit. sourceLen is the byte length of the source buffer. Upon entry, destLen is the total size of the destination buffer, which must be at least the value returned by compressBound(sourceLen). Upon exit, destLen is the actual size of the compressed buffer. compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_BUF_ERROR if there was not enough room in the output buffer, Z_STREAM_ERROR if the level parameter is invalid. */ ZEXTERN uLong ZEXPORT compressBound OF((uLong sourceLen)); /* compressBound() returns an upper bound on the compressed size after compress() or compress2() on sourceLen bytes. It would be used before a compress() or compress2() call to allocate the destination buffer. */ ZEXTERN int ZEXPORT uncompress OF((Bytef *dest, uLongf *destLen, const Bytef *source, uLong sourceLen)); /* Decompresses the source buffer into the destination buffer. sourceLen is the byte length of the source buffer. Upon entry, destLen is the total size of the destination buffer, which must be large enough to hold the entire uncompressed data. (The size of the uncompressed data must have been saved previously by the compressor and transmitted to the decompressor by some mechanism outside the scope of this compression library.) Upon exit, destLen is the actual size of the uncompressed buffer. uncompress returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_BUF_ERROR if there was not enough room in the output buffer, or Z_DATA_ERROR if the input data was corrupted or incomplete. */ /* gzip file access functions */ /* This library supports reading and writing files in gzip (.gz) format with an interface similar to that of stdio, using the functions that start with "gz". The gzip format is different from the zlib format. gzip is a gzip wrapper, documented in RFC 1952, wrapped around a deflate stream. */ typedef voidp gzFile; /* opaque gzip file descriptor */ /* ZEXTERN gzFile ZEXPORT gzopen OF((const char *path, const char *mode)); Opens a gzip (.gz) file for reading or writing. The mode parameter is as in fopen ("rb" or "wb") but can also include a compression level ("wb9") or a strategy: 'f' for filtered data as in "wb6f", 'h' for Huffman-only compression as in "wb1h", 'R' for run-length encoding as in "wb1R", or 'F' for fixed code compression as in "wb9F". (See the description of deflateInit2 for more information about the strategy parameter.) Also "a" can be used instead of "w" to request that the gzip stream that will be written be appended to the file. "+" will result in an error, since reading and writing to the same gzip file is not supported. gzopen can be used to read a file which is not in gzip format; in this case gzread will directly read from the file without decompression. gzopen returns NULL if the file could not be opened, if there was insufficient memory to allocate the gzFile state, or if an invalid mode was specified (an 'r', 'w', or 'a' was not provided, or '+' was provided). errno can be checked to determine if the reason gzopen failed was that the file could not be opened. */ ZEXTERN gzFile ZEXPORT gzdopen OF((int fd, const char *mode)); /* gzdopen associates a gzFile with the file descriptor fd. File descriptors are obtained from calls like open, dup, creat, pipe or fileno (if the file has been previously opened with fopen). The mode parameter is as in gzopen. The next call of gzclose on the returned gzFile will also close the file descriptor fd, just like fclose(fdopen(fd, mode)) closes the file descriptor fd. If you want to keep fd open, use fd = dup(fd_keep); gz = gzdopen(fd, mode);. The duplicated descriptor should be saved to avoid a leak, since gzdopen does not close fd if it fails. gzdopen returns NULL if there was insufficient memory to allocate the gzFile state, if an invalid mode was specified (an 'r', 'w', or 'a' was not provided, or '+' was provided), or if fd is -1. The file descriptor is not used until the next gz* read, write, seek, or close operation, so gzdopen will not detect if fd is invalid (unless fd is -1). */ ZEXTERN int ZEXPORT gzbuffer OF((gzFile file, unsigned size)); /* Set the internal buffer size used by this library's functions. The default buffer size is 8192 bytes. This function must be called after gzopen() or gzdopen(), and before any other calls that read or write the file. The buffer memory allocation is always deferred to the first read or write. Two buffers are allocated, either both of the specified size when writing, or one of the specified size and the other twice that size when reading. A larger buffer size of, for example, 64K or 128K bytes will noticeably increase the speed of decompression (reading). The new buffer size also affects the maximum length for gzprintf(). gzbuffer() returns 0 on success, or -1 on failure, such as being called too late. */ ZEXTERN int ZEXPORT gzsetparams OF((gzFile file, int level, int strategy)); /* Dynamically update the compression level or strategy. See the description of deflateInit2 for the meaning of these parameters. gzsetparams returns Z_OK if success, or Z_STREAM_ERROR if the file was not opened for writing. */ ZEXTERN int ZEXPORT gzread OF((gzFile file, voidp buf, unsigned len)); /* Reads the given number of uncompressed bytes from the compressed file. If the input file was not in gzip format, gzread copies the given number of bytes into the buffer. After reaching the end of a gzip stream in the input, gzread will continue to read, looking for another gzip stream, or failing that, reading the rest of the input file directly without decompression. The entire input file will be read if gzread is called until it returns less than the requested len. gzread returns the number of uncompressed bytes actually read, less than len for end of file, or -1 for error. */ ZEXTERN int ZEXPORT gzwrite OF((gzFile file, voidpc buf, unsigned len)); /* Writes the given number of uncompressed bytes into the compressed file. gzwrite returns the number of uncompressed bytes written or 0 in case of error. */ ZEXTERN int ZEXPORTVA gzprintf OF((gzFile file, const char *format, ...)); /* Converts, formats, and writes the arguments to the compressed file under control of the format string, as in fprintf. gzprintf returns the number of uncompressed bytes actually written, or 0 in case of error. The number of uncompressed bytes written is limited to 8191, or one less than the buffer size given to gzbuffer(). The caller should assure that this limit is not exceeded. If it is exceeded, then gzprintf() will return an error (0) with nothing written. In this case, there may also be a buffer overflow with unpredictable consequences, which is possible only if zlib was compiled with the insecure functions sprintf() or vsprintf() because the secure snprintf() or vsnprintf() functions were not available. This can be determined using zlibCompileFlags(). */ ZEXTERN int ZEXPORT gzputs OF((gzFile file, const char *s)); /* Writes the given null-terminated string to the compressed file, excluding the terminating null character. gzputs returns the number of characters written, or -1 in case of error. */ ZEXTERN char * ZEXPORT gzgets OF((gzFile file, char *buf, int len)); /* Reads bytes from the compressed file until len-1 characters are read, or a newline character is read and transferred to buf, or an end-of-file condition is encountered. If any characters are read or if len == 1, the string is terminated with a null character. If no characters are read due to an end-of-file or len < 1, then the buffer is left untouched. gzgets returns buf which is a null-terminated string, or it returns NULL for end-of-file or in case of error. If there was an error, the contents at buf are indeterminate. */ ZEXTERN int ZEXPORT gzputc OF((gzFile file, int c)); /* Writes c, converted to an unsigned char, into the compressed file. gzputc returns the value that was written, or -1 in case of error. */ ZEXTERN int ZEXPORT gzgetc OF((gzFile file)); /* Reads one byte from the compressed file. gzgetc returns this byte or -1 in case of end of file or error. */ ZEXTERN int ZEXPORT gzungetc OF((int c, gzFile file)); /* Push one character back onto the stream to be read as the first character on the next read. At least one character of push-back is allowed. gzungetc() returns the character pushed, or -1 on failure. gzungetc() will fail if c is -1, and may fail if a character has been pushed but not read yet. If gzungetc is used immediately after gzopen or gzdopen, at least the output buffer size of pushed characters is allowed. (See gzbuffer above.) The pushed character will be discarded if the stream is repositioned with gzseek() or gzrewind(). */ ZEXTERN int ZEXPORT gzflush OF((gzFile file, int flush)); /* Flushes all pending output into the compressed file. The parameter flush is as in the deflate() function. The return value is the zlib error number (see function gzerror below). gzflush is only permitted when writing. If the flush parameter is Z_FINISH, the remaining data is written and the gzip stream is completed in the output. If gzwrite() is called again, a new gzip stream will be started in the output. gzread() is able to read such concatented gzip streams. gzflush should be called only when strictly necessary because it will degrade compression if called too often. */ /* ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile file, z_off_t offset, int whence)); Sets the starting position for the next gzread or gzwrite on the given compressed file. The offset represents a number of bytes in the uncompressed data stream. The whence parameter is defined as in lseek(2); the value SEEK_END is not supported. If the file is opened for reading, this function is emulated but can be extremely slow. If the file is opened for writing, only forward seeks are supported; gzseek then compresses a sequence of zeroes up to the new starting position. gzseek returns the resulting offset location as measured in bytes from the beginning of the uncompressed stream, or -1 in case of error, in particular if the file is opened for writing and the new starting position would be before the current position. */ ZEXTERN int ZEXPORT gzrewind OF((gzFile file)); /* Rewinds the given file. This function is supported only for reading. gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET) */ /* ZEXTERN z_off_t ZEXPORT gztell OF((gzFile file)); Returns the starting position for the next gzread or gzwrite on the given compressed file. This position represents a number of bytes in the uncompressed data stream, and is zero when starting, even if appending or reading a gzip stream from the middle of a file using gzdopen(). gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR) */ /* ZEXTERN z_off_t ZEXPORT gzoffset OF((gzFile file)); Returns the current offset in the file being read or written. This offset includes the count of bytes that precede the gzip stream, for example when appending or when using gzdopen() for reading. When reading, the offset does not include as yet unused buffered input. This information can be used for a progress indicator. On error, gzoffset() returns -1. */ ZEXTERN int ZEXPORT gzeof OF((gzFile file)); /* Returns true (1) if the end-of-file indicator has been set while reading, false (0) otherwise. Note that the end-of-file indicator is set only if the read tried to go past the end of the input, but came up short. Therefore, just like feof(), gzeof() may return false even if there is no more data to read, in the event that the last read request was for the exact number of bytes remaining in the input file. This will happen if the input file size is an exact multiple of the buffer size. If gzeof() returns true, then the read functions will return no more data, unless the end-of-file indicator is reset by gzclearerr() and the input file has grown since the previous end of file was detected. */ ZEXTERN int ZEXPORT gzdirect OF((gzFile file)); /* Returns true (1) if file is being copied directly while reading, or false (0) if file is a gzip stream being decompressed. This state can change from false to true while reading the input file if the end of a gzip stream is reached, but is followed by data that is not another gzip stream. If the input file is empty, gzdirect() will return true, since the input does not contain a gzip stream. If gzdirect() is used immediately after gzopen() or gzdopen() it will cause buffers to be allocated to allow reading the file to determine if it is a gzip file. Therefore if gzbuffer() is used, it should be called before gzdirect(). */ ZEXTERN int ZEXPORT gzclose OF((gzFile file)); /* Flushes all pending output if necessary, closes the compressed file and deallocates the (de)compression state. Note that once file is closed, you cannot call gzerror with file, since its structures have been deallocated. gzclose must not be called more than once on the same file, just as free must not be called more than once on the same allocation. gzclose will return Z_STREAM_ERROR if file is not valid, Z_ERRNO on a file operation error, or Z_OK on success. */ ZEXTERN int ZEXPORT gzclose_r OF((gzFile file)); ZEXTERN int ZEXPORT gzclose_w OF((gzFile file)); /* Same as gzclose(), but gzclose_r() is only for use when reading, and gzclose_w() is only for use when writing or appending. The advantage to using these instead of gzclose() is that they avoid linking in zlib compression or decompression code that is not used when only reading or only writing respectively. If gzclose() is used, then both compression and decompression code will be included the application when linking to a static zlib library. */ ZEXTERN const char * ZEXPORT gzerror OF((gzFile file, int *errnum)); /* Returns the error message for the last error which occurred on the given compressed file. errnum is set to zlib error number. If an error occurred in the file system and not in the compression library, errnum is set to Z_ERRNO and the application may consult errno to get the exact error code. The application must not modify the returned string. Future calls to this function may invalidate the previously returned string. If file is closed, then the string previously returned by gzerror will no longer be available. gzerror() should be used to distinguish errors from end-of-file for those functions above that do not distinguish those cases in their return values. */ ZEXTERN void ZEXPORT gzclearerr OF((gzFile file)); /* Clears the error and end-of-file flags for file. This is analogous to the clearerr() function in stdio. This is useful for continuing to read a gzip file that is being written concurrently. */ /* checksum functions */ /* These functions are not related to compression but are exported anyway because they might be useful in applications using the compression library. */ ZEXTERN uLong ZEXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len)); /* Update a running Adler-32 checksum with the bytes buf[0..len-1] and return the updated checksum. If buf is Z_NULL, this function returns the required initial value for the checksum. An Adler-32 checksum is almost as reliable as a CRC32 but can be computed much faster. Usage example: uLong adler = adler32(0L, Z_NULL, 0); while (read_buffer(buffer, length) != EOF) { adler = adler32(adler, buffer, length); } if (adler != original_adler) error(); */ /* ZEXTERN uLong ZEXPORT adler32_combine OF((uLong adler1, uLong adler2, z_off_t len2)); Combine two Adler-32 checksums into one. For two sequences of bytes, seq1 and seq2 with lengths len1 and len2, Adler-32 checksums were calculated for each, adler1 and adler2. adler32_combine() returns the Adler-32 checksum of seq1 and seq2 concatenated, requiring only adler1, adler2, and len2. */ ZEXTERN uLong ZEXPORT crc32 OF((uLong crc, const Bytef *buf, uInt len)); /* Update a running CRC-32 with the bytes buf[0..len-1] and return the updated CRC-32. If buf is Z_NULL, this function returns the required initial value for the for the crc. Pre- and post-conditioning (one's complement) is performed within this function so it shouldn't be done by the application. Usage example: uLong crc = crc32(0L, Z_NULL, 0); while (read_buffer(buffer, length) != EOF) { crc = crc32(crc, buffer, length); } if (crc != original_crc) error(); */ /* ZEXTERN uLong ZEXPORT crc32_combine OF((uLong crc1, uLong crc2, z_off_t len2)); Combine two CRC-32 check values into one. For two sequences of bytes, seq1 and seq2 with lengths len1 and len2, CRC-32 check values were calculated for each, crc1 and crc2. crc32_combine() returns the CRC-32 check value of seq1 and seq2 concatenated, requiring only crc1, crc2, and len2. */ /* various hacks, don't look :) */ /* deflateInit and inflateInit are macros to allow checking the zlib version * and the compiler's view of z_stream: */ ZEXTERN int ZEXPORT deflateInit_ OF((z_streamp strm, int level, const char *version, int stream_size)); ZEXTERN int ZEXPORT inflateInit_ OF((z_streamp strm, const char *version, int stream_size)); ZEXTERN int ZEXPORT deflateInit2_ OF((z_streamp strm, int level, int method, int windowBits, int memLevel, int strategy, const char *version, int stream_size)); ZEXTERN int ZEXPORT inflateInit2_ OF((z_streamp strm, int windowBits, const char *version, int stream_size)); ZEXTERN int ZEXPORT inflateBackInit_ OF((z_streamp strm, int windowBits, unsigned char FAR *window, const char *version, int stream_size)); #define deflateInit(strm, level) \ deflateInit_((strm), (level), ZLIB_VERSION, sizeof(z_stream)) #define inflateInit(strm) \ inflateInit_((strm), ZLIB_VERSION, sizeof(z_stream)) #define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \ deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\ (strategy), ZLIB_VERSION, sizeof(z_stream)) #define inflateInit2(strm, windowBits) \ inflateInit2_((strm), (windowBits), ZLIB_VERSION, sizeof(z_stream)) #define inflateBackInit(strm, windowBits, window) \ inflateBackInit_((strm), (windowBits), (window), \ ZLIB_VERSION, sizeof(z_stream)) /* provide 64-bit offset functions if _LARGEFILE64_SOURCE defined, and/or * change the regular functions to 64 bits if _FILE_OFFSET_BITS is 64 (if * both are true, the application gets the *64 functions, and the regular * functions are changed to 64 bits) -- in case these are set on systems * without large file support, _LFS64_LARGEFILE must also be true */ #if defined(_LARGEFILE64_SOURCE) && _LFS64_LARGEFILE-0 ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *)); ZEXTERN z_off64_t ZEXPORT gzseek64 OF((gzFile, z_off64_t, int)); ZEXTERN z_off64_t ZEXPORT gztell64 OF((gzFile)); ZEXTERN z_off64_t ZEXPORT gzoffset64 OF((gzFile)); ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off64_t)); ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off64_t)); #endif #if !defined(ZLIB_INTERNAL) && _FILE_OFFSET_BITS-0 == 64 && _LFS64_LARGEFILE-0 # define gzopen gzopen64 # define gzseek gzseek64 # define gztell gztell64 # define gzoffset gzoffset64 # define adler32_combine adler32_combine64 # define crc32_combine crc32_combine64 # ifdef _LARGEFILE64_SOURCE ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *)); ZEXTERN z_off_t ZEXPORT gzseek64 OF((gzFile, z_off_t, int)); ZEXTERN z_off_t ZEXPORT gztell64 OF((gzFile)); ZEXTERN z_off_t ZEXPORT gzoffset64 OF((gzFile)); ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off_t)); ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off_t)); # endif #else ZEXTERN gzFile ZEXPORT gzopen OF((const char *, const char *)); ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile, z_off_t, int)); ZEXTERN z_off_t ZEXPORT gztell OF((gzFile)); ZEXTERN z_off_t ZEXPORT gzoffset OF((gzFile)); ZEXTERN uLong ZEXPORT adler32_combine OF((uLong, uLong, z_off_t)); ZEXTERN uLong ZEXPORT crc32_combine OF((uLong, uLong, z_off_t)); #endif /* hack for buggy compilers */ #if !defined(ZUTIL_H) && !defined(NO_DUMMY_DECL) struct internal_state {int dummy;}; #endif /* undocumented functions */ ZEXTERN const char * ZEXPORT zError OF((int)); ZEXTERN int ZEXPORT inflateSyncPoint OF((z_streamp)); ZEXTERN const uLongf * ZEXPORT get_crc_table OF((void)); ZEXTERN int ZEXPORT inflateUndermine OF((z_streamp, int)); #ifdef __cplusplus } #endif #endif /* ZLIB_H */ libgit2-0.19.0/deps/zlib/zutil.c000066400000000000000000000162211216214232500163430ustar00rootroot00000000000000/* 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 */ libgit2-0.19.0/deps/zlib/zutil.h000066400000000000000000000157611216214232500163600ustar00rootroot00000000000000/* 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 # endif # include # include #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 # endif # else /* MSC or DJGPP */ # include # 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 # 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 /* 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 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 */ libgit2-0.19.0/docs/000077500000000000000000000000001216214232500140635ustar00rootroot00000000000000libgit2-0.19.0/docs/checkout-internals.md000066400000000000000000000221531216214232500202120ustar00rootroot00000000000000Checkout Internals ================== Checkout has to handle a lot of different cases. It examines the differences between the target tree, the baseline tree and the working directory, plus the contents of the index, and groups files into five categories: 1. UNMODIFIED - Files that match in all places. 2. SAFE - Files where the working directory and the baseline content match that can be safely updated to the target. 3. DIRTY/MISSING - Files where the working directory differs from the baseline but there is no conflicting change with the target. One example is a file that doesn't exist in the working directory - no data would be lost as a result of writing this file. Which action will be taken with these files depends on the options you use. 4. CONFLICTS - Files where changes in the working directory conflict with changes to be applied by the target. If conflicts are found, they prevent any other modifications from being made (although there are options to override that and force the update, of course). 5. UNTRACKED/IGNORED - Files in the working directory that are untracked or ignored (i.e. only in the working directory, not the other places). Right now, this classification is done via 3 iterators (for the three trees), with a final lookup in the index. At some point, this may move to a 4 iterator version to incorporate the index better. The actual checkout is done in five phases (at least right now). 1. The diff between the baseline and the target tree is used as a base list of possible updates to be applied. 2. Iterate through the diff and the working directory, building a list of actions to be taken (and sending notifications about conflicts and dirty files). 3. Remove any files / directories as needed (because alphabetical iteration means that an untracked directory will end up sorted *after* a blob that should be checked out with the same name). 4. Update all blobs. 5. Update all submodules (after 4 in case a new .gitmodules blob was checked out) Checkout could be driven either off a target-to-workdir diff or a baseline-to-target diff. There are pros and cons of each. Target-to-workdir means the diff includes every file that could be modified, which simplifies bookkeeping, but the code to constantly refer back to the baseline gets complicated. Baseline-to-target has simpler code because the diff defines the action to take, but needs special handling for untracked and ignored files, if they need to be removed. The current checkout implementation is based on a baseline-to-target diff. Picking Actions =============== The most interesting aspect of this is phase 2, picking the actions that should be taken. There are a lot of corner cases, so it may be easier to start by looking at the rules for a simple 2-iterator diff: Key --- - B1,B2,B3 - blobs with different SHAs, - Bi - ignored blob (WD only) - T1,T2,T3 - trees with different SHAs, - Ti - ignored tree (WD only) - x - nothing Diff with 2 non-workdir iterators --------------------------------- Old New --- --- 0 x x - nothing 1 x B1 - added blob 2 x T1 - added tree 3 B1 x - removed blob 4 B1 B1 - unmodified blob 5 B1 B2 - modified blob 6 B1 T1 - typechange blob -> tree 7 T1 x - removed tree 8 T1 B1 - typechange tree -> blob 9 T1 T1 - unmodified tree 10 T1 T2 - modified tree (implies modified/added/removed blob inside) Now, let's make the "New" iterator into a working directory iterator, so we replace "added" items with either untracked or ignored, like this: Diff with non-work & workdir iterators -------------------------------------- Old New-WD --- ------ 0 x x - nothing 1 x B1 - untracked blob 2 x Bi - ignored file 3 x T1 - untracked tree 4 x Ti - ignored tree 5 B1 x - removed blob 6 B1 B1 - unmodified blob 7 B1 B2 - modified blob 8 B1 T1 - typechange blob -> tree 9 B1 Ti - removed blob AND ignored tree as separate items 10 T1 x - removed tree 11 T1 B1 - typechange tree -> blob 12 T1 Bi - removed tree AND ignored blob as separate items 13 T1 T1 - unmodified tree 14 T1 T2 - modified tree (implies modified/added/removed blob inside) Note: if there is a corresponding entry in the old tree, then a working directory item won't be ignored (i.e. no Bi or Ti for tracked items). Now, expand this to three iterators: a baseline tree, a target tree, and an actual working directory tree: Checkout From 3 Iterators (2 not workdir, 1 workdir) ---------------------------------------------------- (base == old HEAD; target == what to checkout; actual == working dir) base target actual/workdir ---- ------ ------ 0 x x x - nothing 1 x x B1/Bi/T1/Ti - untracked/ignored blob/tree (SAFE) 2+ x B1 x - add blob (SAFE) 3 x B1 B1 - independently added blob (FORCEABLE-2) 4* x B1 B2/Bi/T1/Ti - add blob with content conflict (FORCEABLE-2) 5+ x T1 x - add tree (SAFE) 6* x T1 B1/Bi - add tree with blob conflict (FORCEABLE-2) 7 x T1 T1/i - independently added tree (SAFE+MISSING) 8 B1 x x - independently deleted blob (SAFE+MISSING) 9- B1 x B1 - delete blob (SAFE) 10- B1 x B2 - delete of modified blob (FORCEABLE-1) 11 B1 x T1/Ti - independently deleted blob AND untrack/ign tree (SAFE+MISSING !!!) 12 B1 B1 x - locally deleted blob (DIRTY || SAFE+CREATE) 13+ B1 B2 x - update to deleted blob (SAFE+MISSING) 14 B1 B1 B1 - unmodified file (SAFE) 15 B1 B1 B2 - locally modified file (DIRTY) 16+ B1 B2 B1 - update unmodified blob (SAFE) 17 B1 B2 B2 - independently updated blob (FORCEABLE-1) 18+ B1 B2 B3 - update to modified blob (FORCEABLE-1) 19 B1 B1 T1/Ti - locally deleted blob AND untrack/ign tree (DIRTY) 20* B1 B2 T1/Ti - update to deleted blob AND untrack/ign tree (F-1) 21+ B1 T1 x - add tree with locally deleted blob (SAFE+MISSING) 22* B1 T1 B1 - add tree AND deleted blob (SAFE) 23* B1 T1 B2 - add tree with delete of modified blob (F-1) 24 B1 T1 T1 - add tree with deleted blob (F-1) 25 T1 x x - independently deleted tree (SAFE+MISSING) 26 T1 x B1/Bi - independently deleted tree AND untrack/ign blob (F-1) 27- T1 x T1 - deleted tree (MAYBE SAFE) 28+ T1 B1 x - deleted tree AND added blob (SAFE+MISSING) 29 T1 B1 B1 - independently typechanged tree -> blob (F-1) 30+ T1 B1 B2 - typechange tree->blob with conflicting blob (F-1) 31* T1 B1 T1/T2 - typechange tree->blob (MAYBE SAFE) 32+ T1 T1 x - restore locally deleted tree (SAFE+MISSING) 33 T1 T1 B1/Bi - locally typechange tree->untrack/ign blob (DIRTY) 34 T1 T1 T1/T2 - unmodified tree (MAYBE SAFE) 35+ T1 T2 x - update locally deleted tree (SAFE+MISSING) 36* T1 T2 B1/Bi - update to tree with typechanged tree->blob conflict (F-1) 37 T1 T2 T1/T2/T3 - update to existing tree (MAYBE SAFE) The number is followed by ' ' if no change is needed or '+' if the case needs to write to disk or '-' if something must be deleted and '*' if there should be a delete followed by an write. There are four tiers of safe cases: - SAFE == completely safe to update - SAFE+MISSING == safe except the workdir is missing the expect content - MAYBE SAFE == safe if workdir tree matches (or is missing) baseline content, which is unknown at this point - FORCEABLE == conflict unless FORCE is given - DIRTY == no conflict but change is not applied unless FORCE Some slightly unusual circumstances: 8 - parent dir is only deleted when file is, so parent will be left if empty even though it would be deleted if the file were present 11 - core git does not consider this a conflict but attempts to delete T1 and gives "unable to unlink file" error yet does not skip the rest of the operation 12 - without FORCE file is left deleted (i.e. not restored) so new wd is dirty (and warning message "D file" is printed), with FORCE, file is restored. 24 - This should be considered MAYBE SAFE since effectively it is 7 and 8 combined, but core git considers this a conflict unless forced. 26 - This combines two cases (1 & 25) (and also implied 8 for tree content) which are ok on their own, but core git treat this as a conflict. If not forced, this is a conflict. If forced, this actually doesn't have to write anything and leaves the new blob as an untracked file. 32 - This is the only case where the baseline and target values match and yet we will still write to the working directory. In all other cases, if baseline == target, we don't touch the workdir (it is either already right or is "dirty"). However, since this case also implies that a ?/B1/x case will exist as well, it can be skipped. Cases 3, 17, 24, 26, and 29 are all considered conflicts even though none of them will require making any updates to the working directory. libgit2-0.19.0/docs/diff-internals.md000066400000000000000000000107161216214232500173170ustar00rootroot00000000000000Diff is broken into four phases: 1. Building a list of things that have changed. These changes are called deltas (git_diff_delta objects) and are grouped into a git_diff_list. 2. Applying file similarity measurement for rename and copy detection (and to potentially split files that have changed radically). This step is optional. 3. Computing the textual diff for each delta. Not all deltas have a meaningful textual diff. For those that do, the textual diff can either be generated on the fly and passed to output callbacks or can be turned into a git_diff_patch object. 4. Formatting the diff and/or patch into standard text formats (such as patches, raw lists, etc). In the source code, step 1 is implemented in `src/diff.c`, step 2 in `src/diff_tform.c`, step 3 in `src/diff_patch.c`, and step 4 in `src/diff_print.c`. Additionally, when it comes to accessing file content, everything goes through diff drivers that are implemented in `src/diff_driver.c`. External Objects ---------------- * `git_diff_options` repesents user choices about how a diff should be performed and is passed to most diff generating functions. * `git_diff_file` represents an item on one side of a possible delta * `git_diff_delta` represents a pair of items that have changed in some way - it contains two `git_diff_file` plus a status and other stuff. * `git_diff_list` is a list of deltas along with information about how those particular deltas were found. * `git_diff_patch` represents the actual diff between a pair of items. In some cases, a delta may not have a corresponding patch, if the objects are binary, for example. The content of a patch will be a set of hunks and lines. * A `hunk` is range of lines described by a `git_diff_range` (i.e. "lines 10-20 in the old file became lines 12-23 in the new"). It will have a header that compactly represents that information, and it will have a number of lines of context surrounding added and deleted lines. * A `line` is simple a line of data along with a `git_diff_line_t` value that tells how the data should be interpretted (e.g. context or added). Internal Objects ---------------- * `git_diff_file_content` is an internal structure that represents the data on one side of an item to be diffed; it is an augmented `git_diff_file` with more flags and the actual file data. ** it is created from a repository plus a) a git_diff_file, b) a git_blob, or c) raw data and size ** there are three main operations on git_diff_file_content: *** _initialization_ sets up the data structure and does what it can up to, but not including loading and looking at the actual data *** _loading_ loads the data, preprocesses it (i.e. applies filters) and potentially analyzes it (to decide if binary) *** _free_ releases loaded data and frees any allocated memory * The internal structure of a `git_diff_patch` stores the actual diff between a pair of `git_diff_file_content` items ** it may be "unset" if the items are not diffable ** "empty" if the items are the same ** otherwise it will consist of a set of hunks each of which covers some number of lines of context, additions and deletions ** a patch is created from two git_diff_file_content items ** a patch is fully instantiated in three phases: *** initial creation and initialization *** loading of data and preliminary data examination *** diffing of data and optional storage of diffs ** (TBD) if a patch is asked to store the diffs and the size of the diff is significantly smaller than the raw data of the two sides, then the patch may be flattened using a pool of string data * `git_diff_output` is an internal structure that represents an output target for a `git_diff_patch` ** It consists of file, hunk, and line callbacks, plus a payload ** There is a standard flattened output that can be used for plain text output ** Typically we use a `git_xdiff_output` which drives the callbacks via the xdiff code taken from core Git. * `git_diff_driver` is an internal structure that encapsulates the logic for a given type of file ** a driver is looked up based on the name and mode of a file. ** the driver can then be used to: *** determine if a file is binary (by attributes, by git_diff_options settings, or by examining the content) *** give you a function pointer that is used to evaluate function context for hunk headers ** At some point, the logic for getting a filtered version of file content or calculating the OID of a file may be moved into the driver. libgit2-0.19.0/docs/error-handling.md000066400000000000000000000135171216214232500173270ustar00rootroot00000000000000Error reporting in libgit2 ========================== Error reporting is performed on an explicit `git_error **` argument, which appears at the end of all API calls that can return an error. Yes, this does clutter the API. When a function fails, an error is set on the error variable **and** returns one of the generic error codes. ~~~c int git_repository_open(git_repository **repository, const char *path, git_error **error) { // perform some opening if (p_exists(path) < 0) { giterr_set(error, GITERR_REPOSITORY, "The path '%s' doesn't exist", path); return GIT_ENOTFOUND; } ... if (try_to_parse(path, error) < 0) return GIT_ERROR; ... } ~~~ The simple error API -------------------- - `void giterr_set(git_error **, int, const char *, ...)`: the main function used to set an error. It allocates a new error object and stores it in the passed error pointer. It has no return value. The arguments for `giterr_set` are as follows: - `git_error **error_ptr`: the pointer where the error will be created. - `int error_class`: the class for the error. This is **not** an error code: this is an specific enum that specifies the error family. The point is to map these families 1-1 with Exception types on higher level languages (e.g. GitRepositoryException) - `const char *error_str, ...`: the error string, with optional formatting arguments - `void giterr_free(git_error *)`: takes an error and frees it. This function is available in the external API. - `void giterr_clear(git_error **)`: clears an error previously set in an error pointer, setting it to NULL and calling `giterr_free` on it. - `void giterr_propagate(git_error **, git_error *)`: moves an error to a given error pointer, handling the case when the error pointer is NULL (in that case the error gets freed, because it cannot be propagated). The new error code return values -------------------------------- We are doing this the POSIX way: one error code for each "expected failure", and a generic error code for all the critical failures. For instance: A reference lookup can have an expected failure (which is when the reference cannot be found), and a critical failure (which could be any of a long list of things that could go wrong, such as the refs packfile being corrupted, a loose ref being written with the wrong permissions, etc). We cannot have distinct error codes for every single error in the library, hence `git_reference_lookup` would return GIT_SUCCESS if the operation was successful, GIT_ENOTFOUND when the reference doesn't exist, and GIT_ERROR when an error happens -- **the error is then detailed in the `git_error` parameter**. Please be smart when returning error codes. Functions have max two "expected errors", and in most cases only one. Writing error messages ---------------------- Here are some guidelines when writing error messages: - Use proper English, and an impersonal or past tenses: *The given path does not exist*, *Failed to lookup object in ODB* - Use short, direct and objective messages. **One line, max**. libgit2 is a low level library: think that all the messages reported will be thrown as Ruby or Python exceptions. Think how long are common exception messages in those languages. - **Do not add redundant information to the error message**, specially information that can be inferred from the context. E.g. in `git_repository_open`, do not report a message like "Failed to open repository: path not found". Somebody is calling that function. If it fails, he already knows that the repository failed to open! General guidelines for error reporting -------------------------------------- - We never handle programming errors with these functions. Programming errors are `assert`ed, and when their source is internal, fixed as soon as possible. This is C, people. Example of programming errors that would **not** be handled: passing NULL to a function that expects a valid pointer; passing a `git_tree` to a function that expects a `git_commit`. All these cases need to be identified with `assert` and fixed asap. Example of a runtime error: failing to parse a `git_tree` because it contains invalid data. Failing to open a file because it doesn't exist on disk. These errors would be handled, and a `git_error` would be set. - The `git_error **` argument is always the last in the signature of all API calls. No exceptions. - When the programmer (or us, internally) doesn't need error handling, he can pass `NULL` to the `git_error **` param. This means that the errors won't be *reported*, but obviously they still will be handled (i.e. the failing function will interrupt and return cleanly). This is transparently handled by `giterr_set` - `git_error *` **must be initialized to `NULL` before passing its value to a function!!** ~~~c git_error *err; git_error *good_error = NULL; git_foo_func(arg1, arg2, &error); // invalid: `error` is not initialized git_foo_func2(arg1, arg2, &good_error); // OK! git_foo_func3(arg1, arg2, NULL); // OK! But no error reporting! ~~~ - Piling up errors is an error! Don't do this! Errors must always be free'd when a function returns. ~~~c git_error *error = NULL; git_foo_func1(arg1, &error); git_foo_func2(arg2, &error); // WRONG! What if func1 failed? `error` would leak! ~~~ - Likewise: do not rethrow errors internally! ~~~c int git_commit_create(..., git_error **error) { if (git_reference_exists("HEAD", error) < 0) { /* HEAD does not exist; create it so we can commit... */ if (git_reference_create("HEAD", error) < 0) { /* error could be rethrown */ } } - Remember that errors are now allocated, and hence they need to be free'd after they've been used. Failure to do so internally (e.g. in the already seen examples of error piling) will be reported by Valgrind, so we can easily find where are we rethrowing errors. - Remember that any function that fails **will set an error object**, and that object will be freed. libgit2-0.19.0/docs/merge-df_conflicts.txt000066400000000000000000000025021216214232500203550ustar00rootroot00000000000000Anc / Our / Thr represent the ancestor / ours / theirs side of a merge from branch "branch" into HEAD. Workdir represents the expected files in the working directory. Index represents the expected files in the index, with stage markers. Anc Our Thr Workdir Index 1 D D D/F D/F D/F [0] 2 D D+ D~HEAD (mod/del) D/F [0] D/F D/F D [1] D [2] 3 D D D/F D/F [0] D/F 4 D D+ D~branch (mod/del) D/F [0] D/F D/F D [1] D [3] 5 D D/F (add/add) D/F [2] D/F D/F [3] D/F 6 D/F D/F D D [0] D 7 D/F D/F+ D/F (mod/del) D/F [1] D D~branch (fil/dir) D/F [2] D [3] 8 D/F D/F D D [0] D 9 D/F D/F+ D/F (mod/del) D/F [1] D D~HEAD (fil/dir) D [2] D/F [3] 10 D/F D/F (fil/dir) D/F [0] D D~HEAD D [2] D libgit2-0.19.0/examples/000077500000000000000000000000001216214232500147515ustar00rootroot00000000000000libgit2-0.19.0/examples/.gitignore000066400000000000000000000000471216214232500167420ustar00rootroot00000000000000general showindex diff rev-list *.dSYM libgit2-0.19.0/examples/Makefile000066400000000000000000000004641216214232500164150ustar00rootroot00000000000000.PHONY: all CC = gcc CFLAGS = -g -I../include -I../src -Wall -Wextra -Wmissing-prototypes -Wno-missing-field-initializers LFLAGS = -L../build -lgit2 -lz APPS = general showindex diff rev-list cat-file status all: $(APPS) % : %.c $(CC) -o $@ $(CFLAGS) $< $(LFLAGS) clean: $(RM) $(APPS) $(RM) -r *.dSYM libgit2-0.19.0/examples/README.md000066400000000000000000000006531216214232500162340ustar00rootroot00000000000000libgit2 examples ================ These examples are meant as thin, easy-to-read snippets for Docurium (https://github.com/github/docurium) rather than full-blown implementations of Git commands. They are not vetted as carefully for bugs, error handling, or cross-platform compatibility as the rest of the code in libgit2, so copy with some caution. For HTML versions, check "Examples" at http://libgit2.github.com/libgit2 libgit2-0.19.0/examples/cat-file.c000066400000000000000000000117661216214232500166140ustar00rootroot00000000000000#include #include #include #include static git_repository *g_repo; static void check(int error, const char *message) { if (error) { fprintf(stderr, "%s (%d)\n", message, error); exit(1); } } static void usage(const char *message, const char *arg) { if (message && arg) fprintf(stderr, "%s: %s\n", message, arg); else if (message) fprintf(stderr, "%s\n", message); fprintf(stderr, "usage: cat-file (-t | -s | -e | -p) [] \n"); exit(1); } static int check_str_param( const char *arg, const char *pattern, const char **val) { size_t len = strlen(pattern); if (strncmp(arg, pattern, len)) return 0; *val = (const char *)(arg + len); return 1; } static void print_signature(const char *header, const git_signature *sig) { char sign; int offset, hours, minutes; if (!sig) return; offset = sig->when.offset; if (offset < 0) { sign = '-'; offset = -offset; } else { sign = '+'; } hours = offset / 60; minutes = offset % 60; printf("%s %s <%s> %ld %c%02d%02d\n", header, sig->name, sig->email, (long)sig->when.time, sign, hours, minutes); } static void show_blob(const git_blob *blob) { /* ? Does this need crlf filtering? */ fwrite(git_blob_rawcontent(blob), git_blob_rawsize(blob), 1, stdout); } static void show_tree(const git_tree *tree) { size_t i, max_i = (int)git_tree_entrycount(tree); char oidstr[GIT_OID_HEXSZ + 1]; const git_tree_entry *te; for (i = 0; i < max_i; ++i) { te = git_tree_entry_byindex(tree, i); git_oid_tostr(oidstr, sizeof(oidstr), git_tree_entry_id(te)); printf("%06o %s %s\t%s\n", git_tree_entry_filemode(te), git_object_type2string(git_tree_entry_type(te)), oidstr, git_tree_entry_name(te)); } } static void show_commit(const git_commit *commit) { unsigned int i, max_i; char oidstr[GIT_OID_HEXSZ + 1]; git_oid_tostr(oidstr, sizeof(oidstr), git_commit_tree_id(commit)); printf("tree %s\n", oidstr); max_i = (unsigned int)git_commit_parentcount(commit); for (i = 0; i < max_i; ++i) { git_oid_tostr(oidstr, sizeof(oidstr), git_commit_parent_id(commit, i)); printf("parent %s\n", oidstr); } print_signature("author", git_commit_author(commit)); print_signature("committer", git_commit_committer(commit)); if (git_commit_message(commit)) printf("\n%s\n", git_commit_message(commit)); } static void show_tag(const git_tag *tag) { char oidstr[GIT_OID_HEXSZ + 1]; git_oid_tostr(oidstr, sizeof(oidstr), git_tag_target_id(tag));; printf("object %s\n", oidstr); printf("type %s\n", git_object_type2string(git_tag_target_type(tag))); printf("tag %s\n", git_tag_name(tag)); print_signature("tagger", git_tag_tagger(tag)); if (git_tag_message(tag)) printf("\n%s\n", git_tag_message(tag)); } enum { SHOW_TYPE = 1, SHOW_SIZE = 2, SHOW_NONE = 3, SHOW_PRETTY = 4 }; int main(int argc, char *argv[]) { const char *dir = ".", *rev = NULL; int i, action = 0, verbose = 0; git_object *obj = NULL; char oidstr[GIT_OID_HEXSZ + 1]; git_threads_init(); for (i = 1; i < argc; ++i) { char *a = argv[i]; if (a[0] != '-') { if (rev != NULL) usage("Only one rev should be provided", NULL); else rev = a; } else if (!strcmp(a, "-t")) action = SHOW_TYPE; else if (!strcmp(a, "-s")) action = SHOW_SIZE; else if (!strcmp(a, "-e")) action = SHOW_NONE; else if (!strcmp(a, "-p")) action = SHOW_PRETTY; else if (!strcmp(a, "-q")) verbose = 0; else if (!strcmp(a, "-v")) verbose = 1; else if (!strcmp(a, "--help") || !strcmp(a, "-h")) usage(NULL, NULL); else if (!check_str_param(a, "--git-dir=", &dir)) usage("Unknown option", a); } if (!action || !rev) usage(NULL, NULL); check(git_repository_open_ext(&g_repo, dir, 0, NULL), "Could not open repository"); if (git_revparse_single(&obj, g_repo, rev) < 0) { fprintf(stderr, "Could not resolve '%s'\n", rev); exit(1); } if (verbose) { char oidstr[GIT_OID_HEXSZ + 1]; git_oid_tostr(oidstr, sizeof(oidstr), git_object_id(obj)); printf("%s %s\n--\n", git_object_type2string(git_object_type(obj)), oidstr); } switch (action) { case SHOW_TYPE: printf("%s\n", git_object_type2string(git_object_type(obj))); break; case SHOW_SIZE: { git_odb *odb; git_odb_object *odbobj; check(git_repository_odb(&odb, g_repo), "Could not open ODB"); check(git_odb_read(&odbobj, odb, git_object_id(obj)), "Could not find obj"); printf("%ld\n", (long)git_odb_object_size(odbobj)); git_odb_object_free(odbobj); git_odb_free(odb); } break; case SHOW_NONE: /* just want return result */ break; case SHOW_PRETTY: switch (git_object_type(obj)) { case GIT_OBJ_BLOB: show_blob((const git_blob *)obj); break; case GIT_OBJ_COMMIT: show_commit((const git_commit *)obj); break; case GIT_OBJ_TREE: show_tree((const git_tree *)obj); break; case GIT_OBJ_TAG: show_tag((const git_tag *)obj); break; default: printf("unknown %s\n", oidstr); break; } break; } git_object_free(obj); git_repository_free(g_repo); git_threads_shutdown(); return 0; } libgit2-0.19.0/examples/diff.c000066400000000000000000000155311216214232500160320ustar00rootroot00000000000000#include #include #include #include static void check(int error, const char *message) { if (error) { fprintf(stderr, "%s (%d)\n", message, error); exit(1); } } static int resolve_to_tree( git_repository *repo, const char *identifier, git_tree **tree) { int err = 0; git_object *obj = NULL; if ((err = git_revparse_single(&obj, repo, identifier)) < 0) return err; switch (git_object_type(obj)) { case GIT_OBJ_TREE: *tree = (git_tree *)obj; break; case GIT_OBJ_COMMIT: err = git_commit_tree(tree, (git_commit *)obj); git_object_free(obj); break; default: err = GIT_ENOTFOUND; } return err; } char *colors[] = { "\033[m", /* reset */ "\033[1m", /* bold */ "\033[31m", /* red */ "\033[32m", /* green */ "\033[36m" /* cyan */ }; static int printer( const git_diff_delta *delta, const git_diff_range *range, char usage, const char *line, size_t line_len, void *data) { int *last_color = data, color = 0; (void)delta; (void)range; (void)line_len; if (*last_color >= 0) { switch (usage) { case GIT_DIFF_LINE_ADDITION: color = 3; break; case GIT_DIFF_LINE_DELETION: color = 2; break; case GIT_DIFF_LINE_ADD_EOFNL: color = 3; break; case GIT_DIFF_LINE_DEL_EOFNL: color = 2; break; case GIT_DIFF_LINE_FILE_HDR: color = 1; break; case GIT_DIFF_LINE_HUNK_HDR: color = 4; break; default: color = 0; } if (color != *last_color) { if (*last_color == 1 || color == 1) fputs(colors[0], stdout); fputs(colors[color], stdout); *last_color = color; } } fputs(line, stdout); return 0; } static int check_uint16_param(const char *arg, const char *pattern, uint16_t *val) { size_t len = strlen(pattern); uint16_t strval; char *endptr = NULL; if (strncmp(arg, pattern, len)) return 0; if (arg[len] == '\0' && pattern[len - 1] != '=') return 1; if (arg[len] == '=') len++; strval = strtoul(arg + len, &endptr, 0); if (endptr == arg) return 0; *val = strval; return 1; } static int check_str_param(const char *arg, const char *pattern, const char **val) { size_t len = strlen(pattern); if (strncmp(arg, pattern, len)) return 0; *val = (const char *)(arg + len); return 1; } static void usage(const char *message, const char *arg) { if (message && arg) fprintf(stderr, "%s: %s\n", message, arg); else if (message) fprintf(stderr, "%s\n", message); fprintf(stderr, "usage: diff [ []]\n"); exit(1); } enum { FORMAT_PATCH = 0, FORMAT_COMPACT = 1, FORMAT_RAW = 2 }; int main(int argc, char *argv[]) { git_repository *repo = NULL; git_tree *t1 = NULL, *t2 = NULL; git_diff_options opts = GIT_DIFF_OPTIONS_INIT; git_diff_find_options findopts = GIT_DIFF_FIND_OPTIONS_INIT; git_diff_list *diff; int i, color = -1, format = FORMAT_PATCH, cached = 0; char *a, *treeish1 = NULL, *treeish2 = NULL; const char *dir = "."; git_threads_init(); /* parse arguments as copied from git-diff */ for (i = 1; i < argc; ++i) { a = argv[i]; if (a[0] != '-') { if (treeish1 == NULL) treeish1 = a; else if (treeish2 == NULL) treeish2 = a; else usage("Only one or two tree identifiers can be provided", NULL); } else if (!strcmp(a, "-p") || !strcmp(a, "-u") || !strcmp(a, "--patch")) format = FORMAT_PATCH; else if (!strcmp(a, "--cached")) cached = 1; else if (!strcmp(a, "--name-status")) format = FORMAT_COMPACT; else if (!strcmp(a, "--raw")) format = FORMAT_RAW; else if (!strcmp(a, "--color")) color = 0; else if (!strcmp(a, "--no-color")) color = -1; else if (!strcmp(a, "-R")) opts.flags |= GIT_DIFF_REVERSE; else if (!strcmp(a, "-a") || !strcmp(a, "--text")) opts.flags |= GIT_DIFF_FORCE_TEXT; else if (!strcmp(a, "--ignore-space-at-eol")) opts.flags |= GIT_DIFF_IGNORE_WHITESPACE_EOL; else if (!strcmp(a, "-b") || !strcmp(a, "--ignore-space-change")) opts.flags |= GIT_DIFF_IGNORE_WHITESPACE_CHANGE; else if (!strcmp(a, "-w") || !strcmp(a, "--ignore-all-space")) opts.flags |= GIT_DIFF_IGNORE_WHITESPACE; else if (!strcmp(a, "--ignored")) opts.flags |= GIT_DIFF_INCLUDE_IGNORED; else if (!strcmp(a, "--untracked")) opts.flags |= GIT_DIFF_INCLUDE_UNTRACKED; else if (check_uint16_param(a, "-M", &findopts.rename_threshold) || check_uint16_param(a, "--find-renames", &findopts.rename_threshold)) findopts.flags |= GIT_DIFF_FIND_RENAMES; else if (check_uint16_param(a, "-C", &findopts.copy_threshold) || check_uint16_param(a, "--find-copies", &findopts.copy_threshold)) findopts.flags |= GIT_DIFF_FIND_COPIES; else if (!strcmp(a, "--find-copies-harder")) findopts.flags |= GIT_DIFF_FIND_COPIES_FROM_UNMODIFIED; else if (!strncmp(a, "-B", 2) || !strncmp(a, "--break-rewrites", 16)) { /* TODO: parse thresholds */ findopts.flags |= GIT_DIFF_FIND_REWRITES; } else if (!check_uint16_param(a, "-U", &opts.context_lines) && !check_uint16_param(a, "--unified=", &opts.context_lines) && !check_uint16_param(a, "--inter-hunk-context=", &opts.interhunk_lines) && !check_str_param(a, "--src-prefix=", &opts.old_prefix) && !check_str_param(a, "--dst-prefix=", &opts.new_prefix) && !check_str_param(a, "--git-dir=", &dir)) usage("Unknown arg", a); } /* open repo */ check(git_repository_open_ext(&repo, dir, 0, NULL), "Could not open repository"); if (treeish1) check(resolve_to_tree(repo, treeish1, &t1), "Looking up first tree"); if (treeish2) check(resolve_to_tree(repo, treeish2, &t2), "Looking up second tree"); /* */ /* --cached */ /* */ /* --cached */ /* nothing */ if (t1 && t2) check(git_diff_tree_to_tree(&diff, repo, t1, t2, &opts), "Diff"); else if (t1 && cached) check(git_diff_tree_to_index(&diff, repo, t1, NULL, &opts), "Diff"); else if (t1) { git_diff_list *diff2; check(git_diff_tree_to_index(&diff, repo, t1, NULL, &opts), "Diff"); check(git_diff_index_to_workdir(&diff2, repo, NULL, &opts), "Diff"); check(git_diff_merge(diff, diff2), "Merge diffs"); git_diff_list_free(diff2); } else if (cached) { check(resolve_to_tree(repo, "HEAD", &t1), "looking up HEAD"); check(git_diff_tree_to_index(&diff, repo, t1, NULL, &opts), "Diff"); } else check(git_diff_index_to_workdir(&diff, repo, NULL, &opts), "Diff"); if ((findopts.flags & GIT_DIFF_FIND_ALL) != 0) check(git_diff_find_similar(diff, &findopts), "finding renames and copies "); if (color >= 0) fputs(colors[0], stdout); switch (format) { case FORMAT_PATCH: check(git_diff_print_patch(diff, printer, &color), "Displaying diff"); break; case FORMAT_COMPACT: check(git_diff_print_compact(diff, printer, &color), "Displaying diff"); break; case FORMAT_RAW: check(git_diff_print_raw(diff, printer, &color), "Displaying diff"); break; } if (color >= 0) fputs(colors[0], stdout); git_diff_list_free(diff); git_tree_free(t1); git_tree_free(t2); git_repository_free(repo); git_threads_shutdown(); return 0; } libgit2-0.19.0/examples/general.c000066400000000000000000000461761216214232500165500ustar00rootroot00000000000000// [**libgit2**][lg] is a portable, pure C implementation of the Git core // methods provided as a re-entrant linkable library with a solid API, // allowing you to write native speed custom Git applications in any // language which supports C bindings. // // This file is an example of using that API in a real, compilable C file. // As the API is updated, this file will be updated to demonstrate the new // functionality. // // If you're trying to write something in C using [libgit2][lg], you should // also check out the generated [API documentation][ap]. We try to link to // the relevant sections of the API docs in each section in this file. // // **libgit2** (for the most part) only implements the core plumbing // functions, not really the higher level porcelain stuff. For a primer on // Git Internals that you will need to know to work with Git at this level, // check out [Chapter 9][pg] of the Pro Git book. // // [lg]: http://libgit2.github.com // [ap]: http://libgit2.github.com/libgit2 // [pg]: http://progit.org/book/ch9-0.html // ### Includes // Including the `git2.h` header will include all the other libgit2 headers // that you need. It should be the only thing you need to include in order // to compile properly and get all the libgit2 API. #include #include // Almost all libgit2 functions return 0 on success or negative on error. // This is not production quality error checking, but should be sufficient // as an example. static void check_error(int error_code, const char *action) { if (!error_code) return; const git_error *error = giterr_last(); printf("Error %d %s - %s\n", error_code, action, (error && error->message) ? error->message : "???"); exit(1); } int main (int argc, char** argv) { // ### Opening the Repository // There are a couple of methods for opening a repository, this being the // simplest. There are also [methods][me] for specifying the index file // and work tree locations, here we assume they are in the normal places. // // (Try running this program against tests-clar/resources/testrepo.git.) // // [me]: http://libgit2.github.com/libgit2/#HEAD/group/repository int error; const char *repo_path = (argc > 1) ? argv[1] : "/opt/libgit2-test/.git"; git_repository *repo; error = git_repository_open(&repo, repo_path); check_error(error, "opening repository"); // ### SHA-1 Value Conversions // For our first example, we will convert a 40 character hex value to the // 20 byte raw SHA1 value. printf("*Hex to Raw*\n"); char hex[] = "4a202b346bb0fb0db7eff3cffeb3c70babbd2045"; // The `git_oid` is the structure that keeps the SHA value. We will use // this throughout the example for storing the value of the current SHA // key we're working with. git_oid oid; git_oid_fromstr(&oid, hex); // Once we've converted the string into the oid value, we can get the raw // value of the SHA by accessing `oid.id` // Next we will convert the 20 byte raw SHA1 value to a human readable 40 // char hex value. printf("\n*Raw to Hex*\n"); char out[41]; out[40] = '\0'; // If you have a oid, you can easily get the hex value of the SHA as well. git_oid_fmt(out, &oid); printf("SHA hex string: %s\n", out); // ### Working with the Object Database // **libgit2** provides [direct access][odb] to the object database. The // object database is where the actual objects are stored in Git. For // working with raw objects, we'll need to get this structure from the // repository. // // [odb]: http://libgit2.github.com/libgit2/#HEAD/group/odb git_odb *odb; git_repository_odb(&odb, repo); // #### Raw Object Reading printf("\n*Raw Object Read*\n"); git_odb_object *obj; git_otype otype; const unsigned char *data; const char *str_type; // We can read raw objects directly from the object database if we have // the oid (SHA) of the object. This allows us to access objects without // knowing thier type and inspect the raw bytes unparsed. error = git_odb_read(&obj, odb, &oid); check_error(error, "finding object in repository"); // A raw object only has three properties - the type (commit, blob, tree // or tag), the size of the raw data and the raw, unparsed data itself. // For a commit or tag, that raw data is human readable plain ASCII // text. For a blob it is just file contents, so it could be text or // binary data. For a tree it is a special binary format, so it's unlikely // to be hugely helpful as a raw object. data = (const unsigned char *)git_odb_object_data(obj); otype = git_odb_object_type(obj); // We provide methods to convert from the object type which is an enum, to // a string representation of that value (and vice-versa). str_type = git_object_type2string(otype); printf("object length and type: %d, %s\n", (int)git_odb_object_size(obj), str_type); // For proper memory management, close the object when you are done with // it or it will leak memory. git_odb_object_free(obj); // #### Raw Object Writing printf("\n*Raw Object Write*\n"); // You can also write raw object data to Git. This is pretty cool because // it gives you direct access to the key/value properties of Git. Here // we'll write a new blob object that just contains a simple string. // Notice that we have to specify the object type as the `git_otype` enum. git_odb_write(&oid, odb, "test data", sizeof("test data") - 1, GIT_OBJ_BLOB); // Now that we've written the object, we can check out what SHA1 was // generated when the object was written to our database. git_oid_fmt(out, &oid); printf("Written Object: %s\n", out); // ### Object Parsing // libgit2 has methods to parse every object type in Git so you don't have // to work directly with the raw data. This is much faster and simpler // than trying to deal with the raw data yourself. // #### Commit Parsing // [Parsing commit objects][pco] is simple and gives you access to all the // data in the commit - the author (name, email, datetime), committer // (same), tree, message, encoding and parent(s). // // [pco]: http://libgit2.github.com/libgit2/#HEAD/group/commit printf("\n*Commit Parsing*\n"); git_commit *commit; git_oid_fromstr(&oid, "8496071c1b46c854b31185ea97743be6a8774479"); error = git_commit_lookup(&commit, repo, &oid); check_error(error, "looking up commit"); const git_signature *author, *cmtter; const char *message; time_t ctime; unsigned int parents, p; // Each of the properties of the commit object are accessible via methods, // including commonly needed variations, such as `git_commit_time` which // returns the author time and `git_commit_message` which gives you the // commit message (as a NUL-terminated string). message = git_commit_message(commit); author = git_commit_author(commit); cmtter = git_commit_committer(commit); ctime = git_commit_time(commit); // The author and committer methods return [git_signature] structures, // which give you name, email and `when`, which is a `git_time` structure, // giving you a timestamp and timezone offset. printf("Author: %s (%s)\n", author->name, author->email); // Commits can have zero or more parents. The first (root) commit will // have no parents, most commits will have one (i.e. the commit it was // based on) and merge commits will have two or more. Commits can // technically have any number, though it's rare to have more than two. parents = git_commit_parentcount(commit); for (p = 0;p < parents;p++) { git_commit *parent; git_commit_parent(&parent, commit, p); git_oid_fmt(out, git_commit_id(parent)); printf("Parent: %s\n", out); git_commit_free(parent); } // Don't forget to close the object to prevent memory leaks. You will have // to do this for all the objects you open and parse. git_commit_free(commit); // #### Writing Commits // libgit2 provides a couple of methods to create commit objects easily as // well. There are four different create signatures, we'll just show one // of them here. You can read about the other ones in the [commit API // docs][cd]. // // [cd]: http://libgit2.github.com/libgit2/#HEAD/group/commit printf("\n*Commit Writing*\n"); git_oid tree_id, parent_id, commit_id; git_tree *tree; git_commit *parent; // Creating signatures for an authoring identity and time is simple. You // will need to do this to specify who created a commit and when. Default // values for the name and email should be found in the `user.name` and // `user.email` configuration options. See the `config` section of this // example file to see how to access config values. git_signature_new((git_signature **)&author, "Scott Chacon", "schacon@gmail.com", 123456789, 60); git_signature_new((git_signature **)&cmtter, "Scott A Chacon", "scott@github.com", 987654321, 90); // Commit objects need a tree to point to and optionally one or more // parents. Here we're creating oid objects to create the commit with, // but you can also use git_oid_fromstr(&tree_id, "f60079018b664e4e79329a7ef9559c8d9e0378d1"); git_tree_lookup(&tree, repo, &tree_id); git_oid_fromstr(&parent_id, "5b5b025afb0b4c913b4c338a42934a3863bf3644"); git_commit_lookup(&parent, repo, &parent_id); // Here we actually create the commit object with a single call with all // the values we need to create the commit. The SHA key is written to the // `commit_id` variable here. git_commit_create_v( &commit_id, /* out id */ repo, NULL, /* do not update the HEAD */ author, cmtter, NULL, /* use default message encoding */ "example commit", tree, 1, parent); // Now we can take a look at the commit SHA we've generated. git_oid_fmt(out, &commit_id); printf("New Commit: %s\n", out); // #### Tag Parsing // You can parse and create tags with the [tag management API][tm], which // functions very similarly to the commit lookup, parsing and creation // methods, since the objects themselves are very similar. // // [tm]: http://libgit2.github.com/libgit2/#HEAD/group/tag printf("\n*Tag Parsing*\n"); git_tag *tag; const char *tmessage, *tname; git_otype ttype; // We create an oid for the tag object if we know the SHA and look it up // the same way that we would a commit (or any other object). git_oid_fromstr(&oid, "b25fa35b38051e4ae45d4222e795f9df2e43f1d1"); error = git_tag_lookup(&tag, repo, &oid); check_error(error, "looking up tag"); // Now that we have the tag object, we can extract the information it // generally contains: the target (usually a commit object), the type of // the target object (usually 'commit'), the name ('v1.0'), the tagger (a // git_signature - name, email, timestamp), and the tag message. git_tag_target((git_object **)&commit, tag); tname = git_tag_name(tag); // "test" ttype = git_tag_target_type(tag); // GIT_OBJ_COMMIT (otype enum) tmessage = git_tag_message(tag); // "tag message\n" printf("Tag Message: %s\n", tmessage); git_commit_free(commit); // #### Tree Parsing // [Tree parsing][tp] is a bit different than the other objects, in that // we have a subtype which is the tree entry. This is not an actual // object type in Git, but a useful structure for parsing and traversing // tree entries. // // [tp]: http://libgit2.github.com/libgit2/#HEAD/group/tree printf("\n*Tree Parsing*\n"); const git_tree_entry *entry; git_object *objt; // Create the oid and lookup the tree object just like the other objects. git_oid_fromstr(&oid, "2a741c18ac5ff082a7caaec6e74db3075a1906b5"); git_tree_lookup(&tree, repo, &oid); // Getting the count of entries in the tree so you can iterate over them // if you want to. size_t cnt = git_tree_entrycount(tree); // 3 printf("tree entries: %d\n", (int)cnt); entry = git_tree_entry_byindex(tree, 0); printf("Entry name: %s\n", git_tree_entry_name(entry)); // "hello.c" // You can also access tree entries by name if you know the name of the // entry you're looking for. entry = git_tree_entry_byname(tree, "README"); git_tree_entry_name(entry); // "hello.c" // Once you have the entry object, you can access the content or subtree // (or commit, in the case of submodules) that it points to. You can also // get the mode if you want. git_tree_entry_to_object(&objt, repo, entry); // blob // Remember to close the looked-up object once you are done using it git_object_free(objt); // #### Blob Parsing // The last object type is the simplest and requires the least parsing // help. Blobs are just file contents and can contain anything, there is // no structure to it. The main advantage to using the [simple blob // api][ba] is that when you're creating blobs you don't have to calculate // the size of the content. There is also a helper for reading a file // from disk and writing it to the db and getting the oid back so you // don't have to do all those steps yourself. // // [ba]: http://libgit2.github.com/libgit2/#HEAD/group/blob printf("\n*Blob Parsing*\n"); git_blob *blob; git_oid_fromstr(&oid, "1385f264afb75a56a5bec74243be9b367ba4ca08"); git_blob_lookup(&blob, repo, &oid); // You can access a buffer with the raw contents of the blob directly. // Note that this buffer may not be contain ASCII data for certain blobs // (e.g. binary files): do not consider the buffer a NULL-terminated // string, and use the `git_blob_rawsize` attribute to find out its exact // size in bytes printf("Blob Size: %ld\n", (long)git_blob_rawsize(blob)); // 8 git_blob_rawcontent(blob); // "content" // ### Revwalking // The libgit2 [revision walking api][rw] provides methods to traverse the // directed graph created by the parent pointers of the commit objects. // Since all commits point back to the commit that came directly before // them, you can walk this parentage as a graph and find all the commits // that were ancestors of (reachable from) a given starting point. This // can allow you to create `git log` type functionality. // // [rw]: http://libgit2.github.com/libgit2/#HEAD/group/revwalk printf("\n*Revwalking*\n"); git_revwalk *walk; git_commit *wcommit; git_oid_fromstr(&oid, "5b5b025afb0b4c913b4c338a42934a3863bf3644"); // To use the revwalker, create a new walker, tell it how you want to sort // the output and then push one or more starting points onto the walker. // If you want to emulate the output of `git log` you would push the SHA // of the commit that HEAD points to into the walker and then start // traversing them. You can also 'hide' commits that you want to stop at // or not see any of their ancestors. So if you want to emulate `git log // branch1..branch2`, you would push the oid of `branch2` and hide the oid // of `branch1`. git_revwalk_new(&walk, repo); git_revwalk_sorting(walk, GIT_SORT_TOPOLOGICAL | GIT_SORT_REVERSE); git_revwalk_push(walk, &oid); const git_signature *cauth; const char *cmsg; // Now that we have the starting point pushed onto the walker, we start // asking for ancestors. It will return them in the sorting order we asked // for as commit oids. We can then lookup and parse the commited pointed // at by the returned OID; note that this operation is specially fast // since the raw contents of the commit object will be cached in memory while ((git_revwalk_next(&oid, walk)) == 0) { error = git_commit_lookup(&wcommit, repo, &oid); check_error(error, "looking up commit during revwalk"); cmsg = git_commit_message(wcommit); cauth = git_commit_author(wcommit); printf("%s (%s)\n", cmsg, cauth->email); git_commit_free(wcommit); } // Like the other objects, be sure to free the revwalker when you're done // to prevent memory leaks. Also, make sure that the repository being // walked it not deallocated while the walk is in progress, or it will // result in undefined behavior git_revwalk_free(walk); // ### Index File Manipulation // The [index file API][gi] allows you to read, traverse, update and write // the Git index file (sometimes thought of as the staging area). // // [gi]: http://libgit2.github.com/libgit2/#HEAD/group/index printf("\n*Index Walking*\n"); git_index *index; unsigned int i, ecount; // You can either open the index from the standard location in an open // repository, as we're doing here, or you can open and manipulate any // index file with `git_index_open_bare()`. The index for the repository // will be located and loaded from disk. git_repository_index(&index, repo); // For each entry in the index, you can get a bunch of information // including the SHA (oid), path and mode which map to the tree objects // that are written out. It also has filesystem properties to help // determine what to inspect for changes (ctime, mtime, dev, ino, uid, // gid, file_size and flags) All these properties are exported publicly in // the `git_index_entry` struct ecount = git_index_entrycount(index); for (i = 0; i < ecount; ++i) { const git_index_entry *e = git_index_get_byindex(index, i); printf("path: %s\n", e->path); printf("mtime: %d\n", (int)e->mtime.seconds); printf("fs: %d\n", (int)e->file_size); } git_index_free(index); // ### References // The [reference API][ref] allows you to list, resolve, create and update // references such as branches, tags and remote references (everything in // the .git/refs directory). // // [ref]: http://libgit2.github.com/libgit2/#HEAD/group/reference printf("\n*Reference Listing*\n"); // Here we will implement something like `git for-each-ref` simply listing // out all available references and the object SHA they resolve to. git_strarray ref_list; git_reference_list(&ref_list, repo); const char *refname; git_reference *ref; // Now that we have the list of reference names, we can lookup each ref // one at a time and resolve them to the SHA, then print both values out. for (i = 0; i < ref_list.count; ++i) { refname = ref_list.strings[i]; git_reference_lookup(&ref, repo, refname); switch (git_reference_type(ref)) { case GIT_REF_OID: git_oid_fmt(out, git_reference_target(ref)); printf("%s [%s]\n", refname, out); break; case GIT_REF_SYMBOLIC: printf("%s => %s\n", refname, git_reference_symbolic_target(ref)); break; default: fprintf(stderr, "Unexpected reference type\n"); exit(1); } } git_strarray_free(&ref_list); // ### Config Files // The [config API][config] allows you to list and updatee config values // in any of the accessible config file locations (system, global, local). // // [config]: http://libgit2.github.com/libgit2/#HEAD/group/config printf("\n*Config Listing*\n"); const char *email; int32_t j; git_config *cfg; // Open a config object so we can read global values from it. char config_path[256]; sprintf(config_path, "%s/config", repo_path); check_error(git_config_open_ondisk(&cfg, config_path), "opening config"); git_config_get_int32(&j, cfg, "help.autocorrect"); printf("Autocorrect: %d\n", j); git_config_get_string(&email, cfg, "user.email"); printf("Email: %s\n", email); // Finally, when you're done with the repository, you can free it as well. git_repository_free(repo); return 0; } libgit2-0.19.0/examples/network/000077500000000000000000000000001216214232500164425ustar00rootroot00000000000000libgit2-0.19.0/examples/network/.gitignore000066400000000000000000000000061216214232500204260ustar00rootroot00000000000000/git2 libgit2-0.19.0/examples/network/Makefile000066400000000000000000000004771216214232500201120ustar00rootroot00000000000000default: all CC = gcc CFLAGS += -g CFLAGS += -I../../include LDFLAGS += -L../../build -L../.. LIBRARIES += -lgit2 -lpthread OBJECTS = \ git2.o \ ls-remote.o \ fetch.o \ clone.o \ index-pack.o all: $(OBJECTS) $(CC) $(CFLAGS) $(LDFLAGS) -o git2 $(OBJECTS) $(LIBRARIES) clean: $(RM) $(OBJECTS) $(RM) git2 libgit2-0.19.0/examples/network/clone.c000066400000000000000000000067301216214232500177140ustar00rootroot00000000000000#include "common.h" #include #include #include #include #include #ifndef _WIN32 # include # include #endif /* Shamelessly borrowed from http://stackoverflow.com/questions/3417837/ * with permission of the original author, Martin Pool. * http://sourcefrog.net/weblog/software/languages/C/unused.html */ #ifdef UNUSED #elif defined(__GNUC__) # define UNUSED(x) UNUSED_ ## x __attribute__((unused)) #elif defined(__LCLINT__) # define UNUSED(x) /*@unused@*/ x #else # define UNUSED(x) x #endif typedef struct progress_data { git_transfer_progress fetch_progress; size_t completed_steps; size_t total_steps; const char *path; } progress_data; static void print_progress(const progress_data *pd) { int network_percent = (100*pd->fetch_progress.received_objects) / pd->fetch_progress.total_objects; int index_percent = (100*pd->fetch_progress.indexed_objects) / pd->fetch_progress.total_objects; int checkout_percent = pd->total_steps > 0 ? (100 * pd->completed_steps) / pd->total_steps : 0.f; int kbytes = pd->fetch_progress.received_bytes / 1024; printf("net %3d%% (%4d kb, %5d/%5d) / idx %3d%% (%5d/%5d) / chk %3d%% (%4" PRIuZ "/%4" PRIuZ ") %s\n", network_percent, kbytes, pd->fetch_progress.received_objects, pd->fetch_progress.total_objects, index_percent, pd->fetch_progress.indexed_objects, pd->fetch_progress.total_objects, checkout_percent, pd->completed_steps, pd->total_steps, pd->path); } static int fetch_progress(const git_transfer_progress *stats, void *payload) { progress_data *pd = (progress_data*)payload; pd->fetch_progress = *stats; print_progress(pd); return 0; } static void checkout_progress(const char *path, size_t cur, size_t tot, void *payload) { progress_data *pd = (progress_data*)payload; pd->completed_steps = cur; pd->total_steps = tot; pd->path = path; print_progress(pd); } static int cred_acquire(git_cred **out, const char * UNUSED(url), const char * UNUSED(username_from_url), unsigned int UNUSED(allowed_types), void * UNUSED(payload)) { char username[128] = {0}; char password[128] = {0}; printf("Username: "); scanf("%s", username); /* Yup. Right there on your terminal. Careful where you copy/paste output. */ printf("Password: "); scanf("%s", password); return git_cred_userpass_plaintext_new(out, username, password); } int do_clone(git_repository *repo, int argc, char **argv) { progress_data pd = {{0}}; git_repository *cloned_repo = NULL; git_clone_options clone_opts = GIT_CLONE_OPTIONS_INIT; git_checkout_opts checkout_opts = GIT_CHECKOUT_OPTS_INIT; const char *url = argv[1]; const char *path = argv[2]; int error; (void)repo; // unused // Validate args if (argc < 3) { printf ("USAGE: %s \n", argv[0]); return -1; } // Set up options checkout_opts.checkout_strategy = GIT_CHECKOUT_SAFE_CREATE; checkout_opts.progress_cb = checkout_progress; checkout_opts.progress_payload = &pd; clone_opts.checkout_opts = checkout_opts; clone_opts.fetch_progress_cb = &fetch_progress; clone_opts.fetch_progress_payload = &pd; clone_opts.cred_acquire_cb = cred_acquire; // Do the clone error = git_clone(&cloned_repo, url, path, &clone_opts); printf("\n"); if (error != 0) { const git_error *err = giterr_last(); if (err) printf("ERROR %d: %s\n", err->klass, err->message); else printf("ERROR %d: no detailed info\n", error); } else if (cloned_repo) git_repository_free(cloned_repo); return error; } libgit2-0.19.0/examples/network/common.h000066400000000000000000000012671216214232500201110ustar00rootroot00000000000000#ifndef __COMMON_H__ #define __COMMON_H__ #include typedef int (*git_cb)(git_repository *, int , char **); int ls_remote(git_repository *repo, int argc, char **argv); int parse_pkt_line(git_repository *repo, int argc, char **argv); int show_remote(git_repository *repo, int argc, char **argv); int fetch(git_repository *repo, int argc, char **argv); int index_pack(git_repository *repo, int argc, char **argv); int do_clone(git_repository *repo, int argc, char **argv); #ifndef PRIuZ /* Define the printf format specifer to use for size_t output */ #if defined(_MSC_VER) || defined(__MINGW32__) # define PRIuZ "Iu" #else # define PRIuZ "zu" #endif #endif #endif /* __COMMON_H__ */ libgit2-0.19.0/examples/network/fetch.c000066400000000000000000000070751216214232500177100ustar00rootroot00000000000000#include "common.h" #include #include #include #include #ifndef _WIN32 # include # include #endif struct dl_data { git_remote *remote; int ret; int finished; }; static void progress_cb(const char *str, int len, void *data) { (void)data; printf("remote: %.*s", len, str); fflush(stdout); /* We don't have the \n to force the flush */ } static void *download(void *ptr) { struct dl_data *data = (struct dl_data *)ptr; // Connect to the remote end specifying that we want to fetch // information from it. if (git_remote_connect(data->remote, GIT_DIRECTION_FETCH) < 0) { data->ret = -1; goto exit; } // Download the packfile and index it. This function updates the // amount of received data and the indexer stats which lets you // inform the user about progress. if (git_remote_download(data->remote, NULL, NULL) < 0) { data->ret = -1; goto exit; } data->ret = 0; exit: data->finished = 1; return &data->ret; } static int update_cb(const char *refname, const git_oid *a, const git_oid *b, void *data) { char a_str[GIT_OID_HEXSZ+1], b_str[GIT_OID_HEXSZ+1]; (void)data; git_oid_fmt(b_str, b); b_str[GIT_OID_HEXSZ] = '\0'; if (git_oid_iszero(a)) { printf("[new] %.20s %s\n", b_str, refname); } else { git_oid_fmt(a_str, a); a_str[GIT_OID_HEXSZ] = '\0'; printf("[updated] %.10s..%.10s %s\n", a_str, b_str, refname); } return 0; } int fetch(git_repository *repo, int argc, char **argv) { git_remote *remote = NULL; const git_transfer_progress *stats; struct dl_data data; git_remote_callbacks callbacks = GIT_REMOTE_CALLBACKS_INIT; #ifndef _WIN32 pthread_t worker; #endif if (argc < 2) { fprintf(stderr, "usage: %s fetch \n", argv[-1]); return EXIT_FAILURE; } // Figure out whether it's a named remote or a URL printf("Fetching %s for repo %p\n", argv[1], repo); if (git_remote_load(&remote, repo, argv[1]) < 0) { if (git_remote_create_inmemory(&remote, repo, NULL, argv[1]) < 0) return -1; } // Set up the callbacks (only update_tips for now) callbacks.update_tips = &update_cb; callbacks.progress = &progress_cb; git_remote_set_callbacks(remote, &callbacks); // Set up the information for the background worker thread data.remote = remote; data.ret = 0; data.finished = 0; stats = git_remote_stats(remote); #ifdef _WIN32 download(&data); #else pthread_create(&worker, NULL, download, &data); // Loop while the worker thread is still running. Here we show processed // and total objects in the pack and the amount of received // data. Most frontends will probably want to show a percentage and // the download rate. do { usleep(10000); if (stats->total_objects > 0) printf("Received %d/%d objects (%d) in %" PRIuZ " bytes\r", stats->received_objects, stats->total_objects, stats->indexed_objects, stats->received_bytes); } while (!data.finished); if (data.ret < 0) goto on_error; pthread_join(worker, NULL); #endif printf("\rReceived %d/%d objects in %zu bytes\n", stats->indexed_objects, stats->total_objects, stats->received_bytes); // Disconnect the underlying connection to prevent from idling. git_remote_disconnect(remote); // Update the references in the remote's namespace to point to the // right commits. This may be needed even if there was no packfile // to download, which can happen e.g. when the branches have been // changed but all the neede objects are available locally. if (git_remote_update_tips(remote) < 0) return -1; git_remote_free(remote); return 0; on_error: git_remote_free(remote); return -1; } libgit2-0.19.0/examples/network/git2.c000066400000000000000000000025231216214232500174550ustar00rootroot00000000000000#include #include #include #include "common.h" // This part is not strictly libgit2-dependent, but you can use this // as a starting point for a git-like tool struct { char *name; git_cb fn; } commands[] = { {"ls-remote", ls_remote}, {"fetch", fetch}, {"clone", do_clone}, {"index-pack", index_pack}, { NULL, NULL} }; static int run_command(git_cb fn, int argc, char **argv) { int error; git_repository *repo; // Before running the actual command, create an instance of the local // repository and pass it to the function. error = git_repository_open(&repo, ".git"); if (error < 0) repo = NULL; // Run the command. If something goes wrong, print the error message to stderr error = fn(repo, argc, argv); if (error < 0) { if (giterr_last() == NULL) fprintf(stderr, "Error without message"); else fprintf(stderr, "Bad news:\n %s\n", giterr_last()->message); } if(repo) git_repository_free(repo); return !!error; } int main(int argc, char **argv) { int i; if (argc < 2) { fprintf(stderr, "usage: %s [repo]\n", argv[0]); exit(EXIT_FAILURE); } git_threads_init(); for (i = 0; commands[i].name != NULL; ++i) { if (!strcmp(argv[1], commands[i].name)) return run_command(commands[i].fn, --argc, ++argv); } fprintf(stderr, "Command not found: %s\n", argv[1]); return 1; } libgit2-0.19.0/examples/network/index-pack.c000066400000000000000000000033301216214232500206300ustar00rootroot00000000000000#include #include #include #include #include #include #include #ifdef _WIN32 # include # include # define open _open # define read _read # define close _close #define ssize_t unsigned int #else # include #endif #include "common.h" // This could be run in the main loop whilst the application waits for // the indexing to finish in a worker thread static int index_cb(const git_transfer_progress *stats, void *data) { (void)data; printf("\rProcessing %d of %d", stats->indexed_objects, stats->total_objects); return 0; } int index_pack(git_repository *repo, int argc, char **argv) { git_indexer_stream *idx; git_transfer_progress stats = {0, 0}; int error; char hash[GIT_OID_HEXSZ + 1] = {0}; int fd; ssize_t read_bytes; char buf[512]; (void)repo; if (argc < 2) { fprintf(stderr, "usage: %s index-pack \n", argv[-1]); return EXIT_FAILURE; } if (git_indexer_stream_new(&idx, ".", NULL, NULL) < 0) { puts("bad idx"); return -1; } if ((fd = open(argv[1], 0)) < 0) { perror("open"); return -1; } do { read_bytes = read(fd, buf, sizeof(buf)); if (read_bytes < 0) break; if ((error = git_indexer_stream_add(idx, buf, read_bytes, &stats)) < 0) goto cleanup; index_cb(&stats, NULL); } while (read_bytes > 0); if (read_bytes < 0) { error = -1; perror("failed reading"); goto cleanup; } if ((error = git_indexer_stream_finalize(idx, &stats)) < 0) goto cleanup; printf("\rIndexing %d of %d\n", stats.indexed_objects, stats.total_objects); git_oid_fmt(hash, git_indexer_stream_hash(idx)); puts(hash); cleanup: close(fd); git_indexer_stream_free(idx); return error; } libgit2-0.19.0/examples/network/ls-remote.c000066400000000000000000000034711216214232500205220ustar00rootroot00000000000000#include #include #include #include #include "common.h" static int show_ref__cb(git_remote_head *head, void *payload) { char oid[GIT_OID_HEXSZ + 1] = {0}; (void)payload; git_oid_fmt(oid, &head->oid); printf("%s\t%s\n", oid, head->name); return 0; } static int use_unnamed(git_repository *repo, const char *url) { git_remote *remote = NULL; int error; // Create an instance of a remote from the URL. The transport to use // is detected from the URL error = git_remote_create_inmemory(&remote, repo, NULL, url); if (error < 0) goto cleanup; // When connecting, the underlying code needs to know wether we // want to push or fetch error = git_remote_connect(remote, GIT_DIRECTION_FETCH); if (error < 0) goto cleanup; // With git_remote_ls we can retrieve the advertised heads error = git_remote_ls(remote, &show_ref__cb, NULL); cleanup: git_remote_free(remote); return error; } static int use_remote(git_repository *repo, char *name) { git_remote *remote = NULL; int error; // Find the remote by name error = git_remote_load(&remote, repo, name); if (error < 0) goto cleanup; error = git_remote_connect(remote, GIT_DIRECTION_FETCH); if (error < 0) goto cleanup; error = git_remote_ls(remote, &show_ref__cb, NULL); cleanup: git_remote_free(remote); return error; } // This gets called to do the work. The remote can be given either as // the name of a configured remote or an URL. int ls_remote(git_repository *repo, int argc, char **argv) { int error; if (argc < 2) { fprintf(stderr, "usage: %s ls-remote \n", argv[-1]); return EXIT_FAILURE; } /* If there's a ':' in the name, assume it's an URL */ if (strchr(argv[1], ':') != NULL) { error = use_unnamed(repo, argv[1]); } else { error = use_remote(repo, argv[1]); } return error; } libgit2-0.19.0/examples/rev-list.c000066400000000000000000000055741216214232500166750ustar00rootroot00000000000000#include #include #include static void check_error(int error_code, const char *action) { if (!error_code) return; const git_error *error = giterr_last(); fprintf(stderr, "Error %d %s: %s\n", -error_code, action, (error && error->message) ? error->message : "???"); exit(1); } static int push_commit(git_revwalk *walk, const git_oid *oid, int hide) { if (hide) return git_revwalk_hide(walk, oid); else return git_revwalk_push(walk, oid); } static int push_spec(git_repository *repo, git_revwalk *walk, const char *spec, int hide) { int error; git_object *obj; if ((error = git_revparse_single(&obj, repo, spec)) < 0) return error; error = push_commit(walk, git_object_id(obj), hide); git_object_free(obj); return error; } static int push_range(git_repository *repo, git_revwalk *walk, const char *range, int hide) { git_revspec revspec; int error = 0; if ((error = git_revparse(&revspec, repo, range))) return error; if (revspec.flags & GIT_REVPARSE_MERGE_BASE) { /* TODO: support "..." */ return GIT_EINVALIDSPEC; } if ((error = push_commit(walk, git_object_id(revspec.from), !hide))) goto out; error = push_commit(walk, git_object_id(revspec.to), hide); out: git_object_free(revspec.from); git_object_free(revspec.to); return error; } static int revwalk_parseopts(git_repository *repo, git_revwalk *walk, int nopts, char **opts) { int hide, i, error; unsigned int sorting = GIT_SORT_NONE; hide = 0; for (i = 0; i < nopts; i++) { if (!strcmp(opts[i], "--topo-order")) { sorting = GIT_SORT_TOPOLOGICAL | (sorting & GIT_SORT_REVERSE); git_revwalk_sorting(walk, sorting); } else if (!strcmp(opts[i], "--date-order")) { sorting = GIT_SORT_TIME | (sorting & GIT_SORT_REVERSE); git_revwalk_sorting(walk, sorting); } else if (!strcmp(opts[i], "--reverse")) { sorting = (sorting & ~GIT_SORT_REVERSE) | ((sorting & GIT_SORT_REVERSE) ? 0 : GIT_SORT_REVERSE); git_revwalk_sorting(walk, sorting); } else if (!strcmp(opts[i], "--not")) { hide = !hide; } else if (opts[i][0] == '^') { if ((error = push_spec(repo, walk, opts[i] + 1, !hide))) return error; } else if (strstr(opts[i], "..")) { if ((error = push_range(repo, walk, opts[i], hide))) return error; } else { if ((error = push_spec(repo, walk, opts[i], hide))) return error; } } return 0; } int main (int argc, char **argv) { int error; git_repository *repo; git_revwalk *walk; git_oid oid; char buf[41]; error = git_repository_open_ext(&repo, ".", 0, NULL); check_error(error, "opening repository"); error = git_revwalk_new(&walk, repo); check_error(error, "allocating revwalk"); error = revwalk_parseopts(repo, walk, argc-1, argv+1); check_error(error, "parsing options"); while (!git_revwalk_next(&oid, walk)) { git_oid_fmt(buf, &oid); buf[40] = '\0'; printf("%s\n", buf); } return 0; } libgit2-0.19.0/examples/showindex.c000066400000000000000000000030641216214232500171300ustar00rootroot00000000000000#include #include #include int main (int argc, char** argv) { git_repository *repo = NULL; git_index *index; unsigned int i, ecount; char *dir = "."; size_t dirlen; char out[41]; out[40] = '\0'; if (argc > 1) dir = argv[1]; if (!dir || argc > 2) { fprintf(stderr, "usage: showindex []\n"); return 1; } dirlen = strlen(dir); if (dirlen > 5 && strcmp(dir + dirlen - 5, "index") == 0) { if (git_index_open(&index, dir) < 0) { fprintf(stderr, "could not open index: %s\n", dir); return 1; } } else { if (git_repository_open_ext(&repo, dir, 0, NULL) < 0) { fprintf(stderr, "could not open repository: %s\n", dir); return 1; } if (git_repository_index(&index, repo) < 0) { fprintf(stderr, "could not open repository index\n"); return 1; } } git_index_read(index); ecount = git_index_entrycount(index); if (!ecount) printf("Empty index\n"); for (i = 0; i < ecount; ++i) { const git_index_entry *e = git_index_get_byindex(index, i); git_oid_fmt(out, &e->oid); printf("File Path: %s\n", e->path); printf(" Stage: %d\n", git_index_entry_stage(e)); printf(" Blob SHA: %s\n", out); printf("File Mode: %07o\n", e->mode); printf("File Size: %d bytes\n", (int)e->file_size); printf("Dev/Inode: %d/%d\n", (int)e->dev, (int)e->ino); printf(" UID/GID: %d/%d\n", (int)e->uid, (int)e->gid); printf(" ctime: %d\n", (int)e->ctime.seconds); printf(" mtime: %d\n", (int)e->mtime.seconds); printf("\n"); } git_index_free(index); git_repository_free(repo); return 0; } libgit2-0.19.0/examples/status.c000066400000000000000000000267531216214232500164550ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #include #include #include #include enum { FORMAT_DEFAULT = 0, FORMAT_LONG = 1, FORMAT_SHORT = 2, FORMAT_PORCELAIN = 3, }; #define MAX_PATHSPEC 8 /* * This example demonstrates the use of the libgit2 status APIs, * particularly the `git_status_list` object, to roughly simulate the * output of running `git status`. It serves as a simple example of * using those APIs to get basic status information. * * This does not have: * - Robust error handling * - Colorized or paginated output formatting * * This does have: * - Examples of translating command line arguments to the status * options settings to mimic `git status` results. * - A sample status formatter that matches the default "long" format * from `git status` * - A sample status formatter that matches the "short" format */ static void check(int error, const char *message, const char *extra) { const git_error *lg2err; const char *lg2msg = "", *lg2spacer = ""; if (!error) return; if ((lg2err = giterr_last()) != NULL && lg2err->message != NULL) { lg2msg = lg2err->message; lg2spacer = " - "; } if (extra) fprintf(stderr, "%s '%s' [%d]%s%s\n", message, extra, error, lg2spacer, lg2msg); else fprintf(stderr, "%s [%d]%s%s\n", message, error, lg2spacer, lg2msg); exit(1); } static void fail(const char *message) { check(-1, message, NULL); } static void show_branch(git_repository *repo, int format) { int error = 0; const char *branch = NULL; git_reference *head = NULL; error = git_repository_head(&head, repo); if (error == GIT_EORPHANEDHEAD || error == GIT_ENOTFOUND) branch = NULL; else if (!error) { branch = git_reference_name(head); if (!strncmp(branch, "refs/heads/", strlen("refs/heads/"))) branch += strlen("refs/heads/"); } else check(error, "failed to get current branch", NULL); if (format == FORMAT_LONG) printf("# On branch %s\n", branch ? branch : "Not currently on any branch."); else printf("## %s\n", branch ? branch : "HEAD (no branch)"); git_reference_free(head); } static void print_long(git_repository *repo, git_status_list *status) { size_t i, maxi = git_status_list_entrycount(status); const git_status_entry *s; int header = 0, changes_in_index = 0; int changed_in_workdir = 0, rm_in_workdir = 0; const char *old_path, *new_path; (void)repo; /* print index changes */ for (i = 0; i < maxi; ++i) { char *istatus = NULL; s = git_status_byindex(status, i); if (s->status == GIT_STATUS_CURRENT) continue; if (s->status & GIT_STATUS_WT_DELETED) rm_in_workdir = 1; if (s->status & GIT_STATUS_INDEX_NEW) istatus = "new file: "; if (s->status & GIT_STATUS_INDEX_MODIFIED) istatus = "modified: "; if (s->status & GIT_STATUS_INDEX_DELETED) istatus = "deleted: "; if (s->status & GIT_STATUS_INDEX_RENAMED) istatus = "renamed: "; if (s->status & GIT_STATUS_INDEX_TYPECHANGE) istatus = "typechange:"; if (istatus == NULL) continue; if (!header) { printf("# Changes to be committed:\n"); printf("# (use \"git reset HEAD ...\" to unstage)\n"); printf("#\n"); header = 1; } old_path = s->head_to_index->old_file.path; new_path = s->head_to_index->new_file.path; if (old_path && new_path && strcmp(old_path, new_path)) printf("#\t%s %s -> %s\n", istatus, old_path, new_path); else printf("#\t%s %s\n", istatus, old_path ? old_path : new_path); } if (header) { changes_in_index = 1; printf("#\n"); } header = 0; /* print workdir changes to tracked files */ for (i = 0; i < maxi; ++i) { char *wstatus = NULL; s = git_status_byindex(status, i); if (s->status == GIT_STATUS_CURRENT || s->index_to_workdir == NULL) continue; if (s->status & GIT_STATUS_WT_MODIFIED) wstatus = "modified: "; if (s->status & GIT_STATUS_WT_DELETED) wstatus = "deleted: "; if (s->status & GIT_STATUS_WT_RENAMED) wstatus = "renamed: "; if (s->status & GIT_STATUS_WT_TYPECHANGE) wstatus = "typechange:"; if (wstatus == NULL) continue; if (!header) { printf("# Changes not staged for commit:\n"); printf("# (use \"git add%s ...\" to update what will be committed)\n", rm_in_workdir ? "/rm" : ""); printf("# (use \"git checkout -- ...\" to discard changes in working directory)\n"); printf("#\n"); header = 1; } old_path = s->index_to_workdir->old_file.path; new_path = s->index_to_workdir->new_file.path; if (old_path && new_path && strcmp(old_path, new_path)) printf("#\t%s %s -> %s\n", wstatus, old_path, new_path); else printf("#\t%s %s\n", wstatus, old_path ? old_path : new_path); } if (header) { changed_in_workdir = 1; printf("#\n"); } header = 0; /* print untracked files */ header = 0; for (i = 0; i < maxi; ++i) { s = git_status_byindex(status, i); if (s->status == GIT_STATUS_WT_NEW) { if (!header) { printf("# Untracked files:\n"); printf("# (use \"git add ...\" to include in what will be committed)\n"); printf("#\n"); header = 1; } printf("#\t%s\n", s->index_to_workdir->old_file.path); } } header = 0; /* print ignored files */ for (i = 0; i < maxi; ++i) { s = git_status_byindex(status, i); if (s->status == GIT_STATUS_IGNORED) { if (!header) { printf("# Ignored files:\n"); printf("# (use \"git add -f ...\" to include in what will be committed)\n"); printf("#\n"); header = 1; } printf("#\t%s\n", s->index_to_workdir->old_file.path); } } if (!changes_in_index && changed_in_workdir) printf("no changes added to commit (use \"git add\" and/or \"git commit -a\")\n"); } static void print_short(git_repository *repo, git_status_list *status) { size_t i, maxi = git_status_list_entrycount(status); const git_status_entry *s; char istatus, wstatus; const char *extra, *a, *b, *c; for (i = 0; i < maxi; ++i) { s = git_status_byindex(status, i); if (s->status == GIT_STATUS_CURRENT) continue; a = b = c = NULL; istatus = wstatus = ' '; extra = ""; if (s->status & GIT_STATUS_INDEX_NEW) istatus = 'A'; if (s->status & GIT_STATUS_INDEX_MODIFIED) istatus = 'M'; if (s->status & GIT_STATUS_INDEX_DELETED) istatus = 'D'; if (s->status & GIT_STATUS_INDEX_RENAMED) istatus = 'R'; if (s->status & GIT_STATUS_INDEX_TYPECHANGE) istatus = 'T'; if (s->status & GIT_STATUS_WT_NEW) { if (istatus == ' ') istatus = '?'; wstatus = '?'; } if (s->status & GIT_STATUS_WT_MODIFIED) wstatus = 'M'; if (s->status & GIT_STATUS_WT_DELETED) wstatus = 'D'; if (s->status & GIT_STATUS_WT_RENAMED) wstatus = 'R'; if (s->status & GIT_STATUS_WT_TYPECHANGE) wstatus = 'T'; if (s->status & GIT_STATUS_IGNORED) { istatus = '!'; wstatus = '!'; } if (istatus == '?' && wstatus == '?') continue; if (s->index_to_workdir && s->index_to_workdir->new_file.mode == GIT_FILEMODE_COMMIT) { git_submodule *sm = NULL; unsigned int smstatus = 0; if (!git_submodule_lookup( &sm, repo, s->index_to_workdir->new_file.path) && !git_submodule_status(&smstatus, sm)) { if (smstatus & GIT_SUBMODULE_STATUS_WD_MODIFIED) extra = " (new commits)"; else if (smstatus & GIT_SUBMODULE_STATUS_WD_INDEX_MODIFIED) extra = " (modified content)"; else if (smstatus & GIT_SUBMODULE_STATUS_WD_WD_MODIFIED) extra = " (modified content)"; else if (smstatus & GIT_SUBMODULE_STATUS_WD_UNTRACKED) extra = " (untracked content)"; } } if (s->head_to_index) { a = s->head_to_index->old_file.path; b = s->head_to_index->new_file.path; } if (s->index_to_workdir) { if (!a) a = s->index_to_workdir->old_file.path; if (!b) b = s->index_to_workdir->old_file.path; c = s->index_to_workdir->new_file.path; } if (istatus == 'R') { if (wstatus == 'R') printf("%c%c %s %s %s%s\n", istatus, wstatus, a, b, c, extra); else printf("%c%c %s %s%s\n", istatus, wstatus, a, b, extra); } else { if (wstatus == 'R') printf("%c%c %s %s%s\n", istatus, wstatus, a, c, extra); else printf("%c%c %s%s\n", istatus, wstatus, a, extra); } } for (i = 0; i < maxi; ++i) { s = git_status_byindex(status, i); if (s->status == GIT_STATUS_WT_NEW) printf("?? %s\n", s->index_to_workdir->old_file.path); } } int main(int argc, char *argv[]) { git_repository *repo = NULL; int i, npaths = 0, format = FORMAT_DEFAULT, zterm = 0, showbranch = 0; git_status_options opt = GIT_STATUS_OPTIONS_INIT; git_status_list *status; char *repodir = ".", *pathspec[MAX_PATHSPEC]; opt.show = GIT_STATUS_SHOW_INDEX_AND_WORKDIR; opt.flags = GIT_STATUS_OPT_INCLUDE_UNTRACKED | GIT_STATUS_OPT_RENAMES_HEAD_TO_INDEX | GIT_STATUS_OPT_SORT_CASE_SENSITIVELY; for (i = 1; i < argc; ++i) { if (argv[i][0] != '-') { if (npaths < MAX_PATHSPEC) pathspec[npaths++] = argv[i]; else fail("Example only supports a limited pathspec"); } else if (!strcmp(argv[i], "-s") || !strcmp(argv[i], "--short")) format = FORMAT_SHORT; else if (!strcmp(argv[i], "--long")) format = FORMAT_LONG; else if (!strcmp(argv[i], "--porcelain")) format = FORMAT_PORCELAIN; else if (!strcmp(argv[i], "-b") || !strcmp(argv[i], "--branch")) showbranch = 1; else if (!strcmp(argv[i], "-z")) { zterm = 1; if (format == FORMAT_DEFAULT) format = FORMAT_PORCELAIN; } else if (!strcmp(argv[i], "--ignored")) opt.flags |= GIT_STATUS_OPT_INCLUDE_IGNORED; else if (!strcmp(argv[i], "-uno") || !strcmp(argv[i], "--untracked-files=no")) opt.flags &= ~GIT_STATUS_OPT_INCLUDE_UNTRACKED; else if (!strcmp(argv[i], "-unormal") || !strcmp(argv[i], "--untracked-files=normal")) opt.flags |= GIT_STATUS_OPT_INCLUDE_UNTRACKED; else if (!strcmp(argv[i], "-uall") || !strcmp(argv[i], "--untracked-files=all")) opt.flags |= GIT_STATUS_OPT_INCLUDE_UNTRACKED | GIT_STATUS_OPT_RECURSE_UNTRACKED_DIRS; else if (!strcmp(argv[i], "--ignore-submodules=all")) opt.flags |= GIT_STATUS_OPT_EXCLUDE_SUBMODULES; else if (!strncmp(argv[i], "--git-dir=", strlen("--git-dir="))) repodir = argv[i] + strlen("--git-dir="); else check(-1, "Unsupported option", argv[i]); } if (format == FORMAT_DEFAULT) format = FORMAT_LONG; if (format == FORMAT_LONG) showbranch = 1; if (npaths > 0) { opt.pathspec.strings = pathspec; opt.pathspec.count = npaths; } /* * Try to open the repository at the given path (or at the current * directory if none was given). */ check(git_repository_open_ext(&repo, repodir, 0, NULL), "Could not open repository", repodir); if (git_repository_is_bare(repo)) fail("Cannot report status on bare repository"); /* * Run status on the repository * * Because we want to simluate a full "git status" run and want to * support some command line options, we use `git_status_foreach_ext()` * instead of just the plain status call. This allows (a) iterating * over the index and then the workdir and (b) extra flags that control * which files are included. If you just want simple status (e.g. to * enumerate files that are modified) then you probably don't need the * extended API. */ check(git_status_list_new(&status, repo, &opt), "Could not get status", NULL); if (showbranch) show_branch(repo, format); if (format == FORMAT_LONG) print_long(repo, status); else print_short(repo, status); git_status_list_free(status); git_repository_free(repo); return 0; } libgit2-0.19.0/examples/test/000077500000000000000000000000001216214232500157305ustar00rootroot00000000000000libgit2-0.19.0/examples/test/test-rev-list.sh000077500000000000000000000057151216214232500210210ustar00rootroot00000000000000#!/bin/bash THIS_FILE="$(readlink -f "$0")" ROOT="$(dirname "$(dirname "$(dirname "$THIS_FILE")")")" PROGRAM="$ROOT"/examples/rev-list LIBDIR="$ROOT"/build REPO="$ROOT"/tests-clar/resources/testrepo.git cd "$REPO" run () { LD_LIBRARY_PATH="$LIBDIR" "$PROGRAM" "$@" } diff -u - <(run --date-order a4a7dce) </dev/null || a4a7dce85cf63874e984719f4fdd239f5145052f c47800c7266a2be04c571c04d5a6614691ea99bd 9fd738e8f7967c078dceed8190330fc8648ee56a 4a202b346bb0fb0db7eff3cffeb3c70babbd2045 5b5b025afb0b4c913b4c338a42934a3863bf3644 8496071c1b46c854b31185ea97743be6a8774479 EOF diff -u - <(echo "$out") </dev/null || 8496071c1b46c854b31185ea97743be6a8774479 5b5b025afb0b4c913b4c338a42934a3863bf3644 4a202b346bb0fb0db7eff3cffeb3c70babbd2045 9fd738e8f7967c078dceed8190330fc8648ee56a c47800c7266a2be04c571c04d5a6614691ea99bd a4a7dce85cf63874e984719f4fdd239f5145052f EOF diff -u - <(echo "$out") </dev/null || a4a7dce85cf63874e984719f4fdd239f5145052f c47800c7266a2be04c571c04d5a6614691ea99bd 9fd738e8f7967c078dceed8190330fc8648ee56a 4a202b346bb0fb0db7eff3cffeb3c70babbd2045 5b5b025afb0b4c913b4c338a42934a3863bf3644 8496071c1b46c854b31185ea97743be6a8774479 EOF diff -u - <(echo "$out") <"Author""" # # "ok" means the author consents to relicensing all their # contributed code (possibly with some exceptions) # "no" means the author does not consent # "ask" means that the contributor wants to give/withhold # his/her consent on a patch-by-patch basis. # "???" means the person is a prominent contributor who has # not yet made his/her standpoint clear. # "ign" means the authors consent is ignored for the purpose # of libification. This is because the author has contributed # to areas that aren't interesting for the library. # # Please try to keep the list alphabetically ordered. It will # help in case we get all 600-ish git.git authors on it. # # (Paul Kocher is the author of the mozilla-sha1 implementation # but has otherwise not contributed to git.) # ok Adam Simpkins (http transport) ok Andreas Ericsson ok Boyd Lynn Gerber ok Brian Downing ok Brian Gernhardt ok Christian Couder ok Daniel Barkalow ok Florian Forster ok Holger Weiss ok Jeff King ok Johannes Schindelin ok Johannes Sixt ok Junio C Hamano ok Kristian Høgsberg ok Linus Torvalds ok Lukas Sandström ok Matthieu Moy ign Mike McCormack (imap-send) ok Nicolas Pitre ok Paolo Bonzini ok Paul Kocher ok Peter Hagervall ok Pierre Habouzit ok Pieter de Bie ok René Scharfe ign Robert Shearman (imap-send) ok Sebastian Schuberth ok Shawn O. Pearce ok Steffen Prohaska ok Sven Verdoolaege libgit2-0.19.0/include/000077500000000000000000000000001216214232500145565ustar00rootroot00000000000000libgit2-0.19.0/include/git2.h000066400000000000000000000024261216214232500156000ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #ifndef INCLUDE_git_git_h__ #define INCLUDE_git_git_h__ #include "git2/version.h" #include "git2/common.h" #include "git2/threads.h" #include "git2/errors.h" #include "git2/types.h" #include "git2/oid.h" #include "git2/signature.h" #include "git2/odb.h" #include "git2/repository.h" #include "git2/revwalk.h" #include "git2/merge.h" #include "git2/graph.h" #include "git2/refs.h" #include "git2/reflog.h" #include "git2/revparse.h" #include "git2/object.h" #include "git2/blob.h" #include "git2/commit.h" #include "git2/tag.h" #include "git2/tree.h" #include "git2/diff.h" #include "git2/index.h" #include "git2/config.h" #include "git2/transport.h" #include "git2/remote.h" #include "git2/clone.h" #include "git2/checkout.h" #include "git2/push.h" #include "git2/attr.h" #include "git2/ignore.h" #include "git2/branch.h" #include "git2/refspec.h" #include "git2/net.h" #include "git2/status.h" #include "git2/indexer.h" #include "git2/submodule.h" #include "git2/notes.h" #include "git2/reset.h" #include "git2/message.h" #include "git2/pack.h" #include "git2/stash.h" #endif libgit2-0.19.0/include/git2/000077500000000000000000000000001216214232500154235ustar00rootroot00000000000000libgit2-0.19.0/include/git2/attr.h000066400000000000000000000202621216214232500165500ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #ifndef INCLUDE_git_attr_h__ #define INCLUDE_git_attr_h__ #include "common.h" #include "types.h" /** * @file git2/attr.h * @brief Git attribute management routines * @defgroup git_attr Git attribute management routines * @ingroup Git * @{ */ GIT_BEGIN_DECL /** * GIT_ATTR_TRUE checks if an attribute is set on. In core git * parlance, this the value for "Set" attributes. * * For example, if the attribute file contains: * * *.c foo * * Then for file `xyz.c` looking up attribute "foo" gives a value for * which `GIT_ATTR_TRUE(value)` is true. */ #define GIT_ATTR_TRUE(attr) (git_attr_value(attr) == GIT_ATTR_TRUE_T) /** * GIT_ATTR_FALSE checks if an attribute is set off. In core git * parlance, this is the value for attributes that are "Unset" (not to * be confused with values that a "Unspecified"). * * For example, if the attribute file contains: * * *.h -foo * * Then for file `zyx.h` looking up attribute "foo" gives a value for * which `GIT_ATTR_FALSE(value)` is true. */ #define GIT_ATTR_FALSE(attr) (git_attr_value(attr) == GIT_ATTR_FALSE_T) /** * GIT_ATTR_UNSPECIFIED checks if an attribute is unspecified. This * may be due to the attribute not being mentioned at all or because * the attribute was explicitly set unspecified via the `!` operator. * * For example, if the attribute file contains: * * *.c foo * *.h -foo * onefile.c !foo * * Then for `onefile.c` looking up attribute "foo" yields a value with * `GIT_ATTR_UNSPECIFIED(value)` of true. Also, looking up "foo" on * file `onefile.rb` or looking up "bar" on any file will all give * `GIT_ATTR_UNSPECIFIED(value)` of true. */ #define GIT_ATTR_UNSPECIFIED(attr) (git_attr_value(attr) == GIT_ATTR_UNSPECIFIED_T) /** * GIT_ATTR_HAS_VALUE checks if an attribute is set to a value (as * opposed to TRUE, FALSE or UNSPECIFIED). This would be the case if * for a file with something like: * * *.txt eol=lf * * Given this, looking up "eol" for `onefile.txt` will give back the * string "lf" and `GIT_ATTR_SET_TO_VALUE(attr)` will return true. */ #define GIT_ATTR_HAS_VALUE(attr) (git_attr_value(attr) == GIT_ATTR_VALUE_T) typedef enum { GIT_ATTR_UNSPECIFIED_T = 0, GIT_ATTR_TRUE_T, GIT_ATTR_FALSE_T, GIT_ATTR_VALUE_T, } git_attr_t; /* * Return the value type for a given attribute. * * This can be either `TRUE`, `FALSE`, `UNSPECIFIED` (if the attribute * was not set at all), or `VALUE`, if the attribute was set to * an actual string. * * If the attribute has a `VALUE` string, it can be accessed normally * as a NULL-terminated C string. * * @param attr The attribute * @return the value type for the attribute */ GIT_EXTERN(git_attr_t) git_attr_value(const char *attr); /** * Check attribute flags: Reading values from index and working directory. * * When checking attributes, it is possible to check attribute files * in both the working directory (if there is one) and the index (if * there is one). You can explicitly choose where to check and in * which order using the following flags. * * Core git usually checks the working directory then the index, * except during a checkout when it checks the index first. It will * use index only for creating archives or for a bare repo (if an * index has been specified for the bare repo). */ #define GIT_ATTR_CHECK_FILE_THEN_INDEX 0 #define GIT_ATTR_CHECK_INDEX_THEN_FILE 1 #define GIT_ATTR_CHECK_INDEX_ONLY 2 /** * Check attribute flags: Using the system attributes file. * * Normally, attribute checks include looking in the /etc (or system * equivalent) directory for a `gitattributes` file. Passing this * flag will cause attribute checks to ignore that file. */ #define GIT_ATTR_CHECK_NO_SYSTEM (1 << 2) /** * Look up the value of one git attribute for path. * * @param value_out Output of the value of the attribute. Use the GIT_ATTR_... * macros to test for TRUE, FALSE, UNSPECIFIED, etc. or just * use the string value for attributes set to a value. You * should NOT modify or free this value. * @param repo The repository containing the path. * @param flags A combination of GIT_ATTR_CHECK... flags. * @param path The path to check for attributes. Relative paths are * interpreted relative to the repo root. The file does * not have to exist, but if it does not, then it will be * treated as a plain file (not a directory). * @param name The name of the attribute to look up. */ GIT_EXTERN(int) git_attr_get( const char **value_out, git_repository *repo, uint32_t flags, const char *path, const char *name); /** * Look up a list of git attributes for path. * * Use this if you have a known list of attributes that you want to * look up in a single call. This is somewhat more efficient than * calling `git_attr_get()` multiple times. * * For example, you might write: * * const char *attrs[] = { "crlf", "diff", "foo" }; * const char **values[3]; * git_attr_get_many(values, repo, 0, "my/fun/file.c", 3, attrs); * * Then you could loop through the 3 values to get the settings for * the three attributes you asked about. * * @param values_out An array of num_attr entries that will have string * pointers written into it for the values of the attributes. * You should not modify or free the values that are written * into this array (although of course, you should free the * array itself if you allocated it). * @param repo The repository containing the path. * @param flags A combination of GIT_ATTR_CHECK... flags. * @param path The path inside the repo to check attributes. This * does not have to exist, but if it does not, then * it will be treated as a plain file (i.e. not a directory). * @param num_attr The number of attributes being looked up * @param names An array of num_attr strings containing attribute names. */ GIT_EXTERN(int) git_attr_get_many( const char **values_out, git_repository *repo, uint32_t flags, const char *path, size_t num_attr, const char **names); typedef int (*git_attr_foreach_cb)(const char *name, const char *value, void *payload); /** * Loop over all the git attributes for a path. * * @param repo The repository containing the path. * @param flags A combination of GIT_ATTR_CHECK... flags. * @param path Path inside the repo to check attributes. This does not have * to exist, but if it does not, then it will be treated as a * plain file (i.e. not a directory). * @param callback Function to invoke on each attribute name and value. The * value may be NULL is the attribute is explicitly set to * UNSPECIFIED using the '!' sign. Callback will be invoked * only once per attribute name, even if there are multiple * rules for a given file. The highest priority rule will be * used. Return a non-zero value from this to stop looping. * @param payload Passed on as extra parameter to callback function. * @return 0 on success, GIT_EUSER on non-zero callback, or error code */ GIT_EXTERN(int) git_attr_foreach( git_repository *repo, uint32_t flags, const char *path, git_attr_foreach_cb callback, void *payload); /** * Flush the gitattributes cache. * * Call this if you have reason to believe that the attributes files on * disk no longer match the cached contents of memory. This will cause * the attributes files to be reloaded the next time that an attribute * access function is called. */ GIT_EXTERN(void) git_attr_cache_flush( git_repository *repo); /** * Add a macro definition. * * Macros will automatically be loaded from the top level `.gitattributes` * file of the repository (plus the build-in "binary" macro). This * function allows you to add others. For example, to add the default * macro, you would call: * * git_attr_add_macro(repo, "binary", "-diff -crlf"); */ GIT_EXTERN(int) git_attr_add_macro( git_repository *repo, const char *name, const char *values); /** @} */ GIT_END_DECL #endif libgit2-0.19.0/include/git2/blob.h000066400000000000000000000134051216214232500165150ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #ifndef INCLUDE_git_blob_h__ #define INCLUDE_git_blob_h__ #include "common.h" #include "types.h" #include "oid.h" #include "object.h" /** * @file git2/blob.h * @brief Git blob load and write routines * @defgroup git_blob Git blob load and write routines * @ingroup Git * @{ */ GIT_BEGIN_DECL /** * Lookup a blob object from a repository. * * @param blob pointer to the looked up blob * @param repo the repo to use when locating the blob. * @param id identity of the blob to locate. * @return 0 or an error code */ GIT_EXTERN(int) git_blob_lookup(git_blob **blob, git_repository *repo, const git_oid *id); /** * Lookup a blob object from a repository, * given a prefix of its identifier (short id). * * @see git_object_lookup_prefix * * @param blob pointer to the looked up blob * @param repo the repo to use when locating the blob. * @param id identity of the blob to locate. * @param len the length of the short identifier * @return 0 or an error code */ GIT_EXTERN(int) git_blob_lookup_prefix(git_blob **blob, git_repository *repo, const git_oid *id, size_t len); /** * Close an open blob * * This is a wrapper around git_object_free() * * IMPORTANT: * It *is* necessary to call this method when you stop * using a blob. Failure to do so will cause a memory leak. * * @param blob the blob to close */ GIT_EXTERN(void) git_blob_free(git_blob *blob); /** * Get the id of a blob. * * @param blob a previously loaded blob. * @return SHA1 hash for this blob. */ GIT_EXTERN(const git_oid *) git_blob_id(const git_blob *blob); /** * Get the repository that contains the blob. * * @param blob A previously loaded blob. * @return Repository that contains this blob. */ GIT_EXTERN(git_repository *) git_blob_owner(const git_blob *blob); /** * Get a read-only buffer with the raw content of a blob. * * A pointer to the raw content of a blob is returned; * this pointer is owned internally by the object and shall * not be free'd. The pointer may be invalidated at a later * time. * * @param blob pointer to the blob * @return the pointer; NULL if the blob has no contents */ GIT_EXTERN(const void *) git_blob_rawcontent(const git_blob *blob); /** * Get the size in bytes of the contents of a blob * * @param blob pointer to the blob * @return size on bytes */ GIT_EXTERN(git_off_t) git_blob_rawsize(const git_blob *blob); /** * Read a file from the working folder of a repository * and write it to the Object Database as a loose blob * * @param id return the id of the written blob * @param repo repository where the blob will be written. * this repository cannot be bare * @param relative_path file from which the blob will be created, * relative to the repository's working dir * @return 0 or an error code */ GIT_EXTERN(int) git_blob_create_fromworkdir(git_oid *id, git_repository *repo, const char *relative_path); /** * Read a file from the filesystem and write its content * to the Object Database as a loose blob * * @param id return the id of the written blob * @param repo repository where the blob will be written. * this repository can be bare or not * @param path file from which the blob will be created * @return 0 or an error code */ GIT_EXTERN(int) git_blob_create_fromdisk(git_oid *id, git_repository *repo, const char *path); typedef int (*git_blob_chunk_cb)(char *content, size_t max_length, void *payload); /** * Write a loose blob to the Object Database from a * provider of chunks of data. * * Provided the `hintpath` parameter is filled, its value * will help to determine what git filters should be applied * to the object before it can be placed to the object database. * * * The implementation of the callback has to respect the * following rules: * * - `content` will have to be filled by the consumer. The maximum number * of bytes that the buffer can accept per call is defined by the * `max_length` parameter. Allocation and freeing of the buffer will be taken * care of by the function. * * - The callback is expected to return the number of bytes * that `content` have been filled with. * * - When there is no more data to stream, the callback should * return 0. This will prevent it from being invoked anymore. * * - When an error occurs, the callback should return -1. * * * @param id Return the id of the written blob * * @param repo repository where the blob will be written. * This repository can be bare or not. * * @param hintpath if not NULL, will help selecting the filters * to apply onto the content of the blob to be created. * * @return 0 or an error code */ GIT_EXTERN(int) git_blob_create_fromchunks( git_oid *id, git_repository *repo, const char *hintpath, git_blob_chunk_cb callback, void *payload); /** * Write an in-memory buffer to the ODB as a blob * * @param oid return the oid of the written blob * @param repo repository where to blob will be written * @param buffer data to be written into the blob * @param len length of the data * @return 0 or an error code */ GIT_EXTERN(int) git_blob_create_frombuffer(git_oid *oid, git_repository *repo, const void *buffer, size_t len); /** * Determine if the blob content is most certainly binary or not. * * The heuristic used to guess if a file is binary is taken from core git: * Searching for NUL bytes and looking for a reasonable ratio of printable * to non-printable characters among the first 4000 bytes. * * @param blob The blob which content should be analyzed * @return 1 if the content of the blob is detected * as binary; 0 otherwise. */ GIT_EXTERN(int) git_blob_is_binary(git_blob *blob); /** @} */ GIT_END_DECL #endif libgit2-0.19.0/include/git2/branch.h000066400000000000000000000167071216214232500170440ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #ifndef INCLUDE_git_branch_h__ #define INCLUDE_git_branch_h__ #include "common.h" #include "oid.h" #include "types.h" /** * @file git2/branch.h * @brief Git branch parsing routines * @defgroup git_branch Git branch management * @ingroup Git * @{ */ GIT_BEGIN_DECL /** * Create a new branch pointing at a target commit * * A new direct reference will be created pointing to * this target commit. If `force` is true and a reference * already exists with the given name, it'll be replaced. * * The returned reference must be freed by the user. * * The branch name will be checked for validity. * See `git_tag_create()` for rules about valid names. * * @param out Pointer where to store the underlying reference. * * @param branch_name Name for the branch; this name is * validated for consistency. It should also not conflict with * an already existing branch name. * * @param target Commit to which this branch should point. This object * must belong to the given `repo`. * * @param force Overwrite existing branch. * * @return 0, GIT_EINVALIDSPEC or an error code. * A proper reference is written in the refs/heads namespace * pointing to the provided target commit. */ GIT_EXTERN(int) git_branch_create( git_reference **out, git_repository *repo, const char *branch_name, const git_commit *target, int force); /** * Delete an existing branch reference. * * If the branch is successfully deleted, the passed reference * object will be invalidated. The reference must be freed manually * by the user. * * @param branch A valid reference representing a branch * @return 0 on success, or an error code. */ GIT_EXTERN(int) git_branch_delete(git_reference *branch); typedef int (*git_branch_foreach_cb)( const char *branch_name, git_branch_t branch_type, void *payload); /** * Loop over all the branches and issue a callback for each one. * * If the callback returns a non-zero value, this will stop looping. * * @param repo Repository where to find the branches. * * @param list_flags Filtering flags for the branch * listing. Valid values are GIT_BRANCH_LOCAL, GIT_BRANCH_REMOTE * or a combination of the two. * * @param branch_cb Callback to invoke per found branch. * * @param payload Extra parameter to callback function. * * @return 0 on success, GIT_EUSER on non-zero callback, or error code */ GIT_EXTERN(int) git_branch_foreach( git_repository *repo, unsigned int list_flags, git_branch_foreach_cb branch_cb, void *payload); /** * Move/rename an existing local branch reference. * * The new branch name will be checked for validity. * See `git_tag_create()` for rules about valid names. * * @param branch Current underlying reference of the branch. * * @param new_branch_name Target name of the branch once the move * is performed; this name is validated for consistency. * * @param force Overwrite existing branch. * * @return 0 on success, GIT_EINVALIDSPEC or an error code. */ GIT_EXTERN(int) git_branch_move( git_reference **out, git_reference *branch, const char *new_branch_name, int force); /** * Lookup a branch by its name in a repository. * * The generated reference must be freed by the user. * * The branch name will be checked for validity. * See `git_tag_create()` for rules about valid names. * * @param out pointer to the looked-up branch reference * * @param repo the repository to look up the branch * * @param branch_name Name of the branch to be looked-up; * this name is validated for consistency. * * @param branch_type Type of the considered branch. This should * be valued with either GIT_BRANCH_LOCAL or GIT_BRANCH_REMOTE. * * @return 0 on success; GIT_ENOTFOUND when no matching branch * exists, GIT_EINVALIDSPEC, otherwise an error code. */ GIT_EXTERN(int) git_branch_lookup( git_reference **out, git_repository *repo, const char *branch_name, git_branch_t branch_type); /** * Return the name of the given local or remote branch. * * The name of the branch matches the definition of the name * for git_branch_lookup. That is, if the returned name is given * to git_branch_lookup() then the reference is returned that * was given to this function. * * @param out where the pointer of branch name is stored; * this is valid as long as the ref is not freed. * @param ref the reference ideally pointing to a branch * * @return 0 on success; otherwise an error code (e.g., if the * ref is no local or remote branch). */ GIT_EXTERN(int) git_branch_name(const char **out, git_reference *ref); /** * Return the reference supporting the remote tracking branch, * given a local branch reference. * * @param out Pointer where to store the retrieved * reference. * * @param branch Current underlying reference of the branch. * * @return 0 on success; GIT_ENOTFOUND when no remote tracking * reference exists, otherwise an error code. */ GIT_EXTERN(int) git_branch_upstream( git_reference **out, git_reference *branch); /** * Set the upstream configuration for a given local branch * * @param branch the branch to configure * * @param upstream_name remote-tracking or local branch to set as * upstream. Pass NULL to unset. * * @return 0 or an error code */ GIT_EXTERN(int) git_branch_set_upstream(git_reference *branch, const char *upstream_name); /** * Return the name of the reference supporting the remote tracking branch, * given the name of a local branch reference. * * @param tracking_branch_name_out The user-allocated buffer which will be * filled with the name of the reference. Pass NULL if you just want to * get the needed size of the name of the reference as the output value. * * @param buffer_size Size of the `out` buffer in bytes. * * @param repo the repository where the branches live * * @param canonical_branch_name name of the local branch. * * @return number of characters in the reference name * including the trailing NUL byte; GIT_ENOTFOUND when no remote tracking * reference exists, otherwise an error code. */ GIT_EXTERN(int) git_branch_upstream_name( char *tracking_branch_name_out, size_t buffer_size, git_repository *repo, const char *canonical_branch_name); /** * Determine if the current local branch is pointed at by HEAD. * * @param branch Current underlying reference of the branch. * * @return 1 if HEAD points at the branch, 0 if it isn't, * error code otherwise. */ GIT_EXTERN(int) git_branch_is_head( git_reference *branch); /** * Return the name of remote that the remote tracking branch belongs to. * * @param remote_name_out The user-allocated buffer which will be * filled with the name of the remote. Pass NULL if you just want to * get the needed size of the name of the remote as the output value. * * @param buffer_size Size of the `out` buffer in bytes. * * @param repo The repository where the branch lives. * * @param canonical_branch_name name of the remote tracking branch. * * @return Number of characters in the reference name * including the trailing NUL byte; GIT_ENOTFOUND * when no remote matching remote was found, * GIT_EAMBIGUOUS when the branch maps to several remotes, * otherwise an error code. */ GIT_EXTERN(int) git_branch_remote_name( char *remote_name_out, size_t buffer_size, git_repository *repo, const char *canonical_branch_name); /** @} */ GIT_END_DECL #endif libgit2-0.19.0/include/git2/checkout.h000066400000000000000000000252321216214232500174050ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #ifndef INCLUDE_git_checkout_h__ #define INCLUDE_git_checkout_h__ #include "common.h" #include "types.h" #include "diff.h" /** * @file git2/checkout.h * @brief Git checkout routines * @defgroup git_checkout Git checkout routines * @ingroup Git * @{ */ GIT_BEGIN_DECL /** * Checkout behavior flags * * In libgit2, checkout is used to update the working directory and index * to match a target tree. Unlike git checkout, it does not move the HEAD * commit for you - use `git_repository_set_head` or the like to do that. * * Checkout looks at (up to) four things: the "target" tree you want to * check out, the "baseline" tree of what was checked out previously, the * working directory for actual files, and the index for staged changes. * * You give checkout one of four strategies for update: * * - `GIT_CHECKOUT_NONE` is a dry-run strategy that checks for conflicts, * etc., but doesn't make any actual changes. * * - `GIT_CHECKOUT_FORCE` is at the opposite extreme, taking any action to * make the working directory match the target (including potentially * discarding modified files). * * In between those are `GIT_CHECKOUT_SAFE` and `GIT_CHECKOUT_SAFE_CREATE` * both of which only make modifications that will not lose changes. * * | target == baseline | target != baseline | * ---------------------|-----------------------|----------------------| * workdir == baseline | no action | create, update, or | * | | delete file | * ---------------------|-----------------------|----------------------| * workdir exists and | no action | conflict (notify | * is != baseline | notify dirty MODIFIED | and cancel checkout) | * ---------------------|-----------------------|----------------------| * workdir missing, | create if SAFE_CREATE | create file | * baseline present | notify dirty DELETED | | * ---------------------|-----------------------|----------------------| * * The only difference between SAFE and SAFE_CREATE is that SAFE_CREATE * will cause a file to be checked out if it is missing from the working * directory even if it is not modified between the target and baseline. * * * To emulate `git checkout`, use `GIT_CHECKOUT_SAFE` with a checkout * notification callback (see below) that displays information about dirty * files. The default behavior will cancel checkout on conflicts. * * To emulate `git checkout-index`, use `GIT_CHECKOUT_SAFE_CREATE` with a * notification callback that cancels the operation if a dirty-but-existing * file is found in the working directory. This core git command isn't * quite "force" but is sensitive about some types of changes. * * To emulate `git checkout -f`, use `GIT_CHECKOUT_FORCE`. * * To emulate `git clone` use `GIT_CHECKOUT_SAFE_CREATE` in the options. * * * There are some additional flags to modified the behavior of checkout: * * - GIT_CHECKOUT_ALLOW_CONFLICTS makes SAFE mode apply safe file updates * even if there are conflicts (instead of cancelling the checkout). * * - GIT_CHECKOUT_REMOVE_UNTRACKED means remove untracked files (i.e. not * in target, baseline, or index, and not ignored) from the working dir. * * - GIT_CHECKOUT_REMOVE_IGNORED means remove ignored files (that are also * untracked) from the working directory as well. * * - GIT_CHECKOUT_UPDATE_ONLY means to only update the content of files that * already exist. Files will not be created nor deleted. This just skips * applying adds, deletes, and typechanges. * * - GIT_CHECKOUT_DONT_UPDATE_INDEX prevents checkout from writing the * updated files' information to the index. * * - Normally, checkout will reload the index and git attributes from disk * before any operations. GIT_CHECKOUT_NO_REFRESH prevents this reload. * * - Unmerged index entries are conflicts. GIT_CHECKOUT_SKIP_UNMERGED skips * files with unmerged index entries instead. GIT_CHECKOUT_USE_OURS and * GIT_CHECKOUT_USE_THEIRS to proceed with the checkout using either the * stage 2 ("ours") or stage 3 ("theirs") version of files in the index. */ typedef enum { GIT_CHECKOUT_NONE = 0, /** default is a dry run, no actual updates */ /** Allow safe updates that cannot overwrite uncommitted data */ GIT_CHECKOUT_SAFE = (1u << 0), /** Allow safe updates plus creation of missing files */ GIT_CHECKOUT_SAFE_CREATE = (1u << 1), /** Allow all updates to force working directory to look like index */ GIT_CHECKOUT_FORCE = (1u << 2), /** Allow checkout to make safe updates even if conflicts are found */ GIT_CHECKOUT_ALLOW_CONFLICTS = (1u << 4), /** Remove untracked files not in index (that are not ignored) */ GIT_CHECKOUT_REMOVE_UNTRACKED = (1u << 5), /** Remove ignored files not in index */ GIT_CHECKOUT_REMOVE_IGNORED = (1u << 6), /** Only update existing files, don't create new ones */ GIT_CHECKOUT_UPDATE_ONLY = (1u << 7), /** Normally checkout updates index entries as it goes; this stops that */ GIT_CHECKOUT_DONT_UPDATE_INDEX = (1u << 8), /** Don't refresh index/config/etc before doing checkout */ GIT_CHECKOUT_NO_REFRESH = (1u << 9), /** Treat pathspec as simple list of exact match file paths */ GIT_CHECKOUT_DISABLE_PATHSPEC_MATCH = (1u << 13), /** Ignore directories in use, they will be left empty */ GIT_CHECKOUT_SKIP_LOCKED_DIRECTORIES = (1u << 18), /** * THE FOLLOWING OPTIONS ARE NOT YET IMPLEMENTED */ /** Allow checkout to skip unmerged files (NOT IMPLEMENTED) */ GIT_CHECKOUT_SKIP_UNMERGED = (1u << 10), /** For unmerged files, checkout stage 2 from index (NOT IMPLEMENTED) */ GIT_CHECKOUT_USE_OURS = (1u << 11), /** For unmerged files, checkout stage 3 from index (NOT IMPLEMENTED) */ GIT_CHECKOUT_USE_THEIRS = (1u << 12), /** Recursively checkout submodules with same options (NOT IMPLEMENTED) */ GIT_CHECKOUT_UPDATE_SUBMODULES = (1u << 16), /** Recursively checkout submodules if HEAD moved in super repo (NOT IMPLEMENTED) */ GIT_CHECKOUT_UPDATE_SUBMODULES_IF_CHANGED = (1u << 17), } git_checkout_strategy_t; /** * Checkout notification flags * * Checkout will invoke an options notification callback (`notify_cb`) for * certain cases - you pick which ones via `notify_flags`: * * - GIT_CHECKOUT_NOTIFY_CONFLICT invokes checkout on conflicting paths. * * - GIT_CHECKOUT_NOTIFY_DIRTY notifies about "dirty" files, i.e. those that * do not need an update but no longer match the baseline. Core git * displays these files when checkout runs, but won't stop the checkout. * * - GIT_CHECKOUT_NOTIFY_UPDATED sends notification for any file changed. * * - GIT_CHECKOUT_NOTIFY_UNTRACKED notifies about untracked files. * * - GIT_CHECKOUT_NOTIFY_IGNORED notifies about ignored files. * * Returning a non-zero value from this callback will cancel the checkout. * Notification callbacks are made prior to modifying any files on disk. */ typedef enum { GIT_CHECKOUT_NOTIFY_NONE = 0, GIT_CHECKOUT_NOTIFY_CONFLICT = (1u << 0), GIT_CHECKOUT_NOTIFY_DIRTY = (1u << 1), GIT_CHECKOUT_NOTIFY_UPDATED = (1u << 2), GIT_CHECKOUT_NOTIFY_UNTRACKED = (1u << 3), GIT_CHECKOUT_NOTIFY_IGNORED = (1u << 4), GIT_CHECKOUT_NOTIFY_ALL = 0x0FFFFu } git_checkout_notify_t; /** Checkout notification callback function */ typedef int (*git_checkout_notify_cb)( git_checkout_notify_t why, const char *path, const git_diff_file *baseline, const git_diff_file *target, const git_diff_file *workdir, void *payload); /** Checkout progress notification function */ typedef void (*git_checkout_progress_cb)( const char *path, size_t completed_steps, size_t total_steps, void *payload); /** * Checkout options structure * * Zero out for defaults. Initialize with `GIT_CHECKOUT_OPTS_INIT` macro to * correctly set the `version` field. E.g. * * git_checkout_opts opts = GIT_CHECKOUT_OPTS_INIT; */ typedef struct git_checkout_opts { unsigned int version; unsigned int checkout_strategy; /** default will be a dry run */ int disable_filters; /** don't apply filters like CRLF conversion */ unsigned int dir_mode; /** default is 0755 */ unsigned int file_mode; /** default is 0644 or 0755 as dictated by blob */ int file_open_flags; /** default is O_CREAT | O_TRUNC | O_WRONLY */ unsigned int notify_flags; /** see `git_checkout_notify_t` above */ git_checkout_notify_cb notify_cb; void *notify_payload; /* Optional callback to notify the consumer of checkout progress. */ git_checkout_progress_cb progress_cb; void *progress_payload; /** When not zeroed out, array of fnmatch patterns specifying which * paths should be taken into account, otherwise all files. Use * GIT_CHECKOUT_DISABLE_PATHSPEC_MATCH to treat as simple list. */ git_strarray paths; git_tree *baseline; /** expected content of workdir, defaults to HEAD */ const char *target_directory; /** alternative checkout path to workdir */ } git_checkout_opts; #define GIT_CHECKOUT_OPTS_VERSION 1 #define GIT_CHECKOUT_OPTS_INIT {GIT_CHECKOUT_OPTS_VERSION} /** * Updates files in the index and the working tree to match the content of * the commit pointed at by HEAD. * * @param repo repository to check out (must be non-bare) * @param opts specifies checkout options (may be NULL) * @return 0 on success, GIT_EORPHANEDHEAD when HEAD points to a non existing * branch, GIT_ERROR otherwise (use giterr_last for information * about the error) */ GIT_EXTERN(int) git_checkout_head( git_repository *repo, git_checkout_opts *opts); /** * Updates files in the working tree to match the content of the index. * * @param repo repository into which to check out (must be non-bare) * @param index index to be checked out (or NULL to use repository index) * @param opts specifies checkout options (may be NULL) * @return 0 on success, GIT_ERROR otherwise (use giterr_last for information * about the error) */ GIT_EXTERN(int) git_checkout_index( git_repository *repo, git_index *index, git_checkout_opts *opts); /** * Updates files in the index and working tree to match the content of the * tree pointed at by the treeish. * * @param repo repository to check out (must be non-bare) * @param treeish a commit, tag or tree which content will be used to update * the working directory * @param opts specifies checkout options (may be NULL) * @return 0 on success, GIT_ERROR otherwise (use giterr_last for information * about the error) */ GIT_EXTERN(int) git_checkout_tree( git_repository *repo, const git_object *treeish, git_checkout_opts *opts); /** @} */ GIT_END_DECL #endif libgit2-0.19.0/include/git2/clone.h000066400000000000000000000073351216214232500167040ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #ifndef INCLUDE_git_clone_h__ #define INCLUDE_git_clone_h__ #include "common.h" #include "types.h" #include "indexer.h" #include "checkout.h" #include "remote.h" /** * @file git2/clone.h * @brief Git cloning routines * @defgroup git_clone Git cloning routines * @ingroup Git * @{ */ GIT_BEGIN_DECL /** * Clone options structure * * Use zeros to indicate default settings. It's easiest to use the * `GIT_CLONE_OPTIONS_INIT` macro: * * git_clone_options opts = GIT_CLONE_OPTIONS_INIT; * * - `checkout_opts` is options for the checkout step. To disable checkout, * set the `checkout_strategy` to GIT_CHECKOUT_DEFAULT. * - `bare` should be set to zero to create a standard repo, non-zero for * a bare repo * - `fetch_progress_cb` is optional callback for fetch progress. Be aware that * this is called inline with network and indexing operations, so performance * may be affected. * - `fetch_progress_payload` is payload for fetch_progress_cb * * ** "origin" remote options: ** * - `remote_name` is the name given to the "origin" remote. The default is * "origin". * - `pushurl` is a URL to be used for pushing. NULL means use the fetch url. * - `fetch_spec` is the fetch specification to be used for fetching. NULL * results in the same behavior as GIT_REMOTE_DEFAULT_FETCH. * - `push_spec` is the fetch specification to be used for pushing. NULL means * use the same spec as for fetching. * - `cred_acquire_cb` is a callback to be used if credentials are required * during the initial fetch. * - `cred_acquire_payload` is the payload for the above callback. * - `transport_flags` is flags used to create transport if no transport is * provided. * - `transport` is a custom transport to be used for the initial fetch. NULL * means use the transport autodetected from the URL. * - `remote_callbacks` may be used to specify custom progress callbacks for * the origin remote before the fetch is initiated. * - `remote_autotag` may be used to specify the autotag setting before the * initial fetch. The default is GIT_REMOTE_DOWNLOAD_TAGS_ALL. * - `checkout_branch` gives the name of the branch to checkout. NULL means * use the remote's HEAD. */ typedef struct git_clone_options { unsigned int version; git_checkout_opts checkout_opts; int bare; git_transfer_progress_callback fetch_progress_cb; void *fetch_progress_payload; const char *remote_name; const char *pushurl; const char *fetch_spec; const char *push_spec; git_cred_acquire_cb cred_acquire_cb; void *cred_acquire_payload; git_transport_flags_t transport_flags; git_transport *transport; git_remote_callbacks *remote_callbacks; git_remote_autotag_option_t remote_autotag; const char* checkout_branch; } git_clone_options; #define GIT_CLONE_OPTIONS_VERSION 1 #define GIT_CLONE_OPTIONS_INIT {GIT_CLONE_OPTIONS_VERSION, {GIT_CHECKOUT_OPTS_VERSION, GIT_CHECKOUT_SAFE_CREATE}} /** * Clone a remote repository, and checkout the branch pointed to by the remote * HEAD. * * @param out pointer that will receive the resulting repository object * @param url the remote repository to clone * @param local_path local directory to clone to * @param options configuration options for the clone. If NULL, the function * works as though GIT_OPTIONS_INIT were passed. * @return 0 on success, GIT_ERROR otherwise (use giterr_last for information * about the error) */ GIT_EXTERN(int) git_clone( git_repository **out, const char *url, const char *local_path, const git_clone_options *options); /** @} */ GIT_END_DECL #endif libgit2-0.19.0/include/git2/commit.h000066400000000000000000000210751216214232500170710ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #ifndef INCLUDE_git_commit_h__ #define INCLUDE_git_commit_h__ #include "common.h" #include "types.h" #include "oid.h" #include "object.h" /** * @file git2/commit.h * @brief Git commit parsing, formatting routines * @defgroup git_commit Git commit parsing, formatting routines * @ingroup Git * @{ */ GIT_BEGIN_DECL /** * Lookup a commit object from a repository. * * @param commit pointer to the looked up commit * @param repo the repo to use when locating the commit. * @param id identity of the commit to locate. If the object is * an annotated tag it will be peeled back to the commit. * @return 0 or an error code */ GIT_EXTERN(int) git_commit_lookup(git_commit **commit, git_repository *repo, const git_oid *id); /** * Lookup a commit object from a repository, * given a prefix of its identifier (short id). * * @see git_object_lookup_prefix * * @param commit pointer to the looked up commit * @param repo the repo to use when locating the commit. * @param id identity of the commit to locate. If the object is * an annotated tag it will be peeled back to the commit. * @param len the length of the short identifier * @return 0 or an error code */ GIT_EXTERN(int) git_commit_lookup_prefix(git_commit **commit, git_repository *repo, const git_oid *id, size_t len); /** * Close an open commit * * This is a wrapper around git_object_free() * * IMPORTANT: * It *is* necessary to call this method when you stop * using a commit. Failure to do so will cause a memory leak. * * @param commit the commit to close */ GIT_EXTERN(void) git_commit_free(git_commit *commit); /** * Get the id of a commit. * * @param commit a previously loaded commit. * @return object identity for the commit. */ GIT_EXTERN(const git_oid *) git_commit_id(const git_commit *commit); /** * Get the repository that contains the commit. * * @param commit A previously loaded commit. * @return Repository that contains this commit. */ GIT_EXTERN(git_repository *) git_commit_owner(const git_commit *commit); /** * Get the encoding for the message of a commit, * as a string representing a standard encoding name. * * The encoding may be NULL if the `encoding` header * in the commit is missing; in that case UTF-8 is assumed. * * @param commit a previously loaded commit. * @return NULL, or the encoding */ GIT_EXTERN(const char *) git_commit_message_encoding(const git_commit *commit); /** * Get the full message of a commit. * * @param commit a previously loaded commit. * @return the message of a commit */ GIT_EXTERN(const char *) git_commit_message(const git_commit *commit); /** * Get the commit time (i.e. committer time) of a commit. * * @param commit a previously loaded commit. * @return the time of a commit */ GIT_EXTERN(git_time_t) git_commit_time(const git_commit *commit); /** * Get the commit timezone offset (i.e. committer's preferred timezone) of a commit. * * @param commit a previously loaded commit. * @return positive or negative timezone offset, in minutes from UTC */ GIT_EXTERN(int) git_commit_time_offset(const git_commit *commit); /** * Get the committer of a commit. * * @param commit a previously loaded commit. * @return the committer of a commit */ GIT_EXTERN(const git_signature *) git_commit_committer(const git_commit *commit); /** * Get the author of a commit. * * @param commit a previously loaded commit. * @return the author of a commit */ GIT_EXTERN(const git_signature *) git_commit_author(const git_commit *commit); /** * Get the tree pointed to by a commit. * * @param tree_out pointer where to store the tree object * @param commit a previously loaded commit. * @return 0 or an error code */ GIT_EXTERN(int) git_commit_tree(git_tree **tree_out, const git_commit *commit); /** * Get the id of the tree pointed to by a commit. This differs from * `git_commit_tree` in that no attempts are made to fetch an object * from the ODB. * * @param commit a previously loaded commit. * @return the id of tree pointed to by commit. */ GIT_EXTERN(const git_oid *) git_commit_tree_id(const git_commit *commit); /** * Get the number of parents of this commit * * @param commit a previously loaded commit. * @return integer of count of parents */ GIT_EXTERN(unsigned int) git_commit_parentcount(const git_commit *commit); /** * Get the specified parent of the commit. * * @param out Pointer where to store the parent commit * @param commit a previously loaded commit. * @param n the position of the parent (from 0 to `parentcount`) * @return 0 or an error code */ GIT_EXTERN(int) git_commit_parent( git_commit **out, const git_commit *commit, unsigned int n); /** * Get the oid of a specified parent for a commit. This is different from * `git_commit_parent`, which will attempt to load the parent commit from * the ODB. * * @param commit a previously loaded commit. * @param n the position of the parent (from 0 to `parentcount`) * @return the id of the parent, NULL on error. */ GIT_EXTERN(const git_oid *) git_commit_parent_id( const git_commit *commit, unsigned int n); /** * Get the commit object that is the th generation ancestor * of the named commit object, following only the first parents. * The returned commit has to be freed by the caller. * * Passing `0` as the generation number returns another instance of the * base commit itself. * * @param ancestor Pointer where to store the ancestor commit * @param commit a previously loaded commit. * @param n the requested generation * @return 0 on success; GIT_ENOTFOUND if no matching ancestor exists * or an error code */ GIT_EXTERN(int) git_commit_nth_gen_ancestor( git_commit **ancestor, const git_commit *commit, unsigned int n); /** * Create new commit in the repository from a list of `git_object` pointers * * The message will not be cleaned up automatically. You can do that with * the `git_message_prettify()` function. * * @param id Pointer in which 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. If the reference doesn't * exist yet, it will be created. * * @param author Signature with author and author time of commit * * @param committer Signature with committer and * commit time of commit * * @param message_encoding The encoding for the message in the * commit, represented with a standard encoding name. * E.g. "UTF-8". If NULL, no encoding header is written and * UTF-8 is assumed. * * @param message Full message for this commit * * @param tree An instance of a `git_tree` object that will * be used as the tree for the commit. This tree object must * also be owned by the given `repo`. * * @param parent_count Number of parents for this commit * * @param parents Array of `parent_count` pointers to `git_commit` * objects that will be used as the parents for this commit. This * array may be NULL if `parent_count` is 0 (root commit). All the * given commits must be owned by the `repo`. * * @return 0 or an error code * 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_create( git_oid *id, git_repository *repo, const char *update_ref, const git_signature *author, const git_signature *committer, const char *message_encoding, const char *message, const git_tree *tree, int parent_count, const git_commit *parents[]); /** * Create new commit in the repository using a variable argument list. * * The message will be cleaned up from excess whitespace and it will be made * sure that the last line ends with a '\n'. * * 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 at `git_commit_create()`. * * @see git_commit_create */ GIT_EXTERN(int) git_commit_create_v( git_oid *id, git_repository *repo, const char *update_ref, const git_signature *author, const git_signature *committer, const char *message_encoding, const char *message, const git_tree *tree, int parent_count, ...); /** @} */ GIT_END_DECL #endif libgit2-0.19.0/include/git2/common.h000066400000000000000000000144011216214232500170640ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #ifndef INCLUDE_git_common_h__ #define INCLUDE_git_common_h__ #include #include #ifdef _MSC_VER # include "inttypes.h" #else # include #endif #ifdef __cplusplus # define GIT_BEGIN_DECL extern "C" { # define GIT_END_DECL } #else /** Start declarations in C mode */ # define GIT_BEGIN_DECL /* empty */ /** End declarations in C mode */ # define GIT_END_DECL /* empty */ #endif /** Declare a public function exported for application use. */ #if __GNUC__ >= 4 # define GIT_EXTERN(type) extern \ __attribute__((visibility("default"))) \ type #elif defined(_MSC_VER) # define GIT_EXTERN(type) __declspec(dllexport) type #else # define GIT_EXTERN(type) extern type #endif /** Declare a function as always inlined. */ #if defined(_MSC_VER) # define GIT_INLINE(type) static __inline type #else # define GIT_INLINE(type) static inline type #endif /** Declare a function's takes printf style arguments. */ #ifdef __GNUC__ # define GIT_FORMAT_PRINTF(a,b) __attribute__((format (printf, a, b))) #else # define GIT_FORMAT_PRINTF(a,b) /* empty */ #endif #if (defined(_WIN32)) && !defined(__CYGWIN__) #define GIT_WIN32 1 #endif #ifdef __amigaos4__ #include #endif /** * @file git2/common.h * @brief Git common platform definitions * @defgroup git_common Git common platform definitions * @ingroup Git * @{ */ GIT_BEGIN_DECL /** * The separator used in path list strings (ie like in the PATH * environment variable). A semi-colon ";" is used on Windows, and * a colon ":" for all other systems. */ #ifdef GIT_WIN32 #define GIT_PATH_LIST_SEPARATOR ';' #else #define GIT_PATH_LIST_SEPARATOR ':' #endif /** * The maximum length of a valid git path. */ #define GIT_PATH_MAX 4096 /** * The string representation of the null object ID. */ #define GIT_OID_HEX_ZERO "0000000000000000000000000000000000000000" /** * Return the version of the libgit2 library * being currently used. * * @param major Store the major version number * @param minor Store the minor version number * @param rev Store the revision (patch) number */ GIT_EXTERN(void) git_libgit2_version(int *major, int *minor, int *rev); /** * Combinations of these values describe the capabilities of libgit2. */ typedef enum { GIT_CAP_THREADS = ( 1 << 0 ), GIT_CAP_HTTPS = ( 1 << 1 ) } git_cap_t; /** * Query compile time options for libgit2. * * @return A combination of GIT_CAP_* values. * * - GIT_CAP_THREADS * Libgit2 was compiled with thread support. Note that thread support is * still to be seen as a 'work in progress' - basic object lookups are * believed to be threadsafe, but other operations may not be. * * - GIT_CAP_HTTPS * Libgit2 supports the https:// protocol. This requires the openssl * library to be found when compiling libgit2. */ GIT_EXTERN(int) git_libgit2_capabilities(void); typedef enum { GIT_OPT_GET_MWINDOW_SIZE, GIT_OPT_SET_MWINDOW_SIZE, GIT_OPT_GET_MWINDOW_MAPPED_LIMIT, GIT_OPT_SET_MWINDOW_MAPPED_LIMIT, GIT_OPT_GET_SEARCH_PATH, GIT_OPT_SET_SEARCH_PATH, GIT_OPT_SET_CACHE_OBJECT_LIMIT, GIT_OPT_SET_CACHE_MAX_SIZE, GIT_OPT_ENABLE_CACHING, GIT_OPT_GET_CACHED_MEMORY } git_libgit2_opt_t; /** * Set or query a library global option * * Available options: * * * opts(GIT_OPT_GET_MWINDOW_SIZE, size_t *): * * > Get the maximum mmap window size * * * opts(GIT_OPT_SET_MWINDOW_SIZE, size_t): * * > Set the maximum mmap window size * * * opts(GIT_OPT_GET_MWINDOW_MAPPED_LIMIT, size_t *): * * > Get the maximum memory that will be mapped in total by the library * * * opts(GIT_OPT_SET_MWINDOW_MAPPED_LIMIT, size_t): * * >Set the maximum amount of memory that can be mapped at any time * by the library * * * opts(GIT_OPT_GET_SEARCH_PATH, int level, char *out, size_t len) * * > Get the search path for a given level of config data. "level" must * > be one of `GIT_CONFIG_LEVEL_SYSTEM`, `GIT_CONFIG_LEVEL_GLOBAL`, or * > `GIT_CONFIG_LEVEL_XDG`. The search path is written to the `out` * > buffer up to size `len`. Returns GIT_EBUFS if buffer is too small. * * * opts(GIT_OPT_SET_SEARCH_PATH, int level, const char *path) * * > Set the search path for a level of config data. The search path * > applied to shared attributes and ignore files, too. * > * > - `path` lists directories delimited by GIT_PATH_LIST_SEPARATOR. * > Pass NULL to reset to the default (generally based on environment * > variables). Use magic path `$PATH` to include the old value * > of the path (if you want to prepend or append, for instance). * > * > - `level` must be GIT_CONFIG_LEVEL_SYSTEM, GIT_CONFIG_LEVEL_GLOBAL, * > or GIT_CONFIG_LEVEL_XDG. * * * opts(GIT_OPT_SET_CACHE_OBJECT_LIMIT, git_otype type, size_t size) * * > Set the maximum data size for the given type of object to be * > considered eligible for caching in memory. Setting to value to * > zero means that that type of object will not be cached. * > Defaults to 0 for GIT_OBJ_BLOB (i.e. won't cache blobs) and 4k * > for GIT_OBJ_COMMIT, GIT_OBJ_TREE, and GIT_OBJ_TAG. * * * opts(GIT_OPT_SET_CACHE_MAX_SIZE, ssize_t max_storage_bytes) * * > Set the maximum total data size that will be cached in memory * > across all repositories before libgit2 starts evicting objects * > from the cache. This is a soft limit, in that the library might * > briefly exceed it, but will start aggressively evicting objects * > from cache when that happens. The default cache size is 256Mb. * * * opts(GIT_OPT_ENABLE_CACHING, int enabled) * * > Enable or disable caching completely. * > * > Because caches are repository-specific, disabling the cache * > cannot immediately clear all cached objects, but each cache will * > be cleared on the next attempt to update anything in it. * * * opts(GIT_OPT_GET_CACHED_MEMORY, ssize_t *current, ssize_t *allowed) * * > Get the current bytes in cache and the maximum that would be * > allowed in the cache. * * @param option Option key * @param ... value to set the option * @return 0 on success, <0 on failure */ GIT_EXTERN(int) git_libgit2_opts(int option, ...); /** @} */ GIT_END_DECL #endif libgit2-0.19.0/include/git2/config.h000066400000000000000000000422071216214232500170460ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #ifndef INCLUDE_git_config_h__ #define INCLUDE_git_config_h__ #include "common.h" #include "types.h" /** * @file git2/config.h * @brief Git config management routines * @defgroup git_config Git config management routines * @ingroup Git * @{ */ GIT_BEGIN_DECL /** * Priority level of a config file. * These priority levels correspond to the natural escalation logic * (from higher to lower) when searching for config entries in git.git. * * git_config_open_default() and git_repository_config() honor those * priority levels as well. */ typedef enum { /** System-wide configuration file; /etc/gitconfig on Linux systems */ GIT_CONFIG_LEVEL_SYSTEM = 1, /** XDG compatible configuration file; typically ~/.config/git/config */ GIT_CONFIG_LEVEL_XDG = 2, /** User-specific configuration file (also called Global configuration * file); typically ~/.gitconfig */ GIT_CONFIG_LEVEL_GLOBAL = 3, /** Repository specific configuration file; $WORK_DIR/.git/config on * non-bare repos */ GIT_CONFIG_LEVEL_LOCAL = 4, /** Application specific configuration file; freely defined by applications */ GIT_CONFIG_LEVEL_APP = 5, /** Represents the highest level available config file (i.e. the most * specific config file available that actually is loaded) */ GIT_CONFIG_HIGHEST_LEVEL = -1, } git_config_level_t; typedef struct { const char *name; const char *value; git_config_level_t level; } git_config_entry; typedef int (*git_config_foreach_cb)(const git_config_entry *, void *); typedef enum { GIT_CVAR_FALSE = 0, GIT_CVAR_TRUE = 1, GIT_CVAR_INT32, GIT_CVAR_STRING } git_cvar_t; typedef struct { git_cvar_t cvar_type; const char *str_match; int map_value; } git_cvar_map; /** * Locate the path to the global configuration file * * The user or global configuration file is usually * located in `$HOME/.gitconfig`. * * This method will try to guess the full path to that * file, if the file exists. The returned path * may be used on any `git_config` call to load the * global configuration file. * * This method will not guess the path to the xdg compatible * config file (.config/git/config). * * @param out Buffer to store the path in * @param length size of the buffer in bytes * @return 0 if a global configuration file has been found. Its path will be stored in `buffer`. */ GIT_EXTERN(int) git_config_find_global(char *out, size_t length); /** * Locate the path to the global xdg compatible configuration file * * The xdg compatible configuration file is usually * located in `$HOME/.config/git/config`. * * This method will try to guess the full path to that * file, if the file exists. The returned path * may be used on any `git_config` call to load the * xdg compatible configuration file. * * @param out Buffer to store the path in * @param length size of the buffer in bytes * @return 0 if a xdg compatible configuration file has been * found. Its path will be stored in `buffer`. */ GIT_EXTERN(int) git_config_find_xdg(char *out, size_t length); /** * Locate the path to the system configuration file * * If /etc/gitconfig doesn't exist, it will look for * %PROGRAMFILES%\Git\etc\gitconfig. * @param out Buffer to store the path in * @param length size of the buffer in bytes * @return 0 if a system configuration file has been * found. Its path will be stored in `buffer`. */ GIT_EXTERN(int) git_config_find_system(char *out, size_t length); /** * Open the global, XDG and system configuration files * * Utility wrapper that finds the global, XDG and system configuration files * and opens them into a single prioritized config object that can be * used when accessing default config data outside a repository. * * @param out Pointer to store the config instance * @return 0 or an error code */ GIT_EXTERN(int) git_config_open_default(git_config **out); /** * Allocate a new configuration object * * This object is empty, so you have to add a file to it before you * can do anything with it. * * @param out pointer to the new configuration * @return 0 or an error code */ GIT_EXTERN(int) git_config_new(git_config **out); /** * Add an on-disk config file instance to an existing config * * The on-disk file pointed at by `path` will be opened and * parsed; it's expected to be a native Git config file following * the default Git config syntax (see man git-config). * * Note that the configuration object will free the file * automatically. * * Further queries on this config object will access each * of the config file instances in order (instances with * a higher priority level will be accessed first). * * @param cfg the configuration to add the file to * @param path path to the configuration file to add * @param level the priority level of the backend * @param force replace config file at the given priority level * @return 0 on success, GIT_EEXISTS when adding more than one file * for a given priority level (and force_replace set to 0), * GIT_ENOTFOUND when the file doesn't exist or error code */ GIT_EXTERN(int) git_config_add_file_ondisk( git_config *cfg, const char *path, git_config_level_t level, int force); /** * Create a new config instance containing a single on-disk file * * This method is a simple utility wrapper for the following sequence * of calls: * - git_config_new * - git_config_add_file_ondisk * * @param out The configuration instance to create * @param path Path to the on-disk file to open * @return 0 on success, GIT_ENOTFOUND when the file doesn't exist * or an error code */ GIT_EXTERN(int) git_config_open_ondisk(git_config **out, const char *path); /** * Build a single-level focused config object from a multi-level one. * * The returned config object can be used to perform get/set/delete operations * on a single specific level. * * Getting several times the same level from the same parent multi-level config * will return different config instances, but containing the same config_file * instance. * * @param out The configuration instance to create * @param parent Multi-level config to search for the given level * @param level Configuration level to search for * @return 0, GIT_ENOTFOUND if the passed level cannot be found in the * multi-level parent config, or an error code */ GIT_EXTERN(int) git_config_open_level( git_config **out, const git_config *parent, git_config_level_t level); /** * Open the global/XDG configuration file according to git's rules * * Git allows you to store your global configuration at * `$HOME/.config` or `$XDG_CONFIG_HOME/git/config`. For backwards * compatability, the XDG file shouldn't be used unless the use has * created it explicitly. With this function you'll open the correct * one to write to. * * @param out pointer in which to store the config object * @param config the config object in which to look */ GIT_EXTERN(int) git_config_open_global(git_config **out, git_config *config); /** * Reload changed config files * * A config file may be changed on disk out from under the in-memory * config object. This function causes us to look for files that have * been modified since we last loaded them and refresh the config with * the latest information. * * @param cfg The configuration to refresh * @return 0 or an error code */ GIT_EXTERN(int) git_config_refresh(git_config *cfg); /** * Free the configuration and its associated memory and files * * @param cfg the configuration to free */ GIT_EXTERN(void) git_config_free(git_config *cfg); /** * Get the git_config_entry of a config variable. * * The git_config_entry is owned by the config and should not be freed by the * user. * @param out pointer to the variable git_config_entry * @param cfg where to look for the variable * @param name the variable's name * @return 0 or an error code */ GIT_EXTERN(int) git_config_get_entry( const git_config_entry **out, const git_config *cfg, const char *name); /** * Get the value of an integer config variable. * * All config files will be looked into, in the order of their * defined level. A higher level means a higher priority. The * first occurence of the variable will be returned here. * * @param out pointer to the variable where the value should be stored * @param cfg where to look for the variable * @param name the variable's name * @return 0 or an error code */ GIT_EXTERN(int) git_config_get_int32(int32_t *out, const git_config *cfg, const char *name); /** * Get the value of a long integer config variable. * * All config files will be looked into, in the order of their * defined level. A higher level means a higher priority. The * first occurrence of the variable will be returned here. * * @param out pointer to the variable where the value should be stored * @param cfg where to look for the variable * @param name the variable's name * @return 0 or an error code */ GIT_EXTERN(int) git_config_get_int64(int64_t *out, const git_config *cfg, const char *name); /** * Get the value of a boolean config variable. * * This function uses the usual C convention of 0 being false and * anything else true. * * All config files will be looked into, in the order of their * defined level. A higher level means a higher priority. The * first occurrence of the variable will be returned here. * * @param out pointer to the variable where the value should be stored * @param cfg where to look for the variable * @param name the variable's name * @return 0 or an error code */ GIT_EXTERN(int) git_config_get_bool(int *out, const git_config *cfg, const char *name); /** * Get the value of a string config variable. * * The string is owned by the variable and should not be freed by the * user. * * All config files will be looked into, in the order of their * defined level. A higher level means a higher priority. The * first occurrence of the variable will be returned here. * * @param out pointer to the variable's value * @param cfg where to look for the variable * @param name the variable's name * @return 0 or an error code */ GIT_EXTERN(int) git_config_get_string(const char **out, const git_config *cfg, const char *name); /** * Get each value of a multivar. * * The callback will be called on each variable found * * @param cfg where to look for the variable * @param name the variable's name * @param regexp regular expression to filter which variables we're * interested in. Use NULL to indicate all * @param callback the function to be called on each value of the variable * @param payload opaque pointer to pass to the callback */ GIT_EXTERN(int) git_config_get_multivar(const git_config *cfg, const char *name, const char *regexp, git_config_foreach_cb callback, void *payload); /** * Set the value of an integer config variable in the config file * with the highest level (usually the local one). * * @param cfg where to look for the variable * @param name the variable's name * @param value Integer value for the variable * @return 0 or an error code */ GIT_EXTERN(int) git_config_set_int32(git_config *cfg, const char *name, int32_t value); /** * Set the value of a long integer config variable in the config file * with the highest level (usually the local one). * * @param cfg where to look for the variable * @param name the variable's name * @param value Long integer value for the variable * @return 0 or an error code */ GIT_EXTERN(int) git_config_set_int64(git_config *cfg, const char *name, int64_t value); /** * Set the value of a boolean config variable in the config file * with the highest level (usually the local one). * * @param cfg where to look for the variable * @param name the variable's name * @param value the value to store * @return 0 or an error code */ GIT_EXTERN(int) git_config_set_bool(git_config *cfg, const char *name, int value); /** * Set the value of a string config variable in the config file * with the highest level (usually the local one). * * A copy of the string is made and the user is free to use it * afterwards. * * @param cfg where to look for the variable * @param name the variable's name * @param value the string to store. * @return 0 or an error code */ GIT_EXTERN(int) git_config_set_string(git_config *cfg, const char *name, const char *value); /** * Set a multivar in the local config file. * * @param cfg where to look for the variable * @param name the variable's name * @param regexp a regular expression to indicate which values to replace * @param value the new value. */ GIT_EXTERN(int) git_config_set_multivar(git_config *cfg, const char *name, const char *regexp, const char *value); /** * Delete a config variable from the config file * with the highest level (usually the local one). * * @param cfg the configuration * @param name the variable to delete */ GIT_EXTERN(int) git_config_delete_entry(git_config *cfg, const char *name); /** * Perform an operation on each config variable. * * The callback receives the normalized name and value of each variable * in the config backend, and the data pointer passed to this function. * As soon as one of the callback functions returns something other than 0, * this function stops iterating and returns `GIT_EUSER`. * * @param cfg where to get the variables from * @param callback the function to call on each variable * @param payload the data to pass to the callback * @return 0 on success, GIT_EUSER on non-zero callback, or error code */ GIT_EXTERN(int) git_config_foreach( const git_config *cfg, git_config_foreach_cb callback, void *payload); /** * Perform an operation on each config variable matching a regular expression. * * This behaviors like `git_config_foreach` with an additional filter of a * regular expression that filters which config keys are passed to the * callback. * * @param cfg where to get the variables from * @param regexp regular expression to match against config names * @param callback the function to call on each variable * @param payload the data to pass to the callback * @return 0 or the return value of the callback which didn't return 0 */ GIT_EXTERN(int) git_config_foreach_match( const git_config *cfg, const char *regexp, git_config_foreach_cb callback, void *payload); /** * Query the value of a config variable and return it mapped to * an integer constant. * * This is a helper method to easily map different possible values * to a variable to integer constants that easily identify them. * * A mapping array looks as follows: * * git_cvar_map autocrlf_mapping[] = { * {GIT_CVAR_FALSE, NULL, GIT_AUTO_CRLF_FALSE}, * {GIT_CVAR_TRUE, NULL, GIT_AUTO_CRLF_TRUE}, * {GIT_CVAR_STRING, "input", GIT_AUTO_CRLF_INPUT}, * {GIT_CVAR_STRING, "default", GIT_AUTO_CRLF_DEFAULT}}; * * On any "false" value for the variable (e.g. "false", "FALSE", "no"), the * mapping will store `GIT_AUTO_CRLF_FALSE` in the `out` parameter. * * The same thing applies for any "true" value such as "true", "yes" or "1", storing * the `GIT_AUTO_CRLF_TRUE` variable. * * Otherwise, if the value matches the string "input" (with case insensitive comparison), * the given constant will be stored in `out`, and likewise for "default". * * If not a single match can be made to store in `out`, an error code will be * returned. * * @param out place to store the result of the mapping * @param cfg config file to get the variables from * @param name name of the config variable to lookup * @param maps array of `git_cvar_map` objects specifying the possible mappings * @param map_n number of mapping objects in `maps` * @return 0 on success, error code otherwise */ GIT_EXTERN(int) git_config_get_mapped( int *out, const git_config *cfg, const char *name, const git_cvar_map *maps, size_t map_n); /** * Maps a string value to an integer constant * * @param out place to store the result of the parsing * @param maps array of `git_cvar_map` objects specifying the possible mappings * @param map_n number of mapping objects in `maps` * @param value value to parse */ GIT_EXTERN(int) git_config_lookup_map_value( int *out, const git_cvar_map *maps, size_t map_n, const char *value); /** * Parse a string value as a bool. * * Valid values for true are: 'true', 'yes', 'on', 1 or any * number different from 0 * Valid values for false are: 'false', 'no', 'off', 0 * * @param out place to store the result of the parsing * @param value value to parse */ GIT_EXTERN(int) git_config_parse_bool(int *out, const char *value); /** * Parse a string value as an int32. * * An optional value suffix of 'k', 'm', or 'g' will * cause the value to be multiplied by 1024, 1048576, * or 1073741824 prior to output. * * @param out place to store the result of the parsing * @param value value to parse */ GIT_EXTERN(int) git_config_parse_int32(int32_t *out, const char *value); /** * Parse a string value as an int64. * * An optional value suffix of 'k', 'm', or 'g' will * cause the value to be multiplied by 1024, 1048576, * or 1073741824 prior to output. * * @param out place to store the result of the parsing * @param value value to parse */ GIT_EXTERN(int) git_config_parse_int64(int64_t *out, const char *value); /** @} */ GIT_END_DECL #endif libgit2-0.19.0/include/git2/cred_helpers.h000066400000000000000000000027741216214232500202450ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #ifndef INCLUDE_git_cred_helpers_h__ #define INCLUDE_git_cred_helpers_h__ #include "git2/transport.h" /** * @file git2/cred_helpers.h * @brief Utility functions for credential management * @defgroup git_cred_helpers credential management helpers * @ingroup Git * @{ */ GIT_BEGIN_DECL /** * Payload for git_cred_stock_userpass_plaintext. */ typedef struct git_cred_userpass_payload { char *username; char *password; } git_cred_userpass_payload; /** * Stock callback usable as a git_cred_acquire_cb. This calls * git_cred_userpass_plaintext_new unless the protocol has not specified * `GIT_CREDTYPE_USERPASS_PLAINTEXT` as an allowed type. * * @param cred The newly created credential object. * @param url The resource for which we are demanding a credential. * @param user_from_url The username that was embedded in a "user@host" * remote url, or NULL if not included. * @param allowed_types A bitmask stating which cred types are OK to return. * @param payload The payload provided when specifying this callback. (This is * interpreted as a `git_cred_userpass_payload*`.) */ GIT_EXTERN(int) git_cred_userpass( git_cred **cred, const char *url, const char *user_from_url, unsigned int allowed_types, void *payload); /** @} */ GIT_END_DECL #endif libgit2-0.19.0/include/git2/diff.h000066400000000000000000001244171216214232500165150ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #ifndef INCLUDE_git_diff_h__ #define INCLUDE_git_diff_h__ #include "common.h" #include "types.h" #include "oid.h" #include "tree.h" #include "refs.h" /** * @file git2/diff.h * @brief Git tree and file differencing routines. * * Overview * -------- * * Calculating diffs is generally done in two phases: building a diff list * then traversing the diff list. This makes is easier to share logic * across the various types of diffs (tree vs tree, workdir vs index, etc.), * and also allows you to insert optional diff list post-processing phases, * such as rename detected, in between the steps. When you are done with a * diff list object, it must be freed. * * Terminology * ----------- * * To understand the diff APIs, you should know the following terms: * * - A `diff` or `diff list` represents the cumulative list of differences * between two snapshots of a repository (possibly filtered by a set of * file name patterns). This is the `git_diff_list` object. * - A `delta` is a file pair with an old and new revision. The old version * may be absent if the file was just created and the new version may be * absent if the file was deleted. A diff is mostly just a list of deltas. * - A `binary` file / delta is a file (or pair) for which no text diffs * should be generated. A diff list can contain delta entries that are * binary, but no diff content will be output for those files. There is * a base heuristic for binary detection and you can further tune the * behavior with git attributes or diff flags and option settings. * - A `hunk` is a span of modified lines in a delta along with some stable * surrounding context. You can configure the amount of context and other * properties of how hunks are generated. Each hunk also comes with a * header that described where it starts and ends in both the old and new * versions in the delta. * - A `line` is a range of characters inside a hunk. It could be a context * line (i.e. in both old and new versions), an added line (i.e. only in * the new version), or a removed line (i.e. only in the old version). * Unfortunately, we don't know anything about the encoding of data in the * file being diffed, so we cannot tell you much about the line content. * Line data will not be NUL-byte terminated, however, because it will be * just a span of bytes inside the larger file. * * @ingroup Git * @{ */ GIT_BEGIN_DECL /** * Flags for diff options. A combination of these flags can be passed * in via the `flags` value in the `git_diff_options`. */ typedef enum { /** Normal diff, the default */ GIT_DIFF_NORMAL = 0, /** Reverse the sides of the diff */ GIT_DIFF_REVERSE = (1 << 0), /** Treat all files as text, disabling binary attributes & detection */ GIT_DIFF_FORCE_TEXT = (1 << 1), /** Ignore all whitespace */ GIT_DIFF_IGNORE_WHITESPACE = (1 << 2), /** Ignore changes in amount of whitespace */ GIT_DIFF_IGNORE_WHITESPACE_CHANGE = (1 << 3), /** Ignore whitespace at end of line */ GIT_DIFF_IGNORE_WHITESPACE_EOL = (1 << 4), /** Exclude submodules from the diff completely */ GIT_DIFF_IGNORE_SUBMODULES = (1 << 5), /** Use the "patience diff" algorithm (currently unimplemented) */ GIT_DIFF_PATIENCE = (1 << 6), /** Include ignored files in the diff list */ GIT_DIFF_INCLUDE_IGNORED = (1 << 7), /** Include untracked files in the diff list */ GIT_DIFF_INCLUDE_UNTRACKED = (1 << 8), /** Include unmodified files in the diff list */ GIT_DIFF_INCLUDE_UNMODIFIED = (1 << 9), /** Even with GIT_DIFF_INCLUDE_UNTRACKED, an entire untracked * directory will be marked with only a single entry in the diff list * (a la what core Git does in `git status`); this flag adds *all* * files under untracked directories as UNTRACKED entries, too. */ GIT_DIFF_RECURSE_UNTRACKED_DIRS = (1 << 10), /** If the pathspec is set in the diff options, this flags means to * apply it as an exact match instead of as an fnmatch pattern. */ GIT_DIFF_DISABLE_PATHSPEC_MATCH = (1 << 11), /** Use case insensitive filename comparisons */ GIT_DIFF_DELTAS_ARE_ICASE = (1 << 12), /** When generating patch text, include the content of untracked * files. This automatically turns on GIT_DIFF_INCLUDE_UNTRACKED but * it does not turn on GIT_DIFF_RECURSE_UNTRACKED_DIRS. Add that * flag if you want the content of every single UNTRACKED file. */ GIT_DIFF_INCLUDE_UNTRACKED_CONTENT = (1 << 13), /** Disable updating of the `binary` flag in delta records. This is * useful when iterating over a diff if you don't need hunk and data * callbacks and want to avoid having to load file completely. */ GIT_DIFF_SKIP_BINARY_CHECK = (1 << 14), /** Normally, a type change between files will be converted into a * DELETED record for the old and an ADDED record for the new; this * options enabled the generation of TYPECHANGE delta records. */ GIT_DIFF_INCLUDE_TYPECHANGE = (1 << 15), /** Even with GIT_DIFF_INCLUDE_TYPECHANGE, blob->tree changes still * generally show as a DELETED blob. This flag tries to correctly * label blob->tree transitions as TYPECHANGE records with new_file's * mode set to tree. Note: the tree SHA will not be available. */ GIT_DIFF_INCLUDE_TYPECHANGE_TREES = (1 << 16), /** Ignore file mode changes */ GIT_DIFF_IGNORE_FILEMODE = (1 << 17), /** Even with GIT_DIFF_INCLUDE_IGNORED, an entire ignored directory * will be marked with only a single entry in the diff list; this flag * adds all files under the directory as IGNORED entries, too. */ GIT_DIFF_RECURSE_IGNORED_DIRS = (1 << 18), /** Core Git scans inside untracked directories, labeling them IGNORED * if they are empty or only contain ignored files; a directory is * consider UNTRACKED only if it has an actual untracked file in it. * This scan is extra work for a case you often don't care about. This * flag makes libgit2 immediately label an untracked directory as * UNTRACKED without looking inside it (which differs from core Git). * Of course, ignore rules are still checked for the directory itself. */ GIT_DIFF_FAST_UNTRACKED_DIRS = (1 << 19), /** Treat all files as binary, disabling text diffs */ GIT_DIFF_FORCE_BINARY = (1 << 20), } git_diff_option_t; /** * The diff list object that contains all individual file deltas. * * This is an opaque structure which will be allocated by one of the diff * generator functions below (such as `git_diff_tree_to_tree`). You are * responsible for releasing the object memory when done, using the * `git_diff_list_free()` function. */ typedef struct git_diff_list git_diff_list; /** * Flags for the delta object and the file objects on each side. * * These flags are used for both the `flags` value of the `git_diff_delta` * and the flags for the `git_diff_file` objects representing the old and * new sides of the delta. Values outside of this public range should be * considered reserved for internal or future use. */ typedef enum { GIT_DIFF_FLAG_BINARY = (1 << 0), /** file(s) treated as binary data */ GIT_DIFF_FLAG_NOT_BINARY = (1 << 1), /** file(s) treated as text data */ GIT_DIFF_FLAG_VALID_OID = (1 << 2), /** `oid` value is known correct */ } git_diff_flag_t; /** * What type of change is described by a git_diff_delta? * * `GIT_DELTA_RENAMED` and `GIT_DELTA_COPIED` will only show up if you run * `git_diff_find_similar()` on the diff list object. * * `GIT_DELTA_TYPECHANGE` only shows up given `GIT_DIFF_INCLUDE_TYPECHANGE` * in the option flags (otherwise type changes will be split into ADDED / * DELETED pairs). */ typedef enum { GIT_DELTA_UNMODIFIED = 0, /** no changes */ GIT_DELTA_ADDED = 1, /** entry does not exist in old version */ GIT_DELTA_DELETED = 2, /** entry does not exist in new version */ GIT_DELTA_MODIFIED = 3, /** entry content changed between old and new */ GIT_DELTA_RENAMED = 4, /** entry was renamed between old and new */ GIT_DELTA_COPIED = 5, /** entry was copied from another old entry */ GIT_DELTA_IGNORED = 6, /** entry is ignored item in workdir */ GIT_DELTA_UNTRACKED = 7, /** entry is untracked item in workdir */ GIT_DELTA_TYPECHANGE = 8, /** type of entry changed between old and new */ } git_delta_t; /** * Description of one side of a diff entry. * * Although this is called a "file", it may actually represent a file, a * symbolic link, a submodule commit id, or even a tree (although that only * if you are tracking type changes or ignored/untracked directories). * * The `oid` is the `git_oid` of the item. If the entry represents an * absent side of a diff (e.g. the `old_file` of a `GIT_DELTA_ADDED` delta), * then the oid will be zeroes. * * `path` is the NUL-terminated path to the entry relative to the working * directory of the repository. * * `size` is the size of the entry in bytes. * * `flags` is a combination of the `git_diff_flag_t` types * * `mode` is, roughly, the stat() `st_mode` value for the item. This will * be restricted to one of the `git_filemode_t` values. */ typedef struct { git_oid oid; const char *path; git_off_t size; uint32_t flags; uint16_t mode; } git_diff_file; /** * Description of changes to one entry. * * When iterating over a diff list object, this will be passed to most * callback functions and you can use the contents to understand exactly * what has changed. * * The `old_file` represents the "from" side of the diff and the `new_file` * represents to "to" side of the diff. What those means depend on the * function that was used to generate the diff and will be documented below. * You can also use the `GIT_DIFF_REVERSE` flag to flip it around. * * Although the two sides of the delta are named "old_file" and "new_file", * they actually may correspond to entries that represent a file, a symbolic * link, a submodule commit id, or even a tree (if you are tracking type * changes or ignored/untracked directories). * * Under some circumstances, in the name of efficiency, not all fields will * be filled in, but we generally try to fill in as much as possible. One * example is that the "flags" field may not have either the `BINARY` or the * `NOT_BINARY` flag set to avoid examining file contents if you do not pass * in hunk and/or line callbacks to the diff foreach iteration function. It * will just use the git attributes for those files. * * The similarity score is zero unless you call `git_diff_find_similar()` * which does a similarity analysis of files in the diff. Use that * function to do rename and copy detection, and to split heavily modified * files in add/delete pairs. After that call, deltas with a status of * GIT_DELTA_RENAMED or GIT_DELTA_COPIED will have a similarity score * between 0 and 100 indicating how similar the old and new sides are. * * If you ask `git_diff_find_similar` to find heavily modified files to * break, but to not *actually* break the records, then GIT_DELTA_MODIFIED * records may have a non-zero similarity score if the self-similarity is * below the split threshold. To display this value like core Git, invert * the score (a la `printf("M%03d", 100 - delta->similarity)`). */ typedef struct { git_diff_file old_file; git_diff_file new_file; git_delta_t status; uint32_t similarity; /**< for RENAMED and COPIED, value 0-100 */ uint32_t flags; } git_diff_delta; /** * Diff notification callback function. * * The callback will be called for each file, just before the `git_delta_t` * gets inserted into the diff list. * * When the callback: * - returns < 0, the diff process will be aborted. * - returns > 0, the delta will not be inserted into the diff list, but the * diff process continues. * - returns 0, the delta is inserted into the diff list, and the diff process * continues. */ typedef int (*git_diff_notify_cb)( const git_diff_list *diff_so_far, const git_diff_delta *delta_to_add, const char *matched_pathspec, void *payload); /** * Structure describing options about how the diff should be executed. * * Setting all values of the structure to zero will yield the default * values. Similarly, passing NULL for the options structure will * give the defaults. The default values are marked below. * * - `flags` is a combination of the `git_diff_option_t` values above * - `context_lines` is the number of unchanged lines that define the * boundary of a hunk (and to display before and after) * - `interhunk_lines` is the maximum number of unchanged lines between * hunk boundaries before the hunks will be merged into a one. * - `old_prefix` is the virtual "directory" to prefix to old file names * in hunk headers (default "a") * - `new_prefix` is the virtual "directory" to prefix to new file names * in hunk headers (default "b") * - `pathspec` is an array of paths / fnmatch patterns to constrain diff * - `max_size` is a file size (in bytes) above which a blob will be marked * as binary automatically; pass a negative value to disable. * - `notify_cb` is an optional callback function, notifying the consumer of * which files are being examined as the diff is generated * - `notify_payload` is the payload data to pass to the `notify_cb` function */ typedef struct { unsigned int version; /**< version for the struct */ uint32_t flags; /**< defaults to GIT_DIFF_NORMAL */ uint16_t context_lines; /**< defaults to 3 */ uint16_t interhunk_lines; /**< defaults to 0 */ const char *old_prefix; /**< defaults to "a" */ const char *new_prefix; /**< defaults to "b" */ git_strarray pathspec; /**< defaults to include all paths */ git_off_t max_size; /**< defaults to 512MB */ git_diff_notify_cb notify_cb; void *notify_payload; } git_diff_options; #define GIT_DIFF_OPTIONS_VERSION 1 #define GIT_DIFF_OPTIONS_INIT {GIT_DIFF_OPTIONS_VERSION, GIT_DIFF_NORMAL, 3} /** * When iterating over a diff, callback that will be made per file. * * @param delta A pointer to the delta data for the file * @param progress Goes from 0 to 1 over the diff list * @param payload User-specified pointer from foreach function */ typedef int (*git_diff_file_cb)( const git_diff_delta *delta, float progress, void *payload); /** * Structure describing a hunk of a diff. */ typedef struct { int old_start; /** Starting line number in old_file */ int old_lines; /** Number of lines in old_file */ int new_start; /** Starting line number in new_file */ int new_lines; /** Number of lines in new_file */ } git_diff_range; /** * When iterating over a diff, callback that will be made per hunk. */ typedef int (*git_diff_hunk_cb)( const git_diff_delta *delta, const git_diff_range *range, const char *header, size_t header_len, void *payload); /** * Line origin constants. * * These values describe where a line came from and will be passed to * the git_diff_data_cb when iterating over a diff. There are some * special origin constants at the end that are used for the text * output callbacks to demarcate lines that are actually part of * the file or hunk headers. */ typedef enum { /* These values will be sent to `git_diff_data_cb` along with the line */ GIT_DIFF_LINE_CONTEXT = ' ', GIT_DIFF_LINE_ADDITION = '+', GIT_DIFF_LINE_DELETION = '-', GIT_DIFF_LINE_CONTEXT_EOFNL = '=', /**< Both files have no LF at end */ GIT_DIFF_LINE_ADD_EOFNL = '>', /**< Old has no LF at end, new does */ GIT_DIFF_LINE_DEL_EOFNL = '<', /**< Old has LF at end, new does not */ /* The following values will only be sent to a `git_diff_data_cb` when * the content of a diff is being formatted (eg. through * git_diff_print_patch() or git_diff_print_compact(), for instance). */ GIT_DIFF_LINE_FILE_HDR = 'F', GIT_DIFF_LINE_HUNK_HDR = 'H', GIT_DIFF_LINE_BINARY = 'B' } git_diff_line_t; /** * When iterating over a diff, callback that will be made per text diff * line. In this context, the provided range will be NULL. * * When printing a diff, callback that will be made to output each line * of text. This uses some extra GIT_DIFF_LINE_... constants for output * of lines of file and hunk headers. */ typedef int (*git_diff_data_cb)( const git_diff_delta *delta, /** delta that contains this data */ const git_diff_range *range, /** range of lines containing this data */ char line_origin, /** git_diff_list_t value from above */ const char *content, /** diff data - not NUL terminated */ size_t content_len, /** number of bytes of diff data */ void *payload); /** user reference data */ /** * The diff patch is used to store all the text diffs for a delta. * * You can easily loop over the content of patches and get information about * them. */ typedef struct git_diff_patch git_diff_patch; /** * Flags to control the behavior of diff rename/copy detection. */ typedef enum { /** look for renames? (`--find-renames`) */ GIT_DIFF_FIND_RENAMES = (1 << 0), /** consider old side of modified for renames? (`--break-rewrites=N`) */ GIT_DIFF_FIND_RENAMES_FROM_REWRITES = (1 << 1), /** look for copies? (a la `--find-copies`) */ GIT_DIFF_FIND_COPIES = (1 << 2), /** consider unmodified as copy sources? (`--find-copies-harder`) */ GIT_DIFF_FIND_COPIES_FROM_UNMODIFIED = (1 << 3), /** mark large rewrites for split (`--break-rewrites=/M`) */ GIT_DIFF_FIND_REWRITES = (1 << 4), /** actually split large rewrites into delete/add pairs */ GIT_DIFF_BREAK_REWRITES = (1 << 5), /** mark rewrites for split and break into delete/add pairs */ GIT_DIFF_FIND_AND_BREAK_REWRITES = (GIT_DIFF_FIND_REWRITES | GIT_DIFF_BREAK_REWRITES), /** find renames/copies for untracked items in working directory */ GIT_DIFF_FIND_FOR_UNTRACKED = (1 << 6), /** turn on all finding features */ GIT_DIFF_FIND_ALL = (0x0ff), /** measure similarity ignoring leading whitespace (default) */ GIT_DIFF_FIND_IGNORE_LEADING_WHITESPACE = 0, /** measure similarity ignoring all whitespace */ GIT_DIFF_FIND_IGNORE_WHITESPACE = (1 << 12), /** measure similarity including all data */ GIT_DIFF_FIND_DONT_IGNORE_WHITESPACE = (1 << 13), /** measure similarity only by comparing SHAs (fast and cheap) */ GIT_DIFF_FIND_EXACT_MATCH_ONLY = (1 << 14), } git_diff_find_t; /** * Pluggable similarity metric */ typedef struct { int (*file_signature)( void **out, const git_diff_file *file, const char *fullpath, void *payload); int (*buffer_signature)( void **out, const git_diff_file *file, const char *buf, size_t buflen, void *payload); void (*free_signature)(void *sig, void *payload); int (*similarity)(int *score, void *siga, void *sigb, void *payload); void *payload; } git_diff_similarity_metric; /** * Control behavior of rename and copy detection * * These options mostly mimic parameters that can be passed to git-diff. * * - `rename_threshold` is the same as the -M option with a value * - `copy_threshold` is the same as the -C option with a value * - `rename_from_rewrite_threshold` matches the top of the -B option * - `break_rewrite_threshold` matches the bottom of the -B option * - `rename_limit` is the maximum number of matches to consider for * a particular file. This is a little different from the `-l` option * to regular Git because we will still process up to this many matches * before abandoning the search. * * The `metric` option allows you to plug in a custom similarity metric. * Set it to NULL for the default internal metric which is based on sampling * hashes of ranges of data in the file. The default metric is a pretty * good similarity approximation that should work fairly well for both text * and binary data, and is pretty fast with fixed memory overhead. */ typedef struct { unsigned int version; /** Combination of git_diff_find_t values (default FIND_RENAMES) */ uint32_t flags; /** Similarity to consider a file renamed (default 50) */ uint16_t rename_threshold; /** Similarity of modified to be eligible rename source (default 50) */ uint16_t rename_from_rewrite_threshold; /** Similarity to consider a file a copy (default 50) */ uint16_t copy_threshold; /** Similarity to split modify into delete/add pair (default 60) */ uint16_t break_rewrite_threshold; /** Maximum similarity sources to examine for a file (somewhat like * git-diff's `-l` option or `diff.renameLimit` config) (default 200) */ size_t rename_limit; /** Pluggable similarity metric; pass NULL to use internal metric */ git_diff_similarity_metric *metric; } git_diff_find_options; #define GIT_DIFF_FIND_OPTIONS_VERSION 1 #define GIT_DIFF_FIND_OPTIONS_INIT {GIT_DIFF_FIND_OPTIONS_VERSION} /** @name Diff List Generator Functions * * These are the functions you would use to create (or destroy) a * git_diff_list from various objects in a repository. */ /**@{*/ /** * Deallocate a diff list. * * @param diff The previously created diff list; cannot be used after free. */ GIT_EXTERN(void) git_diff_list_free(git_diff_list *diff); /** * Create a diff list with the difference between two tree objects. * * This is equivalent to `git diff ` * * The first tree will be used for the "old_file" side of the delta and the * second tree will be used for the "new_file" side of the delta. You can * pass NULL to indicate an empty tree, although it is an error to pass * NULL for both the `old_tree` and `new_tree`. * * @param diff Output pointer to a git_diff_list pointer to be allocated. * @param repo The repository containing the trees. * @param old_tree A git_tree object to diff from, or NULL for empty tree. * @param new_tree A git_tree object to diff to, or NULL for empty tree. * @param opts Structure with options to influence diff or NULL for defaults. */ GIT_EXTERN(int) git_diff_tree_to_tree( git_diff_list **diff, git_repository *repo, git_tree *old_tree, git_tree *new_tree, const git_diff_options *opts); /**< can be NULL for defaults */ /** * Create a diff list between a tree and repository index. * * This is equivalent to `git diff --cached ` or if you pass * the HEAD tree, then like `git diff --cached`. * * The tree you pass will be used for the "old_file" side of the delta, and * the index will be used for the "new_file" side of the delta. * * @param diff Output pointer to a git_diff_list pointer to be allocated. * @param repo The repository containing the tree and index. * @param old_tree A git_tree object to diff from, or NULL for empty tree. * @param index The index to diff with; repo index used if NULL. * @param opts Structure with options to influence diff or NULL for defaults. */ GIT_EXTERN(int) git_diff_tree_to_index( git_diff_list **diff, git_repository *repo, git_tree *old_tree, git_index *index, const git_diff_options *opts); /**< can be NULL for defaults */ /** * Create a diff list between the repository index and the workdir directory. * * This matches the `git diff` command. See the note below on * `git_diff_tree_to_workdir` for a discussion of the difference between * `git diff` and `git diff HEAD` and how to emulate a `git diff ` * using libgit2. * * The index will be used for the "old_file" side of the delta, and the * working directory will be used for the "new_file" side of the delta. * * @param diff Output pointer to a git_diff_list pointer to be allocated. * @param repo The repository. * @param index The index to diff from; repo index used if NULL. * @param opts Structure with options to influence diff or NULL for defaults. */ GIT_EXTERN(int) git_diff_index_to_workdir( git_diff_list **diff, git_repository *repo, git_index *index, const git_diff_options *opts); /**< can be NULL for defaults */ /** * Create a diff list between a tree and the working directory. * * The tree you provide will be used for the "old_file" side of the delta, * and the working directory will be used for the "new_file" side. * * Please note: this is *NOT* the same as `git diff `. Running * `git diff HEAD` or the like actually uses information from the index, * along with the tree and working directory info. * * This function returns strictly the differences between the tree and the * files contained in the working directory, regardless of the state of * files in the index. It may come as a surprise, but there is no direct * equivalent in core git. * * To emulate `git diff `, call both `git_diff_tree_to_index` and * `git_diff_index_to_workdir`, then call `git_diff_merge` on the results. * That will yield a `git_diff_list` that matches the git output. * * If this seems confusing, take the case of a file with a staged deletion * where the file has then been put back into the working dir and modified. * The tree-to-workdir diff for that file is 'modified', but core git would * show status 'deleted' since there is a pending deletion in the index. * * @param diff A pointer to a git_diff_list pointer that will be allocated. * @param repo The repository containing the tree. * @param old_tree A git_tree object to diff from, or NULL for empty tree. * @param opts Structure with options to influence diff or NULL for defaults. */ GIT_EXTERN(int) git_diff_tree_to_workdir( git_diff_list **diff, git_repository *repo, git_tree *old_tree, const git_diff_options *opts); /**< can be NULL for defaults */ /** * Merge one diff list into another. * * This merges items from the "from" list into the "onto" list. The * resulting diff list will have all items that appear in either list. * If an item appears in both lists, then it will be "merged" to appear * as if the old version was from the "onto" list and the new version * is from the "from" list (with the exception that if the item has a * pending DELETE in the middle, then it will show as deleted). * * @param onto Diff to merge into. * @param from Diff to merge. */ GIT_EXTERN(int) git_diff_merge( git_diff_list *onto, const git_diff_list *from); /** * Transform a diff list marking file renames, copies, etc. * * This modifies a diff list in place, replacing old entries that look * like renames or copies with new entries reflecting those changes. * This also will, if requested, break modified files into add/remove * pairs if the amount of change is above a threshold. * * @param diff Diff list to run detection algorithms on * @param options Control how detection should be run, NULL for defaults * @return 0 on success, -1 on failure */ GIT_EXTERN(int) git_diff_find_similar( git_diff_list *diff, git_diff_find_options *options); /**@}*/ /** @name Diff List Processor Functions * * These are the functions you apply to a diff list to process it * or read it in some way. */ /**@{*/ /** * Loop over all deltas in a diff list issuing callbacks. * * This will iterate through all of the files described in a diff. You * should provide a file callback to learn about each file. * * The "hunk" and "line" callbacks are optional, and the text diff of the * files will only be calculated if they are not NULL. Of course, these * callbacks will not be invoked for binary files on the diff list or for * files whose only changed is a file mode change. * * Returning a non-zero value from any of the callbacks will terminate * the iteration and cause this return `GIT_EUSER`. * * @param diff A git_diff_list generated by one of the above functions. * @param file_cb Callback function to make per file in the diff. * @param hunk_cb Optional callback to make per hunk of text diff. This * callback is called to describe a range of lines in the * diff. It will not be issued for binary files. * @param line_cb Optional callback to make per line of diff text. This * same callback will be made for context lines, added, and * removed lines, and even for a deleted trailing newline. * @param payload Reference pointer that will be passed to your callbacks. * @return 0 on success, GIT_EUSER on non-zero callback, or error code */ GIT_EXTERN(int) git_diff_foreach( git_diff_list *diff, git_diff_file_cb file_cb, git_diff_hunk_cb hunk_cb, git_diff_data_cb line_cb, void *payload); /** * Iterate over a diff generating text output like "git diff --name-status". * * Returning a non-zero value from the callbacks will terminate the * iteration and cause this return `GIT_EUSER`. * * @param diff A git_diff_list generated by one of the above functions. * @param print_cb Callback to make per line of diff text. * @param payload Reference pointer that will be passed to your callback. * @return 0 on success, GIT_EUSER on non-zero callback, or error code */ GIT_EXTERN(int) git_diff_print_compact( git_diff_list *diff, git_diff_data_cb print_cb, void *payload); /** * Iterate over a diff generating text output like "git diff --raw". * * Returning a non-zero value from the callbacks will terminate the * iteration and cause this return `GIT_EUSER`. * * @param diff A git_diff_list generated by one of the above functions. * @param print_cb Callback to make per line of diff text. * @param payload Reference pointer that will be passed to your callback. * @return 0 on success, GIT_EUSER on non-zero callback, or error code */ GIT_EXTERN(int) git_diff_print_raw( git_diff_list *diff, git_diff_data_cb print_cb, void *payload); /** * Look up the single character abbreviation for a delta status code. * * When you call `git_diff_print_compact` it prints single letter codes into * the output such as 'A' for added, 'D' for deleted, 'M' for modified, etc. * It is sometimes convenient to convert a git_delta_t value into these * letters for your own purposes. This function does just that. By the * way, unmodified will return a space (i.e. ' '). * * @param status The git_delta_t value to look up * @return The single character label for that code */ GIT_EXTERN(char) git_diff_status_char(git_delta_t status); /** * Iterate over a diff generating text output like "git diff". * * This is a super easy way to generate a patch from a diff. * * Returning a non-zero value from the callbacks will terminate the * iteration and cause this return `GIT_EUSER`. * * @param diff A git_diff_list generated by one of the above functions. * @param payload Reference pointer that will be passed to your callbacks. * @param print_cb Callback function to output lines of the diff. This * same function will be called for file headers, hunk * headers, and diff lines. Fortunately, you can probably * use various GIT_DIFF_LINE constants to determine what * text you are given. * @return 0 on success, GIT_EUSER on non-zero callback, or error code */ GIT_EXTERN(int) git_diff_print_patch( git_diff_list *diff, git_diff_data_cb print_cb, void *payload); /** * Query how many diff records are there in a diff list. * * @param diff A git_diff_list generated by one of the above functions * @return Count of number of deltas in the list */ GIT_EXTERN(size_t) git_diff_num_deltas(git_diff_list *diff); /** * Query how many diff deltas are there in a diff list filtered by type. * * This works just like `git_diff_entrycount()` with an extra parameter * that is a `git_delta_t` and returns just the count of how many deltas * match that particular type. * * @param diff A git_diff_list generated by one of the above functions * @param type A git_delta_t value to filter the count * @return Count of number of deltas matching delta_t type */ GIT_EXTERN(size_t) git_diff_num_deltas_of_type( git_diff_list *diff, git_delta_t type); /** * Return the diff delta and patch for an entry in the diff list. * * The `git_diff_patch` is a newly created object contains the text diffs * for the delta. You have to call `git_diff_patch_free()` when you are * done with it. You can use the patch object to loop over all the hunks * and lines in the diff of the one delta. * * For an unchanged file or a binary file, no `git_diff_patch` will be * created, the output will be set to NULL, and the `binary` flag will be * set true in the `git_diff_delta` structure. * * The `git_diff_delta` pointer points to internal data and you do not have * to release it when you are done with it. It will go away when the * `git_diff_list` and `git_diff_patch` go away. * * It is okay to pass NULL for either of the output parameters; if you pass * NULL for the `git_diff_patch`, then the text diff will not be calculated. * * @param patch_out Output parameter for the delta patch object * @param delta_out Output parameter for the delta object * @param diff Diff list object * @param idx Index into diff list * @return 0 on success, other value < 0 on error */ GIT_EXTERN(int) git_diff_get_patch( git_diff_patch **patch_out, const git_diff_delta **delta_out, git_diff_list *diff, size_t idx); /** * Free a git_diff_patch object. */ GIT_EXTERN(void) git_diff_patch_free( git_diff_patch *patch); /** * Get the delta associated with a patch */ GIT_EXTERN(const git_diff_delta *) git_diff_patch_delta( git_diff_patch *patch); /** * Get the number of hunks in a patch */ GIT_EXTERN(size_t) git_diff_patch_num_hunks( git_diff_patch *patch); /** * Get line counts of each type in a patch. * * This helps imitate a diff --numstat type of output. For that purpose, * you only need the `total_additions` and `total_deletions` values, but we * include the `total_context` line count in case you want the total number * of lines of diff output that will be generated. * * All outputs are optional. Pass NULL if you don't need a particular count. * * @param total_context Count of context lines in output, can be NULL. * @param total_additions Count of addition lines in output, can be NULL. * @param total_deletions Count of deletion lines in output, can be NULL. * @param patch The git_diff_patch object * @return 0 on success, <0 on error */ GIT_EXTERN(int) git_diff_patch_line_stats( size_t *total_context, size_t *total_additions, size_t *total_deletions, const git_diff_patch *patch); /** * Get the information about a hunk in a patch * * Given a patch and a hunk index into the patch, this returns detailed * information about that hunk. Any of the output pointers can be passed * as NULL if you don't care about that particular piece of information. * * @param range Output pointer to git_diff_range of hunk * @param header Output pointer to header string for hunk. Unlike the * content pointer for each line, this will be NUL-terminated * @param header_len Output value of characters in header string * @param lines_in_hunk Output count of total lines in this hunk * @param patch Input pointer to patch object * @param hunk_idx Input index of hunk to get information about * @return 0 on success, GIT_ENOTFOUND if hunk_idx out of range, <0 on error */ GIT_EXTERN(int) git_diff_patch_get_hunk( const git_diff_range **range, const char **header, size_t *header_len, size_t *lines_in_hunk, git_diff_patch *patch, size_t hunk_idx); /** * Get the number of lines in a hunk. * * @param patch The git_diff_patch object * @param hunk_idx Index of the hunk * @return Number of lines in hunk or -1 if invalid hunk index */ GIT_EXTERN(int) git_diff_patch_num_lines_in_hunk( git_diff_patch *patch, size_t hunk_idx); /** * Get data about a line in a hunk of a patch. * * Given a patch, a hunk index, and a line index in the hunk, this * will return a lot of details about that line. If you pass a hunk * index larger than the number of hunks or a line index larger than * the number of lines in the hunk, this will return -1. * * @param line_origin A GIT_DIFF_LINE constant from above * @param content Pointer to content of diff line, not NUL-terminated * @param content_len Number of characters in content * @param old_lineno Line number in old file or -1 if line is added * @param new_lineno Line number in new file or -1 if line is deleted * @param patch The patch to look in * @param hunk_idx The index of the hunk * @param line_of_hunk The index of the line in the hunk * @return 0 on success, <0 on failure */ GIT_EXTERN(int) git_diff_patch_get_line_in_hunk( char *line_origin, const char **content, size_t *content_len, int *old_lineno, int *new_lineno, git_diff_patch *patch, size_t hunk_idx, size_t line_of_hunk); /** * Serialize the patch to text via callback. * * Returning a non-zero value from the callback will terminate the iteration * and cause this return `GIT_EUSER`. * * @param patch A git_diff_patch representing changes to one file * @param print_cb Callback function to output lines of the patch. Will be * called for file headers, hunk headers, and diff lines. * @param payload Reference pointer that will be passed to your callbacks. * @return 0 on success, GIT_EUSER on non-zero callback, or error code */ GIT_EXTERN(int) git_diff_patch_print( git_diff_patch *patch, git_diff_data_cb print_cb, void *payload); /** * Get the content of a patch as a single diff text. * * @param string Allocated string; caller must free. * @param patch A git_diff_patch representing changes to one file * @return 0 on success, <0 on failure. */ GIT_EXTERN(int) git_diff_patch_to_str( char **string, git_diff_patch *patch); /**@}*/ /* * Misc */ /** * Directly run a diff on two blobs. * * Compared to a file, a blob lacks some contextual information. As such, * the `git_diff_file` given to the callback will have some fake data; i.e. * `mode` will be 0 and `path` will be NULL. * * NULL is allowed for either `old_blob` or `new_blob` and will be treated * as an empty blob, with the `oid` set to NULL in the `git_diff_file` data. * Passing NULL for both blobs is a noop; no callbacks will be made at all. * * We do run a binary content check on the blob content and if either blob * looks like binary data, the `git_diff_delta` binary attribute will be set * to 1 and no call to the hunk_cb nor line_cb will be made (unless you pass * `GIT_DIFF_FORCE_TEXT` of course). * * @param old_blob Blob for old side of diff, or NULL for empty blob * @param old_as_path Treat old blob as if it had this filename; can be NULL * @param new_blob Blob for new side of diff, or NULL for empty blob * @param new_as_path Treat new blob as if it had this filename; can be NULL * @param options Options for diff, or NULL for default options * @param file_cb Callback for "file"; made once if there is a diff; can be NULL * @param hunk_cb Callback for each hunk in diff; can be NULL * @param line_cb Callback for each line in diff; can be NULL * @param payload Payload passed to each callback function * @return 0 on success, GIT_EUSER on non-zero callback return, or error code */ GIT_EXTERN(int) git_diff_blobs( const git_blob *old_blob, const char *old_as_path, const git_blob *new_blob, const char *new_as_path, const git_diff_options *options, git_diff_file_cb file_cb, git_diff_hunk_cb hunk_cb, git_diff_data_cb line_cb, void *payload); /** * Directly generate a patch from the difference between two blobs. * * This is just like `git_diff_blobs()` except it generates a patch object * for the difference instead of directly making callbacks. You can use the * standard `git_diff_patch` accessor functions to read the patch data, and * you must call `git_diff_patch_free()` on the patch when done. * * @param out The generated patch; NULL on error * @param old_blob Blob for old side of diff, or NULL for empty blob * @param old_as_path Treat old blob as if it had this filename; can be NULL * @param new_blob Blob for new side of diff, or NULL for empty blob * @param new_as_path Treat new blob as if it had this filename; can be NULL * @param opts Options for diff, or NULL for default options * @return 0 on success or error code < 0 */ GIT_EXTERN(int) git_diff_patch_from_blobs( git_diff_patch **out, const git_blob *old_blob, const char *old_as_path, const git_blob *new_blob, const char *new_as_path, const git_diff_options *opts); /** * Directly run a diff between a blob and a buffer. * * As with `git_diff_blobs`, comparing a blob and buffer lacks some context, * so the `git_diff_file` parameters to the callbacks will be faked a la the * rules for `git_diff_blobs()`. * * Passing NULL for `old_blob` will be treated as an empty blob (i.e. the * `file_cb` will be invoked with GIT_DELTA_ADDED and the diff will be the * entire content of the buffer added). Passing NULL to the buffer will do * the reverse, with GIT_DELTA_REMOVED and blob content removed. * * @param old_blob Blob for old side of diff, or NULL for empty blob * @param old_as_path Treat old blob as if it had this filename; can be NULL * @param buffer Raw data for new side of diff, or NULL for empty * @param buffer_len Length of raw data for new side of diff * @param buffer_as_path Treat buffer as if it had this filename; can be NULL * @param options Options for diff, or NULL for default options * @param file_cb Callback for "file"; made once if there is a diff; can be NULL * @param hunk_cb Callback for each hunk in diff; can be NULL * @param data_cb Callback for each line in diff; can be NULL * @param payload Payload passed to each callback function * @return 0 on success, GIT_EUSER on non-zero callback return, or error code */ GIT_EXTERN(int) git_diff_blob_to_buffer( const git_blob *old_blob, const char *old_as_path, const char *buffer, size_t buffer_len, const char *buffer_as_path, const git_diff_options *options, git_diff_file_cb file_cb, git_diff_hunk_cb hunk_cb, git_diff_data_cb data_cb, void *payload); /** * Directly generate a patch from the difference between a blob and a buffer. * * This is just like `git_diff_blob_to_buffer()` except it generates a patch * object for the difference instead of directly making callbacks. You can * use the standard `git_diff_patch` accessor functions to read the patch * data, and you must call `git_diff_patch_free()` on the patch when done. * * @param out The generated patch; NULL on error * @param old_blob Blob for old side of diff, or NULL for empty blob * @param old_as_path Treat old blob as if it had this filename; can be NULL * @param buffer Raw data for new side of diff, or NULL for empty * @param buffer_len Length of raw data for new side of diff * @param buffer_as_path Treat buffer as if it had this filename; can be NULL * @param opts Options for diff, or NULL for default options * @return 0 on success or error code < 0 */ GIT_EXTERN(int) git_diff_patch_from_blob_and_buffer( git_diff_patch **out, const git_blob *old_blob, const char *old_as_path, const char *buffer, size_t buffer_len, const char *buffer_as_path, const git_diff_options *opts); GIT_END_DECL /** @} */ #endif libgit2-0.19.0/include/git2/errors.h000066400000000000000000000061721216214232500171160ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #ifndef INCLUDE_git_errors_h__ #define INCLUDE_git_errors_h__ #include "common.h" /** * @file git2/errors.h * @brief Git error handling routines and variables * @ingroup Git * @{ */ GIT_BEGIN_DECL /** Generic return codes */ typedef enum { GIT_OK = 0, GIT_ERROR = -1, GIT_ENOTFOUND = -3, GIT_EEXISTS = -4, GIT_EAMBIGUOUS = -5, GIT_EBUFS = -6, GIT_EUSER = -7, GIT_EBAREREPO = -8, GIT_EORPHANEDHEAD = -9, GIT_EUNMERGED = -10, GIT_ENONFASTFORWARD = -11, GIT_EINVALIDSPEC = -12, GIT_EMERGECONFLICT = -13, GIT_PASSTHROUGH = -30, GIT_ITEROVER = -31, } git_error_code; typedef struct { char *message; int klass; } git_error; /** Error classes */ typedef enum { GITERR_NOMEMORY, GITERR_OS, GITERR_INVALID, GITERR_REFERENCE, GITERR_ZLIB, GITERR_REPOSITORY, GITERR_CONFIG, GITERR_REGEX, GITERR_ODB, GITERR_INDEX, GITERR_OBJECT, GITERR_NET, GITERR_TAG, GITERR_TREE, GITERR_INDEXER, GITERR_SSL, GITERR_SUBMODULE, GITERR_THREAD, GITERR_STASH, GITERR_CHECKOUT, GITERR_FETCHHEAD, GITERR_MERGE, } git_error_t; /** * Return the last `git_error` object that was generated for the * current thread or NULL if no error has occurred. * * @return A git_error object. */ GIT_EXTERN(const git_error *) giterr_last(void); /** * Clear the last library error that occurred for this thread. */ GIT_EXTERN(void) giterr_clear(void); /** * Set the error message string for this thread. * * This function is public so that custom ODB backends and the like can * relay an error message through libgit2. Most regular users of libgit2 * will never need to call this function -- actually, calling it in most * circumstances (for example, calling from within a callback function) * will just end up having the value overwritten by libgit2 internals. * * This error message is stored in thread-local storage and only applies * to the particular thread that this libgit2 call is made from. * * NOTE: Passing the `error_class` as GITERR_OS has a special behavior: we * attempt to append the system default error message for the last OS error * that occurred and then clear the last error. The specific implementation * of looking up and clearing this last OS error will vary by platform. * * @param error_class One of the `git_error_t` enum above describing the * general subsystem that is responsible for the error. * @param string The formatted error message to keep */ GIT_EXTERN(void) giterr_set_str(int error_class, const char *string); /** * Set the error message to a special value for memory allocation failure. * * The normal `giterr_set_str()` function attempts to `strdup()` the string * that is passed in. This is not a good idea when the error in question * is a memory allocation failure. That circumstance has a special setter * function that sets the error string to a known and statically allocated * internal value. */ GIT_EXTERN(void) giterr_set_oom(void); /** @} */ GIT_END_DECL #endif libgit2-0.19.0/include/git2/graph.h000066400000000000000000000023401216214232500166740ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #ifndef INCLUDE_git_graph_h__ #define INCLUDE_git_graph_h__ #include "common.h" #include "types.h" #include "oid.h" /** * @file git2/graph.h * @brief Git graph traversal routines * @defgroup git_revwalk Git graph traversal routines * @ingroup Git * @{ */ GIT_BEGIN_DECL /** * Count the number of unique commits between two commit objects * * There is no need for branches containing the commits to have any * upstream relationship, but it helps to think of one as a branch and * the other as its upstream, the `ahead` and `behind` values will be * what git would report for the branches. * * @param ahead number of unique from commits in `upstream` * @param behind number of unique from commits in `local` * @param repo the repository where the commits exist * @param local the commit for local * @param upstream the commit for upstream */ GIT_EXTERN(int) git_graph_ahead_behind(size_t *ahead, size_t *behind, git_repository *repo, const git_oid *local, const git_oid *upstream); /** @} */ GIT_END_DECL #endif libgit2-0.19.0/include/git2/ignore.h000066400000000000000000000050531216214232500170620ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #ifndef INCLUDE_git_ignore_h__ #define INCLUDE_git_ignore_h__ #include "common.h" #include "types.h" GIT_BEGIN_DECL /** * Add ignore rules for a repository. * * Excludesfile rules (i.e. .gitignore rules) are generally read from * .gitignore files in the repository tree or from a shared system file * only if a "core.excludesfile" config value is set. The library also * keeps a set of per-repository internal ignores that can be configured * in-memory and will not persist. This function allows you to add to * that internal rules list. * * Example usage: * * error = git_ignore_add_rule(myrepo, "*.c\ndir/\nFile with space\n"); * * This would add three rules to the ignores. * * @param repo The repository to add ignore rules to. * @param rules Text of rules, a la the contents of a .gitignore file. * It is okay to have multiple rules in the text; if so, * each rule should be terminated with a newline. * @return 0 on success */ GIT_EXTERN(int) git_ignore_add_rule( git_repository *repo, const char *rules); /** * Clear ignore rules that were explicitly added. * * Resets to the default internal ignore rules. This will not turn off * rules in .gitignore files that actually exist in the filesystem. * * The default internal ignores ignore ".", ".." and ".git" entries. * * @param repo The repository to remove ignore rules from. * @return 0 on success */ GIT_EXTERN(int) git_ignore_clear_internal_rules( git_repository *repo); /** * Test if the ignore rules apply to a given path. * * This function checks the ignore rules to see if they would apply to the * given file. This indicates if the file would be ignored regardless of * whether the file is already in the index or committed to the repository. * * One way to think of this is if you were to do "git add ." on the * directory containing the file, would it be added or not? * * @param ignored boolean returning 0 if the file is not ignored, 1 if it is * @param repo a repository object * @param path the file to check ignores for, relative to the repo's workdir. * @return 0 if ignore rules could be processed for the file (regardless * of whether it exists or not), or an error < 0 if they could not. */ GIT_EXTERN(int) git_ignore_path_is_ignored( int *ignored, git_repository *repo, const char *path); GIT_END_DECL #endif libgit2-0.19.0/include/git2/index.h000066400000000000000000000525151216214232500167130ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #ifndef INCLUDE_git_index_h__ #define INCLUDE_git_index_h__ #include "common.h" #include "indexer.h" #include "types.h" #include "oid.h" #include "strarray.h" /** * @file git2/index.h * @brief Git index parsing and manipulation routines * @defgroup git_index Git index parsing and manipulation routines * @ingroup Git * @{ */ GIT_BEGIN_DECL /** Time structure used in a git index entry */ typedef struct { git_time_t seconds; /* nsec should not be stored as time_t compatible */ unsigned int nanoseconds; } git_index_time; /** * In-memory representation of a file entry in the index. * * This is a public structure that represents a file entry in the index. * The meaning of the fields corresponds to core Git's documentation (in * "Documentation/technical/index-format.txt"). * * The `flags` field consists of a number of bit fields which can be * accessed via the first set of `GIT_IDXENTRY_...` bitmasks below. These * flags are all read from and persisted to disk. * * The `flags_extended` field also has a number of bit fields which can be * accessed via the later `GIT_IDXENTRY_...` bitmasks below. Some of * these flags are read from and written to disk, but some are set aside * for in-memory only reference. */ typedef struct git_index_entry { git_index_time ctime; git_index_time mtime; unsigned int dev; unsigned int ino; unsigned int mode; unsigned int uid; unsigned int gid; git_off_t file_size; git_oid oid; unsigned short flags; unsigned short flags_extended; char *path; } git_index_entry; /** * Bitmasks for on-disk fields of `git_index_entry`'s `flags` * * These bitmasks match the four fields in the `git_index_entry` `flags` * value both in memory and on disk. You can use them to interpret the * data in the `flags`. */ #define GIT_IDXENTRY_NAMEMASK (0x0fff) #define GIT_IDXENTRY_STAGEMASK (0x3000) #define GIT_IDXENTRY_EXTENDED (0x4000) #define GIT_IDXENTRY_VALID (0x8000) #define GIT_IDXENTRY_STAGESHIFT 12 #define GIT_IDXENTRY_STAGE(E) (((E)->flags & GIT_IDXENTRY_STAGEMASK) >> GIT_IDXENTRY_STAGESHIFT) /** * Bitmasks for on-disk fields of `git_index_entry`'s `flags_extended` * * In memory, the `flags_extended` fields are divided into two parts: the * fields that are read from and written to disk, and other fields that * in-memory only and used by libgit2. Only the flags in * `GIT_IDXENTRY_EXTENDED_FLAGS` will get saved on-disk. * * These bitmasks match the three fields in the `git_index_entry` * `flags_extended` value that belong on disk. You can use them to * interpret the data in the `flags_extended`. */ #define GIT_IDXENTRY_INTENT_TO_ADD (1 << 13) #define GIT_IDXENTRY_SKIP_WORKTREE (1 << 14) /* GIT_IDXENTRY_EXTENDED2 is reserved for future extension */ #define GIT_IDXENTRY_EXTENDED2 (1 << 15) #define GIT_IDXENTRY_EXTENDED_FLAGS (GIT_IDXENTRY_INTENT_TO_ADD | GIT_IDXENTRY_SKIP_WORKTREE) /** * Bitmasks for in-memory only fields of `git_index_entry`'s `flags_extended` * * These bitmasks match the other fields in the `git_index_entry` * `flags_extended` value that are only used in-memory by libgit2. You * can use them to interpret the data in the `flags_extended`. */ #define GIT_IDXENTRY_UPDATE (1 << 0) #define GIT_IDXENTRY_REMOVE (1 << 1) #define GIT_IDXENTRY_UPTODATE (1 << 2) #define GIT_IDXENTRY_ADDED (1 << 3) #define GIT_IDXENTRY_HASHED (1 << 4) #define GIT_IDXENTRY_UNHASHED (1 << 5) #define GIT_IDXENTRY_WT_REMOVE (1 << 6) /* remove in work directory */ #define GIT_IDXENTRY_CONFLICTED (1 << 7) #define GIT_IDXENTRY_UNPACKED (1 << 8) #define GIT_IDXENTRY_NEW_SKIP_WORKTREE (1 << 9) /** Capabilities of system that affect index actions. */ typedef enum { GIT_INDEXCAP_IGNORE_CASE = 1, GIT_INDEXCAP_NO_FILEMODE = 2, GIT_INDEXCAP_NO_SYMLINKS = 4, GIT_INDEXCAP_FROM_OWNER = ~0u } git_indexcap_t; /** Callback for APIs that add/remove/update files matching pathspec */ typedef int (*git_index_matched_path_cb)( const char *path, const char *matched_pathspec, void *payload); /** Flags for APIs that add files matching pathspec */ typedef enum { GIT_INDEX_ADD_DEFAULT = 0, GIT_INDEX_ADD_FORCE = (1u << 0), GIT_INDEX_ADD_DISABLE_PATHSPEC_MATCH = (1u << 1), GIT_INDEX_ADD_CHECK_PATHSPEC = (1u << 2), } git_index_add_option_t; /** @name Index File Functions * * These functions work on the index file itself. */ /**@{*/ /** * Create a new bare Git index object as a memory representation * of the Git index file in 'index_path', without a repository * to back it. * * Since there is no ODB or working directory behind this index, * any Index methods which rely on these (e.g. index_add) will * fail with the GIT_EBAREINDEX error code. * * If you need to access the index of an actual repository, * use the `git_repository_index` wrapper. * * The index must be freed once it's no longer in use. * * @param out the pointer for the new index * @param index_path the path to the index file in disk * @return 0 or an error code */ GIT_EXTERN(int) git_index_open(git_index **out, const char *index_path); /** * Create an in-memory index object. * * This index object cannot be read/written to the filesystem, * but may be used to perform in-memory index operations. * * The index must be freed once it's no longer in use. * * @param out the pointer for the new index * @return 0 or an error code */ GIT_EXTERN(int) git_index_new(git_index **out); /** * Free an existing index object. * * @param index an existing index object */ GIT_EXTERN(void) git_index_free(git_index *index); /** * Get the repository this index relates to * * @param index The index * @return A pointer to the repository */ GIT_EXTERN(git_repository *) git_index_owner(const git_index *index); /** * Read index capabilities flags. * * @param index An existing index object * @return A combination of GIT_INDEXCAP values */ GIT_EXTERN(unsigned int) git_index_caps(const git_index *index); /** * Set index capabilities flags. * * If you pass `GIT_INDEXCAP_FROM_OWNER` for the caps, then the * capabilities will be read from the config of the owner object, * looking at `core.ignorecase`, `core.filemode`, `core.symlinks`. * * @param index An existing index object * @param caps A combination of GIT_INDEXCAP values * @return 0 on success, -1 on failure */ GIT_EXTERN(int) git_index_set_caps(git_index *index, unsigned int caps); /** * Update the contents of an existing index object in memory * by reading from the hard disk. * * @param index an existing index object * @return 0 or an error code */ GIT_EXTERN(int) git_index_read(git_index *index); /** * Write an existing index object from memory back to disk * using an atomic file lock. * * @param index an existing index object * @return 0 or an error code */ GIT_EXTERN(int) git_index_write(git_index *index); /** * Read a tree into the index file with stats * * The current index contents will be replaced by the specified tree. * * @param index an existing index object * @param tree tree to read * @return 0 or an error code */ GIT_EXTERN(int) git_index_read_tree(git_index *index, const git_tree *tree); /** * Write the index as a tree * * This method will scan the index and write a representation * of its current state back to disk; it recursively creates * tree objects for each of the subtrees stored in the index, * but only returns the OID of the root tree. This is the OID * that can be used e.g. to create a commit. * * The index instance cannot be bare, and needs to be associated * to an existing repository. * * The index must not contain any file in conflict. * * @param out Pointer where to store the OID of the written tree * @param index Index to write * @return 0 on success, GIT_EUNMERGED when the index is not clean * or an error code */ GIT_EXTERN(int) git_index_write_tree(git_oid *out, git_index *index); /** * Write the index as a tree to the given repository * * This method will do the same as `git_index_write_tree`, but * letting the user choose the repository where the tree will * be written. * * The index must not contain any file in conflict. * * @param out Pointer where to store OID of the the written tree * @param index Index to write * @param repo Repository where to write the tree * @return 0 on success, GIT_EUNMERGED when the index is not clean * or an error code */ GIT_EXTERN(int) git_index_write_tree_to(git_oid *out, git_index *index, git_repository *repo); /**@}*/ /** @name Raw Index Entry Functions * * These functions work on index entries, and allow for raw manipulation * of the entries. */ /**@{*/ /* Index entry manipulation */ /** * Get the count of entries currently in the index * * @param index an existing index object * @return integer of count of current entries */ GIT_EXTERN(size_t) git_index_entrycount(const git_index *index); /** * Clear the contents (all the entries) of an index object. * This clears the index object in memory; changes must be manually * written to disk for them to take effect. * * @param index an existing index object */ GIT_EXTERN(void) git_index_clear(git_index *index); /** * Get a pointer to one of the entries in the index * * The entry is not modifiable and should not be freed. Because the * `git_index_entry` struct is a publicly defined struct, you should * be able to make your own permanent copy of the data if necessary. * * @param index an existing index object * @param n the position of the entry * @return a pointer to the entry; NULL if out of bounds */ GIT_EXTERN(const git_index_entry *) git_index_get_byindex( git_index *index, size_t n); /** * Get a pointer to one of the entries in the index * * The entry is not modifiable and should not be freed. Because the * `git_index_entry` struct is a publicly defined struct, you should * be able to make your own permanent copy of the data if necessary. * * @param index an existing index object * @param path path to search * @param stage stage to search * @return a pointer to the entry; NULL if it was not found */ GIT_EXTERN(const git_index_entry *) git_index_get_bypath( git_index *index, const char *path, int stage); /** * Remove an entry from the index * * @param index an existing index object * @param path path to search * @param stage stage to search * @return 0 or an error code */ GIT_EXTERN(int) git_index_remove(git_index *index, const char *path, int stage); /** * Remove all entries from the index under a given directory * * @param index an existing index object * @param dir container directory path * @param stage stage to search * @return 0 or an error code */ GIT_EXTERN(int) git_index_remove_directory( git_index *index, const char *dir, int stage); /** * Add or update an index entry from an in-memory struct * * If a previous index entry exists that has the same path and stage * as the given 'source_entry', it will be replaced. Otherwise, the * 'source_entry' will be added. * * A full copy (including the 'path' string) of the given * 'source_entry' will be inserted on the index. * * @param index an existing index object * @param source_entry new entry object * @return 0 or an error code */ GIT_EXTERN(int) git_index_add(git_index *index, const git_index_entry *source_entry); /** * Return the stage number from a git index entry * * This entry is calculated from the entry's flag attribute like this: * * (entry->flags & GIT_IDXENTRY_STAGEMASK) >> GIT_IDXENTRY_STAGESHIFT * * @param entry The entry * @returns the stage number */ GIT_EXTERN(int) git_index_entry_stage(const git_index_entry *entry); /**@}*/ /** @name Workdir Index Entry Functions * * These functions work on index entries specifically in the working * directory (ie, stage 0). */ /**@{*/ /** * Add or update an index entry from a file on disk * * The file `path` must be relative to the repository's * working folder and must be readable. * * This method will fail in bare index instances. * * This forces the file to be added to the index, not looking * at gitignore rules. Those rules can be evaluated through * the git_status APIs (in status.h) before calling this. * * If this file currently is the result of a merge conflict, this * file will no longer be marked as conflicting. The data about * the conflict will be moved to the "resolve undo" (REUC) section. * * @param index an existing index object * @param path filename to add * @return 0 or an error code */ GIT_EXTERN(int) git_index_add_bypath(git_index *index, const char *path); /** * Remove an index entry corresponding to a file on disk * * The file `path` must be relative to the repository's * working folder. It may exist. * * If this file currently is the result of a merge conflict, this * file will no longer be marked as conflicting. The data about * the conflict will be moved to the "resolve undo" (REUC) section. * * @param index an existing index object * @param path filename to remove * @return 0 or an error code */ GIT_EXTERN(int) git_index_remove_bypath(git_index *index, const char *path); /** * Add or update index entries matching files in the working directory. * * This method will fail in bare index instances. * * The `pathspec` is a list of file names or shell glob patterns that will * matched against files in the repository's working directory. Each file * that matches will be added to the index (either updating an existing * entry or adding a new entry). You can disable glob expansion and force * exact matching with the `GIT_INDEX_ADD_DISABLE_PATHSPEC_MATCH` flag. * * Files that are ignored will be skipped (unlike `git_index_add_bypath`). * If a file is already tracked in the index, then it *will* be updated * even if it is ignored. Pass the `GIT_INDEX_ADD_FORCE` flag to * skip the checking of ignore rules. * * To emulate `git add -A` and generate an error if the pathspec contains * the exact path of an ignored file (when not using FORCE), add the * `GIT_INDEX_ADD_CHECK_PATHSPEC` flag. This checks that each entry * in the `pathspec` that is an exact match to a filename on disk is * either not ignored or already in the index. If this check fails, the * function will return GIT_EINVALIDSPEC. * * To emulate `git add -A` with the "dry-run" option, just use a callback * function that always returns a positive value. See below for details. * * If any files are currently the result of a merge conflict, those files * will no longer be marked as conflicting. The data about the conflicts * will be moved to the "resolve undo" (REUC) section. * * If you provide a callback function, it will be invoked on each matching * item in the working directory immediately *before* it is added to / * updated in the index. Returning zero will add the item to the index, * greater than zero will skip the item, and less than zero will abort the * scan and cause GIT_EUSER to be returned. * * @param index an existing index object * @param pathspec array of path patterns * @param flags combination of git_index_add_option_t flags * @param callback notification callback for each added/updated path (also * gets index of matching pathspec entry); can be NULL; * return 0 to add, >0 to skip, <0 to abort scan. * @param payload payload passed through to callback function * @return 0 or an error code */ GIT_EXTERN(int) git_index_add_all( git_index *index, const git_strarray *pathspec, unsigned int flags, git_index_matched_path_cb callback, void *payload); /** * Remove all matching index entries. * * If you provide a callback function, it will be invoked on each matching * item in the index immediately *before* it is removed. Return 0 to * remove the item, > 0 to skip the item, and < 0 to abort the scan. * * @param index An existing index object * @param pathspec array of path patterns * @param callback notification callback for each removed path (also * gets index of matching pathspec entry); can be NULL; * return 0 to add, >0 to skip, <0 to abort scan. * @param payload payload passed through to callback function * @return 0 or an error code */ GIT_EXTERN(int) git_index_remove_all( git_index *index, const git_strarray *pathspec, git_index_matched_path_cb callback, void *payload); /** * Update all index entries to match the working directory * * This method will fail in bare index instances. * * This scans the existing index entries and synchronizes them with the * working directory, deleting them if the corresponding working directory * file no longer exists otherwise updating the information (including * adding the latest version of file to the ODB if needed). * * If you provide a callback function, it will be invoked on each matching * item in the index immediately *before* it is updated (either refreshed * or removed depending on working directory state). Return 0 to proceed * with updating the item, > 0 to skip the item, and < 0 to abort the scan. * * @param index An existing index object * @param pathspec array of path patterns * @param callback notification callback for each updated path (also * gets index of matching pathspec entry); can be NULL; * return 0 to add, >0 to skip, <0 to abort scan. * @param payload payload passed through to callback function * @return 0 or an error code */ GIT_EXTERN(int) git_index_update_all( git_index *index, const git_strarray *pathspec, git_index_matched_path_cb callback, void *payload); /** * Find the first position of any entries which point to given * path in the Git index. * * @param at_pos the address to which the position of the index entry is written (optional) * @param index an existing index object * @param path path to search * @return a zero-based position in the index if found; * GIT_ENOTFOUND otherwise */ GIT_EXTERN(int) git_index_find(size_t *at_pos, git_index *index, const char *path); /**@}*/ /** @name Conflict Index Entry Functions * * These functions work on conflict index entries specifically (ie, stages 1-3) */ /**@{*/ /** * Add or update index entries to represent a conflict * * The entries are the entries from the tree included in the merge. Any * entry may be null to indicate that that file was not present in the * trees during the merge. For example, ancestor_entry may be NULL to * indicate that a file was added in both branches and must be resolved. * * @param index an existing index object * @param ancestor_entry the entry data for the ancestor of the conflict * @param our_entry the entry data for our side of the merge conflict * @param their_entry the entry data for their side of the merge conflict * @return 0 or an error code */ GIT_EXTERN(int) git_index_conflict_add( git_index *index, const git_index_entry *ancestor_entry, const git_index_entry *our_entry, const git_index_entry *their_entry); /** * Get the index entries that represent a conflict of a single file. * * The entries are not modifiable and should not be freed. Because the * `git_index_entry` struct is a publicly defined struct, you should * be able to make your own permanent copy of the data if necessary. * * @param ancestor_out Pointer to store the ancestor entry * @param our_out Pointer to store the our entry * @param their_out Pointer to store the their entry * @param index an existing index object * @param path path to search */ GIT_EXTERN(int) git_index_conflict_get( const git_index_entry **ancestor_out, const git_index_entry **our_out, const git_index_entry **their_out, git_index *index, const char *path); /** * Removes the index entries that represent a conflict of a single file. * * @param index an existing index object * @param path to search */ GIT_EXTERN(int) git_index_conflict_remove(git_index *index, const char *path); /** * Remove all conflicts in the index (entries with a stage greater than 0.) * * @param index an existing index object */ GIT_EXTERN(void) git_index_conflict_cleanup(git_index *index); /** * Determine if the index contains entries representing file conflicts. * * @return 1 if at least one conflict is found, 0 otherwise. */ GIT_EXTERN(int) git_index_has_conflicts(const git_index *index); /** * Create an iterator for the conflicts in the index. You may not modify the * index while iterating, the results are undefined. * * @return 0 or an error code */ GIT_EXTERN(int) git_index_conflict_iterator_new( git_index_conflict_iterator **iterator_out, git_index *index); /** * Returns the current conflict (ancestor, ours and theirs entry) and * advance the iterator internally to the next value. * * @param ancestor_out Pointer to store the ancestor side of the conflict * @param our_out Pointer to store our side of the conflict * @param their_out Pointer to store their side of the conflict * @return 0 (no error), GIT_ITEROVER (iteration is done) or an error code * (negative value) */ GIT_EXTERN(int) git_index_conflict_next( const git_index_entry **ancestor_out, const git_index_entry **our_out, const git_index_entry **their_out, git_index_conflict_iterator *iterator); /** * Frees a `git_index_conflict_iterator`. * * @param iterator pointer to the iterator */ GIT_EXTERN(void) git_index_conflict_iterator_free( git_index_conflict_iterator *iterator); /**@}*/ /** @} */ GIT_END_DECL #endif libgit2-0.19.0/include/git2/indexer.h000066400000000000000000000035211216214232500172330ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #ifndef _INCLUDE_git_indexer_h__ #define _INCLUDE_git_indexer_h__ #include "common.h" #include "types.h" #include "oid.h" GIT_BEGIN_DECL typedef struct git_indexer_stream git_indexer_stream; /** * Create a new streaming indexer instance * * @param out where to store the indexer instance * @param path to the directory where the packfile should be stored * @param progress_cb function to call with progress information * @param progress_cb_payload payload for the progress callback */ GIT_EXTERN(int) git_indexer_stream_new( git_indexer_stream **out, const char *path, git_transfer_progress_callback progress_cb, void *progress_cb_payload); /** * Add data to the indexer * * @param idx the indexer * @param data the data to add * @param size the size of the data in bytes * @param stats stat storage */ GIT_EXTERN(int) git_indexer_stream_add(git_indexer_stream *idx, const void *data, size_t size, git_transfer_progress *stats); /** * Finalize the pack and index * * Resolve any pending deltas and write out the index file * * @param idx the indexer */ GIT_EXTERN(int) git_indexer_stream_finalize(git_indexer_stream *idx, git_transfer_progress *stats); /** * Get the packfile's hash * * A packfile's name is derived from the sorted hashing of all object * names. This is only correct after the index has been finalized. * * @param idx the indexer instance */ GIT_EXTERN(const git_oid *) git_indexer_stream_hash(const git_indexer_stream *idx); /** * Free the indexer and its resources * * @param idx the indexer to free */ GIT_EXTERN(void) git_indexer_stream_free(git_indexer_stream *idx); GIT_END_DECL #endif libgit2-0.19.0/include/git2/inttypes.h000066400000000000000000000175311216214232500174620ustar00rootroot00000000000000// ISO C9x compliant inttypes.h for Microsoft Visual Studio // Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124 // // Copyright (c) 2006 Alexander Chemeris // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // 1. Redistributions of source code must retain the above copyright notice, // this list of conditions and the following disclaimer. // // 2. Redistributions in binary form must reproduce the above copyright // notice, this list of conditions and the following disclaimer in the // documentation and/or other materials provided with the distribution. // // 3. The name of the author may be used to endorse or promote products // derived from this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED // WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO // EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; // OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF // ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // /////////////////////////////////////////////////////////////////////////////// #ifndef _MSC_VER // [ #error "Use this header only with Microsoft Visual C++ compilers!" #endif // _MSC_VER ] #ifndef _MSC_INTTYPES_H_ // [ #define _MSC_INTTYPES_H_ #if _MSC_VER > 1000 #pragma once #endif #if _MSC_VER >= 1600 #include #else #include "stdint.h" #endif // 7.8 Format conversion of integer types typedef struct { intmax_t quot; intmax_t rem; } imaxdiv_t; // 7.8.1 Macros for format specifiers #if !defined(__cplusplus) || defined(__STDC_FORMAT_MACROS) // [ See footnote 185 at page 198 // The fprintf macros for signed integers are: #define PRId8 "d" #define PRIi8 "i" #define PRIdLEAST8 "d" #define PRIiLEAST8 "i" #define PRIdFAST8 "d" #define PRIiFAST8 "i" #define PRId16 "hd" #define PRIi16 "hi" #define PRIdLEAST16 "hd" #define PRIiLEAST16 "hi" #define PRIdFAST16 "hd" #define PRIiFAST16 "hi" #define PRId32 "I32d" #define PRIi32 "I32i" #define PRIdLEAST32 "I32d" #define PRIiLEAST32 "I32i" #define PRIdFAST32 "I32d" #define PRIiFAST32 "I32i" #define PRId64 "I64d" #define PRIi64 "I64i" #define PRIdLEAST64 "I64d" #define PRIiLEAST64 "I64i" #define PRIdFAST64 "I64d" #define PRIiFAST64 "I64i" #define PRIdMAX "I64d" #define PRIiMAX "I64i" #define PRIdPTR "Id" #define PRIiPTR "Ii" // The fprintf macros for unsigned integers are: #define PRIo8 "o" #define PRIu8 "u" #define PRIx8 "x" #define PRIX8 "X" #define PRIoLEAST8 "o" #define PRIuLEAST8 "u" #define PRIxLEAST8 "x" #define PRIXLEAST8 "X" #define PRIoFAST8 "o" #define PRIuFAST8 "u" #define PRIxFAST8 "x" #define PRIXFAST8 "X" #define PRIo16 "ho" #define PRIu16 "hu" #define PRIx16 "hx" #define PRIX16 "hX" #define PRIoLEAST16 "ho" #define PRIuLEAST16 "hu" #define PRIxLEAST16 "hx" #define PRIXLEAST16 "hX" #define PRIoFAST16 "ho" #define PRIuFAST16 "hu" #define PRIxFAST16 "hx" #define PRIXFAST16 "hX" #define PRIo32 "I32o" #define PRIu32 "I32u" #define PRIx32 "I32x" #define PRIX32 "I32X" #define PRIoLEAST32 "I32o" #define PRIuLEAST32 "I32u" #define PRIxLEAST32 "I32x" #define PRIXLEAST32 "I32X" #define PRIoFAST32 "I32o" #define PRIuFAST32 "I32u" #define PRIxFAST32 "I32x" #define PRIXFAST32 "I32X" #define PRIo64 "I64o" #define PRIu64 "I64u" #define PRIx64 "I64x" #define PRIX64 "I64X" #define PRIoLEAST64 "I64o" #define PRIuLEAST64 "I64u" #define PRIxLEAST64 "I64x" #define PRIXLEAST64 "I64X" #define PRIoFAST64 "I64o" #define PRIuFAST64 "I64u" #define PRIxFAST64 "I64x" #define PRIXFAST64 "I64X" #define PRIoMAX "I64o" #define PRIuMAX "I64u" #define PRIxMAX "I64x" #define PRIXMAX "I64X" #define PRIoPTR "Io" #define PRIuPTR "Iu" #define PRIxPTR "Ix" #define PRIXPTR "IX" // The fscanf macros for signed integers are: #define SCNd8 "d" #define SCNi8 "i" #define SCNdLEAST8 "d" #define SCNiLEAST8 "i" #define SCNdFAST8 "d" #define SCNiFAST8 "i" #define SCNd16 "hd" #define SCNi16 "hi" #define SCNdLEAST16 "hd" #define SCNiLEAST16 "hi" #define SCNdFAST16 "hd" #define SCNiFAST16 "hi" #define SCNd32 "ld" #define SCNi32 "li" #define SCNdLEAST32 "ld" #define SCNiLEAST32 "li" #define SCNdFAST32 "ld" #define SCNiFAST32 "li" #define SCNd64 "I64d" #define SCNi64 "I64i" #define SCNdLEAST64 "I64d" #define SCNiLEAST64 "I64i" #define SCNdFAST64 "I64d" #define SCNiFAST64 "I64i" #define SCNdMAX "I64d" #define SCNiMAX "I64i" #ifdef _WIN64 // [ # define SCNdPTR "I64d" # define SCNiPTR "I64i" #else // _WIN64 ][ # define SCNdPTR "ld" # define SCNiPTR "li" #endif // _WIN64 ] // The fscanf macros for unsigned integers are: #define SCNo8 "o" #define SCNu8 "u" #define SCNx8 "x" #define SCNX8 "X" #define SCNoLEAST8 "o" #define SCNuLEAST8 "u" #define SCNxLEAST8 "x" #define SCNXLEAST8 "X" #define SCNoFAST8 "o" #define SCNuFAST8 "u" #define SCNxFAST8 "x" #define SCNXFAST8 "X" #define SCNo16 "ho" #define SCNu16 "hu" #define SCNx16 "hx" #define SCNX16 "hX" #define SCNoLEAST16 "ho" #define SCNuLEAST16 "hu" #define SCNxLEAST16 "hx" #define SCNXLEAST16 "hX" #define SCNoFAST16 "ho" #define SCNuFAST16 "hu" #define SCNxFAST16 "hx" #define SCNXFAST16 "hX" #define SCNo32 "lo" #define SCNu32 "lu" #define SCNx32 "lx" #define SCNX32 "lX" #define SCNoLEAST32 "lo" #define SCNuLEAST32 "lu" #define SCNxLEAST32 "lx" #define SCNXLEAST32 "lX" #define SCNoFAST32 "lo" #define SCNuFAST32 "lu" #define SCNxFAST32 "lx" #define SCNXFAST32 "lX" #define SCNo64 "I64o" #define SCNu64 "I64u" #define SCNx64 "I64x" #define SCNX64 "I64X" #define SCNoLEAST64 "I64o" #define SCNuLEAST64 "I64u" #define SCNxLEAST64 "I64x" #define SCNXLEAST64 "I64X" #define SCNoFAST64 "I64o" #define SCNuFAST64 "I64u" #define SCNxFAST64 "I64x" #define SCNXFAST64 "I64X" #define SCNoMAX "I64o" #define SCNuMAX "I64u" #define SCNxMAX "I64x" #define SCNXMAX "I64X" #ifdef _WIN64 // [ # define SCNoPTR "I64o" # define SCNuPTR "I64u" # define SCNxPTR "I64x" # define SCNXPTR "I64X" #else // _WIN64 ][ # define SCNoPTR "lo" # define SCNuPTR "lu" # define SCNxPTR "lx" # define SCNXPTR "lX" #endif // _WIN64 ] #endif // __STDC_FORMAT_MACROS ] // 7.8.2 Functions for greatest-width integer types // 7.8.2.1 The imaxabs function #define imaxabs _abs64 // 7.8.2.2 The imaxdiv function // This is modified version of div() function from Microsoft's div.c found // in %MSVC.NET%\crt\src\div.c #ifdef STATIC_IMAXDIV // [ static #else // STATIC_IMAXDIV ][ _inline #endif // STATIC_IMAXDIV ] imaxdiv_t __cdecl imaxdiv(intmax_t numer, intmax_t denom) { imaxdiv_t result; result.quot = numer / denom; result.rem = numer % denom; if (numer < 0 && result.rem > 0) { // did division wrong; must fix up ++result.quot; result.rem -= denom; } return result; } // 7.8.2.3 The strtoimax and strtoumax functions #define strtoimax _strtoi64 #define strtoumax _strtoui64 // 7.8.2.4 The wcstoimax and wcstoumax functions #define wcstoimax _wcstoi64 #define wcstoumax _wcstoui64 #endif // _MSC_INTTYPES_H_ ] libgit2-0.19.0/include/git2/merge.h000066400000000000000000000113031216214232500166710ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #ifndef INCLUDE_git_merge_h__ #define INCLUDE_git_merge_h__ #include "git2/common.h" #include "git2/types.h" #include "git2/oid.h" #include "git2/checkout.h" #include "git2/index.h" /** * @file git2/merge.h * @brief Git merge routines * @defgroup git_merge Git merge routines * @ingroup Git * @{ */ GIT_BEGIN_DECL /** * Flags for `git_merge_tree` options. A combination of these flags can be * passed in via the `flags` value in the `git_merge_tree_opts`. */ typedef enum { /** Detect renames */ GIT_MERGE_TREE_FIND_RENAMES = (1 << 0), } git_merge_tree_flag_t; /** * Automerge options for `git_merge_trees_opts`. */ typedef enum { GIT_MERGE_AUTOMERGE_NORMAL = 0, GIT_MERGE_AUTOMERGE_NONE = 1, GIT_MERGE_AUTOMERGE_FAVOR_OURS = 2, GIT_MERGE_AUTOMERGE_FAVOR_THEIRS = 3, } git_merge_automerge_flags; typedef struct { unsigned int version; git_merge_tree_flag_t flags; /** Similarity to consider a file renamed (default 50) */ unsigned int rename_threshold; /** Maximum similarity sources to examine (overrides the * `merge.renameLimit` config) (default 200) */ unsigned int target_limit; /** Pluggable similarity metric; pass NULL to use internal metric */ git_diff_similarity_metric *metric; /** Flags for automerging content. */ git_merge_automerge_flags automerge_flags; } git_merge_tree_opts; #define GIT_MERGE_TREE_OPTS_VERSION 1 #define GIT_MERGE_TREE_OPTS_INIT {GIT_MERGE_TREE_OPTS_VERSION} /** * Find a merge base between two commits * * @param out the OID of a merge base between 'one' and 'two' * @param repo the repository where the commits exist * @param one one of the commits * @param two the other commit * @return Zero on success; GIT_ENOTFOUND or -1 on failure. */ GIT_EXTERN(int) git_merge_base( git_oid *out, git_repository *repo, const git_oid *one, const git_oid *two); /** * Find a merge base given a list of commits * * @param out the OID of a merge base considering all the commits * @param repo the repository where the commits exist * @param input_array oids of the commits * @param length The number of commits in the provided `input_array` * @return Zero on success; GIT_ENOTFOUND or -1 on failure. */ GIT_EXTERN(int) git_merge_base_many( git_oid *out, git_repository *repo, const git_oid input_array[], size_t length); /** * Creates a `git_merge_head` from the given reference * * @param out pointer to store the git_merge_head result in * @param repo repository that contains the given reference * @param ref reference to use as a merge input * @return zero on success, -1 on failure. */ GIT_EXTERN(int) git_merge_head_from_ref( git_merge_head **out, git_repository *repo, git_reference *ref); /** * Creates a `git_merge_head` from the given fetch head data * * @param out pointer to store the git_merge_head result in * @param repo repository that contains the given commit * @param branch_name name of the (remote) branch * @param remote_url url of the remote * @param oid the commit object id to use as a merge input * @return zero on success, -1 on failure. */ GIT_EXTERN(int) git_merge_head_from_fetchhead( git_merge_head **out, git_repository *repo, const char *branch_name, const char *remote_url, const git_oid *oid); /** * Creates a `git_merge_head` from the given commit id * * @param out pointer to store the git_merge_head result in * @param repo repository that contains the given commit * @param oid the commit object id to use as a merge input * @return zero on success, -1 on failure. */ GIT_EXTERN(int) git_merge_head_from_oid( git_merge_head **out, git_repository *repo, const git_oid *oid); /** * Frees a `git_merge_head` * * @param head merge head to free */ GIT_EXTERN(void) git_merge_head_free( git_merge_head *head); /** * Merge two trees, producing a `git_index` that reflects the result of * the merge. * * The returned index must be freed explicitly with `git_index_free`. * * @param out pointer to store the index result in * @param repo repository that contains the given trees * @param ancestor_tree the common ancestor between the trees (or null if none) * @param our_tree the tree that reflects the destination tree * @param their_tree the tree to merge in to `our_tree` * @param opts the merge tree options (or null for defaults) * @return zero on success, -1 on failure. */ GIT_EXTERN(int) git_merge_trees( git_index **out, git_repository *repo, const git_tree *ancestor_tree, const git_tree *our_tree, const git_tree *their_tree, const git_merge_tree_opts *opts); /** @} */ GIT_END_DECL #endif libgit2-0.19.0/include/git2/message.h000066400000000000000000000023711216214232500172230ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #ifndef INCLUDE_git_message_h__ #define INCLUDE_git_message_h__ #include "common.h" /** * @file git2/message.h * @brief Git message management routines * @ingroup Git * @{ */ GIT_BEGIN_DECL /** * Clean up message from excess whitespace and make sure that the last line * ends with a '\n'. * * Optionally, can remove lines starting with a "#". * * @param out The user-allocated buffer which will be filled with the * cleaned up message. Pass NULL if you just want to get the needed * size of the prettified message as the output value. * * @param out_size Size of the `out` buffer in bytes. * * @param message The message to be prettified. * * @param strip_comments Non-zero to remove lines starting with "#", 0 to * leave them in. * * @return -1 on error, else number of characters in prettified message * including the trailing NUL byte */ GIT_EXTERN(int) git_message_prettify( char *out, size_t out_size, const char *message, int strip_comments); /** @} */ GIT_END_DECL #endif /* INCLUDE_git_message_h__ */ libgit2-0.19.0/include/git2/net.h000066400000000000000000000020041216214232500163560ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #ifndef INCLUDE_git_net_h__ #define INCLUDE_git_net_h__ #include "common.h" #include "oid.h" #include "types.h" /** * @file git2/net.h * @brief Git networking declarations * @ingroup Git * @{ */ GIT_BEGIN_DECL #define GIT_DEFAULT_PORT "9418" /* * We need this because we need to know whether we should call * git-upload-pack or git-receive-pack on the remote end when get_refs * gets called. */ typedef enum { GIT_DIRECTION_FETCH = 0, GIT_DIRECTION_PUSH = 1 } git_direction; /** * Remote head description, given out on `ls` calls. */ struct git_remote_head { int local; /* available locally */ git_oid oid; git_oid loid; char *name; }; /** * Callback for listing the remote heads */ typedef int (*git_headlist_cb)(git_remote_head *rhead, void *payload); /** @} */ GIT_END_DECL #endif libgit2-0.19.0/include/git2/notes.h000066400000000000000000000121611216214232500167250ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #ifndef INCLUDE_git_note_h__ #define INCLUDE_git_note_h__ #include "oid.h" /** * @file git2/notes.h * @brief Git notes management routines * @defgroup git_note Git notes management routines * @ingroup Git * @{ */ GIT_BEGIN_DECL /** * Callback for git_note_foreach. * * Receives: * - blob_id: Oid of the blob containing the message * - annotated_object_id: Oid of the git object being annotated * - payload: Payload data passed to `git_note_foreach` */ typedef int (*git_note_foreach_cb)( const git_oid *blob_id, const git_oid *annotated_object_id, void *payload); /** * note iterator */ typedef struct git_iterator git_note_iterator; /** * Creates a new iterator for notes * * The iterator must be freed manually by the user. * * @param out pointer to the iterator * @param repo repository where to look up the note * @param notes_ref canonical name of the reference to use (optional); defaults to * "refs/notes/commits" * * @return 0 or an error code */ GIT_EXTERN(int) git_note_iterator_new( git_note_iterator **out, git_repository *repo, const char *notes_ref); /** * Frees an git_note_iterator * * @param it pointer to the iterator */ GIT_EXTERN(void) git_note_iterator_free(git_note_iterator *it); /** * Returns the current item (note_id and annotated_id) and advance the iterator * internally to the next value * * The notes must not be freed manually by the user. * * @param it pointer to the iterator * @param note_id id of blob containing the message * @param annotated_id id of the git object being annotated * * @return 0 (no error), GIT_ITEROVER (iteration is done) or an error code * (negative value) */ GIT_EXTERN(int) git_note_next( git_oid* note_id, git_oid* annotated_id, git_note_iterator *it); /** * Read the note for an object * * The note must be freed manually by the user. * * @param out pointer to the read note; NULL in case of error * @param repo repository where to look up the note * @param notes_ref canonical name of the reference to use (optional); defaults to * "refs/notes/commits" * @param oid OID of the git object to read the note from * * @return 0 or an error code */ GIT_EXTERN(int) git_note_read( git_note **out, git_repository *repo, const char *notes_ref, const git_oid *oid); /** * Get the note message * * @param note * @return the note message */ GIT_EXTERN(const char *) git_note_message(const git_note *note); /** * Get the note object OID * * @param note * @return the note object OID */ GIT_EXTERN(const git_oid *) git_note_oid(const git_note *note); /** * Add a note for an object * * @param out pointer to store the OID (optional); NULL in case of error * @param repo repository where to store the note * @param author signature of the notes commit author * @param committer signature of the notes commit committer * @param notes_ref canonical name of the reference to use (optional); * defaults to "refs/notes/commits" * @param oid OID of the git object to decorate * @param note Content of the note to add for object oid * @param force Overwrite existing note * * @return 0 or an error code */ GIT_EXTERN(int) git_note_create( git_oid *out, git_repository *repo, const git_signature *author, const git_signature *committer, const char *notes_ref, const git_oid *oid, const char *note, int force); /** * Remove the note for an object * * @param repo repository where the note lives * @param notes_ref canonical name of the reference to use (optional); * defaults to "refs/notes/commits" * @param author signature of the notes commit author * @param committer signature of the notes commit committer * @param oid OID of the git object to remove the note from * * @return 0 or an error code */ GIT_EXTERN(int) git_note_remove( git_repository *repo, const char *notes_ref, const git_signature *author, const git_signature *committer, const git_oid *oid); /** * Free a git_note object * * @param note git_note object */ GIT_EXTERN(void) git_note_free(git_note *note); /** * Get the default notes reference for a repository * * @param out Pointer to the default notes reference * @param repo The Git repository * * @return 0 or an error code */ GIT_EXTERN(int) git_note_default_ref(const char **out, git_repository *repo); /** * Loop over all the notes within a specified namespace * and issue a callback for each one. * * @param repo Repository where to find the notes. * * @param notes_ref Reference to read from (optional); defaults to * "refs/notes/commits". * * @param note_cb Callback to invoke per found annotation. Return non-zero * to stop looping. * * @param payload Extra parameter to callback function. * * @return 0 on success, GIT_EUSER on non-zero callback, or error code */ GIT_EXTERN(int) git_note_foreach( git_repository *repo, const char *notes_ref, git_note_foreach_cb note_cb, void *payload); /** @} */ GIT_END_DECL #endif libgit2-0.19.0/include/git2/object.h000066400000000000000000000137221216214232500170470ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #ifndef INCLUDE_git_object_h__ #define INCLUDE_git_object_h__ #include "common.h" #include "types.h" #include "oid.h" /** * @file git2/object.h * @brief Git revision object management routines * @defgroup git_object Git revision object management routines * @ingroup Git * @{ */ GIT_BEGIN_DECL /** * Lookup a reference to one of the objects in a repository. * * The generated reference is owned by the repository and * should be closed with the `git_object_free` method * instead of free'd manually. * * The 'type' parameter must match the type of the object * in the odb; the method will fail otherwise. * The special value 'GIT_OBJ_ANY' may be passed to let * the method guess the object's type. * * @param object pointer to the looked-up object * @param repo the repository to look up the object * @param id the unique identifier for the object * @param type the type of the object * @return a reference to the object */ GIT_EXTERN(int) git_object_lookup( git_object **object, git_repository *repo, const git_oid *id, git_otype type); /** * Lookup a reference to one of the objects in a repository, * given a prefix of its identifier (short id). * * The object obtained will be so that its identifier * matches the first 'len' hexadecimal characters * (packets of 4 bits) of the given 'id'. * 'len' must be at least GIT_OID_MINPREFIXLEN, and * long enough to identify a unique object matching * the prefix; otherwise the method will fail. * * The generated reference is owned by the repository and * should be closed with the `git_object_free` method * instead of free'd manually. * * The 'type' parameter must match the type of the object * in the odb; the method will fail otherwise. * The special value 'GIT_OBJ_ANY' may be passed to let * the method guess the object's type. * * @param object_out pointer where to store the looked-up object * @param repo the repository to look up the object * @param id a short identifier for the object * @param len the length of the short identifier * @param type the type of the object * @return 0 or an error code */ GIT_EXTERN(int) git_object_lookup_prefix( git_object **object_out, git_repository *repo, const git_oid *id, size_t len, git_otype type); /** * Get the id (SHA1) of a repository object * * @param obj the repository object * @return the SHA1 id */ GIT_EXTERN(const git_oid *) git_object_id(const git_object *obj); /** * Get the object type of an object * * @param obj the repository object * @return the object's type */ GIT_EXTERN(git_otype) git_object_type(const git_object *obj); /** * Get the repository that owns this object * * Freeing or calling `git_repository_close` on the * returned pointer will invalidate the actual object. * * Any other operation may be run on the repository without * affecting the object. * * @param obj the object * @return the repository who owns this object */ GIT_EXTERN(git_repository *) git_object_owner(const git_object *obj); /** * Close an open object * * This method instructs the library to close an existing * object; note that git_objects are owned and cached by the repository * so the object may or may not be freed after this library call, * depending on how aggressive is the caching mechanism used * by the repository. * * IMPORTANT: * It *is* necessary to call this method when you stop using * an object. Failure to do so will cause a memory leak. * * @param object the object to close */ GIT_EXTERN(void) git_object_free(git_object *object); /** * Convert an object type to it's string representation. * * The result is a pointer to a string in static memory and * should not be free()'ed. * * @param type object type to convert. * @return the corresponding string representation. */ GIT_EXTERN(const char *) git_object_type2string(git_otype type); /** * Convert a string object type representation to it's git_otype. * * @param str the string to convert. * @return the corresponding git_otype. */ GIT_EXTERN(git_otype) git_object_string2type(const char *str); /** * Determine if the given git_otype is a valid loose object type. * * @param type object type to test. * @return true if the type represents a valid loose object type, * false otherwise. */ GIT_EXTERN(int) git_object_typeisloose(git_otype type); /** * Get the size in bytes for the structure which * acts as an in-memory representation of any given * object type. * * For all the core types, this would the equivalent * of calling `sizeof(git_commit)` if the core types * were not opaque on the external API. * * @param type object type to get its size * @return size in bytes of the object */ GIT_EXTERN(size_t) git_object__size(git_otype type); /** * Recursively peel an object until an object of the specified type is met. * * The retrieved `peeled` object is owned by the repository and should be * closed with the `git_object_free` method. * * If you pass `GIT_OBJ_ANY` as the target type, then the object will be * peeled until the type changes (e.g. a tag will be chased until the * referenced object is no longer a tag). * * @param peeled Pointer to the peeled git_object * @param object The object to be processed * @param target_type The type of the requested object (GIT_OBJ_COMMIT, * GIT_OBJ_TAG, GIT_OBJ_TREE, GIT_OBJ_BLOB or GIT_OBJ_ANY). * @return 0 on success, GIT_EAMBIGUOUS, GIT_ENOTFOUND or an error code */ GIT_EXTERN(int) git_object_peel( git_object **peeled, const git_object *object, git_otype target_type); /** * Create an in-memory copy of a Git object. The copy must be * explicitly free'd or it will leak. * * @param dest Pointer to store the copy of the object * @param source Original object to copy */ GIT_EXTERN(int) git_object_dup(git_object **dest, git_object *source); /** @} */ GIT_END_DECL #endif libgit2-0.19.0/include/git2/odb.h000066400000000000000000000333711216214232500163470ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #ifndef INCLUDE_git_odb_h__ #define INCLUDE_git_odb_h__ #include "common.h" #include "types.h" #include "oid.h" /** * @file git2/odb.h * @brief Git object database routines * @defgroup git_odb Git object database routines * @ingroup Git * @{ */ GIT_BEGIN_DECL /** * Function type for callbacks from git_odb_foreach. */ typedef int (*git_odb_foreach_cb)(const git_oid *id, void *payload); /** * Create a new object database with no backends. * * Before the ODB can be used for read/writing, a custom database * backend must be manually added using `git_odb_add_backend()` * * @param out location to store the database pointer, if opened. * Set to NULL if the open failed. * @return 0 or an error code */ GIT_EXTERN(int) git_odb_new(git_odb **out); /** * Create a new object database and automatically add * the two default backends: * * - git_odb_backend_loose: read and write loose object files * from disk, assuming `objects_dir` as the Objects folder * * - git_odb_backend_pack: read objects from packfiles, * assuming `objects_dir` as the Objects folder which * contains a 'pack/' folder with the corresponding data * * @param out location to store the database pointer, if opened. * Set to NULL if the open failed. * @param objects_dir path of the backends' "objects" directory. * @return 0 or an error code */ GIT_EXTERN(int) git_odb_open(git_odb **out, const char *objects_dir); /** * Add an on-disk alternate to an existing Object DB. * * Note that the added path must point to an `objects`, not * to a full repository, to use it as an alternate store. * * Alternate backends are always checked for objects *after* * all the main backends have been exhausted. * * Writing is disabled on alternate backends. * * @param odb database to add the backend to * @param path path to the objects folder for the alternate * @return 0 on success; error code otherwise */ GIT_EXTERN(int) git_odb_add_disk_alternate(git_odb *odb, const char *path); /** * Close an open object database. * * @param db database pointer to close. If NULL no action is taken. */ GIT_EXTERN(void) git_odb_free(git_odb *db); /** * Read an object from the database. * * This method queries all available ODB backends * trying to read the given OID. * * The returned object is reference counted and * internally cached, so it should be closed * by the user once it's no longer in use. * * @param out pointer where to store the read object * @param db database to search for the object in. * @param id identity of the object to read. * @return * - 0 if the object was read; * - GIT_ENOTFOUND if the object is not in the database. */ GIT_EXTERN(int) git_odb_read(git_odb_object **out, git_odb *db, const git_oid *id); /** * Read an object from the database, given a prefix * of its identifier. * * This method queries all available ODB backends * trying to match the 'len' first hexadecimal * characters of the 'short_id'. * The remaining (GIT_OID_HEXSZ-len)*4 bits of * 'short_id' must be 0s. * 'len' must be at least GIT_OID_MINPREFIXLEN, * and the prefix must be long enough to identify * a unique object in all the backends; the * method will fail otherwise. * * 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 short_id a prefix of the id of the object to read. * @param len the length of the prefix * @return * - 0 if the object was read; * - GIT_ENOTFOUND if the object is not in the database. * - GIT_EAMBIGUOUS if the prefix is ambiguous (several objects match the prefix) */ GIT_EXTERN(int) git_odb_read_prefix(git_odb_object **out, git_odb *db, const git_oid *short_id, size_t len); /** * Read the header of an object from the database, without * reading its full contents. * * The header includes the length and the type of an object. * * Note that most backends do not support reading only the header * of an object, so the whole object will be read and then the * header will be returned. * * @param len_out pointer where to store the length * @param type_out pointer where to store the type * @param db database to search for the object in. * @param id identity of the object to read. * @return * - 0 if the object was read; * - GIT_ENOTFOUND if the object is not in the database. */ GIT_EXTERN(int) git_odb_read_header(size_t *len_out, git_otype *type_out, git_odb *db, const git_oid *id); /** * Determine if the given object can be found in the object database. * * @param db database to be searched for the given object. * @param id the object to search for. * @return * - 1, if the object was found * - 0, otherwise */ GIT_EXTERN(int) git_odb_exists(git_odb *db, const git_oid *id); /** * Refresh the object database to load newly added files. * * If the object databases have changed on disk while the library * is running, this function will force a reload of the underlying * indexes. * * Use this function when you're confident that an external * application has tampered with the ODB. * * NOTE that it is not necessary to call this function at all. The * library will automatically attempt to refresh the ODB * when a lookup fails, to see if the looked up object exists * on disk but hasn't been loaded yet. * * @param db database to refresh * @return 0 on success, error code otherwise */ GIT_EXTERN(int) git_odb_refresh(struct git_odb *db); /** * List all objects available in the database * * The callback will be called for each object available in the * database. Note that the objects are likely to be returned in the index * order, which would make accessing the objects in that order inefficient. * Return a non-zero value from the callback to stop looping. * * @param db database to use * @param cb the callback to call for each object * @param payload data to pass to the callback * @return 0 on success, GIT_EUSER on non-zero callback, or error code */ GIT_EXTERN(int) git_odb_foreach(git_odb *db, git_odb_foreach_cb cb, void *payload); /** * 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 out 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 store * @param len size of the buffer * @param type type of the data to store * @return 0 or an error code */ GIT_EXTERN(int) git_odb_write(git_oid *out, 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 out 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 **out, 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 out 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 **out, git_odb *db, const git_oid *oid); /** * Open a stream for writing a pack file to the ODB. * * If the ODB layer understands pack files, then the given * packfile will likely be streamed directly to disk (and a * corresponding index created). If the ODB layer does not * understand pack files, the objects will be stored in whatever * format the ODB layer uses. * * @see git_odb_writepack * * @param out pointer to the writepack functions * @param db object database where the stream will read from * @param progress_cb function to call with progress information. * Be aware that this is called inline with network and indexing operations, * so performance may be affected. * @param progress_payload payload for the progress callback */ GIT_EXTERN(int) git_odb_write_pack( git_odb_writepack **out, git_odb *db, git_transfer_progress_callback progress_cb, void *progress_payload); /** * Determine the object-ID (sha1 hash) of a data buffer * * The resulting SHA-1 OID will be the identifier for the data * buffer as if the data buffer it were to written to the ODB. * * @param out the resulting object-ID. * @param data data to hash * @param len size of the data * @param type of the data to hash * @return 0 or an error code */ GIT_EXTERN(int) git_odb_hash(git_oid *out, const void *data, size_t len, git_otype type); /** * Read a file from disk and fill a git_oid with the object id * that the file would have if it were written to the Object * Database as an object of the given type (w/o applying filters). * Similar functionality to git.git's `git hash-object` without * the `-w` flag, however, with the --no-filters flag. * If you need filters, see git_repository_hashfile. * * @param out oid structure the result is written into. * @param path file to read and determine object id for * @param type the type of the object that will be hashed * @return 0 or an error code */ GIT_EXTERN(int) git_odb_hashfile(git_oid *out, const char *path, 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_free(git_odb_object *object); /** * Return the OID of an ODB object * * This is the OID from which the object was read from * * @param object the object * @return a pointer to the OID */ GIT_EXTERN(const git_oid *) git_odb_object_id(git_odb_object *object); /** * Return the data of an ODB object * * This is the uncompressed, raw data as read from the ODB, * without the leading header. * * This pointer is owned by the object and shall not be free'd. * * @param object the object * @return a pointer to the data */ GIT_EXTERN(const void *) git_odb_object_data(git_odb_object *object); /** * Return the size of an ODB object * * This is the real size of the `data` buffer, not the * actual size of the object. * * @param object the object * @return the size */ GIT_EXTERN(size_t) git_odb_object_size(git_odb_object *object); /** * Return the type of an ODB object * * @param object the object * @return the type */ GIT_EXTERN(git_otype) git_odb_object_type(git_odb_object *object); /** * Add a custom backend to an existing Object DB * * The backends are checked in relative ordering, based on the * value of the `priority` parameter. * * Read for more information. * * @param odb database to add the backend to * @param backend pointer to a git_odb_backend instance * @param priority Value for ordering the backends queue * @return 0 on success; error code otherwise */ GIT_EXTERN(int) git_odb_add_backend(git_odb *odb, git_odb_backend *backend, int priority); /** * Add a custom backend to an existing Object DB; this * backend will work as an alternate. * * Alternate backends are always checked for objects *after* * all the main backends have been exhausted. * * The backends are checked in relative ordering, based on the * value of the `priority` parameter. * * Writing is disabled on alternate backends. * * Read for more information. * * @param odb database to add the backend to * @param backend pointer to a git_odb_backend instance * @param priority Value for ordering the backends queue * @return 0 on success; error code otherwise */ GIT_EXTERN(int) git_odb_add_alternate(git_odb *odb, git_odb_backend *backend, int priority); /** * Get the number of ODB backend objects * * @param odb object database * @return number of backends in the ODB */ GIT_EXTERN(size_t) git_odb_num_backends(git_odb *odb); /** * Lookup an ODB backend object by index * * @param out output pointer to ODB backend at pos * @param odb object database * @param pos index into object database backend list * @return 0 on success; GIT_ENOTFOUND if pos is invalid; other errors < 0 */ GIT_EXTERN(int) git_odb_get_backend(git_odb_backend **out, git_odb *odb, size_t pos); /** @} */ GIT_END_DECL #endif libgit2-0.19.0/include/git2/odb_backend.h000066400000000000000000000047661216214232500200240ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #ifndef INCLUDE_git_odb_backend_h__ #define INCLUDE_git_odb_backend_h__ #include "git2/common.h" #include "git2/types.h" /** * @file git2/backend.h * @brief Git custom backend functions * @defgroup git_odb Git object database routines * @ingroup Git * @{ */ GIT_BEGIN_DECL /* * Constructors for in-box ODB backends. */ /** * Create a backend for the packfiles. * * @param out location to store the odb backend pointer * @param objects_dir the Git repository's objects directory * * @return 0 or an error code */ GIT_EXTERN(int) git_odb_backend_pack(git_odb_backend **out, const char *objects_dir); /** * Create a backend for loose objects * * @param out location to store the odb backend pointer * @param objects_dir the Git repository's objects directory * @param compression_level zlib compression level to use * @param do_fsync whether to do an fsync() after writing (currently ignored) * * @return 0 or an error code */ GIT_EXTERN(int) git_odb_backend_loose(git_odb_backend **out, const char *objects_dir, int compression_level, int do_fsync); /** * Create a backend out of a single packfile * * This can be useful for inspecting the contents of a single * packfile. * * @param out location to store the odb backend pointer * @param index_file path to the packfile's .idx file * * @return 0 or an error code */ GIT_EXTERN(int) git_odb_backend_one_pack(git_odb_backend **out, const char *index_file); /** 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_stream_t; /** A stream to read/write from a backend */ struct git_odb_stream { git_odb_backend *backend; unsigned int mode; int (*read)(git_odb_stream *stream, char *buffer, size_t len); int (*write)(git_odb_stream *stream, const char *buffer, size_t len); int (*finalize_write)(git_oid *oid_p, git_odb_stream *stream); void (*free)(git_odb_stream *stream); }; /** A stream to write a pack file to the ODB */ struct git_odb_writepack { git_odb_backend *backend; int (*add)(git_odb_writepack *writepack, const void *data, size_t size, git_transfer_progress *stats); int (*commit)(git_odb_writepack *writepack, git_transfer_progress *stats); void (*free)(git_odb_writepack *writepack); }; GIT_END_DECL #endif libgit2-0.19.0/include/git2/oid.h000066400000000000000000000201031216214232500163430ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #ifndef INCLUDE_git_oid_h__ #define INCLUDE_git_oid_h__ #include "common.h" #include "types.h" /** * @file git2/oid.h * @brief Git object id routines * @defgroup git_oid Git object id routines * @ingroup Git * @{ */ GIT_BEGIN_DECL /** Size (in bytes) of a raw/binary oid */ #define GIT_OID_RAWSZ 20 /** Size (in bytes) of a hex formatted oid */ #define GIT_OID_HEXSZ (GIT_OID_RAWSZ * 2) /** Minimum length (in number of hex characters, * i.e. packets of 4 bits) of an oid prefix */ #define GIT_OID_MINPREFIXLEN 4 /** Unique identity of any object (commit, tree, blob, tag). */ typedef struct git_oid { /** raw binary formatted id */ unsigned char id[GIT_OID_RAWSZ]; } git_oid; /** * Parse a hex formatted object id into a git_oid. * * @param out oid structure the result is written into. * @param str input hex string; must be pointing at the start of * the hex sequence and have at least the number of bytes * needed for an oid encoded in hex (40 bytes). * @return 0 or an error code */ GIT_EXTERN(int) git_oid_fromstr(git_oid *out, const char *str); /** * Parse a hex formatted null-terminated string into a git_oid. * * @param out oid structure the result is written into. * @param str input hex string; must be at least 4 characters * long and null-terminated. * @return 0 or an error code */ GIT_EXTERN(int) git_oid_fromstrp(git_oid *out, const char *str); /** * Parse N characters of a hex formatted object id into a git_oid * * If N is odd, N-1 characters will be parsed instead. * The remaining space in the git_oid will be set to zero. * * @param out oid structure the result is written into. * @param str input hex string of at least size `length` * @param length length of the input string * @return 0 or an error code */ GIT_EXTERN(int) git_oid_fromstrn(git_oid *out, const char *str, size_t length); /** * Copy an already raw oid into a git_oid structure. * * @param out oid structure the result is written into. * @param raw the raw input bytes to be copied. */ GIT_EXTERN(void) git_oid_fromraw(git_oid *out, const unsigned char *raw); /** * Format a git_oid into a hex string. * * @param out output hex string; must be pointing at the start of * the hex sequence and have at least the number of bytes * needed for an oid encoded in hex (40 bytes). Only the * oid digits are written; a '\\0' terminator must be added * by the caller if it is required. * @param id oid structure to format. */ GIT_EXTERN(void) git_oid_fmt(char *out, const git_oid *id); /** * Format a git_oid into a partial hex string. * * @param out output hex string; you say how many bytes to write. * If the number of bytes is > GIT_OID_HEXSZ, extra bytes * will be zeroed; if not, a '\0' terminator is NOT added. * @param n number of characters to write into out string * @param id oid structure to format. */ GIT_EXTERN(void) git_oid_nfmt(char *out, size_t n, const git_oid *id); /** * Format a git_oid into a loose-object path string. * * The resulting string is "aa/...", where "aa" is the first two * hex digits of the oid and "..." is the remaining 38 digits. * * @param out output hex string; must be pointing at the start of * the hex sequence and have at least the number of bytes * needed for an oid encoded in hex (41 bytes). Only the * oid digits are written; a '\\0' terminator must be added * by the caller if it is required. * @param id oid structure to format. */ GIT_EXTERN(void) git_oid_pathfmt(char *out, const git_oid *id); /** * Format a git_oid into a newly allocated c-string. * * @param id the oid structure to format * @return the c-string; NULL if memory is exhausted. Caller must * deallocate the string with git__free(). */ GIT_EXTERN(char *) git_oid_allocfmt(const git_oid *id); /** * Format a git_oid into a buffer as a hex format c-string. * * If the buffer is smaller than GIT_OID_HEXSZ+1, then the resulting * oid c-string will be truncated to n-1 characters (but will still be * NUL-byte terminated). * * If there are any input parameter errors (out == NULL, n == 0, oid == * NULL), then a pointer to an empty string is returned, so that the * return value can always be printed. * * @param out the buffer into which the oid string is output. * @param n the size of the out buffer. * @param id the oid structure to format. * @return the out buffer pointer, assuming no input parameter * errors, otherwise a pointer to an empty string. */ GIT_EXTERN(char *) git_oid_tostr(char *out, size_t n, const git_oid *id); /** * Copy an oid from one structure to another. * * @param out oid structure the result is written into. * @param src oid structure to copy from. */ GIT_EXTERN(void) git_oid_cpy(git_oid *out, const git_oid *src); /** * Compare two oid structures. * * @param a first oid structure. * @param b second oid structure. * @return <0, 0, >0 if a < b, a == b, a > b. */ GIT_EXTERN(int) git_oid_cmp(const git_oid *a, const git_oid *b); /** * Compare two oid structures for equality * * @param a first oid structure. * @param b second oid structure. * @return true if equal, false otherwise */ GIT_INLINE(int) git_oid_equal(const git_oid *a, const git_oid *b) { return !git_oid_cmp(a, b); } /** * Compare the first 'len' hexadecimal characters (packets of 4 bits) * of two oid structures. * * @param a first oid structure. * @param b second oid structure. * @param len the number of hex chars to compare * @return 0 in case of a match */ GIT_EXTERN(int) git_oid_ncmp(const git_oid *a, const git_oid *b, size_t len); /** * Check if an oid equals an hex formatted object id. * * @param id oid structure. * @param str input hex string of an object id. * @return GIT_ENOTOID if str is not a valid hex string, * 0 in case of a match, GIT_ERROR otherwise. */ GIT_EXTERN(int) git_oid_streq(const git_oid *id, const char *str); /** * Compare an oid to an hex formatted object id. * * @param id oid structure. * @param str input hex string of an object id. * @return -1 if str is not valid, <0 if id sorts before str, * 0 if id matches str, >0 if id sorts after str. */ GIT_EXTERN(int) git_oid_strcmp(const git_oid *id, const char *str); /** * Check is an oid is all zeros. * * @return 1 if all zeros, 0 otherwise. */ GIT_EXTERN(int) git_oid_iszero(const git_oid *id); /** * OID Shortener object */ typedef struct git_oid_shorten git_oid_shorten; /** * Create a new OID shortener. * * The OID shortener is used to process a list of OIDs * in text form and return the shortest length that would * uniquely identify all of them. * * E.g. look at the result of `git log --abbrev`. * * @param min_length The minimal length for all identifiers, * which will be used even if shorter OIDs would still * be unique. * @return a `git_oid_shorten` instance, NULL if OOM */ GIT_EXTERN(git_oid_shorten *) git_oid_shorten_new(size_t min_length); /** * Add a new OID to set of shortened OIDs and calculate * the minimal length to uniquely identify all the OIDs in * the set. * * The OID is expected to be a 40-char hexadecimal string. * The OID is owned by the user and will not be modified * or freed. * * For performance reasons, there is a hard-limit of how many * OIDs can be added to a single set (around ~22000, assuming * a mostly randomized distribution), which should be enough * for any kind of program, and keeps the algorithm fast and * memory-efficient. * * Attempting to add more than those OIDs will result in a * GIT_ENOMEM error * * @param os a `git_oid_shorten` instance * @param text_id an OID in text form * @return the minimal length to uniquely identify all OIDs * added so far to the set; or an error code (<0) if an * error occurs. */ GIT_EXTERN(int) git_oid_shorten_add(git_oid_shorten *os, const char *text_id); /** * Free an OID shortener instance * * @param os a `git_oid_shorten` instance */ GIT_EXTERN(void) git_oid_shorten_free(git_oid_shorten *os); /** @} */ GIT_END_DECL #endif libgit2-0.19.0/include/git2/pack.h000066400000000000000000000107771216214232500165260ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #ifndef INCLUDE_git_pack_h__ #define INCLUDE_git_pack_h__ #include "common.h" #include "oid.h" /** * @file git2/pack.h * @brief Git pack management routines * * Packing objects * --------------- * * Creation of packfiles requires two steps: * * - First, insert all the objects you want to put into the packfile * using `git_packbuilder_insert` and `git_packbuilder_insert_tree`. * It's important to add the objects in recency order ("in the order * that they are 'reachable' from head"). * * "ANY order will give you a working pack, ... [but it is] the thing * that gives packs good locality. It keeps the objects close to the * head (whether they are old or new, but they are _reachable_ from the * head) at the head of the pack. So packs actually have absolutely * _wonderful_ IO patterns." - Linus Torvalds * git.git/Documentation/technical/pack-heuristics.txt * * - Second, use `git_packbuilder_write` or `git_packbuilder_foreach` to * write the resulting packfile. * * libgit2 will take care of the delta ordering and generation. * `git_packbuilder_set_threads` can be used to adjust the number of * threads used for the process. * * See tests-clar/pack/packbuilder.c for an example. * * @ingroup Git * @{ */ GIT_BEGIN_DECL /** * Initialize a new packbuilder * * @param out The new packbuilder object * @param repo The repository * * @return 0 or an error code */ GIT_EXTERN(int) git_packbuilder_new(git_packbuilder **out, git_repository *repo); /** * Set number of threads to spawn * * By default, libgit2 won't spawn any threads at all; * when set to 0, libgit2 will autodetect the number of * CPUs. * * @param pb The packbuilder * @param n Number of threads to spawn * @return number of actual threads to be used */ GIT_EXTERN(unsigned int) git_packbuilder_set_threads(git_packbuilder *pb, unsigned int n); /** * Insert a single object * * For an optimal pack it's mandatory to insert objects in recency order, * commits followed by trees and blobs. * * @param pb The packbuilder * @param id The oid of the commit * @param name The name; might be NULL * * @return 0 or an error code */ GIT_EXTERN(int) git_packbuilder_insert(git_packbuilder *pb, const git_oid *id, const char *name); /** * Insert a root tree object * * This will add the tree as well as all referenced trees and blobs. * * @param pb The packbuilder * @param id The oid of the root tree * * @return 0 or an error code */ GIT_EXTERN(int) git_packbuilder_insert_tree(git_packbuilder *pb, const git_oid *id); /** * Insert a commit object * * This will add a commit as well as the completed referenced tree. * * @param pb The packbuilder * @param id The oid of the commit * * @return 0 or an error code */ GIT_EXTERN(int) git_packbuilder_insert_commit(git_packbuilder *pb, const git_oid *id); /** * Write the new pack and corresponding index file to path. * * @param pb The packbuilder * @param path to the directory where the packfile and index should be stored * @param progress_cb function to call with progress information from the indexer (optional) * @param progress_cb_payload payload for the progress callback (optional) * * @return 0 or an error code */ GIT_EXTERN(int) git_packbuilder_write( git_packbuilder *pb, const char *path, git_transfer_progress_callback progress_cb, void *progress_cb_payload); typedef int (*git_packbuilder_foreach_cb)(void *buf, size_t size, void *payload); /** * Create the new pack and pass each object to the callback * * @param pb the packbuilder * @param cb the callback to call with each packed object's buffer * @param payload the callback's data * @return 0 or an error code */ GIT_EXTERN(int) git_packbuilder_foreach(git_packbuilder *pb, git_packbuilder_foreach_cb cb, void *payload); /** * Get the total number of objects the packbuilder will write out * * @param pb the packbuilder * @return */ GIT_EXTERN(uint32_t) git_packbuilder_object_count(git_packbuilder *pb); /** * Get the number of objects the packbuilder has already written out * * @param pb the packbuilder * @return */ GIT_EXTERN(uint32_t) git_packbuilder_written(git_packbuilder *pb); /** * Free the packbuilder and all associated data * * @param pb The packbuilder */ GIT_EXTERN(void) git_packbuilder_free(git_packbuilder *pb); /** @} */ GIT_END_DECL #endif libgit2-0.19.0/include/git2/push.h000066400000000000000000000062011216214232500165520ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #ifndef INCLUDE_git_push_h__ #define INCLUDE_git_push_h__ #include "common.h" /** * @file git2/push.h * @brief Git push management functions * @defgroup git_push push management functions * @ingroup Git * @{ */ GIT_BEGIN_DECL /** * Controls the behavior of a git_push object. */ typedef struct { unsigned int version; /** * If the transport being used to push to the remote requires the creation * of a pack file, this controls the number of worker threads used by * the packbuilder when creating that pack file to be sent to the remote. * * If set to 0, the packbuilder will auto-detect the number of threads * to create. The default value is 1. */ unsigned int pb_parallelism; } git_push_options; #define GIT_PUSH_OPTIONS_VERSION 1 #define GIT_PUSH_OPTIONS_INIT { GIT_PUSH_OPTIONS_VERSION } /** * Create a new push object * * @param out New push object * @param remote Remote instance * * @return 0 or an error code */ GIT_EXTERN(int) git_push_new(git_push **out, git_remote *remote); /** * Set options on a push object * * @param push The push object * @param opts The options to set on the push object * * @return 0 or an error code */ GIT_EXTERN(int) git_push_set_options( git_push *push, const git_push_options *opts); /** * Add a refspec to be pushed * * @param push The push object * @param refspec Refspec string * * @return 0 or an error code */ GIT_EXTERN(int) git_push_add_refspec(git_push *push, const char *refspec); /** * Update remote tips after a push * * @param push The push object * * @return 0 or an error code */ GIT_EXTERN(int) git_push_update_tips(git_push *push); /** * Actually push all given refspecs * * Note: To check if the push was successful (i.e. all remote references * have been updated as requested), you need to call both * `git_push_unpack_ok` and `git_push_status_foreach`. The remote * repository might have refused to update some or all of the references. * * @param push The push object * * @return 0 or an error code */ GIT_EXTERN(int) git_push_finish(git_push *push); /** * Check if remote side successfully unpacked * * @param push The push object * * @return true if equal, false otherwise */ GIT_EXTERN(int) git_push_unpack_ok(git_push *push); /** * Call callback `cb' on each status * * For each of the updated references, we receive a status report in the * form of `ok refs/heads/master` or `ng refs/heads/master `. * `msg != NULL` means the reference has not been updated for the given * reason. * * @param push The push object * @param cb The callback to call on each object * * @return 0 on success, GIT_EUSER on non-zero callback, or error code */ GIT_EXTERN(int) git_push_status_foreach(git_push *push, int (*cb)(const char *ref, const char *msg, void *data), void *data); /** * Free the given push object * * @param push The push object */ GIT_EXTERN(void) git_push_free(git_push *push); /** @} */ GIT_END_DECL #endif libgit2-0.19.0/include/git2/refdb.h000066400000000000000000000034631216214232500166640ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #ifndef INCLUDE_git_refdb_h__ #define INCLUDE_git_refdb_h__ #include "common.h" #include "types.h" #include "oid.h" #include "refs.h" /** * @file git2/refdb.h * @brief Git custom refs backend functions * @defgroup git_refdb Git custom refs backend API * @ingroup Git * @{ */ GIT_BEGIN_DECL /** * Create a new reference database with no backends. * * Before the Ref DB can be used for read/writing, a custom database * backend must be manually set using `git_refdb_set_backend()` * * @param out location to store the database pointer, if opened. * Set to NULL if the open failed. * @param repo the repository * @return 0 or an error code */ GIT_EXTERN(int) git_refdb_new(git_refdb **out, git_repository *repo); /** * Create a new reference database and automatically add * the default backends: * * - git_refdb_dir: read and write loose and packed refs * from disk, assuming the repository dir as the folder * * @param out location to store the database pointer, if opened. * Set to NULL if the open failed. * @param repo the repository * @return 0 or an error code */ GIT_EXTERN(int) git_refdb_open(git_refdb **out, git_repository *repo); /** * Suggests that the given refdb compress or optimize its references. * This mechanism is implementation specific. For on-disk reference * databases, for example, this may pack all loose references. */ GIT_EXTERN(int) git_refdb_compress(git_refdb *refdb); /** * Close an open reference database. * * @param refdb reference database pointer or NULL */ GIT_EXTERN(void) git_refdb_free(git_refdb *refdb); /** @} */ GIT_END_DECL #endif libgit2-0.19.0/include/git2/reflog.h000066400000000000000000000105531216214232500170560ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #ifndef INCLUDE_git_reflog_h__ #define INCLUDE_git_reflog_h__ #include "common.h" #include "types.h" #include "oid.h" /** * @file git2/reflog.h * @brief Git reflog management routines * @defgroup git_reflog Git reflog management routines * @ingroup Git * @{ */ GIT_BEGIN_DECL /** * Read the reflog for the given reference * * If there is no reflog file for the given * reference yet, an empty reflog object will * be returned. * * The reflog must be freed manually by using * git_reflog_free(). * * @param out pointer to reflog * @param ref reference to read the reflog for * @return 0 or an error code */ GIT_EXTERN(int) git_reflog_read(git_reflog **out, const git_reference *ref); /** * Write an existing in-memory reflog object back to disk * using an atomic file lock. * * @param reflog an existing reflog object * @return 0 or an error code */ GIT_EXTERN(int) git_reflog_write(git_reflog *reflog); /** * Add a new entry to the reflog. * * `msg` is optional and can be NULL. * * @param reflog an existing reflog object * @param id the OID the reference is now pointing to * @param committer the signature of the committer * @param msg the reflog message * @return 0 or an error code */ GIT_EXTERN(int) git_reflog_append(git_reflog *reflog, const git_oid *id, const git_signature *committer, const char *msg); /** * Rename the reflog for the given reference * * The reflog to be renamed is expected to already exist * * The new name will be checked for validity. * See `git_reference_create_symbolic()` for rules about valid names. * * @param ref the reference * @param name the new name of the reference * @return 0 on success, GIT_EINVALIDSPEC or an error code */ GIT_EXTERN(int) git_reflog_rename(git_reference *ref, const char *name); /** * Delete the reflog for the given reference * * @param ref the reference * @return 0 or an error code */ GIT_EXTERN(int) git_reflog_delete(git_reference *ref); /** * Get the number of log entries in a reflog * * @param reflog the previously loaded reflog * @return the number of log entries */ GIT_EXTERN(size_t) git_reflog_entrycount(git_reflog *reflog); /** * Lookup an entry by its index * * Requesting the reflog entry with an index of 0 (zero) will * return the most recently created entry. * * @param reflog a previously loaded reflog * @param idx the position of the entry to lookup. Should be greater than or * equal to 0 (zero) and less than `git_reflog_entrycount()`. * @return the entry; NULL if not found */ GIT_EXTERN(const git_reflog_entry *) git_reflog_entry_byindex(git_reflog *reflog, size_t idx); /** * Remove an entry from the reflog by its index * * To ensure there's no gap in the log history, set `rewrite_previous_entry` * param value to 1. When deleting entry `n`, member old_oid of entry `n-1` * (if any) will be updated with the value of member new_oid of entry `n+1`. * * @param reflog a previously loaded reflog. * * @param idx the position of the entry to remove. Should be greater than or * equal to 0 (zero) and less than `git_reflog_entrycount()`. * * @param rewrite_previous_entry 1 to rewrite the history; 0 otherwise. * * @return 0 on success, GIT_ENOTFOUND if the entry doesn't exist * or an error code. */ GIT_EXTERN(int) git_reflog_drop( git_reflog *reflog, size_t idx, int rewrite_previous_entry); /** * Get the old oid * * @param entry a reflog entry * @return the old oid */ GIT_EXTERN(const git_oid *) git_reflog_entry_id_old(const git_reflog_entry *entry); /** * Get the new oid * * @param entry a reflog entry * @return the new oid at this time */ GIT_EXTERN(const git_oid *) git_reflog_entry_id_new(const git_reflog_entry *entry); /** * Get the committer of this entry * * @param entry a reflog entry * @return the committer */ GIT_EXTERN(const git_signature *) git_reflog_entry_committer(const git_reflog_entry *entry); /** * Get the log message * * @param entry a reflog entry * @return the log msg */ GIT_EXTERN(const char *) git_reflog_entry_message(const git_reflog_entry *entry); /** * Free the reflog * * @param reflog reflog to free */ GIT_EXTERN(void) git_reflog_free(git_reflog *reflog); /** @} */ GIT_END_DECL #endif libgit2-0.19.0/include/git2/refs.h000066400000000000000000000446231216214232500165440ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #ifndef INCLUDE_git_refs_h__ #define INCLUDE_git_refs_h__ #include "common.h" #include "types.h" #include "oid.h" #include "strarray.h" /** * @file git2/refs.h * @brief Git reference management routines * @defgroup git_reference Git reference management routines * @ingroup Git * @{ */ GIT_BEGIN_DECL /** * Lookup a reference by name in a repository. * * The returned reference must be freed by the user. * * The name will be checked for validity. * See `git_reference_create_symbolic()` for rules about valid names. * * @param out pointer to the looked-up reference * @param repo the repository to look up the reference * @param name the long name for the reference (e.g. HEAD, refs/heads/master, refs/tags/v0.1.0, ...) * @return 0 on success, ENOTFOUND, EINVALIDSPEC or an error code. */ GIT_EXTERN(int) git_reference_lookup(git_reference **out, git_repository *repo, const char *name); /** * Lookup a reference by name and resolve immediately to OID. * * This function provides a quick way to resolve a reference name straight * through to the object id that it refers to. This avoids having to * allocate or free any `git_reference` objects for simple situations. * * The name will be checked for validity. * See `git_reference_symbolic_create()` for rules about valid names. * * @param out Pointer to oid to be filled in * @param repo The repository in which to look up the reference * @param name The long name for the reference (e.g. HEAD, refs/heads/master, refs/tags/v0.1.0, ...) * @return 0 on success, ENOTFOUND, EINVALIDSPEC or an error code. */ GIT_EXTERN(int) git_reference_name_to_id( git_oid *out, git_repository *repo, const char *name); /** * Lookup a reference by DWIMing its short name * * Apply the git precendence rules to the given shorthand to determine * which reference the user is refering to. * * @param out pointer in which to store the reference * @param repo the repository in which to look * @param shorthand the short name for the reference * @return 0 or an error code */ GIT_EXTERN(int) git_reference_dwim(git_reference **out, git_repository *repo, const char *shorthand); /** * Create a new symbolic reference. * * A symbolic reference is a reference name that refers to another * reference name. If the other name moves, the symbolic name will move, * too. As a simple example, the "HEAD" reference might refer to * "refs/heads/master" while on the "master" branch of a repository. * * The symbolic reference will be created in the repository and written to * the disk. The generated reference object must be freed by the user. * * Valid reference names must follow one of two patterns: * * 1. Top-level names must contain only capital letters and underscores, * and must begin and end with a letter. (e.g. "HEAD", "ORIG_HEAD"). * 2. Names prefixed with "refs/" can be almost anything. You must avoid * the characters '~', '^', ':', '\\', '?', '[', and '*', and the * sequences ".." and "@{" which have special meaning to revparse. * * This function will return an error if a reference already exists with the * given name unless `force` is true, in which case it will be overwritten. * * @param 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 * @param force Overwrite existing references * @return 0 on success, EEXISTS, EINVALIDSPEC or an error code */ GIT_EXTERN(int) git_reference_symbolic_create(git_reference **out, git_repository *repo, const char *name, const char *target, int force); /** * Create a new direct reference. * * A direct reference (also called an object id reference) refers directly * to a specific object id (a.k.a. OID or SHA) in the repository. The id * permanently refers to the object (although the reference itself can be * moved). For example, in libgit2 the direct ref "refs/tags/v0.17.0" * refers to OID 5b9fac39d8a76b9139667c26a63e6b3f204b3977. * * The direct reference will be created in the repository and written to * the disk. The generated reference object must be freed by the user. * * Valid reference names must follow one of two patterns: * * 1. Top-level names must contain only capital letters and underscores, * and must begin and end with a letter. (e.g. "HEAD", "ORIG_HEAD"). * 2. Names prefixed with "refs/" can be almost anything. You must avoid * the characters '~', '^', ':', '\\', '?', '[', and '*', and the * sequences ".." and "@{" which have special meaning to revparse. * * This function will return an error if a reference already exists with the * given name unless `force` is true, in which case it will be overwritten. * * @param 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. * @param force Overwrite existing references * @return 0 on success, EEXISTS, EINVALIDSPEC or an error code */ GIT_EXTERN(int) git_reference_create(git_reference **out, git_repository *repo, const char *name, const git_oid *id, int force); /** * Get the OID pointed to by a direct reference. * * Only available if the reference is direct (i.e. an object id reference, * not a symbolic one). * * To find the OID of a symbolic ref, call `git_reference_resolve()` and * then this function (or maybe use `git_reference_name_to_id()` to * directly resolve a reference name all the way through to an OID). * * @param ref The reference * @return a pointer to the oid if available, NULL otherwise */ GIT_EXTERN(const git_oid *) git_reference_target(const git_reference *ref); /** * Return the peeled OID target of this reference. * * This peeled OID only applies to direct references that point to * a hard Tag object: it is the result of peeling such Tag. * * @param ref The reference * @return a pointer to the oid if available, NULL otherwise */ GIT_EXTERN(const git_oid *) git_reference_target_peel(const git_reference *ref); /** * Get full name to the reference pointed to by a symbolic reference. * * Only available if the reference is symbolic. * * @param ref The reference * @return a pointer to the name if available, NULL otherwise */ GIT_EXTERN(const char *) git_reference_symbolic_target(const git_reference *ref); /** * Get the type of a reference. * * Either direct (GIT_REF_OID) or symbolic (GIT_REF_SYMBOLIC) * * @param ref The reference * @return the type */ GIT_EXTERN(git_ref_t) git_reference_type(const git_reference *ref); /** * Get the full name of a reference. * * See `git_reference_create_symbolic()` for rules about valid names. * * @param ref The reference * @return the full name for the ref */ GIT_EXTERN(const char *) git_reference_name(const git_reference *ref); /** * Resolve a symbolic reference to a direct reference. * * This method iteratively peels a symbolic reference until it resolves to * a direct reference to an OID. * * The peeled reference is returned in the `resolved_ref` argument, and * must be freed manually once it's no longer needed. * * If a direct reference is passed as an argument, a copy of that * reference is returned. This copy must be manually freed too. * * @param out Pointer to the peeled reference * @param ref The reference * @return 0 or an error code */ GIT_EXTERN(int) git_reference_resolve(git_reference **out, const git_reference *ref); /** * Get the repository where a reference resides. * * @param ref The reference * @return a pointer to the repo */ GIT_EXTERN(git_repository *) git_reference_owner(const git_reference *ref); /** * Create a new reference with the same name as the given reference but a * different symbolic target. The reference must be a symbolic reference, * otherwise this will fail. * * The new reference will be written to disk, overwriting the given reference. * * The target name will be checked for validity. * See `git_reference_create_symbolic()` for rules about valid names. * * @param out Pointer to the newly created reference * @param ref The reference * @param target The new target for the reference * @return 0 on success, EINVALIDSPEC or an error code */ GIT_EXTERN(int) git_reference_symbolic_set_target( git_reference **out, git_reference *ref, const char *target); /** * Create a new reference with the same name as the given reference but a * different OID target. The reference must be a direct reference, otherwise * this will fail. * * The new reference will be written to disk, overwriting the given reference. * * @param out Pointer to the newly created reference * @param ref The reference * @param id The new target OID for the reference * @return 0 or an error code */ GIT_EXTERN(int) git_reference_set_target( git_reference **out, git_reference *ref, const git_oid *id); /** * Rename an existing reference. * * This method works for both direct and symbolic references. * * The new name will be checked for validity. * See `git_reference_create_symbolic()` for rules about valid names. * * If the `force` flag is not enabled, and there's already * a reference with the given name, the renaming will fail. * * IMPORTANT: * The user needs to write a proper reflog entry if the * reflog is enabled for the repository. We only rename * the reflog if it exists. * * @param ref The reference to rename * @param new_name The new name for the reference * @param force Overwrite an existing reference * @return 0 on success, EINVALIDSPEC, EEXISTS or an error code * */ GIT_EXTERN(int) git_reference_rename( git_reference **new_ref, git_reference *ref, const char *new_name, int force); /** * Delete an existing reference. * * This method works for both direct and symbolic references. The reference * will be immediately removed on disk but the memory will not be freed. * Callers must call `git_reference_free`. * * @param ref The reference to remove * @return 0 or an error code */ GIT_EXTERN(int) git_reference_delete(git_reference *ref); /** * Fill a list with all the references that can be found in a repository. * * 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 * @return 0 or an error code */ GIT_EXTERN(int) git_reference_list(git_strarray *array, git_repository *repo); typedef int (*git_reference_foreach_cb)(git_reference *reference, void *payload); typedef int (*git_reference_foreach_name_cb)(const char *name, void *payload); /** * Perform a callback on each reference in the repository. * * The `callback` function will be called for each reference in the * repository, receiving the name of the reference and the `payload` value * passed to this method. Returning a non-zero value from the callback * will terminate the iteration. * * @param repo Repository where to find the refs * @param callback Function which will be called for every listed ref * @param payload Additional data to pass to the callback * @return 0 on success, GIT_EUSER on non-zero callback, or error code */ GIT_EXTERN(int) git_reference_foreach( git_repository *repo, git_reference_foreach_cb callback, void *payload); GIT_EXTERN(int) git_reference_foreach_name( git_repository *repo, git_reference_foreach_name_cb callback, void *payload); /** * Free the given reference. * * @param ref git_reference */ GIT_EXTERN(void) git_reference_free(git_reference *ref); /** * Compare two references. * * @param ref1 The first git_reference * @param ref2 The second git_reference * @return 0 if the same, else a stable but meaningless ordering. */ GIT_EXTERN(int) git_reference_cmp(git_reference *ref1, git_reference *ref2); /** * Create an iterator for the repo's references * * @param out pointer in which to store the iterator * @param repo the repository * @return 0 or an error code */ GIT_EXTERN(int) git_reference_iterator_new( git_reference_iterator **out, git_repository *repo); /** * Create an iterator for the repo's references that match the * specified glob * * @param out pointer in which to store the iterator * @param repo the repository * @param glob the glob to match against the reference names * @return 0 or an error code */ GIT_EXTERN(int) git_reference_iterator_glob_new( git_reference_iterator **out, git_repository *repo, const char *glob); /** * Get the next reference * * @param out pointer in which to store the reference * @param iter the iterator * @return 0, GIT_ITEROVER if there are no more; or an error code */ GIT_EXTERN(int) git_reference_next(git_reference **out, git_reference_iterator *iter); GIT_EXTERN(int) git_reference_next_name(const char **out, git_reference_iterator *iter); /** * Free the iterator and its associated resources * * @param iter the iterator to free */ GIT_EXTERN(void) git_reference_iterator_free(git_reference_iterator *iter); /** * Perform a callback on each reference in the repository whose name * matches the given pattern. * * This function acts like `git_reference_foreach()` with an additional * pattern match being applied to the reference name before issuing the * callback function. See that function for more information. * * The pattern is matched using fnmatch or "glob" style where a '*' matches * any sequence of letters, a '?' matches any letter, and square brackets * can be used to define character ranges (such as "[0-9]" for digits). * * @param repo Repository where to find the refs * @param glob Pattern to match (fnmatch-style) against reference name. * @param callback Function which will be called for every listed ref * @param payload Additional data to pass to the callback * @return 0 on success, GIT_EUSER on non-zero callback, or error code */ GIT_EXTERN(int) git_reference_foreach_glob( git_repository *repo, const char *glob, git_reference_foreach_name_cb callback, void *payload); /** * Check if a reflog exists for the specified reference. * * @param ref A git reference * * @return 0 when no reflog can be found, 1 when it exists; * otherwise an error code. */ GIT_EXTERN(int) git_reference_has_log(git_reference *ref); /** * Check if a reference is a local branch. * * @param ref A git reference * * @return 1 when the reference lives in the refs/heads * namespace; 0 otherwise. */ GIT_EXTERN(int) git_reference_is_branch(git_reference *ref); /** * Check if a reference is a remote tracking branch * * @param ref A git reference * * @return 1 when the reference lives in the refs/remotes * namespace; 0 otherwise. */ GIT_EXTERN(int) git_reference_is_remote(git_reference *ref); typedef enum { GIT_REF_FORMAT_NORMAL = 0, /** * Control whether one-level refnames are accepted * (i.e., refnames that do not contain multiple /-separated * components). Those are expected to be written only using * uppercase letters and underscore (FETCH_HEAD, ...) */ GIT_REF_FORMAT_ALLOW_ONELEVEL = (1 << 0), /** * Interpret the provided name as a reference pattern for a * refspec (as used with remote repositories). If this option * is enabled, the name is allowed to contain a single * () * in place of a one full pathname component * (e.g., foo//bar but not foo/bar). */ GIT_REF_FORMAT_REFSPEC_PATTERN = (1 << 1), /** * Interpret the name as part of a refspec in shorthand form * so the `ONELEVEL` naming rules aren't enforced and 'master' * becomes a valid name. */ GIT_REF_FORMAT_REFSPEC_SHORTHAND = (1 << 2), } git_reference_normalize_t; /** * Normalize reference name and check validity. * * This will normalize the reference name by removing any leading slash * '/' characters and collapsing runs of adjacent slashes between name * components into a single slash. * * Once normalized, if the reference name is valid, it will be returned in * the user allocated buffer. * * See `git_reference_create_symbolic()` for rules about valid names. * * @param buffer_out User allocated buffer to store normalized name * @param buffer_size Size of buffer_out * @param name Reference name to be checked. * @param flags Flags to constrain name validation rules - see the * GIT_REF_FORMAT constants above. * @return 0 on success, GIT_EBUFS if buffer is too small, EINVALIDSPEC * or an error code. */ GIT_EXTERN(int) git_reference_normalize_name( char *buffer_out, size_t buffer_size, const char *name, unsigned int flags); /** * Recursively peel reference until object of the specified type is found. * * The retrieved `peeled` object is owned by the repository * and should be closed with the `git_object_free` method. * * If you pass `GIT_OBJ_ANY` as the target type, then the object * will be peeled until a non-tag object is met. * * @param out Pointer to the peeled git_object * @param ref The reference to be processed * @param type The type of the requested object (GIT_OBJ_COMMIT, * GIT_OBJ_TAG, GIT_OBJ_TREE, GIT_OBJ_BLOB or GIT_OBJ_ANY). * @return 0 on success, GIT_EAMBIGUOUS, GIT_ENOTFOUND or an error code */ GIT_EXTERN(int) git_reference_peel( git_object **out, git_reference *ref, git_otype type); /** * Ensure the reference name is well-formed. * * Valid reference names must follow one of two patterns: * * 1. Top-level names must contain only capital letters and underscores, * and must begin and end with a letter. (e.g. "HEAD", "ORIG_HEAD"). * 2. Names prefixed with "refs/" can be almost anything. You must avoid * the characters '~', '^', ':', '\\', '?', '[', and '*', and the * sequences ".." and "@{" which have special meaning to revparse. * * @param refname name to be checked. * @return 1 if the reference name is acceptable; 0 if it isn't */ GIT_EXTERN(int) git_reference_is_valid_name(const char *refname); /** * Get the reference's short name * * This will transform the reference name into a name "human-readable" * version. If no shortname is appropriate, it will return the full * name. * * The memory is owned by the reference and must not be freed. * * @param ref a reference * @return the human-readable version of the name */ GIT_EXTERN(const char *) git_reference_shorthand(git_reference *ref); /** @} */ GIT_END_DECL #endif libgit2-0.19.0/include/git2/refspec.h000066400000000000000000000055041216214232500172270ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #ifndef INCLUDE_git_refspec_h__ #define INCLUDE_git_refspec_h__ #include "common.h" #include "types.h" #include "net.h" /** * @file git2/refspec.h * @brief Git refspec attributes * @defgroup git_refspec Git refspec attributes * @ingroup Git * @{ */ GIT_BEGIN_DECL /** * Get the source specifier * * @param refspec the refspec * @return the refspec's source specifier */ GIT_EXTERN(const char *) git_refspec_src(const git_refspec *refspec); /** * Get the destination specifier * * @param refspec the refspec * @return the refspec's destination specifier */ GIT_EXTERN(const char *) git_refspec_dst(const git_refspec *refspec); /** * Get the refspec's string * * @param refspec the refspec * @returns the refspec's original string */ GIT_EXTERN(const char *) git_refspec_string(const git_refspec *refspec); /** * Get the force update setting * * @param refspec the refspec * @return 1 if force update has been set, 0 otherwise */ GIT_EXTERN(int) git_refspec_force(const git_refspec *refspec); /** * Get the refspec's direction. * * @param spec refspec * @return GIT_DIRECTION_FETCH or GIT_DIRECTION_PUSH */ GIT_EXTERN(git_direction) git_refspec_direction(const git_refspec *spec); /** * Check if a refspec's source descriptor matches a reference * * @param refspec the refspec * @param refname the name of the reference to check * @return 1 if the refspec matches, 0 otherwise */ GIT_EXTERN(int) git_refspec_src_matches(const git_refspec *refspec, const char *refname); /** * Check if a refspec's destination descriptor matches a reference * * @param refspec the refspec * @param refname the name of the reference to check * @return 1 if the refspec matches, 0 otherwise */ GIT_EXTERN(int) git_refspec_dst_matches(const git_refspec *refspec, const char *refname); /** * Transform a reference to its target following the refspec's rules * * @param out where to store the target name * @param outlen the size of the `out` buffer * @param spec the refspec * @param name the name of the reference to transform * @return 0, GIT_EBUFS or another error */ GIT_EXTERN(int) git_refspec_transform(char *out, size_t outlen, const git_refspec *spec, const char *name); /** * Transform a target reference to its source reference following the refspec's rules * * @param out where to store the source reference name * @param outlen the size of the `out` buffer * @param spec the refspec * @param name the name of the reference to transform * @return 0, GIT_EBUFS or another error */ GIT_EXTERN(int) git_refspec_rtransform(char *out, size_t outlen, const git_refspec *spec, const char *name); GIT_END_DECL #endif libgit2-0.19.0/include/git2/remote.h000066400000000000000000000345411216214232500170760ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #ifndef INCLUDE_git_remote_h__ #define INCLUDE_git_remote_h__ #include "common.h" #include "repository.h" #include "refspec.h" #include "net.h" #include "indexer.h" #include "strarray.h" #include "transport.h" /** * @file git2/remote.h * @brief Git remote management functions * @defgroup git_remote remote management functions * @ingroup Git * @{ */ GIT_BEGIN_DECL typedef int (*git_remote_rename_problem_cb)(const char *problematic_refspec, void *payload); /* * TODO: This functions still need to be implemented: * - _listcb/_foreach * - _add * - _rename * - _del (needs support from config) */ /** * Add a remote with the default fetch refspec to the repository's configuration. This * calls git_remote_save before returning. * * @param out the resulting remote * @param repo the repository in which to create the remote * @param name the remote's name * @param url the remote's url * @return 0, GIT_EINVALIDSPEC, GIT_EEXISTS or an error code */ GIT_EXTERN(int) git_remote_create( git_remote **out, git_repository *repo, const char *name, const char *url); /** * Create a remote in memory * * Create a remote with the given refspec in memory. You can use * this when you have a URL instead of a remote's name. Note that in-memory * remotes cannot be converted to persisted remotes. * * The name, when provided, will be checked for validity. * See `git_tag_create()` for rules about valid names. * * @param out pointer to the new remote object * @param repo the associated repository * @param fetch the fetch refspec to use for this remote. May be NULL for defaults. * @param url the remote repository's URL * @return 0 or an error code */ GIT_EXTERN(int) git_remote_create_inmemory( git_remote **out, git_repository *repo, const char *fetch, const char *url); /** * Get the information for a particular remote * * The name will be checked for validity. * See `git_tag_create()` for rules about valid names. * * @param out pointer to the new remote object * @param repo the associated repository * @param name the remote's name * @return 0, GIT_ENOTFOUND, GIT_EINVALIDSPEC or an error code */ GIT_EXTERN(int) git_remote_load(git_remote **out, git_repository *repo, const char *name); /** * Save a remote to its repository's configuration * * One can't save a in-memory remote. Doing so will * result in a GIT_EINVALIDSPEC being returned. * * @param remote the remote to save to config * @return 0, GIT_EINVALIDSPEC or an error code */ GIT_EXTERN(int) git_remote_save(const git_remote *remote); /** * Get the remote's name * * @param remote the remote * @return a pointer to the name or NULL for in-memory remotes */ GIT_EXTERN(const char *) git_remote_name(const git_remote *remote); /** * Get the remote's url * * @param remote the remote * @return a pointer to the url */ GIT_EXTERN(const char *) git_remote_url(const git_remote *remote); /** * Get the remote's url for pushing * * @param remote the remote * @return a pointer to the url or NULL if no special url for pushing is set */ GIT_EXTERN(const char *) git_remote_pushurl(const git_remote *remote); /** * Set the remote's url * * Existing connections will not be updated. * * @param remote the remote * @param url the url to set * @return 0 or an error value */ GIT_EXTERN(int) git_remote_set_url(git_remote *remote, const char* url); /** * Set the remote's url for pushing * * Existing connections will not be updated. * * @param remote the remote * @param url the url to set or NULL to clear the pushurl * @return 0 or an error value */ GIT_EXTERN(int) git_remote_set_pushurl(git_remote *remote, const char* url); /** * Add a fetch refspec to the remote * * @param remote the remote * @apram refspec the new fetch refspec * @return 0 or an error value */ GIT_EXTERN(int) git_remote_add_fetch(git_remote *remote, const char *refspec); /** * Get the remote's list of fetch refspecs * * The memory is owned by the user and should be freed with * `git_strarray_free`. * * @param array pointer to the array in which to store the strings * @param remote the remote to query */ GIT_EXTERN(int) git_remote_get_fetch_refspecs(git_strarray *array, git_remote *remote); /** * Add a push refspec to the remote * * @param remote the remote * @param refspec the new push refspec * @return 0 or an error value */ GIT_EXTERN(int) git_remote_add_push(git_remote *remote, const char *refspec); /** * Get the remote's list of push refspecs * * The memory is owned by the user and should be freed with * `git_strarray_free`. * * @param array pointer to the array in which to store the strings * @param remote the remote to query */ GIT_EXTERN(int) git_remote_get_push_refspecs(git_strarray *array, git_remote *remote); /** * Clear the refspecs * * Remove all configured fetch and push refspecs from the remote. * * @param remote the remote */ GIT_EXTERN(void) git_remote_clear_refspecs(git_remote *remote); /** * Get the number of refspecs for a remote * * @param remote the remote * @return the amount of refspecs configured in this remote */ GIT_EXTERN(size_t) git_remote_refspec_count(git_remote *remote); /** * Get a refspec from the remote * * @param remote the remote to query * @param n the refspec to get * @return the nth refspec */ GIT_EXTERN(const git_refspec *)git_remote_get_refspec(git_remote *remote, size_t n); /** * Remove a refspec from the remote * * @param remote the remote to query * @param n the refspec to remove * @return 0 or GIT_ENOTFOUND */ GIT_EXTERN(int) git_remote_remove_refspec(git_remote *remote, size_t n); /** * Open a connection to a remote * * The transport is selected based on the URL. The direction argument * is due to a limitation of the git protocol (over TCP or SSH) which * starts up a specific binary which can only do the one or the other. * * @param remote the remote to connect to * @param direction GIT_DIRECTION_FETCH if you want to fetch or * GIT_DIRECTION_PUSH if you want to push * @return 0 or an error code */ GIT_EXTERN(int) git_remote_connect(git_remote *remote, git_direction direction); /** * Get a list of refs at the remote * * The remote (or more exactly its transport) must be connected. The * memory belongs to the remote. * * If you a return a non-zero value from the callback, this will stop * looping over the refs. * * @param remote the remote * @param list_cb function to call with each ref discovered at the remote * @param payload additional data to pass to the callback * @return 0 on success, GIT_EUSER on non-zero callback, or error code */ GIT_EXTERN(int) git_remote_ls(git_remote *remote, git_headlist_cb list_cb, void *payload); /** * Download the packfile * * Negotiate what objects should be downloaded and download the * packfile with those objects. The packfile is downloaded with a * temporary filename, as it's final name is not known yet. If there * was no packfile needed (all the objects were available locally), * filename will be NULL and the function will return success. * * @param remote the remote to download from * @param progress_cb function to call with progress information. Be aware that * this is called inline with network and indexing operations, so performance * may be affected. * @param payload payload for the progress callback * @return 0 or an error code */ GIT_EXTERN(int) git_remote_download( git_remote *remote, git_transfer_progress_callback progress_cb, void *payload); /** * Check whether the remote is connected * * Check whether the remote's underlying transport is connected to the * remote host. * * @param remote the remote * @return 1 if it's connected, 0 otherwise. */ GIT_EXTERN(int) git_remote_connected(git_remote *remote); /** * Cancel the operation * * At certain points in its operation, the network code checks whether * the operation has been cancelled and if so stops the operation. * * @param remote the remote */ GIT_EXTERN(void) git_remote_stop(git_remote *remote); /** * Disconnect from the remote * * Close the connection to the remote and free the underlying * transport. * * @param remote the remote to disconnect from */ GIT_EXTERN(void) git_remote_disconnect(git_remote *remote); /** * Free the memory associated with a remote * * This also disconnects from the remote, if the connection * has not been closed yet (using git_remote_disconnect). * * @param remote the remote to free */ GIT_EXTERN(void) git_remote_free(git_remote *remote); /** * Update the tips to the new state * * @param remote the remote to update * @return 0 or an error code */ GIT_EXTERN(int) git_remote_update_tips(git_remote *remote); /** * Return whether a string is a valid remote URL * * @param url the url to check * @return 1 if the url is valid, 0 otherwise */ GIT_EXTERN(int) git_remote_valid_url(const char *url); /** * Return whether the passed URL is supported by this version of the library. * * @param url the url to check * @return 1 if the url is supported, 0 otherwise */ GIT_EXTERN(int) git_remote_supported_url(const char* url); /** * Get a list of the configured remotes for a repo * * The string array must be freed by the user. * * @param out a string array which receives the names of the remotes * @param repo the repository to query * @return 0 or an error code */ GIT_EXTERN(int) git_remote_list(git_strarray *out, git_repository *repo); /** * Choose whether to check the server's certificate (applies to HTTPS only) * * @param remote the remote to configure * @param check whether to check the server's certificate (defaults to yes) */ GIT_EXTERN(void) git_remote_check_cert(git_remote *remote, int check); /** * Set a credentials acquisition callback for this remote. If the remote is * not available for anonymous access, then you must set this callback in order * to provide credentials to the transport at the time of authentication * failure so that retry can be performed. * * @param remote the remote to configure * @param cred_acquire_cb The credentials acquisition callback to use (defaults * to NULL) */ GIT_EXTERN(void) git_remote_set_cred_acquire_cb( git_remote *remote, git_cred_acquire_cb cred_acquire_cb, void *payload); /** * Sets a custom transport for the remote. The caller can use this function * to bypass the automatic discovery of a transport by URL scheme (i.e. * http://, https://, git://) and supply their own transport to be used * instead. After providing the transport to a remote using this function, * the transport object belongs exclusively to that remote, and the remote will * free it when it is freed with git_remote_free. * * @param remote the remote to configure * @param transport the transport object for the remote to use * @return 0 or an error code */ GIT_EXTERN(int) git_remote_set_transport( git_remote *remote, git_transport *transport); /** * Argument to the completion callback which tells it which operation * finished. */ typedef enum git_remote_completion_type { GIT_REMOTE_COMPLETION_DOWNLOAD, GIT_REMOTE_COMPLETION_INDEXING, GIT_REMOTE_COMPLETION_ERROR, } git_remote_completion_type; /** * The callback settings structure * * Set the calbacks to be called by the remote. */ struct git_remote_callbacks { unsigned int version; void (*progress)(const char *str, int len, void *data); int (*completion)(git_remote_completion_type type, void *data); int (*update_tips)(const char *refname, const git_oid *a, const git_oid *b, void *data); void *payload; }; #define GIT_REMOTE_CALLBACKS_VERSION 1 #define GIT_REMOTE_CALLBACKS_INIT {GIT_REMOTE_CALLBACKS_VERSION} /** * Set the callbacks for a remote * * Note that the remote keeps its own copy of the data and you need to * call this function again if you want to change the callbacks. * * @param remote the remote to configure * @param callbacks a pointer to the user's callback settings * @return 0 or an error code */ GIT_EXTERN(int) git_remote_set_callbacks(git_remote *remote, git_remote_callbacks *callbacks); /** * Get the statistics structure that is filled in by the fetch operation. */ GIT_EXTERN(const git_transfer_progress *) git_remote_stats(git_remote *remote); typedef enum { GIT_REMOTE_DOWNLOAD_TAGS_AUTO = 0, GIT_REMOTE_DOWNLOAD_TAGS_NONE = 1, GIT_REMOTE_DOWNLOAD_TAGS_ALL = 2 } git_remote_autotag_option_t; /** * Retrieve the tag auto-follow setting * * @param remote the remote to query * @return the auto-follow setting */ GIT_EXTERN(git_remote_autotag_option_t) git_remote_autotag(git_remote *remote); /** * Set the tag auto-follow setting * * @param remote the remote to configure * @param value a GIT_REMOTE_DOWNLOAD_TAGS value */ GIT_EXTERN(void) git_remote_set_autotag( git_remote *remote, git_remote_autotag_option_t value); /** * Give the remote a new name * * All remote-tracking branches and configuration settings * for the remote are updated. * * The new name will be checked for validity. * See `git_tag_create()` for rules about valid names. * * A temporary in-memory remote cannot be given a name with this method. * * @param remote the remote to rename * @param new_name the new name the remote should bear * @param callback Optional callback to notify the consumer of fetch refspecs * that haven't been automatically updated and need potential manual tweaking. * @param payload Additional data to pass to the callback * @return 0, GIT_EINVALIDSPEC, GIT_EEXISTS or an error code */ GIT_EXTERN(int) git_remote_rename( git_remote *remote, const char *new_name, git_remote_rename_problem_cb callback, void *payload); /** * Retrieve the update FETCH_HEAD setting. * * @param remote the remote to query * @return the update FETCH_HEAD setting */ GIT_EXTERN(int) git_remote_update_fetchhead(git_remote *remote); /** * Sets the update FETCH_HEAD setting. By default, FETCH_HEAD will be * updated on every fetch. Set to 0 to disable. * * @param remote the remote to configure * @param value 0 to disable updating FETCH_HEAD */ GIT_EXTERN(void) git_remote_set_update_fetchhead(git_remote *remote, int value); /** * Ensure the remote name is well-formed. * * @param remote_name name to be checked. * @return 1 if the reference name is acceptable; 0 if it isn't */ GIT_EXTERN(int) git_remote_is_valid_name(const char *remote_name); /** @} */ GIT_END_DECL #endif libgit2-0.19.0/include/git2/repository.h000066400000000000000000000564141216214232500200250ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #ifndef INCLUDE_git_repository_h__ #define INCLUDE_git_repository_h__ #include "common.h" #include "types.h" #include "oid.h" /** * @file git2/repository.h * @brief Git repository management routines * @defgroup git_repository Git repository management routines * @ingroup Git * @{ */ GIT_BEGIN_DECL /** * Open a git repository. * * The 'path' argument must point to either a git repository * folder, or an existing work dir. * * The method will automatically detect if 'path' is a normal * or bare repository or fail is 'path' is neither. * * @param out pointer to the repo which will be opened * @param path the path to the repository * @return 0 or an error code */ GIT_EXTERN(int) git_repository_open(git_repository **out, const char *path); /** * Create a "fake" repository to wrap an object database * * Create a repository object to wrap an object database to be used * with the API when all you have is an object database. This doesn't * have any paths associated with it, so use with care. * * @param out pointer to the repo * @param odb the object database to wrap * @return 0 or an error code */ GIT_EXTERN(int) git_repository_wrap_odb(git_repository **out, git_odb *odb); /** * Look for a git repository and copy its path in the given buffer. * The lookup start from base_path and walk across parent directories * if nothing has been found. The lookup ends when the first repository * is found, or when reaching a directory referenced in ceiling_dirs * or when the filesystem changes (in case across_fs is true). * * The method will automatically detect if the repository is bare * (if there is a repository). * * @param path_out The user allocated buffer which will * contain the found path. * * @param path_size repository_path size * * @param start_path The base path where the lookup starts. * * @param across_fs If true, then the lookup will not stop when a * filesystem device change is detected while exploring parent directories. * * @param ceiling_dirs A GIT_PATH_LIST_SEPARATOR separated list of * absolute symbolic link free paths. The lookup will stop when any * of this paths is reached. Note that the lookup always performs on * start_path no matter start_path appears in ceiling_dirs ceiling_dirs * might be NULL (which is equivalent to an empty string) * * @return 0 or an error code */ GIT_EXTERN(int) git_repository_discover( char *path_out, size_t path_size, const char *start_path, int across_fs, const char *ceiling_dirs); /** * Option flags for `git_repository_open_ext`. * * * GIT_REPOSITORY_OPEN_NO_SEARCH - Only open the repository if it can be * immediately found in the start_path. Do not walk up from the * start_path looking at parent directories. * * GIT_REPOSITORY_OPEN_CROSS_FS - Unless this flag is set, open will not * continue searching across filesystem boundaries (i.e. when `st_dev` * changes from the `stat` system call). (E.g. Searching in a user's home * directory "/home/user/source/" will not return "/.git/" as the found * repo if "/" is a different filesystem than "/home".) */ typedef enum { GIT_REPOSITORY_OPEN_NO_SEARCH = (1 << 0), GIT_REPOSITORY_OPEN_CROSS_FS = (1 << 1), } git_repository_open_flag_t; /** * Find and open a repository with extended controls. * * @param out Pointer to the repo which will be opened. This can * actually be NULL if you only want to use the error code to * see if a repo at this path could be opened. * @param path Path to open as git repository. If the flags * permit "searching", then this can be a path to a subdirectory * inside the working directory of the repository. * @param flags A combination of the GIT_REPOSITORY_OPEN flags above. * @param ceiling_dirs A GIT_PATH_LIST_SEPARATOR delimited list of path * prefixes at which the search for a containing repository should * terminate. * @return 0 on success, GIT_ENOTFOUND if no repository could be found, * or -1 if there was a repository but open failed for some reason * (such as repo corruption or system errors). */ GIT_EXTERN(int) git_repository_open_ext( git_repository **out, const char *path, unsigned int flags, const char *ceiling_dirs); /** * Open a bare repository on the serverside. * * This is a fast open for bare repositories that will come in handy * if you're e.g. hosting git repositories and need to access them * efficiently * * @param out Pointer to the repo which will be opened. * @param bare_path Direct path to the bare repository * @return 0 on success, or an error code */ GIT_EXTERN(int) git_repository_open_bare(git_repository **out, const char *bare_path); /** * 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_free`, but accessing any of the attributes of * an object without a backing repository will result in undefined * behavior * * @param repo repository handle to close. If NULL nothing occurs. */ GIT_EXTERN(void) git_repository_free(git_repository *repo); /** * Creates a new Git repository in the given folder. * * TODO: * - Reinit the repository * * @param out pointer to the repo which will be created or reinitialized * @param path the path to the repository * @param is_bare if true, a Git repository without a working directory is * created at the pointed path. If false, provided path will be * considered as the working directory into which the .git directory * will be created. * * @return 0 or an error code */ GIT_EXTERN(int) git_repository_init( git_repository **out, const char *path, unsigned is_bare); /** * Option flags for `git_repository_init_ext`. * * These flags configure extra behaviors to `git_repository_init_ext`. * In every case, the default behavior is the zero value (i.e. flag is * not set). Just OR the flag values together for the `flags` parameter * when initializing a new repo. Details of individual values are: * * * BARE - Create a bare repository with no working directory. * * NO_REINIT - Return an EEXISTS error if the repo_path appears to * already be an git repository. * * NO_DOTGIT_DIR - Normally a "/.git/" will be appended to the repo * path for non-bare repos (if it is not already there), but * passing this flag prevents that behavior. * * MKDIR - Make the repo_path (and workdir_path) as needed. Init is * always willing to create the ".git" directory even without this * flag. This flag tells init to create the trailing component of * the repo and workdir paths as needed. * * MKPATH - Recursively make all components of the repo and workdir * paths as necessary. * * EXTERNAL_TEMPLATE - libgit2 normally uses internal templates to * initialize a new repo. This flags enables external templates, * looking the "template_path" from the options if set, or the * `init.templatedir` global config if not, or falling back on * "/usr/share/git-core/templates" if it exists. */ typedef enum { GIT_REPOSITORY_INIT_BARE = (1u << 0), GIT_REPOSITORY_INIT_NO_REINIT = (1u << 1), GIT_REPOSITORY_INIT_NO_DOTGIT_DIR = (1u << 2), GIT_REPOSITORY_INIT_MKDIR = (1u << 3), GIT_REPOSITORY_INIT_MKPATH = (1u << 4), GIT_REPOSITORY_INIT_EXTERNAL_TEMPLATE = (1u << 5), } git_repository_init_flag_t; /** * Mode options for `git_repository_init_ext`. * * Set the mode field of the `git_repository_init_options` structure * either to the custom mode that you would like, or to one of the * following modes: * * * SHARED_UMASK - Use permissions configured by umask - the default. * * SHARED_GROUP - Use "--shared=group" behavior, chmod'ing the new repo * to be group writable and "g+sx" for sticky group assignment. * * SHARED_ALL - Use "--shared=all" behavior, adding world readability. * * Anything else - Set to custom value. */ typedef enum { GIT_REPOSITORY_INIT_SHARED_UMASK = 0, GIT_REPOSITORY_INIT_SHARED_GROUP = 0002775, GIT_REPOSITORY_INIT_SHARED_ALL = 0002777, } git_repository_init_mode_t; /** * Extended options structure for `git_repository_init_ext`. * * This contains extra options for `git_repository_init_ext` that enable * additional initialization features. The fields are: * * * flags - Combination of GIT_REPOSITORY_INIT flags above. * * mode - Set to one of the standard GIT_REPOSITORY_INIT_SHARED_... * constants above, or to a custom value that you would like. * * workdir_path - The path to the working dir or NULL for default (i.e. * repo_path parent on non-bare repos). IF THIS IS RELATIVE PATH, * IT WILL BE EVALUATED RELATIVE TO THE REPO_PATH. If this is not * the "natural" working directory, a .git gitlink file will be * created here linking to the repo_path. * * description - If set, this will be used to initialize the "description" * file in the repository, instead of using the template content. * * template_path - When GIT_REPOSITORY_INIT_EXTERNAL_TEMPLATE is set, * this contains the path to use for the template directory. If * this is NULL, the config or default directory options will be * used instead. * * initial_head - The name of the head to point HEAD at. If NULL, then * this will be treated as "master" and the HEAD ref will be set * to "refs/heads/master". If this begins with "refs/" it will be * used verbatim; otherwise "refs/heads/" will be prefixed. * * origin_url - If this is non-NULL, then after the rest of the * repository initialization is completed, an "origin" remote * will be added pointing to this URL. */ typedef struct { unsigned int version; uint32_t flags; uint32_t mode; const char *workdir_path; const char *description; const char *template_path; const char *initial_head; const char *origin_url; } git_repository_init_options; #define GIT_REPOSITORY_INIT_OPTIONS_VERSION 1 #define GIT_REPOSITORY_INIT_OPTIONS_INIT {GIT_REPOSITORY_INIT_OPTIONS_VERSION} /** * Create a new Git repository in the given folder with extended controls. * * This will initialize a new git repository (creating the repo_path * if requested by flags) and working directory as needed. It will * auto-detect the case sensitivity of the file system and if the * file system supports file mode bits correctly. * * @param out Pointer to the repo which will be created or reinitialized. * @param repo_path The path to the repository. * @param opts Pointer to git_repository_init_options struct. * @return 0 or an error code on failure. */ GIT_EXTERN(int) git_repository_init_ext( git_repository **out, const char *repo_path, git_repository_init_options *opts); /** * Retrieve and resolve the reference pointed at by HEAD. * * The returned `git_reference` will be owned by caller and * `git_reference_free()` must be called when done with it to release the * allocated memory and prevent a leak. * * @param out pointer to the reference which will be retrieved * @param repo a repository object * * @return 0 on success, GIT_EORPHANEDHEAD when HEAD points to a non existing * branch, GIT_ENOTFOUND when HEAD is missing; an error code otherwise */ GIT_EXTERN(int) git_repository_head(git_reference **out, git_repository *repo); /** * Check if a repository's HEAD is detached * * A repository's HEAD is detached when it points directly to a commit * instead of a branch. * * @param repo Repo to test * @return 1 if HEAD is detached, 0 if it's not; error code if there * was an error. */ GIT_EXTERN(int) git_repository_head_detached(git_repository *repo); /** * Check if the current branch is an orphan * * An orphan branch is one named from HEAD but which doesn't exist in * the refs namespace, because it doesn't have any commit to point to. * * @param repo Repo to test * @return 1 if the current branch is an orphan, 0 if it's not; error * code if there was an error */ GIT_EXTERN(int) git_repository_head_orphan(git_repository *repo); /** * Check if a repository is empty * * An empty repository has just been initialized and contains * no references. * * @param repo Repo to test * @return 1 if the repository is empty, 0 if it isn't, error code * if the repository is corrupted */ GIT_EXTERN(int) git_repository_is_empty(git_repository *repo); /** * Get the path of this repository * * This is the path of the `.git` folder for normal repositories, * or of the repository itself for bare repositories. * * @param repo A repository object * @return the path to the repository */ GIT_EXTERN(const char *) git_repository_path(git_repository *repo); /** * Get the path of the working directory for this repository * * If the repository is bare, this function will always return * NULL. * * @param repo A repository object * @return the path to the working dir, if it exists */ GIT_EXTERN(const char *) git_repository_workdir(git_repository *repo); /** * Set the path to the working directory for this repository * * The working directory doesn't need to be the same one * that contains the `.git` folder for this repository. * * If this repository is bare, setting its working directory * will turn it into a normal repository, capable of performing * all the common workdir operations (checkout, status, index * manipulation, etc). * * @param repo A repository object * @param workdir The path to a working directory * @param update_gitlink Create/update gitlink in workdir and set config * "core.worktree" (if workdir is not the parent of the .git directory) * @return 0, or an error code */ GIT_EXTERN(int) git_repository_set_workdir( git_repository *repo, const char *workdir, int update_gitlink); /** * Check if a repository is bare * * @param repo Repo to test * @return 1 if the repository is bare, 0 otherwise. */ GIT_EXTERN(int) git_repository_is_bare(git_repository *repo); /** * Get the configuration file for this repository. * * If a configuration file has not been set, the default * config set for the repository will be returned, including * global and system configurations (if they are available). * * The configuration file must be freed once it's no longer * being used by the user. * * @param out Pointer to store the loaded config file * @param repo A repository object * @return 0, or an error code */ GIT_EXTERN(int) git_repository_config(git_config **out, git_repository *repo); /** * Get the Object Database for this repository. * * If a custom ODB has not been set, the default * database for the repository will be returned (the one * located in `.git/objects`). * * The ODB must be freed once it's no longer being used by * the user. * * @param out Pointer to store the loaded ODB * @param repo A repository object * @return 0, or an error code */ GIT_EXTERN(int) git_repository_odb(git_odb **out, git_repository *repo); /** * Get the Reference Database Backend for this repository. * * If a custom refsdb has not been set, the default database for * the repository will be returned (the one that manipulates loose * and packed references in the `.git` directory). * * The refdb must be freed once it's no longer being used by * the user. * * @param out Pointer to store the loaded refdb * @param repo A repository object * @return 0, or an error code */ GIT_EXTERN(int) git_repository_refdb(git_refdb **out, git_repository *repo); /** * Get the Index file for this repository. * * If a custom index has not been set, the default * index for the repository will be returned (the one * located in `.git/index`). * * The index must be freed once it's no longer being used by * the user. * * @param out Pointer to store the loaded index * @param repo A repository object * @return 0, or an error code */ GIT_EXTERN(int) git_repository_index(git_index **out, git_repository *repo); /** * Retrieve git's prepared message * * Operations such as git revert/cherry-pick/merge with the -n option * stop just short of creating a commit with the changes and save * their prepared message in .git/MERGE_MSG so the next git-commit * execution can present it to the user for them to amend if they * wish. * * Use this function to get the contents of this file. Don't forget to * remove the file after you create the commit. * * If the repository message exists and there are no errors reading it, this * returns the bytes needed to store the message in memory (i.e. message * file size plus one terminating NUL byte). That value is returned even if * `out` is NULL or `len` is shorter than the necessary size. * * The `out` buffer will *always* be NUL terminated, even if truncation * occurs. * * @param out Buffer to write data into or NULL to just read required size * @param len Length of `out` buffer in bytes * @param repo Repository to read prepared message from * @return GIT_ENOUTFOUND if no message exists, other value < 0 for other * errors, or total bytes in message (may be > `len`) on success */ GIT_EXTERN(int) git_repository_message(char *out, size_t len, git_repository *repo); /** * Remove git's prepared message. * * Remove the message that `git_repository_message` retrieves. */ GIT_EXTERN(int) git_repository_message_remove(git_repository *repo); /** * Remove all the metadata associated with an ongoing git merge, including * MERGE_HEAD, MERGE_MSG, etc. * * @param repo A repository object * @return 0 on success, or error */ GIT_EXTERN(int) git_repository_merge_cleanup(git_repository *repo); typedef int (*git_repository_fetchhead_foreach_cb)(const char *ref_name, const char *remote_url, const git_oid *oid, unsigned int is_merge, void *payload); /** * Call callback 'callback' for each entry in the given FETCH_HEAD file. * * @param repo A repository object * @param callback Callback function * @param payload Pointer to callback data (optional) * @return 0 on success, GIT_ENOTFOUND, GIT_EUSER or error */ GIT_EXTERN(int) git_repository_fetchhead_foreach(git_repository *repo, git_repository_fetchhead_foreach_cb callback, void *payload); typedef int (*git_repository_mergehead_foreach_cb)(const git_oid *oid, void *payload); /** * If a merge is in progress, call callback 'cb' for each commit ID in the * MERGE_HEAD file. * * @param repo A repository object * @param callback Callback function * @param payload Pointer to callback data (optional) * @return 0 on success, GIT_ENOTFOUND, GIT_EUSER or error */ GIT_EXTERN(int) git_repository_mergehead_foreach(git_repository *repo, git_repository_mergehead_foreach_cb callback, void *payload); /** * Calculate hash of file using repository filtering rules. * * If you simply want to calculate the hash of a file on disk with no filters, * you can just use the `git_odb_hashfile()` API. However, if you want to * hash a file in the repository and you want to apply filtering rules (e.g. * crlf filters) before generating the SHA, then use this function. * * @param out Output value of calculated SHA * @param repo Repository pointer * @param path Path to file on disk whose contents should be hashed. If the * repository is not NULL, this can be a relative path. * @param type The object type to hash as (e.g. GIT_OBJ_BLOB) * @param as_path The path to use to look up filtering rules. If this is * NULL, then the `path` parameter will be used instead. If * this is passed as the empty string, then no filters will be * applied when calculating the hash. */ GIT_EXTERN(int) git_repository_hashfile( git_oid *out, git_repository *repo, const char *path, git_otype type, const char *as_path); /** * Make the repository HEAD point to the specified reference. * * If the provided reference points to a Tree or a Blob, the HEAD is * unaltered and -1 is returned. * * If the provided reference points to a branch, the HEAD will point * to that branch, staying attached, or become attached if it isn't yet. * If the branch doesn't exist yet, no error will be return. The HEAD * will then be attached to an unborn branch. * * Otherwise, the HEAD will be detached and will directly point to * the Commit. * * @param repo Repository pointer * @param refname Canonical name of the reference the HEAD should point at * @return 0 on success, or an error code */ GIT_EXTERN(int) git_repository_set_head( git_repository* repo, const char* refname); /** * Make the repository HEAD directly point to the Commit. * * If the provided committish cannot be found in the repository, the HEAD * is unaltered and GIT_ENOTFOUND is returned. * * If the provided commitish cannot be peeled into a commit, the HEAD * is unaltered and -1 is returned. * * Otherwise, the HEAD will eventually be detached and will directly point to * the peeled Commit. * * @param repo Repository pointer * @param commitish Object id of the Commit the HEAD should point to * @return 0 on success, or an error code */ GIT_EXTERN(int) git_repository_set_head_detached( git_repository* repo, const git_oid* commitish); /** * Detach the HEAD. * * If the HEAD is already detached and points to a Commit, 0 is returned. * * If the HEAD is already detached and points to a Tag, the HEAD is * updated into making it point to the peeled Commit, and 0 is returned. * * If the HEAD is already detached and points to a non commitish, the HEAD is * unaltered, and -1 is returned. * * Otherwise, the HEAD will be detached and point to the peeled Commit. * * @param repo Repository pointer * @return 0 on success, GIT_EORPHANEDHEAD when HEAD points to a non existing * branch or an error code */ GIT_EXTERN(int) git_repository_detach_head( git_repository* repo); typedef enum { GIT_REPOSITORY_STATE_NONE, GIT_REPOSITORY_STATE_MERGE, GIT_REPOSITORY_STATE_REVERT, GIT_REPOSITORY_STATE_CHERRY_PICK, GIT_REPOSITORY_STATE_BISECT, GIT_REPOSITORY_STATE_REBASE, GIT_REPOSITORY_STATE_REBASE_INTERACTIVE, GIT_REPOSITORY_STATE_REBASE_MERGE, GIT_REPOSITORY_STATE_APPLY_MAILBOX, GIT_REPOSITORY_STATE_APPLY_MAILBOX_OR_REBASE, } git_repository_state_t; /** * Determines the status of a git repository - ie, whether an operation * (merge, cherry-pick, etc) is in progress. * * @param repo Repository pointer * @return The state of the repository */ GIT_EXTERN(int) git_repository_state(git_repository *repo); /** * Sets the active namespace for this Git Repository * * This namespace affects all reference operations for the repo. * See `man gitnamespaces` * * @param repo The repo * @param nmspace The namespace. This should not include the refs * folder, e.g. to namespace all references under `refs/namespaces/foo/`, * use `foo` as the namespace. * @return 0 on success, -1 on error */ GIT_EXTERN(int) git_repository_set_namespace(git_repository *repo, const char *nmspace); /** * Get the currently active namespace for this repository * * @param repo The repo * @return the active namespace, or NULL if there isn't one */ GIT_EXTERN(const char *) git_repository_get_namespace(git_repository *repo); /** * Determine if the repository was a shallow clone * * @param repo The repository * @return 1 if shallow, zero if not */ GIT_EXTERN(int) git_repository_is_shallow(git_repository *repo); /** @} */ GIT_END_DECL #endif libgit2-0.19.0/include/git2/reset.h000066400000000000000000000046261216214232500167260ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #ifndef INCLUDE_git_reset_h__ #define INCLUDE_git_reset_h__ /** * @file git2/reset.h * @brief Git reset management routines * @ingroup Git * @{ */ GIT_BEGIN_DECL /** * Kinds of reset operation */ typedef enum { GIT_RESET_SOFT = 1, /** Move the head to the given commit */ GIT_RESET_MIXED = 2, /** SOFT plus reset index to the commit */ GIT_RESET_HARD = 3, /** MIXED plus changes in working tree discarded */ } git_reset_t; /** * Sets the current head to the specified commit oid and optionally * resets the index and working tree to match. * * SOFT reset means the Head will be moved to the commit. * * MIXED reset will trigger a SOFT reset, plus the index will be replaced * with the content of the commit tree. * * HARD reset will trigger a MIXED reset and the working directory will be * replaced with the content of the index. (Untracked and ignored files * will be left alone, however.) * * TODO: Implement remaining kinds of resets. * * @param repo Repository where to perform the reset operation. * * @param target Committish to which the Head should be moved to. This object * must belong to the given `repo` and can either be a git_commit or a * git_tag. When a git_tag is being passed, it should be dereferencable * to a git_commit which oid will be used as the target of the branch. * * @param reset_type Kind of reset operation to perform. * * @return 0 on success or an error code */ GIT_EXTERN(int) git_reset( git_repository *repo, git_object *target, git_reset_t reset_type); /** * Updates some entries in the index from the target commit tree. * * The scope of the updated entries is determined by the paths * being passed in the `pathspec` parameters. * * Passing a NULL `target` will result in removing * entries in the index matching the provided pathspecs. * * @param repo Repository where to perform the reset operation. * * @param target The committish which content will be used to reset the content * of the index. * * @param pathspecs List of pathspecs to operate on. * * @return 0 on success or an error code < 0 */ GIT_EXTERN(int) git_reset_default( git_repository *repo, git_object *target, git_strarray* pathspecs); /** @} */ GIT_END_DECL #endif libgit2-0.19.0/include/git2/revparse.h000066400000000000000000000062641216214232500174330ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #ifndef INCLUDE_git_revparse_h__ #define INCLUDE_git_revparse_h__ #include "common.h" #include "types.h" /** * @file git2/revparse.h * @brief Git revision parsing routines * @defgroup git_revparse Git revision parsing routines * @ingroup Git * @{ */ GIT_BEGIN_DECL /** * Find a single object, as specified by a revision string. See `man gitrevisions`, * or http://git-scm.com/docs/git-rev-parse.html#_specifying_revisions for * information on the syntax accepted. * * @param out pointer to output object * @param repo the repository to search in * @param spec the textual specification for an object * @return 0 on success, GIT_ENOTFOUND, GIT_EAMBIGUOUS, GIT_EINVALIDSPEC or an error code */ GIT_EXTERN(int) git_revparse_single(git_object **out, git_repository *repo, const char *spec); /** * Find a single object, as specified by a revision string. * See `man gitrevisions`, * or http://git-scm.com/docs/git-rev-parse.html#_specifying_revisions for * information on the syntax accepted. * * In some cases (`@{<-n>}` or `@{upstream}`), the expression may * point to an intermediate reference. When such expressions are being passed * in, `reference_out` will be valued as well. * * @param object_out pointer to output object * @param reference_out pointer to output reference or NULL * @param repo the repository to search in * @param spec the textual specification for an object * @return 0 on success, GIT_ENOTFOUND, GIT_EAMBIGUOUS, GIT_EINVALIDSPEC * or an error code */ GIT_EXTERN(int) git_revparse_ext( git_object **object_out, git_reference **reference_out, git_repository *repo, const char *spec); /** * Revparse flags. These indicate the intended behavior of the spec passed to * git_revparse. */ typedef enum { /** The spec targeted a single object. */ GIT_REVPARSE_SINGLE = 1 << 0, /** The spec targeted a range of commits. */ GIT_REVPARSE_RANGE = 1 << 1, /** The spec used the '...' operator, which invokes special semantics. */ GIT_REVPARSE_MERGE_BASE = 1 << 2, } git_revparse_mode_t; /** * Git Revision Spec: output of a `git_revparse` operation */ typedef struct { /** The left element of the revspec; must be freed by the user */ git_object *from; /** The right element of the revspec; must be freed by the user */ git_object *to; /** The intent of the revspec */ unsigned int flags; } git_revspec; /** * Parse a revision string for `from`, `to`, and intent. See `man gitrevisions` or * http://git-scm.com/docs/git-rev-parse.html#_specifying_revisions for information * on the syntax accepted. * * @param revspec Pointer to an user-allocated git_revspec struct where the result * of the rev-parse will be stored * @param repo the repository to search in * @param spec the rev-parse spec to parse * @return 0 on success, GIT_INVALIDSPEC, GIT_ENOTFOUND, GIT_EAMBIGUOUS or an error code */ GIT_EXTERN(int) git_revparse( git_revspec *revspec, git_repository *repo, const char *spec); /** @} */ GIT_END_DECL #endif libgit2-0.19.0/include/git2/revwalk.h000066400000000000000000000163311216214232500172530ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #ifndef INCLUDE_git_revwalk_h__ #define INCLUDE_git_revwalk_h__ #include "common.h" #include "types.h" #include "oid.h" /** * @file git2/revwalk.h * @brief Git revision traversal routines * @defgroup git_revwalk Git revision traversal routines * @ingroup Git * @{ */ GIT_BEGIN_DECL /** * Sort the repository contents in no particular ordering; * this sorting is arbitrary, implementation-specific * and subject to change at any time. * This is the default sorting for new walkers. */ #define GIT_SORT_NONE (0) /** * Sort the repository contents in topological order * (parents before children); this sorting mode * can be combined with time sorting. */ #define GIT_SORT_TOPOLOGICAL (1 << 0) /** * Sort the repository contents by commit time; * this sorting mode can be combined with * topological sorting. */ #define GIT_SORT_TIME (1 << 1) /** * Iterate through the repository contents in reverse * order; this sorting mode can be combined with * any of the above. */ #define GIT_SORT_REVERSE (1 << 2) /** * 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 out pointer to the new revision walker * @param repo the repo to walk through * @return 0 or an error code */ GIT_EXTERN(int) git_revwalk_new(git_revwalk **out, git_repository *repo); /** * Reset the revision walker for reuse. * * This will clear all the pushed and hidden commits, and * leave the walker in a blank state (just like at * creation) ready to receive new commit pushes and * start a new walk. * * The revision walk is automatically reset when a walk * is over. * * @param walker handle to reset. */ GIT_EXTERN(void) git_revwalk_reset(git_revwalk *walker); /** * Mark a commit to start traversal from. * * The 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 onto the walker before a walk can * be started. * * @param walk the walker being used for the traversal. * @param id the oid of the commit to start from. * @return 0 or an error code */ GIT_EXTERN(int) git_revwalk_push(git_revwalk *walk, const git_oid *id); /** * Push matching references * * The OIDs pointed to by the references that match the given glob * pattern will be pushed to the revision walker. * * A leading 'refs/' is implied if not present as well as a trailing * '/ *' if the glob lacks '?', '*' or '['. * * @param walk the walker being used for the traversal * @param glob the glob pattern references should match * @return 0 or an error code */ GIT_EXTERN(int) git_revwalk_push_glob(git_revwalk *walk, const char *glob); /** * Push the repository's HEAD * * @param walk the walker being used for the traversal * @return 0 or an error code */ GIT_EXTERN(int) git_revwalk_push_head(git_revwalk *walk); /** * 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 walk the walker being used for the traversal. * @param commit_id the oid of commit that will be ignored during the traversal * @return 0 or an error code */ GIT_EXTERN(int) git_revwalk_hide(git_revwalk *walk, const git_oid *commit_id); /** * Hide matching references. * * The OIDs pointed to by the references that match the given glob * pattern and their ancestors will be hidden from the output on the * revision walk. * * A leading 'refs/' is implied if not present as well as a trailing * '/ *' if the glob lacks '?', '*' or '['. * * @param walk the walker being used for the traversal * @param glob the glob pattern references should match * @return 0 or an error code */ GIT_EXTERN(int) git_revwalk_hide_glob(git_revwalk *walk, const char *glob); /** * Hide the repository's HEAD * * @param walk the walker being used for the traversal * @return 0 or an error code */ GIT_EXTERN(int) git_revwalk_hide_head(git_revwalk *walk); /** * Push the OID pointed to by a reference * * The reference must point to a commit. * * @param walk the walker being used for the traversal * @param refname the reference to push * @return 0 or an error code */ GIT_EXTERN(int) git_revwalk_push_ref(git_revwalk *walk, const char *refname); /** * Hide the OID pointed to by a reference * * The reference must point to a commit. * * @param walk the walker being used for the traversal * @param refname the reference to hide * @return 0 or an error code */ GIT_EXTERN(int) git_revwalk_hide_ref(git_revwalk *walk, const char *refname); /** * 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. * * 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 out Pointer where to store the oid of the next commit * @param walk the walker to pop the commit from. * @return 0 if the next commit was found; * GIT_ITEROVER if there are no commits left to iterate */ GIT_EXTERN(int) git_revwalk_next(git_oid *out, git_revwalk *walk); /** * Change the sorting mode when iterating through the * repository's contents. * * Changing the sorting mode resets the walker. * * @param walk the walker being used for the traversal. * @param sort_mode combination of GIT_SORT_XXX flags */ GIT_EXTERN(void) git_revwalk_sorting(git_revwalk *walk, unsigned int sort_mode); /** * Push and hide the respective endpoints of the given range. * * The range should be of the form * .. * where each is in the form accepted by 'git_revparse_single'. * The left-hand commit will be hidden and the right-hand commit pushed. * * @param walk the walker being used for the traversal * @param range the range * @return 0 or an error code * */ GIT_EXTERN(int) git_revwalk_push_range(git_revwalk *walk, const char *range); /** * Free a revision walker previously allocated. * * @param walk traversal handle to close. If NULL nothing occurs. */ GIT_EXTERN(void) git_revwalk_free(git_revwalk *walk); /** * Return the repository on which this walker * is operating. * * @param walk the revision walker * @return the repository being walked */ GIT_EXTERN(git_repository *) git_revwalk_repository(git_revwalk *walk); /** @} */ GIT_END_DECL #endif libgit2-0.19.0/include/git2/signature.h000066400000000000000000000040731216214232500176010ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #ifndef INCLUDE_git_signature_h__ #define INCLUDE_git_signature_h__ #include "common.h" #include "types.h" /** * @file git2/signature.h * @brief Git signature creation * @defgroup git_signature Git signature creation * @ingroup Git * @{ */ GIT_BEGIN_DECL /** * Create a new action signature. * * Call `git_signature_free()` to free the data. * * Note: angle brackets ('<' and '>') characters are not allowed * to be used in either the `name` or the `email` parameter. * * @param out new signature, in case of error NULL * @param name name of the person * @param email email of the person * @param time time when the action happened * @param offset timezone offset in minutes for the time * @return 0 or an error code */ GIT_EXTERN(int) git_signature_new(git_signature **out, const char *name, const char *email, git_time_t time, int offset); /** * Create a new action signature with a timestamp of 'now'. * * Call `git_signature_free()` to free the data. * * @param out new signature, in case of error NULL * @param name name of the person * @param email email of the person * @return 0 or an error code */ GIT_EXTERN(int) git_signature_now(git_signature **out, const char *name, const char *email); /** * Create a copy of an existing signature. All internal strings are also * duplicated. * * Call `git_signature_free()` to free the data. * * @param sig signature to duplicated * @return a copy of sig, NULL on out of memory */ GIT_EXTERN(git_signature *) git_signature_dup(const git_signature *sig); /** * Free an existing signature. * * Because the signature is not an opaque structure, it is legal to free it * manually, but be sure to free the "name" and "email" strings in addition * to the structure itself. * * @param sig signature to free */ GIT_EXTERN(void) git_signature_free(git_signature *sig); /** @} */ GIT_END_DECL #endif libgit2-0.19.0/include/git2/stash.h000066400000000000000000000057311216214232500167240ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #ifndef INCLUDE_git_stash_h__ #define INCLUDE_git_stash_h__ #include "common.h" #include "types.h" /** * @file git2/stash.h * @brief Git stash management routines * @ingroup Git * @{ */ GIT_BEGIN_DECL typedef enum { GIT_STASH_DEFAULT = 0, /* All changes already added to the index * are left intact in the working directory */ GIT_STASH_KEEP_INDEX = (1 << 0), /* All untracked files are also stashed and then * cleaned up from the working directory */ GIT_STASH_INCLUDE_UNTRACKED = (1 << 1), /* All ignored files are also stashed and then * cleaned up from the working directory */ GIT_STASH_INCLUDE_IGNORED = (1 << 2), } git_stash_flags; /** * Save the local modifications to a new stash. * * @param out Object id of the commit containing the stashed state. * This commit is also the target of the direct reference refs/stash. * * @param repo The owning repository. * * @param stasher The identity of the person performing the stashing. * * @param message Optional description along with the stashed state. * * @param flags Flags to control the stashing process. (see GIT_STASH_* above) * * @return 0 on success, GIT_ENOTFOUND where there's nothing to stash, * or error code. */ GIT_EXTERN(int) git_stash_save( git_oid *out, git_repository *repo, git_signature *stasher, const char *message, unsigned int flags); /** * When iterating over all the stashed states, callback that will be * issued per entry. * * @param index The position within the stash list. 0 points to the * most recent stashed state. * * @param message The stash message. * * @param stash_id The commit oid of the stashed state. * * @param payload Extra parameter to callback function. * * @return 0 on success, GIT_EUSER on non-zero callback, or error code */ typedef int (*git_stash_cb)( size_t index, const char* message, const git_oid *stash_id, void *payload); /** * Loop over all the stashed states and issue a callback for each one. * * If the callback returns a non-zero value, this will stop looping. * * @param repo Repository where to find the stash. * * @param callback Callback to invoke per found stashed state. The most recent * stash state will be enumerated first. * * @param payload Extra parameter to callback function. * * @return 0 on success, GIT_EUSER on non-zero callback, or error code */ GIT_EXTERN(int) git_stash_foreach( git_repository *repo, git_stash_cb callback, void *payload); /** * Remove a single stashed state from the stash list. * * @param repo The owning repository. * * @param index The position within the stash list. 0 points to the * most recent stashed state. * * @return 0 on success, or error code */ GIT_EXTERN(int) git_stash_drop( git_repository *repo, size_t index); /** @} */ GIT_END_DECL #endif libgit2-0.19.0/include/git2/status.h000066400000000000000000000267551216214232500171360ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #ifndef INCLUDE_git_status_h__ #define INCLUDE_git_status_h__ #include "common.h" #include "types.h" /** * @file git2/status.h * @brief Git file status routines * @defgroup git_status Git file status routines * @ingroup Git * @{ */ GIT_BEGIN_DECL /** * Status flags for a single file. * * A combination of these values will be returned to indicate the status of * a file. Status compares the working directory, the index, and the * current HEAD of the repository. The `GIT_STATUS_INDEX` set of flags * represents the status of file in the index relative to the HEAD, and the * `GIT_STATUS_WT` set of flags represent the status of the file in the * working directory relative to the index. */ typedef enum { GIT_STATUS_CURRENT = 0, GIT_STATUS_INDEX_NEW = (1u << 0), GIT_STATUS_INDEX_MODIFIED = (1u << 1), GIT_STATUS_INDEX_DELETED = (1u << 2), GIT_STATUS_INDEX_RENAMED = (1u << 3), GIT_STATUS_INDEX_TYPECHANGE = (1u << 4), GIT_STATUS_WT_NEW = (1u << 7), GIT_STATUS_WT_MODIFIED = (1u << 8), GIT_STATUS_WT_DELETED = (1u << 9), GIT_STATUS_WT_TYPECHANGE = (1u << 10), GIT_STATUS_WT_RENAMED = (1u << 11), GIT_STATUS_IGNORED = (1u << 14), } git_status_t; /** * Function pointer to receive status on individual files * * `path` is the relative path to the file from the root of the repository. * * `status_flags` is a combination of `git_status_t` values that apply. * * `payload` is the value you passed to the foreach function as payload. */ typedef int (*git_status_cb)( const char *path, unsigned int status_flags, void *payload); /** * For extended status, select the files on which to report status. * * - GIT_STATUS_SHOW_INDEX_AND_WORKDIR is the default. This roughly * matches `git status --porcelain` where each file gets a callback * indicating its status in the index and in the working directory. * - GIT_STATUS_SHOW_INDEX_ONLY only gives status based on HEAD to index * comparison, not looking at working directory changes. * - GIT_STATUS_SHOW_WORKDIR_ONLY only gives status based on index to * working directory comparison, not comparing the index to the HEAD. * - GIT_STATUS_SHOW_INDEX_THEN_WORKDIR runs index-only then workdir-only, * issuing (up to) two callbacks per file (first index, then workdir). * This is slightly more efficient than separate calls and can make it * easier to emulate plain `git status` text output. */ typedef enum { GIT_STATUS_SHOW_INDEX_AND_WORKDIR = 0, GIT_STATUS_SHOW_INDEX_ONLY = 1, GIT_STATUS_SHOW_WORKDIR_ONLY = 2, GIT_STATUS_SHOW_INDEX_THEN_WORKDIR = 3, } git_status_show_t; /** * Flags to control status callbacks * * - GIT_STATUS_OPT_INCLUDE_UNTRACKED says that callbacks should be made * on untracked files. These will only be made if the workdir files are * included in the status "show" option. * - GIT_STATUS_OPT_INCLUDE_IGNORED says that ignored files get callbacks. * Again, these callbacks will only be made if the workdir files are * included in the status "show" option. * - GIT_STATUS_OPT_INCLUDE_UNMODIFIED indicates that callback should be * made even on unmodified files. * - GIT_STATUS_OPT_EXCLUDE_SUBMODULES indicates that submodules should be * skipped. This only applies if there are no pending typechanges to * the submodule (either from or to another type). * - GIT_STATUS_OPT_RECURSE_UNTRACKED_DIRS indicates that all files in * untracked directories should be included. Normally if an entire * directory is new, then just the top-level directory is included (with * a trailing slash on the entry name). This flag says to include all * of the individual files in the directory instead. * - GIT_STATUS_OPT_DISABLE_PATHSPEC_MATCH indicates that the given path * should be treated as a literal path, and not as a pathspec pattern. * - GIT_STATUS_OPT_RECURSE_IGNORED_DIRS indicates that the contents of * ignored directories should be included in the status. This is like * doing `git ls-files -o -i --exclude-standard` with core git. * - GIT_STATUS_OPT_RENAMES_HEAD_TO_INDEX indicates that rename detection * should be processed between the head and the index and enables * the GIT_STATUS_INDEX_RENAMED as a possible status flag. * - GIT_STATUS_OPT_RENAMES_INDEX_TO_WORKDIR indicates tha rename * detection should be run between the index and the working directory * and enabled GIT_STATUS_WT_RENAMED as a possible status flag. * - GIT_STATUS_OPT_SORT_CASE_SENSITIVELY overrides the native case * sensitivity for the file system and forces the output to be in * case-sensitive order * - GIT_STATUS_OPT_SORT_CASE_INSENSITIVELY overrides the native case * sensitivity for the file system and forces the output to be in * case-insensitive order * * Calling `git_status_foreach()` is like calling the extended version * with: GIT_STATUS_OPT_INCLUDE_IGNORED, GIT_STATUS_OPT_INCLUDE_UNTRACKED, * and GIT_STATUS_OPT_RECURSE_UNTRACKED_DIRS. Those options are bundled * together as `GIT_STATUS_OPT_DEFAULTS` if you want them as a baseline. */ typedef enum { GIT_STATUS_OPT_INCLUDE_UNTRACKED = (1u << 0), GIT_STATUS_OPT_INCLUDE_IGNORED = (1u << 1), GIT_STATUS_OPT_INCLUDE_UNMODIFIED = (1u << 2), GIT_STATUS_OPT_EXCLUDE_SUBMODULES = (1u << 3), GIT_STATUS_OPT_RECURSE_UNTRACKED_DIRS = (1u << 4), GIT_STATUS_OPT_DISABLE_PATHSPEC_MATCH = (1u << 5), GIT_STATUS_OPT_RECURSE_IGNORED_DIRS = (1u << 6), GIT_STATUS_OPT_RENAMES_HEAD_TO_INDEX = (1u << 7), GIT_STATUS_OPT_RENAMES_INDEX_TO_WORKDIR = (1u << 8), GIT_STATUS_OPT_SORT_CASE_SENSITIVELY = (1u << 9), GIT_STATUS_OPT_SORT_CASE_INSENSITIVELY = (1u << 10), } git_status_opt_t; #define GIT_STATUS_OPT_DEFAULTS \ (GIT_STATUS_OPT_INCLUDE_IGNORED | \ GIT_STATUS_OPT_INCLUDE_UNTRACKED | \ GIT_STATUS_OPT_RECURSE_UNTRACKED_DIRS) /** * Options to control how `git_status_foreach_ext()` will issue callbacks. * * This structure is set so that zeroing it out will give you relatively * sane defaults. * * The `show` value is one of the `git_status_show_t` constants that * control which files to scan and in what order. * * The `flags` value is an OR'ed combination of the `git_status_opt_t` * values above. * * The `pathspec` is an array of path patterns to match (using * fnmatch-style matching), or just an array of paths to match exactly if * `GIT_STATUS_OPT_DISABLE_PATHSPEC_MATCH` is specified in the flags. */ typedef struct { unsigned int version; git_status_show_t show; unsigned int flags; git_strarray pathspec; } git_status_options; #define GIT_STATUS_OPTIONS_VERSION 1 #define GIT_STATUS_OPTIONS_INIT {GIT_STATUS_OPTIONS_VERSION} /** * A status entry, providing the differences between the file as it exists * in HEAD and the index, and providing the differences between the index * and the working directory. * * The `status` value provides the status flags for this file. * * The `head_to_index` value provides detailed information about the * differences between the file in HEAD and the file in the index. * * The `index_to_workdir` value provides detailed information about the * differences between the file in the index and the file in the * working directory. */ typedef struct { git_status_t status; git_diff_delta *head_to_index; git_diff_delta *index_to_workdir; } git_status_entry; /** * Gather file statuses and run a callback for each one. * * The callback is passed the path of the file, the status (a combination of * the `git_status_t` values above) and the `payload` data pointer passed * into this function. * * If the callback returns a non-zero value, this function will stop looping * and return GIT_EUSER. * * @param repo A repository object * @param callback The function to call on each file * @param payload Pointer to pass through to callback function * @return 0 on success, GIT_EUSER on non-zero callback, or error code */ GIT_EXTERN(int) git_status_foreach( git_repository *repo, git_status_cb callback, void *payload); /** * Gather file status information and run callbacks as requested. * * This is an extended version of the `git_status_foreach()` API that * allows for more granular control over which paths will be processed and * in what order. See the `git_status_options` structure for details * about the additional controls that this makes available. * * @param repo Repository object * @param opts Status options structure * @param callback The function to call on each file * @param payload Pointer to pass through to callback function * @return 0 on success, GIT_EUSER on non-zero callback, or error code */ GIT_EXTERN(int) git_status_foreach_ext( git_repository *repo, const git_status_options *opts, git_status_cb callback, void *payload); /** * Get file status for a single file. * * This is not quite the same as calling `git_status_foreach_ext()` with * the pathspec set to the specified path. * * @param status_flags The status value for the file * @param repo A repository object * @param path The file to retrieve status for, rooted at the repo's workdir * @return 0 on success, GIT_ENOTFOUND if the file is not found in the HEAD, * index, and work tree, GIT_EINVALIDPATH if `path` points at a folder, * GIT_EAMBIGUOUS if "path" matches multiple files, -1 on other error. */ GIT_EXTERN(int) git_status_file( unsigned int *status_flags, git_repository *repo, const char *path); /** * Gather file status information and populate the `git_status_list`. * * @param out Pointer to store the status results in * @param repo Repository object * @param opts Status options structure * @return 0 on success or error code */ GIT_EXTERN(int) git_status_list_new( git_status_list **out, git_repository *repo, const git_status_options *opts); /** * Gets the count of status entries in this list. * * @param statuslist Existing status list object * @return the number of status entries */ GIT_EXTERN(size_t) git_status_list_entrycount( git_status_list *statuslist); /** * Get a pointer to one of the entries in the status list. * * The entry is not modifiable and should not be freed. * * @param statuslist Existing status list object * @param idx Position of the entry * @return Pointer to the entry; NULL if out of bounds */ GIT_EXTERN(const git_status_entry *) git_status_byindex( git_status_list *statuslist, size_t idx); /** * Free an existing status list * * @param statuslist Existing status list object */ GIT_EXTERN(void) git_status_list_free( git_status_list *statuslist); /** * Test if the ignore rules apply to a given file. * * This function checks the ignore rules to see if they would apply to the * given file. This indicates if the file would be ignored regardless of * whether the file is already in the index or committed to the repository. * * One way to think of this is if you were to do "git add ." on the * directory containing the file, would it be added or not? * * @param ignored Boolean returning 0 if the file is not ignored, 1 if it is * @param repo A repository object * @param path The file to check ignores for, rooted at the repo's workdir. * @return 0 if ignore rules could be processed for the file (regardless * of whether it exists or not), or an error < 0 if they could not. */ GIT_EXTERN(int) git_status_should_ignore( int *ignored, git_repository *repo, const char *path); /** @} */ GIT_END_DECL #endif libgit2-0.19.0/include/git2/stdint.h000066400000000000000000000170471216214232500171120ustar00rootroot00000000000000// ISO C9x compliant stdint.h for Microsoft Visual Studio // Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124 // // Copyright (c) 2006-2008 Alexander Chemeris // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // 1. Redistributions of source code must retain the above copyright notice, // this list of conditions and the following disclaimer. // // 2. Redistributions in binary form must reproduce the above copyright // notice, this list of conditions and the following disclaimer in the // documentation and/or other materials provided with the distribution. // // 3. The name of the author may be used to endorse or promote products // derived from this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED // WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO // EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; // OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF // ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // /////////////////////////////////////////////////////////////////////////////// #ifndef _MSC_VER // [ #error "Use this header only with Microsoft Visual C++ compilers!" #endif // _MSC_VER ] #ifndef _MSC_STDINT_H_ // [ #define _MSC_STDINT_H_ #if _MSC_VER > 1000 #pragma once #endif #include // For Visual Studio 6 in C++ mode and for many Visual Studio versions when // compiling for ARM we should wrap include with 'extern "C++" {}' // or compiler give many errors like this: // error C2733: second C linkage of overloaded function 'wmemchr' not allowed #ifdef __cplusplus extern "C" { #endif # include #ifdef __cplusplus } #endif // Define _W64 macros to mark types changing their size, like intptr_t. #ifndef _W64 # if !defined(__midl) && (defined(_X86_) || defined(_M_IX86)) && _MSC_VER >= 1300 # define _W64 __w64 # else # define _W64 # endif #endif // 7.18.1 Integer types // 7.18.1.1 Exact-width integer types // Visual Studio 6 and Embedded Visual C++ 4 doesn't // realize that, e.g. char has the same size as __int8 // so we give up on __intX for them. #if (_MSC_VER < 1300) typedef signed char int8_t; typedef signed short int16_t; typedef signed int int32_t; typedef unsigned char uint8_t; typedef unsigned short uint16_t; typedef unsigned int uint32_t; #else typedef signed __int8 int8_t; typedef signed __int16 int16_t; typedef signed __int32 int32_t; typedef unsigned __int8 uint8_t; typedef unsigned __int16 uint16_t; typedef unsigned __int32 uint32_t; #endif typedef signed __int64 int64_t; typedef unsigned __int64 uint64_t; // 7.18.1.2 Minimum-width integer types typedef int8_t int_least8_t; typedef int16_t int_least16_t; typedef int32_t int_least32_t; typedef int64_t int_least64_t; typedef uint8_t uint_least8_t; typedef uint16_t uint_least16_t; typedef uint32_t uint_least32_t; typedef uint64_t uint_least64_t; // 7.18.1.3 Fastest minimum-width integer types typedef int8_t int_fast8_t; typedef int16_t int_fast16_t; typedef int32_t int_fast32_t; typedef int64_t int_fast64_t; typedef uint8_t uint_fast8_t; typedef uint16_t uint_fast16_t; typedef uint32_t uint_fast32_t; typedef uint64_t uint_fast64_t; // 7.18.1.4 Integer types capable of holding object pointers #ifdef _WIN64 // [ typedef signed __int64 intptr_t; typedef unsigned __int64 uintptr_t; #else // _WIN64 ][ typedef _W64 signed int intptr_t; typedef _W64 unsigned int uintptr_t; #endif // _WIN64 ] // 7.18.1.5 Greatest-width integer types typedef int64_t intmax_t; typedef uint64_t uintmax_t; // 7.18.2 Limits of specified-width integer types #if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS) // [ See footnote 220 at page 257 and footnote 221 at page 259 // 7.18.2.1 Limits of exact-width integer types #define INT8_MIN ((int8_t)_I8_MIN) #define INT8_MAX _I8_MAX #define INT16_MIN ((int16_t)_I16_MIN) #define INT16_MAX _I16_MAX #define INT32_MIN ((int32_t)_I32_MIN) #define INT32_MAX _I32_MAX #define INT64_MIN ((int64_t)_I64_MIN) #define INT64_MAX _I64_MAX #define UINT8_MAX _UI8_MAX #define UINT16_MAX _UI16_MAX #define UINT32_MAX _UI32_MAX #define UINT64_MAX _UI64_MAX // 7.18.2.2 Limits of minimum-width integer types #define INT_LEAST8_MIN INT8_MIN #define INT_LEAST8_MAX INT8_MAX #define INT_LEAST16_MIN INT16_MIN #define INT_LEAST16_MAX INT16_MAX #define INT_LEAST32_MIN INT32_MIN #define INT_LEAST32_MAX INT32_MAX #define INT_LEAST64_MIN INT64_MIN #define INT_LEAST64_MAX INT64_MAX #define UINT_LEAST8_MAX UINT8_MAX #define UINT_LEAST16_MAX UINT16_MAX #define UINT_LEAST32_MAX UINT32_MAX #define UINT_LEAST64_MAX UINT64_MAX // 7.18.2.3 Limits of fastest minimum-width integer types #define INT_FAST8_MIN INT8_MIN #define INT_FAST8_MAX INT8_MAX #define INT_FAST16_MIN INT16_MIN #define INT_FAST16_MAX INT16_MAX #define INT_FAST32_MIN INT32_MIN #define INT_FAST32_MAX INT32_MAX #define INT_FAST64_MIN INT64_MIN #define INT_FAST64_MAX INT64_MAX #define UINT_FAST8_MAX UINT8_MAX #define UINT_FAST16_MAX UINT16_MAX #define UINT_FAST32_MAX UINT32_MAX #define UINT_FAST64_MAX UINT64_MAX // 7.18.2.4 Limits of integer types capable of holding object pointers #ifdef _WIN64 // [ # define INTPTR_MIN INT64_MIN # define INTPTR_MAX INT64_MAX # define UINTPTR_MAX UINT64_MAX #else // _WIN64 ][ # define INTPTR_MIN INT32_MIN # define INTPTR_MAX INT32_MAX # define UINTPTR_MAX UINT32_MAX #endif // _WIN64 ] // 7.18.2.5 Limits of greatest-width integer types #define INTMAX_MIN INT64_MIN #define INTMAX_MAX INT64_MAX #define UINTMAX_MAX UINT64_MAX // 7.18.3 Limits of other integer types #ifdef _WIN64 // [ # define PTRDIFF_MIN _I64_MIN # define PTRDIFF_MAX _I64_MAX #else // _WIN64 ][ # define PTRDIFF_MIN _I32_MIN # define PTRDIFF_MAX _I32_MAX #endif // _WIN64 ] #define SIG_ATOMIC_MIN INT_MIN #define SIG_ATOMIC_MAX INT_MAX #ifndef SIZE_MAX // [ # ifdef _WIN64 // [ # define SIZE_MAX _UI64_MAX # else // _WIN64 ][ # define SIZE_MAX _UI32_MAX # endif // _WIN64 ] #endif // SIZE_MAX ] // WCHAR_MIN and WCHAR_MAX are also defined in #ifndef WCHAR_MIN // [ # define WCHAR_MIN 0 #endif // WCHAR_MIN ] #ifndef WCHAR_MAX // [ # define WCHAR_MAX _UI16_MAX #endif // WCHAR_MAX ] #define WINT_MIN 0 #define WINT_MAX _UI16_MAX #endif // __STDC_LIMIT_MACROS ] // 7.18.4 Limits of other integer types #if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) // [ See footnote 224 at page 260 // 7.18.4.1 Macros for minimum-width integer constants #define INT8_C(val) val##i8 #define INT16_C(val) val##i16 #define INT32_C(val) val##i32 #define INT64_C(val) val##i64 #define UINT8_C(val) val##ui8 #define UINT16_C(val) val##ui16 #define UINT32_C(val) val##ui32 #define UINT64_C(val) val##ui64 // 7.18.4.2 Macros for greatest-width integer constants #define INTMAX_C INT64_C #define UINTMAX_C UINT64_C #endif // __STDC_CONSTANT_MACROS ] #endif // _MSC_STDINT_H_ ] libgit2-0.19.0/include/git2/strarray.h000066400000000000000000000030471216214232500174470ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #ifndef INCLUDE_git_strarray_h__ #define INCLUDE_git_strarray_h__ #include "common.h" /** * @file git2/strarray.h * @brief Git string array routines * @defgroup git_strarray Git string array routines * @ingroup Git * @{ */ GIT_BEGIN_DECL /** Array of strings */ typedef struct git_strarray { char **strings; size_t count; } git_strarray; /** * Close a string array object * * This method should be called on `git_strarray` objects where the strings * array is allocated and contains allocated strings, such as what you * would get from `git_strarray_copy()`. Not doing so, will result in a * memory leak. * * This does not free the `git_strarray` itself, since the library will * never allocate that object directly itself (it is more commonly embedded * inside another struct or created on the stack). * * @param array git_strarray from which to free string data */ GIT_EXTERN(void) git_strarray_free(git_strarray *array); /** * Copy a string array object from source to target. * * Note: target is overwritten and hence should be empty, otherwise its * contents are leaked. Call git_strarray_free() if necessary. * * @param tgt target * @param src source * @return 0 on success, < 0 on allocation failure */ GIT_EXTERN(int) git_strarray_copy(git_strarray *tgt, const git_strarray *src); /** @} */ GIT_END_DECL #endif libgit2-0.19.0/include/git2/submodule.h000066400000000000000000000503071216214232500176000ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #ifndef INCLUDE_git_submodule_h__ #define INCLUDE_git_submodule_h__ #include "common.h" #include "types.h" #include "oid.h" /** * @file git2/submodule.h * @brief Git submodule management utilities * @defgroup git_submodule Git submodule management routines * @ingroup Git * @{ */ GIT_BEGIN_DECL /** * Opaque structure representing a submodule. * * Submodule support in libgit2 builds a list of known submodules and keeps * it in the repository. The list is built from the .gitmodules file, the * .git/config file, the index, and the HEAD tree. Items in the working * directory that look like submodules (i.e. a git repo) but are not * mentioned in those places won't be tracked. */ typedef struct git_submodule git_submodule; /** * Values that could be specified for the update rule of a submodule. * * Use the DEFAULT value if you have altered the update value via * `git_submodule_set_update()` and wish to reset to the original default. */ typedef enum { GIT_SUBMODULE_UPDATE_DEFAULT = -1, GIT_SUBMODULE_UPDATE_CHECKOUT = 0, GIT_SUBMODULE_UPDATE_REBASE = 1, GIT_SUBMODULE_UPDATE_MERGE = 2, GIT_SUBMODULE_UPDATE_NONE = 3 } git_submodule_update_t; /** * Values that could be specified for how closely to examine the * working directory when getting submodule status. * * Use the DEFUALT value if you have altered the ignore value via * `git_submodule_set_ignore()` and wish to reset to the original value. */ typedef enum { GIT_SUBMODULE_IGNORE_DEFAULT = -1, /* reset to default */ GIT_SUBMODULE_IGNORE_NONE = 0, /* any change or untracked == dirty */ GIT_SUBMODULE_IGNORE_UNTRACKED = 1, /* dirty if tracked files change */ GIT_SUBMODULE_IGNORE_DIRTY = 2, /* only dirty if HEAD moved */ GIT_SUBMODULE_IGNORE_ALL = 3 /* never dirty */ } git_submodule_ignore_t; /** * Return codes for submodule status. * * A combination of these flags will be returned to describe the status of a * submodule. Depending on the "ignore" property of the submodule, some of * the flags may never be returned because they indicate changes that are * supposed to be ignored. * * Submodule info is contained in 4 places: the HEAD tree, the index, config * files (both .git/config and .gitmodules), and the working directory. Any * or all of those places might be missing information about the submodule * depending on what state the repo is in. We consider all four places to * build the combination of status flags. * * There are four values that are not really status, but give basic info * about what sources of submodule data are available. These will be * returned even if ignore is set to "ALL". * * * IN_HEAD - superproject head contains submodule * * IN_INDEX - superproject index contains submodule * * IN_CONFIG - superproject gitmodules has submodule * * IN_WD - superproject workdir has submodule * * The following values will be returned so long as ignore is not "ALL". * * * INDEX_ADDED - in index, not in head * * INDEX_DELETED - in head, not in index * * INDEX_MODIFIED - index and head don't match * * WD_UNINITIALIZED - workdir contains empty directory * * WD_ADDED - in workdir, not index * * WD_DELETED - in index, not workdir * * WD_MODIFIED - index and workdir head don't match * * The following can only be returned if ignore is "NONE" or "UNTRACKED". * * * WD_INDEX_MODIFIED - submodule workdir index is dirty * * WD_WD_MODIFIED - submodule workdir has modified files * * Lastly, the following will only be returned for ignore "NONE". * * * WD_UNTRACKED - wd contains untracked files */ typedef enum { GIT_SUBMODULE_STATUS_IN_HEAD = (1u << 0), GIT_SUBMODULE_STATUS_IN_INDEX = (1u << 1), GIT_SUBMODULE_STATUS_IN_CONFIG = (1u << 2), GIT_SUBMODULE_STATUS_IN_WD = (1u << 3), GIT_SUBMODULE_STATUS_INDEX_ADDED = (1u << 4), GIT_SUBMODULE_STATUS_INDEX_DELETED = (1u << 5), GIT_SUBMODULE_STATUS_INDEX_MODIFIED = (1u << 6), GIT_SUBMODULE_STATUS_WD_UNINITIALIZED = (1u << 7), GIT_SUBMODULE_STATUS_WD_ADDED = (1u << 8), GIT_SUBMODULE_STATUS_WD_DELETED = (1u << 9), GIT_SUBMODULE_STATUS_WD_MODIFIED = (1u << 10), GIT_SUBMODULE_STATUS_WD_INDEX_MODIFIED = (1u << 11), GIT_SUBMODULE_STATUS_WD_WD_MODIFIED = (1u << 12), GIT_SUBMODULE_STATUS_WD_UNTRACKED = (1u << 13), } git_submodule_status_t; #define GIT_SUBMODULE_STATUS__IN_FLAGS \ (GIT_SUBMODULE_STATUS_IN_HEAD | \ GIT_SUBMODULE_STATUS_IN_INDEX | \ GIT_SUBMODULE_STATUS_IN_CONFIG | \ GIT_SUBMODULE_STATUS_IN_WD) #define GIT_SUBMODULE_STATUS__INDEX_FLAGS \ (GIT_SUBMODULE_STATUS_INDEX_ADDED | \ GIT_SUBMODULE_STATUS_INDEX_DELETED | \ GIT_SUBMODULE_STATUS_INDEX_MODIFIED) #define GIT_SUBMODULE_STATUS__WD_FLAGS \ ~(GIT_SUBMODULE_STATUS__IN_FLAGS | GIT_SUBMODULE_STATUS__INDEX_FLAGS) #define GIT_SUBMODULE_STATUS_IS_UNMODIFIED(S) \ (((S) & ~GIT_SUBMODULE_STATUS__IN_FLAGS) == 0) #define GIT_SUBMODULE_STATUS_IS_INDEX_UNMODIFIED(S) \ (((S) & GIT_SUBMODULE_STATUS__INDEX_FLAGS) == 0) #define GIT_SUBMODULE_STATUS_IS_WD_UNMODIFIED(S) \ (((S) & GIT_SUBMODULE_STATUS__WD_FLAGS) == 0) #define GIT_SUBMODULE_STATUS_IS_WD_DIRTY(S) \ (((S) & (GIT_SUBMODULE_STATUS_WD_INDEX_MODIFIED | \ GIT_SUBMODULE_STATUS_WD_WD_MODIFIED | \ GIT_SUBMODULE_STATUS_WD_UNTRACKED)) != 0) /** * Lookup submodule information by name or path. * * Given either the submodule name or path (they are usually the same), this * returns a structure describing the submodule. * * There are two expected error scenarios: * * - The submodule is not mentioned in the HEAD, the index, and the config, * but does "exist" in the working directory (i.e. there is a subdirectory * that is a valid self-contained git repo). In this case, this function * returns GIT_EEXISTS to indicate the the submodule exists but not in a * state where a git_submodule can be instantiated. * - The submodule is not mentioned in the HEAD, index, or config and the * working directory doesn't contain a value git repo at that path. * There may or may not be anything else at that path, but nothing that * looks like a submodule. In this case, this returns GIT_ENOTFOUND. * * The submodule object is owned by the containing repo and will be freed * when the repo is freed. The caller need not free the submodule. * * @param submodule Pointer to submodule description object pointer.. * @param repo The repository. * @param name The name of the submodule. Trailing slashes will be ignored. * @return 0 on success, GIT_ENOTFOUND if submodule does not exist, * GIT_EEXISTS if submodule exists in working directory only, -1 on * other errors. */ GIT_EXTERN(int) git_submodule_lookup( git_submodule **submodule, git_repository *repo, const char *name); /** * Iterate over all tracked submodules of a repository. * * See the note on `git_submodule` above. This iterates over the tracked * submodules as decribed therein. * * If you are concerned about items in the working directory that look like * submodules but are not tracked, the diff API will generate a diff record * for workdir items that look like submodules but are not tracked, showing * them as added in the workdir. Also, the status API will treat the entire * subdirectory of a contained git repo as a single GIT_STATUS_WT_NEW item. * * @param repo The repository * @param callback Function to be called with the name of each submodule. * Return a non-zero value to terminate the iteration. * @param payload Extra data to pass to callback * @return 0 on success, -1 on error, or non-zero return value of callback */ GIT_EXTERN(int) git_submodule_foreach( git_repository *repo, int (*callback)(git_submodule *sm, const char *name, void *payload), void *payload); /** * Set up a new git submodule for checkout. * * This does "git submodule add" up to the fetch and checkout of the * submodule contents. It preps a new submodule, creates an entry in * .gitmodules and creates an empty initialized repository either at the * given path in the working directory or in .git/modules with a gitlink * from the working directory to the new repo. * * To fully emulate "git submodule add" call this function, then open the * submodule repo and perform the clone step as needed. Lastly, call * `git_submodule_add_finalize()` to wrap up adding the new submodule and * .gitmodules to the index to be ready to commit. * * @param submodule The newly created submodule ready to open for clone * @param repo Superproject repository to contain the new submodule * @param url URL for the submodules remote * @param path Path at which the submodule should be created * @param use_gitlink Should workdir contain a gitlink to the repo in * .git/modules vs. repo directly in workdir. * @return 0 on success, GIT_EEXISTS if submodule already exists, * -1 on other errors. */ GIT_EXTERN(int) git_submodule_add_setup( git_submodule **submodule, git_repository *repo, const char *url, const char *path, int use_gitlink); /** * Resolve the setup of a new git submodule. * * This should be called on a submodule once you have called add setup * and done the clone of the submodule. This adds the .gitmodules file * and the newly cloned submodule to the index to be ready to be committed * (but doesn't actually do the commit). * * @param submodule The submodule to finish adding. */ GIT_EXTERN(int) git_submodule_add_finalize(git_submodule *submodule); /** * Add current submodule HEAD commit to index of superproject. * * @param submodule The submodule to add to the index * @param write_index Boolean if this should immediately write the index * file. If you pass this as false, you will have to get the * git_index and explicitly call `git_index_write()` on it to * save the change. * @return 0 on success, <0 on failure */ GIT_EXTERN(int) git_submodule_add_to_index( git_submodule *submodule, int write_index); /** * Write submodule settings to .gitmodules file. * * This commits any in-memory changes to the submodule to the gitmodules * file on disk. You may also be interested in `git_submodule_init()` which * writes submodule info to ".git/config" (which is better for local changes * to submodule settings) and/or `git_submodule_sync()` which writes * settings about remotes to the actual submodule repository. * * @param submodule The submodule to write. * @return 0 on success, <0 on failure. */ GIT_EXTERN(int) git_submodule_save(git_submodule *submodule); /** * Get the containing repository for a submodule. * * This returns a pointer to the repository that contains the submodule. * This is a just a reference to the repository that was passed to the * original `git_submodule_lookup()` call, so if that repository has been * freed, then this may be a dangling reference. * * @param submodule Pointer to submodule object * @return Pointer to `git_repository` */ GIT_EXTERN(git_repository *) git_submodule_owner(git_submodule *submodule); /** * Get the name of submodule. * * @param submodule Pointer to submodule object * @return Pointer to the submodule name */ GIT_EXTERN(const char *) git_submodule_name(git_submodule *submodule); /** * Get the path to the submodule. * * The path is almost always the same as the submodule name, but the * two are actually not required to match. * * @param submodule Pointer to submodule object * @return Pointer to the submodule path */ GIT_EXTERN(const char *) git_submodule_path(git_submodule *submodule); /** * Get the URL for the submodule. * * @param submodule Pointer to submodule object * @return Pointer to the submodule url */ GIT_EXTERN(const char *) git_submodule_url(git_submodule *submodule); /** * Set the URL for the submodule. * * This sets the URL in memory for the submodule. This will be used for * any following submodule actions while this submodule data is in memory. * * After calling this, you may wish to call `git_submodule_save()` to write * the changes back to the ".gitmodules" file and `git_submodule_sync()` to * write the changes to the checked out submodule repository. * * @param submodule Pointer to the submodule object * @param url URL that should be used for the submodule * @return 0 on success, <0 on failure */ GIT_EXTERN(int) git_submodule_set_url(git_submodule *submodule, const char *url); /** * Get the OID for the submodule in the index. * * @param submodule Pointer to submodule object * @return Pointer to git_oid or NULL if submodule is not in index. */ GIT_EXTERN(const git_oid *) git_submodule_index_id(git_submodule *submodule); /** * Get the OID for the submodule in the current HEAD tree. * * @param submodule Pointer to submodule object * @return Pointer to git_oid or NULL if submodule is not in the HEAD. */ GIT_EXTERN(const git_oid *) git_submodule_head_id(git_submodule *submodule); /** * Get the OID for the submodule in the current working directory. * * This returns the OID that corresponds to looking up 'HEAD' in the checked * out submodule. If there are pending changes in the index or anything * else, this won't notice that. You should call `git_submodule_status()` * for a more complete picture about the state of the working directory. * * @param submodule Pointer to submodule object * @return Pointer to git_oid or NULL if submodule is not checked out. */ GIT_EXTERN(const git_oid *) git_submodule_wd_id(git_submodule *submodule); /** * Get the ignore rule for the submodule. * * There are four ignore values: * * - **GIT_SUBMODULE_IGNORE_NONE** will consider any change to the contents * of the submodule from a clean checkout to be dirty, including the * addition of untracked files. This is the default if unspecified. * - **GIT_SUBMODULE_IGNORE_UNTRACKED** examines the contents of the * working tree (i.e. call `git_status_foreach()` on the submodule) but * UNTRACKED files will not count as making the submodule dirty. * - **GIT_SUBMODULE_IGNORE_DIRTY** means to only check if the HEAD of the * submodule has moved for status. This is fast since it does not need to * scan the working tree of the submodule at all. * - **GIT_SUBMODULE_IGNORE_ALL** means not to open the submodule repo. * The working directory will be consider clean so long as there is a * checked out version present. */ GIT_EXTERN(git_submodule_ignore_t) git_submodule_ignore( git_submodule *submodule); /** * Set the ignore rule for the submodule. * * This sets the ignore rule in memory for the submodule. This will be used * for any following actions (such as `git_submodule_status()`) while the * submodule is in memory. You should call `git_submodule_save()` if you * want to persist the new ignore role. * * Calling this again with GIT_SUBMODULE_IGNORE_DEFAULT or calling * `git_submodule_reload()` will revert the rule to the value that was in the * original config. * * @return old value for ignore */ GIT_EXTERN(git_submodule_ignore_t) git_submodule_set_ignore( git_submodule *submodule, git_submodule_ignore_t ignore); /** * Get the update rule for the submodule. */ GIT_EXTERN(git_submodule_update_t) git_submodule_update( git_submodule *submodule); /** * Set the update rule for the submodule. * * This sets the update rule in memory for the submodule. You should call * `git_submodule_save()` if you want to persist the new update rule. * * Calling this again with GIT_SUBMODULE_UPDATE_DEFAULT or calling * `git_submodule_reload()` will revert the rule to the value that was in the * original config. * * @return old value for update */ GIT_EXTERN(git_submodule_update_t) git_submodule_set_update( git_submodule *submodule, git_submodule_update_t update); /** * Read the fetchRecurseSubmodules rule for a submodule. * * This accesses the submodule..fetchRecurseSubmodules value for * the submodule that controls fetching behavior for the submodule. * * Note that at this time, libgit2 does not honor this setting and the * fetch functionality current ignores submodules. * * @return 0 if fetchRecurseSubmodules is false, 1 if true */ GIT_EXTERN(int) git_submodule_fetch_recurse_submodules( git_submodule *submodule); /** * Set the fetchRecurseSubmodules rule for a submodule. * * This sets the submodule..fetchRecurseSubmodules value for * the submodule. You should call `git_submodule_save()` if you want * to persist the new value. * * @param submodule The submodule to modify * @param fetch_recurse_submodules Boolean value * @return old value for fetchRecurseSubmodules */ GIT_EXTERN(int) git_submodule_set_fetch_recurse_submodules( git_submodule *submodule, int fetch_recurse_submodules); /** * Copy submodule info into ".git/config" file. * * Just like "git submodule init", this copies information about the * submodule into ".git/config". You can use the accessor functions * above to alter the in-memory git_submodule object and control what * is written to the config, overriding what is in .gitmodules. * * @param submodule The submodule to write into the superproject config * @param overwrite By default, existing entries will not be overwritten, * but setting this to true forces them to be updated. * @return 0 on success, <0 on failure. */ GIT_EXTERN(int) git_submodule_init(git_submodule *submodule, int overwrite); /** * Copy submodule remote info into submodule repo. * * This copies the information about the submodules URL into the checked out * submodule config, acting like "git submodule sync". This is useful if * you have altered the URL for the submodule (or it has been altered by a * fetch of upstream changes) and you need to update your local repo. */ GIT_EXTERN(int) git_submodule_sync(git_submodule *submodule); /** * Open the repository for a submodule. * * This is a newly opened repository object. The caller is responsible for * calling `git_repository_free()` on it when done. Multiple calls to this * function will return distinct `git_repository` objects. This will only * work if the submodule is checked out into the working directory. * * @param repo Pointer to the submodule repo which was opened * @param submodule Submodule to be opened * @return 0 on success, <0 if submodule repo could not be opened. */ GIT_EXTERN(int) git_submodule_open( git_repository **repo, git_submodule *submodule); /** * Reread submodule info from config, index, and HEAD. * * Call this to reread cached submodule information for this submodule if * you have reason to believe that it has changed. */ GIT_EXTERN(int) git_submodule_reload(git_submodule *submodule); /** * Reread all submodule info. * * Call this to reload all cached submodule information for the repo. */ GIT_EXTERN(int) git_submodule_reload_all(git_repository *repo); /** * Get the status for a submodule. * * This looks at a submodule and tries to determine the status. It * will return a combination of the `GIT_SUBMODULE_STATUS` values above. * How deeply it examines the working directory to do this will depend * on the `git_submodule_ignore_t` value for the submodule - which can be * set either temporarily or permanently with `git_submodule_set_ignore()`. * * @param status Combination of `GIT_SUBMODULE_STATUS` flags * @param submodule Submodule for which to get status * @return 0 on success, <0 on error */ GIT_EXTERN(int) git_submodule_status( unsigned int *status, git_submodule *submodule); /** * Get the locations of submodule information. * * This is a bit like a very lightweight version of `git_submodule_status`. * It just returns a made of the first four submodule status values (i.e. * the ones like GIT_SUBMODULE_STATUS_IN_HEAD, etc) that tell you where the * submodule data comes from (i.e. the HEAD commit, gitmodules file, etc.). * This can be useful if you want to know if the submodule is present in the * working directory at this point in time, etc. * * @param location_status Combination of first four `GIT_SUBMODULE_STATUS` flags * @param submodule Submodule for which to get status * @return 0 on success, <0 on error */ GIT_EXTERN(int) git_submodule_location( unsigned int *location_status, git_submodule *submodule); /** @} */ GIT_END_DECL #endif libgit2-0.19.0/include/git2/sys/000077500000000000000000000000001216214232500162415ustar00rootroot00000000000000libgit2-0.19.0/include/git2/sys/commit.h000066400000000000000000000023071216214232500177040ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #ifndef INCLUDE_sys_git_commit_h__ #define INCLUDE_sys_git_commit_h__ #include "git2/common.h" #include "git2/types.h" #include "git2/oid.h" /** * @file git2/sys/commit.h * @brief Low-level Git commit creation * @defgroup git_backend Git custom backend APIs * @ingroup Git * @{ */ GIT_BEGIN_DECL /** * Create new commit in the repository from a list of `git_oid` values * * See documentation for `git_commit_create()` for information about the * parameters, as the meaning is identical excepting that `tree` and * `parents` now take `git_oid`. This is a dangerous API in that nor * the `tree`, neither the `parents` list of `git_oid`s are checked for * validity. */ GIT_EXTERN(int) git_commit_create_from_oids( git_oid *oid, git_repository *repo, const char *update_ref, const git_signature *author, const git_signature *committer, const char *message_encoding, const char *message, const git_oid *tree, int parent_count, const git_oid *parents[]); /** @} */ GIT_END_DECL #endif libgit2-0.19.0/include/git2/sys/config.h000066400000000000000000000046551216214232500176710ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #ifndef INCLUDE_sys_git_config_backend_h__ #define INCLUDE_sys_git_config_backend_h__ #include "git2/common.h" #include "git2/types.h" #include "git2/config.h" /** * @file git2/sys/config.h * @brief Git config backend routines * @defgroup git_backend Git custom backend APIs * @ingroup Git * @{ */ GIT_BEGIN_DECL /** * Generic backend that implements the interface to * access a configuration file */ struct git_config_backend { unsigned int version; struct git_config *cfg; /* Open means open the file/database and parse if necessary */ int (*open)(struct git_config_backend *, git_config_level_t level); int (*get)(const struct git_config_backend *, const char *key, const git_config_entry **entry); int (*get_multivar)(struct git_config_backend *, const char *key, const char *regexp, git_config_foreach_cb callback, void *payload); int (*set)(struct git_config_backend *, const char *key, const char *value); int (*set_multivar)(git_config_backend *cfg, const char *name, const char *regexp, const char *value); int (*del)(struct git_config_backend *, const char *key); int (*foreach)(struct git_config_backend *, const char *, git_config_foreach_cb callback, void *payload); int (*refresh)(struct git_config_backend *); void (*free)(struct git_config_backend *); }; #define GIT_CONFIG_BACKEND_VERSION 1 #define GIT_CONFIG_BACKEND_INIT {GIT_CONFIG_BACKEND_VERSION} /** * Add a generic config file instance to an existing config * * Note that the configuration object will free the file * automatically. * * Further queries on this config object will access each * of the config file instances in order (instances with * a higher priority level will be accessed first). * * @param cfg the configuration to add the file to * @param file the configuration file (backend) to add * @param level the priority level of the backend * @param force if a config file already exists for the given * priority level, replace it * @return 0 on success, GIT_EEXISTS when adding more than one file * for a given priority level (and force_replace set to 0), or error code */ GIT_EXTERN(int) git_config_add_backend( git_config *cfg, git_config_backend *file, git_config_level_t level, int force); /** @} */ GIT_END_DECL #endif libgit2-0.19.0/include/git2/sys/index.h000066400000000000000000000122161216214232500175230ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #ifndef INCLUDE_sys_git_index_h__ #define INCLUDE_sys_git_index_h__ /** * @file git2/sys/index.h * @brief Low-level Git index manipulation routines * @defgroup git_backend Git custom backend APIs * @ingroup Git * @{ */ GIT_BEGIN_DECL /** Representation of a rename conflict entry in the index. */ typedef struct git_index_name_entry { char *ancestor; char *ours; char *theirs; } git_index_name_entry; /** Representation of a resolve undo entry in the index. */ typedef struct git_index_reuc_entry { unsigned int mode[3]; git_oid oid[3]; char *path; } git_index_reuc_entry; /** @name Conflict Name entry functions * * These functions work on rename conflict entries. */ /**@{*/ /** * Get the count of filename conflict entries currently in the index. * * @param index an existing index object * @return integer of count of current filename conflict entries */ GIT_EXTERN(unsigned int) git_index_name_entrycount(git_index *index); /** * Get a filename conflict entry from the index. * * The returned entry is read-only and should not be modified * or freed by the caller. * * @param index an existing index object * @param n the position of the entry * @return a pointer to the filename conflict entry; NULL if out of bounds */ GIT_EXTERN(const git_index_name_entry *) git_index_name_get_byindex( git_index *index, size_t n); /** * Record the filenames involved in a rename conflict. * * @param index an existing index object * @param ancestor the path of the file as it existed in the ancestor * @param ours the path of the file as it existed in our tree * @param theirs the path of the file as it existed in their tree */ GIT_EXTERN(int) git_index_name_add(git_index *index, const char *ancestor, const char *ours, const char *theirs); /** * Remove all filename conflict entries. * * @param index an existing index object * @return 0 or an error code */ GIT_EXTERN(void) git_index_name_clear(git_index *index); /**@}*/ /** @name Resolve Undo (REUC) index entry manipulation. * * These functions work on the Resolve Undo index extension and contains * data about the original files that led to a merge conflict. */ /**@{*/ /** * Get the count of resolve undo entries currently in the index. * * @param index an existing index object * @return integer of count of current resolve undo entries */ GIT_EXTERN(unsigned int) git_index_reuc_entrycount(git_index *index); /** * Finds the resolve undo entry that points to the given path in the Git * index. * * @param at_pos the address to which the position of the reuc entry is written (optional) * @param index an existing index object * @param path path to search * @return 0 if found, < 0 otherwise (GIT_ENOTFOUND) */ GIT_EXTERN(int) git_index_reuc_find(size_t *at_pos, git_index *index, const char *path); /** * Get a resolve undo entry from the index. * * The returned entry is read-only and should not be modified * or freed by the caller. * * @param index an existing index object * @param path path to search * @return the resolve undo entry; NULL if not found */ GIT_EXTERN(const git_index_reuc_entry *) git_index_reuc_get_bypath(git_index *index, const char *path); /** * Get a resolve undo entry from the index. * * The returned entry is read-only and should not be modified * or freed by the caller. * * @param index an existing index object * @param n the position of the entry * @return a pointer to the resolve undo entry; NULL if out of bounds */ GIT_EXTERN(const git_index_reuc_entry *) git_index_reuc_get_byindex(git_index *index, size_t n); /** * Adds a resolve undo entry for a file based on the given parameters. * * The resolve undo entry contains the OIDs of files that were involved * in a merge conflict after the conflict has been resolved. This allows * conflicts to be re-resolved later. * * If there exists a resolve undo entry for the given path in the index, * it will be removed. * * This method will fail in bare index instances. * * @param index an existing index object * @param path filename to add * @param ancestor_mode mode of the ancestor file * @param ancestor_id oid of the ancestor file * @param our_mode mode of our file * @param our_id oid of our file * @param their_mode mode of their file * @param their_id oid of their file * @return 0 or an error code */ GIT_EXTERN(int) git_index_reuc_add(git_index *index, const char *path, int ancestor_mode, const git_oid *ancestor_id, int our_mode, const git_oid *our_id, int their_mode, const git_oid *their_id); /** * Remove an resolve undo entry from the index * * @param index an existing index object * @param n position of the resolve undo entry to remove * @return 0 or an error code */ GIT_EXTERN(int) git_index_reuc_remove(git_index *index, size_t n); /** * Remove all resolve undo entries from the index * * @param index an existing index object * @return 0 or an error code */ GIT_EXTERN(void) git_index_reuc_clear(git_index *index); /**@}*/ /** @} */ GIT_END_DECL #endif libgit2-0.19.0/include/git2/sys/odb_backend.h000066400000000000000000000042761216214232500206360ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #ifndef INCLUDE_sys_git_odb_backend_h__ #define INCLUDE_sys_git_odb_backend_h__ #include "git2/common.h" #include "git2/types.h" #include "git2/oid.h" #include "git2/odb.h" /** * @file git2/sys/backend.h * @brief Git custom backend implementors functions * @defgroup git_backend Git custom backend APIs * @ingroup Git * @{ */ GIT_BEGIN_DECL /** * An instance for a custom backend */ struct git_odb_backend { unsigned int version; git_odb *odb; /* read and read_prefix each return to libgit2 a buffer which * will be freed later. The buffer should be allocated using * the function git_odb_backend_malloc to ensure that it can * be safely freed later. */ int (* read)( void **, size_t *, git_otype *, git_odb_backend *, const git_oid *); /* To find a unique object given a prefix * of its oid. * The oid given must be so that the * remaining (GIT_OID_HEXSZ - len)*4 bits * are 0s. */ int (* read_prefix)( git_oid *, void **, size_t *, git_otype *, git_odb_backend *, const git_oid *, size_t); int (* read_header)( size_t *, git_otype *, git_odb_backend *, const git_oid *); /* The writer may assume that the object * has already been hashed and is passed * in the first parameter. */ int (* write)( git_oid *, git_odb_backend *, const void *, size_t, git_otype); int (* writestream)( git_odb_stream **, git_odb_backend *, size_t, git_otype); int (* readstream)( git_odb_stream **, git_odb_backend *, const git_oid *); int (* exists)( git_odb_backend *, const git_oid *); int (* refresh)(git_odb_backend *); int (* foreach)( git_odb_backend *, git_odb_foreach_cb cb, void *payload); int (* writepack)( git_odb_writepack **, git_odb_backend *, git_transfer_progress_callback progress_cb, void *progress_payload); void (* free)(git_odb_backend *); }; #define GIT_ODB_BACKEND_VERSION 1 #define GIT_ODB_BACKEND_INIT {GIT_ODB_BACKEND_VERSION} GIT_EXTERN(void *) git_odb_backend_malloc(git_odb_backend *backend, size_t len); GIT_END_DECL #endif libgit2-0.19.0/include/git2/sys/refdb_backend.h000066400000000000000000000101211216214232500211360ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #ifndef INCLUDE_sys_git_refdb_backend_h__ #define INCLUDE_sys_git_refdb_backend_h__ #include "git2/common.h" #include "git2/types.h" #include "git2/oid.h" /** * @file git2/refdb_backend.h * @brief Git custom refs backend functions * @defgroup git_refdb_backend Git custom refs backend API * @ingroup Git * @{ */ GIT_BEGIN_DECL /** * Every backend's iterator must have a pointer to itself as the first * element, so the API can talk to it. You'd define your iterator as * * struct my_iterator { * git_reference_iterator parent; * ... * } * * and assign `iter->parent.backend` to your `git_refdb_backend`. */ struct git_reference_iterator { git_refdb *db; /** * Return the current reference and advance the iterator. */ int (*next)( git_reference **ref, git_reference_iterator *iter); /** * Return the name of the current reference and advance the iterator */ int (*next_name)( const char **ref_name, git_reference_iterator *iter); /** * Free the iterator */ void (*free)( git_reference_iterator *iter); }; /** An instance for a custom backend */ struct git_refdb_backend { unsigned int version; /** * Queries the refdb backend to determine if the given ref_name * exists. A refdb implementation must provide this function. */ int (*exists)( int *exists, git_refdb_backend *backend, const char *ref_name); /** * Queries the refdb backend for a given reference. A refdb * implementation must provide this function. */ int (*lookup)( git_reference **out, git_refdb_backend *backend, const char *ref_name); /** * Allocate an iterator object for the backend. * * A refdb implementation must provide this function. */ int (*iterator)( git_reference_iterator **iter, struct git_refdb_backend *backend, const char *glob); /* * Writes the given reference to the refdb. A refdb implementation * must provide this function. */ int (*write)(git_refdb_backend *backend, const git_reference *ref, int force); int (*rename)( git_reference **out, git_refdb_backend *backend, const char *old_name, const char *new_name, int force); /** * Deletes the given reference from the refdb. A refdb implementation * must provide this function. */ int (*delete)(git_refdb_backend *backend, const char *ref_name); /** * Suggests that the given refdb compress or optimize its references. * This mechanism is implementation specific. (For on-disk reference * databases, this may pack all loose references.) A refdb * implementation may provide this function; if it is not provided, * nothing will be done. */ int (*compress)(git_refdb_backend *backend); /** * Frees any resources held by the refdb. A refdb implementation may * provide this function; if it is not provided, nothing will be done. */ void (*free)(git_refdb_backend *backend); }; #define GIT_ODB_BACKEND_VERSION 1 #define GIT_ODB_BACKEND_INIT {GIT_ODB_BACKEND_VERSION} /** * Constructors for default filesystem-based refdb backend * * Under normal usage, this is called for you when the repository is * opened / created, but you can use this to explicitly construct a * filesystem refdb backend for a repository. * * @param backend_out Output pointer to the git_refdb_backend object * @param repo Git repository to access * @return 0 on success, <0 error code on failure */ GIT_EXTERN(int) git_refdb_backend_fs( git_refdb_backend **backend_out, git_repository *repo); /** * Sets the custom backend to an existing reference DB * * The `git_refdb` will take ownership of the `git_refdb_backend` so you * should NOT free it after calling this function. * * @param refdb database to add the backend to * @param backend pointer to a git_refdb_backend instance * @return 0 on success; error code otherwise */ GIT_EXTERN(int) git_refdb_set_backend( git_refdb *refdb, git_refdb_backend *backend); GIT_END_DECL #endif libgit2-0.19.0/include/git2/sys/refs.h000066400000000000000000000017731216214232500173610ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #ifndef INCLUDE_sys_git_refdb_h__ #define INCLUDE_sys_git_refdb_h__ #include "git2/common.h" #include "git2/types.h" #include "git2/oid.h" /** * Create a new direct reference from an OID. * * @param name the reference name * @param oid the object id for a direct reference * @param symbolic the target for a symbolic reference * @return the created git_reference or NULL on error */ GIT_EXTERN(git_reference *) git_reference__alloc( const char *name, const git_oid *oid, const git_oid *peel); /** * Create a new symbolic reference. * * @param name the reference name * @param symbolic the target for a symbolic reference * @return the created git_reference or NULL on error */ GIT_EXTERN(git_reference *) git_reference__alloc_symbolic( const char *name, const char *target); #endif libgit2-0.19.0/include/git2/sys/repository.h000066400000000000000000000061501216214232500206330ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #ifndef INCLUDE_sys_git_repository_h__ #define INCLUDE_sys_git_repository_h__ /** * @file git2/sys/repository.h * @brief Git repository custom implementation routines * @defgroup git_backend Git custom backend APIs * @ingroup Git * @{ */ GIT_BEGIN_DECL /** * Create a new repository with neither backends nor config object * * Note that this is only useful if you wish to associate the repository * with a non-filesystem-backed object database and config store. * * @param out The blank repository * @return 0 on success, or an error code */ GIT_EXTERN(int) git_repository_new(git_repository **out); /** * Reset all the internal state in a repository. * * This will free all the mapped memory and internal objects * of the repository and leave it in a "blank" state. * * There's no need to call this function directly unless you're * trying to aggressively cleanup the repo before its * deallocation. `git_repository_free` already performs this operation * before deallocation the repo. */ GIT_EXTERN(void) git_repository__cleanup(git_repository *repo); /** * Set the configuration file for this repository * * This configuration file will be used for all configuration * queries involving this repository. * * The repository will keep a reference to the config file; * the user must still free the config after setting it * to the repository, or it will leak. * * @param repo A repository object * @param config A Config object */ GIT_EXTERN(void) git_repository_set_config(git_repository *repo, git_config *config); /** * Set the Object Database for this repository * * The ODB will be used for all object-related operations * involving this repository. * * The repository will keep a reference to the ODB; the user * must still free the ODB object after setting it to the * repository, or it will leak. * * @param repo A repository object * @param odb An ODB object */ GIT_EXTERN(void) git_repository_set_odb(git_repository *repo, git_odb *odb); /** * Set the Reference Database Backend for this repository * * The refdb will be used for all reference related operations * involving this repository. * * The repository will keep a reference to the refdb; the user * must still free the refdb object after setting it to the * repository, or it will leak. * * @param repo A repository object * @param refdb An refdb object */ GIT_EXTERN(void) git_repository_set_refdb(git_repository *repo, git_refdb *refdb); /** * Set the index file for this repository * * This index will be used for all index-related operations * involving this repository. * * The repository will keep a reference to the index file; * the user must still free the index after setting it * to the repository, or it will leak. * * @param repo A repository object * @param index An index object */ GIT_EXTERN(void) git_repository_set_index(git_repository *repo, git_index *index); /** @} */ GIT_END_DECL #endif libgit2-0.19.0/include/git2/tag.h000066400000000000000000000231341216214232500163520ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #ifndef INCLUDE_git_tag_h__ #define INCLUDE_git_tag_h__ #include "common.h" #include "types.h" #include "oid.h" #include "object.h" #include "strarray.h" /** * @file git2/tag.h * @brief Git tag parsing routines * @defgroup git_tag Git tag management * @ingroup Git * @{ */ GIT_BEGIN_DECL /** * Lookup a tag object from the repository. * * @param out pointer to the looked up tag * @param repo the repo to use when locating the tag. * @param id identity of the tag to locate. * @return 0 or an error code */ GIT_EXTERN(int) git_tag_lookup( git_tag **out, git_repository *repo, const git_oid *id); /** * Lookup a tag object from the repository, * given a prefix of its identifier (short id). * * @see git_object_lookup_prefix * * @param out pointer to the looked up tag * @param repo the repo to use when locating the tag. * @param id identity of the tag to locate. * @param len the length of the short identifier * @return 0 or an error code */ GIT_EXTERN(int) git_tag_lookup_prefix( git_tag **out, git_repository *repo, const git_oid *id, size_t len); /** * Close an open tag * * You can no longer use the git_tag pointer after this call. * * IMPORTANT: You MUST call this method when you are through with a tag to * release memory. Failure to do so will cause a memory leak. * * @param tag the tag to close */ GIT_EXTERN(void) git_tag_free(git_tag *tag); /** * Get the id of a tag. * * @param tag a previously loaded tag. * @return object identity for the tag. */ GIT_EXTERN(const git_oid *) git_tag_id(const git_tag *tag); /** * Get the repository that contains the tag. * * @param tag A previously loaded tag. * @return Repository that contains this tag. */ GIT_EXTERN(git_repository *) git_tag_owner(const git_tag *tag); /** * Get the tagged object of a tag * * This method performs a repository lookup for the * given object and returns it * * @param target_out pointer where to store the target * @param tag a previously loaded tag. * @return 0 or an error code */ GIT_EXTERN(int) git_tag_target(git_object **target_out, const git_tag *tag); /** * Get the OID of the tagged object of a tag * * @param tag a previously loaded tag. * @return pointer to the OID */ GIT_EXTERN(const git_oid *) git_tag_target_id(const git_tag *tag); /** * Get the type of a tag's tagged object * * @param tag a previously loaded tag. * @return type of the tagged object */ GIT_EXTERN(git_otype) git_tag_target_type(const git_tag *tag); /** * Get the name of a tag * * @param tag a previously loaded tag. * @return name of the tag */ GIT_EXTERN(const char *) git_tag_name(const git_tag *tag); /** * Get the tagger (author) of a tag * * @param tag a previously loaded tag. * @return reference to the tag's author or NULL when unspecified */ GIT_EXTERN(const git_signature *) git_tag_tagger(const git_tag *tag); /** * Get the message of a tag * * @param tag a previously loaded tag. * @return message of the tag or NULL when unspecified */ GIT_EXTERN(const char *) git_tag_message(const git_tag *tag); /** * Create a new tag in the repository from an object * * A new reference will also be created pointing to * this tag object. If `force` is true and a reference * already exists with the given name, it'll be replaced. * * The message will not be cleaned up. This can be achieved * through `git_message_prettify()`. * * The tag name will be checked for validity. You must avoid * the characters '~', '^', ':', '\\', '?', '[', and '*', and the * sequences ".." and "@{" which have special meaning to revparse. * * @param oid Pointer where to store the OID of the * newly created tag. If the tag already exists, this parameter * will be the oid of the existing tag, and the function will * return a GIT_EEXISTS error code. * * @param repo Repository where to store the tag * * @param tag_name Name for the tag; this name is validated * for consistency. It should also not conflict with an * already existing tag name * * @param target Object to which this tag points. This object * must belong to the given `repo`. * * @param tagger Signature of the tagger for this tag, and * of the tagging time * * @param message Full message for this tag * * @param force Overwrite existing references * * @return 0 on success, GIT_EINVALIDSPEC or an error code * A tag object is written to the ODB, and a proper reference * is written in the /refs/tags folder, pointing to it */ GIT_EXTERN(int) git_tag_create( git_oid *oid, git_repository *repo, const char *tag_name, const git_object *target, const git_signature *tagger, const char *message, int force); /** * Create a new tag in the object database pointing to a git_object * * The message will not be cleaned up. This can be achieved * through `git_message_prettify()`. * * @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 * * @param target Object to which this tag points. This object * must belong to the given `repo`. * * @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 or an error code */ GIT_EXTERN(int) git_tag_annotation_create( git_oid *oid, git_repository *repo, const char *tag_name, const git_object *target, const git_signature *tagger, const char *message); /** * Create a new tag in the repository from a buffer * * @param oid Pointer where to store the OID of the newly created tag * @param repo Repository where to store the tag * @param buffer Raw tag data * @param force Overwrite existing tags * @return 0 on success; error code otherwise */ GIT_EXTERN(int) git_tag_create_frombuffer( git_oid *oid, git_repository *repo, const char *buffer, int force); /** * Create a new lightweight tag pointing at a target object * * A new direct reference will be created pointing to * this target object. If `force` is true and a reference * already exists with the given name, it'll be replaced. * * The tag name will be checked for validity. * See `git_tag_create()` for rules about valid names. * * @param oid Pointer where to store the OID of the provided * target object. If the tag already exists, this parameter * will be filled with the oid of the existing pointed object * and the function will return a GIT_EEXISTS error code. * * @param repo Repository where to store the lightweight tag * * @param tag_name Name for the tag; this name is validated * for consistency. It should also not conflict with an * already existing tag name * * @param target Object to which this tag points. This object * must belong to the given `repo`. * * @param force Overwrite existing references * * @return 0 on success, GIT_EINVALIDSPEC or an error code * A proper reference is written in the /refs/tags folder, * pointing to the provided target object */ GIT_EXTERN(int) git_tag_create_lightweight( git_oid *oid, git_repository *repo, const char *tag_name, const git_object *target, int force); /** * Delete an existing tag reference. * * The tag name will be checked for validity. * See `git_tag_create()` for rules about valid names. * * @param repo Repository where lives the tag * * @param tag_name Name of the tag to be deleted; * this name is validated for consistency. * * @return 0 on success, GIT_EINVALIDSPEC or an error code */ GIT_EXTERN(int) git_tag_delete( git_repository *repo, const char *tag_name); /** * Fill a list with all the tags in the Repository * * The string array will be filled with the names of the * matching tags; these values are owned by the user and * should be free'd manually when no longer needed, using * `git_strarray_free`. * * @param tag_names Pointer to a git_strarray structure where * the tag names will be stored * @param repo Repository where to find the tags * @return 0 or an error code */ GIT_EXTERN(int) git_tag_list( git_strarray *tag_names, git_repository *repo); /** * Fill a list with all the tags in the Repository * which name match a defined pattern * * If an empty pattern is provided, all the tags * will be returned. * * The string array will be filled with the names of the * matching tags; these values are owned by the user and * should be free'd manually when no longer needed, using * `git_strarray_free`. * * @param tag_names Pointer to a git_strarray structure where * the tag names will be stored * @param pattern Standard fnmatch pattern * @param repo Repository where to find the tags * @return 0 or an error code */ GIT_EXTERN(int) git_tag_list_match( git_strarray *tag_names, const char *pattern, git_repository *repo); typedef int (*git_tag_foreach_cb)(const char *name, git_oid *oid, void *payload); /** * Call callback `cb' for each tag in the repository * * @param repo Repository * @param callback Callback function * @param payload Pointer to callback data (optional) */ GIT_EXTERN(int) git_tag_foreach( git_repository *repo, git_tag_foreach_cb callback, void *payload); /** * Recursively peel a tag until a non tag git_object is found * * The retrieved `tag_target` object is owned by the repository * and should be closed with the `git_object_free` method. * * @param tag_target_out Pointer to the peeled git_object * @param tag The tag to be processed * @return 0 or an error code */ GIT_EXTERN(int) git_tag_peel( git_object **tag_target_out, const git_tag *tag); /** @} */ GIT_END_DECL #endif libgit2-0.19.0/include/git2/threads.h000066400000000000000000000021361216214232500172300ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #ifndef INCLUDE_git_threads_h__ #define INCLUDE_git_threads_h__ #include "common.h" /** * @file git2/threads.h * @brief Library level thread functions * @defgroup git_thread Threading functions * @ingroup Git * @{ */ GIT_BEGIN_DECL /** * Init the threading system. * * If libgit2 has been built with GIT_THREADS * on, this function must be called once before * any other library functions. * * If libgit2 has been built without GIT_THREADS * support, this function is a no-op. * * @return 0 or an error code */ GIT_EXTERN(int) git_threads_init(void); /** * Shutdown the threading system. * * If libgit2 has been built with GIT_THREADS * on, this function must be called before shutting * down the library. * * If libgit2 has been built without GIT_THREADS * support, this function is a no-op. */ GIT_EXTERN(void) git_threads_shutdown(void); /** @} */ GIT_END_DECL #endif libgit2-0.19.0/include/git2/trace.h000066400000000000000000000033551216214232500167000ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #ifndef INCLUDE_git_trace_h__ #define INCLUDE_git_trace_h__ #include "common.h" #include "types.h" /** * @file git2/trace.h * @brief Git tracing configuration routines * @defgroup git_trace Git tracing configuration routines * @ingroup Git * @{ */ GIT_BEGIN_DECL /** * Available tracing levels. When tracing is set to a particular level, * callers will be provided tracing at the given level and all lower levels. */ typedef enum { /** No tracing will be performed. */ GIT_TRACE_NONE = 0, /** Severe errors that may impact the program's execution */ GIT_TRACE_FATAL = 1, /** Errors that do not impact the program's execution */ GIT_TRACE_ERROR = 2, /** Warnings that suggest abnormal data */ GIT_TRACE_WARN = 3, /** Informational messages about program execution */ GIT_TRACE_INFO = 4, /** Detailed data that allows for debugging */ GIT_TRACE_DEBUG = 5, /** Exceptionally detailed debugging data */ GIT_TRACE_TRACE = 6 } git_trace_level_t; /** * An instance for a tracing function */ typedef void (*git_trace_callback)(git_trace_level_t level, const char *msg); /** * Sets the system tracing configuration to the specified level with the * specified callback. When system events occur at a level equal to, or * lower than, the given level they will be reported to the given callback. * * @param level Level to set tracing to * @param cb Function to call with trace data * @return 0 or an error code */ GIT_EXTERN(int) git_trace_set(git_trace_level_t level, git_trace_callback cb); /** @} */ GIT_END_DECL #endif libgit2-0.19.0/include/git2/transport.h000066400000000000000000000304551216214232500176370ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #ifndef INCLUDE_git_transport_h__ #define INCLUDE_git_transport_h__ #include "indexer.h" #include "net.h" #include "types.h" #ifdef GIT_SSH #include #endif /** * @file git2/transport.h * @brief Git transport interfaces and functions * @defgroup git_transport interfaces and functions * @ingroup Git * @{ */ GIT_BEGIN_DECL /* *** Begin interface for credentials acquisition *** */ typedef enum { /* git_cred_userpass_plaintext */ GIT_CREDTYPE_USERPASS_PLAINTEXT = 1, GIT_CREDTYPE_SSH_KEYFILE_PASSPHRASE = 2, GIT_CREDTYPE_SSH_PUBLICKEY = 3, } git_credtype_t; /* The base structure for all credential types */ typedef struct git_cred { git_credtype_t credtype; void (*free)( struct git_cred *cred); } git_cred; /* A plaintext username and password */ typedef struct git_cred_userpass_plaintext { git_cred parent; char *username; char *password; } git_cred_userpass_plaintext; #ifdef GIT_SSH typedef LIBSSH2_USERAUTH_PUBLICKEY_SIGN_FUNC((*git_cred_sign_callback)); /* A ssh key file and passphrase */ typedef struct git_cred_ssh_keyfile_passphrase { git_cred parent; char *publickey; char *privatekey; char *passphrase; } git_cred_ssh_keyfile_passphrase; /* A ssh public key and authentication callback */ typedef struct git_cred_ssh_publickey { git_cred parent; char *publickey; size_t publickey_len; void *sign_callback; void *sign_data; } git_cred_ssh_publickey; #endif /** * Creates a new plain-text username and password credential object. * The supplied credential parameter will be internally duplicated. * * @param out The newly created credential object. * @param username The username of the credential. * @param password The password of the credential. * @return 0 for success or an error code for failure */ GIT_EXTERN(int) git_cred_userpass_plaintext_new( git_cred **out, const char *username, const char *password); #ifdef GIT_SSH /** * Creates a new ssh key file and passphrase credential object. * The supplied credential parameter will be internally duplicated. * * @param out The newly created credential object. * @param publickey The path to the public key of the credential. * @param privatekey The path to the private key of the credential. * @param passphrase The passphrase of the credential. * @return 0 for success or an error code for failure */ GIT_EXTERN(int) git_cred_ssh_keyfile_passphrase_new( git_cred **out, const char *publickey, const char *privatekey, const char *passphrase); /** * Creates a new ssh public key credential object. * The supplied credential parameter will be internally duplicated. * * @param out The newly created credential object. * @param publickey The bytes of the public key. * @param publickey_len The length of the public key in bytes. * @param sign_callback The callback method for authenticating. * @param sign_data The abstract data sent to the sign_callback method. * @return 0 for success or an error code for failure */ GIT_EXTERN(int) git_cred_ssh_publickey_new( git_cred **out, const char *publickey, size_t publickey_len, git_cred_sign_callback, void *sign_data); #endif /** * Signature of a function which acquires a credential object. * * @param cred The newly created credential object. * @param url The resource for which we are demanding a credential. * @param username_from_url The username that was embedded in a "user@host" * remote url, or NULL if not included. * @param allowed_types A bitmask stating which cred types are OK to return. * @param payload The payload provided when specifying this callback. * @return 0 for success or an error code for failure */ typedef int (*git_cred_acquire_cb)( git_cred **cred, const char *url, const char *username_from_url, unsigned int allowed_types, void *payload); /* *** End interface for credentials acquisition *** *** Begin base transport interface *** */ typedef enum { GIT_TRANSPORTFLAGS_NONE = 0, /* If the connection is secured with SSL/TLS, the authenticity * of the server certificate should not be verified. */ GIT_TRANSPORTFLAGS_NO_CHECK_CERT = 1 } git_transport_flags_t; typedef void (*git_transport_message_cb)(const char *str, int len, void *data); typedef struct git_transport { unsigned int version; /* Set progress and error callbacks */ int (*set_callbacks)(struct git_transport *transport, git_transport_message_cb progress_cb, git_transport_message_cb error_cb, void *payload); /* Connect the transport to the remote repository, using the given * direction. */ int (*connect)(struct git_transport *transport, const char *url, git_cred_acquire_cb cred_acquire_cb, void *cred_acquire_payload, int direction, int flags); /* This function may be called after a successful call to connect(). The * provided callback is invoked for each ref discovered on the remote * end. */ int (*ls)(struct git_transport *transport, git_headlist_cb list_cb, void *payload); /* Executes the push whose context is in the git_push object. */ int (*push)(struct git_transport *transport, git_push *push); /* This function may be called after a successful call to connect(), when * the direction is FETCH. The function performs a negotiation to calculate * the wants list for the fetch. */ int (*negotiate_fetch)(struct git_transport *transport, git_repository *repo, const git_remote_head * const *refs, size_t count); /* This function may be called after a successful call to negotiate_fetch(), * when the direction is FETCH. This function retrieves the pack file for * the fetch from the remote end. */ int (*download_pack)(struct git_transport *transport, git_repository *repo, git_transfer_progress *stats, git_transfer_progress_callback progress_cb, void *progress_payload); /* Checks to see if the transport is connected */ int (*is_connected)(struct git_transport *transport); /* Reads the flags value previously passed into connect() */ int (*read_flags)(struct git_transport *transport, int *flags); /* Cancels any outstanding transport operation */ void (*cancel)(struct git_transport *transport); /* This function is the reverse of connect() -- it terminates the * connection to the remote end. */ int (*close)(struct git_transport *transport); /* Frees/destructs the git_transport object. */ void (*free)(struct git_transport *transport); } git_transport; #define GIT_TRANSPORT_VERSION 1 #define GIT_TRANSPORT_INIT {GIT_TRANSPORT_VERSION} /** * Function to use to create a transport from a URL. The transport database * is scanned to find a transport that implements the scheme of the URI (i.e. * git:// or http://) and a transport object is returned to the caller. * * @param out The newly created transport (out) * @param owner The git_remote which will own this transport * @param url The URL to connect to * @return 0 or an error code */ GIT_EXTERN(int) git_transport_new(git_transport **out, git_remote *owner, const char *url); /* Signature of a function which creates a transport */ typedef int (*git_transport_cb)(git_transport **out, git_remote *owner, void *param); /* Transports which come with libgit2 (match git_transport_cb). The expected * value for "param" is listed in-line below. */ /** * Create an instance of the dummy transport. * * @param out The newly created transport (out) * @param owner The git_remote which will own this transport * @param payload You must pass NULL for this parameter. * @return 0 or an error code */ GIT_EXTERN(int) git_transport_dummy( git_transport **out, git_remote *owner, /* NULL */ void *payload); /** * Create an instance of the local transport. * * @param out The newly created transport (out) * @param owner The git_remote which will own this transport * @param payload You must pass NULL for this parameter. * @return 0 or an error code */ GIT_EXTERN(int) git_transport_local( git_transport **out, git_remote *owner, /* NULL */ void *payload); /** * Create an instance of the smart transport. * * @param out The newly created transport (out) * @param owner The git_remote which will own this transport * @param payload A pointer to a git_smart_subtransport_definition * @return 0 or an error code */ GIT_EXTERN(int) git_transport_smart( git_transport **out, git_remote *owner, /* (git_smart_subtransport_definition *) */ void *payload); /* *** End of base transport interface *** *** Begin interface for subtransports for the smart transport *** */ /* The smart transport knows how to speak the git protocol, but it has no * knowledge of how to establish a connection between it and another endpoint, * or how to move data back and forth. For this, a subtransport interface is * declared, and the smart transport delegates this work to the subtransports. * Three subtransports are implemented: git, http, and winhttp. (The http and * winhttp transports each implement both http and https.) */ /* Subtransports can either be RPC = 0 (persistent connection) or RPC = 1 * (request/response). The smart transport handles the differences in its own * logic. The git subtransport is RPC = 0, while http and winhttp are both * RPC = 1. */ /* Actions that the smart transport can ask * a subtransport to perform */ typedef enum { GIT_SERVICE_UPLOADPACK_LS = 1, GIT_SERVICE_UPLOADPACK = 2, GIT_SERVICE_RECEIVEPACK_LS = 3, GIT_SERVICE_RECEIVEPACK = 4, } git_smart_service_t; struct git_smart_subtransport; /* A stream used by the smart transport to read and write data * from a subtransport */ typedef struct git_smart_subtransport_stream { /* The owning subtransport */ struct git_smart_subtransport *subtransport; int (*read)( struct git_smart_subtransport_stream *stream, char *buffer, size_t buf_size, size_t *bytes_read); int (*write)( struct git_smart_subtransport_stream *stream, const char *buffer, size_t len); void (*free)( struct git_smart_subtransport_stream *stream); } git_smart_subtransport_stream; /* An implementation of a subtransport which carries data for the * smart transport */ typedef struct git_smart_subtransport { int (* action)( git_smart_subtransport_stream **out, struct git_smart_subtransport *transport, const char *url, git_smart_service_t action); /* Subtransports are guaranteed a call to close() between * calls to action(), except for the following two "natural" progressions * of actions against a constant URL. * * 1. UPLOADPACK_LS -> UPLOADPACK * 2. RECEIVEPACK_LS -> RECEIVEPACK */ int (* close)(struct git_smart_subtransport *transport); void (* free)(struct git_smart_subtransport *transport); } git_smart_subtransport; /* A function which creates a new subtransport for the smart transport */ typedef int (*git_smart_subtransport_cb)( git_smart_subtransport **out, git_transport* owner); typedef struct git_smart_subtransport_definition { /* The function to use to create the git_smart_subtransport */ git_smart_subtransport_cb callback; /* True if the protocol is stateless; false otherwise. For example, * http:// is stateless, but git:// is not. */ unsigned rpc; } git_smart_subtransport_definition; /* Smart transport subtransports that come with libgit2 */ /** * Create an instance of the http subtransport. This subtransport * also supports https. On Win32, this subtransport may be implemented * using the WinHTTP library. * * @param out The newly created subtransport * @param owner The smart transport to own this subtransport * @return 0 or an error code */ GIT_EXTERN(int) git_smart_subtransport_http( git_smart_subtransport **out, git_transport* owner); /** * Create an instance of the git subtransport. * * @param out The newly created subtransport * @param owner The smart transport to own this subtransport * @return 0 or an error code */ GIT_EXTERN(int) git_smart_subtransport_git( git_smart_subtransport **out, git_transport* owner); /** * Create an instance of the ssh subtransport. * * @param out The newly created subtransport * @param owner The smart transport to own this subtransport * @return 0 or an error code */ GIT_EXTERN(int) git_smart_subtransport_ssh( git_smart_subtransport **out, git_transport* owner); /* *** End interface for subtransports for the smart transport *** */ /** @} */ GIT_END_DECL #endif libgit2-0.19.0/include/git2/tree.h000066400000000000000000000266321216214232500165440ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #ifndef INCLUDE_git_tree_h__ #define INCLUDE_git_tree_h__ #include "common.h" #include "types.h" #include "oid.h" #include "object.h" /** * @file git2/tree.h * @brief Git tree parsing, loading routines * @defgroup git_tree Git tree parsing, loading routines * @ingroup Git * @{ */ GIT_BEGIN_DECL /** * Lookup a tree object from the repository. * * @param out Pointer to the looked up tree * @param repo The repo to use when locating the tree. * @param id Identity of the tree to locate. * @return 0 or an error code */ GIT_EXTERN(int) git_tree_lookup( git_tree **out, git_repository *repo, const git_oid *id); /** * Lookup a tree object from the repository, * given a prefix of its identifier (short id). * * @see git_object_lookup_prefix * * @param out pointer to the looked up tree * @param repo the repo to use when locating the tree. * @param id identity of the tree to locate. * @param len the length of the short identifier * @return 0 or an error code */ GIT_EXTERN(int) git_tree_lookup_prefix( git_tree **out, git_repository *repo, const git_oid *id, size_t len); /** * Close an open tree * * You can no longer use the git_tree pointer after this call. * * IMPORTANT: You MUST call this method when you stop using a tree to * release memory. Failure to do so will cause a memory leak. * * @param tree The tree to close */ GIT_EXTERN(void) git_tree_free(git_tree *tree); /** * Get the id of a tree. * * @param tree a previously loaded tree. * @return object identity for the tree. */ GIT_EXTERN(const git_oid *) git_tree_id(const git_tree *tree); /** * Get the repository that contains the tree. * * @param tree A previously loaded tree. * @return Repository that contains this tree. */ GIT_EXTERN(git_repository *) git_tree_owner(const git_tree *tree); /** * Get the number of entries listed in a tree * * @param tree a previously loaded tree. * @return the number of entries in the tree */ GIT_EXTERN(size_t) git_tree_entrycount(const git_tree *tree); /** * Lookup a tree entry by its filename * * This returns a git_tree_entry that is owned by the git_tree. You don't * have to free it, but you must not use it after the git_tree is released. * * @param tree a previously loaded tree. * @param filename the filename of the desired entry * @return the tree entry; NULL if not found */ GIT_EXTERN(const git_tree_entry *) git_tree_entry_byname( const git_tree *tree, const char *filename); /** * Lookup a tree entry by its position in the tree * * This returns a git_tree_entry that is owned by the git_tree. You don't * have to free it, but you must not use it after the git_tree is released. * * @param tree a previously loaded tree. * @param idx the position in the entry list * @return the tree entry; NULL if not found */ GIT_EXTERN(const git_tree_entry *) git_tree_entry_byindex( const git_tree *tree, size_t idx); /** * Lookup a tree entry by SHA value. * * This returns a git_tree_entry that is owned by the git_tree. You don't * have to free it, but you must not use it after the git_tree is released. * * Warning: this must examine every entry in the tree, so it is not fast. * * @param tree a previously loaded tree. * @param oid the sha being looked for * @return the tree entry; NULL if not found */ GIT_EXTERN(const git_tree_entry *) git_tree_entry_byoid( const git_tree *tree, const git_oid *oid); /** * Retrieve a tree entry contained in a tree or in any of its subtrees, * given its relative path. * * Unlike the other lookup functions, the returned tree entry is owned by * the user and must be freed explicitly with `git_tree_entry_free()`. * * @param out Pointer where to store the tree entry * @param root Previously loaded tree which is the root of the relative path * @param path Path to the contained entry * @return 0 on success; GIT_ENOTFOUND if the path does not exist */ GIT_EXTERN(int) git_tree_entry_bypath( git_tree_entry **out, const git_tree *root, const char *path); /** * Duplicate a tree entry * * Create a copy of a tree entry. The returned copy is owned by the user, * and must be freed explicitly with `git_tree_entry_free()`. * * @param entry A tree entry to duplicate * @return a copy of the original entry or NULL on error (alloc failure) */ GIT_EXTERN(git_tree_entry *) git_tree_entry_dup(const git_tree_entry *entry); /** * Free a user-owned tree entry * * IMPORTANT: This function is only needed for tree entries owned by the * user, such as the ones returned by `git_tree_entry_dup()` or * `git_tree_entry_bypath()`. * * @param entry The entry to free */ GIT_EXTERN(void) git_tree_entry_free(git_tree_entry *entry); /** * Get the filename of a tree entry * * @param entry a tree entry * @return the name of the file */ GIT_EXTERN(const char *) git_tree_entry_name(const git_tree_entry *entry); /** * Get the id of the object pointed by the entry * * @param entry a tree entry * @return the oid of the object */ GIT_EXTERN(const git_oid *) git_tree_entry_id(const git_tree_entry *entry); /** * Get the type of the object pointed by the entry * * @param entry a tree entry * @return the type of the pointed object */ GIT_EXTERN(git_otype) git_tree_entry_type(const git_tree_entry *entry); /** * Get the UNIX file attributes of a tree entry * * @param entry a tree entry * @return filemode as an integer */ GIT_EXTERN(git_filemode_t) git_tree_entry_filemode(const git_tree_entry *entry); /** * Compare two tree entries * * @param e1 first tree entry * @param e2 second tree entry * @return <0 if e1 is before e2, 0 if e1 == e2, >0 if e1 is after e2 */ GIT_EXTERN(int) git_tree_entry_cmp(const git_tree_entry *e1, const git_tree_entry *e2); /** * Convert a tree entry to the git_object it points too. * * You must call `git_object_free()` on the object when you are done with it. * * @param object_out pointer to the converted object * @param repo repository where to lookup the pointed object * @param entry a tree entry * @return 0 or an error code */ GIT_EXTERN(int) git_tree_entry_to_object( git_object **object_out, git_repository *repo, const git_tree_entry *entry); /** * Create a new tree builder. * * The tree builder can be used to create or modify trees in memory and * write them as tree objects to the database. * * If the `source` parameter is not NULL, the tree builder will be * initialized with the entries of the given tree. * * If the `source` parameter is NULL, the tree builder will start with no * entries and will have to be filled manually. * * @param out Pointer where to store the tree builder * @param source Source tree to initialize the builder (optional) * @return 0 on success; error code otherwise */ GIT_EXTERN(int) git_treebuilder_create( git_treebuilder **out, const git_tree *source); /** * Clear all the entires in the builder * * @param bld Builder to clear */ GIT_EXTERN(void) git_treebuilder_clear(git_treebuilder *bld); /** * Get the number of entries listed in a treebuilder * * @param bld a previously loaded treebuilder. * @return the number of entries in the treebuilder */ GIT_EXTERN(unsigned int) git_treebuilder_entrycount(git_treebuilder *bld); /** * Free a tree builder * * This will clear all the entries and free to builder. * Failing to free the builder after you're done using it * will result in a memory leak * * @param bld Builder to free */ GIT_EXTERN(void) git_treebuilder_free(git_treebuilder *bld); /** * Get an entry from the builder from its filename * * The returned entry is owned by the builder and should * not be freed manually. * * @param bld Tree builder * @param filename Name of the entry * @return pointer to the entry; NULL if not found */ GIT_EXTERN(const git_tree_entry *) git_treebuilder_get( git_treebuilder *bld, const char *filename); /** * Add or update an entry to the builder * * Insert a new entry for `filename` in the builder with the * given attributes. * * If an entry named `filename` already exists, its attributes * will be updated with the given ones. * * The optional pointer `out` can be used to retrieve a pointer to * the newly created/updated entry. Pass NULL if you do not need it. * * No attempt is being made to ensure that the provided oid points * to an existing git object in the object database, nor that the * attributes make sense regarding the type of the pointed at object. * * @param out Pointer to store the entry (optional) * @param bld Tree builder * @param filename Filename of the entry * @param id SHA1 oid of the entry * @param filemode Folder attributes of the entry. This parameter must * be valued with one of the following entries: 0040000, 0100644, * 0100755, 0120000 or 0160000. * @return 0 or an error code */ GIT_EXTERN(int) git_treebuilder_insert( const git_tree_entry **out, git_treebuilder *bld, const char *filename, const git_oid *id, git_filemode_t filemode); /** * Remove an entry from the builder by its filename * * @param bld Tree builder * @param filename Filename of the entry to remove */ GIT_EXTERN(int) git_treebuilder_remove( git_treebuilder *bld, const char *filename); typedef int (*git_treebuilder_filter_cb)( const git_tree_entry *entry, void *payload); /** * Filter the entries in the tree * * The `filter` callback will be called for each entry in the tree with a * pointer to the entry and the provided `payload`; if the callback returns * non-zero, the entry will be filtered (removed from the builder). * * @param bld Tree builder * @param filter Callback to filter entries * @param payload Extra data to pass to filter */ GIT_EXTERN(void) git_treebuilder_filter( git_treebuilder *bld, git_treebuilder_filter_cb filter, void *payload); /** * Write the contents of the tree builder as a tree object * * The tree builder will be written to the given `repo`, and its * identifying SHA1 hash will be stored in the `id` pointer. * * @param id Pointer to store the OID of the newly written tree * @param repo Repository in which to store the object * @param bld Tree builder to write * @return 0 or an error code */ GIT_EXTERN(int) git_treebuilder_write( git_oid *id, git_repository *repo, git_treebuilder *bld); /** Callback for the tree traversal method */ typedef int (*git_treewalk_cb)( const char *root, const git_tree_entry *entry, void *payload); /** Tree traversal modes */ typedef enum { GIT_TREEWALK_PRE = 0, /* Pre-order */ GIT_TREEWALK_POST = 1, /* Post-order */ } git_treewalk_mode; /** * Traverse the entries in a tree and its subtrees in post or pre order. * * The entries will be traversed in the specified order, children subtrees * will be automatically loaded as required, and the `callback` will be * called once per entry with the current (relative) root for the entry and * the entry data itself. * * If the callback returns a positive value, the passed entry will be * skipped on the traversal (in pre mode). A negative value stops the walk. * * @param tree The tree to walk * @param mode Traversal mode (pre or post-order) * @param callback Function to call on each tree entry * @param payload Opaque pointer to be passed on each callback * @return 0 or an error code */ GIT_EXTERN(int) git_tree_walk( const git_tree *tree, git_treewalk_mode mode, git_treewalk_cb callback, void *payload); /** @} */ GIT_END_DECL #endif libgit2-0.19.0/include/git2/types.h000066400000000000000000000153671216214232500167540ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #ifndef INCLUDE_git_types_h__ #define INCLUDE_git_types_h__ #include "common.h" /** * @file git2/types.h * @brief libgit2 base & compatibility types * @ingroup Git * @{ */ GIT_BEGIN_DECL /** * Cross-platform compatibility types for off_t / time_t * * NOTE: This needs to be in a public header so that both the library * implementation and client applications both agree on the same types. * Otherwise we get undefined behavior. * * Use the "best" types that each platform provides. Currently we truncate * these intermediate representations for compatibility with the git ABI, but * if and when it changes to support 64 bit types, our code will naturally * adapt. * NOTE: These types should match those that are returned by our internal * stat() functions, for all platforms. */ #include #ifdef __amigaos4__ #include #endif #if defined(_MSC_VER) typedef __int64 git_off_t; typedef __time64_t git_time_t; #elif defined(__MINGW32__) typedef off64_t git_off_t; typedef __time64_t git_time_t; #elif defined(__HAIKU__) typedef __haiku_std_int64 git_off_t; typedef __haiku_std_int64 git_time_t; #else /* POSIX */ /* * Note: Can't use off_t since if a client program includes * before us (directly or indirectly), they'll get 32 bit off_t in their client * app, even though /we/ define _FILE_OFFSET_BITS=64. */ typedef int64_t git_off_t; typedef int64_t git_time_t; #endif /** Basic type (loose or packed) of any Git object. */ typedef enum { GIT_OBJ_ANY = -2, /**< Object can be any of the following */ GIT_OBJ_BAD = -1, /**< Object is invalid. */ GIT_OBJ__EXT1 = 0, /**< Reserved for future use. */ GIT_OBJ_COMMIT = 1, /**< A commit object. */ GIT_OBJ_TREE = 2, /**< A tree (directory listing) object. */ GIT_OBJ_BLOB = 3, /**< A file revision object. */ GIT_OBJ_TAG = 4, /**< An annotated tag object. */ GIT_OBJ__EXT2 = 5, /**< Reserved for future use. */ GIT_OBJ_OFS_DELTA = 6, /**< A delta, base is given by an offset. */ GIT_OBJ_REF_DELTA = 7, /**< A delta, base is given by object id. */ } git_otype; /** An open object database handle. */ typedef struct git_odb git_odb; /** A custom backend in an ODB */ typedef struct git_odb_backend git_odb_backend; /** An object read from the ODB */ typedef struct git_odb_object git_odb_object; /** A stream to read/write from the ODB */ typedef struct git_odb_stream git_odb_stream; /** A stream to write a packfile to the ODB */ typedef struct git_odb_writepack git_odb_writepack; /** An open refs database handle. */ typedef struct git_refdb git_refdb; /** A custom backend for refs */ typedef struct git_refdb_backend git_refdb_backend; /** * Representation of an existing git repository, * including all its object contents */ typedef struct git_repository git_repository; /** Representation of a generic object in a repository */ typedef struct git_object git_object; /** Representation of an in-progress walk through the commits in a repo */ typedef struct git_revwalk git_revwalk; /** Parsed representation of a tag object. */ typedef struct git_tag git_tag; /** In-memory representation of a blob object. */ typedef struct git_blob git_blob; /** Parsed representation of a commit object. */ typedef struct git_commit git_commit; /** Representation of each one of the entries in a tree object. */ typedef struct git_tree_entry git_tree_entry; /** Representation of a tree object. */ typedef struct git_tree git_tree; /** Constructor for in-memory trees */ typedef struct git_treebuilder git_treebuilder; /** Memory representation of an index file. */ typedef struct git_index git_index; /** An interator for conflicts in the index. */ typedef struct git_index_conflict_iterator git_index_conflict_iterator; /** Memory representation of a set of config files */ typedef struct git_config git_config; /** Interface to access a configuration file */ typedef struct git_config_backend git_config_backend; /** Representation of a reference log entry */ typedef struct git_reflog_entry git_reflog_entry; /** Representation of a reference log */ typedef struct git_reflog git_reflog; /** Representation of a git note */ typedef struct git_note git_note; /** Representation of a git packbuilder */ typedef struct git_packbuilder git_packbuilder; /** Time in a signature */ typedef struct git_time { git_time_t time; /** time in seconds from epoch */ int offset; /** timezone offset, in minutes */ } git_time; /** An action signature (e.g. for committers, taggers, etc) */ typedef struct git_signature { char *name; /** full name of the author */ char *email; /** email of the author */ git_time when; /** time when the action happened */ } git_signature; /** In-memory representation of a reference. */ typedef struct git_reference git_reference; /** Iterator for references */ typedef struct git_reference_iterator git_reference_iterator; /** Merge heads, the input to merge */ typedef struct git_merge_head git_merge_head; /** Representation of a status collection */ typedef struct git_status_list git_status_list; /** Basic type of any Git reference. */ typedef enum { GIT_REF_INVALID = 0, /** Invalid reference */ GIT_REF_OID = 1, /** A reference which points at an object id */ GIT_REF_SYMBOLIC = 2, /** A reference which points at another reference */ GIT_REF_LISTALL = GIT_REF_OID|GIT_REF_SYMBOLIC, } git_ref_t; /** Basic type of any Git branch. */ typedef enum { GIT_BRANCH_LOCAL = 1, GIT_BRANCH_REMOTE = 2, } git_branch_t; /** Valid modes for index and tree entries. */ typedef enum { GIT_FILEMODE_NEW = 0000000, GIT_FILEMODE_TREE = 0040000, GIT_FILEMODE_BLOB = 0100644, GIT_FILEMODE_BLOB_EXECUTABLE = 0100755, GIT_FILEMODE_LINK = 0120000, GIT_FILEMODE_COMMIT = 0160000, } git_filemode_t; typedef struct git_refspec git_refspec; typedef struct git_remote git_remote; typedef struct git_push git_push; typedef struct git_remote_head git_remote_head; typedef struct git_remote_callbacks git_remote_callbacks; /** * This is passed as the first argument to the callback to allow the * user to see the progress. */ typedef struct git_transfer_progress { unsigned int total_objects; unsigned int indexed_objects; unsigned int received_objects; size_t received_bytes; } git_transfer_progress; /** * Type for progress callbacks during indexing. Return a value less than zero * to cancel the transfer. * * @param stats Structure containing information about the state of the transfer * @param payload Payload provided by caller */ typedef int (*git_transfer_progress_callback)(const git_transfer_progress *stats, void *payload); /** @} */ GIT_END_DECL #endif libgit2-0.19.0/include/git2/version.h000066400000000000000000000006311216214232500172610ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #ifndef INCLUDE_git_version_h__ #define INCLUDE_git_version_h__ #define LIBGIT2_VERSION "0.19.0" #define LIBGIT2_VER_MAJOR 0 #define LIBGIT2_VER_MINOR 19 #define LIBGIT2_VER_REVISION 0 #endif libgit2-0.19.0/libgit2.pc.in000066400000000000000000000004201216214232500154140ustar00rootroot00000000000000libdir=@CMAKE_INSTALL_PREFIX@/@LIB_INSTALL_DIR@ includedir=@CMAKE_INSTALL_PREFIX@/@INCLUDE_INSTALL_DIR@ Name: libgit2 Description: The git library, take 2 Version: @LIBGIT2_VERSION_STRING@ Requires: libcrypto Libs: -L${libdir} -lgit2 -lz -lcrypto Cflags: -I${includedir} libgit2-0.19.0/libgit2_clar.supp000066400000000000000000000007621216214232500164060ustar00rootroot00000000000000{ ignore-zlib-errors-cond Memcheck:Cond obj:*libz.so* } { ignore-giterr-set-leak Memcheck:Leak ... fun:giterr_set } { ignore-git-global-state-leak Memcheck:Leak ... fun:git__global_state } { ignore-openssl-ssl-leak Memcheck:Leak ... obj:*libssl.so* ... } { ignore-openssl-crypto-leak Memcheck:Leak ... obj:*libcrypto.so* ... } { ignore-openssl-crypto-cond Memcheck:Cond obj:*libcrypto.so* ... } { ignore-glibc-getaddrinfo-cache Memcheck:Leak ... fun:__check_pf } libgit2-0.19.0/packaging/000077500000000000000000000000001216214232500150575ustar00rootroot00000000000000libgit2-0.19.0/packaging/rpm/000077500000000000000000000000001216214232500156555ustar00rootroot00000000000000libgit2-0.19.0/packaging/rpm/README000066400000000000000000000003661216214232500165420ustar00rootroot00000000000000To build RPM pakcages for Fedora, follow these steps: cp packaging/rpm/libgit2.spec ~/rpmbuild/SPECS cd ~/rpmbuild/SOURCES wget https://github.com/downloads/libgit2/libgit2/libgit2-0.16.0.tar.gz cd ~/rpmbuild/SPECS rpmbuild -ba libgit2.spec libgit2-0.19.0/packaging/rpm/libgit2.spec000066400000000000000000000064651216214232500201000ustar00rootroot00000000000000# # spec file for package libgit2 # # Copyright (c) 2012 Saleem Ansari # Copyright (c) 2012 SUSE LINUX Products GmbH, Nuernberg, Germany. # Copyright (c) 2011, Sascha Peilicke # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed # upon. The license for this file, and modifications and additions to the # file, is the same license as for the pristine package itself (unless the # license for the pristine package is not an Open Source License, in which # case the license is the MIT License). An "Open Source License" is a # license that conforms to the Open Source Definition (Version 1.9) # published by the Open Source Initiative. # Please submit bugfixes or comments via http://bugs.opensuse.org/ # Name: libgit2 Version: 0.16.0 Release: 1 Summary: C git library License: GPL-2.0 with linking Group: Development/Libraries/C and C++ Url: http://libgit2.github.com/ Source0: https://github.com/downloads/libgit2/libgit2/libgit2-0.16.0.tar.gz BuildRequires: cmake BuildRequires: pkgconfig BuildRoot: %{_tmppath}/%{name}-%{version}-build %if 0%{?fedora} || 0%{?rhel_version} || 0%{?centos_version} BuildRequires: openssl-devel %else BuildRequires: libopenssl-devel %endif %description libgit2 is a portable, pure C implementation of the Git core methods provided as a re-entrant linkable library with a solid API, allowing you to write native speed custom Git applications in any language with bindings. %package -n %{name}-0 Summary: C git library Group: System/Libraries %description -n %{name}-0 libgit2 is a portable, pure C implementation of the Git core methods provided as a re-entrant linkable library with a solid API, allowing you to write native speed custom Git applications in any language with bindings. %package devel Summary: C git library Group: Development/Libraries/C and C++ Requires: %{name}-0 >= %{version} %description devel This package contains all necessary include files and libraries needed to compile and develop applications that use libgit2. %prep %setup -q %build cmake . \ -DCMAKE_C_FLAGS:STRING="%{optflags}" \ -DCMAKE_INSTALL_PREFIX:PATH=%{_prefix} \ -DLIB_INSTALL_DIR:PATH=%{_libdir}S make %{?_smp_mflags} %install %make_install %post -n %{name}-0 -p /sbin/ldconfig %postun -n %{name}-0 -p /sbin/ldconfig %files -n %{name}-0 %defattr (-,root,root) %doc AUTHORS COPYING README.md %{_libdir}/%{name}.so.* %files devel %defattr (-,root,root) %doc CONVENTIONS examples %{_libdir}/%{name}.so %{_includedir}/git2* %{_libdir}/pkgconfig/libgit2.pc %changelog * Tue Mar 04 2012 tuxdna@gmail.com - Update to version 0.16.0 * Tue Jan 31 2012 jengelh@medozas.de - Provide pkgconfig symbols * Thu Oct 27 2011 saschpe@suse.de - Change license to 'GPL-2.0 with linking', fixes bnc#726789 * Wed Oct 26 2011 saschpe@suse.de - Update to version 0.15.0: * Upstream doesn't provide changes - Removed outdated %%clean section * Tue Jan 18 2011 saschpe@gmx.de - Proper Requires for devel package * Tue Jan 18 2011 saschpe@gmx.de - Set BuildRequires to "openssl-devel" also for RHEL and CentOS * Tue Jan 18 2011 saschpe@gmx.de - Initial commit (0.0.1) - Added patch to fix shared library soname libgit2-0.19.0/src/000077500000000000000000000000001216214232500137225ustar00rootroot00000000000000libgit2-0.19.0/src/amiga/000077500000000000000000000000001216214232500150005ustar00rootroot00000000000000libgit2-0.19.0/src/amiga/map.c000066400000000000000000000017171216214232500157270ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #include #ifndef GIT_WIN32 #include "posix.h" #include "map.h" #include int p_mmap(git_map *out, size_t len, int prot, int flags, int fd, git_off_t offset) { GIT_MMAP_VALIDATE(out, len, prot, flags); out->data = NULL; out->len = 0; if ((prot & GIT_PROT_WRITE) && ((flags & GIT_MAP_TYPE) == GIT_MAP_SHARED)) { giterr_set(GITERR_OS, "Trying to map shared-writeable"); return -1; } out->data = malloc(len); GITERR_CHECK_ALLOC(out->data); if ((p_lseek(fd, offset, SEEK_SET) < 0) || ((size_t)p_read(fd, out->data, len) != len)) { giterr_set(GITERR_OS, "mmap emulation failed"); return -1; } out->len = len; return 0; } int p_munmap(git_map *map) { assert(map != NULL); free(map->data); return 0; } #endif libgit2-0.19.0/src/array.h000066400000000000000000000034571216214232500152220ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #ifndef INCLUDE_array_h__ #define INCLUDE_array_h__ #include "util.h" /* * Use this to declare a typesafe resizable array of items, a la: * * git_array_t(int) my_ints = GIT_ARRAY_INIT; * ... * int *i = git_array_alloc(my_ints); * GITERR_CHECK_ALLOC(i); * ... * git_array_clear(my_ints); * * You may also want to do things like: * * typedef git_array_t(my_struct) my_struct_array_t; */ #define git_array_t(type) struct { type *ptr; uint32_t size, asize; } #define GIT_ARRAY_INIT { NULL, 0, 0 } #define git_array_init(a) \ do { (a).size = (a).asize = 0; (a).ptr = NULL; } while (0) #define git_array_clear(a) \ do { git__free((a).ptr); git_array_init(a); } while (0) #define GITERR_CHECK_ARRAY(a) GITERR_CHECK_ALLOC((a).ptr) typedef git_array_t(void) git_array_generic_t; /* use a generic array for growth so this can return the new item */ GIT_INLINE(void *) git_array_grow(git_array_generic_t *a, size_t item_size) { uint32_t new_size = (a->size < 8) ? 8 : a->asize * 3 / 2; void *new_array = git__realloc(a->ptr, new_size * item_size); if (!new_array) { git_array_clear(*a); return NULL; } else { a->ptr = new_array; a->asize = new_size; a->size++; return (((char *)a->ptr) + (a->size - 1) * item_size); } } #define git_array_alloc(a) \ ((a).size >= (a).asize) ? \ git_array_grow((git_array_generic_t *)&(a), sizeof(*(a).ptr)) : \ (a).ptr ? &(a).ptr[(a).size++] : NULL #define git_array_last(a) ((a).size ? &(a).ptr[(a).size - 1] : NULL) #define git_array_get(a, i) (((i) < (a).size) ? &(a).ptr[(i)] : NULL) #define git_array_size(a) (a).size #endif libgit2-0.19.0/src/attr.c000066400000000000000000000403561216214232500150500ustar00rootroot00000000000000#include "repository.h" #include "fileops.h" #include "config.h" #include "attr.h" #include "ignore.h" #include "git2/oid.h" #include GIT__USE_STRMAP; const char *git_attr__true = "[internal]__TRUE__"; const char *git_attr__false = "[internal]__FALSE__"; const char *git_attr__unset = "[internal]__UNSET__"; git_attr_t git_attr_value(const char *attr) { if (attr == NULL || attr == git_attr__unset) return GIT_ATTR_UNSPECIFIED_T; if (attr == git_attr__true) return GIT_ATTR_TRUE_T; if (attr == git_attr__false) return GIT_ATTR_FALSE_T; return GIT_ATTR_VALUE_T; } static int collect_attr_files( git_repository *repo, uint32_t flags, const char *path, git_vector *files); int git_attr_get( const char **value, git_repository *repo, uint32_t flags, const char *pathname, const char *name) { int error; git_attr_path path; git_vector files = GIT_VECTOR_INIT; size_t i, j; git_attr_file *file; git_attr_name attr; git_attr_rule *rule; *value = NULL; if (git_attr_path__init(&path, pathname, git_repository_workdir(repo)) < 0) return -1; if ((error = collect_attr_files(repo, flags, pathname, &files)) < 0) goto cleanup; attr.name = name; attr.name_hash = git_attr_file__name_hash(name); git_vector_foreach(&files, i, file) { git_attr_file__foreach_matching_rule(file, &path, j, rule) { size_t pos; if (!git_vector_bsearch(&pos, &rule->assigns, &attr)) { *value = ((git_attr_assignment *)git_vector_get( &rule->assigns, pos))->value; goto cleanup; } } } cleanup: git_vector_free(&files); git_attr_path__free(&path); return error; } typedef struct { git_attr_name name; git_attr_assignment *found; } attr_get_many_info; int git_attr_get_many( const char **values, git_repository *repo, uint32_t flags, const char *pathname, size_t num_attr, const char **names) { int error; git_attr_path path; git_vector files = GIT_VECTOR_INIT; size_t i, j, k; git_attr_file *file; git_attr_rule *rule; attr_get_many_info *info = NULL; size_t num_found = 0; memset((void *)values, 0, sizeof(const char *) * num_attr); if (git_attr_path__init(&path, pathname, git_repository_workdir(repo)) < 0) return -1; if ((error = collect_attr_files(repo, flags, pathname, &files)) < 0) goto cleanup; info = git__calloc(num_attr, sizeof(attr_get_many_info)); GITERR_CHECK_ALLOC(info); git_vector_foreach(&files, i, file) { git_attr_file__foreach_matching_rule(file, &path, j, rule) { for (k = 0; k < num_attr; k++) { size_t pos; if (info[k].found != NULL) /* already found assignment */ continue; if (!info[k].name.name) { info[k].name.name = names[k]; info[k].name.name_hash = git_attr_file__name_hash(names[k]); } if (!git_vector_bsearch(&pos, &rule->assigns, &info[k].name)) { info[k].found = (git_attr_assignment *) git_vector_get(&rule->assigns, pos); values[k] = info[k].found->value; if (++num_found == num_attr) goto cleanup; } } } } cleanup: git_vector_free(&files); git_attr_path__free(&path); git__free(info); return error; } int git_attr_foreach( git_repository *repo, uint32_t flags, const char *pathname, int (*callback)(const char *name, const char *value, void *payload), void *payload) { int error; git_attr_path path; git_vector files = GIT_VECTOR_INIT; size_t i, j, k; git_attr_file *file; git_attr_rule *rule; git_attr_assignment *assign; git_strmap *seen = NULL; if (git_attr_path__init(&path, pathname, git_repository_workdir(repo)) < 0) return -1; if ((error = collect_attr_files(repo, flags, pathname, &files)) < 0) goto cleanup; seen = git_strmap_alloc(); GITERR_CHECK_ALLOC(seen); git_vector_foreach(&files, i, file) { git_attr_file__foreach_matching_rule(file, &path, j, rule) { git_vector_foreach(&rule->assigns, k, assign) { /* skip if higher priority assignment was already seen */ if (git_strmap_exists(seen, assign->name)) continue; git_strmap_insert(seen, assign->name, assign, error); if (error < 0) goto cleanup; error = callback(assign->name, assign->value, payload); if (error) { giterr_clear(); error = GIT_EUSER; goto cleanup; } } } } cleanup: git_strmap_free(seen); git_vector_free(&files); git_attr_path__free(&path); return error; } int git_attr_add_macro( git_repository *repo, const char *name, const char *values) { int error; git_attr_rule *macro = NULL; git_pool *pool; if (git_attr_cache__init(repo) < 0) return -1; macro = git__calloc(1, sizeof(git_attr_rule)); GITERR_CHECK_ALLOC(macro); pool = &git_repository_attr_cache(repo)->pool; macro->match.pattern = git_pool_strdup(pool, name); GITERR_CHECK_ALLOC(macro->match.pattern); macro->match.length = strlen(macro->match.pattern); macro->match.flags = GIT_ATTR_FNMATCH_MACRO; error = git_attr_assignment__parse(repo, pool, ¯o->assigns, &values); if (!error) error = git_attr_cache__insert_macro(repo, macro); if (error < 0) git_attr_rule__free(macro); return error; } bool git_attr_cache__is_cached( git_repository *repo, git_attr_file_source source, const char *path) { git_buf cache_key = GIT_BUF_INIT; git_strmap *files = git_repository_attr_cache(repo)->files; const char *workdir = git_repository_workdir(repo); bool rval; if (workdir && git__prefixcmp(path, workdir) == 0) path += strlen(workdir); if (git_buf_printf(&cache_key, "%d#%s", (int)source, path) < 0) return false; rval = git_strmap_exists(files, git_buf_cstr(&cache_key)); git_buf_free(&cache_key); return rval; } static int load_attr_file( const char **data, git_futils_filestamp *stamp, const char *filename) { int error; git_buf content = GIT_BUF_INIT; error = git_futils_filestamp_check(stamp, filename); if (error < 0) return error; /* if error == 0, then file is up to date. By returning GIT_ENOTFOUND, * we tell the caller not to reparse this file... */ if (!error) return GIT_ENOTFOUND; error = git_futils_readbuffer(&content, filename); if (error < 0) { /* convert error into ENOTFOUND so failed permissions / invalid * file type don't actually stop the operation in progress. */ return GIT_ENOTFOUND; /* TODO: once warnings are available, issue a warning callback */ } *data = git_buf_detach(&content); return 0; } static int load_attr_blob_from_index( const char **content, git_blob **blob, git_repository *repo, const git_oid *old_oid, const char *relfile) { int error; size_t pos; git_index *index; const git_index_entry *entry; if ((error = git_repository_index__weakptr(&index, repo)) < 0 || (error = git_index_find(&pos, index, relfile)) < 0) return error; entry = git_index_get_byindex(index, pos); if (old_oid && git_oid__cmp(old_oid, &entry->oid) == 0) return GIT_ENOTFOUND; if ((error = git_blob_lookup(blob, repo, &entry->oid)) < 0) return error; *content = git_blob_rawcontent(*blob); return 0; } static int load_attr_from_cache( git_attr_file **file, git_attr_cache *cache, git_attr_file_source source, const char *relative_path) { git_buf cache_key = GIT_BUF_INIT; khiter_t cache_pos; *file = NULL; if (!cache || !cache->files) return 0; if (git_buf_printf(&cache_key, "%d#%s", (int)source, relative_path) < 0) return -1; cache_pos = git_strmap_lookup_index(cache->files, cache_key.ptr); git_buf_free(&cache_key); if (git_strmap_valid_index(cache->files, cache_pos)) *file = git_strmap_value_at(cache->files, cache_pos); return 0; } int git_attr_cache__internal_file( git_repository *repo, const char *filename, git_attr_file **file) { int error = 0; git_attr_cache *cache = git_repository_attr_cache(repo); khiter_t cache_pos = git_strmap_lookup_index(cache->files, filename); if (git_strmap_valid_index(cache->files, cache_pos)) { *file = git_strmap_value_at(cache->files, cache_pos); return 0; } if (git_attr_file__new(file, 0, filename, &cache->pool) < 0) return -1; git_strmap_insert(cache->files, (*file)->key + 2, *file, error); if (error > 0) error = 0; return error; } int git_attr_cache__push_file( git_repository *repo, const char *base, const char *filename, git_attr_file_source source, git_attr_file_parser parse, void* parsedata, git_vector *stack) { int error = 0; git_buf path = GIT_BUF_INIT; const char *workdir = git_repository_workdir(repo); const char *relfile, *content = NULL; git_attr_cache *cache = git_repository_attr_cache(repo); git_attr_file *file = NULL; git_blob *blob = NULL; git_futils_filestamp stamp; assert(filename && stack); /* join base and path as needed */ if (base != NULL && git_path_root(filename) < 0) { if (git_buf_joinpath(&path, base, filename) < 0) return -1; filename = path.ptr; } relfile = filename; if (workdir && git__prefixcmp(relfile, workdir) == 0) relfile += strlen(workdir); /* check cache */ if (load_attr_from_cache(&file, cache, source, relfile) < 0) return -1; /* if not in cache, load data, parse, and cache */ if (source == GIT_ATTR_FILE_FROM_FILE) { git_futils_filestamp_set( &stamp, file ? &file->cache_data.stamp : NULL); error = load_attr_file(&content, &stamp, filename); } else { error = load_attr_blob_from_index(&content, &blob, repo, file ? &file->cache_data.oid : NULL, relfile); } if (error) { /* not finding a file is not an error for this function */ if (error == GIT_ENOTFOUND) { giterr_clear(); error = 0; } goto finish; } /* if we got here, we have to parse and/or reparse the file */ if (file) git_attr_file__clear_rules(file); else { error = git_attr_file__new(&file, source, relfile, &cache->pool); if (error < 0) goto finish; } if (parse && (error = parse(repo, parsedata, content, file)) < 0) goto finish; git_strmap_insert(cache->files, file->key, file, error); //-V595 if (error > 0) error = 0; /* remember "cache buster" file signature */ if (blob) git_oid_cpy(&file->cache_data.oid, git_object_id((git_object *)blob)); else git_futils_filestamp_set(&file->cache_data.stamp, &stamp); finish: /* push file onto vector if we found one*/ if (!error && file != NULL) error = git_vector_insert(stack, file); if (error != 0) git_attr_file__free(file); if (blob) git_blob_free(blob); else git__free((void *)content); git_buf_free(&path); return error; } #define push_attr_file(R,S,B,F) \ git_attr_cache__push_file((R),(B),(F),GIT_ATTR_FILE_FROM_FILE,git_attr_file__parse_buffer,NULL,(S)) typedef struct { git_repository *repo; uint32_t flags; const char *workdir; git_index *index; git_vector *files; } attr_walk_up_info; int git_attr_cache__decide_sources( uint32_t flags, bool has_wd, bool has_index, git_attr_file_source *srcs) { int count = 0; switch (flags & 0x03) { case GIT_ATTR_CHECK_FILE_THEN_INDEX: if (has_wd) srcs[count++] = GIT_ATTR_FILE_FROM_FILE; if (has_index) srcs[count++] = GIT_ATTR_FILE_FROM_INDEX; break; case GIT_ATTR_CHECK_INDEX_THEN_FILE: if (has_index) srcs[count++] = GIT_ATTR_FILE_FROM_INDEX; if (has_wd) srcs[count++] = GIT_ATTR_FILE_FROM_FILE; break; case GIT_ATTR_CHECK_INDEX_ONLY: if (has_index) srcs[count++] = GIT_ATTR_FILE_FROM_INDEX; break; } return count; } static int push_one_attr(void *ref, git_buf *path) { int error = 0, n_src, i; attr_walk_up_info *info = (attr_walk_up_info *)ref; git_attr_file_source src[2]; n_src = git_attr_cache__decide_sources( info->flags, info->workdir != NULL, info->index != NULL, src); for (i = 0; !error && i < n_src; ++i) error = git_attr_cache__push_file( info->repo, path->ptr, GIT_ATTR_FILE, src[i], git_attr_file__parse_buffer, NULL, info->files); return error; } static int collect_attr_files( git_repository *repo, uint32_t flags, const char *path, git_vector *files) { int error; git_buf dir = GIT_BUF_INIT; const char *workdir = git_repository_workdir(repo); attr_walk_up_info info; if (git_attr_cache__init(repo) < 0 || git_vector_init(files, 4, NULL) < 0) return -1; /* Resolve path in a non-bare repo */ if (workdir != NULL) error = git_path_find_dir(&dir, path, workdir); else error = git_path_dirname_r(&dir, path); if (error < 0) goto cleanup; /* in precendence order highest to lowest: * - $GIT_DIR/info/attributes * - path components with .gitattributes * - config core.attributesfile * - $GIT_PREFIX/etc/gitattributes */ error = push_attr_file( repo, files, git_repository_path(repo), GIT_ATTR_FILE_INREPO); if (error < 0) goto cleanup; info.repo = repo; info.flags = flags; info.workdir = workdir; if (git_repository_index__weakptr(&info.index, repo) < 0) giterr_clear(); /* no error even if there is no index */ info.files = files; error = git_path_walk_up(&dir, workdir, push_one_attr, &info); if (error < 0) goto cleanup; if (git_repository_attr_cache(repo)->cfg_attr_file != NULL) { error = push_attr_file( repo, files, NULL, git_repository_attr_cache(repo)->cfg_attr_file); if (error < 0) goto cleanup; } if ((flags & GIT_ATTR_CHECK_NO_SYSTEM) == 0) { error = git_futils_find_system_file(&dir, GIT_ATTR_FILE_SYSTEM); if (!error) error = push_attr_file(repo, files, NULL, dir.ptr); else if (error == GIT_ENOTFOUND) { giterr_clear(); error = 0; } } cleanup: if (error < 0) git_vector_free(files); git_buf_free(&dir); return error; } static int attr_cache__lookup_path( char **out, git_config *cfg, const char *key, const char *fallback) { git_buf buf = GIT_BUF_INIT; int error; const char *cfgval = NULL; *out = NULL; if (!(error = git_config_get_string(&cfgval, cfg, key))) { /* expand leading ~/ as needed */ if (cfgval && cfgval[0] == '~' && cfgval[1] == '/' && !git_futils_find_global_file(&buf, &cfgval[2])) *out = git_buf_detach(&buf); else if (cfgval) *out = git__strdup(cfgval); } else if (error == GIT_ENOTFOUND) { giterr_clear(); error = 0; if (!git_futils_find_xdg_file(&buf, fallback)) *out = git_buf_detach(&buf); } git_buf_free(&buf); return error; } int git_attr_cache__init(git_repository *repo) { int ret; git_attr_cache *cache = git_repository_attr_cache(repo); git_config *cfg; if (cache->initialized) return 0; /* cache config settings for attributes and ignores */ if (git_repository_config__weakptr(&cfg, repo) < 0) return -1; ret = attr_cache__lookup_path( &cache->cfg_attr_file, cfg, GIT_ATTR_CONFIG, GIT_ATTR_FILE_XDG); if (ret < 0) return ret; ret = attr_cache__lookup_path( &cache->cfg_excl_file, cfg, GIT_IGNORE_CONFIG, GIT_IGNORE_FILE_XDG); if (ret < 0) return ret; /* allocate hashtable for attribute and ignore file contents */ if (cache->files == NULL) { cache->files = git_strmap_alloc(); GITERR_CHECK_ALLOC(cache->files); } /* allocate hashtable for attribute macros */ if (cache->macros == NULL) { cache->macros = git_strmap_alloc(); GITERR_CHECK_ALLOC(cache->macros); } /* allocate string pool */ if (git_pool_init(&cache->pool, 1, 0) < 0) return -1; cache->initialized = 1; /* insert default macros */ return git_attr_add_macro(repo, "binary", "-diff -crlf -text"); } void git_attr_cache_flush( git_repository *repo) { git_attr_cache *cache; if (!repo) return; cache = git_repository_attr_cache(repo); if (cache->files != NULL) { git_attr_file *file; git_strmap_foreach_value(cache->files, file, { git_attr_file__free(file); }); git_strmap_free(cache->files); } if (cache->macros != NULL) { git_attr_rule *rule; git_strmap_foreach_value(cache->macros, rule, { git_attr_rule__free(rule); }); git_strmap_free(cache->macros); } git_pool_clear(&cache->pool); git__free(cache->cfg_attr_file); cache->cfg_attr_file = NULL; git__free(cache->cfg_excl_file); cache->cfg_excl_file = NULL; cache->initialized = 0; } int git_attr_cache__insert_macro(git_repository *repo, git_attr_rule *macro) { git_strmap *macros = git_repository_attr_cache(repo)->macros; int error; /* TODO: generate warning log if (macro->assigns.length == 0) */ if (macro->assigns.length == 0) return 0; git_strmap_insert(macros, macro->match.pattern, macro, error); return (error < 0) ? -1 : 0; } git_attr_rule *git_attr_cache__lookup_macro( git_repository *repo, const char *name) { git_strmap *macros = git_repository_attr_cache(repo)->macros; khiter_t pos; pos = git_strmap_lookup_index(macros, name); if (!git_strmap_valid_index(macros, pos)) return NULL; return (git_attr_rule *)git_strmap_value_at(macros, pos); } libgit2-0.19.0/src/attr.h000066400000000000000000000024261216214232500150510ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #ifndef INCLUDE_attr_h__ #define INCLUDE_attr_h__ #include "attr_file.h" #define GIT_ATTR_CONFIG "core.attributesfile" #define GIT_IGNORE_CONFIG "core.excludesfile" typedef int (*git_attr_file_parser)( git_repository *, void *, const char *, git_attr_file *); extern int git_attr_cache__insert_macro( git_repository *repo, git_attr_rule *macro); extern git_attr_rule *git_attr_cache__lookup_macro( git_repository *repo, const char *name); extern int git_attr_cache__push_file( git_repository *repo, const char *base, const char *filename, git_attr_file_source source, git_attr_file_parser parse, void *parsedata, /* passed through to parse function */ git_vector *stack); extern int git_attr_cache__internal_file( git_repository *repo, const char *key, git_attr_file **file_ptr); /* returns true if path is in cache */ extern bool git_attr_cache__is_cached( git_repository *repo, git_attr_file_source source, const char *path); extern int git_attr_cache__decide_sources( uint32_t flags, bool has_wd, bool has_index, git_attr_file_source *srcs); #endif libgit2-0.19.0/src/attr_file.c000066400000000000000000000356371216214232500160550ustar00rootroot00000000000000#include "common.h" #include "repository.h" #include "filebuf.h" #include "attr.h" #include "git2/blob.h" #include "git2/tree.h" #include static int sort_by_hash_and_name(const void *a_raw, const void *b_raw); static void git_attr_rule__clear(git_attr_rule *rule); static bool parse_optimized_patterns( git_attr_fnmatch *spec, git_pool *pool, const char *pattern); int git_attr_file__new( git_attr_file **attrs_ptr, git_attr_file_source from, const char *path, git_pool *pool) { git_attr_file *attrs = NULL; attrs = git__calloc(1, sizeof(git_attr_file)); GITERR_CHECK_ALLOC(attrs); if (pool) attrs->pool = pool; else { attrs->pool = git__calloc(1, sizeof(git_pool)); if (!attrs->pool || git_pool_init(attrs->pool, 1, 0) < 0) goto fail; attrs->pool_is_allocated = true; } if (path) { size_t len = strlen(path); attrs->key = git_pool_malloc(attrs->pool, (uint32_t)len + 3); GITERR_CHECK_ALLOC(attrs->key); attrs->key[0] = '0' + from; attrs->key[1] = '#'; memcpy(&attrs->key[2], path, len); attrs->key[len + 2] = '\0'; } if (git_vector_init(&attrs->rules, 4, NULL) < 0) goto fail; *attrs_ptr = attrs; return 0; fail: git_attr_file__free(attrs); attrs_ptr = NULL; return -1; } int git_attr_file__parse_buffer( git_repository *repo, void *parsedata, const char *buffer, git_attr_file *attrs) { int error = 0; const char *scan = NULL; char *context = NULL; git_attr_rule *rule = NULL; GIT_UNUSED(parsedata); assert(buffer && attrs); scan = buffer; /* if subdir file path, convert context for file paths */ if (attrs->key && git__suffixcmp(attrs->key, "/" GIT_ATTR_FILE) == 0) { context = attrs->key + 2; context[strlen(context) - strlen(GIT_ATTR_FILE)] = '\0'; } while (!error && *scan) { /* allocate rule if needed */ if (!rule && !(rule = git__calloc(1, sizeof(git_attr_rule)))) { error = -1; break; } /* parse the next "pattern attr attr attr" line */ if (!(error = git_attr_fnmatch__parse( &rule->match, attrs->pool, context, &scan)) && !(error = git_attr_assignment__parse( repo, attrs->pool, &rule->assigns, &scan))) { if (rule->match.flags & GIT_ATTR_FNMATCH_MACRO) /* should generate error/warning if this is coming from any * file other than .gitattributes at repo root. */ error = git_attr_cache__insert_macro(repo, rule); else error = git_vector_insert(&attrs->rules, rule); } /* if the rule wasn't a pattern, on to the next */ if (error < 0) { git_attr_rule__clear(rule); /* reset rule contents */ if (error == GIT_ENOTFOUND) error = 0; } else { rule = NULL; /* vector now "owns" the rule */ } } git_attr_rule__free(rule); /* restore file path used for context */ if (context) context[strlen(context)] = '.'; /* first char of GIT_ATTR_FILE */ return error; } int git_attr_file__new_and_load( git_attr_file **attrs_ptr, const char *path) { int error; git_buf content = GIT_BUF_INIT; if ((error = git_attr_file__new(attrs_ptr, 0, path, NULL)) < 0) return error; if (!(error = git_futils_readbuffer(&content, path))) error = git_attr_file__parse_buffer( NULL, NULL, git_buf_cstr(&content), *attrs_ptr); git_buf_free(&content); if (error) { git_attr_file__free(*attrs_ptr); *attrs_ptr = NULL; } return error; } void git_attr_file__clear_rules(git_attr_file *file) { unsigned int i; git_attr_rule *rule; git_vector_foreach(&file->rules, i, rule) git_attr_rule__free(rule); git_vector_free(&file->rules); } void git_attr_file__free(git_attr_file *file) { if (!file) return; git_attr_file__clear_rules(file); if (file->pool_is_allocated) { git_pool_clear(file->pool); git__free(file->pool); } file->pool = NULL; git__free(file); } uint32_t git_attr_file__name_hash(const char *name) { uint32_t h = 5381; int c; assert(name); while ((c = (int)*name++) != 0) h = ((h << 5) + h) + c; return h; } int git_attr_file__lookup_one( git_attr_file *file, const git_attr_path *path, const char *attr, const char **value) { size_t i; git_attr_name name; git_attr_rule *rule; *value = NULL; name.name = attr; name.name_hash = git_attr_file__name_hash(attr); git_attr_file__foreach_matching_rule(file, path, i, rule) { size_t pos; if (!git_vector_bsearch(&pos, &rule->assigns, &name)) { *value = ((git_attr_assignment *) git_vector_get(&rule->assigns, pos))->value; break; } } return 0; } bool git_attr_fnmatch__match( git_attr_fnmatch *match, const git_attr_path *path) { int fnm; int icase_flags = (match->flags & GIT_ATTR_FNMATCH_ICASE) ? FNM_CASEFOLD : 0; if (match->flags & GIT_ATTR_FNMATCH_DIRECTORY && !path->is_dir) return false; if (match->flags & GIT_ATTR_FNMATCH_FULLPATH) fnm = p_fnmatch(match->pattern, path->path, FNM_PATHNAME | icase_flags); else if (path->is_dir) fnm = p_fnmatch(match->pattern, path->basename, FNM_LEADING_DIR | icase_flags); else fnm = p_fnmatch(match->pattern, path->basename, icase_flags); return (fnm == FNM_NOMATCH) ? false : true; } bool git_attr_rule__match( git_attr_rule *rule, const git_attr_path *path) { bool matched = git_attr_fnmatch__match(&rule->match, path); if (rule->match.flags & GIT_ATTR_FNMATCH_NEGATIVE) matched = !matched; return matched; } git_attr_assignment *git_attr_rule__lookup_assignment( git_attr_rule *rule, const char *name) { size_t pos; git_attr_name key; key.name = name; key.name_hash = git_attr_file__name_hash(name); if (git_vector_bsearch(&pos, &rule->assigns, &key)) return NULL; return git_vector_get(&rule->assigns, pos); } int git_attr_path__init( git_attr_path *info, const char *path, const char *base) { ssize_t root; /* build full path as best we can */ git_buf_init(&info->full, 0); if (git_path_join_unrooted(&info->full, path, base, &root) < 0) return -1; info->path = info->full.ptr + root; /* remove trailing slashes */ while (info->full.size > 0) { if (info->full.ptr[info->full.size - 1] != '/') break; info->full.size--; } info->full.ptr[info->full.size] = '\0'; /* skip leading slashes in path */ while (*info->path == '/') info->path++; /* find trailing basename component */ info->basename = strrchr(info->path, '/'); if (info->basename) info->basename++; if (!info->basename || !*info->basename) info->basename = info->path; info->is_dir = (int)git_path_isdir(info->full.ptr); return 0; } void git_attr_path__free(git_attr_path *info) { git_buf_free(&info->full); info->path = NULL; info->basename = NULL; } /* * From gitattributes(5): * * Patterns have the following format: * * - A blank line matches no files, so it can serve as a separator for * readability. * * - A line starting with # serves as a comment. * * - An optional prefix ! which negates the pattern; any matching file * excluded by a previous pattern will become included again. If a negated * pattern matches, this will override lower precedence patterns sources. * * - If the pattern ends with a slash, it is removed for the purpose of the * following description, but it would only find a match with a directory. In * other words, foo/ will match a directory foo and paths underneath it, but * will not match a regular file or a symbolic link foo (this is consistent * with the way how pathspec works in general in git). * * - If the pattern does not contain a slash /, git treats it as a shell glob * pattern and checks for a match against the pathname without leading * directories. * * - Otherwise, git treats the pattern as a shell glob suitable for consumption * by fnmatch(3) with the FNM_PATHNAME flag: wildcards in the pattern will * not match a / in the pathname. For example, "Documentation/\*.html" matches * "Documentation/git.html" but not "Documentation/ppc/ppc.html". A leading * slash matches the beginning of the pathname; for example, "/\*.c" matches * "cat-file.c" but not "mozilla-sha1/sha1.c". */ /* * This will return 0 if the spec was filled out, * GIT_ENOTFOUND if the fnmatch does not require matching, or * another error code there was an actual problem. */ int git_attr_fnmatch__parse( git_attr_fnmatch *spec, git_pool *pool, const char *source, const char **base) { const char *pattern, *scan; int slash_count, allow_space; assert(spec && base && *base); if (parse_optimized_patterns(spec, pool, *base)) return 0; spec->flags = (spec->flags & GIT_ATTR_FNMATCH_ALLOWSPACE); allow_space = (spec->flags != 0); pattern = *base; while (git__isspace(*pattern)) pattern++; if (!*pattern || *pattern == '#') { *base = git__next_line(pattern); return GIT_ENOTFOUND; } if (*pattern == '[') { if (strncmp(pattern, "[attr]", 6) == 0) { spec->flags = spec->flags | GIT_ATTR_FNMATCH_MACRO; pattern += 6; } /* else a character range like [a-e]* which is accepted */ } if (*pattern == '!') { spec->flags = spec->flags | GIT_ATTR_FNMATCH_NEGATIVE; pattern++; } slash_count = 0; for (scan = pattern; *scan != '\0'; ++scan) { /* scan until (non-escaped) white space */ if (git__isspace(*scan) && *(scan - 1) != '\\') { if (!allow_space || (*scan != ' ' && *scan != '\t')) break; } if (*scan == '/') { spec->flags = spec->flags | GIT_ATTR_FNMATCH_FULLPATH; slash_count++; if (pattern == scan) pattern++; } /* remember if we see an unescaped wildcard in pattern */ else if (git__iswildcard(*scan) && (scan == pattern || (*(scan - 1) != '\\'))) spec->flags = spec->flags | GIT_ATTR_FNMATCH_HASWILD; } *base = scan; if ((spec->length = scan - pattern) == 0) return GIT_ENOTFOUND; if (pattern[spec->length - 1] == '/') { spec->length--; spec->flags = spec->flags | GIT_ATTR_FNMATCH_DIRECTORY; if (--slash_count <= 0) spec->flags = spec->flags & ~GIT_ATTR_FNMATCH_FULLPATH; } if ((spec->flags & GIT_ATTR_FNMATCH_FULLPATH) != 0 && source != NULL && git_path_root(pattern) < 0) { size_t sourcelen = strlen(source); /* given an unrooted fullpath match from a file inside a repo, * prefix the pattern with the relative directory of the source file */ spec->pattern = git_pool_malloc( pool, (uint32_t)(sourcelen + spec->length + 1)); if (spec->pattern) { memcpy(spec->pattern, source, sourcelen); memcpy(spec->pattern + sourcelen, pattern, spec->length); spec->length += sourcelen; spec->pattern[spec->length] = '\0'; } } else { spec->pattern = git_pool_strndup(pool, pattern, spec->length); } if (!spec->pattern) { *base = git__next_line(pattern); return -1; } else { /* strip '\' that might have be used for internal whitespace */ spec->length = git__unescape(spec->pattern); } return 0; } static bool parse_optimized_patterns( git_attr_fnmatch *spec, git_pool *pool, const char *pattern) { if (!pattern[1] && (pattern[0] == '*' || pattern[0] == '.')) { spec->flags = GIT_ATTR_FNMATCH_MATCH_ALL; spec->pattern = git_pool_strndup(pool, pattern, 1); spec->length = 1; return true; } return false; } static int sort_by_hash_and_name(const void *a_raw, const void *b_raw) { const git_attr_name *a = a_raw; const git_attr_name *b = b_raw; if (b->name_hash < a->name_hash) return 1; else if (b->name_hash > a->name_hash) return -1; else return strcmp(b->name, a->name); } static void git_attr_assignment__free(git_attr_assignment *assign) { /* name and value are stored in a git_pool associated with the * git_attr_file, so they do not need to be freed here */ assign->name = NULL; assign->value = NULL; git__free(assign); } static int merge_assignments(void **old_raw, void *new_raw) { git_attr_assignment **old = (git_attr_assignment **)old_raw; git_attr_assignment *new = (git_attr_assignment *)new_raw; GIT_REFCOUNT_DEC(*old, git_attr_assignment__free); *old = new; return GIT_EEXISTS; } int git_attr_assignment__parse( git_repository *repo, git_pool *pool, git_vector *assigns, const char **base) { int error; const char *scan = *base; git_attr_assignment *assign = NULL; assert(assigns && !assigns->length); git_vector_set_cmp(assigns, sort_by_hash_and_name); while (*scan && *scan != '\n') { const char *name_start, *value_start; /* skip leading blanks */ while (git__isspace(*scan) && *scan != '\n') scan++; /* allocate assign if needed */ if (!assign) { assign = git__calloc(1, sizeof(git_attr_assignment)); GITERR_CHECK_ALLOC(assign); GIT_REFCOUNT_INC(assign); } assign->name_hash = 5381; assign->value = git_attr__true; /* look for magic name prefixes */ if (*scan == '-') { assign->value = git_attr__false; scan++; } else if (*scan == '!') { assign->value = git_attr__unset; /* explicit unspecified state */ scan++; } else if (*scan == '#') /* comment rest of line */ break; /* find the name */ name_start = scan; while (*scan && !git__isspace(*scan) && *scan != '=') { assign->name_hash = ((assign->name_hash << 5) + assign->name_hash) + *scan; scan++; } if (scan == name_start) { /* must have found lone prefix (" - ") or leading = ("=foo") * or end of buffer -- advance until whitespace and continue */ while (*scan && !git__isspace(*scan)) scan++; continue; } /* allocate permanent storage for name */ assign->name = git_pool_strndup(pool, name_start, scan - name_start); GITERR_CHECK_ALLOC(assign->name); /* if there is an equals sign, find the value */ if (*scan == '=') { for (value_start = ++scan; *scan && !git__isspace(*scan); ++scan); /* if we found a value, allocate permanent storage for it */ if (scan > value_start) { assign->value = git_pool_strndup(pool, value_start, scan - value_start); GITERR_CHECK_ALLOC(assign->value); } } /* expand macros (if given a repo with a macro cache) */ if (repo != NULL && assign->value == git_attr__true) { git_attr_rule *macro = git_attr_cache__lookup_macro(repo, assign->name); if (macro != NULL) { unsigned int i; git_attr_assignment *massign; git_vector_foreach(¯o->assigns, i, massign) { GIT_REFCOUNT_INC(massign); error = git_vector_insert_sorted( assigns, massign, &merge_assignments); if (error < 0 && error != GIT_EEXISTS) return error; } } } /* insert allocated assign into vector */ error = git_vector_insert_sorted(assigns, assign, &merge_assignments); if (error < 0 && error != GIT_EEXISTS) return error; /* clear assign since it is now "owned" by the vector */ assign = NULL; } if (assign != NULL) git_attr_assignment__free(assign); *base = git__next_line(scan); return (assigns->length == 0) ? GIT_ENOTFOUND : 0; } static void git_attr_rule__clear(git_attr_rule *rule) { unsigned int i; git_attr_assignment *assign; if (!rule) return; if (!(rule->match.flags & GIT_ATTR_FNMATCH_IGNORE)) { git_vector_foreach(&rule->assigns, i, assign) GIT_REFCOUNT_DEC(assign, git_attr_assignment__free); git_vector_free(&rule->assigns); } /* match.pattern is stored in a git_pool, so no need to free */ rule->match.pattern = NULL; rule->match.length = 0; } void git_attr_rule__free(git_attr_rule *rule) { git_attr_rule__clear(rule); git__free(rule); } libgit2-0.19.0/src/attr_file.h000066400000000000000000000071241216214232500160500ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #ifndef INCLUDE_attr_file_h__ #define INCLUDE_attr_file_h__ #include "git2/oid.h" #include "git2/attr.h" #include "vector.h" #include "pool.h" #include "buffer.h" #include "fileops.h" #define GIT_ATTR_FILE ".gitattributes" #define GIT_ATTR_FILE_INREPO "info/attributes" #define GIT_ATTR_FILE_SYSTEM "gitattributes" #define GIT_ATTR_FILE_XDG "attributes" #define GIT_ATTR_FNMATCH_NEGATIVE (1U << 0) #define GIT_ATTR_FNMATCH_DIRECTORY (1U << 1) #define GIT_ATTR_FNMATCH_FULLPATH (1U << 2) #define GIT_ATTR_FNMATCH_MACRO (1U << 3) #define GIT_ATTR_FNMATCH_IGNORE (1U << 4) #define GIT_ATTR_FNMATCH_HASWILD (1U << 5) #define GIT_ATTR_FNMATCH_ALLOWSPACE (1U << 6) #define GIT_ATTR_FNMATCH_ICASE (1U << 7) #define GIT_ATTR_FNMATCH_MATCH_ALL (1U << 8) extern const char *git_attr__true; extern const char *git_attr__false; extern const char *git_attr__unset; typedef struct { char *pattern; size_t length; unsigned int flags; } git_attr_fnmatch; typedef struct { git_attr_fnmatch match; git_vector assigns; /* vector of */ } git_attr_rule; typedef struct { git_refcount unused; const char *name; uint32_t name_hash; } git_attr_name; typedef struct { git_refcount rc; /* for macros */ char *name; uint32_t name_hash; const char *value; } git_attr_assignment; typedef struct { char *key; /* cache "source#path" this was loaded from */ git_vector rules; /* vector of or */ git_pool *pool; bool pool_is_allocated; union { git_oid oid; git_futils_filestamp stamp; } cache_data; } git_attr_file; typedef struct { git_buf full; char *path; char *basename; int is_dir; } git_attr_path; typedef enum { GIT_ATTR_FILE_FROM_FILE = 0, GIT_ATTR_FILE_FROM_INDEX = 1 } git_attr_file_source; /* * git_attr_file API */ extern int git_attr_file__new( git_attr_file **attrs_ptr, git_attr_file_source src, const char *path, git_pool *pool); extern int git_attr_file__new_and_load( git_attr_file **attrs_ptr, const char *path); extern void git_attr_file__free(git_attr_file *file); extern void git_attr_file__clear_rules(git_attr_file *file); extern int git_attr_file__parse_buffer( git_repository *repo, void *parsedata, const char *buf, git_attr_file *file); extern int git_attr_file__lookup_one( git_attr_file *file, const git_attr_path *path, const char *attr, const char **value); /* loop over rules in file from bottom to top */ #define git_attr_file__foreach_matching_rule(file, path, iter, rule) \ git_vector_rforeach(&(file)->rules, (iter), (rule)) \ if (git_attr_rule__match((rule), (path))) extern uint32_t git_attr_file__name_hash(const char *name); /* * other utilities */ extern int git_attr_fnmatch__parse( git_attr_fnmatch *spec, git_pool *pool, const char *source, const char **base); extern bool git_attr_fnmatch__match( git_attr_fnmatch *rule, const git_attr_path *path); extern void git_attr_rule__free(git_attr_rule *rule); extern bool git_attr_rule__match( git_attr_rule *rule, const git_attr_path *path); extern git_attr_assignment *git_attr_rule__lookup_assignment( git_attr_rule *rule, const char *name); extern int git_attr_path__init( git_attr_path *info, const char *path, const char *base); extern void git_attr_path__free(git_attr_path *info); extern int git_attr_assignment__parse( git_repository *repo, /* needed to expand macros */ git_pool *pool, git_vector *assigns, const char **scan); #endif libgit2-0.19.0/src/attrcache.h000066400000000000000000000013021216214232500160250ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #ifndef INCLUDE_attrcache_h__ #define INCLUDE_attrcache_h__ #include "pool.h" #include "strmap.h" typedef struct { int initialized; git_pool pool; git_strmap *files; /* hash path to git_attr_file of rules */ git_strmap *macros; /* hash name to vector */ char *cfg_attr_file; /* cached value of core.attributesfile */ char *cfg_excl_file; /* cached value of core.excludesfile */ } git_attr_cache; extern int git_attr_cache__init(git_repository *repo); #endif libgit2-0.19.0/src/blob.c000066400000000000000000000172031216214232500150070ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #include "git2/common.h" #include "git2/object.h" #include "git2/repository.h" #include "git2/odb_backend.h" #include "common.h" #include "filebuf.h" #include "blob.h" #include "filter.h" #include "buf_text.h" const void *git_blob_rawcontent(const git_blob *blob) { assert(blob); return git_odb_object_data(blob->odb_object); } git_off_t git_blob_rawsize(const git_blob *blob) { assert(blob); return (git_off_t)git_odb_object_size(blob->odb_object); } int git_blob__getbuf(git_buf *buffer, git_blob *blob) { return git_buf_set( buffer, git_odb_object_data(blob->odb_object), git_odb_object_size(blob->odb_object)); } void git_blob__free(void *blob) { git_odb_object_free(((git_blob *)blob)->odb_object); git__free(blob); } int git_blob__parse(void *blob, git_odb_object *odb_obj) { assert(blob); git_cached_obj_incref((git_cached_obj *)odb_obj); ((git_blob *)blob)->odb_object = odb_obj; return 0; } int git_blob_create_frombuffer(git_oid *oid, git_repository *repo, const void *buffer, size_t len) { int error; git_odb *odb; git_odb_stream *stream; if ((error = git_repository_odb__weakptr(&odb, repo)) < 0 || (error = git_odb_open_wstream(&stream, odb, len, GIT_OBJ_BLOB)) < 0) return error; if ((error = stream->write(stream, buffer, len)) == 0) error = stream->finalize_write(oid, stream); stream->free(stream); return error; } static int write_file_stream( git_oid *oid, git_odb *odb, const char *path, git_off_t file_size) { int fd, error; char buffer[4096]; git_odb_stream *stream = NULL; ssize_t read_len = -1, written = 0; if ((error = git_odb_open_wstream( &stream, odb, (size_t)file_size, GIT_OBJ_BLOB)) < 0) return error; if ((fd = git_futils_open_ro(path)) < 0) { stream->free(stream); return -1; } while (!error && (read_len = p_read(fd, buffer, sizeof(buffer))) > 0) { error = stream->write(stream, buffer, read_len); written += read_len; } p_close(fd); if (written != file_size || read_len < 0) { giterr_set(GITERR_OS, "Failed to read file into stream"); error = -1; } if (!error) error = stream->finalize_write(oid, stream); stream->free(stream); return error; } static int write_file_filtered( git_oid *oid, git_odb *odb, const char *full_path, git_vector *filters) { int error; git_buf source = GIT_BUF_INIT; git_buf dest = GIT_BUF_INIT; if ((error = git_futils_readbuffer(&source, full_path)) < 0) return error; error = git_filters_apply(&dest, &source, filters); /* Free the source as soon as possible. This can be big in memory, * and we don't want to ODB write to choke */ git_buf_free(&source); /* Write the file to disk if it was properly filtered */ if (!error) error = git_odb_write(oid, odb, dest.ptr, dest.size, GIT_OBJ_BLOB); git_buf_free(&dest); return error; } static int write_symlink( git_oid *oid, git_odb *odb, const char *path, size_t link_size) { char *link_data; ssize_t read_len; int error; link_data = git__malloc(link_size); GITERR_CHECK_ALLOC(link_data); read_len = p_readlink(path, link_data, link_size); if (read_len != (ssize_t)link_size) { giterr_set(GITERR_OS, "Failed to create blob. Can't read symlink '%s'", path); git__free(link_data); return -1; } error = git_odb_write(oid, odb, (void *)link_data, link_size, GIT_OBJ_BLOB); git__free(link_data); return error; } static int blob_create_internal(git_oid *oid, git_repository *repo, const char *content_path, const char *hint_path, bool try_load_filters) { int error; struct stat st; git_odb *odb = NULL; git_off_t size; assert(hint_path || !try_load_filters); if ((error = git_path_lstat(content_path, &st)) < 0 || (error = git_repository_odb__weakptr(&odb, repo)) < 0) return error; size = st.st_size; if (S_ISLNK(st.st_mode)) { error = write_symlink(oid, odb, content_path, (size_t)size); } else { git_vector write_filters = GIT_VECTOR_INIT; int filter_count = 0; if (try_load_filters) { /* Load the filters for writing this file to the ODB */ filter_count = git_filters_load( &write_filters, repo, hint_path, GIT_FILTER_TO_ODB); } if (filter_count < 0) { /* Negative value means there was a critical error */ error = filter_count; } else if (filter_count == 0) { /* No filters need to be applied to the document: we can stream * directly from disk */ error = write_file_stream(oid, odb, content_path, size); } else { /* We need to apply one or more filters */ error = write_file_filtered(oid, odb, content_path, &write_filters); } git_filters_free(&write_filters); /* * TODO: eventually support streaming filtered files, for files * which are bigger than a given threshold. This is not a priority * because applying a filter in streaming mode changes the final * size of the blob, and without knowing its final size, the blob * cannot be written in stream mode to the ODB. * * The plan is to do streaming writes to a tempfile on disk and then * opening streaming that file to the ODB, using * `write_file_stream`. * * CAREFULLY DESIGNED APIS YO */ } return error; } int git_blob_create_fromworkdir(git_oid *oid, git_repository *repo, const char *path) { git_buf full_path = GIT_BUF_INIT; const char *workdir; int error; if ((error = git_repository__ensure_not_bare(repo, "create blob from file")) < 0) return error; workdir = git_repository_workdir(repo); if (git_buf_joinpath(&full_path, workdir, path) < 0) { git_buf_free(&full_path); return -1; } error = blob_create_internal( oid, repo, git_buf_cstr(&full_path), git_buf_cstr(&full_path) + strlen(workdir), true); git_buf_free(&full_path); return error; } int git_blob_create_fromdisk(git_oid *oid, git_repository *repo, const char *path) { int error; git_buf full_path = GIT_BUF_INIT; const char *workdir, *hintpath; if ((error = git_path_prettify(&full_path, path, NULL)) < 0) { git_buf_free(&full_path); return error; } hintpath = git_buf_cstr(&full_path); workdir = git_repository_workdir(repo); if (workdir && !git__prefixcmp(hintpath, workdir)) hintpath += strlen(workdir); error = blob_create_internal( oid, repo, git_buf_cstr(&full_path), hintpath, true); git_buf_free(&full_path); return error; } #define BUFFER_SIZE 4096 int git_blob_create_fromchunks( git_oid *oid, git_repository *repo, const char *hintpath, int (*source_cb)(char *content, size_t max_length, void *payload), void *payload) { int error = -1, read_bytes; char *content = NULL; git_filebuf file = GIT_FILEBUF_INIT; git_buf path = GIT_BUF_INIT; if (git_buf_join_n( &path, '/', 3, git_repository_path(repo), GIT_OBJECTS_DIR, "streamed") < 0) goto cleanup; content = git__malloc(BUFFER_SIZE); GITERR_CHECK_ALLOC(content); if (git_filebuf_open(&file, git_buf_cstr(&path), GIT_FILEBUF_TEMPORARY) < 0) goto cleanup; while (1) { read_bytes = source_cb(content, BUFFER_SIZE, payload); assert(read_bytes <= BUFFER_SIZE); if (read_bytes <= 0) break; if (git_filebuf_write(&file, content, read_bytes) < 0) goto cleanup; } if (read_bytes < 0) goto cleanup; if (git_filebuf_flush(&file) < 0) goto cleanup; error = blob_create_internal(oid, repo, file.path_lock, hintpath, hintpath != NULL); cleanup: git_buf_free(&path); git_filebuf_cleanup(&file); git__free(content); return error; } int git_blob_is_binary(git_blob *blob) { git_buf content; assert(blob); content.ptr = blob->odb_object->buffer; content.size = min(blob->odb_object->cached.size, 4000); return git_buf_text_is_binary(&content); } libgit2-0.19.0/src/blob.h000066400000000000000000000010751216214232500150140ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #ifndef INCLUDE_blob_h__ #define INCLUDE_blob_h__ #include "git2/blob.h" #include "repository.h" #include "odb.h" #include "fileops.h" struct git_blob { git_object object; git_odb_object *odb_object; }; void git_blob__free(void *blob); int git_blob__parse(void *blob, git_odb_object *obj); int git_blob__getbuf(git_buf *buffer, git_blob *blob); #endif libgit2-0.19.0/src/branch.c000066400000000000000000000337241216214232500153340ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #include "common.h" #include "commit.h" #include "tag.h" #include "config.h" #include "refspec.h" #include "refs.h" #include "remote.h" #include "git2/branch.h" static int retrieve_branch_reference( git_reference **branch_reference_out, git_repository *repo, const char *branch_name, int is_remote) { git_reference *branch; int error = -1; char *prefix; git_buf ref_name = GIT_BUF_INIT; *branch_reference_out = NULL; prefix = is_remote ? GIT_REFS_REMOTES_DIR : GIT_REFS_HEADS_DIR; if (git_buf_joinpath(&ref_name, prefix, branch_name) < 0) goto cleanup; if ((error = git_reference_lookup(&branch, repo, ref_name.ptr)) < 0) { giterr_set(GITERR_REFERENCE, "Cannot locate %s branch '%s'.", is_remote ? "remote-tracking" : "local", branch_name); goto cleanup; } *branch_reference_out = branch; cleanup: git_buf_free(&ref_name); return error; } static int not_a_local_branch(const char *reference_name) { giterr_set( GITERR_INVALID, "Reference '%s' is not a local branch.", reference_name); return -1; } int git_branch_create( git_reference **ref_out, git_repository *repository, const char *branch_name, const git_commit *commit, int force) { git_reference *branch = NULL; git_buf canonical_branch_name = GIT_BUF_INIT; int error = -1; assert(branch_name && commit && ref_out); assert(git_object_owner((const git_object *)commit) == repository); if (git_buf_joinpath(&canonical_branch_name, GIT_REFS_HEADS_DIR, branch_name) < 0) goto cleanup; error = git_reference_create(&branch, repository, git_buf_cstr(&canonical_branch_name), git_commit_id(commit), force); if (!error) *ref_out = branch; cleanup: git_buf_free(&canonical_branch_name); return error; } int git_branch_delete(git_reference *branch) { int is_head; git_buf config_section = GIT_BUF_INIT; int error = -1; assert(branch); if (!git_reference_is_branch(branch) && !git_reference_is_remote(branch)) { giterr_set(GITERR_INVALID, "Reference '%s' is not a valid branch.", git_reference_name(branch)); return -1; } if ((is_head = git_branch_is_head(branch)) < 0) return is_head; if (is_head) { giterr_set(GITERR_REFERENCE, "Cannot delete branch '%s' as it is the current HEAD of the repository.", git_reference_name(branch)); return -1; } if (git_buf_printf(&config_section, "branch.%s", git_reference_name(branch) + strlen(GIT_REFS_HEADS_DIR)) < 0) goto on_error; if (git_config_rename_section( git_reference_owner(branch), git_buf_cstr(&config_section), NULL) < 0) goto on_error; if (git_reference_delete(branch) < 0) goto on_error; error = 0; on_error: git_buf_free(&config_section); return error; } int git_branch_foreach( git_repository *repo, unsigned int list_flags, git_branch_foreach_cb callback, void *payload) { git_reference_iterator *iter; git_reference *ref; int error = 0; if (git_reference_iterator_new(&iter, repo) < 0) return -1; while ((error = git_reference_next(&ref, iter)) == 0) { if (list_flags & GIT_BRANCH_LOCAL && git__prefixcmp(ref->name, GIT_REFS_HEADS_DIR) == 0) { if (callback(ref->name + strlen(GIT_REFS_HEADS_DIR), GIT_BRANCH_LOCAL, payload)) { error = GIT_EUSER; } } if (list_flags & GIT_BRANCH_REMOTE && git__prefixcmp(ref->name, GIT_REFS_REMOTES_DIR) == 0) { if (callback(ref->name + strlen(GIT_REFS_REMOTES_DIR), GIT_BRANCH_REMOTE, payload)) { error = GIT_EUSER; } } git_reference_free(ref); /* check if the callback has cancelled iteration */ if (error == GIT_EUSER) break; } if (error == GIT_ITEROVER) error = 0; git_reference_iterator_free(iter); return error; } int git_branch_move( git_reference **out, git_reference *branch, const char *new_branch_name, int force) { git_buf new_reference_name = GIT_BUF_INIT, old_config_section = GIT_BUF_INIT, new_config_section = GIT_BUF_INIT; int error; assert(branch && new_branch_name); if (!git_reference_is_branch(branch)) return not_a_local_branch(git_reference_name(branch)); error = git_buf_joinpath(&new_reference_name, GIT_REFS_HEADS_DIR, new_branch_name); if (error < 0) goto done; git_buf_printf(&old_config_section, "branch.%s", git_reference_name(branch) + strlen(GIT_REFS_HEADS_DIR)); git_buf_printf(&new_config_section, "branch.%s", new_branch_name); if ((error = git_config_rename_section(git_reference_owner(branch), git_buf_cstr(&old_config_section), git_buf_cstr(&new_config_section))) < 0) goto done; error = git_reference_rename(out, branch, git_buf_cstr(&new_reference_name), force); done: git_buf_free(&new_reference_name); git_buf_free(&old_config_section); git_buf_free(&new_config_section); return error; } int git_branch_lookup( git_reference **ref_out, git_repository *repo, const char *branch_name, git_branch_t branch_type) { assert(ref_out && repo && branch_name); return retrieve_branch_reference(ref_out, repo, branch_name, branch_type == GIT_BRANCH_REMOTE); } int git_branch_name(const char **out, git_reference *ref) { const char *branch_name; assert(out && ref); branch_name = ref->name; if (git_reference_is_branch(ref)) { branch_name += strlen(GIT_REFS_HEADS_DIR); } else if (git_reference_is_remote(ref)) { branch_name += strlen(GIT_REFS_REMOTES_DIR); } else { giterr_set(GITERR_INVALID, "Reference '%s' is neither a local nor a remote branch.", ref->name); return -1; } *out = branch_name; return 0; } static int retrieve_upstream_configuration( const char **out, git_repository *repo, const char *canonical_branch_name, const char *format) { git_config *config; git_buf buf = GIT_BUF_INIT; int error; if (git_repository_config__weakptr(&config, repo) < 0) return -1; if (git_buf_printf(&buf, format, canonical_branch_name + strlen(GIT_REFS_HEADS_DIR)) < 0) return -1; error = git_config_get_string(out, config, git_buf_cstr(&buf)); git_buf_free(&buf); return error; } int git_branch_upstream__name( git_buf *tracking_name, git_repository *repo, const char *canonical_branch_name) { const char *remote_name, *merge_name; git_buf buf = GIT_BUF_INIT; int error = -1; git_remote *remote = NULL; const git_refspec *refspec; assert(tracking_name && canonical_branch_name); if (!git_reference__is_branch(canonical_branch_name)) return not_a_local_branch(canonical_branch_name); if ((error = retrieve_upstream_configuration( &remote_name, repo, canonical_branch_name, "branch.%s.remote")) < 0) goto cleanup; if ((error = retrieve_upstream_configuration( &merge_name, repo, canonical_branch_name, "branch.%s.merge")) < 0) goto cleanup; if (!*remote_name || !*merge_name) { giterr_set(GITERR_REFERENCE, "branch '%s' does not have an upstream", canonical_branch_name); error = GIT_ENOTFOUND; goto cleanup; } if (strcmp(".", remote_name) != 0) { if ((error = git_remote_load(&remote, repo, remote_name)) < 0) goto cleanup; refspec = git_remote__matching_refspec(remote, merge_name); if (!refspec) { error = GIT_ENOTFOUND; goto cleanup; } if (git_refspec_transform_r(&buf, refspec, merge_name) < 0) goto cleanup; } else if (git_buf_sets(&buf, merge_name) < 0) goto cleanup; error = git_buf_set(tracking_name, git_buf_cstr(&buf), git_buf_len(&buf)); cleanup: git_remote_free(remote); git_buf_free(&buf); return error; } static int remote_name(git_buf *buf, git_repository *repo, const char *canonical_branch_name) { git_strarray remote_list = {0}; size_t i; git_remote *remote; const git_refspec *fetchspec; int error = 0; char *remote_name = NULL; assert(buf && repo && canonical_branch_name); /* Verify that this is a remote branch */ if (!git_reference__is_remote(canonical_branch_name)) { giterr_set(GITERR_INVALID, "Reference '%s' is not a remote branch.", canonical_branch_name); error = GIT_ERROR; goto cleanup; } /* Get the remotes */ if ((error = git_remote_list(&remote_list, repo)) < 0) goto cleanup; /* Find matching remotes */ for (i = 0; i < remote_list.count; i++) { if ((error = git_remote_load(&remote, repo, remote_list.strings[i])) < 0) continue; fetchspec = git_remote__matching_dst_refspec(remote, canonical_branch_name); if (fetchspec) { /* If we have not already set out yet, then set * it to the matching remote name. Otherwise * multiple remotes match this reference, and it * is ambiguous. */ if (!remote_name) { remote_name = remote_list.strings[i]; } else { git_remote_free(remote); giterr_set(GITERR_REFERENCE, "Reference '%s' is ambiguous", canonical_branch_name); error = GIT_EAMBIGUOUS; goto cleanup; } } git_remote_free(remote); } if (remote_name) { git_buf_clear(buf); error = git_buf_puts(buf, remote_name); } else { giterr_set(GITERR_REFERENCE, "Could not determine remote for '%s'", canonical_branch_name); error = GIT_ENOTFOUND; } cleanup: git_strarray_free(&remote_list); return error; } int git_branch_remote_name(char *buffer, size_t buffer_len, git_repository *repo, const char *refname) { int ret; git_buf buf = GIT_BUF_INIT; if ((ret = remote_name(&buf, repo, refname)) < 0) return ret; if (buffer) git_buf_copy_cstr(buffer, buffer_len, &buf); ret = (int)git_buf_len(&buf) + 1; git_buf_free(&buf); return ret; } int git_branch_upstream_name( char *tracking_branch_name_out, size_t buffer_size, git_repository *repo, const char *canonical_branch_name) { git_buf buf = GIT_BUF_INIT; int error; assert(canonical_branch_name); if (tracking_branch_name_out && buffer_size) *tracking_branch_name_out = '\0'; if ((error = git_branch_upstream__name( &buf, repo, canonical_branch_name)) < 0) goto cleanup; if (tracking_branch_name_out && buf.size + 1 > buffer_size) { /* +1 for NUL byte */ giterr_set( GITERR_INVALID, "Buffer too short to hold the tracked reference name."); error = -1; goto cleanup; } if (tracking_branch_name_out) git_buf_copy_cstr(tracking_branch_name_out, buffer_size, &buf); error = (int)buf.size + 1; cleanup: git_buf_free(&buf); return (int)error; } int git_branch_upstream( git_reference **tracking_out, git_reference *branch) { int error; git_buf tracking_name = GIT_BUF_INIT; if ((error = git_branch_upstream__name(&tracking_name, git_reference_owner(branch), git_reference_name(branch))) < 0) return error; error = git_reference_lookup( tracking_out, git_reference_owner(branch), git_buf_cstr(&tracking_name)); git_buf_free(&tracking_name); return error; } static int unset_upstream(git_config *config, const char *shortname) { git_buf buf = GIT_BUF_INIT; if (git_buf_printf(&buf, "branch.%s.remote", shortname) < 0) return -1; if (git_config_delete_entry(config, git_buf_cstr(&buf)) < 0) goto on_error; git_buf_clear(&buf); if (git_buf_printf(&buf, "branch.%s.merge", shortname) < 0) goto on_error; if (git_config_delete_entry(config, git_buf_cstr(&buf)) < 0) goto on_error; git_buf_free(&buf); return 0; on_error: git_buf_free(&buf); return -1; } int git_branch_set_upstream(git_reference *branch, const char *upstream_name) { git_buf key = GIT_BUF_INIT, value = GIT_BUF_INIT; git_reference *upstream; git_repository *repo; git_remote *remote = NULL; git_config *config; const char *name, *shortname; int local; const git_refspec *fetchspec; name = git_reference_name(branch); if (!git_reference__is_branch(name)) return not_a_local_branch(name); if (git_repository_config__weakptr(&config, git_reference_owner(branch)) < 0) return -1; shortname = name + strlen(GIT_REFS_HEADS_DIR); if (upstream_name == NULL) return unset_upstream(config, shortname); repo = git_reference_owner(branch); /* First we need to figure out whether it's a branch or remote-tracking */ if (git_branch_lookup(&upstream, repo, upstream_name, GIT_BRANCH_LOCAL) == 0) local = 1; else if (git_branch_lookup(&upstream, repo, upstream_name, GIT_BRANCH_REMOTE) == 0) local = 0; else { giterr_set(GITERR_REFERENCE, "Cannot set upstream for branch '%s'", shortname); return GIT_ENOTFOUND; } /* * If it's local, the remote is "." and the branch name is * simply the refname. Otherwise we need to figure out what * the remote-tracking branch's name on the remote is and use * that. */ if (local) git_buf_puts(&value, "."); else remote_name(&value, repo, git_reference_name(upstream)); if (git_buf_printf(&key, "branch.%s.remote", shortname) < 0) goto on_error; if (git_config_set_string(config, git_buf_cstr(&key), git_buf_cstr(&value)) < 0) goto on_error; if (local) { git_buf_clear(&value); if (git_buf_puts(&value, git_reference_name(upstream)) < 0) goto on_error; } else { /* Get the remoe-tracking branch's refname in its repo */ if (git_remote_load(&remote, repo, git_buf_cstr(&value)) < 0) goto on_error; fetchspec = git_remote__matching_dst_refspec(remote, git_reference_name(upstream)); git_buf_clear(&value); if (!fetchspec || git_refspec_transform_l(&value, fetchspec, git_reference_name(upstream)) < 0) goto on_error; git_remote_free(remote); remote = NULL; } git_buf_clear(&key); if (git_buf_printf(&key, "branch.%s.merge", shortname) < 0) goto on_error; if (git_config_set_string(config, git_buf_cstr(&key), git_buf_cstr(&value)) < 0) goto on_error; git_reference_free(upstream); git_buf_free(&key); git_buf_free(&value); return 0; on_error: git_reference_free(upstream); git_buf_free(&key); git_buf_free(&value); git_remote_free(remote); return -1; } int git_branch_is_head( git_reference *branch) { git_reference *head; bool is_same = false; int error; assert(branch); if (!git_reference_is_branch(branch)) return false; error = git_repository_head(&head, git_reference_owner(branch)); if (error == GIT_EORPHANEDHEAD || error == GIT_ENOTFOUND) return false; if (error < 0) return -1; is_same = strcmp( git_reference_name(branch), git_reference_name(head)) == 0; git_reference_free(head); return is_same; } libgit2-0.19.0/src/branch.h000066400000000000000000000006371216214232500153360ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #ifndef INCLUDE_branch_h__ #define INCLUDE_branch_h__ #include "buffer.h" int git_branch_upstream__name( git_buf *tracking_name, git_repository *repo, const char *canonical_branch_name); #endif libgit2-0.19.0/src/bswap.h000066400000000000000000000036341216214232500152150ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #include "common.h" /* * Default version that the compiler ought to optimize properly with * constant values. */ GIT_INLINE(uint32_t) default_swab32(uint32_t val) { return (((val & 0xff000000) >> 24) | ((val & 0x00ff0000) >> 8) | ((val & 0x0000ff00) << 8) | ((val & 0x000000ff) << 24)); } #undef bswap32 GIT_INLINE(uint16_t) default_swab16(uint16_t val) { return (((val & 0xff00) >> 8) | ((val & 0x00ff) << 8)); } #undef bswap16 #if defined(__GNUC__) && defined(__i386__) #define bswap32(x) ({ \ uint32_t __res; \ if (__builtin_constant_p(x)) { \ __res = default_swab32(x); \ } else { \ __asm__("bswap %0" : "=r" (__res) : "0" ((uint32_t)(x))); \ } \ __res; }) #define bswap16(x) ({ \ uint16_t __res; \ if (__builtin_constant_p(x)) { \ __res = default_swab16(x); \ } else { \ __asm__("xchgb %b0,%h0" : "=q" (__res) : "0" ((uint16_t)(x))); \ } \ __res; }) #elif defined(__GNUC__) && defined(__x86_64__) #define bswap32(x) ({ \ uint32_t __res; \ if (__builtin_constant_p(x)) { \ __res = default_swab32(x); \ } else { \ __asm__("bswapl %0" : "=r" (__res) : "0" ((uint32_t)(x))); \ } \ __res; }) #define bswap16(x) ({ \ uint16_t __res; \ if (__builtin_constant_p(x)) { \ __res = default_swab16(x); \ } else { \ __asm__("xchgb %b0,%h0" : "=Q" (__res) : "0" ((uint16_t)(x))); \ } \ __res; }) #elif defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_X64)) #include #define bswap32(x) _byteswap_ulong(x) #define bswap16(x) _byteswap_ushort(x) #endif #ifdef bswap32 #undef ntohl #undef htonl #define ntohl(x) bswap32(x) #define htonl(x) bswap32(x) #endif #ifdef bswap16 #undef ntohs #undef htons #define ntohs(x) bswap16(x) #define htons(x) bswap16(x) #endif libgit2-0.19.0/src/buf_text.c000066400000000000000000000141551216214232500157140ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #include "buf_text.h" int git_buf_text_puts_escaped( git_buf *buf, const char *string, const char *esc_chars, const char *esc_with) { const char *scan; size_t total = 0, esc_len = strlen(esc_with), count; if (!string) return 0; for (scan = string; *scan; ) { /* count run of non-escaped characters */ count = strcspn(scan, esc_chars); total += count; scan += count; /* count run of escaped characters */ count = strspn(scan, esc_chars); total += count * (esc_len + 1); scan += count; } if (git_buf_grow(buf, buf->size + total + 1) < 0) return -1; for (scan = string; *scan; ) { count = strcspn(scan, esc_chars); memmove(buf->ptr + buf->size, scan, count); scan += count; buf->size += count; for (count = strspn(scan, esc_chars); count > 0; --count) { /* copy escape sequence */ memmove(buf->ptr + buf->size, esc_with, esc_len); buf->size += esc_len; /* copy character to be escaped */ buf->ptr[buf->size] = *scan; buf->size++; scan++; } } buf->ptr[buf->size] = '\0'; return 0; } void git_buf_text_unescape(git_buf *buf) { buf->size = git__unescape(buf->ptr); } int git_buf_text_crlf_to_lf(git_buf *tgt, const git_buf *src) { const char *scan = src->ptr; const char *scan_end = src->ptr + src->size; const char *next = memchr(scan, '\r', src->size); char *out; assert(tgt != src); if (!next) return GIT_ENOTFOUND; /* reduce reallocs while in the loop */ if (git_buf_grow(tgt, src->size) < 0) return -1; out = tgt->ptr; tgt->size = 0; /* Find the next \r and copy whole chunk up to there to tgt */ for (; next; scan = next + 1, next = memchr(scan, '\r', scan_end - scan)) { if (next > scan) { size_t copylen = next - scan; memcpy(out, scan, copylen); out += copylen; } /* Do not drop \r unless it is followed by \n */ if (next[1] != '\n') *out++ = '\r'; } /* Copy remaining input into dest */ memcpy(out, scan, scan_end - scan + 1); /* +1 for NUL byte */ out += (scan_end - scan); tgt->size = out - tgt->ptr; return 0; } int git_buf_text_lf_to_crlf(git_buf *tgt, const git_buf *src) { const char *start = src->ptr; const char *end = start + src->size; const char *scan = start; const char *next = memchr(scan, '\n', src->size); assert(tgt != src); if (!next) return GIT_ENOTFOUND; /* attempt to reduce reallocs while in the loop */ if (git_buf_grow(tgt, src->size + (src->size >> 4) + 1) < 0) return -1; tgt->size = 0; for (; next; scan = next + 1, next = memchr(scan, '\n', end - scan)) { size_t copylen = next - scan; /* don't convert existing \r\n to \r\r\n */ size_t extralen = (next > start && next[-1] == '\r') ? 1 : 2; size_t needsize = tgt->size + copylen + extralen + 1; if (tgt->asize < needsize && git_buf_grow(tgt, needsize) < 0) return -1; if (next > scan) { memcpy(tgt->ptr + tgt->size, scan, copylen); tgt->size += copylen; } if (extralen == 2) tgt->ptr[tgt->size++] = '\r'; tgt->ptr[tgt->size++] = '\n'; } return git_buf_put(tgt, scan, end - scan); } int git_buf_text_common_prefix(git_buf *buf, const git_strarray *strings) { size_t i; const char *str, *pfx; git_buf_clear(buf); if (!strings || !strings->count) return 0; /* initialize common prefix to first string */ if (git_buf_sets(buf, strings->strings[0]) < 0) return -1; /* go through the rest of the strings, truncating to shared prefix */ for (i = 1; i < strings->count; ++i) { for (str = strings->strings[i], pfx = buf->ptr; *str && *str == *pfx; str++, pfx++) /* scanning */; git_buf_truncate(buf, pfx - buf->ptr); if (!buf->size) break; } return 0; } bool git_buf_text_is_binary(const git_buf *buf) { const char *scan = buf->ptr, *end = buf->ptr + buf->size; int printable = 0, nonprintable = 0; while (scan < end) { unsigned char c = *scan++; if (c > 0x1F && c < 0x7F) printable++; else if (c == '\0') return true; else if (!git__isspace(c)) nonprintable++; } return ((printable >> 7) < nonprintable); } bool git_buf_text_contains_nul(const git_buf *buf) { return (memchr(buf->ptr, '\0', buf->size) != NULL); } int git_buf_text_detect_bom(git_bom_t *bom, const git_buf *buf, size_t offset) { const char *ptr; size_t len; *bom = GIT_BOM_NONE; /* need at least 2 bytes after offset to look for any BOM */ if (buf->size < offset + 2) return 0; ptr = buf->ptr + offset; len = buf->size - offset; switch (*ptr++) { case 0: if (len >= 4 && ptr[0] == 0 && ptr[1] == '\xFE' && ptr[2] == '\xFF') { *bom = GIT_BOM_UTF32_BE; return 4; } break; case '\xEF': if (len >= 3 && ptr[0] == '\xBB' && ptr[1] == '\xBF') { *bom = GIT_BOM_UTF8; return 3; } break; case '\xFE': if (*ptr == '\xFF') { *bom = GIT_BOM_UTF16_BE; return 2; } break; case '\xFF': if (*ptr != '\xFE') break; if (len >= 4 && ptr[1] == 0 && ptr[2] == 0) { *bom = GIT_BOM_UTF32_LE; return 4; } else { *bom = GIT_BOM_UTF16_LE; return 2; } break; default: break; } return 0; } bool git_buf_text_gather_stats( git_buf_text_stats *stats, const git_buf *buf, bool skip_bom) { const char *scan = buf->ptr, *end = buf->ptr + buf->size; int skip; memset(stats, 0, sizeof(*stats)); /* BOM detection */ skip = git_buf_text_detect_bom(&stats->bom, buf, 0); if (skip_bom) scan += skip; /* Ignore EOF character */ if (buf->size > 0 && end[-1] == '\032') end--; /* Counting loop */ while (scan < end) { unsigned char c = *scan++; if ((c > 0x1F && c < 0x7F) || c > 0x9f) stats->printable++; else switch (c) { case '\0': stats->nul++; stats->nonprintable++; break; case '\n': stats->lf++; break; case '\r': stats->cr++; if (scan < end && *scan == '\n') stats->crlf++; break; case '\t': case '\f': case '\v': case '\b': case 0x1b: /*ESC*/ stats->printable++; break; default: stats->nonprintable++; break; } } return (stats->nul > 0 || ((stats->printable >> 7) < stats->nonprintable)); } libgit2-0.19.0/src/buf_text.h000066400000000000000000000070351216214232500157200ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #ifndef INCLUDE_buf_text_h__ #define INCLUDE_buf_text_h__ #include "buffer.h" typedef enum { GIT_BOM_NONE = 0, GIT_BOM_UTF8 = 1, GIT_BOM_UTF16_LE = 2, GIT_BOM_UTF16_BE = 3, GIT_BOM_UTF32_LE = 4, GIT_BOM_UTF32_BE = 5 } git_bom_t; typedef struct { git_bom_t bom; /* BOM found at head of text */ unsigned int nul, cr, lf, crlf; /* NUL, CR, LF and CRLF counts */ unsigned int printable, nonprintable; /* These are just approximations! */ } git_buf_text_stats; /** * Append string to buffer, prefixing each character from `esc_chars` with * `esc_with` string. * * @param buf Buffer to append data to * @param string String to escape and append * @param esc_chars Characters to be escaped * @param esc_with String to insert in from of each found character * @return 0 on success, <0 on failure (probably allocation problem) */ extern int git_buf_text_puts_escaped( git_buf *buf, const char *string, const char *esc_chars, const char *esc_with); /** * Append string escaping characters that are regex special */ GIT_INLINE(int) git_buf_text_puts_escape_regex(git_buf *buf, const char *string) { return git_buf_text_puts_escaped(buf, string, "^.[]$()|*+?{}\\", "\\"); } /** * Unescape all characters in a buffer in place * * I.e. remove backslashes */ extern void git_buf_text_unescape(git_buf *buf); /** * Replace all \r\n with \n (or do nothing if no \r\n are found) * * @return 0 on success, GIT_ENOTFOUND if no \r\n, -1 on memory error */ extern int git_buf_text_crlf_to_lf(git_buf *tgt, const git_buf *src); /** * Replace all \n with \r\n (or do nothing if no \n are found) * * @return 0 on success, GIT_ENOTFOUND if no \n, -1 on memory error */ extern int git_buf_text_lf_to_crlf(git_buf *tgt, const git_buf *src); /** * Fill buffer with the common prefix of a array of strings * * Buffer will be set to empty if there is no common prefix */ extern int git_buf_text_common_prefix(git_buf *buf, const git_strarray *strs); /** * Check quickly if buffer looks like it contains binary data * * @param buf Buffer to check * @return true if buffer looks like non-text data */ extern bool git_buf_text_is_binary(const git_buf *buf); /** * Check quickly if buffer contains a NUL byte * * @param buf Buffer to check * @return true if buffer contains a NUL byte */ extern bool git_buf_text_contains_nul(const git_buf *buf); /** * Check if a buffer begins with a UTF BOM * * @param bom Set to the type of BOM detected or GIT_BOM_NONE * @param buf Buffer in which to check the first bytes for a BOM * @param offset Offset into buffer to look for BOM * @return Number of bytes of BOM data (or 0 if no BOM found) */ extern int git_buf_text_detect_bom( git_bom_t *bom, const git_buf *buf, size_t offset); /** * Gather stats for a piece of text * * Fill the `stats` structure with counts of unreadable characters, carriage * returns, etc, so it can be used in heuristics. This automatically skips * a trailing EOF (\032 character). Also it will look for a BOM at the * start of the text and can be told to skip that as well. * * @param stats Structure to be filled in * @param buf Text to process * @param skip_bom Exclude leading BOM from stats if true * @return Does the buffer heuristically look like binary data */ extern bool git_buf_text_gather_stats( git_buf_text_stats *stats, const git_buf *buf, bool skip_bom); #endif libgit2-0.19.0/src/buffer.c000066400000000000000000000236561216214232500153530ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #include "buffer.h" #include "posix.h" #include #include /* Used as default value for git_buf->ptr so that people can always * assume ptr is non-NULL and zero terminated even for new git_bufs. */ char git_buf__initbuf[1]; char git_buf__oom[1]; #define ENSURE_SIZE(b, d) \ if ((d) > buf->asize && git_buf_grow(b, (d)) < 0)\ return -1; void git_buf_init(git_buf *buf, size_t initial_size) { buf->asize = 0; buf->size = 0; buf->ptr = git_buf__initbuf; if (initial_size) git_buf_grow(buf, initial_size); } int git_buf_try_grow(git_buf *buf, size_t target_size, bool mark_oom) { char *new_ptr; size_t new_size; if (buf->ptr == git_buf__oom) return -1; if (target_size <= buf->asize) return 0; if (buf->asize == 0) { new_size = target_size; new_ptr = NULL; } else { new_size = buf->asize; new_ptr = buf->ptr; } /* grow the buffer size by 1.5, until it's big enough * to fit our target size */ while (new_size < target_size) new_size = (new_size << 1) - (new_size >> 1); /* round allocation up to multiple of 8 */ new_size = (new_size + 7) & ~7; new_ptr = git__realloc(new_ptr, new_size); if (!new_ptr) { if (mark_oom) buf->ptr = git_buf__oom; return -1; } buf->asize = new_size; buf->ptr = new_ptr; /* truncate the existing buffer size if necessary */ if (buf->size >= buf->asize) buf->size = buf->asize - 1; buf->ptr[buf->size] = '\0'; return 0; } void git_buf_free(git_buf *buf) { if (!buf) return; if (buf->ptr != git_buf__initbuf && buf->ptr != git_buf__oom) git__free(buf->ptr); git_buf_init(buf, 0); } void git_buf_clear(git_buf *buf) { buf->size = 0; if (buf->asize > 0) buf->ptr[0] = '\0'; } int git_buf_set(git_buf *buf, const char *data, size_t len) { if (len == 0 || data == NULL) { git_buf_clear(buf); } else { if (data != buf->ptr) { ENSURE_SIZE(buf, len + 1); memmove(buf->ptr, data, len); } buf->size = len; buf->ptr[buf->size] = '\0'; } return 0; } int git_buf_sets(git_buf *buf, const char *string) { return git_buf_set(buf, string, string ? strlen(string) : 0); } int git_buf_putc(git_buf *buf, char c) { ENSURE_SIZE(buf, buf->size + 2); buf->ptr[buf->size++] = c; buf->ptr[buf->size] = '\0'; return 0; } int git_buf_put(git_buf *buf, const char *data, size_t len) { ENSURE_SIZE(buf, buf->size + len + 1); memmove(buf->ptr + buf->size, data, len); buf->size += len; buf->ptr[buf->size] = '\0'; return 0; } int git_buf_puts(git_buf *buf, const char *string) { assert(string); return git_buf_put(buf, string, strlen(string)); } static const char b64str[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; int git_buf_put_base64(git_buf *buf, const char *data, size_t len) { size_t extra = len % 3; uint8_t *write, a, b, c; const uint8_t *read = (const uint8_t *)data; ENSURE_SIZE(buf, buf->size + 4 * ((len / 3) + !!extra) + 1); write = (uint8_t *)&buf->ptr[buf->size]; /* convert each run of 3 bytes into 4 output bytes */ for (len -= extra; len > 0; len -= 3) { a = *read++; b = *read++; c = *read++; *write++ = b64str[a >> 2]; *write++ = b64str[(a & 0x03) << 4 | b >> 4]; *write++ = b64str[(b & 0x0f) << 2 | c >> 6]; *write++ = b64str[c & 0x3f]; } if (extra > 0) { a = *read++; b = (extra > 1) ? *read++ : 0; *write++ = b64str[a >> 2]; *write++ = b64str[(a & 0x03) << 4 | b >> 4]; *write++ = (extra > 1) ? b64str[(b & 0x0f) << 2] : '='; *write++ = '='; } buf->size = ((char *)write) - buf->ptr; buf->ptr[buf->size] = '\0'; return 0; } int git_buf_vprintf(git_buf *buf, const char *format, va_list ap) { int len; const size_t expected_size = buf->size + (strlen(format) * 2); ENSURE_SIZE(buf, expected_size); while (1) { va_list args; va_copy(args, ap); len = p_vsnprintf( buf->ptr + buf->size, buf->asize - buf->size, format, args ); if (len < 0) { git__free(buf->ptr); buf->ptr = git_buf__oom; return -1; } if ((size_t)len + 1 <= buf->asize - buf->size) { buf->size += len; break; } ENSURE_SIZE(buf, buf->size + len + 1); } return 0; } int git_buf_printf(git_buf *buf, const char *format, ...) { int r; va_list ap; va_start(ap, format); r = git_buf_vprintf(buf, format, ap); va_end(ap); return r; } void git_buf_copy_cstr(char *data, size_t datasize, const git_buf *buf) { size_t copylen; assert(data && datasize && buf); data[0] = '\0'; if (buf->size == 0 || buf->asize <= 0) return; copylen = buf->size; if (copylen > datasize - 1) copylen = datasize - 1; memmove(data, buf->ptr, copylen); data[copylen] = '\0'; } void git_buf_consume(git_buf *buf, const char *end) { if (end > buf->ptr && end <= buf->ptr + buf->size) { size_t consumed = end - buf->ptr; memmove(buf->ptr, end, buf->size - consumed); buf->size -= consumed; buf->ptr[buf->size] = '\0'; } } void git_buf_truncate(git_buf *buf, size_t len) { if (len < buf->size) { buf->size = len; buf->ptr[buf->size] = '\0'; } } void git_buf_rtruncate_at_char(git_buf *buf, char separator) { ssize_t idx = git_buf_rfind_next(buf, separator); git_buf_truncate(buf, idx < 0 ? 0 : (size_t)idx); } void git_buf_swap(git_buf *buf_a, git_buf *buf_b) { git_buf t = *buf_a; *buf_a = *buf_b; *buf_b = t; } char *git_buf_detach(git_buf *buf) { char *data = buf->ptr; if (buf->asize == 0 || buf->ptr == git_buf__oom) return NULL; git_buf_init(buf, 0); return data; } void git_buf_attach(git_buf *buf, char *ptr, size_t asize) { git_buf_free(buf); if (ptr) { buf->ptr = ptr; buf->size = strlen(ptr); if (asize) buf->asize = (asize < buf->size) ? buf->size + 1 : asize; else /* pass 0 to fall back on strlen + 1 */ buf->asize = buf->size + 1; } else { git_buf_grow(buf, asize); } } int git_buf_join_n(git_buf *buf, char separator, int nbuf, ...) { va_list ap; int i; size_t total_size = 0, original_size = buf->size; char *out, *original = buf->ptr; if (buf->size > 0 && buf->ptr[buf->size - 1] != separator) ++total_size; /* space for initial separator */ /* Make two passes to avoid multiple reallocation */ va_start(ap, nbuf); for (i = 0; i < nbuf; ++i) { const char* segment; size_t segment_len; segment = va_arg(ap, const char *); if (!segment) continue; segment_len = strlen(segment); total_size += segment_len; if (segment_len == 0 || segment[segment_len - 1] != separator) ++total_size; /* space for separator */ } va_end(ap); /* expand buffer if needed */ if (total_size == 0) return 0; if (git_buf_grow(buf, buf->size + total_size + 1) < 0) return -1; out = buf->ptr + buf->size; /* append separator to existing buf if needed */ if (buf->size > 0 && out[-1] != separator) *out++ = separator; va_start(ap, nbuf); for (i = 0; i < nbuf; ++i) { const char* segment; size_t segment_len; segment = va_arg(ap, const char *); if (!segment) continue; /* deal with join that references buffer's original content */ if (segment >= original && segment < original + original_size) { size_t offset = (segment - original); segment = buf->ptr + offset; segment_len = original_size - offset; } else { segment_len = strlen(segment); } /* skip leading separators */ if (out > buf->ptr && out[-1] == separator) while (segment_len > 0 && *segment == separator) { segment++; segment_len--; } /* copy over next buffer */ if (segment_len > 0) { memmove(out, segment, segment_len); out += segment_len; } /* append trailing separator (except for last item) */ if (i < nbuf - 1 && out > buf->ptr && out[-1] != separator) *out++ = separator; } va_end(ap); /* set size based on num characters actually written */ buf->size = out - buf->ptr; buf->ptr[buf->size] = '\0'; return 0; } int git_buf_join( git_buf *buf, char separator, const char *str_a, const char *str_b) { size_t strlen_a = str_a ? strlen(str_a) : 0; size_t strlen_b = strlen(str_b); int need_sep = 0; ssize_t offset_a = -1; /* not safe to have str_b point internally to the buffer */ assert(str_b < buf->ptr || str_b > buf->ptr + buf->size); /* figure out if we need to insert a separator */ if (separator && strlen_a) { while (*str_b == separator) { str_b++; strlen_b--; } if (str_a[strlen_a - 1] != separator) need_sep = 1; } /* str_a could be part of the buffer */ if (str_a >= buf->ptr && str_a < buf->ptr + buf->size) offset_a = str_a - buf->ptr; if (git_buf_grow(buf, strlen_a + strlen_b + need_sep + 1) < 0) return -1; /* fix up internal pointers */ if (offset_a >= 0) str_a = buf->ptr + offset_a; /* do the actual copying */ if (offset_a != 0) memmove(buf->ptr, str_a, strlen_a); if (need_sep) buf->ptr[strlen_a] = separator; memcpy(buf->ptr + strlen_a + need_sep, str_b, strlen_b); buf->size = strlen_a + strlen_b + need_sep; buf->ptr[buf->size] = '\0'; return 0; } void git_buf_rtrim(git_buf *buf) { while (buf->size > 0) { if (!git__isspace(buf->ptr[buf->size - 1])) break; buf->size--; } buf->ptr[buf->size] = '\0'; } int git_buf_cmp(const git_buf *a, const git_buf *b) { int result = memcmp(a->ptr, b->ptr, min(a->size, b->size)); return (result != 0) ? result : (a->size < b->size) ? -1 : (a->size > b->size) ? 1 : 0; } int git_buf_splice( git_buf *buf, size_t where, size_t nb_to_remove, const char *data, size_t nb_to_insert) { assert(buf && where <= git_buf_len(buf) && where + nb_to_remove <= git_buf_len(buf)); /* Ported from git.git * https://github.com/git/git/blob/16eed7c/strbuf.c#L159-176 */ if (git_buf_grow(buf, git_buf_len(buf) + nb_to_insert - nb_to_remove) < 0) return -1; memmove(buf->ptr + where + nb_to_insert, buf->ptr + where + nb_to_remove, buf->size - where - nb_to_remove); memcpy(buf->ptr + where, data, nb_to_insert); buf->size = buf->size + nb_to_insert - nb_to_remove; buf->ptr[buf->size] = '\0'; return 0; } libgit2-0.19.0/src/buffer.h000066400000000000000000000124561216214232500153540ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #ifndef INCLUDE_buffer_h__ #define INCLUDE_buffer_h__ #include "common.h" #include "git2/strarray.h" #include typedef struct { char *ptr; size_t asize, size; } git_buf; extern char git_buf__initbuf[]; extern char git_buf__oom[]; #define GIT_BUF_INIT { git_buf__initbuf, 0, 0 } /** * Initialize a git_buf structure. * * For the cases where GIT_BUF_INIT cannot be used to do static * initialization. */ extern void git_buf_init(git_buf *buf, size_t initial_size); /** * Attempt to grow the buffer to hold at least `target_size` bytes. * * If the allocation fails, this will return an error. If mark_oom is true, * this will mark the buffer as invalid for future operations; if false, * existing buffer content will be preserved, but calling code must handle * that buffer was not expanded. */ extern int git_buf_try_grow(git_buf *buf, size_t target_size, bool mark_oom); /** * Grow the buffer to hold at least `target_size` bytes. * * If the allocation fails, this will return an error and the buffer will be * marked as invalid for future operations, invaliding contents. * * @return 0 on success or -1 on failure */ GIT_INLINE(int) git_buf_grow(git_buf *buf, size_t target_size) { return git_buf_try_grow(buf, target_size, true); } extern void git_buf_free(git_buf *buf); extern void git_buf_swap(git_buf *buf_a, git_buf *buf_b); extern char *git_buf_detach(git_buf *buf); extern void git_buf_attach(git_buf *buf, char *ptr, size_t asize); /** * Test if there have been any reallocation failures with this git_buf. * * Any function that writes to a git_buf can fail due to memory allocation * issues. If one fails, the git_buf will be marked with an OOM error and * further calls to modify the buffer will fail. Check git_buf_oom() at the * end of your sequence and it will be true if you ran out of memory at any * point with that buffer. * * @return false if no error, true if allocation error */ GIT_INLINE(bool) git_buf_oom(const git_buf *buf) { return (buf->ptr == git_buf__oom); } /* * Functions below that return int value error codes will return 0 on * success or -1 on failure (which generally means an allocation failed). * Using a git_buf where the allocation has failed with result in -1 from * all further calls using that buffer. As a result, you can ignore the * return code of these functions and call them in a series then just call * git_buf_oom at the end. */ int git_buf_set(git_buf *buf, const char *data, size_t len); int git_buf_sets(git_buf *buf, const char *string); int git_buf_putc(git_buf *buf, char c); int git_buf_put(git_buf *buf, const char *data, size_t len); int git_buf_puts(git_buf *buf, const char *string); int git_buf_printf(git_buf *buf, const char *format, ...) GIT_FORMAT_PRINTF(2, 3); int git_buf_vprintf(git_buf *buf, const char *format, va_list ap); void git_buf_clear(git_buf *buf); void git_buf_consume(git_buf *buf, const char *end); void git_buf_truncate(git_buf *buf, size_t len); void git_buf_rtruncate_at_char(git_buf *path, char separator); int git_buf_join_n(git_buf *buf, char separator, int nbuf, ...); int git_buf_join(git_buf *buf, char separator, const char *str_a, const char *str_b); /** * Join two strings as paths, inserting a slash between as needed. * @return 0 on success, -1 on failure */ GIT_INLINE(int) git_buf_joinpath(git_buf *buf, const char *a, const char *b) { return git_buf_join(buf, '/', a, b); } GIT_INLINE(const char *) git_buf_cstr(const git_buf *buf) { return buf->ptr; } GIT_INLINE(size_t) git_buf_len(const git_buf *buf) { return buf->size; } void git_buf_copy_cstr(char *data, size_t datasize, const git_buf *buf); #define git_buf_PUTS(buf, str) git_buf_put(buf, str, sizeof(str) - 1) GIT_INLINE(ssize_t) git_buf_rfind_next(const git_buf *buf, char ch) { ssize_t idx = (ssize_t)buf->size - 1; while (idx >= 0 && buf->ptr[idx] == ch) idx--; while (idx >= 0 && buf->ptr[idx] != ch) idx--; return idx; } GIT_INLINE(ssize_t) git_buf_rfind(const git_buf *buf, char ch) { ssize_t idx = (ssize_t)buf->size - 1; while (idx >= 0 && buf->ptr[idx] != ch) idx--; return idx; } GIT_INLINE(ssize_t) git_buf_find(const git_buf *buf, char ch) { void *found = memchr(buf->ptr, ch, buf->size); return found ? (ssize_t)((const char *)found - buf->ptr) : -1; } /* Remove whitespace from the end of the buffer */ void git_buf_rtrim(git_buf *buf); int git_buf_cmp(const git_buf *a, const git_buf *b); /* Write data as base64 encoded in buffer */ int git_buf_put_base64(git_buf *buf, const char *data, size_t len); /* * Insert, remove or replace a portion of the buffer. * * @param buf The buffer to work with * * @param where The location in the buffer where the transformation * should be applied. * * @param nb_to_remove The number of chars to be removed. 0 to not * remove any character in the buffer. * * @param data A pointer to the data which should be inserted. * * @param nb_to_insert The number of chars to be inserted. 0 to not * insert any character from the buffer. * * @return 0 or an error code. */ int git_buf_splice( git_buf *buf, size_t where, size_t nb_to_remove, const char *data, size_t nb_to_insert); #endif libgit2-0.19.0/src/cache.c000066400000000000000000000143331216214232500151350ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #include "common.h" #include "repository.h" #include "commit.h" #include "thread-utils.h" #include "util.h" #include "cache.h" #include "odb.h" #include "object.h" #include "git2/oid.h" GIT__USE_OIDMAP bool git_cache__enabled = true; ssize_t git_cache__max_storage = (256 * 1024 * 1024); git_atomic_ssize git_cache__current_storage = {0}; static size_t git_cache__max_object_size[8] = { 0, /* GIT_OBJ__EXT1 */ 4096, /* GIT_OBJ_COMMIT */ 4096, /* GIT_OBJ_TREE */ 0, /* GIT_OBJ_BLOB */ 4096, /* GIT_OBJ_TAG */ 0, /* GIT_OBJ__EXT2 */ 0, /* GIT_OBJ_OFS_DELTA */ 0 /* GIT_OBJ_REF_DELTA */ }; int git_cache_set_max_object_size(git_otype type, size_t size) { if (type < 0 || (size_t)type >= ARRAY_SIZE(git_cache__max_object_size)) { giterr_set(GITERR_INVALID, "type out of range"); return -1; } git_cache__max_object_size[type] = size; return 0; } void git_cache_dump_stats(git_cache *cache) { git_cached_obj *object; if (kh_size(cache->map) == 0) return; printf("Cache %p: %d items cached, %d bytes\n", cache, kh_size(cache->map), (int)cache->used_memory); kh_foreach_value(cache->map, object, { char oid_str[9]; printf(" %s%c %s (%d)\n", git_object_type2string(object->type), object->flags == GIT_CACHE_STORE_PARSED ? '*' : ' ', git_oid_tostr(oid_str, sizeof(oid_str), &object->oid), (int)object->size ); }); } int git_cache_init(git_cache *cache) { memset(cache, 0, sizeof(*cache)); cache->map = git_oidmap_alloc(); if (git_mutex_init(&cache->lock)) { giterr_set(GITERR_OS, "Failed to initialize cache mutex"); return -1; } return 0; } /* called with lock */ static void clear_cache(git_cache *cache) { git_cached_obj *evict = NULL; if (kh_size(cache->map) == 0) return; kh_foreach_value(cache->map, evict, { git_cached_obj_decref(evict); }); kh_clear(oid, cache->map); git_atomic_ssize_add(&git_cache__current_storage, -cache->used_memory); cache->used_memory = 0; } void git_cache_clear(git_cache *cache) { if (git_mutex_lock(&cache->lock) < 0) return; clear_cache(cache); git_mutex_unlock(&cache->lock); } void git_cache_free(git_cache *cache) { git_cache_clear(cache); git_oidmap_free(cache->map); git_mutex_free(&cache->lock); git__memzero(cache, sizeof(*cache)); } /* Called with lock */ static void cache_evict_entries(git_cache *cache) { uint32_t seed = rand(); size_t evict_count = 8; ssize_t evicted_memory = 0; /* do not infinite loop if there's not enough entries to evict */ if (evict_count > kh_size(cache->map)) { clear_cache(cache); return; } while (evict_count > 0) { khiter_t pos = seed++ % kh_end(cache->map); if (kh_exist(cache->map, pos)) { git_cached_obj *evict = kh_val(cache->map, pos); evict_count--; evicted_memory += evict->size; git_cached_obj_decref(evict); kh_del(oid, cache->map, pos); } } cache->used_memory -= evicted_memory; git_atomic_ssize_add(&git_cache__current_storage, -evicted_memory); } static bool cache_should_store(git_otype object_type, size_t object_size) { size_t max_size = git_cache__max_object_size[object_type]; return git_cache__enabled && object_size < max_size; } static void *cache_get(git_cache *cache, const git_oid *oid, unsigned int flags) { khiter_t pos; git_cached_obj *entry = NULL; if (!git_cache__enabled || git_mutex_lock(&cache->lock) < 0) return NULL; pos = kh_get(oid, cache->map, oid); if (pos != kh_end(cache->map)) { entry = kh_val(cache->map, pos); if (flags && entry->flags != flags) { entry = NULL; } else { git_cached_obj_incref(entry); } } git_mutex_unlock(&cache->lock); return entry; } static void *cache_store(git_cache *cache, git_cached_obj *entry) { khiter_t pos; git_cached_obj_incref(entry); if (!git_cache__enabled && cache->used_memory > 0) { git_cache_clear(cache); return entry; } if (!cache_should_store(entry->type, entry->size)) return entry; if (git_mutex_lock(&cache->lock) < 0) return entry; /* soften the load on the cache */ if (git_cache__current_storage.val > git_cache__max_storage) cache_evict_entries(cache); pos = kh_get(oid, cache->map, &entry->oid); /* not found */ if (pos == kh_end(cache->map)) { int rval; pos = kh_put(oid, cache->map, &entry->oid, &rval); if (rval >= 0) { kh_key(cache->map, pos) = &entry->oid; kh_val(cache->map, pos) = entry; git_cached_obj_incref(entry); cache->used_memory += entry->size; git_atomic_ssize_add(&git_cache__current_storage, (ssize_t)entry->size); } } /* found */ else { git_cached_obj *stored_entry = kh_val(cache->map, pos); if (stored_entry->flags == entry->flags) { git_cached_obj_decref(entry); git_cached_obj_incref(stored_entry); entry = stored_entry; } else if (stored_entry->flags == GIT_CACHE_STORE_RAW && entry->flags == GIT_CACHE_STORE_PARSED) { git_cached_obj_decref(stored_entry); git_cached_obj_incref(entry); kh_key(cache->map, pos) = &entry->oid; kh_val(cache->map, pos) = entry; } else { /* NO OP */ } } git_mutex_unlock(&cache->lock); return entry; } void *git_cache_store_raw(git_cache *cache, git_odb_object *entry) { entry->cached.flags = GIT_CACHE_STORE_RAW; return cache_store(cache, (git_cached_obj *)entry); } void *git_cache_store_parsed(git_cache *cache, git_object *entry) { entry->cached.flags = GIT_CACHE_STORE_PARSED; return cache_store(cache, (git_cached_obj *)entry); } git_odb_object *git_cache_get_raw(git_cache *cache, const git_oid *oid) { return cache_get(cache, oid, GIT_CACHE_STORE_RAW); } git_object *git_cache_get_parsed(git_cache *cache, const git_oid *oid) { return cache_get(cache, oid, GIT_CACHE_STORE_PARSED); } void *git_cache_get_any(git_cache *cache, const git_oid *oid) { return cache_get(cache, oid, GIT_CACHE_STORE_ANY); } void git_cached_obj_decref(void *_obj) { git_cached_obj *obj = _obj; if (git_atomic_dec(&obj->refcount) == 0) { switch (obj->flags) { case GIT_CACHE_STORE_RAW: git_odb_object__free(_obj); break; case GIT_CACHE_STORE_PARSED: git_object__free(_obj); break; default: git__free(_obj); break; } } } libgit2-0.19.0/src/cache.h000066400000000000000000000031771216214232500151460ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #ifndef INCLUDE_cache_h__ #define INCLUDE_cache_h__ #include "git2/common.h" #include "git2/oid.h" #include "git2/odb.h" #include "thread-utils.h" #include "oidmap.h" enum { GIT_CACHE_STORE_ANY = 0, GIT_CACHE_STORE_RAW = 1, GIT_CACHE_STORE_PARSED = 2 }; typedef struct { git_oid oid; int16_t type; /* git_otype value */ uint16_t flags; /* GIT_CACHE_STORE value */ size_t size; git_atomic refcount; } git_cached_obj; typedef struct { git_oidmap *map; git_mutex lock; ssize_t used_memory; } git_cache; extern bool git_cache__enabled; extern ssize_t git_cache__max_storage; extern git_atomic_ssize git_cache__current_storage; int git_cache_set_max_object_size(git_otype type, size_t size); int git_cache_init(git_cache *cache); void git_cache_free(git_cache *cache); void git_cache_clear(git_cache *cache); void *git_cache_store_raw(git_cache *cache, git_odb_object *entry); void *git_cache_store_parsed(git_cache *cache, git_object *entry); git_odb_object *git_cache_get_raw(git_cache *cache, const git_oid *oid); git_object *git_cache_get_parsed(git_cache *cache, const git_oid *oid); void *git_cache_get_any(git_cache *cache, const git_oid *oid); GIT_INLINE(size_t) git_cache_size(git_cache *cache) { return (size_t)kh_size(cache->map); } GIT_INLINE(void) git_cached_obj_incref(void *_obj) { git_cached_obj *obj = _obj; git_atomic_inc(&obj->refcount); } void git_cached_obj_decref(void *_obj); #endif libgit2-0.19.0/src/cc-compat.h000066400000000000000000000031451216214232500157440ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #ifndef INCLUDE_compat_h__ #define INCLUDE_compat_h__ /* * See if our compiler is known to support flexible array members. */ #ifndef GIT_FLEX_ARRAY # if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) # define GIT_FLEX_ARRAY /* empty */ # elif defined(__GNUC__) # if (__GNUC__ >= 3) # define GIT_FLEX_ARRAY /* empty */ # else # define GIT_FLEX_ARRAY 0 /* older GNU extension */ # endif # endif /* Default to safer but a bit wasteful traditional style */ # ifndef GIT_FLEX_ARRAY # define GIT_FLEX_ARRAY 1 # endif #endif #ifdef __GNUC__ # define GIT_TYPEOF(x) (__typeof__(x)) #else # define GIT_TYPEOF(x) #endif #define GIT_UNUSED(x) ((void)(x)) /* Define the printf format specifer to use for size_t output */ #if defined(_MSC_VER) || defined(__MINGW32__) # define PRIuZ "Iu" # define PRIxZ "Ix" #else # define PRIuZ "zu" # define PRIxZ "zx" #endif /* Micosoft Visual C/C++ */ #if defined(_MSC_VER) /* disable "deprecated function" warnings */ # pragma warning ( disable : 4996 ) /* disable "conditional expression is constant" level 4 warnings */ # pragma warning ( disable : 4127 ) #endif #if defined (_MSC_VER) typedef unsigned char bool; # define true 1 # define false 0 #else # include #endif #ifndef va_copy # ifdef __va_copy # define va_copy(dst, src) __va_copy(dst, src) # else # define va_copy(dst, src) ((dst) = (src)) # endif #endif #endif /* INCLUDE_compat_h__ */ libgit2-0.19.0/src/checkout.c000066400000000000000000001130601216214232500156740ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #include #include "checkout.h" #include "git2/repository.h" #include "git2/refs.h" #include "git2/tree.h" #include "git2/blob.h" #include "git2/config.h" #include "git2/diff.h" #include "git2/submodule.h" #include "git2/sys/index.h" #include "refs.h" #include "repository.h" #include "index.h" #include "filter.h" #include "blob.h" #include "diff.h" #include "pathspec.h" #include "buf_text.h" /* See docs/checkout-internals.md for more information */ enum { CHECKOUT_ACTION__NONE = 0, CHECKOUT_ACTION__REMOVE = 1, CHECKOUT_ACTION__UPDATE_BLOB = 2, CHECKOUT_ACTION__UPDATE_SUBMODULE = 4, CHECKOUT_ACTION__CONFLICT = 8, CHECKOUT_ACTION__MAX = 8, CHECKOUT_ACTION__DEFER_REMOVE = 16, CHECKOUT_ACTION__REMOVE_AND_UPDATE = (CHECKOUT_ACTION__UPDATE_BLOB | CHECKOUT_ACTION__REMOVE), }; typedef struct { git_repository *repo; git_diff_list *diff; git_checkout_opts opts; bool opts_free_baseline; char *pfx; git_index *index; git_pool pool; git_vector removes; git_buf path; size_t workdir_len; unsigned int strategy; int can_symlink; bool reload_submodules; size_t total_steps; size_t completed_steps; } checkout_data; static int checkout_notify( checkout_data *data, git_checkout_notify_t why, const git_diff_delta *delta, const git_index_entry *wditem) { git_diff_file wdfile; const git_diff_file *baseline = NULL, *target = NULL, *workdir = NULL; const char *path = NULL; if (!data->opts.notify_cb) return 0; if ((why & data->opts.notify_flags) == 0) return 0; if (wditem) { memset(&wdfile, 0, sizeof(wdfile)); git_oid_cpy(&wdfile.oid, &wditem->oid); wdfile.path = wditem->path; wdfile.size = wditem->file_size; wdfile.flags = GIT_DIFF_FLAG_VALID_OID; wdfile.mode = wditem->mode; workdir = &wdfile; path = wditem->path; } if (delta) { switch (delta->status) { case GIT_DELTA_UNMODIFIED: case GIT_DELTA_MODIFIED: case GIT_DELTA_TYPECHANGE: default: baseline = &delta->old_file; target = &delta->new_file; break; case GIT_DELTA_ADDED: case GIT_DELTA_IGNORED: case GIT_DELTA_UNTRACKED: target = &delta->new_file; break; case GIT_DELTA_DELETED: baseline = &delta->old_file; break; } path = delta->old_file.path; } return data->opts.notify_cb( why, path, baseline, target, workdir, data->opts.notify_payload); } static bool checkout_is_workdir_modified( checkout_data *data, const git_diff_file *baseitem, const git_index_entry *wditem) { git_oid oid; const git_index_entry *ie; /* handle "modified" submodule */ if (wditem->mode == GIT_FILEMODE_COMMIT) { git_submodule *sm; unsigned int sm_status = 0; const git_oid *sm_oid = NULL; if (git_submodule_lookup(&sm, data->repo, wditem->path) < 0 || git_submodule_status(&sm_status, sm) < 0) return true; if (GIT_SUBMODULE_STATUS_IS_WD_DIRTY(sm_status)) return true; sm_oid = git_submodule_wd_id(sm); if (!sm_oid) return false; return (git_oid__cmp(&baseitem->oid, sm_oid) != 0); } /* Look at the cache to decide if the workdir is modified. If not, * we can simply compare the oid in the cache to the baseitem instead * of hashing the file. */ if ((ie = git_index_get_bypath(data->index, wditem->path, 0)) != NULL) { if (wditem->mtime.seconds == ie->mtime.seconds && wditem->mtime.nanoseconds == ie->mtime.nanoseconds && wditem->file_size == ie->file_size) return (git_oid__cmp(&baseitem->oid, &ie->oid) != 0); } /* depending on where base is coming from, we may or may not know * the actual size of the data, so we can't rely on this shortcut. */ if (baseitem->size && wditem->file_size != baseitem->size) return true; if (git_diff__oid_for_file( data->repo, wditem->path, wditem->mode, wditem->file_size, &oid) < 0) return false; return (git_oid__cmp(&baseitem->oid, &oid) != 0); } #define CHECKOUT_ACTION_IF(FLAG,YES,NO) \ ((data->strategy & GIT_CHECKOUT_##FLAG) ? CHECKOUT_ACTION__##YES : CHECKOUT_ACTION__##NO) static int checkout_action_common( checkout_data *data, int action, const git_diff_delta *delta, const git_index_entry *wd) { git_checkout_notify_t notify = GIT_CHECKOUT_NOTIFY_NONE; if (action <= 0) return action; if ((data->strategy & GIT_CHECKOUT_UPDATE_ONLY) != 0) action = (action & ~CHECKOUT_ACTION__REMOVE); if ((action & CHECKOUT_ACTION__UPDATE_BLOB) != 0) { if (S_ISGITLINK(delta->new_file.mode)) action = (action & ~CHECKOUT_ACTION__UPDATE_BLOB) | CHECKOUT_ACTION__UPDATE_SUBMODULE; /* to "update" a symlink, we must remove the old one first */ if (delta->new_file.mode == GIT_FILEMODE_LINK && wd != NULL) action |= CHECKOUT_ACTION__REMOVE; notify = GIT_CHECKOUT_NOTIFY_UPDATED; } if ((action & CHECKOUT_ACTION__CONFLICT) != 0) notify = GIT_CHECKOUT_NOTIFY_CONFLICT; if (notify != GIT_CHECKOUT_NOTIFY_NONE && checkout_notify(data, notify, delta, wd) != 0) return GIT_EUSER; return action; } static int checkout_action_no_wd( checkout_data *data, const git_diff_delta *delta) { int action = CHECKOUT_ACTION__NONE; switch (delta->status) { case GIT_DELTA_UNMODIFIED: /* case 12 */ if (checkout_notify(data, GIT_CHECKOUT_NOTIFY_DIRTY, delta, NULL)) return GIT_EUSER; action = CHECKOUT_ACTION_IF(SAFE_CREATE, UPDATE_BLOB, NONE); break; case GIT_DELTA_ADDED: /* case 2 or 28 (and 5 but not really) */ action = CHECKOUT_ACTION_IF(SAFE, UPDATE_BLOB, NONE); break; case GIT_DELTA_MODIFIED: /* case 13 (and 35 but not really) */ action = CHECKOUT_ACTION_IF(SAFE_CREATE, UPDATE_BLOB, CONFLICT); break; case GIT_DELTA_TYPECHANGE: /* case 21 (B->T) and 28 (T->B)*/ if (delta->new_file.mode == GIT_FILEMODE_TREE) action = CHECKOUT_ACTION_IF(SAFE, UPDATE_BLOB, NONE); break; case GIT_DELTA_DELETED: /* case 8 or 25 */ default: /* impossible */ break; } return checkout_action_common(data, action, delta, NULL); } static int checkout_action_wd_only( checkout_data *data, git_iterator *workdir, const git_index_entry *wd, git_vector *pathspec) { bool remove = false; git_checkout_notify_t notify = GIT_CHECKOUT_NOTIFY_NONE; if (!git_pathspec_match_path( pathspec, wd->path, (data->strategy & GIT_CHECKOUT_DISABLE_PATHSPEC_MATCH) != 0, git_iterator_ignore_case(workdir), NULL)) return 0; /* check if item is tracked in the index but not in the checkout diff */ if (data->index != NULL) { if (wd->mode != GIT_FILEMODE_TREE) { int error; if ((error = git_index_find(NULL, data->index, wd->path)) == 0) { notify = GIT_CHECKOUT_NOTIFY_DIRTY; remove = ((data->strategy & GIT_CHECKOUT_FORCE) != 0); } else if (error != GIT_ENOTFOUND) return error; } else { /* for tree entries, we have to see if there are any index * entries that are contained inside that tree */ size_t pos = git_index__prefix_position(data->index, wd->path); const git_index_entry *e = git_index_get_byindex(data->index, pos); if (e != NULL && data->diff->pfxcomp(e->path, wd->path) == 0) { notify = GIT_CHECKOUT_NOTIFY_DIRTY; remove = ((data->strategy & GIT_CHECKOUT_FORCE) != 0); } } } if (notify != GIT_CHECKOUT_NOTIFY_NONE) /* found in index */; else if (git_iterator_current_is_ignored(workdir)) { notify = GIT_CHECKOUT_NOTIFY_IGNORED; remove = ((data->strategy & GIT_CHECKOUT_REMOVE_IGNORED) != 0); } else { notify = GIT_CHECKOUT_NOTIFY_UNTRACKED; remove = ((data->strategy & GIT_CHECKOUT_REMOVE_UNTRACKED) != 0); } if (checkout_notify(data, notify, NULL, wd)) return GIT_EUSER; if (remove) { char *path = git_pool_strdup(&data->pool, wd->path); GITERR_CHECK_ALLOC(path); if (git_vector_insert(&data->removes, path) < 0) return -1; } return 0; } static bool submodule_is_config_only( checkout_data *data, const char *path) { git_submodule *sm = NULL; unsigned int sm_loc = 0; if (git_submodule_lookup(&sm, data->repo, path) < 0 || git_submodule_location(&sm_loc, sm) < 0 || sm_loc == GIT_SUBMODULE_STATUS_IN_CONFIG) return true; return false; } static int checkout_action_with_wd( checkout_data *data, const git_diff_delta *delta, const git_index_entry *wd) { int action = CHECKOUT_ACTION__NONE; switch (delta->status) { case GIT_DELTA_UNMODIFIED: /* case 14/15 or 33 */ if (checkout_is_workdir_modified(data, &delta->old_file, wd)) { if (checkout_notify( data, GIT_CHECKOUT_NOTIFY_DIRTY, delta, wd)) return GIT_EUSER; action = CHECKOUT_ACTION_IF(FORCE, UPDATE_BLOB, NONE); } break; case GIT_DELTA_ADDED: /* case 3, 4 or 6 */ action = CHECKOUT_ACTION_IF(FORCE, UPDATE_BLOB, CONFLICT); break; case GIT_DELTA_DELETED: /* case 9 or 10 (or 26 but not really) */ if (checkout_is_workdir_modified(data, &delta->old_file, wd)) action = CHECKOUT_ACTION_IF(FORCE, REMOVE, CONFLICT); else action = CHECKOUT_ACTION_IF(SAFE, REMOVE, NONE); break; case GIT_DELTA_MODIFIED: /* case 16, 17, 18 (or 36 but not really) */ if (checkout_is_workdir_modified(data, &delta->old_file, wd)) action = CHECKOUT_ACTION_IF(FORCE, UPDATE_BLOB, CONFLICT); else action = CHECKOUT_ACTION_IF(SAFE, UPDATE_BLOB, NONE); break; case GIT_DELTA_TYPECHANGE: /* case 22, 23, 29, 30 */ if (delta->old_file.mode == GIT_FILEMODE_TREE) { if (wd->mode == GIT_FILEMODE_TREE) /* either deleting items in old tree will delete the wd dir, * or we'll get a conflict when we attempt blob update... */ action = CHECKOUT_ACTION_IF(SAFE, UPDATE_BLOB, NONE); else if (wd->mode == GIT_FILEMODE_COMMIT) { /* workdir is possibly a "phantom" submodule - treat as a * tree if the only submodule info came from the config */ if (submodule_is_config_only(data, wd->path)) action = CHECKOUT_ACTION_IF(SAFE, UPDATE_BLOB, NONE); else action = CHECKOUT_ACTION_IF(FORCE, REMOVE_AND_UPDATE, CONFLICT); } else action = CHECKOUT_ACTION_IF(FORCE, REMOVE, CONFLICT); } else if (checkout_is_workdir_modified(data, &delta->old_file, wd)) action = CHECKOUT_ACTION_IF(FORCE, REMOVE_AND_UPDATE, CONFLICT); else action = CHECKOUT_ACTION_IF(SAFE, REMOVE_AND_UPDATE, NONE); /* don't update if the typechange is to a tree */ if (delta->new_file.mode == GIT_FILEMODE_TREE) action = (action & ~CHECKOUT_ACTION__UPDATE_BLOB); break; default: /* impossible */ break; } return checkout_action_common(data, action, delta, wd); } static int checkout_action_with_wd_blocker( checkout_data *data, const git_diff_delta *delta, const git_index_entry *wd) { int action = CHECKOUT_ACTION__NONE; switch (delta->status) { case GIT_DELTA_UNMODIFIED: /* should show delta as dirty / deleted */ if (checkout_notify(data, GIT_CHECKOUT_NOTIFY_DIRTY, delta, wd)) return GIT_EUSER; action = CHECKOUT_ACTION_IF(FORCE, REMOVE_AND_UPDATE, NONE); break; case GIT_DELTA_ADDED: case GIT_DELTA_MODIFIED: action = CHECKOUT_ACTION_IF(FORCE, REMOVE_AND_UPDATE, CONFLICT); break; case GIT_DELTA_DELETED: action = CHECKOUT_ACTION_IF(FORCE, REMOVE, CONFLICT); break; case GIT_DELTA_TYPECHANGE: /* not 100% certain about this... */ action = CHECKOUT_ACTION_IF(FORCE, REMOVE_AND_UPDATE, CONFLICT); break; default: /* impossible */ break; } return checkout_action_common(data, action, delta, wd); } static int checkout_action_with_wd_dir( checkout_data *data, const git_diff_delta *delta, const git_index_entry *wd) { int action = CHECKOUT_ACTION__NONE; switch (delta->status) { case GIT_DELTA_UNMODIFIED: /* case 19 or 24 (or 34 but not really) */ if (checkout_notify(data, GIT_CHECKOUT_NOTIFY_DIRTY, delta, NULL) || checkout_notify( data, GIT_CHECKOUT_NOTIFY_UNTRACKED, NULL, wd)) return GIT_EUSER; break; case GIT_DELTA_ADDED:/* case 4 (and 7 for dir) */ case GIT_DELTA_MODIFIED: /* case 20 (or 37 but not really) */ if (delta->old_file.mode == GIT_FILEMODE_COMMIT) /* expected submodule (and maybe found one) */; else if (delta->new_file.mode != GIT_FILEMODE_TREE) action = CHECKOUT_ACTION_IF(FORCE, REMOVE_AND_UPDATE, CONFLICT); break; case GIT_DELTA_DELETED: /* case 11 (and 27 for dir) */ if (delta->old_file.mode != GIT_FILEMODE_TREE && checkout_notify( data, GIT_CHECKOUT_NOTIFY_UNTRACKED, NULL, wd)) return GIT_EUSER; break; case GIT_DELTA_TYPECHANGE: /* case 24 or 31 */ if (delta->old_file.mode == GIT_FILEMODE_TREE) { /* For typechange from dir, remove dir and add blob, but it is * not safe to remove dir if it contains modified files. * However, safely removing child files will remove the parent * directory if is it left empty, so we can defer removing the * dir and it will succeed if no children are left. */ action = CHECKOUT_ACTION_IF(SAFE, UPDATE_BLOB, NONE); if (action != CHECKOUT_ACTION__NONE) action |= CHECKOUT_ACTION__DEFER_REMOVE; } else if (delta->new_file.mode != GIT_FILEMODE_TREE) /* For typechange to dir, dir is already created so no action */ action = CHECKOUT_ACTION_IF(FORCE, REMOVE_AND_UPDATE, CONFLICT); break; default: /* impossible */ break; } return checkout_action_common(data, action, delta, wd); } static int checkout_action( checkout_data *data, git_diff_delta *delta, git_iterator *workdir, const git_index_entry **wditem_ptr, git_vector *pathspec) { const git_index_entry *wd = *wditem_ptr; int cmp = -1, act; int (*strcomp)(const char *, const char *) = data->diff->strcomp; int (*pfxcomp)(const char *str, const char *pfx) = data->diff->pfxcomp; int error; /* move workdir iterator to follow along with deltas */ while (1) { if (!wd) return checkout_action_no_wd(data, delta); cmp = strcomp(wd->path, delta->old_file.path); /* 1. wd before delta ("a/a" before "a/b") * 2. wd prefixes delta & should expand ("a/" before "a/b") * 3. wd prefixes delta & cannot expand ("a/b" before "a/b/c") * 4. wd equals delta ("a/b" and "a/b") * 5. wd after delta & delta prefixes wd ("a/b/c" after "a/b/" or "a/b") * 6. wd after delta ("a/c" after "a/b") */ if (cmp < 0) { cmp = pfxcomp(delta->old_file.path, wd->path); if (cmp == 0) { if (wd->mode == GIT_FILEMODE_TREE) { /* case 2 - entry prefixed by workdir tree */ error = git_iterator_advance_into_or_over(&wd, workdir); if (error && error != GIT_ITEROVER) goto fail; *wditem_ptr = wd; continue; } /* case 3 maybe - wd contains non-dir where dir expected */ if (delta->old_file.path[strlen(wd->path)] == '/') { act = checkout_action_with_wd_blocker(data, delta, wd); *wditem_ptr = git_iterator_advance(&wd, workdir) ? NULL : wd; return act; } } /* case 1 - handle wd item (if it matches pathspec) */ if (checkout_action_wd_only(data, workdir, wd, pathspec) < 0) goto fail; if ((error = git_iterator_advance(&wd, workdir)) < 0 && error != GIT_ITEROVER) goto fail; *wditem_ptr = wd; continue; } if (cmp == 0) { /* case 4 */ act = checkout_action_with_wd(data, delta, wd); *wditem_ptr = git_iterator_advance(&wd, workdir) ? NULL : wd; return act; } cmp = pfxcomp(wd->path, delta->old_file.path); if (cmp == 0) { /* case 5 */ if (wd->path[strlen(delta->old_file.path)] != '/') return checkout_action_no_wd(data, delta); if (delta->status == GIT_DELTA_TYPECHANGE) { if (delta->old_file.mode == GIT_FILEMODE_TREE) { act = checkout_action_with_wd(data, delta, wd); if ((error = git_iterator_advance_into(&wd, workdir)) < 0 && error != GIT_ENOTFOUND) goto fail; *wditem_ptr = wd; return act; } if (delta->new_file.mode == GIT_FILEMODE_TREE || delta->new_file.mode == GIT_FILEMODE_COMMIT || delta->old_file.mode == GIT_FILEMODE_COMMIT) { act = checkout_action_with_wd(data, delta, wd); if ((error = git_iterator_advance(&wd, workdir)) < 0 && error != GIT_ITEROVER) goto fail; *wditem_ptr = wd; return act; } } return checkout_action_with_wd_dir(data, delta, wd); } /* case 6 - wd is after delta */ return checkout_action_no_wd(data, delta); } fail: *wditem_ptr = NULL; return -1; } static int checkout_remaining_wd_items( checkout_data *data, git_iterator *workdir, const git_index_entry *wd, git_vector *spec) { int error = 0; while (wd && !error) { if (!(error = checkout_action_wd_only(data, workdir, wd, spec))) error = git_iterator_advance(&wd, workdir); } if (error == GIT_ITEROVER) error = 0; return error; } static int checkout_get_actions( uint32_t **actions_ptr, size_t **counts_ptr, checkout_data *data, git_iterator *workdir) { int error = 0; const git_index_entry *wditem; git_vector pathspec = GIT_VECTOR_INIT, *deltas; git_pool pathpool = GIT_POOL_INIT_STRINGPOOL; git_diff_delta *delta; size_t i, *counts = NULL; uint32_t *actions = NULL; if (data->opts.paths.count > 0 && git_pathspec_init(&pathspec, &data->opts.paths, &pathpool) < 0) return -1; if ((error = git_iterator_current(&wditem, workdir)) < 0 && error != GIT_ITEROVER) goto fail; deltas = &data->diff->deltas; *counts_ptr = counts = git__calloc(CHECKOUT_ACTION__MAX+1, sizeof(size_t)); *actions_ptr = actions = git__calloc( deltas->length ? deltas->length : 1, sizeof(uint32_t)); if (!counts || !actions) { error = -1; goto fail; } git_vector_foreach(deltas, i, delta) { int act = checkout_action(data, delta, workdir, &wditem, &pathspec); if (act < 0) { error = act; goto fail; } actions[i] = act; if (act & CHECKOUT_ACTION__REMOVE) counts[CHECKOUT_ACTION__REMOVE]++; if (act & CHECKOUT_ACTION__UPDATE_BLOB) counts[CHECKOUT_ACTION__UPDATE_BLOB]++; if (act & CHECKOUT_ACTION__UPDATE_SUBMODULE) counts[CHECKOUT_ACTION__UPDATE_SUBMODULE]++; if (act & CHECKOUT_ACTION__CONFLICT) counts[CHECKOUT_ACTION__CONFLICT]++; } error = checkout_remaining_wd_items(data, workdir, wditem, &pathspec); if (error < 0) goto fail; counts[CHECKOUT_ACTION__REMOVE] += data->removes.length; if (counts[CHECKOUT_ACTION__CONFLICT] > 0 && (data->strategy & GIT_CHECKOUT_ALLOW_CONFLICTS) == 0) { giterr_set(GITERR_CHECKOUT, "%d conflicts prevent checkout", (int)counts[CHECKOUT_ACTION__CONFLICT]); error = GIT_EMERGECONFLICT; goto fail; } git_pathspec_free(&pathspec); git_pool_clear(&pathpool); return 0; fail: *counts_ptr = NULL; git__free(counts); *actions_ptr = NULL; git__free(actions); git_pathspec_free(&pathspec); git_pool_clear(&pathpool); return error; } static int buffer_to_file( struct stat *st, git_buf *buffer, const char *path, mode_t dir_mode, int file_open_flags, mode_t file_mode) { int error; if ((error = git_futils_mkpath2file(path, dir_mode)) < 0) return error; if ((error = git_futils_writebuffer( buffer, path, file_open_flags, file_mode)) < 0) return error; if (st != NULL && (error = p_stat(path, st)) < 0) { giterr_set(GITERR_OS, "Error while statting '%s'", path); return error; } if ((file_mode & 0100) != 0 && (error = p_chmod(path, file_mode)) < 0) { giterr_set(GITERR_OS, "Failed to set permissions on '%s'", path); return error; } return 0; } static int blob_content_to_file( struct stat *st, git_blob *blob, const char *path, mode_t entry_filemode, git_checkout_opts *opts) { int error = -1, nb_filters = 0; mode_t file_mode = opts->file_mode; bool dont_free_filtered; git_buf unfiltered = GIT_BUF_INIT, filtered = GIT_BUF_INIT; git_vector filters = GIT_VECTOR_INIT; /* Create a fake git_buf from the blob raw data... */ filtered.ptr = (void *)git_blob_rawcontent(blob); filtered.size = (size_t)git_blob_rawsize(blob); /* ... and make sure it doesn't get unexpectedly freed */ dont_free_filtered = true; if (!opts->disable_filters && !git_buf_text_is_binary(&filtered) && (nb_filters = git_filters_load( &filters, git_object_owner((git_object *)blob), path, GIT_FILTER_TO_WORKTREE)) > 0) { /* reset 'filtered' so it can be a filter target */ git_buf_init(&filtered, 0); dont_free_filtered = false; } if (nb_filters < 0) return nb_filters; if (nb_filters > 0) { if ((error = git_blob__getbuf(&unfiltered, blob)) < 0) goto cleanup; if ((error = git_filters_apply(&filtered, &unfiltered, &filters)) < 0) goto cleanup; } /* Allow overriding of file mode */ if (!file_mode) file_mode = entry_filemode; error = buffer_to_file( st, &filtered, path, opts->dir_mode, opts->file_open_flags, file_mode); if (!error) st->st_mode = entry_filemode; cleanup: git_filters_free(&filters); git_buf_free(&unfiltered); if (!dont_free_filtered) git_buf_free(&filtered); return error; } static int blob_content_to_link( struct stat *st, git_blob *blob, const char *path, mode_t dir_mode, int can_symlink) { git_buf linktarget = GIT_BUF_INIT; int error; if ((error = git_futils_mkpath2file(path, dir_mode)) < 0) return error; if ((error = git_blob__getbuf(&linktarget, blob)) < 0) return error; if (can_symlink) { if ((error = p_symlink(git_buf_cstr(&linktarget), path)) < 0) giterr_set(GITERR_OS, "Could not create symlink %s\n", path); } else { error = git_futils_fake_symlink(git_buf_cstr(&linktarget), path); } if (!error) { if ((error = p_lstat(path, st)) < 0) giterr_set(GITERR_CHECKOUT, "Could not stat symlink %s", path); st->st_mode = GIT_FILEMODE_LINK; } git_buf_free(&linktarget); return error; } static int checkout_update_index( checkout_data *data, const git_diff_file *file, struct stat *st) { git_index_entry entry; if (!data->index) return 0; memset(&entry, 0, sizeof(entry)); entry.path = (char *)file->path; /* cast to prevent warning */ git_index_entry__init_from_stat(&entry, st); git_oid_cpy(&entry.oid, &file->oid); return git_index_add(data->index, &entry); } static int checkout_submodule_update_index( checkout_data *data, const git_diff_file *file) { struct stat st; /* update the index unless prevented */ if ((data->strategy & GIT_CHECKOUT_DONT_UPDATE_INDEX) != 0) return 0; git_buf_truncate(&data->path, data->workdir_len); if (git_buf_puts(&data->path, file->path) < 0) return -1; if (p_stat(git_buf_cstr(&data->path), &st) < 0) { giterr_set( GITERR_CHECKOUT, "Could not stat submodule %s\n", file->path); return GIT_ENOTFOUND; } st.st_mode = GIT_FILEMODE_COMMIT; return checkout_update_index(data, file, &st); } static int checkout_submodule( checkout_data *data, const git_diff_file *file) { int error = 0; git_submodule *sm; /* Until submodules are supported, UPDATE_ONLY means do nothing here */ if ((data->strategy & GIT_CHECKOUT_UPDATE_ONLY) != 0) return 0; if ((error = git_futils_mkdir( file->path, data->opts.target_directory, data->opts.dir_mode, GIT_MKDIR_PATH)) < 0) return error; if ((error = git_submodule_lookup(&sm, data->repo, file->path)) < 0) { /* I've observed repos with submodules in the tree that do not * have a .gitmodules - core Git just makes an empty directory */ if (error == GIT_ENOTFOUND) { giterr_clear(); return checkout_submodule_update_index(data, file); } return error; } /* TODO: Support checkout_strategy options. Two circumstances: * 1 - submodule already checked out, but we need to move the HEAD * to the new OID, or * 2 - submodule not checked out and we should recursively check it out * * Checkout will not execute a pull on the submodule, but a clone * command should probably be able to. Do we need a submodule callback? */ return checkout_submodule_update_index(data, file); } static void report_progress( checkout_data *data, const char *path) { if (data->opts.progress_cb) data->opts.progress_cb( path, data->completed_steps, data->total_steps, data->opts.progress_payload); } static int checkout_safe_for_update_only(const char *path, mode_t expected_mode) { struct stat st; if (p_lstat(path, &st) < 0) { /* if doesn't exist, then no error and no update */ if (errno == ENOENT || errno == ENOTDIR) return 0; /* otherwise, stat error and no update */ giterr_set(GITERR_OS, "Failed to stat file '%s'", path); return -1; } /* only safe for update if this is the same type of file */ if ((st.st_mode & ~0777) == (expected_mode & ~0777)) return 1; return 0; } static int checkout_blob( checkout_data *data, const git_diff_file *file) { int error = 0; git_blob *blob; struct stat st; git_buf_truncate(&data->path, data->workdir_len); if (git_buf_puts(&data->path, file->path) < 0) return -1; if ((data->strategy & GIT_CHECKOUT_UPDATE_ONLY) != 0) { int rval = checkout_safe_for_update_only( git_buf_cstr(&data->path), file->mode); if (rval <= 0) return rval; } if ((error = git_blob_lookup(&blob, data->repo, &file->oid)) < 0) return error; if (S_ISLNK(file->mode)) error = blob_content_to_link( &st, blob, git_buf_cstr(&data->path), data->opts.dir_mode, data->can_symlink); else error = blob_content_to_file( &st, blob, git_buf_cstr(&data->path), file->mode, &data->opts); git_blob_free(blob); /* if we try to create the blob and an existing directory blocks it from * being written, then there must have been a typechange conflict in a * parent directory - suppress the error and try to continue. */ if ((data->strategy & GIT_CHECKOUT_ALLOW_CONFLICTS) != 0 && (error == GIT_ENOTFOUND || error == GIT_EEXISTS)) { giterr_clear(); error = 0; } /* update the index unless prevented */ if (!error && (data->strategy & GIT_CHECKOUT_DONT_UPDATE_INDEX) == 0) error = checkout_update_index(data, file, &st); /* update the submodule data if this was a new .gitmodules file */ if (!error && strcmp(file->path, ".gitmodules") == 0) data->reload_submodules = true; return error; } static int checkout_remove_the_old( unsigned int *actions, checkout_data *data) { int error = 0; git_diff_delta *delta; const char *str; size_t i; const char *workdir = git_buf_cstr(&data->path); uint32_t flg = GIT_RMDIR_EMPTY_PARENTS | GIT_RMDIR_REMOVE_FILES | GIT_RMDIR_REMOVE_BLOCKERS; if (data->opts.checkout_strategy & GIT_CHECKOUT_SKIP_LOCKED_DIRECTORIES) flg |= GIT_RMDIR_SKIP_NONEMPTY; git_buf_truncate(&data->path, data->workdir_len); git_vector_foreach(&data->diff->deltas, i, delta) { if (actions[i] & CHECKOUT_ACTION__REMOVE) { error = git_futils_rmdir_r(delta->old_file.path, workdir, flg); if (error < 0) return error; data->completed_steps++; report_progress(data, delta->old_file.path); if ((actions[i] & CHECKOUT_ACTION__UPDATE_BLOB) == 0 && (data->strategy & GIT_CHECKOUT_DONT_UPDATE_INDEX) == 0 && data->index != NULL) { (void)git_index_remove(data->index, delta->old_file.path, 0); } } } git_vector_foreach(&data->removes, i, str) { error = git_futils_rmdir_r(str, workdir, flg); if (error < 0) return error; data->completed_steps++; report_progress(data, str); if ((data->strategy & GIT_CHECKOUT_DONT_UPDATE_INDEX) == 0 && data->index != NULL) { if (str[strlen(str) - 1] == '/') (void)git_index_remove_directory(data->index, str, 0); else (void)git_index_remove(data->index, str, 0); } } return 0; } static int checkout_deferred_remove(git_repository *repo, const char *path) { #if 0 int error = git_futils_rmdir_r( path, data->opts.target_directory, GIT_RMDIR_EMPTY_PARENTS); if (error == GIT_ENOTFOUND) { error = 0; giterr_clear(); } return error; #else GIT_UNUSED(repo); GIT_UNUSED(path); assert(false); return 0; #endif } static int checkout_create_the_new( unsigned int *actions, checkout_data *data) { int error = 0; git_diff_delta *delta; size_t i; git_vector_foreach(&data->diff->deltas, i, delta) { if (actions[i] & CHECKOUT_ACTION__DEFER_REMOVE) { /* this had a blocker directory that should only be removed iff * all of the contents of the directory were safely removed */ if ((error = checkout_deferred_remove( data->repo, delta->old_file.path)) < 0) return error; } if (actions[i] & CHECKOUT_ACTION__UPDATE_BLOB) { error = checkout_blob(data, &delta->new_file); if (error < 0) return error; data->completed_steps++; report_progress(data, delta->new_file.path); } } return 0; } static int checkout_create_submodules( unsigned int *actions, checkout_data *data) { int error = 0; git_diff_delta *delta; size_t i; /* initial reload of submodules if .gitmodules was changed */ if (data->reload_submodules && (error = git_submodule_reload_all(data->repo)) < 0) return error; git_vector_foreach(&data->diff->deltas, i, delta) { if (actions[i] & CHECKOUT_ACTION__DEFER_REMOVE) { /* this has a blocker directory that should only be removed iff * all of the contents of the directory were safely removed */ if ((error = checkout_deferred_remove( data->repo, delta->old_file.path)) < 0) return error; } if (actions[i] & CHECKOUT_ACTION__UPDATE_SUBMODULE) { int error = checkout_submodule(data, &delta->new_file); if (error < 0) return error; data->completed_steps++; report_progress(data, delta->new_file.path); } } /* final reload once submodules have been updated */ return git_submodule_reload_all(data->repo); } static int checkout_lookup_head_tree(git_tree **out, git_repository *repo) { int error = 0; git_reference *ref = NULL; git_object *head; if (!(error = git_repository_head(&ref, repo)) && !(error = git_reference_peel(&head, ref, GIT_OBJ_TREE))) *out = (git_tree *)head; git_reference_free(ref); return error; } static void checkout_data_clear(checkout_data *data) { if (data->opts_free_baseline) { git_tree_free(data->opts.baseline); data->opts.baseline = NULL; } git_vector_free(&data->removes); git_pool_clear(&data->pool); git__free(data->pfx); data->pfx = NULL; git_buf_free(&data->path); git_index_free(data->index); data->index = NULL; } static int checkout_data_init( checkout_data *data, git_iterator *target, git_checkout_opts *proposed) { int error = 0; git_repository *repo = git_iterator_owner(target); memset(data, 0, sizeof(*data)); if (!repo) { giterr_set(GITERR_CHECKOUT, "Cannot checkout nothing"); return -1; } if ((!proposed || !proposed->target_directory) && (error = git_repository__ensure_not_bare(repo, "checkout")) < 0) return error; data->repo = repo; GITERR_CHECK_VERSION( proposed, GIT_CHECKOUT_OPTS_VERSION, "git_checkout_opts"); if (!proposed) GIT_INIT_STRUCTURE(&data->opts, GIT_CHECKOUT_OPTS_VERSION); else memmove(&data->opts, proposed, sizeof(git_checkout_opts)); if (!data->opts.target_directory) data->opts.target_directory = git_repository_workdir(repo); else if (!git_path_isdir(data->opts.target_directory) && (error = git_futils_mkdir(data->opts.target_directory, NULL, GIT_DIR_MODE, GIT_MKDIR_VERIFY_DIR)) < 0) goto cleanup; /* refresh config and index content unless NO_REFRESH is given */ if ((data->opts.checkout_strategy & GIT_CHECKOUT_NO_REFRESH) == 0) { git_config *cfg; if ((error = git_repository_config__weakptr(&cfg, repo)) < 0 || (error = git_config_refresh(cfg)) < 0) goto cleanup; /* if we are checking out the index, don't reload, * otherwise get index and force reload */ if ((data->index = git_iterator_get_index(target)) != NULL) { GIT_REFCOUNT_INC(data->index); } else { /* otherwise, grab and reload the index */ if ((error = git_repository_index(&data->index, data->repo)) < 0 || (error = git_index_read(data->index)) < 0) goto cleanup; /* clear the REUC when doing a tree or commit checkout */ git_index_reuc_clear(data->index); } } /* if you are forcing, definitely allow safe updates */ if ((data->opts.checkout_strategy & GIT_CHECKOUT_FORCE) != 0) data->opts.checkout_strategy |= GIT_CHECKOUT_SAFE_CREATE; if ((data->opts.checkout_strategy & GIT_CHECKOUT_SAFE_CREATE) != 0) data->opts.checkout_strategy |= GIT_CHECKOUT_SAFE; data->strategy = data->opts.checkout_strategy; /* opts->disable_filters is false by default */ if (!data->opts.dir_mode) data->opts.dir_mode = GIT_DIR_MODE; if (!data->opts.file_open_flags) data->opts.file_open_flags = O_CREAT | O_TRUNC | O_WRONLY; data->pfx = git_pathspec_prefix(&data->opts.paths); if ((error = git_repository__cvar( &data->can_symlink, repo, GIT_CVAR_SYMLINKS)) < 0) goto cleanup; if (!data->opts.baseline) { data->opts_free_baseline = true; error = checkout_lookup_head_tree(&data->opts.baseline, repo); if (error == GIT_EORPHANEDHEAD) { error = 0; giterr_clear(); } if (error < 0) goto cleanup; } if ((error = git_vector_init(&data->removes, 0, git__strcmp_cb)) < 0 || (error = git_pool_init(&data->pool, 1, 0)) < 0 || (error = git_buf_puts(&data->path, data->opts.target_directory)) < 0 || (error = git_path_to_dir(&data->path)) < 0) goto cleanup; data->workdir_len = git_buf_len(&data->path); cleanup: if (error < 0) checkout_data_clear(data); return error; } int git_checkout_iterator( git_iterator *target, git_checkout_opts *opts) { int error = 0; git_iterator *baseline = NULL, *workdir = NULL; checkout_data data = {0}; git_diff_options diff_opts = GIT_DIFF_OPTIONS_INIT; uint32_t *actions = NULL; size_t *counts = NULL; git_iterator_flag_t iterflags = 0; /* initialize structures and options */ error = checkout_data_init(&data, target, opts); if (error < 0) return error; diff_opts.flags = GIT_DIFF_INCLUDE_UNMODIFIED | GIT_DIFF_INCLUDE_UNTRACKED | GIT_DIFF_RECURSE_UNTRACKED_DIRS | /* needed to match baseline */ GIT_DIFF_INCLUDE_IGNORED | GIT_DIFF_INCLUDE_TYPECHANGE | GIT_DIFF_INCLUDE_TYPECHANGE_TREES | GIT_DIFF_SKIP_BINARY_CHECK; if (data.opts.checkout_strategy & GIT_CHECKOUT_DISABLE_PATHSPEC_MATCH) diff_opts.flags |= GIT_DIFF_DISABLE_PATHSPEC_MATCH; if (data.opts.paths.count > 0) diff_opts.pathspec = data.opts.paths; /* set up iterators */ iterflags = git_iterator_ignore_case(target) ? GIT_ITERATOR_IGNORE_CASE : GIT_ITERATOR_DONT_IGNORE_CASE; if ((error = git_iterator_reset(target, data.pfx, data.pfx)) < 0 || (error = git_iterator_for_workdir_ext( &workdir, data.repo, data.opts.target_directory, iterflags | GIT_ITERATOR_DONT_AUTOEXPAND, data.pfx, data.pfx)) < 0 || (error = git_iterator_for_tree( &baseline, data.opts.baseline, iterflags, data.pfx, data.pfx)) < 0) goto cleanup; /* Should not have case insensitivity mismatch */ assert(git_iterator_ignore_case(workdir) == git_iterator_ignore_case(baseline)); /* Generate baseline-to-target diff which will include an entry for * every possible update that might need to be made. */ if ((error = git_diff__from_iterators( &data.diff, data.repo, baseline, target, &diff_opts)) < 0) goto cleanup; /* Loop through diff (and working directory iterator) building a list of * actions to be taken, plus look for conflicts and send notifications. */ if ((error = checkout_get_actions(&actions, &counts, &data, workdir)) < 0) goto cleanup; data.total_steps = counts[CHECKOUT_ACTION__REMOVE] + counts[CHECKOUT_ACTION__UPDATE_BLOB] + counts[CHECKOUT_ACTION__UPDATE_SUBMODULE]; report_progress(&data, NULL); /* establish 0 baseline */ /* To deal with some order dependencies, perform remaining checkout * in three passes: removes, then update blobs, then update submodules. */ if (counts[CHECKOUT_ACTION__REMOVE] > 0 && (error = checkout_remove_the_old(actions, &data)) < 0) goto cleanup; if (counts[CHECKOUT_ACTION__UPDATE_BLOB] > 0 && (error = checkout_create_the_new(actions, &data)) < 0) goto cleanup; if (counts[CHECKOUT_ACTION__UPDATE_SUBMODULE] > 0 && (error = checkout_create_submodules(actions, &data)) < 0) goto cleanup; assert(data.completed_steps == data.total_steps); cleanup: if (error == GIT_EUSER) giterr_clear(); if (!error && data.index != NULL && (data.strategy & GIT_CHECKOUT_DONT_UPDATE_INDEX) == 0) error = git_index_write(data.index); git_diff_list_free(data.diff); git_iterator_free(workdir); git_iterator_free(baseline); git__free(actions); git__free(counts); checkout_data_clear(&data); return error; } int git_checkout_index( git_repository *repo, git_index *index, git_checkout_opts *opts) { int error; git_iterator *index_i; if (!index && !repo) { giterr_set(GITERR_CHECKOUT, "Must provide either repository or index to checkout"); return -1; } if (index && repo && git_index_owner(index) != repo) { giterr_set(GITERR_CHECKOUT, "Index to checkout does not match repository"); return -1; } if (!repo) repo = git_index_owner(index); if (!index && (error = git_repository_index__weakptr(&index, repo)) < 0) return error; GIT_REFCOUNT_INC(index); if (!(error = git_iterator_for_index(&index_i, index, 0, NULL, NULL))) error = git_checkout_iterator(index_i, opts); git_iterator_free(index_i); git_index_free(index); return error; } int git_checkout_tree( git_repository *repo, const git_object *treeish, git_checkout_opts *opts) { int error; git_tree *tree = NULL; git_iterator *tree_i = NULL; if (!treeish && !repo) { giterr_set(GITERR_CHECKOUT, "Must provide either repository or tree to checkout"); return -1; } if (treeish && repo && git_object_owner(treeish) != repo) { giterr_set(GITERR_CHECKOUT, "Object to checkout does not match repository"); return -1; } if (!repo) repo = git_object_owner(treeish); if (git_object_peel((git_object **)&tree, treeish, GIT_OBJ_TREE) < 0) { giterr_set( GITERR_CHECKOUT, "Provided object cannot be peeled to a tree"); return -1; } if (!(error = git_iterator_for_tree(&tree_i, tree, 0, NULL, NULL))) error = git_checkout_iterator(tree_i, opts); git_iterator_free(tree_i); git_tree_free(tree); return error; } int git_checkout_head( git_repository *repo, git_checkout_opts *opts) { int error; git_tree *head = NULL; git_iterator *head_i = NULL; assert(repo); if (!(error = checkout_lookup_head_tree(&head, repo)) && !(error = git_iterator_for_tree(&head_i, head, 0, NULL, NULL))) error = git_checkout_iterator(head_i, opts); git_iterator_free(head_i); git_tree_free(head); return error; } libgit2-0.19.0/src/checkout.h000066400000000000000000000012231216214232500156760ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #ifndef INCLUDE_checkout_h__ #define INCLUDE_checkout_h__ #include "git2/checkout.h" #include "iterator.h" #define GIT_CHECKOUT__NOTIFY_CONFLICT_TREE (1u << 12) /** * Update the working directory to match the target iterator. The * expected baseline value can be passed in via the checkout options * or else will default to the HEAD commit. */ extern int git_checkout_iterator( git_iterator *target, git_checkout_opts *opts); #endif libgit2-0.19.0/src/clone.c000066400000000000000000000264351216214232500152000ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #include #include "git2/clone.h" #include "git2/remote.h" #include "git2/revparse.h" #include "git2/branch.h" #include "git2/config.h" #include "git2/checkout.h" #include "git2/commit.h" #include "git2/tree.h" #include "common.h" #include "remote.h" #include "fileops.h" #include "refs.h" #include "path.h" #include "repository.h" static int create_branch( git_reference **branch, git_repository *repo, const git_oid *target, const char *name) { git_commit *head_obj = NULL; git_reference *branch_ref = NULL; int error; /* Find the target commit */ if ((error = git_commit_lookup(&head_obj, repo, target)) < 0) return error; /* Create the new branch */ error = git_branch_create(&branch_ref, repo, name, head_obj, 0); git_commit_free(head_obj); if (!error) *branch = branch_ref; else git_reference_free(branch_ref); return error; } static int setup_tracking_config( git_repository *repo, const char *branch_name, const char *remote_name, const char *merge_target) { git_config *cfg; git_buf remote_key = GIT_BUF_INIT, merge_key = GIT_BUF_INIT; int error = -1; if (git_repository_config__weakptr(&cfg, repo) < 0) return -1; if (git_buf_printf(&remote_key, "branch.%s.remote", branch_name) < 0) goto cleanup; if (git_buf_printf(&merge_key, "branch.%s.merge", branch_name) < 0) goto cleanup; if (git_config_set_string(cfg, git_buf_cstr(&remote_key), remote_name) < 0) goto cleanup; if (git_config_set_string(cfg, git_buf_cstr(&merge_key), merge_target) < 0) goto cleanup; error = 0; cleanup: git_buf_free(&remote_key); git_buf_free(&merge_key); return error; } static int create_tracking_branch( git_reference **branch, git_repository *repo, const git_oid *target, const char *branch_name) { int error; if ((error = create_branch(branch, repo, target, branch_name)) < 0) return error; return setup_tracking_config( repo, branch_name, GIT_REMOTE_ORIGIN, git_reference_name(*branch)); } struct head_info { git_repository *repo; git_oid remote_head_oid; git_buf branchname; const git_refspec *refspec; bool found; }; static int reference_matches_remote_head( const char *reference_name, void *payload) { struct head_info *head_info = (struct head_info *)payload; git_oid oid; /* TODO: Should we guard against references * which name doesn't start with refs/heads/ ? */ /* Stop looking if we've already found a match */ if (head_info->found) return 0; if (git_reference_name_to_id( &oid, head_info->repo, reference_name) < 0) { /* If the reference doesn't exists, it obviously cannot match the expected oid. */ giterr_clear(); return 0; } if (git_oid__cmp(&head_info->remote_head_oid, &oid) == 0) { /* Determine the local reference name from the remote tracking one */ if (git_refspec_transform_l( &head_info->branchname, head_info->refspec, reference_name) < 0) return -1; if (git_buf_len(&head_info->branchname) > 0) { if (git_buf_sets( &head_info->branchname, git_buf_cstr(&head_info->branchname) + strlen(GIT_REFS_HEADS_DIR)) < 0) return -1; head_info->found = 1; } } return 0; } static int update_head_to_new_branch( git_repository *repo, const git_oid *target, const char *name) { git_reference *tracking_branch = NULL; int error; if ((error = create_tracking_branch( &tracking_branch, repo, target, name)) < 0) return error; error = git_repository_set_head(repo, git_reference_name(tracking_branch)); git_reference_free(tracking_branch); return error; } static int get_head_callback(git_remote_head *head, void *payload) { git_remote_head **destination = (git_remote_head **)payload; /* Save the first entry, and terminate the enumeration */ *destination = head; return 1; } static int update_head_to_remote(git_repository *repo, git_remote *remote) { int retcode = -1; git_refspec dummy_spec; git_remote_head *remote_head; struct head_info head_info; git_buf remote_master_name = GIT_BUF_INIT; /* Did we just clone an empty repository? */ if (remote->refs.length == 0) { return setup_tracking_config( repo, "master", GIT_REMOTE_ORIGIN, GIT_REFS_HEADS_MASTER_FILE); } /* Get the remote's HEAD. This is always the first ref in remote->refs. */ remote_head = NULL; if (!remote->transport->ls(remote->transport, get_head_callback, &remote_head)) return -1; assert(remote_head); git_oid_cpy(&head_info.remote_head_oid, &remote_head->oid); git_buf_init(&head_info.branchname, 16); head_info.repo = repo; head_info.refspec = git_remote__matching_refspec(remote, GIT_REFS_HEADS_MASTER_FILE); head_info.found = 0; if (head_info.refspec == NULL) { memset(&dummy_spec, 0, sizeof(git_refspec)); head_info.refspec = &dummy_spec; } /* Determine the remote tracking reference name from the local master */ if (git_refspec_transform_r( &remote_master_name, head_info.refspec, GIT_REFS_HEADS_MASTER_FILE) < 0) return -1; /* Check to see if the remote HEAD points to the remote master */ if (reference_matches_remote_head(git_buf_cstr(&remote_master_name), &head_info) < 0) goto cleanup; if (head_info.found) { retcode = update_head_to_new_branch( repo, &head_info.remote_head_oid, git_buf_cstr(&head_info.branchname)); goto cleanup; } /* Not master. Check all the other refs. */ if (git_reference_foreach_name( repo, reference_matches_remote_head, &head_info) < 0) goto cleanup; if (head_info.found) { retcode = update_head_to_new_branch( repo, &head_info.remote_head_oid, git_buf_cstr(&head_info.branchname)); goto cleanup; } else { retcode = git_repository_set_head_detached( repo, &head_info.remote_head_oid); goto cleanup; } cleanup: git_buf_free(&remote_master_name); git_buf_free(&head_info.branchname); return retcode; } static int update_head_to_branch( git_repository *repo, const git_clone_options *options) { int retcode; git_buf remote_branch_name = GIT_BUF_INIT; git_reference* remote_ref = NULL; assert(options->checkout_branch); if ((retcode = git_buf_printf(&remote_branch_name, GIT_REFS_REMOTES_DIR "%s/%s", options->remote_name, options->checkout_branch)) < 0 ) goto cleanup; if ((retcode = git_reference_lookup(&remote_ref, repo, git_buf_cstr(&remote_branch_name))) < 0) goto cleanup; retcode = update_head_to_new_branch(repo, git_reference_target(remote_ref), options->checkout_branch); cleanup: git_reference_free(remote_ref); git_buf_free(&remote_branch_name); return retcode; } /* * submodules? */ static int create_and_configure_origin( git_remote **out, git_repository *repo, const char *url, const git_clone_options *options) { int error; git_remote *origin = NULL; if ((error = git_remote_create(&origin, repo, options->remote_name, url)) < 0) goto on_error; git_remote_set_cred_acquire_cb(origin, options->cred_acquire_cb, options->cred_acquire_payload); git_remote_set_autotag(origin, options->remote_autotag); /* * Don't write FETCH_HEAD, we'll check out the remote tracking * branch ourselves based on the server's default. */ git_remote_set_update_fetchhead(origin, 0); if (options->remote_callbacks && (error = git_remote_set_callbacks(origin, options->remote_callbacks)) < 0) goto on_error; if (options->fetch_spec) { git_remote_clear_refspecs(origin); if ((error = git_remote_add_fetch(origin, options->fetch_spec)) < 0) goto on_error; } if (options->push_spec && (error = git_remote_add_push(origin, options->push_spec)) < 0) goto on_error; if (options->pushurl && (error = git_remote_set_pushurl(origin, options->pushurl)) < 0) goto on_error; if (options->transport_flags == GIT_TRANSPORTFLAGS_NO_CHECK_CERT) { git_remote_check_cert(origin, 0); } if ((error = git_remote_save(origin)) < 0) goto on_error; *out = origin; return 0; on_error: git_remote_free(origin); return error; } static int setup_remotes_and_fetch( git_repository *repo, const char *url, const git_clone_options *options) { int retcode = GIT_ERROR; git_remote *origin = NULL; /* Construct an origin remote */ if ((retcode = create_and_configure_origin(&origin, repo, url, options)) < 0) goto on_error; git_remote_set_update_fetchhead(origin, 0); /* If the download_tags value has not been specified, then make sure to * download tags as well. It is set here because we want to download tags * on the initial clone, but do not want to persist the value in the * configuration file. */ if (origin->download_tags == GIT_REMOTE_DOWNLOAD_TAGS_AUTO && ((retcode = git_remote_add_fetch(origin, "refs/tags/*:refs/tags/*")) < 0)) goto on_error; /* Connect and download everything */ if ((retcode = git_remote_connect(origin, GIT_DIRECTION_FETCH)) < 0) goto on_error; if ((retcode = git_remote_download(origin, options->fetch_progress_cb, options->fetch_progress_payload)) < 0) goto on_error; /* Create "origin/foo" branches for all remote branches */ if ((retcode = git_remote_update_tips(origin)) < 0) goto on_error; /* Point HEAD to the requested branch */ if (options->checkout_branch) retcode = update_head_to_branch(repo, options); /* Point HEAD to the same ref as the remote's head */ else retcode = update_head_to_remote(repo, origin); on_error: git_remote_free(origin); return retcode; } static bool should_checkout( git_repository *repo, bool is_bare, git_checkout_opts *opts) { if (is_bare) return false; if (!opts) return false; if (opts->checkout_strategy == GIT_CHECKOUT_NONE) return false; return !git_repository_head_orphan(repo); } static void normalize_options(git_clone_options *dst, const git_clone_options *src) { git_clone_options default_options = GIT_CLONE_OPTIONS_INIT; if (!src) src = &default_options; *dst = *src; /* Provide defaults for null pointers */ if (!dst->remote_name) dst->remote_name = "origin"; } int git_clone( git_repository **out, const char *url, const char *local_path, const git_clone_options *options) { int retcode = GIT_ERROR; git_repository *repo = NULL; git_clone_options normOptions; int remove_directory_on_failure = 0; assert(out && url && local_path); normalize_options(&normOptions, options); GITERR_CHECK_VERSION(&normOptions, GIT_CLONE_OPTIONS_VERSION, "git_clone_options"); /* Only clone to a new directory or an empty directory */ if (git_path_exists(local_path) && !git_path_is_empty_dir(local_path)) { giterr_set(GITERR_INVALID, "'%s' exists and is not an empty directory", local_path); return GIT_ERROR; } /* Only remove the directory on failure if we create it */ remove_directory_on_failure = !git_path_exists(local_path); if (!(retcode = git_repository_init(&repo, local_path, normOptions.bare))) { if ((retcode = setup_remotes_and_fetch(repo, url, &normOptions)) < 0) { /* Failed to fetch; clean up */ git_repository_free(repo); if (remove_directory_on_failure) git_futils_rmdir_r(local_path, NULL, GIT_RMDIR_REMOVE_FILES); else git_futils_cleanupdir_r(local_path); } else { *out = repo; retcode = 0; } } if (!retcode && should_checkout(repo, normOptions.bare, &normOptions.checkout_opts)) retcode = git_checkout_head(*out, &normOptions.checkout_opts); return retcode; } libgit2-0.19.0/src/commit.c000066400000000000000000000172761216214232500153730ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #include "git2/common.h" #include "git2/object.h" #include "git2/repository.h" #include "git2/signature.h" #include "git2/sys/commit.h" #include "common.h" #include "odb.h" #include "commit.h" #include "signature.h" #include "message.h" #include static void clear_parents(git_commit *commit) { size_t i; for (i = 0; i < commit->parent_ids.length; ++i) { git_oid *parent = git_vector_get(&commit->parent_ids, i); git__free(parent); } git_vector_clear(&commit->parent_ids); } void git_commit__free(void *_commit) { git_commit *commit = _commit; clear_parents(commit); git_vector_free(&commit->parent_ids); git_signature_free(commit->author); git_signature_free(commit->committer); git__free(commit->message); git__free(commit->message_encoding); git__free(commit); } 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_encoding, const char *message, const git_tree *tree, int parent_count, ...) { va_list ap; int i, res; const git_commit **parents; parents = git__malloc(parent_count * sizeof(git_commit *)); GITERR_CHECK_ALLOC(parents); va_start(ap, parent_count); for (i = 0; i < parent_count; ++i) parents[i] = va_arg(ap, const git_commit *); va_end(ap); res = git_commit_create( oid, repo, update_ref, author, committer, message_encoding, message, tree, parent_count, parents); git__free((void *)parents); return res; } int git_commit_create_from_oids( git_oid *oid, git_repository *repo, const char *update_ref, const git_signature *author, const git_signature *committer, const char *message_encoding, const char *message, const git_oid *tree, int parent_count, const git_oid *parents[]) { git_buf commit = GIT_BUF_INIT; int i; git_odb *odb; assert(oid && repo && tree && parent_count >= 0); git_oid__writebuf(&commit, "tree ", tree); for (i = 0; i < parent_count; ++i) git_oid__writebuf(&commit, "parent ", parents[i]); git_signature__writebuf(&commit, "author ", author); git_signature__writebuf(&commit, "committer ", committer); if (message_encoding != NULL) git_buf_printf(&commit, "encoding %s\n", message_encoding); git_buf_putc(&commit, '\n'); if (git_buf_puts(&commit, message) < 0) goto on_error; if (git_repository_odb__weakptr(&odb, repo) < 0) goto on_error; if (git_odb_write(oid, odb, commit.ptr, commit.size, GIT_OBJ_COMMIT) < 0) goto on_error; git_buf_free(&commit); if (update_ref != NULL) return git_reference__update_terminal(repo, update_ref, oid); return 0; on_error: git_buf_free(&commit); giterr_set(GITERR_OBJECT, "Failed to create commit."); return -1; } 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_encoding, const char *message, const git_tree *tree, int parent_count, const git_commit *parents[]) { int retval, i; const git_oid **parent_oids; assert(parent_count >= 0); assert(git_object_owner((const git_object *)tree) == repo); parent_oids = git__malloc(parent_count * sizeof(git_oid *)); GITERR_CHECK_ALLOC(parent_oids); for (i = 0; i < parent_count; ++i) { assert(git_object_owner((const git_object *)parents[i]) == repo); parent_oids[i] = git_object_id((const git_object *)parents[i]); } retval = git_commit_create_from_oids( oid, repo, update_ref, author, committer, message_encoding, message, git_object_id((const git_object *)tree), parent_count, parent_oids); git__free((void *)parent_oids); return retval; } int git_commit__parse(void *_commit, git_odb_object *odb_obj) { git_commit *commit = _commit; const char *buffer = git_odb_object_data(odb_obj); const char *buffer_end = buffer + git_odb_object_size(odb_obj); git_oid parent_id; if (git_vector_init(&commit->parent_ids, 4, NULL) < 0) return -1; if (git_oid__parse(&commit->tree_id, &buffer, buffer_end, "tree ") < 0) goto bad_buffer; /* * TODO: commit grafts! */ while (git_oid__parse(&parent_id, &buffer, buffer_end, "parent ") == 0) { git_oid *new_id = git__malloc(sizeof(git_oid)); GITERR_CHECK_ALLOC(new_id); git_oid_cpy(new_id, &parent_id); if (git_vector_insert(&commit->parent_ids, new_id) < 0) return -1; } commit->author = git__malloc(sizeof(git_signature)); GITERR_CHECK_ALLOC(commit->author); if (git_signature__parse(commit->author, &buffer, buffer_end, "author ", '\n') < 0) return -1; /* Always parse the committer; we need the commit time */ commit->committer = git__malloc(sizeof(git_signature)); GITERR_CHECK_ALLOC(commit->committer); if (git_signature__parse(commit->committer, &buffer, buffer_end, "committer ", '\n') < 0) return -1; /* Parse add'l header entries until blank line found */ while (buffer < buffer_end && *buffer != '\n') { const char *eoln = buffer; while (eoln < buffer_end && *eoln != '\n') ++eoln; if (git__prefixcmp(buffer, "encoding ") == 0) { buffer += strlen("encoding "); commit->message_encoding = git__strndup(buffer, eoln - buffer); GITERR_CHECK_ALLOC(commit->message_encoding); } if (eoln < buffer_end && *eoln == '\n') ++eoln; buffer = eoln; } /* buffer is now at the end of the header, double-check and move forward into the message */ if (buffer < buffer_end && *buffer == '\n') buffer++; /* parse commit message */ if (buffer <= buffer_end) { commit->message = git__strndup(buffer, buffer_end - buffer); GITERR_CHECK_ALLOC(commit->message); } return 0; bad_buffer: giterr_set(GITERR_OBJECT, "Failed to parse bad commit object"); return -1; } #define GIT_COMMIT_GETTER(_rvalue, _name, _return) \ _rvalue git_commit_##_name(const git_commit *commit) \ {\ assert(commit); \ return _return; \ } GIT_COMMIT_GETTER(const git_signature *, author, commit->author) GIT_COMMIT_GETTER(const git_signature *, committer, commit->committer) GIT_COMMIT_GETTER(const char *, message, commit->message) GIT_COMMIT_GETTER(const char *, message_encoding, commit->message_encoding) GIT_COMMIT_GETTER(git_time_t, time, commit->committer->when.time) GIT_COMMIT_GETTER(int, time_offset, commit->committer->when.offset) GIT_COMMIT_GETTER(unsigned int, parentcount, (unsigned int)commit->parent_ids.length) GIT_COMMIT_GETTER(const git_oid *, tree_id, &commit->tree_id); int git_commit_tree(git_tree **tree_out, const git_commit *commit) { assert(commit); return git_tree_lookup(tree_out, commit->object.repo, &commit->tree_id); } const git_oid *git_commit_parent_id( const git_commit *commit, unsigned int n) { assert(commit); return git_vector_get(&commit->parent_ids, n); } int git_commit_parent( git_commit **parent, const git_commit *commit, unsigned int n) { const git_oid *parent_id; assert(commit); parent_id = git_commit_parent_id(commit, n); if (parent_id == NULL) { giterr_set(GITERR_INVALID, "Parent %u does not exist", n); return GIT_ENOTFOUND; } return git_commit_lookup(parent, commit->object.repo, parent_id); } int git_commit_nth_gen_ancestor( git_commit **ancestor, const git_commit *commit, unsigned int n) { git_commit *current, *parent = NULL; int error; assert(ancestor && commit); current = (git_commit *)commit; if (n == 0) return git_commit_lookup( ancestor, commit->object.repo, git_object_id((const git_object *)commit)); while (n--) { error = git_commit_parent(&parent, (git_commit *)current, 0); if (current != commit) git_commit_free(current); if (error < 0) return error; current = parent; } *ancestor = parent; return 0; } libgit2-0.19.0/src/commit.h000066400000000000000000000012251216214232500153630ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #ifndef INCLUDE_commit_h__ #define INCLUDE_commit_h__ #include "git2/commit.h" #include "tree.h" #include "repository.h" #include "vector.h" #include struct git_commit { git_object object; git_vector parent_ids; git_oid tree_id; git_signature *author; git_signature *committer; char *message_encoding; char *message; }; void git_commit__free(void *commit); int git_commit__parse(void *commit, git_odb_object *obj); #endif libgit2-0.19.0/src/commit_list.c000066400000000000000000000114711216214232500164150ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #include "commit_list.h" #include "common.h" #include "revwalk.h" #include "pool.h" #include "odb.h" int git_commit_list_time_cmp(void *a, void *b) { git_commit_list_node *commit_a = (git_commit_list_node *)a; git_commit_list_node *commit_b = (git_commit_list_node *)b; return (commit_a->time < commit_b->time); } git_commit_list *git_commit_list_insert(git_commit_list_node *item, git_commit_list **list_p) { git_commit_list *new_list = git__malloc(sizeof(git_commit_list)); if (new_list != NULL) { new_list->item = item; new_list->next = *list_p; } *list_p = new_list; return new_list; } git_commit_list *git_commit_list_insert_by_date(git_commit_list_node *item, git_commit_list **list_p) { git_commit_list **pp = list_p; git_commit_list *p; while ((p = *pp) != NULL) { if (git_commit_list_time_cmp(p->item, item) < 0) break; pp = &p->next; } return git_commit_list_insert(item, pp); } git_commit_list_node *git_commit_list_alloc_node(git_revwalk *walk) { return (git_commit_list_node *)git_pool_malloc(&walk->commit_pool, COMMIT_ALLOC); } static int commit_error(git_commit_list_node *commit, const char *msg) { char commit_oid[GIT_OID_HEXSZ + 1]; git_oid_fmt(commit_oid, &commit->oid); commit_oid[GIT_OID_HEXSZ] = '\0'; giterr_set(GITERR_ODB, "Failed to parse commit %s - %s", commit_oid, msg); return -1; } static git_commit_list_node **alloc_parents( git_revwalk *walk, git_commit_list_node *commit, size_t n_parents) { if (n_parents <= PARENTS_PER_COMMIT) return (git_commit_list_node **)((char *)commit + sizeof(git_commit_list_node)); return (git_commit_list_node **)git_pool_malloc( &walk->commit_pool, (uint32_t)(n_parents * sizeof(git_commit_list_node *))); } void git_commit_list_free(git_commit_list **list_p) { git_commit_list *list = *list_p; if (list == NULL) return; while (list) { git_commit_list *temp = list; list = temp->next; git__free(temp); } *list_p = NULL; } git_commit_list_node *git_commit_list_pop(git_commit_list **stack) { git_commit_list *top = *stack; git_commit_list_node *item = top ? top->item : NULL; if (top) { *stack = top->next; git__free(top); } return item; } static int commit_quick_parse( git_revwalk *walk, git_commit_list_node *commit, const uint8_t *buffer, size_t buffer_len) { const size_t parent_len = strlen("parent ") + GIT_OID_HEXSZ + 1; const uint8_t *buffer_end = buffer + buffer_len; const uint8_t *parents_start, *committer_start; int i, parents = 0; int commit_time; buffer += strlen("tree ") + GIT_OID_HEXSZ + 1; parents_start = buffer; while (buffer + parent_len < buffer_end && memcmp(buffer, "parent ", strlen("parent ")) == 0) { parents++; buffer += parent_len; } commit->parents = alloc_parents(walk, commit, parents); GITERR_CHECK_ALLOC(commit->parents); buffer = parents_start; for (i = 0; i < parents; ++i) { git_oid oid; if (git_oid_fromstr(&oid, (const char *)buffer + strlen("parent ")) < 0) return -1; commit->parents[i] = git_revwalk__commit_lookup(walk, &oid); if (commit->parents[i] == NULL) return -1; buffer += parent_len; } commit->out_degree = (unsigned short)parents; if ((committer_start = buffer = memchr(buffer, '\n', buffer_end - buffer)) == NULL) return commit_error(commit, "object is corrupted"); buffer++; if ((buffer = memchr(buffer, '\n', buffer_end - buffer)) == NULL) return commit_error(commit, "object is corrupted"); /* Skip trailing spaces */ while (buffer > committer_start && git__isspace(*buffer)) buffer--; /* Seek for the begining of the pack of digits */ while (buffer > committer_start && git__isdigit(*buffer)) buffer--; /* Skip potential timezone offset */ if ((buffer > committer_start) && (*buffer == '+' || *buffer == '-')) { buffer--; while (buffer > committer_start && git__isspace(*buffer)) buffer--; while (buffer > committer_start && git__isdigit(*buffer)) buffer--; } if ((buffer == committer_start) || (git__strtol32(&commit_time, (char *)(buffer + 1), NULL, 10) < 0)) return commit_error(commit, "cannot parse commit time"); commit->time = (time_t)commit_time; commit->parsed = 1; return 0; } int git_commit_list_parse(git_revwalk *walk, git_commit_list_node *commit) { git_odb_object *obj; int error; if (commit->parsed) return 0; if ((error = git_odb_read(&obj, walk->odb, &commit->oid)) < 0) return error; if (obj->cached.type != GIT_OBJ_COMMIT) { giterr_set(GITERR_INVALID, "Object is no commit object"); error = -1; } else error = commit_quick_parse( walk, commit, (const uint8_t *)git_odb_object_data(obj), git_odb_object_size(obj)); git_odb_object_free(obj); return error; } libgit2-0.19.0/src/commit_list.h000066400000000000000000000026641216214232500164260ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #ifndef INCLUDE_commit_list_h__ #define INCLUDE_commit_list_h__ #include "git2/oid.h" #define PARENT1 (1 << 0) #define PARENT2 (1 << 1) #define RESULT (1 << 2) #define STALE (1 << 3) #define PARENTS_PER_COMMIT 2 #define COMMIT_ALLOC \ (sizeof(git_commit_list_node) + PARENTS_PER_COMMIT * sizeof(git_commit_list_node *)) typedef struct git_commit_list_node { git_oid oid; uint32_t time; unsigned int seen:1, uninteresting:1, topo_delay:1, parsed:1, flags : 4; unsigned short in_degree; unsigned short out_degree; struct git_commit_list_node **parents; } git_commit_list_node; typedef struct git_commit_list { git_commit_list_node *item; struct git_commit_list *next; } git_commit_list; git_commit_list_node *git_commit_list_alloc_node(git_revwalk *walk); int git_commit_list_time_cmp(void *a, void *b); void git_commit_list_free(git_commit_list **list_p); git_commit_list *git_commit_list_insert(git_commit_list_node *item, git_commit_list **list_p); git_commit_list *git_commit_list_insert_by_date(git_commit_list_node *item, git_commit_list **list_p); int git_commit_list_parse(git_revwalk *walk, git_commit_list_node *commit); git_commit_list_node *git_commit_list_pop(git_commit_list **stack); #endif libgit2-0.19.0/src/common.h000066400000000000000000000047001216214232500153640ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #ifndef INCLUDE_common_h__ #define INCLUDE_common_h__ #include "git2/common.h" #include "cc-compat.h" #include #include #include #include #include #include #include #include #ifdef GIT_WIN32 # include # include # include # include # include "win32/msvc-compat.h" # include "win32/mingw-compat.h" # include "win32/error.h" # include "win32/version.h" # ifdef GIT_THREADS # include "win32/pthread.h" # endif #else # include # ifdef GIT_THREADS # include # endif #define GIT_STDLIB_CALL #endif #include "git2/types.h" #include "git2/errors.h" #include "thread-utils.h" #include "bswap.h" #include /** * Check a pointer allocation result, returning -1 if it failed. */ #define GITERR_CHECK_ALLOC(ptr) if (ptr == NULL) { return -1; } /** * Check a return value and propogate result if non-zero. */ #define GITERR_CHECK_ERROR(code) \ do { int _err = (code); if (_err < 0) return _err; } while (0) /** * Set the error message for this thread, formatting as needed. */ void giterr_set(int error_class, const char *string, ...); /** * Set the error message for a regex failure, using the internal regex * error code lookup and return a libgit error code. */ int giterr_set_regex(const regex_t *regex, int error_code); /** * Check a versioned structure for validity */ GIT_INLINE(int) giterr__check_version(const void *structure, unsigned int expected_max, const char *name) { unsigned int actual; if (!structure) return 0; actual = *(const unsigned int*)structure; if (actual > 0 && actual <= expected_max) return 0; giterr_set(GITERR_INVALID, "Invalid version %d on %s", actual, name); return -1; } #define GITERR_CHECK_VERSION(S,V,N) if (giterr__check_version(S,V,N) < 0) return -1 /** * Initialize a structure with a version. */ GIT_INLINE(void) git__init_structure(void *structure, size_t len, unsigned int version) { memset(structure, 0, len); *((int*)structure) = version; } #define GIT_INIT_STRUCTURE(S,V) git__init_structure(S, sizeof(*S), V) /* NOTE: other giterr functions are in the public errors.h header file */ #include "util.h" #endif /* INCLUDE_common_h__ */ libgit2-0.19.0/src/compress.c000066400000000000000000000017451216214232500157300ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #include "compress.h" #include #define BUFFER_SIZE (1024 * 1024) int git__compress(git_buf *buf, const void *buff, size_t len) { z_stream zs; char *zb; size_t have; memset(&zs, 0, sizeof(zs)); if (deflateInit(&zs, Z_DEFAULT_COMPRESSION) != Z_OK) return -1; zb = git__malloc(BUFFER_SIZE); GITERR_CHECK_ALLOC(zb); zs.next_in = (void *)buff; zs.avail_in = (uInt)len; do { zs.next_out = (unsigned char *)zb; zs.avail_out = BUFFER_SIZE; if (deflate(&zs, Z_FINISH) == Z_STREAM_ERROR) { git__free(zb); return -1; } have = BUFFER_SIZE - (size_t)zs.avail_out; if (git_buf_put(buf, zb, have) < 0) { git__free(zb); return -1; } } while (zs.avail_out == 0); assert(zs.avail_in == 0); deflateEnd(&zs); git__free(zb); return 0; } libgit2-0.19.0/src/compress.h000066400000000000000000000006361216214232500157330ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #ifndef INCLUDE_compress_h__ #define INCLUDE_compress_h__ #include "common.h" #include "buffer.h" int git__compress(git_buf *buf, const void *buff, size_t len); #endif /* INCLUDE_compress_h__ */ libgit2-0.19.0/src/config.c000066400000000000000000000440241216214232500153370ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #include "common.h" #include "fileops.h" #include "config.h" #include "git2/config.h" #include "git2/sys/config.h" #include "vector.h" #include "buf_text.h" #include "config_file.h" #if GIT_WIN32 # include #endif #include typedef struct { git_refcount rc; git_config_backend *file; git_config_level_t level; } file_internal; static void file_internal_free(file_internal *internal) { git_config_backend *file; file = internal->file; file->free(file); git__free(internal); } static void config_free(git_config *cfg) { size_t i; file_internal *internal; for (i = 0; i < cfg->files.length; ++i) { internal = git_vector_get(&cfg->files, i); GIT_REFCOUNT_DEC(internal, file_internal_free); } git_vector_free(&cfg->files); git__memzero(cfg, sizeof(*cfg)); git__free(cfg); } void git_config_free(git_config *cfg) { if (cfg == NULL) return; GIT_REFCOUNT_DEC(cfg, config_free); } static int config_backend_cmp(const void *a, const void *b) { const file_internal *bk_a = (const file_internal *)(a); const file_internal *bk_b = (const file_internal *)(b); return bk_b->level - bk_a->level; } int git_config_new(git_config **out) { git_config *cfg; cfg = git__malloc(sizeof(git_config)); GITERR_CHECK_ALLOC(cfg); memset(cfg, 0x0, sizeof(git_config)); if (git_vector_init(&cfg->files, 3, config_backend_cmp) < 0) { git__free(cfg); return -1; } *out = cfg; GIT_REFCOUNT_INC(cfg); return 0; } int git_config_add_file_ondisk( git_config *cfg, const char *path, git_config_level_t level, int force) { git_config_backend *file = NULL; struct stat st; int res; assert(cfg && path); res = p_stat(path, &st); if (res < 0 && errno != ENOENT) { giterr_set(GITERR_CONFIG, "Error stat'ing config file '%s'", path); return -1; } if (git_config_file__ondisk(&file, path) < 0) return -1; if ((res = git_config_add_backend(cfg, file, level, force)) < 0) { /* * free manually; the file is not owned by the config * instance yet and will not be freed on cleanup */ file->free(file); return res; } return 0; } int git_config_open_ondisk(git_config **out, const char *path) { int error; git_config *config; *out = NULL; if (git_config_new(&config) < 0) return -1; if ((error = git_config_add_file_ondisk(config, path, GIT_CONFIG_LEVEL_LOCAL, 0)) < 0) git_config_free(config); else *out = config; return error; } static int find_internal_file_by_level( file_internal **internal_out, const git_config *cfg, git_config_level_t level) { int pos = -1; file_internal *internal; size_t i; /* when passing GIT_CONFIG_HIGHEST_LEVEL, the idea is to get the config file * which has the highest level. As config files are stored in a vector * sorted by decreasing order of level, getting the file at position 0 * will do the job. */ if (level == GIT_CONFIG_HIGHEST_LEVEL) { pos = 0; } else { git_vector_foreach(&cfg->files, i, internal) { if (internal->level == level) pos = (int)i; } } if (pos == -1) { giterr_set(GITERR_CONFIG, "No config file exists for the given level '%i'", (int)level); return GIT_ENOTFOUND; } *internal_out = git_vector_get(&cfg->files, pos); return 0; } static int duplicate_level(void **old_raw, void *new_raw) { file_internal **old = (file_internal **)old_raw; GIT_UNUSED(new_raw); giterr_set(GITERR_CONFIG, "A file with the same level (%i) has already been added to the config", (int)(*old)->level); return GIT_EEXISTS; } static void try_remove_existing_file_internal( git_config *cfg, git_config_level_t level) { int pos = -1; file_internal *internal; size_t i; git_vector_foreach(&cfg->files, i, internal) { if (internal->level == level) pos = (int)i; } if (pos == -1) return; internal = git_vector_get(&cfg->files, pos); if (git_vector_remove(&cfg->files, pos) < 0) return; GIT_REFCOUNT_DEC(internal, file_internal_free); } static int git_config__add_internal( git_config *cfg, file_internal *internal, git_config_level_t level, int force) { int result; /* delete existing config file for level if it exists */ if (force) try_remove_existing_file_internal(cfg, level); if ((result = git_vector_insert_sorted(&cfg->files, internal, &duplicate_level)) < 0) return result; git_vector_sort(&cfg->files); internal->file->cfg = cfg; GIT_REFCOUNT_INC(internal); return 0; } int git_config_open_global(git_config **cfg_out, git_config *cfg) { if (!git_config_open_level(cfg_out, cfg, GIT_CONFIG_LEVEL_XDG)) return 0; return git_config_open_level(cfg_out, cfg, GIT_CONFIG_LEVEL_GLOBAL); } int git_config_open_level( git_config **cfg_out, const git_config *cfg_parent, git_config_level_t level) { git_config *cfg; file_internal *internal; int res; if ((res = find_internal_file_by_level(&internal, cfg_parent, level)) < 0) return res; if ((res = git_config_new(&cfg)) < 0) return res; if ((res = git_config__add_internal(cfg, internal, level, true)) < 0) { git_config_free(cfg); return res; } *cfg_out = cfg; return 0; } int git_config_add_backend( git_config *cfg, git_config_backend *file, git_config_level_t level, int force) { file_internal *internal; int result; assert(cfg && file); GITERR_CHECK_VERSION(file, GIT_CONFIG_BACKEND_VERSION, "git_config_backend"); if ((result = file->open(file, level)) < 0) return result; internal = git__malloc(sizeof(file_internal)); GITERR_CHECK_ALLOC(internal); memset(internal, 0x0, sizeof(file_internal)); internal->file = file; internal->level = level; if ((result = git_config__add_internal(cfg, internal, level, force)) < 0) { git__free(internal); return result; } return 0; } int git_config_refresh(git_config *cfg) { int error = 0; size_t i; for (i = 0; i < cfg->files.length && !error; ++i) { file_internal *internal = git_vector_get(&cfg->files, i); git_config_backend *file = internal->file; error = file->refresh(file); } if (!error && GIT_REFCOUNT_OWNER(cfg) != NULL) git_repository__cvar_cache_clear(GIT_REFCOUNT_OWNER(cfg)); return error; } /* * Loop over all the variables */ int git_config_foreach( const git_config *cfg, git_config_foreach_cb cb, void *payload) { return git_config_foreach_match(cfg, NULL, cb, payload); } int git_config_foreach_match( const git_config *cfg, const char *regexp, git_config_foreach_cb cb, void *payload) { int ret = 0; size_t i; file_internal *internal; git_config_backend *file; for (i = 0; i < cfg->files.length && ret == 0; ++i) { internal = git_vector_get(&cfg->files, i); file = internal->file; ret = file->foreach(file, regexp, cb, payload); } return ret; } /************** * Setters **************/ static int config_error_nofiles(const char *name) { giterr_set(GITERR_CONFIG, "Cannot set value for '%s' when no config files exist", name); return GIT_ENOTFOUND; } int git_config_delete_entry(git_config *cfg, const char *name) { git_config_backend *file; file_internal *internal; internal = git_vector_get(&cfg->files, 0); if (!internal || !internal->file) return config_error_nofiles(name); file = internal->file; return file->del(file, name); } int git_config_set_int64(git_config *cfg, const char *name, int64_t value) { char str_value[32]; /* All numbers should fit in here */ p_snprintf(str_value, sizeof(str_value), "%" PRId64, value); return git_config_set_string(cfg, name, str_value); } int git_config_set_int32(git_config *cfg, const char *name, int32_t value) { return git_config_set_int64(cfg, name, (int64_t)value); } int git_config_set_bool(git_config *cfg, const char *name, int value) { return git_config_set_string(cfg, name, value ? "true" : "false"); } int git_config_set_string(git_config *cfg, const char *name, const char *value) { int error; git_config_backend *file; file_internal *internal; if (!value) { giterr_set(GITERR_CONFIG, "The value to set cannot be NULL"); return -1; } internal = git_vector_get(&cfg->files, 0); if (!internal || !internal->file) return config_error_nofiles(name); file = internal->file; error = file->set(file, name, value); if (!error && GIT_REFCOUNT_OWNER(cfg) != NULL) git_repository__cvar_cache_clear(GIT_REFCOUNT_OWNER(cfg)); return error; } /*********** * Getters ***********/ int git_config_get_mapped( int *out, const git_config *cfg, const char *name, const git_cvar_map *maps, size_t map_n) { const char *value; int ret; if ((ret = git_config_get_string(&value, cfg, name)) < 0) return ret; return git_config_lookup_map_value(out, maps, map_n, value); } int git_config_get_int64(int64_t *out, const git_config *cfg, const char *name) { const char *value; int ret; if ((ret = git_config_get_string(&value, cfg, name)) < 0) return ret; return git_config_parse_int64(out, value); } int git_config_get_int32(int32_t *out, const git_config *cfg, const char *name) { const char *value; int ret; if ((ret = git_config_get_string(&value, cfg, name)) < 0) return ret; return git_config_parse_int32(out, value); } static int get_string_at_file(const char **out, const git_config_backend *file, const char *name) { const git_config_entry *entry; int res; res = file->get(file, name, &entry); if (!res) *out = entry->value; return res; } static int config_error_notfound(const char *name) { giterr_set(GITERR_CONFIG, "Config value '%s' was not found", name); return GIT_ENOTFOUND; } static int get_string(const char **out, const git_config *cfg, const char *name) { file_internal *internal; unsigned int i; int res; git_vector_foreach(&cfg->files, i, internal) { if (!internal || !internal->file) continue; res = get_string_at_file(out, internal->file, name); if (res != GIT_ENOTFOUND) return res; } return config_error_notfound(name); } int git_config_get_bool(int *out, const git_config *cfg, const char *name) { const char *value = NULL; int ret; if ((ret = get_string(&value, cfg, name)) < 0) return ret; return git_config_parse_bool(out, value); } int git_config_get_string(const char **out, const git_config *cfg, const char *name) { int ret; const char *str = NULL; if ((ret = get_string(&str, cfg, name)) < 0) return ret; *out = str == NULL ? "" : str; return 0; } int git_config_get_entry(const git_config_entry **out, const git_config *cfg, const char *name) { file_internal *internal; unsigned int i; git_config_backend *file; int ret; *out = NULL; git_vector_foreach(&cfg->files, i, internal) { if (!internal || !internal->file) continue; file = internal->file; ret = file->get(file, name, out); if (ret != GIT_ENOTFOUND) return ret; } return config_error_notfound(name); } int git_config_get_multivar( const git_config *cfg, const char *name, const char *regexp, git_config_foreach_cb cb, void *payload) { file_internal *internal; git_config_backend *file; int ret = GIT_ENOTFOUND; size_t i; /* * This loop runs the "wrong" way 'round because we need to * look at every value from the most general to most specific */ for (i = cfg->files.length; i > 0; --i) { internal = git_vector_get(&cfg->files, i - 1); if (!internal || !internal->file) continue; file = internal->file; ret = file->get_multivar(file, name, regexp, cb, payload); if (ret < 0 && ret != GIT_ENOTFOUND) return ret; } return (ret == GIT_ENOTFOUND) ? config_error_notfound(name) : 0; } int git_config_set_multivar(git_config *cfg, const char *name, const char *regexp, const char *value) { git_config_backend *file; file_internal *internal; internal = git_vector_get(&cfg->files, 0); if (!internal || !internal->file) return config_error_nofiles(name); file = internal->file; return file->set_multivar(file, name, regexp, value); } static int git_config__find_file_to_path( char *out, size_t outlen, int (*find)(git_buf *buf)) { int error = 0; git_buf path = GIT_BUF_INIT; if ((error = find(&path)) < 0) goto done; if (path.size >= outlen) { giterr_set(GITERR_NOMEMORY, "Buffer is too short for the path"); error = GIT_EBUFS; goto done; } git_buf_copy_cstr(out, outlen, &path); done: git_buf_free(&path); return error; } int git_config_find_global_r(git_buf *path) { return git_futils_find_global_file(path, GIT_CONFIG_FILENAME_GLOBAL); } int git_config_find_global(char *global_config_path, size_t length) { return git_config__find_file_to_path( global_config_path, length, git_config_find_global_r); } int git_config_find_xdg_r(git_buf *path) { return git_futils_find_xdg_file(path, GIT_CONFIG_FILENAME_XDG); } int git_config_find_xdg(char *xdg_config_path, size_t length) { return git_config__find_file_to_path( xdg_config_path, length, git_config_find_xdg_r); } int git_config_find_system_r(git_buf *path) { return git_futils_find_system_file(path, GIT_CONFIG_FILENAME_SYSTEM); } int git_config_find_system(char *system_config_path, size_t length) { return git_config__find_file_to_path( system_config_path, length, git_config_find_system_r); } int git_config__global_location(git_buf *buf) { const git_buf *paths; const char *sep, *start; size_t len; if (git_futils_dirs_get(&paths, GIT_FUTILS_DIR_GLOBAL) < 0) return -1; /* no paths, so give up */ if (git_buf_len(paths) == 0) return -1; start = git_buf_cstr(paths); sep = strchr(start, GIT_PATH_LIST_SEPARATOR); if (sep) len = sep - start; else len = paths->size; if (git_buf_set(buf, start, len) < 0) return -1; return git_buf_joinpath(buf, buf->ptr, GIT_CONFIG_FILENAME_GLOBAL); } int git_config_open_default(git_config **out) { int error; git_config *cfg = NULL; git_buf buf = GIT_BUF_INIT; if ((error = git_config_new(&cfg)) < 0) return error; if (!git_config_find_global_r(&buf) || !git_config__global_location(&buf)) { error = git_config_add_file_ondisk(cfg, buf.ptr, GIT_CONFIG_LEVEL_GLOBAL, 0); } if (!error && !git_config_find_xdg_r(&buf)) error = git_config_add_file_ondisk(cfg, buf.ptr, GIT_CONFIG_LEVEL_XDG, 0); if (!error && !git_config_find_system_r(&buf)) error = git_config_add_file_ondisk(cfg, buf.ptr, GIT_CONFIG_LEVEL_SYSTEM, 0); git_buf_free(&buf); if (error) { git_config_free(cfg); cfg = NULL; } *out = cfg; return error; } /*********** * Parsers ***********/ int git_config_lookup_map_value( int *out, const git_cvar_map *maps, size_t map_n, const char *value) { size_t i; if (!value) goto fail_parse; for (i = 0; i < map_n; ++i) { const git_cvar_map *m = maps + i; switch (m->cvar_type) { case GIT_CVAR_FALSE: case GIT_CVAR_TRUE: { int bool_val; if (git__parse_bool(&bool_val, value) == 0 && bool_val == (int)m->cvar_type) { *out = m->map_value; return 0; } break; } case GIT_CVAR_INT32: if (git_config_parse_int32(out, value) == 0) return 0; break; case GIT_CVAR_STRING: if (strcasecmp(value, m->str_match) == 0) { *out = m->map_value; return 0; } break; } } fail_parse: giterr_set(GITERR_CONFIG, "Failed to map '%s'", value); return -1; } int git_config_parse_bool(int *out, const char *value) { if (git__parse_bool(out, value) == 0) return 0; if (git_config_parse_int32(out, value) == 0) { *out = !!(*out); return 0; } giterr_set(GITERR_CONFIG, "Failed to parse '%s' as a boolean value", value); return -1; } int git_config_parse_int64(int64_t *out, const char *value) { const char *num_end; int64_t num; if (git__strtol64(&num, value, &num_end, 0) < 0) goto fail_parse; switch (*num_end) { case 'g': case 'G': num *= 1024; /* fallthrough */ case 'm': case 'M': num *= 1024; /* fallthrough */ case 'k': case 'K': num *= 1024; /* check that that there are no more characters after the * given modifier suffix */ if (num_end[1] != '\0') return -1; /* fallthrough */ case '\0': *out = num; return 0; default: goto fail_parse; } fail_parse: giterr_set(GITERR_CONFIG, "Failed to parse '%s' as an integer", value); return -1; } int git_config_parse_int32(int32_t *out, const char *value) { int64_t tmp; int32_t truncate; if (git_config_parse_int64(&tmp, value) < 0) goto fail_parse; truncate = tmp & 0xFFFFFFFF; if (truncate != tmp) goto fail_parse; *out = truncate; return 0; fail_parse: giterr_set(GITERR_CONFIG, "Failed to parse '%s' as a 32-bit integer", value); return -1; } struct rename_data { git_config *config; git_buf *name; size_t old_len; int actual_error; }; static int rename_config_entries_cb( const git_config_entry *entry, void *payload) { int error = 0; struct rename_data *data = (struct rename_data *)payload; size_t base_len = git_buf_len(data->name); if (base_len > 0 && !(error = git_buf_puts(data->name, entry->name + data->old_len))) { error = git_config_set_string( data->config, git_buf_cstr(data->name), entry->value); git_buf_truncate(data->name, base_len); } if (!error) error = git_config_delete_entry(data->config, entry->name); data->actual_error = error; /* preserve actual error code */ return error; } int git_config_rename_section( git_repository *repo, const char *old_section_name, const char *new_section_name) { git_config *config; git_buf pattern = GIT_BUF_INIT, replace = GIT_BUF_INIT; int error = 0; struct rename_data data; git_buf_text_puts_escape_regex(&pattern, old_section_name); if ((error = git_buf_puts(&pattern, "\\..+")) < 0) goto cleanup; if ((error = git_repository_config__weakptr(&config, repo)) < 0) goto cleanup; data.config = config; data.name = &replace; data.old_len = strlen(old_section_name) + 1; data.actual_error = 0; if ((error = git_buf_join(&replace, '.', new_section_name, "")) < 0) goto cleanup; if (new_section_name != NULL && (error = git_config_file_normalize_section( replace.ptr, strchr(replace.ptr, '.'))) < 0) { giterr_set( GITERR_CONFIG, "Invalid config section '%s'", new_section_name); goto cleanup; } error = git_config_foreach_match( config, git_buf_cstr(&pattern), rename_config_entries_cb, &data); if (error == GIT_EUSER) error = data.actual_error; cleanup: git_buf_free(&pattern); git_buf_free(&replace); return error; } libgit2-0.19.0/src/config.h000066400000000000000000000027531216214232500153470ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #ifndef INCLUDE_config_h__ #define INCLUDE_config_h__ #include "git2.h" #include "git2/config.h" #include "vector.h" #include "repository.h" #define GIT_CONFIG_FILENAME_SYSTEM "gitconfig" #define GIT_CONFIG_FILENAME_GLOBAL ".gitconfig" #define GIT_CONFIG_FILENAME_XDG "config" #define GIT_CONFIG_FILENAME_INREPO "config" #define GIT_CONFIG_FILE_MODE 0666 struct git_config { git_refcount rc; git_vector files; }; extern int git_config_find_global_r(git_buf *global_config_path); extern int git_config_find_xdg_r(git_buf *system_config_path); extern int git_config_find_system_r(git_buf *system_config_path); extern int git_config__global_location(git_buf *buf); extern int git_config_rename_section( git_repository *repo, const char *old_section_name, /* eg "branch.dummy" */ const char *new_section_name); /* NULL to drop the old section */ /** * Create a configuration file backend for ondisk files * * These are the normal `.gitconfig` files that Core Git * processes. Note that you first have to add this file to a * configuration object before you can query it for configuration * variables. * * @param out the new backend * @param path where the config file is located */ extern int git_config_file__ondisk(struct git_config_backend **out, const char *path); #endif libgit2-0.19.0/src/config_cache.c000066400000000000000000000062111216214232500164560ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #include "common.h" #include "fileops.h" #include "config.h" #include "git2/config.h" #include "vector.h" #include "filter.h" #include "repository.h" struct map_data { const char *cvar_name; git_cvar_map *maps; size_t map_count; int default_value; }; /* * core.eol * Sets the line ending type to use in the working directory for * files that have the text property set. Alternatives are lf, crlf * and native, which uses the platform's native line ending. The default * value is native. See gitattributes(5) for more information on * end-of-line conversion. */ static git_cvar_map _cvar_map_eol[] = { {GIT_CVAR_FALSE, NULL, GIT_EOL_UNSET}, {GIT_CVAR_STRING, "lf", GIT_EOL_LF}, {GIT_CVAR_STRING, "crlf", GIT_EOL_CRLF}, {GIT_CVAR_STRING, "native", GIT_EOL_NATIVE} }; /* * core.autocrlf * Setting this variable to "true" is almost the same as setting * the text attribute to "auto" on all files except that text files are * not guaranteed to be normalized: files that contain CRLF in the * repository will not be touched. Use this setting if you want to have * CRLF line endings in your working directory even though the repository * does not have normalized line endings. This variable can be set to input, * in which case no output conversion is performed. */ static git_cvar_map _cvar_map_autocrlf[] = { {GIT_CVAR_FALSE, NULL, GIT_AUTO_CRLF_FALSE}, {GIT_CVAR_TRUE, NULL, GIT_AUTO_CRLF_TRUE}, {GIT_CVAR_STRING, "input", GIT_AUTO_CRLF_INPUT} }; /* * Generic map for integer values */ static git_cvar_map _cvar_map_int[] = { {GIT_CVAR_INT32, NULL, 0}, }; static struct map_data _cvar_maps[] = { {"core.autocrlf", _cvar_map_autocrlf, ARRAY_SIZE(_cvar_map_autocrlf), GIT_AUTO_CRLF_DEFAULT}, {"core.eol", _cvar_map_eol, ARRAY_SIZE(_cvar_map_eol), GIT_EOL_DEFAULT}, {"core.symlinks", NULL, 0, GIT_SYMLINKS_DEFAULT }, {"core.ignorecase", NULL, 0, GIT_IGNORECASE_DEFAULT }, {"core.filemode", NULL, 0, GIT_FILEMODE_DEFAULT }, {"core.ignorestat", NULL, 0, GIT_IGNORESTAT_DEFAULT }, {"core.trustctime", NULL, 0, GIT_TRUSTCTIME_DEFAULT }, {"core.abbrev", _cvar_map_int, 1, GIT_ABBREV_DEFAULT }, }; int git_repository__cvar(int *out, git_repository *repo, git_cvar_cached cvar) { *out = repo->cvar_cache[(int)cvar]; if (*out == GIT_CVAR_NOT_CACHED) { struct map_data *data = &_cvar_maps[(int)cvar]; git_config *config; int error; error = git_repository_config__weakptr(&config, repo); if (error < 0) return error; if (data->maps) error = git_config_get_mapped( out, config, data->cvar_name, data->maps, data->map_count); else error = git_config_get_bool(out, config, data->cvar_name); if (error == GIT_ENOTFOUND) { giterr_clear(); *out = data->default_value; } else if (error < 0) return error; repo->cvar_cache[(int)cvar] = *out; } return 0; } void git_repository__cvar_cache_clear(git_repository *repo) { int i; for (i = 0; i < GIT_CVAR_CACHE_MAX; ++i) repo->cvar_cache[i] = GIT_CVAR_NOT_CACHED; } libgit2-0.19.0/src/config_file.c000066400000000000000000001031621216214232500163350ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #include "common.h" #include "config.h" #include "fileops.h" #include "filebuf.h" #include "buffer.h" #include "buf_text.h" #include "git2/config.h" #include "git2/sys/config.h" #include "git2/types.h" #include "strmap.h" #include #include #include GIT__USE_STRMAP; typedef struct cvar_t { struct cvar_t *next; git_config_entry *entry; } cvar_t; #define CVAR_LIST_HEAD(list) ((list)->head) #define CVAR_LIST_TAIL(list) ((list)->tail) #define CVAR_LIST_NEXT(var) ((var)->next) #define CVAR_LIST_EMPTY(list) ((list)->head == NULL) #define CVAR_LIST_APPEND(list, var) do {\ if (CVAR_LIST_EMPTY(list)) {\ CVAR_LIST_HEAD(list) = CVAR_LIST_TAIL(list) = var;\ } else {\ CVAR_LIST_NEXT(CVAR_LIST_TAIL(list)) = var;\ CVAR_LIST_TAIL(list) = var;\ }\ } while(0) #define CVAR_LIST_REMOVE_HEAD(list) do {\ CVAR_LIST_HEAD(list) = CVAR_LIST_NEXT(CVAR_LIST_HEAD(list));\ } while(0) #define CVAR_LIST_REMOVE_AFTER(var) do {\ CVAR_LIST_NEXT(var) = CVAR_LIST_NEXT(CVAR_LIST_NEXT(var));\ } while(0) #define CVAR_LIST_FOREACH(list, iter)\ for ((iter) = CVAR_LIST_HEAD(list);\ (iter) != NULL;\ (iter) = CVAR_LIST_NEXT(iter)) /* * Inspired by the FreeBSD functions */ #define CVAR_LIST_FOREACH_SAFE(start, iter, tmp)\ for ((iter) = CVAR_LIST_HEAD(vars);\ (iter) && (((tmp) = CVAR_LIST_NEXT(iter) || 1));\ (iter) = (tmp)) typedef struct { git_config_backend parent; git_strmap *values; struct { git_buf buffer; char *read_ptr; int line_number; int eof; } reader; char *file_path; time_t file_mtime; size_t file_size; git_config_level_t level; } diskfile_backend; static int config_parse(diskfile_backend *cfg_file, git_config_level_t level); static int parse_variable(diskfile_backend *cfg, char **var_name, char **var_value); static int config_write(diskfile_backend *cfg, const char *key, const regex_t *preg, const char *value); static char *escape_value(const char *ptr); static void set_parse_error(diskfile_backend *backend, int col, const char *error_str) { giterr_set(GITERR_CONFIG, "Failed to parse config file: %s (in %s:%d, column %d)", error_str, backend->file_path, backend->reader.line_number, col); } static void cvar_free(cvar_t *var) { if (var == NULL) return; git__free((char*)var->entry->name); git__free((char *)var->entry->value); git__free(var->entry); git__free(var); } int git_config_file_normalize_section(char *start, char *end) { char *scan; if (start == end) return GIT_EINVALIDSPEC; /* Validate and downcase range */ for (scan = start; *scan; ++scan) { if (end && scan >= end) break; if (isalnum(*scan)) *scan = tolower(*scan); else if (*scan != '-' || scan == start) return GIT_EINVALIDSPEC; } if (scan == start) return GIT_EINVALIDSPEC; return 0; } /* Take something the user gave us and make it nice for our hash function */ static int normalize_name(const char *in, char **out) { char *name, *fdot, *ldot; assert(in && out); name = git__strdup(in); GITERR_CHECK_ALLOC(name); fdot = strchr(name, '.'); ldot = strrchr(name, '.'); if (fdot == NULL || fdot == name || ldot == NULL || !ldot[1]) goto invalid; /* Validate and downcase up to first dot and after last dot */ if (git_config_file_normalize_section(name, fdot) < 0 || git_config_file_normalize_section(ldot + 1, NULL) < 0) goto invalid; /* If there is a middle range, make sure it doesn't have newlines */ while (fdot < ldot) if (*fdot++ == '\n') goto invalid; *out = name; return 0; invalid: git__free(name); giterr_set(GITERR_CONFIG, "Invalid config item name '%s'", in); return GIT_EINVALIDSPEC; } static void free_vars(git_strmap *values) { cvar_t *var = NULL; if (values == NULL) return; git_strmap_foreach_value(values, var, while (var != NULL) { cvar_t *next = CVAR_LIST_NEXT(var); cvar_free(var); var = next; }); git_strmap_free(values); } static int config_open(git_config_backend *cfg, git_config_level_t level) { int res; diskfile_backend *b = (diskfile_backend *)cfg; b->level = level; b->values = git_strmap_alloc(); GITERR_CHECK_ALLOC(b->values); git_buf_init(&b->reader.buffer, 0); res = git_futils_readbuffer_updated( &b->reader.buffer, b->file_path, &b->file_mtime, &b->file_size, NULL); /* It's fine if the file doesn't exist */ if (res == GIT_ENOTFOUND) return 0; if (res < 0 || (res = config_parse(b, level)) < 0) { free_vars(b->values); b->values = NULL; } git_buf_free(&b->reader.buffer); return res; } static int config_refresh(git_config_backend *cfg) { int res, updated = 0; diskfile_backend *b = (diskfile_backend *)cfg; git_strmap *old_values; res = git_futils_readbuffer_updated( &b->reader.buffer, b->file_path, &b->file_mtime, &b->file_size, &updated); if (res < 0 || !updated) return (res == GIT_ENOTFOUND) ? 0 : res; /* need to reload - store old values and prep for reload */ old_values = b->values; b->values = git_strmap_alloc(); GITERR_CHECK_ALLOC(b->values); if ((res = config_parse(b, b->level)) < 0) { free_vars(b->values); b->values = old_values; } else { free_vars(old_values); } git_buf_free(&b->reader.buffer); return res; } static void backend_free(git_config_backend *_backend) { diskfile_backend *backend = (diskfile_backend *)_backend; if (backend == NULL) return; git__free(backend->file_path); free_vars(backend->values); git__free(backend); } static int file_foreach( git_config_backend *backend, const char *regexp, int (*fn)(const git_config_entry *, void *), void *data) { diskfile_backend *b = (diskfile_backend *)backend; cvar_t *var, *next_var; const char *key; regex_t regex; int result = 0; if (!b->values) return 0; if (regexp != NULL) { if ((result = regcomp(®ex, regexp, REG_EXTENDED)) < 0) { giterr_set_regex(®ex, result); regfree(®ex); return -1; } } git_strmap_foreach(b->values, key, var, for (; var != NULL; var = next_var) { next_var = CVAR_LIST_NEXT(var); /* skip non-matching keys if regexp was provided */ if (regexp && regexec(®ex, key, 0, NULL, 0) != 0) continue; /* abort iterator on non-zero return value */ if (fn(var->entry, data)) { giterr_clear(); result = GIT_EUSER; goto cleanup; } } ); cleanup: if (regexp != NULL) regfree(®ex); return result; } static int config_set(git_config_backend *cfg, const char *name, const char *value) { cvar_t *var = NULL, *old_var = NULL; diskfile_backend *b = (diskfile_backend *)cfg; char *key, *esc_value = NULL; khiter_t pos; int rval, ret; if ((rval = normalize_name(name, &key)) < 0) return rval; /* * Try to find it in the existing values and update it if it * only has one value. */ pos = git_strmap_lookup_index(b->values, key); if (git_strmap_valid_index(b->values, pos)) { cvar_t *existing = git_strmap_value_at(b->values, pos); char *tmp = NULL; git__free(key); if (existing->next != NULL) { giterr_set(GITERR_CONFIG, "Multivar incompatible with simple set"); return -1; } /* don't update if old and new values already match */ if ((!existing->entry->value && !value) || (existing->entry->value && value && !strcmp(existing->entry->value, value))) return 0; if (value) { tmp = git__strdup(value); GITERR_CHECK_ALLOC(tmp); esc_value = escape_value(value); GITERR_CHECK_ALLOC(esc_value); } git__free((void *)existing->entry->value); existing->entry->value = tmp; ret = config_write(b, existing->entry->name, NULL, esc_value); git__free(esc_value); return ret; } var = git__malloc(sizeof(cvar_t)); GITERR_CHECK_ALLOC(var); memset(var, 0x0, sizeof(cvar_t)); var->entry = git__malloc(sizeof(git_config_entry)); GITERR_CHECK_ALLOC(var->entry); memset(var->entry, 0x0, sizeof(git_config_entry)); var->entry->name = key; var->entry->value = NULL; if (value) { var->entry->value = git__strdup(value); GITERR_CHECK_ALLOC(var->entry->value); esc_value = escape_value(value); GITERR_CHECK_ALLOC(esc_value); } if (config_write(b, key, NULL, esc_value) < 0) { git__free(esc_value); cvar_free(var); return -1; } git__free(esc_value); git_strmap_insert2(b->values, key, var, old_var, rval); if (rval < 0) return -1; if (old_var != NULL) cvar_free(old_var); return 0; } /* * Internal function that actually gets the value in string form */ static int config_get(const git_config_backend *cfg, const char *name, const git_config_entry **out) { diskfile_backend *b = (diskfile_backend *)cfg; char *key; khiter_t pos; int error; if ((error = normalize_name(name, &key)) < 0) return error; pos = git_strmap_lookup_index(b->values, key); git__free(key); /* no error message; the config system will write one */ if (!git_strmap_valid_index(b->values, pos)) return GIT_ENOTFOUND; *out = ((cvar_t *)git_strmap_value_at(b->values, pos))->entry; return 0; } static int config_get_multivar( git_config_backend *cfg, const char *name, const char *regex_str, int (*fn)(const git_config_entry *, void *), void *data) { cvar_t *var; diskfile_backend *b = (diskfile_backend *)cfg; char *key; khiter_t pos; int error; if ((error = normalize_name(name, &key)) < 0) return error; pos = git_strmap_lookup_index(b->values, key); git__free(key); if (!git_strmap_valid_index(b->values, pos)) return GIT_ENOTFOUND; var = git_strmap_value_at(b->values, pos); if (regex_str != NULL) { regex_t regex; int result; /* regex matching; build the regex */ result = regcomp(®ex, regex_str, REG_EXTENDED); if (result < 0) { giterr_set_regex(®ex, result); regfree(®ex); return -1; } /* and throw the callback only on the variables that * match the regex */ do { if (regexec(®ex, var->entry->value, 0, NULL, 0) == 0) { /* early termination by the user is not an error; * just break and return successfully */ if (fn(var->entry, data) < 0) break; } var = var->next; } while (var != NULL); regfree(®ex); } else { /* no regex; go through all the variables */ do { /* early termination by the user is not an error; * just break and return successfully */ if (fn(var->entry, data) < 0) break; var = var->next; } while (var != NULL); } return 0; } static int config_set_multivar( git_config_backend *cfg, const char *name, const char *regexp, const char *value) { int replaced = 0; cvar_t *var, *newvar; diskfile_backend *b = (diskfile_backend *)cfg; char *key; regex_t preg; int result; khiter_t pos; assert(regexp); if ((result = normalize_name(name, &key)) < 0) return result; pos = git_strmap_lookup_index(b->values, key); if (!git_strmap_valid_index(b->values, pos)) { /* If we don't have it, behave like a normal set */ result = config_set(cfg, name, value); git__free(key); return result; } var = git_strmap_value_at(b->values, pos); result = regcomp(&preg, regexp, REG_EXTENDED); if (result < 0) { git__free(key); giterr_set_regex(&preg, result); regfree(&preg); return -1; } for (;;) { if (regexec(&preg, var->entry->value, 0, NULL, 0) == 0) { char *tmp = git__strdup(value); GITERR_CHECK_ALLOC(tmp); git__free((void *)var->entry->value); var->entry->value = tmp; replaced = 1; } if (var->next == NULL) break; var = var->next; } /* If we've reached the end of the variables and we haven't found it yet, we need to append it */ if (!replaced) { newvar = git__malloc(sizeof(cvar_t)); GITERR_CHECK_ALLOC(newvar); memset(newvar, 0x0, sizeof(cvar_t)); newvar->entry = git__malloc(sizeof(git_config_entry)); GITERR_CHECK_ALLOC(newvar->entry); memset(newvar->entry, 0x0, sizeof(git_config_entry)); newvar->entry->name = git__strdup(var->entry->name); GITERR_CHECK_ALLOC(newvar->entry->name); newvar->entry->value = git__strdup(value); GITERR_CHECK_ALLOC(newvar->entry->value); newvar->entry->level = var->entry->level; var->next = newvar; } result = config_write(b, key, &preg, value); git__free(key); regfree(&preg); return result; } static int config_delete(git_config_backend *cfg, const char *name) { cvar_t *var; diskfile_backend *b = (diskfile_backend *)cfg; char *key; int result; khiter_t pos; if ((result = normalize_name(name, &key)) < 0) return result; pos = git_strmap_lookup_index(b->values, key); git__free(key); if (!git_strmap_valid_index(b->values, pos)) { giterr_set(GITERR_CONFIG, "Could not find key '%s' to delete", name); return GIT_ENOTFOUND; } var = git_strmap_value_at(b->values, pos); if (var->next != NULL) { giterr_set(GITERR_CONFIG, "Cannot delete multivar with a single delete"); return -1; } git_strmap_delete_at(b->values, pos); result = config_write(b, var->entry->name, NULL, NULL); cvar_free(var); return result; } int git_config_file__ondisk(git_config_backend **out, const char *path) { diskfile_backend *backend; backend = git__calloc(1, sizeof(diskfile_backend)); GITERR_CHECK_ALLOC(backend); backend->parent.version = GIT_CONFIG_BACKEND_VERSION; backend->file_path = git__strdup(path); GITERR_CHECK_ALLOC(backend->file_path); backend->parent.open = config_open; backend->parent.get = config_get; backend->parent.get_multivar = config_get_multivar; backend->parent.set = config_set; backend->parent.set_multivar = config_set_multivar; backend->parent.del = config_delete; backend->parent.foreach = file_foreach; backend->parent.refresh = config_refresh; backend->parent.free = backend_free; *out = (git_config_backend *)backend; return 0; } static int cfg_getchar_raw(diskfile_backend *cfg) { int c; c = *cfg->reader.read_ptr++; /* Win 32 line breaks: if we find a \r\n sequence, return only the \n as a newline */ if (c == '\r' && *cfg->reader.read_ptr == '\n') { cfg->reader.read_ptr++; c = '\n'; } if (c == '\n') cfg->reader.line_number++; if (c == 0) { cfg->reader.eof = 1; c = '\n'; } return c; } #define SKIP_WHITESPACE (1 << 1) #define SKIP_COMMENTS (1 << 2) static int cfg_getchar(diskfile_backend *cfg_file, int flags) { const int skip_whitespace = (flags & SKIP_WHITESPACE); const int skip_comments = (flags & SKIP_COMMENTS); int c; assert(cfg_file->reader.read_ptr); do c = cfg_getchar_raw(cfg_file); while (skip_whitespace && git__isspace(c) && !cfg_file->reader.eof); if (skip_comments && (c == '#' || c == ';')) { do c = cfg_getchar_raw(cfg_file); while (c != '\n'); } return c; } /* * Read the next char, but don't move the reading pointer. */ static int cfg_peek(diskfile_backend *cfg, int flags) { void *old_read_ptr; int old_lineno, old_eof; int ret; assert(cfg->reader.read_ptr); old_read_ptr = cfg->reader.read_ptr; old_lineno = cfg->reader.line_number; old_eof = cfg->reader.eof; ret = cfg_getchar(cfg, flags); cfg->reader.read_ptr = old_read_ptr; cfg->reader.line_number = old_lineno; cfg->reader.eof = old_eof; return ret; } /* * Read and consume a line, returning it in newly-allocated memory. */ static char *cfg_readline(diskfile_backend *cfg, bool skip_whitespace) { char *line = NULL; char *line_src, *line_end; size_t line_len; line_src = cfg->reader.read_ptr; if (skip_whitespace) { /* Skip empty empty lines */ while (git__isspace(*line_src)) ++line_src; } line_end = strchr(line_src, '\n'); /* no newline at EOF */ if (line_end == NULL) line_end = strchr(line_src, 0); line_len = line_end - line_src; line = git__malloc(line_len + 1); if (line == NULL) return NULL; memcpy(line, line_src, line_len); do line[line_len] = '\0'; while (line_len-- > 0 && git__isspace(line[line_len])); if (*line_end == '\n') line_end++; if (*line_end == '\0') cfg->reader.eof = 1; cfg->reader.line_number++; cfg->reader.read_ptr = line_end; return line; } /* * Consume a line, without storing it anywhere */ static void cfg_consume_line(diskfile_backend *cfg) { char *line_start, *line_end; line_start = cfg->reader.read_ptr; line_end = strchr(line_start, '\n'); /* No newline at EOF */ if(line_end == NULL){ line_end = strchr(line_start, '\0'); } if (*line_end == '\n') line_end++; if (*line_end == '\0') cfg->reader.eof = 1; cfg->reader.line_number++; cfg->reader.read_ptr = line_end; } GIT_INLINE(int) config_keychar(int c) { return isalnum(c) || c == '-'; } static int parse_section_header_ext(diskfile_backend *cfg, const char *line, const char *base_name, char **section_name) { int c, rpos; char *first_quote, *last_quote; git_buf buf = GIT_BUF_INIT; int quote_marks; /* * base_name is what came before the space. We should be at the * first quotation mark, except for now, line isn't being kept in * sync so we only really use it to calculate the length. */ first_quote = strchr(line, '"'); last_quote = strrchr(line, '"'); if (last_quote - first_quote == 0) { set_parse_error(cfg, 0, "Missing closing quotation mark in section header"); return -1; } git_buf_grow(&buf, strlen(base_name) + last_quote - first_quote + 2); git_buf_printf(&buf, "%s.", base_name); rpos = 0; quote_marks = 0; line = first_quote; c = line[rpos++]; /* * At the end of each iteration, whatever is stored in c will be * added to the string. In case of error, jump to out */ do { if (quote_marks == 2) { set_parse_error(cfg, rpos, "Unexpected text after closing quotes"); git_buf_free(&buf); return -1; } switch (c) { case '"': ++quote_marks; continue; case '\\': c = line[rpos++]; switch (c) { case '"': case '\\': break; default: set_parse_error(cfg, rpos, "Unsupported escape sequence"); git_buf_free(&buf); return -1; } default: break; } git_buf_putc(&buf, c); } while ((c = line[rpos++]) != ']'); *section_name = git_buf_detach(&buf); return 0; } static int parse_section_header(diskfile_backend *cfg, char **section_out) { char *name, *name_end; int name_length, c, pos; int result; char *line; line = cfg_readline(cfg, true); if (line == NULL) return -1; /* find the end of the variable's name */ name_end = strchr(line, ']'); if (name_end == NULL) { git__free(line); set_parse_error(cfg, 0, "Missing ']' in section header"); return -1; } name = (char *)git__malloc((size_t)(name_end - line) + 1); GITERR_CHECK_ALLOC(name); name_length = 0; pos = 0; /* Make sure we were given a section header */ c = line[pos++]; assert(c == '['); c = line[pos++]; do { if (git__isspace(c)){ name[name_length] = '\0'; result = parse_section_header_ext(cfg, line, name, section_out); git__free(line); git__free(name); return result; } if (!config_keychar(c) && c != '.') { set_parse_error(cfg, pos, "Unexpected character in header"); goto fail_parse; } name[name_length++] = (char) tolower(c); } while ((c = line[pos++]) != ']'); if (line[pos - 1] != ']') { set_parse_error(cfg, pos, "Unexpected end of file"); goto fail_parse; } git__free(line); name[name_length] = 0; *section_out = name; return 0; fail_parse: git__free(line); git__free(name); return -1; } static int skip_bom(diskfile_backend *cfg) { git_bom_t bom; int bom_offset = git_buf_text_detect_bom(&bom, &cfg->reader.buffer, cfg->reader.read_ptr - cfg->reader.buffer.ptr); if (bom == GIT_BOM_UTF8) cfg->reader.read_ptr += bom_offset; /* TODO: reference implementation is pretty stupid with BoM */ return 0; } /* (* basic types *) digit = "0".."9" integer = digit { digit } alphabet = "a".."z" + "A" .. "Z" section_char = alphabet | "." | "-" extension_char = (* any character except newline *) any_char = (* any character *) variable_char = "alphabet" | "-" (* actual grammar *) config = { section } section = header { definition } header = "[" section [subsection | subsection_ext] "]" subsection = "." section subsection_ext = "\"" extension "\"" section = section_char { section_char } extension = extension_char { extension_char } definition = variable_name ["=" variable_value] "\n" variable_name = variable_char { variable_char } variable_value = string | boolean | integer string = quoted_string | plain_string quoted_string = "\"" plain_string "\"" plain_string = { any_char } boolean = boolean_true | boolean_false boolean_true = "yes" | "1" | "true" | "on" boolean_false = "no" | "0" | "false" | "off" */ static int strip_comments(char *line, int in_quotes) { int quote_count = in_quotes; char *ptr; for (ptr = line; *ptr; ++ptr) { if (ptr[0] == '"' && ptr > line && ptr[-1] != '\\') quote_count++; if ((ptr[0] == ';' || ptr[0] == '#') && (quote_count % 2) == 0) { ptr[0] = '\0'; break; } } /* skip any space at the end */ if (ptr > line && git__isspace(ptr[-1])) { ptr--; } ptr[0] = '\0'; return quote_count; } static int config_parse(diskfile_backend *cfg_file, git_config_level_t level) { int c; char *current_section = NULL; char *var_name; char *var_value; cvar_t *var, *existing; git_buf buf = GIT_BUF_INIT; int result = 0; khiter_t pos; /* Initialize the reading position */ cfg_file->reader.read_ptr = cfg_file->reader.buffer.ptr; cfg_file->reader.eof = 0; /* If the file is empty, there's nothing for us to do */ if (*cfg_file->reader.read_ptr == '\0') return 0; skip_bom(cfg_file); while (result == 0 && !cfg_file->reader.eof) { c = cfg_peek(cfg_file, SKIP_WHITESPACE); switch (c) { case '\n': /* EOF when peeking, set EOF in the reader to exit the loop */ cfg_file->reader.eof = 1; break; case '[': /* section header, new section begins */ git__free(current_section); current_section = NULL; result = parse_section_header(cfg_file, ¤t_section); break; case ';': case '#': cfg_consume_line(cfg_file); break; default: /* assume variable declaration */ result = parse_variable(cfg_file, &var_name, &var_value); if (result < 0) break; var = git__malloc(sizeof(cvar_t)); GITERR_CHECK_ALLOC(var); memset(var, 0x0, sizeof(cvar_t)); var->entry = git__malloc(sizeof(git_config_entry)); GITERR_CHECK_ALLOC(var->entry); memset(var->entry, 0x0, sizeof(git_config_entry)); git__strtolower(var_name); git_buf_printf(&buf, "%s.%s", current_section, var_name); git__free(var_name); if (git_buf_oom(&buf)) return -1; var->entry->name = git_buf_detach(&buf); var->entry->value = var_value; var->entry->level = level; /* Add or append the new config option */ pos = git_strmap_lookup_index(cfg_file->values, var->entry->name); if (!git_strmap_valid_index(cfg_file->values, pos)) { git_strmap_insert(cfg_file->values, var->entry->name, var, result); if (result < 0) break; result = 0; } else { existing = git_strmap_value_at(cfg_file->values, pos); while (existing->next != NULL) { existing = existing->next; } existing->next = var; } break; } } git__free(current_section); return result; } static int write_section(git_filebuf *file, const char *key) { int result; const char *dot; git_buf buf = GIT_BUF_INIT; /* All of this just for [section "subsection"] */ dot = strchr(key, '.'); git_buf_putc(&buf, '['); if (dot == NULL) { git_buf_puts(&buf, key); } else { char *escaped; git_buf_put(&buf, key, dot - key); escaped = escape_value(dot + 1); GITERR_CHECK_ALLOC(escaped); git_buf_printf(&buf, " \"%s\"", escaped); git__free(escaped); } git_buf_puts(&buf, "]\n"); if (git_buf_oom(&buf)) return -1; result = git_filebuf_write(file, git_buf_cstr(&buf), buf.size); git_buf_free(&buf); return result; } /* * This is pretty much the parsing, except we write out anything we don't have */ static int config_write(diskfile_backend *cfg, const char *key, const regex_t *preg, const char* value) { int result, c; int section_matches = 0, last_section_matched = 0, preg_replaced = 0, write_trailer = 0; const char *pre_end = NULL, *post_start = NULL, *data_start; char *current_section = NULL, *section, *name, *ldot; git_filebuf file = GIT_FILEBUF_INIT; /* We need to read in our own config file */ result = git_futils_readbuffer(&cfg->reader.buffer, cfg->file_path); /* Initialise the reading position */ if (result == GIT_ENOTFOUND) { cfg->reader.read_ptr = NULL; cfg->reader.eof = 1; data_start = NULL; git_buf_clear(&cfg->reader.buffer); } else if (result == 0) { cfg->reader.read_ptr = cfg->reader.buffer.ptr; cfg->reader.eof = 0; data_start = cfg->reader.read_ptr; } else { return -1; /* OS error when reading the file */ } /* Lock the file */ if (git_filebuf_open(&file, cfg->file_path, 0) < 0) return -1; skip_bom(cfg); ldot = strrchr(key, '.'); name = ldot + 1; section = git__strndup(key, ldot - key); while (!cfg->reader.eof) { c = cfg_peek(cfg, SKIP_WHITESPACE); if (c == '\0') { /* We've arrived at the end of the file */ break; } else if (c == '[') { /* section header, new section begins */ /* * We set both positions to the current one in case we * need to add a variable to the end of a section. In that * case, we want both variables to point just before the * new section. If we actually want to replace it, the * default case will take care of updating them. */ pre_end = post_start = cfg->reader.read_ptr; git__free(current_section); current_section = NULL; if (parse_section_header(cfg, ¤t_section) < 0) goto rewrite_fail; /* Keep track of when it stops matching */ last_section_matched = section_matches; section_matches = !strcmp(current_section, section); } else if (c == ';' || c == '#') { cfg_consume_line(cfg); } else { /* * If the section doesn't match, but the last section did, * it means we need to add a variable (so skip the line * otherwise). If both the section and name match, we need * to overwrite the variable (so skip the line * otherwise). pre_end needs to be updated each time so we * don't loose that information, but we only need to * update post_start if we're going to use it in this * iteration. */ if (!section_matches) { if (!last_section_matched) { cfg_consume_line(cfg); continue; } } else { int has_matched = 0; char *var_name, *var_value; pre_end = cfg->reader.read_ptr; if (parse_variable(cfg, &var_name, &var_value) < 0) goto rewrite_fail; /* First try to match the name of the variable */ if (strcasecmp(name, var_name) == 0) has_matched = 1; /* If the name matches, and we have a regex to match the * value, try to match it */ if (has_matched && preg != NULL) has_matched = (regexec(preg, var_value, 0, NULL, 0) == 0); git__free(var_name); git__free(var_value); /* if there is no match, keep going */ if (!has_matched) continue; post_start = cfg->reader.read_ptr; } /* We've found the variable we wanted to change, so * write anything up to it */ git_filebuf_write(&file, data_start, pre_end - data_start); preg_replaced = 1; /* Then replace the variable. If the value is NULL, it * means we want to delete it, so don't write anything. */ if (value != NULL) { git_filebuf_printf(&file, "\t%s = %s\n", name, value); } /* multiline variable? we need to keep reading lines to match */ if (preg != NULL) { data_start = post_start; continue; } write_trailer = 1; break; /* break from the loop */ } } /* * Being here can mean that * * 1) our section is the last one in the file and we're * adding a variable * * 2) we didn't find a section for us so we need to create it * ourselves. * * 3) we're setting a multivar with a regex, which means we * continue to search for matching values * * In the last case, if we've already replaced a value, we * want to write the rest of the file. Otherwise we need to write * out the whole file and then the new variable. */ if (write_trailer) { /* Write out rest of the file */ git_filebuf_write(&file, post_start, cfg->reader.buffer.size - (post_start - data_start)); } else { if (preg_replaced) { git_filebuf_printf(&file, "\n%s", data_start); } else { git_filebuf_write(&file, cfg->reader.buffer.ptr, cfg->reader.buffer.size); /* And now if we just need to add a variable */ if (!section_matches && write_section(&file, section) < 0) goto rewrite_fail; /* Sanity check: if we are here, and value is NULL, that means that somebody * touched the config file after our intial read. We should probably assert() * this, but instead we'll handle it gracefully with an error. */ if (value == NULL) { giterr_set(GITERR_CONFIG, "Race condition when writing a config file (a cvar has been removed)"); goto rewrite_fail; } /* If we are here, there is at least a section line */ if (cfg->reader.buffer.size > 0 && *(cfg->reader.buffer.ptr + cfg->reader.buffer.size - 1) != '\n') git_filebuf_write(&file, "\n", 1); git_filebuf_printf(&file, "\t%s = %s\n", name, value); } } git__free(section); git__free(current_section); /* refresh stats - if this errors, then commit will error too */ (void)git_filebuf_stats(&cfg->file_mtime, &cfg->file_size, &file); result = git_filebuf_commit(&file, GIT_CONFIG_FILE_MODE); git_buf_free(&cfg->reader.buffer); return result; rewrite_fail: git__free(section); git__free(current_section); git_filebuf_cleanup(&file); git_buf_free(&cfg->reader.buffer); return -1; } static const char *escapes = "ntb\"\\"; static const char *escaped = "\n\t\b\"\\"; /* Escape the values to write them to the file */ static char *escape_value(const char *ptr) { git_buf buf = GIT_BUF_INIT; size_t len; const char *esc; assert(ptr); len = strlen(ptr); git_buf_grow(&buf, len); while (*ptr != '\0') { if ((esc = strchr(escaped, *ptr)) != NULL) { git_buf_putc(&buf, '\\'); git_buf_putc(&buf, escapes[esc - escaped]); } else { git_buf_putc(&buf, *ptr); } ptr++; } if (git_buf_oom(&buf)) { git_buf_free(&buf); return NULL; } return git_buf_detach(&buf); } /* '\"' -> '"' etc */ static char *fixup_line(const char *ptr, int quote_count) { char *str = git__malloc(strlen(ptr) + 1); char *out = str, *esc; if (str == NULL) return NULL; while (*ptr != '\0') { if (*ptr == '"') { quote_count++; } else if (*ptr != '\\') { *out++ = *ptr; } else { /* backslash, check the next char */ ptr++; /* if we're at the end, it's a multiline, so keep the backslash */ if (*ptr == '\0') { *out++ = '\\'; goto out; } if ((esc = strchr(escapes, *ptr)) != NULL) { *out++ = escaped[esc - escapes]; } else { git__free(str); giterr_set(GITERR_CONFIG, "Invalid escape at %s", ptr); return NULL; } } ptr++; } out: *out = '\0'; return str; } static int is_multiline_var(const char *str) { int count = 0; const char *end = str + strlen(str); while (end > str && end[-1] == '\\') { count++; end--; } /* An odd number means last backslash wasn't escaped, so it's multiline */ return (end > str) && (count & 1); } static int parse_multiline_variable(diskfile_backend *cfg, git_buf *value, int in_quotes) { char *line = NULL, *proc_line = NULL; int quote_count; /* Check that the next line exists */ line = cfg_readline(cfg, false); if (line == NULL) return -1; /* We've reached the end of the file, there is input missing */ if (line[0] == '\0') { set_parse_error(cfg, 0, "Unexpected end of file while parsing multine var"); git__free(line); return -1; } quote_count = strip_comments(line, !!in_quotes); /* If it was just a comment, pretend it didn't exist */ if (line[0] == '\0') { git__free(line); return parse_multiline_variable(cfg, value, quote_count); /* TODO: unbounded recursion. This **could** be exploitable */ } /* Drop the continuation character '\': to closely follow the UNIX * standard, this character **has** to be last one in the buf, with * no whitespace after it */ assert(is_multiline_var(value->ptr)); git_buf_truncate(value, git_buf_len(value) - 1); proc_line = fixup_line(line, in_quotes); if (proc_line == NULL) { git__free(line); return -1; } /* add this line to the multiline var */ git_buf_puts(value, proc_line); git__free(line); git__free(proc_line); /* * If we need to continue reading the next line, let's just * keep putting stuff in the buffer */ if (is_multiline_var(value->ptr)) return parse_multiline_variable(cfg, value, quote_count); return 0; } static int parse_variable(diskfile_backend *cfg, char **var_name, char **var_value) { const char *var_end = NULL; const char *value_start = NULL; char *line; int quote_count; line = cfg_readline(cfg, true); if (line == NULL) return -1; quote_count = strip_comments(line, 0); var_end = strchr(line, '='); if (var_end == NULL) var_end = strchr(line, '\0'); else value_start = var_end + 1; do var_end--; while (var_end>line && git__isspace(*var_end)); *var_name = git__strndup(line, var_end - line + 1); GITERR_CHECK_ALLOC(*var_name); /* If there is no value, boolean true is assumed */ *var_value = NULL; /* * Now, let's try to parse the value */ if (value_start != NULL) { while (git__isspace(value_start[0])) value_start++; if (is_multiline_var(value_start)) { git_buf multi_value = GIT_BUF_INIT; char *proc_line = fixup_line(value_start, 0); GITERR_CHECK_ALLOC(proc_line); git_buf_puts(&multi_value, proc_line); git__free(proc_line); if (parse_multiline_variable(cfg, &multi_value, quote_count) < 0 || git_buf_oom(&multi_value)) { git__free(*var_name); git__free(line); git_buf_free(&multi_value); return -1; } *var_value = git_buf_detach(&multi_value); } else if (value_start[0] != '\0') { *var_value = fixup_line(value_start, 0); GITERR_CHECK_ALLOC(*var_value); } else { /* equals sign but missing rhs */ *var_value = git__strdup(""); GITERR_CHECK_ALLOC(*var_value); } } git__free(line); return 0; } libgit2-0.19.0/src/config_file.h000066400000000000000000000025761216214232500163510ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #ifndef INCLUDE_config_file_h__ #define INCLUDE_config_file_h__ #include "git2/config.h" GIT_INLINE(int) git_config_file_open(git_config_backend *cfg, unsigned int level) { return cfg->open(cfg, level); } GIT_INLINE(void) git_config_file_free(git_config_backend *cfg) { cfg->free(cfg); } GIT_INLINE(int) git_config_file_get_string( const git_config_entry **out, git_config_backend *cfg, const char *name) { return cfg->get(cfg, name, out); } GIT_INLINE(int) git_config_file_set_string( git_config_backend *cfg, const char *name, const char *value) { return cfg->set(cfg, name, value); } GIT_INLINE(int) git_config_file_delete( git_config_backend *cfg, const char *name) { return cfg->del(cfg, name); } GIT_INLINE(int) git_config_file_foreach( git_config_backend *cfg, int (*fn)(const git_config_entry *entry, void *data), void *data) { return cfg->foreach(cfg, NULL, fn, data); } GIT_INLINE(int) git_config_file_foreach_match( git_config_backend *cfg, const char *regexp, int (*fn)(const git_config_entry *entry, void *data), void *data) { return cfg->foreach(cfg, regexp, fn, data); } extern int git_config_file_normalize_section(char *start, char *end); #endif libgit2-0.19.0/src/crlf.c000066400000000000000000000156621216214232500150260ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #include "git2/attr.h" #include "git2/blob.h" #include "git2/index.h" #include "common.h" #include "fileops.h" #include "hash.h" #include "filter.h" #include "buf_text.h" #include "repository.h" struct crlf_attrs { int crlf_action; int eol; }; struct crlf_filter { git_filter f; struct crlf_attrs attrs; git_repository *repo; char path[GIT_FLEX_ARRAY]; }; static int check_crlf(const char *value) { if (GIT_ATTR_TRUE(value)) return GIT_CRLF_TEXT; if (GIT_ATTR_FALSE(value)) return GIT_CRLF_BINARY; if (GIT_ATTR_UNSPECIFIED(value)) return GIT_CRLF_GUESS; if (strcmp(value, "input") == 0) return GIT_CRLF_INPUT; if (strcmp(value, "auto") == 0) return GIT_CRLF_AUTO; return GIT_CRLF_GUESS; } static int check_eol(const char *value) { if (GIT_ATTR_UNSPECIFIED(value)) return GIT_EOL_UNSET; if (strcmp(value, "lf") == 0) return GIT_EOL_LF; if (strcmp(value, "crlf") == 0) return GIT_EOL_CRLF; return GIT_EOL_UNSET; } static int crlf_input_action(struct crlf_attrs *ca) { if (ca->crlf_action == GIT_CRLF_BINARY) return GIT_CRLF_BINARY; if (ca->eol == GIT_EOL_LF) return GIT_CRLF_INPUT; if (ca->eol == GIT_EOL_CRLF) return GIT_CRLF_CRLF; return ca->crlf_action; } static int crlf_load_attributes(struct crlf_attrs *ca, git_repository *repo, const char *path) { #define NUM_CONV_ATTRS 3 static const char *attr_names[NUM_CONV_ATTRS] = { "crlf", "eol", "text", }; const char *attr_vals[NUM_CONV_ATTRS]; int error; error = git_attr_get_many(attr_vals, repo, 0, path, NUM_CONV_ATTRS, attr_names); if (error == GIT_ENOTFOUND) { ca->crlf_action = GIT_CRLF_GUESS; ca->eol = GIT_EOL_UNSET; return 0; } if (error == 0) { ca->crlf_action = check_crlf(attr_vals[2]); /* text */ if (ca->crlf_action == GIT_CRLF_GUESS) ca->crlf_action = check_crlf(attr_vals[0]); /* clrf */ ca->eol = check_eol(attr_vals[1]); /* eol */ return 0; } return -1; } static int has_cr_in_index(git_filter *self) { struct crlf_filter *filter = (struct crlf_filter *)self; git_index *index; const git_index_entry *entry; git_blob *blob; const void *blobcontent; git_off_t blobsize; bool found_cr; if (git_repository_index__weakptr(&index, filter->repo) < 0) { giterr_clear(); return false; } if (!(entry = git_index_get_bypath(index, filter->path, 0)) && !(entry = git_index_get_bypath(index, filter->path, 1))) return false; if (!S_ISREG(entry->mode)) /* don't crlf filter non-blobs */ return true; if (git_blob_lookup(&blob, filter->repo, &entry->oid) < 0) return false; blobcontent = git_blob_rawcontent(blob); blobsize = git_blob_rawsize(blob); if (!git__is_sizet(blobsize)) blobsize = (size_t)-1; found_cr = (blobcontent != NULL && blobsize > 0 && memchr(blobcontent, '\r', (size_t)blobsize) != NULL); git_blob_free(blob); return found_cr; } static int crlf_apply_to_odb( git_filter *self, git_buf *dest, const git_buf *source) { struct crlf_filter *filter = (struct crlf_filter *)self; assert(self && dest && source); /* Empty file? Nothing to do */ if (git_buf_len(source) == 0) return 0; /* Heuristics to see if we can skip the conversion. * Straight from Core Git. */ if (filter->attrs.crlf_action == GIT_CRLF_AUTO || filter->attrs.crlf_action == GIT_CRLF_GUESS) { git_buf_text_stats stats; /* Check heuristics for binary vs text... */ if (git_buf_text_gather_stats(&stats, source, false)) return -1; /* * We're currently not going to even try to convert stuff * that has bare CR characters. Does anybody do that crazy * stuff? */ if (stats.cr != stats.crlf) return -1; if (filter->attrs.crlf_action == GIT_CRLF_GUESS) { /* * If the file in the index has any CR in it, do not convert. * This is the new safer autocrlf handling. */ if (has_cr_in_index(self)) return -1; } if (!stats.cr) return -1; } /* Actually drop the carriage returns */ return git_buf_text_crlf_to_lf(dest, source); } static const char *line_ending(struct crlf_filter *filter) { switch (filter->attrs.crlf_action) { case GIT_CRLF_BINARY: case GIT_CRLF_INPUT: return "\n"; case GIT_CRLF_CRLF: return "\r\n"; case GIT_CRLF_AUTO: case GIT_CRLF_TEXT: case GIT_CRLF_GUESS: break; default: goto line_ending_error; } switch (filter->attrs.eol) { case GIT_EOL_UNSET: return GIT_EOL_NATIVE == GIT_EOL_CRLF ? "\r\n" : "\n"; case GIT_EOL_CRLF: return "\r\n"; case GIT_EOL_LF: return "\n"; default: goto line_ending_error; } line_ending_error: giterr_set(GITERR_INVALID, "Invalid input to line ending filter"); return NULL; } static int crlf_apply_to_workdir( git_filter *self, git_buf *dest, const git_buf *source) { struct crlf_filter *filter = (struct crlf_filter *)self; const char *workdir_ending = NULL; assert(self && dest && source); /* Empty file? Nothing to do. */ if (git_buf_len(source) == 0) return -1; /* Determine proper line ending */ workdir_ending = line_ending(filter); if (!workdir_ending) return -1; if (!strcmp("\n", workdir_ending)) /* do nothing for \n ending */ return -1; /* for now, only lf->crlf conversion is supported here */ assert(!strcmp("\r\n", workdir_ending)); return git_buf_text_lf_to_crlf(dest, source); } static int find_and_add_filter( git_vector *filters, git_repository *repo, const char *path, int (*apply)(struct git_filter *self, git_buf *dest, const git_buf *source)) { struct crlf_attrs ca; struct crlf_filter *filter; size_t pathlen; int error; /* Load gitattributes for the path */ if ((error = crlf_load_attributes(&ca, repo, path)) < 0) return error; /* * Use the core Git logic to see if we should perform CRLF for this file * based on its attributes & the value of `core.autocrlf` */ ca.crlf_action = crlf_input_action(&ca); if (ca.crlf_action == GIT_CRLF_BINARY) return 0; if (ca.crlf_action == GIT_CRLF_GUESS) { int auto_crlf; if ((error = git_repository__cvar(&auto_crlf, repo, GIT_CVAR_AUTO_CRLF)) < 0) return error; if (auto_crlf == GIT_AUTO_CRLF_FALSE) return 0; } /* If we're good, we create a new filter object and push it * into the filters array */ pathlen = strlen(path); filter = git__malloc(sizeof(struct crlf_filter) + pathlen + 1); GITERR_CHECK_ALLOC(filter); filter->f.apply = apply; filter->f.do_free = NULL; memcpy(&filter->attrs, &ca, sizeof(struct crlf_attrs)); filter->repo = repo; memcpy(filter->path, path, pathlen + 1); return git_vector_insert(filters, filter); } int git_filter_add__crlf_to_odb( git_vector *filters, git_repository *repo, const char *path) { return find_and_add_filter(filters, repo, path, &crlf_apply_to_odb); } int git_filter_add__crlf_to_workdir( git_vector *filters, git_repository *repo, const char *path) { return find_and_add_filter(filters, repo, path, &crlf_apply_to_workdir); } libgit2-0.19.0/src/date.c000066400000000000000000000456051216214232500150150ustar00rootroot00000000000000/* * GIT - The information manager from hell * * Copyright (C) Linus Torvalds, 2005 */ #include "common.h" #ifndef GIT_WIN32 #include #endif #include "util.h" #include "cache.h" #include "posix.h" #include #include typedef enum { DATE_NORMAL = 0, DATE_RELATIVE, DATE_SHORT, DATE_LOCAL, DATE_ISO8601, DATE_RFC2822, DATE_RAW } date_mode; /* * This is like mktime, but without normalization of tm_wday and tm_yday. */ static git_time_t tm_to_time_t(const struct tm *tm) { static const int mdays[] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 }; int year = tm->tm_year - 70; int month = tm->tm_mon; int day = tm->tm_mday; if (year < 0 || year > 129) /* algo only works for 1970-2099 */ return -1; if (month < 0 || month > 11) /* array bounds */ return -1; if (month < 2 || (year + 2) % 4) day--; if (tm->tm_hour < 0 || tm->tm_min < 0 || tm->tm_sec < 0) return -1; return (year * 365 + (year + 1) / 4 + mdays[month] + day) * 24*60*60UL + tm->tm_hour * 60*60 + tm->tm_min * 60 + tm->tm_sec; } static const char *month_names[] = { "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" }; static const char *weekday_names[] = { "Sundays", "Mondays", "Tuesdays", "Wednesdays", "Thursdays", "Fridays", "Saturdays" }; /* * Check these. And note how it doesn't do the summer-time conversion. * * In my world, it's always summer, and things are probably a bit off * in other ways too. */ static const struct { const char *name; int offset; int dst; } timezone_names[] = { { "IDLW", -12, 0, }, /* International Date Line West */ { "NT", -11, 0, }, /* Nome */ { "CAT", -10, 0, }, /* Central Alaska */ { "HST", -10, 0, }, /* Hawaii Standard */ { "HDT", -10, 1, }, /* Hawaii Daylight */ { "YST", -9, 0, }, /* Yukon Standard */ { "YDT", -9, 1, }, /* Yukon Daylight */ { "PST", -8, 0, }, /* Pacific Standard */ { "PDT", -8, 1, }, /* Pacific Daylight */ { "MST", -7, 0, }, /* Mountain Standard */ { "MDT", -7, 1, }, /* Mountain Daylight */ { "CST", -6, 0, }, /* Central Standard */ { "CDT", -6, 1, }, /* Central Daylight */ { "EST", -5, 0, }, /* Eastern Standard */ { "EDT", -5, 1, }, /* Eastern Daylight */ { "AST", -3, 0, }, /* Atlantic Standard */ { "ADT", -3, 1, }, /* Atlantic Daylight */ { "WAT", -1, 0, }, /* West Africa */ { "GMT", 0, 0, }, /* Greenwich Mean */ { "UTC", 0, 0, }, /* Universal (Coordinated) */ { "Z", 0, 0, }, /* Zulu, alias for UTC */ { "WET", 0, 0, }, /* Western European */ { "BST", 0, 1, }, /* British Summer */ { "CET", +1, 0, }, /* Central European */ { "MET", +1, 0, }, /* Middle European */ { "MEWT", +1, 0, }, /* Middle European Winter */ { "MEST", +1, 1, }, /* Middle European Summer */ { "CEST", +1, 1, }, /* Central European Summer */ { "MESZ", +1, 1, }, /* Middle European Summer */ { "FWT", +1, 0, }, /* French Winter */ { "FST", +1, 1, }, /* French Summer */ { "EET", +2, 0, }, /* Eastern Europe */ { "EEST", +2, 1, }, /* Eastern European Daylight */ { "WAST", +7, 0, }, /* West Australian Standard */ { "WADT", +7, 1, }, /* West Australian Daylight */ { "CCT", +8, 0, }, /* China Coast */ { "JST", +9, 0, }, /* Japan Standard */ { "EAST", +10, 0, }, /* Eastern Australian Standard */ { "EADT", +10, 1, }, /* Eastern Australian Daylight */ { "GST", +10, 0, }, /* Guam Standard */ { "NZT", +12, 0, }, /* New Zealand */ { "NZST", +12, 0, }, /* New Zealand Standard */ { "NZDT", +12, 1, }, /* New Zealand Daylight */ { "IDLE", +12, 0, }, /* International Date Line East */ }; static size_t match_string(const char *date, const char *str) { size_t i = 0; for (i = 0; *date; date++, str++, i++) { if (*date == *str) continue; if (toupper(*date) == toupper(*str)) continue; if (!isalnum(*date)) break; return 0; } return i; } static int skip_alpha(const char *date) { int i = 0; do { i++; } while (isalpha(date[i])); return i; } /* * Parse month, weekday, or timezone name */ static size_t match_alpha(const char *date, struct tm *tm, int *offset) { unsigned int i; for (i = 0; i < 12; i++) { size_t match = match_string(date, month_names[i]); if (match >= 3) { tm->tm_mon = i; return match; } } for (i = 0; i < 7; i++) { size_t match = match_string(date, weekday_names[i]); if (match >= 3) { tm->tm_wday = i; return match; } } for (i = 0; i < ARRAY_SIZE(timezone_names); i++) { size_t match = match_string(date, timezone_names[i].name); if (match >= 3 || match == strlen(timezone_names[i].name)) { int off = timezone_names[i].offset; /* This is bogus, but we like summer */ off += timezone_names[i].dst; /* Only use the tz name offset if we don't have anything better */ if (*offset == -1) *offset = 60*off; return match; } } if (match_string(date, "PM") == 2) { tm->tm_hour = (tm->tm_hour % 12) + 12; return 2; } if (match_string(date, "AM") == 2) { tm->tm_hour = (tm->tm_hour % 12) + 0; return 2; } /* BAD */ return skip_alpha(date); } static int is_date(int year, int month, int day, struct tm *now_tm, time_t now, struct tm *tm) { if (month > 0 && month < 13 && day > 0 && day < 32) { struct tm check = *tm; struct tm *r = (now_tm ? &check : tm); time_t specified; r->tm_mon = month - 1; r->tm_mday = day; if (year == -1) { if (!now_tm) return 1; r->tm_year = now_tm->tm_year; } else if (year >= 1970 && year < 2100) r->tm_year = year - 1900; else if (year > 70 && year < 100) r->tm_year = year; else if (year < 38) r->tm_year = year + 100; else return 0; if (!now_tm) return 1; specified = tm_to_time_t(r); /* Be it commit time or author time, it does not make * sense to specify timestamp way into the future. Make * sure it is not later than ten days from now... */ if (now + 10*24*3600 < specified) return 0; tm->tm_mon = r->tm_mon; tm->tm_mday = r->tm_mday; if (year != -1) tm->tm_year = r->tm_year; return 1; } return 0; } static size_t match_multi_number(unsigned long num, char c, const char *date, char *end, struct tm *tm) { time_t now; struct tm now_tm; struct tm *refuse_future; long num2, num3; num2 = strtol(end+1, &end, 10); num3 = -1; if (*end == c && isdigit(end[1])) num3 = strtol(end+1, &end, 10); /* Time? Date? */ switch (c) { case ':': if (num3 < 0) num3 = 0; if (num < 25 && num2 >= 0 && num2 < 60 && num3 >= 0 && num3 <= 60) { tm->tm_hour = num; tm->tm_min = num2; tm->tm_sec = num3; break; } return 0; case '-': case '/': case '.': now = time(NULL); refuse_future = NULL; if (p_gmtime_r(&now, &now_tm)) refuse_future = &now_tm; if (num > 70) { /* yyyy-mm-dd? */ if (is_date(num, num2, num3, refuse_future, now, tm)) break; /* yyyy-dd-mm? */ if (is_date(num, num3, num2, refuse_future, now, tm)) break; } /* Our eastern European friends say dd.mm.yy[yy] * is the norm there, so giving precedence to * mm/dd/yy[yy] form only when separator is not '.' */ if (c != '.' && is_date(num3, num, num2, refuse_future, now, tm)) break; /* European dd.mm.yy[yy] or funny US dd/mm/yy[yy] */ if (is_date(num3, num2, num, refuse_future, now, tm)) break; /* Funny European mm.dd.yy */ if (c == '.' && is_date(num3, num, num2, refuse_future, now, tm)) break; return 0; } return end - date; } /* * Have we filled in any part of the time/date yet? * We just do a binary 'and' to see if the sign bit * is set in all the values. */ static int nodate(struct tm *tm) { return (tm->tm_year & tm->tm_mon & tm->tm_mday & tm->tm_hour & tm->tm_min & tm->tm_sec) < 0; } /* * We've seen a digit. Time? Year? Date? */ static size_t match_digit(const char *date, struct tm *tm, int *offset, int *tm_gmt) { size_t n; char *end; unsigned long num; num = strtoul(date, &end, 10); /* * Seconds since 1970? We trigger on that for any numbers with * more than 8 digits. This is because we don't want to rule out * numbers like 20070606 as a YYYYMMDD date. */ if (num >= 100000000 && nodate(tm)) { time_t time = num; if (p_gmtime_r(&time, tm)) { *tm_gmt = 1; return end - date; } } /* * Check for special formats: num[-.:/]num[same]num */ switch (*end) { case ':': case '.': case '/': case '-': if (isdigit(end[1])) { size_t match = match_multi_number(num, *end, date, end, tm); if (match) return match; } } /* * None of the special formats? Try to guess what * the number meant. We use the number of digits * to make a more educated guess.. */ n = 0; do { n++; } while (isdigit(date[n])); /* Four-digit year or a timezone? */ if (n == 4) { if (num <= 1400 && *offset == -1) { unsigned int minutes = num % 100; unsigned int hours = num / 100; *offset = hours*60 + minutes; } else if (num > 1900 && num < 2100) tm->tm_year = num - 1900; return n; } /* * Ignore lots of numerals. We took care of 4-digit years above. * Days or months must be one or two digits. */ if (n > 2) return n; /* * NOTE! We will give precedence to day-of-month over month or * year numbers in the 1-12 range. So 05 is always "mday 5", * unless we already have a mday.. * * IOW, 01 Apr 05 parses as "April 1st, 2005". */ if (num > 0 && num < 32 && tm->tm_mday < 0) { tm->tm_mday = num; return n; } /* Two-digit year? */ if (n == 2 && tm->tm_year < 0) { if (num < 10 && tm->tm_mday >= 0) { tm->tm_year = num + 100; return n; } if (num >= 70) { tm->tm_year = num; return n; } } if (num > 0 && num < 13 && tm->tm_mon < 0) tm->tm_mon = num-1; return n; } static size_t match_tz(const char *date, int *offp) { char *end; int hour = strtoul(date + 1, &end, 10); size_t n = end - (date + 1); int min = 0; if (n == 4) { /* hhmm */ min = hour % 100; hour = hour / 100; } else if (n != 2) { min = 99; /* random stuff */ } else if (*end == ':') { /* hh:mm? */ min = strtoul(end + 1, &end, 10); if (end - (date + 1) != 5) min = 99; /* random stuff */ } /* otherwise we parsed "hh" */ /* * Don't accept any random stuff. Even though some places have * offset larger than 12 hours (e.g. Pacific/Kiritimati is at * UTC+14), there is something wrong if hour part is much * larger than that. We might also want to check that the * minutes are divisible by 15 or something too. (Offset of * Kathmandu, Nepal is UTC+5:45) */ if (min < 60 && hour < 24) { int offset = hour * 60 + min; if (*date == '-') offset = -offset; *offp = offset; } return end - date; } /* * Parse a string like "0 +0000" as ancient timestamp near epoch, but * only when it appears not as part of any other string. */ static int match_object_header_date(const char *date, git_time_t *timestamp, int *offset) { char *end; unsigned long stamp; int ofs; if (*date < '0' || '9' <= *date) return -1; stamp = strtoul(date, &end, 10); if (*end != ' ' || stamp == ULONG_MAX || (end[1] != '+' && end[1] != '-')) return -1; date = end + 2; ofs = strtol(date, &end, 10); if ((*end != '\0' && (*end != '\n')) || end != date + 4) return -1; ofs = (ofs / 100) * 60 + (ofs % 100); if (date[-1] == '-') ofs = -ofs; *timestamp = stamp; *offset = ofs; return 0; } /* Gr. strptime is crap for this; it doesn't have a way to require RFC2822 (i.e. English) day/month names, and it doesn't work correctly with %z. */ static int parse_date_basic(const char *date, git_time_t *timestamp, int *offset) { struct tm tm; int tm_gmt; git_time_t dummy_timestamp; int dummy_offset; if (!timestamp) timestamp = &dummy_timestamp; if (!offset) offset = &dummy_offset; memset(&tm, 0, sizeof(tm)); tm.tm_year = -1; tm.tm_mon = -1; tm.tm_mday = -1; tm.tm_isdst = -1; tm.tm_hour = -1; tm.tm_min = -1; tm.tm_sec = -1; *offset = -1; tm_gmt = 0; if (*date == '@' && !match_object_header_date(date + 1, timestamp, offset)) return 0; /* success */ for (;;) { size_t match = 0; unsigned char c = *date; /* Stop at end of string or newline */ if (!c || c == '\n') break; if (isalpha(c)) match = match_alpha(date, &tm, offset); else if (isdigit(c)) match = match_digit(date, &tm, offset, &tm_gmt); else if ((c == '-' || c == '+') && isdigit(date[1])) match = match_tz(date, offset); if (!match) { /* BAD */ match = 1; } date += match; } /* mktime uses local timezone */ *timestamp = tm_to_time_t(&tm); if (*offset == -1) *offset = (int)((time_t)*timestamp - mktime(&tm)) / 60; if (*timestamp == (git_time_t)-1) return -1; if (!tm_gmt) *timestamp -= *offset * 60; return 0; /* success */ } /* * Relative time update (eg "2 days ago"). If we haven't set the time * yet, we need to set it from current time. */ static git_time_t update_tm(struct tm *tm, struct tm *now, unsigned long sec) { time_t n; if (tm->tm_mday < 0) tm->tm_mday = now->tm_mday; if (tm->tm_mon < 0) tm->tm_mon = now->tm_mon; if (tm->tm_year < 0) { tm->tm_year = now->tm_year; if (tm->tm_mon > now->tm_mon) tm->tm_year--; } n = mktime(tm) - sec; p_localtime_r(&n, tm); return n; } static void date_now(struct tm *tm, struct tm *now, int *num) { GIT_UNUSED(num); update_tm(tm, now, 0); } static void date_yesterday(struct tm *tm, struct tm *now, int *num) { GIT_UNUSED(num); update_tm(tm, now, 24*60*60); } static void date_time(struct tm *tm, struct tm *now, int hour) { if (tm->tm_hour < hour) date_yesterday(tm, now, NULL); tm->tm_hour = hour; tm->tm_min = 0; tm->tm_sec = 0; } static void date_midnight(struct tm *tm, struct tm *now, int *num) { GIT_UNUSED(num); date_time(tm, now, 0); } static void date_noon(struct tm *tm, struct tm *now, int *num) { GIT_UNUSED(num); date_time(tm, now, 12); } static void date_tea(struct tm *tm, struct tm *now, int *num) { GIT_UNUSED(num); date_time(tm, now, 17); } static void date_pm(struct tm *tm, struct tm *now, int *num) { int hour, n = *num; *num = 0; GIT_UNUSED(now); hour = tm->tm_hour; if (n) { hour = n; tm->tm_min = 0; tm->tm_sec = 0; } tm->tm_hour = (hour % 12) + 12; } static void date_am(struct tm *tm, struct tm *now, int *num) { int hour, n = *num; *num = 0; GIT_UNUSED(now); hour = tm->tm_hour; if (n) { hour = n; tm->tm_min = 0; tm->tm_sec = 0; } tm->tm_hour = (hour % 12); } static void date_never(struct tm *tm, struct tm *now, int *num) { time_t n = 0; GIT_UNUSED(now); GIT_UNUSED(num); p_localtime_r(&n, tm); } static const struct special { const char *name; void (*fn)(struct tm *, struct tm *, int *); } special[] = { { "yesterday", date_yesterday }, { "noon", date_noon }, { "midnight", date_midnight }, { "tea", date_tea }, { "PM", date_pm }, { "AM", date_am }, { "never", date_never }, { "now", date_now }, { NULL } }; static const char *number_name[] = { "zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten", }; static const struct typelen { const char *type; int length; } typelen[] = { { "seconds", 1 }, { "minutes", 60 }, { "hours", 60*60 }, { "days", 24*60*60 }, { "weeks", 7*24*60*60 }, { NULL } }; static const char *approxidate_alpha(const char *date, struct tm *tm, struct tm *now, int *num, int *touched) { const struct typelen *tl; const struct special *s; const char *end = date; int i; while (isalpha(*++end)) /* scan to non-alpha */; for (i = 0; i < 12; i++) { size_t match = match_string(date, month_names[i]); if (match >= 3) { tm->tm_mon = i; *touched = 1; return end; } } for (s = special; s->name; s++) { size_t len = strlen(s->name); if (match_string(date, s->name) == len) { s->fn(tm, now, num); *touched = 1; return end; } } if (!*num) { for (i = 1; i < 11; i++) { size_t len = strlen(number_name[i]); if (match_string(date, number_name[i]) == len) { *num = i; *touched = 1; return end; } } if (match_string(date, "last") == 4) { *num = 1; *touched = 1; } return end; } tl = typelen; while (tl->type) { size_t len = strlen(tl->type); if (match_string(date, tl->type) >= len-1) { update_tm(tm, now, tl->length * *num); *num = 0; *touched = 1; return end; } tl++; } for (i = 0; i < 7; i++) { size_t match = match_string(date, weekday_names[i]); if (match >= 3) { int diff, n = *num -1; *num = 0; diff = tm->tm_wday - i; if (diff <= 0) n++; diff += 7*n; update_tm(tm, now, diff * 24 * 60 * 60); *touched = 1; return end; } } if (match_string(date, "months") >= 5) { int n; update_tm(tm, now, 0); /* fill in date fields if needed */ n = tm->tm_mon - *num; *num = 0; while (n < 0) { n += 12; tm->tm_year--; } tm->tm_mon = n; *touched = 1; return end; } if (match_string(date, "years") >= 4) { update_tm(tm, now, 0); /* fill in date fields if needed */ tm->tm_year -= *num; *num = 0; *touched = 1; return end; } return end; } static const char *approxidate_digit(const char *date, struct tm *tm, int *num) { char *end; unsigned long number = strtoul(date, &end, 10); switch (*end) { case ':': case '.': case '/': case '-': if (isdigit(end[1])) { size_t match = match_multi_number(number, *end, date, end, tm); if (match) return date + match; } } /* Accept zero-padding only for small numbers ("Dec 02", never "Dec 0002") */ if (date[0] != '0' || end - date <= 2) *num = number; return end; } /* * Do we have a pending number at the end, or when * we see a new one? Let's assume it's a month day, * as in "Dec 6, 1992" */ static void pending_number(struct tm *tm, int *num) { int number = *num; if (number) { *num = 0; if (tm->tm_mday < 0 && number < 32) tm->tm_mday = number; else if (tm->tm_mon < 0 && number < 13) tm->tm_mon = number-1; else if (tm->tm_year < 0) { if (number > 1969 && number < 2100) tm->tm_year = number - 1900; else if (number > 69 && number < 100) tm->tm_year = number; else if (number < 38) tm->tm_year = 100 + number; /* We mess up for number = 00 ? */ } } } static git_time_t approxidate_str(const char *date, const struct timeval *tv, int *error_ret) { int number = 0; int touched = 0; struct tm tm = {0}, now; time_t time_sec; time_sec = tv->tv_sec; p_localtime_r(&time_sec, &tm); now = tm; tm.tm_year = -1; tm.tm_mon = -1; tm.tm_mday = -1; for (;;) { unsigned char c = *date; if (!c) break; date++; if (isdigit(c)) { pending_number(&tm, &number); date = approxidate_digit(date-1, &tm, &number); touched = 1; continue; } if (isalpha(c)) date = approxidate_alpha(date-1, &tm, &now, &number, &touched); } pending_number(&tm, &number); if (!touched) *error_ret = 1; return update_tm(&tm, &now, 0); } int git__date_parse(git_time_t *out, const char *date) { struct timeval tv; git_time_t timestamp; int offset, error_ret=0; if (!parse_date_basic(date, ×tamp, &offset)) { *out = timestamp; return 0; } p_gettimeofday(&tv, NULL); *out = approxidate_str(date, &tv, &error_ret); return error_ret; } libgit2-0.19.0/src/delta-apply.c000066400000000000000000000061371216214232500163110ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #include "common.h" #include "git2/odb.h" #include "delta-apply.h" /* * This file was heavily cribbed from BinaryDelta.java in JGit, which * itself was heavily cribbed from patch-delta.c in the * GIT project. The original delta patching code was written by * Nicolas Pitre . */ static int hdr_sz( size_t *size, const unsigned char **delta, const unsigned char *end) { const unsigned char *d = *delta; size_t r = 0; unsigned int c, shift = 0; do { if (d == end) return -1; c = *d++; r |= (c & 0x7f) << shift; shift += 7; } while (c & 0x80); *delta = d; *size = r; return 0; } int git__delta_read_header( const unsigned char *delta, size_t delta_len, size_t *base_sz, size_t *res_sz) { const unsigned char *delta_end = delta + delta_len; if ((hdr_sz(base_sz, &delta, delta_end) < 0) || (hdr_sz(res_sz, &delta, delta_end) < 0)) return -1; return 0; } int git__delta_apply( git_rawobj *out, const unsigned char *base, size_t base_len, const unsigned char *delta, size_t delta_len) { const unsigned char *delta_end = delta + delta_len; size_t base_sz, res_sz; unsigned char *res_dp; /* Check that the base size matches the data we were given; * if not we would underflow while accessing data from the * base object, resulting in data corruption or segfault. */ if ((hdr_sz(&base_sz, &delta, delta_end) < 0) || (base_sz != base_len)) { giterr_set(GITERR_INVALID, "Failed to apply delta. Base size does not match given data"); return -1; } if (hdr_sz(&res_sz, &delta, delta_end) < 0) { giterr_set(GITERR_INVALID, "Failed to apply delta. Base size does not match given data"); return -1; } res_dp = git__malloc(res_sz + 1); GITERR_CHECK_ALLOC(res_dp); res_dp[res_sz] = '\0'; out->data = res_dp; out->len = res_sz; while (delta < delta_end) { unsigned char cmd = *delta++; if (cmd & 0x80) { /* cmd is a copy instruction; copy from the base. */ size_t off = 0, len = 0; if (cmd & 0x01) off = *delta++; if (cmd & 0x02) off |= *delta++ << 8; if (cmd & 0x04) off |= *delta++ << 16; if (cmd & 0x08) off |= *delta++ << 24; if (cmd & 0x10) len = *delta++; if (cmd & 0x20) len |= *delta++ << 8; if (cmd & 0x40) len |= *delta++ << 16; if (!len) len = 0x10000; if (base_len < off + len || res_sz < len) goto fail; memcpy(res_dp, base + off, len); res_dp += len; res_sz -= len; } else if (cmd) { /* cmd is a literal insert instruction; copy from * the delta stream itself. */ if (delta_end - delta < cmd || res_sz < cmd) goto fail; memcpy(res_dp, delta, cmd); delta += cmd; res_dp += cmd; res_sz -= cmd; } else { /* cmd == 0 is reserved for future encodings. */ goto fail; } } if (delta != delta_end || res_sz) goto fail; return 0; fail: git__free(out->data); out->data = NULL; giterr_set(GITERR_INVALID, "Failed to apply delta"); return -1; } libgit2-0.19.0/src/delta-apply.h000066400000000000000000000030151216214232500163060ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #ifndef INCLUDE_delta_apply_h__ #define INCLUDE_delta_apply_h__ #include "odb.h" /** * Apply a git binary delta to recover the original content. * * @param out the output buffer to receive the original data. * Only out->data and out->len are populated, as this is * the only information available in the delta. * @param base the base to copy from during copy instructions. * @param base_len number of bytes available at base. * @param delta the delta to execute copy/insert instructions from. * @param delta_len total number of bytes in the delta. * @return * - 0 on a successful delta unpack. * - GIT_ERROR if the delta is corrupt or doesn't match the base. */ extern int git__delta_apply( git_rawobj *out, const unsigned char *base, size_t base_len, const unsigned char *delta, size_t delta_len); /** * Read the header of a git binary delta. * * @param delta the delta to execute copy/insert instructions from. * @param delta_len total number of bytes in the delta. * @param base_sz pointer to store the base size field. * @param res_sz pointer to store the result size field. * @return * - 0 on a successful decoding the header. * - GIT_ERROR if the delta is corrupt. */ extern int git__delta_read_header( const unsigned char *delta, size_t delta_len, size_t *base_sz, size_t *res_sz); #endif libgit2-0.19.0/src/delta.c000066400000000000000000000334301216214232500151620ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #include "delta.h" /* maximum hash entry list for the same hash bucket */ #define HASH_LIMIT 64 #define RABIN_SHIFT 23 #define RABIN_WINDOW 16 static const unsigned int T[256] = { 0x00000000, 0xab59b4d1, 0x56b369a2, 0xfdeadd73, 0x063f6795, 0xad66d344, 0x508c0e37, 0xfbd5bae6, 0x0c7ecf2a, 0xa7277bfb, 0x5acda688, 0xf1941259, 0x0a41a8bf, 0xa1181c6e, 0x5cf2c11d, 0xf7ab75cc, 0x18fd9e54, 0xb3a42a85, 0x4e4ef7f6, 0xe5174327, 0x1ec2f9c1, 0xb59b4d10, 0x48719063, 0xe32824b2, 0x1483517e, 0xbfdae5af, 0x423038dc, 0xe9698c0d, 0x12bc36eb, 0xb9e5823a, 0x440f5f49, 0xef56eb98, 0x31fb3ca8, 0x9aa28879, 0x6748550a, 0xcc11e1db, 0x37c45b3d, 0x9c9defec, 0x6177329f, 0xca2e864e, 0x3d85f382, 0x96dc4753, 0x6b369a20, 0xc06f2ef1, 0x3bba9417, 0x90e320c6, 0x6d09fdb5, 0xc6504964, 0x2906a2fc, 0x825f162d, 0x7fb5cb5e, 0xd4ec7f8f, 0x2f39c569, 0x846071b8, 0x798aaccb, 0xd2d3181a, 0x25786dd6, 0x8e21d907, 0x73cb0474, 0xd892b0a5, 0x23470a43, 0x881ebe92, 0x75f463e1, 0xdeadd730, 0x63f67950, 0xc8afcd81, 0x354510f2, 0x9e1ca423, 0x65c91ec5, 0xce90aa14, 0x337a7767, 0x9823c3b6, 0x6f88b67a, 0xc4d102ab, 0x393bdfd8, 0x92626b09, 0x69b7d1ef, 0xc2ee653e, 0x3f04b84d, 0x945d0c9c, 0x7b0be704, 0xd05253d5, 0x2db88ea6, 0x86e13a77, 0x7d348091, 0xd66d3440, 0x2b87e933, 0x80de5de2, 0x7775282e, 0xdc2c9cff, 0x21c6418c, 0x8a9ff55d, 0x714a4fbb, 0xda13fb6a, 0x27f92619, 0x8ca092c8, 0x520d45f8, 0xf954f129, 0x04be2c5a, 0xafe7988b, 0x5432226d, 0xff6b96bc, 0x02814bcf, 0xa9d8ff1e, 0x5e738ad2, 0xf52a3e03, 0x08c0e370, 0xa39957a1, 0x584ced47, 0xf3155996, 0x0eff84e5, 0xa5a63034, 0x4af0dbac, 0xe1a96f7d, 0x1c43b20e, 0xb71a06df, 0x4ccfbc39, 0xe79608e8, 0x1a7cd59b, 0xb125614a, 0x468e1486, 0xedd7a057, 0x103d7d24, 0xbb64c9f5, 0x40b17313, 0xebe8c7c2, 0x16021ab1, 0xbd5bae60, 0x6cb54671, 0xc7ecf2a0, 0x3a062fd3, 0x915f9b02, 0x6a8a21e4, 0xc1d39535, 0x3c394846, 0x9760fc97, 0x60cb895b, 0xcb923d8a, 0x3678e0f9, 0x9d215428, 0x66f4eece, 0xcdad5a1f, 0x3047876c, 0x9b1e33bd, 0x7448d825, 0xdf116cf4, 0x22fbb187, 0x89a20556, 0x7277bfb0, 0xd92e0b61, 0x24c4d612, 0x8f9d62c3, 0x7836170f, 0xd36fa3de, 0x2e857ead, 0x85dcca7c, 0x7e09709a, 0xd550c44b, 0x28ba1938, 0x83e3ade9, 0x5d4e7ad9, 0xf617ce08, 0x0bfd137b, 0xa0a4a7aa, 0x5b711d4c, 0xf028a99d, 0x0dc274ee, 0xa69bc03f, 0x5130b5f3, 0xfa690122, 0x0783dc51, 0xacda6880, 0x570fd266, 0xfc5666b7, 0x01bcbbc4, 0xaae50f15, 0x45b3e48d, 0xeeea505c, 0x13008d2f, 0xb85939fe, 0x438c8318, 0xe8d537c9, 0x153feaba, 0xbe665e6b, 0x49cd2ba7, 0xe2949f76, 0x1f7e4205, 0xb427f6d4, 0x4ff24c32, 0xe4abf8e3, 0x19412590, 0xb2189141, 0x0f433f21, 0xa41a8bf0, 0x59f05683, 0xf2a9e252, 0x097c58b4, 0xa225ec65, 0x5fcf3116, 0xf49685c7, 0x033df00b, 0xa86444da, 0x558e99a9, 0xfed72d78, 0x0502979e, 0xae5b234f, 0x53b1fe3c, 0xf8e84aed, 0x17bea175, 0xbce715a4, 0x410dc8d7, 0xea547c06, 0x1181c6e0, 0xbad87231, 0x4732af42, 0xec6b1b93, 0x1bc06e5f, 0xb099da8e, 0x4d7307fd, 0xe62ab32c, 0x1dff09ca, 0xb6a6bd1b, 0x4b4c6068, 0xe015d4b9, 0x3eb80389, 0x95e1b758, 0x680b6a2b, 0xc352defa, 0x3887641c, 0x93ded0cd, 0x6e340dbe, 0xc56db96f, 0x32c6cca3, 0x999f7872, 0x6475a501, 0xcf2c11d0, 0x34f9ab36, 0x9fa01fe7, 0x624ac294, 0xc9137645, 0x26459ddd, 0x8d1c290c, 0x70f6f47f, 0xdbaf40ae, 0x207afa48, 0x8b234e99, 0x76c993ea, 0xdd90273b, 0x2a3b52f7, 0x8162e626, 0x7c883b55, 0xd7d18f84, 0x2c043562, 0x875d81b3, 0x7ab75cc0, 0xd1eee811 }; static const unsigned int U[256] = { 0x00000000, 0x7eb5200d, 0x5633f4cb, 0x2886d4c6, 0x073e5d47, 0x798b7d4a, 0x510da98c, 0x2fb88981, 0x0e7cba8e, 0x70c99a83, 0x584f4e45, 0x26fa6e48, 0x0942e7c9, 0x77f7c7c4, 0x5f711302, 0x21c4330f, 0x1cf9751c, 0x624c5511, 0x4aca81d7, 0x347fa1da, 0x1bc7285b, 0x65720856, 0x4df4dc90, 0x3341fc9d, 0x1285cf92, 0x6c30ef9f, 0x44b63b59, 0x3a031b54, 0x15bb92d5, 0x6b0eb2d8, 0x4388661e, 0x3d3d4613, 0x39f2ea38, 0x4747ca35, 0x6fc11ef3, 0x11743efe, 0x3eccb77f, 0x40799772, 0x68ff43b4, 0x164a63b9, 0x378e50b6, 0x493b70bb, 0x61bda47d, 0x1f088470, 0x30b00df1, 0x4e052dfc, 0x6683f93a, 0x1836d937, 0x250b9f24, 0x5bbebf29, 0x73386bef, 0x0d8d4be2, 0x2235c263, 0x5c80e26e, 0x740636a8, 0x0ab316a5, 0x2b7725aa, 0x55c205a7, 0x7d44d161, 0x03f1f16c, 0x2c4978ed, 0x52fc58e0, 0x7a7a8c26, 0x04cfac2b, 0x73e5d470, 0x0d50f47d, 0x25d620bb, 0x5b6300b6, 0x74db8937, 0x0a6ea93a, 0x22e87dfc, 0x5c5d5df1, 0x7d996efe, 0x032c4ef3, 0x2baa9a35, 0x551fba38, 0x7aa733b9, 0x041213b4, 0x2c94c772, 0x5221e77f, 0x6f1ca16c, 0x11a98161, 0x392f55a7, 0x479a75aa, 0x6822fc2b, 0x1697dc26, 0x3e1108e0, 0x40a428ed, 0x61601be2, 0x1fd53bef, 0x3753ef29, 0x49e6cf24, 0x665e46a5, 0x18eb66a8, 0x306db26e, 0x4ed89263, 0x4a173e48, 0x34a21e45, 0x1c24ca83, 0x6291ea8e, 0x4d29630f, 0x339c4302, 0x1b1a97c4, 0x65afb7c9, 0x446b84c6, 0x3adea4cb, 0x1258700d, 0x6ced5000, 0x4355d981, 0x3de0f98c, 0x15662d4a, 0x6bd30d47, 0x56ee4b54, 0x285b6b59, 0x00ddbf9f, 0x7e689f92, 0x51d01613, 0x2f65361e, 0x07e3e2d8, 0x7956c2d5, 0x5892f1da, 0x2627d1d7, 0x0ea10511, 0x7014251c, 0x5facac9d, 0x21198c90, 0x099f5856, 0x772a785b, 0x4c921c31, 0x32273c3c, 0x1aa1e8fa, 0x6414c8f7, 0x4bac4176, 0x3519617b, 0x1d9fb5bd, 0x632a95b0, 0x42eea6bf, 0x3c5b86b2, 0x14dd5274, 0x6a687279, 0x45d0fbf8, 0x3b65dbf5, 0x13e30f33, 0x6d562f3e, 0x506b692d, 0x2ede4920, 0x06589de6, 0x78edbdeb, 0x5755346a, 0x29e01467, 0x0166c0a1, 0x7fd3e0ac, 0x5e17d3a3, 0x20a2f3ae, 0x08242768, 0x76910765, 0x59298ee4, 0x279caee9, 0x0f1a7a2f, 0x71af5a22, 0x7560f609, 0x0bd5d604, 0x235302c2, 0x5de622cf, 0x725eab4e, 0x0ceb8b43, 0x246d5f85, 0x5ad87f88, 0x7b1c4c87, 0x05a96c8a, 0x2d2fb84c, 0x539a9841, 0x7c2211c0, 0x029731cd, 0x2a11e50b, 0x54a4c506, 0x69998315, 0x172ca318, 0x3faa77de, 0x411f57d3, 0x6ea7de52, 0x1012fe5f, 0x38942a99, 0x46210a94, 0x67e5399b, 0x19501996, 0x31d6cd50, 0x4f63ed5d, 0x60db64dc, 0x1e6e44d1, 0x36e89017, 0x485db01a, 0x3f77c841, 0x41c2e84c, 0x69443c8a, 0x17f11c87, 0x38499506, 0x46fcb50b, 0x6e7a61cd, 0x10cf41c0, 0x310b72cf, 0x4fbe52c2, 0x67388604, 0x198da609, 0x36352f88, 0x48800f85, 0x6006db43, 0x1eb3fb4e, 0x238ebd5d, 0x5d3b9d50, 0x75bd4996, 0x0b08699b, 0x24b0e01a, 0x5a05c017, 0x728314d1, 0x0c3634dc, 0x2df207d3, 0x534727de, 0x7bc1f318, 0x0574d315, 0x2acc5a94, 0x54797a99, 0x7cffae5f, 0x024a8e52, 0x06852279, 0x78300274, 0x50b6d6b2, 0x2e03f6bf, 0x01bb7f3e, 0x7f0e5f33, 0x57888bf5, 0x293dabf8, 0x08f998f7, 0x764cb8fa, 0x5eca6c3c, 0x207f4c31, 0x0fc7c5b0, 0x7172e5bd, 0x59f4317b, 0x27411176, 0x1a7c5765, 0x64c97768, 0x4c4fa3ae, 0x32fa83a3, 0x1d420a22, 0x63f72a2f, 0x4b71fee9, 0x35c4dee4, 0x1400edeb, 0x6ab5cde6, 0x42331920, 0x3c86392d, 0x133eb0ac, 0x6d8b90a1, 0x450d4467, 0x3bb8646a }; struct index_entry { const unsigned char *ptr; unsigned int val; struct index_entry *next; }; struct git_delta_index { unsigned long memsize; const void *src_buf; unsigned long src_size; unsigned int hash_mask; struct index_entry *hash[GIT_FLEX_ARRAY]; }; struct git_delta_index * git_delta_create_index(const void *buf, unsigned long bufsize) { unsigned int i, hsize, hmask, entries, prev_val, *hash_count; const unsigned char *data, *buffer = buf; struct git_delta_index *index; struct index_entry *entry, **hash; void *mem; unsigned long memsize; if (!buf || !bufsize) return NULL; /* Determine index hash size. Note that indexing skips the first byte to allow for optimizing the rabin polynomial initialization in create_delta(). */ entries = (unsigned int)(bufsize - 1) / RABIN_WINDOW; if (bufsize >= 0xffffffffUL) { /* * Current delta format can't encode offsets into * reference buffer with more than 32 bits. */ entries = 0xfffffffeU / RABIN_WINDOW; } hsize = entries / 4; for (i = 4; (1u << i) < hsize && i < 31; i++); hsize = 1 << i; hmask = hsize - 1; /* allocate lookup index */ memsize = sizeof(*index) + sizeof(*hash) * hsize + sizeof(*entry) * entries; mem = git__malloc(memsize); if (!mem) return NULL; index = mem; mem = index->hash; hash = mem; mem = hash + hsize; entry = mem; index->memsize = memsize; index->src_buf = buf; index->src_size = bufsize; index->hash_mask = hmask; memset(hash, 0, hsize * sizeof(*hash)); /* allocate an array to count hash entries */ hash_count = git__calloc(hsize, sizeof(*hash_count)); if (!hash_count) { git__free(index); return NULL; } /* then populate the index */ prev_val = ~0; for (data = buffer + entries * RABIN_WINDOW - RABIN_WINDOW; data >= buffer; data -= RABIN_WINDOW) { unsigned int val = 0; for (i = 1; i <= RABIN_WINDOW; i++) val = ((val << 8) | data[i]) ^ T[val >> RABIN_SHIFT]; if (val == prev_val) { /* keep the lowest of consecutive identical blocks */ entry[-1].ptr = data + RABIN_WINDOW; } else { prev_val = val; i = val & hmask; entry->ptr = data + RABIN_WINDOW; entry->val = val; entry->next = hash[i]; hash[i] = entry++; hash_count[i]++; } } /* * Determine a limit on the number of entries in the same hash * bucket. This guard us against patological data sets causing * really bad hash distribution with most entries in the same hash * bucket that would bring us to O(m*n) computing costs (m and n * corresponding to reference and target buffer sizes). * * Make sure none of the hash buckets has more entries than * we're willing to test. Otherwise we cull the entry list * uniformly to still preserve a good repartition across * the reference buffer. */ for (i = 0; i < hsize; i++) { if (hash_count[i] < HASH_LIMIT) continue; entry = hash[i]; do { struct index_entry *keep = entry; int skip = hash_count[i] / HASH_LIMIT / 2; do { entry = entry->next; } while(--skip && entry); keep->next = entry; } while (entry); } git__free(hash_count); return index; } void git_delta_free_index(struct git_delta_index *index) { git__free(index); } unsigned long git_delta_sizeof_index(struct git_delta_index *index) { if (index) return index->memsize; else return 0; } /* * The maximum size for any opcode sequence, including the initial header * plus rabin window plus biggest copy. */ #define MAX_OP_SIZE (5 + 5 + 1 + RABIN_WINDOW + 7) void * git_delta_create( const struct git_delta_index *index, const void *trg_buf, unsigned long trg_size, unsigned long *delta_size, unsigned long max_size) { unsigned int i, outpos, outsize, moff, msize, val; int inscnt; const unsigned char *ref_data, *ref_top, *data, *top; unsigned char *out; if (!trg_buf || !trg_size) return NULL; outpos = 0; outsize = 8192; if (max_size && outsize >= max_size) outsize = (unsigned int)(max_size + MAX_OP_SIZE + 1); out = git__malloc(outsize); if (!out) return NULL; /* store reference buffer size */ i = index->src_size; while (i >= 0x80) { out[outpos++] = i | 0x80; i >>= 7; } out[outpos++] = i; /* store target buffer size */ i = trg_size; while (i >= 0x80) { out[outpos++] = i | 0x80; i >>= 7; } out[outpos++] = i; ref_data = index->src_buf; ref_top = ref_data + index->src_size; data = trg_buf; top = (const unsigned char *) trg_buf + trg_size; outpos++; val = 0; for (i = 0; i < RABIN_WINDOW && data < top; i++, data++) { out[outpos++] = *data; val = ((val << 8) | *data) ^ T[val >> RABIN_SHIFT]; } inscnt = i; moff = 0; msize = 0; while (data < top) { if (msize < 4096) { struct index_entry *entry; val ^= U[data[-RABIN_WINDOW]]; val = ((val << 8) | *data) ^ T[val >> RABIN_SHIFT]; i = val & index->hash_mask; for (entry = index->hash[i]; entry; entry = entry->next) { const unsigned char *ref = entry->ptr; const unsigned char *src = data; unsigned int ref_size = (unsigned int)(ref_top - ref); if (entry->val != val) continue; if (ref_size > (unsigned int)(top - src)) ref_size = (unsigned int)(top - src); if (ref_size <= msize) break; while (ref_size-- && *src++ == *ref) ref++; if (msize < (unsigned int)(ref - entry->ptr)) { /* this is our best match so far */ msize = (unsigned int)(ref - entry->ptr); moff = (unsigned int)(entry->ptr - ref_data); if (msize >= 4096) /* good enough */ break; } } } if (msize < 4) { if (!inscnt) outpos++; out[outpos++] = *data++; inscnt++; if (inscnt == 0x7f) { out[outpos - inscnt - 1] = inscnt; inscnt = 0; } msize = 0; } else { unsigned int left; unsigned char *op; if (inscnt) { while (moff && ref_data[moff-1] == data[-1]) { /* we can match one byte back */ msize++; moff--; data--; outpos--; if (--inscnt) continue; outpos--; /* remove count slot */ inscnt--; /* make it -1 */ break; } out[outpos - inscnt - 1] = inscnt; inscnt = 0; } /* A copy op is currently limited to 64KB (pack v2) */ left = (msize < 0x10000) ? 0 : (msize - 0x10000); msize -= left; op = out + outpos++; i = 0x80; if (moff & 0x000000ff) out[outpos++] = moff >> 0, i |= 0x01; if (moff & 0x0000ff00) out[outpos++] = moff >> 8, i |= 0x02; if (moff & 0x00ff0000) out[outpos++] = moff >> 16, i |= 0x04; if (moff & 0xff000000) out[outpos++] = moff >> 24, i |= 0x08; if (msize & 0x00ff) out[outpos++] = msize >> 0, i |= 0x10; if (msize & 0xff00) out[outpos++] = msize >> 8, i |= 0x20; *op = i; data += msize; moff += msize; msize = left; if (msize < 4096) { int j; val = 0; for (j = -RABIN_WINDOW; j < 0; j++) val = ((val << 8) | data[j]) ^ T[val >> RABIN_SHIFT]; } } if (outpos >= outsize - MAX_OP_SIZE) { void *tmp = out; outsize = outsize * 3 / 2; if (max_size && outsize >= max_size) outsize = max_size + MAX_OP_SIZE + 1; if (max_size && outpos > max_size) break; out = git__realloc(out, outsize); if (!out) { git__free(tmp); return NULL; } } } if (inscnt) out[outpos - inscnt - 1] = inscnt; if (max_size && outpos > max_size) { git__free(out); return NULL; } *delta_size = outpos; return out; } libgit2-0.19.0/src/delta.h000066400000000000000000000070501216214232500151660ustar00rootroot00000000000000/* * diff-delta code taken from git.git. See diff-delta.c for details. * */ #ifndef INCLUDE_git_delta_h__ #define INCLUDE_git_delta_h__ #include "common.h" /* opaque object for delta index */ struct git_delta_index; /* * create_delta_index: compute index data from given buffer * * This returns a pointer to a struct delta_index that should be passed to * subsequent create_delta() calls, or to free_delta_index(). A NULL pointer * is returned on failure. The given buffer must not be freed nor altered * before free_delta_index() is called. The returned pointer must be freed * using free_delta_index(). */ extern struct git_delta_index * git_delta_create_index(const void *buf, unsigned long bufsize); /* * free_delta_index: free the index created by create_delta_index() * * Given pointer must be what create_delta_index() returned, or NULL. */ extern void git_delta_free_index(struct git_delta_index *index); /* * sizeof_delta_index: returns memory usage of delta index * * Given pointer must be what create_delta_index() returned, or NULL. */ extern unsigned long git_delta_sizeof_index(struct git_delta_index *index); /* * create_delta: create a delta from given index for the given buffer * * This function may be called multiple times with different buffers using * the same delta_index pointer. If max_delta_size is non-zero and the * resulting delta is to be larger than max_delta_size then NULL is returned. * On success, a non-NULL pointer to the buffer with the delta data is * returned and *delta_size is updated with its size. The returned buffer * must be freed by the caller. */ extern void *git_delta_create( const struct git_delta_index *index, const void *buf, unsigned long bufsize, unsigned long *delta_size, unsigned long max_delta_size); /* * diff_delta: create a delta from source buffer to target buffer * * If max_delta_size is non-zero and the resulting delta is to be larger * than max_delta_size then NULL is returned. On success, a non-NULL * pointer to the buffer with the delta data is returned and *delta_size is * updated with its size. The returned buffer must be freed by the caller. */ GIT_INLINE(void *) git_delta( const void *src_buf, unsigned long src_bufsize, const void *trg_buf, unsigned long trg_bufsize, unsigned long *delta_size, unsigned long max_delta_size) { struct git_delta_index *index = git_delta_create_index(src_buf, src_bufsize); if (index) { void *delta = git_delta_create( index, trg_buf, trg_bufsize, delta_size, max_delta_size); git_delta_free_index(index); return delta; } return NULL; } /* * patch_delta: recreate target buffer given source buffer and delta data * * On success, a non-NULL pointer to the target buffer is returned and * *trg_bufsize is updated with its size. On failure a NULL pointer is * returned. The returned buffer must be freed by the caller. */ extern void *git_delta_patch( const void *src_buf, unsigned long src_size, const void *delta_buf, unsigned long delta_size, unsigned long *dst_size); /* the smallest possible delta size is 4 bytes */ #define GIT_DELTA_SIZE_MIN 4 /* * This must be called twice on the delta data buffer, first to get the * expected source buffer size, and again to get the target buffer size. */ GIT_INLINE(unsigned long) git_delta_get_hdr_size( const unsigned char **datap, const unsigned char *top) { const unsigned char *data = *datap; unsigned long cmd, size = 0; int i = 0; do { cmd = *data++; size |= (cmd & 0x7f) << i; i += 7; } while (cmd & 0x80 && data < top); *datap = data; return size; } #endif libgit2-0.19.0/src/diff.c000066400000000000000000001067301216214232500150050ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #include "common.h" #include "diff.h" #include "fileops.h" #include "config.h" #include "attr_file.h" #include "filter.h" #include "pathspec.h" #include "index.h" #include "odb.h" #define DIFF_FLAG_IS_SET(DIFF,FLAG) (((DIFF)->opts.flags & (FLAG)) != 0) #define DIFF_FLAG_ISNT_SET(DIFF,FLAG) (((DIFF)->opts.flags & (FLAG)) == 0) #define DIFF_FLAG_SET(DIFF,FLAG,VAL) (DIFF)->opts.flags = \ (VAL) ? ((DIFF)->opts.flags | (FLAG)) : ((DIFF)->opts.flags & ~(VAL)) static git_diff_delta *diff_delta__alloc( git_diff_list *diff, git_delta_t status, const char *path) { git_diff_delta *delta = git__calloc(1, sizeof(git_diff_delta)); if (!delta) return NULL; delta->old_file.path = git_pool_strdup(&diff->pool, path); if (delta->old_file.path == NULL) { git__free(delta); return NULL; } delta->new_file.path = delta->old_file.path; if (DIFF_FLAG_IS_SET(diff, GIT_DIFF_REVERSE)) { switch (status) { case GIT_DELTA_ADDED: status = GIT_DELTA_DELETED; break; case GIT_DELTA_DELETED: status = GIT_DELTA_ADDED; break; default: break; /* leave other status values alone */ } } delta->status = status; return delta; } static int diff_notify( const git_diff_list *diff, const git_diff_delta *delta, const char *matched_pathspec) { if (!diff->opts.notify_cb) return 0; return diff->opts.notify_cb( diff, delta, matched_pathspec, diff->opts.notify_payload); } static int diff_delta__from_one( git_diff_list *diff, git_delta_t status, const git_index_entry *entry) { git_diff_delta *delta; const char *matched_pathspec; int notify_res; if (status == GIT_DELTA_IGNORED && DIFF_FLAG_ISNT_SET(diff, GIT_DIFF_INCLUDE_IGNORED)) return 0; if (status == GIT_DELTA_UNTRACKED && DIFF_FLAG_ISNT_SET(diff, GIT_DIFF_INCLUDE_UNTRACKED)) return 0; if (entry->mode == GIT_FILEMODE_COMMIT && DIFF_FLAG_IS_SET(diff, GIT_DIFF_IGNORE_SUBMODULES)) return 0; if (!git_pathspec_match_path( &diff->pathspec, entry->path, DIFF_FLAG_IS_SET(diff, GIT_DIFF_DISABLE_PATHSPEC_MATCH), DIFF_FLAG_IS_SET(diff, GIT_DIFF_DELTAS_ARE_ICASE), &matched_pathspec)) return 0; delta = diff_delta__alloc(diff, status, entry->path); GITERR_CHECK_ALLOC(delta); /* This fn is just for single-sided diffs */ assert(status != GIT_DELTA_MODIFIED); if (delta->status == GIT_DELTA_DELETED) { delta->old_file.mode = entry->mode; delta->old_file.size = entry->file_size; git_oid_cpy(&delta->old_file.oid, &entry->oid); } else /* ADDED, IGNORED, UNTRACKED */ { delta->new_file.mode = entry->mode; delta->new_file.size = entry->file_size; git_oid_cpy(&delta->new_file.oid, &entry->oid); } delta->old_file.flags |= GIT_DIFF_FLAG_VALID_OID; if (delta->status == GIT_DELTA_DELETED || !git_oid_iszero(&delta->new_file.oid)) delta->new_file.flags |= GIT_DIFF_FLAG_VALID_OID; notify_res = diff_notify(diff, delta, matched_pathspec); if (notify_res) git__free(delta); else if (git_vector_insert(&diff->deltas, delta) < 0) { git__free(delta); return -1; } return notify_res < 0 ? GIT_EUSER : 0; } static int diff_delta__from_two( git_diff_list *diff, git_delta_t status, const git_index_entry *old_entry, uint32_t old_mode, const git_index_entry *new_entry, uint32_t new_mode, git_oid *new_oid, const char *matched_pathspec) { git_diff_delta *delta; int notify_res; const char *canonical_path = old_entry->path; if (status == GIT_DELTA_UNMODIFIED && DIFF_FLAG_ISNT_SET(diff, GIT_DIFF_INCLUDE_UNMODIFIED)) return 0; if (old_entry->mode == GIT_FILEMODE_COMMIT && new_entry->mode == GIT_FILEMODE_COMMIT && DIFF_FLAG_IS_SET(diff, GIT_DIFF_IGNORE_SUBMODULES)) return 0; if (DIFF_FLAG_IS_SET(diff, GIT_DIFF_REVERSE)) { uint32_t temp_mode = old_mode; const git_index_entry *temp_entry = old_entry; old_entry = new_entry; new_entry = temp_entry; old_mode = new_mode; new_mode = temp_mode; } delta = diff_delta__alloc(diff, status, canonical_path); GITERR_CHECK_ALLOC(delta); git_oid_cpy(&delta->old_file.oid, &old_entry->oid); delta->old_file.size = old_entry->file_size; delta->old_file.mode = old_mode; delta->old_file.flags |= GIT_DIFF_FLAG_VALID_OID; git_oid_cpy(&delta->new_file.oid, &new_entry->oid); delta->new_file.size = new_entry->file_size; delta->new_file.mode = new_mode; if (new_oid) { if (DIFF_FLAG_IS_SET(diff, GIT_DIFF_REVERSE)) git_oid_cpy(&delta->old_file.oid, new_oid); else git_oid_cpy(&delta->new_file.oid, new_oid); } if (new_oid || !git_oid_iszero(&new_entry->oid)) delta->new_file.flags |= GIT_DIFF_FLAG_VALID_OID; notify_res = diff_notify(diff, delta, matched_pathspec); if (notify_res) git__free(delta); else if (git_vector_insert(&diff->deltas, delta) < 0) { git__free(delta); return -1; } return notify_res < 0 ? GIT_EUSER : 0; } static git_diff_delta *diff_delta__last_for_item( git_diff_list *diff, const git_index_entry *item) { git_diff_delta *delta = git_vector_last(&diff->deltas); if (!delta) return NULL; switch (delta->status) { case GIT_DELTA_UNMODIFIED: case GIT_DELTA_DELETED: if (git_oid__cmp(&delta->old_file.oid, &item->oid) == 0) return delta; break; case GIT_DELTA_ADDED: if (git_oid__cmp(&delta->new_file.oid, &item->oid) == 0) return delta; break; case GIT_DELTA_UNTRACKED: if (diff->strcomp(delta->new_file.path, item->path) == 0 && git_oid__cmp(&delta->new_file.oid, &item->oid) == 0) return delta; break; case GIT_DELTA_MODIFIED: if (git_oid__cmp(&delta->old_file.oid, &item->oid) == 0 || git_oid__cmp(&delta->new_file.oid, &item->oid) == 0) return delta; break; default: break; } return NULL; } static char *diff_strdup_prefix(git_pool *pool, const char *prefix) { size_t len = strlen(prefix); /* append '/' at end if needed */ if (len > 0 && prefix[len - 1] != '/') return git_pool_strcat(pool, prefix, "/"); else return git_pool_strndup(pool, prefix, len + 1); } GIT_INLINE(const char *) diff_delta__path(const git_diff_delta *delta) { const char *str = delta->old_file.path; if (!str || delta->status == GIT_DELTA_ADDED || delta->status == GIT_DELTA_RENAMED || delta->status == GIT_DELTA_COPIED) str = delta->new_file.path; return str; } int git_diff_delta__cmp(const void *a, const void *b) { const git_diff_delta *da = a, *db = b; int val = strcmp(diff_delta__path(da), diff_delta__path(db)); return val ? val : ((int)da->status - (int)db->status); } int git_diff_delta__casecmp(const void *a, const void *b) { const git_diff_delta *da = a, *db = b; int val = strcasecmp(diff_delta__path(da), diff_delta__path(db)); return val ? val : ((int)da->status - (int)db->status); } bool git_diff_delta__should_skip( const git_diff_options *opts, const git_diff_delta *delta) { uint32_t flags = opts ? opts->flags : 0; if (delta->status == GIT_DELTA_UNMODIFIED && (flags & GIT_DIFF_INCLUDE_UNMODIFIED) == 0) return true; if (delta->status == GIT_DELTA_IGNORED && (flags & GIT_DIFF_INCLUDE_IGNORED) == 0) return true; if (delta->status == GIT_DELTA_UNTRACKED && (flags & GIT_DIFF_INCLUDE_UNTRACKED) == 0) return true; return false; } static int config_bool(git_config *cfg, const char *name, int defvalue) { int val = defvalue; if (git_config_get_bool(&val, cfg, name) < 0) giterr_clear(); return val; } static int config_int(git_config *cfg, const char *name, int defvalue) { int val = defvalue; if (git_config_get_int32(&val, cfg, name) < 0) giterr_clear(); return val; } static const char *diff_mnemonic_prefix( git_iterator_type_t type, bool left_side) { const char *pfx = ""; switch (type) { case GIT_ITERATOR_TYPE_EMPTY: pfx = "c"; break; case GIT_ITERATOR_TYPE_TREE: pfx = "c"; break; case GIT_ITERATOR_TYPE_INDEX: pfx = "i"; break; case GIT_ITERATOR_TYPE_WORKDIR: pfx = "w"; break; case GIT_ITERATOR_TYPE_FS: pfx = left_side ? "1" : "2"; break; default: break; } /* note: without a deeper look at pathspecs, there is no easy way * to get the (o)bject / (w)ork tree mnemonics working... */ return pfx; } static git_diff_list *diff_list_alloc( git_repository *repo, git_iterator *old_iter, git_iterator *new_iter) { git_diff_options dflt = GIT_DIFF_OPTIONS_INIT; git_diff_list *diff = git__calloc(1, sizeof(git_diff_list)); if (!diff) return NULL; assert(repo && old_iter && new_iter); GIT_REFCOUNT_INC(diff); diff->repo = repo; diff->old_src = old_iter->type; diff->new_src = new_iter->type; memcpy(&diff->opts, &dflt, sizeof(diff->opts)); if (git_vector_init(&diff->deltas, 0, git_diff_delta__cmp) < 0 || git_pool_init(&diff->pool, 1, 0) < 0) { git_diff_list_free(diff); return NULL; } /* Use case-insensitive compare if either iterator has * the ignore_case bit set */ if (!git_iterator_ignore_case(old_iter) && !git_iterator_ignore_case(new_iter)) { diff->opts.flags &= ~GIT_DIFF_DELTAS_ARE_ICASE; diff->strcomp = git__strcmp; diff->strncomp = git__strncmp; diff->pfxcomp = git__prefixcmp; diff->entrycomp = git_index_entry__cmp; } else { diff->opts.flags |= GIT_DIFF_DELTAS_ARE_ICASE; diff->strcomp = git__strcasecmp; diff->strncomp = git__strncasecmp; diff->pfxcomp = git__prefixcmp_icase; diff->entrycomp = git_index_entry__cmp_icase; git_vector_set_cmp(&diff->deltas, git_diff_delta__casecmp); } return diff; } static int diff_list_apply_options( git_diff_list *diff, const git_diff_options *opts) { git_config *cfg; git_repository *repo = diff->repo; git_pool *pool = &diff->pool; int val; if (opts) { /* copy user options (except case sensitivity info from iterators) */ bool icase = DIFF_FLAG_IS_SET(diff, GIT_DIFF_DELTAS_ARE_ICASE); memcpy(&diff->opts, opts, sizeof(diff->opts)); DIFF_FLAG_SET(diff, GIT_DIFF_DELTAS_ARE_ICASE, icase); /* initialize pathspec from options */ if (git_pathspec_init(&diff->pathspec, &opts->pathspec, pool) < 0) return -1; } /* flag INCLUDE_TYPECHANGE_TREES implies INCLUDE_TYPECHANGE */ if (DIFF_FLAG_IS_SET(diff, GIT_DIFF_INCLUDE_TYPECHANGE_TREES)) diff->opts.flags |= GIT_DIFF_INCLUDE_TYPECHANGE; /* flag INCLUDE_UNTRACKED_CONTENT implies INCLUDE_UNTRACKED */ if (DIFF_FLAG_IS_SET(diff, GIT_DIFF_INCLUDE_UNTRACKED_CONTENT)) diff->opts.flags |= GIT_DIFF_INCLUDE_UNTRACKED; /* load config values that affect diff behavior */ if (git_repository_config__weakptr(&cfg, repo) < 0) return -1; if (!git_repository__cvar(&val, repo, GIT_CVAR_SYMLINKS) && val) diff->diffcaps = diff->diffcaps | GIT_DIFFCAPS_HAS_SYMLINKS; if (!git_repository__cvar(&val, repo, GIT_CVAR_IGNORESTAT) && val) diff->diffcaps = diff->diffcaps | GIT_DIFFCAPS_ASSUME_UNCHANGED; if ((diff->opts.flags & GIT_DIFF_IGNORE_FILEMODE) == 0 && !git_repository__cvar(&val, repo, GIT_CVAR_FILEMODE) && val) diff->diffcaps = diff->diffcaps | GIT_DIFFCAPS_TRUST_MODE_BITS; if (!git_repository__cvar(&val, repo, GIT_CVAR_TRUSTCTIME) && val) diff->diffcaps = diff->diffcaps | GIT_DIFFCAPS_TRUST_CTIME; /* Don't set GIT_DIFFCAPS_USE_DEV - compile time option in core git */ /* Set GIT_DIFFCAPS_TRUST_NANOSECS on a platform basis */ diff->diffcaps = diff->diffcaps | GIT_DIFFCAPS_TRUST_NANOSECS; /* If not given explicit `opts`, check `diff.xyz` configs */ if (!opts) { diff->opts.context_lines = config_int(cfg, "diff.context", 3); if (config_bool(cfg, "diff.ignoreSubmodules", 0)) diff->opts.flags |= GIT_DIFF_IGNORE_SUBMODULES; } /* if either prefix is not set, figure out appropriate value */ if (!diff->opts.old_prefix || !diff->opts.new_prefix) { const char *use_old = DIFF_OLD_PREFIX_DEFAULT; const char *use_new = DIFF_NEW_PREFIX_DEFAULT; if (config_bool(cfg, "diff.noprefix", 0)) { use_old = use_new = ""; } else if (config_bool(cfg, "diff.mnemonicprefix", 0)) { use_old = diff_mnemonic_prefix(diff->old_src, true); use_new = diff_mnemonic_prefix(diff->new_src, false); } if (!diff->opts.old_prefix) diff->opts.old_prefix = use_old; if (!diff->opts.new_prefix) diff->opts.new_prefix = use_new; } /* strdup prefix from pool so we're not dependent on external data */ diff->opts.old_prefix = diff_strdup_prefix(pool, diff->opts.old_prefix); diff->opts.new_prefix = diff_strdup_prefix(pool, diff->opts.new_prefix); if (!diff->opts.old_prefix || !diff->opts.new_prefix) return -1; if (DIFF_FLAG_IS_SET(diff, GIT_DIFF_REVERSE)) { const char *swap = diff->opts.old_prefix; diff->opts.old_prefix = diff->opts.new_prefix; diff->opts.new_prefix = swap; } return 0; } static void diff_list_free(git_diff_list *diff) { git_diff_delta *delta; unsigned int i; git_vector_foreach(&diff->deltas, i, delta) { git__free(delta); diff->deltas.contents[i] = NULL; } git_vector_free(&diff->deltas); git_pathspec_free(&diff->pathspec); git_pool_clear(&diff->pool); git__memzero(diff, sizeof(*diff)); git__free(diff); } void git_diff_list_free(git_diff_list *diff) { if (!diff) return; GIT_REFCOUNT_DEC(diff, diff_list_free); } void git_diff_list_addref(git_diff_list *diff) { GIT_REFCOUNT_INC(diff); } int git_diff__oid_for_file( git_repository *repo, const char *path, uint16_t mode, git_off_t size, git_oid *oid) { int result = 0; git_buf full_path = GIT_BUF_INIT; if (git_buf_joinpath( &full_path, git_repository_workdir(repo), path) < 0) return -1; if (!mode) { struct stat st; if (p_stat(path, &st) < 0) { giterr_set(GITERR_OS, "Could not stat '%s'", path); result = -1; goto cleanup; } mode = st.st_mode; size = st.st_size; } /* calculate OID for file if possible */ if (S_ISGITLINK(mode)) { git_submodule *sm; const git_oid *sm_oid; if (!git_submodule_lookup(&sm, repo, path) && (sm_oid = git_submodule_wd_id(sm)) != NULL) git_oid_cpy(oid, sm_oid); else { /* if submodule lookup failed probably just in an intermediate * state where some init hasn't happened, so ignore the error */ giterr_clear(); memset(oid, 0, sizeof(*oid)); } } else if (S_ISLNK(mode)) { result = git_odb__hashlink(oid, full_path.ptr); } else if (!git__is_sizet(size)) { giterr_set(GITERR_OS, "File size overflow (for 32-bits) on '%s'", path); result = -1; } else { git_vector filters = GIT_VECTOR_INIT; result = git_filters_load(&filters, repo, path, GIT_FILTER_TO_ODB); if (result >= 0) { int fd = git_futils_open_ro(full_path.ptr); if (fd < 0) result = fd; else { result = git_odb__hashfd_filtered( oid, fd, (size_t)size, GIT_OBJ_BLOB, &filters); p_close(fd); } } git_filters_free(&filters); } cleanup: git_buf_free(&full_path); return result; } static bool diff_time_eq( const git_index_time *a, const git_index_time *b, bool use_nanos) { return a->seconds == b->seconds && (!use_nanos || a->nanoseconds == b->nanoseconds); } typedef struct { git_repository *repo; git_iterator *old_iter; git_iterator *new_iter; const git_index_entry *oitem; const git_index_entry *nitem; git_buf ignore_prefix; } diff_in_progress; #define MODE_BITS_MASK 0000777 static int maybe_modified_submodule( git_delta_t *status, git_oid *found_oid, git_diff_list *diff, diff_in_progress *info) { int error = 0; git_submodule *sub; unsigned int sm_status = 0; const git_oid *sm_oid; *status = GIT_DELTA_UNMODIFIED; if (!DIFF_FLAG_IS_SET(diff, GIT_DIFF_IGNORE_SUBMODULES) && !(error = git_submodule_lookup( &sub, diff->repo, info->nitem->path)) && git_submodule_ignore(sub) != GIT_SUBMODULE_IGNORE_ALL && !(error = git_submodule_status(&sm_status, sub))) { /* check IS_WD_UNMODIFIED because this case is only used * when the new side of the diff is the working directory */ if (!GIT_SUBMODULE_STATUS_IS_WD_UNMODIFIED(sm_status)) *status = GIT_DELTA_MODIFIED; /* grab OID while we are here */ if (git_oid_iszero(&info->nitem->oid) && (sm_oid = git_submodule_wd_id(sub)) != NULL) git_oid_cpy(found_oid, sm_oid); } /* GIT_EEXISTS means a dir with .git in it was found - ignore it */ if (error == GIT_EEXISTS) { giterr_clear(); error = 0; } return error; } static int maybe_modified( git_diff_list *diff, diff_in_progress *info) { git_oid noid; git_delta_t status = GIT_DELTA_MODIFIED; const git_index_entry *oitem = info->oitem; const git_index_entry *nitem = info->nitem; unsigned int omode = oitem->mode; unsigned int nmode = nitem->mode; bool new_is_workdir = (info->new_iter->type == GIT_ITERATOR_TYPE_WORKDIR); const char *matched_pathspec; if (!git_pathspec_match_path( &diff->pathspec, oitem->path, DIFF_FLAG_IS_SET(diff, GIT_DIFF_DISABLE_PATHSPEC_MATCH), DIFF_FLAG_IS_SET(diff, GIT_DIFF_DELTAS_ARE_ICASE), &matched_pathspec)) return 0; memset(&noid, 0, sizeof(noid)); /* on platforms with no symlinks, preserve mode of existing symlinks */ if (S_ISLNK(omode) && S_ISREG(nmode) && new_is_workdir && !(diff->diffcaps & GIT_DIFFCAPS_HAS_SYMLINKS)) nmode = omode; /* on platforms with no execmode, just preserve old mode */ if (!(diff->diffcaps & GIT_DIFFCAPS_TRUST_MODE_BITS) && (nmode & MODE_BITS_MASK) != (omode & MODE_BITS_MASK) && new_is_workdir) nmode = (nmode & ~MODE_BITS_MASK) | (omode & MODE_BITS_MASK); /* support "assume unchanged" (poorly, b/c we still stat everything) */ if ((diff->diffcaps & GIT_DIFFCAPS_ASSUME_UNCHANGED) != 0) status = (oitem->flags_extended & GIT_IDXENTRY_INTENT_TO_ADD) ? GIT_DELTA_MODIFIED : GIT_DELTA_UNMODIFIED; /* support "skip worktree" index bit */ else if ((oitem->flags_extended & GIT_IDXENTRY_SKIP_WORKTREE) != 0) status = GIT_DELTA_UNMODIFIED; /* if basic type of file changed, then split into delete and add */ else if (GIT_MODE_TYPE(omode) != GIT_MODE_TYPE(nmode)) { if (DIFF_FLAG_IS_SET(diff, GIT_DIFF_INCLUDE_TYPECHANGE)) status = GIT_DELTA_TYPECHANGE; else { if (diff_delta__from_one(diff, GIT_DELTA_DELETED, oitem) < 0 || diff_delta__from_one(diff, GIT_DELTA_ADDED, nitem) < 0) return -1; return 0; } } /* if oids and modes match (and are valid), then file is unmodified */ else if (git_oid_equal(&oitem->oid, &nitem->oid) && omode == nmode && !git_oid_iszero(&oitem->oid)) status = GIT_DELTA_UNMODIFIED; /* if we have an unknown OID and a workdir iterator, then check some * circumstances that can accelerate things or need special handling */ else if (git_oid_iszero(&nitem->oid) && new_is_workdir) { bool use_ctime = ((diff->diffcaps & GIT_DIFFCAPS_TRUST_CTIME) != 0); bool use_nanos = ((diff->diffcaps & GIT_DIFFCAPS_TRUST_NANOSECS) != 0); status = GIT_DELTA_UNMODIFIED; /* TODO: add check against index file st_mtime to avoid racy-git */ if (S_ISGITLINK(nmode)) { if (maybe_modified_submodule(&status, &noid, diff, info) < 0) return -1; } /* if the stat data looks different, then mark modified - this just * means that the OID will be recalculated below to confirm change */ else if (omode != nmode || oitem->file_size != nitem->file_size || !diff_time_eq(&oitem->mtime, &nitem->mtime, use_nanos) || (use_ctime && !diff_time_eq(&oitem->ctime, &nitem->ctime, use_nanos)) || oitem->ino != nitem->ino || oitem->uid != nitem->uid || oitem->gid != nitem->gid) status = GIT_DELTA_MODIFIED; } /* if mode is GITLINK and submodules are ignored, then skip */ else if (S_ISGITLINK(nmode) && DIFF_FLAG_IS_SET(diff, GIT_DIFF_IGNORE_SUBMODULES)) status = GIT_DELTA_UNMODIFIED; /* if we got here and decided that the files are modified, but we * haven't calculated the OID of the new item, then calculate it now */ if (status != GIT_DELTA_UNMODIFIED && git_oid_iszero(&nitem->oid)) { if (git_oid_iszero(&noid)) { if (git_diff__oid_for_file(diff->repo, nitem->path, nitem->mode, nitem->file_size, &noid) < 0) return -1; } /* if oid matches, then mark unmodified (except submodules, where * the filesystem content may be modified even if the oid still * matches between the index and the workdir HEAD) */ if (omode == nmode && !S_ISGITLINK(omode) && git_oid_equal(&oitem->oid, &noid)) status = GIT_DELTA_UNMODIFIED; } return diff_delta__from_two( diff, status, oitem, omode, nitem, nmode, git_oid_iszero(&noid) ? NULL : &noid, matched_pathspec); } static bool entry_is_prefixed( git_diff_list *diff, const git_index_entry *item, const git_index_entry *prefix_item) { size_t pathlen; if (!item || diff->pfxcomp(item->path, prefix_item->path) != 0) return false; pathlen = strlen(prefix_item->path); return (prefix_item->path[pathlen - 1] == '/' || item->path[pathlen] == '\0' || item->path[pathlen] == '/'); } static int diff_scan_inside_untracked_dir( git_diff_list *diff, diff_in_progress *info, git_delta_t *delta_type) { int error = 0; git_buf base = GIT_BUF_INIT; bool is_ignored; *delta_type = GIT_DELTA_IGNORED; git_buf_sets(&base, info->nitem->path); /* advance into untracked directory */ if ((error = git_iterator_advance_into(&info->nitem, info->new_iter)) < 0) { /* skip ahead if empty */ if (error == GIT_ENOTFOUND) { giterr_clear(); error = git_iterator_advance(&info->nitem, info->new_iter); } goto done; } /* look for actual untracked file */ while (info->nitem != NULL && !diff->pfxcomp(info->nitem->path, git_buf_cstr(&base))) { is_ignored = git_iterator_current_is_ignored(info->new_iter); /* need to recurse into non-ignored directories */ if (!is_ignored && S_ISDIR(info->nitem->mode)) { error = git_iterator_advance_into(&info->nitem, info->new_iter); if (!error) continue; else if (error == GIT_ENOTFOUND) { error = 0; is_ignored = true; /* treat empty as ignored */ } else break; /* real error, must stop */ } /* found a non-ignored item - treat parent dir as untracked */ if (!is_ignored) { *delta_type = GIT_DELTA_UNTRACKED; break; } if ((error = git_iterator_advance(&info->nitem, info->new_iter)) < 0) break; } /* finish off scan */ while (info->nitem != NULL && !diff->pfxcomp(info->nitem->path, git_buf_cstr(&base))) { if ((error = git_iterator_advance(&info->nitem, info->new_iter)) < 0) break; } done: git_buf_free(&base); if (error == GIT_ITEROVER) error = 0; return error; } static int handle_unmatched_new_item( git_diff_list *diff, diff_in_progress *info) { int error = 0; const git_index_entry *nitem = info->nitem; git_delta_t delta_type = GIT_DELTA_UNTRACKED; bool contains_oitem; /* check if this is a prefix of the other side */ contains_oitem = entry_is_prefixed(diff, info->oitem, nitem); /* check if this is contained in an ignored parent directory */ if (git_buf_len(&info->ignore_prefix)) { if (diff->pfxcomp(nitem->path, git_buf_cstr(&info->ignore_prefix)) == 0) delta_type = GIT_DELTA_IGNORED; else git_buf_clear(&info->ignore_prefix); } if (S_ISDIR(nitem->mode)) { bool recurse_into_dir = contains_oitem; /* if not already inside an ignored dir, check if this is ignored */ if (delta_type != GIT_DELTA_IGNORED && git_iterator_current_is_ignored(info->new_iter)) { delta_type = GIT_DELTA_IGNORED; git_buf_sets(&info->ignore_prefix, nitem->path); } /* check if user requests recursion into this type of dir */ recurse_into_dir = contains_oitem || (delta_type == GIT_DELTA_UNTRACKED && DIFF_FLAG_IS_SET(diff, GIT_DIFF_RECURSE_UNTRACKED_DIRS)) || (delta_type == GIT_DELTA_IGNORED && DIFF_FLAG_IS_SET(diff, GIT_DIFF_RECURSE_IGNORED_DIRS)); /* do not advance into directories that contain a .git file */ if (recurse_into_dir) { git_buf *full = NULL; if (git_iterator_current_workdir_path(&full, info->new_iter) < 0) return -1; if (full && git_path_contains_dir(full, DOT_GIT)) recurse_into_dir = false; } /* still have to look into untracked directories to match core git - * with no untracked files, directory is treated as ignored */ if (!recurse_into_dir && delta_type == GIT_DELTA_UNTRACKED && DIFF_FLAG_ISNT_SET(diff, GIT_DIFF_FAST_UNTRACKED_DIRS)) { git_diff_delta *last; /* attempt to insert record for this directory */ if ((error = diff_delta__from_one(diff, delta_type, nitem)) < 0) return error; /* if delta wasn't created (because of rules), just skip ahead */ last = diff_delta__last_for_item(diff, nitem); if (!last) return git_iterator_advance(&info->nitem, info->new_iter); /* iterate into dir looking for an actual untracked file */ if (diff_scan_inside_untracked_dir(diff, info, &delta_type) < 0) return -1; /* it iteration changed delta type, the update the record */ if (delta_type == GIT_DELTA_IGNORED) { last->status = GIT_DELTA_IGNORED; /* remove the record if we don't want ignored records */ if (DIFF_FLAG_ISNT_SET(diff, GIT_DIFF_INCLUDE_IGNORED)) { git_vector_pop(&diff->deltas); git__free(last); } } return 0; } /* try to advance into directory if necessary */ if (recurse_into_dir) { error = git_iterator_advance_into(&info->nitem, info->new_iter); /* if real error or no error, proceed with iteration */ if (error != GIT_ENOTFOUND) return error; giterr_clear(); /* if directory is empty, can't advance into it, so either skip * it or ignore it */ if (contains_oitem) return git_iterator_advance(&info->nitem, info->new_iter); delta_type = GIT_DELTA_IGNORED; } } /* In core git, the next two checks are effectively reversed -- * i.e. when an file contained in an ignored directory is explicitly * ignored, it shows up as an ignored file in the diff list, even though * other untracked files in the same directory are skipped completely. * * To me, this seems odd. If the directory is ignored and the file is * untracked, we should skip it consistently, regardless of whether it * happens to match a pattern in the ignore file. * * To match the core git behavior, reverse the following two if checks * so that individual file ignores are checked before container * directory exclusions are used to skip the file. */ else if (delta_type == GIT_DELTA_IGNORED && DIFF_FLAG_ISNT_SET(diff, GIT_DIFF_RECURSE_IGNORED_DIRS)) /* item contained in ignored directory, so skip over it */ return git_iterator_advance(&info->nitem, info->new_iter); else if (git_iterator_current_is_ignored(info->new_iter)) delta_type = GIT_DELTA_IGNORED; else if (info->new_iter->type != GIT_ITERATOR_TYPE_WORKDIR) delta_type = GIT_DELTA_ADDED; /* Actually create the record for this item if necessary */ if ((error = diff_delta__from_one(diff, delta_type, nitem)) < 0) return error; /* If user requested TYPECHANGE records, then check for that instead of * just generating an ADDED/UNTRACKED record */ if (delta_type != GIT_DELTA_IGNORED && DIFF_FLAG_IS_SET(diff, GIT_DIFF_INCLUDE_TYPECHANGE_TREES) && contains_oitem) { /* this entry was prefixed with a tree - make TYPECHANGE */ git_diff_delta *last = diff_delta__last_for_item(diff, nitem); if (last) { last->status = GIT_DELTA_TYPECHANGE; last->old_file.mode = GIT_FILEMODE_TREE; } } return git_iterator_advance(&info->nitem, info->new_iter); } static int handle_unmatched_old_item( git_diff_list *diff, diff_in_progress *info) { int error = diff_delta__from_one(diff, GIT_DELTA_DELETED, info->oitem); if (error < 0) return error; /* if we are generating TYPECHANGE records then check for that * instead of just generating a DELETE record */ if (DIFF_FLAG_IS_SET(diff, GIT_DIFF_INCLUDE_TYPECHANGE_TREES) && entry_is_prefixed(diff, info->nitem, info->oitem)) { /* this entry has become a tree! convert to TYPECHANGE */ git_diff_delta *last = diff_delta__last_for_item(diff, info->oitem); if (last) { last->status = GIT_DELTA_TYPECHANGE; last->new_file.mode = GIT_FILEMODE_TREE; } /* If new_iter is a workdir iterator, then this situation * will certainly be followed by a series of untracked items. * Unless RECURSE_UNTRACKED_DIRS is set, skip over them... */ if (S_ISDIR(info->nitem->mode) && DIFF_FLAG_ISNT_SET(diff, GIT_DIFF_RECURSE_UNTRACKED_DIRS)) return git_iterator_advance(&info->nitem, info->new_iter); } return git_iterator_advance(&info->oitem, info->old_iter); } static int handle_matched_item( git_diff_list *diff, diff_in_progress *info) { int error = 0; if ((error = maybe_modified(diff, info)) < 0) return error; if (!(error = git_iterator_advance(&info->oitem, info->old_iter)) || error == GIT_ITEROVER) error = git_iterator_advance(&info->nitem, info->new_iter); return error; } int git_diff__from_iterators( git_diff_list **diff_ptr, git_repository *repo, git_iterator *old_iter, git_iterator *new_iter, const git_diff_options *opts) { int error = 0; diff_in_progress info; git_diff_list *diff; *diff_ptr = NULL; diff = diff_list_alloc(repo, old_iter, new_iter); GITERR_CHECK_ALLOC(diff); info.repo = repo; info.old_iter = old_iter; info.new_iter = new_iter; git_buf_init(&info.ignore_prefix, 0); /* make iterators have matching icase behavior */ if (DIFF_FLAG_IS_SET(diff, GIT_DIFF_DELTAS_ARE_ICASE)) { if ((error = git_iterator_set_ignore_case(old_iter, true)) < 0 || (error = git_iterator_set_ignore_case(new_iter, true)) < 0) goto cleanup; } /* finish initialization */ if ((error = diff_list_apply_options(diff, opts)) < 0) goto cleanup; if ((error = git_iterator_current(&info.oitem, old_iter)) < 0 && error != GIT_ITEROVER) goto cleanup; if ((error = git_iterator_current(&info.nitem, new_iter)) < 0 && error != GIT_ITEROVER) goto cleanup; error = 0; /* run iterators building diffs */ while (!error && (info.oitem || info.nitem)) { int cmp = info.oitem ? (info.nitem ? diff->entrycomp(info.oitem, info.nitem) : -1) : 1; /* create DELETED records for old items not matched in new */ if (cmp < 0) error = handle_unmatched_old_item(diff, &info); /* create ADDED, TRACKED, or IGNORED records for new items not * matched in old (and/or descend into directories as needed) */ else if (cmp > 0) error = handle_unmatched_new_item(diff, &info); /* otherwise item paths match, so create MODIFIED record * (or ADDED and DELETED pair if type changed) */ else error = handle_matched_item(diff, &info); /* because we are iterating over two lists, ignore ITEROVER */ if (error == GIT_ITEROVER) error = 0; } cleanup: if (!error) *diff_ptr = diff; else git_diff_list_free(diff); git_buf_free(&info.ignore_prefix); return error; } #define DIFF_FROM_ITERATORS(MAKE_FIRST, MAKE_SECOND) do { \ git_iterator *a = NULL, *b = NULL; \ char *pfx = opts ? git_pathspec_prefix(&opts->pathspec) : NULL; \ GITERR_CHECK_VERSION(opts, GIT_DIFF_OPTIONS_VERSION, "git_diff_options"); \ if (!(error = MAKE_FIRST) && !(error = MAKE_SECOND)) \ error = git_diff__from_iterators(diff, repo, a, b, opts); \ git__free(pfx); git_iterator_free(a); git_iterator_free(b); \ } while (0) int git_diff_tree_to_tree( git_diff_list **diff, git_repository *repo, git_tree *old_tree, git_tree *new_tree, const git_diff_options *opts) { int error = 0; git_iterator_flag_t iflag = GIT_ITERATOR_DONT_IGNORE_CASE; assert(diff && repo); /* for tree to tree diff, be case sensitive even if the index is * currently case insensitive, unless the user explicitly asked * for case insensitivity */ if (opts && (opts->flags & GIT_DIFF_DELTAS_ARE_ICASE) != 0) iflag = GIT_ITERATOR_IGNORE_CASE; DIFF_FROM_ITERATORS( git_iterator_for_tree(&a, old_tree, iflag, pfx, pfx), git_iterator_for_tree(&b, new_tree, iflag, pfx, pfx) ); return error; } int git_diff_tree_to_index( git_diff_list **diff, git_repository *repo, git_tree *old_tree, git_index *index, const git_diff_options *opts) { int error = 0; bool reset_index_ignore_case = false; assert(diff && repo); if (!index && (error = git_repository_index__weakptr(&index, repo)) < 0) return error; if (index->ignore_case) { git_index__set_ignore_case(index, false); reset_index_ignore_case = true; } DIFF_FROM_ITERATORS( git_iterator_for_tree(&a, old_tree, 0, pfx, pfx), git_iterator_for_index(&b, index, 0, pfx, pfx) ); if (reset_index_ignore_case) { git_index__set_ignore_case(index, true); if (!error) { git_diff_list *d = *diff; d->opts.flags |= GIT_DIFF_DELTAS_ARE_ICASE; d->strcomp = git__strcasecmp; d->strncomp = git__strncasecmp; d->pfxcomp = git__prefixcmp_icase; d->entrycomp = git_index_entry__cmp_icase; git_vector_set_cmp(&d->deltas, git_diff_delta__casecmp); git_vector_sort(&d->deltas); } } return error; } int git_diff_index_to_workdir( git_diff_list **diff, git_repository *repo, git_index *index, const git_diff_options *opts) { int error = 0; assert(diff && repo); if (!index && (error = git_repository_index__weakptr(&index, repo)) < 0) return error; DIFF_FROM_ITERATORS( git_iterator_for_index(&a, index, 0, pfx, pfx), git_iterator_for_workdir( &b, repo, GIT_ITERATOR_DONT_AUTOEXPAND, pfx, pfx) ); return error; } int git_diff_tree_to_workdir( git_diff_list **diff, git_repository *repo, git_tree *old_tree, const git_diff_options *opts) { int error = 0; assert(diff && repo); DIFF_FROM_ITERATORS( git_iterator_for_tree(&a, old_tree, 0, pfx, pfx), git_iterator_for_workdir( &b, repo, GIT_ITERATOR_DONT_AUTOEXPAND, pfx, pfx) ); return error; } size_t git_diff_num_deltas(git_diff_list *diff) { assert(diff); return (size_t)diff->deltas.length; } size_t git_diff_num_deltas_of_type(git_diff_list *diff, git_delta_t type) { size_t i, count = 0; git_diff_delta *delta; assert(diff); git_vector_foreach(&diff->deltas, i, delta) { count += (delta->status == type); } return count; } int git_diff__paired_foreach( git_diff_list *head2idx, git_diff_list *idx2wd, int (*cb)(git_diff_delta *h2i, git_diff_delta *i2w, void *payload), void *payload) { int cmp; git_diff_delta *h2i, *i2w; size_t i, j, i_max, j_max; int (*strcomp)(const char *, const char *) = git__strcmp; bool icase_mismatch; i_max = head2idx ? head2idx->deltas.length : 0; j_max = idx2wd ? idx2wd->deltas.length : 0; /* At some point, tree-to-index diffs will probably never ignore case, * even if that isn't true now. Index-to-workdir diffs may or may not * ignore case, but the index filename for the idx2wd diff should * still be using the canonical case-preserving name. * * Therefore the main thing we need to do here is make sure the diffs * are traversed in a compatible order. To do this, we temporarily * resort a mismatched diff to get the order correct. */ icase_mismatch = (head2idx != NULL && idx2wd != NULL && ((head2idx->opts.flags ^ idx2wd->opts.flags) & GIT_DIFF_DELTAS_ARE_ICASE)); /* force case-sensitive delta sort */ if (icase_mismatch) { if (head2idx->opts.flags & GIT_DIFF_DELTAS_ARE_ICASE) { git_vector_set_cmp(&head2idx->deltas, git_diff_delta__cmp); git_vector_sort(&head2idx->deltas); } else { git_vector_set_cmp(&idx2wd->deltas, git_diff_delta__cmp); git_vector_sort(&idx2wd->deltas); } } else if (head2idx->opts.flags & GIT_DIFF_DELTAS_ARE_ICASE) strcomp = git__strcasecmp; for (i = 0, j = 0; i < i_max || j < j_max; ) { h2i = head2idx ? GIT_VECTOR_GET(&head2idx->deltas, i) : NULL; i2w = idx2wd ? GIT_VECTOR_GET(&idx2wd->deltas, j) : NULL; cmp = !i2w ? -1 : !h2i ? 1 : strcomp(h2i->new_file.path, i2w->old_file.path); if (cmp < 0) { if (cb(h2i, NULL, payload)) return GIT_EUSER; i++; } else if (cmp > 0) { if (cb(NULL, i2w, payload)) return GIT_EUSER; j++; } else { if (cb(h2i, i2w, payload)) return GIT_EUSER; i++; j++; } } /* restore case-insensitive delta sort */ if (icase_mismatch) { if (head2idx->opts.flags & GIT_DIFF_DELTAS_ARE_ICASE) { git_vector_set_cmp(&head2idx->deltas, git_diff_delta__casecmp); git_vector_sort(&head2idx->deltas); } else { git_vector_set_cmp(&idx2wd->deltas, git_diff_delta__casecmp); git_vector_sort(&idx2wd->deltas); } } return 0; } libgit2-0.19.0/src/diff.h000066400000000000000000000071401216214232500150050ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #ifndef INCLUDE_diff_h__ #define INCLUDE_diff_h__ #include "git2/diff.h" #include "git2/oid.h" #include #include "vector.h" #include "buffer.h" #include "iterator.h" #include "repository.h" #include "pool.h" #define DIFF_OLD_PREFIX_DEFAULT "a/" #define DIFF_NEW_PREFIX_DEFAULT "b/" enum { GIT_DIFFCAPS_HAS_SYMLINKS = (1 << 0), /* symlinks on platform? */ GIT_DIFFCAPS_ASSUME_UNCHANGED = (1 << 1), /* use stat? */ GIT_DIFFCAPS_TRUST_MODE_BITS = (1 << 2), /* use st_mode? */ GIT_DIFFCAPS_TRUST_CTIME = (1 << 3), /* use st_ctime? */ GIT_DIFFCAPS_USE_DEV = (1 << 4), /* use st_dev? */ GIT_DIFFCAPS_TRUST_NANOSECS = (1 << 5), /* use stat time nanoseconds */ }; #define DIFF_FLAGS_KNOWN_BINARY (GIT_DIFF_FLAG_BINARY|GIT_DIFF_FLAG_NOT_BINARY) #define DIFF_FLAGS_NOT_BINARY (GIT_DIFF_FLAG_NOT_BINARY|GIT_DIFF_FLAG__NO_DATA) enum { GIT_DIFF_FLAG__FREE_PATH = (1 << 7), /* `path` is allocated memory */ GIT_DIFF_FLAG__FREE_DATA = (1 << 8), /* internal file data is allocated */ GIT_DIFF_FLAG__UNMAP_DATA = (1 << 9), /* internal file data is mmap'ed */ GIT_DIFF_FLAG__NO_DATA = (1 << 10), /* file data should not be loaded */ GIT_DIFF_FLAG__FREE_BLOB = (1 << 11), /* release the blob when done */ GIT_DIFF_FLAG__LOADED = (1 << 12), /* file data has been loaded */ GIT_DIFF_FLAG__TO_DELETE = (1 << 16), /* delete entry during rename det. */ GIT_DIFF_FLAG__TO_SPLIT = (1 << 17), /* split entry during rename det. */ GIT_DIFF_FLAG__IS_RENAME_TARGET = (1 << 18), GIT_DIFF_FLAG__IS_RENAME_SOURCE = (1 << 19), GIT_DIFF_FLAG__HAS_SELF_SIMILARITY = (1 << 20), }; #define GIT_DIFF_FLAG__CLEAR_INTERNAL(F) (F) = ((F) & 0x00FFFF) #define GIT_DIFF__VERBOSE (1 << 30) struct git_diff_list { git_refcount rc; git_repository *repo; git_diff_options opts; git_vector pathspec; git_vector deltas; /* vector of git_diff_delta */ git_pool pool; git_iterator_type_t old_src; git_iterator_type_t new_src; uint32_t diffcaps; int (*strcomp)(const char *, const char *); int (*strncomp)(const char *, const char *, size_t); int (*pfxcomp)(const char *str, const char *pfx); int (*entrycomp)(const void *a, const void *b); }; extern void git_diff__cleanup_modes( uint32_t diffcaps, uint32_t *omode, uint32_t *nmode); extern void git_diff_list_addref(git_diff_list *diff); extern int git_diff_delta__cmp(const void *a, const void *b); extern int git_diff_delta__casecmp(const void *a, const void *b); extern bool git_diff_delta__should_skip( const git_diff_options *opts, const git_diff_delta *delta); extern int git_diff__oid_for_file( git_repository *, const char *, uint16_t, git_off_t, git_oid *); extern int git_diff__from_iterators( git_diff_list **diff_ptr, git_repository *repo, git_iterator *old_iter, git_iterator *new_iter, const git_diff_options *opts); extern int git_diff__paired_foreach( git_diff_list *idx2head, git_diff_list *wd2idx, int (*cb)(git_diff_delta *i2h, git_diff_delta *w2i, void *payload), void *payload); extern int git_diff_find_similar__hashsig_for_file( void **out, const git_diff_file *f, const char *path, void *p); extern int git_diff_find_similar__hashsig_for_buf( void **out, const git_diff_file *f, const char *buf, size_t len, void *p); extern void git_diff_find_similar__hashsig_free(void *sig, void *payload); extern int git_diff_find_similar__calc_similarity( int *score, void *siga, void *sigb, void *payload); #endif libgit2-0.19.0/src/diff_driver.c000066400000000000000000000236751216214232500163660ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #include "common.h" #include "git2/attr.h" #include "diff.h" #include "diff_patch.h" #include "diff_driver.h" #include "strmap.h" #include "map.h" #include "buf_text.h" #include "repository.h" GIT__USE_STRMAP; typedef enum { DIFF_DRIVER_AUTO = 0, DIFF_DRIVER_BINARY = 1, DIFF_DRIVER_TEXT = 2, DIFF_DRIVER_PATTERNLIST = 3, } git_diff_driver_t; enum { DIFF_CONTEXT_FIND_NORMAL = 0, DIFF_CONTEXT_FIND_ICASE = (1 << 0), DIFF_CONTEXT_FIND_EXT = (1 << 1), }; /* data for finding function context for a given file type */ struct git_diff_driver { git_diff_driver_t type; uint32_t binary_flags; uint32_t other_flags; git_array_t(regex_t) fn_patterns; regex_t word_pattern; char name[GIT_FLEX_ARRAY]; }; struct git_diff_driver_registry { git_strmap *drivers; }; #define FORCE_DIFFABLE (GIT_DIFF_FORCE_TEXT | GIT_DIFF_FORCE_BINARY) static git_diff_driver global_drivers[3] = { { DIFF_DRIVER_AUTO, 0, 0, }, { DIFF_DRIVER_BINARY, GIT_DIFF_FORCE_BINARY, 0 }, { DIFF_DRIVER_TEXT, GIT_DIFF_FORCE_TEXT, 0 }, }; git_diff_driver_registry *git_diff_driver_registry_new() { git_diff_driver_registry *reg = git__calloc(1, sizeof(git_diff_driver_registry)); if (!reg) return NULL; if ((reg->drivers = git_strmap_alloc()) == NULL) { git_diff_driver_registry_free(reg); return NULL; } return reg; } void git_diff_driver_registry_free(git_diff_driver_registry *reg) { git_diff_driver *drv; if (!reg) return; git_strmap_foreach_value(reg->drivers, drv, git_diff_driver_free(drv)); git_strmap_free(reg->drivers); git__free(reg); } static int diff_driver_add_funcname( git_diff_driver *drv, const char *name, int regex_flags) { int error; regex_t re, *re_ptr; if ((error = regcomp(&re, name, regex_flags)) != 0) { /* TODO: warning about bad regex instead of failure */ error = giterr_set_regex(&re, error); regfree(&re); return error; } re_ptr = git_array_alloc(drv->fn_patterns); GITERR_CHECK_ALLOC(re_ptr); memcpy(re_ptr, &re, sizeof(re)); return 0; } static int diff_driver_xfuncname(const git_config_entry *entry, void *payload) { return diff_driver_add_funcname(payload, entry->value, REG_EXTENDED); } static int diff_driver_funcname(const git_config_entry *entry, void *payload) { return diff_driver_add_funcname(payload, entry->value, 0); } static git_diff_driver_registry *git_repository_driver_registry( git_repository *repo) { if (!repo->diff_drivers) { git_diff_driver_registry *reg = git_diff_driver_registry_new(); reg = git__compare_and_swap(&repo->diff_drivers, NULL, reg); if (reg != NULL) /* if we race, free losing allocation */ git_diff_driver_registry_free(reg); } if (!repo->diff_drivers) giterr_set(GITERR_REPOSITORY, "Unable to create diff driver registry"); return repo->diff_drivers; } static int git_diff_driver_load( git_diff_driver **out, git_repository *repo, const char *driver_name) { int error = 0, bval; git_diff_driver_registry *reg; git_diff_driver *drv; size_t namelen = strlen(driver_name); khiter_t pos; git_config *cfg; git_buf name = GIT_BUF_INIT; const char *val; bool found_driver = false; reg = git_repository_driver_registry(repo); if (!reg) return -1; else { pos = git_strmap_lookup_index(reg->drivers, driver_name); if (git_strmap_valid_index(reg->drivers, pos)) { *out = git_strmap_value_at(reg->drivers, pos); return 0; } } /* if you can't read config for repo, just use default driver */ if (git_repository_config__weakptr(&cfg, repo) < 0) { giterr_clear(); return GIT_ENOTFOUND; } drv = git__calloc(1, sizeof(git_diff_driver) + namelen + 1); GITERR_CHECK_ALLOC(drv); drv->type = DIFF_DRIVER_AUTO; memcpy(drv->name, driver_name, namelen); if ((error = git_buf_printf(&name, "diff.%s.binary", driver_name)) < 0) goto done; if ((error = git_config_get_string(&val, cfg, name.ptr)) < 0) { if (error != GIT_ENOTFOUND) goto done; /* diff..binary unspecified, so just continue */ giterr_clear(); } else if (git_config_parse_bool(&bval, val) < 0) { /* TODO: warn that diff..binary has invalid value */ giterr_clear(); } else if (bval) { /* if diff..binary is true, just return the binary driver */ *out = &global_drivers[DIFF_DRIVER_BINARY]; goto done; } else { /* if diff..binary is false, force binary checks off */ /* but still may have custom function context patterns, etc. */ drv->binary_flags = GIT_DIFF_FORCE_TEXT; found_driver = true; } /* TODO: warn if diff..command or diff..textconv are set */ git_buf_truncate(&name, namelen + strlen("diff..")); git_buf_put(&name, "xfuncname", strlen("xfuncname")); if ((error = git_config_get_multivar( cfg, name.ptr, NULL, diff_driver_xfuncname, drv)) < 0) { if (error != GIT_ENOTFOUND) goto done; giterr_clear(); /* no diff..xfuncname, so just continue */ } git_buf_truncate(&name, namelen + strlen("diff..")); git_buf_put(&name, "funcname", strlen("funcname")); if ((error = git_config_get_multivar( cfg, name.ptr, NULL, diff_driver_funcname, drv)) < 0) { if (error != GIT_ENOTFOUND) goto done; giterr_clear(); /* no diff..funcname, so just continue */ } /* if we found any patterns, set driver type to use correct callback */ if (git_array_size(drv->fn_patterns) > 0) { drv->type = DIFF_DRIVER_PATTERNLIST; found_driver = true; } git_buf_truncate(&name, namelen + strlen("diff..")); git_buf_put(&name, "wordregex", strlen("wordregex")); if ((error = git_config_get_string(&val, cfg, name.ptr)) < 0) { if (error != GIT_ENOTFOUND) goto done; giterr_clear(); /* no diff..wordregex, so just continue */ } else if ((error = regcomp(&drv->word_pattern, val, REG_EXTENDED)) != 0) { /* TODO: warning about bad regex instead of failure */ error = giterr_set_regex(&drv->word_pattern, error); goto done; } else { found_driver = true; } /* TODO: look up diff..algorithm to turn on minimal / patience * diff in drv->other_flags */ /* if no driver config found at all, fall back on AUTO driver */ if (!found_driver) goto done; /* store driver in registry */ git_strmap_insert(reg->drivers, drv->name, drv, error); if (error < 0) goto done; *out = drv; done: git_buf_free(&name); if (!*out) *out = &global_drivers[DIFF_DRIVER_AUTO]; if (drv && drv != *out) git_diff_driver_free(drv); return error; } int git_diff_driver_lookup( git_diff_driver **out, git_repository *repo, const char *path) { int error = 0; const char *value; assert(out); if (!repo || !path || !strlen(path)) goto use_auto; if ((error = git_attr_get(&value, repo, 0, path, "diff")) < 0) return error; if (GIT_ATTR_UNSPECIFIED(value)) /* just use the auto value */; else if (GIT_ATTR_FALSE(value)) *out = &global_drivers[DIFF_DRIVER_BINARY]; else if (GIT_ATTR_TRUE(value)) *out = &global_drivers[DIFF_DRIVER_TEXT]; /* otherwise look for driver information in config and build driver */ else if ((error = git_diff_driver_load(out, repo, value)) < 0) { if (error != GIT_ENOTFOUND) return error; else giterr_clear(); } use_auto: if (!*out) *out = &global_drivers[DIFF_DRIVER_AUTO]; return 0; } void git_diff_driver_free(git_diff_driver *driver) { size_t i; if (!driver) return; for (i = 0; i < git_array_size(driver->fn_patterns); ++i) regfree(git_array_get(driver->fn_patterns, i)); git_array_clear(driver->fn_patterns); regfree(&driver->word_pattern); git__free(driver); } void git_diff_driver_update_options( uint32_t *option_flags, git_diff_driver *driver) { if ((*option_flags & FORCE_DIFFABLE) == 0) *option_flags |= driver->binary_flags; *option_flags |= driver->other_flags; } int git_diff_driver_content_is_binary( git_diff_driver *driver, const char *content, size_t content_len) { const git_buf search = { (char *)content, 0, min(content_len, 4000) }; GIT_UNUSED(driver); /* TODO: provide encoding / binary detection callbacks that can * be UTF-8 aware, etc. For now, instead of trying to be smart, * let's just use the simple NUL-byte detection that core git uses. */ /* previously was: if (git_buf_text_is_binary(&search)) */ if (git_buf_text_contains_nul(&search)) return 1; return 0; } static int diff_context_line__simple( git_diff_driver *driver, const char *line, size_t line_len) { GIT_UNUSED(driver); GIT_UNUSED(line_len); return (git__isalpha(*line) || *line == '_' || *line == '$'); } static int diff_context_line__pattern_match( git_diff_driver *driver, const char *line, size_t line_len) { size_t i; GIT_UNUSED(line_len); for (i = 0; i < git_array_size(driver->fn_patterns); ++i) { if (!regexec(git_array_get(driver->fn_patterns, i), line, 0, NULL, 0)) return true; } return false; } static long diff_context_find( const char *line, long line_len, char *out, long out_size, void *payload) { git_diff_find_context_payload *ctxt = payload; if (git_buf_set(&ctxt->line, line, (size_t)line_len) < 0) return -1; git_buf_rtrim(&ctxt->line); if (!ctxt->line.size) return -1; if (!ctxt->match_line || !ctxt->match_line(ctxt->driver, ctxt->line.ptr, ctxt->line.size)) return -1; git_buf_truncate(&ctxt->line, (size_t)out_size); git_buf_copy_cstr(out, (size_t)out_size, &ctxt->line); return (long)ctxt->line.size; } void git_diff_find_context_init( git_diff_find_context_fn *findfn_out, git_diff_find_context_payload *payload_out, git_diff_driver *driver) { *findfn_out = driver ? diff_context_find : NULL; memset(payload_out, 0, sizeof(*payload_out)); if (driver) { payload_out->driver = driver; payload_out->match_line = (driver->type == DIFF_DRIVER_PATTERNLIST) ? diff_context_line__pattern_match : diff_context_line__simple; git_buf_init(&payload_out->line, 0); } } void git_diff_find_context_clear(git_diff_find_context_payload *payload) { if (payload) { git_buf_free(&payload->line); payload->driver = NULL; } } libgit2-0.19.0/src/diff_driver.h000066400000000000000000000027771216214232500163730ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #ifndef INCLUDE_diff_driver_h__ #define INCLUDE_diff_driver_h__ #include "common.h" #include "buffer.h" typedef struct git_diff_driver_registry git_diff_driver_registry; git_diff_driver_registry *git_diff_driver_registry_new(void); void git_diff_driver_registry_free(git_diff_driver_registry *); typedef struct git_diff_driver git_diff_driver; int git_diff_driver_lookup(git_diff_driver **, git_repository *, const char *); void git_diff_driver_free(git_diff_driver *); /* diff option flags to force off and on for this driver */ void git_diff_driver_update_options(uint32_t *option_flags, git_diff_driver *); /* returns -1 meaning "unknown", 0 meaning not binary, 1 meaning binary */ int git_diff_driver_content_is_binary( git_diff_driver *, const char *content, size_t content_len); typedef long (*git_diff_find_context_fn)( const char *, long, char *, long, void *); typedef int (*git_diff_find_context_line)( git_diff_driver *, const char *, size_t); typedef struct { git_diff_driver *driver; git_diff_find_context_line match_line; git_buf line; } git_diff_find_context_payload; void git_diff_find_context_init( git_diff_find_context_fn *findfn_out, git_diff_find_context_payload *payload_out, git_diff_driver *driver); void git_diff_find_context_clear(git_diff_find_context_payload *); #endif libgit2-0.19.0/src/diff_file.c000066400000000000000000000257111216214232500160030ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #include "common.h" #include "git2/blob.h" #include "git2/submodule.h" #include "diff.h" #include "diff_file.h" #include "odb.h" #include "fileops.h" #include "filter.h" #define DIFF_MAX_FILESIZE 0x20000000 static bool diff_file_content_binary_by_size(git_diff_file_content *fc) { /* if we have diff opts, check max_size vs file size */ if ((fc->file->flags & DIFF_FLAGS_KNOWN_BINARY) == 0 && fc->opts_max_size > 0 && fc->file->size > fc->opts_max_size) fc->file->flags |= GIT_DIFF_FLAG_BINARY; return ((fc->file->flags & GIT_DIFF_FLAG_BINARY) != 0); } static void diff_file_content_binary_by_content(git_diff_file_content *fc) { if ((fc->file->flags & DIFF_FLAGS_KNOWN_BINARY) != 0) return; switch (git_diff_driver_content_is_binary( fc->driver, fc->map.data, fc->map.len)) { case 0: fc->file->flags |= GIT_DIFF_FLAG_NOT_BINARY; break; case 1: fc->file->flags |= GIT_DIFF_FLAG_BINARY; break; default: break; } } static int diff_file_content_init_common( git_diff_file_content *fc, const git_diff_options *opts) { fc->opts_flags = opts ? opts->flags : GIT_DIFF_NORMAL; if (opts && opts->max_size >= 0) fc->opts_max_size = opts->max_size ? opts->max_size : DIFF_MAX_FILESIZE; if (fc->src == GIT_ITERATOR_TYPE_EMPTY) fc->src = GIT_ITERATOR_TYPE_TREE; if (!fc->driver && git_diff_driver_lookup(&fc->driver, fc->repo, fc->file->path) < 0) return -1; /* give driver a chance to modify options */ git_diff_driver_update_options(&fc->opts_flags, fc->driver); /* make sure file is conceivable mmap-able */ if ((git_off_t)((size_t)fc->file->size) != fc->file->size) fc->file->flags |= GIT_DIFF_FLAG_BINARY; /* check if user is forcing text diff the file */ else if (fc->opts_flags & GIT_DIFF_FORCE_TEXT) { fc->file->flags &= ~GIT_DIFF_FLAG_BINARY; fc->file->flags |= GIT_DIFF_FLAG_NOT_BINARY; } /* check if user is forcing binary diff the file */ else if (fc->opts_flags & GIT_DIFF_FORCE_BINARY) { fc->file->flags &= ~GIT_DIFF_FLAG_NOT_BINARY; fc->file->flags |= GIT_DIFF_FLAG_BINARY; } diff_file_content_binary_by_size(fc); if ((fc->flags & GIT_DIFF_FLAG__NO_DATA) != 0) { fc->flags |= GIT_DIFF_FLAG__LOADED; fc->map.len = 0; fc->map.data = ""; } if ((fc->flags & GIT_DIFF_FLAG__LOADED) != 0) diff_file_content_binary_by_content(fc); return 0; } int git_diff_file_content__init_from_diff( git_diff_file_content *fc, git_diff_list *diff, size_t delta_index, bool use_old) { git_diff_delta *delta = git_vector_get(&diff->deltas, delta_index); bool has_data = true; memset(fc, 0, sizeof(*fc)); fc->repo = diff->repo; fc->file = use_old ? &delta->old_file : &delta->new_file; fc->src = use_old ? diff->old_src : diff->new_src; if (git_diff_driver_lookup(&fc->driver, fc->repo, fc->file->path) < 0) return -1; switch (delta->status) { case GIT_DELTA_ADDED: has_data = !use_old; break; case GIT_DELTA_DELETED: has_data = use_old; break; case GIT_DELTA_UNTRACKED: has_data = !use_old && (diff->opts.flags & GIT_DIFF_INCLUDE_UNTRACKED_CONTENT) != 0; break; case GIT_DELTA_MODIFIED: case GIT_DELTA_COPIED: case GIT_DELTA_RENAMED: break; default: has_data = false; break; } if (!has_data) fc->flags |= GIT_DIFF_FLAG__NO_DATA; return diff_file_content_init_common(fc, &diff->opts); } int git_diff_file_content__init_from_blob( git_diff_file_content *fc, git_repository *repo, const git_diff_options *opts, const git_blob *blob, git_diff_file *as_file) { memset(fc, 0, sizeof(*fc)); fc->repo = repo; fc->file = as_file; fc->blob = blob; if (!blob) { fc->flags |= GIT_DIFF_FLAG__NO_DATA; } else { fc->flags |= GIT_DIFF_FLAG__LOADED; fc->file->flags |= GIT_DIFF_FLAG_VALID_OID; fc->file->size = git_blob_rawsize(blob); fc->file->mode = GIT_FILEMODE_BLOB; git_oid_cpy(&fc->file->oid, git_blob_id(blob)); fc->map.len = (size_t)fc->file->size; fc->map.data = (char *)git_blob_rawcontent(blob); } return diff_file_content_init_common(fc, opts); } int git_diff_file_content__init_from_raw( git_diff_file_content *fc, git_repository *repo, const git_diff_options *opts, const char *buf, size_t buflen, git_diff_file *as_file) { memset(fc, 0, sizeof(*fc)); fc->repo = repo; fc->file = as_file; if (!buf) { fc->flags |= GIT_DIFF_FLAG__NO_DATA; } else { fc->flags |= GIT_DIFF_FLAG__LOADED; fc->file->flags |= GIT_DIFF_FLAG_VALID_OID; fc->file->size = buflen; fc->file->mode = GIT_FILEMODE_BLOB; git_odb_hash(&fc->file->oid, buf, buflen, GIT_OBJ_BLOB); fc->map.len = buflen; fc->map.data = (char *)buf; } return diff_file_content_init_common(fc, opts); } static int diff_file_content_commit_to_str( git_diff_file_content *fc, bool check_status) { char oid[GIT_OID_HEXSZ+1]; git_buf content = GIT_BUF_INIT; const char *status = ""; if (check_status) { int error = 0; git_submodule *sm = NULL; unsigned int sm_status = 0; const git_oid *sm_head; if ((error = git_submodule_lookup(&sm, fc->repo, fc->file->path)) < 0 || (error = git_submodule_status(&sm_status, sm)) < 0) { /* GIT_EEXISTS means a "submodule" that has not been git added */ if (error == GIT_EEXISTS) error = 0; return error; } /* update OID if we didn't have it previously */ if ((fc->file->flags & GIT_DIFF_FLAG_VALID_OID) == 0 && ((sm_head = git_submodule_wd_id(sm)) != NULL || (sm_head = git_submodule_head_id(sm)) != NULL)) { git_oid_cpy(&fc->file->oid, sm_head); fc->file->flags |= GIT_DIFF_FLAG_VALID_OID; } if (GIT_SUBMODULE_STATUS_IS_WD_DIRTY(sm_status)) status = "-dirty"; } git_oid_tostr(oid, sizeof(oid), &fc->file->oid); if (git_buf_printf(&content, "Subproject commit %s%s\n", oid, status) < 0) return -1; fc->map.len = git_buf_len(&content); fc->map.data = git_buf_detach(&content); fc->flags |= GIT_DIFF_FLAG__FREE_DATA; return 0; } static int diff_file_content_load_blob(git_diff_file_content *fc) { int error = 0; git_odb_object *odb_obj = NULL; if (git_oid_iszero(&fc->file->oid)) return 0; if (fc->file->mode == GIT_FILEMODE_COMMIT) return diff_file_content_commit_to_str(fc, false); /* if we don't know size, try to peek at object header first */ if (!fc->file->size) { git_odb *odb; size_t len; git_otype type; if (!(error = git_repository_odb__weakptr(&odb, fc->repo))) { error = git_odb__read_header_or_object( &odb_obj, &len, &type, odb, &fc->file->oid); git_odb_free(odb); } if (error) return error; fc->file->size = len; } if (diff_file_content_binary_by_size(fc)) return 0; if (odb_obj != NULL) { error = git_object__from_odb_object( (git_object **)&fc->blob, fc->repo, odb_obj, GIT_OBJ_BLOB); git_odb_object_free(odb_obj); } else { error = git_blob_lookup( (git_blob **)&fc->blob, fc->repo, &fc->file->oid); } if (!error) { fc->flags |= GIT_DIFF_FLAG__FREE_BLOB; fc->map.data = (void *)git_blob_rawcontent(fc->blob); fc->map.len = (size_t)git_blob_rawsize(fc->blob); } return error; } static int diff_file_content_load_workdir_symlink( git_diff_file_content *fc, git_buf *path) { ssize_t alloc_len, read_len; /* link path on disk could be UTF-16, so prepare a buffer that is * big enough to handle some UTF-8 data expansion */ alloc_len = (ssize_t)(fc->file->size * 2) + 1; fc->map.data = git__calloc(alloc_len, sizeof(char)); GITERR_CHECK_ALLOC(fc->map.data); fc->flags |= GIT_DIFF_FLAG__FREE_DATA; read_len = p_readlink(git_buf_cstr(path), fc->map.data, alloc_len); if (read_len < 0) { giterr_set(GITERR_OS, "Failed to read symlink '%s'", fc->file->path); return -1; } fc->map.len = read_len; return 0; } static int diff_file_content_load_workdir_file( git_diff_file_content *fc, git_buf *path) { int error = 0; git_vector filters = GIT_VECTOR_INIT; git_buf raw = GIT_BUF_INIT, filtered = GIT_BUF_INIT; git_file fd = git_futils_open_ro(git_buf_cstr(path)); if (fd < 0) return fd; if (!fc->file->size && !(fc->file->size = git_futils_filesize(fd))) goto cleanup; if (diff_file_content_binary_by_size(fc)) goto cleanup; if ((error = git_filters_load( &filters, fc->repo, fc->file->path, GIT_FILTER_TO_ODB)) < 0) goto cleanup; /* error >= is a filter count */ if (error == 0) { if (!(error = git_futils_mmap_ro( &fc->map, fd, 0, (size_t)fc->file->size))) fc->flags |= GIT_DIFF_FLAG__UNMAP_DATA; else /* fall through to try readbuffer below */ giterr_clear(); } if (error != 0) { error = git_futils_readbuffer_fd(&raw, fd, (size_t)fc->file->size); if (error < 0) goto cleanup; if (!filters.length) git_buf_swap(&filtered, &raw); else error = git_filters_apply(&filtered, &raw, &filters); if (!error) { fc->map.len = git_buf_len(&filtered); fc->map.data = git_buf_detach(&filtered); fc->flags |= GIT_DIFF_FLAG__FREE_DATA; } git_buf_free(&raw); git_buf_free(&filtered); } cleanup: git_filters_free(&filters); p_close(fd); return error; } static int diff_file_content_load_workdir(git_diff_file_content *fc) { int error = 0; git_buf path = GIT_BUF_INIT; if (fc->file->mode == GIT_FILEMODE_COMMIT) return diff_file_content_commit_to_str(fc, true); if (fc->file->mode == GIT_FILEMODE_TREE) return 0; if (git_buf_joinpath( &path, git_repository_workdir(fc->repo), fc->file->path) < 0) return -1; if (S_ISLNK(fc->file->mode)) error = diff_file_content_load_workdir_symlink(fc, &path); else error = diff_file_content_load_workdir_file(fc, &path); /* once data is loaded, update OID if we didn't have it previously */ if (!error && (fc->file->flags & GIT_DIFF_FLAG_VALID_OID) == 0) { error = git_odb_hash( &fc->file->oid, fc->map.data, fc->map.len, GIT_OBJ_BLOB); fc->file->flags |= GIT_DIFF_FLAG_VALID_OID; } git_buf_free(&path); return error; } int git_diff_file_content__load(git_diff_file_content *fc) { int error = 0; if ((fc->flags & GIT_DIFF_FLAG__LOADED) != 0) return 0; if ((fc->file->flags & GIT_DIFF_FLAG_BINARY) != 0) return 0; if (fc->src == GIT_ITERATOR_TYPE_WORKDIR) error = diff_file_content_load_workdir(fc); else error = diff_file_content_load_blob(fc); if (error) return error; fc->flags |= GIT_DIFF_FLAG__LOADED; diff_file_content_binary_by_content(fc); return 0; } void git_diff_file_content__unload(git_diff_file_content *fc) { if (fc->flags & GIT_DIFF_FLAG__FREE_DATA) { git__free(fc->map.data); fc->map.data = ""; fc->map.len = 0; fc->flags &= ~GIT_DIFF_FLAG__FREE_DATA; } else if (fc->flags & GIT_DIFF_FLAG__UNMAP_DATA) { git_futils_mmap_free(&fc->map); fc->map.data = ""; fc->map.len = 0; fc->flags &= ~GIT_DIFF_FLAG__UNMAP_DATA; } if (fc->flags & GIT_DIFF_FLAG__FREE_BLOB) { git_blob_free((git_blob *)fc->blob); fc->blob = NULL; fc->flags &= ~GIT_DIFF_FLAG__FREE_BLOB; } fc->flags &= ~GIT_DIFF_FLAG__LOADED; } void git_diff_file_content__clear(git_diff_file_content *fc) { git_diff_file_content__unload(fc); /* for now, nothing else to do */ } libgit2-0.19.0/src/diff_file.h000066400000000000000000000027701216214232500160100ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #ifndef INCLUDE_diff_file_h__ #define INCLUDE_diff_file_h__ #include "common.h" #include "diff.h" #include "diff_driver.h" #include "map.h" /* expanded information for one side of a delta */ typedef struct { git_repository *repo; git_diff_file *file; git_diff_driver *driver; uint32_t flags; uint32_t opts_flags; git_off_t opts_max_size; git_iterator_type_t src; const git_blob *blob; git_map map; } git_diff_file_content; extern int git_diff_file_content__init_from_diff( git_diff_file_content *fc, git_diff_list *diff, size_t delta_index, bool use_old); extern int git_diff_file_content__init_from_blob( git_diff_file_content *fc, git_repository *repo, const git_diff_options *opts, const git_blob *blob, git_diff_file *as_file); extern int git_diff_file_content__init_from_raw( git_diff_file_content *fc, git_repository *repo, const git_diff_options *opts, const char *buf, size_t buflen, git_diff_file *as_file); /* this loads the blob/file-on-disk as needed */ extern int git_diff_file_content__load(git_diff_file_content *fc); /* this releases the blob/file-in-memory */ extern void git_diff_file_content__unload(git_diff_file_content *fc); /* this unloads and also releases any other resources */ extern void git_diff_file_content__clear(git_diff_file_content *fc); #endif libgit2-0.19.0/src/diff_patch.c000066400000000000000000000571001216214232500161600ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #include "common.h" #include "diff.h" #include "diff_file.h" #include "diff_driver.h" #include "diff_patch.h" #include "diff_xdiff.h" /* cached information about a single span in a diff */ typedef struct diff_patch_line diff_patch_line; struct diff_patch_line { const char *ptr; size_t len; size_t lines, oldno, newno; char origin; }; /* cached information about a hunk in a diff */ typedef struct diff_patch_hunk diff_patch_hunk; struct diff_patch_hunk { git_diff_range range; char header[128]; size_t header_len; size_t line_start; size_t line_count; }; struct git_diff_patch { git_refcount rc; git_diff_list *diff; /* for refcount purposes, maybe NULL for blob diffs */ git_diff_delta *delta; size_t delta_index; git_diff_file_content ofile; git_diff_file_content nfile; uint32_t flags; git_array_t(diff_patch_hunk) hunks; git_array_t(diff_patch_line) lines; size_t oldno, newno; size_t content_size; git_pool flattened; }; enum { GIT_DIFF_PATCH_ALLOCATED = (1 << 0), GIT_DIFF_PATCH_INITIALIZED = (1 << 1), GIT_DIFF_PATCH_LOADED = (1 << 2), GIT_DIFF_PATCH_DIFFABLE = (1 << 3), GIT_DIFF_PATCH_DIFFED = (1 << 4), GIT_DIFF_PATCH_FLATTENED = (1 << 5), }; static void diff_output_init(git_diff_output*, const git_diff_options*, git_diff_file_cb, git_diff_hunk_cb, git_diff_data_cb, void*); static void diff_output_to_patch(git_diff_output *, git_diff_patch *); static void diff_patch_update_binary(git_diff_patch *patch) { if ((patch->delta->flags & DIFF_FLAGS_KNOWN_BINARY) != 0) return; if ((patch->ofile.file->flags & GIT_DIFF_FLAG_BINARY) != 0 || (patch->nfile.file->flags & GIT_DIFF_FLAG_BINARY) != 0) patch->delta->flags |= GIT_DIFF_FLAG_BINARY; else if ((patch->ofile.file->flags & DIFF_FLAGS_NOT_BINARY) != 0 && (patch->nfile.file->flags & DIFF_FLAGS_NOT_BINARY) != 0) patch->delta->flags |= GIT_DIFF_FLAG_NOT_BINARY; } static void diff_patch_init_common(git_diff_patch *patch) { diff_patch_update_binary(patch); if ((patch->delta->flags & GIT_DIFF_FLAG_BINARY) != 0) patch->flags |= GIT_DIFF_PATCH_LOADED; /* set LOADED but not DIFFABLE */ patch->flags |= GIT_DIFF_PATCH_INITIALIZED; if (patch->diff) git_diff_list_addref(patch->diff); } static int diff_patch_init_from_diff( git_diff_patch *patch, git_diff_list *diff, size_t delta_index) { int error = 0; memset(patch, 0, sizeof(*patch)); patch->diff = diff; patch->delta = git_vector_get(&diff->deltas, delta_index); patch->delta_index = delta_index; if ((error = git_diff_file_content__init_from_diff( &patch->ofile, diff, delta_index, true)) < 0 || (error = git_diff_file_content__init_from_diff( &patch->nfile, diff, delta_index, false)) < 0) return error; diff_patch_init_common(patch); return 0; } static int diff_patch_alloc_from_diff( git_diff_patch **out, git_diff_list *diff, size_t delta_index) { int error; git_diff_patch *patch = git__calloc(1, sizeof(git_diff_patch)); GITERR_CHECK_ALLOC(patch); if (!(error = diff_patch_init_from_diff(patch, diff, delta_index))) { patch->flags |= GIT_DIFF_PATCH_ALLOCATED; GIT_REFCOUNT_INC(patch); } else { git__free(patch); patch = NULL; } *out = patch; return error; } static int diff_patch_load(git_diff_patch *patch, git_diff_output *output) { int error = 0; bool incomplete_data; if ((patch->flags & GIT_DIFF_PATCH_LOADED) != 0) return 0; /* if no hunk and data callbacks and user doesn't care if data looks * binary, then there is no need to actually load the data */ if ((patch->ofile.opts_flags & GIT_DIFF_SKIP_BINARY_CHECK) != 0 && output && !output->hunk_cb && !output->data_cb) return 0; incomplete_data = (((patch->ofile.flags & GIT_DIFF_FLAG__NO_DATA) != 0 || (patch->ofile.file->flags & GIT_DIFF_FLAG_VALID_OID) != 0) && ((patch->nfile.flags & GIT_DIFF_FLAG__NO_DATA) != 0 || (patch->nfile.file->flags & GIT_DIFF_FLAG_VALID_OID) != 0)); /* always try to load workdir content first because filtering may * need 2x data size and this minimizes peak memory footprint */ if (patch->ofile.src == GIT_ITERATOR_TYPE_WORKDIR) { if ((error = git_diff_file_content__load(&patch->ofile)) < 0 || (patch->ofile.file->flags & GIT_DIFF_FLAG_BINARY) != 0) goto cleanup; } if (patch->nfile.src == GIT_ITERATOR_TYPE_WORKDIR) { if ((error = git_diff_file_content__load(&patch->nfile)) < 0 || (patch->nfile.file->flags & GIT_DIFF_FLAG_BINARY) != 0) goto cleanup; } /* once workdir has been tried, load other data as needed */ if (patch->ofile.src != GIT_ITERATOR_TYPE_WORKDIR) { if ((error = git_diff_file_content__load(&patch->ofile)) < 0 || (patch->ofile.file->flags & GIT_DIFF_FLAG_BINARY) != 0) goto cleanup; } if (patch->nfile.src != GIT_ITERATOR_TYPE_WORKDIR) { if ((error = git_diff_file_content__load(&patch->nfile)) < 0 || (patch->nfile.file->flags & GIT_DIFF_FLAG_BINARY) != 0) goto cleanup; } /* if we were previously missing an oid, update MODIFIED->UNMODIFIED */ if (incomplete_data && patch->ofile.file->mode == patch->nfile.file->mode && git_oid_equal(&patch->ofile.file->oid, &patch->nfile.file->oid) && patch->delta->status == GIT_DELTA_MODIFIED) /* not RENAMED/COPIED! */ patch->delta->status = GIT_DELTA_UNMODIFIED; cleanup: diff_patch_update_binary(patch); if (!error) { /* patch is diffable only for non-binary, modified files where * at least one side has data and the data actually changed */ if ((patch->delta->flags & GIT_DIFF_FLAG_BINARY) == 0 && patch->delta->status != GIT_DELTA_UNMODIFIED && (patch->ofile.map.len || patch->nfile.map.len) && (patch->ofile.map.len != patch->nfile.map.len || !git_oid_equal(&patch->ofile.file->oid, &patch->nfile.file->oid))) patch->flags |= GIT_DIFF_PATCH_DIFFABLE; patch->flags |= GIT_DIFF_PATCH_LOADED; } return error; } static int diff_patch_file_callback( git_diff_patch *patch, git_diff_output *output) { float progress; if (!output->file_cb) return 0; progress = patch->diff ? ((float)patch->delta_index / patch->diff->deltas.length) : 1.0f; if (output->file_cb(patch->delta, progress, output->payload) != 0) output->error = GIT_EUSER; return output->error; } static int diff_patch_generate(git_diff_patch *patch, git_diff_output *output) { int error = 0; if ((patch->flags & GIT_DIFF_PATCH_DIFFED) != 0) return 0; if ((patch->flags & GIT_DIFF_PATCH_LOADED) == 0 && (error = diff_patch_load(patch, output)) < 0) return error; if ((patch->flags & GIT_DIFF_PATCH_DIFFABLE) == 0) return 0; if (output->diff_cb != NULL && !(error = output->diff_cb(output, patch))) patch->flags |= GIT_DIFF_PATCH_DIFFED; return error; } static void diff_patch_free(git_diff_patch *patch) { git_diff_file_content__clear(&patch->ofile); git_diff_file_content__clear(&patch->nfile); git_array_clear(patch->lines); git_array_clear(patch->hunks); git_diff_list_free(patch->diff); /* decrements refcount */ patch->diff = NULL; git_pool_clear(&patch->flattened); if (patch->flags & GIT_DIFF_PATCH_ALLOCATED) git__free(patch); } static int diff_required(git_diff_list *diff, const char *action) { if (diff) return 0; giterr_set(GITERR_INVALID, "Must provide valid diff to %s", action); return -1; } int git_diff_foreach( git_diff_list *diff, git_diff_file_cb file_cb, git_diff_hunk_cb hunk_cb, git_diff_data_cb data_cb, void *payload) { int error = 0; git_xdiff_output xo; size_t idx; git_diff_patch patch; if (diff_required(diff, "git_diff_foreach") < 0) return -1; diff_output_init((git_diff_output *)&xo, &diff->opts, file_cb, hunk_cb, data_cb, payload); git_xdiff_init(&xo, &diff->opts); git_vector_foreach(&diff->deltas, idx, patch.delta) { /* check flags against patch status */ if (git_diff_delta__should_skip(&diff->opts, patch.delta)) continue; if (!(error = diff_patch_init_from_diff(&patch, diff, idx))) { error = diff_patch_file_callback(&patch, (git_diff_output *)&xo); if (!error) error = diff_patch_generate(&patch, (git_diff_output *)&xo); git_diff_patch_free(&patch); } if (error < 0) break; } if (error == GIT_EUSER) giterr_clear(); /* don't leave error message set invalidly */ return error; } typedef struct { git_diff_patch patch; git_diff_delta delta; char paths[GIT_FLEX_ARRAY]; } diff_patch_with_delta; static int diff_single_generate(diff_patch_with_delta *pd, git_xdiff_output *xo) { int error = 0; git_diff_patch *patch = &pd->patch; bool has_old = ((patch->ofile.flags & GIT_DIFF_FLAG__NO_DATA) == 0); bool has_new = ((patch->nfile.flags & GIT_DIFF_FLAG__NO_DATA) == 0); pd->delta.status = has_new ? (has_old ? GIT_DELTA_MODIFIED : GIT_DELTA_ADDED) : (has_old ? GIT_DELTA_DELETED : GIT_DELTA_UNTRACKED); if (git_oid_equal(&patch->nfile.file->oid, &patch->ofile.file->oid)) pd->delta.status = GIT_DELTA_UNMODIFIED; patch->delta = &pd->delta; diff_patch_init_common(patch); if (pd->delta.status == GIT_DELTA_UNMODIFIED && !(patch->ofile.opts_flags & GIT_DIFF_INCLUDE_UNMODIFIED)) return error; error = diff_patch_file_callback(patch, (git_diff_output *)xo); if (!error) error = diff_patch_generate(patch, (git_diff_output *)xo); if (error == GIT_EUSER) giterr_clear(); /* don't leave error message set invalidly */ return error; } static int diff_patch_from_blobs( diff_patch_with_delta *pd, git_xdiff_output *xo, const git_blob *old_blob, const char *old_path, const git_blob *new_blob, const char *new_path, const git_diff_options *opts) { int error = 0; git_repository *repo = new_blob ? git_object_owner((const git_object *)new_blob) : old_blob ? git_object_owner((const git_object *)old_blob) : NULL; GITERR_CHECK_VERSION(opts, GIT_DIFF_OPTIONS_VERSION, "git_diff_options"); if (opts && (opts->flags & GIT_DIFF_REVERSE) != 0) { const git_blob *tmp_blob; const char *tmp_path; tmp_blob = old_blob; old_blob = new_blob; new_blob = tmp_blob; tmp_path = old_path; old_path = new_path; new_path = tmp_path; } pd->patch.delta = &pd->delta; pd->delta.old_file.path = old_path; pd->delta.new_file.path = new_path; if ((error = git_diff_file_content__init_from_blob( &pd->patch.ofile, repo, opts, old_blob, &pd->delta.old_file)) < 0 || (error = git_diff_file_content__init_from_blob( &pd->patch.nfile, repo, opts, new_blob, &pd->delta.new_file)) < 0) return error; return diff_single_generate(pd, xo); } static int diff_patch_with_delta_alloc( diff_patch_with_delta **out, const char **old_path, const char **new_path) { diff_patch_with_delta *pd; size_t old_len = *old_path ? strlen(*old_path) : 0; size_t new_len = *new_path ? strlen(*new_path) : 0; *out = pd = git__calloc(1, sizeof(*pd) + old_len + new_len + 2); GITERR_CHECK_ALLOC(pd); pd->patch.flags = GIT_DIFF_PATCH_ALLOCATED; if (*old_path) { memcpy(&pd->paths[0], *old_path, old_len); *old_path = &pd->paths[0]; } else if (*new_path) *old_path = &pd->paths[old_len + 1]; if (*new_path) { memcpy(&pd->paths[old_len + 1], *new_path, new_len); *new_path = &pd->paths[old_len + 1]; } else if (*old_path) *new_path = &pd->paths[0]; return 0; } int git_diff_blobs( const git_blob *old_blob, const char *old_path, const git_blob *new_blob, const char *new_path, const git_diff_options *opts, git_diff_file_cb file_cb, git_diff_hunk_cb hunk_cb, git_diff_data_cb data_cb, void *payload) { int error = 0; diff_patch_with_delta pd; git_xdiff_output xo; memset(&pd, 0, sizeof(pd)); memset(&xo, 0, sizeof(xo)); diff_output_init( (git_diff_output *)&xo, opts, file_cb, hunk_cb, data_cb, payload); git_xdiff_init(&xo, opts); if (!old_path && new_path) old_path = new_path; else if (!new_path && old_path) new_path = old_path; error = diff_patch_from_blobs( &pd, &xo, old_blob, old_path, new_blob, new_path, opts); git_diff_patch_free((git_diff_patch *)&pd); return error; } int git_diff_patch_from_blobs( git_diff_patch **out, const git_blob *old_blob, const char *old_path, const git_blob *new_blob, const char *new_path, const git_diff_options *opts) { int error = 0; diff_patch_with_delta *pd; git_xdiff_output xo; assert(out); *out = NULL; if (diff_patch_with_delta_alloc(&pd, &old_path, &new_path) < 0) return -1; memset(&xo, 0, sizeof(xo)); diff_output_to_patch((git_diff_output *)&xo, &pd->patch); git_xdiff_init(&xo, opts); error = diff_patch_from_blobs( pd, &xo, old_blob, old_path, new_blob, new_path, opts); if (!error) *out = (git_diff_patch *)pd; else git_diff_patch_free((git_diff_patch *)pd); return error; } static int diff_patch_from_blob_and_buffer( diff_patch_with_delta *pd, git_xdiff_output *xo, const git_blob *old_blob, const char *old_path, const char *buf, size_t buflen, const char *buf_path, const git_diff_options *opts) { int error = 0; git_repository *repo = old_blob ? git_object_owner((const git_object *)old_blob) : NULL; GITERR_CHECK_VERSION(opts, GIT_DIFF_OPTIONS_VERSION, "git_diff_options"); pd->patch.delta = &pd->delta; if (opts && (opts->flags & GIT_DIFF_REVERSE) != 0) { pd->delta.old_file.path = buf_path; pd->delta.new_file.path = old_path; if (!(error = git_diff_file_content__init_from_raw( &pd->patch.ofile, repo, opts, buf, buflen, &pd->delta.old_file))) error = git_diff_file_content__init_from_blob( &pd->patch.nfile, repo, opts, old_blob, &pd->delta.new_file); } else { pd->delta.old_file.path = old_path; pd->delta.new_file.path = buf_path; if (!(error = git_diff_file_content__init_from_blob( &pd->patch.ofile, repo, opts, old_blob, &pd->delta.old_file))) error = git_diff_file_content__init_from_raw( &pd->patch.nfile, repo, opts, buf, buflen, &pd->delta.new_file); } if (error < 0) return error; return diff_single_generate(pd, xo); } int git_diff_blob_to_buffer( const git_blob *old_blob, const char *old_path, const char *buf, size_t buflen, const char *buf_path, const git_diff_options *opts, git_diff_file_cb file_cb, git_diff_hunk_cb hunk_cb, git_diff_data_cb data_cb, void *payload) { int error = 0; diff_patch_with_delta pd; git_xdiff_output xo; memset(&pd, 0, sizeof(pd)); memset(&xo, 0, sizeof(xo)); diff_output_init( (git_diff_output *)&xo, opts, file_cb, hunk_cb, data_cb, payload); git_xdiff_init(&xo, opts); if (!old_path && buf_path) old_path = buf_path; else if (!buf_path && old_path) buf_path = old_path; error = diff_patch_from_blob_and_buffer( &pd, &xo, old_blob, old_path, buf, buflen, buf_path, opts); git_diff_patch_free((git_diff_patch *)&pd); return error; } int git_diff_patch_from_blob_and_buffer( git_diff_patch **out, const git_blob *old_blob, const char *old_path, const char *buf, size_t buflen, const char *buf_path, const git_diff_options *opts) { int error = 0; diff_patch_with_delta *pd; git_xdiff_output xo; assert(out); *out = NULL; if (diff_patch_with_delta_alloc(&pd, &old_path, &buf_path) < 0) return -1; memset(&xo, 0, sizeof(xo)); diff_output_to_patch((git_diff_output *)&xo, &pd->patch); git_xdiff_init(&xo, opts); error = diff_patch_from_blob_and_buffer( pd, &xo, old_blob, old_path, buf, buflen, buf_path, opts); if (!error) *out = (git_diff_patch *)pd; else git_diff_patch_free((git_diff_patch *)pd); return error; } int git_diff_get_patch( git_diff_patch **patch_ptr, const git_diff_delta **delta_ptr, git_diff_list *diff, size_t idx) { int error = 0; git_xdiff_output xo; git_diff_delta *delta = NULL; git_diff_patch *patch = NULL; if (patch_ptr) *patch_ptr = NULL; if (delta_ptr) *delta_ptr = NULL; if (diff_required(diff, "git_diff_get_patch") < 0) return -1; delta = git_vector_get(&diff->deltas, idx); if (!delta) { giterr_set(GITERR_INVALID, "Index out of range for delta in diff"); return GIT_ENOTFOUND; } if (delta_ptr) *delta_ptr = delta; if (git_diff_delta__should_skip(&diff->opts, delta)) return 0; /* don't load the patch data unless we need it for binary check */ if (!patch_ptr && ((delta->flags & DIFF_FLAGS_KNOWN_BINARY) != 0 || (diff->opts.flags & GIT_DIFF_SKIP_BINARY_CHECK) != 0)) return 0; if ((error = diff_patch_alloc_from_diff(&patch, diff, idx)) < 0) return error; diff_output_to_patch((git_diff_output *)&xo, patch); git_xdiff_init(&xo, &diff->opts); error = diff_patch_file_callback(patch, (git_diff_output *)&xo); if (!error) error = diff_patch_generate(patch, (git_diff_output *)&xo); if (!error) { /* if cumulative diff size is < 0.5 total size, flatten the patch */ /* unload the file content */ } if (error || !patch_ptr) git_diff_patch_free(patch); else *patch_ptr = patch; if (error == GIT_EUSER) giterr_clear(); /* don't leave error message set invalidly */ return error; } void git_diff_patch_free(git_diff_patch *patch) { if (patch) GIT_REFCOUNT_DEC(patch, diff_patch_free); } const git_diff_delta *git_diff_patch_delta(git_diff_patch *patch) { assert(patch); return patch->delta; } size_t git_diff_patch_num_hunks(git_diff_patch *patch) { assert(patch); return git_array_size(patch->hunks); } int git_diff_patch_line_stats( size_t *total_ctxt, size_t *total_adds, size_t *total_dels, const git_diff_patch *patch) { size_t totals[3], idx; memset(totals, 0, sizeof(totals)); for (idx = 0; idx < git_array_size(patch->lines); ++idx) { diff_patch_line *line = git_array_get(patch->lines, idx); if (!line) continue; switch (line->origin) { case GIT_DIFF_LINE_CONTEXT: totals[0]++; break; case GIT_DIFF_LINE_ADDITION: totals[1]++; break; case GIT_DIFF_LINE_DELETION: totals[2]++; break; default: /* diff --stat and --numstat don't count EOFNL marks because * they will always be paired with a ADDITION or DELETION line. */ break; } } if (total_ctxt) *total_ctxt = totals[0]; if (total_adds) *total_adds = totals[1]; if (total_dels) *total_dels = totals[2]; return 0; } static int diff_error_outofrange(const char *thing) { giterr_set(GITERR_INVALID, "Diff patch %s index out of range", thing); return GIT_ENOTFOUND; } int git_diff_patch_get_hunk( const git_diff_range **range, const char **header, size_t *header_len, size_t *lines_in_hunk, git_diff_patch *patch, size_t hunk_idx) { diff_patch_hunk *hunk; assert(patch); hunk = git_array_get(patch->hunks, hunk_idx); if (!hunk) { if (range) *range = NULL; if (header) *header = NULL; if (header_len) *header_len = 0; if (lines_in_hunk) *lines_in_hunk = 0; return diff_error_outofrange("hunk"); } if (range) *range = &hunk->range; if (header) *header = hunk->header; if (header_len) *header_len = hunk->header_len; if (lines_in_hunk) *lines_in_hunk = hunk->line_count; return 0; } int git_diff_patch_num_lines_in_hunk(git_diff_patch *patch, size_t hunk_idx) { diff_patch_hunk *hunk; assert(patch); if (!(hunk = git_array_get(patch->hunks, hunk_idx))) return diff_error_outofrange("hunk"); return (int)hunk->line_count; } int git_diff_patch_get_line_in_hunk( char *line_origin, const char **content, size_t *content_len, int *old_lineno, int *new_lineno, git_diff_patch *patch, size_t hunk_idx, size_t line_of_hunk) { diff_patch_hunk *hunk; diff_patch_line *line; const char *thing; assert(patch); if (!(hunk = git_array_get(patch->hunks, hunk_idx))) { thing = "hunk"; goto notfound; } if (line_of_hunk >= hunk->line_count || !(line = git_array_get( patch->lines, hunk->line_start + line_of_hunk))) { thing = "line"; goto notfound; } if (line_origin) *line_origin = line->origin; if (content) *content = line->ptr; if (content_len) *content_len = line->len; if (old_lineno) *old_lineno = (int)line->oldno; if (new_lineno) *new_lineno = (int)line->newno; return 0; notfound: if (line_origin) *line_origin = GIT_DIFF_LINE_CONTEXT; if (content) *content = NULL; if (content_len) *content_len = 0; if (old_lineno) *old_lineno = -1; if (new_lineno) *new_lineno = -1; return diff_error_outofrange(thing); } git_diff_list *git_diff_patch__diff(git_diff_patch *patch) { return patch->diff; } git_diff_driver *git_diff_patch__driver(git_diff_patch *patch) { /* ofile driver is representative for whole patch */ return patch->ofile.driver; } void git_diff_patch__old_data( char **ptr, size_t *len, git_diff_patch *patch) { *ptr = patch->ofile.map.data; *len = patch->ofile.map.len; } void git_diff_patch__new_data( char **ptr, size_t *len, git_diff_patch *patch) { *ptr = patch->nfile.map.data; *len = patch->nfile.map.len; } int git_diff_patch__invoke_callbacks( git_diff_patch *patch, git_diff_file_cb file_cb, git_diff_hunk_cb hunk_cb, git_diff_data_cb line_cb, void *payload) { int error = 0; uint32_t i, j; if (file_cb) error = file_cb(patch->delta, 0, payload); if (!hunk_cb && !line_cb) return error; for (i = 0; !error && i < git_array_size(patch->hunks); ++i) { diff_patch_hunk *h = git_array_get(patch->hunks, i); error = hunk_cb( patch->delta, &h->range, h->header, h->header_len, payload); if (!line_cb) continue; for (j = 0; !error && j < h->line_count; ++j) { diff_patch_line *l = git_array_get(patch->lines, h->line_start + j); error = line_cb( patch->delta, &h->range, l->origin, l->ptr, l->len, payload); } } return error; } static int diff_patch_file_cb( const git_diff_delta *delta, float progress, void *payload) { GIT_UNUSED(delta); GIT_UNUSED(progress); GIT_UNUSED(payload); return 0; } static int diff_patch_hunk_cb( const git_diff_delta *delta, const git_diff_range *range, const char *header, size_t header_len, void *payload) { git_diff_patch *patch = payload; diff_patch_hunk *hunk; GIT_UNUSED(delta); hunk = git_array_alloc(patch->hunks); GITERR_CHECK_ALLOC(hunk); memcpy(&hunk->range, range, sizeof(hunk->range)); assert(header_len + 1 < sizeof(hunk->header)); memcpy(&hunk->header, header, header_len); hunk->header[header_len] = '\0'; hunk->header_len = header_len; hunk->line_start = git_array_size(patch->lines); hunk->line_count = 0; patch->oldno = range->old_start; patch->newno = range->new_start; return 0; } static int diff_patch_line_cb( const git_diff_delta *delta, const git_diff_range *range, char line_origin, const char *content, size_t content_len, void *payload) { git_diff_patch *patch = payload; diff_patch_hunk *hunk; diff_patch_line *line; GIT_UNUSED(delta); GIT_UNUSED(range); hunk = git_array_last(patch->hunks); GITERR_CHECK_ALLOC(hunk); line = git_array_alloc(patch->lines); GITERR_CHECK_ALLOC(line); line->ptr = content; line->len = content_len; line->origin = line_origin; patch->content_size += content_len; /* do some bookkeeping so we can provide old/new line numbers */ for (line->lines = 0; content_len > 0; --content_len) { if (*content++ == '\n') ++line->lines; } switch (line_origin) { case GIT_DIFF_LINE_ADDITION: case GIT_DIFF_LINE_DEL_EOFNL: line->oldno = -1; line->newno = patch->newno; patch->newno += line->lines; break; case GIT_DIFF_LINE_DELETION: case GIT_DIFF_LINE_ADD_EOFNL: line->oldno = patch->oldno; line->newno = -1; patch->oldno += line->lines; break; default: line->oldno = patch->oldno; line->newno = patch->newno; patch->oldno += line->lines; patch->newno += line->lines; break; } hunk->line_count++; return 0; } static void diff_output_init( git_diff_output *out, const git_diff_options *opts, git_diff_file_cb file_cb, git_diff_hunk_cb hunk_cb, git_diff_data_cb data_cb, void *payload) { GIT_UNUSED(opts); memset(out, 0, sizeof(*out)); out->file_cb = file_cb; out->hunk_cb = hunk_cb; out->data_cb = data_cb; out->payload = payload; } static void diff_output_to_patch(git_diff_output *out, git_diff_patch *patch) { diff_output_init( out, NULL, diff_patch_file_cb, diff_patch_hunk_cb, diff_patch_line_cb, patch); } libgit2-0.19.0/src/diff_patch.h000066400000000000000000000024631216214232500161670ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #ifndef INCLUDE_diff_patch_h__ #define INCLUDE_diff_patch_h__ #include "common.h" #include "diff.h" #include "diff_file.h" #include "array.h" extern git_diff_list *git_diff_patch__diff(git_diff_patch *); extern git_diff_driver *git_diff_patch__driver(git_diff_patch *); extern void git_diff_patch__old_data(char **, size_t *, git_diff_patch *); extern void git_diff_patch__new_data(char **, size_t *, git_diff_patch *); extern int git_diff_patch__invoke_callbacks( git_diff_patch *patch, git_diff_file_cb file_cb, git_diff_hunk_cb hunk_cb, git_diff_data_cb line_cb, void *payload); typedef struct git_diff_output git_diff_output; struct git_diff_output { /* these callbacks are issued with the diff data */ git_diff_file_cb file_cb; git_diff_hunk_cb hunk_cb; git_diff_data_cb data_cb; void *payload; /* this records the actual error in cases where it may be obscured */ int error; /* this callback is used to do the diff and drive the other callbacks. * see diff_xdiff.h for how to use this in practice for now. */ int (*diff_cb)(git_diff_output *output, git_diff_patch *patch); }; #endif libgit2-0.19.0/src/diff_print.c000066400000000000000000000252751216214232500162250ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #include "common.h" #include "diff.h" #include "diff_patch.h" #include "buffer.h" typedef struct { git_diff_list *diff; git_diff_data_cb print_cb; void *payload; git_buf *buf; int oid_strlen; } diff_print_info; static int diff_print_info_init( diff_print_info *pi, git_buf *out, git_diff_list *diff, git_diff_data_cb cb, void *payload) { pi->diff = diff; pi->print_cb = cb; pi->payload = payload; pi->buf = out; if (!diff || !diff->repo) pi->oid_strlen = GIT_ABBREV_DEFAULT; else if (git_repository__cvar( &pi->oid_strlen, diff->repo, GIT_CVAR_ABBREV) < 0) return -1; pi->oid_strlen += 1; /* for NUL byte */ if (pi->oid_strlen < 2) pi->oid_strlen = 2; else if (pi->oid_strlen > GIT_OID_HEXSZ + 1) pi->oid_strlen = GIT_OID_HEXSZ + 1; return 0; } static char diff_pick_suffix(int mode) { if (S_ISDIR(mode)) return '/'; else if (mode & 0100) /* -V536 */ /* in git, modes are very regular, so we must have 0100755 mode */ return '*'; else return ' '; } char git_diff_status_char(git_delta_t status) { char code; switch (status) { case GIT_DELTA_ADDED: code = 'A'; break; case GIT_DELTA_DELETED: code = 'D'; break; case GIT_DELTA_MODIFIED: code = 'M'; break; case GIT_DELTA_RENAMED: code = 'R'; break; case GIT_DELTA_COPIED: code = 'C'; break; case GIT_DELTA_IGNORED: code = 'I'; break; case GIT_DELTA_UNTRACKED: code = '?'; break; default: code = ' '; break; } return code; } static int callback_error(void) { giterr_clear(); return GIT_EUSER; } static int diff_print_one_compact( const git_diff_delta *delta, float progress, void *data) { diff_print_info *pi = data; git_buf *out = pi->buf; char old_suffix, new_suffix, code = git_diff_status_char(delta->status); int (*strcomp)(const char *, const char *) = pi->diff ? pi->diff->strcomp : git__strcmp; GIT_UNUSED(progress); if (code == ' ') return 0; old_suffix = diff_pick_suffix(delta->old_file.mode); new_suffix = diff_pick_suffix(delta->new_file.mode); git_buf_clear(out); if (delta->old_file.path != delta->new_file.path && strcomp(delta->old_file.path,delta->new_file.path) != 0) git_buf_printf(out, "%c\t%s%c -> %s%c\n", code, delta->old_file.path, old_suffix, delta->new_file.path, new_suffix); else if (delta->old_file.mode != delta->new_file.mode && delta->old_file.mode != 0 && delta->new_file.mode != 0) git_buf_printf(out, "%c\t%s%c (%o -> %o)\n", code, delta->old_file.path, new_suffix, delta->old_file.mode, delta->new_file.mode); else if (old_suffix != ' ') git_buf_printf(out, "%c\t%s%c\n", code, delta->old_file.path, old_suffix); else git_buf_printf(out, "%c\t%s\n", code, delta->old_file.path); if (git_buf_oom(out)) return -1; if (pi->print_cb(delta, NULL, GIT_DIFF_LINE_FILE_HDR, git_buf_cstr(out), git_buf_len(out), pi->payload)) return callback_error(); return 0; } /* print a git_diff_list to a print callback in compact format */ int git_diff_print_compact( git_diff_list *diff, git_diff_data_cb print_cb, void *payload) { int error; git_buf buf = GIT_BUF_INIT; diff_print_info pi; if (!(error = diff_print_info_init(&pi, &buf, diff, print_cb, payload))) error = git_diff_foreach(diff, diff_print_one_compact, NULL, NULL, &pi); git_buf_free(&buf); return error; } static int diff_print_one_raw( const git_diff_delta *delta, float progress, void *data) { diff_print_info *pi = data; git_buf *out = pi->buf; char code = git_diff_status_char(delta->status); char start_oid[GIT_OID_HEXSZ+1], end_oid[GIT_OID_HEXSZ+1]; GIT_UNUSED(progress); if (code == ' ') return 0; git_buf_clear(out); git_oid_tostr(start_oid, pi->oid_strlen, &delta->old_file.oid); git_oid_tostr(end_oid, pi->oid_strlen, &delta->new_file.oid); git_buf_printf( out, ":%06o %06o %s... %s... %c", delta->old_file.mode, delta->new_file.mode, start_oid, end_oid, code); if (delta->similarity > 0) git_buf_printf(out, "%03u", delta->similarity); if (delta->old_file.path != delta->new_file.path) git_buf_printf( out, "\t%s %s\n", delta->old_file.path, delta->new_file.path); else git_buf_printf( out, "\t%s\n", delta->old_file.path ? delta->old_file.path : delta->new_file.path); if (git_buf_oom(out)) return -1; if (pi->print_cb(delta, NULL, GIT_DIFF_LINE_FILE_HDR, git_buf_cstr(out), git_buf_len(out), pi->payload)) return callback_error(); return 0; } /* print a git_diff_list to a print callback in raw output format */ int git_diff_print_raw( git_diff_list *diff, git_diff_data_cb print_cb, void *payload) { int error; git_buf buf = GIT_BUF_INIT; diff_print_info pi; if (!(error = diff_print_info_init(&pi, &buf, diff, print_cb, payload))) error = git_diff_foreach(diff, diff_print_one_raw, NULL, NULL, &pi); git_buf_free(&buf); return error; } static int diff_print_oid_range(diff_print_info *pi, const git_diff_delta *delta) { git_buf *out = pi->buf; char start_oid[GIT_OID_HEXSZ+1], end_oid[GIT_OID_HEXSZ+1]; git_oid_tostr(start_oid, pi->oid_strlen, &delta->old_file.oid); git_oid_tostr(end_oid, pi->oid_strlen, &delta->new_file.oid); /* TODO: Match git diff more closely */ if (delta->old_file.mode == delta->new_file.mode) { git_buf_printf(out, "index %s..%s %o\n", start_oid, end_oid, delta->old_file.mode); } else { if (delta->old_file.mode == 0) { git_buf_printf(out, "new file mode %o\n", delta->new_file.mode); } else if (delta->new_file.mode == 0) { git_buf_printf(out, "deleted file mode %o\n", delta->old_file.mode); } else { git_buf_printf(out, "old mode %o\n", delta->old_file.mode); git_buf_printf(out, "new mode %o\n", delta->new_file.mode); } git_buf_printf(out, "index %s..%s\n", start_oid, end_oid); } if (git_buf_oom(out)) return -1; return 0; } static int diff_print_patch_file( const git_diff_delta *delta, float progress, void *data) { diff_print_info *pi = data; const char *oldpfx = pi->diff ? pi->diff->opts.old_prefix : NULL; const char *oldpath = delta->old_file.path; const char *newpfx = pi->diff ? pi->diff->opts.new_prefix : NULL; const char *newpath = delta->new_file.path; uint32_t opts_flags = pi->diff ? pi->diff->opts.flags : GIT_DIFF_NORMAL; GIT_UNUSED(progress); if (S_ISDIR(delta->new_file.mode) || delta->status == GIT_DELTA_UNMODIFIED || delta->status == GIT_DELTA_IGNORED || (delta->status == GIT_DELTA_UNTRACKED && (opts_flags & GIT_DIFF_INCLUDE_UNTRACKED_CONTENT) == 0)) return 0; if (!oldpfx) oldpfx = DIFF_OLD_PREFIX_DEFAULT; if (!newpfx) newpfx = DIFF_NEW_PREFIX_DEFAULT; git_buf_clear(pi->buf); git_buf_printf(pi->buf, "diff --git %s%s %s%s\n", oldpfx, delta->old_file.path, newpfx, delta->new_file.path); if (diff_print_oid_range(pi, delta) < 0) return -1; if (git_oid_iszero(&delta->old_file.oid)) { oldpfx = ""; oldpath = "/dev/null"; } if (git_oid_iszero(&delta->new_file.oid)) { newpfx = ""; newpath = "/dev/null"; } if ((delta->flags & GIT_DIFF_FLAG_BINARY) == 0) { git_buf_printf(pi->buf, "--- %s%s\n", oldpfx, oldpath); git_buf_printf(pi->buf, "+++ %s%s\n", newpfx, newpath); } if (git_buf_oom(pi->buf)) return -1; if (pi->print_cb(delta, NULL, GIT_DIFF_LINE_FILE_HDR, git_buf_cstr(pi->buf), git_buf_len(pi->buf), pi->payload)) return callback_error(); if ((delta->flags & GIT_DIFF_FLAG_BINARY) == 0) return 0; git_buf_clear(pi->buf); git_buf_printf( pi->buf, "Binary files %s%s and %s%s differ\n", oldpfx, oldpath, newpfx, newpath); if (git_buf_oom(pi->buf)) return -1; if (pi->print_cb(delta, NULL, GIT_DIFF_LINE_BINARY, git_buf_cstr(pi->buf), git_buf_len(pi->buf), pi->payload)) return callback_error(); return 0; } static int diff_print_patch_hunk( const git_diff_delta *d, const git_diff_range *r, const char *header, size_t header_len, void *data) { diff_print_info *pi = data; if (S_ISDIR(d->new_file.mode)) return 0; git_buf_clear(pi->buf); if (git_buf_printf(pi->buf, "%.*s", (int)header_len, header) < 0) return -1; if (pi->print_cb(d, r, GIT_DIFF_LINE_HUNK_HDR, git_buf_cstr(pi->buf), git_buf_len(pi->buf), pi->payload)) return callback_error(); return 0; } static int diff_print_patch_line( const git_diff_delta *delta, const git_diff_range *range, char line_origin, /* GIT_DIFF_LINE value from above */ const char *content, size_t content_len, void *data) { diff_print_info *pi = data; if (S_ISDIR(delta->new_file.mode)) return 0; git_buf_clear(pi->buf); if (line_origin == GIT_DIFF_LINE_ADDITION || line_origin == GIT_DIFF_LINE_DELETION || line_origin == GIT_DIFF_LINE_CONTEXT) git_buf_printf(pi->buf, "%c%.*s", line_origin, (int)content_len, content); else if (content_len > 0) git_buf_printf(pi->buf, "%.*s", (int)content_len, content); if (git_buf_oom(pi->buf)) return -1; if (pi->print_cb(delta, range, line_origin, git_buf_cstr(pi->buf), git_buf_len(pi->buf), pi->payload)) return callback_error(); return 0; } /* print a git_diff_list to an output callback in patch format */ int git_diff_print_patch( git_diff_list *diff, git_diff_data_cb print_cb, void *payload) { int error; git_buf buf = GIT_BUF_INIT; diff_print_info pi; if (!(error = diff_print_info_init(&pi, &buf, diff, print_cb, payload))) error = git_diff_foreach( diff, diff_print_patch_file, diff_print_patch_hunk, diff_print_patch_line, &pi); git_buf_free(&buf); return error; } /* print a git_diff_patch to an output callback */ int git_diff_patch_print( git_diff_patch *patch, git_diff_data_cb print_cb, void *payload) { int error; git_buf temp = GIT_BUF_INIT; diff_print_info pi; assert(patch && print_cb); if (!(error = diff_print_info_init( &pi, &temp, git_diff_patch__diff(patch), print_cb, payload))) error = git_diff_patch__invoke_callbacks( patch, diff_print_patch_file, diff_print_patch_hunk, diff_print_patch_line, &pi); git_buf_free(&temp); return error; } static int diff_print_to_buffer_cb( const git_diff_delta *delta, const git_diff_range *range, char line_origin, const char *content, size_t content_len, void *payload) { git_buf *output = payload; GIT_UNUSED(delta); GIT_UNUSED(range); GIT_UNUSED(line_origin); return git_buf_put(output, content, content_len); } /* print a git_diff_patch to a string buffer */ int git_diff_patch_to_str( char **string, git_diff_patch *patch) { int error; git_buf output = GIT_BUF_INIT; error = git_diff_patch_print(patch, diff_print_to_buffer_cb, &output); /* GIT_EUSER means git_buf_put in print_to_buffer_cb returned -1, * meaning a memory allocation failure, so just map to -1... */ if (error == GIT_EUSER) error = -1; *string = git_buf_detach(&output); return error; } libgit2-0.19.0/src/diff_tform.c000066400000000000000000000617611216214232500162200ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #include "common.h" #include "git2/config.h" #include "git2/blob.h" #include "diff.h" #include "hashsig.h" #include "path.h" #include "fileops.h" static git_diff_delta *diff_delta__dup( const git_diff_delta *d, git_pool *pool) { git_diff_delta *delta = git__malloc(sizeof(git_diff_delta)); if (!delta) return NULL; memcpy(delta, d, sizeof(git_diff_delta)); GIT_DIFF_FLAG__CLEAR_INTERNAL(delta->flags); if (d->old_file.path != NULL) { delta->old_file.path = git_pool_strdup(pool, d->old_file.path); if (delta->old_file.path == NULL) goto fail; } if (d->new_file.path != d->old_file.path && d->new_file.path != NULL) { delta->new_file.path = git_pool_strdup(pool, d->new_file.path); if (delta->new_file.path == NULL) goto fail; } else { delta->new_file.path = delta->old_file.path; } return delta; fail: git__free(delta); return NULL; } static git_diff_delta *diff_delta__merge_like_cgit( const git_diff_delta *a, const git_diff_delta *b, git_pool *pool) { git_diff_delta *dup; /* Emulate C git for merging two diffs (a la 'git diff '). * * When C git does a diff between the work dir and a tree, it actually * diffs with the index but uses the workdir contents. This emulates * those choices so we can emulate the type of diff. * * We have three file descriptions here, let's call them: * f1 = a->old_file * f2 = a->new_file AND b->old_file * f3 = b->new_file */ /* if f2 == f3 or f2 is deleted, then just dup the 'a' diff */ if (b->status == GIT_DELTA_UNMODIFIED || a->status == GIT_DELTA_DELETED) return diff_delta__dup(a, pool); /* otherwise, base this diff on the 'b' diff */ if ((dup = diff_delta__dup(b, pool)) == NULL) return NULL; /* If 'a' status is uninteresting, then we're done */ if (a->status == GIT_DELTA_UNMODIFIED) return dup; assert(a->status != GIT_DELTA_UNMODIFIED); assert(b->status != GIT_DELTA_UNMODIFIED); /* A cgit exception is that the diff of a file that is only in the * index (i.e. not in HEAD nor workdir) is given as empty. */ if (dup->status == GIT_DELTA_DELETED) { if (a->status == GIT_DELTA_ADDED) dup->status = GIT_DELTA_UNMODIFIED; /* else don't overwrite DELETE status */ } else { dup->status = a->status; } git_oid_cpy(&dup->old_file.oid, &a->old_file.oid); dup->old_file.mode = a->old_file.mode; dup->old_file.size = a->old_file.size; dup->old_file.flags = a->old_file.flags; return dup; } int git_diff_merge( git_diff_list *onto, const git_diff_list *from) { int error = 0; git_pool onto_pool; git_vector onto_new; git_diff_delta *delta; bool ignore_case = false; unsigned int i, j; assert(onto && from); if (!from->deltas.length) return 0; if (git_vector_init( &onto_new, onto->deltas.length, git_diff_delta__cmp) < 0 || git_pool_init(&onto_pool, 1, 0) < 0) return -1; if ((onto->opts.flags & GIT_DIFF_DELTAS_ARE_ICASE) != 0 || (from->opts.flags & GIT_DIFF_DELTAS_ARE_ICASE) != 0) { ignore_case = true; /* This function currently only supports merging diff lists that * are sorted identically. */ assert((onto->opts.flags & GIT_DIFF_DELTAS_ARE_ICASE) != 0 && (from->opts.flags & GIT_DIFF_DELTAS_ARE_ICASE) != 0); } for (i = 0, j = 0; i < onto->deltas.length || j < from->deltas.length; ) { git_diff_delta *o = GIT_VECTOR_GET(&onto->deltas, i); const git_diff_delta *f = GIT_VECTOR_GET(&from->deltas, j); int cmp = !f ? -1 : !o ? 1 : STRCMP_CASESELECT(ignore_case, o->old_file.path, f->old_file.path); if (cmp < 0) { delta = diff_delta__dup(o, &onto_pool); i++; } else if (cmp > 0) { delta = diff_delta__dup(f, &onto_pool); j++; } else { delta = diff_delta__merge_like_cgit(o, f, &onto_pool); i++; j++; } /* the ignore rules for the target may not match the source * or the result of a merged delta could be skippable... */ if (git_diff_delta__should_skip(&onto->opts, delta)) { git__free(delta); continue; } if ((error = !delta ? -1 : git_vector_insert(&onto_new, delta)) < 0) break; } if (!error) { git_vector_swap(&onto->deltas, &onto_new); git_pool_swap(&onto->pool, &onto_pool); onto->new_src = from->new_src; /* prefix strings also come from old pool, so recreate those.*/ onto->opts.old_prefix = git_pool_strdup_safe(&onto->pool, onto->opts.old_prefix); onto->opts.new_prefix = git_pool_strdup_safe(&onto->pool, onto->opts.new_prefix); } git_vector_foreach(&onto_new, i, delta) git__free(delta); git_vector_free(&onto_new); git_pool_clear(&onto_pool); return error; } int git_diff_find_similar__hashsig_for_file( void **out, const git_diff_file *f, const char *path, void *p) { git_hashsig_option_t opt = (git_hashsig_option_t)p; int error = 0; GIT_UNUSED(f); error = git_hashsig_create_fromfile((git_hashsig **)out, path, opt); if (error == GIT_EBUFS) { error = 0; giterr_clear(); } return error; } int git_diff_find_similar__hashsig_for_buf( void **out, const git_diff_file *f, const char *buf, size_t len, void *p) { git_hashsig_option_t opt = (git_hashsig_option_t)p; int error = 0; GIT_UNUSED(f); error = git_hashsig_create((git_hashsig **)out, buf, len, opt); if (error == GIT_EBUFS) { error = 0; giterr_clear(); } return error; } void git_diff_find_similar__hashsig_free(void *sig, void *payload) { GIT_UNUSED(payload); git_hashsig_free(sig); } int git_diff_find_similar__calc_similarity( int *score, void *siga, void *sigb, void *payload) { GIT_UNUSED(payload); *score = git_hashsig_compare(siga, sigb); return 0; } #define DEFAULT_THRESHOLD 50 #define DEFAULT_BREAK_REWRITE_THRESHOLD 60 #define DEFAULT_RENAME_LIMIT 200 static int normalize_find_opts( git_diff_list *diff, git_diff_find_options *opts, git_diff_find_options *given) { git_config *cfg = NULL; if (diff->repo != NULL && git_repository_config__weakptr(&cfg, diff->repo) < 0) return -1; if (given != NULL) memcpy(opts, given, sizeof(*opts)); else { const char *val = NULL; GIT_INIT_STRUCTURE(opts, GIT_DIFF_FIND_OPTIONS_VERSION); opts->flags = GIT_DIFF_FIND_RENAMES; if (git_config_get_string(&val, cfg, "diff.renames") < 0) giterr_clear(); else if (val && (!strcasecmp(val, "copies") || !strcasecmp(val, "copy"))) opts->flags = GIT_DIFF_FIND_RENAMES | GIT_DIFF_FIND_COPIES; } GITERR_CHECK_VERSION(opts, GIT_DIFF_FIND_OPTIONS_VERSION, "git_diff_find_options"); /* some flags imply others */ if (opts->flags & GIT_DIFF_FIND_EXACT_MATCH_ONLY) { /* if we are only looking for exact matches, then don't turn * MODIFIED items into ADD/DELETE pairs because it's too picky */ opts->flags &= ~(GIT_DIFF_FIND_REWRITES | GIT_DIFF_BREAK_REWRITES); /* similarly, don't look for self-rewrites to split */ opts->flags &= ~GIT_DIFF_FIND_RENAMES_FROM_REWRITES; } if (opts->flags & GIT_DIFF_FIND_RENAMES_FROM_REWRITES) opts->flags |= GIT_DIFF_FIND_RENAMES; if (opts->flags & GIT_DIFF_FIND_COPIES_FROM_UNMODIFIED) opts->flags |= GIT_DIFF_FIND_COPIES; if (opts->flags & GIT_DIFF_BREAK_REWRITES) opts->flags |= GIT_DIFF_FIND_REWRITES; #define USE_DEFAULT(X) ((X) == 0 || (X) > 100) if (USE_DEFAULT(opts->rename_threshold)) opts->rename_threshold = DEFAULT_THRESHOLD; if (USE_DEFAULT(opts->rename_from_rewrite_threshold)) opts->rename_from_rewrite_threshold = DEFAULT_THRESHOLD; if (USE_DEFAULT(opts->copy_threshold)) opts->copy_threshold = DEFAULT_THRESHOLD; if (USE_DEFAULT(opts->break_rewrite_threshold)) opts->break_rewrite_threshold = DEFAULT_BREAK_REWRITE_THRESHOLD; #undef USE_DEFAULT if (!opts->rename_limit) { int32_t limit = 0; opts->rename_limit = DEFAULT_RENAME_LIMIT; if (git_config_get_int32(&limit, cfg, "diff.renameLimit") < 0) giterr_clear(); else if (limit > 0) opts->rename_limit = limit; } /* assign the internal metric with whitespace flag as payload */ if (!opts->metric) { opts->metric = git__malloc(sizeof(git_diff_similarity_metric)); GITERR_CHECK_ALLOC(opts->metric); opts->metric->file_signature = git_diff_find_similar__hashsig_for_file; opts->metric->buffer_signature = git_diff_find_similar__hashsig_for_buf; opts->metric->free_signature = git_diff_find_similar__hashsig_free; opts->metric->similarity = git_diff_find_similar__calc_similarity; if (opts->flags & GIT_DIFF_FIND_IGNORE_WHITESPACE) opts->metric->payload = (void *)GIT_HASHSIG_IGNORE_WHITESPACE; else if (opts->flags & GIT_DIFF_FIND_DONT_IGNORE_WHITESPACE) opts->metric->payload = (void *)GIT_HASHSIG_NORMAL; else opts->metric->payload = (void *)GIT_HASHSIG_SMART_WHITESPACE; } return 0; } static int apply_splits_and_deletes( git_diff_list *diff, size_t expected_size, bool actually_split) { git_vector onto = GIT_VECTOR_INIT; size_t i; git_diff_delta *delta, *deleted; if (git_vector_init(&onto, expected_size, git_diff_delta__cmp) < 0) return -1; /* build new delta list without TO_DELETE and splitting TO_SPLIT */ git_vector_foreach(&diff->deltas, i, delta) { if ((delta->flags & GIT_DIFF_FLAG__TO_DELETE) != 0) continue; if ((delta->flags & GIT_DIFF_FLAG__TO_SPLIT) != 0 && actually_split) { delta->similarity = 0; /* make new record for DELETED side of split */ if (!(deleted = diff_delta__dup(delta, &diff->pool))) goto on_error; deleted->status = GIT_DELTA_DELETED; memset(&deleted->new_file, 0, sizeof(deleted->new_file)); deleted->new_file.path = deleted->old_file.path; deleted->new_file.flags |= GIT_DIFF_FLAG_VALID_OID; if (git_vector_insert(&onto, deleted) < 0) goto on_error; if (diff->new_src == GIT_ITERATOR_TYPE_WORKDIR) delta->status = GIT_DELTA_UNTRACKED; else delta->status = GIT_DELTA_ADDED; memset(&delta->old_file, 0, sizeof(delta->old_file)); delta->old_file.path = delta->new_file.path; delta->old_file.flags |= GIT_DIFF_FLAG_VALID_OID; } /* clean up delta before inserting into new list */ GIT_DIFF_FLAG__CLEAR_INTERNAL(delta->flags); if (delta->status != GIT_DELTA_COPIED && delta->status != GIT_DELTA_RENAMED && (delta->status != GIT_DELTA_MODIFIED || actually_split)) delta->similarity = 0; /* insert into new list */ if (git_vector_insert(&onto, delta) < 0) goto on_error; } /* cannot return an error past this point */ /* free deltas from old list that didn't make it to the new one */ git_vector_foreach(&diff->deltas, i, delta) { if ((delta->flags & GIT_DIFF_FLAG__TO_DELETE) != 0) git__free(delta); } /* swap new delta list into place */ git_vector_swap(&diff->deltas, &onto); git_vector_free(&onto); git_vector_sort(&diff->deltas); return 0; on_error: git_vector_foreach(&onto, i, delta) git__free(delta); git_vector_free(&onto); return -1; } GIT_INLINE(git_diff_file *) similarity_get_file(git_diff_list *diff, size_t idx) { git_diff_delta *delta = git_vector_get(&diff->deltas, idx / 2); return (idx & 1) ? &delta->new_file : &delta->old_file; } static int similarity_calc( git_diff_list *diff, const git_diff_find_options *opts, size_t file_idx, void **cache) { int error = 0; git_diff_file *file = similarity_get_file(diff, file_idx); git_iterator_type_t src = (file_idx & 1) ? diff->new_src : diff->old_src; if (src == GIT_ITERATOR_TYPE_WORKDIR) { /* compute hashsig from file */ git_buf path = GIT_BUF_INIT; /* TODO: apply wd-to-odb filters to file data if necessary */ if ((error = git_buf_joinpath( &path, git_repository_workdir(diff->repo), file->path)) < 0) return error; /* if path is not a regular file, just skip this item */ if (git_path_isfile(path.ptr)) error = opts->metric->file_signature( &cache[file_idx], file, path.ptr, opts->metric->payload); git_buf_free(&path); } else { /* compute hashsig from blob buffer */ git_blob *blob = NULL; git_off_t blobsize; /* TODO: add max size threshold a la diff? */ if (git_blob_lookup(&blob, diff->repo, &file->oid) < 0) { /* if lookup fails, just skip this item in similarity calc */ giterr_clear(); return 0; } blobsize = git_blob_rawsize(blob); if (!git__is_sizet(blobsize)) /* ? what to do ? */ blobsize = (size_t)-1; error = opts->metric->buffer_signature( &cache[file_idx], file, git_blob_rawcontent(blob), (size_t)blobsize, opts->metric->payload); git_blob_free(blob); } return error; } #define FLAG_SET(opts,flag_name) (((opts)->flags & flag_name) != 0) /* - score < 0 means files cannot be compared * - score >= 100 means files are exact match * - score == 0 means files are completely different */ static int similarity_measure( int *score, git_diff_list *diff, const git_diff_find_options *opts, void **cache, size_t a_idx, size_t b_idx) { git_diff_file *a_file = similarity_get_file(diff, a_idx); git_diff_file *b_file = similarity_get_file(diff, b_idx); bool exact_match = FLAG_SET(opts, GIT_DIFF_FIND_EXACT_MATCH_ONLY); *score = -1; /* don't try to compare files of different types */ if (GIT_MODE_TYPE(a_file->mode) != GIT_MODE_TYPE(b_file->mode)) return 0; /* if exact match is requested, force calculation of missing OIDs now */ if (exact_match) { if (git_oid_iszero(&a_file->oid) && diff->old_src == GIT_ITERATOR_TYPE_WORKDIR && !git_diff__oid_for_file(diff->repo, a_file->path, a_file->mode, a_file->size, &a_file->oid)) a_file->flags |= GIT_DIFF_FLAG_VALID_OID; if (git_oid_iszero(&b_file->oid) && diff->new_src == GIT_ITERATOR_TYPE_WORKDIR && !git_diff__oid_for_file(diff->repo, b_file->path, b_file->mode, b_file->size, &b_file->oid)) b_file->flags |= GIT_DIFF_FLAG_VALID_OID; } /* check OID match as a quick test */ if (git_oid__cmp(&a_file->oid, &b_file->oid) == 0) { *score = 100; return 0; } /* don't calculate signatures if we are doing exact match */ if (exact_match) { *score = 0; return 0; } /* update signature cache if needed */ if (!cache[a_idx] && similarity_calc(diff, opts, a_idx, cache) < 0) return -1; if (!cache[b_idx] && similarity_calc(diff, opts, b_idx, cache) < 0) return -1; /* some metrics may not wish to process this file (too big / too small) */ if (!cache[a_idx] || !cache[b_idx]) return 0; /* compare signatures */ return opts->metric->similarity( score, cache[a_idx], cache[b_idx], opts->metric->payload); } static int calc_self_similarity( git_diff_list *diff, const git_diff_find_options *opts, size_t delta_idx, void **cache) { int error, similarity = -1; git_diff_delta *delta = GIT_VECTOR_GET(&diff->deltas, delta_idx); if ((delta->flags & GIT_DIFF_FLAG__HAS_SELF_SIMILARITY) != 0) return 0; error = similarity_measure( &similarity, diff, opts, cache, 2 * delta_idx, 2 * delta_idx + 1); if (error < 0) return error; if (similarity >= 0) { delta->similarity = (uint32_t)similarity; delta->flags |= GIT_DIFF_FLAG__HAS_SELF_SIMILARITY; } return 0; } static bool is_rename_target( git_diff_list *diff, const git_diff_find_options *opts, size_t delta_idx, void **cache) { git_diff_delta *delta = GIT_VECTOR_GET(&diff->deltas, delta_idx); /* skip things that aren't plain blobs */ if (!GIT_MODE_ISBLOB(delta->new_file.mode)) return false; /* only consider ADDED, RENAMED, COPIED, and split MODIFIED as * targets; maybe include UNTRACKED and IGNORED if requested. */ switch (delta->status) { case GIT_DELTA_UNMODIFIED: case GIT_DELTA_DELETED: return false; case GIT_DELTA_MODIFIED: if (!FLAG_SET(opts, GIT_DIFF_FIND_REWRITES) && !FLAG_SET(opts, GIT_DIFF_FIND_RENAMES_FROM_REWRITES)) return false; if (calc_self_similarity(diff, opts, delta_idx, cache) < 0) return false; if (FLAG_SET(opts, GIT_DIFF_BREAK_REWRITES) && delta->similarity < opts->break_rewrite_threshold) { delta->flags |= GIT_DIFF_FLAG__TO_SPLIT; break; } if (FLAG_SET(opts, GIT_DIFF_FIND_RENAMES_FROM_REWRITES) && delta->similarity < opts->rename_from_rewrite_threshold) break; return false; case GIT_DELTA_UNTRACKED: case GIT_DELTA_IGNORED: if (!FLAG_SET(opts, GIT_DIFF_FIND_FOR_UNTRACKED)) return false; break; default: /* all other status values should be checked */ break; } delta->flags |= GIT_DIFF_FLAG__IS_RENAME_TARGET; return true; } static bool is_rename_source( git_diff_list *diff, const git_diff_find_options *opts, size_t delta_idx, void **cache) { git_diff_delta *delta = GIT_VECTOR_GET(&diff->deltas, delta_idx); /* skip things that aren't blobs */ if (!GIT_MODE_ISBLOB(delta->old_file.mode)) return false; switch (delta->status) { case GIT_DELTA_ADDED: case GIT_DELTA_UNTRACKED: case GIT_DELTA_IGNORED: return false; case GIT_DELTA_DELETED: case GIT_DELTA_TYPECHANGE: break; case GIT_DELTA_UNMODIFIED: if (!FLAG_SET(opts, GIT_DIFF_FIND_COPIES_FROM_UNMODIFIED)) return false; break; default: /* MODIFIED, RENAMED, COPIED */ /* if we're finding copies, this could be a source */ if (FLAG_SET(opts, GIT_DIFF_FIND_COPIES)) break; /* otherwise, this is only a source if we can split it */ if (!FLAG_SET(opts, GIT_DIFF_FIND_REWRITES) && !FLAG_SET(opts, GIT_DIFF_FIND_RENAMES_FROM_REWRITES)) return false; if (calc_self_similarity(diff, opts, delta_idx, cache) < 0) return false; if (FLAG_SET(opts, GIT_DIFF_BREAK_REWRITES) && delta->similarity < opts->break_rewrite_threshold) { delta->flags |= GIT_DIFF_FLAG__TO_SPLIT; break; } if (FLAG_SET(opts, GIT_DIFF_FIND_RENAMES_FROM_REWRITES) && delta->similarity < opts->rename_from_rewrite_threshold) break; return false; } delta->flags |= GIT_DIFF_FLAG__IS_RENAME_SOURCE; return true; } GIT_INLINE(bool) delta_is_split(git_diff_delta *delta) { return (delta->status == GIT_DELTA_TYPECHANGE || (delta->flags & GIT_DIFF_FLAG__TO_SPLIT) != 0); } GIT_INLINE(bool) delta_is_new_only(git_diff_delta *delta) { return (delta->status == GIT_DELTA_ADDED || delta->status == GIT_DELTA_UNTRACKED || delta->status == GIT_DELTA_IGNORED); } GIT_INLINE(void) delta_make_rename( git_diff_delta *to, const git_diff_delta *from, uint32_t similarity) { to->status = GIT_DELTA_RENAMED; to->similarity = similarity; memcpy(&to->old_file, &from->old_file, sizeof(to->old_file)); to->flags &= ~GIT_DIFF_FLAG__TO_SPLIT; } typedef struct { uint32_t idx; uint32_t similarity; } diff_find_match; int git_diff_find_similar( git_diff_list *diff, git_diff_find_options *given_opts) { size_t i, j, sigcache_size; int error = 0, similarity; git_diff_delta *from, *to; git_diff_find_options opts; size_t num_srcs = 0, num_tgts = 0, tried_srcs = 0, tried_tgts = 0; size_t num_rewrites = 0, num_updates = 0, num_bumped = 0; void **sigcache; /* cache of similarity metric file signatures */ diff_find_match *match_srcs = NULL, *match_tgts = NULL, *best_match; git_diff_file swap; if ((error = normalize_find_opts(diff, &opts, given_opts)) < 0) return error; /* TODO: maybe abort if deltas.length > rename_limit ??? */ if (!git__is_uint32(diff->deltas.length)) return 0; sigcache_size = diff->deltas.length * 2; /* keep size b/c diff may change */ sigcache = git__calloc(sigcache_size, sizeof(void *)); GITERR_CHECK_ALLOC(sigcache); /* Label rename sources and targets * * This will also set self-similarity scores for MODIFIED files and * mark them for splitting if break-rewrites is enabled */ git_vector_foreach(&diff->deltas, i, to) { if (is_rename_source(diff, &opts, i, sigcache)) ++num_srcs; if (is_rename_target(diff, &opts, i, sigcache)) ++num_tgts; } /* if there are no candidate srcs or tgts, we're done */ if (!num_srcs || !num_tgts) goto cleanup; match_tgts = git__calloc(diff->deltas.length, sizeof(diff_find_match)); GITERR_CHECK_ALLOC(match_tgts); match_srcs = git__calloc(diff->deltas.length, sizeof(diff_find_match)); GITERR_CHECK_ALLOC(match_srcs); /* * Find best-fit matches for rename / copy candidates */ find_best_matches: tried_tgts = num_bumped = 0; git_vector_foreach(&diff->deltas, i, to) { /* skip things that are not rename targets */ if ((to->flags & GIT_DIFF_FLAG__IS_RENAME_TARGET) == 0) continue; tried_srcs = 0; git_vector_foreach(&diff->deltas, j, from) { /* skip things that are not rename sources */ if ((from->flags & GIT_DIFF_FLAG__IS_RENAME_SOURCE) == 0) continue; /* calculate similarity for this pair and find best match */ if (i == j) similarity = -1; /* don't measure self-similarity here */ else if ((error = similarity_measure( &similarity, diff, &opts, sigcache, 2 * j, 2 * i + 1)) < 0) goto cleanup; /* if this pairing is better for the src and the tgt, keep it */ if (similarity > 0 && match_tgts[i].similarity < (uint32_t)similarity && match_srcs[j].similarity < (uint32_t)similarity) { if (match_tgts[i].similarity > 0) { match_tgts[match_srcs[j].idx].similarity = 0; match_srcs[match_tgts[i].idx].similarity = 0; ++num_bumped; } match_tgts[i].similarity = (uint32_t)similarity; match_tgts[i].idx = (uint32_t)j; match_srcs[j].similarity = (uint32_t)similarity; match_srcs[j].idx = (uint32_t)i; } if (++tried_srcs >= num_srcs) break; /* cap on maximum targets we'll examine (per "to" file) */ if (tried_srcs > opts.rename_limit) break; } if (++tried_tgts >= num_tgts) break; } if (num_bumped > 0) /* try again if we bumped some items */ goto find_best_matches; /* * Rewrite the diffs with renames / copies */ tried_tgts = 0; git_vector_foreach(&diff->deltas, i, to) { /* skip things that are not rename targets */ if ((to->flags & GIT_DIFF_FLAG__IS_RENAME_TARGET) == 0) continue; /* check if this delta was the target of a similarity */ best_match = &match_tgts[i]; if (!best_match->similarity) continue; j = best_match->idx; from = GIT_VECTOR_GET(&diff->deltas, j); /* possible scenarios: * 1. from DELETE to ADD/UNTRACK/IGNORE = RENAME * 2. from DELETE to SPLIT/TYPECHANGE = RENAME + DELETE * 3. from SPLIT/TYPECHANGE to ADD/UNTRACK/IGNORE = ADD + RENAME * 4. from SPLIT/TYPECHANGE to SPLIT/TYPECHANGE = RENAME + SPLIT * 5. from OTHER to ADD/UNTRACK/IGNORE = OTHER + COPY */ if (from->status == GIT_DELTA_DELETED) { if (delta_is_new_only(to)) { if (best_match->similarity < opts.rename_threshold) continue; delta_make_rename(to, from, best_match->similarity); from->flags |= GIT_DIFF_FLAG__TO_DELETE; num_rewrites++; } else { assert(delta_is_split(to)); if (best_match->similarity < opts.rename_from_rewrite_threshold) continue; memcpy(&swap, &to->old_file, sizeof(swap)); delta_make_rename(to, from, best_match->similarity); num_rewrites--; from->status = GIT_DELTA_DELETED; memcpy(&from->old_file, &swap, sizeof(from->old_file)); memset(&from->new_file, 0, sizeof(from->new_file)); from->new_file.path = from->old_file.path; from->new_file.flags |= GIT_DIFF_FLAG_VALID_OID; num_updates++; } } else if (delta_is_split(from)) { if (delta_is_new_only(to)) { if (best_match->similarity < opts.rename_threshold) continue; delta_make_rename(to, from, best_match->similarity); from->status = (diff->new_src == GIT_ITERATOR_TYPE_WORKDIR) ? GIT_DELTA_UNTRACKED : GIT_DELTA_ADDED; memset(&from->old_file, 0, sizeof(from->old_file)); from->old_file.path = from->new_file.path; from->old_file.flags |= GIT_DIFF_FLAG_VALID_OID; from->flags &= ~GIT_DIFF_FLAG__TO_SPLIT; num_rewrites--; num_updates++; } else { assert(delta_is_split(from)); if (best_match->similarity < opts.rename_from_rewrite_threshold) continue; memcpy(&swap, &to->old_file, sizeof(swap)); delta_make_rename(to, from, best_match->similarity); num_rewrites--; num_updates++; memcpy(&from->old_file, &swap, sizeof(from->old_file)); /* if we've just swapped the new element into the correct * place, clear the SPLIT flag */ if (match_tgts[j].idx == i && match_tgts[j].similarity > opts.rename_from_rewrite_threshold) { from->status = GIT_DELTA_RENAMED; from->similarity = match_tgts[j].similarity; match_tgts[j].similarity = 0; from->flags &= ~GIT_DIFF_FLAG__TO_SPLIT; num_rewrites--; } /* otherwise, if we just overwrote a source, update mapping */ else if (j > i && match_srcs[i].similarity > 0) { match_tgts[match_srcs[i].idx].idx = j; } num_updates++; } } else if (delta_is_new_only(to)) { if (!FLAG_SET(&opts, GIT_DIFF_FIND_COPIES) || best_match->similarity < opts.copy_threshold) continue; to->status = GIT_DELTA_COPIED; to->similarity = best_match->similarity; memcpy(&to->old_file, &from->old_file, sizeof(to->old_file)); num_updates++; } } /* * Actually split and delete entries as needed */ if (num_rewrites > 0 || num_updates > 0) error = apply_splits_and_deletes( diff, diff->deltas.length - num_rewrites, FLAG_SET(&opts, GIT_DIFF_BREAK_REWRITES)); cleanup: git__free(match_srcs); git__free(match_tgts); for (i = 0; i < sigcache_size; ++i) { if (sigcache[i] != NULL) opts.metric->free_signature(sigcache[i], opts.metric->payload); } git__free(sigcache); if (!given_opts || !given_opts->metric) git__free(opts.metric); return error; } #undef FLAG_SET libgit2-0.19.0/src/diff_xdiff.c000066400000000000000000000112001216214232500161500ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #include "common.h" #include "diff.h" #include "diff_driver.h" #include "diff_patch.h" #include "diff_xdiff.h" static int git_xdiff_scan_int(const char **str, int *value) { const char *scan = *str; int v = 0, digits = 0; /* find next digit */ for (scan = *str; *scan && !git__isdigit(*scan); scan++); /* parse next number */ for (; git__isdigit(*scan); scan++, digits++) v = (v * 10) + (*scan - '0'); *str = scan; *value = v; return (digits > 0) ? 0 : -1; } static int git_xdiff_parse_hunk(git_diff_range *range, const char *header) { /* expect something of the form "@@ -%d[,%d] +%d[,%d] @@" */ if (*header != '@') return -1; if (git_xdiff_scan_int(&header, &range->old_start) < 0) return -1; if (*header == ',') { if (git_xdiff_scan_int(&header, &range->old_lines) < 0) return -1; } else range->old_lines = 1; if (git_xdiff_scan_int(&header, &range->new_start) < 0) return -1; if (*header == ',') { if (git_xdiff_scan_int(&header, &range->new_lines) < 0) return -1; } else range->new_lines = 1; if (range->old_start < 0 || range->new_start < 0) return -1; return 0; } typedef struct { git_xdiff_output *xo; git_diff_patch *patch; git_diff_range range; } git_xdiff_info; static int git_xdiff_cb(void *priv, mmbuffer_t *bufs, int len) { git_xdiff_info *info = priv; git_diff_patch *patch = info->patch; const git_diff_delta *delta = git_diff_patch_delta(patch); git_diff_output *output = &info->xo->output; if (len == 1) { output->error = git_xdiff_parse_hunk(&info->range, bufs[0].ptr); if (output->error < 0) return output->error; if (output->hunk_cb != NULL && output->hunk_cb(delta, &info->range, bufs[0].ptr, bufs[0].size, output->payload)) output->error = GIT_EUSER; } if (len == 2 || len == 3) { /* expect " "/"-"/"+", then data */ char origin = (*bufs[0].ptr == '+') ? GIT_DIFF_LINE_ADDITION : (*bufs[0].ptr == '-') ? GIT_DIFF_LINE_DELETION : GIT_DIFF_LINE_CONTEXT; if (output->data_cb != NULL && output->data_cb(delta, &info->range, origin, bufs[1].ptr, bufs[1].size, output->payload)) output->error = GIT_EUSER; } if (len == 3 && !output->error) { /* If we have a '+' and a third buf, then we have added a line * without a newline and the old code had one, so DEL_EOFNL. * If we have a '-' and a third buf, then we have removed a line * with out a newline but added a blank line, so ADD_EOFNL. */ char origin = (*bufs[0].ptr == '+') ? GIT_DIFF_LINE_DEL_EOFNL : (*bufs[0].ptr == '-') ? GIT_DIFF_LINE_ADD_EOFNL : GIT_DIFF_LINE_CONTEXT_EOFNL; if (output->data_cb != NULL && output->data_cb(delta, &info->range, origin, bufs[2].ptr, bufs[2].size, output->payload)) output->error = GIT_EUSER; } return output->error; } static int git_xdiff(git_diff_output *output, git_diff_patch *patch) { git_xdiff_output *xo = (git_xdiff_output *)output; git_xdiff_info info; git_diff_find_context_payload findctxt; mmfile_t xd_old_data, xd_new_data; memset(&info, 0, sizeof(info)); info.patch = patch; info.xo = xo; xo->callback.priv = &info; git_diff_find_context_init( &xo->config.find_func, &findctxt, git_diff_patch__driver(patch)); xo->config.find_func_priv = &findctxt; if (xo->config.find_func != NULL) xo->config.flags |= XDL_EMIT_FUNCNAMES; else xo->config.flags &= ~XDL_EMIT_FUNCNAMES; /* TODO: check ofile.opts_flags to see if driver-specific per-file * updates are needed to xo->params.flags */ git_diff_patch__old_data(&xd_old_data.ptr, &xd_old_data.size, patch); git_diff_patch__new_data(&xd_new_data.ptr, &xd_new_data.size, patch); xdl_diff(&xd_old_data, &xd_new_data, &xo->params, &xo->config, &xo->callback); git_diff_find_context_clear(&findctxt); return xo->output.error; } void git_xdiff_init(git_xdiff_output *xo, const git_diff_options *opts) { uint32_t flags = opts ? opts->flags : GIT_DIFF_NORMAL; xo->output.diff_cb = git_xdiff; memset(&xo->config, 0, sizeof(xo->config)); xo->config.ctxlen = opts ? opts->context_lines : 3; xo->config.interhunkctxlen = opts ? opts->interhunk_lines : 0; memset(&xo->params, 0, sizeof(xo->params)); if (flags & GIT_DIFF_IGNORE_WHITESPACE) xo->params.flags |= XDF_WHITESPACE_FLAGS; if (flags & GIT_DIFF_IGNORE_WHITESPACE_CHANGE) xo->params.flags |= XDF_IGNORE_WHITESPACE_CHANGE; if (flags & GIT_DIFF_IGNORE_WHITESPACE_EOL) xo->params.flags |= XDF_IGNORE_WHITESPACE_AT_EOL; memset(&xo->callback, 0, sizeof(xo->callback)); xo->callback.outf = git_xdiff_cb; } libgit2-0.19.0/src/diff_xdiff.h000066400000000000000000000013701216214232500161640ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #ifndef INCLUDE_diff_xdiff_h__ #define INCLUDE_diff_xdiff_h__ #include "diff.h" #include "diff_patch.h" #include "xdiff/xdiff.h" /* A git_xdiff_output is a git_diff_output with extra fields necessary * to use libxdiff. Calling git_xdiff_init() will set the diff_cb field * of the output to use xdiff to generate the diffs. */ typedef struct { git_diff_output output; xdemitconf_t config; xpparam_t params; xdemitcb_t callback; } git_xdiff_output; void git_xdiff_init(git_xdiff_output *xo, const git_diff_options *opts); #endif libgit2-0.19.0/src/errors.c000066400000000000000000000044211216214232500154030ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #include "common.h" #include "global.h" #include "posix.h" #include "buffer.h" #include /******************************************** * New error handling ********************************************/ static git_error g_git_oom_error = { "Out of memory", GITERR_NOMEMORY }; static void set_error(int error_class, char *string) { git_error *error = &GIT_GLOBAL->error_t; git__free(error->message); error->message = string; error->klass = error_class; GIT_GLOBAL->last_error = error; } void giterr_set_oom(void) { GIT_GLOBAL->last_error = &g_git_oom_error; } void giterr_set(int error_class, const char *string, ...) { git_buf buf = GIT_BUF_INIT; va_list arglist; #ifdef GIT_WIN32 DWORD win32_error_code = (error_class == GITERR_OS) ? GetLastError() : 0; #endif int error_code = (error_class == GITERR_OS) ? errno : 0; va_start(arglist, string); git_buf_vprintf(&buf, string, arglist); va_end(arglist); if (error_class == GITERR_OS) { #ifdef GIT_WIN32 char * win32_error = git_win32_get_error_message(win32_error_code); if (win32_error) { git_buf_PUTS(&buf, ": "); git_buf_puts(&buf, win32_error); git__free(win32_error); SetLastError(0); } else #endif if (error_code) { git_buf_PUTS(&buf, ": "); git_buf_puts(&buf, strerror(error_code)); } if (error_code) errno = 0; } if (!git_buf_oom(&buf)) set_error(error_class, git_buf_detach(&buf)); } void giterr_set_str(int error_class, const char *string) { char *message; assert(string); message = git__strdup(string); if (message) set_error(error_class, message); } int giterr_set_regex(const regex_t *regex, int error_code) { char error_buf[1024]; assert(error_code); regerror(error_code, regex, error_buf, sizeof(error_buf)); giterr_set_str(GITERR_REGEX, error_buf); if (error_code == REG_NOMATCH) return GIT_ENOTFOUND; return GIT_EINVALIDSPEC; } void giterr_clear(void) { set_error(0, NULL); GIT_GLOBAL->last_error = NULL; errno = 0; #ifdef GIT_WIN32 SetLastError(0); #endif } const git_error *giterr_last(void) { return GIT_GLOBAL->last_error; } libgit2-0.19.0/src/fetch.c000066400000000000000000000062331216214232500151630ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #include "git2/oid.h" #include "git2/refs.h" #include "git2/revwalk.h" #include "git2/transport.h" #include "common.h" #include "remote.h" #include "refspec.h" #include "pack.h" #include "fetch.h" #include "netops.h" #include "repository.h" #include "refs.h" struct filter_payload { git_remote *remote; const git_refspec *spec, *tagspec; git_odb *odb; int found_head; }; static int filter_ref__cb(git_remote_head *head, void *payload) { struct filter_payload *p = payload; int match = 0; if (!git_reference_is_valid_name(head->name)) return 0; if (!p->found_head && strcmp(head->name, GIT_HEAD_FILE) == 0) p->found_head = 1; else if (p->remote->download_tags == GIT_REMOTE_DOWNLOAD_TAGS_ALL) { /* * If tagopt is --tags, then we only use the default * tags refspec and ignore the remote's */ if (git_refspec_src_matches(p->tagspec, head->name)) match = 1; else return 0; } else if (git_remote__matching_refspec(p->remote, head->name)) match = 1; if (!match) return 0; /* If we have the object, mark it so we don't ask for it */ if (git_odb_exists(p->odb, &head->oid)) head->local = 1; else p->remote->need_pack = 1; return git_vector_insert(&p->remote->refs, head); } static int filter_wants(git_remote *remote) { struct filter_payload p; git_refspec tagspec; int error = -1; git_vector_clear(&remote->refs); if (git_refspec__parse(&tagspec, GIT_REFSPEC_TAGS, true) < 0) return error; /* * The fetch refspec can be NULL, and what this means is that the * user didn't specify one. This is fine, as it means that we're * not interested in any particular branch but just the remote's * HEAD, which will be stored in FETCH_HEAD after the fetch. */ p.tagspec = &tagspec; p.found_head = 0; p.remote = remote; if (git_repository_odb__weakptr(&p.odb, remote->repo) < 0) goto cleanup; error = git_remote_ls(remote, filter_ref__cb, &p); cleanup: git_refspec__free(&tagspec); return error; } /* * In this first version, we push all our refs in and start sending * them out. When we get an ACK we hide that commit and continue * traversing until we're done */ int git_fetch_negotiate(git_remote *remote) { git_transport *t = remote->transport; if (filter_wants(remote) < 0) { giterr_set(GITERR_NET, "Failed to filter the reference list for wants"); return -1; } /* Don't try to negotiate when we don't want anything */ if (remote->refs.length == 0 || !remote->need_pack) return 0; /* * Now we have everything set up so we can start tell the * server what we want and what we have. */ return t->negotiate_fetch(t, remote->repo, (const git_remote_head * const *)remote->refs.contents, remote->refs.length); } int git_fetch_download_pack( git_remote *remote, git_transfer_progress_callback progress_cb, void *progress_payload) { git_transport *t = remote->transport; if(!remote->need_pack) return 0; return t->download_pack(t, remote->repo, &remote->stats, progress_cb, progress_payload); } libgit2-0.19.0/src/fetch.h000066400000000000000000000013131216214232500151620ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #ifndef INCLUDE_fetch_h__ #define INCLUDE_fetch_h__ #include "netops.h" int git_fetch_negotiate(git_remote *remote); int git_fetch_download_pack( git_remote *remote, git_transfer_progress_callback progress_cb, void *progress_payload); int git_fetch__download_pack( git_transport *t, git_repository *repo, git_transfer_progress *stats, git_transfer_progress_callback progress_cb, void *progress_payload); int git_fetch_setup_walk(git_revwalk **out, git_repository *repo); #endif libgit2-0.19.0/src/fetchhead.c000066400000000000000000000146571216214232500160160ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #include "git2/types.h" #include "git2/oid.h" #include "fetchhead.h" #include "common.h" #include "buffer.h" #include "fileops.h" #include "filebuf.h" #include "refs.h" #include "repository.h" int git_fetchhead_ref_cmp(const void *a, const void *b) { const git_fetchhead_ref *one = (const git_fetchhead_ref *)a; const git_fetchhead_ref *two = (const git_fetchhead_ref *)b; if (one->is_merge && !two->is_merge) return -1; if (two->is_merge && !one->is_merge) return 1; if (one->ref_name && two->ref_name) return strcmp(one->ref_name, two->ref_name); else if (one->ref_name) return -1; else if (two->ref_name) return 1; return 0; } int git_fetchhead_ref_create( git_fetchhead_ref **out, git_oid *oid, unsigned int is_merge, const char *ref_name, const char *remote_url) { git_fetchhead_ref *fetchhead_ref; assert(out && oid); *out = NULL; fetchhead_ref = git__malloc(sizeof(git_fetchhead_ref)); GITERR_CHECK_ALLOC(fetchhead_ref); memset(fetchhead_ref, 0x0, sizeof(git_fetchhead_ref)); git_oid_cpy(&fetchhead_ref->oid, oid); fetchhead_ref->is_merge = is_merge; if (ref_name) fetchhead_ref->ref_name = git__strdup(ref_name); if (remote_url) fetchhead_ref->remote_url = git__strdup(remote_url); *out = fetchhead_ref; return 0; } static int fetchhead_ref_write( git_filebuf *file, git_fetchhead_ref *fetchhead_ref) { char oid[GIT_OID_HEXSZ + 1]; const char *type, *name; assert(file && fetchhead_ref); git_oid_fmt(oid, &fetchhead_ref->oid); oid[GIT_OID_HEXSZ] = '\0'; if (git__prefixcmp(fetchhead_ref->ref_name, GIT_REFS_HEADS_DIR) == 0) { type = "branch "; name = fetchhead_ref->ref_name + strlen(GIT_REFS_HEADS_DIR); } else if(git__prefixcmp(fetchhead_ref->ref_name, GIT_REFS_TAGS_DIR) == 0) { type = "tag "; name = fetchhead_ref->ref_name + strlen(GIT_REFS_TAGS_DIR); } else { type = ""; name = fetchhead_ref->ref_name; } return git_filebuf_printf(file, "%s\t%s\t%s'%s' of %s\n", oid, (fetchhead_ref->is_merge) ? "" : "not-for-merge", type, name, fetchhead_ref->remote_url); } int git_fetchhead_write(git_repository *repo, git_vector *fetchhead_refs) { git_filebuf file = GIT_FILEBUF_INIT; git_buf path = GIT_BUF_INIT; unsigned int i; git_fetchhead_ref *fetchhead_ref; assert(repo && fetchhead_refs); if (git_buf_joinpath(&path, repo->path_repository, GIT_FETCH_HEAD_FILE) < 0) return -1; if (git_filebuf_open(&file, path.ptr, GIT_FILEBUF_FORCE) < 0) { git_buf_free(&path); return -1; } git_buf_free(&path); git_vector_sort(fetchhead_refs); git_vector_foreach(fetchhead_refs, i, fetchhead_ref) fetchhead_ref_write(&file, fetchhead_ref); return git_filebuf_commit(&file, GIT_REFS_FILE_MODE); } static int fetchhead_ref_parse( git_oid *oid, unsigned int *is_merge, git_buf *ref_name, const char **remote_url, char *line, size_t line_num) { char *oid_str, *is_merge_str, *desc, *name = NULL; const char *type = NULL; int error = 0; *remote_url = NULL; if (!*line) { giterr_set(GITERR_FETCHHEAD, "Empty line in FETCH_HEAD line %d", line_num); return -1; } /* Compat with old git clients that wrote FETCH_HEAD like a loose ref. */ if ((oid_str = git__strsep(&line, "\t")) == NULL) { oid_str = line; line += strlen(line); *is_merge = 1; } if (strlen(oid_str) != GIT_OID_HEXSZ) { giterr_set(GITERR_FETCHHEAD, "Invalid object ID in FETCH_HEAD line %d", line_num); return -1; } if (git_oid_fromstr(oid, oid_str) < 0) { const git_error *oid_err = giterr_last(); const char *err_msg = oid_err ? oid_err->message : "Invalid object ID"; giterr_set(GITERR_FETCHHEAD, "%s in FETCH_HEAD line %d", err_msg, line_num); return -1; } /* Parse new data from newer git clients */ if (*line) { if ((is_merge_str = git__strsep(&line, "\t")) == NULL) { giterr_set(GITERR_FETCHHEAD, "Invalid description data in FETCH_HEAD line %d", line_num); return -1; } if (*is_merge_str == '\0') *is_merge = 1; else if (strcmp(is_merge_str, "not-for-merge") == 0) *is_merge = 0; else { giterr_set(GITERR_FETCHHEAD, "Invalid for-merge entry in FETCH_HEAD line %d", line_num); return -1; } if ((desc = line) == NULL) { giterr_set(GITERR_FETCHHEAD, "Invalid description in FETCH_HEAD line %d", line_num); return -1; } if (git__prefixcmp(desc, "branch '") == 0) { type = GIT_REFS_HEADS_DIR; name = desc + 8; } else if (git__prefixcmp(desc, "tag '") == 0) { type = GIT_REFS_TAGS_DIR; name = desc + 5; } else if (git__prefixcmp(desc, "'") == 0) name = desc + 1; if (name) { if ((desc = strchr(name, '\'')) == NULL || git__prefixcmp(desc, "' of ") != 0) { giterr_set(GITERR_FETCHHEAD, "Invalid description in FETCH_HEAD line %d", line_num); return -1; } *desc = '\0'; desc += 5; } *remote_url = desc; } git_buf_clear(ref_name); if (type) git_buf_join(ref_name, '/', type, name); else if(name) git_buf_puts(ref_name, name); return error; } int git_repository_fetchhead_foreach(git_repository *repo, git_repository_fetchhead_foreach_cb cb, void *payload) { git_buf path = GIT_BUF_INIT, file = GIT_BUF_INIT, name = GIT_BUF_INIT; const char *ref_name; git_oid oid; const char *remote_url; unsigned int is_merge = 0; char *buffer, *line; size_t line_num = 0; int error = 0; assert(repo && cb); if (git_buf_joinpath(&path, repo->path_repository, GIT_FETCH_HEAD_FILE) < 0) return -1; if ((error = git_futils_readbuffer(&file, git_buf_cstr(&path))) < 0) goto done; buffer = file.ptr; while ((line = git__strsep(&buffer, "\n")) != NULL) { ++line_num; if ((error = fetchhead_ref_parse(&oid, &is_merge, &name, &remote_url, line, line_num)) < 0) goto done; if (git_buf_len(&name) > 0) ref_name = git_buf_cstr(&name); else ref_name = NULL; if ((cb(ref_name, remote_url, &oid, is_merge, payload)) != 0) { error = GIT_EUSER; goto done; } } if (*buffer) { giterr_set(GITERR_FETCHHEAD, "No EOL at line %d", line_num+1); error = -1; goto done; } done: git_buf_free(&file); git_buf_free(&path); git_buf_free(&name); return error; } void git_fetchhead_ref_free(git_fetchhead_ref *fetchhead_ref) { if (fetchhead_ref == NULL) return; git__free(fetchhead_ref->remote_url); git__free(fetchhead_ref->ref_name); git__free(fetchhead_ref); } libgit2-0.19.0/src/fetchhead.h000066400000000000000000000014631216214232500160120ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #ifndef INCLUDE_fetchhead_h__ #define INCLUDE_fetchhead_h__ #include "vector.h" struct git_fetchhead_ref { git_oid oid; unsigned int is_merge; char *ref_name; char *remote_url; }; typedef struct git_fetchhead_ref git_fetchhead_ref; int git_fetchhead_ref_create( git_fetchhead_ref **fetchhead_ref_out, git_oid *oid, unsigned int is_merge, const char *ref_name, const char *remote_url); int git_fetchhead_ref_cmp(const void *a, const void *b); int git_fetchhead_write(git_repository *repo, git_vector *fetchhead_refs); void git_fetchhead_ref_free(git_fetchhead_ref *fetchhead_ref); #endif libgit2-0.19.0/src/filebuf.c000066400000000000000000000245761216214232500155200ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #include #include "common.h" #include "filebuf.h" #include "fileops.h" #define GIT_LOCK_FILE_MODE 0644 static const size_t WRITE_BUFFER_SIZE = (4096 * 2); enum buferr_t { BUFERR_OK = 0, BUFERR_WRITE, BUFERR_ZLIB, BUFERR_MEM }; #define ENSURE_BUF_OK(buf) if ((buf)->last_error != BUFERR_OK) { return -1; } static int verify_last_error(git_filebuf *file) { switch (file->last_error) { case BUFERR_WRITE: giterr_set(GITERR_OS, "Failed to write out file"); return -1; case BUFERR_MEM: giterr_set_oom(); return -1; case BUFERR_ZLIB: giterr_set(GITERR_ZLIB, "Buffer error when writing out ZLib data"); return -1; default: return 0; } } static int lock_file(git_filebuf *file, int flags) { if (git_path_exists(file->path_lock) == true) { if (flags & GIT_FILEBUF_FORCE) p_unlink(file->path_lock); else { giterr_clear(); /* actual OS error code just confuses */ giterr_set(GITERR_OS, "Failed to lock file '%s' for writing", file->path_lock); return -1; } } /* create path to the file buffer is required */ if (flags & GIT_FILEBUF_FORCE) { /* XXX: Should dirmode here be configurable? Or is 0777 always fine? */ file->fd = git_futils_creat_locked_withpath(file->path_lock, 0777, GIT_LOCK_FILE_MODE); } else { file->fd = git_futils_creat_locked(file->path_lock, GIT_LOCK_FILE_MODE); } if (file->fd < 0) return -1; file->fd_is_open = true; if ((flags & GIT_FILEBUF_APPEND) && git_path_exists(file->path_original) == true) { git_file source; char buffer[2048]; ssize_t read_bytes; source = p_open(file->path_original, O_RDONLY); if (source < 0) { giterr_set(GITERR_OS, "Failed to open file '%s' for reading", file->path_original); return -1; } while ((read_bytes = p_read(source, buffer, sizeof(buffer))) > 0) { p_write(file->fd, buffer, read_bytes); if (file->compute_digest) git_hash_update(&file->digest, buffer, read_bytes); } p_close(source); if (read_bytes < 0) { giterr_set(GITERR_OS, "Failed to read file '%s'", file->path_original); return -1; } } return 0; } void git_filebuf_cleanup(git_filebuf *file) { if (file->fd_is_open && file->fd >= 0) p_close(file->fd); if (file->fd_is_open && file->path_lock && git_path_exists(file->path_lock)) p_unlink(file->path_lock); if (file->compute_digest) { git_hash_ctx_cleanup(&file->digest); file->compute_digest = 0; } if (file->buffer) git__free(file->buffer); /* use the presence of z_buf to decide if we need to deflateEnd */ if (file->z_buf) { git__free(file->z_buf); deflateEnd(&file->zs); } if (file->path_original) git__free(file->path_original); if (file->path_lock) git__free(file->path_lock); memset(file, 0x0, sizeof(git_filebuf)); file->fd = -1; } GIT_INLINE(int) flush_buffer(git_filebuf *file) { int result = file->write(file, file->buffer, file->buf_pos); file->buf_pos = 0; return result; } int git_filebuf_flush(git_filebuf *file) { return flush_buffer(file); } static int write_normal(git_filebuf *file, void *source, size_t len) { if (len > 0) { if (p_write(file->fd, (void *)source, len) < 0) { file->last_error = BUFERR_WRITE; return -1; } if (file->compute_digest) git_hash_update(&file->digest, source, len); } return 0; } static int write_deflate(git_filebuf *file, void *source, size_t len) { z_stream *zs = &file->zs; if (len > 0 || file->flush_mode == Z_FINISH) { zs->next_in = source; zs->avail_in = (uInt)len; do { size_t have; zs->next_out = file->z_buf; zs->avail_out = (uInt)file->buf_size; if (deflate(zs, file->flush_mode) == Z_STREAM_ERROR) { file->last_error = BUFERR_ZLIB; return -1; } have = file->buf_size - (size_t)zs->avail_out; if (p_write(file->fd, file->z_buf, have) < 0) { file->last_error = BUFERR_WRITE; return -1; } } while (zs->avail_out == 0); assert(zs->avail_in == 0); if (file->compute_digest) git_hash_update(&file->digest, source, len); } return 0; } int git_filebuf_open(git_filebuf *file, const char *path, int flags) { int compression; size_t path_len; /* opening an already open buffer is a programming error; * assert that this never happens instead of returning * an error code */ assert(file && path && file->buffer == NULL); memset(file, 0x0, sizeof(git_filebuf)); if (flags & GIT_FILEBUF_DO_NOT_BUFFER) file->do_not_buffer = true; file->buf_size = WRITE_BUFFER_SIZE; file->buf_pos = 0; file->fd = -1; file->last_error = BUFERR_OK; /* Allocate the main cache buffer */ if (!file->do_not_buffer) { file->buffer = git__malloc(file->buf_size); GITERR_CHECK_ALLOC(file->buffer); } /* If we are hashing on-write, allocate a new hash context */ if (flags & GIT_FILEBUF_HASH_CONTENTS) { file->compute_digest = 1; if (git_hash_ctx_init(&file->digest) < 0) goto cleanup; } compression = flags >> GIT_FILEBUF_DEFLATE_SHIFT; /* If we are deflating on-write, */ if (compression != 0) { /* Initialize the ZLib stream */ if (deflateInit(&file->zs, compression) != Z_OK) { giterr_set(GITERR_ZLIB, "Failed to initialize zlib"); goto cleanup; } /* Allocate the Zlib cache buffer */ file->z_buf = git__malloc(file->buf_size); GITERR_CHECK_ALLOC(file->z_buf); /* Never flush */ file->flush_mode = Z_NO_FLUSH; file->write = &write_deflate; } else { file->write = &write_normal; } /* If we are writing to a temp file */ if (flags & GIT_FILEBUF_TEMPORARY) { git_buf tmp_path = GIT_BUF_INIT; /* Open the file as temporary for locking */ file->fd = git_futils_mktmp(&tmp_path, path); if (file->fd < 0) { git_buf_free(&tmp_path); goto cleanup; } file->fd_is_open = true; /* No original path */ file->path_original = NULL; file->path_lock = git_buf_detach(&tmp_path); GITERR_CHECK_ALLOC(file->path_lock); } else { path_len = strlen(path); /* Save the original path of the file */ file->path_original = git__strdup(path); GITERR_CHECK_ALLOC(file->path_original); /* create the locking path by appending ".lock" to the original */ file->path_lock = git__malloc(path_len + GIT_FILELOCK_EXTLENGTH); GITERR_CHECK_ALLOC(file->path_lock); 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 (lock_file(file, flags) < 0) goto cleanup; } return 0; cleanup: git_filebuf_cleanup(file); return -1; } int git_filebuf_hash(git_oid *oid, git_filebuf *file) { assert(oid && file && file->compute_digest); flush_buffer(file); if (verify_last_error(file) < 0) return -1; git_hash_final(oid, &file->digest); git_hash_ctx_cleanup(&file->digest); file->compute_digest = 0; return 0; } int git_filebuf_commit_at(git_filebuf *file, const char *path, mode_t mode) { git__free(file->path_original); file->path_original = git__strdup(path); GITERR_CHECK_ALLOC(file->path_original); return git_filebuf_commit(file, mode); } int git_filebuf_commit(git_filebuf *file, mode_t mode) { /* temporary files cannot be committed */ assert(file && file->path_original); file->flush_mode = Z_FINISH; flush_buffer(file); if (verify_last_error(file) < 0) goto on_error; file->fd_is_open = false; if (p_close(file->fd) < 0) { giterr_set(GITERR_OS, "Failed to close file at '%s'", file->path_lock); goto on_error; } file->fd = -1; if (p_chmod(file->path_lock, mode)) { giterr_set(GITERR_OS, "Failed to set attributes for file at '%s'", file->path_lock); goto on_error; } p_unlink(file->path_original); if (p_rename(file->path_lock, file->path_original) < 0) { giterr_set(GITERR_OS, "Failed to rename lockfile to '%s'", file->path_original); goto on_error; } git_filebuf_cleanup(file); return 0; on_error: git_filebuf_cleanup(file); return -1; } GIT_INLINE(void) add_to_cache(git_filebuf *file, const void *buf, size_t len) { memcpy(file->buffer + file->buf_pos, buf, len); file->buf_pos += len; } int git_filebuf_write(git_filebuf *file, const void *buff, size_t len) { const unsigned char *buf = buff; ENSURE_BUF_OK(file); if (file->do_not_buffer) return file->write(file, (void *)buff, len); for (;;) { size_t space_left = file->buf_size - file->buf_pos; /* cache if it's small */ if (space_left > len) { add_to_cache(file, buf, len); return 0; } add_to_cache(file, buf, space_left); if (flush_buffer(file) < 0) return -1; len -= space_left; buf += space_left; } } int git_filebuf_reserve(git_filebuf *file, void **buffer, size_t len) { size_t space_left = file->buf_size - file->buf_pos; *buffer = NULL; ENSURE_BUF_OK(file); if (len > file->buf_size) { file->last_error = BUFERR_MEM; return -1; } if (space_left <= len) { if (flush_buffer(file) < 0) return -1; } *buffer = (file->buffer + file->buf_pos); file->buf_pos += len; return 0; } int git_filebuf_printf(git_filebuf *file, const char *format, ...) { va_list arglist; size_t space_left; int len, res; char *tmp_buffer; ENSURE_BUF_OK(file); space_left = file->buf_size - file->buf_pos; do { va_start(arglist, format); len = p_vsnprintf((char *)file->buffer + file->buf_pos, space_left, format, arglist); va_end(arglist); if (len < 0) { file->last_error = BUFERR_MEM; return -1; } if ((size_t)len + 1 <= space_left) { file->buf_pos += len; return 0; } if (flush_buffer(file) < 0) return -1; space_left = file->buf_size - file->buf_pos; } while ((size_t)len + 1 <= space_left); tmp_buffer = git__malloc(len + 1); if (!tmp_buffer) { file->last_error = BUFERR_MEM; return -1; } va_start(arglist, format); len = p_vsnprintf(tmp_buffer, len + 1, format, arglist); va_end(arglist); if (len < 0) { git__free(tmp_buffer); file->last_error = BUFERR_MEM; return -1; } res = git_filebuf_write(file, tmp_buffer, len); git__free(tmp_buffer); return res; } int git_filebuf_stats(time_t *mtime, size_t *size, git_filebuf *file) { int res; struct stat st; if (file->fd_is_open) res = p_fstat(file->fd, &st); else res = p_stat(file->path_original, &st); if (res < 0) { giterr_set(GITERR_OS, "Could not get stat info for '%s'", file->path_original); return res; } if (mtime) *mtime = st.st_mtime; if (size) *size = (size_t)st.st_size; return 0; } libgit2-0.19.0/src/filebuf.h000066400000000000000000000052751216214232500155200ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #ifndef INCLUDE_filebuf_h__ #define INCLUDE_filebuf_h__ #include "fileops.h" #include "hash.h" #include #ifdef GIT_THREADS # define GIT_FILEBUF_THREADS #endif #define GIT_FILEBUF_HASH_CONTENTS (1 << 0) #define GIT_FILEBUF_APPEND (1 << 2) #define GIT_FILEBUF_FORCE (1 << 3) #define GIT_FILEBUF_TEMPORARY (1 << 4) #define GIT_FILEBUF_DO_NOT_BUFFER (1 << 5) #define GIT_FILEBUF_DEFLATE_SHIFT (6) #define GIT_FILELOCK_EXTENSION ".lock\0" #define GIT_FILELOCK_EXTLENGTH 6 struct git_filebuf { char *path_original; char *path_lock; int (*write)(struct git_filebuf *file, void *source, size_t len); bool compute_digest; git_hash_ctx digest; unsigned char *buffer; unsigned char *z_buf; z_stream zs; int flush_mode; size_t buf_size, buf_pos; git_file fd; bool fd_is_open; bool do_not_buffer; int last_error; }; typedef struct git_filebuf git_filebuf; #define GIT_FILEBUF_INIT {0} /* * The git_filebuf object lifecycle is: * - Allocate git_filebuf, preferably using GIT_FILEBUF_INIT. * * - Call git_filebuf_open() to initialize the filebuf for use. * * - Make as many calls to git_filebuf_write(), git_filebuf_printf(), * git_filebuf_reserve() as you like. The error codes for these * functions don't need to be checked. They are stored internally * by the file buffer. * * - While you are writing, you may call git_filebuf_hash() to get * the hash of all you have written so far. This function will * fail if any of the previous writes to the buffer failed. * * - To close the git_filebuf, you may call git_filebuf_commit() or * git_filebuf_commit_at() to save the file, or * git_filebuf_cleanup() to abandon the file. All of these will * free the git_filebuf object. Likewise, all of these will fail * if any of the previous writes to the buffer failed, and set * an error code accordingly. */ int git_filebuf_write(git_filebuf *lock, const void *buff, size_t len); int git_filebuf_reserve(git_filebuf *file, void **buff, size_t len); int git_filebuf_printf(git_filebuf *file, const char *format, ...) GIT_FORMAT_PRINTF(2, 3); int git_filebuf_open(git_filebuf *lock, const char *path, int flags); int git_filebuf_commit(git_filebuf *lock, mode_t mode); int git_filebuf_commit_at(git_filebuf *lock, const char *path, mode_t mode); void git_filebuf_cleanup(git_filebuf *lock); int git_filebuf_hash(git_oid *oid, git_filebuf *file); int git_filebuf_flush(git_filebuf *file); int git_filebuf_stats(time_t *mtime, size_t *size, git_filebuf *file); #endif libgit2-0.19.0/src/fileops.c000066400000000000000000000600441216214232500155330ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #include "common.h" #include "fileops.h" #include #if GIT_WIN32 #include "win32/findfile.h" #endif int git_futils_mkpath2file(const char *file_path, const mode_t mode) { return git_futils_mkdir( file_path, NULL, mode, GIT_MKDIR_PATH | GIT_MKDIR_SKIP_LAST | GIT_MKDIR_VERIFY_DIR); } int git_futils_mktmp(git_buf *path_out, const char *filename) { int fd; git_buf_sets(path_out, filename); git_buf_puts(path_out, "_git2_XXXXXX"); if (git_buf_oom(path_out)) return -1; if ((fd = p_mkstemp(path_out->ptr)) < 0) { giterr_set(GITERR_OS, "Failed to create temporary file '%s'", path_out->ptr); return -1; } return fd; } int git_futils_creat_withpath(const char *path, const mode_t dirmode, const mode_t mode) { int fd; if (git_futils_mkpath2file(path, dirmode) < 0) return -1; fd = p_creat(path, mode); if (fd < 0) { giterr_set(GITERR_OS, "Failed to create file '%s'", path); return -1; } return fd; } int git_futils_creat_locked(const char *path, const mode_t mode) { int fd; #ifdef GIT_WIN32 wchar_t buf[GIT_WIN_PATH]; git__utf8_to_16(buf, GIT_WIN_PATH, path); fd = _wopen(buf, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL | O_BINARY | O_CLOEXEC, mode); #else fd = open(path, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL | O_BINARY | O_CLOEXEC, mode); #endif if (fd < 0) { giterr_set(GITERR_OS, "Failed to create locked file '%s'", path); return -1; } return fd; } int git_futils_creat_locked_withpath(const char *path, const mode_t dirmode, const mode_t mode) { if (git_futils_mkpath2file(path, dirmode) < 0) return -1; return git_futils_creat_locked(path, mode); } int git_futils_open_ro(const char *path) { int fd = p_open(path, O_RDONLY); if (fd < 0) { if (errno == ENOENT || errno == ENOTDIR) fd = GIT_ENOTFOUND; giterr_set(GITERR_OS, "Failed to open '%s'", path); } return fd; } git_off_t git_futils_filesize(git_file fd) { struct stat sb; if (p_fstat(fd, &sb)) { giterr_set(GITERR_OS, "Failed to stat file descriptor"); return -1; } return sb.st_size; } mode_t git_futils_canonical_mode(mode_t raw_mode) { if (S_ISREG(raw_mode)) return S_IFREG | GIT_CANONICAL_PERMS(raw_mode); else if (S_ISLNK(raw_mode)) return S_IFLNK; else if (S_ISGITLINK(raw_mode)) return S_IFGITLINK; else if (S_ISDIR(raw_mode)) return S_IFDIR; else return 0; } int git_futils_readbuffer_fd(git_buf *buf, git_file fd, size_t len) { ssize_t read_size = 0; git_buf_clear(buf); if (git_buf_grow(buf, len + 1) < 0) return -1; /* p_read loops internally to read len bytes */ read_size = p_read(fd, buf->ptr, len); if (read_size != (ssize_t)len) { giterr_set(GITERR_OS, "Failed to read descriptor"); return -1; } buf->ptr[read_size] = '\0'; buf->size = read_size; return 0; } int git_futils_readbuffer_updated( git_buf *buf, const char *path, time_t *mtime, size_t *size, int *updated) { git_file fd; struct stat st; bool changed = false; assert(buf && path && *path); if (updated != NULL) *updated = 0; if ((fd = git_futils_open_ro(path)) < 0) return fd; if (p_fstat(fd, &st) < 0 || S_ISDIR(st.st_mode) || !git__is_sizet(st.st_size+1)) { p_close(fd); giterr_set(GITERR_OS, "Invalid regular file stat for '%s'", path); return -1; } /* * If we were given a time and/or a size, we only want to read the file * if it has been modified. */ if (size && *size != (size_t)st.st_size) changed = true; if (mtime && *mtime != st.st_mtime) changed = true; if (!size && !mtime) changed = true; if (!changed) { p_close(fd); return 0; } if (mtime != NULL) *mtime = st.st_mtime; if (size != NULL) *size = (size_t)st.st_size; if (git_futils_readbuffer_fd(buf, fd, (size_t)st.st_size) < 0) { p_close(fd); return -1; } p_close(fd); if (updated != NULL) *updated = 1; return 0; } int git_futils_readbuffer(git_buf *buf, const char *path) { return git_futils_readbuffer_updated(buf, path, NULL, NULL, NULL); } int git_futils_writebuffer( const git_buf *buf, const char *path, int flags, mode_t mode) { int fd, error = 0; if (flags <= 0) flags = O_CREAT | O_TRUNC | O_WRONLY; if (!mode) mode = GIT_FILEMODE_BLOB; if ((fd = p_open(path, flags, mode)) < 0) { giterr_set(GITERR_OS, "Could not open '%s' for writing", path); return fd; } if ((error = p_write(fd, git_buf_cstr(buf), git_buf_len(buf))) < 0) { giterr_set(GITERR_OS, "Could not write to '%s'", path); (void)p_close(fd); } if ((error = p_close(fd)) < 0) giterr_set(GITERR_OS, "Error while closing '%s'", path); return error; } int git_futils_mv_withpath(const char *from, const char *to, const mode_t dirmode) { if (git_futils_mkpath2file(to, dirmode) < 0) return -1; if (p_rename(from, to) < 0) { giterr_set(GITERR_OS, "Failed to rename '%s' to '%s'", from, to); return -1; } return 0; } int git_futils_mmap_ro(git_map *out, git_file fd, git_off_t begin, size_t len) { return p_mmap(out, len, GIT_PROT_READ, GIT_MAP_SHARED, fd, begin); } int git_futils_mmap_ro_file(git_map *out, const char *path) { git_file fd = git_futils_open_ro(path); git_off_t len; int result; if (fd < 0) return fd; len = git_futils_filesize(fd); if (!git__is_sizet(len)) { giterr_set(GITERR_OS, "File `%s` too large to mmap", path); return -1; } result = git_futils_mmap_ro(out, fd, 0, (size_t)len); p_close(fd); return result; } void git_futils_mmap_free(git_map *out) { p_munmap(out); } int git_futils_mkdir( const char *path, const char *base, mode_t mode, uint32_t flags) { int error = -1; git_buf make_path = GIT_BUF_INIT; ssize_t root = 0, min_root_len; char lastch = '/', *tail; struct stat st; /* build path and find "root" where we should start calling mkdir */ if (git_path_join_unrooted(&make_path, path, base, &root) < 0) return -1; if (make_path.size == 0) { giterr_set(GITERR_OS, "Attempt to create empty path"); goto done; } /* remove trailing slashes on path */ while (make_path.ptr[make_path.size - 1] == '/') { make_path.size--; make_path.ptr[make_path.size] = '\0'; } /* if we are not supposed to made the last element, truncate it */ if ((flags & GIT_MKDIR_SKIP_LAST2) != 0) { git_buf_rtruncate_at_char(&make_path, '/'); flags |= GIT_MKDIR_SKIP_LAST; } if ((flags & GIT_MKDIR_SKIP_LAST) != 0) git_buf_rtruncate_at_char(&make_path, '/'); /* if nothing left after truncation, then we're done! */ if (!make_path.size) { error = 0; goto done; } /* if we are not supposed to make the whole path, reset root */ if ((flags & GIT_MKDIR_PATH) == 0) root = git_buf_rfind(&make_path, '/'); /* advance root past drive name or network mount prefix */ min_root_len = git_path_root(make_path.ptr); if (root < min_root_len) root = min_root_len; while (root >= 0 && make_path.ptr[root] == '/') ++root; /* clip root to make_path length */ if (root > (ssize_t)make_path.size) root = (ssize_t)make_path.size; /* i.e. NUL byte of string */ if (root < 0) root = 0; /* walk down tail of path making each directory */ for (tail = &make_path.ptr[root]; *tail; *tail = lastch) { /* advance tail to include next path component */ while (*tail == '/') tail++; while (*tail && *tail != '/') tail++; /* truncate path at next component */ lastch = *tail; *tail = '\0'; st.st_mode = 0; /* make directory */ if (p_mkdir(make_path.ptr, mode) < 0) { int tmp_errno = errno; /* ignore error if directory already exists */ if (p_stat(make_path.ptr, &st) < 0 || !(S_ISDIR(st.st_mode) || S_ISLNK(st.st_mode))) { errno = tmp_errno; giterr_set(GITERR_OS, "Failed to make directory '%s'", make_path.ptr); goto done; } /* with exclusive create, existing dir is an error */ if ((flags & GIT_MKDIR_EXCL) != 0) { giterr_set(GITERR_OS, "Directory already exists '%s'", make_path.ptr); error = GIT_EEXISTS; goto done; } } /* chmod if requested and necessary */ if (((flags & GIT_MKDIR_CHMOD_PATH) != 0 || (lastch == '\0' && (flags & GIT_MKDIR_CHMOD) != 0)) && st.st_mode != mode && (error = p_chmod(make_path.ptr, mode)) < 0) { giterr_set(GITERR_OS, "Failed to set permissions on '%s'", make_path.ptr); goto done; } } error = 0; /* check that full path really is a directory if requested & needed */ if ((flags & GIT_MKDIR_VERIFY_DIR) != 0 && lastch != '\0' && (p_stat(make_path.ptr, &st) < 0 || !S_ISDIR(st.st_mode))) { giterr_set(GITERR_OS, "Path is not a directory '%s'", make_path.ptr); error = GIT_ENOTFOUND; } done: git_buf_free(&make_path); return error; } int git_futils_mkdir_r(const char *path, const char *base, const mode_t mode) { return git_futils_mkdir(path, base, mode, GIT_MKDIR_PATH); } typedef struct { const char *base; size_t baselen; uint32_t flags; int error; } futils__rmdir_data; static int futils__error_cannot_rmdir(const char *path, const char *filemsg) { if (filemsg) giterr_set(GITERR_OS, "Could not remove directory. File '%s' %s", path, filemsg); else giterr_set(GITERR_OS, "Could not remove directory '%s'", path); return -1; } static int futils__rm_first_parent(git_buf *path, const char *ceiling) { int error = GIT_ENOTFOUND; struct stat st; while (error == GIT_ENOTFOUND) { git_buf_rtruncate_at_char(path, '/'); if (!path->size || git__prefixcmp(path->ptr, ceiling) != 0) error = 0; else if (p_lstat_posixly(path->ptr, &st) == 0) { if (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)) error = p_unlink(path->ptr); else if (!S_ISDIR(st.st_mode)) error = -1; /* fail to remove non-regular file */ } else if (errno != ENOTDIR) error = -1; } if (error) futils__error_cannot_rmdir(path->ptr, "cannot remove parent"); return error; } static int futils__rmdir_recurs_foreach(void *opaque, git_buf *path) { struct stat st; futils__rmdir_data *data = opaque; if ((data->error = p_lstat_posixly(path->ptr, &st)) < 0) { if (errno == ENOENT) data->error = 0; else if (errno == ENOTDIR) { /* asked to remove a/b/c/d/e and a/b is a normal file */ if ((data->flags & GIT_RMDIR_REMOVE_BLOCKERS) != 0) data->error = futils__rm_first_parent(path, data->base); else futils__error_cannot_rmdir( path->ptr, "parent is not directory"); } else futils__error_cannot_rmdir(path->ptr, "cannot access"); } else if (S_ISDIR(st.st_mode)) { int error = git_path_direach(path, futils__rmdir_recurs_foreach, data); if (error < 0) return (error == GIT_EUSER) ? data->error : error; data->error = p_rmdir(path->ptr); if (data->error < 0) { if ((data->flags & GIT_RMDIR_SKIP_NONEMPTY) != 0 && (errno == ENOTEMPTY || errno == EEXIST || errno == EBUSY)) data->error = 0; else futils__error_cannot_rmdir(path->ptr, NULL); } } else if ((data->flags & GIT_RMDIR_REMOVE_FILES) != 0) { data->error = p_unlink(path->ptr); if (data->error < 0) futils__error_cannot_rmdir(path->ptr, "cannot be removed"); } else if ((data->flags & GIT_RMDIR_SKIP_NONEMPTY) == 0) data->error = futils__error_cannot_rmdir(path->ptr, "still present"); return data->error; } static int futils__rmdir_empty_parent(void *opaque, git_buf *path) { futils__rmdir_data *data = opaque; int error; if (git_buf_len(path) <= data->baselen) return GIT_ITEROVER; error = p_rmdir(git_buf_cstr(path)); if (error) { int en = errno; if (en == ENOENT || en == ENOTDIR) { giterr_clear(); error = 0; } else if (en == ENOTEMPTY || en == EEXIST || en == EBUSY) { giterr_clear(); error = GIT_ITEROVER; } else { futils__error_cannot_rmdir(git_buf_cstr(path), NULL); } } return error; } int git_futils_rmdir_r( const char *path, const char *base, uint32_t flags) { int error; git_buf fullpath = GIT_BUF_INIT; futils__rmdir_data data; /* build path and find "root" where we should start calling mkdir */ if (git_path_join_unrooted(&fullpath, path, base, NULL) < 0) return -1; data.base = base ? base : ""; data.baselen = base ? strlen(base) : 0; data.flags = flags; data.error = 0; error = futils__rmdir_recurs_foreach(&data, &fullpath); /* remove now-empty parents if requested */ if (!error && (flags & GIT_RMDIR_EMPTY_PARENTS) != 0) { error = git_path_walk_up( &fullpath, base, futils__rmdir_empty_parent, &data); if (error == GIT_ITEROVER) error = 0; } git_buf_free(&fullpath); return error; } int git_futils_cleanupdir_r(const char *path) { int error; git_buf fullpath = GIT_BUF_INIT; futils__rmdir_data data; if ((error = git_buf_put(&fullpath, path, strlen(path))) < 0) goto clean_up; data.base = ""; data.baselen = 0; data.flags = GIT_RMDIR_REMOVE_FILES; data.error = 0; if (!git_path_exists(path)) { giterr_set(GITERR_OS, "Path does not exist: %s" , path); error = GIT_ERROR; goto clean_up; } if (!git_path_isdir(path)) { giterr_set(GITERR_OS, "Path is not a directory: %s" , path); error = GIT_ERROR; goto clean_up; } error = git_path_direach(&fullpath, futils__rmdir_recurs_foreach, &data); if (error == GIT_EUSER) error = data.error; clean_up: git_buf_free(&fullpath); return error; } static int git_futils_guess_system_dirs(git_buf *out) { #ifdef GIT_WIN32 return git_win32__find_system_dirs(out); #else return git_buf_sets(out, "/etc"); #endif } static int git_futils_guess_global_dirs(git_buf *out) { #ifdef GIT_WIN32 return git_win32__find_global_dirs(out); #else return git_buf_sets(out, getenv("HOME")); #endif } static int git_futils_guess_xdg_dirs(git_buf *out) { #ifdef GIT_WIN32 return git_win32__find_xdg_dirs(out); #else const char *env = NULL; if ((env = getenv("XDG_CONFIG_HOME")) != NULL) return git_buf_joinpath(out, env, "git"); else if ((env = getenv("HOME")) != NULL) return git_buf_joinpath(out, env, ".config/git"); git_buf_clear(out); return 0; #endif } typedef int (*git_futils_dirs_guess_cb)(git_buf *out); static git_buf git_futils__dirs[GIT_FUTILS_DIR__MAX] = { GIT_BUF_INIT, GIT_BUF_INIT, GIT_BUF_INIT }; static git_futils_dirs_guess_cb git_futils__dir_guess[GIT_FUTILS_DIR__MAX] = { git_futils_guess_system_dirs, git_futils_guess_global_dirs, git_futils_guess_xdg_dirs, }; static int git_futils_check_selector(git_futils_dir_t which) { if (which < GIT_FUTILS_DIR__MAX) return 0; giterr_set(GITERR_INVALID, "config directory selector out of range"); return -1; } int git_futils_dirs_get(const git_buf **out, git_futils_dir_t which) { assert(out); *out = NULL; GITERR_CHECK_ERROR(git_futils_check_selector(which)); if (!git_buf_len(&git_futils__dirs[which])) GITERR_CHECK_ERROR( git_futils__dir_guess[which](&git_futils__dirs[which])); *out = &git_futils__dirs[which]; return 0; } int git_futils_dirs_get_str(char *out, size_t outlen, git_futils_dir_t which) { const git_buf *path = NULL; GITERR_CHECK_ERROR(git_futils_check_selector(which)); GITERR_CHECK_ERROR(git_futils_dirs_get(&path, which)); if (!out || path->size >= outlen) { giterr_set(GITERR_NOMEMORY, "Buffer is too short for the path"); return GIT_EBUFS; } git_buf_copy_cstr(out, outlen, path); return 0; } #define PATH_MAGIC "$PATH" int git_futils_dirs_set(git_futils_dir_t which, const char *search_path) { const char *expand_path = NULL; git_buf merge = GIT_BUF_INIT; GITERR_CHECK_ERROR(git_futils_check_selector(which)); if (search_path != NULL) expand_path = strstr(search_path, PATH_MAGIC); /* init with default if not yet done and needed (ignoring error) */ if ((!search_path || expand_path) && !git_buf_len(&git_futils__dirs[which])) git_futils__dir_guess[which](&git_futils__dirs[which]); /* if $PATH is not referenced, then just set the path */ if (!expand_path) return git_buf_sets(&git_futils__dirs[which], search_path); /* otherwise set to join(before $PATH, old value, after $PATH) */ if (expand_path > search_path) git_buf_set(&merge, search_path, expand_path - search_path); if (git_buf_len(&git_futils__dirs[which])) git_buf_join(&merge, GIT_PATH_LIST_SEPARATOR, merge.ptr, git_futils__dirs[which].ptr); expand_path += strlen(PATH_MAGIC); if (*expand_path) git_buf_join(&merge, GIT_PATH_LIST_SEPARATOR, merge.ptr, expand_path); git_buf_swap(&git_futils__dirs[which], &merge); git_buf_free(&merge); return git_buf_oom(&git_futils__dirs[which]) ? -1 : 0; } void git_futils_dirs_free(void) { int i; for (i = 0; i < GIT_FUTILS_DIR__MAX; ++i) git_buf_free(&git_futils__dirs[i]); } static int git_futils_find_in_dirlist( git_buf *path, const char *name, git_futils_dir_t which, const char *label) { size_t len; const char *scan, *next = NULL; const git_buf *syspath; GITERR_CHECK_ERROR(git_futils_dirs_get(&syspath, which)); for (scan = git_buf_cstr(syspath); scan; scan = next) { for (next = strchr(scan, GIT_PATH_LIST_SEPARATOR); next && next > scan && next[-1] == '\\'; next = strchr(next + 1, GIT_PATH_LIST_SEPARATOR)) /* find unescaped separator or end of string */; len = next ? (size_t)(next++ - scan) : strlen(scan); if (!len) continue; GITERR_CHECK_ERROR(git_buf_set(path, scan, len)); GITERR_CHECK_ERROR(git_buf_joinpath(path, path->ptr, name)); if (git_path_exists(path->ptr)) return 0; } git_buf_clear(path); giterr_set(GITERR_OS, "The %s file '%s' doesn't exist", label, name); return GIT_ENOTFOUND; } int git_futils_find_system_file(git_buf *path, const char *filename) { return git_futils_find_in_dirlist( path, filename, GIT_FUTILS_DIR_SYSTEM, "system"); } int git_futils_find_global_file(git_buf *path, const char *filename) { return git_futils_find_in_dirlist( path, filename, GIT_FUTILS_DIR_GLOBAL, "global"); } int git_futils_find_xdg_file(git_buf *path, const char *filename) { return git_futils_find_in_dirlist( path, filename, GIT_FUTILS_DIR_XDG, "global/xdg"); } int git_futils_fake_symlink(const char *old, const char *new) { int retcode = GIT_ERROR; int fd = git_futils_creat_withpath(new, 0755, 0644); if (fd >= 0) { retcode = p_write(fd, old, strlen(old)); p_close(fd); } return retcode; } static int cp_by_fd(int ifd, int ofd, bool close_fd_when_done) { int error = 0; char buffer[4096]; ssize_t len = 0; while (!error && (len = p_read(ifd, buffer, sizeof(buffer))) > 0) /* p_write() does not have the same semantics as write(). It loops * internally and will return 0 when it has completed writing. */ error = p_write(ofd, buffer, len); if (len < 0) { giterr_set(GITERR_OS, "Read error while copying file"); error = (int)len; } if (close_fd_when_done) { p_close(ifd); p_close(ofd); } return error; } int git_futils_cp(const char *from, const char *to, mode_t filemode) { int ifd, ofd; if ((ifd = git_futils_open_ro(from)) < 0) return ifd; if ((ofd = p_open(to, O_WRONLY | O_CREAT | O_EXCL, filemode)) < 0) { if (errno == ENOENT || errno == ENOTDIR) ofd = GIT_ENOTFOUND; giterr_set(GITERR_OS, "Failed to open '%s' for writing", to); p_close(ifd); return ofd; } return cp_by_fd(ifd, ofd, true); } static int cp_link(const char *from, const char *to, size_t link_size) { int error = 0; ssize_t read_len; char *link_data = git__malloc(link_size + 1); GITERR_CHECK_ALLOC(link_data); read_len = p_readlink(from, link_data, link_size); if (read_len != (ssize_t)link_size) { giterr_set(GITERR_OS, "Failed to read symlink data for '%s'", from); error = -1; } else { link_data[read_len] = '\0'; if (p_symlink(link_data, to) < 0) { giterr_set(GITERR_OS, "Could not symlink '%s' as '%s'", link_data, to); error = -1; } } git__free(link_data); return error; } typedef struct { const char *to_root; git_buf to; ssize_t from_prefix; uint32_t flags; uint32_t mkdir_flags; mode_t dirmode; } cp_r_info; #define GIT_CPDIR__MKDIR_DONE_FOR_TO_ROOT (1u << 10) static int _cp_r_mkdir(cp_r_info *info, git_buf *from) { int error = 0; /* create root directory the first time we need to create a directory */ if ((info->flags & GIT_CPDIR__MKDIR_DONE_FOR_TO_ROOT) == 0) { error = git_futils_mkdir( info->to_root, NULL, info->dirmode, (info->flags & GIT_CPDIR_CHMOD_DIRS) ? GIT_MKDIR_CHMOD : 0); info->flags |= GIT_CPDIR__MKDIR_DONE_FOR_TO_ROOT; } /* create directory with root as base to prevent excess chmods */ if (!error) error = git_futils_mkdir( from->ptr + info->from_prefix, info->to_root, info->dirmode, info->mkdir_flags); return error; } static int _cp_r_callback(void *ref, git_buf *from) { int error = 0; cp_r_info *info = ref; struct stat from_st, to_st; bool exists = false; if ((info->flags & GIT_CPDIR_COPY_DOTFILES) == 0 && from->ptr[git_path_basename_offset(from)] == '.') return 0; if (git_buf_joinpath( &info->to, info->to_root, from->ptr + info->from_prefix) < 0) return -1; if (p_lstat(info->to.ptr, &to_st) < 0) { if (errno != ENOENT && errno != ENOTDIR) { giterr_set(GITERR_OS, "Could not access %s while copying files", info->to.ptr); return -1; } } else exists = true; if ((error = git_path_lstat(from->ptr, &from_st)) < 0) return error; if (S_ISDIR(from_st.st_mode)) { mode_t oldmode = info->dirmode; /* if we are not chmod'ing, then overwrite dirmode */ if ((info->flags & GIT_CPDIR_CHMOD_DIRS) == 0) info->dirmode = from_st.st_mode; /* make directory now if CREATE_EMPTY_DIRS is requested and needed */ if (!exists && (info->flags & GIT_CPDIR_CREATE_EMPTY_DIRS) != 0) error = _cp_r_mkdir(info, from); /* recurse onto target directory */ if (!error && (!exists || S_ISDIR(to_st.st_mode))) error = git_path_direach(from, _cp_r_callback, info); if (oldmode != 0) info->dirmode = oldmode; return error; } if (exists) { if ((info->flags & GIT_CPDIR_OVERWRITE) == 0) return 0; if (p_unlink(info->to.ptr) < 0) { giterr_set(GITERR_OS, "Cannot overwrite existing file '%s'", info->to.ptr); return -1; } } /* Done if this isn't a regular file or a symlink */ if (!S_ISREG(from_st.st_mode) && (!S_ISLNK(from_st.st_mode) || (info->flags & GIT_CPDIR_COPY_SYMLINKS) == 0)) return 0; /* Make container directory on demand if needed */ if ((info->flags & GIT_CPDIR_CREATE_EMPTY_DIRS) == 0 && (error = _cp_r_mkdir(info, from)) < 0) return error; /* make symlink or regular file */ if (S_ISLNK(from_st.st_mode)) error = cp_link(from->ptr, info->to.ptr, (size_t)from_st.st_size); else { mode_t usemode = from_st.st_mode; if ((info->flags & GIT_CPDIR_SIMPLE_TO_MODE) != 0) usemode = (usemode & 0111) ? 0777 : 0666; error = git_futils_cp(from->ptr, info->to.ptr, usemode); } return error; } int git_futils_cp_r( const char *from, const char *to, uint32_t flags, mode_t dirmode) { int error; git_buf path = GIT_BUF_INIT; cp_r_info info; if (git_buf_joinpath(&path, from, "") < 0) /* ensure trailing slash */ return -1; info.to_root = to; info.flags = flags; info.dirmode = dirmode; info.from_prefix = path.size; git_buf_init(&info.to, 0); /* precalculate mkdir flags */ if ((flags & GIT_CPDIR_CREATE_EMPTY_DIRS) == 0) { /* if not creating empty dirs, then use mkdir to create the path on * demand right before files are copied. */ info.mkdir_flags = GIT_MKDIR_PATH | GIT_MKDIR_SKIP_LAST; if ((flags & GIT_CPDIR_CHMOD_DIRS) != 0) info.mkdir_flags |= GIT_MKDIR_CHMOD_PATH; } else { /* otherwise, we will do simple mkdir as directories are encountered */ info.mkdir_flags = ((flags & GIT_CPDIR_CHMOD_DIRS) != 0) ? GIT_MKDIR_CHMOD : 0; } error = _cp_r_callback(&info, &path); git_buf_free(&path); git_buf_free(&info.to); return error; } int git_futils_filestamp_check( git_futils_filestamp *stamp, const char *path) { struct stat st; /* if the stamp is NULL, then always reload */ if (stamp == NULL) return 1; if (p_stat(path, &st) < 0) { giterr_set(GITERR_OS, "Could not stat '%s'", path); return GIT_ENOTFOUND; } if (stamp->mtime == (git_time_t)st.st_mtime && stamp->size == (git_off_t)st.st_size && stamp->ino == (unsigned int)st.st_ino) return 0; stamp->mtime = (git_time_t)st.st_mtime; stamp->size = (git_off_t)st.st_size; stamp->ino = (unsigned int)st.st_ino; return 1; } void git_futils_filestamp_set( git_futils_filestamp *target, const git_futils_filestamp *source) { assert(target); if (source) memcpy(target, source, sizeof(*target)); else memset(target, 0, sizeof(*target)); } libgit2-0.19.0/src/fileops.h000066400000000000000000000314351216214232500155420ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #ifndef INCLUDE_fileops_h__ #define INCLUDE_fileops_h__ #include "common.h" #include "map.h" #include "posix.h" #include "path.h" /** * Filebuffer methods * * Read whole files into an in-memory buffer for processing */ extern int git_futils_readbuffer(git_buf *obj, const char *path); extern int git_futils_readbuffer_updated( git_buf *obj, const char *path, time_t *mtime, size_t *size, int *updated); extern int git_futils_readbuffer_fd(git_buf *obj, git_file fd, size_t len); extern int git_futils_writebuffer( const git_buf *buf, const char *path, int open_flags, mode_t mode); /** * File utils * * These are custom filesystem-related helper methods. They are * rather high level, and wrap the underlying POSIX methods * * All these methods return 0 on success, * or an error code on failure and an error message is set. */ /** * Create and open a file, while also * creating all the folders in its path */ extern int git_futils_creat_withpath(const char *path, const mode_t dirmode, const mode_t mode); /** * Create an open a process-locked file */ extern int git_futils_creat_locked(const char *path, const mode_t mode); /** * Create an open a process-locked file, while * also creating all the folders in its path */ extern int git_futils_creat_locked_withpath(const char *path, const mode_t dirmode, const mode_t mode); /** * Create a path recursively * * If a base parameter is being passed, it's expected to be valued with a * path pointing to an already existing directory. */ extern int git_futils_mkdir_r(const char *path, const char *base, const mode_t mode); /** * Flags to pass to `git_futils_mkdir`. * * * GIT_MKDIR_EXCL is "exclusive" - i.e. generate an error if dir exists. * * GIT_MKDIR_PATH says to make all components in the path. * * GIT_MKDIR_CHMOD says to chmod the final directory entry after creation * * GIT_MKDIR_CHMOD_PATH says to chmod each directory component in the path * * GIT_MKDIR_SKIP_LAST says to leave off the last element of the path * * GIT_MKDIR_SKIP_LAST2 says to leave off the last 2 elements of the path * * GIT_MKDIR_VERIFY_DIR says confirm final item is a dir, not just EEXIST * * Note that the chmod options will be executed even if the directory already * exists, unless GIT_MKDIR_EXCL is given. */ typedef enum { GIT_MKDIR_EXCL = 1, GIT_MKDIR_PATH = 2, GIT_MKDIR_CHMOD = 4, GIT_MKDIR_CHMOD_PATH = 8, GIT_MKDIR_SKIP_LAST = 16, GIT_MKDIR_SKIP_LAST2 = 32, GIT_MKDIR_VERIFY_DIR = 64, } git_futils_mkdir_flags; /** * Create a directory or entire path. * * This makes a directory (and the entire path leading up to it if requested), * and optionally chmods the directory immediately after (or each part of the * path if requested). * * @param path The path to create. * @param base Root for relative path. These directories will never be made. * @param mode The mode to use for created directories. * @param flags Combination of the mkdir flags above. * @return 0 on success, else error code */ extern int git_futils_mkdir(const char *path, const char *base, mode_t mode, uint32_t flags); /** * Create all the folders required to contain * the full path of a file */ extern int git_futils_mkpath2file(const char *path, const mode_t mode); /** * Flags to pass to `git_futils_rmdir_r`. * * * GIT_RMDIR_EMPTY_HIERARCHY - the default; remove hierarchy of empty * dirs and generate error if any files are found. * * GIT_RMDIR_REMOVE_FILES - attempt to remove files in the hierarchy. * * GIT_RMDIR_SKIP_NONEMPTY - skip non-empty directories with no error. * * GIT_RMDIR_EMPTY_PARENTS - remove containing directories up to base * if removing this item leaves them empty * * GIT_RMDIR_REMOVE_BLOCKERS - remove blocking file that causes ENOTDIR * * The old values translate into the new as follows: * * * GIT_DIRREMOVAL_EMPTY_HIERARCHY == GIT_RMDIR_EMPTY_HIERARCHY * * GIT_DIRREMOVAL_FILES_AND_DIRS ~= GIT_RMDIR_REMOVE_FILES * * GIT_DIRREMOVAL_ONLY_EMPTY_DIRS == GIT_RMDIR_SKIP_NONEMPTY */ typedef enum { GIT_RMDIR_EMPTY_HIERARCHY = 0, GIT_RMDIR_REMOVE_FILES = (1 << 0), GIT_RMDIR_SKIP_NONEMPTY = (1 << 1), GIT_RMDIR_EMPTY_PARENTS = (1 << 2), GIT_RMDIR_REMOVE_BLOCKERS = (1 << 3), } git_futils_rmdir_flags; /** * Remove path and any files and directories beneath it. * * @param path Path to the top level directory to process. * @param base Root for relative path. * @param flags Combination of git_futils_rmdir_flags values * @return 0 on success; -1 on error. */ extern int git_futils_rmdir_r(const char *path, const char *base, uint32_t flags); /** * Remove all files and directories beneath the specified path. * * @param path Path to the top level directory to process. * @return 0 on success; -1 on error. */ extern int git_futils_cleanupdir_r(const char *path); /** * Create and open a temporary file with a `_git2_` suffix. * Writes the filename into path_out. * @return On success, an open file descriptor, else an error code < 0. */ extern int git_futils_mktmp(git_buf *path_out, const char *filename); /** * Move a file on the filesystem, create the * destination path if it doesn't exist */ extern int git_futils_mv_withpath(const char *from, const char *to, const mode_t dirmode); /** * Copy a file * * The filemode will be used for the newly created file. */ extern int git_futils_cp( const char *from, const char *to, mode_t filemode); /** * Flags that can be passed to `git_futils_cp_r`. * * - GIT_CPDIR_CREATE_EMPTY_DIRS: create directories even if there are no * files under them (otherwise directories will only be created lazily * when a file inside them is copied). * - GIT_CPDIR_COPY_SYMLINKS: copy symlinks, otherwise they are ignored. * - GIT_CPDIR_COPY_DOTFILES: copy files with leading '.', otherwise ignored. * - GIT_CPDIR_OVERWRITE: overwrite pre-existing files with source content, * otherwise they are silently skipped. * - GIT_CPDIR_CHMOD_DIRS: explicitly chmod directories to `dirmode` * - GIT_CPDIR_SIMPLE_TO_MODE: default tries to replicate the mode of the * source file to the target; with this flag, always use 0666 (or 0777 if * source has exec bits set) for target. */ typedef enum { GIT_CPDIR_CREATE_EMPTY_DIRS = (1u << 0), GIT_CPDIR_COPY_SYMLINKS = (1u << 1), GIT_CPDIR_COPY_DOTFILES = (1u << 2), GIT_CPDIR_OVERWRITE = (1u << 3), GIT_CPDIR_CHMOD_DIRS = (1u << 4), GIT_CPDIR_SIMPLE_TO_MODE = (1u << 5), } git_futils_cpdir_flags; /** * Copy a directory tree. * * This copies directories and files from one root to another. You can * pass a combinationof GIT_CPDIR flags as defined above. * * If you pass the CHMOD flag, then the dirmode will be applied to all * directories that are created during the copy, overiding the natural * permissions. If you do not pass the CHMOD flag, then the dirmode * will actually be copied from the source files and the `dirmode` arg * will be ignored. */ extern int git_futils_cp_r( const char *from, const char *to, uint32_t flags, mode_t dirmode); /** * Open a file readonly and set error if needed. */ extern int git_futils_open_ro(const char *path); /** * Get the filesize in bytes of a file */ extern git_off_t git_futils_filesize(git_file fd); #define GIT_MODE_PERMS_MASK 0777 #define GIT_CANONICAL_PERMS(MODE) (((MODE) & 0100) ? 0755 : 0644) #define GIT_MODE_TYPE(MODE) ((MODE) & ~GIT_MODE_PERMS_MASK) #define GIT_MODE_ISBLOB(MODE) (GIT_MODE_TYPE(MODE) == GIT_MODE_TYPE(GIT_FILEMODE_BLOB)) /** * Convert a mode_t from the OS to a legal git mode_t value. */ extern mode_t git_futils_canonical_mode(mode_t raw_mode); /** * Read-only map all or part of a file into memory. * When possible this function should favor a virtual memory * style mapping over some form of malloc()+read(), as the * data access will be random and is not likely to touch the * majority of the region requested. * * @param out buffer to populate with the mapping information. * @param fd open descriptor to configure the mapping from. * @param begin first byte to map, this should be page aligned. * @param end number of bytes to map. * @return * - 0 on success; * - -1 on error. */ extern int git_futils_mmap_ro( git_map *out, git_file fd, git_off_t begin, size_t len); /** * Read-only map an entire file. * * @param out buffer to populate with the mapping information. * @param path path to file to be opened. * @return * - 0 on success; * - GIT_ENOTFOUND if not found; * - -1 on an unspecified OS related error. */ extern int git_futils_mmap_ro_file( git_map *out, const char *path); /** * Release the memory associated with a previous memory mapping. * @param map the mapping description previously configured. */ extern void git_futils_mmap_free(git_map *map); /** * Find a "global" file (i.e. one in a user's home directory). * * @param pathbuf buffer to write the full path into * @param filename name of file to find in the home directory * @return 0 if found, GIT_ENOTFOUND if not found, or -1 on other OS error */ extern int git_futils_find_global_file(git_buf *path, const char *filename); /** * Find an "XDG" file (i.e. one in user's XDG config path). * * @param pathbuf buffer to write the full path into * @param filename name of file to find in the home directory * @return 0 if found, GIT_ENOTFOUND if not found, or -1 on other OS error */ extern int git_futils_find_xdg_file(git_buf *path, const char *filename); /** * Find a "system" file (i.e. one shared for all users of the system). * * @param pathbuf buffer to write the full path into * @param filename name of file to find in the home directory * @return 0 if found, GIT_ENOTFOUND if not found, or -1 on other OS error */ extern int git_futils_find_system_file(git_buf *path, const char *filename); typedef enum { GIT_FUTILS_DIR_SYSTEM = 0, GIT_FUTILS_DIR_GLOBAL = 1, GIT_FUTILS_DIR_XDG = 2, GIT_FUTILS_DIR__MAX = 3, } git_futils_dir_t; /** * Get the search path for global/system/xdg files * * @param out pointer to git_buf containing search path * @param which which list of paths to return * @return 0 on success, <0 on failure */ extern int git_futils_dirs_get(const git_buf **out, git_futils_dir_t which); /** * Get search path into a preallocated buffer * * @param out String buffer to write into * @param outlen Size of string buffer * @param which Which search path to return * @return 0 on success, GIT_EBUFS if out is too small, <0 on other failure */ extern int git_futils_dirs_get_str( char *out, size_t outlen, git_futils_dir_t which); /** * Set search paths for global/system/xdg files * * The first occurrence of the magic string "$PATH" in the new value will * be replaced with the old value of the search path. * * @param which Which search path to modify * @param paths New search path (separated by GIT_PATH_LIST_SEPARATOR) * @return 0 on success, <0 on failure (allocation error) */ extern int git_futils_dirs_set(git_futils_dir_t which, const char *paths); /** * Release / reset all search paths */ extern void git_futils_dirs_free(void); /** * Create a "fake" symlink (text file containing the target path). * * @param new symlink file to be created * @param old original symlink target * @return 0 on success, -1 on error */ extern int git_futils_fake_symlink(const char *new, const char *old); /** * A file stamp represents a snapshot of information about a file that can * be used to test if the file changes. This portable implementation is * based on stat data about that file, but it is possible that OS specific * versions could be implemented in the future. */ typedef struct { git_time_t mtime; git_off_t size; unsigned int ino; } git_futils_filestamp; /** * Compare stat information for file with reference info. * * This function updates the file stamp to current data for the given path * and returns 0 if the file is up-to-date relative to the prior setting or * 1 if the file has been changed. (This also may return GIT_ENOTFOUND if * the file doesn't exist.) * * @param stamp File stamp to be checked * @param path Path to stat and check if changed * @return 0 if up-to-date, 1 if out-of-date, <0 on error */ extern int git_futils_filestamp_check( git_futils_filestamp *stamp, const char *path); /** * Set or reset file stamp data * * This writes the target file stamp. If the source is NULL, this will set * the target stamp to values that will definitely be out of date. If the * source is not NULL, this copies the source values to the target. * * @param tgt File stamp to write to * @param src File stamp to copy from or NULL to clear the target */ extern void git_futils_filestamp_set( git_futils_filestamp *tgt, const git_futils_filestamp *src); #endif /* INCLUDE_fileops_h__ */ libgit2-0.19.0/src/filter.c000066400000000000000000000041151216214232500153540ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #include "common.h" #include "fileops.h" #include "hash.h" #include "filter.h" #include "repository.h" #include "git2/config.h" #include "blob.h" int git_filters_load(git_vector *filters, git_repository *repo, const char *path, int mode) { int error; if (mode == GIT_FILTER_TO_ODB) { /* Load the CRLF cleanup filter when writing to the ODB */ error = git_filter_add__crlf_to_odb(filters, repo, path); if (error < 0) return error; } else { error = git_filter_add__crlf_to_workdir(filters, repo, path); if (error < 0) return error; } return (int)filters->length; } void git_filters_free(git_vector *filters) { size_t i; git_filter *filter; git_vector_foreach(filters, i, filter) { if (filter->do_free != NULL) filter->do_free(filter); else git__free(filter); } git_vector_free(filters); } int git_filters_apply(git_buf *dest, git_buf *source, git_vector *filters) { size_t i; unsigned int src; git_buf *dbuffer[2]; dbuffer[0] = source; dbuffer[1] = dest; src = 0; if (git_buf_len(source) == 0) { git_buf_clear(dest); return 0; } /* Pre-grow the destination buffer to more or less the size * we expect it to have */ if (git_buf_grow(dest, git_buf_len(source)) < 0) return -1; for (i = 0; i < filters->length; ++i) { git_filter *filter = git_vector_get(filters, i); unsigned int dst = 1 - src; git_buf_clear(dbuffer[dst]); /* Apply the filter from dbuffer[src] to the other buffer; * if the filtering is canceled by the user mid-filter, * we skip to the next filter without changing the source * of the double buffering (so that the text goes through * cleanly). */ if (filter->apply(filter, dbuffer[dst], dbuffer[src]) == 0) src = dst; if (git_buf_oom(dbuffer[dst])) return -1; } /* Ensure that the output ends up in dbuffer[1] (i.e. the dest) */ if (src != 1) git_buf_swap(dest, source); return 0; } libgit2-0.19.0/src/filter.h000066400000000000000000000057041216214232500153660ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #ifndef INCLUDE_filter_h__ #define INCLUDE_filter_h__ #include "common.h" #include "buffer.h" #include "git2/odb.h" #include "git2/repository.h" typedef struct git_filter { int (*apply)(struct git_filter *self, git_buf *dest, const git_buf *source); void (*do_free)(struct git_filter *self); } git_filter; typedef enum { GIT_FILTER_TO_WORKTREE, GIT_FILTER_TO_ODB } git_filter_mode; typedef enum { GIT_CRLF_GUESS = -1, GIT_CRLF_BINARY = 0, GIT_CRLF_TEXT, GIT_CRLF_INPUT, GIT_CRLF_CRLF, GIT_CRLF_AUTO, } git_crlf_t; /* * FILTER API */ /* * For any given path in the working directory, fill the `filters` * array with the relevant filters that need to be applied. * * Mode is either `GIT_FILTER_TO_WORKTREE` if you need to load the * filters that will be used when checking out a file to the working * directory, or `GIT_FILTER_TO_ODB` for the filters used when writing * a file to the ODB. * * @param filters Vector where to store all the loaded filters * @param repo Repository object that contains `path` * @param path Relative path of the file to be filtered * @param mode Filtering direction (WT->ODB or ODB->WT) * @return the number of filters loaded for the file (0 if the file * doesn't need filtering), or a negative error code */ extern int git_filters_load(git_vector *filters, git_repository *repo, const char *path, int mode); /* * Apply one or more filters to a file. * * The file must have been loaded as a `git_buf` object. Both the `source` * and `dest` buffers are owned by the caller and must be freed once * they are no longer needed. * * NOTE: Because of the double-buffering schema, the `source` buffer that contains * the original file may be tampered once the filtering is complete. Regardless, * the `dest` buffer will always contain the final result of the filtering * * @param dest Buffer to store the result of the filtering * @param source Buffer containing the document to filter * @param filters A non-empty vector of filters as supplied by `git_filters_load` * @return 0 on success, an error code otherwise */ extern int git_filters_apply(git_buf *dest, git_buf *source, git_vector *filters); /* * Free the `filters` array generated by `git_filters_load`. * * Note that this frees both the array and its contents. The array will * be clean/reusable after this call. * * @param filters A filters array as supplied by `git_filters_load` */ extern void git_filters_free(git_vector *filters); /* * Available filters */ /* Strip CRLF, from Worktree to ODB */ extern int git_filter_add__crlf_to_odb(git_vector *filters, git_repository *repo, const char *path); /* Add CRLF, from ODB to worktree */ extern int git_filter_add__crlf_to_workdir(git_vector *filters, git_repository *repo, const char *path); #endif libgit2-0.19.0/src/fnmatch.c000066400000000000000000000117621216214232500155150ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ /* * Function fnmatch() as specified in POSIX 1003.2-1992, section B.6. * Compares a filename or pathname to a pattern. */ #include #include #include #include "fnmatch.h" #define EOS '\0' #define RANGE_MATCH 1 #define RANGE_NOMATCH 0 #define RANGE_ERROR (-1) static int rangematch(const char *, char, int, char **); static int p_fnmatchx(const char *pattern, const char *string, int flags, size_t recurs) { const char *stringstart; char *newp; char c, test; if (recurs-- == 0) return FNM_NORES; for (stringstart = string;;) switch (c = *pattern++) { case EOS: if ((flags & FNM_LEADING_DIR) && *string == '/') return (0); return (*string == EOS ? 0 : FNM_NOMATCH); case '?': if (*string == EOS) return (FNM_NOMATCH); if (*string == '/' && (flags & FNM_PATHNAME)) return (FNM_NOMATCH); if (*string == '.' && (flags & FNM_PERIOD) && (string == stringstart || ((flags & FNM_PATHNAME) && *(string - 1) == '/'))) return (FNM_NOMATCH); ++string; break; case '*': c = *pattern; /* Collapse multiple stars. */ while (c == '*') c = *++pattern; if (*string == '.' && (flags & FNM_PERIOD) && (string == stringstart || ((flags & FNM_PATHNAME) && *(string - 1) == '/'))) return (FNM_NOMATCH); /* Optimize for pattern with * at end or before /. */ if (c == EOS) { if (flags & FNM_PATHNAME) return ((flags & FNM_LEADING_DIR) || strchr(string, '/') == NULL ? 0 : FNM_NOMATCH); else return (0); } else if (c == '/' && (flags & FNM_PATHNAME)) { if ((string = strchr(string, '/')) == NULL) return (FNM_NOMATCH); break; } /* General case, use recursion. */ while ((test = *string) != EOS) { int e; e = p_fnmatchx(pattern, string, flags & ~FNM_PERIOD, recurs); if (e != FNM_NOMATCH) return e; if (test == '/' && (flags & FNM_PATHNAME)) break; ++string; } return (FNM_NOMATCH); case '[': if (*string == EOS) return (FNM_NOMATCH); if (*string == '/' && (flags & FNM_PATHNAME)) return (FNM_NOMATCH); if (*string == '.' && (flags & FNM_PERIOD) && (string == stringstart || ((flags & FNM_PATHNAME) && *(string - 1) == '/'))) return (FNM_NOMATCH); switch (rangematch(pattern, *string, flags, &newp)) { case RANGE_ERROR: /* not a good range, treat as normal text */ goto normal; case RANGE_MATCH: pattern = newp; break; case RANGE_NOMATCH: return (FNM_NOMATCH); } ++string; break; case '\\': if (!(flags & FNM_NOESCAPE)) { if ((c = *pattern++) == EOS) { c = '\\'; --pattern; } } /* FALLTHROUGH */ default: normal: if (c != *string && !((flags & FNM_CASEFOLD) && (tolower((unsigned char)c) == tolower((unsigned char)*string)))) return (FNM_NOMATCH); ++string; break; } /* NOTREACHED */ } static int rangematch(const char *pattern, char test, int flags, char **newp) { int negate, ok; char c, c2; /* * A bracket expression starting with an unquoted circumflex * character produces unspecified results (IEEE 1003.2-1992, * 3.13.2). This implementation treats it like '!', for * consistency with the regular expression syntax. * J.T. Conklin (conklin@ngai.kaleida.com) */ if ((negate = (*pattern == '!' || *pattern == '^')) != 0) ++pattern; if (flags & FNM_CASEFOLD) test = (char)tolower((unsigned char)test); /* * A right bracket shall lose its special meaning and represent * itself in a bracket expression if it occurs first in the list. * -- POSIX.2 2.8.3.2 */ ok = 0; c = *pattern++; do { if (c == '\\' && !(flags & FNM_NOESCAPE)) c = *pattern++; if (c == EOS) return (RANGE_ERROR); if (c == '/' && (flags & FNM_PATHNAME)) return (RANGE_NOMATCH); if ((flags & FNM_CASEFOLD)) c = (char)tolower((unsigned char)c); if (*pattern == '-' && (c2 = *(pattern+1)) != EOS && c2 != ']') { pattern += 2; if (c2 == '\\' && !(flags & FNM_NOESCAPE)) c2 = *pattern++; if (c2 == EOS) return (RANGE_ERROR); if (flags & FNM_CASEFOLD) c2 = (char)tolower((unsigned char)c2); if (c <= test && test <= c2) ok = 1; } else if (c == test) ok = 1; } while ((c = *pattern++) != ']'); *newp = (char *)pattern; return (ok == negate ? RANGE_NOMATCH : RANGE_MATCH); } int p_fnmatch(const char *pattern, const char *string, int flags) { return p_fnmatchx(pattern, string, flags, 64); } libgit2-0.19.0/src/fnmatch.h000066400000000000000000000016641216214232500155220ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #ifndef INCLUDE_fnmatch__compat_h__ #define INCLUDE_fnmatch__compat_h__ #include "common.h" #define FNM_NOMATCH 1 /* Match failed. */ #define FNM_NOSYS 2 /* Function not supported (unused). */ #define FNM_NORES 3 /* Out of resources */ #define FNM_NOESCAPE 0x01 /* Disable backslash escaping. */ #define FNM_PATHNAME 0x02 /* Slash must be matched by slash. */ #define FNM_PERIOD 0x04 /* Period must be matched by period. */ #define FNM_LEADING_DIR 0x08 /* Ignore / after Imatch. */ #define FNM_CASEFOLD 0x10 /* Case insensitive search. */ #define FNM_IGNORECASE FNM_CASEFOLD #define FNM_FILE_NAME FNM_PATHNAME extern int p_fnmatch(const char *pattern, const char *string, int flags); #endif /* _FNMATCH_H */ libgit2-0.19.0/src/global.c000066400000000000000000000100221216214232500153210ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #include "common.h" #include "global.h" #include "hash.h" #include "fileops.h" #include "git2/threads.h" #include "thread-utils.h" git_mutex git__mwindow_mutex; /** * Handle the global state with TLS * * If libgit2 is built with GIT_THREADS enabled, * the `git_threads_init()` function must be called * before calling any other function of the library. * * This function allocates a TLS index (using pthreads * or the native Win32 API) to store the global state * on a per-thread basis. * * Any internal method that requires global state will * then call `git__global_state()` which returns a pointer * to the global state structure; this pointer is lazily * allocated on each thread. * * Before shutting down the library, the * `git_threads_shutdown` method must be called to free * the previously reserved TLS index. * * If libgit2 is built without threading support, the * `git__global_statestate()` call returns a pointer to a single, * statically allocated global state. The `git_thread_` * functions are not available in that case. */ /* * `git_threads_init()` allows subsystems to perform global setup, * which may take place in the global scope. An explicit memory * fence exists at the exit of `git_threads_init()`. Without this, * CPU cores are free to reorder cache invalidation of `_tls_init` * before cache invalidation of the subsystems' newly written global * state. */ #if defined(GIT_THREADS) && defined(GIT_WIN32) static DWORD _tls_index; static int _tls_init = 0; int git_threads_init(void) { int error; if (_tls_init) return 0; _tls_index = TlsAlloc(); if (git_mutex_init(&git__mwindow_mutex)) return -1; /* Initialize any other subsystems that have global state */ if ((error = git_hash_global_init()) >= 0) _tls_init = 1; if (error == 0) _tls_init = 1; GIT_MEMORY_BARRIER; return error; } void git_threads_shutdown(void) { TlsFree(_tls_index); _tls_init = 0; git_mutex_free(&git__mwindow_mutex); /* Shut down any subsystems that have global state */ git_hash_global_shutdown(); git_futils_dirs_free(); } git_global_st *git__global_state(void) { void *ptr; assert(_tls_init); if ((ptr = TlsGetValue(_tls_index)) != NULL) return ptr; ptr = git__malloc(sizeof(git_global_st)); if (!ptr) return NULL; memset(ptr, 0x0, sizeof(git_global_st)); TlsSetValue(_tls_index, ptr); return ptr; } #elif defined(GIT_THREADS) && defined(_POSIX_THREADS) static pthread_key_t _tls_key; static int _tls_init = 0; static void cb__free_status(void *st) { git__free(st); } int git_threads_init(void) { int error = 0; if (_tls_init) return 0; if (git_mutex_init(&git__mwindow_mutex)) return -1; pthread_key_create(&_tls_key, &cb__free_status); /* Initialize any other subsystems that have global state */ if ((error = git_hash_global_init()) >= 0) _tls_init = 1; GIT_MEMORY_BARRIER; return error; } void git_threads_shutdown(void) { if (_tls_init) { void *ptr = pthread_getspecific(_tls_key); pthread_setspecific(_tls_key, NULL); git__free(ptr); } pthread_key_delete(_tls_key); _tls_init = 0; git_mutex_free(&git__mwindow_mutex); /* Shut down any subsystems that have global state */ git_hash_global_shutdown(); git_futils_dirs_free(); } git_global_st *git__global_state(void) { void *ptr; assert(_tls_init); if ((ptr = pthread_getspecific(_tls_key)) != NULL) return ptr; ptr = git__malloc(sizeof(git_global_st)); if (!ptr) return NULL; memset(ptr, 0x0, sizeof(git_global_st)); pthread_setspecific(_tls_key, ptr); return ptr; } #else static git_global_st __state; int git_threads_init(void) { /* noop */ return 0; } void git_threads_shutdown(void) { /* Shut down any subsystems that have global state */ git_hash_global_shutdown(); git_futils_dirs_free(); } git_global_st *git__global_state(void) { return &__state; } #endif /* GIT_THREADS */ libgit2-0.19.0/src/global.h000066400000000000000000000010051216214232500153270ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #ifndef INCLUDE_global_h__ #define INCLUDE_global_h__ #include "mwindow.h" #include "hash.h" typedef struct { git_error *last_error; git_error error_t; } git_global_st; git_global_st *git__global_state(void); extern git_mutex git__mwindow_mutex; #define GIT_GLOBAL (git__global_state()) #endif libgit2-0.19.0/src/graph.c000066400000000000000000000075741216214232500152040ustar00rootroot00000000000000 /* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #include "revwalk.h" #include "merge.h" #include "git2/graph.h" static int interesting(git_pqueue *list, git_commit_list *roots) { unsigned int i; /* element 0 isn't used - we need to start at 1 */ for (i = 1; i < list->size; i++) { git_commit_list_node *commit = list->d[i]; if ((commit->flags & STALE) == 0) return 1; } while(roots) { if ((roots->item->flags & STALE) == 0) return 1; roots = roots->next; } return 0; } static int mark_parents(git_revwalk *walk, git_commit_list_node *one, git_commit_list_node *two) { unsigned int i; git_commit_list *roots = NULL; git_pqueue list; /* if the commit is repeated, we have a our merge base already */ if (one == two) { one->flags |= PARENT1 | PARENT2 | RESULT; return 0; } if (git_pqueue_init(&list, 2, git_commit_list_time_cmp) < 0) return -1; if (git_commit_list_parse(walk, one) < 0) goto on_error; one->flags |= PARENT1; if (git_pqueue_insert(&list, one) < 0) goto on_error; if (git_commit_list_parse(walk, two) < 0) goto on_error; two->flags |= PARENT2; if (git_pqueue_insert(&list, two) < 0) goto on_error; /* as long as there are non-STALE commits */ while (interesting(&list, roots)) { git_commit_list_node *commit; int flags; commit = git_pqueue_pop(&list); if (commit == NULL) break; flags = commit->flags & (PARENT1 | PARENT2 | STALE); if (flags == (PARENT1 | PARENT2)) { if (!(commit->flags & RESULT)) commit->flags |= RESULT; /* we mark the parents of a merge stale */ flags |= STALE; } for (i = 0; i < commit->out_degree; i++) { git_commit_list_node *p = commit->parents[i]; if ((p->flags & flags) == flags) continue; if (git_commit_list_parse(walk, p) < 0) goto on_error; p->flags |= flags; if (git_pqueue_insert(&list, p) < 0) goto on_error; } /* Keep track of root commits, to make sure the path gets marked */ if (commit->out_degree == 0) { if (git_commit_list_insert(commit, &roots) == NULL) goto on_error; } } git_commit_list_free(&roots); git_pqueue_free(&list); return 0; on_error: git_commit_list_free(&roots); git_pqueue_free(&list); return -1; } static int ahead_behind(git_commit_list_node *one, git_commit_list_node *two, size_t *ahead, size_t *behind) { git_commit_list_node *commit; git_pqueue pq; int i; *ahead = 0; *behind = 0; if (git_pqueue_init(&pq, 2, git_commit_list_time_cmp) < 0) return -1; if (git_pqueue_insert(&pq, one) < 0) goto on_error; if (git_pqueue_insert(&pq, two) < 0) goto on_error; while ((commit = git_pqueue_pop(&pq)) != NULL) { if (commit->flags & RESULT || (commit->flags & (PARENT1 | PARENT2)) == (PARENT1 | PARENT2)) continue; else if (commit->flags & PARENT1) (*behind)++; else if (commit->flags & PARENT2) (*ahead)++; for (i = 0; i < commit->out_degree; i++) { git_commit_list_node *p = commit->parents[i]; if (git_pqueue_insert(&pq, p) < 0) return -1; } commit->flags |= RESULT; } git_pqueue_free(&pq); return 0; on_error: git_pqueue_free(&pq); return -1; } int git_graph_ahead_behind(size_t *ahead, size_t *behind, git_repository *repo, const git_oid *local, const git_oid *upstream) { git_revwalk *walk; git_commit_list_node *commit_u, *commit_l; if (git_revwalk_new(&walk, repo) < 0) return -1; commit_u = git_revwalk__commit_lookup(walk, upstream); if (commit_u == NULL) goto on_error; commit_l = git_revwalk__commit_lookup(walk, local); if (commit_l == NULL) goto on_error; if (mark_parents(walk, commit_l, commit_u) < 0) goto on_error; if (ahead_behind(commit_l, commit_u, ahead, behind) < 0) goto on_error; git_revwalk_free(walk); return 0; on_error: git_revwalk_free(walk); return -1; } libgit2-0.19.0/src/hash.c000066400000000000000000000016061216214232500150140ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #include "common.h" #include "hash.h" int git_hash_buf(git_oid *out, const void *data, size_t len) { git_hash_ctx ctx; int error = 0; if (git_hash_ctx_init(&ctx) < 0) return -1; if ((error = git_hash_update(&ctx, data, len)) >= 0) error = git_hash_final(out, &ctx); git_hash_ctx_cleanup(&ctx); return error; } int git_hash_vec(git_oid *out, git_buf_vec *vec, size_t n) { git_hash_ctx ctx; size_t i; int error = 0; if (git_hash_ctx_init(&ctx) < 0) return -1; for (i = 0; i < n; i++) { if ((error = git_hash_update(&ctx, vec[i].data, vec[i].len)) < 0) goto done; } error = git_hash_final(out, &ctx); done: git_hash_ctx_cleanup(&ctx); return error; } libgit2-0.19.0/src/hash.h000066400000000000000000000020471216214232500150210ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #ifndef INCLUDE_hash_h__ #define INCLUDE_hash_h__ #include "git2/oid.h" typedef struct git_hash_prov git_hash_prov; typedef struct git_hash_ctx git_hash_ctx; int git_hash_global_init(void); void git_hash_global_shutdown(void); int git_hash_ctx_init(git_hash_ctx *ctx); void git_hash_ctx_cleanup(git_hash_ctx *ctx); #if defined(OPENSSL_SHA1) # include "hash/hash_openssl.h" #elif defined(WIN32_SHA1) # include "hash/hash_win32.h" #else # include "hash/hash_generic.h" #endif typedef struct { void *data; size_t len; } git_buf_vec; int git_hash_init(git_hash_ctx *c); int git_hash_update(git_hash_ctx *c, const void *data, size_t len); int git_hash_final(git_oid *out, git_hash_ctx *c); int git_hash_buf(git_oid *out, const void *data, size_t len); int git_hash_vec(git_oid *out, git_buf_vec *vec, size_t n); #endif /* INCLUDE_hash_h__ */ libgit2-0.19.0/src/hash/000077500000000000000000000000001216214232500146455ustar00rootroot00000000000000libgit2-0.19.0/src/hash/hash_generic.c000066400000000000000000000205061216214232500174330ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #include "common.h" #include "hash.h" #include "hash/hash_generic.h" #if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) /* * Force usage of rol or ror by selecting the one with the smaller constant. * It _can_ generate slightly smaller code (a constant of 1 is special), but * perhaps more importantly it's possibly faster on any uarch that does a * rotate with a loop. */ #define SHA_ASM(op, x, n) ({ unsigned int __res; __asm__(op " %1,%0":"=r" (__res):"i" (n), "0" (x)); __res; }) #define SHA_ROL(x,n) SHA_ASM("rol", x, n) #define SHA_ROR(x,n) SHA_ASM("ror", x, n) #else #define SHA_ROT(X,l,r) (((X) << (l)) | ((X) >> (r))) #define SHA_ROL(X,n) SHA_ROT(X,n,32-(n)) #define SHA_ROR(X,n) SHA_ROT(X,32-(n),n) #endif /* * If you have 32 registers or more, the compiler can (and should) * try to change the array[] accesses into registers. However, on * machines with less than ~25 registers, that won't really work, * and at least gcc will make an unholy mess of it. * * So to avoid that mess which just slows things down, we force * the stores to memory to actually happen (we might be better off * with a 'W(t)=(val);asm("":"+m" (W(t))' there instead, as * suggested by Artur Skawina - that will also make gcc unable to * try to do the silly "optimize away loads" part because it won't * see what the value will be). * * Ben Herrenschmidt reports that on PPC, the C version comes close * to the optimized asm with this (ie on PPC you don't want that * 'volatile', since there are lots of registers). * * On ARM we get the best code generation by forcing a full memory barrier * between each SHA_ROUND, otherwise gcc happily get wild with spilling and * the stack frame size simply explode and performance goes down the drain. */ #if defined(__i386__) || defined(__x86_64__) #define setW(x, val) (*(volatile unsigned int *)&W(x) = (val)) #elif defined(__GNUC__) && defined(__arm__) #define setW(x, val) do { W(x) = (val); __asm__("":::"memory"); } while (0) #else #define setW(x, val) (W(x) = (val)) #endif /* * Performance might be improved if the CPU architecture is OK with * unaligned 32-bit loads and a fast ntohl() is available. * Otherwise fall back to byte loads and shifts which is portable, * and is faster on architectures with memory alignment issues. */ #if defined(__i386__) || defined(__x86_64__) || \ defined(_M_IX86) || defined(_M_X64) || \ defined(__ppc__) || defined(__ppc64__) || \ defined(__powerpc__) || defined(__powerpc64__) || \ defined(__s390__) || defined(__s390x__) #define get_be32(p) ntohl(*(const unsigned int *)(p)) #define put_be32(p, v) do { *(unsigned int *)(p) = htonl(v); } while (0) #else #define get_be32(p) ( \ (*((const unsigned char *)(p) + 0) << 24) | \ (*((const unsigned char *)(p) + 1) << 16) | \ (*((const unsigned char *)(p) + 2) << 8) | \ (*((const unsigned char *)(p) + 3) << 0) ) #define put_be32(p, v) do { \ unsigned int __v = (v); \ *((unsigned char *)(p) + 0) = __v >> 24; \ *((unsigned char *)(p) + 1) = __v >> 16; \ *((unsigned char *)(p) + 2) = __v >> 8; \ *((unsigned char *)(p) + 3) = __v >> 0; } while (0) #endif /* This "rolls" over the 512-bit array */ #define W(x) (array[(x)&15]) /* * Where do we get the source from? The first 16 iterations get it from * the input data, the next mix it from the 512-bit array. */ #define SHA_SRC(t) get_be32(data + t) #define SHA_MIX(t) SHA_ROL(W(t+13) ^ W(t+8) ^ W(t+2) ^ W(t), 1) #define SHA_ROUND(t, input, fn, constant, A, B, C, D, E) do { \ unsigned int TEMP = input(t); setW(t, TEMP); \ E += TEMP + SHA_ROL(A,5) + (fn) + (constant); \ B = SHA_ROR(B, 2); } while (0) #define T_0_15(t, A, B, C, D, E) SHA_ROUND(t, SHA_SRC, (((C^D)&B)^D) , 0x5a827999, A, B, C, D, E ) #define T_16_19(t, A, B, C, D, E) SHA_ROUND(t, SHA_MIX, (((C^D)&B)^D) , 0x5a827999, A, B, C, D, E ) #define T_20_39(t, A, B, C, D, E) SHA_ROUND(t, SHA_MIX, (B^C^D) , 0x6ed9eba1, A, B, C, D, E ) #define T_40_59(t, A, B, C, D, E) SHA_ROUND(t, SHA_MIX, ((B&C)+(D&(B^C))) , 0x8f1bbcdc, A, B, C, D, E ) #define T_60_79(t, A, B, C, D, E) SHA_ROUND(t, SHA_MIX, (B^C^D) , 0xca62c1d6, A, B, C, D, E ) static void hash__block(git_hash_ctx *ctx, const unsigned int *data) { unsigned int A,B,C,D,E; unsigned int array[16]; A = ctx->H[0]; B = ctx->H[1]; C = ctx->H[2]; D = ctx->H[3]; E = ctx->H[4]; /* Round 1 - iterations 0-16 take their input from 'data' */ T_0_15( 0, A, B, C, D, E); T_0_15( 1, E, A, B, C, D); T_0_15( 2, D, E, A, B, C); T_0_15( 3, C, D, E, A, B); T_0_15( 4, B, C, D, E, A); T_0_15( 5, A, B, C, D, E); T_0_15( 6, E, A, B, C, D); T_0_15( 7, D, E, A, B, C); T_0_15( 8, C, D, E, A, B); T_0_15( 9, B, C, D, E, A); T_0_15(10, A, B, C, D, E); T_0_15(11, E, A, B, C, D); T_0_15(12, D, E, A, B, C); T_0_15(13, C, D, E, A, B); T_0_15(14, B, C, D, E, A); T_0_15(15, A, B, C, D, E); /* Round 1 - tail. Input from 512-bit mixing array */ T_16_19(16, E, A, B, C, D); T_16_19(17, D, E, A, B, C); T_16_19(18, C, D, E, A, B); T_16_19(19, B, C, D, E, A); /* Round 2 */ T_20_39(20, A, B, C, D, E); T_20_39(21, E, A, B, C, D); T_20_39(22, D, E, A, B, C); T_20_39(23, C, D, E, A, B); T_20_39(24, B, C, D, E, A); T_20_39(25, A, B, C, D, E); T_20_39(26, E, A, B, C, D); T_20_39(27, D, E, A, B, C); T_20_39(28, C, D, E, A, B); T_20_39(29, B, C, D, E, A); T_20_39(30, A, B, C, D, E); T_20_39(31, E, A, B, C, D); T_20_39(32, D, E, A, B, C); T_20_39(33, C, D, E, A, B); T_20_39(34, B, C, D, E, A); T_20_39(35, A, B, C, D, E); T_20_39(36, E, A, B, C, D); T_20_39(37, D, E, A, B, C); T_20_39(38, C, D, E, A, B); T_20_39(39, B, C, D, E, A); /* Round 3 */ T_40_59(40, A, B, C, D, E); T_40_59(41, E, A, B, C, D); T_40_59(42, D, E, A, B, C); T_40_59(43, C, D, E, A, B); T_40_59(44, B, C, D, E, A); T_40_59(45, A, B, C, D, E); T_40_59(46, E, A, B, C, D); T_40_59(47, D, E, A, B, C); T_40_59(48, C, D, E, A, B); T_40_59(49, B, C, D, E, A); T_40_59(50, A, B, C, D, E); T_40_59(51, E, A, B, C, D); T_40_59(52, D, E, A, B, C); T_40_59(53, C, D, E, A, B); T_40_59(54, B, C, D, E, A); T_40_59(55, A, B, C, D, E); T_40_59(56, E, A, B, C, D); T_40_59(57, D, E, A, B, C); T_40_59(58, C, D, E, A, B); T_40_59(59, B, C, D, E, A); /* Round 4 */ T_60_79(60, A, B, C, D, E); T_60_79(61, E, A, B, C, D); T_60_79(62, D, E, A, B, C); T_60_79(63, C, D, E, A, B); T_60_79(64, B, C, D, E, A); T_60_79(65, A, B, C, D, E); T_60_79(66, E, A, B, C, D); T_60_79(67, D, E, A, B, C); T_60_79(68, C, D, E, A, B); T_60_79(69, B, C, D, E, A); T_60_79(70, A, B, C, D, E); T_60_79(71, E, A, B, C, D); T_60_79(72, D, E, A, B, C); T_60_79(73, C, D, E, A, B); T_60_79(74, B, C, D, E, A); T_60_79(75, A, B, C, D, E); T_60_79(76, E, A, B, C, D); T_60_79(77, D, E, A, B, C); T_60_79(78, C, D, E, A, B); T_60_79(79, B, C, D, E, A); ctx->H[0] += A; ctx->H[1] += B; ctx->H[2] += C; ctx->H[3] += D; ctx->H[4] += E; } int git_hash_init(git_hash_ctx *ctx) { ctx->size = 0; /* Initialize H with the magic constants (see FIPS180 for constants) */ ctx->H[0] = 0x67452301; ctx->H[1] = 0xefcdab89; ctx->H[2] = 0x98badcfe; ctx->H[3] = 0x10325476; ctx->H[4] = 0xc3d2e1f0; return 0; } int git_hash_update(git_hash_ctx *ctx, const void *data, size_t len) { unsigned int lenW = ctx->size & 63; ctx->size += len; /* Read the data into W and process blocks as they get full */ if (lenW) { unsigned int left = 64 - lenW; if (len < left) left = (unsigned int)len; memcpy(lenW + (char *)ctx->W, data, left); lenW = (lenW + left) & 63; len -= left; data = ((const char *)data + left); if (lenW) return 0; hash__block(ctx, ctx->W); } while (len >= 64) { hash__block(ctx, data); data = ((const char *)data + 64); len -= 64; } if (len) memcpy(ctx->W, data, len); return 0; } int git_hash_final(git_oid *out, git_hash_ctx *ctx) { static const unsigned char pad[64] = { 0x80 }; unsigned int padlen[2]; int i; /* Pad with a binary 1 (ie 0x80), then zeroes, then length */ padlen[0] = htonl((uint32_t)(ctx->size >> 29)); padlen[1] = htonl((uint32_t)(ctx->size << 3)); i = ctx->size & 63; git_hash_update(ctx, pad, 1+ (63 & (55 - i))); git_hash_update(ctx, padlen, 8); /* Output hash */ for (i = 0; i < 5; i++) put_be32(out->id + i*4, ctx->H[i]); return 0; } libgit2-0.19.0/src/hash/hash_generic.h000066400000000000000000000011251216214232500174340ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #ifndef INCLUDE_hash_generic_h__ #define INCLUDE_hash_generic_h__ #include "hash.h" struct git_hash_ctx { unsigned long long size; unsigned int H[5]; unsigned int W[16]; }; #define git_hash_global_init() 0 #define git_hash_global_shutdown() /* noop */ #define git_hash_ctx_init(ctx) git_hash_init(ctx) #define git_hash_ctx_cleanup(ctx) #endif /* INCLUDE_hash_generic_h__ */ libgit2-0.19.0/src/hash/hash_openssl.h000066400000000000000000000016521216214232500175100ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #ifndef INCLUDE_hash_openssl_h__ #define INCLUDE_hash_openssl_h__ #include "hash.h" #include struct git_hash_ctx { SHA_CTX c; }; #define git_hash_global_init() 0 #define git_hash_global_shutdown() /* noop */ #define git_hash_ctx_init(ctx) git_hash_init(ctx) #define git_hash_ctx_cleanup(ctx) GIT_INLINE(int) git_hash_init(git_hash_ctx *ctx) { assert(ctx); SHA1_Init(&ctx->c); return 0; } GIT_INLINE(int) git_hash_update(git_hash_ctx *ctx, const void *data, size_t len) { assert(ctx); SHA1_Update(&ctx->c, data, len); return 0; } GIT_INLINE(int) git_hash_final(git_oid *out, git_hash_ctx *ctx) { assert(ctx); SHA1_Final(out->id, &ctx->c); return 0; } #endif /* INCLUDE_hash_openssl_h__ */ libgit2-0.19.0/src/hash/hash_win32.c000066400000000000000000000203121216214232500167540ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #include "common.h" #include "global.h" #include "hash.h" #include "hash/hash_win32.h" #include #include static struct git_hash_prov hash_prov = {0}; /* Hash initialization */ /* Initialize CNG, if available */ GIT_INLINE(int) hash_cng_prov_init(void) { OSVERSIONINFOEX version_test = {0}; DWORD version_test_mask; DWORDLONG version_condition_mask = 0; char dll_path[MAX_PATH]; DWORD dll_path_len, size_len; return -1; /* Only use CNG on Windows 2008 / Vista SP1 or better (Windows 6.0 SP1) */ version_test.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); version_test.dwMajorVersion = 6; version_test.dwMinorVersion = 0; version_test.wServicePackMajor = 1; version_test.wServicePackMinor = 0; version_test_mask = (VER_MAJORVERSION | VER_MINORVERSION | VER_SERVICEPACKMAJOR | VER_SERVICEPACKMINOR); VER_SET_CONDITION(version_condition_mask, VER_MAJORVERSION, VER_GREATER_EQUAL); VER_SET_CONDITION(version_condition_mask, VER_MINORVERSION, VER_GREATER_EQUAL); VER_SET_CONDITION(version_condition_mask, VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL); VER_SET_CONDITION(version_condition_mask, VER_SERVICEPACKMINOR, VER_GREATER_EQUAL); if (!VerifyVersionInfo(&version_test, version_test_mask, version_condition_mask)) return -1; /* Load bcrypt.dll explicitly from the system directory */ if ((dll_path_len = GetSystemDirectory(dll_path, MAX_PATH)) == 0 || dll_path_len > MAX_PATH || StringCchCat(dll_path, MAX_PATH, "\\") < 0 || StringCchCat(dll_path, MAX_PATH, GIT_HASH_CNG_DLL_NAME) < 0 || (hash_prov.prov.cng.dll = LoadLibrary(dll_path)) == NULL) return -1; /* Load the function addresses */ if ((hash_prov.prov.cng.open_algorithm_provider = (hash_win32_cng_open_algorithm_provider_fn)GetProcAddress(hash_prov.prov.cng.dll, "BCryptOpenAlgorithmProvider")) == NULL || (hash_prov.prov.cng.get_property = (hash_win32_cng_get_property_fn)GetProcAddress(hash_prov.prov.cng.dll, "BCryptGetProperty")) == NULL || (hash_prov.prov.cng.create_hash = (hash_win32_cng_create_hash_fn)GetProcAddress(hash_prov.prov.cng.dll, "BCryptCreateHash")) == NULL || (hash_prov.prov.cng.finish_hash = (hash_win32_cng_finish_hash_fn)GetProcAddress(hash_prov.prov.cng.dll, "BCryptFinishHash")) == NULL || (hash_prov.prov.cng.hash_data = (hash_win32_cng_hash_data_fn)GetProcAddress(hash_prov.prov.cng.dll, "BCryptHashData")) == NULL || (hash_prov.prov.cng.destroy_hash = (hash_win32_cng_destroy_hash_fn)GetProcAddress(hash_prov.prov.cng.dll, "BCryptDestroyHash")) == NULL || (hash_prov.prov.cng.close_algorithm_provider = (hash_win32_cng_close_algorithm_provider_fn)GetProcAddress(hash_prov.prov.cng.dll, "BCryptCloseAlgorithmProvider")) == NULL) { FreeLibrary(hash_prov.prov.cng.dll); return -1; } /* Load the SHA1 algorithm */ if (hash_prov.prov.cng.open_algorithm_provider(&hash_prov.prov.cng.handle, GIT_HASH_CNG_HASH_TYPE, NULL, GIT_HASH_CNG_HASH_REUSABLE) < 0) { FreeLibrary(hash_prov.prov.cng.dll); return -1; } /* Get storage space for the hash object */ if (hash_prov.prov.cng.get_property(hash_prov.prov.cng.handle, GIT_HASH_CNG_HASH_OBJECT_LEN, (PBYTE)&hash_prov.prov.cng.hash_object_size, sizeof(DWORD), &size_len, 0) < 0) { hash_prov.prov.cng.close_algorithm_provider(hash_prov.prov.cng.handle, 0); FreeLibrary(hash_prov.prov.cng.dll); return -1; } hash_prov.type = CNG; return 0; } GIT_INLINE(void) hash_cng_prov_shutdown(void) { hash_prov.prov.cng.close_algorithm_provider(hash_prov.prov.cng.handle, 0); FreeLibrary(hash_prov.prov.cng.dll); hash_prov.type = INVALID; } /* Initialize CryptoAPI */ GIT_INLINE(int) hash_cryptoapi_prov_init() { if (!CryptAcquireContext(&hash_prov.prov.cryptoapi.handle, NULL, 0, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) return -1; hash_prov.type = CRYPTOAPI; return 0; } GIT_INLINE(void) hash_cryptoapi_prov_shutdown(void) { CryptReleaseContext(hash_prov.prov.cryptoapi.handle, 0); hash_prov.type = INVALID; } int git_hash_global_init() { int error = 0; if (hash_prov.type != INVALID) return 0; if ((error = hash_cng_prov_init()) < 0) error = hash_cryptoapi_prov_init(); return error; } void git_hash_global_shutdown() { if (hash_prov.type == CNG) hash_cng_prov_shutdown(); else if(hash_prov.type == CRYPTOAPI) hash_cryptoapi_prov_shutdown(); } /* CryptoAPI: available in Windows XP and newer */ GIT_INLINE(int) hash_ctx_cryptoapi_init(git_hash_ctx *ctx) { ctx->type = CRYPTOAPI; ctx->prov = &hash_prov; return git_hash_init(ctx); } GIT_INLINE(int) hash_cryptoapi_init(git_hash_ctx *ctx) { if (ctx->ctx.cryptoapi.valid) CryptDestroyHash(ctx->ctx.cryptoapi.hash_handle); if (!CryptCreateHash(ctx->prov->prov.cryptoapi.handle, CALG_SHA1, 0, 0, &ctx->ctx.cryptoapi.hash_handle)) { ctx->ctx.cryptoapi.valid = 0; return -1; } ctx->ctx.cryptoapi.valid = 1; return 0; } GIT_INLINE(int) hash_cryptoapi_update(git_hash_ctx *ctx, const void *data, size_t len) { assert(ctx->ctx.cryptoapi.valid); if (!CryptHashData(ctx->ctx.cryptoapi.hash_handle, (const BYTE *)data, (DWORD)len, 0)) return -1; return 0; } GIT_INLINE(int) hash_cryptoapi_final(git_oid *out, git_hash_ctx *ctx) { DWORD len = 20; int error = 0; assert(ctx->ctx.cryptoapi.valid); if (!CryptGetHashParam(ctx->ctx.cryptoapi.hash_handle, HP_HASHVAL, out->id, &len, 0)) error = -1; CryptDestroyHash(ctx->ctx.cryptoapi.hash_handle); ctx->ctx.cryptoapi.valid = 0; return error; } GIT_INLINE(void) hash_ctx_cryptoapi_cleanup(git_hash_ctx *ctx) { if (ctx->ctx.cryptoapi.valid) CryptDestroyHash(ctx->ctx.cryptoapi.hash_handle); } /* CNG: Available in Windows Server 2008 and newer */ GIT_INLINE(int) hash_ctx_cng_init(git_hash_ctx *ctx) { if ((ctx->ctx.cng.hash_object = git__malloc(hash_prov.prov.cng.hash_object_size)) == NULL) return -1; if (hash_prov.prov.cng.create_hash(hash_prov.prov.cng.handle, &ctx->ctx.cng.hash_handle, ctx->ctx.cng.hash_object, hash_prov.prov.cng.hash_object_size, NULL, 0, 0) < 0) { git__free(ctx->ctx.cng.hash_object); return -1; } ctx->type = CNG; ctx->prov = &hash_prov; return 0; } GIT_INLINE(int) hash_cng_init(git_hash_ctx *ctx) { BYTE hash[GIT_OID_RAWSZ]; if (!ctx->ctx.cng.updated) return 0; /* CNG needs to be finished to restart */ if (ctx->prov->prov.cng.finish_hash(ctx->ctx.cng.hash_handle, hash, GIT_OID_RAWSZ, 0) < 0) return -1; ctx->ctx.cng.updated = 0; return 0; } GIT_INLINE(int) hash_cng_update(git_hash_ctx *ctx, const void *data, size_t len) { if (ctx->prov->prov.cng.hash_data(ctx->ctx.cng.hash_handle, (PBYTE)data, (ULONG)len, 0) < 0) return -1; return 0; } GIT_INLINE(int) hash_cng_final(git_oid *out, git_hash_ctx *ctx) { if (ctx->prov->prov.cng.finish_hash(ctx->ctx.cng.hash_handle, out->id, GIT_OID_RAWSZ, 0) < 0) return -1; ctx->ctx.cng.updated = 0; return 0; } GIT_INLINE(void) hash_ctx_cng_cleanup(git_hash_ctx *ctx) { ctx->prov->prov.cng.destroy_hash(ctx->ctx.cng.hash_handle); git__free(ctx->ctx.cng.hash_object); } /* Indirection between CryptoAPI and CNG */ int git_hash_ctx_init(git_hash_ctx *ctx) { int error = 0; assert(ctx); /* * When compiled with GIT_THREADS, the global hash_prov data is * initialized with git_threads_init. Otherwise, it must be initialized * at first use. */ if (hash_prov.type == INVALID && (error = git_hash_global_init()) < 0) return error; memset(ctx, 0x0, sizeof(git_hash_ctx)); return (hash_prov.type == CNG) ? hash_ctx_cng_init(ctx) : hash_ctx_cryptoapi_init(ctx); } int git_hash_init(git_hash_ctx *ctx) { assert(ctx && ctx->type); return (ctx->type == CNG) ? hash_cng_init(ctx) : hash_cryptoapi_init(ctx); } int git_hash_update(git_hash_ctx *ctx, const void *data, size_t len) { assert(ctx && ctx->type); return (ctx->type == CNG) ? hash_cng_update(ctx, data, len) : hash_cryptoapi_update(ctx, data, len); } int git_hash_final(git_oid *out, git_hash_ctx *ctx) { assert(ctx && ctx->type); return (ctx->type == CNG) ? hash_cng_final(out, ctx) : hash_cryptoapi_final(out, ctx); } void git_hash_ctx_cleanup(git_hash_ctx *ctx) { assert(ctx); if (ctx->type == CNG) hash_ctx_cng_cleanup(ctx); else if(ctx->type == CRYPTOAPI) hash_ctx_cryptoapi_cleanup(ctx); } libgit2-0.19.0/src/hash/hash_win32.h000066400000000000000000000065021216214232500167660ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #ifndef INCLUDE_hash_win32_h__ #define INCLUDE_hash_win32_h__ #include "common.h" #include "hash.h" #include #include enum hash_win32_prov_type { INVALID = 0, CRYPTOAPI, CNG }; /* * CryptoAPI is available for hashing on Windows XP and newer. */ struct hash_cryptoapi_prov { HCRYPTPROV handle; }; /* * CNG (bcrypt.dll) is significantly more performant than CryptoAPI and is * preferred, however it is only available on Windows 2008 and newer and * must therefore be dynamically loaded, and we must inline constants that * would not exist when building in pre-Windows 2008 environments. */ #define GIT_HASH_CNG_DLL_NAME "bcrypt.dll" /* BCRYPT_SHA1_ALGORITHM */ #define GIT_HASH_CNG_HASH_TYPE L"SHA1" /* BCRYPT_OBJECT_LENGTH */ #define GIT_HASH_CNG_HASH_OBJECT_LEN L"ObjectLength" /* BCRYPT_HASH_REUSEABLE_FLAGS */ #define GIT_HASH_CNG_HASH_REUSABLE 0x00000020 /* Function declarations for CNG */ typedef NTSTATUS (WINAPI *hash_win32_cng_open_algorithm_provider_fn)( HANDLE /* BCRYPT_ALG_HANDLE */ *phAlgorithm, LPCWSTR pszAlgId, LPCWSTR pszImplementation, DWORD dwFlags); typedef NTSTATUS (WINAPI *hash_win32_cng_get_property_fn)( HANDLE /* BCRYPT_HANDLE */ hObject, LPCWSTR pszProperty, PUCHAR pbOutput, ULONG cbOutput, ULONG *pcbResult, ULONG dwFlags); typedef NTSTATUS (WINAPI *hash_win32_cng_create_hash_fn)( HANDLE /* BCRYPT_ALG_HANDLE */ hAlgorithm, HANDLE /* BCRYPT_HASH_HANDLE */ *phHash, PUCHAR pbHashObject, ULONG cbHashObject, PUCHAR pbSecret, ULONG cbSecret, ULONG dwFlags); typedef NTSTATUS (WINAPI *hash_win32_cng_finish_hash_fn)( HANDLE /* BCRYPT_HASH_HANDLE */ hHash, PUCHAR pbOutput, ULONG cbOutput, ULONG dwFlags); typedef NTSTATUS (WINAPI *hash_win32_cng_hash_data_fn)( HANDLE /* BCRYPT_HASH_HANDLE */ hHash, PUCHAR pbInput, ULONG cbInput, ULONG dwFlags); typedef NTSTATUS (WINAPI *hash_win32_cng_destroy_hash_fn)( HANDLE /* BCRYPT_HASH_HANDLE */ hHash); typedef NTSTATUS (WINAPI *hash_win32_cng_close_algorithm_provider_fn)( HANDLE /* BCRYPT_ALG_HANDLE */ hAlgorithm, ULONG dwFlags); struct hash_cng_prov { /* DLL for CNG */ HINSTANCE dll; /* Function pointers for CNG */ hash_win32_cng_open_algorithm_provider_fn open_algorithm_provider; hash_win32_cng_get_property_fn get_property; hash_win32_cng_create_hash_fn create_hash; hash_win32_cng_finish_hash_fn finish_hash; hash_win32_cng_hash_data_fn hash_data; hash_win32_cng_destroy_hash_fn destroy_hash; hash_win32_cng_close_algorithm_provider_fn close_algorithm_provider; HANDLE /* BCRYPT_ALG_HANDLE */ handle; DWORD hash_object_size; }; struct git_hash_prov { enum hash_win32_prov_type type; union { struct hash_cryptoapi_prov cryptoapi; struct hash_cng_prov cng; } prov; }; /* Hash contexts */ struct hash_cryptoapi_ctx { bool valid; HCRYPTHASH hash_handle; }; struct hash_cng_ctx { bool updated; HANDLE /* BCRYPT_HASH_HANDLE */ hash_handle; PBYTE hash_object; }; struct git_hash_ctx { enum hash_win32_prov_type type; git_hash_prov *prov; union { struct hash_cryptoapi_ctx cryptoapi; struct hash_cng_ctx cng; } ctx; }; #endif /* INCLUDE_hash_openssl_h__ */ libgit2-0.19.0/src/hashsig.c000066400000000000000000000175501216214232500155240ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #include "hashsig.h" #include "fileops.h" #include "util.h" typedef uint32_t hashsig_t; typedef uint64_t hashsig_state; #define HASHSIG_SCALE 100 #define HASHSIG_HASH_WINDOW 32 #define HASHSIG_HASH_START 0 #define HASHSIG_HASH_SHIFT 5 #define HASHSIG_HASH_MASK 0x7FFFFFFF #define HASHSIG_HEAP_SIZE ((1 << 7) - 1) typedef int (*hashsig_cmp)(const void *a, const void *b, void *); typedef struct { int size, asize; hashsig_cmp cmp; hashsig_t values[HASHSIG_HEAP_SIZE]; } hashsig_heap; typedef struct { hashsig_state state, shift_n; char window[HASHSIG_HASH_WINDOW]; int win_len, win_pos, saw_lf; } hashsig_in_progress; #define HASHSIG_IN_PROGRESS_INIT { HASHSIG_HASH_START, 1, {0}, 0, 0, 1 } struct git_hashsig { hashsig_heap mins; hashsig_heap maxs; git_hashsig_option_t opt; int considered; }; #define HEAP_LCHILD_OF(I) (((I)*2)+1) #define HEAP_RCHILD_OF(I) (((I)*2)+2) #define HEAP_PARENT_OF(I) (((I)-1)>>1) static void hashsig_heap_init(hashsig_heap *h, hashsig_cmp cmp) { h->size = 0; h->asize = HASHSIG_HEAP_SIZE; h->cmp = cmp; } static int hashsig_cmp_max(const void *a, const void *b, void *payload) { hashsig_t av = *(const hashsig_t *)a, bv = *(const hashsig_t *)b; GIT_UNUSED(payload); return (av < bv) ? -1 : (av > bv) ? 1 : 0; } static int hashsig_cmp_min(const void *a, const void *b, void *payload) { hashsig_t av = *(const hashsig_t *)a, bv = *(const hashsig_t *)b; GIT_UNUSED(payload); return (av > bv) ? -1 : (av < bv) ? 1 : 0; } static void hashsig_heap_up(hashsig_heap *h, int el) { int parent_el = HEAP_PARENT_OF(el); while (el > 0 && h->cmp(&h->values[parent_el], &h->values[el], NULL) > 0) { hashsig_t t = h->values[el]; h->values[el] = h->values[parent_el]; h->values[parent_el] = t; el = parent_el; parent_el = HEAP_PARENT_OF(el); } } static void hashsig_heap_down(hashsig_heap *h, int el) { hashsig_t v, lv, rv; /* 'el < h->size / 2' tests if el is bottom row of heap */ while (el < h->size / 2) { int lel = HEAP_LCHILD_OF(el), rel = HEAP_RCHILD_OF(el), swapel; v = h->values[el]; lv = h->values[lel]; rv = h->values[rel]; if (h->cmp(&v, &lv, NULL) < 0 && h->cmp(&v, &rv, NULL) < 0) break; swapel = (h->cmp(&lv, &rv, NULL) < 0) ? lel : rel; h->values[el] = h->values[swapel]; h->values[swapel] = v; el = swapel; } } static void hashsig_heap_sort(hashsig_heap *h) { /* only need to do this at the end for signature comparison */ git__qsort_r(h->values, h->size, sizeof(hashsig_t), h->cmp, NULL); } static void hashsig_heap_insert(hashsig_heap *h, hashsig_t val) { /* if heap is full, pop top if new element should replace it */ if (h->size == h->asize && h->cmp(&val, &h->values[0], NULL) > 0) { h->size--; h->values[0] = h->values[h->size]; hashsig_heap_down(h, 0); } /* if heap is not full, insert new element */ if (h->size < h->asize) { h->values[h->size++] = val; hashsig_heap_up(h, h->size - 1); } } GIT_INLINE(bool) hashsig_include_char( char ch, git_hashsig_option_t opt, int *saw_lf) { if ((opt & GIT_HASHSIG_IGNORE_WHITESPACE) && git__isspace(ch)) return false; if (opt & GIT_HASHSIG_SMART_WHITESPACE) { if (ch == '\r' || (*saw_lf && git__isspace(ch))) return false; *saw_lf = (ch == '\n'); } return true; } static void hashsig_initial_window( git_hashsig *sig, const char **data, size_t size, hashsig_in_progress *prog) { hashsig_state state, shift_n; int win_len; const char *scan, *end; /* init until we have processed at least HASHSIG_HASH_WINDOW data */ if (prog->win_len >= HASHSIG_HASH_WINDOW) return; state = prog->state; win_len = prog->win_len; shift_n = prog->shift_n; scan = *data; end = scan + size; while (scan < end && win_len < HASHSIG_HASH_WINDOW) { char ch = *scan++; if (!hashsig_include_char(ch, sig->opt, &prog->saw_lf)) continue; state = (state * HASHSIG_HASH_SHIFT + ch) & HASHSIG_HASH_MASK; if (!win_len) shift_n = 1; else shift_n = (shift_n * HASHSIG_HASH_SHIFT) & HASHSIG_HASH_MASK; prog->window[win_len++] = ch; } /* insert initial hash if we just finished */ if (win_len == HASHSIG_HASH_WINDOW) { hashsig_heap_insert(&sig->mins, (hashsig_t)state); hashsig_heap_insert(&sig->maxs, (hashsig_t)state); sig->considered = 1; } prog->state = state; prog->win_len = win_len; prog->shift_n = shift_n; *data = scan; } static int hashsig_add_hashes( git_hashsig *sig, const char *data, size_t size, hashsig_in_progress *prog) { const char *scan = data, *end = data + size; hashsig_state state, shift_n, rmv; if (prog->win_len < HASHSIG_HASH_WINDOW) hashsig_initial_window(sig, &scan, size, prog); state = prog->state; shift_n = prog->shift_n; /* advance window, adding new chars and removing old */ for (; scan < end; ++scan) { char ch = *scan; if (!hashsig_include_char(ch, sig->opt, &prog->saw_lf)) continue; rmv = shift_n * prog->window[prog->win_pos]; state = (state - rmv) & HASHSIG_HASH_MASK; state = (state * HASHSIG_HASH_SHIFT) & HASHSIG_HASH_MASK; state = (state + ch) & HASHSIG_HASH_MASK; hashsig_heap_insert(&sig->mins, (hashsig_t)state); hashsig_heap_insert(&sig->maxs, (hashsig_t)state); sig->considered++; prog->window[prog->win_pos] = ch; prog->win_pos = (prog->win_pos + 1) % HASHSIG_HASH_WINDOW; } prog->state = state; return 0; } static int hashsig_finalize_hashes(git_hashsig *sig) { if (sig->mins.size < HASHSIG_HEAP_SIZE) { giterr_set(GITERR_INVALID, "File too small for similarity signature calculation"); return GIT_EBUFS; } hashsig_heap_sort(&sig->mins); hashsig_heap_sort(&sig->maxs); return 0; } static git_hashsig *hashsig_alloc(git_hashsig_option_t opts) { git_hashsig *sig = git__calloc(1, sizeof(git_hashsig)); if (!sig) return NULL; hashsig_heap_init(&sig->mins, hashsig_cmp_min); hashsig_heap_init(&sig->maxs, hashsig_cmp_max); sig->opt = opts; return sig; } int git_hashsig_create( git_hashsig **out, const char *buf, size_t buflen, git_hashsig_option_t opts) { int error; hashsig_in_progress prog = HASHSIG_IN_PROGRESS_INIT; git_hashsig *sig = hashsig_alloc(opts); GITERR_CHECK_ALLOC(sig); error = hashsig_add_hashes(sig, buf, buflen, &prog); if (!error) error = hashsig_finalize_hashes(sig); if (!error) *out = sig; else git_hashsig_free(sig); return error; } int git_hashsig_create_fromfile( git_hashsig **out, const char *path, git_hashsig_option_t opts) { char buf[4096]; ssize_t buflen = 0; int error = 0, fd; hashsig_in_progress prog = HASHSIG_IN_PROGRESS_INIT; git_hashsig *sig = hashsig_alloc(opts); GITERR_CHECK_ALLOC(sig); if ((fd = git_futils_open_ro(path)) < 0) { git__free(sig); return fd; } while (!error) { if ((buflen = p_read(fd, buf, sizeof(buf))) <= 0) { if ((error = (int)buflen) < 0) giterr_set(GITERR_OS, "Read error on '%s' calculating similarity hashes", path); break; } error = hashsig_add_hashes(sig, buf, buflen, &prog); } p_close(fd); if (!error) error = hashsig_finalize_hashes(sig); if (!error) *out = sig; else git_hashsig_free(sig); return error; } void git_hashsig_free(git_hashsig *sig) { git__free(sig); } static int hashsig_heap_compare(const hashsig_heap *a, const hashsig_heap *b) { int matches = 0, i, j, cmp; assert(a->cmp == b->cmp); /* hash heaps are sorted - just look for overlap vs total */ for (i = 0, j = 0; i < a->size && j < b->size; ) { cmp = a->cmp(&a->values[i], &b->values[j], NULL); if (cmp < 0) ++i; else if (cmp > 0) ++j; else { ++i; ++j; ++matches; } } return HASHSIG_SCALE * (matches * 2) / (a->size + b->size); } int git_hashsig_compare(const git_hashsig *a, const git_hashsig *b) { return (hashsig_heap_compare(&a->mins, &b->mins) + hashsig_heap_compare(&a->maxs, &b->maxs)) / 2; } libgit2-0.19.0/src/hashsig.h000066400000000000000000000037521216214232500155300ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #ifndef INCLUDE_hashsig_h__ #define INCLUDE_hashsig_h__ #include "common.h" /** * Similarity signature of line hashes for a buffer */ typedef struct git_hashsig git_hashsig; typedef enum { GIT_HASHSIG_NORMAL = 0, /* use all data */ GIT_HASHSIG_IGNORE_WHITESPACE = 1, /* ignore whitespace */ GIT_HASHSIG_SMART_WHITESPACE = 2, /* ignore \r and all space after \n */ } git_hashsig_option_t; /** * Build a similarity signature for a buffer * * If you have passed a whitespace-ignoring buffer, then the whitespace * will be removed from the buffer while it is being processed, modifying * the buffer in place. Sorry about that! * * This will return an error if the buffer doesn't contain enough data to * compute a valid signature. * * @param out The array of hashed runs representing the file content * @param buf The contents of the file to hash * @param buflen The length of the data at `buf` * @param generate_pairwise_hashes Should pairwise runs be hashed */ extern int git_hashsig_create( git_hashsig **out, const char *buf, size_t buflen, git_hashsig_option_t opts); /** * Build a similarity signature from a file * * This walks through the file, only loading a maximum of 4K of file data at * a time. Otherwise, it acts just like `git_hashsig_create`. * * This will return an error if the file doesn't contain enough data to * compute a valid signature. */ extern int git_hashsig_create_fromfile( git_hashsig **out, const char *path, git_hashsig_option_t opts); /** * Release memory for a content similarity signature */ extern void git_hashsig_free(git_hashsig *sig); /** * Measure similarity between two files * * @return <0 for error, [0 to 100] as similarity score */ extern int git_hashsig_compare( const git_hashsig *a, const git_hashsig *b); #endif libgit2-0.19.0/src/ignore.c000066400000000000000000000224771216214232500153650ustar00rootroot00000000000000#include "git2/ignore.h" #include "ignore.h" #include "attr.h" #include "path.h" #include "config.h" #define GIT_IGNORE_INTERNAL "[internal]exclude" #define GIT_IGNORE_DEFAULT_RULES ".\n..\n.git\n" static int parse_ignore_file( git_repository *repo, void *parsedata, const char *buffer, git_attr_file *ignores) { int error = 0; git_attr_fnmatch *match = NULL; const char *scan = NULL; char *context = NULL; int ignore_case = false; /* Prefer to have the caller pass in a git_ignores as the parsedata * object. If they did not, then look up the value of ignore_case */ if (parsedata != NULL) ignore_case = ((git_ignores *)parsedata)->ignore_case; else if (git_repository__cvar(&ignore_case, repo, GIT_CVAR_IGNORECASE) < 0) return error; if (ignores->key && git__suffixcmp(ignores->key, "/" GIT_IGNORE_FILE) == 0) { context = ignores->key + 2; context[strlen(context) - strlen(GIT_IGNORE_FILE)] = '\0'; } scan = buffer; while (!error && *scan) { if (!match) { match = git__calloc(1, sizeof(*match)); GITERR_CHECK_ALLOC(match); } match->flags = GIT_ATTR_FNMATCH_ALLOWSPACE; if (!(error = git_attr_fnmatch__parse( match, ignores->pool, context, &scan))) { match->flags |= GIT_ATTR_FNMATCH_IGNORE; if (ignore_case) match->flags |= GIT_ATTR_FNMATCH_ICASE; scan = git__next_line(scan); error = git_vector_insert(&ignores->rules, match); } if (error != 0) { git__free(match->pattern); match->pattern = NULL; if (error == GIT_ENOTFOUND) error = 0; } else { match = NULL; /* vector now "owns" the match */ } } git__free(match); /* restore file path used for context */ if (context) context[strlen(context)] = '.'; /* first char of GIT_IGNORE_FILE */ return error; } #define push_ignore_file(R,IGN,S,B,F) \ git_attr_cache__push_file((R),(B),(F),GIT_ATTR_FILE_FROM_FILE,parse_ignore_file,(IGN),(S)) static int push_one_ignore(void *ref, git_buf *path) { git_ignores *ign = (git_ignores *)ref; return push_ignore_file(ign->repo, ign, &ign->ign_path, path->ptr, GIT_IGNORE_FILE); } static int get_internal_ignores(git_attr_file **ign, git_repository *repo) { int error; if (!(error = git_attr_cache__init(repo))) error = git_attr_cache__internal_file(repo, GIT_IGNORE_INTERNAL, ign); if (!error && !(*ign)->rules.length) error = parse_ignore_file(repo, NULL, GIT_IGNORE_DEFAULT_RULES, *ign); return error; } int git_ignore__for_path( git_repository *repo, const char *path, git_ignores *ignores) { int error = 0; const char *workdir = git_repository_workdir(repo); assert(ignores); ignores->repo = repo; git_buf_init(&ignores->dir, 0); ignores->ign_internal = NULL; /* Read the ignore_case flag */ if ((error = git_repository__cvar( &ignores->ignore_case, repo, GIT_CVAR_IGNORECASE)) < 0) goto cleanup; if ((error = git_vector_init(&ignores->ign_path, 8, NULL)) < 0 || (error = git_vector_init(&ignores->ign_global, 2, NULL)) < 0 || (error = git_attr_cache__init(repo)) < 0) goto cleanup; /* given a unrooted path in a non-bare repo, resolve it */ if (workdir && git_path_root(path) < 0) error = git_path_find_dir(&ignores->dir, path, workdir); else error = git_buf_sets(&ignores->dir, path); if (error < 0) goto cleanup; /* set up internals */ error = get_internal_ignores(&ignores->ign_internal, repo); if (error < 0) goto cleanup; /* load .gitignore up the path */ if (workdir != NULL) { error = git_path_walk_up( &ignores->dir, workdir, push_one_ignore, ignores); if (error < 0) goto cleanup; } /* load .git/info/exclude */ error = push_ignore_file(repo, ignores, &ignores->ign_global, git_repository_path(repo), GIT_IGNORE_FILE_INREPO); if (error < 0) goto cleanup; /* load core.excludesfile */ if (git_repository_attr_cache(repo)->cfg_excl_file != NULL) error = push_ignore_file(repo, ignores, &ignores->ign_global, NULL, git_repository_attr_cache(repo)->cfg_excl_file); cleanup: if (error < 0) git_ignore__free(ignores); return error; } int git_ignore__push_dir(git_ignores *ign, const char *dir) { if (git_buf_joinpath(&ign->dir, ign->dir.ptr, dir) < 0) return -1; else return push_ignore_file( ign->repo, ign, &ign->ign_path, ign->dir.ptr, GIT_IGNORE_FILE); } int git_ignore__pop_dir(git_ignores *ign) { if (ign->ign_path.length > 0) { git_attr_file *file = git_vector_last(&ign->ign_path); if (git__suffixcmp(ign->dir.ptr, file->key + 2) == 0) git_vector_pop(&ign->ign_path); git_buf_rtruncate_at_char(&ign->dir, '/'); } return 0; } void git_ignore__free(git_ignores *ignores) { /* don't need to free ignores->ign_internal since it is in cache */ git_vector_free(&ignores->ign_path); git_vector_free(&ignores->ign_global); git_buf_free(&ignores->dir); } static bool ignore_lookup_in_rules( git_vector *rules, git_attr_path *path, int *ignored) { size_t j; git_attr_fnmatch *match; git_vector_rforeach(rules, j, match) { if (git_attr_fnmatch__match(match, path)) { *ignored = ((match->flags & GIT_ATTR_FNMATCH_NEGATIVE) == 0); return true; } } return false; } int git_ignore__lookup( git_ignores *ignores, const char *pathname, int *ignored) { unsigned int i; git_attr_file *file; git_attr_path path; if (git_attr_path__init( &path, pathname, git_repository_workdir(ignores->repo)) < 0) return -1; /* first process builtins - success means path was found */ if (ignore_lookup_in_rules( &ignores->ign_internal->rules, &path, ignored)) goto cleanup; /* next process files in the path */ git_vector_foreach(&ignores->ign_path, i, file) { if (ignore_lookup_in_rules(&file->rules, &path, ignored)) goto cleanup; } /* last process global ignores */ git_vector_foreach(&ignores->ign_global, i, file) { if (ignore_lookup_in_rules(&file->rules, &path, ignored)) goto cleanup; } *ignored = 0; cleanup: git_attr_path__free(&path); return 0; } int git_ignore_add_rule( git_repository *repo, const char *rules) { int error; git_attr_file *ign_internal; if (!(error = get_internal_ignores(&ign_internal, repo))) error = parse_ignore_file(repo, NULL, rules, ign_internal); return error; } int git_ignore_clear_internal_rules( git_repository *repo) { int error; git_attr_file *ign_internal; if (!(error = get_internal_ignores(&ign_internal, repo))) { git_attr_file__clear_rules(ign_internal); return parse_ignore_file( repo, NULL, GIT_IGNORE_DEFAULT_RULES, ign_internal); } return error; } int git_ignore_path_is_ignored( int *ignored, git_repository *repo, const char *pathname) { int error; const char *workdir; git_attr_path path; char *tail, *end; bool full_is_dir; git_ignores ignores; unsigned int i; git_attr_file *file; assert(ignored && pathname); workdir = repo ? git_repository_workdir(repo) : NULL; if ((error = git_attr_path__init(&path, pathname, workdir)) < 0) return error; tail = path.path; end = &path.full.ptr[path.full.size]; full_is_dir = path.is_dir; while (1) { /* advance to next component of path */ path.basename = tail; while (tail < end && *tail != '/') tail++; *tail = '\0'; path.full.size = (tail - path.full.ptr); path.is_dir = (tail == end) ? full_is_dir : true; /* update ignores for new path fragment */ if (path.basename == path.path) error = git_ignore__for_path(repo, path.path, &ignores); else error = git_ignore__push_dir(&ignores, path.basename); if (error < 0) break; /* first process builtins - success means path was found */ if (ignore_lookup_in_rules( &ignores.ign_internal->rules, &path, ignored)) goto cleanup; /* next process files in the path */ git_vector_foreach(&ignores.ign_path, i, file) { if (ignore_lookup_in_rules(&file->rules, &path, ignored)) goto cleanup; } /* last process global ignores */ git_vector_foreach(&ignores.ign_global, i, file) { if (ignore_lookup_in_rules(&file->rules, &path, ignored)) goto cleanup; } /* if we found no rules before reaching the end, we're done */ if (tail == end) break; /* reinstate divider in path */ *tail = '/'; while (*tail == '/') tail++; } *ignored = 0; cleanup: git_attr_path__free(&path); git_ignore__free(&ignores); return error; } int git_ignore__check_pathspec_for_exact_ignores( git_repository *repo, git_vector *vspec, bool no_fnmatch) { int error = 0; size_t i; git_attr_fnmatch *match; int ignored; git_buf path = GIT_BUF_INIT; const char *wd, *filename; git_index *idx; if ((error = git_repository__ensure_not_bare( repo, "validate pathspec")) < 0 || (error = git_repository_index(&idx, repo)) < 0) return error; wd = git_repository_workdir(repo); git_vector_foreach(vspec, i, match) { /* skip wildcard matches (if they are being used) */ if ((match->flags & GIT_ATTR_FNMATCH_HASWILD) != 0 && !no_fnmatch) continue; filename = match->pattern; /* if file is already in the index, it's fine */ if (git_index_get_bypath(idx, filename, 0) != NULL) continue; if ((error = git_buf_joinpath(&path, wd, filename)) < 0) break; /* is there a file on disk that matches this exactly? */ if (!git_path_isfile(path.ptr)) continue; /* is that file ignored? */ if ((error = git_ignore_path_is_ignored(&ignored, repo, filename)) < 0) break; if (ignored) { giterr_set(GITERR_INVALID, "pathspec contains ignored file '%s'", filename); error = GIT_EINVALIDSPEC; break; } } git_index_free(idx); git_buf_free(&path); return error; } libgit2-0.19.0/src/ignore.h000066400000000000000000000033101216214232500153530ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #ifndef INCLUDE_ignore_h__ #define INCLUDE_ignore_h__ #include "repository.h" #include "vector.h" #include "attr_file.h" #define GIT_IGNORE_FILE ".gitignore" #define GIT_IGNORE_FILE_INREPO "info/exclude" #define GIT_IGNORE_FILE_XDG "ignore" /* The git_ignores structure maintains three sets of ignores: * - internal ignores * - per directory ignores * - global ignores (at lower priority than the others) * As you traverse from one directory to another, you can push and pop * directories onto git_ignores list efficiently. */ typedef struct { git_repository *repo; git_buf dir; git_attr_file *ign_internal; git_vector ign_path; git_vector ign_global; int ignore_case; } git_ignores; extern int git_ignore__for_path(git_repository *repo, const char *path, git_ignores *ign); extern int git_ignore__push_dir(git_ignores *ign, const char *dir); extern int git_ignore__pop_dir(git_ignores *ign); extern void git_ignore__free(git_ignores *ign); extern int git_ignore__lookup(git_ignores *ign, const char *path, int *ignored); /* command line Git sometimes generates an error message if given a * pathspec that contains an exact match to an ignored file (provided * --force isn't also given). This makes it easy to check it that has * happened. Returns GIT_EINVALIDSPEC if the pathspec contains ignored * exact matches (that are not already present in the index). */ extern int git_ignore__check_pathspec_for_exact_ignores( git_repository *repo, git_vector *pathspec, bool no_fnmatch); #endif libgit2-0.19.0/src/index.c000066400000000000000000001521121216214232500151770ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #include #include "common.h" #include "repository.h" #include "index.h" #include "tree.h" #include "tree-cache.h" #include "hash.h" #include "iterator.h" #include "pathspec.h" #include "ignore.h" #include "git2/odb.h" #include "git2/oid.h" #include "git2/blob.h" #include "git2/config.h" #include "git2/sys/index.h" #define entry_size(type,len) ((offsetof(type, path) + (len) + 8) & ~7) #define short_entry_size(len) entry_size(struct entry_short, len) #define long_entry_size(len) entry_size(struct entry_long, len) #define minimal_entry_size (offsetof(struct entry_short, path)) static const size_t INDEX_FOOTER_SIZE = GIT_OID_RAWSZ; static const size_t INDEX_HEADER_SIZE = 12; static const unsigned int INDEX_VERSION_NUMBER = 2; static const unsigned int INDEX_VERSION_NUMBER_EXT = 3; static const unsigned int INDEX_HEADER_SIG = 0x44495243; static const char INDEX_EXT_TREECACHE_SIG[] = {'T', 'R', 'E', 'E'}; static const char INDEX_EXT_UNMERGED_SIG[] = {'R', 'E', 'U', 'C'}; static const char INDEX_EXT_CONFLICT_NAME_SIG[] = {'N', 'A', 'M', 'E'}; #define INDEX_OWNER(idx) ((git_repository *)(GIT_REFCOUNT_OWNER(idx))) struct index_header { uint32_t signature; uint32_t version; uint32_t entry_count; }; struct index_extension { char signature[4]; uint32_t extension_size; }; struct entry_time { uint32_t seconds; uint32_t nanoseconds; }; struct entry_short { struct entry_time ctime; struct entry_time mtime; uint32_t dev; uint32_t ino; uint32_t mode; uint32_t uid; uint32_t gid; uint32_t file_size; git_oid oid; uint16_t flags; char path[1]; /* arbitrary length */ }; struct entry_long { struct entry_time ctime; struct entry_time mtime; uint32_t dev; uint32_t ino; uint32_t mode; uint32_t uid; uint32_t gid; uint32_t file_size; git_oid oid; uint16_t flags; uint16_t flags_extended; char path[1]; /* arbitrary length */ }; struct entry_srch_key { const char *path; int stage; }; /* local declarations */ static size_t read_extension(git_index *index, const char *buffer, size_t buffer_size); static size_t read_entry(git_index_entry *dest, const void *buffer, size_t buffer_size); static int read_header(struct index_header *dest, const void *buffer); static int parse_index(git_index *index, const char *buffer, size_t buffer_size); static bool is_index_extended(git_index *index); static int write_index(git_index *index, git_filebuf *file); static int index_find(size_t *at_pos, git_index *index, const char *path, int stage); static void index_entry_free(git_index_entry *entry); static void index_entry_reuc_free(git_index_reuc_entry *reuc); static int index_srch(const void *key, const void *array_member) { const struct entry_srch_key *srch_key = key; const git_index_entry *entry = array_member; int ret; ret = strcmp(srch_key->path, entry->path); if (ret == 0) ret = srch_key->stage - GIT_IDXENTRY_STAGE(entry); return ret; } static int index_isrch(const void *key, const void *array_member) { const struct entry_srch_key *srch_key = key; const git_index_entry *entry = array_member; int ret; ret = strcasecmp(srch_key->path, entry->path); if (ret == 0) ret = srch_key->stage - GIT_IDXENTRY_STAGE(entry); return ret; } static int index_cmp_path(const void *a, const void *b) { return strcmp((const char *)a, (const char *)b); } static int index_icmp_path(const void *a, const void *b) { return strcasecmp((const char *)a, (const char *)b); } static int index_srch_path(const void *path, const void *array_member) { const git_index_entry *entry = array_member; return strcmp((const char *)path, entry->path); } static int index_isrch_path(const void *path, const void *array_member) { const git_index_entry *entry = array_member; return strcasecmp((const char *)path, entry->path); } static int index_cmp(const void *a, const void *b) { int diff; const git_index_entry *entry_a = a; const git_index_entry *entry_b = b; diff = strcmp(entry_a->path, entry_b->path); if (diff == 0) diff = (GIT_IDXENTRY_STAGE(entry_a) - GIT_IDXENTRY_STAGE(entry_b)); return diff; } static int index_icmp(const void *a, const void *b) { int diff; const git_index_entry *entry_a = a; const git_index_entry *entry_b = b; diff = strcasecmp(entry_a->path, entry_b->path); if (diff == 0) diff = (GIT_IDXENTRY_STAGE(entry_a) - GIT_IDXENTRY_STAGE(entry_b)); return diff; } static int conflict_name_cmp(const void *a, const void *b) { const git_index_name_entry *name_a = a; const git_index_name_entry *name_b = b; if (name_a->ancestor && !name_b->ancestor) return 1; if (!name_a->ancestor && name_b->ancestor) return -1; if (name_a->ancestor) return strcmp(name_a->ancestor, name_b->ancestor); if (!name_a->ours || !name_b->ours) return 0; return strcmp(name_a->ours, name_b->ours); } /** * TODO: enable this when resolving case insensitive conflicts */ #if 0 static int conflict_name_icmp(const void *a, const void *b) { const git_index_name_entry *name_a = a; const git_index_name_entry *name_b = b; if (name_a->ancestor && !name_b->ancestor) return 1; if (!name_a->ancestor && name_b->ancestor) return -1; if (name_a->ancestor) return strcasecmp(name_a->ancestor, name_b->ancestor); if (!name_a->ours || !name_b->ours) return 0; return strcasecmp(name_a->ours, name_b->ours); } #endif static int reuc_srch(const void *key, const void *array_member) { const git_index_reuc_entry *reuc = array_member; return strcmp(key, reuc->path); } static int reuc_isrch(const void *key, const void *array_member) { const git_index_reuc_entry *reuc = array_member; return strcasecmp(key, reuc->path); } static int reuc_cmp(const void *a, const void *b) { const git_index_reuc_entry *info_a = a; const git_index_reuc_entry *info_b = b; return strcmp(info_a->path, info_b->path); } static int reuc_icmp(const void *a, const void *b) { const git_index_reuc_entry *info_a = a; const git_index_reuc_entry *info_b = b; return strcasecmp(info_a->path, info_b->path); } static unsigned int index_create_mode(unsigned int mode) { if (S_ISLNK(mode)) return S_IFLNK; if (S_ISDIR(mode) || (mode & S_IFMT) == (S_IFLNK | S_IFDIR)) return (S_IFLNK | S_IFDIR); return S_IFREG | ((mode & 0100) ? 0755 : 0644); } static unsigned int index_merge_mode( git_index *index, git_index_entry *existing, unsigned int mode) { if (index->no_symlinks && S_ISREG(mode) && existing && S_ISLNK(existing->mode)) return existing->mode; if (index->distrust_filemode && S_ISREG(mode)) return (existing && S_ISREG(existing->mode)) ? existing->mode : index_create_mode(0666); return index_create_mode(mode); } void git_index__set_ignore_case(git_index *index, bool ignore_case) { index->ignore_case = ignore_case; index->entries_cmp_path = ignore_case ? index_icmp_path : index_cmp_path; index->entries_search = ignore_case ? index_isrch : index_srch; index->entries_search_path = ignore_case ? index_isrch_path : index_srch_path; git_vector_set_cmp(&index->entries, ignore_case ? index_icmp : index_cmp); git_vector_sort(&index->entries); index->reuc_search = ignore_case ? reuc_isrch : reuc_srch; git_vector_set_cmp(&index->reuc, ignore_case ? reuc_icmp : reuc_cmp); git_vector_sort(&index->reuc); } int git_index_open(git_index **index_out, const char *index_path) { git_index *index; assert(index_out); index = git__calloc(1, sizeof(git_index)); GITERR_CHECK_ALLOC(index); if (index_path != NULL) { index->index_file_path = git__strdup(index_path); GITERR_CHECK_ALLOC(index->index_file_path); /* Check if index file is stored on disk already */ if (git_path_exists(index->index_file_path) == true) index->on_disk = 1; } if (git_vector_init(&index->entries, 32, index_cmp) < 0 || git_vector_init(&index->names, 32, conflict_name_cmp) < 0 || git_vector_init(&index->reuc, 32, reuc_cmp) < 0) return -1; index->entries_cmp_path = index_cmp_path; index->entries_search = index_srch; index->entries_search_path = index_srch_path; index->reuc_search = reuc_srch; *index_out = index; GIT_REFCOUNT_INC(index); return (index_path != NULL) ? git_index_read(index) : 0; } int git_index_new(git_index **out) { return git_index_open(out, NULL); } static void index_free(git_index *index) { git_index_clear(index); git_vector_free(&index->entries); git_vector_free(&index->names); git_vector_free(&index->reuc); git__free(index->index_file_path); git__memzero(index, sizeof(*index)); git__free(index); } void git_index_free(git_index *index) { if (index == NULL) return; GIT_REFCOUNT_DEC(index, index_free); } static void index_entries_free(git_vector *entries) { size_t i; for (i = 0; i < entries->length; ++i) { git_index_entry *e = git_vector_get(entries, i); git__free(e->path); git__free(e); } git_vector_clear(entries); } void git_index_clear(git_index *index) { assert(index); index_entries_free(&index->entries); git_index_reuc_clear(index); git_index_name_clear(index); git_futils_filestamp_set(&index->stamp, NULL); git_tree_cache_free(index->tree); index->tree = NULL; } static int create_index_error(int error, const char *msg) { giterr_set(GITERR_INDEX, msg); return error; } int git_index_set_caps(git_index *index, unsigned int caps) { int old_ignore_case; assert(index); old_ignore_case = index->ignore_case; if (caps == GIT_INDEXCAP_FROM_OWNER) { git_repository *repo = INDEX_OWNER(index); int val; if (!repo) return create_index_error( -1, "Cannot access repository to set index caps"); if (!git_repository__cvar(&val, repo, GIT_CVAR_IGNORECASE)) index->ignore_case = (val != 0); if (!git_repository__cvar(&val, repo, GIT_CVAR_FILEMODE)) index->distrust_filemode = (val == 0); if (!git_repository__cvar(&val, repo, GIT_CVAR_SYMLINKS)) index->no_symlinks = (val == 0); } else { index->ignore_case = ((caps & GIT_INDEXCAP_IGNORE_CASE) != 0); index->distrust_filemode = ((caps & GIT_INDEXCAP_NO_FILEMODE) != 0); index->no_symlinks = ((caps & GIT_INDEXCAP_NO_SYMLINKS) != 0); } if (old_ignore_case != index->ignore_case) { git_index__set_ignore_case(index, index->ignore_case); } return 0; } unsigned int git_index_caps(const git_index *index) { return ((index->ignore_case ? GIT_INDEXCAP_IGNORE_CASE : 0) | (index->distrust_filemode ? GIT_INDEXCAP_NO_FILEMODE : 0) | (index->no_symlinks ? GIT_INDEXCAP_NO_SYMLINKS : 0)); } int git_index_read(git_index *index) { int error = 0, updated; git_buf buffer = GIT_BUF_INIT; git_futils_filestamp stamp = {0}; if (!index->index_file_path) return create_index_error(-1, "Failed to read index: The index is in-memory only"); if (!index->on_disk || git_path_exists(index->index_file_path) == false) { git_index_clear(index); index->on_disk = 0; return 0; } updated = git_futils_filestamp_check(&stamp, index->index_file_path); if (updated <= 0) return updated; error = git_futils_readbuffer(&buffer, index->index_file_path); if (error < 0) return error; git_index_clear(index); error = parse_index(index, buffer.ptr, buffer.size); if (!error) git_futils_filestamp_set(&index->stamp, &stamp); git_buf_free(&buffer); return error; } int git_index_write(git_index *index) { git_filebuf file = GIT_FILEBUF_INIT; int error; if (!index->index_file_path) return create_index_error(-1, "Failed to read index: The index is in-memory only"); git_vector_sort(&index->entries); git_vector_sort(&index->reuc); if ((error = git_filebuf_open( &file, index->index_file_path, GIT_FILEBUF_HASH_CONTENTS)) < 0) return error; if ((error = write_index(index, &file)) < 0) { git_filebuf_cleanup(&file); return error; } if ((error = git_filebuf_commit(&file, GIT_INDEX_FILE_MODE)) < 0) return error; error = git_futils_filestamp_check(&index->stamp, index->index_file_path); if (error < 0) return error; index->on_disk = 1; return 0; } int git_index_write_tree(git_oid *oid, git_index *index) { git_repository *repo; assert(oid && index); repo = INDEX_OWNER(index); if (repo == NULL) return create_index_error(-1, "Failed to write tree. " "The index file is not backed up by an existing repository"); return git_tree__write_index(oid, index, repo); } int git_index_write_tree_to(git_oid *oid, git_index *index, git_repository *repo) { assert(oid && index && repo); return git_tree__write_index(oid, index, repo); } size_t git_index_entrycount(const git_index *index) { assert(index); return index->entries.length; } const git_index_entry *git_index_get_byindex( git_index *index, size_t n) { assert(index); git_vector_sort(&index->entries); return git_vector_get(&index->entries, n); } const git_index_entry *git_index_get_bypath( git_index *index, const char *path, int stage) { size_t pos; assert(index); git_vector_sort(&index->entries); if (index_find(&pos, index, path, stage) < 0) { giterr_set(GITERR_INDEX, "Index does not contain %s", path); return NULL; } return git_index_get_byindex(index, pos); } void git_index_entry__init_from_stat(git_index_entry *entry, struct stat *st) { entry->ctime.seconds = (git_time_t)st->st_ctime; entry->mtime.seconds = (git_time_t)st->st_mtime; /* entry->mtime.nanoseconds = st->st_mtimensec; */ /* entry->ctime.nanoseconds = st->st_ctimensec; */ entry->dev = st->st_rdev; entry->ino = st->st_ino; entry->mode = index_create_mode(st->st_mode); entry->uid = st->st_uid; entry->gid = st->st_gid; entry->file_size = st->st_size; } int git_index_entry__cmp(const void *a, const void *b) { const git_index_entry *entry_a = a; const git_index_entry *entry_b = b; return strcmp(entry_a->path, entry_b->path); } int git_index_entry__cmp_icase(const void *a, const void *b) { const git_index_entry *entry_a = a; const git_index_entry *entry_b = b; return strcasecmp(entry_a->path, entry_b->path); } static int index_entry_init(git_index_entry **entry_out, git_index *index, const char *rel_path) { git_index_entry *entry = NULL; struct stat st; git_oid oid; const char *workdir; git_buf full_path = GIT_BUF_INIT; int error; if (INDEX_OWNER(index) == NULL) return create_index_error(-1, "Could not initialize index entry. " "Index is not backed up by an existing repository."); workdir = git_repository_workdir(INDEX_OWNER(index)); if (!workdir) return create_index_error(GIT_EBAREREPO, "Could not initialize index entry. Repository is bare"); if ((error = git_buf_joinpath(&full_path, workdir, rel_path)) < 0) return error; if ((error = git_path_lstat(full_path.ptr, &st)) < 0) { git_buf_free(&full_path); return error; } git_buf_free(&full_path); /* done with full path */ /* There is no need to validate the rel_path here, since it will be * immediately validated by the call to git_blob_create_fromfile. */ /* write the blob to disk and get the oid */ if ((error = git_blob_create_fromworkdir(&oid, INDEX_OWNER(index), rel_path)) < 0) return error; entry = git__calloc(1, sizeof(git_index_entry)); GITERR_CHECK_ALLOC(entry); git_index_entry__init_from_stat(entry, &st); entry->oid = oid; entry->path = git__strdup(rel_path); GITERR_CHECK_ALLOC(entry->path); *entry_out = entry; return 0; } static int index_entry_reuc_init(git_index_reuc_entry **reuc_out, const char *path, int ancestor_mode, const git_oid *ancestor_oid, int our_mode, const git_oid *our_oid, int their_mode, const git_oid *their_oid) { git_index_reuc_entry *reuc = NULL; assert(reuc_out && path); *reuc_out = NULL; reuc = git__calloc(1, sizeof(git_index_reuc_entry)); GITERR_CHECK_ALLOC(reuc); reuc->path = git__strdup(path); if (reuc->path == NULL) return -1; if ((reuc->mode[0] = ancestor_mode) > 0) git_oid_cpy(&reuc->oid[0], ancestor_oid); if ((reuc->mode[1] = our_mode) > 0) git_oid_cpy(&reuc->oid[1], our_oid); if ((reuc->mode[2] = their_mode) > 0) git_oid_cpy(&reuc->oid[2], their_oid); *reuc_out = reuc; return 0; } static void index_entry_reuc_free(git_index_reuc_entry *reuc) { if (!reuc) return; git__free(reuc->path); git__free(reuc); } static git_index_entry *index_entry_dup(const git_index_entry *source_entry) { git_index_entry *entry; entry = git__malloc(sizeof(git_index_entry)); if (!entry) return NULL; memcpy(entry, source_entry, sizeof(git_index_entry)); /* duplicate the path string so we own it */ entry->path = git__strdup(entry->path); if (!entry->path) return NULL; return entry; } static void index_entry_free(git_index_entry *entry) { if (!entry) return; git__free(entry->path); git__free(entry); } static int index_insert(git_index *index, git_index_entry *entry, int replace) { size_t path_length, position; git_index_entry **existing = NULL; assert(index && entry && entry->path != NULL); /* make sure that the path length flag is correct */ path_length = strlen(entry->path); entry->flags &= ~GIT_IDXENTRY_NAMEMASK; if (path_length < GIT_IDXENTRY_NAMEMASK) entry->flags |= path_length & GIT_IDXENTRY_NAMEMASK; else entry->flags |= GIT_IDXENTRY_NAMEMASK; /* look if an entry with this path already exists */ if (!index_find(&position, index, entry->path, GIT_IDXENTRY_STAGE(entry))) { existing = (git_index_entry **)&index->entries.contents[position]; /* update filemode to existing values if stat is not trusted */ entry->mode = index_merge_mode(index, *existing, entry->mode); } /* if replacing is not requested or no existing entry exists, just * insert entry at the end; the index is no longer sorted */ if (!replace || !existing) return git_vector_insert(&index->entries, entry); /* exists, replace it (preserving name from existing entry) */ git__free(entry->path); entry->path = (*existing)->path; git__free(*existing); *existing = entry; return 0; } static int index_conflict_to_reuc(git_index *index, const char *path) { const git_index_entry *conflict_entries[3]; int ancestor_mode, our_mode, their_mode; git_oid const *ancestor_oid, *our_oid, *their_oid; int ret; if ((ret = git_index_conflict_get(&conflict_entries[0], &conflict_entries[1], &conflict_entries[2], index, path)) < 0) return ret; ancestor_mode = conflict_entries[0] == NULL ? 0 : conflict_entries[0]->mode; our_mode = conflict_entries[1] == NULL ? 0 : conflict_entries[1]->mode; their_mode = conflict_entries[2] == NULL ? 0 : conflict_entries[2]->mode; ancestor_oid = conflict_entries[0] == NULL ? NULL : &conflict_entries[0]->oid; our_oid = conflict_entries[1] == NULL ? NULL : &conflict_entries[1]->oid; their_oid = conflict_entries[2] == NULL ? NULL : &conflict_entries[2]->oid; if ((ret = git_index_reuc_add(index, path, ancestor_mode, ancestor_oid, our_mode, our_oid, their_mode, their_oid)) >= 0) ret = git_index_conflict_remove(index, path); return ret; } int git_index_add_bypath(git_index *index, const char *path) { git_index_entry *entry = NULL; int ret; assert(index && path); if ((ret = index_entry_init(&entry, index, path)) < 0 || (ret = index_insert(index, entry, 1)) < 0) goto on_error; /* Adding implies conflict was resolved, move conflict entries to REUC */ if ((ret = index_conflict_to_reuc(index, path)) < 0 && ret != GIT_ENOTFOUND) goto on_error; git_tree_cache_invalidate_path(index->tree, entry->path); return 0; on_error: index_entry_free(entry); return ret; } int git_index_remove_bypath(git_index *index, const char *path) { int ret; assert(index && path); if (((ret = git_index_remove(index, path, 0)) < 0 && ret != GIT_ENOTFOUND) || ((ret = index_conflict_to_reuc(index, path)) < 0 && ret != GIT_ENOTFOUND)) return ret; return 0; } int git_index_add(git_index *index, const git_index_entry *source_entry) { git_index_entry *entry = NULL; int ret; entry = index_entry_dup(source_entry); if (entry == NULL) return -1; if ((ret = index_insert(index, entry, 1)) < 0) { index_entry_free(entry); return ret; } git_tree_cache_invalidate_path(index->tree, entry->path); return 0; } int git_index_remove(git_index *index, const char *path, int stage) { size_t position; int error; git_index_entry *entry; git_vector_sort(&index->entries); if (index_find(&position, index, path, stage) < 0) { giterr_set(GITERR_INDEX, "Index does not contain %s at stage %d", path, stage); return GIT_ENOTFOUND; } entry = git_vector_get(&index->entries, position); if (entry != NULL) git_tree_cache_invalidate_path(index->tree, entry->path); error = git_vector_remove(&index->entries, position); if (!error) index_entry_free(entry); return error; } int git_index_remove_directory(git_index *index, const char *dir, int stage) { git_buf pfx = GIT_BUF_INIT; int error = 0; size_t pos; git_index_entry *entry; if (git_buf_sets(&pfx, dir) < 0 || git_path_to_dir(&pfx) < 0) return -1; git_vector_sort(&index->entries); pos = git_index__prefix_position(index, pfx.ptr); while (1) { entry = git_vector_get(&index->entries, pos); if (!entry || git__prefixcmp(entry->path, pfx.ptr) != 0) break; if (GIT_IDXENTRY_STAGE(entry) != stage) { ++pos; continue; } git_tree_cache_invalidate_path(index->tree, entry->path); if ((error = git_vector_remove(&index->entries, pos)) < 0) break; index_entry_free(entry); /* removed entry at 'pos' so we don't need to increment it */ } git_buf_free(&pfx); return error; } static int index_find(size_t *at_pos, git_index *index, const char *path, int stage) { struct entry_srch_key srch_key; assert(path); srch_key.path = path; srch_key.stage = stage; return git_vector_bsearch2(at_pos, &index->entries, index->entries_search, &srch_key); } int git_index_find(size_t *at_pos, git_index *index, const char *path) { size_t pos; assert(index && path); if (git_vector_bsearch2(&pos, &index->entries, index->entries_search_path, path) < 0) { giterr_set(GITERR_INDEX, "Index does not contain %s", path); return GIT_ENOTFOUND; } /* Since our binary search only looked at path, we may be in the * middle of a list of stages. */ while (pos > 0) { const git_index_entry *prev = git_vector_get(&index->entries, pos-1); if (index->entries_cmp_path(prev->path, path) != 0) break; --pos; } if (at_pos) *at_pos = pos; return 0; } size_t git_index__prefix_position(git_index *index, const char *path) { struct entry_srch_key srch_key; size_t pos; srch_key.path = path; srch_key.stage = 0; git_vector_sort(&index->entries); git_vector_bsearch2( &pos, &index->entries, index->entries_search, &srch_key); return pos; } int git_index_conflict_add(git_index *index, const git_index_entry *ancestor_entry, const git_index_entry *our_entry, const git_index_entry *their_entry) { git_index_entry *entries[3] = { 0 }; unsigned short i; int ret = 0; assert (index); if ((ancestor_entry != NULL && (entries[0] = index_entry_dup(ancestor_entry)) == NULL) || (our_entry != NULL && (entries[1] = index_entry_dup(our_entry)) == NULL) || (their_entry != NULL && (entries[2] = index_entry_dup(their_entry)) == NULL)) return -1; for (i = 0; i < 3; i++) { if (entries[i] == NULL) continue; /* Make sure stage is correct */ entries[i]->flags = (entries[i]->flags & ~GIT_IDXENTRY_STAGEMASK) | ((i+1) << GIT_IDXENTRY_STAGESHIFT); if ((ret = index_insert(index, entries[i], 1)) < 0) goto on_error; } return 0; on_error: for (i = 0; i < 3; i++) { if (entries[i] != NULL) index_entry_free(entries[i]); } return ret; } static int index_conflict__get_byindex( const git_index_entry **ancestor_out, const git_index_entry **our_out, const git_index_entry **their_out, git_index *index, size_t n) { const git_index_entry *conflict_entry; const char *path = NULL; size_t count; int stage, len = 0; assert(ancestor_out && our_out && their_out && index); *ancestor_out = NULL; *our_out = NULL; *their_out = NULL; for (count = git_index_entrycount(index); n < count; ++n) { conflict_entry = git_vector_get(&index->entries, n); if (path && index->entries_cmp_path(conflict_entry->path, path) != 0) break; stage = GIT_IDXENTRY_STAGE(conflict_entry); path = conflict_entry->path; switch (stage) { case 3: *their_out = conflict_entry; len++; break; case 2: *our_out = conflict_entry; len++; break; case 1: *ancestor_out = conflict_entry; len++; break; default: break; }; } return len; } int git_index_conflict_get( const git_index_entry **ancestor_out, const git_index_entry **our_out, const git_index_entry **their_out, git_index *index, const char *path) { size_t pos; int len = 0; assert(ancestor_out && our_out && their_out && index && path); *ancestor_out = NULL; *our_out = NULL; *their_out = NULL; if (git_index_find(&pos, index, path) < 0) return GIT_ENOTFOUND; if ((len = index_conflict__get_byindex( ancestor_out, our_out, their_out, index, pos)) < 0) return len; else if (len == 0) return GIT_ENOTFOUND; return 0; } int git_index_conflict_remove(git_index *index, const char *path) { size_t pos, posmax; git_index_entry *conflict_entry; int error = 0; assert(index && path); if (git_index_find(&pos, index, path) < 0) return GIT_ENOTFOUND; posmax = git_index_entrycount(index); while (pos < posmax) { conflict_entry = git_vector_get(&index->entries, pos); if (index->entries_cmp_path(conflict_entry->path, path) != 0) break; if (GIT_IDXENTRY_STAGE(conflict_entry) == 0) { pos++; continue; } if ((error = git_vector_remove(&index->entries, pos)) < 0) return error; index_entry_free(conflict_entry); posmax--; } return 0; } static int index_conflicts_match(const git_vector *v, size_t idx) { git_index_entry *entry = git_vector_get(v, idx); if (GIT_IDXENTRY_STAGE(entry) > 0) { index_entry_free(entry); return 1; } return 0; } void git_index_conflict_cleanup(git_index *index) { assert(index); git_vector_remove_matching(&index->entries, index_conflicts_match); } int git_index_has_conflicts(const git_index *index) { size_t i; git_index_entry *entry; assert(index); git_vector_foreach(&index->entries, i, entry) { if (GIT_IDXENTRY_STAGE(entry) > 0) return 1; } return 0; } int git_index_conflict_iterator_new( git_index_conflict_iterator **iterator_out, git_index *index) { git_index_conflict_iterator *it = NULL; assert(iterator_out && index); it = git__calloc(1, sizeof(git_index_conflict_iterator)); GITERR_CHECK_ALLOC(it); it->index = index; *iterator_out = it; return 0; } int git_index_conflict_next( const git_index_entry **ancestor_out, const git_index_entry **our_out, const git_index_entry **their_out, git_index_conflict_iterator *iterator) { const git_index_entry *entry; int len; assert(ancestor_out && our_out && their_out && iterator); *ancestor_out = NULL; *our_out = NULL; *their_out = NULL; while (iterator->cur < iterator->index->entries.length) { entry = git_index_get_byindex(iterator->index, iterator->cur); if (git_index_entry_stage(entry) > 0) { if ((len = index_conflict__get_byindex( ancestor_out, our_out, their_out, iterator->index, iterator->cur)) < 0) return len; iterator->cur += len; return 0; } iterator->cur++; } return GIT_ITEROVER; } void git_index_conflict_iterator_free(git_index_conflict_iterator *iterator) { if (iterator == NULL) return; git__free(iterator); } unsigned int git_index_name_entrycount(git_index *index) { assert(index); return (unsigned int)index->names.length; } const git_index_name_entry *git_index_name_get_byindex( git_index *index, size_t n) { assert(index); git_vector_sort(&index->names); return git_vector_get(&index->names, n); } int git_index_name_add(git_index *index, const char *ancestor, const char *ours, const char *theirs) { git_index_name_entry *conflict_name; assert ((ancestor && ours) || (ancestor && theirs) || (ours && theirs)); conflict_name = git__calloc(1, sizeof(git_index_name_entry)); GITERR_CHECK_ALLOC(conflict_name); if (ancestor) { conflict_name->ancestor = git__strdup(ancestor); GITERR_CHECK_ALLOC(conflict_name->ancestor); } if (ours) { conflict_name->ours = git__strdup(ours); GITERR_CHECK_ALLOC(conflict_name->ours); } if (theirs) { conflict_name->theirs = git__strdup(theirs); GITERR_CHECK_ALLOC(conflict_name->theirs); } return git_vector_insert(&index->names, conflict_name); } void git_index_name_clear(git_index *index) { size_t i; git_index_name_entry *conflict_name; assert(index); git_vector_foreach(&index->names, i, conflict_name) { if (conflict_name->ancestor) git__free(conflict_name->ancestor); if (conflict_name->ours) git__free(conflict_name->ours); if (conflict_name->theirs) git__free(conflict_name->theirs); git__free(conflict_name); } git_vector_clear(&index->names); } unsigned int git_index_reuc_entrycount(git_index *index) { assert(index); return (unsigned int)index->reuc.length; } static int index_reuc_insert( git_index *index, git_index_reuc_entry *reuc, int replace) { git_index_reuc_entry **existing = NULL; size_t position; assert(index && reuc && reuc->path != NULL); if (!git_index_reuc_find(&position, index, reuc->path)) existing = (git_index_reuc_entry **)&index->reuc.contents[position]; if (!replace || !existing) return git_vector_insert(&index->reuc, reuc); /* exists, replace it */ git__free((*existing)->path); git__free(*existing); *existing = reuc; return 0; } int git_index_reuc_add(git_index *index, const char *path, int ancestor_mode, const git_oid *ancestor_oid, int our_mode, const git_oid *our_oid, int their_mode, const git_oid *their_oid) { git_index_reuc_entry *reuc = NULL; int error = 0; assert(index && path); if ((error = index_entry_reuc_init(&reuc, path, ancestor_mode, ancestor_oid, our_mode, our_oid, their_mode, their_oid)) < 0 || (error = index_reuc_insert(index, reuc, 1)) < 0) { index_entry_reuc_free(reuc); return error; } return error; } int git_index_reuc_find(size_t *at_pos, git_index *index, const char *path) { return git_vector_bsearch2(at_pos, &index->reuc, index->reuc_search, path); } const git_index_reuc_entry *git_index_reuc_get_bypath( git_index *index, const char *path) { size_t pos; assert(index && path); if (!index->reuc.length) return NULL; git_vector_sort(&index->reuc); if (git_index_reuc_find(&pos, index, path) < 0) return NULL; return git_vector_get(&index->reuc, pos); } const git_index_reuc_entry *git_index_reuc_get_byindex( git_index *index, size_t n) { assert(index); git_vector_sort(&index->reuc); return git_vector_get(&index->reuc, n); } int git_index_reuc_remove(git_index *index, size_t position) { int error; git_index_reuc_entry *reuc; git_vector_sort(&index->reuc); reuc = git_vector_get(&index->reuc, position); error = git_vector_remove(&index->reuc, position); if (!error) index_entry_reuc_free(reuc); return error; } void git_index_reuc_clear(git_index *index) { size_t i; git_index_reuc_entry *reuc; assert(index); git_vector_foreach(&index->reuc, i, reuc) { git__free(reuc->path); git__free(reuc); } git_vector_clear(&index->reuc); } static int index_error_invalid(const char *message) { giterr_set(GITERR_INDEX, "Invalid data in index - %s", message); return -1; } static int read_reuc(git_index *index, const char *buffer, size_t size) { const char *endptr; size_t len; int i; /* If called multiple times, the vector might already be initialized */ if (index->reuc._alloc_size == 0 && git_vector_init(&index->reuc, 16, reuc_cmp) < 0) return -1; while (size) { git_index_reuc_entry *lost; len = strlen(buffer) + 1; if (size <= len) return index_error_invalid("reading reuc entries"); lost = git__calloc(1, sizeof(git_index_reuc_entry)); GITERR_CHECK_ALLOC(lost); /* read NUL-terminated pathname for entry */ lost->path = git__strdup(buffer); GITERR_CHECK_ALLOC(lost->path); size -= len; buffer += len; /* read 3 ASCII octal numbers for stage entries */ for (i = 0; i < 3; i++) { int tmp; if (git__strtol32(&tmp, buffer, &endptr, 8) < 0 || !endptr || endptr == buffer || *endptr || (unsigned)tmp > UINT_MAX) return index_error_invalid("reading reuc entry stage"); lost->mode[i] = tmp; len = (endptr + 1) - buffer; if (size <= len) return index_error_invalid("reading reuc entry stage"); size -= len; buffer += len; } /* read up to 3 OIDs for stage entries */ for (i = 0; i < 3; i++) { if (!lost->mode[i]) continue; if (size < 20) return index_error_invalid("reading reuc entry oid"); git_oid_fromraw(&lost->oid[i], (const unsigned char *) buffer); size -= 20; buffer += 20; } /* entry was read successfully - insert into reuc vector */ if (git_vector_insert(&index->reuc, lost) < 0) return -1; } /* entries are guaranteed to be sorted on-disk */ index->reuc.sorted = 1; return 0; } static int read_conflict_names(git_index *index, const char *buffer, size_t size) { size_t len; /* This gets called multiple times, the vector might already be initialized */ if (index->names._alloc_size == 0 && git_vector_init(&index->names, 16, conflict_name_cmp) < 0) return -1; #define read_conflict_name(ptr) \ len = strlen(buffer) + 1; \ if (size < len) \ return index_error_invalid("reading conflict name entries"); \ \ if (len == 1) \ ptr = NULL; \ else { \ ptr = git__malloc(len); \ GITERR_CHECK_ALLOC(ptr); \ memcpy(ptr, buffer, len); \ } \ \ buffer += len; \ size -= len; while (size) { git_index_name_entry *conflict_name = git__calloc(1, sizeof(git_index_name_entry)); GITERR_CHECK_ALLOC(conflict_name); read_conflict_name(conflict_name->ancestor); read_conflict_name(conflict_name->ours); read_conflict_name(conflict_name->theirs); if (git_vector_insert(&index->names, conflict_name) < 0) return -1; } #undef read_conflict_name /* entries are guaranteed to be sorted on-disk */ index->names.sorted = 1; return 0; } static size_t read_entry(git_index_entry *dest, const void *buffer, size_t buffer_size) { size_t path_length, entry_size; uint16_t flags_raw; const char *path_ptr; const struct entry_short *source = buffer; if (INDEX_FOOTER_SIZE + minimal_entry_size > buffer_size) return 0; memset(dest, 0x0, sizeof(git_index_entry)); dest->ctime.seconds = (git_time_t)ntohl(source->ctime.seconds); dest->ctime.nanoseconds = ntohl(source->ctime.nanoseconds); dest->mtime.seconds = (git_time_t)ntohl(source->mtime.seconds); dest->mtime.nanoseconds = ntohl(source->mtime.nanoseconds); dest->dev = ntohl(source->dev); dest->ino = ntohl(source->ino); dest->mode = ntohl(source->mode); dest->uid = ntohl(source->uid); dest->gid = ntohl(source->gid); dest->file_size = ntohl(source->file_size); git_oid_cpy(&dest->oid, &source->oid); dest->flags = ntohs(source->flags); if (dest->flags & GIT_IDXENTRY_EXTENDED) { const struct entry_long *source_l = (const struct entry_long *)source; path_ptr = source_l->path; flags_raw = ntohs(source_l->flags_extended); memcpy(&dest->flags_extended, &flags_raw, 2); } else path_ptr = source->path; path_length = dest->flags & GIT_IDXENTRY_NAMEMASK; /* if this is a very long string, we must find its * real length without overflowing */ if (path_length == 0xFFF) { const char *path_end; path_end = memchr(path_ptr, '\0', buffer_size); if (path_end == NULL) return 0; path_length = path_end - path_ptr; } if (dest->flags & GIT_IDXENTRY_EXTENDED) entry_size = long_entry_size(path_length); else entry_size = short_entry_size(path_length); if (INDEX_FOOTER_SIZE + entry_size > buffer_size) return 0; dest->path = git__strdup(path_ptr); assert(dest->path); return entry_size; } static int read_header(struct index_header *dest, const void *buffer) { const struct index_header *source = buffer; dest->signature = ntohl(source->signature); if (dest->signature != INDEX_HEADER_SIG) return index_error_invalid("incorrect header signature"); dest->version = ntohl(source->version); if (dest->version != INDEX_VERSION_NUMBER_EXT && dest->version != INDEX_VERSION_NUMBER) return index_error_invalid("incorrect header version"); dest->entry_count = ntohl(source->entry_count); return 0; } static size_t read_extension(git_index *index, const char *buffer, size_t buffer_size) { const struct index_extension *source; struct index_extension dest; size_t total_size; source = (const struct index_extension *)(buffer); memcpy(dest.signature, source->signature, 4); dest.extension_size = ntohl(source->extension_size); total_size = dest.extension_size + sizeof(struct index_extension); if (buffer_size < total_size || buffer_size - total_size < INDEX_FOOTER_SIZE) return 0; /* optional extension */ if (dest.signature[0] >= 'A' && dest.signature[0] <= 'Z') { /* tree cache */ if (memcmp(dest.signature, INDEX_EXT_TREECACHE_SIG, 4) == 0) { if (git_tree_cache_read(&index->tree, buffer + 8, dest.extension_size) < 0) return 0; } else if (memcmp(dest.signature, INDEX_EXT_UNMERGED_SIG, 4) == 0) { if (read_reuc(index, buffer + 8, dest.extension_size) < 0) return 0; } else if (memcmp(dest.signature, INDEX_EXT_CONFLICT_NAME_SIG, 4) == 0) { if (read_conflict_names(index, buffer + 8, dest.extension_size) < 0) return 0; } /* else, unsupported extension. We cannot parse this, but we can skip * it by returning `total_size */ } else { /* we cannot handle non-ignorable extensions; * in fact they aren't even defined in the standard */ return 0; } return total_size; } static int parse_index(git_index *index, const char *buffer, size_t buffer_size) { unsigned int i; struct index_header header = { 0 }; git_oid checksum_calculated, checksum_expected; #define seek_forward(_increase) { \ if (_increase >= buffer_size) \ return index_error_invalid("ran out of data while parsing"); \ buffer += _increase; \ buffer_size -= _increase;\ } if (buffer_size < INDEX_HEADER_SIZE + INDEX_FOOTER_SIZE) return index_error_invalid("insufficient buffer space"); /* Precalculate the SHA1 of the files's contents -- we'll match it to * the provided SHA1 in the footer */ git_hash_buf(&checksum_calculated, buffer, buffer_size - INDEX_FOOTER_SIZE); /* Parse header */ if (read_header(&header, buffer) < 0) return -1; seek_forward(INDEX_HEADER_SIZE); git_vector_clear(&index->entries); /* Parse all the entries */ for (i = 0; i < header.entry_count && buffer_size > INDEX_FOOTER_SIZE; ++i) { size_t entry_size; git_index_entry *entry; entry = git__malloc(sizeof(git_index_entry)); GITERR_CHECK_ALLOC(entry); entry_size = read_entry(entry, buffer, buffer_size); /* 0 bytes read means an object corruption */ if (entry_size == 0) return index_error_invalid("invalid entry"); if (git_vector_insert(&index->entries, entry) < 0) return -1; seek_forward(entry_size); } if (i != header.entry_count) return index_error_invalid("header entries changed while parsing"); /* There's still space for some extensions! */ while (buffer_size > INDEX_FOOTER_SIZE) { size_t extension_size; extension_size = read_extension(index, buffer, buffer_size); /* see if we have read any bytes from the extension */ if (extension_size == 0) return index_error_invalid("extension is truncated"); seek_forward(extension_size); } if (buffer_size != INDEX_FOOTER_SIZE) return index_error_invalid("buffer size does not match index footer size"); /* 160-bit SHA-1 over the content of the index file before this checksum. */ git_oid_fromraw(&checksum_expected, (const unsigned char *)buffer); if (git_oid__cmp(&checksum_calculated, &checksum_expected) != 0) return index_error_invalid("calculated checksum does not match expected"); #undef seek_forward /* Entries are stored case-sensitively on disk. */ index->entries.sorted = !index->ignore_case; git_vector_sort(&index->entries); return 0; } static bool is_index_extended(git_index *index) { size_t i, extended; git_index_entry *entry; extended = 0; git_vector_foreach(&index->entries, i, entry) { entry->flags &= ~GIT_IDXENTRY_EXTENDED; if (entry->flags_extended & GIT_IDXENTRY_EXTENDED_FLAGS) { extended++; entry->flags |= GIT_IDXENTRY_EXTENDED; } } return (extended > 0); } static int write_disk_entry(git_filebuf *file, git_index_entry *entry) { void *mem = NULL; struct entry_short *ondisk; size_t path_len, disk_size; char *path; path_len = strlen(entry->path); if (entry->flags & GIT_IDXENTRY_EXTENDED) disk_size = long_entry_size(path_len); else disk_size = short_entry_size(path_len); if (git_filebuf_reserve(file, &mem, disk_size) < 0) return -1; ondisk = (struct entry_short *)mem; memset(ondisk, 0x0, disk_size); /** * Yes, we have to truncate. * * The on-disk format for Index entries clearly defines * the time and size fields to be 4 bytes each -- so even if * we store these values with 8 bytes on-memory, they must * be truncated to 4 bytes before writing to disk. * * In 2038 I will be either too dead or too rich to care about this */ ondisk->ctime.seconds = htonl((uint32_t)entry->ctime.seconds); ondisk->mtime.seconds = htonl((uint32_t)entry->mtime.seconds); ondisk->ctime.nanoseconds = htonl(entry->ctime.nanoseconds); ondisk->mtime.nanoseconds = htonl(entry->mtime.nanoseconds); ondisk->dev = htonl(entry->dev); ondisk->ino = htonl(entry->ino); ondisk->mode = htonl(entry->mode); ondisk->uid = htonl(entry->uid); ondisk->gid = htonl(entry->gid); ondisk->file_size = htonl((uint32_t)entry->file_size); git_oid_cpy(&ondisk->oid, &entry->oid); ondisk->flags = htons(entry->flags); if (entry->flags & GIT_IDXENTRY_EXTENDED) { struct entry_long *ondisk_ext; ondisk_ext = (struct entry_long *)ondisk; ondisk_ext->flags_extended = htons(entry->flags_extended); path = ondisk_ext->path; } else path = ondisk->path; memcpy(path, entry->path, path_len); return 0; } static int write_entries(git_index *index, git_filebuf *file) { int error = 0; size_t i; git_vector case_sorted; git_index_entry *entry; git_vector *out = &index->entries; /* If index->entries is sorted case-insensitively, then we need * to re-sort it case-sensitively before writing */ if (index->ignore_case) { git_vector_dup(&case_sorted, &index->entries, index_cmp); git_vector_sort(&case_sorted); out = &case_sorted; } git_vector_foreach(out, i, entry) if ((error = write_disk_entry(file, entry)) < 0) break; if (index->ignore_case) git_vector_free(&case_sorted); return error; } static int write_extension(git_filebuf *file, struct index_extension *header, git_buf *data) { struct index_extension ondisk; int error = 0; memset(&ondisk, 0x0, sizeof(struct index_extension)); memcpy(&ondisk, header, 4); ondisk.extension_size = htonl(header->extension_size); if ((error = git_filebuf_write(file, &ondisk, sizeof(struct index_extension))) == 0) error = git_filebuf_write(file, data->ptr, data->size); return error; } static int create_name_extension_data(git_buf *name_buf, git_index_name_entry *conflict_name) { int error = 0; if (conflict_name->ancestor == NULL) error = git_buf_put(name_buf, "\0", 1); else error = git_buf_put(name_buf, conflict_name->ancestor, strlen(conflict_name->ancestor) + 1); if (error != 0) goto on_error; if (conflict_name->ours == NULL) error = git_buf_put(name_buf, "\0", 1); else error = git_buf_put(name_buf, conflict_name->ours, strlen(conflict_name->ours) + 1); if (error != 0) goto on_error; if (conflict_name->theirs == NULL) error = git_buf_put(name_buf, "\0", 1); else error = git_buf_put(name_buf, conflict_name->theirs, strlen(conflict_name->theirs) + 1); on_error: return error; } static int write_name_extension(git_index *index, git_filebuf *file) { git_buf name_buf = GIT_BUF_INIT; git_vector *out = &index->names; git_index_name_entry *conflict_name; struct index_extension extension; size_t i; int error = 0; git_vector_foreach(out, i, conflict_name) { if ((error = create_name_extension_data(&name_buf, conflict_name)) < 0) goto done; } memset(&extension, 0x0, sizeof(struct index_extension)); memcpy(&extension.signature, INDEX_EXT_CONFLICT_NAME_SIG, 4); extension.extension_size = (uint32_t)name_buf.size; error = write_extension(file, &extension, &name_buf); git_buf_free(&name_buf); done: return error; } static int create_reuc_extension_data(git_buf *reuc_buf, git_index_reuc_entry *reuc) { int i; int error = 0; if ((error = git_buf_put(reuc_buf, reuc->path, strlen(reuc->path) + 1)) < 0) return error; for (i = 0; i < 3; i++) { if ((error = git_buf_printf(reuc_buf, "%o", reuc->mode[i])) < 0 || (error = git_buf_put(reuc_buf, "\0", 1)) < 0) return error; } for (i = 0; i < 3; i++) { if (reuc->mode[i] && (error = git_buf_put(reuc_buf, (char *)&reuc->oid[i].id, GIT_OID_RAWSZ)) < 0) return error; } return 0; } static int write_reuc_extension(git_index *index, git_filebuf *file) { git_buf reuc_buf = GIT_BUF_INIT; git_vector *out = &index->reuc; git_index_reuc_entry *reuc; struct index_extension extension; size_t i; int error = 0; git_vector_foreach(out, i, reuc) { if ((error = create_reuc_extension_data(&reuc_buf, reuc)) < 0) goto done; } memset(&extension, 0x0, sizeof(struct index_extension)); memcpy(&extension.signature, INDEX_EXT_UNMERGED_SIG, 4); extension.extension_size = (uint32_t)reuc_buf.size; error = write_extension(file, &extension, &reuc_buf); git_buf_free(&reuc_buf); done: return error; } static int write_index(git_index *index, git_filebuf *file) { git_oid hash_final; struct index_header header; bool is_extended; assert(index && file); is_extended = is_index_extended(index); header.signature = htonl(INDEX_HEADER_SIG); header.version = htonl(is_extended ? INDEX_VERSION_NUMBER_EXT : INDEX_VERSION_NUMBER); header.entry_count = htonl((uint32_t)index->entries.length); if (git_filebuf_write(file, &header, sizeof(struct index_header)) < 0) return -1; if (write_entries(index, file) < 0) return -1; /* TODO: write tree cache extension */ /* write the rename conflict extension */ if (index->names.length > 0 && write_name_extension(index, file) < 0) return -1; /* write the reuc extension */ if (index->reuc.length > 0 && write_reuc_extension(index, file) < 0) return -1; /* get out the hash for all the contents we've appended to the file */ git_filebuf_hash(&hash_final, file); /* write it at the end of the file */ return git_filebuf_write(file, hash_final.id, GIT_OID_RAWSZ); } int git_index_entry_stage(const git_index_entry *entry) { return GIT_IDXENTRY_STAGE(entry); } typedef struct read_tree_data { git_index *index; git_vector *old_entries; } read_tree_data; static int read_tree_cb( const char *root, const git_tree_entry *tentry, void *payload) { read_tree_data *data = payload; git_index_entry *entry = NULL, *old_entry; git_buf path = GIT_BUF_INIT; if (git_tree_entry__is_tree(tentry)) return 0; if (git_buf_joinpath(&path, root, tentry->filename) < 0) return -1; entry = git__calloc(1, sizeof(git_index_entry)); GITERR_CHECK_ALLOC(entry); entry->mode = tentry->attr; entry->oid = tentry->oid; /* look for corresponding old entry and copy data to new entry */ if (data->old_entries) { size_t pos; struct entry_srch_key skey; skey.path = path.ptr; skey.stage = 0; if (!git_vector_bsearch2( &pos, data->old_entries, data->index->entries_search, &skey) && (old_entry = git_vector_get(data->old_entries, pos)) != NULL && entry->mode == old_entry->mode && git_oid_equal(&entry->oid, &old_entry->oid)) { memcpy(entry, old_entry, sizeof(*entry)); entry->flags_extended = 0; } } if (path.size < GIT_IDXENTRY_NAMEMASK) entry->flags = path.size & GIT_IDXENTRY_NAMEMASK; else entry->flags = GIT_IDXENTRY_NAMEMASK; entry->path = git_buf_detach(&path); git_buf_free(&path); if (git_vector_insert(&data->index->entries, entry) < 0) { index_entry_free(entry); return -1; } return 0; } int git_index_read_tree(git_index *index, const git_tree *tree) { int error = 0; git_vector entries = GIT_VECTOR_INIT; read_tree_data data; git_vector_sort(&index->entries); git_vector_set_cmp(&entries, index->entries._cmp); git_vector_swap(&entries, &index->entries); git_index_clear(index); data.index = index; data.old_entries = &entries; error = git_tree_walk(tree, GIT_TREEWALK_POST, read_tree_cb, &data); index_entries_free(&entries); git_vector_free(&entries); git_vector_sort(&index->entries); return error; } git_repository *git_index_owner(const git_index *index) { return INDEX_OWNER(index); } int git_index_add_all( git_index *index, const git_strarray *paths, unsigned int flags, git_index_matched_path_cb cb, void *payload) { int error; git_repository *repo; git_iterator *wditer = NULL; const git_index_entry *wd = NULL; git_index_entry *entry; git_pathspec_context ps; const char *match; size_t existing; bool no_fnmatch = (flags & GIT_INDEX_ADD_DISABLE_PATHSPEC_MATCH) != 0; int ignorecase; git_oid blobid; assert(index); if (INDEX_OWNER(index) == NULL) return create_index_error(-1, "Could not add paths to index. " "Index is not backed up by an existing repository."); repo = INDEX_OWNER(index); if ((error = git_repository__ensure_not_bare(repo, "index add all")) < 0) return error; if (git_repository__cvar(&ignorecase, repo, GIT_CVAR_IGNORECASE) < 0) return -1; if ((error = git_pathspec_context_init(&ps, paths)) < 0) return error; /* optionally check that pathspec doesn't mention any ignored files */ if ((flags & GIT_INDEX_ADD_CHECK_PATHSPEC) != 0 && (flags & GIT_INDEX_ADD_FORCE) == 0 && (error = git_ignore__check_pathspec_for_exact_ignores( repo, &ps.pathspec, no_fnmatch)) < 0) goto cleanup; if ((error = git_iterator_for_workdir( &wditer, repo, 0, ps.prefix, ps.prefix)) < 0) goto cleanup; while (!(error = git_iterator_advance(&wd, wditer))) { /* check if path actually matches */ if (!git_pathspec_match_path( &ps.pathspec, wd->path, no_fnmatch, ignorecase, &match)) continue; /* skip ignored items that are not already in the index */ if ((flags & GIT_INDEX_ADD_FORCE) == 0 && git_iterator_current_is_ignored(wditer) && index_find(&existing, index, wd->path, 0) < 0) continue; /* issue notification callback if requested */ if (cb && (error = cb(wd->path, match, payload)) != 0) { if (error > 0) /* return > 0 means skip this one */ continue; if (error < 0) { /* return < 0 means abort */ giterr_clear(); error = GIT_EUSER; break; } } /* TODO: Should we check if the file on disk is already an exact * match to the file in the index and skip this work if it is? */ /* write the blob to disk and get the oid */ if ((error = git_blob_create_fromworkdir(&blobid, repo, wd->path)) < 0) break; /* make the new entry to insert */ if ((entry = index_entry_dup(wd)) == NULL) { error = -1; break; } entry->oid = blobid; /* add working directory item to index */ if ((error = index_insert(index, entry, 1)) < 0) { index_entry_free(entry); break; } git_tree_cache_invalidate_path(index->tree, wd->path); /* add implies conflict resolved, move conflict entries to REUC */ if ((error = index_conflict_to_reuc(index, wd->path)) < 0) { if (error != GIT_ENOTFOUND) break; giterr_clear(); } } if (error == GIT_ITEROVER) error = 0; cleanup: git_iterator_free(wditer); git_pathspec_context_free(&ps); return error; } enum { INDEX_ACTION_NONE = 0, INDEX_ACTION_UPDATE = 1, INDEX_ACTION_REMOVE = 2, }; static int index_apply_to_all( git_index *index, int action, const git_strarray *paths, git_index_matched_path_cb cb, void *payload) { int error = 0; size_t i; git_pathspec_context ps; const char *match; git_buf path = GIT_BUF_INIT; assert(index); if ((error = git_pathspec_context_init(&ps, paths)) < 0) return error; git_vector_sort(&index->entries); for (i = 0; !error && i < index->entries.length; ++i) { git_index_entry *entry = git_vector_get(&index->entries, i); /* check if path actually matches */ if (!git_pathspec_match_path( &ps.pathspec, entry->path, false, index->ignore_case, &match)) continue; /* issue notification callback if requested */ if (cb && (error = cb(entry->path, match, payload)) != 0) { if (error > 0) { /* return > 0 means skip this one */ error = 0; continue; } if (error < 0) { /* return < 0 means abort */ giterr_clear(); error = GIT_EUSER; break; } } /* index manipulation may alter entry, so don't depend on it */ if ((error = git_buf_sets(&path, entry->path)) < 0) break; switch (action) { case INDEX_ACTION_NONE: break; case INDEX_ACTION_UPDATE: error = git_index_add_bypath(index, path.ptr); if (error == GIT_ENOTFOUND) { giterr_clear(); error = git_index_remove_bypath(index, path.ptr); if (!error) /* back up foreach if we removed this */ i--; } break; case INDEX_ACTION_REMOVE: if (!(error = git_index_remove_bypath(index, path.ptr))) i--; /* back up foreach if we removed this */ break; default: giterr_set(GITERR_INVALID, "Unknown index action %d", action); error = -1; break; } } git_buf_free(&path); git_pathspec_context_free(&ps); return error; } int git_index_remove_all( git_index *index, const git_strarray *pathspec, git_index_matched_path_cb cb, void *payload) { return index_apply_to_all( index, INDEX_ACTION_REMOVE, pathspec, cb, payload); } int git_index_update_all( git_index *index, const git_strarray *pathspec, git_index_matched_path_cb cb, void *payload) { return index_apply_to_all( index, INDEX_ACTION_UPDATE, pathspec, cb, payload); } libgit2-0.19.0/src/index.h000066400000000000000000000025121216214232500152020ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #ifndef INCLUDE_index_h__ #define INCLUDE_index_h__ #include "fileops.h" #include "filebuf.h" #include "vector.h" #include "tree-cache.h" #include "git2/odb.h" #include "git2/index.h" #define GIT_INDEX_FILE "index" #define GIT_INDEX_FILE_MODE 0666 struct git_index { git_refcount rc; char *index_file_path; git_futils_filestamp stamp; git_vector entries; unsigned int on_disk:1; unsigned int ignore_case:1; unsigned int distrust_filemode:1; unsigned int no_symlinks:1; git_tree_cache *tree; git_vector names; git_vector reuc; git_vector_cmp entries_cmp_path; git_vector_cmp entries_search; git_vector_cmp entries_search_path; git_vector_cmp reuc_search; }; struct git_index_conflict_iterator { git_index *index; size_t cur; }; extern void git_index_entry__init_from_stat(git_index_entry *entry, struct stat *st); extern size_t git_index__prefix_position(git_index *index, const char *path); extern int git_index_entry__cmp(const void *a, const void *b); extern int git_index_entry__cmp_icase(const void *a, const void *b); extern void git_index__set_ignore_case(git_index *index, bool ignore_case); #endif libgit2-0.19.0/src/indexer.c000066400000000000000000000415231216214232500155310ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #include #include "git2/indexer.h" #include "git2/object.h" #include "common.h" #include "pack.h" #include "mwindow.h" #include "posix.h" #include "pack.h" #include "filebuf.h" #include "oid.h" #include "oidmap.h" #define UINT31_MAX (0x7FFFFFFF) struct entry { git_oid oid; uint32_t crc; uint32_t offset; uint64_t offset_long; }; struct git_indexer_stream { unsigned int parsed_header :1, opened_pack :1, have_stream :1, have_delta :1; struct git_pack_file *pack; git_filebuf pack_file; git_off_t off; git_off_t entry_start; git_packfile_stream stream; size_t nr_objects; git_vector objects; git_vector deltas; unsigned int fanout[256]; git_hash_ctx hash_ctx; git_oid hash; git_transfer_progress_callback progress_cb; void *progress_payload; char objbuf[8*1024]; }; struct delta_info { git_off_t delta_off; }; const git_oid *git_indexer_stream_hash(const git_indexer_stream *idx) { return &idx->hash; } static int open_pack(struct git_pack_file **out, const char *filename) { struct git_pack_file *pack; if (git_packfile_alloc(&pack, filename) < 0) return -1; if ((pack->mwf.fd = p_open(pack->pack_name, O_RDONLY)) < 0) { giterr_set(GITERR_OS, "Failed to open packfile."); git_packfile_free(pack); return -1; } *out = pack; return 0; } static int parse_header(struct git_pack_header *hdr, struct git_pack_file *pack) { int error; /* Verify we recognize this pack file format. */ if ((error = p_read(pack->mwf.fd, hdr, sizeof(*hdr))) < 0) { giterr_set(GITERR_OS, "Failed to read in pack header"); return error; } if (hdr->hdr_signature != ntohl(PACK_SIGNATURE)) { giterr_set(GITERR_INDEXER, "Wrong pack signature"); return -1; } if (!pack_version_ok(hdr->hdr_version)) { giterr_set(GITERR_INDEXER, "Wrong pack version"); return -1; } return 0; } static int objects_cmp(const void *a, const void *b) { const struct entry *entrya = a; const struct entry *entryb = b; return git_oid__cmp(&entrya->oid, &entryb->oid); } int git_indexer_stream_new( git_indexer_stream **out, const char *prefix, git_transfer_progress_callback progress_cb, void *progress_payload) { git_indexer_stream *idx; git_buf path = GIT_BUF_INIT; static const char suff[] = "/pack"; int error; idx = git__calloc(1, sizeof(git_indexer_stream)); GITERR_CHECK_ALLOC(idx); idx->progress_cb = progress_cb; idx->progress_payload = progress_payload; error = git_buf_joinpath(&path, prefix, suff); if (error < 0) goto cleanup; error = git_filebuf_open(&idx->pack_file, path.ptr, GIT_FILEBUF_TEMPORARY | GIT_FILEBUF_DO_NOT_BUFFER); git_buf_free(&path); if (error < 0) goto cleanup; *out = idx; return 0; cleanup: git_buf_free(&path); git_filebuf_cleanup(&idx->pack_file); git__free(idx); return -1; } /* Try to store the delta so we can try to resolve it later */ static int store_delta(git_indexer_stream *idx) { struct delta_info *delta; delta = git__calloc(1, sizeof(struct delta_info)); GITERR_CHECK_ALLOC(delta); delta->delta_off = idx->entry_start; if (git_vector_insert(&idx->deltas, delta) < 0) return -1; return 0; } static void hash_header(git_hash_ctx *ctx, git_off_t len, git_otype type) { char buffer[64]; size_t hdrlen; hdrlen = git_odb__format_object_header(buffer, sizeof(buffer), (size_t)len, type); git_hash_update(ctx, buffer, hdrlen); } static int hash_object_stream(git_indexer_stream *idx, git_packfile_stream *stream) { ssize_t read; assert(idx && stream); do { if ((read = git_packfile_stream_read(stream, idx->objbuf, sizeof(idx->objbuf))) < 0) break; git_hash_update(&idx->hash_ctx, idx->objbuf, read); } while (read > 0); if (read < 0) return (int)read; return 0; } /* In order to create the packfile stream, we need to skip over the delta base description */ static int advance_delta_offset(git_indexer_stream *idx, git_otype type) { git_mwindow *w = NULL; assert(type == GIT_OBJ_REF_DELTA || type == GIT_OBJ_OFS_DELTA); if (type == GIT_OBJ_REF_DELTA) { idx->off += GIT_OID_RAWSZ; } else { git_off_t base_off = get_delta_base(idx->pack, &w, &idx->off, type, idx->entry_start); git_mwindow_close(&w); if (base_off < 0) return (int)base_off; } return 0; } /* Read from the stream and discard any output */ static int read_object_stream(git_indexer_stream *idx, git_packfile_stream *stream) { ssize_t read; assert(stream); do { read = git_packfile_stream_read(stream, idx->objbuf, sizeof(idx->objbuf)); } while (read > 0); if (read < 0) return (int)read; return 0; } static int crc_object(uint32_t *crc_out, git_mwindow_file *mwf, git_off_t start, git_off_t size) { void *ptr; uint32_t crc; unsigned int left, len; git_mwindow *w = NULL; crc = crc32(0L, Z_NULL, 0); while (size) { ptr = git_mwindow_open(mwf, &w, start, (size_t)size, &left); if (ptr == NULL) return -1; len = min(left, (unsigned int)size); crc = crc32(crc, ptr, len); size -= len; start += len; git_mwindow_close(&w); } *crc_out = htonl(crc); return 0; } static int store_object(git_indexer_stream *idx) { int i, error; khiter_t k; git_oid oid; struct entry *entry; git_off_t entry_size; struct git_pack_entry *pentry; git_hash_ctx *ctx = &idx->hash_ctx; git_off_t entry_start = idx->entry_start; entry = git__calloc(1, sizeof(*entry)); GITERR_CHECK_ALLOC(entry); pentry = git__calloc(1, sizeof(struct git_pack_entry)); GITERR_CHECK_ALLOC(pentry); git_hash_final(&oid, ctx); entry_size = idx->off - entry_start; if (entry_start > UINT31_MAX) { entry->offset = UINT32_MAX; entry->offset_long = entry_start; } else { entry->offset = (uint32_t)entry_start; } git_oid_cpy(&pentry->sha1, &oid); pentry->offset = entry_start; k = kh_put(oid, idx->pack->idx_cache, &pentry->sha1, &error); if (!error) { git__free(pentry); goto on_error; } kh_value(idx->pack->idx_cache, k) = pentry; git_oid_cpy(&entry->oid, &oid); if (crc_object(&entry->crc, &idx->pack->mwf, entry_start, entry_size) < 0) goto on_error; /* Add the object to the list */ if (git_vector_insert(&idx->objects, entry) < 0) goto on_error; for (i = oid.id[0]; i < 256; ++i) { idx->fanout[i]++; } return 0; on_error: git__free(entry); return -1; } static int hash_and_save(git_indexer_stream *idx, git_rawobj *obj, git_off_t entry_start) { int i, error; khiter_t k; git_oid oid; size_t entry_size; struct entry *entry; struct git_pack_entry *pentry; entry = git__calloc(1, sizeof(*entry)); GITERR_CHECK_ALLOC(entry); if (entry_start > UINT31_MAX) { entry->offset = UINT32_MAX; entry->offset_long = entry_start; } else { entry->offset = (uint32_t)entry_start; } /* FIXME: Parse the object instead of hashing it */ if (git_odb__hashobj(&oid, obj) < 0) { giterr_set(GITERR_INDEXER, "Failed to hash object"); return -1; } pentry = git__calloc(1, sizeof(struct git_pack_entry)); GITERR_CHECK_ALLOC(pentry); git_oid_cpy(&pentry->sha1, &oid); pentry->offset = entry_start; k = kh_put(oid, idx->pack->idx_cache, &pentry->sha1, &error); if (!error) { git__free(pentry); goto on_error; } kh_value(idx->pack->idx_cache, k) = pentry; git_oid_cpy(&entry->oid, &oid); entry->crc = crc32(0L, Z_NULL, 0); entry_size = (size_t)(idx->off - entry_start); if (crc_object(&entry->crc, &idx->pack->mwf, entry_start, entry_size) < 0) goto on_error; /* Add the object to the list */ if (git_vector_insert(&idx->objects, entry) < 0) goto on_error; for (i = oid.id[0]; i < 256; ++i) { idx->fanout[i]++; } return 0; on_error: git__free(entry); git__free(obj->data); return -1; } static int do_progress_callback(git_indexer_stream *idx, git_transfer_progress *stats) { if (!idx->progress_cb) return 0; return idx->progress_cb(stats, idx->progress_payload); } int git_indexer_stream_add(git_indexer_stream *idx, const void *data, size_t size, git_transfer_progress *stats) { int error = -1; struct git_pack_header hdr; size_t processed; git_mwindow_file *mwf = &idx->pack->mwf; assert(idx && data && stats); processed = stats->indexed_objects; if (git_filebuf_write(&idx->pack_file, data, size) < 0) return -1; /* Make sure we set the new size of the pack */ if (idx->opened_pack) { idx->pack->mwf.size += size; } else { if (open_pack(&idx->pack, idx->pack_file.path_lock) < 0) return -1; idx->opened_pack = 1; mwf = &idx->pack->mwf; if (git_mwindow_file_register(&idx->pack->mwf) < 0) return -1; } if (!idx->parsed_header) { unsigned int total_objects; if ((unsigned)idx->pack->mwf.size < sizeof(hdr)) return 0; if (parse_header(&hdr, idx->pack) < 0) return -1; idx->parsed_header = 1; idx->nr_objects = ntohl(hdr.hdr_entries); idx->off = sizeof(struct git_pack_header); /* for now, limit to 2^32 objects */ assert(idx->nr_objects == (size_t)((unsigned int)idx->nr_objects)); if (idx->nr_objects == (size_t)((unsigned int)idx->nr_objects)) total_objects = (unsigned int)idx->nr_objects; else total_objects = UINT_MAX; idx->pack->idx_cache = git_oidmap_alloc(); GITERR_CHECK_ALLOC(idx->pack->idx_cache); idx->pack->has_cache = 1; if (git_vector_init(&idx->objects, total_objects, objects_cmp) < 0) return -1; if (git_vector_init(&idx->deltas, total_objects / 2, NULL) < 0) return -1; stats->received_objects = 0; processed = stats->indexed_objects = 0; stats->total_objects = total_objects; do_progress_callback(idx, stats); } /* Now that we have data in the pack, let's try to parse it */ /* As the file grows any windows we try to use will be out of date */ git_mwindow_free_all(mwf); while (processed < idx->nr_objects) { git_packfile_stream *stream = &idx->stream; git_off_t entry_start = idx->off; size_t entry_size; git_otype type; git_mwindow *w = NULL; if (idx->pack->mwf.size <= idx->off + 20) return 0; if (!idx->have_stream) { error = git_packfile_unpack_header(&entry_size, &type, mwf, &w, &idx->off); if (error == GIT_EBUFS) { idx->off = entry_start; return 0; } if (error < 0) return -1; git_mwindow_close(&w); idx->entry_start = entry_start; git_hash_ctx_init(&idx->hash_ctx); if (type == GIT_OBJ_REF_DELTA || type == GIT_OBJ_OFS_DELTA) { error = advance_delta_offset(idx, type); if (error == GIT_EBUFS) { idx->off = entry_start; return 0; } if (error < 0) return -1; idx->have_delta = 1; } else { idx->have_delta = 0; hash_header(&idx->hash_ctx, entry_size, type); } idx->have_stream = 1; if (git_packfile_stream_open(stream, idx->pack, idx->off) < 0) goto on_error; } if (idx->have_delta) { error = read_object_stream(idx, stream); } else { error = hash_object_stream(idx, stream); } idx->off = stream->curpos; if (error == GIT_EBUFS) return 0; /* We want to free the stream reasorces no matter what here */ idx->have_stream = 0; git_packfile_stream_free(stream); if (error < 0) goto on_error; if (idx->have_delta) { error = store_delta(idx); } else { error = store_object(idx); } if (error < 0) goto on_error; if (!idx->have_delta) { stats->indexed_objects = (unsigned int)++processed; } stats->received_objects++; if (do_progress_callback(idx, stats) != 0) { error = GIT_EUSER; goto on_error; } } return 0; on_error: git_mwindow_free_all(mwf); return error; } static int index_path_stream(git_buf *path, git_indexer_stream *idx, const char *suffix) { const char prefix[] = "pack-"; size_t slash = (size_t)path->size; /* search backwards for '/' */ while (slash > 0 && path->ptr[slash - 1] != '/') slash--; if (git_buf_grow(path, slash + 1 + strlen(prefix) + GIT_OID_HEXSZ + strlen(suffix) + 1) < 0) return -1; git_buf_truncate(path, slash); git_buf_puts(path, prefix); git_oid_fmt(path->ptr + git_buf_len(path), &idx->hash); path->size += GIT_OID_HEXSZ; git_buf_puts(path, suffix); return git_buf_oom(path) ? -1 : 0; } static int resolve_deltas(git_indexer_stream *idx, git_transfer_progress *stats) { unsigned int i; struct delta_info *delta; git_vector_foreach(&idx->deltas, i, delta) { git_rawobj obj; idx->off = delta->delta_off; if (git_packfile_unpack(&obj, idx->pack, &idx->off) < 0) return -1; if (hash_and_save(idx, &obj, delta->delta_off) < 0) return -1; git__free(obj.data); stats->indexed_objects++; do_progress_callback(idx, stats); } return 0; } int git_indexer_stream_finalize(git_indexer_stream *idx, git_transfer_progress *stats) { git_mwindow *w = NULL; unsigned int i, long_offsets = 0, left; struct git_pack_idx_header hdr; git_buf filename = GIT_BUF_INIT; struct entry *entry; void *packfile_hash; git_oid file_hash; git_hash_ctx ctx; git_filebuf index_file = {0}; if (git_hash_ctx_init(&ctx) < 0) return -1; /* Test for this before resolve_deltas(), as it plays with idx->off */ if (idx->off < idx->pack->mwf.size - GIT_OID_RAWSZ) { giterr_set(GITERR_INDEXER, "Indexing error: unexpected data at the end of the pack"); return -1; } if (idx->deltas.length > 0) if (resolve_deltas(idx, stats) < 0) return -1; if (stats->indexed_objects != stats->total_objects) { giterr_set(GITERR_INDEXER, "Indexing error: early EOF"); return -1; } git_vector_sort(&idx->objects); git_buf_sets(&filename, idx->pack->pack_name); git_buf_truncate(&filename, filename.size - strlen("pack")); git_buf_puts(&filename, "idx"); if (git_buf_oom(&filename)) return -1; if (git_filebuf_open(&index_file, filename.ptr, GIT_FILEBUF_HASH_CONTENTS) < 0) goto on_error; /* Write out the header */ hdr.idx_signature = htonl(PACK_IDX_SIGNATURE); hdr.idx_version = htonl(2); git_filebuf_write(&index_file, &hdr, sizeof(hdr)); /* Write out the fanout table */ for (i = 0; i < 256; ++i) { uint32_t n = htonl(idx->fanout[i]); git_filebuf_write(&index_file, &n, sizeof(n)); } /* Write out the object names (SHA-1 hashes) */ git_vector_foreach(&idx->objects, i, entry) { git_filebuf_write(&index_file, &entry->oid, sizeof(git_oid)); git_hash_update(&ctx, &entry->oid, GIT_OID_RAWSZ); } git_hash_final(&idx->hash, &ctx); /* Write out the CRC32 values */ git_vector_foreach(&idx->objects, i, entry) { git_filebuf_write(&index_file, &entry->crc, sizeof(uint32_t)); } /* Write out the offsets */ git_vector_foreach(&idx->objects, i, entry) { uint32_t n; if (entry->offset == UINT32_MAX) n = htonl(0x80000000 | long_offsets++); else n = htonl(entry->offset); git_filebuf_write(&index_file, &n, sizeof(uint32_t)); } /* Write out the long offsets */ git_vector_foreach(&idx->objects, i, entry) { uint32_t split[2]; if (entry->offset != UINT32_MAX) continue; split[0] = htonl(entry->offset_long >> 32); split[1] = htonl(entry->offset_long & 0xffffffff); git_filebuf_write(&index_file, &split, sizeof(uint32_t) * 2); } /* Write out the packfile trailer */ packfile_hash = git_mwindow_open(&idx->pack->mwf, &w, idx->pack->mwf.size - GIT_OID_RAWSZ, GIT_OID_RAWSZ, &left); if (packfile_hash == NULL) { git_mwindow_close(&w); goto on_error; } memcpy(&file_hash, packfile_hash, GIT_OID_RAWSZ); git_mwindow_close(&w); git_filebuf_write(&index_file, &file_hash, sizeof(git_oid)); /* Write out the packfile trailer to the idx file as well */ if (git_filebuf_hash(&file_hash, &index_file) < 0) goto on_error; git_filebuf_write(&index_file, &file_hash, sizeof(git_oid)); /* Figure out what the final name should be */ if (index_path_stream(&filename, idx, ".idx") < 0) goto on_error; /* Commit file */ if (git_filebuf_commit_at(&index_file, filename.ptr, GIT_PACK_FILE_MODE) < 0) goto on_error; git_mwindow_free_all(&idx->pack->mwf); /* We need to close the descriptor here so Windows doesn't choke on commit_at */ p_close(idx->pack->mwf.fd); idx->pack->mwf.fd = -1; if (index_path_stream(&filename, idx, ".pack") < 0) goto on_error; /* And don't forget to rename the packfile to its new place. */ if (git_filebuf_commit_at(&idx->pack_file, filename.ptr, GIT_PACK_FILE_MODE) < 0) return -1; git_buf_free(&filename); return 0; on_error: git_mwindow_free_all(&idx->pack->mwf); git_filebuf_cleanup(&index_file); git_buf_free(&filename); git_hash_ctx_cleanup(&ctx); return -1; } void git_indexer_stream_free(git_indexer_stream *idx) { khiter_t k; unsigned int i; struct entry *e; struct delta_info *delta; if (idx == NULL) return; git_vector_foreach(&idx->objects, i, e) git__free(e); git_vector_free(&idx->objects); if (idx->pack) { for (k = kh_begin(idx->pack->idx_cache); k != kh_end(idx->pack->idx_cache); k++) { if (kh_exist(idx->pack->idx_cache, k)) git__free(kh_value(idx->pack->idx_cache, k)); } git_oidmap_free(idx->pack->idx_cache); } git_vector_foreach(&idx->deltas, i, delta) git__free(delta); git_vector_free(&idx->deltas); git_packfile_free(idx->pack); git_filebuf_cleanup(&idx->pack_file); git__free(idx); } libgit2-0.19.0/src/iterator.c000066400000000000000000001066171216214232500157320ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #include "iterator.h" #include "tree.h" #include "index.h" #include "ignore.h" #include "buffer.h" #include "git2/submodule.h" #include #define ITERATOR_SET_CB(P,NAME_LC) do { \ (P)->cb.current = NAME_LC ## _iterator__current; \ (P)->cb.advance = NAME_LC ## _iterator__advance; \ (P)->cb.advance_into = NAME_LC ## _iterator__advance_into; \ (P)->cb.seek = NAME_LC ## _iterator__seek; \ (P)->cb.reset = NAME_LC ## _iterator__reset; \ (P)->cb.at_end = NAME_LC ## _iterator__at_end; \ (P)->cb.free = NAME_LC ## _iterator__free; \ } while (0) #define ITERATOR_CASE_FLAGS \ (GIT_ITERATOR_IGNORE_CASE | GIT_ITERATOR_DONT_IGNORE_CASE) #define ITERATOR_BASE_INIT(P,NAME_LC,NAME_UC,REPO) do { \ (P)->base.type = GIT_ITERATOR_TYPE_ ## NAME_UC; \ (P)->base.cb = &(P)->cb; \ ITERATOR_SET_CB(P,NAME_LC); \ (P)->base.repo = (REPO); \ (P)->base.start = start ? git__strdup(start) : NULL; \ (P)->base.end = end ? git__strdup(end) : NULL; \ if ((start && !(P)->base.start) || (end && !(P)->base.end)) { \ git__free(P); return -1; } \ (P)->base.prefixcomp = git__prefixcmp; \ (P)->base.flags = flags & ~ITERATOR_CASE_FLAGS; \ if ((P)->base.flags & GIT_ITERATOR_DONT_AUTOEXPAND) \ (P)->base.flags |= GIT_ITERATOR_INCLUDE_TREES; \ } while (0) #define iterator__flag(I,F) ((((git_iterator *)(I))->flags & GIT_ITERATOR_ ## F) != 0) #define iterator__ignore_case(I) iterator__flag(I,IGNORE_CASE) #define iterator__include_trees(I) iterator__flag(I,INCLUDE_TREES) #define iterator__dont_autoexpand(I) iterator__flag(I,DONT_AUTOEXPAND) #define iterator__do_autoexpand(I) !iterator__flag(I,DONT_AUTOEXPAND) #define GIT_ITERATOR_FIRST_ACCESS (1 << 15) #define iterator__has_been_accessed(I) iterator__flag(I,FIRST_ACCESS) #define iterator__end(I) ((git_iterator *)(I))->end #define iterator__past_end(I,PATH) \ (iterator__end(I) && ((git_iterator *)(I))->prefixcomp((PATH),iterator__end(I)) > 0) static int iterator__reset_range( git_iterator *iter, const char *start, const char *end) { if (start) { if (iter->start) git__free(iter->start); iter->start = git__strdup(start); GITERR_CHECK_ALLOC(iter->start); } if (end) { if (iter->end) git__free(iter->end); iter->end = git__strdup(end); GITERR_CHECK_ALLOC(iter->end); } iter->flags &= ~GIT_ITERATOR_FIRST_ACCESS; return 0; } static int iterator__update_ignore_case( git_iterator *iter, git_iterator_flag_t flags) { int error = 0, ignore_case = -1; if ((flags & GIT_ITERATOR_IGNORE_CASE) != 0) ignore_case = true; else if ((flags & GIT_ITERATOR_DONT_IGNORE_CASE) != 0) ignore_case = false; else { git_index *index; if (!(error = git_repository_index__weakptr(&index, iter->repo))) ignore_case = (index->ignore_case != false); } if (ignore_case > 0) iter->flags = (iter->flags | GIT_ITERATOR_IGNORE_CASE); else if (ignore_case == 0) iter->flags = (iter->flags & ~GIT_ITERATOR_IGNORE_CASE); iter->prefixcomp = iterator__ignore_case(iter) ? git__prefixcmp_icase : git__prefixcmp; return error; } GIT_INLINE(void) iterator__clear_entry(const git_index_entry **entry) { if (entry) *entry = NULL; } static int empty_iterator__noop(const git_index_entry **e, git_iterator *i) { GIT_UNUSED(i); iterator__clear_entry(e); return GIT_ITEROVER; } static int empty_iterator__seek(git_iterator *i, const char *p) { GIT_UNUSED(i); GIT_UNUSED(p); return -1; } static int empty_iterator__reset(git_iterator *i, const char *s, const char *e) { GIT_UNUSED(i); GIT_UNUSED(s); GIT_UNUSED(e); return 0; } static int empty_iterator__at_end(git_iterator *i) { GIT_UNUSED(i); return 1; } static void empty_iterator__free(git_iterator *i) { GIT_UNUSED(i); } typedef struct { git_iterator base; git_iterator_callbacks cb; } empty_iterator; int git_iterator_for_nothing( git_iterator **iter, git_iterator_flag_t flags, const char *start, const char *end) { empty_iterator *i = git__calloc(1, sizeof(empty_iterator)); GITERR_CHECK_ALLOC(i); #define empty_iterator__current empty_iterator__noop #define empty_iterator__advance empty_iterator__noop #define empty_iterator__advance_into empty_iterator__noop ITERATOR_BASE_INIT(i, empty, EMPTY, NULL); if ((flags & GIT_ITERATOR_IGNORE_CASE) != 0) i->base.flags |= GIT_ITERATOR_IGNORE_CASE; *iter = (git_iterator *)i; return 0; } typedef struct tree_iterator_entry tree_iterator_entry; struct tree_iterator_entry { tree_iterator_entry *parent; const git_tree_entry *te; git_tree *tree; }; typedef struct tree_iterator_frame tree_iterator_frame; struct tree_iterator_frame { tree_iterator_frame *up, *down; size_t n_entries; /* items in this frame */ size_t current; /* start of currently active range in frame */ size_t next; /* start of next range in frame */ const char *start; size_t startlen; tree_iterator_entry *entries[GIT_FLEX_ARRAY]; }; typedef struct { git_iterator base; git_iterator_callbacks cb; tree_iterator_frame *head, *root; git_pool pool; git_index_entry entry; git_buf path; int path_ambiguities; bool path_has_filename; bool entry_is_current; int (*strncomp)(const char *a, const char *b, size_t sz); } tree_iterator; static char *tree_iterator__current_filename( tree_iterator *ti, const git_tree_entry *te) { if (!ti->path_has_filename) { if (git_buf_joinpath(&ti->path, ti->path.ptr, te->filename) < 0) return NULL; if (git_tree_entry__is_tree(te) && git_buf_putc(&ti->path, '/') < 0) return NULL; ti->path_has_filename = true; } return ti->path.ptr; } static void tree_iterator__rewrite_filename(tree_iterator *ti) { tree_iterator_entry *scan = ti->head->entries[ti->head->current]; ssize_t strpos = ti->path.size; const git_tree_entry *te; if (strpos && ti->path.ptr[strpos - 1] == '/') strpos--; for (; scan && (te = scan->te); scan = scan->parent) { strpos -= te->filename_len; memcpy(&ti->path.ptr[strpos], te->filename, te->filename_len); strpos -= 1; /* separator */ } } static int tree_iterator__te_cmp( const git_tree_entry *a, const git_tree_entry *b, int (*compare)(const char *, const char *, size_t)) { return git_path_cmp( a->filename, a->filename_len, a->attr == GIT_FILEMODE_TREE, b->filename, b->filename_len, b->attr == GIT_FILEMODE_TREE, compare); } static int tree_iterator__ci_cmp(const void *a, const void *b, void *p) { const tree_iterator_entry *ae = a, *be = b; int cmp = tree_iterator__te_cmp(ae->te, be->te, git__strncasecmp); if (!cmp) { /* stabilize sort order among equivalent names */ if (!ae->parent->te || !be->parent->te) cmp = tree_iterator__te_cmp(ae->te, be->te, git__strncmp); else cmp = tree_iterator__ci_cmp(ae->parent, be->parent, p); } return cmp; } static int tree_iterator__search_cmp(const void *key, const void *val, void *p) { const tree_iterator_frame *tf = key; const git_tree_entry *te = ((tree_iterator_entry *)val)->te; return git_path_cmp( tf->start, tf->startlen, false, te->filename, te->filename_len, te->attr == GIT_FILEMODE_TREE, ((tree_iterator *)p)->strncomp); } static bool tree_iterator__move_to_next( tree_iterator *ti, tree_iterator_frame *tf) { if (tf->next > tf->current + 1) ti->path_ambiguities--; if (!tf->up) { /* at root */ tf->current = tf->next; return false; } for (; tf->current < tf->next; tf->current++) { git_tree_free(tf->entries[tf->current]->tree); tf->entries[tf->current]->tree = NULL; } return (tf->current < tf->n_entries); } static int tree_iterator__set_next(tree_iterator *ti, tree_iterator_frame *tf) { int error = 0; const git_tree_entry *te, *last = NULL; tf->next = tf->current; for (; tf->next < tf->n_entries; tf->next++, last = te) { te = tf->entries[tf->next]->te; if (last && tree_iterator__te_cmp(last, te, ti->strncomp)) break; /* try to load trees for items in [current,next) range */ if (!error && git_tree_entry__is_tree(te)) error = git_tree_lookup( &tf->entries[tf->next]->tree, ti->base.repo, &te->oid); } if (tf->next > tf->current + 1) ti->path_ambiguities++; /* if a tree lookup failed, advance over this span and return failure */ if (error < 0) { tree_iterator__move_to_next(ti, tf); return error; } if (last && !tree_iterator__current_filename(ti, last)) return -1; /* must have been allocation failure */ return 0; } GIT_INLINE(bool) tree_iterator__at_tree(tree_iterator *ti) { return (ti->head->current < ti->head->n_entries && ti->head->entries[ti->head->current]->tree != NULL); } static int tree_iterator__push_frame(tree_iterator *ti) { int error = 0; tree_iterator_frame *head = ti->head, *tf = NULL; size_t i, n_entries = 0; if (head->current >= head->n_entries || !head->entries[head->current]->tree) return GIT_ITEROVER; for (i = head->current; i < head->next; ++i) n_entries += git_tree_entrycount(head->entries[i]->tree); tf = git__calloc(sizeof(tree_iterator_frame) + n_entries * sizeof(tree_iterator_entry *), 1); GITERR_CHECK_ALLOC(tf); tf->n_entries = n_entries; tf->up = head; head->down = tf; ti->head = tf; for (i = head->current, n_entries = 0; i < head->next; ++i) { git_tree *tree = head->entries[i]->tree; size_t j, max_j = git_tree_entrycount(tree); for (j = 0; j < max_j; ++j) { tree_iterator_entry *entry = git_pool_malloc(&ti->pool, 1); GITERR_CHECK_ALLOC(entry); entry->parent = head->entries[i]; entry->te = git_tree_entry_byindex(tree, j); entry->tree = NULL; tf->entries[n_entries++] = entry; } } /* if ignore_case, sort entries case insensitively */ if (iterator__ignore_case(ti)) git__tsort_r( (void **)tf->entries, tf->n_entries, tree_iterator__ci_cmp, tf); /* pick tf->current based on "start" (or start at zero) */ if (head->startlen > 0) { git__bsearch_r((void **)tf->entries, tf->n_entries, head, tree_iterator__search_cmp, ti, &tf->current); while (tf->current && !tree_iterator__search_cmp(head, tf->entries[tf->current-1], ti)) tf->current--; if ((tf->start = strchr(head->start, '/')) != NULL) { tf->start++; tf->startlen = strlen(tf->start); } } ti->path_has_filename = ti->entry_is_current = false; if ((error = tree_iterator__set_next(ti, tf)) < 0) return error; /* autoexpand as needed */ if (!iterator__include_trees(ti) && tree_iterator__at_tree(ti)) return tree_iterator__push_frame(ti); return 0; } static bool tree_iterator__pop_frame(tree_iterator *ti, bool final) { tree_iterator_frame *tf = ti->head; if (!tf->up) return false; ti->head = tf->up; ti->head->down = NULL; tree_iterator__move_to_next(ti, tf); if (!final) { /* if final, don't bother to clean up */ git_pool_free_array(&ti->pool, tf->n_entries, (void **)tf->entries); git_buf_rtruncate_at_char(&ti->path, '/'); } git__free(tf); return true; } static void tree_iterator__pop_all(tree_iterator *ti, bool to_end, bool final) { while (tree_iterator__pop_frame(ti, final)) /* pop to root */; if (!final) { ti->head->current = to_end ? ti->head->n_entries : 0; ti->path_ambiguities = 0; git_buf_clear(&ti->path); } } static int tree_iterator__update_entry(tree_iterator *ti) { tree_iterator_frame *tf; const git_tree_entry *te; if (ti->entry_is_current) return 0; tf = ti->head; te = tf->entries[tf->current]->te; ti->entry.mode = te->attr; git_oid_cpy(&ti->entry.oid, &te->oid); ti->entry.path = tree_iterator__current_filename(ti, te); GITERR_CHECK_ALLOC(ti->entry.path); if (ti->path_ambiguities > 0) tree_iterator__rewrite_filename(ti); if (iterator__past_end(ti, ti->entry.path)) { tree_iterator__pop_all(ti, true, false); return GIT_ITEROVER; } ti->entry_is_current = true; return 0; } static int tree_iterator__current( const git_index_entry **entry, git_iterator *self) { int error; tree_iterator *ti = (tree_iterator *)self; tree_iterator_frame *tf = ti->head; iterator__clear_entry(entry); if (tf->current >= tf->n_entries) return GIT_ITEROVER; if ((error = tree_iterator__update_entry(ti)) < 0) return error; if (entry) *entry = &ti->entry; ti->base.flags |= GIT_ITERATOR_FIRST_ACCESS; return 0; } static int tree_iterator__advance_into( const git_index_entry **entry, git_iterator *self) { int error = 0; tree_iterator *ti = (tree_iterator *)self; iterator__clear_entry(entry); if (tree_iterator__at_tree(ti)) error = tree_iterator__push_frame(ti); if (!error && entry) error = tree_iterator__current(entry, self); return error; } static int tree_iterator__advance( const git_index_entry **entry, git_iterator *self) { int error; tree_iterator *ti = (tree_iterator *)self; tree_iterator_frame *tf = ti->head; iterator__clear_entry(entry); if (tf->current >= tf->n_entries) return GIT_ITEROVER; if (!iterator__has_been_accessed(ti)) return tree_iterator__current(entry, self); if (iterator__do_autoexpand(ti) && iterator__include_trees(ti) && tree_iterator__at_tree(ti)) return tree_iterator__advance_into(entry, self); if (ti->path_has_filename) { git_buf_rtruncate_at_char(&ti->path, '/'); ti->path_has_filename = ti->entry_is_current = false; } /* scan forward and up, advancing in frame or popping frame when done */ while (!tree_iterator__move_to_next(ti, tf) && tree_iterator__pop_frame(ti, false)) tf = ti->head; /* find next and load trees */ if ((error = tree_iterator__set_next(ti, tf)) < 0) return error; /* deal with include_trees / auto_expand as needed */ if (!iterator__include_trees(ti) && tree_iterator__at_tree(ti)) return tree_iterator__advance_into(entry, self); return tree_iterator__current(entry, self); } static int tree_iterator__seek(git_iterator *self, const char *prefix) { GIT_UNUSED(self); GIT_UNUSED(prefix); return -1; } static int tree_iterator__reset( git_iterator *self, const char *start, const char *end) { tree_iterator *ti = (tree_iterator *)self; tree_iterator__pop_all(ti, false, false); if (iterator__reset_range(self, start, end) < 0) return -1; return tree_iterator__push_frame(ti); /* re-expand root tree */ } static int tree_iterator__at_end(git_iterator *self) { tree_iterator *ti = (tree_iterator *)self; return (ti->head->current >= ti->head->n_entries); } static void tree_iterator__free(git_iterator *self) { tree_iterator *ti = (tree_iterator *)self; tree_iterator__pop_all(ti, true, false); git_tree_free(ti->head->entries[0]->tree); git__free(ti->head); git_pool_clear(&ti->pool); git_buf_free(&ti->path); } static int tree_iterator__create_root_frame(tree_iterator *ti, git_tree *tree) { size_t sz = sizeof(tree_iterator_frame) + sizeof(tree_iterator_entry); tree_iterator_frame *root = git__calloc(sz, sizeof(char)); GITERR_CHECK_ALLOC(root); root->n_entries = 1; root->next = 1; root->start = ti->base.start; root->startlen = root->start ? strlen(root->start) : 0; root->entries[0] = git_pool_mallocz(&ti->pool, 1); GITERR_CHECK_ALLOC(root->entries[0]); root->entries[0]->tree = tree; ti->head = ti->root = root; return 0; } int git_iterator_for_tree( git_iterator **iter, git_tree *tree, git_iterator_flag_t flags, const char *start, const char *end) { int error; tree_iterator *ti; if (tree == NULL) return git_iterator_for_nothing(iter, flags, start, end); if ((error = git_object_dup((git_object **)&tree, (git_object *)tree)) < 0) return error; ti = git__calloc(1, sizeof(tree_iterator)); GITERR_CHECK_ALLOC(ti); ITERATOR_BASE_INIT(ti, tree, TREE, git_tree_owner(tree)); if ((error = iterator__update_ignore_case((git_iterator *)ti, flags)) < 0) goto fail; ti->strncomp = iterator__ignore_case(ti) ? git__strncasecmp : git__strncmp; if ((error = git_pool_init(&ti->pool, sizeof(tree_iterator_entry),0)) < 0 || (error = tree_iterator__create_root_frame(ti, tree)) < 0 || (error = tree_iterator__push_frame(ti)) < 0) /* expand root now */ goto fail; *iter = (git_iterator *)ti; return 0; fail: git_iterator_free((git_iterator *)ti); return error; } typedef struct { git_iterator base; git_iterator_callbacks cb; git_index *index; size_t current; /* when not in autoexpand mode, use these to represent "tree" state */ git_buf partial; size_t partial_pos; char restore_terminator; git_index_entry tree_entry; } index_iterator; static const git_index_entry *index_iterator__index_entry(index_iterator *ii) { const git_index_entry *ie = git_index_get_byindex(ii->index, ii->current); if (ie != NULL && iterator__past_end(ii, ie->path)) { ii->current = git_index_entrycount(ii->index); ie = NULL; } return ie; } static const git_index_entry *index_iterator__skip_conflicts(index_iterator *ii) { const git_index_entry *ie; while ((ie = index_iterator__index_entry(ii)) != NULL && git_index_entry_stage(ie) != 0) ii->current++; return ie; } static void index_iterator__next_prefix_tree(index_iterator *ii) { const char *slash; if (!iterator__include_trees(ii)) return; slash = strchr(&ii->partial.ptr[ii->partial_pos], '/'); if (slash != NULL) { ii->partial_pos = (slash - ii->partial.ptr) + 1; ii->restore_terminator = ii->partial.ptr[ii->partial_pos]; ii->partial.ptr[ii->partial_pos] = '\0'; } else { ii->partial_pos = ii->partial.size; } if (index_iterator__index_entry(ii) == NULL) ii->partial_pos = ii->partial.size; } static int index_iterator__first_prefix_tree(index_iterator *ii) { const git_index_entry *ie = index_iterator__skip_conflicts(ii); const char *scan, *prior, *slash; if (!ie || !iterator__include_trees(ii)) return 0; /* find longest common prefix with prior index entry */ for (scan = slash = ie->path, prior = ii->partial.ptr; *scan && *scan == *prior; ++scan, ++prior) if (*scan == '/') slash = scan; if (git_buf_sets(&ii->partial, ie->path) < 0) return -1; ii->partial_pos = (slash - ie->path) + 1; index_iterator__next_prefix_tree(ii); return 0; } #define index_iterator__at_tree(I) \ (iterator__include_trees(I) && (I)->partial_pos < (I)->partial.size) static int index_iterator__current( const git_index_entry **entry, git_iterator *self) { index_iterator *ii = (index_iterator *)self; const git_index_entry *ie = git_index_get_byindex(ii->index, ii->current); if (ie != NULL && index_iterator__at_tree(ii)) { ii->tree_entry.path = ii->partial.ptr; ie = &ii->tree_entry; } if (entry) *entry = ie; ii->base.flags |= GIT_ITERATOR_FIRST_ACCESS; return (ie != NULL) ? 0 : GIT_ITEROVER; } static int index_iterator__at_end(git_iterator *self) { index_iterator *ii = (index_iterator *)self; return (ii->current >= git_index_entrycount(ii->index)); } static int index_iterator__advance( const git_index_entry **entry, git_iterator *self) { index_iterator *ii = (index_iterator *)self; size_t entrycount = git_index_entrycount(ii->index); const git_index_entry *ie; if (!iterator__has_been_accessed(ii)) return index_iterator__current(entry, self); if (index_iterator__at_tree(ii)) { if (iterator__do_autoexpand(ii)) { ii->partial.ptr[ii->partial_pos] = ii->restore_terminator; index_iterator__next_prefix_tree(ii); } else { /* advance to sibling tree (i.e. find entry with new prefix) */ while (ii->current < entrycount) { ii->current++; if (!(ie = git_index_get_byindex(ii->index, ii->current)) || ii->base.prefixcomp(ie->path, ii->partial.ptr) != 0) break; } if (index_iterator__first_prefix_tree(ii) < 0) return -1; } } else { if (ii->current < entrycount) ii->current++; if (index_iterator__first_prefix_tree(ii) < 0) return -1; } return index_iterator__current(entry, self); } static int index_iterator__advance_into( const git_index_entry **entry, git_iterator *self) { index_iterator *ii = (index_iterator *)self; const git_index_entry *ie = git_index_get_byindex(ii->index, ii->current); if (ie != NULL && index_iterator__at_tree(ii)) { if (ii->restore_terminator) ii->partial.ptr[ii->partial_pos] = ii->restore_terminator; index_iterator__next_prefix_tree(ii); } return index_iterator__current(entry, self); } static int index_iterator__seek(git_iterator *self, const char *prefix) { GIT_UNUSED(self); GIT_UNUSED(prefix); return -1; } static int index_iterator__reset( git_iterator *self, const char *start, const char *end) { index_iterator *ii = (index_iterator *)self; const git_index_entry *ie; if (iterator__reset_range(self, start, end) < 0) return -1; ii->current = ii->base.start ? git_index__prefix_position(ii->index, ii->base.start) : 0; if ((ie = index_iterator__skip_conflicts(ii)) == NULL) return 0; if (git_buf_sets(&ii->partial, ie->path) < 0) return -1; ii->partial_pos = 0; if (ii->base.start) { size_t startlen = strlen(ii->base.start); ii->partial_pos = (startlen > ii->partial.size) ? ii->partial.size : startlen; } index_iterator__next_prefix_tree(ii); return 0; } static void index_iterator__free(git_iterator *self) { index_iterator *ii = (index_iterator *)self; git_index_free(ii->index); ii->index = NULL; git_buf_free(&ii->partial); } int git_iterator_for_index( git_iterator **iter, git_index *index, git_iterator_flag_t flags, const char *start, const char *end) { index_iterator *ii = git__calloc(1, sizeof(index_iterator)); GITERR_CHECK_ALLOC(ii); ITERATOR_BASE_INIT(ii, index, INDEX, git_index_owner(index)); if (index->ignore_case) { ii->base.flags |= GIT_ITERATOR_IGNORE_CASE; ii->base.prefixcomp = git__prefixcmp_icase; } ii->index = index; GIT_REFCOUNT_INC(index); git_buf_init(&ii->partial, 0); ii->tree_entry.mode = GIT_FILEMODE_TREE; index_iterator__reset((git_iterator *)ii, NULL, NULL); *iter = (git_iterator *)ii; return 0; } typedef struct fs_iterator_frame fs_iterator_frame; struct fs_iterator_frame { fs_iterator_frame *next; git_vector entries; size_t index; }; typedef struct fs_iterator fs_iterator; struct fs_iterator { git_iterator base; git_iterator_callbacks cb; fs_iterator_frame *stack; git_index_entry entry; git_buf path; size_t root_len; int depth; int (*enter_dir_cb)(fs_iterator *self); int (*leave_dir_cb)(fs_iterator *self); int (*update_entry_cb)(fs_iterator *self); }; #define FS_MAX_DEPTH 100 static fs_iterator_frame *fs_iterator__alloc_frame(fs_iterator *fi) { fs_iterator_frame *ff = git__calloc(1, sizeof(fs_iterator_frame)); git_vector_cmp entry_compare = CASESELECT( iterator__ignore_case(fi), git_path_with_stat_cmp_icase, git_path_with_stat_cmp); if (ff && git_vector_init(&ff->entries, 0, entry_compare) < 0) { git__free(ff); ff = NULL; } return ff; } static void fs_iterator__free_frame(fs_iterator_frame *ff) { size_t i; git_path_with_stat *path; git_vector_foreach(&ff->entries, i, path) git__free(path); git_vector_free(&ff->entries); git__free(ff); } static void fs_iterator__pop_frame( fs_iterator *fi, fs_iterator_frame *ff, bool pop_last) { if (fi && fi->stack == ff) { if (!ff->next && !pop_last) { memset(&fi->entry, 0, sizeof(fi->entry)); return; } if (fi->leave_dir_cb) (void)fi->leave_dir_cb(fi); fi->stack = ff->next; fi->depth--; } fs_iterator__free_frame(ff); } static int fs_iterator__update_entry(fs_iterator *fi); static int fs_iterator__advance_over( const git_index_entry **entry, git_iterator *self); static int fs_iterator__entry_cmp(const void *i, const void *item) { const fs_iterator *fi = (const fs_iterator *)i; const git_path_with_stat *ps = item; return fi->base.prefixcomp(fi->base.start, ps->path); } static void fs_iterator__seek_frame_start( fs_iterator *fi, fs_iterator_frame *ff) { if (!ff) return; if (fi->base.start) git_vector_bsearch2( &ff->index, &ff->entries, fs_iterator__entry_cmp, fi); else ff->index = 0; } static int fs_iterator__expand_dir(fs_iterator *fi) { int error; fs_iterator_frame *ff; if (fi->depth > FS_MAX_DEPTH) { giterr_set(GITERR_REPOSITORY, "Directory nesting is too deep (%d)", fi->depth); return -1; } ff = fs_iterator__alloc_frame(fi); GITERR_CHECK_ALLOC(ff); error = git_path_dirload_with_stat( fi->path.ptr, fi->root_len, iterator__ignore_case(fi), fi->base.start, fi->base.end, &ff->entries); if (error < 0) { fs_iterator__free_frame(ff); fs_iterator__advance_over(NULL, (git_iterator *)fi); return error; } if (ff->entries.length == 0) { fs_iterator__free_frame(ff); return GIT_ENOTFOUND; } fs_iterator__seek_frame_start(fi, ff); ff->next = fi->stack; fi->stack = ff; fi->depth++; if (fi->enter_dir_cb && (error = fi->enter_dir_cb(fi)) < 0) return error; return fs_iterator__update_entry(fi); } static int fs_iterator__current( const git_index_entry **entry, git_iterator *self) { fs_iterator *fi = (fs_iterator *)self; const git_index_entry *fe = (fi->entry.path == NULL) ? NULL : &fi->entry; if (entry) *entry = fe; fi->base.flags |= GIT_ITERATOR_FIRST_ACCESS; return (fe != NULL) ? 0 : GIT_ITEROVER; } static int fs_iterator__at_end(git_iterator *self) { return (((fs_iterator *)self)->entry.path == NULL); } static int fs_iterator__advance_into( const git_index_entry **entry, git_iterator *iter) { int error = 0; fs_iterator *fi = (fs_iterator *)iter; iterator__clear_entry(entry); /* Allow you to explicitly advance into a commit/submodule (as well as a * tree) to avoid cases where an entry is mislabeled as a submodule in * the working directory. The fs iterator will never have COMMMIT * entries on it's own, but a wrapper might add them. */ if (fi->entry.path != NULL && (fi->entry.mode == GIT_FILEMODE_TREE || fi->entry.mode == GIT_FILEMODE_COMMIT)) /* returns GIT_ENOTFOUND if the directory is empty */ error = fs_iterator__expand_dir(fi); if (!error && entry) error = fs_iterator__current(entry, iter); if (!error && !fi->entry.path) error = GIT_ITEROVER; return error; } static int fs_iterator__advance_over( const git_index_entry **entry, git_iterator *self) { int error = 0; fs_iterator *fi = (fs_iterator *)self; fs_iterator_frame *ff; git_path_with_stat *next; if (entry != NULL) *entry = NULL; while (fi->entry.path != NULL) { ff = fi->stack; next = git_vector_get(&ff->entries, ++ff->index); if (next != NULL) break; fs_iterator__pop_frame(fi, ff, false); } error = fs_iterator__update_entry(fi); if (!error && entry != NULL) error = fs_iterator__current(entry, self); return error; } static int fs_iterator__advance( const git_index_entry **entry, git_iterator *self) { fs_iterator *fi = (fs_iterator *)self; if (!iterator__has_been_accessed(fi)) return fs_iterator__current(entry, self); /* given include_trees & autoexpand, we might have to go into a tree */ if (iterator__do_autoexpand(fi) && fi->entry.path != NULL && fi->entry.mode == GIT_FILEMODE_TREE) { int error = fs_iterator__advance_into(entry, self); if (error != GIT_ENOTFOUND) return error; /* continue silently past empty directories if autoexpanding */ giterr_clear(); } return fs_iterator__advance_over(entry, self); } static int fs_iterator__seek(git_iterator *self, const char *prefix) { GIT_UNUSED(self); GIT_UNUSED(prefix); /* pop stack until matching prefix */ /* find prefix item in current frame */ /* push subdirectories as deep as possible while matching */ return 0; } static int fs_iterator__reset( git_iterator *self, const char *start, const char *end) { int error; fs_iterator *fi = (fs_iterator *)self; while (fi->stack != NULL && fi->stack->next != NULL) fs_iterator__pop_frame(fi, fi->stack, false); fi->depth = 0; if ((error = iterator__reset_range(self, start, end)) < 0) return error; fs_iterator__seek_frame_start(fi, fi->stack); error = fs_iterator__update_entry(fi); if (error == GIT_ITEROVER) error = 0; return error; } static void fs_iterator__free(git_iterator *self) { fs_iterator *fi = (fs_iterator *)self; while (fi->stack != NULL) fs_iterator__pop_frame(fi, fi->stack, true); git_buf_free(&fi->path); } static int fs_iterator__update_entry(fs_iterator *fi) { git_path_with_stat *ps; memset(&fi->entry, 0, sizeof(fi->entry)); if (!fi->stack) return GIT_ITEROVER; ps = git_vector_get(&fi->stack->entries, fi->stack->index); if (!ps) return GIT_ITEROVER; git_buf_truncate(&fi->path, fi->root_len); if (git_buf_put(&fi->path, ps->path, ps->path_len) < 0) return -1; if (iterator__past_end(fi, fi->path.ptr + fi->root_len)) return GIT_ITEROVER; fi->entry.path = ps->path; git_index_entry__init_from_stat(&fi->entry, &ps->st); /* need different mode here to keep directories during iteration */ fi->entry.mode = git_futils_canonical_mode(ps->st.st_mode); /* allow wrapper to check/update the entry (can force skip) */ if (fi->update_entry_cb && fi->update_entry_cb(fi) == GIT_ENOTFOUND) return fs_iterator__advance_over(NULL, (git_iterator *)fi); /* if this is a tree and trees aren't included, then skip */ if (fi->entry.mode == GIT_FILEMODE_TREE && !iterator__include_trees(fi)) { int error = fs_iterator__advance_into(NULL, (git_iterator *)fi); if (error != GIT_ENOTFOUND) return error; giterr_clear(); return fs_iterator__advance_over(NULL, (git_iterator *)fi); } return 0; } static int fs_iterator__initialize( git_iterator **out, fs_iterator *fi, const char *root) { int error; if (git_buf_sets(&fi->path, root) < 0 || git_path_to_dir(&fi->path) < 0) { git__free(fi); return -1; } fi->root_len = fi->path.size; if ((error = fs_iterator__expand_dir(fi)) < 0) { if (error == GIT_ENOTFOUND || error == GIT_ITEROVER) { giterr_clear(); error = 0; } else { git_iterator_free((git_iterator *)fi); fi = NULL; } } *out = (git_iterator *)fi; return error; } int git_iterator_for_filesystem( git_iterator **out, const char *root, git_iterator_flag_t flags, const char *start, const char *end) { fs_iterator *fi = git__calloc(1, sizeof(fs_iterator)); GITERR_CHECK_ALLOC(fi); ITERATOR_BASE_INIT(fi, fs, FS, NULL); if ((flags & GIT_ITERATOR_IGNORE_CASE) != 0) fi->base.flags |= GIT_ITERATOR_IGNORE_CASE; return fs_iterator__initialize(out, fi, root); } typedef struct { fs_iterator fi; git_ignores ignores; int is_ignored; } workdir_iterator; GIT_INLINE(bool) workdir_path_is_dotgit(const git_buf *path) { size_t len; if (!path || (len = path->size) < 4) return false; if (path->ptr[len - 1] == '/') len--; if (tolower(path->ptr[len - 1]) != 't' || tolower(path->ptr[len - 2]) != 'i' || tolower(path->ptr[len - 3]) != 'g' || tolower(path->ptr[len - 4]) != '.') return false; return (len == 4 || path->ptr[len - 5] == '/'); } static int workdir_iterator__enter_dir(fs_iterator *fi) { /* only push new ignores if this is not top level directory */ if (fi->stack->next != NULL) { workdir_iterator *wi = (workdir_iterator *)fi; ssize_t slash_pos = git_buf_rfind_next(&fi->path, '/'); (void)git_ignore__push_dir(&wi->ignores, &fi->path.ptr[slash_pos + 1]); } return 0; } static int workdir_iterator__leave_dir(fs_iterator *fi) { workdir_iterator *wi = (workdir_iterator *)fi; git_ignore__pop_dir(&wi->ignores); return 0; } static int workdir_iterator__update_entry(fs_iterator *fi) { int error = 0; workdir_iterator *wi = (workdir_iterator *)fi; /* skip over .git entries */ if (workdir_path_is_dotgit(&fi->path)) return GIT_ENOTFOUND; /* reset is_ignored since we haven't checked yet */ wi->is_ignored = -1; /* check if apparent tree entries are actually submodules */ if (fi->entry.mode != GIT_FILEMODE_TREE) return 0; error = git_submodule_lookup(NULL, fi->base.repo, fi->entry.path); if (error < 0) giterr_clear(); /* mark submodule (or any dir with .git) as GITLINK and remove slash */ if (!error || error == GIT_EEXISTS) { fi->entry.mode = S_IFGITLINK; fi->entry.path[strlen(fi->entry.path) - 1] = '\0'; } return 0; } static void workdir_iterator__free(git_iterator *self) { workdir_iterator *wi = (workdir_iterator *)self; fs_iterator__free(self); git_ignore__free(&wi->ignores); } int git_iterator_for_workdir_ext( git_iterator **out, git_repository *repo, const char *repo_workdir, git_iterator_flag_t flags, const char *start, const char *end) { int error; workdir_iterator *wi; if (!repo_workdir) { if (git_repository__ensure_not_bare(repo, "scan working directory") < 0) return GIT_EBAREREPO; repo_workdir = git_repository_workdir(repo); } /* initialize as an fs iterator then do overrides */ wi = git__calloc(1, sizeof(workdir_iterator)); GITERR_CHECK_ALLOC(wi); ITERATOR_BASE_INIT((&wi->fi), fs, FS, repo); wi->fi.base.type = GIT_ITERATOR_TYPE_WORKDIR; wi->fi.cb.free = workdir_iterator__free; wi->fi.enter_dir_cb = workdir_iterator__enter_dir; wi->fi.leave_dir_cb = workdir_iterator__leave_dir; wi->fi.update_entry_cb = workdir_iterator__update_entry; if ((error = iterator__update_ignore_case((git_iterator *)wi, flags)) < 0 || (error = git_ignore__for_path(repo, "", &wi->ignores)) < 0) { git_iterator_free((git_iterator *)wi); return error; } return fs_iterator__initialize(out, &wi->fi, repo_workdir); } void git_iterator_free(git_iterator *iter) { if (iter == NULL) return; iter->cb->free(iter); git__free(iter->start); git__free(iter->end); memset(iter, 0, sizeof(*iter)); git__free(iter); } int git_iterator_set_ignore_case(git_iterator *iter, bool ignore_case) { bool desire_ignore_case = (ignore_case != 0); if (iterator__ignore_case(iter) == desire_ignore_case) return 0; if (iter->type == GIT_ITERATOR_TYPE_EMPTY) { if (desire_ignore_case) iter->flags |= GIT_ITERATOR_IGNORE_CASE; else iter->flags &= ~GIT_ITERATOR_IGNORE_CASE; } else { giterr_set(GITERR_INVALID, "Cannot currently set ignore case on non-empty iterators"); return -1; } return 0; } git_index *git_iterator_get_index(git_iterator *iter) { if (iter->type == GIT_ITERATOR_TYPE_INDEX) return ((index_iterator *)iter)->index; return NULL; } int git_iterator_current_tree_entry( const git_tree_entry **tree_entry, git_iterator *iter) { if (iter->type != GIT_ITERATOR_TYPE_TREE) *tree_entry = NULL; else { tree_iterator_frame *tf = ((tree_iterator *)iter)->head; *tree_entry = (tf->current < tf->n_entries) ? tf->entries[tf->current]->te : NULL; } return 0; } int git_iterator_current_parent_tree( const git_tree **tree_ptr, git_iterator *iter, const char *parent_path) { tree_iterator *ti = (tree_iterator *)iter; tree_iterator_frame *tf; const char *scan = parent_path; const git_tree_entry *te; *tree_ptr = NULL; if (iter->type != GIT_ITERATOR_TYPE_TREE) return 0; for (tf = ti->root; *scan; ) { if (!(tf = tf->down) || tf->current >= tf->n_entries || !(te = tf->entries[tf->current]->te) || ti->strncomp(scan, te->filename, te->filename_len) != 0) return 0; scan += te->filename_len; if (*scan == '/') scan++; } *tree_ptr = tf->entries[tf->current]->tree; return 0; } bool git_iterator_current_is_ignored(git_iterator *iter) { workdir_iterator *wi = (workdir_iterator *)iter; if (iter->type != GIT_ITERATOR_TYPE_WORKDIR) return false; if (wi->is_ignored != -1) return (bool)(wi->is_ignored != 0); if (git_ignore__lookup( &wi->ignores, wi->fi.entry.path, &wi->is_ignored) < 0) wi->is_ignored = true; return (bool)wi->is_ignored; } int git_iterator_cmp(git_iterator *iter, const char *path_prefix) { const git_index_entry *entry; /* a "done" iterator is after every prefix */ if (git_iterator_current(&entry, iter) < 0 || entry == NULL) return 1; /* a NULL prefix is after any valid iterator */ if (!path_prefix) return -1; return iter->prefixcomp(entry->path, path_prefix); } int git_iterator_current_workdir_path(git_buf **path, git_iterator *iter) { workdir_iterator *wi = (workdir_iterator *)iter; if (iter->type != GIT_ITERATOR_TYPE_WORKDIR || !wi->fi.entry.path) *path = NULL; else *path = &wi->fi.path; return 0; } libgit2-0.19.0/src/iterator.h000066400000000000000000000170521216214232500157310ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #ifndef INCLUDE_iterator_h__ #define INCLUDE_iterator_h__ #include "common.h" #include "git2/index.h" #include "vector.h" #include "buffer.h" typedef struct git_iterator git_iterator; typedef enum { GIT_ITERATOR_TYPE_EMPTY = 0, GIT_ITERATOR_TYPE_TREE = 1, GIT_ITERATOR_TYPE_INDEX = 2, GIT_ITERATOR_TYPE_WORKDIR = 3, GIT_ITERATOR_TYPE_FS = 4, } git_iterator_type_t; typedef enum { /** ignore case for entry sort order */ GIT_ITERATOR_IGNORE_CASE = (1 << 0), /** force case sensitivity for entry sort order */ GIT_ITERATOR_DONT_IGNORE_CASE = (1 << 1), /** return tree items in addition to blob items */ GIT_ITERATOR_INCLUDE_TREES = (1 << 2), /** don't flatten trees, requiring advance_into (implies INCLUDE_TREES) */ GIT_ITERATOR_DONT_AUTOEXPAND = (1 << 3), } git_iterator_flag_t; typedef struct { int (*current)(const git_index_entry **, git_iterator *); int (*advance)(const git_index_entry **, git_iterator *); int (*advance_into)(const git_index_entry **, git_iterator *); int (*seek)(git_iterator *, const char *prefix); int (*reset)(git_iterator *, const char *start, const char *end); int (*at_end)(git_iterator *); void (*free)(git_iterator *); } git_iterator_callbacks; struct git_iterator { git_iterator_type_t type; git_iterator_callbacks *cb; git_repository *repo; char *start; char *end; int (*prefixcomp)(const char *str, const char *prefix); unsigned int flags; }; extern int git_iterator_for_nothing( git_iterator **out, git_iterator_flag_t flags, const char *start, const char *end); /* tree iterators will match the ignore_case value from the index of the * repository, unless you override with a non-zero flag value */ extern int git_iterator_for_tree( git_iterator **out, git_tree *tree, git_iterator_flag_t flags, const char *start, const char *end); /* index iterators will take the ignore_case value from the index; the * ignore_case flags are not used */ extern int git_iterator_for_index( git_iterator **out, git_index *index, git_iterator_flag_t flags, const char *start, const char *end); extern int git_iterator_for_workdir_ext( git_iterator **out, git_repository *repo, const char *repo_workdir, git_iterator_flag_t flags, const char *start, const char *end); /* workdir iterators will match the ignore_case value from the index of the * repository, unless you override with a non-zero flag value */ GIT_INLINE(int) git_iterator_for_workdir( git_iterator **out, git_repository *repo, git_iterator_flag_t flags, const char *start, const char *end) { return git_iterator_for_workdir_ext(out, repo, NULL, flags, start, end); } /* for filesystem iterators, you have to explicitly pass in the ignore_case * behavior that you desire */ extern int git_iterator_for_filesystem( git_iterator **out, const char *root, git_iterator_flag_t flags, const char *start, const char *end); extern void git_iterator_free(git_iterator *iter); /* Return a git_index_entry structure for the current value the iterator * is looking at or NULL if the iterator is at the end. * * The entry may noy be fully populated. Tree iterators will only have a * value mode, OID, and path. Workdir iterators will not have an OID (but * you can use `git_iterator_current_oid()` to calculate it on demand). * * You do not need to free the entry. It is still "owned" by the iterator. * Once you call `git_iterator_advance()` then the old entry is no longer * guaranteed to be valid - it may be freed or just overwritten in place. */ GIT_INLINE(int) git_iterator_current( const git_index_entry **entry, git_iterator *iter) { return iter->cb->current(entry, iter); } /** * Advance to the next item for the iterator. * * If GIT_ITERATOR_INCLUDE_TREES is set, this may be a tree item. If * GIT_ITERATOR_DONT_AUTOEXPAND is set, calling this again when on a tree * item will skip over all the items under that tree. */ GIT_INLINE(int) git_iterator_advance( const git_index_entry **entry, git_iterator *iter) { return iter->cb->advance(entry, iter); } /** * Iterate into a tree item (when GIT_ITERATOR_DONT_AUTOEXPAND is set). * * git_iterator_advance() steps through all items being iterated over * (either with or without trees, depending on GIT_ITERATOR_INCLUDE_TREES), * but if GIT_ITERATOR_DONT_AUTOEXPAND is set, it will skip to the next * sibling of a tree instead of going to the first child of the tree. In * that case, use this function to advance to the first child of the tree. * * If the current item is not a tree, this is a no-op. * * For filesystem and working directory iterators, a tree (i.e. directory) * can be empty. In that case, this function returns GIT_ENOTFOUND and * does not advance. That can't happen for tree and index iterators. */ GIT_INLINE(int) git_iterator_advance_into( const git_index_entry **entry, git_iterator *iter) { return iter->cb->advance_into(entry, iter); } /** * Advance into a tree or skip over it if it is empty. * * Because `git_iterator_advance_into` may return GIT_ENOTFOUND if the * directory is empty (only with filesystem and working directory * iterators) and a common response is to just call `git_iterator_advance` * when that happens, this bundles the two into a single simple call. */ GIT_INLINE(int) git_iterator_advance_into_or_over( const git_index_entry **entry, git_iterator *iter) { int error = iter->cb->advance_into(entry, iter); if (error == GIT_ENOTFOUND) { giterr_clear(); error = iter->cb->advance(entry, iter); } return error; } /* Seek is currently unimplemented */ GIT_INLINE(int) git_iterator_seek( git_iterator *iter, const char *prefix) { return iter->cb->seek(iter, prefix); } /** * Go back to the start of the iteration. * * This resets the iterator to the start of the iteration. It also allows * you to reset the `start` and `end` pathname boundaries of the iteration * when doing so. */ GIT_INLINE(int) git_iterator_reset( git_iterator *iter, const char *start, const char *end) { return iter->cb->reset(iter, start, end); } /** * Check if the iterator is at the end * * @return 0 if not at end, >0 if at end */ GIT_INLINE(int) git_iterator_at_end(git_iterator *iter) { return iter->cb->at_end(iter); } GIT_INLINE(git_iterator_type_t) git_iterator_type(git_iterator *iter) { return iter->type; } GIT_INLINE(git_repository *) git_iterator_owner(git_iterator *iter) { return iter->repo; } GIT_INLINE(git_iterator_flag_t) git_iterator_flags(git_iterator *iter) { return iter->flags; } GIT_INLINE(bool) git_iterator_ignore_case(git_iterator *iter) { return ((iter->flags & GIT_ITERATOR_IGNORE_CASE) != 0); } extern int git_iterator_set_ignore_case(git_iterator *iter, bool ignore_case); extern int git_iterator_current_tree_entry( const git_tree_entry **entry_out, git_iterator *iter); extern int git_iterator_current_parent_tree( const git_tree **tree_out, git_iterator *iter, const char *parent_path); extern bool git_iterator_current_is_ignored(git_iterator *iter); extern int git_iterator_cmp( git_iterator *iter, const char *path_prefix); /** * Get full path of the current item from a workdir iterator. This will * return NULL for a non-workdir iterator. The git_buf is still owned by * the iterator; this is exposed just for efficiency. */ extern int git_iterator_current_workdir_path( git_buf **path, git_iterator *iter); /* Return index pointer if index iterator, else NULL */ extern git_index *git_iterator_get_index(git_iterator *iter); #endif libgit2-0.19.0/src/khash.h000066400000000000000000000505321216214232500151760ustar00rootroot00000000000000/* The MIT License Copyright (c) 2008, 2009, 2011 by Attractive Chaos Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* An example: #include "khash.h" KHASH_MAP_INIT_INT(32, char) int main() { int ret, is_missing; khiter_t k; khash_t(32) *h = kh_init(32); k = kh_put(32, h, 5, &ret); kh_value(h, k) = 10; k = kh_get(32, h, 10); is_missing = (k == kh_end(h)); k = kh_get(32, h, 5); kh_del(32, h, k); for (k = kh_begin(h); k != kh_end(h); ++k) if (kh_exist(h, k)) kh_value(h, k) = 1; kh_destroy(32, h); return 0; } */ /* 2011-12-29 (0.2.7): * Minor code clean up; no actual effect. 2011-09-16 (0.2.6): * The capacity is a power of 2. This seems to dramatically improve the speed for simple keys. Thank Zilong Tan for the suggestion. Reference: - http://code.google.com/p/ulib/ - http://nothings.org/computer/judy/ * Allow to optionally use linear probing which usually has better performance for random input. Double hashing is still the default as it is more robust to certain non-random input. * Added Wang's integer hash function (not used by default). This hash function is more robust to certain non-random input. 2011-02-14 (0.2.5): * Allow to declare global functions. 2009-09-26 (0.2.4): * Improve portability 2008-09-19 (0.2.3): * Corrected the example * Improved interfaces 2008-09-11 (0.2.2): * Improved speed a little in kh_put() 2008-09-10 (0.2.1): * Added kh_clear() * Fixed a compiling error 2008-09-02 (0.2.0): * Changed to token concatenation which increases flexibility. 2008-08-31 (0.1.2): * Fixed a bug in kh_get(), which has not been tested previously. 2008-08-31 (0.1.1): * Added destructor */ #ifndef __AC_KHASH_H #define __AC_KHASH_H /*! @header Generic hash table library. */ #define AC_VERSION_KHASH_H "0.2.6" #include #include #include /* compipler specific configuration */ #if UINT_MAX == 0xffffffffu typedef unsigned int khint32_t; #elif ULONG_MAX == 0xffffffffu typedef unsigned long khint32_t; #endif #if ULONG_MAX == ULLONG_MAX typedef unsigned long khint64_t; #else typedef unsigned long long khint64_t; #endif #ifdef _MSC_VER #define kh_inline __inline #else #define kh_inline inline #endif typedef khint32_t khint_t; typedef khint_t khiter_t; #define __ac_isempty(flag, i) ((flag[i>>4]>>((i&0xfU)<<1))&2) #define __ac_isdel(flag, i) ((flag[i>>4]>>((i&0xfU)<<1))&1) #define __ac_iseither(flag, i) ((flag[i>>4]>>((i&0xfU)<<1))&3) #define __ac_set_isdel_false(flag, i) (flag[i>>4]&=~(1ul<<((i&0xfU)<<1))) #define __ac_set_isempty_false(flag, i) (flag[i>>4]&=~(2ul<<((i&0xfU)<<1))) #define __ac_set_isboth_false(flag, i) (flag[i>>4]&=~(3ul<<((i&0xfU)<<1))) #define __ac_set_isdel_true(flag, i) (flag[i>>4]|=1ul<<((i&0xfU)<<1)) #ifdef KHASH_LINEAR #define __ac_inc(k, m) 1 #else #define __ac_inc(k, m) (((k)>>3 ^ (k)<<3) | 1) & (m) #endif #define __ac_fsize(m) ((m) < 16? 1 : (m)>>4) #ifndef kroundup32 #define kroundup32(x) (--(x), (x)|=(x)>>1, (x)|=(x)>>2, (x)|=(x)>>4, (x)|=(x)>>8, (x)|=(x)>>16, ++(x)) #endif #ifndef kcalloc #define kcalloc(N,Z) calloc(N,Z) #endif #ifndef kmalloc #define kmalloc(Z) malloc(Z) #endif #ifndef krealloc #define krealloc(P,Z) realloc(P,Z) #endif #ifndef kfree #define kfree(P) free(P) #endif static const double __ac_HASH_UPPER = 0.77; #define __KHASH_TYPE(name, khkey_t, khval_t) \ typedef struct { \ khint_t n_buckets, size, n_occupied, upper_bound; \ khint32_t *flags; \ khkey_t *keys; \ khval_t *vals; \ } kh_##name##_t; #define __KHASH_PROTOTYPES(name, khkey_t, khval_t) \ extern kh_##name##_t *kh_init_##name(void); \ extern void kh_destroy_##name(kh_##name##_t *h); \ extern void kh_clear_##name(kh_##name##_t *h); \ extern khint_t kh_get_##name(const kh_##name##_t *h, khkey_t key); \ extern int kh_resize_##name(kh_##name##_t *h, khint_t new_n_buckets); \ extern khint_t kh_put_##name(kh_##name##_t *h, khkey_t key, int *ret); \ extern void kh_del_##name(kh_##name##_t *h, khint_t x); #define __KHASH_IMPL(name, SCOPE, khkey_t, khval_t, kh_is_map, __hash_func, __hash_equal) \ SCOPE kh_##name##_t *kh_init_##name(void) { \ return (kh_##name##_t*)kcalloc(1, sizeof(kh_##name##_t)); \ } \ SCOPE void kh_destroy_##name(kh_##name##_t *h) \ { \ if (h) { \ kfree((void *)h->keys); kfree(h->flags); \ kfree((void *)h->vals); \ kfree(h); \ } \ } \ SCOPE void kh_clear_##name(kh_##name##_t *h) \ { \ if (h && h->flags) { \ memset(h->flags, 0xaa, __ac_fsize(h->n_buckets) * sizeof(khint32_t)); \ h->size = h->n_occupied = 0; \ } \ } \ SCOPE khint_t kh_get_##name(const kh_##name##_t *h, khkey_t key) \ { \ if (h->n_buckets) { \ khint_t inc, k, i, last, mask; \ mask = h->n_buckets - 1; \ k = __hash_func(key); i = k & mask; \ inc = __ac_inc(k, mask); last = i; /* inc==1 for linear probing */ \ while (!__ac_isempty(h->flags, i) && (__ac_isdel(h->flags, i) || !__hash_equal(h->keys[i], key))) { \ i = (i + inc) & mask; \ if (i == last) return h->n_buckets; \ } \ return __ac_iseither(h->flags, i)? h->n_buckets : i; \ } else return 0; \ } \ SCOPE int kh_resize_##name(kh_##name##_t *h, khint_t new_n_buckets) \ { /* This function uses 0.25*n_bucktes bytes of working space instead of [sizeof(key_t+val_t)+.25]*n_buckets. */ \ khint32_t *new_flags = 0; \ khint_t j = 1; \ { \ kroundup32(new_n_buckets); \ if (new_n_buckets < 4) new_n_buckets = 4; \ if (h->size >= (khint_t)(new_n_buckets * __ac_HASH_UPPER + 0.5)) j = 0; /* requested size is too small */ \ else { /* hash table size to be changed (shrink or expand); rehash */ \ new_flags = (khint32_t*)kmalloc(__ac_fsize(new_n_buckets) * sizeof(khint32_t)); \ if (!new_flags) return -1; \ memset(new_flags, 0xaa, __ac_fsize(new_n_buckets) * sizeof(khint32_t)); \ if (h->n_buckets < new_n_buckets) { /* expand */ \ khkey_t *new_keys = (khkey_t*)krealloc((void *)h->keys, new_n_buckets * sizeof(khkey_t)); \ if (!new_keys) return -1; \ h->keys = new_keys; \ if (kh_is_map) { \ khval_t *new_vals = (khval_t*)krealloc((void *)h->vals, new_n_buckets * sizeof(khval_t)); \ if (!new_vals) return -1; \ h->vals = new_vals; \ } \ } /* otherwise shrink */ \ } \ } \ if (j) { /* rehashing is needed */ \ for (j = 0; j != h->n_buckets; ++j) { \ if (__ac_iseither(h->flags, j) == 0) { \ khkey_t key = h->keys[j]; \ khval_t val; \ khint_t new_mask; \ new_mask = new_n_buckets - 1; \ if (kh_is_map) val = h->vals[j]; \ __ac_set_isdel_true(h->flags, j); \ while (1) { /* kick-out process; sort of like in Cuckoo hashing */ \ khint_t inc, k, i; \ k = __hash_func(key); \ i = k & new_mask; \ inc = __ac_inc(k, new_mask); \ while (!__ac_isempty(new_flags, i)) i = (i + inc) & new_mask; \ __ac_set_isempty_false(new_flags, i); \ if (i < h->n_buckets && __ac_iseither(h->flags, i) == 0) { /* kick out the existing element */ \ { khkey_t tmp = h->keys[i]; h->keys[i] = key; key = tmp; } \ if (kh_is_map) { khval_t tmp = h->vals[i]; h->vals[i] = val; val = tmp; } \ __ac_set_isdel_true(h->flags, i); /* mark it as deleted in the old hash table */ \ } else { /* write the element and jump out of the loop */ \ h->keys[i] = key; \ if (kh_is_map) h->vals[i] = val; \ break; \ } \ } \ } \ } \ if (h->n_buckets > new_n_buckets) { /* shrink the hash table */ \ h->keys = (khkey_t*)krealloc((void *)h->keys, new_n_buckets * sizeof(khkey_t)); \ if (kh_is_map) h->vals = (khval_t*)krealloc((void *)h->vals, new_n_buckets * sizeof(khval_t)); \ } \ kfree(h->flags); /* free the working space */ \ h->flags = new_flags; \ h->n_buckets = new_n_buckets; \ h->n_occupied = h->size; \ h->upper_bound = (khint_t)(h->n_buckets * __ac_HASH_UPPER + 0.5); \ } \ return 0; \ } \ SCOPE khint_t kh_put_##name(kh_##name##_t *h, khkey_t key, int *ret) \ { \ khint_t x; \ if (h->n_occupied >= h->upper_bound) { /* update the hash table */ \ if (h->n_buckets > (h->size<<1)) { \ if (kh_resize_##name(h, h->n_buckets - 1) < 0) { /* clear "deleted" elements */ \ *ret = -1; return h->n_buckets; \ } \ } else if (kh_resize_##name(h, h->n_buckets + 1) < 0) { /* expand the hash table */ \ *ret = -1; return h->n_buckets; \ } \ } /* TODO: to implement automatically shrinking; resize() already support shrinking */ \ { \ khint_t inc, k, i, site, last, mask = h->n_buckets - 1; \ x = site = h->n_buckets; k = __hash_func(key); i = k & mask; \ if (__ac_isempty(h->flags, i)) x = i; /* for speed up */ \ else { \ inc = __ac_inc(k, mask); last = i; \ while (!__ac_isempty(h->flags, i) && (__ac_isdel(h->flags, i) || !__hash_equal(h->keys[i], key))) { \ if (__ac_isdel(h->flags, i)) site = i; \ i = (i + inc) & mask; \ if (i == last) { x = site; break; } \ } \ if (x == h->n_buckets) { \ if (__ac_isempty(h->flags, i) && site != h->n_buckets) x = site; \ else x = i; \ } \ } \ } \ if (__ac_isempty(h->flags, x)) { /* not present at all */ \ h->keys[x] = key; \ __ac_set_isboth_false(h->flags, x); \ ++h->size; ++h->n_occupied; \ *ret = 1; \ } else if (__ac_isdel(h->flags, x)) { /* deleted */ \ h->keys[x] = key; \ __ac_set_isboth_false(h->flags, x); \ ++h->size; \ *ret = 2; \ } else *ret = 0; /* Don't touch h->keys[x] if present and not deleted */ \ return x; \ } \ SCOPE void kh_del_##name(kh_##name##_t *h, khint_t x) \ { \ if (x != h->n_buckets && !__ac_iseither(h->flags, x)) { \ __ac_set_isdel_true(h->flags, x); \ --h->size; \ } \ } #define KHASH_DECLARE(name, khkey_t, khval_t) \ __KHASH_TYPE(name, khkey_t, khval_t) \ __KHASH_PROTOTYPES(name, khkey_t, khval_t) #define KHASH_INIT2(name, SCOPE, khkey_t, khval_t, kh_is_map, __hash_func, __hash_equal) \ __KHASH_TYPE(name, khkey_t, khval_t) \ __KHASH_IMPL(name, SCOPE, khkey_t, khval_t, kh_is_map, __hash_func, __hash_equal) #define KHASH_INIT(name, khkey_t, khval_t, kh_is_map, __hash_func, __hash_equal) \ KHASH_INIT2(name, static kh_inline, khkey_t, khval_t, kh_is_map, __hash_func, __hash_equal) /* --- BEGIN OF HASH FUNCTIONS --- */ /*! @function @abstract Integer hash function @param key The integer [khint32_t] @return The hash value [khint_t] */ #define kh_int_hash_func(key) (khint32_t)(key) /*! @function @abstract Integer comparison function */ #define kh_int_hash_equal(a, b) ((a) == (b)) /*! @function @abstract 64-bit integer hash function @param key The integer [khint64_t] @return The hash value [khint_t] */ #define kh_int64_hash_func(key) (khint32_t)((key)>>33^(key)^(key)<<11) /*! @function @abstract 64-bit integer comparison function */ #define kh_int64_hash_equal(a, b) ((a) == (b)) /*! @function @abstract const char* hash function @param s Pointer to a null terminated string @return The hash value */ static kh_inline khint_t __ac_X31_hash_string(const char *s) { khint_t h = (khint_t)*s; if (h) for (++s ; *s; ++s) h = (h << 5) - h + (khint_t)*s; return h; } /*! @function @abstract Another interface to const char* hash function @param key Pointer to a null terminated string [const char*] @return The hash value [khint_t] */ #define kh_str_hash_func(key) __ac_X31_hash_string(key) /*! @function @abstract Const char* comparison function */ #define kh_str_hash_equal(a, b) (strcmp(a, b) == 0) static kh_inline khint_t __ac_Wang_hash(khint_t key) { key += ~(key << 15); key ^= (key >> 10); key += (key << 3); key ^= (key >> 6); key += ~(key << 11); key ^= (key >> 16); return key; } #define kh_int_hash_func2(k) __ac_Wang_hash((khint_t)key) /* --- END OF HASH FUNCTIONS --- */ /* Other convenient macros... */ /*! @abstract Type of the hash table. @param name Name of the hash table [symbol] */ #define khash_t(name) kh_##name##_t /*! @function @abstract Initiate a hash table. @param name Name of the hash table [symbol] @return Pointer to the hash table [khash_t(name)*] */ #define kh_init(name) kh_init_##name() /*! @function @abstract Destroy a hash table. @param name Name of the hash table [symbol] @param h Pointer to the hash table [khash_t(name)*] */ #define kh_destroy(name, h) kh_destroy_##name(h) /*! @function @abstract Reset a hash table without deallocating memory. @param name Name of the hash table [symbol] @param h Pointer to the hash table [khash_t(name)*] */ #define kh_clear(name, h) kh_clear_##name(h) /*! @function @abstract Resize a hash table. @param name Name of the hash table [symbol] @param h Pointer to the hash table [khash_t(name)*] @param s New size [khint_t] */ #define kh_resize(name, h, s) kh_resize_##name(h, s) /*! @function @abstract Insert a key to the hash table. @param name Name of the hash table [symbol] @param h Pointer to the hash table [khash_t(name)*] @param k Key [type of keys] @param r Extra return code: 0 if the key is present in the hash table; 1 if the bucket is empty (never used); 2 if the element in the bucket has been deleted [int*] @return Iterator to the inserted element [khint_t] */ #define kh_put(name, h, k, r) kh_put_##name(h, k, r) /*! @function @abstract Retrieve a key from the hash table. @param name Name of the hash table [symbol] @param h Pointer to the hash table [khash_t(name)*] @param k Key [type of keys] @return Iterator to the found element, or kh_end(h) is the element is absent [khint_t] */ #define kh_get(name, h, k) kh_get_##name(h, k) /*! @function @abstract Remove a key from the hash table. @param name Name of the hash table [symbol] @param h Pointer to the hash table [khash_t(name)*] @param k Iterator to the element to be deleted [khint_t] */ #define kh_del(name, h, k) kh_del_##name(h, k) /*! @function @abstract Test whether a bucket contains data. @param h Pointer to the hash table [khash_t(name)*] @param x Iterator to the bucket [khint_t] @return 1 if containing data; 0 otherwise [int] */ #define kh_exist(h, x) (!__ac_iseither((h)->flags, (x))) /*! @function @abstract Get key given an iterator @param h Pointer to the hash table [khash_t(name)*] @param x Iterator to the bucket [khint_t] @return Key [type of keys] */ #define kh_key(h, x) ((h)->keys[x]) /*! @function @abstract Get value given an iterator @param h Pointer to the hash table [khash_t(name)*] @param x Iterator to the bucket [khint_t] @return Value [type of values] @discussion For hash sets, calling this results in segfault. */ #define kh_val(h, x) ((h)->vals[x]) /*! @function @abstract Alias of kh_val() */ #define kh_value(h, x) ((h)->vals[x]) /*! @function @abstract Get the start iterator @param h Pointer to the hash table [khash_t(name)*] @return The start iterator [khint_t] */ #define kh_begin(h) (khint_t)(0) /*! @function @abstract Get the end iterator @param h Pointer to the hash table [khash_t(name)*] @return The end iterator [khint_t] */ #define kh_end(h) ((h)->n_buckets) /*! @function @abstract Get the number of elements in the hash table @param h Pointer to the hash table [khash_t(name)*] @return Number of elements in the hash table [khint_t] */ #define kh_size(h) ((h)->size) /*! @function @abstract Get the number of buckets in the hash table @param h Pointer to the hash table [khash_t(name)*] @return Number of buckets in the hash table [khint_t] */ #define kh_n_buckets(h) ((h)->n_buckets) /*! @function @abstract Iterate over the entries in the hash table @param h Pointer to the hash table [khash_t(name)*] @param kvar Variable to which key will be assigned @param vvar Variable to which value will be assigned @param code Block of code to execute */ #define kh_foreach(h, kvar, vvar, code) { khint_t __i; \ for (__i = kh_begin(h); __i != kh_end(h); ++__i) { \ if (!kh_exist(h,__i)) continue; \ (kvar) = kh_key(h,__i); \ (vvar) = kh_val(h,__i); \ code; \ } } /*! @function @abstract Iterate over the values in the hash table @param h Pointer to the hash table [khash_t(name)*] @param vvar Variable to which value will be assigned @param code Block of code to execute */ #define kh_foreach_value(h, vvar, code) { khint_t __i; \ for (__i = kh_begin(h); __i != kh_end(h); ++__i) { \ if (!kh_exist(h,__i)) continue; \ (vvar) = kh_val(h,__i); \ code; \ } } /* More conenient interfaces */ /*! @function @abstract Instantiate a hash set containing integer keys @param name Name of the hash table [symbol] */ #define KHASH_SET_INIT_INT(name) \ KHASH_INIT(name, khint32_t, char, 0, kh_int_hash_func, kh_int_hash_equal) /*! @function @abstract Instantiate a hash map containing integer keys @param name Name of the hash table [symbol] @param khval_t Type of values [type] */ #define KHASH_MAP_INIT_INT(name, khval_t) \ KHASH_INIT(name, khint32_t, khval_t, 1, kh_int_hash_func, kh_int_hash_equal) /*! @function @abstract Instantiate a hash map containing 64-bit integer keys @param name Name of the hash table [symbol] */ #define KHASH_SET_INIT_INT64(name) \ KHASH_INIT(name, khint64_t, char, 0, kh_int64_hash_func, kh_int64_hash_equal) /*! @function @abstract Instantiate a hash map containing 64-bit integer keys @param name Name of the hash table [symbol] @param khval_t Type of values [type] */ #define KHASH_MAP_INIT_INT64(name, khval_t) \ KHASH_INIT(name, khint64_t, khval_t, 1, kh_int64_hash_func, kh_int64_hash_equal) typedef const char *kh_cstr_t; /*! @function @abstract Instantiate a hash map containing const char* keys @param name Name of the hash table [symbol] */ #define KHASH_SET_INIT_STR(name) \ KHASH_INIT(name, kh_cstr_t, char, 0, kh_str_hash_func, kh_str_hash_equal) /*! @function @abstract Instantiate a hash map containing const char* keys @param name Name of the hash table [symbol] @param khval_t Type of values [type] */ #define KHASH_MAP_INIT_STR(name, khval_t) \ KHASH_INIT(name, kh_cstr_t, khval_t, 1, kh_str_hash_func, kh_str_hash_equal) #endif /* __AC_KHASH_H */ libgit2-0.19.0/src/map.h000066400000000000000000000022251216214232500146510ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #ifndef INCLUDE_map_h__ #define INCLUDE_map_h__ #include "common.h" /* p_mmap() prot values */ #define GIT_PROT_NONE 0x0 #define GIT_PROT_READ 0x1 #define GIT_PROT_WRITE 0x2 #define GIT_PROT_EXEC 0x4 /* git__mmmap() flags values */ #define GIT_MAP_FILE 0 #define GIT_MAP_SHARED 1 #define GIT_MAP_PRIVATE 2 #define GIT_MAP_TYPE 0xf #define GIT_MAP_FIXED 0x10 #ifdef __amigaos4__ #define MAP_FAILED 0 #endif typedef struct { /* memory mapped buffer */ void *data; /* data bytes */ size_t len; /* data length */ #ifdef GIT_WIN32 HANDLE fmh; /* file mapping handle */ #endif } git_map; #define GIT_MMAP_VALIDATE(out, len, prot, flags) do { \ assert(out != NULL && len > 0); \ assert((prot & GIT_PROT_WRITE) || (prot & GIT_PROT_READ)); \ assert((flags & GIT_MAP_FIXED) == 0); } while (0) extern int p_mmap(git_map *out, size_t len, int prot, int flags, int fd, git_off_t offset); extern int p_munmap(git_map *map); #endif /* INCLUDE_map_h__ */ libgit2-0.19.0/src/merge.c000066400000000000000000001576531216214232500152060ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #include "common.h" #include "posix.h" #include "buffer.h" #include "repository.h" #include "revwalk.h" #include "commit_list.h" #include "merge.h" #include "path.h" #include "refs.h" #include "object.h" #include "iterator.h" #include "refs.h" #include "diff.h" #include "checkout.h" #include "tree.h" #include "merge_file.h" #include "blob.h" #include "hashsig.h" #include "oid.h" #include "index.h" #include "filebuf.h" #include "git2/types.h" #include "git2/repository.h" #include "git2/object.h" #include "git2/commit.h" #include "git2/merge.h" #include "git2/refs.h" #include "git2/reset.h" #include "git2/checkout.h" #include "git2/signature.h" #include "git2/config.h" #include "git2/tree.h" #include "git2/sys/index.h" #define GIT_MERGE_INDEX_ENTRY_EXISTS(X) ((X).mode != 0) typedef enum { TREE_IDX_ANCESTOR = 0, TREE_IDX_OURS = 1, TREE_IDX_THEIRS = 2 } merge_tree_index_t; /* Tracks D/F conflicts */ struct merge_diff_df_data { const char *df_path; const char *prev_path; git_merge_diff *prev_conflict; }; /* Merge base computation */ int git_merge_base_many(git_oid *out, git_repository *repo, const git_oid input_array[], size_t length) { git_revwalk *walk; git_vector list; git_commit_list *result = NULL; int error = -1; unsigned int i; git_commit_list_node *commit; assert(out && repo && input_array); if (length < 2) { giterr_set(GITERR_INVALID, "At least two commits are required to find an ancestor. Provided 'length' was %u.", length); return -1; } if (git_vector_init(&list, length - 1, NULL) < 0) return -1; if (git_revwalk_new(&walk, repo) < 0) goto cleanup; for (i = 1; i < length; i++) { commit = git_revwalk__commit_lookup(walk, &input_array[i]); if (commit == NULL) goto cleanup; git_vector_insert(&list, commit); } commit = git_revwalk__commit_lookup(walk, &input_array[0]); if (commit == NULL) goto cleanup; if (git_merge__bases_many(&result, walk, commit, &list) < 0) goto cleanup; if (!result) { giterr_set(GITERR_MERGE, "No merge base found"); error = GIT_ENOTFOUND; goto cleanup; } git_oid_cpy(out, &result->item->oid); error = 0; cleanup: git_commit_list_free(&result); git_revwalk_free(walk); git_vector_free(&list); return error; } int git_merge_base(git_oid *out, git_repository *repo, const git_oid *one, const git_oid *two) { git_revwalk *walk; git_vector list; git_commit_list *result = NULL; git_commit_list_node *commit; void *contents[1]; if (git_revwalk_new(&walk, repo) < 0) return -1; commit = git_revwalk__commit_lookup(walk, two); if (commit == NULL) goto on_error; /* This is just one value, so we can do it on the stack */ memset(&list, 0x0, sizeof(git_vector)); contents[0] = commit; list.length = 1; list.contents = contents; commit = git_revwalk__commit_lookup(walk, one); if (commit == NULL) goto on_error; if (git_merge__bases_many(&result, walk, commit, &list) < 0) goto on_error; if (!result) { git_revwalk_free(walk); giterr_set(GITERR_MERGE, "No merge base found"); return GIT_ENOTFOUND; } git_oid_cpy(out, &result->item->oid); git_commit_list_free(&result); git_revwalk_free(walk); return 0; on_error: git_revwalk_free(walk); return -1; } static int interesting(git_pqueue *list) { unsigned int i; /* element 0 isn't used - we need to start at 1 */ for (i = 1; i < list->size; i++) { git_commit_list_node *commit = list->d[i]; if ((commit->flags & STALE) == 0) return 1; } return 0; } int git_merge__bases_many(git_commit_list **out, git_revwalk *walk, git_commit_list_node *one, git_vector *twos) { int error; unsigned int i; git_commit_list_node *two; git_commit_list *result = NULL, *tmp = NULL; git_pqueue list; /* if the commit is repeated, we have a our merge base already */ git_vector_foreach(twos, i, two) { if (one == two) return git_commit_list_insert(one, out) ? 0 : -1; } if (git_pqueue_init(&list, twos->length * 2, git_commit_list_time_cmp) < 0) return -1; if (git_commit_list_parse(walk, one) < 0) return -1; one->flags |= PARENT1; if (git_pqueue_insert(&list, one) < 0) return -1; git_vector_foreach(twos, i, two) { git_commit_list_parse(walk, two); two->flags |= PARENT2; if (git_pqueue_insert(&list, two) < 0) return -1; } /* as long as there are non-STALE commits */ while (interesting(&list)) { git_commit_list_node *commit; int flags; commit = git_pqueue_pop(&list); flags = commit->flags & (PARENT1 | PARENT2 | STALE); if (flags == (PARENT1 | PARENT2)) { if (!(commit->flags & RESULT)) { commit->flags |= RESULT; if (git_commit_list_insert(commit, &result) == NULL) return -1; } /* we mark the parents of a merge stale */ flags |= STALE; } for (i = 0; i < commit->out_degree; i++) { git_commit_list_node *p = commit->parents[i]; if ((p->flags & flags) == flags) continue; if ((error = git_commit_list_parse(walk, p)) < 0) return error; p->flags |= flags; if (git_pqueue_insert(&list, p) < 0) return -1; } } git_pqueue_free(&list); /* filter out any stale commits in the results */ tmp = result; result = NULL; while (tmp) { struct git_commit_list *next = tmp->next; if (!(tmp->item->flags & STALE)) if (git_commit_list_insert_by_date(tmp->item, &result) == NULL) return -1; git__free(tmp); tmp = next; } *out = result; return 0; } int git_repository_mergehead_foreach(git_repository *repo, git_repository_mergehead_foreach_cb cb, void *payload) { git_buf merge_head_path = GIT_BUF_INIT, merge_head_file = GIT_BUF_INIT; char *buffer, *line; size_t line_num = 1; git_oid oid; int error = 0; assert(repo && cb); if ((error = git_buf_joinpath(&merge_head_path, repo->path_repository, GIT_MERGE_HEAD_FILE)) < 0) return error; if ((error = git_futils_readbuffer(&merge_head_file, git_buf_cstr(&merge_head_path))) < 0) goto cleanup; buffer = merge_head_file.ptr; while ((line = git__strsep(&buffer, "\n")) != NULL) { if (strlen(line) != GIT_OID_HEXSZ) { giterr_set(GITERR_INVALID, "Unable to parse OID - invalid length"); error = -1; goto cleanup; } if ((error = git_oid_fromstr(&oid, line)) < 0) goto cleanup; if (cb(&oid, payload) < 0) { error = GIT_EUSER; goto cleanup; } ++line_num; } if (*buffer) { giterr_set(GITERR_MERGE, "No EOL at line %d", line_num); error = -1; goto cleanup; } cleanup: git_buf_free(&merge_head_path); git_buf_free(&merge_head_file); return error; } GIT_INLINE(int) index_entry_cmp(const git_index_entry *a, const git_index_entry *b) { int value = 0; if (a->path == NULL) return (b->path == NULL) ? 0 : 1; if ((value = a->mode - b->mode) == 0 && (value = git_oid__cmp(&a->oid, &b->oid)) == 0) value = strcmp(a->path, b->path); return value; } /* Conflict resolution */ static int merge_conflict_resolve_trivial( int *resolved, git_merge_diff_list *diff_list, const git_merge_diff *conflict) { int ours_empty, theirs_empty; int ours_changed, theirs_changed, ours_theirs_differ; git_index_entry const *result = NULL; int error = 0; assert(resolved && diff_list && conflict); *resolved = 0; if (conflict->type == GIT_MERGE_DIFF_DIRECTORY_FILE || conflict->type == GIT_MERGE_DIFF_RENAMED_ADDED) return 0; if (conflict->our_status == GIT_DELTA_RENAMED || conflict->their_status == GIT_DELTA_RENAMED) return 0; ours_empty = !GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->our_entry); theirs_empty = !GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->their_entry); ours_changed = (conflict->our_status != GIT_DELTA_UNMODIFIED); theirs_changed = (conflict->their_status != GIT_DELTA_UNMODIFIED); ours_theirs_differ = ours_changed && theirs_changed && index_entry_cmp(&conflict->our_entry, &conflict->their_entry); /* * Note: with only one ancestor, some cases are not distinct: * * 16: ancest:anc1/anc2, head:anc1, remote:anc2 = result:no merge * 3: ancest:(empty)^, head:head, remote:(empty) = result:no merge * 2: ancest:(empty)^, head:(empty), remote:remote = result:no merge * * Note that the two cases that take D/F conflicts into account * specifically do not need to be explicitly tested, as D/F conflicts * would fail the *empty* test: * * 3ALT: ancest:(empty)+, head:head, remote:*empty* = result:head * 2ALT: ancest:(empty)+, head:*empty*, remote:remote = result:remote * * Note that many of these cases need not be explicitly tested, as * they simply degrade to "all different" cases (eg, 11): * * 4: ancest:(empty)^, head:head, remote:remote = result:no merge * 7: ancest:ancest+, head:(empty), remote:remote = result:no merge * 9: ancest:ancest+, head:head, remote:(empty) = result:no merge * 11: ancest:ancest+, head:head, remote:remote = result:no merge */ /* 5ALT: ancest:*, head:head, remote:head = result:head */ if (ours_changed && !ours_empty && !ours_theirs_differ) result = &conflict->our_entry; /* 6: ancest:ancest+, head:(empty), remote:(empty) = result:no merge */ else if (ours_changed && ours_empty && theirs_empty) *resolved = 0; /* 8: ancest:ancest^, head:(empty), remote:ancest = result:no merge */ else if (ours_empty && !theirs_changed) *resolved = 0; /* 10: ancest:ancest^, head:ancest, remote:(empty) = result:no merge */ else if (!ours_changed && theirs_empty) *resolved = 0; /* 13: ancest:ancest+, head:head, remote:ancest = result:head */ else if (ours_changed && !theirs_changed) result = &conflict->our_entry; /* 14: ancest:ancest+, head:ancest, remote:remote = result:remote */ else if (!ours_changed && theirs_changed) result = &conflict->their_entry; else *resolved = 0; if (result != NULL && GIT_MERGE_INDEX_ENTRY_EXISTS(*result) && (error = git_vector_insert(&diff_list->staged, (void *)result)) >= 0) *resolved = 1; /* Note: trivial resolution does not update the REUC. */ return error; } static int merge_conflict_resolve_one_removed( int *resolved, git_merge_diff_list *diff_list, const git_merge_diff *conflict) { int ours_empty, theirs_empty; int ours_changed, theirs_changed; int error = 0; assert(resolved && diff_list && conflict); *resolved = 0; if (conflict->type == GIT_MERGE_DIFF_DIRECTORY_FILE || conflict->type == GIT_MERGE_DIFF_RENAMED_ADDED) return 0; ours_empty = !GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->our_entry); theirs_empty = !GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->their_entry); ours_changed = (conflict->our_status != GIT_DELTA_UNMODIFIED); theirs_changed = (conflict->their_status != GIT_DELTA_UNMODIFIED); /* Removed in both */ if (ours_changed && ours_empty && theirs_empty) *resolved = 1; /* Removed in ours */ else if (ours_empty && !theirs_changed) *resolved = 1; /* Removed in theirs */ else if (!ours_changed && theirs_empty) *resolved = 1; if (*resolved) git_vector_insert(&diff_list->resolved, (git_merge_diff *)conflict); return error; } static int merge_conflict_resolve_one_renamed( int *resolved, git_merge_diff_list *diff_list, const git_merge_diff *conflict) { int ours_renamed, theirs_renamed; int ours_changed, theirs_changed; git_index_entry *merged; int error = 0; assert(resolved && diff_list && conflict); *resolved = 0; if (!GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->our_entry) || !GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->their_entry)) return 0; ours_renamed = (conflict->our_status == GIT_DELTA_RENAMED); theirs_renamed = (conflict->their_status == GIT_DELTA_RENAMED); if (!ours_renamed && !theirs_renamed) return 0; /* Reject one file in a 2->1 conflict */ if (conflict->type == GIT_MERGE_DIFF_BOTH_RENAMED_2_TO_1 || conflict->type == GIT_MERGE_DIFF_BOTH_RENAMED_1_TO_2 || conflict->type == GIT_MERGE_DIFF_RENAMED_ADDED) return 0; ours_changed = (git_oid__cmp(&conflict->ancestor_entry.oid, &conflict->our_entry.oid) != 0); theirs_changed = (git_oid__cmp(&conflict->ancestor_entry.oid, &conflict->their_entry.oid) != 0); /* if both are modified (and not to a common target) require a merge */ if (ours_changed && theirs_changed && git_oid__cmp(&conflict->our_entry.oid, &conflict->their_entry.oid) != 0) return 0; if ((merged = git_pool_malloc(&diff_list->pool, sizeof(git_index_entry))) == NULL) return -1; if (ours_changed) memcpy(merged, &conflict->our_entry, sizeof(git_index_entry)); else memcpy(merged, &conflict->their_entry, sizeof(git_index_entry)); if (ours_renamed) merged->path = conflict->our_entry.path; else merged->path = conflict->their_entry.path; *resolved = 1; git_vector_insert(&diff_list->staged, merged); git_vector_insert(&diff_list->resolved, (git_merge_diff *)conflict); return error; } static int merge_conflict_resolve_automerge( int *resolved, git_merge_diff_list *diff_list, const git_merge_diff *conflict, unsigned int automerge_flags) { git_merge_file_input ancestor = GIT_MERGE_FILE_INPUT_INIT, ours = GIT_MERGE_FILE_INPUT_INIT, theirs = GIT_MERGE_FILE_INPUT_INIT; git_merge_file_result result = GIT_MERGE_FILE_RESULT_INIT; git_index_entry *index_entry; git_odb *odb = NULL; git_oid automerge_oid; int error = 0; assert(resolved && diff_list && conflict); *resolved = 0; if (automerge_flags == GIT_MERGE_AUTOMERGE_NONE) return 0; /* Reject D/F conflicts */ if (conflict->type == GIT_MERGE_DIFF_DIRECTORY_FILE) return 0; /* Reject link/file conflicts. */ if ((S_ISLNK(conflict->ancestor_entry.mode) ^ S_ISLNK(conflict->our_entry.mode)) || (S_ISLNK(conflict->ancestor_entry.mode) ^ S_ISLNK(conflict->their_entry.mode))) return 0; /* Reject name conflicts */ if (conflict->type == GIT_MERGE_DIFF_BOTH_RENAMED_2_TO_1 || conflict->type == GIT_MERGE_DIFF_RENAMED_ADDED) return 0; if ((conflict->our_status & GIT_DELTA_RENAMED) == GIT_DELTA_RENAMED && (conflict->their_status & GIT_DELTA_RENAMED) == GIT_DELTA_RENAMED && strcmp(conflict->ancestor_entry.path, conflict->their_entry.path) != 0) return 0; if ((error = git_repository_odb(&odb, diff_list->repo)) < 0 || (error = git_merge_file_input_from_index_entry(&ancestor, diff_list->repo, &conflict->ancestor_entry)) < 0 || (error = git_merge_file_input_from_index_entry(&ours, diff_list->repo, &conflict->our_entry)) < 0 || (error = git_merge_file_input_from_index_entry(&theirs, diff_list->repo, &conflict->their_entry)) < 0 || (error = git_merge_files(&result, &ancestor, &ours, &theirs, automerge_flags)) < 0 || !result.automergeable || (error = git_odb_write(&automerge_oid, odb, result.data, result.len, GIT_OBJ_BLOB)) < 0) goto done; if ((index_entry = git_pool_malloc(&diff_list->pool, sizeof(git_index_entry))) == NULL) GITERR_CHECK_ALLOC(index_entry); index_entry->path = git_pool_strdup(&diff_list->pool, result.path); GITERR_CHECK_ALLOC(index_entry->path); index_entry->file_size = result.len; index_entry->mode = result.mode; git_oid_cpy(&index_entry->oid, &automerge_oid); git_vector_insert(&diff_list->staged, index_entry); git_vector_insert(&diff_list->resolved, (git_merge_diff *)conflict); *resolved = 1; done: git_merge_file_input_free(&ancestor); git_merge_file_input_free(&ours); git_merge_file_input_free(&theirs); git_merge_file_result_free(&result); git_odb_free(odb); return error; } static int merge_conflict_resolve( int *out, git_merge_diff_list *diff_list, const git_merge_diff *conflict, unsigned int automerge_flags) { int resolved = 0; int error = 0; *out = 0; if ((error = merge_conflict_resolve_trivial(&resolved, diff_list, conflict)) < 0) goto done; if (automerge_flags != GIT_MERGE_AUTOMERGE_NONE) { if (!resolved && (error = merge_conflict_resolve_one_removed(&resolved, diff_list, conflict)) < 0) goto done; if (!resolved && (error = merge_conflict_resolve_one_renamed(&resolved, diff_list, conflict)) < 0) goto done; if (!resolved && (error = merge_conflict_resolve_automerge(&resolved, diff_list, conflict, automerge_flags)) < 0) goto done; } *out = resolved; done: return error; } /* Rename detection and coalescing */ struct merge_diff_similarity { unsigned char similarity; size_t other_idx; }; static int index_entry_similarity_exact( git_repository *repo, git_index_entry *a, size_t a_idx, git_index_entry *b, size_t b_idx, void **cache, const git_merge_tree_opts *opts) { GIT_UNUSED(repo); GIT_UNUSED(a_idx); GIT_UNUSED(b_idx); GIT_UNUSED(cache); GIT_UNUSED(opts); if (git_oid__cmp(&a->oid, &b->oid) == 0) return 100; return 0; } static int index_entry_similarity_calc( void **out, git_repository *repo, git_index_entry *entry, const git_merge_tree_opts *opts) { git_blob *blob; git_diff_file diff_file = {{{0}}}; git_off_t blobsize; int error; *out = NULL; if ((error = git_blob_lookup(&blob, repo, &entry->oid)) < 0) return error; git_oid_cpy(&diff_file.oid, &entry->oid); diff_file.path = entry->path; diff_file.size = entry->file_size; diff_file.mode = entry->mode; diff_file.flags = 0; blobsize = git_blob_rawsize(blob); /* file too big for rename processing */ if (!git__is_sizet(blobsize)) return 0; error = opts->metric->buffer_signature(out, &diff_file, git_blob_rawcontent(blob), (size_t)blobsize, opts->metric->payload); git_blob_free(blob); return error; } static int index_entry_similarity_inexact( git_repository *repo, git_index_entry *a, size_t a_idx, git_index_entry *b, size_t b_idx, void **cache, const git_merge_tree_opts *opts) { int score = 0; int error = 0; if (GIT_MODE_TYPE(a->mode) != GIT_MODE_TYPE(b->mode)) return 0; /* update signature cache if needed */ if (!cache[a_idx] && (error = index_entry_similarity_calc(&cache[a_idx], repo, a, opts)) < 0) return error; if (!cache[b_idx] && (error = index_entry_similarity_calc(&cache[b_idx], repo, b, opts)) < 0) return error; /* some metrics may not wish to process this file (too big / too small) */ if (!cache[a_idx] || !cache[b_idx]) return 0; /* compare signatures */ if (opts->metric->similarity( &score, cache[a_idx], cache[b_idx], opts->metric->payload) < 0) return -1; /* clip score */ if (score < 0) score = 0; else if (score > 100) score = 100; return score; } static int merge_diff_mark_similarity( git_repository *repo, git_merge_diff_list *diff_list, struct merge_diff_similarity *similarity_ours, struct merge_diff_similarity *similarity_theirs, int (*similarity_fn)(git_repository *, git_index_entry *, size_t, git_index_entry *, size_t, void **, const git_merge_tree_opts *), void **cache, const git_merge_tree_opts *opts) { size_t i, j; git_merge_diff *conflict_src, *conflict_tgt; int similarity; git_vector_foreach(&diff_list->conflicts, i, conflict_src) { /* Items can be the source of a rename iff they have an item in the * ancestor slot and lack an item in the ours or theirs slot. */ if (!GIT_MERGE_INDEX_ENTRY_EXISTS(conflict_src->ancestor_entry) || (GIT_MERGE_INDEX_ENTRY_EXISTS(conflict_src->our_entry) && GIT_MERGE_INDEX_ENTRY_EXISTS(conflict_src->their_entry))) continue; git_vector_foreach(&diff_list->conflicts, j, conflict_tgt) { size_t our_idx = diff_list->conflicts.length + j; size_t their_idx = (diff_list->conflicts.length * 2) + j; if (GIT_MERGE_INDEX_ENTRY_EXISTS(conflict_tgt->ancestor_entry)) continue; if (GIT_MERGE_INDEX_ENTRY_EXISTS(conflict_tgt->our_entry) && !GIT_MERGE_INDEX_ENTRY_EXISTS(conflict_src->our_entry)) { similarity = similarity_fn(repo, &conflict_src->ancestor_entry, i, &conflict_tgt->our_entry, our_idx, cache, opts); if (similarity == GIT_EBUFS) continue; else if (similarity < 0) return similarity; if (similarity > similarity_ours[i].similarity && similarity > similarity_ours[j].similarity) { /* Clear previous best similarity */ if (similarity_ours[i].similarity > 0) similarity_ours[similarity_ours[i].other_idx].similarity = 0; if (similarity_ours[j].similarity > 0) similarity_ours[similarity_ours[j].other_idx].similarity = 0; similarity_ours[i].similarity = similarity; similarity_ours[i].other_idx = j; similarity_ours[j].similarity = similarity; similarity_ours[j].other_idx = i; } } if (GIT_MERGE_INDEX_ENTRY_EXISTS(conflict_tgt->their_entry) && !GIT_MERGE_INDEX_ENTRY_EXISTS(conflict_src->their_entry)) { similarity = similarity_fn(repo, &conflict_src->ancestor_entry, i, &conflict_tgt->their_entry, their_idx, cache, opts); if (similarity > similarity_theirs[i].similarity && similarity > similarity_theirs[j].similarity) { /* Clear previous best similarity */ if (similarity_theirs[i].similarity > 0) similarity_theirs[similarity_theirs[i].other_idx].similarity = 0; if (similarity_theirs[j].similarity > 0) similarity_theirs[similarity_theirs[j].other_idx].similarity = 0; similarity_theirs[i].similarity = similarity; similarity_theirs[i].other_idx = j; similarity_theirs[j].similarity = similarity; similarity_theirs[j].other_idx = i; } } } } return 0; } /* * Rename conflicts: * * Ancestor Ours Theirs * * 0a A A A No rename * b A A* A No rename (ours was rewritten) * c A A A* No rename (theirs rewritten) * 1a A A B[A] Rename or rename/edit * b A B[A] A (automergeable) * 2 A B[A] B[A] Both renamed (automergeable) * 3a A B[A] Rename/delete * b A B[A] (same) * 4a A B[A] B Rename/add [B~ours B~theirs] * b A B B[A] (same) * 5 A B[A] C[A] Both renamed ("1 -> 2") * 6 A C[A] Both renamed ("2 -> 1") * B C[B] [C~ours C~theirs] (automergeable) */ static void merge_diff_mark_rename_conflict( git_merge_diff_list *diff_list, struct merge_diff_similarity *similarity_ours, bool ours_renamed, size_t ours_source_idx, struct merge_diff_similarity *similarity_theirs, bool theirs_renamed, size_t theirs_source_idx, git_merge_diff *target, const git_merge_tree_opts *opts) { git_merge_diff *ours_source = NULL, *theirs_source = NULL; if (ours_renamed) ours_source = diff_list->conflicts.contents[ours_source_idx]; if (theirs_renamed) theirs_source = diff_list->conflicts.contents[theirs_source_idx]; /* Detect 2->1 conflicts */ if (ours_renamed && theirs_renamed) { /* Both renamed to the same target name. */ if (ours_source_idx == theirs_source_idx) ours_source->type = GIT_MERGE_DIFF_BOTH_RENAMED; else { ours_source->type = GIT_MERGE_DIFF_BOTH_RENAMED_2_TO_1; theirs_source->type = GIT_MERGE_DIFF_BOTH_RENAMED_2_TO_1; } } else if (ours_renamed) { /* If our source was also renamed in theirs, this is a 1->2 */ if (similarity_theirs[ours_source_idx].similarity >= opts->rename_threshold) ours_source->type = GIT_MERGE_DIFF_BOTH_RENAMED_1_TO_2; else if (GIT_MERGE_INDEX_ENTRY_EXISTS(target->their_entry)) { ours_source->type = GIT_MERGE_DIFF_RENAMED_ADDED; target->type = GIT_MERGE_DIFF_RENAMED_ADDED; } else if (!GIT_MERGE_INDEX_ENTRY_EXISTS(ours_source->their_entry)) ours_source->type = GIT_MERGE_DIFF_RENAMED_DELETED; else if (ours_source->type == GIT_MERGE_DIFF_MODIFIED_DELETED) ours_source->type = GIT_MERGE_DIFF_RENAMED_MODIFIED; } else if (theirs_renamed) { /* If their source was also renamed in ours, this is a 1->2 */ if (similarity_ours[theirs_source_idx].similarity >= opts->rename_threshold) theirs_source->type = GIT_MERGE_DIFF_BOTH_RENAMED_1_TO_2; else if (GIT_MERGE_INDEX_ENTRY_EXISTS(target->our_entry)) { theirs_source->type = GIT_MERGE_DIFF_RENAMED_ADDED; target->type = GIT_MERGE_DIFF_RENAMED_ADDED; } else if (!GIT_MERGE_INDEX_ENTRY_EXISTS(theirs_source->our_entry)) theirs_source->type = GIT_MERGE_DIFF_RENAMED_DELETED; else if (theirs_source->type == GIT_MERGE_DIFF_MODIFIED_DELETED) theirs_source->type = GIT_MERGE_DIFF_RENAMED_MODIFIED; } } GIT_INLINE(void) merge_diff_coalesce_rename( git_index_entry *source_entry, git_delta_t *source_status, git_index_entry *target_entry, git_delta_t *target_status) { /* Coalesce the rename target into the rename source. */ memcpy(source_entry, target_entry, sizeof(git_index_entry)); *source_status = GIT_DELTA_RENAMED; memset(target_entry, 0x0, sizeof(git_index_entry)); *target_status = GIT_DELTA_UNMODIFIED; } static void merge_diff_list_coalesce_renames( git_merge_diff_list *diff_list, struct merge_diff_similarity *similarity_ours, struct merge_diff_similarity *similarity_theirs, const git_merge_tree_opts *opts) { size_t i; bool ours_renamed = 0, theirs_renamed = 0; size_t ours_source_idx = 0, theirs_source_idx = 0; git_merge_diff *ours_source, *theirs_source, *target; for (i = 0; i < diff_list->conflicts.length; i++) { target = diff_list->conflicts.contents[i]; ours_renamed = 0; theirs_renamed = 0; if (GIT_MERGE_INDEX_ENTRY_EXISTS(target->our_entry) && similarity_ours[i].similarity >= opts->rename_threshold) { ours_source_idx = similarity_ours[i].other_idx; ours_source = diff_list->conflicts.contents[ours_source_idx]; merge_diff_coalesce_rename( &ours_source->our_entry, &ours_source->our_status, &target->our_entry, &target->our_status); similarity_ours[ours_source_idx].similarity = 0; similarity_ours[i].similarity = 0; ours_renamed = 1; } /* insufficient to determine direction */ if (GIT_MERGE_INDEX_ENTRY_EXISTS(target->their_entry) && similarity_theirs[i].similarity >= opts->rename_threshold) { theirs_source_idx = similarity_theirs[i].other_idx; theirs_source = diff_list->conflicts.contents[theirs_source_idx]; merge_diff_coalesce_rename( &theirs_source->their_entry, &theirs_source->their_status, &target->their_entry, &target->their_status); similarity_theirs[theirs_source_idx].similarity = 0; similarity_theirs[i].similarity = 0; theirs_renamed = 1; } merge_diff_mark_rename_conflict(diff_list, similarity_ours, ours_renamed, ours_source_idx, similarity_theirs, theirs_renamed, theirs_source_idx, target, opts); } } static int merge_diff_empty(const git_vector *conflicts, size_t idx) { git_merge_diff *conflict = conflicts->contents[idx]; return (!GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->ancestor_entry) && !GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->our_entry) && !GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->their_entry)); } static void merge_diff_list_count_candidates( git_merge_diff_list *diff_list, size_t *src_count, size_t *tgt_count) { git_merge_diff *entry; size_t i; *src_count = 0; *tgt_count = 0; git_vector_foreach(&diff_list->conflicts, i, entry) { if (GIT_MERGE_INDEX_ENTRY_EXISTS(entry->ancestor_entry) && (!GIT_MERGE_INDEX_ENTRY_EXISTS(entry->our_entry) || !GIT_MERGE_INDEX_ENTRY_EXISTS(entry->their_entry))) src_count++; else if (!GIT_MERGE_INDEX_ENTRY_EXISTS(entry->ancestor_entry)) tgt_count++; } } int git_merge_diff_list__find_renames( git_repository *repo, git_merge_diff_list *diff_list, const git_merge_tree_opts *opts) { struct merge_diff_similarity *similarity_ours, *similarity_theirs; void **cache = NULL; size_t cache_size = 0; size_t src_count, tgt_count, i; int error = 0; assert(diff_list && opts); if ((opts->flags & GIT_MERGE_TREE_FIND_RENAMES) == 0) return 0; similarity_ours = git__calloc(diff_list->conflicts.length, sizeof(struct merge_diff_similarity)); GITERR_CHECK_ALLOC(similarity_ours); similarity_theirs = git__calloc(diff_list->conflicts.length, sizeof(struct merge_diff_similarity)); GITERR_CHECK_ALLOC(similarity_theirs); /* Calculate similarity between items that were deleted from the ancestor * and added in the other branch. */ if ((error = merge_diff_mark_similarity(repo, diff_list, similarity_ours, similarity_theirs, index_entry_similarity_exact, NULL, opts)) < 0) goto done; if (diff_list->conflicts.length <= opts->target_limit) { cache_size = diff_list->conflicts.length * 3; cache = git__calloc(cache_size, sizeof(void *)); GITERR_CHECK_ALLOC(cache); merge_diff_list_count_candidates(diff_list, &src_count, &tgt_count); if (src_count > opts->target_limit || tgt_count > opts->target_limit) { /* TODO: report! */ } else { if ((error = merge_diff_mark_similarity( repo, diff_list, similarity_ours, similarity_theirs, index_entry_similarity_inexact, cache, opts)) < 0) goto done; } } /* For entries that are appropriately similar, merge the new name's entry * into the old name. */ merge_diff_list_coalesce_renames(diff_list, similarity_ours, similarity_theirs, opts); /* And remove any entries that were merged and are now empty. */ git_vector_remove_matching(&diff_list->conflicts, merge_diff_empty); done: if (cache != NULL) { for (i = 0; i < cache_size; ++i) { if (cache[i] != NULL) opts->metric->free_signature(cache[i], opts->metric->payload); } git__free(cache); } git__free(similarity_ours); git__free(similarity_theirs); return error; } /* Directory/file conflict handling */ GIT_INLINE(const char *) merge_diff_path( const git_merge_diff *conflict) { if (GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->ancestor_entry)) return conflict->ancestor_entry.path; else if (GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->our_entry)) return conflict->our_entry.path; else if (GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->their_entry)) return conflict->their_entry.path; return NULL; } GIT_INLINE(bool) merge_diff_any_side_added_or_modified( const git_merge_diff *conflict) { if (conflict->our_status == GIT_DELTA_ADDED || conflict->our_status == GIT_DELTA_MODIFIED || conflict->their_status == GIT_DELTA_ADDED || conflict->their_status == GIT_DELTA_MODIFIED) return true; return false; } GIT_INLINE(bool) path_is_prefixed(const char *parent, const char *child) { size_t child_len = strlen(child); size_t parent_len = strlen(parent); if (child_len < parent_len || strncmp(parent, child, parent_len) != 0) return 0; return (child[parent_len] == '/'); } GIT_INLINE(int) merge_diff_detect_df_conflict( struct merge_diff_df_data *df_data, git_merge_diff *conflict) { const char *cur_path = merge_diff_path(conflict); /* Determine if this is a D/F conflict or the child of one */ if (df_data->df_path && path_is_prefixed(df_data->df_path, cur_path)) conflict->type = GIT_MERGE_DIFF_DF_CHILD; else if(df_data->df_path) df_data->df_path = NULL; else if (df_data->prev_path && merge_diff_any_side_added_or_modified(df_data->prev_conflict) && merge_diff_any_side_added_or_modified(conflict) && path_is_prefixed(df_data->prev_path, cur_path)) { conflict->type = GIT_MERGE_DIFF_DF_CHILD; df_data->prev_conflict->type = GIT_MERGE_DIFF_DIRECTORY_FILE; df_data->df_path = df_data->prev_path; } df_data->prev_path = cur_path; df_data->prev_conflict = conflict; return 0; } /* Conflict handling */ GIT_INLINE(int) merge_diff_detect_type( git_merge_diff *conflict) { if (conflict->our_status == GIT_DELTA_ADDED && conflict->their_status == GIT_DELTA_ADDED) conflict->type = GIT_MERGE_DIFF_BOTH_ADDED; else if (conflict->our_status == GIT_DELTA_MODIFIED && conflict->their_status == GIT_DELTA_MODIFIED) conflict->type = GIT_MERGE_DIFF_BOTH_MODIFIED; else if (conflict->our_status == GIT_DELTA_DELETED && conflict->their_status == GIT_DELTA_DELETED) conflict->type = GIT_MERGE_DIFF_BOTH_DELETED; else if (conflict->our_status == GIT_DELTA_MODIFIED && conflict->their_status == GIT_DELTA_DELETED) conflict->type = GIT_MERGE_DIFF_MODIFIED_DELETED; else if (conflict->our_status == GIT_DELTA_DELETED && conflict->their_status == GIT_DELTA_MODIFIED) conflict->type = GIT_MERGE_DIFF_MODIFIED_DELETED; else conflict->type = GIT_MERGE_DIFF_NONE; return 0; } GIT_INLINE(int) index_entry_dup( git_index_entry *out, git_pool *pool, const git_index_entry *src) { if (src != NULL) { memcpy(out, src, sizeof(git_index_entry)); if ((out->path = git_pool_strdup(pool, src->path)) == NULL) return -1; } return 0; } GIT_INLINE(int) merge_delta_type_from_index_entries( const git_index_entry *ancestor, const git_index_entry *other) { if (ancestor == NULL && other == NULL) return GIT_DELTA_UNMODIFIED; else if (ancestor == NULL && other != NULL) return GIT_DELTA_ADDED; else if (ancestor != NULL && other == NULL) return GIT_DELTA_DELETED; else if (S_ISDIR(ancestor->mode) ^ S_ISDIR(other->mode)) return GIT_DELTA_TYPECHANGE; else if(S_ISLNK(ancestor->mode) ^ S_ISLNK(other->mode)) return GIT_DELTA_TYPECHANGE; else if (git_oid__cmp(&ancestor->oid, &other->oid) || ancestor->mode != other->mode) return GIT_DELTA_MODIFIED; return GIT_DELTA_UNMODIFIED; } static git_merge_diff *merge_diff_from_index_entries( git_merge_diff_list *diff_list, const git_index_entry **entries) { git_merge_diff *conflict; git_pool *pool = &diff_list->pool; if ((conflict = git_pool_malloc(pool, sizeof(git_merge_diff))) == NULL) return NULL; if (index_entry_dup(&conflict->ancestor_entry, pool, entries[TREE_IDX_ANCESTOR]) < 0 || index_entry_dup(&conflict->our_entry, pool, entries[TREE_IDX_OURS]) < 0 || index_entry_dup(&conflict->their_entry, pool, entries[TREE_IDX_THEIRS]) < 0) return NULL; conflict->our_status = merge_delta_type_from_index_entries( entries[TREE_IDX_ANCESTOR], entries[TREE_IDX_OURS]); conflict->their_status = merge_delta_type_from_index_entries( entries[TREE_IDX_ANCESTOR], entries[TREE_IDX_THEIRS]); return conflict; } /* Merge trees */ static int merge_index_insert_conflict( git_merge_diff_list *diff_list, struct merge_diff_df_data *merge_df_data, const git_index_entry *tree_items[3]) { git_merge_diff *conflict; if ((conflict = merge_diff_from_index_entries(diff_list, tree_items)) == NULL || merge_diff_detect_type(conflict) < 0 || merge_diff_detect_df_conflict(merge_df_data, conflict) < 0 || git_vector_insert(&diff_list->conflicts, conflict) < 0) return -1; return 0; } static int merge_index_insert_unmodified( git_merge_diff_list *diff_list, const git_index_entry *tree_items[3]) { int error = 0; git_index_entry *entry; entry = git_pool_malloc(&diff_list->pool, sizeof(git_index_entry)); GITERR_CHECK_ALLOC(entry); if ((error = index_entry_dup(entry, &diff_list->pool, tree_items[0])) >= 0) error = git_vector_insert(&diff_list->staged, entry); return error; } int git_merge_diff_list__find_differences( git_merge_diff_list *diff_list, const git_tree *ancestor_tree, const git_tree *our_tree, const git_tree *their_tree) { git_iterator *iterators[3] = {0}; const git_index_entry *items[3] = {0}, *best_cur_item, *cur_items[3]; git_vector_cmp entry_compare = git_index_entry__cmp; struct merge_diff_df_data df_data = {0}; int cur_item_modified; size_t i, j; int error = 0; assert(diff_list && our_tree && their_tree); if ((error = git_iterator_for_tree(&iterators[TREE_IDX_ANCESTOR], (git_tree *)ancestor_tree, GIT_ITERATOR_DONT_IGNORE_CASE, NULL, NULL)) < 0 || (error = git_iterator_for_tree(&iterators[TREE_IDX_OURS], (git_tree *)our_tree, GIT_ITERATOR_DONT_IGNORE_CASE, NULL, NULL)) < 0 || (error = git_iterator_for_tree(&iterators[TREE_IDX_THEIRS], (git_tree *)their_tree, GIT_ITERATOR_DONT_IGNORE_CASE, NULL, NULL)) < 0) goto done; /* Set up the iterators */ for (i = 0; i < 3; i++) { error = git_iterator_current(&items[i], iterators[i]); if (error < 0 && error != GIT_ITEROVER) goto done; } while (true) { for (i = 0; i < 3; i++) cur_items[i] = NULL; best_cur_item = NULL; cur_item_modified = 0; /* Find the next path(s) to consume from each iterator */ for (i = 0; i < 3; i++) { if (items[i] == NULL) { cur_item_modified = 1; continue; } if (best_cur_item == NULL) { best_cur_item = items[i]; cur_items[i] = items[i]; } else { int path_diff = entry_compare(items[i], best_cur_item); if (path_diff < 0) { /* * Found an item that sorts before our current item, make * our current item this one. */ for (j = 0; j < i; j++) cur_items[j] = NULL; cur_item_modified = 1; best_cur_item = items[i]; cur_items[i] = items[i]; } else if (path_diff > 0) { /* No entry for the current item, this is modified */ cur_item_modified = 1; } else if (path_diff == 0) { cur_items[i] = items[i]; if (!cur_item_modified) cur_item_modified = index_entry_cmp(best_cur_item, items[i]); } } } if (best_cur_item == NULL) break; if (cur_item_modified) error = merge_index_insert_conflict(diff_list, &df_data, cur_items); else error = merge_index_insert_unmodified(diff_list, cur_items); if (error < 0) goto done; /* Advance each iterator that participated */ for (i = 0; i < 3; i++) { if (cur_items[i] == NULL) continue; error = git_iterator_advance(&items[i], iterators[i]); if (error < 0 && error != GIT_ITEROVER) goto done; } } done: for (i = 0; i < 3; i++) git_iterator_free(iterators[i]); if (error == GIT_ITEROVER) error = 0; return error; } git_merge_diff_list *git_merge_diff_list__alloc(git_repository *repo) { git_merge_diff_list *diff_list = git__calloc(1, sizeof(git_merge_diff_list)); if (diff_list == NULL) return NULL; diff_list->repo = repo; if (git_vector_init(&diff_list->staged, 0, NULL) < 0 || git_vector_init(&diff_list->conflicts, 0, NULL) < 0 || git_vector_init(&diff_list->resolved, 0, NULL) < 0 || git_pool_init(&diff_list->pool, 1, 0) < 0) return NULL; return diff_list; } void git_merge_diff_list__free(git_merge_diff_list *diff_list) { if (!diff_list) return; git_vector_free(&diff_list->staged); git_vector_free(&diff_list->conflicts); git_vector_free(&diff_list->resolved); git_pool_clear(&diff_list->pool); git__free(diff_list); } static int merge_tree_normalize_opts( git_repository *repo, git_merge_tree_opts *opts, const git_merge_tree_opts *given) { git_config *cfg = NULL; int error = 0; assert(repo && opts); if ((error = git_repository_config__weakptr(&cfg, repo)) < 0) return error; if (given != NULL) memcpy(opts, given, sizeof(git_merge_tree_opts)); else { git_merge_tree_opts init = GIT_MERGE_TREE_OPTS_INIT; memcpy(opts, &init, sizeof(init)); opts->flags = GIT_MERGE_TREE_FIND_RENAMES; opts->rename_threshold = GIT_MERGE_TREE_RENAME_THRESHOLD; } if (!opts->target_limit) { int32_t limit = 0; opts->target_limit = GIT_MERGE_TREE_TARGET_LIMIT; if (git_config_get_int32(&limit, cfg, "merge.renameLimit") < 0) { giterr_clear(); if (git_config_get_int32(&limit, cfg, "diff.renameLimit") < 0) giterr_clear(); } if (limit > 0) opts->target_limit = limit; } /* assign the internal metric with whitespace flag as payload */ if (!opts->metric) { opts->metric = git__malloc(sizeof(git_diff_similarity_metric)); GITERR_CHECK_ALLOC(opts->metric); opts->metric->file_signature = git_diff_find_similar__hashsig_for_file; opts->metric->buffer_signature = git_diff_find_similar__hashsig_for_buf; opts->metric->free_signature = git_diff_find_similar__hashsig_free; opts->metric->similarity = git_diff_find_similar__calc_similarity; if (opts->flags & GIT_DIFF_FIND_IGNORE_WHITESPACE) opts->metric->payload = (void *)GIT_HASHSIG_IGNORE_WHITESPACE; else if (opts->flags & GIT_DIFF_FIND_DONT_IGNORE_WHITESPACE) opts->metric->payload = (void *)GIT_HASHSIG_NORMAL; else opts->metric->payload = (void *)GIT_HASHSIG_SMART_WHITESPACE; } return 0; } static int merge_index_insert_reuc( git_index *index, size_t idx, const git_index_entry *entry) { const git_index_reuc_entry *reuc; int mode[3] = { 0, 0, 0 }; git_oid const *oid[3] = { NULL, NULL, NULL }; size_t i; if (!GIT_MERGE_INDEX_ENTRY_EXISTS(*entry)) return 0; if ((reuc = git_index_reuc_get_bypath(index, entry->path)) != NULL) { for (i = 0; i < 3; i++) { mode[i] = reuc->mode[i]; oid[i] = &reuc->oid[i]; } } mode[idx] = entry->mode; oid[idx] = &entry->oid; return git_index_reuc_add(index, entry->path, mode[0], oid[0], mode[1], oid[1], mode[2], oid[2]); } int index_from_diff_list(git_index **out, git_merge_diff_list *diff_list) { git_index *index; size_t i; git_index_entry *entry; git_merge_diff *conflict; int error = 0; *out = NULL; if ((error = git_index_new(&index)) < 0) return error; git_vector_foreach(&diff_list->staged, i, entry) { if ((error = git_index_add(index, entry)) < 0) goto on_error; } git_vector_foreach(&diff_list->conflicts, i, conflict) { const git_index_entry *ancestor = GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->ancestor_entry) ? &conflict->ancestor_entry : NULL; const git_index_entry *ours = GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->our_entry) ? &conflict->our_entry : NULL; const git_index_entry *theirs = GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->their_entry) ? &conflict->their_entry : NULL; if ((error = git_index_conflict_add(index, ancestor, ours, theirs)) < 0) goto on_error; } /* Add each rename entry to the rename portion of the index. */ git_vector_foreach(&diff_list->conflicts, i, conflict) { const char *ancestor_path, *our_path, *their_path; if (!GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->ancestor_entry)) continue; ancestor_path = conflict->ancestor_entry.path; our_path = GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->our_entry) ? conflict->our_entry.path : NULL; their_path = GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->their_entry) ? conflict->their_entry.path : NULL; if ((our_path && strcmp(ancestor_path, our_path) != 0) || (their_path && strcmp(ancestor_path, their_path) != 0)) { if ((error = git_index_name_add(index, ancestor_path, our_path, their_path)) < 0) goto on_error; } } /* Add each entry in the resolved conflict to the REUC independently, since * the paths may differ due to renames. */ git_vector_foreach(&diff_list->resolved, i, conflict) { const git_index_entry *ancestor = GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->ancestor_entry) ? &conflict->ancestor_entry : NULL; const git_index_entry *ours = GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->our_entry) ? &conflict->our_entry : NULL; const git_index_entry *theirs = GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->their_entry) ? &conflict->their_entry : NULL; if (ancestor != NULL && (error = merge_index_insert_reuc(index, TREE_IDX_ANCESTOR, ancestor)) < 0) goto on_error; if (ours != NULL && (error = merge_index_insert_reuc(index, TREE_IDX_OURS, ours)) < 0) goto on_error; if (theirs != NULL && (error = merge_index_insert_reuc(index, TREE_IDX_THEIRS, theirs)) < 0) goto on_error; } *out = index; return 0; on_error: git_index_free(index); return error; } int git_merge_trees( git_index **out, git_repository *repo, const git_tree *ancestor_tree, const git_tree *our_tree, const git_tree *their_tree, const git_merge_tree_opts *given_opts) { git_merge_diff_list *diff_list; git_merge_tree_opts opts; git_merge_diff *conflict; git_vector changes; size_t i; int error = 0; assert(out && repo && our_tree && their_tree); *out = NULL; if ((error = merge_tree_normalize_opts(repo, &opts, given_opts)) < 0) return error; diff_list = git_merge_diff_list__alloc(repo); GITERR_CHECK_ALLOC(diff_list); if ((error = git_merge_diff_list__find_differences(diff_list, ancestor_tree, our_tree, their_tree)) < 0 || (error = git_merge_diff_list__find_renames(repo, diff_list, &opts)) < 0) goto done; memcpy(&changes, &diff_list->conflicts, sizeof(git_vector)); git_vector_clear(&diff_list->conflicts); git_vector_foreach(&changes, i, conflict) { int resolved = 0; if ((error = merge_conflict_resolve(&resolved, diff_list, conflict, opts.automerge_flags)) < 0) goto done; if (!resolved) git_vector_insert(&diff_list->conflicts, conflict); } if (!given_opts || !given_opts->metric) git__free(opts.metric); error = index_from_diff_list(out, diff_list); done: git_merge_diff_list__free(diff_list); return error; } /* Merge setup / cleanup */ static int write_orig_head( git_repository *repo, const git_merge_head *our_head) { git_filebuf file = GIT_FILEBUF_INIT; git_buf file_path = GIT_BUF_INIT; char orig_oid_str[GIT_OID_HEXSZ + 1]; int error = 0; assert(repo && our_head); git_oid_tostr(orig_oid_str, GIT_OID_HEXSZ+1, &our_head->oid); if ((error = git_buf_joinpath(&file_path, repo->path_repository, GIT_ORIG_HEAD_FILE)) == 0 && (error = git_filebuf_open(&file, file_path.ptr, GIT_FILEBUF_FORCE)) == 0 && (error = git_filebuf_printf(&file, "%s\n", orig_oid_str)) == 0) error = git_filebuf_commit(&file, 0666); if (error < 0) git_filebuf_cleanup(&file); git_buf_free(&file_path); return error; } static int write_merge_head( git_repository *repo, const git_merge_head *heads[], size_t heads_len) { git_filebuf file = GIT_FILEBUF_INIT; git_buf file_path = GIT_BUF_INIT; char merge_oid_str[GIT_OID_HEXSZ + 1]; size_t i; int error = 0; assert(repo && heads); if ((error = git_buf_joinpath(&file_path, repo->path_repository, GIT_MERGE_HEAD_FILE)) < 0 || (error = git_filebuf_open(&file, file_path.ptr, GIT_FILEBUF_FORCE)) < 0) goto cleanup; for (i = 0; i < heads_len; i++) { git_oid_tostr(merge_oid_str, GIT_OID_HEXSZ+1, &heads[i]->oid); if ((error = git_filebuf_printf(&file, "%s\n", merge_oid_str)) < 0) goto cleanup; } error = git_filebuf_commit(&file, 0666); cleanup: if (error < 0) git_filebuf_cleanup(&file); git_buf_free(&file_path); return error; } static int write_merge_mode(git_repository *repo, unsigned int flags) { git_filebuf file = GIT_FILEBUF_INIT; git_buf file_path = GIT_BUF_INIT; int error = 0; /* For future expansion */ GIT_UNUSED(flags); assert(repo); if ((error = git_buf_joinpath(&file_path, repo->path_repository, GIT_MERGE_MODE_FILE)) < 0 || (error = git_filebuf_open(&file, file_path.ptr, GIT_FILEBUF_FORCE)) < 0) goto cleanup; error = git_filebuf_commit(&file, 0666); cleanup: if (error < 0) git_filebuf_cleanup(&file); git_buf_free(&file_path); return error; } struct merge_msg_entry { const git_merge_head *merge_head; bool written; }; static int msg_entry_is_branch( const struct merge_msg_entry *entry, git_vector *entries) { GIT_UNUSED(entries); return (entry->written == 0 && entry->merge_head->remote_url == NULL && entry->merge_head->ref_name != NULL && git__strncmp(GIT_REFS_HEADS_DIR, entry->merge_head->ref_name, strlen(GIT_REFS_HEADS_DIR)) == 0); } static int msg_entry_is_tracking( const struct merge_msg_entry *entry, git_vector *entries) { GIT_UNUSED(entries); return (entry->written == 0 && entry->merge_head->remote_url == NULL && entry->merge_head->ref_name != NULL && git__strncmp(GIT_REFS_REMOTES_DIR, entry->merge_head->ref_name, strlen(GIT_REFS_REMOTES_DIR)) == 0); } static int msg_entry_is_tag( const struct merge_msg_entry *entry, git_vector *entries) { GIT_UNUSED(entries); return (entry->written == 0 && entry->merge_head->remote_url == NULL && entry->merge_head->ref_name != NULL && git__strncmp(GIT_REFS_TAGS_DIR, entry->merge_head->ref_name, strlen(GIT_REFS_TAGS_DIR)) == 0); } static int msg_entry_is_remote( const struct merge_msg_entry *entry, git_vector *entries) { if (entry->written == 0 && entry->merge_head->remote_url != NULL && entry->merge_head->ref_name != NULL && git__strncmp(GIT_REFS_HEADS_DIR, entry->merge_head->ref_name, strlen(GIT_REFS_HEADS_DIR)) == 0) { struct merge_msg_entry *existing; /* Match only branches from the same remote */ if (entries->length == 0) return 1; existing = git_vector_get(entries, 0); return (git__strcmp(existing->merge_head->remote_url, entry->merge_head->remote_url) == 0); } return 0; } static int msg_entry_is_oid( const struct merge_msg_entry *merge_msg_entry) { return (merge_msg_entry->written == 0 && merge_msg_entry->merge_head->ref_name == NULL && merge_msg_entry->merge_head->remote_url == NULL); } static int merge_msg_entry_written( const struct merge_msg_entry *merge_msg_entry) { return (merge_msg_entry->written == 1); } static int merge_msg_entries( git_vector *v, const struct merge_msg_entry *entries, size_t len, int (*match)(const struct merge_msg_entry *entry, git_vector *entries)) { size_t i; int matches, total = 0; git_vector_clear(v); for (i = 0; i < len; i++) { if ((matches = match(&entries[i], v)) < 0) return matches; else if (!matches) continue; git_vector_insert(v, (struct merge_msg_entry *)&entries[i]); total++; } return total; } static int merge_msg_write_entries( git_filebuf *file, git_vector *entries, const char *item_name, const char *item_plural_name, size_t ref_name_skip, const char *source, char sep) { struct merge_msg_entry *entry; size_t i; int error = 0; if (entries->length == 0) return 0; if (sep && (error = git_filebuf_printf(file, "%c ", sep)) < 0) goto done; if ((error = git_filebuf_printf(file, "%s ", (entries->length == 1) ? item_name : item_plural_name)) < 0) goto done; git_vector_foreach(entries, i, entry) { if (i > 0 && (error = git_filebuf_printf(file, "%s", (i == entries->length - 1) ? " and " : ", ")) < 0) goto done; if ((error = git_filebuf_printf(file, "'%s'", entry->merge_head->ref_name + ref_name_skip)) < 0) goto done; entry->written = 1; } if (source) error = git_filebuf_printf(file, " of %s", source); done: return error; } static int merge_msg_write_branches( git_filebuf *file, git_vector *entries, char sep) { return merge_msg_write_entries(file, entries, "branch", "branches", strlen(GIT_REFS_HEADS_DIR), NULL, sep); } static int merge_msg_write_tracking( git_filebuf *file, git_vector *entries, char sep) { return merge_msg_write_entries(file, entries, "remote-tracking branch", "remote-tracking branches", 0, NULL, sep); } static int merge_msg_write_tags( git_filebuf *file, git_vector *entries, char sep) { return merge_msg_write_entries(file, entries, "tag", "tags", strlen(GIT_REFS_TAGS_DIR), NULL, sep); } static int merge_msg_write_remotes( git_filebuf *file, git_vector *entries, char sep) { const char *source; if (entries->length == 0) return 0; source = ((struct merge_msg_entry *)entries->contents[0])->merge_head->remote_url; return merge_msg_write_entries(file, entries, "branch", "branches", strlen(GIT_REFS_HEADS_DIR), source, sep); } static int write_merge_msg( git_repository *repo, const git_merge_head *heads[], size_t heads_len) { git_filebuf file = GIT_FILEBUF_INIT; git_buf file_path = GIT_BUF_INIT; char oid_str[GIT_OID_HEXSZ + 1]; struct merge_msg_entry *entries; git_vector matching = GIT_VECTOR_INIT; size_t i; char sep = 0; int error = 0; assert(repo && heads); entries = git__calloc(heads_len, sizeof(struct merge_msg_entry)); GITERR_CHECK_ALLOC(entries); if (git_vector_init(&matching, heads_len, NULL) < 0) return -1; for (i = 0; i < heads_len; i++) entries[i].merge_head = heads[i]; if ((error = git_buf_joinpath(&file_path, repo->path_repository, GIT_MERGE_MSG_FILE)) < 0 || (error = git_filebuf_open(&file, file_path.ptr, GIT_FILEBUF_FORCE)) < 0 || (error = git_filebuf_write(&file, "Merge ", 6)) < 0) goto cleanup; /* * This is to emulate the format of MERGE_MSG by core git. * * Core git will write all the commits specified by OID, in the order * provided, until the first named branch or tag is reached, at which * point all branches will be written in the order provided, then all * tags, then all remote tracking branches and finally all commits that * were specified by OID that were not already written. * * Yes. Really. */ for (i = 0; i < heads_len; i++) { if (!msg_entry_is_oid(&entries[i])) break; git_oid_fmt(oid_str, &entries[i].merge_head->oid); oid_str[GIT_OID_HEXSZ] = '\0'; if ((error = git_filebuf_printf(&file, "%scommit '%s'", (i > 0) ? "; " : "", oid_str)) < 0) goto cleanup; entries[i].written = 1; } if (i) sep = ';'; if ((error = merge_msg_entries(&matching, entries, heads_len, msg_entry_is_branch)) < 0 || (error = merge_msg_write_branches(&file, &matching, sep)) < 0) goto cleanup; if (matching.length) sep =','; if ((error = merge_msg_entries(&matching, entries, heads_len, msg_entry_is_tracking)) < 0 || (error = merge_msg_write_tracking(&file, &matching, sep)) < 0) goto cleanup; if (matching.length) sep =','; if ((error = merge_msg_entries(&matching, entries, heads_len, msg_entry_is_tag)) < 0 || (error = merge_msg_write_tags(&file, &matching, sep)) < 0) goto cleanup; if (matching.length) sep =','; /* We should never be called with multiple remote branches, but handle * it in case we are... */ while ((error = merge_msg_entries(&matching, entries, heads_len, msg_entry_is_remote)) > 0) { if ((error = merge_msg_write_remotes(&file, &matching, sep)) < 0) goto cleanup; if (matching.length) sep =','; } if (error < 0) goto cleanup; for (i = 0; i < heads_len; i++) { if (merge_msg_entry_written(&entries[i])) continue; git_oid_fmt(oid_str, &entries[i].merge_head->oid); oid_str[GIT_OID_HEXSZ] = '\0'; if ((error = git_filebuf_printf(&file, "; commit '%s'", oid_str)) < 0) goto cleanup; } if ((error = git_filebuf_printf(&file, "\n")) < 0 || (error = git_filebuf_commit(&file, 0666)) < 0) goto cleanup; cleanup: if (error < 0) git_filebuf_cleanup(&file); git_buf_free(&file_path); git_vector_free(&matching); git__free(entries); return error; } int git_merge__setup( git_repository *repo, const git_merge_head *our_head, const git_merge_head *heads[], size_t heads_len, unsigned int flags) { int error = 0; assert (repo && our_head && heads); if ((error = write_orig_head(repo, our_head)) == 0 && (error = write_merge_head(repo, heads, heads_len)) == 0 && (error = write_merge_mode(repo, flags)) == 0) { error = write_merge_msg(repo, heads, heads_len); } return error; } int git_repository_merge_cleanup(git_repository *repo) { int error = 0; git_buf merge_head_path = GIT_BUF_INIT, merge_mode_path = GIT_BUF_INIT, merge_msg_path = GIT_BUF_INIT; assert(repo); if (git_buf_joinpath(&merge_head_path, repo->path_repository, GIT_MERGE_HEAD_FILE) < 0 || git_buf_joinpath(&merge_mode_path, repo->path_repository, GIT_MERGE_MODE_FILE) < 0 || git_buf_joinpath(&merge_msg_path, repo->path_repository, GIT_MERGE_MSG_FILE) < 0) return -1; if (git_path_isfile(merge_head_path.ptr)) { if ((error = p_unlink(merge_head_path.ptr)) < 0) goto cleanup; } if (git_path_isfile(merge_mode_path.ptr)) (void)p_unlink(merge_mode_path.ptr); if (git_path_isfile(merge_msg_path.ptr)) (void)p_unlink(merge_msg_path.ptr); cleanup: git_buf_free(&merge_msg_path); git_buf_free(&merge_mode_path); git_buf_free(&merge_head_path); return error; } /* Merge heads are the input to merge */ static int merge_head_init( git_merge_head **out, git_repository *repo, const char *ref_name, const char *remote_url, const git_oid *oid) { git_merge_head *head; int error = 0; assert(out && oid); *out = NULL; head = git__calloc(1, sizeof(git_merge_head)); GITERR_CHECK_ALLOC(head); if (ref_name) { head->ref_name = git__strdup(ref_name); GITERR_CHECK_ALLOC(head->ref_name); } if (remote_url) { head->remote_url = git__strdup(remote_url); GITERR_CHECK_ALLOC(head->remote_url); } git_oid_cpy(&head->oid, oid); if ((error = git_commit_lookup(&head->commit, repo, &head->oid)) < 0) { git_merge_head_free(head); return error; } *out = head; return error; } int git_merge_head_from_ref( git_merge_head **out, git_repository *repo, git_reference *ref) { git_reference *resolved; int error = 0; assert(out && repo && ref); *out = NULL; if ((error = git_reference_resolve(&resolved, ref)) < 0) return error; error = merge_head_init(out, repo, git_reference_name(ref), NULL, git_reference_target(resolved)); git_reference_free(resolved); return error; } int git_merge_head_from_oid( git_merge_head **out, git_repository *repo, const git_oid *oid) { assert(out && repo && oid); return merge_head_init(out, repo, NULL, NULL, oid); } int git_merge_head_from_fetchhead( git_merge_head **out, git_repository *repo, const char *branch_name, const char *remote_url, const git_oid *oid) { assert(repo && branch_name && remote_url && oid); return merge_head_init(out, repo, branch_name, remote_url, oid); } void git_merge_head_free(git_merge_head *head) { if (head == NULL) return; if (head->commit != NULL) git_object_free((git_object *)head->commit); if (head->ref_name != NULL) git__free(head->ref_name); if (head->remote_url != NULL) git__free(head->remote_url); git__free(head); } libgit2-0.19.0/src/merge.h000066400000000000000000000104171216214232500151750ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #ifndef INCLUDE_merge_h__ #define INCLUDE_merge_h__ #include "vector.h" #include "commit_list.h" #include "pool.h" #include "git2/merge.h" #include "git2/types.h" #define GIT_MERGE_MSG_FILE "MERGE_MSG" #define GIT_MERGE_MODE_FILE "MERGE_MODE" #define GIT_MERGE_TREE_RENAME_THRESHOLD 50 #define GIT_MERGE_TREE_TARGET_LIMIT 1000 /** Types of changes when files are merged from branch to branch. */ typedef enum { /* No conflict - a change only occurs in one branch. */ GIT_MERGE_DIFF_NONE = 0, /* Occurs when a file is modified in both branches. */ GIT_MERGE_DIFF_BOTH_MODIFIED = (1 << 0), /* Occurs when a file is added in both branches. */ GIT_MERGE_DIFF_BOTH_ADDED = (1 << 1), /* Occurs when a file is deleted in both branches. */ GIT_MERGE_DIFF_BOTH_DELETED = (1 << 2), /* Occurs when a file is modified in one branch and deleted in the other. */ GIT_MERGE_DIFF_MODIFIED_DELETED = (1 << 3), /* Occurs when a file is renamed in one branch and modified in the other. */ GIT_MERGE_DIFF_RENAMED_MODIFIED = (1 << 4), /* Occurs when a file is renamed in one branch and deleted in the other. */ GIT_MERGE_DIFF_RENAMED_DELETED = (1 << 5), /* Occurs when a file is renamed in one branch and a file with the same * name is added in the other. Eg, A->B and new file B. Core git calls * this a "rename/delete". */ GIT_MERGE_DIFF_RENAMED_ADDED = (1 << 6), /* Occurs when both a file is renamed to the same name in the ours and * theirs branches. Eg, A->B and A->B in both. Automergeable. */ GIT_MERGE_DIFF_BOTH_RENAMED = (1 << 7), /* Occurs when a file is renamed to different names in the ours and theirs * branches. Eg, A->B and A->C. */ GIT_MERGE_DIFF_BOTH_RENAMED_1_TO_2 = (1 << 8), /* Occurs when two files are renamed to the same name in the ours and * theirs branches. Eg, A->C and B->C. */ GIT_MERGE_DIFF_BOTH_RENAMED_2_TO_1 = (1 << 9), /* Occurs when an item at a path in one branch is a directory, and an * item at the same path in a different branch is a file. */ GIT_MERGE_DIFF_DIRECTORY_FILE = (1 << 10), /* The child of a folder that is in a directory/file conflict. */ GIT_MERGE_DIFF_DF_CHILD = (1 << 11), } git_merge_diff_type_t; typedef struct { git_repository *repo; git_pool pool; /* Vector of git_index_entry that represent the merged items that * have been staged, either because only one side changed, or because * the two changes were non-conflicting and mergeable. These items * will be written as staged entries in the main index. */ git_vector staged; /* Vector of git_merge_diff entries that represent the conflicts that * have not been automerged. These items will be written to high-stage * entries in the main index. */ git_vector conflicts; /* Vector of git_merge_diff that have been automerged. These items * will be written to the REUC when the index is produced. */ git_vector resolved; } git_merge_diff_list; /** * Description of changes to one file across three trees. */ typedef struct { git_merge_diff_type_t type; git_index_entry ancestor_entry; git_index_entry our_entry; git_delta_t our_status; git_index_entry their_entry; git_delta_t their_status; } git_merge_diff; /** Internal structure for merge inputs */ struct git_merge_head { char *ref_name; char *remote_url; git_oid oid; git_commit *commit; }; int git_merge__bases_many( git_commit_list **out, git_revwalk *walk, git_commit_list_node *one, git_vector *twos); /* * Three-way tree differencing */ git_merge_diff_list *git_merge_diff_list__alloc(git_repository *repo); int git_merge_diff_list__find_differences(git_merge_diff_list *merge_diff_list, const git_tree *ancestor_tree, const git_tree *ours_tree, const git_tree *theirs_tree); int git_merge_diff_list__find_renames(git_repository *repo, git_merge_diff_list *merge_diff_list, const git_merge_tree_opts *opts); void git_merge_diff_list__free(git_merge_diff_list *diff_list); /* Merge metadata setup */ int git_merge__setup( git_repository *repo, const git_merge_head *our_head, const git_merge_head *their_heads[], size_t their_heads_len, unsigned int flags); #endif libgit2-0.19.0/src/merge_file.c000066400000000000000000000100451216214232500161640ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #include "common.h" #include "repository.h" #include "merge_file.h" #include "git2/repository.h" #include "git2/object.h" #include "git2/index.h" #include "xdiff/xdiff.h" #define GIT_MERGE_FILE_SIDE_EXISTS(X) ((X)->mode != 0) GIT_INLINE(const char *) merge_file_best_path( const git_merge_file_input *ancestor, const git_merge_file_input *ours, const git_merge_file_input *theirs) { if (!GIT_MERGE_FILE_SIDE_EXISTS(ancestor)) { if (strcmp(ours->path, theirs->path) == 0) return ours->path; return NULL; } if (strcmp(ancestor->path, ours->path) == 0) return theirs->path; else if(strcmp(ancestor->path, theirs->path) == 0) return ours->path; return NULL; } GIT_INLINE(int) merge_file_best_mode( const git_merge_file_input *ancestor, const git_merge_file_input *ours, const git_merge_file_input *theirs) { /* * If ancestor didn't exist and either ours or theirs is executable, * assume executable. Otherwise, if any mode changed from the ancestor, * use that one. */ if (GIT_MERGE_FILE_SIDE_EXISTS(ancestor)) { if (ours->mode == GIT_FILEMODE_BLOB_EXECUTABLE || theirs->mode == GIT_FILEMODE_BLOB_EXECUTABLE) return GIT_FILEMODE_BLOB_EXECUTABLE; return GIT_FILEMODE_BLOB; } if (ancestor->mode == ours->mode) return theirs->mode; else if(ancestor->mode == theirs->mode) return ours->mode; return 0; } int git_merge_file_input_from_index_entry( git_merge_file_input *input, git_repository *repo, const git_index_entry *entry) { git_odb *odb = NULL; int error = 0; assert(input && repo && entry); if (entry->mode == 0) return 0; if ((error = git_repository_odb(&odb, repo)) < 0 || (error = git_odb_read(&input->odb_object, odb, &entry->oid)) < 0) goto done; input->mode = entry->mode; input->path = git__strdup(entry->path); input->mmfile.size = git_odb_object_size(input->odb_object); input->mmfile.ptr = (char *)git_odb_object_data(input->odb_object); if (input->label == NULL) input->label = entry->path; done: git_odb_free(odb); return error; } int git_merge_file_input_from_diff_file( git_merge_file_input *input, git_repository *repo, const git_diff_file *file) { git_odb *odb = NULL; int error = 0; assert(input && repo && file); if (file->mode == 0) return 0; if ((error = git_repository_odb(&odb, repo)) < 0 || (error = git_odb_read(&input->odb_object, odb, &file->oid)) < 0) goto done; input->mode = file->mode; input->path = git__strdup(file->path); input->mmfile.size = git_odb_object_size(input->odb_object); input->mmfile.ptr = (char *)git_odb_object_data(input->odb_object); if (input->label == NULL) input->label = file->path; done: git_odb_free(odb); return error; } int git_merge_files( git_merge_file_result *out, git_merge_file_input *ancestor, git_merge_file_input *ours, git_merge_file_input *theirs, git_merge_automerge_flags flags) { xmparam_t xmparam; mmbuffer_t mmbuffer; int xdl_result; int error = 0; assert(out && ancestor && ours && theirs); memset(out, 0x0, sizeof(git_merge_file_result)); if (!GIT_MERGE_FILE_SIDE_EXISTS(ours) || !GIT_MERGE_FILE_SIDE_EXISTS(theirs)) return 0; memset(&xmparam, 0x0, sizeof(xmparam_t)); xmparam.ancestor = ancestor->label; xmparam.file1 = ours->label; xmparam.file2 = theirs->label; out->path = merge_file_best_path(ancestor, ours, theirs); out->mode = merge_file_best_mode(ancestor, ours, theirs); if (flags == GIT_MERGE_AUTOMERGE_FAVOR_OURS) xmparam.favor = XDL_MERGE_FAVOR_OURS; if (flags == GIT_MERGE_AUTOMERGE_FAVOR_THEIRS) xmparam.favor = XDL_MERGE_FAVOR_THEIRS; if ((xdl_result = xdl_merge(&ancestor->mmfile, &ours->mmfile, &theirs->mmfile, &xmparam, &mmbuffer)) < 0) { giterr_set(GITERR_MERGE, "Failed to merge files."); error = -1; goto done; } out->automergeable = (xdl_result == 0); out->data = (unsigned char *)mmbuffer.ptr; out->len = mmbuffer.size; done: return error; } libgit2-0.19.0/src/merge_file.h000066400000000000000000000027611216214232500161770ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #ifndef INCLUDE_filediff_h__ #define INCLUDE_filediff_h__ #include "xdiff/xdiff.h" #include "git2/merge.h" typedef struct { const char *label; char *path; unsigned int mode; mmfile_t mmfile; git_odb_object *odb_object; } git_merge_file_input; #define GIT_MERGE_FILE_INPUT_INIT {0} typedef struct { bool automergeable; const char *path; int mode; unsigned char *data; size_t len; } git_merge_file_result; #define GIT_MERGE_FILE_RESULT_INIT {0} int git_merge_file_input_from_index_entry( git_merge_file_input *input, git_repository *repo, const git_index_entry *entry); int git_merge_file_input_from_diff_file( git_merge_file_input *input, git_repository *repo, const git_diff_file *file); int git_merge_files( git_merge_file_result *out, git_merge_file_input *ancestor, git_merge_file_input *ours, git_merge_file_input *theirs, git_merge_automerge_flags flags); GIT_INLINE(void) git_merge_file_input_free(git_merge_file_input *input) { assert(input); git__free(input->path); git_odb_object_free(input->odb_object); } GIT_INLINE(void) git_merge_file_result_free(git_merge_file_result *filediff) { if (filediff == NULL) return; /* xdiff uses malloc() not git_malloc, so we use free(), not git_free() */ if (filediff->data != NULL) free(filediff->data); } #endif libgit2-0.19.0/src/message.c000066400000000000000000000042371216214232500155200ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #include "message.h" static size_t line_length_without_trailing_spaces(const char *line, size_t len) { while (len) { unsigned char c = line[len - 1]; if (!git__isspace(c)) break; len--; } return len; } /* Greatly inspired from git.git "stripspace" */ /* see https://github.com/git/git/blob/497215d8811ac7b8955693ceaad0899ecd894ed2/builtin/stripspace.c#L4-67 */ int git_message__prettify(git_buf *message_out, const char *message, int strip_comments) { const size_t message_len = strlen(message); int consecutive_empty_lines = 0; size_t i, line_length, rtrimmed_line_length; char *next_newline; for (i = 0; i < strlen(message); i += line_length) { next_newline = memchr(message + i, '\n', message_len - i); if (next_newline != NULL) { line_length = next_newline - (message + i) + 1; } else { line_length = message_len - i; } if (strip_comments && line_length && message[i] == '#') continue; rtrimmed_line_length = line_length_without_trailing_spaces(message + i, line_length); if (!rtrimmed_line_length) { consecutive_empty_lines++; continue; } if (consecutive_empty_lines > 0 && message_out->size > 0) git_buf_putc(message_out, '\n'); consecutive_empty_lines = 0; git_buf_put(message_out, message + i, rtrimmed_line_length); git_buf_putc(message_out, '\n'); } return git_buf_oom(message_out) ? -1 : 0; } int git_message_prettify(char *message_out, size_t buffer_size, const char *message, int strip_comments) { git_buf buf = GIT_BUF_INIT; ssize_t out_size = -1; if (message_out && buffer_size) *message_out = '\0'; if (git_message__prettify(&buf, message, strip_comments) < 0) goto done; if (message_out && buf.size + 1 > buffer_size) { /* +1 for NUL byte */ giterr_set(GITERR_INVALID, "Buffer too short to hold the cleaned message"); goto done; } if (message_out) git_buf_copy_cstr(message_out, buffer_size, &buf); out_size = buf.size + 1; done: git_buf_free(&buf); return (int)out_size; } libgit2-0.19.0/src/message.h000066400000000000000000000006731216214232500155250ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #ifndef INCLUDE_message_h__ #define INCLUDE_message_h__ #include "git2/message.h" #include "buffer.h" int git_message__prettify(git_buf *message_out, const char *message, int strip_comments); #endif /* INCLUDE_message_h__ */ libgit2-0.19.0/src/mwindow.c000066400000000000000000000157331216214232500155630ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #include "common.h" #include "mwindow.h" #include "vector.h" #include "fileops.h" #include "map.h" #include "global.h" #define DEFAULT_WINDOW_SIZE \ (sizeof(void*) >= 8 \ ? 1 * 1024 * 1024 * 1024 \ : 32 * 1024 * 1024) #define DEFAULT_MAPPED_LIMIT \ ((1024 * 1024) * (sizeof(void*) >= 8 ? 8192ULL : 256UL)) size_t git_mwindow__window_size = DEFAULT_WINDOW_SIZE; size_t git_mwindow__mapped_limit = DEFAULT_MAPPED_LIMIT; /* Whenever you want to read or modify this, grab git__mwindow_mutex */ static git_mwindow_ctl mem_ctl; /* * Free all the windows in a sequence, typically because we're done * with the file */ void git_mwindow_free_all(git_mwindow_file *mwf) { git_mwindow_ctl *ctl = &mem_ctl; size_t i; if (git_mutex_lock(&git__mwindow_mutex)) { giterr_set(GITERR_THREAD, "unable to lock mwindow mutex"); return; } /* * Remove these windows from the global list */ for (i = 0; i < ctl->windowfiles.length; ++i){ if (git_vector_get(&ctl->windowfiles, i) == mwf) { git_vector_remove(&ctl->windowfiles, i); break; } } if (ctl->windowfiles.length == 0) { git_vector_free(&ctl->windowfiles); ctl->windowfiles.contents = NULL; } while (mwf->windows) { git_mwindow *w = mwf->windows; assert(w->inuse_cnt == 0); ctl->mapped -= w->window_map.len; ctl->open_windows--; git_futils_mmap_free(&w->window_map); mwf->windows = w->next; git__free(w); } git_mutex_unlock(&git__mwindow_mutex); } /* * Check if a window 'win' contains the address 'offset' */ int git_mwindow_contains(git_mwindow *win, git_off_t offset) { git_off_t win_off = win->offset; return win_off <= offset && offset <= (git_off_t)(win_off + win->window_map.len); } /* * Find the least-recently-used window in a file */ static void git_mwindow_scan_lru( git_mwindow_file *mwf, git_mwindow **lru_w, git_mwindow **lru_l) { git_mwindow *w, *w_l; for (w_l = NULL, w = mwf->windows; w; w = w->next) { if (!w->inuse_cnt) { /* * If the current one is more recent than the last one, * store it in the output parameter. If lru_w is NULL, * it's the first loop, so store it as well. */ if (!*lru_w || w->last_used < (*lru_w)->last_used) { *lru_w = w; *lru_l = w_l; } } w_l = w; } } /* * Close the least recently used window. You should check to see if * the file descriptors need closing from time to time. Called under * lock from new_window. */ static int git_mwindow_close_lru(git_mwindow_file *mwf) { git_mwindow_ctl *ctl = &mem_ctl; size_t i; git_mwindow *lru_w = NULL, *lru_l = NULL, **list = &mwf->windows; /* FIXME: Does this give us any advantage? */ if(mwf->windows) git_mwindow_scan_lru(mwf, &lru_w, &lru_l); for (i = 0; i < ctl->windowfiles.length; ++i) { git_mwindow *last = lru_w; git_mwindow_file *cur = git_vector_get(&ctl->windowfiles, i); git_mwindow_scan_lru(cur, &lru_w, &lru_l); if (lru_w != last) list = &cur->windows; } if (!lru_w) { giterr_set(GITERR_OS, "Failed to close memory window. Couldn't find LRU"); return -1; } ctl->mapped -= lru_w->window_map.len; git_futils_mmap_free(&lru_w->window_map); if (lru_l) lru_l->next = lru_w->next; else *list = lru_w->next; git__free(lru_w); ctl->open_windows--; return 0; } /* This gets called under lock from git_mwindow_open */ static git_mwindow *new_window( git_mwindow_file *mwf, git_file fd, git_off_t size, git_off_t offset) { git_mwindow_ctl *ctl = &mem_ctl; size_t walign = git_mwindow__window_size / 2; git_off_t len; git_mwindow *w; w = git__malloc(sizeof(*w)); if (w == NULL) return NULL; memset(w, 0x0, sizeof(*w)); w->offset = (offset / walign) * walign; len = size - w->offset; if (len > (git_off_t)git_mwindow__window_size) len = (git_off_t)git_mwindow__window_size; ctl->mapped += (size_t)len; while (git_mwindow__mapped_limit < ctl->mapped && git_mwindow_close_lru(mwf) == 0) /* nop */; /* * We treat `mapped_limit` as a soft limit. If we can't find a * window to close and are above the limit, we still mmap the new * window. */ if (git_futils_mmap_ro(&w->window_map, fd, w->offset, (size_t)len) < 0) { git__free(w); return NULL; } ctl->mmap_calls++; ctl->open_windows++; if (ctl->mapped > ctl->peak_mapped) ctl->peak_mapped = ctl->mapped; if (ctl->open_windows > ctl->peak_open_windows) ctl->peak_open_windows = ctl->open_windows; return w; } /* * Open a new window, closing the least recenty used until we have * enough space. Don't forget to add it to your list */ unsigned char *git_mwindow_open( git_mwindow_file *mwf, git_mwindow **cursor, git_off_t offset, size_t extra, unsigned int *left) { git_mwindow_ctl *ctl = &mem_ctl; git_mwindow *w = *cursor; if (git_mutex_lock(&git__mwindow_mutex)) { giterr_set(GITERR_THREAD, "unable to lock mwindow mutex"); return NULL; } if (!w || !(git_mwindow_contains(w, offset) && git_mwindow_contains(w, offset + extra))) { if (w) { w->inuse_cnt--; } for (w = mwf->windows; w; w = w->next) { if (git_mwindow_contains(w, offset) && git_mwindow_contains(w, offset + extra)) break; } /* * If there isn't a suitable window, we need to create a new * one. */ if (!w) { w = new_window(mwf, mwf->fd, mwf->size, offset); if (w == NULL) { git_mutex_unlock(&git__mwindow_mutex); return NULL; } w->next = mwf->windows; mwf->windows = w; } } /* If we changed w, store it in the cursor */ if (w != *cursor) { w->last_used = ctl->used_ctr++; w->inuse_cnt++; *cursor = w; } offset -= w->offset; if (left) *left = (unsigned int)(w->window_map.len - offset); git_mutex_unlock(&git__mwindow_mutex); return (unsigned char *) w->window_map.data + offset; } int git_mwindow_file_register(git_mwindow_file *mwf) { git_mwindow_ctl *ctl = &mem_ctl; int ret; if (git_mutex_lock(&git__mwindow_mutex)) { giterr_set(GITERR_THREAD, "unable to lock mwindow mutex"); return -1; } if (ctl->windowfiles.length == 0 && git_vector_init(&ctl->windowfiles, 8, NULL) < 0) { git_mutex_unlock(&git__mwindow_mutex); return -1; } ret = git_vector_insert(&ctl->windowfiles, mwf); git_mutex_unlock(&git__mwindow_mutex); return ret; } void git_mwindow_file_deregister(git_mwindow_file *mwf) { git_mwindow_ctl *ctl = &mem_ctl; git_mwindow_file *cur; size_t i; if (git_mutex_lock(&git__mwindow_mutex)) return; git_vector_foreach(&ctl->windowfiles, i, cur) { if (cur == mwf) { git_vector_remove(&ctl->windowfiles, i); git_mutex_unlock(&git__mwindow_mutex); return; } } git_mutex_unlock(&git__mwindow_mutex); } void git_mwindow_close(git_mwindow **window) { git_mwindow *w = *window; if (w) { if (git_mutex_lock(&git__mwindow_mutex)) { giterr_set(GITERR_THREAD, "unable to lock mwindow mutex"); return; } w->inuse_cnt--; git_mutex_unlock(&git__mwindow_mutex); *window = NULL; } } libgit2-0.19.0/src/mwindow.h000066400000000000000000000022461216214232500155630ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #ifndef INCLUDE_mwindow__ #define INCLUDE_mwindow__ #include "map.h" #include "vector.h" typedef struct git_mwindow { struct git_mwindow *next; git_map window_map; git_off_t offset; size_t last_used; size_t inuse_cnt; } git_mwindow; typedef struct git_mwindow_file { git_mwindow *windows; int fd; git_off_t size; } git_mwindow_file; typedef struct git_mwindow_ctl { size_t mapped; unsigned int open_windows; unsigned int mmap_calls; unsigned int peak_open_windows; size_t peak_mapped; size_t used_ctr; git_vector windowfiles; } git_mwindow_ctl; int git_mwindow_contains(git_mwindow *win, git_off_t offset); void git_mwindow_free_all(git_mwindow_file *mwf); unsigned char *git_mwindow_open(git_mwindow_file *mwf, git_mwindow **cursor, git_off_t offset, size_t extra, unsigned int *left); int git_mwindow_file_register(git_mwindow_file *mwf); void git_mwindow_file_deregister(git_mwindow_file *mwf); void git_mwindow_close(git_mwindow **w_cursor); #endif libgit2-0.19.0/src/netops.c000066400000000000000000000322371216214232500154050ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #ifndef _WIN32 # include # include # include # include # include # include # include #else # include # ifdef _MSC_VER # pragma comment(lib, "ws2_32") # endif #endif #ifdef __FreeBSD__ # include #endif #ifdef GIT_SSL # include # include # include #endif #include #include "git2/errors.h" #include "common.h" #include "netops.h" #include "posix.h" #include "buffer.h" #ifdef GIT_WIN32 static void net_set_error(const char *str) { int error = WSAGetLastError(); char * win32_error = git_win32_get_error_message(error); if (win32_error) { giterr_set(GITERR_NET, "%s: %s", str, win32_error); git__free(win32_error); } else { giterr_set(GITERR_NET, str); } } #else static void net_set_error(const char *str) { giterr_set(GITERR_NET, "%s: %s", str, strerror(errno)); } #endif #ifdef GIT_SSL static int ssl_set_error(gitno_ssl *ssl, int error) { int err; unsigned long e; err = SSL_get_error(ssl->ssl, error); assert(err != SSL_ERROR_WANT_READ); assert(err != SSL_ERROR_WANT_WRITE); switch (err) { case SSL_ERROR_WANT_CONNECT: case SSL_ERROR_WANT_ACCEPT: giterr_set(GITERR_NET, "SSL error: connection failure\n"); break; case SSL_ERROR_WANT_X509_LOOKUP: giterr_set(GITERR_NET, "SSL error: x509 error\n"); break; case SSL_ERROR_SYSCALL: e = ERR_get_error(); if (e > 0) { giterr_set(GITERR_NET, "SSL error: %s", ERR_error_string(e, NULL)); break; } else if (error < 0) { giterr_set(GITERR_OS, "SSL error: syscall failure"); break; } giterr_set(GITERR_NET, "SSL error: received early EOF"); break; case SSL_ERROR_SSL: e = ERR_get_error(); giterr_set(GITERR_NET, "SSL error: %s", ERR_error_string(e, NULL)); break; case SSL_ERROR_NONE: case SSL_ERROR_ZERO_RETURN: default: giterr_set(GITERR_NET, "SSL error: unknown error"); break; } return -1; } #endif int gitno_recv(gitno_buffer *buf) { return buf->recv(buf); } #ifdef GIT_SSL static int gitno__recv_ssl(gitno_buffer *buf) { int ret; do { ret = SSL_read(buf->socket->ssl.ssl, buf->data + buf->offset, buf->len - buf->offset); } while (SSL_get_error(buf->socket->ssl.ssl, ret) == SSL_ERROR_WANT_READ); if (ret < 0) { net_set_error("Error receiving socket data"); return -1; } buf->offset += ret; return ret; } #endif static int gitno__recv(gitno_buffer *buf) { int ret; ret = p_recv(buf->socket->socket, buf->data + buf->offset, buf->len - buf->offset, 0); if (ret < 0) { net_set_error("Error receiving socket data"); return -1; } buf->offset += ret; return ret; } void gitno_buffer_setup_callback( gitno_socket *socket, gitno_buffer *buf, char *data, size_t len, int (*recv)(gitno_buffer *buf), void *cb_data) { memset(data, 0x0, len); buf->data = data; buf->len = len; buf->offset = 0; buf->socket = socket; buf->recv = recv; buf->cb_data = cb_data; } void gitno_buffer_setup(gitno_socket *socket, gitno_buffer *buf, char *data, size_t len) { #ifdef GIT_SSL if (socket->ssl.ctx) { gitno_buffer_setup_callback(socket, buf, data, len, gitno__recv_ssl, NULL); return; } #endif gitno_buffer_setup_callback(socket, buf, data, len, gitno__recv, NULL); } /* Consume up to ptr and move the rest of the buffer to the beginning */ void gitno_consume(gitno_buffer *buf, const char *ptr) { size_t consumed; assert(ptr - buf->data >= 0); assert(ptr - buf->data <= (int) buf->len); consumed = ptr - buf->data; memmove(buf->data, ptr, buf->offset - consumed); memset(buf->data + buf->offset, 0x0, buf->len - buf->offset); buf->offset -= consumed; } /* Consume const bytes and move the rest of the buffer to the beginning */ void gitno_consume_n(gitno_buffer *buf, size_t cons) { memmove(buf->data, buf->data + cons, buf->len - buf->offset); memset(buf->data + cons, 0x0, buf->len - buf->offset); buf->offset -= cons; } #ifdef GIT_SSL static int gitno_ssl_teardown(gitno_ssl *ssl) { int ret; ret = SSL_shutdown(ssl->ssl); if (ret < 0) ret = ssl_set_error(ssl, ret); else ret = 0; SSL_free(ssl->ssl); SSL_CTX_free(ssl->ctx); return ret; } /* Match host names according to RFC 2818 rules */ static int match_host(const char *pattern, const char *host) { for (;;) { char c = tolower(*pattern++); if (c == '\0') return *host ? -1 : 0; if (c == '*') { c = *pattern; /* '*' at the end matches everything left */ if (c == '\0') return 0; /* * We've found a pattern, so move towards the next matching * char. The '.' is handled specially because wildcards aren't * allowed to cross subdomains. */ while(*host) { char h = tolower(*host); if (c == h) return match_host(pattern, host++); if (h == '.') return match_host(pattern, host); host++; } return -1; } if (c != tolower(*host++)) return -1; } return -1; } static int check_host_name(const char *name, const char *host) { if (!strcasecmp(name, host)) return 0; if (match_host(name, host) < 0) return -1; return 0; } static int verify_server_cert(gitno_ssl *ssl, const char *host) { X509 *cert; X509_NAME *peer_name; ASN1_STRING *str; unsigned char *peer_cn = NULL; int matched = -1, type = GEN_DNS; GENERAL_NAMES *alts; struct in6_addr addr6; struct in_addr addr4; void *addr; int i = -1,j; if (SSL_get_verify_result(ssl->ssl) != X509_V_OK) { giterr_set(GITERR_SSL, "The SSL certificate is invalid"); return -1; } /* Try to parse the host as an IP address to see if it is */ if (p_inet_pton(AF_INET, host, &addr4)) { type = GEN_IPADD; addr = &addr4; } else { if(p_inet_pton(AF_INET6, host, &addr6)) { type = GEN_IPADD; addr = &addr6; } } cert = SSL_get_peer_certificate(ssl->ssl); /* Check the alternative names */ alts = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL); if (alts) { int num; num = sk_GENERAL_NAME_num(alts); for (i = 0; i < num && matched != 1; i++) { const GENERAL_NAME *gn = sk_GENERAL_NAME_value(alts, i); const char *name = (char *) ASN1_STRING_data(gn->d.ia5); size_t namelen = (size_t) ASN1_STRING_length(gn->d.ia5); /* Skip any names of a type we're not looking for */ if (gn->type != type) continue; if (type == GEN_DNS) { /* If it contains embedded NULs, don't even try */ if (memchr(name, '\0', namelen)) continue; if (check_host_name(name, host) < 0) matched = 0; else matched = 1; } else if (type == GEN_IPADD) { /* Here name isn't so much a name but a binary representation of the IP */ matched = !!memcmp(name, addr, namelen); } } } GENERAL_NAMES_free(alts); if (matched == 0) goto cert_fail; if (matched == 1) return 0; /* If no alternative names are available, check the common name */ peer_name = X509_get_subject_name(cert); if (peer_name == NULL) goto on_error; if (peer_name) { /* Get the index of the last CN entry */ while ((j = X509_NAME_get_index_by_NID(peer_name, NID_commonName, i)) >= 0) i = j; } if (i < 0) goto on_error; str = X509_NAME_ENTRY_get_data(X509_NAME_get_entry(peer_name, i)); if (str == NULL) goto on_error; /* Work around a bug in OpenSSL whereby ASN1_STRING_to_UTF8 fails if it's already in utf-8 */ if (ASN1_STRING_type(str) == V_ASN1_UTF8STRING) { int size = ASN1_STRING_length(str); if (size > 0) { peer_cn = OPENSSL_malloc(size + 1); GITERR_CHECK_ALLOC(peer_cn); memcpy(peer_cn, ASN1_STRING_data(str), size); peer_cn[size] = '\0'; } } else { int size = ASN1_STRING_to_UTF8(&peer_cn, str); GITERR_CHECK_ALLOC(peer_cn); if (memchr(peer_cn, '\0', size)) goto cert_fail; } if (check_host_name((char *)peer_cn, host) < 0) goto cert_fail; OPENSSL_free(peer_cn); return 0; on_error: OPENSSL_free(peer_cn); return ssl_set_error(ssl, 0); cert_fail: OPENSSL_free(peer_cn); giterr_set(GITERR_SSL, "Certificate host name check failed"); return -1; } static int ssl_setup(gitno_socket *socket, const char *host, int flags) { int ret; SSL_library_init(); SSL_load_error_strings(); socket->ssl.ctx = SSL_CTX_new(SSLv23_method()); if (socket->ssl.ctx == NULL) return ssl_set_error(&socket->ssl, 0); SSL_CTX_set_mode(socket->ssl.ctx, SSL_MODE_AUTO_RETRY); SSL_CTX_set_verify(socket->ssl.ctx, SSL_VERIFY_NONE, NULL); if (!SSL_CTX_set_default_verify_paths(socket->ssl.ctx)) return ssl_set_error(&socket->ssl, 0); socket->ssl.ssl = SSL_new(socket->ssl.ctx); if (socket->ssl.ssl == NULL) return ssl_set_error(&socket->ssl, 0); if((ret = SSL_set_fd(socket->ssl.ssl, socket->socket)) == 0) return ssl_set_error(&socket->ssl, ret); if ((ret = SSL_connect(socket->ssl.ssl)) <= 0) return ssl_set_error(&socket->ssl, ret); if (GITNO_CONNECT_SSL_NO_CHECK_CERT & flags) return 0; return verify_server_cert(&socket->ssl, host); } #endif static int gitno__close(GIT_SOCKET s) { #ifdef GIT_WIN32 if (SOCKET_ERROR == closesocket(s)) return -1; if (0 != WSACleanup()) { giterr_set(GITERR_OS, "Winsock cleanup failed"); return -1; } return 0; #else return close(s); #endif } int gitno_connect(gitno_socket *s_out, const char *host, const char *port, int flags) { struct addrinfo *info = NULL, *p; struct addrinfo hints; GIT_SOCKET s = INVALID_SOCKET; int ret; #ifdef GIT_WIN32 /* on win32, the WSA context needs to be initialized * before any socket calls can be performed */ WSADATA wsd; if (WSAStartup(MAKEWORD(2,2), &wsd) != 0) { giterr_set(GITERR_OS, "Winsock init failed"); return -1; } if (LOBYTE(wsd.wVersion) != 2 || HIBYTE(wsd.wVersion) != 2) { WSACleanup(); giterr_set(GITERR_OS, "Winsock init failed"); return -1; } #endif /* Zero the socket structure provided */ memset(s_out, 0x0, sizeof(gitno_socket)); memset(&hints, 0x0, sizeof(struct addrinfo)); hints.ai_socktype = SOCK_STREAM; hints.ai_family = AF_UNSPEC; if ((ret = p_getaddrinfo(host, port, &hints, &info)) < 0) { giterr_set(GITERR_NET, "Failed to resolve address for %s: %s", host, p_gai_strerror(ret)); return -1; } for (p = info; p != NULL; p = p->ai_next) { s = socket(p->ai_family, p->ai_socktype, p->ai_protocol); if (s == INVALID_SOCKET) { net_set_error("error creating socket"); break; } if (connect(s, p->ai_addr, (socklen_t)p->ai_addrlen) == 0) break; /* If we can't connect, try the next one */ gitno__close(s); s = INVALID_SOCKET; } /* Oops, we couldn't connect to any address */ if (s == INVALID_SOCKET && p == NULL) { giterr_set(GITERR_OS, "Failed to connect to %s", host); p_freeaddrinfo(info); return -1; } s_out->socket = s; p_freeaddrinfo(info); #ifdef GIT_SSL if ((flags & GITNO_CONNECT_SSL) && ssl_setup(s_out, host, flags) < 0) return -1; #else /* SSL is not supported */ if (flags & GITNO_CONNECT_SSL) { giterr_set(GITERR_OS, "SSL is not supported by this copy of libgit2."); return -1; } #endif return 0; } #ifdef GIT_SSL static int gitno_send_ssl(gitno_ssl *ssl, const char *msg, size_t len, int flags) { int ret; size_t off = 0; GIT_UNUSED(flags); while (off < len) { ret = SSL_write(ssl->ssl, msg + off, len - off); if (ret <= 0 && ret != SSL_ERROR_WANT_WRITE) return ssl_set_error(ssl, ret); off += ret; } return off; } #endif int gitno_send(gitno_socket *socket, const char *msg, size_t len, int flags) { int ret; size_t off = 0; #ifdef GIT_SSL if (socket->ssl.ctx) return gitno_send_ssl(&socket->ssl, msg, len, flags); #endif while (off < len) { errno = 0; ret = p_send(socket->socket, msg + off, len - off, flags); if (ret < 0) { net_set_error("Error sending data"); return -1; } off += ret; } return (int)off; } int gitno_close(gitno_socket *s) { #ifdef GIT_SSL if (s->ssl.ctx && gitno_ssl_teardown(&s->ssl) < 0) return -1; #endif return gitno__close(s->socket); } int gitno_select_in(gitno_buffer *buf, long int sec, long int usec) { fd_set fds; struct timeval tv; tv.tv_sec = sec; tv.tv_usec = usec; FD_ZERO(&fds); FD_SET(buf->socket->socket, &fds); /* The select(2) interface is silly */ return select((int)buf->socket->socket + 1, &fds, NULL, NULL, &tv); } int gitno_extract_url_parts( char **host, char **port, char **username, char **password, const char *url, const char *default_port) { char *colon, *slash, *at, *end; const char *start; /* * * ==> [user[:pass]@]hostname.tld[:port]/resource */ colon = strchr(url, ':'); slash = strchr(url, '/'); at = strchr(url, '@'); if (slash == NULL) { giterr_set(GITERR_NET, "Malformed URL: missing /"); return -1; } start = url; if (at && at < slash) { start = at+1; *username = git__substrdup(url, at - url); } if (colon && colon < at) { git__free(*username); *username = git__substrdup(url, colon-url); *password = git__substrdup(colon+1, at-colon-1); colon = strchr(at, ':'); } if (colon == NULL) { *port = git__strdup(default_port); } else { *port = git__substrdup(colon + 1, slash - colon - 1); } GITERR_CHECK_ALLOC(*port); end = colon == NULL ? slash : colon; *host = git__substrdup(start, end - start); GITERR_CHECK_ALLOC(*host); return 0; } libgit2-0.19.0/src/netops.h000066400000000000000000000035731216214232500154130ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #ifndef INCLUDE_netops_h__ #define INCLUDE_netops_h__ #include "posix.h" #include "common.h" #ifdef GIT_SSL # include #endif struct gitno_ssl { #ifdef GIT_SSL SSL_CTX *ctx; SSL *ssl; #else size_t dummy; #endif }; typedef struct gitno_ssl gitno_ssl; /* Represents a socket that may or may not be using SSL */ struct gitno_socket { GIT_SOCKET socket; gitno_ssl ssl; }; typedef struct gitno_socket gitno_socket; struct gitno_buffer { char *data; size_t len; size_t offset; gitno_socket *socket; int (*recv)(struct gitno_buffer *buffer); void *cb_data; }; typedef struct gitno_buffer gitno_buffer; /* Flags to gitno_connect */ enum { /* Attempt to create an SSL connection. */ GITNO_CONNECT_SSL = 1, /* Valid only when GITNO_CONNECT_SSL is also specified. * Indicates that the server certificate should not be validated. */ GITNO_CONNECT_SSL_NO_CHECK_CERT = 2, }; void gitno_buffer_setup(gitno_socket *t, gitno_buffer *buf, char *data, size_t len); void gitno_buffer_setup_callback(gitno_socket *t, gitno_buffer *buf, char *data, size_t len, int (*recv)(gitno_buffer *buf), void *cb_data); int gitno_recv(gitno_buffer *buf); void gitno_consume(gitno_buffer *buf, const char *ptr); void gitno_consume_n(gitno_buffer *buf, size_t cons); int gitno_connect(gitno_socket *socket, const char *host, const char *port, int flags); int gitno_send(gitno_socket *socket, const char *msg, size_t len, int flags); int gitno_close(gitno_socket *s); int gitno_select_in(gitno_buffer *buf, long int sec, long int usec); int gitno_extract_url_parts( char **host, char **port, char **username, char **password, const char *url, const char *default_port); #endif libgit2-0.19.0/src/notes.c000066400000000000000000000331651216214232500152260ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #include "notes.h" #include "git2.h" #include "refs.h" #include "config.h" #include "iterator.h" #include "signature.h" static int note_error_notfound(void) { giterr_set(GITERR_INVALID, "Note could not be found"); return GIT_ENOTFOUND; } static int find_subtree_in_current_level( git_tree **out, git_repository *repo, git_tree *parent, const char *annotated_object_sha, int fanout) { size_t i; const git_tree_entry *entry; *out = NULL; if (parent == NULL) return note_error_notfound(); for (i = 0; i < git_tree_entrycount(parent); i++) { entry = git_tree_entry_byindex(parent, i); if (!git__ishex(git_tree_entry_name(entry))) continue; if (S_ISDIR(git_tree_entry_filemode(entry)) && strlen(git_tree_entry_name(entry)) == 2 && !strncmp(git_tree_entry_name(entry), annotated_object_sha + fanout, 2)) return git_tree_lookup(out, repo, git_tree_entry_id(entry)); /* Not a DIR, so do we have an already existing blob? */ if (!strcmp(git_tree_entry_name(entry), annotated_object_sha + fanout)) return GIT_EEXISTS; } return note_error_notfound(); } static int find_subtree_r(git_tree **out, git_tree *root, git_repository *repo, const char *target, int *fanout) { int error; git_tree *subtree = NULL; *out = NULL; error = find_subtree_in_current_level(&subtree, repo, root, target, *fanout); if (error == GIT_EEXISTS) return git_tree_lookup(out, repo, git_tree_id(root)); if (error < 0) return error; *fanout += 2; error = find_subtree_r(out, subtree, repo, target, fanout); git_tree_free(subtree); return error; } static int find_blob(git_oid *blob, git_tree *tree, const char *target) { size_t i; const git_tree_entry *entry; for (i=0; ioid, note_oid); note->message = git__strdup((char *)git_blob_rawcontent(blob)); GITERR_CHECK_ALLOC(note->message); *out = note; return 0; } static int note_lookup( git_note **out, git_repository *repo, git_tree *tree, const char *target) { int error, fanout = 0; git_oid oid; git_blob *blob = NULL; git_note *note = NULL; git_tree *subtree = NULL; if ((error = find_subtree_r(&subtree, tree, repo, target, &fanout)) < 0) goto cleanup; if ((error = find_blob(&oid, subtree, target + fanout)) < 0) goto cleanup; if ((error = git_blob_lookup(&blob, repo, &oid)) < 0) goto cleanup; if ((error = note_new(¬e, &oid, blob)) < 0) goto cleanup; *out = note; cleanup: git_tree_free(subtree); git_blob_free(blob); return error; } static int note_remove(git_repository *repo, const git_signature *author, const git_signature *committer, const char *notes_ref, git_tree *tree, const char *target, git_commit **parents) { int error; git_tree *tree_after_removal = NULL; git_oid oid; if ((error = manipulate_note_in_tree_r( &tree_after_removal, repo, tree, NULL, target, 0, remove_note_in_tree_eexists_cb, remove_note_in_tree_enotfound_cb)) < 0) goto cleanup; error = git_commit_create(&oid, repo, notes_ref, author, committer, NULL, GIT_NOTES_DEFAULT_MSG_RM, tree_after_removal, *parents == NULL ? 0 : 1, (const git_commit **) parents); cleanup: git_tree_free(tree_after_removal); return error; } static int note_get_default_ref(const char **out, git_repository *repo) { int ret; git_config *cfg; *out = NULL; if (git_repository_config__weakptr(&cfg, repo) < 0) return -1; ret = git_config_get_string(out, cfg, "core.notesRef"); if (ret == GIT_ENOTFOUND) { giterr_clear(); *out = GIT_NOTES_DEFAULT_REF; return 0; } return ret; } static int normalize_namespace(const char **notes_ref, git_repository *repo) { if (*notes_ref) return 0; return note_get_default_ref(notes_ref, repo); } static int retrieve_note_tree_and_commit( git_tree **tree_out, git_commit **commit_out, git_repository *repo, const char **notes_ref) { int error; git_oid oid; if ((error = normalize_namespace(notes_ref, repo)) < 0) return error; if ((error = git_reference_name_to_id(&oid, repo, *notes_ref)) < 0) return error; if (git_commit_lookup(commit_out, repo, &oid) < 0) return error; if ((error = git_commit_tree(tree_out, *commit_out)) < 0) return error; return 0; } int git_note_read(git_note **out, git_repository *repo, const char *notes_ref, const git_oid *oid) { int error; char *target = NULL; git_tree *tree = NULL; git_commit *commit = NULL; target = git_oid_allocfmt(oid); GITERR_CHECK_ALLOC(target); if (!(error = retrieve_note_tree_and_commit( &tree, &commit, repo, ¬es_ref))) error = note_lookup(out, repo, tree, target); git__free(target); git_tree_free(tree); git_commit_free(commit); return error; } int git_note_create( git_oid *out, git_repository *repo, const git_signature *author, const git_signature *committer, const char *notes_ref, const git_oid *oid, const char *note, int allow_note_overwrite) { int error; char *target = NULL; git_commit *commit = NULL; git_tree *tree = NULL; target = git_oid_allocfmt(oid); GITERR_CHECK_ALLOC(target); error = retrieve_note_tree_and_commit(&tree, &commit, repo, ¬es_ref); if (error < 0 && error != GIT_ENOTFOUND) goto cleanup; error = note_write(out, repo, author, committer, notes_ref, note, tree, target, &commit, allow_note_overwrite); cleanup: git__free(target); git_commit_free(commit); git_tree_free(tree); return error; } int git_note_remove(git_repository *repo, const char *notes_ref, const git_signature *author, const git_signature *committer, const git_oid *oid) { int error; char *target = NULL; git_commit *commit = NULL; git_tree *tree = NULL; target = git_oid_allocfmt(oid); GITERR_CHECK_ALLOC(target); if (!(error = retrieve_note_tree_and_commit( &tree, &commit, repo, ¬es_ref))) error = note_remove( repo, author, committer, notes_ref, tree, target, &commit); git__free(target); git_commit_free(commit); git_tree_free(tree); return error; } int git_note_default_ref(const char **out, git_repository *repo) { assert(repo); return note_get_default_ref(out, repo); } const char * git_note_message(const git_note *note) { assert(note); return note->message; } const git_oid * git_note_oid(const git_note *note) { assert(note); return ¬e->oid; } void git_note_free(git_note *note) { if (note == NULL) return; git__free(note->message); git__free(note); } static int process_entry_path( const char* entry_path, git_oid *annotated_object_id) { int error = 0; size_t i = 0, j = 0, len; git_buf buf = GIT_BUF_INIT; if ((error = git_buf_puts(&buf, entry_path)) < 0) goto cleanup; len = git_buf_len(&buf); while (i < len) { if (buf.ptr[i] == '/') { i++; continue; } if (git__fromhex(buf.ptr[i]) < 0) { /* This is not a note entry */ goto cleanup; } if (i != j) buf.ptr[j] = buf.ptr[i]; i++; j++; } buf.ptr[j] = '\0'; buf.size = j; if (j != GIT_OID_HEXSZ) { /* This is not a note entry */ goto cleanup; } error = git_oid_fromstr(annotated_object_id, buf.ptr); cleanup: git_buf_free(&buf); return error; } int git_note_foreach( git_repository *repo, const char *notes_ref, git_note_foreach_cb note_cb, void *payload) { int error; git_note_iterator *iter = NULL; git_oid note_id, annotated_id; if ((error = git_note_iterator_new(&iter, repo, notes_ref)) < 0) return error; while (!(error = git_note_next(¬e_id, &annotated_id, iter))) { if (note_cb(¬e_id, &annotated_id, payload)) { error = GIT_EUSER; break; } } if (error == GIT_ITEROVER) error = 0; git_note_iterator_free(iter); return error; } void git_note_iterator_free(git_note_iterator *it) { if (it == NULL) return; git_iterator_free(it); } int git_note_iterator_new( git_note_iterator **it, git_repository *repo, const char *notes_ref) { int error; git_commit *commit = NULL; git_tree *tree = NULL; error = retrieve_note_tree_and_commit(&tree, &commit, repo, ¬es_ref); if (error < 0) goto cleanup; if ((error = git_iterator_for_tree(it, tree, 0, NULL, NULL)) < 0) git_iterator_free(*it); cleanup: git_tree_free(tree); git_commit_free(commit); return error; } int git_note_next( git_oid* note_id, git_oid* annotated_id, git_note_iterator *it) { int error; const git_index_entry *item; if ((error = git_iterator_current(&item, it)) < 0) return error; git_oid_cpy(note_id, &item->oid); if (!(error = process_entry_path(item->path, annotated_id))) git_iterator_advance(NULL, it); return error; } libgit2-0.19.0/src/notes.h000066400000000000000000000012031216214232500152170ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #ifndef INCLUDE_note_h__ #define INCLUDE_note_h__ #include "common.h" #include "git2/oid.h" #include "git2/types.h" #define GIT_NOTES_DEFAULT_REF "refs/notes/commits" #define GIT_NOTES_DEFAULT_MSG_ADD \ "Notes added by 'git_note_create' from libgit2" #define GIT_NOTES_DEFAULT_MSG_RM \ "Notes removed by 'git_note_remove' from libgit2" struct git_note { git_oid oid; char *message; }; #endif /* INCLUDE_notes_h__ */ libgit2-0.19.0/src/object.c000066400000000000000000000207531216214232500153430ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #include #include "git2/object.h" #include "common.h" #include "repository.h" #include "commit.h" #include "tree.h" #include "blob.h" #include "tag.h" static const int OBJECT_BASE_SIZE = 4096; typedef struct { const char *str; /* type name string */ size_t size; /* size in bytes of the object structure */ int (*parse)(void *self, git_odb_object *obj); void (*free)(void *self); } git_object_def; static git_object_def git_objects_table[] = { /* 0 = GIT_OBJ__EXT1 */ { "", 0, NULL, NULL }, /* 1 = GIT_OBJ_COMMIT */ { "commit", sizeof(git_commit), git_commit__parse, git_commit__free }, /* 2 = GIT_OBJ_TREE */ { "tree", sizeof(git_tree), git_tree__parse, git_tree__free }, /* 3 = GIT_OBJ_BLOB */ { "blob", sizeof(git_blob), git_blob__parse, git_blob__free }, /* 4 = GIT_OBJ_TAG */ { "tag", sizeof(git_tag), git_tag__parse, git_tag__free }, /* 5 = GIT_OBJ__EXT2 */ { "", 0, NULL, NULL }, /* 6 = GIT_OBJ_OFS_DELTA */ { "OFS_DELTA", 0, NULL, NULL }, /* 7 = GIT_OBJ_REF_DELTA */ { "REF_DELTA", 0, NULL, NULL }, }; int git_object__from_odb_object( git_object **object_out, git_repository *repo, git_odb_object *odb_obj, git_otype type) { int error; size_t object_size; git_object_def *def; git_object *object = NULL; assert(object_out); *object_out = NULL; /* Validate type match */ if (type != GIT_OBJ_ANY && type != odb_obj->cached.type) { giterr_set(GITERR_INVALID, "The requested type does not match the type in the ODB"); return GIT_ENOTFOUND; } if ((object_size = git_object__size(odb_obj->cached.type)) == 0) { giterr_set(GITERR_INVALID, "The requested type is invalid"); return GIT_ENOTFOUND; } /* Allocate and initialize base object */ object = git__calloc(1, object_size); GITERR_CHECK_ALLOC(object); git_oid_cpy(&object->cached.oid, &odb_obj->cached.oid); object->cached.type = odb_obj->cached.type; object->cached.size = odb_obj->cached.size; object->repo = repo; /* Parse raw object data */ def = &git_objects_table[odb_obj->cached.type]; assert(def->free && def->parse); if ((error = def->parse(object, odb_obj)) < 0) def->free(object); else *object_out = git_cache_store_parsed(&repo->objects, object); return error; } void git_object__free(void *obj) { git_otype type = ((git_object *)obj)->cached.type; if (type < 0 || ((size_t)type) >= ARRAY_SIZE(git_objects_table) || !git_objects_table[type].free) git__free(obj); else git_objects_table[type].free(obj); } int git_object_lookup_prefix( git_object **object_out, git_repository *repo, const git_oid *id, size_t len, git_otype type) { git_object *object = NULL; git_odb *odb = NULL; git_odb_object *odb_obj = NULL; int error = 0; assert(repo && object_out && id); if (len < GIT_OID_MINPREFIXLEN) { giterr_set(GITERR_OBJECT, "Ambiguous lookup - OID prefix is too short"); return GIT_EAMBIGUOUS; } error = git_repository_odb__weakptr(&odb, repo); if (error < 0) return error; if (len > GIT_OID_HEXSZ) len = GIT_OID_HEXSZ; if (len == GIT_OID_HEXSZ) { git_cached_obj *cached = NULL; /* We want to match the full id : we can first look up in the cache, * since there is no need to check for non ambiguousity */ cached = git_cache_get_any(&repo->objects, id); if (cached != NULL) { if (cached->flags == GIT_CACHE_STORE_PARSED) { object = (git_object *)cached; if (type != GIT_OBJ_ANY && type != object->cached.type) { git_object_free(object); giterr_set(GITERR_INVALID, "The requested type does not match the type in ODB"); return GIT_ENOTFOUND; } *object_out = object; return 0; } else if (cached->flags == GIT_CACHE_STORE_RAW) { odb_obj = (git_odb_object *)cached; } else { assert(!"Wrong caching type in the global object cache"); } } else { /* Object was not found in the cache, let's explore the backends. * We could just use git_odb_read_unique_short_oid, * it is the same cost for packed and loose object backends, * but it may be much more costly for sqlite and hiredis. */ error = git_odb_read(&odb_obj, odb, id); } } else { git_oid short_oid; /* We copy the first len*4 bits from id and fill the remaining with 0s */ memcpy(short_oid.id, id->id, (len + 1) / 2); if (len % 2) short_oid.id[len / 2] &= 0xF0; memset(short_oid.id + (len + 1) / 2, 0, (GIT_OID_HEXSZ - len) / 2); /* If len < GIT_OID_HEXSZ (a strict short oid was given), we have * 2 options : * - We always search in the cache first. If we find that short oid is * ambiguous, we can stop. But in all the other cases, we must then * explore all the backends (to find an object if there was match, * or to check that oid is not ambiguous if we have found 1 match in * the cache) * - We never explore the cache, go right to exploring the backends * We chose the latter : we explore directly the backends. */ error = git_odb_read_prefix(&odb_obj, odb, &short_oid, len); } if (error < 0) return error; error = git_object__from_odb_object(object_out, repo, odb_obj, type); git_odb_object_free(odb_obj); return error; } int git_object_lookup(git_object **object_out, git_repository *repo, const git_oid *id, git_otype type) { return git_object_lookup_prefix(object_out, repo, id, GIT_OID_HEXSZ, type); } void git_object_free(git_object *object) { if (object == NULL) return; git_cached_obj_decref(object); } const git_oid *git_object_id(const git_object *obj) { assert(obj); return &obj->cached.oid; } git_otype git_object_type(const git_object *obj) { assert(obj); return obj->cached.type; } git_repository *git_object_owner(const git_object *obj) { assert(obj); return obj->repo; } const char *git_object_type2string(git_otype type) { if (type < 0 || ((size_t) type) >= ARRAY_SIZE(git_objects_table)) return ""; return git_objects_table[type].str; } git_otype git_object_string2type(const char *str) { size_t i; if (!str || !*str) return GIT_OBJ_BAD; for (i = 0; i < ARRAY_SIZE(git_objects_table); i++) if (!strcmp(str, git_objects_table[i].str)) return (git_otype)i; return GIT_OBJ_BAD; } int git_object_typeisloose(git_otype type) { if (type < 0 || ((size_t) type) >= ARRAY_SIZE(git_objects_table)) return 0; return (git_objects_table[type].size > 0) ? 1 : 0; } size_t git_object__size(git_otype type) { if (type < 0 || ((size_t) type) >= ARRAY_SIZE(git_objects_table)) return 0; return git_objects_table[type].size; } static int dereference_object(git_object **dereferenced, git_object *obj) { git_otype type = git_object_type(obj); switch (type) { case GIT_OBJ_COMMIT: return git_commit_tree((git_tree **)dereferenced, (git_commit*)obj); case GIT_OBJ_TAG: return git_tag_target(dereferenced, (git_tag*)obj); case GIT_OBJ_BLOB: return GIT_ENOTFOUND; case GIT_OBJ_TREE: return GIT_EAMBIGUOUS; default: return GIT_EINVALIDSPEC; } } static int peel_error(int error, const git_oid *oid, git_otype type) { const char *type_name; char hex_oid[GIT_OID_HEXSZ + 1]; type_name = git_object_type2string(type); git_oid_fmt(hex_oid, oid); hex_oid[GIT_OID_HEXSZ] = '\0'; giterr_set(GITERR_OBJECT, "The git_object of id '%s' can not be " "successfully peeled into a %s (git_otype=%i).", hex_oid, type_name, type); return error; } int git_object_peel( git_object **peeled, const git_object *object, git_otype target_type) { git_object *source, *deref = NULL; int error; assert(object && peeled); if (git_object_type(object) == target_type) return git_object_dup(peeled, (git_object *)object); assert(target_type == GIT_OBJ_TAG || target_type == GIT_OBJ_COMMIT || target_type == GIT_OBJ_TREE || target_type == GIT_OBJ_BLOB || target_type == GIT_OBJ_ANY); source = (git_object *)object; while (!(error = dereference_object(&deref, source))) { if (source != object) git_object_free(source); if (git_object_type(deref) == target_type) { *peeled = deref; return 0; } if (target_type == GIT_OBJ_ANY && git_object_type(deref) != git_object_type(object)) { *peeled = deref; return 0; } source = deref; deref = NULL; } if (source != object) git_object_free(source); git_object_free(deref); if (error) error = peel_error(error, git_object_id(object), target_type); return error; } int git_object_dup(git_object **dest, git_object *source) { git_cached_obj_incref(source); *dest = source; return 0; } libgit2-0.19.0/src/object.h000066400000000000000000000015371216214232500153470ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #ifndef INCLUDE_object_h__ #define INCLUDE_object_h__ /** Base git object for inheritance */ struct git_object { git_cached_obj cached; git_repository *repo; }; /* fully free the object; internal method, DO NOT EXPORT */ void git_object__free(void *object); int git_object__from_odb_object( git_object **object_out, git_repository *repo, git_odb_object *odb_obj, git_otype type); int git_object__resolve_to_type(git_object **obj, git_otype type); int git_oid__parse(git_oid *oid, const char **buffer_out, const char *buffer_end, const char *header); void git_oid__writebuf(git_buf *buf, const char *header, const git_oid *oid); #endif libgit2-0.19.0/src/object_api.c000066400000000000000000000055541216214232500161760ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #include "git2/object.h" #include "common.h" #include "repository.h" #include "commit.h" #include "tree.h" #include "blob.h" #include "tag.h" /** * Blob */ int git_commit_lookup(git_commit **out, git_repository *repo, const git_oid *id) { return git_object_lookup((git_object **)out, repo, id, GIT_OBJ_COMMIT); } int git_commit_lookup_prefix(git_commit **out, git_repository *repo, const git_oid *id, size_t len) { return git_object_lookup_prefix((git_object **)out, repo, id, len, GIT_OBJ_COMMIT); } void git_commit_free(git_commit *obj) { git_object_free((git_object *)obj); } const git_oid *git_commit_id(const git_commit *obj) { return git_object_id((const git_object *)obj); } git_repository *git_commit_owner(const git_commit *obj) { return git_object_owner((const git_object *)obj); } /** * Tree */ int git_tree_lookup(git_tree **out, git_repository *repo, const git_oid *id) { return git_object_lookup((git_object **)out, repo, id, GIT_OBJ_TREE); } int git_tree_lookup_prefix(git_tree **out, git_repository *repo, const git_oid *id, size_t len) { return git_object_lookup_prefix((git_object **)out, repo, id, len, GIT_OBJ_TREE); } void git_tree_free(git_tree *obj) { git_object_free((git_object *)obj); } const git_oid *git_tree_id(const git_tree *obj) { return git_object_id((const git_object *)obj); } git_repository *git_tree_owner(const git_tree *obj) { return git_object_owner((const git_object *)obj); } /** * Tag */ int git_tag_lookup(git_tag **out, git_repository *repo, const git_oid *id) { return git_object_lookup((git_object **)out, repo, id, GIT_OBJ_TAG); } int git_tag_lookup_prefix(git_tag **out, git_repository *repo, const git_oid *id, size_t len) { return git_object_lookup_prefix((git_object **)out, repo, id, len, GIT_OBJ_TAG); } void git_tag_free(git_tag *obj) { git_object_free((git_object *)obj); } const git_oid *git_tag_id(const git_tag *obj) { return git_object_id((const git_object *)obj); } git_repository *git_tag_owner(const git_tag *obj) { return git_object_owner((const git_object *)obj); } /** * Blob */ int git_blob_lookup(git_blob **out, git_repository *repo, const git_oid *id) { return git_object_lookup((git_object **)out, repo, id, GIT_OBJ_BLOB); } int git_blob_lookup_prefix(git_blob **out, git_repository *repo, const git_oid *id, size_t len) { return git_object_lookup_prefix((git_object **)out, repo, id, len, GIT_OBJ_BLOB); } void git_blob_free(git_blob *obj) { git_object_free((git_object *)obj); } const git_oid *git_blob_id(const git_blob *obj) { return git_object_id((const git_object *)obj); } git_repository *git_blob_owner(const git_blob *obj) { return git_object_owner((const git_object *)obj); } libgit2-0.19.0/src/odb.c000066400000000000000000000537111216214232500146410ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #include "common.h" #include #include "git2/object.h" #include "git2/sys/odb_backend.h" #include "fileops.h" #include "hash.h" #include "odb.h" #include "delta-apply.h" #include "filter.h" #include "repository.h" #include "git2/odb_backend.h" #include "git2/oid.h" #define GIT_ALTERNATES_FILE "info/alternates" /* TODO: is this correct? */ #define GIT_LOOSE_PRIORITY 2 #define GIT_PACKED_PRIORITY 1 #define GIT_ALTERNATES_MAX_DEPTH 5 typedef struct { git_odb_backend *backend; int priority; bool is_alternate; ino_t disk_inode; } backend_internal; static git_cache *odb_cache(git_odb *odb) { if (odb->rc.owner != NULL) { git_repository *owner = odb->rc.owner; return &owner->objects; } return &odb->own_cache; } static int load_alternates(git_odb *odb, const char *objects_dir, int alternate_depth); int git_odb__format_object_header(char *hdr, size_t n, size_t obj_len, git_otype obj_type) { const char *type_str = git_object_type2string(obj_type); int len = p_snprintf(hdr, n, "%s %"PRIuZ, type_str, obj_len); assert(len > 0 && len <= (int)n); return len+1; } int git_odb__hashobj(git_oid *id, git_rawobj *obj) { git_buf_vec vec[2]; char header[64]; int hdrlen; assert(id && obj); if (!git_object_typeisloose(obj->type)) return -1; if (!obj->data && obj->len != 0) return -1; hdrlen = git_odb__format_object_header(header, sizeof(header), obj->len, obj->type); vec[0].data = header; vec[0].len = hdrlen; vec[1].data = obj->data; vec[1].len = obj->len; git_hash_vec(id, vec, 2); return 0; } static git_odb_object *odb_object__alloc(const git_oid *oid, git_rawobj *source) { git_odb_object *object = git__calloc(1, sizeof(git_odb_object)); if (object != NULL) { git_oid_cpy(&object->cached.oid, oid); object->cached.type = source->type; object->cached.size = source->len; object->buffer = source->data; } return object; } void git_odb_object__free(void *object) { if (object != NULL) { git__free(((git_odb_object *)object)->buffer); git__free(object); } } const git_oid *git_odb_object_id(git_odb_object *object) { return &object->cached.oid; } const void *git_odb_object_data(git_odb_object *object) { return object->buffer; } size_t git_odb_object_size(git_odb_object *object) { return object->cached.size; } git_otype git_odb_object_type(git_odb_object *object) { return object->cached.type; } void git_odb_object_free(git_odb_object *object) { if (object == NULL) return; git_cached_obj_decref(object); } int git_odb__hashfd(git_oid *out, git_file fd, size_t size, git_otype type) { int hdr_len; char hdr[64], buffer[2048]; git_hash_ctx ctx; ssize_t read_len = 0; int error = 0; if (!git_object_typeisloose(type)) { giterr_set(GITERR_INVALID, "Invalid object type for hash"); return -1; } if ((error = git_hash_ctx_init(&ctx)) < 0) return -1; hdr_len = git_odb__format_object_header(hdr, sizeof(hdr), size, type); if ((error = git_hash_update(&ctx, hdr, hdr_len)) < 0) goto done; while (size > 0 && (read_len = p_read(fd, buffer, sizeof(buffer))) > 0) { if ((error = git_hash_update(&ctx, buffer, read_len)) < 0) goto done; size -= read_len; } /* If p_read returned an error code, the read obviously failed. * If size is not zero, the file was truncated after we originally * stat'd it, so we consider this a read failure too */ if (read_len < 0 || size > 0) { giterr_set(GITERR_OS, "Error reading file for hashing"); error = -1; goto done; return -1; } error = git_hash_final(out, &ctx); done: git_hash_ctx_cleanup(&ctx); return error; } int git_odb__hashfd_filtered( git_oid *out, git_file fd, size_t size, git_otype type, git_vector *filters) { int error; git_buf raw = GIT_BUF_INIT; git_buf filtered = GIT_BUF_INIT; if (!filters || !filters->length) return git_odb__hashfd(out, fd, size, type); /* size of data is used in header, so we have to read the whole file * into memory to apply filters before beginning to calculate the hash */ if (!(error = git_futils_readbuffer_fd(&raw, fd, size))) error = git_filters_apply(&filtered, &raw, filters); git_buf_free(&raw); if (!error) error = git_odb_hash(out, filtered.ptr, filtered.size, type); git_buf_free(&filtered); return error; } int git_odb__hashlink(git_oid *out, const char *path) { struct stat st; git_off_t size; int result; if (git_path_lstat(path, &st) < 0) return -1; size = st.st_size; if (!git__is_sizet(size)) { giterr_set(GITERR_OS, "File size overflow for 32-bit systems"); return -1; } if (S_ISLNK(st.st_mode)) { char *link_data; ssize_t read_len; link_data = git__malloc((size_t)(size + 1)); GITERR_CHECK_ALLOC(link_data); read_len = p_readlink(path, link_data, (size_t)size); link_data[size] = '\0'; if (read_len != (ssize_t)size) { giterr_set(GITERR_OS, "Failed to read symlink data for '%s'", path); return -1; } result = git_odb_hash(out, link_data, (size_t)size, GIT_OBJ_BLOB); git__free(link_data); } else { int fd = git_futils_open_ro(path); if (fd < 0) return -1; result = git_odb__hashfd(out, fd, (size_t)size, GIT_OBJ_BLOB); p_close(fd); } return result; } int git_odb_hashfile(git_oid *out, const char *path, git_otype type) { git_off_t size; int result, fd = git_futils_open_ro(path); if (fd < 0) return fd; if ((size = git_futils_filesize(fd)) < 0 || !git__is_sizet(size)) { giterr_set(GITERR_OS, "File size overflow for 32-bit systems"); p_close(fd); return -1; } result = git_odb__hashfd(out, fd, (size_t)size, type); p_close(fd); return result; } int git_odb_hash(git_oid *id, const void *data, size_t len, git_otype type) { git_rawobj raw; assert(id); raw.data = (void *)data; raw.len = len; raw.type = type; return git_odb__hashobj(id, &raw); } /** * FAKE WSTREAM */ typedef struct { git_odb_stream stream; char *buffer; size_t size, written; git_otype type; } fake_wstream; static int fake_wstream__fwrite(git_oid *oid, git_odb_stream *_stream) { fake_wstream *stream = (fake_wstream *)_stream; return _stream->backend->write(oid, _stream->backend, stream->buffer, stream->size, stream->type); } static int fake_wstream__write(git_odb_stream *_stream, const char *data, size_t len) { fake_wstream *stream = (fake_wstream *)_stream; if (stream->written + len > stream->size) return -1; memcpy(stream->buffer + stream->written, data, len); stream->written += len; return 0; } static void fake_wstream__free(git_odb_stream *_stream) { fake_wstream *stream = (fake_wstream *)_stream; git__free(stream->buffer); git__free(stream); } static int init_fake_wstream(git_odb_stream **stream_p, git_odb_backend *backend, size_t size, git_otype type) { fake_wstream *stream; stream = git__calloc(1, sizeof(fake_wstream)); GITERR_CHECK_ALLOC(stream); stream->size = size; stream->type = type; stream->buffer = git__malloc(size); if (stream->buffer == NULL) { git__free(stream); return -1; } stream->stream.backend = backend; stream->stream.read = NULL; /* read only */ stream->stream.write = &fake_wstream__write; stream->stream.finalize_write = &fake_wstream__fwrite; stream->stream.free = &fake_wstream__free; stream->stream.mode = GIT_STREAM_WRONLY; *stream_p = (git_odb_stream *)stream; return 0; } /*********************************************************** * * OBJECT DATABASE PUBLIC API * * Public calls for the ODB functionality * ***********************************************************/ static int backend_sort_cmp(const void *a, const void *b) { const backend_internal *backend_a = (const backend_internal *)(a); const backend_internal *backend_b = (const backend_internal *)(b); if (backend_a->is_alternate == backend_b->is_alternate) return (backend_b->priority - backend_a->priority); return backend_a->is_alternate ? 1 : -1; } int git_odb_new(git_odb **out) { git_odb *db = git__calloc(1, sizeof(*db)); GITERR_CHECK_ALLOC(db); if (git_cache_init(&db->own_cache) < 0 || git_vector_init(&db->backends, 4, backend_sort_cmp) < 0) { git__free(db); return -1; } *out = db; GIT_REFCOUNT_INC(db); return 0; } static int add_backend_internal( git_odb *odb, git_odb_backend *backend, int priority, bool is_alternate, ino_t disk_inode) { backend_internal *internal; assert(odb && backend); GITERR_CHECK_VERSION(backend, GIT_ODB_BACKEND_VERSION, "git_odb_backend"); /* Check if the backend is already owned by another ODB */ assert(!backend->odb || backend->odb == odb); internal = git__malloc(sizeof(backend_internal)); GITERR_CHECK_ALLOC(internal); internal->backend = backend; internal->priority = priority; internal->is_alternate = is_alternate; internal->disk_inode = disk_inode; if (git_vector_insert(&odb->backends, internal) < 0) { git__free(internal); return -1; } git_vector_sort(&odb->backends); internal->backend->odb = odb; return 0; } int git_odb_add_backend(git_odb *odb, git_odb_backend *backend, int priority) { return add_backend_internal(odb, backend, priority, false, 0); } int git_odb_add_alternate(git_odb *odb, git_odb_backend *backend, int priority) { return add_backend_internal(odb, backend, priority, true, 0); } size_t git_odb_num_backends(git_odb *odb) { assert(odb); return odb->backends.length; } static int git_odb__error_unsupported_in_backend(const char *action) { giterr_set(GITERR_ODB, "Cannot %s - unsupported in the loaded odb backends", action); return -1; } int git_odb_get_backend(git_odb_backend **out, git_odb *odb, size_t pos) { backend_internal *internal; assert(odb && odb); internal = git_vector_get(&odb->backends, pos); if (internal && internal->backend) { *out = internal->backend; return 0; } giterr_set(GITERR_ODB, "No ODB backend loaded at index " PRIuZ, pos); return GIT_ENOTFOUND; } static int add_default_backends( git_odb *db, const char *objects_dir, bool as_alternates, int alternate_depth) { size_t i; struct stat st; ino_t inode; git_odb_backend *loose, *packed; /* TODO: inodes are not really relevant on Win32, so we need to find * a cross-platform workaround for this */ #ifdef GIT_WIN32 GIT_UNUSED(i); GIT_UNUSED(st); inode = 0; #else if (p_stat(objects_dir, &st) < 0) { if (as_alternates) return 0; giterr_set(GITERR_ODB, "Failed to load object database in '%s'", objects_dir); return -1; } inode = st.st_ino; for (i = 0; i < db->backends.length; ++i) { backend_internal *backend = git_vector_get(&db->backends, i); if (backend->disk_inode == inode) return 0; } #endif /* add the loose object backend */ if (git_odb_backend_loose(&loose, objects_dir, -1, 0) < 0 || add_backend_internal(db, loose, GIT_LOOSE_PRIORITY, as_alternates, inode) < 0) return -1; /* add the packed file backend */ if (git_odb_backend_pack(&packed, objects_dir) < 0 || add_backend_internal(db, packed, GIT_PACKED_PRIORITY, as_alternates, inode) < 0) return -1; return load_alternates(db, objects_dir, alternate_depth); } static int load_alternates(git_odb *odb, const char *objects_dir, int alternate_depth) { git_buf alternates_path = GIT_BUF_INIT; git_buf alternates_buf = GIT_BUF_INIT; char *buffer; const char *alternate; int result = 0; /* Git reports an error, we just ignore anything deeper */ if (alternate_depth > GIT_ALTERNATES_MAX_DEPTH) return 0; if (git_buf_joinpath(&alternates_path, objects_dir, GIT_ALTERNATES_FILE) < 0) return -1; if (git_path_exists(alternates_path.ptr) == false) { git_buf_free(&alternates_path); return 0; } if (git_futils_readbuffer(&alternates_buf, alternates_path.ptr) < 0) { git_buf_free(&alternates_path); return -1; } buffer = (char *)alternates_buf.ptr; /* add each alternate as a new backend; one alternate per line */ while ((alternate = git__strtok(&buffer, "\r\n")) != NULL) { if (*alternate == '\0' || *alternate == '#') continue; /* * Relative path: build based on the current `objects` * folder. However, relative paths are only allowed in * the current repository. */ if (*alternate == '.' && !alternate_depth) { if ((result = git_buf_joinpath(&alternates_path, objects_dir, alternate)) < 0) break; alternate = git_buf_cstr(&alternates_path); } if ((result = add_default_backends(odb, alternate, true, alternate_depth + 1)) < 0) break; } git_buf_free(&alternates_path); git_buf_free(&alternates_buf); return result; } int git_odb_add_disk_alternate(git_odb *odb, const char *path) { return add_default_backends(odb, path, true, 0); } int git_odb_open(git_odb **out, const char *objects_dir) { git_odb *db; assert(out && objects_dir); *out = NULL; if (git_odb_new(&db) < 0) return -1; if (add_default_backends(db, objects_dir, 0, 0) < 0) { git_odb_free(db); return -1; } *out = db; return 0; } static void odb_free(git_odb *db) { size_t i; for (i = 0; i < db->backends.length; ++i) { backend_internal *internal = git_vector_get(&db->backends, i); git_odb_backend *backend = internal->backend; if (backend->free) backend->free(backend); else git__free(backend); git__free(internal); } git_vector_free(&db->backends); git_cache_free(&db->own_cache); git__memzero(db, sizeof(*db)); git__free(db); } void git_odb_free(git_odb *db) { if (db == NULL) return; GIT_REFCOUNT_DEC(db, odb_free); } int git_odb_exists(git_odb *db, const git_oid *id) { git_odb_object *object; size_t i; bool found = false; bool refreshed = false; assert(db && id); if ((object = git_cache_get_raw(odb_cache(db), id)) != NULL) { git_odb_object_free(object); return (int)true; } attempt_lookup: for (i = 0; i < db->backends.length && !found; ++i) { backend_internal *internal = git_vector_get(&db->backends, i); git_odb_backend *b = internal->backend; if (b->exists != NULL) found = b->exists(b, id); } if (!found && !refreshed) { if (git_odb_refresh(db) < 0) { giterr_clear(); return (int)false; } refreshed = true; goto attempt_lookup; } return (int)found; } int git_odb_read_header(size_t *len_p, git_otype *type_p, git_odb *db, const git_oid *id) { int error; git_odb_object *object; error = git_odb__read_header_or_object(&object, len_p, type_p, db, id); if (object) git_odb_object_free(object); return error; } int git_odb__read_header_or_object( git_odb_object **out, size_t *len_p, git_otype *type_p, git_odb *db, const git_oid *id) { size_t i; int error = GIT_ENOTFOUND; git_odb_object *object; assert(db && id && out && len_p && type_p); if ((object = git_cache_get_raw(odb_cache(db), id)) != NULL) { *len_p = object->cached.size; *type_p = object->cached.type; *out = object; return 0; } *out = NULL; for (i = 0; i < db->backends.length && error < 0; ++i) { backend_internal *internal = git_vector_get(&db->backends, i); git_odb_backend *b = internal->backend; if (b->read_header != NULL) error = b->read_header(len_p, type_p, b, id); } if (!error || error == GIT_PASSTHROUGH) return 0; /* * no backend could read only the header. * try reading the whole object and freeing the contents */ if ((error = git_odb_read(&object, db, id)) < 0) return error; /* error already set - pass along */ *len_p = object->cached.size; *type_p = object->cached.type; *out = object; return 0; } int git_odb_read(git_odb_object **out, git_odb *db, const git_oid *id) { size_t i, reads = 0; int error; bool refreshed = false; git_rawobj raw; git_odb_object *object; assert(out && db && id); *out = git_cache_get_raw(odb_cache(db), id); if (*out != NULL) return 0; attempt_lookup: error = GIT_ENOTFOUND; for (i = 0; i < db->backends.length && error < 0; ++i) { backend_internal *internal = git_vector_get(&db->backends, i); git_odb_backend *b = internal->backend; if (b->read != NULL) { ++reads; error = b->read(&raw.data, &raw.len, &raw.type, b, id); } } if (error == GIT_ENOTFOUND && !refreshed) { if ((error = git_odb_refresh(db)) < 0) return error; refreshed = true; goto attempt_lookup; } if (error && error != GIT_PASSTHROUGH) { if (!reads) return git_odb__error_notfound("no match for id", id); return error; } if ((object = odb_object__alloc(id, &raw)) == NULL) return -1; *out = git_cache_store_raw(odb_cache(db), object); return 0; } int git_odb_read_prefix( git_odb_object **out, git_odb *db, const git_oid *short_id, size_t len) { size_t i; int error = GIT_ENOTFOUND; git_oid found_full_oid = {{0}}; git_rawobj raw; void *data = NULL; bool found = false, refreshed = false; git_odb_object *object; assert(out && db); if (len < GIT_OID_MINPREFIXLEN) return git_odb__error_ambiguous("prefix length too short"); if (len > GIT_OID_HEXSZ) len = GIT_OID_HEXSZ; if (len == GIT_OID_HEXSZ) { *out = git_cache_get_raw(odb_cache(db), short_id); if (*out != NULL) return 0; } attempt_lookup: for (i = 0; i < db->backends.length; ++i) { backend_internal *internal = git_vector_get(&db->backends, i); git_odb_backend *b = internal->backend; if (b->read_prefix != NULL) { git_oid full_oid; error = b->read_prefix(&full_oid, &raw.data, &raw.len, &raw.type, b, short_id, len); if (error == GIT_ENOTFOUND || error == GIT_PASSTHROUGH) continue; if (error) return error; git__free(data); data = raw.data; if (found && git_oid__cmp(&full_oid, &found_full_oid)) return git_odb__error_ambiguous("multiple matches for prefix"); found_full_oid = full_oid; found = true; } } if (!found && !refreshed) { if ((error = git_odb_refresh(db)) < 0) return error; refreshed = true; goto attempt_lookup; } if (!found) return git_odb__error_notfound("no match for prefix", short_id); if ((object = odb_object__alloc(&found_full_oid, &raw)) == NULL) return -1; *out = git_cache_store_raw(odb_cache(db), object); return 0; } int git_odb_foreach(git_odb *db, git_odb_foreach_cb cb, void *payload) { unsigned int i; backend_internal *internal; git_vector_foreach(&db->backends, i, internal) { git_odb_backend *b = internal->backend; int error = b->foreach(b, cb, payload); if (error < 0) return error; } return 0; } int git_odb_write( git_oid *oid, git_odb *db, const void *data, size_t len, git_otype type) { size_t i; int error = GIT_ERROR; git_odb_stream *stream; assert(oid && db); git_odb_hash(oid, data, len, type); if (git_odb_exists(db, oid)) return 0; 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->write != NULL) error = b->write(oid, b, data, len, type); } if (!error || error == GIT_PASSTHROUGH) return 0; /* 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_odb_open_wstream(&stream, db, len, type)) != 0) return error; 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) { size_t i, writes = 0; 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) { ++writes; error = b->writestream(stream, b, size, type); } else if (b->write != NULL) { ++writes; error = init_fake_wstream(stream, b, size, type); } } if (error == GIT_PASSTHROUGH) error = 0; if (error < 0 && !writes) error = git_odb__error_unsupported_in_backend("write object"); return error; } int git_odb_open_rstream(git_odb_stream **stream, git_odb *db, const git_oid *oid) { size_t i, reads = 0; 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) { ++reads; error = b->readstream(stream, b, oid); } } if (error == GIT_PASSTHROUGH) error = 0; if (error < 0 && !reads) error = git_odb__error_unsupported_in_backend("read object streamed"); return error; } int git_odb_write_pack(struct git_odb_writepack **out, git_odb *db, git_transfer_progress_callback progress_cb, void *progress_payload) { size_t i, writes = 0; int error = GIT_ERROR; assert(out && 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->writepack != NULL) { ++writes; error = b->writepack(out, b, progress_cb, progress_payload); } } if (error == GIT_PASSTHROUGH) error = 0; if (error < 0 && !writes) error = git_odb__error_unsupported_in_backend("write pack"); return error; } void *git_odb_backend_malloc(git_odb_backend *backend, size_t len) { GIT_UNUSED(backend); return git__malloc(len); } int git_odb_refresh(struct git_odb *db) { size_t i; assert(db); for (i = 0; i < db->backends.length; ++i) { backend_internal *internal = git_vector_get(&db->backends, i); git_odb_backend *b = internal->backend; if (b->refresh != NULL) { int error = b->refresh(b); if (error < 0) return error; } } return 0; } int git_odb__error_notfound(const char *message, const git_oid *oid) { if (oid != NULL) { char oid_str[GIT_OID_HEXSZ + 1]; git_oid_tostr(oid_str, sizeof(oid_str), oid); giterr_set(GITERR_ODB, "Object not found - %s (%s)", message, oid_str); } else giterr_set(GITERR_ODB, "Object not found - %s", message); return GIT_ENOTFOUND; } int git_odb__error_ambiguous(const char *message) { giterr_set(GITERR_ODB, "Ambiguous SHA1 prefix - %s", message); return GIT_EAMBIGUOUS; } libgit2-0.19.0/src/odb.h000066400000000000000000000053131216214232500146410ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #ifndef INCLUDE_odb_h__ #define INCLUDE_odb_h__ #include "git2/odb.h" #include "git2/oid.h" #include "git2/types.h" #include "vector.h" #include "cache.h" #include "posix.h" #define GIT_OBJECTS_DIR "objects/" #define GIT_OBJECT_DIR_MODE 0777 #define GIT_OBJECT_FILE_MODE 0444 /* DO NOT EXPORT */ typedef struct { void *data; /**< Raw, decompressed object data. */ size_t len; /**< Total number of bytes in data. */ git_otype type; /**< Type of this object. */ } git_rawobj; /* EXPORT */ struct git_odb_object { git_cached_obj cached; void *buffer; }; /* EXPORT */ struct git_odb { git_refcount rc; git_vector backends; git_cache own_cache; }; /* * Hash a git_rawobj internally. * The `git_rawobj` is supposed to be previously initialized */ int git_odb__hashobj(git_oid *id, git_rawobj *obj); /* * Format the object header such as it would appear in the on-disk object */ int git_odb__format_object_header(char *hdr, size_t n, size_t obj_len, git_otype obj_type); /* * Hash an open file descriptor. * This is a performance call when the contents of a fd need to be hashed, * but the fd is already open and we have the size of the contents. * * Saves us some `stat` calls. * * The fd is never closed, not even on error. It must be opened and closed * by the caller */ int git_odb__hashfd(git_oid *out, git_file fd, size_t size, git_otype type); /* * Hash an open file descriptor applying an array of filters * Acts just like git_odb__hashfd with the addition of filters... */ int git_odb__hashfd_filtered( git_oid *out, git_file fd, size_t len, git_otype type, git_vector *filters); /* * Hash a `path`, assuming it could be a POSIX symlink: if the path is a * symlink, then the raw contents of the symlink will be hashed. Otherwise, * this will fallback to `git_odb__hashfd`. * * The hash type for this call is always `GIT_OBJ_BLOB` because symlinks may * only point to blobs. */ int git_odb__hashlink(git_oid *out, const char *path); /* * Generate a GIT_ENOTFOUND error for the ODB. */ int git_odb__error_notfound(const char *message, const git_oid *oid); /* * Generate a GIT_EAMBIGUOUS error for the ODB. */ int git_odb__error_ambiguous(const char *message); /* * Attempt to read object header or just return whole object if it could * not be read. */ int git_odb__read_header_or_object( git_odb_object **out, size_t *len_p, git_otype *type_p, git_odb *db, const git_oid *id); /* fully free the object; internal method, DO NOT EXPORT */ void git_odb_object__free(void *object); #endif libgit2-0.19.0/src/odb_loose.c000066400000000000000000000540401216214232500160360ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #include "common.h" #include #include "git2/object.h" #include "git2/sys/odb_backend.h" #include "fileops.h" #include "hash.h" #include "odb.h" #include "delta-apply.h" #include "filebuf.h" #include "git2/odb_backend.h" #include "git2/types.h" typedef struct { /* object header data */ git_otype type; /* object type */ size_t size; /* object size */ } obj_hdr; typedef struct { git_odb_stream stream; git_filebuf fbuf; } loose_writestream; typedef struct loose_backend { git_odb_backend parent; int object_zlib_level; /** loose object zlib compression level. */ int fsync_object_files; /** loose object file fsync flag. */ size_t objects_dirlen; char objects_dir[GIT_FLEX_ARRAY]; } loose_backend; /* State structure for exploring directories, * in order to locate objects matching a short oid. */ typedef struct { size_t dir_len; unsigned char short_oid[GIT_OID_HEXSZ]; /* hex formatted oid to match */ size_t short_oid_len; int found; /* number of matching * objects already found */ unsigned char res_oid[GIT_OID_HEXSZ]; /* hex formatted oid of * the object found */ } loose_locate_object_state; /*********************************************************** * * MISCELANEOUS HELPER FUNCTIONS * ***********************************************************/ static int object_file_name( git_buf *name, const loose_backend *be, const git_oid *id) { /* expand length for object root + 40 hex sha1 chars + 2 * '/' + '\0' */ if (git_buf_grow(name, be->objects_dirlen + GIT_OID_HEXSZ + 3) < 0) return -1; git_buf_set(name, be->objects_dir, be->objects_dirlen); git_path_to_dir(name); /* loose object filename: aa/aaa... (41 bytes) */ git_oid_pathfmt(name->ptr + name->size, id); name->size += GIT_OID_HEXSZ + 1; name->ptr[name->size] = '\0'; return 0; } static int object_mkdir(const git_buf *name, const loose_backend *be) { return git_futils_mkdir( name->ptr + be->objects_dirlen, be->objects_dir, GIT_OBJECT_DIR_MODE, GIT_MKDIR_PATH | GIT_MKDIR_SKIP_LAST | GIT_MKDIR_VERIFY_DIR); } static size_t get_binary_object_header(obj_hdr *hdr, git_buf *obj) { unsigned char c; unsigned char *data = (unsigned char *)obj->ptr; size_t shift, size, used = 0; if (git_buf_len(obj) == 0) return 0; c = data[used++]; hdr->type = (c >> 4) & 7; size = c & 15; shift = 4; while (c & 0x80) { if (git_buf_len(obj) <= used) return 0; if (sizeof(size_t) * 8 <= shift) return 0; c = data[used++]; size += (c & 0x7f) << shift; shift += 7; } hdr->size = size; return used; } static size_t get_object_header(obj_hdr *hdr, unsigned char *data) { char c, typename[10]; size_t size, used = 0; /* * type name string followed by space. */ while ((c = data[used]) != ' ') { typename[used++] = c; if (used >= sizeof(typename)) return 0; } typename[used] = 0; if (used == 0) return 0; hdr->type = git_object_string2type(typename); used++; /* consume the space */ /* * length follows immediately in decimal (without * leading zeros). */ size = data[used++] - '0'; if (size > 9) return 0; if (size) { while ((c = data[used]) != '\0') { size_t d = c - '0'; if (d > 9) break; used++; size = size * 10 + d; } } hdr->size = size; /* * the length must be followed by a zero byte */ if (data[used++] != '\0') return 0; return used; } /*********************************************************** * * ZLIB RELATED FUNCTIONS * ***********************************************************/ static void init_stream(z_stream *s, void *out, size_t len) { memset(s, 0, sizeof(*s)); s->next_out = out; s->avail_out = (uInt)len; } static void set_stream_input(z_stream *s, void *in, size_t len) { s->next_in = in; s->avail_in = (uInt)len; } static void set_stream_output(z_stream *s, void *out, size_t len) { s->next_out = out; s->avail_out = (uInt)len; } static int start_inflate(z_stream *s, git_buf *obj, void *out, size_t len) { int status; init_stream(s, out, len); set_stream_input(s, obj->ptr, git_buf_len(obj)); if ((status = inflateInit(s)) < Z_OK) return status; return inflate(s, 0); } static int finish_inflate(z_stream *s) { int status = Z_OK; while (status == Z_OK) status = inflate(s, Z_FINISH); inflateEnd(s); if ((status != Z_STREAM_END) || (s->avail_in != 0)) { giterr_set(GITERR_ZLIB, "Failed to finish ZLib inflation. Stream aborted prematurely"); return -1; } return 0; } static int is_zlib_compressed_data(unsigned char *data) { unsigned int w; w = ((unsigned int)(data[0]) << 8) + data[1]; return (data[0] & 0x8F) == 0x08 && !(w % 31); } static int inflate_buffer(void *in, size_t inlen, void *out, size_t outlen) { z_stream zs; int status = Z_OK; memset(&zs, 0x0, sizeof(zs)); zs.next_out = out; zs.avail_out = (uInt)outlen; zs.next_in = in; zs.avail_in = (uInt)inlen; if (inflateInit(&zs) < Z_OK) { giterr_set(GITERR_ZLIB, "Failed to inflate buffer"); return -1; } while (status == Z_OK) status = inflate(&zs, Z_FINISH); inflateEnd(&zs); if (status != Z_STREAM_END /* || zs.avail_in != 0 */ || zs.total_out != outlen) { giterr_set(GITERR_ZLIB, "Failed to inflate buffer. Stream aborted prematurely"); return -1; } return 0; } static void *inflate_tail(z_stream *s, void *hb, size_t used, obj_hdr *hdr) { unsigned char *buf, *head = hb; size_t tail; /* * allocate a buffer to hold the inflated data and copy the * initial sequence of inflated data from the tail of the * head buffer, if any. */ if ((buf = git__malloc(hdr->size + 1)) == NULL) { inflateEnd(s); return NULL; } tail = s->total_out - used; if (used > 0 && tail > 0) { if (tail > hdr->size) tail = hdr->size; memcpy(buf, head + used, tail); } used = tail; /* * inflate the remainder of the object data, if any */ if (hdr->size < used) inflateEnd(s); else { set_stream_output(s, buf + used, hdr->size - used); if (finish_inflate(s)) { git__free(buf); return NULL; } } return buf; } /* * At one point, there was a loose object format that was intended to * mimic the format used in pack-files. This was to allow easy copying * of loose object data into packs. This format is no longer used, but * we must still read it. */ static int inflate_packlike_loose_disk_obj(git_rawobj *out, git_buf *obj) { unsigned char *in, *buf; obj_hdr hdr; size_t len, used; /* * read the object header, which is an (uncompressed) * binary encoding of the object type and size. */ if ((used = get_binary_object_header(&hdr, obj)) == 0 || !git_object_typeisloose(hdr.type)) { giterr_set(GITERR_ODB, "Failed to inflate loose object."); return -1; } /* * allocate a buffer and inflate the data into it */ buf = git__malloc(hdr.size + 1); GITERR_CHECK_ALLOC(buf); in = ((unsigned char *)obj->ptr) + used; len = obj->size - used; if (inflate_buffer(in, len, buf, hdr.size) < 0) { git__free(buf); return -1; } buf[hdr.size] = '\0'; out->data = buf; out->len = hdr.size; out->type = hdr.type; return 0; } static int inflate_disk_obj(git_rawobj *out, git_buf *obj) { unsigned char head[64], *buf; z_stream zs; obj_hdr hdr; size_t used; /* * check for a pack-like loose object */ if (!is_zlib_compressed_data((unsigned char *)obj->ptr)) return inflate_packlike_loose_disk_obj(out, obj); /* * inflate the initial part of the io buffer in order * to parse the object header (type and size). */ if (start_inflate(&zs, obj, head, sizeof(head)) < Z_OK || (used = get_object_header(&hdr, head)) == 0 || !git_object_typeisloose(hdr.type)) { giterr_set(GITERR_ODB, "Failed to inflate disk object."); return -1; } /* * allocate a buffer and inflate the object data into it * (including the initial sequence in the head buffer). */ if ((buf = inflate_tail(&zs, head, used, &hdr)) == NULL) return -1; buf[hdr.size] = '\0'; out->data = buf; out->len = hdr.size; out->type = hdr.type; return 0; } /*********************************************************** * * ODB OBJECT READING & WRITING * * Backend for the public API; read headers and full objects * from the ODB. Write raw data to the ODB. * ***********************************************************/ static int read_loose(git_rawobj *out, git_buf *loc) { int error; git_buf obj = GIT_BUF_INIT; assert(out && loc); if (git_buf_oom(loc)) return -1; out->data = NULL; out->len = 0; out->type = GIT_OBJ_BAD; if (!(error = git_futils_readbuffer(&obj, loc->ptr))) error = inflate_disk_obj(out, &obj); git_buf_free(&obj); return error; } static int read_header_loose(git_rawobj *out, git_buf *loc) { int error = 0, z_return = Z_ERRNO, read_bytes; git_file fd; z_stream zs; obj_hdr header_obj; unsigned char raw_buffer[16], inflated_buffer[64]; assert(out && loc); if (git_buf_oom(loc)) return -1; out->data = NULL; if ((fd = git_futils_open_ro(loc->ptr)) < 0) return fd; init_stream(&zs, inflated_buffer, sizeof(inflated_buffer)); z_return = inflateInit(&zs); while (z_return == Z_OK) { if ((read_bytes = p_read(fd, raw_buffer, sizeof(raw_buffer))) > 0) { set_stream_input(&zs, raw_buffer, read_bytes); z_return = inflate(&zs, 0); } else z_return = Z_STREAM_END; } if ((z_return != Z_STREAM_END && z_return != Z_BUF_ERROR) || get_object_header(&header_obj, inflated_buffer) == 0 || git_object_typeisloose(header_obj.type) == 0) { giterr_set(GITERR_ZLIB, "Failed to read loose object header"); error = -1; } else { out->len = header_obj.size; out->type = header_obj.type; } finish_inflate(&zs); p_close(fd); return error; } static int locate_object( git_buf *object_location, loose_backend *backend, const git_oid *oid) { int error = object_file_name(object_location, backend, oid); if (!error && !git_path_exists(object_location->ptr)) return GIT_ENOTFOUND; return error; } /* Explore an entry of a directory and see if it matches a short oid */ static int fn_locate_object_short_oid(void *state, git_buf *pathbuf) { loose_locate_object_state *sstate = (loose_locate_object_state *)state; if (git_buf_len(pathbuf) - sstate->dir_len != GIT_OID_HEXSZ - 2) { /* Entry cannot be an object. Continue to next entry */ return 0; } if (git_path_isdir(pathbuf->ptr) == false) { /* We are already in the directory matching the 2 first hex characters, * compare the first ncmp characters of the oids */ if (!memcmp(sstate->short_oid + 2, (unsigned char *)pathbuf->ptr + sstate->dir_len, sstate->short_oid_len - 2)) { if (!sstate->found) { sstate->res_oid[0] = sstate->short_oid[0]; sstate->res_oid[1] = sstate->short_oid[1]; memcpy(sstate->res_oid+2, pathbuf->ptr+sstate->dir_len, GIT_OID_HEXSZ-2); } sstate->found++; } } if (sstate->found > 1) return git_odb__error_ambiguous("multiple matches in loose objects"); return 0; } /* Locate an object matching a given short oid */ static int locate_object_short_oid( git_buf *object_location, git_oid *res_oid, loose_backend *backend, const git_oid *short_oid, size_t len) { char *objects_dir = backend->objects_dir; size_t dir_len = strlen(objects_dir); loose_locate_object_state state; int error; /* prealloc memory for OBJ_DIR/xx/ */ if (git_buf_grow(object_location, dir_len + 5) < 0) return -1; git_buf_sets(object_location, objects_dir); git_path_to_dir(object_location); /* save adjusted position at end of dir so it can be restored later */ dir_len = git_buf_len(object_location); /* Convert raw oid to hex formatted oid */ git_oid_fmt((char *)state.short_oid, short_oid); /* Explore OBJ_DIR/xx/ where xx is the beginning of hex formatted short oid */ if (git_buf_printf(object_location, "%.2s/", state.short_oid) < 0) return -1; /* Check that directory exists */ if (git_path_isdir(object_location->ptr) == false) return git_odb__error_notfound("no matching loose object for prefix", short_oid); state.dir_len = git_buf_len(object_location); state.short_oid_len = len; state.found = 0; /* Explore directory to find a unique object matching short_oid */ error = git_path_direach( object_location, fn_locate_object_short_oid, &state); if (error) return error; if (!state.found) return git_odb__error_notfound("no matching loose object for prefix", short_oid); /* Convert obtained hex formatted oid to raw */ error = git_oid_fromstr(res_oid, (char *)state.res_oid); if (error) return error; /* Update the location according to the oid obtained */ git_buf_truncate(object_location, dir_len); if (git_buf_grow(object_location, dir_len + GIT_OID_HEXSZ + 2) < 0) return -1; git_oid_pathfmt(object_location->ptr + dir_len, res_oid); object_location->size += GIT_OID_HEXSZ + 1; object_location->ptr[object_location->size] = '\0'; return 0; } /*********************************************************** * * LOOSE BACKEND PUBLIC API * * Implement the git_odb_backend API calls * ***********************************************************/ static int loose_backend__read_header(size_t *len_p, git_otype *type_p, git_odb_backend *backend, const git_oid *oid) { git_buf object_path = GIT_BUF_INIT; git_rawobj raw; int error; assert(backend && oid); raw.len = 0; raw.type = GIT_OBJ_BAD; if (locate_object(&object_path, (loose_backend *)backend, oid) < 0) error = git_odb__error_notfound("no matching loose object", oid); else if ((error = read_header_loose(&raw, &object_path)) == 0) { *len_p = raw.len; *type_p = raw.type; } git_buf_free(&object_path); return error; } static int loose_backend__read(void **buffer_p, size_t *len_p, git_otype *type_p, git_odb_backend *backend, const git_oid *oid) { git_buf object_path = GIT_BUF_INIT; git_rawobj raw; int error = 0; assert(backend && oid); if (locate_object(&object_path, (loose_backend *)backend, oid) < 0) error = git_odb__error_notfound("no matching loose object", oid); else if ((error = read_loose(&raw, &object_path)) == 0) { *buffer_p = raw.data; *len_p = raw.len; *type_p = raw.type; } git_buf_free(&object_path); return error; } static int loose_backend__read_prefix( git_oid *out_oid, void **buffer_p, size_t *len_p, git_otype *type_p, git_odb_backend *backend, const git_oid *short_oid, size_t len) { int error = 0; if (len < GIT_OID_MINPREFIXLEN) error = git_odb__error_ambiguous("prefix length too short"); else if (len >= GIT_OID_HEXSZ) { /* We can fall back to regular read method */ error = loose_backend__read(buffer_p, len_p, type_p, backend, short_oid); if (!error) git_oid_cpy(out_oid, short_oid); } else { git_buf object_path = GIT_BUF_INIT; git_rawobj raw; assert(backend && short_oid); if ((error = locate_object_short_oid(&object_path, out_oid, (loose_backend *)backend, short_oid, len)) == 0 && (error = read_loose(&raw, &object_path)) == 0) { *buffer_p = raw.data; *len_p = raw.len; *type_p = raw.type; } git_buf_free(&object_path); } return error; } static int loose_backend__exists(git_odb_backend *backend, const git_oid *oid) { git_buf object_path = GIT_BUF_INIT; int error; assert(backend && oid); error = locate_object(&object_path, (loose_backend *)backend, oid); git_buf_free(&object_path); return !error; } struct foreach_state { size_t dir_len; git_odb_foreach_cb cb; void *data; int cb_error; }; GIT_INLINE(int) filename_to_oid(git_oid *oid, const char *ptr) { int v, i = 0; if (strlen(ptr) != 41) return -1; if (ptr[2] != '/') { return -1; } v = (git__fromhex(ptr[i]) << 4) | git__fromhex(ptr[i+1]); if (v < 0) return -1; oid->id[0] = (unsigned char) v; ptr += 3; for (i = 0; i < 38; i += 2) { v = (git__fromhex(ptr[i]) << 4) | git__fromhex(ptr[i + 1]); if (v < 0) return -1; oid->id[1 + i/2] = (unsigned char) v; } return 0; } static int foreach_object_dir_cb(void *_state, git_buf *path) { git_oid oid; struct foreach_state *state = (struct foreach_state *) _state; if (filename_to_oid(&oid, path->ptr + state->dir_len) < 0) return 0; if (state->cb(&oid, state->data)) { state->cb_error = GIT_EUSER; return -1; } return 0; } static int foreach_cb(void *_state, git_buf *path) { struct foreach_state *state = (struct foreach_state *) _state; return git_path_direach(path, foreach_object_dir_cb, state); } static int loose_backend__foreach(git_odb_backend *_backend, git_odb_foreach_cb cb, void *data) { char *objects_dir; int error; git_buf buf = GIT_BUF_INIT; struct foreach_state state; loose_backend *backend = (loose_backend *) _backend; assert(backend && cb); objects_dir = backend->objects_dir; git_buf_sets(&buf, objects_dir); git_path_to_dir(&buf); memset(&state, 0, sizeof(state)); state.cb = cb; state.data = data; state.dir_len = git_buf_len(&buf); error = git_path_direach(&buf, foreach_cb, &state); git_buf_free(&buf); return state.cb_error ? state.cb_error : error; } static int loose_backend__stream_fwrite(git_oid *oid, git_odb_stream *_stream) { loose_writestream *stream = (loose_writestream *)_stream; loose_backend *backend = (loose_backend *)_stream->backend; git_buf final_path = GIT_BUF_INIT; int error = 0; if (git_filebuf_hash(oid, &stream->fbuf) < 0 || object_file_name(&final_path, backend, oid) < 0 || object_mkdir(&final_path, backend) < 0) error = -1; /* * Don't try to add an existing object to the repository. This * is what git does and allows us to sidestep the fact that * we're not allowed to overwrite a read-only file on Windows. */ else if (git_path_exists(final_path.ptr) == true) git_filebuf_cleanup(&stream->fbuf); else error = git_filebuf_commit_at( &stream->fbuf, final_path.ptr, GIT_OBJECT_FILE_MODE); git_buf_free(&final_path); return error; } static int loose_backend__stream_write(git_odb_stream *_stream, const char *data, size_t len) { loose_writestream *stream = (loose_writestream *)_stream; return git_filebuf_write(&stream->fbuf, data, len); } static void loose_backend__stream_free(git_odb_stream *_stream) { loose_writestream *stream = (loose_writestream *)_stream; git_filebuf_cleanup(&stream->fbuf); git__free(stream); } static int format_object_header(char *hdr, size_t n, size_t obj_len, git_otype obj_type) { const char *type_str = git_object_type2string(obj_type); int len = snprintf(hdr, n, "%s %"PRIuZ, type_str, obj_len); assert(len > 0); /* otherwise snprintf() is broken */ assert(((size_t)len) < n); /* otherwise the caller is broken! */ return len+1; } static int loose_backend__stream(git_odb_stream **stream_out, git_odb_backend *_backend, size_t length, git_otype type) { loose_backend *backend; loose_writestream *stream = NULL; char hdr[64]; git_buf tmp_path = GIT_BUF_INIT; int hdrlen; assert(_backend); backend = (loose_backend *)_backend; *stream_out = NULL; hdrlen = format_object_header(hdr, sizeof(hdr), length, type); stream = git__calloc(1, sizeof(loose_writestream)); GITERR_CHECK_ALLOC(stream); stream->stream.backend = _backend; stream->stream.read = NULL; /* read only */ stream->stream.write = &loose_backend__stream_write; stream->stream.finalize_write = &loose_backend__stream_fwrite; stream->stream.free = &loose_backend__stream_free; stream->stream.mode = GIT_STREAM_WRONLY; if (git_buf_joinpath(&tmp_path, backend->objects_dir, "tmp_object") < 0 || git_filebuf_open(&stream->fbuf, tmp_path.ptr, GIT_FILEBUF_HASH_CONTENTS | GIT_FILEBUF_TEMPORARY | (backend->object_zlib_level << GIT_FILEBUF_DEFLATE_SHIFT)) < 0 || stream->stream.write((git_odb_stream *)stream, hdr, hdrlen) < 0) { git_filebuf_cleanup(&stream->fbuf); git__free(stream); stream = NULL; } git_buf_free(&tmp_path); *stream_out = (git_odb_stream *)stream; return !stream ? -1 : 0; } static int loose_backend__write(git_oid *oid, git_odb_backend *_backend, const void *data, size_t len, git_otype type) { int error = 0, header_len; git_buf final_path = GIT_BUF_INIT; char header[64]; git_filebuf fbuf = GIT_FILEBUF_INIT; loose_backend *backend; backend = (loose_backend *)_backend; /* prepare the header for the file */ header_len = format_object_header(header, sizeof(header), len, type); if (git_buf_joinpath(&final_path, backend->objects_dir, "tmp_object") < 0 || git_filebuf_open(&fbuf, final_path.ptr, GIT_FILEBUF_TEMPORARY | (backend->object_zlib_level << GIT_FILEBUF_DEFLATE_SHIFT)) < 0) { error = -1; goto cleanup; } git_filebuf_write(&fbuf, header, header_len); git_filebuf_write(&fbuf, data, len); if (object_file_name(&final_path, backend, oid) < 0 || object_mkdir(&final_path, backend) < 0 || git_filebuf_commit_at(&fbuf, final_path.ptr, GIT_OBJECT_FILE_MODE) < 0) error = -1; cleanup: if (error < 0) git_filebuf_cleanup(&fbuf); git_buf_free(&final_path); return error; } static void loose_backend__free(git_odb_backend *_backend) { loose_backend *backend; assert(_backend); backend = (loose_backend *)_backend; git__free(backend); } int git_odb_backend_loose( git_odb_backend **backend_out, const char *objects_dir, int compression_level, int do_fsync) { loose_backend *backend; size_t objects_dirlen; assert(backend_out && objects_dir); objects_dirlen = strlen(objects_dir); backend = git__calloc(1, sizeof(loose_backend) + objects_dirlen + 2); GITERR_CHECK_ALLOC(backend); backend->parent.version = GIT_ODB_BACKEND_VERSION; backend->objects_dirlen = objects_dirlen; memcpy(backend->objects_dir, objects_dir, objects_dirlen); if (backend->objects_dir[backend->objects_dirlen - 1] != '/') backend->objects_dir[backend->objects_dirlen++] = '/'; if (compression_level < 0) compression_level = Z_BEST_SPEED; backend->object_zlib_level = compression_level; backend->fsync_object_files = do_fsync; backend->parent.read = &loose_backend__read; backend->parent.write = &loose_backend__write; backend->parent.read_prefix = &loose_backend__read_prefix; backend->parent.read_header = &loose_backend__read_header; backend->parent.writestream = &loose_backend__stream; backend->parent.exists = &loose_backend__exists; backend->parent.foreach = &loose_backend__foreach; backend->parent.free = &loose_backend__free; *backend_out = (git_odb_backend *)backend; return 0; } libgit2-0.19.0/src/odb_pack.c000066400000000000000000000371201216214232500156330ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #include "common.h" #include #include "git2/repository.h" #include "git2/indexer.h" #include "git2/sys/odb_backend.h" #include "fileops.h" #include "hash.h" #include "odb.h" #include "delta-apply.h" #include "sha1_lookup.h" #include "mwindow.h" #include "pack.h" #include "git2/odb_backend.h" struct pack_backend { git_odb_backend parent; git_vector packs; struct git_pack_file *last_found; char *pack_folder; }; struct pack_writepack { struct git_odb_writepack parent; git_indexer_stream *indexer_stream; }; /** * The wonderful tale of a Packed Object lookup query * =================================================== * A riveting and epic story of epicness and ASCII * art, presented by yours truly, * Sir Vicent of Marti * * * Chapter 1: Once upon a time... * Initialization of the Pack Backend * -------------------------------------------------- * * # git_odb_backend_pack * | Creates the pack backend structure, initializes the * | callback pointers to our default read() and exist() methods, * | and tries to preload all the known packfiles in the ODB. * | * |-# packfile_load_all * | Tries to find the `pack` folder, if it exists. ODBs without * | a pack folder are ignored altogether. If there's a `pack` folder * | we run a `dirent` callback through every file in the pack folder * | to find our packfiles. The packfiles are then sorted according * | to a sorting callback. * | * |-# packfile_load__cb * | | This callback is called from `dirent` with every single file * | | inside the pack folder. We find the packs by actually locating * | | their index (ends in ".idx"). From that index, we verify that * | | the corresponding packfile exists and is valid, and if so, we * | | add it to the pack list. * | | * | |-# packfile_check * | Make sure that there's a packfile to back this index, and store * | some very basic information regarding the packfile itself, * | such as the full path, the size, and the modification time. * | We don't actually open the packfile to check for internal consistency. * | * |-# packfile_sort__cb * Sort all the preloaded packs according to some specific criteria: * we prioritize the "newer" packs because it's more likely they * contain the objects we are looking for, and we prioritize local * packs over remote ones. * * * * Chapter 2: To be, or not to be... * A standard packed `exist` query for an OID * -------------------------------------------------- * * # pack_backend__exists * | Check if the given SHA1 oid exists in any of the packs * | that have been loaded for our ODB. * | * |-# pack_entry_find * | Iterate through all the packs that have been preloaded * | (starting by the pack where the latest object was found) * | to try to find the OID in one of them. * | * |-# pack_entry_find1 * | Check the index of an individual pack to see if the SHA1 * | OID can be found. If we can find the offset to that SHA1 * | inside of the index, that means the object is contained * | inside of the packfile and we can stop searching. * | Before returning, we verify that the packfile behing the * | index we are searching still exists on disk. * | * |-# pack_entry_find_offset * | | Mmap the actual index file to disk if it hasn't been opened * | | yet, and run a binary search through it to find the OID. * | | See for specifics * | | on the Packfile Index format and how do we find entries in it. * | | * | |-# pack_index_open * | | Guess the name of the index based on the full path to the * | | packfile, open it and verify its contents. Only if the index * | | has not been opened already. * | | * | |-# pack_index_check * | Mmap the index file and do a quick run through the header * | to guess the index version (right now we support v1 and v2), * | and to verify that the size of the index makes sense. * | * |-# packfile_open * See `packfile_open` in Chapter 3 * * * * Chapter 3: The neverending story... * A standard packed `lookup` query for an OID * -------------------------------------------------- * TODO * */ /*********************************************************** * * FORWARD DECLARATIONS * ***********************************************************/ static int packfile_sort__cb(const void *a_, const void *b_); static int packfile_load__cb(void *_data, git_buf *path); static int pack_entry_find(struct git_pack_entry *e, struct pack_backend *backend, const git_oid *oid); /* Can find the offset of an object given * a prefix of an identifier. * Sets GIT_EAMBIGUOUS if short oid is ambiguous. * This method assumes that len is between * GIT_OID_MINPREFIXLEN and GIT_OID_HEXSZ. */ static int pack_entry_find_prefix( struct git_pack_entry *e, struct pack_backend *backend, const git_oid *short_oid, size_t len); /*********************************************************** * * PACK WINDOW MANAGEMENT * ***********************************************************/ static int packfile_sort__cb(const void *a_, const void *b_) { const struct git_pack_file *a = a_; const struct git_pack_file *b = b_; int st; /* * Local packs tend to contain objects specific to our * variant of the project than remote ones. In addition, * remote ones could be on a network mounted filesystem. * Favor local ones for these reasons. */ st = a->pack_local - b->pack_local; if (st) return -st; /* * Younger packs tend to contain more recent objects, * and more recent objects tend to get accessed more * often. */ if (a->mtime < b->mtime) return 1; else if (a->mtime == b->mtime) return 0; return -1; } static int packfile_load__cb(void *_data, git_buf *path) { struct pack_backend *backend = (struct pack_backend *)_data; struct git_pack_file *pack; int error; size_t i; if (git__suffixcmp(path->ptr, ".idx") != 0) return 0; /* not an index */ for (i = 0; i < backend->packs.length; ++i) { struct git_pack_file *p = git_vector_get(&backend->packs, i); if (memcmp(p->pack_name, git_buf_cstr(path), git_buf_len(path) - strlen(".idx")) == 0) return 0; } error = git_packfile_alloc(&pack, path->ptr); if (error == GIT_ENOTFOUND) /* ignore missing .pack file as git does */ return 0; else if (error < 0) return error; return git_vector_insert(&backend->packs, pack); } static int pack_entry_find_inner( struct git_pack_entry *e, struct pack_backend *backend, const git_oid *oid, struct git_pack_file *last_found) { size_t i; if (last_found && git_pack_entry_find(e, last_found, oid, GIT_OID_HEXSZ) == 0) return 0; for (i = 0; i < backend->packs.length; ++i) { struct git_pack_file *p; p = git_vector_get(&backend->packs, i); if (p == last_found) continue; if (git_pack_entry_find(e, p, oid, GIT_OID_HEXSZ) == 0) { backend->last_found = p; return 0; } } return -1; } static int pack_entry_find(struct git_pack_entry *e, struct pack_backend *backend, const git_oid *oid) { struct git_pack_file *last_found = backend->last_found; if (backend->last_found && git_pack_entry_find(e, backend->last_found, oid, GIT_OID_HEXSZ) == 0) return 0; if (!pack_entry_find_inner(e, backend, oid, last_found)) return 0; return git_odb__error_notfound("failed to find pack entry", oid); } static unsigned pack_entry_find_prefix_inner( struct git_pack_entry *e, struct pack_backend *backend, const git_oid *short_oid, size_t len, struct git_pack_file *last_found) { int error; size_t i; unsigned found = 0; if (last_found) { error = git_pack_entry_find(e, last_found, short_oid, len); if (error == GIT_EAMBIGUOUS) return error; if (!error) found = 1; } for (i = 0; i < backend->packs.length; ++i) { struct git_pack_file *p; p = git_vector_get(&backend->packs, i); if (p == last_found) continue; error = git_pack_entry_find(e, p, short_oid, len); if (error == GIT_EAMBIGUOUS) return error; if (!error) { if (++found > 1) break; backend->last_found = p; } } return found; } static int pack_entry_find_prefix( struct git_pack_entry *e, struct pack_backend *backend, const git_oid *short_oid, size_t len) { struct git_pack_file *last_found = backend->last_found; unsigned int found = pack_entry_find_prefix_inner(e, backend, short_oid, len, last_found); if (!found) return git_odb__error_notfound("no matching pack entry for prefix", short_oid); else if (found > 1) return git_odb__error_ambiguous("found multiple pack entries"); else return 0; } /*********************************************************** * * PACKED BACKEND PUBLIC API * * Implement the git_odb_backend API calls * ***********************************************************/ static int pack_backend__refresh(git_odb_backend *_backend) { struct pack_backend *backend = (struct pack_backend *)_backend; int error; struct stat st; git_buf path = GIT_BUF_INIT; if (backend->pack_folder == NULL) return 0; if (p_stat(backend->pack_folder, &st) < 0 || !S_ISDIR(st.st_mode)) return git_odb__error_notfound("failed to refresh packfiles", NULL); git_buf_sets(&path, backend->pack_folder); /* reload all packs */ error = git_path_direach(&path, packfile_load__cb, (void *)backend); git_buf_free(&path); if (error < 0) return error; git_vector_sort(&backend->packs); return 0; } static int pack_backend__read_header(size_t *len_p, git_otype *type_p, struct git_odb_backend *backend, const git_oid *oid) { struct git_pack_entry e; int error; assert(len_p && type_p && backend && oid); if ((error = pack_entry_find(&e, (struct pack_backend *)backend, oid)) < 0) return error; return git_packfile_resolve_header(len_p, type_p, e.p, e.offset); } static int pack_backend__read(void **buffer_p, size_t *len_p, git_otype *type_p, git_odb_backend *backend, const git_oid *oid) { struct git_pack_entry e; git_rawobj raw; int error; if ((error = pack_entry_find(&e, (struct pack_backend *)backend, oid)) < 0 || (error = git_packfile_unpack(&raw, e.p, &e.offset)) < 0) return error; *buffer_p = raw.data; *len_p = raw.len; *type_p = raw.type; return 0; } static int pack_backend__read_prefix( git_oid *out_oid, void **buffer_p, size_t *len_p, git_otype *type_p, git_odb_backend *backend, const git_oid *short_oid, size_t len) { int error = 0; if (len < GIT_OID_MINPREFIXLEN) error = git_odb__error_ambiguous("prefix length too short"); else if (len >= GIT_OID_HEXSZ) { /* We can fall back to regular read method */ error = pack_backend__read(buffer_p, len_p, type_p, backend, short_oid); if (!error) git_oid_cpy(out_oid, short_oid); } else { struct git_pack_entry e; git_rawobj raw; if ((error = pack_entry_find_prefix( &e, (struct pack_backend *)backend, short_oid, len)) == 0 && (error = git_packfile_unpack(&raw, e.p, &e.offset)) == 0) { *buffer_p = raw.data; *len_p = raw.len; *type_p = raw.type; git_oid_cpy(out_oid, &e.sha1); } } return error; } static int pack_backend__exists(git_odb_backend *backend, const git_oid *oid) { struct git_pack_entry e; return pack_entry_find(&e, (struct pack_backend *)backend, oid) == 0; } static int pack_backend__foreach(git_odb_backend *_backend, git_odb_foreach_cb cb, void *data) { int error; struct git_pack_file *p; struct pack_backend *backend; unsigned int i; assert(_backend && cb); backend = (struct pack_backend *)_backend; /* Make sure we know about the packfiles */ if ((error = pack_backend__refresh(_backend)) < 0) return error; git_vector_foreach(&backend->packs, i, p) { if ((error = git_pack_foreach_entry(p, cb, data)) < 0) return error; } return 0; } static int pack_backend__writepack_add(struct git_odb_writepack *_writepack, const void *data, size_t size, git_transfer_progress *stats) { struct pack_writepack *writepack = (struct pack_writepack *)_writepack; assert(writepack); return git_indexer_stream_add(writepack->indexer_stream, data, size, stats); } static int pack_backend__writepack_commit(struct git_odb_writepack *_writepack, git_transfer_progress *stats) { struct pack_writepack *writepack = (struct pack_writepack *)_writepack; assert(writepack); return git_indexer_stream_finalize(writepack->indexer_stream, stats); } static void pack_backend__writepack_free(struct git_odb_writepack *_writepack) { struct pack_writepack *writepack = (struct pack_writepack *)_writepack; assert(writepack); git_indexer_stream_free(writepack->indexer_stream); git__free(writepack); } static int pack_backend__writepack(struct git_odb_writepack **out, git_odb_backend *_backend, git_transfer_progress_callback progress_cb, void *progress_payload) { struct pack_backend *backend; struct pack_writepack *writepack; assert(out && _backend); *out = NULL; backend = (struct pack_backend *)_backend; writepack = git__calloc(1, sizeof(struct pack_writepack)); GITERR_CHECK_ALLOC(writepack); if (git_indexer_stream_new(&writepack->indexer_stream, backend->pack_folder, progress_cb, progress_payload) < 0) { git__free(writepack); return -1; } writepack->parent.backend = _backend; writepack->parent.add = pack_backend__writepack_add; writepack->parent.commit = pack_backend__writepack_commit; writepack->parent.free = pack_backend__writepack_free; *out = (git_odb_writepack *)writepack; return 0; } static void pack_backend__free(git_odb_backend *_backend) { struct pack_backend *backend; size_t i; assert(_backend); backend = (struct pack_backend *)_backend; for (i = 0; i < backend->packs.length; ++i) { struct git_pack_file *p = git_vector_get(&backend->packs, i); git_packfile_free(p); } git_vector_free(&backend->packs); git__free(backend->pack_folder); git__free(backend); } static int pack_backend__alloc(struct pack_backend **out, size_t initial_size) { struct pack_backend *backend = git__calloc(1, sizeof(struct pack_backend)); GITERR_CHECK_ALLOC(backend); if (git_vector_init(&backend->packs, initial_size, packfile_sort__cb) < 0) { git__free(backend); return -1; } backend->parent.version = GIT_ODB_BACKEND_VERSION; backend->parent.read = &pack_backend__read; backend->parent.read_prefix = &pack_backend__read_prefix; backend->parent.read_header = &pack_backend__read_header; backend->parent.exists = &pack_backend__exists; backend->parent.refresh = &pack_backend__refresh; backend->parent.foreach = &pack_backend__foreach; backend->parent.writepack = &pack_backend__writepack; backend->parent.free = &pack_backend__free; *out = backend; return 0; } int git_odb_backend_one_pack(git_odb_backend **backend_out, const char *idx) { struct pack_backend *backend = NULL; struct git_pack_file *packfile = NULL; if (pack_backend__alloc(&backend, 1) < 0) return -1; if (git_packfile_alloc(&packfile, idx) < 0 || git_vector_insert(&backend->packs, packfile) < 0) { pack_backend__free((git_odb_backend *)backend); return -1; } *backend_out = (git_odb_backend *)backend; return 0; } int git_odb_backend_pack(git_odb_backend **backend_out, const char *objects_dir) { int error = 0; struct pack_backend *backend = NULL; git_buf path = GIT_BUF_INIT; if (pack_backend__alloc(&backend, 8) < 0) return -1; if (!(error = git_buf_joinpath(&path, objects_dir, "pack")) && git_path_isdir(git_buf_cstr(&path))) { backend->pack_folder = git_buf_detach(&path); error = pack_backend__refresh((git_odb_backend *)backend); } if (error < 0) { pack_backend__free((git_odb_backend *)backend); backend = NULL; } *backend_out = (git_odb_backend *)backend; git_buf_free(&path); return error; } libgit2-0.19.0/src/offmap.h000066400000000000000000000036351216214232500153520ustar00rootroot00000000000000/* * Copyright (C) 2012 the libgit2 contributors * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #ifndef INCLUDE_offmap_h__ #define INCLUDE_offmap_h__ #include "common.h" #include "git2/types.h" #define kmalloc git__malloc #define kcalloc git__calloc #define krealloc git__realloc #define kfree git__free #include "khash.h" __KHASH_TYPE(off, git_off_t, void *); typedef khash_t(off) git_offmap; #define GIT__USE_OFFMAP \ __KHASH_IMPL(off, static kh_inline, git_off_t, void *, 1, kh_int64_hash_func, kh_int64_hash_equal); #define git_offmap_alloc() kh_init(off) #define git_offmap_free(h) kh_destroy(off, h), h = NULL #define git_offmap_clear(h) kh_clear(off, h) #define git_offmap_num_entries(h) kh_size(h) #define git_offmap_lookup_index(h, k) kh_get(off, h, k) #define git_offmap_valid_index(h, idx) (idx != kh_end(h)) #define git_offmap_exists(h, k) (kh_get(off, h, k) != kh_end(h)) #define git_offmap_value_at(h, idx) kh_val(h, idx) #define git_offmap_set_value_at(h, idx, v) kh_val(h, idx) = v #define git_offmap_delete_at(h, idx) kh_del(off, h, idx) #define git_offmap_insert(h, key, val, rval) do { \ khiter_t __pos = kh_put(off, h, key, &rval); \ if (rval >= 0) { \ if (rval == 0) kh_key(h, __pos) = key; \ kh_val(h, __pos) = val; \ } } while (0) #define git_offmap_insert2(h, key, val, oldv, rval) do { \ khiter_t __pos = kh_put(off, h, key, &rval); \ if (rval >= 0) { \ if (rval == 0) { \ oldv = kh_val(h, __pos); \ kh_key(h, __pos) = key; \ } else { oldv = NULL; } \ kh_val(h, __pos) = val; \ } } while (0) #define git_offmap_delete(h, key) do { \ khiter_t __pos = git_offmap_lookup_index(h, key); \ if (git_offmap_valid_index(h, __pos)) \ git_offmap_delete_at(h, __pos); } while (0) #define git_offmap_foreach kh_foreach #define git_offmap_foreach_value kh_foreach_value #endif libgit2-0.19.0/src/oid.c000066400000000000000000000215501216214232500146440ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #include "common.h" #include "git2/oid.h" #include "repository.h" #include #include static char to_hex[] = "0123456789abcdef"; static int oid_error_invalid(const char *msg) { giterr_set(GITERR_INVALID, "Unable to parse OID - %s", msg); return -1; } int git_oid_fromstrn(git_oid *out, const char *str, size_t length) { size_t p; int v; if (length > GIT_OID_HEXSZ) return oid_error_invalid("too long"); for (p = 0; p < length - 1; p += 2) { v = (git__fromhex(str[p + 0]) << 4) | git__fromhex(str[p + 1]); if (v < 0) return oid_error_invalid("contains invalid characters"); out->id[p / 2] = (unsigned char)v; } if (length % 2) { v = (git__fromhex(str[p + 0]) << 4); if (v < 0) return oid_error_invalid("contains invalid characters"); out->id[p / 2] = (unsigned char)v; p += 2; } memset(out->id + p / 2, 0, (GIT_OID_HEXSZ - p) / 2); return 0; } int git_oid_fromstrp(git_oid *out, const char *str) { return git_oid_fromstrn(out, str, strlen(str)); } int git_oid_fromstr(git_oid *out, const char *str) { return git_oid_fromstrn(out, str, GIT_OID_HEXSZ); } GIT_INLINE(char) *fmt_one(char *str, unsigned int val) { *str++ = to_hex[val >> 4]; *str++ = to_hex[val & 0xf]; return str; } void git_oid_nfmt(char *str, size_t n, const git_oid *oid) { size_t i, max_i; if (!oid) { memset(str, 0, n); return; } if (n > GIT_OID_HEXSZ) { memset(&str[GIT_OID_HEXSZ], 0, n - GIT_OID_HEXSZ); n = GIT_OID_HEXSZ; } max_i = n / 2; for (i = 0; i < max_i; i++) str = fmt_one(str, oid->id[i]); if (n & 1) *str++ = to_hex[oid->id[i] >> 4]; } void git_oid_fmt(char *str, const git_oid *oid) { git_oid_nfmt(str, GIT_OID_HEXSZ, oid); } void git_oid_pathfmt(char *str, const git_oid *oid) { size_t i; str = fmt_one(str, oid->id[0]); *str++ = '/'; for (i = 1; i < sizeof(oid->id); i++) str = fmt_one(str, oid->id[i]); } char *git_oid_allocfmt(const git_oid *oid) { char *str = git__malloc(GIT_OID_HEXSZ + 1); if (!str) return NULL; git_oid_nfmt(str, GIT_OID_HEXSZ + 1, oid); return str; } char *git_oid_tostr(char *out, size_t n, const git_oid *oid) { if (!out || n == 0) return ""; if (n > GIT_OID_HEXSZ + 1) n = GIT_OID_HEXSZ + 1; git_oid_nfmt(out, n - 1, oid); /* allow room for terminating NUL */ out[n - 1] = '\0'; return out; } int git_oid__parse( git_oid *oid, const char **buffer_out, const char *buffer_end, const char *header) { const size_t sha_len = GIT_OID_HEXSZ; const size_t header_len = strlen(header); const char *buffer = *buffer_out; if (buffer + (header_len + sha_len + 1) > buffer_end) return -1; if (memcmp(buffer, header, header_len) != 0) return -1; if (buffer[header_len + sha_len] != '\n') return -1; if (git_oid_fromstr(oid, buffer + header_len) < 0) return -1; *buffer_out = buffer + (header_len + sha_len + 1); return 0; } void git_oid__writebuf(git_buf *buf, const char *header, const git_oid *oid) { char hex_oid[GIT_OID_HEXSZ]; git_oid_fmt(hex_oid, oid); git_buf_puts(buf, header); git_buf_put(buf, hex_oid, GIT_OID_HEXSZ); git_buf_putc(buf, '\n'); } void git_oid_fromraw(git_oid *out, const unsigned char *raw) { memcpy(out->id, raw, sizeof(out->id)); } void git_oid_cpy(git_oid *out, const git_oid *src) { memcpy(out->id, src->id, sizeof(out->id)); } int git_oid_cmp(const git_oid *a, const git_oid *b) { return git_oid__cmp(a, b); } int git_oid_ncmp(const git_oid *oid_a, const git_oid *oid_b, size_t len) { const unsigned char *a = oid_a->id; const unsigned char *b = oid_b->id; if (len > GIT_OID_HEXSZ) len = GIT_OID_HEXSZ; while (len > 1) { if (*a != *b) return 1; a++; b++; len -= 2; }; if (len) if ((*a ^ *b) & 0xf0) return 1; return 0; } int git_oid_strcmp(const git_oid *oid_a, const char *str) { const unsigned char *a = oid_a->id; unsigned char strval; int hexval; for (a = oid_a->id; *str && (a - oid_a->id) < GIT_OID_RAWSZ; ++a) { if ((hexval = git__fromhex(*str++)) < 0) return -1; strval = hexval << 4; if (*str) { if ((hexval = git__fromhex(*str++)) < 0) return -1; strval |= hexval; } if (*a != strval) return (*a - strval); } return 0; } int git_oid_streq(const git_oid *oid_a, const char *str) { return git_oid_strcmp(oid_a, str) == 0 ? 0 : -1; } int git_oid_iszero(const git_oid *oid_a) { const unsigned char *a = oid_a->id; unsigned int i; for (i = 0; i < GIT_OID_RAWSZ; ++i, ++a) if (*a != 0) return 0; return 1; } typedef short node_index; typedef union { const char *tail; node_index children[16]; } trie_node; struct git_oid_shorten { trie_node *nodes; size_t node_count, size; int min_length, full; }; static int resize_trie(git_oid_shorten *self, size_t new_size) { self->nodes = git__realloc(self->nodes, new_size * sizeof(trie_node)); GITERR_CHECK_ALLOC(self->nodes); if (new_size > self->size) { memset(&self->nodes[self->size], 0x0, (new_size - self->size) * sizeof(trie_node)); } self->size = new_size; return 0; } static trie_node *push_leaf(git_oid_shorten *os, node_index idx, int push_at, const char *oid) { trie_node *node, *leaf; node_index idx_leaf; if (os->node_count >= os->size) { if (resize_trie(os, os->size * 2) < 0) return NULL; } idx_leaf = (node_index)os->node_count++; if (os->node_count == SHRT_MAX) { os->full = 1; return NULL; } node = &os->nodes[idx]; node->children[push_at] = -idx_leaf; leaf = &os->nodes[idx_leaf]; leaf->tail = oid; return node; } git_oid_shorten *git_oid_shorten_new(size_t min_length) { git_oid_shorten *os; assert((size_t)((int)min_length) == min_length); os = git__calloc(1, sizeof(git_oid_shorten)); if (os == NULL) return NULL; if (resize_trie(os, 16) < 0) { git__free(os); return NULL; } os->node_count = 1; os->min_length = (int)min_length; return os; } void git_oid_shorten_free(git_oid_shorten *os) { git__free(os->nodes); git__free(os); } /* * What wizardry is this? * * This is just a memory-optimized trie: basically a very fancy * 16-ary tree, which is used to store the prefixes of the OID * strings. * * Read more: http://en.wikipedia.org/wiki/Trie * * Magic that happens in this method: * * - Each node in the trie is an union, so it can work both as * a normal node, or as a leaf. * * - Each normal node points to 16 children (one for each possible * character in the oid). This is *not* stored in an array of * pointers, because in a 64-bit arch this would be sucking * 16*sizeof(void*) = 128 bytes of memory per node, which is * insane. What we do is store Node Indexes, and use these indexes * to look up each node in the om->index array. These indexes are * signed shorts, so this limits the amount of unique OIDs that * fit in the structure to about 20000 (assuming a more or less uniform * distribution). * * - All the nodes in om->index array are stored contiguously in * memory, and each of them is 32 bytes, so we fit 2x nodes per * cache line. Convenient for speed. * * - To differentiate the leafs from the normal nodes, we store all * the indexes towards a leaf as a negative index (indexes to normal * nodes are positives). When we find that one of the children for * a node has a negative value, that means it's going to be a leaf. * This reduces the amount of indexes we have by two, but also reduces * the size of each node by 1-4 bytes (the amount we would need to * add a `is_leaf` field): this is good because it allows the nodes * to fit cleanly in cache lines. * * - Once we reach an empty children, instead of continuing to insert * new nodes for each remaining character of the OID, we store a pointer * to the tail in the leaf; if the leaf is reached again, we turn it * into a normal node and use the tail to create a new leaf. * * This is a pretty good balance between performance and memory usage. */ int git_oid_shorten_add(git_oid_shorten *os, const char *text_oid) { int i; bool is_leaf; node_index idx; if (os->full) return -1; if (text_oid == NULL) return os->min_length; idx = 0; is_leaf = false; for (i = 0; i < GIT_OID_HEXSZ; ++i) { int c = git__fromhex(text_oid[i]); trie_node *node; if (c == -1) { giterr_set(GITERR_INVALID, "Unable to shorten OID - invalid hex value"); return -1; } node = &os->nodes[idx]; if (is_leaf) { const char *tail; tail = node->tail; node->tail = NULL; node = push_leaf(os, idx, git__fromhex(tail[0]), &tail[1]); GITERR_CHECK_ALLOC(node); } if (node->children[c] == 0) { if (push_leaf(os, idx, c, &text_oid[i + 1]) == NULL) return -1; break; } idx = node->children[c]; is_leaf = false; if (idx < 0) { node->children[c] = idx = -idx; is_leaf = true; } } if (++i > os->min_length) os->min_length = i; return os->min_length; } libgit2-0.19.0/src/oid.h000066400000000000000000000013141216214232500146450ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #ifndef INCLUDE_oid_h__ #define INCLUDE_oid_h__ #include "git2/oid.h" /* * Compare two oid structures. * * @param a first oid structure. * @param b second oid structure. * @return <0, 0, >0 if a < b, a == b, a > b. */ GIT_INLINE(int) git_oid__cmp(const git_oid *a, const git_oid *b) { const unsigned char *sha1 = a->id; const unsigned char *sha2 = b->id; int i; for (i = 0; i < GIT_OID_RAWSZ; i++, sha1++, sha2++) { if (*sha1 != *sha2) return *sha1 - *sha2; } return 0; } #endif libgit2-0.19.0/src/oidmap.h000066400000000000000000000015431216214232500153470ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #ifndef INCLUDE_oidmap_h__ #define INCLUDE_oidmap_h__ #include "common.h" #include "git2/oid.h" #define kmalloc git__malloc #define kcalloc git__calloc #define krealloc git__realloc #define kfree git__free #include "khash.h" __KHASH_TYPE(oid, const git_oid *, void *); typedef khash_t(oid) git_oidmap; GIT_INLINE(khint_t) git_oidmap_hash(const git_oid *oid) { khint_t h; memcpy(&h, oid, sizeof(khint_t)); return h; } #define GIT__USE_OIDMAP \ __KHASH_IMPL(oid, static kh_inline, const git_oid *, void *, 1, git_oidmap_hash, git_oid_equal) #define git_oidmap_alloc() kh_init(oid) #define git_oidmap_free(h) kh_destroy(oid,h), h = NULL #endif libgit2-0.19.0/src/pack-objects.c000066400000000000000000000760641216214232500164500ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #include "pack-objects.h" #include "compress.h" #include "delta.h" #include "iterator.h" #include "netops.h" #include "pack.h" #include "thread-utils.h" #include "tree.h" #include "git2/pack.h" #include "git2/commit.h" #include "git2/tag.h" #include "git2/indexer.h" #include "git2/config.h" struct unpacked { git_pobject *object; void *data; struct git_delta_index *index; unsigned int depth; }; struct tree_walk_context { git_packbuilder *pb; git_buf buf; }; struct pack_write_context { git_indexer_stream *indexer; git_transfer_progress *stats; }; #ifdef GIT_THREADS #define GIT_PACKBUILDER__MUTEX_OP(pb, mtx, op) do { \ int result = git_mutex_##op(&(pb)->mtx); \ assert(!result); \ GIT_UNUSED(result); \ } while (0) #else #define GIT_PACKBUILDER__MUTEX_OP(pb,mtx,op) GIT_UNUSED(pb) #endif /* GIT_THREADS */ #define git_packbuilder__cache_lock(pb) GIT_PACKBUILDER__MUTEX_OP(pb, cache_mutex, lock) #define git_packbuilder__cache_unlock(pb) GIT_PACKBUILDER__MUTEX_OP(pb, cache_mutex, unlock) #define git_packbuilder__progress_lock(pb) GIT_PACKBUILDER__MUTEX_OP(pb, progress_mutex, lock) #define git_packbuilder__progress_unlock(pb) GIT_PACKBUILDER__MUTEX_OP(pb, progress_mutex, unlock) static unsigned name_hash(const char *name) { unsigned c, hash = 0; if (!name) return 0; /* * This effectively just creates a sortable number from the * last sixteen non-whitespace characters. Last characters * count "most", so things that end in ".c" sort together. */ while ((c = *name++) != 0) { if (git__isspace(c)) continue; hash = (hash >> 2) + (c << 24); } return hash; } static int packbuilder_config(git_packbuilder *pb) { git_config *config; int ret; int64_t val; if (git_repository_config__weakptr(&config, pb->repo) < 0) return -1; #define config_get(KEY,DST,DFLT) do { \ ret = git_config_get_int64(&val, config, KEY); \ if (!ret) (DST) = val; \ else if (ret == GIT_ENOTFOUND) (DST) = (DFLT); \ else if (ret < 0) return -1; } while (0) config_get("pack.deltaCacheSize", pb->max_delta_cache_size, GIT_PACK_DELTA_CACHE_SIZE); config_get("pack.deltaCacheLimit", pb->cache_max_small_delta_size, GIT_PACK_DELTA_CACHE_LIMIT); config_get("pack.deltaCacheSize", pb->big_file_threshold, GIT_PACK_BIG_FILE_THRESHOLD); config_get("pack.windowMemory", pb->window_memory_limit, 0); #undef config_get return 0; } int git_packbuilder_new(git_packbuilder **out, git_repository *repo) { git_packbuilder *pb; *out = NULL; pb = git__calloc(1, sizeof(*pb)); GITERR_CHECK_ALLOC(pb); pb->object_ix = git_oidmap_alloc(); if (!pb->object_ix) goto on_error; pb->repo = repo; pb->nr_threads = 1; /* do not spawn any thread by default */ if (git_hash_ctx_init(&pb->ctx) < 0 || git_repository_odb(&pb->odb, repo) < 0 || packbuilder_config(pb) < 0) goto on_error; #ifdef GIT_THREADS if (git_mutex_init(&pb->cache_mutex) || git_mutex_init(&pb->progress_mutex) || git_cond_init(&pb->progress_cond)) { giterr_set(GITERR_OS, "Failed to initialize packbuilder mutex"); goto on_error; } #endif *out = pb; return 0; on_error: git_packbuilder_free(pb); return -1; } unsigned int git_packbuilder_set_threads(git_packbuilder *pb, unsigned int n) { assert(pb); #ifdef GIT_THREADS pb->nr_threads = n; #else GIT_UNUSED(n); assert(1 == pb->nr_threads); #endif return pb->nr_threads; } static void rehash(git_packbuilder *pb) { git_pobject *po; khiter_t pos; unsigned int i; int ret; kh_clear(oid, pb->object_ix); for (i = 0, po = pb->object_list; i < pb->nr_objects; i++, po++) { pos = kh_put(oid, pb->object_ix, &po->id, &ret); kh_value(pb->object_ix, pos) = po; } } int git_packbuilder_insert(git_packbuilder *pb, const git_oid *oid, const char *name) { git_pobject *po; khiter_t pos; int ret; assert(pb && oid); /* If the object already exists in the hash table, then we don't * have any work to do */ pos = kh_get(oid, pb->object_ix, oid); if (pos != kh_end(pb->object_ix)) return 0; if (pb->nr_objects >= pb->nr_alloc) { pb->nr_alloc = (pb->nr_alloc + 1024) * 3 / 2; pb->object_list = git__realloc(pb->object_list, pb->nr_alloc * sizeof(*po)); GITERR_CHECK_ALLOC(pb->object_list); rehash(pb); } po = pb->object_list + pb->nr_objects; memset(po, 0x0, sizeof(*po)); if (git_odb_read_header(&po->size, &po->type, pb->odb, oid) < 0) return -1; pb->nr_objects++; git_oid_cpy(&po->id, oid); po->hash = name_hash(name); pos = kh_put(oid, pb->object_ix, &po->id, &ret); assert(ret != 0); kh_value(pb->object_ix, pos) = po; pb->done = false; return 0; } /* * The per-object header is a pretty dense thing, which is * - first byte: low four bits are "size", * then three bits of "type", * with the high bit being "size continues". * - each byte afterwards: low seven bits are size continuation, * with the high bit being "size continues" */ static int gen_pack_object_header( unsigned char *hdr, unsigned long size, git_otype type) { unsigned char *hdr_base; unsigned char c; assert(type >= GIT_OBJ_COMMIT && type <= GIT_OBJ_REF_DELTA); /* TODO: add support for chunked objects; see git.git 6c0d19b1 */ c = (unsigned char)((type << 4) | (size & 15)); size >>= 4; hdr_base = hdr; while (size) { *hdr++ = c | 0x80; c = size & 0x7f; size >>= 7; } *hdr++ = c; return (int)(hdr - hdr_base); } static int get_delta(void **out, git_odb *odb, git_pobject *po) { git_odb_object *src = NULL, *trg = NULL; unsigned long delta_size; void *delta_buf; *out = NULL; if (git_odb_read(&src, odb, &po->delta->id) < 0 || git_odb_read(&trg, odb, &po->id) < 0) goto on_error; delta_buf = git_delta( git_odb_object_data(src), (unsigned long)git_odb_object_size(src), git_odb_object_data(trg), (unsigned long)git_odb_object_size(trg), &delta_size, 0); if (!delta_buf || delta_size != po->delta_size) { giterr_set(GITERR_INVALID, "Delta size changed"); goto on_error; } *out = delta_buf; git_odb_object_free(src); git_odb_object_free(trg); return 0; on_error: git_odb_object_free(src); git_odb_object_free(trg); return -1; } static int write_object(git_buf *buf, git_packbuilder *pb, git_pobject *po) { git_odb_object *obj = NULL; git_buf zbuf = GIT_BUF_INIT; git_otype type; unsigned char hdr[10]; unsigned int hdr_len; unsigned long size; void *data; if (po->delta) { if (po->delta_data) data = po->delta_data; else if (get_delta(&data, pb->odb, po) < 0) goto on_error; size = po->delta_size; type = GIT_OBJ_REF_DELTA; } else { if (git_odb_read(&obj, pb->odb, &po->id)) goto on_error; data = (void *)git_odb_object_data(obj); size = (unsigned long)git_odb_object_size(obj); type = git_odb_object_type(obj); } /* Write header */ hdr_len = gen_pack_object_header(hdr, size, type); if (git_buf_put(buf, (char *)hdr, hdr_len) < 0) goto on_error; if (git_hash_update(&pb->ctx, hdr, hdr_len) < 0) goto on_error; if (type == GIT_OBJ_REF_DELTA) { if (git_buf_put(buf, (char *)po->delta->id.id, GIT_OID_RAWSZ) < 0 || git_hash_update(&pb->ctx, po->delta->id.id, GIT_OID_RAWSZ) < 0) goto on_error; } /* Write data */ if (po->z_delta_size) size = po->z_delta_size; else if (git__compress(&zbuf, data, size) < 0) goto on_error; else { if (po->delta) git__free(data); data = zbuf.ptr; size = (unsigned long)zbuf.size; } if (git_buf_put(buf, data, size) < 0 || git_hash_update(&pb->ctx, data, size) < 0) goto on_error; if (po->delta_data) git__free(po->delta_data); git_odb_object_free(obj); git_buf_free(&zbuf); pb->nr_written++; return 0; on_error: git_odb_object_free(obj); git_buf_free(&zbuf); return -1; } enum write_one_status { WRITE_ONE_SKIP = -1, /* already written */ WRITE_ONE_BREAK = 0, /* writing this will bust the limit; not written */ WRITE_ONE_WRITTEN = 1, /* normal */ WRITE_ONE_RECURSIVE = 2 /* already scheduled to be written */ }; static int write_one(git_buf *buf, git_packbuilder *pb, git_pobject *po, enum write_one_status *status) { if (po->recursing) { *status = WRITE_ONE_RECURSIVE; return 0; } else if (po->written) { *status = WRITE_ONE_SKIP; return 0; } if (po->delta) { po->recursing = 1; if (write_one(buf, pb, po->delta, status) < 0) return -1; switch (*status) { case WRITE_ONE_RECURSIVE: /* we cannot depend on this one */ po->delta = NULL; break; default: break; } } po->written = 1; po->recursing = 0; return write_object(buf, pb, po); } GIT_INLINE(void) add_to_write_order(git_pobject **wo, unsigned int *endp, git_pobject *po) { if (po->filled) return; wo[(*endp)++] = po; po->filled = 1; } static void add_descendants_to_write_order(git_pobject **wo, unsigned int *endp, git_pobject *po) { int add_to_order = 1; while (po) { if (add_to_order) { git_pobject *s; /* add this node... */ add_to_write_order(wo, endp, po); /* all its siblings... */ for (s = po->delta_sibling; s; s = s->delta_sibling) { add_to_write_order(wo, endp, s); } } /* drop down a level to add left subtree nodes if possible */ if (po->delta_child) { add_to_order = 1; po = po->delta_child; } else { add_to_order = 0; /* our sibling might have some children, it is next */ if (po->delta_sibling) { po = po->delta_sibling; continue; } /* go back to our parent node */ po = po->delta; while (po && !po->delta_sibling) { /* we're on the right side of a subtree, keep * going up until we can go right again */ po = po->delta; } if (!po) { /* done- we hit our original root node */ return; } /* pass it off to sibling at this level */ po = po->delta_sibling; } }; } static void add_family_to_write_order(git_pobject **wo, unsigned int *endp, git_pobject *po) { git_pobject *root; for (root = po; root->delta; root = root->delta) ; /* nothing */ add_descendants_to_write_order(wo, endp, root); } static int cb_tag_foreach(const char *name, git_oid *oid, void *data) { git_packbuilder *pb = data; git_pobject *po; khiter_t pos; GIT_UNUSED(name); pos = kh_get(oid, pb->object_ix, oid); if (pos == kh_end(pb->object_ix)) return 0; po = kh_value(pb->object_ix, pos); po->tagged = 1; /* TODO: peel objects */ return 0; } static git_pobject **compute_write_order(git_packbuilder *pb) { unsigned int i, wo_end, last_untagged; git_pobject **wo = git__malloc(sizeof(*wo) * pb->nr_objects); for (i = 0; i < pb->nr_objects; i++) { git_pobject *po = pb->object_list + i; po->tagged = 0; po->filled = 0; po->delta_child = NULL; po->delta_sibling = NULL; } /* * Fully connect delta_child/delta_sibling network. * Make sure delta_sibling is sorted in the original * recency order. */ for (i = pb->nr_objects; i > 0;) { git_pobject *po = &pb->object_list[--i]; if (!po->delta) continue; /* Mark me as the first child */ po->delta_sibling = po->delta->delta_child; po->delta->delta_child = po; } /* * Mark objects that are at the tip of tags. */ if (git_tag_foreach(pb->repo, &cb_tag_foreach, pb) < 0) return NULL; /* * Give the objects in the original recency order until * we see a tagged tip. */ for (i = wo_end = 0; i < pb->nr_objects; i++) { git_pobject *po = pb->object_list + i; if (po->tagged) break; add_to_write_order(wo, &wo_end, po); } last_untagged = i; /* * Then fill all the tagged tips. */ for (; i < pb->nr_objects; i++) { git_pobject *po = pb->object_list + i; if (po->tagged) add_to_write_order(wo, &wo_end, po); } /* * And then all remaining commits and tags. */ for (i = last_untagged; i < pb->nr_objects; i++) { git_pobject *po = pb->object_list + i; if (po->type != GIT_OBJ_COMMIT && po->type != GIT_OBJ_TAG) continue; add_to_write_order(wo, &wo_end, po); } /* * And then all the trees. */ for (i = last_untagged; i < pb->nr_objects; i++) { git_pobject *po = pb->object_list + i; if (po->type != GIT_OBJ_TREE) continue; add_to_write_order(wo, &wo_end, po); } /* * Finally all the rest in really tight order */ for (i = last_untagged; i < pb->nr_objects; i++) { git_pobject *po = pb->object_list + i; if (!po->filled) add_family_to_write_order(wo, &wo_end, po); } if (wo_end != pb->nr_objects) { giterr_set(GITERR_INVALID, "invalid write order"); return NULL; } return wo; } static int write_pack(git_packbuilder *pb, int (*cb)(void *buf, size_t size, void *data), void *data) { git_pobject **write_order; git_pobject *po; git_buf buf = GIT_BUF_INIT; enum write_one_status status; struct git_pack_header ph; unsigned int i = 0; write_order = compute_write_order(pb); if (write_order == NULL) goto on_error; /* Write pack header */ ph.hdr_signature = htonl(PACK_SIGNATURE); ph.hdr_version = htonl(PACK_VERSION); ph.hdr_entries = htonl(pb->nr_objects); if (cb(&ph, sizeof(ph), data) < 0) goto on_error; if (git_hash_update(&pb->ctx, &ph, sizeof(ph)) < 0) goto on_error; pb->nr_remaining = pb->nr_objects; do { pb->nr_written = 0; for ( ; i < pb->nr_objects; ++i) { po = write_order[i]; if (write_one(&buf, pb, po, &status) < 0) goto on_error; if (cb(buf.ptr, buf.size, data) < 0) goto on_error; git_buf_clear(&buf); } pb->nr_remaining -= pb->nr_written; } while (pb->nr_remaining && i < pb->nr_objects); git__free(write_order); git_buf_free(&buf); if (git_hash_final(&pb->pack_oid, &pb->ctx) < 0) goto on_error; return cb(pb->pack_oid.id, GIT_OID_RAWSZ, data); on_error: git__free(write_order); git_buf_free(&buf); return -1; } static int write_pack_buf(void *buf, size_t size, void *data) { git_buf *b = (git_buf *)data; return git_buf_put(b, buf, size); } static int type_size_sort(const void *_a, const void *_b) { const git_pobject *a = (git_pobject *)_a; const git_pobject *b = (git_pobject *)_b; if (a->type > b->type) return -1; if (a->type < b->type) return 1; if (a->hash > b->hash) return -1; if (a->hash < b->hash) return 1; /* * TODO * if (a->preferred_base > b->preferred_base) return -1; if (a->preferred_base < b->preferred_base) return 1; */ if (a->size > b->size) return -1; if (a->size < b->size) return 1; return a < b ? -1 : (a > b); /* newest first */ } static int delta_cacheable(git_packbuilder *pb, unsigned long src_size, unsigned long trg_size, unsigned long delta_size) { if (pb->max_delta_cache_size && pb->delta_cache_size + delta_size > pb->max_delta_cache_size) return 0; if (delta_size < pb->cache_max_small_delta_size) return 1; /* cache delta, if objects are large enough compared to delta size */ if ((src_size >> 20) + (trg_size >> 21) > (delta_size >> 10)) return 1; return 0; } static int try_delta(git_packbuilder *pb, struct unpacked *trg, struct unpacked *src, unsigned int max_depth, unsigned long *mem_usage, int *ret) { git_pobject *trg_object = trg->object; git_pobject *src_object = src->object; git_odb_object *obj; unsigned long trg_size, src_size, delta_size, sizediff, max_size, sz; unsigned int ref_depth; void *delta_buf; /* Don't bother doing diffs between different types */ if (trg_object->type != src_object->type) { *ret = -1; return 0; } *ret = 0; /* TODO: support reuse-delta */ /* Let's not bust the allowed depth. */ if (src->depth >= max_depth) return 0; /* Now some size filtering heuristics. */ trg_size = (unsigned long)trg_object->size; if (!trg_object->delta) { max_size = trg_size/2 - 20; ref_depth = 1; } else { max_size = trg_object->delta_size; ref_depth = trg->depth; } max_size = (uint64_t)max_size * (max_depth - src->depth) / (max_depth - ref_depth + 1); if (max_size == 0) return 0; src_size = (unsigned long)src_object->size; sizediff = src_size < trg_size ? trg_size - src_size : 0; if (sizediff >= max_size) return 0; if (trg_size < src_size / 32) return 0; /* Load data if not already done */ if (!trg->data) { if (git_odb_read(&obj, pb->odb, &trg_object->id) < 0) return -1; sz = (unsigned long)git_odb_object_size(obj); trg->data = git__malloc(sz); GITERR_CHECK_ALLOC(trg->data); memcpy(trg->data, git_odb_object_data(obj), sz); git_odb_object_free(obj); if (sz != trg_size) { giterr_set(GITERR_INVALID, "Inconsistent target object length"); return -1; } *mem_usage += sz; } if (!src->data) { if (git_odb_read(&obj, pb->odb, &src_object->id) < 0) return -1; sz = (unsigned long)git_odb_object_size(obj); src->data = git__malloc(sz); GITERR_CHECK_ALLOC(src->data); memcpy(src->data, git_odb_object_data(obj), sz); git_odb_object_free(obj); if (sz != src_size) { giterr_set(GITERR_INVALID, "Inconsistent source object length"); return -1; } *mem_usage += sz; } if (!src->index) { src->index = git_delta_create_index(src->data, src_size); if (!src->index) return 0; /* suboptimal pack - out of memory */ *mem_usage += git_delta_sizeof_index(src->index); } delta_buf = git_delta_create(src->index, trg->data, trg_size, &delta_size, max_size); if (!delta_buf) return 0; if (trg_object->delta) { /* Prefer only shallower same-sized deltas. */ if (delta_size == trg_object->delta_size && src->depth + 1 >= trg->depth) { git__free(delta_buf); return 0; } } git_packbuilder__cache_lock(pb); if (trg_object->delta_data) { git__free(trg_object->delta_data); pb->delta_cache_size -= trg_object->delta_size; trg_object->delta_data = NULL; } if (delta_cacheable(pb, src_size, trg_size, delta_size)) { pb->delta_cache_size += delta_size; git_packbuilder__cache_unlock(pb); trg_object->delta_data = git__realloc(delta_buf, delta_size); GITERR_CHECK_ALLOC(trg_object->delta_data); } else { /* create delta when writing the pack */ git_packbuilder__cache_unlock(pb); git__free(delta_buf); } trg_object->delta = src_object; trg_object->delta_size = delta_size; trg->depth = src->depth + 1; *ret = 1; return 0; } static unsigned int check_delta_limit(git_pobject *me, unsigned int n) { git_pobject *child = me->delta_child; unsigned int m = n; while (child) { unsigned int c = check_delta_limit(child, n + 1); if (m < c) m = c; child = child->delta_sibling; } return m; } static unsigned long free_unpacked(struct unpacked *n) { unsigned long freed_mem = git_delta_sizeof_index(n->index); git_delta_free_index(n->index); n->index = NULL; if (n->data) { freed_mem += (unsigned long)n->object->size; git__free(n->data); n->data = NULL; } n->object = NULL; n->depth = 0; return freed_mem; } static int find_deltas(git_packbuilder *pb, git_pobject **list, unsigned int *list_size, unsigned int window, unsigned int depth) { git_pobject *po; git_buf zbuf = GIT_BUF_INIT; struct unpacked *array; uint32_t idx = 0, count = 0; unsigned long mem_usage = 0; unsigned int i; int error = -1; array = git__calloc(window, sizeof(struct unpacked)); GITERR_CHECK_ALLOC(array); for (;;) { struct unpacked *n = array + idx; unsigned int max_depth; int j, best_base = -1; git_packbuilder__progress_lock(pb); if (!*list_size) { git_packbuilder__progress_unlock(pb); break; } po = *list++; (*list_size)--; git_packbuilder__progress_unlock(pb); mem_usage -= free_unpacked(n); n->object = po; while (pb->window_memory_limit && mem_usage > pb->window_memory_limit && count > 1) { uint32_t tail = (idx + window - count) % window; mem_usage -= free_unpacked(array + tail); count--; } /* * If the current object is at pack edge, take the depth the * objects that depend on the current object into account * otherwise they would become too deep. */ max_depth = depth; if (po->delta_child) { max_depth -= check_delta_limit(po, 0); if (max_depth <= 0) goto next; } j = window; while (--j > 0) { int ret; uint32_t other_idx = idx + j; struct unpacked *m; if (other_idx >= window) other_idx -= window; m = array + other_idx; if (!m->object) break; if (try_delta(pb, n, m, max_depth, &mem_usage, &ret) < 0) goto on_error; if (ret < 0) break; else if (ret > 0) best_base = other_idx; } /* * If we decided to cache the delta data, then it is best * to compress it right away. First because we have to do * it anyway, and doing it here while we're threaded will * save a lot of time in the non threaded write phase, * as well as allow for caching more deltas within * the same cache size limit. * ... * But only if not writing to stdout, since in that case * the network is most likely throttling writes anyway, * and therefore it is best to go to the write phase ASAP * instead, as we can afford spending more time compressing * between writes at that moment. */ if (po->delta_data) { if (git__compress(&zbuf, po->delta_data, po->delta_size) < 0) goto on_error; git__free(po->delta_data); po->delta_data = git__malloc(zbuf.size); GITERR_CHECK_ALLOC(po->delta_data); memcpy(po->delta_data, zbuf.ptr, zbuf.size); po->z_delta_size = (unsigned long)zbuf.size; git_buf_clear(&zbuf); git_packbuilder__cache_lock(pb); pb->delta_cache_size -= po->delta_size; pb->delta_cache_size += po->z_delta_size; git_packbuilder__cache_unlock(pb); } /* * If we made n a delta, and if n is already at max * depth, leaving it in the window is pointless. we * should evict it first. */ if (po->delta && max_depth <= n->depth) continue; /* * Move the best delta base up in the window, after the * currently deltified object, to keep it longer. It will * be the first base object to be attempted next. */ if (po->delta) { struct unpacked swap = array[best_base]; int dist = (window + idx - best_base) % window; int dst = best_base; while (dist--) { int src = (dst + 1) % window; array[dst] = array[src]; dst = src; } array[dst] = swap; } next: idx++; if (count + 1 < window) count++; if (idx >= window) idx = 0; } error = 0; on_error: for (i = 0; i < window; ++i) { git__free(array[i].index); git__free(array[i].data); } git__free(array); git_buf_free(&zbuf); return error; } #ifdef GIT_THREADS struct thread_params { git_thread thread; git_packbuilder *pb; git_pobject **list; git_cond cond; git_mutex mutex; unsigned int list_size; unsigned int remaining; int window; int depth; int working; int data_ready; }; static void *threaded_find_deltas(void *arg) { struct thread_params *me = arg; while (me->remaining) { if (find_deltas(me->pb, me->list, &me->remaining, me->window, me->depth) < 0) { ; /* TODO */ } git_packbuilder__progress_lock(me->pb); me->working = 0; git_cond_signal(&me->pb->progress_cond); git_packbuilder__progress_unlock(me->pb); if (git_mutex_lock(&me->mutex)) { giterr_set(GITERR_THREAD, "unable to lock packfile condition mutex"); return NULL; } while (!me->data_ready) git_cond_wait(&me->cond, &me->mutex); /* * We must not set ->data_ready before we wait on the * condition because the main thread may have set it to 1 * before we get here. In order to be sure that new * work is available if we see 1 in ->data_ready, it * was initialized to 0 before this thread was spawned * and we reset it to 0 right away. */ me->data_ready = 0; git_mutex_unlock(&me->mutex); } /* leave ->working 1 so that this doesn't get more work assigned */ return NULL; } static int ll_find_deltas(git_packbuilder *pb, git_pobject **list, unsigned int list_size, unsigned int window, unsigned int depth) { struct thread_params *p; int i, ret, active_threads = 0; if (!pb->nr_threads) pb->nr_threads = git_online_cpus(); if (pb->nr_threads <= 1) { find_deltas(pb, list, &list_size, window, depth); return 0; } p = git__malloc(pb->nr_threads * sizeof(*p)); GITERR_CHECK_ALLOC(p); /* Partition the work among the threads */ for (i = 0; i < pb->nr_threads; ++i) { unsigned sub_size = list_size / (pb->nr_threads - i); /* don't use too small segments or no deltas will be found */ if (sub_size < 2*window && i+1 < pb->nr_threads) sub_size = 0; p[i].pb = pb; p[i].window = window; p[i].depth = depth; p[i].working = 1; p[i].data_ready = 0; /* try to split chunks on "path" boundaries */ while (sub_size && sub_size < list_size && list[sub_size]->hash && list[sub_size]->hash == list[sub_size-1]->hash) sub_size++; p[i].list = list; p[i].list_size = sub_size; p[i].remaining = sub_size; list += sub_size; list_size -= sub_size; } /* Start work threads */ for (i = 0; i < pb->nr_threads; ++i) { if (!p[i].list_size) continue; git_mutex_init(&p[i].mutex); git_cond_init(&p[i].cond); ret = git_thread_create(&p[i].thread, NULL, threaded_find_deltas, &p[i]); if (ret) { giterr_set(GITERR_THREAD, "unable to create thread"); return -1; } active_threads++; } /* * Now let's wait for work completion. Each time a thread is done * with its work, we steal half of the remaining work from the * thread with the largest number of unprocessed objects and give * it to that newly idle thread. This ensure good load balancing * until the remaining object list segments are simply too short * to be worth splitting anymore. */ while (active_threads) { struct thread_params *target = NULL; struct thread_params *victim = NULL; unsigned sub_size = 0; /* Start by locating a thread that has transitioned its * 'working' flag from 1 -> 0. This indicates that it is * ready to receive more work using our work-stealing * algorithm. */ git_packbuilder__progress_lock(pb); for (;;) { for (i = 0; !target && i < pb->nr_threads; i++) if (!p[i].working) target = &p[i]; if (target) break; git_cond_wait(&pb->progress_cond, &pb->progress_mutex); } /* At this point we hold the progress lock and have located * a thread to receive more work. We still need to locate a * thread from which to steal work (the victim). */ for (i = 0; i < pb->nr_threads; i++) if (p[i].remaining > 2*window && (!victim || victim->remaining < p[i].remaining)) victim = &p[i]; if (victim) { sub_size = victim->remaining / 2; list = victim->list + victim->list_size - sub_size; while (sub_size && list[0]->hash && list[0]->hash == list[-1]->hash) { list++; sub_size--; } if (!sub_size) { /* * It is possible for some "paths" to have * so many objects that no hash boundary * might be found. Let's just steal the * exact half in that case. */ sub_size = victim->remaining / 2; list -= sub_size; } target->list = list; victim->list_size -= sub_size; victim->remaining -= sub_size; } target->list_size = sub_size; target->remaining = sub_size; target->working = 1; git_packbuilder__progress_unlock(pb); if (git_mutex_lock(&target->mutex)) { giterr_set(GITERR_THREAD, "unable to lock packfile condition mutex"); git__free(p); return -1; } target->data_ready = 1; git_cond_signal(&target->cond); git_mutex_unlock(&target->mutex); if (!sub_size) { git_thread_join(target->thread, NULL); git_cond_free(&target->cond); git_mutex_free(&target->mutex); active_threads--; } } git__free(p); return 0; } #else #define ll_find_deltas(pb, l, ls, w, d) find_deltas(pb, l, &ls, w, d) #endif static int prepare_pack(git_packbuilder *pb) { git_pobject **delta_list; unsigned int i, n = 0; if (pb->nr_objects == 0 || pb->done) return 0; /* nothing to do */ delta_list = git__malloc(pb->nr_objects * sizeof(*delta_list)); GITERR_CHECK_ALLOC(delta_list); for (i = 0; i < pb->nr_objects; ++i) { git_pobject *po = pb->object_list + i; /* Make sure the item is within our size limits */ if (po->size < 50 || po->size > pb->big_file_threshold) continue; delta_list[n++] = po; } if (n > 1) { git__tsort((void **)delta_list, n, type_size_sort); if (ll_find_deltas(pb, delta_list, n, GIT_PACK_WINDOW + 1, GIT_PACK_DEPTH) < 0) { git__free(delta_list); return -1; } } pb->done = true; git__free(delta_list); return 0; } #define PREPARE_PACK if (prepare_pack(pb) < 0) { return -1; } int git_packbuilder_foreach(git_packbuilder *pb, int (*cb)(void *buf, size_t size, void *payload), void *payload) { PREPARE_PACK; return write_pack(pb, cb, payload); } int git_packbuilder_write_buf(git_buf *buf, git_packbuilder *pb) { PREPARE_PACK; return write_pack(pb, &write_pack_buf, buf); } static int write_cb(void *buf, size_t len, void *payload) { struct pack_write_context *ctx = payload; return git_indexer_stream_add(ctx->indexer, buf, len, ctx->stats); } int git_packbuilder_write( git_packbuilder *pb, const char *path, git_transfer_progress_callback progress_cb, void *progress_cb_payload) { git_indexer_stream *indexer; git_transfer_progress stats; struct pack_write_context ctx; PREPARE_PACK; if (git_indexer_stream_new( &indexer, path, progress_cb, progress_cb_payload) < 0) return -1; ctx.indexer = indexer; ctx.stats = &stats; if (git_packbuilder_foreach(pb, write_cb, &ctx) < 0 || git_indexer_stream_finalize(indexer, &stats) < 0) { git_indexer_stream_free(indexer); return -1; } git_indexer_stream_free(indexer); return 0; } #undef PREPARE_PACK static int cb_tree_walk(const char *root, const git_tree_entry *entry, void *payload) { struct tree_walk_context *ctx = payload; /* A commit inside a tree represents a submodule commit and should be skipped. */ if (git_tree_entry_type(entry) == GIT_OBJ_COMMIT) return 0; if (git_buf_sets(&ctx->buf, root) < 0 || git_buf_puts(&ctx->buf, git_tree_entry_name(entry)) < 0) return -1; return git_packbuilder_insert(ctx->pb, git_tree_entry_id(entry), git_buf_cstr(&ctx->buf)); } int git_packbuilder_insert_commit(git_packbuilder *pb, const git_oid *oid) { git_commit *commit; if (git_commit_lookup(&commit, pb->repo, oid) < 0 || git_packbuilder_insert(pb, oid, NULL) < 0) return -1; if (git_packbuilder_insert_tree(pb, git_commit_tree_id(commit)) < 0) return -1; git_commit_free(commit); return 0; } int git_packbuilder_insert_tree(git_packbuilder *pb, const git_oid *oid) { git_tree *tree; struct tree_walk_context context = { pb, GIT_BUF_INIT }; if (git_tree_lookup(&tree, pb->repo, oid) < 0 || git_packbuilder_insert(pb, oid, NULL) < 0) return -1; if (git_tree_walk(tree, GIT_TREEWALK_PRE, cb_tree_walk, &context) < 0) { git_tree_free(tree); git_buf_free(&context.buf); return -1; } git_tree_free(tree); git_buf_free(&context.buf); return 0; } uint32_t git_packbuilder_object_count(git_packbuilder *pb) { return pb->nr_objects; } uint32_t git_packbuilder_written(git_packbuilder *pb) { return pb->nr_written; } void git_packbuilder_free(git_packbuilder *pb) { if (pb == NULL) return; #ifdef GIT_THREADS git_mutex_free(&pb->cache_mutex); git_mutex_free(&pb->progress_mutex); git_cond_free(&pb->progress_cond); #endif if (pb->odb) git_odb_free(pb->odb); if (pb->object_ix) git_oidmap_free(pb->object_ix); if (pb->object_list) git__free(pb->object_list); git_hash_ctx_cleanup(&pb->ctx); git__free(pb); } libgit2-0.19.0/src/pack-objects.h000066400000000000000000000036711216214232500164470ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #ifndef INCLUDE_pack_objects_h__ #define INCLUDE_pack_objects_h__ #include "common.h" #include "buffer.h" #include "hash.h" #include "oidmap.h" #include "netops.h" #include "git2/oid.h" #define GIT_PACK_WINDOW 10 /* number of objects to possibly delta against */ #define GIT_PACK_DEPTH 50 /* max delta depth */ #define GIT_PACK_DELTA_CACHE_SIZE (256 * 1024 * 1024) #define GIT_PACK_DELTA_CACHE_LIMIT 1000 #define GIT_PACK_BIG_FILE_THRESHOLD (512 * 1024 * 1024) typedef struct git_pobject { git_oid id; git_otype type; git_off_t offset; size_t size; unsigned int hash; /* name hint hash */ struct git_pobject *delta; /* delta base object */ struct git_pobject *delta_child; /* deltified objects who bases me */ struct git_pobject *delta_sibling; /* other deltified objects * who uses the same base as * me */ void *delta_data; unsigned long delta_size; unsigned long z_delta_size; int written:1, recursing:1, tagged:1, filled:1; } git_pobject; struct git_packbuilder { git_repository *repo; /* associated repository */ git_odb *odb; /* associated object database */ git_hash_ctx ctx; uint32_t nr_objects, nr_alloc, nr_written, nr_remaining; git_pobject *object_list; git_oidmap *object_ix; git_oid pack_oid; /* hash of written pack */ /* synchronization objects */ git_mutex cache_mutex; git_mutex progress_mutex; git_cond progress_cond; /* configs */ uint64_t delta_cache_size; uint64_t max_delta_cache_size; uint64_t cache_max_small_delta_size; uint64_t big_file_threshold; uint64_t window_memory_limit; int nr_threads; /* nr of threads to use */ bool done; }; int git_packbuilder_write_buf(git_buf *buf, git_packbuilder *pb); #endif /* INCLUDE_pack_objects_h__ */ libgit2-0.19.0/src/pack.c000066400000000000000000000664111216214232500150140ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #include "common.h" #include "odb.h" #include "pack.h" #include "delta-apply.h" #include "sha1_lookup.h" #include "mwindow.h" #include "fileops.h" #include "oid.h" #include static int packfile_open(struct git_pack_file *p); static git_off_t nth_packed_object_offset(const struct git_pack_file *p, uint32_t n); int packfile_unpack_compressed( git_rawobj *obj, struct git_pack_file *p, git_mwindow **w_curs, git_off_t *curpos, size_t size, git_otype type); /* Can find the offset of an object given * a prefix of an identifier. * Throws GIT_EAMBIGUOUSOIDPREFIX if short oid * is ambiguous within the pack. * This method assumes that len is between * GIT_OID_MINPREFIXLEN and GIT_OID_HEXSZ. */ static int pack_entry_find_offset( git_off_t *offset_out, git_oid *found_oid, struct git_pack_file *p, const git_oid *short_oid, size_t len); static int packfile_error(const char *message) { giterr_set(GITERR_ODB, "Invalid pack file - %s", message); return -1; } /******************** * Delta base cache ********************/ static git_pack_cache_entry *new_cache_object(git_rawobj *source) { git_pack_cache_entry *e = git__calloc(1, sizeof(git_pack_cache_entry)); if (!e) return NULL; memcpy(&e->raw, source, sizeof(git_rawobj)); return e; } static void free_cache_object(void *o) { git_pack_cache_entry *e = (git_pack_cache_entry *)o; if (e != NULL) { assert(e->refcount.val == 0); git__free(e->raw.data); git__free(e); } } static void cache_free(git_pack_cache *cache) { khiter_t k; if (cache->entries) { for (k = kh_begin(cache->entries); k != kh_end(cache->entries); k++) { if (kh_exist(cache->entries, k)) free_cache_object(kh_value(cache->entries, k)); } git_offmap_free(cache->entries); git_mutex_free(&cache->lock); } memset(cache, 0, sizeof(*cache)); } static int cache_init(git_pack_cache *cache) { memset(cache, 0, sizeof(*cache)); cache->entries = git_offmap_alloc(); GITERR_CHECK_ALLOC(cache->entries); cache->memory_limit = GIT_PACK_CACHE_MEMORY_LIMIT; if (git_mutex_init(&cache->lock)) { giterr_set(GITERR_OS, "Failed to initialize pack cache mutex"); git__free(cache->entries); cache->entries = NULL; return -1; } return 0; } static git_pack_cache_entry *cache_get(git_pack_cache *cache, git_off_t offset) { khiter_t k; git_pack_cache_entry *entry = NULL; if (git_mutex_lock(&cache->lock) < 0) return NULL; k = kh_get(off, cache->entries, offset); if (k != kh_end(cache->entries)) { /* found it */ entry = kh_value(cache->entries, k); git_atomic_inc(&entry->refcount); entry->last_usage = cache->use_ctr++; } git_mutex_unlock(&cache->lock); return entry; } /* Run with the cache lock held */ static void free_lowest_entry(git_pack_cache *cache) { git_pack_cache_entry *entry; khiter_t k; for (k = kh_begin(cache->entries); k != kh_end(cache->entries); k++) { if (!kh_exist(cache->entries, k)) continue; entry = kh_value(cache->entries, k); if (entry && entry->refcount.val == 0) { cache->memory_used -= entry->raw.len; kh_del(off, cache->entries, k); free_cache_object(entry); } } } static int cache_add(git_pack_cache *cache, git_rawobj *base, git_off_t offset) { git_pack_cache_entry *entry; int error, exists = 0; khiter_t k; if (base->len > GIT_PACK_CACHE_SIZE_LIMIT) return -1; entry = new_cache_object(base); if (entry) { if (git_mutex_lock(&cache->lock) < 0) { giterr_set(GITERR_OS, "failed to lock cache"); return -1; } /* Add it to the cache if nobody else has */ exists = kh_get(off, cache->entries, offset) != kh_end(cache->entries); if (!exists) { while (cache->memory_used + base->len > cache->memory_limit) free_lowest_entry(cache); k = kh_put(off, cache->entries, offset, &error); assert(error != 0); kh_value(cache->entries, k) = entry; cache->memory_used += entry->raw.len; } git_mutex_unlock(&cache->lock); /* Somebody beat us to adding it into the cache */ if (exists) { git__free(entry); return -1; } } return 0; } /*********************************************************** * * PACK INDEX METHODS * ***********************************************************/ static void pack_index_free(struct git_pack_file *p) { if (p->oids) { git__free(p->oids); p->oids = NULL; } if (p->index_map.data) { git_futils_mmap_free(&p->index_map); p->index_map.data = NULL; } } static int pack_index_check(const char *path, struct git_pack_file *p) { struct git_pack_idx_header *hdr; uint32_t version, nr, i, *index; void *idx_map; size_t idx_size; struct stat st; int error; /* TODO: properly open the file without access time using O_NOATIME */ git_file fd = git_futils_open_ro(path); if (fd < 0) return fd; if (p_fstat(fd, &st) < 0) { p_close(fd); giterr_set(GITERR_OS, "Unable to stat pack index '%s'", path); return -1; } if (!S_ISREG(st.st_mode) || !git__is_sizet(st.st_size) || (idx_size = (size_t)st.st_size) < 4 * 256 + 20 + 20) { p_close(fd); giterr_set(GITERR_ODB, "Invalid pack index '%s'", path); return -1; } error = git_futils_mmap_ro(&p->index_map, fd, 0, idx_size); p_close(fd); if (error < 0) return error; hdr = idx_map = p->index_map.data; if (hdr->idx_signature == htonl(PACK_IDX_SIGNATURE)) { version = ntohl(hdr->idx_version); if (version < 2 || version > 2) { git_futils_mmap_free(&p->index_map); return packfile_error("unsupported index version"); } } else version = 1; nr = 0; index = idx_map; if (version > 1) index += 2; /* skip index header */ for (i = 0; i < 256; i++) { uint32_t n = ntohl(index[i]); if (n < nr) { git_futils_mmap_free(&p->index_map); return packfile_error("index is non-monotonic"); } nr = n; } if (version == 1) { /* * Total size: * - 256 index entries 4 bytes each * - 24-byte entries * nr (20-byte sha1 + 4-byte offset) * - 20-byte SHA1 of the packfile * - 20-byte SHA1 file checksum */ if (idx_size != 4*256 + nr * 24 + 20 + 20) { git_futils_mmap_free(&p->index_map); return packfile_error("index is corrupted"); } } else if (version == 2) { /* * Minimum size: * - 8 bytes of header * - 256 index entries 4 bytes each * - 20-byte sha1 entry * nr * - 4-byte crc entry * nr * - 4-byte offset entry * nr * - 20-byte SHA1 of the packfile * - 20-byte SHA1 file checksum * And after the 4-byte offset table might be a * variable sized table containing 8-byte entries * for offsets larger than 2^31. */ unsigned long min_size = 8 + 4*256 + nr*(20 + 4 + 4) + 20 + 20; unsigned long max_size = min_size; if (nr) max_size += (nr - 1)*8; if (idx_size < min_size || idx_size > max_size) { git_futils_mmap_free(&p->index_map); return packfile_error("wrong index size"); } } p->num_objects = nr; p->index_version = version; return 0; } static int pack_index_open(struct git_pack_file *p) { char *idx_name; int error = 0; size_t name_len, base_len; if (p->index_version > -1) return 0; name_len = strlen(p->pack_name); assert(name_len > strlen(".pack")); /* checked by git_pack_file alloc */ if ((idx_name = git__malloc(name_len)) == NULL) return -1; base_len = name_len - strlen(".pack"); memcpy(idx_name, p->pack_name, base_len); memcpy(idx_name + base_len, ".idx", sizeof(".idx")); if ((error = git_mutex_lock(&p->lock)) < 0) return error; if (p->index_version == -1) error = pack_index_check(idx_name, p); git__free(idx_name); git_mutex_unlock(&p->lock); return error; } static unsigned char *pack_window_open( struct git_pack_file *p, git_mwindow **w_cursor, git_off_t offset, unsigned int *left) { if (p->mwf.fd == -1 && packfile_open(p) < 0) return NULL; /* Since packfiles end in a hash of their content and it's * pointless to ask for an offset into the middle of that * hash, and the pack_window_contains function above wouldn't match * don't allow an offset too close to the end of the file. */ if (offset > (p->mwf.size - 20)) return NULL; return git_mwindow_open(&p->mwf, w_cursor, offset, 20, left); } static int packfile_unpack_header1( unsigned long *usedp, size_t *sizep, git_otype *type, const unsigned char *buf, unsigned long len) { unsigned shift; unsigned long size, c; unsigned long used = 0; c = buf[used++]; *type = (c >> 4) & 7; size = c & 15; shift = 4; while (c & 0x80) { if (len <= used) return GIT_EBUFS; if (bitsizeof(long) <= shift) { *usedp = 0; return -1; } c = buf[used++]; size += (c & 0x7f) << shift; shift += 7; } *sizep = (size_t)size; *usedp = used; return 0; } int git_packfile_unpack_header( size_t *size_p, git_otype *type_p, git_mwindow_file *mwf, git_mwindow **w_curs, git_off_t *curpos) { unsigned char *base; unsigned int left; unsigned long used; int ret; /* pack_window_open() assures us we have [base, base + 20) available * as a range that we can look at at. (Its actually the hash * size that is assured.) With our object header encoding * the maximum deflated object size is 2^137, which is just * insane, so we know won't exceed what we have been given. */ /* base = pack_window_open(p, w_curs, *curpos, &left); */ base = git_mwindow_open(mwf, w_curs, *curpos, 20, &left); if (base == NULL) return GIT_EBUFS; ret = packfile_unpack_header1(&used, size_p, type_p, base, left); git_mwindow_close(w_curs); if (ret == GIT_EBUFS) return ret; else if (ret < 0) return packfile_error("header length is zero"); *curpos += used; return 0; } int git_packfile_resolve_header( size_t *size_p, git_otype *type_p, struct git_pack_file *p, git_off_t offset) { git_mwindow *w_curs = NULL; git_off_t curpos = offset; size_t size; git_otype type; git_off_t base_offset; int error; error = git_packfile_unpack_header(&size, &type, &p->mwf, &w_curs, &curpos); git_mwindow_close(&w_curs); if (error < 0) return error; if (type == GIT_OBJ_OFS_DELTA || type == GIT_OBJ_REF_DELTA) { size_t base_size; git_rawobj delta; base_offset = get_delta_base(p, &w_curs, &curpos, type, offset); git_mwindow_close(&w_curs); error = packfile_unpack_compressed(&delta, p, &w_curs, &curpos, size, type); git_mwindow_close(&w_curs); if (error < 0) return error; error = git__delta_read_header(delta.data, delta.len, &base_size, size_p); git__free(delta.data); if (error < 0) return error; } else *size_p = size; while (type == GIT_OBJ_OFS_DELTA || type == GIT_OBJ_REF_DELTA) { curpos = base_offset; error = git_packfile_unpack_header(&size, &type, &p->mwf, &w_curs, &curpos); git_mwindow_close(&w_curs); if (error < 0) return error; if (type != GIT_OBJ_OFS_DELTA && type != GIT_OBJ_REF_DELTA) break; base_offset = get_delta_base(p, &w_curs, &curpos, type, base_offset); git_mwindow_close(&w_curs); } *type_p = type; return error; } static int packfile_unpack_delta( git_rawobj *obj, struct git_pack_file *p, git_mwindow **w_curs, git_off_t *curpos, size_t delta_size, git_otype delta_type, git_off_t obj_offset) { git_off_t base_offset, base_key; git_rawobj base, delta; git_pack_cache_entry *cached = NULL; int error, found_base = 0; base_offset = get_delta_base(p, w_curs, curpos, delta_type, obj_offset); git_mwindow_close(w_curs); if (base_offset == 0) return packfile_error("delta offset is zero"); if (base_offset < 0) /* must actually be an error code */ return (int)base_offset; if (!p->bases.entries && (cache_init(&p->bases) < 0)) return -1; base_key = base_offset; /* git_packfile_unpack modifies base_offset */ if ((cached = cache_get(&p->bases, base_offset)) != NULL) { memcpy(&base, &cached->raw, sizeof(git_rawobj)); found_base = 1; } if (!cached) { /* have to inflate it */ error = git_packfile_unpack(&base, p, &base_offset); /* * TODO: git.git tries to load the base from other packfiles * or loose objects. * * We'll need to do this in order to support thin packs. */ if (error < 0) return error; } error = packfile_unpack_compressed(&delta, p, w_curs, curpos, delta_size, delta_type); git_mwindow_close(w_curs); if (error < 0) { if (!found_base) git__free(base.data); return error; } obj->type = base.type; error = git__delta_apply(obj, base.data, base.len, delta.data, delta.len); if (error < 0) goto on_error; if (found_base) git_atomic_dec(&cached->refcount); else if (cache_add(&p->bases, &base, base_key) < 0) git__free(base.data); on_error: git__free(delta.data); return error; /* error set by git__delta_apply */ } int git_packfile_unpack( git_rawobj *obj, struct git_pack_file *p, git_off_t *obj_offset) { git_mwindow *w_curs = NULL; git_off_t curpos = *obj_offset; int error; size_t size = 0; git_otype type; /* * TODO: optionally check the CRC on the packfile */ obj->data = NULL; obj->len = 0; obj->type = GIT_OBJ_BAD; error = git_packfile_unpack_header(&size, &type, &p->mwf, &w_curs, &curpos); git_mwindow_close(&w_curs); if (error < 0) return error; switch (type) { case GIT_OBJ_OFS_DELTA: case GIT_OBJ_REF_DELTA: error = packfile_unpack_delta( obj, p, &w_curs, &curpos, size, type, *obj_offset); break; case GIT_OBJ_COMMIT: case GIT_OBJ_TREE: case GIT_OBJ_BLOB: case GIT_OBJ_TAG: error = packfile_unpack_compressed( obj, p, &w_curs, &curpos, size, type); break; default: error = packfile_error("invalid packfile type in header");; break; } *obj_offset = curpos; return error; } static void *use_git_alloc(void *opaq, unsigned int count, unsigned int size) { GIT_UNUSED(opaq); return git__calloc(count, size); } static void use_git_free(void *opaq, void *ptr) { GIT_UNUSED(opaq); git__free(ptr); } int git_packfile_stream_open(git_packfile_stream *obj, struct git_pack_file *p, git_off_t curpos) { int st; memset(obj, 0, sizeof(git_packfile_stream)); obj->curpos = curpos; obj->p = p; obj->zstream.zalloc = use_git_alloc; obj->zstream.zfree = use_git_free; obj->zstream.next_in = Z_NULL; obj->zstream.next_out = Z_NULL; st = inflateInit(&obj->zstream); if (st != Z_OK) { git__free(obj); giterr_set(GITERR_ZLIB, "Failed to inflate packfile"); return -1; } return 0; } ssize_t git_packfile_stream_read(git_packfile_stream *obj, void *buffer, size_t len) { unsigned char *in; size_t written; int st; if (obj->done) return 0; in = pack_window_open(obj->p, &obj->mw, obj->curpos, &obj->zstream.avail_in); if (in == NULL) return GIT_EBUFS; obj->zstream.next_out = buffer; obj->zstream.avail_out = (unsigned int)len; obj->zstream.next_in = in; st = inflate(&obj->zstream, Z_SYNC_FLUSH); git_mwindow_close(&obj->mw); obj->curpos += obj->zstream.next_in - in; written = len - obj->zstream.avail_out; if (st != Z_OK && st != Z_STREAM_END) { giterr_set(GITERR_ZLIB, "Failed to inflate packfile"); return -1; } if (st == Z_STREAM_END) obj->done = 1; /* If we didn't write anything out but we're not done, we need more data */ if (!written && st != Z_STREAM_END) return GIT_EBUFS; return written; } void git_packfile_stream_free(git_packfile_stream *obj) { inflateEnd(&obj->zstream); } int packfile_unpack_compressed( git_rawobj *obj, struct git_pack_file *p, git_mwindow **w_curs, git_off_t *curpos, size_t size, git_otype type) { int st; z_stream stream; unsigned char *buffer, *in; buffer = git__calloc(1, size + 1); GITERR_CHECK_ALLOC(buffer); memset(&stream, 0, sizeof(stream)); stream.next_out = buffer; stream.avail_out = (uInt)size + 1; stream.zalloc = use_git_alloc; stream.zfree = use_git_free; st = inflateInit(&stream); if (st != Z_OK) { git__free(buffer); giterr_set(GITERR_ZLIB, "Failed to inflate packfile"); return -1; } do { in = pack_window_open(p, w_curs, *curpos, &stream.avail_in); stream.next_in = in; st = inflate(&stream, Z_FINISH); git_mwindow_close(w_curs); if (!stream.avail_out) break; /* the payload is larger than it should be */ if (st == Z_BUF_ERROR && in == NULL) { inflateEnd(&stream); git__free(buffer); return GIT_EBUFS; } *curpos += stream.next_in - in; } while (st == Z_OK || st == Z_BUF_ERROR); inflateEnd(&stream); if ((st != Z_STREAM_END) || stream.total_out != size) { git__free(buffer); giterr_set(GITERR_ZLIB, "Failed to inflate packfile"); return -1; } obj->type = type; obj->len = size; obj->data = buffer; return 0; } /* * curpos is where the data starts, delta_obj_offset is the where the * header starts */ git_off_t get_delta_base( struct git_pack_file *p, git_mwindow **w_curs, git_off_t *curpos, git_otype type, git_off_t delta_obj_offset) { unsigned int left = 0; unsigned char *base_info; git_off_t base_offset; git_oid unused; base_info = pack_window_open(p, w_curs, *curpos, &left); /* Assumption: the only reason this would fail is because the file is too small */ if (base_info == NULL) return GIT_EBUFS; /* pack_window_open() assured us we have [base_info, base_info + 20) * as a range that we can look at without walking off the * end of the mapped window. Its actually the hash size * that is assured. An OFS_DELTA longer than the hash size * is stupid, as then a REF_DELTA would be smaller to store. */ if (type == GIT_OBJ_OFS_DELTA) { unsigned used = 0; unsigned char c = base_info[used++]; base_offset = c & 127; while (c & 128) { if (left <= used) return GIT_EBUFS; base_offset += 1; if (!base_offset || MSB(base_offset, 7)) return 0; /* overflow */ c = base_info[used++]; base_offset = (base_offset << 7) + (c & 127); } base_offset = delta_obj_offset - base_offset; if (base_offset <= 0 || base_offset >= delta_obj_offset) return 0; /* out of bound */ *curpos += used; } else if (type == GIT_OBJ_REF_DELTA) { /* If we have the cooperative cache, search in it first */ if (p->has_cache) { khiter_t k; git_oid oid; git_oid_fromraw(&oid, base_info); k = kh_get(oid, p->idx_cache, &oid); if (k != kh_end(p->idx_cache)) { *curpos += 20; return ((struct git_pack_entry *)kh_value(p->idx_cache, k))->offset; } } /* The base entry _must_ be in the same pack */ if (pack_entry_find_offset(&base_offset, &unused, p, (git_oid *)base_info, GIT_OID_HEXSZ) < 0) return packfile_error("base entry delta is not in the same pack"); *curpos += 20; } else return 0; return base_offset; } /*********************************************************** * * PACKFILE METHODS * ***********************************************************/ void git_packfile_free(struct git_pack_file *p) { if (!p) return; cache_free(&p->bases); git_mwindow_free_all(&p->mwf); if (p->mwf.fd != -1) p_close(p->mwf.fd); pack_index_free(p); git__free(p->bad_object_sha1); git_mutex_free(&p->lock); git__free(p); } static int packfile_open(struct git_pack_file *p) { struct stat st; struct git_pack_header hdr; git_oid sha1; unsigned char *idx_sha1; if (p->index_version == -1 && pack_index_open(p) < 0) return git_odb__error_notfound("failed to open packfile", NULL); /* if mwf opened by another thread, return now */ if (git_mutex_lock(&p->lock) < 0) return packfile_error("failed to get lock for open"); if (p->mwf.fd >= 0) { git_mutex_unlock(&p->lock); return 0; } /* TODO: open with noatime */ p->mwf.fd = git_futils_open_ro(p->pack_name); if (p->mwf.fd < 0) goto cleanup; if (p_fstat(p->mwf.fd, &st) < 0 || git_mwindow_file_register(&p->mwf) < 0) goto cleanup; /* If we created the struct before we had the pack we lack size. */ if (!p->mwf.size) { if (!S_ISREG(st.st_mode)) goto cleanup; p->mwf.size = (git_off_t)st.st_size; } else if (p->mwf.size != st.st_size) goto cleanup; #if 0 /* We leave these file descriptors open with sliding mmap; * there is no point keeping them open across exec(), though. */ fd_flag = fcntl(p->mwf.fd, F_GETFD, 0); if (fd_flag < 0) goto cleanup; fd_flag |= FD_CLOEXEC; if (fcntl(p->pack_fd, F_SETFD, fd_flag) == -1) goto cleanup; #endif /* Verify we recognize this pack file format. */ if (p_read(p->mwf.fd, &hdr, sizeof(hdr)) < 0 || hdr.hdr_signature != htonl(PACK_SIGNATURE) || !pack_version_ok(hdr.hdr_version)) goto cleanup; /* Verify the pack matches its index. */ if (p->num_objects != ntohl(hdr.hdr_entries) || p_lseek(p->mwf.fd, p->mwf.size - GIT_OID_RAWSZ, SEEK_SET) == -1 || p_read(p->mwf.fd, sha1.id, GIT_OID_RAWSZ) < 0) goto cleanup; idx_sha1 = ((unsigned char *)p->index_map.data) + p->index_map.len - 40; if (git_oid__cmp(&sha1, (git_oid *)idx_sha1) != 0) goto cleanup; git_mutex_unlock(&p->lock); return 0; cleanup: giterr_set(GITERR_OS, "Invalid packfile '%s'", p->pack_name); p_close(p->mwf.fd); p->mwf.fd = -1; git_mutex_unlock(&p->lock); return -1; } int git_packfile_alloc(struct git_pack_file **pack_out, const char *path) { struct stat st; struct git_pack_file *p; size_t path_len = path ? strlen(path) : 0; *pack_out = NULL; if (path_len < strlen(".idx")) return git_odb__error_notfound("invalid packfile path", NULL); p = git__calloc(1, sizeof(*p) + path_len + 2); GITERR_CHECK_ALLOC(p); memcpy(p->pack_name, path, path_len + 1); /* * Make sure a corresponding .pack file exists and that * the index looks sane. */ if (git__suffixcmp(path, ".idx") == 0) { size_t root_len = path_len - strlen(".idx"); memcpy(p->pack_name + root_len, ".keep", sizeof(".keep")); if (git_path_exists(p->pack_name) == true) p->pack_keep = 1; memcpy(p->pack_name + root_len, ".pack", sizeof(".pack")); path_len = path_len - strlen(".idx") + strlen(".pack"); } if (p_stat(p->pack_name, &st) < 0 || !S_ISREG(st.st_mode)) { git__free(p); return git_odb__error_notfound("packfile not found", NULL); } /* ok, it looks sane as far as we can check without * actually mapping the pack file. */ p->mwf.fd = -1; p->mwf.size = st.st_size; p->pack_local = 1; p->mtime = (git_time_t)st.st_mtime; p->index_version = -1; if (git_mutex_init(&p->lock)) { giterr_set(GITERR_OS, "Failed to initialize packfile mutex"); git__free(p); return -1; } /* see if we can parse the sha1 oid in the packfile name */ if (path_len < 40 || git_oid_fromstr(&p->sha1, path + path_len - GIT_OID_HEXSZ) < 0) memset(&p->sha1, 0x0, GIT_OID_RAWSZ); *pack_out = p; return 0; } /*********************************************************** * * PACKFILE ENTRY SEARCH INTERNALS * ***********************************************************/ static git_off_t nth_packed_object_offset(const struct git_pack_file *p, uint32_t n) { const unsigned char *index = p->index_map.data; index += 4 * 256; if (p->index_version == 1) { return ntohl(*((uint32_t *)(index + 24 * n))); } else { uint32_t off; index += 8 + p->num_objects * (20 + 4); off = ntohl(*((uint32_t *)(index + 4 * n))); if (!(off & 0x80000000)) return off; index += p->num_objects * 4 + (off & 0x7fffffff) * 8; return (((uint64_t)ntohl(*((uint32_t *)(index + 0)))) << 32) | ntohl(*((uint32_t *)(index + 4))); } } static int git__memcmp4(const void *a, const void *b) { return memcmp(a, b, 4); } int git_pack_foreach_entry( struct git_pack_file *p, git_odb_foreach_cb cb, void *data) { const unsigned char *index = p->index_map.data, *current; uint32_t i; if (index == NULL) { int error; if ((error = pack_index_open(p)) < 0) return error; assert(p->index_map.data); index = p->index_map.data; } if (p->index_version > 1) { index += 8; } index += 4 * 256; if (p->oids == NULL) { git_vector offsets, oids; int error; if ((error = git_vector_init(&oids, p->num_objects, NULL))) return error; if ((error = git_vector_init(&offsets, p->num_objects, git__memcmp4))) return error; if (p->index_version > 1) { const unsigned char *off = index + 24 * p->num_objects; for (i = 0; i < p->num_objects; i++) git_vector_insert(&offsets, (void*)&off[4 * i]); git_vector_sort(&offsets); git_vector_foreach(&offsets, i, current) git_vector_insert(&oids, (void*)&index[5 * (current - off)]); } else { for (i = 0; i < p->num_objects; i++) git_vector_insert(&offsets, (void*)&index[24 * i]); git_vector_sort(&offsets); git_vector_foreach(&offsets, i, current) git_vector_insert(&oids, (void*)¤t[4]); } git_vector_free(&offsets); p->oids = (git_oid **)oids.contents; } for (i = 0; i < p->num_objects; i++) if (cb(p->oids[i], data)) return GIT_EUSER; return 0; } static int pack_entry_find_offset( git_off_t *offset_out, git_oid *found_oid, struct git_pack_file *p, const git_oid *short_oid, size_t len) { const uint32_t *level1_ofs = p->index_map.data; const unsigned char *index = p->index_map.data; unsigned hi, lo, stride; int pos, found = 0; const unsigned char *current = 0; *offset_out = 0; if (p->index_version == -1) { int error; if ((error = pack_index_open(p)) < 0) return error; assert(p->index_map.data); index = p->index_map.data; level1_ofs = p->index_map.data; } if (p->index_version > 1) { level1_ofs += 2; index += 8; } index += 4 * 256; hi = ntohl(level1_ofs[(int)short_oid->id[0]]); lo = ((short_oid->id[0] == 0x0) ? 0 : ntohl(level1_ofs[(int)short_oid->id[0] - 1])); if (p->index_version > 1) { stride = 20; } else { stride = 24; index += 4; } #ifdef INDEX_DEBUG_LOOKUP printf("%02x%02x%02x... lo %u hi %u nr %d\n", short_oid->id[0], short_oid->id[1], short_oid->id[2], lo, hi, p->num_objects); #endif /* Use git.git lookup code */ pos = sha1_entry_pos(index, stride, 0, lo, hi, p->num_objects, short_oid->id); if (pos >= 0) { /* An object matching exactly the oid was found */ found = 1; current = index + pos * stride; } else { /* No object was found */ /* pos refers to the object with the "closest" oid to short_oid */ pos = - 1 - pos; if (pos < (int)p->num_objects) { current = index + pos * stride; if (!git_oid_ncmp(short_oid, (const git_oid *)current, len)) found = 1; } } if (found && len != GIT_OID_HEXSZ && pos + 1 < (int)p->num_objects) { /* Check for ambiguousity */ const unsigned char *next = current + stride; if (!git_oid_ncmp(short_oid, (const git_oid *)next, len)) { found = 2; } } if (!found) return git_odb__error_notfound("failed to find offset for pack entry", short_oid); if (found > 1) return git_odb__error_ambiguous("found multiple offsets for pack entry"); *offset_out = nth_packed_object_offset(p, pos); git_oid_fromraw(found_oid, current); #ifdef INDEX_DEBUG_LOOKUP { unsigned char hex_sha1[GIT_OID_HEXSZ + 1]; git_oid_fmt(hex_sha1, found_oid); hex_sha1[GIT_OID_HEXSZ] = '\0'; printf("found lo=%d %s\n", lo, hex_sha1); } #endif return 0; } int git_pack_entry_find( struct git_pack_entry *e, struct git_pack_file *p, const git_oid *short_oid, size_t len) { git_off_t offset; git_oid found_oid; int error; assert(p); if (len == GIT_OID_HEXSZ && p->num_bad_objects) { unsigned i; for (i = 0; i < p->num_bad_objects; i++) if (git_oid__cmp(short_oid, &p->bad_object_sha1[i]) == 0) return packfile_error("bad object found in packfile"); } error = pack_entry_find_offset(&offset, &found_oid, p, short_oid, len); if (error < 0) return error; /* we found a unique entry in the index; * make sure the packfile backing the index * still exists on disk */ if (p->mwf.fd == -1 && (error = packfile_open(p)) < 0) return error; e->offset = offset; e->p = p; git_oid_cpy(&e->sha1, &found_oid); return 0; } libgit2-0.19.0/src/pack.h000066400000000000000000000100351216214232500150100ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #ifndef INCLUDE_pack_h__ #define INCLUDE_pack_h__ #include #include "git2/oid.h" #include "common.h" #include "map.h" #include "mwindow.h" #include "odb.h" #include "oidmap.h" #define GIT_PACK_FILE_MODE 0444 #define PACK_SIGNATURE 0x5041434b /* "PACK" */ #define PACK_VERSION 2 #define pack_version_ok(v) ((v) == htonl(2) || (v) == htonl(3)) struct git_pack_header { uint32_t hdr_signature; uint32_t hdr_version; uint32_t hdr_entries; }; /* * The first four bytes of index formats later than version 1 should * start with this signature, as all older git binaries would find this * value illegal and abort reading the file. * * This is the case because the number of objects in a packfile * cannot exceed 1,431,660,000 as every object would need at least * 3 bytes of data and the overall packfile cannot exceed 4 GiB with * version 1 of the index file due to the offsets limited to 32 bits. * Clearly the signature exceeds this maximum. * * Very old git binaries will also compare the first 4 bytes to the * next 4 bytes in the index and abort with a "non-monotonic index" * error if the second 4 byte word is smaller than the first 4 * byte word. This would be true in the proposed future index * format as idx_signature would be greater than idx_version. */ #define PACK_IDX_SIGNATURE 0xff744f63 /* "\377tOc" */ struct git_pack_idx_header { uint32_t idx_signature; uint32_t idx_version; }; typedef struct git_pack_cache_entry { size_t last_usage; /* enough? */ git_atomic refcount; git_rawobj raw; } git_pack_cache_entry; #include "offmap.h" GIT__USE_OFFMAP; GIT__USE_OIDMAP; #define GIT_PACK_CACHE_MEMORY_LIMIT 16 * 1024 * 1024 #define GIT_PACK_CACHE_SIZE_LIMIT 1024 * 1024 /* don't bother caching anything over 1MB */ typedef struct { size_t memory_used; size_t memory_limit; size_t use_ctr; git_mutex lock; git_offmap *entries; } git_pack_cache; struct git_pack_file { git_mwindow_file mwf; git_map index_map; git_mutex lock; /* protect updates to mwf and index_map */ uint32_t num_objects; uint32_t num_bad_objects; git_oid *bad_object_sha1; /* array of git_oid */ int index_version; git_time_t mtime; unsigned pack_local:1, pack_keep:1, has_cache:1; git_oid sha1; git_oidmap *idx_cache; git_oid **oids; git_pack_cache bases; /* delta base cache */ /* something like ".git/objects/pack/xxxxx.pack" */ char pack_name[GIT_FLEX_ARRAY]; /* more */ }; struct git_pack_entry { git_off_t offset; git_oid sha1; struct git_pack_file *p; }; typedef struct git_packfile_stream { git_off_t curpos; int done; z_stream zstream; struct git_pack_file *p; git_mwindow *mw; } git_packfile_stream; int git_packfile_unpack_header( size_t *size_p, git_otype *type_p, git_mwindow_file *mwf, git_mwindow **w_curs, git_off_t *curpos); int git_packfile_resolve_header( size_t *size_p, git_otype *type_p, struct git_pack_file *p, git_off_t offset); int git_packfile_unpack(git_rawobj *obj, struct git_pack_file *p, git_off_t *obj_offset); int packfile_unpack_compressed( git_rawobj *obj, struct git_pack_file *p, git_mwindow **w_curs, git_off_t *curpos, size_t size, git_otype type); int git_packfile_stream_open(git_packfile_stream *obj, struct git_pack_file *p, git_off_t curpos); ssize_t git_packfile_stream_read(git_packfile_stream *obj, void *buffer, size_t len); void git_packfile_stream_free(git_packfile_stream *obj); git_off_t get_delta_base(struct git_pack_file *p, git_mwindow **w_curs, git_off_t *curpos, git_otype type, git_off_t delta_obj_offset); void git_packfile_free(struct git_pack_file *p); int git_packfile_alloc(struct git_pack_file **pack_out, const char *path); int git_pack_entry_find( struct git_pack_entry *e, struct git_pack_file *p, const git_oid *short_oid, size_t len); int git_pack_foreach_entry( struct git_pack_file *p, git_odb_foreach_cb cb, void *data); #endif libgit2-0.19.0/src/path.c000066400000000000000000000456771216214232500150450ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #include "common.h" #include "path.h" #include "posix.h" #ifdef GIT_WIN32 #include "win32/dir.h" #include "win32/posix.h" #else #include #endif #include #include #include #define LOOKS_LIKE_DRIVE_PREFIX(S) (git__isalpha((S)[0]) && (S)[1] == ':') #ifdef GIT_WIN32 static bool looks_like_network_computer_name(const char *path, int pos) { if (pos < 3) return false; if (path[0] != '/' || path[1] != '/') return false; while (pos-- > 2) { if (path[pos] == '/') return false; } return true; } #endif /* * Based on the Android implementation, BSD licensed. * http://android.git.kernel.org/ * * Copyright (C) 2008 The Android Open Source Project * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * AS IS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ int git_path_basename_r(git_buf *buffer, const char *path) { const char *endp, *startp; int len, result; /* Empty or NULL string gets treated as "." */ if (path == NULL || *path == '\0') { startp = "."; len = 1; goto Exit; } /* Strip trailing slashes */ endp = path + strlen(path) - 1; while (endp > path && *endp == '/') endp--; /* All slashes becomes "/" */ if (endp == path && *endp == '/') { startp = "/"; len = 1; goto Exit; } /* Find the start of the base */ startp = endp; while (startp > path && *(startp - 1) != '/') startp--; /* Cast is safe because max path < max int */ len = (int)(endp - startp + 1); Exit: result = len; if (buffer != NULL && git_buf_set(buffer, startp, len) < 0) return -1; return result; } /* * Based on the Android implementation, BSD licensed. * Check http://android.git.kernel.org/ */ int git_path_dirname_r(git_buf *buffer, const char *path) { const char *endp; int result, len; /* Empty or NULL string gets treated as "." */ if (path == NULL || *path == '\0') { path = "."; len = 1; goto Exit; } /* Strip trailing slashes */ endp = path + strlen(path) - 1; while (endp > path && *endp == '/') endp--; /* Find the start of the dir */ while (endp > path && *endp != '/') endp--; /* Either the dir is "/" or there are no slashes */ if (endp == path) { path = (*endp == '/') ? "/" : "."; len = 1; goto Exit; } do { endp--; } while (endp > path && *endp == '/'); /* Cast is safe because max path < max int */ len = (int)(endp - path + 1); #ifdef GIT_WIN32 /* Mimic unix behavior where '/.git' returns '/': 'C:/.git' will return 'C:/' here */ if (len == 2 && LOOKS_LIKE_DRIVE_PREFIX(path)) { len = 3; goto Exit; } /* Similarly checks if we're dealing with a network computer name '//computername/.git' will return '//computername/' */ if (looks_like_network_computer_name(path, len)) { len++; goto Exit; } #endif Exit: result = len; if (buffer != NULL && git_buf_set(buffer, path, len) < 0) return -1; return result; } char *git_path_dirname(const char *path) { git_buf buf = GIT_BUF_INIT; char *dirname; git_path_dirname_r(&buf, path); dirname = git_buf_detach(&buf); git_buf_free(&buf); /* avoid memleak if error occurs */ return dirname; } char *git_path_basename(const char *path) { git_buf buf = GIT_BUF_INIT; char *basename; git_path_basename_r(&buf, path); basename = git_buf_detach(&buf); git_buf_free(&buf); /* avoid memleak if error occurs */ return basename; } size_t git_path_basename_offset(git_buf *buffer) { ssize_t slash; if (!buffer || buffer->size <= 0) return 0; slash = git_buf_rfind_next(buffer, '/'); if (slash >= 0 && buffer->ptr[slash] == '/') return (size_t)(slash + 1); return 0; } const char *git_path_topdir(const char *path) { size_t len; ssize_t i; assert(path); len = strlen(path); if (!len || path[len - 1] != '/') return NULL; for (i = (ssize_t)len - 2; i >= 0; --i) if (path[i] == '/') break; return &path[i + 1]; } int git_path_root(const char *path) { int offset = 0; /* Does the root of the path look like a windows drive ? */ if (LOOKS_LIKE_DRIVE_PREFIX(path)) offset += 2; #ifdef GIT_WIN32 /* Are we dealing with a windows network path? */ else if ((path[0] == '/' && path[1] == '/') || (path[0] == '\\' && path[1] == '\\')) { offset += 2; /* Skip the computer name segment */ while (path[offset] && path[offset] != '/' && path[offset] != '\\') offset++; } #endif if (path[offset] == '/' || path[offset] == '\\') return offset; return -1; /* Not a real error - signals that path is not rooted */ } int git_path_join_unrooted( git_buf *path_out, const char *path, const char *base, ssize_t *root_at) { int error, root; assert(path && path_out); root = git_path_root(path); if (base != NULL && root < 0) { error = git_buf_joinpath(path_out, base, path); if (root_at) *root_at = (ssize_t)strlen(base); } else { error = git_buf_sets(path_out, path); if (root_at) *root_at = (root < 0) ? 0 : (ssize_t)root; } return error; } int git_path_prettify(git_buf *path_out, const char *path, const char *base) { char buf[GIT_PATH_MAX]; assert(path && path_out); /* construct path if needed */ if (base != NULL && git_path_root(path) < 0) { if (git_buf_joinpath(path_out, base, path) < 0) return -1; path = path_out->ptr; } if (p_realpath(path, buf) == NULL) { /* giterr_set resets the errno when dealing with a GITERR_OS kind of error */ int error = (errno == ENOENT || errno == ENOTDIR) ? GIT_ENOTFOUND : -1; giterr_set(GITERR_OS, "Failed to resolve path '%s'", path); git_buf_clear(path_out); return error; } return git_buf_sets(path_out, buf); } int git_path_prettify_dir(git_buf *path_out, const char *path, const char *base) { int error = git_path_prettify(path_out, path, base); return (error < 0) ? error : git_path_to_dir(path_out); } int git_path_to_dir(git_buf *path) { if (path->asize > 0 && git_buf_len(path) > 0 && path->ptr[git_buf_len(path) - 1] != '/') git_buf_putc(path, '/'); return git_buf_oom(path) ? -1 : 0; } void git_path_string_to_dir(char* path, size_t size) { size_t end = strlen(path); if (end && path[end - 1] != '/' && end < size) { path[end] = '/'; path[end + 1] = '\0'; } } int git__percent_decode(git_buf *decoded_out, const char *input) { int len, hi, lo, i; assert(decoded_out && input); len = (int)strlen(input); git_buf_clear(decoded_out); for(i = 0; i < len; i++) { char c = input[i]; if (c != '%') goto append; if (i >= len - 2) goto append; hi = git__fromhex(input[i + 1]); lo = git__fromhex(input[i + 2]); if (hi < 0 || lo < 0) goto append; c = (char)(hi << 4 | lo); i += 2; append: if (git_buf_putc(decoded_out, c) < 0) return -1; } return 0; } static int error_invalid_local_file_uri(const char *uri) { giterr_set(GITERR_CONFIG, "'%s' is not a valid local file URI", uri); return -1; } int git_path_fromurl(git_buf *local_path_out, const char *file_url) { int offset = 0, len; assert(local_path_out && file_url); if (git__prefixcmp(file_url, "file://") != 0) return error_invalid_local_file_uri(file_url); offset += 7; len = (int)strlen(file_url); if (offset < len && file_url[offset] == '/') offset++; else if (offset < len && git__prefixcmp(file_url + offset, "localhost/") == 0) offset += 10; else return error_invalid_local_file_uri(file_url); if (offset >= len || file_url[offset] == '/') return error_invalid_local_file_uri(file_url); #ifndef GIT_WIN32 offset--; /* A *nix absolute path starts with a forward slash */ #endif git_buf_clear(local_path_out); return git__percent_decode(local_path_out, file_url + offset); } int git_path_walk_up( git_buf *path, const char *ceiling, int (*cb)(void *data, git_buf *), void *data) { int error = 0; git_buf iter; ssize_t stop = 0, scan; char oldc = '\0'; assert(path && cb); if (ceiling != NULL) { if (git__prefixcmp(path->ptr, ceiling) == 0) stop = (ssize_t)strlen(ceiling); else stop = git_buf_len(path); } scan = git_buf_len(path); iter.ptr = path->ptr; iter.size = git_buf_len(path); iter.asize = path->asize; while (scan >= stop) { error = cb(data, &iter); iter.ptr[scan] = oldc; if (error < 0) break; scan = git_buf_rfind_next(&iter, '/'); if (scan >= 0) { scan++; oldc = iter.ptr[scan]; iter.size = scan; iter.ptr[scan] = '\0'; } } if (scan >= 0) iter.ptr[scan] = oldc; return error; } bool git_path_exists(const char *path) { assert(path); return p_access(path, F_OK) == 0; } bool git_path_isdir(const char *path) { struct stat st; if (p_stat(path, &st) < 0) return false; return S_ISDIR(st.st_mode) != 0; } bool git_path_isfile(const char *path) { struct stat st; assert(path); if (p_stat(path, &st) < 0) return false; return S_ISREG(st.st_mode) != 0; } #ifdef GIT_WIN32 bool git_path_is_empty_dir(const char *path) { git_buf pathbuf = GIT_BUF_INIT; HANDLE hFind = INVALID_HANDLE_VALUE; wchar_t wbuf[GIT_WIN_PATH]; WIN32_FIND_DATAW ffd; bool retval = true; if (!git_path_isdir(path)) return false; git_buf_printf(&pathbuf, "%s\\*", path); git__utf8_to_16(wbuf, GIT_WIN_PATH, git_buf_cstr(&pathbuf)); hFind = FindFirstFileW(wbuf, &ffd); if (INVALID_HANDLE_VALUE == hFind) { giterr_set(GITERR_OS, "Couldn't open '%s'", path); return false; } do { if (!git_path_is_dot_or_dotdotW(ffd.cFileName)) { retval = false; } } while (FindNextFileW(hFind, &ffd) != 0); FindClose(hFind); git_buf_free(&pathbuf); return retval; } #else bool git_path_is_empty_dir(const char *path) { DIR *dir = NULL; struct dirent *e; bool retval = true; if (!git_path_isdir(path)) return false; dir = opendir(path); if (!dir) { giterr_set(GITERR_OS, "Couldn't open '%s'", path); return false; } while ((e = readdir(dir)) != NULL) { if (!git_path_is_dot_or_dotdot(e->d_name)) { giterr_set(GITERR_INVALID, "'%s' exists and is not an empty directory", path); retval = false; break; } } closedir(dir); return retval; } #endif int git_path_lstat(const char *path, struct stat *st) { int err = 0; if (p_lstat(path, st) < 0) { err = (errno == ENOENT) ? GIT_ENOTFOUND : -1; giterr_set(GITERR_OS, "Failed to stat file '%s'", path); } return err; } static bool _check_dir_contents( git_buf *dir, const char *sub, bool (*predicate)(const char *)) { bool result; size_t dir_size = git_buf_len(dir); size_t sub_size = strlen(sub); /* leave base valid even if we could not make space for subdir */ if (git_buf_try_grow(dir, dir_size + sub_size + 2, false) < 0) return false; /* save excursion */ git_buf_joinpath(dir, dir->ptr, sub); result = predicate(dir->ptr); /* restore path */ git_buf_truncate(dir, dir_size); return result; } bool git_path_contains(git_buf *dir, const char *item) { return _check_dir_contents(dir, item, &git_path_exists); } bool git_path_contains_dir(git_buf *base, const char *subdir) { return _check_dir_contents(base, subdir, &git_path_isdir); } bool git_path_contains_file(git_buf *base, const char *file) { return _check_dir_contents(base, file, &git_path_isfile); } int git_path_find_dir(git_buf *dir, const char *path, const char *base) { int error = git_path_join_unrooted(dir, path, base, NULL); if (!error) { char buf[GIT_PATH_MAX]; if (p_realpath(dir->ptr, buf) != NULL) error = git_buf_sets(dir, buf); } /* call dirname if this is not a directory */ if (!error && git_path_isdir(dir->ptr) == false) error = git_path_dirname_r(dir, dir->ptr); if (!error) error = git_path_to_dir(dir); return error; } int git_path_resolve_relative(git_buf *path, size_t ceiling) { char *base, *to, *from, *next; size_t len; if (!path || git_buf_oom(path)) return -1; if (ceiling > path->size) ceiling = path->size; /* recognize drive prefixes, etc. that should not be backed over */ if (ceiling == 0) ceiling = git_path_root(path->ptr) + 1; /* recognize URL prefixes that should not be backed over */ if (ceiling == 0) { for (next = path->ptr; *next && git__isalpha(*next); ++next); if (next[0] == ':' && next[1] == '/' && next[2] == '/') ceiling = (next + 3) - path->ptr; } base = to = from = path->ptr + ceiling; while (*from) { for (next = from; *next && *next != '/'; ++next); len = next - from; if (len == 1 && from[0] == '.') /* do nothing with singleton dot */; else if (len == 2 && from[0] == '.' && from[1] == '.') { while (to > base && to[-1] == '/') to--; while (to > base && to[-1] != '/') to--; } else { if (*next == '/') len++; if (to != from) memmove(to, from, len); to += len; } from += len; while (*from == '/') from++; } *to = '\0'; path->size = to - path->ptr; return 0; } int git_path_apply_relative(git_buf *target, const char *relpath) { git_buf_joinpath(target, git_buf_cstr(target), relpath); return git_path_resolve_relative(target, 0); } int git_path_cmp( const char *name1, size_t len1, int isdir1, const char *name2, size_t len2, int isdir2, int (*compare)(const char *, const char *, size_t)) { unsigned char c1, c2; size_t len = len1 < len2 ? len1 : len2; int cmp; cmp = compare(name1, name2, len); if (cmp) return cmp; c1 = name1[len]; c2 = name2[len]; if (c1 == '\0' && isdir1) c1 = '/'; if (c2 == '\0' && isdir2) c2 = '/'; return (c1 < c2) ? -1 : (c1 > c2) ? 1 : 0; } int git_path_direach( git_buf *path, int (*fn)(void *, git_buf *), void *arg) { ssize_t wd_len; DIR *dir; struct dirent *de, *de_buf; if (git_path_to_dir(path) < 0) return -1; wd_len = git_buf_len(path); if ((dir = opendir(path->ptr)) == NULL) { giterr_set(GITERR_OS, "Failed to open directory '%s'", path->ptr); return -1; } #if defined(__sun) || defined(__GNU__) de_buf = git__malloc(sizeof(struct dirent) + FILENAME_MAX + 1); #else de_buf = git__malloc(sizeof(struct dirent)); #endif while (p_readdir_r(dir, de_buf, &de) == 0 && de != NULL) { int result; if (git_path_is_dot_or_dotdot(de->d_name)) continue; if (git_buf_puts(path, de->d_name) < 0) { closedir(dir); git__free(de_buf); return -1; } result = fn(arg, path); git_buf_truncate(path, wd_len); /* restore path */ if (result < 0) { closedir(dir); git__free(de_buf); return -1; } } closedir(dir); git__free(de_buf); return 0; } int git_path_dirload( const char *path, size_t prefix_len, size_t alloc_extra, git_vector *contents) { int error, need_slash; DIR *dir; struct dirent *de, *de_buf; size_t path_len; assert(path != NULL && contents != NULL); path_len = strlen(path); assert(path_len > 0 && path_len >= prefix_len); if ((dir = opendir(path)) == NULL) { giterr_set(GITERR_OS, "Failed to open directory '%s'", path); return -1; } #if defined(__sun) || defined(__GNU__) de_buf = git__malloc(sizeof(struct dirent) + FILENAME_MAX + 1); #else de_buf = git__malloc(sizeof(struct dirent)); #endif path += prefix_len; path_len -= prefix_len; need_slash = (path_len > 0 && path[path_len-1] != '/') ? 1 : 0; while ((error = p_readdir_r(dir, de_buf, &de)) == 0 && de != NULL) { char *entry_path; size_t entry_len; if (git_path_is_dot_or_dotdot(de->d_name)) continue; entry_len = strlen(de->d_name); entry_path = git__malloc( path_len + need_slash + entry_len + 1 + alloc_extra); GITERR_CHECK_ALLOC(entry_path); if (path_len) memcpy(entry_path, path, path_len); if (need_slash) entry_path[path_len] = '/'; memcpy(&entry_path[path_len + need_slash], de->d_name, entry_len); entry_path[path_len + need_slash + entry_len] = '\0'; if (git_vector_insert(contents, entry_path) < 0) { closedir(dir); git__free(de_buf); return -1; } } closedir(dir); git__free(de_buf); if (error != 0) giterr_set(GITERR_OS, "Failed to process directory entry in '%s'", path); return error; } int git_path_with_stat_cmp(const void *a, const void *b) { const git_path_with_stat *psa = a, *psb = b; return strcmp(psa->path, psb->path); } int git_path_with_stat_cmp_icase(const void *a, const void *b) { const git_path_with_stat *psa = a, *psb = b; return strcasecmp(psa->path, psb->path); } int git_path_dirload_with_stat( const char *path, size_t prefix_len, bool ignore_case, const char *start_stat, const char *end_stat, git_vector *contents) { int error; unsigned int i; git_path_with_stat *ps; git_buf full = GIT_BUF_INIT; int (*strncomp)(const char *a, const char *b, size_t sz); size_t start_len = start_stat ? strlen(start_stat) : 0; size_t end_len = end_stat ? strlen(end_stat) : 0, cmp_len; if (git_buf_set(&full, path, prefix_len) < 0) return -1; error = git_path_dirload( path, prefix_len, sizeof(git_path_with_stat) + 1, contents); if (error < 0) { git_buf_free(&full); return error; } strncomp = ignore_case ? git__strncasecmp : git__strncmp; /* stat struct at start of git_path_with_stat, so shift path text */ git_vector_foreach(contents, i, ps) { size_t path_len = strlen((char *)ps); memmove(ps->path, ps, path_len + 1); ps->path_len = path_len; } git_vector_foreach(contents, i, ps) { /* skip if before start_stat or after end_stat */ cmp_len = min(start_len, ps->path_len); if (cmp_len && strncomp(ps->path, start_stat, cmp_len) < 0) continue; cmp_len = min(end_len, ps->path_len); if (cmp_len && strncomp(ps->path, end_stat, cmp_len) > 0) continue; git_buf_truncate(&full, prefix_len); if ((error = git_buf_joinpath(&full, full.ptr, ps->path)) < 0 || (error = git_path_lstat(full.ptr, &ps->st)) < 0) break; if (S_ISDIR(ps->st.st_mode)) { if ((error = git_buf_joinpath(&full, full.ptr, ".git")) < 0) break; if (p_access(full.ptr, F_OK) == 0) { ps->st.st_mode = GIT_FILEMODE_COMMIT; } else { ps->path[ps->path_len++] = '/'; ps->path[ps->path_len] = '\0'; } } } /* sort now that directory suffix is added */ git_vector_sort(contents); git_buf_free(&full); return error; } libgit2-0.19.0/src/path.h000066400000000000000000000266501216214232500150400ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #ifndef INCLUDE_path_h__ #define INCLUDE_path_h__ #include "common.h" #include "buffer.h" #include "vector.h" /** * Path manipulation utils * * These are path utilities that munge paths without actually * looking at the real filesystem. */ /* * The dirname() function shall take a pointer to a character string * that contains a pathname, and return a pointer to a string that is a * pathname of the parent directory of that file. Trailing '/' characters * in the path are not counted as part of the path. * * If path does not contain a '/', then dirname() shall return a pointer to * the string ".". If path is a null pointer or points to an empty string, * dirname() shall return a pointer to the string "." . * * The `git_path_dirname` implementation is thread safe. The returned * string must be manually free'd. * * The `git_path_dirname_r` implementation writes the dirname to a `git_buf` * if the buffer pointer is not NULL. * It returns an error code < 0 if there is an allocation error, otherwise * the length of the dirname (which will be > 0). */ extern char *git_path_dirname(const char *path); extern int git_path_dirname_r(git_buf *buffer, const char *path); /* * This function returns the basename of the file, which is the last * part of its full name given by fname, with the drive letter and * leading directories stripped off. For example, the basename of * c:/foo/bar/file.ext is file.ext, and the basename of a:foo is foo. * * Trailing slashes and backslashes are significant: the basename of * c:/foo/bar/ is an empty string after the rightmost slash. * * The `git_path_basename` implementation is thread safe. The returned * string must be manually free'd. * * The `git_path_basename_r` implementation writes the basename to a `git_buf`. * It returns an error code < 0 if there is an allocation error, otherwise * the length of the basename (which will be >= 0). */ extern char *git_path_basename(const char *path); extern int git_path_basename_r(git_buf *buffer, const char *path); /* Return the offset of the start of the basename. Unlike the other * basename functions, this returns 0 if the path is empty. */ extern size_t git_path_basename_offset(git_buf *buffer); extern const char *git_path_topdir(const char *path); /** * Find offset to root of path if path has one. * * This will return a number >= 0 which is the offset to the start of the * path, if the path is rooted (i.e. "/rooted/path" returns 0 and * "c:/windows/rooted/path" returns 2). If the path is not rooted, this * returns < 0. */ extern int git_path_root(const char *path); /** * Ensure path has a trailing '/'. */ extern int git_path_to_dir(git_buf *path); /** * Ensure string has a trailing '/' if there is space for it. */ extern void git_path_string_to_dir(char* path, size_t size); /** * Taken from git.git; returns nonzero if the given path is "." or "..". */ GIT_INLINE(int) git_path_is_dot_or_dotdot(const char *name) { return (name[0] == '.' && (name[1] == '\0' || (name[1] == '.' && name[2] == '\0'))); } #ifdef GIT_WIN32 GIT_INLINE(int) git_path_is_dot_or_dotdotW(const wchar_t *name) { return (name[0] == L'.' && (name[1] == L'\0' || (name[1] == L'.' && name[2] == L'\0'))); } /** * Convert backslashes in path to forward slashes. */ GIT_INLINE(void) git_path_mkposix(char *path) { while (*path) { if (*path == '\\') *path = '/'; path++; } } #else # define git_path_mkposix(p) /* blank */ #endif extern int git__percent_decode(git_buf *decoded_out, const char *input); /** * Extract path from file:// URL. */ extern int git_path_fromurl(git_buf *local_path_out, const char *file_url); /** * Path filesystem utils * * These are path utilities that actually access the filesystem. */ /** * Check if a file exists and can be accessed. * @return true or false */ extern bool git_path_exists(const char *path); /** * Check if the given path points to a directory. * @return true or false */ extern bool git_path_isdir(const char *path); /** * Check if the given path points to a regular file. * @return true or false */ extern bool git_path_isfile(const char *path); /** * Check if the given path is a directory, and is empty. */ extern bool git_path_is_empty_dir(const char *path); /** * Stat a file and/or link and set error if needed. */ extern int git_path_lstat(const char *path, struct stat *st); /** * Check if the parent directory contains the item. * * @param dir Directory to check. * @param item Item that might be in the directory. * @return 0 if item exists in directory, <0 otherwise. */ extern bool git_path_contains(git_buf *dir, const char *item); /** * Check if the given path contains the given subdirectory. * * @param parent Directory path that might contain subdir * @param subdir Subdirectory name to look for in parent * @param append_if_exists If true, then subdir will be appended to the parent path if it does exist * @return true if subdirectory exists, false otherwise. */ extern bool git_path_contains_dir(git_buf *parent, const char *subdir); /** * Check if the given path contains the given file. * * @param dir Directory path that might contain file * @param file File name to look for in parent * @param append_if_exists If true, then file will be appended to the path if it does exist * @return true if file exists, false otherwise. */ extern bool git_path_contains_file(git_buf *dir, const char *file); /** * Prepend base to unrooted path or just copy path over. * * This will optionally return the index into the path where the "root" * is, either the end of the base directory prefix or the path root. */ extern int git_path_join_unrooted( git_buf *path_out, const char *path, const char *base, ssize_t *root_at); /** * Clean up path, prepending base if it is not already rooted. */ extern int git_path_prettify(git_buf *path_out, const char *path, const char *base); /** * Clean up path, prepending base if it is not already rooted and * appending a slash. */ extern int git_path_prettify_dir(git_buf *path_out, const char *path, const char *base); /** * Get a directory from a path. * * If path is a directory, this acts like `git_path_prettify_dir` * (cleaning up path and appending a '/'). If path is a normal file, * this prettifies it, then removed the filename a la dirname and * appends the trailing '/'. If the path does not exist, it is * treated like a regular filename. */ extern int git_path_find_dir(git_buf *dir, const char *path, const char *base); /** * Resolve relative references within a path. * * This eliminates "./" and "../" relative references inside a path, * as well as condensing multiple slashes into single ones. It will * not touch the path before the "ceiling" length. * * Additionally, this will recognize an "c:/" drive prefix or a "xyz://" URL * prefix and not touch that part of the path. */ extern int git_path_resolve_relative(git_buf *path, size_t ceiling); /** * Apply a relative path to base path. * * Note that the base path could be a filename or a URL and this * should still work. The relative path is walked segment by segment * with three rules: series of slashes will be condensed to a single * slash, "." will be eaten with no change, and ".." will remove a * segment from the base path. */ extern int git_path_apply_relative(git_buf *target, const char *relpath); /** * Walk each directory entry, except '.' and '..', calling fn(state). * * @param pathbuf buffer the function reads the initial directory * path from, and updates with each successive entry's name. * @param fn function to invoke with each entry. The first arg is * the input state and the second arg is pathbuf. The function * may modify the pathbuf, but only by appending new text. * @param state to pass to fn as the first arg. * @return 0 on success, GIT_EUSER on non-zero callback, or error code */ extern int git_path_direach( git_buf *pathbuf, int (*fn)(void *, git_buf *), void *state); /** * Sort function to order two paths */ extern int git_path_cmp( const char *name1, size_t len1, int isdir1, const char *name2, size_t len2, int isdir2, int (*compare)(const char *, const char *, size_t)); /** * Invoke callback up path directory by directory until the ceiling is * reached (inclusive of a final call at the root_path). * * Returning anything other than 0 from the callback function * will stop the iteration and propogate the error to the caller. * * @param pathbuf Buffer the function reads the directory from and * and updates with each successive name. * @param ceiling Prefix of path at which to stop walking up. If NULL, * this will walk all the way up to the root. If not a prefix of * pathbuf, the callback will be invoked a single time on the * original input path. * @param fn Function to invoke on each path. The first arg is the * input satte and the second arg is the pathbuf. The function * should not modify the pathbuf. * @param state Passed to fn as the first ath. */ extern int git_path_walk_up( git_buf *pathbuf, const char *ceiling, int (*fn)(void *state, git_buf *), void *state); /** * Load all directory entries (except '.' and '..') into a vector. * * For cases where `git_path_direach()` is not appropriate, this * allows you to load the filenames in a directory into a vector * of strings. That vector can then be sorted, iterated, or whatever. * Remember to free alloc of the allocated strings when you are done. * * @param path The directory to read from. * @param prefix_len When inserting entries, the trailing part of path * will be prefixed after this length. I.e. given path "/a/b" and * prefix_len 3, the entries will look like "b/e1", "b/e2", etc. * @param alloc_extra Extra bytes to add to each string allocation in * case you want to append anything funny. * @param contents Vector to fill with directory entry names. */ extern int git_path_dirload( const char *path, size_t prefix_len, size_t alloc_extra, git_vector *contents); typedef struct { struct stat st; size_t path_len; char path[GIT_FLEX_ARRAY]; } git_path_with_stat; extern int git_path_with_stat_cmp(const void *a, const void *b); extern int git_path_with_stat_cmp_icase(const void *a, const void *b); /** * Load all directory entries along with stat info into a vector. * * This adds four things on top of plain `git_path_dirload`: * * 1. Each entry in the vector is a `git_path_with_stat` struct that * contains both the path and the stat info * 2. The entries will be sorted alphabetically * 3. Entries that are directories will be suffixed with a '/' * 4. Optionally, you can be a start and end prefix and only elements * after the start and before the end (inclusively) will be stat'ed. * * @param path The directory to read from * @param prefix_len The trailing part of path to prefix to entry paths * @param ignore_case How to sort and compare paths with start/end limits * @param start_stat As optimization, only stat values after this prefix * @param end_stat As optimization, only stat values before this prefix * @param contents Vector to fill with git_path_with_stat structures */ extern int git_path_dirload_with_stat( const char *path, size_t prefix_len, bool ignore_case, const char *start_stat, const char *end_stat, git_vector *contents); #endif libgit2-0.19.0/src/pathspec.c000066400000000000000000000104121216214232500156730ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #include "pathspec.h" #include "buf_text.h" #include "attr_file.h" /* what is the common non-wildcard prefix for all items in the pathspec */ char *git_pathspec_prefix(const git_strarray *pathspec) { git_buf prefix = GIT_BUF_INIT; const char *scan; if (!pathspec || !pathspec->count || git_buf_text_common_prefix(&prefix, pathspec) < 0) return NULL; /* diff prefix will only be leading non-wildcards */ for (scan = prefix.ptr; *scan; ++scan) { if (git__iswildcard(*scan) && (scan == prefix.ptr || (*(scan - 1) != '\\'))) break; } git_buf_truncate(&prefix, scan - prefix.ptr); if (prefix.size <= 0) { git_buf_free(&prefix); return NULL; } git_buf_text_unescape(&prefix); return git_buf_detach(&prefix); } /* is there anything in the spec that needs to be filtered on */ bool git_pathspec_is_empty(const git_strarray *pathspec) { size_t i; if (pathspec == NULL) return true; for (i = 0; i < pathspec->count; ++i) { const char *str = pathspec->strings[i]; if (str && str[0]) return false; } return true; } /* build a vector of fnmatch patterns to evaluate efficiently */ int git_pathspec_init( git_vector *vspec, const git_strarray *strspec, git_pool *strpool) { size_t i; memset(vspec, 0, sizeof(*vspec)); if (git_pathspec_is_empty(strspec)) return 0; if (git_vector_init(vspec, strspec->count, NULL) < 0) return -1; for (i = 0; i < strspec->count; ++i) { int ret; const char *pattern = strspec->strings[i]; git_attr_fnmatch *match = git__calloc(1, sizeof(git_attr_fnmatch)); if (!match) return -1; match->flags = GIT_ATTR_FNMATCH_ALLOWSPACE; ret = git_attr_fnmatch__parse(match, strpool, NULL, &pattern); if (ret == GIT_ENOTFOUND) { git__free(match); continue; } else if (ret < 0) return ret; if (git_vector_insert(vspec, match) < 0) return -1; } return 0; } /* free data from the pathspec vector */ void git_pathspec_free(git_vector *vspec) { git_attr_fnmatch *match; unsigned int i; git_vector_foreach(vspec, i, match) { git__free(match); vspec->contents[i] = NULL; } git_vector_free(vspec); } /* match a path against the vectorized pathspec */ bool git_pathspec_match_path( git_vector *vspec, const char *path, bool disable_fnmatch, bool casefold, const char **matched_pathspec) { size_t i; git_attr_fnmatch *match; int fnmatch_flags = 0; int (*use_strcmp)(const char *, const char *); int (*use_strncmp)(const char *, const char *, size_t); if (matched_pathspec) *matched_pathspec = NULL; if (!vspec || !vspec->length) return true; if (disable_fnmatch) fnmatch_flags = -1; else if (casefold) fnmatch_flags = FNM_CASEFOLD; if (casefold) { use_strcmp = git__strcasecmp; use_strncmp = git__strncasecmp; } else { use_strcmp = git__strcmp; use_strncmp = git__strncmp; } git_vector_foreach(vspec, i, match) { int result = (match->flags & GIT_ATTR_FNMATCH_MATCH_ALL) ? 0 : FNM_NOMATCH; if (result == FNM_NOMATCH) result = use_strcmp(match->pattern, path) ? FNM_NOMATCH : 0; if (fnmatch_flags >= 0 && result == FNM_NOMATCH) result = p_fnmatch(match->pattern, path, fnmatch_flags); /* if we didn't match, look for exact dirname prefix match */ if (result == FNM_NOMATCH && (match->flags & GIT_ATTR_FNMATCH_HASWILD) == 0 && use_strncmp(path, match->pattern, match->length) == 0 && path[match->length] == '/') result = 0; if (result == 0) { if (matched_pathspec) *matched_pathspec = match->pattern; return (match->flags & GIT_ATTR_FNMATCH_NEGATIVE) ? false : true; } } return false; } int git_pathspec_context_init( git_pathspec_context *ctxt, const git_strarray *paths) { int error = 0; memset(ctxt, 0, sizeof(*ctxt)); ctxt->prefix = git_pathspec_prefix(paths); if ((error = git_pool_init(&ctxt->pool, 1, 0)) < 0 || (error = git_pathspec_init(&ctxt->pathspec, paths, &ctxt->pool)) < 0) git_pathspec_context_free(ctxt); return error; } void git_pathspec_context_free( git_pathspec_context *ctxt) { git__free(ctxt->prefix); git_pathspec_free(&ctxt->pathspec); git_pool_clear(&ctxt->pool); memset(ctxt, 0, sizeof(*ctxt)); } libgit2-0.19.0/src/pathspec.h000066400000000000000000000027411216214232500157060ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #ifndef INCLUDE_pathspec_h__ #define INCLUDE_pathspec_h__ #include "common.h" #include "buffer.h" #include "vector.h" #include "pool.h" /* what is the common non-wildcard prefix for all items in the pathspec */ extern char *git_pathspec_prefix(const git_strarray *pathspec); /* is there anything in the spec that needs to be filtered on */ extern bool git_pathspec_is_empty(const git_strarray *pathspec); /* build a vector of fnmatch patterns to evaluate efficiently */ extern int git_pathspec_init( git_vector *vspec, const git_strarray *strspec, git_pool *strpool); /* free data from the pathspec vector */ extern void git_pathspec_free(git_vector *vspec); /* * Match a path against the vectorized pathspec. * The matched pathspec is passed back into the `matched_pathspec` parameter, * unless it is passed as NULL by the caller. */ extern bool git_pathspec_match_path( git_vector *vspec, const char *path, bool disable_fnmatch, bool casefold, const char **matched_pathspec); /* easy pathspec setup */ typedef struct { char *prefix; git_vector pathspec; git_pool pool; } git_pathspec_context; extern int git_pathspec_context_init( git_pathspec_context *ctxt, const git_strarray *paths); extern void git_pathspec_context_free( git_pathspec_context *ctxt); #endif libgit2-0.19.0/src/pool.c000066400000000000000000000162741216214232500150510ustar00rootroot00000000000000#include "pool.h" #ifndef GIT_WIN32 #include #endif struct git_pool_page { git_pool_page *next; uint32_t size; uint32_t avail; char data[GIT_FLEX_ARRAY]; }; struct pool_freelist { struct pool_freelist *next; }; #define GIT_POOL_MIN_USABLE 4 #define GIT_POOL_MIN_PAGESZ 2 * sizeof(void*) static void *pool_alloc_page(git_pool *pool, uint32_t size); static void pool_insert_page(git_pool *pool, git_pool_page *page); int git_pool_init( git_pool *pool, uint32_t item_size, uint32_t items_per_page) { assert(pool); if (!item_size) item_size = 1; /* round up item_size for decent object alignment */ if (item_size > 4) item_size = (item_size + 7) & ~7; else if (item_size == 3) item_size = 4; if (!items_per_page) items_per_page = git_pool__suggest_items_per_page(item_size); if (item_size * items_per_page < GIT_POOL_MIN_PAGESZ) items_per_page = (GIT_POOL_MIN_PAGESZ + item_size - 1) / item_size; memset(pool, 0, sizeof(git_pool)); pool->item_size = item_size; pool->page_size = item_size * items_per_page; return 0; } void git_pool_clear(git_pool *pool) { git_pool_page *scan, *next; for (scan = pool->open; scan != NULL; scan = next) { next = scan->next; git__free(scan); } pool->open = NULL; for (scan = pool->full; scan != NULL; scan = next) { next = scan->next; git__free(scan); } pool->full = NULL; pool->free_list = NULL; pool->items = 0; pool->has_string_alloc = 0; pool->has_multi_item_alloc = 0; pool->has_large_page_alloc = 0; } void git_pool_swap(git_pool *a, git_pool *b) { git_pool temp; if (a == b) return; memcpy(&temp, a, sizeof(temp)); memcpy(a, b, sizeof(temp)); memcpy(b, &temp, sizeof(temp)); } static void pool_insert_page(git_pool *pool, git_pool_page *page) { git_pool_page *scan; /* If there are no open pages or this page has the most open space, * insert it at the beginning of the list. This is the common case. */ if (pool->open == NULL || pool->open->avail < page->avail) { page->next = pool->open; pool->open = page; return; } /* Otherwise insert into sorted position. */ for (scan = pool->open; scan->next && scan->next->avail > page->avail; scan = scan->next); page->next = scan->next; scan->next = page; } static void *pool_alloc_page(git_pool *pool, uint32_t size) { git_pool_page *page; uint32_t alloc_size; if (size <= pool->page_size) alloc_size = pool->page_size; else { alloc_size = size; pool->has_large_page_alloc = 1; } page = git__calloc(1, alloc_size + sizeof(git_pool_page)); if (!page) return NULL; page->size = alloc_size; page->avail = alloc_size - size; if (page->avail > 0) pool_insert_page(pool, page); else { page->next = pool->full; pool->full = page; } pool->items++; return page->data; } GIT_INLINE(void) pool_remove_page( git_pool *pool, git_pool_page *page, git_pool_page *prev) { if (prev == NULL) pool->open = page->next; else prev->next = page->next; } void *git_pool_malloc(git_pool *pool, uint32_t items) { git_pool_page *scan = pool->open, *prev; uint32_t size = items * pool->item_size; void *ptr = NULL; pool->has_string_alloc = 0; if (items > 1) pool->has_multi_item_alloc = 1; else if (pool->free_list != NULL) { ptr = pool->free_list; pool->free_list = ((struct pool_freelist *)pool->free_list)->next; return ptr; } /* just add a block if there is no open one to accomodate this */ if (size >= pool->page_size || !scan || scan->avail < size) return pool_alloc_page(pool, size); pool->items++; /* find smallest block in free list with space */ for (scan = pool->open, prev = NULL; scan->next && scan->next->avail >= size; prev = scan, scan = scan->next); /* allocate space from the block */ ptr = &scan->data[scan->size - scan->avail]; scan->avail -= size; /* move to full list if there is almost no space left */ if (scan->avail < pool->item_size || scan->avail < GIT_POOL_MIN_USABLE) { pool_remove_page(pool, scan, prev); scan->next = pool->full; pool->full = scan; } /* reorder list if block is now smaller than the one after it */ else if (scan->next != NULL && scan->next->avail > scan->avail) { pool_remove_page(pool, scan, prev); pool_insert_page(pool, scan); } return ptr; } char *git_pool_strndup(git_pool *pool, const char *str, size_t n) { void *ptr = NULL; assert(pool && str && pool->item_size == sizeof(char)); if (n + 1 == 0) { giterr_set_oom(); return NULL; } if ((ptr = git_pool_malloc(pool, (uint32_t)(n + 1))) != NULL) { memcpy(ptr, str, n); *(((char *)ptr) + n) = '\0'; } pool->has_string_alloc = 1; return ptr; } char *git_pool_strdup(git_pool *pool, const char *str) { assert(pool && str && pool->item_size == sizeof(char)); return git_pool_strndup(pool, str, strlen(str)); } char *git_pool_strdup_safe(git_pool *pool, const char *str) { return str ? git_pool_strdup(pool, str) : NULL; } char *git_pool_strcat(git_pool *pool, const char *a, const char *b) { void *ptr; size_t len_a, len_b; assert(pool && a && b && pool->item_size == sizeof(char)); len_a = a ? strlen(a) : 0; len_b = b ? strlen(b) : 0; if ((ptr = git_pool_malloc(pool, (uint32_t)(len_a + len_b + 1))) != NULL) { if (len_a) memcpy(ptr, a, len_a); if (len_b) memcpy(((char *)ptr) + len_a, b, len_b); *(((char *)ptr) + len_a + len_b) = '\0'; } pool->has_string_alloc = 1; return ptr; } void git_pool_free(git_pool *pool, void *ptr) { struct pool_freelist *item = ptr; assert(pool && pool->item_size >= sizeof(void*)); if (item) { item->next = pool->free_list; pool->free_list = item; } } void git_pool_free_array(git_pool *pool, size_t count, void **ptrs) { struct pool_freelist **items = (struct pool_freelist **)ptrs; size_t i; assert(pool && ptrs && pool->item_size >= sizeof(void*)); if (!count) return; for (i = count - 1; i > 0; --i) items[i]->next = items[i - 1]; items[i]->next = pool->free_list; pool->free_list = items[count - 1]; } uint32_t git_pool__open_pages(git_pool *pool) { uint32_t ct = 0; git_pool_page *scan; for (scan = pool->open; scan != NULL; scan = scan->next) ct++; return ct; } uint32_t git_pool__full_pages(git_pool *pool) { uint32_t ct = 0; git_pool_page *scan; for (scan = pool->full; scan != NULL; scan = scan->next) ct++; return ct; } bool git_pool__ptr_in_pool(git_pool *pool, void *ptr) { git_pool_page *scan; for (scan = pool->open; scan != NULL; scan = scan->next) if ((void *)scan->data <= ptr && (void *)(((char *)scan->data) + scan->size) > ptr) return true; for (scan = pool->full; scan != NULL; scan = scan->next) if ((void *)scan->data <= ptr && (void *)(((char *)scan->data) + scan->size) > ptr) return true; return false; } uint32_t git_pool__system_page_size(void) { static uint32_t size = 0; if (!size) { #ifdef GIT_WIN32 SYSTEM_INFO info; GetSystemInfo(&info); size = (uint32_t)info.dwPageSize; #elif defined(__amigaos4__) size = (uint32_t)4096; /* 4K as there is no global value we can query */ #else size = (uint32_t)sysconf(_SC_PAGE_SIZE); #endif size -= 2 * sizeof(void *); /* allow space for malloc overhead */ } return size; } uint32_t git_pool__suggest_items_per_page(uint32_t item_size) { uint32_t page_bytes = git_pool__system_page_size() - sizeof(git_pool_page); return page_bytes / item_size; } libgit2-0.19.0/src/pool.h000066400000000000000000000105001216214232500150400ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #ifndef INCLUDE_pool_h__ #define INCLUDE_pool_h__ #include "common.h" typedef struct git_pool_page git_pool_page; /** * Chunked allocator. * * A `git_pool` can be used when you want to cheaply allocate * multiple items of the same type and are willing to free them * all together with a single call. The two most common cases * are a set of fixed size items (such as lots of OIDs) or a * bunch of strings. * * Internally, a `git_pool` allocates pages of memory and then * deals out blocks from the trailing unused portion of each page. * The pages guarantee that the number of actual allocations done * will be much smaller than the number of items needed. * * For examples of how to set up a `git_pool` see `git_pool_init`. */ typedef struct { git_pool_page *open; /* pages with space left */ git_pool_page *full; /* pages with no space left */ void *free_list; /* optional: list of freed blocks */ uint32_t item_size; /* size of single alloc unit in bytes */ uint32_t page_size; /* size of page in bytes */ uint32_t items; unsigned has_string_alloc : 1; /* was the strdup function used */ unsigned has_multi_item_alloc : 1; /* was items ever > 1 in malloc */ unsigned has_large_page_alloc : 1; /* are any pages > page_size */ } git_pool; #define GIT_POOL_INIT_STRINGPOOL { 0, 0, 0, 1, 4000, 0, 0, 0, 0 } /** * Initialize a pool. * * To allocation strings, use like this: * * git_pool_init(&string_pool, 1, 0); * my_string = git_pool_strdup(&string_pool, your_string); * * To allocate items of fixed size, use like this: * * git_pool_init(&pool, sizeof(item), 0); * my_item = git_pool_malloc(&pool, 1); * * Of course, you can use this in other ways, but those are the * two most common patterns. */ extern int git_pool_init( git_pool *pool, uint32_t item_size, uint32_t items_per_page); /** * Free all items in pool */ extern void git_pool_clear(git_pool *pool); /** * Swap two pools with one another */ extern void git_pool_swap(git_pool *a, git_pool *b); /** * Allocate space for one or more items from a pool. */ extern void *git_pool_malloc(git_pool *pool, uint32_t items); /** * Allocate space and zero it out. */ GIT_INLINE(void *) git_pool_mallocz(git_pool *pool, uint32_t items) { void *ptr = git_pool_malloc(pool, items); if (ptr) memset(ptr, 0, (size_t)items * (size_t)pool->item_size); return ptr; } /** * Allocate space and duplicate string data into it. * * This is allowed only for pools with item_size == sizeof(char) */ extern char *git_pool_strndup(git_pool *pool, const char *str, size_t n); /** * Allocate space and duplicate a string into it. * * This is allowed only for pools with item_size == sizeof(char) */ extern char *git_pool_strdup(git_pool *pool, const char *str); /** * Allocate space and duplicate a string into it, NULL is no error. * * This is allowed only for pools with item_size == sizeof(char) */ extern char *git_pool_strdup_safe(git_pool *pool, const char *str); /** * Allocate space for the concatenation of two strings. * * This is allowed only for pools with item_size == sizeof(char) */ extern char *git_pool_strcat(git_pool *pool, const char *a, const char *b); /** * Push a block back onto the free list for the pool. * * This is allowed only if the item_size is >= sizeof(void*). * * In some cases, it is helpful to "release" an allocated block * for reuse. Pools don't support a general purpose free, but * they will keep a simple free blocks linked list provided the * native block size is large enough to hold a void pointer */ extern void git_pool_free(git_pool *pool, void *ptr); /** * Push an array of pool allocated blocks efficiently onto the free list. * * This has the same constraints as `git_pool_free()` above. */ extern void git_pool_free_array(git_pool *pool, size_t count, void **ptrs); /* * Misc utilities */ extern uint32_t git_pool__open_pages(git_pool *pool); extern uint32_t git_pool__full_pages(git_pool *pool); extern bool git_pool__ptr_in_pool(git_pool *pool, void *ptr); extern uint32_t git_pool__system_page_size(void); extern uint32_t git_pool__suggest_items_per_page(uint32_t item_size); #endif libgit2-0.19.0/src/posix.c000066400000000000000000000074341216214232500152400ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #include "common.h" #include "posix.h" #include "path.h" #include #include #ifndef GIT_WIN32 #ifdef NO_ADDRINFO int p_getaddrinfo( const char *host, const char *port, struct addrinfo *hints, struct addrinfo **info) { struct addrinfo *ainfo, *ai; int p = 0; GIT_UNUSED(hints); if ((ainfo = malloc(sizeof(struct addrinfo))) == NULL) return -1; if ((ainfo->ai_hostent = gethostbyname(host)) == NULL) { free(ainfo); return -2; } ainfo->ai_servent = getservbyname(port, 0); if (ainfo->ai_servent) ainfo->ai_port = ainfo->ai_servent->s_port; else ainfo->ai_port = atol(port); memcpy(&ainfo->ai_addr_in.sin_addr, ainfo->ai_hostent->h_addr_list[0], ainfo->ai_hostent->h_length); ainfo->ai_protocol = 0; ainfo->ai_socktype = hints->ai_socktype; ainfo->ai_family = ainfo->ai_hostent->h_addrtype; ainfo->ai_addr_in.sin_family = ainfo->ai_family; ainfo->ai_addr_in.sin_port = ainfo->ai_port; ainfo->ai_addr = (struct addrinfo *)&ainfo->ai_addr_in; ainfo->ai_addrlen = sizeof(struct sockaddr_in); *info = ainfo; if (ainfo->ai_hostent->h_addr_list[1] == NULL) { ainfo->ai_next = NULL; return 0; } ai = ainfo; for (p = 1; ainfo->ai_hostent->h_addr_list[p] != NULL; p++) { ai->ai_next = malloc(sizeof(struct addrinfo)); memcpy(&ai->ai_next, ainfo, sizeof(struct addrinfo)); memcpy(&ai->ai_next->ai_addr_in.sin_addr, ainfo->ai_hostent->h_addr_list[p], ainfo->ai_hostent->h_length); ai->ai_next->ai_addr = (struct addrinfo *)&ai->ai_next->ai_addr_in; ai = ai->ai_next; } ai->ai_next = NULL; return 0; } void p_freeaddrinfo(struct addrinfo *info) { struct addrinfo *p, *next; p = info; while(p != NULL) { next = p->ai_next; free(p); p = next; } } const char *p_gai_strerror(int ret) { switch(ret) { case -1: return "Out of memory"; break; case -2: return "Address lookup failed"; break; default: return "Unknown error"; break; } } #endif /* NO_ADDRINFO */ int p_open(const char *path, int flags, ...) { mode_t mode = 0; if (flags & O_CREAT) { va_list arg_list; va_start(arg_list, flags); mode = (mode_t)va_arg(arg_list, int); va_end(arg_list); } return open(path, flags | O_BINARY | O_CLOEXEC, mode); } int p_creat(const char *path, mode_t mode) { return open(path, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_CLOEXEC, mode); } int p_getcwd(char *buffer_out, size_t size) { char *cwd_buffer; assert(buffer_out && size > 0); cwd_buffer = getcwd(buffer_out, size); if (cwd_buffer == NULL) return -1; git_path_mkposix(buffer_out); git_path_string_to_dir(buffer_out, size); /* append trailing slash */ return 0; } int p_rename(const char *from, const char *to) { if (!link(from, to)) { p_unlink(from); return 0; } if (!rename(from, to)) return 0; return -1; } #endif /* GIT_WIN32 */ int p_read(git_file fd, void *buf, size_t cnt) { char *b = buf; while (cnt) { ssize_t r; #ifdef GIT_WIN32 assert((size_t)((unsigned int)cnt) == cnt); r = read(fd, b, (unsigned int)cnt); #else r = read(fd, b, cnt); #endif if (r < 0) { if (errno == EINTR || errno == EAGAIN) continue; return -1; } if (!r) break; cnt -= r; b += r; } return (int)(b - (char *)buf); } int p_write(git_file fd, const void *buf, size_t cnt) { const char *b = buf; while (cnt) { ssize_t r; #ifdef GIT_WIN32 assert((size_t)((unsigned int)cnt) == cnt); r = write(fd, b, (unsigned int)cnt); #else r = write(fd, b, cnt); #endif if (r < 0) { if (errno == EINTR || errno == EAGAIN) continue; return -1; } if (!r) { errno = EPIPE; return -1; } cnt -= r; b += r; } return 0; } libgit2-0.19.0/src/posix.h000066400000000000000000000062131216214232500152370ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #ifndef INCLUDE_posix_h__ #define INCLUDE_posix_h__ #include "common.h" #include #include #include "fnmatch.h" #ifndef S_IFGITLINK #define S_IFGITLINK 0160000 #define S_ISGITLINK(m) (((m) & S_IFMT) == S_IFGITLINK) #endif /* if S_ISGID is not defined, then don't try to set it */ #ifndef S_ISGID #define S_ISGID 0 #endif #if !defined(O_BINARY) #define O_BINARY 0 #endif #if !defined(O_CLOEXEC) #define O_CLOEXEC 0 #endif typedef int git_file; /** * Standard POSIX Methods * * All the methods starting with the `p_` prefix are * direct ports of the standard POSIX methods. * * Some of the methods are slightly wrapped to provide * saner defaults. Some of these methods are emulated * in Windows platforns. * * Use your manpages to check the docs on these. */ extern int p_read(git_file fd, void *buf, size_t cnt); extern int p_write(git_file fd, const void *buf, size_t cnt); #define p_fstat(f,b) fstat(f, b) #define p_lseek(f,n,w) lseek(f, n, w) #define p_close(fd) close(fd) #define p_umask(m) umask(m) extern int p_open(const char *path, int flags, ...); extern int p_creat(const char *path, mode_t mode); extern int p_getcwd(char *buffer_out, size_t size); extern int p_rename(const char *from, const char *to); #ifndef GIT_WIN32 #define p_stat(p,b) stat(p, b) #define p_chdir(p) chdir(p) #define p_rmdir(p) rmdir(p) #define p_chmod(p,m) chmod(p, m) #define p_access(p,m) access(p,m) #define p_recv(s,b,l,f) recv(s,b,l,f) #define p_send(s,b,l,f) send(s,b,l,f) typedef int GIT_SOCKET; #define INVALID_SOCKET -1 #define p_localtime_r localtime_r #define p_gmtime_r gmtime_r #define p_gettimeofday gettimeofday #else typedef SOCKET GIT_SOCKET; struct timezone; extern struct tm * p_localtime_r (const time_t *timer, struct tm *result); extern struct tm * p_gmtime_r (const time_t *timer, struct tm *result); extern int p_gettimeofday(struct timeval *tv, struct timezone *tz); #endif /** * Platform-dependent methods */ #ifdef GIT_WIN32 # include "win32/posix.h" #else # include "unix/posix.h" #endif #ifdef NO_READDIR_R # include GIT_INLINE(int) p_readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result) { GIT_UNUSED(entry); *result = readdir(dirp); return 0; } #else /* NO_READDIR_R */ # define p_readdir_r(d,e,r) readdir_r(d,e,r) #endif #ifdef NO_ADDRINFO # include struct addrinfo { struct hostent *ai_hostent; struct servent *ai_servent; struct sockaddr_in ai_addr_in; struct sockaddr *ai_addr; size_t ai_addrlen; int ai_family; int ai_socktype; int ai_protocol; long ai_port; struct addrinfo *ai_next; }; extern int p_getaddrinfo(const char *host, const char *port, struct addrinfo *hints, struct addrinfo **info); extern void p_freeaddrinfo(struct addrinfo *info); extern const char *p_gai_strerror(int ret); #else # define p_getaddrinfo(a, b, c, d) getaddrinfo(a, b, c, d) # define p_freeaddrinfo(a) freeaddrinfo(a) # define p_gai_strerror(c) gai_strerror(c) #endif /* NO_ADDRINFO */ #endif libgit2-0.19.0/src/pqueue.c000066400000000000000000000064611216214232500154010ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. * * This file is based on a modified version of the priority queue found * in the Apache project and libpqueue library. * * https://github.com/vy/libpqueue * * Original file notice: * * Copyright 2010 Volkan Yazici * Copyright 2006-2010 The Apache Software Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ #include "common.h" #include "pqueue.h" #define left(i) ((i) << 1) #define right(i) (((i) << 1) + 1) #define parent(i) ((i) >> 1) int git_pqueue_init(git_pqueue *q, size_t n, git_pqueue_cmp cmppri) { assert(q); /* Need to allocate n+1 elements since element 0 isn't used. */ q->d = git__malloc((n + 1) * sizeof(void *)); GITERR_CHECK_ALLOC(q->d); q->size = 1; q->avail = q->step = (n + 1); /* see comment above about n+1 */ q->cmppri = cmppri; return 0; } void git_pqueue_free(git_pqueue *q) { git__free(q->d); q->d = NULL; } void git_pqueue_clear(git_pqueue *q) { q->size = 1; } size_t git_pqueue_size(git_pqueue *q) { /* queue element 0 exists but doesn't count since it isn't used. */ return (q->size - 1); } static void bubble_up(git_pqueue *q, size_t i) { size_t parent_node; void *moving_node = q->d[i]; for (parent_node = parent(i); ((i > 1) && q->cmppri(q->d[parent_node], moving_node)); i = parent_node, parent_node = parent(i)) { q->d[i] = q->d[parent_node]; } q->d[i] = moving_node; } static size_t maxchild(git_pqueue *q, size_t i) { size_t child_node = left(i); if (child_node >= q->size) return 0; if ((child_node + 1) < q->size && q->cmppri(q->d[child_node], q->d[child_node + 1])) child_node++; /* use right child instead of left */ return child_node; } static void percolate_down(git_pqueue *q, size_t i) { size_t child_node; void *moving_node = q->d[i]; while ((child_node = maxchild(q, i)) != 0 && q->cmppri(moving_node, q->d[child_node])) { q->d[i] = q->d[child_node]; i = child_node; } q->d[i] = moving_node; } int git_pqueue_insert(git_pqueue *q, void *d) { void *tmp; size_t i; size_t newsize; if (!q) return 1; /* allocate more memory if necessary */ if (q->size >= q->avail) { newsize = q->size + q->step; tmp = git__realloc(q->d, sizeof(void *) * newsize); GITERR_CHECK_ALLOC(tmp); q->d = tmp; q->avail = newsize; } /* insert item */ i = q->size++; q->d[i] = d; bubble_up(q, i); return 0; } void *git_pqueue_pop(git_pqueue *q) { void *head; if (!q || q->size == 1) return NULL; head = q->d[1]; q->d[1] = q->d[--q->size]; percolate_down(q, 1); return head; } void *git_pqueue_peek(git_pqueue *q) { if (!q || q->size == 1) return NULL; return q->d[1]; } libgit2-0.19.0/src/pqueue.h000066400000000000000000000051051216214232500154000ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. * * This file is based on a modified version of the priority queue found * in the Apache project and libpqueue library. * * https://github.com/vy/libpqueue * * Original file notice: * * Copyright 2010 Volkan Yazici * Copyright 2006-2010 The Apache Software Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ #ifndef INCLUDE_pqueue_h__ #define INCLUDE_pqueue_h__ /** callback functions to get/set/compare the priority of an element */ typedef int (*git_pqueue_cmp)(void *a, void *b); /** the priority queue handle */ typedef struct { size_t size, avail, step; git_pqueue_cmp cmppri; void **d; } git_pqueue; /** * initialize the queue * * @param n the initial estimate of the number of queue items for which memory * should be preallocated * @param cmppri the callback function to compare two nodes of the queue * * @Return the handle or NULL for insufficent memory */ int git_pqueue_init(git_pqueue *q, size_t n, git_pqueue_cmp cmppri); /** * free all memory used by the queue * @param q the queue */ void git_pqueue_free(git_pqueue *q); /** * clear all the elements in the queue * @param q the queue */ void git_pqueue_clear(git_pqueue *q); /** * return the size of the queue. * @param q the queue */ size_t git_pqueue_size(git_pqueue *q); /** * insert an item into the queue. * @param q the queue * @param d the item * @return 0 on success */ int git_pqueue_insert(git_pqueue *q, void *d); /** * pop the highest-ranking item from the queue. * @param p the queue * @param d where to copy the entry to * @return NULL on error, otherwise the entry */ void *git_pqueue_pop(git_pqueue *q); /** * access highest-ranking item without removing it. * @param q the queue * @param d the entry * @return NULL on error, otherwise the entry */ void *git_pqueue_peek(git_pqueue *q); #endif /* PQUEUE_H */ /** @} */ libgit2-0.19.0/src/push.c000066400000000000000000000340071216214232500150510ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #include "git2.h" #include "common.h" #include "pack.h" #include "pack-objects.h" #include "remote.h" #include "vector.h" #include "push.h" #include "tree.h" static int push_spec_rref_cmp(const void *a, const void *b) { const push_spec *push_spec_a = a, *push_spec_b = b; return strcmp(push_spec_a->rref, push_spec_b->rref); } static int push_status_ref_cmp(const void *a, const void *b) { const push_status *push_status_a = a, *push_status_b = b; return strcmp(push_status_a->ref, push_status_b->ref); } int git_push_new(git_push **out, git_remote *remote) { git_push *p; *out = NULL; p = git__calloc(1, sizeof(*p)); GITERR_CHECK_ALLOC(p); p->repo = remote->repo; p->remote = remote; p->report_status = 1; p->pb_parallelism = 1; if (git_vector_init(&p->specs, 0, push_spec_rref_cmp) < 0) { git__free(p); return -1; } if (git_vector_init(&p->status, 0, push_status_ref_cmp) < 0) { git_vector_free(&p->specs); git__free(p); return -1; } *out = p; return 0; } int git_push_set_options(git_push *push, const git_push_options *opts) { if (!push || !opts) return -1; GITERR_CHECK_VERSION(opts, GIT_PUSH_OPTIONS_VERSION, "git_push_options"); push->pb_parallelism = opts->pb_parallelism; return 0; } static void free_refspec(push_spec *spec) { if (spec == NULL) return; if (spec->lref) git__free(spec->lref); if (spec->rref) git__free(spec->rref); git__free(spec); } static int check_rref(char *ref) { if (git__prefixcmp(ref, "refs/")) { giterr_set(GITERR_INVALID, "Not a valid reference '%s'", ref); return -1; } return 0; } static int check_lref(git_push *push, char *ref) { /* lref must be resolvable to an existing object */ git_object *obj; int error = git_revparse_single(&obj, push->repo, ref); git_object_free(obj); if (!error) return 0; if (error == GIT_ENOTFOUND) giterr_set(GITERR_REFERENCE, "src refspec '%s' does not match any existing object", ref); else giterr_set(GITERR_INVALID, "Not a valid reference '%s'", ref); return -1; } static int parse_refspec(git_push *push, push_spec **spec, const char *str) { push_spec *s; char *delim; *spec = NULL; s = git__calloc(1, sizeof(*s)); GITERR_CHECK_ALLOC(s); if (str[0] == '+') { s->force = true; str++; } delim = strchr(str, ':'); if (delim == NULL) { s->lref = git__strdup(str); if (!s->lref || check_lref(push, s->lref) < 0) goto on_error; } else { if (delim - str) { s->lref = git__strndup(str, delim - str); if (!s->lref || check_lref(push, s->lref) < 0) goto on_error; } if (strlen(delim + 1)) { s->rref = git__strdup(delim + 1); if (!s->rref || check_rref(s->rref) < 0) goto on_error; } } if (!s->lref && !s->rref) goto on_error; /* If rref is ommitted, use the same ref name as lref */ if (!s->rref) { s->rref = git__strdup(s->lref); if (!s->rref || check_rref(s->rref) < 0) goto on_error; } *spec = s; return 0; on_error: free_refspec(s); return -1; } int git_push_add_refspec(git_push *push, const char *refspec) { push_spec *spec; if (parse_refspec(push, &spec, refspec) < 0 || git_vector_insert(&push->specs, spec) < 0) return -1; return 0; } int git_push_update_tips(git_push *push) { git_buf remote_ref_name = GIT_BUF_INIT; size_t i, j; git_refspec *fetch_spec; push_spec *push_spec = NULL; git_reference *remote_ref; push_status *status; int error = 0; git_vector_foreach(&push->status, i, status) { /* If this ref update was successful (ok, not ng), it will have an empty message */ if (status->msg) continue; /* Find the corresponding remote ref */ fetch_spec = git_remote__matching_refspec(push->remote, status->ref); if (!fetch_spec) continue; if ((error = git_refspec_transform_r(&remote_ref_name, fetch_spec, status->ref)) < 0) goto on_error; /* Find matching push ref spec */ git_vector_foreach(&push->specs, j, push_spec) { if (!strcmp(push_spec->rref, status->ref)) break; } /* Could not find the corresponding push ref spec for this push update */ if (j == push->specs.length) continue; /* Update the remote ref */ if (git_oid_iszero(&push_spec->loid)) { error = git_reference_lookup(&remote_ref, push->remote->repo, git_buf_cstr(&remote_ref_name)); if (!error) { if ((error = git_reference_delete(remote_ref)) < 0) { git_reference_free(remote_ref); goto on_error; } git_reference_free(remote_ref); } else if (error == GIT_ENOTFOUND) giterr_clear(); else goto on_error; } else if ((error = git_reference_create(NULL, push->remote->repo, git_buf_cstr(&remote_ref_name), &push_spec->loid, 1)) < 0) goto on_error; } error = 0; on_error: git_buf_free(&remote_ref_name); return error; } static int revwalk(git_vector *commits, git_push *push) { git_remote_head *head; push_spec *spec; git_revwalk *rw; git_oid oid; unsigned int i; int error = -1; if (git_revwalk_new(&rw, push->repo) < 0) return -1; git_revwalk_sorting(rw, GIT_SORT_TIME); git_vector_foreach(&push->specs, i, spec) { git_otype type; size_t size; if (git_oid_iszero(&spec->loid)) /* * Delete reference on remote side; * nothing to do here. */ continue; if (git_oid_equal(&spec->loid, &spec->roid)) continue; /* up-to-date */ if (git_odb_read_header(&size, &type, push->repo->_odb, &spec->loid) < 0) goto on_error; if (type == GIT_OBJ_TAG) { git_tag *tag; git_object *target; if (git_packbuilder_insert(push->pb, &spec->loid, NULL) < 0) goto on_error; if (git_tag_lookup(&tag, push->repo, &spec->loid) < 0) goto on_error; if (git_tag_peel(&target, tag) < 0) { git_tag_free(tag); goto on_error; } git_tag_free(tag); if (git_object_type(target) == GIT_OBJ_COMMIT) { if (git_revwalk_push(rw, git_object_id(target)) < 0) { git_object_free(target); goto on_error; } } else { if (git_packbuilder_insert( push->pb, git_object_id(target), NULL) < 0) { git_object_free(target); goto on_error; } } git_object_free(target); } else if (git_revwalk_push(rw, &spec->loid) < 0) goto on_error; if (!spec->force) { git_oid base; if (git_oid_iszero(&spec->roid)) continue; if (!git_odb_exists(push->repo->_odb, &spec->roid)) { giterr_set(GITERR_REFERENCE, "Cannot push missing reference"); error = GIT_ENONFASTFORWARD; goto on_error; } error = git_merge_base(&base, push->repo, &spec->loid, &spec->roid); if (error == GIT_ENOTFOUND || (!error && !git_oid_equal(&base, &spec->roid))) { giterr_set(GITERR_REFERENCE, "Cannot push non-fastforwardable reference"); error = GIT_ENONFASTFORWARD; goto on_error; } if (error < 0) goto on_error; } } git_vector_foreach(&push->remote->refs, i, head) { if (git_oid_iszero(&head->oid)) continue; /* TODO */ git_revwalk_hide(rw, &head->oid); } while ((error = git_revwalk_next(&oid, rw)) == 0) { git_oid *o = git__malloc(GIT_OID_RAWSZ); if (!o) { error = -1; goto on_error; } git_oid_cpy(o, &oid); if ((error = git_vector_insert(commits, o)) < 0) goto on_error; } on_error: git_revwalk_free(rw); return error == GIT_ITEROVER ? 0 : error; } static int enqueue_object( const git_tree_entry *entry, git_packbuilder *pb) { switch (git_tree_entry_type(entry)) { case GIT_OBJ_COMMIT: return 0; case GIT_OBJ_TREE: return git_packbuilder_insert_tree(pb, &entry->oid); default: return git_packbuilder_insert(pb, &entry->oid, entry->filename); } } static int queue_differences( git_tree *base, git_tree *delta, git_packbuilder *pb) { git_tree *b_child = NULL, *d_child = NULL; size_t b_length = git_tree_entrycount(base); size_t d_length = git_tree_entrycount(delta); size_t i = 0, j = 0; int error; while (i < b_length && j < d_length) { const git_tree_entry *b_entry = git_tree_entry_byindex(base, i); const git_tree_entry *d_entry = git_tree_entry_byindex(delta, j); int cmp = 0; if (!git_oid__cmp(&b_entry->oid, &d_entry->oid)) goto loop; cmp = strcmp(b_entry->filename, d_entry->filename); /* If the entries are both trees and they have the same name but are * different, then we'll recurse after adding the right-hand entry */ if (!cmp && git_tree_entry__is_tree(b_entry) && git_tree_entry__is_tree(d_entry)) { /* Add the right-hand entry */ if ((error = git_packbuilder_insert(pb, &d_entry->oid, d_entry->filename)) < 0) goto on_error; /* Acquire the subtrees and recurse */ if ((error = git_tree_lookup(&b_child, git_tree_owner(base), &b_entry->oid)) < 0 || (error = git_tree_lookup(&d_child, git_tree_owner(delta), &d_entry->oid)) < 0 || (error = queue_differences(b_child, d_child, pb)) < 0) goto on_error; git_tree_free(b_child); b_child = NULL; git_tree_free(d_child); d_child = NULL; } /* If the object is new or different in the right-hand tree, * then enumerate it */ else if (cmp >= 0 && (error = enqueue_object(d_entry, pb)) < 0) goto on_error; loop: if (cmp <= 0) i++; if (cmp >= 0) j++; } /* Drain the right-hand tree of entries */ for (; j < d_length; j++) if ((error = enqueue_object(git_tree_entry_byindex(delta, j), pb)) < 0) goto on_error; error = 0; on_error: if (b_child) git_tree_free(b_child); if (d_child) git_tree_free(d_child); return error; } static int queue_objects(git_push *push) { git_vector commits = GIT_VECTOR_INIT; git_oid *oid; size_t i; unsigned j; int error; if ((error = revwalk(&commits, push)) < 0) goto on_error; git_vector_foreach(&commits, i, oid) { git_commit *parent = NULL, *commit; git_tree *tree = NULL, *ptree = NULL; size_t parentcount; if ((error = git_commit_lookup(&commit, push->repo, oid)) < 0) goto on_error; /* Insert the commit */ if ((error = git_packbuilder_insert(push->pb, oid, NULL)) < 0) goto loop_error; parentcount = git_commit_parentcount(commit); if (!parentcount) { if ((error = git_packbuilder_insert_tree(push->pb, git_commit_tree_id(commit))) < 0) goto loop_error; } else { if ((error = git_tree_lookup(&tree, push->repo, git_commit_tree_id(commit))) < 0 || (error = git_packbuilder_insert(push->pb, git_commit_tree_id(commit), NULL)) < 0) goto loop_error; /* For each parent, add the items which are different */ for (j = 0; j < parentcount; j++) { if ((error = git_commit_parent(&parent, commit, j)) < 0 || (error = git_commit_tree(&ptree, parent)) < 0 || (error = queue_differences(ptree, tree, push->pb)) < 0) goto loop_error; git_tree_free(ptree); ptree = NULL; git_commit_free(parent); parent = NULL; } } error = 0; loop_error: if (tree) git_tree_free(tree); if (ptree) git_tree_free(ptree); if (parent) git_commit_free(parent); git_commit_free(commit); if (error < 0) goto on_error; } error = 0; on_error: git_vector_foreach(&commits, i, oid) git__free(oid); git_vector_free(&commits); return error; } static int calculate_work(git_push *push) { git_remote_head *head; push_spec *spec; unsigned int i, j; /* Update local and remote oids*/ git_vector_foreach(&push->specs, i, spec) { if (spec->lref) { /* This is a create or update. Local ref must exist. */ if (git_reference_name_to_id( &spec->loid, push->repo, spec->lref) < 0) { giterr_set(GITERR_REFERENCE, "No such reference '%s'", spec->lref); return -1; } } if (spec->rref) { /* Remote ref may or may not (e.g. during create) already exist. */ git_vector_foreach(&push->remote->refs, j, head) { if (!strcmp(spec->rref, head->name)) { git_oid_cpy(&spec->roid, &head->oid); break; } } } } return 0; } static int do_push(git_push *push) { int error; git_transport *transport = push->remote->transport; if (!transport->push) { giterr_set(GITERR_NET, "Remote transport doesn't support push"); error = -1; goto on_error; } /* * A pack-file MUST be sent if either create or update command * is used, even if the server already has all the necessary * objects. In this case the client MUST send an empty pack-file. */ if ((error = git_packbuilder_new(&push->pb, push->repo)) < 0) goto on_error; git_packbuilder_set_threads(push->pb, push->pb_parallelism); if ((error = calculate_work(push)) < 0 || (error = queue_objects(push)) < 0 || (error = transport->push(transport, push)) < 0) goto on_error; error = 0; on_error: git_packbuilder_free(push->pb); return error; } static int cb_filter_refs(git_remote_head *ref, void *data) { git_remote *remote = (git_remote *) data; return git_vector_insert(&remote->refs, ref); } static int filter_refs(git_remote *remote) { git_vector_clear(&remote->refs); return git_remote_ls(remote, cb_filter_refs, remote); } int git_push_finish(git_push *push) { int error; if (!git_remote_connected(push->remote) && (error = git_remote_connect(push->remote, GIT_DIRECTION_PUSH)) < 0) return error; if ((error = filter_refs(push->remote)) < 0 || (error = do_push(push)) < 0) return error; return 0; } int git_push_unpack_ok(git_push *push) { return push->unpack_ok; } int git_push_status_foreach(git_push *push, int (*cb)(const char *ref, const char *msg, void *data), void *data) { push_status *status; unsigned int i; git_vector_foreach(&push->status, i, status) { if (cb(status->ref, status->msg, data) < 0) return GIT_EUSER; } return 0; } void git_push_status_free(push_status *status) { if (status == NULL) return; if (status->msg) git__free(status->msg); git__free(status->ref); git__free(status); } void git_push_free(git_push *push) { push_spec *spec; push_status *status; unsigned int i; if (push == NULL) return; git_vector_foreach(&push->specs, i, spec) { free_refspec(spec); } git_vector_free(&push->specs); git_vector_foreach(&push->status, i, status) { git_push_status_free(status); } git_vector_free(&push->status); git__free(push); } libgit2-0.19.0/src/push.h000066400000000000000000000015221216214232500150520ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #ifndef INCLUDE_push_h__ #define INCLUDE_push_h__ #include "git2.h" typedef struct push_spec { char *lref; char *rref; git_oid loid; git_oid roid; bool force; } push_spec; typedef struct push_status { bool ok; char *ref; char *msg; } push_status; struct git_push { git_repository *repo; git_packbuilder *pb; git_remote *remote; git_vector specs; bool report_status; /* report-status */ bool unpack_ok; git_vector status; /* options */ unsigned pb_parallelism; }; /** * Free the given push status object * * @param status The push status object */ void git_push_status_free(push_status *status); #endif libgit2-0.19.0/src/refdb.c000066400000000000000000000072041216214232500151530ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #include "common.h" #include "posix.h" #include "git2/object.h" #include "git2/refs.h" #include "git2/refdb.h" #include "git2/sys/refdb_backend.h" #include "hash.h" #include "refdb.h" #include "refs.h" int git_refdb_new(git_refdb **out, git_repository *repo) { git_refdb *db; assert(out && repo); db = git__calloc(1, sizeof(*db)); GITERR_CHECK_ALLOC(db); db->repo = repo; *out = db; GIT_REFCOUNT_INC(db); return 0; } int git_refdb_open(git_refdb **out, git_repository *repo) { git_refdb *db; git_refdb_backend *dir; assert(out && repo); *out = NULL; if (git_refdb_new(&db, repo) < 0) return -1; /* Add the default (filesystem) backend */ if (git_refdb_backend_fs(&dir, repo) < 0) { git_refdb_free(db); return -1; } db->repo = repo; db->backend = dir; *out = db; return 0; } static void refdb_free_backend(git_refdb *db) { if (db->backend) { if (db->backend->free) db->backend->free(db->backend); else git__free(db->backend); } } int git_refdb_set_backend(git_refdb *db, git_refdb_backend *backend) { refdb_free_backend(db); db->backend = backend; return 0; } int git_refdb_compress(git_refdb *db) { assert(db); if (db->backend->compress) return db->backend->compress(db->backend); return 0; } void git_refdb__free(git_refdb *db) { refdb_free_backend(db); git__memzero(db, sizeof(*db)); git__free(db); } void git_refdb_free(git_refdb *db) { if (db == NULL) return; GIT_REFCOUNT_DEC(db, git_refdb__free); } int git_refdb_exists(int *exists, git_refdb *refdb, const char *ref_name) { assert(exists && refdb && refdb->backend); return refdb->backend->exists(exists, refdb->backend, ref_name); } int git_refdb_lookup(git_reference **out, git_refdb *db, const char *ref_name) { git_reference *ref; int error; assert(db && db->backend && out && ref_name); error = db->backend->lookup(&ref, db->backend, ref_name); if (error < 0) return error; GIT_REFCOUNT_INC(db); ref->db = db; *out = ref; return 0; } int git_refdb_iterator(git_reference_iterator **out, git_refdb *db, const char *glob) { if (!db->backend || !db->backend->iterator) { giterr_set(GITERR_REFERENCE, "This backend doesn't support iterators"); return -1; } if (db->backend->iterator(out, db->backend, glob) < 0) return -1; GIT_REFCOUNT_INC(db); (*out)->db = db; return 0; } int git_refdb_iterator_next(git_reference **out, git_reference_iterator *iter) { int error; if ((error = iter->next(out, iter)) < 0) return error; GIT_REFCOUNT_INC(iter->db); (*out)->db = iter->db; return 0; } int git_refdb_iterator_next_name(const char **out, git_reference_iterator *iter) { return iter->next_name(out, iter); } void git_refdb_iterator_free(git_reference_iterator *iter) { GIT_REFCOUNT_DEC(iter->db, git_refdb__free); iter->free(iter); } int git_refdb_write(git_refdb *db, git_reference *ref, int force) { assert(db && db->backend); GIT_REFCOUNT_INC(db); ref->db = db; return db->backend->write(db->backend, ref, force); } int git_refdb_rename( git_reference **out, git_refdb *db, const char *old_name, const char *new_name, int force) { int error; assert(db && db->backend); error = db->backend->rename(out, db->backend, old_name, new_name, force); if (error < 0) return error; if (out) { GIT_REFCOUNT_INC(db); (*out)->db = db; } return 0; } int git_refdb_delete(struct git_refdb *db, const char *ref_name) { assert(db && db->backend); return db->backend->delete(db->backend, ref_name); } libgit2-0.19.0/src/refdb.h000066400000000000000000000022421216214232500151550ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #ifndef INCLUDE_refdb_h__ #define INCLUDE_refdb_h__ #include "git2/refdb.h" #include "repository.h" struct git_refdb { git_refcount rc; git_repository *repo; git_refdb_backend *backend; }; void git_refdb__free(git_refdb *db); int git_refdb_exists( int *exists, git_refdb *refdb, const char *ref_name); int git_refdb_lookup( git_reference **out, git_refdb *refdb, const char *ref_name); int git_refdb_rename( git_reference **out, git_refdb *db, const char *old_name, const char *new_name, int force); int git_refdb_iterator(git_reference_iterator **out, git_refdb *db, const char *glob); int git_refdb_iterator_next(git_reference **out, git_reference_iterator *iter); int git_refdb_iterator_next_name(const char **out, git_reference_iterator *iter); void git_refdb_iterator_free(git_reference_iterator *iter); int git_refdb_write(git_refdb *refdb, git_reference *ref, int force); int git_refdb_delete(git_refdb *refdb, const char *ref_name); #endif libgit2-0.19.0/src/refdb_fs.c000066400000000000000000000717701216214232500156540ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #include "refs.h" #include "hash.h" #include "repository.h" #include "fileops.h" #include "filebuf.h" #include "pack.h" #include "reflog.h" #include "refdb.h" #include "refdb_fs.h" #include "iterator.h" #include #include #include #include #include GIT__USE_STRMAP; #define DEFAULT_NESTING_LEVEL 5 #define MAX_NESTING_LEVEL 10 enum { PACKREF_HAS_PEEL = 1, PACKREF_WAS_LOOSE = 2, PACKREF_CANNOT_PEEL = 4, PACKREF_SHADOWED = 8, }; enum { PEELING_NONE = 0, PEELING_STANDARD, PEELING_FULL }; struct packref { git_oid oid; git_oid peel; char flags; char name[GIT_FLEX_ARRAY]; }; typedef struct refdb_fs_backend { git_refdb_backend parent; git_repository *repo; char *path; git_refcache refcache; int peeling_mode; } refdb_fs_backend; static int reference_read( git_buf *file_content, time_t *mtime, const char *repo_path, const char *ref_name, int *updated) { git_buf path = GIT_BUF_INIT; int result; assert(file_content && repo_path && ref_name); /* Determine the full path of the file */ if (git_buf_joinpath(&path, repo_path, ref_name) < 0) return -1; result = git_futils_readbuffer_updated(file_content, path.ptr, mtime, NULL, updated); git_buf_free(&path); return result; } static int packed_parse_oid( struct packref **ref_out, const char **buffer_out, const char *buffer_end) { struct packref *ref = NULL; const char *buffer = *buffer_out; const char *refname_begin, *refname_end; size_t refname_len; git_oid id; refname_begin = (buffer + GIT_OID_HEXSZ + 1); if (refname_begin >= buffer_end || refname_begin[-1] != ' ') goto corrupt; /* Is this a valid object id? */ if (git_oid_fromstr(&id, buffer) < 0) goto corrupt; refname_end = memchr(refname_begin, '\n', buffer_end - refname_begin); if (refname_end == NULL) refname_end = buffer_end; if (refname_end[-1] == '\r') refname_end--; refname_len = refname_end - refname_begin; ref = git__calloc(1, sizeof(struct packref) + refname_len + 1); GITERR_CHECK_ALLOC(ref); memcpy(ref->name, refname_begin, refname_len); ref->name[refname_len] = 0; git_oid_cpy(&ref->oid, &id); *ref_out = ref; *buffer_out = refname_end + 1; return 0; corrupt: git__free(ref); giterr_set(GITERR_REFERENCE, "The packed references file is corrupted"); return -1; } static int packed_parse_peel( struct packref *tag_ref, const char **buffer_out, const char *buffer_end) { const char *buffer = *buffer_out + 1; assert(buffer[-1] == '^'); /* Ensure it's not the first entry of the file */ if (tag_ref == NULL) goto corrupt; if (buffer + GIT_OID_HEXSZ > buffer_end) goto corrupt; /* Is this a valid object id? */ if (git_oid_fromstr(&tag_ref->peel, buffer) < 0) goto corrupt; buffer = buffer + GIT_OID_HEXSZ; if (*buffer == '\r') buffer++; if (buffer != buffer_end) { if (*buffer == '\n') buffer++; else goto corrupt; } tag_ref->flags |= PACKREF_HAS_PEEL; *buffer_out = buffer; return 0; corrupt: giterr_set(GITERR_REFERENCE, "The packed references file is corrupted"); return -1; } static int packed_load(refdb_fs_backend *backend) { int result, updated; git_buf packfile = GIT_BUF_INIT; const char *buffer_start, *buffer_end; git_refcache *ref_cache = &backend->refcache; /* First we make sure we have allocated the hash table */ if (ref_cache->packfile == NULL) { ref_cache->packfile = git_strmap_alloc(); GITERR_CHECK_ALLOC(ref_cache->packfile); } if (backend->path == NULL) return 0; result = reference_read(&packfile, &ref_cache->packfile_time, backend->path, GIT_PACKEDREFS_FILE, &updated); /* * If we couldn't find the file, we need to clear the table and * return. On any other error, we return that error. If everything * went fine and the file wasn't updated, then there's nothing new * for us here, so just return. Anything else means we need to * refresh the packed refs. */ if (result == GIT_ENOTFOUND) { git_strmap_clear(ref_cache->packfile); return 0; } if (result < 0) return -1; if (!updated) return 0; /* * At this point, we want to refresh the packed refs. We already * have the contents in our buffer. */ git_strmap_clear(ref_cache->packfile); buffer_start = (const char *)packfile.ptr; buffer_end = (const char *)(buffer_start) + packfile.size; backend->peeling_mode = PEELING_NONE; if (buffer_start[0] == '#') { static const char *traits_header = "# pack-refs with: "; if (git__prefixcmp(buffer_start, traits_header) == 0) { char *traits = (char *)buffer_start + strlen(traits_header); char *traits_end = strchr(traits, '\n'); if (traits_end == NULL) goto parse_failed; *traits_end = '\0'; if (strstr(traits, " fully-peeled ") != NULL) { backend->peeling_mode = PEELING_FULL; } else if (strstr(traits, " peeled ") != NULL) { backend->peeling_mode = PEELING_STANDARD; } buffer_start = traits_end + 1; } } while (buffer_start < buffer_end && buffer_start[0] == '#') { buffer_start = strchr(buffer_start, '\n'); if (buffer_start == NULL) goto parse_failed; buffer_start++; } while (buffer_start < buffer_end) { int err; struct packref *ref = NULL; if (packed_parse_oid(&ref, &buffer_start, buffer_end) < 0) goto parse_failed; if (buffer_start[0] == '^') { if (packed_parse_peel(ref, &buffer_start, buffer_end) < 0) goto parse_failed; } else if (backend->peeling_mode == PEELING_FULL || (backend->peeling_mode == PEELING_STANDARD && git__prefixcmp(ref->name, GIT_REFS_TAGS_DIR) == 0)) { ref->flags |= PACKREF_CANNOT_PEEL; } git_strmap_insert(ref_cache->packfile, ref->name, ref, err); if (err < 0) goto parse_failed; } git_buf_free(&packfile); return 0; parse_failed: git_strmap_free(ref_cache->packfile); ref_cache->packfile = NULL; git_buf_free(&packfile); return -1; } static int loose_parse_oid(git_oid *oid, const char *filename, git_buf *file_content) { size_t len; const char *str; len = git_buf_len(file_content); if (len < GIT_OID_HEXSZ) goto corrupted; /* str is guranteed to be zero-terminated */ str = git_buf_cstr(file_content); /* we need to get 40 OID characters from the file */ if (git_oid_fromstr(oid, git_buf_cstr(file_content)) < 0) goto corrupted; /* If the file is longer than 40 chars, the 41st must be a space */ str += GIT_OID_HEXSZ; if (*str == '\0' || git__isspace(*str)) return 0; corrupted: giterr_set(GITERR_REFERENCE, "Corrupted loose reference file: %s", filename); return -1; } static int loose_lookup_to_packfile( struct packref **ref_out, refdb_fs_backend *backend, const char *name) { git_buf ref_file = GIT_BUF_INIT; struct packref *ref = NULL; size_t name_len; *ref_out = NULL; if (reference_read(&ref_file, NULL, backend->path, name, NULL) < 0) return -1; git_buf_rtrim(&ref_file); name_len = strlen(name); ref = git__calloc(1, sizeof(struct packref) + name_len + 1); GITERR_CHECK_ALLOC(ref); memcpy(ref->name, name, name_len); ref->name[name_len] = 0; if (loose_parse_oid(&ref->oid, name, &ref_file) < 0) { git_buf_free(&ref_file); git__free(ref); return -1; } ref->flags = PACKREF_WAS_LOOSE; *ref_out = ref; git_buf_free(&ref_file); return 0; } static int _dirent_loose_load(void *data, git_buf *full_path) { refdb_fs_backend *backend = (refdb_fs_backend *)data; void *old_ref = NULL; struct packref *ref; const char *file_path; int err; if (git_path_isdir(full_path->ptr) == true) return git_path_direach(full_path, _dirent_loose_load, backend); file_path = full_path->ptr + strlen(backend->path); if (loose_lookup_to_packfile(&ref, backend, file_path) < 0) return -1; git_strmap_insert2( backend->refcache.packfile, ref->name, ref, old_ref, err); if (err < 0) { git__free(ref); return -1; } git__free(old_ref); return 0; } /* * Load all the loose references from the repository * into the in-memory Packfile, and build a vector with * all the references so it can be written back to * disk. */ static int packed_loadloose(refdb_fs_backend *backend) { git_buf refs_path = GIT_BUF_INIT; int result; /* the packfile must have been previously loaded! */ assert(backend->refcache.packfile); if (git_buf_joinpath(&refs_path, backend->path, GIT_REFS_DIR) < 0) return -1; /* * Load all the loose files from disk into the Packfile table. * This will overwrite any old packed entries with their * updated loose versions */ result = git_path_direach(&refs_path, _dirent_loose_load, backend); git_buf_free(&refs_path); return result; } static int refdb_fs_backend__exists( int *exists, git_refdb_backend *_backend, const char *ref_name) { refdb_fs_backend *backend; git_buf ref_path = GIT_BUF_INIT; assert(_backend); backend = (refdb_fs_backend *)_backend; if (packed_load(backend) < 0) return -1; if (git_buf_joinpath(&ref_path, backend->path, ref_name) < 0) return -1; if (git_path_isfile(ref_path.ptr) == true || git_strmap_exists(backend->refcache.packfile, ref_path.ptr)) *exists = 1; else *exists = 0; git_buf_free(&ref_path); return 0; } static const char *loose_parse_symbolic(git_buf *file_content) { const unsigned int header_len = (unsigned int)strlen(GIT_SYMREF); const char *refname_start; refname_start = (const char *)file_content->ptr; if (git_buf_len(file_content) < header_len + 1) { giterr_set(GITERR_REFERENCE, "Corrupted loose reference file"); return NULL; } /* * Assume we have already checked for the header * before calling this function */ refname_start += header_len; return refname_start; } static int loose_lookup( git_reference **out, refdb_fs_backend *backend, const char *ref_name) { const char *target; git_oid oid; git_buf ref_file = GIT_BUF_INIT; int error = 0; error = reference_read(&ref_file, NULL, backend->path, ref_name, NULL); if (error < 0) goto done; if (git__prefixcmp((const char *)(ref_file.ptr), GIT_SYMREF) == 0) { git_buf_rtrim(&ref_file); if ((target = loose_parse_symbolic(&ref_file)) == NULL) { error = -1; goto done; } *out = git_reference__alloc_symbolic(ref_name, target); } else { if ((error = loose_parse_oid(&oid, ref_name, &ref_file)) < 0) goto done; *out = git_reference__alloc(ref_name, &oid, NULL); } if (*out == NULL) error = -1; done: git_buf_free(&ref_file); return error; } static int packed_map_entry( struct packref **entry, khiter_t *pos, refdb_fs_backend *backend, const char *ref_name) { git_strmap *packfile_refs; if (packed_load(backend) < 0) return -1; /* Look up on the packfile */ packfile_refs = backend->refcache.packfile; *pos = git_strmap_lookup_index(packfile_refs, ref_name); if (!git_strmap_valid_index(packfile_refs, *pos)) { giterr_set(GITERR_REFERENCE, "Reference '%s' not found", ref_name); return GIT_ENOTFOUND; } *entry = git_strmap_value_at(packfile_refs, *pos); return 0; } static int packed_lookup( git_reference **out, refdb_fs_backend *backend, const char *ref_name) { struct packref *entry; khiter_t pos; int error = 0; if ((error = packed_map_entry(&entry, &pos, backend, ref_name)) < 0) return error; if ((*out = git_reference__alloc(ref_name, &entry->oid, &entry->peel)) == NULL) return -1; return 0; } static int refdb_fs_backend__lookup( git_reference **out, git_refdb_backend *_backend, const char *ref_name) { refdb_fs_backend *backend; int result; assert(_backend); backend = (refdb_fs_backend *)_backend; if ((result = loose_lookup(out, backend, ref_name)) == 0) return 0; /* only try to lookup this reference on the packfile if it * wasn't found on the loose refs; not if there was a critical error */ if (result == GIT_ENOTFOUND) { giterr_clear(); result = packed_lookup(out, backend, ref_name); } return result; } typedef struct { git_reference_iterator parent; char *glob; git_vector loose; unsigned int loose_pos; khiter_t packed_pos; } refdb_fs_iter; static void refdb_fs_backend__iterator_free(git_reference_iterator *_iter) { refdb_fs_iter *iter = (refdb_fs_iter *) _iter; char *loose_path; size_t i; git_vector_foreach(&iter->loose, i, loose_path) { git__free(loose_path); } git_vector_free(&iter->loose); git__free(iter->glob); git__free(iter); } static int iter_load_loose_paths(refdb_fs_backend *backend, refdb_fs_iter *iter) { git_strmap *packfile = backend->refcache.packfile; git_buf path = GIT_BUF_INIT; git_iterator *fsit; const git_index_entry *entry = NULL; if (!backend->path) /* do nothing if no path for loose refs */ return 0; if (git_buf_printf(&path, "%s/refs", backend->path) < 0) return -1; if (git_iterator_for_filesystem(&fsit, git_buf_cstr(&path), 0, NULL, NULL) < 0) return -1; git_vector_init(&iter->loose, 8, NULL); git_buf_sets(&path, GIT_REFS_DIR); while (!git_iterator_advance(&entry, fsit)) { const char *ref_name; khiter_t pos; git_buf_truncate(&path, strlen(GIT_REFS_DIR)); git_buf_puts(&path, entry->path); ref_name = git_buf_cstr(&path); if (git__suffixcmp(ref_name, ".lock") == 0 || (iter->glob && p_fnmatch(iter->glob, ref_name, 0) != 0)) continue; pos = git_strmap_lookup_index(packfile, ref_name); if (git_strmap_valid_index(packfile, pos)) { struct packref *ref = git_strmap_value_at(packfile, pos); ref->flags |= PACKREF_SHADOWED; } git_vector_insert(&iter->loose, git__strdup(ref_name)); } git_iterator_free(fsit); git_buf_free(&path); return 0; } static int refdb_fs_backend__iterator_next( git_reference **out, git_reference_iterator *_iter) { refdb_fs_iter *iter = (refdb_fs_iter *)_iter; refdb_fs_backend *backend = (refdb_fs_backend *)iter->parent.db->backend; git_strmap *packfile = backend->refcache.packfile; while (iter->loose_pos < iter->loose.length) { const char *path = git_vector_get(&iter->loose, iter->loose_pos++); if (loose_lookup(out, backend, path) == 0) return 0; giterr_clear(); } while (iter->packed_pos < kh_end(packfile)) { struct packref *ref = NULL; while (!kh_exist(packfile, iter->packed_pos)) { iter->packed_pos++; if (iter->packed_pos == kh_end(packfile)) return GIT_ITEROVER; } ref = kh_val(packfile, iter->packed_pos); iter->packed_pos++; if (ref->flags & PACKREF_SHADOWED) continue; if (iter->glob && p_fnmatch(iter->glob, ref->name, 0) != 0) continue; *out = git_reference__alloc(ref->name, &ref->oid, &ref->peel); if (*out == NULL) return -1; return 0; } return GIT_ITEROVER; } static int refdb_fs_backend__iterator_next_name( const char **out, git_reference_iterator *_iter) { refdb_fs_iter *iter = (refdb_fs_iter *)_iter; refdb_fs_backend *backend = (refdb_fs_backend *)iter->parent.db->backend; git_strmap *packfile = backend->refcache.packfile; while (iter->loose_pos < iter->loose.length) { const char *path = git_vector_get(&iter->loose, iter->loose_pos++); if (git_strmap_exists(packfile, path)) continue; *out = path; return 0; } while (iter->packed_pos < kh_end(packfile)) { while (!kh_exist(packfile, iter->packed_pos)) { iter->packed_pos++; if (iter->packed_pos == kh_end(packfile)) return GIT_ITEROVER; } *out = kh_key(packfile, iter->packed_pos); iter->packed_pos++; if (iter->glob && p_fnmatch(iter->glob, *out, 0) != 0) continue; return 0; } return GIT_ITEROVER; } static int refdb_fs_backend__iterator( git_reference_iterator **out, git_refdb_backend *_backend, const char *glob) { refdb_fs_iter *iter; refdb_fs_backend *backend; assert(_backend); backend = (refdb_fs_backend *)_backend; if (packed_load(backend) < 0) return -1; iter = git__calloc(1, sizeof(refdb_fs_iter)); GITERR_CHECK_ALLOC(iter); if (glob != NULL) iter->glob = git__strdup(glob); iter->parent.next = refdb_fs_backend__iterator_next; iter->parent.next_name = refdb_fs_backend__iterator_next_name; iter->parent.free = refdb_fs_backend__iterator_free; if (iter_load_loose_paths(backend, iter) < 0) { refdb_fs_backend__iterator_free((git_reference_iterator *)iter); return -1; } *out = (git_reference_iterator *)iter; return 0; } static bool ref_is_available( const char *old_ref, const char *new_ref, const char *this_ref) { if (old_ref == NULL || strcmp(old_ref, this_ref)) { size_t reflen = strlen(this_ref); size_t newlen = strlen(new_ref); size_t cmplen = reflen < newlen ? reflen : newlen; const char *lead = reflen < newlen ? new_ref : this_ref; if (!strncmp(new_ref, this_ref, cmplen) && lead[cmplen] == '/') { return false; } } return true; } static int reference_path_available( refdb_fs_backend *backend, const char *new_ref, const char* old_ref, int force) { struct packref *this_ref; if (packed_load(backend) < 0) return -1; if (!force) { int exists; if (refdb_fs_backend__exists(&exists, (git_refdb_backend *)backend, new_ref) < 0) return -1; if (exists) { giterr_set(GITERR_REFERENCE, "Failed to write reference '%s': a reference with " " that name already exists.", new_ref); return GIT_EEXISTS; } } git_strmap_foreach_value(backend->refcache.packfile, this_ref, { if (!ref_is_available(old_ref, new_ref, this_ref->name)) { giterr_set(GITERR_REFERENCE, "The path to reference '%s' collides with an existing one", new_ref); return -1; } }); return 0; } static int loose_write(refdb_fs_backend *backend, const git_reference *ref) { git_filebuf file = GIT_FILEBUF_INIT; git_buf ref_path = GIT_BUF_INIT; /* Remove a possibly existing empty directory hierarchy * which name would collide with the reference name */ if (git_futils_rmdir_r(ref->name, backend->path, GIT_RMDIR_SKIP_NONEMPTY) < 0) return -1; if (git_buf_joinpath(&ref_path, backend->path, ref->name) < 0) return -1; if (git_filebuf_open(&file, ref_path.ptr, GIT_FILEBUF_FORCE) < 0) { git_buf_free(&ref_path); return -1; } git_buf_free(&ref_path); if (ref->type == GIT_REF_OID) { char oid[GIT_OID_HEXSZ + 1]; git_oid_fmt(oid, &ref->target.oid); oid[GIT_OID_HEXSZ] = '\0'; git_filebuf_printf(&file, "%s\n", oid); } else if (ref->type == GIT_REF_SYMBOLIC) { git_filebuf_printf(&file, GIT_SYMREF "%s\n", ref->target.symbolic); } else { assert(0); /* don't let this happen */ } return git_filebuf_commit(&file, GIT_REFS_FILE_MODE); } static int packed_sort(const void *a, const void *b) { const struct packref *ref_a = (const struct packref *)a; const struct packref *ref_b = (const struct packref *)b; return strcmp(ref_a->name, ref_b->name); } /* * Find out what object this reference resolves to. * * For references that point to a 'big' tag (e.g. an * actual tag object on the repository), we need to * cache on the packfile the OID of the object to * which that 'big tag' is pointing to. */ static int packed_find_peel(refdb_fs_backend *backend, struct packref *ref) { git_object *object; if (ref->flags & PACKREF_HAS_PEEL || ref->flags & PACKREF_CANNOT_PEEL) return 0; /* * Find the tagged object in the repository */ if (git_object_lookup(&object, backend->repo, &ref->oid, GIT_OBJ_ANY) < 0) return -1; /* * If the tagged object is a Tag object, we need to resolve it; * if the ref is actually a 'weak' ref, we don't need to resolve * anything. */ if (git_object_type(object) == GIT_OBJ_TAG) { git_tag *tag = (git_tag *)object; /* * Find the object pointed at by this tag */ git_oid_cpy(&ref->peel, git_tag_target_id(tag)); ref->flags |= PACKREF_HAS_PEEL; /* * The reference has now cached the resolved OID, and is * marked at such. When written to the packfile, it'll be * accompanied by this resolved oid */ } git_object_free(object); return 0; } /* * Write a single reference into a packfile */ static int packed_write_ref(struct packref *ref, git_filebuf *file) { char oid[GIT_OID_HEXSZ + 1]; git_oid_fmt(oid, &ref->oid); oid[GIT_OID_HEXSZ] = 0; /* * For references that peel to an object in the repo, we must * write the resulting peel on a separate line, e.g. * * 6fa8a902cc1d18527e1355773c86721945475d37 refs/tags/libgit2-0.4 * ^2ec0cb7959b0bf965d54f95453f5b4b34e8d3100 * * This obviously only applies to tags. * The required peels have already been loaded into `ref->peel_target`. */ if (ref->flags & PACKREF_HAS_PEEL) { char peel[GIT_OID_HEXSZ + 1]; git_oid_fmt(peel, &ref->peel); peel[GIT_OID_HEXSZ] = 0; if (git_filebuf_printf(file, "%s %s\n^%s\n", oid, ref->name, peel) < 0) return -1; } else { if (git_filebuf_printf(file, "%s %s\n", oid, ref->name) < 0) return -1; } return 0; } /* * Remove all loose references * * Once we have successfully written a packfile, * all the loose references that were packed must be * removed from disk. * * This is a dangerous method; make sure the packfile * is well-written, because we are destructing references * here otherwise. */ static int packed_remove_loose( refdb_fs_backend *backend, git_vector *packing_list) { size_t i; git_buf full_path = GIT_BUF_INIT; int failed = 0; for (i = 0; i < packing_list->length; ++i) { struct packref *ref = git_vector_get(packing_list, i); if ((ref->flags & PACKREF_WAS_LOOSE) == 0) continue; if (git_buf_joinpath(&full_path, backend->path, ref->name) < 0) return -1; /* critical; do not try to recover on oom */ if (git_path_exists(full_path.ptr) == true && p_unlink(full_path.ptr) < 0) { if (failed) continue; giterr_set(GITERR_REFERENCE, "Failed to remove loose reference '%s' after packing: %s", full_path.ptr, strerror(errno)); failed = 1; } /* * if we fail to remove a single file, this is *not* good, * but we should keep going and remove as many as possible. * After we've removed as many files as possible, we return * the error code anyway. */ } git_buf_free(&full_path); return failed ? -1 : 0; } /* * Write all the contents in the in-memory packfile to disk. */ static int packed_write(refdb_fs_backend *backend) { git_filebuf pack_file = GIT_FILEBUF_INIT; size_t i; git_buf pack_file_path = GIT_BUF_INIT; git_vector packing_list; unsigned int total_refs; assert(backend && backend->refcache.packfile); total_refs = (unsigned int)git_strmap_num_entries(backend->refcache.packfile); if (git_vector_init(&packing_list, total_refs, packed_sort) < 0) return -1; /* Load all the packfile into a vector */ { struct packref *reference; /* cannot fail: vector already has the right size */ git_strmap_foreach_value(backend->refcache.packfile, reference, { git_vector_insert(&packing_list, reference); }); } /* sort the vector so the entries appear sorted on the packfile */ git_vector_sort(&packing_list); /* Now we can open the file! */ if (git_buf_joinpath(&pack_file_path, backend->path, GIT_PACKEDREFS_FILE) < 0) goto cleanup_memory; if (git_filebuf_open(&pack_file, pack_file_path.ptr, 0) < 0) goto cleanup_packfile; /* Packfiles have a header... apparently * This is in fact not required, but we might as well print it * just for kicks */ if (git_filebuf_printf(&pack_file, "%s\n", GIT_PACKEDREFS_HEADER) < 0) goto cleanup_packfile; for (i = 0; i < packing_list.length; ++i) { struct packref *ref = (struct packref *)git_vector_get(&packing_list, i); if (packed_find_peel(backend, ref) < 0) goto cleanup_packfile; if (packed_write_ref(ref, &pack_file) < 0) goto cleanup_packfile; } /* if we've written all the references properly, we can commit * the packfile to make the changes effective */ if (git_filebuf_commit(&pack_file, GIT_PACKEDREFS_FILE_MODE) < 0) goto cleanup_memory; /* when and only when the packfile has been properly written, * we can go ahead and remove the loose refs */ if (packed_remove_loose(backend, &packing_list) < 0) goto cleanup_memory; { struct stat st; if (p_stat(pack_file_path.ptr, &st) == 0) backend->refcache.packfile_time = st.st_mtime; } git_vector_free(&packing_list); git_buf_free(&pack_file_path); /* we're good now */ return 0; cleanup_packfile: git_filebuf_cleanup(&pack_file); cleanup_memory: git_vector_free(&packing_list); git_buf_free(&pack_file_path); return -1; } static int refdb_fs_backend__write( git_refdb_backend *_backend, const git_reference *ref, int force) { refdb_fs_backend *backend; int error; assert(_backend); backend = (refdb_fs_backend *)_backend; error = reference_path_available(backend, ref->name, NULL, force); if (error < 0) return error; return loose_write(backend, ref); } static int refdb_fs_backend__delete( git_refdb_backend *_backend, const char *ref_name) { refdb_fs_backend *backend; git_buf loose_path = GIT_BUF_INIT; struct packref *pack_ref; khiter_t pack_ref_pos; int error = 0; bool loose_deleted = 0; assert(_backend); assert(ref_name); backend = (refdb_fs_backend *)_backend; /* If a loose reference exists, remove it from the filesystem */ if (git_buf_joinpath(&loose_path, backend->path, ref_name) < 0) return -1; if (git_path_isfile(loose_path.ptr)) { error = p_unlink(loose_path.ptr); loose_deleted = 1; } git_buf_free(&loose_path); if (error != 0) return error; /* If a packed reference exists, remove it from the packfile and repack */ error = packed_map_entry(&pack_ref, &pack_ref_pos, backend, ref_name); if (error == GIT_ENOTFOUND) return loose_deleted ? 0 : GIT_ENOTFOUND; if (error == 0) { git_strmap_delete_at(backend->refcache.packfile, pack_ref_pos); git__free(pack_ref); error = packed_write(backend); } return error; } static int refdb_fs_backend__rename( git_reference **out, git_refdb_backend *_backend, const char *old_name, const char *new_name, int force) { refdb_fs_backend *backend; git_reference *old, *new; int error; assert(_backend); backend = (refdb_fs_backend *)_backend; error = reference_path_available(backend, new_name, old_name, force); if (error < 0) return error; error = refdb_fs_backend__lookup(&old, _backend, old_name); if (error < 0) return error; error = refdb_fs_backend__delete(_backend, old_name); if (error < 0) { git_reference_free(old); return error; } new = realloc(old, sizeof(git_reference) + strlen(new_name) + 1); memcpy(new->name, new_name, strlen(new_name) + 1); error = loose_write(backend, new); if (error < 0) { git_reference_free(new); return error; } if (out) { *out = new; } else { git_reference_free(new); } return 0; } static int refdb_fs_backend__compress(git_refdb_backend *_backend) { refdb_fs_backend *backend; assert(_backend); backend = (refdb_fs_backend *)_backend; if (packed_load(backend) < 0 || /* load the existing packfile */ packed_loadloose(backend) < 0 || /* add all the loose refs */ packed_write(backend) < 0) /* write back to disk */ return -1; return 0; } static void refcache_free(git_refcache *refs) { assert(refs); if (refs->packfile) { struct packref *reference; git_strmap_foreach_value(refs->packfile, reference, { git__free(reference); }); git_strmap_free(refs->packfile); } } static void refdb_fs_backend__free(git_refdb_backend *_backend) { refdb_fs_backend *backend; assert(_backend); backend = (refdb_fs_backend *)_backend; refcache_free(&backend->refcache); git__free(backend->path); git__free(backend); } static int setup_namespace(git_buf *path, git_repository *repo) { char *parts, *start, *end; /* Not all repositories have a path */ if (repo->path_repository == NULL) return 0; /* Load the path to the repo first */ git_buf_puts(path, repo->path_repository); /* if the repo is not namespaced, nothing else to do */ if (repo->namespace == NULL) return 0; parts = end = git__strdup(repo->namespace); if (parts == NULL) return -1; /** * From `man gitnamespaces`: * namespaces which include a / will expand to a hierarchy * of namespaces; for example, GIT_NAMESPACE=foo/bar will store * refs under refs/namespaces/foo/refs/namespaces/bar/ */ while ((start = git__strsep(&end, "/")) != NULL) { git_buf_printf(path, "refs/namespaces/%s/", start); } git_buf_printf(path, "refs/namespaces/%s/refs", end); git__free(parts); /* Make sure that the folder with the namespace exists */ if (git_futils_mkdir_r(git_buf_cstr(path), repo->path_repository, 0777) < 0) return -1; /* Return the root of the namespaced path, i.e. without the trailing '/refs' */ git_buf_rtruncate_at_char(path, '/'); return 0; } int git_refdb_backend_fs( git_refdb_backend **backend_out, git_repository *repository) { git_buf path = GIT_BUF_INIT; refdb_fs_backend *backend; backend = git__calloc(1, sizeof(refdb_fs_backend)); GITERR_CHECK_ALLOC(backend); backend->repo = repository; if (setup_namespace(&path, repository) < 0) { git__free(backend); return -1; } backend->path = git_buf_detach(&path); backend->parent.exists = &refdb_fs_backend__exists; backend->parent.lookup = &refdb_fs_backend__lookup; backend->parent.iterator = &refdb_fs_backend__iterator; backend->parent.write = &refdb_fs_backend__write; backend->parent.delete = &refdb_fs_backend__delete; backend->parent.rename = &refdb_fs_backend__rename; backend->parent.compress = &refdb_fs_backend__compress; backend->parent.free = &refdb_fs_backend__free; *backend_out = (git_refdb_backend *)backend; return 0; } libgit2-0.19.0/src/refdb_fs.h000066400000000000000000000005511216214232500156460ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #ifndef INCLUDE_refdb_fs_h__ #define INCLUDE_refdb_fs_h__ typedef struct { git_strmap *packfile; time_t packfile_time; } git_refcache; #endif libgit2-0.19.0/src/reflog.c000066400000000000000000000260461216214232500153540ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #include "reflog.h" #include "repository.h" #include "filebuf.h" #include "signature.h" static int reflog_init(git_reflog **reflog, const git_reference *ref) { git_reflog *log; *reflog = NULL; log = git__calloc(1, sizeof(git_reflog)); GITERR_CHECK_ALLOC(log); log->ref_name = git__strdup(ref->name); GITERR_CHECK_ALLOC(log->ref_name); if (git_vector_init(&log->entries, 0, NULL) < 0) { git__free(log->ref_name); git__free(log); return -1; } log->owner = git_reference_owner(ref); *reflog = log; return 0; } static int serialize_reflog_entry( git_buf *buf, const git_oid *oid_old, const git_oid *oid_new, const git_signature *committer, const char *msg) { char raw_old[GIT_OID_HEXSZ+1]; char raw_new[GIT_OID_HEXSZ+1]; git_oid_tostr(raw_old, GIT_OID_HEXSZ+1, oid_old); git_oid_tostr(raw_new, GIT_OID_HEXSZ+1, oid_new); git_buf_clear(buf); git_buf_puts(buf, raw_old); git_buf_putc(buf, ' '); git_buf_puts(buf, raw_new); git_signature__writebuf(buf, " ", committer); /* drop trailing LF */ git_buf_rtrim(buf); if (msg) { git_buf_putc(buf, '\t'); git_buf_puts(buf, msg); } git_buf_putc(buf, '\n'); return git_buf_oom(buf); } static int reflog_entry_new(git_reflog_entry **entry) { git_reflog_entry *e; assert(entry); e = git__malloc(sizeof(git_reflog_entry)); GITERR_CHECK_ALLOC(e); memset(e, 0, sizeof(git_reflog_entry)); *entry = e; return 0; } static void reflog_entry_free(git_reflog_entry *entry) { git_signature_free(entry->committer); git__free(entry->msg); git__free(entry); } static int reflog_parse(git_reflog *log, const char *buf, size_t buf_size) { const char *ptr; git_reflog_entry *entry; #define seek_forward(_increase) do { \ if (_increase >= buf_size) { \ giterr_set(GITERR_INVALID, "Ran out of data while parsing reflog"); \ goto fail; \ } \ buf += _increase; \ buf_size -= _increase; \ } while (0) while (buf_size > GIT_REFLOG_SIZE_MIN) { if (reflog_entry_new(&entry) < 0) return -1; entry->committer = git__malloc(sizeof(git_signature)); GITERR_CHECK_ALLOC(entry->committer); if (git_oid_fromstrn(&entry->oid_old, buf, GIT_OID_HEXSZ) < 0) goto fail; seek_forward(GIT_OID_HEXSZ + 1); if (git_oid_fromstrn(&entry->oid_cur, buf, GIT_OID_HEXSZ) < 0) goto fail; seek_forward(GIT_OID_HEXSZ + 1); ptr = buf; /* Seek forward to the end of the signature. */ while (*buf && *buf != '\t' && *buf != '\n') seek_forward(1); if (git_signature__parse(entry->committer, &ptr, buf + 1, NULL, *buf) < 0) goto fail; if (*buf == '\t') { /* We got a message. Read everything till we reach LF. */ seek_forward(1); ptr = buf; while (*buf && *buf != '\n') seek_forward(1); entry->msg = git__strndup(ptr, buf - ptr); GITERR_CHECK_ALLOC(entry->msg); } else entry->msg = NULL; while (*buf && *buf == '\n' && buf_size > 1) seek_forward(1); if (git_vector_insert(&log->entries, entry) < 0) goto fail; } return 0; #undef seek_forward fail: if (entry) reflog_entry_free(entry); return -1; } void git_reflog_free(git_reflog *reflog) { size_t i; git_reflog_entry *entry; if (reflog == NULL) return; for (i=0; i < reflog->entries.length; i++) { entry = git_vector_get(&reflog->entries, i); reflog_entry_free(entry); } git_vector_free(&reflog->entries); git__free(reflog->ref_name); git__free(reflog); } static int retrieve_reflog_path(git_buf *path, const git_reference *ref) { return git_buf_join_n(path, '/', 3, git_reference_owner(ref)->path_repository, GIT_REFLOG_DIR, ref->name); } static int create_new_reflog_file(const char *filepath) { int fd, error; if ((error = git_futils_mkpath2file(filepath, GIT_REFLOG_DIR_MODE)) < 0) return error; if ((fd = p_open(filepath, O_WRONLY | O_CREAT | O_TRUNC, GIT_REFLOG_FILE_MODE)) < 0) return -1; return p_close(fd); } int git_reflog_read(git_reflog **reflog, const git_reference *ref) { int error = -1; git_buf log_path = GIT_BUF_INIT; git_buf log_file = GIT_BUF_INIT; git_reflog *log = NULL; assert(reflog && ref); *reflog = NULL; if (reflog_init(&log, ref) < 0) return -1; if (retrieve_reflog_path(&log_path, ref) < 0) goto cleanup; error = git_futils_readbuffer(&log_file, git_buf_cstr(&log_path)); if (error < 0 && error != GIT_ENOTFOUND) goto cleanup; if ((error == GIT_ENOTFOUND) && ((error = create_new_reflog_file(git_buf_cstr(&log_path))) < 0)) goto cleanup; if ((error = reflog_parse(log, git_buf_cstr(&log_file), git_buf_len(&log_file))) < 0) goto cleanup; *reflog = log; goto success; cleanup: git_reflog_free(log); success: git_buf_free(&log_file); git_buf_free(&log_path); return error; } int git_reflog_write(git_reflog *reflog) { int error = -1; unsigned int i; git_reflog_entry *entry; git_buf log_path = GIT_BUF_INIT; git_buf log = GIT_BUF_INIT; git_filebuf fbuf = GIT_FILEBUF_INIT; assert(reflog); if (git_buf_join_n(&log_path, '/', 3, git_repository_path(reflog->owner), GIT_REFLOG_DIR, reflog->ref_name) < 0) return -1; if (!git_path_isfile(git_buf_cstr(&log_path))) { giterr_set(GITERR_INVALID, "Log file for reference '%s' doesn't exist.", reflog->ref_name); goto cleanup; } if ((error = git_filebuf_open(&fbuf, git_buf_cstr(&log_path), 0)) < 0) goto cleanup; git_vector_foreach(&reflog->entries, i, entry) { if (serialize_reflog_entry(&log, &(entry->oid_old), &(entry->oid_cur), entry->committer, entry->msg) < 0) goto cleanup; if ((error = git_filebuf_write(&fbuf, log.ptr, log.size)) < 0) goto cleanup; } error = git_filebuf_commit(&fbuf, GIT_REFLOG_FILE_MODE); goto success; cleanup: git_filebuf_cleanup(&fbuf); success: git_buf_free(&log); git_buf_free(&log_path); return error; } int git_reflog_append(git_reflog *reflog, const git_oid *new_oid, const git_signature *committer, const char *msg) { git_reflog_entry *entry; const git_reflog_entry *previous; const char *newline; assert(reflog && new_oid && committer); if (reflog_entry_new(&entry) < 0) return -1; if ((entry->committer = git_signature_dup(committer)) == NULL) goto cleanup; if (msg != NULL) { if ((entry->msg = git__strdup(msg)) == NULL) goto cleanup; newline = strchr(msg, '\n'); if (newline) { if (newline[1] != '\0') { giterr_set(GITERR_INVALID, "Reflog message cannot contain newline"); goto cleanup; } entry->msg[newline - msg] = '\0'; } } previous = git_reflog_entry_byindex(reflog, 0); if (previous == NULL) git_oid_fromstr(&entry->oid_old, GIT_OID_HEX_ZERO); else git_oid_cpy(&entry->oid_old, &previous->oid_cur); git_oid_cpy(&entry->oid_cur, new_oid); if (git_vector_insert(&reflog->entries, entry) < 0) goto cleanup; return 0; cleanup: reflog_entry_free(entry); return -1; } int git_reflog_rename(git_reference *ref, const char *new_name) { int error = 0, fd; git_buf old_path = GIT_BUF_INIT; git_buf new_path = GIT_BUF_INIT; git_buf temp_path = GIT_BUF_INIT; git_buf normalized = GIT_BUF_INIT; assert(ref && new_name); if ((error = git_reference__normalize_name( &normalized, new_name, GIT_REF_FORMAT_ALLOW_ONELEVEL)) < 0) return error; if (git_buf_joinpath(&temp_path, git_reference_owner(ref)->path_repository, GIT_REFLOG_DIR) < 0) return -1; if (git_buf_joinpath(&old_path, git_buf_cstr(&temp_path), ref->name) < 0) return -1; if (git_buf_joinpath(&new_path, git_buf_cstr(&temp_path), git_buf_cstr(&normalized)) < 0) return -1; /* * Move the reflog to a temporary place. This two-phase renaming is required * in order to cope with funny renaming use cases when one tries to move a reference * to a partially colliding namespace: * - a/b -> a/b/c * - a/b/c/d -> a/b/c */ if (git_buf_joinpath(&temp_path, git_buf_cstr(&temp_path), "temp_reflog") < 0) return -1; if ((fd = git_futils_mktmp(&temp_path, git_buf_cstr(&temp_path))) < 0) { error = -1; goto cleanup; } p_close(fd); if (p_rename(git_buf_cstr(&old_path), git_buf_cstr(&temp_path)) < 0) { giterr_set(GITERR_OS, "Failed to rename reflog for %s", new_name); error = -1; goto cleanup; } if (git_path_isdir(git_buf_cstr(&new_path)) && (git_futils_rmdir_r(git_buf_cstr(&new_path), NULL, GIT_RMDIR_SKIP_NONEMPTY) < 0)) { error = -1; goto cleanup; } if (git_futils_mkpath2file(git_buf_cstr(&new_path), GIT_REFLOG_DIR_MODE) < 0) { error = -1; goto cleanup; } if (p_rename(git_buf_cstr(&temp_path), git_buf_cstr(&new_path)) < 0) { giterr_set(GITERR_OS, "Failed to rename reflog for %s", new_name); error = -1; } cleanup: git_buf_free(&temp_path); git_buf_free(&old_path); git_buf_free(&new_path); git_buf_free(&normalized); return error; } int git_reflog_delete(git_reference *ref) { int error; git_buf path = GIT_BUF_INIT; error = retrieve_reflog_path(&path, ref); if (!error && git_path_exists(path.ptr)) error = p_unlink(path.ptr); git_buf_free(&path); return error; } size_t git_reflog_entrycount(git_reflog *reflog) { assert(reflog); return reflog->entries.length; } GIT_INLINE(size_t) reflog_inverse_index(size_t idx, size_t total) { return (total - 1) - idx; } const git_reflog_entry * git_reflog_entry_byindex(git_reflog *reflog, size_t idx) { assert(reflog); if (idx >= reflog->entries.length) return NULL; return git_vector_get( &reflog->entries, reflog_inverse_index(idx, reflog->entries.length)); } const git_oid * git_reflog_entry_id_old(const git_reflog_entry *entry) { assert(entry); return &entry->oid_old; } const git_oid * git_reflog_entry_id_new(const git_reflog_entry *entry) { assert(entry); return &entry->oid_cur; } const git_signature * git_reflog_entry_committer(const git_reflog_entry *entry) { assert(entry); return entry->committer; } const char * git_reflog_entry_message(const git_reflog_entry *entry) { assert(entry); return entry->msg; } int git_reflog_drop( git_reflog *reflog, size_t idx, int rewrite_previous_entry) { size_t entrycount; git_reflog_entry *entry, *previous; assert(reflog); entrycount = git_reflog_entrycount(reflog); entry = (git_reflog_entry *)git_reflog_entry_byindex(reflog, idx); if (entry == NULL) { giterr_set(GITERR_REFERENCE, "No reflog entry at index "PRIuZ, idx); return GIT_ENOTFOUND; } reflog_entry_free(entry); if (git_vector_remove( &reflog->entries, reflog_inverse_index(idx, entrycount)) < 0) return -1; if (!rewrite_previous_entry) return 0; /* No need to rewrite anything when removing the most recent entry */ if (idx == 0) return 0; /* Have the latest entry just been dropped? */ if (entrycount == 1) return 0; entry = (git_reflog_entry *)git_reflog_entry_byindex(reflog, idx - 1); /* If the oldest entry has just been removed... */ if (idx == entrycount - 1) { /* ...clear the oid_old member of the "new" oldest entry */ if (git_oid_fromstr(&entry->oid_old, GIT_OID_HEX_ZERO) < 0) return -1; return 0; } previous = (git_reflog_entry *)git_reflog_entry_byindex(reflog, idx); git_oid_cpy(&entry->oid_old, &previous->oid_cur); return 0; } libgit2-0.19.0/src/reflog.h000066400000000000000000000013101216214232500153440ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #ifndef INCLUDE_reflog_h__ #define INCLUDE_reflog_h__ #include "common.h" #include "git2/reflog.h" #include "vector.h" #define GIT_REFLOG_DIR "logs/" #define GIT_REFLOG_DIR_MODE 0777 #define GIT_REFLOG_FILE_MODE 0666 #define GIT_REFLOG_SIZE_MIN (2*GIT_OID_HEXSZ+2+17) struct git_reflog_entry { git_oid oid_old; git_oid oid_cur; git_signature *committer; char *msg; }; struct git_reflog { char *ref_name; git_repository *owner; git_vector entries; }; #endif /* INCLUDE_reflog_h__ */ libgit2-0.19.0/src/refs.c000066400000000000000000000527771216214232500150470ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #include "refs.h" #include "hash.h" #include "repository.h" #include "fileops.h" #include "filebuf.h" #include "pack.h" #include "reflog.h" #include "refdb.h" #include #include #include #include #include #include #include GIT__USE_STRMAP; #define DEFAULT_NESTING_LEVEL 5 #define MAX_NESTING_LEVEL 10 enum { GIT_PACKREF_HAS_PEEL = 1, GIT_PACKREF_WAS_LOOSE = 2 }; static git_reference *alloc_ref(const char *name) { git_reference *ref; size_t namelen = strlen(name); if ((ref = git__calloc(1, sizeof(git_reference) + namelen + 1)) == NULL) return NULL; memcpy(ref->name, name, namelen + 1); return ref; } git_reference *git_reference__alloc_symbolic( const char *name, const char *target) { git_reference *ref; assert(name && target); ref = alloc_ref(name); if (!ref) return NULL; ref->type = GIT_REF_SYMBOLIC; if ((ref->target.symbolic = git__strdup(target)) == NULL) { git__free(ref); return NULL; } return ref; } git_reference *git_reference__alloc( const char *name, const git_oid *oid, const git_oid *peel) { git_reference *ref; assert(name && oid); ref = alloc_ref(name); if (!ref) return NULL; ref->type = GIT_REF_OID; git_oid_cpy(&ref->target.oid, oid); if (peel != NULL) git_oid_cpy(&ref->peel, peel); return ref; } void git_reference_free(git_reference *reference) { if (reference == NULL) return; if (reference->type == GIT_REF_SYMBOLIC) git__free(reference->target.symbolic); if (reference->db) GIT_REFCOUNT_DEC(reference->db, git_refdb__free); git__free(reference); } int git_reference_delete(git_reference *ref) { return git_refdb_delete(ref->db, ref->name); } int git_reference_lookup(git_reference **ref_out, git_repository *repo, const char *name) { return git_reference_lookup_resolved(ref_out, repo, name, 0); } int git_reference_name_to_id( git_oid *out, git_repository *repo, const char *name) { int error; git_reference *ref; if ((error = git_reference_lookup_resolved(&ref, repo, name, -1)) < 0) return error; git_oid_cpy(out, git_reference_target(ref)); git_reference_free(ref); return 0; } int git_reference_lookup_resolved( git_reference **ref_out, git_repository *repo, const char *name, int max_nesting) { char scan_name[GIT_REFNAME_MAX]; git_ref_t scan_type; int error = 0, nesting; git_reference *ref = NULL; git_refdb *refdb; assert(ref_out && repo && name); *ref_out = NULL; if (max_nesting > MAX_NESTING_LEVEL) max_nesting = MAX_NESTING_LEVEL; else if (max_nesting < 0) max_nesting = DEFAULT_NESTING_LEVEL; strncpy(scan_name, name, GIT_REFNAME_MAX); scan_type = GIT_REF_SYMBOLIC; if ((error = git_repository_refdb__weakptr(&refdb, repo)) < 0) return -1; if ((error = git_reference__normalize_name_lax(scan_name, GIT_REFNAME_MAX, name)) < 0) return error; for (nesting = max_nesting; nesting >= 0 && scan_type == GIT_REF_SYMBOLIC; nesting--) { if (nesting != max_nesting) { strncpy(scan_name, ref->target.symbolic, GIT_REFNAME_MAX); git_reference_free(ref); } if ((error = git_refdb_lookup(&ref, refdb, scan_name)) < 0) return error; scan_type = ref->type; } if (scan_type != GIT_REF_OID && max_nesting != 0) { giterr_set(GITERR_REFERENCE, "Cannot resolve reference (>%u levels deep)", max_nesting); git_reference_free(ref); return -1; } *ref_out = ref; return 0; } int git_reference_dwim(git_reference **out, git_repository *repo, const char *refname) { int error = 0, i; bool fallbackmode = true, foundvalid = false; git_reference *ref; git_buf refnamebuf = GIT_BUF_INIT, name = GIT_BUF_INIT; static const char* formatters[] = { "%s", GIT_REFS_DIR "%s", GIT_REFS_TAGS_DIR "%s", GIT_REFS_HEADS_DIR "%s", GIT_REFS_REMOTES_DIR "%s", GIT_REFS_REMOTES_DIR "%s/" GIT_HEAD_FILE, NULL }; if (*refname) git_buf_puts(&name, refname); else { git_buf_puts(&name, GIT_HEAD_FILE); fallbackmode = false; } for (i = 0; formatters[i] && (fallbackmode || i == 0); i++) { git_buf_clear(&refnamebuf); if ((error = git_buf_printf(&refnamebuf, formatters[i], git_buf_cstr(&name))) < 0) goto cleanup; if (!git_reference_is_valid_name(git_buf_cstr(&refnamebuf))) { error = GIT_EINVALIDSPEC; continue; } foundvalid = true; error = git_reference_lookup_resolved(&ref, repo, git_buf_cstr(&refnamebuf), -1); if (!error) { *out = ref; error = 0; goto cleanup; } if (error != GIT_ENOTFOUND) goto cleanup; } cleanup: if (error && !foundvalid) { /* never found a valid reference name */ giterr_set(GITERR_REFERENCE, "Could not use '%s' as valid reference name", git_buf_cstr(&name)); } git_buf_free(&name); git_buf_free(&refnamebuf); return error; } /** * Getters */ git_ref_t git_reference_type(const git_reference *ref) { assert(ref); return ref->type; } const char *git_reference_name(const git_reference *ref) { assert(ref); return ref->name; } git_repository *git_reference_owner(const git_reference *ref) { assert(ref); return ref->db->repo; } const git_oid *git_reference_target(const git_reference *ref) { assert(ref); if (ref->type != GIT_REF_OID) return NULL; return &ref->target.oid; } const git_oid *git_reference_target_peel(const git_reference *ref) { assert(ref); if (ref->type != GIT_REF_OID || git_oid_iszero(&ref->peel)) return NULL; return &ref->peel; } const char *git_reference_symbolic_target(const git_reference *ref) { assert(ref); if (ref->type != GIT_REF_SYMBOLIC) return NULL; return ref->target.symbolic; } static int reference__create( git_reference **ref_out, git_repository *repo, const char *name, const git_oid *oid, const char *symbolic, int force) { char normalized[GIT_REFNAME_MAX]; git_refdb *refdb; git_reference *ref = NULL; int error = 0; if (ref_out) *ref_out = NULL; error = git_reference__normalize_name_lax(normalized, sizeof(normalized), name); if (error < 0) return error; error = git_repository_refdb__weakptr(&refdb, repo); if (error < 0) return error; if (oid != NULL) { assert(symbolic == NULL); ref = git_reference__alloc(normalized, oid, NULL); } else { ref = git_reference__alloc_symbolic(normalized, symbolic); } GITERR_CHECK_ALLOC(ref); if ((error = git_refdb_write(refdb, ref, force)) < 0) { git_reference_free(ref); return error; } if (ref_out == NULL) git_reference_free(ref); else *ref_out = ref; return 0; } int git_reference_create( git_reference **ref_out, git_repository *repo, const char *name, const git_oid *oid, int force) { git_odb *odb; int error = 0; assert(repo && name && oid); /* Sanity check the reference being created - target must exist. */ if ((error = git_repository_odb__weakptr(&odb, repo)) < 0) return error; if (!git_odb_exists(odb, oid)) { giterr_set(GITERR_REFERENCE, "Target OID for the reference doesn't exist on the repository"); return -1; } return reference__create(ref_out, repo, name, oid, NULL, force); } int git_reference_symbolic_create( git_reference **ref_out, git_repository *repo, const char *name, const char *target, int force) { char normalized[GIT_REFNAME_MAX]; int error = 0; assert(repo && name && target); if ((error = git_reference__normalize_name_lax( normalized, sizeof(normalized), target)) < 0) return error; return reference__create(ref_out, repo, name, NULL, normalized, force); } int git_reference_set_target( git_reference **out, git_reference *ref, const git_oid *id) { assert(out && ref && id); if (ref->type != GIT_REF_OID) { giterr_set(GITERR_REFERENCE, "Cannot set OID on symbolic reference"); return -1; } return git_reference_create(out, ref->db->repo, ref->name, id, 1); } int git_reference_symbolic_set_target( git_reference **out, git_reference *ref, const char *target) { assert(out && ref && target); if (ref->type != GIT_REF_SYMBOLIC) { giterr_set(GITERR_REFERENCE, "Cannot set symbolic target on a direct reference"); return -1; } return git_reference_symbolic_create(out, ref->db->repo, ref->name, target, 1); } int git_reference_rename( git_reference **out, git_reference *ref, const char *new_name, int force) { unsigned int normalization_flags; char normalized[GIT_REFNAME_MAX]; bool should_head_be_updated = false; int error = 0; int reference_has_log; normalization_flags = ref->type == GIT_REF_SYMBOLIC ? GIT_REF_FORMAT_ALLOW_ONELEVEL : GIT_REF_FORMAT_NORMAL; if ((error = git_reference_normalize_name( normalized, sizeof(normalized), new_name, normalization_flags)) < 0) return error; /* Check if we have to update HEAD. */ if ((error = git_branch_is_head(ref)) < 0) return error; should_head_be_updated = (error > 0); if ((error = git_refdb_rename(out, ref->db, ref->name, new_name, force)) < 0) return error; /* Update HEAD it was poiting to the reference being renamed. */ if (should_head_be_updated && (error = git_repository_set_head(ref->db->repo, new_name)) < 0) { giterr_set(GITERR_REFERENCE, "Failed to update HEAD after renaming reference"); return error; } /* Rename the reflog file, if it exists. */ reference_has_log = git_reference_has_log(ref); if (reference_has_log < 0) return reference_has_log; if (reference_has_log && (error = git_reflog_rename(ref, new_name)) < 0) return error; return 0; } int git_reference_resolve(git_reference **ref_out, const git_reference *ref) { switch (git_reference_type(ref)) { case GIT_REF_OID: return git_reference_lookup(ref_out, ref->db->repo, ref->name); case GIT_REF_SYMBOLIC: return git_reference_lookup_resolved(ref_out, ref->db->repo, ref->target.symbolic, -1); default: giterr_set(GITERR_REFERENCE, "Invalid reference"); return -1; } } int git_reference_foreach( git_repository *repo, git_reference_foreach_cb callback, void *payload) { git_reference_iterator *iter; git_reference *ref; int error; if (git_reference_iterator_new(&iter, repo) < 0) return -1; while ((error = git_reference_next(&ref, iter)) == 0) { if (callback(ref, payload)) { error = GIT_EUSER; goto out; } } if (error == GIT_ITEROVER) error = 0; out: git_reference_iterator_free(iter); return error; } int git_reference_foreach_name( git_repository *repo, git_reference_foreach_name_cb callback, void *payload) { git_reference_iterator *iter; const char *refname; int error; if (git_reference_iterator_new(&iter, repo) < 0) return -1; while ((error = git_reference_next_name(&refname, iter)) == 0) { if (callback(refname, payload)) { error = GIT_EUSER; goto out; } } if (error == GIT_ITEROVER) error = 0; out: git_reference_iterator_free(iter); return error; } int git_reference_foreach_glob( git_repository *repo, const char *glob, git_reference_foreach_name_cb callback, void *payload) { git_reference_iterator *iter; const char *refname; int error; if (git_reference_iterator_glob_new(&iter, repo, glob) < 0) return -1; while ((error = git_reference_next_name(&refname, iter)) == 0) { if (callback(refname, payload)) { error = GIT_EUSER; goto out; } } if (error == GIT_ITEROVER) error = 0; out: git_reference_iterator_free(iter); return error; } int git_reference_iterator_new(git_reference_iterator **out, git_repository *repo) { git_refdb *refdb; if (git_repository_refdb__weakptr(&refdb, repo) < 0) return -1; return git_refdb_iterator(out, refdb, NULL); } int git_reference_iterator_glob_new( git_reference_iterator **out, git_repository *repo, const char *glob) { git_refdb *refdb; if (git_repository_refdb__weakptr(&refdb, repo) < 0) return -1; return git_refdb_iterator(out, refdb, glob); } int git_reference_next(git_reference **out, git_reference_iterator *iter) { return git_refdb_iterator_next(out, iter); } int git_reference_next_name(const char **out, git_reference_iterator *iter) { return git_refdb_iterator_next_name(out, iter); } void git_reference_iterator_free(git_reference_iterator *iter) { git_refdb_iterator_free(iter); } static int cb__reflist_add(const char *ref, void *data) { return git_vector_insert((git_vector *)data, git__strdup(ref)); } int git_reference_list( git_strarray *array, git_repository *repo) { git_vector ref_list; assert(array && repo); array->strings = NULL; array->count = 0; if (git_vector_init(&ref_list, 8, NULL) < 0) return -1; if (git_reference_foreach_name( repo, &cb__reflist_add, (void *)&ref_list) < 0) { git_vector_free(&ref_list); return -1; } array->strings = (char **)ref_list.contents; array->count = ref_list.length; return 0; } static int is_valid_ref_char(char ch) { if ((unsigned) ch <= ' ') return 0; switch (ch) { case '~': case '^': case ':': case '\\': case '?': case '[': case '*': return 0; default: return 1; } } static int ensure_segment_validity(const char *name) { const char *current = name; char prev = '\0'; const int lock_len = (int)strlen(GIT_FILELOCK_EXTENSION); int segment_len; if (*current == '.') return -1; /* Refname starts with "." */ for (current = name; ; current++) { if (*current == '\0' || *current == '/') break; if (!is_valid_ref_char(*current)) return -1; /* Illegal character in refname */ if (prev == '.' && *current == '.') return -1; /* Refname contains ".." */ if (prev == '@' && *current == '{') return -1; /* Refname contains "@{" */ prev = *current; } segment_len = (int)(current - name); /* A refname component can not end with ".lock" */ if (segment_len >= lock_len && !memcmp(current - lock_len, GIT_FILELOCK_EXTENSION, lock_len)) return -1; return segment_len; } static bool is_all_caps_and_underscore(const char *name, size_t len) { size_t i; char c; assert(name && len > 0); for (i = 0; i < len; i++) { c = name[i]; if ((c < 'A' || c > 'Z') && c != '_') return false; } if (*name == '_' || name[len - 1] == '_') return false; return true; } int git_reference__normalize_name( git_buf *buf, const char *name, unsigned int flags) { // Inspired from https://github.com/git/git/blob/f06d47e7e0d9db709ee204ed13a8a7486149f494/refs.c#L36-100 char *current; int segment_len, segments_count = 0, error = GIT_EINVALIDSPEC; unsigned int process_flags; bool normalize = (buf != NULL); assert(name); process_flags = flags; current = (char *)name; if (*current == '/') goto cleanup; if (normalize) git_buf_clear(buf); while (true) { segment_len = ensure_segment_validity(current); if (segment_len < 0) { if ((process_flags & GIT_REF_FORMAT_REFSPEC_PATTERN) && current[0] == '*' && (current[1] == '\0' || current[1] == '/')) { /* Accept one wildcard as a full refname component. */ process_flags &= ~GIT_REF_FORMAT_REFSPEC_PATTERN; segment_len = 1; } else goto cleanup; } if (segment_len > 0) { if (normalize) { size_t cur_len = git_buf_len(buf); git_buf_joinpath(buf, git_buf_cstr(buf), current); git_buf_truncate(buf, cur_len + segment_len + (segments_count ? 1 : 0)); if (git_buf_oom(buf)) { error = -1; goto cleanup; } } segments_count++; } /* No empty segment is allowed when not normalizing */ if (segment_len == 0 && !normalize) goto cleanup; if (current[segment_len] == '\0') break; current += segment_len + 1; } /* A refname can not be empty */ if (segment_len == 0 && segments_count == 0) goto cleanup; /* A refname can not end with "." */ if (current[segment_len - 1] == '.') goto cleanup; /* A refname can not end with "/" */ if (current[segment_len - 1] == '/') goto cleanup; if ((segments_count == 1 ) && !(flags & GIT_REF_FORMAT_ALLOW_ONELEVEL)) goto cleanup; if ((segments_count == 1 ) && !(flags & GIT_REF_FORMAT_REFSPEC_SHORTHAND) && !(is_all_caps_and_underscore(name, (size_t)segment_len) || ((flags & GIT_REF_FORMAT_REFSPEC_PATTERN) && !strcmp("*", name)))) goto cleanup; if ((segments_count > 1) && (is_all_caps_and_underscore(name, strchr(name, '/') - name))) goto cleanup; error = 0; cleanup: if (error == GIT_EINVALIDSPEC) giterr_set( GITERR_REFERENCE, "The given reference name '%s' is not valid", name); if (error && normalize) git_buf_free(buf); return error; } int git_reference_normalize_name( char *buffer_out, size_t buffer_size, const char *name, unsigned int flags) { git_buf buf = GIT_BUF_INIT; int error; if ((error = git_reference__normalize_name(&buf, name, flags)) < 0) goto cleanup; if (git_buf_len(&buf) > buffer_size - 1) { giterr_set( GITERR_REFERENCE, "The provided buffer is too short to hold the normalization of '%s'", name); error = GIT_EBUFS; goto cleanup; } git_buf_copy_cstr(buffer_out, buffer_size, &buf); error = 0; cleanup: git_buf_free(&buf); return error; } int git_reference__normalize_name_lax( char *buffer_out, size_t out_size, const char *name) { return git_reference_normalize_name( buffer_out, out_size, name, GIT_REF_FORMAT_ALLOW_ONELEVEL); } #define GIT_REF_TYPEMASK (GIT_REF_OID | GIT_REF_SYMBOLIC) int git_reference_cmp(git_reference *ref1, git_reference *ref2) { git_ref_t type1, type2; assert(ref1 && ref2); type1 = git_reference_type(ref1); type2 = git_reference_type(ref2); /* let's put symbolic refs before OIDs */ if (type1 != type2) return (type1 == GIT_REF_SYMBOLIC) ? -1 : 1; if (type1 == GIT_REF_SYMBOLIC) return strcmp(ref1->target.symbolic, ref2->target.symbolic); return git_oid__cmp(&ref1->target.oid, &ref2->target.oid); } static int reference__update_terminal( git_repository *repo, const char *ref_name, const git_oid *oid, int nesting) { git_reference *ref; int error = 0; if (nesting > MAX_NESTING_LEVEL) { giterr_set(GITERR_REFERENCE, "Reference chain too deep (%d)", nesting); return GIT_ENOTFOUND; } error = git_reference_lookup(&ref, repo, ref_name); /* If we haven't found the reference at all, create a new reference. */ if (error == GIT_ENOTFOUND) { giterr_clear(); return git_reference_create(NULL, repo, ref_name, oid, 0); } if (error < 0) return error; /* If the ref is a symbolic reference, follow its target. */ if (git_reference_type(ref) == GIT_REF_SYMBOLIC) { error = reference__update_terminal(repo, git_reference_symbolic_target(ref), oid, nesting+1); git_reference_free(ref); } else { git_reference_free(ref); error = git_reference_create(NULL, repo, ref_name, oid, 1); } return error; } /* * Starting with the reference given by `ref_name`, follows symbolic * references until a direct reference is found and updated the OID * on that direct reference to `oid`. */ int git_reference__update_terminal( git_repository *repo, const char *ref_name, const git_oid *oid) { return reference__update_terminal(repo, ref_name, oid, 0); } int git_reference_has_log( git_reference *ref) { git_buf path = GIT_BUF_INIT; int result; assert(ref); if (git_buf_join_n(&path, '/', 3, ref->db->repo->path_repository, GIT_REFLOG_DIR, ref->name) < 0) return -1; result = git_path_isfile(git_buf_cstr(&path)); git_buf_free(&path); return result; } int git_reference__is_branch(const char *ref_name) { return git__prefixcmp(ref_name, GIT_REFS_HEADS_DIR) == 0; } int git_reference_is_branch(git_reference *ref) { assert(ref); return git_reference__is_branch(ref->name); } int git_reference__is_remote(const char *ref_name) { return git__prefixcmp(ref_name, GIT_REFS_REMOTES_DIR) == 0; } int git_reference_is_remote(git_reference *ref) { assert(ref); return git_reference__is_remote(ref->name); } static int peel_error(int error, git_reference *ref, const char* msg) { giterr_set( GITERR_INVALID, "The reference '%s' cannot be peeled - %s", git_reference_name(ref), msg); return error; } int git_reference_peel( git_object **peeled, git_reference *ref, git_otype target_type) { git_reference *resolved = NULL; git_object *target = NULL; int error; assert(ref); if (ref->type == GIT_REF_OID) { resolved = ref; } else { if ((error = git_reference_resolve(&resolved, ref)) < 0) return peel_error(error, ref, "Cannot resolve reference"); } if (!git_oid_iszero(&resolved->peel)) { error = git_object_lookup(&target, git_reference_owner(ref), &resolved->peel, GIT_OBJ_ANY); } else { error = git_object_lookup(&target, git_reference_owner(ref), &resolved->target.oid, GIT_OBJ_ANY); } if (error < 0) { peel_error(error, ref, "Cannot retrieve reference target"); goto cleanup; } if (target_type == GIT_OBJ_ANY && git_object_type(target) != GIT_OBJ_TAG) error = git_object_dup(peeled, target); else error = git_object_peel(peeled, target, target_type); cleanup: git_object_free(target); if (resolved != ref) git_reference_free(resolved); return error; } int git_reference__is_valid_name( const char *refname, unsigned int flags) { int error; error = git_reference__normalize_name(NULL, refname, flags) == 0; giterr_clear(); return error; } int git_reference_is_valid_name( const char *refname) { return git_reference__is_valid_name( refname, GIT_REF_FORMAT_ALLOW_ONELEVEL); } const char *git_reference_shorthand(git_reference *ref) { const char *name = ref->name; if (!git__prefixcmp(name, GIT_REFS_HEADS_DIR)) return name + strlen(GIT_REFS_HEADS_DIR); else if (!git__prefixcmp(name, GIT_REFS_TAGS_DIR)) return name + strlen(GIT_REFS_TAGS_DIR); else if (!git__prefixcmp(name, GIT_REFS_REMOTES_DIR)) return name + strlen(GIT_REFS_REMOTES_DIR); else if (!git__prefixcmp(name, GIT_REFS_DIR)) return name + strlen(GIT_REFS_DIR); /* No shorthands are avaiable, so just return the name */ return name; } libgit2-0.19.0/src/refs.h000066400000000000000000000064551216214232500150440ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #ifndef INCLUDE_refs_h__ #define INCLUDE_refs_h__ #include "common.h" #include "git2/oid.h" #include "git2/refs.h" #include "git2/refdb.h" #include "strmap.h" #include "buffer.h" #include "oid.h" #define GIT_REFS_DIR "refs/" #define GIT_REFS_HEADS_DIR GIT_REFS_DIR "heads/" #define GIT_REFS_TAGS_DIR GIT_REFS_DIR "tags/" #define GIT_REFS_REMOTES_DIR GIT_REFS_DIR "remotes/" #define GIT_REFS_DIR_MODE 0777 #define GIT_REFS_FILE_MODE 0666 #define GIT_RENAMED_REF_FILE GIT_REFS_DIR "RENAMED-REF" #define GIT_SYMREF "ref: " #define GIT_PACKEDREFS_FILE "packed-refs" #define GIT_PACKEDREFS_HEADER "# pack-refs with: peeled fully-peeled " #define GIT_PACKEDREFS_FILE_MODE 0666 #define GIT_HEAD_FILE "HEAD" #define GIT_ORIG_HEAD_FILE "ORIG_HEAD" #define GIT_FETCH_HEAD_FILE "FETCH_HEAD" #define GIT_MERGE_HEAD_FILE "MERGE_HEAD" #define GIT_REVERT_HEAD_FILE "REVERT_HEAD" #define GIT_CHERRY_PICK_HEAD_FILE "CHERRY_PICK_HEAD" #define GIT_BISECT_LOG_FILE "BISECT_LOG" #define GIT_REBASE_MERGE_DIR "rebase-merge/" #define GIT_REBASE_MERGE_INTERACTIVE_FILE GIT_REBASE_MERGE_DIR "interactive" #define GIT_REBASE_APPLY_DIR "rebase-apply/" #define GIT_REBASE_APPLY_REBASING_FILE GIT_REBASE_APPLY_DIR "rebasing" #define GIT_REBASE_APPLY_APPLYING_FILE GIT_REBASE_APPLY_DIR "applying" #define GIT_REFS_HEADS_MASTER_FILE GIT_REFS_HEADS_DIR "master" #define GIT_STASH_FILE "stash" #define GIT_REFS_STASH_FILE GIT_REFS_DIR GIT_STASH_FILE #define GIT_REFNAME_MAX 1024 struct git_reference { git_refdb *db; git_ref_t type; union { git_oid oid; char *symbolic; } target; git_oid peel; char name[0]; }; int git_reference__normalize_name_lax(char *buffer_out, size_t out_size, const char *name); int git_reference__normalize_name(git_buf *buf, const char *name, unsigned int flags); int git_reference__update_terminal(git_repository *repo, const char *ref_name, const git_oid *oid); int git_reference__is_valid_name(const char *refname, unsigned int flags); int git_reference__is_branch(const char *ref_name); int git_reference__is_remote(const char *ref_name); /** * Lookup a reference by name and try to resolve to an OID. * * You can control how many dereferences this will attempt to resolve the * reference with the `max_deref` parameter, or pass -1 to use a sane * default. If you pass 0 for `max_deref`, this will not attempt to resolve * the reference. For any value of `max_deref` other than 0, not * successfully resolving the reference will be reported as an error. * The generated reference must be freed by the user. * * @param reference_out Pointer to the looked-up reference * @param repo The repository to look up the reference * @param name The long name for the reference (e.g. HEAD, ref/heads/master, refs/tags/v0.1.0, ...) * @param max_deref Maximum number of dereferences to make of symbolic refs, 0 means simple lookup, < 0 means use default reasonable value * @return 0 on success or < 0 on error; not being able to resolve the reference is an error unless 0 was passed for max_deref */ int git_reference_lookup_resolved( git_reference **reference_out, git_repository *repo, const char *name, int max_deref); #endif libgit2-0.19.0/src/refspec.c000066400000000000000000000146751216214232500155320ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #include "git2/errors.h" #include "common.h" #include "refspec.h" #include "util.h" #include "posix.h" #include "refs.h" int git_refspec__parse(git_refspec *refspec, const char *input, bool is_fetch) { // Ported from https://github.com/git/git/blob/f06d47e7e0d9db709ee204ed13a8a7486149f494/remote.c#L518-636 size_t llen; int is_glob = 0; const char *lhs, *rhs; int flags; assert(refspec && input); memset(refspec, 0x0, sizeof(git_refspec)); refspec->push = !is_fetch; lhs = input; if (*lhs == '+') { refspec->force = 1; lhs++; } rhs = strrchr(lhs, ':'); /* * Before going on, special case ":" (or "+:") as a refspec * for matching refs. */ if (!is_fetch && rhs == lhs && rhs[1] == '\0') { refspec->matching = 1; return 0; } if (rhs) { size_t rlen = strlen(++rhs); is_glob = (1 <= rlen && strchr(rhs, '*')); refspec->dst = git__strndup(rhs, rlen); } llen = (rhs ? (size_t)(rhs - lhs - 1) : strlen(lhs)); if (1 <= llen && memchr(lhs, '*', llen)) { if ((rhs && !is_glob) || (!rhs && is_fetch)) goto invalid; is_glob = 1; } else if (rhs && is_glob) goto invalid; refspec->pattern = is_glob; refspec->src = git__strndup(lhs, llen); flags = GIT_REF_FORMAT_ALLOW_ONELEVEL | GIT_REF_FORMAT_REFSPEC_SHORTHAND | (is_glob ? GIT_REF_FORMAT_REFSPEC_PATTERN : 0); if (is_fetch) { /* * LHS * - empty is allowed; it means HEAD. * - otherwise it must be a valid looking ref. */ if (!*refspec->src) ; /* empty is ok */ else if (!git_reference__is_valid_name(refspec->src, flags)) goto invalid; /* * RHS * - missing is ok, and is same as empty. * - empty is ok; it means not to store. * - otherwise it must be a valid looking ref. */ if (!refspec->dst) ; /* ok */ else if (!*refspec->dst) ; /* ok */ else if (!git_reference__is_valid_name(refspec->dst, flags)) goto invalid; } else { /* * LHS * - empty is allowed; it means delete. * - when wildcarded, it must be a valid looking ref. * - otherwise, it must be an extended SHA-1, but * there is no existing way to validate this. */ if (!*refspec->src) ; /* empty is ok */ else if (is_glob) { if (!git_reference__is_valid_name(refspec->src, flags)) goto invalid; } else { ; /* anything goes, for now */ } /* * RHS * - missing is allowed, but LHS then must be a * valid looking ref. * - empty is not allowed. * - otherwise it must be a valid looking ref. */ if (!refspec->dst) { if (!git_reference__is_valid_name(refspec->src, flags)) goto invalid; } else if (!*refspec->dst) { goto invalid; } else { if (!git_reference__is_valid_name(refspec->dst, flags)) goto invalid; } } refspec->string = git__strdup(input); GITERR_CHECK_ALLOC(refspec->string); return 0; invalid: return -1; } void git_refspec__free(git_refspec *refspec) { if (refspec == NULL) return; git__free(refspec->src); git__free(refspec->dst); git__free(refspec->string); } const char *git_refspec_src(const git_refspec *refspec) { return refspec == NULL ? NULL : refspec->src; } const char *git_refspec_dst(const git_refspec *refspec) { return refspec == NULL ? NULL : refspec->dst; } const char *git_refspec_string(const git_refspec *refspec) { return refspec == NULL ? NULL : refspec->string; } int git_refspec_force(const git_refspec *refspec) { assert(refspec); return refspec->force; } int git_refspec_src_matches(const git_refspec *refspec, const char *refname) { if (refspec == NULL || refspec->src == NULL) return false; return (p_fnmatch(refspec->src, refname, 0) == 0); } int git_refspec_dst_matches(const git_refspec *refspec, const char *refname) { if (refspec == NULL || refspec->dst == NULL) return false; return (p_fnmatch(refspec->dst, refname, 0) == 0); } static int refspec_transform_internal(char *out, size_t outlen, const char *from, const char *to, const char *name) { size_t baselen, namelen; baselen = strlen(to); if (outlen <= baselen) { giterr_set(GITERR_INVALID, "Reference name too long"); return GIT_EBUFS; } /* * No '*' at the end means that it's mapped to one specific local * branch, so no actual transformation is needed. */ if (to[baselen - 1] != '*') { memcpy(out, to, baselen + 1); /* include '\0' */ return 0; } /* There's a '*' at the end, so remove its length */ baselen--; /* skip the prefix, -1 is for the '*' */ name += strlen(from) - 1; namelen = strlen(name); if (outlen <= baselen + namelen) { giterr_set(GITERR_INVALID, "Reference name too long"); return GIT_EBUFS; } memcpy(out, to, baselen); memcpy(out + baselen, name, namelen + 1); return 0; } int git_refspec_transform(char *out, size_t outlen, const git_refspec *spec, const char *name) { return refspec_transform_internal(out, outlen, spec->src, spec->dst, name); } int git_refspec_rtransform(char *out, size_t outlen, const git_refspec *spec, const char *name) { return refspec_transform_internal(out, outlen, spec->dst, spec->src, name); } static int refspec_transform(git_buf *out, const char *from, const char *to, const char *name) { if (git_buf_sets(out, to) < 0) return -1; /* * No '*' at the end means that it's mapped to one specific * branch, so no actual transformation is needed. */ if (git_buf_len(out) > 0 && out->ptr[git_buf_len(out) - 1] != '*') return 0; git_buf_truncate(out, git_buf_len(out) - 1); /* remove trailing '*' */ git_buf_puts(out, name + strlen(from) - 1); if (git_buf_oom(out)) return -1; return 0; } int git_refspec_transform_r(git_buf *out, const git_refspec *spec, const char *name) { return refspec_transform(out, spec->src, spec->dst, name); } int git_refspec_transform_l(git_buf *out, const git_refspec *spec, const char *name) { return refspec_transform(out, spec->dst, spec->src, name); } int git_refspec__serialize(git_buf *out, const git_refspec *refspec) { if (refspec->force) git_buf_putc(out, '+'); git_buf_printf(out, "%s:%s", refspec->src != NULL ? refspec->src : "", refspec->dst != NULL ? refspec->dst : ""); return git_buf_oom(out) == false; } int git_refspec_is_wildcard(const git_refspec *spec) { assert(spec && spec->src); return (spec->src[strlen(spec->src) - 1] == '*'); } git_direction git_refspec_direction(const git_refspec *spec) { assert(spec); return spec->push; } libgit2-0.19.0/src/refspec.h000066400000000000000000000033451216214232500155270ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #ifndef INCLUDE_refspec_h__ #define INCLUDE_refspec_h__ #include "git2/refspec.h" #include "buffer.h" struct git_refspec { char *string; char *src; char *dst; unsigned int force :1, push : 1, pattern :1, dwim :1, matching :1; }; #define GIT_REFSPEC_TAGS "refs/tags/*:refs/tags/*" int git_refspec_parse(struct git_refspec *refspec, const char *str); int git_refspec__parse( struct git_refspec *refspec, const char *str, bool is_fetch); void git_refspec__free(git_refspec *refspec); /** * Transform a reference to its target following the refspec's rules, * and writes the results into a git_buf. * * @param out where to store the target name * @param spec the refspec * @param name the name of the reference to transform * @return 0 or error if buffer allocation fails */ int git_refspec_transform_r(git_buf *out, const git_refspec *spec, const char *name); /** * Transform a reference from its target following the refspec's rules, * and writes the results into a git_buf. * * @param out where to store the source name * @param spec the refspec * @param name the name of the reference to transform * @return 0 or error if buffer allocation fails */ int git_refspec_transform_l(git_buf *out, const git_refspec *spec, const char *name); int git_refspec__serialize(git_buf *out, const git_refspec *refspec); /** * Determines if a refspec is a wildcard refspec. * * @param spec the refspec * @return 1 if the refspec is a wildcard, 0 otherwise */ int git_refspec_is_wildcard(const git_refspec *spec); #endif libgit2-0.19.0/src/remote.c000066400000000000000000001030351216214232500153630ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #include "git2/config.h" #include "git2/types.h" #include "git2/oid.h" #include "git2/net.h" #include "config.h" #include "repository.h" #include "remote.h" #include "fetch.h" #include "refs.h" #include "refspec.h" #include "fetchhead.h" #include static int add_refspec(git_remote *remote, const char *string, bool is_fetch) { git_refspec *spec; spec = git__calloc(1, sizeof(git_refspec)); GITERR_CHECK_ALLOC(spec); if (git_refspec__parse(spec, string, is_fetch) < 0) { git__free(spec); return -1; } spec->push = !is_fetch; if (git_vector_insert(&remote->refspecs, spec) < 0) { git_refspec__free(spec); git__free(spec); return -1; } return 0; } static int download_tags_value(git_remote *remote, git_config *cfg) { const char *val; git_buf buf = GIT_BUF_INIT; int error; /* The 0 value is the default (auto), let's see if we need to change it */ if (git_buf_printf(&buf, "remote.%s.tagopt", remote->name) < 0) return -1; error = git_config_get_string(&val, cfg, git_buf_cstr(&buf)); git_buf_free(&buf); if (!error && !strcmp(val, "--no-tags")) remote->download_tags = GIT_REMOTE_DOWNLOAD_TAGS_NONE; else if (!error && !strcmp(val, "--tags")) remote->download_tags = GIT_REMOTE_DOWNLOAD_TAGS_ALL; if (error == GIT_ENOTFOUND) { giterr_clear(); error = 0; } return error; } static int ensure_remote_name_is_valid(const char *name) { int error = 0; if (!git_remote_is_valid_name(name)) { giterr_set( GITERR_CONFIG, "'%s' is not a valid remote name.", name); error = GIT_EINVALIDSPEC; } return error; } static int create_internal(git_remote **out, git_repository *repo, const char *name, const char *url, const char *fetch) { git_remote *remote; git_buf fetchbuf = GIT_BUF_INIT; int error = -1; /* name is optional */ assert(out && repo && url); remote = git__calloc(1, sizeof(git_remote)); GITERR_CHECK_ALLOC(remote); remote->repo = repo; remote->check_cert = 1; remote->update_fetchhead = 1; if (git_vector_init(&remote->refs, 32, NULL) < 0) goto on_error; remote->url = git__strdup(url); GITERR_CHECK_ALLOC(remote->url); if (name != NULL) { remote->name = git__strdup(name); GITERR_CHECK_ALLOC(remote->name); } if (fetch != NULL) { if (add_refspec(remote, fetch, true) < 0) goto on_error; } if (!name) /* A remote without a name doesn't download tags */ remote->download_tags = GIT_REMOTE_DOWNLOAD_TAGS_NONE; *out = remote; git_buf_free(&fetchbuf); return 0; on_error: git_remote_free(remote); git_buf_free(&fetchbuf); return error; } static int ensure_remote_doesnot_exist(git_repository *repo, const char *name) { int error; git_remote *remote; error = git_remote_load(&remote, repo, name); if (error == GIT_ENOTFOUND) return 0; if (error < 0) return error; git_remote_free(remote); giterr_set( GITERR_CONFIG, "Remote '%s' already exists.", name); return GIT_EEXISTS; } int git_remote_create(git_remote **out, git_repository *repo, const char *name, const char *url) { git_buf buf = GIT_BUF_INIT; git_remote *remote = NULL; int error; if ((error = ensure_remote_name_is_valid(name)) < 0) return error; if ((error = ensure_remote_doesnot_exist(repo, name)) < 0) return error; if (git_buf_printf(&buf, "+refs/heads/*:refs/remotes/%s/*", name) < 0) return -1; if (create_internal(&remote, repo, name, url, git_buf_cstr(&buf)) < 0) goto on_error; git_buf_free(&buf); if (git_remote_save(remote) < 0) goto on_error; *out = remote; return 0; on_error: git_buf_free(&buf); git_remote_free(remote); return -1; } int git_remote_create_inmemory(git_remote **out, git_repository *repo, const char *fetch, const char *url) { int error; git_remote *remote; if ((error = create_internal(&remote, repo, NULL, url, fetch)) < 0) return error; *out = remote; return 0; } struct refspec_cb_data { git_remote *remote; int fetch; }; static int refspec_cb(const git_config_entry *entry, void *payload) { const struct refspec_cb_data *data = (struct refspec_cb_data *)payload; return add_refspec(data->remote, entry->value, data->fetch); } static int get_optional_config( git_config *config, git_buf *buf, git_config_foreach_cb cb, void *payload) { int error = 0; const char *key = git_buf_cstr(buf); if (git_buf_oom(buf)) return -1; if (cb != NULL) error = git_config_get_multivar(config, key, NULL, cb, payload); else error = git_config_get_string(payload, config, key); if (error == GIT_ENOTFOUND) { giterr_clear(); error = 0; } if (error < 0) error = -1; return error; } int git_remote_load(git_remote **out, git_repository *repo, const char *name) { git_remote *remote; git_buf buf = GIT_BUF_INIT; const char *val; int error = 0; git_config *config; struct refspec_cb_data data; assert(out && repo && name); if ((error = ensure_remote_name_is_valid(name)) < 0) return error; if (git_repository_config__weakptr(&config, repo) < 0) return -1; remote = git__malloc(sizeof(git_remote)); GITERR_CHECK_ALLOC(remote); memset(remote, 0x0, sizeof(git_remote)); remote->check_cert = 1; remote->update_fetchhead = 1; remote->name = git__strdup(name); GITERR_CHECK_ALLOC(remote->name); if ((git_vector_init(&remote->refs, 32, NULL) < 0) || (git_vector_init(&remote->refspecs, 2, NULL))) { error = -1; goto cleanup; } if (git_buf_printf(&buf, "remote.%s.url", name) < 0) { error = -1; goto cleanup; } if ((error = git_config_get_string(&val, config, git_buf_cstr(&buf))) < 0) goto cleanup; if (strlen(val) == 0) { giterr_set(GITERR_INVALID, "Malformed remote '%s' - missing URL", name); error = -1; goto cleanup; } remote->repo = repo; remote->url = git__strdup(val); GITERR_CHECK_ALLOC(remote->url); val = NULL; git_buf_clear(&buf); git_buf_printf(&buf, "remote.%s.pushurl", name); if ((error = get_optional_config(config, &buf, NULL, (void *)&val)) < 0) goto cleanup; if (val) { remote->pushurl = git__strdup(val); GITERR_CHECK_ALLOC(remote->pushurl); } data.remote = remote; data.fetch = true; git_buf_clear(&buf); git_buf_printf(&buf, "remote.%s.fetch", name); if ((error = get_optional_config(config, &buf, refspec_cb, &data)) < 0) goto cleanup; data.fetch = false; git_buf_clear(&buf); git_buf_printf(&buf, "remote.%s.push", name); if ((error = get_optional_config(config, &buf, refspec_cb, &data)) < 0) goto cleanup; if (download_tags_value(remote, config) < 0) goto cleanup; *out = remote; cleanup: git_buf_free(&buf); if (error < 0) git_remote_free(remote); return error; } static int update_config_refspec(const git_remote *remote, git_config *config, int direction) { git_buf name = GIT_BUF_INIT; int push; const char *dir; size_t i; int error = 0; push = direction == GIT_DIRECTION_PUSH; dir = push ? "push" : "fetch"; if (git_buf_printf(&name, "remote.%s.%s", remote->name, dir) < 0) return -1; /* Clear out the existing config */ while (!error) error = git_config_delete_entry(config, git_buf_cstr(&name)); if (error != GIT_ENOTFOUND) return error; for (i = 0; i < remote->refspecs.length; i++) { git_refspec *spec = git_vector_get(&remote->refspecs, i); if (spec->push != push) continue; if ((error = git_config_set_multivar( config, git_buf_cstr(&name), "", spec->string)) < 0) { goto cleanup; } } giterr_clear(); error = 0; cleanup: git_buf_free(&name); return error; } int git_remote_save(const git_remote *remote) { int error; git_config *config; const char *tagopt = NULL; git_buf buf = GIT_BUF_INIT; assert(remote); if (!remote->name) { giterr_set(GITERR_INVALID, "Can't save an in-memory remote."); return GIT_EINVALIDSPEC; } if ((error = ensure_remote_name_is_valid(remote->name)) < 0) return error; if (git_repository_config__weakptr(&config, remote->repo) < 0) return -1; if (git_buf_printf(&buf, "remote.%s.url", remote->name) < 0) return -1; if (git_config_set_string(config, git_buf_cstr(&buf), remote->url) < 0) { git_buf_free(&buf); return -1; } git_buf_clear(&buf); if (git_buf_printf(&buf, "remote.%s.pushurl", remote->name) < 0) return -1; if (remote->pushurl) { if (git_config_set_string(config, git_buf_cstr(&buf), remote->pushurl) < 0) { git_buf_free(&buf); return -1; } } else { int error = git_config_delete_entry(config, git_buf_cstr(&buf)); if (error == GIT_ENOTFOUND) { error = 0; giterr_clear(); } if (error < 0) { git_buf_free(&buf); return -1; } } if (update_config_refspec(remote, config, GIT_DIRECTION_FETCH) < 0) goto on_error; if (update_config_refspec(remote, config, GIT_DIRECTION_PUSH) < 0) goto on_error; /* * What action to take depends on the old and new values. This * is describes by the table below. tagopt means whether the * is already a value set in the config * * AUTO ALL or NONE * +-----------------------+ * tagopt | remove | set | * +---------+-------------| * !tagopt | nothing | set | * +---------+-------------+ */ git_buf_clear(&buf); if (git_buf_printf(&buf, "remote.%s.tagopt", remote->name) < 0) goto on_error; error = git_config_get_string(&tagopt, config, git_buf_cstr(&buf)); if (error < 0 && error != GIT_ENOTFOUND) goto on_error; if (remote->download_tags == GIT_REMOTE_DOWNLOAD_TAGS_ALL) { if (git_config_set_string(config, git_buf_cstr(&buf), "--tags") < 0) goto on_error; } else if (remote->download_tags == GIT_REMOTE_DOWNLOAD_TAGS_NONE) { if (git_config_set_string(config, git_buf_cstr(&buf), "--no-tags") < 0) goto on_error; } else if (tagopt) { if (git_config_delete_entry(config, git_buf_cstr(&buf)) < 0) goto on_error; } git_buf_free(&buf); return 0; on_error: git_buf_free(&buf); return -1; } const char *git_remote_name(const git_remote *remote) { assert(remote); return remote->name; } const char *git_remote_url(const git_remote *remote) { assert(remote); return remote->url; } int git_remote_set_url(git_remote *remote, const char* url) { assert(remote); assert(url); git__free(remote->url); remote->url = git__strdup(url); GITERR_CHECK_ALLOC(remote->url); return 0; } const char *git_remote_pushurl(const git_remote *remote) { assert(remote); return remote->pushurl; } int git_remote_set_pushurl(git_remote *remote, const char* url) { assert(remote); git__free(remote->pushurl); if (url) { remote->pushurl = git__strdup(url); GITERR_CHECK_ALLOC(remote->pushurl); } else { remote->pushurl = NULL; } return 0; } const char* git_remote__urlfordirection(git_remote *remote, int direction) { assert(remote); if (direction == GIT_DIRECTION_FETCH) { return remote->url; } if (direction == GIT_DIRECTION_PUSH) { return remote->pushurl ? remote->pushurl : remote->url; } return NULL; } int git_remote_connect(git_remote *remote, git_direction direction) { git_transport *t; const char *url; int flags = GIT_TRANSPORTFLAGS_NONE; assert(remote); t = remote->transport; url = git_remote__urlfordirection(remote, direction); if (url == NULL ) return -1; /* A transport could have been supplied in advance with * git_remote_set_transport */ if (!t && git_transport_new(&t, remote, url) < 0) return -1; if (t->set_callbacks && t->set_callbacks(t, remote->callbacks.progress, NULL, remote->callbacks.payload) < 0) goto on_error; if (!remote->check_cert) flags |= GIT_TRANSPORTFLAGS_NO_CHECK_CERT; if (t->connect(t, url, remote->cred_acquire_cb, remote->cred_acquire_payload, direction, flags) < 0) goto on_error; remote->transport = t; return 0; on_error: t->free(t); if (t == remote->transport) remote->transport = NULL; return -1; } int git_remote_ls(git_remote *remote, git_headlist_cb list_cb, void *payload) { assert(remote); return remote->transport->ls(remote->transport, list_cb, payload); } int git_remote__get_http_proxy(git_remote *remote, bool use_ssl, char **proxy_url) { git_config *cfg; const char *val; assert(remote); if (!proxy_url || !remote->repo) return -1; *proxy_url = NULL; if (git_repository_config__weakptr(&cfg, remote->repo) < 0) return -1; /* Go through the possible sources for proxy configuration, from most specific * to least specific. */ /* remote..proxy config setting */ if (remote->name && 0 != *(remote->name)) { git_buf buf = GIT_BUF_INIT; if (git_buf_printf(&buf, "remote.%s.proxy", remote->name) < 0) return -1; if (!git_config_get_string(&val, cfg, git_buf_cstr(&buf)) && val && ('\0' != *val)) { git_buf_free(&buf); *proxy_url = git__strdup(val); GITERR_CHECK_ALLOC(*proxy_url); return 0; } git_buf_free(&buf); } /* http.proxy config setting */ if (!git_config_get_string(&val, cfg, "http.proxy") && val && ('\0' != *val)) { *proxy_url = git__strdup(val); GITERR_CHECK_ALLOC(*proxy_url); return 0; } /* HTTP_PROXY / HTTPS_PROXY environment variables */ val = use_ssl ? getenv("HTTPS_PROXY") : getenv("HTTP_PROXY"); if (val && ('\0' != *val)) { *proxy_url = git__strdup(val); GITERR_CHECK_ALLOC(*proxy_url); return 0; } return 0; } static int store_refs(git_remote_head *head, void *payload) { git_vector *refs = (git_vector *)payload; return git_vector_insert(refs, head); } static int dwim_refspecs(git_vector *refspecs, git_vector *refs) { git_buf buf = GIT_BUF_INIT; git_refspec *spec; size_t i, j, pos; git_remote_head key; const char* formatters[] = { GIT_REFS_DIR "%s", GIT_REFS_TAGS_DIR "%s", GIT_REFS_HEADS_DIR "%s", NULL }; git_vector_foreach(refspecs, i, spec) { if (spec->dwim) continue; /* shorthand on the lhs */ if (git__prefixcmp(spec->src, GIT_REFS_DIR)) { for (j = 0; formatters[j]; j++) { git_buf_clear(&buf); if (git_buf_printf(&buf, formatters[j], spec->src) < 0) return -1; key.name = (char *) git_buf_cstr(&buf); if (!git_vector_search(&pos, refs, &key)) { /* we found something to match the shorthand, set src to that */ git__free(spec->src); spec->src = git_buf_detach(&buf); } } } if (spec->dst && git__prefixcmp(spec->dst, GIT_REFS_DIR)) { /* if it starts with "remotes" then we just prepend "refs/" */ if (!git__prefixcmp(spec->dst, "remotes/")) { git_buf_puts(&buf, GIT_REFS_DIR); } else { git_buf_puts(&buf, GIT_REFS_HEADS_DIR); } if (git_buf_puts(&buf, spec->dst) < 0) return -1; git__free(spec->dst); spec->dst = git_buf_detach(&buf); } spec->dwim = 1; } git_buf_free(&buf); return 0; } static int remote_head_cmp(const void *_a, const void *_b) { const git_remote_head *a = (git_remote_head *) _a; const git_remote_head *b = (git_remote_head *) _b; return git__strcmp_cb(a->name, b->name); } int git_remote_download( git_remote *remote, git_transfer_progress_callback progress_cb, void *progress_payload) { int error; git_vector refs; assert(remote); if (git_vector_init(&refs, 16, remote_head_cmp) < 0) return -1; if (git_remote_ls(remote, store_refs, &refs) < 0) { return -1; } error = dwim_refspecs(&remote->refspecs, &refs); git_vector_free(&refs); if (error < 0) return -1; if ((error = git_fetch_negotiate(remote)) < 0) return error; return git_fetch_download_pack(remote, progress_cb, progress_payload); } static int remote_head_for_fetchspec_src(git_remote_head **out, git_vector *update_heads, const char *fetchspec_src) { unsigned int i; git_remote_head *remote_ref; assert(update_heads && fetchspec_src); *out = NULL; git_vector_foreach(update_heads, i, remote_ref) { if (strcmp(remote_ref->name, fetchspec_src) == 0) { *out = remote_ref; break; } } return 0; } static int remote_head_for_ref(git_remote_head **out, git_refspec *spec, git_vector *update_heads, git_reference *ref) { git_reference *resolved_ref = NULL; git_reference *tracking_ref = NULL; git_buf remote_name = GIT_BUF_INIT; int error = 0; assert(out && spec && ref); *out = NULL; if ((error = git_reference_resolve(&resolved_ref, ref)) < 0 || (!git_reference_is_branch(resolved_ref)) || (error = git_branch_upstream(&tracking_ref, resolved_ref)) < 0 || (error = git_refspec_transform_l(&remote_name, spec, git_reference_name(tracking_ref))) < 0) { /* Not an error if HEAD is orphaned or no tracking branch */ if (error == GIT_ENOTFOUND) error = 0; goto cleanup; } error = remote_head_for_fetchspec_src(out, update_heads, git_buf_cstr(&remote_name)); cleanup: git_reference_free(tracking_ref); git_reference_free(resolved_ref); git_buf_free(&remote_name); return error; } static int git_remote_write_fetchhead(git_remote *remote, git_refspec *spec, git_vector *update_heads) { git_reference *head_ref = NULL; git_fetchhead_ref *fetchhead_ref; git_remote_head *remote_ref, *merge_remote_ref; git_vector fetchhead_refs; bool include_all_fetchheads; unsigned int i = 0; int error = 0; assert(remote); /* no heads, nothing to do */ if (update_heads->length == 0) return 0; if (git_vector_init(&fetchhead_refs, update_heads->length, git_fetchhead_ref_cmp) < 0) return -1; /* Iff refspec is * (but not subdir slash star), include tags */ include_all_fetchheads = (strcmp(GIT_REFS_HEADS_DIR "*", git_refspec_src(spec)) == 0); /* Determine what to merge: if refspec was a wildcard, just use HEAD */ if (git_refspec_is_wildcard(spec)) { if ((error = git_reference_lookup(&head_ref, remote->repo, GIT_HEAD_FILE)) < 0 || (error = remote_head_for_ref(&merge_remote_ref, spec, update_heads, head_ref)) < 0) goto cleanup; } else { /* If we're fetching a single refspec, that's the only thing that should be in FETCH_HEAD. */ if ((error = remote_head_for_fetchspec_src(&merge_remote_ref, update_heads, git_refspec_src(spec))) < 0) goto cleanup; } /* Create the FETCH_HEAD file */ git_vector_foreach(update_heads, i, remote_ref) { int merge_this_fetchhead = (merge_remote_ref == remote_ref); if (!include_all_fetchheads && !git_refspec_src_matches(spec, remote_ref->name) && !merge_this_fetchhead) continue; if (git_fetchhead_ref_create(&fetchhead_ref, &remote_ref->oid, merge_this_fetchhead, remote_ref->name, git_remote_url(remote)) < 0) goto cleanup; if (git_vector_insert(&fetchhead_refs, fetchhead_ref) < 0) goto cleanup; } git_fetchhead_write(remote->repo, &fetchhead_refs); cleanup: for (i = 0; i < fetchhead_refs.length; ++i) git_fetchhead_ref_free(fetchhead_refs.contents[i]); git_vector_free(&fetchhead_refs); git_reference_free(head_ref); return error; } static int update_tips_for_spec(git_remote *remote, git_refspec *spec, git_vector *refs) { int error = 0, autotag; unsigned int i = 0; git_buf refname = GIT_BUF_INIT; git_oid old; git_odb *odb; git_remote_head *head; git_reference *ref; git_refspec tagspec; git_vector update_heads; assert(remote); if (git_repository_odb__weakptr(&odb, remote->repo) < 0) return -1; if (git_refspec__parse(&tagspec, GIT_REFSPEC_TAGS, true) < 0) return -1; /* Make a copy of the transport's refs */ if (git_vector_init(&update_heads, 16, NULL) < 0) return -1; for (; i < refs->length; ++i) { head = git_vector_get(refs, i); autotag = 0; /* Ignore malformed ref names (which also saves us from tag^{} */ if (!git_reference_is_valid_name(head->name)) continue; if (git_refspec_src_matches(spec, head->name) && spec->dst) { if (git_refspec_transform_r(&refname, spec, head->name) < 0) goto on_error; } else if (remote->download_tags != GIT_REMOTE_DOWNLOAD_TAGS_NONE) { if (remote->download_tags != GIT_REMOTE_DOWNLOAD_TAGS_ALL) autotag = 1; if (!git_refspec_src_matches(&tagspec, head->name)) continue; git_buf_clear(&refname); if (git_buf_puts(&refname, head->name) < 0) goto on_error; } else { continue; } if (autotag && !git_odb_exists(odb, &head->oid)) continue; if (git_vector_insert(&update_heads, head) < 0) goto on_error; error = git_reference_name_to_id(&old, remote->repo, refname.ptr); if (error < 0 && error != GIT_ENOTFOUND) goto on_error; if (error == GIT_ENOTFOUND) memset(&old, 0, GIT_OID_RAWSZ); if (!git_oid__cmp(&old, &head->oid)) continue; /* In autotag mode, don't overwrite any locally-existing tags */ error = git_reference_create(&ref, remote->repo, refname.ptr, &head->oid, !autotag); if (error < 0 && error != GIT_EEXISTS) goto on_error; git_reference_free(ref); if (remote->callbacks.update_tips != NULL) { if (remote->callbacks.update_tips(refname.ptr, &old, &head->oid, remote->callbacks.payload) < 0) goto on_error; } } if (git_remote_update_fetchhead(remote) && (error = git_remote_write_fetchhead(remote, spec, &update_heads)) < 0) goto on_error; git_vector_free(&update_heads); git_refspec__free(&tagspec); git_buf_free(&refname); return 0; on_error: git_vector_free(&update_heads); git_refspec__free(&tagspec); git_buf_free(&refname); return -1; } int git_remote_update_tips(git_remote *remote) { git_refspec *spec, tagspec; git_vector refs; int error; size_t i; if (git_refspec__parse(&tagspec, GIT_REFSPEC_TAGS, true) < 0) return -1; if (git_vector_init(&refs, 16, NULL) < 0) return -1; if ((error = git_remote_ls(remote, store_refs, &refs)) < 0) goto out; if (remote->download_tags == GIT_REMOTE_DOWNLOAD_TAGS_ALL) { error = update_tips_for_spec(remote, &tagspec, &refs); goto out; } git_vector_foreach(&remote->refspecs, i, spec) { if (spec->push) continue; if ((error = update_tips_for_spec(remote, spec, &refs)) < 0) goto out; } out: git_refspec__free(&tagspec); git_vector_free(&refs); return error; } int git_remote_connected(git_remote *remote) { assert(remote); if (!remote->transport || !remote->transport->is_connected) return 0; /* Ask the transport if it's connected. */ return remote->transport->is_connected(remote->transport); } void git_remote_stop(git_remote *remote) { assert(remote); if (remote->transport && remote->transport->cancel) remote->transport->cancel(remote->transport); } void git_remote_disconnect(git_remote *remote) { assert(remote); if (git_remote_connected(remote)) remote->transport->close(remote->transport); } void git_remote_free(git_remote *remote) { git_refspec *spec; size_t i; if (remote == NULL) return; if (remote->transport != NULL) { git_remote_disconnect(remote); remote->transport->free(remote->transport); remote->transport = NULL; } git_vector_free(&remote->refs); git_vector_foreach(&remote->refspecs, i, spec) { git_refspec__free(spec); git__free(spec); } git_vector_free(&remote->refspecs); git__free(remote->url); git__free(remote->pushurl); git__free(remote->name); git__free(remote); } struct cb_data { git_vector *list; regex_t *preg; }; static int remote_list_cb(const git_config_entry *entry, void *data_) { struct cb_data *data = (struct cb_data *)data_; size_t nmatch = 2; regmatch_t pmatch[2]; const char *name = entry->name; if (!regexec(data->preg, name, nmatch, pmatch, 0)) { char *remote_name = git__strndup(&name[pmatch[1].rm_so], pmatch[1].rm_eo - pmatch[1].rm_so); GITERR_CHECK_ALLOC(remote_name); if (git_vector_insert(data->list, remote_name) < 0) return -1; } return 0; } int git_remote_list(git_strarray *remotes_list, git_repository *repo) { git_config *cfg; git_vector list; regex_t preg; struct cb_data data; int error; if (git_repository_config__weakptr(&cfg, repo) < 0) return -1; if (git_vector_init(&list, 4, NULL) < 0) return -1; if (regcomp(&preg, "^remote\\.(.*)\\.url$", REG_EXTENDED) < 0) { giterr_set(GITERR_OS, "Remote catch regex failed to compile"); return -1; } data.list = &list; data.preg = &preg; error = git_config_foreach(cfg, remote_list_cb, &data); regfree(&preg); if (error < 0) { size_t i; char *elem; git_vector_foreach(&list, i, elem) { git__free(elem); } git_vector_free(&list); /* cb error is converted to GIT_EUSER by git_config_foreach */ if (error == GIT_EUSER) error = -1; return error; } remotes_list->strings = (char **)list.contents; remotes_list->count = list.length; return 0; } void git_remote_check_cert(git_remote *remote, int check) { assert(remote); remote->check_cert = check; } int git_remote_set_callbacks(git_remote *remote, git_remote_callbacks *callbacks) { assert(remote && callbacks); GITERR_CHECK_VERSION(callbacks, GIT_REMOTE_CALLBACKS_VERSION, "git_remote_callbacks"); memcpy(&remote->callbacks, callbacks, sizeof(git_remote_callbacks)); if (remote->transport && remote->transport->set_callbacks) remote->transport->set_callbacks(remote->transport, remote->callbacks.progress, NULL, remote->callbacks.payload); return 0; } void git_remote_set_cred_acquire_cb( git_remote *remote, git_cred_acquire_cb cred_acquire_cb, void *payload) { assert(remote); remote->cred_acquire_cb = cred_acquire_cb; remote->cred_acquire_payload = payload; } int git_remote_set_transport(git_remote *remote, git_transport *transport) { assert(remote && transport); GITERR_CHECK_VERSION(transport, GIT_TRANSPORT_VERSION, "git_transport"); if (remote->transport) { giterr_set(GITERR_NET, "A transport is already bound to this remote"); return -1; } remote->transport = transport; return 0; } const git_transfer_progress* git_remote_stats(git_remote *remote) { assert(remote); return &remote->stats; } git_remote_autotag_option_t git_remote_autotag(git_remote *remote) { return remote->download_tags; } void git_remote_set_autotag(git_remote *remote, git_remote_autotag_option_t value) { remote->download_tags = value; } static int rename_remote_config_section( git_repository *repo, const char *old_name, const char *new_name) { git_buf old_section_name = GIT_BUF_INIT, new_section_name = GIT_BUF_INIT; int error = -1; if (git_buf_printf(&old_section_name, "remote.%s", old_name) < 0) goto cleanup; if (git_buf_printf(&new_section_name, "remote.%s", new_name) < 0) goto cleanup; error = git_config_rename_section( repo, git_buf_cstr(&old_section_name), git_buf_cstr(&new_section_name)); cleanup: git_buf_free(&old_section_name); git_buf_free(&new_section_name); return error; } struct update_data { git_config *config; const char *old_remote_name; const char *new_remote_name; }; static int update_config_entries_cb( const git_config_entry *entry, void *payload) { struct update_data *data = (struct update_data *)payload; if (strcmp(entry->value, data->old_remote_name)) return 0; return git_config_set_string( data->config, entry->name, data->new_remote_name); } static int update_branch_remote_config_entry( git_repository *repo, const char *old_name, const char *new_name) { git_config *config; struct update_data data; if (git_repository_config__weakptr(&config, repo) < 0) return -1; data.config = config; data.old_remote_name = old_name; data.new_remote_name = new_name; return git_config_foreach_match( config, "branch\\..+\\.remote", update_config_entries_cb, &data); } static int rename_one_remote_reference( git_reference *reference, const char *old_remote_name, const char *new_remote_name) { int error = -1; git_buf new_name = GIT_BUF_INIT; if (git_buf_printf( &new_name, GIT_REFS_REMOTES_DIR "%s%s", new_remote_name, reference->name + strlen(GIT_REFS_REMOTES_DIR) + strlen(old_remote_name)) < 0) return -1; error = git_reference_rename(NULL, reference, git_buf_cstr(&new_name), 0); git_reference_free(reference); git_buf_free(&new_name); return error; } static int rename_remote_references( git_repository *repo, const char *old_name, const char *new_name) { int error = -1; git_reference *ref; git_reference_iterator *iter; if (git_reference_iterator_new(&iter, repo) < 0) return -1; while ((error = git_reference_next(&ref, iter)) == 0) { if (git__prefixcmp(ref->name, GIT_REFS_REMOTES_DIR)) { git_reference_free(ref); continue; } if ((error = rename_one_remote_reference(ref, old_name, new_name)) < 0) { git_reference_iterator_free(iter); return error; } } git_reference_iterator_free(iter); if (error == GIT_ITEROVER) return 0; return error; } static int rename_fetch_refspecs( git_remote *remote, const char *new_name, int (*callback)(const char *problematic_refspec, void *payload), void *payload) { git_config *config; git_buf base = GIT_BUF_INIT, var = GIT_BUF_INIT, val = GIT_BUF_INIT; const git_refspec *spec; size_t i; int error = -1; if (git_buf_printf(&base, "+refs/heads/*:refs/remotes/%s/*", remote->name) < 0) goto cleanup; git_vector_foreach(&remote->refspecs, i, spec) { if (spec->push) continue; /* Every refspec is a problem refspec for an in-memory remote */ if (!remote->name) { if (callback(spec->string, payload) < 0) { error = GIT_EUSER; goto cleanup; } continue; } /* Does the dst part of the refspec follow the extected standard format? */ if (strcmp(git_buf_cstr(&base), spec->string)) { if (callback(spec->string, payload) < 0) { error = GIT_EUSER; goto cleanup; } continue; } /* If we do want to move it to the new section */ if (git_buf_printf(&val, "+refs/heads/*:refs/remotes/%s/*", new_name) < 0) goto cleanup; if (git_buf_printf(&var, "remote.%s.fetch", new_name) < 0) goto cleanup; if (git_repository_config__weakptr(&config, remote->repo) < 0) goto cleanup; if (git_config_set_string(config, git_buf_cstr(&var), git_buf_cstr(&val)) < 0) goto cleanup; } error = 0; cleanup: git_buf_free(&base); git_buf_free(&var); git_buf_free(&val); return error; } int git_remote_rename( git_remote *remote, const char *new_name, git_remote_rename_problem_cb callback, void *payload) { int error; assert(remote && new_name); if (!remote->name) { giterr_set(GITERR_INVALID, "Can't rename an in-memory remote."); return GIT_EINVALIDSPEC; } if ((error = ensure_remote_name_is_valid(new_name)) < 0) return error; if (remote->repo) { if ((error = ensure_remote_doesnot_exist(remote->repo, new_name)) < 0) return error; if (!remote->name) { if ((error = rename_fetch_refspecs( remote, new_name, callback, payload)) < 0) return error; remote->name = git__strdup(new_name); if (!remote->name) return 0; return git_remote_save(remote); } if ((error = rename_remote_config_section( remote->repo, remote->name, new_name)) < 0) return error; if ((error = update_branch_remote_config_entry( remote->repo, remote->name, new_name)) < 0) return error; if ((error = rename_remote_references( remote->repo, remote->name, new_name)) < 0) return error; if ((error = rename_fetch_refspecs( remote, new_name, callback, payload)) < 0) return error; } git__free(remote->name); remote->name = git__strdup(new_name); return 0; } int git_remote_update_fetchhead(git_remote *remote) { return remote->update_fetchhead; } void git_remote_set_update_fetchhead(git_remote *remote, int value) { remote->update_fetchhead = value; } int git_remote_is_valid_name( const char *remote_name) { git_buf buf = GIT_BUF_INIT; git_refspec refspec; int error = -1; if (!remote_name || *remote_name == '\0') return 0; git_buf_printf(&buf, "refs/heads/test:refs/remotes/%s/test", remote_name); error = git_refspec__parse(&refspec, git_buf_cstr(&buf), true); git_buf_free(&buf); git_refspec__free(&refspec); giterr_clear(); return error == 0; } git_refspec *git_remote__matching_refspec(git_remote *remote, const char *refname) { git_refspec *spec; size_t i; git_vector_foreach(&remote->refspecs, i, spec) { if (spec->push) continue; if (git_refspec_src_matches(spec, refname)) return spec; } return NULL; } git_refspec *git_remote__matching_dst_refspec(git_remote *remote, const char *refname) { git_refspec *spec; size_t i; git_vector_foreach(&remote->refspecs, i, spec) { if (spec->push) continue; if (git_refspec_dst_matches(spec, refname)) return spec; } return NULL; } void git_remote_clear_refspecs(git_remote *remote) { git_refspec *spec; size_t i; git_vector_foreach(&remote->refspecs, i, spec) { git_refspec__free(spec); git__free(spec); } git_vector_clear(&remote->refspecs); } int git_remote_add_fetch(git_remote *remote, const char *refspec) { return add_refspec(remote, refspec, true); } int git_remote_add_push(git_remote *remote, const char *refspec) { return add_refspec(remote, refspec, false); } static int copy_refspecs(git_strarray *array, git_remote *remote, int push) { size_t i; git_vector refspecs; git_refspec *spec; char *dup; if (git_vector_init(&refspecs, remote->refspecs.length, NULL) < 0) return -1; git_vector_foreach(&remote->refspecs, i, spec) { if (spec->push != push) continue; if ((dup = git__strdup(spec->string)) == NULL) goto on_error; if (git_vector_insert(&refspecs, dup) < 0) { git__free(dup); goto on_error; } } array->strings = (char **)refspecs.contents; array->count = refspecs.length; return 0; on_error: git_vector_foreach(&refspecs, i, dup) git__free(dup); git_vector_free(&refspecs); return -1; } int git_remote_get_fetch_refspecs(git_strarray *array, git_remote *remote) { return copy_refspecs(array, remote, false); } int git_remote_get_push_refspecs(git_strarray *array, git_remote *remote) { return copy_refspecs(array, remote, true); } size_t git_remote_refspec_count(git_remote *remote) { return remote->refspecs.length; } const git_refspec *git_remote_get_refspec(git_remote *remote, size_t n) { return git_vector_get(&remote->refspecs, n); } int git_remote_remove_refspec(git_remote *remote, size_t n) { git_refspec *spec; assert(remote); spec = git_vector_get(&remote->refspecs, n); if (spec) { git_refspec__free(spec); git__free(spec); } return git_vector_remove(&remote->refspecs, n); } libgit2-0.19.0/src/remote.h000066400000000000000000000022121216214232500153630ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #ifndef INCLUDE_remote_h__ #define INCLUDE_remote_h__ #include "git2/remote.h" #include "git2/transport.h" #include "refspec.h" #include "vector.h" #define GIT_REMOTE_ORIGIN "origin" struct git_remote { char *name; char *url; char *pushurl; git_vector refs; git_vector refspecs; git_cred_acquire_cb cred_acquire_cb; void *cred_acquire_payload; git_transport *transport; git_repository *repo; git_remote_callbacks callbacks; git_transfer_progress stats; unsigned int need_pack; git_remote_autotag_option_t download_tags; unsigned int check_cert; unsigned int update_fetchhead; }; const char* git_remote__urlfordirection(struct git_remote *remote, int direction); int git_remote__get_http_proxy(git_remote *remote, bool use_ssl, char **proxy_url); git_refspec *git_remote__matching_refspec(git_remote *remote, const char *refname); git_refspec *git_remote__matching_dst_refspec(git_remote *remote, const char *refname); #endif libgit2-0.19.0/src/repo_template.h000066400000000000000000000040421216214232500167330ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #ifndef INCLUDE_repo_template_h__ #define INCLUDE_repo_template_h__ #define GIT_OBJECTS_INFO_DIR GIT_OBJECTS_DIR "info/" #define GIT_OBJECTS_PACK_DIR GIT_OBJECTS_DIR "pack/" #define GIT_HOOKS_DIR "hooks/" #define GIT_HOOKS_DIR_MODE 0777 #define GIT_HOOKS_README_FILE GIT_HOOKS_DIR "README.sample" #define GIT_HOOKS_README_MODE 0777 #define GIT_HOOKS_README_CONTENT \ "#!/bin/sh\n"\ "#\n"\ "# Place appropriately named executable hook scripts into this directory\n"\ "# to intercept various actions that git takes. See `git help hooks` for\n"\ "# more information.\n" #define GIT_INFO_DIR "info/" #define GIT_INFO_DIR_MODE 0777 #define GIT_INFO_EXCLUDE_FILE GIT_INFO_DIR "exclude" #define GIT_INFO_EXCLUDE_MODE 0666 #define GIT_INFO_EXCLUDE_CONTENT \ "# File patterns to ignore; see `git help ignore` for more information.\n"\ "# Lines that start with '#' are comments.\n" #define GIT_DESC_FILE "description" #define GIT_DESC_MODE 0666 #define GIT_DESC_CONTENT \ "Unnamed repository; edit this file 'description' to name the repository.\n" typedef struct { const char *path; mode_t mode; const char *content; } repo_template_item; static repo_template_item repo_template[] = { { GIT_OBJECTS_INFO_DIR, GIT_OBJECT_DIR_MODE, NULL }, /* '/objects/info/' */ { GIT_OBJECTS_PACK_DIR, GIT_OBJECT_DIR_MODE, NULL }, /* '/objects/pack/' */ { GIT_REFS_HEADS_DIR, GIT_REFS_DIR_MODE, NULL }, /* '/refs/heads/' */ { GIT_REFS_TAGS_DIR, GIT_REFS_DIR_MODE, NULL }, /* '/refs/tags/' */ { GIT_HOOKS_DIR, GIT_HOOKS_DIR_MODE, NULL }, /* '/hooks/' */ { GIT_INFO_DIR, GIT_INFO_DIR_MODE, NULL }, /* '/info/' */ { GIT_DESC_FILE, GIT_DESC_MODE, GIT_DESC_CONTENT }, { GIT_HOOKS_README_FILE, GIT_HOOKS_README_MODE, GIT_HOOKS_README_CONTENT }, { GIT_INFO_EXCLUDE_FILE, GIT_INFO_EXCLUDE_MODE, GIT_INFO_EXCLUDE_CONTENT }, { NULL, 0, NULL } }; #endif libgit2-0.19.0/src/repository.c000066400000000000000000001236141216214232500163140ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #include #include #include "git2/object.h" #include "git2/refdb.h" #include "git2/sys/repository.h" #include "common.h" #include "repository.h" #include "commit.h" #include "tag.h" #include "blob.h" #include "fileops.h" #include "filebuf.h" #include "index.h" #include "config.h" #include "refs.h" #include "filter.h" #include "odb.h" #include "remote.h" #include "merge.h" #include "diff_driver.h" #define GIT_FILE_CONTENT_PREFIX "gitdir:" #define GIT_BRANCH_MASTER "master" #define GIT_REPO_VERSION 0 #define GIT_TEMPLATE_DIR "/usr/share/git-core/templates" static void set_odb(git_repository *repo, git_odb *odb) { if (odb) { GIT_REFCOUNT_OWN(odb, repo); GIT_REFCOUNT_INC(odb); } if ((odb = git__swap(repo->_odb, odb)) != NULL) { GIT_REFCOUNT_OWN(odb, NULL); git_odb_free(odb); } } static void set_refdb(git_repository *repo, git_refdb *refdb) { if (refdb) { GIT_REFCOUNT_OWN(refdb, repo); GIT_REFCOUNT_INC(refdb); } if ((refdb = git__swap(repo->_refdb, refdb)) != NULL) { GIT_REFCOUNT_OWN(refdb, NULL); git_refdb_free(refdb); } } static void set_config(git_repository *repo, git_config *config) { if (config) { GIT_REFCOUNT_OWN(config, repo); GIT_REFCOUNT_INC(config); } if ((config = git__swap(repo->_config, config)) != NULL) { GIT_REFCOUNT_OWN(config, NULL); git_config_free(config); } git_repository__cvar_cache_clear(repo); } static void set_index(git_repository *repo, git_index *index) { if (index) { GIT_REFCOUNT_OWN(index, repo); GIT_REFCOUNT_INC(index); } if ((index = git__swap(repo->_index, index)) != NULL) { GIT_REFCOUNT_OWN(index, NULL); git_index_free(index); } } void git_repository__cleanup(git_repository *repo) { assert(repo); git_cache_clear(&repo->objects); git_attr_cache_flush(repo); set_config(repo, NULL); set_index(repo, NULL); set_odb(repo, NULL); set_refdb(repo, NULL); } void git_repository_free(git_repository *repo) { if (repo == NULL) return; git_repository__cleanup(repo); git_cache_free(&repo->objects); git_submodule_config_free(repo); git_diff_driver_registry_free(repo->diff_drivers); repo->diff_drivers = NULL; git__free(repo->path_repository); git__free(repo->workdir); git__free(repo->namespace); git__memzero(repo, sizeof(*repo)); git__free(repo); } /* * Git repository open methods * * Open a repository object from its path */ static bool valid_repository_path(git_buf *repository_path) { /* Check OBJECTS_DIR first, since it will generate the longest path name */ if (git_path_contains_dir(repository_path, GIT_OBJECTS_DIR) == false) return false; /* Ensure HEAD file exists */ if (git_path_contains_file(repository_path, GIT_HEAD_FILE) == false) return false; if (git_path_contains_dir(repository_path, GIT_REFS_DIR) == false) return false; return true; } static git_repository *repository_alloc(void) { git_repository *repo = git__calloc(1, sizeof(git_repository)); if (!repo) return NULL; if (git_cache_init(&repo->objects) < 0) { git__free(repo); return NULL; } /* set all the entries in the cvar cache to `unset` */ git_repository__cvar_cache_clear(repo); return repo; } int git_repository_new(git_repository **out) { *out = repository_alloc(); return 0; } static int load_config_data(git_repository *repo) { int is_bare; git_config *config; if (git_repository_config__weakptr(&config, repo) < 0) return -1; /* Try to figure out if it's bare, default to non-bare if it's not set */ if (git_config_get_bool(&is_bare, config, "core.bare") < 0) repo->is_bare = 0; else repo->is_bare = is_bare; return 0; } static int load_workdir(git_repository *repo, git_buf *parent_path) { int error; git_config *config; const char *worktree; git_buf worktree_buf = GIT_BUF_INIT; if (repo->is_bare) return 0; if (git_repository_config__weakptr(&config, repo) < 0) return -1; error = git_config_get_string(&worktree, config, "core.worktree"); if (!error && worktree != NULL) { error = git_path_prettify_dir( &worktree_buf, worktree, repo->path_repository); if (error < 0) return error; repo->workdir = git_buf_detach(&worktree_buf); } else if (error != GIT_ENOTFOUND) return error; else { giterr_clear(); if (parent_path && git_path_isdir(parent_path->ptr)) repo->workdir = git_buf_detach(parent_path); else { git_path_dirname_r(&worktree_buf, repo->path_repository); git_path_to_dir(&worktree_buf); repo->workdir = git_buf_detach(&worktree_buf); } } GITERR_CHECK_ALLOC(repo->workdir); return 0; } /* * This function returns furthest offset into path where a ceiling dir * is found, so we can stop processing the path at that point. * * Note: converting this to use git_bufs instead of GIT_PATH_MAX buffers on * the stack could remove directories name limits, but at the cost of doing * repeated malloc/frees inside the loop below, so let's not do it now. */ static int find_ceiling_dir_offset( const char *path, const char *ceiling_directories) { char buf[GIT_PATH_MAX + 1]; char buf2[GIT_PATH_MAX + 1]; const char *ceil, *sep; size_t len, max_len = 0, min_len; assert(path); min_len = (size_t)(git_path_root(path) + 1); if (ceiling_directories == NULL || min_len == 0) return (int)min_len; for (sep = ceil = ceiling_directories; *sep; ceil = sep + 1) { for (sep = ceil; *sep && *sep != GIT_PATH_LIST_SEPARATOR; sep++); len = sep - ceil; if (len == 0 || len >= sizeof(buf) || git_path_root(ceil) == -1) continue; strncpy(buf, ceil, len); buf[len] = '\0'; if (p_realpath(buf, buf2) == NULL) continue; len = strlen(buf2); if (len > 0 && buf2[len-1] == '/') buf[--len] = '\0'; if (!strncmp(path, buf2, len) && path[len] == '/' && len > max_len) { max_len = len; } } return (int)(max_len <= min_len ? min_len : max_len); } /* * Read the contents of `file_path` and set `path_out` to the repo dir that * it points to. Before calling, set `path_out` to the base directory that * should be used if the contents of `file_path` are a relative path. */ static int read_gitfile(git_buf *path_out, const char *file_path) { int error = 0; git_buf file = GIT_BUF_INIT; size_t prefix_len = strlen(GIT_FILE_CONTENT_PREFIX); assert(path_out && file_path); if (git_futils_readbuffer(&file, file_path) < 0) return -1; git_buf_rtrim(&file); if (git_buf_len(&file) <= prefix_len || memcmp(git_buf_cstr(&file), GIT_FILE_CONTENT_PREFIX, prefix_len) != 0) { giterr_set(GITERR_REPOSITORY, "The `.git` file at '%s' is malformed", file_path); error = -1; } else if ((error = git_path_dirname_r(path_out, file_path)) >= 0) { const char *gitlink = git_buf_cstr(&file) + prefix_len; while (*gitlink && git__isspace(*gitlink)) gitlink++; error = git_path_prettify_dir( path_out, gitlink, git_buf_cstr(path_out)); } git_buf_free(&file); return error; } static int find_repo( git_buf *repo_path, git_buf *parent_path, const char *start_path, uint32_t flags, const char *ceiling_dirs) { int error; git_buf path = GIT_BUF_INIT; struct stat st; dev_t initial_device = 0; bool try_with_dot_git = false; int ceiling_offset; git_buf_free(repo_path); if ((error = git_path_prettify_dir(&path, start_path, NULL)) < 0) return error; ceiling_offset = find_ceiling_dir_offset(path.ptr, ceiling_dirs); if ((error = git_buf_joinpath(&path, path.ptr, DOT_GIT)) < 0) return error; while (!error && !git_buf_len(repo_path)) { if (p_stat(path.ptr, &st) == 0) { /* check that we have not crossed device boundaries */ if (initial_device == 0) initial_device = st.st_dev; else if (st.st_dev != initial_device && (flags & GIT_REPOSITORY_OPEN_CROSS_FS) == 0) break; if (S_ISDIR(st.st_mode)) { if (valid_repository_path(&path)) { git_path_to_dir(&path); git_buf_set(repo_path, path.ptr, path.size); break; } } else if (S_ISREG(st.st_mode)) { git_buf repo_link = GIT_BUF_INIT; if (!(error = read_gitfile(&repo_link, path.ptr))) { if (valid_repository_path(&repo_link)) git_buf_swap(repo_path, &repo_link); git_buf_free(&repo_link); break; } git_buf_free(&repo_link); } } /* move up one directory level */ if (git_path_dirname_r(&path, path.ptr) < 0) { error = -1; break; } if (try_with_dot_git) { /* if we tried original dir with and without .git AND either hit * directory ceiling or NO_SEARCH was requested, then be done. */ if (path.ptr[ceiling_offset] == '\0' || (flags & GIT_REPOSITORY_OPEN_NO_SEARCH) != 0) break; /* otherwise look first for .git item */ error = git_buf_joinpath(&path, path.ptr, DOT_GIT); } try_with_dot_git = !try_with_dot_git; } if (!error && parent_path != NULL) { if (!git_buf_len(repo_path)) git_buf_clear(parent_path); else { git_path_dirname_r(parent_path, path.ptr); git_path_to_dir(parent_path); } if (git_buf_oom(parent_path)) return -1; } git_buf_free(&path); if (!git_buf_len(repo_path) && !error) { giterr_set(GITERR_REPOSITORY, "Could not find repository from '%s'", start_path); error = GIT_ENOTFOUND; } return error; } int git_repository_open_bare( git_repository **repo_ptr, const char *bare_path) { int error; git_buf path = GIT_BUF_INIT; git_repository *repo = NULL; if ((error = git_path_prettify_dir(&path, bare_path, NULL)) < 0) return error; if (!valid_repository_path(&path)) { git_buf_free(&path); giterr_set(GITERR_REPOSITORY, "Path is not a repository: %s", bare_path); return GIT_ENOTFOUND; } repo = repository_alloc(); GITERR_CHECK_ALLOC(repo); repo->path_repository = git_buf_detach(&path); GITERR_CHECK_ALLOC(repo->path_repository); /* of course we're bare! */ repo->is_bare = 1; repo->workdir = NULL; *repo_ptr = repo; return 0; } int git_repository_open_ext( git_repository **repo_ptr, const char *start_path, unsigned int flags, const char *ceiling_dirs) { int error; git_buf path = GIT_BUF_INIT, parent = GIT_BUF_INIT; git_repository *repo; if (repo_ptr) *repo_ptr = NULL; error = find_repo(&path, &parent, start_path, flags, ceiling_dirs); if (error < 0 || !repo_ptr) return error; repo = repository_alloc(); GITERR_CHECK_ALLOC(repo); repo->path_repository = git_buf_detach(&path); GITERR_CHECK_ALLOC(repo->path_repository); if ((error = load_config_data(repo)) < 0 || (error = load_workdir(repo, &parent)) < 0) { git_repository_free(repo); return error; } git_buf_free(&parent); *repo_ptr = repo; return 0; } int git_repository_open(git_repository **repo_out, const char *path) { return git_repository_open_ext( repo_out, path, GIT_REPOSITORY_OPEN_NO_SEARCH, NULL); } int git_repository_wrap_odb(git_repository **repo_out, git_odb *odb) { git_repository *repo; repo = repository_alloc(); GITERR_CHECK_ALLOC(repo); git_repository_set_odb(repo, odb); *repo_out = repo; return 0; } int git_repository_discover( char *repository_path, size_t size, const char *start_path, int across_fs, const char *ceiling_dirs) { git_buf path = GIT_BUF_INIT; uint32_t flags = across_fs ? GIT_REPOSITORY_OPEN_CROSS_FS : 0; int error; assert(start_path && repository_path && size > 0); *repository_path = '\0'; if ((error = find_repo(&path, NULL, start_path, flags, ceiling_dirs)) < 0) return error != GIT_ENOTFOUND ? -1 : error; if (size < (size_t)(path.size + 1)) { giterr_set(GITERR_REPOSITORY, "The given buffer is too small to store the discovered path"); git_buf_free(&path); return -1; } /* success: we discovered a repository */ git_buf_copy_cstr(repository_path, size, &path); git_buf_free(&path); return 0; } static int load_config( git_config **out, git_repository *repo, const char *global_config_path, const char *xdg_config_path, const char *system_config_path) { int error; git_buf config_path = GIT_BUF_INIT; git_config *cfg = NULL; assert(repo && out); if ((error = git_config_new(&cfg)) < 0) return error; error = git_buf_joinpath( &config_path, repo->path_repository, GIT_CONFIG_FILENAME_INREPO); if (error < 0) goto on_error; if ((error = git_config_add_file_ondisk( cfg, config_path.ptr, GIT_CONFIG_LEVEL_LOCAL, 0)) < 0 && error != GIT_ENOTFOUND) goto on_error; git_buf_free(&config_path); if (global_config_path != NULL && (error = git_config_add_file_ondisk( cfg, global_config_path, GIT_CONFIG_LEVEL_GLOBAL, 0)) < 0 && error != GIT_ENOTFOUND) goto on_error; if (xdg_config_path != NULL && (error = git_config_add_file_ondisk( cfg, xdg_config_path, GIT_CONFIG_LEVEL_XDG, 0)) < 0 && error != GIT_ENOTFOUND) goto on_error; if (system_config_path != NULL && (error = git_config_add_file_ondisk( cfg, system_config_path, GIT_CONFIG_LEVEL_SYSTEM, 0)) < 0 && error != GIT_ENOTFOUND) goto on_error; giterr_clear(); /* clear any lingering ENOTFOUND errors */ *out = cfg; return 0; on_error: git_buf_free(&config_path); git_config_free(cfg); *out = NULL; return error; } static const char *path_unless_empty(git_buf *buf) { return git_buf_len(buf) > 0 ? git_buf_cstr(buf) : NULL; } int git_repository_config__weakptr(git_config **out, git_repository *repo) { int error = 0; if (repo->_config == NULL) { git_buf global_buf = GIT_BUF_INIT; git_buf xdg_buf = GIT_BUF_INIT; git_buf system_buf = GIT_BUF_INIT; git_config *config; git_config_find_global_r(&global_buf); git_config_find_xdg_r(&xdg_buf); git_config_find_system_r(&system_buf); /* If there is no global file, open a backend for it anyway */ if (git_buf_len(&global_buf) == 0) git_config__global_location(&global_buf); error = load_config( &config, repo, path_unless_empty(&global_buf), path_unless_empty(&xdg_buf), path_unless_empty(&system_buf)); if (!error) { GIT_REFCOUNT_OWN(config, repo); config = git__compare_and_swap(&repo->_config, NULL, config); if (config != NULL) { GIT_REFCOUNT_OWN(config, NULL); git_config_free(config); } } git_buf_free(&global_buf); git_buf_free(&xdg_buf); git_buf_free(&system_buf); } *out = repo->_config; return error; } int git_repository_config(git_config **out, git_repository *repo) { if (git_repository_config__weakptr(out, repo) < 0) return -1; GIT_REFCOUNT_INC(*out); return 0; } void git_repository_set_config(git_repository *repo, git_config *config) { assert(repo && config); set_config(repo, config); } int git_repository_odb__weakptr(git_odb **out, git_repository *repo) { int error = 0; assert(repo && out); if (repo->_odb == NULL) { git_buf odb_path = GIT_BUF_INIT; git_odb *odb; git_buf_joinpath(&odb_path, repo->path_repository, GIT_OBJECTS_DIR); error = git_odb_open(&odb, odb_path.ptr); if (!error) { GIT_REFCOUNT_OWN(odb, repo); odb = git__compare_and_swap(&repo->_odb, NULL, odb); if (odb != NULL) { GIT_REFCOUNT_OWN(odb, NULL); git_odb_free(odb); } } git_buf_free(&odb_path); } *out = repo->_odb; return error; } int git_repository_odb(git_odb **out, git_repository *repo) { if (git_repository_odb__weakptr(out, repo) < 0) return -1; GIT_REFCOUNT_INC(*out); return 0; } void git_repository_set_odb(git_repository *repo, git_odb *odb) { assert(repo && odb); set_odb(repo, odb); } int git_repository_refdb__weakptr(git_refdb **out, git_repository *repo) { int error = 0; assert(out && repo); if (repo->_refdb == NULL) { git_refdb *refdb; error = git_refdb_open(&refdb, repo); if (!error) { GIT_REFCOUNT_OWN(refdb, repo); refdb = git__compare_and_swap(&repo->_refdb, NULL, refdb); if (refdb != NULL) { GIT_REFCOUNT_OWN(refdb, NULL); git_refdb_free(refdb); } } } *out = repo->_refdb; return error; } int git_repository_refdb(git_refdb **out, git_repository *repo) { if (git_repository_refdb__weakptr(out, repo) < 0) return -1; GIT_REFCOUNT_INC(*out); return 0; } void git_repository_set_refdb(git_repository *repo, git_refdb *refdb) { assert(repo && refdb); set_refdb(repo, refdb); } int git_repository_index__weakptr(git_index **out, git_repository *repo) { int error = 0; assert(out && repo); if (repo->_index == NULL) { git_buf index_path = GIT_BUF_INIT; git_index *index; git_buf_joinpath(&index_path, repo->path_repository, GIT_INDEX_FILE); error = git_index_open(&index, index_path.ptr); if (!error) { GIT_REFCOUNT_OWN(index, repo); index = git__compare_and_swap(&repo->_index, NULL, index); if (index != NULL) { GIT_REFCOUNT_OWN(index, NULL); git_index_free(index); } error = git_index_set_caps(repo->_index, GIT_INDEXCAP_FROM_OWNER); } git_buf_free(&index_path); } *out = repo->_index; return error; } int git_repository_index(git_index **out, git_repository *repo) { if (git_repository_index__weakptr(out, repo) < 0) return -1; GIT_REFCOUNT_INC(*out); return 0; } void git_repository_set_index(git_repository *repo, git_index *index) { assert(repo && index); set_index(repo, index); } int git_repository_set_namespace(git_repository *repo, const char *namespace) { git__free(repo->namespace); if (namespace == NULL) { repo->namespace = NULL; return 0; } return (repo->namespace = git__strdup(namespace)) ? 0 : -1; } const char *git_repository_get_namespace(git_repository *repo) { return repo->namespace; } static int check_repositoryformatversion(git_config *config) { int version; if (git_config_get_int32(&version, config, "core.repositoryformatversion") < 0) return -1; if (GIT_REPO_VERSION < version) { giterr_set(GITERR_REPOSITORY, "Unsupported repository version %d. Only versions up to %d are supported.", version, GIT_REPO_VERSION); return -1; } return 0; } static int repo_init_create_head(const char *git_dir, const char *ref_name) { git_buf ref_path = GIT_BUF_INIT; git_filebuf ref = GIT_FILEBUF_INIT; const char *fmt; if (git_buf_joinpath(&ref_path, git_dir, GIT_HEAD_FILE) < 0 || git_filebuf_open(&ref, ref_path.ptr, 0) < 0) goto fail; if (!ref_name) ref_name = GIT_BRANCH_MASTER; if (git__prefixcmp(ref_name, GIT_REFS_DIR) == 0) fmt = "ref: %s\n"; else fmt = "ref: " GIT_REFS_HEADS_DIR "%s\n"; if (git_filebuf_printf(&ref, fmt, ref_name) < 0 || git_filebuf_commit(&ref, GIT_REFS_FILE_MODE) < 0) goto fail; git_buf_free(&ref_path); return 0; fail: git_buf_free(&ref_path); git_filebuf_cleanup(&ref); return -1; } static bool is_chmod_supported(const char *file_path) { struct stat st1, st2; static int _is_supported = -1; if (_is_supported > -1) return _is_supported; if (p_stat(file_path, &st1) < 0) return false; if (p_chmod(file_path, st1.st_mode ^ S_IXUSR) < 0) return false; if (p_stat(file_path, &st2) < 0) return false; _is_supported = (st1.st_mode != st2.st_mode); return _is_supported; } static bool is_filesystem_case_insensitive(const char *gitdir_path) { git_buf path = GIT_BUF_INIT; static int _is_insensitive = -1; if (_is_insensitive > -1) return _is_insensitive; if (git_buf_joinpath(&path, gitdir_path, "CoNfIg") < 0) goto cleanup; _is_insensitive = git_path_exists(git_buf_cstr(&path)); cleanup: git_buf_free(&path); return _is_insensitive; } static bool are_symlinks_supported(const char *wd_path) { git_buf path = GIT_BUF_INIT; int fd; struct stat st; static int _symlinks_supported = -1; if (_symlinks_supported > -1) return _symlinks_supported; if ((fd = git_futils_mktmp(&path, wd_path)) < 0 || p_close(fd) < 0 || p_unlink(path.ptr) < 0 || p_symlink("testing", path.ptr) < 0 || p_lstat(path.ptr, &st) < 0) _symlinks_supported = false; else _symlinks_supported = (S_ISLNK(st.st_mode) != 0); (void)p_unlink(path.ptr); git_buf_free(&path); return _symlinks_supported; } static int create_empty_file(const char *path, mode_t mode) { int fd; if ((fd = p_creat(path, mode)) < 0) { giterr_set(GITERR_OS, "Error while creating '%s'", path); return -1; } if (p_close(fd) < 0) { giterr_set(GITERR_OS, "Error while closing '%s'", path); return -1; } return 0; } static int repo_init_config( const char *repo_dir, const char *work_dir, git_repository_init_options *opts) { int error = 0; git_buf cfg_path = GIT_BUF_INIT; git_config *config = NULL; #define SET_REPO_CONFIG(TYPE, NAME, VAL) do {\ if ((error = git_config_set_##TYPE(config, NAME, VAL)) < 0) \ goto cleanup; } while (0) if (git_buf_joinpath(&cfg_path, repo_dir, GIT_CONFIG_FILENAME_INREPO) < 0) return -1; if (!git_path_isfile(git_buf_cstr(&cfg_path)) && create_empty_file(git_buf_cstr(&cfg_path), GIT_CONFIG_FILE_MODE) < 0) { git_buf_free(&cfg_path); return -1; } if (git_config_open_ondisk(&config, git_buf_cstr(&cfg_path)) < 0) { git_buf_free(&cfg_path); return -1; } if ((opts->flags & GIT_REPOSITORY_INIT__IS_REINIT) != 0 && (error = check_repositoryformatversion(config)) < 0) goto cleanup; SET_REPO_CONFIG( bool, "core.bare", (opts->flags & GIT_REPOSITORY_INIT_BARE) != 0); SET_REPO_CONFIG( int32, "core.repositoryformatversion", GIT_REPO_VERSION); SET_REPO_CONFIG( bool, "core.filemode", is_chmod_supported(git_buf_cstr(&cfg_path))); if (!(opts->flags & GIT_REPOSITORY_INIT_BARE)) { SET_REPO_CONFIG(bool, "core.logallrefupdates", true); if (!are_symlinks_supported(work_dir)) SET_REPO_CONFIG(bool, "core.symlinks", false); if (!(opts->flags & GIT_REPOSITORY_INIT__NATURAL_WD)) { SET_REPO_CONFIG(string, "core.worktree", work_dir); } else if ((opts->flags & GIT_REPOSITORY_INIT__IS_REINIT) != 0) { if (git_config_delete_entry(config, "core.worktree") < 0) giterr_clear(); } } else { if (!are_symlinks_supported(repo_dir)) SET_REPO_CONFIG(bool, "core.symlinks", false); } if (!(opts->flags & GIT_REPOSITORY_INIT__IS_REINIT) && is_filesystem_case_insensitive(repo_dir)) SET_REPO_CONFIG(bool, "core.ignorecase", true); if (opts->mode == GIT_REPOSITORY_INIT_SHARED_GROUP) { SET_REPO_CONFIG(int32, "core.sharedrepository", 1); SET_REPO_CONFIG(bool, "receive.denyNonFastforwards", true); } else if (opts->mode == GIT_REPOSITORY_INIT_SHARED_ALL) { SET_REPO_CONFIG(int32, "core.sharedrepository", 2); SET_REPO_CONFIG(bool, "receive.denyNonFastforwards", true); } cleanup: git_buf_free(&cfg_path); git_config_free(config); return error; } static int repo_write_template( const char *git_dir, bool allow_overwrite, const char *file, mode_t mode, bool hidden, const char *content) { git_buf path = GIT_BUF_INIT; int fd, error = 0, flags; if (git_buf_joinpath(&path, git_dir, file) < 0) return -1; if (allow_overwrite) flags = O_WRONLY | O_CREAT | O_TRUNC; else flags = O_WRONLY | O_CREAT | O_EXCL; fd = p_open(git_buf_cstr(&path), flags, mode); if (fd >= 0) { error = p_write(fd, content, strlen(content)); p_close(fd); } else if (errno != EEXIST) error = fd; #ifdef GIT_WIN32 if (!error && hidden) { if (p_hide_directory__w32(path.ptr) < 0) error = -1; } #else GIT_UNUSED(hidden); #endif git_buf_free(&path); if (error) giterr_set(GITERR_OS, "Failed to initialize repository with template '%s'", file); return error; } static int repo_write_gitlink( const char *in_dir, const char *to_repo) { int error; git_buf buf = GIT_BUF_INIT; struct stat st; git_path_dirname_r(&buf, to_repo); git_path_to_dir(&buf); if (git_buf_oom(&buf)) return -1; /* don't write gitlink to natural workdir */ if (git__suffixcmp(to_repo, "/" DOT_GIT "/") == 0 && strcmp(in_dir, buf.ptr) == 0) { error = GIT_PASSTHROUGH; goto cleanup; } if ((error = git_buf_joinpath(&buf, in_dir, DOT_GIT)) < 0) goto cleanup; if (!p_stat(buf.ptr, &st) && !S_ISREG(st.st_mode)) { giterr_set(GITERR_REPOSITORY, "Cannot overwrite gitlink file into path '%s'", in_dir); error = GIT_EEXISTS; goto cleanup; } git_buf_clear(&buf); error = git_buf_printf(&buf, "%s %s", GIT_FILE_CONTENT_PREFIX, to_repo); if (!error) error = repo_write_template(in_dir, true, DOT_GIT, 0666, true, buf.ptr); cleanup: git_buf_free(&buf); return error; } static mode_t pick_dir_mode(git_repository_init_options *opts) { if (opts->mode == GIT_REPOSITORY_INIT_SHARED_UMASK) return 0777; if (opts->mode == GIT_REPOSITORY_INIT_SHARED_GROUP) return (0775 | S_ISGID); if (opts->mode == GIT_REPOSITORY_INIT_SHARED_ALL) return (0777 | S_ISGID); return opts->mode; } #include "repo_template.h" static int repo_init_structure( const char *repo_dir, const char *work_dir, git_repository_init_options *opts) { int error = 0; repo_template_item *tpl; bool external_tpl = ((opts->flags & GIT_REPOSITORY_INIT_EXTERNAL_TEMPLATE) != 0); mode_t dmode = pick_dir_mode(opts); /* Hide the ".git" directory */ #ifdef GIT_WIN32 if ((opts->flags & GIT_REPOSITORY_INIT__HAS_DOTGIT) != 0) { if (p_hide_directory__w32(repo_dir) < 0) { giterr_set(GITERR_REPOSITORY, "Failed to mark Git repository folder as hidden"); return -1; } } #endif /* Create the .git gitlink if appropriate */ if ((opts->flags & GIT_REPOSITORY_INIT_BARE) == 0 && (opts->flags & GIT_REPOSITORY_INIT__NATURAL_WD) == 0) { if (repo_write_gitlink(work_dir, repo_dir) < 0) return -1; } /* Copy external template if requested */ if (external_tpl) { git_config *cfg; const char *tdir; if (opts->template_path) tdir = opts->template_path; else if ((error = git_config_open_default(&cfg)) < 0) return error; else { error = git_config_get_string(&tdir, cfg, "init.templatedir"); git_config_free(cfg); if (error && error != GIT_ENOTFOUND) return error; giterr_clear(); tdir = GIT_TEMPLATE_DIR; } error = git_futils_cp_r(tdir, repo_dir, GIT_CPDIR_COPY_SYMLINKS | GIT_CPDIR_CHMOD_DIRS | GIT_CPDIR_SIMPLE_TO_MODE, dmode); if (error < 0) { if (strcmp(tdir, GIT_TEMPLATE_DIR) != 0) return error; /* if template was default, ignore error and use internal */ giterr_clear(); external_tpl = false; error = 0; } } /* Copy internal template * - always ensure existence of dirs * - only create files if no external template was specified */ for (tpl = repo_template; !error && tpl->path; ++tpl) { if (!tpl->content) error = git_futils_mkdir( tpl->path, repo_dir, dmode, GIT_MKDIR_PATH | GIT_MKDIR_CHMOD); else if (!external_tpl) { const char *content = tpl->content; if (opts->description && strcmp(tpl->path, GIT_DESC_FILE) == 0) content = opts->description; error = repo_write_template( repo_dir, false, tpl->path, tpl->mode, false, content); } } return error; } static int mkdir_parent(git_buf *buf, uint32_t mode, bool skip2) { /* When making parent directories during repository initialization * don't try to set gid or grant world write access */ return git_futils_mkdir( buf->ptr, NULL, mode & ~(S_ISGID | 0002), GIT_MKDIR_PATH | GIT_MKDIR_VERIFY_DIR | (skip2 ? GIT_MKDIR_SKIP_LAST2 : GIT_MKDIR_SKIP_LAST)); } static int repo_init_directories( git_buf *repo_path, git_buf *wd_path, const char *given_repo, git_repository_init_options *opts) { int error = 0; bool is_bare, add_dotgit, has_dotgit, natural_wd; mode_t dirmode; /* There are three possible rules for what we are allowed to create: * - MKPATH means anything we need * - MKDIR means just the .git directory and its parent and the workdir * - Neither means only the .git directory can be created * * There are 5 "segments" of path that we might need to deal with: * 1. The .git directory * 2. The parent of the .git directory * 3. Everything above the parent of the .git directory * 4. The working directory (often the same as #2) * 5. Everything above the working directory (often the same as #3) * * For all directories created, we start with the init_mode value for * permissions and then strip off bits in some cases: * * For MKPATH, we create #3 (and #5) paths without S_ISGID or S_IWOTH * For MKPATH and MKDIR, we create #2 (and #4) without S_ISGID * For all rules, we create #1 using the untouched init_mode */ /* set up repo path */ is_bare = ((opts->flags & GIT_REPOSITORY_INIT_BARE) != 0); add_dotgit = (opts->flags & GIT_REPOSITORY_INIT_NO_DOTGIT_DIR) == 0 && !is_bare && git__suffixcmp(given_repo, "/" DOT_GIT) != 0 && git__suffixcmp(given_repo, "/" GIT_DIR) != 0; if (git_buf_joinpath(repo_path, given_repo, add_dotgit ? GIT_DIR : "") < 0) return -1; has_dotgit = (git__suffixcmp(repo_path->ptr, "/" GIT_DIR) == 0); if (has_dotgit) opts->flags |= GIT_REPOSITORY_INIT__HAS_DOTGIT; /* set up workdir path */ if (!is_bare) { if (opts->workdir_path) { if (git_path_join_unrooted( wd_path, opts->workdir_path, repo_path->ptr, NULL) < 0) return -1; } else if (has_dotgit) { if (git_path_dirname_r(wd_path, repo_path->ptr) < 0) return -1; } else { giterr_set(GITERR_REPOSITORY, "Cannot pick working directory" " for non-bare repository that isn't a '.git' directory"); return -1; } if (git_path_to_dir(wd_path) < 0) return -1; } else { git_buf_clear(wd_path); } natural_wd = has_dotgit && wd_path->size > 0 && wd_path->size + strlen(GIT_DIR) == repo_path->size && memcmp(repo_path->ptr, wd_path->ptr, wd_path->size) == 0; if (natural_wd) opts->flags |= GIT_REPOSITORY_INIT__NATURAL_WD; /* create directories as needed / requested */ dirmode = pick_dir_mode(opts); if ((opts->flags & GIT_REPOSITORY_INIT_MKPATH) != 0) { /* create path #5 */ if (wd_path->size > 0 && (error = mkdir_parent(wd_path, dirmode, false)) < 0) return error; /* create path #3 (if not the same as #5) */ if (!natural_wd && (error = mkdir_parent(repo_path, dirmode, has_dotgit)) < 0) return error; } if ((opts->flags & GIT_REPOSITORY_INIT_MKDIR) != 0 || (opts->flags & GIT_REPOSITORY_INIT_MKPATH) != 0) { /* create path #4 */ if (wd_path->size > 0 && (error = git_futils_mkdir( wd_path->ptr, NULL, dirmode & ~S_ISGID, GIT_MKDIR_VERIFY_DIR)) < 0) return error; /* create path #2 (if not the same as #4) */ if (!natural_wd && (error = git_futils_mkdir( repo_path->ptr, NULL, dirmode & ~S_ISGID, GIT_MKDIR_VERIFY_DIR | GIT_MKDIR_SKIP_LAST)) < 0) return error; } if ((opts->flags & GIT_REPOSITORY_INIT_MKDIR) != 0 || (opts->flags & GIT_REPOSITORY_INIT_MKPATH) != 0 || has_dotgit) { /* create path #1 */ error = git_futils_mkdir(repo_path->ptr, NULL, dirmode, GIT_MKDIR_VERIFY_DIR | ((dirmode & S_ISGID) ? GIT_MKDIR_CHMOD : 0)); } /* prettify both directories now that they are created */ if (!error) { error = git_path_prettify_dir(repo_path, repo_path->ptr, NULL); if (!error && wd_path->size > 0) error = git_path_prettify_dir(wd_path, wd_path->ptr, NULL); } return error; } static int repo_init_create_origin(git_repository *repo, const char *url) { int error; git_remote *remote; if (!(error = git_remote_create(&remote, repo, GIT_REMOTE_ORIGIN, url))) { git_remote_free(remote); } return error; } int git_repository_init( git_repository **repo_out, const char *path, unsigned is_bare) { git_repository_init_options opts = GIT_REPOSITORY_INIT_OPTIONS_INIT; opts.flags = GIT_REPOSITORY_INIT_MKPATH; /* don't love this default */ if (is_bare) opts.flags |= GIT_REPOSITORY_INIT_BARE; return git_repository_init_ext(repo_out, path, &opts); } int git_repository_init_ext( git_repository **out, const char *given_repo, git_repository_init_options *opts) { int error; git_buf repo_path = GIT_BUF_INIT, wd_path = GIT_BUF_INIT; assert(out && given_repo && opts); GITERR_CHECK_VERSION(opts, GIT_REPOSITORY_INIT_OPTIONS_VERSION, "git_repository_init_options"); error = repo_init_directories(&repo_path, &wd_path, given_repo, opts); if (error < 0) goto cleanup; if (valid_repository_path(&repo_path)) { if ((opts->flags & GIT_REPOSITORY_INIT_NO_REINIT) != 0) { giterr_set(GITERR_REPOSITORY, "Attempt to reinitialize '%s'", given_repo); error = GIT_EEXISTS; goto cleanup; } opts->flags |= GIT_REPOSITORY_INIT__IS_REINIT; error = repo_init_config( git_buf_cstr(&repo_path), git_buf_cstr(&wd_path), opts); /* TODO: reinitialize the templates */ } else { if (!(error = repo_init_structure( git_buf_cstr(&repo_path), git_buf_cstr(&wd_path), opts)) && !(error = repo_init_config( git_buf_cstr(&repo_path), git_buf_cstr(&wd_path), opts))) error = repo_init_create_head( git_buf_cstr(&repo_path), opts->initial_head); } if (error < 0) goto cleanup; error = git_repository_open(out, git_buf_cstr(&repo_path)); if (!error && opts->origin_url) error = repo_init_create_origin(*out, opts->origin_url); cleanup: git_buf_free(&repo_path); git_buf_free(&wd_path); return error; } int git_repository_head_detached(git_repository *repo) { git_reference *ref; git_odb *odb = NULL; int exists; if (git_repository_odb__weakptr(&odb, repo) < 0) return -1; if (git_reference_lookup(&ref, repo, GIT_HEAD_FILE) < 0) return -1; if (git_reference_type(ref) == GIT_REF_SYMBOLIC) { git_reference_free(ref); return 0; } exists = git_odb_exists(odb, git_reference_target(ref)); git_reference_free(ref); return exists; } int git_repository_head(git_reference **head_out, git_repository *repo) { git_reference *head; int error; if ((error = git_reference_lookup(&head, repo, GIT_HEAD_FILE)) < 0) return error; if (git_reference_type(head) == GIT_REF_OID) { *head_out = head; return 0; } error = git_reference_lookup_resolved(head_out, repo, git_reference_symbolic_target(head), -1); git_reference_free(head); return error == GIT_ENOTFOUND ? GIT_EORPHANEDHEAD : error; } int git_repository_head_orphan(git_repository *repo) { git_reference *ref = NULL; int error; error = git_repository_head(&ref, repo); git_reference_free(ref); if (error == GIT_EORPHANEDHEAD) return 1; if (error < 0) return -1; return 0; } static int at_least_one_cb(const char *refname, void *payload) { GIT_UNUSED(refname); GIT_UNUSED(payload); return GIT_EUSER; } static int repo_contains_no_reference(git_repository *repo) { int error = git_reference_foreach_name(repo, &at_least_one_cb, NULL); if (error == GIT_EUSER) return 0; if (!error) return 1; return error; } int git_repository_is_empty(git_repository *repo) { git_reference *head = NULL; int error; if (git_reference_lookup(&head, repo, GIT_HEAD_FILE) < 0) return -1; if (!(error = git_reference_type(head) == GIT_REF_SYMBOLIC)) goto cleanup; if (!(error = strcmp( git_reference_symbolic_target(head), GIT_REFS_HEADS_DIR "master") == 0)) goto cleanup; error = repo_contains_no_reference(repo); cleanup: git_reference_free(head); return error < 0 ? -1 : error; } const char *git_repository_path(git_repository *repo) { assert(repo); return repo->path_repository; } const char *git_repository_workdir(git_repository *repo) { assert(repo); if (repo->is_bare) return NULL; return repo->workdir; } int git_repository_set_workdir( git_repository *repo, const char *workdir, int update_gitlink) { int error = 0; git_buf path = GIT_BUF_INIT; assert(repo && workdir); if (git_path_prettify_dir(&path, workdir, NULL) < 0) return -1; if (repo->workdir && strcmp(repo->workdir, path.ptr) == 0) return 0; if (update_gitlink) { git_config *config; if (git_repository_config__weakptr(&config, repo) < 0) return -1; error = repo_write_gitlink(path.ptr, git_repository_path(repo)); /* passthrough error means gitlink is unnecessary */ if (error == GIT_PASSTHROUGH) error = git_config_delete_entry(config, "core.worktree"); else if (!error) error = git_config_set_string(config, "core.worktree", path.ptr); if (!error) error = git_config_set_bool(config, "core.bare", false); } if (!error) { char *old_workdir = repo->workdir; repo->workdir = git_buf_detach(&path); repo->is_bare = 0; git__free(old_workdir); } return error; } int git_repository_is_bare(git_repository *repo) { assert(repo); return repo->is_bare; } int git_repository_head_tree(git_tree **tree, git_repository *repo) { git_reference *head; git_object *obj; int error; if ((error = git_repository_head(&head, repo)) < 0) return error; if ((error = git_reference_peel(&obj, head, GIT_OBJ_TREE)) < 0) goto cleanup; *tree = (git_tree *)obj; cleanup: git_reference_free(head); return error; } int git_repository_message(char *buffer, size_t len, git_repository *repo) { git_buf buf = GIT_BUF_INIT, path = GIT_BUF_INIT; struct stat st; int error; if (buffer != NULL) *buffer = '\0'; if (git_buf_joinpath(&path, repo->path_repository, GIT_MERGE_MSG_FILE) < 0) return -1; if ((error = p_stat(git_buf_cstr(&path), &st)) < 0) { if (errno == ENOENT) error = GIT_ENOTFOUND; giterr_set(GITERR_OS, "Could not access message file"); } else if (buffer != NULL) { error = git_futils_readbuffer(&buf, git_buf_cstr(&path)); git_buf_copy_cstr(buffer, len, &buf); } git_buf_free(&path); git_buf_free(&buf); if (!error) error = (int)st.st_size + 1; /* add 1 for NUL byte */ return error; } int git_repository_message_remove(git_repository *repo) { git_buf path = GIT_BUF_INIT; int error; if (git_buf_joinpath(&path, repo->path_repository, GIT_MERGE_MSG_FILE) < 0) return -1; error = p_unlink(git_buf_cstr(&path)); git_buf_free(&path); return error; } int git_repository_hashfile( git_oid *out, git_repository *repo, const char *path, git_otype type, const char *as_path) { int error; git_vector filters = GIT_VECTOR_INIT; git_file fd = -1; git_off_t len; git_buf full_path = GIT_BUF_INIT; assert(out && path && repo); /* as_path can be NULL */ /* At some point, it would be nice if repo could be NULL to just * apply filter rules defined in system and global files, but for * now that is not possible because git_filters_load() needs it. */ error = git_path_join_unrooted( &full_path, path, repo ? git_repository_workdir(repo) : NULL, NULL); if (error < 0) return error; if (!as_path) as_path = path; /* passing empty string for "as_path" indicated --no-filters */ if (strlen(as_path) > 0) { error = git_filters_load(&filters, repo, as_path, GIT_FILTER_TO_ODB); if (error < 0) return error; } else { error = 0; } /* at this point, error is a count of the number of loaded filters */ fd = git_futils_open_ro(full_path.ptr); if (fd < 0) { error = fd; goto cleanup; } len = git_futils_filesize(fd); if (len < 0) { error = (int)len; goto cleanup; } if (!git__is_sizet(len)) { giterr_set(GITERR_OS, "File size overflow for 32-bit systems"); error = -1; goto cleanup; } error = git_odb__hashfd_filtered(out, fd, (size_t)len, type, &filters); cleanup: if (fd >= 0) p_close(fd); git_filters_free(&filters); git_buf_free(&full_path); return error; } static bool looks_like_a_branch(const char *refname) { return git__prefixcmp(refname, GIT_REFS_HEADS_DIR) == 0; } int git_repository_set_head( git_repository* repo, const char* refname) { git_reference *ref, *new_head = NULL; int error; assert(repo && refname); error = git_reference_lookup(&ref, repo, refname); if (error < 0 && error != GIT_ENOTFOUND) return error; if (!error) { if (git_reference_is_branch(ref)) error = git_reference_symbolic_create(&new_head, repo, GIT_HEAD_FILE, git_reference_name(ref), 1); else error = git_repository_set_head_detached(repo, git_reference_target(ref)); } else if (looks_like_a_branch(refname)) error = git_reference_symbolic_create(&new_head, repo, GIT_HEAD_FILE, refname, 1); git_reference_free(ref); git_reference_free(new_head); return error; } int git_repository_set_head_detached( git_repository* repo, const git_oid* commitish) { int error; git_object *object, *peeled = NULL; git_reference *new_head = NULL; assert(repo && commitish); if ((error = git_object_lookup(&object, repo, commitish, GIT_OBJ_ANY)) < 0) return error; if ((error = git_object_peel(&peeled, object, GIT_OBJ_COMMIT)) < 0) goto cleanup; error = git_reference_create(&new_head, repo, GIT_HEAD_FILE, git_object_id(peeled), 1); cleanup: git_object_free(object); git_object_free(peeled); git_reference_free(new_head); return error; } int git_repository_detach_head( git_repository* repo) { git_reference *old_head = NULL, *new_head = NULL; git_object *object = NULL; int error; assert(repo); if ((error = git_repository_head(&old_head, repo)) < 0) return error; if ((error = git_object_lookup(&object, repo, git_reference_target(old_head), GIT_OBJ_COMMIT)) < 0) goto cleanup; error = git_reference_create(&new_head, repo, GIT_HEAD_FILE, git_reference_target(old_head), 1); cleanup: git_object_free(object); git_reference_free(old_head); git_reference_free(new_head); return error; } /** * Loosely ported from git.git * https://github.com/git/git/blob/master/contrib/completion/git-prompt.sh#L198-289 */ int git_repository_state(git_repository *repo) { git_buf repo_path = GIT_BUF_INIT; int state = GIT_REPOSITORY_STATE_NONE; assert(repo); if (git_buf_puts(&repo_path, repo->path_repository) < 0) return -1; if (git_path_contains_file(&repo_path, GIT_REBASE_MERGE_INTERACTIVE_FILE)) state = GIT_REPOSITORY_STATE_REBASE_INTERACTIVE; else if (git_path_contains_dir(&repo_path, GIT_REBASE_MERGE_DIR)) state = GIT_REPOSITORY_STATE_REBASE_MERGE; else if (git_path_contains_file(&repo_path, GIT_REBASE_APPLY_REBASING_FILE)) state = GIT_REPOSITORY_STATE_REBASE; else if (git_path_contains_file(&repo_path, GIT_REBASE_APPLY_APPLYING_FILE)) state = GIT_REPOSITORY_STATE_APPLY_MAILBOX; else if (git_path_contains_dir(&repo_path, GIT_REBASE_APPLY_DIR)) state = GIT_REPOSITORY_STATE_APPLY_MAILBOX_OR_REBASE; else if (git_path_contains_file(&repo_path, GIT_MERGE_HEAD_FILE)) state = GIT_REPOSITORY_STATE_MERGE; else if(git_path_contains_file(&repo_path, GIT_REVERT_HEAD_FILE)) state = GIT_REPOSITORY_STATE_REVERT; else if(git_path_contains_file(&repo_path, GIT_CHERRY_PICK_HEAD_FILE)) state = GIT_REPOSITORY_STATE_CHERRY_PICK; else if(git_path_contains_file(&repo_path, GIT_BISECT_LOG_FILE)) state = GIT_REPOSITORY_STATE_BISECT; git_buf_free(&repo_path); return state; } int git_repository_is_shallow(git_repository *repo) { git_buf path = GIT_BUF_INIT; struct stat st; int error; git_buf_joinpath(&path, repo->path_repository, "shallow"); error = git_path_lstat(path.ptr, &st); git_buf_free(&path); if (error == GIT_ENOTFOUND) return 0; if (error < 0) return -1; return st.st_size == 0 ? 0 : 1; } libgit2-0.19.0/src/repository.h000066400000000000000000000105541216214232500163170ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #ifndef INCLUDE_repository_h__ #define INCLUDE_repository_h__ #include "git2/common.h" #include "git2/oid.h" #include "git2/odb.h" #include "git2/repository.h" #include "git2/object.h" #include "git2/config.h" #include "cache.h" #include "refs.h" #include "buffer.h" #include "object.h" #include "attrcache.h" #include "strmap.h" #include "diff_driver.h" #define DOT_GIT ".git" #define GIT_DIR DOT_GIT "/" #define GIT_DIR_MODE 0755 #define GIT_BARE_DIR_MODE 0777 /** Cvar cache identifiers */ typedef enum { GIT_CVAR_AUTO_CRLF = 0, /* core.autocrlf */ GIT_CVAR_EOL, /* core.eol */ GIT_CVAR_SYMLINKS, /* core.symlinks */ GIT_CVAR_IGNORECASE, /* core.ignorecase */ GIT_CVAR_FILEMODE, /* core.filemode */ GIT_CVAR_IGNORESTAT, /* core.ignorestat */ GIT_CVAR_TRUSTCTIME, /* core.trustctime */ GIT_CVAR_ABBREV, /* core.abbrev */ GIT_CVAR_CACHE_MAX } git_cvar_cached; /** * CVAR value enumerations * * These are the values that are actually stored in the cvar cache, instead * of their string equivalents. These values are internal and symbolic; * make sure that none of them is set to `-1`, since that is the unique * identifier for "not cached" */ typedef enum { /* The value hasn't been loaded from the cache yet */ GIT_CVAR_NOT_CACHED = -1, /* core.safecrlf: false, 'fail', 'warn' */ GIT_SAFE_CRLF_FALSE = 0, GIT_SAFE_CRLF_FAIL = 1, GIT_SAFE_CRLF_WARN = 2, /* core.autocrlf: false, true, 'input; */ GIT_AUTO_CRLF_FALSE = 0, GIT_AUTO_CRLF_TRUE = 1, GIT_AUTO_CRLF_INPUT = 2, GIT_AUTO_CRLF_DEFAULT = GIT_AUTO_CRLF_FALSE, /* core.eol: unset, 'crlf', 'lf', 'native' */ GIT_EOL_UNSET = 0, GIT_EOL_CRLF = 1, GIT_EOL_LF = 2, #ifdef GIT_WIN32 GIT_EOL_NATIVE = GIT_EOL_CRLF, #else GIT_EOL_NATIVE = GIT_EOL_LF, #endif GIT_EOL_DEFAULT = GIT_EOL_NATIVE, /* core.symlinks: bool */ GIT_SYMLINKS_DEFAULT = GIT_CVAR_TRUE, /* core.ignorecase */ GIT_IGNORECASE_DEFAULT = GIT_CVAR_FALSE, /* core.filemode */ GIT_FILEMODE_DEFAULT = GIT_CVAR_TRUE, /* core.ignorestat */ GIT_IGNORESTAT_DEFAULT = GIT_CVAR_FALSE, /* core.trustctime */ GIT_TRUSTCTIME_DEFAULT = GIT_CVAR_TRUE, /* core.abbrev */ GIT_ABBREV_DEFAULT = 7, } git_cvar_value; /* internal repository init flags */ enum { GIT_REPOSITORY_INIT__HAS_DOTGIT = (1u << 16), GIT_REPOSITORY_INIT__NATURAL_WD = (1u << 17), GIT_REPOSITORY_INIT__IS_REINIT = (1u << 18), }; /** Internal structure for repository object */ struct git_repository { git_odb *_odb; git_refdb *_refdb; git_config *_config; git_index *_index; git_cache objects; git_attr_cache attrcache; git_strmap *submodules; git_diff_driver_registry *diff_drivers; char *path_repository; char *workdir; char *namespace; unsigned is_bare:1; unsigned int lru_counter; git_cvar_value cvar_cache[GIT_CVAR_CACHE_MAX]; }; GIT_INLINE(git_attr_cache *) git_repository_attr_cache(git_repository *repo) { return &repo->attrcache; } int git_repository_head_tree(git_tree **tree, git_repository *repo); /* * Weak pointers to repository internals. * * The returned pointers do not need to be freed. Do not keep * permanent references to these (i.e. between API calls), since they may * become invalidated if the user replaces a repository internal. */ int git_repository_config__weakptr(git_config **out, git_repository *repo); int git_repository_odb__weakptr(git_odb **out, git_repository *repo); int git_repository_refdb__weakptr(git_refdb **out, git_repository *repo); int git_repository_index__weakptr(git_index **out, git_repository *repo); /* * CVAR cache * * Efficient access to the most used config variables of a repository. * The cache is cleared everytime the config backend is replaced. */ int git_repository__cvar(int *out, git_repository *repo, git_cvar_cached cvar); void git_repository__cvar_cache_clear(git_repository *repo); /* * Submodule cache */ extern void git_submodule_config_free(git_repository *repo); GIT_INLINE(int) git_repository__ensure_not_bare( git_repository *repo, const char *operation_name) { if (!git_repository_is_bare(repo)) return 0; giterr_set( GITERR_REPOSITORY, "Cannot %s. This operation is not allowed against bare repositories.", operation_name); return GIT_EBAREREPO; } #endif libgit2-0.19.0/src/reset.c000066400000000000000000000100321216214232500152040ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #include "common.h" #include "commit.h" #include "tag.h" #include "merge.h" #include "diff.h" #include "git2/reset.h" #include "git2/checkout.h" #include "git2/merge.h" #include "git2/refs.h" #define ERROR_MSG "Cannot perform reset" int git_reset_default( git_repository *repo, git_object *target, git_strarray* pathspecs) { git_object *commit = NULL; git_tree *tree = NULL; git_diff_list *diff = NULL; git_diff_options opts = GIT_DIFF_OPTIONS_INIT; size_t i; git_diff_delta *delta; git_index_entry entry; int error; git_index *index = NULL; assert(pathspecs != NULL && pathspecs->count > 0); memset(&entry, 0, sizeof(git_index_entry)); if ((error = git_repository_index(&index, repo)) < 0) goto cleanup; if (target) { if (git_object_owner(target) != repo) { giterr_set(GITERR_OBJECT, "%s_default - The given target does not belong to this repository.", ERROR_MSG); return -1; } if ((error = git_object_peel(&commit, target, GIT_OBJ_COMMIT)) < 0 || (error = git_commit_tree(&tree, (git_commit *)commit)) < 0) goto cleanup; } opts.pathspec = *pathspecs; opts.flags = GIT_DIFF_REVERSE; if ((error = git_diff_tree_to_index( &diff, repo, tree, index, &opts)) < 0) goto cleanup; git_vector_foreach(&diff->deltas, i, delta) { if ((error = git_index_conflict_remove(index, delta->old_file.path)) < 0) goto cleanup; assert(delta->status == GIT_DELTA_ADDED || delta->status == GIT_DELTA_MODIFIED || delta->status == GIT_DELTA_DELETED); if (delta->status == GIT_DELTA_DELETED) { if ((error = git_index_remove(index, delta->old_file.path, 0)) < 0) goto cleanup; } else { entry.mode = delta->new_file.mode; git_oid_cpy(&entry.oid, &delta->new_file.oid); entry.path = (char *)delta->new_file.path; if ((error = git_index_add(index, &entry)) < 0) goto cleanup; } } error = git_index_write(index); cleanup: git_object_free(commit); git_tree_free(tree); git_index_free(index); git_diff_list_free(diff); return error; } int git_reset( git_repository *repo, git_object *target, git_reset_t reset_type) { git_object *commit = NULL; git_index *index = NULL; git_tree *tree = NULL; int error = 0; git_checkout_opts opts = GIT_CHECKOUT_OPTS_INIT; assert(repo && target); if (git_object_owner(target) != repo) { giterr_set(GITERR_OBJECT, "%s - The given target does not belong to this repository.", ERROR_MSG); return -1; } if (reset_type != GIT_RESET_SOFT && (error = git_repository__ensure_not_bare(repo, reset_type == GIT_RESET_MIXED ? "reset mixed" : "reset hard")) < 0) return error; if ((error = git_object_peel(&commit, target, GIT_OBJ_COMMIT)) < 0 || (error = git_repository_index(&index, repo)) < 0 || (error = git_commit_tree(&tree, (git_commit *)commit)) < 0) goto cleanup; if (reset_type == GIT_RESET_SOFT && (git_repository_state(repo) == GIT_REPOSITORY_STATE_MERGE || git_index_has_conflicts(index))) { giterr_set(GITERR_OBJECT, "%s (soft) in the middle of a merge.", ERROR_MSG); error = GIT_EUNMERGED; goto cleanup; } /* move HEAD to the new target */ if ((error = git_reference__update_terminal(repo, GIT_HEAD_FILE, git_object_id(commit))) < 0) goto cleanup; if (reset_type == GIT_RESET_HARD) { /* overwrite working directory with HEAD */ opts.checkout_strategy = GIT_CHECKOUT_FORCE; if ((error = git_checkout_tree(repo, (git_object *)tree, &opts)) < 0) goto cleanup; } if (reset_type > GIT_RESET_SOFT) { /* reset index to the target content */ if ((error = git_index_read_tree(index, tree)) < 0 || (error = git_index_write(index)) < 0) goto cleanup; if ((error = git_repository_merge_cleanup(repo)) < 0) { giterr_set(GITERR_INDEX, "%s - failed to clean up merge data", ERROR_MSG); goto cleanup; } } cleanup: git_object_free(commit); git_index_free(index); git_tree_free(tree); return error; } libgit2-0.19.0/src/revparse.c000066400000000000000000000471101216214232500157200ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #include #include "common.h" #include "buffer.h" #include "tree.h" #include "refdb.h" #include "git2.h" static int maybe_sha_or_abbrev(git_object** out, git_repository *repo, const char *spec, size_t speclen) { git_oid oid; if (git_oid_fromstrn(&oid, spec, speclen) < 0) return GIT_ENOTFOUND; return git_object_lookup_prefix(out, repo, &oid, speclen, GIT_OBJ_ANY); } static int maybe_sha(git_object** out, git_repository *repo, const char *spec) { size_t speclen = strlen(spec); if (speclen != GIT_OID_HEXSZ) return GIT_ENOTFOUND; return maybe_sha_or_abbrev(out, repo, spec, speclen); } static int maybe_abbrev(git_object** out, git_repository *repo, const char *spec) { size_t speclen = strlen(spec); return maybe_sha_or_abbrev(out, repo, spec, speclen); } static int build_regex(regex_t *regex, const char *pattern) { int error; if (*pattern == '\0') { giterr_set(GITERR_REGEX, "Empty pattern"); return GIT_EINVALIDSPEC; } error = regcomp(regex, pattern, REG_EXTENDED); if (!error) return 0; error = giterr_set_regex(regex, error); regfree(regex); return error; } static int maybe_describe(git_object**out, git_repository *repo, const char *spec) { const char *substr; int error; regex_t regex; substr = strstr(spec, "-g"); if (substr == NULL) return GIT_ENOTFOUND; if (build_regex(®ex, ".+-[0-9]+-g[0-9a-fA-F]+") < 0) return -1; error = regexec(®ex, spec, 0, NULL, 0); regfree(®ex); if (error) return GIT_ENOTFOUND; return maybe_abbrev(out, repo, substr+2); } static int revparse_lookup_object( git_object **object_out, git_reference **reference_out, git_repository *repo, const char *spec) { int error; git_reference *ref; error = maybe_sha(object_out, repo, spec); if (!error) return 0; if (error < 0 && error != GIT_ENOTFOUND) return error; error = git_reference_dwim(&ref, repo, spec); if (!error) { error = git_object_lookup( object_out, repo, git_reference_target(ref), GIT_OBJ_ANY); if (!error) *reference_out = ref; return error; } if (error < 0 && error != GIT_ENOTFOUND) return error; error = maybe_abbrev(object_out, repo, spec); if (!error) return 0; if (error < 0 && error != GIT_ENOTFOUND) return error; error = maybe_describe(object_out, repo, spec); if (!error) return 0; if (error < 0 && error != GIT_ENOTFOUND) return error; giterr_set(GITERR_REFERENCE, "Refspec '%s' not found.", spec); return GIT_ENOTFOUND; } static int try_parse_numeric(int *n, const char *curly_braces_content) { int32_t content; const char *end_ptr; if (git__strtol32(&content, curly_braces_content, &end_ptr, 10) < 0) return -1; if (*end_ptr != '\0') return -1; *n = (int)content; return 0; } static int retrieve_previously_checked_out_branch_or_revision(git_object **out, git_reference **base_ref, git_repository *repo, const char *identifier, size_t position) { git_reference *ref = NULL; git_reflog *reflog = NULL; regex_t preg; int error = -1; size_t i, numentries, cur; const git_reflog_entry *entry; const char *msg; regmatch_t regexmatches[2]; git_buf buf = GIT_BUF_INIT; cur = position; if (*identifier != '\0' || *base_ref != NULL) return GIT_EINVALIDSPEC; if (build_regex(&preg, "checkout: moving from (.*) to .*") < 0) return -1; if (git_reference_lookup(&ref, repo, GIT_HEAD_FILE) < 0) goto cleanup; if (git_reflog_read(&reflog, ref) < 0) goto cleanup; numentries = git_reflog_entrycount(reflog); for (i = 0; i < numentries; i++) { entry = git_reflog_entry_byindex(reflog, i); msg = git_reflog_entry_message(entry); if (regexec(&preg, msg, 2, regexmatches, 0)) continue; cur--; if (cur > 0) continue; git_buf_put(&buf, msg+regexmatches[1].rm_so, regexmatches[1].rm_eo - regexmatches[1].rm_so); if ((error = git_reference_dwim(base_ref, repo, git_buf_cstr(&buf))) == 0) goto cleanup; if (error < 0 && error != GIT_ENOTFOUND) goto cleanup; error = maybe_abbrev(out, repo, git_buf_cstr(&buf)); goto cleanup; } error = GIT_ENOTFOUND; cleanup: git_reference_free(ref); git_buf_free(&buf); regfree(&preg); git_reflog_free(reflog); return error; } static int retrieve_oid_from_reflog(git_oid *oid, git_reference *ref, size_t identifier) { git_reflog *reflog; int error = -1; size_t numentries; const git_reflog_entry *entry; bool search_by_pos = (identifier <= 100000000); if (git_reflog_read(&reflog, ref) < 0) return -1; numentries = git_reflog_entrycount(reflog); if (search_by_pos) { if (numentries < identifier + 1) { giterr_set( GITERR_REFERENCE, "Reflog for '%s' has only "PRIuZ" entries, asked for "PRIuZ, git_reference_name(ref), numentries, identifier); error = GIT_ENOTFOUND; goto cleanup; } entry = git_reflog_entry_byindex(reflog, identifier); git_oid_cpy(oid, git_reflog_entry_id_new(entry)); error = 0; goto cleanup; } else { size_t i; git_time commit_time; for (i = 0; i < numentries; i++) { entry = git_reflog_entry_byindex(reflog, i); commit_time = git_reflog_entry_committer(entry)->when; if (commit_time.time > (git_time_t)identifier) continue; git_oid_cpy(oid, git_reflog_entry_id_new(entry)); error = 0; goto cleanup; } error = GIT_ENOTFOUND; } cleanup: git_reflog_free(reflog); return error; } static int retrieve_revobject_from_reflog(git_object **out, git_reference **base_ref, git_repository *repo, const char *identifier, size_t position) { git_reference *ref; git_oid oid; int error = -1; if (*base_ref == NULL) { if ((error = git_reference_dwim(&ref, repo, identifier)) < 0) return error; } else { ref = *base_ref; *base_ref = NULL; } if (position == 0) { error = git_object_lookup(out, repo, git_reference_target(ref), GIT_OBJ_ANY); goto cleanup; } if ((error = retrieve_oid_from_reflog(&oid, ref, position)) < 0) goto cleanup; error = git_object_lookup(out, repo, &oid, GIT_OBJ_ANY); cleanup: git_reference_free(ref); return error; } static int retrieve_remote_tracking_reference(git_reference **base_ref, const char *identifier, git_repository *repo) { git_reference *tracking, *ref; int error = -1; if (*base_ref == NULL) { if ((error = git_reference_dwim(&ref, repo, identifier)) < 0) return error; } else { ref = *base_ref; *base_ref = NULL; } if (!git_reference_is_branch(ref)) { error = GIT_EINVALIDSPEC; goto cleanup; } if ((error = git_branch_upstream(&tracking, ref)) < 0) goto cleanup; *base_ref = tracking; cleanup: git_reference_free(ref); return error; } static int handle_at_syntax(git_object **out, git_reference **ref, const char *spec, size_t identifier_len, git_repository* repo, const char *curly_braces_content) { bool is_numeric; int parsed = 0, error = -1; git_buf identifier = GIT_BUF_INIT; git_time_t timestamp; assert(*out == NULL); if (git_buf_put(&identifier, spec, identifier_len) < 0) return -1; is_numeric = !try_parse_numeric(&parsed, curly_braces_content); if (*curly_braces_content == '-' && (!is_numeric || parsed == 0)) { error = GIT_EINVALIDSPEC; goto cleanup; } if (is_numeric) { if (parsed < 0) error = retrieve_previously_checked_out_branch_or_revision(out, ref, repo, git_buf_cstr(&identifier), -parsed); else error = retrieve_revobject_from_reflog(out, ref, repo, git_buf_cstr(&identifier), parsed); goto cleanup; } if (!strcmp(curly_braces_content, "u") || !strcmp(curly_braces_content, "upstream")) { error = retrieve_remote_tracking_reference(ref, git_buf_cstr(&identifier), repo); goto cleanup; } if (git__date_parse(×tamp, curly_braces_content) < 0) goto cleanup; error = retrieve_revobject_from_reflog(out, ref, repo, git_buf_cstr(&identifier), (size_t)timestamp); cleanup: git_buf_free(&identifier); return error; } static git_otype parse_obj_type(const char *str) { if (!strcmp(str, "commit")) return GIT_OBJ_COMMIT; if (!strcmp(str, "tree")) return GIT_OBJ_TREE; if (!strcmp(str, "blob")) return GIT_OBJ_BLOB; if (!strcmp(str, "tag")) return GIT_OBJ_TAG; return GIT_OBJ_BAD; } static int dereference_to_non_tag(git_object **out, git_object *obj) { if (git_object_type(obj) == GIT_OBJ_TAG) return git_tag_peel(out, (git_tag *)obj); return git_object_dup(out, obj); } static int handle_caret_parent_syntax(git_object **out, git_object *obj, int n) { git_object *temp_commit = NULL; int error; if ((error = git_object_peel(&temp_commit, obj, GIT_OBJ_COMMIT)) < 0) return (error == GIT_EAMBIGUOUS || error == GIT_ENOTFOUND) ? GIT_EINVALIDSPEC : error; if (n == 0) { *out = temp_commit; return 0; } error = git_commit_parent((git_commit **)out, (git_commit*)temp_commit, n - 1); git_object_free(temp_commit); return error; } static int handle_linear_syntax(git_object **out, git_object *obj, int n) { git_object *temp_commit = NULL; int error; if ((error = git_object_peel(&temp_commit, obj, GIT_OBJ_COMMIT)) < 0) return (error == GIT_EAMBIGUOUS || error == GIT_ENOTFOUND) ? GIT_EINVALIDSPEC : error; error = git_commit_nth_gen_ancestor((git_commit **)out, (git_commit*)temp_commit, n); git_object_free(temp_commit); return error; } static int handle_colon_syntax( git_object **out, git_object *obj, const char *path) { git_object *tree; int error = -1; git_tree_entry *entry = NULL; if ((error = git_object_peel(&tree, obj, GIT_OBJ_TREE)) < 0) return error == GIT_ENOTFOUND ? GIT_EINVALIDSPEC : error; if (*path == '\0') { *out = tree; return 0; } /* * TODO: Handle the relative path syntax * (:./relative/path and :../relative/path) */ if ((error = git_tree_entry_bypath(&entry, (git_tree *)tree, path)) < 0) goto cleanup; error = git_tree_entry_to_object(out, git_object_owner(tree), entry); cleanup: git_tree_entry_free(entry); git_object_free(tree); return error; } static int walk_and_search(git_object **out, git_revwalk *walk, regex_t *regex) { int error; git_oid oid; git_object *obj; while (!(error = git_revwalk_next(&oid, walk))) { error = git_object_lookup(&obj, git_revwalk_repository(walk), &oid, GIT_OBJ_COMMIT); if ((error < 0) && (error != GIT_ENOTFOUND)) return -1; if (!regexec(regex, git_commit_message((git_commit*)obj), 0, NULL, 0)) { *out = obj; return 0; } git_object_free(obj); } if (error < 0 && error == GIT_ITEROVER) error = GIT_ENOTFOUND; return error; } static int handle_grep_syntax(git_object **out, git_repository *repo, const git_oid *spec_oid, const char *pattern) { regex_t preg; git_revwalk *walk = NULL; int error; if ((error = build_regex(&preg, pattern)) < 0) return error; if ((error = git_revwalk_new(&walk, repo)) < 0) goto cleanup; git_revwalk_sorting(walk, GIT_SORT_TIME); if (spec_oid == NULL) { // TODO: @carlosmn: The glob should be refs/* but this makes git_revwalk_next() fails if ((error = git_revwalk_push_glob(walk, GIT_REFS_HEADS_DIR "*")) < 0) goto cleanup; } else if ((error = git_revwalk_push(walk, spec_oid)) < 0) goto cleanup; error = walk_and_search(out, walk, &preg); cleanup: regfree(&preg); git_revwalk_free(walk); return error; } static int handle_caret_curly_syntax(git_object **out, git_object *obj, const char *curly_braces_content) { git_otype expected_type; if (*curly_braces_content == '\0') return dereference_to_non_tag(out, obj); if (*curly_braces_content == '/') return handle_grep_syntax(out, git_object_owner(obj), git_object_id(obj), curly_braces_content + 1); expected_type = parse_obj_type(curly_braces_content); if (expected_type == GIT_OBJ_BAD) return GIT_EINVALIDSPEC; return git_object_peel(out, obj, expected_type); } static int extract_curly_braces_content(git_buf *buf, const char *spec, size_t *pos) { git_buf_clear(buf); assert(spec[*pos] == '^' || spec[*pos] == '@'); (*pos)++; if (spec[*pos] == '\0' || spec[*pos] != '{') return GIT_EINVALIDSPEC; (*pos)++; while (spec[*pos] != '}') { if (spec[*pos] == '\0') return GIT_EINVALIDSPEC; git_buf_putc(buf, spec[(*pos)++]); } (*pos)++; return 0; } static int extract_path(git_buf *buf, const char *spec, size_t *pos) { git_buf_clear(buf); assert(spec[*pos] == ':'); (*pos)++; if (git_buf_puts(buf, spec + *pos) < 0) return -1; *pos += git_buf_len(buf); return 0; } static int extract_how_many(int *n, const char *spec, size_t *pos) { const char *end_ptr; int parsed, accumulated; char kind = spec[*pos]; assert(spec[*pos] == '^' || spec[*pos] == '~'); accumulated = 0; do { do { (*pos)++; accumulated++; } while (spec[(*pos)] == kind && kind == '~'); if (git__isdigit(spec[*pos])) { if (git__strtol32(&parsed, spec + *pos, &end_ptr, 10) < 0) return GIT_EINVALIDSPEC; accumulated += (parsed - 1); *pos = end_ptr - spec; } } while (spec[(*pos)] == kind && kind == '~'); *n = accumulated; return 0; } static int object_from_reference(git_object **object, git_reference *reference) { git_reference *resolved = NULL; int error; if (git_reference_resolve(&resolved, reference) < 0) return -1; error = git_object_lookup(object, reference->db->repo, git_reference_target(resolved), GIT_OBJ_ANY); git_reference_free(resolved); return error; } static int ensure_base_rev_loaded(git_object **object, git_reference **reference, const char *spec, size_t identifier_len, git_repository *repo, bool allow_empty_identifier) { int error; git_buf identifier = GIT_BUF_INIT; if (*object != NULL) return 0; if (*reference != NULL) return object_from_reference(object, *reference); if (!allow_empty_identifier && identifier_len == 0) return GIT_EINVALIDSPEC; if (git_buf_put(&identifier, spec, identifier_len) < 0) return -1; error = revparse_lookup_object(object, reference, repo, git_buf_cstr(&identifier)); git_buf_free(&identifier); return error; } static int ensure_base_rev_is_not_known_yet(git_object *object) { if (object == NULL) return 0; return GIT_EINVALIDSPEC; } static bool any_left_hand_identifier(git_object *object, git_reference *reference, size_t identifier_len) { if (object != NULL) return true; if (reference != NULL) return true; if (identifier_len > 0) return true; return false; } static int ensure_left_hand_identifier_is_not_known_yet(git_object *object, git_reference *reference) { if (!ensure_base_rev_is_not_known_yet(object) && reference == NULL) return 0; return GIT_EINVALIDSPEC; } int revparse__ext( git_object **object_out, git_reference **reference_out, size_t *identifier_len_out, git_repository *repo, const char *spec) { size_t pos = 0, identifier_len = 0; int error = -1, n; git_buf buf = GIT_BUF_INIT; git_reference *reference = NULL; git_object *base_rev = NULL; assert(object_out && reference_out && repo && spec); *object_out = NULL; *reference_out = NULL; while (spec[pos]) { switch (spec[pos]) { case '^': if ((error = ensure_base_rev_loaded(&base_rev, &reference, spec, identifier_len, repo, false)) < 0) goto cleanup; if (spec[pos+1] == '{') { git_object *temp_object = NULL; if ((error = extract_curly_braces_content(&buf, spec, &pos)) < 0) goto cleanup; if ((error = handle_caret_curly_syntax(&temp_object, base_rev, git_buf_cstr(&buf))) < 0) goto cleanup; git_object_free(base_rev); base_rev = temp_object; } else { git_object *temp_object = NULL; if ((error = extract_how_many(&n, spec, &pos)) < 0) goto cleanup; if ((error = handle_caret_parent_syntax(&temp_object, base_rev, n)) < 0) goto cleanup; git_object_free(base_rev); base_rev = temp_object; } break; case '~': { git_object *temp_object = NULL; if ((error = extract_how_many(&n, spec, &pos)) < 0) goto cleanup; if ((error = ensure_base_rev_loaded(&base_rev, &reference, spec, identifier_len, repo, false)) < 0) goto cleanup; if ((error = handle_linear_syntax(&temp_object, base_rev, n)) < 0) goto cleanup; git_object_free(base_rev); base_rev = temp_object; break; } case ':': { git_object *temp_object = NULL; if ((error = extract_path(&buf, spec, &pos)) < 0) goto cleanup; if (any_left_hand_identifier(base_rev, reference, identifier_len)) { if ((error = ensure_base_rev_loaded(&base_rev, &reference, spec, identifier_len, repo, true)) < 0) goto cleanup; if ((error = handle_colon_syntax(&temp_object, base_rev, git_buf_cstr(&buf))) < 0) goto cleanup; } else { if (*git_buf_cstr(&buf) == '/') { if ((error = handle_grep_syntax(&temp_object, repo, NULL, git_buf_cstr(&buf) + 1)) < 0) goto cleanup; } else { /* * TODO: support merge-stage path lookup (":2:Makefile") * and plain index blob lookup (:i-am/a/blob) */ giterr_set(GITERR_INVALID, "Unimplemented"); error = GIT_ERROR; goto cleanup; } } git_object_free(base_rev); base_rev = temp_object; break; } case '@': { if (spec[pos+1] == '{') { git_object *temp_object = NULL; if ((error = extract_curly_braces_content(&buf, spec, &pos)) < 0) goto cleanup; if ((error = ensure_base_rev_is_not_known_yet(base_rev)) < 0) goto cleanup; if ((error = handle_at_syntax(&temp_object, &reference, spec, identifier_len, repo, git_buf_cstr(&buf))) < 0) goto cleanup; if (temp_object != NULL) base_rev = temp_object; break; } else { /* Fall through */ } } default: if ((error = ensure_left_hand_identifier_is_not_known_yet(base_rev, reference)) < 0) goto cleanup; pos++; identifier_len++; } } if ((error = ensure_base_rev_loaded(&base_rev, &reference, spec, identifier_len, repo, false)) < 0) goto cleanup; *object_out = base_rev; *reference_out = reference; *identifier_len_out = identifier_len; error = 0; cleanup: if (error) { if (error == GIT_EINVALIDSPEC) giterr_set(GITERR_INVALID, "Failed to parse revision specifier - Invalid pattern '%s'", spec); git_object_free(base_rev); git_reference_free(reference); } git_buf_free(&buf); return error; } int git_revparse_ext( git_object **object_out, git_reference **reference_out, git_repository *repo, const char *spec) { int error; size_t identifier_len; git_object *obj = NULL; git_reference *ref = NULL; if ((error = revparse__ext(&obj, &ref, &identifier_len, repo, spec)) < 0) goto cleanup; *object_out = obj; *reference_out = ref; GIT_UNUSED(identifier_len); return 0; cleanup: git_object_free(obj); git_reference_free(ref); return error; } int git_revparse_single(git_object **out, git_repository *repo, const char *spec) { int error; git_object *obj = NULL; git_reference *ref = NULL; *out = NULL; if ((error = git_revparse_ext(&obj, &ref, repo, spec)) < 0) goto cleanup; git_reference_free(ref); *out = obj; return 0; cleanup: git_object_free(obj); git_reference_free(ref); return error; } int git_revparse( git_revspec *revspec, git_repository *repo, const char *spec) { const char *dotdot; int error = 0; assert(revspec && repo && spec); memset(revspec, 0x0, sizeof(*revspec)); if ((dotdot = strstr(spec, "..")) != NULL) { char *lstr; const char *rstr; revspec->flags = GIT_REVPARSE_RANGE; lstr = git__substrdup(spec, dotdot - spec); rstr = dotdot + 2; if (dotdot[2] == '.') { revspec->flags |= GIT_REVPARSE_MERGE_BASE; rstr++; } if ((error = git_revparse_single(&revspec->from, repo, lstr)) < 0) { return error; } if ((error = git_revparse_single(&revspec->to, repo, rstr)) < 0) { return error; } git__free((void*)lstr); } else { revspec->flags = GIT_REVPARSE_SINGLE; error = git_revparse_single(&revspec->from, repo, spec); } return error; } libgit2-0.19.0/src/revwalk.c000066400000000000000000000263011216214232500155430ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #include "common.h" #include "commit.h" #include "odb.h" #include "pool.h" #include "revwalk.h" #include "git2/revparse.h" #include "merge.h" #include git_commit_list_node *git_revwalk__commit_lookup( git_revwalk *walk, const git_oid *oid) { git_commit_list_node *commit; khiter_t pos; int ret; /* lookup and reserve space if not already present */ pos = kh_get(oid, walk->commits, oid); if (pos != kh_end(walk->commits)) return kh_value(walk->commits, pos); commit = git_commit_list_alloc_node(walk); if (commit == NULL) return NULL; git_oid_cpy(&commit->oid, oid); pos = kh_put(oid, walk->commits, &commit->oid, &ret); assert(ret != 0); kh_value(walk->commits, pos) = commit; return commit; } static void mark_uninteresting(git_commit_list_node *commit) { unsigned short i; assert(commit); commit->uninteresting = 1; /* This means we've reached a merge base, so there's no need to walk any more */ if ((commit->flags & (RESULT | STALE)) == RESULT) return; for (i = 0; i < commit->out_degree; ++i) if (!commit->parents[i]->uninteresting) mark_uninteresting(commit->parents[i]); } static int process_commit(git_revwalk *walk, git_commit_list_node *commit, int hide) { int error; if (hide) mark_uninteresting(commit); if (commit->seen) return 0; commit->seen = 1; if ((error = git_commit_list_parse(walk, commit)) < 0) return error; return walk->enqueue(walk, commit); } static int process_commit_parents(git_revwalk *walk, git_commit_list_node *commit) { unsigned short i; int error = 0; for (i = 0; i < commit->out_degree && !error; ++i) error = process_commit(walk, commit->parents[i], commit->uninteresting); return error; } static int push_commit(git_revwalk *walk, const git_oid *oid, int uninteresting) { git_object *obj; git_otype type; git_commit_list_node *commit; if (git_object_lookup(&obj, walk->repo, oid, GIT_OBJ_ANY) < 0) return -1; type = git_object_type(obj); git_object_free(obj); if (type != GIT_OBJ_COMMIT) { giterr_set(GITERR_INVALID, "Object is no commit object"); return -1; } commit = git_revwalk__commit_lookup(walk, oid); if (commit == NULL) return -1; /* error already reported by failed lookup */ commit->uninteresting = uninteresting; if (walk->one == NULL && !uninteresting) { walk->one = commit; } else { if (git_vector_insert(&walk->twos, commit) < 0) return -1; } return 0; } int git_revwalk_push(git_revwalk *walk, const git_oid *oid) { assert(walk && oid); return push_commit(walk, oid, 0); } int git_revwalk_hide(git_revwalk *walk, const git_oid *oid) { assert(walk && oid); return push_commit(walk, oid, 1); } static int push_ref(git_revwalk *walk, const char *refname, int hide) { git_oid oid; if (git_reference_name_to_id(&oid, walk->repo, refname) < 0) return -1; return push_commit(walk, &oid, hide); } struct push_cb_data { git_revwalk *walk; int hide; }; static int push_glob_cb(const char *refname, void *data_) { struct push_cb_data *data = (struct push_cb_data *)data_; return push_ref(data->walk, refname, data->hide); } static int push_glob(git_revwalk *walk, const char *glob, int hide) { git_buf buf = GIT_BUF_INIT; struct push_cb_data data; regex_t preg; assert(walk && glob); /* refs/ is implied if not given in the glob */ if (strncmp(glob, GIT_REFS_DIR, strlen(GIT_REFS_DIR))) { git_buf_printf(&buf, GIT_REFS_DIR "%s", glob); } else { git_buf_puts(&buf, glob); } /* If no '?', '*' or '[' exist, we append '/ *' to the glob */ memset(&preg, 0x0, sizeof(regex_t)); if (regcomp(&preg, "[?*[]", REG_EXTENDED)) { giterr_set(GITERR_OS, "Regex failed to compile"); git_buf_free(&buf); return -1; } if (regexec(&preg, glob, 0, NULL, 0)) git_buf_puts(&buf, "/*"); if (git_buf_oom(&buf)) goto on_error; data.walk = walk; data.hide = hide; if (git_reference_foreach_glob( walk->repo, git_buf_cstr(&buf), push_glob_cb, &data) < 0) goto on_error; regfree(&preg); git_buf_free(&buf); return 0; on_error: regfree(&preg); git_buf_free(&buf); return -1; } int git_revwalk_push_glob(git_revwalk *walk, const char *glob) { assert(walk && glob); return push_glob(walk, glob, 0); } int git_revwalk_hide_glob(git_revwalk *walk, const char *glob) { assert(walk && glob); return push_glob(walk, glob, 1); } int git_revwalk_push_head(git_revwalk *walk) { assert(walk); return push_ref(walk, GIT_HEAD_FILE, 0); } int git_revwalk_hide_head(git_revwalk *walk) { assert(walk); return push_ref(walk, GIT_HEAD_FILE, 1); } int git_revwalk_push_ref(git_revwalk *walk, const char *refname) { assert(walk && refname); return push_ref(walk, refname, 0); } int git_revwalk_push_range(git_revwalk *walk, const char *range) { git_revspec revspec; int error = 0; if ((error = git_revparse(&revspec, walk->repo, range))) return error; if (revspec.flags & GIT_REVPARSE_MERGE_BASE) { /* TODO: support "..." */ giterr_set(GITERR_INVALID, "Symmetric differences not implemented in revwalk"); return GIT_EINVALIDSPEC; } if ((error = push_commit(walk, git_object_id(revspec.from), 1))) goto out; error = push_commit(walk, git_object_id(revspec.to), 0); out: git_object_free(revspec.from); git_object_free(revspec.to); return error; } int git_revwalk_hide_ref(git_revwalk *walk, const char *refname) { assert(walk && refname); return push_ref(walk, refname, 1); } static int revwalk_enqueue_timesort(git_revwalk *walk, git_commit_list_node *commit) { return git_pqueue_insert(&walk->iterator_time, commit); } static int revwalk_enqueue_unsorted(git_revwalk *walk, git_commit_list_node *commit) { return git_commit_list_insert(commit, &walk->iterator_rand) ? 0 : -1; } static int revwalk_next_timesort(git_commit_list_node **object_out, git_revwalk *walk) { int error; git_commit_list_node *next; while ((next = git_pqueue_pop(&walk->iterator_time)) != NULL) { if ((error = process_commit_parents(walk, next)) < 0) return error; if (!next->uninteresting) { *object_out = next; return 0; } } giterr_clear(); return GIT_ITEROVER; } static int revwalk_next_unsorted(git_commit_list_node **object_out, git_revwalk *walk) { int error; git_commit_list_node *next; while ((next = git_commit_list_pop(&walk->iterator_rand)) != NULL) { if ((error = process_commit_parents(walk, next)) < 0) return error; if (!next->uninteresting) { *object_out = next; return 0; } } giterr_clear(); return GIT_ITEROVER; } static int revwalk_next_toposort(git_commit_list_node **object_out, git_revwalk *walk) { git_commit_list_node *next; unsigned short i; for (;;) { next = git_commit_list_pop(&walk->iterator_topo); if (next == NULL) { giterr_clear(); return GIT_ITEROVER; } if (next->in_degree > 0) { next->topo_delay = 1; continue; } for (i = 0; i < next->out_degree; ++i) { git_commit_list_node *parent = next->parents[i]; if (--parent->in_degree == 0 && parent->topo_delay) { parent->topo_delay = 0; if (git_commit_list_insert(parent, &walk->iterator_topo) == NULL) return -1; } } *object_out = next; return 0; } } static int revwalk_next_reverse(git_commit_list_node **object_out, git_revwalk *walk) { *object_out = git_commit_list_pop(&walk->iterator_reverse); return *object_out ? 0 : GIT_ITEROVER; } static int prepare_walk(git_revwalk *walk) { int error; unsigned int i; git_commit_list_node *next, *two; git_commit_list *bases = NULL; /* * If walk->one is NULL, there were no positive references, * so we know that the walk is already over. */ if (walk->one == NULL) { giterr_clear(); return GIT_ITEROVER; } /* first figure out what the merge bases are */ if (git_merge__bases_many(&bases, walk, walk->one, &walk->twos) < 0) return -1; git_commit_list_free(&bases); if (process_commit(walk, walk->one, walk->one->uninteresting) < 0) return -1; git_vector_foreach(&walk->twos, i, two) { if (process_commit(walk, two, two->uninteresting) < 0) return -1; } if (walk->sorting & GIT_SORT_TOPOLOGICAL) { unsigned short i; while ((error = walk->get_next(&next, walk)) == 0) { for (i = 0; i < next->out_degree; ++i) { git_commit_list_node *parent = next->parents[i]; parent->in_degree++; } if (git_commit_list_insert(next, &walk->iterator_topo) == NULL) return -1; } if (error != GIT_ITEROVER) return error; walk->get_next = &revwalk_next_toposort; } if (walk->sorting & GIT_SORT_REVERSE) { while ((error = walk->get_next(&next, walk)) == 0) if (git_commit_list_insert(next, &walk->iterator_reverse) == NULL) return -1; if (error != GIT_ITEROVER) return error; walk->get_next = &revwalk_next_reverse; } walk->walking = 1; return 0; } int git_revwalk_new(git_revwalk **revwalk_out, git_repository *repo) { git_revwalk *walk; walk = git__malloc(sizeof(git_revwalk)); GITERR_CHECK_ALLOC(walk); memset(walk, 0x0, sizeof(git_revwalk)); walk->commits = git_oidmap_alloc(); GITERR_CHECK_ALLOC(walk->commits); if (git_pqueue_init(&walk->iterator_time, 8, git_commit_list_time_cmp) < 0 || git_vector_init(&walk->twos, 4, NULL) < 0 || git_pool_init(&walk->commit_pool, 1, git_pool__suggest_items_per_page(COMMIT_ALLOC) * COMMIT_ALLOC) < 0) return -1; walk->get_next = &revwalk_next_unsorted; walk->enqueue = &revwalk_enqueue_unsorted; walk->repo = repo; if (git_repository_odb(&walk->odb, repo) < 0) { git_revwalk_free(walk); return -1; } *revwalk_out = walk; return 0; } void git_revwalk_free(git_revwalk *walk) { if (walk == NULL) return; git_revwalk_reset(walk); git_odb_free(walk->odb); git_oidmap_free(walk->commits); git_pool_clear(&walk->commit_pool); git_pqueue_free(&walk->iterator_time); git_vector_free(&walk->twos); git__free(walk); } git_repository *git_revwalk_repository(git_revwalk *walk) { assert(walk); return walk->repo; } void git_revwalk_sorting(git_revwalk *walk, unsigned int sort_mode) { assert(walk); if (walk->walking) git_revwalk_reset(walk); walk->sorting = sort_mode; if (walk->sorting & GIT_SORT_TIME) { walk->get_next = &revwalk_next_timesort; walk->enqueue = &revwalk_enqueue_timesort; } else { walk->get_next = &revwalk_next_unsorted; walk->enqueue = &revwalk_enqueue_unsorted; } } int git_revwalk_next(git_oid *oid, git_revwalk *walk) { int error; git_commit_list_node *next; assert(walk && oid); if (!walk->walking) { if ((error = prepare_walk(walk)) < 0) return error; } error = walk->get_next(&next, walk); if (error == GIT_ITEROVER) { git_revwalk_reset(walk); giterr_clear(); return GIT_ITEROVER; } if (!error) git_oid_cpy(oid, &next->oid); return error; } void git_revwalk_reset(git_revwalk *walk) { git_commit_list_node *commit; assert(walk); kh_foreach_value(walk->commits, commit, { commit->seen = 0; commit->in_degree = 0; commit->topo_delay = 0; commit->uninteresting = 0; }); git_pqueue_clear(&walk->iterator_time); git_commit_list_free(&walk->iterator_topo); git_commit_list_free(&walk->iterator_rand); git_commit_list_free(&walk->iterator_reverse); walk->walking = 0; walk->one = NULL; git_vector_clear(&walk->twos); } libgit2-0.19.0/src/revwalk.h000066400000000000000000000017411216214232500155510ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #ifndef INCLUDE_revwalk_h__ #define INCLUDE_revwalk_h__ #include "git2/revwalk.h" #include "oidmap.h" #include "commit_list.h" #include "pqueue.h" #include "pool.h" #include "vector.h" GIT__USE_OIDMAP; struct git_revwalk { git_repository *repo; git_odb *odb; git_oidmap *commits; git_pool commit_pool; git_commit_list *iterator_topo; git_commit_list *iterator_rand; git_commit_list *iterator_reverse; git_pqueue iterator_time; int (*get_next)(git_commit_list_node **, git_revwalk *); int (*enqueue)(git_revwalk *, git_commit_list_node *); unsigned walking:1; unsigned int sorting; /* merge base calculation */ git_commit_list_node *one; git_vector twos; }; git_commit_list_node *git_revwalk__commit_lookup(git_revwalk *walk, const git_oid *oid); #endif libgit2-0.19.0/src/sha1_lookup.c000066400000000000000000000123401216214232500163130ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #include #include "sha1_lookup.h" #include "common.h" /* * Conventional binary search loop looks like this: * * unsigned lo, hi; * do { * unsigned mi = (lo + hi) / 2; * int cmp = "entry pointed at by mi" minus "target"; * if (!cmp) * return (mi is the wanted one) * if (cmp > 0) * hi = mi; "mi is larger than target" * else * lo = mi+1; "mi is smaller than target" * } while (lo < hi); * * The invariants are: * * - When entering the loop, lo points at a slot that is never * above the target (it could be at the target), hi points at a * slot that is guaranteed to be above the target (it can never * be at the target). * * - We find a point 'mi' between lo and hi (mi could be the same * as lo, but never can be as same as hi), and check if it hits * the target. There are three cases: * * - if it is a hit, we are happy. * * - if it is strictly higher than the target, we set it to hi, * and repeat the search. * * - if it is strictly lower than the target, we update lo to * one slot after it, because we allow lo to be at the target. * * If the loop exits, there is no matching entry. * * When choosing 'mi', we do not have to take the "middle" but * anywhere in between lo and hi, as long as lo <= mi < hi is * satisfied. When we somehow know that the distance between the * target and lo is much shorter than the target and hi, we could * pick mi that is much closer to lo than the midway. * * Now, we can take advantage of the fact that SHA-1 is a good hash * function, and as long as there are enough entries in the table, we * can expect uniform distribution. An entry that begins with for * example "deadbeef..." is much likely to appear much later than in * the midway of the table. It can reasonably be expected to be near * 87% (222/256) from the top of the table. * * However, we do not want to pick "mi" too precisely. If the entry at * the 87% in the above example turns out to be higher than the target * we are looking for, we would end up narrowing the search space down * only by 13%, instead of 50% we would get if we did a simple binary * search. So we would want to hedge our bets by being less aggressive. * * The table at "table" holds at least "nr" entries of "elem_size" * bytes each. Each entry has the SHA-1 key at "key_offset". The * table is sorted by the SHA-1 key of the entries. The caller wants * to find the entry with "key", and knows that the entry at "lo" is * not higher than the entry it is looking for, and that the entry at * "hi" is higher than the entry it is looking for. */ int sha1_entry_pos(const void *table, size_t elem_size, size_t key_offset, unsigned lo, unsigned hi, unsigned nr, const unsigned char *key) { const unsigned char *base = (const unsigned char*)table; const unsigned char *hi_key, *lo_key; unsigned ofs_0; if (!nr || lo >= hi) return -1; if (nr == hi) hi_key = NULL; else hi_key = base + elem_size * hi + key_offset; lo_key = base + elem_size * lo + key_offset; ofs_0 = 0; do { int cmp; unsigned ofs, mi, range; unsigned lov, hiv, kyv; const unsigned char *mi_key; range = hi - lo; if (hi_key) { for (ofs = ofs_0; ofs < 20; ofs++) if (lo_key[ofs] != hi_key[ofs]) break; ofs_0 = ofs; /* * byte 0 thru (ofs-1) are the same between * lo and hi; ofs is the first byte that is * different. */ hiv = hi_key[ofs_0]; if (ofs_0 < 19) hiv = (hiv << 8) | hi_key[ofs_0+1]; } else { hiv = 256; if (ofs_0 < 19) hiv <<= 8; } lov = lo_key[ofs_0]; kyv = key[ofs_0]; if (ofs_0 < 19) { lov = (lov << 8) | lo_key[ofs_0+1]; kyv = (kyv << 8) | key[ofs_0+1]; } assert(lov < hiv); if (kyv < lov) return -1 - lo; if (hiv < kyv) return -1 - hi; /* * Even if we know the target is much closer to 'hi' * than 'lo', if we pick too precisely and overshoot * (e.g. when we know 'mi' is closer to 'hi' than to * 'lo', pick 'mi' that is higher than the target), we * end up narrowing the search space by a smaller * amount (i.e. the distance between 'mi' and 'hi') * than what we would have (i.e. about half of 'lo' * and 'hi'). Hedge our bets to pick 'mi' less * aggressively, i.e. make 'mi' a bit closer to the * middle than we would otherwise pick. */ kyv = (kyv * 6 + lov + hiv) / 8; if (lov < hiv - 1) { if (kyv == lov) kyv++; else if (kyv == hiv) kyv--; } mi = (range - 1) * (kyv - lov) / (hiv - lov) + lo; #ifdef INDEX_DEBUG_LOOKUP printf("lo %u hi %u rg %u mi %u ", lo, hi, range, mi); printf("ofs %u lov %x, hiv %x, kyv %x\n", ofs_0, lov, hiv, kyv); #endif if (!(lo <= mi && mi < hi)) { giterr_set(GITERR_INVALID, "Assertion failure. Binary search invariant is false"); return -1; } mi_key = base + elem_size * mi + key_offset; cmp = memcmp(mi_key + ofs_0, key + ofs_0, 20 - ofs_0); if (!cmp) return mi; if (cmp > 0) { hi = mi; hi_key = mi_key; } else { lo = mi + 1; lo_key = mi_key + elem_size; } } while (lo < hi); return -((int)lo)-1; } libgit2-0.19.0/src/sha1_lookup.h000066400000000000000000000007161216214232500163240ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #ifndef INCLUDE_sha1_lookup_h__ #define INCLUDE_sha1_lookup_h__ #include int sha1_entry_pos(const void *table, size_t elem_size, size_t key_offset, unsigned lo, unsigned hi, unsigned nr, const unsigned char *key); #endif libgit2-0.19.0/src/signature.c000066400000000000000000000123171216214232500160730ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #include "common.h" #include "signature.h" #include "repository.h" #include "git2/common.h" #include "posix.h" void git_signature_free(git_signature *sig) { if (sig == NULL) return; git__free(sig->name); sig->name = NULL; git__free(sig->email); sig->email = NULL; git__free(sig); } static int signature_error(const char *msg) { giterr_set(GITERR_INVALID, "Failed to parse signature - %s", msg); return -1; } static bool contains_angle_brackets(const char *input) { return strchr(input, '<') != NULL || strchr(input, '>') != NULL; } static char *extract_trimmed(const char *ptr, size_t len) { while (len && git__isspace(ptr[0])) { ptr++; len--; } while (len && git__isspace(ptr[len - 1])) { len--; } return git__substrdup(ptr, len); } int git_signature_new(git_signature **sig_out, const char *name, const char *email, git_time_t time, int offset) { git_signature *p = NULL; assert(name && email); *sig_out = NULL; if (contains_angle_brackets(name) || contains_angle_brackets(email)) { return signature_error( "Neither `name` nor `email` should contain angle brackets chars."); } p = git__calloc(1, sizeof(git_signature)); GITERR_CHECK_ALLOC(p); p->name = extract_trimmed(name, strlen(name)); p->email = extract_trimmed(email, strlen(email)); if (p->name == NULL || p->email == NULL) return -1; /* oom */ if (p->name[0] == '\0') { git_signature_free(p); return signature_error("Signature cannot have an empty name"); } p->when.time = time; p->when.offset = offset; *sig_out = p; return 0; } git_signature *git_signature_dup(const git_signature *sig) { git_signature *new = git__calloc(1, sizeof(git_signature)); if (new == NULL) return NULL; new->name = git__strdup(sig->name); new->email = git__strdup(sig->email); new->when.time = sig->when.time; new->when.offset = sig->when.offset; return new; } int git_signature_now(git_signature **sig_out, const char *name, const char *email) { time_t now; time_t offset; struct tm *utc_tm; git_signature *sig; struct tm _utc; *sig_out = NULL; /* * Get the current time as seconds since the epoch and * transform that into a tm struct containing the time at * UTC. Give that to mktime which considers it a local time * (tm_isdst = -1 asks it to take DST into account) and gives * us that time as seconds since the epoch. The difference * between its return value and 'now' is our offset to UTC. */ time(&now); utc_tm = p_gmtime_r(&now, &_utc); utc_tm->tm_isdst = -1; offset = (time_t)difftime(now, mktime(utc_tm)); offset /= 60; if (git_signature_new(&sig, name, email, now, (int)offset) < 0) return -1; *sig_out = sig; return 0; } int git_signature__parse(git_signature *sig, const char **buffer_out, const char *buffer_end, const char *header, char ender) { const char *buffer = *buffer_out; const char *email_start, *email_end; memset(sig, 0, sizeof(git_signature)); if ((buffer_end = memchr(buffer, ender, buffer_end - buffer)) == NULL) return signature_error("no newline given"); if (header) { const size_t header_len = strlen(header); if (buffer + header_len >= buffer_end || memcmp(buffer, header, header_len) != 0) return signature_error("expected prefix doesn't match actual"); buffer += header_len; } email_start = git__memrchr(buffer, '<', buffer_end - buffer); email_end = git__memrchr(buffer, '>', buffer_end - buffer); if (!email_start || !email_end || email_end <= email_start) return signature_error("malformed e-mail"); email_start += 1; sig->name = extract_trimmed(buffer, email_start - buffer - 1); sig->email = extract_trimmed(email_start, email_end - email_start); /* Do we even have a time at the end of the signature? */ if (email_end + 2 < buffer_end) { const char *time_start = email_end + 2; const char *time_end; if (git__strtol64(&sig->when.time, time_start, &time_end, 10) < 0) return signature_error("invalid Unix timestamp"); /* do we have a timezone? */ if (time_end + 1 < buffer_end) { int offset, hours, mins; const char *tz_start, *tz_end; tz_start = time_end + 1; if ((tz_start[0] != '-' && tz_start[0] != '+') || git__strtol32(&offset, tz_start + 1, &tz_end, 10) < 0) { //malformed timezone, just assume it's zero offset = 0; } hours = offset / 100; mins = offset % 100; /* * only store timezone if it's not overflowing; * see http://www.worldtimezone.com/faq.html */ if (hours < 14 && mins < 59) { sig->when.offset = (hours * 60) + mins; if (tz_start[0] == '-') sig->when.offset = -sig->when.offset; } } } *buffer_out = buffer_end + 1; return 0; } void git_signature__writebuf(git_buf *buf, const char *header, const git_signature *sig) { int offset, hours, mins; char sign; offset = sig->when.offset; sign = (sig->when.offset < 0) ? '-' : '+'; if (offset < 0) offset = -offset; hours = offset / 60; mins = offset % 60; git_buf_printf(buf, "%s%s <%s> %u %c%02d%02d\n", header ? header : "", sig->name, sig->email, (unsigned)sig->when.time, sign, hours, mins); } libgit2-0.19.0/src/signature.h000066400000000000000000000011251216214232500160730ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #ifndef INCLUDE_signature_h__ #define INCLUDE_signature_h__ #include "git2/common.h" #include "git2/signature.h" #include "repository.h" #include int git_signature__parse(git_signature *sig, const char **buffer_out, const char *buffer_end, const char *header, char ender); void git_signature__writebuf(git_buf *buf, const char *header, const git_signature *sig); #endif libgit2-0.19.0/src/stash.c000066400000000000000000000335141216214232500152160ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #include "common.h" #include "repository.h" #include "commit.h" #include "tree.h" #include "reflog.h" #include "git2/diff.h" #include "git2/stash.h" #include "git2/status.h" #include "git2/checkout.h" #include "git2/index.h" #include "signature.h" static int create_error(int error, const char *msg) { giterr_set(GITERR_STASH, "Cannot stash changes - %s", msg); return error; } static int retrieve_head(git_reference **out, git_repository *repo) { int error = git_repository_head(out, repo); if (error == GIT_EORPHANEDHEAD) return create_error(error, "You do not have the initial commit yet."); return error; } static int append_abbreviated_oid(git_buf *out, const git_oid *b_commit) { char *formatted_oid; formatted_oid = git_oid_allocfmt(b_commit); GITERR_CHECK_ALLOC(formatted_oid); git_buf_put(out, formatted_oid, 7); git__free(formatted_oid); return git_buf_oom(out) ? -1 : 0; } static int append_commit_description(git_buf *out, git_commit* commit) { const char *message; size_t pos = 0, len; if (append_abbreviated_oid(out, git_commit_id(commit)) < 0) return -1; message = git_commit_message(commit); len = strlen(message); /* TODO: Replace with proper commit short message * when git_commit_message_short() is implemented. */ while (pos < len && message[pos] != '\n') pos++; git_buf_putc(out, ' '); git_buf_put(out, message, pos); git_buf_putc(out, '\n'); return git_buf_oom(out) ? -1 : 0; } static int retrieve_base_commit_and_message( git_commit **b_commit, git_buf *stash_message, git_repository *repo) { git_reference *head = NULL; int error; if ((error = retrieve_head(&head, repo)) < 0) return error; if (strcmp("HEAD", git_reference_name(head)) == 0) error = git_buf_puts(stash_message, "(no branch): "); else error = git_buf_printf( stash_message, "%s: ", git_reference_name(head) + strlen(GIT_REFS_HEADS_DIR)); if (error < 0) goto cleanup; if ((error = git_commit_lookup( b_commit, repo, git_reference_target(head))) < 0) goto cleanup; if ((error = append_commit_description(stash_message, *b_commit)) < 0) goto cleanup; cleanup: git_reference_free(head); return error; } static int build_tree_from_index(git_tree **out, git_index *index) { int error; git_oid i_tree_oid; if ((error = git_index_write_tree(&i_tree_oid, index)) < 0) return -1; return git_tree_lookup(out, git_index_owner(index), &i_tree_oid); } static int commit_index( git_commit **i_commit, git_index *index, git_signature *stasher, const char *message, const git_commit *parent) { git_tree *i_tree = NULL; git_oid i_commit_oid; git_buf msg = GIT_BUF_INIT; int error; if ((error = build_tree_from_index(&i_tree, index)) < 0) goto cleanup; if ((error = git_buf_printf(&msg, "index on %s\n", message)) < 0) goto cleanup; if ((error = git_commit_create( &i_commit_oid, git_index_owner(index), NULL, stasher, stasher, NULL, git_buf_cstr(&msg), i_tree, 1, &parent)) < 0) goto cleanup; error = git_commit_lookup(i_commit, git_index_owner(index), &i_commit_oid); cleanup: git_tree_free(i_tree); git_buf_free(&msg); return error; } struct cb_data { git_index *index; int error; bool include_changed; bool include_untracked; bool include_ignored; }; static int update_index_cb( const git_diff_delta *delta, float progress, void *payload) { struct cb_data *data = (struct cb_data *)payload; const char *add_path = NULL; GIT_UNUSED(progress); switch (delta->status) { case GIT_DELTA_IGNORED: if (data->include_ignored) add_path = delta->new_file.path; break; case GIT_DELTA_UNTRACKED: if (data->include_untracked) add_path = delta->new_file.path; break; case GIT_DELTA_ADDED: case GIT_DELTA_MODIFIED: if (data->include_changed) add_path = delta->new_file.path; break; case GIT_DELTA_DELETED: if (!data->include_changed) break; if (git_index_find(NULL, data->index, delta->old_file.path) == 0) data->error = git_index_remove( data->index, delta->old_file.path, 0); break; default: /* Unimplemented */ giterr_set( GITERR_INVALID, "Cannot update index. Unimplemented status (%d)", delta->status); data->error = -1; break; } if (add_path != NULL) data->error = git_index_add_bypath(data->index, add_path); return data->error; } static int build_untracked_tree( git_tree **tree_out, git_index *index, git_commit *i_commit, uint32_t flags) { git_tree *i_tree = NULL; git_diff_list *diff = NULL; git_diff_options opts = GIT_DIFF_OPTIONS_INIT; struct cb_data data = {0}; int error; git_index_clear(index); data.index = index; if (flags & GIT_STASH_INCLUDE_UNTRACKED) { opts.flags |= GIT_DIFF_INCLUDE_UNTRACKED | GIT_DIFF_RECURSE_UNTRACKED_DIRS; data.include_untracked = true; } if (flags & GIT_STASH_INCLUDE_IGNORED) { opts.flags |= GIT_DIFF_INCLUDE_IGNORED; data.include_ignored = true; } if ((error = git_commit_tree(&i_tree, i_commit)) < 0) goto cleanup; if ((error = git_diff_tree_to_workdir( &diff, git_index_owner(index), i_tree, &opts)) < 0) goto cleanup; if ((error = git_diff_foreach( diff, update_index_cb, NULL, NULL, &data)) < 0) { if (error == GIT_EUSER) error = data.error; goto cleanup; } error = build_tree_from_index(tree_out, index); cleanup: git_diff_list_free(diff); git_tree_free(i_tree); return error; } static int commit_untracked( git_commit **u_commit, git_index *index, git_signature *stasher, const char *message, git_commit *i_commit, uint32_t flags) { git_tree *u_tree = NULL; git_oid u_commit_oid; git_buf msg = GIT_BUF_INIT; int error; if ((error = build_untracked_tree(&u_tree, index, i_commit, flags)) < 0) goto cleanup; if ((error = git_buf_printf(&msg, "untracked files on %s\n", message)) < 0) goto cleanup; if ((error = git_commit_create( &u_commit_oid, git_index_owner(index), NULL, stasher, stasher, NULL, git_buf_cstr(&msg), u_tree, 0, NULL)) < 0) goto cleanup; error = git_commit_lookup(u_commit, git_index_owner(index), &u_commit_oid); cleanup: git_tree_free(u_tree); git_buf_free(&msg); return error; } static int build_workdir_tree( git_tree **tree_out, git_index *index, git_commit *b_commit) { git_repository *repo = git_index_owner(index); git_tree *b_tree = NULL; git_diff_list *diff = NULL, *diff2 = NULL; git_diff_options opts = GIT_DIFF_OPTIONS_INIT; struct cb_data data = {0}; int error; if ((error = git_commit_tree(&b_tree, b_commit)) < 0) goto cleanup; if ((error = git_diff_tree_to_index(&diff, repo, b_tree, NULL, &opts)) < 0) goto cleanup; if ((error = git_diff_index_to_workdir(&diff2, repo, NULL, &opts)) < 0) goto cleanup; if ((error = git_diff_merge(diff, diff2)) < 0) goto cleanup; data.index = index; data.include_changed = true; if ((error = git_diff_foreach( diff, update_index_cb, NULL, NULL, &data)) < 0) { if (error == GIT_EUSER) error = data.error; goto cleanup; } if ((error = build_tree_from_index(tree_out, index)) < 0) goto cleanup; cleanup: git_diff_list_free(diff); git_diff_list_free(diff2); git_tree_free(b_tree); return error; } static int commit_worktree( git_oid *w_commit_oid, git_index *index, git_signature *stasher, const char *message, git_commit *i_commit, git_commit *b_commit, git_commit *u_commit) { int error = 0; git_tree *w_tree = NULL, *i_tree = NULL; const git_commit *parents[] = { NULL, NULL, NULL }; parents[0] = b_commit; parents[1] = i_commit; parents[2] = u_commit; if ((error = git_commit_tree(&i_tree, i_commit)) < 0) goto cleanup; if ((error = git_index_read_tree(index, i_tree)) < 0) goto cleanup; if ((error = build_workdir_tree(&w_tree, index, b_commit)) < 0) goto cleanup; error = git_commit_create( w_commit_oid, git_index_owner(index), NULL, stasher, stasher, NULL, message, w_tree, u_commit ? 3 : 2, parents); cleanup: git_tree_free(i_tree); git_tree_free(w_tree); return error; } static int prepare_worktree_commit_message( git_buf* msg, const char *user_message) { git_buf buf = GIT_BUF_INIT; int error; if ((error = git_buf_set(&buf, git_buf_cstr(msg), git_buf_len(msg))) < 0) return error; git_buf_clear(msg); if (!user_message) git_buf_printf(msg, "WIP on %s", git_buf_cstr(&buf)); else { const char *colon; if ((colon = strchr(git_buf_cstr(&buf), ':')) == NULL) goto cleanup; git_buf_puts(msg, "On "); git_buf_put(msg, git_buf_cstr(&buf), colon - buf.ptr); git_buf_printf(msg, ": %s\n", user_message); } error = (git_buf_oom(msg) || git_buf_oom(&buf)) ? -1 : 0; cleanup: git_buf_free(&buf); return error; } static int update_reflog( git_oid *w_commit_oid, git_repository *repo, git_signature *stasher, const char *message) { git_reference *stash = NULL; git_reflog *reflog = NULL; int error; if ((error = git_reference_create(&stash, repo, GIT_REFS_STASH_FILE, w_commit_oid, 1)) < 0) goto cleanup; if ((error = git_reflog_read(&reflog, stash)) < 0) goto cleanup; if ((error = git_reflog_append(reflog, w_commit_oid, stasher, message)) < 0) goto cleanup; if ((error = git_reflog_write(reflog)) < 0) goto cleanup; cleanup: git_reference_free(stash); git_reflog_free(reflog); return error; } static int is_dirty_cb(const char *path, unsigned int status, void *payload) { GIT_UNUSED(path); GIT_UNUSED(status); GIT_UNUSED(payload); return 1; } static int ensure_there_are_changes_to_stash( git_repository *repo, bool include_untracked_files, bool include_ignored_files) { int error; git_status_options opts = GIT_STATUS_OPTIONS_INIT; opts.show = GIT_STATUS_SHOW_INDEX_AND_WORKDIR; if (include_untracked_files) opts.flags = GIT_STATUS_OPT_INCLUDE_UNTRACKED | GIT_STATUS_OPT_RECURSE_UNTRACKED_DIRS; if (include_ignored_files) opts.flags = GIT_STATUS_OPT_INCLUDE_IGNORED; error = git_status_foreach_ext(repo, &opts, is_dirty_cb, NULL); if (error == GIT_EUSER) return 0; if (!error) return create_error(GIT_ENOTFOUND, "There is nothing to stash."); return error; } static int reset_index_and_workdir( git_repository *repo, git_commit *commit, bool remove_untracked) { git_checkout_opts opts = GIT_CHECKOUT_OPTS_INIT; opts.checkout_strategy = GIT_CHECKOUT_FORCE; if (remove_untracked) opts.checkout_strategy |= GIT_CHECKOUT_REMOVE_UNTRACKED; return git_checkout_tree(repo, (git_object *)commit, &opts); } int git_stash_save( git_oid *out, git_repository *repo, git_signature *stasher, const char *message, uint32_t flags) { git_index *index = NULL; git_commit *b_commit = NULL, *i_commit = NULL, *u_commit = NULL; git_buf msg = GIT_BUF_INIT; int error; assert(out && repo && stasher); if ((error = git_repository__ensure_not_bare(repo, "stash save")) < 0) return error; if ((error = retrieve_base_commit_and_message(&b_commit, &msg, repo)) < 0) goto cleanup; if ((error = ensure_there_are_changes_to_stash( repo, (flags & GIT_STASH_INCLUDE_UNTRACKED) != 0, (flags & GIT_STASH_INCLUDE_IGNORED) != 0)) < 0) goto cleanup; if ((error = git_repository_index(&index, repo)) < 0) goto cleanup; if ((error = commit_index( &i_commit, index, stasher, git_buf_cstr(&msg), b_commit)) < 0) goto cleanup; if ((flags & (GIT_STASH_INCLUDE_UNTRACKED | GIT_STASH_INCLUDE_IGNORED)) && (error = commit_untracked( &u_commit, index, stasher, git_buf_cstr(&msg), i_commit, flags)) < 0) goto cleanup; if ((error = prepare_worktree_commit_message(&msg, message)) < 0) goto cleanup; if ((error = commit_worktree( out, index, stasher, git_buf_cstr(&msg), i_commit, b_commit, u_commit)) < 0) goto cleanup; git_buf_rtrim(&msg); if ((error = update_reflog(out, repo, stasher, git_buf_cstr(&msg))) < 0) goto cleanup; if ((error = reset_index_and_workdir( repo, ((flags & GIT_STASH_KEEP_INDEX) != 0) ? i_commit : b_commit, (flags & GIT_STASH_INCLUDE_UNTRACKED) != 0)) < 0) goto cleanup; cleanup: git_buf_free(&msg); git_commit_free(i_commit); git_commit_free(b_commit); git_commit_free(u_commit); git_index_free(index); return error; } int git_stash_foreach( git_repository *repo, git_stash_cb callback, void *payload) { git_reference *stash; git_reflog *reflog = NULL; int error; size_t i, max; const git_reflog_entry *entry; error = git_reference_lookup(&stash, repo, GIT_REFS_STASH_FILE); if (error == GIT_ENOTFOUND) { giterr_clear(); return 0; } if (error < 0) goto cleanup; if ((error = git_reflog_read(&reflog, stash)) < 0) goto cleanup; max = git_reflog_entrycount(reflog); for (i = 0; i < max; i++) { entry = git_reflog_entry_byindex(reflog, i); if (callback(i, git_reflog_entry_message(entry), git_reflog_entry_id_new(entry), payload)) { error = GIT_EUSER; break; } } cleanup: git_reference_free(stash); git_reflog_free(reflog); return error; } int git_stash_drop( git_repository *repo, size_t index) { git_reference *stash; git_reflog *reflog = NULL; size_t max; int error; if ((error = git_reference_lookup(&stash, repo, GIT_REFS_STASH_FILE)) < 0) return error; if ((error = git_reflog_read(&reflog, stash)) < 0) goto cleanup; max = git_reflog_entrycount(reflog); if (index > max - 1) { error = GIT_ENOTFOUND; giterr_set(GITERR_STASH, "No stashed state at position %" PRIuZ, index); goto cleanup; } if ((error = git_reflog_drop(reflog, index, true)) < 0) goto cleanup; if ((error = git_reflog_write(reflog)) < 0) goto cleanup; if (max == 1) { error = git_reference_delete(stash); git_reference_free(stash); stash = NULL; } else if (index == 0) { const git_reflog_entry *entry; entry = git_reflog_entry_byindex(reflog, 0); git_reference_free(stash); error = git_reference_create(&stash, repo, GIT_REFS_STASH_FILE, &entry->oid_cur, 1); } cleanup: git_reference_free(stash); git_reflog_free(reflog); return error; } libgit2-0.19.0/src/status.c000066400000000000000000000315421216214232500154160ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #include "common.h" #include "git2.h" #include "fileops.h" #include "hash.h" #include "vector.h" #include "tree.h" #include "status.h" #include "git2/status.h" #include "repository.h" #include "ignore.h" #include "index.h" #include "git2/diff.h" #include "diff.h" static unsigned int index_delta2status(const git_diff_delta *head2idx) { git_status_t st = GIT_STATUS_CURRENT; switch (head2idx->status) { case GIT_DELTA_ADDED: case GIT_DELTA_COPIED: st = GIT_STATUS_INDEX_NEW; break; case GIT_DELTA_DELETED: st = GIT_STATUS_INDEX_DELETED; break; case GIT_DELTA_MODIFIED: st = GIT_STATUS_INDEX_MODIFIED; break; case GIT_DELTA_RENAMED: st = GIT_STATUS_INDEX_RENAMED; if (!git_oid_equal(&head2idx->old_file.oid, &head2idx->new_file.oid)) st |= GIT_STATUS_INDEX_MODIFIED; break; case GIT_DELTA_TYPECHANGE: st = GIT_STATUS_INDEX_TYPECHANGE; break; default: break; } return st; } static unsigned int workdir_delta2status( git_diff_list *diff, git_diff_delta *idx2wd) { git_status_t st = GIT_STATUS_CURRENT; switch (idx2wd->status) { case GIT_DELTA_ADDED: case GIT_DELTA_COPIED: case GIT_DELTA_UNTRACKED: st = GIT_STATUS_WT_NEW; break; case GIT_DELTA_DELETED: st = GIT_STATUS_WT_DELETED; break; case GIT_DELTA_MODIFIED: st = GIT_STATUS_WT_MODIFIED; break; case GIT_DELTA_IGNORED: st = GIT_STATUS_IGNORED; break; case GIT_DELTA_RENAMED: st = GIT_STATUS_WT_RENAMED; if (!git_oid_equal(&idx2wd->old_file.oid, &idx2wd->new_file.oid)) { /* if OIDs don't match, we might need to calculate them now to * discern between RENAMED vs RENAMED+MODIFED */ if (git_oid_iszero(&idx2wd->old_file.oid) && diff->old_src == GIT_ITERATOR_TYPE_WORKDIR && !git_diff__oid_for_file( diff->repo, idx2wd->old_file.path, idx2wd->old_file.mode, idx2wd->old_file.size, &idx2wd->old_file.oid)) idx2wd->old_file.flags |= GIT_DIFF_FLAG_VALID_OID; if (git_oid_iszero(&idx2wd->new_file.oid) && diff->new_src == GIT_ITERATOR_TYPE_WORKDIR && !git_diff__oid_for_file( diff->repo, idx2wd->new_file.path, idx2wd->new_file.mode, idx2wd->new_file.size, &idx2wd->new_file.oid)) idx2wd->new_file.flags |= GIT_DIFF_FLAG_VALID_OID; if (!git_oid_equal(&idx2wd->old_file.oid, &idx2wd->new_file.oid)) st |= GIT_STATUS_WT_MODIFIED; } break; case GIT_DELTA_TYPECHANGE: st = GIT_STATUS_WT_TYPECHANGE; break; default: break; } return st; } static bool status_is_included( git_status_list *status, git_diff_delta *head2idx, git_diff_delta *idx2wd) { if (!(status->opts.flags & GIT_STATUS_OPT_EXCLUDE_SUBMODULES)) return 1; /* if excluding submodules and this is a submodule everywhere */ if (head2idx) { if (head2idx->status != GIT_DELTA_ADDED && head2idx->old_file.mode != GIT_FILEMODE_COMMIT) return 1; if (head2idx->status != GIT_DELTA_DELETED && head2idx->new_file.mode != GIT_FILEMODE_COMMIT) return 1; } if (idx2wd) { if (idx2wd->status != GIT_DELTA_ADDED && idx2wd->old_file.mode != GIT_FILEMODE_COMMIT) return 1; if (idx2wd->status != GIT_DELTA_DELETED && idx2wd->new_file.mode != GIT_FILEMODE_COMMIT) return 1; } /* only get here if every valid mode is GIT_FILEMODE_COMMIT */ return 0; } static git_status_t status_compute( git_status_list *status, git_diff_delta *head2idx, git_diff_delta *idx2wd) { git_status_t st = GIT_STATUS_CURRENT; if (head2idx) st |= index_delta2status(head2idx); if (idx2wd) st |= workdir_delta2status(status->idx2wd, idx2wd); return st; } static int status_collect( git_diff_delta *head2idx, git_diff_delta *idx2wd, void *payload) { git_status_list *status = payload; git_status_entry *status_entry; if (!status_is_included(status, head2idx, idx2wd)) return 0; status_entry = git__malloc(sizeof(git_status_entry)); GITERR_CHECK_ALLOC(status_entry); status_entry->status = status_compute(status, head2idx, idx2wd); status_entry->head_to_index = head2idx; status_entry->index_to_workdir = idx2wd; return git_vector_insert(&status->paired, status_entry); } GIT_INLINE(int) status_entry_cmp_base( const void *a, const void *b, int (*strcomp)(const char *a, const char *b)) { const git_status_entry *entry_a = a; const git_status_entry *entry_b = b; const git_diff_delta *delta_a, *delta_b; delta_a = entry_a->index_to_workdir ? entry_a->index_to_workdir : entry_a->head_to_index; delta_b = entry_b->index_to_workdir ? entry_b->index_to_workdir : entry_b->head_to_index; if (!delta_a && delta_b) return -1; if (delta_a && !delta_b) return 1; if (!delta_a && !delta_b) return 0; return strcomp(delta_a->new_file.path, delta_b->new_file.path); } static int status_entry_icmp(const void *a, const void *b) { return status_entry_cmp_base(a, b, git__strcasecmp); } static int status_entry_cmp(const void *a, const void *b) { return status_entry_cmp_base(a, b, git__strcmp); } static git_status_list *git_status_list_alloc(git_index *index) { git_status_list *status = NULL; int (*entrycmp)(const void *a, const void *b); if (!(status = git__calloc(1, sizeof(git_status_list)))) return NULL; entrycmp = index->ignore_case ? status_entry_icmp : status_entry_cmp; if (git_vector_init(&status->paired, 0, entrycmp) < 0) { git__free(status); return NULL; } return status; } /* static int newfile_cmp(const void *a, const void *b) { const git_diff_delta *delta_a = a; const git_diff_delta *delta_b = b; return git__strcmp(delta_a->new_file.path, delta_b->new_file.path); } static int newfile_casecmp(const void *a, const void *b) { const git_diff_delta *delta_a = a; const git_diff_delta *delta_b = b; return git__strcasecmp(delta_a->new_file.path, delta_b->new_file.path); } */ int git_status_list_new( git_status_list **out, git_repository *repo, const git_status_options *opts) { git_index *index = NULL; git_status_list *status = NULL; git_diff_options diffopt = GIT_DIFF_OPTIONS_INIT; git_diff_find_options findopts_i2w = GIT_DIFF_FIND_OPTIONS_INIT; git_tree *head = NULL; git_status_show_t show = opts ? opts->show : GIT_STATUS_SHOW_INDEX_AND_WORKDIR; int error = 0; unsigned int flags = opts ? opts->flags : GIT_STATUS_OPT_DEFAULTS; assert(show <= GIT_STATUS_SHOW_INDEX_THEN_WORKDIR); *out = NULL; GITERR_CHECK_VERSION(opts, GIT_STATUS_OPTIONS_VERSION, "git_status_options"); if ((error = git_repository__ensure_not_bare(repo, "status")) < 0 || (error = git_repository_index(&index, repo)) < 0) return error; /* if there is no HEAD, that's okay - we'll make an empty iterator */ if (((error = git_repository_head_tree(&head, repo)) < 0) && error != GIT_ENOTFOUND && error != GIT_EORPHANEDHEAD) { git_index_free(index); /* release index */ return error; } status = git_status_list_alloc(index); GITERR_CHECK_ALLOC(status); if (opts) { memcpy(&status->opts, opts, sizeof(git_status_options)); memcpy(&diffopt.pathspec, &opts->pathspec, sizeof(diffopt.pathspec)); } diffopt.flags = GIT_DIFF_INCLUDE_TYPECHANGE; if ((flags & GIT_STATUS_OPT_INCLUDE_UNTRACKED) != 0) diffopt.flags = diffopt.flags | GIT_DIFF_INCLUDE_UNTRACKED; if ((flags & GIT_STATUS_OPT_INCLUDE_IGNORED) != 0) diffopt.flags = diffopt.flags | GIT_DIFF_INCLUDE_IGNORED; if ((flags & GIT_STATUS_OPT_INCLUDE_UNMODIFIED) != 0) diffopt.flags = diffopt.flags | GIT_DIFF_INCLUDE_UNMODIFIED; if ((flags & GIT_STATUS_OPT_RECURSE_UNTRACKED_DIRS) != 0) diffopt.flags = diffopt.flags | GIT_DIFF_RECURSE_UNTRACKED_DIRS; if ((flags & GIT_STATUS_OPT_DISABLE_PATHSPEC_MATCH) != 0) diffopt.flags = diffopt.flags | GIT_DIFF_DISABLE_PATHSPEC_MATCH; if ((flags & GIT_STATUS_OPT_RECURSE_IGNORED_DIRS) != 0) diffopt.flags = diffopt.flags | GIT_DIFF_RECURSE_IGNORED_DIRS; if ((flags & GIT_STATUS_OPT_EXCLUDE_SUBMODULES) != 0) diffopt.flags = diffopt.flags | GIT_DIFF_IGNORE_SUBMODULES; findopts_i2w.flags |= GIT_DIFF_FIND_FOR_UNTRACKED; if (show != GIT_STATUS_SHOW_WORKDIR_ONLY) { if ((error = git_diff_tree_to_index( &status->head2idx, repo, head, NULL, &diffopt)) < 0) goto done; if ((flags & GIT_STATUS_OPT_RENAMES_HEAD_TO_INDEX) != 0 && (error = git_diff_find_similar(status->head2idx, NULL)) < 0) goto done; } if (show != GIT_STATUS_SHOW_INDEX_ONLY) { if ((error = git_diff_index_to_workdir( &status->idx2wd, repo, NULL, &diffopt)) < 0) goto done; if ((flags & GIT_STATUS_OPT_RENAMES_INDEX_TO_WORKDIR) != 0 && (error = git_diff_find_similar(status->idx2wd, &findopts_i2w)) < 0) goto done; } if (show == GIT_STATUS_SHOW_INDEX_THEN_WORKDIR) { if ((error = git_diff__paired_foreach( status->head2idx, NULL, status_collect, status)) < 0) goto done; git_diff_list_free(status->head2idx); status->head2idx = NULL; } if ((error = git_diff__paired_foreach( status->head2idx, status->idx2wd, status_collect, status)) < 0) goto done; if (flags & GIT_STATUS_OPT_SORT_CASE_SENSITIVELY) git_vector_set_cmp(&status->paired, status_entry_cmp); if (flags & GIT_STATUS_OPT_SORT_CASE_INSENSITIVELY) git_vector_set_cmp(&status->paired, status_entry_icmp); if ((flags & (GIT_STATUS_OPT_RENAMES_HEAD_TO_INDEX | GIT_STATUS_OPT_RENAMES_INDEX_TO_WORKDIR | GIT_STATUS_OPT_SORT_CASE_SENSITIVELY | GIT_STATUS_OPT_SORT_CASE_INSENSITIVELY)) != 0) git_vector_sort(&status->paired); done: if (error < 0) { git_status_list_free(status); status = NULL; } *out = status; git_tree_free(head); git_index_free(index); return error; } size_t git_status_list_entrycount(git_status_list *status) { assert(status); return status->paired.length; } const git_status_entry *git_status_byindex(git_status_list *status, size_t i) { assert(status); return git_vector_get(&status->paired, i); } void git_status_list_free(git_status_list *status) { git_status_entry *status_entry; size_t i; if (status == NULL) return; git_diff_list_free(status->head2idx); git_diff_list_free(status->idx2wd); git_vector_foreach(&status->paired, i, status_entry) git__free(status_entry); git_vector_free(&status->paired); git__memzero(status, sizeof(*status)); git__free(status); } int git_status_foreach_ext( git_repository *repo, const git_status_options *opts, git_status_cb cb, void *payload) { git_status_list *status; const git_status_entry *status_entry; size_t i; int error = 0; if ((error = git_status_list_new(&status, repo, opts)) < 0) return error; git_vector_foreach(&status->paired, i, status_entry) { const char *path = status_entry->head_to_index ? status_entry->head_to_index->old_file.path : status_entry->index_to_workdir->old_file.path; if (cb(path, status_entry->status, payload) != 0) { error = GIT_EUSER; giterr_clear(); break; } } git_status_list_free(status); return error; } int git_status_foreach(git_repository *repo, git_status_cb cb, void *payload) { return git_status_foreach_ext(repo, NULL, cb, payload); } struct status_file_info { char *expected; unsigned int count; unsigned int status; int fnm_flags; int ambiguous; }; static int get_one_status(const char *path, unsigned int status, void *data) { struct status_file_info *sfi = data; int (*strcomp)(const char *a, const char *b); sfi->count++; sfi->status = status; strcomp = (sfi->fnm_flags & FNM_CASEFOLD) ? git__strcasecmp : git__strcmp; if (sfi->count > 1 || (strcomp(sfi->expected, path) != 0 && p_fnmatch(sfi->expected, path, sfi->fnm_flags) != 0)) { sfi->ambiguous = true; return GIT_EAMBIGUOUS; /* giterr_set will be done by caller */ } return 0; } int git_status_file( unsigned int *status_flags, git_repository *repo, const char *path) { int error; git_status_options opts = GIT_STATUS_OPTIONS_INIT; struct status_file_info sfi = {0}; git_index *index; assert(status_flags && repo && path); if ((error = git_repository_index__weakptr(&index, repo)) < 0) return error; if ((sfi.expected = git__strdup(path)) == NULL) return -1; if (index->ignore_case) sfi.fnm_flags = FNM_CASEFOLD; opts.show = GIT_STATUS_SHOW_INDEX_AND_WORKDIR; opts.flags = GIT_STATUS_OPT_INCLUDE_IGNORED | GIT_STATUS_OPT_RECURSE_IGNORED_DIRS | GIT_STATUS_OPT_INCLUDE_UNTRACKED | GIT_STATUS_OPT_RECURSE_UNTRACKED_DIRS | GIT_STATUS_OPT_INCLUDE_UNMODIFIED; opts.pathspec.count = 1; opts.pathspec.strings = &sfi.expected; error = git_status_foreach_ext(repo, &opts, get_one_status, &sfi); if (error < 0 && sfi.ambiguous) { giterr_set(GITERR_INVALID, "Ambiguous path '%s' given to git_status_file", sfi.expected); error = GIT_EAMBIGUOUS; } if (!error && !sfi.count) { giterr_set(GITERR_INVALID, "Attempt to get status of nonexistent file '%s'", path); error = GIT_ENOTFOUND; } *status_flags = sfi.status; git__free(sfi.expected); return error; } int git_status_should_ignore( int *ignored, git_repository *repo, const char *path) { return git_ignore_path_is_ignored(ignored, repo, path); } libgit2-0.19.0/src/status.h000066400000000000000000000007271216214232500154240ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #ifndef INCLUDE_status_h__ #define INCLUDE_status_h__ #include "diff.h" #include "git2/status.h" #include "git2/diff.h" struct git_status_list { git_status_options opts; git_diff_list *head2idx; git_diff_list *idx2wd; git_vector paired; }; #endif libgit2-0.19.0/src/strmap.h000066400000000000000000000036271216214232500154110ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #ifndef INCLUDE_strmap_h__ #define INCLUDE_strmap_h__ #include "common.h" #define kmalloc git__malloc #define kcalloc git__calloc #define krealloc git__realloc #define kfree git__free #include "khash.h" __KHASH_TYPE(str, const char *, void *); typedef khash_t(str) git_strmap; #define GIT__USE_STRMAP \ __KHASH_IMPL(str, static kh_inline, const char *, void *, 1, kh_str_hash_func, kh_str_hash_equal) #define git_strmap_alloc() kh_init(str) #define git_strmap_free(h) kh_destroy(str, h), h = NULL #define git_strmap_clear(h) kh_clear(str, h) #define git_strmap_num_entries(h) kh_size(h) #define git_strmap_lookup_index(h, k) kh_get(str, h, k) #define git_strmap_valid_index(h, idx) (idx != kh_end(h)) #define git_strmap_exists(h, k) (kh_get(str, h, k) != kh_end(h)) #define git_strmap_value_at(h, idx) kh_val(h, idx) #define git_strmap_set_value_at(h, idx, v) kh_val(h, idx) = v #define git_strmap_delete_at(h, idx) kh_del(str, h, idx) #define git_strmap_insert(h, key, val, rval) do { \ khiter_t __pos = kh_put(str, h, key, &rval); \ if (rval >= 0) { \ if (rval == 0) kh_key(h, __pos) = key; \ kh_val(h, __pos) = val; \ } } while (0) #define git_strmap_insert2(h, key, val, oldv, rval) do { \ khiter_t __pos = kh_put(str, h, key, &rval); \ if (rval >= 0) { \ if (rval == 0) { \ oldv = kh_val(h, __pos); \ kh_key(h, __pos) = key; \ } else { oldv = NULL; } \ kh_val(h, __pos) = val; \ } } while (0) #define git_strmap_delete(h, key) do { \ khiter_t __pos = git_strmap_lookup_index(h, key); \ if (git_strmap_valid_index(h, __pos)) \ git_strmap_delete_at(h, __pos); } while (0) #define git_strmap_foreach kh_foreach #define git_strmap_foreach_value kh_foreach_value #endif libgit2-0.19.0/src/submodule.c000066400000000000000000001076171216214232500161010ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #include "common.h" #include "git2/config.h" #include "git2/sys/config.h" #include "git2/types.h" #include "git2/repository.h" #include "git2/index.h" #include "git2/submodule.h" #include "buffer.h" #include "buf_text.h" #include "vector.h" #include "posix.h" #include "config_file.h" #include "config.h" #include "repository.h" #include "submodule.h" #include "tree.h" #include "iterator.h" #include "path.h" #include "index.h" #define GIT_MODULES_FILE ".gitmodules" static git_cvar_map _sm_update_map[] = { {GIT_CVAR_STRING, "checkout", GIT_SUBMODULE_UPDATE_CHECKOUT}, {GIT_CVAR_STRING, "rebase", GIT_SUBMODULE_UPDATE_REBASE}, {GIT_CVAR_STRING, "merge", GIT_SUBMODULE_UPDATE_MERGE}, {GIT_CVAR_STRING, "none", GIT_SUBMODULE_UPDATE_NONE}, }; static git_cvar_map _sm_ignore_map[] = { {GIT_CVAR_STRING, "none", GIT_SUBMODULE_IGNORE_NONE}, {GIT_CVAR_STRING, "untracked", GIT_SUBMODULE_IGNORE_UNTRACKED}, {GIT_CVAR_STRING, "dirty", GIT_SUBMODULE_IGNORE_DIRTY}, {GIT_CVAR_STRING, "all", GIT_SUBMODULE_IGNORE_ALL}, }; static kh_inline khint_t str_hash_no_trailing_slash(const char *s) { khint_t h; for (h = 0; *s; ++s) if (s[1] != '\0' || *s != '/') h = (h << 5) - h + *s; return h; } static kh_inline int str_equal_no_trailing_slash(const char *a, const char *b) { size_t alen = a ? strlen(a) : 0; size_t blen = b ? strlen(b) : 0; if (alen > 0 && a[alen - 1] == '/') alen--; if (blen > 0 && b[blen - 1] == '/') blen--; return (alen == blen && strncmp(a, b, alen) == 0); } __KHASH_IMPL( str, static kh_inline, const char *, void *, 1, str_hash_no_trailing_slash, str_equal_no_trailing_slash); static int load_submodule_config(git_repository *repo); static git_config_backend *open_gitmodules(git_repository *, bool, const git_oid *); static int lookup_head_remote(git_buf *url, git_repository *repo); static int submodule_get(git_submodule **, git_repository *, const char *, const char *); static void submodule_release(git_submodule *sm, int decr); static int submodule_load_from_index(git_repository *, const git_index_entry *); static int submodule_load_from_head(git_repository*, const char*, const git_oid*); static int submodule_load_from_config(const git_config_entry *, void *); static int submodule_load_from_wd_lite(git_submodule *, const char *, void *); static int submodule_update_config(git_submodule *, const char *, const char *, bool, bool); static void submodule_mode_mismatch(git_repository *, const char *, unsigned int); static int submodule_index_status(unsigned int *status, git_submodule *sm); static int submodule_wd_status(unsigned int *status, git_submodule *sm); static int submodule_cmp(const void *a, const void *b) { return strcmp(((git_submodule *)a)->name, ((git_submodule *)b)->name); } static int submodule_config_key_trunc_puts(git_buf *key, const char *suffix) { ssize_t idx = git_buf_rfind(key, '.'); git_buf_truncate(key, (size_t)(idx + 1)); return git_buf_puts(key, suffix); } /* * PUBLIC APIS */ int git_submodule_lookup( git_submodule **sm_ptr, /* NULL if user only wants to test existence */ git_repository *repo, const char *name) /* trailing slash is allowed */ { int error; khiter_t pos; assert(repo && name); if ((error = load_submodule_config(repo)) < 0) return error; pos = git_strmap_lookup_index(repo->submodules, name); if (!git_strmap_valid_index(repo->submodules, pos)) { error = GIT_ENOTFOUND; /* check if a plausible submodule exists at path */ if (git_repository_workdir(repo)) { git_buf path = GIT_BUF_INIT; if (git_buf_joinpath(&path, git_repository_workdir(repo), name) < 0) return -1; if (git_path_contains_dir(&path, DOT_GIT)) error = GIT_EEXISTS; git_buf_free(&path); } giterr_set(GITERR_SUBMODULE, (error == GIT_ENOTFOUND) ? "No submodule named '%s'" : "Submodule '%s' has not been added yet", name); return error; } if (sm_ptr) *sm_ptr = git_strmap_value_at(repo->submodules, pos); return 0; } int git_submodule_foreach( git_repository *repo, int (*callback)(git_submodule *sm, const char *name, void *payload), void *payload) { int error; git_submodule *sm; git_vector seen = GIT_VECTOR_INIT; git_vector_set_cmp(&seen, submodule_cmp); assert(repo && callback); if ((error = load_submodule_config(repo)) < 0) return error; git_strmap_foreach_value(repo->submodules, sm, { /* Usually the following will not come into play - it just prevents * us from issuing a callback twice for a submodule where the name * and path are not the same. */ if (sm->refcount > 1) { if (git_vector_bsearch(NULL, &seen, sm) != GIT_ENOTFOUND) continue; if ((error = git_vector_insert(&seen, sm)) < 0) break; } if (callback(sm, sm->name, payload)) { giterr_clear(); error = GIT_EUSER; break; } }); git_vector_free(&seen); return error; } void git_submodule_config_free(git_repository *repo) { git_strmap *smcfg; git_submodule *sm; assert(repo); smcfg = repo->submodules; repo->submodules = NULL; if (smcfg == NULL) return; git_strmap_foreach_value(smcfg, sm, { submodule_release(sm,1); }); git_strmap_free(smcfg); } int git_submodule_add_setup( git_submodule **submodule, git_repository *repo, const char *url, const char *path, int use_gitlink) { int error = 0; git_config_backend *mods = NULL; git_submodule *sm; git_buf name = GIT_BUF_INIT, real_url = GIT_BUF_INIT; git_repository_init_options initopt = GIT_REPOSITORY_INIT_OPTIONS_INIT; git_repository *subrepo = NULL; assert(repo && url && path); /* see if there is already an entry for this submodule */ if (git_submodule_lookup(&sm, repo, path) < 0) giterr_clear(); else { giterr_set(GITERR_SUBMODULE, "Attempt to add a submodule that already exists"); return GIT_EEXISTS; } /* resolve parameters */ if (url[0] == '.' && (url[1] == '/' || (url[1] == '.' && url[2] == '/'))) { if (!(error = lookup_head_remote(&real_url, repo))) error = git_path_apply_relative(&real_url, url); } else if (strchr(url, ':') != NULL || url[0] == '/') { error = git_buf_sets(&real_url, url); } else { giterr_set(GITERR_SUBMODULE, "Invalid format for submodule URL"); error = -1; } if (error) goto cleanup; /* validate and normalize path */ if (git__prefixcmp(path, git_repository_workdir(repo)) == 0) path += strlen(git_repository_workdir(repo)); if (git_path_root(path) >= 0) { giterr_set(GITERR_SUBMODULE, "Submodule path must be a relative path"); error = -1; goto cleanup; } /* update .gitmodules */ if ((mods = open_gitmodules(repo, true, NULL)) == NULL) { giterr_set(GITERR_SUBMODULE, "Adding submodules to a bare repository is not supported (for now)"); return -1; } if ((error = git_buf_printf(&name, "submodule.%s.path", path)) < 0 || (error = git_config_file_set_string(mods, name.ptr, path)) < 0) goto cleanup; if ((error = submodule_config_key_trunc_puts(&name, "url")) < 0 || (error = git_config_file_set_string(mods, name.ptr, real_url.ptr)) < 0) goto cleanup; git_buf_clear(&name); /* init submodule repository and add origin remote as needed */ error = git_buf_joinpath(&name, git_repository_workdir(repo), path); if (error < 0) goto cleanup; /* New style: sub-repo goes in /modules// with a * gitlink in the sub-repo workdir directory to that repository * * Old style: sub-repo goes directly into repo//.git/ */ initopt.flags = GIT_REPOSITORY_INIT_MKPATH | GIT_REPOSITORY_INIT_NO_REINIT; initopt.origin_url = real_url.ptr; if (git_path_exists(name.ptr) && git_path_contains(&name, DOT_GIT)) { /* repo appears to already exist - reinit? */ } else if (use_gitlink) { git_buf repodir = GIT_BUF_INIT; error = git_buf_join_n( &repodir, '/', 3, git_repository_path(repo), "modules", path); if (error < 0) goto cleanup; initopt.workdir_path = name.ptr; initopt.flags |= GIT_REPOSITORY_INIT_NO_DOTGIT_DIR; error = git_repository_init_ext(&subrepo, repodir.ptr, &initopt); git_buf_free(&repodir); } else { error = git_repository_init_ext(&subrepo, name.ptr, &initopt); } if (error < 0) goto cleanup; /* add submodule to hash and "reload" it */ if (!(error = submodule_get(&sm, repo, path, NULL)) && !(error = git_submodule_reload(sm))) error = git_submodule_init(sm, false); cleanup: if (submodule != NULL) *submodule = !error ? sm : NULL; if (mods != NULL) git_config_file_free(mods); git_repository_free(subrepo); git_buf_free(&real_url); git_buf_free(&name); return error; } int git_submodule_add_finalize(git_submodule *sm) { int error; git_index *index; assert(sm); if ((error = git_repository_index__weakptr(&index, sm->owner)) < 0 || (error = git_index_add_bypath(index, GIT_MODULES_FILE)) < 0) return error; return git_submodule_add_to_index(sm, true); } int git_submodule_add_to_index(git_submodule *sm, int write_index) { int error; git_repository *repo, *sm_repo = NULL; git_index *index; git_buf path = GIT_BUF_INIT; git_commit *head; git_index_entry entry; struct stat st; assert(sm); repo = sm->owner; /* force reload of wd OID by git_submodule_open */ sm->flags = sm->flags & ~GIT_SUBMODULE_STATUS__WD_OID_VALID; if ((error = git_repository_index__weakptr(&index, repo)) < 0 || (error = git_buf_joinpath( &path, git_repository_workdir(repo), sm->path)) < 0 || (error = git_submodule_open(&sm_repo, sm)) < 0) goto cleanup; /* read stat information for submodule working directory */ if (p_stat(path.ptr, &st) < 0) { giterr_set(GITERR_SUBMODULE, "Cannot add submodule without working directory"); error = -1; goto cleanup; } memset(&entry, 0, sizeof(entry)); entry.path = sm->path; git_index_entry__init_from_stat(&entry, &st); /* calling git_submodule_open will have set sm->wd_oid if possible */ if ((sm->flags & GIT_SUBMODULE_STATUS__WD_OID_VALID) == 0) { giterr_set(GITERR_SUBMODULE, "Cannot add submodule without HEAD to index"); error = -1; goto cleanup; } git_oid_cpy(&entry.oid, &sm->wd_oid); if ((error = git_commit_lookup(&head, sm_repo, &sm->wd_oid)) < 0) goto cleanup; entry.ctime.seconds = git_commit_time(head); entry.ctime.nanoseconds = 0; entry.mtime.seconds = git_commit_time(head); entry.mtime.nanoseconds = 0; git_commit_free(head); /* add it */ error = git_index_add(index, &entry); /* write it, if requested */ if (!error && write_index) { error = git_index_write(index); if (!error) git_oid_cpy(&sm->index_oid, &sm->wd_oid); } cleanup: git_repository_free(sm_repo); git_buf_free(&path); return error; } int git_submodule_save(git_submodule *submodule) { int error = 0; git_config_backend *mods; git_buf key = GIT_BUF_INIT; assert(submodule); mods = open_gitmodules(submodule->owner, true, NULL); if (!mods) { giterr_set(GITERR_SUBMODULE, "Adding submodules to a bare repository is not supported (for now)"); return -1; } if ((error = git_buf_printf(&key, "submodule.%s.", submodule->name)) < 0) goto cleanup; /* save values for path, url, update, ignore, fetchRecurseSubmodules */ if ((error = submodule_config_key_trunc_puts(&key, "path")) < 0 || (error = git_config_file_set_string(mods, key.ptr, submodule->path)) < 0) goto cleanup; if ((error = submodule_config_key_trunc_puts(&key, "url")) < 0 || (error = git_config_file_set_string(mods, key.ptr, submodule->url)) < 0) goto cleanup; if (!(error = submodule_config_key_trunc_puts(&key, "update")) && submodule->update != GIT_SUBMODULE_UPDATE_DEFAULT) { const char *val = (submodule->update == GIT_SUBMODULE_UPDATE_CHECKOUT) ? NULL : _sm_update_map[submodule->update].str_match; error = git_config_file_set_string(mods, key.ptr, val); } if (error < 0) goto cleanup; if (!(error = submodule_config_key_trunc_puts(&key, "ignore")) && submodule->ignore != GIT_SUBMODULE_IGNORE_DEFAULT) { const char *val = (submodule->ignore == GIT_SUBMODULE_IGNORE_NONE) ? NULL : _sm_ignore_map[submodule->ignore].str_match; error = git_config_file_set_string(mods, key.ptr, val); } if (error < 0) goto cleanup; if ((error = submodule_config_key_trunc_puts( &key, "fetchRecurseSubmodules")) < 0 || (error = git_config_file_set_string( mods, key.ptr, submodule->fetch_recurse ? "true" : "false")) < 0) goto cleanup; /* update internal defaults */ submodule->ignore_default = submodule->ignore; submodule->update_default = submodule->update; submodule->flags |= GIT_SUBMODULE_STATUS_IN_CONFIG; cleanup: if (mods != NULL) git_config_file_free(mods); git_buf_free(&key); return error; } git_repository *git_submodule_owner(git_submodule *submodule) { assert(submodule); return submodule->owner; } const char *git_submodule_name(git_submodule *submodule) { assert(submodule); return submodule->name; } const char *git_submodule_path(git_submodule *submodule) { assert(submodule); return submodule->path; } const char *git_submodule_url(git_submodule *submodule) { assert(submodule); return submodule->url; } int git_submodule_set_url(git_submodule *submodule, const char *url) { assert(submodule && url); git__free(submodule->url); submodule->url = git__strdup(url); GITERR_CHECK_ALLOC(submodule->url); return 0; } const git_oid *git_submodule_index_id(git_submodule *submodule) { assert(submodule); if (submodule->flags & GIT_SUBMODULE_STATUS__INDEX_OID_VALID) return &submodule->index_oid; else return NULL; } const git_oid *git_submodule_head_id(git_submodule *submodule) { assert(submodule); if (submodule->flags & GIT_SUBMODULE_STATUS__HEAD_OID_VALID) return &submodule->head_oid; else return NULL; } const git_oid *git_submodule_wd_id(git_submodule *submodule) { assert(submodule); if (!(submodule->flags & GIT_SUBMODULE_STATUS__WD_OID_VALID)) { git_repository *subrepo; /* calling submodule open grabs the HEAD OID if possible */ if (!git_submodule_open(&subrepo, submodule)) git_repository_free(subrepo); else giterr_clear(); } if (submodule->flags & GIT_SUBMODULE_STATUS__WD_OID_VALID) return &submodule->wd_oid; else return NULL; } git_submodule_ignore_t git_submodule_ignore(git_submodule *submodule) { assert(submodule); return submodule->ignore; } git_submodule_ignore_t git_submodule_set_ignore( git_submodule *submodule, git_submodule_ignore_t ignore) { git_submodule_ignore_t old; assert(submodule); if (ignore == GIT_SUBMODULE_IGNORE_DEFAULT) ignore = submodule->ignore_default; old = submodule->ignore; submodule->ignore = ignore; return old; } git_submodule_update_t git_submodule_update(git_submodule *submodule) { assert(submodule); return submodule->update; } git_submodule_update_t git_submodule_set_update( git_submodule *submodule, git_submodule_update_t update) { git_submodule_update_t old; assert(submodule); if (update == GIT_SUBMODULE_UPDATE_DEFAULT) update = submodule->update_default; old = submodule->update; submodule->update = update; return old; } int git_submodule_fetch_recurse_submodules( git_submodule *submodule) { assert(submodule); return submodule->fetch_recurse; } int git_submodule_set_fetch_recurse_submodules( git_submodule *submodule, int fetch_recurse_submodules) { int old; assert(submodule); old = submodule->fetch_recurse; submodule->fetch_recurse = (fetch_recurse_submodules != 0); return old; } int git_submodule_init(git_submodule *submodule, int overwrite) { int error; /* write "submodule.NAME.url" */ if (!submodule->url) { giterr_set(GITERR_SUBMODULE, "No URL configured for submodule '%s'", submodule->name); return -1; } error = submodule_update_config( submodule, "url", submodule->url, overwrite != 0, false); if (error < 0) return error; /* write "submodule.NAME.update" if not default */ if (submodule->update == GIT_SUBMODULE_UPDATE_CHECKOUT) error = submodule_update_config( submodule, "update", NULL, (overwrite != 0), false); else if (submodule->update != GIT_SUBMODULE_UPDATE_DEFAULT) error = submodule_update_config( submodule, "update", _sm_update_map[submodule->update].str_match, (overwrite != 0), false); return error; } int git_submodule_sync(git_submodule *submodule) { if (!submodule->url) { giterr_set(GITERR_SUBMODULE, "No URL configured for submodule '%s'", submodule->name); return -1; } /* copy URL over to config only if it already exists */ return submodule_update_config( submodule, "url", submodule->url, true, true); } int git_submodule_open( git_repository **subrepo, git_submodule *submodule) { int error; git_buf path = GIT_BUF_INIT; git_repository *repo; const char *workdir; assert(submodule && subrepo); repo = submodule->owner; workdir = git_repository_workdir(repo); if (!workdir) { giterr_set(GITERR_REPOSITORY, "Cannot open submodule repository in a bare repo"); return GIT_ENOTFOUND; } if ((submodule->flags & GIT_SUBMODULE_STATUS_IN_WD) == 0) { giterr_set(GITERR_REPOSITORY, "Cannot open submodule repository that is not checked out"); return GIT_ENOTFOUND; } if (git_buf_joinpath(&path, workdir, submodule->path) < 0) return -1; error = git_repository_open(subrepo, path.ptr); git_buf_free(&path); /* if we have opened the submodule successfully, let's grab the HEAD OID */ if (!error) { if (!git_reference_name_to_id( &submodule->wd_oid, *subrepo, GIT_HEAD_FILE)) submodule->flags |= GIT_SUBMODULE_STATUS__WD_OID_VALID; else giterr_clear(); } return error; } int git_submodule_reload_all(git_repository *repo) { assert(repo); git_submodule_config_free(repo); return load_submodule_config(repo); } int git_submodule_reload(git_submodule *submodule) { git_repository *repo; git_index *index; int error; size_t pos; git_tree *head; git_config_backend *mods; assert(submodule); /* refresh index data */ repo = submodule->owner; if (git_repository_index__weakptr(&index, repo) < 0) return -1; submodule->flags = submodule->flags & ~(GIT_SUBMODULE_STATUS_IN_INDEX | GIT_SUBMODULE_STATUS__INDEX_OID_VALID); if (!git_index_find(&pos, index, submodule->path)) { const git_index_entry *entry = git_index_get_byindex(index, pos); if (S_ISGITLINK(entry->mode)) { if ((error = submodule_load_from_index(repo, entry)) < 0) return error; } else { submodule_mode_mismatch( repo, entry->path, GIT_SUBMODULE_STATUS__INDEX_NOT_SUBMODULE); } } /* refresh HEAD tree data */ if (!(error = git_repository_head_tree(&head, repo))) { git_tree_entry *te; submodule->flags = submodule->flags & ~(GIT_SUBMODULE_STATUS_IN_HEAD | GIT_SUBMODULE_STATUS__HEAD_OID_VALID); if (!(error = git_tree_entry_bypath(&te, head, submodule->path))) { if (S_ISGITLINK(te->attr)) { error = submodule_load_from_head(repo, submodule->path, &te->oid); } else { submodule_mode_mismatch( repo, submodule->path, GIT_SUBMODULE_STATUS__HEAD_NOT_SUBMODULE); } git_tree_entry_free(te); } else if (error == GIT_ENOTFOUND) { giterr_clear(); error = 0; } git_tree_free(head); } if (error < 0) return error; /* refresh config data */ if ((mods = open_gitmodules(repo, false, NULL)) != NULL) { git_buf path = GIT_BUF_INIT; git_buf_sets(&path, "submodule\\."); git_buf_text_puts_escape_regex(&path, submodule->name); git_buf_puts(&path, ".*"); if (git_buf_oom(&path)) error = -1; else error = git_config_file_foreach_match( mods, path.ptr, submodule_load_from_config, repo); git_buf_free(&path); git_config_file_free(mods); } if (error < 0) return error; /* refresh wd data */ submodule->flags = submodule->flags & ~(GIT_SUBMODULE_STATUS_IN_WD | GIT_SUBMODULE_STATUS__WD_OID_VALID); error = submodule_load_from_wd_lite(submodule, submodule->path, NULL); return error; } int git_submodule_status( unsigned int *status, git_submodule *submodule) { int error = 0; unsigned int status_val; assert(status && submodule); status_val = GIT_SUBMODULE_STATUS__CLEAR_INTERNAL(submodule->flags); if (submodule->ignore != GIT_SUBMODULE_IGNORE_ALL) { if (!(error = submodule_index_status(&status_val, submodule))) error = submodule_wd_status(&status_val, submodule); } *status = status_val; return error; } int git_submodule_location( unsigned int *location_status, git_submodule *submodule) { assert(location_status && submodule); *location_status = submodule->flags & (GIT_SUBMODULE_STATUS_IN_HEAD | GIT_SUBMODULE_STATUS_IN_INDEX | GIT_SUBMODULE_STATUS_IN_CONFIG | GIT_SUBMODULE_STATUS_IN_WD); return 0; } /* * INTERNAL FUNCTIONS */ static git_submodule *submodule_alloc(git_repository *repo, const char *name) { git_submodule *sm; if (!name || !strlen(name)) { giterr_set(GITERR_SUBMODULE, "Invalid submodule name"); return NULL; } sm = git__calloc(1, sizeof(git_submodule)); if (sm == NULL) goto fail; sm->path = sm->name = git__strdup(name); if (!sm->name) goto fail; sm->owner = repo; sm->refcount = 1; return sm; fail: submodule_release(sm, 0); return NULL; } static void submodule_release(git_submodule *sm, int decr) { if (!sm) return; sm->refcount -= decr; if (sm->refcount == 0) { if (sm->name != sm->path) { git__free(sm->path); sm->path = NULL; } git__free(sm->name); sm->name = NULL; git__free(sm->url); sm->url = NULL; sm->owner = NULL; git__free(sm); } } static int submodule_get( git_submodule **sm_ptr, git_repository *repo, const char *name, const char *alternate) { git_strmap *smcfg = repo->submodules; khiter_t pos; git_submodule *sm; int error; assert(repo && name); pos = git_strmap_lookup_index(smcfg, name); if (!git_strmap_valid_index(smcfg, pos) && alternate) pos = git_strmap_lookup_index(smcfg, alternate); if (!git_strmap_valid_index(smcfg, pos)) { sm = submodule_alloc(repo, name); /* insert value at name - if another thread beats us to it, then use * their record and release our own. */ pos = kh_put(str, smcfg, sm->name, &error); if (error < 0) { submodule_release(sm, 1); sm = NULL; } else if (error == 0) { submodule_release(sm, 1); sm = git_strmap_value_at(smcfg, pos); } else { git_strmap_set_value_at(smcfg, pos, sm); } } else { sm = git_strmap_value_at(smcfg, pos); } *sm_ptr = sm; return (sm != NULL) ? 0 : -1; } static int submodule_load_from_index( git_repository *repo, const git_index_entry *entry) { git_submodule *sm; if (submodule_get(&sm, repo, entry->path, NULL) < 0) return -1; if (sm->flags & GIT_SUBMODULE_STATUS_IN_INDEX) { sm->flags |= GIT_SUBMODULE_STATUS__INDEX_MULTIPLE_ENTRIES; return 0; } sm->flags |= GIT_SUBMODULE_STATUS_IN_INDEX; git_oid_cpy(&sm->index_oid, &entry->oid); sm->flags |= GIT_SUBMODULE_STATUS__INDEX_OID_VALID; return 0; } static int submodule_load_from_head( git_repository *repo, const char *path, const git_oid *oid) { git_submodule *sm; if (submodule_get(&sm, repo, path, NULL) < 0) return -1; sm->flags |= GIT_SUBMODULE_STATUS_IN_HEAD; git_oid_cpy(&sm->head_oid, oid); sm->flags |= GIT_SUBMODULE_STATUS__HEAD_OID_VALID; return 0; } static int submodule_config_error(const char *property, const char *value) { giterr_set(GITERR_INVALID, "Invalid value for submodule '%s' property: '%s'", property, value); return -1; } static int submodule_load_from_config( const git_config_entry *entry, void *data) { git_repository *repo = data; git_strmap *smcfg = repo->submodules; const char *namestart, *property, *alternate = NULL; const char *key = entry->name, *value = entry->value; git_buf name = GIT_BUF_INIT; git_submodule *sm; bool is_path; int error = 0; if (git__prefixcmp(key, "submodule.") != 0) return 0; namestart = key + strlen("submodule."); property = strrchr(namestart, '.'); if (property == NULL) return 0; property++; is_path = (strcasecmp(property, "path") == 0); if (git_buf_set(&name, namestart, property - namestart - 1) < 0) return -1; if (submodule_get(&sm, repo, name.ptr, is_path ? value : NULL) < 0) { git_buf_free(&name); return -1; } sm->flags |= GIT_SUBMODULE_STATUS_IN_CONFIG; /* Only from config might we get differing names & paths. If so, then * update the submodule and insert under the alternative key. */ /* TODO: if case insensitive filesystem, then the following strcmps * should be strcasecmp */ if (strcmp(sm->name, name.ptr) != 0) { alternate = sm->name = git_buf_detach(&name); } else if (is_path && value && strcmp(sm->path, value) != 0) { alternate = sm->path = git__strdup(value); if (!sm->path) error = -1; } if (alternate) { void *old_sm = NULL; git_strmap_insert2(smcfg, alternate, sm, old_sm, error); if (error >= 0) sm->refcount++; /* inserted under a new key */ /* if we replaced an old module under this key, release the old one */ if (old_sm && ((git_submodule *)old_sm) != sm) { submodule_release(old_sm, 1); /* TODO: log warning about multiple submodules with same path */ } } git_buf_free(&name); if (error < 0) return error; /* TODO: Look up path in index and if it is present but not a GITLINK * then this should be deleted (at least to match git's behavior) */ if (is_path) return 0; /* copy other properties into submodule entry */ if (strcasecmp(property, "url") == 0) { git__free(sm->url); sm->url = NULL; if (value != NULL && (sm->url = git__strdup(value)) == NULL) return -1; } else if (strcasecmp(property, "update") == 0) { int val; if (git_config_lookup_map_value( &val, _sm_update_map, ARRAY_SIZE(_sm_update_map), value) < 0) return submodule_config_error("update", value); sm->update_default = sm->update = (git_submodule_update_t)val; } else if (strcasecmp(property, "fetchRecurseSubmodules") == 0) { if (git__parse_bool(&sm->fetch_recurse, value) < 0) return submodule_config_error("fetchRecurseSubmodules", value); } else if (strcasecmp(property, "ignore") == 0) { int val; if (git_config_lookup_map_value( &val, _sm_ignore_map, ARRAY_SIZE(_sm_ignore_map), value) < 0) return submodule_config_error("ignore", value); sm->ignore_default = sm->ignore = (git_submodule_ignore_t)val; } /* ignore other unknown submodule properties */ return 0; } static int submodule_load_from_wd_lite( git_submodule *sm, const char *name, void *payload) { git_repository *repo = git_submodule_owner(sm); git_buf path = GIT_BUF_INIT; GIT_UNUSED(name); GIT_UNUSED(payload); if (git_buf_joinpath(&path, git_repository_workdir(repo), sm->path) < 0) return -1; if (git_path_isdir(path.ptr)) sm->flags |= GIT_SUBMODULE_STATUS__WD_SCANNED; if (git_path_contains(&path, DOT_GIT)) sm->flags |= GIT_SUBMODULE_STATUS_IN_WD; git_buf_free(&path); return 0; } static void submodule_mode_mismatch( git_repository *repo, const char *path, unsigned int flag) { khiter_t pos = git_strmap_lookup_index(repo->submodules, path); if (git_strmap_valid_index(repo->submodules, pos)) { git_submodule *sm = git_strmap_value_at(repo->submodules, pos); sm->flags |= flag; } } static int load_submodule_config_from_index( git_repository *repo, git_oid *gitmodules_oid) { int error; git_index *index; git_iterator *i; const git_index_entry *entry; if ((error = git_repository_index__weakptr(&index, repo)) < 0 || (error = git_iterator_for_index(&i, index, 0, NULL, NULL)) < 0) return error; while (!(error = git_iterator_advance(&entry, i))) { if (S_ISGITLINK(entry->mode)) { error = submodule_load_from_index(repo, entry); if (error < 0) break; } else { submodule_mode_mismatch( repo, entry->path, GIT_SUBMODULE_STATUS__INDEX_NOT_SUBMODULE); if (strcmp(entry->path, GIT_MODULES_FILE) == 0) git_oid_cpy(gitmodules_oid, &entry->oid); } } if (error == GIT_ITEROVER) error = 0; git_iterator_free(i); return error; } static int load_submodule_config_from_head( git_repository *repo, git_oid *gitmodules_oid) { int error; git_tree *head; git_iterator *i; const git_index_entry *entry; if ((error = git_repository_head_tree(&head, repo)) < 0) return error; if ((error = git_iterator_for_tree(&i, head, 0, NULL, NULL)) < 0) { git_tree_free(head); return error; } while (!(error = git_iterator_advance(&entry, i))) { if (S_ISGITLINK(entry->mode)) { error = submodule_load_from_head(repo, entry->path, &entry->oid); if (error < 0) break; } else { submodule_mode_mismatch( repo, entry->path, GIT_SUBMODULE_STATUS__HEAD_NOT_SUBMODULE); if (strcmp(entry->path, GIT_MODULES_FILE) == 0 && git_oid_iszero(gitmodules_oid)) git_oid_cpy(gitmodules_oid, &entry->oid); } } if (error == GIT_ITEROVER) error = 0; git_iterator_free(i); git_tree_free(head); return error; } static git_config_backend *open_gitmodules( git_repository *repo, bool okay_to_create, const git_oid *gitmodules_oid) { const char *workdir = git_repository_workdir(repo); git_buf path = GIT_BUF_INIT; git_config_backend *mods = NULL; if (workdir != NULL) { if (git_buf_joinpath(&path, workdir, GIT_MODULES_FILE) != 0) return NULL; if (okay_to_create || git_path_isfile(path.ptr)) { /* git_config_file__ondisk should only fail if OOM */ if (git_config_file__ondisk(&mods, path.ptr) < 0) mods = NULL; /* open should only fail here if the file is malformed */ else if (git_config_file_open(mods, GIT_CONFIG_LEVEL_LOCAL) < 0) { git_config_file_free(mods); mods = NULL; } } } if (!mods && gitmodules_oid && !git_oid_iszero(gitmodules_oid)) { /* TODO: Retrieve .gitmodules content from ODB */ /* Should we actually do this? Core git does not, but it means you * can't really get much information about submodules on bare repos. */ } git_buf_free(&path); return mods; } static int load_submodule_config(git_repository *repo) { int error; git_oid gitmodules_oid; git_buf path = GIT_BUF_INIT; git_config_backend *mods = NULL; if (repo->submodules) return 0; memset(&gitmodules_oid, 0, sizeof(gitmodules_oid)); /* Submodule data is kept in a hashtable keyed by both name and path. * These are usually the same, but that is not guaranteed. */ if (!repo->submodules) { repo->submodules = git_strmap_alloc(); GITERR_CHECK_ALLOC(repo->submodules); } /* add submodule information from index */ if ((error = load_submodule_config_from_index(repo, &gitmodules_oid)) < 0) goto cleanup; /* add submodule information from HEAD */ if ((error = load_submodule_config_from_head(repo, &gitmodules_oid)) < 0) goto cleanup; /* add submodule information from .gitmodules */ if ((mods = open_gitmodules(repo, false, &gitmodules_oid)) != NULL) error = git_config_file_foreach(mods, submodule_load_from_config, repo); if (error != 0) goto cleanup; /* shallow scan submodules in work tree */ if (!git_repository_is_bare(repo)) error = git_submodule_foreach(repo, submodule_load_from_wd_lite, NULL); cleanup: git_buf_free(&path); if (mods != NULL) git_config_file_free(mods); if (error) git_submodule_config_free(repo); return error; } static int lookup_head_remote(git_buf *url, git_repository *repo) { int error; git_config *cfg; git_reference *head = NULL, *remote = NULL; const char *tgt, *scan; git_buf key = GIT_BUF_INIT; /* 1. resolve HEAD -> refs/heads/BRANCH * 2. lookup config branch.BRANCH.remote -> ORIGIN * 3. lookup remote.ORIGIN.url */ if ((error = git_repository_config__weakptr(&cfg, repo)) < 0) return error; if (git_reference_lookup(&head, repo, GIT_HEAD_FILE) < 0) { giterr_set(GITERR_SUBMODULE, "Cannot resolve relative URL when HEAD cannot be resolved"); error = GIT_ENOTFOUND; goto cleanup; } if (git_reference_type(head) != GIT_REF_SYMBOLIC) { giterr_set(GITERR_SUBMODULE, "Cannot resolve relative URL when HEAD is not symbolic"); error = GIT_ENOTFOUND; goto cleanup; } if ((error = git_branch_upstream(&remote, head)) < 0) goto cleanup; /* remote should refer to something like refs/remotes/ORIGIN/BRANCH */ if (git_reference_type(remote) != GIT_REF_SYMBOLIC || git__prefixcmp(git_reference_symbolic_target(remote), GIT_REFS_REMOTES_DIR) != 0) { giterr_set(GITERR_SUBMODULE, "Cannot resolve relative URL when HEAD is not symbolic"); error = GIT_ENOTFOUND; goto cleanup; } scan = tgt = git_reference_symbolic_target(remote) + strlen(GIT_REFS_REMOTES_DIR); while (*scan && (*scan != '/' || (scan > tgt && scan[-1] != '\\'))) scan++; /* find non-escaped slash to end ORIGIN name */ error = git_buf_printf(&key, "remote.%.*s.url", (int)(scan - tgt), tgt); if (error < 0) goto cleanup; if ((error = git_config_get_string(&tgt, cfg, key.ptr)) < 0) goto cleanup; error = git_buf_sets(url, tgt); cleanup: git_buf_free(&key); git_reference_free(head); git_reference_free(remote); return error; } static int submodule_update_config( git_submodule *submodule, const char *attr, const char *value, bool overwrite, bool only_existing) { int error; git_config *config; git_buf key = GIT_BUF_INIT; const char *old = NULL; assert(submodule); error = git_repository_config__weakptr(&config, submodule->owner); if (error < 0) return error; error = git_buf_printf(&key, "submodule.%s.%s", submodule->name, attr); if (error < 0) goto cleanup; if (git_config_get_string(&old, config, key.ptr) < 0) giterr_clear(); if (!old && only_existing) goto cleanup; if (old && !overwrite) goto cleanup; if ((!old && !value) || (old && value && strcmp(old, value) == 0)) goto cleanup; if (!value) error = git_config_delete_entry(config, key.ptr); else error = git_config_set_string(config, key.ptr, value); cleanup: git_buf_free(&key); return error; } static int submodule_index_status(unsigned int *status, git_submodule *sm) { const git_oid *head_oid = git_submodule_head_id(sm); const git_oid *index_oid = git_submodule_index_id(sm); if (!head_oid) { if (index_oid) *status |= GIT_SUBMODULE_STATUS_INDEX_ADDED; } else if (!index_oid) *status |= GIT_SUBMODULE_STATUS_INDEX_DELETED; else if (!git_oid_equal(head_oid, index_oid)) *status |= GIT_SUBMODULE_STATUS_INDEX_MODIFIED; return 0; } static int submodule_wd_status(unsigned int *status, git_submodule *sm) { int error = 0; const git_oid *wd_oid, *index_oid; git_repository *sm_repo = NULL; /* open repo now if we need it (so wd_id() call won't reopen) */ if ((sm->ignore == GIT_SUBMODULE_IGNORE_NONE || sm->ignore == GIT_SUBMODULE_IGNORE_UNTRACKED) && (sm->flags & GIT_SUBMODULE_STATUS_IN_WD) != 0) { if ((error = git_submodule_open(&sm_repo, sm)) < 0) return error; } index_oid = git_submodule_index_id(sm); wd_oid = git_submodule_wd_id(sm); if (!index_oid) { if (wd_oid) *status |= GIT_SUBMODULE_STATUS_WD_ADDED; } else if (!wd_oid) { if ((sm->flags & GIT_SUBMODULE_STATUS__WD_SCANNED) != 0 && (sm->flags & GIT_SUBMODULE_STATUS_IN_WD) == 0) *status |= GIT_SUBMODULE_STATUS_WD_UNINITIALIZED; else *status |= GIT_SUBMODULE_STATUS_WD_DELETED; } else if (!git_oid_equal(index_oid, wd_oid)) *status |= GIT_SUBMODULE_STATUS_WD_MODIFIED; if (sm_repo != NULL) { git_tree *sm_head; git_diff_options opt = GIT_DIFF_OPTIONS_INIT; git_diff_list *diff; /* the diffs below could be optimized with an early termination * option to the git_diff functions, but for now this is sufficient * (and certainly no worse that what core git does). */ /* perform head-to-index diff on submodule */ if ((error = git_repository_head_tree(&sm_head, sm_repo)) < 0) return error; if (sm->ignore == GIT_SUBMODULE_IGNORE_NONE) opt.flags |= GIT_DIFF_INCLUDE_UNTRACKED; error = git_diff_tree_to_index(&diff, sm_repo, sm_head, NULL, &opt); if (!error) { if (git_diff_num_deltas(diff) > 0) *status |= GIT_SUBMODULE_STATUS_WD_INDEX_MODIFIED; git_diff_list_free(diff); diff = NULL; } git_tree_free(sm_head); if (error < 0) return error; /* perform index-to-workdir diff on submodule */ error = git_diff_index_to_workdir(&diff, sm_repo, NULL, &opt); if (!error) { size_t untracked = git_diff_num_deltas_of_type(diff, GIT_DELTA_UNTRACKED); if (untracked > 0) *status |= GIT_SUBMODULE_STATUS_WD_UNTRACKED; if (git_diff_num_deltas(diff) != untracked) *status |= GIT_SUBMODULE_STATUS_WD_WD_MODIFIED; git_diff_list_free(diff); diff = NULL; } git_repository_free(sm_repo); } return error; } libgit2-0.19.0/src/submodule.h000066400000000000000000000074451216214232500161040ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #ifndef INCLUDE_submodule_h__ #define INCLUDE_submodule_h__ /* Notes: * * Submodule information can be in four places: the index, the config files * (both .git/config and .gitmodules), the HEAD tree, and the working * directory. * * In the index: * - submodule is found by path * - may be missing, present, or of the wrong type * - will have an oid if present * * In the HEAD tree: * - submodule is found by path * - may be missing, present, or of the wrong type * - will have an oid if present * * In the config files: * - submodule is found by submodule "name" which is usually the path * - may be missing or present * - will have a name, path, url, and other properties * * In the working directory: * - submodule is found by path * - may be missing, an empty directory, a checked out directory, * or of the wrong type * - if checked out, will have a HEAD oid * - if checked out, will have git history that can be used to compare oids * - if checked out, may have modified files and/or untracked files */ /** * Description of submodule * * This record describes a submodule found in a repository. There should be * an entry for every submodule found in the HEAD and index, and for every * submodule described in .gitmodules. The fields are as follows: * * - `owner` is the git_repository containing this submodule * - `name` is the name of the submodule from .gitmodules. * - `path` is the path to the submodule from the repo root. It is almost * always the same as `name`. * - `url` is the url for the submodule. * - `tree_oid` is the SHA1 for the submodule path in the repo HEAD. * - `index_oid` is the SHA1 for the submodule recorded in the index. * - `workdir_oid` is the SHA1 for the HEAD of the checked out submodule. * - `update` is a git_submodule_update_t value - see gitmodules(5) update. * - `ignore` is a git_submodule_ignore_t value - see gitmodules(5) ignore. * - `fetch_recurse` is 0 or 1 - see gitmodules(5) fetchRecurseSubmodules. * - `refcount` tracks how many hashmap entries there are for this submodule. * It only comes into play if the name and path of the submodule differ. * - `flags` is for internal use, tracking where this submodule has been * found (head, index, config, workdir) and other misc info about it. * * If the submodule has been added to .gitmodules but not yet git added, * then the `index_oid` will be valid and zero. If the submodule has been * deleted, but the delete has not been committed yet, then the `index_oid` * will be set, but the `url` will be NULL. */ struct git_submodule { git_repository *owner; char *name; char *path; /* important: may point to same string data as "name" */ char *url; uint32_t flags; git_oid head_oid; git_oid index_oid; git_oid wd_oid; /* information from config */ git_submodule_update_t update; git_submodule_update_t update_default; git_submodule_ignore_t ignore; git_submodule_ignore_t ignore_default; int fetch_recurse; /* internal information */ int refcount; }; /* Additional flags on top of public GIT_SUBMODULE_STATUS values */ enum { GIT_SUBMODULE_STATUS__WD_SCANNED = (1u << 20), GIT_SUBMODULE_STATUS__HEAD_OID_VALID = (1u << 21), GIT_SUBMODULE_STATUS__INDEX_OID_VALID = (1u << 22), GIT_SUBMODULE_STATUS__WD_OID_VALID = (1u << 23), GIT_SUBMODULE_STATUS__HEAD_NOT_SUBMODULE = (1u << 24), GIT_SUBMODULE_STATUS__INDEX_NOT_SUBMODULE = (1u << 25), GIT_SUBMODULE_STATUS__WD_NOT_SUBMODULE = (1u << 26), GIT_SUBMODULE_STATUS__INDEX_MULTIPLE_ENTRIES = (1u << 27), }; #define GIT_SUBMODULE_STATUS__CLEAR_INTERNAL(S) \ ((S) & ~(0xFFFFFFFFu << 20)) #endif libgit2-0.19.0/src/tag.c000066400000000000000000000262351216214232500146510ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #include "common.h" #include "commit.h" #include "tag.h" #include "signature.h" #include "message.h" #include "git2/object.h" #include "git2/repository.h" #include "git2/signature.h" #include "git2/odb_backend.h" void git_tag__free(void *_tag) { git_tag *tag = _tag; git_signature_free(tag->tagger); git__free(tag->message); git__free(tag->tag_name); git__free(tag); } int git_tag_target(git_object **target, const git_tag *t) { assert(t); return git_object_lookup(target, t->object.repo, &t->target, t->type); } const git_oid *git_tag_target_id(const git_tag *t) { assert(t); return &t->target; } git_otype git_tag_target_type(const git_tag *t) { assert(t); return t->type; } const char *git_tag_name(const git_tag *t) { assert(t); return t->tag_name; } const git_signature *git_tag_tagger(const git_tag *t) { return t->tagger; } const char *git_tag_message(const git_tag *t) { assert(t); return t->message; } static int tag_error(const char *str) { giterr_set(GITERR_TAG, "Failed to parse tag. %s", str); return -1; } static int tag_parse(git_tag *tag, const char *buffer, const char *buffer_end) { static const char *tag_types[] = { NULL, "commit\n", "tree\n", "blob\n", "tag\n" }; unsigned int i; size_t text_len; char *search; if (git_oid__parse(&tag->target, &buffer, buffer_end, "object ") < 0) return tag_error("Object field invalid"); if (buffer + 5 >= buffer_end) return tag_error("Object too short"); if (memcmp(buffer, "type ", 5) != 0) return tag_error("Type field not found"); buffer += 5; tag->type = GIT_OBJ_BAD; for (i = 1; i < ARRAY_SIZE(tag_types); ++i) { size_t type_length = strlen(tag_types[i]); if (buffer + type_length >= buffer_end) return tag_error("Object too short"); if (memcmp(buffer, tag_types[i], type_length) == 0) { tag->type = i; buffer += type_length; break; } } if (tag->type == GIT_OBJ_BAD) return tag_error("Invalid object type"); if (buffer + 4 >= buffer_end) return tag_error("Object too short"); if (memcmp(buffer, "tag ", 4) != 0) return tag_error("Tag field not found"); buffer += 4; search = memchr(buffer, '\n', buffer_end - buffer); if (search == NULL) return tag_error("Object too short"); text_len = search - buffer; tag->tag_name = git__malloc(text_len + 1); GITERR_CHECK_ALLOC(tag->tag_name); memcpy(tag->tag_name, buffer, text_len); tag->tag_name[text_len] = '\0'; buffer = search + 1; tag->tagger = NULL; if (buffer < buffer_end && *buffer != '\n') { tag->tagger = git__malloc(sizeof(git_signature)); GITERR_CHECK_ALLOC(tag->tagger); if (git_signature__parse(tag->tagger, &buffer, buffer_end, "tagger ", '\n') < 0) return -1; } tag->message = NULL; if (buffer < buffer_end) { if( *buffer != '\n' ) return tag_error("No new line before message"); text_len = buffer_end - ++buffer; tag->message = git__malloc(text_len + 1); GITERR_CHECK_ALLOC(tag->message); memcpy(tag->message, buffer, text_len); tag->message[text_len] = '\0'; } return 0; } int git_tag__parse(void *_tag, git_odb_object *odb_obj) { git_tag *tag = _tag; const char *buffer = git_odb_object_data(odb_obj); const char *buffer_end = buffer + git_odb_object_size(odb_obj); return tag_parse(tag, buffer, buffer_end); } static int retrieve_tag_reference( git_reference **tag_reference_out, git_buf *ref_name_out, git_repository *repo, const char *tag_name) { git_reference *tag_ref; int error; *tag_reference_out = NULL; if (git_buf_joinpath(ref_name_out, GIT_REFS_TAGS_DIR, tag_name) < 0) return -1; error = git_reference_lookup(&tag_ref, repo, ref_name_out->ptr); if (error < 0) return error; /* Be it not foundo or corrupted */ *tag_reference_out = tag_ref; return 0; } static int retrieve_tag_reference_oid( git_oid *oid, git_buf *ref_name_out, git_repository *repo, const char *tag_name) { if (git_buf_joinpath(ref_name_out, GIT_REFS_TAGS_DIR, tag_name) < 0) return -1; return git_reference_name_to_id(oid, repo, ref_name_out->ptr); } static int write_tag_annotation( git_oid *oid, git_repository *repo, const char *tag_name, const git_object *target, const git_signature *tagger, const char *message) { git_buf tag = GIT_BUF_INIT; git_odb *odb; git_oid__writebuf(&tag, "object ", git_object_id(target)); git_buf_printf(&tag, "type %s\n", git_object_type2string(git_object_type(target))); git_buf_printf(&tag, "tag %s\n", tag_name); git_signature__writebuf(&tag, "tagger ", tagger); git_buf_putc(&tag, '\n'); if (git_buf_puts(&tag, message) < 0) goto on_error; if (git_repository_odb__weakptr(&odb, repo) < 0) goto on_error; if (git_odb_write(oid, odb, tag.ptr, tag.size, GIT_OBJ_TAG) < 0) goto on_error; git_buf_free(&tag); return 0; on_error: git_buf_free(&tag); giterr_set(GITERR_OBJECT, "Failed to create tag annotation."); return -1; } static int git_tag_create__internal( git_oid *oid, git_repository *repo, const char *tag_name, const git_object *target, const git_signature *tagger, const char *message, int allow_ref_overwrite, int create_tag_annotation) { git_reference *new_ref = NULL; git_buf ref_name = GIT_BUF_INIT; int error; assert(repo && tag_name && target); assert(!create_tag_annotation || (tagger && message)); if (git_object_owner(target) != repo) { giterr_set(GITERR_INVALID, "The given target does not belong to this repository"); return -1; } error = retrieve_tag_reference_oid(oid, &ref_name, repo, tag_name); if (error < 0 && error != GIT_ENOTFOUND) goto cleanup; /** Ensure the tag name doesn't conflict with an already existing * reference unless overwriting has explictly been requested **/ if (error == 0 && !allow_ref_overwrite) { git_buf_free(&ref_name); giterr_set(GITERR_TAG, "Tag already exists"); return GIT_EEXISTS; } if (create_tag_annotation) { if (write_tag_annotation(oid, repo, tag_name, target, tagger, message) < 0) return -1; } else git_oid_cpy(oid, git_object_id(target)); error = git_reference_create(&new_ref, repo, ref_name.ptr, oid, allow_ref_overwrite); cleanup: git_reference_free(new_ref); git_buf_free(&ref_name); return error; } int git_tag_create( git_oid *oid, git_repository *repo, const char *tag_name, const git_object *target, const git_signature *tagger, const char *message, int allow_ref_overwrite) { return git_tag_create__internal(oid, repo, tag_name, target, tagger, message, allow_ref_overwrite, 1); } int git_tag_annotation_create( git_oid *oid, git_repository *repo, const char *tag_name, const git_object *target, const git_signature *tagger, const char *message) { assert(oid && repo && tag_name && target && tagger && message); return write_tag_annotation(oid, repo, tag_name, target, tagger, message); } int git_tag_create_lightweight( git_oid *oid, git_repository *repo, const char *tag_name, const git_object *target, int allow_ref_overwrite) { return git_tag_create__internal(oid, repo, tag_name, target, NULL, NULL, allow_ref_overwrite, 0); } int git_tag_create_frombuffer(git_oid *oid, git_repository *repo, const char *buffer, int allow_ref_overwrite) { git_tag tag; int error; git_odb *odb; git_odb_stream *stream; git_odb_object *target_obj; git_reference *new_ref = NULL; git_buf ref_name = GIT_BUF_INIT; assert(oid && buffer); memset(&tag, 0, sizeof(tag)); if (git_repository_odb__weakptr(&odb, repo) < 0) return -1; /* validate the buffer */ if (tag_parse(&tag, buffer, buffer + strlen(buffer)) < 0) return -1; /* validate the target */ if (git_odb_read(&target_obj, odb, &tag.target) < 0) goto on_error; if (tag.type != target_obj->cached.type) { giterr_set(GITERR_TAG, "The type for the given target is invalid"); goto on_error; } error = retrieve_tag_reference_oid(oid, &ref_name, repo, tag.tag_name); if (error < 0 && error != GIT_ENOTFOUND) goto on_error; /* We don't need these objects after this */ git_signature_free(tag.tagger); git__free(tag.tag_name); git__free(tag.message); git_odb_object_free(target_obj); /** Ensure the tag name doesn't conflict with an already existing * reference unless overwriting has explictly been requested **/ if (error == 0 && !allow_ref_overwrite) { giterr_set(GITERR_TAG, "Tag already exists"); return GIT_EEXISTS; } /* write the buffer */ if (git_odb_open_wstream(&stream, odb, strlen(buffer), GIT_OBJ_TAG) < 0) return -1; stream->write(stream, buffer, strlen(buffer)); error = stream->finalize_write(oid, stream); stream->free(stream); if (error < 0) { git_buf_free(&ref_name); return -1; } error = git_reference_create(&new_ref, repo, ref_name.ptr, oid, allow_ref_overwrite); git_reference_free(new_ref); git_buf_free(&ref_name); return error; on_error: git_signature_free(tag.tagger); git__free(tag.tag_name); git__free(tag.message); git_odb_object_free(target_obj); return -1; } int git_tag_delete(git_repository *repo, const char *tag_name) { git_reference *tag_ref; git_buf ref_name = GIT_BUF_INIT; int error; error = retrieve_tag_reference(&tag_ref, &ref_name, repo, tag_name); git_buf_free(&ref_name); if (error < 0) return error; if ((error = git_reference_delete(tag_ref)) == 0) git_reference_free(tag_ref); return error; } typedef struct { git_repository *repo; git_tag_foreach_cb cb; void *cb_data; } tag_cb_data; static int tags_cb(const char *ref, void *data) { git_oid oid; tag_cb_data *d = (tag_cb_data *)data; if (git__prefixcmp(ref, GIT_REFS_TAGS_DIR) != 0) return 0; /* no tag */ if (git_reference_name_to_id(&oid, d->repo, ref) < 0) return -1; return d->cb(ref, &oid, d->cb_data); } int git_tag_foreach(git_repository *repo, git_tag_foreach_cb cb, void *cb_data) { tag_cb_data data; assert(repo && cb); data.cb = cb; data.cb_data = cb_data; data.repo = repo; return git_reference_foreach_name(repo, &tags_cb, &data); } typedef struct { git_vector *taglist; const char *pattern; } tag_filter_data; #define GIT_REFS_TAGS_DIR_LEN strlen(GIT_REFS_TAGS_DIR) static int tag_list_cb(const char *tag_name, git_oid *oid, void *data) { tag_filter_data *filter = (tag_filter_data *)data; GIT_UNUSED(oid); if (!*filter->pattern || p_fnmatch(filter->pattern, tag_name + GIT_REFS_TAGS_DIR_LEN, 0) == 0) return git_vector_insert(filter->taglist, git__strdup(tag_name + GIT_REFS_TAGS_DIR_LEN)); return 0; } int git_tag_list_match(git_strarray *tag_names, const char *pattern, git_repository *repo) { int error; tag_filter_data filter; git_vector taglist; assert(tag_names && repo && pattern); if (git_vector_init(&taglist, 8, NULL) < 0) return -1; filter.taglist = &taglist; filter.pattern = pattern; error = git_tag_foreach(repo, &tag_list_cb, (void *)&filter); if (error < 0) { git_vector_free(&taglist); return -1; } tag_names->strings = (char **)taglist.contents; tag_names->count = taglist.length; return 0; } int git_tag_list(git_strarray *tag_names, git_repository *repo) { return git_tag_list_match(tag_names, "", repo); } int git_tag_peel(git_object **tag_target, const git_tag *tag) { return git_object_peel(tag_target, (const git_object *)tag, GIT_OBJ_ANY); } libgit2-0.19.0/src/tag.h000066400000000000000000000010511216214232500146430ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #ifndef INCLUDE_tag_h__ #define INCLUDE_tag_h__ #include "git2/tag.h" #include "repository.h" #include "odb.h" struct git_tag { git_object object; git_oid target; git_otype type; char *tag_name; git_signature *tagger; char *message; }; void git_tag__free(void *tag); int git_tag__parse(void *tag, git_odb_object *obj); #endif libgit2-0.19.0/src/thread-utils.c000066400000000000000000000023661216214232500165020ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #include "common.h" #include "thread-utils.h" #ifdef _WIN32 # define WIN32_LEAN_AND_MEAN # include #elif defined(hpux) || defined(__hpux) || defined(_hpux) # include #endif /* * By doing this in two steps we can at least get * the function to be somewhat coherent, even * with this disgusting nest of #ifdefs. */ #ifndef _SC_NPROCESSORS_ONLN # ifdef _SC_NPROC_ONLN # define _SC_NPROCESSORS_ONLN _SC_NPROC_ONLN # elif defined _SC_CRAY_NCPU # define _SC_NPROCESSORS_ONLN _SC_CRAY_NCPU # endif #endif int git_online_cpus(void) { #ifdef _SC_NPROCESSORS_ONLN long ncpus; #endif #ifdef _WIN32 SYSTEM_INFO info; GetSystemInfo(&info); if ((int)info.dwNumberOfProcessors > 0) return (int)info.dwNumberOfProcessors; #elif defined(hpux) || defined(__hpux) || defined(_hpux) struct pst_dynamic psd; if (!pstat_getdynamic(&psd, sizeof(psd), (size_t)1, 0)) return (int)psd.psd_proc_cnt; #endif #ifdef _SC_NPROCESSORS_ONLN if ((ncpus = (long)sysconf(_SC_NPROCESSORS_ONLN)) > 0) return (int)ncpus; #endif return 1; } libgit2-0.19.0/src/thread-utils.h000066400000000000000000000116411216214232500165030ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #ifndef INCLUDE_thread_utils_h__ #define INCLUDE_thread_utils_h__ /* Common operations even if threading has been disabled */ typedef struct { #if defined(GIT_WIN32) volatile long val; #else volatile int val; #endif } git_atomic; #ifdef GIT_ARCH_64 typedef struct { #if defined(GIT_WIN32) __int64 val; #else int64_t val; #endif } git_atomic64; typedef git_atomic64 git_atomic_ssize; #define git_atomic_ssize_add git_atomic64_add #else typedef git_atomic git_atomic_ssize; #define git_atomic_ssize_add git_atomic_add #endif GIT_INLINE(void) git_atomic_set(git_atomic *a, int val) { a->val = val; } #ifdef GIT_THREADS #define git_thread pthread_t #define git_thread_create(thread, attr, start_routine, arg) pthread_create(thread, attr, start_routine, arg) #define git_thread_kill(thread) pthread_cancel(thread) #define git_thread_exit(status) pthread_exit(status) #define git_thread_join(id, status) pthread_join(id, status) /* Pthreads Mutex */ #define git_mutex pthread_mutex_t #define git_mutex_init(a) pthread_mutex_init(a, NULL) #define git_mutex_lock(a) pthread_mutex_lock(a) #define git_mutex_unlock(a) pthread_mutex_unlock(a) #define git_mutex_free(a) pthread_mutex_destroy(a) /* Pthreads condition vars */ #define git_cond pthread_cond_t #define git_cond_init(c) pthread_cond_init(c, NULL) #define git_cond_free(c) pthread_cond_destroy(c) #define git_cond_wait(c, l) pthread_cond_wait(c, l) #define git_cond_signal(c) pthread_cond_signal(c) #define git_cond_broadcast(c) pthread_cond_broadcast(c) GIT_INLINE(int) git_atomic_inc(git_atomic *a) { #if defined(GIT_WIN32) return InterlockedIncrement(&a->val); #elif defined(__GNUC__) return __sync_add_and_fetch(&a->val, 1); #else # error "Unsupported architecture for atomic operations" #endif } GIT_INLINE(int) git_atomic_add(git_atomic *a, int32_t addend) { #if defined(GIT_WIN32) return InterlockedExchangeAdd(&a->val, addend); #elif defined(__GNUC__) return __sync_add_and_fetch(&a->val, addend); #else # error "Unsupported architecture for atomic operations" #endif } GIT_INLINE(int) git_atomic_dec(git_atomic *a) { #if defined(GIT_WIN32) return InterlockedDecrement(&a->val); #elif defined(__GNUC__) return __sync_sub_and_fetch(&a->val, 1); #else # error "Unsupported architecture for atomic operations" #endif } GIT_INLINE(void *) git___compare_and_swap( volatile void **ptr, void *oldval, void *newval) { volatile void *foundval; #if defined(GIT_WIN32) foundval = InterlockedCompareExchangePointer(ptr, newval, oldval); #elif defined(__GNUC__) foundval = __sync_val_compare_and_swap(ptr, oldval, newval); #else # error "Unsupported architecture for atomic operations" #endif return (foundval == oldval) ? oldval : newval; } #ifdef GIT_ARCH_64 GIT_INLINE(int64_t) git_atomic64_add(git_atomic64 *a, int64_t addend) { #if defined(GIT_WIN32) return InterlockedExchangeAdd64(&a->val, addend); #elif defined(__GNUC__) return __sync_add_and_fetch(&a->val, addend); #else # error "Unsupported architecture for atomic operations" #endif } #endif #else #define git_thread unsigned int #define git_thread_create(thread, attr, start_routine, arg) (void)0 #define git_thread_kill(thread) (void)0 #define git_thread_exit(status) (void)0 #define git_thread_join(id, status) (void)0 /* Pthreads Mutex */ #define git_mutex unsigned int #define git_mutex_init(a) 0 #define git_mutex_lock(a) 0 #define git_mutex_unlock(a) (void)0 #define git_mutex_free(a) (void)0 /* Pthreads condition vars */ #define git_cond unsigned int #define git_cond_init(c, a) (void)0 #define git_cond_free(c) (void)0 #define git_cond_wait(c, l) (void)0 #define git_cond_signal(c) (void)0 #define git_cond_broadcast(c) (void)0 GIT_INLINE(int) git_atomic_inc(git_atomic *a) { return ++a->val; } GIT_INLINE(int) git_atomic_add(git_atomic *a, int32_t addend) { a->val += addend; return a->val; } GIT_INLINE(int) git_atomic_dec(git_atomic *a) { return --a->val; } GIT_INLINE(void *) git___compare_and_swap( volatile void **ptr, void *oldval, void *newval) { if (*ptr == oldval) *ptr = newval; else oldval = newval; return oldval; } #ifdef GIT_ARCH_64 GIT_INLINE(int64_t) git_atomic64_add(git_atomic64 *a, int64_t addend) { a->val += addend; return a->val; } #endif #endif /* Atomically replace oldval with newval * @return oldval if it was replaced or newval if it was not */ #define git__compare_and_swap(P,O,N) \ git___compare_and_swap((volatile void **)P, O, N) #define git__swap(ptr, val) git__compare_and_swap(&ptr, ptr, val) extern int git_online_cpus(void); #if defined(GIT_THREADS) && defined(GIT_WIN32) # define GIT_MEMORY_BARRIER MemoryBarrier() #elif defined(GIT_THREADS) # define GIT_MEMORY_BARRIER __sync_synchronize() #else # define GIT_MEMORY_BARRIER /* noop */ #endif #endif /* INCLUDE_thread_utils_h__ */ libgit2-0.19.0/src/trace.c000066400000000000000000000014211216214232500151620ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #include "buffer.h" #include "common.h" #include "global.h" #include "trace.h" #include "git2/trace.h" #ifdef GIT_TRACE struct git_trace_data git_trace__data = {0}; #endif int git_trace_set(git_trace_level_t level, git_trace_callback callback) { #ifdef GIT_TRACE assert(level == 0 || callback != NULL); git_trace__data.level = level; git_trace__data.callback = callback; GIT_MEMORY_BARRIER; return 0; #else GIT_UNUSED(level); GIT_UNUSED(callback); giterr_set(GITERR_INVALID, "This version of libgit2 was not built with tracing."); return -1; #endif } libgit2-0.19.0/src/trace.h000066400000000000000000000022171216214232500151730ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #ifndef INCLUDE_trace_h__ #define INCLUDE_trace_h__ #include #include #include "buffer.h" #ifdef GIT_TRACE struct git_trace_data { git_trace_level_t level; git_trace_callback callback; }; extern struct git_trace_data git_trace__data; GIT_INLINE(void) git_trace__write_fmt( git_trace_level_t level, const char *fmt, ...) { git_trace_callback callback = git_trace__data.callback; git_buf message = GIT_BUF_INIT; va_list ap; va_start(ap, fmt); git_buf_vprintf(&message, fmt, ap); va_end(ap); callback(level, git_buf_cstr(&message)); git_buf_free(&message); } #define git_trace_level() (git_trace__data.level) #define git_trace(l, ...) { \ if (git_trace__data.level >= l && \ git_trace__data.callback != NULL) { \ git_trace__write_fmt(l, __VA_ARGS__); \ } \ } #else #define git_trace_level() ((void)0) #define git_trace(lvl, ...) ((void)0) #endif #endif libgit2-0.19.0/src/transport.c000066400000000000000000000106621216214232500161270ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #include "common.h" #include "git2/types.h" #include "git2/remote.h" #include "git2/net.h" #include "git2/transport.h" #include "path.h" typedef struct transport_definition { char *prefix; unsigned priority; git_transport_cb fn; void *param; } transport_definition; static git_smart_subtransport_definition http_subtransport_definition = { git_smart_subtransport_http, 1 }; static git_smart_subtransport_definition git_subtransport_definition = { git_smart_subtransport_git, 0 }; #ifdef GIT_SSH static git_smart_subtransport_definition ssh_subtransport_definition = { git_smart_subtransport_ssh, 0 }; #endif static transport_definition local_transport_definition = { "file://", 1, git_transport_local, NULL }; #ifdef GIT_SSH static transport_definition ssh_transport_definition = { "ssh://", 1, git_transport_smart, &ssh_subtransport_definition }; #else static transport_definition dummy_transport_definition = { NULL, 1, git_transport_dummy, NULL }; #endif static transport_definition transports[] = { {"git://", 1, git_transport_smart, &git_subtransport_definition}, {"http://", 1, git_transport_smart, &http_subtransport_definition}, {"https://", 1, git_transport_smart, &http_subtransport_definition}, {"file://", 1, git_transport_local, NULL}, #ifdef GIT_SSH {"ssh://", 1, git_transport_smart, &ssh_subtransport_definition}, #endif {NULL, 0, 0} }; #define GIT_TRANSPORT_COUNT (sizeof(transports)/sizeof(transports[0])) - 1 static int transport_find_fn(const char *url, git_transport_cb *callback, void **param) { size_t i = 0; unsigned priority = 0; transport_definition *definition = NULL, *definition_iter; // First, check to see if it's an obvious URL, which a URL scheme for (i = 0; i < GIT_TRANSPORT_COUNT; ++i) { definition_iter = &transports[i]; if (strncasecmp(url, definition_iter->prefix, strlen(definition_iter->prefix))) continue; if (definition_iter->priority > priority) definition = definition_iter; } #ifdef GIT_WIN32 /* On Windows, it might not be possible to discern between absolute local * and ssh paths - first check if this is a valid local path that points * to a directory and if so assume local path, else assume SSH */ /* Check to see if the path points to a file on the local file system */ if (!definition && git_path_exists(url) && git_path_isdir(url)) definition = &local_transport_definition; /* It could be a SSH remote path. Check to see if there's a : * SSH is an unsupported transport mechanism in this version of libgit2 */ if (!definition && strrchr(url, ':')) definition = &dummy_transport_definition; #else /* For other systems, perform the SSH check first, to avoid going to the * filesystem if it is not necessary */ /* It could be a SSH remote path. Check to see if there's a : * SSH is an unsupported transport mechanism in this version of libgit2 */ if (!definition && strrchr(url, ':')) #ifdef GIT_SSH definition = &ssh_transport_definition; #else definition = &dummy_transport_definition; #endif /* Check to see if the path points to a file on the local file system */ if (!definition && git_path_exists(url) && git_path_isdir(url)) definition = &local_transport_definition; #endif if (!definition) return -1; *callback = definition->fn; *param = definition->param; return 0; } /************** * Public API * **************/ int git_transport_dummy(git_transport **transport, git_remote *owner, void *param) { GIT_UNUSED(transport); GIT_UNUSED(owner); GIT_UNUSED(param); giterr_set(GITERR_NET, "This transport isn't implemented. Sorry"); return -1; } int git_transport_new(git_transport **out, git_remote *owner, const char *url) { git_transport_cb fn; git_transport *transport; void *param; int error; if (transport_find_fn(url, &fn, ¶m) < 0) { giterr_set(GITERR_NET, "Unsupported URL protocol"); return -1; } error = fn(&transport, owner, param); if (error < 0) return error; *out = transport; return 0; } /* from remote.h */ int git_remote_valid_url(const char *url) { git_transport_cb fn; void *param; return !transport_find_fn(url, &fn, ¶m); } int git_remote_supported_url(const char* url) { git_transport_cb fn; void *param; if (transport_find_fn(url, &fn, ¶m) < 0) return 0; return fn != &git_transport_dummy; } libgit2-0.19.0/src/transports/000077500000000000000000000000001216214232500161415ustar00rootroot00000000000000libgit2-0.19.0/src/transports/cred.c000066400000000000000000000065331216214232500172310ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #include "git2.h" #include "smart.h" #include "git2/cred_helpers.h" static void plaintext_free(struct git_cred *cred) { git_cred_userpass_plaintext *c = (git_cred_userpass_plaintext *)cred; size_t pass_len = strlen(c->password); git__free(c->username); /* Zero the memory which previously held the password */ git__memzero(c->password, pass_len); git__free(c->password); memset(c, 0, sizeof(*c)); git__free(c); } int git_cred_userpass_plaintext_new( git_cred **cred, const char *username, const char *password) { git_cred_userpass_plaintext *c; if (!cred) return -1; c = git__malloc(sizeof(git_cred_userpass_plaintext)); GITERR_CHECK_ALLOC(c); c->parent.credtype = GIT_CREDTYPE_USERPASS_PLAINTEXT; c->parent.free = plaintext_free; c->username = git__strdup(username); if (!c->username) { git__free(c); return -1; } c->password = git__strdup(password); if (!c->password) { git__free(c->username); git__free(c); return -1; } *cred = &c->parent; return 0; } #ifdef GIT_SSH static void ssh_keyfile_passphrase_free(struct git_cred *cred) { git_cred_ssh_keyfile_passphrase *c = (git_cred_ssh_keyfile_passphrase *)cred; size_t pass_len = strlen(c->passphrase); if (c->publickey) { git__free(c->publickey); } git__free(c->privatekey); if (c->passphrase) { /* Zero the memory which previously held the passphrase */ git__memzero(c->passphrase, pass_len); git__free(c->passphrase); } memset(c, 0, sizeof(*c)); git__free(c); } int git_cred_ssh_keyfile_passphrase_new( git_cred **cred, const char *publickey, const char *privatekey, const char *passphrase) { git_cred_ssh_keyfile_passphrase *c; assert(cred && privatekey); c = git__calloc(1, sizeof(git_cred_ssh_keyfile_passphrase)); GITERR_CHECK_ALLOC(c); c->parent.credtype = GIT_CREDTYPE_SSH_KEYFILE_PASSPHRASE; c->parent.free = ssh_keyfile_passphrase_free; c->privatekey = git__strdup(privatekey); GITERR_CHECK_ALLOC(c->privatekey); if (publickey) { c->publickey = git__strdup(publickey); GITERR_CHECK_ALLOC(c->publickey); } if (passphrase) { c->passphrase = git__strdup(passphrase); GITERR_CHECK_ALLOC(c->passphrase); } *cred = &c->parent; return 0; } static void ssh_publickey_free(struct git_cred *cred) { git_cred_ssh_publickey *c = (git_cred_ssh_publickey *)cred; git__free(c->publickey); c->sign_callback = NULL; c->sign_data = NULL; memset(c, 0, sizeof(*c)); git__free(c); } int git_cred_ssh_publickey_new( git_cred **cred, const char *publickey, size_t publickey_len, LIBSSH2_USERAUTH_PUBLICKEY_SIGN_FUNC((*sign_callback)), void *sign_data) { git_cred_ssh_publickey *c; if (!cred) return -1; c = git__malloc(sizeof(git_cred_ssh_publickey)); GITERR_CHECK_ALLOC(c); c->parent.credtype = GIT_CREDTYPE_SSH_PUBLICKEY; c->parent.free = ssh_publickey_free; c->publickey = git__malloc(publickey_len); GITERR_CHECK_ALLOC(c->publickey); memcpy(c->publickey, publickey, publickey_len); c->publickey_len = publickey_len; c->sign_callback = sign_callback; c->sign_data = sign_data; *cred = &c->parent; return 0; } #endif libgit2-0.19.0/src/transports/cred_helpers.c000066400000000000000000000026451216214232500207530ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #include "common.h" #include "git2/cred_helpers.h" int git_cred_userpass( git_cred **cred, const char *url, const char *user_from_url, unsigned int allowed_types, void *payload) { git_cred_userpass_payload *userpass = (git_cred_userpass_payload*)payload; const char *effective_username = NULL; GIT_UNUSED(url); if (!userpass || !userpass->password) return -1; /* Username resolution: a username can be passed with the URL, the * credentials payload, or both. Here's what we do. Note that if we get * this far, we know that any password the url may contain has already * failed at least once, so we ignore it. * * | Payload | URL | Used | * +-------------+----------+-----------+ * | yes | no | payload | * | yes | yes | payload | * | no | yes | url | * | no | no | FAIL | */ if (userpass->username) effective_username = userpass->username; else if (user_from_url) effective_username = user_from_url; else return -1; if ((GIT_CREDTYPE_USERPASS_PLAINTEXT & allowed_types) == 0 || git_cred_userpass_plaintext_new(cred, effective_username, userpass->password) < 0) return -1; return 0; } libgit2-0.19.0/src/transports/git.c000066400000000000000000000153711216214232500170770ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #include "git2.h" #include "buffer.h" #include "netops.h" #define OWNING_SUBTRANSPORT(s) ((git_subtransport *)(s)->parent.subtransport) static const char prefix_git[] = "git://"; static const char cmd_uploadpack[] = "git-upload-pack"; static const char cmd_receivepack[] = "git-receive-pack"; typedef struct { git_smart_subtransport_stream parent; gitno_socket socket; const char *cmd; char *url; unsigned sent_command : 1; } git_stream; typedef struct { git_smart_subtransport parent; git_transport *owner; git_stream *current_stream; } git_subtransport; /* * Create a git protocol request. * * For example: 0035git-upload-pack /libgit2/libgit2\0host=github.com\0 */ static int gen_proto(git_buf *request, const char *cmd, const char *url) { char *delim, *repo; char host[] = "host="; size_t len; delim = strchr(url, '/'); if (delim == NULL) { giterr_set(GITERR_NET, "Malformed URL"); return -1; } repo = delim; delim = strchr(url, ':'); if (delim == NULL) delim = strchr(url, '/'); len = 4 + strlen(cmd) + 1 + strlen(repo) + 1 + strlen(host) + (delim - url) + 1; git_buf_grow(request, len); git_buf_printf(request, "%04x%s %s%c%s", (unsigned int)(len & 0x0FFFF), cmd, repo, 0, host); git_buf_put(request, url, delim - url); git_buf_putc(request, '\0'); if (git_buf_oom(request)) return -1; return 0; } static int send_command(git_stream *s) { int error; git_buf request = GIT_BUF_INIT; error = gen_proto(&request, s->cmd, s->url); if (error < 0) goto cleanup; /* It looks like negative values are errors here, and positive values * are the number of bytes sent. */ error = gitno_send(&s->socket, request.ptr, request.size, 0); if (error >= 0) s->sent_command = 1; cleanup: git_buf_free(&request); return error; } static int git_stream_read( git_smart_subtransport_stream *stream, char *buffer, size_t buf_size, size_t *bytes_read) { git_stream *s = (git_stream *)stream; gitno_buffer buf; *bytes_read = 0; if (!s->sent_command && send_command(s) < 0) return -1; gitno_buffer_setup(&s->socket, &buf, buffer, buf_size); if (gitno_recv(&buf) < 0) return -1; *bytes_read = buf.offset; return 0; } static int git_stream_write( git_smart_subtransport_stream *stream, const char *buffer, size_t len) { git_stream *s = (git_stream *)stream; if (!s->sent_command && send_command(s) < 0) return -1; return gitno_send(&s->socket, buffer, len, 0); } static void git_stream_free(git_smart_subtransport_stream *stream) { git_stream *s = (git_stream *)stream; git_subtransport *t = OWNING_SUBTRANSPORT(s); int ret; GIT_UNUSED(ret); t->current_stream = NULL; if (s->socket.socket) { ret = gitno_close(&s->socket); assert(!ret); } git__free(s->url); git__free(s); } static int git_stream_alloc( git_subtransport *t, const char *url, const char *cmd, git_smart_subtransport_stream **stream) { git_stream *s; if (!stream) return -1; s = git__calloc(sizeof(git_stream), 1); GITERR_CHECK_ALLOC(s); s->parent.subtransport = &t->parent; s->parent.read = git_stream_read; s->parent.write = git_stream_write; s->parent.free = git_stream_free; s->cmd = cmd; s->url = git__strdup(url); if (!s->url) { git__free(s); return -1; } *stream = &s->parent; return 0; } static int _git_uploadpack_ls( git_subtransport *t, const char *url, git_smart_subtransport_stream **stream) { char *host, *port, *user=NULL, *pass=NULL; git_stream *s; *stream = NULL; if (!git__prefixcmp(url, prefix_git)) url += strlen(prefix_git); if (git_stream_alloc(t, url, cmd_uploadpack, stream) < 0) return -1; s = (git_stream *)*stream; if (gitno_extract_url_parts(&host, &port, &user, &pass, url, GIT_DEFAULT_PORT) < 0) goto on_error; if (gitno_connect(&s->socket, host, port, 0) < 0) goto on_error; t->current_stream = s; git__free(host); git__free(port); git__free(user); git__free(pass); return 0; on_error: if (*stream) git_stream_free(*stream); git__free(host); git__free(port); return -1; } static int _git_uploadpack( git_subtransport *t, const char *url, git_smart_subtransport_stream **stream) { GIT_UNUSED(url); if (t->current_stream) { *stream = &t->current_stream->parent; return 0; } giterr_set(GITERR_NET, "Must call UPLOADPACK_LS before UPLOADPACK"); return -1; } static int _git_receivepack_ls( git_subtransport *t, const char *url, git_smart_subtransport_stream **stream) { char *host, *port, *user=NULL, *pass=NULL; git_stream *s; *stream = NULL; if (!git__prefixcmp(url, prefix_git)) url += strlen(prefix_git); if (git_stream_alloc(t, url, cmd_receivepack, stream) < 0) return -1; s = (git_stream *)*stream; if (gitno_extract_url_parts(&host, &port, &user, &pass, url, GIT_DEFAULT_PORT) < 0) goto on_error; if (gitno_connect(&s->socket, host, port, 0) < 0) goto on_error; t->current_stream = s; git__free(host); git__free(port); git__free(user); git__free(pass); return 0; on_error: if (*stream) git_stream_free(*stream); git__free(host); git__free(port); return -1; } static int _git_receivepack( git_subtransport *t, const char *url, git_smart_subtransport_stream **stream) { GIT_UNUSED(url); if (t->current_stream) { *stream = &t->current_stream->parent; return 0; } giterr_set(GITERR_NET, "Must call RECEIVEPACK_LS before RECEIVEPACK"); return -1; } static int _git_action( git_smart_subtransport_stream **stream, git_smart_subtransport *subtransport, const char *url, git_smart_service_t action) { git_subtransport *t = (git_subtransport *) subtransport; switch (action) { case GIT_SERVICE_UPLOADPACK_LS: return _git_uploadpack_ls(t, url, stream); case GIT_SERVICE_UPLOADPACK: return _git_uploadpack(t, url, stream); case GIT_SERVICE_RECEIVEPACK_LS: return _git_receivepack_ls(t, url, stream); case GIT_SERVICE_RECEIVEPACK: return _git_receivepack(t, url, stream); } *stream = NULL; return -1; } static int _git_close(git_smart_subtransport *subtransport) { git_subtransport *t = (git_subtransport *) subtransport; assert(!t->current_stream); GIT_UNUSED(t); return 0; } static void _git_free(git_smart_subtransport *subtransport) { git_subtransport *t = (git_subtransport *) subtransport; assert(!t->current_stream); git__free(t); } int git_smart_subtransport_git(git_smart_subtransport **out, git_transport *owner) { git_subtransport *t; if (!out) return -1; t = git__calloc(sizeof(git_subtransport), 1); GITERR_CHECK_ALLOC(t); t->owner = owner; t->parent.action = _git_action; t->parent.close = _git_close; t->parent.free = _git_free; *out = (git_smart_subtransport *) t; return 0; } libgit2-0.19.0/src/transports/http.c000066400000000000000000000516461216214232500173000ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #ifndef GIT_WINHTTP #include "git2.h" #include "http_parser.h" #include "buffer.h" #include "netops.h" #include "smart.h" static const char *prefix_http = "http://"; static const char *prefix_https = "https://"; static const char *upload_pack_service = "upload-pack"; static const char *upload_pack_ls_service_url = "/info/refs?service=git-upload-pack"; static const char *upload_pack_service_url = "/git-upload-pack"; static const char *receive_pack_service = "receive-pack"; static const char *receive_pack_ls_service_url = "/info/refs?service=git-receive-pack"; static const char *receive_pack_service_url = "/git-receive-pack"; static const char *get_verb = "GET"; static const char *post_verb = "POST"; static const char *basic_authtype = "Basic"; #define OWNING_SUBTRANSPORT(s) ((http_subtransport *)(s)->parent.subtransport) #define PARSE_ERROR_GENERIC -1 #define PARSE_ERROR_REPLAY -2 #define CHUNK_SIZE 4096 enum last_cb { NONE, FIELD, VALUE }; typedef enum { GIT_HTTP_AUTH_BASIC = 1, } http_authmechanism_t; typedef struct { git_smart_subtransport_stream parent; const char *service; const char *service_url; char *redirect_url; const char *verb; char *chunk_buffer; unsigned chunk_buffer_len; unsigned sent_request : 1, received_response : 1, chunked : 1, redirect_count : 3; } http_stream; typedef struct { git_smart_subtransport parent; transport_smart *owner; gitno_socket socket; const char *path; char *host; char *port; char *user_from_url; char *pass_from_url; git_cred *cred; git_cred *url_cred; http_authmechanism_t auth_mechanism; unsigned connected : 1, use_ssl : 1; /* Parser structures */ http_parser parser; http_parser_settings settings; gitno_buffer parse_buffer; git_buf parse_header_name; git_buf parse_header_value; char parse_buffer_data[2048]; char *content_type; char *location; git_vector www_authenticate; enum last_cb last_cb; int parse_error; unsigned parse_finished : 1; } http_subtransport; typedef struct { http_stream *s; http_subtransport *t; /* Target buffer details from read() */ char *buffer; size_t buf_size; size_t *bytes_read; } parser_context; static int apply_basic_credential(git_buf *buf, git_cred *cred) { git_cred_userpass_plaintext *c = (git_cred_userpass_plaintext *)cred; git_buf raw = GIT_BUF_INIT; int error = -1; git_buf_printf(&raw, "%s:%s", c->username, c->password); if (git_buf_oom(&raw) || git_buf_puts(buf, "Authorization: Basic ") < 0 || git_buf_put_base64(buf, git_buf_cstr(&raw), raw.size) < 0 || git_buf_puts(buf, "\r\n") < 0) goto on_error; error = 0; on_error: if (raw.size) memset(raw.ptr, 0x0, raw.size); git_buf_free(&raw); return error; } static int gen_request( git_buf *buf, http_stream *s, size_t content_length) { http_subtransport *t = OWNING_SUBTRANSPORT(s); if (!t->path) t->path = "/"; /* If we were redirected, make sure to respect that here */ if (s->redirect_url) git_buf_printf(buf, "%s %s HTTP/1.1\r\n", s->verb, s->redirect_url); else git_buf_printf(buf, "%s %s%s HTTP/1.1\r\n", s->verb, t->path, s->service_url); git_buf_puts(buf, "User-Agent: git/1.0 (libgit2 " LIBGIT2_VERSION ")\r\n"); git_buf_printf(buf, "Host: %s\r\n", t->host); if (s->chunked || content_length > 0) { git_buf_printf(buf, "Accept: application/x-git-%s-result\r\n", s->service); git_buf_printf(buf, "Content-Type: application/x-git-%s-request\r\n", s->service); if (s->chunked) git_buf_puts(buf, "Transfer-Encoding: chunked\r\n"); else git_buf_printf(buf, "Content-Length: %"PRIuZ "\r\n", content_length); } else git_buf_puts(buf, "Accept: */*\r\n"); /* Apply credentials to the request */ if (t->cred && t->cred->credtype == GIT_CREDTYPE_USERPASS_PLAINTEXT && t->auth_mechanism == GIT_HTTP_AUTH_BASIC && apply_basic_credential(buf, t->cred) < 0) return -1; /* Use url-parsed basic auth if username and password are both provided */ if (!t->cred && t->user_from_url && t->pass_from_url) { if (!t->url_cred && git_cred_userpass_plaintext_new(&t->url_cred, t->user_from_url, t->pass_from_url) < 0) return -1; if (apply_basic_credential(buf, t->url_cred) < 0) return -1; } git_buf_puts(buf, "\r\n"); if (git_buf_oom(buf)) return -1; return 0; } static int parse_unauthorized_response( git_vector *www_authenticate, int *allowed_types, http_authmechanism_t *auth_mechanism) { unsigned i; char *entry; git_vector_foreach(www_authenticate, i, entry) { if (!strncmp(entry, basic_authtype, 5) && (entry[5] == '\0' || entry[5] == ' ')) { *allowed_types |= GIT_CREDTYPE_USERPASS_PLAINTEXT; *auth_mechanism = GIT_HTTP_AUTH_BASIC; } } return 0; } static int on_header_ready(http_subtransport *t) { git_buf *name = &t->parse_header_name; git_buf *value = &t->parse_header_value; if (!strcasecmp("Content-Type", git_buf_cstr(name))) { if (!t->content_type) { t->content_type = git__strdup(git_buf_cstr(value)); GITERR_CHECK_ALLOC(t->content_type); } } else if (!strcmp("WWW-Authenticate", git_buf_cstr(name))) { char *dup = git__strdup(git_buf_cstr(value)); GITERR_CHECK_ALLOC(dup); git_vector_insert(&t->www_authenticate, dup); } else if (!strcasecmp("Location", git_buf_cstr(name))) { if (!t->location) { t->location= git__strdup(git_buf_cstr(value)); GITERR_CHECK_ALLOC(t->location); } } return 0; } static int on_header_field(http_parser *parser, const char *str, size_t len) { parser_context *ctx = (parser_context *) parser->data; http_subtransport *t = ctx->t; /* Both parse_header_name and parse_header_value are populated * and ready for consumption */ if (VALUE == t->last_cb) if (on_header_ready(t) < 0) return t->parse_error = PARSE_ERROR_GENERIC; if (NONE == t->last_cb || VALUE == t->last_cb) git_buf_clear(&t->parse_header_name); if (git_buf_put(&t->parse_header_name, str, len) < 0) return t->parse_error = PARSE_ERROR_GENERIC; t->last_cb = FIELD; return 0; } static int on_header_value(http_parser *parser, const char *str, size_t len) { parser_context *ctx = (parser_context *) parser->data; http_subtransport *t = ctx->t; assert(NONE != t->last_cb); if (FIELD == t->last_cb) git_buf_clear(&t->parse_header_value); if (git_buf_put(&t->parse_header_value, str, len) < 0) return t->parse_error = PARSE_ERROR_GENERIC; t->last_cb = VALUE; return 0; } static int on_headers_complete(http_parser *parser) { parser_context *ctx = (parser_context *) parser->data; http_subtransport *t = ctx->t; http_stream *s = ctx->s; git_buf buf = GIT_BUF_INIT; /* Both parse_header_name and parse_header_value are populated * and ready for consumption. */ if (VALUE == t->last_cb) if (on_header_ready(t) < 0) return t->parse_error = PARSE_ERROR_GENERIC; /* Check for an authentication failure. */ if (parser->status_code == 401 && get_verb == s->verb && t->owner->cred_acquire_cb) { int allowed_types = 0; if (parse_unauthorized_response(&t->www_authenticate, &allowed_types, &t->auth_mechanism) < 0) return t->parse_error = PARSE_ERROR_GENERIC; if (allowed_types && (!t->cred || 0 == (t->cred->credtype & allowed_types))) { if (t->owner->cred_acquire_cb(&t->cred, t->owner->url, t->user_from_url, allowed_types, t->owner->cred_acquire_payload) < 0) return PARSE_ERROR_GENERIC; assert(t->cred); /* Successfully acquired a credential. */ return t->parse_error = PARSE_ERROR_REPLAY; } } /* Check for a redirect. * Right now we only permit a redirect to the same hostname. */ if ((parser->status_code == 301 || parser->status_code == 302 || (parser->status_code == 303 && get_verb == s->verb) || parser->status_code == 307) && t->location) { if (s->redirect_count >= 7) { giterr_set(GITERR_NET, "Too many redirects"); return t->parse_error = PARSE_ERROR_GENERIC; } if (t->location[0] != '/') { giterr_set(GITERR_NET, "Only relative redirects are supported"); return t->parse_error = PARSE_ERROR_GENERIC; } /* Set the redirect URL on the stream. This is a transfer of * ownership of the memory. */ if (s->redirect_url) git__free(s->redirect_url); s->redirect_url = t->location; t->location = NULL; t->connected = 0; s->redirect_count++; return t->parse_error = PARSE_ERROR_REPLAY; } /* Check for a 200 HTTP status code. */ if (parser->status_code != 200) { giterr_set(GITERR_NET, "Unexpected HTTP status code: %d", parser->status_code); return t->parse_error = PARSE_ERROR_GENERIC; } /* The response must contain a Content-Type header. */ if (!t->content_type) { giterr_set(GITERR_NET, "No Content-Type header in response"); return t->parse_error = PARSE_ERROR_GENERIC; } /* The Content-Type header must match our expectation. */ if (get_verb == s->verb) git_buf_printf(&buf, "application/x-git-%s-advertisement", ctx->s->service); else git_buf_printf(&buf, "application/x-git-%s-result", ctx->s->service); if (git_buf_oom(&buf)) return t->parse_error = PARSE_ERROR_GENERIC; if (strcmp(t->content_type, git_buf_cstr(&buf))) { git_buf_free(&buf); giterr_set(GITERR_NET, "Invalid Content-Type: %s", t->content_type); return t->parse_error = PARSE_ERROR_GENERIC; } git_buf_free(&buf); return 0; } static int on_message_complete(http_parser *parser) { parser_context *ctx = (parser_context *) parser->data; http_subtransport *t = ctx->t; t->parse_finished = 1; return 0; } static int on_body_fill_buffer(http_parser *parser, const char *str, size_t len) { parser_context *ctx = (parser_context *) parser->data; http_subtransport *t = ctx->t; if (ctx->buf_size < len) { giterr_set(GITERR_NET, "Can't fit data in the buffer"); return t->parse_error = PARSE_ERROR_GENERIC; } memcpy(ctx->buffer, str, len); *(ctx->bytes_read) += len; ctx->buffer += len; ctx->buf_size -= len; return 0; } static void clear_parser_state(http_subtransport *t) { unsigned i; char *entry; http_parser_init(&t->parser, HTTP_RESPONSE); gitno_buffer_setup(&t->socket, &t->parse_buffer, t->parse_buffer_data, sizeof(t->parse_buffer_data)); t->last_cb = NONE; t->parse_error = 0; t->parse_finished = 0; git_buf_free(&t->parse_header_name); git_buf_init(&t->parse_header_name, 0); git_buf_free(&t->parse_header_value); git_buf_init(&t->parse_header_value, 0); git__free(t->content_type); t->content_type = NULL; git__free(t->location); t->location = NULL; git_vector_foreach(&t->www_authenticate, i, entry) git__free(entry); git_vector_free(&t->www_authenticate); } static int write_chunk(gitno_socket *socket, const char *buffer, size_t len) { git_buf buf = GIT_BUF_INIT; /* Chunk header */ git_buf_printf(&buf, "%X\r\n", (unsigned)len); if (git_buf_oom(&buf)) return -1; if (gitno_send(socket, buf.ptr, buf.size, 0) < 0) { git_buf_free(&buf); return -1; } git_buf_free(&buf); /* Chunk body */ if (len > 0 && gitno_send(socket, buffer, len, 0) < 0) return -1; /* Chunk footer */ if (gitno_send(socket, "\r\n", 2, 0) < 0) return -1; return 0; } static int http_connect(http_subtransport *t) { int flags = 0; if (t->connected && http_should_keep_alive(&t->parser) && http_body_is_final(&t->parser)) return 0; if (t->socket.socket) gitno_close(&t->socket); if (t->use_ssl) { int tflags; if (t->owner->parent.read_flags(&t->owner->parent, &tflags) < 0) return -1; flags |= GITNO_CONNECT_SSL; if (GIT_TRANSPORTFLAGS_NO_CHECK_CERT & tflags) flags |= GITNO_CONNECT_SSL_NO_CHECK_CERT; } if (gitno_connect(&t->socket, t->host, t->port, flags) < 0) return -1; t->connected = 1; return 0; } static int http_stream_read( git_smart_subtransport_stream *stream, char *buffer, size_t buf_size, size_t *bytes_read) { http_stream *s = (http_stream *)stream; http_subtransport *t = OWNING_SUBTRANSPORT(s); parser_context ctx; size_t bytes_parsed; replay: *bytes_read = 0; assert(t->connected); if (!s->sent_request) { git_buf request = GIT_BUF_INIT; clear_parser_state(t); if (gen_request(&request, s, 0) < 0) { giterr_set(GITERR_NET, "Failed to generate request"); return -1; } if (gitno_send(&t->socket, request.ptr, request.size, 0) < 0) { git_buf_free(&request); return -1; } git_buf_free(&request); s->sent_request = 1; } if (!s->received_response) { if (s->chunked) { assert(s->verb == post_verb); /* Flush, if necessary */ if (s->chunk_buffer_len > 0 && write_chunk(&t->socket, s->chunk_buffer, s->chunk_buffer_len) < 0) return -1; s->chunk_buffer_len = 0; /* Write the final chunk. */ if (gitno_send(&t->socket, "0\r\n\r\n", 5, 0) < 0) return -1; } s->received_response = 1; } while (!*bytes_read && !t->parse_finished) { t->parse_buffer.offset = 0; if (gitno_recv(&t->parse_buffer) < 0) return -1; /* This call to http_parser_execute will result in invocations of the * on_* family of callbacks. The most interesting of these is * on_body_fill_buffer, which is called when data is ready to be copied * into the target buffer. We need to marshal the buffer, buf_size, and * bytes_read parameters to this callback. */ ctx.t = t; ctx.s = s; ctx.buffer = buffer; ctx.buf_size = buf_size; ctx.bytes_read = bytes_read; /* Set the context, call the parser, then unset the context. */ t->parser.data = &ctx; bytes_parsed = http_parser_execute(&t->parser, &t->settings, t->parse_buffer.data, t->parse_buffer.offset); t->parser.data = NULL; /* If there was a handled authentication failure, then parse_error * will have signaled us that we should replay the request. */ if (PARSE_ERROR_REPLAY == t->parse_error) { s->sent_request = 0; if (http_connect(t) < 0) return -1; goto replay; } if (t->parse_error < 0) return -1; if (bytes_parsed != t->parse_buffer.offset) { giterr_set(GITERR_NET, "HTTP parser error: %s", http_errno_description((enum http_errno)t->parser.http_errno)); return -1; } } return 0; } static int http_stream_write_chunked( git_smart_subtransport_stream *stream, const char *buffer, size_t len) { http_stream *s = (http_stream *)stream; http_subtransport *t = OWNING_SUBTRANSPORT(s); assert(t->connected); /* Send the request, if necessary */ if (!s->sent_request) { git_buf request = GIT_BUF_INIT; clear_parser_state(t); if (gen_request(&request, s, 0) < 0) { giterr_set(GITERR_NET, "Failed to generate request"); return -1; } if (gitno_send(&t->socket, request.ptr, request.size, 0) < 0) { git_buf_free(&request); return -1; } git_buf_free(&request); s->sent_request = 1; } if (len > CHUNK_SIZE) { /* Flush, if necessary */ if (s->chunk_buffer_len > 0) { if (write_chunk(&t->socket, s->chunk_buffer, s->chunk_buffer_len) < 0) return -1; s->chunk_buffer_len = 0; } /* Write chunk directly */ if (write_chunk(&t->socket, buffer, len) < 0) return -1; } else { /* Append as much to the buffer as we can */ int count = min(CHUNK_SIZE - s->chunk_buffer_len, len); if (!s->chunk_buffer) s->chunk_buffer = git__malloc(CHUNK_SIZE); memcpy(s->chunk_buffer + s->chunk_buffer_len, buffer, count); s->chunk_buffer_len += count; buffer += count; len -= count; /* Is the buffer full? If so, then flush */ if (CHUNK_SIZE == s->chunk_buffer_len) { if (write_chunk(&t->socket, s->chunk_buffer, s->chunk_buffer_len) < 0) return -1; s->chunk_buffer_len = 0; if (len > 0) { memcpy(s->chunk_buffer, buffer, len); s->chunk_buffer_len = len; } } } return 0; } static int http_stream_write_single( git_smart_subtransport_stream *stream, const char *buffer, size_t len) { http_stream *s = (http_stream *)stream; http_subtransport *t = OWNING_SUBTRANSPORT(s); git_buf request = GIT_BUF_INIT; assert(t->connected); if (s->sent_request) { giterr_set(GITERR_NET, "Subtransport configured for only one write"); return -1; } clear_parser_state(t); if (gen_request(&request, s, len) < 0) { giterr_set(GITERR_NET, "Failed to generate request"); return -1; } if (gitno_send(&t->socket, request.ptr, request.size, 0) < 0) goto on_error; if (len && gitno_send(&t->socket, buffer, len, 0) < 0) goto on_error; git_buf_free(&request); s->sent_request = 1; return 0; on_error: git_buf_free(&request); return -1; } static void http_stream_free(git_smart_subtransport_stream *stream) { http_stream *s = (http_stream *)stream; if (s->chunk_buffer) git__free(s->chunk_buffer); if (s->redirect_url) git__free(s->redirect_url); git__free(s); } static int http_stream_alloc(http_subtransport *t, git_smart_subtransport_stream **stream) { http_stream *s; if (!stream) return -1; s = git__calloc(sizeof(http_stream), 1); GITERR_CHECK_ALLOC(s); s->parent.subtransport = &t->parent; s->parent.read = http_stream_read; s->parent.write = http_stream_write_single; s->parent.free = http_stream_free; *stream = (git_smart_subtransport_stream *)s; return 0; } static int http_uploadpack_ls( http_subtransport *t, git_smart_subtransport_stream **stream) { http_stream *s; if (http_stream_alloc(t, stream) < 0) return -1; s = (http_stream *)*stream; s->service = upload_pack_service; s->service_url = upload_pack_ls_service_url; s->verb = get_verb; return 0; } static int http_uploadpack( http_subtransport *t, git_smart_subtransport_stream **stream) { http_stream *s; if (http_stream_alloc(t, stream) < 0) return -1; s = (http_stream *)*stream; s->service = upload_pack_service; s->service_url = upload_pack_service_url; s->verb = post_verb; return 0; } static int http_receivepack_ls( http_subtransport *t, git_smart_subtransport_stream **stream) { http_stream *s; if (http_stream_alloc(t, stream) < 0) return -1; s = (http_stream *)*stream; s->service = receive_pack_service; s->service_url = receive_pack_ls_service_url; s->verb = get_verb; return 0; } static int http_receivepack( http_subtransport *t, git_smart_subtransport_stream **stream) { http_stream *s; if (http_stream_alloc(t, stream) < 0) return -1; s = (http_stream *)*stream; /* Use Transfer-Encoding: chunked for this request */ s->chunked = 1; s->parent.write = http_stream_write_chunked; s->service = receive_pack_service; s->service_url = receive_pack_service_url; s->verb = post_verb; return 0; } static int http_action( git_smart_subtransport_stream **stream, git_smart_subtransport *subtransport, const char *url, git_smart_service_t action) { http_subtransport *t = (http_subtransport *)subtransport; const char *default_port = NULL; int ret; if (!stream) return -1; if (!t->host || !t->port || !t->path) { if (!git__prefixcmp(url, prefix_http)) { url = url + strlen(prefix_http); default_port = "80"; } if (!git__prefixcmp(url, prefix_https)) { url += strlen(prefix_https); default_port = "443"; t->use_ssl = 1; } if (!default_port) return -1; if ((ret = gitno_extract_url_parts(&t->host, &t->port, &t->user_from_url, &t->pass_from_url, url, default_port)) < 0) return ret; t->path = strchr(url, '/'); } if (http_connect(t) < 0) return -1; switch (action) { case GIT_SERVICE_UPLOADPACK_LS: return http_uploadpack_ls(t, stream); case GIT_SERVICE_UPLOADPACK: return http_uploadpack(t, stream); case GIT_SERVICE_RECEIVEPACK_LS: return http_receivepack_ls(t, stream); case GIT_SERVICE_RECEIVEPACK: return http_receivepack(t, stream); } *stream = NULL; return -1; } static int http_close(git_smart_subtransport *subtransport) { http_subtransport *t = (http_subtransport *) subtransport; clear_parser_state(t); if (t->socket.socket) { gitno_close(&t->socket); memset(&t->socket, 0x0, sizeof(gitno_socket)); } if (t->cred) { t->cred->free(t->cred); t->cred = NULL; } if (t->url_cred) { t->url_cred->free(t->url_cred); t->url_cred = NULL; } if (t->host) { git__free(t->host); t->host = NULL; } if (t->port) { git__free(t->port); t->port = NULL; } if (t->user_from_url) { git__free(t->user_from_url); t->user_from_url = NULL; } if (t->pass_from_url) { git__free(t->pass_from_url); t->pass_from_url = NULL; } return 0; } static void http_free(git_smart_subtransport *subtransport) { http_subtransport *t = (http_subtransport *) subtransport; http_close(subtransport); git__free(t); } int git_smart_subtransport_http(git_smart_subtransport **out, git_transport *owner) { http_subtransport *t; if (!out) return -1; t = git__calloc(sizeof(http_subtransport), 1); GITERR_CHECK_ALLOC(t); t->owner = (transport_smart *)owner; t->parent.action = http_action; t->parent.close = http_close; t->parent.free = http_free; t->settings.on_header_field = on_header_field; t->settings.on_header_value = on_header_value; t->settings.on_headers_complete = on_headers_complete; t->settings.on_body = on_body_fill_buffer; t->settings.on_message_complete = on_message_complete; *out = (git_smart_subtransport *) t; return 0; } #endif /* !GIT_WINHTTP */ libgit2-0.19.0/src/transports/local.c000066400000000000000000000346751216214232500174160ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #include "common.h" #include "git2/types.h" #include "git2/net.h" #include "git2/repository.h" #include "git2/object.h" #include "git2/tag.h" #include "git2/transport.h" #include "git2/revwalk.h" #include "git2/odb_backend.h" #include "git2/pack.h" #include "git2/commit.h" #include "git2/revparse.h" #include "git2/push.h" #include "pack-objects.h" #include "refs.h" #include "posix.h" #include "path.h" #include "buffer.h" #include "repository.h" #include "odb.h" #include "push.h" #include "remote.h" typedef struct { git_transport parent; git_remote *owner; char *url; int direction; int flags; git_atomic cancelled; git_repository *repo; git_vector refs; unsigned connected : 1, have_refs : 1; } transport_local; static int add_ref(transport_local *t, const char *name) { const char peeled[] = "^{}"; git_remote_head *head; git_object *obj = NULL, *target = NULL; git_buf buf = GIT_BUF_INIT; int error; head = git__calloc(1, sizeof(git_remote_head)); GITERR_CHECK_ALLOC(head); head->name = git__strdup(name); GITERR_CHECK_ALLOC(head->name); error = git_reference_name_to_id(&head->oid, t->repo, name); if (error < 0) { git__free(head->name); git__free(head); if (!strcmp(name, GIT_HEAD_FILE) && error == GIT_ENOTFOUND) { /* This is actually okay. Empty repos often have a HEAD that points to * a nonexistent "refs/heads/master". */ giterr_clear(); return 0; } return error; } if (git_vector_insert(&t->refs, head) < 0) { git__free(head->name); git__free(head); return -1; } /* If it's not a tag, we don't need to try to peel it */ if (git__prefixcmp(name, GIT_REFS_TAGS_DIR)) return 0; if (git_object_lookup(&obj, t->repo, &head->oid, GIT_OBJ_ANY) < 0) return -1; head = NULL; /* If it's not an annotated tag, or if we're mocking * git-receive-pack, just get out */ if (git_object_type(obj) != GIT_OBJ_TAG || t->direction != GIT_DIRECTION_FETCH) { git_object_free(obj); return 0; } /* And if it's a tag, peel it, and add it to the list */ head = git__calloc(1, sizeof(git_remote_head)); GITERR_CHECK_ALLOC(head); if (git_buf_join(&buf, 0, name, peeled) < 0) return -1; head->name = git_buf_detach(&buf); if (git_tag_peel(&target, (git_tag *) obj) < 0) goto on_error; git_oid_cpy(&head->oid, git_object_id(target)); git_object_free(obj); git_object_free(target); if (git_vector_insert(&t->refs, head) < 0) return -1; return 0; on_error: git_object_free(obj); git_object_free(target); return -1; } static int store_refs(transport_local *t) { unsigned int i; git_strarray ref_names = {0}; assert(t); if (git_reference_list(&ref_names, t->repo) < 0 || git_vector_init(&t->refs, ref_names.count, NULL) < 0) goto on_error; /* Sort the references first */ git__tsort((void **)ref_names.strings, ref_names.count, &git__strcmp_cb); /* Add HEAD iff direction is fetch */ if (t->direction == GIT_DIRECTION_FETCH && add_ref(t, GIT_HEAD_FILE) < 0) goto on_error; for (i = 0; i < ref_names.count; ++i) { if (add_ref(t, ref_names.strings[i]) < 0) goto on_error; } t->have_refs = 1; git_strarray_free(&ref_names); return 0; on_error: git_vector_free(&t->refs); git_strarray_free(&ref_names); return -1; } /* * Try to open the url as a git directory. The direction doesn't * matter in this case because we're calulating the heads ourselves. */ static int local_connect( git_transport *transport, const char *url, git_cred_acquire_cb cred_acquire_cb, void *cred_acquire_payload, int direction, int flags) { git_repository *repo; int error; transport_local *t = (transport_local *) transport; const char *path; git_buf buf = GIT_BUF_INIT; GIT_UNUSED(cred_acquire_cb); GIT_UNUSED(cred_acquire_payload); t->url = git__strdup(url); GITERR_CHECK_ALLOC(t->url); t->direction = direction; t->flags = flags; /* The repo layer doesn't want the prefix */ if (!git__prefixcmp(t->url, "file://")) { if (git_path_fromurl(&buf, t->url) < 0) { git_buf_free(&buf); return -1; } path = git_buf_cstr(&buf); } else { /* We assume transport->url is already a path */ path = t->url; } error = git_repository_open(&repo, path); git_buf_free(&buf); if (error < 0) return -1; t->repo = repo; if (store_refs(t) < 0) return -1; t->connected = 1; return 0; } static int local_ls(git_transport *transport, git_headlist_cb list_cb, void *payload) { transport_local *t = (transport_local *)transport; unsigned int i; git_remote_head *head = NULL; if (!t->have_refs) { giterr_set(GITERR_NET, "The transport has not yet loaded the refs"); return -1; } git_vector_foreach(&t->refs, i, head) { if (list_cb(head, payload)) return GIT_EUSER; } return 0; } static int local_negotiate_fetch( git_transport *transport, git_repository *repo, const git_remote_head * const *refs, size_t count) { transport_local *t = (transport_local*)transport; git_remote_head *rhead; unsigned int i; GIT_UNUSED(refs); GIT_UNUSED(count); /* Fill in the loids */ git_vector_foreach(&t->refs, i, rhead) { git_object *obj; int error = git_revparse_single(&obj, repo, rhead->name); if (!error) git_oid_cpy(&rhead->loid, git_object_id(obj)); else if (error != GIT_ENOTFOUND) return error; git_object_free(obj); giterr_clear(); } return 0; } static int local_push_copy_object( git_odb *local_odb, git_odb *remote_odb, git_pobject *obj) { int error = 0; git_odb_object *odb_obj = NULL; git_odb_stream *odb_stream; size_t odb_obj_size; git_otype odb_obj_type; git_oid remote_odb_obj_oid; /* Object already exists in the remote ODB; do nothing and return 0*/ if (git_odb_exists(remote_odb, &obj->id)) return 0; if ((error = git_odb_read(&odb_obj, local_odb, &obj->id)) < 0) return error; odb_obj_size = git_odb_object_size(odb_obj); odb_obj_type = git_odb_object_type(odb_obj); if ((error = git_odb_open_wstream(&odb_stream, remote_odb, odb_obj_size, odb_obj_type)) < 0) goto on_error; if (odb_stream->write(odb_stream, (char *)git_odb_object_data(odb_obj), odb_obj_size) < 0 || odb_stream->finalize_write(&remote_odb_obj_oid, odb_stream) < 0) { error = -1; } else if (git_oid__cmp(&obj->id, &remote_odb_obj_oid) != 0) { giterr_set(GITERR_ODB, "Error when writing object to remote odb " "during local push operation. Remote odb object oid does not " "match local oid."); error = -1; } odb_stream->free(odb_stream); on_error: git_odb_object_free(odb_obj); return error; } static int local_push_update_remote_ref( git_repository *remote_repo, const char *lref, const char *rref, git_oid *loid, git_oid *roid) { int error; git_reference *remote_ref = NULL; /* rref will be NULL if it is implicit in the pushspec (e.g. 'b1:') */ rref = rref ? rref : lref; if (lref) { /* Create or update a ref */ if ((error = git_reference_create(NULL, remote_repo, rref, loid, !git_oid_iszero(roid))) < 0) return error; } else { /* Delete a ref */ if ((error = git_reference_lookup(&remote_ref, remote_repo, rref)) < 0) { if (error == GIT_ENOTFOUND) error = 0; return error; } if ((error = git_reference_delete(remote_ref)) < 0) return error; git_reference_free(remote_ref); } return 0; } static int local_push( git_transport *transport, git_push *push) { transport_local *t = (transport_local *)transport; git_odb *remote_odb = NULL; git_odb *local_odb = NULL; git_repository *remote_repo = NULL; push_spec *spec; char *url = NULL; int error; unsigned int i; size_t j; if ((error = git_repository_open(&remote_repo, push->remote->url)) < 0) return error; /* We don't currently support pushing locally to non-bare repos. Proper non-bare repo push support would require checking configs to see if we should override the default 'don't let this happen' behavior */ if (!remote_repo->is_bare) { error = -1; goto on_error; } if ((error = git_repository_odb__weakptr(&remote_odb, remote_repo)) < 0 || (error = git_repository_odb__weakptr(&local_odb, push->repo)) < 0) goto on_error; for (i = 0; i < push->pb->nr_objects; i++) { if ((error = local_push_copy_object(local_odb, remote_odb, &push->pb->object_list[i])) < 0) goto on_error; } push->unpack_ok = 1; git_vector_foreach(&push->specs, j, spec) { push_status *status; const git_error *last; char *ref = spec->rref ? spec->rref : spec->lref; status = git__calloc(sizeof(push_status), 1); if (!status) goto on_error; status->ref = git__strdup(ref); if (!status->ref) { git_push_status_free(status); goto on_error; } error = local_push_update_remote_ref(remote_repo, spec->lref, spec->rref, &spec->loid, &spec->roid); switch (error) { case GIT_OK: break; case GIT_EINVALIDSPEC: status->msg = git__strdup("funny refname"); break; case GIT_ENOTFOUND: status->msg = git__strdup("Remote branch not found to delete"); break; default: last = giterr_last(); if (last && last->message) status->msg = git__strdup(last->message); else status->msg = git__strdup("Unspecified error encountered"); break; } /* failed to allocate memory for a status message */ if (error < 0 && !status->msg) { git_push_status_free(status); goto on_error; } /* failed to insert the ref update status */ if ((error = git_vector_insert(&push->status, status)) < 0) { git_push_status_free(status); goto on_error; } } if (push->specs.length) { int flags = t->flags; url = git__strdup(t->url); if (!url || t->parent.close(&t->parent) < 0 || t->parent.connect(&t->parent, url, push->remote->cred_acquire_cb, NULL, GIT_DIRECTION_PUSH, flags)) goto on_error; } error = 0; on_error: git_repository_free(remote_repo); git__free(url); return error; } typedef struct foreach_data { git_transfer_progress *stats; git_transfer_progress_callback progress_cb; void *progress_payload; git_odb_writepack *writepack; } foreach_data; static int foreach_cb(void *buf, size_t len, void *payload) { foreach_data *data = (foreach_data*)payload; data->stats->received_bytes += len; return data->writepack->add(data->writepack, buf, len, data->stats); } static int local_download_pack( git_transport *transport, git_repository *repo, git_transfer_progress *stats, git_transfer_progress_callback progress_cb, void *progress_payload) { transport_local *t = (transport_local*)transport; git_revwalk *walk = NULL; git_remote_head *rhead; unsigned int i; int error = -1; git_oid oid; git_packbuilder *pack = NULL; git_odb_writepack *writepack = NULL; git_odb *odb = NULL; if ((error = git_revwalk_new(&walk, t->repo)) < 0) goto cleanup; git_revwalk_sorting(walk, GIT_SORT_TIME); if ((error = git_packbuilder_new(&pack, t->repo)) < 0) goto cleanup; stats->total_objects = 0; stats->indexed_objects = 0; stats->received_objects = 0; stats->received_bytes = 0; git_vector_foreach(&t->refs, i, rhead) { git_object *obj; if ((error = git_object_lookup(&obj, t->repo, &rhead->oid, GIT_OBJ_ANY)) < 0) goto cleanup; if (git_object_type(obj) == GIT_OBJ_COMMIT) { /* Revwalker includes only wanted commits */ error = git_revwalk_push(walk, &rhead->oid); if (!git_oid_iszero(&rhead->loid)) error = git_revwalk_hide(walk, &rhead->loid); } else { /* Tag or some other wanted object. Add it on its own */ error = git_packbuilder_insert(pack, &rhead->oid, rhead->name); } git_object_free(obj); } /* Walk the objects, building a packfile */ if ((error = git_repository_odb__weakptr(&odb, repo)) < 0) goto cleanup; while ((error = git_revwalk_next(&oid, walk)) == 0) { git_commit *commit; /* Skip commits we already have */ if (git_odb_exists(odb, &oid)) continue; if (!git_object_lookup((git_object**)&commit, t->repo, &oid, GIT_OBJ_COMMIT)) { const git_oid *tree_oid = git_commit_tree_id(commit); /* Add the commit and its tree */ if ((error = git_packbuilder_insert(pack, &oid, NULL)) < 0 || (error = git_packbuilder_insert_tree(pack, tree_oid)) < 0) { git_commit_free(commit); goto cleanup; } git_commit_free(commit); } } if ((error = git_odb_write_pack(&writepack, odb, progress_cb, progress_payload)) < 0) goto cleanup; /* Write the data to the ODB */ { foreach_data data = {0}; data.stats = stats; data.progress_cb = progress_cb; data.progress_payload = progress_payload; data.writepack = writepack; if ((error = git_packbuilder_foreach(pack, foreach_cb, &data)) < 0) goto cleanup; } error = writepack->commit(writepack, stats); cleanup: if (writepack) writepack->free(writepack); git_packbuilder_free(pack); git_revwalk_free(walk); return error; } static int local_is_connected(git_transport *transport) { transport_local *t = (transport_local *)transport; return t->connected; } static int local_read_flags(git_transport *transport, int *flags) { transport_local *t = (transport_local *)transport; *flags = t->flags; return 0; } static void local_cancel(git_transport *transport) { transport_local *t = (transport_local *)transport; git_atomic_set(&t->cancelled, 1); } static int local_close(git_transport *transport) { transport_local *t = (transport_local *)transport; size_t i; git_remote_head *head; t->connected = 0; if (t->repo) { git_repository_free(t->repo); t->repo = NULL; } if (t->url) { git__free(t->url); t->url = NULL; } git_vector_foreach(&t->refs, i, head) { git__free(head->name); git__free(head); } git_vector_free(&t->refs); return 0; } static void local_free(git_transport *transport) { transport_local *t = (transport_local *)transport; /* Close the transport, if it's still open. */ local_close(transport); /* Free the transport */ git__free(t); } /************** * Public API * **************/ int git_transport_local(git_transport **out, git_remote *owner, void *param) { transport_local *t; GIT_UNUSED(param); t = git__calloc(1, sizeof(transport_local)); GITERR_CHECK_ALLOC(t); t->parent.version = GIT_TRANSPORT_VERSION; t->parent.connect = local_connect; t->parent.negotiate_fetch = local_negotiate_fetch; t->parent.download_pack = local_download_pack; t->parent.push = local_push; t->parent.close = local_close; t->parent.free = local_free; t->parent.ls = local_ls; t->parent.is_connected = local_is_connected; t->parent.read_flags = local_read_flags; t->parent.cancel = local_cancel; t->owner = owner; *out = (git_transport *) t; return 0; } libgit2-0.19.0/src/transports/smart.c000066400000000000000000000202031216214232500174300ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #include "git2.h" #include "smart.h" #include "refs.h" static int git_smart__recv_cb(gitno_buffer *buf) { transport_smart *t = (transport_smart *) buf->cb_data; size_t old_len, bytes_read; int error; assert(t->current_stream); old_len = buf->offset; if ((error = t->current_stream->read(t->current_stream, buf->data + buf->offset, buf->len - buf->offset, &bytes_read)) < 0) return error; buf->offset += bytes_read; if (t->packetsize_cb) t->packetsize_cb(bytes_read, t->packetsize_payload); return (int)(buf->offset - old_len); } GIT_INLINE(int) git_smart__reset_stream(transport_smart *t, bool close_subtransport) { if (t->current_stream) { t->current_stream->free(t->current_stream); t->current_stream = NULL; } if (close_subtransport && t->wrapped->close(t->wrapped) < 0) return -1; return 0; } static int git_smart__set_callbacks( git_transport *transport, git_transport_message_cb progress_cb, git_transport_message_cb error_cb, void *message_cb_payload) { transport_smart *t = (transport_smart *)transport; t->progress_cb = progress_cb; t->error_cb = error_cb; t->message_cb_payload = message_cb_payload; return 0; } static int git_smart__connect( git_transport *transport, const char *url, git_cred_acquire_cb cred_acquire_cb, void *cred_acquire_payload, int direction, int flags) { transport_smart *t = (transport_smart *)transport; git_smart_subtransport_stream *stream; int error; git_pkt *pkt; git_pkt_ref *first; git_smart_service_t service; if (git_smart__reset_stream(t, true) < 0) return -1; t->url = git__strdup(url); GITERR_CHECK_ALLOC(t->url); t->direction = direction; t->flags = flags; t->cred_acquire_cb = cred_acquire_cb; t->cred_acquire_payload = cred_acquire_payload; if (GIT_DIRECTION_FETCH == t->direction) service = GIT_SERVICE_UPLOADPACK_LS; else if (GIT_DIRECTION_PUSH == t->direction) service = GIT_SERVICE_RECEIVEPACK_LS; else { giterr_set(GITERR_NET, "Invalid direction"); return -1; } if ((error = t->wrapped->action(&stream, t->wrapped, t->url, service)) < 0) return error; /* Save off the current stream (i.e. socket) that we are working with */ t->current_stream = stream; gitno_buffer_setup_callback(NULL, &t->buffer, t->buffer_data, sizeof(t->buffer_data), git_smart__recv_cb, t); /* 2 flushes for RPC; 1 for stateful */ if ((error = git_smart__store_refs(t, t->rpc ? 2 : 1)) < 0) return error; /* Strip the comment packet for RPC */ if (t->rpc) { pkt = (git_pkt *)git_vector_get(&t->refs, 0); if (!pkt || GIT_PKT_COMMENT != pkt->type) { giterr_set(GITERR_NET, "Invalid response"); return -1; } else { /* Remove the comment pkt from the list */ git_vector_remove(&t->refs, 0); git__free(pkt); } } /* We now have loaded the refs. */ t->have_refs = 1; first = (git_pkt_ref *)git_vector_get(&t->refs, 0); /* Detect capabilities */ if (git_smart__detect_caps(first, &t->caps) < 0) return -1; /* If the only ref in the list is capabilities^{} with OID_ZERO, remove it */ if (1 == t->refs.length && !strcmp(first->head.name, "capabilities^{}") && git_oid_iszero(&first->head.oid)) { git_vector_clear(&t->refs); git_pkt_free((git_pkt *)first); } if (t->rpc && git_smart__reset_stream(t, false) < 0) return -1; /* We're now logically connected. */ t->connected = 1; return 0; } static int git_smart__ls(git_transport *transport, git_headlist_cb list_cb, void *payload) { transport_smart *t = (transport_smart *)transport; unsigned int i; git_pkt *p = NULL; if (!t->have_refs) { giterr_set(GITERR_NET, "The transport has not yet loaded the refs"); return -1; } git_vector_foreach(&t->refs, i, p) { git_pkt_ref *pkt = NULL; if (p->type != GIT_PKT_REF) continue; pkt = (git_pkt_ref *)p; if (list_cb(&pkt->head, payload)) return GIT_EUSER; } return 0; } int git_smart__negotiation_step(git_transport *transport, void *data, size_t len) { transport_smart *t = (transport_smart *)transport; git_smart_subtransport_stream *stream; int error; if (t->rpc && git_smart__reset_stream(t, false) < 0) return -1; if (GIT_DIRECTION_FETCH != t->direction) { giterr_set(GITERR_NET, "This operation is only valid for fetch"); return -1; } if ((error = t->wrapped->action(&stream, t->wrapped, t->url, GIT_SERVICE_UPLOADPACK)) < 0) return error; /* If this is a stateful implementation, the stream we get back should be the same */ assert(t->rpc || t->current_stream == stream); /* Save off the current stream (i.e. socket) that we are working with */ t->current_stream = stream; if ((error = stream->write(stream, (const char *)data, len)) < 0) return error; gitno_buffer_setup_callback(NULL, &t->buffer, t->buffer_data, sizeof(t->buffer_data), git_smart__recv_cb, t); return 0; } int git_smart__get_push_stream(transport_smart *t, git_smart_subtransport_stream **stream) { int error; if (t->rpc && git_smart__reset_stream(t, false) < 0) return -1; if (GIT_DIRECTION_PUSH != t->direction) { giterr_set(GITERR_NET, "This operation is only valid for push"); return -1; } if ((error = t->wrapped->action(stream, t->wrapped, t->url, GIT_SERVICE_RECEIVEPACK)) < 0) return error; /* If this is a stateful implementation, the stream we get back should be the same */ assert(t->rpc || t->current_stream == *stream); /* Save off the current stream (i.e. socket) that we are working with */ t->current_stream = *stream; gitno_buffer_setup_callback(NULL, &t->buffer, t->buffer_data, sizeof(t->buffer_data), git_smart__recv_cb, t); return 0; } static void git_smart__cancel(git_transport *transport) { transport_smart *t = (transport_smart *)transport; git_atomic_set(&t->cancelled, 1); } static int git_smart__is_connected(git_transport *transport) { transport_smart *t = (transport_smart *)transport; return t->connected; } static int git_smart__read_flags(git_transport *transport, int *flags) { transport_smart *t = (transport_smart *)transport; *flags = t->flags; return 0; } static int git_smart__close(git_transport *transport) { transport_smart *t = (transport_smart *)transport; git_vector *common = &t->common; unsigned int i; git_pkt *p; int ret; ret = git_smart__reset_stream(t, true); git_vector_foreach(common, i, p) git_pkt_free(p); git_vector_free(common); if (t->url) { git__free(t->url); t->url = NULL; } t->connected = 0; return ret; } static void git_smart__free(git_transport *transport) { transport_smart *t = (transport_smart *)transport; git_vector *refs = &t->refs; unsigned int i; git_pkt *p; /* Make sure that the current stream is closed, if we have one. */ git_smart__close(transport); /* Free the subtransport */ t->wrapped->free(t->wrapped); git_vector_foreach(refs, i, p) git_pkt_free(p); git_vector_free(refs); git__free(t); } static int ref_name_cmp(const void *a, const void *b) { const git_pkt_ref *ref_a = a, *ref_b = b; return strcmp(ref_a->head.name, ref_b->head.name); } int git_transport_smart(git_transport **out, git_remote *owner, void *param) { transport_smart *t; git_smart_subtransport_definition *definition = (git_smart_subtransport_definition *)param; if (!param) return -1; t = git__calloc(sizeof(transport_smart), 1); GITERR_CHECK_ALLOC(t); t->parent.version = GIT_TRANSPORT_VERSION; t->parent.set_callbacks = git_smart__set_callbacks; t->parent.connect = git_smart__connect; t->parent.close = git_smart__close; t->parent.free = git_smart__free; t->parent.negotiate_fetch = git_smart__negotiate_fetch; t->parent.download_pack = git_smart__download_pack; t->parent.push = git_smart__push; t->parent.ls = git_smart__ls; t->parent.is_connected = git_smart__is_connected; t->parent.read_flags = git_smart__read_flags; t->parent.cancel = git_smart__cancel; t->owner = owner; t->rpc = definition->rpc; if (git_vector_init(&t->refs, 16, ref_name_cmp) < 0) { git__free(t); return -1; } if (definition->callback(&t->wrapped, &t->parent) < 0) { git__free(t); return -1; } *out = (git_transport *) t; return 0; } libgit2-0.19.0/src/transports/smart.h000066400000000000000000000077651216214232500174570ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #include "git2.h" #include "vector.h" #include "netops.h" #include "buffer.h" #include "push.h" #define GIT_SIDE_BAND_DATA 1 #define GIT_SIDE_BAND_PROGRESS 2 #define GIT_SIDE_BAND_ERROR 3 #define GIT_CAP_OFS_DELTA "ofs-delta" #define GIT_CAP_MULTI_ACK "multi_ack" #define GIT_CAP_SIDE_BAND "side-band" #define GIT_CAP_SIDE_BAND_64K "side-band-64k" #define GIT_CAP_INCLUDE_TAG "include-tag" #define GIT_CAP_DELETE_REFS "delete-refs" #define GIT_CAP_REPORT_STATUS "report-status" enum git_pkt_type { GIT_PKT_CMD, GIT_PKT_FLUSH, GIT_PKT_REF, GIT_PKT_HAVE, GIT_PKT_ACK, GIT_PKT_NAK, GIT_PKT_PACK, GIT_PKT_COMMENT, GIT_PKT_ERR, GIT_PKT_DATA, GIT_PKT_PROGRESS, GIT_PKT_OK, GIT_PKT_NG, GIT_PKT_UNPACK, }; /* Used for multi-ack */ enum git_ack_status { GIT_ACK_NONE, GIT_ACK_CONTINUE, GIT_ACK_COMMON, GIT_ACK_READY }; /* This would be a flush pkt */ typedef struct { enum git_pkt_type type; } git_pkt; struct git_pkt_cmd { enum git_pkt_type type; char *cmd; char *path; char *host; }; /* This is a pkt-line with some info in it */ typedef struct { enum git_pkt_type type; git_remote_head head; char *capabilities; } git_pkt_ref; /* Useful later */ typedef struct { enum git_pkt_type type; git_oid oid; enum git_ack_status status; } git_pkt_ack; typedef struct { enum git_pkt_type type; char comment[GIT_FLEX_ARRAY]; } git_pkt_comment; typedef struct { enum git_pkt_type type; int len; char data[GIT_FLEX_ARRAY]; } git_pkt_data; typedef git_pkt_data git_pkt_progress; typedef struct { enum git_pkt_type type; int len; char error[GIT_FLEX_ARRAY]; } git_pkt_err; typedef struct { enum git_pkt_type type; char *ref; } git_pkt_ok; typedef struct { enum git_pkt_type type; char *ref; char *msg; } git_pkt_ng; typedef struct { enum git_pkt_type type; int unpack_ok; } git_pkt_unpack; typedef struct transport_smart_caps { int common:1, ofs_delta:1, multi_ack: 1, side_band:1, side_band_64k:1, include_tag:1, delete_refs:1, report_status:1; } transport_smart_caps; typedef void (*packetsize_cb)(size_t received, void *payload); typedef struct { git_transport parent; git_remote *owner; char *url; git_cred_acquire_cb cred_acquire_cb; void *cred_acquire_payload; int direction; int flags; git_transport_message_cb progress_cb; git_transport_message_cb error_cb; void *message_cb_payload; git_smart_subtransport *wrapped; git_smart_subtransport_stream *current_stream; transport_smart_caps caps; git_vector refs; git_vector common; git_atomic cancelled; packetsize_cb packetsize_cb; void *packetsize_payload; unsigned rpc : 1, have_refs : 1, connected : 1; gitno_buffer buffer; char buffer_data[65536]; } transport_smart; /* smart_protocol.c */ int git_smart__store_refs(transport_smart *t, int flushes); int git_smart__detect_caps(git_pkt_ref *pkt, transport_smart_caps *caps); int git_smart__push(git_transport *transport, git_push *push); int git_smart__negotiate_fetch( git_transport *transport, git_repository *repo, const git_remote_head * const *refs, size_t count); int git_smart__download_pack( git_transport *transport, git_repository *repo, git_transfer_progress *stats, git_transfer_progress_callback progress_cb, void *progress_payload); /* smart.c */ int git_smart__negotiation_step(git_transport *transport, void *data, size_t len); int git_smart__get_push_stream(transport_smart *t, git_smart_subtransport_stream **out); /* smart_pkt.c */ int git_pkt_parse_line(git_pkt **head, const char *line, const char **out, size_t len); int git_pkt_buffer_flush(git_buf *buf); int git_pkt_send_flush(GIT_SOCKET s); int git_pkt_buffer_done(git_buf *buf); int git_pkt_buffer_wants(const git_remote_head * const *refs, size_t count, transport_smart_caps *caps, git_buf *buf); int git_pkt_buffer_have(git_oid *oid, git_buf *buf); void git_pkt_free(git_pkt *pkt); libgit2-0.19.0/src/transports/smart_pkt.c000066400000000000000000000251571216214232500203230ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #include "common.h" #include "git2/types.h" #include "git2/errors.h" #include "git2/refs.h" #include "git2/revwalk.h" #include "smart.h" #include "util.h" #include "netops.h" #include "posix.h" #include "buffer.h" #include #define PKT_LEN_SIZE 4 static const char pkt_done_str[] = "0009done\n"; static const char pkt_flush_str[] = "0000"; static const char pkt_have_prefix[] = "0032have "; static const char pkt_want_prefix[] = "0032want "; static int flush_pkt(git_pkt **out) { git_pkt *pkt; pkt = git__malloc(sizeof(git_pkt)); GITERR_CHECK_ALLOC(pkt); pkt->type = GIT_PKT_FLUSH; *out = pkt; return 0; } /* the rest of the line will be useful for multi_ack */ static int ack_pkt(git_pkt **out, const char *line, size_t len) { git_pkt_ack *pkt; GIT_UNUSED(line); GIT_UNUSED(len); pkt = git__calloc(1, sizeof(git_pkt_ack)); GITERR_CHECK_ALLOC(pkt); pkt->type = GIT_PKT_ACK; line += 3; len -= 3; if (len >= GIT_OID_HEXSZ) { git_oid_fromstr(&pkt->oid, line + 1); line += GIT_OID_HEXSZ + 1; len -= GIT_OID_HEXSZ + 1; } if (len >= 7) { if (!git__prefixcmp(line + 1, "continue")) pkt->status = GIT_ACK_CONTINUE; } *out = (git_pkt *) pkt; return 0; } static int nak_pkt(git_pkt **out) { git_pkt *pkt; pkt = git__malloc(sizeof(git_pkt)); GITERR_CHECK_ALLOC(pkt); pkt->type = GIT_PKT_NAK; *out = pkt; return 0; } static int pack_pkt(git_pkt **out) { git_pkt *pkt; pkt = git__malloc(sizeof(git_pkt)); GITERR_CHECK_ALLOC(pkt); pkt->type = GIT_PKT_PACK; *out = pkt; return 0; } static int comment_pkt(git_pkt **out, const char *line, size_t len) { git_pkt_comment *pkt; pkt = git__malloc(sizeof(git_pkt_comment) + len + 1); GITERR_CHECK_ALLOC(pkt); pkt->type = GIT_PKT_COMMENT; memcpy(pkt->comment, line, len); pkt->comment[len] = '\0'; *out = (git_pkt *) pkt; return 0; } static int err_pkt(git_pkt **out, const char *line, size_t len) { git_pkt_err *pkt; /* Remove "ERR " from the line */ line += 4; len -= 4; pkt = git__malloc(sizeof(git_pkt_err) + len + 1); GITERR_CHECK_ALLOC(pkt); pkt->type = GIT_PKT_ERR; pkt->len = (int)len; memcpy(pkt->error, line, len); pkt->error[len] = '\0'; *out = (git_pkt *) pkt; return 0; } static int data_pkt(git_pkt **out, const char *line, size_t len) { git_pkt_data *pkt; line++; len--; pkt = git__malloc(sizeof(git_pkt_data) + len); GITERR_CHECK_ALLOC(pkt); pkt->type = GIT_PKT_DATA; pkt->len = (int) len; memcpy(pkt->data, line, len); *out = (git_pkt *) pkt; return 0; } static int progress_pkt(git_pkt **out, const char *line, size_t len) { git_pkt_progress *pkt; line++; len--; pkt = git__malloc(sizeof(git_pkt_progress) + len); GITERR_CHECK_ALLOC(pkt); pkt->type = GIT_PKT_PROGRESS; pkt->len = (int) len; memcpy(pkt->data, line, len); *out = (git_pkt *) pkt; return 0; } static int sideband_error_pkt(git_pkt **out, const char *line, size_t len) { git_pkt_err *pkt; line++; len--; pkt = git__malloc(sizeof(git_pkt_err) + len + 1); GITERR_CHECK_ALLOC(pkt); pkt->type = GIT_PKT_ERR; pkt->len = (int)len; memcpy(pkt->error, line, len); pkt->error[len] = '\0'; *out = (git_pkt *)pkt; return 0; } /* * Parse an other-ref line. */ static int ref_pkt(git_pkt **out, const char *line, size_t len) { int error; git_pkt_ref *pkt; pkt = git__malloc(sizeof(git_pkt_ref)); GITERR_CHECK_ALLOC(pkt); memset(pkt, 0x0, sizeof(git_pkt_ref)); pkt->type = GIT_PKT_REF; if ((error = git_oid_fromstr(&pkt->head.oid, line)) < 0) goto error_out; /* Check for a bit of consistency */ if (line[GIT_OID_HEXSZ] != ' ') { giterr_set(GITERR_NET, "Error parsing pkt-line"); error = -1; goto error_out; } /* Jump from the name */ line += GIT_OID_HEXSZ + 1; len -= (GIT_OID_HEXSZ + 1); if (line[len - 1] == '\n') --len; pkt->head.name = git__malloc(len + 1); GITERR_CHECK_ALLOC(pkt->head.name); memcpy(pkt->head.name, line, len); pkt->head.name[len] = '\0'; if (strlen(pkt->head.name) < len) { pkt->capabilities = strchr(pkt->head.name, '\0') + 1; } *out = (git_pkt *)pkt; return 0; error_out: git__free(pkt); return error; } static int ok_pkt(git_pkt **out, const char *line, size_t len) { git_pkt_ok *pkt; const char *ptr; pkt = git__malloc(sizeof(*pkt)); GITERR_CHECK_ALLOC(pkt); pkt->type = GIT_PKT_OK; line += 3; /* skip "ok " */ ptr = strchr(line, '\n'); len = ptr - line; pkt->ref = git__malloc(len + 1); GITERR_CHECK_ALLOC(pkt->ref); memcpy(pkt->ref, line, len); pkt->ref[len] = '\0'; *out = (git_pkt *)pkt; return 0; } static int ng_pkt(git_pkt **out, const char *line, size_t len) { git_pkt_ng *pkt; const char *ptr; pkt = git__malloc(sizeof(*pkt)); GITERR_CHECK_ALLOC(pkt); pkt->type = GIT_PKT_NG; line += 3; /* skip "ng " */ ptr = strchr(line, ' '); len = ptr - line; pkt->ref = git__malloc(len + 1); GITERR_CHECK_ALLOC(pkt->ref); memcpy(pkt->ref, line, len); pkt->ref[len] = '\0'; line = ptr + 1; ptr = strchr(line, '\n'); len = ptr - line; pkt->msg = git__malloc(len + 1); GITERR_CHECK_ALLOC(pkt->msg); memcpy(pkt->msg, line, len); pkt->msg[len] = '\0'; *out = (git_pkt *)pkt; return 0; } static int unpack_pkt(git_pkt **out, const char *line, size_t len) { git_pkt_unpack *pkt; GIT_UNUSED(len); pkt = git__malloc(sizeof(*pkt)); GITERR_CHECK_ALLOC(pkt); pkt->type = GIT_PKT_UNPACK; if (!git__prefixcmp(line, "unpack ok")) pkt->unpack_ok = 1; else pkt->unpack_ok = 0; *out = (git_pkt *)pkt; return 0; } static int32_t parse_len(const char *line) { char num[PKT_LEN_SIZE + 1]; int i, error; int32_t len; const char *num_end; memcpy(num, line, PKT_LEN_SIZE); num[PKT_LEN_SIZE] = '\0'; for (i = 0; i < PKT_LEN_SIZE; ++i) { if (!isxdigit(num[i])) { giterr_set(GITERR_NET, "Found invalid hex digit in length"); return -1; } } if ((error = git__strtol32(&len, num, &num_end, 16)) < 0) return error; return len; } /* * As per the documentation, the syntax is: * * pkt-line = data-pkt / flush-pkt * data-pkt = pkt-len pkt-payload * pkt-len = 4*(HEXDIG) * pkt-payload = (pkt-len -4)*(OCTET) * flush-pkt = "0000" * * Which means that the first four bytes are the length of the line, * in ASCII hexadecimal (including itself) */ int git_pkt_parse_line( git_pkt **head, const char *line, const char **out, size_t bufflen) { int ret; int32_t len; /* Not even enough for the length */ if (bufflen > 0 && bufflen < PKT_LEN_SIZE) return GIT_EBUFS; len = parse_len(line); if (len < 0) { /* * If we fail to parse the length, it might be because the * server is trying to send us the packfile already. */ if (bufflen >= 4 && !git__prefixcmp(line, "PACK")) { giterr_clear(); *out = line; return pack_pkt(head); } return (int)len; } /* * If we were given a buffer length, then make sure there is * enough in the buffer to satisfy this line */ if (bufflen > 0 && bufflen < (size_t)len) return GIT_EBUFS; line += PKT_LEN_SIZE; /* * TODO: How do we deal with empty lines? Try again? with the next * line? */ if (len == PKT_LEN_SIZE) { *out = line; return 0; } if (len == 0) { /* Flush pkt */ *out = line; return flush_pkt(head); } len -= PKT_LEN_SIZE; /* the encoded length includes its own size */ if (*line == GIT_SIDE_BAND_DATA) ret = data_pkt(head, line, len); else if (*line == GIT_SIDE_BAND_PROGRESS) ret = progress_pkt(head, line, len); else if (*line == GIT_SIDE_BAND_ERROR) ret = sideband_error_pkt(head, line, len); else if (!git__prefixcmp(line, "ACK")) ret = ack_pkt(head, line, len); else if (!git__prefixcmp(line, "NAK")) ret = nak_pkt(head); else if (!git__prefixcmp(line, "ERR ")) ret = err_pkt(head, line, len); else if (*line == '#') ret = comment_pkt(head, line, len); else if (!git__prefixcmp(line, "ok")) ret = ok_pkt(head, line, len); else if (!git__prefixcmp(line, "ng")) ret = ng_pkt(head, line, len); else if (!git__prefixcmp(line, "unpack")) ret = unpack_pkt(head, line, len); else ret = ref_pkt(head, line, len); *out = line + len; return ret; } void git_pkt_free(git_pkt *pkt) { if (pkt->type == GIT_PKT_REF) { git_pkt_ref *p = (git_pkt_ref *) pkt; git__free(p->head.name); } if (pkt->type == GIT_PKT_OK) { git_pkt_ok *p = (git_pkt_ok *) pkt; git__free(p->ref); } if (pkt->type == GIT_PKT_NG) { git_pkt_ng *p = (git_pkt_ng *) pkt; git__free(p->ref); git__free(p->msg); } git__free(pkt); } int git_pkt_buffer_flush(git_buf *buf) { return git_buf_put(buf, pkt_flush_str, strlen(pkt_flush_str)); } static int buffer_want_with_caps(const git_remote_head *head, transport_smart_caps *caps, git_buf *buf) { git_buf str = GIT_BUF_INIT; char oid[GIT_OID_HEXSZ +1] = {0}; unsigned int len; /* Prefer side-band-64k if the server supports both */ if (caps->side_band) { if (caps->side_band_64k) git_buf_printf(&str, "%s ", GIT_CAP_SIDE_BAND_64K); else git_buf_printf(&str, "%s ", GIT_CAP_SIDE_BAND); } if (caps->ofs_delta) git_buf_puts(&str, GIT_CAP_OFS_DELTA " "); if (caps->multi_ack) git_buf_puts(&str, GIT_CAP_MULTI_ACK " "); if (caps->include_tag) git_buf_puts(&str, GIT_CAP_INCLUDE_TAG " "); if (git_buf_oom(&str)) return -1; len = (unsigned int) (strlen("XXXXwant ") + GIT_OID_HEXSZ + 1 /* NUL */ + git_buf_len(&str) + 1 /* LF */); git_buf_grow(buf, git_buf_len(buf) + len); git_oid_fmt(oid, &head->oid); git_buf_printf(buf, "%04xwant %s %s\n", len, oid, git_buf_cstr(&str)); git_buf_free(&str); return git_buf_oom(buf); } /* * All "want" packets have the same length and format, so what we do * is overwrite the OID each time. */ int git_pkt_buffer_wants( const git_remote_head * const *refs, size_t count, transport_smart_caps *caps, git_buf *buf) { size_t i = 0; const git_remote_head *head; if (caps->common) { for (; i < count; ++i) { head = refs[i]; if (!head->local) break; } if (buffer_want_with_caps(refs[i], caps, buf) < 0) return -1; i++; } for (; i < count; ++i) { char oid[GIT_OID_HEXSZ]; head = refs[i]; if (head->local) continue; git_oid_fmt(oid, &head->oid); git_buf_put(buf, pkt_want_prefix, strlen(pkt_want_prefix)); git_buf_put(buf, oid, GIT_OID_HEXSZ); git_buf_putc(buf, '\n'); if (git_buf_oom(buf)) return -1; } return git_pkt_buffer_flush(buf); } int git_pkt_buffer_have(git_oid *oid, git_buf *buf) { char oidhex[GIT_OID_HEXSZ + 1]; memset(oidhex, 0x0, sizeof(oidhex)); git_oid_fmt(oidhex, oid); return git_buf_printf(buf, "%s%s\n", pkt_have_prefix, oidhex); } int git_pkt_buffer_done(git_buf *buf) { return git_buf_puts(buf, pkt_done_str); } libgit2-0.19.0/src/transports/smart_protocol.c000066400000000000000000000470411216214232500213620ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #include "git2.h" #include "git2/odb_backend.h" #include "smart.h" #include "refs.h" #include "repository.h" #include "push.h" #include "pack-objects.h" #include "remote.h" #define NETWORK_XFER_THRESHOLD (100*1024) int git_smart__store_refs(transport_smart *t, int flushes) { gitno_buffer *buf = &t->buffer; git_vector *refs = &t->refs; int error, flush = 0, recvd; const char *line_end = NULL; git_pkt *pkt = NULL; git_pkt_ref *ref; size_t i; /* Clear existing refs in case git_remote_connect() is called again * after git_remote_disconnect(). */ git_vector_foreach(refs, i, ref) { git__free(ref->head.name); git__free(ref); } git_vector_clear(refs); do { if (buf->offset > 0) error = git_pkt_parse_line(&pkt, buf->data, &line_end, buf->offset); else error = GIT_EBUFS; if (error < 0 && error != GIT_EBUFS) return -1; if (error == GIT_EBUFS) { if ((recvd = gitno_recv(buf)) < 0) return -1; if (recvd == 0 && !flush) { giterr_set(GITERR_NET, "Early EOF"); return -1; } continue; } gitno_consume(buf, line_end); if (pkt->type == GIT_PKT_ERR) { giterr_set(GITERR_NET, "Remote error: %s", ((git_pkt_err *)pkt)->error); git__free(pkt); return -1; } if (pkt->type != GIT_PKT_FLUSH && git_vector_insert(refs, pkt) < 0) return -1; if (pkt->type == GIT_PKT_FLUSH) { flush++; git_pkt_free(pkt); } } while (flush < flushes); return flush; } int git_smart__detect_caps(git_pkt_ref *pkt, transport_smart_caps *caps) { const char *ptr; /* No refs or capabilites, odd but not a problem */ if (pkt == NULL || pkt->capabilities == NULL) return 0; ptr = pkt->capabilities; while (ptr != NULL && *ptr != '\0') { if (*ptr == ' ') ptr++; if (!git__prefixcmp(ptr, GIT_CAP_OFS_DELTA)) { caps->common = caps->ofs_delta = 1; ptr += strlen(GIT_CAP_OFS_DELTA); continue; } if (!git__prefixcmp(ptr, GIT_CAP_MULTI_ACK)) { caps->common = caps->multi_ack = 1; ptr += strlen(GIT_CAP_MULTI_ACK); continue; } if (!git__prefixcmp(ptr, GIT_CAP_INCLUDE_TAG)) { caps->common = caps->include_tag = 1; ptr += strlen(GIT_CAP_INCLUDE_TAG); continue; } /* Keep side-band check after side-band-64k */ if (!git__prefixcmp(ptr, GIT_CAP_SIDE_BAND_64K)) { caps->common = caps->side_band_64k = 1; ptr += strlen(GIT_CAP_SIDE_BAND_64K); continue; } if (!git__prefixcmp(ptr, GIT_CAP_SIDE_BAND)) { caps->common = caps->side_band = 1; ptr += strlen(GIT_CAP_SIDE_BAND); continue; } if (!git__prefixcmp(ptr, GIT_CAP_DELETE_REFS)) { caps->common = caps->delete_refs = 1; ptr += strlen(GIT_CAP_DELETE_REFS); continue; } /* We don't know this capability, so skip it */ ptr = strchr(ptr, ' '); } return 0; } static int recv_pkt(git_pkt **out, gitno_buffer *buf) { const char *ptr = buf->data, *line_end = ptr; git_pkt *pkt = NULL; int pkt_type, error = 0, ret; do { if (buf->offset > 0) error = git_pkt_parse_line(&pkt, ptr, &line_end, buf->offset); else error = GIT_EBUFS; if (error == 0) break; /* return the pkt */ if (error < 0 && error != GIT_EBUFS) return -1; if ((ret = gitno_recv(buf)) < 0) return -1; } while (error); gitno_consume(buf, line_end); pkt_type = pkt->type; if (out != NULL) *out = pkt; else git__free(pkt); return pkt_type; } static int store_common(transport_smart *t) { git_pkt *pkt = NULL; gitno_buffer *buf = &t->buffer; do { if (recv_pkt(&pkt, buf) < 0) return -1; if (pkt->type == GIT_PKT_ACK) { if (git_vector_insert(&t->common, pkt) < 0) return -1; } else { git__free(pkt); return 0; } } while (1); return 0; } static int fetch_setup_walk(git_revwalk **out, git_repository *repo) { git_revwalk *walk; git_strarray refs; unsigned int i; git_reference *ref; if (git_reference_list(&refs, repo) < 0) return -1; if (git_revwalk_new(&walk, repo) < 0) return -1; git_revwalk_sorting(walk, GIT_SORT_TIME); for (i = 0; i < refs.count; ++i) { /* No tags */ if (!git__prefixcmp(refs.strings[i], GIT_REFS_TAGS_DIR)) continue; if (git_reference_lookup(&ref, repo, refs.strings[i]) < 0) goto on_error; if (git_reference_type(ref) == GIT_REF_SYMBOLIC) continue; if (git_revwalk_push(walk, git_reference_target(ref)) < 0) goto on_error; git_reference_free(ref); } git_strarray_free(&refs); *out = walk; return 0; on_error: git_reference_free(ref); git_strarray_free(&refs); return -1; } int git_smart__negotiate_fetch(git_transport *transport, git_repository *repo, const git_remote_head * const *refs, size_t count) { transport_smart *t = (transport_smart *)transport; gitno_buffer *buf = &t->buffer; git_buf data = GIT_BUF_INIT; git_revwalk *walk = NULL; int error = -1, pkt_type; unsigned int i; git_oid oid; /* No own logic, do our thing */ if ((error = git_pkt_buffer_wants(refs, count, &t->caps, &data)) < 0) return error; if ((error = fetch_setup_walk(&walk, repo)) < 0) goto on_error; /* * We don't support any kind of ACK extensions, so the negotiation * boils down to sending what we have and listening for an ACK * every once in a while. */ i = 0; while (true) { error = git_revwalk_next(&oid, walk); if (error < 0) { if (GIT_ITEROVER == error) break; goto on_error; } git_pkt_buffer_have(&oid, &data); i++; if (i % 20 == 0) { if (t->cancelled.val) { giterr_set(GITERR_NET, "The fetch was cancelled by the user"); error = GIT_EUSER; goto on_error; } git_pkt_buffer_flush(&data); if (git_buf_oom(&data)) { error = -1; goto on_error; } if ((error = git_smart__negotiation_step(&t->parent, data.ptr, data.size)) < 0) goto on_error; git_buf_clear(&data); if (t->caps.multi_ack) { if ((error = store_common(t)) < 0) goto on_error; } else { pkt_type = recv_pkt(NULL, buf); if (pkt_type == GIT_PKT_ACK) { break; } else if (pkt_type == GIT_PKT_NAK) { continue; } else if (pkt_type < 0) { /* recv_pkt returned an error */ error = pkt_type; goto on_error; } else { giterr_set(GITERR_NET, "Unexpected pkt type"); error = -1; goto on_error; } } } if (t->common.length > 0) break; if (i % 20 == 0 && t->rpc) { git_pkt_ack *pkt; unsigned int i; if ((error = git_pkt_buffer_wants(refs, count, &t->caps, &data)) < 0) goto on_error; git_vector_foreach(&t->common, i, pkt) { if ((error = git_pkt_buffer_have(&pkt->oid, &data)) < 0) goto on_error; } if (git_buf_oom(&data)) { error = -1; goto on_error; } } } /* Tell the other end that we're done negotiating */ if (t->rpc && t->common.length > 0) { git_pkt_ack *pkt; unsigned int i; if ((error = git_pkt_buffer_wants(refs, count, &t->caps, &data)) < 0) goto on_error; git_vector_foreach(&t->common, i, pkt) { if ((error = git_pkt_buffer_have(&pkt->oid, &data)) < 0) goto on_error; } if (git_buf_oom(&data)) { error = -1; goto on_error; } } if ((error = git_pkt_buffer_done(&data)) < 0) goto on_error; if (t->cancelled.val) { giterr_set(GITERR_NET, "The fetch was cancelled by the user"); error = GIT_EUSER; goto on_error; } if ((error = git_smart__negotiation_step(&t->parent, data.ptr, data.size)) < 0) goto on_error; git_buf_free(&data); git_revwalk_free(walk); /* Now let's eat up whatever the server gives us */ if (!t->caps.multi_ack) { pkt_type = recv_pkt(NULL, buf); if (pkt_type < 0) { return pkt_type; } else if (pkt_type != GIT_PKT_ACK && pkt_type != GIT_PKT_NAK) { giterr_set(GITERR_NET, "Unexpected pkt type"); return -1; } } else { git_pkt_ack *pkt; do { if ((error = recv_pkt((git_pkt **)&pkt, buf)) < 0) return error; if (pkt->type == GIT_PKT_NAK || (pkt->type == GIT_PKT_ACK && pkt->status != GIT_ACK_CONTINUE)) { git__free(pkt); break; } git__free(pkt); } while (1); } return 0; on_error: git_revwalk_free(walk); git_buf_free(&data); return error; } static int no_sideband(transport_smart *t, struct git_odb_writepack *writepack, gitno_buffer *buf, git_transfer_progress *stats) { int recvd; do { if (t->cancelled.val) { giterr_set(GITERR_NET, "The fetch was cancelled by the user"); return GIT_EUSER; } if (writepack->add(writepack, buf->data, buf->offset, stats) < 0) return -1; gitno_consume_n(buf, buf->offset); if ((recvd = gitno_recv(buf)) < 0) return -1; } while(recvd > 0); if (writepack->commit(writepack, stats)) return -1; return 0; } struct network_packetsize_payload { git_transfer_progress_callback callback; void *payload; git_transfer_progress *stats; size_t last_fired_bytes; }; static void network_packetsize(size_t received, void *payload) { struct network_packetsize_payload *npp = (struct network_packetsize_payload*)payload; /* Accumulate bytes */ npp->stats->received_bytes += received; /* Fire notification if the threshold is reached */ if ((npp->stats->received_bytes - npp->last_fired_bytes) > NETWORK_XFER_THRESHOLD) { npp->last_fired_bytes = npp->stats->received_bytes; npp->callback(npp->stats, npp->payload); } } int git_smart__download_pack( git_transport *transport, git_repository *repo, git_transfer_progress *stats, git_transfer_progress_callback progress_cb, void *progress_payload) { transport_smart *t = (transport_smart *)transport; gitno_buffer *buf = &t->buffer; git_odb *odb; struct git_odb_writepack *writepack = NULL; int error = -1; struct network_packetsize_payload npp = {0}; memset(stats, 0, sizeof(git_transfer_progress)); if (progress_cb) { npp.callback = progress_cb; npp.payload = progress_payload; npp.stats = stats; t->packetsize_cb = &network_packetsize; t->packetsize_payload = &npp; /* We might have something in the buffer already from negotiate_fetch */ if (t->buffer.offset > 0) t->packetsize_cb(t->buffer.offset, t->packetsize_payload); } if ((error = git_repository_odb__weakptr(&odb, repo)) < 0 || ((error = git_odb_write_pack(&writepack, odb, progress_cb, progress_payload)) < 0)) goto on_error; /* * If the remote doesn't support the side-band, we can feed * the data directly to the pack writer. Otherwise, we need to * check which one belongs there. */ if (!t->caps.side_band && !t->caps.side_band_64k) { if (no_sideband(t, writepack, buf, stats) < 0) goto on_error; goto on_success; } do { git_pkt *pkt; if (t->cancelled.val) { giterr_set(GITERR_NET, "The fetch was cancelled by the user"); error = GIT_EUSER; goto on_error; } if (recv_pkt(&pkt, buf) < 0) goto on_error; if (pkt->type == GIT_PKT_PROGRESS) { if (t->progress_cb) { git_pkt_progress *p = (git_pkt_progress *) pkt; t->progress_cb(p->data, p->len, t->message_cb_payload); } git__free(pkt); } else if (pkt->type == GIT_PKT_DATA) { git_pkt_data *p = (git_pkt_data *) pkt; error = writepack->add(writepack, p->data, p->len, stats); git__free(pkt); if (error < 0) goto on_error; } else if (pkt->type == GIT_PKT_FLUSH) { /* A flush indicates the end of the packfile */ git__free(pkt); break; } } while (1); if (writepack->commit(writepack, stats) < 0) goto on_error; on_success: error = 0; on_error: if (writepack) writepack->free(writepack); /* Trailing execution of progress_cb, if necessary */ if (npp.callback && npp.stats->received_bytes > npp.last_fired_bytes) npp.callback(npp.stats, npp.payload); return error; } static int gen_pktline(git_buf *buf, git_push *push) { push_spec *spec; size_t i, len; char old_id[41], new_id[41]; old_id[40] = '\0'; new_id[40] = '\0'; git_vector_foreach(&push->specs, i, spec) { len = 2*GIT_OID_HEXSZ + 7 + strlen(spec->rref); if (i == 0) { ++len; /* '\0' */ if (push->report_status) len += strlen(GIT_CAP_REPORT_STATUS) + 1; len += strlen(GIT_CAP_SIDE_BAND_64K) + 1; } git_oid_fmt(old_id, &spec->roid); git_oid_fmt(new_id, &spec->loid); git_buf_printf(buf, "%04"PRIxZ"%s %s %s", len, old_id, new_id, spec->rref); if (i == 0) { git_buf_putc(buf, '\0'); /* Core git always starts their capabilities string with a space */ if (push->report_status) { git_buf_putc(buf, ' '); git_buf_printf(buf, GIT_CAP_REPORT_STATUS); } git_buf_putc(buf, ' '); git_buf_printf(buf, GIT_CAP_SIDE_BAND_64K); } git_buf_putc(buf, '\n'); } git_buf_puts(buf, "0000"); return git_buf_oom(buf) ? -1 : 0; } static int add_push_report_pkt(git_push *push, git_pkt *pkt) { push_status *status; switch (pkt->type) { case GIT_PKT_OK: status = git__calloc(1, sizeof(push_status)); GITERR_CHECK_ALLOC(status); status->msg = NULL; status->ref = git__strdup(((git_pkt_ok *)pkt)->ref); if (!status->ref || git_vector_insert(&push->status, status) < 0) { git_push_status_free(status); return -1; } break; case GIT_PKT_NG: status = git__calloc(sizeof(push_status), 1); GITERR_CHECK_ALLOC(status); status->ref = git__strdup(((git_pkt_ng *)pkt)->ref); status->msg = git__strdup(((git_pkt_ng *)pkt)->msg); if (!status->ref || !status->msg || git_vector_insert(&push->status, status) < 0) { git_push_status_free(status); return -1; } break; case GIT_PKT_UNPACK: push->unpack_ok = ((git_pkt_unpack *)pkt)->unpack_ok; break; case GIT_PKT_FLUSH: return GIT_ITEROVER; default: giterr_set(GITERR_NET, "report-status: protocol error"); return -1; } return 0; } static int add_push_report_sideband_pkt(git_push *push, git_pkt_data *data_pkt) { git_pkt *pkt; const char *line = data_pkt->data, *line_end; size_t line_len = data_pkt->len; int error; while (line_len > 0) { error = git_pkt_parse_line(&pkt, line, &line_end, line_len); if (error < 0) return error; /* Advance in the buffer */ line_len -= (line_end - line); line = line_end; error = add_push_report_pkt(push, pkt); git_pkt_free(pkt); if (error < 0 && error != GIT_ITEROVER) return error; } return 0; } static int parse_report(gitno_buffer *buf, git_push *push) { git_pkt *pkt = NULL; const char *line_end = NULL; int error, recvd; for (;;) { if (buf->offset > 0) error = git_pkt_parse_line(&pkt, buf->data, &line_end, buf->offset); else error = GIT_EBUFS; if (error < 0 && error != GIT_EBUFS) return -1; if (error == GIT_EBUFS) { if ((recvd = gitno_recv(buf)) < 0) return -1; if (recvd == 0) { giterr_set(GITERR_NET, "Early EOF"); return -1; } continue; } gitno_consume(buf, line_end); error = 0; switch (pkt->type) { case GIT_PKT_DATA: /* This is a sideband packet which contains other packets */ error = add_push_report_sideband_pkt(push, (git_pkt_data *)pkt); break; case GIT_PKT_ERR: giterr_set(GITERR_NET, "report-status: Error reported: %s", ((git_pkt_err *)pkt)->error); error = -1; break; case GIT_PKT_PROGRESS: break; default: error = add_push_report_pkt(push, pkt); break; } git_pkt_free(pkt); /* add_push_report_pkt returns GIT_ITEROVER when it receives a flush */ if (error == GIT_ITEROVER) return 0; if (error < 0) return error; } } static int add_ref_from_push_spec(git_vector *refs, push_spec *push_spec) { git_pkt_ref *added = git__calloc(1, sizeof(git_pkt_ref)); GITERR_CHECK_ALLOC(added); added->type = GIT_PKT_REF; git_oid_cpy(&added->head.oid, &push_spec->loid); added->head.name = git__strdup(push_spec->rref); if (!added->head.name || git_vector_insert(refs, added) < 0) { git_pkt_free((git_pkt *)added); return -1; } return 0; } static int update_refs_from_report( git_vector *refs, git_vector *push_specs, git_vector *push_report) { git_pkt_ref *ref; push_spec *push_spec; push_status *push_status; size_t i, j, refs_len; int cmp; /* For each push spec we sent to the server, we should have * gotten back a status packet in the push report */ if (push_specs->length != push_report->length) { giterr_set(GITERR_NET, "report-status: protocol error"); return -1; } /* We require that push_specs be sorted with push_spec_rref_cmp, * and that push_report be sorted with push_status_ref_cmp */ git_vector_sort(push_specs); git_vector_sort(push_report); git_vector_foreach(push_specs, i, push_spec) { push_status = git_vector_get(push_report, i); /* For each push spec we sent to the server, we should have * gotten back a status packet in the push report which matches */ if (strcmp(push_spec->rref, push_status->ref)) { giterr_set(GITERR_NET, "report-status: protocol error"); return -1; } } /* We require that refs be sorted with ref_name_cmp */ git_vector_sort(refs); i = j = 0; refs_len = refs->length; /* Merge join push_specs with refs */ while (i < push_specs->length && j < refs_len) { push_spec = git_vector_get(push_specs, i); push_status = git_vector_get(push_report, i); ref = git_vector_get(refs, j); cmp = strcmp(push_spec->rref, ref->head.name); /* Iterate appropriately */ if (cmp <= 0) i++; if (cmp >= 0) j++; /* Add case */ if (cmp < 0 && !push_status->msg && add_ref_from_push_spec(refs, push_spec) < 0) return -1; /* Update case, delete case */ if (cmp == 0 && !push_status->msg) git_oid_cpy(&ref->head.oid, &push_spec->loid); } for (; i < push_specs->length; i++) { push_spec = git_vector_get(push_specs, i); push_status = git_vector_get(push_report, i); /* Add case */ if (!push_status->msg && add_ref_from_push_spec(refs, push_spec) < 0) return -1; } /* Remove any refs which we updated to have a zero OID. */ git_vector_rforeach(refs, i, ref) { if (git_oid_iszero(&ref->head.oid)) { git_vector_remove(refs, i); git_pkt_free((git_pkt *)ref); } } git_vector_sort(refs); return 0; } static int stream_thunk(void *buf, size_t size, void *data) { git_smart_subtransport_stream *s = (git_smart_subtransport_stream *)data; return s->write(s, (const char *)buf, size); } int git_smart__push(git_transport *transport, git_push *push) { transport_smart *t = (transport_smart *)transport; git_smart_subtransport_stream *s; git_buf pktline = GIT_BUF_INIT; int error = -1, need_pack = 0; push_spec *spec; unsigned int i; #ifdef PUSH_DEBUG { git_remote_head *head; char hex[41]; hex[40] = '\0'; git_vector_foreach(&push->remote->refs, i, head) { git_oid_fmt(hex, &head->oid); fprintf(stderr, "%s (%s)\n", hex, head->name); } git_vector_foreach(&push->specs, i, spec) { git_oid_fmt(hex, &spec->roid); fprintf(stderr, "%s (%s) -> ", hex, spec->lref); git_oid_fmt(hex, &spec->loid); fprintf(stderr, "%s (%s)\n", hex, spec->rref ? spec->rref : spec->lref); } } #endif /* * Figure out if we need to send a packfile; which is in all * cases except when we only send delete commands */ git_vector_foreach(&push->specs, i, spec) { if (spec->lref) { need_pack = 1; break; } } if (git_smart__get_push_stream(t, &s) < 0 || gen_pktline(&pktline, push) < 0 || s->write(s, git_buf_cstr(&pktline), git_buf_len(&pktline)) < 0) goto on_error; if (need_pack && git_packbuilder_foreach(push->pb, &stream_thunk, s) < 0) goto on_error; /* If we sent nothing or the server doesn't support report-status, then * we consider the pack to have been unpacked successfully */ if (!push->specs.length || !push->report_status) push->unpack_ok = 1; else if (parse_report(&t->buffer, push) < 0) goto on_error; if (push->status.length && update_refs_from_report(&t->refs, &push->specs, &push->status) < 0) goto on_error; error = 0; on_error: git_buf_free(&pktline); return error; } libgit2-0.19.0/src/transports/ssh.c000066400000000000000000000234561216214232500171140ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #ifdef GIT_SSH #include "git2.h" #include "buffer.h" #include "netops.h" #include "smart.h" #include #define OWNING_SUBTRANSPORT(s) ((ssh_subtransport *)(s)->parent.subtransport) static const char prefix_ssh[] = "ssh://"; static const char default_user[] = "git"; static const char cmd_uploadpack[] = "git-upload-pack"; static const char cmd_receivepack[] = "git-receive-pack"; typedef struct { git_smart_subtransport_stream parent; gitno_socket socket; LIBSSH2_SESSION *session; LIBSSH2_CHANNEL *channel; const char *cmd; char *url; unsigned sent_command : 1; } ssh_stream; typedef struct { git_smart_subtransport parent; transport_smart *owner; ssh_stream *current_stream; git_cred *cred; } ssh_subtransport; /* * Create a git protocol request. * * For example: git-upload-pack '/libgit2/libgit2' */ static int gen_proto(git_buf *request, const char *cmd, const char *url) { char *repo; if (!git__prefixcmp(url, prefix_ssh)) { url = url + strlen(prefix_ssh); repo = strchr(url, '/'); } else { repo = strchr(url, ':'); } if (!repo) { return -1; } int len = strlen(cmd) + 1 /* Space */ + 1 /* Quote */ + strlen(repo) + 1 /* Quote */ + 1; git_buf_grow(request, len); git_buf_printf(request, "%s '%s'", cmd, repo); git_buf_putc(request, '\0'); if (git_buf_oom(request)) return -1; return 0; } static int send_command(ssh_stream *s) { int error; git_buf request = GIT_BUF_INIT; error = gen_proto(&request, s->cmd, s->url); if (error < 0) goto cleanup; error = libssh2_channel_exec( s->channel, request.ptr ); if (0 != error) goto cleanup; s->sent_command = 1; cleanup: git_buf_free(&request); return error; } static int ssh_stream_read( git_smart_subtransport_stream *stream, char *buffer, size_t buf_size, size_t *bytes_read) { ssh_stream *s = (ssh_stream *)stream; *bytes_read = 0; if (!s->sent_command && send_command(s) < 0) return -1; int rc = libssh2_channel_read(s->channel, buffer, buf_size); if (rc < 0) return -1; *bytes_read = rc; return 0; } static int ssh_stream_write( git_smart_subtransport_stream *stream, const char *buffer, size_t len) { ssh_stream *s = (ssh_stream *)stream; if (!s->sent_command && send_command(s) < 0) return -1; int rc = libssh2_channel_write(s->channel, buffer, len); if (rc < 0) { return -1; } return rc; } static void ssh_stream_free(git_smart_subtransport_stream *stream) { ssh_stream *s = (ssh_stream *)stream; ssh_subtransport *t = OWNING_SUBTRANSPORT(s); int ret; GIT_UNUSED(ret); t->current_stream = NULL; if (s->channel) { libssh2_channel_close(s->channel); libssh2_channel_free(s->channel); s->channel = NULL; } if (s->session) { libssh2_session_free(s->session), s->session = NULL; } if (s->socket.socket) { ret = gitno_close(&s->socket); assert(!ret); } git__free(s->url); git__free(s); } static int ssh_stream_alloc( ssh_subtransport *t, const char *url, const char *cmd, git_smart_subtransport_stream **stream) { ssh_stream *s; if (!stream) return -1; s = git__calloc(sizeof(ssh_stream), 1); GITERR_CHECK_ALLOC(s); s->parent.subtransport = &t->parent; s->parent.read = ssh_stream_read; s->parent.write = ssh_stream_write; s->parent.free = ssh_stream_free; s->cmd = cmd; s->url = git__strdup(url); if (!s->url) { git__free(s); return -1; } *stream = &s->parent; return 0; } static int git_ssh_extract_url_parts( char **host, char **username, const char *url) { char *colon, *at; const char *start; colon = strchr(url, ':'); if (colon == NULL) { giterr_set(GITERR_NET, "Malformed URL: missing :"); return -1; } at = strchr(url, '@'); if (at) { start = at+1; *username = git__substrdup(url, at - url); } else { start = url; *username = git__strdup(default_user); } *host = git__substrdup(start, colon - start); return 0; } static int _git_ssh_authenticate_session( LIBSSH2_SESSION* session, const char *user, git_cred* cred ) { int rc; do { switch (cred->credtype) { case GIT_CREDTYPE_USERPASS_PLAINTEXT: { git_cred_userpass_plaintext *c = (git_cred_userpass_plaintext *)cred; rc = libssh2_userauth_password( session, c->username, c->password ); break; } case GIT_CREDTYPE_SSH_KEYFILE_PASSPHRASE: { git_cred_ssh_keyfile_passphrase *c = (git_cred_ssh_keyfile_passphrase *)cred; rc = libssh2_userauth_publickey_fromfile( session, user, c->publickey, c->privatekey, c->passphrase ); break; } case GIT_CREDTYPE_SSH_PUBLICKEY: { git_cred_ssh_publickey *c = (git_cred_ssh_publickey *)cred; rc = libssh2_userauth_publickey( session, user, (const unsigned char *)c->publickey, c->publickey_len, c->sign_callback, &c->sign_data ); break; } default: rc = LIBSSH2_ERROR_AUTHENTICATION_FAILED; } } while (LIBSSH2_ERROR_EAGAIN == rc || LIBSSH2_ERROR_TIMEOUT == rc); return rc; } static int _git_ssh_session_create ( LIBSSH2_SESSION** session, gitno_socket socket ) { if (!session) { return -1; } LIBSSH2_SESSION* s = libssh2_session_init(); if (!s) return -1; int rc = 0; do { rc = libssh2_session_startup(s, socket.socket); } while (LIBSSH2_ERROR_EAGAIN == rc || LIBSSH2_ERROR_TIMEOUT == rc); if (0 != rc) { goto on_error; } libssh2_session_set_blocking(s, 1); *session = s; return 0; on_error: if (s) { libssh2_session_free(s), s = NULL; } return -1; } static int _git_ssh_setup_conn( ssh_subtransport *t, const char *url, const char *cmd, git_smart_subtransport_stream **stream ) { char *host, *port=NULL, *user=NULL, *pass=NULL; const char *default_port="22"; ssh_stream *s; LIBSSH2_SESSION* session=NULL; LIBSSH2_CHANNEL* channel=NULL; *stream = NULL; if (ssh_stream_alloc(t, url, cmd, stream) < 0) return -1; s = (ssh_stream *)*stream; if (!git__prefixcmp(url, prefix_ssh)) { url = url + strlen(prefix_ssh); if (gitno_extract_url_parts(&host, &port, &user, &pass, url, default_port) < 0) goto on_error; } else { if (git_ssh_extract_url_parts(&host, &user, url) < 0) goto on_error; port = git__strdup(default_port); GITERR_CHECK_ALLOC(port); } if (gitno_connect(&s->socket, host, port, 0) < 0) goto on_error; if (user && pass) { if (git_cred_userpass_plaintext_new(&t->cred, user, pass) < 0) goto on_error; } else { if (t->owner->cred_acquire_cb(&t->cred, t->owner->url, user, GIT_CREDTYPE_USERPASS_PLAINTEXT | GIT_CREDTYPE_SSH_KEYFILE_PASSPHRASE, t->owner->cred_acquire_payload) < 0) return -1; } assert(t->cred); if (!user) { user = git__strdup(default_user); } if (_git_ssh_session_create(&session, s->socket) < 0) goto on_error; if (_git_ssh_authenticate_session(session, user, t->cred) < 0) goto on_error; channel = libssh2_channel_open_session(session); if (!channel) goto on_error; libssh2_channel_set_blocking(channel, 1); s->session = session; s->channel = channel; t->current_stream = s; git__free(host); git__free(port); git__free(user); git__free(pass); return 0; on_error: if (*stream) ssh_stream_free(*stream); git__free(host); git__free(port); git__free(user); git__free(pass); if (session) libssh2_session_free(session), session = NULL; return -1; } static int ssh_uploadpack_ls( ssh_subtransport *t, const char *url, git_smart_subtransport_stream **stream) { if (_git_ssh_setup_conn(t, url, cmd_uploadpack, stream) < 0) return -1; return 0; } static int ssh_uploadpack( ssh_subtransport *t, const char *url, git_smart_subtransport_stream **stream) { GIT_UNUSED(url); if (t->current_stream) { *stream = &t->current_stream->parent; return 0; } giterr_set(GITERR_NET, "Must call UPLOADPACK_LS before UPLOADPACK"); return -1; } static int ssh_receivepack_ls( ssh_subtransport *t, const char *url, git_smart_subtransport_stream **stream) { if (_git_ssh_setup_conn(t, url, cmd_receivepack, stream) < 0) return -1; return 0; } static int ssh_receivepack( ssh_subtransport *t, const char *url, git_smart_subtransport_stream **stream) { GIT_UNUSED(url); if (t->current_stream) { *stream = &t->current_stream->parent; return 0; } giterr_set(GITERR_NET, "Must call RECEIVEPACK_LS before RECEIVEPACK"); return -1; } static int _ssh_action( git_smart_subtransport_stream **stream, git_smart_subtransport *subtransport, const char *url, git_smart_service_t action) { ssh_subtransport *t = (ssh_subtransport *) subtransport; switch (action) { case GIT_SERVICE_UPLOADPACK_LS: return ssh_uploadpack_ls(t, url, stream); case GIT_SERVICE_UPLOADPACK: return ssh_uploadpack(t, url, stream); case GIT_SERVICE_RECEIVEPACK_LS: return ssh_receivepack_ls(t, url, stream); case GIT_SERVICE_RECEIVEPACK: return ssh_receivepack(t, url, stream); } *stream = NULL; return -1; } static int _ssh_close(git_smart_subtransport *subtransport) { ssh_subtransport *t = (ssh_subtransport *) subtransport; assert(!t->current_stream); GIT_UNUSED(t); return 0; } static void _ssh_free(git_smart_subtransport *subtransport) { ssh_subtransport *t = (ssh_subtransport *) subtransport; assert(!t->current_stream); git__free(t); } int git_smart_subtransport_ssh(git_smart_subtransport **out, git_transport *owner) { ssh_subtransport *t; if (!out) return -1; t = git__calloc(sizeof(ssh_subtransport), 1); GITERR_CHECK_ALLOC(t); t->owner = (transport_smart *)owner; t->parent.action = _ssh_action; t->parent.close = _ssh_close; t->parent.free = _ssh_free; *out = (git_smart_subtransport *) t; return 0; } #endif libgit2-0.19.0/src/transports/winhttp.c000066400000000000000000000656641216214232500200230ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #ifdef GIT_WINHTTP #include "git2.h" #include "git2/transport.h" #include "buffer.h" #include "posix.h" #include "netops.h" #include "smart.h" #include "remote.h" #include "repository.h" #include #pragma comment(lib, "winhttp") #include /* For UuidCreate */ #pragma comment(lib, "rpcrt4") #define WIDEN2(s) L ## s #define WIDEN(s) WIDEN2(s) #define MAX_CONTENT_TYPE_LEN 100 #define WINHTTP_OPTION_PEERDIST_EXTENSION_STATE 109 #define CACHED_POST_BODY_BUF_SIZE 4096 #define UUID_LENGTH_CCH 32 static const char *prefix_http = "http://"; static const char *prefix_https = "https://"; static const char *upload_pack_service = "upload-pack"; static const char *upload_pack_ls_service_url = "/info/refs?service=git-upload-pack"; static const char *upload_pack_service_url = "/git-upload-pack"; static const char *receive_pack_service = "receive-pack"; static const char *receive_pack_ls_service_url = "/info/refs?service=git-receive-pack"; static const char *receive_pack_service_url = "/git-receive-pack"; static const wchar_t *get_verb = L"GET"; static const wchar_t *post_verb = L"POST"; static const wchar_t *pragma_nocache = L"Pragma: no-cache"; static const wchar_t *transfer_encoding = L"Transfer-Encoding: chunked"; static const int no_check_cert_flags = SECURITY_FLAG_IGNORE_CERT_CN_INVALID | SECURITY_FLAG_IGNORE_CERT_DATE_INVALID | SECURITY_FLAG_IGNORE_UNKNOWN_CA; #define OWNING_SUBTRANSPORT(s) ((winhttp_subtransport *)(s)->parent.subtransport) typedef enum { GIT_WINHTTP_AUTH_BASIC = 1, } winhttp_authmechanism_t; typedef struct { git_smart_subtransport_stream parent; const char *service; const char *service_url; const wchar_t *verb; HINTERNET request; wchar_t *request_uri; char *chunk_buffer; unsigned chunk_buffer_len; HANDLE post_body; DWORD post_body_len; unsigned sent_request : 1, received_response : 1, chunked : 1; } winhttp_stream; typedef struct { git_smart_subtransport parent; transport_smart *owner; const char *path; char *host; char *port; char *user_from_url; char *pass_from_url; git_cred *cred; git_cred *url_cred; int auth_mechanism; HINTERNET session; HINTERNET connection; unsigned use_ssl : 1; } winhttp_subtransport; static int apply_basic_credential(HINTERNET request, git_cred *cred) { git_cred_userpass_plaintext *c = (git_cred_userpass_plaintext *)cred; git_buf buf = GIT_BUF_INIT, raw = GIT_BUF_INIT; wchar_t *wide = NULL; int error = -1, wide_len = 0; git_buf_printf(&raw, "%s:%s", c->username, c->password); if (git_buf_oom(&raw) || git_buf_puts(&buf, "Authorization: Basic ") < 0 || git_buf_put_base64(&buf, git_buf_cstr(&raw), raw.size) < 0) goto on_error; wide_len = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, git_buf_cstr(&buf), -1, NULL, 0); if (!wide_len) { giterr_set(GITERR_OS, "Failed to measure string for wide conversion"); goto on_error; } wide = git__malloc(wide_len * sizeof(wchar_t)); if (!wide) goto on_error; if (!MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, git_buf_cstr(&buf), -1, wide, wide_len)) { giterr_set(GITERR_OS, "Failed to convert string to wide form"); goto on_error; } if (!WinHttpAddRequestHeaders(request, wide, (ULONG) -1L, WINHTTP_ADDREQ_FLAG_ADD)) { giterr_set(GITERR_OS, "Failed to add a header to the request"); goto on_error; } error = 0; on_error: /* We were dealing with plaintext passwords, so clean up after ourselves a bit. */ if (wide) memset(wide, 0x0, wide_len * sizeof(wchar_t)); if (buf.size) memset(buf.ptr, 0x0, buf.size); if (raw.size) memset(raw.ptr, 0x0, raw.size); git__free(wide); git_buf_free(&buf); git_buf_free(&raw); return error; } static int winhttp_stream_connect(winhttp_stream *s) { winhttp_subtransport *t = OWNING_SUBTRANSPORT(s); git_buf buf = GIT_BUF_INIT; char *proxy_url = NULL; wchar_t ct[MAX_CONTENT_TYPE_LEN]; wchar_t *types[] = { L"*/*", NULL }; BOOL peerdist = FALSE; int error = -1, wide_len; /* Prepare URL */ git_buf_printf(&buf, "%s%s", t->path, s->service_url); if (git_buf_oom(&buf)) return -1; /* Convert URL to wide characters */ wide_len = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, git_buf_cstr(&buf), -1, NULL, 0); if (!wide_len) { giterr_set(GITERR_OS, "Failed to measure string for wide conversion"); goto on_error; } s->request_uri = git__malloc(wide_len * sizeof(wchar_t)); if (!s->request_uri) goto on_error; if (!MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, git_buf_cstr(&buf), -1, s->request_uri, wide_len)) { giterr_set(GITERR_OS, "Failed to convert string to wide form"); goto on_error; } /* Establish request */ s->request = WinHttpOpenRequest( t->connection, s->verb, s->request_uri, NULL, WINHTTP_NO_REFERER, types, t->use_ssl ? WINHTTP_FLAG_SECURE : 0); if (!s->request) { giterr_set(GITERR_OS, "Failed to open request"); goto on_error; } /* Set proxy if necessary */ if (git_remote__get_http_proxy(t->owner->owner, t->use_ssl, &proxy_url) < 0) goto on_error; if (proxy_url) { WINHTTP_PROXY_INFO proxy_info; wchar_t *proxy_wide; /* Convert URL to wide characters */ wide_len = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, proxy_url, -1, NULL, 0); if (!wide_len) { giterr_set(GITERR_OS, "Failed to measure string for wide conversion"); goto on_error; } proxy_wide = git__malloc(wide_len * sizeof(wchar_t)); if (!proxy_wide) goto on_error; if (!MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, proxy_url, -1, proxy_wide, wide_len)) { giterr_set(GITERR_OS, "Failed to convert string to wide form"); git__free(proxy_wide); goto on_error; } /* Strip any trailing forward slash on the proxy URL; * WinHTTP doesn't like it if one is present */ if (wide_len > 1 && L'/' == proxy_wide[wide_len - 2]) proxy_wide[wide_len - 2] = L'\0'; proxy_info.dwAccessType = WINHTTP_ACCESS_TYPE_NAMED_PROXY; proxy_info.lpszProxy = proxy_wide; proxy_info.lpszProxyBypass = NULL; if (!WinHttpSetOption(s->request, WINHTTP_OPTION_PROXY, &proxy_info, sizeof(WINHTTP_PROXY_INFO))) { giterr_set(GITERR_OS, "Failed to set proxy"); git__free(proxy_wide); goto on_error; } git__free(proxy_wide); } /* Strip unwanted headers (X-P2P-PeerDist, X-P2P-PeerDistEx) that WinHTTP * adds itself. This option may not be supported by the underlying * platform, so we do not error-check it */ WinHttpSetOption(s->request, WINHTTP_OPTION_PEERDIST_EXTENSION_STATE, &peerdist, sizeof(peerdist)); /* Send Pragma: no-cache header */ if (!WinHttpAddRequestHeaders(s->request, pragma_nocache, (ULONG) -1L, WINHTTP_ADDREQ_FLAG_ADD)) { giterr_set(GITERR_OS, "Failed to add a header to the request"); goto on_error; } /* Send Content-Type header -- only necessary on a POST */ if (post_verb == s->verb) { git_buf_clear(&buf); if (git_buf_printf(&buf, "Content-Type: application/x-git-%s-request", s->service) < 0) goto on_error; git__utf8_to_16(ct, MAX_CONTENT_TYPE_LEN, git_buf_cstr(&buf)); if (!WinHttpAddRequestHeaders(s->request, ct, (ULONG) -1L, WINHTTP_ADDREQ_FLAG_ADD)) { giterr_set(GITERR_OS, "Failed to add a header to the request"); goto on_error; } } /* If requested, disable certificate validation */ if (t->use_ssl) { int flags; if (t->owner->parent.read_flags(&t->owner->parent, &flags) < 0) goto on_error; if ((GIT_TRANSPORTFLAGS_NO_CHECK_CERT & flags) && !WinHttpSetOption(s->request, WINHTTP_OPTION_SECURITY_FLAGS, (LPVOID)&no_check_cert_flags, sizeof(no_check_cert_flags))) { giterr_set(GITERR_OS, "Failed to set options to ignore cert errors"); goto on_error; } } /* If we have a credential on the subtransport, apply it to the request */ if (t->cred && t->cred->credtype == GIT_CREDTYPE_USERPASS_PLAINTEXT && t->auth_mechanism == GIT_WINHTTP_AUTH_BASIC && apply_basic_credential(s->request, t->cred) < 0) goto on_error; /* If no other credentials have been applied and the URL has username and * password, use those */ if (!t->cred && t->user_from_url && t->pass_from_url) { if (!t->url_cred && git_cred_userpass_plaintext_new(&t->url_cred, t->user_from_url, t->pass_from_url) < 0) goto on_error; if (apply_basic_credential(s->request, t->url_cred) < 0) goto on_error; } /* We've done everything up to calling WinHttpSendRequest. */ error = 0; on_error: git__free(proxy_url); git_buf_free(&buf); return error; } static int parse_unauthorized_response( HINTERNET request, int *allowed_types, int *auth_mechanism) { DWORD supported, first, target; *allowed_types = 0; *auth_mechanism = 0; /* WinHttpQueryHeaders() must be called before WinHttpQueryAuthSchemes(). * We can assume this was already done, since we know we are unauthorized. */ if (!WinHttpQueryAuthSchemes(request, &supported, &first, &target)) { giterr_set(GITERR_OS, "Failed to parse supported auth schemes"); return -1; } if (WINHTTP_AUTH_SCHEME_BASIC & supported) { *allowed_types |= GIT_CREDTYPE_USERPASS_PLAINTEXT; *auth_mechanism = GIT_WINHTTP_AUTH_BASIC; } return 0; } static int write_chunk(HINTERNET request, const char *buffer, size_t len) { DWORD bytes_written; git_buf buf = GIT_BUF_INIT; /* Chunk header */ git_buf_printf(&buf, "%X\r\n", len); if (git_buf_oom(&buf)) return -1; if (!WinHttpWriteData(request, git_buf_cstr(&buf), (DWORD)git_buf_len(&buf), &bytes_written)) { git_buf_free(&buf); giterr_set(GITERR_OS, "Failed to write chunk header"); return -1; } git_buf_free(&buf); /* Chunk body */ if (!WinHttpWriteData(request, buffer, (DWORD)len, &bytes_written)) { giterr_set(GITERR_OS, "Failed to write chunk"); return -1; } /* Chunk footer */ if (!WinHttpWriteData(request, "\r\n", 2, &bytes_written)) { giterr_set(GITERR_OS, "Failed to write chunk footer"); return -1; } return 0; } static int winhttp_stream_read( git_smart_subtransport_stream *stream, char *buffer, size_t buf_size, size_t *bytes_read) { winhttp_stream *s = (winhttp_stream *)stream; winhttp_subtransport *t = OWNING_SUBTRANSPORT(s); DWORD dw_bytes_read; char replay_count = 0; replay: /* Enforce a reasonable cap on the number of replays */ if (++replay_count >= 7) { giterr_set(GITERR_NET, "Too many redirects or authentication replays"); return -1; } /* Connect if necessary */ if (!s->request && winhttp_stream_connect(s) < 0) return -1; if (!s->received_response) { DWORD status_code, status_code_length, content_type_length, bytes_written; char expected_content_type_8[MAX_CONTENT_TYPE_LEN]; wchar_t expected_content_type[MAX_CONTENT_TYPE_LEN], content_type[MAX_CONTENT_TYPE_LEN]; if (!s->sent_request) { if (!WinHttpSendRequest(s->request, WINHTTP_NO_ADDITIONAL_HEADERS, 0, WINHTTP_NO_REQUEST_DATA, 0, s->post_body_len, 0)) { giterr_set(GITERR_OS, "Failed to send request"); return -1; } s->sent_request = 1; } if (s->chunked) { assert(s->verb == post_verb); /* Flush, if necessary */ if (s->chunk_buffer_len > 0 && write_chunk(s->request, s->chunk_buffer, s->chunk_buffer_len) < 0) return -1; s->chunk_buffer_len = 0; /* Write the final chunk. */ if (!WinHttpWriteData(s->request, "0\r\n\r\n", 5, &bytes_written)) { giterr_set(GITERR_OS, "Failed to write final chunk"); return -1; } } else if (s->post_body) { char *buffer; DWORD len = s->post_body_len, bytes_read; if (INVALID_SET_FILE_POINTER == SetFilePointer(s->post_body, 0, 0, FILE_BEGIN) && NO_ERROR != GetLastError()) { giterr_set(GITERR_OS, "Failed to reset file pointer"); return -1; } buffer = git__malloc(CACHED_POST_BODY_BUF_SIZE); while (len > 0) { DWORD bytes_written; if (!ReadFile(s->post_body, buffer, min(CACHED_POST_BODY_BUF_SIZE, len), &bytes_read, NULL) || !bytes_read) { git__free(buffer); giterr_set(GITERR_OS, "Failed to read from temp file"); return -1; } if (!WinHttpWriteData(s->request, buffer, bytes_read, &bytes_written)) { git__free(buffer); giterr_set(GITERR_OS, "Failed to write data"); return -1; } len -= bytes_read; assert(bytes_read == bytes_written); } git__free(buffer); /* Eagerly close the temp file */ CloseHandle(s->post_body); s->post_body = NULL; } if (!WinHttpReceiveResponse(s->request, 0)) { giterr_set(GITERR_OS, "Failed to receive response"); return -1; } /* Verify that we got a 200 back */ status_code_length = sizeof(status_code); if (!WinHttpQueryHeaders(s->request, WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER, WINHTTP_HEADER_NAME_BY_INDEX, &status_code, &status_code_length, WINHTTP_NO_HEADER_INDEX)) { giterr_set(GITERR_OS, "Failed to retrieve status code"); return -1; } /* The implementation of WinHTTP prior to Windows 7 will not * redirect to an identical URI. Some Git hosters use self-redirects * as part of their DoS mitigation strategy. Check first to see if we * have a redirect status code, and that we haven't already streamed * a post body. (We can't replay a streamed POST.) */ if (!s->chunked && (HTTP_STATUS_MOVED == status_code || HTTP_STATUS_REDIRECT == status_code || (HTTP_STATUS_REDIRECT_METHOD == status_code && get_verb == s->verb) || HTTP_STATUS_REDIRECT_KEEP_VERB == status_code)) { /* Check for Windows 7. This workaround is only necessary on * Windows Vista and earlier. Windows 7 is version 6.1. */ if (!git_has_win32_version(6, 1)) { wchar_t *location; DWORD location_length; int redirect_cmp; /* OK, fetch the Location header from the redirect. */ if (WinHttpQueryHeaders(s->request, WINHTTP_QUERY_LOCATION, WINHTTP_HEADER_NAME_BY_INDEX, WINHTTP_NO_OUTPUT_BUFFER, &location_length, WINHTTP_NO_HEADER_INDEX) || GetLastError() != ERROR_INSUFFICIENT_BUFFER) { giterr_set(GITERR_OS, "Failed to read Location header"); return -1; } location = git__malloc(location_length); GITERR_CHECK_ALLOC(location); if (!WinHttpQueryHeaders(s->request, WINHTTP_QUERY_LOCATION, WINHTTP_HEADER_NAME_BY_INDEX, location, &location_length, WINHTTP_NO_HEADER_INDEX)) { giterr_set(GITERR_OS, "Failed to read Location header"); git__free(location); return -1; } /* Compare the Location header with the request URI */ redirect_cmp = wcscmp(location, s->request_uri); git__free(location); if (!redirect_cmp) { /* Replay the request */ WinHttpCloseHandle(s->request); s->request = NULL; s->sent_request = 0; goto replay; } } } /* Handle authentication failures */ if (HTTP_STATUS_DENIED == status_code && get_verb == s->verb && t->owner->cred_acquire_cb) { int allowed_types; if (parse_unauthorized_response(s->request, &allowed_types, &t->auth_mechanism) < 0) return -1; if (allowed_types && (!t->cred || 0 == (t->cred->credtype & allowed_types))) { if (t->owner->cred_acquire_cb(&t->cred, t->owner->url, t->user_from_url, allowed_types, t->owner->cred_acquire_payload) < 0) return -1; assert(t->cred); WinHttpCloseHandle(s->request); s->request = NULL; s->sent_request = 0; /* Successfully acquired a credential */ goto replay; } } if (HTTP_STATUS_OK != status_code) { giterr_set(GITERR_NET, "Request failed with status code: %d", status_code); return -1; } /* Verify that we got the correct content-type back */ if (post_verb == s->verb) snprintf(expected_content_type_8, MAX_CONTENT_TYPE_LEN, "application/x-git-%s-result", s->service); else snprintf(expected_content_type_8, MAX_CONTENT_TYPE_LEN, "application/x-git-%s-advertisement", s->service); git__utf8_to_16(expected_content_type, MAX_CONTENT_TYPE_LEN, expected_content_type_8); content_type_length = sizeof(content_type); if (!WinHttpQueryHeaders(s->request, WINHTTP_QUERY_CONTENT_TYPE, WINHTTP_HEADER_NAME_BY_INDEX, &content_type, &content_type_length, WINHTTP_NO_HEADER_INDEX)) { giterr_set(GITERR_OS, "Failed to retrieve response content-type"); return -1; } if (wcscmp(expected_content_type, content_type)) { giterr_set(GITERR_NET, "Received unexpected content-type"); return -1; } s->received_response = 1; } if (!WinHttpReadData(s->request, (LPVOID)buffer, (DWORD)buf_size, &dw_bytes_read)) { giterr_set(GITERR_OS, "Failed to read data"); return -1; } *bytes_read = dw_bytes_read; return 0; } static int winhttp_stream_write_single( git_smart_subtransport_stream *stream, const char *buffer, size_t len) { winhttp_stream *s = (winhttp_stream *)stream; winhttp_subtransport *t = OWNING_SUBTRANSPORT(s); DWORD bytes_written; if (!s->request && winhttp_stream_connect(s) < 0) return -1; /* This implementation of write permits only a single call. */ if (s->sent_request) { giterr_set(GITERR_NET, "Subtransport configured for only one write"); return -1; } if (!WinHttpSendRequest(s->request, WINHTTP_NO_ADDITIONAL_HEADERS, 0, WINHTTP_NO_REQUEST_DATA, 0, (DWORD)len, 0)) { giterr_set(GITERR_OS, "Failed to send request"); return -1; } s->sent_request = 1; if (!WinHttpWriteData(s->request, (LPCVOID)buffer, (DWORD)len, &bytes_written)) { giterr_set(GITERR_OS, "Failed to write data"); return -1; } assert((DWORD)len == bytes_written); return 0; } static int put_uuid_string(LPWSTR buffer, size_t buffer_len_cch) { UUID uuid; RPC_STATUS status = UuidCreate(&uuid); HRESULT result; if (RPC_S_OK != status && RPC_S_UUID_LOCAL_ONLY != status && RPC_S_UUID_NO_ADDRESS != status) { giterr_set(GITERR_NET, "Unable to generate name for temp file"); return -1; } if (buffer_len_cch < UUID_LENGTH_CCH + 1) { giterr_set(GITERR_NET, "Buffer too small for name of temp file"); return -1; } result = StringCbPrintfW( buffer, buffer_len_cch, L"%08x%04x%04x%02x%02x%02x%02x%02x%02x%02x%02x", uuid.Data1, uuid.Data2, uuid.Data3, uuid.Data4[0], uuid.Data4[1], uuid.Data4[2], uuid.Data4[3], uuid.Data4[4], uuid.Data4[5], uuid.Data4[6], uuid.Data4[7]); if (FAILED(result)) { giterr_set(GITERR_OS, "Unable to generate name for temp file"); return -1; } return 0; } static int get_temp_file(LPWSTR buffer, DWORD buffer_len_cch) { size_t len; if (!GetTempPathW(buffer_len_cch, buffer)) { giterr_set(GITERR_OS, "Failed to get temp path"); return -1; } len = wcslen(buffer); if (buffer[len - 1] != '\\' && len < buffer_len_cch) buffer[len++] = '\\'; if (put_uuid_string(&buffer[len], (size_t)buffer_len_cch - len) < 0) return -1; return 0; } static int winhttp_stream_write_buffered( git_smart_subtransport_stream *stream, const char *buffer, size_t len) { winhttp_stream *s = (winhttp_stream *)stream; winhttp_subtransport *t = OWNING_SUBTRANSPORT(s); DWORD bytes_written; if (!s->request && winhttp_stream_connect(s) < 0) return -1; /* Buffer the payload, using a temporary file so we delegate * memory management of the data to the operating system. */ if (!s->post_body) { wchar_t temp_path[MAX_PATH + 1]; if (get_temp_file(temp_path, MAX_PATH + 1) < 0) return -1; s->post_body = CreateFileW(temp_path, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_DELETE, NULL, CREATE_NEW, FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE | FILE_FLAG_SEQUENTIAL_SCAN, NULL); if (INVALID_HANDLE_VALUE == s->post_body) { s->post_body = NULL; giterr_set(GITERR_OS, "Failed to create temporary file"); return -1; } } if (!WriteFile(s->post_body, buffer, (DWORD)len, &bytes_written, NULL)) { giterr_set(GITERR_OS, "Failed to write to temporary file"); return -1; } assert((DWORD)len == bytes_written); s->post_body_len += bytes_written; return 0; } static int winhttp_stream_write_chunked( git_smart_subtransport_stream *stream, const char *buffer, size_t len) { winhttp_stream *s = (winhttp_stream *)stream; winhttp_subtransport *t = OWNING_SUBTRANSPORT(s); if (!s->request && winhttp_stream_connect(s) < 0) return -1; if (!s->sent_request) { /* Send Transfer-Encoding: chunked header */ if (!WinHttpAddRequestHeaders(s->request, transfer_encoding, (ULONG) -1L, WINHTTP_ADDREQ_FLAG_ADD)) { giterr_set(GITERR_OS, "Failed to add a header to the request"); return -1; } if (!WinHttpSendRequest(s->request, WINHTTP_NO_ADDITIONAL_HEADERS, 0, WINHTTP_NO_REQUEST_DATA, 0, WINHTTP_IGNORE_REQUEST_TOTAL_LENGTH, 0)) { giterr_set(GITERR_OS, "Failed to send request"); return -1; } s->sent_request = 1; } if (len > CACHED_POST_BODY_BUF_SIZE) { /* Flush, if necessary */ if (s->chunk_buffer_len > 0) { if (write_chunk(s->request, s->chunk_buffer, s->chunk_buffer_len) < 0) return -1; s->chunk_buffer_len = 0; } /* Write chunk directly */ if (write_chunk(s->request, buffer, len) < 0) return -1; } else { /* Append as much to the buffer as we can */ int count = min(CACHED_POST_BODY_BUF_SIZE - s->chunk_buffer_len, (int)len); if (!s->chunk_buffer) s->chunk_buffer = git__malloc(CACHED_POST_BODY_BUF_SIZE); memcpy(s->chunk_buffer + s->chunk_buffer_len, buffer, count); s->chunk_buffer_len += count; buffer += count; len -= count; /* Is the buffer full? If so, then flush */ if (CACHED_POST_BODY_BUF_SIZE == s->chunk_buffer_len) { if (write_chunk(s->request, s->chunk_buffer, s->chunk_buffer_len) < 0) return -1; s->chunk_buffer_len = 0; /* Is there any remaining data from the source? */ if (len > 0) { memcpy(s->chunk_buffer, buffer, len); s->chunk_buffer_len = (unsigned int)len; } } } return 0; } static void winhttp_stream_free(git_smart_subtransport_stream *stream) { winhttp_stream *s = (winhttp_stream *)stream; if (s->chunk_buffer) { git__free(s->chunk_buffer); s->chunk_buffer = NULL; } if (s->post_body) { CloseHandle(s->post_body); s->post_body = NULL; } if (s->request_uri) { git__free(s->request_uri); s->request_uri = NULL; } if (s->request) { WinHttpCloseHandle(s->request); s->request = NULL; } git__free(s); } static int winhttp_stream_alloc(winhttp_subtransport *t, winhttp_stream **stream) { winhttp_stream *s; if (!stream) return -1; s = git__calloc(sizeof(winhttp_stream), 1); GITERR_CHECK_ALLOC(s); s->parent.subtransport = &t->parent; s->parent.read = winhttp_stream_read; s->parent.write = winhttp_stream_write_single; s->parent.free = winhttp_stream_free; *stream = s; return 0; } static int winhttp_connect( winhttp_subtransport *t, const char *url) { wchar_t *ua = L"git/1.0 (libgit2 " WIDEN(LIBGIT2_VERSION) L")"; wchar_t host[GIT_WIN_PATH]; int32_t port; const char *default_port = "80"; int ret; if (!git__prefixcmp(url, prefix_http)) { url = url + strlen(prefix_http); default_port = "80"; } if (!git__prefixcmp(url, prefix_https)) { url += strlen(prefix_https); default_port = "443"; t->use_ssl = 1; } if ((ret = gitno_extract_url_parts(&t->host, &t->port, &t->user_from_url, &t->pass_from_url, url, default_port)) < 0) return ret; t->path = strchr(url, '/'); /* Prepare port */ if (git__strtol32(&port, t->port, NULL, 10) < 0) return -1; /* Prepare host */ git__utf8_to_16(host, GIT_WIN_PATH, t->host); /* Establish session */ t->session = WinHttpOpen( ua, WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0); if (!t->session) { giterr_set(GITERR_OS, "Failed to init WinHTTP"); return -1; } /* Establish connection */ t->connection = WinHttpConnect( t->session, host, port, 0); if (!t->connection) { giterr_set(GITERR_OS, "Failed to connect to host"); return -1; } return 0; } static int winhttp_uploadpack_ls( winhttp_subtransport *t, winhttp_stream *s) { s->service = upload_pack_service; s->service_url = upload_pack_ls_service_url; s->verb = get_verb; return 0; } static int winhttp_uploadpack( winhttp_subtransport *t, winhttp_stream *s) { s->service = upload_pack_service; s->service_url = upload_pack_service_url; s->verb = post_verb; return 0; } static int winhttp_receivepack_ls( winhttp_subtransport *t, winhttp_stream *s) { s->service = receive_pack_service; s->service_url = receive_pack_ls_service_url; s->verb = get_verb; return 0; } static int winhttp_receivepack( winhttp_subtransport *t, winhttp_stream *s) { /* WinHTTP only supports Transfer-Encoding: chunked * on Windows Vista (NT 6.0) and higher. */ s->chunked = git_has_win32_version(6, 0); if (s->chunked) s->parent.write = winhttp_stream_write_chunked; else s->parent.write = winhttp_stream_write_buffered; s->service = receive_pack_service; s->service_url = receive_pack_service_url; s->verb = post_verb; return 0; } static int winhttp_action( git_smart_subtransport_stream **stream, git_smart_subtransport *subtransport, const char *url, git_smart_service_t action) { winhttp_subtransport *t = (winhttp_subtransport *)subtransport; winhttp_stream *s; int ret = -1; if (!t->connection && winhttp_connect(t, url) < 0) return -1; if (winhttp_stream_alloc(t, &s) < 0) return -1; if (!stream) return -1; switch (action) { case GIT_SERVICE_UPLOADPACK_LS: ret = winhttp_uploadpack_ls(t, s); break; case GIT_SERVICE_UPLOADPACK: ret = winhttp_uploadpack(t, s); break; case GIT_SERVICE_RECEIVEPACK_LS: ret = winhttp_receivepack_ls(t, s); break; case GIT_SERVICE_RECEIVEPACK: ret = winhttp_receivepack(t, s); break; default: assert(0); } if (!ret) *stream = &s->parent; return ret; } static int winhttp_close(git_smart_subtransport *subtransport) { winhttp_subtransport *t = (winhttp_subtransport *)subtransport; int ret = 0; if (t->host) { git__free(t->host); t->host = NULL; } if (t->port) { git__free(t->port); t->port = NULL; } if (t->user_from_url) { git__free(t->user_from_url); t->user_from_url = NULL; } if (t->pass_from_url) { git__free(t->pass_from_url); t->pass_from_url = NULL; } if (t->cred) { t->cred->free(t->cred); t->cred = NULL; } if (t->url_cred) { t->url_cred->free(t->url_cred); t->url_cred = NULL; } if (t->connection) { if (!WinHttpCloseHandle(t->connection)) { giterr_set(GITERR_OS, "Unable to close connection"); ret = -1; } t->connection = NULL; } if (t->session) { if (!WinHttpCloseHandle(t->session)) { giterr_set(GITERR_OS, "Unable to close session"); ret = -1; } t->session = NULL; } return ret; } static void winhttp_free(git_smart_subtransport *subtransport) { winhttp_subtransport *t = (winhttp_subtransport *)subtransport; winhttp_close(subtransport); git__free(t); } int git_smart_subtransport_http(git_smart_subtransport **out, git_transport *owner) { winhttp_subtransport *t; if (!out) return -1; t = git__calloc(sizeof(winhttp_subtransport), 1); GITERR_CHECK_ALLOC(t); t->owner = (transport_smart *)owner; t->parent.action = winhttp_action; t->parent.close = winhttp_close; t->parent.free = winhttp_free; *out = (git_smart_subtransport *) t; return 0; } #endif /* GIT_WINHTTP */ libgit2-0.19.0/src/tree-cache.c000066400000000000000000000076561216214232500161040ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #include "tree-cache.h" static git_tree_cache *find_child(const git_tree_cache *tree, const char *path) { size_t i, dirlen; const char *end; end = strchr(path, '/'); if (end == NULL) { end = strrchr(path, '\0'); } dirlen = end - path; for (i = 0; i < tree->children_count; ++i) { const char *childname = tree->children[i]->name; if (strlen(childname) == dirlen && !memcmp(path, childname, dirlen)) return tree->children[i]; } return NULL; } void git_tree_cache_invalidate_path(git_tree_cache *tree, const char *path) { const char *ptr = path, *end; if (tree == NULL) return; tree->entries = -1; while (ptr != NULL) { end = strchr(ptr, '/'); if (end == NULL) /* End of path */ break; tree = find_child(tree, ptr); if (tree == NULL) /* We don't have that tree */ return; tree->entries = -1; ptr = end + 1; } } const git_tree_cache *git_tree_cache_get(const git_tree_cache *tree, const char *path) { const char *ptr = path, *end; if (tree == NULL) { return NULL; } while (1) { end = strchr(ptr, '/'); tree = find_child(tree, ptr); if (tree == NULL) { /* Can't find it */ return NULL; } if (end == NULL || *end + 1 == '\0') return tree; ptr = end + 1; } } static int read_tree_internal(git_tree_cache **out, const char **buffer_in, const char *buffer_end, git_tree_cache *parent) { git_tree_cache *tree = NULL; const char *name_start, *buffer; int count; size_t name_len; buffer = name_start = *buffer_in; if ((buffer = memchr(buffer, '\0', buffer_end - buffer)) == NULL) goto corrupted; if (++buffer >= buffer_end) goto corrupted; name_len = strlen(name_start); tree = git__malloc(sizeof(git_tree_cache) + name_len + 1); GITERR_CHECK_ALLOC(tree); memset(tree, 0x0, sizeof(git_tree_cache)); tree->parent = parent; /* NUL-terminated tree name */ memcpy(tree->name, name_start, name_len); tree->name[name_len] = '\0'; /* Blank-terminated ASCII decimal number of entries in this tree */ if (git__strtol32(&count, buffer, &buffer, 10) < 0) goto corrupted; tree->entries = count; if (*buffer != ' ' || ++buffer >= buffer_end) goto corrupted; /* Number of children of the tree, newline-terminated */ if (git__strtol32(&count, buffer, &buffer, 10) < 0 || count < 0) goto corrupted; tree->children_count = count; if (*buffer != '\n' || ++buffer > buffer_end) goto corrupted; /* The SHA1 is only there if it's not invalidated */ if (tree->entries >= 0) { /* 160-bit SHA-1 for this tree and it's children */ if (buffer + GIT_OID_RAWSZ > buffer_end) goto corrupted; git_oid_fromraw(&tree->oid, (const unsigned char *)buffer); buffer += GIT_OID_RAWSZ; } /* Parse children: */ if (tree->children_count > 0) { unsigned int i; tree->children = git__malloc(tree->children_count * sizeof(git_tree_cache *)); GITERR_CHECK_ALLOC(tree->children); for (i = 0; i < tree->children_count; ++i) { if (read_tree_internal(&tree->children[i], &buffer, buffer_end, tree) < 0) return -1; } } *buffer_in = buffer; *out = tree; return 0; corrupted: git_tree_cache_free(tree); giterr_set(GITERR_INDEX, "Corruped TREE extension in index"); return -1; } int git_tree_cache_read(git_tree_cache **tree, const char *buffer, size_t buffer_size) { const char *buffer_end = buffer + buffer_size; if (read_tree_internal(tree, &buffer, buffer_end, NULL) < 0) return -1; if (buffer < buffer_end) { giterr_set(GITERR_INDEX, "Corruped TREE extension in index (unexpected trailing data)"); return -1; } return 0; } void git_tree_cache_free(git_tree_cache *tree) { unsigned int i; if (tree == NULL) return; for (i = 0; i < tree->children_count; ++i) git_tree_cache_free(tree->children[i]); git__free(tree->children); git__free(tree); } libgit2-0.19.0/src/tree-cache.h000066400000000000000000000015321216214232500160740ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #ifndef INCLUDE_tree_cache_h__ #define INCLUDE_tree_cache_h__ #include "common.h" #include "git2/oid.h" struct git_tree_cache { struct git_tree_cache *parent; struct git_tree_cache **children; size_t children_count; ssize_t entries; git_oid oid; char name[GIT_FLEX_ARRAY]; }; typedef struct git_tree_cache git_tree_cache; int git_tree_cache_read(git_tree_cache **tree, const char *buffer, size_t buffer_size); void git_tree_cache_invalidate_path(git_tree_cache *tree, const char *path); const git_tree_cache *git_tree_cache_get(const git_tree_cache *tree, const char *path); void git_tree_cache_free(git_tree_cache *tree); #endif libgit2-0.19.0/src/tree.c000066400000000000000000000524631216214232500150370ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #include "common.h" #include "commit.h" #include "tree.h" #include "git2/repository.h" #include "git2/object.h" #include "path.h" #include "tree-cache.h" #include "index.h" #define DEFAULT_TREE_SIZE 16 #define MAX_FILEMODE_BYTES 6 static bool valid_filemode(const int filemode) { return (filemode == GIT_FILEMODE_TREE || filemode == GIT_FILEMODE_BLOB || filemode == GIT_FILEMODE_BLOB_EXECUTABLE || filemode == GIT_FILEMODE_LINK || filemode == GIT_FILEMODE_COMMIT); } GIT_INLINE(git_filemode_t) normalize_filemode(git_filemode_t filemode) { /* Tree bits set, but it's not a commit */ if (filemode & GIT_FILEMODE_TREE && !(filemode & 0100000)) return GIT_FILEMODE_TREE; /* If any of the x bits is set */ if (filemode & 0111) return GIT_FILEMODE_BLOB_EXECUTABLE; /* 16XXXX means commit */ if ((filemode & GIT_FILEMODE_COMMIT) == GIT_FILEMODE_COMMIT) return GIT_FILEMODE_COMMIT; /* 12XXXX means commit */ if ((filemode & GIT_FILEMODE_LINK) == GIT_FILEMODE_LINK) return GIT_FILEMODE_LINK; /* Otherwise, return a blob */ return GIT_FILEMODE_BLOB; } static int valid_entry_name(const char *filename) { return *filename != '\0' && strchr(filename, '/') == NULL && (*filename != '.' || (strcmp(filename, ".") != 0 && strcmp(filename, "..") != 0 && strcmp(filename, DOT_GIT) != 0)); } static int entry_sort_cmp(const void *a, const void *b) { const git_tree_entry *e1 = (const git_tree_entry *)a; const git_tree_entry *e2 = (const git_tree_entry *)b; return git_path_cmp( e1->filename, e1->filename_len, git_tree_entry__is_tree(e1), e2->filename, e2->filename_len, git_tree_entry__is_tree(e2), git__strncmp); } int git_tree_entry_cmp(const git_tree_entry *e1, const git_tree_entry *e2) { return entry_sort_cmp(e1, e2); } int git_tree_entry_icmp(const git_tree_entry *e1, const git_tree_entry *e2) { return git_path_cmp( e1->filename, e1->filename_len, git_tree_entry__is_tree(e1), e2->filename, e2->filename_len, git_tree_entry__is_tree(e2), git__strncasecmp); } static git_tree_entry *alloc_entry(const char *filename) { git_tree_entry *entry = NULL; size_t filename_len = strlen(filename); entry = git__malloc(sizeof(git_tree_entry) + filename_len + 1); if (!entry) return NULL; memset(entry, 0x0, sizeof(git_tree_entry)); memcpy(entry->filename, filename, filename_len); entry->filename[filename_len] = 0; entry->filename_len = filename_len; return entry; } struct tree_key_search { const char *filename; size_t filename_len; }; static int homing_search_cmp(const void *key, const void *array_member) { const struct tree_key_search *ksearch = key; const git_tree_entry *entry = array_member; const size_t len1 = ksearch->filename_len; const size_t len2 = entry->filename_len; return memcmp( ksearch->filename, entry->filename, len1 < len2 ? len1 : len2 ); } /* * Search for an entry in a given tree. * * Note that this search is performed in two steps because * of the way tree entries are sorted internally in git: * * Entries in a tree are not sorted alphabetically; two entries * with the same root prefix will have different positions * depending on whether they are folders (subtrees) or normal files. * * Consequently, it is not possible to find an entry on the tree * with a binary search if you don't know whether the filename * you're looking for is a folder or a normal file. * * To work around this, we first perform a homing binary search * on the tree, using the minimal length root prefix of our filename. * Once the comparisons for this homing search start becoming * ambiguous because of folder vs file sorting, we look linearly * around the area for our target file. */ static int tree_key_search( size_t *at_pos, git_vector *entries, const char *filename, size_t filename_len) { struct tree_key_search ksearch; const git_tree_entry *entry; size_t homing, i; ksearch.filename = filename; ksearch.filename_len = filename_len; /* Initial homing search; find an entry on the tree with * the same prefix as the filename we're looking for */ if (git_vector_bsearch2(&homing, entries, &homing_search_cmp, &ksearch) < 0) return GIT_ENOTFOUND; /* just a signal error; not passed back to user */ /* We found a common prefix. Look forward as long as * there are entries that share the common prefix */ for (i = homing; i < entries->length; ++i) { entry = entries->contents[i]; if (homing_search_cmp(&ksearch, entry) < 0) break; if (entry->filename_len == filename_len && memcmp(filename, entry->filename, filename_len) == 0) { if (at_pos) *at_pos = i; return 0; } } /* If we haven't found our filename yet, look backwards * too as long as we have entries with the same prefix */ if (homing > 0) { i = homing - 1; do { entry = entries->contents[i]; if (homing_search_cmp(&ksearch, entry) > 0) break; if (entry->filename_len == filename_len && memcmp(filename, entry->filename, filename_len) == 0) { if (at_pos) *at_pos = i; return 0; } } while (i-- > 0); } /* The filename doesn't exist at all */ return GIT_ENOTFOUND; } void git_tree_entry_free(git_tree_entry *entry) { if (entry == NULL) return; git__free(entry); } git_tree_entry *git_tree_entry_dup(const git_tree_entry *entry) { size_t total_size; git_tree_entry *copy; assert(entry); total_size = sizeof(git_tree_entry) + entry->filename_len + 1; copy = git__malloc(total_size); if (!copy) return NULL; memcpy(copy, entry, total_size); return copy; } void git_tree__free(void *_tree) { git_tree *tree = _tree; size_t i; git_tree_entry *e; git_vector_foreach(&tree->entries, i, e) git_tree_entry_free(e); git_vector_free(&tree->entries); git__free(tree); } git_filemode_t git_tree_entry_filemode(const git_tree_entry *entry) { return (git_filemode_t)entry->attr; } const char *git_tree_entry_name(const git_tree_entry *entry) { assert(entry); return entry->filename; } const git_oid *git_tree_entry_id(const git_tree_entry *entry) { assert(entry); return &entry->oid; } git_otype git_tree_entry_type(const git_tree_entry *entry) { assert(entry); if (S_ISGITLINK(entry->attr)) return GIT_OBJ_COMMIT; else if (S_ISDIR(entry->attr)) return GIT_OBJ_TREE; else return GIT_OBJ_BLOB; } int git_tree_entry_to_object( git_object **object_out, git_repository *repo, const git_tree_entry *entry) { assert(entry && object_out); return git_object_lookup(object_out, repo, &entry->oid, GIT_OBJ_ANY); } static const git_tree_entry *entry_fromname( const git_tree *tree, const char *name, size_t name_len) { size_t idx; assert(tree->entries.sorted); /* be safe when we cast away constness */ if (tree_key_search(&idx, (git_vector *)&tree->entries, name, name_len) < 0) return NULL; return git_vector_get(&tree->entries, idx); } const git_tree_entry *git_tree_entry_byname( const git_tree *tree, const char *filename) { assert(tree && filename); return entry_fromname(tree, filename, strlen(filename)); } const git_tree_entry *git_tree_entry_byindex( const git_tree *tree, size_t idx) { assert(tree); return git_vector_get(&tree->entries, idx); } const git_tree_entry *git_tree_entry_byoid( const git_tree *tree, const git_oid *oid) { size_t i; const git_tree_entry *e; assert(tree); git_vector_foreach(&tree->entries, i, e) { if (memcmp(&e->oid.id, &oid->id, sizeof(oid->id)) == 0) return e; } return NULL; } int git_tree__prefix_position(const git_tree *tree, const char *path) { const git_vector *entries = &tree->entries; struct tree_key_search ksearch; size_t at_pos; if (!path) return 0; ksearch.filename = path; ksearch.filename_len = strlen(path); assert(tree->entries.sorted); /* be safe when we cast away constness */ /* Find tree entry with appropriate prefix */ git_vector_bsearch2( &at_pos, (git_vector *)entries, &homing_search_cmp, &ksearch); for (; at_pos < entries->length; ++at_pos) { const git_tree_entry *entry = entries->contents[at_pos]; if (homing_search_cmp(&ksearch, entry) < 0) break; } for (; at_pos > 0; --at_pos) { const git_tree_entry *entry = entries->contents[at_pos - 1]; if (homing_search_cmp(&ksearch, entry) > 0) break; } return (int)at_pos; } size_t git_tree_entrycount(const git_tree *tree) { assert(tree); return tree->entries.length; } unsigned int git_treebuilder_entrycount(git_treebuilder *bld) { assert(bld); return (unsigned int)bld->entrycount; } static int tree_error(const char *str, const char *path) { if (path) giterr_set(GITERR_TREE, "%s - %s", str, path); else giterr_set(GITERR_TREE, "%s", str); return -1; } int git_tree__parse(void *_tree, git_odb_object *odb_obj) { git_tree *tree = _tree; const char *buffer = git_odb_object_data(odb_obj); const char *buffer_end = buffer + git_odb_object_size(odb_obj); if (git_vector_init(&tree->entries, DEFAULT_TREE_SIZE, entry_sort_cmp) < 0) return -1; while (buffer < buffer_end) { git_tree_entry *entry; int attr; if (git__strtol32(&attr, buffer, &buffer, 8) < 0 || !buffer) return tree_error("Failed to parse tree. Can't parse filemode", NULL); attr = normalize_filemode(attr); /* make sure to normalize the filemode */ if (*buffer++ != ' ') return tree_error("Failed to parse tree. Object is corrupted", NULL); if (memchr(buffer, 0, buffer_end - buffer) == NULL) return tree_error("Failed to parse tree. Object is corrupted", NULL); /** Allocate the entry and store it in the entries vector */ { entry = alloc_entry(buffer); GITERR_CHECK_ALLOC(entry); if (git_vector_insert(&tree->entries, entry) < 0) { git__free(entry); return -1; } entry->attr = attr; } while (buffer < buffer_end && *buffer != 0) buffer++; buffer++; git_oid_fromraw(&entry->oid, (const unsigned char *)buffer); buffer += GIT_OID_RAWSZ; } git_vector_sort(&tree->entries); return 0; } static size_t find_next_dir(const char *dirname, git_index *index, size_t start) { size_t dirlen, i, entries = git_index_entrycount(index); dirlen = strlen(dirname); for (i = start; i < entries; ++i) { const git_index_entry *entry = git_index_get_byindex(index, i); if (strlen(entry->path) < dirlen || memcmp(entry->path, dirname, dirlen) || (dirlen > 0 && entry->path[dirlen] != '/')) { break; } } return i; } static int append_entry( git_treebuilder *bld, const char *filename, const git_oid *id, git_filemode_t filemode) { git_tree_entry *entry; if (!valid_entry_name(filename)) return tree_error("Failed to insert entry. Invalid name for a tree entry", filename); entry = alloc_entry(filename); GITERR_CHECK_ALLOC(entry); git_oid_cpy(&entry->oid, id); entry->attr = (uint16_t)filemode; if (git_vector_insert(&bld->entries, entry) < 0) { git__free(entry); return -1; } bld->entrycount++; return 0; } static int write_tree( git_oid *oid, git_repository *repo, git_index *index, const char *dirname, size_t start) { git_treebuilder *bld = NULL; size_t i, entries = git_index_entrycount(index); int error; size_t dirname_len = strlen(dirname); const git_tree_cache *cache; cache = git_tree_cache_get(index->tree, dirname); if (cache != NULL && cache->entries >= 0){ git_oid_cpy(oid, &cache->oid); return (int)find_next_dir(dirname, index, start); } if ((error = git_treebuilder_create(&bld, NULL)) < 0 || bld == NULL) return -1; /* * This loop is unfortunate, but necessary. The index doesn't have * any directores, so we need to handle that manually, and we * need to keep track of the current position. */ for (i = start; i < entries; ++i) { const git_index_entry *entry = git_index_get_byindex(index, i); const char *filename, *next_slash; /* * If we've left our (sub)tree, exit the loop and return. The * first check is an early out (and security for the * third). The second check is a simple prefix comparison. The * third check catches situations where there is a directory * win32/sys and a file win32mmap.c. Without it, the following * code believes there is a file win32/mmap.c */ if (strlen(entry->path) < dirname_len || memcmp(entry->path, dirname, dirname_len) || (dirname_len > 0 && entry->path[dirname_len] != '/')) { break; } filename = entry->path + dirname_len; if (*filename == '/') filename++; next_slash = strchr(filename, '/'); if (next_slash) { git_oid sub_oid; int written; char *subdir, *last_comp; subdir = git__strndup(entry->path, next_slash - entry->path); GITERR_CHECK_ALLOC(subdir); /* Write out the subtree */ written = write_tree(&sub_oid, repo, index, subdir, i); if (written < 0) { git__free(subdir); goto on_error; } else { i = written - 1; /* -1 because of the loop increment */ } /* * We need to figure out what we want toinsert * into this tree. If we're traversing * deps/zlib/, then we only want to write * 'zlib' into the tree. */ last_comp = strrchr(subdir, '/'); if (last_comp) { last_comp++; /* Get rid of the '/' */ } else { last_comp = subdir; } error = append_entry(bld, last_comp, &sub_oid, S_IFDIR); git__free(subdir); if (error < 0) goto on_error; } else { error = append_entry(bld, filename, &entry->oid, entry->mode); if (error < 0) goto on_error; } } if (git_treebuilder_write(oid, repo, bld) < 0) goto on_error; git_treebuilder_free(bld); return (int)i; on_error: git_treebuilder_free(bld); return -1; } int git_tree__write_index( git_oid *oid, git_index *index, git_repository *repo) { int ret; bool old_ignore_case = false; assert(oid && index && repo); if (git_index_has_conflicts(index)) { giterr_set(GITERR_INDEX, "Cannot create a tree from a not fully merged index."); return GIT_EUNMERGED; } if (index->tree != NULL && index->tree->entries >= 0) { git_oid_cpy(oid, &index->tree->oid); return 0; } /* The tree cache didn't help us; we'll have to write * out a tree. If the index is ignore_case, we must * make it case-sensitive for the duration of the tree-write * operation. */ if (index->ignore_case) { old_ignore_case = true; git_index__set_ignore_case(index, false); } ret = write_tree(oid, repo, index, "", 0); if (old_ignore_case) git_index__set_ignore_case(index, true); return ret < 0 ? ret : 0; } int git_treebuilder_create(git_treebuilder **builder_p, const git_tree *source) { git_treebuilder *bld; size_t i, source_entries = DEFAULT_TREE_SIZE; assert(builder_p); bld = git__calloc(1, sizeof(git_treebuilder)); GITERR_CHECK_ALLOC(bld); if (source != NULL) source_entries = source->entries.length; if (git_vector_init(&bld->entries, source_entries, entry_sort_cmp) < 0) goto on_error; if (source != NULL) { git_tree_entry *entry_src; git_vector_foreach(&source->entries, i, entry_src) { if (append_entry( bld, entry_src->filename, &entry_src->oid, entry_src->attr) < 0) goto on_error; } } *builder_p = bld; return 0; on_error: git_treebuilder_free(bld); return -1; } int git_treebuilder_insert( const git_tree_entry **entry_out, git_treebuilder *bld, const char *filename, const git_oid *id, git_filemode_t filemode) { git_tree_entry *entry; size_t pos; assert(bld && id && filename); if (!valid_filemode(filemode)) return tree_error("Failed to insert entry. Invalid filemode for file", filename); if (!valid_entry_name(filename)) return tree_error("Failed to insert entry. Invalid name for a tree entry", filename); if (!tree_key_search(&pos, &bld->entries, filename, strlen(filename))) { entry = git_vector_get(&bld->entries, pos); if (entry->removed) { entry->removed = 0; bld->entrycount++; } } else { entry = alloc_entry(filename); GITERR_CHECK_ALLOC(entry); if (git_vector_insert(&bld->entries, entry) < 0) { git__free(entry); return -1; } bld->entrycount++; } git_oid_cpy(&entry->oid, id); entry->attr = filemode; if (entry_out) *entry_out = entry; return 0; } static git_tree_entry *treebuilder_get(git_treebuilder *bld, const char *filename) { size_t idx; git_tree_entry *entry; assert(bld && filename); if (tree_key_search(&idx, &bld->entries, filename, strlen(filename)) < 0) return NULL; entry = git_vector_get(&bld->entries, idx); if (entry->removed) return NULL; return entry; } const git_tree_entry *git_treebuilder_get(git_treebuilder *bld, const char *filename) { return treebuilder_get(bld, filename); } int git_treebuilder_remove(git_treebuilder *bld, const char *filename) { git_tree_entry *remove_ptr = treebuilder_get(bld, filename); if (remove_ptr == NULL || remove_ptr->removed) return tree_error("Failed to remove entry. File isn't in the tree", filename); remove_ptr->removed = 1; bld->entrycount--; return 0; } int git_treebuilder_write(git_oid *oid, git_repository *repo, git_treebuilder *bld) { int error = 0; size_t i; git_buf tree = GIT_BUF_INIT; git_odb *odb; assert(bld); git_vector_sort(&bld->entries); /* Grow the buffer beforehand to an estimated size */ error = git_buf_grow(&tree, bld->entries.length * 72); for (i = 0; i < bld->entries.length && !error; ++i) { git_tree_entry *entry = git_vector_get(&bld->entries, i); if (entry->removed) continue; git_buf_printf(&tree, "%o ", entry->attr); git_buf_put(&tree, entry->filename, entry->filename_len + 1); git_buf_put(&tree, (char *)entry->oid.id, GIT_OID_RAWSZ); if (git_buf_oom(&tree)) error = -1; } if (!error && !(error = git_repository_odb__weakptr(&odb, repo))) error = git_odb_write(oid, odb, tree.ptr, tree.size, GIT_OBJ_TREE); git_buf_free(&tree); return error; } void git_treebuilder_filter( git_treebuilder *bld, git_treebuilder_filter_cb filter, void *payload) { size_t i; git_tree_entry *entry; assert(bld && filter); git_vector_foreach(&bld->entries, i, entry) { if (!entry->removed && filter(entry, payload)) { entry->removed = 1; bld->entrycount--; } } } void git_treebuilder_clear(git_treebuilder *bld) { size_t i; git_tree_entry *e; assert(bld); git_vector_foreach(&bld->entries, i, e) git_tree_entry_free(e); git_vector_clear(&bld->entries); bld->entrycount = 0; } void git_treebuilder_free(git_treebuilder *bld) { if (bld == NULL) return; git_treebuilder_clear(bld); git_vector_free(&bld->entries); git__free(bld); } static size_t subpath_len(const char *path) { const char *slash_pos = strchr(path, '/'); if (slash_pos == NULL) return strlen(path); return slash_pos - path; } int git_tree_entry_bypath( git_tree_entry **entry_out, const git_tree *root, const char *path) { int error = 0; git_tree *subtree; const git_tree_entry *entry; size_t filename_len; /* Find how long is the current path component (i.e. * the filename between two slashes */ filename_len = subpath_len(path); if (filename_len == 0) { giterr_set(GITERR_TREE, "Invalid tree path given"); return GIT_ENOTFOUND; } entry = entry_fromname(root, path, filename_len); if (entry == NULL) { giterr_set(GITERR_TREE, "The path '%s' does not exist in the given tree", path); return GIT_ENOTFOUND; } switch (path[filename_len]) { case '/': /* If there are more components in the path... * then this entry *must* be a tree */ if (!git_tree_entry__is_tree(entry)) { giterr_set(GITERR_TREE, "The path '%s' does not exist in the given tree", path); return GIT_ENOTFOUND; } /* If there's only a slash left in the path, we * return the current entry; otherwise, we keep * walking down the path */ if (path[filename_len + 1] != '\0') break; case '\0': /* If there are no more components in the path, return * this entry */ *entry_out = git_tree_entry_dup(entry); return 0; } if (git_tree_lookup(&subtree, root->object.repo, &entry->oid) < 0) return -1; error = git_tree_entry_bypath( entry_out, subtree, path + filename_len + 1 ); git_tree_free(subtree); return error; } static int tree_walk( const git_tree *tree, git_treewalk_cb callback, git_buf *path, void *payload, bool preorder) { int error = 0; size_t i; const git_tree_entry *entry; git_vector_foreach(&tree->entries, i, entry) { if (preorder) { error = callback(path->ptr, entry, payload); if (error > 0) continue; if (error < 0) { giterr_clear(); return GIT_EUSER; } } if (git_tree_entry__is_tree(entry)) { git_tree *subtree; size_t path_len = git_buf_len(path); if ((error = git_tree_lookup( &subtree, tree->object.repo, &entry->oid)) < 0) break; /* append the next entry to the path */ git_buf_puts(path, entry->filename); git_buf_putc(path, '/'); if (git_buf_oom(path)) return -1; error = tree_walk(subtree, callback, path, payload, preorder); if (error != 0) break; git_buf_truncate(path, path_len); git_tree_free(subtree); } if (!preorder && callback(path->ptr, entry, payload) < 0) { giterr_clear(); error = GIT_EUSER; break; } } return error; } int git_tree_walk( const git_tree *tree, git_treewalk_mode mode, git_treewalk_cb callback, void *payload) { int error = 0; git_buf root_path = GIT_BUF_INIT; if (mode != GIT_TREEWALK_POST && mode != GIT_TREEWALK_PRE) { giterr_set(GITERR_INVALID, "Invalid walking mode for tree walk"); return -1; } error = tree_walk( tree, callback, &root_path, payload, (mode == GIT_TREEWALK_PRE)); git_buf_free(&root_path); return error; } libgit2-0.19.0/src/tree.h000066400000000000000000000027461216214232500150430ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #ifndef INCLUDE_tree_h__ #define INCLUDE_tree_h__ #include "git2/tree.h" #include "repository.h" #include "odb.h" #include "vector.h" struct git_tree_entry { uint16_t removed; uint16_t attr; git_oid oid; size_t filename_len; char filename[1]; }; struct git_tree { git_object object; git_vector entries; }; struct git_treebuilder { git_vector entries; size_t entrycount; /* vector may contain "removed" entries */ }; GIT_INLINE(bool) git_tree_entry__is_tree(const struct git_tree_entry *e) { return (S_ISDIR(e->attr) && !S_ISGITLINK(e->attr)); } extern int git_tree_entry_icmp(const git_tree_entry *e1, const git_tree_entry *e2); void git_tree__free(void *tree); int git_tree__parse(void *tree, git_odb_object *obj); /** * Lookup the first position in the tree with a given prefix. * * @param tree a previously loaded tree. * @param prefix the beginning of a path to find in the tree. * @return index of the first item at or after the given prefix. */ int git_tree__prefix_position(const git_tree *tree, const char *prefix); /** * Write a tree to the given repository */ int git_tree__write_index( git_oid *oid, git_index *index, git_repository *repo); /** * Obsolete mode kept for compatibility reasons */ #define GIT_FILEMODE_BLOB_GROUP_WRITABLE 0100664 #endif libgit2-0.19.0/src/tsort.c000066400000000000000000000204131216214232500152410ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #include "common.h" /** * An array-of-pointers implementation of Python's Timsort * Based on code by Christopher Swenson under the MIT license * * Copyright (c) 2010 Christopher Swenson * Copyright (c) 2011 Vicent Marti */ #ifndef MAX # define MAX(x,y) (((x) > (y) ? (x) : (y))) #endif #ifndef MIN # define MIN(x,y) (((x) < (y) ? (x) : (y))) #endif static int binsearch( void **dst, const void *x, size_t size, git__sort_r_cmp cmp, void *payload) { int l, c, r; void *lx, *cx; assert(size > 0); l = 0; r = (int)size - 1; c = r >> 1; lx = dst[l]; /* check for beginning conditions */ if (cmp(x, lx, payload) < 0) return 0; else if (cmp(x, lx, payload) == 0) { int i = 1; while (cmp(x, dst[i], payload) == 0) i++; return i; } /* guaranteed not to be >= rx */ cx = dst[c]; while (1) { const int val = cmp(x, cx, payload); if (val < 0) { if (c - l <= 1) return c; r = c; } else if (val > 0) { if (r - c <= 1) return c + 1; l = c; lx = cx; } else { do { cx = dst[++c]; } while (cmp(x, cx, payload) == 0); return c; } c = l + ((r - l) >> 1); cx = dst[c]; } } /* Binary insertion sort, but knowing that the first "start" entries are sorted. Used in timsort. */ static void bisort( void **dst, size_t start, size_t size, git__sort_r_cmp cmp, void *payload) { size_t i; void *x; int location; for (i = start; i < size; i++) { int j; /* If this entry is already correct, just move along */ if (cmp(dst[i - 1], dst[i], payload) <= 0) continue; /* Else we need to find the right place, shift everything over, and squeeze in */ x = dst[i]; location = binsearch(dst, x, i, cmp, payload); for (j = (int)i - 1; j >= location; j--) { dst[j + 1] = dst[j]; } dst[location] = x; } } /* timsort implementation, based on timsort.txt */ struct tsort_run { ssize_t start; ssize_t length; }; struct tsort_store { size_t alloc; git__sort_r_cmp cmp; void *payload; void **storage; }; static void reverse_elements(void **dst, ssize_t start, ssize_t end) { while (start < end) { void *tmp = dst[start]; dst[start] = dst[end]; dst[end] = tmp; start++; end--; } } static ssize_t count_run( void **dst, ssize_t start, ssize_t size, struct tsort_store *store) { ssize_t curr = start + 2; if (size - start == 1) return 1; if (start >= size - 2) { if (store->cmp(dst[size - 2], dst[size - 1], store->payload) > 0) { void *tmp = dst[size - 1]; dst[size - 1] = dst[size - 2]; dst[size - 2] = tmp; } return 2; } if (store->cmp(dst[start], dst[start + 1], store->payload) <= 0) { while (curr < size - 1 && store->cmp(dst[curr - 1], dst[curr], store->payload) <= 0) curr++; return curr - start; } else { while (curr < size - 1 && store->cmp(dst[curr - 1], dst[curr], store->payload) > 0) curr++; /* reverse in-place */ reverse_elements(dst, start, curr - 1); return curr - start; } } static size_t compute_minrun(size_t n) { int r = 0; while (n >= 64) { r |= n & 1; n >>= 1; } return n + r; } static int check_invariant(struct tsort_run *stack, ssize_t stack_curr) { if (stack_curr < 2) return 1; else if (stack_curr == 2) { const ssize_t A = stack[stack_curr - 2].length; const ssize_t B = stack[stack_curr - 1].length; return (A > B); } else { const ssize_t A = stack[stack_curr - 3].length; const ssize_t B = stack[stack_curr - 2].length; const ssize_t C = stack[stack_curr - 1].length; return !((A <= B + C) || (B <= C)); } } static int resize(struct tsort_store *store, size_t new_size) { if (store->alloc < new_size) { void **tempstore = git__realloc(store->storage, new_size * sizeof(void *)); /** * Do not propagate on OOM; this will abort the sort and * leave the array unsorted, but no error code will be * raised */ if (tempstore == NULL) return -1; store->storage = tempstore; store->alloc = new_size; } return 0; } static void merge(void **dst, const struct tsort_run *stack, ssize_t stack_curr, struct tsort_store *store) { const ssize_t A = stack[stack_curr - 2].length; const ssize_t B = stack[stack_curr - 1].length; const ssize_t curr = stack[stack_curr - 2].start; void **storage; ssize_t i, j, k; if (resize(store, MIN(A, B)) < 0) return; storage = store->storage; /* left merge */ if (A < B) { memcpy(storage, &dst[curr], A * sizeof(void *)); i = 0; j = curr + A; for (k = curr; k < curr + A + B; k++) { if ((i < A) && (j < curr + A + B)) { if (store->cmp(storage[i], dst[j], store->payload) <= 0) dst[k] = storage[i++]; else dst[k] = dst[j++]; } else if (i < A) { dst[k] = storage[i++]; } else dst[k] = dst[j++]; } } else { memcpy(storage, &dst[curr + A], B * sizeof(void *)); i = B - 1; j = curr + A - 1; for (k = curr + A + B - 1; k >= curr; k--) { if ((i >= 0) && (j >= curr)) { if (store->cmp(dst[j], storage[i], store->payload) > 0) dst[k] = dst[j--]; else dst[k] = storage[i--]; } else if (i >= 0) dst[k] = storage[i--]; else dst[k] = dst[j--]; } } } static ssize_t collapse(void **dst, struct tsort_run *stack, ssize_t stack_curr, struct tsort_store *store, ssize_t size) { ssize_t A, B, C; while (1) { /* if the stack only has one thing on it, we are done with the collapse */ if (stack_curr <= 1) break; /* if this is the last merge, just do it */ if ((stack_curr == 2) && (stack[0].length + stack[1].length == size)) { merge(dst, stack, stack_curr, store); stack[0].length += stack[1].length; stack_curr--; break; } /* check if the invariant is off for a stack of 2 elements */ else if ((stack_curr == 2) && (stack[0].length <= stack[1].length)) { merge(dst, stack, stack_curr, store); stack[0].length += stack[1].length; stack_curr--; break; } else if (stack_curr == 2) break; A = stack[stack_curr - 3].length; B = stack[stack_curr - 2].length; C = stack[stack_curr - 1].length; /* check first invariant */ if (A <= B + C) { if (A < C) { merge(dst, stack, stack_curr - 1, store); stack[stack_curr - 3].length += stack[stack_curr - 2].length; stack[stack_curr - 2] = stack[stack_curr - 1]; stack_curr--; } else { merge(dst, stack, stack_curr, store); stack[stack_curr - 2].length += stack[stack_curr - 1].length; stack_curr--; } } else if (B <= C) { merge(dst, stack, stack_curr, store); stack[stack_curr - 2].length += stack[stack_curr - 1].length; stack_curr--; } else break; } return stack_curr; } #define PUSH_NEXT() do {\ len = count_run(dst, curr, size, store);\ run = minrun;\ if (run < minrun) run = minrun;\ if (run > (ssize_t)size - curr) run = size - curr;\ if (run > len) {\ bisort(&dst[curr], len, run, cmp, payload);\ len = run;\ }\ run_stack[stack_curr].start = curr;\ run_stack[stack_curr++].length = len;\ curr += len;\ if (curr == (ssize_t)size) {\ /* finish up */ \ while (stack_curr > 1) { \ merge(dst, run_stack, stack_curr, store); \ run_stack[stack_curr - 2].length += run_stack[stack_curr - 1].length; \ stack_curr--; \ } \ if (store->storage != NULL) {\ git__free(store->storage);\ store->storage = NULL;\ }\ return;\ }\ }\ while (0) void git__tsort_r( void **dst, size_t size, git__sort_r_cmp cmp, void *payload) { struct tsort_store _store, *store = &_store; struct tsort_run run_stack[128]; ssize_t stack_curr = 0; ssize_t len, run; ssize_t curr = 0; ssize_t minrun; if (size < 64) { bisort(dst, 1, size, cmp, payload); return; } /* compute the minimum run length */ minrun = (ssize_t)compute_minrun(size); /* temporary storage for merges */ store->alloc = 0; store->storage = NULL; store->cmp = cmp; store->payload = payload; PUSH_NEXT(); PUSH_NEXT(); PUSH_NEXT(); while (1) { if (!check_invariant(run_stack, stack_curr)) { stack_curr = collapse(dst, run_stack, stack_curr, store, size); continue; } PUSH_NEXT(); } } static int tsort_r_cmp(const void *a, const void *b, void *payload) { return ((git__tsort_cmp)payload)(a, b); } void git__tsort(void **dst, size_t size, git__tsort_cmp cmp) { git__tsort_r(dst, size, tsort_r_cmp, cmp); } libgit2-0.19.0/src/unix/000077500000000000000000000000001216214232500147055ustar00rootroot00000000000000libgit2-0.19.0/src/unix/map.c000066400000000000000000000021341216214232500156260ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #include #ifndef GIT_WIN32 #include "map.h" #include #include int p_mmap(git_map *out, size_t len, int prot, int flags, int fd, git_off_t offset) { int mprot = 0; int mflag = 0; GIT_MMAP_VALIDATE(out, len, prot, flags); out->data = NULL; out->len = 0; if (prot & GIT_PROT_WRITE) mprot = PROT_WRITE; else if (prot & GIT_PROT_READ) mprot = PROT_READ; if ((flags & GIT_MAP_TYPE) == GIT_MAP_SHARED) mflag = MAP_SHARED; else if ((flags & GIT_MAP_TYPE) == GIT_MAP_PRIVATE) mflag = MAP_PRIVATE; else mflag = MAP_SHARED; out->data = mmap(NULL, len, mprot, mflag, fd, offset); if (!out->data || out->data == MAP_FAILED) { giterr_set(GITERR_OS, "Failed to mmap. Could not write data"); return -1; } out->len = len; return 0; } int p_munmap(git_map *map) { assert(map != NULL); munmap(map->data, map->len); return 0; } #endif libgit2-0.19.0/src/unix/posix.h000066400000000000000000000020771216214232500162260ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #ifndef INCLUDE_posix__w32_h__ #define INCLUDE_posix__w32_h__ #include #include #define p_lstat(p,b) lstat(p,b) #define p_readlink(a, b, c) readlink(a, b, c) #define p_symlink(o,n) symlink(o, n) #define p_link(o,n) link(o, n) #define p_unlink(p) unlink(p) #define p_mkdir(p,m) mkdir(p, m) #define p_fsync(fd) fsync(fd) /* The OpenBSD realpath function behaves differently */ #if !defined(__OpenBSD__) # define p_realpath(p, po) realpath(p, po) #else char *p_realpath(const char *, char *); #endif #define p_vsnprintf(b, c, f, a) vsnprintf(b, c, f, a) #define p_snprintf(b, c, f, ...) snprintf(b, c, f, __VA_ARGS__) #define p_mkstemp(p) mkstemp(p) #define p_setenv(n,v,o) setenv(n,v,o) #define p_inet_pton(a, b, c) inet_pton(a, b, c) /* see win32/posix.h for explanation about why this exists */ #define p_lstat_posixly(p,b) lstat(p,b) #endif libgit2-0.19.0/src/unix/realpath.c000066400000000000000000000011031216214232500166440ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #include #ifdef __OpenBSD__ #include #include #include #include char *p_realpath(const char *pathname, char *resolved) { char *ret; if ((ret = realpath(pathname, resolved)) == NULL) return NULL; /* Figure out if the file exists */ if (!access(ret, F_OK)) return ret; return NULL; } #endif libgit2-0.19.0/src/util.c000066400000000000000000000357331216214232500150560ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #include #include "common.h" #include #include #include #include "posix.h" #include "fileops.h" #include "cache.h" #ifdef _MSC_VER # include #endif void git_libgit2_version(int *major, int *minor, int *rev) { *major = LIBGIT2_VER_MAJOR; *minor = LIBGIT2_VER_MINOR; *rev = LIBGIT2_VER_REVISION; } int git_libgit2_capabilities() { return 0 #ifdef GIT_THREADS | GIT_CAP_THREADS #endif #if defined(GIT_SSL) || defined(GIT_WINHTTP) | GIT_CAP_HTTPS #endif ; } /* Declarations for tuneable settings */ extern size_t git_mwindow__window_size; extern size_t git_mwindow__mapped_limit; static int config_level_to_futils_dir(int config_level) { int val = -1; switch (config_level) { case GIT_CONFIG_LEVEL_SYSTEM: val = GIT_FUTILS_DIR_SYSTEM; break; case GIT_CONFIG_LEVEL_XDG: val = GIT_FUTILS_DIR_XDG; break; case GIT_CONFIG_LEVEL_GLOBAL: val = GIT_FUTILS_DIR_GLOBAL; break; default: giterr_set( GITERR_INVALID, "Invalid config path selector %d", config_level); } return val; } int git_libgit2_opts(int key, ...) { int error = 0; va_list ap; va_start(ap, key); switch (key) { case GIT_OPT_SET_MWINDOW_SIZE: git_mwindow__window_size = va_arg(ap, size_t); break; case GIT_OPT_GET_MWINDOW_SIZE: *(va_arg(ap, size_t *)) = git_mwindow__window_size; break; case GIT_OPT_SET_MWINDOW_MAPPED_LIMIT: git_mwindow__mapped_limit = va_arg(ap, size_t); break; case GIT_OPT_GET_MWINDOW_MAPPED_LIMIT: *(va_arg(ap, size_t *)) = git_mwindow__mapped_limit; break; case GIT_OPT_GET_SEARCH_PATH: if ((error = config_level_to_futils_dir(va_arg(ap, int))) >= 0) { char *out = va_arg(ap, char *); size_t outlen = va_arg(ap, size_t); error = git_futils_dirs_get_str(out, outlen, error); } break; case GIT_OPT_SET_SEARCH_PATH: if ((error = config_level_to_futils_dir(va_arg(ap, int))) >= 0) error = git_futils_dirs_set(error, va_arg(ap, const char *)); break; case GIT_OPT_SET_CACHE_OBJECT_LIMIT: { git_otype type = (git_otype)va_arg(ap, int); size_t size = va_arg(ap, size_t); error = git_cache_set_max_object_size(type, size); break; } case GIT_OPT_SET_CACHE_MAX_SIZE: git_cache__max_storage = va_arg(ap, ssize_t); break; case GIT_OPT_ENABLE_CACHING: git_cache__enabled = (va_arg(ap, int) != 0); break; case GIT_OPT_GET_CACHED_MEMORY: *(va_arg(ap, ssize_t *)) = git_cache__current_storage.val; *(va_arg(ap, ssize_t *)) = git_cache__max_storage; break; } va_end(ap); return error; } void git_strarray_free(git_strarray *array) { size_t i; for (i = 0; i < array->count; ++i) git__free(array->strings[i]); git__free(array->strings); memset(array, 0, sizeof(*array)); } int git_strarray_copy(git_strarray *tgt, const git_strarray *src) { size_t i; assert(tgt && src); memset(tgt, 0, sizeof(*tgt)); if (!src->count) return 0; tgt->strings = git__calloc(src->count, sizeof(char *)); GITERR_CHECK_ALLOC(tgt->strings); for (i = 0; i < src->count; ++i) { if (!src->strings[i]) continue; tgt->strings[tgt->count] = git__strdup(src->strings[i]); if (!tgt->strings[tgt->count]) { git_strarray_free(tgt); memset(tgt, 0, sizeof(*tgt)); return -1; } tgt->count++; } return 0; } int git__strtol64(int64_t *result, const char *nptr, const char **endptr, int base) { const char *p; int64_t n, nn; int c, ovfl, v, neg, ndig; p = nptr; neg = 0; n = 0; ndig = 0; ovfl = 0; /* * White space */ while (git__isspace(*p)) p++; /* * Sign */ if (*p == '-' || *p == '+') if (*p++ == '-') neg = 1; /* * Base */ if (base == 0) { if (*p != '0') base = 10; else { base = 8; if (p[1] == 'x' || p[1] == 'X') { p += 2; base = 16; } } } else if (base == 16 && *p == '0') { if (p[1] == 'x' || p[1] == 'X') p += 2; } else if (base < 0 || 36 < base) goto Return; /* * Non-empty sequence of digits */ for (;; p++,ndig++) { c = *p; v = base; if ('0'<=c && c<='9') v = c - '0'; else if ('a'<=c && c<='z') v = c - 'a' + 10; else if ('A'<=c && c<='Z') v = c - 'A' + 10; if (v >= base) break; nn = n*base + v; if (nn < n) ovfl = 1; n = nn; } Return: if (ndig == 0) { giterr_set(GITERR_INVALID, "Failed to convert string to long. Not a number"); return -1; } if (endptr) *endptr = p; if (ovfl) { giterr_set(GITERR_INVALID, "Failed to convert string to long. Overflow error"); return -1; } *result = neg ? -n : n; return 0; } int git__strtol32(int32_t *result, const char *nptr, const char **endptr, int base) { int error; int32_t tmp_int; int64_t tmp_long; if ((error = git__strtol64(&tmp_long, nptr, endptr, base)) < 0) return error; tmp_int = tmp_long & 0xFFFFFFFF; if (tmp_int != tmp_long) { giterr_set(GITERR_INVALID, "Failed to convert. '%s' is too large", nptr); return -1; } *result = tmp_int; return error; } int git__strcmp(const char *a, const char *b) { while (*a && *b && *a == *b) ++a, ++b; return (int)(*(const unsigned char *)a) - (int)(*(const unsigned char *)b); } int git__strcasecmp(const char *a, const char *b) { while (*a && *b && tolower(*a) == tolower(*b)) ++a, ++b; return (tolower(*a) - tolower(*b)); } int git__strcasesort_cmp(const char *a, const char *b) { int cmp = 0; while (*a && *b) { if (*a != *b) { if (tolower(*a) != tolower(*b)) break; /* use case in sort order even if not in equivalence */ if (!cmp) cmp = (int)(*(const uint8_t *)a) - (int)(*(const uint8_t *)b); } ++a, ++b; } if (*a || *b) return tolower(*a) - tolower(*b); return cmp; } int git__strncmp(const char *a, const char *b, size_t sz) { while (sz && *a && *b && *a == *b) --sz, ++a, ++b; if (!sz) return 0; return (int)(*(const unsigned char *)a) - (int)(*(const unsigned char *)b); } int git__strncasecmp(const char *a, const char *b, size_t sz) { int al, bl; do { al = (unsigned char)tolower(*a); bl = (unsigned char)tolower(*b); ++a, ++b; } while (--sz && al && al == bl); return al - bl; } void git__strntolower(char *str, size_t len) { size_t i; for (i = 0; i < len; ++i) { str[i] = (char) tolower(str[i]); } } void git__strtolower(char *str) { git__strntolower(str, strlen(str)); } int git__prefixcmp(const char *str, const char *prefix) { for (;;) { unsigned char p = *(prefix++), s; if (!p) return 0; if ((s = *(str++)) != p) return s - p; } } int git__prefixcmp_icase(const char *str, const char *prefix) { return strncasecmp(str, prefix, strlen(prefix)); } int git__suffixcmp(const char *str, const char *suffix) { size_t a = strlen(str); size_t b = strlen(suffix); if (a < b) return -1; return strcmp(str + (a - b), suffix); } char *git__strtok(char **end, const char *sep) { char *ptr = *end; while (*ptr && strchr(sep, *ptr)) ++ptr; if (*ptr) { char *start = ptr; *end = start + 1; while (**end && !strchr(sep, **end)) ++*end; if (**end) { **end = '\0'; ++*end; } return start; } return NULL; } /* Similar to strtok, but does not collapse repeated tokens. */ char *git__strsep(char **end, const char *sep) { char *start = *end, *ptr = *end; while (*ptr && !strchr(sep, *ptr)) ++ptr; if (*ptr) { *end = ptr + 1; *ptr = '\0'; return start; } return NULL; } void git__hexdump(const char *buffer, size_t len) { static const size_t LINE_WIDTH = 16; size_t line_count, last_line, i, j; const char *line; line_count = (len / LINE_WIDTH); last_line = (len % LINE_WIDTH); for (i = 0; i < line_count; ++i) { line = buffer + (i * LINE_WIDTH); for (j = 0; j < LINE_WIDTH; ++j, ++line) printf("%02X ", (unsigned char)*line & 0xFF); printf("| "); line = buffer + (i * LINE_WIDTH); for (j = 0; j < LINE_WIDTH; ++j, ++line) printf("%c", (*line >= 32 && *line <= 126) ? *line : '.'); printf("\n"); } if (last_line > 0) { line = buffer + (line_count * LINE_WIDTH); for (j = 0; j < last_line; ++j, ++line) printf("%02X ", (unsigned char)*line & 0xFF); for (j = 0; j < (LINE_WIDTH - last_line); ++j) printf(" "); printf("| "); line = buffer + (line_count * LINE_WIDTH); for (j = 0; j < last_line; ++j, ++line) printf("%c", (*line >= 32 && *line <= 126) ? *line : '.'); printf("\n"); } printf("\n"); } #ifdef GIT_LEGACY_HASH uint32_t git__hash(const void *key, int len, unsigned int seed) { const uint32_t m = 0x5bd1e995; const int r = 24; uint32_t h = seed ^ len; const unsigned char *data = (const unsigned char *)key; while(len >= 4) { uint32_t k = *(uint32_t *)data; k *= m; k ^= k >> r; k *= m; h *= m; h ^= k; data += 4; len -= 4; } switch(len) { case 3: h ^= data[2] << 16; case 2: h ^= data[1] << 8; case 1: h ^= data[0]; h *= m; }; h ^= h >> 13; h *= m; h ^= h >> 15; return h; } #else /* Cross-platform version of Murmurhash3 http://code.google.com/p/smhasher/wiki/MurmurHash3 by Austin Appleby (aappleby@gmail.com) This code is on the public domain. */ uint32_t git__hash(const void *key, int len, uint32_t seed) { #define MURMUR_BLOCK() {\ k1 *= c1; \ k1 = git__rotl(k1,11);\ k1 *= c2;\ h1 ^= k1;\ h1 = h1*3 + 0x52dce729;\ c1 = c1*5 + 0x7b7d159c;\ c2 = c2*5 + 0x6bce6396;\ } const uint8_t *data = (const uint8_t*)key; const int nblocks = len / 4; const uint32_t *blocks = (const uint32_t *)(data + nblocks * 4); const uint8_t *tail = (const uint8_t *)(data + nblocks * 4); uint32_t h1 = 0x971e137b ^ seed; uint32_t k1; uint32_t c1 = 0x95543787; uint32_t c2 = 0x2ad7eb25; int i; for (i = -nblocks; i; i++) { k1 = blocks[i]; MURMUR_BLOCK(); } k1 = 0; switch(len & 3) { case 3: k1 ^= tail[2] << 16; case 2: k1 ^= tail[1] << 8; case 1: k1 ^= tail[0]; MURMUR_BLOCK(); } h1 ^= len; h1 ^= h1 >> 16; h1 *= 0x85ebca6b; h1 ^= h1 >> 13; h1 *= 0xc2b2ae35; h1 ^= h1 >> 16; return h1; } #endif /** * A modified `bsearch` from the BSD glibc. * * Copyright (c) 1990 Regents of the University of California. * All rights reserved. * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. [rescinded 22 July 1999] * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ int git__bsearch( void **array, size_t array_len, const void *key, int (*compare)(const void *, const void *), size_t *position) { size_t lim; int cmp = -1; void **part, **base = array; for (lim = array_len; lim != 0; lim >>= 1) { part = base + (lim >> 1); cmp = (*compare)(key, *part); if (cmp == 0) { base = part; break; } if (cmp > 0) { /* key > p; take right partition */ base = part + 1; lim--; } /* else take left partition */ } if (position) *position = (base - array); return (cmp == 0) ? 0 : GIT_ENOTFOUND; } int git__bsearch_r( void **array, size_t array_len, const void *key, int (*compare_r)(const void *, const void *, void *), void *payload, size_t *position) { size_t lim; int cmp = -1; void **part, **base = array; for (lim = array_len; lim != 0; lim >>= 1) { part = base + (lim >> 1); cmp = (*compare_r)(key, *part, payload); if (cmp == 0) { base = part; break; } if (cmp > 0) { /* key > p; take right partition */ base = part + 1; lim--; } /* else take left partition */ } if (position) *position = (base - array); return (cmp == 0) ? 0 : GIT_ENOTFOUND; } /** * A strcmp wrapper * * We don't want direct pointers to the CRT on Windows, we may * get stdcall conflicts. */ int git__strcmp_cb(const void *a, const void *b) { const char *stra = (const char *)a; const char *strb = (const char *)b; return strcmp(stra, strb); } int git__parse_bool(int *out, const char *value) { /* A missing value means true */ if (value == NULL || !strcasecmp(value, "true") || !strcasecmp(value, "yes") || !strcasecmp(value, "on")) { *out = 1; return 0; } if (!strcasecmp(value, "false") || !strcasecmp(value, "no") || !strcasecmp(value, "off") || value[0] == '\0') { *out = 0; return 0; } return -1; } size_t git__unescape(char *str) { char *scan, *pos = str; for (scan = str; *scan; pos++, scan++) { if (*scan == '\\' && *(scan + 1) != '\0') scan++; /* skip '\' but include next char */ if (pos != scan) *pos = *scan; } if (pos != scan) { *pos = '\0'; } return (pos - str); } #if defined(GIT_WIN32) || defined(BSD) typedef struct { git__sort_r_cmp cmp; void *payload; } git__qsort_r_glue; static int GIT_STDLIB_CALL git__qsort_r_glue_cmp( void *payload, const void *a, const void *b) { git__qsort_r_glue *glue = payload; return glue->cmp(a, b, glue->payload); } #endif void git__qsort_r( void *els, size_t nel, size_t elsize, git__sort_r_cmp cmp, void *payload) { #if defined(__MINGW32__) || defined(__OpenBSD__) || defined(AMIGA) || \ defined(__gnu_hurd__) || \ (__GLIBC__ == 2 && __GLIBC_MINOR__ < 8) git__insertsort_r(els, nel, elsize, NULL, cmp, payload); #elif defined(GIT_WIN32) git__qsort_r_glue glue = { cmp, payload }; qsort_s(els, nel, elsize, git__qsort_r_glue_cmp, &glue); #elif defined(BSD) git__qsort_r_glue glue = { cmp, payload }; qsort_r(els, nel, elsize, &glue, git__qsort_r_glue_cmp); #else qsort_r(els, nel, elsize, cmp, payload); #endif } void git__insertsort_r( void *els, size_t nel, size_t elsize, void *swapel, git__sort_r_cmp cmp, void *payload) { uint8_t *base = els; uint8_t *end = base + nel * elsize; uint8_t *i, *j; bool freeswap = !swapel; if (freeswap) swapel = git__malloc(elsize); for (i = base + elsize; i < end; i += elsize) for (j = i; j > base && cmp(j, j - elsize, payload) < 0; j -= elsize) { memcpy(swapel, j, elsize); memcpy(j, j - elsize, elsize); memcpy(j - elsize, swapel, elsize); } if (freeswap) git__free(swapel); } libgit2-0.19.0/src/util.h000066400000000000000000000211551216214232500150540ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #ifndef INCLUDE_util_h__ #define INCLUDE_util_h__ #include "common.h" #define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0])) #define bitsizeof(x) (CHAR_BIT * sizeof(x)) #define MSB(x, bits) ((x) & (~0ULL << (bitsizeof(x) - (bits)))) #ifndef min # define min(a,b) ((a) < (b) ? (a) : (b)) #endif #ifndef max # define max(a,b) ((a) > (b) ? (a) : (b)) #endif /* * Custom memory allocation wrappers * that set error code and error message * on allocation failure */ GIT_INLINE(void *) git__malloc(size_t len) { void *ptr = malloc(len); if (!ptr) giterr_set_oom(); return ptr; } GIT_INLINE(void *) git__calloc(size_t nelem, size_t elsize) { void *ptr = calloc(nelem, elsize); if (!ptr) giterr_set_oom(); return ptr; } GIT_INLINE(char *) git__strdup(const char *str) { char *ptr = strdup(str); if (!ptr) giterr_set_oom(); return ptr; } GIT_INLINE(char *) git__strndup(const char *str, size_t n) { size_t length = 0; char *ptr; while (length < n && str[length]) ++length; ptr = (char*)git__malloc(length + 1); if (length) memcpy(ptr, str, length); ptr[length] = '\0'; return ptr; } /* NOTE: This doesn't do null or '\0' checking. Watch those boundaries! */ GIT_INLINE(char *) git__substrdup(const char *start, size_t n) { char *ptr = (char*)git__malloc(n+1); memcpy(ptr, start, n); ptr[n] = '\0'; return ptr; } GIT_INLINE(void *) git__realloc(void *ptr, size_t size) { void *new_ptr = realloc(ptr, size); if (!new_ptr) giterr_set_oom(); return new_ptr; } #define git__free(ptr) free(ptr) #define STRCMP_CASESELECT(IGNORE_CASE, STR1, STR2) \ ((IGNORE_CASE) ? strcasecmp((STR1), (STR2)) : strcmp((STR1), (STR2))) #define CASESELECT(IGNORE_CASE, ICASE, CASE) \ ((IGNORE_CASE) ? (ICASE) : (CASE)) extern int git__prefixcmp(const char *str, const char *prefix); extern int git__prefixcmp_icase(const char *str, const char *prefix); extern int git__suffixcmp(const char *str, const char *suffix); GIT_INLINE(int) git__signum(int val) { return ((val > 0) - (val < 0)); } extern int git__strtol32(int32_t *n, const char *buff, const char **end_buf, int base); extern int git__strtol64(int64_t *n, const char *buff, const char **end_buf, int base); extern void git__hexdump(const char *buffer, size_t n); extern uint32_t git__hash(const void *key, int len, uint32_t seed); /** @return true if p fits into the range of a size_t */ GIT_INLINE(int) git__is_sizet(git_off_t p) { size_t r = (size_t)p; return p == (git_off_t)r; } /** @return true if p fits into the range of a uint32_t */ GIT_INLINE(int) git__is_uint32(size_t p) { uint32_t r = (uint32_t)p; return p == (size_t)r; } /* 32-bit cross-platform rotl */ #ifdef _MSC_VER /* use built-in method in MSVC */ # define git__rotl(v, s) (uint32_t)_rotl(v, s) #else /* use bitops in GCC; with o2 this gets optimized to a rotl instruction */ # define git__rotl(v, s) (uint32_t)(((uint32_t)(v) << (s)) | ((uint32_t)(v) >> (32 - (s)))) #endif extern char *git__strtok(char **end, const char *sep); extern char *git__strsep(char **end, const char *sep); extern void git__strntolower(char *str, size_t len); extern void git__strtolower(char *str); GIT_INLINE(const char *) git__next_line(const char *s) { while (*s && *s != '\n') s++; while (*s == '\n' || *s == '\r') s++; return s; } GIT_INLINE(const void *) git__memrchr(const void *s, int c, size_t n) { const unsigned char *cp; if (n != 0) { cp = (unsigned char *)s + n; do { if (*(--cp) == (unsigned char)c) return cp; } while (--n != 0); } return NULL; } typedef int (*git__tsort_cmp)(const void *a, const void *b); extern void git__tsort(void **dst, size_t size, git__tsort_cmp cmp); typedef int (*git__sort_r_cmp)(const void *a, const void *b, void *payload); extern void git__tsort_r( void **dst, size_t size, git__sort_r_cmp cmp, void *payload); extern void git__qsort_r( void *els, size_t nel, size_t elsize, git__sort_r_cmp cmp, void *payload); extern void git__insertsort_r( void *els, size_t nel, size_t elsize, void *swapel, git__sort_r_cmp cmp, void *payload); /** * @param position If non-NULL, this will be set to the position where the * element is or would be inserted if not found. * @return 0 if found; GIT_ENOTFOUND if not found */ extern int git__bsearch( void **array, size_t array_len, const void *key, int (*compare)(const void *key, const void *element), size_t *position); extern int git__bsearch_r( void **array, size_t array_len, const void *key, int (*compare_r)(const void *key, const void *element, void *payload), void *payload, size_t *position); extern int git__strcmp_cb(const void *a, const void *b); extern int git__strcmp(const char *a, const char *b); extern int git__strcasecmp(const char *a, const char *b); extern int git__strncmp(const char *a, const char *b, size_t sz); extern int git__strncasecmp(const char *a, const char *b, size_t sz); extern int git__strcasesort_cmp(const char *a, const char *b); #include "thread-utils.h" typedef struct { git_atomic refcount; void *owner; } git_refcount; typedef void (*git_refcount_freeptr)(void *r); #define GIT_REFCOUNT_INC(r) { \ git_atomic_inc(&((git_refcount *)(r))->refcount); \ } #define GIT_REFCOUNT_DEC(_r, do_free) { \ git_refcount *r = (git_refcount *)(_r); \ int val = git_atomic_dec(&r->refcount); \ if (val <= 0 && r->owner == NULL) { do_free(_r); } \ } #define GIT_REFCOUNT_OWN(r, o) { \ ((git_refcount *)(r))->owner = o; \ } #define GIT_REFCOUNT_OWNER(r) (((git_refcount *)(r))->owner) static signed char from_hex[] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 00 */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 10 */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 20 */ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, /* 30 */ -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 40 */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 50 */ -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 60 */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 70 */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 80 */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 90 */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* a0 */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* b0 */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* c0 */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* d0 */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* e0 */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* f0 */ }; GIT_INLINE(int) git__fromhex(char h) { return from_hex[(unsigned char) h]; } GIT_INLINE(int) git__ishex(const char *str) { unsigned i; for (i=0; i> 1; v |= v >> 2; v |= v >> 4; v |= v >> 8; v |= v >> 16; return v; } GIT_INLINE(size_t) git__size_t_powerof2(size_t v) { return git__size_t_bitmask(v) + 1; } GIT_INLINE(bool) git__isupper(int c) { return (c >= 'A' && c <= 'Z'); } GIT_INLINE(bool) git__isalpha(int c) { return ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')); } GIT_INLINE(bool) git__isdigit(int c) { return (c >= '0' && c <= '9'); } GIT_INLINE(bool) git__isspace(int c) { return (c == ' ' || c == '\t' || c == '\n' || c == '\f' || c == '\r' || c == '\v' || c == 0x85 /* Unicode CR+LF */); } GIT_INLINE(bool) git__iswildcard(int c) { return (c == '*' || c == '?' || c == '['); } /* * Parse a string value as a boolean, just like Core Git does. * * Valid values for true are: 'true', 'yes', 'on' * Valid values for false are: 'false', 'no', 'off' */ extern int git__parse_bool(int *out, const char *value); /* * Parse a string into a value as a git_time_t. * * Sample valid input: * - "yesterday" * - "July 17, 2003" * - "2003-7-17 08:23" */ extern int git__date_parse(git_time_t *out, const char *date); /* * Unescapes a string in-place. * * Edge cases behavior: * - "jackie\" -> "jacky\" * - "chan\\" -> "chan\" */ extern size_t git__unescape(char *str); /* * Safely zero-out memory, making sure that the compiler * doesn't optimize away the operation. */ GIT_INLINE(void) git__memzero(void *data, size_t size) { #ifdef _MSC_VER SecureZeroMemory((PVOID)data, size); #else volatile uint8_t *scan = (volatile uint8_t *)data; while (size--) *scan++ = 0x0; #endif } #endif /* INCLUDE_util_h__ */ libgit2-0.19.0/src/vector.c000066400000000000000000000133011216214232500153660ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #include "common.h" #include "repository.h" #include "vector.h" /* In elements, not bytes */ #define MIN_ALLOCSIZE 8 GIT_INLINE(size_t) compute_new_size(git_vector *v) { size_t new_size = v->_alloc_size; /* Use a resize factor of 1.5, which is quick to compute using integer * instructions and less than the golden ratio (1.618...) */ if (new_size < MIN_ALLOCSIZE) new_size = MIN_ALLOCSIZE; else if (new_size <= (SIZE_MAX / 3) * 2) new_size += new_size / 2; else new_size = SIZE_MAX; return new_size; } GIT_INLINE(int) resize_vector(git_vector *v, size_t new_size) { size_t new_bytes = new_size * sizeof(void *); void *new_contents; /* Check for overflow */ if (new_bytes / sizeof(void *) != new_size) GITERR_CHECK_ALLOC(NULL); new_contents = git__realloc(v->contents, new_bytes); GITERR_CHECK_ALLOC(new_contents); v->_alloc_size = new_size; v->contents = new_contents; return 0; } int git_vector_dup(git_vector *v, const git_vector *src, git_vector_cmp cmp) { size_t bytes; assert(v && src); bytes = src->length * sizeof(void *); v->_alloc_size = src->length; v->_cmp = cmp; v->length = src->length; v->sorted = src->sorted && cmp == src->_cmp; v->contents = git__malloc(bytes); GITERR_CHECK_ALLOC(v->contents); memcpy(v->contents, src->contents, bytes); return 0; } void git_vector_free(git_vector *v) { assert(v); git__free(v->contents); v->contents = NULL; v->length = 0; v->_alloc_size = 0; } int git_vector_init(git_vector *v, size_t initial_size, git_vector_cmp cmp) { assert(v); v->_alloc_size = 0; v->_cmp = cmp; v->length = 0; v->sorted = 1; v->contents = NULL; return resize_vector(v, max(initial_size, MIN_ALLOCSIZE)); } int git_vector_insert(git_vector *v, void *element) { assert(v); if (v->length >= v->_alloc_size && resize_vector(v, compute_new_size(v)) < 0) return -1; v->contents[v->length++] = element; v->sorted = 0; return 0; } int git_vector_insert_sorted( git_vector *v, void *element, int (*on_dup)(void **old, void *new)) { int result; size_t pos; assert(v && v->_cmp); if (!v->sorted) git_vector_sort(v); if (v->length >= v->_alloc_size && resize_vector(v, compute_new_size(v)) < 0) return -1; /* If we find the element and have a duplicate handler callback, * invoke it. If it returns non-zero, then cancel insert, otherwise * proceed with normal insert. */ if (!git__bsearch(v->contents, v->length, element, v->_cmp, &pos) && on_dup && (result = on_dup(&v->contents[pos], element)) < 0) return result; /* shift elements to the right */ if (pos < v->length) memmove(v->contents + pos + 1, v->contents + pos, (v->length - pos) * sizeof(void *)); v->contents[pos] = element; v->length++; return 0; } void git_vector_sort(git_vector *v) { assert(v); if (v->sorted || !v->_cmp) return; git__tsort(v->contents, v->length, v->_cmp); v->sorted = 1; } int git_vector_bsearch2( size_t *at_pos, git_vector *v, git_vector_cmp key_lookup, const void *key) { assert(v && key && key_lookup); /* need comparison function to sort the vector */ if (!v->_cmp) return -1; git_vector_sort(v); return git__bsearch(v->contents, v->length, key, key_lookup, at_pos); } int git_vector_search2( size_t *at_pos, const git_vector *v, git_vector_cmp key_lookup, const void *key) { size_t i; assert(v && key && key_lookup); for (i = 0; i < v->length; ++i) { if (key_lookup(key, v->contents[i]) == 0) { if (at_pos) *at_pos = i; return 0; } } return GIT_ENOTFOUND; } static int strict_comparison(const void *a, const void *b) { return (a == b) ? 0 : -1; } int git_vector_search(size_t *at_pos, const git_vector *v, const void *entry) { return git_vector_search2(at_pos, v, v->_cmp ? v->_cmp : strict_comparison, entry); } int git_vector_remove(git_vector *v, size_t idx) { size_t shift_count; assert(v); if (idx >= v->length) return GIT_ENOTFOUND; shift_count = v->length - idx - 1; if (shift_count) memmove(&v->contents[idx], &v->contents[idx + 1], shift_count * sizeof(void *)); v->length--; return 0; } void git_vector_pop(git_vector *v) { if (v->length > 0) v->length--; } void git_vector_uniq(git_vector *v) { git_vector_cmp cmp; size_t i, j; if (v->length <= 1) return; git_vector_sort(v); cmp = v->_cmp ? v->_cmp : strict_comparison; for (i = 0, j = 1 ; j < v->length; ++j) if (!cmp(v->contents[i], v->contents[j])) v->contents[i] = v->contents[j]; else v->contents[++i] = v->contents[j]; v->length -= j - i - 1; } void git_vector_remove_matching( git_vector *v, int (*match)(const git_vector *v, size_t idx)) { size_t i, j; for (i = 0, j = 0; j < v->length; ++j) { v->contents[i] = v->contents[j]; if (!match(v, i)) i++; } v->length = i; } void git_vector_clear(git_vector *v) { assert(v); v->length = 0; v->sorted = 1; } void git_vector_swap(git_vector *a, git_vector *b) { git_vector t; assert(a && b); if (a != b) { memcpy(&t, a, sizeof(t)); memcpy(a, b, sizeof(t)); memcpy(b, &t, sizeof(t)); } } int git_vector_resize_to(git_vector *v, size_t new_length) { if (new_length > v->_alloc_size && resize_vector(v, new_length) < 0) return -1; if (new_length > v->length) memset(&v->contents[v->length], 0, sizeof(void *) * (new_length - v->length)); v->length = new_length; return 0; } int git_vector_set(void **old, git_vector *v, size_t position, void *value) { if (git_vector_resize_to(v, position + 1) < 0) return -1; if (old != NULL) *old = v->contents[position]; v->contents[position] = value; return 0; } libgit2-0.19.0/src/vector.h000066400000000000000000000056231216214232500154030ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #ifndef INCLUDE_vector_h__ #define INCLUDE_vector_h__ #include "git2/common.h" typedef int (*git_vector_cmp)(const void *, const void *); typedef struct git_vector { size_t _alloc_size; git_vector_cmp _cmp; void **contents; size_t length; int sorted; } git_vector; #define GIT_VECTOR_INIT {0} int git_vector_init(git_vector *v, size_t initial_size, git_vector_cmp cmp); void git_vector_free(git_vector *v); void git_vector_clear(git_vector *v); int git_vector_dup(git_vector *v, const git_vector *src, git_vector_cmp cmp); void git_vector_swap(git_vector *a, git_vector *b); void git_vector_sort(git_vector *v); /** Linear search for matching entry using internal comparison function */ int git_vector_search(size_t *at_pos, const git_vector *v, const void *entry); /** Linear search for matching entry using explicit comparison function */ int git_vector_search2(size_t *at_pos, const git_vector *v, git_vector_cmp cmp, const void *key); /** * Binary search for matching entry using explicit comparison function that * returns position where item would go if not found. */ int git_vector_bsearch2( size_t *at_pos, git_vector *v, git_vector_cmp cmp, const void *key); /** Binary search for matching entry using internal comparison function */ GIT_INLINE(int) git_vector_bsearch(size_t *at_pos, git_vector *v, const void *key) { return git_vector_bsearch2(at_pos, v, v->_cmp, key); } GIT_INLINE(void *) git_vector_get(const git_vector *v, size_t position) { return (position < v->length) ? v->contents[position] : NULL; } #define GIT_VECTOR_GET(V,I) ((I) < (V)->length ? (V)->contents[(I)] : NULL) GIT_INLINE(void *) git_vector_last(const git_vector *v) { return (v->length > 0) ? git_vector_get(v, v->length - 1) : NULL; } #define git_vector_foreach(v, iter, elem) \ for ((iter) = 0; (iter) < (v)->length && ((elem) = (v)->contents[(iter)], 1); (iter)++ ) #define git_vector_rforeach(v, iter, elem) \ for ((iter) = (v)->length - 1; (iter) < SIZE_MAX && ((elem) = (v)->contents[(iter)], 1); (iter)-- ) int git_vector_insert(git_vector *v, void *element); int git_vector_insert_sorted(git_vector *v, void *element, int (*on_dup)(void **old, void *new)); int git_vector_remove(git_vector *v, size_t idx); void git_vector_pop(git_vector *v); void git_vector_uniq(git_vector *v); void git_vector_remove_matching( git_vector *v, int (*match)(const git_vector *v, size_t idx)); int git_vector_resize_to(git_vector *v, size_t new_length); int git_vector_set(void **old, git_vector *v, size_t position, void *value); /** Set the comparison function used for sorting the vector */ GIT_INLINE(void) git_vector_set_cmp(git_vector *v, git_vector_cmp cmp) { if (cmp != v->_cmp) { v->_cmp = cmp; v->sorted = 0; } } #endif libgit2-0.19.0/src/win32/000077500000000000000000000000001216214232500146645ustar00rootroot00000000000000libgit2-0.19.0/src/win32/dir.c000066400000000000000000000052401216214232500156070ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #define GIT__WIN32_NO_WRAP_DIR #include "dir.h" #include "utf-conv.h" static int init_filter(char *filter, size_t n, const char *dir) { size_t len = strlen(dir); if (len+3 >= n) return 0; strcpy(filter, dir); if (len && dir[len-1] != '/') strcat(filter, "/"); strcat(filter, "*"); return 1; } git__DIR *git__opendir(const char *dir) { char filter[GIT_WIN_PATH]; wchar_t filter_w[GIT_WIN_PATH]; git__DIR *new = NULL; if (!dir || !init_filter(filter, sizeof(filter), dir)) return NULL; new = git__calloc(1, sizeof(*new)); if (!new) return NULL; new->dir = git__strdup(dir); if (!new->dir) goto fail; git__utf8_to_16(filter_w, GIT_WIN_PATH, filter); new->h = FindFirstFileW(filter_w, &new->f); if (new->h == INVALID_HANDLE_VALUE) { giterr_set(GITERR_OS, "Could not open directory '%s'", dir); goto fail; } new->first = 1; return new; fail: git__free(new->dir); git__free(new); return NULL; } int git__readdir_ext( git__DIR *d, struct git__dirent *entry, struct git__dirent **result, int *is_dir) { if (!d || !entry || !result || d->h == INVALID_HANDLE_VALUE) return -1; *result = NULL; if (d->first) d->first = 0; else if (!FindNextFileW(d->h, &d->f)) { if (GetLastError() == ERROR_NO_MORE_FILES) return 0; giterr_set(GITERR_OS, "Could not read from directory '%s'", d->dir); return -1; } if (wcslen(d->f.cFileName) >= sizeof(entry->d_name)) return -1; git__utf16_to_8(entry->d_name, d->f.cFileName); entry->d_ino = 0; *result = entry; if (is_dir != NULL) *is_dir = ((d->f.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0); return 0; } struct git__dirent *git__readdir(git__DIR *d) { struct git__dirent *result; if (git__readdir_ext(d, &d->entry, &result, NULL) < 0) return NULL; return result; } void git__rewinddir(git__DIR *d) { char filter[GIT_WIN_PATH]; wchar_t filter_w[GIT_WIN_PATH]; if (!d) return; if (d->h != INVALID_HANDLE_VALUE) { FindClose(d->h); d->h = INVALID_HANDLE_VALUE; d->first = 0; } if (!init_filter(filter, sizeof(filter), d->dir)) return; git__utf8_to_16(filter_w, GIT_WIN_PATH, filter); d->h = FindFirstFileW(filter_w, &d->f); if (d->h == INVALID_HANDLE_VALUE) giterr_set(GITERR_OS, "Could not open directory '%s'", d->dir); else d->first = 1; } int git__closedir(git__DIR *d) { if (!d) return 0; if (d->h != INVALID_HANDLE_VALUE) { FindClose(d->h); d->h = INVALID_HANDLE_VALUE; } git__free(d->dir); d->dir = NULL; git__free(d); return 0; } libgit2-0.19.0/src/win32/dir.h000066400000000000000000000020131216214232500156070ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #ifndef INCLUDE_dir_h__ #define INCLUDE_dir_h__ #include "common.h" struct git__dirent { int d_ino; char d_name[261]; }; typedef struct { HANDLE h; WIN32_FIND_DATAW f; struct git__dirent entry; char *dir; int first; } git__DIR; extern git__DIR *git__opendir(const char *); extern struct git__dirent *git__readdir(git__DIR *); extern int git__readdir_ext( git__DIR *, struct git__dirent *, struct git__dirent **, int *); extern void git__rewinddir(git__DIR *); extern int git__closedir(git__DIR *); # ifndef GIT__WIN32_NO_WRAP_DIR # define dirent git__dirent # define DIR git__DIR # define opendir git__opendir # define readdir git__readdir # define readdir_r(d,e,r) git__readdir_ext((d),(e),(r),NULL) # define rewinddir git__rewinddir # define closedir git__closedir # endif #endif /* INCLUDE_dir_h__ */ libgit2-0.19.0/src/win32/error.c000066400000000000000000000032261216214232500161640ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #include "common.h" #include "error.h" #ifdef GIT_WINHTTP # include #endif #ifndef WC_ERR_INVALID_CHARS #define WC_ERR_INVALID_CHARS 0x80 #endif char *git_win32_get_error_message(DWORD error_code) { LPWSTR lpMsgBuf = NULL; HMODULE hModule = NULL; char *utf8_msg = NULL; int utf8_size; DWORD dwFlags = FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS; if (!error_code) return NULL; #ifdef GIT_WINHTTP /* Errors raised by WinHTTP are not in the system resource table */ if (error_code >= WINHTTP_ERROR_BASE && error_code <= WINHTTP_ERROR_LAST) hModule = GetModuleHandleW(L"winhttp"); #endif GIT_UNUSED(hModule); if (hModule) dwFlags |= FORMAT_MESSAGE_FROM_HMODULE; else dwFlags |= FORMAT_MESSAGE_FROM_SYSTEM; if (FormatMessageW(dwFlags, hModule, error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPWSTR)&lpMsgBuf, 0, NULL)) { /* Invalid code point check supported on Vista+ only */ if (git_has_win32_version(6, 0)) dwFlags = WC_ERR_INVALID_CHARS; else dwFlags = 0; utf8_size = WideCharToMultiByte(CP_UTF8, dwFlags, lpMsgBuf, -1, NULL, 0, NULL, NULL); if (!utf8_size) { assert(0); goto on_error; } utf8_msg = git__malloc(utf8_size); if (!utf8_msg) goto on_error; if (!WideCharToMultiByte(CP_UTF8, dwFlags, lpMsgBuf, -1, utf8_msg, utf8_size, NULL, NULL)) { git__free(utf8_msg); goto on_error; } on_error: LocalFree(lpMsgBuf); } return utf8_msg; } libgit2-0.19.0/src/win32/error.h000066400000000000000000000005451216214232500161720ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #ifndef INCLUDE_git_win32_error_h__ #define INCLUDE_git_win32_error_h__ extern char *git_win32_get_error_message(DWORD error_code); #endif libgit2-0.19.0/src/win32/findfile.c000066400000000000000000000134031216214232500166110ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #include "utf-conv.h" #include "path.h" #include "findfile.h" #define REG_MSYSGIT_INSTALL_LOCAL L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\Git_is1" #ifndef _WIN64 #define REG_MSYSGIT_INSTALL REG_MSYSGIT_INSTALL_LOCAL #else #define REG_MSYSGIT_INSTALL L"SOFTWARE\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\Git_is1" #endif int git_win32__expand_path(struct git_win32__path *s_root, const wchar_t *templ) { s_root->len = ExpandEnvironmentStringsW(templ, s_root->path, MAX_PATH); return s_root->len ? 0 : -1; } static int win32_path_utf16_to_8(git_buf *path_utf8, const wchar_t *path_utf16) { char temp_utf8[GIT_PATH_MAX]; git__utf16_to_8(temp_utf8, path_utf16); git_path_mkposix(temp_utf8); return git_buf_sets(path_utf8, temp_utf8); } int git_win32__find_file( git_buf *path, const struct git_win32__path *root, const char *filename) { size_t len, alloc_len; wchar_t *file_utf16 = NULL; if (!root || !filename || (len = strlen(filename)) == 0) return GIT_ENOTFOUND; /* allocate space for wchar_t path to file */ alloc_len = root->len + len + 2; file_utf16 = git__calloc(alloc_len, sizeof(wchar_t)); GITERR_CHECK_ALLOC(file_utf16); /* append root + '\\' + filename as wchar_t */ memcpy(file_utf16, root->path, root->len * sizeof(wchar_t)); if (*filename == '/' || *filename == '\\') filename++; git__utf8_to_16(file_utf16 + root->len - 1, alloc_len, filename); /* check access */ if (_waccess(file_utf16, F_OK) < 0) { git__free(file_utf16); return GIT_ENOTFOUND; } win32_path_utf16_to_8(path, file_utf16); git__free(file_utf16); return 0; } static wchar_t* win32_walkpath(wchar_t *path, wchar_t *buf, size_t buflen) { wchar_t term, *base = path; assert(path && buf && buflen); term = (*path == L'"') ? *path++ : L';'; for (buflen--; *path && *path != term && buflen; buflen--) *buf++ = *path++; *buf = L'\0'; /* reserved a byte via initial subtract */ while (*path == term || *path == L';') path++; return (path != base) ? path : NULL; } static int win32_find_git_in_path(git_buf *buf, const wchar_t *gitexe) { wchar_t *env = _wgetenv(L"PATH"), lastch; struct git_win32__path root; size_t gitexe_len = wcslen(gitexe); if (!env) return -1; while ((env = win32_walkpath(env, root.path, MAX_PATH-1)) && *root.path) { root.len = (DWORD)wcslen(root.path); lastch = root.path[root.len - 1]; /* ensure trailing slash (MAX_PATH-1 to walkpath guarantees space) */ if (lastch != L'/' && lastch != L'\\') { root.path[root.len++] = L'\\'; root.path[root.len] = L'\0'; } if (root.len + gitexe_len >= MAX_PATH) continue; wcscpy(&root.path[root.len], gitexe); if (_waccess(root.path, F_OK) == 0 && root.len > 5) { /* replace "bin\\" or "cmd\\" with "etc\\" */ wcscpy(&root.path[root.len - 4], L"etc\\"); win32_path_utf16_to_8(buf, root.path); return 0; } } return GIT_ENOTFOUND; } static int win32_find_git_in_registry( git_buf *buf, const HKEY hieve, const wchar_t *key) { HKEY hKey; DWORD dwType = REG_SZ; struct git_win32__path path16; assert(buf); path16.len = 0; if (RegOpenKeyExW(hieve, key, 0, KEY_ALL_ACCESS, &hKey) == ERROR_SUCCESS) { if (RegQueryValueExW(hKey, L"InstallLocation", NULL, &dwType, (LPBYTE)&path16.path, &path16.len) == ERROR_SUCCESS) { /* InstallLocation points to the root of the git directory */ if (path16.len + 4 > MAX_PATH) { /* 4 = wcslen(L"etc\\") */ giterr_set(GITERR_OS, "Cannot locate git - path too long"); return -1; } wcscat(path16.path, L"etc\\"); path16.len += 4; win32_path_utf16_to_8(buf, path16.path); } RegCloseKey(hKey); } return path16.len ? 0 : GIT_ENOTFOUND; } static int win32_find_existing_dirs( git_buf *out, const wchar_t *tmpl[], char *temp[]) { struct git_win32__path path16; git_buf buf = GIT_BUF_INIT; git_buf_clear(out); for (; *tmpl != NULL; tmpl++) { if (!git_win32__expand_path(&path16, *tmpl) && path16.path[0] != L'%' && !_waccess(path16.path, F_OK)) { win32_path_utf16_to_8(&buf, path16.path); if (buf.size) git_buf_join(out, GIT_PATH_LIST_SEPARATOR, out->ptr, buf.ptr); } } git_buf_free(&buf); return (git_buf_oom(out) ? -1 : 0); } int git_win32__find_system_dirs(git_buf *out) { git_buf buf = GIT_BUF_INIT; /* directories where git.exe & git.cmd are found */ if (!win32_find_git_in_path(&buf, L"git.exe") && buf.size) git_buf_set(out, buf.ptr, buf.size); else git_buf_clear(out); if (!win32_find_git_in_path(&buf, L"git.cmd") && buf.size) git_buf_join(out, GIT_PATH_LIST_SEPARATOR, out->ptr, buf.ptr); /* directories where git is installed according to registry */ if (!win32_find_git_in_registry( &buf, HKEY_CURRENT_USER, REG_MSYSGIT_INSTALL_LOCAL) && buf.size) git_buf_join(out, GIT_PATH_LIST_SEPARATOR, out->ptr, buf.ptr); if (!win32_find_git_in_registry( &buf, HKEY_LOCAL_MACHINE, REG_MSYSGIT_INSTALL) && buf.size) git_buf_join(out, GIT_PATH_LIST_SEPARATOR, out->ptr, buf.ptr); git_buf_free(&buf); return (git_buf_oom(out) ? -1 : 0); } int git_win32__find_global_dirs(git_buf *out) { char *temp[3]; static const wchar_t *global_tmpls[4] = { L"%HOME%\\", L"%HOMEDRIVE%%HOMEPATH%\\", L"%USERPROFILE%\\", NULL, }; return win32_find_existing_dirs(out, global_tmpls, temp); } int git_win32__find_xdg_dirs(git_buf *out) { char *temp[6]; static const wchar_t *global_tmpls[7] = { L"%XDG_CONFIG_HOME%\\git", L"%APPDATA%\\git", L"%LOCALAPPDATA%\\git", L"%HOME%\\.config\\git", L"%HOMEDRIVE%%HOMEPATH%\\.config\\git", L"%USERPROFILE%\\.config\\git", NULL, }; return win32_find_existing_dirs(out, global_tmpls, temp); } libgit2-0.19.0/src/win32/findfile.h000066400000000000000000000013161216214232500166160ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #ifndef INCLUDE_git_findfile_h__ #define INCLUDE_git_findfile_h__ struct git_win32__path { wchar_t path[MAX_PATH]; DWORD len; }; extern int git_win32__expand_path( struct git_win32__path *s_root, const wchar_t *templ); extern int git_win32__find_file( git_buf *path, const struct git_win32__path *root, const char *filename); extern int git_win32__find_system_dirs(git_buf *out); extern int git_win32__find_global_dirs(git_buf *out); extern int git_win32__find_xdg_dirs(git_buf *out); #endif libgit2-0.19.0/src/win32/git2.rc000066400000000000000000000023431216214232500160610ustar00rootroot00000000000000#include #include "../../include/git2/version.h" #ifndef LIBGIT2_FILENAME # define LIBGIT2_FILENAME "git2" #endif VS_VERSION_INFO VERSIONINFO MOVEABLE IMPURE LOADONCALL DISCARDABLE FILEVERSION LIBGIT2_VER_MAJOR,LIBGIT2_VER_MINOR,LIBGIT2_VER_REVISION,0 PRODUCTVERSION LIBGIT2_VER_MAJOR,LIBGIT2_VER_MINOR,LIBGIT2_VER_REVISION,0 FILEFLAGSMASK VS_FFI_FILEFLAGSMASK #ifdef _DEBUG FILEFLAGS VS_FF_DEBUG #else FILEFLAGS 0 #endif FILEOS VOS_NT_WINDOWS32 FILETYPE VFT_DLL FILESUBTYPE VFT2_UNKNOWN BEGIN BLOCK "StringFileInfo" BEGIN BLOCK "040904E4" //language ID = U.S. English, char set = Windows, Multilingual BEGIN VALUE "FileDescription", "libgit2 - the Git linkable library\0" VALUE "FileVersion", LIBGIT2_VERSION "\0" VALUE "InternalName", LIBGIT2_FILENAME ".dll\0" VALUE "LegalCopyright", "Copyright (C) the libgit2 contributors. All rights reserved.\0" VALUE "OriginalFilename", LIBGIT2_FILENAME ".dll\0" VALUE "ProductName", "libgit2\0" VALUE "ProductVersion", LIBGIT2_VERSION "\0" VALUE "Comments", "For more information visit http://libgit2.github.com/\0" END END BLOCK "VarFileInfo" BEGIN VALUE "Translation", 0x0409, 1252 END END libgit2-0.19.0/src/win32/map.c000066400000000000000000000046401216214232500156110ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #include "map.h" #include static DWORD get_page_size(void) { static DWORD page_size; SYSTEM_INFO sys; if (!page_size) { GetSystemInfo(&sys); page_size = sys.dwAllocationGranularity; } return page_size; } int p_mmap(git_map *out, size_t len, int prot, int flags, int fd, git_off_t offset) { HANDLE fh = (HANDLE)_get_osfhandle(fd); DWORD page_size = get_page_size(); DWORD fmap_prot = 0; DWORD view_prot = 0; DWORD off_low = 0; DWORD off_hi = 0; git_off_t page_start; git_off_t page_offset; GIT_MMAP_VALIDATE(out, len, prot, flags); out->data = NULL; out->len = 0; out->fmh = NULL; if (fh == INVALID_HANDLE_VALUE) { errno = EBADF; giterr_set(GITERR_OS, "Failed to mmap. Invalid handle value"); return -1; } if (prot & GIT_PROT_WRITE) fmap_prot |= PAGE_READWRITE; else if (prot & GIT_PROT_READ) fmap_prot |= PAGE_READONLY; if (prot & GIT_PROT_WRITE) view_prot |= FILE_MAP_WRITE; if (prot & GIT_PROT_READ) view_prot |= FILE_MAP_READ; page_start = (offset / page_size) * page_size; page_offset = offset - page_start; if (page_offset != 0) { /* offset must be multiple of page size */ errno = EINVAL; giterr_set(GITERR_OS, "Failed to mmap. Offset must be multiple of page size"); return -1; } out->fmh = CreateFileMapping(fh, NULL, fmap_prot, 0, 0, NULL); if (!out->fmh || out->fmh == INVALID_HANDLE_VALUE) { giterr_set(GITERR_OS, "Failed to mmap. Invalid handle value"); out->fmh = NULL; return -1; } assert(sizeof(git_off_t) == 8); off_low = (DWORD)(page_start); off_hi = (DWORD)(page_start >> 32); out->data = MapViewOfFile(out->fmh, view_prot, off_hi, off_low, len); if (!out->data) { giterr_set(GITERR_OS, "Failed to mmap. No data written"); CloseHandle(out->fmh); out->fmh = NULL; return -1; } out->len = len; return 0; } int p_munmap(git_map *map) { int error = 0; assert(map != NULL); if (map->data) { if (!UnmapViewOfFile(map->data)) { giterr_set(GITERR_OS, "Failed to munmap. Could not unmap view of file"); error = -1; } map->data = NULL; } if (map->fmh) { if (!CloseHandle(map->fmh)) { giterr_set(GITERR_OS, "Failed to munmap. Could not close handle"); error = -1; } map->fmh = NULL; } return error; } libgit2-0.19.0/src/win32/mingw-compat.h000066400000000000000000000011331216214232500174350ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #ifndef INCLUDE_mingw_compat__ #define INCLUDE_mingw_compat__ #if defined(__MINGW32__) /* use a 64-bit file offset type */ # define lseek _lseeki64 # define stat _stati64 # define fstat _fstati64 /* stat: file mode type testing macros */ # define _S_IFLNK 0120000 # define S_IFLNK _S_IFLNK # define S_ISLNK(m) (((m) & _S_IFMT) == _S_IFLNK) #endif #endif /* INCLUDE_mingw_compat__ */ libgit2-0.19.0/src/win32/msvc-compat.h000066400000000000000000000024711216214232500172720ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #ifndef INCLUDE_msvc_compat__ #define INCLUDE_msvc_compat__ #if defined(_MSC_VER) /* access() mode parameter #defines */ # define F_OK 0 /* existence check */ # define W_OK 2 /* write mode check */ # define R_OK 4 /* read mode check */ # define lseek _lseeki64 # define stat _stat64 # define fstat _fstat64 /* stat: file mode type testing macros */ # define _S_IFLNK 0120000 # define S_IFLNK _S_IFLNK # define S_IXUSR 00100 # define S_ISDIR(m) (((m) & _S_IFMT) == _S_IFDIR) # define S_ISREG(m) (((m) & _S_IFMT) == _S_IFREG) # define S_ISFIFO(m) (((m) & _S_IFMT) == _S_IFIFO) # define S_ISLNK(m) (((m) & _S_IFMT) == _S_IFLNK) # define mode_t unsigned short /* case-insensitive string comparison */ # define strcasecmp _stricmp # define strncasecmp _strnicmp /* MSVC doesn't define ssize_t at all */ typedef SSIZE_T ssize_t; /* define snprintf using variadic macro support if available */ #if _MSC_VER >= 1400 # define snprintf(BUF, SZ, FMT, ...) _snprintf_s(BUF, SZ, _TRUNCATE, FMT, __VA_ARGS__) #else # define snprintf _snprintf #endif #endif #define GIT_STDLIB_CALL __cdecl #endif /* INCLUDE_msvc_compat__ */ libgit2-0.19.0/src/win32/posix.h000066400000000000000000000045101216214232500161770ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #ifndef INCLUDE_posix__w32_h__ #define INCLUDE_posix__w32_h__ #include "common.h" #include "utf-conv.h" GIT_INLINE(int) p_link(const char *old, const char *new) { GIT_UNUSED(old); GIT_UNUSED(new); errno = ENOSYS; return -1; } GIT_INLINE(int) p_mkdir(const char *path, mode_t mode) { wchar_t buf[GIT_WIN_PATH]; GIT_UNUSED(mode); git__utf8_to_16(buf, GIT_WIN_PATH, path); return _wmkdir(buf); } extern int p_unlink(const char *path); extern int p_lstat(const char *file_name, struct stat *buf); extern int p_readlink(const char *link, char *target, size_t target_len); extern int p_symlink(const char *old, const char *new); extern int p_hide_directory__w32(const char *path); extern char *p_realpath(const char *orig_path, char *buffer); extern int p_vsnprintf(char *buffer, size_t count, const char *format, va_list argptr); extern int p_snprintf(char *buffer, size_t count, const char *format, ...) GIT_FORMAT_PRINTF(3, 4); extern int p_mkstemp(char *tmp_path); extern int p_setenv(const char* name, const char* value, int overwrite); extern int p_stat(const char* path, struct stat* buf); extern int p_chdir(const char* path); extern int p_chmod(const char* path, mode_t mode); extern int p_rmdir(const char* path); extern int p_access(const char* path, mode_t mode); extern int p_fsync(int fd); extern int p_open(const char *path, int flags, ...); extern int p_creat(const char *path, mode_t mode); extern int p_getcwd(char *buffer_out, size_t size); extern int p_rename(const char *from, const char *to); extern int p_recv(GIT_SOCKET socket, void *buffer, size_t length, int flags); extern int p_send(GIT_SOCKET socket, const void *buffer, size_t length, int flags); extern int p_inet_pton(int af, const char* src, void* dst); /* p_lstat is almost but not quite POSIX correct. Specifically, the use of * ENOTDIR is wrong, in that it does not mean precisely that a non-directory * entry was encountered. Making it correct is potentially expensive, * however, so this is a separate version of p_lstat to use when correct * POSIX ENOTDIR semantics is required. */ extern int p_lstat_posixly(const char *filename, struct stat *buf); #endif libgit2-0.19.0/src/win32/posix_w32.c000066400000000000000000000323011216214232500166640ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #include "../posix.h" #include "../fileops.h" #include "path.h" #include "utf-conv.h" #include "repository.h" #include #include #include #include int p_unlink(const char *path) { wchar_t buf[GIT_WIN_PATH]; git__utf8_to_16(buf, GIT_WIN_PATH, path); _wchmod(buf, 0666); return _wunlink(buf); } int p_fsync(int fd) { HANDLE fh = (HANDLE)_get_osfhandle(fd); if (fh == INVALID_HANDLE_VALUE) { errno = EBADF; return -1; } if (!FlushFileBuffers(fh)) { DWORD code = GetLastError(); if (code == ERROR_INVALID_HANDLE) errno = EINVAL; else errno = EIO; return -1; } return 0; } GIT_INLINE(time_t) filetime_to_time_t(const FILETIME *ft) { long long winTime = ((long long)ft->dwHighDateTime << 32) + ft->dwLowDateTime; winTime -= 116444736000000000LL; /* Windows to Unix Epoch conversion */ winTime /= 10000000; /* Nano to seconds resolution */ return (time_t)winTime; } #define WIN32_IS_WSEP(CH) ((CH) == L'/' || (CH) == L'\\') static int do_lstat( const char *file_name, struct stat *buf, int posix_enotdir) { WIN32_FILE_ATTRIBUTE_DATA fdata; wchar_t fbuf[GIT_WIN_PATH], lastch; int flen; flen = git__utf8_to_16(fbuf, GIT_WIN_PATH, file_name); /* truncate trailing slashes */ for (; flen > 0; --flen) { lastch = fbuf[flen - 1]; if (WIN32_IS_WSEP(lastch)) fbuf[flen - 1] = L'\0'; else if (lastch != L'\0') break; } if (GetFileAttributesExW(fbuf, GetFileExInfoStandard, &fdata)) { int fMode = S_IREAD; if (!buf) return 0; if (fdata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) fMode |= S_IFDIR; else fMode |= S_IFREG; if (!(fdata.dwFileAttributes & FILE_ATTRIBUTE_READONLY)) fMode |= S_IWRITE; if (fdata.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) fMode |= S_IFLNK; buf->st_ino = 0; buf->st_gid = 0; buf->st_uid = 0; buf->st_nlink = 1; buf->st_mode = (mode_t)fMode; buf->st_size = ((git_off_t)fdata.nFileSizeHigh << 32) + fdata.nFileSizeLow; buf->st_dev = buf->st_rdev = (_getdrive() - 1); buf->st_atime = filetime_to_time_t(&(fdata.ftLastAccessTime)); buf->st_mtime = filetime_to_time_t(&(fdata.ftLastWriteTime)); buf->st_ctime = filetime_to_time_t(&(fdata.ftCreationTime)); /* Windows symlinks have zero file size, call readlink to determine * the length of the path pointed to, which we expect everywhere else */ if (S_ISLNK(fMode)) { char target[GIT_WIN_PATH]; int readlink_result; readlink_result = p_readlink(file_name, target, GIT_WIN_PATH); if (readlink_result == -1) return -1; buf->st_size = strlen(target); } return 0; } errno = ENOENT; /* We need POSIX behavior, then ENOTDIR must set when any of the folders in the * file path is a regular file,otherwise ENOENT must be set. */ if (posix_enotdir) { /* scan up path until we find an existing item */ while (1) { /* remove last directory component */ for (--flen; flen > 0 && !WIN32_IS_WSEP(fbuf[flen]); --flen); if (flen <= 0) break; fbuf[flen] = L'\0'; if (GetFileAttributesExW(fbuf, GetFileExInfoStandard, &fdata)) { if (!(fdata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) errno = ENOTDIR; break; } } } return -1; } int p_lstat(const char *filename, struct stat *buf) { return do_lstat(filename, buf, 0); } int p_lstat_posixly(const char *filename, struct stat *buf) { return do_lstat(filename, buf, 1); } int p_readlink(const char *link, char *target, size_t target_len) { typedef DWORD (WINAPI *fpath_func)(HANDLE, LPWSTR, DWORD, DWORD); static fpath_func pGetFinalPath = NULL; HANDLE hFile; DWORD dwRet; wchar_t link_w[GIT_WIN_PATH]; wchar_t* target_w; int error = 0; assert(link && target && target_len > 0); /* * Try to load the pointer to pGetFinalPath dynamically, because * it is not available in platforms older than Vista */ if (pGetFinalPath == NULL) { HMODULE module = GetModuleHandle("kernel32"); if (module != NULL) pGetFinalPath = (fpath_func)GetProcAddress(module, "GetFinalPathNameByHandleW"); if (pGetFinalPath == NULL) { giterr_set(GITERR_OS, "'GetFinalPathNameByHandleW' is not available in this platform"); return -1; } } git__utf8_to_16(link_w, GIT_WIN_PATH, link); hFile = CreateFileW(link_w, // file to open GENERIC_READ, // open for reading FILE_SHARE_READ, // share for reading NULL, // default security OPEN_EXISTING, // existing file only FILE_FLAG_BACKUP_SEMANTICS, // normal file NULL); // no attr. template if (hFile == INVALID_HANDLE_VALUE) { giterr_set(GITERR_OS, "Cannot open '%s' for reading", link); return -1; } target_w = (wchar_t*)git__malloc(target_len * sizeof(wchar_t)); GITERR_CHECK_ALLOC(target_w); dwRet = pGetFinalPath(hFile, target_w, (DWORD)target_len, 0x0); if (dwRet == 0 || dwRet >= target_len || !WideCharToMultiByte(CP_UTF8, 0, target_w, -1, target, (int)(target_len * sizeof(char)), NULL, NULL)) error = -1; git__free(target_w); CloseHandle(hFile); if (error) return error; /* Skip first 4 characters if they are "\\?\" */ if (dwRet > 4 && target[0] == '\\' && target[1] == '\\' && target[2] == '?' && target[3] == '\\') { unsigned int offset = 4; dwRet -= 4; /* \??\UNC\ */ if (dwRet > 7 && target[4] == 'U' && target[5] == 'N' && target[6] == 'C') { offset += 2; dwRet -= 2; target[offset] = '\\'; } memmove(target, target + offset, dwRet); } target[dwRet] = '\0'; return dwRet; } int p_symlink(const char *old, const char *new) { /* Real symlinks on NTFS require admin privileges. Until this changes, * libgit2 just creates a text file with the link target in the contents. */ return git_futils_fake_symlink(old, new); } int p_open(const char *path, int flags, ...) { wchar_t buf[GIT_WIN_PATH]; mode_t mode = 0; git__utf8_to_16(buf, GIT_WIN_PATH, path); if (flags & O_CREAT) { va_list arg_list; va_start(arg_list, flags); mode = (mode_t)va_arg(arg_list, int); va_end(arg_list); } return _wopen(buf, flags | _O_BINARY, mode); } int p_creat(const char *path, mode_t mode) { wchar_t buf[GIT_WIN_PATH]; git__utf8_to_16(buf, GIT_WIN_PATH, path); return _wopen(buf, _O_WRONLY | _O_CREAT | _O_TRUNC | _O_BINARY, mode); } int p_getcwd(char *buffer_out, size_t size) { int ret; wchar_t *buf; if ((size_t)((int)size) != size) return -1; buf = (wchar_t*)git__malloc(sizeof(wchar_t) * (int)size); GITERR_CHECK_ALLOC(buf); _wgetcwd(buf, (int)size); ret = WideCharToMultiByte( CP_UTF8, 0, buf, -1, buffer_out, (int)size, NULL, NULL); git__free(buf); return !ret ? -1 : 0; } int p_stat(const char* path, struct stat* buf) { char target[GIT_WIN_PATH]; int error = 0; error = do_lstat(path, buf, 0); /* We need not do this in a loop to unwind chains of symlinks since * p_readlink calls GetFinalPathNameByHandle which does it for us. */ if (error >= 0 && S_ISLNK(buf->st_mode) && (error = p_readlink(path, target, GIT_WIN_PATH)) >= 0) error = do_lstat(target, buf, 0); return error; } int p_chdir(const char* path) { wchar_t buf[GIT_WIN_PATH]; git__utf8_to_16(buf, GIT_WIN_PATH, path); return _wchdir(buf); } int p_chmod(const char* path, mode_t mode) { wchar_t buf[GIT_WIN_PATH]; git__utf8_to_16(buf, GIT_WIN_PATH, path); return _wchmod(buf, mode); } int p_rmdir(const char* path) { int error; wchar_t buf[GIT_WIN_PATH]; git__utf8_to_16(buf, GIT_WIN_PATH, path); error = _wrmdir(buf); /* _wrmdir() is documented to return EACCES if "A program has an open * handle to the directory." This sounds like what everybody else calls * EBUSY. Let's convert appropriate error codes. */ if (GetLastError() == ERROR_SHARING_VIOLATION) errno = EBUSY; return error; } int p_hide_directory__w32(const char *path) { wchar_t buf[GIT_WIN_PATH]; git__utf8_to_16(buf, GIT_WIN_PATH, path); return (SetFileAttributesW(buf, FILE_ATTRIBUTE_HIDDEN) != 0) ? 0 : -1; } char *p_realpath(const char *orig_path, char *buffer) { int ret; wchar_t orig_path_w[GIT_WIN_PATH]; wchar_t buffer_w[GIT_WIN_PATH]; git__utf8_to_16(orig_path_w, GIT_WIN_PATH, orig_path); /* Implicitly use GetCurrentDirectory which can be a threading issue */ ret = GetFullPathNameW(orig_path_w, GIT_WIN_PATH, buffer_w, NULL); /* According to MSDN, a return value equals to zero means a failure. */ if (ret == 0 || ret > GIT_WIN_PATH) buffer = NULL; else if (GetFileAttributesW(buffer_w) == INVALID_FILE_ATTRIBUTES) { buffer = NULL; errno = ENOENT; } else if (buffer == NULL) { int buffer_sz = WideCharToMultiByte( CP_UTF8, 0, buffer_w, -1, NULL, 0, NULL, NULL); if (!buffer_sz || !(buffer = (char *)git__malloc(buffer_sz)) || !WideCharToMultiByte( CP_UTF8, 0, buffer_w, -1, buffer, buffer_sz, NULL, NULL)) { git__free(buffer); buffer = NULL; } } else if (!WideCharToMultiByte( CP_UTF8, 0, buffer_w, -1, buffer, GIT_PATH_MAX, NULL, NULL)) buffer = NULL; if (buffer) git_path_mkposix(buffer); return buffer; } int p_vsnprintf(char *buffer, size_t count, const char *format, va_list argptr) { #ifdef _MSC_VER int len; if (count == 0 || (len = _vsnprintf_s(buffer, count, _TRUNCATE, format, argptr)) < 0) return _vscprintf(format, argptr); return len; #else /* MinGW */ return vsnprintf(buffer, count, format, argptr); #endif } int p_snprintf(char *buffer, size_t count, const char *format, ...) { va_list va; int r; va_start(va, format); r = p_vsnprintf(buffer, count, format, va); va_end(va); return r; } extern int p_creat(const char *path, mode_t mode); int p_mkstemp(char *tmp_path) { #if defined(_MSC_VER) if (_mktemp_s(tmp_path, strlen(tmp_path) + 1) != 0) return -1; #else if (_mktemp(tmp_path) == NULL) return -1; #endif return p_creat(tmp_path, 0744); //-V536 } int p_setenv(const char* name, const char* value, int overwrite) { if (overwrite != 1) return -1; return (SetEnvironmentVariableA(name, value) == 0 ? -1 : 0); } int p_access(const char* path, mode_t mode) { wchar_t buf[GIT_WIN_PATH]; git__utf8_to_16(buf, GIT_WIN_PATH, path); return _waccess(buf, mode); } int p_rename(const char *from, const char *to) { wchar_t wfrom[GIT_WIN_PATH]; wchar_t wto[GIT_WIN_PATH]; git__utf8_to_16(wfrom, GIT_WIN_PATH, from); git__utf8_to_16(wto, GIT_WIN_PATH, to); return MoveFileExW(wfrom, wto, MOVEFILE_REPLACE_EXISTING | MOVEFILE_COPY_ALLOWED) ? 0 : -1; } int p_recv(GIT_SOCKET socket, void *buffer, size_t length, int flags) { if ((size_t)((int)length) != length) return -1; /* giterr_set will be done by caller */ return recv(socket, buffer, (int)length, flags); } int p_send(GIT_SOCKET socket, const void *buffer, size_t length, int flags) { if ((size_t)((int)length) != length) return -1; /* giterr_set will be done by caller */ return send(socket, buffer, (int)length, flags); } /** * Borrowed from http://old.nabble.com/Porting-localtime_r-and-gmtime_r-td15282276.html * On Win32, `gmtime_r` doesn't exist but `gmtime` is threadsafe, so we can use that */ struct tm * p_localtime_r (const time_t *timer, struct tm *result) { struct tm *local_result; local_result = localtime (timer); if (local_result == NULL || result == NULL) return NULL; memcpy (result, local_result, sizeof (struct tm)); return result; } struct tm * p_gmtime_r (const time_t *timer, struct tm *result) { struct tm *local_result; local_result = gmtime (timer); if (local_result == NULL || result == NULL) return NULL; memcpy (result, local_result, sizeof (struct tm)); return result; } #if defined(_MSC_VER) || defined(_MSC_EXTENSIONS) #define DELTA_EPOCH_IN_MICROSECS 11644473600000000Ui64 #else #define DELTA_EPOCH_IN_MICROSECS 11644473600000000ULL #endif #ifndef _TIMEZONE_DEFINED #define _TIMEZONE_DEFINED struct timezone { int tz_minuteswest; /* minutes W of Greenwich */ int tz_dsttime; /* type of dst correction */ }; #endif int p_gettimeofday(struct timeval *tv, struct timezone *tz) { FILETIME ft; unsigned __int64 tmpres = 0; static int tzflag; if (NULL != tv) { GetSystemTimeAsFileTime(&ft); tmpres |= ft.dwHighDateTime; tmpres <<= 32; tmpres |= ft.dwLowDateTime; /*converting file time to unix epoch*/ tmpres /= 10; /*convert into microseconds*/ tmpres -= DELTA_EPOCH_IN_MICROSECS; tv->tv_sec = (long)(tmpres / 1000000UL); tv->tv_usec = (long)(tmpres % 1000000UL); } if (NULL != tz) { if (!tzflag) { _tzset(); tzflag++; } tz->tz_minuteswest = _timezone / 60; tz->tz_dsttime = _daylight; } return 0; } int p_inet_pton(int af, const char* src, void* dst) { union { struct sockaddr_in6 sin6; struct sockaddr_in sin; } sa; int srcsize; switch(af) { case AF_INET: sa.sin.sin_family = AF_INET; srcsize = (int)sizeof(sa.sin); break; case AF_INET6: sa.sin6.sin6_family = AF_INET6; srcsize = (int)sizeof(sa.sin6); break; default: errno = WSAEPFNOSUPPORT; return -1; } if (WSAStringToAddress((LPSTR)src, af, NULL, (struct sockaddr *) &sa, &srcsize) != 0) { errno = WSAGetLastError(); return -1; } switch(af) { case AF_INET: memcpy(dst, &sa.sin.sin_addr, sizeof(sa.sin.sin_addr)); break; case AF_INET6: memcpy(dst, &sa.sin6.sin6_addr, sizeof(sa.sin6.sin6_addr)); break; } return 1; } libgit2-0.19.0/src/win32/precompiled.c000066400000000000000000000000311216214232500173250ustar00rootroot00000000000000#include "precompiled.h" libgit2-0.19.0/src/win32/precompiled.h000066400000000000000000000004461216214232500173440ustar00rootroot00000000000000#include "git2.h" #include #include #include #include #include #include #include #include #include #include #include #ifdef GIT_THREADS #include "win32/pthread.h" #endif libgit2-0.19.0/src/win32/pthread.c000066400000000000000000000054321216214232500164630ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #include "pthread.h" int pthread_create( pthread_t *GIT_RESTRICT thread, const pthread_attr_t *GIT_RESTRICT attr, void *(*start_routine)(void*), void *GIT_RESTRICT arg) { GIT_UNUSED(attr); *thread = CreateThread( NULL, 0, (LPTHREAD_START_ROUTINE)start_routine, arg, 0, NULL); return *thread ? 0 : -1; } int pthread_join(pthread_t thread, void **value_ptr) { DWORD ret = WaitForSingleObject(thread, INFINITE); if (ret == WAIT_OBJECT_0) { if (value_ptr != NULL) { *value_ptr = NULL; GetExitCodeThread(thread, (void *)value_ptr); } CloseHandle(thread); return 0; } return -1; } int pthread_mutex_init( pthread_mutex_t *GIT_RESTRICT mutex, const pthread_mutexattr_t *GIT_RESTRICT mutexattr) { GIT_UNUSED(mutexattr); InitializeCriticalSection(mutex); return 0; } int pthread_mutex_destroy(pthread_mutex_t *mutex) { DeleteCriticalSection(mutex); return 0; } int pthread_mutex_lock(pthread_mutex_t *mutex) { EnterCriticalSection(mutex); return 0; } int pthread_mutex_unlock(pthread_mutex_t *mutex) { LeaveCriticalSection(mutex); return 0; } int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr) { /* We don't support non-default attributes. */ if (attr) return EINVAL; /* This is an auto-reset event. */ *cond = CreateEventW(NULL, FALSE, FALSE, NULL); assert(*cond); /* If we can't create the event, claim that the reason was out-of-memory. * The actual reason can be fetched with GetLastError(). */ return *cond ? 0 : ENOMEM; } int pthread_cond_destroy(pthread_cond_t *cond) { BOOL closed; if (!cond) return EINVAL; closed = CloseHandle(*cond); assert(closed); GIT_UNUSED(closed); *cond = NULL; return 0; } int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex) { int error; DWORD wait_result; if (!cond || !mutex) return EINVAL; /* The caller must be holding the mutex. */ error = pthread_mutex_unlock(mutex); if (error) return error; wait_result = WaitForSingleObject(*cond, INFINITE); assert(WAIT_OBJECT_0 == wait_result); GIT_UNUSED(wait_result); return pthread_mutex_lock(mutex); } int pthread_cond_signal(pthread_cond_t *cond) { BOOL signaled; if (!cond) return EINVAL; signaled = SetEvent(*cond); assert(signaled); GIT_UNUSED(signaled); return 0; } /* pthread_cond_broadcast is not implemented because doing so with just Win32 events * is quite complicated, and no caller in libgit2 uses it yet. */ int pthread_num_processors_np(void) { DWORD_PTR p, s; int n = 0; if (GetProcessAffinityMask(GetCurrentProcess(), &p, &s)) for (; p; p >>= 1) n += p&1; return n ? n : 1; } libgit2-0.19.0/src/win32/pthread.h000066400000000000000000000025211216214232500164640ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #ifndef GIT_PTHREAD_H #define GIT_PTHREAD_H #include "../common.h" #if defined (_MSC_VER) # define GIT_RESTRICT __restrict #else # define GIT_RESTRICT __restrict__ #endif typedef int pthread_mutexattr_t; typedef int pthread_condattr_t; typedef int pthread_attr_t; typedef CRITICAL_SECTION pthread_mutex_t; typedef HANDLE pthread_t; typedef HANDLE pthread_cond_t; #define PTHREAD_MUTEX_INITIALIZER {(void*)-1}; int pthread_create( pthread_t *GIT_RESTRICT, const pthread_attr_t *GIT_RESTRICT, void *(*start_routine)(void*), void *__restrict); int pthread_join(pthread_t, void **); int pthread_mutex_init( pthread_mutex_t *GIT_RESTRICT, const pthread_mutexattr_t *GIT_RESTRICT); int pthread_mutex_destroy(pthread_mutex_t *); int pthread_mutex_lock(pthread_mutex_t *); int pthread_mutex_unlock(pthread_mutex_t *); int pthread_cond_init(pthread_cond_t *, const pthread_condattr_t *); int pthread_cond_destroy(pthread_cond_t *); int pthread_cond_wait(pthread_cond_t *, pthread_mutex_t *); int pthread_cond_signal(pthread_cond_t *); /* pthread_cond_broadcast is not supported on Win32 yet. */ int pthread_num_processors_np(void); #endif libgit2-0.19.0/src/win32/utf-conv.c000066400000000000000000000041451216214232500165750ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #include "common.h" #include "utf-conv.h" #define U16_LEAD(c) (wchar_t)(((c)>>10)+0xd7c0) #define U16_TRAIL(c) (wchar_t)(((c)&0x3ff)|0xdc00) #if 0 void git__utf8_to_16(wchar_t *dest, size_t length, const char *src) { wchar_t *pDest = dest; uint32_t ch; const uint8_t* pSrc = (uint8_t*) src; assert(dest && src && length); length--; while(*pSrc && length > 0) { ch = *pSrc++; length--; if(ch < 0xc0) { /* * ASCII, or a trail byte in lead position which is treated like * a single-byte sequence for better character boundary * resynchronization after illegal sequences. */ *pDest++ = (wchar_t)ch; continue; } else if(ch < 0xe0) { /* U+0080..U+07FF */ if (pSrc[0]) { /* 0x3080 = (0xc0 << 6) + 0x80 */ *pDest++ = (wchar_t)((ch << 6) + *pSrc++ - 0x3080); continue; } } else if(ch < 0xf0) { /* U+0800..U+FFFF */ if (pSrc[0] && pSrc[1]) { /* no need for (ch & 0xf) because the upper bits are truncated after <<12 in the cast to (UChar) */ /* 0x2080 = (0x80 << 6) + 0x80 */ ch = (ch << 12) + (*pSrc++ << 6); *pDest++ = (wchar_t)(ch + *pSrc++ - 0x2080); continue; } } else /* f0..f4 */ { /* U+10000..U+10FFFF */ if (length >= 1 && pSrc[0] && pSrc[1] && pSrc[2]) { /* 0x3c82080 = (0xf0 << 18) + (0x80 << 12) + (0x80 << 6) + 0x80 */ ch = (ch << 18) + (*pSrc++ << 12); ch += *pSrc++ << 6; ch += *pSrc++ - 0x3c82080; *(pDest++) = U16_LEAD(ch); *(pDest++) = U16_TRAIL(ch); length--; /* two bytes for this character */ continue; } } /* truncated character at the end */ *pDest++ = 0xfffd; break; } *pDest++ = 0x0; } #endif int git__utf8_to_16(wchar_t *dest, size_t length, const char *src) { return MultiByteToWideChar(CP_UTF8, 0, src, -1, dest, (int)length); } int git__utf16_to_8(char *out, const wchar_t *input) { return WideCharToMultiByte(CP_UTF8, 0, input, -1, out, GIT_WIN_PATH, NULL, NULL); } libgit2-0.19.0/src/win32/utf-conv.h000066400000000000000000000007171216214232500166030ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #include #ifndef INCLUDE_git_utfconv_h__ #define INCLUDE_git_utfconv_h__ #define GIT_WIN_PATH (260 + 1) int git__utf8_to_16(wchar_t *dest, size_t length, const char *src); int git__utf16_to_8(char *dest, const wchar_t *src); #endif libgit2-0.19.0/src/win32/version.h000066400000000000000000000010021216214232500165130ustar00rootroot00000000000000/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #ifndef INCLUDE_win32_version_h__ #define INCLUDE_win32_version_h__ #include GIT_INLINE(int) git_has_win32_version(int major, int minor) { WORD wVersion = LOWORD(GetVersion()); return LOBYTE(wVersion) > major || (LOBYTE(wVersion) == major && HIBYTE(wVersion) >= minor); } #endif libgit2-0.19.0/src/xdiff/000077500000000000000000000000001216214232500150225ustar00rootroot00000000000000libgit2-0.19.0/src/xdiff/xdiff.h000066400000000000000000000066601216214232500163030ustar00rootroot00000000000000/* * LibXDiff by Davide Libenzi ( File Differential Library ) * Copyright (C) 2003 Davide Libenzi * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Davide Libenzi * */ #if !defined(XDIFF_H) #define XDIFF_H #ifdef __cplusplus extern "C" { #endif /* #ifdef __cplusplus */ #define XDF_NEED_MINIMAL (1 << 1) #define XDF_IGNORE_WHITESPACE (1 << 2) #define XDF_IGNORE_WHITESPACE_CHANGE (1 << 3) #define XDF_IGNORE_WHITESPACE_AT_EOL (1 << 4) #define XDF_PATIENCE_DIFF (1 << 5) #define XDF_HISTOGRAM_DIFF (1 << 6) #define XDF_WHITESPACE_FLAGS (XDF_IGNORE_WHITESPACE | XDF_IGNORE_WHITESPACE_CHANGE | XDF_IGNORE_WHITESPACE_AT_EOL) #define XDL_PATCH_NORMAL '-' #define XDL_PATCH_REVERSE '+' #define XDL_PATCH_MODEMASK ((1 << 8) - 1) #define XDL_PATCH_IGNOREBSPACE (1 << 8) #define XDL_EMIT_FUNCNAMES (1 << 0) #define XDL_EMIT_COMMON (1 << 1) #define XDL_EMIT_FUNCCONTEXT (1 << 2) #define XDL_MMB_READONLY (1 << 0) #define XDL_MMF_ATOMIC (1 << 0) #define XDL_BDOP_INS 1 #define XDL_BDOP_CPY 2 #define XDL_BDOP_INSB 3 /* merge simplification levels */ #define XDL_MERGE_MINIMAL 0 #define XDL_MERGE_EAGER 1 #define XDL_MERGE_ZEALOUS 2 #define XDL_MERGE_ZEALOUS_ALNUM 3 /* merge favor modes */ #define XDL_MERGE_FAVOR_OURS 1 #define XDL_MERGE_FAVOR_THEIRS 2 #define XDL_MERGE_FAVOR_UNION 3 /* merge output styles */ #define XDL_MERGE_DIFF3 1 typedef struct s_mmfile { char *ptr; size_t size; } mmfile_t; typedef struct s_mmbuffer { char *ptr; size_t size; } mmbuffer_t; typedef struct s_xpparam { unsigned long flags; } xpparam_t; typedef struct s_xdemitcb { void *priv; int (*outf)(void *, mmbuffer_t *, int); } xdemitcb_t; typedef long (*find_func_t)(const char *line, long line_len, char *buffer, long buffer_size, void *priv); typedef struct s_xdemitconf { long ctxlen; long interhunkctxlen; unsigned long flags; find_func_t find_func; void *find_func_priv; void (*emit_func)(void); } xdemitconf_t; typedef struct s_bdiffparam { long bsize; } bdiffparam_t; #define xdl_malloc(x) malloc(x) #define xdl_free(ptr) free(ptr) #define xdl_realloc(ptr,x) realloc(ptr,x) void *xdl_mmfile_first(mmfile_t *mmf, long *size); long xdl_mmfile_size(mmfile_t *mmf); int xdl_diff(mmfile_t *mf1, mmfile_t *mf2, xpparam_t const *xpp, xdemitconf_t const *xecfg, xdemitcb_t *ecb); typedef struct s_xmparam { xpparam_t xpp; int marker_size; int level; int favor; int style; const char *ancestor; /* label for orig */ const char *file1; /* label for mf1 */ const char *file2; /* label for mf2 */ } xmparam_t; #define DEFAULT_CONFLICT_MARKER_SIZE 7 int xdl_merge(mmfile_t *orig, mmfile_t *mf1, mmfile_t *mf2, xmparam_t const *xmp, mmbuffer_t *result); #ifdef __cplusplus } #endif /* #ifdef __cplusplus */ #endif /* #if !defined(XDIFF_H) */ libgit2-0.19.0/src/xdiff/xdiffi.c000066400000000000000000000352661216214232500164530ustar00rootroot00000000000000/* * LibXDiff by Davide Libenzi ( File Differential Library ) * Copyright (C) 2003 Davide Libenzi * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Davide Libenzi * */ #include "xinclude.h" #define XDL_MAX_COST_MIN 256 #define XDL_HEUR_MIN_COST 256 #define XDL_LINE_MAX (long)((1UL << (CHAR_BIT * sizeof(long) - 1)) - 1) #define XDL_SNAKE_CNT 20 #define XDL_K_HEUR 4 typedef struct s_xdpsplit { long i1, i2; int min_lo, min_hi; } xdpsplit_t; static long xdl_split(unsigned long const *ha1, long off1, long lim1, unsigned long const *ha2, long off2, long lim2, long *kvdf, long *kvdb, int need_min, xdpsplit_t *spl, xdalgoenv_t *xenv); static xdchange_t *xdl_add_change(xdchange_t *xscr, long i1, long i2, long chg1, long chg2); /* * See "An O(ND) Difference Algorithm and its Variations", by Eugene Myers. * Basically considers a "box" (off1, off2, lim1, lim2) and scan from both * the forward diagonal starting from (off1, off2) and the backward diagonal * starting from (lim1, lim2). If the K values on the same diagonal crosses * returns the furthest point of reach. We might end up having to expensive * cases using this algorithm is full, so a little bit of heuristic is needed * to cut the search and to return a suboptimal point. */ static long xdl_split(unsigned long const *ha1, long off1, long lim1, unsigned long const *ha2, long off2, long lim2, long *kvdf, long *kvdb, int need_min, xdpsplit_t *spl, xdalgoenv_t *xenv) { long dmin = off1 - lim2, dmax = lim1 - off2; long fmid = off1 - off2, bmid = lim1 - lim2; long odd = (fmid - bmid) & 1; long fmin = fmid, fmax = fmid; long bmin = bmid, bmax = bmid; long ec, d, i1, i2, prev1, best, dd, v, k; /* * Set initial diagonal values for both forward and backward path. */ kvdf[fmid] = off1; kvdb[bmid] = lim1; for (ec = 1;; ec++) { int got_snake = 0; /* * We need to extent the diagonal "domain" by one. If the next * values exits the box boundaries we need to change it in the * opposite direction because (max - min) must be a power of two. * Also we initialize the external K value to -1 so that we can * avoid extra conditions check inside the core loop. */ if (fmin > dmin) kvdf[--fmin - 1] = -1; else ++fmin; if (fmax < dmax) kvdf[++fmax + 1] = -1; else --fmax; for (d = fmax; d >= fmin; d -= 2) { if (kvdf[d - 1] >= kvdf[d + 1]) i1 = kvdf[d - 1] + 1; else i1 = kvdf[d + 1]; prev1 = i1; i2 = i1 - d; for (; i1 < lim1 && i2 < lim2 && ha1[i1] == ha2[i2]; i1++, i2++); if (i1 - prev1 > xenv->snake_cnt) got_snake = 1; kvdf[d] = i1; if (odd && bmin <= d && d <= bmax && kvdb[d] <= i1) { spl->i1 = i1; spl->i2 = i2; spl->min_lo = spl->min_hi = 1; return ec; } } /* * We need to extent the diagonal "domain" by one. If the next * values exits the box boundaries we need to change it in the * opposite direction because (max - min) must be a power of two. * Also we initialize the external K value to -1 so that we can * avoid extra conditions check inside the core loop. */ if (bmin > dmin) kvdb[--bmin - 1] = XDL_LINE_MAX; else ++bmin; if (bmax < dmax) kvdb[++bmax + 1] = XDL_LINE_MAX; else --bmax; for (d = bmax; d >= bmin; d -= 2) { if (kvdb[d - 1] < kvdb[d + 1]) i1 = kvdb[d - 1]; else i1 = kvdb[d + 1] - 1; prev1 = i1; i2 = i1 - d; for (; i1 > off1 && i2 > off2 && ha1[i1 - 1] == ha2[i2 - 1]; i1--, i2--); if (prev1 - i1 > xenv->snake_cnt) got_snake = 1; kvdb[d] = i1; if (!odd && fmin <= d && d <= fmax && i1 <= kvdf[d]) { spl->i1 = i1; spl->i2 = i2; spl->min_lo = spl->min_hi = 1; return ec; } } if (need_min) continue; /* * If the edit cost is above the heuristic trigger and if * we got a good snake, we sample current diagonals to see * if some of the, have reached an "interesting" path. Our * measure is a function of the distance from the diagonal * corner (i1 + i2) penalized with the distance from the * mid diagonal itself. If this value is above the current * edit cost times a magic factor (XDL_K_HEUR) we consider * it interesting. */ if (got_snake && ec > xenv->heur_min) { for (best = 0, d = fmax; d >= fmin; d -= 2) { dd = d > fmid ? d - fmid: fmid - d; i1 = kvdf[d]; i2 = i1 - d; v = (i1 - off1) + (i2 - off2) - dd; if (v > XDL_K_HEUR * ec && v > best && off1 + xenv->snake_cnt <= i1 && i1 < lim1 && off2 + xenv->snake_cnt <= i2 && i2 < lim2) { for (k = 1; ha1[i1 - k] == ha2[i2 - k]; k++) if (k == xenv->snake_cnt) { best = v; spl->i1 = i1; spl->i2 = i2; break; } } } if (best > 0) { spl->min_lo = 1; spl->min_hi = 0; return ec; } for (best = 0, d = bmax; d >= bmin; d -= 2) { dd = d > bmid ? d - bmid: bmid - d; i1 = kvdb[d]; i2 = i1 - d; v = (lim1 - i1) + (lim2 - i2) - dd; if (v > XDL_K_HEUR * ec && v > best && off1 < i1 && i1 <= lim1 - xenv->snake_cnt && off2 < i2 && i2 <= lim2 - xenv->snake_cnt) { for (k = 0; ha1[i1 + k] == ha2[i2 + k]; k++) if (k == xenv->snake_cnt - 1) { best = v; spl->i1 = i1; spl->i2 = i2; break; } } } if (best > 0) { spl->min_lo = 0; spl->min_hi = 1; return ec; } } /* * Enough is enough. We spent too much time here and now we collect * the furthest reaching path using the (i1 + i2) measure. */ if (ec >= xenv->mxcost) { long fbest, fbest1, bbest, bbest1; fbest = fbest1 = -1; for (d = fmax; d >= fmin; d -= 2) { i1 = XDL_MIN(kvdf[d], lim1); i2 = i1 - d; if (lim2 < i2) i1 = lim2 + d, i2 = lim2; if (fbest < i1 + i2) { fbest = i1 + i2; fbest1 = i1; } } bbest = bbest1 = XDL_LINE_MAX; for (d = bmax; d >= bmin; d -= 2) { i1 = XDL_MAX(off1, kvdb[d]); i2 = i1 - d; if (i2 < off2) i1 = off2 + d, i2 = off2; if (i1 + i2 < bbest) { bbest = i1 + i2; bbest1 = i1; } } if ((lim1 + lim2) - bbest < fbest - (off1 + off2)) { spl->i1 = fbest1; spl->i2 = fbest - fbest1; spl->min_lo = 1; spl->min_hi = 0; } else { spl->i1 = bbest1; spl->i2 = bbest - bbest1; spl->min_lo = 0; spl->min_hi = 1; } return ec; } } } /* * Rule: "Divide et Impera". Recursively split the box in sub-boxes by calling * the box splitting function. Note that the real job (marking changed lines) * is done in the two boundary reaching checks. */ int xdl_recs_cmp(diffdata_t *dd1, long off1, long lim1, diffdata_t *dd2, long off2, long lim2, long *kvdf, long *kvdb, int need_min, xdalgoenv_t *xenv) { unsigned long const *ha1 = dd1->ha, *ha2 = dd2->ha; /* * Shrink the box by walking through each diagonal snake (SW and NE). */ for (; off1 < lim1 && off2 < lim2 && ha1[off1] == ha2[off2]; off1++, off2++); for (; off1 < lim1 && off2 < lim2 && ha1[lim1 - 1] == ha2[lim2 - 1]; lim1--, lim2--); /* * If one dimension is empty, then all records on the other one must * be obviously changed. */ if (off1 == lim1) { char *rchg2 = dd2->rchg; long *rindex2 = dd2->rindex; for (; off2 < lim2; off2++) rchg2[rindex2[off2]] = 1; } else if (off2 == lim2) { char *rchg1 = dd1->rchg; long *rindex1 = dd1->rindex; for (; off1 < lim1; off1++) rchg1[rindex1[off1]] = 1; } else { xdpsplit_t spl; spl.i1 = spl.i2 = 0; /* * Divide ... */ if (xdl_split(ha1, off1, lim1, ha2, off2, lim2, kvdf, kvdb, need_min, &spl, xenv) < 0) { return -1; } /* * ... et Impera. */ if (xdl_recs_cmp(dd1, off1, spl.i1, dd2, off2, spl.i2, kvdf, kvdb, spl.min_lo, xenv) < 0 || xdl_recs_cmp(dd1, spl.i1, lim1, dd2, spl.i2, lim2, kvdf, kvdb, spl.min_hi, xenv) < 0) { return -1; } } return 0; } int xdl_do_diff(mmfile_t *mf1, mmfile_t *mf2, xpparam_t const *xpp, xdfenv_t *xe) { long ndiags; long *kvd, *kvdf, *kvdb; xdalgoenv_t xenv; diffdata_t dd1, dd2; if (xpp->flags & XDF_PATIENCE_DIFF) return xdl_do_patience_diff(mf1, mf2, xpp, xe); if (xpp->flags & XDF_HISTOGRAM_DIFF) return xdl_do_histogram_diff(mf1, mf2, xpp, xe); if (xdl_prepare_env(mf1, mf2, xpp, xe) < 0) { return -1; } /* * Allocate and setup K vectors to be used by the differential algorithm. * One is to store the forward path and one to store the backward path. */ ndiags = xe->xdf1.nreff + xe->xdf2.nreff + 3; if (!(kvd = (long *) xdl_malloc((2 * ndiags + 2) * sizeof(long)))) { xdl_free_env(xe); return -1; } kvdf = kvd; kvdb = kvdf + ndiags; kvdf += xe->xdf2.nreff + 1; kvdb += xe->xdf2.nreff + 1; xenv.mxcost = xdl_bogosqrt(ndiags); if (xenv.mxcost < XDL_MAX_COST_MIN) xenv.mxcost = XDL_MAX_COST_MIN; xenv.snake_cnt = XDL_SNAKE_CNT; xenv.heur_min = XDL_HEUR_MIN_COST; dd1.nrec = xe->xdf1.nreff; dd1.ha = xe->xdf1.ha; dd1.rchg = xe->xdf1.rchg; dd1.rindex = xe->xdf1.rindex; dd2.nrec = xe->xdf2.nreff; dd2.ha = xe->xdf2.ha; dd2.rchg = xe->xdf2.rchg; dd2.rindex = xe->xdf2.rindex; if (xdl_recs_cmp(&dd1, 0, dd1.nrec, &dd2, 0, dd2.nrec, kvdf, kvdb, (xpp->flags & XDF_NEED_MINIMAL) != 0, &xenv) < 0) { xdl_free(kvd); xdl_free_env(xe); return -1; } xdl_free(kvd); return 0; } static xdchange_t *xdl_add_change(xdchange_t *xscr, long i1, long i2, long chg1, long chg2) { xdchange_t *xch; if (!(xch = (xdchange_t *) xdl_malloc(sizeof(xdchange_t)))) return NULL; xch->next = xscr; xch->i1 = i1; xch->i2 = i2; xch->chg1 = chg1; xch->chg2 = chg2; return xch; } int xdl_change_compact(xdfile_t *xdf, xdfile_t *xdfo, long flags) { long ix, ixo, ixs, ixref, grpsiz, nrec = xdf->nrec; char *rchg = xdf->rchg, *rchgo = xdfo->rchg; xrecord_t **recs = xdf->recs; /* * This is the same of what GNU diff does. Move back and forward * change groups for a consistent and pretty diff output. This also * helps in finding joinable change groups and reduce the diff size. */ for (ix = ixo = 0;;) { /* * Find the first changed line in the to-be-compacted file. * We need to keep track of both indexes, so if we find a * changed lines group on the other file, while scanning the * to-be-compacted file, we need to skip it properly. Note * that loops that are testing for changed lines on rchg* do * not need index bounding since the array is prepared with * a zero at position -1 and N. */ for (; ix < nrec && !rchg[ix]; ix++) while (rchgo[ixo++]); if (ix == nrec) break; /* * Record the start of a changed-group in the to-be-compacted file * and find the end of it, on both to-be-compacted and other file * indexes (ix and ixo). */ ixs = ix; for (ix++; rchg[ix]; ix++); for (; rchgo[ixo]; ixo++); do { grpsiz = ix - ixs; /* * If the line before the current change group, is equal to * the last line of the current change group, shift backward * the group. */ while (ixs > 0 && recs[ixs - 1]->ha == recs[ix - 1]->ha && xdl_recmatch(recs[ixs - 1]->ptr, recs[ixs - 1]->size, recs[ix - 1]->ptr, recs[ix - 1]->size, flags)) { rchg[--ixs] = 1; rchg[--ix] = 0; /* * This change might have joined two change groups, * so we try to take this scenario in account by moving * the start index accordingly (and so the other-file * end-of-group index). */ for (; rchg[ixs - 1]; ixs--); while (rchgo[--ixo]); } /* * Record the end-of-group position in case we are matched * with a group of changes in the other file (that is, the * change record before the end-of-group index in the other * file is set). */ ixref = rchgo[ixo - 1] ? ix: nrec; /* * If the first line of the current change group, is equal to * the line next of the current change group, shift forward * the group. */ while (ix < nrec && recs[ixs]->ha == recs[ix]->ha && xdl_recmatch(recs[ixs]->ptr, recs[ixs]->size, recs[ix]->ptr, recs[ix]->size, flags)) { rchg[ixs++] = 0; rchg[ix++] = 1; /* * This change might have joined two change groups, * so we try to take this scenario in account by moving * the start index accordingly (and so the other-file * end-of-group index). Keep tracking the reference * index in case we are shifting together with a * corresponding group of changes in the other file. */ for (; rchg[ix]; ix++); while (rchgo[++ixo]) ixref = ix; } } while (grpsiz != ix - ixs); /* * Try to move back the possibly merged group of changes, to match * the recorded postion in the other file. */ while (ixref < ix) { rchg[--ixs] = 1; rchg[--ix] = 0; while (rchgo[--ixo]); } } return 0; } int xdl_build_script(xdfenv_t *xe, xdchange_t **xscr) { xdchange_t *cscr = NULL, *xch; char *rchg1 = xe->xdf1.rchg, *rchg2 = xe->xdf2.rchg; long i1, i2, l1, l2; /* * Trivial. Collects "groups" of changes and creates an edit script. */ for (i1 = xe->xdf1.nrec, i2 = xe->xdf2.nrec; i1 >= 0 || i2 >= 0; i1--, i2--) if (rchg1[i1 - 1] || rchg2[i2 - 1]) { for (l1 = i1; rchg1[i1 - 1]; i1--); for (l2 = i2; rchg2[i2 - 1]; i2--); if (!(xch = xdl_add_change(cscr, i1, i2, l1 - i1, l2 - i2))) { xdl_free_script(cscr); return -1; } cscr = xch; } *xscr = cscr; return 0; } void xdl_free_script(xdchange_t *xscr) { xdchange_t *xch; while ((xch = xscr) != NULL) { xscr = xscr->next; xdl_free(xch); } } int xdl_diff(mmfile_t *mf1, mmfile_t *mf2, xpparam_t const *xpp, xdemitconf_t const *xecfg, xdemitcb_t *ecb) { xdchange_t *xscr; xdfenv_t xe; emit_func_t ef = xecfg->emit_func ? (emit_func_t)xecfg->emit_func : xdl_emit_diff; if (xdl_do_diff(mf1, mf2, xpp, &xe) < 0) { return -1; } if (xdl_change_compact(&xe.xdf1, &xe.xdf2, xpp->flags) < 0 || xdl_change_compact(&xe.xdf2, &xe.xdf1, xpp->flags) < 0 || xdl_build_script(&xe, &xscr) < 0) { xdl_free_env(&xe); return -1; } if (xscr) { if (ef(&xe, xscr, ecb, xecfg) < 0) { xdl_free_script(xscr); xdl_free_env(&xe); return -1; } xdl_free_script(xscr); } xdl_free_env(&xe); return 0; } libgit2-0.19.0/src/xdiff/xdiffi.h000066400000000000000000000037041216214232500164500ustar00rootroot00000000000000/* * LibXDiff by Davide Libenzi ( File Differential Library ) * Copyright (C) 2003 Davide Libenzi * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Davide Libenzi * */ #if !defined(XDIFFI_H) #define XDIFFI_H typedef struct s_diffdata { long nrec; unsigned long const *ha; long *rindex; char *rchg; } diffdata_t; typedef struct s_xdalgoenv { long mxcost; long snake_cnt; long heur_min; } xdalgoenv_t; typedef struct s_xdchange { struct s_xdchange *next; long i1, i2; long chg1, chg2; } xdchange_t; int xdl_recs_cmp(diffdata_t *dd1, long off1, long lim1, diffdata_t *dd2, long off2, long lim2, long *kvdf, long *kvdb, int need_min, xdalgoenv_t *xenv); int xdl_do_diff(mmfile_t *mf1, mmfile_t *mf2, xpparam_t const *xpp, xdfenv_t *xe); int xdl_change_compact(xdfile_t *xdf, xdfile_t *xdfo, long flags); int xdl_build_script(xdfenv_t *xe, xdchange_t **xscr); void xdl_free_script(xdchange_t *xscr); int xdl_emit_diff(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb, xdemitconf_t const *xecfg); int xdl_do_patience_diff(mmfile_t *mf1, mmfile_t *mf2, xpparam_t const *xpp, xdfenv_t *env); int xdl_do_histogram_diff(mmfile_t *mf1, mmfile_t *mf2, xpparam_t const *xpp, xdfenv_t *env); #endif /* #if !defined(XDIFFI_H) */ libgit2-0.19.0/src/xdiff/xemit.c000066400000000000000000000141421216214232500163160ustar00rootroot00000000000000/* * LibXDiff by Davide Libenzi ( File Differential Library ) * Copyright (C) 2003 Davide Libenzi * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Davide Libenzi * */ #include "xinclude.h" static long xdl_get_rec(xdfile_t *xdf, long ri, char const **rec); static int xdl_emit_record(xdfile_t *xdf, long ri, char const *pre, xdemitcb_t *ecb); static long xdl_get_rec(xdfile_t *xdf, long ri, char const **rec) { *rec = xdf->recs[ri]->ptr; return xdf->recs[ri]->size; } static int xdl_emit_record(xdfile_t *xdf, long ri, char const *pre, xdemitcb_t *ecb) { long size, psize = (long)strlen(pre); char const *rec; size = xdl_get_rec(xdf, ri, &rec); if (xdl_emit_diffrec(rec, size, pre, psize, ecb) < 0) { return -1; } return 0; } /* * Starting at the passed change atom, find the latest change atom to be included * inside the differential hunk according to the specified configuration. */ xdchange_t *xdl_get_hunk(xdchange_t *xscr, xdemitconf_t const *xecfg) { xdchange_t *xch, *xchp; long max_common = 2 * xecfg->ctxlen + xecfg->interhunkctxlen; for (xchp = xscr, xch = xscr->next; xch; xchp = xch, xch = xch->next) if (xch->i1 - (xchp->i1 + xchp->chg1) > max_common) break; return xchp; } static long def_ff(const char *rec, long len, char *buf, long sz, void *priv) { (void)priv; if (len > 0 && (isalpha((unsigned char)*rec) || /* identifier? */ *rec == '_' || /* also identifier? */ *rec == '$')) { /* identifiers from VMS and other esoterico */ if (len > sz) len = sz; while (0 < len && isspace((unsigned char)rec[len - 1])) len--; memcpy(buf, rec, len); return len; } return -1; } static int xdl_emit_common(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb, xdemitconf_t const *xecfg) { xdfile_t *xdf = &xe->xdf2; const char *rchg = xdf->rchg; long ix; (void)xscr; (void)xecfg; for (ix = 0; ix < xdf->nrec; ix++) { if (rchg[ix]) continue; if (xdl_emit_record(xdf, ix, "", ecb)) return -1; } return 0; } struct func_line { long len; char buf[80]; }; static long get_func_line(xdfenv_t *xe, xdemitconf_t const *xecfg, struct func_line *func_line, long start, long limit) { find_func_t ff = xecfg->find_func ? xecfg->find_func : def_ff; long l, size, step = (start > limit) ? -1 : 1; char *buf, dummy[1]; buf = func_line ? func_line->buf : dummy; size = func_line ? sizeof(func_line->buf) : sizeof(dummy); for (l = start; l != limit && 0 <= l && l < xe->xdf1.nrec; l += step) { const char *rec; long reclen = xdl_get_rec(&xe->xdf1, l, &rec); long len = ff(rec, reclen, buf, size, xecfg->find_func_priv); if (len >= 0) { if (func_line) func_line->len = len; return l; } } return -1; } int xdl_emit_diff(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb, xdemitconf_t const *xecfg) { long s1, s2, e1, e2, lctx; xdchange_t *xch, *xche; long funclineprev = -1; struct func_line func_line = { 0 }; if (xecfg->flags & XDL_EMIT_COMMON) return xdl_emit_common(xe, xscr, ecb, xecfg); for (xch = xscr; xch; xch = xche->next) { xche = xdl_get_hunk(xch, xecfg); s1 = XDL_MAX(xch->i1 - xecfg->ctxlen, 0); s2 = XDL_MAX(xch->i2 - xecfg->ctxlen, 0); if (xecfg->flags & XDL_EMIT_FUNCCONTEXT) { long fs1 = get_func_line(xe, xecfg, NULL, xch->i1, -1); if (fs1 < 0) fs1 = 0; if (fs1 < s1) { s2 -= s1 - fs1; s1 = fs1; } } again: lctx = xecfg->ctxlen; lctx = XDL_MIN(lctx, xe->xdf1.nrec - (xche->i1 + xche->chg1)); lctx = XDL_MIN(lctx, xe->xdf2.nrec - (xche->i2 + xche->chg2)); e1 = xche->i1 + xche->chg1 + lctx; e2 = xche->i2 + xche->chg2 + lctx; if (xecfg->flags & XDL_EMIT_FUNCCONTEXT) { long fe1 = get_func_line(xe, xecfg, NULL, xche->i1 + xche->chg1, xe->xdf1.nrec); if (fe1 < 0) fe1 = xe->xdf1.nrec; if (fe1 > e1) { e2 += fe1 - e1; e1 = fe1; } /* * Overlap with next change? Then include it * in the current hunk and start over to find * its new end. */ if (xche->next) { long l = xche->next->i1; if (l <= e1 || get_func_line(xe, xecfg, NULL, l, e1) < 0) { xche = xche->next; goto again; } } } /* * Emit current hunk header. */ if (xecfg->flags & XDL_EMIT_FUNCNAMES) { get_func_line(xe, xecfg, &func_line, s1 - 1, funclineprev); funclineprev = s1 - 1; } if (xdl_emit_hunk_hdr(s1 + 1, e1 - s1, s2 + 1, e2 - s2, func_line.buf, func_line.len, ecb) < 0) return -1; /* * Emit pre-context. */ for (; s2 < xch->i2; s2++) if (xdl_emit_record(&xe->xdf2, s2, " ", ecb) < 0) return -1; for (s1 = xch->i1, s2 = xch->i2;; xch = xch->next) { /* * Merge previous with current change atom. */ for (; s1 < xch->i1 && s2 < xch->i2; s1++, s2++) if (xdl_emit_record(&xe->xdf2, s2, " ", ecb) < 0) return -1; /* * Removes lines from the first file. */ for (s1 = xch->i1; s1 < xch->i1 + xch->chg1; s1++) if (xdl_emit_record(&xe->xdf1, s1, "-", ecb) < 0) return -1; /* * Adds lines from the second file. */ for (s2 = xch->i2; s2 < xch->i2 + xch->chg2; s2++) if (xdl_emit_record(&xe->xdf2, s2, "+", ecb) < 0) return -1; if (xch == xche) break; s1 = xch->i1 + xch->chg1; s2 = xch->i2 + xch->chg2; } /* * Emit post-context. */ for (s2 = xche->i2 + xche->chg2; s2 < e2; s2++) if (xdl_emit_record(&xe->xdf2, s2, " ", ecb) < 0) return -1; } return 0; } libgit2-0.19.0/src/xdiff/xemit.h000066400000000000000000000023641216214232500163260ustar00rootroot00000000000000/* * LibXDiff by Davide Libenzi ( File Differential Library ) * Copyright (C) 2003 Davide Libenzi * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Davide Libenzi * */ #if !defined(XEMIT_H) #define XEMIT_H typedef int (*emit_func_t)(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb, xdemitconf_t const *xecfg); xdchange_t *xdl_get_hunk(xdchange_t *xscr, xdemitconf_t const *xecfg); int xdl_emit_diff(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb, xdemitconf_t const *xecfg); #endif /* #if !defined(XEMIT_H) */ libgit2-0.19.0/src/xdiff/xhistogram.c000066400000000000000000000222041216214232500173530ustar00rootroot00000000000000/* * Copyright (C) 2010, Google Inc. * and other copyright owners as documented in JGit's IP log. * * This program and the accompanying materials are made available * under the terms of the Eclipse Distribution License v1.0 which * accompanies this distribution, is reproduced below, and is * available at http://www.eclipse.org/org/documents/edl-v10.php * * All rights reserved. * * Redistribution and use in source and binary forms, with or * without modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials provided * with the distribution. * * - Neither the name of the Eclipse Foundation, Inc. nor the * names of its contributors may be used to endorse or promote * products derived from this software without specific prior * written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "xinclude.h" #include "xtypes.h" #include "xdiff.h" #define MAX_PTR UINT_MAX #define MAX_CNT UINT_MAX #define LINE_END(n) (line##n + count##n - 1) #define LINE_END_PTR(n) (*line##n + *count##n - 1) struct histindex { struct record { unsigned int ptr, cnt; struct record *next; } **records, /* an ocurrence */ **line_map; /* map of line to record chain */ chastore_t rcha; unsigned int *next_ptrs; unsigned int table_bits, records_size, line_map_size; unsigned int max_chain_length, key_shift, ptr_shift; unsigned int cnt, has_common; xdfenv_t *env; xpparam_t const *xpp; }; struct region { unsigned int begin1, end1; unsigned int begin2, end2; }; #define LINE_MAP(i, a) (i->line_map[(a) - i->ptr_shift]) #define NEXT_PTR(index, ptr) \ (index->next_ptrs[(ptr) - index->ptr_shift]) #define CNT(index, ptr) \ ((LINE_MAP(index, ptr))->cnt) #define REC(env, s, l) \ (env->xdf##s.recs[l - 1]) static int cmp_recs(xpparam_t const *xpp, xrecord_t *r1, xrecord_t *r2) { return r1->ha == r2->ha && xdl_recmatch(r1->ptr, r1->size, r2->ptr, r2->size, xpp->flags); } #define CMP_ENV(xpp, env, s1, l1, s2, l2) \ (cmp_recs(xpp, REC(env, s1, l1), REC(env, s2, l2))) #define CMP(i, s1, l1, s2, l2) \ (cmp_recs(i->xpp, REC(i->env, s1, l1), REC(i->env, s2, l2))) #define TABLE_HASH(index, side, line) \ XDL_HASHLONG((REC(index->env, side, line))->ha, index->table_bits) static int scanA(struct histindex *index, unsigned int line1, unsigned int count1) { unsigned int ptr; unsigned int tbl_idx; unsigned int chain_len; struct record **rec_chain, *rec; for (ptr = LINE_END(1); line1 <= ptr; ptr--) { tbl_idx = TABLE_HASH(index, 1, ptr); rec_chain = index->records + tbl_idx; rec = *rec_chain; chain_len = 0; while (rec) { if (CMP(index, 1, rec->ptr, 1, ptr)) { /* * ptr is identical to another element. Insert * it onto the front of the existing element * chain. */ NEXT_PTR(index, ptr) = rec->ptr; rec->ptr = ptr; /* cap rec->cnt at MAX_CNT */ rec->cnt = XDL_MIN(MAX_CNT, rec->cnt + 1); LINE_MAP(index, ptr) = rec; goto continue_scan; } rec = rec->next; chain_len++; } if (chain_len == index->max_chain_length) return -1; /* * This is the first time we have ever seen this particular * element in the sequence. Construct a new chain for it. */ if (!(rec = xdl_cha_alloc(&index->rcha))) return -1; rec->ptr = ptr; rec->cnt = 1; rec->next = *rec_chain; *rec_chain = rec; LINE_MAP(index, ptr) = rec; continue_scan: ; /* no op */ } return 0; } static int try_lcs( struct histindex *index, struct region *lcs, unsigned int b_ptr, unsigned int line1, unsigned int count1, unsigned int line2, unsigned int count2) { unsigned int b_next = b_ptr + 1; struct record *rec = index->records[TABLE_HASH(index, 2, b_ptr)]; unsigned int as, ae, bs, be, np, rc; int should_break; for (; rec; rec = rec->next) { if (rec->cnt > index->cnt) { if (!index->has_common) index->has_common = CMP(index, 1, rec->ptr, 2, b_ptr); continue; } as = rec->ptr; if (!CMP(index, 1, as, 2, b_ptr)) continue; index->has_common = 1; for (;;) { should_break = 0; np = NEXT_PTR(index, as); bs = b_ptr; ae = as; be = bs; rc = rec->cnt; while (line1 < as && line2 < bs && CMP(index, 1, as - 1, 2, bs - 1)) { as--; bs--; if (1 < rc) rc = XDL_MIN(rc, CNT(index, as)); } while (ae < LINE_END(1) && be < LINE_END(2) && CMP(index, 1, ae + 1, 2, be + 1)) { ae++; be++; if (1 < rc) rc = XDL_MIN(rc, CNT(index, ae)); } if (b_next <= be) b_next = be + 1; if (lcs->end1 - lcs->begin1 < ae - as || rc < index->cnt) { lcs->begin1 = as; lcs->begin2 = bs; lcs->end1 = ae; lcs->end2 = be; index->cnt = rc; } if (np == 0) break; while (np <= ae) { np = NEXT_PTR(index, np); if (np == 0) { should_break = 1; break; } } if (should_break) break; as = np; } } return b_next; } static int find_lcs( struct histindex *index, struct region *lcs, unsigned int line1, unsigned int count1, unsigned int line2, unsigned int count2) { unsigned int b_ptr; if (scanA(index, line1, count1)) return -1; index->cnt = index->max_chain_length + 1; for (b_ptr = line2; b_ptr <= LINE_END(2); ) b_ptr = try_lcs(index, lcs, b_ptr, line1, count1, line2, count2); return index->has_common && index->max_chain_length < index->cnt; } static int fall_back_to_classic_diff(struct histindex *index, int line1, int count1, int line2, int count2) { xpparam_t xpp; xpp.flags = index->xpp->flags & ~XDF_HISTOGRAM_DIFF; return xdl_fall_back_diff(index->env, &xpp, line1, count1, line2, count2); } static int histogram_diff( xpparam_t const *xpp, xdfenv_t *env, unsigned int line1, unsigned int count1, unsigned int line2, unsigned int count2) { struct histindex index; struct region lcs; unsigned int sz; int result = -1; if (count1 <= 0 && count2 <= 0) return 0; if (LINE_END(1) >= MAX_PTR) return -1; if (!count1) { while(count2--) env->xdf2.rchg[line2++ - 1] = 1; return 0; } else if (!count2) { while(count1--) env->xdf1.rchg[line1++ - 1] = 1; return 0; } memset(&index, 0, sizeof(index)); index.env = env; index.xpp = xpp; index.records = NULL; index.line_map = NULL; /* in case of early xdl_cha_free() */ index.rcha.head = NULL; index.table_bits = xdl_hashbits(count1); sz = index.records_size = 1 << index.table_bits; sz *= sizeof(struct record *); if (!(index.records = (struct record **) xdl_malloc(sz))) goto cleanup; memset(index.records, 0, sz); sz = index.line_map_size = count1; sz *= sizeof(struct record *); if (!(index.line_map = (struct record **) xdl_malloc(sz))) goto cleanup; memset(index.line_map, 0, sz); sz = index.line_map_size; sz *= sizeof(unsigned int); if (!(index.next_ptrs = (unsigned int *) xdl_malloc(sz))) goto cleanup; memset(index.next_ptrs, 0, sz); /* lines / 4 + 1 comes from xprepare.c:xdl_prepare_ctx() */ if (xdl_cha_init(&index.rcha, sizeof(struct record), count1 / 4 + 1) < 0) goto cleanup; index.ptr_shift = line1; index.max_chain_length = 64; memset(&lcs, 0, sizeof(lcs)); if (find_lcs(&index, &lcs, line1, count1, line2, count2)) result = fall_back_to_classic_diff(&index, line1, count1, line2, count2); else { if (lcs.begin1 == 0 && lcs.begin2 == 0) { while (count1--) env->xdf1.rchg[line1++ - 1] = 1; while (count2--) env->xdf2.rchg[line2++ - 1] = 1; result = 0; } else { result = histogram_diff(xpp, env, line1, lcs.begin1 - line1, line2, lcs.begin2 - line2); if (result) goto cleanup; result = histogram_diff(xpp, env, lcs.end1 + 1, LINE_END(1) - lcs.end1, lcs.end2 + 1, LINE_END(2) - lcs.end2); if (result) goto cleanup; } } cleanup: xdl_free(index.records); xdl_free(index.line_map); xdl_free(index.next_ptrs); xdl_cha_free(&index.rcha); return result; } int xdl_do_histogram_diff(mmfile_t *file1, mmfile_t *file2, xpparam_t const *xpp, xdfenv_t *env) { if (xdl_prepare_env(file1, file2, xpp, env) < 0) return -1; return histogram_diff(xpp, env, env->xdf1.dstart + 1, env->xdf1.dend - env->xdf1.dstart + 1, env->xdf2.dstart + 1, env->xdf2.dend - env->xdf2.dstart + 1); } libgit2-0.19.0/src/xdiff/xinclude.h000066400000000000000000000024021216214232500170040ustar00rootroot00000000000000/* * LibXDiff by Davide Libenzi ( File Differential Library ) * Copyright (C) 2003 Davide Libenzi * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Davide Libenzi * */ #if !defined(XINCLUDE_H) #define XINCLUDE_H #include #include #include #include #include #ifdef _WIN32 #else #include #endif #include "xmacros.h" #include "xdiff.h" #include "xtypes.h" #include "xutils.h" #include "xprepare.h" #include "xdiffi.h" #include "xemit.h" #endif /* #if !defined(XINCLUDE_H) */ libgit2-0.19.0/src/xdiff/xmacros.h000066400000000000000000000036561216214232500166610ustar00rootroot00000000000000/* * LibXDiff by Davide Libenzi ( File Differential Library ) * Copyright (C) 2003 Davide Libenzi * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Davide Libenzi * */ #if !defined(XMACROS_H) #define XMACROS_H #define XDL_MIN(a, b) ((a) < (b) ? (a): (b)) #define XDL_MAX(a, b) ((a) > (b) ? (a): (b)) #define XDL_ABS(v) ((v) >= 0 ? (v): -(v)) #define XDL_ISDIGIT(c) ((c) >= '0' && (c) <= '9') #define XDL_ISSPACE(c) (isspace((unsigned char)(c))) #define XDL_ADDBITS(v,b) ((v) + ((v) >> (b))) #define XDL_MASKBITS(b) ((1UL << (b)) - 1) #define XDL_HASHLONG(v,b) (XDL_ADDBITS((unsigned long)(v), b) & XDL_MASKBITS(b)) #define XDL_PTRFREE(p) do { if (p) { xdl_free(p); (p) = NULL; } } while (0) #define XDL_LE32_PUT(p, v) \ do { \ unsigned char *__p = (unsigned char *) (p); \ *__p++ = (unsigned char) (v); \ *__p++ = (unsigned char) ((v) >> 8); \ *__p++ = (unsigned char) ((v) >> 16); \ *__p = (unsigned char) ((v) >> 24); \ } while (0) #define XDL_LE32_GET(p, v) \ do { \ unsigned char const *__p = (unsigned char const *) (p); \ (v) = (unsigned long) __p[0] | ((unsigned long) __p[1]) << 8 | \ ((unsigned long) __p[2]) << 16 | ((unsigned long) __p[3]) << 24; \ } while (0) #endif /* #if !defined(XMACROS_H) */ libgit2-0.19.0/src/xdiff/xmerge.c000066400000000000000000000361661216214232500164710ustar00rootroot00000000000000/* * LibXDiff by Davide Libenzi ( File Differential Library ) * Copyright (C) 2003-2006 Davide Libenzi, Johannes E. Schindelin * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Davide Libenzi * */ #include "xinclude.h" typedef struct s_xdmerge { struct s_xdmerge *next; /* * 0 = conflict, * 1 = no conflict, take first, * 2 = no conflict, take second. * 3 = no conflict, take both. */ int mode; /* * These point at the respective postimages. E.g. is * how side #1 wants to change the common ancestor; if there is no * overlap, lines before i1 in the postimage of side #1 appear * in the merge result as a region touched by neither side. */ long i1, i2; long chg1, chg2; /* * These point at the preimage; of course there is just one * preimage, that is from the shared common ancestor. */ long i0; long chg0; } xdmerge_t; static int xdl_append_merge(xdmerge_t **merge, int mode, long i0, long chg0, long i1, long chg1, long i2, long chg2) { xdmerge_t *m = *merge; if (m && (i1 <= m->i1 + m->chg1 || i2 <= m->i2 + m->chg2)) { if (mode != m->mode) m->mode = 0; m->chg0 = i0 + chg0 - m->i0; m->chg1 = i1 + chg1 - m->i1; m->chg2 = i2 + chg2 - m->i2; } else { m = xdl_malloc(sizeof(xdmerge_t)); if (!m) return -1; m->next = NULL; m->mode = mode; m->i0 = i0; m->chg0 = chg0; m->i1 = i1; m->chg1 = chg1; m->i2 = i2; m->chg2 = chg2; if (*merge) (*merge)->next = m; *merge = m; } return 0; } static int xdl_cleanup_merge(xdmerge_t *c) { int count = 0; xdmerge_t *next_c; /* were there conflicts? */ for (; c; c = next_c) { if (c->mode == 0) count++; next_c = c->next; free(c); } return count; } static int xdl_merge_cmp_lines(xdfenv_t *xe1, int i1, xdfenv_t *xe2, int i2, int line_count, long flags) { int i; xrecord_t **rec1 = xe1->xdf2.recs + i1; xrecord_t **rec2 = xe2->xdf2.recs + i2; for (i = 0; i < line_count; i++) { int result = xdl_recmatch(rec1[i]->ptr, rec1[i]->size, rec2[i]->ptr, rec2[i]->size, flags); if (!result) return -1; } return 0; } static int xdl_recs_copy_0(int use_orig, xdfenv_t *xe, int i, int count, int add_nl, char *dest) { xrecord_t **recs; int size = 0; recs = (use_orig ? xe->xdf1.recs : xe->xdf2.recs) + i; if (count < 1) return 0; for (i = 0; i < count; size += recs[i++]->size) if (dest) memcpy(dest + size, recs[i]->ptr, recs[i]->size); if (add_nl) { i = recs[count - 1]->size; if (i == 0 || recs[count - 1]->ptr[i - 1] != '\n') { if (dest) dest[size] = '\n'; size++; } } return size; } static int xdl_recs_copy(xdfenv_t *xe, int i, int count, int add_nl, char *dest) { return xdl_recs_copy_0(0, xe, i, count, add_nl, dest); } static int xdl_orig_copy(xdfenv_t *xe, int i, int count, int add_nl, char *dest) { return xdl_recs_copy_0(1, xe, i, count, add_nl, dest); } static int fill_conflict_hunk(xdfenv_t *xe1, const char *name1, xdfenv_t *xe2, const char *name2, const char *name3, int size, int i, int style, xdmerge_t *m, char *dest, int marker_size) { int marker1_size = (name1 ? (int)strlen(name1) + 1 : 0); int marker2_size = (name2 ? (int)strlen(name2) + 1 : 0); int marker3_size = (name3 ? (int)strlen(name3) + 1 : 0); if (marker_size <= 0) marker_size = DEFAULT_CONFLICT_MARKER_SIZE; /* Before conflicting part */ size += xdl_recs_copy(xe1, i, m->i1 - i, 0, dest ? dest + size : NULL); if (!dest) { size += marker_size + 1 + marker1_size; } else { memset(dest + size, '<', marker_size); size += marker_size; if (marker1_size) { dest[size] = ' '; memcpy(dest + size + 1, name1, marker1_size - 1); size += marker1_size; } dest[size++] = '\n'; } /* Postimage from side #1 */ size += xdl_recs_copy(xe1, m->i1, m->chg1, 1, dest ? dest + size : NULL); if (style == XDL_MERGE_DIFF3) { /* Shared preimage */ if (!dest) { size += marker_size + 1 + marker3_size; } else { memset(dest + size, '|', marker_size); size += marker_size; if (marker3_size) { dest[size] = ' '; memcpy(dest + size + 1, name3, marker3_size - 1); size += marker3_size; } dest[size++] = '\n'; } size += xdl_orig_copy(xe1, m->i0, m->chg0, 1, dest ? dest + size : NULL); } if (!dest) { size += marker_size + 1; } else { memset(dest + size, '=', marker_size); size += marker_size; dest[size++] = '\n'; } /* Postimage from side #2 */ size += xdl_recs_copy(xe2, m->i2, m->chg2, 1, dest ? dest + size : NULL); if (!dest) { size += marker_size + 1 + marker2_size; } else { memset(dest + size, '>', marker_size); size += marker_size; if (marker2_size) { dest[size] = ' '; memcpy(dest + size + 1, name2, marker2_size - 1); size += marker2_size; } dest[size++] = '\n'; } return size; } static int xdl_fill_merge_buffer(xdfenv_t *xe1, const char *name1, xdfenv_t *xe2, const char *name2, const char *ancestor_name, int favor, xdmerge_t *m, char *dest, int style, int marker_size) { int size, i; for (size = i = 0; m; m = m->next) { if (favor && !m->mode) m->mode = favor; if (m->mode == 0) size = fill_conflict_hunk(xe1, name1, xe2, name2, ancestor_name, size, i, style, m, dest, marker_size); else if (m->mode & 3) { /* Before conflicting part */ size += xdl_recs_copy(xe1, i, m->i1 - i, 0, dest ? dest + size : NULL); /* Postimage from side #1 */ if (m->mode & 1) size += xdl_recs_copy(xe1, m->i1, m->chg1, 1, dest ? dest + size : NULL); /* Postimage from side #2 */ if (m->mode & 2) size += xdl_recs_copy(xe2, m->i2, m->chg2, 1, dest ? dest + size : NULL); } else continue; i = m->i1 + m->chg1; } size += xdl_recs_copy(xe1, i, xe1->xdf2.nrec - i, 0, dest ? dest + size : NULL); return size; } /* * Sometimes, changes are not quite identical, but differ in only a few * lines. Try hard to show only these few lines as conflicting. */ static int xdl_refine_conflicts(xdfenv_t *xe1, xdfenv_t *xe2, xdmerge_t *m, xpparam_t const *xpp) { for (; m; m = m->next) { mmfile_t t1, t2; xdfenv_t xe; xdchange_t *xscr, *x; int i1 = m->i1, i2 = m->i2; /* let's handle just the conflicts */ if (m->mode) continue; /* no sense refining a conflict when one side is empty */ if (m->chg1 == 0 || m->chg2 == 0) continue; /* * This probably does not work outside git, since * we have a very simple mmfile structure. */ t1.ptr = (char *)xe1->xdf2.recs[m->i1]->ptr; t1.size = xe1->xdf2.recs[m->i1 + m->chg1 - 1]->ptr + xe1->xdf2.recs[m->i1 + m->chg1 - 1]->size - t1.ptr; t2.ptr = (char *)xe2->xdf2.recs[m->i2]->ptr; t2.size = xe2->xdf2.recs[m->i2 + m->chg2 - 1]->ptr + xe2->xdf2.recs[m->i2 + m->chg2 - 1]->size - t2.ptr; if (xdl_do_diff(&t1, &t2, xpp, &xe) < 0) return -1; if (xdl_change_compact(&xe.xdf1, &xe.xdf2, xpp->flags) < 0 || xdl_change_compact(&xe.xdf2, &xe.xdf1, xpp->flags) < 0 || xdl_build_script(&xe, &xscr) < 0) { xdl_free_env(&xe); return -1; } if (!xscr) { /* If this happens, the changes are identical. */ xdl_free_env(&xe); m->mode = 4; continue; } x = xscr; m->i1 = xscr->i1 + i1; m->chg1 = xscr->chg1; m->i2 = xscr->i2 + i2; m->chg2 = xscr->chg2; while (xscr->next) { xdmerge_t *m2 = xdl_malloc(sizeof(xdmerge_t)); if (!m2) { xdl_free_env(&xe); xdl_free_script(x); return -1; } xscr = xscr->next; m2->next = m->next; m->next = m2; m = m2; m->mode = 0; m->i1 = xscr->i1 + i1; m->chg1 = xscr->chg1; m->i2 = xscr->i2 + i2; m->chg2 = xscr->chg2; } xdl_free_env(&xe); xdl_free_script(x); } return 0; } static int line_contains_alnum(const char *ptr, long size) { while (size--) if (isalnum((unsigned char)*(ptr++))) return 1; return 0; } static int lines_contain_alnum(xdfenv_t *xe, int i, int chg) { for (; chg; chg--, i++) if (line_contains_alnum(xe->xdf2.recs[i]->ptr, xe->xdf2.recs[i]->size)) return 1; return 0; } /* * This function merges m and m->next, marking everything between those hunks * as conflicting, too. */ static void xdl_merge_two_conflicts(xdmerge_t *m) { xdmerge_t *next_m = m->next; m->chg1 = next_m->i1 + next_m->chg1 - m->i1; m->chg2 = next_m->i2 + next_m->chg2 - m->i2; m->next = next_m->next; free(next_m); } /* * If there are less than 3 non-conflicting lines between conflicts, * it appears simpler -- because it takes up less (or as many) lines -- * if the lines are moved into the conflicts. */ static int xdl_simplify_non_conflicts(xdfenv_t *xe1, xdmerge_t *m, int simplify_if_no_alnum) { int result = 0; if (!m) return result; for (;;) { xdmerge_t *next_m = m->next; int begin, end; if (!next_m) return result; begin = m->i1 + m->chg1; end = next_m->i1; if (m->mode != 0 || next_m->mode != 0 || (end - begin > 3 && (!simplify_if_no_alnum || lines_contain_alnum(xe1, begin, end - begin)))) { m = next_m; } else { result++; xdl_merge_two_conflicts(m); } } } /* * level == 0: mark all overlapping changes as conflict * level == 1: mark overlapping changes as conflict only if not identical * level == 2: analyze non-identical changes for minimal conflict set * level == 3: analyze non-identical changes for minimal conflict set, but * treat hunks not containing any letter or number as conflicting * * returns < 0 on error, == 0 for no conflicts, else number of conflicts */ static int xdl_do_merge(xdfenv_t *xe1, xdchange_t *xscr1, xdfenv_t *xe2, xdchange_t *xscr2, xmparam_t const *xmp, mmbuffer_t *result) { xdmerge_t *changes, *c; xpparam_t const *xpp = &xmp->xpp; const char *const ancestor_name = xmp->ancestor; const char *const name1 = xmp->file1; const char *const name2 = xmp->file2; int i0, i1, i2, chg0, chg1, chg2; int level = xmp->level; int style = xmp->style; int favor = xmp->favor; if (style == XDL_MERGE_DIFF3) { /* * "diff3 -m" output does not make sense for anything * more aggressive than XDL_MERGE_EAGER. */ if (XDL_MERGE_EAGER < level) level = XDL_MERGE_EAGER; } c = changes = NULL; while (xscr1 && xscr2) { if (!changes) changes = c; if (xscr1->i1 + xscr1->chg1 < xscr2->i1) { i0 = xscr1->i1; i1 = xscr1->i2; i2 = xscr2->i2 - xscr2->i1 + xscr1->i1; chg0 = xscr1->chg1; chg1 = xscr1->chg2; chg2 = xscr1->chg1; if (xdl_append_merge(&c, 1, i0, chg0, i1, chg1, i2, chg2)) { xdl_cleanup_merge(changes); return -1; } xscr1 = xscr1->next; continue; } if (xscr2->i1 + xscr2->chg1 < xscr1->i1) { i0 = xscr2->i1; i1 = xscr1->i2 - xscr1->i1 + xscr2->i1; i2 = xscr2->i2; chg0 = xscr2->chg1; chg1 = xscr2->chg1; chg2 = xscr2->chg2; if (xdl_append_merge(&c, 2, i0, chg0, i1, chg1, i2, chg2)) { xdl_cleanup_merge(changes); return -1; } xscr2 = xscr2->next; continue; } if (level == XDL_MERGE_MINIMAL || xscr1->i1 != xscr2->i1 || xscr1->chg1 != xscr2->chg1 || xscr1->chg2 != xscr2->chg2 || xdl_merge_cmp_lines(xe1, xscr1->i2, xe2, xscr2->i2, xscr1->chg2, xpp->flags)) { /* conflict */ int off = xscr1->i1 - xscr2->i1; int ffo = off + xscr1->chg1 - xscr2->chg1; i0 = xscr1->i1; i1 = xscr1->i2; i2 = xscr2->i2; if (off > 0) { i0 -= off; i1 -= off; } else i2 += off; chg0 = xscr1->i1 + xscr1->chg1 - i0; chg1 = xscr1->i2 + xscr1->chg2 - i1; chg2 = xscr2->i2 + xscr2->chg2 - i2; if (ffo < 0) { chg0 -= ffo; chg1 -= ffo; } else chg2 += ffo; if (xdl_append_merge(&c, 0, i0, chg0, i1, chg1, i2, chg2)) { xdl_cleanup_merge(changes); return -1; } } i1 = xscr1->i1 + xscr1->chg1; i2 = xscr2->i1 + xscr2->chg1; if (i1 >= i2) xscr2 = xscr2->next; if (i2 >= i1) xscr1 = xscr1->next; } while (xscr1) { if (!changes) changes = c; i0 = xscr1->i1; i1 = xscr1->i2; i2 = xscr1->i1 + xe2->xdf2.nrec - xe2->xdf1.nrec; chg0 = xscr1->chg1; chg1 = xscr1->chg2; chg2 = xscr1->chg1; if (xdl_append_merge(&c, 1, i0, chg0, i1, chg1, i2, chg2)) { xdl_cleanup_merge(changes); return -1; } xscr1 = xscr1->next; } while (xscr2) { if (!changes) changes = c; i0 = xscr2->i1; i1 = xscr2->i1 + xe1->xdf2.nrec - xe1->xdf1.nrec; i2 = xscr2->i2; chg0 = xscr2->chg1; chg1 = xscr2->chg1; chg2 = xscr2->chg2; if (xdl_append_merge(&c, 2, i0, chg0, i1, chg1, i2, chg2)) { xdl_cleanup_merge(changes); return -1; } xscr2 = xscr2->next; } if (!changes) changes = c; /* refine conflicts */ if (XDL_MERGE_ZEALOUS <= level && (xdl_refine_conflicts(xe1, xe2, changes, xpp) < 0 || xdl_simplify_non_conflicts(xe1, changes, XDL_MERGE_ZEALOUS < level) < 0)) { xdl_cleanup_merge(changes); return -1; } /* output */ if (result) { int marker_size = xmp->marker_size; int size = xdl_fill_merge_buffer(xe1, name1, xe2, name2, ancestor_name, favor, changes, NULL, style, marker_size); result->ptr = xdl_malloc(size); if (!result->ptr) { xdl_cleanup_merge(changes); return -1; } result->size = size; xdl_fill_merge_buffer(xe1, name1, xe2, name2, ancestor_name, favor, changes, result->ptr, style, marker_size); } return xdl_cleanup_merge(changes); } int xdl_merge(mmfile_t *orig, mmfile_t *mf1, mmfile_t *mf2, xmparam_t const *xmp, mmbuffer_t *result) { xdchange_t *xscr1, *xscr2; xdfenv_t xe1, xe2; int status; xpparam_t const *xpp = &xmp->xpp; result->ptr = NULL; result->size = 0; if (xdl_do_diff(orig, mf1, xpp, &xe1) < 0 || xdl_do_diff(orig, mf2, xpp, &xe2) < 0) { return -1; } if (xdl_change_compact(&xe1.xdf1, &xe1.xdf2, xpp->flags) < 0 || xdl_change_compact(&xe1.xdf2, &xe1.xdf1, xpp->flags) < 0 || xdl_build_script(&xe1, &xscr1) < 0) { xdl_free_env(&xe1); return -1; } if (xdl_change_compact(&xe2.xdf1, &xe2.xdf2, xpp->flags) < 0 || xdl_change_compact(&xe2.xdf2, &xe2.xdf1, xpp->flags) < 0 || xdl_build_script(&xe2, &xscr2) < 0) { xdl_free_env(&xe2); return -1; } status = 0; if (!xscr1) { result->ptr = xdl_malloc(mf2->size); memcpy(result->ptr, mf2->ptr, mf2->size); result->size = mf2->size; } else if (!xscr2) { result->ptr = xdl_malloc(mf1->size); memcpy(result->ptr, mf1->ptr, mf1->size); result->size = mf1->size; } else { status = xdl_do_merge(&xe1, xscr1, &xe2, xscr2, xmp, result); } xdl_free_script(xscr1); xdl_free_script(xscr2); xdl_free_env(&xe1); xdl_free_env(&xe2); return status; } libgit2-0.19.0/src/xdiff/xpatience.c000066400000000000000000000235661216214232500171620ustar00rootroot00000000000000/* * LibXDiff by Davide Libenzi ( File Differential Library ) * Copyright (C) 2003-2009 Davide Libenzi, Johannes E. Schindelin * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Davide Libenzi * */ #include "xinclude.h" #include "xtypes.h" #include "xdiff.h" /* * The basic idea of patience diff is to find lines that are unique in * both files. These are intuitively the ones that we want to see as * common lines. * * The maximal ordered sequence of such line pairs (where ordered means * that the order in the sequence agrees with the order of the lines in * both files) naturally defines an initial set of common lines. * * Now, the algorithm tries to extend the set of common lines by growing * the line ranges where the files have identical lines. * * Between those common lines, the patience diff algorithm is applied * recursively, until no unique line pairs can be found; these line ranges * are handled by the well-known Myers algorithm. */ #define NON_UNIQUE ULONG_MAX /* * This is a hash mapping from line hash to line numbers in the first and * second file. */ struct hashmap { int nr, alloc; struct entry { unsigned long hash; /* * 0 = unused entry, 1 = first line, 2 = second, etc. * line2 is NON_UNIQUE if the line is not unique * in either the first or the second file. */ unsigned long line1, line2; /* * "next" & "previous" are used for the longest common * sequence; * initially, "next" reflects only the order in file1. */ struct entry *next, *previous; } *entries, *first, *last; /* were common records found? */ unsigned long has_matches; mmfile_t *file1, *file2; xdfenv_t *env; xpparam_t const *xpp; }; /* The argument "pass" is 1 for the first file, 2 for the second. */ static void insert_record(int line, struct hashmap *map, int pass) { xrecord_t **records = pass == 1 ? map->env->xdf1.recs : map->env->xdf2.recs; xrecord_t *record = records[line - 1], *other; /* * After xdl_prepare_env() (or more precisely, due to * xdl_classify_record()), the "ha" member of the records (AKA lines) * is _not_ the hash anymore, but a linearized version of it. In * other words, the "ha" member is guaranteed to start with 0 and * the second record's ha can only be 0 or 1, etc. * * So we multiply ha by 2 in the hope that the hashing was * "unique enough". */ int index = (int)((record->ha << 1) % map->alloc); while (map->entries[index].line1) { other = map->env->xdf1.recs[map->entries[index].line1 - 1]; if (map->entries[index].hash != record->ha || !xdl_recmatch(record->ptr, record->size, other->ptr, other->size, map->xpp->flags)) { if (++index >= map->alloc) index = 0; continue; } if (pass == 2) map->has_matches = 1; if (pass == 1 || map->entries[index].line2) map->entries[index].line2 = NON_UNIQUE; else map->entries[index].line2 = line; return; } if (pass == 2) return; map->entries[index].line1 = line; map->entries[index].hash = record->ha; if (!map->first) map->first = map->entries + index; if (map->last) { map->last->next = map->entries + index; map->entries[index].previous = map->last; } map->last = map->entries + index; map->nr++; } /* * This function has to be called for each recursion into the inter-hunk * parts, as previously non-unique lines can become unique when being * restricted to a smaller part of the files. * * It is assumed that env has been prepared using xdl_prepare(). */ static int fill_hashmap(mmfile_t *file1, mmfile_t *file2, xpparam_t const *xpp, xdfenv_t *env, struct hashmap *result, int line1, int count1, int line2, int count2) { result->file1 = file1; result->file2 = file2; result->xpp = xpp; result->env = env; /* We know exactly how large we want the hash map */ result->alloc = count1 * 2; result->entries = (struct entry *) xdl_malloc(result->alloc * sizeof(struct entry)); if (!result->entries) return -1; memset(result->entries, 0, result->alloc * sizeof(struct entry)); /* First, fill with entries from the first file */ while (count1--) insert_record(line1++, result, 1); /* Then search for matches in the second file */ while (count2--) insert_record(line2++, result, 2); return 0; } /* * Find the longest sequence with a smaller last element (meaning a smaller * line2, as we construct the sequence with entries ordered by line1). */ static int binary_search(struct entry **sequence, int longest, struct entry *entry) { int left = -1, right = longest; while (left + 1 < right) { int middle = (left + right) / 2; /* by construction, no two entries can be equal */ if (sequence[middle]->line2 > entry->line2) right = middle; else left = middle; } /* return the index in "sequence", _not_ the sequence length */ return left; } /* * The idea is to start with the list of common unique lines sorted by * the order in file1. For each of these pairs, the longest (partial) * sequence whose last element's line2 is smaller is determined. * * For efficiency, the sequences are kept in a list containing exactly one * item per sequence length: the sequence with the smallest last * element (in terms of line2). */ static struct entry *find_longest_common_sequence(struct hashmap *map) { struct entry **sequence = xdl_malloc(map->nr * sizeof(struct entry *)); int longest = 0, i; struct entry *entry; for (entry = map->first; entry; entry = entry->next) { if (!entry->line2 || entry->line2 == NON_UNIQUE) continue; i = binary_search(sequence, longest, entry); entry->previous = i < 0 ? NULL : sequence[i]; sequence[++i] = entry; if (i == longest) longest++; } /* No common unique lines were found */ if (!longest) { xdl_free(sequence); return NULL; } /* Iterate starting at the last element, adjusting the "next" members */ entry = sequence[longest - 1]; entry->next = NULL; while (entry->previous) { entry->previous->next = entry; entry = entry->previous; } xdl_free(sequence); return entry; } static int match(struct hashmap *map, int line1, int line2) { xrecord_t *record1 = map->env->xdf1.recs[line1 - 1]; xrecord_t *record2 = map->env->xdf2.recs[line2 - 1]; return xdl_recmatch(record1->ptr, record1->size, record2->ptr, record2->size, map->xpp->flags); } static int patience_diff(mmfile_t *file1, mmfile_t *file2, xpparam_t const *xpp, xdfenv_t *env, int line1, int count1, int line2, int count2); static int walk_common_sequence(struct hashmap *map, struct entry *first, int line1, int count1, int line2, int count2) { int end1 = line1 + count1, end2 = line2 + count2; int next1, next2; for (;;) { /* Try to grow the line ranges of common lines */ if (first) { next1 = first->line1; next2 = first->line2; while (next1 > line1 && next2 > line2 && match(map, next1 - 1, next2 - 1)) { next1--; next2--; } } else { next1 = end1; next2 = end2; } while (line1 < next1 && line2 < next2 && match(map, line1, line2)) { line1++; line2++; } /* Recurse */ if (next1 > line1 || next2 > line2) { struct hashmap submap; memset(&submap, 0, sizeof(submap)); if (patience_diff(map->file1, map->file2, map->xpp, map->env, line1, next1 - line1, line2, next2 - line2)) return -1; } if (!first) return 0; while (first->next && first->next->line1 == first->line1 + 1 && first->next->line2 == first->line2 + 1) first = first->next; line1 = first->line1 + 1; line2 = first->line2 + 1; first = first->next; } } static int fall_back_to_classic_diff(struct hashmap *map, int line1, int count1, int line2, int count2) { xpparam_t xpp; xpp.flags = map->xpp->flags & ~XDF_PATIENCE_DIFF; return xdl_fall_back_diff(map->env, &xpp, line1, count1, line2, count2); } /* * Recursively find the longest common sequence of unique lines, * and if none was found, ask xdl_do_diff() to do the job. * * This function assumes that env was prepared with xdl_prepare_env(). */ static int patience_diff(mmfile_t *file1, mmfile_t *file2, xpparam_t const *xpp, xdfenv_t *env, int line1, int count1, int line2, int count2) { struct hashmap map; struct entry *first; int result = 0; /* trivial case: one side is empty */ if (!count1) { while(count2--) env->xdf2.rchg[line2++ - 1] = 1; return 0; } else if (!count2) { while(count1--) env->xdf1.rchg[line1++ - 1] = 1; return 0; } memset(&map, 0, sizeof(map)); if (fill_hashmap(file1, file2, xpp, env, &map, line1, count1, line2, count2)) return -1; /* are there any matching lines at all? */ if (!map.has_matches) { while(count1--) env->xdf1.rchg[line1++ - 1] = 1; while(count2--) env->xdf2.rchg[line2++ - 1] = 1; xdl_free(map.entries); return 0; } first = find_longest_common_sequence(&map); if (first) result = walk_common_sequence(&map, first, line1, count1, line2, count2); else result = fall_back_to_classic_diff(&map, line1, count1, line2, count2); xdl_free(map.entries); return result; } int xdl_do_patience_diff(mmfile_t *file1, mmfile_t *file2, xpparam_t const *xpp, xdfenv_t *env) { if (xdl_prepare_env(file1, file2, xpp, env) < 0) return -1; /* environment is cleaned up in xdl_diff() */ return patience_diff(file1, file2, xpp, env, 1, env->xdf1.nrec, 1, env->xdf2.nrec); } libgit2-0.19.0/src/xdiff/xprepare.c000066400000000000000000000276151216214232500170270ustar00rootroot00000000000000/* * LibXDiff by Davide Libenzi ( File Differential Library ) * Copyright (C) 2003 Davide Libenzi * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Davide Libenzi * */ #include "xinclude.h" #define XDL_KPDIS_RUN 4 #define XDL_MAX_EQLIMIT 1024 #define XDL_SIMSCAN_WINDOW 100 #define XDL_GUESS_NLINES1 256 #define XDL_GUESS_NLINES2 20 typedef struct s_xdlclass { struct s_xdlclass *next; unsigned long ha; char const *line; long size; long idx; long len1, len2; } xdlclass_t; typedef struct s_xdlclassifier { unsigned int hbits; long hsize; xdlclass_t **rchash; chastore_t ncha; xdlclass_t **rcrecs; long alloc; long count; long flags; } xdlclassifier_t; static int xdl_init_classifier(xdlclassifier_t *cf, long size, long flags); static void xdl_free_classifier(xdlclassifier_t *cf); static int xdl_classify_record(unsigned int pass, xdlclassifier_t *cf, xrecord_t **rhash, unsigned int hbits, xrecord_t *rec); static int xdl_prepare_ctx(unsigned int pass, mmfile_t *mf, long narec, xpparam_t const *xpp, xdlclassifier_t *cf, xdfile_t *xdf); static void xdl_free_ctx(xdfile_t *xdf); static int xdl_clean_mmatch(char const *dis, long i, long s, long e); static int xdl_cleanup_records(xdlclassifier_t *cf, xdfile_t *xdf1, xdfile_t *xdf2); static int xdl_trim_ends(xdfile_t *xdf1, xdfile_t *xdf2); static int xdl_optimize_ctxs(xdlclassifier_t *cf, xdfile_t *xdf1, xdfile_t *xdf2); static int xdl_init_classifier(xdlclassifier_t *cf, long size, long flags) { cf->flags = flags; cf->hbits = xdl_hashbits((unsigned int) size); cf->hsize = 1 << cf->hbits; if (xdl_cha_init(&cf->ncha, sizeof(xdlclass_t), size / 4 + 1) < 0) { return -1; } if (!(cf->rchash = (xdlclass_t **) xdl_malloc(cf->hsize * sizeof(xdlclass_t *)))) { xdl_cha_free(&cf->ncha); return -1; } memset(cf->rchash, 0, cf->hsize * sizeof(xdlclass_t *)); cf->alloc = size; if (!(cf->rcrecs = (xdlclass_t **) xdl_malloc(cf->alloc * sizeof(xdlclass_t *)))) { xdl_free(cf->rchash); xdl_cha_free(&cf->ncha); return -1; } cf->count = 0; return 0; } static void xdl_free_classifier(xdlclassifier_t *cf) { xdl_free(cf->rcrecs); xdl_free(cf->rchash); xdl_cha_free(&cf->ncha); } static int xdl_classify_record(unsigned int pass, xdlclassifier_t *cf, xrecord_t **rhash, unsigned int hbits, xrecord_t *rec) { long hi; char const *line; xdlclass_t *rcrec; xdlclass_t **rcrecs; line = rec->ptr; hi = (long) XDL_HASHLONG(rec->ha, cf->hbits); for (rcrec = cf->rchash[hi]; rcrec; rcrec = rcrec->next) if (rcrec->ha == rec->ha && xdl_recmatch(rcrec->line, rcrec->size, rec->ptr, rec->size, cf->flags)) break; if (!rcrec) { if (!(rcrec = xdl_cha_alloc(&cf->ncha))) { return -1; } rcrec->idx = cf->count++; if (cf->count > cf->alloc) { cf->alloc *= 2; if (!(rcrecs = (xdlclass_t **) xdl_realloc(cf->rcrecs, cf->alloc * sizeof(xdlclass_t *)))) { return -1; } cf->rcrecs = rcrecs; } cf->rcrecs[rcrec->idx] = rcrec; rcrec->line = line; rcrec->size = rec->size; rcrec->ha = rec->ha; rcrec->len1 = rcrec->len2 = 0; rcrec->next = cf->rchash[hi]; cf->rchash[hi] = rcrec; } (pass == 1) ? rcrec->len1++ : rcrec->len2++; rec->ha = (unsigned long) rcrec->idx; hi = (long) XDL_HASHLONG(rec->ha, hbits); rec->next = rhash[hi]; rhash[hi] = rec; return 0; } static int xdl_prepare_ctx(unsigned int pass, mmfile_t *mf, long narec, xpparam_t const *xpp, xdlclassifier_t *cf, xdfile_t *xdf) { unsigned int hbits; long nrec, hsize, bsize; unsigned long hav; char const *blk, *cur, *top, *prev; xrecord_t *crec; xrecord_t **recs, **rrecs; xrecord_t **rhash; unsigned long *ha; char *rchg; long *rindex; ha = NULL; rindex = NULL; rchg = NULL; rhash = NULL; recs = NULL; if (xdl_cha_init(&xdf->rcha, sizeof(xrecord_t), narec / 4 + 1) < 0) goto abort; if (!(recs = (xrecord_t **) xdl_malloc(narec * sizeof(xrecord_t *)))) goto abort; if (xpp->flags & XDF_HISTOGRAM_DIFF) hbits = hsize = 0; else { hbits = xdl_hashbits((unsigned int) narec); hsize = 1 << hbits; if (!(rhash = (xrecord_t **) xdl_malloc(hsize * sizeof(xrecord_t *)))) goto abort; memset(rhash, 0, hsize * sizeof(xrecord_t *)); } nrec = 0; if ((cur = blk = xdl_mmfile_first(mf, &bsize)) != NULL) { for (top = blk + bsize; cur < top; ) { prev = cur; hav = xdl_hash_record(&cur, top, xpp->flags); if (nrec >= narec) { narec *= 2; if (!(rrecs = (xrecord_t **) xdl_realloc(recs, narec * sizeof(xrecord_t *)))) goto abort; recs = rrecs; } if (!(crec = xdl_cha_alloc(&xdf->rcha))) goto abort; crec->ptr = prev; crec->size = (long) (cur - prev); crec->ha = hav; recs[nrec++] = crec; if (!(xpp->flags & XDF_HISTOGRAM_DIFF) && xdl_classify_record(pass, cf, rhash, hbits, crec) < 0) goto abort; } } if (!(rchg = (char *) xdl_malloc((nrec + 2) * sizeof(char)))) goto abort; memset(rchg, 0, (nrec + 2) * sizeof(char)); if (!(rindex = (long *) xdl_malloc((nrec + 1) * sizeof(long)))) goto abort; if (!(ha = (unsigned long *) xdl_malloc((nrec + 1) * sizeof(unsigned long)))) goto abort; xdf->nrec = nrec; xdf->recs = recs; xdf->hbits = hbits; xdf->rhash = rhash; xdf->rchg = rchg + 1; xdf->rindex = rindex; xdf->nreff = 0; xdf->ha = ha; xdf->dstart = 0; xdf->dend = nrec - 1; return 0; abort: xdl_free(ha); xdl_free(rindex); xdl_free(rchg); xdl_free(rhash); xdl_free(recs); xdl_cha_free(&xdf->rcha); return -1; } static void xdl_free_ctx(xdfile_t *xdf) { xdl_free(xdf->rhash); xdl_free(xdf->rindex); xdl_free(xdf->rchg - 1); xdl_free(xdf->ha); xdl_free(xdf->recs); xdl_cha_free(&xdf->rcha); } int xdl_prepare_env(mmfile_t *mf1, mmfile_t *mf2, xpparam_t const *xpp, xdfenv_t *xe) { long enl1, enl2, sample; xdlclassifier_t cf; memset(&cf, 0, sizeof(cf)); /* * For histogram diff, we can afford a smaller sample size and * thus a poorer estimate of the number of lines, as the hash * table (rhash) won't be filled up/grown. The number of lines * (nrecs) will be updated correctly anyway by * xdl_prepare_ctx(). */ sample = xpp->flags & XDF_HISTOGRAM_DIFF ? XDL_GUESS_NLINES2 : XDL_GUESS_NLINES1; enl1 = xdl_guess_lines(mf1, sample) + 1; enl2 = xdl_guess_lines(mf2, sample) + 1; if (!(xpp->flags & XDF_HISTOGRAM_DIFF) && xdl_init_classifier(&cf, enl1 + enl2 + 1, xpp->flags) < 0) { return -1; } if (xdl_prepare_ctx(1, mf1, enl1, xpp, &cf, &xe->xdf1) < 0) { xdl_free_classifier(&cf); return -1; } if (xdl_prepare_ctx(2, mf2, enl2, xpp, &cf, &xe->xdf2) < 0) { xdl_free_ctx(&xe->xdf1); xdl_free_classifier(&cf); return -1; } if (!(xpp->flags & XDF_PATIENCE_DIFF) && !(xpp->flags & XDF_HISTOGRAM_DIFF) && xdl_optimize_ctxs(&cf, &xe->xdf1, &xe->xdf2) < 0) { xdl_free_ctx(&xe->xdf2); xdl_free_ctx(&xe->xdf1); return -1; } if (!(xpp->flags & XDF_HISTOGRAM_DIFF)) xdl_free_classifier(&cf); return 0; } void xdl_free_env(xdfenv_t *xe) { xdl_free_ctx(&xe->xdf2); xdl_free_ctx(&xe->xdf1); } static int xdl_clean_mmatch(char const *dis, long i, long s, long e) { long r, rdis0, rpdis0, rdis1, rpdis1; /* * Limits the window the is examined during the similar-lines * scan. The loops below stops when dis[i - r] == 1 (line that * has no match), but there are corner cases where the loop * proceed all the way to the extremities by causing huge * performance penalties in case of big files. */ if (i - s > XDL_SIMSCAN_WINDOW) s = i - XDL_SIMSCAN_WINDOW; if (e - i > XDL_SIMSCAN_WINDOW) e = i + XDL_SIMSCAN_WINDOW; /* * Scans the lines before 'i' to find a run of lines that either * have no match (dis[j] == 0) or have multiple matches (dis[j] > 1). * Note that we always call this function with dis[i] > 1, so the * current line (i) is already a multimatch line. */ for (r = 1, rdis0 = 0, rpdis0 = 1; (i - r) >= s; r++) { if (!dis[i - r]) rdis0++; else if (dis[i - r] == 2) rpdis0++; else break; } /* * If the run before the line 'i' found only multimatch lines, we * return 0 and hence we don't make the current line (i) discarded. * We want to discard multimatch lines only when they appear in the * middle of runs with nomatch lines (dis[j] == 0). */ if (rdis0 == 0) return 0; for (r = 1, rdis1 = 0, rpdis1 = 1; (i + r) <= e; r++) { if (!dis[i + r]) rdis1++; else if (dis[i + r] == 2) rpdis1++; else break; } /* * If the run after the line 'i' found only multimatch lines, we * return 0 and hence we don't make the current line (i) discarded. */ if (rdis1 == 0) return 0; rdis1 += rdis0; rpdis1 += rpdis0; return rpdis1 * XDL_KPDIS_RUN < (rpdis1 + rdis1); } /* * Try to reduce the problem complexity, discard records that have no * matches on the other file. Also, lines that have multiple matches * might be potentially discarded if they happear in a run of discardable. */ static int xdl_cleanup_records(xdlclassifier_t *cf, xdfile_t *xdf1, xdfile_t *xdf2) { long i, nm, nreff, mlim; xrecord_t **recs; xdlclass_t *rcrec; char *dis, *dis1, *dis2; if (!(dis = (char *) xdl_malloc(xdf1->nrec + xdf2->nrec + 2))) { return -1; } memset(dis, 0, xdf1->nrec + xdf2->nrec + 2); dis1 = dis; dis2 = dis1 + xdf1->nrec + 1; if ((mlim = xdl_bogosqrt(xdf1->nrec)) > XDL_MAX_EQLIMIT) mlim = XDL_MAX_EQLIMIT; for (i = xdf1->dstart, recs = &xdf1->recs[xdf1->dstart]; i <= xdf1->dend; i++, recs++) { rcrec = cf->rcrecs[(*recs)->ha]; nm = rcrec ? rcrec->len2 : 0; dis1[i] = (nm == 0) ? 0: (nm >= mlim) ? 2: 1; } if ((mlim = xdl_bogosqrt(xdf2->nrec)) > XDL_MAX_EQLIMIT) mlim = XDL_MAX_EQLIMIT; for (i = xdf2->dstart, recs = &xdf2->recs[xdf2->dstart]; i <= xdf2->dend; i++, recs++) { rcrec = cf->rcrecs[(*recs)->ha]; nm = rcrec ? rcrec->len1 : 0; dis2[i] = (nm == 0) ? 0: (nm >= mlim) ? 2: 1; } for (nreff = 0, i = xdf1->dstart, recs = &xdf1->recs[xdf1->dstart]; i <= xdf1->dend; i++, recs++) { if (dis1[i] == 1 || (dis1[i] == 2 && !xdl_clean_mmatch(dis1, i, xdf1->dstart, xdf1->dend))) { xdf1->rindex[nreff] = i; xdf1->ha[nreff] = (*recs)->ha; nreff++; } else xdf1->rchg[i] = 1; } xdf1->nreff = nreff; for (nreff = 0, i = xdf2->dstart, recs = &xdf2->recs[xdf2->dstart]; i <= xdf2->dend; i++, recs++) { if (dis2[i] == 1 || (dis2[i] == 2 && !xdl_clean_mmatch(dis2, i, xdf2->dstart, xdf2->dend))) { xdf2->rindex[nreff] = i; xdf2->ha[nreff] = (*recs)->ha; nreff++; } else xdf2->rchg[i] = 1; } xdf2->nreff = nreff; xdl_free(dis); return 0; } /* * Early trim initial and terminal matching records. */ static int xdl_trim_ends(xdfile_t *xdf1, xdfile_t *xdf2) { long i, lim; xrecord_t **recs1, **recs2; recs1 = xdf1->recs; recs2 = xdf2->recs; for (i = 0, lim = XDL_MIN(xdf1->nrec, xdf2->nrec); i < lim; i++, recs1++, recs2++) if ((*recs1)->ha != (*recs2)->ha) break; xdf1->dstart = xdf2->dstart = i; recs1 = xdf1->recs + xdf1->nrec - 1; recs2 = xdf2->recs + xdf2->nrec - 1; for (lim -= i, i = 0; i < lim; i++, recs1--, recs2--) if ((*recs1)->ha != (*recs2)->ha) break; xdf1->dend = xdf1->nrec - i - 1; xdf2->dend = xdf2->nrec - i - 1; return 0; } static int xdl_optimize_ctxs(xdlclassifier_t *cf, xdfile_t *xdf1, xdfile_t *xdf2) { if (xdl_trim_ends(xdf1, xdf2) < 0 || xdl_cleanup_records(cf, xdf1, xdf2) < 0) { return -1; } return 0; } libgit2-0.19.0/src/xdiff/xprepare.h000066400000000000000000000021431216214232500170210ustar00rootroot00000000000000/* * LibXDiff by Davide Libenzi ( File Differential Library ) * Copyright (C) 2003 Davide Libenzi * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Davide Libenzi * */ #if !defined(XPREPARE_H) #define XPREPARE_H int xdl_prepare_env(mmfile_t *mf1, mmfile_t *mf2, xpparam_t const *xpp, xdfenv_t *xe); void xdl_free_env(xdfenv_t *xe); #endif /* #if !defined(XPREPARE_H) */ libgit2-0.19.0/src/xdiff/xtypes.h000066400000000000000000000030721216214232500165310ustar00rootroot00000000000000/* * LibXDiff by Davide Libenzi ( File Differential Library ) * Copyright (C) 2003 Davide Libenzi * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Davide Libenzi * */ #if !defined(XTYPES_H) #define XTYPES_H typedef struct s_chanode { struct s_chanode *next; long icurr; } chanode_t; typedef struct s_chastore { chanode_t *head, *tail; long isize, nsize; chanode_t *ancur; chanode_t *sncur; long scurr; } chastore_t; typedef struct s_xrecord { struct s_xrecord *next; char const *ptr; long size; unsigned long ha; } xrecord_t; typedef struct s_xdfile { chastore_t rcha; long nrec; unsigned int hbits; xrecord_t **rhash; long dstart, dend; xrecord_t **recs; char *rchg; long *rindex; long nreff; unsigned long *ha; } xdfile_t; typedef struct s_xdfenv { xdfile_t xdf1, xdf2; } xdfenv_t; #endif /* #if !defined(XTYPES_H) */ libgit2-0.19.0/src/xdiff/xutils.c000066400000000000000000000217631216214232500165270ustar00rootroot00000000000000/* * LibXDiff by Davide Libenzi ( File Differential Library ) * Copyright (C) 2003 Davide Libenzi * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Davide Libenzi * */ #include "xinclude.h" long xdl_bogosqrt(long n) { long i; /* * Classical integer square root approximation using shifts. */ for (i = 1; n > 0; n >>= 2) i <<= 1; return i; } int xdl_emit_diffrec(char const *rec, long size, char const *pre, long psize, xdemitcb_t *ecb) { int i = 2; mmbuffer_t mb[3]; mb[0].ptr = (char *) pre; mb[0].size = psize; mb[1].ptr = (char *) rec; mb[1].size = size; if (size > 0 && rec[size - 1] != '\n') { mb[2].ptr = (char *) "\n\\ No newline at end of file\n"; mb[2].size = strlen(mb[2].ptr); i++; } if (ecb->outf(ecb->priv, mb, i) < 0) { return -1; } return 0; } void *xdl_mmfile_first(mmfile_t *mmf, long *size) { *size = (long)mmf->size; return mmf->ptr; } long xdl_mmfile_size(mmfile_t *mmf) { return (long)mmf->size; } int xdl_cha_init(chastore_t *cha, long isize, long icount) { cha->head = cha->tail = NULL; cha->isize = isize; cha->nsize = icount * isize; cha->ancur = cha->sncur = NULL; cha->scurr = 0; return 0; } void xdl_cha_free(chastore_t *cha) { chanode_t *cur, *tmp; for (cur = cha->head; (tmp = cur) != NULL;) { cur = cur->next; xdl_free(tmp); } } void *xdl_cha_alloc(chastore_t *cha) { chanode_t *ancur; void *data; if (!(ancur = cha->ancur) || ancur->icurr == cha->nsize) { if (!(ancur = (chanode_t *) xdl_malloc(sizeof(chanode_t) + cha->nsize))) { return NULL; } ancur->icurr = 0; ancur->next = NULL; if (cha->tail) cha->tail->next = ancur; if (!cha->head) cha->head = ancur; cha->tail = ancur; cha->ancur = ancur; } data = (char *) ancur + sizeof(chanode_t) + ancur->icurr; ancur->icurr += cha->isize; return data; } void *xdl_cha_first(chastore_t *cha) { chanode_t *sncur; if (!(cha->sncur = sncur = cha->head)) return NULL; cha->scurr = 0; return (char *) sncur + sizeof(chanode_t) + cha->scurr; } void *xdl_cha_next(chastore_t *cha) { chanode_t *sncur; if (!(sncur = cha->sncur)) return NULL; cha->scurr += cha->isize; if (cha->scurr == sncur->icurr) { if (!(sncur = cha->sncur = sncur->next)) return NULL; cha->scurr = 0; } return (char *) sncur + sizeof(chanode_t) + cha->scurr; } long xdl_guess_lines(mmfile_t *mf, long sample) { long nl = 0, size, tsize = 0; char const *data, *cur, *top; if ((cur = data = xdl_mmfile_first(mf, &size)) != NULL) { for (top = data + size; nl < sample && cur < top; ) { nl++; if (!(cur = memchr(cur, '\n', top - cur))) cur = top; else cur++; } tsize += (long) (cur - data); } if (nl && tsize) nl = xdl_mmfile_size(mf) / (tsize / nl); return nl + 1; } int xdl_recmatch(const char *l1, long s1, const char *l2, long s2, long flags) { int i1, i2; if (s1 == s2 && !memcmp(l1, l2, s1)) return 1; if (!(flags & XDF_WHITESPACE_FLAGS)) return 0; i1 = 0; i2 = 0; /* * -w matches everything that matches with -b, and -b in turn * matches everything that matches with --ignore-space-at-eol. * * Each flavor of ignoring needs different logic to skip whitespaces * while we have both sides to compare. */ if (flags & XDF_IGNORE_WHITESPACE) { goto skip_ws; while (i1 < s1 && i2 < s2) { if (l1[i1++] != l2[i2++]) return 0; skip_ws: while (i1 < s1 && XDL_ISSPACE(l1[i1])) i1++; while (i2 < s2 && XDL_ISSPACE(l2[i2])) i2++; } } else if (flags & XDF_IGNORE_WHITESPACE_CHANGE) { while (i1 < s1 && i2 < s2) { if (XDL_ISSPACE(l1[i1]) && XDL_ISSPACE(l2[i2])) { /* Skip matching spaces and try again */ while (i1 < s1 && XDL_ISSPACE(l1[i1])) i1++; while (i2 < s2 && XDL_ISSPACE(l2[i2])) i2++; continue; } if (l1[i1++] != l2[i2++]) return 0; } } else if (flags & XDF_IGNORE_WHITESPACE_AT_EOL) { while (i1 < s1 && i2 < s2 && l1[i1++] == l2[i2++]) ; /* keep going */ } /* * After running out of one side, the remaining side must have * nothing but whitespace for the lines to match. Note that * ignore-whitespace-at-eol case may break out of the loop * while there still are characters remaining on both lines. */ if (i1 < s1) { while (i1 < s1 && XDL_ISSPACE(l1[i1])) i1++; if (s1 != i1) return 0; } if (i2 < s2) { while (i2 < s2 && XDL_ISSPACE(l2[i2])) i2++; return (s2 == i2); } return 1; } static unsigned long xdl_hash_record_with_whitespace(char const **data, char const *top, long flags) { unsigned long ha = 5381; char const *ptr = *data; for (; ptr < top && *ptr != '\n'; ptr++) { if (XDL_ISSPACE(*ptr)) { const char *ptr2 = ptr; int at_eol; while (ptr + 1 < top && XDL_ISSPACE(ptr[1]) && ptr[1] != '\n') ptr++; at_eol = (top <= ptr + 1 || ptr[1] == '\n'); if (flags & XDF_IGNORE_WHITESPACE) ; /* already handled */ else if (flags & XDF_IGNORE_WHITESPACE_CHANGE && !at_eol) { ha += (ha << 5); ha ^= (unsigned long) ' '; } else if (flags & XDF_IGNORE_WHITESPACE_AT_EOL && !at_eol) { while (ptr2 != ptr + 1) { ha += (ha << 5); ha ^= (unsigned long) *ptr2; ptr2++; } } continue; } ha += (ha << 5); ha ^= (unsigned long) *ptr; } *data = ptr < top ? ptr + 1: ptr; return ha; } unsigned long xdl_hash_record(char const **data, char const *top, long flags) { unsigned long ha = 5381; char const *ptr = *data; if (flags & XDF_WHITESPACE_FLAGS) return xdl_hash_record_with_whitespace(data, top, flags); for (; ptr < top && *ptr != '\n'; ptr++) { ha += (ha << 5); ha ^= (unsigned long) *ptr; } *data = ptr < top ? ptr + 1: ptr; return ha; } unsigned int xdl_hashbits(unsigned int size) { unsigned int val = 1, bits = 0; for (; val < size && bits < CHAR_BIT * sizeof(unsigned int); val <<= 1, bits++); return bits ? bits: 1; } int xdl_num_out(char *out, long val) { char *ptr, *str = out; char buf[32]; ptr = buf + sizeof(buf) - 1; *ptr = '\0'; if (val < 0) { *--ptr = '-'; val = -val; } for (; val && ptr > buf; val /= 10) *--ptr = "0123456789"[val % 10]; if (*ptr) for (; *ptr; ptr++, str++) *str = *ptr; else *str++ = '0'; *str = '\0'; return (int)(str - out); } long xdl_atol(char const *str, char const **next) { long val, base; char const *top; for (top = str; XDL_ISDIGIT(*top); top++); if (next) *next = top; for (val = 0, base = 1, top--; top >= str; top--, base *= 10) val += base * (long)(*top - '0'); return val; } int xdl_emit_hunk_hdr(long s1, long c1, long s2, long c2, const char *func, long funclen, xdemitcb_t *ecb) { int nb = 0; mmbuffer_t mb; char buf[128]; memcpy(buf, "@@ -", 4); nb += 4; nb += xdl_num_out(buf + nb, c1 ? s1: s1 - 1); if (c1 != 1) { memcpy(buf + nb, ",", 1); nb += 1; nb += xdl_num_out(buf + nb, c1); } memcpy(buf + nb, " +", 2); nb += 2; nb += xdl_num_out(buf + nb, c2 ? s2: s2 - 1); if (c2 != 1) { memcpy(buf + nb, ",", 1); nb += 1; nb += xdl_num_out(buf + nb, c2); } memcpy(buf + nb, " @@", 3); nb += 3; if (func && funclen) { buf[nb++] = ' '; if (funclen > (long)sizeof(buf) - nb - 1) funclen = (long)sizeof(buf) - nb - 1; memcpy(buf + nb, func, funclen); nb += funclen; } buf[nb++] = '\n'; mb.ptr = buf; mb.size = nb; if (ecb->outf(ecb->priv, &mb, 1) < 0) return -1; return 0; } int xdl_fall_back_diff(xdfenv_t *diff_env, xpparam_t const *xpp, int line1, int count1, int line2, int count2) { /* * This probably does not work outside Git, since * we have a very simple mmfile structure. * * Note: ideally, we would reuse the prepared environment, but * the libxdiff interface does not (yet) allow for diffing only * ranges of lines instead of the whole files. */ mmfile_t subfile1, subfile2; xdfenv_t env; subfile1.ptr = (char *)diff_env->xdf1.recs[line1 - 1]->ptr; subfile1.size = diff_env->xdf1.recs[line1 + count1 - 2]->ptr + diff_env->xdf1.recs[line1 + count1 - 2]->size - subfile1.ptr; subfile2.ptr = (char *)diff_env->xdf2.recs[line2 - 1]->ptr; subfile2.size = diff_env->xdf2.recs[line2 + count2 - 2]->ptr + diff_env->xdf2.recs[line2 + count2 - 2]->size - subfile2.ptr; if (xdl_do_diff(&subfile1, &subfile2, xpp, &env) < 0) return -1; memcpy(diff_env->xdf1.rchg + line1 - 1, env.xdf1.rchg, count1); memcpy(diff_env->xdf2.rchg + line2 - 1, env.xdf2.rchg, count2); xdl_free_env(&env); return 0; } libgit2-0.19.0/src/xdiff/xutils.h000066400000000000000000000035661216214232500165350ustar00rootroot00000000000000/* * LibXDiff by Davide Libenzi ( File Differential Library ) * Copyright (C) 2003 Davide Libenzi * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Davide Libenzi * */ #if !defined(XUTILS_H) #define XUTILS_H long xdl_bogosqrt(long n); int xdl_emit_diffrec(char const *rec, long size, char const *pre, long psize, xdemitcb_t *ecb); int xdl_cha_init(chastore_t *cha, long isize, long icount); void xdl_cha_free(chastore_t *cha); void *xdl_cha_alloc(chastore_t *cha); void *xdl_cha_first(chastore_t *cha); void *xdl_cha_next(chastore_t *cha); long xdl_guess_lines(mmfile_t *mf, long sample); int xdl_recmatch(const char *l1, long s1, const char *l2, long s2, long flags); unsigned long xdl_hash_record(char const **data, char const *top, long flags); unsigned int xdl_hashbits(unsigned int size); int xdl_num_out(char *out, long val); long xdl_atol(char const *str, char const **next); int xdl_emit_hunk_hdr(long s1, long c1, long s2, long c2, const char *func, long funclen, xdemitcb_t *ecb); int xdl_fall_back_diff(xdfenv_t *diff_env, xpparam_t const *xpp, int line1, int count1, int line2, int count2); #endif /* #if !defined(XUTILS_H) */ libgit2-0.19.0/tests-clar/000077500000000000000000000000001216214232500152145ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/README.md000066400000000000000000000006741216214232500165020ustar00rootroot00000000000000Writing Clar tests for libgit2 ============================== For information on the Clar testing framework and a detailed introduction please visit: https://github.com/vmg/clar * Write your modules and tests. Use good, meaningful names. * Make sure you actually build the tests by setting: cmake -DBUILD_CLAR=ON build/ * Test: ./build/libgit2_clar * Make sure everything is fine. * Send your pull request. That's it. libgit2-0.19.0/tests-clar/attr/000077500000000000000000000000001216214232500161665ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/attr/attr_expect.h000066400000000000000000000013541216214232500206640ustar00rootroot00000000000000#ifndef __CLAR_TEST_ATTR_EXPECT__ #define __CLAR_TEST_ATTR_EXPECT__ enum attr_expect_t { EXPECT_FALSE, EXPECT_TRUE, EXPECT_UNDEFINED, EXPECT_STRING }; struct attr_expected { const char *path; const char *attr; enum attr_expect_t expected; const char *expected_str; }; GIT_INLINE(void) attr_check_expected( enum attr_expect_t expected, const char *expected_str, const char *name, const char *value) { switch (expected) { case EXPECT_TRUE: cl_assert_(GIT_ATTR_TRUE(value), name); break; case EXPECT_FALSE: cl_assert_(GIT_ATTR_FALSE(value), name); break; case EXPECT_UNDEFINED: cl_assert_(GIT_ATTR_UNSPECIFIED(value), name); break; case EXPECT_STRING: cl_assert_equal_s(expected_str, value); break; } } #endif libgit2-0.19.0/tests-clar/attr/file.c000066400000000000000000000170471216214232500172620ustar00rootroot00000000000000#include "clar_libgit2.h" #include "attr_file.h" #include "attr_expect.h" #define get_rule(X) ((git_attr_rule *)git_vector_get(&file->rules,(X))) #define get_assign(R,Y) ((git_attr_assignment *)git_vector_get(&(R)->assigns,(Y))) void test_attr_file__simple_read(void) { git_attr_file *file; git_attr_assignment *assign; git_attr_rule *rule; cl_git_pass(git_attr_file__new_and_load(&file, cl_fixture("attr/attr0"))); cl_assert_equal_s(cl_fixture("attr/attr0"), file->key + 2); cl_assert(file->rules.length == 1); rule = get_rule(0); cl_assert(rule != NULL); cl_assert_equal_s("*", rule->match.pattern); cl_assert(rule->match.length == 1); cl_assert((rule->match.flags & GIT_ATTR_FNMATCH_HASWILD) != 0); cl_assert(rule->assigns.length == 1); assign = get_assign(rule, 0); cl_assert(assign != NULL); cl_assert_equal_s("binary", assign->name); cl_assert(GIT_ATTR_TRUE(assign->value)); git_attr_file__free(file); } void test_attr_file__match_variants(void) { git_attr_file *file; git_attr_rule *rule; git_attr_assignment *assign; cl_git_pass(git_attr_file__new_and_load(&file, cl_fixture("attr/attr1"))); cl_assert_equal_s(cl_fixture("attr/attr1"), file->key + 2); cl_assert(file->rules.length == 10); /* let's do a thorough check of this rule, then just verify * the things that are unique for the later rules */ rule = get_rule(0); cl_assert(rule); cl_assert_equal_s("pat0", rule->match.pattern); cl_assert(rule->match.length == strlen("pat0")); cl_assert(rule->match.flags == 0); cl_assert(rule->assigns.length == 1); assign = get_assign(rule,0); cl_assert_equal_s("attr0", assign->name); cl_assert(assign->name_hash == git_attr_file__name_hash(assign->name)); cl_assert(GIT_ATTR_TRUE(assign->value)); rule = get_rule(1); cl_assert_equal_s("pat1", rule->match.pattern); cl_assert(rule->match.length == strlen("pat1")); cl_assert(rule->match.flags == GIT_ATTR_FNMATCH_NEGATIVE); rule = get_rule(2); cl_assert_equal_s("pat2", rule->match.pattern); cl_assert(rule->match.length == strlen("pat2")); cl_assert(rule->match.flags == GIT_ATTR_FNMATCH_DIRECTORY); rule = get_rule(3); cl_assert_equal_s("pat3dir/pat3file", rule->match.pattern); cl_assert(rule->match.flags == GIT_ATTR_FNMATCH_FULLPATH); rule = get_rule(4); cl_assert_equal_s("pat4.*", rule->match.pattern); cl_assert((rule->match.flags & GIT_ATTR_FNMATCH_HASWILD) != 0); rule = get_rule(5); cl_assert_equal_s("*.pat5", rule->match.pattern); cl_assert((rule->match.flags & GIT_ATTR_FNMATCH_HASWILD) != 0); rule = get_rule(7); cl_assert_equal_s("pat7[a-e]??[xyz]", rule->match.pattern); cl_assert(rule->assigns.length == 1); cl_assert((rule->match.flags & GIT_ATTR_FNMATCH_HASWILD) != 0); assign = get_assign(rule,0); cl_assert_equal_s("attr7", assign->name); cl_assert(GIT_ATTR_TRUE(assign->value)); rule = get_rule(8); cl_assert_equal_s("pat8 with spaces", rule->match.pattern); cl_assert(rule->match.length == strlen("pat8 with spaces")); cl_assert(rule->match.flags == 0); rule = get_rule(9); cl_assert_equal_s("pat9", rule->match.pattern); git_attr_file__free(file); } static void check_one_assign( git_attr_file *file, int rule_idx, int assign_idx, const char *pattern, const char *name, enum attr_expect_t expected, const char *expected_str) { git_attr_rule *rule = get_rule(rule_idx); git_attr_assignment *assign = get_assign(rule, assign_idx); cl_assert_equal_s(pattern, rule->match.pattern); cl_assert(rule->assigns.length == 1); cl_assert_equal_s(name, assign->name); cl_assert(assign->name_hash == git_attr_file__name_hash(assign->name)); attr_check_expected(expected, expected_str, assign->name, assign->value); } void test_attr_file__assign_variants(void) { git_attr_file *file; git_attr_rule *rule; git_attr_assignment *assign; cl_git_pass(git_attr_file__new_and_load(&file, cl_fixture("attr/attr2"))); cl_assert_equal_s(cl_fixture("attr/attr2"), file->key + 2); cl_assert(file->rules.length == 11); check_one_assign(file, 0, 0, "pat0", "simple", EXPECT_TRUE, NULL); check_one_assign(file, 1, 0, "pat1", "neg", EXPECT_FALSE, NULL); check_one_assign(file, 2, 0, "*", "notundef", EXPECT_TRUE, NULL); check_one_assign(file, 3, 0, "pat2", "notundef", EXPECT_UNDEFINED, NULL); check_one_assign(file, 4, 0, "pat3", "assigned", EXPECT_STRING, "test-value"); check_one_assign(file, 5, 0, "pat4", "rule-with-more-chars", EXPECT_STRING, "value-with-more-chars"); check_one_assign(file, 6, 0, "pat5", "empty", EXPECT_TRUE, NULL); check_one_assign(file, 7, 0, "pat6", "negempty", EXPECT_FALSE, NULL); rule = get_rule(8); cl_assert_equal_s("pat7", rule->match.pattern); cl_assert(rule->assigns.length == 5); /* assignments will be sorted by hash value, so we have to do * lookups by search instead of by position */ assign = git_attr_rule__lookup_assignment(rule, "multiple"); cl_assert(assign); cl_assert_equal_s("multiple", assign->name); cl_assert(GIT_ATTR_TRUE(assign->value)); assign = git_attr_rule__lookup_assignment(rule, "single"); cl_assert(assign); cl_assert_equal_s("single", assign->name); cl_assert(GIT_ATTR_FALSE(assign->value)); assign = git_attr_rule__lookup_assignment(rule, "values"); cl_assert(assign); cl_assert_equal_s("values", assign->name); cl_assert_equal_s("1", assign->value); assign = git_attr_rule__lookup_assignment(rule, "also"); cl_assert(assign); cl_assert_equal_s("also", assign->name); cl_assert_equal_s("a-really-long-value/*", assign->value); assign = git_attr_rule__lookup_assignment(rule, "happy"); cl_assert(assign); cl_assert_equal_s("happy", assign->name); cl_assert_equal_s("yes!", assign->value); assign = git_attr_rule__lookup_assignment(rule, "other"); cl_assert(!assign); rule = get_rule(9); cl_assert_equal_s("pat8", rule->match.pattern); cl_assert(rule->assigns.length == 2); assign = git_attr_rule__lookup_assignment(rule, "again"); cl_assert(assign); cl_assert_equal_s("again", assign->name); cl_assert(GIT_ATTR_TRUE(assign->value)); assign = git_attr_rule__lookup_assignment(rule, "another"); cl_assert(assign); cl_assert_equal_s("another", assign->name); cl_assert_equal_s("12321", assign->value); check_one_assign(file, 10, 0, "pat9", "at-eof", EXPECT_FALSE, NULL); git_attr_file__free(file); } void test_attr_file__check_attr_examples(void) { git_attr_file *file; git_attr_rule *rule; git_attr_assignment *assign; cl_git_pass(git_attr_file__new_and_load(&file, cl_fixture("attr/attr3"))); cl_assert_equal_s(cl_fixture("attr/attr3"), file->key + 2); cl_assert(file->rules.length == 3); rule = get_rule(0); cl_assert_equal_s("*.java", rule->match.pattern); cl_assert(rule->assigns.length == 3); assign = git_attr_rule__lookup_assignment(rule, "diff"); cl_assert_equal_s("diff", assign->name); cl_assert_equal_s("java", assign->value); assign = git_attr_rule__lookup_assignment(rule, "crlf"); cl_assert_equal_s("crlf", assign->name); cl_assert(GIT_ATTR_FALSE(assign->value)); assign = git_attr_rule__lookup_assignment(rule, "myAttr"); cl_assert_equal_s("myAttr", assign->name); cl_assert(GIT_ATTR_TRUE(assign->value)); assign = git_attr_rule__lookup_assignment(rule, "missing"); cl_assert(assign == NULL); rule = get_rule(1); cl_assert_equal_s("NoMyAttr.java", rule->match.pattern); cl_assert(rule->assigns.length == 1); assign = get_assign(rule, 0); cl_assert_equal_s("myAttr", assign->name); cl_assert(GIT_ATTR_UNSPECIFIED(assign->value)); rule = get_rule(2); cl_assert_equal_s("README", rule->match.pattern); cl_assert(rule->assigns.length == 1); assign = get_assign(rule, 0); cl_assert_equal_s("caveat", assign->name); cl_assert_equal_s("unspecified", assign->value); git_attr_file__free(file); } libgit2-0.19.0/tests-clar/attr/flags.c000066400000000000000000000061051216214232500174300ustar00rootroot00000000000000#include "clar_libgit2.h" #include "git2/attr.h" void test_attr_flags__cleanup(void) { cl_git_sandbox_cleanup(); } void test_attr_flags__bare(void) { git_repository *repo = cl_git_sandbox_init("testrepo.git"); const char *value; cl_assert(git_repository_is_bare(repo)); cl_git_pass(git_attr_get( &value, repo, GIT_ATTR_CHECK_NO_SYSTEM, "README.md", "diff")); cl_assert(GIT_ATTR_UNSPECIFIED(value)); } void test_attr_flags__index_vs_workdir(void) { git_repository *repo = cl_git_sandbox_init("attr_index"); const char *value; cl_assert(!git_repository_is_bare(repo)); /* wd then index */ cl_git_pass(git_attr_get( &value, repo, GIT_ATTR_CHECK_NO_SYSTEM | GIT_ATTR_CHECK_FILE_THEN_INDEX, "README.md", "bar")); cl_assert(GIT_ATTR_FALSE(value)); cl_git_pass(git_attr_get( &value, repo, GIT_ATTR_CHECK_NO_SYSTEM | GIT_ATTR_CHECK_FILE_THEN_INDEX, "README.md", "blargh")); cl_assert_equal_s(value, "goop"); cl_git_pass(git_attr_get( &value, repo, GIT_ATTR_CHECK_NO_SYSTEM | GIT_ATTR_CHECK_FILE_THEN_INDEX, "README.txt", "foo")); cl_assert(GIT_ATTR_FALSE(value)); /* index then wd */ cl_git_pass(git_attr_get( &value, repo, GIT_ATTR_CHECK_NO_SYSTEM | GIT_ATTR_CHECK_INDEX_THEN_FILE, "README.md", "bar")); cl_assert(GIT_ATTR_TRUE(value)); cl_git_pass(git_attr_get( &value, repo, GIT_ATTR_CHECK_NO_SYSTEM | GIT_ATTR_CHECK_INDEX_THEN_FILE, "README.md", "blargh")); cl_assert_equal_s(value, "garble"); cl_git_pass(git_attr_get( &value, repo, GIT_ATTR_CHECK_NO_SYSTEM | GIT_ATTR_CHECK_INDEX_THEN_FILE, "README.txt", "foo")); cl_assert(GIT_ATTR_TRUE(value)); } void test_attr_flags__subdir(void) { git_repository *repo = cl_git_sandbox_init("attr_index"); const char *value; /* wd then index */ cl_git_pass(git_attr_get( &value, repo, GIT_ATTR_CHECK_NO_SYSTEM | GIT_ATTR_CHECK_FILE_THEN_INDEX, "sub/sub/README.md", "bar")); cl_assert_equal_s(value, "1234"); cl_git_pass(git_attr_get( &value, repo, GIT_ATTR_CHECK_NO_SYSTEM | GIT_ATTR_CHECK_FILE_THEN_INDEX, "sub/sub/README.txt", "another")); cl_assert_equal_s(value, "one"); cl_git_pass(git_attr_get( &value, repo, GIT_ATTR_CHECK_NO_SYSTEM | GIT_ATTR_CHECK_FILE_THEN_INDEX, "sub/sub/README.txt", "again")); cl_assert(GIT_ATTR_TRUE(value)); cl_git_pass(git_attr_get( &value, repo, GIT_ATTR_CHECK_NO_SYSTEM | GIT_ATTR_CHECK_FILE_THEN_INDEX, "sub/sub/README.txt", "beep")); cl_assert_equal_s(value, "10"); /* index then wd */ cl_git_pass(git_attr_get( &value, repo, GIT_ATTR_CHECK_NO_SYSTEM | GIT_ATTR_CHECK_INDEX_THEN_FILE, "sub/sub/README.md", "bar")); cl_assert_equal_s(value, "1337"); cl_git_pass(git_attr_get( &value, repo, GIT_ATTR_CHECK_NO_SYSTEM | GIT_ATTR_CHECK_INDEX_THEN_FILE, "sub/sub/README.txt", "another")); cl_assert_equal_s(value, "one"); cl_git_pass(git_attr_get( &value, repo, GIT_ATTR_CHECK_NO_SYSTEM | GIT_ATTR_CHECK_INDEX_THEN_FILE, "sub/sub/README.txt", "again")); cl_assert(GIT_ATTR_TRUE(value)); cl_git_pass(git_attr_get( &value, repo, GIT_ATTR_CHECK_NO_SYSTEM | GIT_ATTR_CHECK_INDEX_THEN_FILE, "sub/sub/README.txt", "beep")); cl_assert_equal_s(value, "5"); } libgit2-0.19.0/tests-clar/attr/ignore.c000066400000000000000000000054471216214232500176270ustar00rootroot00000000000000#include "clar_libgit2.h" #include "posix.h" #include "path.h" #include "fileops.h" static git_repository *g_repo = NULL; void test_attr_ignore__initialize(void) { g_repo = cl_git_sandbox_init("attr"); } void test_attr_ignore__cleanup(void) { cl_git_sandbox_cleanup(); g_repo = NULL; } void assert_is_ignored(bool expected, const char *filepath) { int is_ignored; cl_git_pass(git_ignore_path_is_ignored(&is_ignored, g_repo, filepath)); cl_assert_equal_b(expected, is_ignored); } void test_attr_ignore__honor_temporary_rules(void) { cl_git_rewritefile("attr/.gitignore", "/NewFolder\n/NewFolder/NewFolder"); assert_is_ignored(false, "File.txt"); assert_is_ignored(true, "NewFolder"); assert_is_ignored(true, "NewFolder/NewFolder"); assert_is_ignored(true, "NewFolder/NewFolder/File.txt"); } void test_attr_ignore__allow_root(void) { cl_git_rewritefile("attr/.gitignore", "/"); assert_is_ignored(false, "File.txt"); assert_is_ignored(false, "NewFolder"); assert_is_ignored(false, "NewFolder/NewFolder"); assert_is_ignored(false, "NewFolder/NewFolder/File.txt"); } void test_attr_ignore__ignore_root(void) { cl_git_rewritefile("attr/.gitignore", "/\n\n/NewFolder\n/NewFolder/NewFolder"); assert_is_ignored(false, "File.txt"); assert_is_ignored(true, "NewFolder"); assert_is_ignored(true, "NewFolder/NewFolder"); assert_is_ignored(true, "NewFolder/NewFolder/File.txt"); } void test_attr_ignore__skip_gitignore_directory(void) { cl_git_rewritefile("attr/.git/info/exclude", "/NewFolder\n/NewFolder/NewFolder"); p_unlink("attr/.gitignore"); cl_assert(!git_path_exists("attr/.gitignore")); p_mkdir("attr/.gitignore", 0777); cl_git_mkfile("attr/.gitignore/garbage.txt", "new_file\n"); assert_is_ignored(false, "File.txt"); assert_is_ignored(true, "NewFolder"); assert_is_ignored(true, "NewFolder/NewFolder"); assert_is_ignored(true, "NewFolder/NewFolder/File.txt"); } void test_attr_ignore__expand_tilde_to_homedir(void) { git_buf path = GIT_BUF_INIT; git_config *cfg; assert_is_ignored(false, "example.global_with_tilde"); /* construct fake home with fake global excludes */ cl_must_pass(p_mkdir("home", 0777)); cl_git_pass(git_path_prettify(&path, "home", NULL)); cl_git_pass(git_libgit2_opts( GIT_OPT_SET_SEARCH_PATH, GIT_CONFIG_LEVEL_GLOBAL, path.ptr)); cl_git_mkfile("home/globalexcludes", "# found me\n*.global_with_tilde\n"); cl_git_pass(git_repository_config(&cfg, g_repo)); cl_git_pass(git_config_set_string(cfg, "core.excludesfile", "~/globalexcludes")); git_config_free(cfg); git_attr_cache_flush(g_repo); /* must reset to pick up change */ assert_is_ignored(true, "example.global_with_tilde"); cl_git_pass(git_futils_rmdir_r("home", NULL, GIT_RMDIR_REMOVE_FILES)); cl_git_pass(git_libgit2_opts( GIT_OPT_SET_SEARCH_PATH, GIT_CONFIG_LEVEL_GLOBAL, NULL)); git_buf_free(&path); } libgit2-0.19.0/tests-clar/attr/lookup.c000066400000000000000000000222221216214232500176430ustar00rootroot00000000000000#include "clar_libgit2.h" #include "attr_file.h" #include "attr_expect.h" void test_attr_lookup__simple(void) { git_attr_file *file; git_attr_path path; const char *value = NULL; cl_git_pass(git_attr_file__new_and_load(&file, cl_fixture("attr/attr0"))); cl_assert_equal_s(cl_fixture("attr/attr0"), file->key + 2); cl_assert(file->rules.length == 1); cl_git_pass(git_attr_path__init(&path, "test", NULL)); cl_assert_equal_s("test", path.path); cl_assert_equal_s("test", path.basename); cl_assert(!path.is_dir); cl_git_pass(git_attr_file__lookup_one(file,&path,"binary",&value)); cl_assert(GIT_ATTR_TRUE(value)); cl_git_pass(git_attr_file__lookup_one(file,&path,"missing",&value)); cl_assert(!value); git_attr_path__free(&path); git_attr_file__free(file); } static void run_test_cases(git_attr_file *file, struct attr_expected *cases, int force_dir) { git_attr_path path; const char *value = NULL; struct attr_expected *c; int error; for (c = cases; c->path != NULL; c++) { cl_git_pass(git_attr_path__init(&path, c->path, NULL)); if (force_dir) path.is_dir = 1; error = git_attr_file__lookup_one(file,&path,c->attr,&value); cl_git_pass(error); attr_check_expected(c->expected, c->expected_str, c->attr, value); git_attr_path__free(&path); } } void test_attr_lookup__match_variants(void) { git_attr_file *file; git_attr_path path; struct attr_expected dir_cases[] = { { "pat2", "attr2", EXPECT_TRUE, NULL }, { "/testing/for/pat2", "attr2", EXPECT_TRUE, NULL }, { "/not/pat2/yousee", "attr2", EXPECT_UNDEFINED, NULL }, { "/fun/fun/fun/pat4.dir", "attr4", EXPECT_TRUE, NULL }, { "foo.pat5", "attr5", EXPECT_TRUE, NULL }, { NULL, NULL, 0, NULL } }; struct attr_expected cases[] = { /* pat0 -> simple match */ { "pat0", "attr0", EXPECT_TRUE, NULL }, { "/testing/for/pat0", "attr0", EXPECT_TRUE, NULL }, { "relative/to/pat0", "attr0", EXPECT_TRUE, NULL }, { "this-contains-pat0-inside", "attr0", EXPECT_UNDEFINED, NULL }, { "this-aint-right", "attr0", EXPECT_UNDEFINED, NULL }, { "/this/pat0/dont/match", "attr0", EXPECT_UNDEFINED, NULL }, /* negative match */ { "pat0", "attr1", EXPECT_TRUE, NULL }, { "pat1", "attr1", EXPECT_UNDEFINED, NULL }, { "/testing/for/pat1", "attr1", EXPECT_UNDEFINED, NULL }, { "/testing/for/pat0", "attr1", EXPECT_TRUE, NULL }, { "/testing/for/pat1/inside", "attr1", EXPECT_TRUE, NULL }, { "misc", "attr1", EXPECT_TRUE, NULL }, /* dir match */ { "pat2", "attr2", EXPECT_UNDEFINED, NULL }, { "/testing/for/pat2", "attr2", EXPECT_UNDEFINED, NULL }, { "/not/pat2/yousee", "attr2", EXPECT_UNDEFINED, NULL }, /* path match */ { "pat3file", "attr3", EXPECT_UNDEFINED, NULL }, { "/pat3dir/pat3file", "attr3", EXPECT_TRUE, NULL }, { "pat3dir/pat3file", "attr3", EXPECT_TRUE, NULL }, /* pattern* match */ { "pat4.txt", "attr4", EXPECT_TRUE, NULL }, { "/fun/fun/fun/pat4.c", "attr4", EXPECT_TRUE, NULL }, { "pat4.", "attr4", EXPECT_TRUE, NULL }, { "pat4", "attr4", EXPECT_UNDEFINED, NULL }, /* *pattern match */ { "foo.pat5", "attr5", EXPECT_TRUE, NULL }, { "/this/is/ok.pat5", "attr5", EXPECT_TRUE, NULL }, { "/this/is/bad.pat5/yousee.txt", "attr5", EXPECT_UNDEFINED, NULL }, { "foo.pat5", "attr100", EXPECT_UNDEFINED, NULL }, /* glob match with slashes */ { "foo.pat6", "attr6", EXPECT_UNDEFINED, NULL }, { "pat6/pat6/foobar.pat6", "attr6", EXPECT_TRUE, NULL }, { "pat6/pat6/.pat6", "attr6", EXPECT_TRUE, NULL }, { "pat6/pat6/extra/foobar.pat6", "attr6", EXPECT_UNDEFINED, NULL }, { "/prefix/pat6/pat6/foobar.pat6", "attr6", EXPECT_UNDEFINED, NULL }, { "/pat6/pat6/foobar.pat6", "attr6", EXPECT_TRUE, NULL }, /* complex pattern */ { "pat7a12z", "attr7", EXPECT_TRUE, NULL }, { "pat7e__x", "attr7", EXPECT_TRUE, NULL }, { "pat7b/1y", "attr7", EXPECT_UNDEFINED, NULL }, /* ? does not match / */ { "pat7e_x", "attr7", EXPECT_UNDEFINED, NULL }, { "pat7aaaa", "attr7", EXPECT_UNDEFINED, NULL }, { "pat7zzzz", "attr7", EXPECT_UNDEFINED, NULL }, { "/this/can/be/anything/pat7a12z", "attr7", EXPECT_TRUE, NULL }, { "but/it/still/must/match/pat7aaaa", "attr7", EXPECT_UNDEFINED, NULL }, { "pat7aaay.fail", "attr7", EXPECT_UNDEFINED, NULL }, /* pattern with spaces */ { "pat8 with spaces", "attr8", EXPECT_TRUE, NULL }, { "/gotta love/pat8 with spaces", "attr8", EXPECT_TRUE, NULL }, { "failing pat8 with spaces", "attr8", EXPECT_UNDEFINED, NULL }, { "spaces", "attr8", EXPECT_UNDEFINED, NULL }, /* pattern at eof */ { "pat9", "attr9", EXPECT_TRUE, NULL }, { "/eof/pat9", "attr9", EXPECT_TRUE, NULL }, { "pat", "attr9", EXPECT_UNDEFINED, NULL }, { "at9", "attr9", EXPECT_UNDEFINED, NULL }, { "pat9.fail", "attr9", EXPECT_UNDEFINED, NULL }, /* sentinel at end */ { NULL, NULL, 0, NULL } }; cl_git_pass(git_attr_file__new_and_load(&file, cl_fixture("attr/attr1"))); cl_assert_equal_s(cl_fixture("attr/attr1"), file->key + 2); cl_assert(file->rules.length == 10); cl_git_pass(git_attr_path__init(&path, "/testing/for/pat0", NULL)); cl_assert_equal_s("pat0", path.basename); run_test_cases(file, cases, 0); run_test_cases(file, dir_cases, 1); git_attr_file__free(file); git_attr_path__free(&path); } void test_attr_lookup__assign_variants(void) { git_attr_file *file; struct attr_expected cases[] = { /* pat0 -> simple assign */ { "pat0", "simple", EXPECT_TRUE, NULL }, { "/testing/pat0", "simple", EXPECT_TRUE, NULL }, { "pat0", "fail", EXPECT_UNDEFINED, NULL }, { "/testing/pat0", "fail", EXPECT_UNDEFINED, NULL }, /* negative assign */ { "pat1", "neg", EXPECT_FALSE, NULL }, { "/testing/pat1", "neg", EXPECT_FALSE, NULL }, { "pat1", "fail", EXPECT_UNDEFINED, NULL }, { "/testing/pat1", "fail", EXPECT_UNDEFINED, NULL }, /* forced undef */ { "pat1", "notundef", EXPECT_TRUE, NULL }, { "pat2", "notundef", EXPECT_UNDEFINED, NULL }, { "/lead/in/pat1", "notundef", EXPECT_TRUE, NULL }, { "/lead/in/pat2", "notundef", EXPECT_UNDEFINED, NULL }, /* assign value */ { "pat3", "assigned", EXPECT_STRING, "test-value" }, { "pat3", "notassigned", EXPECT_UNDEFINED, NULL }, /* assign value */ { "pat4", "rule-with-more-chars", EXPECT_STRING, "value-with-more-chars" }, { "pat4", "notassigned-rule-with-more-chars", EXPECT_UNDEFINED, NULL }, /* empty assignments */ { "pat5", "empty", EXPECT_TRUE, NULL }, { "pat6", "negempty", EXPECT_FALSE, NULL }, /* multiple assignment */ { "pat7", "multiple", EXPECT_TRUE, NULL }, { "pat7", "single", EXPECT_FALSE, NULL }, { "pat7", "values", EXPECT_STRING, "1" }, { "pat7", "also", EXPECT_STRING, "a-really-long-value/*" }, { "pat7", "happy", EXPECT_STRING, "yes!" }, { "pat8", "again", EXPECT_TRUE, NULL }, { "pat8", "another", EXPECT_STRING, "12321" }, /* bad assignment */ { "patbad0", "simple", EXPECT_UNDEFINED, NULL }, { "patbad0", "notundef", EXPECT_TRUE, NULL }, { "patbad1", "simple", EXPECT_UNDEFINED, NULL }, /* eof assignment */ { "pat9", "at-eof", EXPECT_FALSE, NULL }, /* sentinel at end */ { NULL, NULL, 0, NULL } }; cl_git_pass(git_attr_file__new_and_load(&file, cl_fixture("attr/attr2"))); cl_assert(file->rules.length == 11); run_test_cases(file, cases, 0); git_attr_file__free(file); } void test_attr_lookup__check_attr_examples(void) { git_attr_file *file; struct attr_expected cases[] = { { "foo.java", "diff", EXPECT_STRING, "java" }, { "foo.java", "crlf", EXPECT_FALSE, NULL }, { "foo.java", "myAttr", EXPECT_TRUE, NULL }, { "foo.java", "other", EXPECT_UNDEFINED, NULL }, { "/prefix/dir/foo.java", "diff", EXPECT_STRING, "java" }, { "/prefix/dir/foo.java", "crlf", EXPECT_FALSE, NULL }, { "/prefix/dir/foo.java", "myAttr", EXPECT_TRUE, NULL }, { "/prefix/dir/foo.java", "other", EXPECT_UNDEFINED, NULL }, { "NoMyAttr.java", "crlf", EXPECT_FALSE, NULL }, { "NoMyAttr.java", "myAttr", EXPECT_UNDEFINED, NULL }, { "NoMyAttr.java", "other", EXPECT_UNDEFINED, NULL }, { "/prefix/dir/NoMyAttr.java", "crlf", EXPECT_FALSE, NULL }, { "/prefix/dir/NoMyAttr.java", "myAttr", EXPECT_UNDEFINED, NULL }, { "/prefix/dir/NoMyAttr.java", "other", EXPECT_UNDEFINED, NULL }, { "README", "caveat", EXPECT_STRING, "unspecified" }, { "/specific/path/README", "caveat", EXPECT_STRING, "unspecified" }, { "README", "missing", EXPECT_UNDEFINED, NULL }, { "/specific/path/README", "missing", EXPECT_UNDEFINED, NULL }, /* sentinel at end */ { NULL, NULL, 0, NULL } }; cl_git_pass(git_attr_file__new_and_load(&file, cl_fixture("attr/attr3"))); cl_assert(file->rules.length == 3); run_test_cases(file, cases, 0); git_attr_file__free(file); } void test_attr_lookup__from_buffer(void) { git_attr_file *file; struct attr_expected cases[] = { { "abc", "foo", EXPECT_TRUE, NULL }, { "abc", "bar", EXPECT_TRUE, NULL }, { "abc", "baz", EXPECT_TRUE, NULL }, { "aaa", "foo", EXPECT_TRUE, NULL }, { "aaa", "bar", EXPECT_UNDEFINED, NULL }, { "aaa", "baz", EXPECT_TRUE, NULL }, { "qqq", "foo", EXPECT_UNDEFINED, NULL }, { "qqq", "bar", EXPECT_UNDEFINED, NULL }, { "qqq", "baz", EXPECT_TRUE, NULL }, { NULL, NULL, 0, NULL } }; cl_git_pass(git_attr_file__new(&file, 0, NULL, NULL)); cl_git_pass(git_attr_file__parse_buffer(NULL, NULL, "a* foo\nabc bar\n* baz", file)); cl_assert(file->rules.length == 3); run_test_cases(file, cases, 0); git_attr_file__free(file); } libgit2-0.19.0/tests-clar/attr/repo.c000066400000000000000000000222431216214232500173020ustar00rootroot00000000000000#include "clar_libgit2.h" #include "fileops.h" #include "git2/attr.h" #include "attr.h" #include "attr_expect.h" static git_repository *g_repo = NULL; void test_attr_repo__initialize(void) { /* Before each test, instantiate the attr repo from the fixtures and * rename the .gitted to .git so it is a repo with a working dir. * Also rename gitattributes to .gitattributes, because it contains * macro definitions which are only allowed in the root. */ g_repo = cl_git_sandbox_init("attr"); } void test_attr_repo__cleanup(void) { cl_git_sandbox_cleanup(); g_repo = NULL; } void test_attr_repo__get_one(void) { struct attr_expected test_cases[] = { { "root_test1", "repoattr", EXPECT_TRUE, NULL }, { "root_test1", "rootattr", EXPECT_TRUE, NULL }, { "root_test1", "missingattr", EXPECT_UNDEFINED, NULL }, { "root_test1", "subattr", EXPECT_UNDEFINED, NULL }, { "root_test1", "negattr", EXPECT_UNDEFINED, NULL }, { "root_test2", "repoattr", EXPECT_TRUE, NULL }, { "root_test2", "rootattr", EXPECT_FALSE, NULL }, { "root_test2", "missingattr", EXPECT_UNDEFINED, NULL }, { "root_test2", "multiattr", EXPECT_FALSE, NULL }, { "root_test3", "repoattr", EXPECT_TRUE, NULL }, { "root_test3", "rootattr", EXPECT_UNDEFINED, NULL }, { "root_test3", "multiattr", EXPECT_STRING, "3" }, { "root_test3", "multi2", EXPECT_UNDEFINED, NULL }, { "sub/subdir_test1", "repoattr", EXPECT_TRUE, NULL }, { "sub/subdir_test1", "rootattr", EXPECT_TRUE, NULL }, { "sub/subdir_test1", "missingattr", EXPECT_UNDEFINED, NULL }, { "sub/subdir_test1", "subattr", EXPECT_STRING, "yes" }, { "sub/subdir_test1", "negattr", EXPECT_FALSE, NULL }, { "sub/subdir_test1", "another", EXPECT_UNDEFINED, NULL }, { "sub/subdir_test2.txt", "repoattr", EXPECT_TRUE, NULL }, { "sub/subdir_test2.txt", "rootattr", EXPECT_TRUE, NULL }, { "sub/subdir_test2.txt", "missingattr", EXPECT_UNDEFINED, NULL }, { "sub/subdir_test2.txt", "subattr", EXPECT_STRING, "yes" }, { "sub/subdir_test2.txt", "negattr", EXPECT_FALSE, NULL }, { "sub/subdir_test2.txt", "another", EXPECT_STRING, "zero" }, { "sub/subdir_test2.txt", "reposub", EXPECT_TRUE, NULL }, { "sub/sub/subdir.txt", "another", EXPECT_STRING, "one" }, { "sub/sub/subdir.txt", "reposubsub", EXPECT_TRUE, NULL }, { "sub/sub/subdir.txt", "reposub", EXPECT_UNDEFINED, NULL }, { "does-not-exist", "foo", EXPECT_STRING, "yes" }, { "sub/deep/file", "deepdeep", EXPECT_TRUE, NULL }, { "sub/sub/d/no", "test", EXPECT_STRING, "a/b/d/*" }, { "sub/sub/d/yes", "test", EXPECT_UNDEFINED, NULL }, { NULL, NULL, 0, NULL } }, *scan; for (scan = test_cases; scan->path != NULL; scan++) { const char *value; cl_git_pass(git_attr_get(&value, g_repo, 0, scan->path, scan->attr)); attr_check_expected(scan->expected, scan->expected_str, scan->attr, value); } cl_assert(git_attr_cache__is_cached(g_repo, 0, ".git/info/attributes")); cl_assert(git_attr_cache__is_cached(g_repo, 0, ".gitattributes")); cl_assert(git_attr_cache__is_cached(g_repo, 0, "sub/.gitattributes")); } void test_attr_repo__get_many(void) { const char *names[4] = { "repoattr", "rootattr", "missingattr", "subattr" }; const char *values[4]; cl_git_pass(git_attr_get_many(values, g_repo, 0, "root_test1", 4, names)); cl_assert(GIT_ATTR_TRUE(values[0])); cl_assert(GIT_ATTR_TRUE(values[1])); cl_assert(GIT_ATTR_UNSPECIFIED(values[2])); cl_assert(GIT_ATTR_UNSPECIFIED(values[3])); cl_git_pass(git_attr_get_many(values, g_repo, 0, "root_test2", 4, names)); cl_assert(GIT_ATTR_TRUE(values[0])); cl_assert(GIT_ATTR_FALSE(values[1])); cl_assert(GIT_ATTR_UNSPECIFIED(values[2])); cl_assert(GIT_ATTR_UNSPECIFIED(values[3])); cl_git_pass(git_attr_get_many(values, g_repo, 0, "sub/subdir_test1", 4, names)); cl_assert(GIT_ATTR_TRUE(values[0])); cl_assert(GIT_ATTR_TRUE(values[1])); cl_assert(GIT_ATTR_UNSPECIFIED(values[2])); cl_assert_equal_s("yes", values[3]); } static int count_attrs( const char *name, const char *value, void *payload) { GIT_UNUSED(name); GIT_UNUSED(value); *((int *)payload) += 1; return 0; } static int cancel_iteration( const char *name, const char *value, void *payload) { GIT_UNUSED(name); GIT_UNUSED(value); *((int *)payload) -= 1; if (*((int *)payload) < 0) return -1; return 0; } void test_attr_repo__foreach(void) { int count; count = 0; cl_git_pass(git_attr_foreach( g_repo, 0, "root_test1", &count_attrs, &count)); cl_assert(count == 2); count = 0; cl_git_pass(git_attr_foreach(g_repo, 0, "sub/subdir_test1", &count_attrs, &count)); cl_assert(count == 4); /* repoattr, rootattr, subattr, negattr */ count = 0; cl_git_pass(git_attr_foreach(g_repo, 0, "sub/subdir_test2.txt", &count_attrs, &count)); cl_assert(count == 6); /* repoattr, rootattr, subattr, reposub, negattr, another */ count = 2; cl_assert_equal_i( GIT_EUSER, git_attr_foreach( g_repo, 0, "sub/subdir_test1", &cancel_iteration, &count) ); } void test_attr_repo__manpage_example(void) { const char *value; cl_git_pass(git_attr_get(&value, g_repo, 0, "sub/abc", "foo")); cl_assert(GIT_ATTR_TRUE(value)); cl_git_pass(git_attr_get(&value, g_repo, 0, "sub/abc", "bar")); cl_assert(GIT_ATTR_UNSPECIFIED(value)); cl_git_pass(git_attr_get(&value, g_repo, 0, "sub/abc", "baz")); cl_assert(GIT_ATTR_FALSE(value)); cl_git_pass(git_attr_get(&value, g_repo, 0, "sub/abc", "merge")); cl_assert_equal_s("filfre", value); cl_git_pass(git_attr_get(&value, g_repo, 0, "sub/abc", "frotz")); cl_assert(GIT_ATTR_UNSPECIFIED(value)); } void test_attr_repo__macros(void) { const char *names[5] = { "rootattr", "binary", "diff", "crlf", "frotz" }; const char *names2[5] = { "mymacro", "positive", "negative", "rootattr", "another" }; const char *names3[3] = { "macro2", "multi2", "multi3" }; const char *values[5]; cl_git_pass(git_attr_get_many(values, g_repo, 0, "binfile", 5, names)); cl_assert(GIT_ATTR_TRUE(values[0])); cl_assert(GIT_ATTR_TRUE(values[1])); cl_assert(GIT_ATTR_FALSE(values[2])); cl_assert(GIT_ATTR_FALSE(values[3])); cl_assert(GIT_ATTR_UNSPECIFIED(values[4])); cl_git_pass(git_attr_get_many(values, g_repo, 0, "macro_test", 5, names2)); cl_assert(GIT_ATTR_TRUE(values[0])); cl_assert(GIT_ATTR_TRUE(values[1])); cl_assert(GIT_ATTR_FALSE(values[2])); cl_assert(GIT_ATTR_UNSPECIFIED(values[3])); cl_assert_equal_s("77", values[4]); cl_git_pass(git_attr_get_many(values, g_repo, 0, "macro_test", 3, names3)); cl_assert(GIT_ATTR_TRUE(values[0])); cl_assert(GIT_ATTR_FALSE(values[1])); cl_assert_equal_s("answer", values[2]); } void test_attr_repo__bad_macros(void) { const char *names[6] = { "rootattr", "positive", "negative", "firstmacro", "secondmacro", "thirdmacro" }; const char *values[6]; cl_git_pass(git_attr_get_many(values, g_repo, 0, "macro_bad", 6, names)); /* these three just confirm that the "mymacro" rule ran */ cl_assert(GIT_ATTR_UNSPECIFIED(values[0])); cl_assert(GIT_ATTR_TRUE(values[1])); cl_assert(GIT_ATTR_FALSE(values[2])); /* file contains: * # let's try some malicious macro defs * [attr]firstmacro -thirdmacro -secondmacro * [attr]secondmacro firstmacro -firstmacro * [attr]thirdmacro secondmacro=hahaha -firstmacro * macro_bad firstmacro secondmacro thirdmacro * * firstmacro assignment list ends up with: * -thirdmacro -secondmacro * secondmacro assignment list expands "firstmacro" and ends up with: * -thirdmacro -secondmacro -firstmacro * thirdmacro assignment don't expand so list ends up with: * secondmacro="hahaha" * * macro_bad assignment list ends up with: * -thirdmacro -secondmacro firstmacro && * -thirdmacro -secondmacro -firstmacro secondmacro && * secondmacro="hahaha" thirdmacro * * so summary results should be: * -firstmacro secondmacro="hahaha" thirdmacro */ cl_assert(GIT_ATTR_FALSE(values[3])); cl_assert_equal_s("hahaha", values[4]); cl_assert(GIT_ATTR_TRUE(values[5])); } #define CONTENT "I'm going to be dynamically processed\r\n" \ "And my line endings...\r\n" \ "...are going to be\n" \ "normalized!\r\n" #define GITATTR "* text=auto\n" \ "*.txt text\n" \ "*.data binary\n" static void add_to_workdir(const char *filename, const char *content) { git_buf buf = GIT_BUF_INIT; cl_git_pass(git_buf_joinpath(&buf, "attr", filename)); cl_git_rewritefile(git_buf_cstr(&buf), content); git_buf_free(&buf); } static void assert_proper_normalization(git_index *index, const char *filename, const char *expected_sha) { size_t index_pos; const git_index_entry *entry; add_to_workdir(filename, CONTENT); cl_git_pass(git_index_add_bypath(index, filename)); cl_assert(!git_index_find(&index_pos, index, filename)); entry = git_index_get_byindex(index, index_pos); cl_assert_equal_i(0, git_oid_streq(&entry->oid, expected_sha)); } void test_attr_repo__staging_properly_normalizes_line_endings_according_to_gitattributes_directives(void) { git_index* index; cl_git_pass(git_repository_index(&index, g_repo)); add_to_workdir(".gitattributes", GITATTR); assert_proper_normalization(index, "text.txt", "22c74203bace3c2e950278c7ab08da0fca9f4e9b"); assert_proper_normalization(index, "huh.dunno", "22c74203bace3c2e950278c7ab08da0fca9f4e9b"); assert_proper_normalization(index, "binary.data", "66eeff1fcbacf589e6d70aa70edd3fce5be2b37c"); git_index_free(index); } libgit2-0.19.0/tests-clar/buf/000077500000000000000000000000001216214232500157705ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/buf/basic.c000066400000000000000000000015031216214232500172140ustar00rootroot00000000000000#include "clar_libgit2.h" #include "buffer.h" static const char *test_string = "Have you seen that? Have you seeeen that??"; void test_buf_basic__resize(void) { git_buf buf1 = GIT_BUF_INIT; git_buf_puts(&buf1, test_string); cl_assert(git_buf_oom(&buf1) == 0); cl_assert_equal_s(git_buf_cstr(&buf1), test_string); git_buf_puts(&buf1, test_string); cl_assert(strlen(git_buf_cstr(&buf1)) == strlen(test_string) * 2); git_buf_free(&buf1); } void test_buf_basic__printf(void) { git_buf buf2 = GIT_BUF_INIT; git_buf_printf(&buf2, "%s %s %d ", "shoop", "da", 23); cl_assert(git_buf_oom(&buf2) == 0); cl_assert_equal_s(git_buf_cstr(&buf2), "shoop da 23 "); git_buf_printf(&buf2, "%s %d", "woop", 42); cl_assert(git_buf_oom(&buf2) == 0); cl_assert_equal_s(git_buf_cstr(&buf2), "shoop da 23 woop 42"); git_buf_free(&buf2); } libgit2-0.19.0/tests-clar/buf/splice.c000066400000000000000000000042661216214232500174230ustar00rootroot00000000000000#include "clar_libgit2.h" #include "buffer.h" static git_buf _buf; void test_buf_splice__initialize(void) { git_buf_init(&_buf, 16); } void test_buf_splice__cleanup(void) { git_buf_free(&_buf); } void test_buf_splice__preprend(void) { git_buf_sets(&_buf, "world!"); cl_git_pass(git_buf_splice(&_buf, 0, 0, "Hello Dolly", strlen("Hello "))); cl_assert_equal_s("Hello world!", git_buf_cstr(&_buf)); } void test_buf_splice__append(void) { git_buf_sets(&_buf, "Hello"); cl_git_pass(git_buf_splice(&_buf, git_buf_len(&_buf), 0, " world!", strlen(" world!"))); cl_assert_equal_s("Hello world!", git_buf_cstr(&_buf)); } void test_buf_splice__insert_at(void) { git_buf_sets(&_buf, "Hell world!"); cl_git_pass(git_buf_splice(&_buf, strlen("Hell"), 0, "o", strlen("o"))); cl_assert_equal_s("Hello world!", git_buf_cstr(&_buf)); } void test_buf_splice__remove_at(void) { git_buf_sets(&_buf, "Hello world of warcraft!"); cl_git_pass(git_buf_splice(&_buf, strlen("Hello world"), strlen(" of warcraft"), "", 0)); cl_assert_equal_s("Hello world!", git_buf_cstr(&_buf)); } void test_buf_splice__replace(void) { git_buf_sets(&_buf, "Hell0 w0rld!"); cl_git_pass(git_buf_splice(&_buf, strlen("Hell"), strlen("0 w0"), "o wo", strlen("o wo"))); cl_assert_equal_s("Hello world!", git_buf_cstr(&_buf)); } void test_buf_splice__replace_with_longer(void) { git_buf_sets(&_buf, "Hello you!"); cl_git_pass(git_buf_splice(&_buf, strlen("Hello "), strlen("you"), "world", strlen("world"))); cl_assert_equal_s("Hello world!", git_buf_cstr(&_buf)); } void test_buf_splice__replace_with_shorter(void) { git_buf_sets(&_buf, "Brave new world!"); cl_git_pass(git_buf_splice(&_buf, 0, strlen("Brave new"), "Hello", strlen("Hello"))); cl_assert_equal_s("Hello world!", git_buf_cstr(&_buf)); } void test_buf_splice__truncate(void) { git_buf_sets(&_buf, "Hello world!!"); cl_git_pass(git_buf_splice(&_buf, strlen("Hello world!"), strlen("!"), "", 0)); cl_assert_equal_s("Hello world!", git_buf_cstr(&_buf)); } void test_buf_splice__dont_do_anything(void) { git_buf_sets(&_buf, "Hello world!"); cl_git_pass(git_buf_splice(&_buf, 3, 0, "Hello", 0)); cl_assert_equal_s("Hello world!", git_buf_cstr(&_buf)); } libgit2-0.19.0/tests-clar/checkout/000077500000000000000000000000001216214232500170215ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/checkout/binaryunicode.c000066400000000000000000000031151216214232500220200ustar00rootroot00000000000000#include "clar_libgit2.h" #include "refs.h" #include "repo/repo_helpers.h" #include "path.h" #include "fileops.h" static git_repository *g_repo; void test_checkout_binaryunicode__initialize(void) { g_repo = cl_git_sandbox_init("binaryunicode"); } void test_checkout_binaryunicode__cleanup(void) { cl_git_sandbox_cleanup(); } static void execute_test(void) { git_oid oid, check; git_commit *commit; git_tree *tree; git_checkout_opts opts = GIT_CHECKOUT_OPTS_INIT; cl_git_pass(git_reference_name_to_id(&oid, g_repo, "refs/heads/branch1")); cl_git_pass(git_commit_lookup(&commit, g_repo, &oid)); cl_git_pass(git_commit_tree(&tree, commit)); opts.checkout_strategy = GIT_CHECKOUT_SAFE; cl_git_pass(git_checkout_tree(g_repo, (git_object *)tree, &opts)); git_tree_free(tree); git_commit_free(commit); /* Verify that the lenna.jpg file was checked out correctly */ cl_git_pass(git_oid_fromstr(&check, "8ab005d890fe53f65eda14b23672f60d9f4ec5a1")); cl_git_pass(git_odb_hashfile(&oid, "binaryunicode/lenna.jpg", GIT_OBJ_BLOB)); cl_assert(git_oid_equal(&oid, &check)); /* Verify that the text file was checked out correctly */ cl_git_pass(git_oid_fromstr(&check, "965b223880dd4249e2c66a0cc0b4cffe1dc40f5a")); cl_git_pass(git_odb_hashfile(&oid, "binaryunicode/utf16_withbom_noeol_crlf.txt", GIT_OBJ_BLOB)); cl_assert(git_oid_equal(&oid, &check)); } void test_checkout_binaryunicode__noautocrlf(void) { cl_repo_set_bool(g_repo, "core.autocrlf", false); execute_test(); } void test_checkout_binaryunicode__autocrlf(void) { cl_repo_set_bool(g_repo, "core.autocrlf", true); execute_test(); } libgit2-0.19.0/tests-clar/checkout/checkout_helpers.c000066400000000000000000000106611216214232500225200ustar00rootroot00000000000000#include "clar_libgit2.h" #include "checkout_helpers.h" #include "refs.h" #include "fileops.h" /* this is essentially the code from git__unescape modified slightly */ void strip_cr_from_buf(git_buf *buf) { char *scan, *pos = buf->ptr, *end = pos + buf->size; for (scan = pos; scan < end; pos++, scan++) { if (*scan == '\r') scan++; /* skip '\r' */ if (pos != scan) *pos = *scan; } *pos = '\0'; buf->size = (pos - buf->ptr); } void assert_on_branch(git_repository *repo, const char *branch) { git_reference *head; git_buf bname = GIT_BUF_INIT; cl_git_pass(git_reference_lookup(&head, repo, GIT_HEAD_FILE)); cl_assert_(git_reference_type(head) == GIT_REF_SYMBOLIC, branch); cl_git_pass(git_buf_joinpath(&bname, "refs/heads", branch)); cl_assert_equal_s(bname.ptr, git_reference_symbolic_target(head)); git_reference_free(head); git_buf_free(&bname); } void reset_index_to_treeish(git_object *treeish) { git_object *tree; git_index *index; git_repository *repo = git_object_owner(treeish); cl_git_pass(git_object_peel(&tree, treeish, GIT_OBJ_TREE)); cl_git_pass(git_repository_index(&index, repo)); cl_git_pass(git_index_read_tree(index, (git_tree *)tree)); cl_git_pass(git_index_write(index)); git_object_free(tree); git_index_free(index); } static void check_file_contents_internal( const char *path, const char *expected_content, bool strip_cr, const char *file, int line, const char *msg) { int fd; char data[1024] = {0}; git_buf buf = GIT_BUF_INIT; size_t expected_len = expected_content ? strlen(expected_content) : 0; fd = p_open(path, O_RDONLY); cl_assert(fd >= 0); buf.ptr = data; buf.size = p_read(fd, buf.ptr, sizeof(data)); cl_git_pass(p_close(fd)); if (strip_cr) strip_cr_from_buf(&buf); clar__assert_equal_i((int)expected_len, (int)buf.size, file, line, "strlen(expected_content) != strlen(actual_content)", 1); clar__assert_equal_s(expected_content, buf.ptr, file, line, msg, 1); } void check_file_contents_at_line( const char *path, const char *expected, const char *file, int line, const char *msg) { check_file_contents_internal(path, expected, false, file, line, msg); } void check_file_contents_nocr_at_line( const char *path, const char *expected, const char *file, int line, const char *msg) { check_file_contents_internal(path, expected, true, file, line, msg); } int checkout_count_callback( git_checkout_notify_t why, const char *path, const git_diff_file *baseline, const git_diff_file *target, const git_diff_file *workdir, void *payload) { checkout_counts *ct = payload; GIT_UNUSED(baseline); GIT_UNUSED(target); GIT_UNUSED(workdir); if (why & GIT_CHECKOUT_NOTIFY_CONFLICT) { ct->n_conflicts++; if (ct->debug) { if (workdir) { if (baseline) { if (target) fprintf(stderr, "M %s (conflicts with M %s)\n", workdir->path, target->path); else fprintf(stderr, "M %s (conflicts with D %s)\n", workdir->path, baseline->path); } else { if (target) fprintf(stderr, "Existing %s (conflicts with A %s)\n", workdir->path, target->path); else fprintf(stderr, "How can an untracked file be a conflict (%s)\n", workdir->path); } } else { if (baseline) { if (target) fprintf(stderr, "D %s (conflicts with M %s)\n", target->path, baseline->path); else fprintf(stderr, "D %s (conflicts with D %s)\n", baseline->path, baseline->path); } else { if (target) fprintf(stderr, "How can an added file with no workdir be a conflict (%s)\n", target->path); else fprintf(stderr, "How can a nonexistent file be a conflict (%s)\n", path); } } } } if (why & GIT_CHECKOUT_NOTIFY_DIRTY) { ct->n_dirty++; if (ct->debug) { if (workdir) fprintf(stderr, "M %s\n", workdir->path); else fprintf(stderr, "D %s\n", baseline->path); } } if (why & GIT_CHECKOUT_NOTIFY_UPDATED) { ct->n_updates++; if (ct->debug) { if (baseline) { if (target) fprintf(stderr, "update: M %s\n", path); else fprintf(stderr, "update: D %s\n", path); } else { if (target) fprintf(stderr, "update: A %s\n", path); else fprintf(stderr, "update: this makes no sense %s\n", path); } } } if (why & GIT_CHECKOUT_NOTIFY_UNTRACKED) { ct->n_untracked++; if (ct->debug) fprintf(stderr, "? %s\n", path); } if (why & GIT_CHECKOUT_NOTIFY_IGNORED) { ct->n_ignored++; if (ct->debug) fprintf(stderr, "I %s\n", path); } return 0; } libgit2-0.19.0/tests-clar/checkout/checkout_helpers.h000066400000000000000000000021411216214232500225170ustar00rootroot00000000000000#include "buffer.h" #include "git2/object.h" #include "git2/repository.h" extern void strip_cr_from_buf(git_buf *buf); extern void assert_on_branch(git_repository *repo, const char *branch); extern void reset_index_to_treeish(git_object *treeish); extern void check_file_contents_at_line( const char *path, const char *expected, const char *file, int line, const char *msg); extern void check_file_contents_nocr_at_line( const char *path, const char *expected, const char *file, int line, const char *msg); #define check_file_contents(PATH,EXP) \ check_file_contents_at_line(PATH,EXP,__FILE__,__LINE__,"String mismatch: " #EXP " != " #PATH) #define check_file_contents_nocr(PATH,EXP) \ check_file_contents_nocr_at_line(PATH,EXP,__FILE__,__LINE__,"String mismatch: " #EXP " != " #PATH) typedef struct { int n_conflicts; int n_dirty; int n_updates; int n_untracked; int n_ignored; int debug; } checkout_counts; extern int checkout_count_callback( git_checkout_notify_t why, const char *path, const git_diff_file *baseline, const git_diff_file *target, const git_diff_file *workdir, void *payload); libgit2-0.19.0/tests-clar/checkout/crlf.c000066400000000000000000000101011216214232500201040ustar00rootroot00000000000000#include "clar_libgit2.h" #include "checkout_helpers.h" #include "git2/checkout.h" #include "repository.h" #define UTF8_BOM "\xEF\xBB\xBF" #define ALL_CRLF_TEXT_RAW "crlf\r\ncrlf\r\ncrlf\r\ncrlf\r\n" #define ALL_LF_TEXT_RAW "lf\nlf\nlf\nlf\nlf\n" #define MORE_CRLF_TEXT_RAW "crlf\r\ncrlf\r\nlf\ncrlf\r\ncrlf\r\n" #define MORE_LF_TEXT_RAW "lf\nlf\ncrlf\r\nlf\nlf\n" #define ALL_LF_TEXT_AS_CRLF "lf\r\nlf\r\nlf\r\nlf\r\nlf\r\n" #define MORE_CRLF_TEXT_AS_CRLF "crlf\r\ncrlf\r\nlf\r\ncrlf\r\ncrlf\r\n" #define MORE_LF_TEXT_AS_CRLF "lf\r\nlf\r\ncrlf\r\nlf\r\nlf\r\n" static git_repository *g_repo; void test_checkout_crlf__initialize(void) { g_repo = cl_git_sandbox_init("crlf"); } void test_checkout_crlf__cleanup(void) { cl_git_sandbox_cleanup(); } void test_checkout_crlf__detect_crlf_autocrlf_false(void) { git_checkout_opts opts = GIT_CHECKOUT_OPTS_INIT; opts.checkout_strategy = GIT_CHECKOUT_SAFE_CREATE; cl_repo_set_bool(g_repo, "core.autocrlf", false); git_checkout_head(g_repo, &opts); check_file_contents("./crlf/all-lf", ALL_LF_TEXT_RAW); check_file_contents("./crlf/all-crlf", ALL_CRLF_TEXT_RAW); } void test_checkout_crlf__autocrlf_false_index_size_is_unfiltered_size(void) { git_index *index; const git_index_entry *entry; git_checkout_opts opts = GIT_CHECKOUT_OPTS_INIT; opts.checkout_strategy = GIT_CHECKOUT_SAFE_CREATE; cl_repo_set_bool(g_repo, "core.autocrlf", false); git_checkout_head(g_repo, &opts); git_repository_index(&index, g_repo); cl_assert((entry = git_index_get_bypath(index, "all-lf", 0)) != NULL); cl_assert(entry->file_size == strlen(ALL_LF_TEXT_RAW)); cl_assert((entry = git_index_get_bypath(index, "all-crlf", 0)) != NULL); cl_assert(entry->file_size == strlen(ALL_CRLF_TEXT_RAW)); git_index_free(index); } void test_checkout_crlf__detect_crlf_autocrlf_true(void) { git_checkout_opts opts = GIT_CHECKOUT_OPTS_INIT; opts.checkout_strategy = GIT_CHECKOUT_SAFE_CREATE; cl_repo_set_bool(g_repo, "core.autocrlf", true); git_checkout_head(g_repo, &opts); if (GIT_EOL_NATIVE == GIT_EOL_LF) check_file_contents("./crlf/all-lf", ALL_LF_TEXT_RAW); else check_file_contents("./crlf/all-lf", ALL_LF_TEXT_AS_CRLF); check_file_contents("./crlf/all-crlf", ALL_CRLF_TEXT_RAW); } void test_checkout_crlf__more_lf_autocrlf_true(void) { git_checkout_opts opts = GIT_CHECKOUT_OPTS_INIT; opts.checkout_strategy = GIT_CHECKOUT_SAFE_CREATE; cl_repo_set_bool(g_repo, "core.autocrlf", true); git_checkout_head(g_repo, &opts); if (GIT_EOL_NATIVE == GIT_EOL_LF) check_file_contents("./crlf/more-lf", MORE_LF_TEXT_RAW); else check_file_contents("./crlf/more-lf", MORE_LF_TEXT_AS_CRLF); } void test_checkout_crlf__more_crlf_autocrlf_true(void) { git_checkout_opts opts = GIT_CHECKOUT_OPTS_INIT; opts.checkout_strategy = GIT_CHECKOUT_SAFE_CREATE; cl_repo_set_bool(g_repo, "core.autocrlf", true); git_checkout_head(g_repo, &opts); if (GIT_EOL_NATIVE == GIT_EOL_LF) check_file_contents("./crlf/more-crlf", MORE_CRLF_TEXT_RAW); else check_file_contents("./crlf/more-crlf", MORE_CRLF_TEXT_AS_CRLF); } void test_checkout_crlf__all_crlf_autocrlf_true(void) { git_checkout_opts opts = GIT_CHECKOUT_OPTS_INIT; opts.checkout_strategy = GIT_CHECKOUT_SAFE_CREATE; cl_repo_set_bool(g_repo, "core.autocrlf", true); git_checkout_head(g_repo, &opts); check_file_contents("./crlf/all-crlf", ALL_CRLF_TEXT_RAW); } void test_checkout_crlf__autocrlf_true_index_size_is_filtered_size(void) { git_index *index; const git_index_entry *entry; git_checkout_opts opts = GIT_CHECKOUT_OPTS_INIT; opts.checkout_strategy = GIT_CHECKOUT_SAFE_CREATE; cl_repo_set_bool(g_repo, "core.autocrlf", true); git_checkout_head(g_repo, &opts); git_repository_index(&index, g_repo); cl_assert((entry = git_index_get_bypath(index, "all-lf", 0)) != NULL); if (GIT_EOL_NATIVE == GIT_EOL_LF) cl_assert_equal_sz(strlen(ALL_LF_TEXT_RAW), entry->file_size); else cl_assert_equal_sz(strlen(ALL_LF_TEXT_AS_CRLF), entry->file_size); cl_assert((entry = git_index_get_bypath(index, "all-crlf", 0)) != NULL); cl_assert_equal_sz(strlen(ALL_CRLF_TEXT_RAW), entry->file_size); git_index_free(index); } libgit2-0.19.0/tests-clar/checkout/head.c000066400000000000000000000033171216214232500200720ustar00rootroot00000000000000#include "clar_libgit2.h" #include "refs.h" #include "repo/repo_helpers.h" #include "path.h" #include "fileops.h" static git_repository *g_repo; void test_checkout_head__initialize(void) { g_repo = cl_git_sandbox_init("testrepo"); } void test_checkout_head__cleanup(void) { cl_git_sandbox_cleanup(); } void test_checkout_head__orphaned_head_returns_GIT_EORPHANEDHEAD(void) { make_head_orphaned(g_repo, NON_EXISTING_HEAD); cl_assert_equal_i(GIT_EORPHANEDHEAD, git_checkout_head(g_repo, NULL)); } void test_checkout_head__with_index_only_tree(void) { git_checkout_opts opts = GIT_CHECKOUT_OPTS_INIT; git_index *index; /* let's start by getting things into a known state */ opts.checkout_strategy = GIT_CHECKOUT_FORCE; cl_git_pass(git_checkout_head(g_repo, &opts)); /* now let's stage some new stuff including a new directory */ cl_git_pass(git_repository_index(&index, g_repo)); p_mkdir("testrepo/newdir", 0777); cl_git_mkfile("testrepo/newdir/newfile.txt", "new file\n"); cl_git_pass(git_index_add_bypath(index, "newdir/newfile.txt")); cl_git_pass(git_index_write(index)); cl_assert(git_path_isfile("testrepo/newdir/newfile.txt")); cl_assert(git_index_get_bypath(index, "newdir/newfile.txt", 0) != NULL); git_index_free(index); /* okay, so now we have staged this new file; let's see if we can remove */ opts.checkout_strategy = GIT_CHECKOUT_FORCE | GIT_CHECKOUT_REMOVE_UNTRACKED; cl_git_pass(git_checkout_head(g_repo, &opts)); cl_git_pass(git_repository_index(&index, g_repo)); cl_git_pass(git_index_read(index)); /* reload if needed */ cl_assert(!git_path_isfile("testrepo/newdir/newfile.txt")); cl_assert(git_index_get_bypath(index, "newdir/newfile.txt", 0) == NULL); git_index_free(index); } libgit2-0.19.0/tests-clar/checkout/index.c000066400000000000000000000430251216214232500203000ustar00rootroot00000000000000#include "clar_libgit2.h" #include "checkout_helpers.h" #include "git2/checkout.h" #include "fileops.h" #include "repository.h" static git_repository *g_repo; void test_checkout_index__initialize(void) { git_tree *tree; g_repo = cl_git_sandbox_init("testrepo"); cl_git_pass(git_repository_head_tree(&tree, g_repo)); reset_index_to_treeish((git_object *)tree); git_tree_free(tree); cl_git_rewritefile( "./testrepo/.gitattributes", "* text eol=lf\n"); } void test_checkout_index__cleanup(void) { cl_git_sandbox_cleanup(); /* try to remove alternative dir */ if (git_path_isdir("alternative")) git_futils_rmdir_r("alternative", NULL, GIT_RMDIR_REMOVE_FILES); } void test_checkout_index__cannot_checkout_a_bare_repository(void) { test_checkout_index__cleanup(); g_repo = cl_git_sandbox_init("testrepo.git"); cl_git_fail(git_checkout_index(g_repo, NULL, NULL)); } void test_checkout_index__can_create_missing_files(void) { git_checkout_opts opts = GIT_CHECKOUT_OPTS_INIT; cl_assert_equal_i(false, git_path_isfile("./testrepo/README")); cl_assert_equal_i(false, git_path_isfile("./testrepo/branch_file.txt")); cl_assert_equal_i(false, git_path_isfile("./testrepo/new.txt")); opts.checkout_strategy = GIT_CHECKOUT_SAFE_CREATE; cl_git_pass(git_checkout_index(g_repo, NULL, &opts)); check_file_contents("./testrepo/README", "hey there\n"); check_file_contents("./testrepo/branch_file.txt", "hi\nbye!\n"); check_file_contents("./testrepo/new.txt", "my new file\n"); } void test_checkout_index__can_remove_untracked_files(void) { git_checkout_opts opts = GIT_CHECKOUT_OPTS_INIT; git_futils_mkdir("./testrepo/dir/subdir/subsubdir", NULL, 0755, GIT_MKDIR_PATH); cl_git_mkfile("./testrepo/dir/one", "one\n"); cl_git_mkfile("./testrepo/dir/subdir/two", "two\n"); cl_assert_equal_i(true, git_path_isdir("./testrepo/dir/subdir/subsubdir")); opts.checkout_strategy = GIT_CHECKOUT_SAFE_CREATE | GIT_CHECKOUT_REMOVE_UNTRACKED; cl_git_pass(git_checkout_index(g_repo, NULL, &opts)); cl_assert_equal_i(false, git_path_isdir("./testrepo/dir")); } void test_checkout_index__honor_the_specified_pathspecs(void) { git_checkout_opts opts = GIT_CHECKOUT_OPTS_INIT; char *entries[] = { "*.txt" }; opts.paths.strings = entries; opts.paths.count = 1; cl_assert_equal_i(false, git_path_isfile("./testrepo/README")); cl_assert_equal_i(false, git_path_isfile("./testrepo/branch_file.txt")); cl_assert_equal_i(false, git_path_isfile("./testrepo/new.txt")); opts.checkout_strategy = GIT_CHECKOUT_SAFE_CREATE; cl_git_pass(git_checkout_index(g_repo, NULL, &opts)); cl_assert_equal_i(false, git_path_isfile("./testrepo/README")); check_file_contents("./testrepo/branch_file.txt", "hi\nbye!\n"); check_file_contents("./testrepo/new.txt", "my new file\n"); } void test_checkout_index__honor_the_gitattributes_directives(void) { git_checkout_opts opts = GIT_CHECKOUT_OPTS_INIT; const char *attributes = "branch_file.txt text eol=crlf\n" "new.txt text eol=lf\n"; cl_git_mkfile("./testrepo/.gitattributes", attributes); cl_repo_set_bool(g_repo, "core.autocrlf", false); opts.checkout_strategy = GIT_CHECKOUT_SAFE_CREATE; cl_git_pass(git_checkout_index(g_repo, NULL, &opts)); check_file_contents("./testrepo/README", "hey there\n"); check_file_contents("./testrepo/new.txt", "my new file\n"); check_file_contents("./testrepo/branch_file.txt", "hi\r\nbye!\r\n"); } void test_checkout_index__honor_coreautocrlf_setting_set_to_true(void) { #ifdef GIT_WIN32 git_checkout_opts opts = GIT_CHECKOUT_OPTS_INIT; const char *expected_readme_text = "hey there\r\n"; cl_git_pass(p_unlink("./testrepo/.gitattributes")); cl_repo_set_bool(g_repo, "core.autocrlf", true); opts.checkout_strategy = GIT_CHECKOUT_SAFE_CREATE; cl_git_pass(git_checkout_index(g_repo, NULL, &opts)); check_file_contents("./testrepo/README", expected_readme_text); #endif } void test_checkout_index__honor_coresymlinks_setting_set_to_true(void) { git_checkout_opts opts = GIT_CHECKOUT_OPTS_INIT; cl_repo_set_bool(g_repo, "core.symlinks", true); opts.checkout_strategy = GIT_CHECKOUT_SAFE_CREATE; cl_git_pass(git_checkout_index(g_repo, NULL, &opts)); #ifdef GIT_WIN32 check_file_contents("./testrepo/link_to_new.txt", "new.txt"); #else { char link_data[1024]; size_t link_size = 1024; link_size = p_readlink("./testrepo/link_to_new.txt", link_data, link_size); link_data[link_size] = '\0'; cl_assert_equal_i(link_size, strlen("new.txt")); cl_assert_equal_s(link_data, "new.txt"); check_file_contents("./testrepo/link_to_new.txt", "my new file\n"); } #endif } void test_checkout_index__honor_coresymlinks_setting_set_to_false(void) { git_checkout_opts opts = GIT_CHECKOUT_OPTS_INIT; cl_repo_set_bool(g_repo, "core.symlinks", false); opts.checkout_strategy = GIT_CHECKOUT_SAFE_CREATE; cl_git_pass(git_checkout_index(g_repo, NULL, &opts)); check_file_contents("./testrepo/link_to_new.txt", "new.txt"); } void test_checkout_index__donot_overwrite_modified_file_by_default(void) { git_checkout_opts opts = GIT_CHECKOUT_OPTS_INIT; cl_git_mkfile("./testrepo/new.txt", "This isn't what's stored!"); /* set this up to not return an error code on conflicts, but it * still will not have permission to overwrite anything... */ opts.checkout_strategy = GIT_CHECKOUT_SAFE | GIT_CHECKOUT_ALLOW_CONFLICTS; cl_git_pass(git_checkout_index(g_repo, NULL, &opts)); check_file_contents("./testrepo/new.txt", "This isn't what's stored!"); } void test_checkout_index__can_overwrite_modified_file(void) { git_checkout_opts opts = GIT_CHECKOUT_OPTS_INIT; cl_git_mkfile("./testrepo/new.txt", "This isn't what's stored!"); opts.checkout_strategy = GIT_CHECKOUT_FORCE; cl_git_pass(git_checkout_index(g_repo, NULL, &opts)); check_file_contents("./testrepo/new.txt", "my new file\n"); } void test_checkout_index__options_disable_filters(void) { git_checkout_opts opts = GIT_CHECKOUT_OPTS_INIT; cl_git_mkfile("./testrepo/.gitattributes", "*.txt text eol=crlf\n"); opts.checkout_strategy = GIT_CHECKOUT_SAFE_CREATE; opts.disable_filters = false; cl_git_pass(git_checkout_index(g_repo, NULL, &opts)); check_file_contents("./testrepo/new.txt", "my new file\r\n"); p_unlink("./testrepo/new.txt"); opts.disable_filters = true; cl_git_pass(git_checkout_index(g_repo, NULL, &opts)); check_file_contents("./testrepo/new.txt", "my new file\n"); } void test_checkout_index__options_dir_modes(void) { #ifndef GIT_WIN32 git_checkout_opts opts = GIT_CHECKOUT_OPTS_INIT; struct stat st; git_oid oid; git_commit *commit; cl_git_pass(git_reference_name_to_id(&oid, g_repo, "refs/heads/dir")); cl_git_pass(git_commit_lookup(&commit, g_repo, &oid)); reset_index_to_treeish((git_object *)commit); opts.checkout_strategy = GIT_CHECKOUT_SAFE_CREATE; opts.dir_mode = 0701; cl_git_pass(git_checkout_index(g_repo, NULL, &opts)); cl_git_pass(p_stat("./testrepo/a", &st)); cl_assert_equal_i(st.st_mode & 0777, 0701); /* File-mode test, since we're on the 'dir' branch */ cl_git_pass(p_stat("./testrepo/a/b.txt", &st)); cl_assert_equal_i(st.st_mode & 0777, 0755); git_commit_free(commit); #endif } void test_checkout_index__options_override_file_modes(void) { #ifndef GIT_WIN32 git_checkout_opts opts = GIT_CHECKOUT_OPTS_INIT; struct stat st; opts.checkout_strategy = GIT_CHECKOUT_SAFE_CREATE; opts.file_mode = 0700; cl_git_pass(git_checkout_index(g_repo, NULL, &opts)); cl_git_pass(p_stat("./testrepo/new.txt", &st)); cl_assert_equal_i(st.st_mode & 0777, 0700); #endif } void test_checkout_index__options_open_flags(void) { git_checkout_opts opts = GIT_CHECKOUT_OPTS_INIT; cl_git_mkfile("./testrepo/new.txt", "hi\n"); opts.checkout_strategy = GIT_CHECKOUT_SAFE_CREATE; opts.file_open_flags = O_CREAT | O_RDWR | O_APPEND; opts.checkout_strategy = GIT_CHECKOUT_FORCE; cl_git_pass(git_checkout_index(g_repo, NULL, &opts)); check_file_contents("./testrepo/new.txt", "hi\nmy new file\n"); } struct notify_data { const char *file; const char *sha; }; static int test_checkout_notify_cb( git_checkout_notify_t why, const char *path, const git_diff_file *baseline, const git_diff_file *target, const git_diff_file *workdir, void *payload) { struct notify_data *expectations = (struct notify_data *)payload; GIT_UNUSED(workdir); cl_assert_equal_i(GIT_CHECKOUT_NOTIFY_CONFLICT, why); cl_assert_equal_s(expectations->file, path); cl_assert_equal_i(0, git_oid_streq(&baseline->oid, expectations->sha)); cl_assert_equal_i(0, git_oid_streq(&target->oid, expectations->sha)); return 0; } void test_checkout_index__can_notify_of_skipped_files(void) { git_checkout_opts opts = GIT_CHECKOUT_OPTS_INIT; struct notify_data data; cl_git_mkfile("./testrepo/new.txt", "This isn't what's stored!"); /* * $ git ls-tree HEAD * 100644 blob a8233120f6ad708f843d861ce2b7228ec4e3dec6 README * 100644 blob 3697d64be941a53d4ae8f6a271e4e3fa56b022cc branch_file.txt * 100644 blob a71586c1dfe8a71c6cbf6c129f404c5642ff31bd new.txt */ data.file = "new.txt"; data.sha = "a71586c1dfe8a71c6cbf6c129f404c5642ff31bd"; opts.checkout_strategy = GIT_CHECKOUT_SAFE_CREATE | GIT_CHECKOUT_ALLOW_CONFLICTS; opts.notify_flags = GIT_CHECKOUT_NOTIFY_CONFLICT; opts.notify_cb = test_checkout_notify_cb; opts.notify_payload = &data; cl_git_pass(git_checkout_index(g_repo, NULL, &opts)); } static int dont_notify_cb( git_checkout_notify_t why, const char *path, const git_diff_file *baseline, const git_diff_file *target, const git_diff_file *workdir, void *payload) { GIT_UNUSED(why); GIT_UNUSED(path); GIT_UNUSED(baseline); GIT_UNUSED(target); GIT_UNUSED(workdir); GIT_UNUSED(payload); cl_assert(false); return 0; } void test_checkout_index__wont_notify_of_expected_line_ending_changes(void) { git_checkout_opts opts = GIT_CHECKOUT_OPTS_INIT; cl_git_pass(p_unlink("./testrepo/.gitattributes")); cl_repo_set_bool(g_repo, "core.autocrlf", true); cl_git_mkfile("./testrepo/new.txt", "my new file\r\n"); opts.checkout_strategy = GIT_CHECKOUT_SAFE_CREATE | GIT_CHECKOUT_ALLOW_CONFLICTS; opts.notify_flags = GIT_CHECKOUT_NOTIFY_CONFLICT; opts.notify_cb = dont_notify_cb; opts.notify_payload = NULL; cl_git_pass(git_checkout_index(g_repo, NULL, &opts)); } static void checkout_progress_counter( const char *path, size_t cur, size_t tot, void *payload) { GIT_UNUSED(path); GIT_UNUSED(cur); GIT_UNUSED(tot); (*(int *)payload)++; } void test_checkout_index__calls_progress_callback(void) { git_checkout_opts opts = GIT_CHECKOUT_OPTS_INIT; int calls = 0; opts.checkout_strategy = GIT_CHECKOUT_SAFE_CREATE; opts.progress_cb = checkout_progress_counter; opts.progress_payload = &calls; cl_git_pass(git_checkout_index(g_repo, NULL, &opts)); cl_assert(calls > 0); } void test_checkout_index__can_overcome_name_clashes(void) { git_checkout_opts opts = GIT_CHECKOUT_OPTS_INIT; git_index *index; cl_git_pass(git_repository_index(&index, g_repo)); git_index_clear(index); cl_git_mkfile("./testrepo/path0", "content\r\n"); cl_git_pass(p_mkdir("./testrepo/path1", 0777)); cl_git_mkfile("./testrepo/path1/file1", "content\r\n"); cl_git_pass(git_index_add_bypath(index, "path0")); cl_git_pass(git_index_add_bypath(index, "path1/file1")); cl_git_pass(p_unlink("./testrepo/path0")); cl_git_pass(git_futils_rmdir_r( "./testrepo/path1", NULL, GIT_RMDIR_REMOVE_FILES)); cl_git_mkfile("./testrepo/path1", "content\r\n"); cl_git_pass(p_mkdir("./testrepo/path0", 0777)); cl_git_mkfile("./testrepo/path0/file0", "content\r\n"); cl_assert(git_path_isfile("./testrepo/path1")); cl_assert(git_path_isfile("./testrepo/path0/file0")); opts.checkout_strategy = GIT_CHECKOUT_SAFE_CREATE | GIT_CHECKOUT_ALLOW_CONFLICTS; cl_git_pass(git_checkout_index(g_repo, index, &opts)); cl_assert(git_path_isfile("./testrepo/path1")); cl_assert(git_path_isfile("./testrepo/path0/file0")); opts.checkout_strategy = GIT_CHECKOUT_FORCE; cl_git_pass(git_checkout_index(g_repo, index, &opts)); cl_assert(git_path_isfile("./testrepo/path0")); cl_assert(git_path_isfile("./testrepo/path1/file1")); git_index_free(index); } void test_checkout_index__validates_struct_version(void) { git_checkout_opts opts = GIT_CHECKOUT_OPTS_INIT; const git_error *err; opts.version = 1024; cl_git_fail(git_checkout_index(g_repo, NULL, &opts)); err = giterr_last(); cl_assert_equal_i(err->klass, GITERR_INVALID); opts.version = 0; giterr_clear(); cl_git_fail(git_checkout_index(g_repo, NULL, &opts)); err = giterr_last(); cl_assert_equal_i(err->klass, GITERR_INVALID); } void test_checkout_index__can_update_prefixed_files(void) { git_checkout_opts opts = GIT_CHECKOUT_OPTS_INIT; cl_assert_equal_i(false, git_path_isfile("./testrepo/README")); cl_assert_equal_i(false, git_path_isfile("./testrepo/branch_file.txt")); cl_assert_equal_i(false, git_path_isfile("./testrepo/new.txt")); cl_git_mkfile("./testrepo/READ", "content\n"); cl_git_mkfile("./testrepo/README.after", "content\n"); cl_git_pass(p_mkdir("./testrepo/branch_file", 0777)); cl_git_pass(p_mkdir("./testrepo/branch_file/contained_dir", 0777)); cl_git_mkfile("./testrepo/branch_file/contained_file", "content\n"); cl_git_pass(p_mkdir("./testrepo/branch_file.txt.after", 0777)); opts.checkout_strategy = GIT_CHECKOUT_SAFE_CREATE | GIT_CHECKOUT_REMOVE_UNTRACKED; cl_git_pass(git_checkout_index(g_repo, NULL, &opts)); /* remove untracked will remove the .gitattributes file before the blobs * were created, so they will have had crlf filtering applied on Windows */ check_file_contents_nocr("./testrepo/README", "hey there\n"); check_file_contents_nocr("./testrepo/branch_file.txt", "hi\nbye!\n"); check_file_contents_nocr("./testrepo/new.txt", "my new file\n"); cl_assert(!git_path_exists("testrepo/READ")); cl_assert(!git_path_exists("testrepo/README.after")); cl_assert(!git_path_exists("testrepo/branch_file")); cl_assert(!git_path_exists("testrepo/branch_file.txt.after")); } void test_checkout_index__can_checkout_a_newly_initialized_repository(void) { test_checkout_index__cleanup(); g_repo = cl_git_sandbox_init("empty_standard_repo"); cl_git_remove_placeholders(git_repository_path(g_repo), "dummy-marker.txt"); cl_git_pass(git_checkout_index(g_repo, NULL, NULL)); } void test_checkout_index__issue_1397(void) { git_checkout_opts opts = GIT_CHECKOUT_OPTS_INIT; test_checkout_index__cleanup(); g_repo = cl_git_sandbox_init("issue_1397"); cl_repo_set_bool(g_repo, "core.autocrlf", true); opts.checkout_strategy = GIT_CHECKOUT_FORCE; cl_git_pass(git_checkout_index(g_repo, NULL, &opts)); check_file_contents("./issue_1397/crlf_file.txt", "first line\r\nsecond line\r\nboth with crlf"); } void test_checkout_index__target_directory(void) { git_checkout_opts opts = GIT_CHECKOUT_OPTS_INIT; checkout_counts cts; memset(&cts, 0, sizeof(cts)); opts.checkout_strategy = GIT_CHECKOUT_SAFE_CREATE; opts.target_directory = "alternative"; cl_assert(!git_path_isdir("alternative")); opts.notify_flags = GIT_CHECKOUT_NOTIFY_ALL; opts.notify_cb = checkout_count_callback; opts.notify_payload = &cts; /* create some files that *would* conflict if we were using the wd */ cl_git_mkfile("testrepo/README", "I'm in the way!\n"); cl_git_mkfile("testrepo/new.txt", "my new file\n"); cl_git_pass(git_checkout_index(g_repo, NULL, &opts)); cl_assert_equal_i(0, cts.n_untracked); cl_assert_equal_i(0, cts.n_ignored); cl_assert_equal_i(4, cts.n_updates); check_file_contents("./alternative/README", "hey there\n"); check_file_contents("./alternative/branch_file.txt", "hi\nbye!\n"); check_file_contents("./alternative/new.txt", "my new file\n"); cl_git_pass(git_futils_rmdir_r( "alternative", NULL, GIT_RMDIR_REMOVE_FILES)); } void test_checkout_index__target_directory_from_bare(void) { git_checkout_opts opts = GIT_CHECKOUT_OPTS_INIT; git_index *index; git_object *head = NULL; checkout_counts cts; memset(&cts, 0, sizeof(cts)); test_checkout_index__cleanup(); g_repo = cl_git_sandbox_init("testrepo.git"); cl_assert(git_repository_is_bare(g_repo)); cl_git_pass(git_repository_index(&index, g_repo)); cl_git_pass(git_revparse_single(&head, g_repo, "HEAD^{tree}")); cl_git_pass(git_index_read_tree(index, (const git_tree *)head)); cl_git_pass(git_index_write(index)); git_index_free(index); opts.checkout_strategy = GIT_CHECKOUT_SAFE_CREATE; opts.notify_flags = GIT_CHECKOUT_NOTIFY_ALL; opts.notify_cb = checkout_count_callback; opts.notify_payload = &cts; /* fail to checkout a bare repo */ cl_git_fail(git_checkout_index(g_repo, NULL, &opts)); opts.target_directory = "alternative"; cl_assert(!git_path_isdir("alternative")); cl_git_pass(git_checkout_index(g_repo, NULL, &opts)); cl_assert_equal_i(0, cts.n_untracked); cl_assert_equal_i(0, cts.n_ignored); cl_assert_equal_i(3, cts.n_updates); /* files will have been filtered if needed, so strip CR */ check_file_contents_nocr("./alternative/README", "hey there\n"); check_file_contents_nocr("./alternative/branch_file.txt", "hi\nbye!\n"); check_file_contents_nocr("./alternative/new.txt", "my new file\n"); cl_git_pass(git_futils_rmdir_r( "alternative", NULL, GIT_RMDIR_REMOVE_FILES)); } void test_checkout_index__can_get_repo_from_index(void) { git_index *index; git_checkout_opts opts = GIT_CHECKOUT_OPTS_INIT; cl_assert_equal_i(false, git_path_isfile("./testrepo/README")); cl_assert_equal_i(false, git_path_isfile("./testrepo/branch_file.txt")); cl_assert_equal_i(false, git_path_isfile("./testrepo/new.txt")); opts.checkout_strategy = GIT_CHECKOUT_SAFE_CREATE; cl_git_pass(git_repository_index(&index, g_repo)); cl_git_pass(git_checkout_index(NULL, index, &opts)); check_file_contents("./testrepo/README", "hey there\n"); check_file_contents("./testrepo/branch_file.txt", "hi\nbye!\n"); check_file_contents("./testrepo/new.txt", "my new file\n"); git_index_free(index); } libgit2-0.19.0/tests-clar/checkout/tree.c000066400000000000000000000474161216214232500201400ustar00rootroot00000000000000#include "clar_libgit2.h" #include "checkout_helpers.h" #include "git2/checkout.h" #include "repository.h" #include "buffer.h" #include "fileops.h" static git_repository *g_repo; static git_checkout_opts g_opts; static git_object *g_object; void test_checkout_tree__initialize(void) { g_repo = cl_git_sandbox_init("testrepo"); GIT_INIT_STRUCTURE(&g_opts, GIT_CHECKOUT_OPTS_VERSION); g_opts.checkout_strategy = GIT_CHECKOUT_SAFE_CREATE; } void test_checkout_tree__cleanup(void) { git_object_free(g_object); g_object = NULL; cl_git_sandbox_cleanup(); if (git_path_isdir("alternative")) git_futils_rmdir_r("alternative", NULL, GIT_RMDIR_REMOVE_FILES); } void test_checkout_tree__cannot_checkout_a_non_treeish(void) { /* blob */ cl_git_pass(git_revparse_single(&g_object, g_repo, "a71586c1dfe8a71c6cbf6c129f404c5642ff31bd")); cl_git_fail(git_checkout_tree(g_repo, g_object, NULL)); } void test_checkout_tree__can_checkout_a_subdirectory_from_a_commit(void) { char *entries[] = { "ab/de/" }; g_opts.paths.strings = entries; g_opts.paths.count = 1; cl_git_pass(git_revparse_single(&g_object, g_repo, "subtrees")); cl_assert_equal_i(false, git_path_isdir("./testrepo/ab/")); cl_git_pass(git_checkout_tree(g_repo, g_object, &g_opts)); cl_assert_equal_i(true, git_path_isfile("./testrepo/ab/de/2.txt")); cl_assert_equal_i(true, git_path_isfile("./testrepo/ab/de/fgh/1.txt")); } void test_checkout_tree__can_checkout_and_remove_directory(void) { cl_assert_equal_i(false, git_path_isdir("./testrepo/ab/")); /* Checkout brach "subtrees" and update HEAD, so that HEAD matches the * current working tree */ cl_git_pass(git_revparse_single(&g_object, g_repo, "subtrees")); cl_git_pass(git_checkout_tree(g_repo, g_object, &g_opts)); cl_git_pass(git_repository_set_head(g_repo, "refs/heads/subtrees")); cl_assert_equal_i(true, git_path_isdir("./testrepo/ab/")); cl_assert_equal_i(true, git_path_isfile("./testrepo/ab/de/2.txt")); cl_assert_equal_i(true, git_path_isfile("./testrepo/ab/de/fgh/1.txt")); git_object_free(g_object); g_object = NULL; /* Checkout brach "master" and update HEAD, so that HEAD matches the * current working tree */ cl_git_pass(git_revparse_single(&g_object, g_repo, "master")); cl_git_pass(git_checkout_tree(g_repo, g_object, &g_opts)); cl_git_pass(git_repository_set_head(g_repo, "refs/heads/master")); /* This directory should no longer exist */ cl_assert_equal_i(false, git_path_isdir("./testrepo/ab/")); } void test_checkout_tree__can_checkout_a_subdirectory_from_a_subtree(void) { char *entries[] = { "de/" }; g_opts.paths.strings = entries; g_opts.paths.count = 1; cl_git_pass(git_revparse_single(&g_object, g_repo, "subtrees:ab")); cl_assert_equal_i(false, git_path_isdir("./testrepo/de/")); cl_git_pass(git_checkout_tree(g_repo, g_object, &g_opts)); cl_assert_equal_i(true, git_path_isfile("./testrepo/de/2.txt")); cl_assert_equal_i(true, git_path_isfile("./testrepo/de/fgh/1.txt")); } static void progress(const char *path, size_t cur, size_t tot, void *payload) { bool *was_called = (bool*)payload; GIT_UNUSED(path); GIT_UNUSED(cur); GIT_UNUSED(tot); *was_called = true; } void test_checkout_tree__calls_progress_callback(void) { bool was_called = 0; g_opts.progress_cb = progress; g_opts.progress_payload = &was_called; cl_git_pass(git_revparse_single(&g_object, g_repo, "master")); cl_git_pass(git_checkout_tree(g_repo, g_object, &g_opts)); cl_assert_equal_i(was_called, true); } void test_checkout_tree__doesnt_write_unrequested_files_to_worktree(void) { git_oid master_oid; git_oid chomped_oid; git_commit* p_master_commit; git_commit* p_chomped_commit; git_checkout_opts opts = GIT_CHECKOUT_OPTS_INIT; git_oid_fromstr(&master_oid, "a65fedf39aefe402d3bb6e24df4d4f5fe4547750"); git_oid_fromstr(&chomped_oid, "e90810b8df3e80c413d903f631643c716887138d"); cl_git_pass(git_commit_lookup(&p_master_commit, g_repo, &master_oid)); cl_git_pass(git_commit_lookup(&p_chomped_commit, g_repo, &chomped_oid)); /* GIT_CHECKOUT_NONE should not add any file to the working tree from the * index as it is supposed to be a dry run. */ opts.checkout_strategy = GIT_CHECKOUT_NONE; git_checkout_tree(g_repo, (git_object*)p_chomped_commit, &opts); cl_assert_equal_i(false, git_path_isfile("testrepo/readme.txt")); git_commit_free(p_master_commit); git_commit_free(p_chomped_commit); } void test_checkout_tree__can_switch_branches(void) { git_checkout_opts opts = GIT_CHECKOUT_OPTS_INIT; git_oid oid; git_object *obj = NULL; assert_on_branch(g_repo, "master"); /* do first checkout with FORCE because we don't know if testrepo * base data is clean for a checkout or not */ opts.checkout_strategy = GIT_CHECKOUT_FORCE; cl_git_pass(git_reference_name_to_id(&oid, g_repo, "refs/heads/dir")); cl_git_pass(git_object_lookup(&obj, g_repo, &oid, GIT_OBJ_ANY)); cl_git_pass(git_checkout_tree(g_repo, obj, &opts)); cl_git_pass(git_repository_set_head(g_repo, "refs/heads/dir")); cl_assert(git_path_isfile("testrepo/README")); cl_assert(git_path_isfile("testrepo/branch_file.txt")); cl_assert(git_path_isfile("testrepo/new.txt")); cl_assert(git_path_isfile("testrepo/a/b.txt")); cl_assert(!git_path_isdir("testrepo/ab")); assert_on_branch(g_repo, "dir"); git_object_free(obj); /* do second checkout safe because we should be clean after first */ opts.checkout_strategy = GIT_CHECKOUT_SAFE; cl_git_pass(git_reference_name_to_id(&oid, g_repo, "refs/heads/subtrees")); cl_git_pass(git_object_lookup(&obj, g_repo, &oid, GIT_OBJ_ANY)); cl_git_pass(git_checkout_tree(g_repo, obj, &opts)); cl_git_pass(git_repository_set_head(g_repo, "refs/heads/subtrees")); cl_assert(git_path_isfile("testrepo/README")); cl_assert(git_path_isfile("testrepo/branch_file.txt")); cl_assert(git_path_isfile("testrepo/new.txt")); cl_assert(git_path_isfile("testrepo/ab/4.txt")); cl_assert(git_path_isfile("testrepo/ab/c/3.txt")); cl_assert(git_path_isfile("testrepo/ab/de/2.txt")); cl_assert(git_path_isfile("testrepo/ab/de/fgh/1.txt")); cl_assert(!git_path_isdir("testrepo/a")); assert_on_branch(g_repo, "subtrees"); git_object_free(obj); } void test_checkout_tree__can_remove_untracked(void) { git_checkout_opts opts = GIT_CHECKOUT_OPTS_INIT; opts.checkout_strategy = GIT_CHECKOUT_SAFE | GIT_CHECKOUT_REMOVE_UNTRACKED; cl_git_mkfile("testrepo/untracked_file", "as you wish"); cl_assert(git_path_isfile("testrepo/untracked_file")); cl_git_pass(git_checkout_head(g_repo, &opts)); cl_assert(!git_path_isfile("testrepo/untracked_file")); } void test_checkout_tree__can_remove_ignored(void) { git_checkout_opts opts = GIT_CHECKOUT_OPTS_INIT; int ignored = 0; opts.checkout_strategy = GIT_CHECKOUT_SAFE | GIT_CHECKOUT_REMOVE_IGNORED; cl_git_mkfile("testrepo/ignored_file", "as you wish"); cl_git_pass(git_ignore_add_rule(g_repo, "ignored_file\n")); cl_git_pass(git_ignore_path_is_ignored(&ignored, g_repo, "ignored_file")); cl_assert_equal_i(1, ignored); cl_assert(git_path_isfile("testrepo/ignored_file")); cl_git_pass(git_checkout_head(g_repo, &opts)); cl_assert(!git_path_isfile("testrepo/ignored_file")); } void test_checkout_tree__can_update_only(void) { git_checkout_opts opts = GIT_CHECKOUT_OPTS_INIT; git_oid oid; git_object *obj = NULL; /* first let's get things into a known state - by checkout out the HEAD */ assert_on_branch(g_repo, "master"); opts.checkout_strategy = GIT_CHECKOUT_FORCE; cl_git_pass(git_checkout_head(g_repo, &opts)); cl_assert(!git_path_isdir("testrepo/a")); check_file_contents_nocr("testrepo/branch_file.txt", "hi\nbye!\n"); /* now checkout branch but with update only */ opts.checkout_strategy = GIT_CHECKOUT_SAFE | GIT_CHECKOUT_UPDATE_ONLY; cl_git_pass(git_reference_name_to_id(&oid, g_repo, "refs/heads/dir")); cl_git_pass(git_object_lookup(&obj, g_repo, &oid, GIT_OBJ_ANY)); cl_git_pass(git_checkout_tree(g_repo, obj, &opts)); cl_git_pass(git_repository_set_head(g_repo, "refs/heads/dir")); assert_on_branch(g_repo, "dir"); /* this normally would have been created (which was tested separately in * the test_checkout_tree__can_switch_branches test), but with * UPDATE_ONLY it will not have been created. */ cl_assert(!git_path_isdir("testrepo/a")); /* but this file still should have been updated */ check_file_contents_nocr("testrepo/branch_file.txt", "hi\n"); git_object_free(obj); } void test_checkout_tree__can_checkout_with_pattern(void) { char *entries[] = { "[l-z]*.txt" }; /* reset to beginning of history (i.e. just a README file) */ g_opts.checkout_strategy = GIT_CHECKOUT_FORCE | GIT_CHECKOUT_REMOVE_UNTRACKED; cl_git_pass(git_revparse_single(&g_object, g_repo, "8496071c1b46c854b31185ea97743be6a8774479")); cl_git_pass(git_checkout_tree(g_repo, g_object, &g_opts)); cl_git_pass( git_repository_set_head_detached(g_repo, git_object_id(g_object))); git_object_free(g_object); g_object = NULL; cl_assert(git_path_exists("testrepo/README")); cl_assert(!git_path_exists("testrepo/branch_file.txt")); cl_assert(!git_path_exists("testrepo/link_to_new.txt")); cl_assert(!git_path_exists("testrepo/new.txt")); /* now to a narrow patterned checkout */ g_opts.checkout_strategy = GIT_CHECKOUT_SAFE_CREATE; g_opts.paths.strings = entries; g_opts.paths.count = 1; cl_git_pass(git_revparse_single(&g_object, g_repo, "refs/heads/master")); cl_git_pass(git_checkout_tree(g_repo, g_object, &g_opts)); cl_assert(git_path_exists("testrepo/README")); cl_assert(!git_path_exists("testrepo/branch_file.txt")); cl_assert(git_path_exists("testrepo/link_to_new.txt")); cl_assert(git_path_exists("testrepo/new.txt")); } void test_checkout_tree__can_disable_pattern_match(void) { char *entries[] = { "b*.txt" }; /* reset to beginning of history (i.e. just a README file) */ g_opts.checkout_strategy = GIT_CHECKOUT_FORCE | GIT_CHECKOUT_REMOVE_UNTRACKED; cl_git_pass(git_revparse_single(&g_object, g_repo, "8496071c1b46c854b31185ea97743be6a8774479")); cl_git_pass(git_checkout_tree(g_repo, g_object, &g_opts)); cl_git_pass( git_repository_set_head_detached(g_repo, git_object_id(g_object))); git_object_free(g_object); g_object = NULL; cl_assert(!git_path_isfile("testrepo/branch_file.txt")); /* now to a narrow patterned checkout, but disable pattern */ g_opts.checkout_strategy = GIT_CHECKOUT_SAFE_CREATE | GIT_CHECKOUT_DISABLE_PATHSPEC_MATCH; g_opts.paths.strings = entries; g_opts.paths.count = 1; cl_git_pass(git_revparse_single(&g_object, g_repo, "refs/heads/master")); cl_git_pass(git_checkout_tree(g_repo, g_object, &g_opts)); cl_assert(!git_path_isfile("testrepo/branch_file.txt")); /* let's try that again, but allow the pattern match */ g_opts.checkout_strategy = GIT_CHECKOUT_SAFE_CREATE; cl_git_pass(git_checkout_tree(g_repo, g_object, &g_opts)); cl_assert(git_path_isfile("testrepo/branch_file.txt")); } void assert_conflict( const char *entry_path, const char *new_content, const char *parent_sha, const char *commit_sha) { git_index *index; git_object *hack_tree; git_reference *branch, *head; git_buf file_path = GIT_BUF_INIT; cl_git_pass(git_repository_index(&index, g_repo)); /* Create a branch pointing at the parent */ cl_git_pass(git_revparse_single(&g_object, g_repo, parent_sha)); cl_git_pass(git_branch_create(&branch, g_repo, "potential_conflict", (git_commit *)g_object, 0)); /* Make HEAD point to this branch */ cl_git_pass(git_reference_symbolic_create( &head, g_repo, "HEAD", git_reference_name(branch), 1)); git_reference_free(head); git_reference_free(branch); /* Checkout the parent */ g_opts.checkout_strategy = GIT_CHECKOUT_FORCE; cl_git_pass(git_checkout_tree(g_repo, g_object, &g_opts)); /* Hack-ishy workaound to ensure *all* the index entries * match the content of the tree */ cl_git_pass(git_object_peel(&hack_tree, g_object, GIT_OBJ_TREE)); cl_git_pass(git_index_read_tree(index, (git_tree *)hack_tree)); git_object_free(hack_tree); git_object_free(g_object); g_object = NULL; /* Create a conflicting file */ cl_git_pass(git_buf_joinpath(&file_path, "./testrepo", entry_path)); cl_git_mkfile(git_buf_cstr(&file_path), new_content); git_buf_free(&file_path); /* Trying to checkout the original commit */ cl_git_pass(git_revparse_single(&g_object, g_repo, commit_sha)); g_opts.checkout_strategy = GIT_CHECKOUT_SAFE; cl_assert_equal_i( GIT_EMERGECONFLICT, git_checkout_tree(g_repo, g_object, &g_opts)); /* Stage the conflicting change */ cl_git_pass(git_index_add_bypath(index, entry_path)); cl_git_pass(git_index_write(index)); git_index_free(index); cl_assert_equal_i( GIT_EMERGECONFLICT, git_checkout_tree(g_repo, g_object, &g_opts)); } void test_checkout_tree__checking_out_a_conflicting_type_change_returns_EMERGECONFLICT(void) { /* * 099faba adds a symlink named 'link_to_new.txt' * a65fedf is the parent of 099faba */ assert_conflict("link_to_new.txt", "old.txt", "a65fedf", "099faba"); } void test_checkout_tree__checking_out_a_conflicting_type_change_returns_EMERGECONFLICT_2(void) { /* * cf80f8d adds a directory named 'a/' * a4a7dce is the parent of cf80f8d */ assert_conflict("a", "hello\n", "a4a7dce", "cf80f8d"); } void test_checkout_tree__checking_out_a_conflicting_content_change_returns_EMERGECONFLICT(void) { /* * c47800c adds a symlink named 'branch_file.txt' * 5b5b025 is the parent of 763d71a */ assert_conflict("branch_file.txt", "hello\n", "5b5b025", "c47800c"); } void test_checkout_tree__donot_update_deleted_file_by_default(void) { git_checkout_opts opts = GIT_CHECKOUT_OPTS_INIT; git_oid old_id, new_id; git_commit *old_commit = NULL, *new_commit = NULL; git_index *index = NULL; checkout_counts ct; opts.checkout_strategy = GIT_CHECKOUT_SAFE; memset(&ct, 0, sizeof(ct)); opts.notify_flags = GIT_CHECKOUT_NOTIFY_ALL; opts.notify_cb = checkout_count_callback; opts.notify_payload = &ct; cl_git_pass(git_repository_index(&index, g_repo)); cl_git_pass(git_oid_fromstr(&old_id, "be3563ae3f795b2b4353bcce3a527ad0a4f7f644")); cl_git_pass(git_commit_lookup(&old_commit, g_repo, &old_id)); cl_git_pass(git_reset(g_repo, (git_object *)old_commit, GIT_RESET_HARD)); cl_git_pass(p_unlink("testrepo/branch_file.txt")); cl_git_pass(git_index_remove_bypath(index ,"branch_file.txt")); cl_git_pass(git_index_write(index)); cl_assert(!git_path_exists("testrepo/branch_file.txt")); cl_git_pass(git_oid_fromstr(&new_id, "099fabac3a9ea935598528c27f866e34089c2eff")); cl_git_pass(git_commit_lookup(&new_commit, g_repo, &new_id)); cl_git_fail(git_checkout_tree(g_repo, (git_object *)new_commit, &opts)); cl_assert_equal_i(1, ct.n_conflicts); cl_assert_equal_i(1, ct.n_updates); git_commit_free(old_commit); git_commit_free(new_commit); git_index_free(index); } void test_checkout_tree__can_checkout_with_last_workdir_item_missing(void) { git_index *index = NULL; git_checkout_opts opts = GIT_CHECKOUT_OPTS_INIT; git_oid tree_id, commit_id; git_tree *tree = NULL; git_commit *commit = NULL; git_repository_index(&index, g_repo); opts.checkout_strategy = GIT_CHECKOUT_FORCE; cl_git_pass(git_reference_name_to_id(&commit_id, g_repo, "refs/heads/master")); cl_git_pass(git_commit_lookup(&commit, g_repo, &commit_id)); cl_git_pass(git_checkout_tree(g_repo, (git_object *)commit, &opts)); cl_git_pass(git_repository_set_head(g_repo, "refs/heads/master")); cl_git_pass(p_mkdir("./testrepo/this-is-dir", 0777)); cl_git_mkfile("./testrepo/this-is-dir/contained_file", "content\n"); cl_git_pass(git_index_add_bypath(index, "this-is-dir/contained_file")); git_index_write_tree(&tree_id, index); cl_git_pass(git_tree_lookup(&tree, g_repo, &tree_id)); cl_git_pass(p_unlink("./testrepo/this-is-dir/contained_file")); opts.checkout_strategy = GIT_CHECKOUT_SAFE; opts.checkout_strategy = 1; git_checkout_tree(g_repo, (git_object *)tree, &opts); git_tree_free(tree); git_commit_free(commit); git_index_free(index); } void test_checkout_tree__issue_1397(void) { git_checkout_opts opts = GIT_CHECKOUT_OPTS_INIT; const char *partial_oid = "8a7ef04"; git_object *tree = NULL; test_checkout_tree__cleanup(); /* cleanup default checkout */ g_repo = cl_git_sandbox_init("issue_1397"); cl_repo_set_bool(g_repo, "core.autocrlf", true); cl_git_pass(git_revparse_single(&tree, g_repo, partial_oid)); opts.checkout_strategy = GIT_CHECKOUT_FORCE; cl_git_pass(git_checkout_tree(g_repo, tree, &opts)); check_file_contents("./issue_1397/crlf_file.txt", "first line\r\nsecond line\r\nboth with crlf"); git_object_free(tree); } void test_checkout_tree__can_write_to_empty_dirs(void) { git_checkout_opts opts = GIT_CHECKOUT_OPTS_INIT; git_oid oid; git_object *obj = NULL; assert_on_branch(g_repo, "master"); cl_git_pass(p_mkdir("testrepo/a", 0777)); /* do first checkout with FORCE because we don't know if testrepo * base data is clean for a checkout or not */ opts.checkout_strategy = GIT_CHECKOUT_FORCE; cl_git_pass(git_reference_name_to_id(&oid, g_repo, "refs/heads/dir")); cl_git_pass(git_object_lookup(&obj, g_repo, &oid, GIT_OBJ_ANY)); cl_git_pass(git_checkout_tree(g_repo, obj, &opts)); cl_assert(git_path_isfile("testrepo/a/b.txt")); git_object_free(obj); } void test_checkout_tree__fails_when_dir_in_use(void) { #ifdef GIT_WIN32 git_checkout_opts opts = GIT_CHECKOUT_OPTS_INIT; git_oid oid; git_object *obj = NULL; opts.checkout_strategy = GIT_CHECKOUT_FORCE; cl_git_pass(git_reference_name_to_id(&oid, g_repo, "refs/heads/dir")); cl_git_pass(git_object_lookup(&obj, g_repo, &oid, GIT_OBJ_ANY)); cl_git_pass(git_checkout_tree(g_repo, obj, &opts)); cl_assert(git_path_isfile("testrepo/a/b.txt")); git_object_free(obj); cl_git_pass(p_chdir("testrepo/a")); cl_git_pass(git_reference_name_to_id(&oid, g_repo, "refs/heads/master")); cl_git_pass(git_object_lookup(&obj, g_repo, &oid, GIT_OBJ_ANY)); cl_git_fail(git_checkout_tree(g_repo, obj, &opts)); cl_git_pass(p_chdir("../..")); cl_assert(git_path_is_empty_dir("testrepo/a")); git_object_free(obj); #endif } void test_checkout_tree__can_continue_when_dir_in_use(void) { #ifdef GIT_WIN32 git_checkout_opts opts = GIT_CHECKOUT_OPTS_INIT; git_oid oid; git_object *obj = NULL; opts.checkout_strategy = GIT_CHECKOUT_FORCE | GIT_CHECKOUT_SKIP_LOCKED_DIRECTORIES; cl_git_pass(git_reference_name_to_id(&oid, g_repo, "refs/heads/dir")); cl_git_pass(git_object_lookup(&obj, g_repo, &oid, GIT_OBJ_ANY)); cl_git_pass(git_checkout_tree(g_repo, obj, &opts)); cl_assert(git_path_isfile("testrepo/a/b.txt")); git_object_free(obj); cl_git_pass(p_chdir("testrepo/a")); cl_git_pass(git_reference_name_to_id(&oid, g_repo, "refs/heads/master")); cl_git_pass(git_object_lookup(&obj, g_repo, &oid, GIT_OBJ_ANY)); cl_git_pass(git_checkout_tree(g_repo, obj, &opts)); cl_git_pass(p_chdir("../..")); cl_assert(git_path_is_empty_dir("testrepo/a")); git_object_free(obj); #endif } void test_checkout_tree__target_directory_from_bare(void) { git_checkout_opts opts = GIT_CHECKOUT_OPTS_INIT; git_oid oid; checkout_counts cts; memset(&cts, 0, sizeof(cts)); test_checkout_tree__cleanup(); /* cleanup default checkout */ g_repo = cl_git_sandbox_init("testrepo.git"); cl_assert(git_repository_is_bare(g_repo)); opts.checkout_strategy = GIT_CHECKOUT_SAFE_CREATE; opts.notify_flags = GIT_CHECKOUT_NOTIFY_ALL; opts.notify_cb = checkout_count_callback; opts.notify_payload = &cts; cl_git_pass(git_reference_name_to_id(&oid, g_repo, "HEAD")); cl_git_pass(git_object_lookup(&g_object, g_repo, &oid, GIT_OBJ_ANY)); cl_git_fail(git_checkout_tree(g_repo, g_object, &opts)); opts.target_directory = "alternative"; cl_assert(!git_path_isdir("alternative")); cl_git_pass(git_checkout_tree(g_repo, g_object, &opts)); cl_assert_equal_i(0, cts.n_untracked); cl_assert_equal_i(0, cts.n_ignored); cl_assert_equal_i(3, cts.n_updates); check_file_contents_nocr("./alternative/README", "hey there\n"); check_file_contents_nocr("./alternative/branch_file.txt", "hi\nbye!\n"); check_file_contents_nocr("./alternative/new.txt", "my new file\n"); cl_git_pass(git_futils_rmdir_r( "alternative", NULL, GIT_RMDIR_REMOVE_FILES)); } libgit2-0.19.0/tests-clar/checkout/typechange.c000066400000000000000000000145131216214232500213200ustar00rootroot00000000000000#include "clar_libgit2.h" #include "git2/checkout.h" #include "path.h" #include "posix.h" #include "fileops.h" static git_repository *g_repo = NULL; static const char *g_typechange_oids[] = { "79b9f23e85f55ea36a472a902e875bc1121a94cb", "9bdb75b73836a99e3dbeea640a81de81031fdc29", "0e7ed140b514b8cae23254cb8656fe1674403aff", "9d0235c7a7edc0889a18f97a42ee6db9fe688447", "9b19edf33a03a0c59cdfc113bfa5c06179bf9b1a", "1b63caae4a5ca96f78e8dfefc376c6a39a142475", "6eae26c90e8ccc4d16208972119c40635489c6f0", NULL }; static bool g_typechange_empty[] = { true, false, false, false, false, false, true, true }; void test_checkout_typechange__initialize(void) { g_repo = cl_git_sandbox_init("typechanges"); cl_fixture_sandbox("submod2_target"); p_rename("submod2_target/.gitted", "submod2_target/.git"); } void test_checkout_typechange__cleanup(void) { cl_git_sandbox_cleanup(); cl_fixture_cleanup("submod2_target"); } static void assert_file_exists(const char *path) { cl_assert_(git_path_isfile(path), path); } static void assert_dir_exists(const char *path) { cl_assert_(git_path_isdir(path), path); } static void assert_workdir_matches_tree( git_repository *repo, const git_oid *id, const char *root, bool recurse) { git_object *obj; git_tree *tree; size_t i, max_i; git_buf path = GIT_BUF_INIT; if (!root) root = git_repository_workdir(repo); cl_assert(root); cl_git_pass(git_object_lookup(&obj, repo, id, GIT_OBJ_ANY)); cl_git_pass(git_object_peel((git_object **)&tree, obj, GIT_OBJ_TREE)); git_object_free(obj); max_i = git_tree_entrycount(tree); for (i = 0; i < max_i; ++i) { const git_tree_entry *te = git_tree_entry_byindex(tree, i); cl_assert(te); cl_git_pass(git_buf_joinpath(&path, root, git_tree_entry_name(te))); switch (git_tree_entry_type(te)) { case GIT_OBJ_COMMIT: assert_dir_exists(path.ptr); break; case GIT_OBJ_TREE: assert_dir_exists(path.ptr); if (recurse) assert_workdir_matches_tree( repo, git_tree_entry_id(te), path.ptr, true); break; case GIT_OBJ_BLOB: switch (git_tree_entry_filemode(te)) { case GIT_FILEMODE_BLOB: case GIT_FILEMODE_BLOB_EXECUTABLE: assert_file_exists(path.ptr); /* because of cross-platform, don't confirm exec bit yet */ break; case GIT_FILEMODE_LINK: cl_assert_(git_path_exists(path.ptr), path.ptr); /* because of cross-platform, don't confirm link yet */ break; default: cl_assert(false); /* really?! */ } break; default: cl_assert(false); /* really?!! */ } } git_tree_free(tree); git_buf_free(&path); } void test_checkout_typechange__checkout_typechanges_safe(void) { int i; git_object *obj; git_checkout_opts opts = GIT_CHECKOUT_OPTS_INIT; for (i = 0; g_typechange_oids[i] != NULL; ++i) { cl_git_pass(git_revparse_single(&obj, g_repo, g_typechange_oids[i])); opts.checkout_strategy = GIT_CHECKOUT_FORCE; /* There are bugs in some submodule->tree changes that prevent * SAFE from passing here, even though the following should work: */ /* !i ? GIT_CHECKOUT_FORCE : GIT_CHECKOUT_SAFE; */ cl_git_pass(git_checkout_tree(g_repo, obj, &opts)); cl_git_pass( git_repository_set_head_detached(g_repo, git_object_id(obj))); assert_workdir_matches_tree(g_repo, git_object_id(obj), NULL, true); git_object_free(obj); if (!g_typechange_empty[i]) { cl_assert(git_path_isdir("typechanges")); cl_assert(git_path_exists("typechanges/a")); cl_assert(git_path_exists("typechanges/b")); cl_assert(git_path_exists("typechanges/c")); cl_assert(git_path_exists("typechanges/d")); cl_assert(git_path_exists("typechanges/e")); } else { cl_assert(git_path_isdir("typechanges")); cl_assert(!git_path_exists("typechanges/a")); cl_assert(!git_path_exists("typechanges/b")); cl_assert(!git_path_exists("typechanges/c")); cl_assert(!git_path_exists("typechanges/d")); cl_assert(!git_path_exists("typechanges/e")); } } } typedef struct { int conflicts; int dirty; int updates; int untracked; int ignored; } notify_counts; static int notify_counter( git_checkout_notify_t why, const char *path, const git_diff_file *baseline, const git_diff_file *target, const git_diff_file *workdir, void *payload) { notify_counts *cts = payload; GIT_UNUSED(path); GIT_UNUSED(baseline); GIT_UNUSED(target); GIT_UNUSED(workdir); switch (why) { case GIT_CHECKOUT_NOTIFY_CONFLICT: cts->conflicts++; break; case GIT_CHECKOUT_NOTIFY_DIRTY: cts->dirty++; break; case GIT_CHECKOUT_NOTIFY_UPDATED: cts->updates++; break; case GIT_CHECKOUT_NOTIFY_UNTRACKED: cts->untracked++; break; case GIT_CHECKOUT_NOTIFY_IGNORED: cts->ignored++; break; default: break; } return 0; } static void force_create_file(const char *file) { int error = git_futils_rmdir_r(file, NULL, GIT_RMDIR_REMOVE_FILES | GIT_RMDIR_REMOVE_BLOCKERS); cl_assert(!error || error == GIT_ENOTFOUND); cl_git_pass(git_futils_mkpath2file(file, 0777)); cl_git_rewritefile(file, "yowza!!"); } void test_checkout_typechange__checkout_with_conflicts(void) { int i; git_object *obj; git_checkout_opts opts = GIT_CHECKOUT_OPTS_INIT; notify_counts cts = {0}; opts.notify_flags = GIT_CHECKOUT_NOTIFY_CONFLICT | GIT_CHECKOUT_NOTIFY_UNTRACKED; opts.notify_cb = notify_counter; opts.notify_payload = &cts; for (i = 0; g_typechange_oids[i] != NULL; ++i) { cl_git_pass(git_revparse_single(&obj, g_repo, g_typechange_oids[i])); force_create_file("typechanges/a/blocker"); force_create_file("typechanges/b"); force_create_file("typechanges/c/sub/sub/file"); git_futils_rmdir_r("typechanges/d", NULL, GIT_RMDIR_REMOVE_FILES); p_mkdir("typechanges/d", 0777); /* intentionally empty dir */ force_create_file("typechanges/untracked"); opts.checkout_strategy = GIT_CHECKOUT_SAFE_CREATE; memset(&cts, 0, sizeof(cts)); cl_git_fail(git_checkout_tree(g_repo, obj, &opts)); cl_assert(cts.conflicts > 0); cl_assert(cts.untracked > 0); opts.checkout_strategy = GIT_CHECKOUT_FORCE | GIT_CHECKOUT_REMOVE_UNTRACKED; memset(&cts, 0, sizeof(cts)); cl_assert(git_path_exists("typechanges/untracked")); cl_git_pass(git_checkout_tree(g_repo, obj, &opts)); cl_assert_equal_i(0, cts.conflicts); cl_assert(!git_path_exists("typechanges/untracked")); cl_git_pass( git_repository_set_head_detached(g_repo, git_object_id(obj))); assert_workdir_matches_tree(g_repo, git_object_id(obj), NULL, true); git_object_free(obj); } } libgit2-0.19.0/tests-clar/clar.c000066400000000000000000000225701216214232500163070ustar00rootroot00000000000000/* * Copyright (c) Vicent Marti. All rights reserved. * * This file is part of clar, distributed under the ISC license. * For full terms see the included COPYING file. */ #include #include #include #include #include #include #include /* required for sandboxing */ #include #include #ifdef _WIN32 # include # include # include # include # define _MAIN_CC __cdecl # define stat(path, st) _stat(path, st) # define mkdir(path, mode) _mkdir(path) # define chdir(path) _chdir(path) # define access(path, mode) _access(path, mode) # define strdup(str) _strdup(str) # define strcasecmp(a,b) _stricmp(a,b) # ifndef __MINGW32__ # pragma comment(lib, "shell32") # define strncpy(to, from, to_size) strncpy_s(to, to_size, from, _TRUNCATE) # define W_OK 02 # define S_ISDIR(x) ((x & _S_IFDIR) != 0) # define snprint_eq(buf,sz,fmt,a,b) _snprintf_s(buf,sz,_TRUNCATE,fmt,a,b) # else # define snprint_eq snprintf # endif typedef struct _stat STAT_T; #else # include /* waitpid(2) */ # include # define _MAIN_CC # define snprint_eq snprintf typedef struct stat STAT_T; #endif #include "clar.h" static void fs_rm(const char *_source); static void fs_copy(const char *_source, const char *dest); static const char * fixture_path(const char *base, const char *fixture_name); struct clar_error { const char *test; int test_number; const char *suite; const char *file; int line_number; const char *error_msg; char *description; struct clar_error *next; }; static struct { const char *active_test; const char *active_suite; int suite_errors; int total_errors; int tests_ran; int suites_ran; int report_errors_only; int exit_on_error; int report_suite_names; struct clar_error *errors; struct clar_error *last_error; void (*local_cleanup)(void *); void *local_cleanup_payload; jmp_buf trampoline; int trampoline_enabled; } _clar; struct clar_func { const char *name; void (*ptr)(void); }; struct clar_suite { const char *name; struct clar_func initialize; struct clar_func cleanup; const struct clar_func *tests; size_t test_count; int enabled; }; /* From clar_print_*.c */ static void clar_print_init(int test_count, int suite_count, const char *suite_names); static void clar_print_shutdown(int test_count, int suite_count, int error_count); static void clar_print_error(int num, const struct clar_error *error); static void clar_print_ontest(const char *test_name, int test_number, int failed); static void clar_print_onsuite(const char *suite_name, int suite_index); static void clar_print_onabort(const char *msg, ...); /* From clar_sandbox.c */ static void clar_unsandbox(void); static int clar_sandbox(void); /* Load the declarations for the test suite */ #include "clar.suite" /* Core test functions */ static void clar_report_errors(void) { int i = 1; struct clar_error *error, *next; error = _clar.errors; while (error != NULL) { next = error->next; clar_print_error(i++, error); free(error->description); free(error); error = next; } _clar.errors = _clar.last_error = NULL; } static void clar_run_test( const struct clar_func *test, const struct clar_func *initialize, const struct clar_func *cleanup) { int error_st = _clar.suite_errors; _clar.trampoline_enabled = 1; if (setjmp(_clar.trampoline) == 0) { if (initialize->ptr != NULL) initialize->ptr(); test->ptr(); } _clar.trampoline_enabled = 0; if (_clar.local_cleanup != NULL) _clar.local_cleanup(_clar.local_cleanup_payload); if (cleanup->ptr != NULL) cleanup->ptr(); _clar.tests_ran++; /* remove any local-set cleanup methods */ _clar.local_cleanup = NULL; _clar.local_cleanup_payload = NULL; if (_clar.report_errors_only) clar_report_errors(); else clar_print_ontest( test->name, _clar.tests_ran, (_clar.suite_errors > error_st) ); } static void clar_run_suite(const struct clar_suite *suite, const char *filter) { const struct clar_func *test = suite->tests; size_t i, matchlen; if (!suite->enabled) return; if (_clar.exit_on_error && _clar.total_errors) return; if (!_clar.report_errors_only) clar_print_onsuite(suite->name, ++_clar.suites_ran); _clar.active_suite = suite->name; _clar.suite_errors = 0; if (filter) { size_t suitelen = strlen(suite->name); matchlen = strlen(filter); if (matchlen <= suitelen) { filter = NULL; } else { filter += suitelen; while (*filter == ':') ++filter; matchlen = strlen(filter); } } for (i = 0; i < suite->test_count; ++i) { if (filter && strncmp(test[i].name, filter, matchlen)) continue; _clar.active_test = test[i].name; clar_run_test(&test[i], &suite->initialize, &suite->cleanup); if (_clar.exit_on_error && _clar.total_errors) return; } } static void clar_usage(const char *arg) { printf("Usage: %s [options]\n\n", arg); printf("Options:\n"); printf(" -sname\tRun only the suite with `name` (can go to individual test name)\n"); printf(" -iname\tInclude the suite with `name`\n"); printf(" -xname\tExclude the suite with `name`\n"); printf(" -q \tOnly report tests that had an error\n"); printf(" -Q \tQuit as soon as a test fails\n"); printf(" -l \tPrint suite names\n"); exit(-1); } static void clar_parse_args(int argc, char **argv) { int i; for (i = 1; i < argc; ++i) { char *argument = argv[i]; if (argument[0] != '-') clar_usage(argv[0]); switch (argument[1]) { case 's': case 'i': case 'x': { /* given suite name */ int offset = (argument[2] == '=') ? 3 : 2, found = 0; char action = argument[1]; size_t j, arglen, suitelen, cmplen; argument += offset; arglen = strlen(argument); if (arglen == 0) clar_usage(argv[0]); for (j = 0; j < _clar_suite_count; ++j) { suitelen = strlen(_clar_suites[j].name); cmplen = (arglen < suitelen) ? arglen : suitelen; if (strncmp(argument, _clar_suites[j].name, cmplen) == 0) { int exact = (arglen >= suitelen); ++found; if (!exact) _clar.report_suite_names = 1; switch (action) { case 's': clar_run_suite(&_clar_suites[j], argument); break; case 'i': _clar_suites[j].enabled = 1; break; case 'x': _clar_suites[j].enabled = 0; break; } if (exact) break; } } if (!found) { clar_print_onabort("No suite matching '%s' found.\n", argument); exit(-1); } break; } case 'q': _clar.report_errors_only = 1; break; case 'Q': _clar.exit_on_error = 1; break; case 'l': { size_t j; printf("Test suites (use -s to run just one):\n"); for (j = 0; j < _clar_suite_count; ++j) printf(" %3d: %s\n", (int)j, _clar_suites[j].name); exit(0); } default: clar_usage(argv[0]); } } } int clar_test(int argc, char **argv) { clar_print_init( (int)_clar_callback_count, (int)_clar_suite_count, "" ); if (clar_sandbox() < 0) { clar_print_onabort("Failed to sandbox the test runner.\n"); exit(-1); } if (argc > 1) clar_parse_args(argc, argv); if (!_clar.suites_ran) { size_t i; for (i = 0; i < _clar_suite_count; ++i) clar_run_suite(&_clar_suites[i], NULL); } clar_print_shutdown( _clar.tests_ran, (int)_clar_suite_count, _clar.total_errors ); clar_unsandbox(); return _clar.total_errors; } void clar__fail( const char *file, int line, const char *error_msg, const char *description, int should_abort) { struct clar_error *error = calloc(1, sizeof(struct clar_error)); if (_clar.errors == NULL) _clar.errors = error; if (_clar.last_error != NULL) _clar.last_error->next = error; _clar.last_error = error; error->test = _clar.active_test; error->test_number = _clar.tests_ran; error->suite = _clar.active_suite; error->file = file; error->line_number = line; error->error_msg = error_msg; if (description != NULL) error->description = strdup(description); _clar.suite_errors++; _clar.total_errors++; if (should_abort) { if (!_clar.trampoline_enabled) { clar_print_onabort( "Fatal error: a cleanup method raised an exception."); clar_report_errors(); exit(-1); } longjmp(_clar.trampoline, -1); } } void clar__assert( int condition, const char *file, int line, const char *error_msg, const char *description, int should_abort) { if (condition) return; clar__fail(file, line, error_msg, description, should_abort); } void clar__assert_equal_s( const char *s1, const char *s2, const char *file, int line, const char *err, int should_abort) { int match = (s1 == NULL || s2 == NULL) ? (s1 == s2) : (strcmp(s1, s2) == 0); if (!match) { char buf[4096]; if (s1 && s2) { int pos; for (pos = 0; s1[pos] == s2[pos] && s1[pos] && s2[pos]; ++pos) /* find differing byte offset */; snprint_eq(buf, sizeof(buf), "'%s' != '%s' (at byte %d)", s1, s2, pos); } else { snprint_eq(buf, sizeof(buf), "'%s' != '%s'", s1, s2); } clar__fail(file, line, err, buf, should_abort); } } void clar__assert_equal_i( int i1, int i2, const char *file, int line, const char *err, int should_abort) { if (i1 != i2) { char buf[128]; snprint_eq(buf, sizeof(buf), "%d != %d", i1, i2); clar__fail(file, line, err, buf, should_abort); } } void cl_set_cleanup(void (*cleanup)(void *), void *opaque) { _clar.local_cleanup = cleanup; _clar.local_cleanup_payload = opaque; } #include "clar/sandbox.h" #include "clar/fixtures.h" #include "clar/fs.h" #include "clar/print.h" libgit2-0.19.0/tests-clar/clar.h000066400000000000000000000060671216214232500163170ustar00rootroot00000000000000/* * Copyright (c) Vicent Marti. All rights reserved. * * This file is part of clar, distributed under the ISC license. * For full terms see the included COPYING file. */ #ifndef __CLAR_TEST_H__ #define __CLAR_TEST_H__ #include int clar_test(int argc, char *argv[]); void cl_set_cleanup(void (*cleanup)(void *), void *opaque); void cl_fs_cleanup(void); #ifdef CLAR_FIXTURE_PATH const char *cl_fixture(const char *fixture_name); void cl_fixture_sandbox(const char *fixture_name); void cl_fixture_cleanup(const char *fixture_name); #endif /** * Assertion macros with explicit error message */ #define cl_must_pass_(expr, desc) clar__assert((expr) >= 0, __FILE__, __LINE__, "Function call failed: " #expr, desc, 1) #define cl_must_fail_(expr, desc) clar__assert((expr) < 0, __FILE__, __LINE__, "Expected function call to fail: " #expr, desc, 1) #define cl_assert_(expr, desc) clar__assert((expr) != 0, __FILE__, __LINE__, "Expression is not true: " #expr, desc, 1) /** * Check macros with explicit error message */ #define cl_check_pass_(expr, desc) clar__assert((expr) >= 0, __FILE__, __LINE__, "Function call failed: " #expr, desc, 0) #define cl_check_fail_(expr, desc) clar__assert((expr) < 0, __FILE__, __LINE__, "Expected function call to fail: " #expr, desc, 0) #define cl_check_(expr, desc) clar__assert((expr) != 0, __FILE__, __LINE__, "Expression is not true: " #expr, desc, 0) /** * Assertion macros with no error message */ #define cl_must_pass(expr) cl_must_pass_(expr, NULL) #define cl_must_fail(expr) cl_must_fail_(expr, NULL) #define cl_assert(expr) cl_assert_(expr, NULL) /** * Check macros with no error message */ #define cl_check_pass(expr) cl_check_pass_(expr, NULL) #define cl_check_fail(expr) cl_check_fail_(expr, NULL) #define cl_check(expr) cl_check_(expr, NULL) /** * Forced failure/warning */ #define cl_fail(desc) clar__fail(__FILE__, __LINE__, "Test failed.", desc, 1) #define cl_warning(desc) clar__fail(__FILE__, __LINE__, "Warning during test execution:", desc, 0) /** * Typed assertion macros */ #define cl_assert_equal_s(s1,s2) clar__assert_equal_s((s1),(s2),__FILE__,__LINE__,"String mismatch: " #s1 " != " #s2, 1) #define cl_assert_equal_s_(s1,s2,note) clar__assert_equal_s((s1),(s2),__FILE__,__LINE__,"String mismatch: " #s1 " != " #s2 " (" #note ")", 1) #define cl_assert_equal_i(i1,i2) clar__assert_equal_i((i1),(i2),__FILE__,__LINE__,#i1 " != " #i2, 1) #define cl_assert_equal_i_(i1,i2,note) clar__assert_equal_i((i1),(i2),__FILE__,__LINE__,#i1 " != " #i2 " (" #note ")", 1) #define cl_assert_equal_b(b1,b2) clar__assert_equal_i(!!(b1),!!(b2),__FILE__,__LINE__,#b1 " != " #b2, 1) #define cl_assert_equal_p(p1,p2) cl_assert((p1) == (p2)) void clar__fail( const char *file, int line, const char *error, const char *description, int should_abort); void clar__assert( int condition, const char *file, int line, const char *error, const char *description, int should_abort); void clar__assert_equal_s(const char *,const char *,const char *,int,const char *,int); void clar__assert_equal_i(int,int,const char *,int,const char *,int); #endif libgit2-0.19.0/tests-clar/clar/000077500000000000000000000000001216214232500161355ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/clar/fixtures.h000066400000000000000000000013371216214232500201630ustar00rootroot00000000000000static const char * fixture_path(const char *base, const char *fixture_name) { static char _path[4096]; size_t root_len; root_len = strlen(base); strncpy(_path, base, sizeof(_path)); if (_path[root_len - 1] != '/') _path[root_len++] = '/'; if (fixture_name[0] == '/') fixture_name++; strncpy(_path + root_len, fixture_name, sizeof(_path) - root_len); return _path; } #ifdef CLAR_FIXTURE_PATH const char *cl_fixture(const char *fixture_name) { return fixture_path(CLAR_FIXTURE_PATH, fixture_name); } void cl_fixture_sandbox(const char *fixture_name) { fs_copy(cl_fixture(fixture_name), _clar_path); } void cl_fixture_cleanup(const char *fixture_name) { fs_rm(fixture_path(_clar_path, fixture_name)); } #endif libgit2-0.19.0/tests-clar/clar/fs.h000066400000000000000000000166201216214232500167230ustar00rootroot00000000000000#ifdef _WIN32 #define RM_RETRY_COUNT 5 #define RM_RETRY_DELAY 10 #ifdef __MINGW32__ /* These security-enhanced functions are not available * in MinGW, so just use the vanilla ones */ #define wcscpy_s(a, b, c) wcscpy((a), (c)) #define wcscat_s(a, b, c) wcscat((a), (c)) #endif /* __MINGW32__ */ static int fs__dotordotdot(WCHAR *_tocheck) { return _tocheck[0] == '.' && (_tocheck[1] == '\0' || (_tocheck[1] == '.' && _tocheck[2] == '\0')); } static int fs_rmdir_rmdir(WCHAR *_wpath) { unsigned retries = 1; while (!RemoveDirectoryW(_wpath)) { /* Only retry when we have retries remaining, and the * error was ERROR_DIR_NOT_EMPTY. */ if (retries++ > RM_RETRY_COUNT || ERROR_DIR_NOT_EMPTY != GetLastError()) return -1; /* Give whatever has a handle to a child item some time * to release it before trying again */ Sleep(RM_RETRY_DELAY * retries * retries); } return 0; } static void fs_rmdir_helper(WCHAR *_wsource) { WCHAR buffer[MAX_PATH]; HANDLE find_handle; WIN32_FIND_DATAW find_data; size_t buffer_prefix_len; /* Set up the buffer and capture the length */ wcscpy_s(buffer, MAX_PATH, _wsource); wcscat_s(buffer, MAX_PATH, L"\\"); buffer_prefix_len = wcslen(buffer); /* FindFirstFile needs a wildcard to match multiple items */ wcscat_s(buffer, MAX_PATH, L"*"); find_handle = FindFirstFileW(buffer, &find_data); cl_assert(INVALID_HANDLE_VALUE != find_handle); do { /* FindFirstFile/FindNextFile gives back . and .. * entries at the beginning */ if (fs__dotordotdot(find_data.cFileName)) continue; wcscpy_s(buffer + buffer_prefix_len, MAX_PATH - buffer_prefix_len, find_data.cFileName); if (FILE_ATTRIBUTE_DIRECTORY & find_data.dwFileAttributes) fs_rmdir_helper(buffer); else { /* If set, the +R bit must be cleared before deleting */ if (FILE_ATTRIBUTE_READONLY & find_data.dwFileAttributes) cl_assert(SetFileAttributesW(buffer, find_data.dwFileAttributes & ~FILE_ATTRIBUTE_READONLY)); cl_assert(DeleteFileW(buffer)); } } while (FindNextFileW(find_handle, &find_data)); /* Ensure that we successfully completed the enumeration */ cl_assert(ERROR_NO_MORE_FILES == GetLastError()); /* Close the find handle */ FindClose(find_handle); /* Now that the directory is empty, remove it */ cl_assert(0 == fs_rmdir_rmdir(_wsource)); } static int fs_rm_wait(WCHAR *_wpath) { unsigned retries = 1; DWORD last_error; do { if (INVALID_FILE_ATTRIBUTES == GetFileAttributesW(_wpath)) last_error = GetLastError(); else last_error = ERROR_SUCCESS; /* Is the item gone? */ if (ERROR_FILE_NOT_FOUND == last_error || ERROR_PATH_NOT_FOUND == last_error) return 0; Sleep(RM_RETRY_DELAY * retries * retries); } while (retries++ <= RM_RETRY_COUNT); return -1; } static void fs_rm(const char *_source) { WCHAR wsource[MAX_PATH]; DWORD attrs; /* The input path is UTF-8. Convert it to wide characters * for use with the Windows API */ cl_assert(MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, _source, -1, /* Indicates NULL termination */ wsource, MAX_PATH)); /* Does the item exist? If not, we have no work to do */ attrs = GetFileAttributesW(wsource); if (INVALID_FILE_ATTRIBUTES == attrs) return; if (FILE_ATTRIBUTE_DIRECTORY & attrs) fs_rmdir_helper(wsource); else { /* The item is a file. Strip the +R bit */ if (FILE_ATTRIBUTE_READONLY & attrs) cl_assert(SetFileAttributesW(wsource, attrs & ~FILE_ATTRIBUTE_READONLY)); cl_assert(DeleteFileW(wsource)); } /* Wait for the DeleteFile or RemoveDirectory call to complete */ cl_assert(0 == fs_rm_wait(wsource)); } static void fs_copydir_helper(WCHAR *_wsource, WCHAR *_wdest) { WCHAR buf_source[MAX_PATH], buf_dest[MAX_PATH]; HANDLE find_handle; WIN32_FIND_DATAW find_data; size_t buf_source_prefix_len, buf_dest_prefix_len; wcscpy_s(buf_source, MAX_PATH, _wsource); wcscat_s(buf_source, MAX_PATH, L"\\"); buf_source_prefix_len = wcslen(buf_source); wcscpy_s(buf_dest, MAX_PATH, _wdest); wcscat_s(buf_dest, MAX_PATH, L"\\"); buf_dest_prefix_len = wcslen(buf_dest); /* Get an enumerator for the items in the source. */ wcscat_s(buf_source, MAX_PATH, L"*"); find_handle = FindFirstFileW(buf_source, &find_data); cl_assert(INVALID_HANDLE_VALUE != find_handle); /* Create the target directory. */ cl_assert(CreateDirectoryW(_wdest, NULL)); do { /* FindFirstFile/FindNextFile gives back . and .. * entries at the beginning */ if (fs__dotordotdot(find_data.cFileName)) continue; wcscpy_s(buf_source + buf_source_prefix_len, MAX_PATH - buf_source_prefix_len, find_data.cFileName); wcscpy_s(buf_dest + buf_dest_prefix_len, MAX_PATH - buf_dest_prefix_len, find_data.cFileName); if (FILE_ATTRIBUTE_DIRECTORY & find_data.dwFileAttributes) fs_copydir_helper(buf_source, buf_dest); else cl_assert(CopyFileW(buf_source, buf_dest, TRUE)); } while (FindNextFileW(find_handle, &find_data)); /* Ensure that we successfully completed the enumeration */ cl_assert(ERROR_NO_MORE_FILES == GetLastError()); /* Close the find handle */ FindClose(find_handle); } static void fs_copy(const char *_source, const char *_dest) { WCHAR wsource[MAX_PATH], wdest[MAX_PATH]; DWORD source_attrs, dest_attrs; HANDLE find_handle; WIN32_FIND_DATAW find_data; /* The input paths are UTF-8. Convert them to wide characters * for use with the Windows API. */ cl_assert(MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, _source, -1, wsource, MAX_PATH)); cl_assert(MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, _dest, -1, wdest, MAX_PATH)); /* Check the source for existence */ source_attrs = GetFileAttributesW(wsource); cl_assert(INVALID_FILE_ATTRIBUTES != source_attrs); /* Check the target for existence */ dest_attrs = GetFileAttributesW(wdest); if (INVALID_FILE_ATTRIBUTES != dest_attrs) { /* Target exists; append last path part of source to target. * Use FindFirstFile to parse the path */ find_handle = FindFirstFileW(wsource, &find_data); cl_assert(INVALID_HANDLE_VALUE != find_handle); wcscat_s(wdest, MAX_PATH, L"\\"); wcscat_s(wdest, MAX_PATH, find_data.cFileName); FindClose(find_handle); /* Check the new target for existence */ cl_assert(INVALID_FILE_ATTRIBUTES == GetFileAttributesW(wdest)); } if (FILE_ATTRIBUTE_DIRECTORY & source_attrs) fs_copydir_helper(wsource, wdest); else cl_assert(CopyFileW(wsource, wdest, TRUE)); } void cl_fs_cleanup(void) { fs_rm(fixture_path(_clar_path, "*")); } #else static int shell_out(char * const argv[]) { int status; pid_t pid; pid = fork(); if (pid < 0) { fprintf(stderr, "System error: `fork()` call failed.\n"); exit(-1); } if (pid == 0) { execv(argv[0], argv); } waitpid(pid, &status, 0); return WEXITSTATUS(status); } static void fs_copy(const char *_source, const char *dest) { char *argv[5]; char *source; size_t source_len; source = strdup(_source); source_len = strlen(source); if (source[source_len - 1] == '/') source[source_len - 1] = 0; argv[0] = "/bin/cp"; argv[1] = "-R"; argv[2] = source; argv[3] = (char *)dest; argv[4] = NULL; cl_must_pass_( shell_out(argv), "Failed to copy test fixtures to sandbox" ); free(source); } static void fs_rm(const char *source) { char *argv[4]; argv[0] = "/bin/rm"; argv[1] = "-Rf"; argv[2] = (char *)source; argv[3] = NULL; cl_must_pass_( shell_out(argv), "Failed to cleanup the sandbox" ); } void cl_fs_cleanup(void) { clar_unsandbox(); clar_sandbox(); } #endif libgit2-0.19.0/tests-clar/clar/print.h000066400000000000000000000022751216214232500174500ustar00rootroot00000000000000 static void clar_print_init(int test_count, int suite_count, const char *suite_names) { (void)test_count; printf("Loaded %d suites: %s\n", (int)suite_count, suite_names); printf("Started\n"); } static void clar_print_shutdown(int test_count, int suite_count, int error_count) { (void)test_count; (void)suite_count; (void)error_count; printf("\n\n"); clar_report_errors(); } static void clar_print_error(int num, const struct clar_error *error) { printf(" %d) Failure:\n", num); printf("%s::%s [%s:%d]\n", error->suite, error->test, error->file, error->line_number); printf(" %s\n", error->error_msg); if (error->description != NULL) printf(" %s\n", error->description); printf("\n"); fflush(stdout); } static void clar_print_ontest(const char *test_name, int test_number, int failed) { (void)test_name; (void)test_number; printf("%c", failed ? 'F' : '.'); fflush(stdout); } static void clar_print_onsuite(const char *suite_name, int suite_index) { if (_clar.report_suite_names) printf("\n%s", suite_name); (void)suite_index; } static void clar_print_onabort(const char *msg, ...) { va_list argp; va_start(argp, msg); vfprintf(stderr, msg, argp); va_end(argp); } libgit2-0.19.0/tests-clar/clar/sandbox.h000066400000000000000000000042571216214232500177540ustar00rootroot00000000000000static char _clar_path[4096]; static int is_valid_tmp_path(const char *path) { STAT_T st; if (stat(path, &st) != 0) return 0; if (!S_ISDIR(st.st_mode)) return 0; return (access(path, W_OK) == 0); } static int find_tmp_path(char *buffer, size_t length) { #ifndef _WIN32 static const size_t var_count = 5; static const char *env_vars[] = { "CLAR_TMP", "TMPDIR", "TMP", "TEMP", "USERPROFILE" }; size_t i; for (i = 0; i < var_count; ++i) { const char *env = getenv(env_vars[i]); if (!env) continue; if (is_valid_tmp_path(env)) { strncpy(buffer, env, length); return 0; } } /* If the environment doesn't say anything, try to use /tmp */ if (is_valid_tmp_path("/tmp")) { strncpy(buffer, "/tmp", length); return 0; } #else DWORD env_len; if ((env_len = GetEnvironmentVariable("CLAR_TMP", buffer, length)) > 0 && env_len < length) return 0; if (GetTempPath((DWORD)length, buffer)) return 0; #endif /* This system doesn't like us, try to use the current directory */ if (is_valid_tmp_path(".")) { strncpy(buffer, ".", length); return 0; } return -1; } static void clar_unsandbox(void) { if (_clar_path[0] == '\0') return; chdir(".."); fs_rm(_clar_path); } static int build_sandbox_path(void) { const char path_tail[] = "clar_tmp_XXXXXX"; size_t len; if (find_tmp_path(_clar_path, sizeof(_clar_path)) < 0) return -1; len = strlen(_clar_path); #ifdef _WIN32 { /* normalize path to POSIX forward slashes */ size_t i; for (i = 0; i < len; ++i) { if (_clar_path[i] == '\\') _clar_path[i] = '/'; } } #endif if (_clar_path[len - 1] != '/') { _clar_path[len++] = '/'; } strncpy(_clar_path + len, path_tail, sizeof(_clar_path) - len); #if defined(__MINGW32__) if (_mktemp(_clar_path) == NULL) return -1; if (mkdir(_clar_path, 0700) != 0) return -1; #elif defined(_WIN32) if (_mktemp_s(_clar_path, sizeof(_clar_path)) != 0) return -1; if (mkdir(_clar_path, 0700) != 0) return -1; #else if (mkdtemp(_clar_path) == NULL) return -1; #endif return 0; } static int clar_sandbox(void) { if (_clar_path[0] == '\0' && build_sandbox_path() < 0) return -1; if (chdir(_clar_path) != 0) return -1; return 0; } libgit2-0.19.0/tests-clar/clar_libgit2.c000066400000000000000000000204711216214232500177210ustar00rootroot00000000000000#include "clar_libgit2.h" #include "posix.h" #include "path.h" void cl_git_report_failure( int error, const char *file, int line, const char *fncall) { char msg[4096]; const git_error *last = giterr_last(); p_snprintf(msg, 4096, "error %d - %s", error, last ? last->message : ""); clar__assert(0, file, line, fncall, msg, 1); } void cl_git_mkfile(const char *filename, const char *content) { int fd; fd = p_creat(filename, 0666); cl_assert(fd != 0); if (content) { cl_must_pass(p_write(fd, content, strlen(content))); } else { cl_must_pass(p_write(fd, filename, strlen(filename))); cl_must_pass(p_write(fd, "\n", 1)); } cl_must_pass(p_close(fd)); } void cl_git_write2file( const char *filename, const char *new_content, int flags, unsigned int mode) { int fd = p_open(filename, flags, mode); cl_assert(fd >= 0); if (!new_content) new_content = "\n"; cl_must_pass(p_write(fd, new_content, strlen(new_content))); cl_must_pass(p_close(fd)); } void cl_git_append2file(const char *filename, const char *new_content) { cl_git_write2file(filename, new_content, O_WRONLY | O_CREAT | O_APPEND, 0644); } void cl_git_rewritefile(const char *filename, const char *new_content) { cl_git_write2file(filename, new_content, O_WRONLY | O_CREAT | O_TRUNC, 0644); } #ifdef GIT_WIN32 #include "win32/utf-conv.h" char *cl_getenv(const char *name) { wchar_t name_utf16[GIT_WIN_PATH]; DWORD alloc_len; wchar_t *value_utf16; char *value_utf8; git__utf8_to_16(name_utf16, GIT_WIN_PATH, name); alloc_len = GetEnvironmentVariableW(name_utf16, NULL, 0); if (alloc_len <= 0) return NULL; alloc_len = GIT_WIN_PATH; cl_assert(value_utf16 = git__calloc(alloc_len, sizeof(wchar_t))); GetEnvironmentVariableW(name_utf16, value_utf16, alloc_len); cl_assert(value_utf8 = git__malloc(alloc_len)); git__utf16_to_8(value_utf8, value_utf16); git__free(value_utf16); return value_utf8; } int cl_setenv(const char *name, const char *value) { wchar_t name_utf16[GIT_WIN_PATH]; wchar_t value_utf16[GIT_WIN_PATH]; git__utf8_to_16(name_utf16, GIT_WIN_PATH, name); if (value) { git__utf8_to_16(value_utf16, GIT_WIN_PATH, value); cl_assert(SetEnvironmentVariableW(name_utf16, value_utf16)); } else { /* Windows XP returns 0 (failed) when passing NULL for lpValue when * lpName does not exist in the environment block. This behavior * seems to have changed in later versions. Don't check return value * of SetEnvironmentVariable when passing NULL for lpValue. */ SetEnvironmentVariableW(name_utf16, NULL); } return 0; } /* This function performs retries on calls to MoveFile in order * to provide enhanced reliability in the face of antivirus * agents that may be scanning the source (or in the case that * the source is a directory, a child of the source). */ int cl_rename(const char *source, const char *dest) { wchar_t source_utf16[GIT_WIN_PATH]; wchar_t dest_utf16[GIT_WIN_PATH]; unsigned retries = 1; git__utf8_to_16(source_utf16, GIT_WIN_PATH, source); git__utf8_to_16(dest_utf16, GIT_WIN_PATH, dest); while (!MoveFileW(source_utf16, dest_utf16)) { /* Only retry if the error is ERROR_ACCESS_DENIED; * this may indicate that an antivirus agent is * preventing the rename from source to target */ if (retries > 5 || ERROR_ACCESS_DENIED != GetLastError()) return -1; /* With 5 retries and a coefficient of 10ms, the maximum * delay here is 550 ms */ Sleep(10 * retries * retries); retries++; } return 0; } #else #include char *cl_getenv(const char *name) { return getenv(name); } int cl_setenv(const char *name, const char *value) { return (value == NULL) ? unsetenv(name) : setenv(name, value, 1); } int cl_rename(const char *source, const char *dest) { return p_rename(source, dest); } #endif static const char *_cl_sandbox = NULL; static git_repository *_cl_repo = NULL; git_repository *cl_git_sandbox_init(const char *sandbox) { /* Copy the whole sandbox folder from our fixtures to our test sandbox * area. After this it can be accessed with `./sandbox` */ cl_fixture_sandbox(sandbox); _cl_sandbox = sandbox; cl_git_pass(p_chdir(sandbox)); /* If this is not a bare repo, then rename `sandbox/.gitted` to * `sandbox/.git` which must be done since we cannot store a folder * named `.git` inside the fixtures folder of our libgit2 repo. */ if (p_access(".gitted", F_OK) == 0) cl_git_pass(cl_rename(".gitted", ".git")); /* If we have `gitattributes`, rename to `.gitattributes`. This may * be necessary if we don't want the attributes to be applied in the * libgit2 repo, but just during testing. */ if (p_access("gitattributes", F_OK) == 0) cl_git_pass(cl_rename("gitattributes", ".gitattributes")); /* As with `gitattributes`, we may need `gitignore` just for testing. */ if (p_access("gitignore", F_OK) == 0) cl_git_pass(cl_rename("gitignore", ".gitignore")); cl_git_pass(p_chdir("..")); /* Now open the sandbox repository and make it available for tests */ cl_git_pass(git_repository_open(&_cl_repo, sandbox)); return _cl_repo; } git_repository *cl_git_sandbox_reopen(void) { if (_cl_repo) { git_repository_free(_cl_repo); _cl_repo = NULL; cl_git_pass(git_repository_open(&_cl_repo, _cl_sandbox)); } return _cl_repo; } void cl_git_sandbox_cleanup(void) { if (_cl_repo) { git_repository_free(_cl_repo); _cl_repo = NULL; } if (_cl_sandbox) { cl_fixture_cleanup(_cl_sandbox); _cl_sandbox = NULL; } } bool cl_toggle_filemode(const char *filename) { struct stat st1, st2; cl_must_pass(p_stat(filename, &st1)); cl_must_pass(p_chmod(filename, st1.st_mode ^ 0100)); cl_must_pass(p_stat(filename, &st2)); return (st1.st_mode != st2.st_mode); } bool cl_is_chmod_supported(void) { static int _is_supported = -1; if (_is_supported < 0) { cl_git_mkfile("filemode.t", "Test if filemode can be modified"); _is_supported = cl_toggle_filemode("filemode.t"); cl_must_pass(p_unlink("filemode.t")); } return _is_supported; } const char* cl_git_fixture_url(const char *fixturename) { return cl_git_path_url(cl_fixture(fixturename)); } const char* cl_git_path_url(const char *path) { static char url[4096]; const char *in_buf; git_buf path_buf = GIT_BUF_INIT; git_buf url_buf = GIT_BUF_INIT; cl_git_pass(git_path_prettify_dir(&path_buf, path, NULL)); cl_git_pass(git_buf_puts(&url_buf, "file://")); #ifdef GIT_WIN32 /* * A FILE uri matches the following format: file://[host]/path * where "host" can be empty and "path" is an absolute path to the resource. * * In this test, no hostname is used, but we have to ensure the leading triple slashes: * * *nix: file:///usr/home/... * Windows: file:///C:/Users/... */ cl_git_pass(git_buf_putc(&url_buf, '/')); #endif in_buf = git_buf_cstr(&path_buf); /* * A very hacky Url encoding that only takes care of escaping the spaces */ while (*in_buf) { if (*in_buf == ' ') cl_git_pass(git_buf_puts(&url_buf, "%20")); else cl_git_pass(git_buf_putc(&url_buf, *in_buf)); in_buf++; } strncpy(url, git_buf_cstr(&url_buf), 4096); git_buf_free(&url_buf); git_buf_free(&path_buf); return url; } typedef struct { const char *filename; size_t filename_len; } remove_data; static int remove_placeholders_recurs(void *_data, git_buf *path) { remove_data *data = (remove_data *)_data; size_t pathlen; if (git_path_isdir(path->ptr) == true) return git_path_direach(path, remove_placeholders_recurs, data); pathlen = path->size; if (pathlen < data->filename_len) return 0; /* if path ends in '/'+filename (or equals filename) */ if (!strcmp(data->filename, path->ptr + pathlen - data->filename_len) && (pathlen == data->filename_len || path->ptr[pathlen - data->filename_len - 1] == '/')) return p_unlink(path->ptr); return 0; } int cl_git_remove_placeholders(const char *directory_path, const char *filename) { int error; remove_data data; git_buf buffer = GIT_BUF_INIT; if (git_path_isdir(directory_path) == false) return -1; if (git_buf_sets(&buffer, directory_path) < 0) return -1; data.filename = filename; data.filename_len = strlen(filename); error = remove_placeholders_recurs(&data, &buffer); git_buf_free(&buffer); return error; } void cl_repo_set_bool(git_repository *repo, const char *cfg, int value) { git_config *config; cl_git_pass(git_repository_config(&config, repo)); cl_git_pass(git_config_set_bool(config, cfg, value != 0)); git_config_free(config); } libgit2-0.19.0/tests-clar/clar_libgit2.h000066400000000000000000000044311216214232500177240ustar00rootroot00000000000000#ifndef __CLAR_LIBGIT2__ #define __CLAR_LIBGIT2__ #include "clar.h" #include #include "common.h" /** * Replace for `clar_must_pass` that passes the last library error as the * test failure message. * * Use this wrapper around all `git_` library calls that return error codes! */ #define cl_git_pass(expr) do { \ int _lg2_error; \ giterr_clear(); \ if ((_lg2_error = (expr)) != 0) \ cl_git_report_failure(_lg2_error, __FILE__, __LINE__, "Function call failed: " #expr); \ } while (0) /** * Wrapper for `clar_must_fail` -- this one is * just for consistency. Use with `git_` library * calls that are supposed to fail! */ #define cl_git_fail(expr) cl_must_fail(expr) #define cl_git_fail_with(expr, error) cl_assert_equal_i(error,expr) void cl_git_report_failure(int, const char *, int, const char *); #define cl_assert_equal_sz(sz1,sz2) cl_assert_equal_i((int)sz1, (int)(sz2)) /* * Some utility macros for building long strings */ #define REP4(STR) STR STR STR STR #define REP15(STR) REP4(STR) REP4(STR) REP4(STR) STR STR STR #define REP16(STR) REP4(REP4(STR)) #define REP256(STR) REP16(REP16(STR)) #define REP1024(STR) REP4(REP256(STR)) /* Write the contents of a buffer to disk */ void cl_git_mkfile(const char *filename, const char *content); void cl_git_append2file(const char *filename, const char *new_content); void cl_git_rewritefile(const char *filename, const char *new_content); void cl_git_write2file(const char *filename, const char *new_content, int flags, unsigned int mode); bool cl_toggle_filemode(const char *filename); bool cl_is_chmod_supported(void); /* Environment wrappers */ char *cl_getenv(const char *name); int cl_setenv(const char *name, const char *value); /* Reliable rename */ int cl_rename(const char *source, const char *dest); /* Git sandbox setup helpers */ git_repository *cl_git_sandbox_init(const char *sandbox); void cl_git_sandbox_cleanup(void); git_repository *cl_git_sandbox_reopen(void); /* Local-repo url helpers */ const char* cl_git_fixture_url(const char *fixturename); const char* cl_git_path_url(const char *path); /* Test repository cleaner */ int cl_git_remove_placeholders(const char *directory_path, const char *filename); /* config setting helpers */ void cl_repo_set_bool(git_repository *repo, const char *cfg, int value); #endif libgit2-0.19.0/tests-clar/clone/000077500000000000000000000000001216214232500163145ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/clone/empty.c000066400000000000000000000047141216214232500176240ustar00rootroot00000000000000#include "clar_libgit2.h" #include "git2/clone.h" #include "repository.h" static git_clone_options g_options; static git_repository *g_repo; static git_repository *g_repo_cloned; void test_clone_empty__initialize(void) { git_repository *sandbox = cl_git_sandbox_init("empty_bare.git"); cl_git_remove_placeholders(git_repository_path(sandbox), "dummy-marker.txt"); g_repo = NULL; memset(&g_options, 0, sizeof(git_clone_options)); g_options.version = GIT_CLONE_OPTIONS_VERSION; } void test_clone_empty__cleanup(void) { cl_git_sandbox_cleanup(); } static void cleanup_repository(void *path) { cl_fixture_cleanup((const char *)path); git_repository_free(g_repo_cloned); g_repo_cloned = NULL; } void test_clone_empty__can_clone_an_empty_local_repo_barely(void) { char *local_name = "refs/heads/master"; const char *expected_tracked_branch_name = "refs/remotes/origin/master"; const char *expected_remote_name = "origin"; char buffer[1024]; git_reference *ref; cl_set_cleanup(&cleanup_repository, "./empty"); g_options.bare = true; cl_git_pass(git_clone(&g_repo_cloned, "./empty_bare.git", "./empty", &g_options)); /* Although the HEAD is orphaned... */ cl_assert_equal_i(GIT_ENOTFOUND, git_reference_lookup(&ref, g_repo_cloned, local_name)); /* ...one can still retrieve the name of the remote tracking reference */ cl_assert_equal_i((int)strlen(expected_tracked_branch_name) + 1, git_branch_upstream_name(buffer, 1024, g_repo_cloned, local_name)); cl_assert_equal_s(expected_tracked_branch_name, buffer); /* ...and the name of the remote... */ cl_assert_equal_i((int)strlen(expected_remote_name) + 1, git_branch_remote_name(buffer, 1024, g_repo_cloned, expected_tracked_branch_name)); cl_assert_equal_s(expected_remote_name, buffer); /* ...even when the remote HEAD is orphaned as well */ cl_assert_equal_i(GIT_ENOTFOUND, git_reference_lookup(&ref, g_repo_cloned, expected_tracked_branch_name)); } void test_clone_empty__can_clone_an_empty_local_repo(void) { cl_set_cleanup(&cleanup_repository, "./empty"); cl_git_pass(git_clone(&g_repo_cloned, "./empty_bare.git", "./empty", &g_options)); } void test_clone_empty__can_clone_an_empty_standard_repo(void) { cl_git_sandbox_cleanup(); g_repo = cl_git_sandbox_init("empty_standard_repo"); cl_git_remove_placeholders(git_repository_path(g_repo), "dummy-marker.txt"); cl_set_cleanup(&cleanup_repository, "./empty"); cl_git_pass(git_clone(&g_repo_cloned, "./empty_standard_repo", "./empty", &g_options)); } libgit2-0.19.0/tests-clar/clone/nonetwork.c000066400000000000000000000165471216214232500205230ustar00rootroot00000000000000#include "clar_libgit2.h" #include "git2/clone.h" #include "remote.h" #include "fileops.h" #include "repository.h" #define LIVE_REPO_URL "git://github.com/libgit2/TestGitRepository" static git_clone_options g_options; static git_repository *g_repo; static git_reference* g_ref; static git_remote* g_remote; void test_clone_nonetwork__initialize(void) { git_checkout_opts dummy_opts = GIT_CHECKOUT_OPTS_INIT; g_repo = NULL; memset(&g_options, 0, sizeof(git_clone_options)); g_options.version = GIT_CLONE_OPTIONS_VERSION; g_options.checkout_opts = dummy_opts; g_options.checkout_opts.checkout_strategy = GIT_CHECKOUT_SAFE; } void test_clone_nonetwork__cleanup(void) { if (g_repo) { git_repository_free(g_repo); g_repo = NULL; } if (g_ref) { git_reference_free(g_ref); g_ref = NULL; } if (g_remote) { git_remote_free(g_remote); g_remote = NULL; } cl_fixture_cleanup("./foo"); } void test_clone_nonetwork__bad_url(void) { /* Clone should clean up the mess if the URL isn't a git repository */ cl_git_fail(git_clone(&g_repo, "not_a_repo", "./foo", &g_options)); cl_assert(!git_path_exists("./foo")); g_options.bare = true; cl_git_fail(git_clone(&g_repo, "not_a_repo", "./foo", &g_options)); cl_assert(!git_path_exists("./foo")); } static int dont_call_me(void *state, git_buf *path) { GIT_UNUSED(state); GIT_UNUSED(path); return GIT_ERROR; } void test_clone_nonetwork__do_not_clean_existing_directory(void) { git_buf path_buf = GIT_BUF_INIT; git_buf_put(&path_buf, "./foo", 5); /* Clone should not remove the directory if it already exists, but * Should clean up entries it creates. */ p_mkdir("./foo", GIT_DIR_MODE); cl_git_fail(git_clone(&g_repo, "not_a_repo", "./foo", &g_options)); cl_assert(git_path_exists("./foo")); /* Make sure the directory is empty. */ cl_git_pass(git_path_direach(&path_buf, dont_call_me, NULL)); /* Try again with a bare repository. */ g_options.bare = true; cl_git_fail(git_clone(&g_repo, "not_a_repo", "./foo", &g_options)); cl_assert(git_path_exists("./foo")); /* Make sure the directory is empty. */ cl_git_pass(git_path_direach(&path_buf, dont_call_me, NULL)); git_buf_free(&path_buf); } void test_clone_nonetwork__local(void) { cl_git_pass(git_clone(&g_repo, cl_git_fixture_url("testrepo.git"), "./foo", &g_options)); } void test_clone_nonetwork__local_absolute_path(void) { const char *local_src; local_src = cl_fixture("testrepo.git"); cl_git_pass(git_clone(&g_repo, local_src, "./foo", &g_options)); } void test_clone_nonetwork__local_bare(void) { g_options.bare = true; cl_git_pass(git_clone(&g_repo, cl_git_fixture_url("testrepo.git"), "./foo", &g_options)); } void test_clone_nonetwork__fail_when_the_target_is_a_file(void) { cl_git_mkfile("./foo", "Bar!"); cl_git_fail(git_clone(&g_repo, cl_git_fixture_url("testrepo.git"), "./foo", &g_options)); } void test_clone_nonetwork__fail_with_already_existing_but_non_empty_directory(void) { p_mkdir("./foo", GIT_DIR_MODE); cl_git_mkfile("./foo/bar", "Baz!"); cl_git_fail(git_clone(&g_repo, cl_git_fixture_url("testrepo.git"), "./foo", &g_options)); } void test_clone_nonetwork__custom_origin_name(void) { g_options.remote_name = "my_origin"; cl_git_pass(git_clone(&g_repo, cl_git_fixture_url("testrepo.git"), "./foo", &g_options)); cl_git_pass(git_remote_load(&g_remote, g_repo, "my_origin")); } void test_clone_nonetwork__custom_push_url(void) { const char *url = "http://example.com"; g_options.pushurl = url; cl_git_pass(git_clone(&g_repo, cl_git_fixture_url("testrepo.git"), "./foo", &g_options)); cl_git_pass(git_remote_load(&g_remote, g_repo, "origin")); cl_assert_equal_s(url, git_remote_pushurl(g_remote)); } void test_clone_nonetwork__custom_fetch_spec(void) { const git_refspec *actual_fs; const char *spec = "+refs/heads/master:refs/heads/foo"; g_options.fetch_spec = spec; cl_git_pass(git_clone(&g_repo, cl_git_fixture_url("testrepo.git"), "./foo", &g_options)); cl_git_pass(git_remote_load(&g_remote, g_repo, "origin")); actual_fs = git_remote_get_refspec(g_remote, 0); cl_assert_equal_s("refs/heads/master", git_refspec_src(actual_fs)); cl_assert_equal_s("refs/heads/foo", git_refspec_dst(actual_fs)); cl_git_pass(git_reference_lookup(&g_ref, g_repo, "refs/heads/foo")); } void test_clone_nonetwork__custom_push_spec(void) { const git_refspec *actual_fs; const char *spec = "+refs/heads/master:refs/heads/foo"; g_options.push_spec = spec; cl_git_pass(git_clone(&g_repo, cl_git_fixture_url("testrepo.git"), "./foo", &g_options)); cl_git_pass(git_remote_load(&g_remote, g_repo, "origin")); actual_fs = git_remote_get_refspec(g_remote, git_remote_refspec_count(g_remote) - 1); cl_assert_equal_s("refs/heads/master", git_refspec_src(actual_fs)); cl_assert_equal_s("refs/heads/foo", git_refspec_dst(actual_fs)); } void test_clone_nonetwork__custom_autotag(void) { git_remote *origin; git_strarray tags = {0}; g_options.remote_autotag = GIT_REMOTE_DOWNLOAD_TAGS_NONE; cl_git_pass(git_clone(&g_repo, cl_git_fixture_url("testrepo.git"), "./foo", &g_options)); cl_git_pass(git_tag_list(&tags, g_repo)); cl_assert_equal_sz(0, tags.count); cl_git_pass(git_remote_load(&origin, g_repo, "origin")); cl_assert_equal_i(GIT_REMOTE_DOWNLOAD_TAGS_NONE, origin->download_tags); git_strarray_free(&tags); git_remote_free(origin); } void test_clone_nonetwork__custom_autotag_tags_all(void) { git_strarray tags = {0}; git_remote *origin; g_options.remote_autotag = GIT_REMOTE_DOWNLOAD_TAGS_ALL; cl_git_pass(git_clone(&g_repo, cl_git_fixture_url("testrepo.git"), "./foo", &g_options)); cl_git_pass(git_remote_load(&origin, g_repo, "origin")); cl_assert_equal_i(GIT_REMOTE_DOWNLOAD_TAGS_ALL, origin->download_tags); git_strarray_free(&tags); git_remote_free(origin); } void test_clone_nonetwork__cope_with_already_existing_directory(void) { p_mkdir("./foo", GIT_DIR_MODE); cl_git_pass(git_clone(&g_repo, cl_git_fixture_url("testrepo.git"), "./foo", &g_options)); } void test_clone_nonetwork__can_prevent_the_checkout_of_a_standard_repo(void) { git_buf path = GIT_BUF_INIT; g_options.checkout_opts.checkout_strategy = 0; cl_git_pass(git_clone(&g_repo, cl_git_fixture_url("testrepo.git"), "./foo", &g_options)); cl_git_pass(git_buf_joinpath(&path, git_repository_workdir(g_repo), "master.txt")); cl_assert_equal_i(false, git_path_isfile(git_buf_cstr(&path))); git_buf_free(&path); } void test_clone_nonetwork__can_checkout_given_branch(void) { g_options.checkout_branch = "test"; cl_git_pass(git_clone(&g_repo, cl_git_fixture_url("testrepo.git"), "./foo", &g_options)); cl_assert_equal_i(0, git_repository_head_orphan(g_repo)); cl_git_pass(git_repository_head(&g_ref, g_repo)); cl_assert_equal_s(git_reference_name(g_ref), "refs/heads/test"); } void test_clone_nonetwork__can_detached_head(void) { git_object *obj; git_repository *cloned; git_reference *cloned_head; cl_git_pass(git_clone(&g_repo, cl_git_fixture_url("testrepo.git"), "./foo", &g_options)); cl_git_pass(git_revparse_single(&obj, g_repo, "master~1")); cl_git_pass(git_repository_set_head_detached(g_repo, git_object_id(obj))); cl_git_pass(git_clone(&cloned, "./foo", "./foo1", &g_options)); cl_assert(git_repository_head_detached(cloned)); cl_git_pass(git_repository_head(&cloned_head, cloned)); cl_assert(!git_oid_cmp(git_object_id(obj), git_reference_target(cloned_head))); git_object_free(obj); git_reference_free(cloned_head); git_repository_free(cloned); cl_fixture_cleanup("./foo1"); } libgit2-0.19.0/tests-clar/commit/000077500000000000000000000000001216214232500165045ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/commit/commit.c000066400000000000000000000023271216214232500201440ustar00rootroot00000000000000#include "clar_libgit2.h" static git_repository *_repo; void test_commit_commit__initialize(void) { cl_fixture_sandbox("testrepo.git"); cl_git_pass(git_repository_open(&_repo, "testrepo.git")); } void test_commit_commit__cleanup(void) { git_repository_free(_repo); _repo = NULL; cl_fixture_cleanup("testrepo.git"); } void test_commit_commit__create_unexisting_update_ref(void) { git_oid oid; git_tree *tree; git_commit *commit; git_signature *s; git_reference *ref; git_oid_fromstr(&oid, "a65fedf39aefe402d3bb6e24df4d4f5fe4547750"); cl_git_pass(git_commit_lookup(&commit, _repo, &oid)); git_oid_fromstr(&oid, "944c0f6e4dfa41595e6eb3ceecdb14f50fe18162"); cl_git_pass(git_tree_lookup(&tree, _repo, &oid)); cl_git_pass(git_signature_now(&s, "alice", "alice@example.com")); cl_git_fail(git_reference_lookup(&ref, _repo, "refs/heads/foo/bar")); cl_git_pass(git_commit_create(&oid, _repo, "refs/heads/foo/bar", s, s, NULL, "some msg", tree, 1, (const git_commit **) &commit)); cl_git_pass(git_reference_lookup(&ref, _repo, "refs/heads/foo/bar")); cl_assert(!git_oid_cmp(&oid, git_reference_target(ref))); git_tree_free(tree); git_commit_free(commit); git_signature_free(s); git_reference_free(ref); } libgit2-0.19.0/tests-clar/commit/parent.c000066400000000000000000000027761216214232500201550ustar00rootroot00000000000000#include "clar_libgit2.h" static git_repository *_repo; static git_commit *commit; void test_commit_parent__initialize(void) { git_oid oid; cl_git_pass(git_repository_open(&_repo, cl_fixture("testrepo.git"))); git_oid_fromstr(&oid, "be3563ae3f795b2b4353bcce3a527ad0a4f7f644"); cl_git_pass(git_commit_lookup(&commit, _repo, &oid)); } void test_commit_parent__cleanup(void) { git_commit_free(commit); commit = NULL; git_repository_free(_repo); _repo = NULL; } static void assert_nth_gen_parent(unsigned int gen, const char *expected_oid) { git_commit *parent = NULL; int error; error = git_commit_nth_gen_ancestor(&parent, commit, gen); if (expected_oid != NULL) { cl_assert_equal_i(0, error); cl_assert_equal_i(0, git_oid_streq(git_commit_id(parent), expected_oid)); } else cl_assert_equal_i(GIT_ENOTFOUND, error); git_commit_free(parent); } /* * $ git show be35~0 * commit be3563ae3f795b2b4353bcce3a527ad0a4f7f644 * * $ git show be35~1 * commit 9fd738e8f7967c078dceed8190330fc8648ee56a * * $ git show be35~3 * commit 5b5b025afb0b4c913b4c338a42934a3863bf3644 * * $ git show be35~42 * fatal: ambiguous argument 'be35~42': unknown revision or path not in the working tree. */ void test_commit_parent__can_retrieve_nth_generation_parent(void) { assert_nth_gen_parent(0, "be3563ae3f795b2b4353bcce3a527ad0a4f7f644"); assert_nth_gen_parent(1, "9fd738e8f7967c078dceed8190330fc8648ee56a"); assert_nth_gen_parent(3, "5b5b025afb0b4c913b4c338a42934a3863bf3644"); assert_nth_gen_parent(42, NULL); } libgit2-0.19.0/tests-clar/commit/parse.c000066400000000000000000000356421216214232500177740ustar00rootroot00000000000000#include "clar_libgit2.h" #include #include "commit.h" #include "signature.h" // Fixture setup static git_repository *g_repo; void test_commit_parse__initialize(void) { g_repo = cl_git_sandbox_init("testrepo"); } void test_commit_parse__cleanup(void) { cl_git_sandbox_cleanup(); } // Header parsing typedef struct { const char *line; const char *header; } parse_test_case; static parse_test_case passing_header_cases[] = { { "parent 05452d6349abcd67aa396dfb28660d765d8b2a36\n", "parent " }, { "tree 05452d6349abcd67aa396dfb28660d765d8b2a36\n", "tree " }, { "random_heading 05452d6349abcd67aa396dfb28660d765d8b2a36\n", "random_heading " }, { "stuck_heading05452d6349abcd67aa396dfb28660d765d8b2a36\n", "stuck_heading" }, { "tree 5F4BEFFC0759261D015AA63A3A85613FF2F235DE\n", "tree " }, { "tree 1A669B8AB81B5EB7D9DB69562D34952A38A9B504\n", "tree " }, { "tree 5B20DCC6110FCC75D31C6CEDEBD7F43ECA65B503\n", "tree " }, { "tree 173E7BF00EA5C33447E99E6C1255954A13026BE4\n", "tree " }, { NULL, NULL } }; static parse_test_case failing_header_cases[] = { { "parent 05452d6349abcd67aa396dfb28660d765d8b2a36", "parent " }, { "05452d6349abcd67aa396dfb28660d765d8b2a36\n", "tree " }, { "parent05452d6349abcd67aa396dfb28660d765d8b2a6a\n", "parent " }, { "parent 05452d6349abcd67aa396dfb280d765d8b2a6\n", "parent " }, { "tree 05452d6349abcd67aa396dfb28660d765d8b2a36\n", "tree " }, { "parent 0545xd6349abcd67aa396dfb28660d765d8b2a36\n", "parent " }, { "parent 0545xd6349abcd67aa396dfb28660d765d8b2a36FF\n", "parent " }, { "", "tree " }, { "", "" }, { NULL, NULL } }; void test_commit_parse__header(void) { git_oid oid; parse_test_case *testcase; for (testcase = passing_header_cases; testcase->line != NULL; testcase++) { const char *line = testcase->line; const char *line_end = line + strlen(line); cl_git_pass(git_oid__parse(&oid, &line, line_end, testcase->header)); cl_assert(line == line_end); } for (testcase = failing_header_cases; testcase->line != NULL; testcase++) { const char *line = testcase->line; const char *line_end = line + strlen(line); cl_git_fail(git_oid__parse(&oid, &line, line_end, testcase->header)); } } // Signature parsing typedef struct { const char *string; const char *header; const char *name; const char *email; git_time_t time; int offset; } passing_signature_test_case; passing_signature_test_case passing_signature_cases[] = { {"author Vicent Marti 12345 \n", "author ", "Vicent Marti", "tanoku@gmail.com", 12345, 0}, {"author Vicent Marti <> 12345 \n", "author ", "Vicent Marti", "", 12345, 0}, {"author Vicent Marti 231301 +1020\n", "author ", "Vicent Marti", "tanoku@gmail.com", 231301, 620}, {"author Vicent Marti with an outrageously long name which will probably overflow the buffer 12345 \n", "author ", "Vicent Marti with an outrageously long name which will probably overflow the buffer", "tanoku@gmail.com", 12345, 0}, {"author Vicent Marti 12345 \n", "author ", "Vicent Marti", "tanokuwithaveryveryverylongemailwhichwillprobablyvoverflowtheemailbuffer@gmail.com", 12345, 0}, {"committer Vicent Marti 123456 +0000 \n", "committer ", "Vicent Marti", "tanoku@gmail.com", 123456, 0}, {"committer Vicent Marti 123456 +0100 \n", "committer ", "Vicent Marti", "tanoku@gmail.com", 123456, 60}, {"committer Vicent Marti 123456 -0100 \n", "committer ", "Vicent Marti", "tanoku@gmail.com", 123456, -60}, // Parse a signature without an author field {"committer 123456 -0100 \n", "committer ", "", "tanoku@gmail.com", 123456, -60}, // Parse a signature without an author field {"committer 123456 -0100 \n", "committer ", "", "tanoku@gmail.com", 123456, -60}, // Parse a signature with an empty author field {"committer 123456 -0100 \n", "committer ", "", "tanoku@gmail.com", 123456, -60}, // Parse a signature with an empty email field {"committer Vicent Marti <> 123456 -0100 \n", "committer ", "Vicent Marti", "", 123456, -60}, // Parse a signature with an empty email field {"committer Vicent Marti < > 123456 -0100 \n", "committer ", "Vicent Marti", "", 123456, -60}, // Parse a signature with empty name and email {"committer <> 123456 -0100 \n", "committer ", "", "", 123456, -60}, // Parse a signature with empty name and email {"committer <> 123456 -0100 \n", "committer ", "", "", 123456, -60}, // Parse a signature with empty name and email {"committer < > 123456 -0100 \n", "committer ", "", "", 123456, -60}, // Parse an obviously invalid signature {"committer foo<@bar> 123456 -0100 \n", "committer ", "foo", "@bar", 123456, -60}, // Parse an obviously invalid signature {"committer foo<@bar> 123456 -0100 \n", "committer ", "foo", "@bar", 123456, -60}, // Parse an obviously invalid signature {"committer <>\n", "committer ", "", "", 0, 0}, {"committer Vicent Marti 123456 -1500 \n", "committer ", "Vicent Marti", "tanoku@gmail.com", 123456, 0}, {"committer Vicent Marti 123456 +0163 \n", "committer ", "Vicent Marti", "tanoku@gmail.com", 123456, 0}, {"author Vicent Marti \n", "author ", "Vicent Marti", "tanoku@gmail.com", 0, 0}, /* a variety of dates */ {"author Vicent Marti 0 \n", "author ", "Vicent Marti", "tanoku@gmail.com", 0, 0}, {"author Vicent Marti 1234567890 \n", "author ", "Vicent Marti", "tanoku@gmail.com", 1234567890, 0}, {"author Vicent Marti 2147483647 \n", "author ", "Vicent Marti", "tanoku@gmail.com", 0x7fffffff, 0}, {"author Vicent Marti 4294967295 \n", "author ", "Vicent Marti", "tanoku@gmail.com", 0xffffffff, 0}, {"author Vicent Marti 4294967296 \n", "author ", "Vicent Marti", "tanoku@gmail.com", 4294967296, 0}, {"author Vicent Marti 8589934592 \n", "author ", "Vicent Marti", "tanoku@gmail.com", 8589934592, 0}, {NULL,NULL,NULL,NULL,0,0} }; typedef struct { const char *string; const char *header; } failing_signature_test_case; failing_signature_test_case failing_signature_cases[] = { {"committer Vicent Marti tanoku@gmail.com> 123456 -0100 \n", "committer "}, {"author Vicent Marti 12345 \n", "author "}, {"author Vicent Marti 12345 \n", "committer "}, {"author Vicent Marti 12345 \n", "author "}, {"author Vicent Marti <\n", "committer "}, {"author ", "author "}, {NULL, NULL,} }; void test_commit_parse__signature(void) { passing_signature_test_case *passcase; failing_signature_test_case *failcase; for (passcase = passing_signature_cases; passcase->string != NULL; passcase++) { const char *str = passcase->string; size_t len = strlen(passcase->string); struct git_signature person = {0}; cl_git_pass(git_signature__parse(&person, &str, str + len, passcase->header, '\n')); cl_assert_equal_s(passcase->name, person.name); cl_assert_equal_s(passcase->email, person.email); cl_assert_equal_i((int)passcase->time, (int)person.when.time); cl_assert_equal_i(passcase->offset, person.when.offset); git__free(person.name); git__free(person.email); } for (failcase = failing_signature_cases; failcase->string != NULL; failcase++) { const char *str = failcase->string; size_t len = strlen(failcase->string); git_signature person = {0}; cl_git_fail(git_signature__parse(&person, &str, str + len, failcase->header, '\n')); git__free(person.name); git__free(person.email); } } static char *failing_commit_cases[] = { // empty commit "", // random garbage "asd97sa9du902e9a0jdsuusad09as9du098709aweu8987sd\n", // broken endlines 1 "tree f6c0dad3c7b3481caa9d73db21f91964894a945b\r\n\ parent 05452d6349abcd67aa396dfb28660d765d8b2a36\r\n\ author Vicent Marti 1273848544 +0200\r\n\ committer Vicent Marti 1273848544 +0200\r\n\ \r\n\ a test commit with broken endlines\r\n", // broken endlines 2 "tree f6c0dad3c7b3481caa9d73db21f91964894a945b\ parent 05452d6349abcd67aa396dfb28660d765d8b2a36\ author Vicent Marti 1273848544 +0200\ committer Vicent Marti 1273848544 +0200\ \ another test commit with broken endlines", // starting endlines "\ntree f6c0dad3c7b3481caa9d73db21f91964894a945b\n\ parent 05452d6349abcd67aa396dfb28660d765d8b2a36\n\ author Vicent Marti 1273848544 +0200\n\ committer Vicent Marti 1273848544 +0200\n\ \n\ a test commit with a starting endline\n", // corrupted commit 1 "tree f6c0dad3c7b3481caa9d73db21f91964894a945b\n\ parent 05452d6349abcd67aa396df", // corrupted commit 2 "tree f6c0dad3c7b3481caa9d73db21f91964894a945b\n\ parent ", // corrupted commit 3 "tree f6c0dad3c7b3481caa9d73db21f91964894a945b\n\ parent ", // corrupted commit 4 "tree f6c0dad3c7b3481caa9d73db21f91964894a945b\n\ par", }; static char *passing_commit_cases[] = { // simple commit with no message "tree 1810dff58d8a660512d4832e740f692884338ccd\n\ author Vicent Marti 1273848544 +0200\n\ committer Vicent Marti 1273848544 +0200\n\ \n", // simple commit, no parent "tree 1810dff58d8a660512d4832e740f692884338ccd\n\ author Vicent Marti 1273848544 +0200\n\ committer Vicent Marti 1273848544 +0200\n\ \n\ a simple commit which works\n", // simple commit, no parent, no newline in message "tree 1810dff58d8a660512d4832e740f692884338ccd\n\ author Vicent Marti 1273848544 +0200\n\ committer Vicent Marti 1273848544 +0200\n\ \n\ a simple commit which works", // simple commit, 1 parent "tree 1810dff58d8a660512d4832e740f692884338ccd\n\ parent e90810b8df3e80c413d903f631643c716887138d\n\ author Vicent Marti 1273848544 +0200\n\ committer Vicent Marti 1273848544 +0200\n\ \n\ a simple commit which works\n", /* simple commit with GPG signature */ "tree 6b79e22d69bf46e289df0345a14ca059dfc9bdf6\n\ parent 34734e478d6cf50c27c9d69026d93974d052c454\n\ author Ben Burkert 1358451456 -0800\n\ committer Ben Burkert 1358451456 -0800\n\ gpgsig -----BEGIN PGP SIGNATURE-----\n\ Version: GnuPG v1.4.12 (Darwin)\n\ \n\ iQIcBAABAgAGBQJQ+FMIAAoJEH+LfPdZDSs1e3EQAJMjhqjWF+WkGLHju7pTw2al\n\ o6IoMAhv0Z/LHlWhzBd9e7JeCnanRt12bAU7yvYp9+Z+z+dbwqLwDoFp8LVuigl8\n\ JGLcnwiUW3rSvhjdCp9irdb4+bhKUnKUzSdsR2CK4/hC0N2i/HOvMYX+BRsvqweq\n\ AsAkA6dAWh+gAfedrBUkCTGhlNYoetjdakWqlGL1TiKAefEZrtA1TpPkGn92vbLq\n\ SphFRUY9hVn1ZBWrT3hEpvAIcZag3rTOiRVT1X1flj8B2vGCEr3RrcwOIZikpdaW\n\ who/X3xh/DGbI2RbuxmmJpxxP/8dsVchRJJzBwG+yhwU/iN3MlV2c5D69tls/Dok\n\ 6VbyU4lm/ae0y3yR83D9dUlkycOnmmlBAHKIZ9qUts9X7mWJf0+yy2QxJVpjaTGG\n\ cmnQKKPeNIhGJk2ENnnnzjEve7L7YJQF6itbx5VCOcsGh3Ocb3YR7DMdWjt7f8pu\n\ c6j+q1rP7EpE2afUN/geSlp5i3x8aXZPDj67jImbVCE/Q1X9voCtyzGJH7MXR0N9\n\ ZpRF8yzveRfMH8bwAJjSOGAFF5XkcR/RNY95o+J+QcgBLdX48h+ZdNmUf6jqlu3J\n\ 7KmTXXQcOVpN6dD3CmRFsbjq+x6RHwa8u1iGn+oIkX908r97ckfB/kHKH7ZdXIJc\n\ cpxtDQQMGYFpXK/71stq\n\ =ozeK\n\ -----END PGP SIGNATURE-----\n\ \n\ a simple commit which works\n", }; static int parse_commit(git_commit **out, const char *buffer) { git_commit *commit; git_odb_object fake_odb_object; int error; commit = (git_commit*)git__malloc(sizeof(git_commit)); memset(commit, 0x0, sizeof(git_commit)); commit->object.repo = g_repo; memset(&fake_odb_object, 0x0, sizeof(git_odb_object)); fake_odb_object.buffer = (char *)buffer; fake_odb_object.cached.size = strlen(fake_odb_object.buffer); error = git_commit__parse(commit, &fake_odb_object); *out = commit; return error; } void test_commit_parse__entire_commit(void) { const int failing_commit_count = ARRAY_SIZE(failing_commit_cases); const int passing_commit_count = ARRAY_SIZE(passing_commit_cases); int i; git_commit *commit; for (i = 0; i < failing_commit_count; ++i) { cl_git_fail(parse_commit(&commit, failing_commit_cases[i])); git_commit__free(commit); } for (i = 0; i < passing_commit_count; ++i) { cl_git_pass(parse_commit(&commit, passing_commit_cases[i])); if (!i) cl_assert_equal_s("", git_commit_message(commit)); else cl_assert(git__prefixcmp( git_commit_message(commit), "a simple commit which works") == 0); git_commit__free(commit); } } // query the details on a parsed commit void test_commit_parse__details0(void) { static const char *commit_ids[] = { "a4a7dce85cf63874e984719f4fdd239f5145052f", /* 0 */ "9fd738e8f7967c078dceed8190330fc8648ee56a", /* 1 */ "4a202b346bb0fb0db7eff3cffeb3c70babbd2045", /* 2 */ "c47800c7266a2be04c571c04d5a6614691ea99bd", /* 3 */ "8496071c1b46c854b31185ea97743be6a8774479", /* 4 */ "5b5b025afb0b4c913b4c338a42934a3863bf3644", /* 5 */ "a65fedf39aefe402d3bb6e24df4d4f5fe4547750", /* 6 */ }; const size_t commit_count = sizeof(commit_ids) / sizeof(const char *); unsigned int i; for (i = 0; i < commit_count; ++i) { git_oid id; git_commit *commit; const git_signature *author, *committer; const char *message; git_time_t commit_time; unsigned int parents, p; git_commit *parent = NULL, *old_parent = NULL; git_oid_fromstr(&id, commit_ids[i]); cl_git_pass(git_commit_lookup(&commit, g_repo, &id)); message = git_commit_message(commit); author = git_commit_author(commit); committer = git_commit_committer(commit); commit_time = git_commit_time(commit); parents = git_commit_parentcount(commit); cl_assert_equal_s("Scott Chacon", author->name); cl_assert_equal_s("schacon@gmail.com", author->email); cl_assert_equal_s("Scott Chacon", committer->name); cl_assert_equal_s("schacon@gmail.com", committer->email); cl_assert(message != NULL); cl_assert(strchr(message, '\n') != NULL); cl_assert(commit_time > 0); cl_assert(parents <= 2); for (p = 0;p < parents;p++) { if (old_parent != NULL) git_commit_free(old_parent); old_parent = parent; cl_git_pass(git_commit_parent(&parent, commit, p)); cl_assert(parent != NULL); cl_assert(git_commit_author(parent) != NULL); // is it really a commit? } git_commit_free(old_parent); git_commit_free(parent); cl_git_fail(git_commit_parent(&parent, commit, parents)); git_commit_free(commit); } } void test_commit_parse__leading_lf(void) { git_commit *commit; const char *buffer = "tree 1810dff58d8a660512d4832e740f692884338ccd\n\ parent e90810b8df3e80c413d903f631643c716887138d\n\ author Vicent Marti 1273848544 +0200\n\ committer Vicent Marti 1273848544 +0200\n\ \n\ \n\ \n\ This commit has a few LF at the start of the commit message"; const char *message = "\n\ \n\ This commit has a few LF at the start of the commit message"; cl_git_pass(parse_commit(&commit, buffer)); cl_assert_equal_s(message, git_commit_message(commit)); git_commit__free(commit); } libgit2-0.19.0/tests-clar/commit/signature.c000066400000000000000000000053421216214232500206550ustar00rootroot00000000000000#include "clar_libgit2.h" static int try_build_signature(const char *name, const char *email, git_time_t time, int offset) { git_signature *sign; int error = 0; if ((error = git_signature_new(&sign, name, email, time, offset)) < 0) return error; git_signature_free((git_signature *)sign); return error; } static void assert_name_and_email( const char *expected_name, const char *expected_email, const char *name, const char *email) { git_signature *sign; cl_git_pass(git_signature_new(&sign, name, email, 1234567890, 60)); cl_assert_equal_s(expected_name, sign->name); cl_assert_equal_s(expected_email, sign->email); git_signature_free(sign); } void test_commit_signature__leading_and_trailing_spaces_are_trimmed(void) { assert_name_and_email("nulltoken", "emeric.fermas@gmail.com", " nulltoken ", " emeric.fermas@gmail.com "); assert_name_and_email("nulltoken", "emeric.fermas@gmail.com", " nulltoken ", " emeric.fermas@gmail.com \n"); assert_name_and_email("nulltoken", "emeric.fermas@gmail.com", " \t nulltoken \n", " \n emeric.fermas@gmail.com \n"); } void test_commit_signature__angle_brackets_in_names_are_not_supported(void) { cl_git_fail(try_build_signature("Haack", "phil@haack", 1234567890, 60)); cl_git_fail(try_build_signature("", "phil@haack", 1234567890, 60)); } void test_commit_signature__angle_brackets_in_email_are_not_supported(void) { cl_git_fail(try_build_signature("Phil Haack", ">phil@haack", 1234567890, 60)); cl_git_fail(try_build_signature("Phil Haack", "phil@>haack", 1234567890, 60)); cl_git_fail(try_build_signature("Phil Haack", "", 1234567890, 60)); } void test_commit_signature__create_empties(void) { // can not create a signature with empty name or email cl_git_pass(try_build_signature("nulltoken", "emeric.fermas@gmail.com", 1234567890, 60)); cl_git_fail(try_build_signature("", "emeric.fermas@gmail.com", 1234567890, 60)); cl_git_fail(try_build_signature(" ", "emeric.fermas@gmail.com", 1234567890, 60)); cl_git_pass(try_build_signature("nulltoken", "", 1234567890, 60)); cl_git_pass(try_build_signature("nulltoken", " ", 1234567890, 60)); } void test_commit_signature__create_one_char(void) { // creating a one character signature assert_name_and_email("x", "foo@bar.baz", "x", "foo@bar.baz"); } void test_commit_signature__create_two_char(void) { // creating a two character signature assert_name_and_email("xx", "foo@bar.baz", "xx", "foo@bar.baz"); } void test_commit_signature__create_zero_char(void) { // creating a zero character signature git_signature *sign; cl_git_fail(git_signature_new(&sign, "", "x@y.z", 1234567890, 60)); cl_assert(sign == NULL); } libgit2-0.19.0/tests-clar/commit/write.c000066400000000000000000000106721216214232500200100ustar00rootroot00000000000000#include "clar_libgit2.h" static const char *committer_name = "Vicent Marti"; static const char *committer_email = "vicent@github.com"; static const char *commit_message = "This commit has been created in memory\n\ This is a commit created in memory and it will be written back to disk\n"; static const char *tree_oid = "1810dff58d8a660512d4832e740f692884338ccd"; static const char *root_commit_message = "This is a root commit\n\ This is a root commit and should be the only one in this branch\n"; static char *head_old; static git_reference *head, *branch; static git_commit *commit; // Fixture setup static git_repository *g_repo; void test_commit_write__initialize(void) { g_repo = cl_git_sandbox_init("testrepo"); } void test_commit_write__cleanup(void) { git_reference_free(head); head = NULL; git_reference_free(branch); branch = NULL; git_commit_free(commit); commit = NULL; git__free(head_old); head_old = NULL; cl_git_sandbox_cleanup(); } // write a new commit object from memory to disk void test_commit_write__from_memory(void) { git_oid tree_id, parent_id, commit_id; git_signature *author, *committer; const git_signature *author1, *committer1; git_commit *parent; git_tree *tree; const char *commit_id_str = "8496071c1b46c854b31185ea97743be6a8774479"; git_oid_fromstr(&tree_id, tree_oid); cl_git_pass(git_tree_lookup(&tree, g_repo, &tree_id)); git_oid_fromstr(&parent_id, commit_id_str); cl_git_pass(git_commit_lookup(&parent, g_repo, &parent_id)); /* create signatures */ cl_git_pass(git_signature_new(&committer, committer_name, committer_email, 123456789, 60)); cl_git_pass(git_signature_new(&author, committer_name, committer_email, 987654321, 90)); cl_git_pass(git_commit_create_v( &commit_id, /* out id */ g_repo, NULL, /* do not update the HEAD */ author, committer, NULL, commit_message, tree, 1, parent)); git_object_free((git_object *)parent); git_object_free((git_object *)tree); git_signature_free(committer); git_signature_free(author); cl_git_pass(git_commit_lookup(&commit, g_repo, &commit_id)); /* Check attributes were set correctly */ author1 = git_commit_author(commit); cl_assert(author1 != NULL); cl_assert_equal_s(committer_name, author1->name); cl_assert_equal_s(committer_email, author1->email); cl_assert(author1->when.time == 987654321); cl_assert(author1->when.offset == 90); committer1 = git_commit_committer(commit); cl_assert(committer1 != NULL); cl_assert_equal_s(committer_name, committer1->name); cl_assert_equal_s(committer_email, committer1->email); cl_assert(committer1->when.time == 123456789); cl_assert(committer1->when.offset == 60); cl_assert_equal_s(commit_message, git_commit_message(commit)); } // create a root commit void test_commit_write__root(void) { git_oid tree_id, commit_id; const git_oid *branch_oid; git_signature *author, *committer; const char *branch_name = "refs/heads/root-commit-branch"; git_tree *tree; git_oid_fromstr(&tree_id, tree_oid); cl_git_pass(git_tree_lookup(&tree, g_repo, &tree_id)); /* create signatures */ cl_git_pass(git_signature_new(&committer, committer_name, committer_email, 123456789, 60)); cl_git_pass(git_signature_new(&author, committer_name, committer_email, 987654321, 90)); /* First we need to update HEAD so it points to our non-existant branch */ cl_git_pass(git_reference_lookup(&head, g_repo, "HEAD")); cl_assert(git_reference_type(head) == GIT_REF_SYMBOLIC); head_old = git__strdup(git_reference_symbolic_target(head)); cl_assert(head_old != NULL); git_reference_free(head); cl_git_pass(git_reference_symbolic_create(&head, g_repo, "HEAD", branch_name, 1)); cl_git_pass(git_commit_create_v( &commit_id, /* out id */ g_repo, "HEAD", author, committer, NULL, root_commit_message, tree, 0)); git_object_free((git_object *)tree); git_signature_free(committer); git_signature_free(author); /* * The fact that creating a commit works has already been * tested. Here we just make sure it's our commit and that it was * written as a root commit. */ cl_git_pass(git_commit_lookup(&commit, g_repo, &commit_id)); cl_assert(git_commit_parentcount(commit) == 0); cl_git_pass(git_reference_lookup(&branch, g_repo, branch_name)); branch_oid = git_reference_target(branch); cl_git_pass(git_oid_cmp(branch_oid, &commit_id)); cl_assert_equal_s(root_commit_message, git_commit_message(commit)); } libgit2-0.19.0/tests-clar/config/000077500000000000000000000000001216214232500164615ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/config/add.c000066400000000000000000000015771216214232500173670ustar00rootroot00000000000000#include "clar_libgit2.h" void test_config_add__initialize(void) { cl_fixture_sandbox("config/config10"); } void test_config_add__cleanup(void) { cl_fixture_cleanup("config10"); } void test_config_add__to_existing_section(void) { git_config *cfg; int32_t i; cl_git_pass(git_config_open_ondisk(&cfg, "config10")); cl_git_pass(git_config_set_int32(cfg, "empty.tmp", 5)); cl_git_pass(git_config_get_int32(&i, cfg, "empty.tmp")); cl_assert(i == 5); cl_git_pass(git_config_delete_entry(cfg, "empty.tmp")); git_config_free(cfg); } void test_config_add__to_new_section(void) { git_config *cfg; int32_t i; cl_git_pass(git_config_open_ondisk(&cfg, "config10")); cl_git_pass(git_config_set_int32(cfg, "section.tmp", 5)); cl_git_pass(git_config_get_int32(&i, cfg, "section.tmp")); cl_assert(i == 5); cl_git_pass(git_config_delete_entry(cfg, "section.tmp")); git_config_free(cfg); } libgit2-0.19.0/tests-clar/config/backend.c000066400000000000000000000011271216214232500202150ustar00rootroot00000000000000#include "clar_libgit2.h" #include "git2/sys/config.h" void test_config_backend__checks_version(void) { git_config *cfg; git_config_backend backend = GIT_CONFIG_BACKEND_INIT; const git_error *err; backend.version = 1024; cl_git_pass(git_config_new(&cfg)); cl_git_fail(git_config_add_backend(cfg, &backend, 0, false)); err = giterr_last(); cl_assert_equal_i(GITERR_INVALID, err->klass); giterr_clear(); backend.version = 1024; cl_git_fail(git_config_add_backend(cfg, &backend, 0, false)); err = giterr_last(); cl_assert_equal_i(GITERR_INVALID, err->klass); git_config_free(cfg); } libgit2-0.19.0/tests-clar/config/config_helpers.c000066400000000000000000000014001216214232500216070ustar00rootroot00000000000000#include "clar_libgit2.h" #include "config_helpers.h" #include "repository.h" void assert_config_entry_existence( git_repository *repo, const char *name, bool is_supposed_to_exist) { git_config *config; const char *out; int result; cl_git_pass(git_repository_config__weakptr(&config, repo)); result = git_config_get_string(&out, config, name); if (is_supposed_to_exist) cl_git_pass(result); else cl_assert_equal_i(GIT_ENOTFOUND, result); } void assert_config_entry_value( git_repository *repo, const char *name, const char *expected_value) { git_config *config; const char *out; cl_git_pass(git_repository_config__weakptr(&config, repo)); cl_git_pass(git_config_get_string(&out, config, name)); cl_assert_equal_s(expected_value, out); } libgit2-0.19.0/tests-clar/config/config_helpers.h000066400000000000000000000003421216214232500216200ustar00rootroot00000000000000extern void assert_config_entry_existence( git_repository *repo, const char *name, bool is_supposed_to_exist); extern void assert_config_entry_value( git_repository *repo, const char *name, const char *expected_value); libgit2-0.19.0/tests-clar/config/configlevel.c000066400000000000000000000040641216214232500211260ustar00rootroot00000000000000#include "clar_libgit2.h" void test_config_configlevel__adding_the_same_level_twice_returns_EEXISTS(void) { int error; git_config *cfg; cl_git_pass(git_config_new(&cfg)); cl_git_pass(git_config_add_file_ondisk(cfg, cl_fixture("config/config9"), GIT_CONFIG_LEVEL_LOCAL, 0)); cl_git_pass(git_config_add_file_ondisk(cfg, cl_fixture("config/config15"), GIT_CONFIG_LEVEL_GLOBAL, 0)); error = git_config_add_file_ondisk(cfg, cl_fixture("config/config16"), GIT_CONFIG_LEVEL_GLOBAL, 0); cl_git_fail(error); cl_assert_equal_i(GIT_EEXISTS, error); git_config_free(cfg); } void test_config_configlevel__can_replace_a_config_file_at_an_existing_level(void) { git_config *cfg; const char *s; cl_git_pass(git_config_new(&cfg)); cl_git_pass(git_config_add_file_ondisk(cfg, cl_fixture("config/config18"), GIT_CONFIG_LEVEL_LOCAL, 1)); cl_git_pass(git_config_add_file_ondisk(cfg, cl_fixture("config/config19"), GIT_CONFIG_LEVEL_LOCAL, 1)); cl_git_pass(git_config_get_string(&s, cfg, "core.stringglobal")); cl_assert_equal_s("don't find me!", s); git_config_free(cfg); } void test_config_configlevel__can_read_from_a_single_level_focused_file_after_parent_config_has_been_freed(void) { git_config *cfg; git_config *single_level_cfg; const char *s; cl_git_pass(git_config_new(&cfg)); cl_git_pass(git_config_add_file_ondisk(cfg, cl_fixture("config/config18"), GIT_CONFIG_LEVEL_GLOBAL, 0)); cl_git_pass(git_config_add_file_ondisk(cfg, cl_fixture("config/config19"), GIT_CONFIG_LEVEL_LOCAL, 0)); cl_git_pass(git_config_open_level(&single_level_cfg, cfg, GIT_CONFIG_LEVEL_LOCAL)); git_config_free(cfg); cl_git_pass(git_config_get_string(&s, single_level_cfg, "core.stringglobal")); cl_assert_equal_s("don't find me!", s); git_config_free(single_level_cfg); } void test_config_configlevel__fetching_a_level_from_an_empty_compound_config_returns_ENOTFOUND(void) { git_config *cfg; git_config *local_cfg; cl_git_pass(git_config_new(&cfg)); cl_assert_equal_i(GIT_ENOTFOUND, git_config_open_level(&local_cfg, cfg, GIT_CONFIG_LEVEL_LOCAL)); git_config_free(cfg); } libgit2-0.19.0/tests-clar/config/global.c000066400000000000000000000035541216214232500200740ustar00rootroot00000000000000#include "clar_libgit2.h" #include "buffer.h" #include "fileops.h" void test_config_global__initialize(void) { git_buf path = GIT_BUF_INIT; cl_must_pass(p_mkdir("home", 0777)); cl_git_pass(git_path_prettify(&path, "home", NULL)); cl_git_pass(git_libgit2_opts( GIT_OPT_SET_SEARCH_PATH, GIT_CONFIG_LEVEL_GLOBAL, path.ptr)); cl_must_pass(p_mkdir("xdg", 0777)); cl_git_pass(git_path_prettify(&path, "xdg", NULL)); cl_git_pass(git_libgit2_opts( GIT_OPT_SET_SEARCH_PATH, GIT_CONFIG_LEVEL_SYSTEM, path.ptr)); cl_git_pass(git_libgit2_opts( GIT_OPT_SET_SEARCH_PATH, GIT_CONFIG_LEVEL_XDG, NULL)); git_buf_free(&path); } void test_config_global__cleanup(void) { cl_git_pass(git_futils_rmdir_r("home", NULL, GIT_RMDIR_REMOVE_FILES)); cl_git_pass(git_futils_rmdir_r("xdg", NULL, GIT_RMDIR_REMOVE_FILES)); } void test_config_global__open_global(void) { git_config *cfg, *global, *selected, *dummy; cl_git_pass(git_config_open_default(&cfg)); cl_git_pass(git_config_open_level(&global, cfg, GIT_CONFIG_LEVEL_GLOBAL)); cl_git_fail(git_config_open_level(&dummy, cfg, GIT_CONFIG_LEVEL_XDG)); cl_git_pass(git_config_open_global(&selected, cfg)); git_config_free(selected); git_config_free(global); git_config_free(cfg); } void test_config_global__open_xdg(void) { git_config *cfg, *xdg, *selected; const char *val, *str = "teststring"; const char *key = "this.variable"; p_setenv("XDG_CONFIG_HOME", "xdg", 1); cl_must_pass(p_mkdir("xdg/git/", 0777)); cl_git_mkfile("xdg/git/config", ""); cl_git_pass(git_config_open_default(&cfg)); cl_git_pass(git_config_open_level(&xdg, cfg, GIT_CONFIG_LEVEL_XDG)); cl_git_pass(git_config_open_global(&selected, cfg)); cl_git_pass(git_config_set_string(xdg, key, str)); cl_git_pass(git_config_get_string(&val, selected, key)); cl_assert_equal_s(str, val); git_config_free(selected); git_config_free(xdg); git_config_free(cfg); } libgit2-0.19.0/tests-clar/config/multivar.c000066400000000000000000000066121216214232500204750ustar00rootroot00000000000000#include "clar_libgit2.h" static const char *_name = "remote.fancy.url"; void test_config_multivar__initialize(void) { cl_fixture_sandbox("config"); } void test_config_multivar__cleanup(void) { cl_fixture_cleanup("config"); } static int mv_read_cb(const git_config_entry *entry, void *data) { int *n = (int *) data; if (!strcmp(entry->name, _name)) (*n)++; return 0; } void test_config_multivar__foreach(void) { git_config *cfg; int n = 0; cl_git_pass(git_config_open_ondisk(&cfg, cl_fixture("config/config11"))); cl_git_pass(git_config_foreach(cfg, mv_read_cb, &n)); cl_assert(n == 2); git_config_free(cfg); } static int cb(const git_config_entry *entry, void *data) { int *n = (int *) data; GIT_UNUSED(entry); (*n)++; return 0; } void test_config_multivar__get(void) { git_config *cfg; int n; cl_git_pass(git_config_open_ondisk(&cfg, "config/config11")); n = 0; cl_git_pass(git_config_get_multivar(cfg, _name, NULL, cb, &n)); cl_assert(n == 2); n = 0; cl_git_pass(git_config_get_multivar(cfg, _name, "example", cb, &n)); cl_assert(n == 1); git_config_free(cfg); } void test_config_multivar__add(void) { git_config *cfg; int n; cl_git_pass(git_config_open_ondisk(&cfg, "config/config11")); cl_git_pass(git_config_set_multivar(cfg, _name, "nonexistant", "git://git.otherplace.org/libgit2")); n = 0; cl_git_pass(git_config_get_multivar(cfg, _name, NULL, cb, &n)); cl_assert(n == 3); n = 0; cl_git_pass(git_config_get_multivar(cfg, _name, "otherplace", cb, &n)); cl_assert(n == 1); git_config_free(cfg); /* We know it works in memory, let's see if the file is written correctly */ cl_git_pass(git_config_open_ondisk(&cfg, "config/config11")); n = 0; cl_git_pass(git_config_get_multivar(cfg, _name, NULL, cb, &n)); cl_assert(n == 3); n = 0; cl_git_pass(git_config_get_multivar(cfg, _name, "otherplace", cb, &n)); cl_assert(n == 1); git_config_free(cfg); } void test_config_multivar__add_new(void) { const char *var = "a.brand.new"; git_config *cfg; int n; cl_git_pass(git_config_open_ondisk(&cfg, "config/config11")); cl_git_pass(git_config_set_multivar(cfg, var, "", "variable")); n = 0; cl_git_pass(git_config_get_multivar(cfg, var, NULL, cb, &n)); cl_assert(n == 1); git_config_free(cfg); } void test_config_multivar__replace(void) { git_config *cfg; int n; cl_git_pass(git_config_open_ondisk(&cfg, "config/config11")); n = 0; cl_git_pass(git_config_get_multivar(cfg, _name, NULL, cb, &n)); cl_assert(n == 2); cl_git_pass(git_config_set_multivar(cfg, _name, "github", "git://git.otherplace.org/libgit2")); n = 0; cl_git_pass(git_config_get_multivar(cfg, _name, NULL, cb, &n)); cl_assert(n == 2); git_config_free(cfg); cl_git_pass(git_config_open_ondisk(&cfg, "config/config11")); n = 0; cl_git_pass(git_config_get_multivar(cfg, _name, NULL, cb, &n)); cl_assert(n == 2); git_config_free(cfg); } void test_config_multivar__replace_multiple(void) { git_config *cfg; int n; cl_git_pass(git_config_open_ondisk(&cfg, "config/config11")); cl_git_pass(git_config_set_multivar(cfg, _name, "git://", "git://git.otherplace.org/libgit2")); n = 0; cl_git_pass(git_config_get_multivar(cfg, _name, "otherplace", cb, &n)); cl_assert(n == 2); git_config_free(cfg); cl_git_pass(git_config_open_ondisk(&cfg, "config/config11")); n = 0; cl_git_pass(git_config_get_multivar(cfg, _name, "otherplace", cb, &n)); cl_assert(n == 2); git_config_free(cfg); } libgit2-0.19.0/tests-clar/config/new.c000066400000000000000000000014071216214232500174200ustar00rootroot00000000000000#include "clar_libgit2.h" #include "filebuf.h" #include "fileops.h" #include "posix.h" #define TEST_CONFIG "git-new-config" void test_config_new__write_new_config(void) { const char *out; git_config *config; cl_git_mkfile(TEST_CONFIG, ""); cl_git_pass(git_config_open_ondisk(&config, TEST_CONFIG)); cl_git_pass(git_config_set_string(config, "color.ui", "auto")); cl_git_pass(git_config_set_string(config, "core.editor", "ed")); git_config_free(config); cl_git_pass(git_config_open_ondisk(&config, TEST_CONFIG)); cl_git_pass(git_config_get_string(&out, config, "color.ui")); cl_assert_equal_s(out, "auto"); cl_git_pass(git_config_get_string(&out, config, "core.editor")); cl_assert_equal_s(out, "ed"); git_config_free(config); p_unlink(TEST_CONFIG); } libgit2-0.19.0/tests-clar/config/read.c000066400000000000000000000272651216214232500175540ustar00rootroot00000000000000#include "clar_libgit2.h" void test_config_read__simple_read(void) { git_config *cfg; int32_t i; cl_git_pass(git_config_open_ondisk(&cfg, cl_fixture("config/config0"))); cl_git_pass(git_config_get_int32(&i, cfg, "core.repositoryformatversion")); cl_assert(i == 0); cl_git_pass(git_config_get_bool(&i, cfg, "core.filemode")); cl_assert(i == 1); cl_git_pass(git_config_get_bool(&i, cfg, "core.bare")); cl_assert(i == 0); cl_git_pass(git_config_get_bool(&i, cfg, "core.logallrefupdates")); cl_assert(i == 1); git_config_free(cfg); } void test_config_read__case_sensitive(void) { git_config *cfg; int i; const char *str; cl_git_pass(git_config_open_ondisk(&cfg, cl_fixture("config/config1"))); cl_git_pass(git_config_get_string(&str, cfg, "this.that.other")); cl_assert_equal_s(str, "true"); cl_git_pass(git_config_get_string(&str, cfg, "this.That.other")); cl_assert_equal_s(str, "yes"); cl_git_pass(git_config_get_bool(&i, cfg, "this.that.other")); cl_assert(i == 1); cl_git_pass(git_config_get_bool(&i, cfg, "this.That.other")); cl_assert(i == 1); /* This one doesn't exist */ cl_must_fail(git_config_get_bool(&i, cfg, "this.thaT.other")); git_config_free(cfg); } /* * If \ is the last non-space character on the line, we read the next * one, separating each line with SP. */ void test_config_read__multiline_value(void) { git_config *cfg; const char *str; cl_git_pass(git_config_open_ondisk(&cfg, cl_fixture("config/config2"))); cl_git_pass(git_config_get_string(&str, cfg, "this.That.and")); cl_assert_equal_s(str, "one one one two two three three"); git_config_free(cfg); } /* * This kind of subsection declaration is case-insensitive */ void test_config_read__subsection_header(void) { git_config *cfg; const char *str; cl_git_pass(git_config_open_ondisk(&cfg, cl_fixture("config/config3"))); cl_git_pass(git_config_get_string(&str, cfg, "section.subsection.var")); cl_assert_equal_s(str, "hello"); /* The subsection is transformed to lower-case */ cl_must_fail(git_config_get_string(&str, cfg, "section.subSectIon.var")); git_config_free(cfg); } void test_config_read__lone_variable(void) { git_config *cfg; const char *str; int i; cl_git_pass(git_config_open_ondisk(&cfg, cl_fixture("config/config4"))); cl_git_fail(git_config_get_int32(&i, cfg, "some.section.variable")); cl_git_pass(git_config_get_string(&str, cfg, "some.section.variable")); cl_assert_equal_s(str, ""); cl_git_pass(git_config_get_bool(&i, cfg, "some.section.variable")); cl_assert(i == 1); cl_git_pass(git_config_get_string(&str, cfg, "some.section.variableeq")); cl_assert_equal_s(str, ""); cl_git_pass(git_config_get_bool(&i, cfg, "some.section.variableeq")); cl_assert(i == 0); git_config_free(cfg); } void test_config_read__number_suffixes(void) { git_config *cfg; int64_t i; cl_git_pass(git_config_open_ondisk(&cfg, cl_fixture("config/config5"))); cl_git_pass(git_config_get_int64(&i, cfg, "number.simple")); cl_assert(i == 1); cl_git_pass(git_config_get_int64(&i, cfg, "number.k")); cl_assert(i == 1 * 1024); cl_git_pass(git_config_get_int64(&i, cfg, "number.kk")); cl_assert(i == 1 * 1024); cl_git_pass(git_config_get_int64(&i, cfg, "number.m")); cl_assert(i == 1 * 1024 * 1024); cl_git_pass(git_config_get_int64(&i, cfg, "number.mm")); cl_assert(i == 1 * 1024 * 1024); cl_git_pass(git_config_get_int64(&i, cfg, "number.g")); cl_assert(i == 1 * 1024 * 1024 * 1024); cl_git_pass(git_config_get_int64(&i, cfg, "number.gg")); cl_assert(i == 1 * 1024 * 1024 * 1024); git_config_free(cfg); } void test_config_read__blank_lines(void) { git_config *cfg; int i; cl_git_pass(git_config_open_ondisk(&cfg, cl_fixture("config/config6"))); cl_git_pass(git_config_get_bool(&i, cfg, "valid.subsection.something")); cl_assert(i == 1); cl_git_pass(git_config_get_bool(&i, cfg, "something.else.something")); cl_assert(i == 0); git_config_free(cfg); } void test_config_read__invalid_ext_headers(void) { git_config *cfg; cl_must_fail(git_config_open_ondisk(&cfg, cl_fixture("config/config7"))); } void test_config_read__empty_files(void) { git_config *cfg; cl_git_pass(git_config_open_ondisk(&cfg, cl_fixture("config/config8"))); git_config_free(cfg); } void test_config_read__header_in_last_line(void) { git_config *cfg; cl_git_pass(git_config_open_ondisk(&cfg, cl_fixture("config/config10"))); git_config_free(cfg); } void test_config_read__prefixes(void) { git_config *cfg; const char *str; cl_git_pass(git_config_open_ondisk(&cfg, cl_fixture("config/config9"))); cl_git_pass(git_config_get_string(&str, cfg, "remote.ab.url")); cl_assert_equal_s(str, "http://example.com/git/ab"); cl_git_pass(git_config_get_string(&str, cfg, "remote.abba.url")); cl_assert_equal_s(str, "http://example.com/git/abba"); git_config_free(cfg); } void test_config_read__escaping_quotes(void) { git_config *cfg; const char *str; cl_git_pass(git_config_open_ondisk(&cfg, cl_fixture("config/config13"))); cl_git_pass(git_config_get_string(&str, cfg, "core.editor")); cl_assert_equal_s("\"C:/Program Files/Nonsense/bah.exe\" \"--some option\"", str); git_config_free(cfg); } static int count_cfg_entries_and_compare_levels( const git_config_entry *entry, void *payload) { int *count = payload; if (!strcmp(entry->value, "7") || !strcmp(entry->value, "17")) cl_assert(entry->level == GIT_CONFIG_LEVEL_GLOBAL); else cl_assert(entry->level == GIT_CONFIG_LEVEL_SYSTEM); (*count)++; return 0; } static int cfg_callback_countdown(const git_config_entry *entry, void *payload) { int *count = payload; GIT_UNUSED(entry); (*count)--; if (*count == 0) return -100; return 0; } void test_config_read__foreach(void) { git_config *cfg; int count, ret; cl_git_pass(git_config_new(&cfg)); cl_git_pass(git_config_add_file_ondisk(cfg, cl_fixture("config/config9"), GIT_CONFIG_LEVEL_SYSTEM, 0)); cl_git_pass(git_config_add_file_ondisk(cfg, cl_fixture("config/config15"), GIT_CONFIG_LEVEL_GLOBAL, 0)); count = 0; cl_git_pass(git_config_foreach(cfg, count_cfg_entries_and_compare_levels, &count)); cl_assert_equal_i(7, count); count = 3; cl_git_fail(ret = git_config_foreach(cfg, cfg_callback_countdown, &count)); cl_assert_equal_i(GIT_EUSER, ret); git_config_free(cfg); } static int count_cfg_entries(const git_config_entry *entry, void *payload) { int *count = payload; GIT_UNUSED(entry); (*count)++; return 0; } void test_config_read__foreach_match(void) { git_config *cfg; int count; cl_git_pass(git_config_open_ondisk(&cfg, cl_fixture("config/config9"))); count = 0; cl_git_pass( git_config_foreach_match(cfg, "core.*", count_cfg_entries, &count)); cl_assert_equal_i(3, count); count = 0; cl_git_pass( git_config_foreach_match(cfg, "remote\\.ab.*", count_cfg_entries, &count)); cl_assert_equal_i(2, count); count = 0; cl_git_pass( git_config_foreach_match(cfg, ".*url$", count_cfg_entries, &count)); cl_assert_equal_i(2, count); count = 0; cl_git_pass( git_config_foreach_match(cfg, ".*dummy.*", count_cfg_entries, &count)); cl_assert_equal_i(2, count); count = 0; cl_git_pass( git_config_foreach_match(cfg, ".*nomatch.*", count_cfg_entries, &count)); cl_assert_equal_i(0, count); git_config_free(cfg); } void test_config_read__whitespace_not_required_around_assignment(void) { git_config *cfg; const char *str; cl_git_pass(git_config_open_ondisk(&cfg, cl_fixture("config/config14"))); cl_git_pass(git_config_get_string(&str, cfg, "a.b")); cl_assert_equal_s(str, "c"); cl_git_pass(git_config_get_string(&str, cfg, "d.e")); cl_assert_equal_s(str, "f"); git_config_free(cfg); } void test_config_read__read_git_config_entry(void) { git_config *cfg; const git_config_entry *entry; cl_git_pass(git_config_new(&cfg)); cl_git_pass(git_config_add_file_ondisk(cfg, cl_fixture("config/config9"), GIT_CONFIG_LEVEL_SYSTEM, 0)); cl_git_pass(git_config_get_entry(&entry, cfg, "core.dummy2")); cl_assert_equal_s("core.dummy2", entry->name); cl_assert_equal_s("42", entry->value); cl_assert_equal_i(GIT_CONFIG_LEVEL_SYSTEM, entry->level); git_config_free(cfg); } /* * At the beginning of the test: * - config9 has: core.dummy2=42 * - config15 has: core.dummy2=7 * - config16 has: core.dummy2=28 */ void test_config_read__local_config_overrides_global_config_overrides_system_config(void) { git_config *cfg; int32_t i; cl_git_pass(git_config_new(&cfg)); cl_git_pass(git_config_add_file_ondisk(cfg, cl_fixture("config/config9"), GIT_CONFIG_LEVEL_SYSTEM, 0)); cl_git_pass(git_config_add_file_ondisk(cfg, cl_fixture("config/config15"), GIT_CONFIG_LEVEL_GLOBAL, 0)); cl_git_pass(git_config_add_file_ondisk(cfg, cl_fixture("config/config16"), GIT_CONFIG_LEVEL_LOCAL, 0)); cl_git_pass(git_config_get_int32(&i, cfg, "core.dummy2")); cl_assert_equal_i(28, i); git_config_free(cfg); cl_git_pass(git_config_new(&cfg)); cl_git_pass(git_config_add_file_ondisk(cfg, cl_fixture("config/config9"), GIT_CONFIG_LEVEL_SYSTEM, 0)); cl_git_pass(git_config_add_file_ondisk(cfg, cl_fixture("config/config15"), GIT_CONFIG_LEVEL_GLOBAL, 0)); cl_git_pass(git_config_get_int32(&i, cfg, "core.dummy2")); cl_assert_equal_i(7, i); git_config_free(cfg); } /* * At the beginning of the test: * - config9 has: core.global does not exist * - config15 has: core.global=17 * - config16 has: core.global=29 * * And also: * - config9 has: core.system does not exist * - config15 has: core.system does not exist * - config16 has: core.system=11 */ void test_config_read__fallback_from_local_to_global_and_from_global_to_system(void) { git_config *cfg; int32_t i; cl_git_pass(git_config_new(&cfg)); cl_git_pass(git_config_add_file_ondisk(cfg, cl_fixture("config/config9"), GIT_CONFIG_LEVEL_SYSTEM, 0)); cl_git_pass(git_config_add_file_ondisk(cfg, cl_fixture("config/config15"), GIT_CONFIG_LEVEL_GLOBAL, 0)); cl_git_pass(git_config_add_file_ondisk(cfg, cl_fixture("config/config16"), GIT_CONFIG_LEVEL_LOCAL, 0)); cl_git_pass(git_config_get_int32(&i, cfg, "core.global")); cl_assert_equal_i(17, i); cl_git_pass(git_config_get_int32(&i, cfg, "core.system")); cl_assert_equal_i(11, i); git_config_free(cfg); } /* * At the beginning of the test, config18 has: * int32global = 28 * int64global = 9223372036854775803 * boolglobal = true * stringglobal = I'm a global config value! * * And config19 has: * int32global = -1 * int64global = -2 * boolglobal = false * stringglobal = don't find me! * */ void test_config_read__simple_read_from_specific_level(void) { git_config *cfg, *cfg_specific; int i; int64_t l, expected = +9223372036854775803; const char *s; cl_git_pass(git_config_new(&cfg)); cl_git_pass(git_config_add_file_ondisk(cfg, cl_fixture("config/config18"), GIT_CONFIG_LEVEL_GLOBAL, 0)); cl_git_pass(git_config_add_file_ondisk(cfg, cl_fixture("config/config19"), GIT_CONFIG_LEVEL_SYSTEM, 0)); cl_git_pass(git_config_open_level(&cfg_specific, cfg, GIT_CONFIG_LEVEL_GLOBAL)); cl_git_pass(git_config_get_int32(&i, cfg_specific, "core.int32global")); cl_assert_equal_i(28, i); cl_git_pass(git_config_get_int64(&l, cfg_specific, "core.int64global")); cl_assert(l == expected); cl_git_pass(git_config_get_bool(&i, cfg_specific, "core.boolglobal")); cl_assert_equal_b(true, i); cl_git_pass(git_config_get_string(&s, cfg_specific, "core.stringglobal")); cl_assert_equal_s("I'm a global config value!", s); git_config_free(cfg_specific); git_config_free(cfg); } static void clean_empty_config(void *unused) { GIT_UNUSED(unused); cl_fixture_cleanup("./empty"); } void test_config_read__can_load_and_parse_an_empty_config_file(void) { git_config *cfg; int i; cl_set_cleanup(&clean_empty_config, NULL); cl_git_mkfile("./empty", ""); cl_git_pass(git_config_open_ondisk(&cfg, "./empty")); cl_assert_equal_i(GIT_ENOTFOUND, git_config_get_int32(&i, cfg, "nope.neither")); git_config_free(cfg); } libgit2-0.19.0/tests-clar/config/refresh.c000066400000000000000000000032251216214232500202650ustar00rootroot00000000000000#include "clar_libgit2.h" #define TEST_FILE "config.refresh" void test_config_refresh__initialize(void) { } void test_config_refresh__cleanup(void) { cl_fixture_cleanup(TEST_FILE); } void test_config_refresh__update_value(void) { git_config *cfg; int32_t v; cl_git_mkfile(TEST_FILE, "[section]\n\tvalue = 1\n\n"); /* By freeing the config, we make sure we flush the values */ cl_git_pass(git_config_open_ondisk(&cfg, TEST_FILE)); cl_git_pass(git_config_get_int32(&v, cfg, "section.value")); cl_assert_equal_i(1, v); cl_git_rewritefile(TEST_FILE, "[section]\n\tvalue = 10\n\n"); cl_git_pass(git_config_get_int32(&v, cfg, "section.value")); cl_assert_equal_i(1, v); cl_git_pass(git_config_refresh(cfg)); cl_git_pass(git_config_get_int32(&v, cfg, "section.value")); cl_assert_equal_i(10, v); git_config_free(cfg); } void test_config_refresh__delete_value(void) { git_config *cfg; int32_t v; cl_git_mkfile(TEST_FILE, "[section]\n\tvalue = 1\n\n"); /* By freeing the config, we make sure we flush the values */ cl_git_pass(git_config_open_ondisk(&cfg, TEST_FILE)); cl_git_pass(git_config_get_int32(&v, cfg, "section.value")); cl_assert_equal_i(1, v); cl_git_fail(git_config_get_int32(&v, cfg, "section.newval")); cl_git_rewritefile(TEST_FILE, "[section]\n\tnewval = 10\n\n"); cl_git_pass(git_config_get_int32(&v, cfg, "section.value")); cl_assert_equal_i(1, v); cl_git_fail(git_config_get_int32(&v, cfg, "section.newval")); cl_git_pass(git_config_refresh(cfg)); cl_git_fail(git_config_get_int32(&v, cfg, "section.value")); cl_git_pass(git_config_get_int32(&v, cfg, "section.newval")); cl_assert_equal_i(10, v); git_config_free(cfg); } libgit2-0.19.0/tests-clar/config/stress.c000066400000000000000000000047331216214232500201570ustar00rootroot00000000000000#include "clar_libgit2.h" #include "filebuf.h" #include "fileops.h" #include "posix.h" #define TEST_CONFIG "git-test-config" void test_config_stress__initialize(void) { git_filebuf file = GIT_FILEBUF_INIT; cl_git_pass(git_filebuf_open(&file, TEST_CONFIG, 0)); git_filebuf_printf(&file, "[color]\n\tui = auto\n"); git_filebuf_printf(&file, "[core]\n\teditor = \n"); cl_git_pass(git_filebuf_commit(&file, 0666)); } void test_config_stress__cleanup(void) { p_unlink(TEST_CONFIG); } void test_config_stress__dont_break_on_invalid_input(void) { const char *editor, *color; git_config *config; cl_assert(git_path_exists(TEST_CONFIG)); cl_git_pass(git_config_open_ondisk(&config, TEST_CONFIG)); cl_git_pass(git_config_get_string(&color, config, "color.ui")); cl_git_pass(git_config_get_string(&editor, config, "core.editor")); git_config_free(config); } void test_config_stress__comments(void) { git_config *config; const char *str; cl_git_pass(git_config_open_ondisk(&config, cl_fixture("config/config12"))); cl_git_pass(git_config_get_string(&str, config, "some.section.other")); cl_assert_equal_s("hello! \" ; ; ; ", str); cl_git_pass(git_config_get_string(&str, config, "some.section.multi")); cl_assert_equal_s("hi, this is a ; multiline comment # with ;\n special chars and other stuff !@#", str); cl_git_pass(git_config_get_string(&str, config, "some.section.back")); cl_assert_equal_s("this is \ba phrase", str); git_config_free(config); } void test_config_stress__escape_subsection_names(void) { git_config *config; const char *str; cl_assert(git_path_exists("git-test-config")); cl_git_pass(git_config_open_ondisk(&config, TEST_CONFIG)); cl_git_pass(git_config_set_string(config, "some.sec\\tion.other", "foo")); git_config_free(config); cl_git_pass(git_config_open_ondisk(&config, TEST_CONFIG)); cl_git_pass(git_config_get_string(&str, config, "some.sec\\tion.other")); cl_assert_equal_s("foo", str); git_config_free(config); } void test_config_stress__trailing_backslash(void) { git_config *config; const char *str; const char *path = "C:\\iam\\some\\windows\\path\\"; cl_assert(git_path_exists("git-test-config")); cl_git_pass(git_config_open_ondisk(&config, TEST_CONFIG)); cl_git_pass(git_config_set_string(config, "windows.path", path)); git_config_free(config); cl_git_pass(git_config_open_ondisk(&config, TEST_CONFIG)); cl_git_pass(git_config_get_string(&str, config, "windows.path")); cl_assert_equal_s(path, str); git_config_free(config); } libgit2-0.19.0/tests-clar/config/validkeyname.c000066400000000000000000000037451216214232500213070ustar00rootroot00000000000000#include "clar_libgit2.h" #include "config.h" static git_config *cfg; static const char *value; void test_config_validkeyname__initialize(void) { cl_fixture_sandbox("config/config10"); cl_git_pass(git_config_open_ondisk(&cfg, "config10")); } void test_config_validkeyname__cleanup(void) { git_config_free(cfg); cfg = NULL; cl_fixture_cleanup("config10"); } static void assert_invalid_config_key_name(const char *name) { cl_git_fail_with(git_config_get_string(&value, cfg, name), GIT_EINVALIDSPEC); cl_git_fail_with(git_config_set_string(cfg, name, "42"), GIT_EINVALIDSPEC); cl_git_fail_with(git_config_delete_entry(cfg, name), GIT_EINVALIDSPEC); cl_git_fail_with(git_config_get_multivar(cfg, name, "*", NULL, NULL), GIT_EINVALIDSPEC); cl_git_fail_with(git_config_set_multivar(cfg, name, "*", "42"), GIT_EINVALIDSPEC); } void test_config_validkeyname__accessing_requires_a_valid_name(void) { assert_invalid_config_key_name(""); assert_invalid_config_key_name("."); assert_invalid_config_key_name(".."); assert_invalid_config_key_name("core."); assert_invalid_config_key_name("d#ff.dirstat.lines"); assert_invalid_config_key_name("diff.dirstat.lines#"); assert_invalid_config_key_name("dif\nf.dirstat.lines"); assert_invalid_config_key_name("dif.dir\nstat.lines"); assert_invalid_config_key_name("dif.dirstat.li\nes"); } static void assert_invalid_config_section_name(git_repository *repo, const char *name) { cl_git_fail_with(git_config_rename_section(repo, "branch.remoteless", name), GIT_EINVALIDSPEC); } void test_config_validkeyname__renaming_a_section_requires_a_valid_name(void) { git_repository *repo; cl_git_pass(git_repository_open(&repo, cl_fixture("testrepo.git"))); assert_invalid_config_section_name(repo, ""); assert_invalid_config_section_name(repo, "bra\nch"); assert_invalid_config_section_name(repo, "branc#"); assert_invalid_config_section_name(repo, "bra\nch.duh"); assert_invalid_config_section_name(repo, "branc#.duh"); git_repository_free(repo); } libgit2-0.19.0/tests-clar/config/write.c000066400000000000000000000167161216214232500177720ustar00rootroot00000000000000#include "clar_libgit2.h" void test_config_write__initialize(void) { cl_fixture_sandbox("config/config9"); cl_fixture_sandbox("config/config15"); cl_fixture_sandbox("config/config17"); } void test_config_write__cleanup(void) { cl_fixture_cleanup("config9"); cl_fixture_cleanup("config15"); cl_fixture_cleanup("config17"); } void test_config_write__replace_value(void) { git_config *cfg; int i; int64_t l, expected = +9223372036854775803; /* By freeing the config, we make sure we flush the values */ cl_git_pass(git_config_open_ondisk(&cfg, "config9")); cl_git_pass(git_config_set_int32(cfg, "core.dummy", 5)); git_config_free(cfg); cl_git_pass(git_config_open_ondisk(&cfg, "config9")); cl_git_pass(git_config_get_int32(&i, cfg, "core.dummy")); cl_assert(i == 5); git_config_free(cfg); cl_git_pass(git_config_open_ondisk(&cfg, "config9")); cl_git_pass(git_config_set_int32(cfg, "core.dummy", 1)); git_config_free(cfg); cl_git_pass(git_config_open_ondisk(&cfg, "config9")); cl_git_pass(git_config_set_int64(cfg, "core.verylong", expected)); git_config_free(cfg); cl_git_pass(git_config_open_ondisk(&cfg, "config9")); cl_git_pass(git_config_get_int64(&l, cfg, "core.verylong")); cl_assert(l == expected); git_config_free(cfg); cl_git_pass(git_config_open_ondisk(&cfg, "config9")); cl_must_fail(git_config_get_int32(&i, cfg, "core.verylong")); git_config_free(cfg); cl_git_pass(git_config_open_ondisk(&cfg, "config9")); cl_git_pass(git_config_set_int64(cfg, "core.verylong", 1)); git_config_free(cfg); } void test_config_write__delete_value(void) { git_config *cfg; int32_t i; cl_git_pass(git_config_open_ondisk(&cfg, "config9")); cl_git_pass(git_config_set_int32(cfg, "core.dummy", 5)); git_config_free(cfg); cl_git_pass(git_config_open_ondisk(&cfg, "config9")); cl_git_pass(git_config_delete_entry(cfg, "core.dummy")); git_config_free(cfg); cl_git_pass(git_config_open_ondisk(&cfg, "config9")); cl_assert(git_config_get_int32(&i, cfg, "core.dummy") == GIT_ENOTFOUND); cl_git_pass(git_config_set_int32(cfg, "core.dummy", 1)); git_config_free(cfg); } /* * At the beginning of the test: * - config9 has: core.dummy2=42 * - config15 has: core.dummy2=7 */ void test_config_write__delete_value_at_specific_level(void) { git_config *cfg, *cfg_specific; int32_t i; cl_git_pass(git_config_open_ondisk(&cfg, "config15")); cl_git_pass(git_config_get_int32(&i, cfg, "core.dummy2")); cl_assert(i == 7); git_config_free(cfg); cl_git_pass(git_config_new(&cfg)); cl_git_pass(git_config_add_file_ondisk(cfg, "config9", GIT_CONFIG_LEVEL_LOCAL, 0)); cl_git_pass(git_config_add_file_ondisk(cfg, "config15", GIT_CONFIG_LEVEL_GLOBAL, 0)); cl_git_pass(git_config_open_level(&cfg_specific, cfg, GIT_CONFIG_LEVEL_GLOBAL)); cl_git_pass(git_config_delete_entry(cfg_specific, "core.dummy2")); git_config_free(cfg); cl_git_pass(git_config_open_ondisk(&cfg, "config15")); cl_assert(git_config_get_int32(&i, cfg, "core.dummy2") == GIT_ENOTFOUND); cl_git_pass(git_config_set_int32(cfg, "core.dummy2", 7)); git_config_free(cfg_specific); git_config_free(cfg); } void test_config_write__write_subsection(void) { git_config *cfg; const char *str; cl_git_pass(git_config_open_ondisk(&cfg, "config9")); cl_git_pass(git_config_set_string(cfg, "my.own.var", "works")); git_config_free(cfg); cl_git_pass(git_config_open_ondisk(&cfg, "config9")); cl_git_pass(git_config_get_string(&str, cfg, "my.own.var")); cl_assert_equal_s("works", str); git_config_free(cfg); } void test_config_write__delete_inexistent(void) { git_config *cfg; cl_git_pass(git_config_open_ondisk(&cfg, "config9")); cl_assert(git_config_delete_entry(cfg, "core.imaginary") == GIT_ENOTFOUND); git_config_free(cfg); } void test_config_write__value_containing_quotes(void) { git_config *cfg; const char* str; cl_git_pass(git_config_open_ondisk(&cfg, "config9")); cl_git_pass(git_config_set_string(cfg, "core.somevar", "this \"has\" quotes")); cl_git_pass(git_config_get_string(&str, cfg, "core.somevar")); cl_assert_equal_s(str, "this \"has\" quotes"); git_config_free(cfg); cl_git_pass(git_config_open_ondisk(&cfg, "config9")); cl_git_pass(git_config_get_string(&str, cfg, "core.somevar")); cl_assert_equal_s(str, "this \"has\" quotes"); git_config_free(cfg); /* The code path for values that already exist is different, check that one as well */ cl_git_pass(git_config_open_ondisk(&cfg, "config9")); cl_git_pass(git_config_set_string(cfg, "core.somevar", "this also \"has\" quotes")); cl_git_pass(git_config_get_string(&str, cfg, "core.somevar")); cl_assert_equal_s(str, "this also \"has\" quotes"); git_config_free(cfg); cl_git_pass(git_config_open_ondisk(&cfg, "config9")); cl_git_pass(git_config_get_string(&str, cfg, "core.somevar")); cl_assert_equal_s(str, "this also \"has\" quotes"); git_config_free(cfg); } void test_config_write__escape_value(void) { git_config *cfg; const char* str; cl_git_pass(git_config_open_ondisk(&cfg, "config9")); cl_git_pass(git_config_set_string(cfg, "core.somevar", "this \"has\" quotes and \t")); cl_git_pass(git_config_get_string(&str, cfg, "core.somevar")); cl_assert_equal_s(str, "this \"has\" quotes and \t"); git_config_free(cfg); cl_git_pass(git_config_open_ondisk(&cfg, "config9")); cl_git_pass(git_config_get_string(&str, cfg, "core.somevar")); cl_assert_equal_s(str, "this \"has\" quotes and \t"); git_config_free(cfg); } void test_config_write__add_value_at_specific_level(void) { git_config *cfg, *cfg_specific; int i; int64_t l, expected = +9223372036854775803; const char *s; // open config15 as global level config file cl_git_pass(git_config_new(&cfg)); cl_git_pass(git_config_add_file_ondisk(cfg, "config9", GIT_CONFIG_LEVEL_LOCAL, 0)); cl_git_pass(git_config_add_file_ondisk(cfg, "config15", GIT_CONFIG_LEVEL_GLOBAL, 0)); cl_git_pass(git_config_open_level(&cfg_specific, cfg, GIT_CONFIG_LEVEL_GLOBAL)); cl_git_pass(git_config_set_int32(cfg_specific, "core.int32global", 28)); cl_git_pass(git_config_set_int64(cfg_specific, "core.int64global", expected)); cl_git_pass(git_config_set_bool(cfg_specific, "core.boolglobal", true)); cl_git_pass(git_config_set_string(cfg_specific, "core.stringglobal", "I'm a global config value!")); git_config_free(cfg_specific); git_config_free(cfg); // open config15 as local level config file cl_git_pass(git_config_open_ondisk(&cfg, "config15")); cl_git_pass(git_config_get_int32(&i, cfg, "core.int32global")); cl_assert_equal_i(28, i); cl_git_pass(git_config_get_int64(&l, cfg, "core.int64global")); cl_assert(l == expected); cl_git_pass(git_config_get_bool(&i, cfg, "core.boolglobal")); cl_assert_equal_b(true, i); cl_git_pass(git_config_get_string(&s, cfg, "core.stringglobal")); cl_assert_equal_s("I'm a global config value!", s); git_config_free(cfg); } void test_config_write__add_value_at_file_with_no_clrf_at_the_end(void) { git_config *cfg; int i; cl_git_pass(git_config_open_ondisk(&cfg, "config17")); cl_git_pass(git_config_set_int32(cfg, "core.newline", 7)); git_config_free(cfg); cl_git_pass(git_config_open_ondisk(&cfg, "config17")); cl_git_pass(git_config_get_int32(&i, cfg, "core.newline")); cl_assert_equal_i(7, i); git_config_free(cfg); } void test_config_write__can_set_a_value_to_NULL(void) { git_repository *repository; git_config *config; repository = cl_git_sandbox_init("testrepo.git"); cl_git_pass(git_repository_config(&config, repository)); cl_git_fail(git_config_set_string(config, "a.b.c", NULL)); git_config_free(config); cl_git_sandbox_cleanup(); } libgit2-0.19.0/tests-clar/core/000077500000000000000000000000001216214232500161445ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/core/buffer.c000066400000000000000000000674661216214232500176040ustar00rootroot00000000000000#include "clar_libgit2.h" #include "buffer.h" #include "buf_text.h" #include "hashsig.h" #include "fileops.h" #define TESTSTR "Have you seen that? Have you seeeen that??" const char *test_string = TESTSTR; const char *test_string_x2 = TESTSTR TESTSTR; #define TESTSTR_4096 REP1024("1234") #define TESTSTR_8192 REP1024("12341234") const char *test_4096 = TESTSTR_4096; const char *test_8192 = TESTSTR_8192; /* test basic data concatenation */ void test_core_buffer__0(void) { git_buf buf = GIT_BUF_INIT; cl_assert(buf.size == 0); git_buf_puts(&buf, test_string); cl_assert(git_buf_oom(&buf) == 0); cl_assert_equal_s(test_string, git_buf_cstr(&buf)); git_buf_puts(&buf, test_string); cl_assert(git_buf_oom(&buf) == 0); cl_assert_equal_s(test_string_x2, git_buf_cstr(&buf)); git_buf_free(&buf); } /* test git_buf_printf */ void test_core_buffer__1(void) { git_buf buf = GIT_BUF_INIT; git_buf_printf(&buf, "%s %s %d ", "shoop", "da", 23); cl_assert(git_buf_oom(&buf) == 0); cl_assert_equal_s("shoop da 23 ", git_buf_cstr(&buf)); git_buf_printf(&buf, "%s %d", "woop", 42); cl_assert(git_buf_oom(&buf) == 0); cl_assert_equal_s("shoop da 23 woop 42", git_buf_cstr(&buf)); git_buf_free(&buf); } /* more thorough test of concatenation options */ void test_core_buffer__2(void) { git_buf buf = GIT_BUF_INIT; int i; char data[128]; cl_assert(buf.size == 0); /* this must be safe to do */ git_buf_free(&buf); cl_assert(buf.size == 0); cl_assert(buf.asize == 0); /* empty buffer should be empty string */ cl_assert_equal_s("", git_buf_cstr(&buf)); cl_assert(buf.size == 0); /* cl_assert(buf.asize == 0); -- should not assume what git_buf does */ /* free should set us back to the beginning */ git_buf_free(&buf); cl_assert(buf.size == 0); cl_assert(buf.asize == 0); /* add letter */ git_buf_putc(&buf, '+'); cl_assert(git_buf_oom(&buf) == 0); cl_assert_equal_s("+", git_buf_cstr(&buf)); /* add letter again */ git_buf_putc(&buf, '+'); cl_assert(git_buf_oom(&buf) == 0); cl_assert_equal_s("++", git_buf_cstr(&buf)); /* let's try that a few times */ for (i = 0; i < 16; ++i) { git_buf_putc(&buf, '+'); cl_assert(git_buf_oom(&buf) == 0); } cl_assert_equal_s("++++++++++++++++++", git_buf_cstr(&buf)); git_buf_free(&buf); /* add data */ git_buf_put(&buf, "xo", 2); cl_assert(git_buf_oom(&buf) == 0); cl_assert_equal_s("xo", git_buf_cstr(&buf)); /* add letter again */ git_buf_put(&buf, "xo", 2); cl_assert(git_buf_oom(&buf) == 0); cl_assert_equal_s("xoxo", git_buf_cstr(&buf)); /* let's try that a few times */ for (i = 0; i < 16; ++i) { git_buf_put(&buf, "xo", 2); cl_assert(git_buf_oom(&buf) == 0); } cl_assert_equal_s("xoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxo", git_buf_cstr(&buf)); git_buf_free(&buf); /* set to string */ git_buf_sets(&buf, test_string); cl_assert(git_buf_oom(&buf) == 0); cl_assert_equal_s(test_string, git_buf_cstr(&buf)); /* append string */ git_buf_puts(&buf, test_string); cl_assert(git_buf_oom(&buf) == 0); cl_assert_equal_s(test_string_x2, git_buf_cstr(&buf)); /* set to string again (should overwrite - not append) */ git_buf_sets(&buf, test_string); cl_assert(git_buf_oom(&buf) == 0); cl_assert_equal_s(test_string, git_buf_cstr(&buf)); /* test clear */ git_buf_clear(&buf); cl_assert_equal_s("", git_buf_cstr(&buf)); git_buf_free(&buf); /* test extracting data into buffer */ git_buf_puts(&buf, REP4("0123456789")); cl_assert(git_buf_oom(&buf) == 0); git_buf_copy_cstr(data, sizeof(data), &buf); cl_assert_equal_s(REP4("0123456789"), data); git_buf_copy_cstr(data, 11, &buf); cl_assert_equal_s("0123456789", data); git_buf_copy_cstr(data, 3, &buf); cl_assert_equal_s("01", data); git_buf_copy_cstr(data, 1, &buf); cl_assert_equal_s("", data); git_buf_copy_cstr(data, sizeof(data), &buf); cl_assert_equal_s(REP4("0123456789"), data); git_buf_sets(&buf, REP256("x")); git_buf_copy_cstr(data, sizeof(data), &buf); /* since sizeof(data) == 128, only 127 bytes should be copied */ cl_assert_equal_s(REP4(REP16("x")) REP16("x") REP16("x") REP16("x") "xxxxxxxxxxxxxxx", data); git_buf_free(&buf); git_buf_copy_cstr(data, sizeof(data), &buf); cl_assert_equal_s("", data); } /* let's do some tests with larger buffers to push our limits */ void test_core_buffer__3(void) { git_buf buf = GIT_BUF_INIT; /* set to string */ git_buf_set(&buf, test_4096, 4096); cl_assert(git_buf_oom(&buf) == 0); cl_assert_equal_s(test_4096, git_buf_cstr(&buf)); /* append string */ git_buf_puts(&buf, test_4096); cl_assert(git_buf_oom(&buf) == 0); cl_assert_equal_s(test_8192, git_buf_cstr(&buf)); /* set to string again (should overwrite - not append) */ git_buf_set(&buf, test_4096, 4096); cl_assert(git_buf_oom(&buf) == 0); cl_assert_equal_s(test_4096, git_buf_cstr(&buf)); git_buf_free(&buf); } /* let's try some producer/consumer tests */ void test_core_buffer__4(void) { git_buf buf = GIT_BUF_INIT; int i; for (i = 0; i < 10; ++i) { git_buf_puts(&buf, "1234"); /* add 4 */ cl_assert(git_buf_oom(&buf) == 0); git_buf_consume(&buf, buf.ptr + 2); /* eat the first two */ cl_assert(strlen(git_buf_cstr(&buf)) == (size_t)((i + 1) * 2)); } /* we have appended 1234 10x and removed the first 20 letters */ cl_assert_equal_s("12341234123412341234", git_buf_cstr(&buf)); git_buf_consume(&buf, NULL); cl_assert_equal_s("12341234123412341234", git_buf_cstr(&buf)); git_buf_consume(&buf, "invalid pointer"); cl_assert_equal_s("12341234123412341234", git_buf_cstr(&buf)); git_buf_consume(&buf, buf.ptr); cl_assert_equal_s("12341234123412341234", git_buf_cstr(&buf)); git_buf_consume(&buf, buf.ptr + 1); cl_assert_equal_s("2341234123412341234", git_buf_cstr(&buf)); git_buf_consume(&buf, buf.ptr + buf.size); cl_assert_equal_s("", git_buf_cstr(&buf)); git_buf_free(&buf); } static void check_buf_append( const char* data_a, const char* data_b, const char* expected_data, size_t expected_size, size_t expected_asize) { git_buf tgt = GIT_BUF_INIT; git_buf_sets(&tgt, data_a); cl_assert(git_buf_oom(&tgt) == 0); git_buf_puts(&tgt, data_b); cl_assert(git_buf_oom(&tgt) == 0); cl_assert_equal_s(expected_data, git_buf_cstr(&tgt)); cl_assert(tgt.size == expected_size); if (expected_asize > 0) cl_assert(tgt.asize == expected_asize); git_buf_free(&tgt); } static void check_buf_append_abc( const char* buf_a, const char* buf_b, const char* buf_c, const char* expected_ab, const char* expected_abc, const char* expected_abca, const char* expected_abcab, const char* expected_abcabc) { git_buf buf = GIT_BUF_INIT; git_buf_sets(&buf, buf_a); cl_assert(git_buf_oom(&buf) == 0); cl_assert_equal_s(buf_a, git_buf_cstr(&buf)); git_buf_puts(&buf, buf_b); cl_assert(git_buf_oom(&buf) == 0); cl_assert_equal_s(expected_ab, git_buf_cstr(&buf)); git_buf_puts(&buf, buf_c); cl_assert(git_buf_oom(&buf) == 0); cl_assert_equal_s(expected_abc, git_buf_cstr(&buf)); git_buf_puts(&buf, buf_a); cl_assert(git_buf_oom(&buf) == 0); cl_assert_equal_s(expected_abca, git_buf_cstr(&buf)); git_buf_puts(&buf, buf_b); cl_assert(git_buf_oom(&buf) == 0); cl_assert_equal_s(expected_abcab, git_buf_cstr(&buf)); git_buf_puts(&buf, buf_c); cl_assert(git_buf_oom(&buf) == 0); cl_assert_equal_s(expected_abcabc, git_buf_cstr(&buf)); git_buf_free(&buf); } /* more variations on append tests */ void test_core_buffer__5(void) { check_buf_append("", "", "", 0, 8); check_buf_append("a", "", "a", 1, 8); check_buf_append("", "a", "a", 1, 8); check_buf_append("", "a", "a", 1, 8); check_buf_append("a", "", "a", 1, 8); check_buf_append("a", "b", "ab", 2, 8); check_buf_append("", "abcdefgh", "abcdefgh", 8, 16); check_buf_append("abcdefgh", "", "abcdefgh", 8, 16); /* buffer with starting asize will grow to: * 1 -> 2, 2 -> 3, 3 -> 5, 4 -> 6, 5 -> 8, 6 -> 9, * 7 -> 11, 8 -> 12, 9 -> 14, 10 -> 15, 11 -> 17, 12 -> 18, * 13 -> 20, 14 -> 21, 15 -> 23, 16 -> 24, 17 -> 26, 18 -> 27, * 19 -> 29, 20 -> 30, 21 -> 32, 22 -> 33, 23 -> 35, 24 -> 36, * ... * follow sequence until value > target size, * then round up to nearest multiple of 8. */ check_buf_append("abcdefgh", "/", "abcdefgh/", 9, 16); check_buf_append("abcdefgh", "ijklmno", "abcdefghijklmno", 15, 16); check_buf_append("abcdefgh", "ijklmnop", "abcdefghijklmnop", 16, 24); check_buf_append("0123456789", "0123456789", "01234567890123456789", 20, 24); check_buf_append(REP16("x"), REP16("o"), REP16("x") REP16("o"), 32, 40); check_buf_append(test_4096, "", test_4096, 4096, 4104); check_buf_append(test_4096, test_4096, test_8192, 8192, 9240); /* check sequences of appends */ check_buf_append_abc("a", "b", "c", "ab", "abc", "abca", "abcab", "abcabc"); check_buf_append_abc("a1", "b2", "c3", "a1b2", "a1b2c3", "a1b2c3a1", "a1b2c3a1b2", "a1b2c3a1b2c3"); check_buf_append_abc("a1/", "b2/", "c3/", "a1/b2/", "a1/b2/c3/", "a1/b2/c3/a1/", "a1/b2/c3/a1/b2/", "a1/b2/c3/a1/b2/c3/"); } /* test swap */ void test_core_buffer__6(void) { git_buf a = GIT_BUF_INIT; git_buf b = GIT_BUF_INIT; git_buf_sets(&a, "foo"); cl_assert(git_buf_oom(&a) == 0); git_buf_sets(&b, "bar"); cl_assert(git_buf_oom(&b) == 0); cl_assert_equal_s("foo", git_buf_cstr(&a)); cl_assert_equal_s("bar", git_buf_cstr(&b)); git_buf_swap(&a, &b); cl_assert_equal_s("bar", git_buf_cstr(&a)); cl_assert_equal_s("foo", git_buf_cstr(&b)); git_buf_free(&a); git_buf_free(&b); } /* test detach/attach data */ void test_core_buffer__7(void) { const char *fun = "This is fun"; git_buf a = GIT_BUF_INIT; char *b = NULL; git_buf_sets(&a, "foo"); cl_assert(git_buf_oom(&a) == 0); cl_assert_equal_s("foo", git_buf_cstr(&a)); b = git_buf_detach(&a); cl_assert_equal_s("foo", b); cl_assert_equal_s("", a.ptr); git__free(b); b = git_buf_detach(&a); cl_assert_equal_s(NULL, b); cl_assert_equal_s("", a.ptr); git_buf_free(&a); b = git__strdup(fun); git_buf_attach(&a, b, 0); cl_assert_equal_s(fun, a.ptr); cl_assert(a.size == strlen(fun)); cl_assert(a.asize == strlen(fun) + 1); git_buf_free(&a); b = git__strdup(fun); git_buf_attach(&a, b, strlen(fun) + 1); cl_assert_equal_s(fun, a.ptr); cl_assert(a.size == strlen(fun)); cl_assert(a.asize == strlen(fun) + 1); git_buf_free(&a); } static void check_joinbuf_2( const char *a, const char *b, const char *expected) { char sep = '/'; git_buf buf = GIT_BUF_INIT; git_buf_join(&buf, sep, a, b); cl_assert(git_buf_oom(&buf) == 0); cl_assert_equal_s(expected, git_buf_cstr(&buf)); git_buf_free(&buf); } static void check_joinbuf_n_2( const char *a, const char *b, const char *expected) { char sep = '/'; git_buf buf = GIT_BUF_INIT; git_buf_sets(&buf, a); cl_assert(git_buf_oom(&buf) == 0); git_buf_join_n(&buf, sep, 1, b); cl_assert(git_buf_oom(&buf) == 0); cl_assert_equal_s(expected, git_buf_cstr(&buf)); git_buf_free(&buf); } static void check_joinbuf_n_4( const char *a, const char *b, const char *c, const char *d, const char *expected) { char sep = ';'; git_buf buf = GIT_BUF_INIT; git_buf_join_n(&buf, sep, 4, a, b, c, d); cl_assert(git_buf_oom(&buf) == 0); cl_assert_equal_s(expected, git_buf_cstr(&buf)); git_buf_free(&buf); } /* test join */ void test_core_buffer__8(void) { git_buf a = GIT_BUF_INIT; git_buf_join_n(&a, '/', 1, "foo"); cl_assert(git_buf_oom(&a) == 0); cl_assert_equal_s("foo", git_buf_cstr(&a)); git_buf_join_n(&a, '/', 1, "bar"); cl_assert(git_buf_oom(&a) == 0); cl_assert_equal_s("foo/bar", git_buf_cstr(&a)); git_buf_join_n(&a, '/', 1, "baz"); cl_assert(git_buf_oom(&a) == 0); cl_assert_equal_s("foo/bar/baz", git_buf_cstr(&a)); git_buf_free(&a); check_joinbuf_2(NULL, "", ""); check_joinbuf_2(NULL, "a", "a"); check_joinbuf_2(NULL, "/a", "/a"); check_joinbuf_2("", "", ""); check_joinbuf_2("", "a", "a"); check_joinbuf_2("", "/a", "/a"); check_joinbuf_2("a", "", "a/"); check_joinbuf_2("a", "/", "a/"); check_joinbuf_2("a", "b", "a/b"); check_joinbuf_2("/", "a", "/a"); check_joinbuf_2("/", "", "/"); check_joinbuf_2("/a", "/b", "/a/b"); check_joinbuf_2("/a", "/b/", "/a/b/"); check_joinbuf_2("/a/", "b/", "/a/b/"); check_joinbuf_2("/a/", "/b/", "/a/b/"); check_joinbuf_2("/a/", "//b/", "/a/b/"); check_joinbuf_2("/abcd", "/defg", "/abcd/defg"); check_joinbuf_2("/abcd", "/defg/", "/abcd/defg/"); check_joinbuf_2("/abcd/", "defg/", "/abcd/defg/"); check_joinbuf_2("/abcd/", "/defg/", "/abcd/defg/"); check_joinbuf_n_2("", "", ""); check_joinbuf_n_2("", "a", "a"); check_joinbuf_n_2("", "/a", "/a"); check_joinbuf_n_2("a", "", "a/"); check_joinbuf_n_2("a", "/", "a/"); check_joinbuf_n_2("a", "b", "a/b"); check_joinbuf_n_2("/", "a", "/a"); check_joinbuf_n_2("/", "", "/"); check_joinbuf_n_2("/a", "/b", "/a/b"); check_joinbuf_n_2("/a", "/b/", "/a/b/"); check_joinbuf_n_2("/a/", "b/", "/a/b/"); check_joinbuf_n_2("/a/", "/b/", "/a/b/"); check_joinbuf_n_2("/abcd", "/defg", "/abcd/defg"); check_joinbuf_n_2("/abcd", "/defg/", "/abcd/defg/"); check_joinbuf_n_2("/abcd/", "defg/", "/abcd/defg/"); check_joinbuf_n_2("/abcd/", "/defg/", "/abcd/defg/"); check_joinbuf_n_4("", "", "", "", ""); check_joinbuf_n_4("", "a", "", "", "a;"); check_joinbuf_n_4("a", "", "", "", "a;"); check_joinbuf_n_4("", "", "", "a", "a"); check_joinbuf_n_4("a", "b", "", ";c;d;", "a;b;c;d;"); check_joinbuf_n_4("a", "b", "", ";c;d", "a;b;c;d"); check_joinbuf_n_4("abcd", "efgh", "ijkl", "mnop", "abcd;efgh;ijkl;mnop"); check_joinbuf_n_4("abcd;", "efgh;", "ijkl;", "mnop;", "abcd;efgh;ijkl;mnop;"); check_joinbuf_n_4(";abcd;", ";efgh;", ";ijkl;", ";mnop;", ";abcd;efgh;ijkl;mnop;"); } void test_core_buffer__9(void) { git_buf buf = GIT_BUF_INIT; /* just some exhaustive tests of various separator placement */ char *a[] = { "", "-", "a-", "-a", "-a-" }; char *b[] = { "", "-", "b-", "-b", "-b-" }; char sep[] = { 0, '-', '/' }; char *expect_null[] = { "", "-", "a-", "-a", "-a-", "-", "--", "a--", "-a-", "-a--", "b-", "-b-", "a-b-", "-ab-", "-a-b-", "-b", "--b", "a--b", "-a-b", "-a--b", "-b-", "--b-", "a--b-", "-a-b-", "-a--b-" }; char *expect_dash[] = { "", "-", "a-", "-a-", "-a-", "-", "-", "a-", "-a-", "-a-", "b-", "-b-", "a-b-", "-a-b-", "-a-b-", "-b", "-b", "a-b", "-a-b", "-a-b", "-b-", "-b-", "a-b-", "-a-b-", "-a-b-" }; char *expect_slas[] = { "", "-/", "a-/", "-a/", "-a-/", "-", "-/-", "a-/-", "-a/-", "-a-/-", "b-", "-/b-", "a-/b-", "-a/b-", "-a-/b-", "-b", "-/-b", "a-/-b", "-a/-b", "-a-/-b", "-b-", "-/-b-", "a-/-b-", "-a/-b-", "-a-/-b-" }; char **expect_values[] = { expect_null, expect_dash, expect_slas }; char separator, **expect; unsigned int s, i, j; for (s = 0; s < sizeof(sep) / sizeof(char); ++s) { separator = sep[s]; expect = expect_values[s]; for (j = 0; j < sizeof(b) / sizeof(char*); ++j) { for (i = 0; i < sizeof(a) / sizeof(char*); ++i) { git_buf_join(&buf, separator, a[i], b[j]); cl_assert_equal_s(*expect, buf.ptr); expect++; } } } git_buf_free(&buf); } void test_core_buffer__10(void) { git_buf a = GIT_BUF_INIT; cl_git_pass(git_buf_join_n(&a, '/', 1, "test")); cl_assert_equal_s(a.ptr, "test"); cl_git_pass(git_buf_join_n(&a, '/', 1, "string")); cl_assert_equal_s(a.ptr, "test/string"); git_buf_clear(&a); cl_git_pass(git_buf_join_n(&a, '/', 3, "test", "string", "join")); cl_assert_equal_s(a.ptr, "test/string/join"); cl_git_pass(git_buf_join_n(&a, '/', 2, a.ptr, "more")); cl_assert_equal_s(a.ptr, "test/string/join/test/string/join/more"); git_buf_free(&a); } void test_core_buffer__11(void) { git_buf a = GIT_BUF_INIT; git_strarray t; char *t1[] = { "nothing", "in", "common" }; char *t2[] = { "something", "something else", "some other" }; char *t3[] = { "something", "some fun", "no fun" }; char *t4[] = { "happy", "happier", "happiest" }; char *t5[] = { "happiest", "happier", "happy" }; char *t6[] = { "no", "nope", "" }; char *t7[] = { "", "doesn't matter" }; t.strings = t1; t.count = 3; cl_git_pass(git_buf_text_common_prefix(&a, &t)); cl_assert_equal_s(a.ptr, ""); t.strings = t2; t.count = 3; cl_git_pass(git_buf_text_common_prefix(&a, &t)); cl_assert_equal_s(a.ptr, "some"); t.strings = t3; t.count = 3; cl_git_pass(git_buf_text_common_prefix(&a, &t)); cl_assert_equal_s(a.ptr, ""); t.strings = t4; t.count = 3; cl_git_pass(git_buf_text_common_prefix(&a, &t)); cl_assert_equal_s(a.ptr, "happ"); t.strings = t5; t.count = 3; cl_git_pass(git_buf_text_common_prefix(&a, &t)); cl_assert_equal_s(a.ptr, "happ"); t.strings = t6; t.count = 3; cl_git_pass(git_buf_text_common_prefix(&a, &t)); cl_assert_equal_s(a.ptr, ""); t.strings = t7; t.count = 3; cl_git_pass(git_buf_text_common_prefix(&a, &t)); cl_assert_equal_s(a.ptr, ""); git_buf_free(&a); } void test_core_buffer__rfind_variants(void) { git_buf a = GIT_BUF_INIT; ssize_t len; cl_git_pass(git_buf_sets(&a, "/this/is/it/")); len = (ssize_t)git_buf_len(&a); cl_assert(git_buf_rfind(&a, '/') == len - 1); cl_assert(git_buf_rfind_next(&a, '/') == len - 4); cl_assert(git_buf_rfind(&a, 'i') == len - 3); cl_assert(git_buf_rfind_next(&a, 'i') == len - 3); cl_assert(git_buf_rfind(&a, 'h') == 2); cl_assert(git_buf_rfind_next(&a, 'h') == 2); cl_assert(git_buf_rfind(&a, 'q') == -1); cl_assert(git_buf_rfind_next(&a, 'q') == -1); git_buf_free(&a); } void test_core_buffer__puts_escaped(void) { git_buf a = GIT_BUF_INIT; git_buf_clear(&a); cl_git_pass(git_buf_text_puts_escaped(&a, "this is a test", "", "")); cl_assert_equal_s("this is a test", a.ptr); git_buf_clear(&a); cl_git_pass(git_buf_text_puts_escaped(&a, "this is a test", "t", "\\")); cl_assert_equal_s("\\this is a \\tes\\t", a.ptr); git_buf_clear(&a); cl_git_pass(git_buf_text_puts_escaped(&a, "this is a test", "i ", "__")); cl_assert_equal_s("th__is__ __is__ a__ test", a.ptr); git_buf_clear(&a); cl_git_pass(git_buf_text_puts_escape_regex(&a, "^match\\s*[A-Z]+.*")); cl_assert_equal_s("\\^match\\\\s\\*\\[A-Z\\]\\+\\.\\*", a.ptr); git_buf_free(&a); } static void assert_unescape(char *expected, char *to_unescape) { git_buf buf = GIT_BUF_INIT; cl_git_pass(git_buf_sets(&buf, to_unescape)); git_buf_text_unescape(&buf); cl_assert_equal_s(expected, buf.ptr); cl_assert_equal_sz(strlen(expected), buf.size); git_buf_free(&buf); } void test_core_buffer__unescape(void) { assert_unescape("Escaped\\", "Es\\ca\\ped\\"); assert_unescape("Es\\caped\\", "Es\\\\ca\\ped\\\\"); assert_unescape("\\", "\\"); assert_unescape("\\", "\\\\"); assert_unescape("", ""); } void test_core_buffer__base64(void) { git_buf buf = GIT_BUF_INIT; /* t h i s * 0x 74 68 69 73 * 0b 01110100 01101000 01101001 01110011 * 0b 011101 000110 100001 101001 011100 110000 * 0x 1d 06 21 29 1c 30 * d G h p c w */ cl_git_pass(git_buf_put_base64(&buf, "this", 4)); cl_assert_equal_s("dGhpcw==", buf.ptr); git_buf_clear(&buf); cl_git_pass(git_buf_put_base64(&buf, "this!", 5)); cl_assert_equal_s("dGhpcyE=", buf.ptr); git_buf_clear(&buf); cl_git_pass(git_buf_put_base64(&buf, "this!\n", 6)); cl_assert_equal_s("dGhpcyEK", buf.ptr); git_buf_free(&buf); } void test_core_buffer__classify_with_utf8(void) { char *data0 = "Simple text\n"; size_t data0len = 12; char *data1 = "Is that UTF-8 data I see…\nYep!\n"; size_t data1len = 31; char *data2 = "Internal NUL!!!\000\n\nI see you!\n"; size_t data2len = 29; git_buf b; b.ptr = data0; b.size = b.asize = data0len; cl_assert(!git_buf_text_is_binary(&b)); cl_assert(!git_buf_text_contains_nul(&b)); b.ptr = data1; b.size = b.asize = data1len; cl_assert(git_buf_text_is_binary(&b)); cl_assert(!git_buf_text_contains_nul(&b)); b.ptr = data2; b.size = b.asize = data2len; cl_assert(git_buf_text_is_binary(&b)); cl_assert(git_buf_text_contains_nul(&b)); } #define SIMILARITY_TEST_DATA_1 \ "test data\nright here\ninline\ntada\nneeds more data\nlots of data\n" \ "is this enough?\nthere has to be enough data to fill the hash array!\n" \ "Apparently 191 bytes is the minimum amount of data needed.\nHere goes!\n" \ "Let's make sure we've got plenty to go with here.\n smile \n" void test_core_buffer__similarity_metric(void) { git_hashsig *a, *b; git_buf buf = GIT_BUF_INIT; int sim; /* in the first case, we compare data to itself and expect 100% match */ cl_git_pass(git_buf_sets(&buf, SIMILARITY_TEST_DATA_1)); cl_git_pass(git_hashsig_create(&a, buf.ptr, buf.size, GIT_HASHSIG_NORMAL)); cl_git_pass(git_hashsig_create(&b, buf.ptr, buf.size, GIT_HASHSIG_NORMAL)); cl_assert_equal_i(100, git_hashsig_compare(a, b)); git_hashsig_free(a); git_hashsig_free(b); /* if we change just a single byte, how much does that change magnify? */ cl_git_pass(git_buf_sets(&buf, SIMILARITY_TEST_DATA_1)); cl_git_pass(git_hashsig_create(&a, buf.ptr, buf.size, GIT_HASHSIG_NORMAL)); cl_git_pass(git_buf_sets(&buf, "Test data\nright here\ninline\ntada\nneeds more data\nlots of data\n" "is this enough?\nthere has to be enough data to fill the hash array!\n" "Apparently 191 bytes is the minimum amount of data needed.\nHere goes!\n" "Let's make sure we've got plenty to go with here.\n smile \n")); cl_git_pass(git_hashsig_create(&b, buf.ptr, buf.size, GIT_HASHSIG_NORMAL)); sim = git_hashsig_compare(a, b); cl_assert(95 < sim && sim < 100); /* expect >95% similarity */ git_hashsig_free(a); git_hashsig_free(b); /* let's try comparing data to a superset of itself */ cl_git_pass(git_buf_sets(&buf, SIMILARITY_TEST_DATA_1)); cl_git_pass(git_hashsig_create(&a, buf.ptr, buf.size, GIT_HASHSIG_NORMAL)); cl_git_pass(git_buf_sets(&buf, SIMILARITY_TEST_DATA_1 "and if I add some more, it should still be pretty similar, yes?\n")); cl_git_pass(git_hashsig_create(&b, buf.ptr, buf.size, GIT_HASHSIG_NORMAL)); sim = git_hashsig_compare(a, b); cl_assert(70 < sim && sim < 80); /* expect in the 70-80% similarity range */ git_hashsig_free(a); git_hashsig_free(b); /* what if we keep about half the original data and add half new */ cl_git_pass(git_buf_sets(&buf, SIMILARITY_TEST_DATA_1)); cl_git_pass(git_hashsig_create(&a, buf.ptr, buf.size, GIT_HASHSIG_NORMAL)); cl_git_pass(git_buf_sets(&buf, "test data\nright here\ninline\ntada\nneeds more data\nlots of data\n" "is this enough?\nthere has to be enough data to fill the hash array!\n" "okay, that's half the original\nwhat else can we add?\nmore data\n" "one more line will complete this\nshort\nlines\ndon't\nmatter\n")); cl_git_pass(git_hashsig_create(&b, buf.ptr, buf.size, GIT_HASHSIG_NORMAL)); sim = git_hashsig_compare(a, b); cl_assert(40 < sim && sim < 60); /* expect in the 40-60% similarity range */ git_hashsig_free(a); git_hashsig_free(b); /* lastly, let's check that we can hash file content as well */ cl_git_pass(git_buf_sets(&buf, SIMILARITY_TEST_DATA_1)); cl_git_pass(git_hashsig_create(&a, buf.ptr, buf.size, GIT_HASHSIG_NORMAL)); cl_git_pass(git_futils_mkdir("scratch", NULL, 0755, GIT_MKDIR_PATH)); cl_git_mkfile("scratch/testdata", SIMILARITY_TEST_DATA_1); cl_git_pass(git_hashsig_create_fromfile( &b, "scratch/testdata", GIT_HASHSIG_NORMAL)); cl_assert_equal_i(100, git_hashsig_compare(a, b)); git_hashsig_free(a); git_hashsig_free(b); git_buf_free(&buf); git_futils_rmdir_r("scratch", NULL, GIT_RMDIR_REMOVE_FILES); } void test_core_buffer__similarity_metric_whitespace(void) { git_hashsig *a, *b; git_buf buf = GIT_BUF_INIT; int sim, i, j; git_hashsig_option_t opt; const char *tabbed = " for (s = 0; s < sizeof(sep) / sizeof(char); ++s) {\n" " separator = sep[s];\n" " expect = expect_values[s];\n" "\n" " for (j = 0; j < sizeof(b) / sizeof(char*); ++j) {\n" " for (i = 0; i < sizeof(a) / sizeof(char*); ++i) {\n" " git_buf_join(&buf, separator, a[i], b[j]);\n" " cl_assert_equal_s(*expect, buf.ptr);\n" " expect++;\n" " }\n" " }\n" " }\n"; const char *spaced = " for (s = 0; s < sizeof(sep) / sizeof(char); ++s) {\n" " separator = sep[s];\n" " expect = expect_values[s];\n" "\n" " for (j = 0; j < sizeof(b) / sizeof(char*); ++j) {\n" " for (i = 0; i < sizeof(a) / sizeof(char*); ++i) {\n" " git_buf_join(&buf, separator, a[i], b[j]);\n" " cl_assert_equal_s(*expect, buf.ptr);\n" " expect++;\n" " }\n" " }\n" " }\n"; const char *crlf_spaced2 = " for (s = 0; s < sizeof(sep) / sizeof(char); ++s) {\r\n" " separator = sep[s];\r\n" " expect = expect_values[s];\r\n" "\r\n" " for (j = 0; j < sizeof(b) / sizeof(char*); ++j) {\r\n" " for (i = 0; i < sizeof(a) / sizeof(char*); ++i) {\r\n" " git_buf_join(&buf, separator, a[i], b[j]);\r\n" " cl_assert_equal_s(*expect, buf.ptr);\r\n" " expect++;\r\n" " }\r\n" " }\r\n" " }\r\n"; const char *text[3] = { tabbed, spaced, crlf_spaced2 }; /* let's try variations of our own code with whitespace changes */ for (opt = GIT_HASHSIG_NORMAL; opt <= GIT_HASHSIG_SMART_WHITESPACE; ++opt) { for (i = 0; i < 3; ++i) { for (j = 0; j < 3; ++j) { cl_git_pass(git_buf_sets(&buf, text[i])); cl_git_pass(git_hashsig_create(&a, buf.ptr, buf.size, opt)); cl_git_pass(git_buf_sets(&buf, text[j])); cl_git_pass(git_hashsig_create(&b, buf.ptr, buf.size, opt)); sim = git_hashsig_compare(a, b); if (opt == GIT_HASHSIG_NORMAL) { if (i == j) cl_assert_equal_i(100, sim); else cl_assert(sim < 30); /* expect pretty different */ } else { cl_assert_equal_i(100, sim); } git_hashsig_free(a); git_hashsig_free(b); } } } git_buf_free(&buf); } #define check_buf(expected,buf) do { \ cl_assert_equal_s(expected, buf.ptr); \ cl_assert_equal_sz(strlen(expected), buf.size); } while (0) void test_core_buffer__lf_and_crlf_conversions(void) { git_buf src = GIT_BUF_INIT, tgt = GIT_BUF_INIT; /* LF source */ git_buf_sets(&src, "lf\nlf\nlf\nlf\n"); cl_git_pass(git_buf_text_lf_to_crlf(&tgt, &src)); check_buf("lf\r\nlf\r\nlf\r\nlf\r\n", tgt); cl_assert_equal_i(GIT_ENOTFOUND, git_buf_text_crlf_to_lf(&tgt, &src)); /* no conversion needed if all LFs already */ git_buf_sets(&src, "\nlf\nlf\nlf\nlf\nlf"); cl_git_pass(git_buf_text_lf_to_crlf(&tgt, &src)); check_buf("\r\nlf\r\nlf\r\nlf\r\nlf\r\nlf", tgt); cl_assert_equal_i(GIT_ENOTFOUND, git_buf_text_crlf_to_lf(&tgt, &src)); /* no conversion needed if all LFs already */ /* CRLF source */ git_buf_sets(&src, "crlf\r\ncrlf\r\ncrlf\r\ncrlf\r\n"); cl_git_pass(git_buf_text_lf_to_crlf(&tgt, &src)); check_buf("crlf\r\ncrlf\r\ncrlf\r\ncrlf\r\n", tgt); check_buf(src.ptr, tgt); cl_git_pass(git_buf_text_crlf_to_lf(&tgt, &src)); check_buf("crlf\ncrlf\ncrlf\ncrlf\n", tgt); git_buf_sets(&src, "\r\ncrlf\r\ncrlf\r\ncrlf\r\ncrlf\r\ncrlf"); cl_git_pass(git_buf_text_lf_to_crlf(&tgt, &src)); check_buf("\r\ncrlf\r\ncrlf\r\ncrlf\r\ncrlf\r\ncrlf", tgt); check_buf(src.ptr, tgt); cl_git_pass(git_buf_text_crlf_to_lf(&tgt, &src)); check_buf("\ncrlf\ncrlf\ncrlf\ncrlf\ncrlf", tgt); /* CRLF in LF text */ git_buf_sets(&src, "\nlf\nlf\ncrlf\r\nlf\nlf\ncrlf\r\n"); cl_git_pass(git_buf_text_lf_to_crlf(&tgt, &src)); check_buf("\r\nlf\r\nlf\r\ncrlf\r\nlf\r\nlf\r\ncrlf\r\n", tgt); cl_git_pass(git_buf_text_crlf_to_lf(&tgt, &src)); check_buf("\nlf\nlf\ncrlf\nlf\nlf\ncrlf\n", tgt); /* LF in CRLF text */ git_buf_sets(&src, "\ncrlf\r\ncrlf\r\nlf\ncrlf\r\ncrlf"); cl_git_pass(git_buf_text_lf_to_crlf(&tgt, &src)); check_buf("\r\ncrlf\r\ncrlf\r\nlf\r\ncrlf\r\ncrlf", tgt); cl_git_pass(git_buf_text_crlf_to_lf(&tgt, &src)); check_buf("\ncrlf\ncrlf\nlf\ncrlf\ncrlf", tgt); /* bare CR test */ git_buf_sets(&src, "\rcrlf\r\nlf\nlf\ncr\rcrlf\r\nlf\ncr\r"); cl_git_pass(git_buf_text_lf_to_crlf(&tgt, &src)); check_buf("\rcrlf\r\nlf\r\nlf\r\ncr\rcrlf\r\nlf\r\ncr\r", tgt); cl_git_pass(git_buf_text_crlf_to_lf(&tgt, &src)); check_buf("\rcrlf\nlf\nlf\ncr\rcrlf\nlf\ncr\r", tgt); git_buf_sets(&src, "\rcr\r"); cl_assert_equal_i(GIT_ENOTFOUND, git_buf_text_lf_to_crlf(&tgt, &src)); cl_git_pass(git_buf_text_crlf_to_lf(&tgt, &src)); check_buf("\rcr\r", tgt); git_buf_free(&src); git_buf_free(&tgt); } libgit2-0.19.0/tests-clar/core/copy.c000066400000000000000000000071641216214232500172720ustar00rootroot00000000000000#include "clar_libgit2.h" #include "fileops.h" #include "path.h" #include "posix.h" void test_core_copy__file(void) { struct stat st; const char *content = "This is some stuff to copy\n"; cl_git_mkfile("copy_me", content); cl_git_pass(git_futils_cp("copy_me", "copy_me_two", 0664)); cl_git_pass(git_path_lstat("copy_me_two", &st)); cl_assert(S_ISREG(st.st_mode)); cl_assert(strlen(content) == (size_t)st.st_size); cl_git_pass(p_unlink("copy_me_two")); cl_git_pass(p_unlink("copy_me")); } void test_core_copy__file_in_dir(void) { struct stat st; const char *content = "This is some other stuff to copy\n"; cl_git_pass(git_futils_mkdir("an_dir/in_a_dir", NULL, 0775, GIT_MKDIR_PATH)); cl_git_mkfile("an_dir/in_a_dir/copy_me", content); cl_assert(git_path_isdir("an_dir")); cl_git_pass(git_futils_mkpath2file ("an_dir/second_dir/and_more/copy_me_two", 0775)); cl_git_pass(git_futils_cp ("an_dir/in_a_dir/copy_me", "an_dir/second_dir/and_more/copy_me_two", 0664)); cl_git_pass(git_path_lstat("an_dir/second_dir/and_more/copy_me_two", &st)); cl_assert(S_ISREG(st.st_mode)); cl_assert(strlen(content) == (size_t)st.st_size); cl_git_pass(git_futils_rmdir_r("an_dir", NULL, GIT_RMDIR_REMOVE_FILES)); cl_assert(!git_path_isdir("an_dir")); } void test_core_copy__tree(void) { struct stat st; const char *content = "File content\n"; cl_git_pass(git_futils_mkdir("src/b", NULL, 0775, GIT_MKDIR_PATH)); cl_git_pass(git_futils_mkdir("src/c/d", NULL, 0775, GIT_MKDIR_PATH)); cl_git_pass(git_futils_mkdir("src/c/e", NULL, 0775, GIT_MKDIR_PATH)); cl_git_mkfile("src/f1", content); cl_git_mkfile("src/b/f2", content); cl_git_mkfile("src/c/f3", content); cl_git_mkfile("src/c/d/f4", content); cl_git_mkfile("src/c/d/.f5", content); #ifndef GIT_WIN32 cl_assert(p_symlink("../../b/f2", "src/c/d/l1") == 0); #endif cl_assert(git_path_isdir("src")); cl_assert(git_path_isdir("src/b")); cl_assert(git_path_isdir("src/c/d")); cl_assert(git_path_isfile("src/c/d/f4")); /* copy with no empty dirs, yes links, no dotfiles, no overwrite */ cl_git_pass( git_futils_cp_r("src", "t1", GIT_CPDIR_COPY_SYMLINKS, 0) ); cl_assert(git_path_isdir("t1")); cl_assert(git_path_isdir("t1/b")); cl_assert(git_path_isdir("t1/c")); cl_assert(git_path_isdir("t1/c/d")); cl_assert(!git_path_isdir("t1/c/e")); cl_assert(git_path_isfile("t1/f1")); cl_assert(git_path_isfile("t1/b/f2")); cl_assert(git_path_isfile("t1/c/f3")); cl_assert(git_path_isfile("t1/c/d/f4")); cl_assert(!git_path_isfile("t1/c/d/.f5")); cl_git_pass(git_path_lstat("t1/c/f3", &st)); cl_assert(S_ISREG(st.st_mode)); cl_assert(strlen(content) == (size_t)st.st_size); #ifndef GIT_WIN32 cl_git_pass(git_path_lstat("t1/c/d/l1", &st)); cl_assert(S_ISLNK(st.st_mode)); #endif cl_git_pass(git_futils_rmdir_r("t1", NULL, GIT_RMDIR_REMOVE_FILES)); cl_assert(!git_path_isdir("t1")); /* copy with empty dirs, no links, yes dotfiles, no overwrite */ cl_git_pass( git_futils_cp_r("src", "t2", GIT_CPDIR_CREATE_EMPTY_DIRS | GIT_CPDIR_COPY_DOTFILES, 0) ); cl_assert(git_path_isdir("t2")); cl_assert(git_path_isdir("t2/b")); cl_assert(git_path_isdir("t2/c")); cl_assert(git_path_isdir("t2/c/d")); cl_assert(git_path_isdir("t2/c/e")); cl_assert(git_path_isfile("t2/f1")); cl_assert(git_path_isfile("t2/b/f2")); cl_assert(git_path_isfile("t2/c/f3")); cl_assert(git_path_isfile("t2/c/d/f4")); cl_assert(git_path_isfile("t2/c/d/.f5")); #ifndef GIT_WIN32 cl_git_fail(git_path_lstat("t2/c/d/l1", &st)); #endif cl_git_pass(git_futils_rmdir_r("t2", NULL, GIT_RMDIR_REMOVE_FILES)); cl_assert(!git_path_isdir("t2")); cl_git_pass(git_futils_rmdir_r("src", NULL, GIT_RMDIR_REMOVE_FILES)); } libgit2-0.19.0/tests-clar/core/dirent.c000066400000000000000000000100741216214232500175770ustar00rootroot00000000000000#include "clar_libgit2.h" #include "fileops.h" typedef struct name_data { int count; /* return count */ char *name; /* filename */ } name_data; typedef struct walk_data { char *sub; /* sub-directory name */ name_data *names; /* name state data */ git_buf path; } walk_data; static char *top_dir = "dir-walk"; static walk_data *state_loc; static void setup(walk_data *d) { name_data *n; cl_must_pass(p_mkdir(top_dir, 0777)); cl_must_pass(p_chdir(top_dir)); if (strcmp(d->sub, ".") != 0) cl_must_pass(p_mkdir(d->sub, 0777)); cl_git_pass(git_buf_sets(&d->path, d->sub)); state_loc = d; for (n = d->names; n->name; n++) { git_file fd = p_creat(n->name, 0666); cl_assert(fd >= 0); p_close(fd); n->count = 0; } } static void dirent_cleanup__cb(void *_d) { walk_data *d = _d; name_data *n; for (n = d->names; n->name; n++) { cl_must_pass(p_unlink(n->name)); } if (strcmp(d->sub, ".") != 0) cl_must_pass(p_rmdir(d->sub)); cl_must_pass(p_chdir("..")); cl_must_pass(p_rmdir(top_dir)); git_buf_free(&d->path); } static void check_counts(walk_data *d) { name_data *n; for (n = d->names; n->name; n++) { cl_assert(n->count == 1); } } static int one_entry(void *state, git_buf *path) { walk_data *d = (walk_data *) state; name_data *n; if (state != state_loc) return GIT_ERROR; if (path != &d->path) return GIT_ERROR; for (n = d->names; n->name; n++) { if (!strcmp(n->name, path->ptr)) { n->count++; return 0; } } return GIT_ERROR; } static int dont_call_me(void *state, git_buf *path) { GIT_UNUSED(state); GIT_UNUSED(path); return GIT_ERROR; } static name_data dot_names[] = { { 0, "./a" }, { 0, "./asdf" }, { 0, "./pack-foo.pack" }, { 0, NULL } }; static walk_data dot = { ".", dot_names, GIT_BUF_INIT }; /* make sure that the '.' folder is not traversed */ void test_core_dirent__dont_traverse_dot(void) { cl_set_cleanup(&dirent_cleanup__cb, &dot); setup(&dot); cl_git_pass(git_path_direach(&dot.path, one_entry, &dot)); check_counts(&dot); } static name_data sub_names[] = { { 0, "sub/a" }, { 0, "sub/asdf" }, { 0, "sub/pack-foo.pack" }, { 0, NULL } }; static walk_data sub = { "sub", sub_names, GIT_BUF_INIT }; /* traverse a subfolder */ void test_core_dirent__traverse_subfolder(void) { cl_set_cleanup(&dirent_cleanup__cb, &sub); setup(&sub); cl_git_pass(git_path_direach(&sub.path, one_entry, &sub)); check_counts(&sub); } static walk_data sub_slash = { "sub/", sub_names, GIT_BUF_INIT }; /* traverse a slash-terminated subfolder */ void test_core_dirent__traverse_slash_terminated_folder(void) { cl_set_cleanup(&dirent_cleanup__cb, &sub_slash); setup(&sub_slash); cl_git_pass(git_path_direach(&sub_slash.path, one_entry, &sub_slash)); check_counts(&sub_slash); } static name_data empty_names[] = { { 0, NULL } }; static walk_data empty = { "empty", empty_names, GIT_BUF_INIT }; /* make sure that empty folders are not traversed */ void test_core_dirent__dont_traverse_empty_folders(void) { cl_set_cleanup(&dirent_cleanup__cb, &empty); setup(&empty); cl_git_pass(git_path_direach(&empty.path, one_entry, &empty)); check_counts(&empty); /* make sure callback not called */ cl_git_pass(git_path_direach(&empty.path, dont_call_me, &empty)); } static name_data odd_names[] = { { 0, "odd/.a" }, { 0, "odd/..c" }, /* the following don't work on cygwin/win32 */ /* { 0, "odd/.b." }, */ /* { 0, "odd/..d.." }, */ { 0, NULL } }; static walk_data odd = { "odd", odd_names, GIT_BUF_INIT }; /* make sure that strange looking filenames ('..c') are traversed */ void test_core_dirent__traverse_weird_filenames(void) { cl_set_cleanup(&dirent_cleanup__cb, &odd); setup(&odd); cl_git_pass(git_path_direach(&odd.path, one_entry, &odd)); check_counts(&odd); } /* test filename length limits */ void test_core_dirent__length_limits(void) { char *big_filename = (char *)git__malloc(FILENAME_MAX + 1); memset(big_filename, 'a', FILENAME_MAX + 1); big_filename[FILENAME_MAX] = 0; cl_must_fail(p_creat(big_filename, 0666)); git__free(big_filename); } libgit2-0.19.0/tests-clar/core/env.c000066400000000000000000000175071216214232500171120ustar00rootroot00000000000000#include "clar_libgit2.h" #include "fileops.h" #include "path.h" #ifdef GIT_WIN32 #define NUM_VARS 5 static const char *env_vars[NUM_VARS] = { "HOME", "HOMEDRIVE", "HOMEPATH", "USERPROFILE", "PROGRAMFILES" }; #else #define NUM_VARS 1 static const char *env_vars[NUM_VARS] = { "HOME" }; #endif static char *env_save[NUM_VARS]; static char *home_values[] = { "fake_home", "f\xc3\xa1ke_h\xc3\xb5me", /* all in latin-1 supplement */ "f\xc4\x80ke_\xc4\xa4ome", /* latin extended */ "f\xce\xb1\xce\xba\xce\xb5_h\xce\xbfm\xce\xad", /* having fun with greek */ "fa\xe0" "\xb8" "\x87" "e_\xe0" "\xb8" "\x99" "ome", /* thai characters */ "f\xe1\x9cx80ke_\xe1\x9c\x91ome", /* tagalog characters */ "\xe1\xb8\x9f\xe1\xba\xa2" "ke_ho" "\xe1" "\xb9" "\x81" "e", /* latin extended additional */ "\xf0\x9f\x98\x98\xf0\x9f\x98\x82", /* emoticons */ NULL }; void test_core_env__initialize(void) { int i; for (i = 0; i < NUM_VARS; ++i) { const char *original = cl_getenv(env_vars[i]); #ifdef GIT_WIN32 env_save[i] = (char *)original; #else env_save[i] = original ? git__strdup(original) : NULL; #endif } } static void reset_global_search_path(void) { cl_git_pass(git_futils_dirs_set(GIT_FUTILS_DIR_GLOBAL, NULL)); } static void reset_system_search_path(void) { cl_git_pass(git_futils_dirs_set(GIT_FUTILS_DIR_SYSTEM, NULL)); } void test_core_env__cleanup(void) { int i; char **val; for (i = 0; i < NUM_VARS; ++i) { cl_setenv(env_vars[i], env_save[i]); git__free(env_save[i]); env_save[i] = NULL; } /* these will probably have already been cleaned up, but if a test * fails, then it's probably good to try and clear out these dirs */ for (val = home_values; *val != NULL; val++) { if (**val != '\0') (void)p_rmdir(*val); } /* reset search paths to default */ reset_global_search_path(); reset_system_search_path(); } static void setenv_and_check(const char *name, const char *value) { char *check; cl_git_pass(cl_setenv(name, value)); check = cl_getenv(name); cl_assert_equal_s(value, check); #ifdef GIT_WIN32 git__free(check); #endif } void test_core_env__0(void) { git_buf path = GIT_BUF_INIT, found = GIT_BUF_INIT; char testfile[16], tidx = '0'; char **val; const char *testname = "testfile"; size_t testlen = strlen(testname); strncpy(testfile, testname, sizeof(testfile)); cl_assert_equal_s(testname, testfile); for (val = home_values; *val != NULL; val++) { /* if we can't make the directory, let's just assume * we are on a filesystem that doesn't support the * characters in question and skip this test... */ if (p_mkdir(*val, 0777) != 0) { *val = ""; /* mark as not created */ continue; } cl_git_pass(git_path_prettify(&path, *val, NULL)); /* vary testfile name in each directory so accidentally leaving * an environment variable set from a previous iteration won't * accidentally make this test pass... */ testfile[testlen] = tidx++; cl_git_pass(git_buf_joinpath(&path, path.ptr, testfile)); cl_git_mkfile(path.ptr, "find me"); git_buf_rtruncate_at_char(&path, '/'); cl_assert_equal_i( GIT_ENOTFOUND, git_futils_find_global_file(&found, testfile)); setenv_and_check("HOME", path.ptr); reset_global_search_path(); cl_git_pass(git_futils_find_global_file(&found, testfile)); cl_setenv("HOME", env_save[0]); reset_global_search_path(); cl_assert_equal_i( GIT_ENOTFOUND, git_futils_find_global_file(&found, testfile)); #ifdef GIT_WIN32 setenv_and_check("HOMEDRIVE", NULL); setenv_and_check("HOMEPATH", NULL); setenv_and_check("USERPROFILE", path.ptr); reset_global_search_path(); cl_git_pass(git_futils_find_global_file(&found, testfile)); { int root = git_path_root(path.ptr); char old; if (root >= 0) { setenv_and_check("USERPROFILE", NULL); reset_global_search_path(); cl_assert_equal_i( GIT_ENOTFOUND, git_futils_find_global_file(&found, testfile)); old = path.ptr[root]; path.ptr[root] = '\0'; setenv_and_check("HOMEDRIVE", path.ptr); path.ptr[root] = old; setenv_and_check("HOMEPATH", &path.ptr[root]); reset_global_search_path(); cl_git_pass(git_futils_find_global_file(&found, testfile)); } } #endif (void)p_rmdir(*val); } git_buf_free(&path); git_buf_free(&found); } void test_core_env__1(void) { git_buf path = GIT_BUF_INIT; cl_assert_equal_i( GIT_ENOTFOUND, git_futils_find_global_file(&path, "nonexistentfile")); cl_git_pass(cl_setenv("HOME", "doesnotexist")); #ifdef GIT_WIN32 cl_git_pass(cl_setenv("HOMEPATH", "doesnotexist")); cl_git_pass(cl_setenv("USERPROFILE", "doesnotexist")); #endif reset_global_search_path(); cl_assert_equal_i( GIT_ENOTFOUND, git_futils_find_global_file(&path, "nonexistentfile")); cl_git_pass(cl_setenv("HOME", NULL)); #ifdef GIT_WIN32 cl_git_pass(cl_setenv("HOMEPATH", NULL)); cl_git_pass(cl_setenv("USERPROFILE", NULL)); #endif reset_global_search_path(); reset_system_search_path(); cl_assert_equal_i( GIT_ENOTFOUND, git_futils_find_global_file(&path, "nonexistentfile")); cl_assert_equal_i( GIT_ENOTFOUND, git_futils_find_system_file(&path, "nonexistentfile")); #ifdef GIT_WIN32 cl_git_pass(cl_setenv("PROGRAMFILES", NULL)); reset_system_search_path(); cl_assert_equal_i( GIT_ENOTFOUND, git_futils_find_system_file(&path, "nonexistentfile")); #endif git_buf_free(&path); } static void check_global_searchpath( const char *path, int position, const char *file, git_buf *temp) { char out[GIT_PATH_MAX]; /* build and set new path */ if (position < 0) cl_git_pass(git_buf_join(temp, GIT_PATH_LIST_SEPARATOR, path, "$PATH")); else if (position > 0) cl_git_pass(git_buf_join(temp, GIT_PATH_LIST_SEPARATOR, "$PATH", path)); else cl_git_pass(git_buf_sets(temp, path)); cl_git_pass(git_libgit2_opts( GIT_OPT_SET_SEARCH_PATH, GIT_CONFIG_LEVEL_GLOBAL, temp->ptr)); /* get path and make sure $PATH expansion worked */ cl_git_pass(git_libgit2_opts( GIT_OPT_GET_SEARCH_PATH, GIT_CONFIG_LEVEL_GLOBAL, out, sizeof(out))); if (position < 0) cl_assert(git__prefixcmp(out, path) == 0); else if (position > 0) cl_assert(git__suffixcmp(out, path) == 0); else cl_assert_equal_s(out, path); /* find file using new path */ cl_git_pass(git_futils_find_global_file(temp, file)); /* reset path and confirm file not found */ cl_git_pass(git_libgit2_opts( GIT_OPT_SET_SEARCH_PATH, GIT_CONFIG_LEVEL_GLOBAL, NULL)); cl_assert_equal_i( GIT_ENOTFOUND, git_futils_find_global_file(temp, file)); } void test_core_env__2(void) { git_buf path = GIT_BUF_INIT, found = GIT_BUF_INIT; char testfile[16], tidx = '0'; char **val; const char *testname = "alternate"; size_t testlen = strlen(testname); strncpy(testfile, testname, sizeof(testfile)); cl_assert_equal_s(testname, testfile); for (val = home_values; *val != NULL; val++) { /* if we can't make the directory, let's just assume * we are on a filesystem that doesn't support the * characters in question and skip this test... */ if (p_mkdir(*val, 0777) != 0 && errno != EEXIST) { *val = ""; /* mark as not created */ continue; } cl_git_pass(git_path_prettify(&path, *val, NULL)); /* vary testfile name so any sloppiness is resetting variables or * deleting files won't accidentally make a test pass. */ testfile[testlen] = tidx++; cl_git_pass(git_buf_joinpath(&path, path.ptr, testfile)); cl_git_mkfile(path.ptr, "find me"); git_buf_rtruncate_at_char(&path, '/'); /* default should be NOTFOUND */ cl_assert_equal_i( GIT_ENOTFOUND, git_futils_find_global_file(&found, testfile)); /* try plain, append $PATH, and prepend $PATH */ check_global_searchpath(path.ptr, 0, testfile, &found); check_global_searchpath(path.ptr, -1, testfile, &found); check_global_searchpath(path.ptr, 1, testfile, &found); /* cleanup */ cl_git_pass(git_buf_joinpath(&path, path.ptr, testfile)); (void)p_unlink(path.ptr); (void)p_rmdir(*val); } git_buf_free(&path); git_buf_free(&found); } libgit2-0.19.0/tests-clar/core/errors.c000066400000000000000000000043051216214232500176260ustar00rootroot00000000000000#include "clar_libgit2.h" void test_core_errors__public_api(void) { char *str_in_error; giterr_clear(); cl_assert(giterr_last() == NULL); giterr_set_oom(); cl_assert(giterr_last() != NULL); cl_assert(giterr_last()->klass == GITERR_NOMEMORY); str_in_error = strstr(giterr_last()->message, "memory"); cl_assert(str_in_error != NULL); giterr_clear(); giterr_set_str(GITERR_REPOSITORY, "This is a test"); cl_assert(giterr_last() != NULL); str_in_error = strstr(giterr_last()->message, "This is a test"); cl_assert(str_in_error != NULL); giterr_clear(); cl_assert(giterr_last() == NULL); } #include "common.h" #include "util.h" #include "posix.h" void test_core_errors__new_school(void) { char *str_in_error; giterr_clear(); cl_assert(giterr_last() == NULL); giterr_set_oom(); /* internal fn */ cl_assert(giterr_last() != NULL); cl_assert(giterr_last()->klass == GITERR_NOMEMORY); str_in_error = strstr(giterr_last()->message, "memory"); cl_assert(str_in_error != NULL); giterr_clear(); giterr_set(GITERR_REPOSITORY, "This is a test"); /* internal fn */ cl_assert(giterr_last() != NULL); str_in_error = strstr(giterr_last()->message, "This is a test"); cl_assert(str_in_error != NULL); giterr_clear(); cl_assert(giterr_last() == NULL); do { struct stat st; memset(&st, 0, sizeof(st)); cl_assert(p_lstat("this_file_does_not_exist", &st) < 0); GIT_UNUSED(st); } while (false); giterr_set(GITERR_OS, "stat failed"); /* internal fn */ cl_assert(giterr_last() != NULL); str_in_error = strstr(giterr_last()->message, "stat failed"); cl_assert(str_in_error != NULL); cl_assert(git__prefixcmp(str_in_error, "stat failed: ") == 0); cl_assert(strlen(str_in_error) > strlen("stat failed: ")); #ifdef GIT_WIN32 giterr_clear(); /* The MSDN docs use this to generate a sample error */ cl_assert(GetProcessId(NULL) == 0); giterr_set(GITERR_OS, "GetProcessId failed"); /* internal fn */ cl_assert(giterr_last() != NULL); str_in_error = strstr(giterr_last()->message, "GetProcessId failed"); cl_assert(str_in_error != NULL); cl_assert(git__prefixcmp(str_in_error, "GetProcessId failed: ") == 0); cl_assert(strlen(str_in_error) > strlen("GetProcessId failed: ")); #endif giterr_clear(); } libgit2-0.19.0/tests-clar/core/filebuf.c000066400000000000000000000042471216214232500177330ustar00rootroot00000000000000#include "clar_libgit2.h" #include "filebuf.h" /* make sure git_filebuf_open doesn't delete an existing lock */ void test_core_filebuf__0(void) { git_filebuf file = GIT_FILEBUF_INIT; int fd; char test[] = "test", testlock[] = "test.lock"; fd = p_creat(testlock, 0744); //-V536 cl_must_pass(fd); cl_must_pass(p_close(fd)); cl_git_fail(git_filebuf_open(&file, test, 0)); cl_assert(git_path_exists(testlock)); cl_must_pass(p_unlink(testlock)); } /* make sure GIT_FILEBUF_APPEND works as expected */ void test_core_filebuf__1(void) { git_filebuf file = GIT_FILEBUF_INIT; int fd; char test[] = "test"; fd = p_creat(test, 0666); //-V536 cl_must_pass(fd); cl_must_pass(p_write(fd, "libgit2 rocks\n", 14)); cl_must_pass(p_close(fd)); cl_git_pass(git_filebuf_open(&file, test, GIT_FILEBUF_APPEND)); cl_git_pass(git_filebuf_printf(&file, "%s\n", "libgit2 rocks")); cl_git_pass(git_filebuf_commit(&file, 0666)); cl_must_pass(p_unlink(test)); } /* make sure git_filebuf_write writes large buffer correctly */ void test_core_filebuf__2(void) { git_filebuf file = GIT_FILEBUF_INIT; char test[] = "test"; unsigned char buf[4096 * 4]; /* 2 * WRITE_BUFFER_SIZE */ memset(buf, 0xfe, sizeof(buf)); cl_git_pass(git_filebuf_open(&file, test, 0)); cl_git_pass(git_filebuf_write(&file, buf, sizeof(buf))); cl_git_pass(git_filebuf_commit(&file, 0666)); cl_must_pass(p_unlink(test)); } /* make sure git_filebuf_cleanup clears the buffer */ void test_core_filebuf__4(void) { git_filebuf file = GIT_FILEBUF_INIT; char test[] = "test"; cl_assert(file.buffer == NULL); cl_git_pass(git_filebuf_open(&file, test, 0)); cl_assert(file.buffer != NULL); git_filebuf_cleanup(&file); cl_assert(file.buffer == NULL); } /* make sure git_filebuf_commit clears the buffer */ void test_core_filebuf__5(void) { git_filebuf file = GIT_FILEBUF_INIT; char test[] = "test"; cl_assert(file.buffer == NULL); cl_git_pass(git_filebuf_open(&file, test, 0)); cl_assert(file.buffer != NULL); cl_git_pass(git_filebuf_printf(&file, "%s\n", "libgit2 rocks")); cl_assert(file.buffer != NULL); cl_git_pass(git_filebuf_commit(&file, 0666)); cl_assert(file.buffer == NULL); cl_must_pass(p_unlink(test)); } libgit2-0.19.0/tests-clar/core/hex.c000066400000000000000000000011511216214232500170720ustar00rootroot00000000000000#include "clar_libgit2.h" #include "util.h" void test_core_hex__fromhex(void) { /* Passing cases */ cl_assert(git__fromhex('0') == 0x0); cl_assert(git__fromhex('1') == 0x1); cl_assert(git__fromhex('3') == 0x3); cl_assert(git__fromhex('9') == 0x9); cl_assert(git__fromhex('A') == 0xa); cl_assert(git__fromhex('C') == 0xc); cl_assert(git__fromhex('F') == 0xf); cl_assert(git__fromhex('a') == 0xa); cl_assert(git__fromhex('c') == 0xc); cl_assert(git__fromhex('f') == 0xf); /* Failing cases */ cl_assert(git__fromhex('g') == -1); cl_assert(git__fromhex('z') == -1); cl_assert(git__fromhex('X') == -1); } libgit2-0.19.0/tests-clar/core/mkdir.c000066400000000000000000000134601216214232500174220ustar00rootroot00000000000000#include "clar_libgit2.h" #include "fileops.h" #include "path.h" #include "posix.h" static void cleanup_basic_dirs(void *ref) { GIT_UNUSED(ref); git_futils_rmdir_r("d0", NULL, GIT_RMDIR_EMPTY_HIERARCHY); git_futils_rmdir_r("d1", NULL, GIT_RMDIR_EMPTY_HIERARCHY); git_futils_rmdir_r("d2", NULL, GIT_RMDIR_EMPTY_HIERARCHY); git_futils_rmdir_r("d3", NULL, GIT_RMDIR_EMPTY_HIERARCHY); git_futils_rmdir_r("d4", NULL, GIT_RMDIR_EMPTY_HIERARCHY); } void test_core_mkdir__basic(void) { cl_set_cleanup(cleanup_basic_dirs, NULL); /* make a directory */ cl_assert(!git_path_isdir("d0")); cl_git_pass(git_futils_mkdir("d0", NULL, 0755, 0)); cl_assert(git_path_isdir("d0")); /* make a path */ cl_assert(!git_path_isdir("d1")); cl_git_pass(git_futils_mkdir("d1/d1.1/d1.2", NULL, 0755, GIT_MKDIR_PATH)); cl_assert(git_path_isdir("d1")); cl_assert(git_path_isdir("d1/d1.1")); cl_assert(git_path_isdir("d1/d1.1/d1.2")); /* make a dir exclusively */ cl_assert(!git_path_isdir("d2")); cl_git_pass(git_futils_mkdir("d2", NULL, 0755, GIT_MKDIR_EXCL)); cl_assert(git_path_isdir("d2")); /* make exclusive failure */ cl_git_fail(git_futils_mkdir("d2", NULL, 0755, GIT_MKDIR_EXCL)); /* make a path exclusively */ cl_assert(!git_path_isdir("d3")); cl_git_pass(git_futils_mkdir("d3/d3.1/d3.2", NULL, 0755, GIT_MKDIR_PATH | GIT_MKDIR_EXCL)); cl_assert(git_path_isdir("d3")); cl_assert(git_path_isdir("d3/d3.1/d3.2")); /* make exclusive path failure */ cl_git_fail(git_futils_mkdir("d3/d3.1/d3.2", NULL, 0755, GIT_MKDIR_PATH | GIT_MKDIR_EXCL)); /* ??? Should EXCL only apply to the last item in the path? */ /* path with trailing slash? */ cl_assert(!git_path_isdir("d4")); cl_git_pass(git_futils_mkdir("d4/d4.1/", NULL, 0755, GIT_MKDIR_PATH)); cl_assert(git_path_isdir("d4/d4.1")); } static void cleanup_basedir(void *ref) { GIT_UNUSED(ref); git_futils_rmdir_r("base", NULL, GIT_RMDIR_EMPTY_HIERARCHY); } void test_core_mkdir__with_base(void) { #define BASEDIR "base/dir/here" cl_set_cleanup(cleanup_basedir, NULL); cl_git_pass(git_futils_mkdir(BASEDIR, NULL, 0755, GIT_MKDIR_PATH)); cl_git_pass(git_futils_mkdir("a", BASEDIR, 0755, 0)); cl_assert(git_path_isdir(BASEDIR "/a")); cl_git_pass(git_futils_mkdir("b/b1/b2", BASEDIR, 0755, GIT_MKDIR_PATH)); cl_assert(git_path_isdir(BASEDIR "/b/b1/b2")); /* exclusive with existing base */ cl_git_pass(git_futils_mkdir("c/c1/c2", BASEDIR, 0755, GIT_MKDIR_PATH | GIT_MKDIR_EXCL)); /* fail: exclusive with duplicated suffix */ cl_git_fail(git_futils_mkdir("c/c1/c3", BASEDIR, 0755, GIT_MKDIR_PATH | GIT_MKDIR_EXCL)); /* fail: exclusive with any duplicated component */ cl_git_fail(git_futils_mkdir("c/cz/cz", BASEDIR, 0755, GIT_MKDIR_PATH | GIT_MKDIR_EXCL)); /* success: exclusive without path */ cl_git_pass(git_futils_mkdir("c/c1/c3", BASEDIR, 0755, GIT_MKDIR_EXCL)); /* path with shorter base and existing dirs */ cl_git_pass(git_futils_mkdir("dir/here/d/", "base", 0755, GIT_MKDIR_PATH)); cl_assert(git_path_isdir("base/dir/here/d")); /* fail: path with shorter base and existing dirs */ cl_git_fail(git_futils_mkdir("dir/here/e/", "base", 0755, GIT_MKDIR_PATH | GIT_MKDIR_EXCL)); /* fail: base with missing components */ cl_git_fail(git_futils_mkdir("f/", "base/missing", 0755, GIT_MKDIR_PATH)); /* success: shift missing component to path */ cl_git_pass(git_futils_mkdir("missing/f/", "base/", 0755, GIT_MKDIR_PATH)); } static void cleanup_chmod_root(void *ref) { mode_t *mode = ref; if (*mode != 0) { (void)p_umask(*mode); git__free(mode); } git_futils_rmdir_r("r", NULL, GIT_RMDIR_EMPTY_HIERARCHY); } static void check_mode(mode_t expected, mode_t actual) { #ifdef GIT_WIN32 /* chmod on Win32 doesn't support exec bit, not group/world bits */ cl_assert((expected & 0600) == (actual & 0777)); #else cl_assert(expected == (actual & 0777)); #endif } void test_core_mkdir__chmods(void) { struct stat st; mode_t *old = git__malloc(sizeof(mode_t)); *old = p_umask(022); cl_set_cleanup(cleanup_chmod_root, old); cl_git_pass(git_futils_mkdir("r", NULL, 0777, 0)); cl_git_pass(git_futils_mkdir("mode/is/important", "r", 0777, GIT_MKDIR_PATH)); cl_git_pass(git_path_lstat("r/mode", &st)); check_mode(0755, st.st_mode); cl_git_pass(git_path_lstat("r/mode/is", &st)); check_mode(0755, st.st_mode); cl_git_pass(git_path_lstat("r/mode/is/important", &st)); check_mode(0755, st.st_mode); cl_git_pass(git_futils_mkdir("mode2/is2/important2", "r", 0777, GIT_MKDIR_PATH | GIT_MKDIR_CHMOD)); cl_git_pass(git_path_lstat("r/mode2", &st)); check_mode(0755, st.st_mode); cl_git_pass(git_path_lstat("r/mode2/is2", &st)); check_mode(0755, st.st_mode); cl_git_pass(git_path_lstat("r/mode2/is2/important2", &st)); check_mode(0777, st.st_mode); cl_git_pass(git_futils_mkdir("mode3/is3/important3", "r", 0777, GIT_MKDIR_PATH | GIT_MKDIR_CHMOD_PATH)); cl_git_pass(git_path_lstat("r/mode3", &st)); check_mode(0777, st.st_mode); cl_git_pass(git_path_lstat("r/mode3/is3", &st)); check_mode(0777, st.st_mode); cl_git_pass(git_path_lstat("r/mode3/is3/important3", &st)); check_mode(0777, st.st_mode); /* test that we chmod existing dir */ cl_git_pass(git_futils_mkdir("mode/is/important", "r", 0777, GIT_MKDIR_PATH | GIT_MKDIR_CHMOD)); cl_git_pass(git_path_lstat("r/mode", &st)); check_mode(0755, st.st_mode); cl_git_pass(git_path_lstat("r/mode/is", &st)); check_mode(0755, st.st_mode); cl_git_pass(git_path_lstat("r/mode/is/important", &st)); check_mode(0777, st.st_mode); /* test that we chmod even existing dirs if CHMOD_PATH is set */ cl_git_pass(git_futils_mkdir("mode2/is2/important2.1", "r", 0777, GIT_MKDIR_PATH | GIT_MKDIR_CHMOD_PATH)); cl_git_pass(git_path_lstat("r/mode2", &st)); check_mode(0777, st.st_mode); cl_git_pass(git_path_lstat("r/mode2/is2", &st)); check_mode(0777, st.st_mode); cl_git_pass(git_path_lstat("r/mode2/is2/important2.1", &st)); check_mode(0777, st.st_mode); } libgit2-0.19.0/tests-clar/core/oid.c000066400000000000000000000052001216214232500170600ustar00rootroot00000000000000#include "clar_libgit2.h" static git_oid id; static git_oid idp; static git_oid idm; const char *str_oid = "ae90f12eea699729ed24555e40b9fd669da12a12"; const char *str_oid_p = "ae90f12eea699729ed"; const char *str_oid_m = "ae90f12eea699729ed24555e40b9fd669da12a12THIS IS EXTRA TEXT THAT SHOULD GET IGNORED"; void test_core_oid__initialize(void) { cl_git_pass(git_oid_fromstr(&id, str_oid)); cl_git_pass(git_oid_fromstrp(&idp, str_oid_p)); cl_git_fail(git_oid_fromstrp(&idm, str_oid_m)); } void test_core_oid__streq(void) { cl_assert_equal_i(0, git_oid_streq(&id, str_oid)); cl_assert_equal_i(-1, git_oid_streq(&id, "deadbeefdeadbeefdeadbeefdeadbeefdeadbeef")); cl_assert_equal_i(-1, git_oid_streq(&id, "deadbeef")); cl_assert_equal_i(-1, git_oid_streq(&id, "I'm not an oid.... :)")); cl_assert_equal_i(0, git_oid_streq(&idp, "ae90f12eea699729ed0000000000000000000000")); cl_assert_equal_i(0, git_oid_streq(&idp, "ae90f12eea699729ed")); cl_assert_equal_i(-1, git_oid_streq(&idp, "ae90f12eea699729ed1")); cl_assert_equal_i(-1, git_oid_streq(&idp, "ae90f12eea699729ec")); cl_assert_equal_i(-1, git_oid_streq(&idp, "deadbeefdeadbeefdeadbeefdeadbeefdeadbeef")); cl_assert_equal_i(-1, git_oid_streq(&idp, "deadbeef")); cl_assert_equal_i(-1, git_oid_streq(&idp, "I'm not an oid.... :)")); } void test_core_oid__strcmp(void) { cl_assert_equal_i(0, git_oid_strcmp(&id, str_oid)); cl_assert(git_oid_strcmp(&id, "deadbeefdeadbeefdeadbeefdeadbeefdeadbeef") < 0); cl_assert(git_oid_strcmp(&id, "deadbeef") < 0); cl_assert_equal_i(-1, git_oid_strcmp(&id, "I'm not an oid.... :)")); cl_assert_equal_i(0, git_oid_strcmp(&idp, "ae90f12eea699729ed0000000000000000000000")); cl_assert_equal_i(0, git_oid_strcmp(&idp, "ae90f12eea699729ed")); cl_assert(git_oid_strcmp(&idp, "ae90f12eea699729ed1") < 0); cl_assert(git_oid_strcmp(&idp, "ae90f12eea699729ec") > 0); cl_assert(git_oid_strcmp(&idp, "deadbeefdeadbeefdeadbeefdeadbeefdeadbeef") < 0); cl_assert(git_oid_strcmp(&idp, "deadbeef") < 0); cl_assert_equal_i(-1, git_oid_strcmp(&idp, "I'm not an oid.... :)")); } void test_core_oid__ncmp(void) { cl_assert(!git_oid_ncmp(&id, &idp, 0)); cl_assert(!git_oid_ncmp(&id, &idp, 1)); cl_assert(!git_oid_ncmp(&id, &idp, 2)); cl_assert(!git_oid_ncmp(&id, &idp, 17)); cl_assert(!git_oid_ncmp(&id, &idp, 18)); cl_assert(git_oid_ncmp(&id, &idp, 19)); cl_assert(git_oid_ncmp(&id, &idp, 40)); cl_assert(git_oid_ncmp(&id, &idp, 41)); cl_assert(git_oid_ncmp(&id, &idp, 42)); cl_assert(!git_oid_ncmp(&id, &id, 0)); cl_assert(!git_oid_ncmp(&id, &id, 1)); cl_assert(!git_oid_ncmp(&id, &id, 39)); cl_assert(!git_oid_ncmp(&id, &id, 40)); cl_assert(!git_oid_ncmp(&id, &id, 41)); } libgit2-0.19.0/tests-clar/core/oidmap.c000066400000000000000000000043521216214232500175650ustar00rootroot00000000000000#include "clar_libgit2.h" #include "oidmap.h" GIT__USE_OIDMAP; typedef struct { git_oid oid; size_t extra; } oidmap_item; #define NITEMS 0x0fff void test_core_oidmap__basic(void) { git_oidmap *map; oidmap_item items[NITEMS]; uint32_t i, j; for (i = 0; i < NITEMS; ++i) { items[i].extra = i; for (j = 0; j < GIT_OID_RAWSZ / 4; ++j) { items[i].oid.id[j * 4 ] = (unsigned char)i; items[i].oid.id[j * 4 + 1] = (unsigned char)(i >> 8); items[i].oid.id[j * 4 + 2] = (unsigned char)(i >> 16); items[i].oid.id[j * 4 + 3] = (unsigned char)(i >> 24); } } map = git_oidmap_alloc(); cl_assert(map != NULL); for (i = 0; i < NITEMS; ++i) { khiter_t pos; int ret; pos = kh_get(oid, map, &items[i].oid); cl_assert(pos == kh_end(map)); pos = kh_put(oid, map, &items[i].oid, &ret); cl_assert(ret != 0); kh_val(map, pos) = &items[i]; } for (i = 0; i < NITEMS; ++i) { khiter_t pos; pos = kh_get(oid, map, &items[i].oid); cl_assert(pos != kh_end(map)); cl_assert_equal_p(kh_val(map, pos), &items[i]); } git_oidmap_free(map); } void test_core_oidmap__hash_collision(void) { git_oidmap *map; oidmap_item items[NITEMS]; uint32_t i, j; for (i = 0; i < NITEMS; ++i) { uint32_t segment = i / 8; int modi = i - (segment * 8); items[i].extra = i; for (j = 0; j < GIT_OID_RAWSZ / 4; ++j) { items[i].oid.id[j * 4 ] = (unsigned char)modi; items[i].oid.id[j * 4 + 1] = (unsigned char)(modi >> 8); items[i].oid.id[j * 4 + 2] = (unsigned char)(modi >> 16); items[i].oid.id[j * 4 + 3] = (unsigned char)(modi >> 24); } items[i].oid.id[ 8] = (unsigned char)i; items[i].oid.id[ 9] = (unsigned char)(i >> 8); items[i].oid.id[10] = (unsigned char)(i >> 16); items[i].oid.id[11] = (unsigned char)(i >> 24); } map = git_oidmap_alloc(); cl_assert(map != NULL); for (i = 0; i < NITEMS; ++i) { khiter_t pos; int ret; pos = kh_get(oid, map, &items[i].oid); cl_assert(pos == kh_end(map)); pos = kh_put(oid, map, &items[i].oid, &ret); cl_assert(ret != 0); kh_val(map, pos) = &items[i]; } for (i = 0; i < NITEMS; ++i) { khiter_t pos; pos = kh_get(oid, map, &items[i].oid); cl_assert(pos != kh_end(map)); cl_assert_equal_p(kh_val(map, pos), &items[i]); } git_oidmap_free(map); } libgit2-0.19.0/tests-clar/core/opts.c000066400000000000000000000007301216214232500172750ustar00rootroot00000000000000#include "clar_libgit2.h" #include "cache.h" void test_core_opts__readwrite(void) { size_t old_val = 0; size_t new_val = 0; git_libgit2_opts(GIT_OPT_GET_MWINDOW_SIZE, &old_val); git_libgit2_opts(GIT_OPT_SET_MWINDOW_SIZE, (size_t)1234); git_libgit2_opts(GIT_OPT_GET_MWINDOW_SIZE, &new_val); cl_assert(new_val == 1234); git_libgit2_opts(GIT_OPT_SET_MWINDOW_SIZE, old_val); git_libgit2_opts(GIT_OPT_GET_MWINDOW_SIZE, &new_val); cl_assert(new_val == old_val); } libgit2-0.19.0/tests-clar/core/path.c000066400000000000000000000332141216214232500172470ustar00rootroot00000000000000#include "clar_libgit2.h" #include static void check_dirname(const char *A, const char *B) { git_buf dir = GIT_BUF_INIT; char *dir2; cl_assert(git_path_dirname_r(&dir, A) >= 0); cl_assert_equal_s(B, dir.ptr); git_buf_free(&dir); cl_assert((dir2 = git_path_dirname(A)) != NULL); cl_assert_equal_s(B, dir2); git__free(dir2); } static void check_basename(const char *A, const char *B) { git_buf base = GIT_BUF_INIT; char *base2; cl_assert(git_path_basename_r(&base, A) >= 0); cl_assert_equal_s(B, base.ptr); git_buf_free(&base); cl_assert((base2 = git_path_basename(A)) != NULL); cl_assert_equal_s(B, base2); git__free(base2); } static void check_topdir(const char *A, const char *B) { const char *dir; cl_assert((dir = git_path_topdir(A)) != NULL); cl_assert_equal_s(B, dir); } static void check_joinpath(const char *path_a, const char *path_b, const char *expected_path) { git_buf joined_path = GIT_BUF_INIT; cl_git_pass(git_buf_joinpath(&joined_path, path_a, path_b)); cl_assert_equal_s(expected_path, joined_path.ptr); git_buf_free(&joined_path); } static void check_joinpath_n( const char *path_a, const char *path_b, const char *path_c, const char *path_d, const char *expected_path) { git_buf joined_path = GIT_BUF_INIT; cl_git_pass(git_buf_join_n(&joined_path, '/', 4, path_a, path_b, path_c, path_d)); cl_assert_equal_s(expected_path, joined_path.ptr); git_buf_free(&joined_path); } /* get the dirname of a path */ void test_core_path__00_dirname(void) { check_dirname(NULL, "."); check_dirname("", "."); check_dirname("a", "."); check_dirname("/", "/"); check_dirname("/usr", "/"); check_dirname("/usr/", "/"); check_dirname("/usr/lib", "/usr"); check_dirname("/usr/lib/", "/usr"); check_dirname("/usr/lib//", "/usr"); check_dirname("usr/lib", "usr"); check_dirname("usr/lib/", "usr"); check_dirname("usr/lib//", "usr"); check_dirname(".git/", "."); check_dirname(REP16("/abc"), REP15("/abc")); #ifdef GIT_WIN32 check_dirname("C:/path/", "C:/"); check_dirname("C:/path", "C:/"); check_dirname("//computername/path/", "//computername/"); check_dirname("//computername/path", "//computername/"); check_dirname("//computername/sub/path/", "//computername/sub"); check_dirname("//computername/sub/path", "//computername/sub"); #endif } /* get the base name of a path */ void test_core_path__01_basename(void) { check_basename(NULL, "."); check_basename("", "."); check_basename("a", "a"); check_basename("/", "/"); check_basename("/usr", "usr"); check_basename("/usr/", "usr"); check_basename("/usr/lib", "lib"); check_basename("/usr/lib//", "lib"); check_basename("usr/lib", "lib"); check_basename(REP16("/abc"), "abc"); check_basename(REP1024("/abc"), "abc"); } /* get the latest component in a path */ void test_core_path__02_topdir(void) { check_topdir(".git/", ".git/"); check_topdir("/.git/", ".git/"); check_topdir("usr/local/.git/", ".git/"); check_topdir("./.git/", ".git/"); check_topdir("/usr/.git/", ".git/"); check_topdir("/", "/"); check_topdir("a/", "a/"); cl_assert(git_path_topdir("/usr/.git") == NULL); cl_assert(git_path_topdir(".") == NULL); cl_assert(git_path_topdir("") == NULL); cl_assert(git_path_topdir("a") == NULL); } /* properly join path components */ void test_core_path__05_joins(void) { check_joinpath("", "", ""); check_joinpath("", "a", "a"); check_joinpath("", "/a", "/a"); check_joinpath("a", "", "a/"); check_joinpath("a", "/", "a/"); check_joinpath("a", "b", "a/b"); check_joinpath("/", "a", "/a"); check_joinpath("/", "", "/"); check_joinpath("/a", "/b", "/a/b"); check_joinpath("/a", "/b/", "/a/b/"); check_joinpath("/a/", "b/", "/a/b/"); check_joinpath("/a/", "/b/", "/a/b/"); check_joinpath("/abcd", "/defg", "/abcd/defg"); check_joinpath("/abcd", "/defg/", "/abcd/defg/"); check_joinpath("/abcd/", "defg/", "/abcd/defg/"); check_joinpath("/abcd/", "/defg/", "/abcd/defg/"); check_joinpath("/abcdefgh", "/12345678", "/abcdefgh/12345678"); check_joinpath("/abcdefgh", "/12345678/", "/abcdefgh/12345678/"); check_joinpath("/abcdefgh/", "12345678/", "/abcdefgh/12345678/"); check_joinpath(REP1024("aaaa"), "", REP1024("aaaa") "/"); check_joinpath(REP1024("aaaa/"), "", REP1024("aaaa/")); check_joinpath(REP1024("/aaaa"), "", REP1024("/aaaa") "/"); check_joinpath(REP1024("aaaa"), REP1024("bbbb"), REP1024("aaaa") "/" REP1024("bbbb")); check_joinpath(REP1024("/aaaa"), REP1024("/bbbb"), REP1024("/aaaa") REP1024("/bbbb")); } /* properly join path components for more than one path */ void test_core_path__06_long_joins(void) { check_joinpath_n("", "", "", "", ""); check_joinpath_n("", "a", "", "", "a/"); check_joinpath_n("a", "", "", "", "a/"); check_joinpath_n("", "", "", "a", "a"); check_joinpath_n("a", "b", "", "/c/d/", "a/b/c/d/"); check_joinpath_n("a", "b", "", "/c/d", "a/b/c/d"); check_joinpath_n("abcd", "efgh", "ijkl", "mnop", "abcd/efgh/ijkl/mnop"); check_joinpath_n("abcd/", "efgh/", "ijkl/", "mnop/", "abcd/efgh/ijkl/mnop/"); check_joinpath_n("/abcd/", "/efgh/", "/ijkl/", "/mnop/", "/abcd/efgh/ijkl/mnop/"); check_joinpath_n(REP1024("a"), REP1024("b"), REP1024("c"), REP1024("d"), REP1024("a") "/" REP1024("b") "/" REP1024("c") "/" REP1024("d")); check_joinpath_n(REP1024("/a"), REP1024("/b"), REP1024("/c"), REP1024("/d"), REP1024("/a") REP1024("/b") REP1024("/c") REP1024("/d")); } static void check_path_to_dir( const char* path, const char* expected) { git_buf tgt = GIT_BUF_INIT; git_buf_sets(&tgt, path); cl_git_pass(git_path_to_dir(&tgt)); cl_assert_equal_s(expected, tgt.ptr); git_buf_free(&tgt); } static void check_string_to_dir( const char* path, size_t maxlen, const char* expected) { size_t len = strlen(path); char *buf = git__malloc(len + 2); cl_assert(buf); strncpy(buf, path, len + 2); git_path_string_to_dir(buf, maxlen); cl_assert_equal_s(expected, buf); git__free(buf); } /* convert paths to dirs */ void test_core_path__07_path_to_dir(void) { check_path_to_dir("", ""); check_path_to_dir(".", "./"); check_path_to_dir("./", "./"); check_path_to_dir("a/", "a/"); check_path_to_dir("ab", "ab/"); /* make sure we try just under and just over an expansion that will * require a realloc */ check_path_to_dir("abcdef", "abcdef/"); check_path_to_dir("abcdefg", "abcdefg/"); check_path_to_dir("abcdefgh", "abcdefgh/"); check_path_to_dir("abcdefghi", "abcdefghi/"); check_path_to_dir(REP1024("abcd") "/", REP1024("abcd") "/"); check_path_to_dir(REP1024("abcd"), REP1024("abcd") "/"); check_string_to_dir("", 1, ""); check_string_to_dir(".", 1, "."); check_string_to_dir(".", 2, "./"); check_string_to_dir(".", 3, "./"); check_string_to_dir("abcd", 3, "abcd"); check_string_to_dir("abcd", 4, "abcd"); check_string_to_dir("abcd", 5, "abcd/"); check_string_to_dir("abcd", 6, "abcd/"); } /* join path to itself */ void test_core_path__08_self_join(void) { git_buf path = GIT_BUF_INIT; size_t asize = 0; asize = path.asize; cl_git_pass(git_buf_sets(&path, "/foo")); cl_assert_equal_s(path.ptr, "/foo"); cl_assert(asize < path.asize); asize = path.asize; cl_git_pass(git_buf_joinpath(&path, path.ptr, "this is a new string")); cl_assert_equal_s(path.ptr, "/foo/this is a new string"); cl_assert(asize < path.asize); asize = path.asize; cl_git_pass(git_buf_joinpath(&path, path.ptr, "/grow the buffer, grow the buffer, grow the buffer")); cl_assert_equal_s(path.ptr, "/foo/this is a new string/grow the buffer, grow the buffer, grow the buffer"); cl_assert(asize < path.asize); git_buf_free(&path); cl_git_pass(git_buf_sets(&path, "/foo/bar")); cl_git_pass(git_buf_joinpath(&path, path.ptr + 4, "baz")); cl_assert_equal_s(path.ptr, "/bar/baz"); asize = path.asize; cl_git_pass(git_buf_joinpath(&path, path.ptr + 4, "somethinglongenoughtorealloc")); cl_assert_equal_s(path.ptr, "/baz/somethinglongenoughtorealloc"); cl_assert(asize < path.asize); git_buf_free(&path); } static void check_percent_decoding(const char *expected_result, const char *input) { git_buf buf = GIT_BUF_INIT; cl_git_pass(git__percent_decode(&buf, input)); cl_assert_equal_s(expected_result, git_buf_cstr(&buf)); git_buf_free(&buf); } void test_core_path__09_percent_decode(void) { check_percent_decoding("abcd", "abcd"); check_percent_decoding("a2%", "a2%"); check_percent_decoding("a2%3", "a2%3"); check_percent_decoding("a2%%3", "a2%%3"); check_percent_decoding("a2%3z", "a2%3z"); check_percent_decoding("a,", "a%2c"); check_percent_decoding("a21", "a2%31"); check_percent_decoding("a2%1", "a2%%31"); check_percent_decoding("a bc ", "a%20bc%20"); check_percent_decoding("Vicent Mart" "\355", "Vicent%20Mart%ED"); } static void check_fromurl(const char *expected_result, const char *input, int should_fail) { git_buf buf = GIT_BUF_INIT; assert(should_fail || expected_result); if (!should_fail) { cl_git_pass(git_path_fromurl(&buf, input)); cl_assert_equal_s(expected_result, git_buf_cstr(&buf)); } else cl_git_fail(git_path_fromurl(&buf, input)); git_buf_free(&buf); } #ifdef GIT_WIN32 #define ABS_PATH_MARKER "" #else #define ABS_PATH_MARKER "/" #endif void test_core_path__10_fromurl(void) { /* Failing cases */ check_fromurl(NULL, "a", 1); check_fromurl(NULL, "http:///c:/Temp%20folder/note.txt", 1); check_fromurl(NULL, "file://c:/Temp%20folder/note.txt", 1); check_fromurl(NULL, "file:////c:/Temp%20folder/note.txt", 1); check_fromurl(NULL, "file:///", 1); check_fromurl(NULL, "file:////", 1); check_fromurl(NULL, "file://servername/c:/Temp%20folder/note.txt", 1); /* Passing cases */ check_fromurl(ABS_PATH_MARKER "c:/Temp folder/note.txt", "file:///c:/Temp%20folder/note.txt", 0); check_fromurl(ABS_PATH_MARKER "c:/Temp folder/note.txt", "file://localhost/c:/Temp%20folder/note.txt", 0); check_fromurl(ABS_PATH_MARKER "c:/Temp+folder/note.txt", "file:///c:/Temp+folder/note.txt", 0); check_fromurl(ABS_PATH_MARKER "a", "file:///a", 0); } typedef struct { int expect_idx; char **expect; } check_walkup_info; static int check_one_walkup_step(void *ref, git_buf *path) { check_walkup_info *info = (check_walkup_info *)ref; cl_assert(info->expect[info->expect_idx] != NULL); cl_assert_equal_s(info->expect[info->expect_idx], path->ptr); info->expect_idx++; return 0; } void test_core_path__11_walkup(void) { git_buf p = GIT_BUF_INIT; char *expect[] = { "/a/b/c/d/e/", "/a/b/c/d/", "/a/b/c/", "/a/b/", "/a/", "/", NULL, "/a/b/c/d/e", "/a/b/c/d/", "/a/b/c/", "/a/b/", "/a/", "/", NULL, "/a/b/c/d/e", "/a/b/c/d/", "/a/b/c/", "/a/b/", "/a/", "/", NULL, "/a/b/c/d/e", "/a/b/c/d/", "/a/b/c/", "/a/b/", "/a/", "/", NULL, "/a/b/c/d/e", "/a/b/c/d/", "/a/b/c/", "/a/b/", NULL, "/a/b/c/d/e", "/a/b/c/d/", "/a/b/c/", "/a/b/", NULL, "this is a path", NULL, "///a///b///c///d///e///", "///a///b///c///d///", "///a///b///c///", "///a///b///", "///a///", "///", NULL, NULL }; char *root[] = { NULL, NULL, "/", "", "/a/b", "/a/b/", NULL, NULL, NULL }; int i, j; check_walkup_info info; info.expect = expect; for (i = 0, j = 0; expect[i] != NULL; i++, j++) { git_buf_sets(&p, expect[i]); info.expect_idx = i; cl_git_pass( git_path_walk_up(&p, root[j], check_one_walkup_step, &info) ); cl_assert_equal_s(p.ptr, expect[i]); /* skip to next run of expectations */ while (expect[i] != NULL) i++; } git_buf_free(&p); } void test_core_path__12_offset_to_path_root(void) { cl_assert(git_path_root("non/rooted/path") == -1); cl_assert(git_path_root("/rooted/path") == 0); #ifdef GIT_WIN32 /* Windows specific tests */ cl_assert(git_path_root("C:non/rooted/path") == -1); cl_assert(git_path_root("C:/rooted/path") == 2); cl_assert(git_path_root("//computername/sharefolder/resource") == 14); cl_assert(git_path_root("//computername/sharefolder") == 14); cl_assert(git_path_root("//computername") == -1); #endif } #define NON_EXISTING_FILEPATH "i_hope_i_do_not_exist" void test_core_path__13_cannot_prettify_a_non_existing_file(void) { git_buf p = GIT_BUF_INIT; cl_must_pass(git_path_exists(NON_EXISTING_FILEPATH) == false); cl_assert_equal_i(GIT_ENOTFOUND, git_path_prettify(&p, NON_EXISTING_FILEPATH, NULL)); cl_assert_equal_i(GIT_ENOTFOUND, git_path_prettify(&p, NON_EXISTING_FILEPATH "/so-do-i", NULL)); git_buf_free(&p); } void test_core_path__14_apply_relative(void) { git_buf p = GIT_BUF_INIT; cl_git_pass(git_buf_sets(&p, "/this/is/a/base")); cl_git_pass(git_path_apply_relative(&p, "../test")); cl_assert_equal_s("/this/is/a/test", p.ptr); cl_git_pass(git_path_apply_relative(&p, "../../the/./end")); cl_assert_equal_s("/this/is/the/end", p.ptr); cl_git_pass(git_path_apply_relative(&p, "./of/this/../the/string")); cl_assert_equal_s("/this/is/the/end/of/the/string", p.ptr); cl_git_pass(git_path_apply_relative(&p, "../../../../../..")); cl_assert_equal_s("/this/", p.ptr); cl_git_pass(git_path_apply_relative(&p, "../../../../../")); cl_assert_equal_s("/", p.ptr); cl_git_pass(git_path_apply_relative(&p, "../../../../..")); cl_assert_equal_s("/", p.ptr); cl_git_pass(git_buf_sets(&p, "d:/another/test")); cl_git_pass(git_path_apply_relative(&p, "../../../../..")); cl_assert_equal_s("d:/", p.ptr); cl_git_pass(git_path_apply_relative(&p, "from/here/to/../and/./back/.")); cl_assert_equal_s("d:/from/here/and/back/", p.ptr); cl_git_pass(git_buf_sets(&p, "https://my.url.com/test.git")); cl_git_pass(git_path_apply_relative(&p, "../another.git")); cl_assert_equal_s("https://my.url.com/another.git", p.ptr); cl_git_pass(git_path_apply_relative(&p, "../full/path/url.patch")); cl_assert_equal_s("https://my.url.com/full/path/url.patch", p.ptr); cl_git_pass(git_path_apply_relative(&p, "..")); cl_assert_equal_s("https://my.url.com/full/path/", p.ptr); cl_git_pass(git_path_apply_relative(&p, "../../../../../")); cl_assert_equal_s("https://", p.ptr); git_buf_free(&p); } libgit2-0.19.0/tests-clar/core/pool.c000066400000000000000000000060151216214232500172630ustar00rootroot00000000000000#include "clar_libgit2.h" #include "pool.h" #include "git2/oid.h" void test_core_pool__0(void) { int i; git_pool p; void *ptr; cl_git_pass(git_pool_init(&p, 1, 4000)); for (i = 1; i < 10000; i *= 2) { ptr = git_pool_malloc(&p, i); cl_assert(ptr != NULL); cl_assert(git_pool__ptr_in_pool(&p, ptr)); cl_assert(!git_pool__ptr_in_pool(&p, &i)); } /* 1+2+4+8+16+32+64+128+256+512+1024 -> original block */ /* 2048 -> 1 block */ /* 4096 -> 1 block */ /* 8192 -> 1 block */ cl_assert(git_pool__open_pages(&p) + git_pool__full_pages(&p) == 4); git_pool_clear(&p); } void test_core_pool__1(void) { int i; git_pool p; cl_git_pass(git_pool_init(&p, 1, 4000)); for (i = 2010; i > 0; i--) cl_assert(git_pool_malloc(&p, i) != NULL); /* with fixed page size, allocation must end up with these values */ cl_assert(git_pool__open_pages(&p) == 1); cl_assert(git_pool__full_pages(&p) == 505); git_pool_clear(&p); cl_git_pass(git_pool_init(&p, 1, 4100)); for (i = 2010; i > 0; i--) cl_assert(git_pool_malloc(&p, i) != NULL); /* with fixed page size, allocation must end up with these values */ cl_assert(git_pool__open_pages(&p) == 1); cl_assert(git_pool__full_pages(&p) == 492); git_pool_clear(&p); } static char to_hex[] = "0123456789abcdef"; void test_core_pool__2(void) { git_pool p; char oid_hex[GIT_OID_HEXSZ]; git_oid *oid; int i, j; memset(oid_hex, '0', sizeof(oid_hex)); cl_git_pass(git_pool_init(&p, sizeof(git_oid), 100)); for (i = 1000; i < 10000; i++) { oid = git_pool_malloc(&p, 1); cl_assert(oid != NULL); for (j = 0; j < 8; j++) oid_hex[j] = to_hex[(i >> (4 * j)) & 0x0f]; cl_git_pass(git_oid_fromstr(oid, oid_hex)); } /* with fixed page size, allocation must end up with these values */ cl_assert(git_pool__open_pages(&p) == 0); cl_assert(git_pool__full_pages(&p) == 90); git_pool_clear(&p); } void test_core_pool__free_list(void) { int i; git_pool p; void *ptr, *ptrs[50]; cl_git_pass(git_pool_init(&p, 100, 100)); for (i = 0; i < 10; ++i) { ptr = git_pool_malloc(&p, 1); cl_assert(ptr != NULL); } cl_assert_equal_i(10, (int)p.items); for (i = 0; i < 50; ++i) { ptrs[i] = git_pool_malloc(&p, 1); cl_assert(ptrs[i] != NULL); } cl_assert_equal_i(60, (int)p.items); git_pool_free(&p, ptr); cl_assert_equal_i(60, (int)p.items); git_pool_free_array(&p, 50, ptrs); cl_assert_equal_i(60, (int)p.items); for (i = 0; i < 50; ++i) { ptrs[i] = git_pool_malloc(&p, 1); cl_assert(ptrs[i] != NULL); } cl_assert_equal_i(60, (int)p.items); for (i = 0; i < 111; ++i) { ptr = git_pool_malloc(&p, 1); cl_assert(ptr != NULL); } cl_assert_equal_i(170, (int)p.items); git_pool_free_array(&p, 50, ptrs); cl_assert_equal_i(170, (int)p.items); for (i = 0; i < 50; ++i) { ptrs[i] = git_pool_malloc(&p, 1); cl_assert(ptrs[i] != NULL); } cl_assert_equal_i(170, (int)p.items); git_pool_clear(&p); } void test_core_pool__strndup_limit(void) { git_pool p; cl_git_pass(git_pool_init(&p, 1, 100)); cl_assert(git_pool_strndup(&p, "foo", -1) == NULL); git_pool_clear(&p); } libgit2-0.19.0/tests-clar/core/rmdir.c000066400000000000000000000056461216214232500174400ustar00rootroot00000000000000#include "clar_libgit2.h" #include "fileops.h" static const char *empty_tmp_dir = "test_gitfo_rmdir_recurs_test"; void test_core_rmdir__initialize(void) { git_buf path = GIT_BUF_INIT; cl_must_pass(p_mkdir(empty_tmp_dir, 0777)); cl_git_pass(git_buf_joinpath(&path, empty_tmp_dir, "/one")); cl_must_pass(p_mkdir(path.ptr, 0777)); cl_git_pass(git_buf_joinpath(&path, empty_tmp_dir, "/one/two_one")); cl_must_pass(p_mkdir(path.ptr, 0777)); cl_git_pass(git_buf_joinpath(&path, empty_tmp_dir, "/one/two_two")); cl_must_pass(p_mkdir(path.ptr, 0777)); cl_git_pass(git_buf_joinpath(&path, empty_tmp_dir, "/one/two_two/three")); cl_must_pass(p_mkdir(path.ptr, 0777)); cl_git_pass(git_buf_joinpath(&path, empty_tmp_dir, "/two")); cl_must_pass(p_mkdir(path.ptr, 0777)); git_buf_free(&path); } /* make sure empty dir can be deleted recusively */ void test_core_rmdir__delete_recursive(void) { cl_git_pass(git_futils_rmdir_r(empty_tmp_dir, NULL, GIT_RMDIR_EMPTY_HIERARCHY)); } /* make sure non-empty dir cannot be deleted recusively */ void test_core_rmdir__fail_to_delete_non_empty_dir(void) { git_buf file = GIT_BUF_INIT; cl_git_pass(git_buf_joinpath(&file, empty_tmp_dir, "/two/file.txt")); cl_git_mkfile(git_buf_cstr(&file), "dummy"); cl_git_fail(git_futils_rmdir_r(empty_tmp_dir, NULL, GIT_RMDIR_EMPTY_HIERARCHY)); cl_must_pass(p_unlink(file.ptr)); cl_git_pass(git_futils_rmdir_r(empty_tmp_dir, NULL, GIT_RMDIR_EMPTY_HIERARCHY)); git_buf_free(&file); } void test_core_rmdir__can_skip_non_empty_dir(void) { git_buf file = GIT_BUF_INIT; cl_git_pass(git_buf_joinpath(&file, empty_tmp_dir, "/two/file.txt")); cl_git_mkfile(git_buf_cstr(&file), "dummy"); cl_git_pass(git_futils_rmdir_r(empty_tmp_dir, NULL, GIT_RMDIR_SKIP_NONEMPTY)); cl_assert(git_path_exists(git_buf_cstr(&file)) == true); cl_git_pass(git_futils_rmdir_r(empty_tmp_dir, NULL, GIT_RMDIR_REMOVE_FILES)); cl_assert(git_path_exists(empty_tmp_dir) == false); git_buf_free(&file); } void test_core_rmdir__can_remove_empty_parents(void) { git_buf file = GIT_BUF_INIT; cl_git_pass( git_buf_joinpath(&file, empty_tmp_dir, "/one/two_two/three/file.txt")); cl_git_mkfile(git_buf_cstr(&file), "dummy"); cl_assert(git_path_isfile(git_buf_cstr(&file))); cl_git_pass(git_futils_rmdir_r("one/two_two/three/file.txt", empty_tmp_dir, GIT_RMDIR_REMOVE_FILES | GIT_RMDIR_EMPTY_PARENTS)); cl_assert(!git_path_exists(git_buf_cstr(&file))); git_buf_rtruncate_at_char(&file, '/'); /* three (only contained file.txt) */ cl_assert(!git_path_exists(git_buf_cstr(&file))); git_buf_rtruncate_at_char(&file, '/'); /* two_two (only contained three) */ cl_assert(!git_path_exists(git_buf_cstr(&file))); git_buf_rtruncate_at_char(&file, '/'); /* one (contained two_one also) */ cl_assert(git_path_exists(git_buf_cstr(&file))); cl_assert(git_path_exists(empty_tmp_dir) == true); git_buf_free(&file); cl_git_pass(git_futils_rmdir_r(empty_tmp_dir, NULL, GIT_RMDIR_EMPTY_HIERARCHY)); } libgit2-0.19.0/tests-clar/core/stat.c000066400000000000000000000046211216214232500172660ustar00rootroot00000000000000#include "clar_libgit2.h" #include "fileops.h" #include "path.h" #include "posix.h" void test_core_stat__initialize(void) { cl_git_pass(git_futils_mkdir("root/d1/d2", NULL, 0755, GIT_MKDIR_PATH)); cl_git_mkfile("root/file", "whatever\n"); cl_git_mkfile("root/d1/file", "whatever\n"); } void test_core_stat__cleanup(void) { git_futils_rmdir_r("root", NULL, GIT_RMDIR_REMOVE_FILES); } #define cl_assert_error(val) \ do { err = errno; cl_assert_equal_i((val), err); } while (0) void test_core_stat__0(void) { struct stat st; int err; cl_assert_equal_i(0, p_lstat("root", &st)); cl_assert(S_ISDIR(st.st_mode)); cl_assert_error(0); cl_assert_equal_i(0, p_lstat("root/", &st)); cl_assert(S_ISDIR(st.st_mode)); cl_assert_error(0); cl_assert_equal_i(0, p_lstat("root/file", &st)); cl_assert(S_ISREG(st.st_mode)); cl_assert_error(0); cl_assert_equal_i(0, p_lstat("root/d1", &st)); cl_assert(S_ISDIR(st.st_mode)); cl_assert_error(0); cl_assert_equal_i(0, p_lstat("root/d1/", &st)); cl_assert(S_ISDIR(st.st_mode)); cl_assert_error(0); cl_assert_equal_i(0, p_lstat("root/d1/file", &st)); cl_assert(S_ISREG(st.st_mode)); cl_assert_error(0); cl_assert(p_lstat("root/missing", &st) < 0); cl_assert_error(ENOENT); cl_assert(p_lstat("root/missing/but/could/be/created", &st) < 0); cl_assert_error(ENOENT); cl_assert(p_lstat_posixly("root/missing/but/could/be/created", &st) < 0); cl_assert_error(ENOENT); cl_assert(p_lstat("root/d1/missing", &st) < 0); cl_assert_error(ENOENT); cl_assert(p_lstat("root/d1/missing/deeper/path", &st) < 0); cl_assert_error(ENOENT); cl_assert(p_lstat_posixly("root/d1/missing/deeper/path", &st) < 0); cl_assert_error(ENOENT); cl_assert(p_lstat_posixly("root/d1/file/deeper/path", &st) < 0); cl_assert_error(ENOTDIR); cl_assert(p_lstat("root/file/invalid", &st) < 0); #ifdef GIT_WIN32 cl_assert_error(ENOENT); #else cl_assert_error(ENOTDIR); #endif cl_assert(p_lstat_posixly("root/file/invalid", &st) < 0); cl_assert_error(ENOTDIR); cl_assert(p_lstat("root/file/invalid/deeper_path", &st) < 0); #ifdef GIT_WIN32 cl_assert_error(ENOENT); #else cl_assert_error(ENOTDIR); #endif cl_assert(p_lstat_posixly("root/file/invalid/deeper_path", &st) < 0); cl_assert_error(ENOTDIR); cl_assert(p_lstat_posixly("root/d1/file/extra", &st) < 0); cl_assert_error(ENOTDIR); cl_assert(p_lstat_posixly("root/d1/file/further/invalid/items", &st) < 0); cl_assert_error(ENOTDIR); } libgit2-0.19.0/tests-clar/core/string.c000066400000000000000000000025431216214232500176220ustar00rootroot00000000000000#include "clar_libgit2.h" /* compare prefixes */ void test_core_string__0(void) { cl_assert(git__prefixcmp("", "") == 0); cl_assert(git__prefixcmp("a", "") == 0); cl_assert(git__prefixcmp("", "a") < 0); cl_assert(git__prefixcmp("a", "b") < 0); cl_assert(git__prefixcmp("b", "a") > 0); cl_assert(git__prefixcmp("ab", "a") == 0); cl_assert(git__prefixcmp("ab", "ac") < 0); cl_assert(git__prefixcmp("ab", "aa") > 0); } /* compare suffixes */ void test_core_string__1(void) { cl_assert(git__suffixcmp("", "") == 0); cl_assert(git__suffixcmp("a", "") == 0); cl_assert(git__suffixcmp("", "a") < 0); cl_assert(git__suffixcmp("a", "b") < 0); cl_assert(git__suffixcmp("b", "a") > 0); cl_assert(git__suffixcmp("ba", "a") == 0); cl_assert(git__suffixcmp("zaa", "ac") < 0); cl_assert(git__suffixcmp("zaz", "ac") > 0); } /* compare icase sorting with case equality */ void test_core_string__2(void) { cl_assert(git__strcasesort_cmp("", "") == 0); cl_assert(git__strcasesort_cmp("foo", "foo") == 0); cl_assert(git__strcasesort_cmp("foo", "bar") > 0); cl_assert(git__strcasesort_cmp("bar", "foo") < 0); cl_assert(git__strcasesort_cmp("foo", "FOO") > 0); cl_assert(git__strcasesort_cmp("FOO", "foo") < 0); cl_assert(git__strcasesort_cmp("foo", "BAR") > 0); cl_assert(git__strcasesort_cmp("BAR", "foo") < 0); cl_assert(git__strcasesort_cmp("fooBar", "foobar") < 0); } libgit2-0.19.0/tests-clar/core/strmap.c000066400000000000000000000044321216214232500176210ustar00rootroot00000000000000#include "clar_libgit2.h" #include "strmap.h" GIT__USE_STRMAP; void test_core_strmap__0(void) { git_strmap *table = git_strmap_alloc(); cl_assert(table != NULL); cl_assert(git_strmap_num_entries(table) == 0); git_strmap_free(table); } static void insert_strings(git_strmap *table, int count) { int i, j, over, err; char *str; for (i = 0; i < count; ++i) { str = malloc(10); for (j = 0; j < 10; ++j) str[j] = 'a' + (i % 26); str[9] = '\0'; /* if > 26, then encode larger value in first letters */ for (j = 0, over = i / 26; over > 0; j++, over = over / 26) str[j] = 'A' + (over % 26); git_strmap_insert(table, str, str, err); cl_assert(err >= 0); } cl_assert((int)git_strmap_num_entries(table) == count); } void test_core_strmap__1(void) { int i; char *str; git_strmap *table = git_strmap_alloc(); cl_assert(table != NULL); insert_strings(table, 20); cl_assert(git_strmap_exists(table, "aaaaaaaaa")); cl_assert(git_strmap_exists(table, "ggggggggg")); cl_assert(!git_strmap_exists(table, "aaaaaaaab")); cl_assert(!git_strmap_exists(table, "abcdefghi")); i = 0; git_strmap_foreach_value(table, str, { i++; free(str); }); cl_assert(i == 20); git_strmap_free(table); } void test_core_strmap__2(void) { khiter_t pos; int i; char *str; git_strmap *table = git_strmap_alloc(); cl_assert(table != NULL); insert_strings(table, 20); cl_assert(git_strmap_exists(table, "aaaaaaaaa")); cl_assert(git_strmap_exists(table, "ggggggggg")); cl_assert(!git_strmap_exists(table, "aaaaaaaab")); cl_assert(!git_strmap_exists(table, "abcdefghi")); cl_assert(git_strmap_exists(table, "bbbbbbbbb")); pos = git_strmap_lookup_index(table, "bbbbbbbbb"); cl_assert(git_strmap_valid_index(table, pos)); cl_assert_equal_s(git_strmap_value_at(table, pos), "bbbbbbbbb"); free(git_strmap_value_at(table, pos)); git_strmap_delete_at(table, pos); cl_assert(!git_strmap_exists(table, "bbbbbbbbb")); i = 0; git_strmap_foreach_value(table, str, { i++; free(str); }); cl_assert(i == 19); git_strmap_free(table); } void test_core_strmap__3(void) { int i; char *str; git_strmap *table = git_strmap_alloc(); cl_assert(table != NULL); insert_strings(table, 10000); i = 0; git_strmap_foreach_value(table, str, { i++; free(str); }); cl_assert(i == 10000); git_strmap_free(table); } libgit2-0.19.0/tests-clar/core/strtol.c000066400000000000000000000021161216214232500176370ustar00rootroot00000000000000#include "clar_libgit2.h" void test_core_strtol__int32(void) { int32_t i; cl_git_pass(git__strtol32(&i, "123", NULL, 10)); cl_assert(i == 123); cl_git_pass(git__strtol32(&i, " +123 ", NULL, 10)); cl_assert(i == 123); cl_git_pass(git__strtol32(&i, " +2147483647 ", NULL, 10)); cl_assert(i == 2147483647); cl_git_pass(git__strtol32(&i, " -2147483648 ", NULL, 10)); cl_assert(i == -2147483648LL); cl_git_fail(git__strtol32(&i, " 2147483657 ", NULL, 10)); cl_git_fail(git__strtol32(&i, " -2147483657 ", NULL, 10)); } void test_core_strtol__int64(void) { int64_t i; cl_git_pass(git__strtol64(&i, "123", NULL, 10)); cl_assert(i == 123); cl_git_pass(git__strtol64(&i, " +123 ", NULL, 10)); cl_assert(i == 123); cl_git_pass(git__strtol64(&i, " +2147483647 ", NULL, 10)); cl_assert(i == 2147483647); cl_git_pass(git__strtol64(&i, " -2147483648 ", NULL, 10)); cl_assert(i == -2147483648LL); cl_git_pass(git__strtol64(&i, " 2147483657 ", NULL, 10)); cl_assert(i == 2147483657LL); cl_git_pass(git__strtol64(&i, " -2147483657 ", NULL, 10)); cl_assert(i == -2147483657LL); } libgit2-0.19.0/tests-clar/core/vector.c000066400000000000000000000136311216214232500176160ustar00rootroot00000000000000#include "clar_libgit2.h" #include "vector.h" /* initial size of 1 would cause writing past array bounds */ void test_core_vector__0(void) { git_vector x; int i; git_vector_init(&x, 1, NULL); for (i = 0; i < 10; ++i) { git_vector_insert(&x, (void*) 0xabc); } git_vector_free(&x); } /* don't read past array bounds on remove() */ void test_core_vector__1(void) { git_vector x; // make initial capacity exact for our insertions. git_vector_init(&x, 3, NULL); git_vector_insert(&x, (void*) 0xabc); git_vector_insert(&x, (void*) 0xdef); git_vector_insert(&x, (void*) 0x123); git_vector_remove(&x, 0); // used to read past array bounds. git_vector_free(&x); } static int test_cmp(const void *a, const void *b) { return *(const int *)a - *(const int *)b; } /* remove duplicates */ void test_core_vector__2(void) { git_vector x; int *ptrs[2]; ptrs[0] = git__malloc(sizeof(int)); ptrs[1] = git__malloc(sizeof(int)); *ptrs[0] = 2; *ptrs[1] = 1; cl_git_pass(git_vector_init(&x, 5, test_cmp)); cl_git_pass(git_vector_insert(&x, ptrs[0])); cl_git_pass(git_vector_insert(&x, ptrs[1])); cl_git_pass(git_vector_insert(&x, ptrs[1])); cl_git_pass(git_vector_insert(&x, ptrs[0])); cl_git_pass(git_vector_insert(&x, ptrs[1])); cl_assert(x.length == 5); git_vector_uniq(&x); cl_assert(x.length == 2); git_vector_free(&x); git__free(ptrs[0]); git__free(ptrs[1]); } static int compare_them(const void *a, const void *b) { return (int)((long)a - (long)b); } /* insert_sorted */ void test_core_vector__3(void) { git_vector x; long i; git_vector_init(&x, 1, &compare_them); for (i = 0; i < 10; i += 2) { git_vector_insert_sorted(&x, (void*)(i + 1), NULL); } for (i = 9; i > 0; i -= 2) { git_vector_insert_sorted(&x, (void*)(i + 1), NULL); } cl_assert(x.length == 10); for (i = 0; i < 10; ++i) { cl_assert(git_vector_get(&x, i) == (void*)(i + 1)); } git_vector_free(&x); } /* insert_sorted with duplicates */ void test_core_vector__4(void) { git_vector x; long i; git_vector_init(&x, 1, &compare_them); for (i = 0; i < 10; i += 2) { git_vector_insert_sorted(&x, (void*)(i + 1), NULL); } for (i = 9; i > 0; i -= 2) { git_vector_insert_sorted(&x, (void*)(i + 1), NULL); } for (i = 0; i < 10; i += 2) { git_vector_insert_sorted(&x, (void*)(i + 1), NULL); } for (i = 9; i > 0; i -= 2) { git_vector_insert_sorted(&x, (void*)(i + 1), NULL); } cl_assert(x.length == 20); for (i = 0; i < 20; ++i) { cl_assert(git_vector_get(&x, i) == (void*)(i / 2 + 1)); } git_vector_free(&x); } typedef struct { int content; int count; } my_struct; static int _struct_count = 0; static int compare_structs(const void *a, const void *b) { return ((const my_struct *)a)->content - ((const my_struct *)b)->content; } static int merge_structs(void **old_raw, void *new) { my_struct *old = *(my_struct **)old_raw; cl_assert(((my_struct *)old)->content == ((my_struct *)new)->content); ((my_struct *)old)->count += 1; git__free(new); _struct_count--; return GIT_EEXISTS; } static my_struct *alloc_struct(int value) { my_struct *st = git__malloc(sizeof(my_struct)); st->content = value; st->count = 0; _struct_count++; return st; } /* insert_sorted with duplicates and special handling */ void test_core_vector__5(void) { git_vector x; int i; git_vector_init(&x, 1, &compare_structs); for (i = 0; i < 10; i += 2) git_vector_insert_sorted(&x, alloc_struct(i), &merge_structs); for (i = 9; i > 0; i -= 2) git_vector_insert_sorted(&x, alloc_struct(i), &merge_structs); cl_assert(x.length == 10); cl_assert(_struct_count == 10); for (i = 0; i < 10; i += 2) git_vector_insert_sorted(&x, alloc_struct(i), &merge_structs); for (i = 9; i > 0; i -= 2) git_vector_insert_sorted(&x, alloc_struct(i), &merge_structs); cl_assert(x.length == 10); cl_assert(_struct_count == 10); for (i = 0; i < 10; ++i) { cl_assert(((my_struct *)git_vector_get(&x, i))->content == i); git__free(git_vector_get(&x, i)); _struct_count--; } git_vector_free(&x); } static int remove_ones(const git_vector *v, size_t idx) { return (git_vector_get(v, idx) == (void *)0x001); } /* Test removal based on callback */ void test_core_vector__remove_matching(void) { git_vector x; size_t i; void *compare; git_vector_init(&x, 1, NULL); git_vector_insert(&x, (void*) 0x001); cl_assert(x.length == 1); git_vector_remove_matching(&x, remove_ones); cl_assert(x.length == 0); git_vector_insert(&x, (void*) 0x001); git_vector_insert(&x, (void*) 0x001); git_vector_insert(&x, (void*) 0x001); cl_assert(x.length == 3); git_vector_remove_matching(&x, remove_ones); cl_assert(x.length == 0); git_vector_insert(&x, (void*) 0x002); git_vector_insert(&x, (void*) 0x001); git_vector_insert(&x, (void*) 0x002); git_vector_insert(&x, (void*) 0x001); cl_assert(x.length == 4); git_vector_remove_matching(&x, remove_ones); cl_assert(x.length == 2); git_vector_foreach(&x, i, compare) { cl_assert(compare != (void *)0x001); } git_vector_clear(&x); git_vector_insert(&x, (void*) 0x001); git_vector_insert(&x, (void*) 0x002); git_vector_insert(&x, (void*) 0x002); git_vector_insert(&x, (void*) 0x001); cl_assert(x.length == 4); git_vector_remove_matching(&x, remove_ones); cl_assert(x.length == 2); git_vector_foreach(&x, i, compare) { cl_assert(compare != (void *)0x001); } git_vector_clear(&x); git_vector_insert(&x, (void*) 0x002); git_vector_insert(&x, (void*) 0x001); git_vector_insert(&x, (void*) 0x002); git_vector_insert(&x, (void*) 0x001); cl_assert(x.length == 4); git_vector_remove_matching(&x, remove_ones); cl_assert(x.length == 2); git_vector_foreach(&x, i, compare) { cl_assert(compare != (void *)0x001); } git_vector_clear(&x); git_vector_insert(&x, (void*) 0x002); git_vector_insert(&x, (void*) 0x003); git_vector_insert(&x, (void*) 0x002); git_vector_insert(&x, (void*) 0x003); cl_assert(x.length == 4); git_vector_remove_matching(&x, remove_ones); cl_assert(x.length == 4); git_vector_free(&x); } libgit2-0.19.0/tests-clar/date/000077500000000000000000000000001216214232500161315ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/date/date.c000066400000000000000000000005101216214232500172060ustar00rootroot00000000000000#include "clar_libgit2.h" #include "util.h" void test_date_date__overflow(void) { #ifdef __LP64__ git_time_t d2038, d2039; /* This is expected to fail on a 32-bit machine. */ cl_git_pass(git__date_parse(&d2038, "2038-1-1")); cl_git_pass(git__date_parse(&d2039, "2039-1-1")); cl_assert(d2038 < d2039); #endif } libgit2-0.19.0/tests-clar/diff/000077500000000000000000000000001216214232500161245ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/diff/blob.c000066400000000000000000001016501216214232500172110ustar00rootroot00000000000000#include "clar_libgit2.h" #include "diff_helpers.h" static git_repository *g_repo = NULL; static diff_expects expected; static git_diff_options opts; static git_blob *d, *alien; static void quick_diff_blob_to_str( const git_blob *blob, const char *blob_path, const char *str, size_t len, const char *str_path) { memset(&expected, 0, sizeof(expected)); if (str && !len) len = strlen(str); cl_git_pass(git_diff_blob_to_buffer( blob, blob_path, str, len, str_path, &opts, diff_file_cb, diff_hunk_cb, diff_line_cb, &expected)); } void test_diff_blob__initialize(void) { git_oid oid; g_repo = cl_git_sandbox_init("attr"); GIT_INIT_STRUCTURE(&opts, GIT_DIFF_OPTIONS_VERSION); opts.context_lines = 1; opts.interhunk_lines = 0; memset(&expected, 0, sizeof(expected)); /* tests/resources/attr/root_test4.txt */ cl_git_pass(git_oid_fromstrn(&oid, "a0f7217a", 8)); cl_git_pass(git_blob_lookup_prefix(&d, g_repo, &oid, 4)); /* alien.png */ cl_git_pass(git_oid_fromstrn(&oid, "edf3dcee", 8)); cl_git_pass(git_blob_lookup_prefix(&alien, g_repo, &oid, 4)); } void test_diff_blob__cleanup(void) { git_blob_free(d); d = NULL; git_blob_free(alien); alien = NULL; cl_git_sandbox_cleanup(); } void test_diff_blob__can_compare_text_blobs(void) { git_blob *a, *b, *c; git_oid a_oid, b_oid, c_oid; /* tests/resources/attr/root_test1 */ cl_git_pass(git_oid_fromstrn(&a_oid, "45141a79", 8)); cl_git_pass(git_blob_lookup_prefix(&a, g_repo, &a_oid, 4)); /* tests/resources/attr/root_test2 */ cl_git_pass(git_oid_fromstrn(&b_oid, "4d713dc4", 8)); cl_git_pass(git_blob_lookup_prefix(&b, g_repo, &b_oid, 4)); /* tests/resources/attr/root_test3 */ cl_git_pass(git_oid_fromstrn(&c_oid, "c96bbb2c2557a832", 16)); cl_git_pass(git_blob_lookup_prefix(&c, g_repo, &c_oid, 8)); /* Doing the equivalent of a `git diff -U1` on these files */ /* diff on tests/resources/attr/root_test1 */ cl_git_pass(git_diff_blobs( a, NULL, b, NULL, &opts, diff_file_cb, diff_hunk_cb, diff_line_cb, &expected)); cl_assert_equal_i(1, expected.files); cl_assert_equal_i(1, expected.file_status[GIT_DELTA_MODIFIED]); cl_assert_equal_i(0, expected.files_binary); cl_assert_equal_i(1, expected.hunks); cl_assert_equal_i(6, expected.lines); cl_assert_equal_i(1, expected.line_ctxt); cl_assert_equal_i(5, expected.line_adds); cl_assert_equal_i(0, expected.line_dels); /* diff on tests/resources/attr/root_test2 */ memset(&expected, 0, sizeof(expected)); cl_git_pass(git_diff_blobs( b, NULL, c, NULL, &opts, diff_file_cb, diff_hunk_cb, diff_line_cb, &expected)); cl_assert_equal_i(1, expected.files); cl_assert_equal_i(1, expected.file_status[GIT_DELTA_MODIFIED]); cl_assert_equal_i(0, expected.files_binary); cl_assert_equal_i(1, expected.hunks); cl_assert_equal_i(15, expected.lines); cl_assert_equal_i(3, expected.line_ctxt); cl_assert_equal_i(9, expected.line_adds); cl_assert_equal_i(3, expected.line_dels); /* diff on tests/resources/attr/root_test3 */ memset(&expected, 0, sizeof(expected)); cl_git_pass(git_diff_blobs( a, NULL, c, NULL, &opts, diff_file_cb, diff_hunk_cb, diff_line_cb, &expected)); cl_assert_equal_i(1, expected.files); cl_assert_equal_i(1, expected.file_status[GIT_DELTA_MODIFIED]); cl_assert_equal_i(0, expected.files_binary); cl_assert_equal_i(1, expected.hunks); cl_assert_equal_i(13, expected.lines); cl_assert_equal_i(0, expected.line_ctxt); cl_assert_equal_i(12, expected.line_adds); cl_assert_equal_i(1, expected.line_dels); memset(&expected, 0, sizeof(expected)); cl_git_pass(git_diff_blobs( c, NULL, d, NULL, &opts, diff_file_cb, diff_hunk_cb, diff_line_cb, &expected)); cl_assert_equal_i(1, expected.files); cl_assert_equal_i(1, expected.file_status[GIT_DELTA_MODIFIED]); cl_assert_equal_i(0, expected.files_binary); cl_assert_equal_i(2, expected.hunks); cl_assert_equal_i(14, expected.lines); cl_assert_equal_i(4, expected.line_ctxt); cl_assert_equal_i(6, expected.line_adds); cl_assert_equal_i(4, expected.line_dels); git_blob_free(a); git_blob_free(b); git_blob_free(c); } void test_diff_blob__can_compare_text_blobs_with_patch(void) { git_blob *a, *b, *c; git_oid a_oid, b_oid, c_oid; git_diff_patch *p; const git_diff_delta *delta; size_t tc, ta, td; /* tests/resources/attr/root_test1 */ cl_git_pass(git_oid_fromstrn(&a_oid, "45141a79", 8)); cl_git_pass(git_blob_lookup_prefix(&a, g_repo, &a_oid, 4)); /* tests/resources/attr/root_test2 */ cl_git_pass(git_oid_fromstrn(&b_oid, "4d713dc4", 8)); cl_git_pass(git_blob_lookup_prefix(&b, g_repo, &b_oid, 4)); /* tests/resources/attr/root_test3 */ cl_git_pass(git_oid_fromstrn(&c_oid, "c96bbb2c2557a832", 16)); cl_git_pass(git_blob_lookup_prefix(&c, g_repo, &c_oid, 8)); /* Doing the equivalent of a `git diff -U1` on these files */ /* diff on tests/resources/attr/root_test1 */ cl_git_pass(git_diff_patch_from_blobs(&p, a, NULL, b, NULL, &opts)); cl_assert(p != NULL); delta = git_diff_patch_delta(p); cl_assert(delta != NULL); cl_assert_equal_i(GIT_DELTA_MODIFIED, delta->status); cl_assert(git_oid_equal(git_blob_id(a), &delta->old_file.oid)); cl_assert_equal_sz(git_blob_rawsize(a), delta->old_file.size); cl_assert(git_oid_equal(git_blob_id(b), &delta->new_file.oid)); cl_assert_equal_sz(git_blob_rawsize(b), delta->new_file.size); cl_assert_equal_i(1, (int)git_diff_patch_num_hunks(p)); cl_assert_equal_i(6, git_diff_patch_num_lines_in_hunk(p, 0)); cl_git_pass(git_diff_patch_line_stats(&tc, &ta, &td, p)); cl_assert_equal_i(1, (int)tc); cl_assert_equal_i(5, (int)ta); cl_assert_equal_i(0, (int)td); git_diff_patch_free(p); /* diff on tests/resources/attr/root_test2 */ cl_git_pass(git_diff_patch_from_blobs(&p, b, NULL, c, NULL, &opts)); cl_assert(p != NULL); delta = git_diff_patch_delta(p); cl_assert(delta != NULL); cl_assert_equal_i(GIT_DELTA_MODIFIED, delta->status); cl_assert(git_oid_equal(git_blob_id(b), &delta->old_file.oid)); cl_assert_equal_sz(git_blob_rawsize(b), delta->old_file.size); cl_assert(git_oid_equal(git_blob_id(c), &delta->new_file.oid)); cl_assert_equal_sz(git_blob_rawsize(c), delta->new_file.size); cl_assert_equal_i(1, (int)git_diff_patch_num_hunks(p)); cl_assert_equal_i(15, git_diff_patch_num_lines_in_hunk(p, 0)); cl_git_pass(git_diff_patch_line_stats(&tc, &ta, &td, p)); cl_assert_equal_i(3, (int)tc); cl_assert_equal_i(9, (int)ta); cl_assert_equal_i(3, (int)td); git_diff_patch_free(p); /* diff on tests/resources/attr/root_test3 */ cl_git_pass(git_diff_patch_from_blobs(&p, a, NULL, c, NULL, &opts)); cl_assert(p != NULL); delta = git_diff_patch_delta(p); cl_assert(delta != NULL); cl_assert_equal_i(GIT_DELTA_MODIFIED, delta->status); cl_assert(git_oid_equal(git_blob_id(a), &delta->old_file.oid)); cl_assert_equal_sz(git_blob_rawsize(a), delta->old_file.size); cl_assert(git_oid_equal(git_blob_id(c), &delta->new_file.oid)); cl_assert_equal_sz(git_blob_rawsize(c), delta->new_file.size); cl_git_pass(git_diff_patch_line_stats(&tc, &ta, &td, p)); cl_assert_equal_i(0, (int)tc); cl_assert_equal_i(12, (int)ta); cl_assert_equal_i(1, (int)td); git_diff_patch_free(p); /* one more */ cl_git_pass(git_diff_patch_from_blobs(&p, c, NULL, d, NULL, &opts)); cl_assert(p != NULL); delta = git_diff_patch_delta(p); cl_assert(delta != NULL); cl_assert_equal_i(GIT_DELTA_MODIFIED, delta->status); cl_assert(git_oid_equal(git_blob_id(c), &delta->old_file.oid)); cl_assert_equal_sz(git_blob_rawsize(c), delta->old_file.size); cl_assert(git_oid_equal(git_blob_id(d), &delta->new_file.oid)); cl_assert_equal_sz(git_blob_rawsize(d), delta->new_file.size); cl_assert_equal_i(2, (int)git_diff_patch_num_hunks(p)); cl_assert_equal_i(5, git_diff_patch_num_lines_in_hunk(p, 0)); cl_assert_equal_i(9, git_diff_patch_num_lines_in_hunk(p, 1)); cl_git_pass(git_diff_patch_line_stats(&tc, &ta, &td, p)); cl_assert_equal_i(4, (int)tc); cl_assert_equal_i(6, (int)ta); cl_assert_equal_i(4, (int)td); git_diff_patch_free(p); git_blob_free(a); git_blob_free(b); git_blob_free(c); } void test_diff_blob__can_compare_against_null_blobs(void) { git_blob *e = NULL; cl_git_pass(git_diff_blobs( d, NULL, e, NULL, &opts, diff_file_cb, diff_hunk_cb, diff_line_cb, &expected)); cl_assert_equal_i(1, expected.files); cl_assert_equal_i(1, expected.file_status[GIT_DELTA_DELETED]); cl_assert_equal_i(0, expected.files_binary); cl_assert_equal_i(1, expected.hunks); cl_assert_equal_i(14, expected.hunk_old_lines); cl_assert_equal_i(14, expected.lines); cl_assert_equal_i(14, expected.line_dels); opts.flags |= GIT_DIFF_REVERSE; memset(&expected, 0, sizeof(expected)); cl_git_pass(git_diff_blobs( d, NULL, e, NULL, &opts, diff_file_cb, diff_hunk_cb, diff_line_cb, &expected)); cl_assert_equal_i(1, expected.files); cl_assert_equal_i(1, expected.file_status[GIT_DELTA_ADDED]); cl_assert_equal_i(0, expected.files_binary); cl_assert_equal_i(1, expected.hunks); cl_assert_equal_i(14, expected.hunk_new_lines); cl_assert_equal_i(14, expected.lines); cl_assert_equal_i(14, expected.line_adds); opts.flags ^= GIT_DIFF_REVERSE; memset(&expected, 0, sizeof(expected)); cl_git_pass(git_diff_blobs( alien, NULL, NULL, NULL, &opts, diff_file_cb, diff_hunk_cb, diff_line_cb, &expected)); cl_assert_equal_i(1, expected.files); cl_assert_equal_i(1, expected.files_binary); cl_assert_equal_i(1, expected.file_status[GIT_DELTA_DELETED]); cl_assert_equal_i(0, expected.hunks); cl_assert_equal_i(0, expected.lines); memset(&expected, 0, sizeof(expected)); cl_git_pass(git_diff_blobs( NULL, NULL, alien, NULL, &opts, diff_file_cb, diff_hunk_cb, diff_line_cb, &expected)); cl_assert_equal_i(1, expected.files); cl_assert_equal_i(1, expected.files_binary); cl_assert_equal_i(1, expected.file_status[GIT_DELTA_ADDED]); cl_assert_equal_i(0, expected.hunks); cl_assert_equal_i(0, expected.lines); } void test_diff_blob__can_compare_against_null_blobs_with_patch(void) { git_blob *e = NULL; git_diff_patch *p; const git_diff_delta *delta; int line; char origin; cl_git_pass(git_diff_patch_from_blobs(&p, d, NULL, e, NULL, &opts)); cl_assert(p != NULL); delta = git_diff_patch_delta(p); cl_assert(delta != NULL); cl_assert_equal_i(GIT_DELTA_DELETED, delta->status); cl_assert(git_oid_equal(git_blob_id(d), &delta->old_file.oid)); cl_assert_equal_sz(git_blob_rawsize(d), delta->old_file.size); cl_assert(git_oid_iszero(&delta->new_file.oid)); cl_assert_equal_sz(0, delta->new_file.size); cl_assert_equal_i(1, (int)git_diff_patch_num_hunks(p)); cl_assert_equal_i(14, git_diff_patch_num_lines_in_hunk(p, 0)); for (line = 0; line < git_diff_patch_num_lines_in_hunk(p, 0); ++line) { cl_git_pass(git_diff_patch_get_line_in_hunk( &origin, NULL, NULL, NULL, NULL, p, 0, line)); cl_assert_equal_i(GIT_DIFF_LINE_DELETION, (int)origin); } git_diff_patch_free(p); opts.flags |= GIT_DIFF_REVERSE; cl_git_pass(git_diff_patch_from_blobs(&p, d, NULL, e, NULL, &opts)); cl_assert(p != NULL); delta = git_diff_patch_delta(p); cl_assert(delta != NULL); cl_assert_equal_i(GIT_DELTA_ADDED, delta->status); cl_assert(git_oid_iszero(&delta->old_file.oid)); cl_assert_equal_sz(0, delta->old_file.size); cl_assert(git_oid_equal(git_blob_id(d), &delta->new_file.oid)); cl_assert_equal_sz(git_blob_rawsize(d), delta->new_file.size); cl_assert_equal_i(1, (int)git_diff_patch_num_hunks(p)); cl_assert_equal_i(14, git_diff_patch_num_lines_in_hunk(p, 0)); for (line = 0; line < git_diff_patch_num_lines_in_hunk(p, 0); ++line) { cl_git_pass(git_diff_patch_get_line_in_hunk( &origin, NULL, NULL, NULL, NULL, p, 0, line)); cl_assert_equal_i(GIT_DIFF_LINE_ADDITION, (int)origin); } git_diff_patch_free(p); opts.flags ^= GIT_DIFF_REVERSE; cl_git_pass(git_diff_patch_from_blobs(&p, alien, NULL, NULL, NULL, &opts)); cl_assert(p != NULL); delta = git_diff_patch_delta(p); cl_assert(delta != NULL); cl_assert_equal_i(GIT_DELTA_DELETED, delta->status); cl_assert((delta->flags & GIT_DIFF_FLAG_BINARY) != 0); cl_assert_equal_i(0, (int)git_diff_patch_num_hunks(p)); git_diff_patch_free(p); cl_git_pass(git_diff_patch_from_blobs(&p, NULL, NULL, alien, NULL, &opts)); cl_assert(p != NULL); delta = git_diff_patch_delta(p); cl_assert(delta != NULL); cl_assert_equal_i(GIT_DELTA_ADDED, delta->status); cl_assert((delta->flags & GIT_DIFF_FLAG_BINARY) != 0); cl_assert_equal_i(0, (int)git_diff_patch_num_hunks(p)); git_diff_patch_free(p); } static void assert_identical_blobs_comparison(diff_expects *expected) { cl_assert_equal_i(1, expected->files); cl_assert_equal_i(1, expected->file_status[GIT_DELTA_UNMODIFIED]); cl_assert_equal_i(0, expected->hunks); cl_assert_equal_i(0, expected->lines); } void test_diff_blob__can_compare_identical_blobs(void) { opts.flags |= GIT_DIFF_INCLUDE_UNMODIFIED; cl_git_pass(git_diff_blobs( d, NULL, d, NULL, &opts, diff_file_cb, diff_hunk_cb, diff_line_cb, &expected)); assert_identical_blobs_comparison(&expected); cl_assert_equal_i(0, expected.files_binary); memset(&expected, 0, sizeof(expected)); cl_git_pass(git_diff_blobs( NULL, NULL, NULL, NULL, &opts, diff_file_cb, diff_hunk_cb, diff_line_cb, &expected)); assert_identical_blobs_comparison(&expected); cl_assert_equal_i(0, expected.files_binary); memset(&expected, 0, sizeof(expected)); cl_git_pass(git_diff_blobs( alien, NULL, alien, NULL, &opts, diff_file_cb, diff_hunk_cb, diff_line_cb, &expected)); assert_identical_blobs_comparison(&expected); cl_assert(expected.files_binary > 0); } void test_diff_blob__can_compare_identical_blobs_with_patch(void) { git_diff_patch *p; const git_diff_delta *delta; cl_git_pass(git_diff_patch_from_blobs(&p, d, NULL, d, NULL, &opts)); cl_assert(p != NULL); delta = git_diff_patch_delta(p); cl_assert(delta != NULL); cl_assert_equal_i(GIT_DELTA_UNMODIFIED, delta->status); cl_assert_equal_sz(delta->old_file.size, git_blob_rawsize(d)); cl_assert(git_oid_equal(git_blob_id(d), &delta->old_file.oid)); cl_assert_equal_sz(delta->new_file.size, git_blob_rawsize(d)); cl_assert(git_oid_equal(git_blob_id(d), &delta->new_file.oid)); cl_assert_equal_i(0, (int)git_diff_patch_num_hunks(p)); git_diff_patch_free(p); cl_git_pass(git_diff_patch_from_blobs(&p, NULL, NULL, NULL, NULL, &opts)); cl_assert(p != NULL); delta = git_diff_patch_delta(p); cl_assert(delta != NULL); cl_assert_equal_i(GIT_DELTA_UNMODIFIED, delta->status); cl_assert_equal_sz(0, delta->old_file.size); cl_assert(git_oid_iszero(&delta->old_file.oid)); cl_assert_equal_sz(0, delta->new_file.size); cl_assert(git_oid_iszero(&delta->new_file.oid)); cl_assert_equal_i(0, (int)git_diff_patch_num_hunks(p)); git_diff_patch_free(p); cl_git_pass(git_diff_patch_from_blobs(&p, alien, NULL, alien, NULL, &opts)); cl_assert(p != NULL); cl_assert_equal_i(GIT_DELTA_UNMODIFIED, git_diff_patch_delta(p)->status); cl_assert_equal_i(0, (int)git_diff_patch_num_hunks(p)); git_diff_patch_free(p); } static void assert_binary_blobs_comparison(diff_expects *expected) { cl_assert(expected->files_binary > 0); cl_assert_equal_i(1, expected->files); cl_assert_equal_i(1, expected->file_status[GIT_DELTA_MODIFIED]); cl_assert_equal_i(0, expected->hunks); cl_assert_equal_i(0, expected->lines); } void test_diff_blob__can_compare_two_binary_blobs(void) { git_blob *heart; git_oid h_oid; /* heart.png */ cl_git_pass(git_oid_fromstrn(&h_oid, "de863bff", 8)); cl_git_pass(git_blob_lookup_prefix(&heart, g_repo, &h_oid, 4)); cl_git_pass(git_diff_blobs( alien, NULL, heart, NULL, &opts, diff_file_cb, diff_hunk_cb, diff_line_cb, &expected)); assert_binary_blobs_comparison(&expected); memset(&expected, 0, sizeof(expected)); cl_git_pass(git_diff_blobs( heart, NULL, alien, NULL, &opts, diff_file_cb, diff_hunk_cb, diff_line_cb, &expected)); assert_binary_blobs_comparison(&expected); git_blob_free(heart); } void test_diff_blob__can_compare_a_binary_blob_and_a_text_blob(void) { cl_git_pass(git_diff_blobs( alien, NULL, d, NULL, &opts, diff_file_cb, diff_hunk_cb, diff_line_cb, &expected)); assert_binary_blobs_comparison(&expected); memset(&expected, 0, sizeof(expected)); cl_git_pass(git_diff_blobs( d, NULL, alien, NULL, &opts, diff_file_cb, diff_hunk_cb, diff_line_cb, &expected)); assert_binary_blobs_comparison(&expected); } /* * $ git diff fe773770 a0f7217 * diff --git a/fe773770 b/a0f7217 * index fe77377..a0f7217 100644 * --- a/fe773770 * +++ b/a0f7217 * @@ -1,6 +1,6 @@ * Here is some stuff at the start * * -This should go in one hunk * +This should go in one hunk (first) * * Some additional lines * * @@ -8,7 +8,7 @@ Down here below the other lines * * With even more at the end * * -Followed by a second hunk of stuff * +Followed by a second hunk of stuff (second) * * That happens down here */ void test_diff_blob__comparing_two_text_blobs_honors_interhunkcontext(void) { git_blob *old_d; git_oid old_d_oid; opts.context_lines = 3; /* tests/resources/attr/root_test1 from commit f5b0af1 */ cl_git_pass(git_oid_fromstrn(&old_d_oid, "fe773770", 8)); cl_git_pass(git_blob_lookup_prefix(&old_d, g_repo, &old_d_oid, 4)); /* Test with default inter-hunk-context (not set) => default is 0 */ cl_git_pass(git_diff_blobs( old_d, NULL, d, NULL, &opts, diff_file_cb, diff_hunk_cb, diff_line_cb, &expected)); cl_assert_equal_i(2, expected.hunks); /* Test with inter-hunk-context explicitly set to 0 */ opts.interhunk_lines = 0; memset(&expected, 0, sizeof(expected)); cl_git_pass(git_diff_blobs( old_d, NULL, d, NULL, &opts, diff_file_cb, diff_hunk_cb, diff_line_cb, &expected)); cl_assert_equal_i(2, expected.hunks); /* Test with inter-hunk-context explicitly set to 1 */ opts.interhunk_lines = 1; memset(&expected, 0, sizeof(expected)); cl_git_pass(git_diff_blobs( old_d, NULL, d, NULL, &opts, diff_file_cb, diff_hunk_cb, diff_line_cb, &expected)); cl_assert_equal_i(1, expected.hunks); git_blob_free(old_d); } void test_diff_blob__checks_options_version_too_low(void) { const git_error *err; opts.version = 0; cl_git_fail(git_diff_blobs( d, NULL, alien, NULL, &opts, diff_file_cb, diff_hunk_cb, diff_line_cb, &expected)); err = giterr_last(); cl_assert_equal_i(GITERR_INVALID, err->klass); } void test_diff_blob__checks_options_version_too_high(void) { const git_error *err; opts.version = 1024; cl_git_fail(git_diff_blobs( d, NULL, alien, NULL, &opts, diff_file_cb, diff_hunk_cb, diff_line_cb, &expected)); err = giterr_last(); cl_assert_equal_i(GITERR_INVALID, err->klass); } void test_diff_blob__can_correctly_detect_a_binary_blob_as_binary(void) { /* alien.png */ cl_assert_equal_i(true, git_blob_is_binary(alien)); } void test_diff_blob__can_correctly_detect_a_textual_blob_as_non_binary(void) { /* tests/resources/attr/root_test4.txt */ cl_assert_equal_i(false, git_blob_is_binary(d)); } /* * git_diff_blob_to_buffer tests */ static void assert_changed_single_one_line_file( diff_expects *expected, git_delta_t mod) { cl_assert_equal_i(1, expected->files); cl_assert_equal_i(1, expected->file_status[mod]); cl_assert_equal_i(1, expected->hunks); cl_assert_equal_i(1, expected->lines); if (mod == GIT_DELTA_ADDED) cl_assert_equal_i(1, expected->line_adds); else if (mod == GIT_DELTA_DELETED) cl_assert_equal_i(1, expected->line_dels); } void test_diff_blob__can_compare_blob_to_buffer(void) { git_blob *a; git_oid a_oid; const char *a_content = "Hello from the root\n"; const char *b_content = "Hello from the root\n\nSome additional lines\n\nDown here below\n\n"; /* tests/resources/attr/root_test1 */ cl_git_pass(git_oid_fromstrn(&a_oid, "45141a79", 8)); cl_git_pass(git_blob_lookup_prefix(&a, g_repo, &a_oid, 4)); /* diff from blob a to content of b */ quick_diff_blob_to_str(a, NULL, b_content, 0, NULL); cl_assert_equal_i(1, expected.files); cl_assert_equal_i(1, expected.file_status[GIT_DELTA_MODIFIED]); cl_assert_equal_i(0, expected.files_binary); cl_assert_equal_i(1, expected.hunks); cl_assert_equal_i(6, expected.lines); cl_assert_equal_i(1, expected.line_ctxt); cl_assert_equal_i(5, expected.line_adds); cl_assert_equal_i(0, expected.line_dels); /* diff from blob a to content of a */ opts.flags |= GIT_DIFF_INCLUDE_UNMODIFIED; quick_diff_blob_to_str(a, NULL, a_content, 0, NULL); assert_identical_blobs_comparison(&expected); /* diff from NULL blob to content of a */ memset(&expected, 0, sizeof(expected)); quick_diff_blob_to_str(NULL, NULL, a_content, 0, NULL); assert_changed_single_one_line_file(&expected, GIT_DELTA_ADDED); /* diff from blob a to NULL buffer */ memset(&expected, 0, sizeof(expected)); quick_diff_blob_to_str(a, NULL, NULL, 0, NULL); assert_changed_single_one_line_file(&expected, GIT_DELTA_DELETED); /* diff with reverse */ opts.flags ^= GIT_DIFF_REVERSE; memset(&expected, 0, sizeof(expected)); quick_diff_blob_to_str(a, NULL, NULL, 0, NULL); assert_changed_single_one_line_file(&expected, GIT_DELTA_ADDED); git_blob_free(a); } void test_diff_blob__can_compare_blob_to_buffer_with_patch(void) { git_diff_patch *p; git_blob *a; git_oid a_oid; const char *a_content = "Hello from the root\n"; const char *b_content = "Hello from the root\n\nSome additional lines\n\nDown here below\n\n"; size_t tc, ta, td; /* tests/resources/attr/root_test1 */ cl_git_pass(git_oid_fromstrn(&a_oid, "45141a79", 8)); cl_git_pass(git_blob_lookup_prefix(&a, g_repo, &a_oid, 4)); /* diff from blob a to content of b */ cl_git_pass(git_diff_patch_from_blob_and_buffer( &p, a, NULL, b_content, strlen(b_content), NULL, &opts)); cl_assert(p != NULL); cl_assert_equal_i(GIT_DELTA_MODIFIED, git_diff_patch_delta(p)->status); cl_assert_equal_i(1, (int)git_diff_patch_num_hunks(p)); cl_assert_equal_i(6, git_diff_patch_num_lines_in_hunk(p, 0)); cl_git_pass(git_diff_patch_line_stats(&tc, &ta, &td, p)); cl_assert_equal_i(1, (int)tc); cl_assert_equal_i(5, (int)ta); cl_assert_equal_i(0, (int)td); git_diff_patch_free(p); /* diff from blob a to content of a */ opts.flags |= GIT_DIFF_INCLUDE_UNMODIFIED; cl_git_pass(git_diff_patch_from_blob_and_buffer( &p, a, NULL, a_content, strlen(a_content), NULL, &opts)); cl_assert(p != NULL); cl_assert_equal_i(GIT_DELTA_UNMODIFIED, git_diff_patch_delta(p)->status); cl_assert_equal_i(0, (int)git_diff_patch_num_hunks(p)); git_diff_patch_free(p); /* diff from NULL blob to content of a */ cl_git_pass(git_diff_patch_from_blob_and_buffer( &p, NULL, NULL, a_content, strlen(a_content), NULL, &opts)); cl_assert(p != NULL); cl_assert_equal_i(GIT_DELTA_ADDED, git_diff_patch_delta(p)->status); cl_assert_equal_i(1, (int)git_diff_patch_num_hunks(p)); cl_assert_equal_i(1, git_diff_patch_num_lines_in_hunk(p, 0)); git_diff_patch_free(p); /* diff from blob a to NULL buffer */ cl_git_pass(git_diff_patch_from_blob_and_buffer( &p, a, NULL, NULL, 0, NULL, &opts)); cl_assert(p != NULL); cl_assert_equal_i(GIT_DELTA_DELETED, git_diff_patch_delta(p)->status); cl_assert_equal_i(1, (int)git_diff_patch_num_hunks(p)); cl_assert_equal_i(1, git_diff_patch_num_lines_in_hunk(p, 0)); git_diff_patch_free(p); /* diff with reverse */ opts.flags ^= GIT_DIFF_REVERSE; cl_git_pass(git_diff_patch_from_blob_and_buffer( &p, a, NULL, NULL, 0, NULL, &opts)); cl_assert(p != NULL); cl_assert_equal_i(GIT_DELTA_ADDED, git_diff_patch_delta(p)->status); cl_assert_equal_i(1, (int)git_diff_patch_num_hunks(p)); cl_assert_equal_i(1, git_diff_patch_num_lines_in_hunk(p, 0)); git_diff_patch_free(p); git_blob_free(a); } static void assert_one_modified_with_lines(diff_expects *expected, int lines) { cl_assert_equal_i(1, expected->files); cl_assert_equal_i(1, expected->file_status[GIT_DELTA_MODIFIED]); cl_assert_equal_i(0, expected->files_binary); cl_assert_equal_i(lines, expected->lines); } void test_diff_blob__binary_data_comparisons(void) { git_blob *bin, *nonbin; git_oid oid; const char *nonbin_content = "Hello from the root\n"; size_t nonbin_len = 20; const char *bin_content = "0123456789\n\x01\x02\x03\x04\x05\x06\x07\x08\x09\x00\n0123456789\n"; size_t bin_len = 33; opts.flags |= GIT_DIFF_INCLUDE_UNMODIFIED; cl_git_pass(git_oid_fromstrn(&oid, "45141a79", 8)); cl_git_pass(git_blob_lookup_prefix(&nonbin, g_repo, &oid, 4)); cl_git_pass(git_oid_fromstrn(&oid, "b435cd56", 8)); cl_git_pass(git_blob_lookup_prefix(&bin, g_repo, &oid, 4)); /* non-binary to reference content */ quick_diff_blob_to_str(nonbin, NULL, nonbin_content, nonbin_len, NULL); assert_identical_blobs_comparison(&expected); cl_assert_equal_i(0, expected.files_binary); /* binary to reference content */ quick_diff_blob_to_str(bin, NULL, bin_content, bin_len, NULL); assert_identical_blobs_comparison(&expected); cl_assert_equal_i(1, expected.files_binary); /* non-binary to binary content */ quick_diff_blob_to_str(nonbin, NULL, bin_content, bin_len, NULL); assert_binary_blobs_comparison(&expected); /* binary to non-binary content */ quick_diff_blob_to_str(bin, NULL, nonbin_content, nonbin_len, NULL); assert_binary_blobs_comparison(&expected); /* non-binary to binary blob */ memset(&expected, 0, sizeof(expected)); cl_git_pass(git_diff_blobs( bin, NULL, nonbin, NULL, &opts, diff_file_cb, diff_hunk_cb, diff_line_cb, &expected)); assert_binary_blobs_comparison(&expected); /* * repeat with FORCE_TEXT */ opts.flags |= GIT_DIFF_FORCE_TEXT; quick_diff_blob_to_str(bin, NULL, bin_content, bin_len, NULL); assert_identical_blobs_comparison(&expected); quick_diff_blob_to_str(nonbin, NULL, bin_content, bin_len, NULL); assert_one_modified_with_lines(&expected, 4); quick_diff_blob_to_str(bin, NULL, nonbin_content, nonbin_len, NULL); assert_one_modified_with_lines(&expected, 4); memset(&expected, 0, sizeof(expected)); cl_git_pass(git_diff_blobs( bin, NULL, nonbin, NULL, &opts, diff_file_cb, diff_hunk_cb, diff_line_cb, &expected)); assert_one_modified_with_lines(&expected, 4); /* cleanup */ git_blob_free(bin); git_blob_free(nonbin); } void test_diff_blob__using_path_and_attributes(void) { git_config *cfg; git_blob *bin, *nonbin; git_oid oid; const char *nonbin_content = "Hello from the root\n"; const char *bin_content = "0123456789\n\x01\x02\x03\x04\x05\x06\x07\x08\x09\x00\n0123456789\n"; size_t bin_len = 33; const char *changed; git_diff_patch *p; char *pout; /* set up custom diff drivers and 'diff' attribute mappings for them */ cl_git_pass(git_repository_config(&cfg, g_repo)); cl_git_pass(git_config_set_bool(cfg, "diff.iam_binary.binary", 1)); cl_git_pass(git_config_set_bool(cfg, "diff.iam_text.binary", 0)); cl_git_pass(git_config_set_string( cfg, "diff.iam_alphactx.xfuncname", "^[A-Za-z]")); cl_git_pass(git_config_set_bool(cfg, "diff.iam_textalpha.binary", 0)); cl_git_pass(git_config_set_string( cfg, "diff.iam_textalpha.xfuncname", "^[A-Za-z]")); cl_git_pass(git_config_set_string( cfg, "diff.iam_numctx.funcname", "^[0-9]")); cl_git_pass(git_config_set_bool(cfg, "diff.iam_textnum.binary", 0)); cl_git_pass(git_config_set_string( cfg, "diff.iam_textnum.funcname", "^[0-9]")); git_config_free(cfg); cl_git_append2file( "attr/.gitattributes", "\n\n# test_diff_blob__using_path_and_attributes extra\n\n" "*.binary diff=iam_binary\n" "*.textary diff=iam_text\n" "*.alphary diff=iam_alphactx\n" "*.textalphary diff=iam_textalpha\n" "*.textnumary diff=iam_textnum\n" "*.numary diff=iam_numctx\n\n"); opts.context_lines = 0; opts.flags |= GIT_DIFF_INCLUDE_UNMODIFIED; cl_git_pass(git_oid_fromstrn(&oid, "45141a79", 8)); cl_git_pass(git_blob_lookup_prefix(&nonbin, g_repo, &oid, 4)); /* 20b: "Hello from the root\n" */ cl_git_pass(git_oid_fromstrn(&oid, "b435cd56", 8)); cl_git_pass(git_blob_lookup_prefix(&bin, g_repo, &oid, 4)); /* 33b: "0123456789\n\x01\x02\x03\x04\x05\x06\x07\x08\x09\n0123456789\n" */ /* non-binary to reference content */ quick_diff_blob_to_str(nonbin, NULL, nonbin_content, 0, NULL); assert_identical_blobs_comparison(&expected); cl_assert_equal_i(0, expected.files_binary); /* binary to reference content */ quick_diff_blob_to_str(bin, NULL, bin_content, bin_len, NULL); assert_identical_blobs_comparison(&expected); cl_assert_equal_i(1, expected.files_binary); /* add some text */ changed = "Hello from the root\nMore lines\nAnd more\nGo here\n"; quick_diff_blob_to_str(nonbin, NULL, changed, 0, NULL); cl_assert_equal_i(1, expected.files); cl_assert_equal_i(1, expected.file_status[GIT_DELTA_MODIFIED]); cl_assert_equal_i(0, expected.files_binary); cl_assert_equal_i(1, expected.hunks); cl_assert_equal_i(3, expected.lines); cl_assert_equal_i(0, expected.line_ctxt); cl_assert_equal_i(3, expected.line_adds); cl_assert_equal_i(0, expected.line_dels); quick_diff_blob_to_str(nonbin, "foo/bar.binary", changed, 0, NULL); cl_assert_equal_i(1, expected.files); cl_assert_equal_i(1, expected.file_status[GIT_DELTA_MODIFIED]); cl_assert_equal_i(1, expected.files_binary); cl_assert_equal_i(0, expected.hunks); cl_assert_equal_i(0, expected.lines); cl_assert_equal_i(0, expected.line_ctxt); cl_assert_equal_i(0, expected.line_adds); cl_assert_equal_i(0, expected.line_dels); quick_diff_blob_to_str(nonbin, "foo/bar.textary", changed, 0, NULL); cl_assert_equal_i(1, expected.files); cl_assert_equal_i(1, expected.file_status[GIT_DELTA_MODIFIED]); cl_assert_equal_i(0, expected.files_binary); cl_assert_equal_i(1, expected.hunks); cl_assert_equal_i(3, expected.lines); cl_assert_equal_i(0, expected.line_ctxt); cl_assert_equal_i(3, expected.line_adds); cl_assert_equal_i(0, expected.line_dels); quick_diff_blob_to_str(nonbin, "foo/bar.alphary", changed, 0, NULL); cl_assert_equal_i(1, expected.files); cl_assert_equal_i(1, expected.file_status[GIT_DELTA_MODIFIED]); cl_assert_equal_i(0, expected.files_binary); cl_assert_equal_i(1, expected.hunks); cl_assert_equal_i(3, expected.lines); cl_assert_equal_i(0, expected.line_ctxt); cl_assert_equal_i(3, expected.line_adds); cl_assert_equal_i(0, expected.line_dels); cl_git_pass(git_diff_patch_from_blob_and_buffer( &p, nonbin, "zzz.normal", changed, strlen(changed), NULL, &opts)); cl_git_pass(git_diff_patch_to_str(&pout, p)); cl_assert_equal_s( "diff --git a/zzz.normal b/zzz.normal\n" "index 45141a7..75b0dbb 100644\n" "--- a/zzz.normal\n" "+++ b/zzz.normal\n" "@@ -1,0 +2,3 @@ Hello from the root\n" "+More lines\n" "+And more\n" "+Go here\n", pout); git__free(pout); git_diff_patch_free(p); cl_git_pass(git_diff_patch_from_blob_and_buffer( &p, nonbin, "zzz.binary", changed, strlen(changed), NULL, &opts)); cl_git_pass(git_diff_patch_to_str(&pout, p)); cl_assert_equal_s( "diff --git a/zzz.binary b/zzz.binary\n" "index 45141a7..75b0dbb 100644\n" "Binary files a/zzz.binary and b/zzz.binary differ\n", pout); git__free(pout); git_diff_patch_free(p); cl_git_pass(git_diff_patch_from_blob_and_buffer( &p, nonbin, "zzz.alphary", changed, strlen(changed), NULL, &opts)); cl_git_pass(git_diff_patch_to_str(&pout, p)); cl_assert_equal_s( "diff --git a/zzz.alphary b/zzz.alphary\n" "index 45141a7..75b0dbb 100644\n" "--- a/zzz.alphary\n" "+++ b/zzz.alphary\n" "@@ -1,0 +2,3 @@ Hello from the root\n" "+More lines\n" "+And more\n" "+Go here\n", pout); git__free(pout); git_diff_patch_free(p); cl_git_pass(git_diff_patch_from_blob_and_buffer( &p, nonbin, "zzz.numary", changed, strlen(changed), NULL, &opts)); cl_git_pass(git_diff_patch_to_str(&pout, p)); cl_assert_equal_s( "diff --git a/zzz.numary b/zzz.numary\n" "index 45141a7..75b0dbb 100644\n" "--- a/zzz.numary\n" "+++ b/zzz.numary\n" "@@ -1,0 +2,3 @@\n" "+More lines\n" "+And more\n" "+Go here\n", pout); git__free(pout); git_diff_patch_free(p); /* "0123456789\n\x01\x02\x03\x04\x05\x06\x07\x08\x09\x00\n0123456789\n" * 33 bytes */ changed = "0123456789\n\x01\x02\x03\x04\x05\x06\x07\x08\x09\x00\nreplace a line\n"; cl_git_pass(git_diff_patch_from_blob_and_buffer( &p, bin, "zzz.normal", changed, 37, NULL, &opts)); cl_git_pass(git_diff_patch_to_str(&pout, p)); cl_assert_equal_s( "diff --git a/zzz.normal b/zzz.normal\n" "index b435cd5..1604519 100644\n" "Binary files a/zzz.normal and b/zzz.normal differ\n", pout); git__free(pout); git_diff_patch_free(p); cl_git_pass(git_diff_patch_from_blob_and_buffer( &p, bin, "zzz.textary", changed, 37, NULL, &opts)); cl_git_pass(git_diff_patch_to_str(&pout, p)); cl_assert_equal_s( "diff --git a/zzz.textary b/zzz.textary\n" "index b435cd5..1604519 100644\n" "--- a/zzz.textary\n" "+++ b/zzz.textary\n" "@@ -3 +3 @@\n" "-0123456789\n" "+replace a line\n", pout); git__free(pout); git_diff_patch_free(p); cl_git_pass(git_diff_patch_from_blob_and_buffer( &p, bin, "zzz.textalphary", changed, 37, NULL, &opts)); cl_git_pass(git_diff_patch_to_str(&pout, p)); cl_assert_equal_s( "diff --git a/zzz.textalphary b/zzz.textalphary\n" "index b435cd5..1604519 100644\n" "--- a/zzz.textalphary\n" "+++ b/zzz.textalphary\n" "@@ -3 +3 @@\n" "-0123456789\n" "+replace a line\n", pout); git__free(pout); git_diff_patch_free(p); cl_git_pass(git_diff_patch_from_blob_and_buffer( &p, bin, "zzz.textnumary", changed, 37, NULL, &opts)); cl_git_pass(git_diff_patch_to_str(&pout, p)); cl_assert_equal_s( "diff --git a/zzz.textnumary b/zzz.textnumary\n" "index b435cd5..1604519 100644\n" "--- a/zzz.textnumary\n" "+++ b/zzz.textnumary\n" "@@ -3 +3 @@ 0123456789\n" "-0123456789\n" "+replace a line\n", pout); git__free(pout); git_diff_patch_free(p); git_blob_free(nonbin); git_blob_free(bin); } libgit2-0.19.0/tests-clar/diff/diff_helpers.c000066400000000000000000000112521216214232500207230ustar00rootroot00000000000000#include "clar_libgit2.h" #include "diff_helpers.h" git_tree *resolve_commit_oid_to_tree( git_repository *repo, const char *partial_oid) { size_t len = strlen(partial_oid); git_oid oid; git_object *obj = NULL; git_tree *tree = NULL; if (git_oid_fromstrn(&oid, partial_oid, len) == 0) git_object_lookup_prefix(&obj, repo, &oid, len, GIT_OBJ_ANY); cl_assert(obj); if (git_object_type(obj) == GIT_OBJ_TREE) return (git_tree *)obj; cl_assert(git_object_type(obj) == GIT_OBJ_COMMIT); cl_git_pass(git_commit_tree(&tree, (git_commit *)obj)); git_object_free(obj); return tree; } int diff_file_cb( const git_diff_delta *delta, float progress, void *payload) { diff_expects *e = payload; if (e->debug) fprintf(stderr, "%c %s (%.3f)\n", git_diff_status_char(delta->status), delta->old_file.path, progress); if (e->names) cl_assert_equal_s(e->names[e->files], delta->old_file.path); if (e->statuses) cl_assert_equal_i(e->statuses[e->files], (int)delta->status); e->files++; if ((delta->flags & GIT_DIFF_FLAG_BINARY) != 0) e->files_binary++; cl_assert(delta->status <= GIT_DELTA_TYPECHANGE); e->file_status[delta->status] += 1; return 0; } int diff_print_file_cb( const git_diff_delta *delta, float progress, void *payload) { fprintf(stderr, "%c %s\n", git_diff_status_char(delta->status), delta->old_file.path); return diff_file_cb(delta, progress, payload); } int diff_hunk_cb( const git_diff_delta *delta, const git_diff_range *range, const char *header, size_t header_len, void *payload) { diff_expects *e = payload; GIT_UNUSED(delta); GIT_UNUSED(header); GIT_UNUSED(header_len); e->hunks++; e->hunk_old_lines += range->old_lines; e->hunk_new_lines += range->new_lines; return 0; } int diff_line_cb( const git_diff_delta *delta, const git_diff_range *range, char line_origin, const char *content, size_t content_len, void *payload) { diff_expects *e = payload; GIT_UNUSED(delta); GIT_UNUSED(range); GIT_UNUSED(content); GIT_UNUSED(content_len); e->lines++; switch (line_origin) { case GIT_DIFF_LINE_CONTEXT: case GIT_DIFF_LINE_CONTEXT_EOFNL: /* techically not a line */ e->line_ctxt++; break; case GIT_DIFF_LINE_ADDITION: case GIT_DIFF_LINE_ADD_EOFNL: /* technically not a line add */ e->line_adds++; break; case GIT_DIFF_LINE_DELETION: case GIT_DIFF_LINE_DEL_EOFNL: /* technically not a line delete */ e->line_dels++; break; default: break; } return 0; } int diff_foreach_via_iterator( git_diff_list *diff, git_diff_file_cb file_cb, git_diff_hunk_cb hunk_cb, git_diff_data_cb line_cb, void *data) { size_t d, num_d = git_diff_num_deltas(diff); for (d = 0; d < num_d; ++d) { git_diff_patch *patch; const git_diff_delta *delta; size_t h, num_h; cl_git_pass(git_diff_get_patch(&patch, &delta, diff, d)); cl_assert(delta); /* call file_cb for this file */ if (file_cb != NULL && file_cb(delta, (float)d / num_d, data) != 0) { git_diff_patch_free(patch); goto abort; } /* if there are no changes, then the patch will be NULL */ if (!patch) { cl_assert(delta->status == GIT_DELTA_UNMODIFIED || (delta->flags & GIT_DIFF_FLAG_BINARY) != 0); continue; } if (!hunk_cb && !line_cb) { git_diff_patch_free(patch); continue; } num_h = git_diff_patch_num_hunks(patch); for (h = 0; h < num_h; h++) { const git_diff_range *range; const char *hdr; size_t hdr_len, l, num_l; cl_git_pass(git_diff_patch_get_hunk( &range, &hdr, &hdr_len, &num_l, patch, h)); if (hunk_cb && hunk_cb(delta, range, hdr, hdr_len, data) != 0) { git_diff_patch_free(patch); goto abort; } for (l = 0; l < num_l; ++l) { char origin; const char *line; size_t line_len; int old_lineno, new_lineno; cl_git_pass(git_diff_patch_get_line_in_hunk( &origin, &line, &line_len, &old_lineno, &new_lineno, patch, h, l)); if (line_cb && line_cb(delta, range, origin, line, line_len, data) != 0) { git_diff_patch_free(patch); goto abort; } } } git_diff_patch_free(patch); } return 0; abort: giterr_clear(); return GIT_EUSER; } static int diff_print_cb( const git_diff_delta *delta, const git_diff_range *range, char line_origin, /**< GIT_DIFF_LINE_... value from above */ const char *content, size_t content_len, void *payload) { GIT_UNUSED(payload); GIT_UNUSED(delta); GIT_UNUSED(range); GIT_UNUSED(line_origin); GIT_UNUSED(content_len); fputs(content, (FILE *)payload); return 0; } void diff_print(FILE *fp, git_diff_list *diff) { cl_git_pass(git_diff_print_patch(diff, diff_print_cb, fp ? fp : stderr)); } void diff_print_raw(FILE *fp, git_diff_list *diff) { cl_git_pass(git_diff_print_raw(diff, diff_print_cb, fp ? fp : stderr)); } libgit2-0.19.0/tests-clar/diff/diff_helpers.h000066400000000000000000000024661216214232500207370ustar00rootroot00000000000000#include "fileops.h" #include "git2/diff.h" extern git_tree *resolve_commit_oid_to_tree( git_repository *repo, const char *partial_oid); typedef struct { int files; int files_binary; int file_status[10]; /* indexed by git_delta_t value */ int hunks; int hunk_new_lines; int hunk_old_lines; int lines; int line_ctxt; int line_adds; int line_dels; /* optional arrays of expected specific values */ const char **names; int *statuses; int debug; } diff_expects; typedef struct { const char *path; const char *matched_pathspec; } notify_expected; extern int diff_file_cb( const git_diff_delta *delta, float progress, void *cb_data); extern int diff_print_file_cb( const git_diff_delta *delta, float progress, void *cb_data); extern int diff_hunk_cb( const git_diff_delta *delta, const git_diff_range *range, const char *header, size_t header_len, void *cb_data); extern int diff_line_cb( const git_diff_delta *delta, const git_diff_range *range, char line_origin, const char *content, size_t content_len, void *cb_data); extern int diff_foreach_via_iterator( git_diff_list *diff, git_diff_file_cb file_cb, git_diff_hunk_cb hunk_cb, git_diff_data_cb line_cb, void *data); extern void diff_print(FILE *fp, git_diff_list *diff); extern void diff_print_raw(FILE *fp, git_diff_list *diff); libgit2-0.19.0/tests-clar/diff/diffiter.c000066400000000000000000000272411216214232500200720ustar00rootroot00000000000000#include "clar_libgit2.h" #include "diff_helpers.h" void test_diff_diffiter__initialize(void) { } void test_diff_diffiter__cleanup(void) { cl_git_sandbox_cleanup(); } void test_diff_diffiter__create(void) { git_repository *repo = cl_git_sandbox_init("attr"); git_diff_list *diff; size_t d, num_d; cl_git_pass(git_diff_index_to_workdir(&diff, repo, NULL, NULL)); num_d = git_diff_num_deltas(diff); for (d = 0; d < num_d; ++d) { const git_diff_delta *delta; cl_git_pass(git_diff_get_patch(NULL, &delta, diff, d)); } git_diff_list_free(diff); } void test_diff_diffiter__iterate_files(void) { git_repository *repo = cl_git_sandbox_init("attr"); git_diff_list *diff; size_t d, num_d; int count = 0; cl_git_pass(git_diff_index_to_workdir(&diff, repo, NULL, NULL)); num_d = git_diff_num_deltas(diff); cl_assert_equal_i(6, (int)num_d); for (d = 0; d < num_d; ++d) { const git_diff_delta *delta; cl_git_pass(git_diff_get_patch(NULL, &delta, diff, d)); cl_assert(delta != NULL); count++; } cl_assert_equal_i(6, count); git_diff_list_free(diff); } void test_diff_diffiter__iterate_files_2(void) { git_repository *repo = cl_git_sandbox_init("status"); git_diff_list *diff; size_t d, num_d; int count = 0; cl_git_pass(git_diff_index_to_workdir(&diff, repo, NULL, NULL)); num_d = git_diff_num_deltas(diff); cl_assert_equal_i(8, (int)num_d); for (d = 0; d < num_d; ++d) { const git_diff_delta *delta; cl_git_pass(git_diff_get_patch(NULL, &delta, diff, d)); cl_assert(delta != NULL); count++; } cl_assert_equal_i(8, count); git_diff_list_free(diff); } void test_diff_diffiter__iterate_files_and_hunks(void) { git_repository *repo = cl_git_sandbox_init("status"); git_diff_options opts = GIT_DIFF_OPTIONS_INIT; git_diff_list *diff = NULL; size_t d, num_d; int file_count = 0, hunk_count = 0; opts.context_lines = 3; opts.interhunk_lines = 1; opts.flags |= GIT_DIFF_INCLUDE_IGNORED | GIT_DIFF_INCLUDE_UNTRACKED; cl_git_pass(git_diff_index_to_workdir(&diff, repo, NULL, &opts)); num_d = git_diff_num_deltas(diff); for (d = 0; d < num_d; ++d) { git_diff_patch *patch; const git_diff_delta *delta; size_t h, num_h; cl_git_pass(git_diff_get_patch(&patch, &delta, diff, d)); cl_assert(delta); cl_assert(patch); file_count++; num_h = git_diff_patch_num_hunks(patch); for (h = 0; h < num_h; h++) { const git_diff_range *range; const char *header; size_t header_len, num_l; cl_git_pass(git_diff_patch_get_hunk( &range, &header, &header_len, &num_l, patch, h)); cl_assert(range); cl_assert(header); hunk_count++; } git_diff_patch_free(patch); } cl_assert_equal_i(13, file_count); cl_assert_equal_i(8, hunk_count); git_diff_list_free(diff); } void test_diff_diffiter__max_size_threshold(void) { git_repository *repo = cl_git_sandbox_init("status"); git_diff_options opts = GIT_DIFF_OPTIONS_INIT; git_diff_list *diff = NULL; int file_count = 0, binary_count = 0, hunk_count = 0; size_t d, num_d; opts.context_lines = 3; opts.interhunk_lines = 1; opts.flags |= GIT_DIFF_INCLUDE_IGNORED | GIT_DIFF_INCLUDE_UNTRACKED; cl_git_pass(git_diff_index_to_workdir(&diff, repo, NULL, &opts)); num_d = git_diff_num_deltas(diff); for (d = 0; d < num_d; ++d) { git_diff_patch *patch; const git_diff_delta *delta; cl_git_pass(git_diff_get_patch(&patch, &delta, diff, d)); cl_assert(delta); cl_assert(patch); file_count++; hunk_count += (int)git_diff_patch_num_hunks(patch); assert((delta->flags & (GIT_DIFF_FLAG_BINARY|GIT_DIFF_FLAG_NOT_BINARY)) != 0); binary_count += ((delta->flags & GIT_DIFF_FLAG_BINARY) != 0); git_diff_patch_free(patch); } cl_assert_equal_i(13, file_count); cl_assert_equal_i(0, binary_count); cl_assert_equal_i(8, hunk_count); git_diff_list_free(diff); /* try again with low file size threshold */ file_count = binary_count = hunk_count = 0; opts.context_lines = 3; opts.interhunk_lines = 1; opts.flags |= GIT_DIFF_INCLUDE_IGNORED | GIT_DIFF_INCLUDE_UNTRACKED; opts.max_size = 50; /* treat anything over 50 bytes as binary! */ cl_git_pass(git_diff_index_to_workdir(&diff, repo, NULL, &opts)); num_d = git_diff_num_deltas(diff); for (d = 0; d < num_d; ++d) { git_diff_patch *patch; const git_diff_delta *delta; cl_git_pass(git_diff_get_patch(&patch, &delta, diff, d)); file_count++; hunk_count += (int)git_diff_patch_num_hunks(patch); assert((delta->flags & (GIT_DIFF_FLAG_BINARY|GIT_DIFF_FLAG_NOT_BINARY)) != 0); binary_count += ((delta->flags & GIT_DIFF_FLAG_BINARY) != 0); git_diff_patch_free(patch); } cl_assert_equal_i(13, file_count); /* Three files are over the 50 byte threshold: * - staged_changes_file_deleted * - staged_changes_modified_file * - staged_new_file_modified_file */ cl_assert_equal_i(3, binary_count); cl_assert_equal_i(5, hunk_count); git_diff_list_free(diff); } void test_diff_diffiter__iterate_all(void) { git_repository *repo = cl_git_sandbox_init("status"); git_diff_options opts = GIT_DIFF_OPTIONS_INIT; git_diff_list *diff = NULL; diff_expects exp = {0}; size_t d, num_d; opts.context_lines = 3; opts.interhunk_lines = 1; opts.flags |= GIT_DIFF_INCLUDE_IGNORED | GIT_DIFF_INCLUDE_UNTRACKED; cl_git_pass(git_diff_index_to_workdir(&diff, repo, NULL, &opts)); num_d = git_diff_num_deltas(diff); for (d = 0; d < num_d; ++d) { git_diff_patch *patch; const git_diff_delta *delta; size_t h, num_h; cl_git_pass(git_diff_get_patch(&patch, &delta, diff, d)); cl_assert(patch && delta); exp.files++; num_h = git_diff_patch_num_hunks(patch); for (h = 0; h < num_h; h++) { const git_diff_range *range; const char *header; size_t header_len, l, num_l; cl_git_pass(git_diff_patch_get_hunk( &range, &header, &header_len, &num_l, patch, h)); cl_assert(range && header); exp.hunks++; for (l = 0; l < num_l; ++l) { char origin; const char *content; size_t content_len; cl_git_pass(git_diff_patch_get_line_in_hunk( &origin, &content, &content_len, NULL, NULL, patch, h, l)); cl_assert(content); exp.lines++; } } git_diff_patch_free(patch); } cl_assert_equal_i(13, exp.files); cl_assert_equal_i(8, exp.hunks); cl_assert_equal_i(14, exp.lines); git_diff_list_free(diff); } static void iterate_over_patch(git_diff_patch *patch, diff_expects *exp) { size_t h, num_h = git_diff_patch_num_hunks(patch), num_l; exp->files++; exp->hunks += (int)num_h; /* let's iterate in reverse, just because we can! */ for (h = 1, num_l = 0; h <= num_h; ++h) num_l += git_diff_patch_num_lines_in_hunk(patch, num_h - h); exp->lines += (int)num_l; } #define PATCH_CACHE 5 void test_diff_diffiter__iterate_randomly_while_saving_state(void) { git_repository *repo = cl_git_sandbox_init("status"); git_diff_options opts = GIT_DIFF_OPTIONS_INIT; git_diff_list *diff = NULL; diff_expects exp = {0}; git_diff_patch *patches[PATCH_CACHE]; size_t p, d, num_d; memset(patches, 0, sizeof(patches)); opts.context_lines = 3; opts.interhunk_lines = 1; opts.flags |= GIT_DIFF_INCLUDE_IGNORED | GIT_DIFF_INCLUDE_UNTRACKED; cl_git_pass(git_diff_index_to_workdir(&diff, repo, NULL, &opts)); num_d = git_diff_num_deltas(diff); /* To make sure that references counts work for diff and patch objects, * this generates patches and randomly caches them. Only when the patch * is removed from the cache are hunks and lines counted. At the end, * there are still patches in the cache, so free the diff and try to * process remaining patches after the diff is freed. */ srand(121212); p = rand() % PATCH_CACHE; for (d = 0; d < num_d; ++d) { /* take old patch */ git_diff_patch *patch = patches[p]; patches[p] = NULL; /* cache new patch */ cl_git_pass(git_diff_get_patch(&patches[p], NULL, diff, d)); cl_assert(patches[p] != NULL); /* process old patch if non-NULL */ if (patch != NULL) { iterate_over_patch(patch, &exp); git_diff_patch_free(patch); } p = rand() % PATCH_CACHE; } /* free diff list now - refcounts should keep things safe */ git_diff_list_free(diff); /* process remaining unprocessed patches */ for (p = 0; p < PATCH_CACHE; p++) { git_diff_patch *patch = patches[p]; if (patch != NULL) { iterate_over_patch(patch, &exp); git_diff_patch_free(patch); } } /* hopefully it all still added up right */ cl_assert_equal_i(13, exp.files); cl_assert_equal_i(8, exp.hunks); cl_assert_equal_i(14, exp.lines); } /* This output is taken directly from `git diff` on the status test data */ static const char *expected_patch_text[8] = { /* 0 */ "diff --git a/file_deleted b/file_deleted\n" "deleted file mode 100644\n" "index 5452d32..0000000\n" "--- a/file_deleted\n" "+++ /dev/null\n" "@@ -1 +0,0 @@\n" "-file_deleted\n", /* 1 */ "diff --git a/modified_file b/modified_file\n" "index 452e424..0a53963 100644\n" "--- a/modified_file\n" "+++ b/modified_file\n" "@@ -1 +1,2 @@\n" " modified_file\n" "+modified_file\n", /* 2 */ "diff --git a/staged_changes_file_deleted b/staged_changes_file_deleted\n" "deleted file mode 100644\n" "index a6be623..0000000\n" "--- a/staged_changes_file_deleted\n" "+++ /dev/null\n" "@@ -1,2 +0,0 @@\n" "-staged_changes_file_deleted\n" "-staged_changes_file_deleted\n", /* 3 */ "diff --git a/staged_changes_modified_file b/staged_changes_modified_file\n" "index 906ee77..011c344 100644\n" "--- a/staged_changes_modified_file\n" "+++ b/staged_changes_modified_file\n" "@@ -1,2 +1,3 @@\n" " staged_changes_modified_file\n" " staged_changes_modified_file\n" "+staged_changes_modified_file\n", /* 4 */ "diff --git a/staged_new_file_deleted_file b/staged_new_file_deleted_file\n" "deleted file mode 100644\n" "index 90b8c29..0000000\n" "--- a/staged_new_file_deleted_file\n" "+++ /dev/null\n" "@@ -1 +0,0 @@\n" "-staged_new_file_deleted_file\n", /* 5 */ "diff --git a/staged_new_file_modified_file b/staged_new_file_modified_file\n" "index ed06290..8b090c0 100644\n" "--- a/staged_new_file_modified_file\n" "+++ b/staged_new_file_modified_file\n" "@@ -1 +1,2 @@\n" " staged_new_file_modified_file\n" "+staged_new_file_modified_file\n", /* 6 */ "diff --git a/subdir/deleted_file b/subdir/deleted_file\n" "deleted file mode 100644\n" "index 1888c80..0000000\n" "--- a/subdir/deleted_file\n" "+++ /dev/null\n" "@@ -1 +0,0 @@\n" "-subdir/deleted_file\n", /* 7 */ "diff --git a/subdir/modified_file b/subdir/modified_file\n" "index a619198..57274b7 100644\n" "--- a/subdir/modified_file\n" "+++ b/subdir/modified_file\n" "@@ -1 +1,2 @@\n" " subdir/modified_file\n" "+subdir/modified_file\n" }; void test_diff_diffiter__iterate_and_generate_patch_text(void) { git_repository *repo = cl_git_sandbox_init("status"); git_diff_list *diff; size_t d, num_d; cl_git_pass(git_diff_index_to_workdir(&diff, repo, NULL, NULL)); num_d = git_diff_num_deltas(diff); cl_assert_equal_i(8, (int)num_d); for (d = 0; d < num_d; ++d) { git_diff_patch *patch; char *text; cl_git_pass(git_diff_get_patch(&patch, NULL, diff, d)); cl_assert(patch != NULL); cl_git_pass(git_diff_patch_to_str(&text, patch)); cl_assert_equal_s(expected_patch_text[d], text); git__free(text); git_diff_patch_free(patch); } git_diff_list_free(diff); } void test_diff_diffiter__checks_options_version(void) { git_repository *repo = cl_git_sandbox_init("status"); git_diff_options opts = GIT_DIFF_OPTIONS_INIT; git_diff_list *diff = NULL; const git_error *err; opts.version = 0; opts.flags |= GIT_DIFF_INCLUDE_IGNORED | GIT_DIFF_INCLUDE_UNTRACKED; cl_git_fail(git_diff_index_to_workdir(&diff, repo, NULL, &opts)); err = giterr_last(); cl_assert_equal_i(GITERR_INVALID, err->klass); giterr_clear(); opts.version = 1024; cl_git_fail(git_diff_index_to_workdir(&diff, repo, NULL, &opts)); err = giterr_last(); cl_assert_equal_i(GITERR_INVALID, err->klass); } libgit2-0.19.0/tests-clar/diff/drivers.c000066400000000000000000000100741216214232500177500ustar00rootroot00000000000000#include "clar_libgit2.h" #include "diff_helpers.h" #include "repository.h" #include "diff_driver.h" static git_repository *g_repo = NULL; void test_diff_drivers__initialize(void) { } void test_diff_drivers__cleanup(void) { cl_git_sandbox_cleanup(); g_repo = NULL; } void test_diff_drivers__patterns(void) { git_config *cfg; const char *one_sha = "19dd32dfb1520a64e5bbaae8dce6ef423dfa2f13"; git_tree *one; git_diff_list *diff; git_diff_patch *patch; char *text; const char *expected0 = "diff --git a/untimely.txt b/untimely.txt\nindex 9a69d96..57fd0cf 100644\n--- a/untimely.txt\n+++ b/untimely.txt\n@@ -22,3 +22,5 @@ Comes through the blood of the vanguards who\n dreamed--too soon--it had sounded.\r\n \r\n -- Rudyard Kipling\r\n+\r\n+Some new stuff\r\n"; const char *expected1 = "diff --git a/untimely.txt b/untimely.txt\nindex 9a69d96..57fd0cf 100644\nBinary files a/untimely.txt and b/untimely.txt differ\n"; const char *expected2 = "diff --git a/untimely.txt b/untimely.txt\nindex 9a69d96..57fd0cf 100644\n--- a/untimely.txt\n+++ b/untimely.txt\n@@ -22,3 +22,5 @@ Heaven delivers on earth the Hour that cannot be\n dreamed--too soon--it had sounded.\r\n \r\n -- Rudyard Kipling\r\n+\r\n+Some new stuff\r\n"; g_repo = cl_git_sandbox_init("renames"); one = resolve_commit_oid_to_tree(g_repo, one_sha); /* no diff */ cl_git_pass(git_diff_tree_to_workdir(&diff, g_repo, one, NULL)); cl_assert_equal_i(0, (int)git_diff_num_deltas(diff)); git_diff_list_free(diff); /* default diff */ cl_git_append2file("renames/untimely.txt", "\r\nSome new stuff\r\n"); cl_git_pass(git_diff_tree_to_workdir(&diff, g_repo, one, NULL)); cl_assert_equal_i(1, (int)git_diff_num_deltas(diff)); cl_git_pass(git_diff_get_patch(&patch, NULL, diff, 0)); cl_git_pass(git_diff_patch_to_str(&text, patch)); cl_assert_equal_s(expected0, text); git__free(text); git_diff_patch_free(patch); git_diff_list_free(diff); /* attribute diff set to false */ cl_git_rewritefile("renames/.gitattributes", "untimely.txt -diff\n"); cl_git_pass(git_diff_tree_to_workdir(&diff, g_repo, one, NULL)); cl_assert_equal_i(1, (int)git_diff_num_deltas(diff)); cl_git_pass(git_diff_get_patch(&patch, NULL, diff, 0)); cl_git_pass(git_diff_patch_to_str(&text, patch)); cl_assert_equal_s(expected1, text); git__free(text); git_diff_patch_free(patch); git_diff_list_free(diff); /* attribute diff set to unconfigured value (should use default) */ cl_git_rewritefile("renames/.gitattributes", "untimely.txt diff=kipling0\n"); cl_git_pass(git_diff_tree_to_workdir(&diff, g_repo, one, NULL)); cl_assert_equal_i(1, (int)git_diff_num_deltas(diff)); cl_git_pass(git_diff_get_patch(&patch, NULL, diff, 0)); cl_git_pass(git_diff_patch_to_str(&text, patch)); cl_assert_equal_s(expected0, text); git__free(text); git_diff_patch_free(patch); git_diff_list_free(diff); /* let's define that driver */ cl_git_pass(git_repository_config(&cfg, g_repo)); cl_git_pass(git_config_set_bool(cfg, "diff.kipling0.binary", 1)); git_config_free(cfg); cl_git_pass(git_diff_tree_to_workdir(&diff, g_repo, one, NULL)); cl_assert_equal_i(1, (int)git_diff_num_deltas(diff)); cl_git_pass(git_diff_get_patch(&patch, NULL, diff, 0)); cl_git_pass(git_diff_patch_to_str(&text, patch)); cl_assert_equal_s(expected1, text); git__free(text); git_diff_patch_free(patch); git_diff_list_free(diff); /* let's use a real driver with some regular expressions */ git_diff_driver_registry_free(g_repo->diff_drivers); g_repo->diff_drivers = NULL; cl_git_pass(git_repository_config(&cfg, g_repo)); cl_git_pass(git_config_set_bool(cfg, "diff.kipling0.binary", 0)); cl_git_pass(git_config_set_string(cfg, "diff.kipling0.xfuncname", "^H")); git_config_free(cfg); cl_git_pass(git_diff_tree_to_workdir(&diff, g_repo, one, NULL)); cl_assert_equal_i(1, (int)git_diff_num_deltas(diff)); cl_git_pass(git_diff_get_patch(&patch, NULL, diff, 0)); cl_git_pass(git_diff_patch_to_str(&text, patch)); cl_assert_equal_s(expected2, text); git__free(text); git_diff_patch_free(patch); git_diff_list_free(diff); git_tree_free(one); } libgit2-0.19.0/tests-clar/diff/index.c000066400000000000000000000102141216214232500173750ustar00rootroot00000000000000#include "clar_libgit2.h" #include "diff_helpers.h" static git_repository *g_repo = NULL; void test_diff_index__initialize(void) { g_repo = cl_git_sandbox_init("status"); } void test_diff_index__cleanup(void) { cl_git_sandbox_cleanup(); } void test_diff_index__0(void) { /* grabbed a couple of commit oids from the history of the attr repo */ const char *a_commit = "26a125ee1bf"; /* the current HEAD */ const char *b_commit = "0017bd4ab1ec3"; /* the start */ git_tree *a = resolve_commit_oid_to_tree(g_repo, a_commit); git_tree *b = resolve_commit_oid_to_tree(g_repo, b_commit); git_diff_options opts = GIT_DIFF_OPTIONS_INIT; git_diff_list *diff = NULL; diff_expects exp; cl_assert(a); cl_assert(b); opts.context_lines = 1; opts.interhunk_lines = 1; memset(&exp, 0, sizeof(exp)); cl_git_pass(git_diff_tree_to_index(&diff, g_repo, a, NULL, &opts)); cl_git_pass(git_diff_foreach( diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp)); /* to generate these values: * - cd to tests/resources/status, * - mv .gitted .git * - git diff --name-status --cached 26a125ee1bf * - git diff -U1 --cached 26a125ee1bf * - mv .git .gitted */ cl_assert_equal_i(8, exp.files); cl_assert_equal_i(3, exp.file_status[GIT_DELTA_ADDED]); cl_assert_equal_i(2, exp.file_status[GIT_DELTA_DELETED]); cl_assert_equal_i(3, exp.file_status[GIT_DELTA_MODIFIED]); cl_assert_equal_i(8, exp.hunks); cl_assert_equal_i(11, exp.lines); cl_assert_equal_i(3, exp.line_ctxt); cl_assert_equal_i(6, exp.line_adds); cl_assert_equal_i(2, exp.line_dels); git_diff_list_free(diff); diff = NULL; memset(&exp, 0, sizeof(exp)); cl_git_pass(git_diff_tree_to_index(&diff, g_repo, b, NULL, &opts)); cl_git_pass(git_diff_foreach( diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp)); /* to generate these values: * - cd to tests/resources/status, * - mv .gitted .git * - git diff --name-status --cached 0017bd4ab1ec3 * - git diff -U1 --cached 0017bd4ab1ec3 * - mv .git .gitted */ cl_assert_equal_i(12, exp.files); cl_assert_equal_i(7, exp.file_status[GIT_DELTA_ADDED]); cl_assert_equal_i(2, exp.file_status[GIT_DELTA_DELETED]); cl_assert_equal_i(3, exp.file_status[GIT_DELTA_MODIFIED]); cl_assert_equal_i(12, exp.hunks); cl_assert_equal_i(16, exp.lines); cl_assert_equal_i(3, exp.line_ctxt); cl_assert_equal_i(11, exp.line_adds); cl_assert_equal_i(2, exp.line_dels); git_diff_list_free(diff); diff = NULL; git_tree_free(a); git_tree_free(b); } static int diff_stop_after_2_files( const git_diff_delta *delta, float progress, void *payload) { diff_expects *e = payload; GIT_UNUSED(progress); GIT_UNUSED(delta); e->files++; return (e->files == 2); } void test_diff_index__1(void) { /* grabbed a couple of commit oids from the history of the attr repo */ const char *a_commit = "26a125ee1bf"; /* the current HEAD */ const char *b_commit = "0017bd4ab1ec3"; /* the start */ git_tree *a = resolve_commit_oid_to_tree(g_repo, a_commit); git_tree *b = resolve_commit_oid_to_tree(g_repo, b_commit); git_diff_options opts = GIT_DIFF_OPTIONS_INIT; git_diff_list *diff = NULL; diff_expects exp; cl_assert(a); cl_assert(b); opts.context_lines = 1; opts.interhunk_lines = 1; memset(&exp, 0, sizeof(exp)); cl_git_pass(git_diff_tree_to_index(&diff, g_repo, a, NULL, &opts)); cl_assert_equal_i( GIT_EUSER, git_diff_foreach(diff, diff_stop_after_2_files, NULL, NULL, &exp) ); cl_assert_equal_i(2, exp.files); git_diff_list_free(diff); diff = NULL; git_tree_free(a); git_tree_free(b); } void test_diff_index__checks_options_version(void) { const char *a_commit = "26a125ee1bf"; git_tree *a = resolve_commit_oid_to_tree(g_repo, a_commit); git_diff_options opts = GIT_DIFF_OPTIONS_INIT; git_diff_list *diff = NULL; const git_error *err; opts.version = 0; cl_git_fail(git_diff_tree_to_index(&diff, g_repo, a, NULL, &opts)); err = giterr_last(); cl_assert_equal_i(GITERR_INVALID, err->klass); cl_assert_equal_p(diff, NULL); giterr_clear(); opts.version = 1024; cl_git_fail(git_diff_tree_to_index(&diff, g_repo, a, NULL, &opts)); err = giterr_last(); cl_assert_equal_i(GITERR_INVALID, err->klass); cl_assert_equal_p(diff, NULL); git_tree_free(a); } libgit2-0.19.0/tests-clar/diff/iterator.c000066400000000000000000000553341216214232500201330ustar00rootroot00000000000000#include "clar_libgit2.h" #include "diff_helpers.h" #include "iterator.h" #include "tree.h" void test_diff_iterator__initialize(void) { /* since we are doing tests with different sandboxes, defer setup * to the actual tests. cleanup will still be done in the global * cleanup function so that assertion failures don't result in a * missed cleanup. */ } void test_diff_iterator__cleanup(void) { cl_git_sandbox_cleanup(); } /* -- TREE ITERATOR TESTS -- */ static void tree_iterator_test( const char *sandbox, const char *treeish, const char *start, const char *end, int expected_count, const char **expected_values) { git_tree *t; git_iterator *i; const git_index_entry *entry; int error, count = 0, count_post_reset = 0; git_repository *repo = cl_git_sandbox_init(sandbox); cl_assert(t = resolve_commit_oid_to_tree(repo, treeish)); cl_git_pass(git_iterator_for_tree( &i, t, GIT_ITERATOR_DONT_IGNORE_CASE, start, end)); /* test loop */ while (!(error = git_iterator_advance(&entry, i))) { cl_assert(entry); if (expected_values != NULL) cl_assert_equal_s(expected_values[count], entry->path); count++; } cl_assert_equal_i(GIT_ITEROVER, error); cl_assert(!entry); cl_assert_equal_i(expected_count, count); /* test reset */ cl_git_pass(git_iterator_reset(i, NULL, NULL)); while (!(error = git_iterator_advance(&entry, i))) { cl_assert(entry); if (expected_values != NULL) cl_assert_equal_s(expected_values[count_post_reset], entry->path); count_post_reset++; } cl_assert_equal_i(GIT_ITEROVER, error); cl_assert(!entry); cl_assert_equal_i(count, count_post_reset); git_iterator_free(i); git_tree_free(t); } /* results of: git ls-tree -r --name-only 605812a */ const char *expected_tree_0[] = { ".gitattributes", "attr0", "attr1", "attr2", "attr3", "binfile", "macro_test", "root_test1", "root_test2", "root_test3", "root_test4.txt", "subdir/.gitattributes", "subdir/abc", "subdir/subdir_test1", "subdir/subdir_test2.txt", "subdir2/subdir2_test1", NULL }; void test_diff_iterator__tree_0(void) { tree_iterator_test("attr", "605812a", NULL, NULL, 16, expected_tree_0); } /* results of: git ls-tree -r --name-only 6bab5c79 */ const char *expected_tree_1[] = { ".gitattributes", "attr0", "attr1", "attr2", "attr3", "root_test1", "root_test2", "root_test3", "root_test4.txt", "subdir/.gitattributes", "subdir/subdir_test1", "subdir/subdir_test2.txt", "subdir2/subdir2_test1", NULL }; void test_diff_iterator__tree_1(void) { tree_iterator_test("attr", "6bab5c79cd5", NULL, NULL, 13, expected_tree_1); } /* results of: git ls-tree -r --name-only 26a125ee1 */ const char *expected_tree_2[] = { "current_file", "file_deleted", "modified_file", "staged_changes", "staged_changes_file_deleted", "staged_changes_modified_file", "staged_delete_file_deleted", "staged_delete_modified_file", "subdir.txt", "subdir/current_file", "subdir/deleted_file", "subdir/modified_file", NULL }; void test_diff_iterator__tree_2(void) { tree_iterator_test("status", "26a125ee1", NULL, NULL, 12, expected_tree_2); } /* $ git ls-tree -r --name-only 0017bd4ab1e */ const char *expected_tree_3[] = { "current_file", "file_deleted", "modified_file", "staged_changes", "staged_changes_file_deleted", "staged_changes_modified_file", "staged_delete_file_deleted", "staged_delete_modified_file" }; void test_diff_iterator__tree_3(void) { tree_iterator_test("status", "0017bd4ab1e", NULL, NULL, 8, expected_tree_3); } /* $ git ls-tree -r --name-only 24fa9a9fc4e202313e24b648087495441dab432b */ const char *expected_tree_4[] = { "attr0", "attr1", "attr2", "attr3", "binfile", "gitattributes", "macro_bad", "macro_test", "root_test1", "root_test2", "root_test3", "root_test4.txt", "sub/abc", "sub/file", "sub/sub/file", "sub/sub/subsub.txt", "sub/subdir_test1", "sub/subdir_test2.txt", "subdir/.gitattributes", "subdir/abc", "subdir/subdir_test1", "subdir/subdir_test2.txt", "subdir2/subdir2_test1", NULL }; void test_diff_iterator__tree_4(void) { tree_iterator_test( "attr", "24fa9a9fc4e202313e24b648087495441dab432b", NULL, NULL, 23, expected_tree_4); } void test_diff_iterator__tree_4_ranged(void) { tree_iterator_test( "attr", "24fa9a9fc4e202313e24b648087495441dab432b", "sub", "sub", 11, &expected_tree_4[12]); } const char *expected_tree_ranged_0[] = { "gitattributes", "macro_bad", "macro_test", "root_test1", "root_test2", "root_test3", "root_test4.txt", NULL }; void test_diff_iterator__tree_ranged_0(void) { tree_iterator_test( "attr", "24fa9a9fc4e202313e24b648087495441dab432b", "git", "root", 7, expected_tree_ranged_0); } const char *expected_tree_ranged_1[] = { "sub/subdir_test2.txt", NULL }; void test_diff_iterator__tree_ranged_1(void) { tree_iterator_test( "attr", "24fa9a9fc4e202313e24b648087495441dab432b", "sub/subdir_test2.txt", "sub/subdir_test2.txt", 1, expected_tree_ranged_1); } void test_diff_iterator__tree_range_empty_0(void) { tree_iterator_test( "attr", "24fa9a9fc4e202313e24b648087495441dab432b", "empty", "empty", 0, NULL); } void test_diff_iterator__tree_range_empty_1(void) { tree_iterator_test( "attr", "24fa9a9fc4e202313e24b648087495441dab432b", "z_empty_after", NULL, 0, NULL); } void test_diff_iterator__tree_range_empty_2(void) { tree_iterator_test( "attr", "24fa9a9fc4e202313e24b648087495441dab432b", NULL, ".aaa_empty_before", 0, NULL); } static void check_tree_entry( git_iterator *i, const char *oid, const char *oid_p, const char *oid_pp, const char *oid_ppp) { const git_index_entry *ie; const git_tree_entry *te; const git_tree *tree; git_buf path = GIT_BUF_INIT; cl_git_pass(git_iterator_current_tree_entry(&te, i)); cl_assert(te); cl_assert(git_oid_streq(&te->oid, oid) == 0); cl_git_pass(git_iterator_current(&ie, i)); cl_git_pass(git_buf_sets(&path, ie->path)); if (oid_p) { git_buf_rtruncate_at_char(&path, '/'); cl_git_pass(git_iterator_current_parent_tree(&tree, i, path.ptr)); cl_assert(tree); cl_assert(git_oid_streq(git_tree_id(tree), oid_p) == 0); } if (oid_pp) { git_buf_rtruncate_at_char(&path, '/'); cl_git_pass(git_iterator_current_parent_tree(&tree, i, path.ptr)); cl_assert(tree); cl_assert(git_oid_streq(git_tree_id(tree), oid_pp) == 0); } if (oid_ppp) { git_buf_rtruncate_at_char(&path, '/'); cl_git_pass(git_iterator_current_parent_tree(&tree, i, path.ptr)); cl_assert(tree); cl_assert(git_oid_streq(git_tree_id(tree), oid_ppp) == 0); } git_buf_free(&path); } void test_diff_iterator__tree_special_functions(void) { git_tree *t; git_iterator *i; const git_index_entry *entry; git_repository *repo = cl_git_sandbox_init("attr"); int error, cases = 0; const char *rootoid = "ce39a97a7fb1fa90bcf5e711249c1e507476ae0e"; t = resolve_commit_oid_to_tree( repo, "24fa9a9fc4e202313e24b648087495441dab432b"); cl_assert(t != NULL); cl_git_pass(git_iterator_for_tree( &i, t, GIT_ITERATOR_DONT_IGNORE_CASE, NULL, NULL)); while (!(error = git_iterator_advance(&entry, i))) { cl_assert(entry); if (strcmp(entry->path, "sub/file") == 0) { cases++; check_tree_entry( i, "45b983be36b73c0788dc9cbcb76cbb80fc7bb057", "ecb97df2a174987475ac816e3847fc8e9f6c596b", rootoid, NULL); } else if (strcmp(entry->path, "sub/sub/subsub.txt") == 0) { cases++; check_tree_entry( i, "9e5bdc47d6a80f2be0ea3049ad74231b94609242", "4e49ba8c5b6c32ff28cd9dcb60be34df50fcc485", "ecb97df2a174987475ac816e3847fc8e9f6c596b", rootoid); } else if (strcmp(entry->path, "subdir/.gitattributes") == 0) { cases++; check_tree_entry( i, "99eae476896f4907224978b88e5ecaa6c5bb67a9", "9fb40b6675dde60b5697afceae91b66d908c02d9", rootoid, NULL); } else if (strcmp(entry->path, "subdir2/subdir2_test1") == 0) { cases++; check_tree_entry( i, "dccada462d3df8ac6de596fb8c896aba9344f941", "2929de282ce999e95183aedac6451d3384559c4b", rootoid, NULL); } } cl_assert_equal_i(GIT_ITEROVER, error); cl_assert(!entry); cl_assert_equal_i(4, cases); git_iterator_free(i); git_tree_free(t); } /* -- INDEX ITERATOR TESTS -- */ static void index_iterator_test( const char *sandbox, const char *start, const char *end, int expected_count, const char **expected_names, const char **expected_oids) { git_index *index; git_iterator *i; const git_index_entry *entry; int error, count = 0; git_repository *repo = cl_git_sandbox_init(sandbox); cl_git_pass(git_repository_index(&index, repo)); cl_git_pass(git_iterator_for_index(&i, index, 0, start, end)); while (!(error = git_iterator_advance(&entry, i))) { cl_assert(entry); if (expected_names != NULL) cl_assert_equal_s(expected_names[count], entry->path); if (expected_oids != NULL) { git_oid oid; cl_git_pass(git_oid_fromstr(&oid, expected_oids[count])); cl_assert_equal_i(git_oid_cmp(&oid, &entry->oid), 0); } count++; } cl_assert_equal_i(GIT_ITEROVER, error); cl_assert(!entry); cl_assert_equal_i(expected_count, count); git_iterator_free(i); git_index_free(index); } static const char *expected_index_0[] = { "attr0", "attr1", "attr2", "attr3", "binfile", "gitattributes", "macro_bad", "macro_test", "root_test1", "root_test2", "root_test3", "root_test4.txt", "sub/abc", "sub/file", "sub/sub/file", "sub/sub/subsub.txt", "sub/subdir_test1", "sub/subdir_test2.txt", "subdir/.gitattributes", "subdir/abc", "subdir/subdir_test1", "subdir/subdir_test2.txt", "subdir2/subdir2_test1", }; static const char *expected_index_oids_0[] = { "556f8c827b8e4a02ad5cab77dca2bcb3e226b0b3", "3b74db7ab381105dc0d28f8295a77f6a82989292", "2c66e14f77196ea763fb1e41612c1aa2bc2d8ed2", "c485abe35abd4aa6fd83b076a78bbea9e2e7e06c", "d800886d9c86731ae5c4a62b0b77c437015e00d2", "2b40c5aca159b04ea8d20ffe36cdf8b09369b14a", "5819a185d77b03325aaf87cafc771db36f6ddca7", "ff69f8639ce2e6010b3f33a74160aad98b48da2b", "45141a79a77842c59a63229403220a4e4be74e3d", "4d713dc48e6b1bd75b0d61ad078ba9ca3a56745d", "108bb4e7fd7b16490dc33ff7d972151e73d7166e", "a0f7217ae99f5ac3e88534f5cea267febc5fa85b", "3e42ffc54a663f9401cc25843d6c0e71a33e4249", "45b983be36b73c0788dc9cbcb76cbb80fc7bb057", "45b983be36b73c0788dc9cbcb76cbb80fc7bb057", "9e5bdc47d6a80f2be0ea3049ad74231b94609242", "e563cf4758f0d646f1b14b76016aa17fa9e549a4", "fb5067b1aef3ac1ada4b379dbcb7d17255df7d78", "99eae476896f4907224978b88e5ecaa6c5bb67a9", "3e42ffc54a663f9401cc25843d6c0e71a33e4249", "e563cf4758f0d646f1b14b76016aa17fa9e549a4", "fb5067b1aef3ac1ada4b379dbcb7d17255df7d78", "dccada462d3df8ac6de596fb8c896aba9344f941" }; void test_diff_iterator__index_0(void) { index_iterator_test( "attr", NULL, NULL, 23, expected_index_0, expected_index_oids_0); } static const char *expected_index_range[] = { "root_test1", "root_test2", "root_test3", "root_test4.txt", }; static const char *expected_index_oids_range[] = { "45141a79a77842c59a63229403220a4e4be74e3d", "4d713dc48e6b1bd75b0d61ad078ba9ca3a56745d", "108bb4e7fd7b16490dc33ff7d972151e73d7166e", "a0f7217ae99f5ac3e88534f5cea267febc5fa85b", }; void test_diff_iterator__index_range(void) { index_iterator_test( "attr", "root", "root", 4, expected_index_range, expected_index_oids_range); } void test_diff_iterator__index_range_empty_0(void) { index_iterator_test( "attr", "empty", "empty", 0, NULL, NULL); } void test_diff_iterator__index_range_empty_1(void) { index_iterator_test( "attr", "z_empty_after", NULL, 0, NULL, NULL); } void test_diff_iterator__index_range_empty_2(void) { index_iterator_test( "attr", NULL, ".aaa_empty_before", 0, NULL, NULL); } static const char *expected_index_1[] = { "current_file", "file_deleted", "modified_file", "staged_changes", "staged_changes_file_deleted", "staged_changes_modified_file", "staged_new_file", "staged_new_file_deleted_file", "staged_new_file_modified_file", "subdir.txt", "subdir/current_file", "subdir/deleted_file", "subdir/modified_file", }; static const char* expected_index_oids_1[] = { "a0de7e0ac200c489c41c59dfa910154a70264e6e", "5452d32f1dd538eb0405e8a83cc185f79e25e80f", "452e4244b5d083ddf0460acf1ecc74db9dcfa11a", "55d316c9ba708999f1918e9677d01dfcae69c6b9", "a6be623522ce87a1d862128ac42672604f7b468b", "906ee7711f4f4928ddcb2a5f8fbc500deba0d2a8", "529a16e8e762d4acb7b9636ff540a00831f9155a", "90b8c29d8ba39434d1c63e1b093daaa26e5bd972", "ed062903b8f6f3dccb2fa81117ba6590944ef9bd", "e8ee89e15bbe9b20137715232387b3de5b28972e", "53ace0d1cc1145a5f4fe4f78a186a60263190733", "1888c805345ba265b0ee9449b8877b6064592058", "a6191982709b746d5650e93c2acf34ef74e11504" }; void test_diff_iterator__index_1(void) { index_iterator_test( "status", NULL, NULL, 13, expected_index_1, expected_index_oids_1); } /* -- WORKDIR ITERATOR TESTS -- */ static void workdir_iterator_test( const char *sandbox, const char *start, const char *end, int expected_count, int expected_ignores, const char **expected_names, const char *an_ignored_name) { git_iterator *i; const git_index_entry *entry; int error, count = 0, count_all = 0, count_all_post_reset = 0; git_repository *repo = cl_git_sandbox_init(sandbox); cl_git_pass(git_iterator_for_workdir( &i, repo, GIT_ITERATOR_DONT_AUTOEXPAND, start, end)); error = git_iterator_current(&entry, i); cl_assert((error == 0 && entry != NULL) || (error == GIT_ITEROVER && entry == NULL)); while (entry != NULL) { int ignored = git_iterator_current_is_ignored(i); if (S_ISDIR(entry->mode)) { cl_git_pass(git_iterator_advance_into(&entry, i)); continue; } if (expected_names != NULL) cl_assert_equal_s(expected_names[count_all], entry->path); if (an_ignored_name && strcmp(an_ignored_name,entry->path)==0) cl_assert(ignored); if (!ignored) count++; count_all++; error = git_iterator_advance(&entry, i); cl_assert((error == 0 && entry != NULL) || (error == GIT_ITEROVER && entry == NULL)); } cl_assert_equal_i(expected_count, count); cl_assert_equal_i(expected_count + expected_ignores, count_all); cl_git_pass(git_iterator_reset(i, NULL, NULL)); error = git_iterator_current(&entry, i); cl_assert((error == 0 && entry != NULL) || (error == GIT_ITEROVER && entry == NULL)); while (entry != NULL) { if (S_ISDIR(entry->mode)) { cl_git_pass(git_iterator_advance_into(&entry, i)); continue; } if (expected_names != NULL) cl_assert_equal_s( expected_names[count_all_post_reset], entry->path); count_all_post_reset++; error = git_iterator_advance(&entry, i); cl_assert(error == 0 || error == GIT_ITEROVER); } cl_assert_equal_i(count_all, count_all_post_reset); git_iterator_free(i); } void test_diff_iterator__workdir_0(void) { workdir_iterator_test("attr", NULL, NULL, 27, 1, NULL, "ign"); } static const char *status_paths[] = { "current_file", "ignored_file", "modified_file", "new_file", "staged_changes", "staged_changes_modified_file", "staged_delete_modified_file", "staged_new_file", "staged_new_file_modified_file", "subdir.txt", "subdir/current_file", "subdir/modified_file", "subdir/new_file", "\xe8\xbf\x99", NULL }; void test_diff_iterator__workdir_1(void) { workdir_iterator_test( "status", NULL, NULL, 13, 1, status_paths, "ignored_file"); } static const char *status_paths_range_0[] = { "staged_changes", "staged_changes_modified_file", "staged_delete_modified_file", "staged_new_file", "staged_new_file_modified_file", NULL }; void test_diff_iterator__workdir_1_ranged_0(void) { workdir_iterator_test( "status", "staged", "staged", 5, 0, status_paths_range_0, NULL); } static const char *status_paths_range_1[] = { "modified_file", NULL }; void test_diff_iterator__workdir_1_ranged_1(void) { workdir_iterator_test( "status", "modified_file", "modified_file", 1, 0, status_paths_range_1, NULL); } static const char *status_paths_range_3[] = { "subdir.txt", "subdir/current_file", "subdir/modified_file", NULL }; void test_diff_iterator__workdir_1_ranged_3(void) { workdir_iterator_test( "status", "subdir", "subdir/modified_file", 3, 0, status_paths_range_3, NULL); } static const char *status_paths_range_4[] = { "subdir/current_file", "subdir/modified_file", "subdir/new_file", "\xe8\xbf\x99", NULL }; void test_diff_iterator__workdir_1_ranged_4(void) { workdir_iterator_test( "status", "subdir/", NULL, 4, 0, status_paths_range_4, NULL); } static const char *status_paths_range_5[] = { "subdir/modified_file", NULL }; void test_diff_iterator__workdir_1_ranged_5(void) { workdir_iterator_test( "status", "subdir/modified_file", "subdir/modified_file", 1, 0, status_paths_range_5, NULL); } void test_diff_iterator__workdir_1_ranged_empty_0(void) { workdir_iterator_test( "status", "\xff_does_not_exist", NULL, 0, 0, NULL, NULL); } void test_diff_iterator__workdir_1_ranged_empty_1(void) { workdir_iterator_test( "status", "empty", "empty", 0, 0, NULL, NULL); } void test_diff_iterator__workdir_1_ranged_empty_2(void) { workdir_iterator_test( "status", NULL, "aaaa_empty_before", 0, 0, NULL, NULL); } void test_diff_iterator__workdir_builtin_ignores(void) { git_repository *repo = cl_git_sandbox_init("attr"); git_iterator *i; const git_index_entry *entry; int idx; static struct { const char *path; bool ignored; } expected[] = { { "dir/", true }, { "file", false }, { "ign", true }, { "macro_bad", false }, { "macro_test", false }, { "root_test1", false }, { "root_test2", false }, { "root_test3", false }, { "root_test4.txt", false }, { "sub", false }, { "sub/.gitattributes", false }, { "sub/abc", false }, { "sub/dir/", true }, { "sub/file", false }, { "sub/ign/", true }, { "sub/sub", false }, { "sub/sub/.gitattributes", false }, { "sub/sub/dir", false }, /* file is not actually a dir */ { "sub/sub/file", false }, { NULL, false } }; cl_git_pass(p_mkdir("attr/sub/sub/.git", 0777)); cl_git_mkfile("attr/sub/.git", "whatever"); cl_git_pass(git_iterator_for_workdir( &i, repo, GIT_ITERATOR_DONT_AUTOEXPAND, "dir", "sub/sub/file")); cl_git_pass(git_iterator_current(&entry, i)); for (idx = 0; entry != NULL; ++idx) { int ignored = git_iterator_current_is_ignored(i); cl_assert_equal_s(expected[idx].path, entry->path); cl_assert_(ignored == expected[idx].ignored, expected[idx].path); if (!ignored && (entry->mode == GIT_FILEMODE_TREE || entry->mode == GIT_FILEMODE_COMMIT)) { /* it is possible to advance "into" a submodule */ cl_git_pass(git_iterator_advance_into(&entry, i)); } else { int error = git_iterator_advance(&entry, i); cl_assert(!error || error == GIT_ITEROVER); } } cl_assert(expected[idx].path == NULL); git_iterator_free(i); } static void check_wd_first_through_third_range( git_repository *repo, const char *start, const char *end) { git_iterator *i; const git_index_entry *entry; int error, idx; static const char *expected[] = { "FIRST", "second", "THIRD", NULL }; cl_git_pass(git_iterator_for_workdir( &i, repo, GIT_ITERATOR_IGNORE_CASE, start, end)); cl_git_pass(git_iterator_current(&entry, i)); for (idx = 0; entry != NULL; ++idx) { cl_assert_equal_s(expected[idx], entry->path); error = git_iterator_advance(&entry, i); cl_assert(!error || error == GIT_ITEROVER); } cl_assert(expected[idx] == NULL); git_iterator_free(i); } void test_diff_iterator__workdir_handles_icase_range(void) { git_repository *repo; repo = cl_git_sandbox_init("empty_standard_repo"); cl_git_remove_placeholders(git_repository_path(repo), "dummy-marker.txt"); cl_git_mkfile("empty_standard_repo/before", "whatever\n"); cl_git_mkfile("empty_standard_repo/FIRST", "whatever\n"); cl_git_mkfile("empty_standard_repo/second", "whatever\n"); cl_git_mkfile("empty_standard_repo/THIRD", "whatever\n"); cl_git_mkfile("empty_standard_repo/zafter", "whatever\n"); cl_git_mkfile("empty_standard_repo/Zlast", "whatever\n"); check_wd_first_through_third_range(repo, "first", "third"); check_wd_first_through_third_range(repo, "FIRST", "THIRD"); check_wd_first_through_third_range(repo, "first", "THIRD"); check_wd_first_through_third_range(repo, "FIRST", "third"); check_wd_first_through_third_range(repo, "FirSt", "tHiRd"); } static void check_tree_range( git_repository *repo, const char *start, const char *end, bool ignore_case, int expected_count) { git_tree *head; git_iterator *i; int error, count; cl_git_pass(git_repository_head_tree(&head, repo)); cl_git_pass(git_iterator_for_tree( &i, head, ignore_case ? GIT_ITERATOR_IGNORE_CASE : GIT_ITERATOR_DONT_IGNORE_CASE, start, end)); for (count = 0; !(error = git_iterator_advance(NULL, i)); ++count) /* count em up */; cl_assert_equal_i(GIT_ITEROVER, error); cl_assert_equal_i(expected_count, count); git_iterator_free(i); git_tree_free(head); } void test_diff_iterator__tree_handles_icase_range(void) { git_repository *repo; repo = cl_git_sandbox_init("testrepo"); check_tree_range(repo, "B", "C", false, 0); check_tree_range(repo, "B", "C", true, 1); check_tree_range(repo, "b", "c", false, 1); check_tree_range(repo, "b", "c", true, 1); check_tree_range(repo, "a", "z", false, 3); check_tree_range(repo, "a", "z", true, 4); check_tree_range(repo, "A", "Z", false, 1); check_tree_range(repo, "A", "Z", true, 4); check_tree_range(repo, "a", "Z", false, 0); check_tree_range(repo, "a", "Z", true, 4); check_tree_range(repo, "A", "z", false, 4); check_tree_range(repo, "A", "z", true, 4); check_tree_range(repo, "new.txt", "new.txt", true, 1); check_tree_range(repo, "new.txt", "new.txt", false, 1); check_tree_range(repo, "README", "README", true, 1); check_tree_range(repo, "README", "README", false, 1); } static void check_index_range( git_repository *repo, const char *start, const char *end, bool ignore_case, int expected_count) { git_index *index; git_iterator *i; int error, count, caps; bool is_ignoring_case; cl_git_pass(git_repository_index(&index, repo)); caps = git_index_caps(index); is_ignoring_case = ((caps & GIT_INDEXCAP_IGNORE_CASE) != 0); if (ignore_case != is_ignoring_case) cl_git_pass(git_index_set_caps(index, caps ^ GIT_INDEXCAP_IGNORE_CASE)); cl_git_pass(git_iterator_for_index(&i, index, 0, start, end)); cl_assert(git_iterator_ignore_case(i) == ignore_case); for (count = 0; !(error = git_iterator_advance(NULL, i)); ++count) /* count em up */; cl_assert_equal_i(GIT_ITEROVER, error); cl_assert_equal_i(expected_count, count); git_iterator_free(i); git_index_free(index); } void test_diff_iterator__index_handles_icase_range(void) { git_repository *repo; git_index *index; git_tree *head; repo = cl_git_sandbox_init("testrepo"); /* reset index to match HEAD */ cl_git_pass(git_repository_head_tree(&head, repo)); cl_git_pass(git_repository_index(&index, repo)); cl_git_pass(git_index_read_tree(index, head)); cl_git_pass(git_index_write(index)); git_tree_free(head); git_index_free(index); /* do some ranged iterator checks toggling case sensitivity */ check_index_range(repo, "B", "C", false, 0); check_index_range(repo, "B", "C", true, 1); check_index_range(repo, "a", "z", false, 3); check_index_range(repo, "a", "z", true, 4); } libgit2-0.19.0/tests-clar/diff/notify.c000066400000000000000000000131411216214232500176000ustar00rootroot00000000000000#include "clar_libgit2.h" #include "diff_helpers.h" static git_repository *g_repo = NULL; void test_diff_notify__initialize(void) { } void test_diff_notify__cleanup(void) { cl_git_sandbox_cleanup(); } static int assert_called_notifications( const git_diff_list *diff_so_far, const git_diff_delta *delta_to_add, const char *matched_pathspec, void *payload) { bool found = false; notify_expected *exp = (notify_expected*)payload; notify_expected *e;; GIT_UNUSED(diff_so_far); for (e = exp; e->path != NULL; e++) { if (strcmp(e->path, delta_to_add->new_file.path)) continue; cl_assert_equal_s(e->matched_pathspec, matched_pathspec); found = true; break; } cl_assert(found); return 0; } static void test_notify( char **searched_pathspecs, int pathspecs_count, notify_expected *expected_matched_pathspecs, int expected_diffed_files_count) { git_diff_options opts = GIT_DIFF_OPTIONS_INIT; git_diff_list *diff = NULL; diff_expects exp; g_repo = cl_git_sandbox_init("status"); opts.flags |= GIT_DIFF_INCLUDE_IGNORED | GIT_DIFF_INCLUDE_UNTRACKED; opts.notify_cb = assert_called_notifications; opts.pathspec.strings = searched_pathspecs; opts.pathspec.count = pathspecs_count; opts.notify_payload = expected_matched_pathspecs; memset(&exp, 0, sizeof(exp)); cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts)); cl_git_pass(git_diff_foreach(diff, diff_file_cb, NULL, NULL, &exp)); cl_assert_equal_i(expected_diffed_files_count, exp.files); git_diff_list_free(diff); } void test_diff_notify__notify_single_pathspec(void) { char *searched_pathspecs[] = { "*_deleted", }; notify_expected expected_matched_pathspecs[] = { { "file_deleted", "*_deleted" }, { "staged_changes_file_deleted", "*_deleted" }, { NULL, NULL } }; test_notify(searched_pathspecs, 1, expected_matched_pathspecs, 2); } void test_diff_notify__notify_multiple_pathspec(void) { char *searched_pathspecs[] = { "staged_changes_cant_find_me", "subdir/modified_cant_find_me", "subdir/*", "staged*" }; notify_expected expected_matched_pathspecs[] = { { "staged_changes_file_deleted", "staged*" }, { "staged_changes_modified_file", "staged*" }, { "staged_delete_modified_file", "staged*" }, { "staged_new_file_deleted_file", "staged*" }, { "staged_new_file_modified_file", "staged*" }, { "subdir/deleted_file", "subdir/*" }, { "subdir/modified_file", "subdir/*" }, { "subdir/new_file", "subdir/*" }, { NULL, NULL } }; test_notify(searched_pathspecs, 4, expected_matched_pathspecs, 8); } void test_diff_notify__notify_catchall_with_empty_pathspecs(void) { char *searched_pathspecs[] = { "", "" }; notify_expected expected_matched_pathspecs[] = { { "file_deleted", NULL }, { "ignored_file", NULL }, { "modified_file", NULL }, { "new_file", NULL }, { "\xe8\xbf\x99", NULL }, { "staged_changes_file_deleted", NULL }, { "staged_changes_modified_file", NULL }, { "staged_delete_modified_file", NULL }, { "staged_new_file_deleted_file", NULL }, { "staged_new_file_modified_file", NULL }, { "subdir/deleted_file", NULL }, { "subdir/modified_file", NULL }, { "subdir/new_file", NULL }, { NULL, NULL } }; test_notify(searched_pathspecs, 1, expected_matched_pathspecs, 13); } void test_diff_notify__notify_catchall(void) { char *searched_pathspecs[] = { "*", }; notify_expected expected_matched_pathspecs[] = { { "file_deleted", "*" }, { "ignored_file", "*" }, { "modified_file", "*" }, { "new_file", "*" }, { "\xe8\xbf\x99", "*" }, { "staged_changes_file_deleted", "*" }, { "staged_changes_modified_file", "*" }, { "staged_delete_modified_file", "*" }, { "staged_new_file_deleted_file", "*" }, { "staged_new_file_modified_file", "*" }, { "subdir/deleted_file", "*" }, { "subdir/modified_file", "*" }, { "subdir/new_file", "*" }, { NULL, NULL } }; test_notify(searched_pathspecs, 1, expected_matched_pathspecs, 13); } static int abort_diff( const git_diff_list *diff_so_far, const git_diff_delta *delta_to_add, const char *matched_pathspec, void *payload) { GIT_UNUSED(diff_so_far); GIT_UNUSED(delta_to_add); GIT_UNUSED(matched_pathspec); GIT_UNUSED(payload); return -42; } void test_diff_notify__notify_cb_can_abort_diff(void) { git_diff_options opts = GIT_DIFF_OPTIONS_INIT; git_diff_list *diff = NULL; char *pathspec = NULL; g_repo = cl_git_sandbox_init("status"); opts.flags |= GIT_DIFF_INCLUDE_IGNORED | GIT_DIFF_INCLUDE_UNTRACKED; opts.notify_cb = abort_diff; opts.pathspec.strings = &pathspec; opts.pathspec.count = 1; pathspec = "file_deleted"; cl_git_fail(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts)); pathspec = "staged_changes_modified_file"; cl_git_fail(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts)); } static int filter_all( const git_diff_list *diff_so_far, const git_diff_delta *delta_to_add, const char *matched_pathspec, void *payload) { GIT_UNUSED(diff_so_far); GIT_UNUSED(delta_to_add); GIT_UNUSED(matched_pathspec); GIT_UNUSED(payload); return 42; } void test_diff_notify__notify_cb_can_be_used_as_filtering_function(void) { git_diff_options opts = GIT_DIFF_OPTIONS_INIT; git_diff_list *diff = NULL; char *pathspec = NULL; diff_expects exp; g_repo = cl_git_sandbox_init("status"); opts.flags |= GIT_DIFF_INCLUDE_IGNORED | GIT_DIFF_INCLUDE_UNTRACKED; opts.notify_cb = filter_all; opts.pathspec.strings = &pathspec; opts.pathspec.count = 1; pathspec = "*_deleted"; memset(&exp, 0, sizeof(exp)); cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts)); cl_git_pass(git_diff_foreach(diff, diff_file_cb, NULL, NULL, &exp)); cl_assert_equal_i(0, exp.files); git_diff_list_free(diff); } libgit2-0.19.0/tests-clar/diff/patch.c000066400000000000000000000453261216214232500174010ustar00rootroot00000000000000#include "clar_libgit2.h" #include "git2/sys/repository.h" #include "diff_helpers.h" #include "repository.h" #include "buf_text.h" static git_repository *g_repo = NULL; void test_diff_patch__initialize(void) { } void test_diff_patch__cleanup(void) { cl_git_sandbox_cleanup(); } #define EXPECTED_HEADER "diff --git a/subdir.txt b/subdir.txt\n" \ "deleted file mode 100644\n" \ "index e8ee89e..0000000\n" \ "--- a/subdir.txt\n" \ "+++ /dev/null\n" #define EXPECTED_HUNK "@@ -1,2 +0,0 @@\n" static int check_removal_cb( const git_diff_delta *delta, const git_diff_range *range, char line_origin, const char *formatted_output, size_t output_len, void *payload) { GIT_UNUSED(payload); GIT_UNUSED(output_len); switch (line_origin) { case GIT_DIFF_LINE_FILE_HDR: cl_assert_equal_s(EXPECTED_HEADER, formatted_output); cl_assert(range == NULL); goto check_delta; case GIT_DIFF_LINE_HUNK_HDR: cl_assert_equal_s(EXPECTED_HUNK, formatted_output); /* Fall through */ case GIT_DIFF_LINE_CONTEXT: case GIT_DIFF_LINE_DELETION: goto check_range; default: /* unexpected code path */ return -1; } check_range: cl_assert(range != NULL); cl_assert_equal_i(1, range->old_start); cl_assert_equal_i(2, range->old_lines); cl_assert_equal_i(0, range->new_start); cl_assert_equal_i(0, range->new_lines); check_delta: cl_assert_equal_s("subdir.txt", delta->old_file.path); cl_assert_equal_s("subdir.txt", delta->new_file.path); cl_assert_equal_i(GIT_DELTA_DELETED, delta->status); return 0; } void test_diff_patch__can_properly_display_the_removal_of_a_file(void) { /* * $ git diff 26a125e..735b6a2 * diff --git a/subdir.txt b/subdir.txt * deleted file mode 100644 * index e8ee89e..0000000 * --- a/subdir.txt * +++ /dev/null * @@ -1,2 +0,0 @@ * -Is it a bird? * -Is it a plane? */ const char *one_sha = "26a125e"; const char *another_sha = "735b6a2"; git_tree *one, *another; git_diff_list *diff; g_repo = cl_git_sandbox_init("status"); one = resolve_commit_oid_to_tree(g_repo, one_sha); another = resolve_commit_oid_to_tree(g_repo, another_sha); cl_git_pass(git_diff_tree_to_tree(&diff, g_repo, one, another, NULL)); cl_git_pass(git_diff_print_patch(diff, check_removal_cb, NULL)); git_diff_list_free(diff); git_tree_free(another); git_tree_free(one); } void test_diff_patch__to_string(void) { const char *one_sha = "26a125e"; const char *another_sha = "735b6a2"; git_tree *one, *another; git_diff_list *diff; git_diff_patch *patch; char *text; const char *expected = "diff --git a/subdir.txt b/subdir.txt\ndeleted file mode 100644\nindex e8ee89e..0000000\n--- a/subdir.txt\n+++ /dev/null\n@@ -1,2 +0,0 @@\n-Is it a bird?\n-Is it a plane?\n"; g_repo = cl_git_sandbox_init("status"); one = resolve_commit_oid_to_tree(g_repo, one_sha); another = resolve_commit_oid_to_tree(g_repo, another_sha); cl_git_pass(git_diff_tree_to_tree(&diff, g_repo, one, another, NULL)); cl_assert_equal_i(1, (int)git_diff_num_deltas(diff)); cl_git_pass(git_diff_get_patch(&patch, NULL, diff, 0)); cl_git_pass(git_diff_patch_to_str(&text, patch)); cl_assert_equal_s(expected, text); git__free(text); git_diff_patch_free(patch); git_diff_list_free(diff); git_tree_free(another); git_tree_free(one); } void test_diff_patch__config_options(void) { const char *one_sha = "26a125e"; /* current HEAD */ git_tree *one; git_config *cfg; git_diff_list *diff; git_diff_patch *patch; char *text; git_diff_options opts = GIT_DIFF_OPTIONS_INIT; char *onefile = "staged_changes_modified_file"; const char *expected1 = "diff --git c/staged_changes_modified_file i/staged_changes_modified_file\nindex 70bd944..906ee77 100644\n--- c/staged_changes_modified_file\n+++ i/staged_changes_modified_file\n@@ -1 +1,2 @@\n staged_changes_modified_file\n+staged_changes_modified_file\n"; const char *expected2 = "diff --git i/staged_changes_modified_file w/staged_changes_modified_file\nindex 906ee77..011c344 100644\n--- i/staged_changes_modified_file\n+++ w/staged_changes_modified_file\n@@ -1,2 +1,3 @@\n staged_changes_modified_file\n staged_changes_modified_file\n+staged_changes_modified_file\n"; const char *expected3 = "diff --git staged_changes_modified_file staged_changes_modified_file\nindex 906ee77..011c344 100644\n--- staged_changes_modified_file\n+++ staged_changes_modified_file\n@@ -1,2 +1,3 @@\n staged_changes_modified_file\n staged_changes_modified_file\n+staged_changes_modified_file\n"; const char *expected4 = "diff --git staged_changes_modified_file staged_changes_modified_file\nindex 70bd9443ada0..906ee7711f4f 100644\n--- staged_changes_modified_file\n+++ staged_changes_modified_file\n@@ -1 +1,2 @@\n staged_changes_modified_file\n+staged_changes_modified_file\n"; g_repo = cl_git_sandbox_init("status"); cl_git_pass(git_repository_config(&cfg, g_repo)); one = resolve_commit_oid_to_tree(g_repo, one_sha); opts.pathspec.count = 1; opts.pathspec.strings = &onefile; cl_git_pass(git_config_set_string(cfg, "diff.mnemonicprefix", "true")); cl_git_pass(git_diff_tree_to_index(&diff, g_repo, one, NULL, &opts)); cl_assert_equal_i(1, (int)git_diff_num_deltas(diff)); cl_git_pass(git_diff_get_patch(&patch, NULL, diff, 0)); cl_git_pass(git_diff_patch_to_str(&text, patch)); cl_assert_equal_s(expected1, text); git__free(text); git_diff_patch_free(patch); git_diff_list_free(diff); cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts)); cl_assert_equal_i(1, (int)git_diff_num_deltas(diff)); cl_git_pass(git_diff_get_patch(&patch, NULL, diff, 0)); cl_git_pass(git_diff_patch_to_str(&text, patch)); cl_assert_equal_s(expected2, text); git__free(text); git_diff_patch_free(patch); git_diff_list_free(diff); cl_git_pass(git_config_set_string(cfg, "diff.noprefix", "true")); cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts)); cl_assert_equal_i(1, (int)git_diff_num_deltas(diff)); cl_git_pass(git_diff_get_patch(&patch, NULL, diff, 0)); cl_git_pass(git_diff_patch_to_str(&text, patch)); cl_assert_equal_s(expected3, text); git__free(text); git_diff_patch_free(patch); git_diff_list_free(diff); cl_git_pass(git_config_set_int32(cfg, "core.abbrev", 12)); cl_git_pass(git_diff_tree_to_index(&diff, g_repo, one, NULL, &opts)); cl_assert_equal_i(1, (int)git_diff_num_deltas(diff)); cl_git_pass(git_diff_get_patch(&patch, NULL, diff, 0)); cl_git_pass(git_diff_patch_to_str(&text, patch)); cl_assert_equal_s(expected4, text); git__free(text); git_diff_patch_free(patch); git_diff_list_free(diff); git_tree_free(one); git_config_free(cfg); } void test_diff_patch__hunks_have_correct_line_numbers(void) { git_config *cfg; git_tree *head; git_diff_options opt = GIT_DIFF_OPTIONS_INIT; git_diff_list *diff; git_diff_patch *patch; const git_diff_delta *delta; const git_diff_range *range; const char *hdr, *text; size_t hdrlen, hunklen, textlen; char origin; int oldno, newno; git_buf old_content = GIT_BUF_INIT, actual = GIT_BUF_INIT; const char *new_content = "The Song of Seven Cities\n------------------------\n\nI WAS Lord of Cities very sumptuously builded.\nSeven roaring Cities paid me tribute from afar.\nIvory their outposts were--the guardrooms of them gilded,\nAnd garrisoned with Amazons invincible in war.\n\nThis is some new text;\nNot as good as the old text;\nBut here it is.\n\nSo they warred and trafficked only yesterday, my Cities.\nTo-day there is no mark or mound of where my Cities stood.\nFor the River rose at midnight and it washed away my Cities.\nThey are evened with Atlantis and the towns before the Flood.\n\nRain on rain-gorged channels raised the water-levels round them,\nFreshet backed on freshet swelled and swept their world from sight,\nTill the emboldened floods linked arms and, flashing forward, drowned them--\nDrowned my Seven Cities and their peoples in one night!\n\nLow among the alders lie their derelict foundations,\nThe beams wherein they trusted and the plinths whereon they built--\nMy rulers and their treasure and their unborn populations,\nDead, destroyed, aborted, and defiled with mud and silt!\n\nAnother replacement;\nBreaking up the poem;\nGenerating some hunks.\n\nTo the sound of trumpets shall their seed restore my Cities\nWealthy and well-weaponed, that once more may I behold\nAll the world go softly when it walks before my Cities,\nAnd the horses and the chariots fleeing from them as of old!\n\n -- Rudyard Kipling\n"; g_repo = cl_git_sandbox_init("renames"); cl_git_pass(git_config_new(&cfg)); git_repository_set_config(g_repo, cfg); cl_git_pass( git_futils_readbuffer(&old_content, "renames/songof7cities.txt")); cl_git_rewritefile("renames/songof7cities.txt", new_content); cl_git_pass(git_repository_head_tree(&head, g_repo)); cl_git_pass(git_diff_tree_to_workdir(&diff, g_repo, head, &opt)); cl_assert_equal_i(1, (int)git_diff_num_deltas(diff)); cl_git_pass(git_diff_get_patch(&patch, &delta, diff, 0)); cl_assert_equal_i(GIT_DELTA_MODIFIED, (int)delta->status); cl_assert_equal_i(2, (int)git_diff_patch_num_hunks(patch)); /* check hunk 0 */ cl_git_pass( git_diff_patch_get_hunk(&range, &hdr, &hdrlen, &hunklen, patch, 0)); cl_assert_equal_i(18, (int)hunklen); cl_assert_equal_i(6, (int)range->old_start); cl_assert_equal_i(15, (int)range->old_lines); cl_assert_equal_i(6, (int)range->new_start); cl_assert_equal_i(9, (int)range->new_lines); cl_assert_equal_i(18, (int)git_diff_patch_num_lines_in_hunk(patch, 0)); cl_git_pass(git_diff_patch_get_line_in_hunk( &origin, &text, &textlen, &oldno, &newno, patch, 0, 0)); cl_assert_equal_i(GIT_DIFF_LINE_CONTEXT, (int)origin); cl_git_pass(git_buf_set(&actual, text, textlen)); cl_assert_equal_s("Ivory their outposts were--the guardrooms of them gilded,\n", actual.ptr); cl_assert_equal_i(6, oldno); cl_assert_equal_i(6, newno); cl_git_pass(git_diff_patch_get_line_in_hunk( &origin, &text, &textlen, &oldno, &newno, patch, 0, 3)); cl_assert_equal_i(GIT_DIFF_LINE_DELETION, (int)origin); cl_git_pass(git_buf_set(&actual, text, textlen)); cl_assert_equal_s("All the world went softly when it walked before my Cities--\n", actual.ptr); cl_assert_equal_i(9, oldno); cl_assert_equal_i(-1, newno); cl_git_pass(git_diff_patch_get_line_in_hunk( &origin, &text, &textlen, &oldno, &newno, patch, 0, 12)); cl_assert_equal_i(GIT_DIFF_LINE_ADDITION, (int)origin); cl_git_pass(git_buf_set(&actual, text, textlen)); cl_assert_equal_s("This is some new text;\n", actual.ptr); cl_assert_equal_i(-1, oldno); cl_assert_equal_i(9, newno); /* check hunk 1 */ cl_git_pass( git_diff_patch_get_hunk(&range, &hdr, &hdrlen, &hunklen, patch, 1)); cl_assert_equal_i(18, (int)hunklen); cl_assert_equal_i(31, (int)range->old_start); cl_assert_equal_i(15, (int)range->old_lines); cl_assert_equal_i(25, (int)range->new_start); cl_assert_equal_i(9, (int)range->new_lines); cl_assert_equal_i(18, (int)git_diff_patch_num_lines_in_hunk(patch, 1)); cl_git_pass(git_diff_patch_get_line_in_hunk( &origin, &text, &textlen, &oldno, &newno, patch, 1, 0)); cl_assert_equal_i(GIT_DIFF_LINE_CONTEXT, (int)origin); cl_git_pass(git_buf_set(&actual, text, textlen)); cl_assert_equal_s("My rulers and their treasure and their unborn populations,\n", actual.ptr); cl_assert_equal_i(31, oldno); cl_assert_equal_i(25, newno); cl_git_pass(git_diff_patch_get_line_in_hunk( &origin, &text, &textlen, &oldno, &newno, patch, 1, 3)); cl_assert_equal_i(GIT_DIFF_LINE_DELETION, (int)origin); cl_git_pass(git_buf_set(&actual, text, textlen)); cl_assert_equal_s("The Daughters of the Palace whom they cherished in my Cities,\n", actual.ptr); cl_assert_equal_i(34, oldno); cl_assert_equal_i(-1, newno); cl_git_pass(git_diff_patch_get_line_in_hunk( &origin, &text, &textlen, &oldno, &newno, patch, 1, 12)); cl_assert_equal_i(GIT_DIFF_LINE_ADDITION, (int)origin); cl_git_pass(git_buf_set(&actual, text, textlen)); cl_assert_equal_s("Another replacement;\n", actual.ptr); cl_assert_equal_i(-1, oldno); cl_assert_equal_i(28, newno); git_diff_patch_free(patch); git_diff_list_free(diff); /* Let's check line numbers when there is no newline */ git_buf_rtrim(&old_content); cl_git_rewritefile("renames/songof7cities.txt", old_content.ptr); cl_git_pass(git_diff_tree_to_workdir(&diff, g_repo, head, &opt)); cl_assert_equal_i(1, (int)git_diff_num_deltas(diff)); cl_git_pass(git_diff_get_patch(&patch, &delta, diff, 0)); cl_assert_equal_i(GIT_DELTA_MODIFIED, (int)delta->status); cl_assert_equal_i(1, (int)git_diff_patch_num_hunks(patch)); /* check hunk 0 */ cl_git_pass( git_diff_patch_get_hunk(&range, &hdr, &hdrlen, &hunklen, patch, 0)); cl_assert_equal_i(6, (int)hunklen); cl_assert_equal_i(46, (int)range->old_start); cl_assert_equal_i(4, (int)range->old_lines); cl_assert_equal_i(46, (int)range->new_start); cl_assert_equal_i(4, (int)range->new_lines); cl_assert_equal_i(6, (int)git_diff_patch_num_lines_in_hunk(patch, 0)); cl_git_pass(git_diff_patch_get_line_in_hunk( &origin, &text, &textlen, &oldno, &newno, patch, 0, 1)); cl_assert_equal_i(GIT_DIFF_LINE_CONTEXT, (int)origin); cl_git_pass(git_buf_set(&actual, text, textlen)); cl_assert_equal_s("And the horses and the chariots fleeing from them as of old!\n", actual.ptr); cl_assert_equal_i(47, oldno); cl_assert_equal_i(47, newno); cl_git_pass(git_diff_patch_get_line_in_hunk( &origin, &text, &textlen, &oldno, &newno, patch, 0, 2)); cl_assert_equal_i(GIT_DIFF_LINE_CONTEXT, (int)origin); cl_git_pass(git_buf_set(&actual, text, textlen)); cl_assert_equal_s("\n", actual.ptr); cl_assert_equal_i(48, oldno); cl_assert_equal_i(48, newno); cl_git_pass(git_diff_patch_get_line_in_hunk( &origin, &text, &textlen, &oldno, &newno, patch, 0, 3)); cl_assert_equal_i(GIT_DIFF_LINE_DELETION, (int)origin); cl_git_pass(git_buf_set(&actual, text, textlen)); cl_assert_equal_s(" -- Rudyard Kipling\n", actual.ptr); cl_assert_equal_i(49, oldno); cl_assert_equal_i(-1, newno); cl_git_pass(git_diff_patch_get_line_in_hunk( &origin, &text, &textlen, &oldno, &newno, patch, 0, 4)); cl_assert_equal_i(GIT_DIFF_LINE_ADDITION, (int)origin); cl_git_pass(git_buf_set(&actual, text, textlen)); cl_assert_equal_s(" -- Rudyard Kipling", actual.ptr); cl_assert_equal_i(-1, oldno); cl_assert_equal_i(49, newno); cl_git_pass(git_diff_patch_get_line_in_hunk( &origin, &text, &textlen, &oldno, &newno, patch, 0, 5)); cl_assert_equal_i(GIT_DIFF_LINE_DEL_EOFNL, (int)origin); cl_git_pass(git_buf_set(&actual, text, textlen)); cl_assert_equal_s("\n\\ No newline at end of file\n", actual.ptr); cl_assert_equal_i(-1, oldno); cl_assert_equal_i(49, newno); git_diff_patch_free(patch); git_diff_list_free(diff); git_buf_free(&actual); git_buf_free(&old_content); git_tree_free(head); git_config_free(cfg); } static void check_single_patch_stats( git_repository *repo, size_t hunks, size_t adds, size_t dels, size_t ctxt, const char *expected) { git_diff_list *diff; git_diff_patch *patch; const git_diff_delta *delta; size_t actual_ctxt, actual_adds, actual_dels; cl_git_pass(git_diff_index_to_workdir(&diff, repo, NULL, NULL)); cl_assert_equal_i(1, (int)git_diff_num_deltas(diff)); cl_git_pass(git_diff_get_patch(&patch, &delta, diff, 0)); cl_assert_equal_i(GIT_DELTA_MODIFIED, (int)delta->status); cl_assert_equal_i((int)hunks, (int)git_diff_patch_num_hunks(patch)); cl_git_pass( git_diff_patch_line_stats( &actual_ctxt, &actual_adds, &actual_dels, patch) ); cl_assert_equal_sz(ctxt, actual_ctxt); cl_assert_equal_sz(adds, actual_adds); cl_assert_equal_sz(dels, actual_dels); if (expected != NULL) { char *text; cl_git_pass(git_diff_patch_to_str(&text, patch)); cl_assert_equal_s(expected, text); git__free(text); } /* walk lines in hunk with basic sanity checks */ for (; hunks > 0; --hunks) { size_t i, max_i; int lastoldno = -1, oldno, lastnewno = -1, newno; char origin; max_i = git_diff_patch_num_lines_in_hunk(patch, hunks - 1); for (i = 0; i < max_i; ++i) { int expected = 1; cl_git_pass(git_diff_patch_get_line_in_hunk( &origin, NULL, NULL, &oldno, &newno, patch, hunks - 1, i)); if (origin == GIT_DIFF_LINE_ADD_EOFNL || origin == GIT_DIFF_LINE_DEL_EOFNL || origin == GIT_DIFF_LINE_CONTEXT_EOFNL) expected = 0; if (oldno >= 0) { if (lastoldno >= 0) cl_assert_equal_i(expected, oldno - lastoldno); lastoldno = oldno; } if (newno >= 0) { if (lastnewno >= 0) cl_assert_equal_i(expected, newno - lastnewno); lastnewno = newno; } } } git_diff_patch_free(patch); git_diff_list_free(diff); } void test_diff_patch__line_counts_with_eofnl(void) { git_config *cfg; git_buf content = GIT_BUF_INIT; const char *end; git_index *index; g_repo = cl_git_sandbox_init("renames"); cl_git_pass(git_config_new(&cfg)); git_repository_set_config(g_repo, cfg); cl_git_pass(git_futils_readbuffer(&content, "renames/songof7cities.txt")); /* remove first line */ end = git_buf_cstr(&content) + git_buf_find(&content, '\n') + 1; git_buf_consume(&content, end); cl_git_rewritefile("renames/songof7cities.txt", content.ptr); check_single_patch_stats(g_repo, 1, 0, 1, 3, NULL); /* remove trailing whitespace */ git_buf_rtrim(&content); cl_git_rewritefile("renames/songof7cities.txt", content.ptr); check_single_patch_stats(g_repo, 2, 1, 2, 6, NULL); /* add trailing whitespace */ cl_git_pass(git_repository_index(&index, g_repo)); cl_git_pass(git_index_add_bypath(index, "songof7cities.txt")); cl_git_pass(git_index_write(index)); git_index_free(index); cl_git_pass(git_buf_putc(&content, '\n')); cl_git_rewritefile("renames/songof7cities.txt", content.ptr); check_single_patch_stats(g_repo, 1, 1, 1, 3, NULL); /* no trailing whitespace as context line */ { /* walk back a couple lines, make space and insert char */ char *scan = content.ptr + content.size; int i; for (i = 0; i < 5; ++i) { for (--scan; scan > content.ptr && *scan != '\n'; --scan) /* seek to prev \n */; } cl_assert(scan > content.ptr); /* overwrite trailing \n with right-shifted content */ memmove(scan + 1, scan, content.size - (scan - content.ptr) - 1); /* insert '#' char into space we created */ scan[1] = '#'; } cl_git_rewritefile("renames/songof7cities.txt", content.ptr); check_single_patch_stats( g_repo, 1, 1, 1, 6, /* below is pasted output of 'git diff' with fn context removed */ "diff --git a/songof7cities.txt b/songof7cities.txt\n" "index 378a7d9..3d0154e 100644\n" "--- a/songof7cities.txt\n" "+++ b/songof7cities.txt\n" "@@ -42,7 +42,7 @@ With peoples undefeated of the dark, enduring blood.\n" " \n" " To the sound of trumpets shall their seed restore my Cities\n" " Wealthy and well-weaponed, that once more may I behold\n" "-All the world go softly when it walks before my Cities,\n" "+#All the world go softly when it walks before my Cities,\n" " And the horses and the chariots fleeing from them as of old!\n" " \n" " -- Rudyard Kipling\n" "\\ No newline at end of file\n"); git_buf_free(&content); git_config_free(cfg); } libgit2-0.19.0/tests-clar/diff/rename.c000066400000000000000000001113661216214232500175470ustar00rootroot00000000000000#include "clar_libgit2.h" #include "diff_helpers.h" #include "buf_text.h" static git_repository *g_repo = NULL; void test_diff_rename__initialize(void) { g_repo = cl_git_sandbox_init("renames"); } void test_diff_rename__cleanup(void) { cl_git_sandbox_cleanup(); } /* * Renames repo has: * * commit 31e47d8c1fa36d7f8d537b96158e3f024de0a9f2 - * serving.txt (25 lines) * sevencities.txt (50 lines) * commit 2bc7f351d20b53f1c72c16c4b036e491c478c49a - * serving.txt -> sixserving.txt (rename, no change, 100% match) * sevencities.txt -> sevencities.txt (no change) * sevencities.txt -> songofseven.txt (copy, no change, 100% match) * commit 1c068dee5790ef1580cfc4cd670915b48d790084 * songofseven.txt -> songofseven.txt (major rewrite, <20% match - split) * sixserving.txt -> sixserving.txt (indentation change) * sixserving.txt -> ikeepsix.txt (copy, add title, >80% match) * sevencities.txt (no change) * commit 19dd32dfb1520a64e5bbaae8dce6ef423dfa2f13 * songofseven.txt -> untimely.txt (rename, convert to crlf) * ikeepsix.txt -> ikeepsix.txt (reorder sections in file) * sixserving.txt -> sixserving.txt (whitespace change - not just indent) * sevencities.txt -> songof7cities.txt (rename, small text changes) */ void test_diff_rename__match_oid(void) { const char *old_sha = "31e47d8c1fa36d7f8d537b96158e3f024de0a9f2"; const char *new_sha = "2bc7f351d20b53f1c72c16c4b036e491c478c49a"; git_tree *old_tree, *new_tree; git_diff_list *diff; git_diff_options diffopts = GIT_DIFF_OPTIONS_INIT; git_diff_find_options opts = GIT_DIFF_FIND_OPTIONS_INIT; diff_expects exp; old_tree = resolve_commit_oid_to_tree(g_repo, old_sha); new_tree = resolve_commit_oid_to_tree(g_repo, new_sha); /* Must pass GIT_DIFF_INCLUDE_UNMODIFIED if you expect to emulate * --find-copies-harder during rename transformion... */ diffopts.flags |= GIT_DIFF_INCLUDE_UNMODIFIED; cl_git_pass(git_diff_tree_to_tree( &diff, g_repo, old_tree, new_tree, &diffopts)); /* git diff --no-renames \ * 31e47d8c1fa36d7f8d537b96158e3f024de0a9f2 \ * 2bc7f351d20b53f1c72c16c4b036e491c478c49a */ memset(&exp, 0, sizeof(exp)); cl_git_pass(git_diff_foreach( diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp)); cl_assert_equal_i(4, exp.files); cl_assert_equal_i(1, exp.file_status[GIT_DELTA_UNMODIFIED]); cl_assert_equal_i(2, exp.file_status[GIT_DELTA_ADDED]); cl_assert_equal_i(1, exp.file_status[GIT_DELTA_DELETED]); /* git diff 31e47d8c1fa36d7f8d537b96158e3f024de0a9f2 \ * 2bc7f351d20b53f1c72c16c4b036e491c478c49a * don't use NULL opts to avoid config `diff.renames` contamination */ opts.flags = GIT_DIFF_FIND_RENAMES; cl_git_pass(git_diff_find_similar(diff, &opts)); memset(&exp, 0, sizeof(exp)); cl_git_pass(git_diff_foreach( diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp)); cl_assert_equal_i(3, exp.files); cl_assert_equal_i(1, exp.file_status[GIT_DELTA_UNMODIFIED]); cl_assert_equal_i(1, exp.file_status[GIT_DELTA_ADDED]); cl_assert_equal_i(1, exp.file_status[GIT_DELTA_RENAMED]); git_diff_list_free(diff); cl_git_pass(git_diff_tree_to_tree( &diff, g_repo, old_tree, new_tree, &diffopts)); /* git diff --find-copies-harder \ * 31e47d8c1fa36d7f8d537b96158e3f024de0a9f2 \ * 2bc7f351d20b53f1c72c16c4b036e491c478c49a */ opts.flags = GIT_DIFF_FIND_COPIES_FROM_UNMODIFIED; cl_git_pass(git_diff_find_similar(diff, &opts)); memset(&exp, 0, sizeof(exp)); cl_git_pass(git_diff_foreach( diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp)); cl_assert_equal_i(3, exp.files); cl_assert_equal_i(1, exp.file_status[GIT_DELTA_UNMODIFIED]); cl_assert_equal_i(1, exp.file_status[GIT_DELTA_COPIED]); cl_assert_equal_i(1, exp.file_status[GIT_DELTA_RENAMED]); git_diff_list_free(diff); git_tree_free(old_tree); git_tree_free(new_tree); } void test_diff_rename__checks_options_version(void) { const char *old_sha = "31e47d8c1fa36d7f8d537b96158e3f024de0a9f2"; const char *new_sha = "2bc7f351d20b53f1c72c16c4b036e491c478c49a"; git_tree *old_tree, *new_tree; git_diff_list *diff; git_diff_options diffopts = GIT_DIFF_OPTIONS_INIT; git_diff_find_options opts = GIT_DIFF_FIND_OPTIONS_INIT; const git_error *err; old_tree = resolve_commit_oid_to_tree(g_repo, old_sha); new_tree = resolve_commit_oid_to_tree(g_repo, new_sha); diffopts.flags |= GIT_DIFF_INCLUDE_UNMODIFIED; cl_git_pass(git_diff_tree_to_tree( &diff, g_repo, old_tree, new_tree, &diffopts)); opts.version = 0; cl_git_fail(git_diff_find_similar(diff, &opts)); err = giterr_last(); cl_assert_equal_i(GITERR_INVALID, err->klass); giterr_clear(); opts.version = 1024; cl_git_fail(git_diff_find_similar(diff, &opts)); err = giterr_last(); cl_assert_equal_i(GITERR_INVALID, err->klass); git_diff_list_free(diff); git_tree_free(old_tree); git_tree_free(new_tree); } void test_diff_rename__not_exact_match(void) { const char *sha0 = "2bc7f351d20b53f1c72c16c4b036e491c478c49a"; const char *sha1 = "1c068dee5790ef1580cfc4cd670915b48d790084"; const char *sha2 = "19dd32dfb1520a64e5bbaae8dce6ef423dfa2f13"; git_tree *old_tree, *new_tree; git_diff_list *diff; git_diff_options diffopts = GIT_DIFF_OPTIONS_INIT; git_diff_find_options opts = GIT_DIFF_FIND_OPTIONS_INIT; diff_expects exp; /* == Changes ===================================================== * songofseven.txt -> songofseven.txt (major rewrite, <20% match - split) * sixserving.txt -> sixserving.txt (indentation change) * sixserving.txt -> ikeepsix.txt (copy, add title, >80% match) * sevencities.txt (no change) */ old_tree = resolve_commit_oid_to_tree(g_repo, sha0); new_tree = resolve_commit_oid_to_tree(g_repo, sha1); /* Must pass GIT_DIFF_INCLUDE_UNMODIFIED if you expect to emulate * --find-copies-harder during rename transformion... */ diffopts.flags |= GIT_DIFF_INCLUDE_UNMODIFIED; cl_git_pass(git_diff_tree_to_tree( &diff, g_repo, old_tree, new_tree, &diffopts)); /* git diff --no-renames \ * 2bc7f351d20b53f1c72c16c4b036e491c478c49a \ * 1c068dee5790ef1580cfc4cd670915b48d790084 */ memset(&exp, 0, sizeof(exp)); cl_git_pass(git_diff_foreach( diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp)); cl_assert_equal_i(4, exp.files); cl_assert_equal_i(1, exp.file_status[GIT_DELTA_UNMODIFIED]); cl_assert_equal_i(2, exp.file_status[GIT_DELTA_MODIFIED]); cl_assert_equal_i(1, exp.file_status[GIT_DELTA_ADDED]); /* git diff -M 2bc7f351d20b53f1c72c16c4b036e491c478c49a \ * 1c068dee5790ef1580cfc4cd670915b48d790084 * * must not pass NULL for opts because it will pick up environment * values for "diff.renames" and test won't be consistent. */ opts.flags = GIT_DIFF_FIND_RENAMES; cl_git_pass(git_diff_find_similar(diff, &opts)); memset(&exp, 0, sizeof(exp)); cl_git_pass(git_diff_foreach( diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp)); cl_assert_equal_i(4, exp.files); cl_assert_equal_i(1, exp.file_status[GIT_DELTA_UNMODIFIED]); cl_assert_equal_i(2, exp.file_status[GIT_DELTA_MODIFIED]); cl_assert_equal_i(1, exp.file_status[GIT_DELTA_ADDED]); git_diff_list_free(diff); /* git diff -M -C \ * 2bc7f351d20b53f1c72c16c4b036e491c478c49a \ * 1c068dee5790ef1580cfc4cd670915b48d790084 */ cl_git_pass(git_diff_tree_to_tree( &diff, g_repo, old_tree, new_tree, &diffopts)); opts.flags = GIT_DIFF_FIND_RENAMES | GIT_DIFF_FIND_COPIES; cl_git_pass(git_diff_find_similar(diff, &opts)); memset(&exp, 0, sizeof(exp)); cl_git_pass(git_diff_foreach( diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp)); cl_assert_equal_i(4, exp.files); cl_assert_equal_i(1, exp.file_status[GIT_DELTA_UNMODIFIED]); cl_assert_equal_i(2, exp.file_status[GIT_DELTA_MODIFIED]); cl_assert_equal_i(1, exp.file_status[GIT_DELTA_COPIED]); git_diff_list_free(diff); /* git diff -M -C --find-copies-harder --break-rewrites \ * 2bc7f351d20b53f1c72c16c4b036e491c478c49a \ * 1c068dee5790ef1580cfc4cd670915b48d790084 */ cl_git_pass(git_diff_tree_to_tree( &diff, g_repo, old_tree, new_tree, &diffopts)); opts.flags = GIT_DIFF_FIND_ALL; cl_git_pass(git_diff_find_similar(diff, &opts)); memset(&exp, 0, sizeof(exp)); cl_git_pass(git_diff_foreach( diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp)); cl_assert_equal_i(5, exp.files); cl_assert_equal_i(1, exp.file_status[GIT_DELTA_UNMODIFIED]); cl_assert_equal_i(1, exp.file_status[GIT_DELTA_MODIFIED]); cl_assert_equal_i(1, exp.file_status[GIT_DELTA_ADDED]); cl_assert_equal_i(1, exp.file_status[GIT_DELTA_DELETED]); cl_assert_equal_i(1, exp.file_status[GIT_DELTA_COPIED]); git_diff_list_free(diff); /* == Changes ===================================================== * songofseven.txt -> untimely.txt (rename, convert to crlf) * ikeepsix.txt -> ikeepsix.txt (reorder sections in file) * sixserving.txt -> sixserving.txt (whitespace - not just indent) * sevencities.txt -> songof7cities.txt (rename, small text changes) */ git_tree_free(old_tree); old_tree = new_tree; new_tree = resolve_commit_oid_to_tree(g_repo, sha2); cl_git_pass(git_diff_tree_to_tree( &diff, g_repo, old_tree, new_tree, &diffopts)); /* git diff --no-renames \ * 1c068dee5790ef1580cfc4cd670915b48d790084 \ * 19dd32dfb1520a64e5bbaae8dce6ef423dfa2f13 */ memset(&exp, 0, sizeof(exp)); cl_git_pass(git_diff_foreach( diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp)); cl_assert_equal_i(6, exp.files); cl_assert_equal_i(2, exp.file_status[GIT_DELTA_MODIFIED]); cl_assert_equal_i(2, exp.file_status[GIT_DELTA_ADDED]); cl_assert_equal_i(2, exp.file_status[GIT_DELTA_DELETED]); git_diff_list_free(diff); /* git diff -M -C \ * 1c068dee5790ef1580cfc4cd670915b48d790084 \ * 19dd32dfb1520a64e5bbaae8dce6ef423dfa2f13 */ cl_git_pass(git_diff_tree_to_tree( &diff, g_repo, old_tree, new_tree, &diffopts)); opts.flags = GIT_DIFF_FIND_RENAMES | GIT_DIFF_FIND_COPIES; cl_git_pass(git_diff_find_similar(diff, &opts)); memset(&exp, 0, sizeof(exp)); cl_git_pass(git_diff_foreach( diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp)); cl_assert_equal_i(4, exp.files); cl_assert_equal_i(2, exp.file_status[GIT_DELTA_MODIFIED]); cl_assert_equal_i(2, exp.file_status[GIT_DELTA_RENAMED]); git_diff_list_free(diff); /* git diff -M -C --find-copies-harder --break-rewrites \ * 1c068dee5790ef1580cfc4cd670915b48d790084 \ * 19dd32dfb1520a64e5bbaae8dce6ef423dfa2f13 * with libgit2 default similarity comparison... */ cl_git_pass(git_diff_tree_to_tree( &diff, g_repo, old_tree, new_tree, &diffopts)); opts.flags = GIT_DIFF_FIND_ALL; cl_git_pass(git_diff_find_similar(diff, &opts)); /* the default match algorithm is going to find the internal * whitespace differences in the lines of sixserving.txt to be * significant enough that this will decide to split it into * an ADD and a DELETE */ memset(&exp, 0, sizeof(exp)); cl_git_pass(git_diff_foreach( diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp)); cl_assert_equal_i(5, exp.files); cl_assert_equal_i(1, exp.file_status[GIT_DELTA_MODIFIED]); cl_assert_equal_i(1, exp.file_status[GIT_DELTA_ADDED]); cl_assert_equal_i(1, exp.file_status[GIT_DELTA_DELETED]); cl_assert_equal_i(2, exp.file_status[GIT_DELTA_RENAMED]); git_diff_list_free(diff); /* git diff -M -C --find-copies-harder --break-rewrites \ * 1c068dee5790ef1580cfc4cd670915b48d790084 \ * 19dd32dfb1520a64e5bbaae8dce6ef423dfa2f13 * with ignore_space whitespace comparision */ cl_git_pass(git_diff_tree_to_tree( &diff, g_repo, old_tree, new_tree, &diffopts)); opts.flags = GIT_DIFF_FIND_ALL | GIT_DIFF_FIND_IGNORE_WHITESPACE; cl_git_pass(git_diff_find_similar(diff, &opts)); /* Ignoring whitespace, this should no longer split sixserver.txt */ memset(&exp, 0, sizeof(exp)); cl_git_pass(git_diff_foreach( diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp)); cl_assert_equal_i(4, exp.files); cl_assert_equal_i(2, exp.file_status[GIT_DELTA_MODIFIED]); cl_assert_equal_i(2, exp.file_status[GIT_DELTA_RENAMED]); git_diff_list_free(diff); git_tree_free(old_tree); git_tree_free(new_tree); } void test_diff_rename__handles_small_files(void) { const char *tree_sha = "2bc7f351d20b53f1c72c16c4b036e491c478c49a"; git_index *index; git_tree *tree; git_diff_list *diff; git_diff_options diffopts = GIT_DIFF_OPTIONS_INIT; git_diff_find_options opts = GIT_DIFF_FIND_OPTIONS_INIT; cl_git_pass(git_repository_index(&index, g_repo)); tree = resolve_commit_oid_to_tree(g_repo, tree_sha); cl_git_rewritefile("renames/songof7cities.txt", "single line\n"); cl_git_pass(git_index_add_bypath(index, "songof7cities.txt")); cl_git_rewritefile("renames/untimely.txt", "untimely\n"); cl_git_pass(git_index_add_bypath(index, "untimely.txt")); /* Tests that we can invoke find_similar on small files * and that the GIT_EBUFS (too small) error code is not * propagated to the caller. */ cl_git_pass(git_diff_tree_to_index(&diff, g_repo, tree, index, &diffopts)); opts.flags = GIT_DIFF_FIND_RENAMES | GIT_DIFF_FIND_COPIES | GIT_DIFF_FIND_AND_BREAK_REWRITES; cl_git_pass(git_diff_find_similar(diff, &opts)); git_diff_list_free(diff); git_tree_free(tree); git_index_free(index); } void test_diff_rename__working_directory_changes(void) { const char *sha0 = "2bc7f351d20b53f1c72c16c4b036e491c478c49a"; const char *blobsha = "66311f5cfbe7836c27510a3ba2f43e282e2c8bba"; git_oid id; git_tree *tree; git_blob *blob; git_diff_list *diff; git_diff_options diffopts = GIT_DIFF_OPTIONS_INIT; git_diff_find_options opts = GIT_DIFF_FIND_OPTIONS_INIT; diff_expects exp; git_buf old_content = GIT_BUF_INIT, content = GIT_BUF_INIT;; tree = resolve_commit_oid_to_tree(g_repo, sha0); diffopts.flags |= GIT_DIFF_INCLUDE_UNMODIFIED | GIT_DIFF_INCLUDE_UNTRACKED; /* $ git cat-file -p 2bc7f351d20b53f1c72c16c4b036e491c478c49a^{tree} 100644 blob 66311f5cfbe7836c27510a3ba2f43e282e2c8bba sevencities.txt 100644 blob ad0a8e55a104ac54a8a29ed4b84b49e76837a113 sixserving.txt 100644 blob 66311f5cfbe7836c27510a3ba2f43e282e2c8bba songofseven.txt $ for f in *.txt; do echo `git hash-object -t blob $f` $f done eaf4a3e3bfe68585e90cada20736ace491cd100b ikeepsix.txt f90d4fc20ecddf21eebe6a37e9225d244339d2b5 sixserving.txt 4210ffd5c390b21dd5483375e75288dea9ede512 songof7cities.txt 9a69d960ae94b060f56c2a8702545e2bb1abb935 untimely.txt */ cl_git_pass(git_diff_tree_to_workdir(&diff, g_repo, tree, &diffopts)); /* git diff --no-renames 2bc7f351d20b53f1c72c16c4b036e491c478c49a */ memset(&exp, 0, sizeof(exp)); cl_git_pass(git_diff_foreach( diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp)); cl_assert_equal_i(6, exp.files); cl_assert_equal_i(1, exp.file_status[GIT_DELTA_MODIFIED]); cl_assert_equal_i(2, exp.file_status[GIT_DELTA_DELETED]); cl_assert_equal_i(3, exp.file_status[GIT_DELTA_UNTRACKED]); /* git diff -M 2bc7f351d20b53f1c72c16c4b036e491c478c49a */ opts.flags = GIT_DIFF_FIND_ALL; cl_git_pass(git_diff_find_similar(diff, &opts)); memset(&exp, 0, sizeof(exp)); cl_git_pass(git_diff_foreach( diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp)); cl_assert_equal_i(5, exp.files); cl_assert_equal_i(2, exp.file_status[GIT_DELTA_RENAMED]); cl_assert_equal_i(1, exp.file_status[GIT_DELTA_DELETED]); cl_assert_equal_i(2, exp.file_status[GIT_DELTA_UNTRACKED]); git_diff_list_free(diff); /* rewrite files in the working directory with / without CRLF changes */ cl_git_pass( git_futils_readbuffer(&old_content, "renames/songof7cities.txt")); cl_git_pass( git_buf_text_lf_to_crlf(&content, &old_content)); cl_git_pass( git_futils_writebuffer(&content, "renames/songof7cities.txt", 0, 0)); cl_git_pass(git_diff_tree_to_workdir(&diff, g_repo, tree, &diffopts)); /* git diff -M 2bc7f351d20b53f1c72c16c4b036e491c478c49a */ opts.flags = GIT_DIFF_FIND_ALL; cl_git_pass(git_diff_find_similar(diff, &opts)); memset(&exp, 0, sizeof(exp)); cl_git_pass(git_diff_foreach( diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp)); cl_assert_equal_i(5, exp.files); cl_assert_equal_i(2, exp.file_status[GIT_DELTA_RENAMED]); cl_assert_equal_i(1, exp.file_status[GIT_DELTA_DELETED]); cl_assert_equal_i(2, exp.file_status[GIT_DELTA_UNTRACKED]); git_diff_list_free(diff); /* try a different whitespace option */ cl_git_pass(git_diff_tree_to_workdir(&diff, g_repo, tree, &diffopts)); opts.flags = GIT_DIFF_FIND_ALL | GIT_DIFF_FIND_DONT_IGNORE_WHITESPACE; cl_git_pass(git_diff_find_similar(diff, &opts)); memset(&exp, 0, sizeof(exp)); cl_git_pass(git_diff_foreach( diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp)); cl_assert_equal_i(6, exp.files); cl_assert_equal_i(1, exp.file_status[GIT_DELTA_RENAMED]); cl_assert_equal_i(2, exp.file_status[GIT_DELTA_DELETED]); cl_assert_equal_i(3, exp.file_status[GIT_DELTA_UNTRACKED]); git_diff_list_free(diff); /* try a different matching option */ cl_git_pass(git_diff_tree_to_workdir(&diff, g_repo, tree, &diffopts)); opts.flags = GIT_DIFF_FIND_ALL | GIT_DIFF_FIND_EXACT_MATCH_ONLY; cl_git_pass(git_diff_find_similar(diff, &opts)); memset(&exp, 0, sizeof(exp)); cl_git_pass(git_diff_foreach( diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp)); cl_assert_equal_i(6, exp.files); cl_assert_equal_i(1, exp.file_status[GIT_DELTA_MODIFIED]); cl_assert_equal_i(3, exp.file_status[GIT_DELTA_UNTRACKED]); cl_assert_equal_i(2, exp.file_status[GIT_DELTA_DELETED]); git_diff_list_free(diff); /* again with exact match blob */ cl_git_pass(git_oid_fromstr(&id, blobsha)); cl_git_pass(git_blob_lookup(&blob, g_repo, &id)); cl_git_pass(git_buf_set( &content, git_blob_rawcontent(blob), git_blob_rawsize(blob))); cl_git_rewritefile("renames/songof7cities.txt", content.ptr); git_blob_free(blob); cl_git_pass(git_diff_tree_to_workdir(&diff, g_repo, tree, &diffopts)); opts.flags = GIT_DIFF_FIND_ALL | GIT_DIFF_FIND_EXACT_MATCH_ONLY; cl_git_pass(git_diff_find_similar(diff, &opts)); /* fprintf(stderr, "\n\n"); diff_print_raw(stderr, diff); */ memset(&exp, 0, sizeof(exp)); cl_git_pass(git_diff_foreach( diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp)); cl_assert_equal_i(5, exp.files); cl_assert_equal_i(1, exp.file_status[GIT_DELTA_MODIFIED]); cl_assert_equal_i(1, exp.file_status[GIT_DELTA_DELETED]); cl_assert_equal_i(1, exp.file_status[GIT_DELTA_RENAMED]); cl_assert_equal_i(2, exp.file_status[GIT_DELTA_UNTRACKED]); git_diff_list_free(diff); git_tree_free(tree); git_buf_free(&content); git_buf_free(&old_content); } void test_diff_rename__patch(void) { const char *sha0 = "2bc7f351d20b53f1c72c16c4b036e491c478c49a"; const char *sha1 = "1c068dee5790ef1580cfc4cd670915b48d790084"; git_tree *old_tree, *new_tree; git_diff_list *diff; git_diff_options diffopts = GIT_DIFF_OPTIONS_INIT; git_diff_find_options opts = GIT_DIFF_FIND_OPTIONS_INIT; git_diff_patch *patch; const git_diff_delta *delta; char *text; const char *expected = "diff --git a/sixserving.txt b/ikeepsix.txt\nindex ad0a8e5..36020db 100644\n--- a/sixserving.txt\n+++ b/ikeepsix.txt\n@@ -1,3 +1,6 @@\n+I Keep Six Honest Serving-Men\n+=============================\n+\n I KEEP six honest serving-men\n (They taught me all I knew);\n Their names are What and Why and When\n@@ -21,4 +24,4 @@ She sends'em abroad on her own affairs,\n One million Hows, two million Wheres,\n And seven million Whys!\n \n- -- Rudyard Kipling\n+ -- Rudyard Kipling\n"; old_tree = resolve_commit_oid_to_tree(g_repo, sha0); new_tree = resolve_commit_oid_to_tree(g_repo, sha1); diffopts.flags |= GIT_DIFF_INCLUDE_UNMODIFIED; cl_git_pass(git_diff_tree_to_tree( &diff, g_repo, old_tree, new_tree, &diffopts)); opts.flags = GIT_DIFF_FIND_RENAMES | GIT_DIFF_FIND_COPIES; cl_git_pass(git_diff_find_similar(diff, &opts)); /* == Changes ===================================================== * sixserving.txt -> ikeepsix.txt (copy, add title, >80% match) * sevencities.txt (no change) * sixserving.txt -> sixserving.txt (indentation change) * songofseven.txt -> songofseven.txt (major rewrite, <20% match - split) */ cl_assert_equal_i(4, (int)git_diff_num_deltas(diff)); cl_git_pass(git_diff_get_patch(&patch, &delta, diff, 0)); cl_assert_equal_i(GIT_DELTA_COPIED, (int)delta->status); cl_git_pass(git_diff_patch_to_str(&text, patch)); cl_assert_equal_s(expected, text); git__free(text); git_diff_patch_free(patch); cl_git_pass(git_diff_get_patch(NULL, &delta, diff, 1)); cl_assert_equal_i(GIT_DELTA_UNMODIFIED, (int)delta->status); cl_git_pass(git_diff_get_patch(NULL, &delta, diff, 2)); cl_assert_equal_i(GIT_DELTA_MODIFIED, (int)delta->status); cl_git_pass(git_diff_get_patch(NULL, &delta, diff, 3)); cl_assert_equal_i(GIT_DELTA_MODIFIED, (int)delta->status); git_diff_list_free(diff); git_tree_free(old_tree); git_tree_free(new_tree); } void test_diff_rename__file_exchange(void) { git_buf c1 = GIT_BUF_INIT, c2 = GIT_BUF_INIT; git_index *index; git_tree *tree; git_diff_list *diff; git_diff_options diffopts = GIT_DIFF_OPTIONS_INIT; git_diff_find_options opts = GIT_DIFF_FIND_OPTIONS_INIT; diff_expects exp; cl_git_pass(git_futils_readbuffer(&c1, "renames/untimely.txt")); cl_git_pass(git_futils_readbuffer(&c2, "renames/songof7cities.txt")); cl_git_pass(git_futils_writebuffer(&c1, "renames/songof7cities.txt", 0, 0)); cl_git_pass(git_futils_writebuffer(&c2, "renames/untimely.txt", 0, 0)); cl_git_pass( git_revparse_single((git_object **)&tree, g_repo, "HEAD^{tree}")); cl_git_pass(git_repository_index(&index, g_repo)); cl_git_pass(git_index_read_tree(index, tree)); cl_git_pass(git_index_add_bypath(index, "songof7cities.txt")); cl_git_pass(git_index_add_bypath(index, "untimely.txt")); cl_git_pass(git_diff_tree_to_index(&diff, g_repo, tree, index, &diffopts)); memset(&exp, 0, sizeof(exp)); cl_git_pass(git_diff_foreach( diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp)); cl_assert_equal_i(2, exp.files); cl_assert_equal_i(2, exp.file_status[GIT_DELTA_MODIFIED]); opts.flags = GIT_DIFF_FIND_ALL; cl_git_pass(git_diff_find_similar(diff, &opts)); memset(&exp, 0, sizeof(exp)); cl_git_pass(git_diff_foreach( diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp)); cl_assert_equal_i(2, exp.files); cl_assert_equal_i(2, exp.file_status[GIT_DELTA_RENAMED]); git_diff_list_free(diff); git_tree_free(tree); git_index_free(index); git_buf_free(&c1); git_buf_free(&c2); } void test_diff_rename__file_exchange_three(void) { git_buf c1 = GIT_BUF_INIT, c2 = GIT_BUF_INIT, c3 = GIT_BUF_INIT; git_index *index; git_tree *tree; git_diff_list *diff; git_diff_options diffopts = GIT_DIFF_OPTIONS_INIT; git_diff_find_options opts = GIT_DIFF_FIND_OPTIONS_INIT; diff_expects exp; cl_git_pass(git_futils_readbuffer(&c1, "renames/untimely.txt")); cl_git_pass(git_futils_readbuffer(&c2, "renames/songof7cities.txt")); cl_git_pass(git_futils_readbuffer(&c3, "renames/ikeepsix.txt")); cl_git_pass(git_futils_writebuffer(&c1, "renames/ikeepsix.txt", 0, 0)); cl_git_pass(git_futils_writebuffer(&c2, "renames/untimely.txt", 0, 0)); cl_git_pass(git_futils_writebuffer(&c3, "renames/songof7cities.txt", 0, 0)); cl_git_pass( git_revparse_single((git_object **)&tree, g_repo, "HEAD^{tree}")); cl_git_pass(git_repository_index(&index, g_repo)); cl_git_pass(git_index_read_tree(index, tree)); cl_git_pass(git_index_add_bypath(index, "songof7cities.txt")); cl_git_pass(git_index_add_bypath(index, "untimely.txt")); cl_git_pass(git_index_add_bypath(index, "ikeepsix.txt")); cl_git_pass(git_diff_tree_to_index(&diff, g_repo, tree, index, &diffopts)); memset(&exp, 0, sizeof(exp)); cl_git_pass(git_diff_foreach( diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp)); cl_assert_equal_i(3, exp.files); cl_assert_equal_i(3, exp.file_status[GIT_DELTA_MODIFIED]); opts.flags = GIT_DIFF_FIND_ALL; cl_git_pass(git_diff_find_similar(diff, &opts)); memset(&exp, 0, sizeof(exp)); cl_git_pass(git_diff_foreach( diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp)); cl_assert_equal_i(3, exp.files); cl_assert_equal_i(3, exp.file_status[GIT_DELTA_RENAMED]); git_diff_list_free(diff); git_tree_free(tree); git_index_free(index); git_buf_free(&c1); git_buf_free(&c2); git_buf_free(&c3); } void test_diff_rename__file_partial_exchange(void) { git_buf c1 = GIT_BUF_INIT, c2 = GIT_BUF_INIT; git_index *index; git_tree *tree; git_diff_list *diff; git_diff_options diffopts = GIT_DIFF_OPTIONS_INIT; git_diff_find_options opts = GIT_DIFF_FIND_OPTIONS_INIT; diff_expects exp; int i; cl_git_pass(git_futils_readbuffer(&c1, "renames/untimely.txt")); cl_git_pass(git_futils_writebuffer(&c1, "renames/songof7cities.txt", 0, 0)); for (i = 0; i < 100; ++i) cl_git_pass(git_buf_puts(&c2, "this is not the content you are looking for\n")); cl_git_pass(git_futils_writebuffer(&c2, "renames/untimely.txt", 0, 0)); cl_git_pass( git_revparse_single((git_object **)&tree, g_repo, "HEAD^{tree}")); cl_git_pass(git_repository_index(&index, g_repo)); cl_git_pass(git_index_read_tree(index, tree)); cl_git_pass(git_index_add_bypath(index, "songof7cities.txt")); cl_git_pass(git_index_add_bypath(index, "untimely.txt")); cl_git_pass(git_diff_tree_to_index(&diff, g_repo, tree, index, &diffopts)); memset(&exp, 0, sizeof(exp)); cl_git_pass(git_diff_foreach( diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp)); cl_assert_equal_i(2, exp.files); cl_assert_equal_i(2, exp.file_status[GIT_DELTA_MODIFIED]); opts.flags = GIT_DIFF_FIND_ALL; cl_git_pass(git_diff_find_similar(diff, &opts)); memset(&exp, 0, sizeof(exp)); cl_git_pass(git_diff_foreach( diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp)); cl_assert_equal_i(3, exp.files); cl_assert_equal_i(1, exp.file_status[GIT_DELTA_RENAMED]); cl_assert_equal_i(1, exp.file_status[GIT_DELTA_ADDED]); cl_assert_equal_i(1, exp.file_status[GIT_DELTA_DELETED]); git_diff_list_free(diff); git_tree_free(tree); git_index_free(index); git_buf_free(&c1); git_buf_free(&c2); } void test_diff_rename__rename_and_copy_from_same_source(void) { git_buf c1 = GIT_BUF_INIT, c2 = GIT_BUF_INIT; git_index *index; git_tree *tree; git_diff_list *diff; git_diff_options diffopts = GIT_DIFF_OPTIONS_INIT; git_diff_find_options opts = GIT_DIFF_FIND_OPTIONS_INIT; diff_expects exp; /* put the first 2/3 of file into one new place * and the second 2/3 of file into another new place */ cl_git_pass(git_futils_readbuffer(&c1, "renames/songof7cities.txt")); cl_git_pass(git_buf_set(&c2, c1.ptr, c1.size)); git_buf_truncate(&c1, c1.size * 2 / 3); git_buf_consume(&c2, ((char *)c2.ptr) + (c2.size / 3)); cl_git_pass(git_futils_writebuffer(&c1, "renames/song_a.txt", 0, 0)); cl_git_pass(git_futils_writebuffer(&c2, "renames/song_b.txt", 0, 0)); cl_git_pass( git_revparse_single((git_object **)&tree, g_repo, "HEAD^{tree}")); cl_git_pass(git_repository_index(&index, g_repo)); cl_git_pass(git_index_read_tree(index, tree)); cl_git_pass(git_index_add_bypath(index, "song_a.txt")); cl_git_pass(git_index_add_bypath(index, "song_b.txt")); diffopts.flags = GIT_DIFF_INCLUDE_UNMODIFIED; cl_git_pass(git_diff_tree_to_index(&diff, g_repo, tree, index, &diffopts)); memset(&exp, 0, sizeof(exp)); cl_git_pass(git_diff_foreach( diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp)); cl_assert_equal_i(6, exp.files); cl_assert_equal_i(2, exp.file_status[GIT_DELTA_ADDED]); cl_assert_equal_i(4, exp.file_status[GIT_DELTA_UNMODIFIED]); opts.flags = GIT_DIFF_FIND_ALL; cl_git_pass(git_diff_find_similar(diff, &opts)); memset(&exp, 0, sizeof(exp)); cl_git_pass(git_diff_foreach( diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp)); cl_assert_equal_i(6, exp.files); cl_assert_equal_i(2, exp.file_status[GIT_DELTA_COPIED]); cl_assert_equal_i(4, exp.file_status[GIT_DELTA_UNMODIFIED]); git_diff_list_free(diff); git_tree_free(tree); git_index_free(index); git_buf_free(&c1); git_buf_free(&c2); } void test_diff_rename__from_deleted_to_split(void) { git_buf c1 = GIT_BUF_INIT; git_index *index; git_tree *tree; git_diff_list *diff; git_diff_options diffopts = GIT_DIFF_OPTIONS_INIT; git_diff_find_options opts = GIT_DIFF_FIND_OPTIONS_INIT; diff_expects exp; /* old file is missing, new file is actually old file renamed */ cl_git_pass(git_futils_readbuffer(&c1, "renames/songof7cities.txt")); cl_git_pass(git_futils_writebuffer(&c1, "renames/untimely.txt", 0, 0)); cl_git_pass( git_revparse_single((git_object **)&tree, g_repo, "HEAD^{tree}")); cl_git_pass(git_repository_index(&index, g_repo)); cl_git_pass(git_index_read_tree(index, tree)); cl_git_pass(git_index_remove_bypath(index, "songof7cities.txt")); cl_git_pass(git_index_add_bypath(index, "untimely.txt")); diffopts.flags = GIT_DIFF_INCLUDE_UNMODIFIED; cl_git_pass(git_diff_tree_to_index(&diff, g_repo, tree, index, &diffopts)); memset(&exp, 0, sizeof(exp)); cl_git_pass(git_diff_foreach( diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp)); cl_assert_equal_i(4, exp.files); cl_assert_equal_i(1, exp.file_status[GIT_DELTA_DELETED]); cl_assert_equal_i(1, exp.file_status[GIT_DELTA_MODIFIED]); cl_assert_equal_i(2, exp.file_status[GIT_DELTA_UNMODIFIED]); opts.flags = GIT_DIFF_FIND_ALL; cl_git_pass(git_diff_find_similar(diff, &opts)); memset(&exp, 0, sizeof(exp)); cl_git_pass(git_diff_foreach( diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp)); cl_assert_equal_i(4, exp.files); cl_assert_equal_i(1, exp.file_status[GIT_DELTA_DELETED]); cl_assert_equal_i(1, exp.file_status[GIT_DELTA_RENAMED]); cl_assert_equal_i(2, exp.file_status[GIT_DELTA_UNMODIFIED]); git_diff_list_free(diff); git_tree_free(tree); git_index_free(index); git_buf_free(&c1); } struct rename_expected { size_t len; const char **sources; const char **targets; size_t idx; }; int test_names_expected(const git_diff_delta *delta, float progress, void *p) { struct rename_expected *expected = p; GIT_UNUSED(progress); cl_assert(expected->idx < expected->len); cl_assert_equal_i(delta->status, GIT_DELTA_RENAMED); cl_assert(git__strcmp(expected->sources[expected->idx], delta->old_file.path) == 0); cl_assert(git__strcmp(expected->targets[expected->idx], delta->new_file.path) == 0); expected->idx++; return 0; } void test_diff_rename__rejected_match_can_match_others(void) { git_reference *head, *selfsimilar; git_index *index; git_tree *tree; git_checkout_opts opts = GIT_CHECKOUT_OPTS_INIT; git_diff_list *diff; git_diff_options diffopts = GIT_DIFF_OPTIONS_INIT; git_diff_find_options findopts = GIT_DIFF_FIND_OPTIONS_INIT; git_buf one = GIT_BUF_INIT, two = GIT_BUF_INIT; const char *sources[] = { "Class1.cs", "Class2.cs" }; const char *targets[] = { "ClassA.cs", "ClassB.cs" }; struct rename_expected expect = { 2, sources, targets }; char *ptr; opts.checkout_strategy = GIT_CHECKOUT_FORCE; cl_git_pass(git_reference_lookup(&head, g_repo, "HEAD")); cl_git_pass(git_reference_symbolic_set_target( &selfsimilar, head, "refs/heads/renames_similar")); cl_git_pass(git_checkout_head(g_repo, &opts)); cl_git_pass(git_repository_index(&index, g_repo)); cl_git_pass(git_futils_readbuffer(&one, "renames/Class1.cs")); cl_git_pass(git_futils_readbuffer(&two, "renames/Class2.cs")); cl_git_pass(p_unlink("renames/Class1.cs")); cl_git_pass(p_unlink("renames/Class2.cs")); cl_git_pass(git_index_remove_bypath(index, "Class1.cs")); cl_git_pass(git_index_remove_bypath(index, "Class2.cs")); cl_assert(ptr = strstr(one.ptr, "Class1")); ptr[5] = 'A'; cl_assert(ptr = strstr(two.ptr, "Class2")); ptr[5] = 'B'; cl_git_pass( git_futils_writebuffer(&one, "renames/ClassA.cs", O_RDWR|O_CREAT, 0777)); cl_git_pass( git_futils_writebuffer(&two, "renames/ClassB.cs", O_RDWR|O_CREAT, 0777)); cl_git_pass(git_index_add_bypath(index, "ClassA.cs")); cl_git_pass(git_index_add_bypath(index, "ClassB.cs")); cl_git_pass(git_index_write(index)); cl_git_pass( git_revparse_single((git_object **)&tree, g_repo, "HEAD^{tree}")); cl_git_pass( git_diff_tree_to_index(&diff, g_repo, tree, index, &diffopts)); cl_git_pass(git_diff_find_similar(diff, &findopts)); cl_git_pass( git_diff_foreach(diff, test_names_expected, NULL, NULL, &expect)); git_diff_list_free(diff); git_tree_free(tree); git_index_free(index); git_reference_free(head); git_reference_free(selfsimilar); git_buf_free(&one); git_buf_free(&two); } static void write_similarity_file_two(const char *filename, size_t b_lines) { git_buf contents = GIT_BUF_INIT; size_t i; for (i = 0; i < b_lines; i++) git_buf_printf(&contents, "%02d - bbbbb\r\n", (int)(i+1)); for (i = b_lines; i < 50; i++) git_buf_printf(&contents, "%02d - aaaaa%s", (int)(i+1), (i == 49 ? "" : "\r\n")); cl_git_pass( git_futils_writebuffer(&contents, filename, O_RDWR|O_CREAT, 0777)); git_buf_free(&contents); } void test_diff_rename__rejected_match_can_match_others_two(void) { git_reference *head, *selfsimilar; git_index *index; git_tree *tree; git_checkout_opts opts = GIT_CHECKOUT_OPTS_INIT; git_diff_list *diff; git_diff_options diffopts = GIT_DIFF_OPTIONS_INIT; git_diff_find_options findopts = GIT_DIFF_FIND_OPTIONS_INIT; const char *sources[] = { "a.txt", "b.txt" }; const char *targets[] = { "c.txt", "d.txt" }; struct rename_expected expect = { 2, sources, targets }; opts.checkout_strategy = GIT_CHECKOUT_FORCE; cl_git_pass(git_reference_lookup(&head, g_repo, "HEAD")); cl_git_pass(git_reference_symbolic_set_target( &selfsimilar, head, "refs/heads/renames_similar_two")); cl_git_pass(git_checkout_head(g_repo, &opts)); cl_git_pass(git_repository_index(&index, g_repo)); cl_git_pass(p_unlink("renames/a.txt")); cl_git_pass(p_unlink("renames/b.txt")); cl_git_pass(git_index_remove_bypath(index, "a.txt")); cl_git_pass(git_index_remove_bypath(index, "b.txt")); write_similarity_file_two("renames/c.txt", 7); write_similarity_file_two("renames/d.txt", 8); cl_git_pass(git_index_add_bypath(index, "c.txt")); cl_git_pass(git_index_add_bypath(index, "d.txt")); cl_git_pass(git_index_write(index)); cl_git_pass( git_revparse_single((git_object **)&tree, g_repo, "HEAD^{tree}")); cl_git_pass( git_diff_tree_to_index(&diff, g_repo, tree, index, &diffopts)); cl_git_pass(git_diff_find_similar(diff, &findopts)); cl_git_pass( git_diff_foreach(diff, test_names_expected, NULL, NULL, &expect)); cl_assert(expect.idx > 0); git_diff_list_free(diff); git_tree_free(tree); git_index_free(index); git_reference_free(head); git_reference_free(selfsimilar); } void test_diff_rename__case_changes_are_split(void) { git_index *index; git_tree *tree; git_diff_list *diff = NULL; diff_expects exp; git_diff_find_options opts = GIT_DIFF_FIND_OPTIONS_INIT; cl_git_pass(git_repository_index(&index, g_repo)); cl_git_pass( git_revparse_single((git_object **)&tree, g_repo, "HEAD^{tree}")); cl_git_pass(p_rename("renames/ikeepsix.txt", "renames/IKEEPSIX.txt")); cl_git_pass(git_index_remove_bypath(index, "ikeepsix.txt")); cl_git_pass(git_index_add_bypath(index, "IKEEPSIX.txt")); cl_git_pass(git_index_write(index)); cl_git_pass(git_diff_tree_to_index(&diff, g_repo, tree, index, NULL)); memset(&exp, 0, sizeof(exp)); cl_git_pass(git_diff_foreach( diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp)); cl_assert_equal_i(2, exp.files); cl_assert_equal_i(1, exp.file_status[GIT_DELTA_DELETED]); cl_assert_equal_i(1, exp.file_status[GIT_DELTA_ADDED]); opts.flags = GIT_DIFF_FIND_ALL; cl_git_pass(git_diff_find_similar(diff, &opts)); memset(&exp, 0, sizeof(exp)); cl_git_pass(git_diff_foreach( diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp)); cl_assert_equal_i(1, exp.files); cl_assert_equal_i(1, exp.file_status[GIT_DELTA_RENAMED]); git_diff_list_free(diff); git_index_free(index); git_tree_free(tree); } void test_diff_rename__unmodified_can_be_renamed(void) { git_index *index; git_tree *tree; git_diff_list *diff = NULL; diff_expects exp; git_diff_options diffopts = GIT_DIFF_OPTIONS_INIT; git_diff_find_options opts = GIT_DIFF_FIND_OPTIONS_INIT; cl_git_pass(git_repository_index(&index, g_repo)); cl_git_pass( git_revparse_single((git_object **)&tree, g_repo, "HEAD^{tree}")); cl_git_pass(p_rename("renames/ikeepsix.txt", "renames/ikeepsix2.txt")); cl_git_pass(git_index_remove_bypath(index, "ikeepsix.txt")); cl_git_pass(git_index_add_bypath(index, "ikeepsix2.txt")); cl_git_pass(git_index_write(index)); cl_git_pass(git_diff_tree_to_index(&diff, g_repo, tree, index, &diffopts)); memset(&exp, 0, sizeof(exp)); cl_git_pass(git_diff_foreach( diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp)); cl_assert_equal_i(2, exp.files); cl_assert_equal_i(1, exp.file_status[GIT_DELTA_DELETED]); cl_assert_equal_i(1, exp.file_status[GIT_DELTA_ADDED]); opts.flags = GIT_DIFF_FIND_ALL; cl_git_pass(git_diff_find_similar(diff, &opts)); memset(&exp, 0, sizeof(exp)); cl_git_pass(git_diff_foreach( diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp)); cl_assert_equal_i(1, exp.files); cl_assert_equal_i(1, exp.file_status[GIT_DELTA_RENAMED]); memset(&exp, 0, sizeof(exp)); cl_git_pass(git_diff_foreach( diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp)); cl_assert_equal_i(1, exp.files); cl_assert_equal_i(1, exp.file_status[GIT_DELTA_RENAMED]); git_diff_list_free(diff); git_index_free(index); git_tree_free(tree); } libgit2-0.19.0/tests-clar/diff/submodules.c000066400000000000000000000142361216214232500204600ustar00rootroot00000000000000#include "clar_libgit2.h" #include "repository.h" #include "posix.h" #include "../submodule/submodule_helpers.h" static git_repository *g_repo = NULL; static void setup_submodules(void) { g_repo = cl_git_sandbox_init("submodules"); cl_fixture_sandbox("testrepo.git"); rewrite_gitmodules(git_repository_workdir(g_repo)); p_rename("submodules/testrepo/.gitted", "submodules/testrepo/.git"); } static void setup_submodules2(void) { g_repo = cl_git_sandbox_init("submod2"); cl_fixture_sandbox("submod2_target"); p_rename("submod2_target/.gitted", "submod2_target/.git"); rewrite_gitmodules(git_repository_workdir(g_repo)); p_rename("submod2/not-submodule/.gitted", "submod2/not-submodule/.git"); p_rename("submod2/not/.gitted", "submod2/not/.git"); } void test_diff_submodules__initialize(void) { } void test_diff_submodules__cleanup(void) { cl_git_sandbox_cleanup(); cl_fixture_cleanup("testrepo.git"); cl_fixture_cleanup("submod2_target"); } static void check_diff_patches(git_diff_list *diff, const char **expected) { const git_diff_delta *delta; git_diff_patch *patch = NULL; size_t d, num_d = git_diff_num_deltas(diff); char *patch_text; for (d = 0; d < num_d; ++d, git_diff_patch_free(patch)) { cl_git_pass(git_diff_get_patch(&patch, &delta, diff, d)); if (delta->status == GIT_DELTA_UNMODIFIED) continue; if (expected[d] && !strcmp(expected[d], "")) continue; if (expected[d] && !strcmp(expected[d], "")) cl_assert(0); cl_git_pass(git_diff_patch_to_str(&patch_text, patch)); cl_assert_equal_s(expected[d], patch_text); git__free(patch_text); } cl_assert(expected[d] && !strcmp(expected[d], "")); } void test_diff_submodules__unmodified_submodule(void) { git_diff_options opts = GIT_DIFF_OPTIONS_INIT; git_diff_list *diff = NULL; static const char *expected[] = { "", /* .gitmodules */ NULL, /* added */ NULL, /* ignored */ "diff --git a/modified b/modified\nindex 092bfb9..452216e 100644\n--- a/modified\n+++ b/modified\n@@ -1 +1,2 @@\n-yo\n+changed\n+\n", /* modified */ NULL, /* testrepo.git */ NULL, /* unmodified */ NULL, /* untracked */ "" }; setup_submodules(); opts.flags = GIT_DIFF_INCLUDE_IGNORED | GIT_DIFF_INCLUDE_UNTRACKED | GIT_DIFF_INCLUDE_UNMODIFIED; cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts)); check_diff_patches(diff, expected); git_diff_list_free(diff); } void test_diff_submodules__dirty_submodule(void) { git_diff_options opts = GIT_DIFF_OPTIONS_INIT; git_diff_list *diff = NULL; static const char *expected[] = { "", /* .gitmodules */ NULL, /* added */ NULL, /* ignored */ "diff --git a/modified b/modified\nindex 092bfb9..452216e 100644\n--- a/modified\n+++ b/modified\n@@ -1 +1,2 @@\n-yo\n+changed\n+\n", /* modified */ "diff --git a/testrepo b/testrepo\nindex a65fedf..a65fedf 160000\n--- a/testrepo\n+++ b/testrepo\n@@ -1 +1 @@\n-Subproject commit a65fedf39aefe402d3bb6e24df4d4f5fe4547750\n+Subproject commit a65fedf39aefe402d3bb6e24df4d4f5fe4547750-dirty\n", /* testrepo.git */ NULL, /* unmodified */ NULL, /* untracked */ "" }; setup_submodules(); cl_git_rewritefile("submodules/testrepo/README", "heyheyhey"); cl_git_mkfile("submodules/testrepo/all_new.txt", "never seen before"); opts.flags = GIT_DIFF_INCLUDE_IGNORED | GIT_DIFF_INCLUDE_UNTRACKED | GIT_DIFF_INCLUDE_UNMODIFIED; cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts)); check_diff_patches(diff, expected); git_diff_list_free(diff); } void test_diff_submodules__submod2_index_to_wd(void) { git_diff_options opts = GIT_DIFF_OPTIONS_INIT; git_diff_list *diff = NULL; static const char *expected[] = { "", /* .gitmodules */ NULL, /* not-submodule */ NULL, /* not */ "diff --git a/sm_changed_file b/sm_changed_file\nindex 4800958..4800958 160000\n--- a/sm_changed_file\n+++ b/sm_changed_file\n@@ -1 +1 @@\n-Subproject commit 480095882d281ed676fe5b863569520e54a7d5c0\n+Subproject commit 480095882d281ed676fe5b863569520e54a7d5c0-dirty\n", /* sm_changed_file */ "diff --git a/sm_changed_head b/sm_changed_head\nindex 4800958..3d9386c 160000\n--- a/sm_changed_head\n+++ b/sm_changed_head\n@@ -1 +1 @@\n-Subproject commit 480095882d281ed676fe5b863569520e54a7d5c0\n+Subproject commit 3d9386c507f6b093471a3e324085657a3c2b4247\n", /* sm_changed_head */ "diff --git a/sm_changed_index b/sm_changed_index\nindex 4800958..4800958 160000\n--- a/sm_changed_index\n+++ b/sm_changed_index\n@@ -1 +1 @@\n-Subproject commit 480095882d281ed676fe5b863569520e54a7d5c0\n+Subproject commit 480095882d281ed676fe5b863569520e54a7d5c0-dirty\n", /* sm_changed_index */ "diff --git a/sm_changed_untracked_file b/sm_changed_untracked_file\nindex 4800958..4800958 160000\n--- a/sm_changed_untracked_file\n+++ b/sm_changed_untracked_file\n@@ -1 +1 @@\n-Subproject commit 480095882d281ed676fe5b863569520e54a7d5c0\n+Subproject commit 480095882d281ed676fe5b863569520e54a7d5c0-dirty\n", /* sm_changed_untracked_file */ "diff --git a/sm_missing_commits b/sm_missing_commits\nindex 4800958..5e49635 160000\n--- a/sm_missing_commits\n+++ b/sm_missing_commits\n@@ -1 +1 @@\n-Subproject commit 480095882d281ed676fe5b863569520e54a7d5c0\n+Subproject commit 5e4963595a9774b90524d35a807169049de8ccad\n", /* sm_missing_commits */ "" }; setup_submodules2(); opts.flags = GIT_DIFF_INCLUDE_UNTRACKED; cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts)); check_diff_patches(diff, expected); git_diff_list_free(diff); } void test_diff_submodules__submod2_head_to_index(void) { git_diff_options opts = GIT_DIFF_OPTIONS_INIT; git_tree *head; git_diff_list *diff = NULL; static const char *expected[] = { "", /* .gitmodules */ "diff --git a/sm_added_and_uncommited b/sm_added_and_uncommited\nnew file mode 160000\nindex 0000000..4800958\n--- /dev/null\n+++ b/sm_added_and_uncommited\n@@ -0,0 +1 @@\n+Subproject commit 480095882d281ed676fe5b863569520e54a7d5c0\n", /* sm_added_and_uncommited */ "" }; setup_submodules2(); cl_git_pass(git_repository_head_tree(&head, g_repo)); opts.flags = GIT_DIFF_INCLUDE_UNTRACKED; cl_git_pass(git_diff_tree_to_index(&diff, g_repo, head, NULL, &opts)); check_diff_patches(diff, expected); git_diff_list_free(diff); git_tree_free(head); } libgit2-0.19.0/tests-clar/diff/tree.c000066400000000000000000000374701216214232500172420ustar00rootroot00000000000000#include "clar_libgit2.h" #include "diff_helpers.h" static git_repository *g_repo = NULL; static git_diff_options opts; static git_diff_list *diff; static git_tree *a, *b; static diff_expects expect; void test_diff_tree__initialize(void) { GIT_INIT_STRUCTURE(&opts, GIT_DIFF_OPTIONS_VERSION); /* The default context lines is set by _INIT which we can't use here */ opts.context_lines = 3; memset(&expect, 0, sizeof(expect)); diff = NULL; a = NULL; b = NULL; } void test_diff_tree__cleanup(void) { git_diff_list_free(diff); git_tree_free(a); git_tree_free(b); cl_git_sandbox_cleanup(); } void test_diff_tree__0(void) { /* grabbed a couple of commit oids from the history of the attr repo */ const char *a_commit = "605812a"; const char *b_commit = "370fe9ec22"; const char *c_commit = "f5b0af1fb4f5c"; git_tree *c; g_repo = cl_git_sandbox_init("attr"); cl_assert((a = resolve_commit_oid_to_tree(g_repo, a_commit)) != NULL); cl_assert((b = resolve_commit_oid_to_tree(g_repo, b_commit)) != NULL); cl_assert((c = resolve_commit_oid_to_tree(g_repo, c_commit)) != NULL); opts.context_lines = 1; opts.interhunk_lines = 1; cl_git_pass(git_diff_tree_to_tree(&diff, g_repo, a, b, &opts)); cl_git_pass(git_diff_foreach( diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &expect)); cl_assert_equal_i(5, expect.files); cl_assert_equal_i(2, expect.file_status[GIT_DELTA_ADDED]); cl_assert_equal_i(1, expect.file_status[GIT_DELTA_DELETED]); cl_assert_equal_i(2, expect.file_status[GIT_DELTA_MODIFIED]); cl_assert_equal_i(5, expect.hunks); cl_assert_equal_i(7 + 24 + 1 + 6 + 6, expect.lines); cl_assert_equal_i(1, expect.line_ctxt); cl_assert_equal_i(24 + 1 + 5 + 5, expect.line_adds); cl_assert_equal_i(7 + 1, expect.line_dels); git_diff_list_free(diff); diff = NULL; memset(&expect, 0, sizeof(expect)); cl_git_pass(git_diff_tree_to_tree(&diff, g_repo, c, b, &opts)); cl_git_pass(git_diff_foreach( diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &expect)); cl_assert_equal_i(2, expect.files); cl_assert_equal_i(0, expect.file_status[GIT_DELTA_ADDED]); cl_assert_equal_i(0, expect.file_status[GIT_DELTA_DELETED]); cl_assert_equal_i(2, expect.file_status[GIT_DELTA_MODIFIED]); cl_assert_equal_i(2, expect.hunks); cl_assert_equal_i(8 + 15, expect.lines); cl_assert_equal_i(1, expect.line_ctxt); cl_assert_equal_i(1, expect.line_adds); cl_assert_equal_i(7 + 14, expect.line_dels); git_tree_free(c); } void test_diff_tree__options(void) { /* grabbed a couple of commit oids from the history of the attr repo */ const char *a_commit = "6bab5c79cd5140d0"; const char *b_commit = "605812ab7fe421fdd"; const char *c_commit = "f5b0af1fb4f5"; const char *d_commit = "a97cc019851"; git_tree *c, *d; diff_expects actual; int test_ab_or_cd[] = { 0, 0, 0, 0, 1, 1, 1, 1, 1 }; git_diff_options test_options[] = { /* a vs b tests */ { 1, GIT_DIFF_NORMAL, 1, 1, NULL, NULL, {0} }, { 1, GIT_DIFF_NORMAL, 3, 1, NULL, NULL, {0} }, { 1, GIT_DIFF_REVERSE, 2, 1, NULL, NULL, {0} }, { 1, GIT_DIFF_FORCE_TEXT, 2, 1, NULL, NULL, {0} }, /* c vs d tests */ { 1, GIT_DIFF_NORMAL, 3, 1, NULL, NULL, {0} }, { 1, GIT_DIFF_IGNORE_WHITESPACE, 3, 1, NULL, NULL, {0} }, { 1, GIT_DIFF_IGNORE_WHITESPACE_CHANGE, 3, 1, NULL, NULL, {0} }, { 1, GIT_DIFF_IGNORE_WHITESPACE_EOL, 3, 1, NULL, NULL, {0} }, { 1, GIT_DIFF_IGNORE_WHITESPACE | GIT_DIFF_REVERSE, 1, 1, NULL, NULL, {0} }, }; /* to generate these values: * - cd to tests/resources/attr, * - mv .gitted .git * - git diff [options] 6bab5c79cd5140d0 605812ab7fe421fdd * - mv .git .gitted */ #define EXPECT_STATUS_ADM(ADDS,DELS,MODS) { 0, ADDS, DELS, MODS, 0, 0, 0, 0, 0 } diff_expects test_expects[] = { /* a vs b tests */ { 5, 0, EXPECT_STATUS_ADM(3, 0, 2), 4, 0, 0, 51, 2, 46, 3 }, { 5, 0, EXPECT_STATUS_ADM(3, 0, 2), 4, 0, 0, 53, 4, 46, 3 }, { 5, 0, EXPECT_STATUS_ADM(0, 3, 2), 4, 0, 0, 52, 3, 3, 46 }, { 5, 0, EXPECT_STATUS_ADM(3, 0, 2), 5, 0, 0, 54, 3, 47, 4 }, /* c vs d tests */ { 1, 0, EXPECT_STATUS_ADM(0, 0, 1), 1, 0, 0, 22, 9, 10, 3 }, { 1, 0, EXPECT_STATUS_ADM(0, 0, 1), 1, 0, 0, 19, 12, 7, 0 }, { 1, 0, EXPECT_STATUS_ADM(0, 0, 1), 1, 0, 0, 20, 11, 8, 1 }, { 1, 0, EXPECT_STATUS_ADM(0, 0, 1), 1, 0, 0, 20, 11, 8, 1 }, { 1, 0, EXPECT_STATUS_ADM(0, 0, 1), 1, 0, 0, 18, 11, 0, 7 }, { 0 }, }; diff_expects *expected; int i, j; g_repo = cl_git_sandbox_init("attr"); cl_assert((a = resolve_commit_oid_to_tree(g_repo, a_commit)) != NULL); cl_assert((b = resolve_commit_oid_to_tree(g_repo, b_commit)) != NULL); cl_assert((c = resolve_commit_oid_to_tree(g_repo, c_commit)) != NULL); cl_assert((d = resolve_commit_oid_to_tree(g_repo, d_commit)) != NULL); for (i = 0; test_expects[i].files > 0; i++) { memset(&actual, 0, sizeof(actual)); /* clear accumulator */ opts = test_options[i]; if (test_ab_or_cd[i] == 0) cl_git_pass(git_diff_tree_to_tree(&diff, g_repo, a, b, &opts)); else cl_git_pass(git_diff_tree_to_tree(&diff, g_repo, c, d, &opts)); cl_git_pass(git_diff_foreach( diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &actual)); expected = &test_expects[i]; cl_assert_equal_i(actual.files, expected->files); for (j = GIT_DELTA_UNMODIFIED; j <= GIT_DELTA_TYPECHANGE; ++j) cl_assert_equal_i(expected->file_status[j], actual.file_status[j]); cl_assert_equal_i(actual.hunks, expected->hunks); cl_assert_equal_i(actual.lines, expected->lines); cl_assert_equal_i(actual.line_ctxt, expected->line_ctxt); cl_assert_equal_i(actual.line_adds, expected->line_adds); cl_assert_equal_i(actual.line_dels, expected->line_dels); git_diff_list_free(diff); diff = NULL; } git_tree_free(c); git_tree_free(d); } void test_diff_tree__bare(void) { const char *a_commit = "8496071c1b46c85"; const char *b_commit = "be3563ae3f79"; g_repo = cl_git_sandbox_init("testrepo.git"); cl_assert((a = resolve_commit_oid_to_tree(g_repo, a_commit)) != NULL); cl_assert((b = resolve_commit_oid_to_tree(g_repo, b_commit)) != NULL); opts.context_lines = 1; opts.interhunk_lines = 1; cl_git_pass(git_diff_tree_to_tree(&diff, g_repo, a, b, &opts)); cl_git_pass(git_diff_foreach( diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &expect)); cl_assert_equal_i(3, expect.files); cl_assert_equal_i(2, expect.file_status[GIT_DELTA_ADDED]); cl_assert_equal_i(0, expect.file_status[GIT_DELTA_DELETED]); cl_assert_equal_i(1, expect.file_status[GIT_DELTA_MODIFIED]); cl_assert_equal_i(3, expect.hunks); cl_assert_equal_i(4, expect.lines); cl_assert_equal_i(0, expect.line_ctxt); cl_assert_equal_i(3, expect.line_adds); cl_assert_equal_i(1, expect.line_dels); } void test_diff_tree__merge(void) { /* grabbed a couple of commit oids from the history of the attr repo */ const char *a_commit = "605812a"; const char *b_commit = "370fe9ec22"; const char *c_commit = "f5b0af1fb4f5c"; git_tree *c; git_diff_list *diff1 = NULL, *diff2 = NULL; g_repo = cl_git_sandbox_init("attr"); cl_assert((a = resolve_commit_oid_to_tree(g_repo, a_commit)) != NULL); cl_assert((b = resolve_commit_oid_to_tree(g_repo, b_commit)) != NULL); cl_assert((c = resolve_commit_oid_to_tree(g_repo, c_commit)) != NULL); cl_git_pass(git_diff_tree_to_tree(&diff1, g_repo, a, b, NULL)); cl_git_pass(git_diff_tree_to_tree(&diff2, g_repo, c, b, NULL)); git_tree_free(c); cl_git_pass(git_diff_merge(diff1, diff2)); git_diff_list_free(diff2); cl_git_pass(git_diff_foreach( diff1, diff_file_cb, diff_hunk_cb, diff_line_cb, &expect)); cl_assert_equal_i(6, expect.files); cl_assert_equal_i(2, expect.file_status[GIT_DELTA_ADDED]); cl_assert_equal_i(1, expect.file_status[GIT_DELTA_DELETED]); cl_assert_equal_i(3, expect.file_status[GIT_DELTA_MODIFIED]); cl_assert_equal_i(6, expect.hunks); cl_assert_equal_i(59, expect.lines); cl_assert_equal_i(1, expect.line_ctxt); cl_assert_equal_i(36, expect.line_adds); cl_assert_equal_i(22, expect.line_dels); git_diff_list_free(diff1); } void test_diff_tree__larger_hunks(void) { const char *a_commit = "d70d245ed97ed2aa596dd1af6536e4bfdb047b69"; const char *b_commit = "7a9e0b02e63179929fed24f0a3e0f19168114d10"; size_t d, num_d, h, num_h, l, num_l, header_len, line_len; const git_diff_delta *delta; git_diff_patch *patch; const git_diff_range *range; const char *header, *line; char origin; g_repo = cl_git_sandbox_init("diff"); cl_assert((a = resolve_commit_oid_to_tree(g_repo, a_commit)) != NULL); cl_assert((b = resolve_commit_oid_to_tree(g_repo, b_commit)) != NULL); opts.context_lines = 1; opts.interhunk_lines = 0; cl_git_pass(git_diff_tree_to_tree(&diff, g_repo, a, b, &opts)); num_d = git_diff_num_deltas(diff); for (d = 0; d < num_d; ++d) { cl_git_pass(git_diff_get_patch(&patch, &delta, diff, d)); cl_assert(patch && delta); num_h = git_diff_patch_num_hunks(patch); for (h = 0; h < num_h; h++) { cl_git_pass(git_diff_patch_get_hunk( &range, &header, &header_len, &num_l, patch, h)); for (l = 0; l < num_l; ++l) { cl_git_pass(git_diff_patch_get_line_in_hunk( &origin, &line, &line_len, NULL, NULL, patch, h, l)); cl_assert(line); } cl_git_fail(git_diff_patch_get_line_in_hunk( &origin, &line, &line_len, NULL, NULL, patch, h, num_l)); } cl_git_fail(git_diff_patch_get_hunk( &range, &header, &header_len, &num_l, patch, num_h)); git_diff_patch_free(patch); } cl_git_fail(git_diff_get_patch(&patch, &delta, diff, num_d)); cl_assert_equal_i(2, (int)num_d); } void test_diff_tree__checks_options_version(void) { const char *a_commit = "8496071c1b46c85"; const char *b_commit = "be3563ae3f79"; const git_error *err; g_repo = cl_git_sandbox_init("testrepo.git"); cl_assert((a = resolve_commit_oid_to_tree(g_repo, a_commit)) != NULL); cl_assert((b = resolve_commit_oid_to_tree(g_repo, b_commit)) != NULL); opts.version = 0; cl_git_fail(git_diff_tree_to_tree(&diff, g_repo, a, b, &opts)); err = giterr_last(); cl_assert_equal_i(GITERR_INVALID, err->klass); giterr_clear(); opts.version = 1024; cl_git_fail(git_diff_tree_to_tree(&diff, g_repo, a, b, &opts)); err = giterr_last(); } void process_tree_to_tree_diffing( const char *old_commit, const char *new_commit) { g_repo = cl_git_sandbox_init("unsymlinked.git"); cl_assert((a = resolve_commit_oid_to_tree(g_repo, old_commit)) != NULL); cl_assert((b = resolve_commit_oid_to_tree(g_repo, new_commit)) != NULL); cl_git_pass(git_diff_tree_to_tree(&diff, g_repo, a, b, &opts)); cl_git_pass(git_diff_foreach( diff, diff_file_cb, NULL, NULL, &expect)); } void test_diff_tree__symlink_blob_mode_changed_to_regular_file(void) { /* * $ git diff 7fccd7..806999 * diff --git a/include/Nu/Nu.h b/include/Nu/Nu.h * deleted file mode 120000 * index 19bf568..0000000 * --- a/include/Nu/Nu.h * +++ /dev/null * @@ -1 +0,0 @@ * -../../objc/Nu.h * \ No newline at end of file * diff --git a/include/Nu/Nu.h b/include/Nu/Nu.h * new file mode 100644 * index 0000000..f9e6561 * --- /dev/null * +++ b/include/Nu/Nu.h * @@ -0,0 +1 @@ * +awesome content * diff --git a/objc/Nu.h b/objc/Nu.h * deleted file mode 100644 * index f9e6561..0000000 * --- a/objc/Nu.h * +++ /dev/null * @@ -1 +0,0 @@ * -awesome content */ process_tree_to_tree_diffing("7fccd7", "806999"); cl_assert_equal_i(3, expect.files); cl_assert_equal_i(2, expect.file_status[GIT_DELTA_DELETED]); cl_assert_equal_i(0, expect.file_status[GIT_DELTA_MODIFIED]); cl_assert_equal_i(1, expect.file_status[GIT_DELTA_ADDED]); cl_assert_equal_i(0, expect.file_status[GIT_DELTA_TYPECHANGE]); } void test_diff_tree__symlink_blob_mode_changed_to_regular_file_as_typechange(void) { /* * $ git diff 7fccd7..a8595c * diff --git a/include/Nu/Nu.h b/include/Nu/Nu.h * deleted file mode 120000 * index 19bf568..0000000 * --- a/include/Nu/Nu.h * +++ /dev/null * @@ -1 +0,0 @@ * -../../objc/Nu.h * \ No newline at end of file * diff --git a/include/Nu/Nu.h b/include/Nu/Nu.h * new file mode 100755 * index 0000000..f9e6561 * --- /dev/null * +++ b/include/Nu/Nu.h * @@ -0,0 +1 @@ * +awesome content * diff --git a/objc/Nu.h b/objc/Nu.h * deleted file mode 100644 * index f9e6561..0000000 * --- a/objc/Nu.h * +++ /dev/null * @@ -1 +0,0 @@ * -awesome content */ opts.flags = GIT_DIFF_INCLUDE_TYPECHANGE; process_tree_to_tree_diffing("7fccd7", "a8595c"); cl_assert_equal_i(2, expect.files); cl_assert_equal_i(1, expect.file_status[GIT_DELTA_DELETED]); cl_assert_equal_i(0, expect.file_status[GIT_DELTA_MODIFIED]); cl_assert_equal_i(0, expect.file_status[GIT_DELTA_ADDED]); cl_assert_equal_i(1, expect.file_status[GIT_DELTA_TYPECHANGE]); } void test_diff_tree__regular_blob_mode_changed_to_executable_file(void) { /* * $ git diff 806999..a8595c * diff --git a/include/Nu/Nu.h b/include/Nu/Nu.h * old mode 100644 * new mode 100755 */ process_tree_to_tree_diffing("806999", "a8595c"); cl_assert_equal_i(1, expect.files); cl_assert_equal_i(0, expect.file_status[GIT_DELTA_DELETED]); cl_assert_equal_i(1, expect.file_status[GIT_DELTA_MODIFIED]); cl_assert_equal_i(0, expect.file_status[GIT_DELTA_ADDED]); cl_assert_equal_i(0, expect.file_status[GIT_DELTA_TYPECHANGE]); } void test_diff_tree__issue_1397(void) { /* this test shows that it is not needed */ g_repo = cl_git_sandbox_init("issue_1397"); cl_repo_set_bool(g_repo, "core.autocrlf", true); cl_assert((a = resolve_commit_oid_to_tree(g_repo, "8a7ef04")) != NULL); cl_assert((b = resolve_commit_oid_to_tree(g_repo, "7f483a7")) != NULL); cl_git_pass(git_diff_tree_to_tree(&diff, g_repo, a, b, &opts)); cl_git_pass(git_diff_foreach( diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &expect)); cl_assert_equal_i(1, expect.files); cl_assert_equal_i(0, expect.file_status[GIT_DELTA_DELETED]); cl_assert_equal_i(1, expect.file_status[GIT_DELTA_MODIFIED]); cl_assert_equal_i(0, expect.file_status[GIT_DELTA_ADDED]); cl_assert_equal_i(0, expect.file_status[GIT_DELTA_TYPECHANGE]); } static void set_config_int(git_repository *repo, const char *name, int value) { git_config *cfg; cl_git_pass(git_repository_config(&cfg, repo)); cl_git_pass(git_config_set_int32(cfg, name, value)); git_config_free(cfg); } void test_diff_tree__diff_configs(void) { const char *a_commit = "d70d245e"; const char *b_commit = "7a9e0b02"; g_repo = cl_git_sandbox_init("diff"); cl_assert((a = resolve_commit_oid_to_tree(g_repo, a_commit)) != NULL); cl_assert((b = resolve_commit_oid_to_tree(g_repo, b_commit)) != NULL); cl_git_pass(git_diff_tree_to_tree(&diff, g_repo, a, b, NULL)); cl_git_pass(git_diff_foreach( diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &expect)); cl_assert_equal_i(2, expect.files); cl_assert_equal_i(2, expect.file_status[GIT_DELTA_MODIFIED]); cl_assert_equal_i(6, expect.hunks); cl_assert_equal_i(55, expect.lines); cl_assert_equal_i(33, expect.line_ctxt); cl_assert_equal_i(7, expect.line_adds); cl_assert_equal_i(15, expect.line_dels); git_diff_list_free(diff); diff = NULL; set_config_int(g_repo, "diff.context", 1); memset(&expect, 0, sizeof(expect)); cl_git_pass(git_diff_tree_to_tree(&diff, g_repo, a, b, NULL)); cl_git_pass(git_diff_foreach( diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &expect)); cl_assert_equal_i(2, expect.files); cl_assert_equal_i(2, expect.file_status[GIT_DELTA_MODIFIED]); cl_assert_equal_i(7, expect.hunks); cl_assert_equal_i(34, expect.lines); cl_assert_equal_i(12, expect.line_ctxt); cl_assert_equal_i(7, expect.line_adds); cl_assert_equal_i(15, expect.line_dels); git_diff_list_free(diff); diff = NULL; set_config_int(g_repo, "diff.context", 0); set_config_int(g_repo, "diff.noprefix", 1); memset(&expect, 0, sizeof(expect)); cl_git_pass(git_diff_tree_to_tree(&diff, g_repo, a, b, NULL)); cl_git_pass(git_diff_foreach( diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &expect)); cl_assert_equal_i(2, expect.files); cl_assert_equal_i(2, expect.file_status[GIT_DELTA_MODIFIED]); cl_assert_equal_i(7, expect.hunks); cl_assert_equal_i(22, expect.lines); cl_assert_equal_i(0, expect.line_ctxt); cl_assert_equal_i(7, expect.line_adds); cl_assert_equal_i(15, expect.line_dels); } libgit2-0.19.0/tests-clar/diff/workdir.c000066400000000000000000001144111216214232500177530ustar00rootroot00000000000000#include "clar_libgit2.h" #include "diff_helpers.h" #include "repository.h" static git_repository *g_repo = NULL; void test_diff_workdir__initialize(void) { } void test_diff_workdir__cleanup(void) { cl_git_sandbox_cleanup(); } void test_diff_workdir__to_index(void) { git_diff_options opts = GIT_DIFF_OPTIONS_INIT; git_diff_list *diff = NULL; diff_expects exp; int use_iterator; g_repo = cl_git_sandbox_init("status"); opts.context_lines = 3; opts.interhunk_lines = 1; opts.flags |= GIT_DIFF_INCLUDE_IGNORED | GIT_DIFF_INCLUDE_UNTRACKED; cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts)); for (use_iterator = 0; use_iterator <= 1; use_iterator++) { memset(&exp, 0, sizeof(exp)); if (use_iterator) cl_git_pass(diff_foreach_via_iterator( diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp)); else cl_git_pass(git_diff_foreach( diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp)); /* to generate these values: * - cd to tests/resources/status, * - mv .gitted .git * - git diff --name-status * - git diff * - mv .git .gitted */ cl_assert_equal_i(13, exp.files); cl_assert_equal_i(0, exp.file_status[GIT_DELTA_ADDED]); cl_assert_equal_i(4, exp.file_status[GIT_DELTA_DELETED]); cl_assert_equal_i(4, exp.file_status[GIT_DELTA_MODIFIED]); cl_assert_equal_i(1, exp.file_status[GIT_DELTA_IGNORED]); cl_assert_equal_i(4, exp.file_status[GIT_DELTA_UNTRACKED]); cl_assert_equal_i(8, exp.hunks); cl_assert_equal_i(14, exp.lines); cl_assert_equal_i(5, exp.line_ctxt); cl_assert_equal_i(4, exp.line_adds); cl_assert_equal_i(5, exp.line_dels); } git_diff_list_free(diff); } void test_diff_workdir__to_tree(void) { /* grabbed a couple of commit oids from the history of the attr repo */ const char *a_commit = "26a125ee1bf"; /* the current HEAD */ const char *b_commit = "0017bd4ab1ec3"; /* the start */ git_tree *a, *b; git_diff_options opts = GIT_DIFF_OPTIONS_INIT; git_diff_list *diff = NULL; git_diff_list *diff2 = NULL; diff_expects exp; int use_iterator; g_repo = cl_git_sandbox_init("status"); a = resolve_commit_oid_to_tree(g_repo, a_commit); b = resolve_commit_oid_to_tree(g_repo, b_commit); opts.context_lines = 3; opts.interhunk_lines = 1; opts.flags |= GIT_DIFF_INCLUDE_IGNORED | GIT_DIFF_INCLUDE_UNTRACKED; /* You can't really generate the equivalent of git_diff_tree_to_workdir() * using C git. It really wants to interpose the index into the diff. * * To validate the following results with command line git, I ran the * following: * - git ls-tree 26a125 * - find . ! -path ./.git/\* -a -type f | git hash-object --stdin-paths * The results are documented at the bottom of this file in the * long comment entitled "PREPARATION OF TEST DATA". */ cl_git_pass(git_diff_tree_to_workdir(&diff, g_repo, a, &opts)); for (use_iterator = 0; use_iterator <= 1; use_iterator++) { memset(&exp, 0, sizeof(exp)); if (use_iterator) cl_git_pass(diff_foreach_via_iterator( diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp)); else cl_git_pass(git_diff_foreach( diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp)); cl_assert_equal_i(14, exp.files); cl_assert_equal_i(0, exp.file_status[GIT_DELTA_ADDED]); cl_assert_equal_i(4, exp.file_status[GIT_DELTA_DELETED]); cl_assert_equal_i(4, exp.file_status[GIT_DELTA_MODIFIED]); cl_assert_equal_i(1, exp.file_status[GIT_DELTA_IGNORED]); cl_assert_equal_i(5, exp.file_status[GIT_DELTA_UNTRACKED]); } /* Since there is no git diff equivalent, let's just assume that the * text diffs produced by git_diff_foreach are accurate here. We will * do more apples-to-apples test comparison below. */ git_diff_list_free(diff); diff = NULL; memset(&exp, 0, sizeof(exp)); /* This is a compatible emulation of "git diff " which looks like * a workdir to tree diff (even though it is not really). This is what * you would get from "git diff --name-status 26a125ee1bf" */ cl_git_pass(git_diff_tree_to_index(&diff, g_repo, a, NULL, &opts)); cl_git_pass(git_diff_index_to_workdir(&diff2, g_repo, NULL, &opts)); cl_git_pass(git_diff_merge(diff, diff2)); git_diff_list_free(diff2); for (use_iterator = 0; use_iterator <= 1; use_iterator++) { memset(&exp, 0, sizeof(exp)); if (use_iterator) cl_git_pass(diff_foreach_via_iterator( diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp)); else cl_git_pass(git_diff_foreach( diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp)); cl_assert_equal_i(15, exp.files); cl_assert_equal_i(2, exp.file_status[GIT_DELTA_ADDED]); cl_assert_equal_i(5, exp.file_status[GIT_DELTA_DELETED]); cl_assert_equal_i(4, exp.file_status[GIT_DELTA_MODIFIED]); cl_assert_equal_i(1, exp.file_status[GIT_DELTA_IGNORED]); cl_assert_equal_i(3, exp.file_status[GIT_DELTA_UNTRACKED]); cl_assert_equal_i(11, exp.hunks); cl_assert_equal_i(17, exp.lines); cl_assert_equal_i(4, exp.line_ctxt); cl_assert_equal_i(8, exp.line_adds); cl_assert_equal_i(5, exp.line_dels); } git_diff_list_free(diff); diff = NULL; memset(&exp, 0, sizeof(exp)); /* Again, emulating "git diff " for testing purposes using * "git diff --name-status 0017bd4ab1ec3" instead. */ cl_git_pass(git_diff_tree_to_index(&diff, g_repo, b, NULL, &opts)); cl_git_pass(git_diff_index_to_workdir(&diff2, g_repo, NULL, &opts)); cl_git_pass(git_diff_merge(diff, diff2)); git_diff_list_free(diff2); for (use_iterator = 0; use_iterator <= 1; use_iterator++) { memset(&exp, 0, sizeof(exp)); if (use_iterator) cl_git_pass(diff_foreach_via_iterator( diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp)); else cl_git_pass(git_diff_foreach( diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp)); cl_assert_equal_i(16, exp.files); cl_assert_equal_i(5, exp.file_status[GIT_DELTA_ADDED]); cl_assert_equal_i(4, exp.file_status[GIT_DELTA_DELETED]); cl_assert_equal_i(3, exp.file_status[GIT_DELTA_MODIFIED]); cl_assert_equal_i(1, exp.file_status[GIT_DELTA_IGNORED]); cl_assert_equal_i(3, exp.file_status[GIT_DELTA_UNTRACKED]); cl_assert_equal_i(12, exp.hunks); cl_assert_equal_i(19, exp.lines); cl_assert_equal_i(3, exp.line_ctxt); cl_assert_equal_i(12, exp.line_adds); cl_assert_equal_i(4, exp.line_dels); } git_diff_list_free(diff); git_tree_free(a); git_tree_free(b); } void test_diff_workdir__to_index_with_pathspec(void) { git_diff_options opts = GIT_DIFF_OPTIONS_INIT; git_diff_list *diff = NULL; diff_expects exp; char *pathspec = NULL; int use_iterator; g_repo = cl_git_sandbox_init("status"); opts.context_lines = 3; opts.interhunk_lines = 1; opts.flags |= GIT_DIFF_INCLUDE_IGNORED | GIT_DIFF_INCLUDE_UNTRACKED; opts.pathspec.strings = &pathspec; opts.pathspec.count = 1; cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts)); for (use_iterator = 0; use_iterator <= 1; use_iterator++) { memset(&exp, 0, sizeof(exp)); if (use_iterator) cl_git_pass(diff_foreach_via_iterator( diff, diff_file_cb, NULL, NULL, &exp)); else cl_git_pass(git_diff_foreach(diff, diff_file_cb, NULL, NULL, &exp)); cl_assert_equal_i(13, exp.files); cl_assert_equal_i(0, exp.file_status[GIT_DELTA_ADDED]); cl_assert_equal_i(4, exp.file_status[GIT_DELTA_DELETED]); cl_assert_equal_i(4, exp.file_status[GIT_DELTA_MODIFIED]); cl_assert_equal_i(1, exp.file_status[GIT_DELTA_IGNORED]); cl_assert_equal_i(4, exp.file_status[GIT_DELTA_UNTRACKED]); } git_diff_list_free(diff); pathspec = "modified_file"; cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts)); for (use_iterator = 0; use_iterator <= 1; use_iterator++) { memset(&exp, 0, sizeof(exp)); if (use_iterator) cl_git_pass(diff_foreach_via_iterator( diff, diff_file_cb, NULL, NULL, &exp)); else cl_git_pass(git_diff_foreach(diff, diff_file_cb, NULL, NULL, &exp)); cl_assert_equal_i(1, exp.files); cl_assert_equal_i(0, exp.file_status[GIT_DELTA_ADDED]); cl_assert_equal_i(0, exp.file_status[GIT_DELTA_DELETED]); cl_assert_equal_i(1, exp.file_status[GIT_DELTA_MODIFIED]); cl_assert_equal_i(0, exp.file_status[GIT_DELTA_IGNORED]); cl_assert_equal_i(0, exp.file_status[GIT_DELTA_UNTRACKED]); } git_diff_list_free(diff); pathspec = "subdir"; cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts)); for (use_iterator = 0; use_iterator <= 1; use_iterator++) { memset(&exp, 0, sizeof(exp)); if (use_iterator) cl_git_pass(diff_foreach_via_iterator( diff, diff_file_cb, NULL, NULL, &exp)); else cl_git_pass(git_diff_foreach(diff, diff_file_cb, NULL, NULL, &exp)); cl_assert_equal_i(3, exp.files); cl_assert_equal_i(0, exp.file_status[GIT_DELTA_ADDED]); cl_assert_equal_i(1, exp.file_status[GIT_DELTA_DELETED]); cl_assert_equal_i(1, exp.file_status[GIT_DELTA_MODIFIED]); cl_assert_equal_i(0, exp.file_status[GIT_DELTA_IGNORED]); cl_assert_equal_i(1, exp.file_status[GIT_DELTA_UNTRACKED]); } git_diff_list_free(diff); pathspec = "*_deleted"; cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts)); for (use_iterator = 0; use_iterator <= 1; use_iterator++) { memset(&exp, 0, sizeof(exp)); if (use_iterator) cl_git_pass(diff_foreach_via_iterator( diff, diff_file_cb, NULL, NULL, &exp)); else cl_git_pass(git_diff_foreach(diff, diff_file_cb, NULL, NULL, &exp)); cl_assert_equal_i(2, exp.files); cl_assert_equal_i(0, exp.file_status[GIT_DELTA_ADDED]); cl_assert_equal_i(2, exp.file_status[GIT_DELTA_DELETED]); cl_assert_equal_i(0, exp.file_status[GIT_DELTA_MODIFIED]); cl_assert_equal_i(0, exp.file_status[GIT_DELTA_IGNORED]); cl_assert_equal_i(0, exp.file_status[GIT_DELTA_UNTRACKED]); } git_diff_list_free(diff); } void test_diff_workdir__filemode_changes(void) { git_diff_list *diff = NULL; diff_expects exp; int use_iterator; if (!cl_is_chmod_supported()) return; g_repo = cl_git_sandbox_init("issue_592"); cl_repo_set_bool(g_repo, "core.filemode", true); /* test once with no mods */ cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, NULL)); for (use_iterator = 0; use_iterator <= 1; use_iterator++) { memset(&exp, 0, sizeof(exp)); if (use_iterator) cl_git_pass(diff_foreach_via_iterator( diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp)); else cl_git_pass(git_diff_foreach( diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp)); cl_assert_equal_i(0, exp.files); cl_assert_equal_i(0, exp.file_status[GIT_DELTA_MODIFIED]); cl_assert_equal_i(0, exp.hunks); } git_diff_list_free(diff); /* chmod file and test again */ cl_assert(cl_toggle_filemode("issue_592/a.txt")); cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, NULL)); for (use_iterator = 0; use_iterator <= 1; use_iterator++) { memset(&exp, 0, sizeof(exp)); if (use_iterator) cl_git_pass(diff_foreach_via_iterator( diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp)); else cl_git_pass(git_diff_foreach( diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp)); cl_assert_equal_i(1, exp.files); cl_assert_equal_i(1, exp.file_status[GIT_DELTA_MODIFIED]); cl_assert_equal_i(0, exp.hunks); } git_diff_list_free(diff); cl_assert(cl_toggle_filemode("issue_592/a.txt")); } void test_diff_workdir__filemode_changes_with_filemode_false(void) { git_diff_list *diff = NULL; diff_expects exp; if (!cl_is_chmod_supported()) return; g_repo = cl_git_sandbox_init("issue_592"); cl_repo_set_bool(g_repo, "core.filemode", false); /* test once with no mods */ cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, NULL)); memset(&exp, 0, sizeof(exp)); cl_git_pass(git_diff_foreach( diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp)); cl_assert_equal_i(0, exp.files); cl_assert_equal_i(0, exp.file_status[GIT_DELTA_MODIFIED]); cl_assert_equal_i(0, exp.hunks); git_diff_list_free(diff); /* chmod file and test again */ cl_assert(cl_toggle_filemode("issue_592/a.txt")); cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, NULL)); memset(&exp, 0, sizeof(exp)); cl_git_pass(git_diff_foreach( diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp)); cl_assert_equal_i(0, exp.files); cl_assert_equal_i(0, exp.file_status[GIT_DELTA_MODIFIED]); cl_assert_equal_i(0, exp.hunks); git_diff_list_free(diff); cl_assert(cl_toggle_filemode("issue_592/a.txt")); } void test_diff_workdir__head_index_and_workdir_all_differ(void) { git_diff_options opts = GIT_DIFF_OPTIONS_INIT; git_diff_list *diff_i2t = NULL, *diff_w2i = NULL; diff_expects exp; char *pathspec = "staged_changes_modified_file"; git_tree *tree; int use_iterator; /* For this file, * - head->index diff has 1 line of context, 1 line of diff * - index->workdir diff has 2 lines of context, 1 line of diff * but * - head->workdir diff has 1 line of context, 2 lines of diff * Let's make sure the right one is returned from each fn. */ g_repo = cl_git_sandbox_init("status"); tree = resolve_commit_oid_to_tree(g_repo, "26a125ee1bfc5df1e1b2e9441bbe63c8a7ae989f"); opts.pathspec.strings = &pathspec; opts.pathspec.count = 1; cl_git_pass(git_diff_tree_to_index(&diff_i2t, g_repo, tree, NULL, &opts)); cl_git_pass(git_diff_index_to_workdir(&diff_w2i, g_repo, NULL, &opts)); for (use_iterator = 0; use_iterator <= 1; use_iterator++) { memset(&exp, 0, sizeof(exp)); if (use_iterator) cl_git_pass(diff_foreach_via_iterator( diff_i2t, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp)); else cl_git_pass(git_diff_foreach( diff_i2t, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp)); cl_assert_equal_i(1, exp.files); cl_assert_equal_i(0, exp.file_status[GIT_DELTA_ADDED]); cl_assert_equal_i(0, exp.file_status[GIT_DELTA_DELETED]); cl_assert_equal_i(1, exp.file_status[GIT_DELTA_MODIFIED]); cl_assert_equal_i(1, exp.hunks); cl_assert_equal_i(2, exp.lines); cl_assert_equal_i(1, exp.line_ctxt); cl_assert_equal_i(1, exp.line_adds); cl_assert_equal_i(0, exp.line_dels); } for (use_iterator = 0; use_iterator <= 1; use_iterator++) { memset(&exp, 0, sizeof(exp)); if (use_iterator) cl_git_pass(diff_foreach_via_iterator( diff_w2i, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp)); else cl_git_pass(git_diff_foreach( diff_w2i, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp)); cl_assert_equal_i(1, exp.files); cl_assert_equal_i(0, exp.file_status[GIT_DELTA_ADDED]); cl_assert_equal_i(0, exp.file_status[GIT_DELTA_DELETED]); cl_assert_equal_i(1, exp.file_status[GIT_DELTA_MODIFIED]); cl_assert_equal_i(1, exp.hunks); cl_assert_equal_i(3, exp.lines); cl_assert_equal_i(2, exp.line_ctxt); cl_assert_equal_i(1, exp.line_adds); cl_assert_equal_i(0, exp.line_dels); } cl_git_pass(git_diff_merge(diff_i2t, diff_w2i)); for (use_iterator = 0; use_iterator <= 1; use_iterator++) { memset(&exp, 0, sizeof(exp)); if (use_iterator) cl_git_pass(diff_foreach_via_iterator( diff_i2t, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp)); else cl_git_pass(git_diff_foreach( diff_i2t, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp)); cl_assert_equal_i(1, exp.files); cl_assert_equal_i(0, exp.file_status[GIT_DELTA_ADDED]); cl_assert_equal_i(0, exp.file_status[GIT_DELTA_DELETED]); cl_assert_equal_i(1, exp.file_status[GIT_DELTA_MODIFIED]); cl_assert_equal_i(1, exp.hunks); cl_assert_equal_i(3, exp.lines); cl_assert_equal_i(1, exp.line_ctxt); cl_assert_equal_i(2, exp.line_adds); cl_assert_equal_i(0, exp.line_dels); } git_diff_list_free(diff_i2t); git_diff_list_free(diff_w2i); git_tree_free(tree); } void test_diff_workdir__eof_newline_changes(void) { git_diff_options opts = GIT_DIFF_OPTIONS_INIT; git_diff_list *diff = NULL; diff_expects exp; char *pathspec = "current_file"; int use_iterator; g_repo = cl_git_sandbox_init("status"); opts.pathspec.strings = &pathspec; opts.pathspec.count = 1; cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts)); for (use_iterator = 0; use_iterator <= 1; use_iterator++) { memset(&exp, 0, sizeof(exp)); if (use_iterator) cl_git_pass(diff_foreach_via_iterator( diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp)); else cl_git_pass(git_diff_foreach( diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp)); cl_assert_equal_i(0, exp.files); cl_assert_equal_i(0, exp.file_status[GIT_DELTA_ADDED]); cl_assert_equal_i(0, exp.file_status[GIT_DELTA_DELETED]); cl_assert_equal_i(0, exp.file_status[GIT_DELTA_MODIFIED]); cl_assert_equal_i(0, exp.hunks); cl_assert_equal_i(0, exp.lines); cl_assert_equal_i(0, exp.line_ctxt); cl_assert_equal_i(0, exp.line_adds); cl_assert_equal_i(0, exp.line_dels); } git_diff_list_free(diff); cl_git_append2file("status/current_file", "\n"); cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts)); for (use_iterator = 0; use_iterator <= 1; use_iterator++) { memset(&exp, 0, sizeof(exp)); if (use_iterator) cl_git_pass(diff_foreach_via_iterator( diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp)); else cl_git_pass(git_diff_foreach( diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp)); cl_assert_equal_i(1, exp.files); cl_assert_equal_i(0, exp.file_status[GIT_DELTA_ADDED]); cl_assert_equal_i(0, exp.file_status[GIT_DELTA_DELETED]); cl_assert_equal_i(1, exp.file_status[GIT_DELTA_MODIFIED]); cl_assert_equal_i(1, exp.hunks); cl_assert_equal_i(2, exp.lines); cl_assert_equal_i(1, exp.line_ctxt); cl_assert_equal_i(1, exp.line_adds); cl_assert_equal_i(0, exp.line_dels); } git_diff_list_free(diff); cl_git_rewritefile("status/current_file", "current_file"); cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts)); for (use_iterator = 0; use_iterator <= 1; use_iterator++) { memset(&exp, 0, sizeof(exp)); if (use_iterator) cl_git_pass(diff_foreach_via_iterator( diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp)); else cl_git_pass(git_diff_foreach( diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp)); cl_assert_equal_i(1, exp.files); cl_assert_equal_i(0, exp.file_status[GIT_DELTA_ADDED]); cl_assert_equal_i(0, exp.file_status[GIT_DELTA_DELETED]); cl_assert_equal_i(1, exp.file_status[GIT_DELTA_MODIFIED]); cl_assert_equal_i(1, exp.hunks); cl_assert_equal_i(3, exp.lines); cl_assert_equal_i(0, exp.line_ctxt); cl_assert_equal_i(1, exp.line_adds); cl_assert_equal_i(2, exp.line_dels); } git_diff_list_free(diff); } /* PREPARATION OF TEST DATA * * Since there is no command line equivalent of git_diff_tree_to_workdir, * it was a bit of a pain to confirm that I was getting the expected * results in the first part of this tests. Here is what I ended up * doing to set my expectation for the file counts and results: * * Running "git ls-tree 26a125" and "git ls-tree aa27a6" shows: * * A a0de7e0ac200c489c41c59dfa910154a70264e6e current_file * B 5452d32f1dd538eb0405e8a83cc185f79e25e80f file_deleted * C 452e4244b5d083ddf0460acf1ecc74db9dcfa11a modified_file * D 32504b727382542f9f089e24fddac5e78533e96c staged_changes * E 061d42a44cacde5726057b67558821d95db96f19 staged_changes_file_deleted * F 70bd9443ada07063e7fbf0b3ff5c13f7494d89c2 staged_changes_modified_file * G e9b9107f290627c04d097733a10055af941f6bca staged_delete_file_deleted * H dabc8af9bd6e9f5bbe96a176f1a24baf3d1f8916 staged_delete_modified_file * I 53ace0d1cc1145a5f4fe4f78a186a60263190733 subdir/current_file * J 1888c805345ba265b0ee9449b8877b6064592058 subdir/deleted_file * K a6191982709b746d5650e93c2acf34ef74e11504 subdir/modified_file * L e8ee89e15bbe9b20137715232387b3de5b28972e subdir.txt * * -------- * * find . ! -path ./.git/\* -a -type f | git hash-object --stdin-paths * * A a0de7e0ac200c489c41c59dfa910154a70264e6e current_file * M 6a79f808a9c6bc9531ac726c184bbcd9351ccf11 ignored_file * C 0a539630525aca2e7bc84975958f92f10a64c9b6 modified_file * N d4fa8600b4f37d7516bef4816ae2c64dbf029e3a new_file * D 55d316c9ba708999f1918e9677d01dfcae69c6b9 staged_changes * F 011c3440d5c596e21d836aa6d7b10eb581f68c49 staged_changes_modified_file * H dabc8af9bd6e9f5bbe96a176f1a24baf3d1f8916 staged_delete_modified_file * O 529a16e8e762d4acb7b9636ff540a00831f9155a staged_new_file * P 8b090c06d14ffa09c4e880088ebad33893f921d1 staged_new_file_modified_file * I 53ace0d1cc1145a5f4fe4f78a186a60263190733 subdir/current_file * K 57274b75eeb5f36fd55527806d567b2240a20c57 subdir/modified_file * Q 80a86a6931b91bc01c2dbf5ca55bdd24ad1ef466 subdir/new_file * L e8ee89e15bbe9b20137715232387b3de5b28972e subdir.txt * * -------- * * A - current_file (UNMODIFIED) -> not in results * B D file_deleted * M I ignored_file (IGNORED) * C M modified_file * N U new_file (UNTRACKED) * D M staged_changes * E D staged_changes_file_deleted * F M staged_changes_modified_file * G D staged_delete_file_deleted * H - staged_delete_modified_file (UNMODIFIED) -> not in results * O U staged_new_file * P U staged_new_file_modified_file * I - subdir/current_file (UNMODIFIED) -> not in results * J D subdir/deleted_file * K M subdir/modified_file * Q U subdir/new_file * L - subdir.txt (UNMODIFIED) -> not in results * * Expect 13 files, 0 ADD, 4 DEL, 4 MOD, 1 IGN, 4 UNTR */ void test_diff_workdir__larger_hunks(void) { const char *a_commit = "d70d245ed97ed2aa596dd1af6536e4bfdb047b69"; const char *b_commit = "7a9e0b02e63179929fed24f0a3e0f19168114d10"; git_tree *a, *b; git_diff_options opts = GIT_DIFF_OPTIONS_INIT; size_t i, d, num_d, h, num_h, l, num_l, header_len, line_len; g_repo = cl_git_sandbox_init("diff"); cl_assert((a = resolve_commit_oid_to_tree(g_repo, a_commit)) != NULL); cl_assert((b = resolve_commit_oid_to_tree(g_repo, b_commit)) != NULL); opts.context_lines = 1; opts.interhunk_lines = 0; for (i = 0; i <= 2; ++i) { git_diff_list *diff = NULL; git_diff_patch *patch; const git_diff_range *range; const char *header, *line; char origin; /* okay, this is a bit silly, but oh well */ switch (i) { case 0: cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts)); break; case 1: cl_git_pass(git_diff_tree_to_workdir(&diff, g_repo, a, &opts)); break; case 2: cl_git_pass(git_diff_tree_to_workdir(&diff, g_repo, b, &opts)); break; } num_d = git_diff_num_deltas(diff); cl_assert_equal_i(2, (int)num_d); for (d = 0; d < num_d; ++d) { cl_git_pass(git_diff_get_patch(&patch, NULL, diff, d)); cl_assert(patch); num_h = git_diff_patch_num_hunks(patch); for (h = 0; h < num_h; h++) { cl_git_pass(git_diff_patch_get_hunk( &range, &header, &header_len, &num_l, patch, h)); for (l = 0; l < num_l; ++l) { cl_git_pass(git_diff_patch_get_line_in_hunk( &origin, &line, &line_len, NULL, NULL, patch, h, l)); cl_assert(line); } /* confirm fail after the last item */ cl_git_fail(git_diff_patch_get_line_in_hunk( &origin, &line, &line_len, NULL, NULL, patch, h, num_l)); } /* confirm fail after the last item */ cl_git_fail(git_diff_patch_get_hunk( &range, &header, &header_len, &num_l, patch, num_h)); git_diff_patch_free(patch); } git_diff_list_free(diff); } git_tree_free(a); git_tree_free(b); } /* Set up a test that exercises this code. The easiest test using existing * test data is probably to create a sandbox of submod2 and then run a * git_diff_tree_to_workdir against tree * 873585b94bdeabccea991ea5e3ec1a277895b698. As for what you should actually * test, you can start by just checking that the number of lines of diff * content matches the actual output of git diff. That will at least * demonstrate that the submodule content is being used to generate somewhat * comparable outputs. It is a test that would fail without this code and * will succeed with it. */ #include "../submodule/submodule_helpers.h" void test_diff_workdir__submodules(void) { const char *a_commit = "873585b94bdeabccea991ea5e3ec1a277895b698"; git_tree *a; git_diff_options opts = GIT_DIFF_OPTIONS_INIT; git_diff_list *diff = NULL; diff_expects exp; g_repo = cl_git_sandbox_init("submod2"); cl_fixture_sandbox("submod2_target"); p_rename("submod2_target/.gitted", "submod2_target/.git"); rewrite_gitmodules(git_repository_workdir(g_repo)); p_rename("submod2/not-submodule/.gitted", "submod2/not-submodule/.git"); p_rename("submod2/not/.gitted", "submod2/not/.git"); cl_fixture_cleanup("submod2_target"); a = resolve_commit_oid_to_tree(g_repo, a_commit); opts.flags = GIT_DIFF_INCLUDE_UNTRACKED | GIT_DIFF_RECURSE_UNTRACKED_DIRS | GIT_DIFF_INCLUDE_UNTRACKED_CONTENT; cl_git_pass(git_diff_tree_to_workdir(&diff, g_repo, a, &opts)); /* diff_print(stderr, diff); */ /* essentially doing: git diff 873585b94bdeabccea991ea5e3ec1a277895b698 */ memset(&exp, 0, sizeof(exp)); cl_git_pass(git_diff_foreach( diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp)); /* so "git diff 873585" returns: * M .gitmodules * A just_a_dir/contents * A just_a_file * A sm_added_and_uncommited * A sm_changed_file * A sm_changed_head * A sm_changed_index * A sm_changed_untracked_file * M sm_missing_commits * A sm_unchanged * which is a little deceptive because of the difference between the * "git diff " results from "git_diff_tree_to_workdir". The * only significant difference is that those Added items will show up * as Untracked items in the pure libgit2 diff. * * Then add in the two extra untracked items "not" and "not-submodule" * to get the 12 files reported here. */ cl_assert_equal_i(12, exp.files); cl_assert_equal_i(0, exp.file_status[GIT_DELTA_ADDED]); cl_assert_equal_i(0, exp.file_status[GIT_DELTA_DELETED]); cl_assert_equal_i(2, exp.file_status[GIT_DELTA_MODIFIED]); cl_assert_equal_i(0, exp.file_status[GIT_DELTA_IGNORED]); cl_assert_equal_i(10, exp.file_status[GIT_DELTA_UNTRACKED]); /* the following numbers match "git diff 873585" exactly */ cl_assert_equal_i(9, exp.hunks); cl_assert_equal_i(33, exp.lines); cl_assert_equal_i(2, exp.line_ctxt); cl_assert_equal_i(30, exp.line_adds); cl_assert_equal_i(1, exp.line_dels); git_diff_list_free(diff); git_tree_free(a); } void test_diff_workdir__cannot_diff_against_a_bare_repository(void) { git_diff_options opts = GIT_DIFF_OPTIONS_INIT; git_diff_list *diff = NULL; git_tree *tree; g_repo = cl_git_sandbox_init("testrepo.git"); cl_assert_equal_i( GIT_EBAREREPO, git_diff_index_to_workdir(&diff, g_repo, NULL, &opts)); cl_git_pass(git_repository_head_tree(&tree, g_repo)); cl_assert_equal_i( GIT_EBAREREPO, git_diff_tree_to_workdir(&diff, g_repo, tree, &opts)); git_tree_free(tree); } void test_diff_workdir__to_null_tree(void) { git_diff_list *diff; diff_expects exp; git_diff_options opts = GIT_DIFF_OPTIONS_INIT; opts.flags = GIT_DIFF_INCLUDE_UNTRACKED | GIT_DIFF_RECURSE_UNTRACKED_DIRS; g_repo = cl_git_sandbox_init("status"); cl_git_pass(git_diff_tree_to_workdir(&diff, g_repo, NULL, &opts)); memset(&exp, 0, sizeof(exp)); cl_git_pass(git_diff_foreach( diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp)); cl_assert_equal_i(exp.files, exp.file_status[GIT_DELTA_UNTRACKED]); git_diff_list_free(diff); } void test_diff_workdir__checks_options_version(void) { git_diff_list *diff; git_diff_options opts = GIT_DIFF_OPTIONS_INIT; const git_error *err; g_repo = cl_git_sandbox_init("status"); opts.version = 0; cl_git_fail(git_diff_tree_to_workdir(&diff, g_repo, NULL, &opts)); err = giterr_last(); cl_assert_equal_i(GITERR_INVALID, err->klass); giterr_clear(); opts.version = 1024; cl_git_fail(git_diff_tree_to_workdir(&diff, g_repo, NULL, &opts)); err = giterr_last(); cl_assert_equal_i(GITERR_INVALID, err->klass); } void test_diff_workdir__can_diff_empty_file(void) { git_diff_list *diff; git_tree *tree; git_diff_options opts = GIT_DIFF_OPTIONS_INIT; struct stat st; git_diff_patch *patch; g_repo = cl_git_sandbox_init("attr_index"); tree = resolve_commit_oid_to_tree(g_repo, "3812cfef3661"); /* HEAD */ /* baseline - make sure there are no outstanding diffs */ cl_git_pass(git_diff_tree_to_workdir(&diff, g_repo, tree, &opts)); cl_assert_equal_i(2, (int)git_diff_num_deltas(diff)); git_diff_list_free(diff); /* empty contents of file */ cl_git_rewritefile("attr_index/README.txt", ""); cl_git_pass(git_path_lstat("attr_index/README.txt", &st)); cl_assert_equal_i(0, (int)st.st_size); cl_git_pass(git_diff_tree_to_workdir(&diff, g_repo, tree, &opts)); cl_assert_equal_i(3, (int)git_diff_num_deltas(diff)); /* diffs are: .gitattributes, README.txt, sub/sub/.gitattributes */ cl_git_pass(git_diff_get_patch(&patch, NULL, diff, 1)); git_diff_patch_free(patch); git_diff_list_free(diff); /* remove a file altogether */ cl_git_pass(p_unlink("attr_index/README.txt")); cl_assert(!git_path_exists("attr_index/README.txt")); cl_git_pass(git_diff_tree_to_workdir(&diff, g_repo, tree, &opts)); cl_assert_equal_i(3, (int)git_diff_num_deltas(diff)); cl_git_pass(git_diff_get_patch(&patch, NULL, diff, 1)); git_diff_patch_free(patch); git_diff_list_free(diff); git_tree_free(tree); } void test_diff_workdir__to_index_issue_1397(void) { git_diff_options opts = GIT_DIFF_OPTIONS_INIT; git_diff_list *diff = NULL; diff_expects exp; g_repo = cl_git_sandbox_init("issue_1397"); cl_repo_set_bool(g_repo, "core.autocrlf", true); opts.context_lines = 3; opts.interhunk_lines = 1; cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts)); memset(&exp, 0, sizeof(exp)); cl_git_pass(git_diff_foreach( diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp)); cl_assert_equal_i(0, exp.files); cl_assert_equal_i(0, exp.hunks); cl_assert_equal_i(0, exp.lines); git_diff_list_free(diff); diff = NULL; cl_git_rewritefile("issue_1397/crlf_file.txt", "first line\r\nsecond line modified\r\nboth with crlf"); cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts)); memset(&exp, 0, sizeof(exp)); cl_git_pass(git_diff_foreach( diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp)); cl_assert_equal_i(1, exp.files); cl_assert_equal_i(1, exp.file_status[GIT_DELTA_MODIFIED]); cl_assert_equal_i(1, exp.hunks); cl_assert_equal_i(5, exp.lines); cl_assert_equal_i(3, exp.line_ctxt); cl_assert_equal_i(1, exp.line_adds); cl_assert_equal_i(1, exp.line_dels); git_diff_list_free(diff); } void test_diff_workdir__to_tree_issue_1397(void) { const char *a_commit = "7f483a738"; /* the current HEAD */ git_tree *a; git_diff_options opts = GIT_DIFF_OPTIONS_INIT; git_diff_list *diff = NULL; git_diff_list *diff2 = NULL; diff_expects exp; g_repo = cl_git_sandbox_init("issue_1397"); cl_repo_set_bool(g_repo, "core.autocrlf", true); a = resolve_commit_oid_to_tree(g_repo, a_commit); opts.context_lines = 3; opts.interhunk_lines = 1; cl_git_pass(git_diff_tree_to_workdir(&diff, g_repo, a, &opts)); memset(&exp, 0, sizeof(exp)); cl_git_pass(git_diff_foreach( diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp)); cl_assert_equal_i(0, exp.files); cl_assert_equal_i(0, exp.hunks); cl_assert_equal_i(0, exp.lines); git_diff_list_free(diff); diff = NULL; cl_git_pass(git_diff_tree_to_index(&diff, g_repo, a, NULL, &opts)); cl_git_pass(git_diff_index_to_workdir(&diff2, g_repo, NULL, &opts)); cl_git_pass(git_diff_merge(diff, diff2)); git_diff_list_free(diff2); memset(&exp, 0, sizeof(exp)); cl_git_pass(git_diff_foreach( diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp)); cl_assert_equal_i(0, exp.files); cl_assert_equal_i(0, exp.hunks); cl_assert_equal_i(0, exp.lines); git_diff_list_free(diff); git_tree_free(a); } void test_diff_workdir__untracked_directory_scenarios(void) { git_diff_options opts = GIT_DIFF_OPTIONS_INIT; git_diff_list *diff = NULL; diff_expects exp; char *pathspec = NULL; static const char *files0[] = { "subdir/deleted_file", "subdir/modified_file", "subdir/new_file", NULL }; static const char *files1[] = { "subdir/deleted_file", "subdir/directory/", "subdir/modified_file", "subdir/new_file", NULL }; static const char *files2[] = { "subdir/deleted_file", "subdir/directory/more/notignored", "subdir/modified_file", "subdir/new_file", NULL }; g_repo = cl_git_sandbox_init("status"); cl_git_mkfile("status/.gitignore", "ignored\n"); opts.context_lines = 3; opts.interhunk_lines = 1; opts.flags |= GIT_DIFF_INCLUDE_IGNORED | GIT_DIFF_INCLUDE_UNTRACKED; opts.pathspec.strings = &pathspec; opts.pathspec.count = 1; pathspec = "subdir"; /* baseline for "subdir" pathspec */ memset(&exp, 0, sizeof(exp)); exp.names = files0; cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts)); cl_git_pass(git_diff_foreach(diff, diff_file_cb, NULL, NULL, &exp)); cl_assert_equal_i(3, exp.files); cl_assert_equal_i(0, exp.file_status[GIT_DELTA_ADDED]); cl_assert_equal_i(1, exp.file_status[GIT_DELTA_DELETED]); cl_assert_equal_i(1, exp.file_status[GIT_DELTA_MODIFIED]); cl_assert_equal_i(0, exp.file_status[GIT_DELTA_IGNORED]); cl_assert_equal_i(1, exp.file_status[GIT_DELTA_UNTRACKED]); git_diff_list_free(diff); /* empty directory */ cl_git_pass(p_mkdir("status/subdir/directory", 0777)); memset(&exp, 0, sizeof(exp)); exp.names = files1; cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts)); cl_git_pass(git_diff_foreach(diff, diff_file_cb, NULL, NULL, &exp)); cl_assert_equal_i(4, exp.files); cl_assert_equal_i(0, exp.file_status[GIT_DELTA_ADDED]); cl_assert_equal_i(1, exp.file_status[GIT_DELTA_DELETED]); cl_assert_equal_i(1, exp.file_status[GIT_DELTA_MODIFIED]); cl_assert_equal_i(1, exp.file_status[GIT_DELTA_IGNORED]); cl_assert_equal_i(1, exp.file_status[GIT_DELTA_UNTRACKED]); git_diff_list_free(diff); /* empty directory in empty directory */ cl_git_pass(p_mkdir("status/subdir/directory/empty", 0777)); memset(&exp, 0, sizeof(exp)); exp.names = files1; cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts)); cl_git_pass(git_diff_foreach(diff, diff_file_cb, NULL, NULL, &exp)); cl_assert_equal_i(4, exp.files); cl_assert_equal_i(0, exp.file_status[GIT_DELTA_ADDED]); cl_assert_equal_i(1, exp.file_status[GIT_DELTA_DELETED]); cl_assert_equal_i(1, exp.file_status[GIT_DELTA_MODIFIED]); cl_assert_equal_i(1, exp.file_status[GIT_DELTA_IGNORED]); cl_assert_equal_i(1, exp.file_status[GIT_DELTA_UNTRACKED]); git_diff_list_free(diff); /* directory with only ignored files */ cl_git_pass(p_mkdir("status/subdir/directory/deeper", 0777)); cl_git_mkfile("status/subdir/directory/deeper/ignored", "ignore me\n"); cl_git_pass(p_mkdir("status/subdir/directory/another", 0777)); cl_git_mkfile("status/subdir/directory/another/ignored", "ignore me\n"); memset(&exp, 0, sizeof(exp)); exp.names = files1; cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts)); cl_git_pass(git_diff_foreach(diff, diff_file_cb, NULL, NULL, &exp)); cl_assert_equal_i(4, exp.files); cl_assert_equal_i(0, exp.file_status[GIT_DELTA_ADDED]); cl_assert_equal_i(1, exp.file_status[GIT_DELTA_DELETED]); cl_assert_equal_i(1, exp.file_status[GIT_DELTA_MODIFIED]); cl_assert_equal_i(1, exp.file_status[GIT_DELTA_IGNORED]); cl_assert_equal_i(1, exp.file_status[GIT_DELTA_UNTRACKED]); git_diff_list_free(diff); /* directory with ignored directory (contents irrelevant) */ cl_git_pass(p_mkdir("status/subdir/directory/more", 0777)); cl_git_pass(p_mkdir("status/subdir/directory/more/ignored", 0777)); cl_git_mkfile("status/subdir/directory/more/ignored/notignored", "inside ignored dir\n"); memset(&exp, 0, sizeof(exp)); exp.names = files1; cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts)); cl_git_pass(git_diff_foreach(diff, diff_file_cb, NULL, NULL, &exp)); cl_assert_equal_i(4, exp.files); cl_assert_equal_i(0, exp.file_status[GIT_DELTA_ADDED]); cl_assert_equal_i(1, exp.file_status[GIT_DELTA_DELETED]); cl_assert_equal_i(1, exp.file_status[GIT_DELTA_MODIFIED]); cl_assert_equal_i(1, exp.file_status[GIT_DELTA_IGNORED]); cl_assert_equal_i(1, exp.file_status[GIT_DELTA_UNTRACKED]); git_diff_list_free(diff); /* quick version avoids directory scan */ opts.flags = opts.flags | GIT_DIFF_FAST_UNTRACKED_DIRS; memset(&exp, 0, sizeof(exp)); exp.names = files1; cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts)); cl_git_pass(git_diff_foreach(diff, diff_file_cb, NULL, NULL, &exp)); cl_assert_equal_i(4, exp.files); cl_assert_equal_i(0, exp.file_status[GIT_DELTA_ADDED]); cl_assert_equal_i(1, exp.file_status[GIT_DELTA_DELETED]); cl_assert_equal_i(1, exp.file_status[GIT_DELTA_MODIFIED]); cl_assert_equal_i(0, exp.file_status[GIT_DELTA_IGNORED]); cl_assert_equal_i(2, exp.file_status[GIT_DELTA_UNTRACKED]); git_diff_list_free(diff); /* directory with nested non-ignored content */ opts.flags = opts.flags & ~GIT_DIFF_FAST_UNTRACKED_DIRS; cl_git_mkfile("status/subdir/directory/more/notignored", "not ignored deep under untracked\n"); memset(&exp, 0, sizeof(exp)); exp.names = files1; cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts)); cl_git_pass(git_diff_foreach(diff, diff_file_cb, NULL, NULL, &exp)); cl_assert_equal_i(4, exp.files); cl_assert_equal_i(0, exp.file_status[GIT_DELTA_ADDED]); cl_assert_equal_i(1, exp.file_status[GIT_DELTA_DELETED]); cl_assert_equal_i(1, exp.file_status[GIT_DELTA_MODIFIED]); cl_assert_equal_i(0, exp.file_status[GIT_DELTA_IGNORED]); cl_assert_equal_i(2, exp.file_status[GIT_DELTA_UNTRACKED]); git_diff_list_free(diff); /* use RECURSE_UNTRACKED_DIRS to get actual untracked files (no ignores) */ opts.flags = opts.flags & ~GIT_DIFF_INCLUDE_IGNORED; opts.flags = opts.flags | GIT_DIFF_RECURSE_UNTRACKED_DIRS; memset(&exp, 0, sizeof(exp)); exp.names = files2; cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts)); cl_git_pass(git_diff_foreach(diff, diff_file_cb, NULL, NULL, &exp)); cl_assert_equal_i(4, exp.files); cl_assert_equal_i(0, exp.file_status[GIT_DELTA_ADDED]); cl_assert_equal_i(1, exp.file_status[GIT_DELTA_DELETED]); cl_assert_equal_i(1, exp.file_status[GIT_DELTA_MODIFIED]); cl_assert_equal_i(0, exp.file_status[GIT_DELTA_IGNORED]); cl_assert_equal_i(2, exp.file_status[GIT_DELTA_UNTRACKED]); git_diff_list_free(diff); } void test_diff_workdir__untracked_directory_comes_last(void) { git_diff_options opts = GIT_DIFF_OPTIONS_INIT; git_diff_list *diff = NULL; g_repo = cl_git_sandbox_init("renames"); cl_git_mkfile("renames/.gitignore", "*.ign\n"); cl_git_pass(p_mkdir("renames/zzz_untracked", 0777)); cl_git_mkfile("renames/zzz_untracked/an.ign", "ignore me please"); cl_git_mkfile("renames/zzz_untracked/skip.ign", "ignore me really"); cl_git_mkfile("renames/zzz_untracked/test.ign", "ignore me now"); opts.context_lines = 3; opts.interhunk_lines = 1; opts.flags |= GIT_DIFF_INCLUDE_IGNORED | GIT_DIFF_INCLUDE_UNTRACKED; cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts)); cl_assert(diff != NULL); git_diff_list_free(diff); } libgit2-0.19.0/tests-clar/fetchhead/000077500000000000000000000000001216214232500171275ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/fetchhead/fetchhead_data.h000066400000000000000000000053531216214232500222120ustar00rootroot00000000000000 #define FETCH_HEAD_WILDCARD_DATA_LOCAL \ "49322bb17d3acc9146f98c97d078513228bbf3c0\t\tbranch 'master' of git://github.com/libgit2/TestGitRepository\n" \ "0966a434eb1a025db6b71485ab63a3bfbea520b6\tnot-for-merge\tbranch 'first-merge' of git://github.com/libgit2/TestGitRepository\n" \ "42e4e7c5e507e113ebbb7801b16b52cf867b7ce1\tnot-for-merge\tbranch 'no-parent' of git://github.com/libgit2/TestGitRepository\n" \ "d96c4e80345534eccee5ac7b07fc7603b56124cb\tnot-for-merge\ttag 'annotated_tag' of git://github.com/libgit2/TestGitRepository\n" \ "55a1a760df4b86a02094a904dfa511deb5655905\tnot-for-merge\ttag 'blob' of git://github.com/libgit2/TestGitRepository\n" \ "8f50ba15d49353813cc6e20298002c0d17b0a9ee\tnot-for-merge\ttag 'commit_tree' of git://github.com/libgit2/TestGitRepository\n" #define FETCH_HEAD_WILDCARD_DATA \ "49322bb17d3acc9146f98c97d078513228bbf3c0\t\tbranch 'master' of git://github.com/libgit2/TestGitRepository\n" \ "0966a434eb1a025db6b71485ab63a3bfbea520b6\tnot-for-merge\tbranch 'first-merge' of git://github.com/libgit2/TestGitRepository\n" \ "42e4e7c5e507e113ebbb7801b16b52cf867b7ce1\tnot-for-merge\tbranch 'no-parent' of git://github.com/libgit2/TestGitRepository\n" \ "d96c4e80345534eccee5ac7b07fc7603b56124cb\tnot-for-merge\ttag 'annotated_tag' of git://github.com/libgit2/TestGitRepository\n" \ "55a1a760df4b86a02094a904dfa511deb5655905\tnot-for-merge\ttag 'blob' of git://github.com/libgit2/TestGitRepository\n" \ "8f50ba15d49353813cc6e20298002c0d17b0a9ee\tnot-for-merge\ttag 'commit_tree' of git://github.com/libgit2/TestGitRepository\n" \ "6e0c7bdb9b4ed93212491ee778ca1c65047cab4e\tnot-for-merge\ttag 'nearly-dangling' of git://github.com/libgit2/TestGitRepository\n" #define FETCH_HEAD_NO_MERGE_DATA \ "0966a434eb1a025db6b71485ab63a3bfbea520b6\tnot-for-merge\tbranch 'first-merge' of git://github.com/libgit2/TestGitRepository\n" \ "49322bb17d3acc9146f98c97d078513228bbf3c0\tnot-for-merge\tbranch 'master' of git://github.com/libgit2/TestGitRepository\n" \ "42e4e7c5e507e113ebbb7801b16b52cf867b7ce1\tnot-for-merge\tbranch 'no-parent' of git://github.com/libgit2/TestGitRepository\n" \ "d96c4e80345534eccee5ac7b07fc7603b56124cb\tnot-for-merge\ttag 'annotated_tag' of git://github.com/libgit2/TestGitRepository\n" \ "55a1a760df4b86a02094a904dfa511deb5655905\tnot-for-merge\ttag 'blob' of git://github.com/libgit2/TestGitRepository\n" \ "8f50ba15d49353813cc6e20298002c0d17b0a9ee\tnot-for-merge\ttag 'commit_tree' of git://github.com/libgit2/TestGitRepository\n" \ "6e0c7bdb9b4ed93212491ee778ca1c65047cab4e\tnot-for-merge\ttag 'nearly-dangling' of git://github.com/libgit2/TestGitRepository\n" #define FETCH_HEAD_EXPLICIT_DATA \ "0966a434eb1a025db6b71485ab63a3bfbea520b6\t\tbranch 'first-merge' of git://github.com/libgit2/TestGitRepository\n" libgit2-0.19.0/tests-clar/fetchhead/nonetwork.c000066400000000000000000000207461216214232500213320ustar00rootroot00000000000000#include "clar_libgit2.h" #include "fileops.h" #include "fetchhead.h" #include "fetchhead_data.h" #define DO_LOCAL_TEST 0 static git_repository *g_repo; void test_fetchhead_nonetwork__initialize(void) { g_repo = NULL; } static void cleanup_repository(void *path) { if (g_repo) { git_repository_free(g_repo); g_repo = NULL; } cl_fixture_cleanup((const char *)path); } static void populate_fetchhead(git_vector *out, git_repository *repo) { git_fetchhead_ref *fetchhead_ref; git_oid oid; cl_git_pass(git_oid_fromstr(&oid, "49322bb17d3acc9146f98c97d078513228bbf3c0")); cl_git_pass(git_fetchhead_ref_create(&fetchhead_ref, &oid, 1, "refs/heads/master", "git://github.com/libgit2/TestGitRepository")); cl_git_pass(git_vector_insert(out, fetchhead_ref)); cl_git_pass(git_oid_fromstr(&oid, "0966a434eb1a025db6b71485ab63a3bfbea520b6")); cl_git_pass(git_fetchhead_ref_create(&fetchhead_ref, &oid, 0, "refs/heads/first-merge", "git://github.com/libgit2/TestGitRepository")); cl_git_pass(git_vector_insert(out, fetchhead_ref)); cl_git_pass(git_oid_fromstr(&oid, "42e4e7c5e507e113ebbb7801b16b52cf867b7ce1")); cl_git_pass(git_fetchhead_ref_create(&fetchhead_ref, &oid, 0, "refs/heads/no-parent", "git://github.com/libgit2/TestGitRepository")); cl_git_pass(git_vector_insert(out, fetchhead_ref)); cl_git_pass(git_oid_fromstr(&oid, "d96c4e80345534eccee5ac7b07fc7603b56124cb")); cl_git_pass(git_fetchhead_ref_create(&fetchhead_ref, &oid, 0, "refs/tags/annotated_tag", "git://github.com/libgit2/TestGitRepository")); cl_git_pass(git_vector_insert(out, fetchhead_ref)); cl_git_pass(git_oid_fromstr(&oid, "55a1a760df4b86a02094a904dfa511deb5655905")); cl_git_pass(git_fetchhead_ref_create(&fetchhead_ref, &oid, 0, "refs/tags/blob", "git://github.com/libgit2/TestGitRepository")); cl_git_pass(git_vector_insert(out, fetchhead_ref)); cl_git_pass(git_oid_fromstr(&oid, "8f50ba15d49353813cc6e20298002c0d17b0a9ee")); cl_git_pass(git_fetchhead_ref_create(&fetchhead_ref, &oid, 0, "refs/tags/commit_tree", "git://github.com/libgit2/TestGitRepository")); cl_git_pass(git_vector_insert(out, fetchhead_ref)); cl_git_pass(git_fetchhead_write(repo, out)); } void test_fetchhead_nonetwork__write(void) { git_vector fetchhead_vector = GIT_VECTOR_INIT; git_fetchhead_ref *fetchhead_ref; git_buf fetchhead_buf = GIT_BUF_INIT; int equals = 0; size_t i; git_vector_init(&fetchhead_vector, 6, NULL); cl_set_cleanup(&cleanup_repository, "./test1"); cl_git_pass(git_repository_init(&g_repo, "./test1", 0)); populate_fetchhead(&fetchhead_vector, g_repo); cl_git_pass(git_futils_readbuffer(&fetchhead_buf, "./test1/.git/FETCH_HEAD")); equals = (strcmp(fetchhead_buf.ptr, FETCH_HEAD_WILDCARD_DATA_LOCAL) == 0); git_buf_free(&fetchhead_buf); git_vector_foreach(&fetchhead_vector, i, fetchhead_ref) { git_fetchhead_ref_free(fetchhead_ref); } git_vector_free(&fetchhead_vector); cl_assert(equals); } typedef struct { git_vector *fetchhead_vector; size_t idx; } fetchhead_ref_cb_data; static int fetchhead_ref_cb(const char *name, const char *url, const git_oid *oid, unsigned int is_merge, void *payload) { fetchhead_ref_cb_data *cb_data = payload; git_fetchhead_ref *expected; cl_assert(payload); expected = git_vector_get(cb_data->fetchhead_vector, cb_data->idx); cl_assert(git_oid_cmp(&expected->oid, oid) == 0); cl_assert(expected->is_merge == is_merge); if (expected->ref_name) cl_assert_equal_s(expected->ref_name, name); else cl_assert(name == NULL); if (expected->remote_url) cl_assert_equal_s(expected->remote_url, url); else cl_assert(url == NULL); cb_data->idx++; return 0; } void test_fetchhead_nonetwork__read(void) { git_vector fetchhead_vector = GIT_VECTOR_INIT; git_fetchhead_ref *fetchhead_ref; fetchhead_ref_cb_data cb_data; size_t i; memset(&cb_data, 0x0, sizeof(fetchhead_ref_cb_data)); cl_set_cleanup(&cleanup_repository, "./test1"); cl_git_pass(git_repository_init(&g_repo, "./test1", 0)); populate_fetchhead(&fetchhead_vector, g_repo); cb_data.fetchhead_vector = &fetchhead_vector; cl_git_pass(git_repository_fetchhead_foreach(g_repo, fetchhead_ref_cb, &cb_data)); git_vector_foreach(&fetchhead_vector, i, fetchhead_ref) { git_fetchhead_ref_free(fetchhead_ref); } git_vector_free(&fetchhead_vector); } static int read_old_style_cb(const char *name, const char *url, const git_oid *oid, unsigned int is_merge, void *payload) { git_oid expected; GIT_UNUSED(payload); git_oid_fromstr(&expected, "49322bb17d3acc9146f98c97d078513228bbf3c0"); cl_assert(name == NULL); cl_assert(url == NULL); cl_assert(git_oid_cmp(&expected, oid) == 0); cl_assert(is_merge == 1); return 0; } void test_fetchhead_nonetwork__read_old_style(void) { cl_set_cleanup(&cleanup_repository, "./test1"); cl_git_pass(git_repository_init(&g_repo, "./test1", 0)); cl_git_rewritefile("./test1/.git/FETCH_HEAD", "49322bb17d3acc9146f98c97d078513228bbf3c0\n"); cl_git_pass(git_repository_fetchhead_foreach(g_repo, read_old_style_cb, NULL)); } static int read_type_missing(const char *ref_name, const char *remote_url, const git_oid *oid, unsigned int is_merge, void *payload) { git_oid expected; GIT_UNUSED(payload); git_oid_fromstr(&expected, "49322bb17d3acc9146f98c97d078513228bbf3c0"); cl_assert_equal_s("name", ref_name); cl_assert_equal_s("remote_url", remote_url); cl_assert(git_oid_cmp(&expected, oid) == 0); cl_assert(is_merge == 0); return 0; } void test_fetchhead_nonetwork__type_missing(void) { cl_set_cleanup(&cleanup_repository, "./test1"); cl_git_pass(git_repository_init(&g_repo, "./test1", 0)); cl_git_rewritefile("./test1/.git/FETCH_HEAD", "49322bb17d3acc9146f98c97d078513228bbf3c0\tnot-for-merge\t'name' of remote_url\n"); cl_git_pass(git_repository_fetchhead_foreach(g_repo, read_type_missing, NULL)); } static int read_name_missing(const char *ref_name, const char *remote_url, const git_oid *oid, unsigned int is_merge, void *payload) { git_oid expected; GIT_UNUSED(payload); git_oid_fromstr(&expected, "49322bb17d3acc9146f98c97d078513228bbf3c0"); cl_assert(ref_name == NULL); cl_assert_equal_s("remote_url", remote_url); cl_assert(git_oid_cmp(&expected, oid) == 0); cl_assert(is_merge == 0); return 0; } void test_fetchhead_nonetwork__name_missing(void) { cl_set_cleanup(&cleanup_repository, "./test1"); cl_git_pass(git_repository_init(&g_repo, "./test1", 0)); cl_git_rewritefile("./test1/.git/FETCH_HEAD", "49322bb17d3acc9146f98c97d078513228bbf3c0\tnot-for-merge\tremote_url\n"); cl_git_pass(git_repository_fetchhead_foreach(g_repo, read_name_missing, NULL)); } static int read_noop(const char *ref_name, const char *remote_url, const git_oid *oid, unsigned int is_merge, void *payload) { GIT_UNUSED(ref_name); GIT_UNUSED(remote_url); GIT_UNUSED(oid); GIT_UNUSED(is_merge); GIT_UNUSED(payload); return 0; } void test_fetchhead_nonetwork__nonexistent(void) { int error; cl_set_cleanup(&cleanup_repository, "./test1"); cl_git_pass(git_repository_init(&g_repo, "./test1", 0)); cl_git_fail((error = git_repository_fetchhead_foreach(g_repo, read_noop, NULL))); cl_assert(error == GIT_ENOTFOUND); } void test_fetchhead_nonetwork__invalid_unterminated_last_line(void) { cl_set_cleanup(&cleanup_repository, "./test1"); cl_git_pass(git_repository_init(&g_repo, "./test1", 0)); cl_git_rewritefile("./test1/.git/FETCH_HEAD", "unterminated"); cl_git_fail(git_repository_fetchhead_foreach(g_repo, read_noop, NULL)); } void test_fetchhead_nonetwork__invalid_oid(void) { cl_set_cleanup(&cleanup_repository, "./test1"); cl_git_pass(git_repository_init(&g_repo, "./test1", 0)); cl_git_rewritefile("./test1/.git/FETCH_HEAD", "shortoid\n"); cl_git_fail(git_repository_fetchhead_foreach(g_repo, read_noop, NULL)); } void test_fetchhead_nonetwork__invalid_for_merge(void) { cl_set_cleanup(&cleanup_repository, "./test1"); cl_git_pass(git_repository_init(&g_repo, "./test1", 0)); cl_git_rewritefile("./test1/.git/FETCH_HEAD", "49322bb17d3acc9146f98c97d078513228bbf3c0\tinvalid-merge\t\n"); cl_git_fail(git_repository_fetchhead_foreach(g_repo, read_noop, NULL)); cl_assert(git__prefixcmp(giterr_last()->message, "Invalid for-merge") == 0); } void test_fetchhead_nonetwork__invalid_description(void) { cl_set_cleanup(&cleanup_repository, "./test1"); cl_git_pass(git_repository_init(&g_repo, "./test1", 0)); cl_git_rewritefile("./test1/.git/FETCH_HEAD", "49322bb17d3acc9146f98c97d078513228bbf3c0\tnot-for-merge\n"); cl_git_fail(git_repository_fetchhead_foreach(g_repo, read_noop, NULL)); cl_assert(git__prefixcmp(giterr_last()->message, "Invalid description") == 0); } libgit2-0.19.0/tests-clar/generate.py000066400000000000000000000163721216214232500173710ustar00rootroot00000000000000#!/usr/bin/env python # # Copyright (c) Vicent Marti. All rights reserved. # # This file is part of clar, distributed under the ISC license. # For full terms see the included COPYING file. # from __future__ import with_statement from string import Template import re, fnmatch, os, codecs, pickle class Module(object): class Template(object): def __init__(self, module): self.module = module def _render_callback(self, cb): if not cb: return ' { NULL, NULL }' return ' { "%s", &%s }' % (cb['short_name'], cb['symbol']) class DeclarationTemplate(Template): def render(self): out = "\n".join("extern %s;" % cb['declaration'] for cb in self.module.callbacks) + "\n" if self.module.initialize: out += "extern %s;\n" % self.module.initialize['declaration'] if self.module.cleanup: out += "extern %s;\n" % self.module.cleanup['declaration'] return out class CallbacksTemplate(Template): def render(self): out = "static const struct clar_func _clar_cb_%s[] = {\n" % self.module.name out += ",\n".join(self._render_callback(cb) for cb in self.module.callbacks) out += "\n};\n" return out class InfoTemplate(Template): def render(self): return Template( r""" { "${clean_name}", ${initialize}, ${cleanup}, ${cb_ptr}, ${cb_count}, ${enabled} }""" ).substitute( clean_name = self.module.clean_name(), initialize = self._render_callback(self.module.initialize), cleanup = self._render_callback(self.module.cleanup), cb_ptr = "_clar_cb_%s" % self.module.name, cb_count = len(self.module.callbacks), enabled = int(self.module.enabled) ) def __init__(self, name): self.name = name self.mtime = 0 self.enabled = True self.modified = False def clean_name(self): return self.name.replace("_", "::") def _skip_comments(self, text): SKIP_COMMENTS_REGEX = re.compile( r'//.*?$|/\*.*?\*/|\'(?:\\.|[^\\\'])*\'|"(?:\\.|[^\\"])*"', re.DOTALL | re.MULTILINE) def _replacer(match): s = match.group(0) return "" if s.startswith('/') else s return re.sub(SKIP_COMMENTS_REGEX, _replacer, text) def parse(self, contents): TEST_FUNC_REGEX = r"^(void\s+(test_%s__(\w+))\(\s*void\s*\))\s*\{" contents = self._skip_comments(contents) regex = re.compile(TEST_FUNC_REGEX % self.name, re.MULTILINE) self.callbacks = [] self.initialize = None self.cleanup = None for (declaration, symbol, short_name) in regex.findall(contents): data = { "short_name" : short_name, "declaration" : declaration, "symbol" : symbol } if short_name == 'initialize': self.initialize = data elif short_name == 'cleanup': self.cleanup = data else: self.callbacks.append(data) return self.callbacks != [] def refresh(self, path): self.modified = False try: st = os.stat(path) # Not modified if st.st_mtime == self.mtime: return True self.modified = True self.mtime = st.st_mtime with open(path) as fp: raw_content = fp.read() except IOError: return False return self.parse(raw_content) class TestSuite(object): def __init__(self, path): self.path = path def should_generate(self, path): if not os.path.isfile(path): return True if any(module.modified for module in self.modules.values()): return True return False def find_modules(self): modules = [] for root, _, files in os.walk(self.path): module_root = root[len(self.path):] module_root = [c for c in module_root.split(os.sep) if c] tests_in_module = fnmatch.filter(files, "*.c") for test_file in tests_in_module: full_path = os.path.join(root, test_file) module_name = "_".join(module_root + [test_file[:-2]]) modules.append((full_path, module_name)) return modules def load_cache(self): path = os.path.join(self.path, '.clarcache') cache = {} try: fp = open(path, 'rb') cache = pickle.load(fp) fp.close() except (IOError, ValueError): pass return cache def save_cache(self): path = os.path.join(self.path, '.clarcache') with open(path, 'wb') as cache: pickle.dump(self.modules, cache) def load(self, force = False): module_data = self.find_modules() self.modules = {} if force else self.load_cache() for path, name in module_data: if name not in self.modules: self.modules[name] = Module(name) if not self.modules[name].refresh(path): del self.modules[name] def disable(self, excluded): for exclude in excluded: for module in self.modules.values(): name = module.clean_name() if name.startswith(exclude): module.enabled = False module.modified = True def suite_count(self): return len(self.modules) def callback_count(self): return sum(len(module.callbacks) for module in self.modules.values()) def write(self): output = os.path.join(self.path, 'clar.suite') if not self.should_generate(output): return False with open(output, 'w') as data: for module in self.modules.values(): t = Module.DeclarationTemplate(module) data.write(t.render()) for module in self.modules.values(): t = Module.CallbacksTemplate(module) data.write(t.render()) suites = "static struct clar_suite _clar_suites[] = {" + ','.join( Module.InfoTemplate(module).render() for module in sorted(self.modules.values(), key=lambda module: module.name) ) + "\n};\n" data.write(suites) data.write("static const size_t _clar_suite_count = %d;\n" % self.suite_count()) data.write("static const size_t _clar_callback_count = %d;\n" % self.callback_count()) suite.save_cache() return True if __name__ == '__main__': from optparse import OptionParser parser = OptionParser() parser.add_option('-f', '--force', dest='force', default=False) parser.add_option('-x', '--exclude', dest='excluded', action='append', default=[]) options, args = parser.parse_args() for path in args or ['.']: suite = TestSuite(path) suite.load(options.force) suite.disable(options.excluded) if suite.write(): print("Written `clar.suite` (%d tests in %d suites)" % (suite.callback_count(), suite.suite_count())) libgit2-0.19.0/tests-clar/index/000077500000000000000000000000001216214232500163235ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/index/addall.c000066400000000000000000000201041216214232500177050ustar00rootroot00000000000000#include "clar_libgit2.h" #include "../status/status_helpers.h" #include "posix.h" git_repository *g_repo = NULL; void test_index_addall__initialize(void) { } void test_index_addall__cleanup(void) { git_repository_free(g_repo); g_repo = NULL; } #define STATUS_INDEX_FLAGS \ (GIT_STATUS_INDEX_NEW | GIT_STATUS_INDEX_MODIFIED | \ GIT_STATUS_INDEX_DELETED | GIT_STATUS_INDEX_RENAMED | \ GIT_STATUS_INDEX_TYPECHANGE) #define STATUS_WT_FLAGS \ (GIT_STATUS_WT_NEW | GIT_STATUS_WT_MODIFIED | \ GIT_STATUS_WT_DELETED | GIT_STATUS_WT_TYPECHANGE | \ GIT_STATUS_WT_RENAMED) typedef struct { size_t index_adds; size_t index_dels; size_t index_mods; size_t wt_adds; size_t wt_dels; size_t wt_mods; size_t ignores; } index_status_counts; static int index_status_cb( const char *path, unsigned int status_flags, void *payload) { index_status_counts *vals = payload; /* cb_status__print(path, status_flags, NULL); */ GIT_UNUSED(path); if (status_flags & GIT_STATUS_INDEX_NEW) vals->index_adds++; if (status_flags & GIT_STATUS_INDEX_MODIFIED) vals->index_mods++; if (status_flags & GIT_STATUS_INDEX_DELETED) vals->index_dels++; if (status_flags & GIT_STATUS_INDEX_TYPECHANGE) vals->index_mods++; if (status_flags & GIT_STATUS_WT_NEW) vals->wt_adds++; if (status_flags & GIT_STATUS_WT_MODIFIED) vals->wt_mods++; if (status_flags & GIT_STATUS_WT_DELETED) vals->wt_dels++; if (status_flags & GIT_STATUS_WT_TYPECHANGE) vals->wt_mods++; if (status_flags & GIT_STATUS_IGNORED) vals->ignores++; return 0; } static void check_status( git_repository *repo, size_t index_adds, size_t index_dels, size_t index_mods, size_t wt_adds, size_t wt_dels, size_t wt_mods, size_t ignores) { index_status_counts vals; memset(&vals, 0, sizeof(vals)); cl_git_pass(git_status_foreach(repo, index_status_cb, &vals)); cl_assert_equal_sz(index_adds, vals.index_adds); cl_assert_equal_sz(index_dels, vals.index_dels); cl_assert_equal_sz(index_mods, vals.index_mods); cl_assert_equal_sz(wt_adds, vals.wt_adds); cl_assert_equal_sz(wt_dels, vals.wt_dels); cl_assert_equal_sz(wt_mods, vals.wt_mods); cl_assert_equal_sz(ignores, vals.ignores); } static void check_stat_data(git_index *index, const char *path, bool match) { const git_index_entry *entry; struct stat st; cl_must_pass(p_lstat(path, &st)); /* skip repo base dir name */ while (*path != '/') ++path; ++path; entry = git_index_get_bypath(index, path, 0); cl_assert(entry); if (match) { cl_assert(st.st_ctime == entry->ctime.seconds); cl_assert(st.st_mtime == entry->mtime.seconds); cl_assert(st.st_size == entry->file_size); cl_assert(st.st_uid == entry->uid); cl_assert(st.st_gid == entry->gid); cl_assert_equal_b(st.st_mode & ~0777, entry->mode & ~0777); cl_assert_equal_b(st.st_mode & 0111, entry->mode & 0111); } else { /* most things will still match */ cl_assert(st.st_size != entry->file_size); /* would check mtime, but with second resolution it won't work :( */ } } static void commit_index_to_head( git_repository *repo, const char *commit_message) { git_index *index; git_oid tree_id, commit_id; git_tree *tree; git_signature *sig; git_commit *parent = NULL; git_revparse_single((git_object **)&parent, repo, "HEAD"); /* it is okay if looking up the HEAD fails */ cl_git_pass(git_repository_index(&index, repo)); cl_git_pass(git_index_write_tree(&tree_id, index)); cl_git_pass(git_index_write(index)); /* not needed, but might as well */ git_index_free(index); cl_git_pass(git_tree_lookup(&tree, repo, &tree_id)); cl_git_pass(git_signature_now(&sig, "Testy McTester", "tt@tester.test")); cl_git_pass(git_commit_create_v( &commit_id, repo, "HEAD", sig, sig, NULL, commit_message, tree, parent ? 1 : 0, parent)); git_commit_free(parent); git_tree_free(tree); git_signature_free(sig); } void test_index_addall__repo_lifecycle(void) { int error; git_index *index; git_strarray paths = { NULL, 0 }; char *strs[1]; cl_git_pass(git_repository_init(&g_repo, "addall", false)); check_status(g_repo, 0, 0, 0, 0, 0, 0, 0); cl_git_pass(git_repository_index(&index, g_repo)); cl_git_mkfile("addall/file.foo", "a file"); check_status(g_repo, 0, 0, 0, 1, 0, 0, 0); cl_git_mkfile("addall/.gitignore", "*.foo\n"); check_status(g_repo, 0, 0, 0, 1, 0, 0, 1); cl_git_mkfile("addall/file.bar", "another file"); check_status(g_repo, 0, 0, 0, 2, 0, 0, 1); strs[0] = "file.*"; paths.strings = strs; paths.count = 1; cl_git_pass(git_index_add_all(index, &paths, 0, NULL, NULL)); check_stat_data(index, "addall/file.bar", true); check_status(g_repo, 1, 0, 0, 1, 0, 0, 1); cl_git_rewritefile("addall/file.bar", "new content for file"); check_stat_data(index, "addall/file.bar", false); check_status(g_repo, 1, 0, 0, 1, 0, 1, 1); cl_git_mkfile("addall/file.zzz", "yet another one"); cl_git_mkfile("addall/other.zzz", "yet another one"); cl_git_mkfile("addall/more.zzz", "yet another one"); check_status(g_repo, 1, 0, 0, 4, 0, 1, 1); cl_git_pass(git_index_update_all(index, NULL, NULL, NULL)); check_stat_data(index, "addall/file.bar", true); check_status(g_repo, 1, 0, 0, 4, 0, 0, 1); cl_git_pass(git_index_add_all(index, &paths, 0, NULL, NULL)); check_stat_data(index, "addall/file.zzz", true); check_status(g_repo, 2, 0, 0, 3, 0, 0, 1); commit_index_to_head(g_repo, "first commit"); check_status(g_repo, 0, 0, 0, 3, 0, 0, 1); /* attempt to add an ignored file - does nothing */ strs[0] = "file.foo"; cl_git_pass(git_index_add_all(index, &paths, 0, NULL, NULL)); check_status(g_repo, 0, 0, 0, 3, 0, 0, 1); /* add with check - should generate error */ error = git_index_add_all( index, &paths, GIT_INDEX_ADD_CHECK_PATHSPEC, NULL, NULL); cl_assert_equal_i(GIT_EINVALIDSPEC, error); check_status(g_repo, 0, 0, 0, 3, 0, 0, 1); /* add with force - should allow */ cl_git_pass(git_index_add_all( index, &paths, GIT_INDEX_ADD_FORCE, NULL, NULL)); check_stat_data(index, "addall/file.foo", true); check_status(g_repo, 1, 0, 0, 3, 0, 0, 0); /* now it's in the index, so regular add should work */ cl_git_rewritefile("addall/file.foo", "new content for file"); check_stat_data(index, "addall/file.foo", false); check_status(g_repo, 1, 0, 0, 3, 0, 1, 0); cl_git_pass(git_index_add_all(index, &paths, 0, NULL, NULL)); check_stat_data(index, "addall/file.foo", true); check_status(g_repo, 1, 0, 0, 3, 0, 0, 0); cl_git_pass(git_index_add_bypath(index, "more.zzz")); check_stat_data(index, "addall/more.zzz", true); check_status(g_repo, 2, 0, 0, 2, 0, 0, 0); cl_git_rewritefile("addall/file.zzz", "new content for file"); check_status(g_repo, 2, 0, 0, 2, 0, 1, 0); cl_git_pass(git_index_add_bypath(index, "file.zzz")); check_stat_data(index, "addall/file.zzz", true); check_status(g_repo, 2, 0, 1, 2, 0, 0, 0); strs[0] = "*.zzz"; cl_git_pass(git_index_remove_all(index, &paths, NULL, NULL)); check_status(g_repo, 1, 1, 0, 4, 0, 0, 0); cl_git_pass(git_index_add_bypath(index, "file.zzz")); check_status(g_repo, 1, 0, 1, 3, 0, 0, 0); commit_index_to_head(g_repo, "second commit"); check_status(g_repo, 0, 0, 0, 3, 0, 0, 0); cl_must_pass(p_unlink("addall/file.zzz")); check_status(g_repo, 0, 0, 0, 3, 1, 0, 0); /* update_all should be able to remove entries */ cl_git_pass(git_index_update_all(index, NULL, NULL, NULL)); check_status(g_repo, 0, 1, 0, 3, 0, 0, 0); strs[0] = "*"; cl_git_pass(git_index_add_all(index, &paths, 0, NULL, NULL)); check_status(g_repo, 3, 1, 0, 0, 0, 0, 0); /* must be able to remove at any position while still updating other files */ cl_must_pass(p_unlink("addall/.gitignore")); cl_git_rewritefile("addall/file.zzz", "reconstructed file"); cl_git_rewritefile("addall/more.zzz", "altered file reality"); check_status(g_repo, 3, 1, 0, 1, 1, 1, 0); cl_git_pass(git_index_update_all(index, NULL, NULL, NULL)); check_status(g_repo, 2, 1, 0, 1, 0, 0, 0); /* this behavior actually matches 'git add -u' where "file.zzz" has * been removed from the index, so when you go to update, even though * it exists in the HEAD, it is not re-added to the index, leaving it * as a DELETE when comparing HEAD to index and as an ADD comparing * index to worktree */ git_index_free(index); } libgit2-0.19.0/tests-clar/index/conflicts.c000066400000000000000000000226761216214232500204700ustar00rootroot00000000000000#include "clar_libgit2.h" #include "index.h" #include "git2/repository.h" static git_repository *repo; static git_index *repo_index; #define TEST_REPO_PATH "mergedrepo" #define TEST_INDEX_PATH TEST_REPO_PATH "/.git/index" #define CONFLICTS_ONE_ANCESTOR_OID "1f85ca51b8e0aac893a621b61a9c2661d6aa6d81" #define CONFLICTS_ONE_OUR_OID "6aea5f295304c36144ad6e9247a291b7f8112399" #define CONFLICTS_ONE_THEIR_OID "516bd85f78061e09ccc714561d7b504672cb52da" #define CONFLICTS_TWO_ANCESTOR_OID "84af62840be1b1c47b778a8a249f3ff45155038c" #define CONFLICTS_TWO_OUR_OID "8b3f43d2402825c200f835ca1762413e386fd0b2" #define CONFLICTS_TWO_THEIR_OID "220bd62631c8cf7a83ef39c6b94595f00517211e" #define TEST_ANCESTOR_OID "f00ff00ff00ff00ff00ff00ff00ff00ff00ff00f" #define TEST_OUR_OID "b44bb44bb44bb44bb44bb44bb44bb44bb44bb44b" #define TEST_THEIR_OID "0123456789abcdef0123456789abcdef01234567" // Fixture setup and teardown void test_index_conflicts__initialize(void) { repo = cl_git_sandbox_init("mergedrepo"); git_repository_index(&repo_index, repo); } void test_index_conflicts__cleanup(void) { git_index_free(repo_index); repo_index = NULL; cl_git_sandbox_cleanup(); } void test_index_conflicts__add(void) { git_index_entry ancestor_entry, our_entry, their_entry; cl_assert(git_index_entrycount(repo_index) == 8); memset(&ancestor_entry, 0x0, sizeof(git_index_entry)); memset(&our_entry, 0x0, sizeof(git_index_entry)); memset(&their_entry, 0x0, sizeof(git_index_entry)); ancestor_entry.path = "test-one.txt"; ancestor_entry.flags |= (1 << GIT_IDXENTRY_STAGESHIFT); git_oid_fromstr(&ancestor_entry.oid, TEST_ANCESTOR_OID); our_entry.path = "test-one.txt"; ancestor_entry.flags |= (2 << GIT_IDXENTRY_STAGESHIFT); git_oid_fromstr(&our_entry.oid, TEST_OUR_OID); their_entry.path = "test-one.txt"; ancestor_entry.flags |= (3 << GIT_IDXENTRY_STAGESHIFT); git_oid_fromstr(&their_entry.oid, TEST_THEIR_OID); cl_git_pass(git_index_conflict_add(repo_index, &ancestor_entry, &our_entry, &their_entry)); cl_assert(git_index_entrycount(repo_index) == 11); } void test_index_conflicts__add_fixes_incorrect_stage(void) { git_index_entry ancestor_entry, our_entry, their_entry; const git_index_entry *conflict_entry[3]; cl_assert(git_index_entrycount(repo_index) == 8); memset(&ancestor_entry, 0x0, sizeof(git_index_entry)); memset(&our_entry, 0x0, sizeof(git_index_entry)); memset(&their_entry, 0x0, sizeof(git_index_entry)); ancestor_entry.path = "test-one.txt"; ancestor_entry.flags |= (3 << GIT_IDXENTRY_STAGESHIFT); git_oid_fromstr(&ancestor_entry.oid, TEST_ANCESTOR_OID); our_entry.path = "test-one.txt"; ancestor_entry.flags |= (1 << GIT_IDXENTRY_STAGESHIFT); git_oid_fromstr(&our_entry.oid, TEST_OUR_OID); their_entry.path = "test-one.txt"; ancestor_entry.flags |= (2 << GIT_IDXENTRY_STAGESHIFT); git_oid_fromstr(&their_entry.oid, TEST_THEIR_OID); cl_git_pass(git_index_conflict_add(repo_index, &ancestor_entry, &our_entry, &their_entry)); cl_assert(git_index_entrycount(repo_index) == 11); cl_git_pass(git_index_conflict_get(&conflict_entry[0], &conflict_entry[1], &conflict_entry[2], repo_index, "test-one.txt")); cl_assert(git_index_entry_stage(conflict_entry[0]) == 1); cl_assert(git_index_entry_stage(conflict_entry[1]) == 2); cl_assert(git_index_entry_stage(conflict_entry[2]) == 3); } void test_index_conflicts__get(void) { const git_index_entry *conflict_entry[3]; git_oid oid; cl_git_pass(git_index_conflict_get(&conflict_entry[0], &conflict_entry[1], &conflict_entry[2], repo_index, "conflicts-one.txt")); cl_assert_equal_s("conflicts-one.txt", conflict_entry[0]->path); git_oid_fromstr(&oid, CONFLICTS_ONE_ANCESTOR_OID); cl_assert(git_oid_cmp(&conflict_entry[0]->oid, &oid) == 0); git_oid_fromstr(&oid, CONFLICTS_ONE_OUR_OID); cl_assert(git_oid_cmp(&conflict_entry[1]->oid, &oid) == 0); git_oid_fromstr(&oid, CONFLICTS_ONE_THEIR_OID); cl_assert(git_oid_cmp(&conflict_entry[2]->oid, &oid) == 0); cl_git_pass(git_index_conflict_get(&conflict_entry[0], &conflict_entry[1], &conflict_entry[2], repo_index, "conflicts-two.txt")); cl_assert_equal_s("conflicts-two.txt", conflict_entry[0]->path); git_oid_fromstr(&oid, CONFLICTS_TWO_ANCESTOR_OID); cl_assert(git_oid_cmp(&conflict_entry[0]->oid, &oid) == 0); git_oid_fromstr(&oid, CONFLICTS_TWO_OUR_OID); cl_assert(git_oid_cmp(&conflict_entry[1]->oid, &oid) == 0); git_oid_fromstr(&oid, CONFLICTS_TWO_THEIR_OID); cl_assert(git_oid_cmp(&conflict_entry[2]->oid, &oid) == 0); } void test_index_conflicts__iterate(void) { git_index_conflict_iterator *iterator; const git_index_entry *conflict_entry[3]; git_oid oid; cl_git_pass(git_index_conflict_iterator_new(&iterator, repo_index)); cl_git_pass(git_index_conflict_next(&conflict_entry[0], &conflict_entry[1], &conflict_entry[2], iterator)); git_oid_fromstr(&oid, CONFLICTS_ONE_ANCESTOR_OID); cl_assert(git_oid_cmp(&conflict_entry[0]->oid, &oid) == 0); cl_assert(git__strcmp(conflict_entry[0]->path, "conflicts-one.txt") == 0); git_oid_fromstr(&oid, CONFLICTS_ONE_OUR_OID); cl_assert(git_oid_cmp(&conflict_entry[1]->oid, &oid) == 0); cl_assert(git__strcmp(conflict_entry[0]->path, "conflicts-one.txt") == 0); git_oid_fromstr(&oid, CONFLICTS_ONE_THEIR_OID); cl_assert(git_oid_cmp(&conflict_entry[2]->oid, &oid) == 0); cl_assert(git__strcmp(conflict_entry[0]->path, "conflicts-one.txt") == 0); cl_git_pass(git_index_conflict_next(&conflict_entry[0], &conflict_entry[1], &conflict_entry[2], iterator)); git_oid_fromstr(&oid, CONFLICTS_TWO_ANCESTOR_OID); cl_assert(git_oid_cmp(&conflict_entry[0]->oid, &oid) == 0); cl_assert(git__strcmp(conflict_entry[0]->path, "conflicts-two.txt") == 0); git_oid_fromstr(&oid, CONFLICTS_TWO_OUR_OID); cl_assert(git_oid_cmp(&conflict_entry[1]->oid, &oid) == 0); cl_assert(git__strcmp(conflict_entry[0]->path, "conflicts-two.txt") == 0); git_oid_fromstr(&oid, CONFLICTS_TWO_THEIR_OID); cl_assert(git_oid_cmp(&conflict_entry[2]->oid, &oid) == 0); cl_assert(git__strcmp(conflict_entry[0]->path, "conflicts-two.txt") == 0); cl_assert(git_index_conflict_next(&conflict_entry[0], &conflict_entry[1], &conflict_entry[2], iterator) == GIT_ITEROVER); cl_assert(conflict_entry[0] == NULL); cl_assert(conflict_entry[2] == NULL); cl_assert(conflict_entry[2] == NULL); git_index_conflict_iterator_free(iterator); } void test_index_conflicts__remove(void) { const git_index_entry *entry; size_t i; cl_assert(git_index_entrycount(repo_index) == 8); cl_git_pass(git_index_conflict_remove(repo_index, "conflicts-one.txt")); cl_assert(git_index_entrycount(repo_index) == 5); for (i = 0; i < git_index_entrycount(repo_index); i++) { cl_assert(entry = git_index_get_byindex(repo_index, i)); cl_assert(strcmp(entry->path, "conflicts-one.txt") != 0); } cl_git_pass(git_index_conflict_remove(repo_index, "conflicts-two.txt")); cl_assert(git_index_entrycount(repo_index) == 2); for (i = 0; i < git_index_entrycount(repo_index); i++) { cl_assert(entry = git_index_get_byindex(repo_index, i)); cl_assert(strcmp(entry->path, "conflicts-two.txt") != 0); } } void test_index_conflicts__moved_to_reuc_on_add(void) { const git_index_entry *entry; size_t i; cl_assert(git_index_entrycount(repo_index) == 8); cl_git_mkfile("./mergedrepo/conflicts-one.txt", "new-file\n"); cl_git_pass(git_index_add_bypath(repo_index, "conflicts-one.txt")); cl_assert(git_index_entrycount(repo_index) == 6); for (i = 0; i < git_index_entrycount(repo_index); i++) { cl_assert(entry = git_index_get_byindex(repo_index, i)); if (strcmp(entry->path, "conflicts-one.txt") == 0) cl_assert(git_index_entry_stage(entry) == 0); } } void test_index_conflicts__moved_to_reuc_on_remove(void) { const git_index_entry *entry; size_t i; cl_assert(git_index_entrycount(repo_index) == 8); cl_git_pass(p_unlink("./mergedrepo/conflicts-one.txt")); cl_git_pass(git_index_remove_bypath(repo_index, "conflicts-one.txt")); cl_assert(git_index_entrycount(repo_index) == 5); for (i = 0; i < git_index_entrycount(repo_index); i++) { cl_assert(entry = git_index_get_byindex(repo_index, i)); cl_assert(strcmp(entry->path, "conflicts-one.txt") != 0); } } void test_index_conflicts__remove_all_conflicts(void) { size_t i; const git_index_entry *entry; cl_assert(git_index_entrycount(repo_index) == 8); cl_assert_equal_i(true, git_index_has_conflicts(repo_index)); git_index_conflict_cleanup(repo_index); cl_assert_equal_i(false, git_index_has_conflicts(repo_index)); cl_assert(git_index_entrycount(repo_index) == 2); for (i = 0; i < git_index_entrycount(repo_index); i++) { cl_assert(entry = git_index_get_byindex(repo_index, i)); cl_assert(git_index_entry_stage(entry) == 0); } } void test_index_conflicts__partial(void) { git_index_entry ancestor_entry, our_entry, their_entry; const git_index_entry *conflict_entry[3]; cl_assert(git_index_entrycount(repo_index) == 8); memset(&ancestor_entry, 0x0, sizeof(git_index_entry)); memset(&our_entry, 0x0, sizeof(git_index_entry)); memset(&their_entry, 0x0, sizeof(git_index_entry)); ancestor_entry.path = "test-one.txt"; ancestor_entry.flags |= (1 << GIT_IDXENTRY_STAGESHIFT); git_oid_fromstr(&ancestor_entry.oid, TEST_ANCESTOR_OID); cl_git_pass(git_index_conflict_add(repo_index, &ancestor_entry, NULL, NULL)); cl_assert(git_index_entrycount(repo_index) == 9); cl_git_pass(git_index_conflict_get(&conflict_entry[0], &conflict_entry[1], &conflict_entry[2], repo_index, "test-one.txt")); cl_assert(git_oid_cmp(&ancestor_entry.oid, &conflict_entry[0]->oid) == 0); cl_assert(conflict_entry[1] == NULL); cl_assert(conflict_entry[2] == NULL); } libgit2-0.19.0/tests-clar/index/filemodes.c000066400000000000000000000111171216214232500204370ustar00rootroot00000000000000#include "clar_libgit2.h" #include "buffer.h" #include "posix.h" #include "index.h" static git_repository *g_repo = NULL; void test_index_filemodes__initialize(void) { g_repo = cl_git_sandbox_init("filemodes"); } void test_index_filemodes__cleanup(void) { cl_git_sandbox_cleanup(); } void test_index_filemodes__read(void) { git_index *index; unsigned int i; static bool expected[6] = { 0, 1, 0, 1, 0, 1 }; cl_git_pass(git_repository_index(&index, g_repo)); cl_assert_equal_i(6, (int)git_index_entrycount(index)); for (i = 0; i < 6; ++i) { const git_index_entry *entry = git_index_get_byindex(index, i); cl_assert(entry != NULL); cl_assert(((entry->mode & 0100) ? 1 : 0) == expected[i]); } git_index_free(index); } static void replace_file_with_mode( const char *filename, const char *backup, unsigned int create_mode) { git_buf path = GIT_BUF_INIT, content = GIT_BUF_INIT; cl_git_pass(git_buf_joinpath(&path, "filemodes", filename)); cl_git_pass(git_buf_printf(&content, "%s as %08u (%d)", filename, create_mode, rand())); cl_git_pass(p_rename(path.ptr, backup)); cl_git_write2file( path.ptr, content.ptr, O_WRONLY|O_CREAT|O_TRUNC, create_mode); git_buf_free(&path); git_buf_free(&content); } static void add_and_check_mode( git_index *index, const char *filename, unsigned int expect_mode) { size_t pos; const git_index_entry *entry; cl_git_pass(git_index_add_bypath(index, filename)); cl_assert(!git_index_find(&pos, index, filename)); entry = git_index_get_byindex(index, pos); cl_assert(entry->mode == expect_mode); } void test_index_filemodes__untrusted(void) { git_index *index; bool can_filemode = cl_is_chmod_supported(); cl_repo_set_bool(g_repo, "core.filemode", false); cl_git_pass(git_repository_index(&index, g_repo)); cl_assert((git_index_caps(index) & GIT_INDEXCAP_NO_FILEMODE) != 0); /* 1 - add 0644 over existing 0644 -> expect 0644 */ replace_file_with_mode("exec_off", "filemodes/exec_off.0", 0644); add_and_check_mode(index, "exec_off", GIT_FILEMODE_BLOB); /* 2 - add 0644 over existing 0755 -> expect 0755 */ replace_file_with_mode("exec_on", "filemodes/exec_on.0", 0644); add_and_check_mode(index, "exec_on", GIT_FILEMODE_BLOB_EXECUTABLE); /* 3 - add 0755 over existing 0644 -> expect 0644 */ replace_file_with_mode("exec_off", "filemodes/exec_off.1", 0755); add_and_check_mode(index, "exec_off", GIT_FILEMODE_BLOB); /* 4 - add 0755 over existing 0755 -> expect 0755 */ replace_file_with_mode("exec_on", "filemodes/exec_on.1", 0755); add_and_check_mode(index, "exec_on", GIT_FILEMODE_BLOB_EXECUTABLE); /* 5 - add new 0644 -> expect 0644 */ cl_git_write2file("filemodes/new_off", "blah", O_WRONLY | O_CREAT | O_TRUNC, 0644); add_and_check_mode(index, "new_off", GIT_FILEMODE_BLOB); /* this test won't give predictable results on a platform * that doesn't support filemodes correctly, so skip it. */ if (can_filemode) { /* 6 - add 0755 -> expect 0755 */ cl_git_write2file("filemodes/new_on", "blah", O_WRONLY | O_CREAT | O_TRUNC, 0755); add_and_check_mode(index, "new_on", GIT_FILEMODE_BLOB_EXECUTABLE); } git_index_free(index); } void test_index_filemodes__trusted(void) { git_index *index; /* Only run these tests on platforms where I can actually * chmod a file and get the stat results I expect! */ if (!cl_is_chmod_supported()) return; cl_repo_set_bool(g_repo, "core.filemode", true); cl_git_pass(git_repository_index(&index, g_repo)); cl_assert((git_index_caps(index) & GIT_INDEXCAP_NO_FILEMODE) == 0); /* 1 - add 0644 over existing 0644 -> expect 0644 */ replace_file_with_mode("exec_off", "filemodes/exec_off.0", 0644); add_and_check_mode(index, "exec_off", GIT_FILEMODE_BLOB); /* 2 - add 0644 over existing 0755 -> expect 0644 */ replace_file_with_mode("exec_on", "filemodes/exec_on.0", 0644); add_and_check_mode(index, "exec_on", GIT_FILEMODE_BLOB); /* 3 - add 0755 over existing 0644 -> expect 0755 */ replace_file_with_mode("exec_off", "filemodes/exec_off.1", 0755); add_and_check_mode(index, "exec_off", GIT_FILEMODE_BLOB_EXECUTABLE); /* 4 - add 0755 over existing 0755 -> expect 0755 */ replace_file_with_mode("exec_on", "filemodes/exec_on.1", 0755); add_and_check_mode(index, "exec_on", GIT_FILEMODE_BLOB_EXECUTABLE); /* 5 - add new 0644 -> expect 0644 */ cl_git_write2file("filemodes/new_off", "blah", O_WRONLY | O_CREAT | O_TRUNC, 0644); add_and_check_mode(index, "new_off", GIT_FILEMODE_BLOB); /* 6 - add 0755 -> expect 0755 */ cl_git_write2file("filemodes/new_on", "blah", O_WRONLY | O_CREAT | O_TRUNC, 0755); add_and_check_mode(index, "new_on", GIT_FILEMODE_BLOB_EXECUTABLE); git_index_free(index); } libgit2-0.19.0/tests-clar/index/inmemory.c000066400000000000000000000007161216214232500203320ustar00rootroot00000000000000#include "clar_libgit2.h" void test_index_inmemory__can_create_an_inmemory_index(void) { git_index *index; cl_git_pass(git_index_new(&index)); cl_assert_equal_i(0, (int)git_index_entrycount(index)); git_index_free(index); } void test_index_inmemory__cannot_add_bypath_to_an_inmemory_index(void) { git_index *index; cl_git_pass(git_index_new(&index)); cl_assert_equal_i(GIT_ERROR, git_index_add_bypath(index, "test.txt")); git_index_free(index); } libgit2-0.19.0/tests-clar/index/names.c000066400000000000000000000054301216214232500175740ustar00rootroot00000000000000#include "clar_libgit2.h" #include "index.h" #include "git2/sys/index.h" #include "git2/repository.h" #include "../reset/reset_helpers.h" static git_repository *repo; static git_index *repo_index; #define TEST_REPO_PATH "mergedrepo" #define TEST_INDEX_PATH TEST_REPO_PATH "/.git/index" // Fixture setup and teardown void test_index_names__initialize(void) { repo = cl_git_sandbox_init("mergedrepo"); git_repository_index(&repo_index, repo); } void test_index_names__cleanup(void) { git_index_free(repo_index); repo_index = NULL; cl_git_sandbox_cleanup(); } void test_index_names__add(void) { const git_index_name_entry *conflict_name; cl_git_pass(git_index_name_add(repo_index, "ancestor", "ours", "theirs")); cl_git_pass(git_index_name_add(repo_index, "ancestor2", "ours2", NULL)); cl_git_pass(git_index_name_add(repo_index, "ancestor3", NULL, "theirs3")); cl_assert(git_index_name_entrycount(repo_index) == 3); conflict_name = git_index_name_get_byindex(repo_index, 0); cl_assert(strcmp(conflict_name->ancestor, "ancestor") == 0); cl_assert(strcmp(conflict_name->ours, "ours") == 0); cl_assert(strcmp(conflict_name->theirs, "theirs") == 0); conflict_name = git_index_name_get_byindex(repo_index, 1); cl_assert(strcmp(conflict_name->ancestor, "ancestor2") == 0); cl_assert(strcmp(conflict_name->ours, "ours2") == 0); cl_assert(conflict_name->theirs == NULL); conflict_name = git_index_name_get_byindex(repo_index, 2); cl_assert(strcmp(conflict_name->ancestor, "ancestor3") == 0); cl_assert(conflict_name->ours == NULL); cl_assert(strcmp(conflict_name->theirs, "theirs3") == 0); } void test_index_names__roundtrip(void) { const git_index_name_entry *conflict_name; cl_git_pass(git_index_name_add(repo_index, "ancestor", "ours", "theirs")); cl_git_pass(git_index_name_add(repo_index, "ancestor2", "ours2", NULL)); cl_git_pass(git_index_name_add(repo_index, "ancestor3", NULL, "theirs3")); cl_git_pass(git_index_write(repo_index)); git_index_clear(repo_index); cl_assert(git_index_name_entrycount(repo_index) == 0); cl_git_pass(git_index_read(repo_index)); cl_assert(git_index_name_entrycount(repo_index) == 3); conflict_name = git_index_name_get_byindex(repo_index, 0); cl_assert(strcmp(conflict_name->ancestor, "ancestor") == 0); cl_assert(strcmp(conflict_name->ours, "ours") == 0); cl_assert(strcmp(conflict_name->theirs, "theirs") == 0); conflict_name = git_index_name_get_byindex(repo_index, 1); cl_assert(strcmp(conflict_name->ancestor, "ancestor2") == 0); cl_assert(strcmp(conflict_name->ours, "ours2") == 0); cl_assert(conflict_name->theirs == NULL); conflict_name = git_index_name_get_byindex(repo_index, 2); cl_assert(strcmp(conflict_name->ancestor, "ancestor3") == 0); cl_assert(conflict_name->ours == NULL); cl_assert(strcmp(conflict_name->theirs, "theirs3") == 0); } libgit2-0.19.0/tests-clar/index/read_tree.c000066400000000000000000000022601216214232500204210ustar00rootroot00000000000000#include "clar_libgit2.h" #include "posix.h" /* Test that reading and writing a tree is a no-op */ void test_index_read_tree__read_write_involution(void) { git_repository *repo; git_index *index; git_oid tree_oid; git_tree *tree; git_oid expected; p_mkdir("read_tree", 0700); cl_git_pass(git_repository_init(&repo, "./read_tree", 0)); cl_git_pass(git_repository_index(&index, repo)); cl_assert(git_index_entrycount(index) == 0); p_mkdir("./read_tree/abc", 0700); /* Sort order: '-' < '/' < '_' */ cl_git_mkfile("./read_tree/abc-d", NULL); cl_git_mkfile("./read_tree/abc/d", NULL); cl_git_mkfile("./read_tree/abc_d", NULL); cl_git_pass(git_index_add_bypath(index, "abc-d")); cl_git_pass(git_index_add_bypath(index, "abc_d")); cl_git_pass(git_index_add_bypath(index, "abc/d")); /* write-tree */ cl_git_pass(git_index_write_tree(&expected, index)); /* read-tree */ git_tree_lookup(&tree, repo, &expected); cl_git_pass(git_index_read_tree(index, tree)); git_tree_free(tree); cl_git_pass(git_index_write_tree(&tree_oid, index)); cl_assert(git_oid_cmp(&expected, &tree_oid) == 0); git_index_free(index); git_repository_free(repo); cl_fixture_cleanup("read_tree"); } libgit2-0.19.0/tests-clar/index/rename.c000066400000000000000000000027611216214232500177440ustar00rootroot00000000000000#include "clar_libgit2.h" #include "posix.h" void test_index_rename__single_file(void) { git_repository *repo; git_index *index; size_t position; git_oid expected; const git_index_entry *entry; p_mkdir("rename", 0700); cl_git_pass(git_repository_init(&repo, "./rename", 0)); cl_git_pass(git_repository_index(&index, repo)); cl_assert(git_index_entrycount(index) == 0); cl_git_mkfile("./rename/lame.name.txt", "new_file\n"); /* This should add a new blob to the object database in 'd4/fa8600b4f37d7516bef4816ae2c64dbf029e3a' */ cl_git_pass(git_index_add_bypath(index, "lame.name.txt")); cl_assert(git_index_entrycount(index) == 1); cl_git_pass(git_oid_fromstr(&expected, "d4fa8600b4f37d7516bef4816ae2c64dbf029e3a")); cl_assert(!git_index_find(&position, index, "lame.name.txt")); entry = git_index_get_byindex(index, position); cl_assert(git_oid_cmp(&expected, &entry->oid) == 0); /* This removes the entry from the index, but not from the object database */ cl_git_pass(git_index_remove(index, "lame.name.txt", 0)); cl_assert(git_index_entrycount(index) == 0); p_rename("./rename/lame.name.txt", "./rename/fancy.name.txt"); cl_git_pass(git_index_add_bypath(index, "fancy.name.txt")); cl_assert(git_index_entrycount(index) == 1); cl_assert(!git_index_find(&position, index, "fancy.name.txt")); entry = git_index_get_byindex(index, position); cl_assert(git_oid_cmp(&expected, &entry->oid) == 0); git_index_free(index); git_repository_free(repo); cl_fixture_cleanup("rename"); } libgit2-0.19.0/tests-clar/index/reuc.c000066400000000000000000000254571216214232500174420ustar00rootroot00000000000000#include "clar_libgit2.h" #include "index.h" #include "git2/sys/index.h" #include "git2/repository.h" #include "../reset/reset_helpers.h" static git_repository *repo; static git_index *repo_index; #define TEST_REPO_PATH "mergedrepo" #define TEST_INDEX_PATH TEST_REPO_PATH "/.git/index" #define ONE_ANCESTOR_OID "478871385b9cd03908c5383acfd568bef023c6b3" #define ONE_OUR_OID "4458b8bc9e72b6c8755ae456f60e9844d0538d8c" #define ONE_THEIR_OID "8b72416545c7e761b64cecad4f1686eae4078aa8" #define TWO_ANCESTOR_OID "9d81f82fccc7dcd7de7a1ffead1815294c2e092c" #define TWO_OUR_OID "8f3c06cff9a83757cec40c80bc9bf31a2582bde9" #define TWO_THEIR_OID "887b153b165d32409c70163e0f734c090f12f673" // Fixture setup and teardown void test_index_reuc__initialize(void) { repo = cl_git_sandbox_init("mergedrepo"); git_repository_index(&repo_index, repo); } void test_index_reuc__cleanup(void) { git_index_free(repo_index); repo_index = NULL; cl_git_sandbox_cleanup(); } void test_index_reuc__add(void) { git_oid ancestor_oid, our_oid, their_oid; const git_index_reuc_entry *reuc; git_oid_fromstr(&ancestor_oid, ONE_ANCESTOR_OID); git_oid_fromstr(&our_oid, ONE_OUR_OID); git_oid_fromstr(&their_oid, ONE_THEIR_OID); cl_git_pass(git_index_reuc_add(repo_index, "newfile.txt", 0100644, &ancestor_oid, 0100644, &our_oid, 0100644, &their_oid)); cl_assert(reuc = git_index_reuc_get_bypath(repo_index, "newfile.txt")); cl_assert_equal_s("newfile.txt", reuc->path); cl_assert(reuc->mode[0] == 0100644); cl_assert(reuc->mode[1] == 0100644); cl_assert(reuc->mode[2] == 0100644); cl_assert(git_oid_cmp(&reuc->oid[0], &ancestor_oid) == 0); cl_assert(git_oid_cmp(&reuc->oid[1], &our_oid) == 0); cl_assert(git_oid_cmp(&reuc->oid[2], &their_oid) == 0); } void test_index_reuc__add_no_ancestor(void) { git_oid ancestor_oid, our_oid, their_oid; const git_index_reuc_entry *reuc; memset(&ancestor_oid, 0x0, sizeof(git_oid)); git_oid_fromstr(&our_oid, ONE_OUR_OID); git_oid_fromstr(&their_oid, ONE_THEIR_OID); cl_git_pass(git_index_reuc_add(repo_index, "newfile.txt", 0, NULL, 0100644, &our_oid, 0100644, &their_oid)); cl_assert(reuc = git_index_reuc_get_bypath(repo_index, "newfile.txt")); cl_assert_equal_s("newfile.txt", reuc->path); cl_assert(reuc->mode[0] == 0); cl_assert(reuc->mode[1] == 0100644); cl_assert(reuc->mode[2] == 0100644); cl_assert(git_oid_cmp(&reuc->oid[0], &ancestor_oid) == 0); cl_assert(git_oid_cmp(&reuc->oid[1], &our_oid) == 0); cl_assert(git_oid_cmp(&reuc->oid[2], &their_oid) == 0); } void test_index_reuc__read_bypath(void) { const git_index_reuc_entry *reuc; git_oid oid; cl_assert_equal_i(2, git_index_reuc_entrycount(repo_index)); cl_assert(reuc = git_index_reuc_get_bypath(repo_index, "two.txt")); cl_assert_equal_s("two.txt", reuc->path); cl_assert(reuc->mode[0] == 0100644); cl_assert(reuc->mode[1] == 0100644); cl_assert(reuc->mode[2] == 0100644); git_oid_fromstr(&oid, TWO_ANCESTOR_OID); cl_assert(git_oid_cmp(&reuc->oid[0], &oid) == 0); git_oid_fromstr(&oid, TWO_OUR_OID); cl_assert(git_oid_cmp(&reuc->oid[1], &oid) == 0); git_oid_fromstr(&oid, TWO_THEIR_OID); cl_assert(git_oid_cmp(&reuc->oid[2], &oid) == 0); cl_assert(reuc = git_index_reuc_get_bypath(repo_index, "one.txt")); cl_assert_equal_s("one.txt", reuc->path); cl_assert(reuc->mode[0] == 0100644); cl_assert(reuc->mode[1] == 0100644); cl_assert(reuc->mode[2] == 0100644); git_oid_fromstr(&oid, ONE_ANCESTOR_OID); cl_assert(git_oid_cmp(&reuc->oid[0], &oid) == 0); git_oid_fromstr(&oid, ONE_OUR_OID); cl_assert(git_oid_cmp(&reuc->oid[1], &oid) == 0); git_oid_fromstr(&oid, ONE_THEIR_OID); cl_assert(git_oid_cmp(&reuc->oid[2], &oid) == 0); } void test_index_reuc__ignore_case(void) { const git_index_reuc_entry *reuc; git_oid oid; int index_caps; index_caps = git_index_caps(repo_index); index_caps &= ~GIT_INDEXCAP_IGNORE_CASE; cl_git_pass(git_index_set_caps(repo_index, index_caps)); cl_assert(!git_index_reuc_get_bypath(repo_index, "TWO.txt")); index_caps |= GIT_INDEXCAP_IGNORE_CASE; cl_git_pass(git_index_set_caps(repo_index, index_caps)); cl_assert_equal_i(2, git_index_reuc_entrycount(repo_index)); cl_assert(reuc = git_index_reuc_get_bypath(repo_index, "TWO.txt")); cl_assert_equal_s("two.txt", reuc->path); cl_assert(reuc->mode[0] == 0100644); cl_assert(reuc->mode[1] == 0100644); cl_assert(reuc->mode[2] == 0100644); git_oid_fromstr(&oid, TWO_ANCESTOR_OID); cl_assert(git_oid_cmp(&reuc->oid[0], &oid) == 0); git_oid_fromstr(&oid, TWO_OUR_OID); cl_assert(git_oid_cmp(&reuc->oid[1], &oid) == 0); git_oid_fromstr(&oid, TWO_THEIR_OID); cl_assert(git_oid_cmp(&reuc->oid[2], &oid) == 0); } void test_index_reuc__read_byindex(void) { const git_index_reuc_entry *reuc; git_oid oid; cl_assert_equal_i(2, git_index_reuc_entrycount(repo_index)); cl_assert(reuc = git_index_reuc_get_byindex(repo_index, 0)); cl_assert_equal_s("one.txt", reuc->path); cl_assert(reuc->mode[0] == 0100644); cl_assert(reuc->mode[1] == 0100644); cl_assert(reuc->mode[2] == 0100644); git_oid_fromstr(&oid, ONE_ANCESTOR_OID); cl_assert(git_oid_cmp(&reuc->oid[0], &oid) == 0); git_oid_fromstr(&oid, ONE_OUR_OID); cl_assert(git_oid_cmp(&reuc->oid[1], &oid) == 0); git_oid_fromstr(&oid, ONE_THEIR_OID); cl_assert(git_oid_cmp(&reuc->oid[2], &oid) == 0); cl_assert(reuc = git_index_reuc_get_byindex(repo_index, 1)); cl_assert_equal_s("two.txt", reuc->path); cl_assert(reuc->mode[0] == 0100644); cl_assert(reuc->mode[1] == 0100644); cl_assert(reuc->mode[2] == 0100644); git_oid_fromstr(&oid, TWO_ANCESTOR_OID); cl_assert(git_oid_cmp(&reuc->oid[0], &oid) == 0); git_oid_fromstr(&oid, TWO_OUR_OID); cl_assert(git_oid_cmp(&reuc->oid[1], &oid) == 0); git_oid_fromstr(&oid, TWO_THEIR_OID); cl_assert(git_oid_cmp(&reuc->oid[2], &oid) == 0); } void test_index_reuc__updates_existing(void) { const git_index_reuc_entry *reuc; git_oid ancestor_oid, our_oid, their_oid, oid; int index_caps; git_index_clear(repo_index); index_caps = git_index_caps(repo_index); index_caps |= GIT_INDEXCAP_IGNORE_CASE; cl_git_pass(git_index_set_caps(repo_index, index_caps)); git_oid_fromstr(&ancestor_oid, TWO_ANCESTOR_OID); git_oid_fromstr(&our_oid, TWO_OUR_OID); git_oid_fromstr(&their_oid, TWO_THEIR_OID); cl_git_pass(git_index_reuc_add(repo_index, "two.txt", 0100644, &ancestor_oid, 0100644, &our_oid, 0100644, &their_oid)); cl_git_pass(git_index_reuc_add(repo_index, "TWO.txt", 0100644, &our_oid, 0100644, &their_oid, 0100644, &ancestor_oid)); cl_assert_equal_i(1, git_index_reuc_entrycount(repo_index)); cl_assert(reuc = git_index_reuc_get_byindex(repo_index, 0)); cl_assert_equal_s("TWO.txt", reuc->path); git_oid_fromstr(&oid, TWO_OUR_OID); cl_assert(git_oid_cmp(&reuc->oid[0], &oid) == 0); git_oid_fromstr(&oid, TWO_THEIR_OID); cl_assert(git_oid_cmp(&reuc->oid[1], &oid) == 0); git_oid_fromstr(&oid, TWO_ANCESTOR_OID); cl_assert(git_oid_cmp(&reuc->oid[2], &oid) == 0); } void test_index_reuc__remove(void) { git_oid oid; const git_index_reuc_entry *reuc; cl_assert_equal_i(2, git_index_reuc_entrycount(repo_index)); cl_git_pass(git_index_reuc_remove(repo_index, 0)); cl_git_fail(git_index_reuc_remove(repo_index, 1)); cl_assert_equal_i(1, git_index_reuc_entrycount(repo_index)); cl_assert(reuc = git_index_reuc_get_byindex(repo_index, 0)); cl_assert_equal_s("two.txt", reuc->path); cl_assert(reuc->mode[0] == 0100644); cl_assert(reuc->mode[1] == 0100644); cl_assert(reuc->mode[2] == 0100644); git_oid_fromstr(&oid, TWO_ANCESTOR_OID); cl_assert(git_oid_cmp(&reuc->oid[0], &oid) == 0); git_oid_fromstr(&oid, TWO_OUR_OID); cl_assert(git_oid_cmp(&reuc->oid[1], &oid) == 0); git_oid_fromstr(&oid, TWO_THEIR_OID); cl_assert(git_oid_cmp(&reuc->oid[2], &oid) == 0); } void test_index_reuc__write(void) { git_oid ancestor_oid, our_oid, their_oid; const git_index_reuc_entry *reuc; git_index_clear(repo_index); /* Write out of order to ensure sorting is correct */ git_oid_fromstr(&ancestor_oid, TWO_ANCESTOR_OID); git_oid_fromstr(&our_oid, TWO_OUR_OID); git_oid_fromstr(&their_oid, TWO_THEIR_OID); cl_git_pass(git_index_reuc_add(repo_index, "two.txt", 0100644, &ancestor_oid, 0100644, &our_oid, 0100644, &their_oid)); git_oid_fromstr(&ancestor_oid, ONE_ANCESTOR_OID); git_oid_fromstr(&our_oid, ONE_OUR_OID); git_oid_fromstr(&their_oid, ONE_THEIR_OID); cl_git_pass(git_index_reuc_add(repo_index, "one.txt", 0100644, &ancestor_oid, 0100644, &our_oid, 0100644, &their_oid)); cl_git_pass(git_index_write(repo_index)); cl_git_pass(git_index_read(repo_index)); cl_assert_equal_i(2, git_index_reuc_entrycount(repo_index)); /* ensure sort order was round-tripped correct */ cl_assert(reuc = git_index_reuc_get_byindex(repo_index, 0)); cl_assert_equal_s("one.txt", reuc->path); cl_assert(reuc = git_index_reuc_get_byindex(repo_index, 1)); cl_assert_equal_s("two.txt", reuc->path); } static int reuc_entry_exists(void) { return (git_index_reuc_get_bypath(repo_index, "newfile.txt") != NULL); } void test_index_reuc__cleaned_on_reset_hard(void) { git_object *target; retrieve_target_from_oid(&target, repo, "3a34580a35add43a4cf361e8e9a30060a905c876"); test_index_reuc__add(); cl_git_pass(git_reset(repo, target, GIT_RESET_HARD)); cl_assert(reuc_entry_exists() == false); git_object_free(target); } void test_index_reuc__cleaned_on_reset_mixed(void) { git_object *target; retrieve_target_from_oid(&target, repo, "3a34580a35add43a4cf361e8e9a30060a905c876"); test_index_reuc__add(); cl_git_pass(git_reset(repo, target, GIT_RESET_MIXED)); cl_assert(reuc_entry_exists() == false); git_object_free(target); } void test_index_reuc__retained_on_reset_soft(void) { git_object *target; retrieve_target_from_oid(&target, repo, "3a34580a35add43a4cf361e8e9a30060a905c876"); git_reset(repo, target, GIT_RESET_HARD); test_index_reuc__add(); cl_git_pass(git_reset(repo, target, GIT_RESET_SOFT)); cl_assert(reuc_entry_exists() == true); git_object_free(target); } void test_index_reuc__cleaned_on_checkout_tree(void) { git_oid oid; git_object *obj; git_checkout_opts opts = GIT_CHECKOUT_OPTS_INIT; opts.checkout_strategy = GIT_CHECKOUT_SAFE | GIT_CHECKOUT_UPDATE_ONLY; test_index_reuc__add(); git_reference_name_to_id(&oid, repo, "refs/heads/master"); git_object_lookup(&obj, repo, &oid, GIT_OBJ_ANY); git_checkout_tree(repo, obj, &opts); cl_assert(reuc_entry_exists() == false); git_object_free(obj); } void test_index_reuc__cleaned_on_checkout_head(void) { git_checkout_opts opts = GIT_CHECKOUT_OPTS_INIT; opts.checkout_strategy = GIT_CHECKOUT_SAFE | GIT_CHECKOUT_UPDATE_ONLY; test_index_reuc__add(); git_checkout_head(repo, &opts); cl_assert(reuc_entry_exists() == false); } void test_index_reuc__retained_on_checkout_index(void) { git_checkout_opts opts = GIT_CHECKOUT_OPTS_INIT; opts.checkout_strategy = GIT_CHECKOUT_SAFE | GIT_CHECKOUT_UPDATE_ONLY; test_index_reuc__add(); git_checkout_index(repo, repo_index, &opts); cl_assert(reuc_entry_exists() == true); } libgit2-0.19.0/tests-clar/index/stage.c000066400000000000000000000034241216214232500175750ustar00rootroot00000000000000#include "clar_libgit2.h" #include "index.h" #include "git2/repository.h" static git_repository *repo; static git_index *repo_index; #define TEST_REPO_PATH "mergedrepo" #define TEST_INDEX_PATH TEST_REPO_PATH "/.git/index" // Fixture setup and teardown void test_index_stage__initialize(void) { repo = cl_git_sandbox_init("mergedrepo"); git_repository_index(&repo_index, repo); } void test_index_stage__cleanup(void) { git_index_free(repo_index); repo_index = NULL; cl_git_sandbox_cleanup(); } void test_index_stage__add_always_adds_stage_0(void) { size_t entry_idx; const git_index_entry *entry; cl_git_mkfile("./mergedrepo/new-file.txt", "new-file\n"); cl_git_pass(git_index_add_bypath(repo_index, "new-file.txt")); cl_assert(!git_index_find(&entry_idx, repo_index, "new-file.txt")); cl_assert((entry = git_index_get_byindex(repo_index, entry_idx)) != NULL); cl_assert(git_index_entry_stage(entry) == 0); } void test_index_stage__find_gets_first_stage(void) { size_t entry_idx; const git_index_entry *entry; cl_assert(!git_index_find(&entry_idx, repo_index, "one.txt")); cl_assert((entry = git_index_get_byindex(repo_index, entry_idx)) != NULL); cl_assert(git_index_entry_stage(entry) == 0); cl_assert(!git_index_find(&entry_idx, repo_index, "two.txt")); cl_assert((entry = git_index_get_byindex(repo_index, entry_idx)) != NULL); cl_assert(git_index_entry_stage(entry) == 0); cl_assert(!git_index_find(&entry_idx, repo_index, "conflicts-one.txt")); cl_assert((entry = git_index_get_byindex(repo_index, entry_idx)) != NULL); cl_assert(git_index_entry_stage(entry) == 1); cl_assert(!git_index_find(&entry_idx, repo_index, "conflicts-two.txt")); cl_assert((entry = git_index_get_byindex(repo_index, entry_idx)) != NULL); cl_assert(git_index_entry_stage(entry) == 1); } libgit2-0.19.0/tests-clar/index/tests.c000066400000000000000000000303401216214232500176310ustar00rootroot00000000000000#include "clar_libgit2.h" #include "index.h" static const size_t index_entry_count = 109; static const size_t index_entry_count_2 = 1437; #define TEST_INDEX_PATH cl_fixture("testrepo.git/index") #define TEST_INDEX2_PATH cl_fixture("gitgit.index") #define TEST_INDEXBIG_PATH cl_fixture("big.index") // Suite data struct test_entry { size_t index; char path[128]; git_off_t file_size; git_time_t mtime; }; static struct test_entry test_entries[] = { {4, "Makefile", 5064, 0x4C3F7F33}, {62, "tests/Makefile", 2631, 0x4C3F7F33}, {36, "src/index.c", 10014, 0x4C43368D}, {6, "git.git-authors", 2709, 0x4C3F7F33}, {48, "src/revobject.h", 1448, 0x4C3F7FE2} }; // Helpers static void copy_file(const char *src, const char *dst) { git_buf source_buf = GIT_BUF_INIT; git_file dst_fd; cl_git_pass(git_futils_readbuffer(&source_buf, src)); dst_fd = git_futils_creat_withpath(dst, 0777, 0666); //-V536 if (dst_fd < 0) goto cleanup; cl_git_pass(p_write(dst_fd, source_buf.ptr, source_buf.size)); cleanup: git_buf_free(&source_buf); p_close(dst_fd); } static void files_are_equal(const char *a, const char *b) { git_buf buf_a = GIT_BUF_INIT; git_buf buf_b = GIT_BUF_INIT; int pass; if (git_futils_readbuffer(&buf_a, a) < 0) cl_assert(0); if (git_futils_readbuffer(&buf_b, b) < 0) { git_buf_free(&buf_a); cl_assert(0); } pass = (buf_a.size == buf_b.size && !memcmp(buf_a.ptr, buf_b.ptr, buf_a.size)); git_buf_free(&buf_a); git_buf_free(&buf_b); cl_assert(pass); } // Fixture setup and teardown void test_index_tests__initialize(void) { } void test_index_tests__empty_index(void) { git_index *index; cl_git_pass(git_index_open(&index, "in-memory-index")); cl_assert(index->on_disk == 0); cl_assert(git_index_entrycount(index) == 0); cl_assert(index->entries.sorted); git_index_free(index); } void test_index_tests__default_test_index(void) { git_index *index; unsigned int i; git_index_entry **entries; cl_git_pass(git_index_open(&index, TEST_INDEX_PATH)); cl_assert(index->on_disk); cl_assert(git_index_entrycount(index) == index_entry_count); cl_assert(index->entries.sorted); entries = (git_index_entry **)index->entries.contents; for (i = 0; i < ARRAY_SIZE(test_entries); ++i) { git_index_entry *e = entries[test_entries[i].index]; cl_assert_equal_s(e->path, test_entries[i].path); cl_assert(e->mtime.seconds == test_entries[i].mtime); cl_assert(e->file_size == test_entries[i].file_size); } git_index_free(index); } void test_index_tests__gitgit_index(void) { git_index *index; cl_git_pass(git_index_open(&index, TEST_INDEX2_PATH)); cl_assert(index->on_disk); cl_assert(git_index_entrycount(index) == index_entry_count_2); cl_assert(index->entries.sorted); cl_assert(index->tree != NULL); git_index_free(index); } void test_index_tests__find_in_existing(void) { git_index *index; unsigned int i; cl_git_pass(git_index_open(&index, TEST_INDEX_PATH)); for (i = 0; i < ARRAY_SIZE(test_entries); ++i) { size_t idx; cl_assert(!git_index_find(&idx, index, test_entries[i].path)); cl_assert(idx == test_entries[i].index); } git_index_free(index); } void test_index_tests__find_in_empty(void) { git_index *index; unsigned int i; cl_git_pass(git_index_open(&index, "fake-index")); for (i = 0; i < ARRAY_SIZE(test_entries); ++i) { cl_assert(GIT_ENOTFOUND == git_index_find(NULL, index, test_entries[i].path)); } git_index_free(index); } void test_index_tests__write(void) { git_index *index; copy_file(TEST_INDEXBIG_PATH, "index_rewrite"); cl_git_pass(git_index_open(&index, "index_rewrite")); cl_assert(index->on_disk); cl_git_pass(git_index_write(index)); files_are_equal(TEST_INDEXBIG_PATH, "index_rewrite"); git_index_free(index); p_unlink("index_rewrite"); } void test_index_tests__sort0(void) { // sort the entires in an index /* * TODO: This no longer applies: * index sorting in Git uses some specific changes to the way * directories are sorted. * * We need to specificially check for this by creating a new * index, adding entries in random order and then * checking for consistency */ } void test_index_tests__sort1(void) { // sort the entires in an empty index git_index *index; cl_git_pass(git_index_open(&index, "fake-index")); /* FIXME: this test is slightly dumb */ cl_assert(index->entries.sorted); git_index_free(index); } static void cleanup_myrepo(void *opaque) { GIT_UNUSED(opaque); cl_fixture_cleanup("myrepo"); } void test_index_tests__add(void) { git_index *index; git_filebuf file = GIT_FILEBUF_INIT; git_repository *repo; const git_index_entry *entry; git_oid id1; cl_set_cleanup(&cleanup_myrepo, NULL); /* Intialize a new repository */ cl_git_pass(git_repository_init(&repo, "./myrepo", 0)); /* Ensure we're the only guy in the room */ cl_git_pass(git_repository_index(&index, repo)); cl_assert(git_index_entrycount(index) == 0); /* Create a new file in the working directory */ cl_git_pass(git_futils_mkpath2file("myrepo/test.txt", 0777)); cl_git_pass(git_filebuf_open(&file, "myrepo/test.txt", 0)); cl_git_pass(git_filebuf_write(&file, "hey there\n", 10)); cl_git_pass(git_filebuf_commit(&file, 0666)); /* Store the expected hash of the file/blob * This has been generated by executing the following * $ echo "hey there" | git hash-object --stdin */ cl_git_pass(git_oid_fromstr(&id1, "a8233120f6ad708f843d861ce2b7228ec4e3dec6")); /* Add the new file to the index */ cl_git_pass(git_index_add_bypath(index, "test.txt")); /* Wow... it worked! */ cl_assert(git_index_entrycount(index) == 1); entry = git_index_get_byindex(index, 0); /* And the built-in hashing mechanism worked as expected */ cl_assert(git_oid_cmp(&id1, &entry->oid) == 0); /* Test access by path instead of index */ cl_assert((entry = git_index_get_bypath(index, "test.txt", 0)) != NULL); cl_assert(git_oid_cmp(&id1, &entry->oid) == 0); git_index_free(index); git_repository_free(repo); } static void cleanup_1397(void *opaque) { GIT_UNUSED(opaque); cl_git_sandbox_cleanup(); } void test_index_tests__add_issue_1397(void) { git_index *index; git_repository *repo; const git_index_entry *entry; git_oid id1; cl_set_cleanup(&cleanup_1397, NULL); repo = cl_git_sandbox_init("issue_1397"); cl_repo_set_bool(repo, "core.autocrlf", true); /* Ensure we're the only guy in the room */ cl_git_pass(git_repository_index(&index, repo)); /* Store the expected hash of the file/blob * This has been generated by executing the following * $ git hash-object crlf_file.txt */ cl_git_pass(git_oid_fromstr(&id1, "8312e0889a9cbab77c732b6bc39b51a683e3a318")); /* Make sure the initial SHA-1 is correct */ cl_assert((entry = git_index_get_bypath(index, "crlf_file.txt", 0)) != NULL); cl_assert_(git_oid_cmp(&id1, &entry->oid) == 0, "first oid check"); /* Update the index */ cl_git_pass(git_index_add_bypath(index, "crlf_file.txt")); /* Check the new SHA-1 */ cl_assert((entry = git_index_get_bypath(index, "crlf_file.txt", 0)) != NULL); cl_assert_(git_oid_cmp(&id1, &entry->oid) == 0, "second oid check"); git_index_free(index); } void test_index_tests__add_bypath_to_a_bare_repository_returns_EBAREPO(void) { git_repository *bare_repo; git_index *index; cl_git_pass(git_repository_open(&bare_repo, cl_fixture("testrepo.git"))); cl_git_pass(git_repository_index(&index, bare_repo)); cl_assert_equal_i(GIT_EBAREREPO, git_index_add_bypath(index, "test.txt")); git_index_free(index); git_repository_free(bare_repo); } /* Test that writing an invalid filename fails */ void test_index_tests__write_invalid_filename(void) { git_repository *repo; git_index *index; git_oid expected; p_mkdir("read_tree", 0700); cl_git_pass(git_repository_init(&repo, "./read_tree", 0)); cl_git_pass(git_repository_index(&index, repo)); cl_assert(git_index_entrycount(index) == 0); cl_git_mkfile("./read_tree/.git/hello", NULL); cl_git_pass(git_index_add_bypath(index, ".git/hello")); /* write-tree */ cl_git_fail(git_index_write_tree(&expected, index)); git_index_free(index); git_repository_free(repo); cl_fixture_cleanup("read_tree"); } void test_index_tests__remove_entry(void) { git_repository *repo; git_index *index; p_mkdir("index_test", 0770); cl_git_pass(git_repository_init(&repo, "index_test", 0)); cl_git_pass(git_repository_index(&index, repo)); cl_assert(git_index_entrycount(index) == 0); cl_git_mkfile("index_test/hello", NULL); cl_git_pass(git_index_add_bypath(index, "hello")); cl_git_pass(git_index_write(index)); cl_git_pass(git_index_read(index)); /* reload */ cl_assert(git_index_entrycount(index) == 1); cl_assert(git_index_get_bypath(index, "hello", 0) != NULL); cl_git_pass(git_index_remove(index, "hello", 0)); cl_git_pass(git_index_write(index)); cl_git_pass(git_index_read(index)); /* reload */ cl_assert(git_index_entrycount(index) == 0); cl_assert(git_index_get_bypath(index, "hello", 0) == NULL); git_index_free(index); git_repository_free(repo); cl_fixture_cleanup("index_test"); } void test_index_tests__remove_directory(void) { git_repository *repo; git_index *index; p_mkdir("index_test", 0770); cl_git_pass(git_repository_init(&repo, "index_test", 0)); cl_git_pass(git_repository_index(&index, repo)); cl_assert_equal_i(0, (int)git_index_entrycount(index)); p_mkdir("index_test/a", 0770); cl_git_mkfile("index_test/a/1.txt", NULL); cl_git_mkfile("index_test/a/2.txt", NULL); cl_git_mkfile("index_test/a/3.txt", NULL); cl_git_mkfile("index_test/b.txt", NULL); cl_git_pass(git_index_add_bypath(index, "a/1.txt")); cl_git_pass(git_index_add_bypath(index, "a/2.txt")); cl_git_pass(git_index_add_bypath(index, "a/3.txt")); cl_git_pass(git_index_add_bypath(index, "b.txt")); cl_git_pass(git_index_write(index)); cl_git_pass(git_index_read(index)); /* reload */ cl_assert_equal_i(4, (int)git_index_entrycount(index)); cl_assert(git_index_get_bypath(index, "a/1.txt", 0) != NULL); cl_assert(git_index_get_bypath(index, "a/2.txt", 0) != NULL); cl_assert(git_index_get_bypath(index, "b.txt", 0) != NULL); cl_git_pass(git_index_remove(index, "a/1.txt", 0)); cl_git_pass(git_index_write(index)); cl_git_pass(git_index_read(index)); /* reload */ cl_assert_equal_i(3, (int)git_index_entrycount(index)); cl_assert(git_index_get_bypath(index, "a/1.txt", 0) == NULL); cl_assert(git_index_get_bypath(index, "a/2.txt", 0) != NULL); cl_assert(git_index_get_bypath(index, "b.txt", 0) != NULL); cl_git_pass(git_index_remove_directory(index, "a", 0)); cl_git_pass(git_index_write(index)); cl_git_pass(git_index_read(index)); /* reload */ cl_assert_equal_i(1, (int)git_index_entrycount(index)); cl_assert(git_index_get_bypath(index, "a/1.txt", 0) == NULL); cl_assert(git_index_get_bypath(index, "a/2.txt", 0) == NULL); cl_assert(git_index_get_bypath(index, "b.txt", 0) != NULL); git_index_free(index); git_repository_free(repo); cl_fixture_cleanup("index_test"); } void test_index_tests__preserves_case(void) { git_repository *repo; git_index *index; const git_index_entry *entry; int index_caps; cl_set_cleanup(&cleanup_myrepo, NULL); cl_git_pass(git_repository_init(&repo, "./myrepo", 0)); cl_git_pass(git_repository_index(&index, repo)); index_caps = git_index_caps(index); cl_git_rewritefile("myrepo/test.txt", "hey there\n"); cl_git_pass(git_index_add_bypath(index, "test.txt")); cl_git_pass(p_rename("myrepo/test.txt", "myrepo/TEST.txt")); cl_git_rewritefile("myrepo/TEST.txt", "hello again\n"); cl_git_pass(git_index_add_bypath(index, "TEST.txt")); if (index_caps & GIT_INDEXCAP_IGNORE_CASE) cl_assert_equal_i(1, (int)git_index_entrycount(index)); else cl_assert_equal_i(2, (int)git_index_entrycount(index)); /* Test access by path instead of index */ cl_assert((entry = git_index_get_bypath(index, "test.txt", 0)) != NULL); /* The path should *not* have changed without an explicit remove */ cl_assert(git__strcmp(entry->path, "test.txt") == 0); cl_assert((entry = git_index_get_bypath(index, "TEST.txt", 0)) != NULL); if (index_caps & GIT_INDEXCAP_IGNORE_CASE) /* The path should *not* have changed without an explicit remove */ cl_assert(git__strcmp(entry->path, "test.txt") == 0); else cl_assert(git__strcmp(entry->path, "TEST.txt") == 0); git_index_free(index); git_repository_free(repo); } libgit2-0.19.0/tests-clar/main.c000066400000000000000000000004261216214232500163060ustar00rootroot00000000000000#include "clar_libgit2.h" #ifdef _WIN32 int __cdecl main(int argc, char *argv[]) #else int main(int argc, char *argv[]) #endif { int res; git_threads_init(); /* Run the test suite */ res = clar_test(argc, argv); giterr_clear(); git_threads_shutdown(); return res; } libgit2-0.19.0/tests-clar/merge/000077500000000000000000000000001216214232500163135ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/merge/merge_helpers.c000066400000000000000000000177521216214232500213140ustar00rootroot00000000000000#include "clar_libgit2.h" #include "fileops.h" #include "refs.h" #include "tree.h" #include "merge_helpers.h" #include "merge.h" #include "git2/merge.h" #include "git2/sys/index.h" int merge_trees_from_branches( git_index **index, git_repository *repo, const char *ours_name, const char *theirs_name, git_merge_tree_opts *opts) { git_commit *our_commit, *their_commit, *ancestor_commit = NULL; git_tree *our_tree, *their_tree, *ancestor_tree = NULL; git_oid our_oid, their_oid, ancestor_oid; git_buf branch_buf = GIT_BUF_INIT; int error; git_buf_printf(&branch_buf, "%s%s", GIT_REFS_HEADS_DIR, ours_name); cl_git_pass(git_reference_name_to_id(&our_oid, repo, branch_buf.ptr)); cl_git_pass(git_commit_lookup(&our_commit, repo, &our_oid)); git_buf_clear(&branch_buf); git_buf_printf(&branch_buf, "%s%s", GIT_REFS_HEADS_DIR, theirs_name); cl_git_pass(git_reference_name_to_id(&their_oid, repo, branch_buf.ptr)); cl_git_pass(git_commit_lookup(&their_commit, repo, &their_oid)); error = git_merge_base(&ancestor_oid, repo, git_commit_id(our_commit), git_commit_id(their_commit)); if (error != GIT_ENOTFOUND) { cl_git_pass(error); cl_git_pass(git_commit_lookup(&ancestor_commit, repo, &ancestor_oid)); cl_git_pass(git_commit_tree(&ancestor_tree, ancestor_commit)); } cl_git_pass(git_commit_tree(&our_tree, our_commit)); cl_git_pass(git_commit_tree(&their_tree, their_commit)); cl_git_pass(git_merge_trees(index, repo, ancestor_tree, our_tree, their_tree, opts)); git_buf_free(&branch_buf); git_tree_free(our_tree); git_tree_free(their_tree); git_tree_free(ancestor_tree); git_commit_free(our_commit); git_commit_free(their_commit); git_commit_free(ancestor_commit); return 0; } void merge__dump_index_entries(git_vector *index_entries) { size_t i; const git_index_entry *index_entry; printf ("\nINDEX [%d]:\n", (int)index_entries->length); for (i = 0; i < index_entries->length; i++) { index_entry = index_entries->contents[i]; printf("%o ", index_entry->mode); printf("%s ", git_oid_allocfmt(&index_entry->oid)); printf("%d ", git_index_entry_stage(index_entry)); printf("%s ", index_entry->path); printf("\n"); } printf("\n"); } void merge__dump_names(git_index *index) { size_t i; const git_index_name_entry *conflict_name; for (i = 0; i < git_index_name_entrycount(index); i++) { conflict_name = git_index_name_get_byindex(index, i); printf("%s %s %s\n", conflict_name->ancestor, conflict_name->ours, conflict_name->theirs); } printf("\n"); } void merge__dump_reuc(git_index *index) { size_t i; const git_index_reuc_entry *reuc; printf ("\nREUC:\n"); for (i = 0; i < git_index_reuc_entrycount(index); i++) { reuc = git_index_reuc_get_byindex(index, i); printf("%s ", reuc->path); printf("%o ", reuc->mode[0]); printf("%s\n", git_oid_allocfmt(&reuc->oid[0])); printf(" %o ", reuc->mode[1]); printf(" %s\n", git_oid_allocfmt(&reuc->oid[1])); printf(" %o ", reuc->mode[2]); printf(" %s ", git_oid_allocfmt(&reuc->oid[2])); printf("\n"); } printf("\n"); } static int index_entry_eq_merge_index_entry(const struct merge_index_entry *expected, const git_index_entry *actual) { git_oid expected_oid; bool test_oid; if (strlen(expected->oid_str) != 0) { cl_git_pass(git_oid_fromstr(&expected_oid, expected->oid_str)); test_oid = 1; } else test_oid = 0; if (actual->mode != expected->mode || (test_oid && git_oid_cmp(&actual->oid, &expected_oid) != 0) || git_index_entry_stage(actual) != expected->stage) return 0; if (actual->mode == 0 && (actual->path != NULL || strlen(expected->path) > 0)) return 0; if (actual->mode != 0 && (strcmp(actual->path, expected->path) != 0)) return 0; return 1; } static int name_entry_eq(const char *expected, const char *actual) { if (strlen(expected) == 0) return (actual == NULL) ? 1 : 0; return (strcmp(expected, actual) == 0) ? 1 : 0; } static int name_entry_eq_merge_name_entry(const struct merge_name_entry *expected, const git_index_name_entry *actual) { if (name_entry_eq(expected->ancestor_path, actual->ancestor) == 0 || name_entry_eq(expected->our_path, actual->ours) == 0 || name_entry_eq(expected->their_path, actual->theirs) == 0) return 0; return 1; } static int index_conflict_data_eq_merge_diff(const struct merge_index_conflict_data *expected, git_merge_diff *actual) { if (!index_entry_eq_merge_index_entry(&expected->ancestor.entry, &actual->ancestor_entry) || !index_entry_eq_merge_index_entry(&expected->ours.entry, &actual->our_entry) || !index_entry_eq_merge_index_entry(&expected->theirs.entry, &actual->their_entry)) return 0; if (expected->ours.status != actual->our_status || expected->theirs.status != actual->their_status) return 0; return 1; } int merge_test_merge_conflicts(git_vector *conflicts, const struct merge_index_conflict_data expected[], size_t expected_len) { git_merge_diff *actual; size_t i; if (conflicts->length != expected_len) return 0; for (i = 0; i < expected_len; i++) { actual = conflicts->contents[i]; if (!index_conflict_data_eq_merge_diff(&expected[i], actual)) return 0; } return 1; } int merge_test_index(git_index *index, const struct merge_index_entry expected[], size_t expected_len) { size_t i; const git_index_entry *index_entry; /* dump_index_entries(&index->entries); */ if (git_index_entrycount(index) != expected_len) return 0; for (i = 0; i < expected_len; i++) { if ((index_entry = git_index_get_byindex(index, i)) == NULL) return 0; if (!index_entry_eq_merge_index_entry(&expected[i], index_entry)) return 0; } return 1; } int merge_test_names(git_index *index, const struct merge_name_entry expected[], size_t expected_len) { size_t i; const git_index_name_entry *name_entry; /* dump_names(index); */ if (git_index_name_entrycount(index) != expected_len) return 0; for (i = 0; i < expected_len; i++) { if ((name_entry = git_index_name_get_byindex(index, i)) == NULL) return 0; if (! name_entry_eq_merge_name_entry(&expected[i], name_entry)) return 0; } return 1; } int merge_test_reuc(git_index *index, const struct merge_reuc_entry expected[], size_t expected_len) { size_t i; const git_index_reuc_entry *reuc_entry; git_oid expected_oid; /* dump_reuc(index); */ if (git_index_reuc_entrycount(index) != expected_len) return 0; for (i = 0; i < expected_len; i++) { if ((reuc_entry = git_index_reuc_get_byindex(index, i)) == NULL) return 0; if (strcmp(reuc_entry->path, expected[i].path) != 0 || reuc_entry->mode[0] != expected[i].ancestor_mode || reuc_entry->mode[1] != expected[i].our_mode || reuc_entry->mode[2] != expected[i].their_mode) return 0; if (expected[i].ancestor_mode > 0) { cl_git_pass(git_oid_fromstr(&expected_oid, expected[i].ancestor_oid_str)); if (git_oid_cmp(&reuc_entry->oid[0], &expected_oid) != 0) return 0; } if (expected[i].our_mode > 0) { cl_git_pass(git_oid_fromstr(&expected_oid, expected[i].our_oid_str)); if (git_oid_cmp(&reuc_entry->oid[1], &expected_oid) != 0) return 0; } if (expected[i].their_mode > 0) { cl_git_pass(git_oid_fromstr(&expected_oid, expected[i].their_oid_str)); if (git_oid_cmp(&reuc_entry->oid[2], &expected_oid) != 0) return 0; } } return 1; } int dircount(void *payload, git_buf *pathbuf) { int *entries = payload; size_t len = git_buf_len(pathbuf); if (len < 5 || strcmp(pathbuf->ptr + (git_buf_len(pathbuf) - 5), "/.git") != 0) (*entries)++; return 0; } int merge_test_workdir(git_repository *repo, const struct merge_index_entry expected[], size_t expected_len) { size_t actual_len = 0, i; git_oid actual_oid, expected_oid; git_buf wd = GIT_BUF_INIT; git_buf_puts(&wd, repo->workdir); git_path_direach(&wd, dircount, &actual_len); if (actual_len != expected_len) return 0; for (i = 0; i < expected_len; i++) { git_blob_create_fromworkdir(&actual_oid, repo, expected[i].path); git_oid_fromstr(&expected_oid, expected[i].oid_str); if (git_oid_cmp(&actual_oid, &expected_oid) != 0) return 0; } git_buf_free(&wd); return 1; } libgit2-0.19.0/tests-clar/merge/merge_helpers.h000066400000000000000000000031441216214232500213070ustar00rootroot00000000000000#ifndef INCLUDE_cl_merge_helpers_h__ #define INCLUDE_cl_merge_helpers_h__ #include "merge.h" #include "git2/merge.h" struct merge_index_entry { uint16_t mode; char oid_str[41]; int stage; char path[128]; }; struct merge_name_entry { char ancestor_path[128]; char our_path[128]; char their_path[128]; }; struct merge_index_with_status { struct merge_index_entry entry; unsigned int status; }; struct merge_reuc_entry { char path[128]; unsigned int ancestor_mode; unsigned int our_mode; unsigned int their_mode; char ancestor_oid_str[41]; char our_oid_str[41]; char their_oid_str[41]; }; struct merge_index_conflict_data { struct merge_index_with_status ancestor; struct merge_index_with_status ours; struct merge_index_with_status theirs; git_merge_diff_type_t change_type; }; int merge_trees_from_branches( git_index **index, git_repository *repo, const char *ours_name, const char *theirs_name, git_merge_tree_opts *opts); int merge_test_diff_list(git_merge_diff_list *diff_list, const struct merge_index_entry expected[], size_t expected_len); int merge_test_merge_conflicts(git_vector *conflicts, const struct merge_index_conflict_data expected[], size_t expected_len); int merge_test_index(git_index *index, const struct merge_index_entry expected[], size_t expected_len); int merge_test_names(git_index *index, const struct merge_name_entry expected[], size_t expected_len); int merge_test_reuc(git_index *index, const struct merge_reuc_entry expected[], size_t expected_len); int merge_test_workdir(git_repository *repo, const struct merge_index_entry expected[], size_t expected_len); #endif libgit2-0.19.0/tests-clar/merge/trees/000077500000000000000000000000001216214232500174355ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/merge/trees/automerge.c000066400000000000000000000166311216214232500216000ustar00rootroot00000000000000#include "clar_libgit2.h" #include "git2/repository.h" #include "git2/merge.h" #include "buffer.h" #include "merge.h" #include "../merge_helpers.h" #include "fileops.h" static git_repository *repo; #define TEST_REPO_PATH "merge-resolve" #define TEST_INDEX_PATH TEST_REPO_PATH "/.git/index" #define THEIRS_AUTOMERGE_BRANCH "branch" #define THEIRS_UNRELATED_BRANCH "unrelated" #define THEIRS_UNRELATED_OID "55b4e4687e7a0d9ca367016ed930f385d4022e6f" #define THEIRS_UNRELATED_PARENT "d6cf6c7741b3316826af1314042550c97ded1d50" #define OURS_DIRECTORY_FILE "df_side1" #define THEIRS_DIRECTORY_FILE "df_side2" /* Non-conflicting files, index entries are common to every merge operation */ #define ADDED_IN_MASTER_INDEX_ENTRY \ { 0100644, "233c0919c998ed110a4b6ff36f353aec8b713487", 0, "added-in-master.txt" } #define AUTOMERGEABLE_INDEX_ENTRY \ { 0100644, "f2e1550a0c9e53d5811175864a29536642ae3821", 0, "automergeable.txt" } #define CHANGED_IN_BRANCH_INDEX_ENTRY \ { 0100644, "4eb04c9e79e88f6640d01ff5b25ca2a60764f216", 0, "changed-in-branch.txt" } #define CHANGED_IN_MASTER_INDEX_ENTRY \ { 0100644, "11deab00b2d3a6f5a3073988ac050c2d7b6655e2", 0, "changed-in-master.txt" } #define UNCHANGED_INDEX_ENTRY \ { 0100644, "c8f06f2e3bb2964174677e91f0abead0e43c9e5d", 0, "unchanged.txt" } /* Expected REUC entries */ #define AUTOMERGEABLE_REUC_ENTRY \ { "automergeable.txt", 0100644, 0100644, 0100644, \ "6212c31dab5e482247d7977e4f0dd3601decf13b", \ "ee3fa1b8c00aff7fe02065fdb50864bb0d932ccf", \ "058541fc37114bfc1dddf6bd6bffc7fae5c2e6fe" } #define CONFLICTING_REUC_ENTRY \ { "conflicting.txt", 0100644, 0100644, 0100644, \ "d427e0b2e138501a3d15cc376077a3631e15bd46", \ "4e886e602529caa9ab11d71f86634bd1b6e0de10", \ "2bd0a343aeef7a2cf0d158478966a6e587ff3863" } #define REMOVED_IN_BRANCH_REUC_ENTRY \ { "removed-in-branch.txt", 0100644, 0100644, 0, \ "dfe3f22baa1f6fce5447901c3086bae368de6bdd", \ "dfe3f22baa1f6fce5447901c3086bae368de6bdd", \ "" } #define REMOVED_IN_MASTER_REUC_ENTRY \ { "removed-in-master.txt", 0100644, 0, 0100644, \ "5c3b68a71fc4fa5d362fd3875e53137c6a5ab7a5", \ "", \ "5c3b68a71fc4fa5d362fd3875e53137c6a5ab7a5" } #define AUTOMERGEABLE_MERGED_FILE \ "this file is changed in master\n" \ "this file is automergeable\n" \ "this file is automergeable\n" \ "this file is automergeable\n" \ "this file is automergeable\n" \ "this file is automergeable\n" \ "this file is automergeable\n" \ "this file is automergeable\n" \ "this file is changed in branch\n" #define AUTOMERGEABLE_MERGED_FILE_CRLF \ "this file is changed in master\r\n" \ "this file is automergeable\r\n" \ "this file is automergeable\r\n" \ "this file is automergeable\r\n" \ "this file is automergeable\r\n" \ "this file is automergeable\r\n" \ "this file is automergeable\r\n" \ "this file is automergeable\r\n" \ "this file is changed in branch\r\n" // Fixture setup and teardown void test_merge_trees_automerge__initialize(void) { repo = cl_git_sandbox_init(TEST_REPO_PATH); } void test_merge_trees_automerge__cleanup(void) { cl_git_sandbox_cleanup(); } void test_merge_trees_automerge__automerge(void) { git_index *index; const git_index_entry *entry; git_merge_tree_opts opts = GIT_MERGE_TREE_OPTS_INIT; git_blob *blob; struct merge_index_entry merge_index_entries[] = { ADDED_IN_MASTER_INDEX_ENTRY, AUTOMERGEABLE_INDEX_ENTRY, CHANGED_IN_BRANCH_INDEX_ENTRY, CHANGED_IN_MASTER_INDEX_ENTRY, { 0100644, "d427e0b2e138501a3d15cc376077a3631e15bd46", 1, "conflicting.txt" }, { 0100644, "4e886e602529caa9ab11d71f86634bd1b6e0de10", 2, "conflicting.txt" }, { 0100644, "2bd0a343aeef7a2cf0d158478966a6e587ff3863", 3, "conflicting.txt" }, UNCHANGED_INDEX_ENTRY, }; struct merge_reuc_entry merge_reuc_entries[] = { AUTOMERGEABLE_REUC_ENTRY, REMOVED_IN_BRANCH_REUC_ENTRY, REMOVED_IN_MASTER_REUC_ENTRY }; cl_git_pass(merge_trees_from_branches(&index, repo, "master", THEIRS_AUTOMERGE_BRANCH, &opts)); cl_assert(merge_test_index(index, merge_index_entries, 8)); cl_assert(merge_test_reuc(index, merge_reuc_entries, 3)); cl_assert((entry = git_index_get_bypath(index, "automergeable.txt", 0)) != NULL); cl_assert(entry->file_size == strlen(AUTOMERGEABLE_MERGED_FILE)); cl_git_pass(git_object_lookup((git_object **)&blob, repo, &entry->oid, GIT_OBJ_BLOB)); cl_assert(memcmp(git_blob_rawcontent(blob), AUTOMERGEABLE_MERGED_FILE, entry->file_size) == 0); git_index_free(index); git_blob_free(blob); } void test_merge_trees_automerge__favor_ours(void) { git_index *index; git_merge_tree_opts opts = GIT_MERGE_TREE_OPTS_INIT; struct merge_index_entry merge_index_entries[] = { ADDED_IN_MASTER_INDEX_ENTRY, AUTOMERGEABLE_INDEX_ENTRY, CHANGED_IN_BRANCH_INDEX_ENTRY, CHANGED_IN_MASTER_INDEX_ENTRY, { 0100644, "4e886e602529caa9ab11d71f86634bd1b6e0de10", 0, "conflicting.txt" }, UNCHANGED_INDEX_ENTRY, }; struct merge_reuc_entry merge_reuc_entries[] = { AUTOMERGEABLE_REUC_ENTRY, CONFLICTING_REUC_ENTRY, REMOVED_IN_BRANCH_REUC_ENTRY, REMOVED_IN_MASTER_REUC_ENTRY, }; opts.automerge_flags = GIT_MERGE_AUTOMERGE_FAVOR_OURS; cl_git_pass(merge_trees_from_branches(&index, repo, "master", THEIRS_AUTOMERGE_BRANCH, &opts)); cl_assert(merge_test_index(index, merge_index_entries, 6)); cl_assert(merge_test_reuc(index, merge_reuc_entries, 4)); git_index_free(index); } void test_merge_trees_automerge__favor_theirs(void) { git_index *index; git_merge_tree_opts opts = GIT_MERGE_TREE_OPTS_INIT; struct merge_index_entry merge_index_entries[] = { ADDED_IN_MASTER_INDEX_ENTRY, AUTOMERGEABLE_INDEX_ENTRY, CHANGED_IN_BRANCH_INDEX_ENTRY, CHANGED_IN_MASTER_INDEX_ENTRY, { 0100644, "2bd0a343aeef7a2cf0d158478966a6e587ff3863", 0, "conflicting.txt" }, UNCHANGED_INDEX_ENTRY, }; struct merge_reuc_entry merge_reuc_entries[] = { AUTOMERGEABLE_REUC_ENTRY, CONFLICTING_REUC_ENTRY, REMOVED_IN_BRANCH_REUC_ENTRY, REMOVED_IN_MASTER_REUC_ENTRY, }; opts.automerge_flags = GIT_MERGE_AUTOMERGE_FAVOR_THEIRS; cl_git_pass(merge_trees_from_branches(&index, repo, "master", THEIRS_AUTOMERGE_BRANCH, &opts)); cl_assert(merge_test_index(index, merge_index_entries, 6)); cl_assert(merge_test_reuc(index, merge_reuc_entries, 4)); git_index_free(index); } void test_merge_trees_automerge__unrelated(void) { git_index *index; git_merge_tree_opts opts = GIT_MERGE_TREE_OPTS_INIT; struct merge_index_entry merge_index_entries[] = { { 0100644, "233c0919c998ed110a4b6ff36f353aec8b713487", 0, "added-in-master.txt" }, { 0100644, "ee3fa1b8c00aff7fe02065fdb50864bb0d932ccf", 2, "automergeable.txt" }, { 0100644, "d07ec190c306ec690bac349e87d01c4358e49bb2", 3, "automergeable.txt" }, { 0100644, "ab6c44a2e84492ad4b41bb6bac87353e9d02ac8b", 0, "changed-in-branch.txt" }, { 0100644, "11deab00b2d3a6f5a3073988ac050c2d7b6655e2", 0, "changed-in-master.txt" }, { 0100644, "4e886e602529caa9ab11d71f86634bd1b6e0de10", 2, "conflicting.txt" }, { 0100644, "4b253da36a0ae8bfce63aeabd8c5b58429925594", 3, "conflicting.txt" }, { 0100644, "ef58fdd8086c243bdc81f99e379acacfd21d32d6", 0, "new-in-unrelated1.txt" }, { 0100644, "948ba6e701c1edab0c2d394fb7c5538334129793", 0, "new-in-unrelated2.txt" }, { 0100644, "dfe3f22baa1f6fce5447901c3086bae368de6bdd", 0, "removed-in-branch.txt" }, { 0100644, "c8f06f2e3bb2964174677e91f0abead0e43c9e5d", 0, "unchanged.txt" }, }; cl_git_pass(merge_trees_from_branches(&index, repo, "master", THEIRS_UNRELATED_BRANCH, &opts)); cl_assert(merge_test_index(index, merge_index_entries, 11)); git_index_free(index); } libgit2-0.19.0/tests-clar/merge/trees/modeconflict.c000066400000000000000000000044421216214232500222530ustar00rootroot00000000000000#include "clar_libgit2.h" #include "git2/repository.h" #include "git2/merge.h" #include "buffer.h" #include "merge.h" #include "../merge_helpers.h" #include "fileops.h" static git_repository *repo; #define TEST_REPO_PATH "merge-resolve" #define DF_SIDE1_BRANCH "df_side1" #define DF_SIDE2_BRANCH "df_side2" // Fixture setup and teardown void test_merge_trees_modeconflict__initialize(void) { repo = cl_git_sandbox_init(TEST_REPO_PATH); } void test_merge_trees_modeconflict__cleanup(void) { cl_git_sandbox_cleanup(); } void test_merge_trees_modeconflict__df_conflict(void) { git_index *index; struct merge_index_entry merge_index_entries[] = { { 0100644, "49130a28ef567af9a6a6104c38773fedfa5f9742", 2, "dir-10" }, { 0100644, "6c06dcd163587c2cc18be44857e0b71116382aeb", 3, "dir-10" }, { 0100644, "43aafd43bea779ec74317dc361f45ae3f532a505", 0, "dir-6" }, { 0100644, "a031a28ae70e33a641ce4b8a8f6317f1ab79dee4", 3, "dir-7" }, { 0100644, "5012fd565b1393bdfda1805d4ec38ce6619e1fd1", 1, "dir-7/file.txt" }, { 0100644, "a5563304ddf6caba25cb50323a2ea6f7dbfcadca", 2, "dir-7/file.txt" }, { 0100644, "e9ad6ec3e38364a3d07feda7c4197d4d845c53b5", 0, "dir-8" }, { 0100644, "3ef4d30382ca33fdeba9fda895a99e0891ba37aa", 2, "dir-9" }, { 0100644, "fc4c636d6515e9e261f9260dbcf3cc6eca97ea08", 1, "dir-9/file.txt" }, { 0100644, "76ab0e2868197ec158ddd6c78d8a0d2fd73d38f9", 3, "dir-9/file.txt" }, { 0100644, "5c2411f8075f48a6b2fdb85ebc0d371747c4df15", 0, "file-1/new" }, { 0100644, "a39a620dae5bc8b4e771cd4d251b7d080401a21e", 1, "file-2" }, { 0100644, "d963979c237d08b6ba39062ee7bf64c7d34a27f8", 2, "file-2" }, { 0100644, "5c341ead2ba6f2af98ce5ec3fe84f6b6d2899c0d", 0, "file-2/new" }, { 0100644, "9efe7723802d4305142eee177e018fee1572c4f4", 0, "file-3/new" }, { 0100644, "bacac9b3493509aa15e1730e1545fc0919d1dae0", 1, "file-4" }, { 0100644, "7663fce0130db092936b137cabd693ec234eb060", 3, "file-4" }, { 0100644, "e49f917b448d1340b31d76e54ba388268fd4c922", 0, "file-4/new" }, { 0100644, "cab2cf23998b40f1af2d9d9a756dc9e285a8df4b", 2, "file-5/new" }, { 0100644, "f5504f36e6f4eb797a56fc5bac6c6c7f32969bf2", 3, "file-5/new" }, }; cl_git_pass(merge_trees_from_branches(&index, repo, DF_SIDE1_BRANCH, DF_SIDE2_BRANCH, NULL)); cl_assert(merge_test_index(index, merge_index_entries, 20)); git_index_free(index); } libgit2-0.19.0/tests-clar/merge/trees/renames.c000066400000000000000000000255121216214232500212400ustar00rootroot00000000000000#include "clar_libgit2.h" #include "git2/repository.h" #include "git2/merge.h" #include "buffer.h" #include "merge.h" #include "../merge_helpers.h" #include "fileops.h" static git_repository *repo; #define TEST_REPO_PATH "merge-resolve" #define BRANCH_RENAME_OURS "rename_conflict_ours" #define BRANCH_RENAME_THEIRS "rename_conflict_theirs" // Fixture setup and teardown void test_merge_trees_renames__initialize(void) { repo = cl_git_sandbox_init(TEST_REPO_PATH); } void test_merge_trees_renames__cleanup(void) { cl_git_sandbox_cleanup(); } void test_merge_trees_renames__index(void) { git_index *index; git_merge_tree_opts *opts = NULL; struct merge_index_entry merge_index_entries[] = { { 0100644, "68c6c84b091926c7d90aa6a79b2bc3bb6adccd8e", 0, "0a-no-change.txt" }, { 0100644, "f0ce2b8e4986084d9b308fb72709e414c23eb5e6", 0, "0b-duplicated-in-ours.txt" }, { 0100644, "f0ce2b8e4986084d9b308fb72709e414c23eb5e6", 1, "0b-rewritten-in-ours.txt" }, { 0100644, "e376fbdd06ebf021c92724da9f26f44212734e3e", 2, "0b-rewritten-in-ours.txt" }, { 0100644, "b2d399ae15224e1d58066e3c8df70ce37de7a656", 3, "0b-rewritten-in-ours.txt" }, { 0100644, "2f56120107d680129a5d9791b521cb1e73a2ed31", 0, "0c-duplicated-in-theirs.txt" }, { 0100644, "2f56120107d680129a5d9791b521cb1e73a2ed31", 1, "0c-rewritten-in-theirs.txt" }, { 0100644, "efc9121fdedaf08ba180b53ebfbcf71bd488ed09", 2, "0c-rewritten-in-theirs.txt" }, { 0100644, "712ebba6669ea847d9829e4f1059d6c830c8b531", 3, "0c-rewritten-in-theirs.txt" }, { 0100644, "0d872f8e871a30208305978ecbf9e66d864f1638", 0, "1a-newname-in-ours-edited-in-theirs.txt" }, { 0100644, "d0d4594e16f2e19107e3fa7ea63e7aaaff305ffb", 0, "1a-newname-in-ours.txt" }, { 0100644, "ed9523e62e453e50dd9be1606af19399b96e397a", 0, "1b-newname-in-theirs-edited-in-ours.txt" }, { 0100644, "2b5f1f181ee3b58ea751f5dd5d8f9b445520a136", 0, "1b-newname-in-theirs.txt" }, { 0100644, "178940b450f238a56c0d75b7955cb57b38191982", 0, "2-newname-in-both.txt" }, { 0100644, "18cb316b1cefa0f8a6946f0e201a8e1a6f845ab9", 2, "3a-newname-in-ours-deleted-in-theirs.txt" }, { 0100644, "18cb316b1cefa0f8a6946f0e201a8e1a6f845ab9", 1, "3a-renamed-in-ours-deleted-in-theirs.txt" }, { 0100644, "36219b49367146cb2e6a1555b5a9ebd4d0328495", 3, "3b-newname-in-theirs-deleted-in-ours.txt" }, { 0100644, "36219b49367146cb2e6a1555b5a9ebd4d0328495", 1, "3b-renamed-in-theirs-deleted-in-ours.txt" }, { 0100644, "227792b52aaa0b238bea00ec7e509b02623f168c", 2, "4a-newname-in-ours-added-in-theirs.txt" }, { 0100644, "8b5b53cb2aa9ceb1139f5312fcfa3cc3c5a47c9a", 3, "4a-newname-in-ours-added-in-theirs.txt" }, { 0100644, "227792b52aaa0b238bea00ec7e509b02623f168c", 1, "4a-renamed-in-ours-added-in-theirs.txt" }, { 0100644, "de872ee3618b894992e9d1e18ba2ebe256a112f9", 2, "4b-newname-in-theirs-added-in-ours.txt" }, { 0100644, "98d52d07c0b0bbf2b46548f6aa521295c2cb55db", 3, "4b-newname-in-theirs-added-in-ours.txt" }, { 0100644, "98d52d07c0b0bbf2b46548f6aa521295c2cb55db", 1, "4b-renamed-in-theirs-added-in-ours.txt" }, { 0100644, "d3719a5ae8e4d92276b5313ce976f6ee5af2b436", 2, "5a-newname-in-ours-added-in-theirs.txt" }, { 0100644, "98ba4205fcf31f5dd93c916d35fe3f3b3d0e6714", 3, "5a-newname-in-ours-added-in-theirs.txt" }, { 0100644, "d3719a5ae8e4d92276b5313ce976f6ee5af2b436", 1, "5a-renamed-in-ours-added-in-theirs.txt" }, { 0100644, "d3719a5ae8e4d92276b5313ce976f6ee5af2b436", 3, "5a-renamed-in-ours-added-in-theirs.txt" }, { 0100644, "385c8a0f26ddf79e9041e15e17dc352ed2c4cced", 2, "5b-newname-in-theirs-added-in-ours.txt" }, { 0100644, "63247125386de9ec90a27ad36169307bf8a11a38", 3, "5b-newname-in-theirs-added-in-ours.txt" }, { 0100644, "63247125386de9ec90a27ad36169307bf8a11a38", 1, "5b-renamed-in-theirs-added-in-ours.txt" }, { 0100644, "63247125386de9ec90a27ad36169307bf8a11a38", 2, "5b-renamed-in-theirs-added-in-ours.txt" }, { 0100644, "d8fa77b6833082c1ea36b7828a582d4c43882450", 2, "6-both-renamed-1-to-2-ours.txt" }, { 0100644, "d8fa77b6833082c1ea36b7828a582d4c43882450", 3, "6-both-renamed-1-to-2-theirs.txt" }, { 0100644, "d8fa77b6833082c1ea36b7828a582d4c43882450", 1, "6-both-renamed-1-to-2.txt" }, { 0100644, "b42712cfe99a1a500b2a51fe984e0b8a7702ba11", 1, "7-both-renamed-side-1.txt" }, { 0100644, "b42712cfe99a1a500b2a51fe984e0b8a7702ba11", 3, "7-both-renamed-side-1.txt" }, { 0100644, "b69fe837e4cecfd4c9a40cdca7c138468687df07", 1, "7-both-renamed-side-2.txt" }, { 0100644, "b69fe837e4cecfd4c9a40cdca7c138468687df07", 2, "7-both-renamed-side-2.txt" }, { 0100644, "b42712cfe99a1a500b2a51fe984e0b8a7702ba11", 2, "7-both-renamed.txt" }, { 0100644, "b69fe837e4cecfd4c9a40cdca7c138468687df07", 3, "7-both-renamed.txt" }, }; struct merge_name_entry merge_name_entries[] = { { "3a-renamed-in-ours-deleted-in-theirs.txt", "3a-newname-in-ours-deleted-in-theirs.txt", "" }, { "3b-renamed-in-theirs-deleted-in-ours.txt", "", "3b-newname-in-theirs-deleted-in-ours.txt", }, { "4a-renamed-in-ours-added-in-theirs.txt", "4a-newname-in-ours-added-in-theirs.txt", "", }, { "4b-renamed-in-theirs-added-in-ours.txt", "", "4b-newname-in-theirs-added-in-ours.txt", }, { "5a-renamed-in-ours-added-in-theirs.txt", "5a-newname-in-ours-added-in-theirs.txt", "5a-renamed-in-ours-added-in-theirs.txt", }, { "5b-renamed-in-theirs-added-in-ours.txt", "5b-renamed-in-theirs-added-in-ours.txt", "5b-newname-in-theirs-added-in-ours.txt", }, { "6-both-renamed-1-to-2.txt", "6-both-renamed-1-to-2-ours.txt", "6-both-renamed-1-to-2-theirs.txt", }, { "7-both-renamed-side-1.txt", "7-both-renamed.txt", "7-both-renamed-side-1.txt", }, { "7-both-renamed-side-2.txt", "7-both-renamed-side-2.txt", "7-both-renamed.txt", }, }; struct merge_reuc_entry merge_reuc_entries[] = { { "1a-newname-in-ours-edited-in-theirs.txt", 0, 0100644, 0, "", "c3d02eeef75183df7584d8d13ac03053910c1301", "" }, { "1a-newname-in-ours.txt", 0, 0100644, 0, "", "d0d4594e16f2e19107e3fa7ea63e7aaaff305ffb", "" }, { "1a-renamed-in-ours-edited-in-theirs.txt", 0100644, 0, 0100644, "c3d02eeef75183df7584d8d13ac03053910c1301", "", "0d872f8e871a30208305978ecbf9e66d864f1638" }, { "1a-renamed-in-ours.txt", 0100644, 0, 0100644, "d0d4594e16f2e19107e3fa7ea63e7aaaff305ffb", "", "d0d4594e16f2e19107e3fa7ea63e7aaaff305ffb" }, { "1b-newname-in-theirs-edited-in-ours.txt", 0, 0, 0100644, "", "", "241a1005cd9b980732741b74385b891142bcba28" }, { "1b-newname-in-theirs.txt", 0, 0, 0100644, "", "", "2b5f1f181ee3b58ea751f5dd5d8f9b445520a136" }, { "1b-renamed-in-theirs-edited-in-ours.txt", 0100644, 0100644, 0, "241a1005cd9b980732741b74385b891142bcba28", "ed9523e62e453e50dd9be1606af19399b96e397a", "" }, { "1b-renamed-in-theirs.txt", 0100644, 0100644, 0, "2b5f1f181ee3b58ea751f5dd5d8f9b445520a136", "2b5f1f181ee3b58ea751f5dd5d8f9b445520a136", "" }, { "2-newname-in-both.txt", 0, 0100644, 0100644, "", "178940b450f238a56c0d75b7955cb57b38191982", "178940b450f238a56c0d75b7955cb57b38191982" }, { "2-renamed-in-both.txt", 0100644, 0, 0, "178940b450f238a56c0d75b7955cb57b38191982", "", "" }, }; cl_git_pass(merge_trees_from_branches(&index, repo, BRANCH_RENAME_OURS, BRANCH_RENAME_THEIRS, opts)); cl_assert(merge_test_index(index, merge_index_entries, 41)); cl_assert(merge_test_names(index, merge_name_entries, 9)); cl_assert(merge_test_reuc(index, merge_reuc_entries, 10)); git_index_free(index); } void test_merge_trees_renames__no_rename_index(void) { git_index *index; git_merge_tree_opts opts = GIT_MERGE_TREE_OPTS_INIT; struct merge_index_entry merge_index_entries[] = { { 0100644, "68c6c84b091926c7d90aa6a79b2bc3bb6adccd8e", 0, "0a-no-change.txt" }, { 0100644, "f0ce2b8e4986084d9b308fb72709e414c23eb5e6", 0, "0b-duplicated-in-ours.txt" }, { 0100644, "f0ce2b8e4986084d9b308fb72709e414c23eb5e6", 1, "0b-rewritten-in-ours.txt" }, { 0100644, "e376fbdd06ebf021c92724da9f26f44212734e3e", 2, "0b-rewritten-in-ours.txt" }, { 0100644, "b2d399ae15224e1d58066e3c8df70ce37de7a656", 3, "0b-rewritten-in-ours.txt" }, { 0100644, "2f56120107d680129a5d9791b521cb1e73a2ed31", 0, "0c-duplicated-in-theirs.txt" }, { 0100644, "2f56120107d680129a5d9791b521cb1e73a2ed31", 1, "0c-rewritten-in-theirs.txt" }, { 0100644, "efc9121fdedaf08ba180b53ebfbcf71bd488ed09", 2, "0c-rewritten-in-theirs.txt" }, { 0100644, "712ebba6669ea847d9829e4f1059d6c830c8b531", 3, "0c-rewritten-in-theirs.txt" }, { 0100644, "c3d02eeef75183df7584d8d13ac03053910c1301", 0, "1a-newname-in-ours-edited-in-theirs.txt" }, { 0100644, "d0d4594e16f2e19107e3fa7ea63e7aaaff305ffb", 0, "1a-newname-in-ours.txt" }, { 0100644, "c3d02eeef75183df7584d8d13ac03053910c1301", 1, "1a-renamed-in-ours-edited-in-theirs.txt" }, { 0100644, "0d872f8e871a30208305978ecbf9e66d864f1638", 3, "1a-renamed-in-ours-edited-in-theirs.txt" }, { 0100644, "241a1005cd9b980732741b74385b891142bcba28", 0, "1b-newname-in-theirs-edited-in-ours.txt" }, { 0100644, "2b5f1f181ee3b58ea751f5dd5d8f9b445520a136", 0, "1b-newname-in-theirs.txt" }, { 0100644, "241a1005cd9b980732741b74385b891142bcba28", 1, "1b-renamed-in-theirs-edited-in-ours.txt" }, { 0100644, "ed9523e62e453e50dd9be1606af19399b96e397a", 2, "1b-renamed-in-theirs-edited-in-ours.txt" }, { 0100644, "178940b450f238a56c0d75b7955cb57b38191982", 0, "2-newname-in-both.txt" }, { 0100644, "18cb316b1cefa0f8a6946f0e201a8e1a6f845ab9", 0, "3a-newname-in-ours-deleted-in-theirs.txt" }, { 0100644, "36219b49367146cb2e6a1555b5a9ebd4d0328495", 0, "3b-newname-in-theirs-deleted-in-ours.txt" }, { 0100644, "227792b52aaa0b238bea00ec7e509b02623f168c", 2, "4a-newname-in-ours-added-in-theirs.txt" }, { 0100644, "8b5b53cb2aa9ceb1139f5312fcfa3cc3c5a47c9a", 3, "4a-newname-in-ours-added-in-theirs.txt" }, { 0100644, "de872ee3618b894992e9d1e18ba2ebe256a112f9", 2, "4b-newname-in-theirs-added-in-ours.txt" }, { 0100644, "98d52d07c0b0bbf2b46548f6aa521295c2cb55db", 3, "4b-newname-in-theirs-added-in-ours.txt" }, { 0100644, "d3719a5ae8e4d92276b5313ce976f6ee5af2b436", 2, "5a-newname-in-ours-added-in-theirs.txt" }, { 0100644, "98ba4205fcf31f5dd93c916d35fe3f3b3d0e6714", 3, "5a-newname-in-ours-added-in-theirs.txt" }, { 0100644, "385c8a0f26ddf79e9041e15e17dc352ed2c4cced", 2, "5b-newname-in-theirs-added-in-ours.txt" }, { 0100644, "63247125386de9ec90a27ad36169307bf8a11a38", 3, "5b-newname-in-theirs-added-in-ours.txt" }, { 0100644, "d8fa77b6833082c1ea36b7828a582d4c43882450", 0, "6-both-renamed-1-to-2-ours.txt" }, { 0100644, "d8fa77b6833082c1ea36b7828a582d4c43882450", 0, "6-both-renamed-1-to-2-theirs.txt" }, { 0100644, "b42712cfe99a1a500b2a51fe984e0b8a7702ba11", 2, "7-both-renamed.txt" }, { 0100644, "b69fe837e4cecfd4c9a40cdca7c138468687df07", 3, "7-both-renamed.txt" }, }; cl_git_pass(merge_trees_from_branches(&index, repo, BRANCH_RENAME_OURS, BRANCH_RENAME_THEIRS, &opts)); cl_assert(merge_test_index(index, merge_index_entries, 32)); git_index_free(index); } libgit2-0.19.0/tests-clar/merge/trees/treediff.c000066400000000000000000000546551216214232500214100ustar00rootroot00000000000000#include "clar_libgit2.h" #include "git2/tree.h" #include "merge.h" #include "../merge_helpers.h" #include "diff.h" #include "hashsig.h" static git_repository *repo; #define TEST_REPO_PATH "merge-resolve" #define TREE_OID_ANCESTOR "0d52e3a556e189ba0948ae56780918011c1b167d" #define TREE_OID_MASTER "1f81433e3161efbf250576c58fede7f6b836f3d3" #define TREE_OID_BRANCH "eea9286df54245fea72c5b557291470eb825f38f" #define TREE_OID_RENAMES1 "f5f9dd5886a6ee20272be0aafc790cba43b31931" #define TREE_OID_RENAMES2 "5fbfbdc04b4eca46f54f4853a3c5a1dce28f5165" #define TREE_OID_DF_ANCESTOR "b8a3a806d3950e8c0a03a34f234a92eff0e2c68d" #define TREE_OID_DF_SIDE1 "ee1d6f164893c1866a323f072eeed36b855656be" #define TREE_OID_DF_SIDE2 "6178885b38fe96e825ac0f492c0a941f288b37f6" #define TREE_OID_RENAME_CONFLICT_ANCESTOR "476dbb3e207313d1d8aaa120c6ad204bf1295e53" #define TREE_OID_RENAME_CONFLICT_OURS "c4efe31e9decccc8b2b4d3df9aac2cdfe2995618" #define TREE_OID_RENAME_CONFLICT_THEIRS "9e7f4359c469f309b6057febf4c6e80742cbed5b" void test_merge_trees_treediff__initialize(void) { repo = cl_git_sandbox_init(TEST_REPO_PATH); } void test_merge_trees_treediff__cleanup(void) { cl_git_sandbox_cleanup(); } static void test_find_differences( const char *ancestor_oidstr, const char *ours_oidstr, const char *theirs_oidstr, struct merge_index_conflict_data *treediff_conflict_data, size_t treediff_conflict_data_len) { git_merge_diff_list *merge_diff_list = git_merge_diff_list__alloc(repo); git_oid ancestor_oid, ours_oid, theirs_oid; git_tree *ancestor_tree, *ours_tree, *theirs_tree; git_merge_tree_opts opts = GIT_MERGE_TREE_OPTS_INIT; opts.flags |= GIT_MERGE_TREE_FIND_RENAMES; opts.target_limit = 1000; opts.rename_threshold = 50; opts.metric = git__malloc(sizeof(git_diff_similarity_metric)); cl_assert(opts.metric != NULL); opts.metric->file_signature = git_diff_find_similar__hashsig_for_file; opts.metric->buffer_signature = git_diff_find_similar__hashsig_for_buf; opts.metric->free_signature = git_diff_find_similar__hashsig_free; opts.metric->similarity = git_diff_find_similar__calc_similarity; opts.metric->payload = (void *)GIT_HASHSIG_SMART_WHITESPACE; cl_git_pass(git_oid_fromstr(&ancestor_oid, ancestor_oidstr)); cl_git_pass(git_oid_fromstr(&ours_oid, ours_oidstr)); cl_git_pass(git_oid_fromstr(&theirs_oid, theirs_oidstr)); cl_git_pass(git_tree_lookup(&ancestor_tree, repo, &ancestor_oid)); cl_git_pass(git_tree_lookup(&ours_tree, repo, &ours_oid)); cl_git_pass(git_tree_lookup(&theirs_tree, repo, &theirs_oid)); cl_git_pass(git_merge_diff_list__find_differences(merge_diff_list, ancestor_tree, ours_tree, theirs_tree)); cl_git_pass(git_merge_diff_list__find_renames(repo, merge_diff_list, &opts)); /* dump_merge_index(merge_index); */ cl_assert(treediff_conflict_data_len == merge_diff_list->conflicts.length); cl_assert(merge_test_merge_conflicts(&merge_diff_list->conflicts, treediff_conflict_data, treediff_conflict_data_len)); git_tree_free(ancestor_tree); git_tree_free(ours_tree); git_tree_free(theirs_tree); git_merge_diff_list__free(merge_diff_list); git__free(opts.metric); } void test_merge_trees_treediff__simple(void) { struct merge_index_conflict_data treediff_conflict_data[] = { { { { 0, "", 0, "" }, GIT_DELTA_UNMODIFIED }, { { 0100644, "233c0919c998ed110a4b6ff36f353aec8b713487", 0, "added-in-master.txt" }, GIT_DELTA_ADDED }, { { 0, "", 0, "" }, GIT_DELTA_UNMODIFIED }, GIT_MERGE_DIFF_NONE }, { { { 0100644, "6212c31dab5e482247d7977e4f0dd3601decf13b", 0, "automergeable.txt" }, GIT_DELTA_UNMODIFIED }, { { 0100644, "ee3fa1b8c00aff7fe02065fdb50864bb0d932ccf", 0, "automergeable.txt" }, GIT_DELTA_MODIFIED }, { { 0100644, "058541fc37114bfc1dddf6bd6bffc7fae5c2e6fe", 0, "automergeable.txt" }, GIT_DELTA_MODIFIED }, GIT_MERGE_DIFF_BOTH_MODIFIED }, { { { 0100644, "ab6c44a2e84492ad4b41bb6bac87353e9d02ac8b", 0, "changed-in-branch.txt" }, GIT_DELTA_UNMODIFIED }, { { 0100644, "ab6c44a2e84492ad4b41bb6bac87353e9d02ac8b", 0, "changed-in-branch.txt" }, GIT_DELTA_UNMODIFIED }, { { 0100644, "4eb04c9e79e88f6640d01ff5b25ca2a60764f216", 0, "changed-in-branch.txt" }, GIT_DELTA_MODIFIED }, GIT_MERGE_DIFF_NONE }, { { { 0100644, "ab6c44a2e84492ad4b41bb6bac87353e9d02ac8b", 0, "changed-in-master.txt" }, GIT_DELTA_UNMODIFIED }, { { 0100644, "11deab00b2d3a6f5a3073988ac050c2d7b6655e2", 0, "changed-in-master.txt" }, GIT_DELTA_MODIFIED }, { { 0100644, "ab6c44a2e84492ad4b41bb6bac87353e9d02ac8b", 0, "changed-in-master.txt" }, GIT_DELTA_UNMODIFIED }, GIT_MERGE_DIFF_NONE }, { { { 0100644, "d427e0b2e138501a3d15cc376077a3631e15bd46", 0, "conflicting.txt" }, GIT_DELTA_UNMODIFIED }, { { 0100644, "4e886e602529caa9ab11d71f86634bd1b6e0de10", 0, "conflicting.txt" }, GIT_DELTA_MODIFIED }, { { 0100644, "2bd0a343aeef7a2cf0d158478966a6e587ff3863", 0, "conflicting.txt" }, GIT_DELTA_MODIFIED }, GIT_MERGE_DIFF_BOTH_MODIFIED }, { { { 0100644, "dfe3f22baa1f6fce5447901c3086bae368de6bdd", 0, "removed-in-branch.txt" }, GIT_DELTA_UNMODIFIED }, { { 0100644, "dfe3f22baa1f6fce5447901c3086bae368de6bdd", 0, "removed-in-branch.txt" }, GIT_DELTA_UNMODIFIED }, { { 0, "", 0, "" }, GIT_DELTA_DELETED }, GIT_MERGE_DIFF_NONE }, { { { 0100644, "5c3b68a71fc4fa5d362fd3875e53137c6a5ab7a5", 0, "removed-in-master.txt" }, GIT_DELTA_UNMODIFIED }, { { 0, "", 0, "" }, GIT_DELTA_DELETED }, { { 0100644, "5c3b68a71fc4fa5d362fd3875e53137c6a5ab7a5", 0, "removed-in-master.txt" }, GIT_DELTA_UNMODIFIED }, GIT_MERGE_DIFF_NONE }, }; test_find_differences(TREE_OID_ANCESTOR, TREE_OID_MASTER, TREE_OID_BRANCH, treediff_conflict_data, 7); } void test_merge_trees_treediff__df_conflicts(void) { struct merge_index_conflict_data treediff_conflict_data[] = { { { { 0, "", 0, "" }, GIT_DELTA_UNMODIFIED }, { { 0100644, "49130a28ef567af9a6a6104c38773fedfa5f9742", 0, "dir-10" }, GIT_DELTA_ADDED }, { { 0100644, "6c06dcd163587c2cc18be44857e0b71116382aeb", 0, "dir-10" }, GIT_DELTA_ADDED }, GIT_MERGE_DIFF_BOTH_ADDED, }, { { { 0100644, "242591eb280ee9eeb2ce63524b9a8b9bc4cb515d", 0, "dir-10/file.txt" }, GIT_DELTA_UNMODIFIED }, { { 0, "", 0, "" }, GIT_DELTA_DELETED }, { { 0, "", 0, "" }, GIT_DELTA_DELETED }, GIT_MERGE_DIFF_BOTH_DELETED, }, { { { 0, "", 0, "" }, GIT_DELTA_UNMODIFIED }, { { 0, "", 0, "" }, GIT_DELTA_UNMODIFIED }, { { 0100644, "43aafd43bea779ec74317dc361f45ae3f532a505", 0, "dir-6" }, GIT_DELTA_ADDED }, GIT_MERGE_DIFF_NONE, }, { { { 0100644, "cf8c5cc8a85a1ff5a4ba51e0bc7cf5665669924d", 0, "dir-6/file.txt" }, GIT_DELTA_UNMODIFIED }, { { 0100644, "cf8c5cc8a85a1ff5a4ba51e0bc7cf5665669924d", 0, "dir-6/file.txt" }, GIT_DELTA_UNMODIFIED }, { { 0, "", 0, "" }, GIT_DELTA_DELETED }, GIT_MERGE_DIFF_NONE, }, { { { 0, "", 0, "" }, GIT_DELTA_UNMODIFIED }, { { 0, "", 0, "" }, GIT_DELTA_UNMODIFIED }, { { 0100644, "a031a28ae70e33a641ce4b8a8f6317f1ab79dee4", 0, "dir-7" }, GIT_DELTA_ADDED }, GIT_MERGE_DIFF_DIRECTORY_FILE, }, { { { 0100644, "5012fd565b1393bdfda1805d4ec38ce6619e1fd1", 0, "dir-7/file.txt" }, GIT_DELTA_UNMODIFIED }, { { 0100644, "a5563304ddf6caba25cb50323a2ea6f7dbfcadca", 0, "dir-7/file.txt" }, GIT_DELTA_MODIFIED }, { { 0, "", 0, "" }, GIT_DELTA_DELETED }, GIT_MERGE_DIFF_DF_CHILD, }, { { { 0, "", 0, "" }, GIT_DELTA_UNMODIFIED }, { { 0100644, "e9ad6ec3e38364a3d07feda7c4197d4d845c53b5", 0, "dir-8" }, GIT_DELTA_ADDED }, { {0, "", 0, "" }, GIT_DELTA_UNMODIFIED }, GIT_MERGE_DIFF_NONE, }, { { { 0100644, "f20c9063fa0bda9a397c96947a7b687305c49753", 0, "dir-8/file.txt" }, GIT_DELTA_UNMODIFIED }, { { 0, "", 0, "" }, GIT_DELTA_DELETED }, { { 0100644, "f20c9063fa0bda9a397c96947a7b687305c49753", 0, "dir-8/file.txt" }, GIT_DELTA_UNMODIFIED }, GIT_MERGE_DIFF_NONE, }, { { { 0, "", 0, "" }, GIT_DELTA_UNMODIFIED }, { { 0100644, "3ef4d30382ca33fdeba9fda895a99e0891ba37aa", 0, "dir-9" }, GIT_DELTA_ADDED }, { { 0, "", 0, "" }, GIT_DELTA_UNMODIFIED }, GIT_MERGE_DIFF_DIRECTORY_FILE, }, { { { 0100644, "fc4c636d6515e9e261f9260dbcf3cc6eca97ea08", 0, "dir-9/file.txt" }, GIT_DELTA_UNMODIFIED }, { { 0, "", 0, "" }, GIT_DELTA_DELETED }, { { 0100644, "76ab0e2868197ec158ddd6c78d8a0d2fd73d38f9", 0, "dir-9/file.txt" }, GIT_DELTA_MODIFIED }, GIT_MERGE_DIFF_DF_CHILD, }, { { { 0100644, "1e4ff029aee68d0d69ef9eb6efa6cbf1ec732f99", 0, "file-1" }, GIT_DELTA_UNMODIFIED }, { { 0100644, "1e4ff029aee68d0d69ef9eb6efa6cbf1ec732f99", 0, "file-1" }, GIT_DELTA_UNMODIFIED }, { { 0, "", 0, "" }, GIT_DELTA_DELETED }, GIT_MERGE_DIFF_NONE, }, { { { 0, "", 0, "" }, GIT_DELTA_UNMODIFIED }, { { 0, "", 0, "" }, GIT_DELTA_UNMODIFIED }, { { 0100644, "5c2411f8075f48a6b2fdb85ebc0d371747c4df15", 0, "file-1/new" }, GIT_DELTA_ADDED }, GIT_MERGE_DIFF_NONE, }, { { { 0100644, "a39a620dae5bc8b4e771cd4d251b7d080401a21e", 0, "file-2" }, GIT_DELTA_UNMODIFIED }, { { 0100644, "d963979c237d08b6ba39062ee7bf64c7d34a27f8", 0, "file-2" }, GIT_DELTA_MODIFIED }, { { 0, "", 0, "" }, GIT_DELTA_DELETED }, GIT_MERGE_DIFF_DIRECTORY_FILE, }, { { { 0, "", 0, "" }, GIT_DELTA_UNMODIFIED }, { { 0, "", 0, "" }, GIT_DELTA_UNMODIFIED }, { { 0100644, "5c341ead2ba6f2af98ce5ec3fe84f6b6d2899c0d", 0, "file-2/new" }, GIT_DELTA_ADDED }, GIT_MERGE_DIFF_DF_CHILD, }, { { { 0100644, "032ebc5ab85d9553bb187d3cd40875ff23a63ed0", 0, "file-3" }, GIT_DELTA_UNMODIFIED }, { { 0, "", 0, "" }, GIT_DELTA_DELETED }, { { 0100644, "032ebc5ab85d9553bb187d3cd40875ff23a63ed0", 0, "file-3" }, GIT_DELTA_UNMODIFIED }, GIT_MERGE_DIFF_NONE, }, { { { 0, "", 0, "" }, GIT_DELTA_UNMODIFIED }, { { 0100644, "9efe7723802d4305142eee177e018fee1572c4f4", 0, "file-3/new" }, GIT_DELTA_ADDED }, { { 0, "", 0, "" }, GIT_DELTA_UNMODIFIED }, GIT_MERGE_DIFF_NONE, }, { { { 0100644, "bacac9b3493509aa15e1730e1545fc0919d1dae0", 0, "file-4" }, GIT_DELTA_UNMODIFIED }, { { 0, "", 0, "" }, GIT_DELTA_DELETED }, { { 0100644, "7663fce0130db092936b137cabd693ec234eb060", 0, "file-4" }, GIT_DELTA_MODIFIED }, GIT_MERGE_DIFF_DIRECTORY_FILE, }, { { { 0, "", 0, "" }, GIT_DELTA_UNMODIFIED }, { { 0100644, "e49f917b448d1340b31d76e54ba388268fd4c922", 0, "file-4/new" }, GIT_DELTA_ADDED }, { { 0, "", 0, "" }, GIT_DELTA_UNMODIFIED }, GIT_MERGE_DIFF_DF_CHILD, }, { { { 0100644, "ac4045f965119e6998f4340ed0f411decfb3ec05", 0, "file-5" }, GIT_DELTA_UNMODIFIED }, { { 0, "", 0, "" }, GIT_DELTA_DELETED }, { { 0, "", 0, "" }, GIT_DELTA_DELETED }, GIT_MERGE_DIFF_BOTH_DELETED, }, { { { 0, "", 0, "" }, GIT_DELTA_UNMODIFIED }, { { 0100644, "cab2cf23998b40f1af2d9d9a756dc9e285a8df4b", 0, "file-5/new" }, GIT_DELTA_ADDED }, { { 0100644, "f5504f36e6f4eb797a56fc5bac6c6c7f32969bf2", 0, "file-5/new" }, GIT_DELTA_ADDED }, GIT_MERGE_DIFF_BOTH_ADDED, }, }; test_find_differences(TREE_OID_DF_ANCESTOR, TREE_OID_DF_SIDE1, TREE_OID_DF_SIDE2, treediff_conflict_data, 20); } void test_merge_trees_treediff__strict_renames(void) { struct merge_index_conflict_data treediff_conflict_data[] = { { { { 0, "", 0, "" }, GIT_DELTA_UNMODIFIED }, { { 0100644, "233c0919c998ed110a4b6ff36f353aec8b713487", 0, "added-in-master.txt" }, GIT_DELTA_ADDED }, { { 0, "", 0, "" }, GIT_DELTA_UNMODIFIED }, GIT_MERGE_DIFF_NONE, }, { { { 0100644, "6212c31dab5e482247d7977e4f0dd3601decf13b", 0, "automergeable.txt" }, GIT_DELTA_UNMODIFIED }, { { 0100644, "ee3fa1b8c00aff7fe02065fdb50864bb0d932ccf", 0, "automergeable.txt" }, GIT_DELTA_MODIFIED }, { { 0100644, "6212c31dab5e482247d7977e4f0dd3601decf13b", 0, "automergeable.txt" }, GIT_DELTA_UNMODIFIED }, GIT_MERGE_DIFF_NONE, }, { { { 0100644, "ab6c44a2e84492ad4b41bb6bac87353e9d02ac8b", 0, "changed-in-master.txt" }, GIT_DELTA_UNMODIFIED }, { { 0100644, "11deab00b2d3a6f5a3073988ac050c2d7b6655e2", 0, "changed-in-master.txt" }, GIT_DELTA_MODIFIED }, { { 0100644, "ab6c44a2e84492ad4b41bb6bac87353e9d02ac8b", 0, "changed-in-master.txt" }, GIT_DELTA_UNMODIFIED }, GIT_MERGE_DIFF_NONE, }, { { { 0100644, "d427e0b2e138501a3d15cc376077a3631e15bd46", 0, "conflicting.txt" }, GIT_DELTA_UNMODIFIED }, { { 0100644, "4e886e602529caa9ab11d71f86634bd1b6e0de10", 0, "conflicting.txt" }, GIT_DELTA_MODIFIED }, { { 0100644, "d427e0b2e138501a3d15cc376077a3631e15bd46", 0, "conflicting.txt" }, GIT_DELTA_UNMODIFIED }, GIT_MERGE_DIFF_NONE, }, { { { 0100644, "dfe3f22baa1f6fce5447901c3086bae368de6bdd", 0, "removed-in-branch.txt" }, GIT_DELTA_UNMODIFIED }, { { 0100644, "dfe3f22baa1f6fce5447901c3086bae368de6bdd", 0, "removed-in-branch.txt" }, GIT_DELTA_UNMODIFIED }, { { 0100644, "dfe3f22baa1f6fce5447901c3086bae368de6bdd", 0, "renamed-in-branch.txt" }, GIT_DELTA_RENAMED }, GIT_MERGE_DIFF_NONE, }, { { { 0100644, "5c3b68a71fc4fa5d362fd3875e53137c6a5ab7a5", 0, "removed-in-master.txt" }, GIT_DELTA_UNMODIFIED }, { { 0, "", 0, "" }, GIT_DELTA_DELETED }, { { 0100644, "5c3b68a71fc4fa5d362fd3875e53137c6a5ab7a5", 0, "removed-in-master.txt" }, GIT_DELTA_UNMODIFIED }, GIT_MERGE_DIFF_NONE, }, { { { 0, "", 0, "" }, GIT_DELTA_UNMODIFIED }, { { 0, "", 0, "" }, GIT_DELTA_UNMODIFIED }, { { 0100644, "c8f06f2e3bb2964174677e91f0abead0e43c9e5d", 0, "renamed.txt" }, GIT_DELTA_ADDED }, GIT_MERGE_DIFF_NONE, }, { { { 0100644, "c8f06f2e3bb2964174677e91f0abead0e43c9e5d", 0, "unchanged.txt" }, GIT_DELTA_UNMODIFIED }, { { 0100644, "c8f06f2e3bb2964174677e91f0abead0e43c9e5d", 0, "unchanged.txt" }, GIT_DELTA_UNMODIFIED }, { { 0100644, "c8f06f2e3bb2964174677e91f0abead0e43c9e5d", 0, "copied.txt" }, GIT_DELTA_RENAMED }, GIT_MERGE_DIFF_NONE, }, }; test_find_differences(TREE_OID_ANCESTOR, TREE_OID_MASTER, TREE_OID_RENAMES1, treediff_conflict_data, 8); } void test_merge_trees_treediff__rename_conflicts(void) { struct merge_index_conflict_data treediff_conflict_data[] = { { { { 0, "", 0, "" }, GIT_DELTA_UNMODIFIED }, { { 0100644, "f0ce2b8e4986084d9b308fb72709e414c23eb5e6", 0, "0b-duplicated-in-ours.txt" }, GIT_DELTA_ADDED }, { { 0, "", 0, "" }, GIT_DELTA_UNMODIFIED }, GIT_MERGE_DIFF_NONE, }, { { { 0100644, "f0ce2b8e4986084d9b308fb72709e414c23eb5e6", 0, "0b-rewritten-in-ours.txt" }, GIT_DELTA_UNMODIFIED }, { { 0100644, "e376fbdd06ebf021c92724da9f26f44212734e3e", 0, "0b-rewritten-in-ours.txt" }, GIT_DELTA_MODIFIED }, { { 0100644, "b2d399ae15224e1d58066e3c8df70ce37de7a656", 0, "0b-rewritten-in-ours.txt" }, GIT_DELTA_MODIFIED }, GIT_MERGE_DIFF_BOTH_MODIFIED, }, { { { 0, "", 0, "" }, GIT_DELTA_UNMODIFIED }, { { 0, "", 0, "" }, GIT_DELTA_UNMODIFIED }, { { 0100644, "2f56120107d680129a5d9791b521cb1e73a2ed31", 0, "0c-duplicated-in-theirs.txt" }, GIT_DELTA_ADDED }, GIT_MERGE_DIFF_NONE, }, { { { 0100644, "2f56120107d680129a5d9791b521cb1e73a2ed31", 0, "0c-rewritten-in-theirs.txt" }, GIT_DELTA_UNMODIFIED }, { { 0100644, "efc9121fdedaf08ba180b53ebfbcf71bd488ed09", 0, "0c-rewritten-in-theirs.txt" }, GIT_DELTA_MODIFIED }, { { 0100644, "712ebba6669ea847d9829e4f1059d6c830c8b531", 0, "0c-rewritten-in-theirs.txt" }, GIT_DELTA_MODIFIED }, GIT_MERGE_DIFF_BOTH_MODIFIED, }, { { { 0100644, "c3d02eeef75183df7584d8d13ac03053910c1301", 0, "1a-renamed-in-ours-edited-in-theirs.txt" }, GIT_DELTA_UNMODIFIED }, { { 0100644, "c3d02eeef75183df7584d8d13ac03053910c1301", 0, "1a-newname-in-ours-edited-in-theirs.txt" }, GIT_DELTA_RENAMED }, { { 0100644, "0d872f8e871a30208305978ecbf9e66d864f1638", 0, "1a-renamed-in-ours-edited-in-theirs.txt" }, GIT_DELTA_MODIFIED }, GIT_MERGE_DIFF_RENAMED_MODIFIED, }, { { { 0100644, "d0d4594e16f2e19107e3fa7ea63e7aaaff305ffb", 0, "1a-renamed-in-ours.txt" }, GIT_DELTA_UNMODIFIED }, { { 0100644, "d0d4594e16f2e19107e3fa7ea63e7aaaff305ffb", 0, "1a-newname-in-ours.txt" }, GIT_DELTA_RENAMED }, { { 0100644, "d0d4594e16f2e19107e3fa7ea63e7aaaff305ffb", 0, "1a-renamed-in-ours.txt" }, GIT_DELTA_UNMODIFIED }, GIT_MERGE_DIFF_NONE, }, { { { 0100644, "241a1005cd9b980732741b74385b891142bcba28", 0, "1b-renamed-in-theirs-edited-in-ours.txt" }, GIT_DELTA_UNMODIFIED }, { { 0100644, "ed9523e62e453e50dd9be1606af19399b96e397a", 0, "1b-renamed-in-theirs-edited-in-ours.txt" }, GIT_DELTA_MODIFIED }, { { 0100644, "241a1005cd9b980732741b74385b891142bcba28", 0, "1b-newname-in-theirs-edited-in-ours.txt" }, GIT_DELTA_RENAMED }, GIT_MERGE_DIFF_RENAMED_MODIFIED, }, { { { 0100644, "2b5f1f181ee3b58ea751f5dd5d8f9b445520a136", 0, "1b-renamed-in-theirs.txt" }, GIT_DELTA_UNMODIFIED }, { { 0100644, "2b5f1f181ee3b58ea751f5dd5d8f9b445520a136", 0, "1b-renamed-in-theirs.txt" }, GIT_DELTA_UNMODIFIED }, { { 0100644, "2b5f1f181ee3b58ea751f5dd5d8f9b445520a136", 0, "1b-newname-in-theirs.txt" }, GIT_DELTA_RENAMED }, GIT_MERGE_DIFF_NONE, }, { { { 0100644, "178940b450f238a56c0d75b7955cb57b38191982", 0, "2-renamed-in-both.txt" }, GIT_DELTA_UNMODIFIED }, { { 0100644, "178940b450f238a56c0d75b7955cb57b38191982", 0, "2-newname-in-both.txt" }, GIT_DELTA_RENAMED }, { { 0100644, "178940b450f238a56c0d75b7955cb57b38191982", 0, "2-newname-in-both.txt" }, GIT_DELTA_RENAMED }, GIT_MERGE_DIFF_BOTH_RENAMED, }, { { { 0100644, "18cb316b1cefa0f8a6946f0e201a8e1a6f845ab9", 0, "3a-renamed-in-ours-deleted-in-theirs.txt" }, GIT_DELTA_UNMODIFIED }, { { 0100644, "18cb316b1cefa0f8a6946f0e201a8e1a6f845ab9", 0, "3a-newname-in-ours-deleted-in-theirs.txt" }, GIT_DELTA_RENAMED }, { { 0, "", 0, "" }, GIT_DELTA_DELETED }, GIT_MERGE_DIFF_RENAMED_DELETED, }, { { { 0100644, "36219b49367146cb2e6a1555b5a9ebd4d0328495", 0, "3b-renamed-in-theirs-deleted-in-ours.txt" }, GIT_DELTA_UNMODIFIED }, { { 0, "", 0, "" }, GIT_DELTA_DELETED }, { { 0100644, "36219b49367146cb2e6a1555b5a9ebd4d0328495", 0, "3b-newname-in-theirs-deleted-in-ours.txt" }, GIT_DELTA_RENAMED }, GIT_MERGE_DIFF_RENAMED_DELETED, }, { { { 0, "", 0, "" }, GIT_DELTA_UNMODIFIED }, { { 0, "", 0, "" }, GIT_DELTA_UNMODIFIED }, { { 0100644, "8b5b53cb2aa9ceb1139f5312fcfa3cc3c5a47c9a", 0, "4a-newname-in-ours-added-in-theirs.txt" }, GIT_DELTA_ADDED }, GIT_MERGE_DIFF_RENAMED_ADDED, }, { { { 0100644, "227792b52aaa0b238bea00ec7e509b02623f168c", 0, "4a-renamed-in-ours-added-in-theirs.txt" }, GIT_DELTA_UNMODIFIED }, { { 0100644, "227792b52aaa0b238bea00ec7e509b02623f168c", 0, "4a-newname-in-ours-added-in-theirs.txt" }, GIT_DELTA_RENAMED }, { { 0, "", 0, "" }, GIT_DELTA_DELETED }, GIT_MERGE_DIFF_RENAMED_ADDED, }, { { { 0, "", 0, "" }, GIT_DELTA_UNMODIFIED }, { { 0100644, "de872ee3618b894992e9d1e18ba2ebe256a112f9", 0, "4b-newname-in-theirs-added-in-ours.txt" }, GIT_DELTA_ADDED }, { { 0, "", 0, "" }, GIT_DELTA_UNMODIFIED }, GIT_MERGE_DIFF_RENAMED_ADDED, }, { { { 0100644, "98d52d07c0b0bbf2b46548f6aa521295c2cb55db", 0, "4b-renamed-in-theirs-added-in-ours.txt" }, GIT_DELTA_UNMODIFIED }, { { 0, "", 0, "" }, GIT_DELTA_DELETED }, { { 0100644, "98d52d07c0b0bbf2b46548f6aa521295c2cb55db", 0, "4b-newname-in-theirs-added-in-ours.txt" }, GIT_DELTA_RENAMED }, GIT_MERGE_DIFF_RENAMED_ADDED, }, { { { 0100644, "d8fa77b6833082c1ea36b7828a582d4c43882450", 0, "5-both-renamed-1-to-2.txt" }, GIT_DELTA_UNMODIFIED }, { { 0100644, "d8fa77b6833082c1ea36b7828a582d4c43882450", 0, "5-both-renamed-1-to-2-ours.txt" }, GIT_DELTA_RENAMED }, { { 0100644, "d8fa77b6833082c1ea36b7828a582d4c43882450", 0, "5-both-renamed-1-to-2-theirs.txt" }, GIT_DELTA_RENAMED }, GIT_MERGE_DIFF_BOTH_RENAMED_1_TO_2, }, { { { 0100644, "b42712cfe99a1a500b2a51fe984e0b8a7702ba11", 0, "6-both-renamed-side-1.txt" }, GIT_DELTA_UNMODIFIED }, { { 0100644, "b42712cfe99a1a500b2a51fe984e0b8a7702ba11", 0, "6-both-renamed.txt" }, GIT_DELTA_RENAMED }, { { 0100644, "b42712cfe99a1a500b2a51fe984e0b8a7702ba11", 0, "6-both-renamed-side-1.txt" }, GIT_DELTA_UNMODIFIED }, GIT_MERGE_DIFF_BOTH_RENAMED_2_TO_1, }, { { { 0100644, "b69fe837e4cecfd4c9a40cdca7c138468687df07", 0, "6-both-renamed-side-2.txt" }, GIT_DELTA_UNMODIFIED }, { { 0100644, "b69fe837e4cecfd4c9a40cdca7c138468687df07", 0, "6-both-renamed-side-2.txt" }, GIT_DELTA_UNMODIFIED }, { { 0100644, "b69fe837e4cecfd4c9a40cdca7c138468687df07", 0, "6-both-renamed.txt" }, GIT_DELTA_RENAMED }, GIT_MERGE_DIFF_BOTH_RENAMED_2_TO_1, }, }; test_find_differences(TREE_OID_RENAME_CONFLICT_ANCESTOR, TREE_OID_RENAME_CONFLICT_OURS, TREE_OID_RENAME_CONFLICT_THEIRS, treediff_conflict_data, 18); } void test_merge_trees_treediff__best_renames(void) { struct merge_index_conflict_data treediff_conflict_data[] = { { { { 0, "", 0, "" }, GIT_DELTA_UNMODIFIED }, { { 0100644, "233c0919c998ed110a4b6ff36f353aec8b713487", 0, "added-in-master.txt" }, GIT_DELTA_ADDED }, { { 0, "", 0, "" }, GIT_DELTA_UNMODIFIED }, GIT_MERGE_DIFF_NONE, }, { { { 0100644, "6212c31dab5e482247d7977e4f0dd3601decf13b", 0, "automergeable.txt" }, GIT_DELTA_UNMODIFIED }, { { 0100644, "ee3fa1b8c00aff7fe02065fdb50864bb0d932ccf", 0, "automergeable.txt" }, GIT_DELTA_MODIFIED }, { { 0100644, "45299c1ca5e07bba1fd90843056fb559f96b1f5a", 0, "renamed-90.txt" }, GIT_DELTA_RENAMED }, GIT_MERGE_DIFF_RENAMED_MODIFIED, }, { { { 0100644, "ab6c44a2e84492ad4b41bb6bac87353e9d02ac8b", 0, "changed-in-master.txt" }, GIT_DELTA_UNMODIFIED }, { { 0100644, "11deab00b2d3a6f5a3073988ac050c2d7b6655e2", 0, "changed-in-master.txt" }, GIT_DELTA_MODIFIED }, { { 0100644, "ab6c44a2e84492ad4b41bb6bac87353e9d02ac8b", 0, "changed-in-master.txt" }, GIT_DELTA_UNMODIFIED }, GIT_MERGE_DIFF_NONE, }, { { { 0100644, "d427e0b2e138501a3d15cc376077a3631e15bd46", 0, "conflicting.txt" }, GIT_DELTA_UNMODIFIED }, { { 0100644, "4e886e602529caa9ab11d71f86634bd1b6e0de10", 0, "conflicting.txt" }, GIT_DELTA_MODIFIED }, { { 0100644, "d427e0b2e138501a3d15cc376077a3631e15bd46", 0, "conflicting.txt" }, GIT_DELTA_UNMODIFIED }, GIT_MERGE_DIFF_NONE, }, { { { 0100644, "5c3b68a71fc4fa5d362fd3875e53137c6a5ab7a5", 0, "removed-in-master.txt" },GIT_DELTA_UNMODIFIED }, { { 0, "", 0, "" }, GIT_DELTA_DELETED }, { { 0100644, "5c3b68a71fc4fa5d362fd3875e53137c6a5ab7a5", 0, "removed-in-master.txt" }, GIT_DELTA_UNMODIFIED }, GIT_MERGE_DIFF_MODIFIED_DELETED, }, { { { 0, "", 0, "" }, GIT_DELTA_UNMODIFIED }, { { 0, "", 0, "" }, GIT_DELTA_UNMODIFIED }, { { 0100644, "5843febcb23480df0b5edb22a21c59c772bb8e29", 0, "renamed-50.txt" }, GIT_DELTA_ADDED }, GIT_MERGE_DIFF_NONE, }, { { { 0, "", 0, "" }, GIT_DELTA_UNMODIFIED }, { { 0, "", 0, "" }, GIT_DELTA_UNMODIFIED }, { { 0100644, "a77a56a49f8f3ae242e02717f18ebbc60c5cc543", 0, "renamed-75.txt" }, GIT_DELTA_ADDED }, GIT_MERGE_DIFF_NONE, }, }; test_find_differences(TREE_OID_ANCESTOR, TREE_OID_MASTER, TREE_OID_RENAMES2, treediff_conflict_data, 7); } libgit2-0.19.0/tests-clar/merge/trees/trivial.c000066400000000000000000000310451216214232500212560ustar00rootroot00000000000000#include "clar_libgit2.h" #include "git2/repository.h" #include "git2/merge.h" #include "merge.h" #include "../merge_helpers.h" #include "refs.h" #include "fileops.h" #include "git2/sys/index.h" static git_repository *repo; #define TEST_REPO_PATH "merge-resolve" #define TEST_INDEX_PATH TEST_REPO_PATH "/.git/index" // Fixture setup and teardown void test_merge_trees_trivial__initialize(void) { repo = cl_git_sandbox_init(TEST_REPO_PATH); } void test_merge_trees_trivial__cleanup(void) { cl_git_sandbox_cleanup(); } static int merge_trivial(git_index **index, const char *ours, const char *theirs, bool automerge) { git_commit *our_commit, *their_commit, *ancestor_commit; git_tree *our_tree, *their_tree, *ancestor_tree; git_oid our_oid, their_oid, ancestor_oid; git_buf branch_buf = GIT_BUF_INIT; git_merge_tree_opts opts = GIT_MERGE_TREE_OPTS_INIT; opts.automerge_flags |= automerge ? 0 : GIT_MERGE_AUTOMERGE_NONE; git_buf_printf(&branch_buf, "%s%s", GIT_REFS_HEADS_DIR, ours); cl_git_pass(git_reference_name_to_id(&our_oid, repo, branch_buf.ptr)); cl_git_pass(git_commit_lookup(&our_commit, repo, &our_oid)); git_buf_clear(&branch_buf); git_buf_printf(&branch_buf, "%s%s", GIT_REFS_HEADS_DIR, theirs); cl_git_pass(git_reference_name_to_id(&their_oid, repo, branch_buf.ptr)); cl_git_pass(git_commit_lookup(&their_commit, repo, &their_oid)); cl_git_pass(git_merge_base(&ancestor_oid, repo, git_commit_id(our_commit), git_commit_id(their_commit))); cl_git_pass(git_commit_lookup(&ancestor_commit, repo, &ancestor_oid)); cl_git_pass(git_commit_tree(&ancestor_tree, ancestor_commit)); cl_git_pass(git_commit_tree(&our_tree, our_commit)); cl_git_pass(git_commit_tree(&their_tree, their_commit)); cl_git_pass(git_merge_trees(index, repo, ancestor_tree, our_tree, their_tree, &opts)); git_buf_free(&branch_buf); git_tree_free(our_tree); git_tree_free(their_tree); git_tree_free(ancestor_tree); git_commit_free(our_commit); git_commit_free(their_commit); git_commit_free(ancestor_commit); return 0; } static int merge_trivial_conflict_entrycount(git_index *index) { const git_index_entry *entry; int count = 0; size_t i; for (i = 0; i < git_index_entrycount(index); i++) { cl_assert(entry = git_index_get_byindex(index, i)); if (git_index_entry_stage(entry) > 0) count++; } return count; } /* 2ALT: ancest:(empty)+, head:*empty*, remote:remote = result:remote */ void test_merge_trees_trivial__2alt(void) { git_index *result; const git_index_entry *entry; cl_git_pass(merge_trivial(&result, "trivial-2alt", "trivial-2alt-branch", 0)); cl_assert(entry = git_index_get_bypath(result, "new-in-branch.txt", 0)); cl_assert(git_index_reuc_entrycount(result) == 0); cl_assert(merge_trivial_conflict_entrycount(result) == 0); git_index_free(result); } /* 3ALT: ancest:(empty)+, head:head, remote:*empty* = result:head */ void test_merge_trees_trivial__3alt(void) { git_index *result; const git_index_entry *entry; cl_git_pass(merge_trivial(&result, "trivial-3alt", "trivial-3alt-branch", 0)); cl_assert(entry = git_index_get_bypath(result, "new-in-3alt.txt", 0)); cl_assert(git_index_reuc_entrycount(result) == 0); cl_assert(merge_trivial_conflict_entrycount(result) == 0); git_index_free(result); } /* 4: ancest:(empty)^, head:head, remote:remote = result:no merge */ void test_merge_trees_trivial__4(void) { git_index *result; const git_index_entry *entry; cl_git_pass(merge_trivial(&result, "trivial-4", "trivial-4-branch", 0)); cl_assert((entry = git_index_get_bypath(result, "new-and-different.txt", 0)) == NULL); cl_assert(git_index_reuc_entrycount(result) == 0); cl_assert(merge_trivial_conflict_entrycount(result) == 2); cl_assert(entry = git_index_get_bypath(result, "new-and-different.txt", 2)); cl_assert(entry = git_index_get_bypath(result, "new-and-different.txt", 3)); git_index_free(result); } /* 5ALT: ancest:*, head:head, remote:head = result:head */ void test_merge_trees_trivial__5alt_1(void) { git_index *result; const git_index_entry *entry; cl_git_pass(merge_trivial(&result, "trivial-5alt-1", "trivial-5alt-1-branch", 0)); cl_assert(entry = git_index_get_bypath(result, "new-and-same.txt", 0)); cl_assert(git_index_reuc_entrycount(result) == 0); cl_assert(merge_trivial_conflict_entrycount(result) == 0); git_index_free(result); } /* 5ALT: ancest:*, head:head, remote:head = result:head */ void test_merge_trees_trivial__5alt_2(void) { git_index *result; const git_index_entry *entry; cl_git_pass(merge_trivial(&result, "trivial-5alt-2", "trivial-5alt-2-branch", 0)); cl_assert(entry = git_index_get_bypath(result, "modified-to-same.txt", 0)); cl_assert(git_index_reuc_entrycount(result) == 0); cl_assert(merge_trivial_conflict_entrycount(result) == 0); git_index_free(result); } /* 6: ancest:ancest+, head:(empty), remote:(empty) = result:no merge */ void test_merge_trees_trivial__6(void) { git_index *result; const git_index_entry *entry; cl_git_pass(merge_trivial(&result, "trivial-6", "trivial-6-branch", 0)); cl_assert((entry = git_index_get_bypath(result, "removed-in-both.txt", 0)) == NULL); cl_assert(git_index_reuc_entrycount(result) == 0); cl_assert(merge_trivial_conflict_entrycount(result) == 1); cl_assert(entry = git_index_get_bypath(result, "removed-in-both.txt", 1)); git_index_free(result); } /* 6: ancest:ancest+, head:(empty), remote:(empty) = result:no merge */ void test_merge_trees_trivial__6_automerge(void) { git_index *result; const git_index_entry *entry; const git_index_reuc_entry *reuc; cl_git_pass(merge_trivial(&result, "trivial-6", "trivial-6-branch", 1)); cl_assert((entry = git_index_get_bypath(result, "removed-in-both.txt", 0)) == NULL); cl_assert(git_index_reuc_entrycount(result) == 1); cl_assert(reuc = git_index_reuc_get_bypath(result, "removed-in-both.txt")); cl_assert(merge_trivial_conflict_entrycount(result) == 0); git_index_free(result); } /* 8: ancest:ancest^, head:(empty), remote:ancest = result:no merge */ void test_merge_trees_trivial__8(void) { git_index *result; const git_index_entry *entry; cl_git_pass(merge_trivial(&result, "trivial-8", "trivial-8-branch", 0)); cl_assert((entry = git_index_get_bypath(result, "removed-in-8.txt", 0)) == NULL); cl_assert(git_index_reuc_entrycount(result) == 0); cl_assert(merge_trivial_conflict_entrycount(result) == 2); cl_assert(entry = git_index_get_bypath(result, "removed-in-8.txt", 1)); cl_assert(entry = git_index_get_bypath(result, "removed-in-8.txt", 3)); git_index_free(result); } /* 8: ancest:ancest^, head:(empty), remote:ancest = result:no merge */ void test_merge_trees_trivial__8_automerge(void) { git_index *result; const git_index_entry *entry; const git_index_reuc_entry *reuc; cl_git_pass(merge_trivial(&result, "trivial-8", "trivial-8-branch", 1)); cl_assert((entry = git_index_get_bypath(result, "removed-in-8.txt", 0)) == NULL); cl_assert(git_index_reuc_entrycount(result) == 1); cl_assert(reuc = git_index_reuc_get_bypath(result, "removed-in-8.txt")); cl_assert(merge_trivial_conflict_entrycount(result) == 0); git_index_free(result); } /* 7: ancest:ancest+, head:(empty), remote:remote = result:no merge */ void test_merge_trees_trivial__7(void) { git_index *result; const git_index_entry *entry; cl_git_pass(merge_trivial(&result, "trivial-7", "trivial-7-branch", 0)); cl_assert((entry = git_index_get_bypath(result, "removed-in-7.txt", 0)) == NULL); cl_assert(git_index_reuc_entrycount(result) == 0); cl_assert(merge_trivial_conflict_entrycount(result) == 2); cl_assert(entry = git_index_get_bypath(result, "removed-in-7.txt", 1)); cl_assert(entry = git_index_get_bypath(result, "removed-in-7.txt", 3)); git_index_free(result); } /* 7: ancest:ancest+, head:(empty), remote:remote = result:no merge */ void test_merge_trees_trivial__7_automerge(void) { git_index *result; const git_index_entry *entry; cl_git_pass(merge_trivial(&result, "trivial-7", "trivial-7-branch", 0)); cl_assert((entry = git_index_get_bypath(result, "removed-in-7.txt", 0)) == NULL); cl_assert(git_index_reuc_entrycount(result) == 0); cl_assert(merge_trivial_conflict_entrycount(result) == 2); cl_assert(entry = git_index_get_bypath(result, "removed-in-7.txt", 1)); cl_assert(entry = git_index_get_bypath(result, "removed-in-7.txt", 3)); git_index_free(result); } /* 10: ancest:ancest^, head:ancest, remote:(empty) = result:no merge */ void test_merge_trees_trivial__10(void) { git_index *result; const git_index_entry *entry; cl_git_pass(merge_trivial(&result, "trivial-10", "trivial-10-branch", 0)); cl_assert((entry = git_index_get_bypath(result, "removed-in-10-branch.txt", 0)) == NULL); cl_assert(git_index_reuc_entrycount(result) == 0); cl_assert(merge_trivial_conflict_entrycount(result) == 2); cl_assert(entry = git_index_get_bypath(result, "removed-in-10-branch.txt", 1)); cl_assert(entry = git_index_get_bypath(result, "removed-in-10-branch.txt", 2)); git_index_free(result); } /* 10: ancest:ancest^, head:ancest, remote:(empty) = result:no merge */ void test_merge_trees_trivial__10_automerge(void) { git_index *result; const git_index_entry *entry; const git_index_reuc_entry *reuc; cl_git_pass(merge_trivial(&result, "trivial-10", "trivial-10-branch", 1)); cl_assert((entry = git_index_get_bypath(result, "removed-in-10-branch.txt", 0)) == NULL); cl_assert(git_index_reuc_entrycount(result) == 1); cl_assert(reuc = git_index_reuc_get_bypath(result, "removed-in-10-branch.txt")); cl_assert(merge_trivial_conflict_entrycount(result) == 0); git_index_free(result); } /* 9: ancest:ancest+, head:head, remote:(empty) = result:no merge */ void test_merge_trees_trivial__9(void) { git_index *result; const git_index_entry *entry; cl_git_pass(merge_trivial(&result, "trivial-9", "trivial-9-branch", 0)); cl_assert((entry = git_index_get_bypath(result, "removed-in-9-branch.txt", 0)) == NULL); cl_assert(git_index_reuc_entrycount(result) == 0); cl_assert(merge_trivial_conflict_entrycount(result) == 2); cl_assert(entry = git_index_get_bypath(result, "removed-in-9-branch.txt", 1)); cl_assert(entry = git_index_get_bypath(result, "removed-in-9-branch.txt", 2)); git_index_free(result); } /* 9: ancest:ancest+, head:head, remote:(empty) = result:no merge */ void test_merge_trees_trivial__9_automerge(void) { git_index *result; const git_index_entry *entry; cl_git_pass(merge_trivial(&result, "trivial-9", "trivial-9-branch", 1)); cl_assert((entry = git_index_get_bypath(result, "removed-in-9-branch.txt", 0)) == NULL); cl_assert(git_index_reuc_entrycount(result) == 0); cl_assert(merge_trivial_conflict_entrycount(result) == 2); cl_assert(entry = git_index_get_bypath(result, "removed-in-9-branch.txt", 1)); cl_assert(entry = git_index_get_bypath(result, "removed-in-9-branch.txt", 2)); git_index_free(result); } /* 13: ancest:ancest+, head:head, remote:ancest = result:head */ void test_merge_trees_trivial__13(void) { git_index *result; const git_index_entry *entry; git_oid expected_oid; cl_git_pass(merge_trivial(&result, "trivial-13", "trivial-13-branch", 0)); cl_assert(entry = git_index_get_bypath(result, "modified-in-13.txt", 0)); cl_git_pass(git_oid_fromstr(&expected_oid, "1cff9ec6a47a537380dedfdd17c9e76d74259a2b")); cl_assert(git_oid_cmp(&entry->oid, &expected_oid) == 0); cl_assert(git_index_reuc_entrycount(result) == 0); cl_assert(merge_trivial_conflict_entrycount(result) == 0); git_index_free(result); } /* 14: ancest:ancest+, head:ancest, remote:remote = result:remote */ void test_merge_trees_trivial__14(void) { git_index *result; const git_index_entry *entry; git_oid expected_oid; cl_git_pass(merge_trivial(&result, "trivial-14", "trivial-14-branch", 0)); cl_assert(entry = git_index_get_bypath(result, "modified-in-14-branch.txt", 0)); cl_git_pass(git_oid_fromstr(&expected_oid, "26153a3ff3649b6c2bb652d3f06878c6e0a172f9")); cl_assert(git_oid_cmp(&entry->oid, &expected_oid) == 0); cl_assert(git_index_reuc_entrycount(result) == 0); cl_assert(merge_trivial_conflict_entrycount(result) == 0); git_index_free(result); } /* 11: ancest:ancest+, head:head, remote:remote = result:no merge */ void test_merge_trees_trivial__11(void) { git_index *result; const git_index_entry *entry; cl_git_pass(merge_trivial(&result, "trivial-11", "trivial-11-branch", 0)); cl_assert((entry = git_index_get_bypath(result, "modified-in-both.txt", 0)) == NULL); cl_assert(git_index_reuc_entrycount(result) == 0); cl_assert(merge_trivial_conflict_entrycount(result) == 3); cl_assert(entry = git_index_get_bypath(result, "modified-in-both.txt", 1)); cl_assert(entry = git_index_get_bypath(result, "modified-in-both.txt", 2)); cl_assert(entry = git_index_get_bypath(result, "modified-in-both.txt", 3)); git_index_free(result); } libgit2-0.19.0/tests-clar/merge/workdir/000077500000000000000000000000001216214232500177745ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/merge/workdir/setup.c000066400000000000000000001115601216214232500213040ustar00rootroot00000000000000#include "clar_libgit2.h" #include "git2/repository.h" #include "git2/merge.h" #include "merge.h" #include "refs.h" #include "fileops.h" static git_repository *repo; static git_index *repo_index; #define TEST_REPO_PATH "merge-resolve" #define TEST_INDEX_PATH TEST_REPO_PATH "/.git/index" #define ORIG_HEAD "bd593285fc7fe4ca18ccdbabf027f5d689101452" #define THEIRS_SIMPLE_BRANCH "branch" #define THEIRS_SIMPLE_OID "7cb63eed597130ba4abb87b3e544b85021905520" #define OCTO1_BRANCH "octo1" #define OCTO1_OID "16f825815cfd20a07a75c71554e82d8eede0b061" #define OCTO2_BRANCH "octo2" #define OCTO2_OID "158dc7bedb202f5b26502bf3574faa7f4238d56c" #define OCTO3_BRANCH "octo3" #define OCTO3_OID "50ce7d7d01217679e26c55939eef119e0c93e272" #define OCTO4_BRANCH "octo4" #define OCTO4_OID "54269b3f6ec3d7d4ede24dd350dd5d605495c3ae" #define OCTO5_BRANCH "octo5" #define OCTO5_OID "e4f618a2c3ed0669308735727df5ebf2447f022f" // Fixture setup and teardown void test_merge_workdir_setup__initialize(void) { repo = cl_git_sandbox_init(TEST_REPO_PATH); git_repository_index(&repo_index, repo); } void test_merge_workdir_setup__cleanup(void) { git_index_free(repo_index); cl_git_sandbox_cleanup(); } static bool test_file_contents(const char *filename, const char *expected) { git_buf file_path_buf = GIT_BUF_INIT, file_buf = GIT_BUF_INIT; bool equals; git_buf_printf(&file_path_buf, "%s/%s", git_repository_path(repo), filename); cl_git_pass(git_futils_readbuffer(&file_buf, file_path_buf.ptr)); equals = (strcmp(file_buf.ptr, expected) == 0); git_buf_free(&file_path_buf); git_buf_free(&file_buf); return equals; } static void write_file_contents(const char *filename, const char *output) { git_buf file_path_buf = GIT_BUF_INIT; git_buf_printf(&file_path_buf, "%s/%s", git_repository_path(repo), filename); cl_git_rewritefile(file_path_buf.ptr, output); git_buf_free(&file_path_buf); } /* git merge --no-ff octo1 */ void test_merge_workdir_setup__one_branch(void) { git_oid our_oid; git_reference *octo1_ref; git_merge_head *our_head, *their_heads[1]; cl_git_pass(git_oid_fromstr(&our_oid, ORIG_HEAD)); cl_git_pass(git_merge_head_from_oid(&our_head, repo, &our_oid)); cl_git_pass(git_reference_lookup(&octo1_ref, repo, GIT_REFS_HEADS_DIR OCTO1_BRANCH)); cl_git_pass(git_merge_head_from_ref(&their_heads[0], repo, octo1_ref)); cl_git_pass(git_merge__setup(repo, our_head, (const git_merge_head **)their_heads, 1, 0)); cl_assert(test_file_contents(GIT_MERGE_HEAD_FILE, OCTO1_OID "\n")); cl_assert(test_file_contents(GIT_ORIG_HEAD_FILE, ORIG_HEAD "\n")); cl_assert(test_file_contents(GIT_MERGE_MODE_FILE, "")); cl_assert(test_file_contents(GIT_MERGE_MSG_FILE, "Merge branch '" OCTO1_BRANCH "'\n")); git_reference_free(octo1_ref); git_merge_head_free(our_head); git_merge_head_free(their_heads[0]); } /* git merge --no-ff 16f825815cfd20a07a75c71554e82d8eede0b061 */ void test_merge_workdir_setup__one_oid(void) { git_oid our_oid; git_oid octo1_oid; git_merge_head *our_head, *their_heads[1]; cl_git_pass(git_oid_fromstr(&our_oid, ORIG_HEAD)); cl_git_pass(git_merge_head_from_oid(&our_head, repo, &our_oid)); cl_git_pass(git_oid_fromstr(&octo1_oid, OCTO1_OID)); cl_git_pass(git_merge_head_from_oid(&their_heads[0], repo, &octo1_oid)); cl_git_pass(git_merge__setup(repo, our_head, (const git_merge_head **)their_heads, 1, 0)); cl_assert(test_file_contents(GIT_MERGE_HEAD_FILE, OCTO1_OID "\n")); cl_assert(test_file_contents(GIT_ORIG_HEAD_FILE, ORIG_HEAD "\n")); cl_assert(test_file_contents(GIT_MERGE_MODE_FILE, "")); cl_assert(test_file_contents(GIT_MERGE_MSG_FILE, "Merge commit '" OCTO1_OID "'\n")); git_merge_head_free(our_head); git_merge_head_free(their_heads[0]); } /* git merge octo1 octo2 */ void test_merge_workdir_setup__two_branches(void) { git_oid our_oid; git_reference *octo1_ref; git_reference *octo2_ref; git_merge_head *our_head, *their_heads[2]; cl_git_pass(git_oid_fromstr(&our_oid, ORIG_HEAD)); cl_git_pass(git_merge_head_from_oid(&our_head, repo, &our_oid)); cl_git_pass(git_reference_lookup(&octo1_ref, repo, GIT_REFS_HEADS_DIR OCTO1_BRANCH)); cl_git_pass(git_merge_head_from_ref(&their_heads[0], repo, octo1_ref)); cl_git_pass(git_reference_lookup(&octo2_ref, repo, GIT_REFS_HEADS_DIR OCTO2_BRANCH)); cl_git_pass(git_merge_head_from_ref(&their_heads[1], repo, octo2_ref)); cl_git_pass(git_merge__setup(repo, our_head, (const git_merge_head **)their_heads, 2, 0)); cl_assert(test_file_contents(GIT_MERGE_HEAD_FILE, OCTO1_OID "\n" OCTO2_OID "\n")); cl_assert(test_file_contents(GIT_ORIG_HEAD_FILE, ORIG_HEAD "\n")); cl_assert(test_file_contents(GIT_MERGE_MODE_FILE, "")); cl_assert(test_file_contents(GIT_MERGE_MSG_FILE, "Merge branches '" OCTO1_BRANCH "' and '" OCTO2_BRANCH "'\n")); git_reference_free(octo1_ref); git_reference_free(octo2_ref); git_merge_head_free(our_head); git_merge_head_free(their_heads[0]); git_merge_head_free(their_heads[1]); } /* git merge octo1 octo2 octo3 */ void test_merge_workdir_setup__three_branches(void) { git_oid our_oid; git_reference *octo1_ref; git_reference *octo2_ref; git_reference *octo3_ref; git_merge_head *our_head, *their_heads[3]; cl_git_pass(git_oid_fromstr(&our_oid, ORIG_HEAD)); cl_git_pass(git_merge_head_from_oid(&our_head, repo, &our_oid)); cl_git_pass(git_reference_lookup(&octo1_ref, repo, GIT_REFS_HEADS_DIR OCTO1_BRANCH)); cl_git_pass(git_merge_head_from_ref(&their_heads[0], repo, octo1_ref)); cl_git_pass(git_reference_lookup(&octo2_ref, repo, GIT_REFS_HEADS_DIR OCTO2_BRANCH)); cl_git_pass(git_merge_head_from_ref(&their_heads[1], repo, octo2_ref)); cl_git_pass(git_reference_lookup(&octo3_ref, repo, GIT_REFS_HEADS_DIR OCTO3_BRANCH)); cl_git_pass(git_merge_head_from_ref(&their_heads[2], repo, octo3_ref)); cl_git_pass(git_merge__setup(repo, our_head, (const git_merge_head **)their_heads, 3, 0)); cl_assert(test_file_contents(GIT_MERGE_HEAD_FILE, OCTO1_OID "\n" OCTO2_OID "\n" OCTO3_OID "\n")); cl_assert(test_file_contents(GIT_ORIG_HEAD_FILE, ORIG_HEAD "\n")); cl_assert(test_file_contents(GIT_MERGE_MODE_FILE, "")); cl_assert(test_file_contents(GIT_MERGE_MSG_FILE, "Merge branches '" OCTO1_BRANCH "', '" OCTO2_BRANCH "' and '" OCTO3_BRANCH "'\n")); git_reference_free(octo1_ref); git_reference_free(octo2_ref); git_reference_free(octo3_ref); git_merge_head_free(our_head); git_merge_head_free(their_heads[0]); git_merge_head_free(their_heads[1]); git_merge_head_free(their_heads[2]); } /* git merge 16f825815cfd20a07a75c71554e82d8eede0b061 158dc7bedb202f5b26502bf3574faa7f4238d56c 50ce7d7d01217679e26c55939eef119e0c93e272 */ void test_merge_workdir_setup__three_oids(void) { git_oid our_oid; git_oid octo1_oid; git_oid octo2_oid; git_oid octo3_oid; git_merge_head *our_head, *their_heads[3]; cl_git_pass(git_oid_fromstr(&our_oid, ORIG_HEAD)); cl_git_pass(git_merge_head_from_oid(&our_head, repo, &our_oid)); cl_git_pass(git_oid_fromstr(&octo1_oid, OCTO1_OID)); cl_git_pass(git_merge_head_from_oid(&their_heads[0], repo, &octo1_oid)); cl_git_pass(git_oid_fromstr(&octo2_oid, OCTO2_OID)); cl_git_pass(git_merge_head_from_oid(&their_heads[1], repo, &octo2_oid)); cl_git_pass(git_oid_fromstr(&octo3_oid, OCTO3_OID)); cl_git_pass(git_merge_head_from_oid(&their_heads[2], repo, &octo3_oid)); cl_git_pass(git_merge__setup(repo, our_head, (const git_merge_head **)their_heads, 3, 0)); cl_assert(test_file_contents(GIT_MERGE_HEAD_FILE, OCTO1_OID "\n" OCTO2_OID "\n" OCTO3_OID "\n")); cl_assert(test_file_contents(GIT_ORIG_HEAD_FILE, ORIG_HEAD "\n")); cl_assert(test_file_contents(GIT_MERGE_MODE_FILE, "")); cl_assert(test_file_contents(GIT_MERGE_MSG_FILE, "Merge commit '" OCTO1_OID "'; commit '" OCTO2_OID "'; commit '" OCTO3_OID "'\n")); git_merge_head_free(our_head); git_merge_head_free(their_heads[0]); git_merge_head_free(their_heads[1]); git_merge_head_free(their_heads[2]); } /* git merge octo1 158dc7bedb202f5b26502bf3574faa7f4238d56c */ void test_merge_workdir_setup__branches_and_oids_1(void) { git_oid our_oid; git_reference *octo1_ref; git_oid octo2_oid; git_merge_head *our_head, *their_heads[2]; cl_git_pass(git_oid_fromstr(&our_oid, ORIG_HEAD)); cl_git_pass(git_merge_head_from_oid(&our_head, repo, &our_oid)); cl_git_pass(git_reference_lookup(&octo1_ref, repo, GIT_REFS_HEADS_DIR OCTO1_BRANCH)); cl_git_pass(git_merge_head_from_ref(&their_heads[0], repo, octo1_ref)); cl_git_pass(git_oid_fromstr(&octo2_oid, OCTO2_OID)); cl_git_pass(git_merge_head_from_oid(&their_heads[1], repo, &octo2_oid)); cl_git_pass(git_merge__setup(repo, our_head, (const git_merge_head **)their_heads, 2, 0)); cl_assert(test_file_contents(GIT_MERGE_HEAD_FILE, OCTO1_OID "\n" OCTO2_OID "\n")); cl_assert(test_file_contents(GIT_ORIG_HEAD_FILE, ORIG_HEAD "\n")); cl_assert(test_file_contents(GIT_MERGE_MODE_FILE, "")); cl_assert(test_file_contents(GIT_MERGE_MSG_FILE, "Merge branch '" OCTO1_BRANCH "'; commit '" OCTO2_OID "'\n")); git_reference_free(octo1_ref); git_merge_head_free(our_head); git_merge_head_free(their_heads[0]); git_merge_head_free(their_heads[1]); } /* git merge octo1 158dc7bedb202f5b26502bf3574faa7f4238d56c octo3 54269b3f6ec3d7d4ede24dd350dd5d605495c3ae */ void test_merge_workdir_setup__branches_and_oids_2(void) { git_oid our_oid; git_reference *octo1_ref; git_oid octo2_oid; git_reference *octo3_ref; git_oid octo4_oid; git_merge_head *our_head, *their_heads[4]; cl_git_pass(git_oid_fromstr(&our_oid, ORIG_HEAD)); cl_git_pass(git_merge_head_from_oid(&our_head, repo, &our_oid)); cl_git_pass(git_reference_lookup(&octo1_ref, repo, GIT_REFS_HEADS_DIR OCTO1_BRANCH)); cl_git_pass(git_merge_head_from_ref(&their_heads[0], repo, octo1_ref)); cl_git_pass(git_oid_fromstr(&octo2_oid, OCTO2_OID)); cl_git_pass(git_merge_head_from_oid(&their_heads[1], repo, &octo2_oid)); cl_git_pass(git_reference_lookup(&octo3_ref, repo, GIT_REFS_HEADS_DIR OCTO3_BRANCH)); cl_git_pass(git_merge_head_from_ref(&their_heads[2], repo, octo3_ref)); cl_git_pass(git_oid_fromstr(&octo4_oid, OCTO4_OID)); cl_git_pass(git_merge_head_from_oid(&their_heads[3], repo, &octo4_oid)); cl_git_pass(git_merge__setup(repo, our_head, (const git_merge_head **)their_heads, 4, 0)); cl_assert(test_file_contents(GIT_MERGE_HEAD_FILE, OCTO1_OID "\n" OCTO2_OID "\n" OCTO3_OID "\n" OCTO4_OID "\n")); cl_assert(test_file_contents(GIT_ORIG_HEAD_FILE, ORIG_HEAD "\n")); cl_assert(test_file_contents(GIT_MERGE_MODE_FILE, "")); cl_assert(test_file_contents(GIT_MERGE_MSG_FILE, "Merge branches '" OCTO1_BRANCH "' and '" OCTO3_BRANCH "'; commit '" OCTO2_OID "'; commit '" OCTO4_OID "'\n")); git_reference_free(octo1_ref); git_reference_free(octo3_ref); git_merge_head_free(our_head); git_merge_head_free(their_heads[0]); git_merge_head_free(their_heads[1]); git_merge_head_free(their_heads[2]); git_merge_head_free(their_heads[3]); } /* git merge 16f825815cfd20a07a75c71554e82d8eede0b061 octo2 50ce7d7d01217679e26c55939eef119e0c93e272 octo4 */ void test_merge_workdir_setup__branches_and_oids_3(void) { git_oid our_oid; git_oid octo1_oid; git_reference *octo2_ref; git_oid octo3_oid; git_reference *octo4_ref; git_merge_head *our_head, *their_heads[4]; cl_git_pass(git_oid_fromstr(&our_oid, ORIG_HEAD)); cl_git_pass(git_merge_head_from_oid(&our_head, repo, &our_oid)); cl_git_pass(git_oid_fromstr(&octo1_oid, OCTO1_OID)); cl_git_pass(git_merge_head_from_oid(&their_heads[0], repo, &octo1_oid)); cl_git_pass(git_reference_lookup(&octo2_ref, repo, GIT_REFS_HEADS_DIR OCTO2_BRANCH)); cl_git_pass(git_merge_head_from_ref(&their_heads[1], repo, octo2_ref)); cl_git_pass(git_oid_fromstr(&octo3_oid, OCTO3_OID)); cl_git_pass(git_merge_head_from_oid(&their_heads[2], repo, &octo3_oid)); cl_git_pass(git_reference_lookup(&octo4_ref, repo, GIT_REFS_HEADS_DIR OCTO4_BRANCH)); cl_git_pass(git_merge_head_from_ref(&their_heads[3], repo, octo4_ref)); cl_git_pass(git_merge__setup(repo, our_head, (const git_merge_head **)their_heads, 4, 0)); cl_assert(test_file_contents(GIT_MERGE_HEAD_FILE, OCTO1_OID "\n" OCTO2_OID "\n" OCTO3_OID "\n" OCTO4_OID "\n")); cl_assert(test_file_contents(GIT_ORIG_HEAD_FILE, ORIG_HEAD "\n")); cl_assert(test_file_contents(GIT_MERGE_MODE_FILE, "")); cl_assert(test_file_contents(GIT_MERGE_MSG_FILE, "Merge commit '" OCTO1_OID "'; branches '" OCTO2_BRANCH "' and '" OCTO4_BRANCH "'; commit '" OCTO3_OID "'\n")); git_reference_free(octo2_ref); git_reference_free(octo4_ref); git_merge_head_free(our_head); git_merge_head_free(their_heads[0]); git_merge_head_free(their_heads[1]); git_merge_head_free(their_heads[2]); git_merge_head_free(their_heads[3]); } /* git merge 16f825815cfd20a07a75c71554e82d8eede0b061 octo2 50ce7d7d01217679e26c55939eef119e0c93e272 octo4 octo5 */ void test_merge_workdir_setup__branches_and_oids_4(void) { git_oid our_oid; git_oid octo1_oid; git_reference *octo2_ref; git_oid octo3_oid; git_reference *octo4_ref; git_reference *octo5_ref; git_merge_head *our_head, *their_heads[5]; cl_git_pass(git_oid_fromstr(&our_oid, ORIG_HEAD)); cl_git_pass(git_merge_head_from_oid(&our_head, repo, &our_oid)); cl_git_pass(git_oid_fromstr(&octo1_oid, OCTO1_OID)); cl_git_pass(git_merge_head_from_oid(&their_heads[0], repo, &octo1_oid)); cl_git_pass(git_reference_lookup(&octo2_ref, repo, GIT_REFS_HEADS_DIR OCTO2_BRANCH)); cl_git_pass(git_merge_head_from_ref(&their_heads[1], repo, octo2_ref)); cl_git_pass(git_oid_fromstr(&octo3_oid, OCTO3_OID)); cl_git_pass(git_merge_head_from_oid(&their_heads[2], repo, &octo3_oid)); cl_git_pass(git_reference_lookup(&octo4_ref, repo, GIT_REFS_HEADS_DIR OCTO4_BRANCH)); cl_git_pass(git_merge_head_from_ref(&their_heads[3], repo, octo4_ref)); cl_git_pass(git_reference_lookup(&octo5_ref, repo, GIT_REFS_HEADS_DIR OCTO5_BRANCH)); cl_git_pass(git_merge_head_from_ref(&their_heads[4], repo, octo5_ref)); cl_git_pass(git_merge__setup(repo, our_head, (const git_merge_head **)their_heads, 5, 0)); cl_assert(test_file_contents(GIT_MERGE_HEAD_FILE, OCTO1_OID "\n" OCTO2_OID "\n" OCTO3_OID "\n" OCTO4_OID "\n" OCTO5_OID "\n")); cl_assert(test_file_contents(GIT_ORIG_HEAD_FILE, ORIG_HEAD "\n")); cl_assert(test_file_contents(GIT_MERGE_MODE_FILE, "")); cl_assert(test_file_contents(GIT_MERGE_MSG_FILE, "Merge commit '" OCTO1_OID "'; branches '" OCTO2_BRANCH "', '" OCTO4_BRANCH "' and '" OCTO5_BRANCH "'; commit '" OCTO3_OID "'\n")); git_reference_free(octo2_ref); git_reference_free(octo4_ref); git_reference_free(octo5_ref); git_merge_head_free(our_head); git_merge_head_free(their_heads[0]); git_merge_head_free(their_heads[1]); git_merge_head_free(their_heads[2]); git_merge_head_free(their_heads[3]); git_merge_head_free(their_heads[4]); } /* git merge octo1 octo1 octo1 */ void test_merge_workdir_setup__three_same_branches(void) { git_oid our_oid; git_reference *octo1_1_ref; git_reference *octo1_2_ref; git_reference *octo1_3_ref; git_merge_head *our_head, *their_heads[3]; cl_git_pass(git_oid_fromstr(&our_oid, ORIG_HEAD)); cl_git_pass(git_merge_head_from_oid(&our_head, repo, &our_oid)); cl_git_pass(git_reference_lookup(&octo1_1_ref, repo, GIT_REFS_HEADS_DIR OCTO1_BRANCH)); cl_git_pass(git_merge_head_from_ref(&their_heads[0], repo, octo1_1_ref)); cl_git_pass(git_reference_lookup(&octo1_2_ref, repo, GIT_REFS_HEADS_DIR OCTO1_BRANCH)); cl_git_pass(git_merge_head_from_ref(&their_heads[1], repo, octo1_2_ref)); cl_git_pass(git_reference_lookup(&octo1_3_ref, repo, GIT_REFS_HEADS_DIR OCTO1_BRANCH)); cl_git_pass(git_merge_head_from_ref(&their_heads[2], repo, octo1_3_ref)); cl_git_pass(git_merge__setup(repo, our_head, (const git_merge_head **)their_heads, 3, 0)); cl_assert(test_file_contents(GIT_MERGE_HEAD_FILE, OCTO1_OID "\n" OCTO1_OID "\n" OCTO1_OID "\n")); cl_assert(test_file_contents(GIT_ORIG_HEAD_FILE, ORIG_HEAD "\n")); cl_assert(test_file_contents(GIT_MERGE_MODE_FILE, "")); cl_assert(test_file_contents(GIT_MERGE_MSG_FILE, "Merge branches '" OCTO1_BRANCH "', '" OCTO1_BRANCH "' and '" OCTO1_BRANCH "'\n")); git_reference_free(octo1_1_ref); git_reference_free(octo1_2_ref); git_reference_free(octo1_3_ref); git_merge_head_free(our_head); git_merge_head_free(their_heads[0]); git_merge_head_free(their_heads[1]); git_merge_head_free(their_heads[2]); } /* git merge 16f825815cfd20a07a75c71554e82d8eede0b061 16f825815cfd20a07a75c71554e82d8eede0b061 16f825815cfd20a07a75c71554e82d8eede0b061 */ void test_merge_workdir_setup__three_same_oids(void) { git_oid our_oid; git_oid octo1_1_oid; git_oid octo1_2_oid; git_oid octo1_3_oid; git_merge_head *our_head, *their_heads[3]; cl_git_pass(git_oid_fromstr(&our_oid, ORIG_HEAD)); cl_git_pass(git_merge_head_from_oid(&our_head, repo, &our_oid)); cl_git_pass(git_oid_fromstr(&octo1_1_oid, OCTO1_OID)); cl_git_pass(git_merge_head_from_oid(&their_heads[0], repo, &octo1_1_oid)); cl_git_pass(git_oid_fromstr(&octo1_2_oid, OCTO1_OID)); cl_git_pass(git_merge_head_from_oid(&their_heads[1], repo, &octo1_2_oid)); cl_git_pass(git_oid_fromstr(&octo1_3_oid, OCTO1_OID)); cl_git_pass(git_merge_head_from_oid(&their_heads[2], repo, &octo1_3_oid)); cl_git_pass(git_merge__setup(repo, our_head, (const git_merge_head **)their_heads, 3, 0)); cl_assert(test_file_contents(GIT_MERGE_HEAD_FILE, OCTO1_OID "\n" OCTO1_OID "\n" OCTO1_OID "\n")); cl_assert(test_file_contents(GIT_ORIG_HEAD_FILE, ORIG_HEAD "\n")); cl_assert(test_file_contents(GIT_MERGE_MODE_FILE, "")); cl_assert(test_file_contents(GIT_MERGE_MSG_FILE, "Merge commit '" OCTO1_OID "'; commit '" OCTO1_OID "'; commit '" OCTO1_OID "'\n")); git_merge_head_free(our_head); git_merge_head_free(their_heads[0]); git_merge_head_free(their_heads[1]); git_merge_head_free(their_heads[2]); } static int create_remote_tracking_branch(const char *branch_name, const char *oid_str) { int error = 0; git_buf remotes_path = GIT_BUF_INIT, origin_path = GIT_BUF_INIT, filename = GIT_BUF_INIT, data = GIT_BUF_INIT; if ((error = git_buf_puts(&remotes_path, git_repository_path(repo))) < 0 || (error = git_buf_puts(&remotes_path, GIT_REFS_REMOTES_DIR)) < 0) goto done; if (!git_path_exists(git_buf_cstr(&remotes_path)) && (error = p_mkdir(git_buf_cstr(&remotes_path), 0777)) < 0) goto done; if ((error = git_buf_puts(&origin_path, git_buf_cstr(&remotes_path))) < 0 || (error = git_buf_puts(&origin_path, "origin")) < 0) goto done; if (!git_path_exists(git_buf_cstr(&origin_path)) && (error = p_mkdir(git_buf_cstr(&origin_path), 0777)) < 0) goto done; if ((error = git_buf_puts(&filename, git_buf_cstr(&origin_path))) < 0 || (error = git_buf_puts(&filename, "/")) < 0 || (error = git_buf_puts(&filename, branch_name)) < 0 || (error = git_buf_puts(&data, oid_str)) < 0 || (error = git_buf_puts(&data, "\n")) < 0) goto done; cl_git_rewritefile(git_buf_cstr(&filename), git_buf_cstr(&data)); done: git_buf_free(&remotes_path); git_buf_free(&origin_path); git_buf_free(&filename); git_buf_free(&data); return error; } /* git merge refs/remotes/origin/octo1 */ void test_merge_workdir_setup__remote_tracking_one_branch(void) { git_oid our_oid; git_reference *octo1_ref; git_merge_head *our_head, *their_heads[1]; cl_git_pass(create_remote_tracking_branch(OCTO1_BRANCH, OCTO1_OID)); cl_git_pass(git_oid_fromstr(&our_oid, ORIG_HEAD)); cl_git_pass(git_merge_head_from_oid(&our_head, repo, &our_oid)); cl_git_pass(git_reference_lookup(&octo1_ref, repo, GIT_REFS_REMOTES_DIR "origin/" OCTO1_BRANCH)); cl_git_pass(git_merge_head_from_ref(&their_heads[0], repo, octo1_ref)); cl_git_pass(git_merge__setup(repo, our_head, (const git_merge_head **)their_heads, 1, 0)); cl_assert(test_file_contents(GIT_MERGE_HEAD_FILE, OCTO1_OID "\n")); cl_assert(test_file_contents(GIT_ORIG_HEAD_FILE, ORIG_HEAD "\n")); cl_assert(test_file_contents(GIT_MERGE_MODE_FILE, "")); cl_assert(test_file_contents(GIT_MERGE_MSG_FILE, "Merge remote-tracking branch 'refs/remotes/origin/" OCTO1_BRANCH "'\n")); git_reference_free(octo1_ref); git_merge_head_free(our_head); git_merge_head_free(their_heads[0]); } /* git merge refs/remotes/origin/octo1 refs/remotes/origin/octo2 */ void test_merge_workdir_setup__remote_tracking_two_branches(void) { git_oid our_oid; git_reference *octo1_ref; git_reference *octo2_ref; git_merge_head *our_head, *their_heads[2]; cl_git_pass(create_remote_tracking_branch(OCTO1_BRANCH, OCTO1_OID)); cl_git_pass(create_remote_tracking_branch(OCTO2_BRANCH, OCTO2_OID)); cl_git_pass(git_oid_fromstr(&our_oid, ORIG_HEAD)); cl_git_pass(git_merge_head_from_oid(&our_head, repo, &our_oid)); cl_git_pass(git_reference_lookup(&octo1_ref, repo, GIT_REFS_REMOTES_DIR "origin/" OCTO1_BRANCH)); cl_git_pass(git_merge_head_from_ref(&their_heads[0], repo, octo1_ref)); cl_git_pass(git_reference_lookup(&octo2_ref, repo, GIT_REFS_REMOTES_DIR "origin/" OCTO2_BRANCH)); cl_git_pass(git_merge_head_from_ref(&their_heads[1], repo, octo2_ref)); cl_git_pass(git_merge__setup(repo, our_head, (const git_merge_head **)their_heads, 2, 0)); cl_assert(test_file_contents(GIT_MERGE_HEAD_FILE, OCTO1_OID "\n" OCTO2_OID "\n")); cl_assert(test_file_contents(GIT_ORIG_HEAD_FILE, ORIG_HEAD "\n")); cl_assert(test_file_contents(GIT_MERGE_MODE_FILE, "")); cl_assert(test_file_contents(GIT_MERGE_MSG_FILE, "Merge remote-tracking branches 'refs/remotes/origin/" OCTO1_BRANCH "' and 'refs/remotes/origin/" OCTO2_BRANCH "'\n")); git_reference_free(octo1_ref); git_reference_free(octo2_ref); git_merge_head_free(our_head); git_merge_head_free(their_heads[0]); git_merge_head_free(their_heads[1]); } /* git merge refs/remotes/origin/octo1 refs/remotes/origin/octo2 refs/remotes/origin/octo3 */ void test_merge_workdir_setup__remote_tracking_three_branches(void) { git_oid our_oid; git_reference *octo1_ref; git_reference *octo2_ref; git_reference *octo3_ref; git_merge_head *our_head, *their_heads[3]; cl_git_pass(create_remote_tracking_branch(OCTO1_BRANCH, OCTO1_OID)); cl_git_pass(create_remote_tracking_branch(OCTO2_BRANCH, OCTO2_OID)); cl_git_pass(create_remote_tracking_branch(OCTO3_BRANCH, OCTO3_OID)); cl_git_pass(git_oid_fromstr(&our_oid, ORIG_HEAD)); cl_git_pass(git_merge_head_from_oid(&our_head, repo, &our_oid)); cl_git_pass(git_reference_lookup(&octo1_ref, repo, GIT_REFS_REMOTES_DIR "origin/" OCTO1_BRANCH)); cl_git_pass(git_merge_head_from_ref(&their_heads[0], repo, octo1_ref)); cl_git_pass(git_reference_lookup(&octo2_ref, repo, GIT_REFS_REMOTES_DIR "origin/" OCTO2_BRANCH)); cl_git_pass(git_merge_head_from_ref(&their_heads[1], repo, octo2_ref)); cl_git_pass(git_reference_lookup(&octo3_ref, repo, GIT_REFS_REMOTES_DIR "origin/" OCTO3_BRANCH)); cl_git_pass(git_merge_head_from_ref(&their_heads[2], repo, octo3_ref)); cl_git_pass(git_merge__setup(repo, our_head, (const git_merge_head **)their_heads, 3, 0)); cl_assert(test_file_contents(GIT_MERGE_HEAD_FILE, OCTO1_OID "\n" OCTO2_OID "\n" OCTO3_OID "\n")); cl_assert(test_file_contents(GIT_ORIG_HEAD_FILE, ORIG_HEAD "\n")); cl_assert(test_file_contents(GIT_MERGE_MODE_FILE, "")); cl_assert(test_file_contents(GIT_MERGE_MSG_FILE, "Merge remote-tracking branches 'refs/remotes/origin/" OCTO1_BRANCH "', 'refs/remotes/origin/" OCTO2_BRANCH "' and 'refs/remotes/origin/" OCTO3_BRANCH "'\n")); git_reference_free(octo1_ref); git_reference_free(octo2_ref); git_reference_free(octo3_ref); git_merge_head_free(our_head); git_merge_head_free(their_heads[0]); git_merge_head_free(their_heads[1]); git_merge_head_free(their_heads[2]); } /* git merge octo1 refs/remotes/origin/octo2 */ void test_merge_workdir_setup__normal_branch_and_remote_tracking_branch(void) { git_oid our_oid; git_reference *octo1_ref; git_reference *octo2_ref; git_merge_head *our_head, *their_heads[2]; cl_git_pass(create_remote_tracking_branch(OCTO2_BRANCH, OCTO2_OID)); cl_git_pass(git_oid_fromstr(&our_oid, ORIG_HEAD)); cl_git_pass(git_merge_head_from_oid(&our_head, repo, &our_oid)); cl_git_pass(git_reference_lookup(&octo1_ref, repo, GIT_REFS_HEADS_DIR OCTO1_BRANCH)); cl_git_pass(git_merge_head_from_ref(&their_heads[0], repo, octo1_ref)); cl_git_pass(git_reference_lookup(&octo2_ref, repo, GIT_REFS_REMOTES_DIR "origin/" OCTO2_BRANCH)); cl_git_pass(git_merge_head_from_ref(&their_heads[1], repo, octo2_ref)); cl_git_pass(git_merge__setup(repo, our_head, (const git_merge_head **)their_heads, 2, 0)); cl_assert(test_file_contents(GIT_MERGE_HEAD_FILE, OCTO1_OID "\n" OCTO2_OID "\n")); cl_assert(test_file_contents(GIT_ORIG_HEAD_FILE, ORIG_HEAD "\n")); cl_assert(test_file_contents(GIT_MERGE_MODE_FILE, "")); cl_assert(test_file_contents(GIT_MERGE_MSG_FILE, "Merge branch '" OCTO1_BRANCH "', remote-tracking branch 'refs/remotes/origin/" OCTO2_BRANCH "'\n")); git_reference_free(octo1_ref); git_reference_free(octo2_ref); git_merge_head_free(our_head); git_merge_head_free(their_heads[0]); git_merge_head_free(their_heads[1]); } /* git merge refs/remotes/origin/octo1 octo2 */ void test_merge_workdir_setup__remote_tracking_branch_and_normal_branch(void) { git_oid our_oid; git_reference *octo1_ref; git_reference *octo2_ref; git_merge_head *our_head, *their_heads[2]; cl_git_pass(create_remote_tracking_branch(OCTO1_BRANCH, OCTO1_OID)); cl_git_pass(git_oid_fromstr(&our_oid, ORIG_HEAD)); cl_git_pass(git_merge_head_from_oid(&our_head, repo, &our_oid)); cl_git_pass(git_reference_lookup(&octo1_ref, repo, GIT_REFS_REMOTES_DIR "origin/" OCTO1_BRANCH)); cl_git_pass(git_merge_head_from_ref(&their_heads[0], repo, octo1_ref)); cl_git_pass(git_reference_lookup(&octo2_ref, repo, GIT_REFS_HEADS_DIR OCTO2_BRANCH)); cl_git_pass(git_merge_head_from_ref(&their_heads[1], repo, octo2_ref)); cl_git_pass(git_merge__setup(repo, our_head, (const git_merge_head **)their_heads, 2, 0)); cl_assert(test_file_contents(GIT_MERGE_HEAD_FILE, OCTO1_OID "\n" OCTO2_OID "\n")); cl_assert(test_file_contents(GIT_ORIG_HEAD_FILE, ORIG_HEAD "\n")); cl_assert(test_file_contents(GIT_MERGE_MODE_FILE, "")); cl_assert(test_file_contents(GIT_MERGE_MSG_FILE, "Merge branch '" OCTO2_BRANCH "', remote-tracking branch 'refs/remotes/origin/" OCTO1_BRANCH "'\n")); git_reference_free(octo1_ref); git_reference_free(octo2_ref); git_merge_head_free(our_head); git_merge_head_free(their_heads[0]); git_merge_head_free(their_heads[1]); } /* git merge octo1 refs/remotes/origin/octo2 octo3 refs/remotes/origin/octo4 */ void test_merge_workdir_setup__two_remote_tracking_branch_and_two_normal_branches(void) { git_oid our_oid; git_reference *octo1_ref; git_reference *octo2_ref; git_reference *octo3_ref; git_reference *octo4_ref; git_merge_head *our_head, *their_heads[4]; cl_git_pass(create_remote_tracking_branch(OCTO2_BRANCH, OCTO2_OID)); cl_git_pass(create_remote_tracking_branch(OCTO4_BRANCH, OCTO4_OID)); cl_git_pass(git_oid_fromstr(&our_oid, ORIG_HEAD)); cl_git_pass(git_merge_head_from_oid(&our_head, repo, &our_oid)); cl_git_pass(git_reference_lookup(&octo1_ref, repo, GIT_REFS_HEADS_DIR OCTO1_BRANCH)); cl_git_pass(git_merge_head_from_ref(&their_heads[0], repo, octo1_ref)); cl_git_pass(git_reference_lookup(&octo2_ref, repo, GIT_REFS_REMOTES_DIR "origin/" OCTO2_BRANCH)); cl_git_pass(git_merge_head_from_ref(&their_heads[1], repo, octo2_ref)); cl_git_pass(git_reference_lookup(&octo3_ref, repo, GIT_REFS_HEADS_DIR OCTO3_BRANCH)); cl_git_pass(git_merge_head_from_ref(&their_heads[2], repo, octo3_ref)); cl_git_pass(git_reference_lookup(&octo4_ref, repo, GIT_REFS_REMOTES_DIR "origin/" OCTO4_BRANCH)); cl_git_pass(git_merge_head_from_ref(&their_heads[3], repo, octo4_ref)); cl_git_pass(git_merge__setup(repo, our_head, (const git_merge_head **)their_heads, 4, 0)); cl_assert(test_file_contents(GIT_MERGE_HEAD_FILE, OCTO1_OID "\n" OCTO2_OID "\n" OCTO3_OID "\n" OCTO4_OID "\n")); cl_assert(test_file_contents(GIT_ORIG_HEAD_FILE, ORIG_HEAD "\n")); cl_assert(test_file_contents(GIT_MERGE_MODE_FILE, "")); cl_assert(test_file_contents(GIT_MERGE_MSG_FILE, "Merge branches '" OCTO1_BRANCH "' and '" OCTO3_BRANCH "', remote-tracking branches 'refs/remotes/origin/" OCTO2_BRANCH "' and 'refs/remotes/origin/" OCTO4_BRANCH "'\n")); git_reference_free(octo1_ref); git_reference_free(octo2_ref); git_reference_free(octo3_ref); git_reference_free(octo4_ref); git_merge_head_free(our_head); git_merge_head_free(their_heads[0]); git_merge_head_free(their_heads[1]); git_merge_head_free(their_heads[2]); git_merge_head_free(their_heads[3]); } /* git pull origin branch octo1 */ void test_merge_workdir_setup__pull_one(void) { git_oid our_oid; git_oid octo1_1_oid; git_merge_head *our_head, *their_heads[1]; cl_git_pass(git_oid_fromstr(&our_oid, ORIG_HEAD)); cl_git_pass(git_merge_head_from_oid(&our_head, repo, &our_oid)); cl_git_pass(git_oid_fromstr(&octo1_1_oid, OCTO1_OID)); cl_git_pass(git_merge_head_from_fetchhead(&their_heads[0], repo, GIT_REFS_HEADS_DIR OCTO1_BRANCH, "http://remote.url/repo.git", &octo1_1_oid)); cl_git_pass(git_merge__setup(repo, our_head, (const git_merge_head **)their_heads, 1, 0)); cl_assert(test_file_contents(GIT_MERGE_HEAD_FILE, OCTO1_OID "\n")); cl_assert(test_file_contents(GIT_ORIG_HEAD_FILE, ORIG_HEAD "\n")); cl_assert(test_file_contents(GIT_MERGE_MODE_FILE, "")); cl_assert(test_file_contents(GIT_MERGE_MSG_FILE, "Merge branch 'octo1' of http://remote.url/repo.git\n")); git_merge_head_free(our_head); git_merge_head_free(their_heads[0]); } /* git pull origin octo1 octo2 */ void test_merge_workdir_setup__pull_two(void) { git_oid our_oid; git_oid octo1_oid; git_oid octo2_oid; git_merge_head *our_head, *their_heads[2]; cl_git_pass(git_oid_fromstr(&our_oid, ORIG_HEAD)); cl_git_pass(git_merge_head_from_oid(&our_head, repo, &our_oid)); cl_git_pass(git_oid_fromstr(&octo1_oid, OCTO1_OID)); cl_git_pass(git_merge_head_from_fetchhead(&their_heads[0], repo, GIT_REFS_HEADS_DIR OCTO1_BRANCH, "http://remote.url/repo.git", &octo1_oid)); cl_git_pass(git_oid_fromstr(&octo2_oid, OCTO2_OID)); cl_git_pass(git_merge_head_from_fetchhead(&their_heads[1], repo, GIT_REFS_HEADS_DIR OCTO2_BRANCH, "http://remote.url/repo.git", &octo2_oid)); cl_git_pass(git_merge__setup(repo, our_head, (const git_merge_head **)their_heads, 2, 0)); cl_assert(test_file_contents(GIT_MERGE_HEAD_FILE, OCTO1_OID "\n" OCTO2_OID "\n")); cl_assert(test_file_contents(GIT_ORIG_HEAD_FILE, ORIG_HEAD "\n")); cl_assert(test_file_contents(GIT_MERGE_MODE_FILE, "")); cl_assert(test_file_contents(GIT_MERGE_MSG_FILE, "Merge branches '" OCTO1_BRANCH "' and '" OCTO2_BRANCH "' of http://remote.url/repo.git\n")); git_merge_head_free(our_head); git_merge_head_free(their_heads[0]); git_merge_head_free(their_heads[1]); } /* git pull origin octo1 octo2 octo3 */ void test_merge_workdir_setup__pull_three(void) { git_oid our_oid; git_oid octo1_oid; git_oid octo2_oid; git_oid octo3_oid; git_merge_head *our_head, *their_heads[3]; cl_git_pass(git_oid_fromstr(&our_oid, ORIG_HEAD)); cl_git_pass(git_merge_head_from_oid(&our_head, repo, &our_oid)); cl_git_pass(git_oid_fromstr(&octo1_oid, OCTO1_OID)); cl_git_pass(git_merge_head_from_fetchhead(&their_heads[0], repo, GIT_REFS_HEADS_DIR OCTO1_BRANCH, "http://remote.url/repo.git", &octo1_oid)); cl_git_pass(git_oid_fromstr(&octo2_oid, OCTO2_OID)); cl_git_pass(git_merge_head_from_fetchhead(&their_heads[1], repo, GIT_REFS_HEADS_DIR OCTO2_BRANCH, "http://remote.url/repo.git", &octo2_oid)); cl_git_pass(git_oid_fromstr(&octo3_oid, OCTO3_OID)); cl_git_pass(git_merge_head_from_fetchhead(&their_heads[2], repo, GIT_REFS_HEADS_DIR OCTO3_BRANCH, "http://remote.url/repo.git", &octo3_oid)); cl_git_pass(git_merge__setup(repo, our_head, (const git_merge_head **)their_heads, 3, 0)); cl_assert(test_file_contents(GIT_MERGE_HEAD_FILE, OCTO1_OID "\n" OCTO2_OID "\n" OCTO3_OID "\n")); cl_assert(test_file_contents(GIT_ORIG_HEAD_FILE, ORIG_HEAD "\n")); cl_assert(test_file_contents(GIT_MERGE_MODE_FILE, "")); cl_assert(test_file_contents(GIT_MERGE_MSG_FILE, "Merge branches '" OCTO1_BRANCH "', '" OCTO2_BRANCH "' and '" OCTO3_BRANCH "' of http://remote.url/repo.git\n")); git_merge_head_free(our_head); git_merge_head_free(their_heads[0]); git_merge_head_free(their_heads[1]); git_merge_head_free(their_heads[2]); } void test_merge_workdir_setup__three_remotes(void) { git_oid our_oid; git_oid octo1_oid; git_oid octo2_oid; git_oid octo3_oid; git_merge_head *our_head, *their_heads[3]; cl_git_pass(git_oid_fromstr(&our_oid, ORIG_HEAD)); cl_git_pass(git_merge_head_from_oid(&our_head, repo, &our_oid)); cl_git_pass(git_oid_fromstr(&octo1_oid, OCTO1_OID)); cl_git_pass(git_merge_head_from_fetchhead(&their_heads[0], repo, GIT_REFS_HEADS_DIR OCTO1_BRANCH, "http://remote.first/repo.git", &octo1_oid)); cl_git_pass(git_oid_fromstr(&octo2_oid, OCTO2_OID)); cl_git_pass(git_merge_head_from_fetchhead(&their_heads[1], repo, GIT_REFS_HEADS_DIR OCTO2_BRANCH, "http://remote.second/repo.git", &octo2_oid)); cl_git_pass(git_oid_fromstr(&octo3_oid, OCTO3_OID)); cl_git_pass(git_merge_head_from_fetchhead(&their_heads[2], repo, GIT_REFS_HEADS_DIR OCTO3_BRANCH, "http://remote.third/repo.git", &octo3_oid)); cl_git_pass(git_merge__setup(repo, our_head, (const git_merge_head **)their_heads, 3, 0)); cl_assert(test_file_contents(GIT_MERGE_HEAD_FILE, OCTO1_OID "\n" OCTO2_OID "\n" OCTO3_OID "\n")); cl_assert(test_file_contents(GIT_ORIG_HEAD_FILE, ORIG_HEAD "\n")); cl_assert(test_file_contents(GIT_MERGE_MODE_FILE, "")); cl_assert(test_file_contents(GIT_MERGE_MSG_FILE, "Merge branch '" OCTO1_BRANCH "' of http://remote.first/repo.git, branch '" OCTO2_BRANCH "' of http://remote.second/repo.git, branch '" OCTO3_BRANCH "' of http://remote.third/repo.git\n")); git_merge_head_free(our_head); git_merge_head_free(their_heads[0]); git_merge_head_free(their_heads[1]); git_merge_head_free(their_heads[2]); } void test_merge_workdir_setup__two_remotes(void) { git_oid our_oid; git_oid octo1_oid; git_oid octo2_oid; git_oid octo3_oid; git_oid octo4_oid; git_merge_head *our_head, *their_heads[4]; cl_git_pass(git_oid_fromstr(&our_oid, ORIG_HEAD)); cl_git_pass(git_merge_head_from_oid(&our_head, repo, &our_oid)); cl_git_pass(git_oid_fromstr(&octo1_oid, OCTO1_OID)); cl_git_pass(git_merge_head_from_fetchhead(&their_heads[0], repo, GIT_REFS_HEADS_DIR OCTO1_BRANCH, "http://remote.first/repo.git", &octo1_oid)); cl_git_pass(git_oid_fromstr(&octo2_oid, OCTO2_OID)); cl_git_pass(git_merge_head_from_fetchhead(&their_heads[1], repo, GIT_REFS_HEADS_DIR OCTO2_BRANCH, "http://remote.second/repo.git", &octo2_oid)); cl_git_pass(git_oid_fromstr(&octo3_oid, OCTO3_OID)); cl_git_pass(git_merge_head_from_fetchhead(&their_heads[2], repo, GIT_REFS_HEADS_DIR OCTO3_BRANCH, "http://remote.first/repo.git", &octo3_oid)); cl_git_pass(git_oid_fromstr(&octo4_oid, OCTO4_OID)); cl_git_pass(git_merge_head_from_fetchhead(&their_heads[3], repo, GIT_REFS_HEADS_DIR OCTO4_BRANCH, "http://remote.second/repo.git", &octo4_oid)); cl_git_pass(git_merge__setup(repo, our_head, (const git_merge_head **)their_heads, 4, 0)); cl_assert(test_file_contents(GIT_MERGE_HEAD_FILE, OCTO1_OID "\n" OCTO2_OID "\n" OCTO3_OID "\n" OCTO4_OID "\n")); cl_assert(test_file_contents(GIT_ORIG_HEAD_FILE, ORIG_HEAD "\n")); cl_assert(test_file_contents(GIT_MERGE_MODE_FILE, "")); cl_assert(test_file_contents(GIT_MERGE_MSG_FILE, "Merge branches '" OCTO1_BRANCH "' and '" OCTO3_BRANCH "' of http://remote.first/repo.git, branches '" OCTO2_BRANCH "' and '" OCTO4_BRANCH "' of http://remote.second/repo.git\n")); git_merge_head_free(our_head); git_merge_head_free(their_heads[0]); git_merge_head_free(their_heads[1]); git_merge_head_free(their_heads[2]); git_merge_head_free(their_heads[3]); } struct merge_head_cb_data { const char **oid_str; unsigned int len; unsigned int i; }; static int merge_head_foreach_cb(const git_oid *oid, void *payload) { git_oid expected_oid; struct merge_head_cb_data *cb_data = payload; git_oid_fromstr(&expected_oid, cb_data->oid_str[cb_data->i]); cl_assert(git_oid_cmp(&expected_oid, oid) == 0); cb_data->i++; return 0; } void test_merge_workdir_setup__head_notfound(void) { int error; cl_git_fail((error = git_repository_mergehead_foreach(repo, merge_head_foreach_cb, NULL))); cl_assert(error == GIT_ENOTFOUND); } void test_merge_workdir_setup__head_invalid_oid(void) { int error; write_file_contents(GIT_MERGE_HEAD_FILE, "invalid-oid\n"); cl_git_fail((error = git_repository_mergehead_foreach(repo, merge_head_foreach_cb, NULL))); cl_assert(error == -1); } void test_merge_workdir_setup__head_foreach_nonewline(void) { int error; write_file_contents(GIT_MERGE_HEAD_FILE, THEIRS_SIMPLE_OID); cl_git_fail((error = git_repository_mergehead_foreach(repo, merge_head_foreach_cb, NULL))); cl_assert(error == -1); } void test_merge_workdir_setup__head_foreach_one(void) { const char *expected = THEIRS_SIMPLE_OID; struct merge_head_cb_data cb_data = { &expected, 1 }; write_file_contents(GIT_MERGE_HEAD_FILE, THEIRS_SIMPLE_OID "\n"); cl_git_pass(git_repository_mergehead_foreach(repo, merge_head_foreach_cb, &cb_data)); cl_assert(cb_data.i == cb_data.len); } void test_merge_workdir_setup__head_foreach_octopus(void) { const char *expected[] = { THEIRS_SIMPLE_OID, OCTO1_OID, OCTO2_OID, OCTO3_OID, OCTO4_OID, OCTO5_OID }; struct merge_head_cb_data cb_data = { expected, 6 }; write_file_contents(GIT_MERGE_HEAD_FILE, THEIRS_SIMPLE_OID "\n" OCTO1_OID "\n" OCTO2_OID "\n" OCTO3_OID "\n" OCTO4_OID "\n" OCTO5_OID "\n"); cl_git_pass(git_repository_mergehead_foreach(repo, merge_head_foreach_cb, &cb_data)); cl_assert(cb_data.i == cb_data.len); } libgit2-0.19.0/tests-clar/network/000077500000000000000000000000001216214232500167055ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/network/cred.c000066400000000000000000000031161216214232500177670ustar00rootroot00000000000000#include "clar_libgit2.h" #include "git2/cred_helpers.h" void test_network_cred__stock_userpass_validates_args(void) { git_cred_userpass_payload payload = {0}; cl_git_fail(git_cred_userpass(NULL, NULL, NULL, 0, NULL)); payload.username = "user"; cl_git_fail(git_cred_userpass(NULL, NULL, NULL, 0, &payload)); payload.username = NULL; payload.username = "pass"; cl_git_fail(git_cred_userpass(NULL, NULL, NULL, 0, &payload)); } void test_network_cred__stock_userpass_validates_that_method_is_allowed(void) { git_cred *cred; git_cred_userpass_payload payload = {"user", "pass"}; cl_git_fail(git_cred_userpass(&cred, NULL, NULL, 0, &payload)); cl_git_pass(git_cred_userpass(&cred, NULL, NULL, GIT_CREDTYPE_USERPASS_PLAINTEXT, &payload)); cred->free(cred); } void test_network_cred__stock_userpass_properly_handles_username_in_url(void) { git_cred *cred; git_cred_userpass_plaintext *plain; git_cred_userpass_payload payload = {"alice", "password"}; cl_git_pass(git_cred_userpass(&cred, NULL, NULL, GIT_CREDTYPE_USERPASS_PLAINTEXT, &payload)); plain = (git_cred_userpass_plaintext*)cred; cl_assert_equal_s(plain->username, "alice"); cred->free(cred); cl_git_pass(git_cred_userpass(&cred, NULL, "bob", GIT_CREDTYPE_USERPASS_PLAINTEXT, &payload)); plain = (git_cred_userpass_plaintext*)cred; cl_assert_equal_s(plain->username, "alice"); cred->free(cred); payload.username = NULL; cl_git_pass(git_cred_userpass(&cred, NULL, "bob", GIT_CREDTYPE_USERPASS_PLAINTEXT, &payload)); plain = (git_cred_userpass_plaintext*)cred; cl_assert_equal_s(plain->username, "bob"); cred->free(cred); } libgit2-0.19.0/tests-clar/network/fetchlocal.c000066400000000000000000000040111216214232500211510ustar00rootroot00000000000000#include "clar_libgit2.h" #include "buffer.h" #include "path.h" #include "remote.h" static int transfer_cb(const git_transfer_progress *stats, void *payload) { int *callcount = (int*)payload; GIT_UNUSED(stats); (*callcount)++; return 0; } static void cleanup_local_repo(void *path) { cl_fixture_cleanup((char *)path); } void test_network_fetchlocal__complete(void) { git_repository *repo; git_remote *origin; int callcount = 0; git_strarray refnames = {0}; const char *url = cl_git_fixture_url("testrepo.git"); cl_set_cleanup(&cleanup_local_repo, "foo"); cl_git_pass(git_repository_init(&repo, "foo", true)); cl_git_pass(git_remote_create(&origin, repo, GIT_REMOTE_ORIGIN, url)); cl_git_pass(git_remote_connect(origin, GIT_DIRECTION_FETCH)); cl_git_pass(git_remote_download(origin, transfer_cb, &callcount)); cl_git_pass(git_remote_update_tips(origin)); cl_git_pass(git_reference_list(&refnames, repo)); cl_assert_equal_i(19, (int)refnames.count); cl_assert(callcount > 0); git_strarray_free(&refnames); git_remote_free(origin); git_repository_free(repo); } static void cleanup_sandbox(void *unused) { GIT_UNUSED(unused); cl_git_sandbox_cleanup(); } void test_network_fetchlocal__partial(void) { git_repository *repo = cl_git_sandbox_init("partial-testrepo"); git_remote *origin; int callcount = 0; git_strarray refnames = {0}; const char *url; cl_set_cleanup(&cleanup_sandbox, NULL); cl_git_pass(git_reference_list(&refnames, repo)); cl_assert_equal_i(1, (int)refnames.count); url = cl_git_fixture_url("testrepo.git"); cl_git_pass(git_remote_create(&origin, repo, GIT_REMOTE_ORIGIN, url)); cl_git_pass(git_remote_connect(origin, GIT_DIRECTION_FETCH)); cl_git_pass(git_remote_download(origin, transfer_cb, &callcount)); cl_git_pass(git_remote_update_tips(origin)); git_strarray_free(&refnames); cl_git_pass(git_reference_list(&refnames, repo)); cl_assert_equal_i(20, (int)refnames.count); /* 18 remote + 1 local */ cl_assert(callcount > 0); git_strarray_free(&refnames); git_remote_free(origin); } libgit2-0.19.0/tests-clar/network/refspecs.c000066400000000000000000000100751216214232500206660ustar00rootroot00000000000000#include "clar_libgit2.h" #include "refspec.h" #include "remote.h" static void assert_refspec(unsigned int direction, const char *input, bool is_expected_to_be_valid) { git_refspec refspec; int error; error = git_refspec__parse(&refspec, input, direction == GIT_DIRECTION_FETCH); git_refspec__free(&refspec); if (is_expected_to_be_valid) cl_assert_equal_i(0, error); else cl_assert_equal_i(GIT_ERROR, error); } void test_network_refspecs__parsing(void) { // Ported from https://github.com/git/git/blob/abd2bde78bd994166900290434a2048e660dabed/t/t5511-refspec.sh assert_refspec(GIT_DIRECTION_PUSH, "", false); assert_refspec(GIT_DIRECTION_PUSH, ":", true); assert_refspec(GIT_DIRECTION_PUSH, "::", false); assert_refspec(GIT_DIRECTION_PUSH, "+:", true); assert_refspec(GIT_DIRECTION_FETCH, "", true); assert_refspec(GIT_DIRECTION_PUSH, ":", true); assert_refspec(GIT_DIRECTION_FETCH, "::", false); assert_refspec(GIT_DIRECTION_PUSH, "refs/heads/*:refs/remotes/frotz/*", true); assert_refspec(GIT_DIRECTION_PUSH, "refs/heads/*:refs/remotes/frotz", false); assert_refspec(GIT_DIRECTION_PUSH, "refs/heads:refs/remotes/frotz/*", false); assert_refspec(GIT_DIRECTION_PUSH, "refs/heads/master:refs/remotes/frotz/xyzzy", true); /* * These have invalid LHS, but we do not have a formal "valid sha-1 * expression syntax checker" so they are not checked with the current * code. They will be caught downstream anyway, but we may want to * have tighter check later... */ //assert_refspec(GIT_DIRECTION_PUSH, "refs/heads/master::refs/remotes/frotz/xyzzy", false); //assert_refspec(GIT_DIRECTION_PUSH, "refs/heads/maste :refs/remotes/frotz/xyzzy", false); assert_refspec(GIT_DIRECTION_FETCH, "refs/heads/*:refs/remotes/frotz/*", true); assert_refspec(GIT_DIRECTION_FETCH, "refs/heads/*:refs/remotes/frotz", false); assert_refspec(GIT_DIRECTION_FETCH, "refs/heads:refs/remotes/frotz/*", false); assert_refspec(GIT_DIRECTION_FETCH, "refs/heads/master:refs/remotes/frotz/xyzzy", true); assert_refspec(GIT_DIRECTION_FETCH, "refs/heads/master::refs/remotes/frotz/xyzzy", false); assert_refspec(GIT_DIRECTION_FETCH, "refs/heads/maste :refs/remotes/frotz/xyzzy", false); assert_refspec(GIT_DIRECTION_PUSH, "master~1:refs/remotes/frotz/backup", true); assert_refspec(GIT_DIRECTION_FETCH, "master~1:refs/remotes/frotz/backup", false); assert_refspec(GIT_DIRECTION_PUSH, "HEAD~4:refs/remotes/frotz/new", true); assert_refspec(GIT_DIRECTION_FETCH, "HEAD~4:refs/remotes/frotz/new", false); assert_refspec(GIT_DIRECTION_PUSH, "HEAD", true); assert_refspec(GIT_DIRECTION_FETCH, "HEAD", true); assert_refspec(GIT_DIRECTION_PUSH, "refs/heads/ nitfol", false); assert_refspec(GIT_DIRECTION_FETCH, "refs/heads/ nitfol", false); assert_refspec(GIT_DIRECTION_PUSH, "HEAD:", false); assert_refspec(GIT_DIRECTION_FETCH, "HEAD:", true); assert_refspec(GIT_DIRECTION_PUSH, "refs/heads/ nitfol:", false); assert_refspec(GIT_DIRECTION_FETCH, "refs/heads/ nitfol:", false); assert_refspec(GIT_DIRECTION_PUSH, ":refs/remotes/frotz/deleteme", true); assert_refspec(GIT_DIRECTION_FETCH, ":refs/remotes/frotz/HEAD-to-me", true); assert_refspec(GIT_DIRECTION_PUSH, ":refs/remotes/frotz/delete me", false); assert_refspec(GIT_DIRECTION_FETCH, ":refs/remotes/frotz/HEAD to me", false); assert_refspec(GIT_DIRECTION_FETCH, "refs/heads/*/for-linus:refs/remotes/mine/*-blah", false); assert_refspec(GIT_DIRECTION_PUSH, "refs/heads/*/for-linus:refs/remotes/mine/*-blah", false); assert_refspec(GIT_DIRECTION_FETCH, "refs/heads*/for-linus:refs/remotes/mine/*", false); assert_refspec(GIT_DIRECTION_PUSH, "refs/heads*/for-linus:refs/remotes/mine/*", false); assert_refspec(GIT_DIRECTION_FETCH, "refs/heads/*/*/for-linus:refs/remotes/mine/*", false); assert_refspec(GIT_DIRECTION_PUSH, "refs/heads/*/*/for-linus:refs/remotes/mine/*", false); assert_refspec(GIT_DIRECTION_FETCH, "refs/heads/*/for-linus:refs/remotes/mine/*", true); assert_refspec(GIT_DIRECTION_PUSH, "refs/heads/*/for-linus:refs/remotes/mine/*", true); assert_refspec(GIT_DIRECTION_FETCH, "master", true); assert_refspec(GIT_DIRECTION_PUSH, "master", true); } libgit2-0.19.0/tests-clar/network/remote/000077500000000000000000000000001216214232500202005ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/network/remote/createthenload.c000066400000000000000000000017601216214232500233320ustar00rootroot00000000000000#include "clar_libgit2.h" static git_remote *_remote; static git_repository *_repo; static git_config *_config; static char url[] = "http://github.com/libgit2/libgit2.git"; void test_network_remote_createthenload__initialize(void) { cl_fixture_sandbox("testrepo.git"); cl_git_pass(git_repository_open(&_repo, "testrepo.git")); cl_git_pass(git_repository_config(&_config, _repo)); cl_git_pass(git_config_set_string(_config, "remote.origin.fetch", "+refs/heads/*:refs/remotes/origin/*")); cl_git_pass(git_config_set_string(_config, "remote.origin.url", url)); git_config_free(_config); cl_git_pass(git_remote_load(&_remote, _repo, "origin")); } void test_network_remote_createthenload__cleanup(void) { git_remote_free(_remote); _remote = NULL; git_repository_free(_repo); _repo = NULL; cl_fixture_cleanup("testrepo.git"); } void test_network_remote_createthenload__parsing(void) { cl_assert_equal_s(git_remote_name(_remote), "origin"); cl_assert_equal_s(git_remote_url(_remote), url); } libgit2-0.19.0/tests-clar/network/remote/isvalidname.c000066400000000000000000000013211216214232500226350ustar00rootroot00000000000000#include "clar_libgit2.h" void test_network_remote_isvalidname__can_detect_invalid_formats(void) { cl_assert_equal_i(false, git_remote_is_valid_name("/")); cl_assert_equal_i(false, git_remote_is_valid_name("//")); cl_assert_equal_i(false, git_remote_is_valid_name(".lock")); cl_assert_equal_i(false, git_remote_is_valid_name("a.lock")); cl_assert_equal_i(false, git_remote_is_valid_name("/no/leading/slash")); cl_assert_equal_i(false, git_remote_is_valid_name("no/trailing/slash/")); } void test_network_remote_isvalidname__wont_hopefully_choke_on_valid_formats(void) { cl_assert_equal_i(true, git_remote_is_valid_name("webmatrix")); cl_assert_equal_i(true, git_remote_is_valid_name("yishaigalatzer/rules")); } libgit2-0.19.0/tests-clar/network/remote/local.c000066400000000000000000000101241216214232500214340ustar00rootroot00000000000000#include "clar_libgit2.h" #include "buffer.h" #include "path.h" #include "posix.h" static git_repository *repo; static git_buf file_path_buf = GIT_BUF_INIT; static git_remote *remote; void test_network_remote_local__initialize(void) { cl_git_pass(git_repository_init(&repo, "remotelocal/", 0)); cl_assert(repo != NULL); } void test_network_remote_local__cleanup(void) { git_buf_free(&file_path_buf); git_remote_free(remote); remote = NULL; git_repository_free(repo); repo = NULL; cl_fixture_cleanup("remotelocal"); } static int count_ref__cb(git_remote_head *head, void *payload) { int *count = (int *)payload; (void)head; (*count)++; return 0; } static int ensure_peeled__cb(git_remote_head *head, void *payload) { GIT_UNUSED(payload); if(strcmp(head->name, "refs/tags/test^{}") != 0) return 0; return git_oid_streq(&head->oid, "e90810b8df3e80c413d903f631643c716887138d"); } static void connect_to_local_repository(const char *local_repository) { git_buf_sets(&file_path_buf, cl_git_path_url(local_repository)); cl_git_pass(git_remote_create_inmemory(&remote, repo, NULL, git_buf_cstr(&file_path_buf))); cl_git_pass(git_remote_connect(remote, GIT_DIRECTION_FETCH)); } void test_network_remote_local__connected(void) { connect_to_local_repository(cl_fixture("testrepo.git")); cl_assert(git_remote_connected(remote)); git_remote_disconnect(remote); cl_assert(!git_remote_connected(remote)); } void test_network_remote_local__retrieve_advertised_references(void) { int how_many_refs = 0; connect_to_local_repository(cl_fixture("testrepo.git")); cl_git_pass(git_remote_ls(remote, &count_ref__cb, &how_many_refs)); cl_assert_equal_i(how_many_refs, 28); } void test_network_remote_local__retrieve_advertised_references_from_spaced_repository(void) { int how_many_refs = 0; cl_fixture_sandbox("testrepo.git"); cl_git_pass(p_rename("testrepo.git", "spaced testrepo.git")); connect_to_local_repository("spaced testrepo.git"); cl_git_pass(git_remote_ls(remote, &count_ref__cb, &how_many_refs)); cl_assert_equal_i(how_many_refs, 28); git_remote_free(remote); /* Disconnect from the "spaced repo" before the cleanup */ remote = NULL; cl_fixture_cleanup("spaced testrepo.git"); } void test_network_remote_local__nested_tags_are_completely_peeled(void) { connect_to_local_repository(cl_fixture("testrepo.git")); cl_git_pass(git_remote_ls(remote, &ensure_peeled__cb, NULL)); } void test_network_remote_local__shorthand_fetch_refspec0(void) { const char *refspec = "master:remotes/sloppy/master"; const char *refspec2 = "master:boh/sloppy/master"; git_reference *ref; connect_to_local_repository(cl_fixture("testrepo.git")); cl_git_pass(git_remote_add_fetch(remote, refspec)); cl_git_pass(git_remote_add_fetch(remote, refspec2)); cl_git_pass(git_remote_download(remote, NULL, NULL)); cl_git_pass(git_remote_update_tips(remote)); cl_git_pass(git_reference_lookup(&ref, repo, "refs/remotes/sloppy/master")); git_reference_free(ref); cl_git_pass(git_reference_lookup(&ref, repo, "refs/heads/boh/sloppy/master")); git_reference_free(ref); } void test_network_remote_local__shorthand_fetch_refspec1(void) { const char *refspec = "master"; const char *refspec2 = "hard_tag"; git_reference *ref; connect_to_local_repository(cl_fixture("testrepo.git")); git_remote_clear_refspecs(remote); cl_git_pass(git_remote_add_fetch(remote, refspec)); cl_git_pass(git_remote_add_fetch(remote, refspec2)); cl_git_pass(git_remote_download(remote, NULL, NULL)); cl_git_pass(git_remote_update_tips(remote)); cl_git_fail(git_reference_lookup(&ref, repo, "refs/remotes/master")); cl_git_fail(git_reference_lookup(&ref, repo, "refs/tags/hard_tag")); } void test_network_remote_local__tagopt(void) { git_reference *ref; connect_to_local_repository(cl_fixture("testrepo.git")); git_remote_set_autotag(remote, GIT_REMOTE_DOWNLOAD_TAGS_ALL); cl_git_pass(git_remote_download(remote, NULL, NULL)); cl_git_pass(git_remote_update_tips(remote)); cl_git_fail(git_reference_lookup(&ref, repo, "refs/remotes/master")); cl_git_pass(git_reference_lookup(&ref, repo, "refs/tags/hard_tag")); git_reference_free(ref); } libgit2-0.19.0/tests-clar/network/remote/remotes.c000066400000000000000000000326631216214232500220340ustar00rootroot00000000000000#include "clar_libgit2.h" #include "buffer.h" #include "refspec.h" #include "remote.h" static git_remote *_remote; static git_repository *_repo; static const git_refspec *_refspec; void test_network_remote_remotes__initialize(void) { _repo = cl_git_sandbox_init("testrepo.git"); cl_git_pass(git_remote_load(&_remote, _repo, "test")); _refspec = git_remote_get_refspec(_remote, 0); cl_assert(_refspec != NULL); } void test_network_remote_remotes__cleanup(void) { git_remote_free(_remote); _remote = NULL; cl_git_sandbox_cleanup(); } void test_network_remote_remotes__parsing(void) { git_remote *_remote2 = NULL; cl_assert_equal_s(git_remote_name(_remote), "test"); cl_assert_equal_s(git_remote_url(_remote), "git://github.com/libgit2/libgit2"); cl_assert(git_remote_pushurl(_remote) == NULL); cl_assert_equal_s(git_remote__urlfordirection(_remote, GIT_DIRECTION_FETCH), "git://github.com/libgit2/libgit2"); cl_assert_equal_s(git_remote__urlfordirection(_remote, GIT_DIRECTION_PUSH), "git://github.com/libgit2/libgit2"); cl_git_pass(git_remote_load(&_remote2, _repo, "test_with_pushurl")); cl_assert_equal_s(git_remote_name(_remote2), "test_with_pushurl"); cl_assert_equal_s(git_remote_url(_remote2), "git://github.com/libgit2/fetchlibgit2"); cl_assert_equal_s(git_remote_pushurl(_remote2), "git://github.com/libgit2/pushlibgit2"); cl_assert_equal_s(git_remote__urlfordirection(_remote2, GIT_DIRECTION_FETCH), "git://github.com/libgit2/fetchlibgit2"); cl_assert_equal_s(git_remote__urlfordirection(_remote2, GIT_DIRECTION_PUSH), "git://github.com/libgit2/pushlibgit2"); git_remote_free(_remote2); } void test_network_remote_remotes__pushurl(void) { cl_git_pass(git_remote_set_pushurl(_remote, "git://github.com/libgit2/notlibgit2")); cl_assert_equal_s(git_remote_pushurl(_remote), "git://github.com/libgit2/notlibgit2"); cl_git_pass(git_remote_set_pushurl(_remote, NULL)); cl_assert(git_remote_pushurl(_remote) == NULL); } void test_network_remote_remotes__error_when_no_push_available(void) { git_remote *r; git_transport *t; git_push *p; cl_git_pass(git_remote_create_inmemory(&r, _repo, NULL, cl_fixture("testrepo.git"))); cl_git_pass(git_transport_local(&t,r,NULL)); /* Make sure that push is really not available */ t->push = NULL; cl_git_pass(git_remote_set_transport(r, t)); cl_git_pass(git_remote_connect(r, GIT_DIRECTION_PUSH)); cl_git_pass(git_push_new(&p, r)); cl_git_pass(git_push_add_refspec(p, "refs/heads/master")); cl_git_fail_with(git_push_finish(p), GIT_ERROR); git_push_free(p); git_remote_free(r); } void test_network_remote_remotes__parsing_ssh_remote(void) { cl_assert( git_remote_valid_url("git@github.com:libgit2/libgit2.git") ); } void test_network_remote_remotes__parsing_local_path_fails_if_path_not_found(void) { cl_assert( !git_remote_valid_url("/home/git/repos/libgit2.git") ); } void test_network_remote_remotes__supported_transport_methods_are_supported(void) { cl_assert( git_remote_supported_url("git://github.com/libgit2/libgit2") ); } void test_network_remote_remotes__unsupported_transport_methods_are_unsupported(void) { #ifndef GIT_SSH cl_assert( !git_remote_supported_url("git@github.com:libgit2/libgit2.git") ); #endif } void test_network_remote_remotes__refspec_parsing(void) { cl_assert_equal_s(git_refspec_src(_refspec), "refs/heads/*"); cl_assert_equal_s(git_refspec_dst(_refspec), "refs/remotes/test/*"); } void test_network_remote_remotes__add_fetchspec(void) { size_t size; size = git_remote_refspec_count(_remote); cl_git_pass(git_remote_add_fetch(_remote, "refs/*:refs/*")); size++; cl_assert_equal_i((int)size, (int)git_remote_refspec_count(_remote)); _refspec = git_remote_get_refspec(_remote, size - 1); cl_assert_equal_s(git_refspec_src(_refspec), "refs/*"); cl_assert_equal_s(git_refspec_dst(_refspec), "refs/*"); cl_assert_equal_s(git_refspec_string(_refspec), "refs/*:refs/*"); cl_assert_equal_b(_refspec->push, false); } void test_network_remote_remotes__add_pushspec(void) { size_t size; size = git_remote_refspec_count(_remote); cl_git_pass(git_remote_add_push(_remote, "refs/*:refs/*")); size++; cl_assert_equal_i((int)size, (int)git_remote_refspec_count(_remote)); _refspec = git_remote_get_refspec(_remote, size - 1); cl_assert_equal_s(git_refspec_src(_refspec), "refs/*"); cl_assert_equal_s(git_refspec_dst(_refspec), "refs/*"); cl_assert_equal_s(git_refspec_string(_refspec), "refs/*:refs/*"); cl_assert_equal_b(_refspec->push, true); } void test_network_remote_remotes__save(void) { git_strarray array; const char *fetch_refspec = "refs/heads/*:refs/remotes/upstream/*"; const char *push_refspec = "refs/heads/*:refs/heads/*"; git_remote_free(_remote); _remote = NULL; /* Set up the remote and save it to config */ cl_git_pass(git_remote_create(&_remote, _repo, "upstream", "git://github.com/libgit2/libgit2")); git_remote_clear_refspecs(_remote); cl_git_pass(git_remote_add_fetch(_remote, fetch_refspec)); cl_git_pass(git_remote_add_push(_remote, push_refspec)); cl_git_pass(git_remote_set_pushurl(_remote, "git://github.com/libgit2/libgit2_push")); cl_git_pass(git_remote_save(_remote)); git_remote_free(_remote); _remote = NULL; /* Load it from config and make sure everything matches */ cl_git_pass(git_remote_load(&_remote, _repo, "upstream")); cl_git_pass(git_remote_get_fetch_refspecs(&array, _remote)); cl_assert_equal_i(1, (int)array.count); cl_assert_equal_s(fetch_refspec, array.strings[0]); git_strarray_free(&array); cl_git_pass(git_remote_get_push_refspecs(&array, _remote)); cl_assert_equal_i(1, (int)array.count); cl_assert_equal_s(push_refspec, array.strings[0]); cl_assert_equal_s(git_remote_url(_remote), "git://github.com/libgit2/libgit2"); cl_assert_equal_s(git_remote_pushurl(_remote), "git://github.com/libgit2/libgit2_push"); git_strarray_free(&array); /* remove the pushurl again and see if we can save that too */ cl_git_pass(git_remote_set_pushurl(_remote, NULL)); cl_git_pass(git_remote_save(_remote)); git_remote_free(_remote); _remote = NULL; cl_git_pass(git_remote_load(&_remote, _repo, "upstream")); cl_assert(git_remote_pushurl(_remote) == NULL); } void test_network_remote_remotes__fnmatch(void) { cl_assert(git_refspec_src_matches(_refspec, "refs/heads/master")); cl_assert(git_refspec_src_matches(_refspec, "refs/heads/multi/level/branch")); } void test_network_remote_remotes__transform(void) { char ref[1024] = {0}; cl_git_pass(git_refspec_transform(ref, sizeof(ref), _refspec, "refs/heads/master")); cl_assert_equal_s(ref, "refs/remotes/test/master"); } void test_network_remote_remotes__transform_destination_to_source(void) { char ref[1024] = {0}; cl_git_pass(git_refspec_rtransform(ref, sizeof(ref), _refspec, "refs/remotes/test/master")); cl_assert_equal_s(ref, "refs/heads/master"); } void test_network_remote_remotes__transform_r(void) { git_buf buf = GIT_BUF_INIT; cl_git_pass(git_refspec_transform_r(&buf, _refspec, "refs/heads/master")); cl_assert_equal_s(git_buf_cstr(&buf), "refs/remotes/test/master"); git_buf_free(&buf); } void test_network_remote_remotes__missing_refspecs(void) { git_config *cfg; git_remote_free(_remote); _remote = NULL; cl_git_pass(git_repository_config(&cfg, _repo)); cl_git_pass(git_config_set_string(cfg, "remote.specless.url", "http://example.com")); cl_git_pass(git_remote_load(&_remote, _repo, "specless")); git_config_free(cfg); } void test_network_remote_remotes__list(void) { git_strarray list; git_config *cfg; cl_git_pass(git_remote_list(&list, _repo)); cl_assert(list.count == 4); git_strarray_free(&list); cl_git_pass(git_repository_config(&cfg, _repo)); cl_git_pass(git_config_set_string(cfg, "remote.specless.url", "http://example.com")); cl_git_pass(git_remote_list(&list, _repo)); cl_assert(list.count == 5); git_strarray_free(&list); git_config_free(cfg); } void test_network_remote_remotes__loading_a_missing_remote_returns_ENOTFOUND(void) { git_remote_free(_remote); _remote = NULL; cl_assert_equal_i(GIT_ENOTFOUND, git_remote_load(&_remote, _repo, "just-left-few-minutes-ago")); } void test_network_remote_remotes__loading_with_an_invalid_name_returns_EINVALIDSPEC(void) { git_remote_free(_remote); _remote = NULL; cl_assert_equal_i(GIT_EINVALIDSPEC, git_remote_load(&_remote, _repo, "Inv@{id")); } /* * $ git remote add addtest http://github.com/libgit2/libgit2 * * $ cat .git/config * [...] * [remote "addtest"] * url = http://github.com/libgit2/libgit2 * fetch = +refs/heads/\*:refs/remotes/addtest/\* */ void test_network_remote_remotes__add(void) { git_remote_free(_remote); _remote = NULL; cl_git_pass(git_remote_create(&_remote, _repo, "addtest", "http://github.com/libgit2/libgit2")); cl_assert_equal_i(GIT_REMOTE_DOWNLOAD_TAGS_AUTO, git_remote_autotag(_remote)); git_remote_free(_remote); _remote = NULL; cl_git_pass(git_remote_load(&_remote, _repo, "addtest")); cl_assert_equal_i(GIT_REMOTE_DOWNLOAD_TAGS_AUTO, git_remote_autotag(_remote)); _refspec = git_vector_get(&_remote->refspecs, 0); cl_assert_equal_s("refs/heads/*", git_refspec_src(_refspec)); cl_assert(git_refspec_force(_refspec) == 1); cl_assert_equal_s("refs/remotes/addtest/*", git_refspec_dst(_refspec)); cl_assert_equal_s(git_remote_url(_remote), "http://github.com/libgit2/libgit2"); } void test_network_remote_remotes__cannot_add_a_nameless_remote(void) { git_remote *remote; cl_assert_equal_i( GIT_EINVALIDSPEC, git_remote_create(&remote, _repo, NULL, "git://github.com/libgit2/libgit2")); } void test_network_remote_remotes__cannot_save_an_inmemory_remote(void) { git_remote *remote; cl_git_pass(git_remote_create_inmemory(&remote, _repo, NULL, "git://github.com/libgit2/libgit2")); cl_assert_equal_p(NULL, git_remote_name(remote)); cl_git_fail(git_remote_save(remote)); git_remote_free(remote); } void test_network_remote_remotes__cannot_add_a_remote_with_an_invalid_name(void) { git_remote *remote = NULL; cl_assert_equal_i( GIT_EINVALIDSPEC, git_remote_create(&remote, _repo, "Inv@{id", "git://github.com/libgit2/libgit2")); cl_assert_equal_p(remote, NULL); cl_assert_equal_i( GIT_EINVALIDSPEC, git_remote_create(&remote, _repo, "", "git://github.com/libgit2/libgit2")); cl_assert_equal_p(remote, NULL); } void test_network_remote_remotes__tagopt(void) { const char *opt; git_config *cfg; cl_git_pass(git_repository_config(&cfg, _repo)); git_remote_set_autotag(_remote, GIT_REMOTE_DOWNLOAD_TAGS_ALL); cl_git_pass(git_remote_save(_remote)); cl_git_pass(git_config_get_string(&opt, cfg, "remote.test.tagopt")); cl_assert_equal_s("--tags", opt); git_remote_set_autotag(_remote, GIT_REMOTE_DOWNLOAD_TAGS_NONE); cl_git_pass(git_remote_save(_remote)); cl_git_pass(git_config_get_string(&opt, cfg, "remote.test.tagopt")); cl_assert_equal_s("--no-tags", opt); git_remote_set_autotag(_remote, GIT_REMOTE_DOWNLOAD_TAGS_AUTO); cl_git_pass(git_remote_save(_remote)); cl_assert(git_config_get_string(&opt, cfg, "remote.test.tagopt") == GIT_ENOTFOUND); git_config_free(cfg); } void test_network_remote_remotes__cannot_load_with_an_empty_url(void) { git_remote *remote = NULL; cl_git_fail(git_remote_load(&remote, _repo, "empty-remote-url")); cl_assert(giterr_last()->klass == GITERR_INVALID); cl_assert_equal_p(remote, NULL); } void test_network_remote_remotes__check_structure_version(void) { git_transport transport = GIT_TRANSPORT_INIT; const git_error *err; git_remote_free(_remote); _remote = NULL; cl_git_pass(git_remote_create_inmemory(&_remote, _repo, NULL, "test-protocol://localhost")); transport.version = 0; cl_git_fail(git_remote_set_transport(_remote, &transport)); err = giterr_last(); cl_assert_equal_i(GITERR_INVALID, err->klass); giterr_clear(); transport.version = 1024; cl_git_fail(git_remote_set_transport(_remote, &transport)); err = giterr_last(); cl_assert_equal_i(GITERR_INVALID, err->klass); } void assert_cannot_create_remote(const char *name, int expected_error) { git_remote *remote = NULL; cl_git_fail_with( git_remote_create(&remote, _repo, name, "git://github.com/libgit2/libgit2"), expected_error); cl_assert_equal_p(remote, NULL); } void test_network_remote_remotes__cannot_create_a_remote_which_name_conflicts_with_an_existing_remote(void) { assert_cannot_create_remote("test", GIT_EEXISTS); } void test_network_remote_remotes__cannot_create_a_remote_which_name_is_invalid(void) { assert_cannot_create_remote("/", GIT_EINVALIDSPEC); assert_cannot_create_remote("//", GIT_EINVALIDSPEC); assert_cannot_create_remote(".lock", GIT_EINVALIDSPEC); assert_cannot_create_remote("a.lock", GIT_EINVALIDSPEC); } static const char *fetch_refspecs[] = { "+refs/heads/*:refs/remotes/origin/*", "refs/tags/*:refs/tags/*", "+refs/pull/*:refs/pull/*", }; static const char *push_refspecs[] = { "refs/heads/*:refs/heads/*", "refs/tags/*:refs/tags/*", "refs/notes/*:refs/notes/*", }; void test_network_remote_remotes__query_refspecs(void) { git_remote *remote; git_strarray array; int i; cl_git_pass(git_remote_create_inmemory(&remote, _repo, NULL, "git://github.com/libgit2/libgit2")); for (i = 0; i < 3; i++) { cl_git_pass(git_remote_add_fetch(remote, fetch_refspecs[i])); cl_git_pass(git_remote_add_push(remote, push_refspecs[i])); } cl_git_pass(git_remote_get_fetch_refspecs(&array, remote)); for (i = 0; i < 3; i++) { cl_assert_equal_s(fetch_refspecs[i], array.strings[i]); } git_strarray_free(&array); cl_git_pass(git_remote_get_push_refspecs(&array, remote)); for (i = 0; i < 3; i++) { cl_assert_equal_s(push_refspecs[i], array.strings[i]); } git_strarray_free(&array); git_remote_free(remote); } libgit2-0.19.0/tests-clar/network/remote/rename.c000066400000000000000000000121041216214232500216110ustar00rootroot00000000000000#include "clar_libgit2.h" #include "config/config_helpers.h" #include "repository.h" static git_remote *_remote; static git_repository *_repo; void test_network_remote_rename__initialize(void) { _repo = cl_git_sandbox_init("testrepo.git"); cl_git_pass(git_remote_load(&_remote, _repo, "test")); } void test_network_remote_rename__cleanup(void) { git_remote_free(_remote); _remote = NULL; cl_git_sandbox_cleanup(); } static int dont_call_me_cb(const char *fetch_refspec, void *payload) { GIT_UNUSED(fetch_refspec); GIT_UNUSED(payload); cl_assert(false); return -1; } void test_network_remote_rename__renaming_a_remote_moves_related_configuration_section(void) { assert_config_entry_existence(_repo, "remote.test.fetch", true); assert_config_entry_existence(_repo, "remote.just/renamed.fetch", false); cl_git_pass(git_remote_rename(_remote, "just/renamed", dont_call_me_cb, NULL)); assert_config_entry_existence(_repo, "remote.test.fetch", false); assert_config_entry_existence(_repo, "remote.just/renamed.fetch", true); } void test_network_remote_rename__renaming_a_remote_updates_branch_related_configuration_entries(void) { assert_config_entry_value(_repo, "branch.master.remote", "test"); cl_git_pass(git_remote_rename(_remote, "just/renamed", dont_call_me_cb, NULL)); assert_config_entry_value(_repo, "branch.master.remote", "just/renamed"); } void test_network_remote_rename__renaming_a_remote_updates_default_fetchrefspec(void) { cl_git_pass(git_remote_rename(_remote, "just/renamed", dont_call_me_cb, NULL)); assert_config_entry_value(_repo, "remote.just/renamed.fetch", "+refs/heads/*:refs/remotes/just/renamed/*"); } void test_network_remote_rename__renaming_a_remote_without_a_fetchrefspec_doesnt_create_one(void) { git_config *config; git_remote_free(_remote); cl_git_pass(git_repository_config__weakptr(&config, _repo)); cl_git_pass(git_config_delete_entry(config, "remote.test.fetch")); cl_git_pass(git_remote_load(&_remote, _repo, "test")); assert_config_entry_existence(_repo, "remote.test.fetch", false); cl_git_pass(git_remote_rename(_remote, "just/renamed", dont_call_me_cb, NULL)); assert_config_entry_existence(_repo, "remote.just/renamed.fetch", false); } static int ensure_refspecs(const char* refspec_name, void *payload) { int i = 0; bool found = false; const char ** exp = (const char **)payload; while (exp[i]) { if (strcmp(exp[i++], refspec_name)) continue; found = true; break; } cl_assert(found); return 0; } void test_network_remote_rename__renaming_a_remote_notifies_of_non_default_fetchrefspec(void) { git_config *config; char *expected_refspecs[] = { "+refs/*:refs/*", NULL }; git_remote_free(_remote); cl_git_pass(git_repository_config__weakptr(&config, _repo)); cl_git_pass(git_config_set_string(config, "remote.test.fetch", "+refs/*:refs/*")); cl_git_pass(git_remote_load(&_remote, _repo, "test")); cl_git_pass(git_remote_rename(_remote, "just/renamed", ensure_refspecs, &expected_refspecs)); assert_config_entry_value(_repo, "remote.just/renamed.fetch", "+refs/*:refs/*"); } void test_network_remote_rename__new_name_can_contain_dots(void) { cl_git_pass(git_remote_rename(_remote, "just.renamed", dont_call_me_cb, NULL)); cl_assert_equal_s("just.renamed", git_remote_name(_remote)); } void test_network_remote_rename__new_name_must_conform_to_reference_naming_conventions(void) { cl_assert_equal_i( GIT_EINVALIDSPEC, git_remote_rename(_remote, "new@{name", dont_call_me_cb, NULL)); } void test_network_remote_rename__renamed_name_is_persisted(void) { git_remote *renamed; git_repository *another_repo; cl_git_fail(git_remote_load(&renamed, _repo, "just/renamed")); cl_git_pass(git_remote_rename(_remote, "just/renamed", dont_call_me_cb, NULL)); cl_git_pass(git_repository_open(&another_repo, "testrepo.git")); cl_git_pass(git_remote_load(&renamed, _repo, "just/renamed")); git_remote_free(renamed); git_repository_free(another_repo); } void test_network_remote_rename__cannot_overwrite_an_existing_remote(void) { cl_assert_equal_i(GIT_EEXISTS, git_remote_rename(_remote, "test", dont_call_me_cb, NULL)); cl_assert_equal_i(GIT_EEXISTS, git_remote_rename(_remote, "test_with_pushurl", dont_call_me_cb, NULL)); } void test_network_remote_rename__renaming_a_remote_moves_the_underlying_reference(void) { git_reference *underlying; cl_assert_equal_i(GIT_ENOTFOUND, git_reference_lookup(&underlying, _repo, "refs/remotes/just/renamed")); cl_git_pass(git_reference_lookup(&underlying, _repo, "refs/remotes/test/master")); git_reference_free(underlying); cl_git_pass(git_remote_rename(_remote, "just/renamed", dont_call_me_cb, NULL)); cl_assert_equal_i(GIT_ENOTFOUND, git_reference_lookup(&underlying, _repo, "refs/remotes/test/master")); cl_git_pass(git_reference_lookup(&underlying, _repo, "refs/remotes/just/renamed/master")); git_reference_free(underlying); } void test_network_remote_rename__cannot_rename_an_inmemory_remote(void) { git_remote *remote; cl_git_pass(git_remote_create_inmemory(&remote, _repo, NULL, "file:///blah")); cl_git_fail(git_remote_rename(remote, "newname", NULL, NULL)); git_remote_free(remote); } libgit2-0.19.0/tests-clar/network/urlparse.c000066400000000000000000000044101216214232500207050ustar00rootroot00000000000000#include "clar_libgit2.h" #include "netops.h" char *host, *port, *user, *pass; void test_network_urlparse__initialize(void) { host = port = user = pass = NULL; } void test_network_urlparse__cleanup(void) { #define FREE_AND_NULL(x) if (x) { git__free(x); x = NULL; } FREE_AND_NULL(host); FREE_AND_NULL(port); FREE_AND_NULL(user); FREE_AND_NULL(pass); } void test_network_urlparse__trivial(void) { cl_git_pass(gitno_extract_url_parts(&host, &port, &user, &pass, "example.com/resource", "8080")); cl_assert_equal_s(host, "example.com"); cl_assert_equal_s(port, "8080"); cl_assert_equal_p(user, NULL); cl_assert_equal_p(pass, NULL); } void test_network_urlparse__user(void) { cl_git_pass(gitno_extract_url_parts(&host, &port, &user, &pass, "user@example.com/resource", "8080")); cl_assert_equal_s(host, "example.com"); cl_assert_equal_s(port, "8080"); cl_assert_equal_s(user, "user"); cl_assert_equal_p(pass, NULL); } void test_network_urlparse__user_pass(void) { /* user:pass@hostname.tld/resource */ cl_git_pass(gitno_extract_url_parts(&host, &port, &user, &pass, "user:pass@example.com/resource", "8080")); cl_assert_equal_s(host, "example.com"); cl_assert_equal_s(port, "8080"); cl_assert_equal_s(user, "user"); cl_assert_equal_s(pass, "pass"); } void test_network_urlparse__port(void) { /* hostname.tld:port/resource */ cl_git_pass(gitno_extract_url_parts(&host, &port, &user, &pass, "example.com:9191/resource", "8080")); cl_assert_equal_s(host, "example.com"); cl_assert_equal_s(port, "9191"); cl_assert_equal_p(user, NULL); cl_assert_equal_p(pass, NULL); } void test_network_urlparse__user_port(void) { /* user@hostname.tld:port/resource */ cl_git_pass(gitno_extract_url_parts(&host, &port, &user, &pass, "user@example.com:9191/resource", "8080")); cl_assert_equal_s(host, "example.com"); cl_assert_equal_s(port, "9191"); cl_assert_equal_s(user, "user"); cl_assert_equal_p(pass, NULL); } void test_network_urlparse__user_pass_port(void) { /* user:pass@hostname.tld:port/resource */ cl_git_pass(gitno_extract_url_parts(&host, &port, &user, &pass, "user:pass@example.com:9191/resource", "8080")); cl_assert_equal_s(host, "example.com"); cl_assert_equal_s(port, "9191"); cl_assert_equal_s(user, "user"); cl_assert_equal_s(pass, "pass"); } libgit2-0.19.0/tests-clar/notes/000077500000000000000000000000001216214232500163445ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/notes/notes.c000066400000000000000000000331341216214232500176440ustar00rootroot00000000000000#include "clar_libgit2.h" static git_repository *_repo; static git_signature *_sig; void test_notes_notes__initialize(void) { _repo = cl_git_sandbox_init("testrepo.git"); cl_git_pass(git_signature_now(&_sig, "alice", "alice@example.com")); } void test_notes_notes__cleanup(void) { git_signature_free(_sig); _sig = NULL; cl_git_sandbox_cleanup(); } static void assert_note_equal(git_note *note, char *message, git_oid *note_oid) { git_blob *blob; cl_assert_equal_s(git_note_message(note), message); cl_assert(!git_oid_cmp(git_note_oid(note), note_oid)); cl_git_pass(git_blob_lookup(&blob, _repo, note_oid)); cl_assert_equal_s(git_note_message(note), (const char *)git_blob_rawcontent(blob)); git_blob_free(blob); } static void create_note(git_oid *note_oid, const char *canonical_namespace, const char *target_sha, const char *message) { git_oid oid; cl_git_pass(git_oid_fromstr(&oid, target_sha)); cl_git_pass(git_note_create(note_oid, _repo, _sig, _sig, canonical_namespace, &oid, message, 0)); } static struct { const char *note_sha; const char *annotated_object_sha; } list_expectations[] = { { "1c73b1f51762155d357bcd1fd4f2c409ef80065b", "4a202b346bb0fb0db7eff3cffeb3c70babbd2045" }, { "1c73b1f51762155d357bcd1fd4f2c409ef80065b", "9fd738e8f7967c078dceed8190330fc8648ee56a" }, { "257b43746b6b46caa4aa788376c647cce0a33e2b", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750" }, { "1ec1c8e03f461f4f5d3f3702172483662e7223f3", "c47800c7266a2be04c571c04d5a6614691ea99bd" }, { NULL, NULL } }; #define EXPECTATIONS_COUNT (sizeof(list_expectations)/sizeof(list_expectations[0])) - 1 static int note_list_cb( const git_oid *blob_id, const git_oid *annotated_obj_id, void *payload) { git_oid expected_note_oid, expected_target_oid; unsigned int *count = (unsigned int *)payload; cl_assert(*count < EXPECTATIONS_COUNT); cl_git_pass(git_oid_fromstr(&expected_note_oid, list_expectations[*count].note_sha)); cl_assert(git_oid_cmp(&expected_note_oid, blob_id) == 0); cl_git_pass(git_oid_fromstr(&expected_target_oid, list_expectations[*count].annotated_object_sha)); cl_assert(git_oid_cmp(&expected_target_oid, annotated_obj_id) == 0); (*count)++; return 0; } /* * $ git notes --ref i-can-see-dead-notes add -m "I decorate a65f" a65fedf39aefe402d3bb6e24df4d4f5fe4547750 * $ git notes --ref i-can-see-dead-notes add -m "I decorate c478" c47800c7266a2be04c571c04d5a6614691ea99bd * $ git notes --ref i-can-see-dead-notes add -m "I decorate 9fd7 and 4a20" 9fd738e8f7967c078dceed8190330fc8648ee56a * $ git notes --ref i-can-see-dead-notes add -m "I decorate 9fd7 and 4a20" 4a202b346bb0fb0db7eff3cffeb3c70babbd2045 * * $ git notes --ref i-can-see-dead-notes list * 1c73b1f51762155d357bcd1fd4f2c409ef80065b 4a202b346bb0fb0db7eff3cffeb3c70babbd2045 * 1c73b1f51762155d357bcd1fd4f2c409ef80065b 9fd738e8f7967c078dceed8190330fc8648ee56a * 257b43746b6b46caa4aa788376c647cce0a33e2b a65fedf39aefe402d3bb6e24df4d4f5fe4547750 * 1ec1c8e03f461f4f5d3f3702172483662e7223f3 c47800c7266a2be04c571c04d5a6614691ea99bd * * $ git ls-tree refs/notes/i-can-see-dead-notes * 100644 blob 1c73b1f51762155d357bcd1fd4f2c409ef80065b 4a202b346bb0fb0db7eff3cffeb3c70babbd2045 * 100644 blob 1c73b1f51762155d357bcd1fd4f2c409ef80065b 9fd738e8f7967c078dceed8190330fc8648ee56a * 100644 blob 257b43746b6b46caa4aa788376c647cce0a33e2b a65fedf39aefe402d3bb6e24df4d4f5fe4547750 * 100644 blob 1ec1c8e03f461f4f5d3f3702172483662e7223f3 c47800c7266a2be04c571c04d5a6614691ea99bd */ void test_notes_notes__can_retrieve_a_list_of_notes_for_a_given_namespace(void) { git_oid note_oid1, note_oid2, note_oid3, note_oid4; unsigned int retrieved_notes = 0; create_note(¬e_oid1, "refs/notes/i-can-see-dead-notes", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750", "I decorate a65f\n"); create_note(¬e_oid2, "refs/notes/i-can-see-dead-notes", "c47800c7266a2be04c571c04d5a6614691ea99bd", "I decorate c478\n"); create_note(¬e_oid3, "refs/notes/i-can-see-dead-notes", "9fd738e8f7967c078dceed8190330fc8648ee56a", "I decorate 9fd7 and 4a20\n"); create_note(¬e_oid4, "refs/notes/i-can-see-dead-notes", "4a202b346bb0fb0db7eff3cffeb3c70babbd2045", "I decorate 9fd7 and 4a20\n"); cl_git_pass(git_note_foreach (_repo, "refs/notes/i-can-see-dead-notes", note_list_cb, &retrieved_notes)); cl_assert_equal_i(4, retrieved_notes); } static int note_cancel_cb( const git_oid *blob_id, const git_oid *annotated_obj_id, void *payload) { unsigned int *count = (unsigned int *)payload; GIT_UNUSED(blob_id); GIT_UNUSED(annotated_obj_id); (*count)++; return (*count > 2); } void test_notes_notes__can_cancel_foreach(void) { git_oid note_oid1, note_oid2, note_oid3, note_oid4; unsigned int retrieved_notes = 0; create_note(¬e_oid1, "refs/notes/i-can-see-dead-notes", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750", "I decorate a65f\n"); create_note(¬e_oid2, "refs/notes/i-can-see-dead-notes", "c47800c7266a2be04c571c04d5a6614691ea99bd", "I decorate c478\n"); create_note(¬e_oid3, "refs/notes/i-can-see-dead-notes", "9fd738e8f7967c078dceed8190330fc8648ee56a", "I decorate 9fd7 and 4a20\n"); create_note(¬e_oid4, "refs/notes/i-can-see-dead-notes", "4a202b346bb0fb0db7eff3cffeb3c70babbd2045", "I decorate 9fd7 and 4a20\n"); cl_assert_equal_i( GIT_EUSER, git_note_foreach(_repo, "refs/notes/i-can-see-dead-notes", note_cancel_cb, &retrieved_notes)); } void test_notes_notes__retrieving_a_list_of_notes_for_an_unknown_namespace_returns_ENOTFOUND(void) { int error; unsigned int retrieved_notes = 0; error = git_note_foreach(_repo, "refs/notes/i-am-not", note_list_cb, &retrieved_notes); cl_git_fail(error); cl_assert_equal_i(GIT_ENOTFOUND, error); cl_assert_equal_i(0, retrieved_notes); } void test_notes_notes__inserting_a_note_without_passing_a_namespace_uses_the_default_namespace(void) { git_oid note_oid, target_oid; git_note *note, *default_namespace_note; const char *default_ref; cl_git_pass(git_oid_fromstr(&target_oid, "08b041783f40edfe12bb406c9c9a8a040177c125")); cl_git_pass(git_note_default_ref(&default_ref, _repo)); create_note(¬e_oid, NULL, "08b041783f40edfe12bb406c9c9a8a040177c125", "hello world\n"); cl_git_pass(git_note_read(¬e, _repo, NULL, &target_oid)); cl_git_pass(git_note_read(&default_namespace_note, _repo, default_ref, &target_oid)); assert_note_equal(note, "hello world\n", ¬e_oid); assert_note_equal(default_namespace_note, "hello world\n", ¬e_oid); git_note_free(note); git_note_free(default_namespace_note); } void test_notes_notes__can_insert_a_note_with_a_custom_namespace(void) { git_oid note_oid, target_oid; git_note *note; cl_git_pass(git_oid_fromstr(&target_oid, "08b041783f40edfe12bb406c9c9a8a040177c125")); create_note(¬e_oid, "refs/notes/some/namespace", "08b041783f40edfe12bb406c9c9a8a040177c125", "hello world on a custom namespace\n"); cl_git_pass(git_note_read(¬e, _repo, "refs/notes/some/namespace", &target_oid)); assert_note_equal(note, "hello world on a custom namespace\n", ¬e_oid); git_note_free(note); } /* * $ git notes --ref fanout list 8496071c1b46c854b31185ea97743be6a8774479 * 08b041783f40edfe12bb406c9c9a8a040177c125 */ void test_notes_notes__creating_a_note_on_a_target_which_already_has_one_returns_EEXISTS(void) { int error; git_oid note_oid, target_oid; cl_git_pass(git_oid_fromstr(&target_oid, "08b041783f40edfe12bb406c9c9a8a040177c125")); create_note(¬e_oid, NULL, "08b041783f40edfe12bb406c9c9a8a040177c125", "hello world\n"); error = git_note_create(¬e_oid, _repo, _sig, _sig, NULL, &target_oid, "hello world\n", 0); cl_git_fail(error); cl_assert_equal_i(GIT_EEXISTS, error); create_note(¬e_oid, "refs/notes/some/namespace", "08b041783f40edfe12bb406c9c9a8a040177c125", "hello world\n"); error = git_note_create(¬e_oid, _repo, _sig, _sig, "refs/notes/some/namespace", &target_oid, "hello world\n", 0); cl_git_fail(error); cl_assert_equal_i(GIT_EEXISTS, error); } void test_notes_notes__creating_a_note_on_a_target_can_overwrite_existing_note(void) { git_oid note_oid, target_oid; git_note *note, *namespace_note; cl_git_pass(git_oid_fromstr(&target_oid, "08b041783f40edfe12bb406c9c9a8a040177c125")); create_note(¬e_oid, NULL, "08b041783f40edfe12bb406c9c9a8a040177c125", "hello old world\n"); cl_git_pass(git_note_create(¬e_oid, _repo, _sig, _sig, NULL, &target_oid, "hello new world\n", 1)); cl_git_pass(git_note_read(¬e, _repo, NULL, &target_oid)); assert_note_equal(note, "hello new world\n", ¬e_oid); create_note(¬e_oid, "refs/notes/some/namespace", "08b041783f40edfe12bb406c9c9a8a040177c125", "hello old world\n"); cl_git_pass(git_note_create(¬e_oid, _repo, _sig, _sig, "refs/notes/some/namespace", &target_oid, "hello new ref world\n", 1)); cl_git_pass(git_note_read(&namespace_note, _repo, "refs/notes/some/namespace", &target_oid)); assert_note_equal(namespace_note, "hello new ref world\n", ¬e_oid); git_note_free(note); git_note_free(namespace_note); } static char *messages[] = { "08c041783f40edfe12bb406c9c9a8a040177c125", "96c45fbe09ab7445fc7c60fd8d17f32494399343", "48cc7e38dcfc1ec87e70ec03e08c3e83d7a16aa1", "24c3eaafb681c3df668f9df96f58e7b8c756eb04", "96ca1b6ccc7858ae94684777f85ac0e7447f7040", "7ac2db4378a08bb244a427c357e0082ee0d57ac6", "e6cba23dbf4ef84fe35e884f017f4e24dc228572", "c8cf3462c7d8feba716deeb2ebe6583bd54589e2", "39c16b9834c2d665ac5f68ad91dc5b933bad8549", "f3c582b1397df6a664224ebbaf9d4cc952706597", "29cec67037fe8e89977474988219016ae7f342a6", "36c4cd238bf8e82e27b740e0741b025f2e8c79ab", "f1c45a47c02e01d5a9a326f1d9f7f756373387f8", "4aca84406f5daee34ab513a60717c8d7b1763ead", "84ce167da452552f63ed8407b55d5ece4901845f", NULL }; #define MESSAGES_COUNT (sizeof(messages)/sizeof(messages[0])) - 1 /* * $ git ls-tree refs/notes/fanout * 040000 tree 4b22b35d44b5a4f589edf3dc89196399771796ea 84 * * $ git ls-tree 4b22b35 * 040000 tree d71aab4f9b04b45ce09bcaa636a9be6231474759 96 * * $ git ls-tree d71aab4 * 100644 blob 08b041783f40edfe12bb406c9c9a8a040177c125 071c1b46c854b31185ea97743be6a8774479 */ void test_notes_notes__can_insert_a_note_in_an_existing_fanout(void) { size_t i; git_oid note_oid, target_oid; git_note *_note; cl_git_pass(git_oid_fromstr(&target_oid, "08b041783f40edfe12bb406c9c9a8a040177c125")); for (i = 0; i < MESSAGES_COUNT; i++) { cl_git_pass(git_note_create(¬e_oid, _repo, _sig, _sig, "refs/notes/fanout", &target_oid, messages[i], 0)); cl_git_pass(git_note_read(&_note, _repo, "refs/notes/fanout", &target_oid)); git_note_free(_note); git_oid_cpy(&target_oid, ¬e_oid); } } /* * $ git notes --ref fanout list 8496071c1b46c854b31185ea97743be6a8774479 * 08b041783f40edfe12bb406c9c9a8a040177c125 */ void test_notes_notes__can_read_a_note_in_an_existing_fanout(void) { git_oid note_oid, target_oid; git_note *note; cl_git_pass(git_oid_fromstr(&target_oid, "8496071c1b46c854b31185ea97743be6a8774479")); cl_git_pass(git_note_read(¬e, _repo, "refs/notes/fanout", &target_oid)); cl_git_pass(git_oid_fromstr(¬e_oid, "08b041783f40edfe12bb406c9c9a8a040177c125")); cl_assert(!git_oid_cmp(git_note_oid(note), ¬e_oid)); git_note_free(note); } void test_notes_notes__can_remove_a_note_in_an_existing_fanout(void) { git_oid target_oid; git_note *note; cl_git_pass(git_oid_fromstr(&target_oid, "8496071c1b46c854b31185ea97743be6a8774479")); cl_git_pass(git_note_remove(_repo, "refs/notes/fanout", _sig, _sig, &target_oid)); cl_git_fail(git_note_read(¬e, _repo, "refs/notes/fanout", &target_oid)); } void test_notes_notes__removing_a_note_which_doesnt_exists_returns_ENOTFOUND(void) { int error; git_oid target_oid; cl_git_pass(git_oid_fromstr(&target_oid, "8496071c1b46c854b31185ea97743be6a8774479")); cl_git_pass(git_note_remove(_repo, "refs/notes/fanout", _sig, _sig, &target_oid)); error = git_note_remove(_repo, "refs/notes/fanout", _sig, _sig, &target_oid); cl_git_fail(error); cl_assert_equal_i(GIT_ENOTFOUND, error); } void test_notes_notes__can_iterate_default_namespace(void) { git_note_iterator *iter; git_note *note; git_oid note_id, annotated_id; git_oid note_created[2]; const char* note_message[] = { "I decorate a65f\n", "I decorate c478\n" }; int i, err; create_note(¬e_created[0], "refs/notes/commits", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750", note_message[0]); create_note(¬e_created[1], "refs/notes/commits", "c47800c7266a2be04c571c04d5a6614691ea99bd", note_message[1]); cl_git_pass(git_note_iterator_new(&iter, _repo, NULL)); for (i = 0; (err = git_note_next(¬e_id, &annotated_id, iter)) >= 0; ++i) { cl_git_pass(git_note_read(¬e, _repo, NULL, &annotated_id)); cl_assert_equal_s(git_note_message(note), note_message[i]); git_note_free(note); } cl_assert_equal_i(GIT_ITEROVER, err); cl_assert_equal_i(2, i); git_note_iterator_free(iter); } void test_notes_notes__can_iterate_custom_namespace(void) { git_note_iterator *iter; git_note *note; git_oid note_id, annotated_id; git_oid note_created[2]; const char* note_message[] = { "I decorate a65f\n", "I decorate c478\n" }; int i, err; create_note(¬e_created[0], "refs/notes/beer", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750", note_message[0]); create_note(¬e_created[1], "refs/notes/beer", "c47800c7266a2be04c571c04d5a6614691ea99bd", note_message[1]); cl_git_pass(git_note_iterator_new(&iter, _repo, "refs/notes/beer")); for (i = 0; (err = git_note_next(¬e_id, &annotated_id, iter)) >= 0; ++i) { cl_git_pass(git_note_read(¬e, _repo, "refs/notes/beer", &annotated_id)); cl_assert_equal_s(git_note_message(note), note_message[i]); git_note_free(note); } cl_assert_equal_i(GIT_ITEROVER, err); cl_assert_equal_i(2, i); git_note_iterator_free(iter); } void test_notes_notes__empty_iterate(void) { git_note_iterator *iter; cl_git_fail(git_note_iterator_new(&iter, _repo, "refs/notes/commits")); } libgit2-0.19.0/tests-clar/notes/notesref.c000066400000000000000000000033231216214232500203360ustar00rootroot00000000000000#include "clar_libgit2.h" #include "notes.h" static git_repository *_repo; static git_note *_note; static git_signature *_sig; static git_config *_cfg; void test_notes_notesref__initialize(void) { cl_fixture_sandbox("testrepo.git"); cl_git_pass(git_repository_open(&_repo, "testrepo.git")); } void test_notes_notesref__cleanup(void) { git_note_free(_note); _note = NULL; git_signature_free(_sig); _sig = NULL; git_config_free(_cfg); _cfg = NULL; git_repository_free(_repo); _repo = NULL; cl_fixture_cleanup("testrepo.git"); } void test_notes_notesref__config_corenotesref(void) { git_oid oid, note_oid; const char *default_ref; cl_git_pass(git_signature_now(&_sig, "alice", "alice@example.com")); cl_git_pass(git_oid_fromstr(&oid, "8496071c1b46c854b31185ea97743be6a8774479")); cl_git_pass(git_repository_config(&_cfg, _repo)); cl_git_pass(git_config_set_string(_cfg, "core.notesRef", "refs/notes/mydefaultnotesref")); cl_git_pass(git_note_create(¬e_oid, _repo, _sig, _sig, NULL, &oid, "test123test\n", 0)); cl_git_pass(git_note_read(&_note, _repo, NULL, &oid)); cl_assert_equal_s("test123test\n", git_note_message(_note)); cl_assert(!git_oid_cmp(git_note_oid(_note), ¬e_oid)); git_note_free(_note); cl_git_pass(git_note_read(&_note, _repo, "refs/notes/mydefaultnotesref", &oid)); cl_assert_equal_s("test123test\n", git_note_message(_note)); cl_assert(!git_oid_cmp(git_note_oid(_note), ¬e_oid)); cl_git_pass(git_note_default_ref(&default_ref, _repo)); cl_assert_equal_s("refs/notes/mydefaultnotesref", default_ref); cl_git_pass(git_config_delete_entry(_cfg, "core.notesRef")); cl_git_pass(git_note_default_ref(&default_ref, _repo)); cl_assert_equal_s(GIT_NOTES_DEFAULT_REF, default_ref); } libgit2-0.19.0/tests-clar/object/000077500000000000000000000000001216214232500164625ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/object/blob/000077500000000000000000000000001216214232500174005ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/object/blob/filter.c000066400000000000000000000066311216214232500210370ustar00rootroot00000000000000#include "clar_libgit2.h" #include "posix.h" #include "blob.h" #include "filter.h" #include "buf_text.h" static git_repository *g_repo = NULL; #define NUM_TEST_OBJECTS 8 static git_oid g_oids[NUM_TEST_OBJECTS]; static const char *g_raw[NUM_TEST_OBJECTS] = { "", "foo\nbar\n", "foo\rbar\r", "foo\r\nbar\r\n", "foo\nbar\rboth\r\nreversed\n\ragain\nproblems\r", "123\n\000\001\002\003\004abc\255\254\253\r\n", "\xEF\xBB\xBFThis is UTF-8\n", "\xFE\xFF\x00T\x00h\x00i\x00s\x00!" }; static git_off_t g_len[NUM_TEST_OBJECTS] = { -1, -1, -1, -1, -1, 17, -1, 12 }; static git_buf_text_stats g_stats[NUM_TEST_OBJECTS] = { { 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 2, 0, 6, 0 }, { 0, 0, 2, 0, 0, 6, 0 }, { 0, 0, 2, 2, 2, 6, 0 }, { 0, 0, 4, 4, 1, 31, 0 }, { 0, 1, 1, 2, 1, 9, 5 }, { GIT_BOM_UTF8, 0, 0, 1, 0, 16, 0 }, { GIT_BOM_UTF16_BE, 5, 0, 0, 0, 7, 5 }, }; static git_buf g_crlf_filtered[NUM_TEST_OBJECTS] = { { "", 0, 0 }, { "foo\nbar\n", 0, 8 }, { "foo\rbar\r", 0, 8 }, { "foo\nbar\n", 0, 8 }, { "foo\nbar\rboth\nreversed\n\ragain\nproblems\r", 0, 38 }, { "123\n\000\001\002\003\004abc\255\254\253\n", 0, 16 }, { "\xEF\xBB\xBFThis is UTF-8\n", 0, 17 }, { "\xFE\xFF\x00T\x00h\x00i\x00s\x00!", 0, 12 } }; void test_object_blob_filter__initialize(void) { int i; cl_fixture_sandbox("empty_standard_repo"); cl_git_pass(p_rename( "empty_standard_repo/.gitted", "empty_standard_repo/.git")); cl_git_pass(git_repository_open(&g_repo, "empty_standard_repo")); for (i = 0; i < NUM_TEST_OBJECTS; i++) { size_t len = (g_len[i] < 0) ? strlen(g_raw[i]) : (size_t)g_len[i]; g_len[i] = (git_off_t)len; cl_git_pass( git_blob_create_frombuffer(&g_oids[i], g_repo, g_raw[i], len) ); } } void test_object_blob_filter__cleanup(void) { git_repository_free(g_repo); g_repo = NULL; cl_fixture_cleanup("empty_standard_repo"); } void test_object_blob_filter__unfiltered(void) { int i; git_blob *blob; for (i = 0; i < NUM_TEST_OBJECTS; i++) { cl_git_pass(git_blob_lookup(&blob, g_repo, &g_oids[i])); cl_assert(g_len[i] == git_blob_rawsize(blob)); cl_assert(memcmp(git_blob_rawcontent(blob), g_raw[i], (size_t)g_len[i]) == 0); git_blob_free(blob); } } void test_object_blob_filter__stats(void) { int i; git_blob *blob; git_buf buf = GIT_BUF_INIT; git_buf_text_stats stats; for (i = 0; i < NUM_TEST_OBJECTS; i++) { cl_git_pass(git_blob_lookup(&blob, g_repo, &g_oids[i])); cl_git_pass(git_blob__getbuf(&buf, blob)); git_buf_text_gather_stats(&stats, &buf, false); cl_assert(memcmp(&g_stats[i], &stats, sizeof(stats)) == 0); git_blob_free(blob); } git_buf_free(&buf); } void test_object_blob_filter__to_odb(void) { git_vector filters = GIT_VECTOR_INIT; git_config *cfg; int i; git_blob *blob; git_buf orig = GIT_BUF_INIT, out = GIT_BUF_INIT; cl_git_pass(git_repository_config(&cfg, g_repo)); cl_assert(cfg); git_attr_cache_flush(g_repo); cl_git_append2file("empty_standard_repo/.gitattributes", "*.txt text\n"); cl_assert(git_filters_load( &filters, g_repo, "filename.txt", GIT_FILTER_TO_ODB) > 0); cl_assert(filters.length == 1); for (i = 0; i < NUM_TEST_OBJECTS; i++) { cl_git_pass(git_blob_lookup(&blob, g_repo, &g_oids[i])); cl_git_pass(git_blob__getbuf(&orig, blob)); cl_git_pass(git_filters_apply(&out, &orig, &filters)); cl_assert(git_buf_cmp(&out, &g_crlf_filtered[i]) == 0); git_blob_free(blob); } git_filters_free(&filters); git_buf_free(&orig); git_buf_free(&out); git_config_free(cfg); } libgit2-0.19.0/tests-clar/object/blob/fromchunks.c000066400000000000000000000044411216214232500217260ustar00rootroot00000000000000#include "clar_libgit2.h" #include "buffer.h" #include "posix.h" #include "path.h" #include "fileops.h" static git_repository *repo; static char textual_content[] = "libgit2\n\r\n\0"; void test_object_blob_fromchunks__initialize(void) { repo = cl_git_sandbox_init("testrepo.git"); } void test_object_blob_fromchunks__cleanup(void) { cl_git_sandbox_cleanup(); } static int text_chunked_source_cb(char *content, size_t max_length, void *payload) { int *count; GIT_UNUSED(max_length); count = (int *)payload; (*count)--; if (*count == 0) return 0; strcpy(content, textual_content); return (int)strlen(textual_content); } void test_object_blob_fromchunks__can_create_a_blob_from_a_in_memory_chunk_provider(void) { git_oid expected_oid, oid; git_object *blob; int howmany = 7; cl_git_pass(git_oid_fromstr(&expected_oid, "321cbdf08803c744082332332838df6bd160f8f9")); cl_git_fail(git_object_lookup(&blob, repo, &expected_oid, GIT_OBJ_ANY)); cl_git_pass(git_blob_create_fromchunks(&oid, repo, NULL, text_chunked_source_cb, &howmany)); cl_git_pass(git_object_lookup(&blob, repo, &expected_oid, GIT_OBJ_ANY)); git_object_free(blob); } #define GITATTR "* text=auto\n" \ "*.txt text\n" \ "*.data binary\n" static void write_attributes(git_repository *repo) { git_buf buf = GIT_BUF_INIT; cl_git_pass(git_buf_joinpath(&buf, git_repository_path(repo), "info")); cl_git_pass(git_buf_joinpath(&buf, git_buf_cstr(&buf), "attributes")); cl_git_pass(git_futils_mkpath2file(git_buf_cstr(&buf), 0777)); cl_git_rewritefile(git_buf_cstr(&buf), GITATTR); git_buf_free(&buf); } static void assert_named_chunked_blob(const char *expected_sha, const char *fake_name) { git_oid expected_oid, oid; int howmany = 7; cl_git_pass(git_oid_fromstr(&expected_oid, expected_sha)); cl_git_pass(git_blob_create_fromchunks(&oid, repo, fake_name, text_chunked_source_cb, &howmany)); cl_assert(git_oid_cmp(&expected_oid, &oid) == 0); } void test_object_blob_fromchunks__creating_a_blob_from_chunks_honors_the_attributes_directives(void) { write_attributes(repo); assert_named_chunked_blob("321cbdf08803c744082332332838df6bd160f8f9", "dummy.data"); assert_named_chunked_blob("e9671e138a780833cb689753570fd10a55be84fb", "dummy.txt"); assert_named_chunked_blob("e9671e138a780833cb689753570fd10a55be84fb", "dummy.dunno"); } libgit2-0.19.0/tests-clar/object/blob/write.c000066400000000000000000000040541216214232500207010ustar00rootroot00000000000000#include "clar_libgit2.h" #include "buffer.h" #include "posix.h" #include "path.h" #include "fileops.h" static git_repository *repo; #define WORKDIR "empty_standard_repo" #define BARE_REPO "testrepo.git" #define ELSEWHERE "elsewhere" typedef int (*blob_creator_fn)( git_oid *, git_repository *, const char *); void test_object_blob_write__cleanup(void) { cl_git_sandbox_cleanup(); } static void assert_blob_creation(const char *path_to_file, const char *blob_from_path, blob_creator_fn creator) { git_oid oid; cl_git_mkfile(path_to_file, "1..2...3... Can you hear me?\n"); cl_must_pass(creator(&oid, repo, blob_from_path)); cl_assert(git_oid_streq(&oid, "da5e4f20c91c81b44a7e298f3d3fb3fe2f178e32") == 0); } void test_object_blob_write__can_create_a_blob_in_a_standard_repo_from_a_file_located_in_the_working_directory(void) { repo = cl_git_sandbox_init(WORKDIR); assert_blob_creation(WORKDIR "/test.txt", "test.txt", &git_blob_create_fromworkdir); } void test_object_blob_write__can_create_a_blob_in_a_standard_repo_from_a_absolute_filepath_pointing_outside_of_the_working_directory(void) { git_buf full_path = GIT_BUF_INIT; repo = cl_git_sandbox_init(WORKDIR); cl_must_pass(p_mkdir(ELSEWHERE, 0777)); cl_must_pass(git_path_prettify_dir(&full_path, ELSEWHERE, NULL)); cl_must_pass(git_buf_puts(&full_path, "test.txt")); assert_blob_creation(ELSEWHERE "/test.txt", git_buf_cstr(&full_path), &git_blob_create_fromdisk); git_buf_free(&full_path); cl_must_pass(git_futils_rmdir_r(ELSEWHERE, NULL, GIT_RMDIR_REMOVE_FILES)); } void test_object_blob_write__can_create_a_blob_in_a_bare_repo_from_a_absolute_filepath(void) { git_buf full_path = GIT_BUF_INIT; repo = cl_git_sandbox_init(BARE_REPO); cl_must_pass(p_mkdir(ELSEWHERE, 0777)); cl_must_pass(git_path_prettify_dir(&full_path, ELSEWHERE, NULL)); cl_must_pass(git_buf_puts(&full_path, "test.txt")); assert_blob_creation(ELSEWHERE "/test.txt", git_buf_cstr(&full_path), &git_blob_create_fromdisk); git_buf_free(&full_path); cl_must_pass(git_futils_rmdir_r(ELSEWHERE, NULL, GIT_RMDIR_REMOVE_FILES)); } libgit2-0.19.0/tests-clar/object/cache.c000066400000000000000000000167111216214232500176770ustar00rootroot00000000000000#include "clar_libgit2.h" #include "repository.h" static git_repository *g_repo; void test_object_cache__initialize(void) { g_repo = NULL; } void test_object_cache__cleanup(void) { git_repository_free(g_repo); g_repo = NULL; git_libgit2_opts(GIT_OPT_SET_CACHE_OBJECT_LIMIT, (int)GIT_OBJ_BLOB, (size_t)0); } static struct { git_otype type; const char *sha; } g_data[] = { /* HEAD */ { GIT_OBJ_BLOB, "a8233120f6ad708f843d861ce2b7228ec4e3dec6" }, /* README */ { GIT_OBJ_BLOB, "3697d64be941a53d4ae8f6a271e4e3fa56b022cc" }, /* branch_file.txt */ { GIT_OBJ_BLOB, "a71586c1dfe8a71c6cbf6c129f404c5642ff31bd" }, /* new.txt */ /* refs/heads/subtrees */ { GIT_OBJ_BLOB, "1385f264afb75a56a5bec74243be9b367ba4ca08" }, /* README */ { GIT_OBJ_TREE, "f1425cef211cc08caa31e7b545ffb232acb098c3" }, /* ab */ { GIT_OBJ_BLOB, "d6c93164c249c8000205dd4ec5cbca1b516d487f" }, /* ab/4.txt */ { GIT_OBJ_TREE, "9a03079b8a8ee85a0bee58bf9be3da8b62414ed4" }, /* ab/c */ { GIT_OBJ_BLOB, "270b8ea76056d5cad83af921837702d3e3c2924d" }, /* ab/c/3.txt */ { GIT_OBJ_TREE, "b6361fc6a97178d8fc8639fdeed71c775ab52593" }, /* ab/de */ { GIT_OBJ_BLOB, "e7b4ad382349ff96dd8199000580b9b1e2042eb0" }, /* ab/de/2.txt */ { GIT_OBJ_TREE, "3259a6bd5b57fb9c1281bb7ed3167b50f224cb54" }, /* ab/de/fgh */ { GIT_OBJ_BLOB, "1f67fc4386b2d171e0d21be1c447e12660561f9b" }, /* ab/de/fgh/1.txt */ { GIT_OBJ_BLOB, "45b983be36b73c0788dc9cbcb76cbb80fc7bb057" }, /* branch_file.txt */ { GIT_OBJ_BLOB, "fa49b077972391ad58037050f2a75f74e3671e92" }, /* new.txt */ /* refs/heads/chomped */ { GIT_OBJ_BLOB, "0266163a49e280c4f5ed1e08facd36a2bd716bcf" }, /* readme.txt */ { 0, NULL }, { 0, NULL } }; void test_object_cache__cache_everything(void) { int i, start; git_oid oid; git_odb_object *odb_obj; git_object *obj; git_odb *odb; git_libgit2_opts( GIT_OPT_SET_CACHE_OBJECT_LIMIT, (int)GIT_OBJ_BLOB, (size_t)32767); cl_git_pass(git_repository_open(&g_repo, cl_fixture("testrepo.git"))); cl_git_pass(git_repository_odb(&odb, g_repo)); start = (int)git_cache_size(&g_repo->objects); for (i = 0; g_data[i].sha != NULL; ++i) { int count = (int)git_cache_size(&g_repo->objects); cl_git_pass(git_oid_fromstr(&oid, g_data[i].sha)); /* alternate between loading raw and parsed objects */ if ((i & 1) == 0) { cl_git_pass(git_odb_read(&odb_obj, odb, &oid)); cl_assert(g_data[i].type == git_odb_object_type(odb_obj)); git_odb_object_free(odb_obj); } else { cl_git_pass(git_object_lookup(&obj, g_repo, &oid, GIT_OBJ_ANY)); cl_assert(g_data[i].type == git_object_type(obj)); git_object_free(obj); } cl_assert_equal_i(count + 1, (int)git_cache_size(&g_repo->objects)); } cl_assert_equal_i(i, (int)git_cache_size(&g_repo->objects) - start); git_odb_free(odb); for (i = 0; g_data[i].sha != NULL; ++i) { int count = (int)git_cache_size(&g_repo->objects); cl_git_pass(git_oid_fromstr(&oid, g_data[i].sha)); cl_git_pass(git_object_lookup(&obj, g_repo, &oid, GIT_OBJ_ANY)); cl_assert(g_data[i].type == git_object_type(obj)); git_object_free(obj); cl_assert_equal_i(count, (int)git_cache_size(&g_repo->objects)); } } void test_object_cache__cache_no_blobs(void) { int i, start, nonblobs = 0; git_oid oid; git_odb_object *odb_obj; git_object *obj; git_odb *odb; git_libgit2_opts(GIT_OPT_SET_CACHE_OBJECT_LIMIT, (int)GIT_OBJ_BLOB, (size_t)0); cl_git_pass(git_repository_open(&g_repo, cl_fixture("testrepo.git"))); cl_git_pass(git_repository_odb(&odb, g_repo)); start = (int)git_cache_size(&g_repo->objects); for (i = 0; g_data[i].sha != NULL; ++i) { int count = (int)git_cache_size(&g_repo->objects); cl_git_pass(git_oid_fromstr(&oid, g_data[i].sha)); /* alternate between loading raw and parsed objects */ if ((i & 1) == 0) { cl_git_pass(git_odb_read(&odb_obj, odb, &oid)); cl_assert(g_data[i].type == git_odb_object_type(odb_obj)); git_odb_object_free(odb_obj); } else { cl_git_pass(git_object_lookup(&obj, g_repo, &oid, GIT_OBJ_ANY)); cl_assert(g_data[i].type == git_object_type(obj)); git_object_free(obj); } if (g_data[i].type == GIT_OBJ_BLOB) cl_assert_equal_i(count, (int)git_cache_size(&g_repo->objects)); else { cl_assert_equal_i(count + 1, (int)git_cache_size(&g_repo->objects)); nonblobs++; } } cl_assert_equal_i(nonblobs, (int)git_cache_size(&g_repo->objects) - start); git_odb_free(odb); } static void *cache_parsed(void *arg) { int i; git_oid oid; git_object *obj; for (i = ((int *)arg)[1]; g_data[i].sha != NULL; i += 2) { cl_git_pass(git_oid_fromstr(&oid, g_data[i].sha)); cl_git_pass(git_object_lookup(&obj, g_repo, &oid, GIT_OBJ_ANY)); cl_assert(g_data[i].type == git_object_type(obj)); git_object_free(obj); } for (i = 0; i < ((int *)arg)[1]; i += 2) { cl_git_pass(git_oid_fromstr(&oid, g_data[i].sha)); cl_git_pass(git_object_lookup(&obj, g_repo, &oid, GIT_OBJ_ANY)); cl_assert(g_data[i].type == git_object_type(obj)); git_object_free(obj); } return arg; } static void *cache_raw(void *arg) { int i; git_oid oid; git_odb *odb; git_odb_object *odb_obj; cl_git_pass(git_repository_odb(&odb, g_repo)); for (i = ((int *)arg)[1]; g_data[i].sha != NULL; i += 2) { cl_git_pass(git_oid_fromstr(&oid, g_data[i].sha)); cl_git_pass(git_odb_read(&odb_obj, odb, &oid)); cl_assert(g_data[i].type == git_odb_object_type(odb_obj)); git_odb_object_free(odb_obj); } for (i = 0; i < ((int *)arg)[1]; i += 2) { cl_git_pass(git_oid_fromstr(&oid, g_data[i].sha)); cl_git_pass(git_odb_read(&odb_obj, odb, &oid)); cl_assert(g_data[i].type == git_odb_object_type(odb_obj)); git_odb_object_free(odb_obj); } git_odb_free(odb); return arg; } #define REPEAT 20 #define THREADCOUNT 50 void test_object_cache__threadmania(void) { int try, th, max_i; void *data; void *(*fn)(void *); #ifdef GIT_THREADS git_thread t[THREADCOUNT]; #endif for (max_i = 0; g_data[max_i].sha != NULL; ++max_i) /* count up */; for (try = 0; try < REPEAT; ++try) { cl_git_pass(git_repository_open(&g_repo, cl_fixture("testrepo.git"))); for (th = 0; th < THREADCOUNT; ++th) { data = git__malloc(2 * sizeof(int)); ((int *)data)[0] = th; ((int *)data)[1] = th % max_i; fn = (th & 1) ? cache_parsed : cache_raw; #ifdef GIT_THREADS cl_git_pass(git_thread_create(&t[th], NULL, fn, data)); #else cl_assert(fn(data) == data); git__free(data); #endif } #ifdef GIT_THREADS for (th = 0; th < THREADCOUNT; ++th) { cl_git_pass(git_thread_join(t[th], &data)); cl_assert_equal_i(th, ((int *)data)[0]); git__free(data); } #endif git_repository_free(g_repo); g_repo = NULL; } } static void *cache_quick(void *arg) { git_oid oid; git_object *obj; cl_git_pass(git_oid_fromstr(&oid, g_data[4].sha)); cl_git_pass(git_object_lookup(&obj, g_repo, &oid, GIT_OBJ_ANY)); cl_assert(g_data[4].type == git_object_type(obj)); git_object_free(obj); return arg; } void test_object_cache__fast_thread_rush(void) { int try, th, data[THREADCOUNT*2]; #ifdef GIT_THREADS git_thread t[THREADCOUNT*2]; #endif for (try = 0; try < REPEAT; ++try) { cl_git_pass(git_repository_open(&g_repo, cl_fixture("testrepo.git"))); for (th = 0; th < THREADCOUNT*2; ++th) { data[th] = th; #ifdef GIT_THREADS cl_git_pass( git_thread_create(&t[th], NULL, cache_quick, &data[th])); #else cl_assert(cache_quick(&data[th]) == &data[th]); #endif } #ifdef GIT_THREADS for (th = 0; th < THREADCOUNT*2; ++th) { void *rval; cl_git_pass(git_thread_join(t[th], &rval)); cl_assert_equal_i(th, *((int *)rval)); } #endif git_repository_free(g_repo); g_repo = NULL; } } libgit2-0.19.0/tests-clar/object/commit/000077500000000000000000000000001216214232500177525ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/object/commit/commitstagedfile.c000066400000000000000000000066041216214232500234440ustar00rootroot00000000000000#include "clar_libgit2.h" #include "posix.h" static git_repository *repo; void test_object_commit_commitstagedfile__initialize(void) { cl_fixture("treebuilder"); cl_git_pass(git_repository_init(&repo, "treebuilder/", 0)); cl_assert(repo != NULL); } void test_object_commit_commitstagedfile__cleanup(void) { git_repository_free(repo); repo = NULL; cl_fixture_cleanup("treebuilder"); } void test_object_commit_commitstagedfile__generate_predictable_object_ids(void) { git_index *index; const git_index_entry *entry; git_oid expected_blob_oid, tree_oid, expected_tree_oid, commit_oid, expected_commit_oid; git_signature *signature; git_tree *tree; char buffer[128]; /* * The test below replicates the following git scenario * * $ echo "test" > test.txt * $ git hash-object test.txt * 9daeafb9864cf43055ae93beb0afd6c7d144bfa4 * * $ git add . * $ git commit -m "Initial commit" * * $ git log * commit 1fe3126578fc4eca68c193e4a3a0a14a0704624d * Author: nulltoken * Date: Wed Dec 14 08:29:03 2011 +0100 * * Initial commit * * $ git show 1fe3 --format=raw * commit 1fe3126578fc4eca68c193e4a3a0a14a0704624d * tree 2b297e643c551e76cfa1f93810c50811382f9117 * author nulltoken 1323847743 +0100 * committer nulltoken 1323847743 +0100 * * Initial commit * * diff --git a/test.txt b/test.txt * new file mode 100644 * index 0000000..9daeafb * --- /dev/null * +++ b/test.txt * @@ -0,0 +1 @@ * +test * * $ git ls-tree 2b297 * 100644 blob 9daeafb9864cf43055ae93beb0afd6c7d144bfa4 test.txt */ cl_git_pass(git_oid_fromstr(&expected_commit_oid, "1fe3126578fc4eca68c193e4a3a0a14a0704624d")); cl_git_pass(git_oid_fromstr(&expected_tree_oid, "2b297e643c551e76cfa1f93810c50811382f9117")); cl_git_pass(git_oid_fromstr(&expected_blob_oid, "9daeafb9864cf43055ae93beb0afd6c7d144bfa4")); /* * Add a new file to the index */ cl_git_mkfile("treebuilder/test.txt", "test\n"); cl_git_pass(git_repository_index(&index, repo)); cl_git_pass(git_index_add_bypath(index, "test.txt")); entry = git_index_get_byindex(index, 0); cl_assert(git_oid_cmp(&expected_blob_oid, &entry->oid) == 0); /* * Information about index entry should match test file */ { struct stat st; cl_must_pass(p_lstat("treebuilder/test.txt", &st)); cl_assert(entry->file_size == st.st_size); #ifndef _WIN32 /* * Windows doesn't populate these fields, and the signage is * wrong in the Windows version of the struct, so lets avoid * the "comparing signed and unsigned" compilation warning in * that case. */ cl_assert(entry->uid == st.st_uid); cl_assert(entry->gid == st.st_gid); #endif } /* * Build the tree from the index */ cl_git_pass(git_index_write_tree(&tree_oid, index)); cl_assert(git_oid_cmp(&expected_tree_oid, &tree_oid) == 0); /* * Commit the staged file */ cl_git_pass(git_signature_new(&signature, "nulltoken", "emeric.fermas@gmail.com", 1323847743, 60)); cl_git_pass(git_tree_lookup(&tree, repo, &tree_oid)); cl_assert_equal_i(16, git_message_prettify(buffer, 128, "Initial commit", 0)); cl_git_pass(git_commit_create_v( &commit_oid, repo, "HEAD", signature, signature, NULL, buffer, tree, 0)); cl_assert(git_oid_cmp(&expected_commit_oid, &commit_oid) == 0); git_signature_free(signature); git_tree_free(tree); git_index_free(index); } libgit2-0.19.0/tests-clar/object/lookup.c000066400000000000000000000032221216214232500201360ustar00rootroot00000000000000#include "clar_libgit2.h" #include "repository.h" static git_repository *g_repo; void test_object_lookup__initialize(void) { cl_git_pass(git_repository_open(&g_repo, cl_fixture("testrepo.git"))); } void test_object_lookup__cleanup(void) { git_repository_free(g_repo); g_repo = NULL; } void test_object_lookup__lookup_wrong_type_returns_enotfound(void) { const char *commit = "e90810b8df3e80c413d903f631643c716887138d"; git_oid oid; git_object *object; cl_git_pass(git_oid_fromstr(&oid, commit)); cl_assert_equal_i( GIT_ENOTFOUND, git_object_lookup(&object, g_repo, &oid, GIT_OBJ_TAG)); } void test_object_lookup__lookup_nonexisting_returns_enotfound(void) { const char *unknown = "deadbeefdeadbeefdeadbeefdeadbeefdeadbeef"; git_oid oid; git_object *object; cl_git_pass(git_oid_fromstr(&oid, unknown)); cl_assert_equal_i( GIT_ENOTFOUND, git_object_lookup(&object, g_repo, &oid, GIT_OBJ_ANY)); } void test_object_lookup__lookup_wrong_type_by_abbreviated_id_returns_enotfound(void) { const char *commit = "e90810b"; git_oid oid; git_object *object; cl_git_pass(git_oid_fromstrn(&oid, commit, strlen(commit))); cl_assert_equal_i( GIT_ENOTFOUND, git_object_lookup_prefix(&object, g_repo, &oid, strlen(commit), GIT_OBJ_TAG)); } void test_object_lookup__lookup_wrong_type_eventually_returns_enotfound(void) { const char *commit = "e90810b8df3e80c413d903f631643c716887138d"; git_oid oid; git_object *object; cl_git_pass(git_oid_fromstr(&oid, commit)); cl_git_pass(git_object_lookup(&object, g_repo, &oid, GIT_OBJ_COMMIT)); git_object_free(object); cl_assert_equal_i( GIT_ENOTFOUND, git_object_lookup(&object, g_repo, &oid, GIT_OBJ_TAG)); } libgit2-0.19.0/tests-clar/object/message.c000066400000000000000000000255121216214232500202570ustar00rootroot00000000000000#include "clar_libgit2.h" #include "buffer.h" #include "message.h" static void assert_message_prettifying(char *expected_output, char *input, int strip_comments) { git_buf prettified_message = GIT_BUF_INIT; git_message__prettify(&prettified_message, input, strip_comments); cl_assert_equal_s(expected_output, git_buf_cstr(&prettified_message)); git_buf_free(&prettified_message); } #define t40 "A quick brown fox jumps over the lazy do" #define s40 " " #define sss s40 s40 s40 s40 s40 s40 s40 s40 s40 s40 // # 400 #define ttt t40 t40 t40 t40 t40 t40 t40 t40 t40 t40 // # 400 /* Ported from git.git */ /* see https://github.com/git/git/blob/master/t/t0030-stripspace.sh */ void test_object_message__long_lines_without_spaces_should_be_unchanged(void) { assert_message_prettifying(ttt "\n", ttt, 0); assert_message_prettifying(ttt ttt "\n", ttt ttt, 0); assert_message_prettifying(ttt ttt ttt "\n", ttt ttt ttt, 0); assert_message_prettifying(ttt ttt ttt ttt "\n", ttt ttt ttt ttt, 0); } void test_object_message__lines_with_spaces_at_the_beginning_should_be_unchanged(void) { assert_message_prettifying(sss ttt "\n", sss ttt, 0); assert_message_prettifying(sss sss ttt "\n", sss sss ttt, 0); assert_message_prettifying(sss sss sss ttt "\n", sss sss sss ttt, 0); } void test_object_message__lines_with_intermediate_spaces_should_be_unchanged(void) { assert_message_prettifying(ttt sss ttt "\n", ttt sss ttt, 0); assert_message_prettifying(ttt sss sss ttt "\n", ttt sss sss ttt, 0); } void test_object_message__consecutive_blank_lines_should_be_unified(void) { assert_message_prettifying(ttt "\n\n" ttt "\n", ttt "\n\n\n\n\n" ttt "\n", 0); assert_message_prettifying(ttt ttt "\n\n" ttt "\n", ttt ttt "\n\n\n\n\n" ttt "\n", 0); assert_message_prettifying(ttt ttt ttt "\n\n" ttt "\n", ttt ttt ttt "\n\n\n\n\n" ttt "\n", 0); assert_message_prettifying(ttt "\n\n" ttt ttt "\n", ttt "\n\n\n\n\n" ttt ttt "\n", 0); assert_message_prettifying(ttt "\n\n" ttt ttt ttt "\n", ttt "\n\n\n\n\n" ttt ttt ttt "\n", 0); assert_message_prettifying(ttt "\n\n" ttt "\n", ttt "\n\t\n \n\n \t\t\n" ttt "\n", 0); assert_message_prettifying(ttt ttt "\n\n" ttt "\n", ttt ttt "\n\t\n \n\n \t\t\n" ttt "\n", 0); assert_message_prettifying(ttt ttt ttt "\n\n" ttt "\n", ttt ttt ttt "\n\t\n \n\n \t\t\n" ttt "\n", 0); assert_message_prettifying(ttt "\n\n" ttt ttt "\n", ttt "\n\t\n \n\n \t\t\n" ttt ttt "\n", 0); assert_message_prettifying(ttt "\n\n" ttt ttt ttt "\n", ttt "\n\t\n \n\n \t\t\n" ttt ttt ttt "\n", 0); } void test_object_message__only_consecutive_blank_lines_should_be_completely_removed(void) { assert_message_prettifying("", "\n", 0); assert_message_prettifying("", "\n\n\n", 0); assert_message_prettifying("", sss "\n" sss "\n" sss "\n", 0); assert_message_prettifying("", sss sss "\n" sss "\n\n", 0); } void test_object_message__consecutive_blank_lines_at_the_beginning_should_be_removed(void) { assert_message_prettifying(ttt "\n", "\n" ttt "\n", 0); assert_message_prettifying(ttt "\n", "\n\n\n" ttt "\n", 0); assert_message_prettifying(ttt ttt "\n", "\n\n\n" ttt ttt "\n", 0); assert_message_prettifying(ttt ttt ttt "\n", "\n\n\n" ttt ttt ttt "\n", 0); assert_message_prettifying(ttt ttt ttt ttt "\n", "\n\n\n" ttt ttt ttt ttt "\n", 0); assert_message_prettifying(ttt "\n", sss "\n" sss "\n" sss "\n" ttt "\n", 0); assert_message_prettifying(ttt "\n", "\n" sss "\n" sss sss "\n" ttt "\n", 0); assert_message_prettifying(ttt "\n", sss sss "\n" sss "\n\n" ttt "\n", 0); assert_message_prettifying(ttt "\n", sss sss sss "\n\n\n" ttt "\n", 0); assert_message_prettifying(ttt "\n", "\n" sss sss sss "\n\n" ttt "\n", 0); assert_message_prettifying(ttt "\n", "\n\n" sss sss sss "\n" ttt "\n", 0); } void test_object_message__consecutive_blank_lines_at_the_end_should_be_removed(void) { assert_message_prettifying(ttt "\n", ttt "\n\n", 0); assert_message_prettifying(ttt "\n", ttt "\n\n\n\n", 0); assert_message_prettifying(ttt ttt "\n", ttt ttt "\n\n\n\n", 0); assert_message_prettifying(ttt ttt ttt "\n", ttt ttt ttt "\n\n\n\n", 0); assert_message_prettifying(ttt ttt ttt ttt "\n", ttt ttt ttt ttt "\n\n\n\n", 0); assert_message_prettifying(ttt "\n", ttt "\n" sss "\n" sss "\n" sss "\n", 0); assert_message_prettifying(ttt "\n", ttt "\n\n" sss "\n" sss sss "\n", 0); assert_message_prettifying(ttt "\n", ttt "\n" sss sss "\n" sss "\n\n", 0); assert_message_prettifying(ttt "\n", ttt "\n" sss sss sss "\n\n\n", 0); assert_message_prettifying(ttt "\n", ttt "\n\n" sss sss sss "\n\n", 0); assert_message_prettifying(ttt "\n", ttt "\n\n\n" sss sss sss "\n\n", 0); } void test_object_message__text_without_newline_at_end_should_end_with_newline(void) { assert_message_prettifying(ttt "\n", ttt, 0); assert_message_prettifying(ttt ttt "\n", ttt ttt, 0); assert_message_prettifying(ttt ttt ttt "\n", ttt ttt ttt, 0); assert_message_prettifying(ttt ttt ttt ttt "\n", ttt ttt ttt ttt, 0); } void test_object_message__text_plus_spaces_without_newline_should_not_show_spaces_and_end_with_newline(void) { assert_message_prettifying(ttt "\n", ttt sss, 0); assert_message_prettifying(ttt ttt "\n", ttt ttt sss, 0); assert_message_prettifying(ttt ttt ttt "\n", ttt ttt ttt sss, 0); assert_message_prettifying(ttt "\n", ttt sss sss, 0); assert_message_prettifying(ttt ttt "\n", ttt ttt sss sss, 0); assert_message_prettifying(ttt "\n", ttt sss sss sss, 0); } void test_object_message__text_plus_spaces_ending_with_newline_should_be_cleaned_and_newline_must_remain(void){ assert_message_prettifying(ttt "\n", ttt sss "\n", 0); assert_message_prettifying(ttt "\n", ttt sss sss "\n", 0); assert_message_prettifying(ttt "\n", ttt sss sss sss "\n", 0); assert_message_prettifying(ttt ttt "\n", ttt ttt sss "\n", 0); assert_message_prettifying(ttt ttt "\n", ttt ttt sss sss "\n", 0); assert_message_prettifying(ttt ttt ttt "\n", ttt ttt ttt sss "\n", 0); } void test_object_message__spaces_with_newline_at_end_should_be_replaced_with_empty_string(void) { assert_message_prettifying("", sss "\n", 0); assert_message_prettifying("", sss sss "\n", 0); assert_message_prettifying("", sss sss sss "\n", 0); assert_message_prettifying("", sss sss sss sss "\n", 0); } void test_object_message__spaces_without_newline_at_end_should_be_replaced_with_empty_string(void) { assert_message_prettifying("", "", 0); assert_message_prettifying("", sss sss, 0); assert_message_prettifying("", sss sss sss, 0); assert_message_prettifying("", sss sss sss sss, 0); } void test_object_message__consecutive_text_lines_should_be_unchanged(void) { assert_message_prettifying(ttt ttt "\n" ttt "\n", ttt ttt "\n" ttt "\n", 0); assert_message_prettifying(ttt "\n" ttt ttt "\n" ttt "\n", ttt "\n" ttt ttt "\n" ttt "\n", 0); assert_message_prettifying(ttt "\n" ttt "\n" ttt "\n" ttt ttt "\n", ttt "\n" ttt "\n" ttt "\n" ttt ttt "\n", 0); assert_message_prettifying(ttt "\n" ttt "\n\n" ttt ttt "\n" ttt "\n", ttt "\n" ttt "\n\n" ttt ttt "\n" ttt "\n", 0); assert_message_prettifying(ttt ttt "\n\n" ttt "\n" ttt ttt "\n", ttt ttt "\n\n" ttt "\n" ttt ttt "\n", 0); assert_message_prettifying(ttt "\n" ttt ttt "\n\n" ttt "\n", ttt "\n" ttt ttt "\n\n" ttt "\n", 0); } void test_object_message__strip_comments(void) { assert_message_prettifying("", "# comment", 1); assert_message_prettifying("", "# comment\n", 1); assert_message_prettifying("", "# comment \n", 1); assert_message_prettifying(ttt "\n", ttt "\n" "# comment\n", 1); assert_message_prettifying(ttt "\n", "# comment\n" ttt "\n", 1); assert_message_prettifying(ttt "\n" ttt "\n", ttt "\n" "# comment\n" ttt "\n", 1); } void test_object_message__keep_comments(void) { assert_message_prettifying("# comment\n", "# comment", 0); assert_message_prettifying("# comment\n", "# comment\n", 0); assert_message_prettifying("# comment\n", "# comment \n", 0); assert_message_prettifying(ttt "\n" "# comment\n", ttt "\n" "# comment\n", 0); assert_message_prettifying("# comment\n" ttt "\n", "# comment\n" ttt "\n", 0); assert_message_prettifying(ttt "\n" "# comment\n" ttt "\n", ttt "\n" "# comment\n" ttt "\n", 0); } void test_object_message__message_prettify(void) { char buffer[100]; cl_assert(git_message_prettify(buffer, sizeof(buffer), "", 0) == 1); cl_assert_equal_s(buffer, ""); cl_assert(git_message_prettify(buffer, sizeof(buffer), "", 1) == 1); cl_assert_equal_s(buffer, ""); cl_assert_equal_i(7, git_message_prettify(buffer, sizeof(buffer), "Short", 0)); cl_assert_equal_s("Short\n", buffer); cl_assert_equal_i(7, git_message_prettify(buffer, sizeof(buffer), "Short", 1)); cl_assert_equal_s("Short\n", buffer); cl_assert(git_message_prettify(buffer, sizeof(buffer), "This is longer\nAnd multiline\n# with some comments still in\n", 0) > 0); cl_assert_equal_s(buffer, "This is longer\nAnd multiline\n# with some comments still in\n"); cl_assert(git_message_prettify(buffer, sizeof(buffer), "This is longer\nAnd multiline\n# with some comments still in\n", 1) > 0); cl_assert_equal_s(buffer, "This is longer\nAnd multiline\n"); /* try out overflow */ cl_assert(git_message_prettify(buffer, sizeof(buffer), "1234567890" "1234567890" "1234567890" "1234567890" "1234567890" "1234567890" "1234567890" "1234567890" "1234567890" "12345678", 0) > 0); cl_assert_equal_s(buffer, "1234567890" "1234567890" "1234567890" "1234567890" "1234567890" "1234567890" "1234567890" "1234567890" "1234567890" "12345678\n"); cl_assert(git_message_prettify(buffer, sizeof(buffer), "1234567890" "1234567890" "1234567890" "1234567890" "1234567890" "1234567890" "1234567890" "1234567890" "1234567890" "12345678\n", 0) > 0); cl_assert_equal_s(buffer, "1234567890" "1234567890" "1234567890" "1234567890" "1234567890" "1234567890" "1234567890" "1234567890" "1234567890" "12345678\n"); cl_git_fail(git_message_prettify(buffer, sizeof(buffer), "1234567890" "1234567890" "1234567890" "1234567890" "1234567890" "1234567890" "1234567890" "1234567890" "1234567890" "123456789", 0)); cl_git_fail(git_message_prettify(buffer, sizeof(buffer), "1234567890" "1234567890" "1234567890" "1234567890" "1234567890" "1234567890" "1234567890" "1234567890" "1234567890" "123456789\n", 0)); cl_git_fail(git_message_prettify(buffer, sizeof(buffer), "1234567890" "1234567890" "1234567890" "1234567890" "1234567890" "1234567890" "1234567890" "1234567890" "1234567890" "1234567890", 0)); cl_git_fail(git_message_prettify(buffer, sizeof(buffer), "1234567890" "1234567890" "1234567890" "1234567890" "1234567890" "1234567890" "1234567890" "1234567890" "1234567890" "1234567890""x", 0)); cl_assert(git_message_prettify(buffer, sizeof(buffer), "1234567890" "1234567890" "1234567890" "1234567890" "1234567890\n" "# 1234567890" "1234567890" "1234567890" "1234567890" "1234567890\n" "1234567890", 1) > 0); cl_assert(git_message_prettify(NULL, 0, "", 0) == 1); cl_assert(git_message_prettify(NULL, 0, "Short test", 0) == 12); cl_assert(git_message_prettify(NULL, 0, "Test\n# with\nComments", 1) == 15); } libgit2-0.19.0/tests-clar/object/peel.c000066400000000000000000000063031216214232500175550ustar00rootroot00000000000000#include "clar_libgit2.h" static git_repository *g_repo; void test_object_peel__initialize(void) { cl_git_pass(git_repository_open(&g_repo, cl_fixture("testrepo.git"))); } void test_object_peel__cleanup(void) { git_repository_free(g_repo); g_repo = NULL; } static void assert_peel( const char *sha, git_otype requested_type, const char* expected_sha, git_otype expected_type) { git_oid oid, expected_oid; git_object *obj; git_object *peeled; cl_git_pass(git_oid_fromstr(&oid, sha)); cl_git_pass(git_object_lookup(&obj, g_repo, &oid, GIT_OBJ_ANY)); cl_git_pass(git_object_peel(&peeled, obj, requested_type)); cl_git_pass(git_oid_fromstr(&expected_oid, expected_sha)); cl_assert_equal_i(0, git_oid_cmp(&expected_oid, git_object_id(peeled))); cl_assert_equal_i(expected_type, git_object_type(peeled)); git_object_free(peeled); git_object_free(obj); } static void assert_peel_error(int error, const char *sha, git_otype requested_type) { git_oid oid; git_object *obj; git_object *peeled; cl_git_pass(git_oid_fromstr(&oid, sha)); cl_git_pass(git_object_lookup(&obj, g_repo, &oid, GIT_OBJ_ANY)); cl_assert_equal_i(error, git_object_peel(&peeled, obj, requested_type)); git_object_free(obj); } void test_object_peel__peeling_an_object_into_its_own_type_returns_another_instance_of_it(void) { assert_peel("e90810b8df3e80c413d903f631643c716887138d", GIT_OBJ_COMMIT, "e90810b8df3e80c413d903f631643c716887138d", GIT_OBJ_COMMIT); assert_peel("7b4384978d2493e851f9cca7858815fac9b10980", GIT_OBJ_TAG, "7b4384978d2493e851f9cca7858815fac9b10980", GIT_OBJ_TAG); assert_peel("53fc32d17276939fc79ed05badaef2db09990016", GIT_OBJ_TREE, "53fc32d17276939fc79ed05badaef2db09990016", GIT_OBJ_TREE); assert_peel("0266163a49e280c4f5ed1e08facd36a2bd716bcf", GIT_OBJ_BLOB, "0266163a49e280c4f5ed1e08facd36a2bd716bcf", GIT_OBJ_BLOB); } void test_object_peel__can_peel_a_tag(void) { assert_peel("7b4384978d2493e851f9cca7858815fac9b10980", GIT_OBJ_COMMIT, "e90810b8df3e80c413d903f631643c716887138d", GIT_OBJ_COMMIT); assert_peel("7b4384978d2493e851f9cca7858815fac9b10980", GIT_OBJ_TREE, "53fc32d17276939fc79ed05badaef2db09990016", GIT_OBJ_TREE); } void test_object_peel__can_peel_a_commit(void) { assert_peel("e90810b8df3e80c413d903f631643c716887138d", GIT_OBJ_TREE, "53fc32d17276939fc79ed05badaef2db09990016", GIT_OBJ_TREE); } void test_object_peel__cannot_peel_a_tree(void) { assert_peel_error(GIT_EAMBIGUOUS, "53fc32d17276939fc79ed05badaef2db09990016", GIT_OBJ_BLOB); } void test_object_peel__cannot_peel_a_blob(void) { assert_peel_error(GIT_ENOTFOUND, "0266163a49e280c4f5ed1e08facd36a2bd716bcf", GIT_OBJ_COMMIT); } void test_object_peel__target_any_object_for_type_change(void) { /* tag to commit */ assert_peel("7b4384978d2493e851f9cca7858815fac9b10980", GIT_OBJ_ANY, "e90810b8df3e80c413d903f631643c716887138d", GIT_OBJ_COMMIT); /* commit to tree */ assert_peel("e90810b8df3e80c413d903f631643c716887138d", GIT_OBJ_ANY, "53fc32d17276939fc79ed05badaef2db09990016", GIT_OBJ_TREE); /* fail to peel tree */ assert_peel_error(GIT_EAMBIGUOUS, "53fc32d17276939fc79ed05badaef2db09990016", GIT_OBJ_ANY); /* fail to peel blob */ assert_peel_error(GIT_ENOTFOUND, "0266163a49e280c4f5ed1e08facd36a2bd716bcf", GIT_OBJ_ANY); } libgit2-0.19.0/tests-clar/object/raw/000077500000000000000000000000001216214232500172535ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/object/raw/chars.c000066400000000000000000000017121216214232500205200ustar00rootroot00000000000000 #include "clar_libgit2.h" #include "odb.h" void test_object_raw_chars__find_invalid_chars_in_oid(void) { git_oid out; unsigned char exp[] = { 0x16, 0xa6, 0x77, 0x70, 0xb7, 0xd8, 0xd7, 0x23, 0x17, 0xc4, 0xb7, 0x75, 0x21, 0x3c, 0x23, 0xa8, 0xbd, 0x74, 0xf5, 0xe0, }; char in[41] = "16a67770b7d8d72317c4b775213c23a8bd74f5e0"; unsigned int i; for (i = 0; i < 256; i++) { in[38] = (char)i; if (git__fromhex(i) >= 0) { exp[19] = (unsigned char)(git__fromhex(i) << 4); cl_git_pass(git_oid_fromstr(&out, in)); cl_assert(memcmp(out.id, exp, sizeof(out.id)) == 0); } else { cl_git_fail(git_oid_fromstr(&out, in)); } } } void test_object_raw_chars__build_valid_oid_from_raw_bytes(void) { git_oid out; unsigned char exp[] = { 0x16, 0xa6, 0x77, 0x70, 0xb7, 0xd8, 0xd7, 0x23, 0x17, 0xc4, 0xb7, 0x75, 0x21, 0x3c, 0x23, 0xa8, 0xbd, 0x74, 0xf5, 0xe0, }; git_oid_fromraw(&out, exp); cl_git_pass(memcmp(out.id, exp, sizeof(out.id))); } libgit2-0.19.0/tests-clar/object/raw/compare.c000066400000000000000000000056561216214232500210610ustar00rootroot00000000000000 #include "clar_libgit2.h" #include "odb.h" void test_object_raw_compare__succeed_on_copy_oid(void) { git_oid a, b; unsigned char exp[] = { 0x16, 0xa6, 0x77, 0x70, 0xb7, 0xd8, 0xd7, 0x23, 0x17, 0xc4, 0xb7, 0x75, 0x21, 0x3c, 0x23, 0xa8, 0xbd, 0x74, 0xf5, 0xe0, }; memset(&b, 0, sizeof(b)); git_oid_fromraw(&a, exp); git_oid_cpy(&b, &a); cl_git_pass(memcmp(a.id, exp, sizeof(a.id))); } void test_object_raw_compare__succeed_on_oid_comparison_lesser(void) { git_oid a, b; unsigned char a_in[] = { 0x16, 0xa6, 0x77, 0x70, 0xb7, 0xd8, 0xd7, 0x23, 0x17, 0xc4, 0xb7, 0x75, 0x21, 0x3c, 0x23, 0xa8, 0xbd, 0x74, 0xf5, 0xe0, }; unsigned char b_in[] = { 0x16, 0xa6, 0x77, 0x70, 0xb7, 0xd8, 0xd7, 0x23, 0x17, 0xc4, 0xb7, 0x75, 0x21, 0x3c, 0x23, 0xa8, 0xbd, 0x74, 0xf5, 0xf0, }; git_oid_fromraw(&a, a_in); git_oid_fromraw(&b, b_in); cl_assert(git_oid_cmp(&a, &b) < 0); } void test_object_raw_compare__succeed_on_oid_comparison_equal(void) { git_oid a, b; unsigned char a_in[] = { 0x16, 0xa6, 0x77, 0x70, 0xb7, 0xd8, 0xd7, 0x23, 0x17, 0xc4, 0xb7, 0x75, 0x21, 0x3c, 0x23, 0xa8, 0xbd, 0x74, 0xf5, 0xe0, }; git_oid_fromraw(&a, a_in); git_oid_fromraw(&b, a_in); cl_assert(git_oid_cmp(&a, &b) == 0); } void test_object_raw_compare__succeed_on_oid_comparison_greater(void) { git_oid a, b; unsigned char a_in[] = { 0x16, 0xa6, 0x77, 0x70, 0xb7, 0xd8, 0xd7, 0x23, 0x17, 0xc4, 0xb7, 0x75, 0x21, 0x3c, 0x23, 0xa8, 0xbd, 0x74, 0xf5, 0xe0, }; unsigned char b_in[] = { 0x16, 0xa6, 0x77, 0x70, 0xb7, 0xd8, 0xd7, 0x23, 0x17, 0xc4, 0xb7, 0x75, 0x21, 0x3c, 0x23, 0xa8, 0xbd, 0x74, 0xf5, 0xd0, }; git_oid_fromraw(&a, a_in); git_oid_fromraw(&b, b_in); cl_assert(git_oid_cmp(&a, &b) > 0); } void test_object_raw_compare__compare_fmt_oids(void) { const char *exp = "16a0123456789abcdef4b775213c23a8bd74f5e0"; git_oid in; char out[GIT_OID_HEXSZ + 1]; cl_git_pass(git_oid_fromstr(&in, exp)); /* Format doesn't touch the last byte */ out[GIT_OID_HEXSZ] = 'Z'; git_oid_fmt(out, &in); cl_assert(out[GIT_OID_HEXSZ] == 'Z'); /* Format produced the right result */ out[GIT_OID_HEXSZ] = '\0'; cl_assert_equal_s(exp, out); } void test_object_raw_compare__compare_allocfmt_oids(void) { const char *exp = "16a0123456789abcdef4b775213c23a8bd74f5e0"; git_oid in; char *out; cl_git_pass(git_oid_fromstr(&in, exp)); out = git_oid_allocfmt(&in); cl_assert(out); cl_assert_equal_s(exp, out); git__free(out); } void test_object_raw_compare__compare_pathfmt_oids(void) { const char *exp1 = "16a0123456789abcdef4b775213c23a8bd74f5e0"; const char *exp2 = "16/a0123456789abcdef4b775213c23a8bd74f5e0"; git_oid in; char out[GIT_OID_HEXSZ + 2]; cl_git_pass(git_oid_fromstr(&in, exp1)); /* Format doesn't touch the last byte */ out[GIT_OID_HEXSZ + 1] = 'Z'; git_oid_pathfmt(out, &in); cl_assert(out[GIT_OID_HEXSZ + 1] == 'Z'); /* Format produced the right result */ out[GIT_OID_HEXSZ + 1] = '\0'; cl_assert_equal_s(exp2, out); } libgit2-0.19.0/tests-clar/object/raw/convert.c000066400000000000000000000066401216214232500211050ustar00rootroot00000000000000 #include "clar_libgit2.h" #include "odb.h" void test_object_raw_convert__succeed_on_oid_to_string_conversion(void) { const char *exp = "16a0123456789abcdef4b775213c23a8bd74f5e0"; git_oid in; char out[GIT_OID_HEXSZ + 1]; char *str; int i; cl_git_pass(git_oid_fromstr(&in, exp)); /* NULL buffer pointer, returns static empty string */ str = git_oid_tostr(NULL, sizeof(out), &in); cl_assert(str && *str == '\0' && str != out); /* zero buffer size, returns static empty string */ str = git_oid_tostr(out, 0, &in); cl_assert(str && *str == '\0' && str != out); /* NULL oid pointer, sets existing buffer to empty string */ str = git_oid_tostr(out, sizeof(out), NULL); cl_assert(str && *str == '\0' && str == out); /* n == 1, returns out as an empty string */ str = git_oid_tostr(out, 1, &in); cl_assert(str && *str == '\0' && str == out); for (i = 1; i < GIT_OID_HEXSZ; i++) { out[i+1] = 'Z'; str = git_oid_tostr(out, i+1, &in); /* returns out containing c-string */ cl_assert(str && str == out); /* must be '\0' terminated */ cl_assert(*(str+i) == '\0'); /* must not touch bytes past end of string */ cl_assert(*(str+(i+1)) == 'Z'); /* i == n-1 charaters of string */ cl_git_pass(strncmp(exp, out, i)); } /* returns out as hex formatted c-string */ str = git_oid_tostr(out, sizeof(out), &in); cl_assert(str && str == out && *(str+GIT_OID_HEXSZ) == '\0'); cl_assert_equal_s(exp, out); } void test_object_raw_convert__succeed_on_oid_to_string_conversion_big(void) { const char *exp = "16a0123456789abcdef4b775213c23a8bd74f5e0"; git_oid in; char big[GIT_OID_HEXSZ + 1 + 3]; /* note + 4 => big buffer */ char *str; cl_git_pass(git_oid_fromstr(&in, exp)); /* place some tail material */ big[GIT_OID_HEXSZ+0] = 'W'; /* should be '\0' afterwards */ big[GIT_OID_HEXSZ+1] = 'X'; /* should remain untouched */ big[GIT_OID_HEXSZ+2] = 'Y'; /* ditto */ big[GIT_OID_HEXSZ+3] = 'Z'; /* ditto */ /* returns big as hex formatted c-string */ str = git_oid_tostr(big, sizeof(big), &in); cl_assert(str && str == big && *(str+GIT_OID_HEXSZ) == '\0'); cl_assert_equal_s(exp, big); /* check tail material is untouched */ cl_assert(str && str == big && *(str+GIT_OID_HEXSZ+1) == 'X'); cl_assert(str && str == big && *(str+GIT_OID_HEXSZ+2) == 'Y'); cl_assert(str && str == big && *(str+GIT_OID_HEXSZ+3) == 'Z'); } static void check_partial_oid( char *buffer, size_t count, const git_oid *oid, const char *expected) { git_oid_nfmt(buffer, count, oid); buffer[count] = '\0'; cl_assert_equal_s(expected, buffer); } void test_object_raw_convert__convert_oid_partially(void) { const char *exp = "16a0123456789abcdef4b775213c23a8bd74f5e0"; git_oid in; char big[GIT_OID_HEXSZ + 1 + 3]; /* note + 4 => big buffer */ cl_git_pass(git_oid_fromstr(&in, exp)); git_oid_nfmt(big, sizeof(big), &in); cl_assert_equal_s(exp, big); git_oid_nfmt(big, GIT_OID_HEXSZ + 1, &in); cl_assert_equal_s(exp, big); check_partial_oid(big, 1, &in, "1"); check_partial_oid(big, 2, &in, "16"); check_partial_oid(big, 3, &in, "16a"); check_partial_oid(big, 4, &in, "16a0"); check_partial_oid(big, 5, &in, "16a01"); check_partial_oid(big, GIT_OID_HEXSZ, &in, exp); check_partial_oid( big, GIT_OID_HEXSZ - 1, &in, "16a0123456789abcdef4b775213c23a8bd74f5e"); check_partial_oid( big, GIT_OID_HEXSZ - 2, &in, "16a0123456789abcdef4b775213c23a8bd74f5"); check_partial_oid( big, GIT_OID_HEXSZ - 3, &in, "16a0123456789abcdef4b775213c23a8bd74f"); } libgit2-0.19.0/tests-clar/object/raw/data.h000066400000000000000000000320361216214232500203410ustar00rootroot00000000000000 /* * Raw data */ static unsigned char commit_data[] = { 0x74, 0x72, 0x65, 0x65, 0x20, 0x64, 0x66, 0x66, 0x32, 0x64, 0x61, 0x39, 0x30, 0x62, 0x32, 0x35, 0x34, 0x65, 0x31, 0x62, 0x65, 0x62, 0x38, 0x38, 0x39, 0x64, 0x31, 0x66, 0x31, 0x66, 0x31, 0x32, 0x38, 0x38, 0x62, 0x65, 0x31, 0x38, 0x30, 0x33, 0x37, 0x38, 0x32, 0x64, 0x66, 0x0a, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x20, 0x41, 0x20, 0x55, 0x20, 0x54, 0x68, 0x6f, 0x72, 0x20, 0x3c, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x40, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x3e, 0x20, 0x31, 0x32, 0x32, 0x37, 0x38, 0x31, 0x34, 0x32, 0x39, 0x37, 0x20, 0x2b, 0x30, 0x30, 0x30, 0x30, 0x0a, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x74, 0x65, 0x72, 0x20, 0x43, 0x20, 0x4f, 0x20, 0x4d, 0x69, 0x74, 0x74, 0x65, 0x72, 0x20, 0x3c, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x74, 0x65, 0x72, 0x40, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x3e, 0x20, 0x31, 0x32, 0x32, 0x37, 0x38, 0x31, 0x34, 0x32, 0x39, 0x37, 0x20, 0x2b, 0x30, 0x30, 0x30, 0x30, 0x0a, 0x0a, 0x41, 0x20, 0x6f, 0x6e, 0x65, 0x2d, 0x6c, 0x69, 0x6e, 0x65, 0x20, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x20, 0x73, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x0a, 0x0a, 0x54, 0x68, 0x65, 0x20, 0x62, 0x6f, 0x64, 0x79, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2c, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x69, 0x6e, 0x67, 0x20, 0x66, 0x75, 0x72, 0x74, 0x68, 0x65, 0x72, 0x20, 0x65, 0x78, 0x70, 0x6c, 0x61, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x0a, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x75, 0x72, 0x70, 0x6f, 0x73, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x20, 0x69, 0x6e, 0x74, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x65, 0x64, 0x20, 0x62, 0x79, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x2e, 0x0a, 0x0a, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x2d, 0x6f, 0x66, 0x2d, 0x62, 0x79, 0x3a, 0x20, 0x41, 0x20, 0x55, 0x20, 0x54, 0x68, 0x6f, 0x72, 0x20, 0x3c, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x40, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x3e, 0x0a, }; static unsigned char tree_data[] = { 0x31, 0x30, 0x30, 0x36, 0x34, 0x34, 0x20, 0x6f, 0x6e, 0x65, 0x00, 0x8b, 0x13, 0x78, 0x91, 0x79, 0x1f, 0xe9, 0x69, 0x27, 0xad, 0x78, 0xe6, 0x4b, 0x0a, 0xad, 0x7b, 0xde, 0xd0, 0x8b, 0xdc, 0x31, 0x30, 0x30, 0x36, 0x34, 0x34, 0x20, 0x73, 0x6f, 0x6d, 0x65, 0x00, 0xfd, 0x84, 0x30, 0xbc, 0x86, 0x4c, 0xfc, 0xd5, 0xf1, 0x0e, 0x55, 0x90, 0xf8, 0xa4, 0x47, 0xe0, 0x1b, 0x94, 0x2b, 0xfe, 0x31, 0x30, 0x30, 0x36, 0x34, 0x34, 0x20, 0x74, 0x77, 0x6f, 0x00, 0x78, 0x98, 0x19, 0x22, 0x61, 0x3b, 0x2a, 0xfb, 0x60, 0x25, 0x04, 0x2f, 0xf6, 0xbd, 0x87, 0x8a, 0xc1, 0x99, 0x4e, 0x85, 0x31, 0x30, 0x30, 0x36, 0x34, 0x34, 0x20, 0x7a, 0x65, 0x72, 0x6f, 0x00, 0xe6, 0x9d, 0xe2, 0x9b, 0xb2, 0xd1, 0xd6, 0x43, 0x4b, 0x8b, 0x29, 0xae, 0x77, 0x5a, 0xd8, 0xc2, 0xe4, 0x8c, 0x53, 0x91, }; static unsigned char tag_data[] = { 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x20, 0x33, 0x64, 0x37, 0x66, 0x38, 0x61, 0x36, 0x61, 0x66, 0x30, 0x37, 0x36, 0x63, 0x38, 0x63, 0x33, 0x66, 0x32, 0x30, 0x30, 0x37, 0x31, 0x61, 0x38, 0x39, 0x33, 0x35, 0x63, 0x64, 0x62, 0x65, 0x38, 0x32, 0x32, 0x38, 0x35, 0x39, 0x34, 0x64, 0x31, 0x0a, 0x74, 0x79, 0x70, 0x65, 0x20, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x0a, 0x74, 0x61, 0x67, 0x20, 0x76, 0x30, 0x2e, 0x30, 0x2e, 0x31, 0x0a, 0x74, 0x61, 0x67, 0x67, 0x65, 0x72, 0x20, 0x43, 0x20, 0x4f, 0x20, 0x4d, 0x69, 0x74, 0x74, 0x65, 0x72, 0x20, 0x3c, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x74, 0x65, 0x72, 0x40, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x3e, 0x20, 0x31, 0x32, 0x32, 0x37, 0x38, 0x31, 0x34, 0x32, 0x39, 0x37, 0x20, 0x2b, 0x30, 0x30, 0x30, 0x30, 0x0a, 0x0a, 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x61, 0x67, 0x20, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x20, 0x76, 0x30, 0x2e, 0x30, 0x2e, 0x31, 0x0a, }; /* * Dummy data */ static unsigned char zero_data[] = { 0x00, }; static unsigned char one_data[] = { 0x0a, }; static unsigned char two_data[] = { 0x61, 0x0a, }; static unsigned char some_data[] = { 0x2f, 0x2a, 0x0a, 0x20, 0x2a, 0x20, 0x54, 0x68, 0x69, 0x73, 0x20, 0x66, 0x69, 0x6c, 0x65, 0x20, 0x69, 0x73, 0x20, 0x66, 0x72, 0x65, 0x65, 0x20, 0x73, 0x6f, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0x3b, 0x20, 0x79, 0x6f, 0x75, 0x20, 0x63, 0x61, 0x6e, 0x20, 0x72, 0x65, 0x64, 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x20, 0x69, 0x74, 0x20, 0x61, 0x6e, 0x64, 0x2f, 0x6f, 0x72, 0x20, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0a, 0x20, 0x2a, 0x20, 0x69, 0x74, 0x20, 0x75, 0x6e, 0x64, 0x65, 0x72, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x65, 0x72, 0x6d, 0x73, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x47, 0x4e, 0x55, 0x20, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x6c, 0x20, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x20, 0x4c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x2c, 0x20, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x32, 0x2c, 0x0a, 0x20, 0x2a, 0x20, 0x61, 0x73, 0x20, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x65, 0x64, 0x20, 0x62, 0x79, 0x20, 0x74, 0x68, 0x65, 0x20, 0x46, 0x72, 0x65, 0x65, 0x20, 0x53, 0x6f, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0x20, 0x46, 0x6f, 0x75, 0x6e, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x0a, 0x20, 0x2a, 0x0a, 0x20, 0x2a, 0x20, 0x49, 0x6e, 0x20, 0x61, 0x64, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x74, 0x6f, 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x47, 0x4e, 0x55, 0x20, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x6c, 0x20, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x20, 0x4c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x2c, 0x0a, 0x20, 0x2a, 0x20, 0x74, 0x68, 0x65, 0x20, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x73, 0x20, 0x67, 0x69, 0x76, 0x65, 0x20, 0x79, 0x6f, 0x75, 0x20, 0x75, 0x6e, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x65, 0x64, 0x20, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x74, 0x6f, 0x20, 0x6c, 0x69, 0x6e, 0x6b, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x64, 0x0a, 0x20, 0x2a, 0x20, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x66, 0x69, 0x6c, 0x65, 0x20, 0x69, 0x6e, 0x74, 0x6f, 0x20, 0x63, 0x6f, 0x6d, 0x62, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x6f, 0x74, 0x68, 0x65, 0x72, 0x20, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x73, 0x2c, 0x0a, 0x20, 0x2a, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x74, 0x6f, 0x20, 0x64, 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x20, 0x74, 0x68, 0x6f, 0x73, 0x65, 0x20, 0x63, 0x6f, 0x6d, 0x62, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x77, 0x69, 0x74, 0x68, 0x6f, 0x75, 0x74, 0x20, 0x61, 0x6e, 0x79, 0x20, 0x72, 0x65, 0x73, 0x74, 0x72, 0x69, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x0a, 0x20, 0x2a, 0x20, 0x63, 0x6f, 0x6d, 0x69, 0x6e, 0x67, 0x20, 0x66, 0x72, 0x6f, 0x6d, 0x20, 0x74, 0x68, 0x65, 0x20, 0x75, 0x73, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x66, 0x69, 0x6c, 0x65, 0x2e, 0x20, 0x20, 0x28, 0x54, 0x68, 0x65, 0x20, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x6c, 0x20, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x20, 0x4c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x0a, 0x20, 0x2a, 0x20, 0x72, 0x65, 0x73, 0x74, 0x72, 0x69, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x64, 0x6f, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x79, 0x20, 0x69, 0x6e, 0x20, 0x6f, 0x74, 0x68, 0x65, 0x72, 0x20, 0x72, 0x65, 0x73, 0x70, 0x65, 0x63, 0x74, 0x73, 0x3b, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2c, 0x20, 0x74, 0x68, 0x65, 0x79, 0x20, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x0a, 0x20, 0x2a, 0x20, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x66, 0x69, 0x6c, 0x65, 0x2c, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x64, 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x77, 0x68, 0x65, 0x6e, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x6c, 0x69, 0x6e, 0x6b, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x74, 0x6f, 0x0a, 0x20, 0x2a, 0x20, 0x61, 0x20, 0x63, 0x6f, 0x6d, 0x62, 0x69, 0x6e, 0x65, 0x64, 0x20, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x2e, 0x29, 0x0a, 0x20, 0x2a, 0x0a, 0x20, 0x2a, 0x20, 0x54, 0x68, 0x69, 0x73, 0x20, 0x66, 0x69, 0x6c, 0x65, 0x20, 0x69, 0x73, 0x20, 0x64, 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x68, 0x6f, 0x70, 0x65, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x69, 0x74, 0x20, 0x77, 0x69, 0x6c, 0x6c, 0x20, 0x62, 0x65, 0x20, 0x75, 0x73, 0x65, 0x66, 0x75, 0x6c, 0x2c, 0x20, 0x62, 0x75, 0x74, 0x0a, 0x20, 0x2a, 0x20, 0x57, 0x49, 0x54, 0x48, 0x4f, 0x55, 0x54, 0x20, 0x41, 0x4e, 0x59, 0x20, 0x57, 0x41, 0x52, 0x52, 0x41, 0x4e, 0x54, 0x59, 0x3b, 0x20, 0x77, 0x69, 0x74, 0x68, 0x6f, 0x75, 0x74, 0x20, 0x65, 0x76, 0x65, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x69, 0x6d, 0x70, 0x6c, 0x69, 0x65, 0x64, 0x20, 0x77, 0x61, 0x72, 0x72, 0x61, 0x6e, 0x74, 0x79, 0x20, 0x6f, 0x66, 0x0a, 0x20, 0x2a, 0x20, 0x4d, 0x45, 0x52, 0x43, 0x48, 0x41, 0x4e, 0x54, 0x41, 0x42, 0x49, 0x4c, 0x49, 0x54, 0x59, 0x20, 0x6f, 0x72, 0x20, 0x46, 0x49, 0x54, 0x4e, 0x45, 0x53, 0x53, 0x20, 0x46, 0x4f, 0x52, 0x20, 0x41, 0x20, 0x50, 0x41, 0x52, 0x54, 0x49, 0x43, 0x55, 0x4c, 0x41, 0x52, 0x20, 0x50, 0x55, 0x52, 0x50, 0x4f, 0x53, 0x45, 0x2e, 0x20, 0x20, 0x53, 0x65, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, 0x47, 0x4e, 0x55, 0x0a, 0x20, 0x2a, 0x20, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x6c, 0x20, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x20, 0x4c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x6d, 0x6f, 0x72, 0x65, 0x20, 0x64, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x2e, 0x0a, 0x20, 0x2a, 0x0a, 0x20, 0x2a, 0x20, 0x59, 0x6f, 0x75, 0x20, 0x73, 0x68, 0x6f, 0x75, 0x6c, 0x64, 0x20, 0x68, 0x61, 0x76, 0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x64, 0x20, 0x61, 0x20, 0x63, 0x6f, 0x70, 0x79, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x47, 0x4e, 0x55, 0x20, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x6c, 0x20, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x20, 0x4c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x0a, 0x20, 0x2a, 0x20, 0x61, 0x6c, 0x6f, 0x6e, 0x67, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x3b, 0x20, 0x73, 0x65, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, 0x66, 0x69, 0x6c, 0x65, 0x20, 0x43, 0x4f, 0x50, 0x59, 0x49, 0x4e, 0x47, 0x2e, 0x20, 0x20, 0x49, 0x66, 0x20, 0x6e, 0x6f, 0x74, 0x2c, 0x20, 0x77, 0x72, 0x69, 0x74, 0x65, 0x20, 0x74, 0x6f, 0x0a, 0x20, 0x2a, 0x20, 0x74, 0x68, 0x65, 0x20, 0x46, 0x72, 0x65, 0x65, 0x20, 0x53, 0x6f, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0x20, 0x46, 0x6f, 0x75, 0x6e, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2c, 0x20, 0x35, 0x31, 0x20, 0x46, 0x72, 0x61, 0x6e, 0x6b, 0x6c, 0x69, 0x6e, 0x20, 0x53, 0x74, 0x72, 0x65, 0x65, 0x74, 0x2c, 0x20, 0x46, 0x69, 0x66, 0x74, 0x68, 0x20, 0x46, 0x6c, 0x6f, 0x6f, 0x72, 0x2c, 0x0a, 0x20, 0x2a, 0x20, 0x42, 0x6f, 0x73, 0x74, 0x6f, 0x6e, 0x2c, 0x20, 0x4d, 0x41, 0x20, 0x30, 0x32, 0x31, 0x31, 0x30, 0x2d, 0x31, 0x33, 0x30, 0x31, 0x2c, 0x20, 0x55, 0x53, 0x41, 0x2e, 0x0a, 0x20, 0x2a, 0x2f, 0x0a, }; /* * SHA1 Hashes */ static char *commit_id = "3d7f8a6af076c8c3f20071a8935cdbe8228594d1"; static char *tree_id = "dff2da90b254e1beb889d1f1f1288be1803782df"; static char *tag_id = "09d373e1dfdc16b129ceec6dd649739911541e05"; static char *zero_id = "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391"; static char *one_id = "8b137891791fe96927ad78e64b0aad7bded08bdc"; static char *two_id = "78981922613b2afb6025042ff6bd878ac1994e85"; static char *some_id = "fd8430bc864cfcd5f10e5590f8a447e01b942bfe"; /* * In-memory objects */ static git_rawobj tree_obj = { tree_data, sizeof(tree_data), GIT_OBJ_TREE }; static git_rawobj tag_obj = { tag_data, sizeof(tag_data), GIT_OBJ_TAG }; static git_rawobj zero_obj = { zero_data, 0, GIT_OBJ_BLOB }; static git_rawobj one_obj = { one_data, sizeof(one_data), GIT_OBJ_BLOB }; static git_rawobj two_obj = { two_data, sizeof(two_data), GIT_OBJ_BLOB }; static git_rawobj commit_obj = { commit_data, sizeof(commit_data), GIT_OBJ_COMMIT }; static git_rawobj some_obj = { some_data, sizeof(some_data), GIT_OBJ_BLOB }; static git_rawobj junk_obj = { NULL, 0, GIT_OBJ_BAD }; libgit2-0.19.0/tests-clar/object/raw/fromstr.c000066400000000000000000000014401216214232500211120ustar00rootroot00000000000000 #include "clar_libgit2.h" #include "odb.h" void test_object_raw_fromstr__fail_on_invalid_oid_string(void) { git_oid out; cl_git_fail(git_oid_fromstr(&out, "")); cl_git_fail(git_oid_fromstr(&out, "moo")); cl_git_fail(git_oid_fromstr(&out, "16a67770b7d8d72317c4b775213c23a8bd74f5ez")); } void test_object_raw_fromstr__succeed_on_valid_oid_string(void) { git_oid out; unsigned char exp[] = { 0x16, 0xa6, 0x77, 0x70, 0xb7, 0xd8, 0xd7, 0x23, 0x17, 0xc4, 0xb7, 0x75, 0x21, 0x3c, 0x23, 0xa8, 0xbd, 0x74, 0xf5, 0xe0, }; cl_git_pass(git_oid_fromstr(&out, "16a67770b7d8d72317c4b775213c23a8bd74f5e0")); cl_git_pass(memcmp(out.id, exp, sizeof(out.id))); cl_git_pass(git_oid_fromstr(&out, "16A67770B7D8D72317C4b775213C23A8BD74F5E0")); cl_git_pass(memcmp(out.id, exp, sizeof(out.id))); } libgit2-0.19.0/tests-clar/object/raw/hash.c000066400000000000000000000075031216214232500203470ustar00rootroot00000000000000 #include "clar_libgit2.h" #include "odb.h" #include "hash.h" #include "data.h" static void hash_object_pass(git_oid *oid, git_rawobj *obj) { cl_git_pass(git_odb_hash(oid, obj->data, obj->len, obj->type)); } static void hash_object_fail(git_oid *oid, git_rawobj *obj) { cl_git_fail(git_odb_hash(oid, obj->data, obj->len, obj->type)); } static char *hello_id = "22596363b3de40b06f981fb85d82312e8c0ed511"; static char *hello_text = "hello world\n"; static char *bye_id = "ce08fe4884650f067bd5703b6a59a8b3b3c99a09"; static char *bye_text = "bye world\n"; void test_object_raw_hash__hash_by_blocks(void) { git_hash_ctx ctx; git_oid id1, id2; cl_git_pass(git_hash_ctx_init(&ctx)); /* should already be init'd */ cl_git_pass(git_hash_update(&ctx, hello_text, strlen(hello_text))); cl_git_pass(git_hash_final(&id2, &ctx)); cl_git_pass(git_oid_fromstr(&id1, hello_id)); cl_assert(git_oid_cmp(&id1, &id2) == 0); /* reinit should permit reuse */ cl_git_pass(git_hash_init(&ctx)); cl_git_pass(git_hash_update(&ctx, bye_text, strlen(bye_text))); cl_git_pass(git_hash_final(&id2, &ctx)); cl_git_pass(git_oid_fromstr(&id1, bye_id)); cl_assert(git_oid_cmp(&id1, &id2) == 0); git_hash_ctx_cleanup(&ctx); } void test_object_raw_hash__hash_buffer_in_single_call(void) { git_oid id1, id2; cl_git_pass(git_oid_fromstr(&id1, hello_id)); git_hash_buf(&id2, hello_text, strlen(hello_text)); cl_assert(git_oid_cmp(&id1, &id2) == 0); } void test_object_raw_hash__hash_vector(void) { git_oid id1, id2; git_buf_vec vec[2]; cl_git_pass(git_oid_fromstr(&id1, hello_id)); vec[0].data = hello_text; vec[0].len = 4; vec[1].data = hello_text+4; vec[1].len = strlen(hello_text)-4; git_hash_vec(&id2, vec, 2); cl_assert(git_oid_cmp(&id1, &id2) == 0); } void test_object_raw_hash__hash_junk_data(void) { git_oid id, id_zero; cl_git_pass(git_oid_fromstr(&id_zero, zero_id)); /* invalid types: */ junk_obj.data = some_data; hash_object_fail(&id, &junk_obj); junk_obj.type = GIT_OBJ__EXT1; hash_object_fail(&id, &junk_obj); junk_obj.type = GIT_OBJ__EXT2; hash_object_fail(&id, &junk_obj); junk_obj.type = GIT_OBJ_OFS_DELTA; hash_object_fail(&id, &junk_obj); junk_obj.type = GIT_OBJ_REF_DELTA; hash_object_fail(&id, &junk_obj); /* data can be NULL only if len is zero: */ junk_obj.type = GIT_OBJ_BLOB; junk_obj.data = NULL; hash_object_pass(&id, &junk_obj); cl_assert(git_oid_cmp(&id, &id_zero) == 0); junk_obj.len = 1; hash_object_fail(&id, &junk_obj); } void test_object_raw_hash__hash_commit_object(void) { git_oid id1, id2; cl_git_pass(git_oid_fromstr(&id1, commit_id)); hash_object_pass(&id2, &commit_obj); cl_assert(git_oid_cmp(&id1, &id2) == 0); } void test_object_raw_hash__hash_tree_object(void) { git_oid id1, id2; cl_git_pass(git_oid_fromstr(&id1, tree_id)); hash_object_pass(&id2, &tree_obj); cl_assert(git_oid_cmp(&id1, &id2) == 0); } void test_object_raw_hash__hash_tag_object(void) { git_oid id1, id2; cl_git_pass(git_oid_fromstr(&id1, tag_id)); hash_object_pass(&id2, &tag_obj); cl_assert(git_oid_cmp(&id1, &id2) == 0); } void test_object_raw_hash__hash_zero_length_object(void) { git_oid id1, id2; cl_git_pass(git_oid_fromstr(&id1, zero_id)); hash_object_pass(&id2, &zero_obj); cl_assert(git_oid_cmp(&id1, &id2) == 0); } void test_object_raw_hash__hash_one_byte_object(void) { git_oid id1, id2; cl_git_pass(git_oid_fromstr(&id1, one_id)); hash_object_pass(&id2, &one_obj); cl_assert(git_oid_cmp(&id1, &id2) == 0); } void test_object_raw_hash__hash_two_byte_object(void) { git_oid id1, id2; cl_git_pass(git_oid_fromstr(&id1, two_id)); hash_object_pass(&id2, &two_obj); cl_assert(git_oid_cmp(&id1, &id2) == 0); } void test_object_raw_hash__hash_multi_byte_object(void) { git_oid id1, id2; cl_git_pass(git_oid_fromstr(&id1, some_id)); hash_object_pass(&id2, &some_obj); cl_assert(git_oid_cmp(&id1, &id2) == 0); } libgit2-0.19.0/tests-clar/object/raw/short.c000066400000000000000000000060231216214232500205570ustar00rootroot00000000000000 #include "clar_libgit2.h" #include "odb.h" #include "hash.h" void test_object_raw_short__oid_shortener_no_duplicates(void) { git_oid_shorten *os; int min_len; os = git_oid_shorten_new(0); cl_assert(os != NULL); git_oid_shorten_add(os, "22596363b3de40b06f981fb85d82312e8c0ed511"); git_oid_shorten_add(os, "ce08fe4884650f067bd5703b6a59a8b3b3c99a09"); git_oid_shorten_add(os, "16a0123456789abcdef4b775213c23a8bd74f5e0"); min_len = git_oid_shorten_add(os, "ce08fe4884650f067bd5703b6a59a8b3b3c99a09"); cl_assert(min_len == GIT_OID_HEXSZ + 1); git_oid_shorten_free(os); } static int insert_sequential_oids( char ***out, git_oid_shorten *os, int n, int fail) { int i, min_len = 0; char numbuf[16]; git_oid oid; char **oids = git__calloc(n, sizeof(char *)); cl_assert(oids != NULL); for (i = 0; i < n; ++i) { p_snprintf(numbuf, sizeof(numbuf), "%u", (unsigned int)i); git_hash_buf(&oid, numbuf, strlen(numbuf)); oids[i] = git__malloc(GIT_OID_HEXSZ + 1); cl_assert(oids[i]); git_oid_nfmt(oids[i], GIT_OID_HEXSZ + 1, &oid); min_len = git_oid_shorten_add(os, oids[i]); /* After "fail", we expect git_oid_shorten_add to fail */ if (fail >= 0 && i >= fail) cl_assert(min_len < 0); else cl_assert(min_len >= 0); } *out = oids; return min_len; } static void free_oids(int n, char **oids) { int i; for (i = 0; i < n; ++i) { git__free(oids[i]); } git__free(oids); } void test_object_raw_short__oid_shortener_stresstest_git_oid_shorten(void) { #define MAX_OIDS 1000 git_oid_shorten *os; size_t i, j; int min_len = 0, found_collision; char **oids; os = git_oid_shorten_new(0); cl_assert(os != NULL); /* * Insert in the shortener 1000 unique SHA1 ids */ min_len = insert_sequential_oids(&oids, os, MAX_OIDS, MAX_OIDS); cl_assert(min_len > 0); /* * Compare the first `min_char - 1` characters of each * SHA1 OID. If the minimizer worked, we should find at * least one collision */ found_collision = 0; for (i = 0; i < MAX_OIDS; ++i) { for (j = i + 1; j < MAX_OIDS; ++j) { if (memcmp(oids[i], oids[j], min_len - 1) == 0) found_collision = 1; } } cl_assert_equal_b(true, found_collision); /* * Compare the first `min_char` characters of each * SHA1 OID. If the minimizer worked, every single preffix * should be unique. */ found_collision = 0; for (i = 0; i < MAX_OIDS; ++i) { for (j = i + 1; j < MAX_OIDS; ++j) { if (memcmp(oids[i], oids[j], min_len) == 0) found_collision = 1; } } cl_assert_equal_b(false, found_collision); /* cleanup */ free_oids(MAX_OIDS, oids); git_oid_shorten_free(os); #undef MAX_OIDS } void test_object_raw_short__oid_shortener_too_much_oids(void) { /* The magic number of oids at which an oid_shortener will fail. * This was experimentally established. */ #define MAX_OIDS 24556 git_oid_shorten *os; char **oids; os = git_oid_shorten_new(0); cl_assert(os != NULL); cl_assert(insert_sequential_oids(&oids, os, MAX_OIDS, MAX_OIDS - 1) < 0); free_oids(MAX_OIDS, oids); git_oid_shorten_free(os); #undef MAX_OIDS } libgit2-0.19.0/tests-clar/object/raw/size.c000066400000000000000000000004141216214232500203700ustar00rootroot00000000000000 #include "clar_libgit2.h" #include "odb.h" void test_object_raw_size__validate_oid_size(void) { git_oid out; cl_assert(20 == GIT_OID_RAWSZ); cl_assert(40 == GIT_OID_HEXSZ); cl_assert(sizeof(out) == GIT_OID_RAWSZ); cl_assert(sizeof(out.id) == GIT_OID_RAWSZ); } libgit2-0.19.0/tests-clar/object/raw/type2string.c000066400000000000000000000043601216214232500217140ustar00rootroot00000000000000 #include "clar_libgit2.h" #include "odb.h" #include "hash.h" void test_object_raw_type2string__convert_type_to_string(void) { cl_assert_equal_s(git_object_type2string(GIT_OBJ_BAD), ""); cl_assert_equal_s(git_object_type2string(GIT_OBJ__EXT1), ""); cl_assert_equal_s(git_object_type2string(GIT_OBJ_COMMIT), "commit"); cl_assert_equal_s(git_object_type2string(GIT_OBJ_TREE), "tree"); cl_assert_equal_s(git_object_type2string(GIT_OBJ_BLOB), "blob"); cl_assert_equal_s(git_object_type2string(GIT_OBJ_TAG), "tag"); cl_assert_equal_s(git_object_type2string(GIT_OBJ__EXT2), ""); cl_assert_equal_s(git_object_type2string(GIT_OBJ_OFS_DELTA), "OFS_DELTA"); cl_assert_equal_s(git_object_type2string(GIT_OBJ_REF_DELTA), "REF_DELTA"); cl_assert_equal_s(git_object_type2string(-2), ""); cl_assert_equal_s(git_object_type2string(8), ""); cl_assert_equal_s(git_object_type2string(1234), ""); } void test_object_raw_type2string__convert_string_to_type(void) { cl_assert(git_object_string2type(NULL) == GIT_OBJ_BAD); cl_assert(git_object_string2type("") == GIT_OBJ_BAD); cl_assert(git_object_string2type("commit") == GIT_OBJ_COMMIT); cl_assert(git_object_string2type("tree") == GIT_OBJ_TREE); cl_assert(git_object_string2type("blob") == GIT_OBJ_BLOB); cl_assert(git_object_string2type("tag") == GIT_OBJ_TAG); cl_assert(git_object_string2type("OFS_DELTA") == GIT_OBJ_OFS_DELTA); cl_assert(git_object_string2type("REF_DELTA") == GIT_OBJ_REF_DELTA); cl_assert(git_object_string2type("CoMmIt") == GIT_OBJ_BAD); cl_assert(git_object_string2type("hohoho") == GIT_OBJ_BAD); } void test_object_raw_type2string__check_type_is_loose(void) { cl_assert(git_object_typeisloose(GIT_OBJ_BAD) == 0); cl_assert(git_object_typeisloose(GIT_OBJ__EXT1) == 0); cl_assert(git_object_typeisloose(GIT_OBJ_COMMIT) == 1); cl_assert(git_object_typeisloose(GIT_OBJ_TREE) == 1); cl_assert(git_object_typeisloose(GIT_OBJ_BLOB) == 1); cl_assert(git_object_typeisloose(GIT_OBJ_TAG) == 1); cl_assert(git_object_typeisloose(GIT_OBJ__EXT2) == 0); cl_assert(git_object_typeisloose(GIT_OBJ_OFS_DELTA) == 0); cl_assert(git_object_typeisloose(GIT_OBJ_REF_DELTA) == 0); cl_assert(git_object_typeisloose(-2) == 0); cl_assert(git_object_typeisloose(8) == 0); cl_assert(git_object_typeisloose(1234) == 0); } libgit2-0.19.0/tests-clar/object/raw/write.c000066400000000000000000000414621216214232500205600ustar00rootroot00000000000000#include "clar_libgit2.h" #include "git2/odb_backend.h" #include "fileops.h" #include "odb.h" typedef struct object_data { char *id; /* object id (sha1) */ char *dir; /* object store (fan-out) directory name */ char *file; /* object store filename */ } object_data; static const char *odb_dir = "test-objects"; void test_body(object_data *d, git_rawobj *o); // Helpers static void remove_object_files(object_data *d) { cl_git_pass(p_unlink(d->file)); cl_git_pass(p_rmdir(d->dir)); cl_assert(errno != ENOTEMPTY); cl_git_pass(p_rmdir(odb_dir) < 0); } static void streaming_write(git_oid *oid, git_odb *odb, git_rawobj *raw) { git_odb_stream *stream; int error; cl_git_pass(git_odb_open_wstream(&stream, odb, raw->len, raw->type)); stream->write(stream, raw->data, raw->len); error = stream->finalize_write(oid, stream); stream->free(stream); cl_git_pass(error); } static void check_object_files(object_data *d) { cl_assert(git_path_exists(d->dir)); cl_assert(git_path_exists(d->file)); } static void cmp_objects(git_rawobj *o1, git_rawobj *o2) { cl_assert(o1->type == o2->type); cl_assert(o1->len == o2->len); if (o1->len > 0) cl_assert(memcmp(o1->data, o2->data, o1->len) == 0); } static void make_odb_dir(void) { cl_git_pass(p_mkdir(odb_dir, GIT_OBJECT_DIR_MODE)); } // Standard test form void test_body(object_data *d, git_rawobj *o) { git_odb *db; git_oid id1, id2; git_odb_object *obj; git_rawobj tmp; make_odb_dir(); cl_git_pass(git_odb_open(&db, odb_dir)); cl_git_pass(git_oid_fromstr(&id1, d->id)); streaming_write(&id2, db, o); cl_assert(git_oid_cmp(&id1, &id2) == 0); check_object_files(d); cl_git_pass(git_odb_read(&obj, db, &id1)); tmp.data = obj->buffer; tmp.len = obj->cached.size; tmp.type = obj->cached.type; cmp_objects(&tmp, o); git_odb_object_free(obj); git_odb_free(db); remove_object_files(d); } void test_object_raw_write__loose_object(void) { object_data commit = { "3d7f8a6af076c8c3f20071a8935cdbe8228594d1", "test-objects/3d", "test-objects/3d/7f8a6af076c8c3f20071a8935cdbe8228594d1", }; unsigned char commit_data[] = { 0x74, 0x72, 0x65, 0x65, 0x20, 0x64, 0x66, 0x66, 0x32, 0x64, 0x61, 0x39, 0x30, 0x62, 0x32, 0x35, 0x34, 0x65, 0x31, 0x62, 0x65, 0x62, 0x38, 0x38, 0x39, 0x64, 0x31, 0x66, 0x31, 0x66, 0x31, 0x32, 0x38, 0x38, 0x62, 0x65, 0x31, 0x38, 0x30, 0x33, 0x37, 0x38, 0x32, 0x64, 0x66, 0x0a, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x20, 0x41, 0x20, 0x55, 0x20, 0x54, 0x68, 0x6f, 0x72, 0x20, 0x3c, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x40, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x3e, 0x20, 0x31, 0x32, 0x32, 0x37, 0x38, 0x31, 0x34, 0x32, 0x39, 0x37, 0x20, 0x2b, 0x30, 0x30, 0x30, 0x30, 0x0a, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x74, 0x65, 0x72, 0x20, 0x43, 0x20, 0x4f, 0x20, 0x4d, 0x69, 0x74, 0x74, 0x65, 0x72, 0x20, 0x3c, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x74, 0x65, 0x72, 0x40, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x3e, 0x20, 0x31, 0x32, 0x32, 0x37, 0x38, 0x31, 0x34, 0x32, 0x39, 0x37, 0x20, 0x2b, 0x30, 0x30, 0x30, 0x30, 0x0a, 0x0a, 0x41, 0x20, 0x6f, 0x6e, 0x65, 0x2d, 0x6c, 0x69, 0x6e, 0x65, 0x20, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x20, 0x73, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x0a, 0x0a, 0x54, 0x68, 0x65, 0x20, 0x62, 0x6f, 0x64, 0x79, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2c, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x69, 0x6e, 0x67, 0x20, 0x66, 0x75, 0x72, 0x74, 0x68, 0x65, 0x72, 0x20, 0x65, 0x78, 0x70, 0x6c, 0x61, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x0a, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x75, 0x72, 0x70, 0x6f, 0x73, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x20, 0x69, 0x6e, 0x74, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x65, 0x64, 0x20, 0x62, 0x79, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x2e, 0x0a, 0x0a, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x2d, 0x6f, 0x66, 0x2d, 0x62, 0x79, 0x3a, 0x20, 0x41, 0x20, 0x55, 0x20, 0x54, 0x68, 0x6f, 0x72, 0x20, 0x3c, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x40, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x3e, 0x0a, }; git_rawobj commit_obj = { commit_data, sizeof(commit_data), GIT_OBJ_COMMIT }; test_body(&commit, &commit_obj); } void test_object_raw_write__loose_tree(void) { static object_data tree = { "dff2da90b254e1beb889d1f1f1288be1803782df", "test-objects/df", "test-objects/df/f2da90b254e1beb889d1f1f1288be1803782df", }; static unsigned char tree_data[] = { 0x31, 0x30, 0x30, 0x36, 0x34, 0x34, 0x20, 0x6f, 0x6e, 0x65, 0x00, 0x8b, 0x13, 0x78, 0x91, 0x79, 0x1f, 0xe9, 0x69, 0x27, 0xad, 0x78, 0xe6, 0x4b, 0x0a, 0xad, 0x7b, 0xde, 0xd0, 0x8b, 0xdc, 0x31, 0x30, 0x30, 0x36, 0x34, 0x34, 0x20, 0x73, 0x6f, 0x6d, 0x65, 0x00, 0xfd, 0x84, 0x30, 0xbc, 0x86, 0x4c, 0xfc, 0xd5, 0xf1, 0x0e, 0x55, 0x90, 0xf8, 0xa4, 0x47, 0xe0, 0x1b, 0x94, 0x2b, 0xfe, 0x31, 0x30, 0x30, 0x36, 0x34, 0x34, 0x20, 0x74, 0x77, 0x6f, 0x00, 0x78, 0x98, 0x19, 0x22, 0x61, 0x3b, 0x2a, 0xfb, 0x60, 0x25, 0x04, 0x2f, 0xf6, 0xbd, 0x87, 0x8a, 0xc1, 0x99, 0x4e, 0x85, 0x31, 0x30, 0x30, 0x36, 0x34, 0x34, 0x20, 0x7a, 0x65, 0x72, 0x6f, 0x00, 0xe6, 0x9d, 0xe2, 0x9b, 0xb2, 0xd1, 0xd6, 0x43, 0x4b, 0x8b, 0x29, 0xae, 0x77, 0x5a, 0xd8, 0xc2, 0xe4, 0x8c, 0x53, 0x91, }; static git_rawobj tree_obj = { tree_data, sizeof(tree_data), GIT_OBJ_TREE }; test_body(&tree, &tree_obj); } void test_object_raw_write__loose_tag(void) { static object_data tag = { "09d373e1dfdc16b129ceec6dd649739911541e05", "test-objects/09", "test-objects/09/d373e1dfdc16b129ceec6dd649739911541e05", }; static unsigned char tag_data[] = { 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x20, 0x33, 0x64, 0x37, 0x66, 0x38, 0x61, 0x36, 0x61, 0x66, 0x30, 0x37, 0x36, 0x63, 0x38, 0x63, 0x33, 0x66, 0x32, 0x30, 0x30, 0x37, 0x31, 0x61, 0x38, 0x39, 0x33, 0x35, 0x63, 0x64, 0x62, 0x65, 0x38, 0x32, 0x32, 0x38, 0x35, 0x39, 0x34, 0x64, 0x31, 0x0a, 0x74, 0x79, 0x70, 0x65, 0x20, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x0a, 0x74, 0x61, 0x67, 0x20, 0x76, 0x30, 0x2e, 0x30, 0x2e, 0x31, 0x0a, 0x74, 0x61, 0x67, 0x67, 0x65, 0x72, 0x20, 0x43, 0x20, 0x4f, 0x20, 0x4d, 0x69, 0x74, 0x74, 0x65, 0x72, 0x20, 0x3c, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x74, 0x65, 0x72, 0x40, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x3e, 0x20, 0x31, 0x32, 0x32, 0x37, 0x38, 0x31, 0x34, 0x32, 0x39, 0x37, 0x20, 0x2b, 0x30, 0x30, 0x30, 0x30, 0x0a, 0x0a, 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x61, 0x67, 0x20, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x20, 0x76, 0x30, 0x2e, 0x30, 0x2e, 0x31, 0x0a, }; static git_rawobj tag_obj = { tag_data, sizeof(tag_data), GIT_OBJ_TAG }; test_body(&tag, &tag_obj); } void test_object_raw_write__zero_length(void) { static object_data zero = { "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391", "test-objects/e6", "test-objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391", }; static unsigned char zero_data[] = { 0x00 /* dummy data */ }; static git_rawobj zero_obj = { zero_data, 0, GIT_OBJ_BLOB }; test_body(&zero, &zero_obj); } void test_object_raw_write__one_byte(void) { static object_data one = { "8b137891791fe96927ad78e64b0aad7bded08bdc", "test-objects/8b", "test-objects/8b/137891791fe96927ad78e64b0aad7bded08bdc", }; static unsigned char one_data[] = { 0x0a, }; static git_rawobj one_obj = { one_data, sizeof(one_data), GIT_OBJ_BLOB }; test_body(&one, &one_obj); } void test_object_raw_write__two_byte(void) { static object_data two = { "78981922613b2afb6025042ff6bd878ac1994e85", "test-objects/78", "test-objects/78/981922613b2afb6025042ff6bd878ac1994e85", }; static unsigned char two_data[] = { 0x61, 0x0a, }; static git_rawobj two_obj = { two_data, sizeof(two_data), GIT_OBJ_BLOB }; test_body(&two, &two_obj); } void test_object_raw_write__several_bytes(void) { static object_data some = { "fd8430bc864cfcd5f10e5590f8a447e01b942bfe", "test-objects/fd", "test-objects/fd/8430bc864cfcd5f10e5590f8a447e01b942bfe", }; static unsigned char some_data[] = { 0x2f, 0x2a, 0x0a, 0x20, 0x2a, 0x20, 0x54, 0x68, 0x69, 0x73, 0x20, 0x66, 0x69, 0x6c, 0x65, 0x20, 0x69, 0x73, 0x20, 0x66, 0x72, 0x65, 0x65, 0x20, 0x73, 0x6f, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0x3b, 0x20, 0x79, 0x6f, 0x75, 0x20, 0x63, 0x61, 0x6e, 0x20, 0x72, 0x65, 0x64, 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x20, 0x69, 0x74, 0x20, 0x61, 0x6e, 0x64, 0x2f, 0x6f, 0x72, 0x20, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0a, 0x20, 0x2a, 0x20, 0x69, 0x74, 0x20, 0x75, 0x6e, 0x64, 0x65, 0x72, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x65, 0x72, 0x6d, 0x73, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x47, 0x4e, 0x55, 0x20, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x6c, 0x20, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x20, 0x4c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x2c, 0x20, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x32, 0x2c, 0x0a, 0x20, 0x2a, 0x20, 0x61, 0x73, 0x20, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x65, 0x64, 0x20, 0x62, 0x79, 0x20, 0x74, 0x68, 0x65, 0x20, 0x46, 0x72, 0x65, 0x65, 0x20, 0x53, 0x6f, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0x20, 0x46, 0x6f, 0x75, 0x6e, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x0a, 0x20, 0x2a, 0x0a, 0x20, 0x2a, 0x20, 0x49, 0x6e, 0x20, 0x61, 0x64, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x74, 0x6f, 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x47, 0x4e, 0x55, 0x20, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x6c, 0x20, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x20, 0x4c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x2c, 0x0a, 0x20, 0x2a, 0x20, 0x74, 0x68, 0x65, 0x20, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x73, 0x20, 0x67, 0x69, 0x76, 0x65, 0x20, 0x79, 0x6f, 0x75, 0x20, 0x75, 0x6e, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x65, 0x64, 0x20, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x74, 0x6f, 0x20, 0x6c, 0x69, 0x6e, 0x6b, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x64, 0x0a, 0x20, 0x2a, 0x20, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x66, 0x69, 0x6c, 0x65, 0x20, 0x69, 0x6e, 0x74, 0x6f, 0x20, 0x63, 0x6f, 0x6d, 0x62, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x6f, 0x74, 0x68, 0x65, 0x72, 0x20, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x73, 0x2c, 0x0a, 0x20, 0x2a, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x74, 0x6f, 0x20, 0x64, 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x20, 0x74, 0x68, 0x6f, 0x73, 0x65, 0x20, 0x63, 0x6f, 0x6d, 0x62, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x77, 0x69, 0x74, 0x68, 0x6f, 0x75, 0x74, 0x20, 0x61, 0x6e, 0x79, 0x20, 0x72, 0x65, 0x73, 0x74, 0x72, 0x69, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x0a, 0x20, 0x2a, 0x20, 0x63, 0x6f, 0x6d, 0x69, 0x6e, 0x67, 0x20, 0x66, 0x72, 0x6f, 0x6d, 0x20, 0x74, 0x68, 0x65, 0x20, 0x75, 0x73, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x66, 0x69, 0x6c, 0x65, 0x2e, 0x20, 0x20, 0x28, 0x54, 0x68, 0x65, 0x20, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x6c, 0x20, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x20, 0x4c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x0a, 0x20, 0x2a, 0x20, 0x72, 0x65, 0x73, 0x74, 0x72, 0x69, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x64, 0x6f, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x79, 0x20, 0x69, 0x6e, 0x20, 0x6f, 0x74, 0x68, 0x65, 0x72, 0x20, 0x72, 0x65, 0x73, 0x70, 0x65, 0x63, 0x74, 0x73, 0x3b, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2c, 0x20, 0x74, 0x68, 0x65, 0x79, 0x20, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x0a, 0x20, 0x2a, 0x20, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x66, 0x69, 0x6c, 0x65, 0x2c, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x64, 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x77, 0x68, 0x65, 0x6e, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x6c, 0x69, 0x6e, 0x6b, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x74, 0x6f, 0x0a, 0x20, 0x2a, 0x20, 0x61, 0x20, 0x63, 0x6f, 0x6d, 0x62, 0x69, 0x6e, 0x65, 0x64, 0x20, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x2e, 0x29, 0x0a, 0x20, 0x2a, 0x0a, 0x20, 0x2a, 0x20, 0x54, 0x68, 0x69, 0x73, 0x20, 0x66, 0x69, 0x6c, 0x65, 0x20, 0x69, 0x73, 0x20, 0x64, 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x68, 0x6f, 0x70, 0x65, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x69, 0x74, 0x20, 0x77, 0x69, 0x6c, 0x6c, 0x20, 0x62, 0x65, 0x20, 0x75, 0x73, 0x65, 0x66, 0x75, 0x6c, 0x2c, 0x20, 0x62, 0x75, 0x74, 0x0a, 0x20, 0x2a, 0x20, 0x57, 0x49, 0x54, 0x48, 0x4f, 0x55, 0x54, 0x20, 0x41, 0x4e, 0x59, 0x20, 0x57, 0x41, 0x52, 0x52, 0x41, 0x4e, 0x54, 0x59, 0x3b, 0x20, 0x77, 0x69, 0x74, 0x68, 0x6f, 0x75, 0x74, 0x20, 0x65, 0x76, 0x65, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x69, 0x6d, 0x70, 0x6c, 0x69, 0x65, 0x64, 0x20, 0x77, 0x61, 0x72, 0x72, 0x61, 0x6e, 0x74, 0x79, 0x20, 0x6f, 0x66, 0x0a, 0x20, 0x2a, 0x20, 0x4d, 0x45, 0x52, 0x43, 0x48, 0x41, 0x4e, 0x54, 0x41, 0x42, 0x49, 0x4c, 0x49, 0x54, 0x59, 0x20, 0x6f, 0x72, 0x20, 0x46, 0x49, 0x54, 0x4e, 0x45, 0x53, 0x53, 0x20, 0x46, 0x4f, 0x52, 0x20, 0x41, 0x20, 0x50, 0x41, 0x52, 0x54, 0x49, 0x43, 0x55, 0x4c, 0x41, 0x52, 0x20, 0x50, 0x55, 0x52, 0x50, 0x4f, 0x53, 0x45, 0x2e, 0x20, 0x20, 0x53, 0x65, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, 0x47, 0x4e, 0x55, 0x0a, 0x20, 0x2a, 0x20, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x6c, 0x20, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x20, 0x4c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x6d, 0x6f, 0x72, 0x65, 0x20, 0x64, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x2e, 0x0a, 0x20, 0x2a, 0x0a, 0x20, 0x2a, 0x20, 0x59, 0x6f, 0x75, 0x20, 0x73, 0x68, 0x6f, 0x75, 0x6c, 0x64, 0x20, 0x68, 0x61, 0x76, 0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x64, 0x20, 0x61, 0x20, 0x63, 0x6f, 0x70, 0x79, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x47, 0x4e, 0x55, 0x20, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x6c, 0x20, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x20, 0x4c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x0a, 0x20, 0x2a, 0x20, 0x61, 0x6c, 0x6f, 0x6e, 0x67, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x3b, 0x20, 0x73, 0x65, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, 0x66, 0x69, 0x6c, 0x65, 0x20, 0x43, 0x4f, 0x50, 0x59, 0x49, 0x4e, 0x47, 0x2e, 0x20, 0x20, 0x49, 0x66, 0x20, 0x6e, 0x6f, 0x74, 0x2c, 0x20, 0x77, 0x72, 0x69, 0x74, 0x65, 0x20, 0x74, 0x6f, 0x0a, 0x20, 0x2a, 0x20, 0x74, 0x68, 0x65, 0x20, 0x46, 0x72, 0x65, 0x65, 0x20, 0x53, 0x6f, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0x20, 0x46, 0x6f, 0x75, 0x6e, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2c, 0x20, 0x35, 0x31, 0x20, 0x46, 0x72, 0x61, 0x6e, 0x6b, 0x6c, 0x69, 0x6e, 0x20, 0x53, 0x74, 0x72, 0x65, 0x65, 0x74, 0x2c, 0x20, 0x46, 0x69, 0x66, 0x74, 0x68, 0x20, 0x46, 0x6c, 0x6f, 0x6f, 0x72, 0x2c, 0x0a, 0x20, 0x2a, 0x20, 0x42, 0x6f, 0x73, 0x74, 0x6f, 0x6e, 0x2c, 0x20, 0x4d, 0x41, 0x20, 0x30, 0x32, 0x31, 0x31, 0x30, 0x2d, 0x31, 0x33, 0x30, 0x31, 0x2c, 0x20, 0x55, 0x53, 0x41, 0x2e, 0x0a, 0x20, 0x2a, 0x2f, 0x0a, }; static git_rawobj some_obj = { some_data, sizeof(some_data), GIT_OBJ_BLOB }; test_body(&some, &some_obj); } libgit2-0.19.0/tests-clar/object/tag/000077500000000000000000000000001216214232500172355ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/object/tag/list.c000066400000000000000000000050001216214232500203470ustar00rootroot00000000000000#include "clar_libgit2.h" #include "tag.h" static git_repository *g_repo; #define MAX_USED_TAGS 6 struct pattern_match_t { const char* pattern; const size_t expected_matches; const char* expected_results[MAX_USED_TAGS]; }; // Helpers static void ensure_tag_pattern_match(git_repository *repo, const struct pattern_match_t* data) { int already_found[MAX_USED_TAGS] = { 0 }; git_strarray tag_list; int error = 0; size_t sucessfully_found = 0; size_t i, j; cl_assert(data->expected_matches <= MAX_USED_TAGS); if ((error = git_tag_list_match(&tag_list, data->pattern, repo)) < 0) goto exit; if (tag_list.count != data->expected_matches) { error = GIT_ERROR; goto exit; } // we have to be prepared that tags come in any order. for (i = 0; i < tag_list.count; i++) { for (j = 0; j < data->expected_matches; j++) { if (!already_found[j] && !strcmp(data->expected_results[j], tag_list.strings[i])) { already_found[j] = 1; sucessfully_found++; break; } } } cl_assert_equal_i((int)sucessfully_found, (int)data->expected_matches); exit: git_strarray_free(&tag_list); cl_git_pass(error); } // Fixture setup and teardown void test_object_tag_list__initialize(void) { g_repo = cl_git_sandbox_init("testrepo"); } void test_object_tag_list__cleanup(void) { cl_git_sandbox_cleanup(); } void test_object_tag_list__list_all(void) { // list all tag names from the repository git_strarray tag_list; cl_git_pass(git_tag_list(&tag_list, g_repo)); cl_assert_equal_i((int)tag_list.count, 6); git_strarray_free(&tag_list); } static const struct pattern_match_t matches[] = { // All tags, including a packed one and two namespaced ones. { "", 6, { "e90810b", "point_to_blob", "test", "packed-tag", "foo/bar", "foo/foo/bar" } }, // beginning with { "t*", 1, { "test" } }, // ending with { "*b", 2, { "e90810b", "point_to_blob" } }, // exact match { "e", 0 }, { "e90810b", 1, { "e90810b" } }, // either or { "e90810[ab]", 1, { "e90810b" } }, // glob in the middle { "foo/*/bar", 1, { "foo/foo/bar" } }, // The matching of '*' is based on plain string matching analog to the regular expression ".*" // => a '/' in the tag name has no special meaning. // Compare to `git tag -l "*bar"` { "*bar", 2, { "foo/bar", "foo/foo/bar" } }, // End of list { NULL } }; void test_object_tag_list__list_by_pattern(void) { // list all tag names from the repository matching a specified pattern size_t i = 0; while (matches[i].pattern) ensure_tag_pattern_match(g_repo, &matches[i++]); } libgit2-0.19.0/tests-clar/object/tag/peel.c000066400000000000000000000032401216214232500203250ustar00rootroot00000000000000#include "clar_libgit2.h" #include "tag.h" static git_repository *repo; static git_tag *tag; static git_object *target; void test_object_tag_peel__initialize(void) { cl_fixture_sandbox("testrepo.git"); cl_git_pass(git_repository_open(&repo, "testrepo.git")); } void test_object_tag_peel__cleanup(void) { git_tag_free(tag); tag = NULL; git_object_free(target); target = NULL; git_repository_free(repo); repo = NULL; cl_fixture_cleanup("testrepo.git"); } static void retrieve_tag_from_oid(git_tag **tag_out, git_repository *repo, const char *sha) { git_oid oid; cl_git_pass(git_oid_fromstr(&oid, sha)); cl_git_pass(git_tag_lookup(tag_out, repo, &oid)); } void test_object_tag_peel__can_peel_to_a_commit(void) { retrieve_tag_from_oid(&tag, repo, "7b4384978d2493e851f9cca7858815fac9b10980"); cl_git_pass(git_tag_peel(&target, tag)); cl_assert(git_object_type(target) == GIT_OBJ_COMMIT); cl_git_pass(git_oid_streq(git_object_id(target), "e90810b8df3e80c413d903f631643c716887138d")); } void test_object_tag_peel__can_peel_several_nested_tags_to_a_commit(void) { retrieve_tag_from_oid(&tag, repo, "b25fa35b38051e4ae45d4222e795f9df2e43f1d1"); cl_git_pass(git_tag_peel(&target, tag)); cl_assert(git_object_type(target) == GIT_OBJ_COMMIT); cl_git_pass(git_oid_streq(git_object_id(target), "e90810b8df3e80c413d903f631643c716887138d")); } void test_object_tag_peel__can_peel_to_a_non_commit(void) { retrieve_tag_from_oid(&tag, repo, "521d87c1ec3aef9824daf6d96cc0ae3710766d91"); cl_git_pass(git_tag_peel(&target, tag)); cl_assert(git_object_type(target) == GIT_OBJ_BLOB); cl_git_pass(git_oid_streq(git_object_id(target), "1385f264afb75a56a5bec74243be9b367ba4ca08")); } libgit2-0.19.0/tests-clar/object/tag/read.c000066400000000000000000000076461216214232500203310ustar00rootroot00000000000000#include "clar_libgit2.h" #include "tag.h" static const char *tag1_id = "b25fa35b38051e4ae45d4222e795f9df2e43f1d1"; static const char *tag2_id = "7b4384978d2493e851f9cca7858815fac9b10980"; static const char *tagged_commit = "e90810b8df3e80c413d903f631643c716887138d"; static const char *bad_tag_id = "eda9f45a2a98d4c17a09d681d88569fa4ea91755"; static const char *badly_tagged_commit = "e90810b8df3e80c413d903f631643c716887138d"; static const char *short_tag_id = "5da7760512a953e3c7c4e47e4392c7a4338fb729"; static const char *short_tagged_commit = "4a5ed60bafcf4638b7c8356bd4ce1916bfede93c"; static const char *taggerless = "4a23e2e65ad4e31c4c9db7dc746650bfad082679"; static git_repository *g_repo; // Fixture setup and teardown void test_object_tag_read__initialize(void) { g_repo = cl_git_sandbox_init("testrepo"); } void test_object_tag_read__cleanup(void) { cl_git_sandbox_cleanup(); } void test_object_tag_read__parse(void) { // read and parse a tag from the repository git_tag *tag1, *tag2; git_commit *commit; git_oid id1, id2, id_commit; git_oid_fromstr(&id1, tag1_id); git_oid_fromstr(&id2, tag2_id); git_oid_fromstr(&id_commit, tagged_commit); cl_git_pass(git_tag_lookup(&tag1, g_repo, &id1)); cl_assert_equal_s(git_tag_name(tag1), "test"); cl_assert(git_tag_target_type(tag1) == GIT_OBJ_TAG); cl_git_pass(git_tag_target((git_object **)&tag2, tag1)); cl_assert(tag2 != NULL); cl_assert(git_oid_cmp(&id2, git_tag_id(tag2)) == 0); cl_git_pass(git_tag_target((git_object **)&commit, tag2)); cl_assert(commit != NULL); cl_assert(git_oid_cmp(&id_commit, git_commit_id(commit)) == 0); git_tag_free(tag1); git_tag_free(tag2); git_commit_free(commit); } void test_object_tag_read__parse_without_tagger(void) { // read and parse a tag without a tagger field git_repository *bad_tag_repo; git_tag *bad_tag; git_commit *commit; git_oid id, id_commit; // TODO: This is a little messy cl_git_pass(git_repository_open(&bad_tag_repo, cl_fixture("bad_tag.git"))); git_oid_fromstr(&id, bad_tag_id); git_oid_fromstr(&id_commit, badly_tagged_commit); cl_git_pass(git_tag_lookup(&bad_tag, bad_tag_repo, &id)); cl_assert(bad_tag != NULL); cl_assert_equal_s(git_tag_name(bad_tag), "e90810b"); cl_assert(git_oid_cmp(&id, git_tag_id(bad_tag)) == 0); cl_assert(bad_tag->tagger == NULL); cl_git_pass(git_tag_target((git_object **)&commit, bad_tag)); cl_assert(commit != NULL); cl_assert(git_oid_cmp(&id_commit, git_commit_id(commit)) == 0); git_tag_free(bad_tag); git_commit_free(commit); git_repository_free(bad_tag_repo); } void test_object_tag_read__parse_without_message(void) { // read and parse a tag without a message field git_repository *short_tag_repo; git_tag *short_tag; git_commit *commit; git_oid id, id_commit; // TODO: This is a little messy cl_git_pass(git_repository_open(&short_tag_repo, cl_fixture("short_tag.git"))); git_oid_fromstr(&id, short_tag_id); git_oid_fromstr(&id_commit, short_tagged_commit); cl_git_pass(git_tag_lookup(&short_tag, short_tag_repo, &id)); cl_assert(short_tag != NULL); cl_assert_equal_s(git_tag_name(short_tag), "no_description"); cl_assert(git_oid_cmp(&id, git_tag_id(short_tag)) == 0); cl_assert(short_tag->message == NULL); cl_git_pass(git_tag_target((git_object **)&commit, short_tag)); cl_assert(commit != NULL); cl_assert(git_oid_cmp(&id_commit, git_commit_id(commit)) == 0); git_tag_free(short_tag); git_commit_free(commit); git_repository_free(short_tag_repo); } void test_object_tag_read__without_tagger_nor_message(void) { git_tag *tag; git_oid id; git_repository *repo; cl_git_pass(git_repository_open(&repo, cl_fixture("testrepo.git"))); cl_git_pass(git_oid_fromstr(&id, taggerless)); cl_git_pass(git_tag_lookup(&tag, repo, &id)); cl_assert_equal_s(git_tag_name(tag), "taggerless"); cl_assert(git_tag_target_type(tag) == GIT_OBJ_COMMIT); cl_assert(tag->message == NULL); cl_assert(tag->tagger == NULL); git_tag_free(tag); git_repository_free(repo); } libgit2-0.19.0/tests-clar/object/tag/write.c000066400000000000000000000173151216214232500205420ustar00rootroot00000000000000#include "clar_libgit2.h" static const char* tagger_name = "Vicent Marti"; static const char* tagger_email = "vicent@github.com"; static const char* tagger_message = "This is my tag.\n\nThere are many tags, but this one is mine\n"; static const char *tag2_id = "7b4384978d2493e851f9cca7858815fac9b10980"; static const char *tagged_commit = "e90810b8df3e80c413d903f631643c716887138d"; static git_repository *g_repo; // Fixture setup and teardown void test_object_tag_write__initialize(void) { g_repo = cl_git_sandbox_init("testrepo"); } void test_object_tag_write__cleanup(void) { cl_git_sandbox_cleanup(); } void test_object_tag_write__basic(void) { // write a tag to the repository and read it again git_tag *tag; git_oid target_id, tag_id; git_signature *tagger; const git_signature *tagger1; git_reference *ref_tag; git_object *target; git_oid_fromstr(&target_id, tagged_commit); cl_git_pass(git_object_lookup(&target, g_repo, &target_id, GIT_OBJ_COMMIT)); /* create signature */ cl_git_pass(git_signature_new(&tagger, tagger_name, tagger_email, 123456789, 60)); cl_git_pass( git_tag_create(&tag_id, g_repo, "the-tag", target, tagger, tagger_message, 0) ); git_object_free(target); git_signature_free(tagger); cl_git_pass(git_tag_lookup(&tag, g_repo, &tag_id)); cl_assert(git_oid_cmp(git_tag_target_id(tag), &target_id) == 0); /* Check attributes were set correctly */ tagger1 = git_tag_tagger(tag); cl_assert(tagger1 != NULL); cl_assert_equal_s(tagger1->name, tagger_name); cl_assert_equal_s(tagger1->email, tagger_email); cl_assert(tagger1->when.time == 123456789); cl_assert(tagger1->when.offset == 60); cl_assert_equal_s(git_tag_message(tag), tagger_message); cl_git_pass(git_reference_lookup(&ref_tag, g_repo, "refs/tags/the-tag")); cl_assert(git_oid_cmp(git_reference_target(ref_tag), &tag_id) == 0); cl_git_pass(git_reference_delete(ref_tag)); git_reference_free(ref_tag); git_tag_free(tag); } void test_object_tag_write__overwrite(void) { // Attempt to write a tag bearing the same name than an already existing tag git_oid target_id, tag_id; git_signature *tagger; git_object *target; git_oid_fromstr(&target_id, tagged_commit); cl_git_pass(git_object_lookup(&target, g_repo, &target_id, GIT_OBJ_COMMIT)); /* create signature */ cl_git_pass(git_signature_new(&tagger, tagger_name, tagger_email, 123456789, 60)); cl_assert_equal_i(GIT_EEXISTS, git_tag_create( &tag_id, /* out id */ g_repo, "e90810b", target, tagger, tagger_message, 0)); git_object_free(target); git_signature_free(tagger); } void test_object_tag_write__replace(void) { // Replace an already existing tag git_oid target_id, tag_id, old_tag_id; git_signature *tagger; git_reference *ref_tag; git_object *target; git_oid_fromstr(&target_id, tagged_commit); cl_git_pass(git_object_lookup(&target, g_repo, &target_id, GIT_OBJ_COMMIT)); cl_git_pass(git_reference_lookup(&ref_tag, g_repo, "refs/tags/e90810b")); git_oid_cpy(&old_tag_id, git_reference_target(ref_tag)); git_reference_free(ref_tag); /* create signature */ cl_git_pass(git_signature_new(&tagger, tagger_name, tagger_email, 123456789, 60)); cl_git_pass(git_tag_create( &tag_id, /* out id */ g_repo, "e90810b", target, tagger, tagger_message, 1)); git_object_free(target); git_signature_free(tagger); cl_git_pass(git_reference_lookup(&ref_tag, g_repo, "refs/tags/e90810b")); cl_assert(git_oid_cmp(git_reference_target(ref_tag), &tag_id) == 0); cl_assert(git_oid_cmp(git_reference_target(ref_tag), &old_tag_id) != 0); git_reference_free(ref_tag); } void test_object_tag_write__lightweight(void) { // write a lightweight tag to the repository and read it again git_oid target_id, object_id; git_reference *ref_tag; git_object *target; git_oid_fromstr(&target_id, tagged_commit); cl_git_pass(git_object_lookup(&target, g_repo, &target_id, GIT_OBJ_COMMIT)); cl_git_pass(git_tag_create_lightweight( &object_id, g_repo, "light-tag", target, 0)); git_object_free(target); cl_assert(git_oid_cmp(&object_id, &target_id) == 0); cl_git_pass(git_reference_lookup(&ref_tag, g_repo, "refs/tags/light-tag")); cl_assert(git_oid_cmp(git_reference_target(ref_tag), &target_id) == 0); cl_git_pass(git_tag_delete(g_repo, "light-tag")); git_reference_free(ref_tag); } void test_object_tag_write__lightweight_over_existing(void) { // Attempt to write a lightweight tag bearing the same name than an already existing tag git_oid target_id, object_id, existing_object_id; git_object *target; git_oid_fromstr(&target_id, tagged_commit); cl_git_pass(git_object_lookup(&target, g_repo, &target_id, GIT_OBJ_COMMIT)); cl_assert_equal_i(GIT_EEXISTS, git_tag_create_lightweight( &object_id, g_repo, "e90810b", target, 0)); git_oid_fromstr(&existing_object_id, tag2_id); cl_assert(git_oid_cmp(&object_id, &existing_object_id) == 0); git_object_free(target); } void test_object_tag_write__delete(void) { // Delete an already existing tag git_reference *ref_tag; cl_git_pass(git_tag_delete(g_repo, "e90810b")); cl_git_fail(git_reference_lookup(&ref_tag, g_repo, "refs/tags/e90810b")); git_reference_free(ref_tag); } void test_object_tag_write__creating_with_an_invalid_name_returns_EINVALIDSPEC(void) { git_oid target_id, tag_id; git_signature *tagger; git_object *target; git_oid_fromstr(&target_id, tagged_commit); cl_git_pass(git_object_lookup(&target, g_repo, &target_id, GIT_OBJ_COMMIT)); cl_git_pass(git_signature_new(&tagger, tagger_name, tagger_email, 123456789, 60)); cl_assert_equal_i(GIT_EINVALIDSPEC, git_tag_create(&tag_id, g_repo, "Inv@{id", target, tagger, tagger_message, 0) ); cl_assert_equal_i(GIT_EINVALIDSPEC, git_tag_create_lightweight(&tag_id, g_repo, "Inv@{id", target, 0) ); git_object_free(target); git_signature_free(tagger); } void test_object_tag_write__deleting_with_an_invalid_name_returns_EINVALIDSPEC(void) { cl_assert_equal_i(GIT_EINVALIDSPEC, git_tag_delete(g_repo, "Inv@{id")); } void create_annotation(git_oid *tag_id, const char *name) { git_object *target; git_oid target_id; git_signature *tagger; cl_git_pass(git_signature_new(&tagger, tagger_name, tagger_email, 123456789, 60)); git_oid_fromstr(&target_id, tagged_commit); cl_git_pass(git_object_lookup(&target, g_repo, &target_id, GIT_OBJ_COMMIT)); cl_git_pass(git_tag_annotation_create(tag_id, g_repo, name, target, tagger, "boom!")); git_object_free(target); git_signature_free(tagger); } void test_object_tag_write__creating_an_annotation_stores_the_new_object_in_the_odb(void) { git_oid tag_id; git_tag *tag; create_annotation(&tag_id, "new_tag"); cl_git_pass(git_tag_lookup(&tag, g_repo, &tag_id)); cl_assert_equal_s("new_tag", git_tag_name(tag)); git_tag_free(tag); } void test_object_tag_write__creating_an_annotation_does_not_create_a_reference(void) { git_oid tag_id; git_reference *tag_ref; create_annotation(&tag_id, "new_tag"); cl_git_fail_with(git_reference_lookup(&tag_ref, g_repo, "refs/tags/new_tag"), GIT_ENOTFOUND); } libgit2-0.19.0/tests-clar/object/tree/000077500000000000000000000000001216214232500174215ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/object/tree/attributes.c000066400000000000000000000060521216214232500217560ustar00rootroot00000000000000#include "clar_libgit2.h" #include "tree.h" static const char *blob_oid = "3d0970ec547fc41ef8a5882dde99c6adce65b021"; static const char *tree_oid = "1b05fdaa881ee45b48cbaa5e9b037d667a47745e"; void test_object_tree_attributes__ensure_correctness_of_attributes_on_insertion(void) { git_treebuilder *builder; git_oid oid; cl_git_pass(git_oid_fromstr(&oid, blob_oid)); cl_git_pass(git_treebuilder_create(&builder, NULL)); cl_git_fail(git_treebuilder_insert(NULL, builder, "one.txt", &oid, (git_filemode_t)0777777)); cl_git_fail(git_treebuilder_insert(NULL, builder, "one.txt", &oid, (git_filemode_t)0100666)); cl_git_fail(git_treebuilder_insert(NULL, builder, "one.txt", &oid, (git_filemode_t)0000001)); git_treebuilder_free(builder); } void test_object_tree_attributes__group_writable_tree_entries_created_with_an_antique_git_version_can_still_be_accessed(void) { git_repository *repo; git_oid tid; git_tree *tree; const git_tree_entry *entry; cl_git_pass(git_repository_open(&repo, cl_fixture("deprecated-mode.git"))); cl_git_pass(git_oid_fromstr(&tid, tree_oid)); cl_git_pass(git_tree_lookup(&tree, repo, &tid)); entry = git_tree_entry_byname(tree, "old_mode.txt"); cl_assert_equal_i( GIT_FILEMODE_BLOB, git_tree_entry_filemode(entry)); git_tree_free(tree); git_repository_free(repo); } void test_object_tree_attributes__treebuilder_reject_invalid_filemode(void) { git_treebuilder *builder; git_oid bid; const git_tree_entry *entry; cl_git_pass(git_oid_fromstr(&bid, blob_oid)); cl_git_pass(git_treebuilder_create(&builder, NULL)); cl_git_fail(git_treebuilder_insert( &entry, builder, "normalized.txt", &bid, GIT_FILEMODE_BLOB_GROUP_WRITABLE)); git_treebuilder_free(builder); } void test_object_tree_attributes__normalize_attributes_when_creating_a_tree_from_an_existing_one(void) { git_repository *repo; git_treebuilder *builder; git_oid tid, tid2; git_tree *tree; const git_tree_entry *entry; repo = cl_git_sandbox_init("deprecated-mode.git"); cl_git_pass(git_oid_fromstr(&tid, tree_oid)); cl_git_pass(git_tree_lookup(&tree, repo, &tid)); cl_git_pass(git_treebuilder_create(&builder, tree)); entry = git_treebuilder_get(builder, "old_mode.txt"); cl_assert_equal_i( GIT_FILEMODE_BLOB, git_tree_entry_filemode(entry)); cl_git_pass(git_treebuilder_write(&tid2, repo, builder)); git_treebuilder_free(builder); git_tree_free(tree); cl_git_pass(git_tree_lookup(&tree, repo, &tid2)); entry = git_tree_entry_byname(tree, "old_mode.txt"); cl_assert_equal_i( GIT_FILEMODE_BLOB, git_tree_entry_filemode(entry)); git_tree_free(tree); cl_git_sandbox_cleanup(); } void test_object_tree_attributes__normalize_600(void) { git_oid id; git_tree *tree; git_repository *repo; const git_tree_entry *entry; repo = cl_git_sandbox_init("deprecated-mode.git"); git_oid_fromstr(&id, "0810fb7818088ff5ac41ee49199b51473b1bd6c7"); cl_git_pass(git_tree_lookup(&tree, repo, &id)); entry = git_tree_entry_byname(tree, "ListaTeste.xml"); cl_assert_equal_i(entry->attr, GIT_FILEMODE_BLOB); git_tree_free(tree); cl_git_sandbox_cleanup(); } libgit2-0.19.0/tests-clar/object/tree/duplicateentries.c000066400000000000000000000106621216214232500231360ustar00rootroot00000000000000#include "clar_libgit2.h" #include "tree.h" static git_repository *_repo; void test_object_tree_duplicateentries__initialize(void) { _repo = cl_git_sandbox_init("testrepo"); } void test_object_tree_duplicateentries__cleanup(void) { cl_git_sandbox_cleanup(); } /* * $ git show --format=raw refs/heads/dir * commit 144344043ba4d4a405da03de3844aa829ae8be0e * tree d52a8fe84ceedf260afe4f0287bbfca04a117e83 * parent cf80f8de9f1185bf3a05f993f6121880dd0cfbc9 * author Ben Straub 1343755506 -0700 * committer Ben Straub 1343755506 -0700 * * Change a file mode * * diff --git a/a/b.txt b/a/b.txt * old mode 100644 * new mode 100755 * * $ git ls-tree d52a8fe84ceedf260afe4f0287bbfca04a117e83 * 100644 blob a8233120f6ad708f843d861ce2b7228ec4e3dec6 README * 040000 tree 4e0883eeeeebc1fb1735161cea82f7cb5fab7e63 a * 100644 blob 45b983be36b73c0788dc9cbcb76cbb80fc7bb057 branch_file.txt * 100644 blob a71586c1dfe8a71c6cbf6c129f404c5642ff31bd new.txt */ static void tree_checker( git_oid *tid, const char *expected_sha, git_filemode_t expected_filemode) { git_tree *tree; const git_tree_entry *entry; git_oid oid; cl_git_pass(git_tree_lookup(&tree, _repo, tid)); cl_assert_equal_i(1, (int)git_tree_entrycount(tree)); entry = git_tree_entry_byindex(tree, 0); cl_git_pass(git_oid_fromstr(&oid, expected_sha)); cl_assert_equal_i(0, git_oid_cmp(&oid, git_tree_entry_id(entry))); cl_assert_equal_i(expected_filemode, git_tree_entry_filemode(entry)); git_tree_free(tree); } static void tree_creator(git_oid *out, void (*fn)(git_treebuilder *)) { git_treebuilder *builder; cl_git_pass(git_treebuilder_create(&builder, NULL)); fn(builder); cl_git_pass(git_treebuilder_write(out, _repo, builder)); git_treebuilder_free(builder); } static void two_blobs(git_treebuilder *bld) { git_oid oid; const git_tree_entry *entry; cl_git_pass(git_oid_fromstr(&oid, "a8233120f6ad708f843d861ce2b7228ec4e3dec6")); /* blob oid (README) */ cl_git_pass(git_treebuilder_insert( &entry, bld, "duplicate", &oid, GIT_FILEMODE_BLOB)); cl_git_pass(git_oid_fromstr(&oid, "a71586c1dfe8a71c6cbf6c129f404c5642ff31bd")); /* blob oid (new.txt) */ cl_git_pass(git_treebuilder_insert( &entry, bld, "duplicate", &oid, GIT_FILEMODE_BLOB)); } static void one_blob_and_one_tree(git_treebuilder *bld) { git_oid oid; const git_tree_entry *entry; cl_git_pass(git_oid_fromstr(&oid, "a8233120f6ad708f843d861ce2b7228ec4e3dec6")); /* blob oid (README) */ cl_git_pass(git_treebuilder_insert( &entry, bld, "duplicate", &oid, GIT_FILEMODE_BLOB)); cl_git_pass(git_oid_fromstr(&oid, "4e0883eeeeebc1fb1735161cea82f7cb5fab7e63")); /* tree oid (a) */ cl_git_pass(git_treebuilder_insert( &entry, bld, "duplicate", &oid, GIT_FILEMODE_TREE)); } void test_object_tree_duplicateentries__cannot_create_a_duplicate_entry_through_the_treebuilder(void) { git_oid tid; tree_creator(&tid, two_blobs); tree_checker(&tid, "a71586c1dfe8a71c6cbf6c129f404c5642ff31bd", GIT_FILEMODE_BLOB); tree_creator(&tid, one_blob_and_one_tree); tree_checker(&tid, "4e0883eeeeebc1fb1735161cea82f7cb5fab7e63", GIT_FILEMODE_TREE); } static void add_fake_conflicts(git_index *index) { git_index_entry ancestor_entry, our_entry, their_entry; memset(&ancestor_entry, 0x0, sizeof(git_index_entry)); memset(&our_entry, 0x0, sizeof(git_index_entry)); memset(&their_entry, 0x0, sizeof(git_index_entry)); ancestor_entry.path = "duplicate"; ancestor_entry.mode = GIT_FILEMODE_BLOB; ancestor_entry.flags |= (1 << GIT_IDXENTRY_STAGESHIFT); git_oid_fromstr(&ancestor_entry.oid, "a8233120f6ad708f843d861ce2b7228ec4e3dec6"); our_entry.path = "duplicate"; our_entry.mode = GIT_FILEMODE_BLOB; ancestor_entry.flags |= (2 << GIT_IDXENTRY_STAGESHIFT); git_oid_fromstr(&our_entry.oid, "45b983be36b73c0788dc9cbcb76cbb80fc7bb057"); their_entry.path = "duplicate"; their_entry.mode = GIT_FILEMODE_BLOB; ancestor_entry.flags |= (3 << GIT_IDXENTRY_STAGESHIFT); git_oid_fromstr(&their_entry.oid, "a71586c1dfe8a71c6cbf6c129f404c5642ff31bd"); cl_git_pass(git_index_conflict_add(index, &ancestor_entry, &our_entry, &their_entry)); } void test_object_tree_duplicateentries__cannot_create_a_duplicate_entry_building_a_tree_from_a_index_with_conflicts(void) { git_index *index; git_oid tid; cl_git_pass(git_repository_index(&index, _repo)); add_fake_conflicts(index); cl_assert_equal_i(GIT_EUNMERGED, git_index_write_tree(&tid, index)); git_index_free(index); } libgit2-0.19.0/tests-clar/object/tree/frompath.c000066400000000000000000000042301216214232500214040ustar00rootroot00000000000000#include "clar_libgit2.h" static git_repository *repo; static git_tree *tree; void test_object_tree_frompath__initialize(void) { git_oid id; const char *tree_with_subtrees_oid = "ae90f12eea699729ed24555e40b9fd669da12a12"; cl_git_pass(git_repository_open(&repo, cl_fixture("testrepo.git"))); cl_assert(repo != NULL); cl_git_pass(git_oid_fromstr(&id, tree_with_subtrees_oid)); cl_git_pass(git_tree_lookup(&tree, repo, &id)); cl_assert(tree != NULL); } void test_object_tree_frompath__cleanup(void) { git_tree_free(tree); tree = NULL; git_repository_free(repo); repo = NULL; } static void assert_tree_from_path( git_tree *root, const char *path, const char *expected_entry_name) { git_tree_entry *entry; cl_git_pass(git_tree_entry_bypath(&entry, root, path)); cl_assert_equal_s(git_tree_entry_name(entry), expected_entry_name); git_tree_entry_free(entry); } void test_object_tree_frompath__retrieve_tree_from_path_to_treeentry(void) { git_tree_entry *e; assert_tree_from_path(tree, "README", "README"); assert_tree_from_path(tree, "ab/de/fgh/1.txt", "1.txt"); assert_tree_from_path(tree, "ab/de/fgh", "fgh"); assert_tree_from_path(tree, "ab/de/fgh/", "fgh"); assert_tree_from_path(tree, "ab/de", "de"); assert_tree_from_path(tree, "ab/", "ab"); assert_tree_from_path(tree, "ab/de/", "de"); cl_assert_equal_i(GIT_ENOTFOUND, git_tree_entry_bypath(&e, tree, "i-do-not-exist.txt")); cl_assert_equal_i(GIT_ENOTFOUND, git_tree_entry_bypath(&e, tree, "README/")); cl_assert_equal_i(GIT_ENOTFOUND, git_tree_entry_bypath(&e, tree, "ab/de/fgh/i-do-not-exist.txt")); cl_assert_equal_i(GIT_ENOTFOUND, git_tree_entry_bypath(&e, tree, "nope/de/fgh/1.txt")); cl_assert_equal_i(GIT_ENOTFOUND, git_tree_entry_bypath(&e, tree, "ab/me-neither/fgh/2.txt")); cl_assert_equal_i(GIT_ENOTFOUND, git_tree_entry_bypath(&e, tree, "ab/me-neither/fgh/2.txt/")); } void test_object_tree_frompath__fail_when_processing_an_invalid_path(void) { git_tree_entry *e; cl_must_fail(git_tree_entry_bypath(&e, tree, "/")); cl_must_fail(git_tree_entry_bypath(&e, tree, "/ab")); cl_must_fail(git_tree_entry_bypath(&e, tree, "/ab/de")); cl_must_fail(git_tree_entry_bypath(&e, tree, "ab//de")); } libgit2-0.19.0/tests-clar/object/tree/read.c000066400000000000000000000035141216214232500205030ustar00rootroot00000000000000#include "clar_libgit2.h" #include "tree.h" static const char *tree_oid = "1810dff58d8a660512d4832e740f692884338ccd"; static git_repository *g_repo; // Fixture setup and teardown void test_object_tree_read__initialize(void) { g_repo = cl_git_sandbox_init("testrepo"); } void test_object_tree_read__cleanup(void) { cl_git_sandbox_cleanup(); } void test_object_tree_read__loaded(void) { // acces randomly the entries on a loaded tree git_oid id; git_tree *tree; git_oid_fromstr(&id, tree_oid); cl_git_pass(git_tree_lookup(&tree, g_repo, &id)); cl_assert(git_tree_entry_byname(tree, "README") != NULL); cl_assert(git_tree_entry_byname(tree, "NOTEXISTS") == NULL); cl_assert(git_tree_entry_byname(tree, "") == NULL); cl_assert(git_tree_entry_byindex(tree, 0) != NULL); cl_assert(git_tree_entry_byindex(tree, 2) != NULL); cl_assert(git_tree_entry_byindex(tree, 3) == NULL); cl_assert(git_tree_entry_byindex(tree, (unsigned int)-1) == NULL); git_tree_free(tree); } void test_object_tree_read__two(void) { // read a tree from the repository git_oid id; git_tree *tree; const git_tree_entry *entry; git_object *obj; git_oid_fromstr(&id, tree_oid); cl_git_pass(git_tree_lookup(&tree, g_repo, &id)); cl_assert(git_tree_entrycount(tree) == 3); /* GH-86: git_object_lookup() should also check the type if the object comes from the cache */ cl_assert(git_object_lookup(&obj, g_repo, &id, GIT_OBJ_TREE) == 0); cl_assert(obj != NULL); git_object_free(obj); obj = NULL; cl_git_fail(git_object_lookup(&obj, g_repo, &id, GIT_OBJ_BLOB)); cl_assert(obj == NULL); entry = git_tree_entry_byname(tree, "README"); cl_assert(entry != NULL); cl_assert_equal_s(git_tree_entry_name(entry), "README"); cl_git_pass(git_tree_entry_to_object(&obj, g_repo, entry)); cl_assert(obj != NULL); git_object_free(obj); git_tree_free(tree); } libgit2-0.19.0/tests-clar/object/tree/walk.c000066400000000000000000000037311216214232500205270ustar00rootroot00000000000000#include "clar_libgit2.h" #include "tree.h" static const char *tree_oid = "1810dff58d8a660512d4832e740f692884338ccd"; static git_repository *g_repo; void test_object_tree_walk__initialize(void) { g_repo = cl_git_sandbox_init("testrepo"); } void test_object_tree_walk__cleanup(void) { cl_git_sandbox_cleanup(); } static int treewalk_count_cb( const char *root, const git_tree_entry *entry, void *payload) { int *count = payload; GIT_UNUSED(root); GIT_UNUSED(entry); (*count) += 1; return 0; } void test_object_tree_walk__0(void) { git_oid id; git_tree *tree; int ct; git_oid_fromstr(&id, tree_oid); cl_git_pass(git_tree_lookup(&tree, g_repo, &id)); ct = 0; cl_git_pass(git_tree_walk(tree, GIT_TREEWALK_PRE, treewalk_count_cb, &ct)); cl_assert_equal_i(3, ct); ct = 0; cl_git_pass(git_tree_walk(tree, GIT_TREEWALK_POST, treewalk_count_cb, &ct)); cl_assert_equal_i(3, ct); git_tree_free(tree); } static int treewalk_stop_cb( const char *root, const git_tree_entry *entry, void *payload) { int *count = payload; GIT_UNUSED(root); GIT_UNUSED(entry); (*count) += 1; return (*count == 2) ? -1 : 0; } static int treewalk_stop_immediately_cb( const char *root, const git_tree_entry *entry, void *payload) { GIT_UNUSED(root); GIT_UNUSED(entry); GIT_UNUSED(payload); return -100; } void test_object_tree_walk__1(void) { git_oid id; git_tree *tree; int ct; git_oid_fromstr(&id, tree_oid); cl_git_pass(git_tree_lookup(&tree, g_repo, &id)); ct = 0; cl_assert_equal_i( GIT_EUSER, git_tree_walk(tree, GIT_TREEWALK_PRE, treewalk_stop_cb, &ct)); cl_assert_equal_i(2, ct); ct = 0; cl_assert_equal_i( GIT_EUSER, git_tree_walk(tree, GIT_TREEWALK_POST, treewalk_stop_cb, &ct)); cl_assert_equal_i(2, ct); cl_assert_equal_i( GIT_EUSER, git_tree_walk( tree, GIT_TREEWALK_PRE, treewalk_stop_immediately_cb, NULL)); cl_assert_equal_i( GIT_EUSER, git_tree_walk( tree, GIT_TREEWALK_POST, treewalk_stop_immediately_cb, NULL)); git_tree_free(tree); } libgit2-0.19.0/tests-clar/object/tree/write.c000066400000000000000000000175151216214232500207300ustar00rootroot00000000000000#include "clar_libgit2.h" #include "tree.h" static const char *blob_oid = "fa49b077972391ad58037050f2a75f74e3671e92"; static const char *first_tree = "181037049a54a1eb5fab404658a3a250b44335d7"; static const char *second_tree = "f60079018b664e4e79329a7ef9559c8d9e0378d1"; static const char *third_tree = "eb86d8b81d6adbd5290a935d6c9976882de98488"; static git_repository *g_repo; // Fixture setup and teardown void test_object_tree_write__initialize(void) { g_repo = cl_git_sandbox_init("testrepo"); } void test_object_tree_write__cleanup(void) { cl_git_sandbox_cleanup(); } void test_object_tree_write__from_memory(void) { // write a tree from a memory git_treebuilder *builder; git_tree *tree; git_oid id, bid, rid, id2; git_oid_fromstr(&id, first_tree); git_oid_fromstr(&id2, second_tree); git_oid_fromstr(&bid, blob_oid); //create a second tree from first tree using `git_treebuilder_insert` on REPOSITORY_FOLDER. cl_git_pass(git_tree_lookup(&tree, g_repo, &id)); cl_git_pass(git_treebuilder_create(&builder, tree)); cl_git_fail(git_treebuilder_insert(NULL, builder, "", &bid, GIT_FILEMODE_BLOB)); cl_git_fail(git_treebuilder_insert(NULL, builder, "/", &bid, GIT_FILEMODE_BLOB)); cl_git_fail(git_treebuilder_insert(NULL, builder, ".git", &bid, GIT_FILEMODE_BLOB)); cl_git_fail(git_treebuilder_insert(NULL, builder, "..", &bid, GIT_FILEMODE_BLOB)); cl_git_fail(git_treebuilder_insert(NULL, builder, ".", &bid, GIT_FILEMODE_BLOB)); cl_git_fail(git_treebuilder_insert(NULL, builder, "folder/new.txt", &bid, GIT_FILEMODE_BLOB)); cl_git_pass(git_treebuilder_insert( NULL, builder, "new.txt", &bid, GIT_FILEMODE_BLOB)); cl_git_pass(git_treebuilder_write(&rid, g_repo, builder)); cl_assert(git_oid_cmp(&rid, &id2) == 0); git_treebuilder_free(builder); git_tree_free(tree); } void test_object_tree_write__subtree(void) { // write a hierarchical tree from a memory git_treebuilder *builder; git_tree *tree; git_oid id, bid, subtree_id, id2, id3; git_oid id_hiearar; git_oid_fromstr(&id, first_tree); git_oid_fromstr(&id2, second_tree); git_oid_fromstr(&id3, third_tree); git_oid_fromstr(&bid, blob_oid); //create subtree cl_git_pass(git_treebuilder_create(&builder, NULL)); cl_git_pass(git_treebuilder_insert( NULL, builder, "new.txt", &bid, GIT_FILEMODE_BLOB)); //-V536 cl_git_pass(git_treebuilder_write(&subtree_id, g_repo, builder)); git_treebuilder_free(builder); // create parent tree cl_git_pass(git_tree_lookup(&tree, g_repo, &id)); cl_git_pass(git_treebuilder_create(&builder, tree)); cl_git_pass(git_treebuilder_insert( NULL, builder, "new", &subtree_id, GIT_FILEMODE_TREE)); //-V536 cl_git_pass(git_treebuilder_write(&id_hiearar, g_repo, builder)); git_treebuilder_free(builder); git_tree_free(tree); cl_assert(git_oid_cmp(&id_hiearar, &id3) == 0); // check data is correct cl_git_pass(git_tree_lookup(&tree, g_repo, &id_hiearar)); cl_assert(2 == git_tree_entrycount(tree)); git_tree_free(tree); } /* * And the Lord said: Is this tree properly sorted? */ void test_object_tree_write__sorted_subtrees(void) { git_treebuilder *builder; unsigned int i; int position_c = -1, position_cake = -1, position_config = -1; struct { unsigned int attr; const char *filename; } entries[] = { { GIT_FILEMODE_BLOB, ".gitattributes" }, { GIT_FILEMODE_BLOB, ".gitignore" }, { GIT_FILEMODE_BLOB, ".htaccess" }, { GIT_FILEMODE_BLOB, "Capfile" }, { GIT_FILEMODE_BLOB, "Makefile"}, { GIT_FILEMODE_BLOB, "README"}, { GIT_FILEMODE_TREE, "app"}, { GIT_FILEMODE_TREE, "cake"}, { GIT_FILEMODE_TREE, "config"}, { GIT_FILEMODE_BLOB, "c"}, { GIT_FILEMODE_BLOB, "git_test.txt"}, { GIT_FILEMODE_BLOB, "htaccess.htaccess"}, { GIT_FILEMODE_BLOB, "index.php"}, { GIT_FILEMODE_TREE, "plugins"}, { GIT_FILEMODE_TREE, "schemas"}, { GIT_FILEMODE_TREE, "ssl-certs"}, { GIT_FILEMODE_TREE, "vendors"} }; git_oid blank_oid, tree_oid; memset(&blank_oid, 0x0, sizeof(blank_oid)); cl_git_pass(git_treebuilder_create(&builder, NULL)); for (i = 0; i < ARRAY_SIZE(entries); ++i) { cl_git_pass(git_treebuilder_insert(NULL, builder, entries[i].filename, &blank_oid, entries[i].attr)); } cl_git_pass(git_treebuilder_write(&tree_oid, g_repo, builder)); for (i = 0; i < builder->entries.length; ++i) { git_tree_entry *entry = git_vector_get(&builder->entries, i); if (strcmp(entry->filename, "c") == 0) position_c = i; if (strcmp(entry->filename, "cake") == 0) position_cake = i; if (strcmp(entry->filename, "config") == 0) position_config = i; } cl_assert(position_c != -1); cl_assert(position_cake != -1); cl_assert(position_config != -1); cl_assert(position_c < position_cake); cl_assert(position_cake < position_config); git_treebuilder_free(builder); } void test_object_tree_write__removing_and_re_adding_in_treebuilder(void) { git_treebuilder *builder; int i, aardvark_i, apple_i, apple_after_i, apple_extra_i, last_i; git_oid blank_oid, tree_oid; git_tree *tree; struct { unsigned int attr; const char *filename; } entries[] = { { GIT_FILEMODE_BLOB, "aardvark" }, { GIT_FILEMODE_BLOB, ".first" }, { GIT_FILEMODE_BLOB, "apple" }, { GIT_FILEMODE_BLOB, "last"}, { GIT_FILEMODE_BLOB, "apple_after"}, { GIT_FILEMODE_BLOB, "after_aardvark"}, { 0, NULL }, }; memset(&blank_oid, 0x0, sizeof(blank_oid)); cl_git_pass(git_treebuilder_create(&builder, NULL)); cl_assert_equal_i(0, (int)git_treebuilder_entrycount(builder)); for (i = 0; entries[i].filename; ++i) cl_git_pass(git_treebuilder_insert(NULL, builder, entries[i].filename, &blank_oid, entries[i].attr)); cl_assert_equal_i(6, (int)git_treebuilder_entrycount(builder)); cl_git_pass(git_treebuilder_remove(builder, "apple")); cl_assert_equal_i(5, (int)git_treebuilder_entrycount(builder)); cl_git_pass(git_treebuilder_remove(builder, "apple_after")); cl_assert_equal_i(4, (int)git_treebuilder_entrycount(builder)); cl_git_pass(git_treebuilder_insert( NULL, builder, "before_last", &blank_oid, GIT_FILEMODE_BLOB)); cl_assert_equal_i(5, (int)git_treebuilder_entrycount(builder)); /* reinsert apple_after */ cl_git_pass(git_treebuilder_insert( NULL, builder, "apple_after", &blank_oid, GIT_FILEMODE_BLOB)); cl_assert_equal_i(6, (int)git_treebuilder_entrycount(builder)); cl_git_pass(git_treebuilder_remove(builder, "last")); cl_assert_equal_i(5, (int)git_treebuilder_entrycount(builder)); /* reinsert last */ cl_git_pass(git_treebuilder_insert( NULL, builder, "last", &blank_oid, GIT_FILEMODE_BLOB)); cl_assert_equal_i(6, (int)git_treebuilder_entrycount(builder)); cl_git_pass(git_treebuilder_insert( NULL, builder, "apple_extra", &blank_oid, GIT_FILEMODE_BLOB)); cl_assert_equal_i(7, (int)git_treebuilder_entrycount(builder)); cl_git_pass(git_treebuilder_write(&tree_oid, g_repo, builder)); git_treebuilder_free(builder); cl_git_pass(git_tree_lookup(&tree, g_repo, &tree_oid)); cl_assert_equal_i(7, (int)git_tree_entrycount(tree)); cl_assert(git_tree_entry_byname(tree, ".first") != NULL); cl_assert(git_tree_entry_byname(tree, "apple") == NULL); cl_assert(git_tree_entry_byname(tree, "apple_after") != NULL); cl_assert(git_tree_entry_byname(tree, "apple_extra") != NULL); cl_assert(git_tree_entry_byname(tree, "last") != NULL); aardvark_i = apple_i = apple_after_i = apple_extra_i = last_i = -1; for (i = 0; i < 7; ++i) { const git_tree_entry *entry = git_tree_entry_byindex(tree, i); if (!strcmp(entry->filename, "aardvark")) aardvark_i = i; else if (!strcmp(entry->filename, "apple")) apple_i = i; else if (!strcmp(entry->filename, "apple_after")) apple_after_i = i; else if (!strcmp(entry->filename, "apple_extra")) apple_extra_i = i; else if (!strcmp(entry->filename, "last")) last_i = i; } cl_assert_equal_i(-1, apple_i); cl_assert_equal_i(6, last_i); cl_assert(aardvark_i < apple_after_i); cl_assert(apple_after_i < apple_extra_i); git_tree_free(tree); } libgit2-0.19.0/tests-clar/odb/000077500000000000000000000000001216214232500157605ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/odb/alternates.c000066400000000000000000000044621216214232500202740ustar00rootroot00000000000000#include "clar_libgit2.h" #include "odb.h" #include "filebuf.h" static git_buf destpath, filepath; static const char *paths[] = { "A.git", "B.git", "C.git", "D.git", "E.git", "F.git", "G.git" }; static git_filebuf file; static git_repository *repo; void test_odb_alternates__cleanup(void) { size_t i; git_buf_free(&destpath); git_buf_free(&filepath); for (i = 0; i < ARRAY_SIZE(paths); i++) cl_fixture_cleanup(paths[i]); } static void init_linked_repo(const char *path, const char *alternate) { git_buf_clear(&destpath); git_buf_clear(&filepath); cl_git_pass(git_repository_init(&repo, path, 1)); cl_git_pass(git_path_prettify(&destpath, alternate, NULL)); cl_git_pass(git_buf_joinpath(&destpath, destpath.ptr, "objects")); cl_git_pass(git_buf_joinpath(&filepath, git_repository_path(repo), "objects/info")); cl_git_pass(git_futils_mkdir(filepath.ptr, NULL, 0755, GIT_MKDIR_PATH)); cl_git_pass(git_buf_joinpath(&filepath, filepath.ptr , "alternates")); cl_git_pass(git_filebuf_open(&file, git_buf_cstr(&filepath), 0)); git_filebuf_printf(&file, "%s\n", git_buf_cstr(&destpath)); cl_git_pass(git_filebuf_commit(&file, 0644)); git_repository_free(repo); } void test_odb_alternates__chained(void) { git_commit *commit; git_oid oid; /* Set the alternate A -> testrepo.git */ init_linked_repo(paths[0], cl_fixture("testrepo.git")); /* Set the alternate B -> A */ init_linked_repo(paths[1], paths[0]); /* Now load B and see if we can find an object from testrepo.git */ cl_git_pass(git_repository_open(&repo, paths[1])); git_oid_fromstr(&oid, "a65fedf39aefe402d3bb6e24df4d4f5fe4547750"); cl_git_pass(git_commit_lookup(&commit, repo, &oid)); git_commit_free(commit); git_repository_free(repo); } void test_odb_alternates__long_chain(void) { git_commit *commit; git_oid oid; size_t i; /* Set the alternate A -> testrepo.git */ init_linked_repo(paths[0], cl_fixture("testrepo.git")); /* Set up the five-element chain */ for (i = 1; i < ARRAY_SIZE(paths); i++) { init_linked_repo(paths[i], paths[i-1]); } /* Now load the last one and see if we can find an object from testrepo.git */ cl_git_pass(git_repository_open(&repo, paths[ARRAY_SIZE(paths)-1])); git_oid_fromstr(&oid, "a65fedf39aefe402d3bb6e24df4d4f5fe4547750"); cl_git_fail(git_commit_lookup(&commit, repo, &oid)); git_repository_free(repo); } libgit2-0.19.0/tests-clar/odb/foreach.c000066400000000000000000000032151216214232500175340ustar00rootroot00000000000000#include "clar_libgit2.h" #include "odb.h" #include "git2/odb_backend.h" #include "pack.h" static git_odb *_odb; static git_repository *_repo; static int nobj; void test_odb_foreach__cleanup(void) { git_odb_free(_odb); git_repository_free(_repo); _odb = NULL; _repo = NULL; } static int foreach_cb(const git_oid *oid, void *data) { GIT_UNUSED(data); GIT_UNUSED(oid); nobj++; return 0; } /* * $ git --git-dir tests-clar/resources/testrepo.git count-objects --verbose * count: 47 * size: 4 * in-pack: 1640 * packs: 3 * size-pack: 425 * prune-packable: 0 * garbage: 0 */ void test_odb_foreach__foreach(void) { cl_git_pass(git_repository_open(&_repo, cl_fixture("testrepo.git"))); git_repository_odb(&_odb, _repo); cl_git_pass(git_odb_foreach(_odb, foreach_cb, NULL)); cl_assert_equal_i(47 + 1640, nobj); /* count + in-pack */ } void test_odb_foreach__one_pack(void) { git_odb_backend *backend = NULL; cl_git_pass(git_odb_new(&_odb)); cl_git_pass(git_odb_backend_one_pack(&backend, cl_fixture("testrepo.git/objects/pack/pack-a81e489679b7d3418f9ab594bda8ceb37dd4c695.idx"))); cl_git_pass(git_odb_add_backend(_odb, backend, 1)); _repo = NULL; nobj = 0; cl_git_pass(git_odb_foreach(_odb, foreach_cb, NULL)); cl_assert(nobj == 1628); } static int foreach_stop_cb(const git_oid *oid, void *data) { GIT_UNUSED(data); GIT_UNUSED(oid); nobj++; return (nobj == 1000); } void test_odb_foreach__interrupt_foreach(void) { nobj = 0; cl_git_pass(git_repository_open(&_repo, cl_fixture("testrepo.git"))); git_repository_odb(&_odb, _repo); cl_assert_equal_i(GIT_EUSER, git_odb_foreach(_odb, foreach_stop_cb, NULL)); cl_assert(nobj == 1000); } libgit2-0.19.0/tests-clar/odb/loose.c000066400000000000000000000035301216214232500172460ustar00rootroot00000000000000#include "clar_libgit2.h" #include "odb.h" #include "posix.h" #include "loose_data.h" static void write_object_files(object_data *d) { int fd; if (p_mkdir(d->dir, GIT_OBJECT_DIR_MODE) < 0) cl_assert(errno == EEXIST); cl_assert((fd = p_creat(d->file, S_IREAD | S_IWRITE)) >= 0); cl_must_pass(p_write(fd, d->bytes, d->blen)); p_close(fd); } static void cmp_objects(git_rawobj *o, object_data *d) { cl_assert(o->type == git_object_string2type(d->type)); cl_assert(o->len == d->dlen); if (o->len > 0) cl_assert(memcmp(o->data, d->data, o->len) == 0); } static void test_read_object(object_data *data) { git_oid id; git_odb_object *obj; git_odb *odb; git_rawobj tmp; write_object_files(data); cl_git_pass(git_odb_open(&odb, "test-objects")); cl_git_pass(git_oid_fromstr(&id, data->id)); cl_git_pass(git_odb_read(&obj, odb, &id)); tmp.data = obj->buffer; tmp.len = obj->cached.size; tmp.type = obj->cached.type; cmp_objects(&tmp, data); git_odb_object_free(obj); git_odb_free(odb); } void test_odb_loose__initialize(void) { cl_must_pass(p_mkdir("test-objects", GIT_OBJECT_DIR_MODE)); } void test_odb_loose__cleanup(void) { cl_fixture_cleanup("test-objects"); } void test_odb_loose__exists(void) { git_oid id, id2; git_odb *odb; write_object_files(&one); cl_git_pass(git_odb_open(&odb, "test-objects")); cl_git_pass(git_oid_fromstr(&id, one.id)); cl_assert(git_odb_exists(odb, &id)); /* Test for a non-existant object */ cl_git_pass(git_oid_fromstr(&id2, "8b137891791fe96927ad78e64b0aad7bded08baa")); cl_assert(!git_odb_exists(odb, &id2)); git_odb_free(odb); } void test_odb_loose__simple_reads(void) { test_read_object(&commit); test_read_object(&tree); test_read_object(&tag); test_read_object(&zero); test_read_object(&one); test_read_object(&two); test_read_object(&some); } libgit2-0.19.0/tests-clar/odb/loose_data.h000066400000000000000000000547701216214232500202600ustar00rootroot00000000000000typedef struct object_data { unsigned char *bytes; /* (compressed) bytes stored in object store */ size_t blen; /* length of data in object store */ char *id; /* object id (sha1) */ char *type; /* object type */ char *dir; /* object store (fan-out) directory name */ char *file; /* object store filename */ unsigned char *data; /* (uncompressed) object data */ size_t dlen; /* length of (uncompressed) object data */ } object_data; /* one == 8b137891791fe96927ad78e64b0aad7bded08bdc */ static unsigned char one_bytes[] = { 0x31, 0x78, 0x9c, 0xe3, 0x02, 0x00, 0x00, 0x0b, 0x00, 0x0b, }; static unsigned char one_data[] = { 0x0a, }; static object_data one = { one_bytes, sizeof(one_bytes), "8b137891791fe96927ad78e64b0aad7bded08bdc", "blob", "test-objects/8b", "test-objects/8b/137891791fe96927ad78e64b0aad7bded08bdc", one_data, sizeof(one_data), }; /* commit == 3d7f8a6af076c8c3f20071a8935cdbe8228594d1 */ static unsigned char commit_bytes[] = { 0x78, 0x01, 0x85, 0x50, 0xc1, 0x6a, 0xc3, 0x30, 0x0c, 0xdd, 0xd9, 0x5f, 0xa1, 0xfb, 0x96, 0x12, 0xbb, 0x29, 0x71, 0x46, 0x19, 0x2b, 0x3d, 0x97, 0x1d, 0xd6, 0x7d, 0x80, 0x1d, 0xcb, 0x89, 0x21, 0xb6, 0x82, 0xed, 0x40, 0xf3, 0xf7, 0xf3, 0x48, 0x29, 0x3b, 0x6d, 0xd2, 0xe5, 0xbd, 0x27, 0xbd, 0x27, 0x50, 0x4f, 0xde, 0xbb, 0x0c, 0xfb, 0x43, 0xf3, 0x94, 0x23, 0x22, 0x18, 0x6b, 0x85, 0x51, 0x5d, 0xad, 0xc5, 0xa1, 0x41, 0xae, 0x51, 0x4b, 0xd9, 0x19, 0x6e, 0x4b, 0x0b, 0x29, 0x35, 0x72, 0x59, 0xef, 0x5b, 0x29, 0x8c, 0x65, 0x6a, 0xc9, 0x23, 0x45, 0x38, 0xc1, 0x17, 0x5c, 0x7f, 0xc0, 0x71, 0x13, 0xde, 0xf1, 0xa6, 0xfc, 0x3c, 0xe1, 0xae, 0x27, 0xff, 0x06, 0x5c, 0x88, 0x56, 0xf2, 0x46, 0x74, 0x2d, 0x3c, 0xd7, 0xa5, 0x58, 0x51, 0xcb, 0xb9, 0x8c, 0x11, 0xce, 0xf0, 0x01, 0x97, 0x0d, 0x1e, 0x1f, 0xea, 0x3f, 0x6e, 0x76, 0x02, 0x0a, 0x58, 0x4d, 0x2e, 0x20, 0x6c, 0x1e, 0x48, 0x8b, 0xf7, 0x2a, 0xae, 0x8c, 0x5d, 0x47, 0x04, 0x4d, 0x66, 0x05, 0xb2, 0x90, 0x0b, 0xbe, 0xcf, 0x3d, 0xa6, 0xa4, 0x06, 0x7c, 0x29, 0x3c, 0x64, 0xe5, 0x82, 0x0b, 0x03, 0xd8, 0x25, 0x96, 0x8d, 0x08, 0x78, 0x9b, 0x27, 0x15, 0x54, 0x76, 0x14, 0xd8, 0xdd, 0x35, 0x2f, 0x71, 0xa6, 0x84, 0x8f, 0x90, 0x51, 0x85, 0x01, 0x13, 0xb8, 0x90, 0x23, 0x99, 0xa5, 0x47, 0x03, 0x7a, 0xfd, 0x15, 0xbf, 0x63, 0xec, 0xd3, 0x0d, 0x01, 0x4d, 0x45, 0xb6, 0xd2, 0xeb, 0xeb, 0xdf, 0xef, 0x60, 0xdf, 0xef, 0x1f, 0x78, 0x35, }; static unsigned char commit_data[] = { 0x74, 0x72, 0x65, 0x65, 0x20, 0x64, 0x66, 0x66, 0x32, 0x64, 0x61, 0x39, 0x30, 0x62, 0x32, 0x35, 0x34, 0x65, 0x31, 0x62, 0x65, 0x62, 0x38, 0x38, 0x39, 0x64, 0x31, 0x66, 0x31, 0x66, 0x31, 0x32, 0x38, 0x38, 0x62, 0x65, 0x31, 0x38, 0x30, 0x33, 0x37, 0x38, 0x32, 0x64, 0x66, 0x0a, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x20, 0x41, 0x20, 0x55, 0x20, 0x54, 0x68, 0x6f, 0x72, 0x20, 0x3c, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x40, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x3e, 0x20, 0x31, 0x32, 0x32, 0x37, 0x38, 0x31, 0x34, 0x32, 0x39, 0x37, 0x20, 0x2b, 0x30, 0x30, 0x30, 0x30, 0x0a, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x74, 0x65, 0x72, 0x20, 0x43, 0x20, 0x4f, 0x20, 0x4d, 0x69, 0x74, 0x74, 0x65, 0x72, 0x20, 0x3c, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x74, 0x65, 0x72, 0x40, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x3e, 0x20, 0x31, 0x32, 0x32, 0x37, 0x38, 0x31, 0x34, 0x32, 0x39, 0x37, 0x20, 0x2b, 0x30, 0x30, 0x30, 0x30, 0x0a, 0x0a, 0x41, 0x20, 0x6f, 0x6e, 0x65, 0x2d, 0x6c, 0x69, 0x6e, 0x65, 0x20, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x20, 0x73, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x0a, 0x0a, 0x54, 0x68, 0x65, 0x20, 0x62, 0x6f, 0x64, 0x79, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2c, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x69, 0x6e, 0x67, 0x20, 0x66, 0x75, 0x72, 0x74, 0x68, 0x65, 0x72, 0x20, 0x65, 0x78, 0x70, 0x6c, 0x61, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x0a, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x75, 0x72, 0x70, 0x6f, 0x73, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x20, 0x69, 0x6e, 0x74, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x65, 0x64, 0x20, 0x62, 0x79, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x2e, 0x0a, 0x0a, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x2d, 0x6f, 0x66, 0x2d, 0x62, 0x79, 0x3a, 0x20, 0x41, 0x20, 0x55, 0x20, 0x54, 0x68, 0x6f, 0x72, 0x20, 0x3c, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x40, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x3e, 0x0a, }; static object_data commit = { commit_bytes, sizeof(commit_bytes), "3d7f8a6af076c8c3f20071a8935cdbe8228594d1", "commit", "test-objects/3d", "test-objects/3d/7f8a6af076c8c3f20071a8935cdbe8228594d1", commit_data, sizeof(commit_data), }; /* tree == dff2da90b254e1beb889d1f1f1288be1803782df */ static unsigned char tree_bytes[] = { 0x78, 0x01, 0x2b, 0x29, 0x4a, 0x4d, 0x55, 0x30, 0x34, 0x32, 0x63, 0x30, 0x34, 0x30, 0x30, 0x33, 0x31, 0x51, 0xc8, 0xcf, 0x4b, 0x65, 0xe8, 0x16, 0xae, 0x98, 0x58, 0x29, 0xff, 0x32, 0x53, 0x7d, 0x6d, 0xc5, 0x33, 0x6f, 0xae, 0xb5, 0xd5, 0xf7, 0x2e, 0x74, 0xdf, 0x81, 0x4a, 0x17, 0xe7, 0xe7, 0xa6, 0x32, 0xfc, 0x6d, 0x31, 0xd8, 0xd3, 0xe6, 0xf3, 0xe7, 0xea, 0x47, 0xbe, 0xd0, 0x09, 0x3f, 0x96, 0xb8, 0x3f, 0x90, 0x9e, 0xa2, 0xfd, 0x0f, 0x2a, 0x5f, 0x52, 0x9e, 0xcf, 0x50, 0x31, 0x43, 0x52, 0x29, 0xd1, 0x5a, 0xeb, 0x77, 0x82, 0x2a, 0x8b, 0xfe, 0xb7, 0xbd, 0xed, 0x5d, 0x07, 0x67, 0xfa, 0xb5, 0x42, 0xa5, 0xab, 0x52, 0x8b, 0xf2, 0x19, 0x9e, 0xcd, 0x7d, 0x34, 0x7b, 0xd3, 0xc5, 0x6b, 0xce, 0xde, 0xdd, 0x9a, 0xeb, 0xca, 0xa3, 0x6e, 0x1c, 0x7a, 0xd2, 0x13, 0x3c, 0x11, 0x00, 0xe2, 0xaa, 0x38, 0x57, }; static unsigned char tree_data[] = { 0x31, 0x30, 0x30, 0x36, 0x34, 0x34, 0x20, 0x6f, 0x6e, 0x65, 0x00, 0x8b, 0x13, 0x78, 0x91, 0x79, 0x1f, 0xe9, 0x69, 0x27, 0xad, 0x78, 0xe6, 0x4b, 0x0a, 0xad, 0x7b, 0xde, 0xd0, 0x8b, 0xdc, 0x31, 0x30, 0x30, 0x36, 0x34, 0x34, 0x20, 0x73, 0x6f, 0x6d, 0x65, 0x00, 0xfd, 0x84, 0x30, 0xbc, 0x86, 0x4c, 0xfc, 0xd5, 0xf1, 0x0e, 0x55, 0x90, 0xf8, 0xa4, 0x47, 0xe0, 0x1b, 0x94, 0x2b, 0xfe, 0x31, 0x30, 0x30, 0x36, 0x34, 0x34, 0x20, 0x74, 0x77, 0x6f, 0x00, 0x78, 0x98, 0x19, 0x22, 0x61, 0x3b, 0x2a, 0xfb, 0x60, 0x25, 0x04, 0x2f, 0xf6, 0xbd, 0x87, 0x8a, 0xc1, 0x99, 0x4e, 0x85, 0x31, 0x30, 0x30, 0x36, 0x34, 0x34, 0x20, 0x7a, 0x65, 0x72, 0x6f, 0x00, 0xe6, 0x9d, 0xe2, 0x9b, 0xb2, 0xd1, 0xd6, 0x43, 0x4b, 0x8b, 0x29, 0xae, 0x77, 0x5a, 0xd8, 0xc2, 0xe4, 0x8c, 0x53, 0x91, }; static object_data tree = { tree_bytes, sizeof(tree_bytes), "dff2da90b254e1beb889d1f1f1288be1803782df", "tree", "test-objects/df", "test-objects/df/f2da90b254e1beb889d1f1f1288be1803782df", tree_data, sizeof(tree_data), }; /* tag == 09d373e1dfdc16b129ceec6dd649739911541e05 */ static unsigned char tag_bytes[] = { 0x78, 0x01, 0x35, 0x4e, 0xcb, 0x0a, 0xc2, 0x40, 0x10, 0xf3, 0xbc, 0x5f, 0x31, 0x77, 0xa1, 0xec, 0xa3, 0xed, 0x6e, 0x41, 0x44, 0xf0, 0x2c, 0x5e, 0xfc, 0x81, 0xe9, 0x76, 0xb6, 0xad, 0xb4, 0xb4, 0x6c, 0x07, 0xd1, 0xbf, 0x77, 0x44, 0x0d, 0x39, 0x84, 0x10, 0x92, 0x30, 0xf6, 0x60, 0xbc, 0xdb, 0x2d, 0xed, 0x9d, 0x22, 0x83, 0xeb, 0x7c, 0x0a, 0x58, 0x63, 0xd2, 0xbe, 0x8e, 0x21, 0xba, 0x64, 0xb5, 0xf6, 0x06, 0x43, 0xe3, 0xaa, 0xd8, 0xb5, 0x14, 0xac, 0x0d, 0x55, 0x53, 0x76, 0x46, 0xf1, 0x6b, 0x25, 0x88, 0xcb, 0x3c, 0x8f, 0xac, 0x58, 0x3a, 0x1e, 0xba, 0xd0, 0x85, 0xd8, 0xd8, 0xf7, 0x94, 0xe1, 0x0c, 0x57, 0xb8, 0x8c, 0xcc, 0x22, 0x0f, 0xdf, 0x90, 0xc8, 0x13, 0x3d, 0x71, 0x5e, 0x27, 0x2a, 0xc4, 0x39, 0x82, 0xb1, 0xd6, 0x07, 0x53, 0xda, 0xc6, 0xc3, 0x5e, 0x0b, 0x94, 0xba, 0x0d, 0xe3, 0x06, 0x42, 0x1e, 0x08, 0x3e, 0x95, 0xbf, 0x4b, 0x69, 0xc9, 0x90, 0x69, 0x22, 0xdc, 0xe8, 0xbf, 0xf2, 0x06, 0x42, 0x9a, 0x36, 0xb1, }; static unsigned char tag_data[] = { 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x20, 0x33, 0x64, 0x37, 0x66, 0x38, 0x61, 0x36, 0x61, 0x66, 0x30, 0x37, 0x36, 0x63, 0x38, 0x63, 0x33, 0x66, 0x32, 0x30, 0x30, 0x37, 0x31, 0x61, 0x38, 0x39, 0x33, 0x35, 0x63, 0x64, 0x62, 0x65, 0x38, 0x32, 0x32, 0x38, 0x35, 0x39, 0x34, 0x64, 0x31, 0x0a, 0x74, 0x79, 0x70, 0x65, 0x20, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x0a, 0x74, 0x61, 0x67, 0x20, 0x76, 0x30, 0x2e, 0x30, 0x2e, 0x31, 0x0a, 0x74, 0x61, 0x67, 0x67, 0x65, 0x72, 0x20, 0x43, 0x20, 0x4f, 0x20, 0x4d, 0x69, 0x74, 0x74, 0x65, 0x72, 0x20, 0x3c, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x74, 0x65, 0x72, 0x40, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x3e, 0x20, 0x31, 0x32, 0x32, 0x37, 0x38, 0x31, 0x34, 0x32, 0x39, 0x37, 0x20, 0x2b, 0x30, 0x30, 0x30, 0x30, 0x0a, 0x0a, 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x61, 0x67, 0x20, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x20, 0x76, 0x30, 0x2e, 0x30, 0x2e, 0x31, 0x0a, }; static object_data tag = { tag_bytes, sizeof(tag_bytes), "09d373e1dfdc16b129ceec6dd649739911541e05", "tag", "test-objects/09", "test-objects/09/d373e1dfdc16b129ceec6dd649739911541e05", tag_data, sizeof(tag_data), }; /* zero == e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 */ static unsigned char zero_bytes[] = { 0x78, 0x01, 0x4b, 0xca, 0xc9, 0x4f, 0x52, 0x30, 0x60, 0x00, 0x00, 0x09, 0xb0, 0x01, 0xf0, }; static unsigned char zero_data[] = { 0x00 /* dummy data */ }; static object_data zero = { zero_bytes, sizeof(zero_bytes), "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391", "blob", "test-objects/e6", "test-objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391", zero_data, 0, }; /* two == 78981922613b2afb6025042ff6bd878ac1994e85 */ static unsigned char two_bytes[] = { 0x78, 0x01, 0x4b, 0xca, 0xc9, 0x4f, 0x52, 0x30, 0x62, 0x48, 0xe4, 0x02, 0x00, 0x0e, 0x64, 0x02, 0x5d, }; static unsigned char two_data[] = { 0x61, 0x0a, }; static object_data two = { two_bytes, sizeof(two_bytes), "78981922613b2afb6025042ff6bd878ac1994e85", "blob", "test-objects/78", "test-objects/78/981922613b2afb6025042ff6bd878ac1994e85", two_data, sizeof(two_data), }; /* some == fd8430bc864cfcd5f10e5590f8a447e01b942bfe */ static unsigned char some_bytes[] = { 0x78, 0x01, 0x7d, 0x54, 0xc1, 0x4e, 0xe3, 0x30, 0x10, 0xdd, 0x33, 0x5f, 0x31, 0xc7, 0x5d, 0x94, 0xa5, 0x84, 0xd5, 0x22, 0xad, 0x7a, 0x0a, 0x15, 0x85, 0x48, 0xd0, 0x56, 0x49, 0x2a, 0xd4, 0xa3, 0x13, 0x4f, 0x88, 0x85, 0x63, 0x47, 0xb6, 0x43, 0xc9, 0xdf, 0xef, 0x8c, 0x69, 0x17, 0x56, 0x0b, 0x7b, 0xaa, 0x62, 0x7b, 0xde, 0xbc, 0xf7, 0xe6, 0x4d, 0x6b, 0x6d, 0x6b, 0x48, 0xd3, 0xcb, 0x5f, 0x5f, 0x66, 0xa7, 0x27, 0x70, 0x0a, 0x55, 0xa7, 0x3c, 0xb4, 0x4a, 0x23, 0xf0, 0xaf, 0x43, 0x04, 0x6f, 0xdb, 0xb0, 0x17, 0x0e, 0xe7, 0x30, 0xd9, 0x11, 0x1a, 0x61, 0xc0, 0xa1, 0x54, 0x3e, 0x38, 0x55, 0x8f, 0x81, 0x9e, 0x05, 0x10, 0x46, 0xce, 0xac, 0x83, 0xde, 0x4a, 0xd5, 0x4e, 0x0c, 0x42, 0x67, 0xa3, 0x91, 0xe8, 0x20, 0x74, 0x08, 0x01, 0x5d, 0xef, 0xc1, 0xb6, 0xf1, 0xe3, 0x66, 0xb5, 0x85, 0x1b, 0x34, 0xe8, 0x84, 0x86, 0xcd, 0x58, 0x6b, 0xd5, 0xc0, 0x9d, 0x6a, 0xd0, 0x78, 0x4c, 0xe0, 0x19, 0x9d, 0x57, 0xd6, 0xc0, 0x45, 0xc2, 0x18, 0xc2, 0xc3, 0xc0, 0x0f, 0x7c, 0x87, 0x12, 0xea, 0x29, 0x56, 0x2f, 0x99, 0x4f, 0x79, 0xe0, 0x03, 0x4b, 0x4b, 0x4d, 0x44, 0xa0, 0x92, 0x33, 0x2a, 0xe0, 0x9a, 0xdc, 0x80, 0x90, 0x52, 0xf1, 0x11, 0x04, 0x1b, 0x4b, 0x06, 0xea, 0xae, 0x3c, 0xe3, 0x7a, 0x50, 0x74, 0x4a, 0x84, 0xfe, 0xc3, 0x81, 0x41, 0xf8, 0x89, 0x18, 0x43, 0x67, 0x9d, 0x87, 0x47, 0xf5, 0x8c, 0x51, 0xf6, 0x68, 0xb4, 0xea, 0x55, 0x20, 0x2a, 0x6f, 0x80, 0xdc, 0x42, 0x2b, 0xf3, 0x14, 0x2b, 0x1a, 0xdb, 0x0f, 0xe4, 0x9a, 0x64, 0x84, 0xa3, 0x90, 0xa8, 0xf9, 0x8f, 0x9d, 0x86, 0x9e, 0xd3, 0xab, 0x5a, 0x99, 0xc8, 0xd9, 0xc3, 0x5e, 0x85, 0x0e, 0x2c, 0xb5, 0x73, 0x30, 0x38, 0xfb, 0xe8, 0x44, 0xef, 0x5f, 0x95, 0x1b, 0xc9, 0xd0, 0xef, 0x3c, 0x26, 0x32, 0x1e, 0xff, 0x2d, 0xb6, 0x23, 0x7b, 0x3f, 0xd1, 0x3c, 0x78, 0x1a, 0x0d, 0xcb, 0xe6, 0xf6, 0xd4, 0x44, 0x99, 0x47, 0x1a, 0x9e, 0xed, 0x23, 0xb5, 0x91, 0x6a, 0xdf, 0x53, 0x39, 0x03, 0xf8, 0x5a, 0xb1, 0x0f, 0x1f, 0xce, 0x81, 0x11, 0xde, 0x01, 0x7a, 0x90, 0x16, 0xc4, 0x30, 0xe8, 0x89, 0xed, 0x7b, 0x65, 0x4b, 0xd7, 0x03, 0x36, 0xc1, 0xcf, 0xa1, 0xa5, 0xb1, 0xe3, 0x8b, 0xe8, 0x07, 0x4d, 0xf3, 0x23, 0x25, 0x13, 0x35, 0x27, 0xf5, 0x8c, 0x11, 0xd3, 0xa0, 0x9a, 0xa8, 0xf5, 0x38, 0x7d, 0xce, 0x55, 0xc2, 0x71, 0x79, 0x13, 0xc7, 0xa3, 0xda, 0x77, 0x68, 0xc0, 0xd8, 0x10, 0xdd, 0x24, 0x8b, 0x15, 0x59, 0xc5, 0x10, 0xe2, 0x20, 0x99, 0x8e, 0xf0, 0x05, 0x9b, 0x31, 0x88, 0x5a, 0xe3, 0xd9, 0x37, 0xba, 0xe2, 0xdb, 0xbf, 0x92, 0xfa, 0x66, 0x16, 0x97, 0x47, 0xd9, 0x9d, 0x1d, 0x28, 0x7c, 0x9d, 0x08, 0x1c, 0xc7, 0xbd, 0xd2, 0x1a, 0x6a, 0x04, 0xf2, 0xa2, 0x1d, 0x75, 0x02, 0x14, 0x5d, 0xc6, 0x78, 0xc8, 0xab, 0xdb, 0xf5, 0xb6, 0x82, 0x6c, 0xb5, 0x83, 0x87, 0xac, 0x28, 0xb2, 0x55, 0xb5, 0x9b, 0xc7, 0xc1, 0xb0, 0xb7, 0xf8, 0x4c, 0xbc, 0x38, 0x0e, 0x8a, 0x04, 0x2a, 0x62, 0x41, 0x6b, 0xe0, 0x84, 0x09, 0x13, 0xe9, 0xe1, 0xea, 0xfb, 0xeb, 0x62, 0x71, 0x4b, 0x25, 0xd9, 0x55, 0x7e, 0x97, 0x57, 0x3b, 0x20, 0x33, 0x96, 0x79, 0xb5, 0xba, 0x2e, 0x4b, 0x58, 0xae, 0x0b, 0xc8, 0x60, 0x93, 0x15, 0x55, 0xbe, 0xd8, 0xde, 0x65, 0x05, 0x6c, 0xb6, 0xc5, 0x66, 0x5d, 0x5e, 0x93, 0xf7, 0x25, 0x65, 0x98, 0x41, 0x29, 0x86, 0x0c, 0xf2, 0xf1, 0x14, 0xa2, 0xb3, 0xbd, 0x75, 0x08, 0x12, 0x83, 0x50, 0xda, 0x1f, 0x23, 0xbe, 0xa3, 0x1d, 0xf4, 0x9d, 0x1d, 0xb5, 0x84, 0x4e, 0x50, 0x38, 0x1d, 0x36, 0x48, 0x21, 0x95, 0xd1, 0xac, 0x81, 0x99, 0x1d, 0xc1, 0x3f, 0x41, 0xe6, 0x9e, 0x42, 0x5b, 0x0a, 0x48, 0xcc, 0x5f, 0xe0, 0x7d, 0x3f, 0xc4, 0x6f, 0x0e, 0xfe, 0xc0, 0x2d, 0xfe, 0x01, 0x2c, 0xd6, 0x9b, 0x5d, 0xbe, 0xba, 0x21, 0xca, 0x79, 0xcb, 0xe3, 0x49, 0x60, 0xef, 0x68, 0x05, 0x28, 0x9b, 0x8c, 0xc1, 0x12, 0x3e, 0xdb, 0xc7, 0x04, 0x7e, 0xa6, 0x74, 0x29, 0xcc, 0x13, 0xed, 0x07, 0x94, 0x81, 0xd6, 0x96, 0xaa, 0x97, 0xaa, 0xa5, 0xc0, 0x2f, 0xb5, 0xb5, 0x2e, 0xe6, 0xfc, 0xca, 0xfa, 0x60, 0x4d, 0x02, 0xf7, 0x19, 0x9c, 0x5f, 0xa4, 0xe9, 0xf9, 0xf7, 0xf4, 0xc7, 0x79, 0x9a, 0xc0, 0xb6, 0xcc, 0x58, 0xec, 0xec, 0xe4, 0x37, 0x22, 0xfa, 0x8b, 0x53, }; static unsigned char some_data[] = { 0x2f, 0x2a, 0x0a, 0x20, 0x2a, 0x20, 0x54, 0x68, 0x69, 0x73, 0x20, 0x66, 0x69, 0x6c, 0x65, 0x20, 0x69, 0x73, 0x20, 0x66, 0x72, 0x65, 0x65, 0x20, 0x73, 0x6f, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0x3b, 0x20, 0x79, 0x6f, 0x75, 0x20, 0x63, 0x61, 0x6e, 0x20, 0x72, 0x65, 0x64, 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x20, 0x69, 0x74, 0x20, 0x61, 0x6e, 0x64, 0x2f, 0x6f, 0x72, 0x20, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0a, 0x20, 0x2a, 0x20, 0x69, 0x74, 0x20, 0x75, 0x6e, 0x64, 0x65, 0x72, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x65, 0x72, 0x6d, 0x73, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x47, 0x4e, 0x55, 0x20, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x6c, 0x20, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x20, 0x4c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x2c, 0x20, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x32, 0x2c, 0x0a, 0x20, 0x2a, 0x20, 0x61, 0x73, 0x20, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x65, 0x64, 0x20, 0x62, 0x79, 0x20, 0x74, 0x68, 0x65, 0x20, 0x46, 0x72, 0x65, 0x65, 0x20, 0x53, 0x6f, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0x20, 0x46, 0x6f, 0x75, 0x6e, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x0a, 0x20, 0x2a, 0x0a, 0x20, 0x2a, 0x20, 0x49, 0x6e, 0x20, 0x61, 0x64, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x74, 0x6f, 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x47, 0x4e, 0x55, 0x20, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x6c, 0x20, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x20, 0x4c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x2c, 0x0a, 0x20, 0x2a, 0x20, 0x74, 0x68, 0x65, 0x20, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x73, 0x20, 0x67, 0x69, 0x76, 0x65, 0x20, 0x79, 0x6f, 0x75, 0x20, 0x75, 0x6e, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x65, 0x64, 0x20, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x74, 0x6f, 0x20, 0x6c, 0x69, 0x6e, 0x6b, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x64, 0x0a, 0x20, 0x2a, 0x20, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x66, 0x69, 0x6c, 0x65, 0x20, 0x69, 0x6e, 0x74, 0x6f, 0x20, 0x63, 0x6f, 0x6d, 0x62, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x6f, 0x74, 0x68, 0x65, 0x72, 0x20, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x73, 0x2c, 0x0a, 0x20, 0x2a, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x74, 0x6f, 0x20, 0x64, 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x20, 0x74, 0x68, 0x6f, 0x73, 0x65, 0x20, 0x63, 0x6f, 0x6d, 0x62, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x77, 0x69, 0x74, 0x68, 0x6f, 0x75, 0x74, 0x20, 0x61, 0x6e, 0x79, 0x20, 0x72, 0x65, 0x73, 0x74, 0x72, 0x69, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x0a, 0x20, 0x2a, 0x20, 0x63, 0x6f, 0x6d, 0x69, 0x6e, 0x67, 0x20, 0x66, 0x72, 0x6f, 0x6d, 0x20, 0x74, 0x68, 0x65, 0x20, 0x75, 0x73, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x66, 0x69, 0x6c, 0x65, 0x2e, 0x20, 0x20, 0x28, 0x54, 0x68, 0x65, 0x20, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x6c, 0x20, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x20, 0x4c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x0a, 0x20, 0x2a, 0x20, 0x72, 0x65, 0x73, 0x74, 0x72, 0x69, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x64, 0x6f, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x79, 0x20, 0x69, 0x6e, 0x20, 0x6f, 0x74, 0x68, 0x65, 0x72, 0x20, 0x72, 0x65, 0x73, 0x70, 0x65, 0x63, 0x74, 0x73, 0x3b, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2c, 0x20, 0x74, 0x68, 0x65, 0x79, 0x20, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x0a, 0x20, 0x2a, 0x20, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x66, 0x69, 0x6c, 0x65, 0x2c, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x64, 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x77, 0x68, 0x65, 0x6e, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x6c, 0x69, 0x6e, 0x6b, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x74, 0x6f, 0x0a, 0x20, 0x2a, 0x20, 0x61, 0x20, 0x63, 0x6f, 0x6d, 0x62, 0x69, 0x6e, 0x65, 0x64, 0x20, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x2e, 0x29, 0x0a, 0x20, 0x2a, 0x0a, 0x20, 0x2a, 0x20, 0x54, 0x68, 0x69, 0x73, 0x20, 0x66, 0x69, 0x6c, 0x65, 0x20, 0x69, 0x73, 0x20, 0x64, 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x68, 0x6f, 0x70, 0x65, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x69, 0x74, 0x20, 0x77, 0x69, 0x6c, 0x6c, 0x20, 0x62, 0x65, 0x20, 0x75, 0x73, 0x65, 0x66, 0x75, 0x6c, 0x2c, 0x20, 0x62, 0x75, 0x74, 0x0a, 0x20, 0x2a, 0x20, 0x57, 0x49, 0x54, 0x48, 0x4f, 0x55, 0x54, 0x20, 0x41, 0x4e, 0x59, 0x20, 0x57, 0x41, 0x52, 0x52, 0x41, 0x4e, 0x54, 0x59, 0x3b, 0x20, 0x77, 0x69, 0x74, 0x68, 0x6f, 0x75, 0x74, 0x20, 0x65, 0x76, 0x65, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x69, 0x6d, 0x70, 0x6c, 0x69, 0x65, 0x64, 0x20, 0x77, 0x61, 0x72, 0x72, 0x61, 0x6e, 0x74, 0x79, 0x20, 0x6f, 0x66, 0x0a, 0x20, 0x2a, 0x20, 0x4d, 0x45, 0x52, 0x43, 0x48, 0x41, 0x4e, 0x54, 0x41, 0x42, 0x49, 0x4c, 0x49, 0x54, 0x59, 0x20, 0x6f, 0x72, 0x20, 0x46, 0x49, 0x54, 0x4e, 0x45, 0x53, 0x53, 0x20, 0x46, 0x4f, 0x52, 0x20, 0x41, 0x20, 0x50, 0x41, 0x52, 0x54, 0x49, 0x43, 0x55, 0x4c, 0x41, 0x52, 0x20, 0x50, 0x55, 0x52, 0x50, 0x4f, 0x53, 0x45, 0x2e, 0x20, 0x20, 0x53, 0x65, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, 0x47, 0x4e, 0x55, 0x0a, 0x20, 0x2a, 0x20, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x6c, 0x20, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x20, 0x4c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x6d, 0x6f, 0x72, 0x65, 0x20, 0x64, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x2e, 0x0a, 0x20, 0x2a, 0x0a, 0x20, 0x2a, 0x20, 0x59, 0x6f, 0x75, 0x20, 0x73, 0x68, 0x6f, 0x75, 0x6c, 0x64, 0x20, 0x68, 0x61, 0x76, 0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x64, 0x20, 0x61, 0x20, 0x63, 0x6f, 0x70, 0x79, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x47, 0x4e, 0x55, 0x20, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x6c, 0x20, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x20, 0x4c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x0a, 0x20, 0x2a, 0x20, 0x61, 0x6c, 0x6f, 0x6e, 0x67, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x3b, 0x20, 0x73, 0x65, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, 0x66, 0x69, 0x6c, 0x65, 0x20, 0x43, 0x4f, 0x50, 0x59, 0x49, 0x4e, 0x47, 0x2e, 0x20, 0x20, 0x49, 0x66, 0x20, 0x6e, 0x6f, 0x74, 0x2c, 0x20, 0x77, 0x72, 0x69, 0x74, 0x65, 0x20, 0x74, 0x6f, 0x0a, 0x20, 0x2a, 0x20, 0x74, 0x68, 0x65, 0x20, 0x46, 0x72, 0x65, 0x65, 0x20, 0x53, 0x6f, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0x20, 0x46, 0x6f, 0x75, 0x6e, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2c, 0x20, 0x35, 0x31, 0x20, 0x46, 0x72, 0x61, 0x6e, 0x6b, 0x6c, 0x69, 0x6e, 0x20, 0x53, 0x74, 0x72, 0x65, 0x65, 0x74, 0x2c, 0x20, 0x46, 0x69, 0x66, 0x74, 0x68, 0x20, 0x46, 0x6c, 0x6f, 0x6f, 0x72, 0x2c, 0x0a, 0x20, 0x2a, 0x20, 0x42, 0x6f, 0x73, 0x74, 0x6f, 0x6e, 0x2c, 0x20, 0x4d, 0x41, 0x20, 0x30, 0x32, 0x31, 0x31, 0x30, 0x2d, 0x31, 0x33, 0x30, 0x31, 0x2c, 0x20, 0x55, 0x53, 0x41, 0x2e, 0x0a, 0x20, 0x2a, 0x2f, 0x0a, }; static object_data some = { some_bytes, sizeof(some_bytes), "fd8430bc864cfcd5f10e5590f8a447e01b942bfe", "blob", "test-objects/fd", "test-objects/fd/8430bc864cfcd5f10e5590f8a447e01b942bfe", some_data, sizeof(some_data), }; libgit2-0.19.0/tests-clar/odb/mixed.c000066400000000000000000000010261216214232500172310ustar00rootroot00000000000000#include "clar_libgit2.h" #include "odb.h" static git_odb *_odb; void test_odb_mixed__initialize(void) { cl_git_pass(git_odb_open(&_odb, cl_fixture("duplicate.git/objects"))); } void test_odb_mixed__cleanup(void) { git_odb_free(_odb); _odb = NULL; } void test_odb_mixed__dup_oid(void) { const char hex[] = "ce013625030ba8dba906f756967f9e9ca394464a"; git_oid oid; git_odb_object *obj; cl_git_pass(git_oid_fromstr(&oid, hex)); cl_git_pass(git_odb_read_prefix(&obj, _odb, &oid, GIT_OID_HEXSZ)); git_odb_object_free(obj); } libgit2-0.19.0/tests-clar/odb/pack_data.h000066400000000000000000000147221216214232500200460ustar00rootroot00000000000000 static const char *packed_objects[] = { "0266163a49e280c4f5ed1e08facd36a2bd716bcf", "53fc32d17276939fc79ed05badaef2db09990016", "6336846bd5c88d32f93ae57d846683e61ab5c530", "6dcf9bf7541ee10456529833502442f385010c3d", "bed08a0b30b72a9d4aed7f1af8c8ca124e8d64b9", "e90810b8df3e80c413d903f631643c716887138d", "fc3c3a2083e9f6f89e6bd53e9420e70d1e357c9b", "fc58168adf502d0c0ef614c3111a7038fc8c09c8", "fd0ec0333948dfe23265ac46be0205a436a8c3a5", "fd8430bc864cfcd5f10e5590f8a447e01b942bfe", "fd899f45951c15c1c5f7c34b1c864e91bd6556c6", "fda23b974899e7e1f938619099280bfda13bdca9", "fdbec189efb657c8325962b494875987881a356b", "fe1ca6bd22b5d8353ce6c2f3aba80805c438a7a5", "fe3a6a42c87ff1239370c741a265f3997add87c1", "deb106bfd2d36ecf9f0079224c12022201a39ad1", "dec93efc79e60f2680de3e666755d335967eec30", "def425bf8568b9c1e20879bf5be6f9c52b7361c4", "df48000ac4f48570054e3a71a81916357997b680", "dfae6ed8f6dd8acc3b40a31811ea316239223559", "dff79e27d3d2cdc09790ded80fe2ea8ff5d61034", "e00e46abe4c542e17c8bc83d72cf5be8018d7b0e", "e01b107b4f77f8f98645adac0206a504f2d29d7c", "e032d863f512c47b479bd984f8b6c8061f66b7d4", "e044baa468a1c74f9f9da36805445f6888358b49", "e04529998989ba8ae3419538dd57969af819b241", "e0637ddfbea67c8d7f557c709e095af8906e9176", "e0743ad4031231e71700abdc6fdbe94f189d20e5", "cf33ac7a3d8b2b8f6bb266518aadbf59de397608", "cf5f7235b9c9689b133f6ea12015720b411329bd", "cf6cccf1297284833a9a03138a1f5738fa1c6c94", "cf7992bde17ce7a79cab5f0c1fcbe8a0108721ed", "cfe3a027ab12506d4144ee8a35669ae8fc4b7ab1", "cfe96f31dfad7bab49977aa1df7302f7fafcb025", "cff54d138945ef4de384e9d2759291d0c13ea90a", "d01f7573ac34c2f502bd1cf18cde73480c741151", "d03f567593f346a1ca96a57f8191def098d126e3", "d047b47aadf88501238f36f5c17dd0a50dc62087", "d0a0d63086fae3b0682af7261df21f7d0f7f066d", "d0a44bd6ed0be21b725a96c0891bbc79bc1a540c", "d0d7e736e536a41bcb885005f8bf258c61cad682", "d0e7959d4b95ffec6198df6f5a7ae259b23a5f50", "bf2fe2acca17d13356ce802ba9dc8343f710dfb7", "bf55f407d6d9418e51f42ea7a3a6aadf17388349", "bf92206f8b633b88a66dca4a911777630b06fbac", "bfaf8c42eb8842abe206179fee864cfba87e3ca9", "bfe05675d4e8f6b59d50932add8790f1a06b10ee", "bff8618112330763327cfa6ce6e914db84f51ddf", "bff873e9853ed99fed52c25f7ad29f78b27dcec2", "c01c3fae7251098d7af1b459bcd0786e81d4616d", "c0220fca67f48b8a5d4163d53b1486224be3a198", "c02d0b160b82ee72469c269f13de4c26a7ea09cb", "c059510ad1b45ab58390e042d7dee1ac46703854", "c07204a1897aeeaa3c248d29dbfa9b033baf9755", "c073337a4dd7276931b4b3fdbc3f0040e9441793", "0fd7e4bfba5b3a82be88d1057757ca8b2c5e6d26", "100746511cc45c9f1ad6721c4ef5be49222fee4d", "1088490171d9b984d68b8b9be9ca003f4eafff59", "1093c8ff4cb78fcf5f79dbbeedcb6e824bd4e253", "10aa3fa72afab7ee31e116ae06442fe0f7b79df2", "10b759e734e8299aa0dca08be935d95d886127b6", "111d5ccf0bb010c4e8d7af3eedfa12ef4c5e265b", "11261fbff21758444d426356ff6327ee01e90752", "112998d425717bb922ce74e8f6f0f831d8dc4510", "2ef4e5d838b6507bd61d457cf6466662b791c5c0", "2ef4faa0f82efa00eeac6cae9e8b2abccc8566ee", "2f06098183b0d7be350acbe39cdbaccff2df0c4a", "2f1c5d509ac5bffb3c62f710a1c2c542e126dfd1", "2f205b20fc16423c42b3ba51b2ea78d7b9ff3578", "2f9b6b6e3d9250ba09360734aa47973a993b59d1", "30c62a2d5a8d644f1311d4f7fe3f6a788e4c8188", "31438e245492d85fd6da4d1406eba0fbde8332a4", "3184a3abdfea231992254929ff4e275898e5bbf6", "3188ffdbb3a3d52e0f78f30c484533899224436e", "32581d0093429770d044a60eb0e9cc0462bedb13", "32679a9544d83e5403202c4d5efb61ad02492847", "4e7e9f60b7e2049b7f5697daf133161a18ef688f", "4e8cda27ddc8be7db875ceb0f360c37734724c6d", "4ea481c61c59ab55169b7cbaae536ad50b49d6f0", "4f0adcd0e61eabe06fe32be66b16559537124b7a", "4f1355c91100d12f9e7202f91b245df0c110867c", "4f6eadeb08b9d0d1e8b1b3eac8a34940adf29a2d", "4f9339df943c53117a5fc8e86e2f38716ff3a668", "4fc3874b118752e40de556b1c3e7b4a9f1737d00", "4ff1dd0992dd6baafdb5e166be6f9f23b59bdf87", "5018a35e0b7e2eec7ce5050baf9c7343f3f74164", "50298f44a45eda3a29dae82dbe911b5aa176ac07", "502acd164fb115768d723144da2e7bb5a24891bb", "50330c02bd4fd95c9db1fcf2f97f4218e42b7226", "5052bf355d9f8c52446561a39733a8767bf31e37", "6f2cd729ae42988c1dd43588d3a6661ba48ad7a0", "6f4e2c42d9138bfbf3e0f908f1308828cc6f2178", "6f6a17db05a83620cef4572761831c20a70ba9b9", "6faad60901e36538634f0d8b8ff3f21f83503c71", "6fc72e46de3df0c3842dab302bbacf697a63abab", "6fdccd49f442a7204399ca9b418f017322dbded8", "6fe7568fc3861c334cb008fd85d57d9647249ef5", "700f55d91d7b55665594676a4bada1f1457a0598", "702bd70595a7b19afc48a1f784a6505be68469d4", "7033f9ee0e52b08cb5679cd49b7b7999eaf9eaf8", "70957110ce446c4e250f865760fb3da513cdcc92", "8ec696a4734f16479d091bc70574d23dd9fe7443", "8ed341c55ed4d6f4cdc8bf4f0ca18a08c93f6962", "8edc2805f1f11b63e44bf81f4557f8b473612b69", "8ef9060a954118a698fc10e20acdc430566a100f", "8f0c4b543f4bb6eb1518ecfc3d4699e43108d393", "8fac94df3035405c2e60b3799153ce7c428af6b9", "904c0ac12b23548de524adae712241b423d765a3", "90bbaa9a809c3a768d873a9cc7d52b4f3bf3d1b9", "90d4d2f0fc362beabbbf76b4ffda0828229c198d", "90f9ff6755330b685feff6c3d81782ee3592ab04", "91822c50ebe4f9bf5bbb8308ecf9f6557062775c", "91d973263a55708fa8255867b3202d81ef9c2868", "af292c99c6148d772af3315a1c74e83330e7ead7", "af3b99d5be330dbbce0b9250c3a5fb05911908cc", "af55d0cdeb280af2db8697e5afa506e081012719", "af795e498d411142ddb073e8ca2c5447c3295a4c", "afadc73a392f8cc8e2cc77dd62a7433dd3bafa8c", "affd84ed8ec7ce67612fe3c12a80f8164b101f6a", "b0941f9c70ffe67f0387a827b338e64ecf3190f0", "b0a3077f9ef6e093f8d9869bdb0c07095bd722cb", "b0a8568a7614806378a54db5706ee3b06ae58693", "b0fb7372f242233d1d35ce7d8e74d3990cbc5841", "b10489944b9ead17427551759d180d10203e06ba", "b196a807b323f2748ffc6b1d42cd0812d04c9a40", "b1bb1d888f0c5e19278536d49fa77db035fac7ae" }; static const char *loose_objects[] = { "45b983be36b73c0788dc9cbcb76cbb80fc7bb057", "a8233120f6ad708f843d861ce2b7228ec4e3dec6", "fd093bff70906175335656e6ce6ae05783708765", "c47800c7266a2be04c571c04d5a6614691ea99bd", "a71586c1dfe8a71c6cbf6c129f404c5642ff31bd", "8496071c1b46c854b31185ea97743be6a8774479", "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391", "814889a078c031f61ed08ab5fa863aea9314344d", "5b5b025afb0b4c913b4c338a42934a3863bf3644", "1385f264afb75a56a5bec74243be9b367ba4ca08", "f60079018b664e4e79329a7ef9559c8d9e0378d1", "be3563ae3f795b2b4353bcce3a527ad0a4f7f644", "75057dd4114e74cca1d750d0aee1647c903cb60a", "fa49b077972391ad58037050f2a75f74e3671e92", "9fd738e8f7967c078dceed8190330fc8648ee56a", "1810dff58d8a660512d4832e740f692884338ccd", "181037049a54a1eb5fab404658a3a250b44335d7", "a4a7dce85cf63874e984719f4fdd239f5145052f", "4a202b346bb0fb0db7eff3cffeb3c70babbd2045" }; libgit2-0.19.0/tests-clar/odb/pack_data_one.h000066400000000000000000000015051216214232500207020ustar00rootroot00000000000000/* Just a few to make sure it's working, the rest is tested already */ static const char *packed_objects_one[] = { "9fcf811e00fa469688943a9152c16d4ee90fb9a9", "a93f42a5b5e9de40fa645a9ff1e276a021c9542b", "12bf5f3e3470d90db177ccf1b5e8126409377fc6", "ed1ea164cdbe3c4b200fb4fa19861ea90eaee222", "dfae6ed8f6dd8acc3b40a31811ea316239223559", "aefe66d192771201e369fde830530f4475beec30", "775e4b4c1296e9e3104f2a36ca9cf9356a130959", "412ec4e4a6a7419bc1be00561fe474e54cb499fe", "236e7579fed7763be77209efb8708960982f3cb3", "09fe9364461cf60dd1c46b0e9545b1e47bb1a297", "d76d8a6390d1cf32138d98a91b1eb7e0275a12f5", "d0fdf2dcff2f548952eec536ccc6d266550041bc", "a20d733a9fa79fa5b4cbb9639864f93325ec27a6", "785d3fe8e7db5ade2c2242fecd46c32a7f4dc59f", "4d8d0fd9cb6045075385701c3f933ec13345e9c4", "0cfd861bd547b6520d1fc2e190e8359e0a9c9b90" }; libgit2-0.19.0/tests-clar/odb/packed.c000066400000000000000000000030521216214232500173530ustar00rootroot00000000000000#include "clar_libgit2.h" #include "odb.h" #include "pack_data.h" static git_odb *_odb; void test_odb_packed__initialize(void) { cl_git_pass(git_odb_open(&_odb, cl_fixture("testrepo.git/objects"))); } void test_odb_packed__cleanup(void) { git_odb_free(_odb); _odb = NULL; } void test_odb_packed__mass_read(void) { unsigned int i; for (i = 0; i < ARRAY_SIZE(packed_objects); ++i) { git_oid id; git_odb_object *obj; cl_git_pass(git_oid_fromstr(&id, packed_objects[i])); cl_assert(git_odb_exists(_odb, &id) == 1); cl_git_pass(git_odb_read(&obj, _odb, &id)); git_odb_object_free(obj); } } void test_odb_packed__read_header_0(void) { unsigned int i; for (i = 0; i < ARRAY_SIZE(packed_objects); ++i) { git_oid id; git_odb_object *obj; size_t len; git_otype type; cl_git_pass(git_oid_fromstr(&id, packed_objects[i])); cl_git_pass(git_odb_read(&obj, _odb, &id)); cl_git_pass(git_odb_read_header(&len, &type, _odb, &id)); cl_assert(obj->cached.size == len); cl_assert(obj->cached.type == type); git_odb_object_free(obj); } } void test_odb_packed__read_header_1(void) { unsigned int i; for (i = 0; i < ARRAY_SIZE(loose_objects); ++i) { git_oid id; git_odb_object *obj; size_t len; git_otype type; cl_git_pass(git_oid_fromstr(&id, loose_objects[i])); cl_assert(git_odb_exists(_odb, &id) == 1); cl_git_pass(git_odb_read(&obj, _odb, &id)); cl_git_pass(git_odb_read_header(&len, &type, _odb, &id)); cl_assert(obj->cached.size == len); cl_assert(obj->cached.type == type); git_odb_object_free(obj); } } libgit2-0.19.0/tests-clar/odb/packed_one.c000066400000000000000000000024621216214232500202200ustar00rootroot00000000000000#include "clar_libgit2.h" #include "git2/odb_backend.h" #include "pack_data_one.h" #include "pack.h" static git_odb *_odb; void test_odb_packed_one__initialize(void) { git_odb_backend *backend = NULL; cl_git_pass(git_odb_new(&_odb)); cl_git_pass(git_odb_backend_one_pack(&backend, cl_fixture("testrepo.git/objects/pack/pack-a81e489679b7d3418f9ab594bda8ceb37dd4c695.idx"))); cl_git_pass(git_odb_add_backend(_odb, backend, 1)); } void test_odb_packed_one__cleanup(void) { git_odb_free(_odb); _odb = NULL; } void test_odb_packed_one__mass_read(void) { unsigned int i; for (i = 0; i < ARRAY_SIZE(packed_objects_one); ++i) { git_oid id; git_odb_object *obj; cl_git_pass(git_oid_fromstr(&id, packed_objects_one[i])); cl_assert(git_odb_exists(_odb, &id) == 1); cl_git_pass(git_odb_read(&obj, _odb, &id)); git_odb_object_free(obj); } } void test_odb_packed_one__read_header_0(void) { unsigned int i; for (i = 0; i < ARRAY_SIZE(packed_objects_one); ++i) { git_oid id; git_odb_object *obj; size_t len; git_otype type; cl_git_pass(git_oid_fromstr(&id, packed_objects_one[i])); cl_git_pass(git_odb_read(&obj, _odb, &id)); cl_git_pass(git_odb_read_header(&len, &type, _odb, &id)); cl_assert(obj->cached.size == len); cl_assert(obj->cached.type == type); git_odb_object_free(obj); } } libgit2-0.19.0/tests-clar/odb/sorting.c000066400000000000000000000033671216214232500176220ustar00rootroot00000000000000#include "clar_libgit2.h" #include "git2/sys/odb_backend.h" typedef struct { git_odb_backend base; size_t position; } fake_backend; static git_odb_backend *new_backend(size_t position) { fake_backend *b; b = git__calloc(1, sizeof(fake_backend)); if (b == NULL) return NULL; b->base.version = GIT_ODB_BACKEND_VERSION; b->position = position; return (git_odb_backend *)b; } static void check_backend_sorting(git_odb *odb) { size_t i, max_i = git_odb_num_backends(odb); fake_backend *internal; for (i = 0; i < max_i; ++i) { cl_git_pass(git_odb_get_backend((git_odb_backend **)&internal, odb, i)); cl_assert(internal != NULL); cl_assert_equal_sz(i, internal->position); } } static git_odb *_odb; void test_odb_sorting__initialize(void) { cl_git_pass(git_odb_new(&_odb)); } void test_odb_sorting__cleanup(void) { git_odb_free(_odb); _odb = NULL; } void test_odb_sorting__basic_backends_sorting(void) { cl_git_pass(git_odb_add_backend(_odb, new_backend(0), 5)); cl_git_pass(git_odb_add_backend(_odb, new_backend(2), 3)); cl_git_pass(git_odb_add_backend(_odb, new_backend(1), 4)); cl_git_pass(git_odb_add_backend(_odb, new_backend(3), 1)); check_backend_sorting(_odb); } void test_odb_sorting__alternate_backends_sorting(void) { cl_git_pass(git_odb_add_backend(_odb, new_backend(0), 5)); cl_git_pass(git_odb_add_backend(_odb, new_backend(2), 3)); cl_git_pass(git_odb_add_backend(_odb, new_backend(1), 4)); cl_git_pass(git_odb_add_backend(_odb, new_backend(3), 1)); cl_git_pass(git_odb_add_alternate(_odb, new_backend(4), 5)); cl_git_pass(git_odb_add_alternate(_odb, new_backend(6), 3)); cl_git_pass(git_odb_add_alternate(_odb, new_backend(5), 4)); cl_git_pass(git_odb_add_alternate(_odb, new_backend(7), 1)); check_backend_sorting(_odb); } libgit2-0.19.0/tests-clar/online/000077500000000000000000000000001216214232500165005ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/online/clone.c000066400000000000000000000137261216214232500177550ustar00rootroot00000000000000#include "clar_libgit2.h" #include "git2/clone.h" #include "git2/cred_helpers.h" #include "remote.h" #include "fileops.h" #include "refs.h" #define LIVE_REPO_URL "http://github.com/libgit2/TestGitRepository" #define LIVE_EMPTYREPO_URL "http://github.com/libgit2/TestEmptyRepository" #define BB_REPO_URL "https://libgit2@bitbucket.org/libgit2/testgitrepository.git" #define BB_REPO_URL_WITH_PASS "https://libgit2:libgit2@bitbucket.org/libgit2/testgitrepository.git" #define BB_REPO_URL_WITH_WRONG_PASS "https://libgit2:wrong@bitbucket.org/libgit2/testgitrepository.git" static git_repository *g_repo; static git_clone_options g_options; void test_online_clone__initialize(void) { git_checkout_opts dummy_opts = GIT_CHECKOUT_OPTS_INIT; g_repo = NULL; memset(&g_options, 0, sizeof(git_clone_options)); g_options.version = GIT_CLONE_OPTIONS_VERSION; g_options.checkout_opts = dummy_opts; g_options.checkout_opts.checkout_strategy = GIT_CHECKOUT_SAFE; } void test_online_clone__cleanup(void) { if (g_repo) { git_repository_free(g_repo); g_repo = NULL; } cl_fixture_cleanup("./foo"); } void test_online_clone__network_full(void) { git_remote *origin; cl_git_pass(git_clone(&g_repo, LIVE_REPO_URL, "./foo", &g_options)); cl_assert(!git_repository_is_bare(g_repo)); cl_git_pass(git_remote_load(&origin, g_repo, "origin")); cl_assert_equal_i(GIT_REMOTE_DOWNLOAD_TAGS_AUTO, origin->download_tags); git_remote_free(origin); } void test_online_clone__network_bare(void) { git_remote *origin; g_options.bare = true; cl_git_pass(git_clone(&g_repo, LIVE_REPO_URL, "./foo", &g_options)); cl_assert(git_repository_is_bare(g_repo)); cl_git_pass(git_remote_load(&origin, g_repo, "origin")); git_remote_free(origin); } void test_online_clone__empty_repository(void) { git_reference *head; cl_git_pass(git_clone(&g_repo, LIVE_EMPTYREPO_URL, "./foo", &g_options)); cl_assert_equal_i(true, git_repository_is_empty(g_repo)); cl_assert_equal_i(true, git_repository_head_orphan(g_repo)); cl_git_pass(git_reference_lookup(&head, g_repo, GIT_HEAD_FILE)); cl_assert_equal_i(GIT_REF_SYMBOLIC, git_reference_type(head)); cl_assert_equal_s("refs/heads/master", git_reference_symbolic_target(head)); git_reference_free(head); } static void checkout_progress(const char *path, size_t cur, size_t tot, void *payload) { bool *was_called = (bool*)payload; GIT_UNUSED(path); GIT_UNUSED(cur); GIT_UNUSED(tot); (*was_called) = true; } static int fetch_progress(const git_transfer_progress *stats, void *payload) { bool *was_called = (bool*)payload; GIT_UNUSED(stats); (*was_called) = true; return 0; } void test_online_clone__can_checkout_a_cloned_repo(void) { git_buf path = GIT_BUF_INIT; git_reference *head; bool checkout_progress_cb_was_called = false, fetch_progress_cb_was_called = false; g_options.checkout_opts.checkout_strategy = GIT_CHECKOUT_SAFE_CREATE; g_options.checkout_opts.progress_cb = &checkout_progress; g_options.checkout_opts.progress_payload = &checkout_progress_cb_was_called; g_options.fetch_progress_cb = &fetch_progress; g_options.fetch_progress_payload = &fetch_progress_cb_was_called; cl_git_pass(git_clone(&g_repo, LIVE_REPO_URL, "./foo", &g_options)); cl_git_pass(git_buf_joinpath(&path, git_repository_workdir(g_repo), "master.txt")); cl_assert_equal_i(true, git_path_isfile(git_buf_cstr(&path))); cl_git_pass(git_reference_lookup(&head, g_repo, "HEAD")); cl_assert_equal_i(GIT_REF_SYMBOLIC, git_reference_type(head)); cl_assert_equal_s("refs/heads/master", git_reference_symbolic_target(head)); cl_assert_equal_i(true, checkout_progress_cb_was_called); cl_assert_equal_i(true, fetch_progress_cb_was_called); git_reference_free(head); git_buf_free(&path); } static int update_tips(const char *refname, const git_oid *a, const git_oid *b, void *payload) { int *callcount = (int*)payload; GIT_UNUSED(refname); GIT_UNUSED(a); GIT_UNUSED(b); *callcount = *callcount + 1; return 0; } void test_online_clone__custom_remote_callbacks(void) { git_remote_callbacks remote_callbacks = GIT_REMOTE_CALLBACKS_INIT; int callcount = 0; g_options.remote_callbacks = &remote_callbacks; remote_callbacks.update_tips = update_tips; remote_callbacks.payload = &callcount; cl_git_pass(git_clone(&g_repo, LIVE_REPO_URL, "./foo", &g_options)); cl_assert(callcount > 0); } void test_online_clone__credentials(void) { /* Remote URL environment variable must be set. User and password are optional. */ const char *remote_url = cl_getenv("GITTEST_REMOTE_URL"); git_cred_userpass_payload user_pass = { cl_getenv("GITTEST_REMOTE_USER"), cl_getenv("GITTEST_REMOTE_PASS") }; if (!remote_url) return; g_options.cred_acquire_cb = git_cred_userpass; g_options.cred_acquire_payload = &user_pass; cl_git_pass(git_clone(&g_repo, remote_url, "./foo", &g_options)); git_repository_free(g_repo); g_repo = NULL; cl_fixture_cleanup("./foo"); } void test_online_clone__bitbucket_style(void) { git_cred_userpass_payload user_pass = { "libgit2", "libgit2" }; g_options.cred_acquire_cb = git_cred_userpass; g_options.cred_acquire_payload = &user_pass; cl_git_pass(git_clone(&g_repo, BB_REPO_URL, "./foo", &g_options)); git_repository_free(g_repo); g_repo = NULL; cl_fixture_cleanup("./foo"); /* User and pass from URL */ user_pass.password = "wrong"; cl_git_pass(git_clone(&g_repo, BB_REPO_URL_WITH_PASS, "./foo", &g_options)); git_repository_free(g_repo); g_repo = NULL; cl_fixture_cleanup("./foo"); /* Wrong password in URL, fall back to user_pass */ user_pass.password = "libgit2"; cl_git_pass(git_clone(&g_repo, BB_REPO_URL_WITH_WRONG_PASS, "./foo", &g_options)); git_repository_free(g_repo); g_repo = NULL; cl_fixture_cleanup("./foo"); } static int cancel_at_half(const git_transfer_progress *stats, void *payload) { GIT_UNUSED(payload); if (stats->received_objects > (stats->total_objects/2)) return 1; return 0; } void test_online_clone__can_cancel(void) { g_options.fetch_progress_cb = cancel_at_half; cl_git_fail_with(git_clone(&g_repo, LIVE_REPO_URL, "./foo", &g_options), GIT_EUSER); } libgit2-0.19.0/tests-clar/online/fetch.c000066400000000000000000000101561216214232500177400ustar00rootroot00000000000000#include "clar_libgit2.h" static git_repository *_repo; static int counter; void test_online_fetch__initialize(void) { cl_git_pass(git_repository_init(&_repo, "./fetch", 0)); } void test_online_fetch__cleanup(void) { git_repository_free(_repo); _repo = NULL; cl_fixture_cleanup("./fetch"); } static int update_tips(const char *refname, const git_oid *a, const git_oid *b, void *data) { GIT_UNUSED(refname); GIT_UNUSED(a); GIT_UNUSED(b); GIT_UNUSED(data); ++counter; return 0; } static int progress(const git_transfer_progress *stats, void *payload) { size_t *bytes_received = (size_t *)payload; *bytes_received = stats->received_bytes; return 0; } static void do_fetch(const char *url, git_remote_autotag_option_t flag, int n) { git_remote *remote; git_remote_callbacks callbacks = GIT_REMOTE_CALLBACKS_INIT; size_t bytes_received = 0; callbacks.update_tips = update_tips; counter = 0; cl_git_pass(git_remote_create(&remote, _repo, "test", url)); git_remote_set_callbacks(remote, &callbacks); git_remote_set_autotag(remote, flag); cl_git_pass(git_remote_connect(remote, GIT_DIRECTION_FETCH)); cl_git_pass(git_remote_download(remote, progress, &bytes_received)); cl_git_pass(git_remote_update_tips(remote)); git_remote_disconnect(remote); cl_assert_equal_i(counter, n); cl_assert(bytes_received > 0); git_remote_free(remote); } void test_online_fetch__default_git(void) { do_fetch("git://github.com/libgit2/TestGitRepository.git", GIT_REMOTE_DOWNLOAD_TAGS_AUTO, 6); } void test_online_fetch__default_http(void) { do_fetch("http://github.com/libgit2/TestGitRepository.git", GIT_REMOTE_DOWNLOAD_TAGS_AUTO, 6); } void test_online_fetch__no_tags_git(void) { do_fetch("git://github.com/libgit2/TestGitRepository.git", GIT_REMOTE_DOWNLOAD_TAGS_NONE, 3); } void test_online_fetch__no_tags_http(void) { do_fetch("http://github.com/libgit2/TestGitRepository.git", GIT_REMOTE_DOWNLOAD_TAGS_NONE, 3); } static int transferProgressCallback(const git_transfer_progress *stats, void *payload) { bool *invoked = (bool *)payload; GIT_UNUSED(stats); *invoked = true; return 0; } void test_online_fetch__doesnt_retrieve_a_pack_when_the_repository_is_up_to_date(void) { git_repository *_repository; bool invoked = false; git_remote *remote; git_clone_options opts = GIT_CLONE_OPTIONS_INIT; opts.bare = true; cl_git_pass(git_clone(&_repository, "https://github.com/libgit2/TestGitRepository.git", "./fetch/lg2", &opts)); git_repository_free(_repository); cl_git_pass(git_repository_open(&_repository, "./fetch/lg2")); cl_git_pass(git_remote_load(&remote, _repository, "origin")); cl_git_pass(git_remote_connect(remote, GIT_DIRECTION_FETCH)); cl_assert_equal_i(false, invoked); cl_git_pass(git_remote_download(remote, &transferProgressCallback, &invoked)); cl_assert_equal_i(false, invoked); cl_git_pass(git_remote_update_tips(remote)); git_remote_disconnect(remote); git_remote_free(remote); git_repository_free(_repository); } static int cancel_at_half(const git_transfer_progress *stats, void *payload) { GIT_UNUSED(payload); if (stats->received_objects > (stats->total_objects/2)) return -1; return 0; } void test_online_fetch__can_cancel(void) { git_remote *remote; size_t bytes_received = 0; cl_git_pass(git_remote_create(&remote, _repo, "test", "http://github.com/libgit2/TestGitRepository.git")); cl_git_pass(git_remote_connect(remote, GIT_DIRECTION_FETCH)); cl_git_fail_with(git_remote_download(remote, cancel_at_half, &bytes_received), GIT_EUSER); git_remote_disconnect(remote); git_remote_free(remote); } int ls_cb(git_remote_head *rhead, void *payload) { int *nr = payload; GIT_UNUSED(rhead); (*nr)++; return 0; } void test_online_fetch__ls_disconnected(void) { git_remote *remote; int nr_before = 0, nr_after = 0; cl_git_pass(git_remote_create(&remote, _repo, "test", "http://github.com/libgit2/TestGitRepository.git")); cl_git_pass(git_remote_connect(remote, GIT_DIRECTION_FETCH)); cl_git_pass(git_remote_ls(remote, ls_cb, &nr_before)); git_remote_disconnect(remote); cl_git_pass(git_remote_ls(remote, ls_cb, &nr_after)); cl_assert_equal_i(nr_before, nr_after); git_remote_free(remote); } libgit2-0.19.0/tests-clar/online/fetchhead.c000066400000000000000000000042421216214232500205610ustar00rootroot00000000000000#include "clar_libgit2.h" #include "fileops.h" #include "fetchhead.h" #include "../fetchhead/fetchhead_data.h" #include "git2/clone.h" #define LIVE_REPO_URL "git://github.com/libgit2/TestGitRepository" static git_repository *g_repo; static git_clone_options g_options; void test_online_fetchhead__initialize(void) { g_repo = NULL; memset(&g_options, 0, sizeof(git_clone_options)); g_options.version = GIT_CLONE_OPTIONS_VERSION; } void test_online_fetchhead__cleanup(void) { if (g_repo) { git_repository_free(g_repo); g_repo = NULL; } cl_fixture_cleanup("./foo"); } static void fetchhead_test_clone(void) { cl_git_pass(git_clone(&g_repo, LIVE_REPO_URL, "./foo", &g_options)); } static void fetchhead_test_fetch(const char *fetchspec, const char *expected_fetchhead) { git_remote *remote; git_buf fetchhead_buf = GIT_BUF_INIT; int equals = 0; cl_git_pass(git_remote_load(&remote, g_repo, "origin")); git_remote_set_autotag(remote, GIT_REMOTE_DOWNLOAD_TAGS_AUTO); if(fetchspec != NULL) { git_remote_clear_refspecs(remote); git_remote_add_fetch(remote, fetchspec); } cl_git_pass(git_remote_connect(remote, GIT_DIRECTION_FETCH)); cl_git_pass(git_remote_download(remote, NULL, NULL)); cl_git_pass(git_remote_update_tips(remote)); git_remote_disconnect(remote); git_remote_free(remote); cl_git_pass(git_futils_readbuffer(&fetchhead_buf, "./foo/.git/FETCH_HEAD")); equals = (strcmp(fetchhead_buf.ptr, expected_fetchhead) == 0); git_buf_free(&fetchhead_buf); cl_assert(equals); } void test_online_fetchhead__wildcard_spec(void) { fetchhead_test_clone(); fetchhead_test_fetch(NULL, FETCH_HEAD_WILDCARD_DATA); } void test_online_fetchhead__explicit_spec(void) { fetchhead_test_clone(); fetchhead_test_fetch("refs/heads/first-merge:refs/remotes/origin/first-merge", FETCH_HEAD_EXPLICIT_DATA); } void test_online_fetchhead__no_merges(void) { git_config *config; fetchhead_test_clone(); cl_git_pass(git_repository_config(&config, g_repo)); cl_git_pass(git_config_delete_entry(config, "branch.master.remote")); cl_git_pass(git_config_delete_entry(config, "branch.master.merge")); git_config_free(config); fetchhead_test_fetch(NULL, FETCH_HEAD_NO_MERGE_DATA); } libgit2-0.19.0/tests-clar/online/push.c000066400000000000000000000533121216214232500176270ustar00rootroot00000000000000#include "clar_libgit2.h" #include "buffer.h" #include "posix.h" #include "vector.h" #include "../submodule/submodule_helpers.h" #include "push_util.h" #include "refspec.h" #include "remote.h" static git_repository *_repo; static char *_remote_url; static char *_remote_user; static char *_remote_pass; static git_remote *_remote; static bool _cred_acquire_called; static record_callbacks_data _record_cbs_data = {{ 0 }}; static git_remote_callbacks _record_cbs = RECORD_CALLBACKS_INIT(&_record_cbs_data); static git_oid _oid_b6; static git_oid _oid_b5; static git_oid _oid_b4; static git_oid _oid_b3; static git_oid _oid_b2; static git_oid _oid_b1; static git_oid _tag_commit; static git_oid _tag_tree; static git_oid _tag_blob; static git_oid _tag_lightweight; static int cred_acquire_cb( git_cred **cred, const char *url, const char *user_from_url, unsigned int allowed_types, void *payload) { GIT_UNUSED(url); GIT_UNUSED(user_from_url); *((bool*)payload) = true; if ((GIT_CREDTYPE_USERPASS_PLAINTEXT & allowed_types) == 0 || git_cred_userpass_plaintext_new(cred, _remote_user, _remote_pass) < 0) return -1; return 0; } typedef struct { const char *ref; const char *msg; } push_status; /** * git_push_status_foreach callback that records status entries. * @param data (git_vector *) of push_status instances */ static int record_push_status_cb(const char *ref, const char *msg, void *data) { git_vector *statuses = (git_vector *)data; push_status *s; cl_assert(s = git__malloc(sizeof(*s))); s->ref = ref; s->msg = msg; git_vector_insert(statuses, s); return 0; } static void do_verify_push_status(git_push *push, const push_status expected[], const size_t expected_len) { git_vector actual = GIT_VECTOR_INIT; push_status *iter; bool failed = false; size_t i; git_push_status_foreach(push, record_push_status_cb, &actual); if (expected_len != actual.length) failed = true; else git_vector_foreach(&actual, i, iter) if (strcmp(expected[i].ref, iter->ref) || (expected[i].msg && !iter->msg) || (!expected[i].msg && iter->msg) || (expected[i].msg && iter->msg && strcmp(expected[i].msg, iter->msg))) { failed = true; break; } if (failed) { git_buf msg = GIT_BUF_INIT; git_buf_puts(&msg, "Expected and actual push statuses differ:\nEXPECTED:\n"); for(i = 0; i < expected_len; i++) { git_buf_printf(&msg, "%s: %s\n", expected[i].ref, expected[i].msg ? expected[i].msg : ""); } git_buf_puts(&msg, "\nACTUAL:\n"); git_vector_foreach(&actual, i, iter) git_buf_printf(&msg, "%s: %s\n", iter->ref, iter->msg); cl_fail(git_buf_cstr(&msg)); git_buf_free(&msg); } git_vector_foreach(&actual, i, iter) git__free(iter); git_vector_free(&actual); } /** * Verifies that after git_push_finish(), refs on a remote have the expected * names, oids, and order. * * @param remote remote to verify * @param expected_refs expected remote refs after push * @param expected_refs_len length of expected_refs */ static void verify_refs(git_remote *remote, expected_ref expected_refs[], size_t expected_refs_len) { git_vector actual_refs = GIT_VECTOR_INIT; git_remote_ls(remote, record_ref_cb, &actual_refs); verify_remote_refs(&actual_refs, expected_refs, expected_refs_len); git_vector_free(&actual_refs); } static int tracking_branch_list_cb(const char *branch_name, git_branch_t branch_type, void *payload) { git_vector *tracking = (git_vector *)payload; if (branch_type == GIT_BRANCH_REMOTE) git_vector_insert(tracking, git__strdup(branch_name)); else GIT_UNUSED(branch_name); return 0; } /** * Verifies that after git_push_update_tips(), remote tracking branches have the expected * names and oids. * * @param remote remote to verify * @param expected_refs expected remote refs after push * @param expected_refs_len length of expected_refs */ static void verify_tracking_branches(git_remote *remote, expected_ref expected_refs[], size_t expected_refs_len) { git_refspec *fetch_spec; size_t i, j; git_buf msg = GIT_BUF_INIT; git_buf ref_name = GIT_BUF_INIT; git_buf canonical_ref_name = GIT_BUF_INIT; git_vector actual_refs = GIT_VECTOR_INIT; char *actual_ref; git_oid oid; int failed = 0; /* Get current remote branches */ cl_git_pass(git_branch_foreach(remote->repo, GIT_BRANCH_REMOTE, tracking_branch_list_cb, &actual_refs)); /* Loop through expected refs, make sure they exist */ for (i = 0; i < expected_refs_len; i++) { /* Convert remote reference name into tracking branch name. * If the spec is not under refs/heads/, then skip. */ fetch_spec = git_remote__matching_refspec(remote, expected_refs[i].name); if (!fetch_spec) continue; cl_git_pass(git_refspec_transform_r(&ref_name, fetch_spec, expected_refs[i].name)); /* Find matching remote branch */ git_vector_foreach(&actual_refs, j, actual_ref) { /* Construct canonical ref name from the actual_ref name */ git_buf_clear(&canonical_ref_name); cl_git_pass(git_buf_printf(&canonical_ref_name, "refs/remotes/%s", actual_ref)); if (!strcmp(git_buf_cstr(&ref_name), git_buf_cstr(&canonical_ref_name))) break; } if (j == actual_refs.length) { git_buf_printf(&msg, "Did not find expected tracking branch '%s'.", git_buf_cstr(&ref_name)); failed = 1; goto failed; } /* Make sure tracking branch is at expected commit ID */ cl_git_pass(git_reference_name_to_id(&oid, remote->repo, git_buf_cstr(&canonical_ref_name))); if (git_oid_cmp(expected_refs[i].oid, &oid) != 0) { git_buf_puts(&msg, "Tracking branch commit does not match expected ID."); failed = 1; goto failed; } git__free(actual_ref); cl_git_pass(git_vector_remove(&actual_refs, j)); } /* Make sure there are no extra branches */ if (actual_refs.length > 0) { git_buf_puts(&msg, "Unexpected remote tracking branches exist."); failed = 1; goto failed; } failed: if(failed) cl_fail(git_buf_cstr(&msg)); git_vector_foreach(&actual_refs, i, actual_ref) git__free(actual_ref); git_vector_free(&actual_refs); git_buf_free(&msg); git_buf_free(&canonical_ref_name); git_buf_free(&ref_name); return; } void test_online_push__initialize(void) { git_vector delete_specs = GIT_VECTOR_INIT; size_t i; char *curr_del_spec; _cred_acquire_called = false; _repo = cl_git_sandbox_init("push_src"); cl_fixture_sandbox("testrepo.git"); cl_rename("push_src/submodule/.gitted", "push_src/submodule/.git"); rewrite_gitmodules(git_repository_workdir(_repo)); /* git log --format=oneline --decorate --graph * *-. 951bbbb90e2259a4c8950db78946784fb53fcbce (HEAD, b6) merge b3, b4, and b5 to b6 * |\ \ * | | * fa38b91f199934685819bea316186d8b008c52a2 (b5) added submodule named 'submodule' pointing to '../testrepo.git' * | * | 27b7ce66243eb1403862d05f958c002312df173d (b4) edited fold\b.txt * | |/ * * | d9b63a88223d8367516f50bd131a5f7349b7f3e4 (b3) edited a.txt * |/ * * a78705c3b2725f931d3ee05348d83cc26700f247 (b2, b1) added fold and fold/b.txt * * 5c0bb3d1b9449d1cc69d7519fd05166f01840915 added a.txt */ git_oid_fromstr(&_oid_b6, "951bbbb90e2259a4c8950db78946784fb53fcbce"); git_oid_fromstr(&_oid_b5, "fa38b91f199934685819bea316186d8b008c52a2"); git_oid_fromstr(&_oid_b4, "27b7ce66243eb1403862d05f958c002312df173d"); git_oid_fromstr(&_oid_b3, "d9b63a88223d8367516f50bd131a5f7349b7f3e4"); git_oid_fromstr(&_oid_b2, "a78705c3b2725f931d3ee05348d83cc26700f247"); git_oid_fromstr(&_oid_b1, "a78705c3b2725f931d3ee05348d83cc26700f247"); git_oid_fromstr(&_tag_commit, "805c54522e614f29f70d2413a0470247d8b424ac"); git_oid_fromstr(&_tag_tree, "ff83aa4c5e5d28e3bcba2f5c6e2adc61286a4e5e"); git_oid_fromstr(&_tag_blob, "b483ae7ba66decee9aee971f501221dea84b1498"); git_oid_fromstr(&_tag_lightweight, "951bbbb90e2259a4c8950db78946784fb53fcbce"); /* Remote URL environment variable must be set. User and password are optional. */ _remote_url = cl_getenv("GITTEST_REMOTE_URL"); _remote_user = cl_getenv("GITTEST_REMOTE_USER"); _remote_pass = cl_getenv("GITTEST_REMOTE_PASS"); _remote = NULL; if (_remote_url) { cl_git_pass(git_remote_create(&_remote, _repo, "test", _remote_url)); git_remote_set_cred_acquire_cb(_remote, cred_acquire_cb, &_cred_acquire_called); record_callbacks_data_clear(&_record_cbs_data); git_remote_set_callbacks(_remote, &_record_cbs); cl_git_pass(git_remote_connect(_remote, GIT_DIRECTION_PUSH)); /* Clean up previously pushed branches. Fails if receive.denyDeletes is * set on the remote. Also, on Git 1.7.0 and newer, you must run * 'git config receive.denyDeleteCurrent ignore' in the remote repo in * order to delete the remote branch pointed to by HEAD (usually master). * See: https://raw.github.com/git/git/master/Documentation/RelNotes/1.7.0.txt */ cl_git_pass(git_remote_ls(_remote, delete_ref_cb, &delete_specs)); if (delete_specs.length) { git_push *push; cl_git_pass(git_push_new(&push, _remote)); git_vector_foreach(&delete_specs, i, curr_del_spec) { git_push_add_refspec(push, curr_del_spec); git__free(curr_del_spec); } cl_git_pass(git_push_finish(push)); git_push_free(push); } git_remote_disconnect(_remote); git_vector_free(&delete_specs); /* Now that we've deleted everything, fetch from the remote */ cl_git_pass(git_remote_connect(_remote, GIT_DIRECTION_FETCH)); cl_git_pass(git_remote_download(_remote, NULL, NULL)); cl_git_pass(git_remote_update_tips(_remote)); git_remote_disconnect(_remote); } else printf("GITTEST_REMOTE_URL unset; skipping push test\n"); } void test_online_push__cleanup(void) { if (_remote) git_remote_free(_remote); _remote = NULL; /* Freed by cl_git_sandbox_cleanup */ _repo = NULL; record_callbacks_data_clear(&_record_cbs_data); cl_fixture_cleanup("testrepo.git"); cl_git_sandbox_cleanup(); } /** * Calls push and relists refs on remote to verify success. * * @param refspecs refspecs to push * @param refspecs_len length of refspecs * @param expected_refs expected remote refs after push * @param expected_refs_len length of expected_refs * @param expected_ret expected return value from git_push_finish() */ static void do_push(const char *refspecs[], size_t refspecs_len, push_status expected_statuses[], size_t expected_statuses_len, expected_ref expected_refs[], size_t expected_refs_len, int expected_ret) { git_push *push; git_push_options opts = GIT_PUSH_OPTIONS_INIT; size_t i; int ret; if (_remote) { /* Auto-detect the number of threads to use */ opts.pb_parallelism = 0; cl_git_pass(git_remote_connect(_remote, GIT_DIRECTION_PUSH)); cl_git_pass(git_push_new(&push, _remote)); cl_git_pass(git_push_set_options(push, &opts)); for (i = 0; i < refspecs_len; i++) cl_git_pass(git_push_add_refspec(push, refspecs[i])); if (expected_ret < 0) { cl_git_fail(ret = git_push_finish(push)); cl_assert_equal_i(0, git_push_unpack_ok(push)); } else { cl_git_pass(ret = git_push_finish(push)); cl_assert_equal_i(1, git_push_unpack_ok(push)); } do_verify_push_status(push, expected_statuses, expected_statuses_len); cl_assert_equal_i(expected_ret, ret); verify_refs(_remote, expected_refs, expected_refs_len); cl_git_pass(git_push_update_tips(push)); verify_tracking_branches(_remote, expected_refs, expected_refs_len); git_push_free(push); git_remote_disconnect(_remote); } } /* Call push_finish() without ever calling git_push_add_refspec() */ void test_online_push__noop(void) { do_push(NULL, 0, NULL, 0, NULL, 0, 0); } void test_online_push__b1(void) { const char *specs[] = { "refs/heads/b1:refs/heads/b1" }; push_status exp_stats[] = { { "refs/heads/b1", NULL } }; expected_ref exp_refs[] = { { "refs/heads/b1", &_oid_b1 } }; do_push(specs, ARRAY_SIZE(specs), exp_stats, ARRAY_SIZE(exp_stats), exp_refs, ARRAY_SIZE(exp_refs), 0); } void test_online_push__b2(void) { const char *specs[] = { "refs/heads/b2:refs/heads/b2" }; push_status exp_stats[] = { { "refs/heads/b2", NULL } }; expected_ref exp_refs[] = { { "refs/heads/b2", &_oid_b2 } }; do_push(specs, ARRAY_SIZE(specs), exp_stats, ARRAY_SIZE(exp_stats), exp_refs, ARRAY_SIZE(exp_refs), 0); } void test_online_push__b3(void) { const char *specs[] = { "refs/heads/b3:refs/heads/b3" }; push_status exp_stats[] = { { "refs/heads/b3", NULL } }; expected_ref exp_refs[] = { { "refs/heads/b3", &_oid_b3 } }; do_push(specs, ARRAY_SIZE(specs), exp_stats, ARRAY_SIZE(exp_stats), exp_refs, ARRAY_SIZE(exp_refs), 0); } void test_online_push__b4(void) { const char *specs[] = { "refs/heads/b4:refs/heads/b4" }; push_status exp_stats[] = { { "refs/heads/b4", NULL } }; expected_ref exp_refs[] = { { "refs/heads/b4", &_oid_b4 } }; do_push(specs, ARRAY_SIZE(specs), exp_stats, ARRAY_SIZE(exp_stats), exp_refs, ARRAY_SIZE(exp_refs), 0); } void test_online_push__b5(void) { const char *specs[] = { "refs/heads/b5:refs/heads/b5" }; push_status exp_stats[] = { { "refs/heads/b5", NULL } }; expected_ref exp_refs[] = { { "refs/heads/b5", &_oid_b5 } }; do_push(specs, ARRAY_SIZE(specs), exp_stats, ARRAY_SIZE(exp_stats), exp_refs, ARRAY_SIZE(exp_refs), 0); } void test_online_push__multi(void) { const char *specs[] = { "refs/heads/b1:refs/heads/b1", "refs/heads/b2:refs/heads/b2", "refs/heads/b3:refs/heads/b3", "refs/heads/b4:refs/heads/b4", "refs/heads/b5:refs/heads/b5" }; push_status exp_stats[] = { { "refs/heads/b1", NULL }, { "refs/heads/b2", NULL }, { "refs/heads/b3", NULL }, { "refs/heads/b4", NULL }, { "refs/heads/b5", NULL } }; expected_ref exp_refs[] = { { "refs/heads/b1", &_oid_b1 }, { "refs/heads/b2", &_oid_b2 }, { "refs/heads/b3", &_oid_b3 }, { "refs/heads/b4", &_oid_b4 }, { "refs/heads/b5", &_oid_b5 } }; do_push(specs, ARRAY_SIZE(specs), exp_stats, ARRAY_SIZE(exp_stats), exp_refs, ARRAY_SIZE(exp_refs), 0); } void test_online_push__implicit_tgt(void) { const char *specs1[] = { "refs/heads/b1:" }; push_status exp_stats1[] = { { "refs/heads/b1", NULL } }; expected_ref exp_refs1[] = { { "refs/heads/b1", &_oid_b1 } }; const char *specs2[] = { "refs/heads/b2:" }; push_status exp_stats2[] = { { "refs/heads/b2", NULL } }; expected_ref exp_refs2[] = { { "refs/heads/b1", &_oid_b1 }, { "refs/heads/b2", &_oid_b2 } }; do_push(specs1, ARRAY_SIZE(specs1), exp_stats1, ARRAY_SIZE(exp_stats1), exp_refs1, ARRAY_SIZE(exp_refs1), 0); do_push(specs2, ARRAY_SIZE(specs2), exp_stats2, ARRAY_SIZE(exp_stats2), exp_refs2, ARRAY_SIZE(exp_refs2), 0); } void test_online_push__fast_fwd(void) { /* Fast forward b1 in tgt from _oid_b1 to _oid_b6. */ const char *specs_init[] = { "refs/heads/b1:refs/heads/b1" }; push_status exp_stats_init[] = { { "refs/heads/b1", NULL } }; expected_ref exp_refs_init[] = { { "refs/heads/b1", &_oid_b1 } }; const char *specs_ff[] = { "refs/heads/b6:refs/heads/b1" }; push_status exp_stats_ff[] = { { "refs/heads/b1", NULL } }; expected_ref exp_refs_ff[] = { { "refs/heads/b1", &_oid_b6 } }; /* Do a force push to reset b1 in target back to _oid_b1 */ const char *specs_reset[] = { "+refs/heads/b1:refs/heads/b1" }; /* Force should have no effect on a fast forward push */ const char *specs_ff_force[] = { "+refs/heads/b6:refs/heads/b1" }; do_push(specs_init, ARRAY_SIZE(specs_init), exp_stats_init, ARRAY_SIZE(exp_stats_init), exp_refs_init, ARRAY_SIZE(exp_refs_init), 0); do_push(specs_ff, ARRAY_SIZE(specs_ff), exp_stats_ff, ARRAY_SIZE(exp_stats_ff), exp_refs_ff, ARRAY_SIZE(exp_refs_ff), 0); do_push(specs_reset, ARRAY_SIZE(specs_reset), exp_stats_init, ARRAY_SIZE(exp_stats_init), exp_refs_init, ARRAY_SIZE(exp_refs_init), 0); do_push(specs_ff_force, ARRAY_SIZE(specs_ff_force), exp_stats_ff, ARRAY_SIZE(exp_stats_ff), exp_refs_ff, ARRAY_SIZE(exp_refs_ff), 0); } void test_online_push__tag_commit(void) { const char *specs[] = { "refs/tags/tag-commit:refs/tags/tag-commit" }; push_status exp_stats[] = { { "refs/tags/tag-commit", NULL } }; expected_ref exp_refs[] = { { "refs/tags/tag-commit", &_tag_commit } }; do_push(specs, ARRAY_SIZE(specs), exp_stats, ARRAY_SIZE(exp_stats), exp_refs, ARRAY_SIZE(exp_refs), 0); } void test_online_push__tag_tree(void) { const char *specs[] = { "refs/tags/tag-tree:refs/tags/tag-tree" }; push_status exp_stats[] = { { "refs/tags/tag-tree", NULL } }; expected_ref exp_refs[] = { { "refs/tags/tag-tree", &_tag_tree } }; do_push(specs, ARRAY_SIZE(specs), exp_stats, ARRAY_SIZE(exp_stats), exp_refs, ARRAY_SIZE(exp_refs), 0); } void test_online_push__tag_blob(void) { const char *specs[] = { "refs/tags/tag-blob:refs/tags/tag-blob" }; push_status exp_stats[] = { { "refs/tags/tag-blob", NULL } }; expected_ref exp_refs[] = { { "refs/tags/tag-blob", &_tag_blob } }; do_push(specs, ARRAY_SIZE(specs), exp_stats, ARRAY_SIZE(exp_stats), exp_refs, ARRAY_SIZE(exp_refs), 0); } void test_online_push__tag_lightweight(void) { const char *specs[] = { "refs/tags/tag-lightweight:refs/tags/tag-lightweight" }; push_status exp_stats[] = { { "refs/tags/tag-lightweight", NULL } }; expected_ref exp_refs[] = { { "refs/tags/tag-lightweight", &_tag_lightweight } }; do_push(specs, ARRAY_SIZE(specs), exp_stats, ARRAY_SIZE(exp_stats), exp_refs, ARRAY_SIZE(exp_refs), 0); } void test_online_push__force(void) { const char *specs1[] = {"refs/heads/b3:refs/heads/tgt"}; push_status exp_stats1[] = { { "refs/heads/tgt", NULL } }; expected_ref exp_refs1[] = { { "refs/heads/tgt", &_oid_b3 } }; const char *specs2[] = {"refs/heads/b4:refs/heads/tgt"}; const char *specs2_force[] = {"+refs/heads/b4:refs/heads/tgt"}; push_status exp_stats2_force[] = { { "refs/heads/tgt", NULL } }; expected_ref exp_refs2_force[] = { { "refs/heads/tgt", &_oid_b4 } }; do_push(specs1, ARRAY_SIZE(specs1), exp_stats1, ARRAY_SIZE(exp_stats1), exp_refs1, ARRAY_SIZE(exp_refs1), 0); do_push(specs2, ARRAY_SIZE(specs2), NULL, 0, exp_refs1, ARRAY_SIZE(exp_refs1), GIT_ENONFASTFORWARD); /* Non-fast-forward update with force should pass. */ do_push(specs2_force, ARRAY_SIZE(specs2_force), exp_stats2_force, ARRAY_SIZE(exp_stats2_force), exp_refs2_force, ARRAY_SIZE(exp_refs2_force), 0); } void test_online_push__delete(void) { const char *specs1[] = { "refs/heads/b1:refs/heads/tgt1", "refs/heads/b1:refs/heads/tgt2" }; push_status exp_stats1[] = { { "refs/heads/tgt1", NULL }, { "refs/heads/tgt2", NULL } }; expected_ref exp_refs1[] = { { "refs/heads/tgt1", &_oid_b1 }, { "refs/heads/tgt2", &_oid_b1 } }; const char *specs_del_fake[] = { ":refs/heads/fake" }; /* Force has no effect for delete. */ const char *specs_del_fake_force[] = { "+:refs/heads/fake" }; push_status exp_stats_fake[] = { { "refs/heads/fake", NULL } }; const char *specs_delete[] = { ":refs/heads/tgt1" }; push_status exp_stats_delete[] = { { "refs/heads/tgt1", NULL } }; expected_ref exp_refs_delete[] = { { "refs/heads/tgt2", &_oid_b1 } }; /* Force has no effect for delete. */ const char *specs_delete_force[] = { "+:refs/heads/tgt1" }; do_push(specs1, ARRAY_SIZE(specs1), exp_stats1, ARRAY_SIZE(exp_stats1), exp_refs1, ARRAY_SIZE(exp_refs1), 0); /* When deleting a non-existent branch, the git client sends zero for both * the old and new commit id. This should succeed on the server with the * same status report as if the branch were actually deleted. The server * returns a warning on the side-band iff the side-band is supported. * Since libgit2 doesn't support the side-band yet, there are no warnings. */ do_push(specs_del_fake, ARRAY_SIZE(specs_del_fake), exp_stats_fake, 1, exp_refs1, ARRAY_SIZE(exp_refs1), 0); do_push(specs_del_fake_force, ARRAY_SIZE(specs_del_fake_force), exp_stats_fake, 1, exp_refs1, ARRAY_SIZE(exp_refs1), 0); /* Delete one of the pushed branches. */ do_push(specs_delete, ARRAY_SIZE(specs_delete), exp_stats_delete, ARRAY_SIZE(exp_stats_delete), exp_refs_delete, ARRAY_SIZE(exp_refs_delete), 0); /* Re-push branches and retry delete with force. */ do_push(specs1, ARRAY_SIZE(specs1), exp_stats1, ARRAY_SIZE(exp_stats1), exp_refs1, ARRAY_SIZE(exp_refs1), 0); do_push(specs_delete_force, ARRAY_SIZE(specs_delete_force), exp_stats_delete, ARRAY_SIZE(exp_stats_delete), exp_refs_delete, ARRAY_SIZE(exp_refs_delete), 0); } void test_online_push__bad_refspecs(void) { /* All classes of refspecs that should be rejected by * git_push_add_refspec() should go in this test. */ git_push *push; if (_remote) { // cl_git_pass(git_remote_connect(_remote, GIT_DIRECTION_PUSH)); cl_git_pass(git_push_new(&push, _remote)); /* Unexpanded branch names not supported */ cl_git_fail(git_push_add_refspec(push, "b6:b6")); git_push_free(push); } } void test_online_push__expressions(void) { /* TODO: Expressions in refspecs doesn't actually work yet */ const char *specs_left_expr[] = { "refs/heads/b2~1:refs/heads/b2" }; const char *specs_right_expr[] = { "refs/heads/b2:refs/heads/b2~1" }; push_status exp_stats_right_expr[] = { { "refs/heads/b2~1", "funny refname" } }; /* TODO: Find a more precise way of checking errors than a exit code of -1. */ do_push(specs_left_expr, ARRAY_SIZE(specs_left_expr), NULL, 0, NULL, 0, -1); do_push(specs_right_expr, ARRAY_SIZE(specs_right_expr), exp_stats_right_expr, ARRAY_SIZE(exp_stats_right_expr), NULL, 0, 0); } void test_online_push__notes(void) { git_oid note_oid, *target_oid, expected_oid; git_signature *signature; const char *specs[] = { "refs/notes/commits:refs/notes/commits" }; push_status exp_stats[] = { { "refs/notes/commits", NULL } }; expected_ref exp_refs[] = { { "refs/notes/commits", &expected_oid } }; git_oid_fromstr(&expected_oid, "8461a99b27b7043e58ff6e1f5d2cf07d282534fb"); target_oid = &_oid_b6; /* Create note to push */ cl_git_pass(git_signature_new(&signature, "nulltoken", "emeric.fermas@gmail.com", 1323847743, 60)); /* Wed Dec 14 08:29:03 2011 +0100 */ cl_git_pass(git_note_create(¬e_oid, _repo, signature, signature, NULL, target_oid, "hello world\n", 0)); do_push(specs, ARRAY_SIZE(specs), exp_stats, ARRAY_SIZE(exp_stats), exp_refs, ARRAY_SIZE(exp_refs), 0); git_signature_free(signature); } libgit2-0.19.0/tests-clar/online/push_util.c000066400000000000000000000061351216214232500206650ustar00rootroot00000000000000 #include "clar_libgit2.h" #include "buffer.h" #include "vector.h" #include "push_util.h" const git_oid OID_ZERO = {{ 0 }}; void updated_tip_free(updated_tip *t) { git__free(t->name); git__free(t->old_oid); git__free(t->new_oid); git__free(t); } void record_callbacks_data_clear(record_callbacks_data *data) { size_t i; updated_tip *tip; git_vector_foreach(&data->updated_tips, i, tip) updated_tip_free(tip); git_vector_free(&data->updated_tips); } int record_update_tips_cb(const char *refname, const git_oid *a, const git_oid *b, void *data) { updated_tip *t; record_callbacks_data *record_data = (record_callbacks_data *)data; cl_assert(t = git__malloc(sizeof(*t))); cl_assert(t->name = git__strdup(refname)); cl_assert(t->old_oid = git__malloc(sizeof(*t->old_oid))); git_oid_cpy(t->old_oid, a); cl_assert(t->new_oid = git__malloc(sizeof(*t->new_oid))); git_oid_cpy(t->new_oid, b); git_vector_insert(&record_data->updated_tips, t); return 0; } int delete_ref_cb(git_remote_head *head, void *payload) { git_vector *delete_specs = (git_vector *)payload; git_buf del_spec = GIT_BUF_INIT; /* Ignore malformed ref names (which also saves us from tag^{} */ if (!git_reference_is_valid_name(head->name)) return 0; /* Create a refspec that deletes a branch in the remote */ if (strcmp(head->name, "refs/heads/master")) { cl_git_pass(git_buf_putc(&del_spec, ':')); cl_git_pass(git_buf_puts(&del_spec, head->name)); cl_git_pass(git_vector_insert(delete_specs, git_buf_detach(&del_spec))); } return 0; } int record_ref_cb(git_remote_head *head, void *payload) { git_vector *refs = (git_vector *) payload; return git_vector_insert(refs, head); } void verify_remote_refs(git_vector *actual_refs, const expected_ref expected_refs[], size_t expected_refs_len) { size_t i, j = 0; git_buf msg = GIT_BUF_INIT; git_remote_head *actual; char *oid_str; bool master_present = false; /* We don't care whether "master" is present on the other end or not */ git_vector_foreach(actual_refs, i, actual) { if (!strcmp(actual->name, "refs/heads/master")) { master_present = true; break; } } if (expected_refs_len + (master_present ? 1 : 0) != actual_refs->length) goto failed; git_vector_foreach(actual_refs, i, actual) { if (master_present && !strcmp(actual->name, "refs/heads/master")) continue; if (strcmp(expected_refs[j].name, actual->name) || git_oid_cmp(expected_refs[j].oid, &actual->oid)) goto failed; j++; } return; failed: git_buf_puts(&msg, "Expected and actual refs differ:\nEXPECTED:\n"); for(i = 0; i < expected_refs_len; i++) { cl_assert(oid_str = git_oid_allocfmt(expected_refs[i].oid)); cl_git_pass(git_buf_printf(&msg, "%s = %s\n", expected_refs[i].name, oid_str)); git__free(oid_str); } git_buf_puts(&msg, "\nACTUAL:\n"); git_vector_foreach(actual_refs, i, actual) { if (master_present && !strcmp(actual->name, "refs/heads/master")) continue; cl_assert(oid_str = git_oid_allocfmt(&actual->oid)); cl_git_pass(git_buf_printf(&msg, "%s = %s\n", actual->name, oid_str)); git__free(oid_str); } cl_fail(git_buf_cstr(&msg)); git_buf_free(&msg); } libgit2-0.19.0/tests-clar/online/push_util.h000066400000000000000000000035151216214232500206710ustar00rootroot00000000000000#ifndef INCLUDE_cl_push_util_h__ #define INCLUDE_cl_push_util_h__ #include "git2/oid.h" /* Constant for zero oid */ extern const git_oid OID_ZERO; /** * Macro for initializing git_remote_callbacks to use test helpers that * record data in a record_callbacks_data instance. * @param data pointer to a record_callbacks_data instance */ #define RECORD_CALLBACKS_INIT(data) \ { GIT_REMOTE_CALLBACKS_VERSION, NULL, NULL, record_update_tips_cb, data } typedef struct { char *name; git_oid *old_oid; git_oid *new_oid; } updated_tip; typedef struct { git_vector updated_tips; } record_callbacks_data; typedef struct { const char *name; const git_oid *oid; } expected_ref; void updated_tip_free(updated_tip *t); void record_callbacks_data_clear(record_callbacks_data *data); /** * Callback for git_remote_update_tips that records updates * * @param data (git_vector *) of updated_tip instances */ int record_update_tips_cb(const char *refname, const git_oid *a, const git_oid *b, void *data); /** * Callback for git_remote_list that adds refspecs to delete each ref * * @param head a ref on the remote * @param payload a git_push instance */ int delete_ref_cb(git_remote_head *head, void *payload); /** * Callback for git_remote_list that adds refspecs to vector * * @param head a ref on the remote * @param payload (git_vector *) of git_remote_head instances */ int record_ref_cb(git_remote_head *head, void *payload); /** * Verifies that refs on remote stored by record_ref_cb match the expected * names, oids, and order. * * @param actual_refs actual refs stored by record_ref_cb() * @param expected_refs expected remote refs * @param expected_refs_len length of expected_refs */ void verify_remote_refs(git_vector *actual_refs, const expected_ref expected_refs[], size_t expected_refs_len); #endif /* INCLUDE_cl_push_util_h__ */ libgit2-0.19.0/tests-clar/pack/000077500000000000000000000000001216214232500161325ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/pack/packbuilder.c000066400000000000000000000075071216214232500205740ustar00rootroot00000000000000#include "clar_libgit2.h" #include "fileops.h" #include "hash.h" #include "iterator.h" #include "vector.h" #include "posix.h" static git_repository *_repo; static git_revwalk *_revwalker; static git_packbuilder *_packbuilder; static git_indexer_stream *_indexer; static git_vector _commits; static int _commits_is_initialized; void test_pack_packbuilder__initialize(void) { _repo = cl_git_sandbox_init("testrepo.git"); cl_git_pass(git_revwalk_new(&_revwalker, _repo)); cl_git_pass(git_packbuilder_new(&_packbuilder, _repo)); cl_git_pass(git_vector_init(&_commits, 0, NULL)); _commits_is_initialized = 1; } void test_pack_packbuilder__cleanup(void) { git_oid *o; unsigned int i; if (_commits_is_initialized) { _commits_is_initialized = 0; git_vector_foreach(&_commits, i, o) { git__free(o); } git_vector_free(&_commits); } git_packbuilder_free(_packbuilder); _packbuilder = NULL; git_revwalk_free(_revwalker); _revwalker = NULL; git_indexer_stream_free(_indexer); _indexer = NULL; cl_git_sandbox_cleanup(); _repo = NULL; } static void seed_packbuilder(void) { git_oid oid, *o; unsigned int i; git_revwalk_sorting(_revwalker, GIT_SORT_TIME); cl_git_pass(git_revwalk_push_ref(_revwalker, "HEAD")); while (git_revwalk_next(&oid, _revwalker) == 0) { o = git__malloc(GIT_OID_RAWSZ); cl_assert(o != NULL); git_oid_cpy(o, &oid); cl_git_pass(git_vector_insert(&_commits, o)); } git_vector_foreach(&_commits, i, o) { cl_git_pass(git_packbuilder_insert(_packbuilder, o, NULL)); } git_vector_foreach(&_commits, i, o) { git_object *obj; cl_git_pass(git_object_lookup(&obj, _repo, o, GIT_OBJ_COMMIT)); cl_git_pass(git_packbuilder_insert_tree(_packbuilder, git_commit_tree_id((git_commit *)obj))); git_object_free(obj); } } static int feed_indexer(void *ptr, size_t len, void *payload) { git_transfer_progress *stats = (git_transfer_progress *)payload; return git_indexer_stream_add(_indexer, ptr, len, stats); } void test_pack_packbuilder__create_pack(void) { git_transfer_progress stats; git_buf buf = GIT_BUF_INIT, path = GIT_BUF_INIT; git_hash_ctx ctx; git_oid hash; char hex[41]; hex[40] = '\0'; seed_packbuilder(); cl_git_pass(git_indexer_stream_new(&_indexer, ".", NULL, NULL)); cl_git_pass(git_packbuilder_foreach(_packbuilder, feed_indexer, &stats)); cl_git_pass(git_indexer_stream_finalize(_indexer, &stats)); git_oid_fmt(hex, git_indexer_stream_hash(_indexer)); git_buf_printf(&path, "pack-%s.pack", hex); /* * By default, packfiles are created with only one thread. * Therefore we can predict the object ordering and make sure * we create exactly the same pack as git.git does when *not* * reusing existing deltas (as libgit2). * * $ cd tests-clar/resources/testrepo.git * $ git rev-list --objects HEAD | \ * git pack-objects -q --no-reuse-delta --threads=1 pack * $ sha1sum git-80e61eb315239ef3c53033e37fee43b744d57122.pack * 5d410bdf97cf896f9007681b92868471d636954b * */ cl_git_pass(git_futils_readbuffer(&buf, git_buf_cstr(&path))); cl_git_pass(git_hash_ctx_init(&ctx)); cl_git_pass(git_hash_update(&ctx, buf.ptr, buf.size)); cl_git_pass(git_hash_final(&hash, &ctx)); git_hash_ctx_cleanup(&ctx); git_buf_free(&path); git_buf_free(&buf); git_oid_fmt(hex, &hash); cl_assert_equal_s(hex, "5d410bdf97cf896f9007681b92868471d636954b"); } static git_transfer_progress stats; static int foreach_cb(void *buf, size_t len, void *payload) { git_indexer_stream *idx = (git_indexer_stream *) payload; cl_git_pass(git_indexer_stream_add(idx, buf, len, &stats)); return 0; } void test_pack_packbuilder__foreach(void) { git_indexer_stream *idx; seed_packbuilder(); cl_git_pass(git_indexer_stream_new(&idx, ".", NULL, NULL)); cl_git_pass(git_packbuilder_foreach(_packbuilder, foreach_cb, idx)); cl_git_pass(git_indexer_stream_finalize(idx, &stats)); git_indexer_stream_free(idx); } libgit2-0.19.0/tests-clar/refs/000077500000000000000000000000001216214232500161535ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/refs/branches/000077500000000000000000000000001216214232500177405ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/refs/branches/create.c000066400000000000000000000037361216214232500213600ustar00rootroot00000000000000#include "clar_libgit2.h" #include "refs.h" static git_repository *repo; static git_commit *target; static git_reference *branch; void test_refs_branches_create__initialize(void) { cl_fixture_sandbox("testrepo.git"); cl_git_pass(git_repository_open(&repo, "testrepo.git")); branch = NULL; } void test_refs_branches_create__cleanup(void) { git_reference_free(branch); branch = NULL; git_commit_free(target); target = NULL; git_repository_free(repo); repo = NULL; cl_fixture_cleanup("testrepo.git"); } static void retrieve_target_from_oid(git_commit **out, git_repository *repo, const char *sha) { git_oid oid; cl_git_pass(git_oid_fromstr(&oid, sha)); cl_git_pass(git_commit_lookup(out, repo, &oid)); } static void retrieve_known_commit(git_commit **commit, git_repository *repo) { retrieve_target_from_oid(commit, repo, "e90810b8df3e80c413d903f631643c716887138d"); } #define NEW_BRANCH_NAME "new-branch-on-the-block" void test_refs_branches_create__can_create_a_local_branch(void) { retrieve_known_commit(&target, repo); cl_git_pass(git_branch_create(&branch, repo, NEW_BRANCH_NAME, target, 0)); cl_git_pass(git_oid_cmp(git_reference_target(branch), git_commit_id(target))); } void test_refs_branches_create__can_not_create_a_branch_if_its_name_collide_with_an_existing_one(void) { retrieve_known_commit(&target, repo); cl_assert_equal_i(GIT_EEXISTS, git_branch_create(&branch, repo, "br2", target, 0)); } void test_refs_branches_create__can_force_create_over_an_existing_branch(void) { retrieve_known_commit(&target, repo); cl_git_pass(git_branch_create(&branch, repo, "br2", target, 1)); cl_git_pass(git_oid_cmp(git_reference_target(branch), git_commit_id(target))); cl_assert_equal_s("refs/heads/br2", git_reference_name(branch)); } void test_refs_branches_create__creating_a_branch_with_an_invalid_name_returns_EINVALIDSPEC(void) { retrieve_known_commit(&target, repo); cl_assert_equal_i(GIT_EINVALIDSPEC, git_branch_create(&branch, repo, "inv@{id", target, 0)); }libgit2-0.19.0/tests-clar/refs/branches/delete.c000066400000000000000000000067561216214232500213640ustar00rootroot00000000000000#include "clar_libgit2.h" #include "refs.h" #include "repo/repo_helpers.h" #include "config/config_helpers.h" static git_repository *repo; static git_reference *fake_remote; void test_refs_branches_delete__initialize(void) { git_oid id; cl_fixture_sandbox("testrepo.git"); cl_git_pass(git_repository_open(&repo, "testrepo.git")); cl_git_pass(git_oid_fromstr(&id, "be3563ae3f795b2b4353bcce3a527ad0a4f7f644")); cl_git_pass(git_reference_create(&fake_remote, repo, "refs/remotes/nulltoken/master", &id, 0)); } void test_refs_branches_delete__cleanup(void) { git_reference_free(fake_remote); fake_remote = NULL; git_repository_free(repo); repo = NULL; cl_fixture_cleanup("testrepo.git"); } void test_refs_branches_delete__can_not_delete_a_branch_pointed_at_by_HEAD(void) { git_reference *head; git_reference *branch; /* Ensure HEAD targets the local master branch */ cl_git_pass(git_reference_lookup(&head, repo, GIT_HEAD_FILE)); cl_assert_equal_s("refs/heads/master", git_reference_symbolic_target(head)); git_reference_free(head); cl_git_pass(git_branch_lookup(&branch, repo, "master", GIT_BRANCH_LOCAL)); cl_git_fail(git_branch_delete(branch)); git_reference_free(branch); } void test_refs_branches_delete__can_delete_a_branch_even_if_HEAD_is_missing(void) { git_reference *head; git_reference *branch; cl_git_pass(git_reference_lookup(&head, repo, GIT_HEAD_FILE)); git_reference_delete(head); git_reference_free(head); cl_git_pass(git_branch_lookup(&branch, repo, "br2", GIT_BRANCH_LOCAL)); cl_git_pass(git_branch_delete(branch)); git_reference_free(branch); } void test_refs_branches_delete__can_delete_a_branch_when_HEAD_is_orphaned(void) { git_reference *branch; make_head_orphaned(repo, NON_EXISTING_HEAD); cl_git_pass(git_branch_lookup(&branch, repo, "br2", GIT_BRANCH_LOCAL)); cl_git_pass(git_branch_delete(branch)); git_reference_free(branch); } void test_refs_branches_delete__can_delete_a_branch_pointed_at_by_detached_HEAD(void) { git_reference *head, *branch; cl_git_pass(git_reference_lookup(&head, repo, GIT_HEAD_FILE)); cl_assert_equal_i(GIT_REF_SYMBOLIC, git_reference_type(head)); cl_assert_equal_s("refs/heads/master", git_reference_symbolic_target(head)); git_reference_free(head); /* Detach HEAD and make it target the commit that "master" points to */ git_repository_detach_head(repo); cl_git_pass(git_branch_lookup(&branch, repo, "master", GIT_BRANCH_LOCAL)); cl_git_pass(git_branch_delete(branch)); git_reference_free(branch); } void test_refs_branches_delete__can_delete_a_local_branch(void) { git_reference *branch; cl_git_pass(git_branch_lookup(&branch, repo, "br2", GIT_BRANCH_LOCAL)); cl_git_pass(git_branch_delete(branch)); git_reference_free(branch); } void test_refs_branches_delete__can_delete_a_remote_branch(void) { git_reference *branch; cl_git_pass(git_branch_lookup(&branch, repo, "nulltoken/master", GIT_BRANCH_REMOTE)); cl_git_pass(git_branch_delete(branch)); git_reference_free(branch); } void test_refs_branches_delete__deleting_a_branch_removes_related_configuration_data(void) { git_reference *branch; assert_config_entry_existence(repo, "branch.track-local.remote", true); assert_config_entry_existence(repo, "branch.track-local.merge", true); cl_git_pass(git_branch_lookup(&branch, repo, "track-local", GIT_BRANCH_LOCAL)); cl_git_pass(git_branch_delete(branch)); git_reference_free(branch); assert_config_entry_existence(repo, "branch.track-local.remote", false); assert_config_entry_existence(repo, "branch.track-local.merge", false); } libgit2-0.19.0/tests-clar/refs/branches/foreach.c000066400000000000000000000076341216214232500215250ustar00rootroot00000000000000#include "clar_libgit2.h" #include "refs.h" static git_repository *repo; static git_reference *fake_remote; void test_refs_branches_foreach__initialize(void) { git_oid id; cl_fixture_sandbox("testrepo.git"); cl_git_pass(git_repository_open(&repo, "testrepo.git")); cl_git_pass(git_oid_fromstr(&id, "be3563ae3f795b2b4353bcce3a527ad0a4f7f644")); cl_git_pass(git_reference_create(&fake_remote, repo, "refs/remotes/nulltoken/master", &id, 0)); } void test_refs_branches_foreach__cleanup(void) { git_reference_free(fake_remote); fake_remote = NULL; git_repository_free(repo); repo = NULL; cl_fixture_cleanup("testrepo.git"); cl_git_sandbox_cleanup(); } static int count_branch_list_cb(const char *branch_name, git_branch_t branch_type, void *payload) { int *count; GIT_UNUSED(branch_type); GIT_UNUSED(branch_name); count = (int *)payload; (*count)++; return 0; } static void assert_retrieval(unsigned int flags, unsigned int expected_count) { int count = 0; cl_git_pass(git_branch_foreach(repo, flags, count_branch_list_cb, &count)); cl_assert_equal_i(expected_count, count); } void test_refs_branches_foreach__retrieve_all_branches(void) { assert_retrieval(GIT_BRANCH_LOCAL | GIT_BRANCH_REMOTE, 14); } void test_refs_branches_foreach__retrieve_remote_branches(void) { assert_retrieval(GIT_BRANCH_REMOTE, 2); } void test_refs_branches_foreach__retrieve_local_branches(void) { assert_retrieval(GIT_BRANCH_LOCAL, 12); } struct expectations { const char *branch_name; int encounters; }; static void assert_branch_has_been_found(struct expectations *findings, const char* expected_branch_name) { int pos = 0; for (pos = 0; findings[pos].branch_name; ++pos) { if (strcmp(expected_branch_name, findings[pos].branch_name) == 0) { cl_assert_equal_i(1, findings[pos].encounters); return; } } cl_fail("expected branch not found in list."); } static int contains_branch_list_cb(const char *branch_name, git_branch_t branch_type, void *payload) { int pos = 0; struct expectations *exp; GIT_UNUSED(branch_type); exp = (struct expectations *)payload; for (pos = 0; exp[pos].branch_name; ++pos) { if (strcmp(branch_name, exp[pos].branch_name) == 0) exp[pos].encounters++; } return 0; } /* * $ git branch -r * nulltoken/HEAD -> nulltoken/master * nulltoken/master */ void test_refs_branches_foreach__retrieve_remote_symbolic_HEAD_when_present(void) { struct expectations exp[] = { { "nulltoken/HEAD", 0 }, { "nulltoken/master", 0 }, { NULL, 0 } }; git_reference_free(fake_remote); cl_git_pass(git_reference_symbolic_create(&fake_remote, repo, "refs/remotes/nulltoken/HEAD", "refs/remotes/nulltoken/master", 0)); assert_retrieval(GIT_BRANCH_REMOTE, 3); cl_git_pass(git_branch_foreach(repo, GIT_BRANCH_REMOTE, contains_branch_list_cb, &exp)); assert_branch_has_been_found(exp, "nulltoken/HEAD"); assert_branch_has_been_found(exp, "nulltoken/master"); } static int branch_list_interrupt_cb( const char *branch_name, git_branch_t branch_type, void *payload) { int *count; GIT_UNUSED(branch_type); GIT_UNUSED(branch_name); count = (int *)payload; (*count)++; return (*count == 5); } void test_refs_branches_foreach__can_cancel(void) { int count = 0; cl_assert_equal_i(GIT_EUSER, git_branch_foreach(repo, GIT_BRANCH_LOCAL | GIT_BRANCH_REMOTE, branch_list_interrupt_cb, &count)); cl_assert_equal_i(5, count); } void test_refs_branches_foreach__mix_of_packed_and_loose(void) { struct expectations exp[] = { { "master", 0 }, { "origin/HEAD", 0 }, { "origin/master", 0 }, { "origin/packed", 0 }, { NULL, 0 } }; git_repository *r2; r2 = cl_git_sandbox_init("testrepo2"); cl_git_pass(git_branch_foreach(r2, GIT_BRANCH_LOCAL | GIT_BRANCH_REMOTE, contains_branch_list_cb, &exp)); assert_branch_has_been_found(exp, "master"); assert_branch_has_been_found(exp, "origin/HEAD"); assert_branch_has_been_found(exp, "origin/master"); assert_branch_has_been_found(exp, "origin/packed"); } libgit2-0.19.0/tests-clar/refs/branches/ishead.c000066400000000000000000000057661216214232500213570ustar00rootroot00000000000000#include "clar_libgit2.h" #include "refs.h" #include "repo/repo_helpers.h" static git_repository *repo; static git_reference *branch; void test_refs_branches_ishead__initialize(void) { cl_git_pass(git_repository_open(&repo, cl_fixture("testrepo.git"))); } void test_refs_branches_ishead__cleanup(void) { git_reference_free(branch); branch = NULL; git_repository_free(repo); repo = NULL; } void test_refs_branches_ishead__can_tell_if_a_branch_is_pointed_at_by_HEAD(void) { cl_git_pass(git_reference_lookup(&branch, repo, "refs/heads/master")); cl_assert_equal_i(true, git_branch_is_head(branch)); } void test_refs_branches_ishead__can_properly_handle_orphaned_HEAD(void) { git_repository_free(repo); repo = cl_git_sandbox_init("testrepo.git"); make_head_orphaned(repo, NON_EXISTING_HEAD); cl_git_pass(git_reference_lookup(&branch, repo, "refs/heads/master")); cl_assert_equal_i(false, git_branch_is_head(branch)); cl_git_sandbox_cleanup(); repo = NULL; } void test_refs_branches_ishead__can_properly_handle_missing_HEAD(void) { git_repository_free(repo); repo = cl_git_sandbox_init("testrepo.git"); delete_head(repo); cl_git_pass(git_reference_lookup(&branch, repo, "refs/heads/master")); cl_assert_equal_i(false, git_branch_is_head(branch)); cl_git_sandbox_cleanup(); repo = NULL; } void test_refs_branches_ishead__can_tell_if_a_branch_is_not_pointed_at_by_HEAD(void) { cl_git_pass(git_reference_lookup(&branch, repo, "refs/heads/br2")); cl_assert_equal_i(false, git_branch_is_head(branch)); } void test_refs_branches_ishead__wont_be_fooled_by_a_non_branch(void) { cl_git_pass(git_reference_lookup(&branch, repo, "refs/tags/e90810b")); cl_assert_equal_i(false, git_branch_is_head(branch)); } /* * $ git init . * Initialized empty Git repository in d:/temp/tempee/.git/ * * $ touch a && git add a * $ git commit -m" boom" * [master (root-commit) b47b758] boom * 0 files changed * create mode 100644 a * * $ echo "ref: refs/heads/master" > .git/refs/heads/linked * $ echo "ref: refs/heads/linked" > .git/refs/heads/super * $ echo "ref: refs/heads/super" > .git/HEAD * * $ git branch * linked -> master * * master * super -> master */ void test_refs_branches_ishead__only_direct_references_are_considered(void) { git_reference *linked, *super, *head; git_repository_free(repo); repo = cl_git_sandbox_init("testrepo.git"); cl_git_pass(git_reference_symbolic_create(&linked, repo, "refs/heads/linked", "refs/heads/master", 0)); cl_git_pass(git_reference_symbolic_create(&super, repo, "refs/heads/super", "refs/heads/linked", 0)); cl_git_pass(git_reference_symbolic_create(&head, repo, GIT_HEAD_FILE, "refs/heads/super", 1)); cl_assert_equal_i(false, git_branch_is_head(linked)); cl_assert_equal_i(false, git_branch_is_head(super)); cl_git_pass(git_repository_head(&branch, repo)); cl_assert_equal_s("refs/heads/master", git_reference_name(branch)); git_reference_free(linked); git_reference_free(super); git_reference_free(head); cl_git_sandbox_cleanup(); repo = NULL; } libgit2-0.19.0/tests-clar/refs/branches/lookup.c000066400000000000000000000024531216214232500214210ustar00rootroot00000000000000#include "clar_libgit2.h" #include "refs.h" static git_repository *repo; static git_reference *branch; void test_refs_branches_lookup__initialize(void) { cl_git_pass(git_repository_open(&repo, cl_fixture("testrepo.git"))); branch = NULL; } void test_refs_branches_lookup__cleanup(void) { git_reference_free(branch); branch = NULL; git_repository_free(repo); repo = NULL; } void test_refs_branches_lookup__can_retrieve_a_local_branch(void) { cl_git_pass(git_branch_lookup(&branch, repo, "br2", GIT_BRANCH_LOCAL)); } void test_refs_branches_lookup__can_retrieve_a_remote_tracking_branch(void) { cl_git_pass(git_branch_lookup(&branch, repo, "test/master", GIT_BRANCH_REMOTE)); } void test_refs_branches_lookup__trying_to_retrieve_an_unknown_branch_returns_ENOTFOUND(void) { cl_assert_equal_i(GIT_ENOTFOUND, git_branch_lookup(&branch, repo, "where/are/you", GIT_BRANCH_LOCAL)); cl_assert_equal_i(GIT_ENOTFOUND, git_branch_lookup(&branch, repo, "over/here", GIT_BRANCH_REMOTE)); } void test_refs_branches_lookup__trying_to_retrieve_a_branch_with_an_invalid_name_returns_EINVALIDSPEC(void) { cl_assert_equal_i(GIT_EINVALIDSPEC, git_branch_lookup(&branch, repo, "are/you/inv@{id", GIT_BRANCH_LOCAL)); cl_assert_equal_i(GIT_EINVALIDSPEC, git_branch_lookup(&branch, repo, "yes/i am", GIT_BRANCH_REMOTE)); } libgit2-0.19.0/tests-clar/refs/branches/move.c000066400000000000000000000105321216214232500210530ustar00rootroot00000000000000#include "clar_libgit2.h" #include "refs.h" #include "config/config_helpers.h" static git_repository *repo; void test_refs_branches_move__initialize(void) { repo = cl_git_sandbox_init("testrepo.git"); } void test_refs_branches_move__cleanup(void) { cl_git_sandbox_cleanup(); } #define NEW_BRANCH_NAME "new-branch-on-the-block" void test_refs_branches_move__can_move_a_local_branch(void) { git_reference *original_ref, *new_ref; cl_git_pass(git_reference_lookup(&original_ref, repo, "refs/heads/br2")); cl_git_pass(git_branch_move(&new_ref, original_ref, NEW_BRANCH_NAME, 0)); cl_assert_equal_s(GIT_REFS_HEADS_DIR NEW_BRANCH_NAME, git_reference_name(new_ref)); git_reference_free(original_ref); git_reference_free(new_ref); } void test_refs_branches_move__can_move_a_local_branch_to_a_different_namespace(void) { git_reference *original_ref, *new_ref, *newer_ref; cl_git_pass(git_reference_lookup(&original_ref, repo, "refs/heads/br2")); /* Downward */ cl_git_pass(git_branch_move(&new_ref, original_ref, "somewhere/" NEW_BRANCH_NAME, 0)); git_reference_free(original_ref); /* Upward */ cl_git_pass(git_branch_move(&newer_ref, new_ref, "br2", 0)); git_reference_free(new_ref); git_reference_free(newer_ref); } void test_refs_branches_move__can_move_a_local_branch_to_a_partially_colliding_namespace(void) { git_reference *original_ref, *new_ref, *newer_ref; cl_git_pass(git_reference_lookup(&original_ref, repo, "refs/heads/br2")); /* Downward */ cl_git_pass(git_branch_move(&new_ref, original_ref, "br2/" NEW_BRANCH_NAME, 0)); git_reference_free(original_ref); /* Upward */ cl_git_pass(git_branch_move(&newer_ref, new_ref, "br2", 0)); git_reference_free(new_ref); git_reference_free(newer_ref); } void test_refs_branches_move__can_not_move_a_branch_if_its_destination_name_collide_with_an_existing_one(void) { git_reference *original_ref, *new_ref; cl_git_pass(git_reference_lookup(&original_ref, repo, "refs/heads/br2")); cl_assert_equal_i(GIT_EEXISTS, git_branch_move(&new_ref, original_ref, "master", 0)); git_reference_free(original_ref); } void test_refs_branches_move__moving_a_branch_with_an_invalid_name_returns_EINVALIDSPEC(void) { git_reference *original_ref, *new_ref; cl_git_pass(git_reference_lookup(&original_ref, repo, "refs/heads/br2")); cl_assert_equal_i(GIT_EINVALIDSPEC, git_branch_move(&new_ref, original_ref, "Inv@{id", 0)); git_reference_free(original_ref); } void test_refs_branches_move__can_not_move_a_non_branch(void) { git_reference *tag, *new_ref; cl_git_pass(git_reference_lookup(&tag, repo, "refs/tags/e90810b")); cl_git_fail(git_branch_move(&new_ref, tag, NEW_BRANCH_NAME, 0)); git_reference_free(tag); } void test_refs_branches_move__can_force_move_over_an_existing_branch(void) { git_reference *original_ref, *new_ref; cl_git_pass(git_reference_lookup(&original_ref, repo, "refs/heads/br2")); cl_git_pass(git_branch_move(&new_ref, original_ref, "master", 1)); git_reference_free(original_ref); git_reference_free(new_ref); } void test_refs_branches_move__moving_a_branch_moves_related_configuration_data(void) { git_reference *branch; git_reference *new_branch; cl_git_pass(git_branch_lookup(&branch, repo, "track-local", GIT_BRANCH_LOCAL)); assert_config_entry_existence(repo, "branch.track-local.remote", true); assert_config_entry_existence(repo, "branch.track-local.merge", true); assert_config_entry_existence(repo, "branch.moved.remote", false); assert_config_entry_existence(repo, "branch.moved.merge", false); cl_git_pass(git_branch_move(&new_branch, branch, "moved", 0)); git_reference_free(branch); assert_config_entry_existence(repo, "branch.track-local.remote", false); assert_config_entry_existence(repo, "branch.track-local.merge", false); assert_config_entry_existence(repo, "branch.moved.remote", true); assert_config_entry_existence(repo, "branch.moved.merge", true); git_reference_free(new_branch); } void test_refs_branches_move__moving_the_branch_pointed_at_by_HEAD_updates_HEAD(void) { git_reference *branch; git_reference *new_branch; cl_git_pass(git_reference_lookup(&branch, repo, "refs/heads/master")); cl_git_pass(git_branch_move(&new_branch, branch, "master2", 0)); git_reference_free(branch); git_reference_free(new_branch); cl_git_pass(git_repository_head(&branch, repo)); cl_assert_equal_s("refs/heads/master2", git_reference_name(branch)); git_reference_free(branch); } libgit2-0.19.0/tests-clar/refs/branches/name.c000066400000000000000000000020121216214232500210170ustar00rootroot00000000000000#include "clar_libgit2.h" #include "branch.h" static git_repository *repo; static git_reference *ref; void test_refs_branches_name__initialize(void) { cl_git_pass(git_repository_open(&repo, cl_fixture("testrepo.git"))); } void test_refs_branches_name__cleanup(void) { git_reference_free(ref); ref = NULL; git_repository_free(repo); repo = NULL; } void test_refs_branches_name__can_get_local_branch_name(void) { const char *name; cl_git_pass(git_branch_lookup(&ref,repo,"master",GIT_BRANCH_LOCAL)); cl_git_pass(git_branch_name(&name,ref)); cl_assert_equal_s("master",name); } void test_refs_branches_name__can_get_remote_branch_name(void) { const char *name; cl_git_pass(git_branch_lookup(&ref,repo,"test/master",GIT_BRANCH_REMOTE)); cl_git_pass(git_branch_name(&name,ref)); cl_assert_equal_s("test/master",name); } void test_refs_branches_name__error_when_ref_is_no_branch(void) { const char *name; cl_git_pass(git_reference_lookup(&ref,repo,"refs/notes/fanout")); cl_git_fail(git_branch_name(&name,ref)); } libgit2-0.19.0/tests-clar/refs/branches/remote.c000066400000000000000000000046051216214232500214040ustar00rootroot00000000000000#include "clar_libgit2.h" #include "branch.h" #include "remote.h" static git_repository *g_repo; static const char *remote_tracking_branch_name = "refs/remotes/test/master"; static const char *expected_remote_name = "test"; static int expected_remote_name_length; void test_refs_branches_remote__initialize(void) { g_repo = cl_git_sandbox_init("testrepo"); expected_remote_name_length = (int)strlen(expected_remote_name) + 1; } void test_refs_branches_remote__cleanup(void) { cl_git_sandbox_cleanup(); } void test_refs_branches_remote__can_get_remote_for_branch(void) { char remotename[1024] = {0}; cl_assert_equal_i(expected_remote_name_length, git_branch_remote_name(NULL, 0, g_repo, remote_tracking_branch_name)); cl_assert_equal_i(expected_remote_name_length, git_branch_remote_name(remotename, expected_remote_name_length, g_repo, remote_tracking_branch_name)); cl_assert_equal_s("test", remotename); } void test_refs_branches_remote__insufficient_buffer_returns_error(void) { char remotename[1024] = {0}; cl_assert_equal_i(expected_remote_name_length, git_branch_remote_name(NULL, 0, g_repo, remote_tracking_branch_name)); cl_git_fail_with(git_branch_remote_name(remotename, expected_remote_name_length - 1, g_repo, remote_tracking_branch_name), expected_remote_name_length); } void test_refs_branches_remote__no_matching_remote_returns_error(void) { const char *unknown = "refs/remotes/nonexistent/master"; giterr_clear(); cl_git_fail_with(git_branch_remote_name( NULL, 0, g_repo, unknown), GIT_ENOTFOUND); cl_assert(giterr_last() != NULL); } void test_refs_branches_remote__local_remote_returns_error(void) { const char *local = "refs/heads/master"; giterr_clear(); cl_git_fail_with(git_branch_remote_name( NULL, 0, g_repo, local), GIT_ERROR); cl_assert(giterr_last() != NULL); } void test_refs_branches_remote__ambiguous_remote_returns_error(void) { git_remote *remote; /* Create the remote */ cl_git_pass(git_remote_create(&remote, g_repo, "addtest", "http://github.com/libgit2/libgit2")); /* Update the remote fetch spec */ git_remote_clear_refspecs(remote); cl_git_pass(git_remote_add_fetch(remote, "refs/heads/*:refs/remotes/test/*")); cl_git_pass(git_remote_save(remote)); git_remote_free(remote); giterr_clear(); cl_git_fail_with(git_branch_remote_name(NULL, 0, g_repo, remote_tracking_branch_name), GIT_EAMBIGUOUS); cl_assert(giterr_last() != NULL); } libgit2-0.19.0/tests-clar/refs/branches/upstream.c000066400000000000000000000112631216214232500217470ustar00rootroot00000000000000#include "clar_libgit2.h" #include "refs.h" static git_repository *repo; static git_reference *branch, *upstream; void test_refs_branches_upstream__initialize(void) { cl_git_pass(git_repository_open(&repo, cl_fixture("testrepo.git"))); branch = NULL; upstream = NULL; } void test_refs_branches_upstream__cleanup(void) { git_reference_free(upstream); git_reference_free(branch); branch = NULL; git_repository_free(repo); repo = NULL; } void test_refs_branches_upstream__can_retrieve_the_remote_tracking_reference_of_a_local_branch(void) { cl_git_pass(git_reference_lookup(&branch, repo, "refs/heads/master")); cl_git_pass(git_branch_upstream(&upstream, branch)); cl_assert_equal_s("refs/remotes/test/master", git_reference_name(upstream)); } void test_refs_branches_upstream__can_retrieve_the_local_upstream_reference_of_a_local_branch(void) { cl_git_pass(git_reference_lookup(&branch, repo, "refs/heads/track-local")); cl_git_pass(git_branch_upstream(&upstream, branch)); cl_assert_equal_s("refs/heads/master", git_reference_name(upstream)); } void test_refs_branches_upstream__cannot_retrieve_a_remote_upstream_reference_from_a_non_branch(void) { cl_git_pass(git_reference_lookup(&branch, repo, "refs/tags/e90810b")); cl_git_fail(git_branch_upstream(&upstream, branch)); } void test_refs_branches_upstream__trying_to_retrieve_a_remote_tracking_reference_from_a_plain_local_branch_returns_GIT_ENOTFOUND(void) { cl_git_pass(git_reference_lookup(&branch, repo, "refs/heads/subtrees")); cl_assert_equal_i(GIT_ENOTFOUND, git_branch_upstream(&upstream, branch)); } void test_refs_branches_upstream__trying_to_retrieve_a_remote_tracking_reference_from_a_branch_with_no_fetchspec_returns_GIT_ENOTFOUND(void) { cl_git_pass(git_reference_lookup(&branch, repo, "refs/heads/cannot-fetch")); cl_assert_equal_i(GIT_ENOTFOUND, git_branch_upstream(&upstream, branch)); } static void assert_merge_and_or_remote_key_missing(git_repository *repository, const git_commit *target, const char *entry_name) { git_reference *branch; cl_assert_equal_i(GIT_OBJ_COMMIT, git_object_type((git_object*)target)); cl_git_pass(git_branch_create(&branch, repository, entry_name, (git_commit*)target, 0)); cl_assert_equal_i(GIT_ENOTFOUND, git_branch_upstream(&upstream, branch)); git_reference_free(branch); } void test_refs_branches_upstream__retrieve_a_remote_tracking_reference_from_a_branch_with_no_remote_returns_GIT_ENOTFOUND(void) { git_reference *head; git_repository *repository; git_commit *target; repository = cl_git_sandbox_init("testrepo.git"); cl_git_pass(git_repository_head(&head, repository)); cl_git_pass(git_reference_peel(((git_object **)&target), head, GIT_OBJ_COMMIT)); git_reference_free(head); assert_merge_and_or_remote_key_missing(repository, target, "remoteless"); assert_merge_and_or_remote_key_missing(repository, target, "mergeless"); assert_merge_and_or_remote_key_missing(repository, target, "mergeandremoteless"); git_commit_free(target); cl_git_sandbox_cleanup(); } void test_refs_branches_upstream__set_unset_upstream(void) { git_reference *branch; git_repository *repository; const char *value; git_config *config; repository = cl_git_sandbox_init("testrepo.git"); /* remote */ cl_git_pass(git_reference_lookup(&branch, repository, "refs/heads/test")); cl_git_pass(git_branch_set_upstream(branch, "test/master")); cl_git_pass(git_repository_config(&config, repository)); cl_git_pass(git_config_get_string(&value, config, "branch.test.remote")); cl_assert_equal_s(value, "test"); cl_git_pass(git_config_get_string(&value, config, "branch.test.merge")); cl_assert_equal_s(value, "refs/heads/master"); git_reference_free(branch); /* local */ cl_git_pass(git_reference_lookup(&branch, repository, "refs/heads/test")); cl_git_pass(git_branch_set_upstream(branch, "master")); cl_git_pass(git_config_get_string(&value, config, "branch.test.remote")); cl_assert_equal_s(value, "."); cl_git_pass(git_config_get_string(&value, config, "branch.test.merge")); cl_assert_equal_s(value, "refs/heads/master"); /* unset */ cl_git_pass(git_branch_set_upstream(branch, NULL)); cl_git_fail_with(git_config_get_string(&value, config, "branch.test.merge"), GIT_ENOTFOUND); cl_git_fail_with(git_config_get_string(&value, config, "branch.test.remote"), GIT_ENOTFOUND); git_reference_free(branch); cl_git_pass(git_reference_lookup(&branch, repository, "refs/heads/master")); cl_git_pass(git_branch_set_upstream(branch, NULL)); cl_git_fail_with(git_config_get_string(&value, config, "branch.master.merge"), GIT_ENOTFOUND); cl_git_fail_with(git_config_get_string(&value, config, "branch.master.remote"), GIT_ENOTFOUND); git_reference_free(branch); git_config_free(config); cl_git_sandbox_cleanup(); } libgit2-0.19.0/tests-clar/refs/branches/upstreamname.c000066400000000000000000000022731216214232500226110ustar00rootroot00000000000000#include "clar_libgit2.h" #include "branch.h" static git_repository *repo; static git_buf upstream_name; void test_refs_branches_upstreamname__initialize(void) { cl_git_pass(git_repository_open(&repo, cl_fixture("testrepo.git"))); git_buf_init(&upstream_name, 0); } void test_refs_branches_upstreamname__cleanup(void) { git_buf_free(&upstream_name); git_repository_free(repo); repo = NULL; } void test_refs_branches_upstreamname__can_retrieve_the_remote_tracking_reference_name_of_a_local_branch(void) { cl_git_pass(git_branch_upstream__name( &upstream_name, repo, "refs/heads/master")); cl_assert_equal_s("refs/remotes/test/master", git_buf_cstr(&upstream_name)); } void test_refs_branches_upstreamname__can_retrieve_the_local_upstream_reference_name_of_a_local_branch(void) { cl_git_pass(git_branch_upstream__name( &upstream_name, repo, "refs/heads/track-local")); cl_assert_equal_s("refs/heads/master", git_buf_cstr(&upstream_name)); } void test_refs_branches_upstreamname__can_return_the_size_of_thelocal_upstream_reference_name_of_a_local_branch(void) { cl_assert_equal_i((int)strlen("refs/heads/master") + 1, git_branch_upstream_name(NULL, 0, repo, "refs/heads/track-local")); } libgit2-0.19.0/tests-clar/refs/crashes.c000066400000000000000000000011641216214232500177510ustar00rootroot00000000000000#include "clar_libgit2.h" void test_refs_crashes__double_free(void) { git_repository *repo; git_reference *ref, *ref2; const char *REFNAME = "refs/heads/xxx"; cl_git_pass(git_repository_open(&repo, cl_fixture("testrepo.git"))); cl_git_pass(git_reference_symbolic_create(&ref, repo, REFNAME, "refs/heads/master", 0)); cl_git_pass(git_reference_lookup(&ref2, repo, REFNAME)); cl_git_pass(git_reference_delete(ref)); git_reference_free(ref); git_reference_free(ref2); /* reference is gone from disk, so reloading it will fail */ cl_git_fail(git_reference_lookup(&ref2, repo, REFNAME)); git_repository_free(repo); } libgit2-0.19.0/tests-clar/refs/create.c000066400000000000000000000123201216214232500175600ustar00rootroot00000000000000#include "clar_libgit2.h" #include "repository.h" #include "git2/reflog.h" #include "reflog.h" #include "ref_helpers.h" static const char *current_master_tip = "099fabac3a9ea935598528c27f866e34089c2eff"; static const char *current_head_target = "refs/heads/master"; static git_repository *g_repo; void test_refs_create__initialize(void) { g_repo = cl_git_sandbox_init("testrepo"); } void test_refs_create__cleanup(void) { cl_git_sandbox_cleanup(); } void test_refs_create__symbolic(void) { // create a new symbolic reference git_reference *new_reference, *looked_up_ref, *resolved_ref; git_repository *repo2; git_oid id; const char *new_head_tracker = "ANOTHER_HEAD_TRACKER"; git_oid_fromstr(&id, current_master_tip); /* Create and write the new symbolic reference */ cl_git_pass(git_reference_symbolic_create(&new_reference, g_repo, new_head_tracker, current_head_target, 0)); /* Ensure the reference can be looked-up... */ cl_git_pass(git_reference_lookup(&looked_up_ref, g_repo, new_head_tracker)); cl_assert(git_reference_type(looked_up_ref) & GIT_REF_SYMBOLIC); cl_assert(reference_is_packed(looked_up_ref) == 0); cl_assert_equal_s(looked_up_ref->name, new_head_tracker); /* ...peeled.. */ cl_git_pass(git_reference_resolve(&resolved_ref, looked_up_ref)); cl_assert(git_reference_type(resolved_ref) == GIT_REF_OID); /* ...and that it points to the current master tip */ cl_assert(git_oid_cmp(&id, git_reference_target(resolved_ref)) == 0); git_reference_free(looked_up_ref); git_reference_free(resolved_ref); /* Similar test with a fresh new repository */ cl_git_pass(git_repository_open(&repo2, "testrepo")); cl_git_pass(git_reference_lookup(&looked_up_ref, repo2, new_head_tracker)); cl_git_pass(git_reference_resolve(&resolved_ref, looked_up_ref)); cl_assert(git_oid_cmp(&id, git_reference_target(resolved_ref)) == 0); git_repository_free(repo2); git_reference_free(new_reference); git_reference_free(looked_up_ref); git_reference_free(resolved_ref); } void test_refs_create__deep_symbolic(void) { // create a deep symbolic reference git_reference *new_reference, *looked_up_ref, *resolved_ref; git_oid id; const char *new_head_tracker = "deep/rooted/tracker"; git_oid_fromstr(&id, current_master_tip); cl_git_pass(git_reference_symbolic_create(&new_reference, g_repo, new_head_tracker, current_head_target, 0)); cl_git_pass(git_reference_lookup(&looked_up_ref, g_repo, new_head_tracker)); cl_git_pass(git_reference_resolve(&resolved_ref, looked_up_ref)); cl_assert(git_oid_cmp(&id, git_reference_target(resolved_ref)) == 0); git_reference_free(new_reference); git_reference_free(looked_up_ref); git_reference_free(resolved_ref); } void test_refs_create__oid(void) { // create a new OID reference git_reference *new_reference, *looked_up_ref; git_repository *repo2; git_oid id; const char *new_head = "refs/heads/new-head"; git_oid_fromstr(&id, current_master_tip); /* Create and write the new object id reference */ cl_git_pass(git_reference_create(&new_reference, g_repo, new_head, &id, 0)); /* Ensure the reference can be looked-up... */ cl_git_pass(git_reference_lookup(&looked_up_ref, g_repo, new_head)); cl_assert(git_reference_type(looked_up_ref) & GIT_REF_OID); cl_assert(reference_is_packed(looked_up_ref) == 0); cl_assert_equal_s(looked_up_ref->name, new_head); /* ...and that it points to the current master tip */ cl_assert(git_oid_cmp(&id, git_reference_target(looked_up_ref)) == 0); git_reference_free(looked_up_ref); /* Similar test with a fresh new repository */ cl_git_pass(git_repository_open(&repo2, "testrepo")); cl_git_pass(git_reference_lookup(&looked_up_ref, repo2, new_head)); cl_assert(git_oid_cmp(&id, git_reference_target(looked_up_ref)) == 0); git_repository_free(repo2); git_reference_free(new_reference); git_reference_free(looked_up_ref); } void test_refs_create__oid_unknown(void) { // Can not create a new OID reference which targets at an unknown id git_reference *new_reference, *looked_up_ref; git_oid id; const char *new_head = "refs/heads/new-head"; git_oid_fromstr(&id, "deadbeef3f795b2b4353bcce3a527ad0a4f7f644"); /* Create and write the new object id reference */ cl_git_fail(git_reference_create(&new_reference, g_repo, new_head, &id, 0)); /* Ensure the reference can't be looked-up... */ cl_git_fail(git_reference_lookup(&looked_up_ref, g_repo, new_head)); } void test_refs_create__propagate_eexists(void) { int error; git_oid oid; git_reference *ref; /* Make sure it works for oid and for symbolic both */ git_oid_fromstr(&oid, current_master_tip); error = git_reference_create(&ref, g_repo, current_head_target, &oid, false); cl_assert(error == GIT_EEXISTS); error = git_reference_symbolic_create(&ref, g_repo, "HEAD", current_head_target, false); cl_assert(error == GIT_EEXISTS); } void test_refs_create__creating_a_reference_with_an_invalid_name_returns_EINVALIDSPEC(void) { git_reference *new_reference; git_oid id; const char *name = "refs/heads/inv@{id"; git_oid_fromstr(&id, current_master_tip); cl_assert_equal_i(GIT_EINVALIDSPEC, git_reference_create( &new_reference, g_repo, name, &id, 0)); cl_assert_equal_i(GIT_EINVALIDSPEC, git_reference_symbolic_create( &new_reference, g_repo, name, current_head_target, 0)); } libgit2-0.19.0/tests-clar/refs/delete.c000066400000000000000000000051101216214232500175560ustar00rootroot00000000000000#include "clar_libgit2.h" #include "fileops.h" #include "git2/reflog.h" #include "git2/refdb.h" #include "reflog.h" #include "ref_helpers.h" static const char *packed_test_head_name = "refs/heads/packed-test"; static const char *current_master_tip = "a65fedf39aefe402d3bb6e24df4d4f5fe4547750"; static git_repository *g_repo; void test_refs_delete__initialize(void) { g_repo = cl_git_sandbox_init("testrepo"); } void test_refs_delete__cleanup(void) { cl_git_sandbox_cleanup(); } void test_refs_delete__packed_loose(void) { // deleting a ref which is both packed and loose should remove both tracks in the filesystem git_reference *looked_up_ref, *another_looked_up_ref; git_buf temp_path = GIT_BUF_INIT; /* Ensure the loose reference exists on the file system */ cl_git_pass(git_buf_joinpath(&temp_path, git_repository_path(g_repo), packed_test_head_name)); cl_assert(git_path_exists(temp_path.ptr)); /* Lookup the reference */ cl_git_pass(git_reference_lookup(&looked_up_ref, g_repo, packed_test_head_name)); /* Ensure it's the loose version that has been found */ cl_assert(reference_is_packed(looked_up_ref) == 0); /* Now that the reference is deleted... */ cl_git_pass(git_reference_delete(looked_up_ref)); git_reference_free(looked_up_ref); /* Looking up the reference once again should not retrieve it */ cl_git_fail(git_reference_lookup(&another_looked_up_ref, g_repo, packed_test_head_name)); /* Ensure the loose reference doesn't exist any longer on the file system */ cl_assert(!git_path_exists(temp_path.ptr)); git_reference_free(another_looked_up_ref); git_buf_free(&temp_path); } void test_refs_delete__packed_only(void) { // can delete a just packed reference git_reference *ref; git_refdb *refdb; git_oid id; const char *new_ref = "refs/heads/new_ref"; git_oid_fromstr(&id, current_master_tip); /* Create and write the new object id reference */ cl_git_pass(git_reference_create(&ref, g_repo, new_ref, &id, 0)); git_reference_free(ref); /* Lookup the reference */ cl_git_pass(git_reference_lookup(&ref, g_repo, new_ref)); /* Ensure it's a loose reference */ cl_assert(reference_is_packed(ref) == 0); /* Pack all existing references */ cl_git_pass(git_repository_refdb(&refdb, g_repo)); cl_git_pass(git_refdb_compress(refdb)); /* Reload the reference from disk */ git_reference_free(ref); cl_git_pass(git_reference_lookup(&ref, g_repo, new_ref)); /* Ensure it's a packed reference */ cl_assert(reference_is_packed(ref) == 1); /* This should pass */ cl_git_pass(git_reference_delete(ref)); git_reference_free(ref); git_refdb_free(refdb); } libgit2-0.19.0/tests-clar/refs/foreachglob.c000066400000000000000000000036061216214232500205770ustar00rootroot00000000000000#include "clar_libgit2.h" #include "refs.h" static git_repository *repo; static git_reference *fake_remote; void test_refs_foreachglob__initialize(void) { git_oid id; cl_fixture_sandbox("testrepo.git"); cl_git_pass(git_repository_open(&repo, "testrepo.git")); cl_git_pass(git_oid_fromstr(&id, "be3563ae3f795b2b4353bcce3a527ad0a4f7f644")); cl_git_pass(git_reference_create(&fake_remote, repo, "refs/remotes/nulltoken/master", &id, 0)); } void test_refs_foreachglob__cleanup(void) { git_reference_free(fake_remote); fake_remote = NULL; git_repository_free(repo); repo = NULL; cl_fixture_cleanup("testrepo.git"); } static int count_cb(const char *reference_name, void *payload) { int *count = (int *)payload; GIT_UNUSED(reference_name); (*count)++; return 0; } static void assert_retrieval(const char *glob, int expected_count) { int count = 0; cl_git_pass(git_reference_foreach_glob(repo, glob, count_cb, &count)); cl_assert_equal_i(expected_count, count); } void test_refs_foreachglob__retrieve_all_refs(void) { /* 12 heads (including one packed head) + 1 note + 2 remotes + 7 tags */ assert_retrieval("*", 22); } void test_refs_foreachglob__retrieve_remote_branches(void) { assert_retrieval("refs/remotes/*", 2); } void test_refs_foreachglob__retrieve_local_branches(void) { assert_retrieval("refs/heads/*", 12); } void test_refs_foreachglob__retrieve_partially_named_references(void) { /* * refs/heads/packed-test, refs/heads/test * refs/remotes/test/master, refs/tags/test */ assert_retrieval("*test*", 4); } static int interrupt_cb(const char *reference_name, void *payload) { int *count = (int *)payload; GIT_UNUSED(reference_name); (*count)++; return (*count == 11); } void test_refs_foreachglob__can_cancel(void) { int count = 0; cl_assert_equal_i(GIT_EUSER, git_reference_foreach_glob( repo, "*", interrupt_cb, &count) ); cl_assert_equal_i(11, count); } libgit2-0.19.0/tests-clar/refs/isvalidname.c000066400000000000000000000033731216214232500206210ustar00rootroot00000000000000#include "clar_libgit2.h" void test_refs_isvalidname__can_detect_invalid_formats(void) { cl_assert_equal_i(false, git_reference_is_valid_name("refs/tags/0.17.0^{}")); cl_assert_equal_i(false, git_reference_is_valid_name("TWO/LEVELS")); cl_assert_equal_i(false, git_reference_is_valid_name("ONE.LEVEL")); cl_assert_equal_i(false, git_reference_is_valid_name("HEAD/")); cl_assert_equal_i(false, git_reference_is_valid_name("NO_TRAILING_UNDERSCORE_")); cl_assert_equal_i(false, git_reference_is_valid_name("_NO_LEADING_UNDERSCORE")); cl_assert_equal_i(false, git_reference_is_valid_name("HEAD/aa")); cl_assert_equal_i(false, git_reference_is_valid_name("lower_case")); cl_assert_equal_i(false, git_reference_is_valid_name("/stupid/name/master")); cl_assert_equal_i(false, git_reference_is_valid_name("/")); cl_assert_equal_i(false, git_reference_is_valid_name("//")); cl_assert_equal_i(false, git_reference_is_valid_name("")); cl_assert_equal_i(false, git_reference_is_valid_name("refs/heads/sub.lock/webmatrix")); } void test_refs_isvalidname__wont_hopefully_choke_on_valid_formats(void) { cl_assert_equal_i(true, git_reference_is_valid_name("refs/tags/0.17.0")); cl_assert_equal_i(true, git_reference_is_valid_name("refs/LEVELS")); cl_assert_equal_i(true, git_reference_is_valid_name("HEAD")); cl_assert_equal_i(true, git_reference_is_valid_name("ONE_LEVEL")); cl_assert_equal_i(true, git_reference_is_valid_name("refs/stash")); cl_assert_equal_i(true, git_reference_is_valid_name("refs/remotes/origin/bim_with_3d@11296")); cl_assert_equal_i(true, git_reference_is_valid_name("refs/master{yesterday")); cl_assert_equal_i(true, git_reference_is_valid_name("refs/master}yesterday")); cl_assert_equal_i(true, git_reference_is_valid_name("refs/master{yesterday}")); } libgit2-0.19.0/tests-clar/refs/iterator.c000066400000000000000000000042111216214232500201460ustar00rootroot00000000000000#include "clar_libgit2.h" #include "refs.h" #include "vector.h" static git_repository *repo; void test_refs_iterator__initialize(void) { cl_git_pass(git_repository_open(&repo, cl_fixture("testrepo.git"))); } void test_refs_iterator__cleanup(void) { git_repository_free(repo); } static const char *refnames[] = { "refs/heads/br2", "refs/heads/cannot-fetch", "refs/heads/chomped", "refs/heads/haacked", "refs/heads/master", "refs/heads/not-good", "refs/heads/packed", "refs/heads/packed-test", "refs/heads/subtrees", "refs/heads/test", "refs/heads/track-local", "refs/heads/trailing", "refs/notes/fanout", "refs/remotes/test/master", "refs/tags/annotated_tag_to_blob", "refs/tags/e90810b", "refs/tags/hard_tag", "refs/tags/point_to_blob", "refs/tags/taggerless", "refs/tags/test", "refs/tags/wrapped_tag", }; static int refcmp_cb(const void *a, const void *b) { const git_reference *refa = (const git_reference *)a; const git_reference *refb = (const git_reference *)b; return strcmp(refa->name, refb->name); } void test_refs_iterator__list(void) { git_reference_iterator *iter; git_vector output; git_reference *ref; int error; size_t i; cl_git_pass(git_vector_init(&output, 32, &refcmp_cb)); cl_git_pass(git_reference_iterator_new(&iter, repo)); do { error = git_reference_next(&ref, iter); cl_assert(error == 0 || error == GIT_ITEROVER); if (error != GIT_ITEROVER) { cl_git_pass(git_vector_insert(&output, ref)); } } while (!error); git_reference_iterator_free(iter); cl_assert_equal_sz(output.length, ARRAY_SIZE(refnames)); git_vector_sort(&output); git_vector_foreach(&output, i, ref) { cl_assert_equal_s(ref->name, refnames[i]); git_reference_free(ref); } git_vector_free(&output); } void test_refs_iterator__empty(void) { git_reference_iterator *iter; git_odb *odb; git_reference *ref; git_repository *empty; cl_git_pass(git_odb_new(&odb)); cl_git_pass(git_repository_wrap_odb(&empty, odb)); cl_git_pass(git_reference_iterator_new(&iter, empty)); cl_assert_equal_i(GIT_ITEROVER, git_reference_next(&ref, iter)); git_reference_iterator_free(iter); git_odb_free(odb); git_repository_free(empty); } libgit2-0.19.0/tests-clar/refs/list.c000066400000000000000000000023021216214232500172670ustar00rootroot00000000000000#include "clar_libgit2.h" #include "repository.h" #include "git2/reflog.h" #include "reflog.h" static git_repository *g_repo; void test_refs_list__initialize(void) { g_repo = cl_git_sandbox_init("testrepo"); } void test_refs_list__cleanup(void) { cl_git_sandbox_cleanup(); } void test_refs_list__all(void) { // try to list all the references in our test repo git_strarray ref_list; cl_git_pass(git_reference_list(&ref_list, g_repo)); /*{ unsigned short i; for (i = 0; i < ref_list.count; ++i) printf("# %s\n", ref_list.strings[i]); }*/ /* We have exactly 12 refs in total if we include the packed ones: * there is a reference that exists both in the packfile and as * loose, but we only list it once */ cl_assert_equal_i((int)ref_list.count, 13); git_strarray_free(&ref_list); } void test_refs_list__do_not_retrieve_references_which_name_end_with_a_lock_extension(void) { git_strarray ref_list; /* Create a fake locked reference */ cl_git_mkfile( "./testrepo/.git/refs/heads/hanwen.lock", "144344043ba4d4a405da03de3844aa829ae8be0e\n"); cl_git_pass(git_reference_list(&ref_list, g_repo)); cl_assert_equal_i((int)ref_list.count, 13); git_strarray_free(&ref_list); } libgit2-0.19.0/tests-clar/refs/listall.c000066400000000000000000000022461216214232500177670ustar00rootroot00000000000000#include "clar_libgit2.h" #include "posix.h" static git_repository *repo; static git_strarray ref_list; static void ensure_no_refname_starts_with_a_forward_slash(const char *path) { size_t i; cl_git_pass(git_repository_open(&repo, path)); cl_git_pass(git_reference_list(&ref_list, repo)); cl_assert(ref_list.count > 0); for (i = 0; i < ref_list.count; i++) cl_assert(git__prefixcmp(ref_list.strings[i], "/") != 0); git_strarray_free(&ref_list); git_repository_free(repo); } void test_refs_listall__from_repository_opened_through_workdir_path(void) { cl_fixture_sandbox("status"); cl_git_pass(p_rename("status/.gitted", "status/.git")); ensure_no_refname_starts_with_a_forward_slash("status"); cl_fixture_cleanup("status"); } void test_refs_listall__from_repository_opened_through_gitdir_path(void) { ensure_no_refname_starts_with_a_forward_slash(cl_fixture("testrepo.git")); } void test_refs_listall__from_repository_with_no_trailing_newline(void) { cl_git_pass(git_repository_open(&repo, cl_fixture("bad_tag.git"))); cl_git_pass(git_reference_list(&ref_list, repo)); cl_assert(ref_list.count > 0); git_strarray_free(&ref_list); git_repository_free(repo); } libgit2-0.19.0/tests-clar/refs/lookup.c000066400000000000000000000022231216214232500176270ustar00rootroot00000000000000#include "clar_libgit2.h" #include "refs.h" static git_repository *g_repo; void test_refs_lookup__initialize(void) { g_repo = cl_git_sandbox_init("testrepo.git"); } void test_refs_lookup__cleanup(void) { cl_git_sandbox_cleanup(); } void test_refs_lookup__with_resolve(void) { git_reference *a, *b, *temp; cl_git_pass(git_reference_lookup(&temp, g_repo, "HEAD")); cl_git_pass(git_reference_resolve(&a, temp)); git_reference_free(temp); cl_git_pass(git_reference_lookup_resolved(&b, g_repo, "HEAD", 5)); cl_assert(git_reference_cmp(a, b) == 0); git_reference_free(b); cl_git_pass(git_reference_lookup_resolved(&b, g_repo, "HEAD_TRACKER", 5)); cl_assert(git_reference_cmp(a, b) == 0); git_reference_free(b); git_reference_free(a); } void test_refs_lookup__invalid_name(void) { git_oid oid; cl_git_fail(git_reference_name_to_id(&oid, g_repo, "/refs/tags/point_to_blob")); } void test_refs_lookup__oid(void) { git_oid tag, expected; cl_git_pass(git_reference_name_to_id(&tag, g_repo, "refs/tags/point_to_blob")); cl_git_pass(git_oid_fromstr(&expected, "1385f264afb75a56a5bec74243be9b367ba4ca08")); cl_assert(git_oid_cmp(&tag, &expected) == 0); } libgit2-0.19.0/tests-clar/refs/normalize.c000066400000000000000000000330411216214232500203200ustar00rootroot00000000000000#include "clar_libgit2.h" #include "repository.h" #include "git2/reflog.h" #include "reflog.h" // Helpers static void ensure_refname_normalized( unsigned int flags, const char *input_refname, const char *expected_refname) { char buffer_out[GIT_REFNAME_MAX]; cl_git_pass(git_reference_normalize_name(buffer_out, sizeof(buffer_out), input_refname, flags)); cl_assert_equal_s(expected_refname, buffer_out); } static void ensure_refname_invalid(unsigned int flags, const char *input_refname) { char buffer_out[GIT_REFNAME_MAX]; cl_assert_equal_i( GIT_EINVALIDSPEC, git_reference_normalize_name(buffer_out, sizeof(buffer_out), input_refname, flags)); } void test_refs_normalize__can_normalize_a_direct_reference_name(void) { ensure_refname_normalized( GIT_REF_FORMAT_NORMAL, "refs/dummy/a", "refs/dummy/a"); ensure_refname_normalized( GIT_REF_FORMAT_NORMAL, "refs/stash", "refs/stash"); ensure_refname_normalized( GIT_REF_FORMAT_NORMAL, "refs/tags/a", "refs/tags/a"); ensure_refname_normalized( GIT_REF_FORMAT_NORMAL, "refs/heads/a/b", "refs/heads/a/b"); ensure_refname_normalized( GIT_REF_FORMAT_NORMAL, "refs/heads/a./b", "refs/heads/a./b"); ensure_refname_normalized( GIT_REF_FORMAT_NORMAL, "refs/heads/v@ation", "refs/heads/v@ation"); ensure_refname_normalized( GIT_REF_FORMAT_NORMAL, "refs///heads///a", "refs/heads/a"); } void test_refs_normalize__cannot_normalize_any_direct_reference_name(void) { ensure_refname_invalid( GIT_REF_FORMAT_NORMAL, "a"); ensure_refname_invalid( GIT_REF_FORMAT_NORMAL, "/a"); ensure_refname_invalid( GIT_REF_FORMAT_NORMAL, "//a"); ensure_refname_invalid( GIT_REF_FORMAT_NORMAL, ""); ensure_refname_invalid( GIT_REF_FORMAT_NORMAL, "/refs/heads/a/"); ensure_refname_invalid( GIT_REF_FORMAT_NORMAL, "refs/heads/a/"); ensure_refname_invalid( GIT_REF_FORMAT_NORMAL, "refs/heads/a."); ensure_refname_invalid( GIT_REF_FORMAT_NORMAL, "refs/heads/a.lock"); ensure_refname_invalid( GIT_REF_FORMAT_NORMAL, "refs/heads/foo?bar"); ensure_refname_invalid( GIT_REF_FORMAT_NORMAL, "refs/heads\foo"); ensure_refname_normalized( GIT_REF_FORMAT_NORMAL, "refs/heads/v@ation", "refs/heads/v@ation"); ensure_refname_normalized( GIT_REF_FORMAT_NORMAL, "refs///heads///a", "refs/heads/a"); ensure_refname_invalid( GIT_REF_FORMAT_NORMAL, "refs/heads/.a/b"); ensure_refname_invalid( GIT_REF_FORMAT_NORMAL, "refs/heads/foo/../bar"); ensure_refname_invalid( GIT_REF_FORMAT_NORMAL, "refs/heads/foo..bar"); ensure_refname_invalid( GIT_REF_FORMAT_NORMAL, "refs/heads/./foo"); ensure_refname_invalid( GIT_REF_FORMAT_NORMAL, "refs/heads/v@{ation"); } void test_refs_normalize__symbolic(void) { ensure_refname_invalid( GIT_REF_FORMAT_ALLOW_ONELEVEL, ""); ensure_refname_invalid( GIT_REF_FORMAT_ALLOW_ONELEVEL, "heads\foo"); ensure_refname_invalid( GIT_REF_FORMAT_ALLOW_ONELEVEL, "/"); ensure_refname_invalid( GIT_REF_FORMAT_ALLOW_ONELEVEL, "///"); ensure_refname_normalized( GIT_REF_FORMAT_ALLOW_ONELEVEL, "ALL_CAPS_AND_UNDERSCORES", "ALL_CAPS_AND_UNDERSCORES"); ensure_refname_normalized( GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/MixedCasing", "refs/MixedCasing"); ensure_refname_normalized( GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs///heads///a", "refs/heads/a"); ensure_refname_normalized( GIT_REF_FORMAT_ALLOW_ONELEVEL, "HEAD", "HEAD"); ensure_refname_normalized( GIT_REF_FORMAT_ALLOW_ONELEVEL, "MERGE_HEAD", "MERGE_HEAD"); ensure_refname_normalized( GIT_REF_FORMAT_ALLOW_ONELEVEL, "FETCH_HEAD", "FETCH_HEAD"); } /* Ported from JGit, BSD licence. * See https://github.com/spearce/JGit/commit/e4bf8f6957bbb29362575d641d1e77a02d906739 * * Copyright (C) 2009, Google Inc. * * All rights reserved. * * Redistribution and use in source and binary forms, with or * without modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials provided * with the distribution. * * - Neither the name of the Git Development Community nor the * names of its contributors may be used to endorse or promote * products derived from this software without specific prior * written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ void test_refs_normalize__jgit_suite(void) { // tests borrowed from JGit /* EmptyString */ ensure_refname_invalid( GIT_REF_FORMAT_ALLOW_ONELEVEL, ""); ensure_refname_invalid( GIT_REF_FORMAT_ALLOW_ONELEVEL, "/"); /* MustHaveTwoComponents */ ensure_refname_invalid( GIT_REF_FORMAT_NORMAL, "master"); ensure_refname_normalized( GIT_REF_FORMAT_NORMAL, "heads/master", "heads/master"); /* ValidHead */ ensure_refname_normalized( GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/master", "refs/heads/master"); ensure_refname_normalized( GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/pu", "refs/heads/pu"); ensure_refname_normalized( GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/z", "refs/heads/z"); ensure_refname_normalized( GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/FoO", "refs/heads/FoO"); /* ValidTag */ ensure_refname_normalized( GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/tags/v1.0", "refs/tags/v1.0"); /* NoLockSuffix */ ensure_refname_invalid(GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/master.lock"); /* NoDirectorySuffix */ ensure_refname_invalid( GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/master/"); /* NoSpace */ ensure_refname_invalid( GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/i haz space"); /* NoAsciiControlCharacters */ { char c; char buffer[GIT_REFNAME_MAX]; for (c = '\1'; c < ' '; c++) { strncpy(buffer, "refs/heads/mast", 15); strncpy(buffer + 15, (const char *)&c, 1); strncpy(buffer + 16, "er", 2); buffer[18 - 1] = '\0'; ensure_refname_invalid(GIT_REF_FORMAT_ALLOW_ONELEVEL, buffer); } } /* NoBareDot */ ensure_refname_invalid( GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/."); ensure_refname_invalid( GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/.."); ensure_refname_invalid( GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/./master"); ensure_refname_invalid( GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/../master"); /* NoLeadingOrTrailingDot */ ensure_refname_invalid( GIT_REF_FORMAT_ALLOW_ONELEVEL, "."); ensure_refname_invalid( GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/.bar"); ensure_refname_invalid( GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/..bar"); ensure_refname_invalid( GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/bar."); /* ContainsDot */ ensure_refname_normalized( GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/m.a.s.t.e.r", "refs/heads/m.a.s.t.e.r"); ensure_refname_invalid( GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/master..pu"); /* NoMagicRefCharacters */ ensure_refname_invalid( GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/master^"); ensure_refname_invalid( GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/^master"); ensure_refname_invalid( GIT_REF_FORMAT_ALLOW_ONELEVEL, "^refs/heads/master"); ensure_refname_invalid( GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/master~"); ensure_refname_invalid( GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/~master"); ensure_refname_invalid( GIT_REF_FORMAT_ALLOW_ONELEVEL, "~refs/heads/master"); ensure_refname_invalid( GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/master:"); ensure_refname_invalid( GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/:master"); ensure_refname_invalid( GIT_REF_FORMAT_ALLOW_ONELEVEL, ":refs/heads/master"); /* ShellGlob */ ensure_refname_invalid( GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/master?"); ensure_refname_invalid( GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/?master"); ensure_refname_invalid( GIT_REF_FORMAT_ALLOW_ONELEVEL, "?refs/heads/master"); ensure_refname_invalid( GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/master["); ensure_refname_invalid( GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/[master"); ensure_refname_invalid( GIT_REF_FORMAT_ALLOW_ONELEVEL, "[refs/heads/master"); ensure_refname_invalid( GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/master*"); ensure_refname_invalid( GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/*master"); ensure_refname_invalid( GIT_REF_FORMAT_ALLOW_ONELEVEL, "*refs/heads/master"); /* ValidSpecialCharacters */ ensure_refname_normalized (GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/!", "refs/heads/!"); ensure_refname_normalized( GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/\"", "refs/heads/\""); ensure_refname_normalized( GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/#", "refs/heads/#"); ensure_refname_normalized( GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/$", "refs/heads/$"); ensure_refname_normalized( GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/%", "refs/heads/%"); ensure_refname_normalized( GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/&", "refs/heads/&"); ensure_refname_normalized( GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/'", "refs/heads/'"); ensure_refname_normalized( GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/(", "refs/heads/("); ensure_refname_normalized( GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/)", "refs/heads/)"); ensure_refname_normalized( GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/+", "refs/heads/+"); ensure_refname_normalized( GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/,", "refs/heads/,"); ensure_refname_normalized( GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/-", "refs/heads/-"); ensure_refname_normalized( GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/;", "refs/heads/;"); ensure_refname_normalized( GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/<", "refs/heads/<"); ensure_refname_normalized( GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/=", "refs/heads/="); ensure_refname_normalized( GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/>", "refs/heads/>"); ensure_refname_normalized( GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/@", "refs/heads/@"); ensure_refname_normalized( GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/]", "refs/heads/]"); ensure_refname_normalized( GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/_", "refs/heads/_"); ensure_refname_normalized( GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/`", "refs/heads/`"); ensure_refname_normalized( GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/{", "refs/heads/{"); ensure_refname_normalized( GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/|", "refs/heads/|"); ensure_refname_normalized( GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/}", "refs/heads/}"); // This is valid on UNIX, but not on Windows // hence we make in invalid due to non-portability // ensure_refname_invalid( GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/\\"); /* UnicodeNames */ /* * Currently this fails. * ensure_refname_normalized(GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/\u00e5ngstr\u00f6m", "refs/heads/\u00e5ngstr\u00f6m"); */ /* RefLogQueryIsValidRef */ ensure_refname_invalid( GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/master@{1}"); ensure_refname_invalid( GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/master@{1.hour.ago}"); } void test_refs_normalize__buffer_has_to_be_big_enough_to_hold_the_normalized_version(void) { char buffer_out[21]; cl_git_pass(git_reference_normalize_name( buffer_out, 21, "refs//heads///long///name", GIT_REF_FORMAT_NORMAL)); cl_git_fail(git_reference_normalize_name( buffer_out, 20, "refs//heads///long///name", GIT_REF_FORMAT_NORMAL)); } #define ONE_LEVEL_AND_REFSPEC \ GIT_REF_FORMAT_ALLOW_ONELEVEL \ | GIT_REF_FORMAT_REFSPEC_PATTERN void test_refs_normalize__refspec_pattern(void) { ensure_refname_invalid( GIT_REF_FORMAT_REFSPEC_PATTERN, "heads/*foo/bar"); ensure_refname_invalid( GIT_REF_FORMAT_REFSPEC_PATTERN, "heads/foo*/bar"); ensure_refname_invalid( GIT_REF_FORMAT_REFSPEC_PATTERN, "heads/f*o/bar"); ensure_refname_invalid( GIT_REF_FORMAT_REFSPEC_PATTERN, "foo"); ensure_refname_normalized( ONE_LEVEL_AND_REFSPEC, "FOO", "FOO"); ensure_refname_normalized( GIT_REF_FORMAT_REFSPEC_PATTERN, "foo/bar", "foo/bar"); ensure_refname_normalized( ONE_LEVEL_AND_REFSPEC, "foo/bar", "foo/bar"); ensure_refname_normalized( GIT_REF_FORMAT_REFSPEC_PATTERN, "*/foo", "*/foo"); ensure_refname_normalized( ONE_LEVEL_AND_REFSPEC, "*/foo", "*/foo"); ensure_refname_normalized( GIT_REF_FORMAT_REFSPEC_PATTERN, "foo/*/bar", "foo/*/bar"); ensure_refname_normalized( ONE_LEVEL_AND_REFSPEC, "foo/*/bar", "foo/*/bar"); ensure_refname_invalid( GIT_REF_FORMAT_REFSPEC_PATTERN, "*"); ensure_refname_normalized( ONE_LEVEL_AND_REFSPEC, "*", "*"); ensure_refname_invalid( GIT_REF_FORMAT_REFSPEC_PATTERN, "foo/*/*"); ensure_refname_invalid( ONE_LEVEL_AND_REFSPEC, "foo/*/*"); ensure_refname_invalid( GIT_REF_FORMAT_REFSPEC_PATTERN, "*/foo/*"); ensure_refname_invalid( ONE_LEVEL_AND_REFSPEC, "*/foo/*"); ensure_refname_invalid( GIT_REF_FORMAT_REFSPEC_PATTERN, "*/*/foo"); ensure_refname_invalid( ONE_LEVEL_AND_REFSPEC, "*/*/foo"); } libgit2-0.19.0/tests-clar/refs/overwrite.c000066400000000000000000000110351216214232500203450ustar00rootroot00000000000000#include "clar_libgit2.h" #include "repository.h" #include "git2/reflog.h" #include "reflog.h" static const char *ref_name = "refs/heads/other"; static const char *ref_master_name = "refs/heads/master"; static const char *ref_branch_name = "refs/heads/branch"; static const char *ref_test_name = "refs/heads/test"; static git_repository *g_repo; void test_refs_overwrite__initialize(void) { g_repo = cl_git_sandbox_init("testrepo"); } void test_refs_overwrite__cleanup(void) { cl_git_sandbox_cleanup(); } void test_refs_overwrite__symbolic(void) { // Overwrite an existing symbolic reference git_reference *ref, *branch_ref; /* The target needds to exist and we need to check the name has changed */ cl_git_pass(git_reference_symbolic_create(&branch_ref, g_repo, ref_branch_name, ref_master_name, 0)); cl_git_pass(git_reference_symbolic_create(&ref, g_repo, ref_name, ref_branch_name, 0)); git_reference_free(ref); /* Ensure it points to the right place*/ cl_git_pass(git_reference_lookup(&ref, g_repo, ref_name)); cl_assert(git_reference_type(ref) & GIT_REF_SYMBOLIC); cl_assert_equal_s(git_reference_symbolic_target(ref), ref_branch_name); git_reference_free(ref); /* Ensure we can't create it unless we force it to */ cl_git_fail(git_reference_symbolic_create(&ref, g_repo, ref_name, ref_master_name, 0)); cl_git_pass(git_reference_symbolic_create(&ref, g_repo, ref_name, ref_master_name, 1)); git_reference_free(ref); /* Ensure it points to the right place */ cl_git_pass(git_reference_lookup(&ref, g_repo, ref_name)); cl_assert(git_reference_type(ref) & GIT_REF_SYMBOLIC); cl_assert_equal_s(git_reference_symbolic_target(ref), ref_master_name); git_reference_free(ref); git_reference_free(branch_ref); } void test_refs_overwrite__object_id(void) { // Overwrite an existing object id reference git_reference *ref; git_oid id; cl_git_pass(git_reference_lookup(&ref, g_repo, ref_master_name)); cl_assert(git_reference_type(ref) & GIT_REF_OID); git_oid_cpy(&id, git_reference_target(ref)); git_reference_free(ref); /* Create it */ cl_git_pass(git_reference_create(&ref, g_repo, ref_name, &id, 0)); git_reference_free(ref); cl_git_pass(git_reference_lookup(&ref, g_repo, ref_test_name)); cl_assert(git_reference_type(ref) & GIT_REF_OID); git_oid_cpy(&id, git_reference_target(ref)); git_reference_free(ref); /* Ensure we can't overwrite unless we force it */ cl_git_fail(git_reference_create(&ref, g_repo, ref_name, &id, 0)); cl_git_pass(git_reference_create(&ref, g_repo, ref_name, &id, 1)); git_reference_free(ref); /* Ensure it has been overwritten */ cl_git_pass(git_reference_lookup(&ref, g_repo, ref_name)); cl_assert(!git_oid_cmp(&id, git_reference_target(ref))); git_reference_free(ref); } void test_refs_overwrite__object_id_with_symbolic(void) { // Overwrite an existing object id reference with a symbolic one git_reference *ref; git_oid id; cl_git_pass(git_reference_lookup(&ref, g_repo, ref_master_name)); cl_assert(git_reference_type(ref) & GIT_REF_OID); git_oid_cpy(&id, git_reference_target(ref)); git_reference_free(ref); cl_git_pass(git_reference_create(&ref, g_repo, ref_name, &id, 0)); git_reference_free(ref); cl_git_fail(git_reference_symbolic_create(&ref, g_repo, ref_name, ref_master_name, 0)); cl_git_pass(git_reference_symbolic_create(&ref, g_repo, ref_name, ref_master_name, 1)); git_reference_free(ref); /* Ensure it points to the right place */ cl_git_pass(git_reference_lookup(&ref, g_repo, ref_name)); cl_assert(git_reference_type(ref) & GIT_REF_SYMBOLIC); cl_assert_equal_s(git_reference_symbolic_target(ref), ref_master_name); git_reference_free(ref); } void test_refs_overwrite__symbolic_with_object_id(void) { // Overwrite an existing symbolic reference with an object id one git_reference *ref; git_oid id; cl_git_pass(git_reference_lookup(&ref, g_repo, ref_master_name)); cl_assert(git_reference_type(ref) & GIT_REF_OID); git_oid_cpy(&id, git_reference_target(ref)); git_reference_free(ref); /* Create the symbolic ref */ cl_git_pass(git_reference_symbolic_create(&ref, g_repo, ref_name, ref_master_name, 0)); git_reference_free(ref); /* It shouldn't overwrite unless we tell it to */ cl_git_fail(git_reference_create(&ref, g_repo, ref_name, &id, 0)); cl_git_pass(git_reference_create(&ref, g_repo, ref_name, &id, 1)); git_reference_free(ref); /* Ensure it points to the right place */ cl_git_pass(git_reference_lookup(&ref, g_repo, ref_name)); cl_assert(git_reference_type(ref) & GIT_REF_OID); cl_assert(!git_oid_cmp(git_reference_target(ref), &id)); git_reference_free(ref); } libgit2-0.19.0/tests-clar/refs/pack.c000066400000000000000000000042241216214232500172370ustar00rootroot00000000000000#include "clar_libgit2.h" #include "fileops.h" #include "git2/reflog.h" #include "git2/refdb.h" #include "reflog.h" #include "refs.h" #include "ref_helpers.h" static const char *loose_tag_ref_name = "refs/tags/e90810b"; static git_repository *g_repo; void test_refs_pack__initialize(void) { g_repo = cl_git_sandbox_init("testrepo"); } void test_refs_pack__cleanup(void) { cl_git_sandbox_cleanup(); } static void packall(void) { git_refdb *refdb; cl_git_pass(git_repository_refdb(&refdb, g_repo)); cl_git_pass(git_refdb_compress(refdb)); git_refdb_free(refdb); } void test_refs_pack__empty(void) { // create a packfile for an empty folder git_buf temp_path = GIT_BUF_INIT; cl_git_pass(git_buf_join_n(&temp_path, '/', 3, git_repository_path(g_repo), GIT_REFS_HEADS_DIR, "empty_dir")); cl_git_pass(git_futils_mkdir_r(temp_path.ptr, NULL, GIT_REFS_DIR_MODE)); git_buf_free(&temp_path); packall(); } void test_refs_pack__loose(void) { // create a packfile from all the loose rn a repo git_reference *reference; git_buf temp_path = GIT_BUF_INIT; /* Ensure a known loose ref can be looked up */ cl_git_pass(git_reference_lookup(&reference, g_repo, loose_tag_ref_name)); cl_assert(reference_is_packed(reference) == 0); cl_assert_equal_s(reference->name, loose_tag_ref_name); git_reference_free(reference); /* * We are now trying to pack also a loose reference * called `points_to_blob`, to make sure we can properly * pack weak tags */ packall(); /* Ensure the packed-refs file exists */ cl_git_pass(git_buf_joinpath(&temp_path, git_repository_path(g_repo), GIT_PACKEDREFS_FILE)); cl_assert(git_path_exists(temp_path.ptr)); /* Ensure the known ref can still be looked up but is now packed */ cl_git_pass(git_reference_lookup(&reference, g_repo, loose_tag_ref_name)); cl_assert(reference_is_packed(reference)); cl_assert_equal_s(reference->name, loose_tag_ref_name); /* Ensure the known ref has been removed from the loose folder structure */ cl_git_pass(git_buf_joinpath(&temp_path, git_repository_path(g_repo), loose_tag_ref_name)); cl_assert(!git_path_exists(temp_path.ptr)); git_reference_free(reference); git_buf_free(&temp_path); } libgit2-0.19.0/tests-clar/refs/peel.c000066400000000000000000000066451216214232500172570ustar00rootroot00000000000000#include "clar_libgit2.h" static git_repository *g_repo; static git_repository *g_peel_repo; void test_refs_peel__initialize(void) { cl_git_pass(git_repository_open(&g_repo, cl_fixture("testrepo.git"))); cl_git_pass(git_repository_open(&g_peel_repo, cl_fixture("peeled.git"))); } void test_refs_peel__cleanup(void) { git_repository_free(g_repo); g_repo = NULL; git_repository_free(g_peel_repo); g_peel_repo = NULL; } static void assert_peel_generic( git_repository *repo, const char *ref_name, git_otype requested_type, const char* expected_sha, git_otype expected_type) { git_oid expected_oid; git_reference *ref; git_object *peeled; cl_git_pass(git_reference_lookup(&ref, repo, ref_name)); cl_git_pass(git_reference_peel(&peeled, ref, requested_type)); cl_git_pass(git_oid_fromstr(&expected_oid, expected_sha)); cl_assert_equal_i(0, git_oid_cmp(&expected_oid, git_object_id(peeled))); cl_assert_equal_i(expected_type, git_object_type(peeled)); git_object_free(peeled); git_reference_free(ref); } static void assert_peel( const char *ref_name, git_otype requested_type, const char* expected_sha, git_otype expected_type) { assert_peel_generic(g_repo, ref_name, requested_type, expected_sha, expected_type); } static void assert_peel_error(int error, const char *ref_name, git_otype requested_type) { git_reference *ref; git_object *peeled; cl_git_pass(git_reference_lookup(&ref, g_repo, ref_name)); cl_assert_equal_i(error, git_reference_peel(&peeled, ref, requested_type)); git_reference_free(ref); } void test_refs_peel__can_peel_a_tag(void) { assert_peel("refs/tags/test", GIT_OBJ_TAG, "b25fa35b38051e4ae45d4222e795f9df2e43f1d1", GIT_OBJ_TAG); assert_peel("refs/tags/test", GIT_OBJ_COMMIT, "e90810b8df3e80c413d903f631643c716887138d", GIT_OBJ_COMMIT); assert_peel("refs/tags/test", GIT_OBJ_TREE, "53fc32d17276939fc79ed05badaef2db09990016", GIT_OBJ_TREE); assert_peel("refs/tags/point_to_blob", GIT_OBJ_BLOB, "1385f264afb75a56a5bec74243be9b367ba4ca08", GIT_OBJ_BLOB); } void test_refs_peel__can_peel_a_branch(void) { assert_peel("refs/heads/master", GIT_OBJ_COMMIT, "a65fedf39aefe402d3bb6e24df4d4f5fe4547750", GIT_OBJ_COMMIT); assert_peel("refs/heads/master", GIT_OBJ_TREE, "944c0f6e4dfa41595e6eb3ceecdb14f50fe18162", GIT_OBJ_TREE); } void test_refs_peel__can_peel_a_symbolic_reference(void) { assert_peel("HEAD", GIT_OBJ_COMMIT, "a65fedf39aefe402d3bb6e24df4d4f5fe4547750", GIT_OBJ_COMMIT); assert_peel("HEAD", GIT_OBJ_TREE, "944c0f6e4dfa41595e6eb3ceecdb14f50fe18162", GIT_OBJ_TREE); } void test_refs_peel__cannot_peel_into_a_non_existing_target(void) { assert_peel_error(GIT_ENOTFOUND, "refs/tags/point_to_blob", GIT_OBJ_TAG); } void test_refs_peel__can_peel_into_any_non_tag_object(void) { assert_peel("refs/heads/master", GIT_OBJ_ANY, "a65fedf39aefe402d3bb6e24df4d4f5fe4547750", GIT_OBJ_COMMIT); assert_peel("refs/tags/point_to_blob", GIT_OBJ_ANY, "1385f264afb75a56a5bec74243be9b367ba4ca08", GIT_OBJ_BLOB); assert_peel("refs/tags/test", GIT_OBJ_ANY, "e90810b8df3e80c413d903f631643c716887138d", GIT_OBJ_COMMIT); } void test_refs_peel__can_peel_fully_peeled_packed_refs(void) { assert_peel_generic(g_peel_repo, "refs/tags/tag-inside-tags", GIT_OBJ_ANY, "0df1a5865c8abfc09f1f2182e6a31be550e99f07", GIT_OBJ_COMMIT); assert_peel_generic(g_peel_repo, "refs/foo/tag-outside-tags", GIT_OBJ_ANY, "0df1a5865c8abfc09f1f2182e6a31be550e99f07", GIT_OBJ_COMMIT); } libgit2-0.19.0/tests-clar/refs/read.c000066400000000000000000000211561216214232500172370ustar00rootroot00000000000000#include "clar_libgit2.h" #include "repository.h" #include "git2/reflog.h" #include "reflog.h" #include "ref_helpers.h" static const char *loose_tag_ref_name = "refs/tags/e90810b"; static const char *non_existing_tag_ref_name = "refs/tags/i-do-not-exist"; static const char *head_tracker_sym_ref_name = "HEAD_TRACKER"; static const char *current_head_target = "refs/heads/master"; static const char *current_master_tip = "a65fedf39aefe402d3bb6e24df4d4f5fe4547750"; static const char *packed_head_name = "refs/heads/packed"; static const char *packed_test_head_name = "refs/heads/packed-test"; static git_repository *g_repo; void test_refs_read__initialize(void) { cl_git_pass(git_repository_open(&g_repo, cl_fixture("testrepo.git"))); } void test_refs_read__cleanup(void) { git_repository_free(g_repo); g_repo = NULL; } void test_refs_read__loose_tag(void) { // lookup a loose tag reference git_reference *reference; git_object *object; git_buf ref_name_from_tag_name = GIT_BUF_INIT; cl_git_pass(git_reference_lookup(&reference, g_repo, loose_tag_ref_name)); cl_assert(git_reference_type(reference) & GIT_REF_OID); cl_assert(reference_is_packed(reference) == 0); cl_assert_equal_s(reference->name, loose_tag_ref_name); cl_git_pass(git_object_lookup(&object, g_repo, git_reference_target(reference), GIT_OBJ_ANY)); cl_assert(object != NULL); cl_assert(git_object_type(object) == GIT_OBJ_TAG); /* Ensure the name of the tag matches the name of the reference */ cl_git_pass(git_buf_joinpath(&ref_name_from_tag_name, GIT_REFS_TAGS_DIR, git_tag_name((git_tag *)object))); cl_assert_equal_s(ref_name_from_tag_name.ptr, loose_tag_ref_name); git_buf_free(&ref_name_from_tag_name); git_object_free(object); git_reference_free(reference); } void test_refs_read__nonexisting_tag(void) { // lookup a loose tag reference that doesn't exist git_reference *reference; cl_git_fail(git_reference_lookup(&reference, g_repo, non_existing_tag_ref_name)); git_reference_free(reference); } void test_refs_read__symbolic(void) { // lookup a symbolic reference git_reference *reference, *resolved_ref; git_object *object; git_oid id; cl_git_pass(git_reference_lookup(&reference, g_repo, GIT_HEAD_FILE)); cl_assert(git_reference_type(reference) & GIT_REF_SYMBOLIC); cl_assert(reference_is_packed(reference) == 0); cl_assert_equal_s(reference->name, GIT_HEAD_FILE); cl_git_pass(git_reference_resolve(&resolved_ref, reference)); cl_assert(git_reference_type(resolved_ref) == GIT_REF_OID); cl_git_pass(git_object_lookup(&object, g_repo, git_reference_target(resolved_ref), GIT_OBJ_ANY)); cl_assert(object != NULL); cl_assert(git_object_type(object) == GIT_OBJ_COMMIT); git_oid_fromstr(&id, current_master_tip); cl_assert(git_oid_cmp(&id, git_object_id(object)) == 0); git_object_free(object); git_reference_free(reference); git_reference_free(resolved_ref); } void test_refs_read__nested_symbolic(void) { // lookup a nested symbolic reference git_reference *reference, *resolved_ref; git_object *object; git_oid id; cl_git_pass(git_reference_lookup(&reference, g_repo, head_tracker_sym_ref_name)); cl_assert(git_reference_type(reference) & GIT_REF_SYMBOLIC); cl_assert(reference_is_packed(reference) == 0); cl_assert_equal_s(reference->name, head_tracker_sym_ref_name); cl_git_pass(git_reference_resolve(&resolved_ref, reference)); cl_assert(git_reference_type(resolved_ref) == GIT_REF_OID); cl_git_pass(git_object_lookup(&object, g_repo, git_reference_target(resolved_ref), GIT_OBJ_ANY)); cl_assert(object != NULL); cl_assert(git_object_type(object) == GIT_OBJ_COMMIT); git_oid_fromstr(&id, current_master_tip); cl_assert(git_oid_cmp(&id, git_object_id(object)) == 0); git_object_free(object); git_reference_free(reference); git_reference_free(resolved_ref); } void test_refs_read__head_then_master(void) { // lookup the HEAD and resolve the master branch git_reference *reference, *resolved_ref, *comp_base_ref; cl_git_pass(git_reference_lookup(&reference, g_repo, head_tracker_sym_ref_name)); cl_git_pass(git_reference_resolve(&comp_base_ref, reference)); git_reference_free(reference); cl_git_pass(git_reference_lookup(&reference, g_repo, GIT_HEAD_FILE)); cl_git_pass(git_reference_resolve(&resolved_ref, reference)); cl_git_pass(git_oid_cmp(git_reference_target(comp_base_ref), git_reference_target(resolved_ref))); git_reference_free(reference); git_reference_free(resolved_ref); cl_git_pass(git_reference_lookup(&reference, g_repo, current_head_target)); cl_git_pass(git_reference_resolve(&resolved_ref, reference)); cl_git_pass(git_oid_cmp(git_reference_target(comp_base_ref), git_reference_target(resolved_ref))); git_reference_free(reference); git_reference_free(resolved_ref); git_reference_free(comp_base_ref); } void test_refs_read__master_then_head(void) { // lookup the master branch and then the HEAD git_reference *reference, *master_ref, *resolved_ref; cl_git_pass(git_reference_lookup(&master_ref, g_repo, current_head_target)); cl_git_pass(git_reference_lookup(&reference, g_repo, GIT_HEAD_FILE)); cl_git_pass(git_reference_resolve(&resolved_ref, reference)); cl_git_pass(git_oid_cmp(git_reference_target(master_ref), git_reference_target(resolved_ref))); git_reference_free(reference); git_reference_free(resolved_ref); git_reference_free(master_ref); } void test_refs_read__packed(void) { // lookup a packed reference git_reference *reference; git_object *object; cl_git_pass(git_reference_lookup(&reference, g_repo, packed_head_name)); cl_assert(git_reference_type(reference) & GIT_REF_OID); cl_assert(reference_is_packed(reference)); cl_assert_equal_s(reference->name, packed_head_name); cl_git_pass(git_object_lookup(&object, g_repo, git_reference_target(reference), GIT_OBJ_ANY)); cl_assert(object != NULL); cl_assert(git_object_type(object) == GIT_OBJ_COMMIT); git_object_free(object); git_reference_free(reference); } void test_refs_read__loose_first(void) { // assure that a loose reference is looked up before a packed reference git_reference *reference; cl_git_pass(git_reference_lookup(&reference, g_repo, packed_head_name)); git_reference_free(reference); cl_git_pass(git_reference_lookup(&reference, g_repo, packed_test_head_name)); cl_assert(git_reference_type(reference) & GIT_REF_OID); cl_assert(reference_is_packed(reference) == 0); cl_assert_equal_s(reference->name, packed_test_head_name); git_reference_free(reference); } void test_refs_read__chomped(void) { git_reference *test, *chomped; cl_git_pass(git_reference_lookup(&test, g_repo, "refs/heads/test")); cl_git_pass(git_reference_lookup(&chomped, g_repo, "refs/heads/chomped")); cl_git_pass(git_oid_cmp(git_reference_target(test), git_reference_target(chomped))); git_reference_free(test); git_reference_free(chomped); } void test_refs_read__trailing(void) { git_reference *test, *trailing; cl_git_pass(git_reference_lookup(&test, g_repo, "refs/heads/test")); cl_git_pass(git_reference_lookup(&trailing, g_repo, "refs/heads/trailing")); cl_git_pass(git_oid_cmp(git_reference_target(test), git_reference_target(trailing))); git_reference_free(trailing); cl_git_pass(git_reference_lookup(&trailing, g_repo, "FETCH_HEAD")); git_reference_free(test); git_reference_free(trailing); } void test_refs_read__unfound_return_ENOTFOUND(void) { git_reference *reference; git_oid id; cl_assert_equal_i(GIT_ENOTFOUND, git_reference_lookup(&reference, g_repo, "TEST_MASTER")); cl_assert_equal_i(GIT_ENOTFOUND, git_reference_lookup(&reference, g_repo, "refs/test/master")); cl_assert_equal_i(GIT_ENOTFOUND, git_reference_lookup(&reference, g_repo, "refs/tags/test/master")); cl_assert_equal_i(GIT_ENOTFOUND, git_reference_lookup(&reference, g_repo, "refs/tags/test/farther/master")); cl_assert_equal_i(GIT_ENOTFOUND, git_reference_name_to_id(&id, g_repo, "refs/tags/test/farther/master")); } static void assert_is_branch(const char *name, bool expected_branchness) { git_reference *reference; cl_git_pass(git_reference_lookup(&reference, g_repo, name)); cl_assert_equal_i(expected_branchness, git_reference_is_branch(reference)); git_reference_free(reference); } void test_refs_read__can_determine_if_a_reference_is_a_local_branch(void) { assert_is_branch("refs/heads/master", true); assert_is_branch("refs/heads/packed", true); assert_is_branch("refs/remotes/test/master", false); assert_is_branch("refs/tags/e90810b", false); } void test_refs_read__invalid_name_returns_EINVALIDSPEC(void) { git_reference *reference; git_oid id; cl_assert_equal_i(GIT_EINVALIDSPEC, git_reference_lookup(&reference, g_repo, "refs/heads/Inv@{id")); cl_assert_equal_i(GIT_EINVALIDSPEC, git_reference_name_to_id(&id, g_repo, "refs/heads/Inv@{id")); } libgit2-0.19.0/tests-clar/refs/ref_helpers.c000066400000000000000000000007061216214232500206200ustar00rootroot00000000000000#include "git2/repository.h" #include "git2/refs.h" #include "common.h" #include "util.h" #include "buffer.h" #include "path.h" int reference_is_packed(git_reference *ref) { git_buf ref_path = GIT_BUF_INIT; int packed; assert(ref); if (git_buf_joinpath(&ref_path, git_repository_path(git_reference_owner(ref)), git_reference_name(ref)) < 0) return -1; packed = !git_path_isfile(ref_path.ptr); git_buf_free(&ref_path); return packed; } libgit2-0.19.0/tests-clar/refs/ref_helpers.h000066400000000000000000000000551216214232500206220ustar00rootroot00000000000000int reference_is_packed(git_reference *ref); libgit2-0.19.0/tests-clar/refs/reflog/000077500000000000000000000000001216214232500174315ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/refs/reflog/drop.c000066400000000000000000000064531216214232500205510ustar00rootroot00000000000000#include "clar_libgit2.h" #include "reflog.h" static git_repository *g_repo; static git_reflog *g_reflog; static size_t entrycount; void test_refs_reflog_drop__initialize(void) { git_reference *ref; g_repo = cl_git_sandbox_init("testrepo.git"); cl_git_pass(git_reference_lookup(&ref, g_repo, "HEAD")); git_reflog_read(&g_reflog, ref); entrycount = git_reflog_entrycount(g_reflog); git_reference_free(ref); } void test_refs_reflog_drop__cleanup(void) { git_reflog_free(g_reflog); g_reflog = NULL; cl_git_sandbox_cleanup(); } void test_refs_reflog_drop__dropping_a_non_exisiting_entry_from_the_log_returns_ENOTFOUND(void) { cl_assert_equal_i(GIT_ENOTFOUND, git_reflog_drop(g_reflog, entrycount, 0)); cl_assert_equal_sz(entrycount, git_reflog_entrycount(g_reflog)); } void test_refs_reflog_drop__can_drop_an_entry(void) { cl_assert(entrycount > 4); cl_git_pass(git_reflog_drop(g_reflog, 2, 0)); cl_assert_equal_sz(entrycount - 1, git_reflog_entrycount(g_reflog)); } void test_refs_reflog_drop__can_drop_an_entry_and_rewrite_the_log_history(void) { const git_reflog_entry *before_current; const git_reflog_entry *after_current; git_oid before_current_old_oid, before_current_cur_oid; cl_assert(entrycount > 4); before_current = git_reflog_entry_byindex(g_reflog, 1); git_oid_cpy(&before_current_old_oid, &before_current->oid_old); git_oid_cpy(&before_current_cur_oid, &before_current->oid_cur); cl_git_pass(git_reflog_drop(g_reflog, 1, 1)); cl_assert_equal_sz(entrycount - 1, git_reflog_entrycount(g_reflog)); after_current = git_reflog_entry_byindex(g_reflog, 0); cl_assert_equal_i(0, git_oid_cmp(&before_current_old_oid, &after_current->oid_old)); cl_assert(0 != git_oid_cmp(&before_current_cur_oid, &after_current->oid_cur)); } void test_refs_reflog_drop__can_drop_the_oldest_entry(void) { const git_reflog_entry *entry; cl_assert(entrycount > 2); cl_git_pass(git_reflog_drop(g_reflog, entrycount - 1, 0)); cl_assert_equal_sz(entrycount - 1, git_reflog_entrycount(g_reflog)); entry = git_reflog_entry_byindex(g_reflog, entrycount - 2); cl_assert(git_oid_streq(&entry->oid_old, GIT_OID_HEX_ZERO) != 0); } void test_refs_reflog_drop__can_drop_the_oldest_entry_and_rewrite_the_log_history(void) { const git_reflog_entry *entry; cl_assert(entrycount > 2); cl_git_pass(git_reflog_drop(g_reflog, entrycount - 1, 1)); cl_assert_equal_sz(entrycount - 1, git_reflog_entrycount(g_reflog)); entry = git_reflog_entry_byindex(g_reflog, entrycount - 2); cl_assert(git_oid_streq(&entry->oid_old, GIT_OID_HEX_ZERO) == 0); } void test_refs_reflog_drop__can_drop_all_the_entries(void) { cl_assert(--entrycount > 0); do { cl_git_pass(git_reflog_drop(g_reflog, 0, 1)); } while (--entrycount > 0); cl_git_pass(git_reflog_drop(g_reflog, 0, 1)); cl_assert_equal_i(0, (int)git_reflog_entrycount(g_reflog)); } void test_refs_reflog_drop__can_persist_deletion_on_disk(void) { git_reference *ref; cl_assert(entrycount > 2); cl_git_pass(git_reference_lookup(&ref, g_repo, g_reflog->ref_name)); cl_git_pass(git_reflog_drop(g_reflog, 0, 1)); cl_assert_equal_sz(entrycount - 1, git_reflog_entrycount(g_reflog)); cl_git_pass(git_reflog_write(g_reflog)); git_reflog_free(g_reflog); git_reflog_read(&g_reflog, ref); git_reference_free(ref); cl_assert_equal_sz(entrycount - 1, git_reflog_entrycount(g_reflog)); } libgit2-0.19.0/tests-clar/refs/reflog/reflog.c000066400000000000000000000133431216214232500210570ustar00rootroot00000000000000#include "clar_libgit2.h" #include "fileops.h" #include "git2/reflog.h" #include "reflog.h" static const char *new_ref = "refs/heads/test-reflog"; static const char *current_master_tip = "a65fedf39aefe402d3bb6e24df4d4f5fe4547750"; #define commit_msg "commit: bla bla" static git_repository *g_repo; // helpers static void assert_signature(git_signature *expected, git_signature *actual) { cl_assert(actual); cl_assert_equal_s(expected->name, actual->name); cl_assert_equal_s(expected->email, actual->email); cl_assert(expected->when.offset == actual->when.offset); cl_assert(expected->when.time == actual->when.time); } // Fixture setup and teardown void test_refs_reflog_reflog__initialize(void) { g_repo = cl_git_sandbox_init("testrepo.git"); } void test_refs_reflog_reflog__cleanup(void) { cl_git_sandbox_cleanup(); } void test_refs_reflog_reflog__append_then_read(void) { // write a reflog for a given reference and ensure it can be read back git_repository *repo2; git_reference *ref, *lookedup_ref; git_oid oid; git_signature *committer; git_reflog *reflog; const git_reflog_entry *entry; /* Create a new branch pointing at the HEAD */ git_oid_fromstr(&oid, current_master_tip); cl_git_pass(git_reference_create(&ref, g_repo, new_ref, &oid, 0)); cl_git_pass(git_signature_now(&committer, "foo", "foo@bar")); cl_git_pass(git_reflog_read(&reflog, ref)); cl_git_fail(git_reflog_append(reflog, &oid, committer, "no inner\nnewline")); cl_git_pass(git_reflog_append(reflog, &oid, committer, NULL)); cl_git_pass(git_reflog_append(reflog, &oid, committer, commit_msg "\n")); cl_git_pass(git_reflog_write(reflog)); git_reflog_free(reflog); /* Reopen a new instance of the repository */ cl_git_pass(git_repository_open(&repo2, "testrepo.git")); /* Lookup the previously created branch */ cl_git_pass(git_reference_lookup(&lookedup_ref, repo2, new_ref)); /* Read and parse the reflog for this branch */ cl_git_pass(git_reflog_read(&reflog, lookedup_ref)); cl_assert_equal_i(2, (int)git_reflog_entrycount(reflog)); entry = git_reflog_entry_byindex(reflog, 1); assert_signature(committer, entry->committer); cl_assert(git_oid_streq(&entry->oid_old, GIT_OID_HEX_ZERO) == 0); cl_assert(git_oid_cmp(&oid, &entry->oid_cur) == 0); cl_assert(entry->msg == NULL); entry = git_reflog_entry_byindex(reflog, 0); assert_signature(committer, entry->committer); cl_assert(git_oid_cmp(&oid, &entry->oid_old) == 0); cl_assert(git_oid_cmp(&oid, &entry->oid_cur) == 0); cl_assert_equal_s(commit_msg, entry->msg); git_signature_free(committer); git_reflog_free(reflog); git_repository_free(repo2); git_reference_free(ref); git_reference_free(lookedup_ref); } void test_refs_reflog_reflog__renaming_the_reference_moves_the_reflog(void) { git_reference *master, *new_master; git_buf master_log_path = GIT_BUF_INIT, moved_log_path = GIT_BUF_INIT; git_buf_joinpath(&master_log_path, git_repository_path(g_repo), GIT_REFLOG_DIR); git_buf_puts(&moved_log_path, git_buf_cstr(&master_log_path)); git_buf_joinpath(&master_log_path, git_buf_cstr(&master_log_path), "refs/heads/master"); git_buf_joinpath(&moved_log_path, git_buf_cstr(&moved_log_path), "refs/moved"); cl_assert_equal_i(true, git_path_isfile(git_buf_cstr(&master_log_path))); cl_assert_equal_i(false, git_path_isfile(git_buf_cstr(&moved_log_path))); cl_git_pass(git_reference_lookup(&master, g_repo, "refs/heads/master")); cl_git_pass(git_reference_rename(&new_master, master, "refs/moved", 0)); git_reference_free(master); cl_assert_equal_i(false, git_path_isfile(git_buf_cstr(&master_log_path))); cl_assert_equal_i(true, git_path_isfile(git_buf_cstr(&moved_log_path))); git_reference_free(new_master); git_buf_free(&moved_log_path); git_buf_free(&master_log_path); } static void assert_has_reflog(bool expected_result, const char *name) { git_reference *ref; cl_git_pass(git_reference_lookup(&ref, g_repo, name)); cl_assert_equal_i(expected_result, git_reference_has_log(ref)); git_reference_free(ref); } void test_refs_reflog_reflog__reference_has_reflog(void) { assert_has_reflog(true, "HEAD"); assert_has_reflog(true, "refs/heads/master"); assert_has_reflog(false, "refs/heads/subtrees"); } void test_refs_reflog_reflog__reading_the_reflog_from_a_reference_with_no_log_returns_an_empty_one(void) { git_reference *subtrees; git_reflog *reflog; git_buf subtrees_log_path = GIT_BUF_INIT; cl_git_pass(git_reference_lookup(&subtrees, g_repo, "refs/heads/subtrees")); git_buf_join_n(&subtrees_log_path, '/', 3, git_repository_path(g_repo), GIT_REFLOG_DIR, git_reference_name(subtrees)); cl_assert_equal_i(false, git_path_isfile(git_buf_cstr(&subtrees_log_path))); cl_git_pass(git_reflog_read(&reflog, subtrees)); cl_assert_equal_i(0, (int)git_reflog_entrycount(reflog)); git_reflog_free(reflog); git_reference_free(subtrees); git_buf_free(&subtrees_log_path); } void test_refs_reflog_reflog__cannot_write_a_moved_reflog(void) { git_reference *master, *new_master; git_buf master_log_path = GIT_BUF_INIT, moved_log_path = GIT_BUF_INIT; git_reflog *reflog; cl_git_pass(git_reference_lookup(&master, g_repo, "refs/heads/master")); cl_git_pass(git_reflog_read(&reflog, master)); cl_git_pass(git_reflog_write(reflog)); cl_git_pass(git_reference_rename(&new_master, master, "refs/moved", 0)); git_reference_free(master); cl_git_fail(git_reflog_write(reflog)); git_reflog_free(reflog); git_reference_free(new_master); git_buf_free(&moved_log_path); git_buf_free(&master_log_path); } void test_refs_reflog_reflog__renaming_with_an_invalid_name_returns_EINVALIDSPEC(void) { git_reference *master; cl_git_pass(git_reference_lookup(&master, g_repo, "refs/heads/master")); cl_assert_equal_i(GIT_EINVALIDSPEC, git_reflog_rename(master, "refs/heads/Inv@{id")); git_reference_free(master); } libgit2-0.19.0/tests-clar/refs/rename.c000066400000000000000000000312111216214232500175640ustar00rootroot00000000000000#include "clar_libgit2.h" #include "fileops.h" #include "git2/reflog.h" #include "reflog.h" #include "refs.h" #include "ref_helpers.h" static const char *loose_tag_ref_name = "refs/tags/e90810b"; static const char *packed_head_name = "refs/heads/packed"; static const char *packed_test_head_name = "refs/heads/packed-test"; static const char *ref_one_name = "refs/heads/one/branch"; static const char *ref_one_name_new = "refs/heads/two/branch"; static const char *ref_two_name = "refs/heads/two"; static const char *ref_master_name = "refs/heads/master"; static const char *ref_two_name_new = "refs/heads/two/two"; static git_repository *g_repo; void test_refs_rename__initialize(void) { g_repo = cl_git_sandbox_init("testrepo"); } void test_refs_rename__cleanup(void) { cl_git_sandbox_cleanup(); } void test_refs_rename__loose(void) { // rename a loose reference git_reference *looked_up_ref, *new_ref, *another_looked_up_ref; git_buf temp_path = GIT_BUF_INIT; const char *new_name = "refs/tags/Nemo/knows/refs.kung-fu"; /* Ensure the ref doesn't exist on the file system */ cl_git_pass(git_buf_joinpath(&temp_path, git_repository_path(g_repo), new_name)); cl_assert(!git_path_exists(temp_path.ptr)); /* Retrieval of the reference to rename */ cl_git_pass(git_reference_lookup(&looked_up_ref, g_repo, loose_tag_ref_name)); /* ... which is indeed loose */ cl_assert(reference_is_packed(looked_up_ref) == 0); /* Now that the reference is renamed... */ cl_git_pass(git_reference_rename(&new_ref, looked_up_ref, new_name, 0)); cl_assert_equal_s(new_ref->name, new_name); git_reference_free(looked_up_ref); /* ...It can't be looked-up with the old name... */ cl_git_fail(git_reference_lookup(&another_looked_up_ref, g_repo, loose_tag_ref_name)); /* ...but the new name works ok... */ cl_git_pass(git_reference_lookup(&another_looked_up_ref, g_repo, new_name)); cl_assert_equal_s(new_ref->name, new_name); /* .. the new ref is loose... */ cl_assert(reference_is_packed(another_looked_up_ref) == 0); cl_assert(reference_is_packed(new_ref) == 0); /* ...and the ref can be found in the file system */ cl_git_pass(git_buf_joinpath(&temp_path, git_repository_path(g_repo), new_name)); cl_assert(git_path_exists(temp_path.ptr)); git_reference_free(new_ref); git_reference_free(another_looked_up_ref); git_buf_free(&temp_path); } void test_refs_rename__packed(void) { // rename a packed reference (should make it loose) git_reference *looked_up_ref, *new_ref, *another_looked_up_ref; git_buf temp_path = GIT_BUF_INIT; const char *brand_new_name = "refs/heads/brand_new_name"; /* Ensure the ref doesn't exist on the file system */ cl_git_pass(git_buf_joinpath(&temp_path, git_repository_path(g_repo), packed_head_name)); cl_assert(!git_path_exists(temp_path.ptr)); /* The reference can however be looked-up... */ cl_git_pass(git_reference_lookup(&looked_up_ref, g_repo, packed_head_name)); /* .. and it's packed */ cl_assert(reference_is_packed(looked_up_ref) != 0); /* Now that the reference is renamed... */ cl_git_pass(git_reference_rename(&new_ref, looked_up_ref, brand_new_name, 0)); cl_assert_equal_s(new_ref->name, brand_new_name); git_reference_free(looked_up_ref); /* ...It can't be looked-up with the old name... */ cl_git_fail(git_reference_lookup(&another_looked_up_ref, g_repo, packed_head_name)); /* ...but the new name works ok... */ cl_git_pass(git_reference_lookup(&another_looked_up_ref, g_repo, brand_new_name)); cl_assert_equal_s(another_looked_up_ref->name, brand_new_name); /* .. the ref is no longer packed... */ cl_assert(reference_is_packed(another_looked_up_ref) == 0); cl_assert(reference_is_packed(new_ref) == 0); /* ...and the ref now happily lives in the file system */ cl_git_pass(git_buf_joinpath(&temp_path, git_repository_path(g_repo), brand_new_name)); cl_assert(git_path_exists(temp_path.ptr)); git_reference_free(new_ref); git_reference_free(another_looked_up_ref); git_buf_free(&temp_path); } void test_refs_rename__packed_doesnt_pack_others(void) { // renaming a packed reference does not pack another reference which happens to be in both loose and pack state git_reference *looked_up_ref, *another_looked_up_ref, *renamed_ref; git_buf temp_path = GIT_BUF_INIT; const char *brand_new_name = "refs/heads/brand_new_name"; /* Ensure the other reference exists on the file system */ cl_git_pass(git_buf_joinpath(&temp_path, git_repository_path(g_repo), packed_test_head_name)); cl_assert(git_path_exists(temp_path.ptr)); /* Lookup the other reference */ cl_git_pass(git_reference_lookup(&another_looked_up_ref, g_repo, packed_test_head_name)); /* Ensure it's loose */ cl_assert(reference_is_packed(another_looked_up_ref) == 0); git_reference_free(another_looked_up_ref); /* Lookup the reference to rename */ cl_git_pass(git_reference_lookup(&looked_up_ref, g_repo, packed_head_name)); /* Ensure it's packed */ cl_assert(reference_is_packed(looked_up_ref) != 0); /* Now that the reference is renamed... */ cl_git_pass(git_reference_rename(&renamed_ref, looked_up_ref, brand_new_name, 0)); git_reference_free(looked_up_ref); /* Lookup the other reference */ cl_git_pass(git_reference_lookup(&another_looked_up_ref, g_repo, packed_test_head_name)); /* Ensure it's loose */ cl_assert(reference_is_packed(another_looked_up_ref) == 0); /* Ensure the other ref still exists on the file system */ cl_assert(git_path_exists(temp_path.ptr)); git_reference_free(renamed_ref); git_reference_free(another_looked_up_ref); git_buf_free(&temp_path); } void test_refs_rename__name_collision(void) { // can not rename a reference with the name of an existing reference git_reference *looked_up_ref, *renamed_ref; /* An existing reference... */ cl_git_pass(git_reference_lookup(&looked_up_ref, g_repo, packed_head_name)); /* Can not be renamed to the name of another existing reference. */ cl_git_fail(git_reference_rename(&renamed_ref, looked_up_ref, packed_test_head_name, 0)); git_reference_free(looked_up_ref); /* Failure to rename it hasn't corrupted its state */ cl_git_pass(git_reference_lookup(&looked_up_ref, g_repo, packed_head_name)); cl_assert_equal_s(looked_up_ref->name, packed_head_name); git_reference_free(looked_up_ref); } void test_refs_rename__invalid_name(void) { // can not rename a reference with an invalid name git_reference *looked_up_ref, *renamed_ref; /* An existing oid reference... */ cl_git_pass(git_reference_lookup(&looked_up_ref, g_repo, packed_test_head_name)); /* Can not be renamed with an invalid name. */ cl_assert_equal_i( GIT_EINVALIDSPEC, git_reference_rename(&renamed_ref, looked_up_ref, "Hello! I'm a very invalid name.", 0)); /* Can not be renamed outside of the refs hierarchy * unless it's ALL_CAPS_AND_UNDERSCORES. */ cl_assert_equal_i(GIT_EINVALIDSPEC, git_reference_rename(&renamed_ref, looked_up_ref, "i-will-sudo-you", 0)); /* Failure to rename it hasn't corrupted its state */ git_reference_free(looked_up_ref); cl_git_pass(git_reference_lookup(&looked_up_ref, g_repo, packed_test_head_name)); cl_assert_equal_s(looked_up_ref->name, packed_test_head_name); git_reference_free(looked_up_ref); } void test_refs_rename__force_loose_packed(void) { // can force-rename a packed reference with the name of an existing loose and packed reference git_reference *looked_up_ref, *renamed_ref; git_oid oid; /* An existing reference... */ cl_git_pass(git_reference_lookup(&looked_up_ref, g_repo, packed_head_name)); git_oid_cpy(&oid, git_reference_target(looked_up_ref)); /* Can be force-renamed to the name of another existing reference. */ cl_git_pass(git_reference_rename(&renamed_ref, looked_up_ref, packed_test_head_name, 1)); git_reference_free(looked_up_ref); git_reference_free(renamed_ref); /* Check we actually renamed it */ cl_git_pass(git_reference_lookup(&looked_up_ref, g_repo, packed_test_head_name)); cl_assert_equal_s(looked_up_ref->name, packed_test_head_name); cl_assert(!git_oid_cmp(&oid, git_reference_target(looked_up_ref))); git_reference_free(looked_up_ref); /* And that the previous one doesn't exist any longer */ cl_git_fail(git_reference_lookup(&looked_up_ref, g_repo, packed_head_name)); } void test_refs_rename__force_loose(void) { // can force-rename a loose reference with the name of an existing loose reference git_reference *looked_up_ref, *renamed_ref; git_oid oid; /* An existing reference... */ cl_git_pass(git_reference_lookup(&looked_up_ref, g_repo, "refs/heads/br2")); git_oid_cpy(&oid, git_reference_target(looked_up_ref)); /* Can be force-renamed to the name of another existing reference. */ cl_git_pass(git_reference_rename(&renamed_ref, looked_up_ref, "refs/heads/test", 1)); git_reference_free(looked_up_ref); git_reference_free(renamed_ref); /* Check we actually renamed it */ cl_git_pass(git_reference_lookup(&looked_up_ref, g_repo, "refs/heads/test")); cl_assert_equal_s(looked_up_ref->name, "refs/heads/test"); cl_assert(!git_oid_cmp(&oid, git_reference_target(looked_up_ref))); git_reference_free(looked_up_ref); /* And that the previous one doesn't exist any longer */ cl_git_fail(git_reference_lookup(&looked_up_ref, g_repo, "refs/heads/br2")); git_reference_free(looked_up_ref); } void test_refs_rename__overwrite(void) { // can not overwrite name of existing reference git_reference *ref, *ref_one, *ref_one_new, *ref_two; git_refdb *refdb; git_oid id; cl_git_pass(git_reference_lookup(&ref, g_repo, ref_master_name)); cl_assert(git_reference_type(ref) & GIT_REF_OID); git_oid_cpy(&id, git_reference_target(ref)); /* Create loose references */ cl_git_pass(git_reference_create(&ref_one, g_repo, ref_one_name, &id, 0)); cl_git_pass(git_reference_create(&ref_two, g_repo, ref_two_name, &id, 0)); /* Pack everything */ cl_git_pass(git_repository_refdb(&refdb, g_repo)); cl_git_pass(git_refdb_compress(refdb)); /* Attempt to create illegal reference */ cl_git_fail(git_reference_create(&ref_one_new, g_repo, ref_one_name_new, &id, 0)); /* Illegal reference couldn't be created so this is supposed to fail */ cl_git_fail(git_reference_lookup(&ref_one_new, g_repo, ref_one_name_new)); git_reference_free(ref); git_reference_free(ref_one); git_reference_free(ref_one_new); git_reference_free(ref_two); git_refdb_free(refdb); } void test_refs_rename__prefix(void) { // can be renamed to a new name prefixed with the old name git_reference *ref, *ref_two, *looked_up_ref, *renamed_ref; git_oid id; cl_git_pass(git_reference_lookup(&ref, g_repo, ref_master_name)); cl_assert(git_reference_type(ref) & GIT_REF_OID); git_oid_cpy(&id, git_reference_target(ref)); /* Create loose references */ cl_git_pass(git_reference_create(&ref_two, g_repo, ref_two_name, &id, 0)); /* An existing reference... */ cl_git_pass(git_reference_lookup(&looked_up_ref, g_repo, ref_two_name)); /* Can be rename to a new name starting with the old name. */ cl_git_pass(git_reference_rename(&renamed_ref, looked_up_ref, ref_two_name_new, 0)); git_reference_free(looked_up_ref); git_reference_free(renamed_ref); /* Check we actually renamed it */ cl_git_pass(git_reference_lookup(&looked_up_ref, g_repo, ref_two_name_new)); cl_assert_equal_s(looked_up_ref->name, ref_two_name_new); git_reference_free(looked_up_ref); cl_git_fail(git_reference_lookup(&looked_up_ref, g_repo, ref_two_name)); git_reference_free(ref); git_reference_free(ref_two); git_reference_free(looked_up_ref); } void test_refs_rename__move_up(void) { // can move a reference to a upper reference hierarchy git_reference *ref, *ref_two, *looked_up_ref, *renamed_ref; git_oid id; cl_git_pass(git_reference_lookup(&ref, g_repo, ref_master_name)); cl_assert(git_reference_type(ref) & GIT_REF_OID); git_oid_cpy(&id, git_reference_target(ref)); /* Create loose references */ cl_git_pass(git_reference_create(&ref_two, g_repo, ref_two_name_new, &id, 0)); git_reference_free(ref_two); /* An existing reference... */ cl_git_pass(git_reference_lookup(&looked_up_ref, g_repo, ref_two_name_new)); /* Can be renamed upward the reference tree. */ cl_git_pass(git_reference_rename(&renamed_ref, looked_up_ref, ref_two_name, 0)); git_reference_free(looked_up_ref); git_reference_free(renamed_ref); /* Check we actually renamed it */ cl_git_pass(git_reference_lookup(&looked_up_ref, g_repo, ref_two_name)); cl_assert_equal_s(looked_up_ref->name, ref_two_name); git_reference_free(looked_up_ref); cl_git_fail(git_reference_lookup(&looked_up_ref, g_repo, ref_two_name_new)); git_reference_free(ref); git_reference_free(looked_up_ref); } void test_refs_rename__propagate_eexists(void) { git_reference *ref, *new_ref; cl_git_pass(git_reference_lookup(&ref, g_repo, packed_head_name)); cl_assert_equal_i(GIT_EEXISTS, git_reference_rename(&new_ref, ref, packed_test_head_name, 0)); git_reference_free(ref); } libgit2-0.19.0/tests-clar/refs/revparse.c000066400000000000000000000574751216214232500201700ustar00rootroot00000000000000#include "clar_libgit2.h" #include "git2/revparse.h" #include "buffer.h" #include "refs.h" #include "path.h" static git_repository *g_repo; static git_object *g_obj; /* Helpers */ static void test_object_and_ref_inrepo( const char *spec, const char *expected_oid, const char *expected_refname, git_repository *repo, bool assert_reference_retrieval) { char objstr[64] = {0}; git_object *obj = NULL; git_reference *ref = NULL; int error; error = git_revparse_ext(&obj, &ref, repo, spec); if (expected_oid != NULL) { cl_assert_equal_i(0, error); git_oid_fmt(objstr, git_object_id(obj)); cl_assert_equal_s(objstr, expected_oid); } else cl_assert_equal_i(GIT_ENOTFOUND, error); if (assert_reference_retrieval) { if (expected_refname == NULL) cl_assert(NULL == ref); else cl_assert_equal_s(expected_refname, git_reference_name(ref)); } git_object_free(obj); git_reference_free(ref); } static void test_object_inrepo(const char *spec, const char *expected_oid, git_repository *repo) { test_object_and_ref_inrepo(spec, expected_oid, NULL, repo, false); } static void test_id_inrepo( const char *spec, const char *expected_left, const char *expected_right, git_revparse_mode_t expected_flags, git_repository *repo) { git_revspec revspec; int error = git_revparse(&revspec, repo, spec); if (expected_left) { char str[64] = {0}; cl_assert_equal_i(0, error); git_oid_fmt(str, git_object_id(revspec.from)); cl_assert_equal_s(str, expected_left); git_object_free(revspec.from); } else { cl_assert_equal_i(GIT_ENOTFOUND, error); } if (expected_right) { char str[64] = {0}; git_oid_fmt(str, git_object_id(revspec.to)); cl_assert_equal_s(str, expected_right); git_object_free(revspec.to); } if (expected_flags) cl_assert_equal_i(expected_flags, revspec.flags); } static void test_object(const char *spec, const char *expected_oid) { test_object_inrepo(spec, expected_oid, g_repo); } static void test_object_and_ref(const char *spec, const char *expected_oid, const char *expected_refname) { test_object_and_ref_inrepo(spec, expected_oid, expected_refname, g_repo, true); } static void test_rangelike(const char *rangelike, const char *expected_left, const char *expected_right, git_revparse_mode_t expected_revparseflags) { char objstr[64] = {0}; git_revspec revspec; int error; error = git_revparse(&revspec, g_repo, rangelike); if (expected_left != NULL) { cl_assert_equal_i(0, error); cl_assert_equal_i(revspec.flags, expected_revparseflags); git_oid_fmt(objstr, git_object_id(revspec.from)); cl_assert_equal_s(objstr, expected_left); git_oid_fmt(objstr, git_object_id(revspec.to)); cl_assert_equal_s(objstr, expected_right); } else cl_assert(error != 0); git_object_free(revspec.from); git_object_free(revspec.to); } static void test_id( const char *spec, const char *expected_left, const char *expected_right, git_revparse_mode_t expected_flags) { test_id_inrepo(spec, expected_left, expected_right, expected_flags, g_repo); } void test_refs_revparse__initialize(void) { cl_git_pass(git_repository_open(&g_repo, cl_fixture("testrepo.git"))); } void test_refs_revparse__cleanup(void) { git_repository_free(g_repo); } void test_refs_revparse__nonexistant_object(void) { test_object("this-does-not-exist", NULL); test_object("this-does-not-exist^1", NULL); test_object("this-does-not-exist~2", NULL); } static void assert_invalid_single_spec(const char *invalid_spec) { cl_assert_equal_i( GIT_EINVALIDSPEC, git_revparse_single(&g_obj, g_repo, invalid_spec)); } void test_refs_revparse__invalid_reference_name(void) { assert_invalid_single_spec("this doesn't make sense"); assert_invalid_single_spec("Inv@{id"); assert_invalid_single_spec(""); } void test_refs_revparse__shas(void) { test_object("c47800c7266a2be04c571c04d5a6614691ea99bd", "c47800c7266a2be04c571c04d5a6614691ea99bd"); test_object("c47800c", "c47800c7266a2be04c571c04d5a6614691ea99bd"); } void test_refs_revparse__head(void) { test_object("HEAD", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750"); test_object("HEAD^0", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750"); test_object("HEAD~0", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750"); test_object("master", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750"); } void test_refs_revparse__full_refs(void) { test_object("refs/heads/master", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750"); test_object("refs/heads/test", "e90810b8df3e80c413d903f631643c716887138d"); test_object("refs/tags/test", "b25fa35b38051e4ae45d4222e795f9df2e43f1d1"); } void test_refs_revparse__partial_refs(void) { test_object("point_to_blob", "1385f264afb75a56a5bec74243be9b367ba4ca08"); test_object("packed-test", "4a202b346bb0fb0db7eff3cffeb3c70babbd2045"); test_object("br2", "a4a7dce85cf63874e984719f4fdd239f5145052f"); } void test_refs_revparse__describe_output(void) { test_object("blah-7-gc47800c", "c47800c7266a2be04c571c04d5a6614691ea99bd"); test_object("not-good", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750"); } void test_refs_revparse__nth_parent(void) { assert_invalid_single_spec("be3563a^-1"); assert_invalid_single_spec("^"); assert_invalid_single_spec("be3563a^{tree}^"); assert_invalid_single_spec("point_to_blob^{blob}^"); assert_invalid_single_spec("this doesn't make sense^1"); test_object("be3563a^1", "9fd738e8f7967c078dceed8190330fc8648ee56a"); test_object("be3563a^", "9fd738e8f7967c078dceed8190330fc8648ee56a"); test_object("be3563a^2", "c47800c7266a2be04c571c04d5a6614691ea99bd"); test_object("be3563a^1^1", "4a202b346bb0fb0db7eff3cffeb3c70babbd2045"); test_object("be3563a^^", "4a202b346bb0fb0db7eff3cffeb3c70babbd2045"); test_object("be3563a^2^1", "5b5b025afb0b4c913b4c338a42934a3863bf3644"); test_object("be3563a^0", "be3563ae3f795b2b4353bcce3a527ad0a4f7f644"); test_object("be3563a^{commit}^", "9fd738e8f7967c078dceed8190330fc8648ee56a"); test_object("be3563a^42", NULL); } void test_refs_revparse__not_tag(void) { test_object("point_to_blob^{}", "1385f264afb75a56a5bec74243be9b367ba4ca08"); test_object("wrapped_tag^{}", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750"); test_object("master^{}", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750"); test_object("master^{tree}^{}", "944c0f6e4dfa41595e6eb3ceecdb14f50fe18162"); test_object("e90810b^{}", "e90810b8df3e80c413d903f631643c716887138d"); test_object("tags/e90810b^{}", "e90810b8df3e80c413d903f631643c716887138d"); test_object("e908^{}", "e90810b8df3e80c413d903f631643c716887138d"); } void test_refs_revparse__to_type(void) { assert_invalid_single_spec("wrapped_tag^{trip}"); test_object("point_to_blob^{commit}", NULL); cl_assert_equal_i( GIT_EAMBIGUOUS, git_revparse_single(&g_obj, g_repo, "wrapped_tag^{blob}")); test_object("wrapped_tag^{commit}", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750"); test_object("wrapped_tag^{tree}", "944c0f6e4dfa41595e6eb3ceecdb14f50fe18162"); test_object("point_to_blob^{blob}", "1385f264afb75a56a5bec74243be9b367ba4ca08"); test_object("master^{commit}^{commit}", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750"); } void test_refs_revparse__linear_history(void) { assert_invalid_single_spec("~"); test_object("foo~bar", NULL); assert_invalid_single_spec("master~bar"); assert_invalid_single_spec("master~-1"); assert_invalid_single_spec("master~0bar"); assert_invalid_single_spec("this doesn't make sense~2"); assert_invalid_single_spec("be3563a^{tree}~"); assert_invalid_single_spec("point_to_blob^{blob}~"); test_object("master~0", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750"); test_object("master~1", "be3563ae3f795b2b4353bcce3a527ad0a4f7f644"); test_object("master~2", "9fd738e8f7967c078dceed8190330fc8648ee56a"); test_object("master~1~1", "9fd738e8f7967c078dceed8190330fc8648ee56a"); test_object("master~~", "9fd738e8f7967c078dceed8190330fc8648ee56a"); } void test_refs_revparse__chaining(void) { assert_invalid_single_spec("master@{0}@{0}"); assert_invalid_single_spec("@{u}@{-1}"); assert_invalid_single_spec("@{-1}@{-1}"); assert_invalid_single_spec("@{-3}@{0}"); test_object("master@{0}~1^1", "9fd738e8f7967c078dceed8190330fc8648ee56a"); test_object("@{u}@{0}", "be3563ae3f795b2b4353bcce3a527ad0a4f7f644"); test_object("@{-1}@{0}", "a4a7dce85cf63874e984719f4fdd239f5145052f"); test_object("@{-4}@{1}", "be3563ae3f795b2b4353bcce3a527ad0a4f7f644"); test_object("master~1^1", "9fd738e8f7967c078dceed8190330fc8648ee56a"); test_object("master~1^2", "c47800c7266a2be04c571c04d5a6614691ea99bd"); test_object("master^1^2~1", "5b5b025afb0b4c913b4c338a42934a3863bf3644"); test_object("master^^2^", "5b5b025afb0b4c913b4c338a42934a3863bf3644"); test_object("master^1^1^1^1^1", "8496071c1b46c854b31185ea97743be6a8774479"); test_object("master^^1^2^1", NULL); } void test_refs_revparse__upstream(void) { assert_invalid_single_spec("e90810b@{u}"); assert_invalid_single_spec("refs/tags/e90810b@{u}"); test_object("refs/heads/e90810b@{u}", NULL); test_object("master@{upstream}", "be3563ae3f795b2b4353bcce3a527ad0a4f7f644"); test_object("@{u}", "be3563ae3f795b2b4353bcce3a527ad0a4f7f644"); test_object("master@{u}", "be3563ae3f795b2b4353bcce3a527ad0a4f7f644"); test_object("heads/master@{u}", "be3563ae3f795b2b4353bcce3a527ad0a4f7f644"); test_object("refs/heads/master@{u}", "be3563ae3f795b2b4353bcce3a527ad0a4f7f644"); } void test_refs_revparse__ordinal(void) { assert_invalid_single_spec("master@{-2}"); /* TODO: make the test below actually fail * cl_git_fail(git_revparse_single(&g_obj, g_repo, "master@{1a}")); */ test_object("nope@{0}", NULL); test_object("master@{31415}", NULL); test_object("@{1000}", NULL); test_object("@{2}", NULL); test_object("@{0}", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750"); test_object("@{1}", "be3563ae3f795b2b4353bcce3a527ad0a4f7f644"); test_object("master@{0}", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750"); test_object("master@{1}", "be3563ae3f795b2b4353bcce3a527ad0a4f7f644"); test_object("heads/master@{1}", "be3563ae3f795b2b4353bcce3a527ad0a4f7f644"); test_object("refs/heads/master@{1}", "be3563ae3f795b2b4353bcce3a527ad0a4f7f644"); } void test_refs_revparse__previous_head(void) { assert_invalid_single_spec("@{-xyz}"); assert_invalid_single_spec("@{-0}"); assert_invalid_single_spec("@{-1b}"); test_object("@{-42}", NULL); test_object("@{-2}", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750"); test_object("@{-1}", "a4a7dce85cf63874e984719f4fdd239f5145052f"); } static void create_fake_stash_reference_and_reflog(git_repository *repo) { git_reference *master, *new_master; git_buf log_path = GIT_BUF_INIT; git_buf_joinpath(&log_path, git_repository_path(repo), "logs/refs/fakestash"); cl_assert_equal_i(false, git_path_isfile(git_buf_cstr(&log_path))); cl_git_pass(git_reference_lookup(&master, repo, "refs/heads/master")); cl_git_pass(git_reference_rename(&new_master, master, "refs/fakestash", 0)); git_reference_free(master); cl_assert_equal_i(true, git_path_isfile(git_buf_cstr(&log_path))); git_buf_free(&log_path); git_reference_free(new_master); } void test_refs_revparse__reflog_of_a_ref_under_refs(void) { git_repository *repo = cl_git_sandbox_init("testrepo.git"); test_object_inrepo("refs/fakestash", NULL, repo); create_fake_stash_reference_and_reflog(repo); /* * $ git reflog -1 refs/fakestash * a65fedf refs/fakestash@{0}: commit: checking in * * $ git reflog -1 refs/fakestash@{0} * a65fedf refs/fakestash@{0}: commit: checking in * * $ git reflog -1 fakestash * a65fedf fakestash@{0}: commit: checking in * * $ git reflog -1 fakestash@{0} * a65fedf fakestash@{0}: commit: checking in */ test_object_inrepo("refs/fakestash", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750", repo); test_object_inrepo("refs/fakestash@{0}", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750", repo); test_object_inrepo("fakestash", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750", repo); test_object_inrepo("fakestash@{0}", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750", repo); cl_git_sandbox_cleanup(); } void test_refs_revparse__revwalk(void) { test_object("master^{/not found in any commit}", NULL); test_object("master^{/merge}", NULL); assert_invalid_single_spec("master^{/((}"); test_object("master^{/anoth}", "5b5b025afb0b4c913b4c338a42934a3863bf3644"); test_object("master^{/Merge}", "be3563ae3f795b2b4353bcce3a527ad0a4f7f644"); test_object("br2^{/Merge}", "a4a7dce85cf63874e984719f4fdd239f5145052f"); test_object("master^{/fo.rth}", "9fd738e8f7967c078dceed8190330fc8648ee56a"); } void test_refs_revparse__date(void) { /* * $ git reflog HEAD --date=iso * a65fedf HEAD@{2012-04-30 08:23:41 -0900}: checkout: moving from br2 to master * a4a7dce HEAD@{2012-04-30 08:23:37 -0900}: commit: checking in * c47800c HEAD@{2012-04-30 08:23:28 -0900}: checkout: moving from master to br2 * a65fedf HEAD@{2012-04-30 08:23:23 -0900}: commit: * be3563a HEAD@{2012-04-30 10:22:43 -0700}: clone: from /Users/ben/src/libgit2/tes * * $ git reflog HEAD --date=raw * a65fedf HEAD@{1335806621 -0900}: checkout: moving from br2 to master * a4a7dce HEAD@{1335806617 -0900}: commit: checking in * c47800c HEAD@{1335806608 -0900}: checkout: moving from master to br2 * a65fedf HEAD@{1335806603 -0900}: commit: * be3563a HEAD@{1335806563 -0700}: clone: from /Users/ben/src/libgit2/tests/resour */ test_object("HEAD@{10 years ago}", NULL); test_object("HEAD@{1 second}", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750"); test_object("HEAD@{1 second ago}", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750"); test_object("HEAD@{2 days ago}", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750"); /* * $ git reflog master --date=iso * a65fedf master@{2012-04-30 09:23:23 -0800}: commit: checking in * be3563a master@{2012-04-30 09:22:43 -0800}: clone: from /Users/ben/src... * * $ git reflog master --date=raw * a65fedf master@{1335806603 -0800}: commit: checking in * be3563a master@{1335806563 -0800}: clone: from /Users/ben/src/libgit2/tests/reso */ /* * $ git reflog -1 "master@{2012-04-30 17:22:42 +0000}" * warning: Log for 'master' only goes back to Mon, 30 Apr 2012 09:22:43 -0800. */ test_object("master@{2012-04-30 17:22:42 +0000}", NULL); test_object("master@{2012-04-30 09:22:42 -0800}", NULL); /* * $ git reflog -1 "master@{2012-04-30 17:22:43 +0000}" * be3563a master@{Mon Apr 30 09:22:43 2012 -0800}: clone: from /Users/ben/src/libg */ test_object("master@{2012-04-30 17:22:43 +0000}", "be3563ae3f795b2b4353bcce3a527ad0a4f7f644"); test_object("master@{2012-04-30 09:22:43 -0800}", "be3563ae3f795b2b4353bcce3a527ad0a4f7f644"); /* * $ git reflog -1 "master@{2012-4-30 09:23:27 -0800}" * a65fedf master@{Mon Apr 30 09:23:23 2012 -0800}: commit: checking in */ test_object("master@{2012-4-30 09:23:27 -0800}", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750"); /* * $ git reflog -1 master@{2012-05-03} * a65fedf master@{Mon Apr 30 09:23:23 2012 -0800}: commit: checking in */ test_object("master@{2012-05-03}", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750"); /* * $ git reflog -1 "master@{1335806603}" * a65fedf * * $ git reflog -1 "master@{1335806602}" * be3563a */ test_object("master@{1335806603}", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750"); test_object("master@{1335806602}", "be3563ae3f795b2b4353bcce3a527ad0a4f7f644"); } void test_refs_revparse__colon(void) { assert_invalid_single_spec(":/"); assert_invalid_single_spec("point_to_blob:readme.txt"); cl_git_fail(git_revparse_single(&g_obj, g_repo, ":2:README")); /* Not implemented */ test_object(":/not found in any commit", NULL); test_object("subtrees:ab/42.txt", NULL); test_object("subtrees:ab/4.txt/nope", NULL); test_object("subtrees:nope", NULL); test_object("test/master^1:branch_file.txt", NULL); /* From tags */ test_object("test:readme.txt", "0266163a49e280c4f5ed1e08facd36a2bd716bcf"); test_object("tags/test:readme.txt", "0266163a49e280c4f5ed1e08facd36a2bd716bcf"); test_object("e90810b:readme.txt", "0266163a49e280c4f5ed1e08facd36a2bd716bcf"); test_object("tags/e90810b:readme.txt", "0266163a49e280c4f5ed1e08facd36a2bd716bcf"); /* From commits */ test_object("a65f:branch_file.txt", "3697d64be941a53d4ae8f6a271e4e3fa56b022cc"); /* From trees */ test_object("a65f^{tree}:branch_file.txt", "3697d64be941a53d4ae8f6a271e4e3fa56b022cc"); test_object("944c:branch_file.txt", "3697d64be941a53d4ae8f6a271e4e3fa56b022cc"); /* Retrieving trees */ test_object("master:", "944c0f6e4dfa41595e6eb3ceecdb14f50fe18162"); test_object("subtrees:", "ae90f12eea699729ed24555e40b9fd669da12a12"); test_object("subtrees:ab", "f1425cef211cc08caa31e7b545ffb232acb098c3"); test_object("subtrees:ab/", "f1425cef211cc08caa31e7b545ffb232acb098c3"); /* Retrieving blobs */ test_object("subtrees:ab/4.txt", "d6c93164c249c8000205dd4ec5cbca1b516d487f"); test_object("subtrees:ab/de/fgh/1.txt", "1f67fc4386b2d171e0d21be1c447e12660561f9b"); test_object("master:README", "a8233120f6ad708f843d861ce2b7228ec4e3dec6"); test_object("master:new.txt", "a71586c1dfe8a71c6cbf6c129f404c5642ff31bd"); test_object(":/Merge", "a4a7dce85cf63874e984719f4fdd239f5145052f"); test_object(":/one", "c47800c7266a2be04c571c04d5a6614691ea99bd"); test_object(":/packed commit t", "41bc8c69075bbdb46c5c6f0566cc8cc5b46e8bd9"); test_object("test/master^2:branch_file.txt", "45b983be36b73c0788dc9cbcb76cbb80fc7bb057"); test_object("test/master@{1}:branch_file.txt", "3697d64be941a53d4ae8f6a271e4e3fa56b022cc"); } void test_refs_revparse__disambiguation(void) { /* * $ git show e90810b * tag e90810b * Tagger: Vicent Marti * Date: Thu Aug 12 03:59:17 2010 +0200 * * This is a very simple tag. * * commit e90810b8df3e80c413d903f631643c716887138d * Author: Vicent Marti * Date: Thu Aug 5 18:42:20 2010 +0200 * * Test commit 2 * * diff --git a/readme.txt b/readme.txt * index 6336846..0266163 100644 * --- a/readme.txt * +++ b/readme.txt * @@ -1 +1,2 @@ * Testing a readme.txt * +Now we add a single line here * * $ git show-ref e90810b * 7b4384978d2493e851f9cca7858815fac9b10980 refs/tags/e90810b * */ test_object("e90810b", "7b4384978d2493e851f9cca7858815fac9b10980"); /* * $ git show e90810 * commit e90810b8df3e80c413d903f631643c716887138d * Author: Vicent Marti * Date: Thu Aug 5 18:42:20 2010 +0200 * * Test commit 2 * * diff --git a/readme.txt b/readme.txt * index 6336846..0266163 100644 * --- a/readme.txt * +++ b/readme.txt * @@ -1 +1,2 @@ * Testing a readme.txt * +Now we add a single line here */ test_object("e90810", "e90810b8df3e80c413d903f631643c716887138d"); } void test_refs_revparse__a_too_short_objectid_returns_EAMBIGUOUS(void) { cl_assert_equal_i( GIT_EAMBIGUOUS, git_revparse_single(&g_obj, g_repo, "e90")); } void test_refs_revparse__issue_994(void) { git_repository *repo; git_reference *head, *with_at; git_object *target; repo = cl_git_sandbox_init("testrepo.git"); cl_assert_equal_i(GIT_ENOTFOUND, git_revparse_single(&target, repo, "origin/bim_with_3d@11296")); cl_assert_equal_i(GIT_ENOTFOUND, git_revparse_single(&target, repo, "refs/remotes/origin/bim_with_3d@11296")); cl_git_pass(git_repository_head(&head, repo)); cl_git_pass(git_reference_create( &with_at, repo, "refs/remotes/origin/bim_with_3d@11296", git_reference_target(head), 0)); cl_git_pass(git_revparse_single(&target, repo, "origin/bim_with_3d@11296")); git_object_free(target); cl_git_pass(git_revparse_single(&target, repo, "refs/remotes/origin/bim_with_3d@11296")); git_object_free(target); git_reference_free(with_at); git_reference_free(head); cl_git_sandbox_cleanup(); } /** * $ git rev-parse blah-7-gc47800c * c47800c7266a2be04c571c04d5a6614691ea99bd * * $ git rev-parse HEAD~3 * 4a202b346bb0fb0db7eff3cffeb3c70babbd2045 * * $ git branch blah-7-gc47800c HEAD~3 * * $ git rev-parse blah-7-gc47800c * 4a202b346bb0fb0db7eff3cffeb3c70babbd2045 */ void test_refs_revparse__try_to_retrieve_branch_before_described_tag(void) { git_repository *repo; git_reference *branch; git_object *target; char sha[GIT_OID_HEXSZ + 1]; repo = cl_git_sandbox_init("testrepo.git"); test_object_inrepo("blah-7-gc47800c", "c47800c7266a2be04c571c04d5a6614691ea99bd", repo); cl_git_pass(git_revparse_single(&target, repo, "HEAD~3")); cl_git_pass(git_branch_create(&branch, repo, "blah-7-gc47800c", (git_commit *)target, 0)); git_oid_tostr(sha, GIT_OID_HEXSZ + 1, git_object_id(target)); test_object_inrepo("blah-7-gc47800c", sha, repo); git_reference_free(branch); git_object_free(target); cl_git_sandbox_cleanup(); } /** * $ git rev-parse a65fedf39aefe402d3bb6e24df4d4f5fe4547750 * a65fedf39aefe402d3bb6e24df4d4f5fe4547750 * * $ git rev-parse HEAD~3 * 4a202b346bb0fb0db7eff3cffeb3c70babbd2045 * * $ git branch a65fedf39aefe402d3bb6e24df4d4f5fe4547750 HEAD~3 * * $ git rev-parse a65fedf39aefe402d3bb6e24df4d4f5fe4547750 * a65fedf39aefe402d3bb6e24df4d4f5fe4547750 * * $ git rev-parse heads/a65fedf39aefe402d3bb6e24df4d4f5fe4547750 * 4a202b346bb0fb0db7eff3cffeb3c70babbd2045 */ void test_refs_revparse__try_to_retrieve_sha_before_branch(void) { git_repository *repo; git_reference *branch; git_object *target; char sha[GIT_OID_HEXSZ + 1]; repo = cl_git_sandbox_init("testrepo.git"); test_object_inrepo("a65fedf39aefe402d3bb6e24df4d4f5fe4547750", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750", repo); cl_git_pass(git_revparse_single(&target, repo, "HEAD~3")); cl_git_pass(git_branch_create(&branch, repo, "a65fedf39aefe402d3bb6e24df4d4f5fe4547750", (git_commit *)target, 0)); git_oid_tostr(sha, GIT_OID_HEXSZ + 1, git_object_id(target)); test_object_inrepo("a65fedf39aefe402d3bb6e24df4d4f5fe4547750", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750", repo); test_object_inrepo("heads/a65fedf39aefe402d3bb6e24df4d4f5fe4547750", sha, repo); git_reference_free(branch); git_object_free(target); cl_git_sandbox_cleanup(); } /** * $ git rev-parse c47800 * c47800c7266a2be04c571c04d5a6614691ea99bd * * $ git rev-parse HEAD~3 * 4a202b346bb0fb0db7eff3cffeb3c70babbd2045 * * $ git branch c47800 HEAD~3 * * $ git rev-parse c47800 * 4a202b346bb0fb0db7eff3cffeb3c70babbd2045 */ void test_refs_revparse__try_to_retrieve_branch_before_abbrev_sha(void) { git_repository *repo; git_reference *branch; git_object *target; char sha[GIT_OID_HEXSZ + 1]; repo = cl_git_sandbox_init("testrepo.git"); test_object_inrepo("c47800", "c47800c7266a2be04c571c04d5a6614691ea99bd", repo); cl_git_pass(git_revparse_single(&target, repo, "HEAD~3")); cl_git_pass(git_branch_create(&branch, repo, "c47800", (git_commit *)target, 0)); git_oid_tostr(sha, GIT_OID_HEXSZ + 1, git_object_id(target)); test_object_inrepo("c47800", sha, repo); git_reference_free(branch); git_object_free(target); cl_git_sandbox_cleanup(); } void test_refs_revparse__range(void) { assert_invalid_single_spec("be3563a^1..be3563a"); test_rangelike("be3563a^1..be3563a", "9fd738e8f7967c078dceed8190330fc8648ee56a", "be3563ae3f795b2b4353bcce3a527ad0a4f7f644", GIT_REVPARSE_RANGE); test_rangelike("be3563a^1...be3563a", "9fd738e8f7967c078dceed8190330fc8648ee56a", "be3563ae3f795b2b4353bcce3a527ad0a4f7f644", GIT_REVPARSE_RANGE | GIT_REVPARSE_MERGE_BASE); test_rangelike("be3563a^1.be3563a", NULL, NULL, 0); } void test_refs_revparse__parses_range_operator(void) { test_id("HEAD", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750", NULL, GIT_REVPARSE_SINGLE); test_id("HEAD~3..HEAD", "4a202b346bb0fb0db7eff3cffeb3c70babbd2045", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750", GIT_REVPARSE_RANGE); test_id("HEAD~3...HEAD", "4a202b346bb0fb0db7eff3cffeb3c70babbd2045", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750", GIT_REVPARSE_RANGE | GIT_REVPARSE_MERGE_BASE); } void test_refs_revparse__ext_retrieves_both_the_reference_and_its_target(void) { test_object_and_ref( "master@{upstream}", "be3563ae3f795b2b4353bcce3a527ad0a4f7f644", "refs/remotes/test/master"); test_object_and_ref( "@{-1}", "a4a7dce85cf63874e984719f4fdd239f5145052f", "refs/heads/br2"); } void test_refs_revparse__ext_can_expand_short_reference_names(void) { test_object_and_ref( "master", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750", "refs/heads/master"); } libgit2-0.19.0/tests-clar/refs/setter.c000066400000000000000000000055721216214232500176360ustar00rootroot00000000000000#include "clar_libgit2.h" #include "repository.h" #include "git2/reflog.h" #include "reflog.h" #include "git2/refs.h" static const char *ref_name = "refs/heads/other"; static const char *ref_master_name = "refs/heads/master"; static const char *ref_test_name = "refs/heads/test"; static git_repository *g_repo; void test_refs_setter__initialize(void) { g_repo = cl_git_sandbox_init("testrepo"); } void test_refs_setter__cleanup(void) { cl_git_sandbox_cleanup(); } void test_refs_setter__update_direct(void) { git_reference *ref, *test_ref, *new_ref; git_oid id; cl_git_pass(git_reference_lookup(&ref, g_repo, ref_master_name)); cl_assert(git_reference_type(ref) == GIT_REF_OID); git_oid_cpy(&id, git_reference_target(ref)); git_reference_free(ref); cl_git_pass(git_reference_lookup(&test_ref, g_repo, ref_test_name)); cl_assert(git_reference_type(test_ref) == GIT_REF_OID); cl_git_pass(git_reference_set_target(&new_ref, test_ref, &id)); git_reference_free(test_ref); git_reference_free(new_ref); cl_git_pass(git_reference_lookup(&test_ref, g_repo, ref_test_name)); cl_assert(git_reference_type(test_ref) == GIT_REF_OID); cl_assert(git_oid_cmp(&id, git_reference_target(test_ref)) == 0); git_reference_free(test_ref); } void test_refs_setter__update_symbolic(void) { git_reference *head, *new_head; cl_git_pass(git_reference_lookup(&head, g_repo, "HEAD")); cl_assert(git_reference_type(head) == GIT_REF_SYMBOLIC); cl_assert(strcmp(git_reference_symbolic_target(head), ref_master_name) == 0); cl_git_pass(git_reference_symbolic_set_target(&new_head, head, ref_test_name)); git_reference_free(new_head); git_reference_free(head); cl_git_pass(git_reference_lookup(&head, g_repo, "HEAD")); cl_assert(git_reference_type(head) == GIT_REF_SYMBOLIC); cl_assert(strcmp(git_reference_symbolic_target(head), ref_test_name) == 0); git_reference_free(head); } void test_refs_setter__cant_update_direct_with_symbolic(void) { // Overwrite an existing object id reference with a symbolic one git_reference *ref, *new; git_oid id; cl_git_pass(git_reference_lookup(&ref, g_repo, ref_master_name)); cl_assert(git_reference_type(ref) == GIT_REF_OID); git_oid_cpy(&id, git_reference_target(ref)); cl_git_fail(git_reference_symbolic_set_target(&new, ref, ref_name)); git_reference_free(ref); } void test_refs_setter__cant_update_symbolic_with_direct(void) { // Overwrite an existing symbolic reference with an object id one git_reference *ref, *new; git_oid id; cl_git_pass(git_reference_lookup(&ref, g_repo, ref_master_name)); cl_assert(git_reference_type(ref) == GIT_REF_OID); git_oid_cpy(&id, git_reference_target(ref)); git_reference_free(ref); /* Create the symbolic ref */ cl_git_pass(git_reference_symbolic_create(&ref, g_repo, ref_name, ref_master_name, 0)); /* Can't set an OID on a direct ref */ cl_git_fail(git_reference_set_target(&new, ref, &id)); git_reference_free(ref); } libgit2-0.19.0/tests-clar/refs/shorthand.c000066400000000000000000000013071216214232500203120ustar00rootroot00000000000000#include "clar_libgit2.h" #include "repository.h" void assert_shorthand(git_repository *repo, const char *refname, const char *shorthand) { git_reference *ref; cl_git_pass(git_reference_lookup(&ref, repo, refname)); cl_assert_equal_s(git_reference_shorthand(ref), shorthand); git_reference_free(ref); } void test_refs_shorthand__0(void) { git_repository *repo; cl_git_pass(git_repository_open(&repo, cl_fixture("testrepo.git"))); assert_shorthand(repo, "refs/heads/master", "master"); assert_shorthand(repo, "refs/tags/test", "test"); assert_shorthand(repo, "refs/remotes/test/master", "test/master"); assert_shorthand(repo, "refs/notes/fanout", "notes/fanout"); git_repository_free(repo); } libgit2-0.19.0/tests-clar/refs/unicode.c000066400000000000000000000022761216214232500177540ustar00rootroot00000000000000#include "clar_libgit2.h" static git_repository *repo; void test_refs_unicode__initialize(void) { cl_fixture_sandbox("testrepo.git"); cl_git_pass(git_repository_open(&repo, "testrepo.git")); } void test_refs_unicode__cleanup(void) { git_repository_free(repo); repo = NULL; cl_fixture_cleanup("testrepo.git"); } void test_refs_unicode__create_and_lookup(void) { git_reference *ref0, *ref1, *ref2; git_repository *repo2; const char *REFNAME = "refs/heads/" "\305" "ngstr" "\366" "m"; const char *master = "refs/heads/master"; /* Create the reference */ cl_git_pass(git_reference_lookup(&ref0, repo, master)); cl_git_pass(git_reference_create(&ref1, repo, REFNAME, git_reference_target(ref0), 0)); cl_assert_equal_s(REFNAME, git_reference_name(ref1)); /* Lookup the reference in a different instance of the repository */ cl_git_pass(git_repository_open(&repo2, "testrepo.git")); cl_git_pass(git_reference_lookup(&ref2, repo2, REFNAME)); cl_assert(git_oid_cmp(git_reference_target(ref1), git_reference_target(ref2)) == 0); cl_assert_equal_s(REFNAME, git_reference_name(ref2)); git_reference_free(ref0); git_reference_free(ref1); git_reference_free(ref2); git_repository_free(repo2); } libgit2-0.19.0/tests-clar/refs/update.c000066400000000000000000000012171216214232500176020ustar00rootroot00000000000000#include "clar_libgit2.h" #include "refs.h" static git_repository *g_repo; void test_refs_update__initialize(void) { g_repo = cl_git_sandbox_init("testrepo.git"); } void test_refs_update__cleanup(void) { cl_git_sandbox_cleanup(); } void test_refs_update__updating_the_target_of_a_symref_with_an_invalid_name_returns_EINVALIDSPEC(void) { git_reference *head; cl_git_pass(git_reference_lookup(&head, g_repo, GIT_HEAD_FILE)); cl_assert_equal_i(GIT_REF_SYMBOLIC, git_reference_type(head)); git_reference_free(head); cl_assert_equal_i(GIT_EINVALIDSPEC, git_reference_symbolic_create(&head, g_repo, GIT_HEAD_FILE, "refs/heads/inv@{id", 1)); } libgit2-0.19.0/tests-clar/repo/000077500000000000000000000000001216214232500161615ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/repo/config.c000066400000000000000000000143011216214232500175710ustar00rootroot00000000000000#include "clar_libgit2.h" #include "fileops.h" #include git_buf path = GIT_BUF_INIT; void test_repo_config__initialize(void) { cl_fixture_sandbox("empty_standard_repo"); cl_git_pass(cl_rename("empty_standard_repo/.gitted", "empty_standard_repo/.git")); git_buf_clear(&path); cl_must_pass(p_mkdir("alternate", 0777)); cl_git_pass(git_path_prettify(&path, "alternate", NULL)); } void test_repo_config__cleanup(void) { cl_git_pass(git_path_prettify(&path, "alternate", NULL)); cl_git_pass(git_futils_rmdir_r(path.ptr, NULL, GIT_RMDIR_REMOVE_FILES)); git_buf_free(&path); cl_assert(!git_path_isdir("alternate")); cl_fixture_cleanup("empty_standard_repo"); } void test_repo_config__open_missing_global(void) { git_repository *repo; git_config *config, *global; cl_git_pass(git_libgit2_opts( GIT_OPT_SET_SEARCH_PATH, GIT_CONFIG_LEVEL_GLOBAL, path.ptr)); cl_git_pass(git_libgit2_opts( GIT_OPT_SET_SEARCH_PATH, GIT_CONFIG_LEVEL_SYSTEM, path.ptr)); cl_git_pass(git_libgit2_opts( GIT_OPT_SET_SEARCH_PATH, GIT_CONFIG_LEVEL_XDG, path.ptr)); cl_git_pass(git_repository_open(&repo, "empty_standard_repo")); cl_git_pass(git_repository_config(&config, repo)); cl_git_pass(git_config_open_level(&global, config, GIT_CONFIG_LEVEL_GLOBAL)); cl_git_pass(git_config_set_string(global, "test.set", "42")); git_config_free(global); git_config_free(config); git_repository_free(repo); } void test_repo_config__open_missing_global_with_separators(void) { git_repository *repo; git_config *config, *global; cl_git_pass(git_buf_printf(&path, "%c%s", GIT_PATH_LIST_SEPARATOR, "dummy")); cl_git_pass(git_libgit2_opts( GIT_OPT_SET_SEARCH_PATH, GIT_CONFIG_LEVEL_GLOBAL, path.ptr)); cl_git_pass(git_libgit2_opts( GIT_OPT_SET_SEARCH_PATH, GIT_CONFIG_LEVEL_SYSTEM, path.ptr)); cl_git_pass(git_libgit2_opts( GIT_OPT_SET_SEARCH_PATH, GIT_CONFIG_LEVEL_XDG, path.ptr)); git_buf_free(&path); cl_git_pass(git_repository_open(&repo, "empty_standard_repo")); cl_git_pass(git_repository_config(&config, repo)); cl_git_pass(git_config_open_level(&global, config, GIT_CONFIG_LEVEL_GLOBAL)); cl_git_pass(git_config_set_string(global, "test.set", "42")); git_config_free(global); git_config_free(config); git_repository_free(repo); } #include "repository.h" void test_repo_config__read_no_configs(void) { git_repository *repo; int val; cl_git_pass(git_libgit2_opts( GIT_OPT_SET_SEARCH_PATH, GIT_CONFIG_LEVEL_GLOBAL, path.ptr)); cl_git_pass(git_libgit2_opts( GIT_OPT_SET_SEARCH_PATH, GIT_CONFIG_LEVEL_SYSTEM, path.ptr)); cl_git_pass(git_libgit2_opts( GIT_OPT_SET_SEARCH_PATH, GIT_CONFIG_LEVEL_XDG, path.ptr)); /* with none */ cl_must_pass(p_unlink("empty_standard_repo/.git/config")); cl_assert(!git_path_isfile("empty_standard_repo/.git/config")); cl_git_pass(git_repository_open(&repo, "empty_standard_repo")); git_repository__cvar_cache_clear(repo); val = -1; cl_git_pass(git_repository__cvar(&val, repo, GIT_CVAR_ABBREV)); cl_assert_equal_i(GIT_ABBREV_DEFAULT, val); git_repository_free(repo); /* with just system */ cl_must_pass(p_mkdir("alternate/1", 0777)); cl_git_pass(git_buf_joinpath(&path, path.ptr, "1")); cl_git_rewritefile("alternate/1/gitconfig", "[core]\n\tabbrev = 10\n"); cl_git_pass(git_libgit2_opts( GIT_OPT_SET_SEARCH_PATH, GIT_CONFIG_LEVEL_SYSTEM, path.ptr)); cl_git_pass(git_repository_open(&repo, "empty_standard_repo")); git_repository__cvar_cache_clear(repo); val = -1; cl_git_pass(git_repository__cvar(&val, repo, GIT_CVAR_ABBREV)); cl_assert_equal_i(10, val); git_repository_free(repo); /* with xdg + system */ cl_must_pass(p_mkdir("alternate/2", 0777)); path.ptr[path.size - 1] = '2'; cl_git_rewritefile("alternate/2/config", "[core]\n\tabbrev = 20\n"); cl_git_pass(git_libgit2_opts( GIT_OPT_SET_SEARCH_PATH, GIT_CONFIG_LEVEL_XDG, path.ptr)); cl_git_pass(git_repository_open(&repo, "empty_standard_repo")); git_repository__cvar_cache_clear(repo); val = -1; cl_git_pass(git_repository__cvar(&val, repo, GIT_CVAR_ABBREV)); cl_assert_equal_i(20, val); git_repository_free(repo); /* with global + xdg + system */ cl_must_pass(p_mkdir("alternate/3", 0777)); path.ptr[path.size - 1] = '3'; cl_git_rewritefile("alternate/3/.gitconfig", "[core]\n\tabbrev = 30\n"); cl_git_pass(git_libgit2_opts( GIT_OPT_SET_SEARCH_PATH, GIT_CONFIG_LEVEL_GLOBAL, path.ptr)); cl_git_pass(git_repository_open(&repo, "empty_standard_repo")); git_repository__cvar_cache_clear(repo); val = -1; cl_git_pass(git_repository__cvar(&val, repo, GIT_CVAR_ABBREV)); cl_assert_equal_i(30, val); git_repository_free(repo); /* with all configs */ cl_git_rewritefile("empty_standard_repo/.git/config", "[core]\n\tabbrev = 40\n"); cl_git_pass(git_repository_open(&repo, "empty_standard_repo")); git_repository__cvar_cache_clear(repo); val = -1; cl_git_pass(git_repository__cvar(&val, repo, GIT_CVAR_ABBREV)); cl_assert_equal_i(40, val); git_repository_free(repo); /* with all configs but delete the files ? */ cl_git_pass(git_repository_open(&repo, "empty_standard_repo")); git_repository__cvar_cache_clear(repo); val = -1; cl_git_pass(git_repository__cvar(&val, repo, GIT_CVAR_ABBREV)); cl_assert_equal_i(40, val); cl_must_pass(p_unlink("empty_standard_repo/.git/config")); cl_assert(!git_path_isfile("empty_standard_repo/.git/config")); cl_must_pass(p_unlink("alternate/1/gitconfig")); cl_assert(!git_path_isfile("alternate/1/gitconfig")); cl_must_pass(p_unlink("alternate/2/config")); cl_assert(!git_path_isfile("alternate/2/config")); cl_must_pass(p_unlink("alternate/3/.gitconfig")); cl_assert(!git_path_isfile("alternate/3/.gitconfig")); git_repository__cvar_cache_clear(repo); val = -1; cl_git_pass(git_repository__cvar(&val, repo, GIT_CVAR_ABBREV)); cl_assert_equal_i(40, val); git_repository_free(repo); /* reopen */ cl_assert(!git_path_isfile("empty_standard_repo/.git/config")); cl_assert(!git_path_isfile("alternate/3/.gitconfig")); cl_git_pass(git_repository_open(&repo, "empty_standard_repo")); git_repository__cvar_cache_clear(repo); val = -1; cl_git_pass(git_repository__cvar(&val, repo, GIT_CVAR_ABBREV)); cl_assert_equal_i(7, val); git_repository_free(repo); cl_assert(!git_path_exists("empty_standard_repo/.git/config")); cl_assert(!git_path_exists("alternate/3/.gitconfig")); } libgit2-0.19.0/tests-clar/repo/discover.c000066400000000000000000000160371216214232500201520ustar00rootroot00000000000000#include "clar_libgit2.h" #include "odb.h" #include "fileops.h" #include "repository.h" #define TEMP_REPO_FOLDER "temprepo/" #define DISCOVER_FOLDER TEMP_REPO_FOLDER "discover.git" #define SUB_REPOSITORY_FOLDER_NAME "sub_repo" #define SUB_REPOSITORY_FOLDER DISCOVER_FOLDER "/" SUB_REPOSITORY_FOLDER_NAME #define SUB_REPOSITORY_FOLDER_SUB SUB_REPOSITORY_FOLDER "/sub" #define SUB_REPOSITORY_FOLDER_SUB_SUB SUB_REPOSITORY_FOLDER_SUB "/subsub" #define SUB_REPOSITORY_FOLDER_SUB_SUB_SUB SUB_REPOSITORY_FOLDER_SUB_SUB "/subsubsub" #define REPOSITORY_ALTERNATE_FOLDER DISCOVER_FOLDER "/alternate_sub_repo" #define REPOSITORY_ALTERNATE_FOLDER_SUB REPOSITORY_ALTERNATE_FOLDER "/sub" #define REPOSITORY_ALTERNATE_FOLDER_SUB_SUB REPOSITORY_ALTERNATE_FOLDER_SUB "/subsub" #define REPOSITORY_ALTERNATE_FOLDER_SUB_SUB_SUB REPOSITORY_ALTERNATE_FOLDER_SUB_SUB "/subsubsub" #define ALTERNATE_MALFORMED_FOLDER1 DISCOVER_FOLDER "/alternate_malformed_repo1" #define ALTERNATE_MALFORMED_FOLDER2 DISCOVER_FOLDER "/alternate_malformed_repo2" #define ALTERNATE_MALFORMED_FOLDER3 DISCOVER_FOLDER "/alternate_malformed_repo3" #define ALTERNATE_NOT_FOUND_FOLDER DISCOVER_FOLDER "/alternate_not_found_repo" static void ensure_repository_discover(const char *start_path, const char *ceiling_dirs, const char *expected_path) { char found_path[GIT_PATH_MAX]; cl_git_pass(git_repository_discover(found_path, sizeof(found_path), start_path, 0, ceiling_dirs)); //across_fs is always 0 as we can't automate the filesystem change tests cl_assert_equal_s(found_path, expected_path); } static void write_file(const char *path, const char *content) { git_file file; int error; if (git_path_exists(path)) { cl_git_pass(p_unlink(path)); } file = git_futils_creat_withpath(path, 0777, 0666); cl_assert(file >= 0); error = p_write(file, content, strlen(content) * sizeof(char)); p_close(file); cl_git_pass(error); } //no check is performed on ceiling_dirs length, so be sure it's long enough static void append_ceiling_dir(git_buf *ceiling_dirs, const char *path) { git_buf pretty_path = GIT_BUF_INIT; char ceiling_separator[2] = { GIT_PATH_LIST_SEPARATOR, '\0' }; cl_git_pass(git_path_prettify_dir(&pretty_path, path, NULL)); if (ceiling_dirs->size > 0) git_buf_puts(ceiling_dirs, ceiling_separator); git_buf_puts(ceiling_dirs, pretty_path.ptr); git_buf_free(&pretty_path); cl_assert(git_buf_oom(ceiling_dirs) == 0); } void test_repo_discover__0(void) { // test discover git_repository *repo; git_buf ceiling_dirs_buf = GIT_BUF_INIT; const char *ceiling_dirs; char repository_path[GIT_PATH_MAX]; char sub_repository_path[GIT_PATH_MAX]; char found_path[GIT_PATH_MAX]; const mode_t mode = 0777; git_futils_mkdir_r(DISCOVER_FOLDER, NULL, mode); append_ceiling_dir(&ceiling_dirs_buf, TEMP_REPO_FOLDER); ceiling_dirs = git_buf_cstr(&ceiling_dirs_buf); cl_assert_equal_i(GIT_ENOTFOUND, git_repository_discover(repository_path, sizeof(repository_path), DISCOVER_FOLDER, 0, ceiling_dirs)); cl_git_pass(git_repository_init(&repo, DISCOVER_FOLDER, 1)); cl_git_pass(git_repository_discover(repository_path, sizeof(repository_path), DISCOVER_FOLDER, 0, ceiling_dirs)); git_repository_free(repo); cl_git_pass(git_repository_init(&repo, SUB_REPOSITORY_FOLDER, 0)); cl_git_pass(git_futils_mkdir_r(SUB_REPOSITORY_FOLDER_SUB_SUB_SUB, NULL, mode)); cl_git_pass(git_repository_discover(sub_repository_path, sizeof(sub_repository_path), SUB_REPOSITORY_FOLDER, 0, ceiling_dirs)); cl_git_pass(git_futils_mkdir_r(SUB_REPOSITORY_FOLDER_SUB_SUB_SUB, NULL, mode)); ensure_repository_discover(SUB_REPOSITORY_FOLDER_SUB, ceiling_dirs, sub_repository_path); ensure_repository_discover(SUB_REPOSITORY_FOLDER_SUB_SUB, ceiling_dirs, sub_repository_path); ensure_repository_discover(SUB_REPOSITORY_FOLDER_SUB_SUB_SUB, ceiling_dirs, sub_repository_path); cl_git_pass(git_futils_mkdir_r(REPOSITORY_ALTERNATE_FOLDER_SUB_SUB_SUB, NULL, mode)); write_file(REPOSITORY_ALTERNATE_FOLDER "/" DOT_GIT, "gitdir: ../" SUB_REPOSITORY_FOLDER_NAME "/" DOT_GIT); write_file(REPOSITORY_ALTERNATE_FOLDER_SUB_SUB "/" DOT_GIT, "gitdir: ../../../" SUB_REPOSITORY_FOLDER_NAME "/" DOT_GIT); write_file(REPOSITORY_ALTERNATE_FOLDER_SUB_SUB_SUB "/" DOT_GIT, "gitdir: ../../../../"); ensure_repository_discover(REPOSITORY_ALTERNATE_FOLDER, ceiling_dirs, sub_repository_path); ensure_repository_discover(REPOSITORY_ALTERNATE_FOLDER_SUB, ceiling_dirs, sub_repository_path); ensure_repository_discover(REPOSITORY_ALTERNATE_FOLDER_SUB_SUB, ceiling_dirs, sub_repository_path); ensure_repository_discover(REPOSITORY_ALTERNATE_FOLDER_SUB_SUB_SUB, ceiling_dirs, repository_path); cl_git_pass(git_futils_mkdir_r(ALTERNATE_MALFORMED_FOLDER1, NULL, mode)); write_file(ALTERNATE_MALFORMED_FOLDER1 "/" DOT_GIT, "Anything but not gitdir:"); cl_git_pass(git_futils_mkdir_r(ALTERNATE_MALFORMED_FOLDER2, NULL, mode)); write_file(ALTERNATE_MALFORMED_FOLDER2 "/" DOT_GIT, "gitdir:"); cl_git_pass(git_futils_mkdir_r(ALTERNATE_MALFORMED_FOLDER3, NULL, mode)); write_file(ALTERNATE_MALFORMED_FOLDER3 "/" DOT_GIT, "gitdir: \n\n\n"); cl_git_pass(git_futils_mkdir_r(ALTERNATE_NOT_FOUND_FOLDER, NULL, mode)); write_file(ALTERNATE_NOT_FOUND_FOLDER "/" DOT_GIT, "gitdir: a_repository_that_surely_does_not_exist"); cl_git_fail(git_repository_discover(found_path, sizeof(found_path), ALTERNATE_MALFORMED_FOLDER1, 0, ceiling_dirs)); cl_git_fail(git_repository_discover(found_path, sizeof(found_path), ALTERNATE_MALFORMED_FOLDER2, 0, ceiling_dirs)); cl_git_fail(git_repository_discover(found_path, sizeof(found_path), ALTERNATE_MALFORMED_FOLDER3, 0, ceiling_dirs)); cl_assert_equal_i(GIT_ENOTFOUND, git_repository_discover(found_path, sizeof(found_path), ALTERNATE_NOT_FOUND_FOLDER, 0, ceiling_dirs)); append_ceiling_dir(&ceiling_dirs_buf, SUB_REPOSITORY_FOLDER); ceiling_dirs = git_buf_cstr(&ceiling_dirs_buf); //this must pass as ceiling_directories cannot predent the current //working directory to be checked cl_git_pass(git_repository_discover(found_path, sizeof(found_path), SUB_REPOSITORY_FOLDER, 0, ceiling_dirs)); cl_assert_equal_i(GIT_ENOTFOUND, git_repository_discover(found_path, sizeof(found_path), SUB_REPOSITORY_FOLDER_SUB, 0, ceiling_dirs)); cl_assert_equal_i(GIT_ENOTFOUND, git_repository_discover(found_path, sizeof(found_path), SUB_REPOSITORY_FOLDER_SUB_SUB, 0, ceiling_dirs)); cl_assert_equal_i(GIT_ENOTFOUND, git_repository_discover(found_path, sizeof(found_path), SUB_REPOSITORY_FOLDER_SUB_SUB_SUB, 0, ceiling_dirs)); //.gitfile redirection should not be affected by ceiling directories ensure_repository_discover(REPOSITORY_ALTERNATE_FOLDER, ceiling_dirs, sub_repository_path); ensure_repository_discover(REPOSITORY_ALTERNATE_FOLDER_SUB, ceiling_dirs, sub_repository_path); ensure_repository_discover(REPOSITORY_ALTERNATE_FOLDER_SUB_SUB, ceiling_dirs, sub_repository_path); ensure_repository_discover(REPOSITORY_ALTERNATE_FOLDER_SUB_SUB_SUB, ceiling_dirs, repository_path); cl_git_pass(git_futils_rmdir_r(TEMP_REPO_FOLDER, NULL, GIT_RMDIR_REMOVE_FILES)); git_repository_free(repo); git_buf_free(&ceiling_dirs_buf); } libgit2-0.19.0/tests-clar/repo/getters.c000066400000000000000000000017361216214232500200110ustar00rootroot00000000000000#include "clar_libgit2.h" void test_repo_getters__is_empty_correctly_deals_with_pristine_looking_repos(void) { git_repository *repo; repo = cl_git_sandbox_init("empty_bare.git"); cl_git_remove_placeholders(git_repository_path(repo), "dummy-marker.txt"); cl_assert_equal_i(true, git_repository_is_empty(repo)); cl_git_sandbox_cleanup(); } void test_repo_getters__is_empty_can_detect_used_repositories(void) { git_repository *repo; cl_git_pass(git_repository_open(&repo, cl_fixture("testrepo.git"))); cl_assert_equal_i(false, git_repository_is_empty(repo)); git_repository_free(repo); } void test_repo_getters__retrieving_the_odb_honors_the_refcount(void) { git_odb *odb; git_repository *repo; cl_git_pass(git_repository_open(&repo, cl_fixture("testrepo.git"))); cl_git_pass(git_repository_odb(&odb, repo)); cl_assert(((git_refcount *)odb)->refcount.val == 2); git_repository_free(repo); cl_assert(((git_refcount *)odb)->refcount.val == 1); git_odb_free(odb); } libgit2-0.19.0/tests-clar/repo/hashfile.c000066400000000000000000000057471216214232500201250ustar00rootroot00000000000000#include "clar_libgit2.h" #include "buffer.h" static git_repository *_repo; void test_repo_hashfile__initialize(void) { _repo = cl_git_sandbox_init("status"); } void test_repo_hashfile__cleanup(void) { cl_git_sandbox_cleanup(); _repo = NULL; } void test_repo_hashfile__simple(void) { git_oid a, b; git_buf full = GIT_BUF_INIT; /* hash with repo relative path */ cl_git_pass(git_odb_hashfile(&a, "status/current_file", GIT_OBJ_BLOB)); cl_git_pass(git_repository_hashfile(&b, _repo, "current_file", GIT_OBJ_BLOB, NULL)); cl_assert(git_oid_equal(&a, &b)); cl_git_pass(git_buf_joinpath(&full, git_repository_workdir(_repo), "current_file")); /* hash with full path */ cl_git_pass(git_odb_hashfile(&a, full.ptr, GIT_OBJ_BLOB)); cl_git_pass(git_repository_hashfile(&b, _repo, full.ptr, GIT_OBJ_BLOB, NULL)); cl_assert(git_oid_equal(&a, &b)); /* hash with invalid type */ cl_git_fail(git_odb_hashfile(&a, full.ptr, GIT_OBJ_ANY)); cl_git_fail(git_repository_hashfile(&b, _repo, full.ptr, GIT_OBJ_OFS_DELTA, NULL)); git_buf_free(&full); } void test_repo_hashfile__filtered(void) { git_oid a, b; cl_repo_set_bool(_repo, "core.autocrlf", true); cl_git_append2file("status/.gitattributes", "*.txt text\n*.bin binary\n\n"); /* create some sample content with CRLF in it */ cl_git_mkfile("status/testfile.txt", "content\r\n"); cl_git_mkfile("status/testfile.bin", "other\r\nstuff\r\n"); /* not equal hashes because of filtering */ cl_git_pass(git_odb_hashfile(&a, "status/testfile.txt", GIT_OBJ_BLOB)); cl_git_pass(git_repository_hashfile(&b, _repo, "testfile.txt", GIT_OBJ_BLOB, NULL)); cl_assert(git_oid_cmp(&a, &b)); /* equal hashes because filter is binary */ cl_git_pass(git_odb_hashfile(&a, "status/testfile.bin", GIT_OBJ_BLOB)); cl_git_pass(git_repository_hashfile(&b, _repo, "testfile.bin", GIT_OBJ_BLOB, NULL)); cl_assert(git_oid_equal(&a, &b)); /* equal hashes when 'as_file' points to binary filtering */ cl_git_pass(git_odb_hashfile(&a, "status/testfile.txt", GIT_OBJ_BLOB)); cl_git_pass(git_repository_hashfile(&b, _repo, "testfile.txt", GIT_OBJ_BLOB, "foo.bin")); cl_assert(git_oid_equal(&a, &b)); /* not equal hashes when 'as_file' points to text filtering */ cl_git_pass(git_odb_hashfile(&a, "status/testfile.bin", GIT_OBJ_BLOB)); cl_git_pass(git_repository_hashfile(&b, _repo, "testfile.bin", GIT_OBJ_BLOB, "foo.txt")); cl_assert(git_oid_cmp(&a, &b)); /* equal hashes when 'as_file' is empty and turns off filtering */ cl_git_pass(git_odb_hashfile(&a, "status/testfile.txt", GIT_OBJ_BLOB)); cl_git_pass(git_repository_hashfile(&b, _repo, "testfile.txt", GIT_OBJ_BLOB, "")); cl_assert(git_oid_equal(&a, &b)); cl_git_pass(git_odb_hashfile(&a, "status/testfile.bin", GIT_OBJ_BLOB)); cl_git_pass(git_repository_hashfile(&b, _repo, "testfile.bin", GIT_OBJ_BLOB, "")); cl_assert(git_oid_equal(&a, &b)); /* some hash type failures */ cl_git_fail(git_odb_hashfile(&a, "status/testfile.txt", 0)); cl_git_fail(git_repository_hashfile(&b, _repo, "testfile.txt", GIT_OBJ_ANY, NULL)); } libgit2-0.19.0/tests-clar/repo/head.c000066400000000000000000000120211216214232500172220ustar00rootroot00000000000000#include "clar_libgit2.h" #include "refs.h" #include "repo_helpers.h" #include "posix.h" static git_repository *repo; void test_repo_head__initialize(void) { repo = cl_git_sandbox_init("testrepo.git"); } void test_repo_head__cleanup(void) { cl_git_sandbox_cleanup(); } void test_repo_head__head_detached(void) { git_reference *ref; cl_git_pass(git_repository_head_detached(repo)); cl_git_pass(git_repository_detach_head(repo)); cl_assert_equal_i(true, git_repository_head_detached(repo)); /* take the reop back to it's original state */ cl_git_pass(git_reference_symbolic_create(&ref, repo, "HEAD", "refs/heads/master", 1)); git_reference_free(ref); cl_assert_equal_i(false, git_repository_head_detached(repo)); } void test_repo_head__head_orphan(void) { git_reference *ref; cl_git_pass(git_repository_head_detached(repo)); make_head_orphaned(repo, NON_EXISTING_HEAD); cl_assert(git_repository_head_orphan(repo) == 1); /* take the repo back to it's original state */ cl_git_pass(git_reference_symbolic_create(&ref, repo, "HEAD", "refs/heads/master", 1)); cl_assert(git_repository_head_orphan(repo) == 0); git_reference_free(ref); } void test_repo_head__set_head_Attaches_HEAD_to_un_unborn_branch_when_the_branch_doesnt_exist(void) { git_reference *head; cl_git_pass(git_repository_set_head(repo, "refs/heads/doesnt/exist/yet")); cl_assert_equal_i(false, git_repository_head_detached(repo)); cl_assert_equal_i(GIT_EORPHANEDHEAD, git_repository_head(&head, repo)); } void test_repo_head__set_head_Returns_ENOTFOUND_when_the_reference_doesnt_exist(void) { cl_assert_equal_i(GIT_ENOTFOUND, git_repository_set_head(repo, "refs/tags/doesnt/exist/yet")); } void test_repo_head__set_head_Fails_when_the_reference_points_to_a_non_commitish(void) { cl_git_fail(git_repository_set_head(repo, "refs/tags/point_to_blob")); } void test_repo_head__set_head_Attaches_HEAD_when_the_reference_points_to_a_branch(void) { git_reference *head; cl_git_pass(git_repository_set_head(repo, "refs/heads/br2")); cl_assert_equal_i(false, git_repository_head_detached(repo)); cl_git_pass(git_repository_head(&head, repo)); cl_assert_equal_s("refs/heads/br2", git_reference_name(head)); git_reference_free(head); } static void assert_head_is_correctly_detached(void) { git_reference *head; git_object *commit; cl_assert_equal_i(true, git_repository_head_detached(repo)); cl_git_pass(git_repository_head(&head, repo)); cl_git_pass(git_object_lookup(&commit, repo, git_reference_target(head), GIT_OBJ_COMMIT)); git_object_free(commit); git_reference_free(head); } void test_repo_head__set_head_Detaches_HEAD_when_the_reference_doesnt_point_to_a_branch(void) { cl_git_pass(git_repository_set_head(repo, "refs/tags/test")); cl_assert_equal_i(true, git_repository_head_detached(repo)); assert_head_is_correctly_detached(); } void test_repo_head__set_head_detached_Return_ENOTFOUND_when_the_object_doesnt_exist(void) { git_oid oid; cl_git_pass(git_oid_fromstr(&oid, "deadbeefdeadbeefdeadbeefdeadbeefdeadbeef")); cl_assert_equal_i(GIT_ENOTFOUND, git_repository_set_head_detached(repo, &oid)); } void test_repo_head__set_head_detached_Fails_when_the_object_isnt_a_commitish(void) { git_object *blob; cl_git_pass(git_revparse_single(&blob, repo, "point_to_blob")); cl_git_fail(git_repository_set_head_detached(repo, git_object_id(blob))); git_object_free(blob); } void test_repo_head__set_head_detached_Detaches_HEAD_and_make_it_point_to_the_peeled_commit(void) { git_object *tag; cl_git_pass(git_revparse_single(&tag, repo, "tags/test")); cl_assert_equal_i(GIT_OBJ_TAG, git_object_type(tag)); cl_git_pass(git_repository_set_head_detached(repo, git_object_id(tag))); assert_head_is_correctly_detached(); git_object_free(tag); } void test_repo_head__detach_head_Detaches_HEAD_and_make_it_point_to_the_peeled_commit(void) { cl_assert_equal_i(false, git_repository_head_detached(repo)); cl_git_pass(git_repository_detach_head(repo)); assert_head_is_correctly_detached(); } void test_repo_head__detach_head_Fails_if_HEAD_and_point_to_a_non_commitish(void) { git_reference *head; cl_git_pass(git_reference_symbolic_create(&head, repo, GIT_HEAD_FILE, "refs/tags/point_to_blob", 1)); cl_git_fail(git_repository_detach_head(repo)); git_reference_free(head); } void test_repo_head__detaching_an_orphaned_head_returns_GIT_EORPHANEDHEAD(void) { make_head_orphaned(repo, NON_EXISTING_HEAD); cl_assert_equal_i(GIT_EORPHANEDHEAD, git_repository_detach_head(repo)); } void test_repo_head__retrieving_an_orphaned_head_returns_GIT_EORPHANEDHEAD(void) { git_reference *head; make_head_orphaned(repo, NON_EXISTING_HEAD); cl_assert_equal_i(GIT_EORPHANEDHEAD, git_repository_head(&head, repo)); } void test_repo_head__retrieving_a_missing_head_returns_GIT_ENOTFOUND(void) { git_reference *head; delete_head(repo); cl_assert_equal_i(GIT_ENOTFOUND, git_repository_head(&head, repo)); } void test_repo_head__can_tell_if_an_orphaned_head_is_detached(void) { make_head_orphaned(repo, NON_EXISTING_HEAD); cl_assert_equal_i(false, git_repository_head_detached(repo)); } libgit2-0.19.0/tests-clar/repo/headtree.c000066400000000000000000000024001216214232500201020ustar00rootroot00000000000000#include "clar_libgit2.h" #include "repository.h" #include "repo_helpers.h" #include "posix.h" static git_repository *repo; static git_tree *tree; void test_repo_headtree__initialize(void) { repo = cl_git_sandbox_init("testrepo.git"); tree = NULL; } void test_repo_headtree__cleanup(void) { git_tree_free(tree); cl_git_sandbox_cleanup(); } void test_repo_headtree__can_retrieve_the_root_tree_from_a_detached_head(void) { cl_git_pass(git_repository_detach_head(repo)); cl_git_pass(git_repository_head_tree(&tree, repo)); cl_assert(git_oid_streq(git_tree_id(tree), "az")); } void test_repo_headtree__can_retrieve_the_root_tree_from_a_non_detached_head(void) { cl_assert_equal_i(false, git_repository_head_detached(repo)); cl_git_pass(git_repository_head_tree(&tree, repo)); cl_assert(git_oid_streq(git_tree_id(tree), "az")); } void test_repo_headtree__when_head_is_orphaned_returns_EORPHANEDHEAD(void) { make_head_orphaned(repo, NON_EXISTING_HEAD); cl_assert_equal_i(true, git_repository_head_orphan(repo)); cl_assert_equal_i(GIT_EORPHANEDHEAD, git_repository_head_tree(&tree, repo)); } void test_repo_headtree__when_head_is_missing_returns_ENOTFOUND(void) { delete_head(repo); cl_assert_equal_i(GIT_ENOTFOUND, git_repository_head_tree(&tree, repo)); } libgit2-0.19.0/tests-clar/repo/init.c000066400000000000000000000360411216214232500172740ustar00rootroot00000000000000#include "clar_libgit2.h" #include "fileops.h" #include "repository.h" #include "config.h" #include "path.h" enum repo_mode { STANDARD_REPOSITORY = 0, BARE_REPOSITORY = 1 }; static git_repository *_repo = NULL; void test_repo_init__initialize(void) { _repo = NULL; } static void cleanup_repository(void *path) { git_repository_free(_repo); _repo = NULL; cl_fixture_cleanup((const char *)path); } static void ensure_repository_init( const char *working_directory, int is_bare, const char *expected_path_repository, const char *expected_working_directory) { const char *workdir; cl_assert(!git_path_isdir(working_directory)); cl_git_pass(git_repository_init(&_repo, working_directory, is_bare)); workdir = git_repository_workdir(_repo); if (workdir != NULL || expected_working_directory != NULL) { cl_assert( git__suffixcmp(workdir, expected_working_directory) == 0 ); } cl_assert( git__suffixcmp(git_repository_path(_repo), expected_path_repository) == 0 ); cl_assert(git_repository_is_bare(_repo) == is_bare); #ifdef GIT_WIN32 if (!is_bare) { DWORD fattrs = GetFileAttributes(git_repository_path(_repo)); cl_assert((fattrs & FILE_ATTRIBUTE_HIDDEN) != 0); } #endif cl_assert(git_repository_is_empty(_repo)); } void test_repo_init__standard_repo(void) { cl_set_cleanup(&cleanup_repository, "testrepo"); ensure_repository_init("testrepo/", 0, "testrepo/.git/", "testrepo/"); } void test_repo_init__standard_repo_noslash(void) { cl_set_cleanup(&cleanup_repository, "testrepo"); ensure_repository_init("testrepo", 0, "testrepo/.git/", "testrepo/"); } void test_repo_init__bare_repo(void) { cl_set_cleanup(&cleanup_repository, "testrepo.git"); ensure_repository_init("testrepo.git/", 1, "testrepo.git/", NULL); } void test_repo_init__bare_repo_noslash(void) { cl_set_cleanup(&cleanup_repository, "testrepo.git"); ensure_repository_init("testrepo.git", 1, "testrepo.git/", NULL); } void test_repo_init__bare_repo_escaping_current_workdir(void) { git_buf path_repository = GIT_BUF_INIT; git_buf path_current_workdir = GIT_BUF_INIT; cl_git_pass(git_path_prettify_dir(&path_current_workdir, ".", NULL)); cl_git_pass(git_buf_joinpath(&path_repository, git_buf_cstr(&path_current_workdir), "a/b/c")); cl_git_pass(git_futils_mkdir_r(git_buf_cstr(&path_repository), NULL, GIT_DIR_MODE)); /* Change the current working directory */ cl_git_pass(chdir(git_buf_cstr(&path_repository))); /* Initialize a bare repo with a relative path escaping out of the current working directory */ cl_git_pass(git_repository_init(&_repo, "../d/e.git", 1)); cl_git_pass(git__suffixcmp(git_repository_path(_repo), "/a/b/d/e.git/")); git_repository_free(_repo); /* Open a bare repo with a relative path escaping out of the current working directory */ cl_git_pass(git_repository_open(&_repo, "../d/e.git")); cl_git_pass(chdir(git_buf_cstr(&path_current_workdir))); git_buf_free(&path_current_workdir); git_buf_free(&path_repository); cleanup_repository("a"); } void test_repo_init__reinit_bare_repo(void) { cl_set_cleanup(&cleanup_repository, "reinit.git"); /* Initialize the repository */ cl_git_pass(git_repository_init(&_repo, "reinit.git", 1)); git_repository_free(_repo); /* Reinitialize the repository */ cl_git_pass(git_repository_init(&_repo, "reinit.git", 1)); } void test_repo_init__reinit_too_recent_bare_repo(void) { git_config *config; /* Initialize the repository */ cl_git_pass(git_repository_init(&_repo, "reinit.git", 1)); git_repository_config(&config, _repo); /* * Hack the config of the repository to make it look like it has * been created by a recenter version of git/libgit2 */ cl_git_pass(git_config_set_int32(config, "core.repositoryformatversion", 42)); git_config_free(config); git_repository_free(_repo); /* Try to reinitialize the repository */ cl_git_fail(git_repository_init(&_repo, "reinit.git", 1)); cl_fixture_cleanup("reinit.git"); } void test_repo_init__additional_templates(void) { git_buf path = GIT_BUF_INIT; cl_set_cleanup(&cleanup_repository, "tester"); ensure_repository_init("tester", 0, "tester/.git/", "tester/"); cl_git_pass( git_buf_joinpath(&path, git_repository_path(_repo), "description")); cl_assert(git_path_isfile(git_buf_cstr(&path))); cl_git_pass( git_buf_joinpath(&path, git_repository_path(_repo), "info/exclude")); cl_assert(git_path_isfile(git_buf_cstr(&path))); cl_git_pass( git_buf_joinpath(&path, git_repository_path(_repo), "hooks")); cl_assert(git_path_isdir(git_buf_cstr(&path))); /* won't confirm specific contents of hooks dir since it may vary */ git_buf_free(&path); } static void assert_config_entry_on_init_bytype(const char *config_key, int expected_value, bool is_bare) { git_config *config; int current_value; git_buf repo_path = GIT_BUF_INIT; cl_set_cleanup(&cleanup_repository, "config_entry"); cl_git_pass(git_buf_puts(&repo_path, "config_entry/test.")); if (!is_bare) cl_git_pass(git_buf_puts(&repo_path, "non.")); cl_git_pass(git_buf_puts(&repo_path, "bare.git")); cl_git_pass(git_repository_init(&_repo, git_buf_cstr(&repo_path), is_bare)); git_buf_free(&repo_path); git_repository_config(&config, _repo); if (expected_value >= 0) { cl_git_pass(git_config_get_bool(¤t_value, config, config_key)); cl_assert_equal_i(expected_value, current_value); } else { int error = git_config_get_bool(¤t_value, config, config_key); cl_assert_equal_i(expected_value, error); } git_config_free(config); } static void assert_config_entry_on_init(const char *config_key, int expected_value) { assert_config_entry_on_init_bytype(config_key, expected_value, true); git_repository_free(_repo); assert_config_entry_on_init_bytype(config_key, expected_value, false); } void test_repo_init__detect_filemode(void) { #ifdef GIT_WIN32 assert_config_entry_on_init("core.filemode", false); #else assert_config_entry_on_init("core.filemode", true); #endif } #define CASE_INSENSITIVE_FILESYSTEM (defined GIT_WIN32 || defined __APPLE__) void test_repo_init__detect_ignorecase(void) { #if CASE_INSENSITIVE_FILESYSTEM assert_config_entry_on_init("core.ignorecase", true); #else assert_config_entry_on_init("core.ignorecase", GIT_ENOTFOUND); #endif } void test_repo_init__reinit_doesnot_overwrite_ignorecase(void) { git_config *config; int current_value; /* Init a new repo */ cl_set_cleanup(&cleanup_repository, "not.overwrite.git"); cl_git_pass(git_repository_init(&_repo, "not.overwrite.git", 1)); /* Change the "core.ignorecase" config value to something unlikely */ git_repository_config(&config, _repo); git_config_set_int32(config, "core.ignorecase", 42); git_config_free(config); git_repository_free(_repo); _repo = NULL; /* Reinit the repository */ cl_git_pass(git_repository_init(&_repo, "not.overwrite.git", 1)); git_repository_config(&config, _repo); /* Ensure the "core.ignorecase" config value hasn't been updated */ cl_git_pass(git_config_get_int32(¤t_value, config, "core.ignorecase")); cl_assert_equal_i(42, current_value); git_config_free(config); } void test_repo_init__reinit_overwrites_filemode(void) { git_config *config; int expected, current_value; #ifdef GIT_WIN32 expected = false; #else expected = true; #endif /* Init a new repo */ cl_set_cleanup(&cleanup_repository, "overwrite.git"); cl_git_pass(git_repository_init(&_repo, "overwrite.git", 1)); /* Change the "core.filemode" config value to something unlikely */ cl_repo_set_bool(_repo, "core.filemode", !expected); git_repository_free(_repo); _repo = NULL; /* Reinit the repository */ cl_git_pass(git_repository_init(&_repo, "overwrite.git", 1)); git_repository_config(&config, _repo); /* Ensure the "core.filemode" config value has been reset */ cl_git_pass(git_config_get_bool(¤t_value, config, "core.filemode")); cl_assert_equal_i(expected, current_value); git_config_free(config); } void test_repo_init__sets_logAllRefUpdates_according_to_type_of_repository(void) { assert_config_entry_on_init_bytype("core.logallrefupdates", GIT_ENOTFOUND, true); git_repository_free(_repo); assert_config_entry_on_init_bytype("core.logallrefupdates", true, false); } void test_repo_init__extended_0(void) { git_repository_init_options opts = GIT_REPOSITORY_INIT_OPTIONS_INIT; /* without MKDIR this should fail */ cl_git_fail(git_repository_init_ext(&_repo, "extended", &opts)); /* make the directory first, then it should succeed */ cl_git_pass(git_futils_mkdir("extended", NULL, 0775, 0)); cl_git_pass(git_repository_init_ext(&_repo, "extended", &opts)); cl_assert(!git__suffixcmp(git_repository_workdir(_repo), "/extended/")); cl_assert(!git__suffixcmp(git_repository_path(_repo), "/extended/.git/")); cl_assert(!git_repository_is_bare(_repo)); cl_assert(git_repository_is_empty(_repo)); cleanup_repository("extended"); } void test_repo_init__extended_1(void) { git_reference *ref; git_remote *remote; struct stat st; git_repository_init_options opts = GIT_REPOSITORY_INIT_OPTIONS_INIT; opts.flags = GIT_REPOSITORY_INIT_MKPATH | GIT_REPOSITORY_INIT_NO_DOTGIT_DIR; opts.mode = GIT_REPOSITORY_INIT_SHARED_GROUP; opts.workdir_path = "../c_wd"; opts.description = "Awesomest test repository evah"; opts.initial_head = "development"; opts.origin_url = "https://github.com/libgit2/libgit2.git"; cl_git_pass(git_repository_init_ext(&_repo, "root/b/c.git", &opts)); cl_assert(!git__suffixcmp(git_repository_workdir(_repo), "/c_wd/")); cl_assert(!git__suffixcmp(git_repository_path(_repo), "/c.git/")); cl_assert(git_path_isfile("root/b/c_wd/.git")); cl_assert(!git_repository_is_bare(_repo)); /* repo will not be counted as empty because we set head to "development" */ cl_assert(!git_repository_is_empty(_repo)); cl_git_pass(git_path_lstat(git_repository_path(_repo), &st)); cl_assert(S_ISDIR(st.st_mode)); cl_assert((S_ISGID & st.st_mode) == S_ISGID); cl_git_pass(git_reference_lookup(&ref, _repo, "HEAD")); cl_assert(git_reference_type(ref) == GIT_REF_SYMBOLIC); cl_assert_equal_s("refs/heads/development", git_reference_symbolic_target(ref)); git_reference_free(ref); cl_git_pass(git_remote_load(&remote, _repo, "origin")); cl_assert_equal_s("origin", git_remote_name(remote)); cl_assert_equal_s(opts.origin_url, git_remote_url(remote)); git_remote_free(remote); git_repository_free(_repo); cl_fixture_cleanup("root"); } static void assert_hooks_match( const char *template_dir, const char *repo_dir, const char *hook_path, bool core_filemode) { git_buf expected = GIT_BUF_INIT; git_buf actual = GIT_BUF_INIT; struct stat expected_st, st; cl_git_pass(git_buf_joinpath(&expected, template_dir, hook_path)); cl_git_pass(git_path_lstat(expected.ptr, &expected_st)); cl_git_pass(git_buf_joinpath(&actual, repo_dir, hook_path)); cl_git_pass(git_path_lstat(actual.ptr, &st)); cl_assert(expected_st.st_size == st.st_size); if (!core_filemode) { expected_st.st_mode = expected_st.st_mode & ~0111; st.st_mode = st.st_mode & ~0111; } cl_assert_equal_i((int)expected_st.st_mode, (int)st.st_mode); git_buf_free(&expected); git_buf_free(&actual); } static void assert_mode_seems_okay( const char *base, const char *path, git_filemode_t expect_mode, bool expect_setgid, bool core_filemode) { git_buf full = GIT_BUF_INIT; struct stat st; cl_git_pass(git_buf_joinpath(&full, base, path)); cl_git_pass(git_path_lstat(full.ptr, &st)); git_buf_free(&full); if (!core_filemode) { expect_mode = expect_mode & ~0111; st.st_mode = st.st_mode & ~0111; expect_setgid = false; } if (S_ISGID != 0) { if (expect_setgid) cl_assert((st.st_mode & S_ISGID) != 0); else cl_assert((st.st_mode & S_ISGID) == 0); } if ((expect_mode & 0111) != 0) cl_assert((st.st_mode & 0111) != 0); else cl_assert((st.st_mode & 0111) == 0); cl_assert((expect_mode & 0170000) == (st.st_mode & 0170000)); } void test_repo_init__extended_with_template(void) { git_buf expected = GIT_BUF_INIT; git_buf actual = GIT_BUF_INIT; git_repository_init_options opts = GIT_REPOSITORY_INIT_OPTIONS_INIT; cl_set_cleanup(&cleanup_repository, "templated.git"); opts.flags = GIT_REPOSITORY_INIT_MKPATH | GIT_REPOSITORY_INIT_BARE | GIT_REPOSITORY_INIT_EXTERNAL_TEMPLATE; opts.template_path = cl_fixture("template"); cl_git_pass(git_repository_init_ext(&_repo, "templated.git", &opts)); cl_assert(git_repository_is_bare(_repo)); cl_assert(!git__suffixcmp(git_repository_path(_repo), "/templated.git/")); cl_git_pass(git_futils_readbuffer( &expected, cl_fixture("template/description"))); cl_git_pass(git_futils_readbuffer( &actual, "templated.git/description")); cl_assert_equal_s(expected.ptr, actual.ptr); git_buf_free(&expected); git_buf_free(&actual); assert_hooks_match( cl_fixture("template"), git_repository_path(_repo), "hooks/update.sample", true); assert_hooks_match( cl_fixture("template"), git_repository_path(_repo), "hooks/link.sample", true); } void test_repo_init__extended_with_template_and_shared_mode(void) { git_buf expected = GIT_BUF_INIT; git_buf actual = GIT_BUF_INIT; git_repository_init_options opts = GIT_REPOSITORY_INIT_OPTIONS_INIT; git_config *config; int filemode = true; const char *repo_path = NULL; cl_set_cleanup(&cleanup_repository, "init_shared_from_tpl"); opts.flags = GIT_REPOSITORY_INIT_MKPATH | GIT_REPOSITORY_INIT_EXTERNAL_TEMPLATE; opts.template_path = cl_fixture("template"); opts.mode = GIT_REPOSITORY_INIT_SHARED_GROUP; cl_git_pass(git_repository_init_ext(&_repo, "init_shared_from_tpl", &opts)); cl_assert(!git_repository_is_bare(_repo)); cl_assert(!git__suffixcmp(git_repository_path(_repo), "/init_shared_from_tpl/.git/")); cl_git_pass(git_repository_config(&config, _repo)); cl_git_pass(git_config_get_bool(&filemode, config, "core.filemode")); git_config_free(config); cl_git_pass(git_futils_readbuffer( &expected, cl_fixture("template/description"))); cl_git_pass(git_futils_readbuffer( &actual, "init_shared_from_tpl/.git/description")); cl_assert_equal_s(expected.ptr, actual.ptr); git_buf_free(&expected); git_buf_free(&actual); repo_path = git_repository_path(_repo); assert_mode_seems_okay(repo_path, "hooks", GIT_FILEMODE_TREE | GIT_REPOSITORY_INIT_SHARED_GROUP, true, filemode); assert_mode_seems_okay(repo_path, "info", GIT_FILEMODE_TREE | GIT_REPOSITORY_INIT_SHARED_GROUP, true, filemode); assert_mode_seems_okay(repo_path, "description", GIT_FILEMODE_BLOB, false, filemode); /* for a non-symlinked hook, it should have shared permissions now */ assert_hooks_match( cl_fixture("template"), git_repository_path(_repo), "hooks/update.sample", filemode); /* for a symlinked hook, the permissions still should match the * source link, not the GIT_REPOSITORY_INIT_SHARED_GROUP value */ assert_hooks_match( cl_fixture("template"), git_repository_path(_repo), "hooks/link.sample", filemode); } void test_repo_init__can_reinit_an_initialized_repository(void) { git_repository *reinit; cl_set_cleanup(&cleanup_repository, "extended"); cl_git_pass(git_futils_mkdir("extended", NULL, 0775, 0)); cl_git_pass(git_repository_init(&_repo, "extended", false)); cl_git_pass(git_repository_init(&reinit, "extended", false)); cl_assert_equal_s(git_repository_path(_repo), git_repository_path(reinit)); git_repository_free(reinit); } libgit2-0.19.0/tests-clar/repo/iterator.c000066400000000000000000000670211216214232500201640ustar00rootroot00000000000000#include "clar_libgit2.h" #include "iterator.h" #include "repository.h" #include "fileops.h" #include static git_repository *g_repo; void test_repo_iterator__initialize(void) { } void test_repo_iterator__cleanup(void) { cl_git_sandbox_cleanup(); g_repo = NULL; } static void expect_iterator_items( git_iterator *i, int expected_flat, const char **expected_flat_paths, int expected_total, const char **expected_total_paths) { const git_index_entry *entry; int count, error; int no_trees = !(git_iterator_flags(i) & GIT_ITERATOR_INCLUDE_TREES); bool v = false; if (expected_flat < 0) { v = true; expected_flat = -expected_flat; } if (expected_total < 0) { v = true; expected_total = -expected_total; } if (v) fprintf(stderr, "== %s ==\n", no_trees ? "notrees" : "trees"); count = 0; while (!git_iterator_advance(&entry, i)) { if (v) fprintf(stderr, " %s %07o\n", entry->path, (int)entry->mode); if (no_trees) cl_assert(entry->mode != GIT_FILEMODE_TREE); if (expected_flat_paths) { const char *expect_path = expected_flat_paths[count]; size_t expect_len = strlen(expect_path); cl_assert_equal_s(expect_path, entry->path); if (expect_path[expect_len - 1] == '/') cl_assert_equal_i(GIT_FILEMODE_TREE, entry->mode); else cl_assert(entry->mode != GIT_FILEMODE_TREE); } if (++count > expected_flat) break; } cl_assert_equal_i(expected_flat, count); cl_git_pass(git_iterator_reset(i, NULL, NULL)); count = 0; cl_git_pass(git_iterator_current(&entry, i)); if (v) fprintf(stderr, "-- %s --\n", no_trees ? "notrees" : "trees"); while (entry != NULL) { if (v) fprintf(stderr, " %s %07o\n", entry->path, (int)entry->mode); if (no_trees) cl_assert(entry->mode != GIT_FILEMODE_TREE); if (expected_total_paths) { const char *expect_path = expected_total_paths[count]; size_t expect_len = strlen(expect_path); cl_assert_equal_s(expect_path, entry->path); if (expect_path[expect_len - 1] == '/') cl_assert_equal_i(GIT_FILEMODE_TREE, entry->mode); else cl_assert(entry->mode != GIT_FILEMODE_TREE); } if (entry->mode == GIT_FILEMODE_TREE) { error = git_iterator_advance_into(&entry, i); /* could return NOTFOUND if directory is empty */ cl_assert(!error || error == GIT_ENOTFOUND); if (error == GIT_ENOTFOUND) { error = git_iterator_advance(&entry, i); cl_assert(!error || error == GIT_ITEROVER); } } else { error = git_iterator_advance(&entry, i); cl_assert(!error || error == GIT_ITEROVER); } if (++count > expected_total) break; } cl_assert_equal_i(expected_total, count); } /* Index contents (including pseudotrees): * * 0: a 5: F 10: k/ 16: L/ * 1: B 6: g 11: k/1 17: L/1 * 2: c 7: H 12: k/a 18: L/a * 3: D 8: i 13: k/B 19: L/B * 4: e 9: J 14: k/c 20: L/c * 15: k/D 21: L/D * * 0: B 5: L/ 11: a 16: k/ * 1: D 6: L/1 12: c 17: k/1 * 2: F 7: L/B 13: e 18: k/B * 3: H 8: L/D 14: g 19: k/D * 4: J 9: L/a 15: i 20: k/a * 10: L/c 21: k/c */ void test_repo_iterator__index(void) { git_iterator *i; git_index *index; g_repo = cl_git_sandbox_init("icase"); cl_git_pass(git_repository_index(&index, g_repo)); /* autoexpand with no tree entries for index */ cl_git_pass(git_iterator_for_index(&i, index, 0, NULL, NULL)); expect_iterator_items(i, 20, NULL, 20, NULL); git_iterator_free(i); /* auto expand with tree entries */ cl_git_pass(git_iterator_for_index( &i, index, GIT_ITERATOR_INCLUDE_TREES, NULL, NULL)); expect_iterator_items(i, 22, NULL, 22, NULL); git_iterator_free(i); /* no auto expand (implies trees included) */ cl_git_pass(git_iterator_for_index( &i, index, GIT_ITERATOR_DONT_AUTOEXPAND, NULL, NULL)); expect_iterator_items(i, 12, NULL, 22, NULL); git_iterator_free(i); git_index_free(index); } void test_repo_iterator__index_icase(void) { git_iterator *i; git_index *index; unsigned int caps; g_repo = cl_git_sandbox_init("icase"); cl_git_pass(git_repository_index(&index, g_repo)); caps = git_index_caps(index); /* force case sensitivity */ cl_git_pass(git_index_set_caps(index, caps & ~GIT_INDEXCAP_IGNORE_CASE)); /* autoexpand with no tree entries over range */ cl_git_pass(git_iterator_for_index(&i, index, 0, "c", "k/D")); expect_iterator_items(i, 7, NULL, 7, NULL); git_iterator_free(i); cl_git_pass(git_iterator_for_index(&i, index, 0, "k", "k/Z")); expect_iterator_items(i, 3, NULL, 3, NULL); git_iterator_free(i); /* auto expand with tree entries */ cl_git_pass(git_iterator_for_index( &i, index, GIT_ITERATOR_INCLUDE_TREES, "c", "k/D")); expect_iterator_items(i, 8, NULL, 8, NULL); git_iterator_free(i); cl_git_pass(git_iterator_for_index( &i, index, GIT_ITERATOR_INCLUDE_TREES, "k", "k/Z")); expect_iterator_items(i, 4, NULL, 4, NULL); git_iterator_free(i); /* no auto expand (implies trees included) */ cl_git_pass(git_iterator_for_index( &i, index, GIT_ITERATOR_DONT_AUTOEXPAND, "c", "k/D")); expect_iterator_items(i, 5, NULL, 8, NULL); git_iterator_free(i); cl_git_pass(git_iterator_for_index( &i, index, GIT_ITERATOR_DONT_AUTOEXPAND, "k", "k/Z")); expect_iterator_items(i, 1, NULL, 4, NULL); git_iterator_free(i); /* force case insensitivity */ cl_git_pass(git_index_set_caps(index, caps | GIT_INDEXCAP_IGNORE_CASE)); /* autoexpand with no tree entries over range */ cl_git_pass(git_iterator_for_index(&i, index, 0, "c", "k/D")); expect_iterator_items(i, 13, NULL, 13, NULL); git_iterator_free(i); cl_git_pass(git_iterator_for_index(&i, index, 0, "k", "k/Z")); expect_iterator_items(i, 5, NULL, 5, NULL); git_iterator_free(i); /* auto expand with tree entries */ cl_git_pass(git_iterator_for_index( &i, index, GIT_ITERATOR_INCLUDE_TREES, "c", "k/D")); expect_iterator_items(i, 14, NULL, 14, NULL); git_iterator_free(i); cl_git_pass(git_iterator_for_index( &i, index, GIT_ITERATOR_INCLUDE_TREES, "k", "k/Z")); expect_iterator_items(i, 6, NULL, 6, NULL); git_iterator_free(i); /* no auto expand (implies trees included) */ cl_git_pass(git_iterator_for_index( &i, index, GIT_ITERATOR_DONT_AUTOEXPAND, "c", "k/D")); expect_iterator_items(i, 9, NULL, 14, NULL); git_iterator_free(i); cl_git_pass(git_iterator_for_index( &i, index, GIT_ITERATOR_DONT_AUTOEXPAND, "k", "k/Z")); expect_iterator_items(i, 1, NULL, 6, NULL); git_iterator_free(i); cl_git_pass(git_index_set_caps(index, caps)); git_index_free(index); } void test_repo_iterator__tree(void) { git_iterator *i; git_tree *head; g_repo = cl_git_sandbox_init("icase"); cl_git_pass(git_repository_head_tree(&head, g_repo)); /* auto expand with no tree entries */ cl_git_pass(git_iterator_for_tree(&i, head, 0, NULL, NULL)); expect_iterator_items(i, 20, NULL, 20, NULL); git_iterator_free(i); /* auto expand with tree entries */ cl_git_pass(git_iterator_for_tree( &i, head, GIT_ITERATOR_INCLUDE_TREES, NULL, NULL)); expect_iterator_items(i, 22, NULL, 22, NULL); git_iterator_free(i); /* no auto expand (implies trees included) */ cl_git_pass(git_iterator_for_tree( &i, head, GIT_ITERATOR_DONT_AUTOEXPAND, NULL, NULL)); expect_iterator_items(i, 12, NULL, 22, NULL); git_iterator_free(i); git_tree_free(head); } void test_repo_iterator__tree_icase(void) { git_iterator *i; git_tree *head; git_iterator_flag_t flag; g_repo = cl_git_sandbox_init("icase"); cl_git_pass(git_repository_head_tree(&head, g_repo)); flag = GIT_ITERATOR_DONT_IGNORE_CASE; /* auto expand with no tree entries */ cl_git_pass(git_iterator_for_tree(&i, head, flag, "c", "k/D")); expect_iterator_items(i, 7, NULL, 7, NULL); git_iterator_free(i); cl_git_pass(git_iterator_for_tree(&i, head, flag, "k", "k/Z")); expect_iterator_items(i, 3, NULL, 3, NULL); git_iterator_free(i); /* auto expand with tree entries */ cl_git_pass(git_iterator_for_tree( &i, head, flag | GIT_ITERATOR_INCLUDE_TREES, "c", "k/D")); expect_iterator_items(i, 8, NULL, 8, NULL); git_iterator_free(i); cl_git_pass(git_iterator_for_tree( &i, head, flag | GIT_ITERATOR_INCLUDE_TREES, "k", "k/Z")); expect_iterator_items(i, 4, NULL, 4, NULL); git_iterator_free(i); /* no auto expand (implies trees included) */ cl_git_pass(git_iterator_for_tree( &i, head, flag | GIT_ITERATOR_DONT_AUTOEXPAND, "c", "k/D")); expect_iterator_items(i, 5, NULL, 8, NULL); git_iterator_free(i); cl_git_pass(git_iterator_for_tree( &i, head, flag | GIT_ITERATOR_DONT_AUTOEXPAND, "k", "k/Z")); expect_iterator_items(i, 1, NULL, 4, NULL); git_iterator_free(i); flag = GIT_ITERATOR_IGNORE_CASE; /* auto expand with no tree entries */ cl_git_pass(git_iterator_for_tree(&i, head, flag, "c", "k/D")); expect_iterator_items(i, 13, NULL, 13, NULL); git_iterator_free(i); cl_git_pass(git_iterator_for_tree(&i, head, flag, "k", "k/Z")); expect_iterator_items(i, 5, NULL, 5, NULL); git_iterator_free(i); /* auto expand with tree entries */ cl_git_pass(git_iterator_for_tree( &i, head, flag | GIT_ITERATOR_INCLUDE_TREES, "c", "k/D")); expect_iterator_items(i, 14, NULL, 14, NULL); git_iterator_free(i); cl_git_pass(git_iterator_for_tree( &i, head, flag | GIT_ITERATOR_INCLUDE_TREES, "k", "k/Z")); expect_iterator_items(i, 6, NULL, 6, NULL); git_iterator_free(i); /* no auto expand (implies trees included) */ cl_git_pass(git_iterator_for_tree( &i, head, flag | GIT_ITERATOR_DONT_AUTOEXPAND, "c", "k/D")); expect_iterator_items(i, 9, NULL, 14, NULL); git_iterator_free(i); cl_git_pass(git_iterator_for_tree( &i, head, flag | GIT_ITERATOR_DONT_AUTOEXPAND, "k", "k/Z")); expect_iterator_items(i, 1, NULL, 6, NULL); git_iterator_free(i); git_tree_free(head); } void test_repo_iterator__tree_more(void) { git_iterator *i; git_tree *head; static const char *expect_basic[] = { "current_file", "file_deleted", "modified_file", "staged_changes", "staged_changes_file_deleted", "staged_changes_modified_file", "staged_delete_file_deleted", "staged_delete_modified_file", "subdir.txt", "subdir/current_file", "subdir/deleted_file", "subdir/modified_file", NULL, }; static const char *expect_trees[] = { "current_file", "file_deleted", "modified_file", "staged_changes", "staged_changes_file_deleted", "staged_changes_modified_file", "staged_delete_file_deleted", "staged_delete_modified_file", "subdir.txt", "subdir/", "subdir/current_file", "subdir/deleted_file", "subdir/modified_file", NULL, }; static const char *expect_noauto[] = { "current_file", "file_deleted", "modified_file", "staged_changes", "staged_changes_file_deleted", "staged_changes_modified_file", "staged_delete_file_deleted", "staged_delete_modified_file", "subdir.txt", "subdir/", NULL }; g_repo = cl_git_sandbox_init("status"); cl_git_pass(git_repository_head_tree(&head, g_repo)); /* auto expand with no tree entries */ cl_git_pass(git_iterator_for_tree(&i, head, 0, NULL, NULL)); expect_iterator_items(i, 12, expect_basic, 12, expect_basic); git_iterator_free(i); /* auto expand with tree entries */ cl_git_pass(git_iterator_for_tree( &i, head, GIT_ITERATOR_INCLUDE_TREES, NULL, NULL)); expect_iterator_items(i, 13, expect_trees, 13, expect_trees); git_iterator_free(i); /* no auto expand (implies trees included) */ cl_git_pass(git_iterator_for_tree( &i, head, GIT_ITERATOR_DONT_AUTOEXPAND, NULL, NULL)); expect_iterator_items(i, 10, expect_noauto, 13, expect_trees); git_iterator_free(i); git_tree_free(head); } /* "b=name,t=name", blob_id, tree_id */ static void build_test_tree( git_oid *out, git_repository *repo, const char *fmt, ...) { git_oid *id; git_treebuilder *builder; const char *scan = fmt, *next; char type, delimiter; git_filemode_t mode = GIT_FILEMODE_BLOB; git_buf name = GIT_BUF_INIT; va_list arglist; cl_git_pass(git_treebuilder_create(&builder, NULL)); /* start builder */ va_start(arglist, fmt); while (*scan) { switch (type = *scan++) { case 't': case 'T': mode = GIT_FILEMODE_TREE; break; case 'b': case 'B': mode = GIT_FILEMODE_BLOB; break; default: cl_assert(type == 't' || type == 'T' || type == 'b' || type == 'B'); } delimiter = *scan++; /* read and skip delimiter */ for (next = scan; *next && *next != delimiter; ++next) /* seek end */; cl_git_pass(git_buf_set(&name, scan, (size_t)(next - scan))); for (scan = next; *scan && (*scan == delimiter || *scan == ','); ++scan) /* skip delimiter and optional comma */; id = va_arg(arglist, git_oid *); cl_git_pass(git_treebuilder_insert(NULL, builder, name.ptr, id, mode)); } va_end(arglist); cl_git_pass(git_treebuilder_write(out, repo, builder)); git_treebuilder_free(builder); git_buf_free(&name); } void test_repo_iterator__tree_case_conflicts_0(void) { const char *blob_sha = "d44e18fb93b7107b5cd1b95d601591d77869a1b6"; git_tree *tree; git_oid blob_id, biga_id, littlea_id, tree_id; git_iterator *i; const char *expect_cs[] = { "A/1.file", "A/3.file", "a/2.file", "a/4.file" }; const char *expect_ci[] = { "A/1.file", "a/2.file", "A/3.file", "a/4.file" }; const char *expect_cs_trees[] = { "A/", "A/1.file", "A/3.file", "a/", "a/2.file", "a/4.file" }; const char *expect_ci_trees[] = { "A/", "A/1.file", "a/2.file", "A/3.file", "a/4.file" }; g_repo = cl_git_sandbox_init("icase"); cl_git_pass(git_oid_fromstr(&blob_id, blob_sha)); /* lookup blob */ /* create tree with: A/1.file, A/3.file, a/2.file, a/4.file */ build_test_tree( &biga_id, g_repo, "b|1.file|,b|3.file|", &blob_id, &blob_id); build_test_tree( &littlea_id, g_repo, "b|2.file|,b|4.file|", &blob_id, &blob_id); build_test_tree( &tree_id, g_repo, "t|A|,t|a|", &biga_id, &littlea_id); cl_git_pass(git_tree_lookup(&tree, g_repo, &tree_id)); cl_git_pass(git_iterator_for_tree( &i, tree, GIT_ITERATOR_DONT_IGNORE_CASE, NULL, NULL)); expect_iterator_items(i, 4, expect_cs, 4, expect_cs); git_iterator_free(i); cl_git_pass(git_iterator_for_tree( &i, tree, GIT_ITERATOR_IGNORE_CASE, NULL, NULL)); expect_iterator_items(i, 4, expect_ci, 4, expect_ci); git_iterator_free(i); cl_git_pass(git_iterator_for_tree( &i, tree, GIT_ITERATOR_DONT_IGNORE_CASE | GIT_ITERATOR_INCLUDE_TREES, NULL, NULL)); expect_iterator_items(i, 6, expect_cs_trees, 6, expect_cs_trees); git_iterator_free(i); cl_git_pass(git_iterator_for_tree( &i, tree, GIT_ITERATOR_IGNORE_CASE | GIT_ITERATOR_INCLUDE_TREES, NULL, NULL)); expect_iterator_items(i, 5, expect_ci_trees, 5, expect_ci_trees); git_iterator_free(i); git_tree_free(tree); } void test_repo_iterator__tree_case_conflicts_1(void) { const char *blob_sha = "d44e18fb93b7107b5cd1b95d601591d77869a1b6"; git_tree *tree; git_oid blob_id, Ab_id, biga_id, littlea_id, tree_id; git_iterator *i; const char *expect_cs[] = { "A/a", "A/b/1", "A/c", "a/C", "a/a", "a/b" }; const char *expect_ci[] = { "A/a", "a/b", "A/b/1", "A/c" }; const char *expect_cs_trees[] = { "A/", "A/a", "A/b/", "A/b/1", "A/c", "a/", "a/C", "a/a", "a/b" }; const char *expect_ci_trees[] = { "A/", "A/a", "a/b", "A/b/", "A/b/1", "A/c" }; g_repo = cl_git_sandbox_init("icase"); cl_git_pass(git_oid_fromstr(&blob_id, blob_sha)); /* lookup blob */ /* create: A/a A/b/1 A/c a/a a/b a/C */ build_test_tree(&Ab_id, g_repo, "b|1|", &blob_id); build_test_tree( &biga_id, g_repo, "b|a|,t|b|,b|c|", &blob_id, &Ab_id, &blob_id); build_test_tree( &littlea_id, g_repo, "b|a|,b|b|,b|C|", &blob_id, &blob_id, &blob_id); build_test_tree( &tree_id, g_repo, "t|A|,t|a|", &biga_id, &littlea_id); cl_git_pass(git_tree_lookup(&tree, g_repo, &tree_id)); cl_git_pass(git_iterator_for_tree( &i, tree, GIT_ITERATOR_DONT_IGNORE_CASE, NULL, NULL)); expect_iterator_items(i, 6, expect_cs, 6, expect_cs); git_iterator_free(i); cl_git_pass(git_iterator_for_tree( &i, tree, GIT_ITERATOR_IGNORE_CASE, NULL, NULL)); expect_iterator_items(i, 4, expect_ci, 4, expect_ci); git_iterator_free(i); cl_git_pass(git_iterator_for_tree( &i, tree, GIT_ITERATOR_DONT_IGNORE_CASE | GIT_ITERATOR_INCLUDE_TREES, NULL, NULL)); expect_iterator_items(i, 9, expect_cs_trees, 9, expect_cs_trees); git_iterator_free(i); cl_git_pass(git_iterator_for_tree( &i, tree, GIT_ITERATOR_IGNORE_CASE | GIT_ITERATOR_INCLUDE_TREES, NULL, NULL)); expect_iterator_items(i, 6, expect_ci_trees, 6, expect_ci_trees); git_iterator_free(i); git_tree_free(tree); } void test_repo_iterator__tree_case_conflicts_2(void) { const char *blob_sha = "d44e18fb93b7107b5cd1b95d601591d77869a1b6"; git_tree *tree; git_oid blob_id, d1, d2, c1, c2, b1, b2, a1, a2, tree_id; git_iterator *i; const char *expect_cs[] = { "A/B/C/D/16", "A/B/C/D/foo", "A/B/C/d/15", "A/B/C/d/FOO", "A/B/c/D/14", "A/B/c/D/foo", "A/B/c/d/13", "A/B/c/d/FOO", "A/b/C/D/12", "A/b/C/D/foo", "A/b/C/d/11", "A/b/C/d/FOO", "A/b/c/D/10", "A/b/c/D/foo", "A/b/c/d/09", "A/b/c/d/FOO", "a/B/C/D/08", "a/B/C/D/foo", "a/B/C/d/07", "a/B/C/d/FOO", "a/B/c/D/06", "a/B/c/D/foo", "a/B/c/d/05", "a/B/c/d/FOO", "a/b/C/D/04", "a/b/C/D/foo", "a/b/C/d/03", "a/b/C/d/FOO", "a/b/c/D/02", "a/b/c/D/foo", "a/b/c/d/01", "a/b/c/d/FOO", }; const char *expect_ci[] = { "a/b/c/d/01", "a/b/c/D/02", "a/b/C/d/03", "a/b/C/D/04", "a/B/c/d/05", "a/B/c/D/06", "a/B/C/d/07", "a/B/C/D/08", "A/b/c/d/09", "A/b/c/D/10", "A/b/C/d/11", "A/b/C/D/12", "A/B/c/d/13", "A/B/c/D/14", "A/B/C/d/15", "A/B/C/D/16", "A/B/C/D/foo", }; const char *expect_ci_trees[] = { "A/", "A/B/", "A/B/C/", "A/B/C/D/", "a/b/c/d/01", "a/b/c/D/02", "a/b/C/d/03", "a/b/C/D/04", "a/B/c/d/05", "a/B/c/D/06", "a/B/C/d/07", "a/B/C/D/08", "A/b/c/d/09", "A/b/c/D/10", "A/b/C/d/11", "A/b/C/D/12", "A/B/c/d/13", "A/B/c/D/14", "A/B/C/d/15", "A/B/C/D/16", "A/B/C/D/foo", }; g_repo = cl_git_sandbox_init("icase"); cl_git_pass(git_oid_fromstr(&blob_id, blob_sha)); /* lookup blob */ build_test_tree(&d1, g_repo, "b|16|,b|foo|", &blob_id, &blob_id); build_test_tree(&d2, g_repo, "b|15|,b|FOO|", &blob_id, &blob_id); build_test_tree(&c1, g_repo, "t|D|,t|d|", &d1, &d2); build_test_tree(&d1, g_repo, "b|14|,b|foo|", &blob_id, &blob_id); build_test_tree(&d2, g_repo, "b|13|,b|FOO|", &blob_id, &blob_id); build_test_tree(&c2, g_repo, "t|D|,t|d|", &d1, &d2); build_test_tree(&b1, g_repo, "t|C|,t|c|", &c1, &c2); build_test_tree(&d1, g_repo, "b|12|,b|foo|", &blob_id, &blob_id); build_test_tree(&d2, g_repo, "b|11|,b|FOO|", &blob_id, &blob_id); build_test_tree(&c1, g_repo, "t|D|,t|d|", &d1, &d2); build_test_tree(&d1, g_repo, "b|10|,b|foo|", &blob_id, &blob_id); build_test_tree(&d2, g_repo, "b|09|,b|FOO|", &blob_id, &blob_id); build_test_tree(&c2, g_repo, "t|D|,t|d|", &d1, &d2); build_test_tree(&b2, g_repo, "t|C|,t|c|", &c1, &c2); build_test_tree(&a1, g_repo, "t|B|,t|b|", &b1, &b2); build_test_tree(&d1, g_repo, "b|08|,b|foo|", &blob_id, &blob_id); build_test_tree(&d2, g_repo, "b|07|,b|FOO|", &blob_id, &blob_id); build_test_tree(&c1, g_repo, "t|D|,t|d|", &d1, &d2); build_test_tree(&d1, g_repo, "b|06|,b|foo|", &blob_id, &blob_id); build_test_tree(&d2, g_repo, "b|05|,b|FOO|", &blob_id, &blob_id); build_test_tree(&c2, g_repo, "t|D|,t|d|", &d1, &d2); build_test_tree(&b1, g_repo, "t|C|,t|c|", &c1, &c2); build_test_tree(&d1, g_repo, "b|04|,b|foo|", &blob_id, &blob_id); build_test_tree(&d2, g_repo, "b|03|,b|FOO|", &blob_id, &blob_id); build_test_tree(&c1, g_repo, "t|D|,t|d|", &d1, &d2); build_test_tree(&d1, g_repo, "b|02|,b|foo|", &blob_id, &blob_id); build_test_tree(&d2, g_repo, "b|01|,b|FOO|", &blob_id, &blob_id); build_test_tree(&c2, g_repo, "t|D|,t|d|", &d1, &d2); build_test_tree(&b2, g_repo, "t|C|,t|c|", &c1, &c2); build_test_tree(&a2, g_repo, "t|B|,t|b|", &b1, &b2); build_test_tree(&tree_id, g_repo, "t/A/,t/a/", &a1, &a2); cl_git_pass(git_tree_lookup(&tree, g_repo, &tree_id)); cl_git_pass(git_iterator_for_tree( &i, tree, GIT_ITERATOR_DONT_IGNORE_CASE, NULL, NULL)); expect_iterator_items(i, 32, expect_cs, 32, expect_cs); git_iterator_free(i); cl_git_pass(git_iterator_for_tree( &i, tree, GIT_ITERATOR_IGNORE_CASE, NULL, NULL)); expect_iterator_items(i, 17, expect_ci, 17, expect_ci); git_iterator_free(i); cl_git_pass(git_iterator_for_tree( &i, tree, GIT_ITERATOR_IGNORE_CASE | GIT_ITERATOR_INCLUDE_TREES, NULL, NULL)); expect_iterator_items(i, 21, expect_ci_trees, 21, expect_ci_trees); git_iterator_free(i); git_tree_free(tree); } void test_repo_iterator__workdir(void) { git_iterator *i; g_repo = cl_git_sandbox_init("icase"); /* auto expand with no tree entries */ cl_git_pass(git_iterator_for_workdir(&i, g_repo, 0, NULL, NULL)); expect_iterator_items(i, 20, NULL, 20, NULL); git_iterator_free(i); /* auto expand with tree entries */ cl_git_pass(git_iterator_for_workdir( &i, g_repo, GIT_ITERATOR_INCLUDE_TREES, NULL, NULL)); expect_iterator_items(i, 22, NULL, 22, NULL); git_iterator_free(i); /* no auto expand (implies trees included) */ cl_git_pass(git_iterator_for_workdir( &i, g_repo, GIT_ITERATOR_DONT_AUTOEXPAND, NULL, NULL)); expect_iterator_items(i, 12, NULL, 22, NULL); git_iterator_free(i); } void test_repo_iterator__workdir_icase(void) { git_iterator *i; git_iterator_flag_t flag; g_repo = cl_git_sandbox_init("icase"); flag = GIT_ITERATOR_DONT_IGNORE_CASE; /* auto expand with no tree entries */ cl_git_pass(git_iterator_for_workdir(&i, g_repo, flag, "c", "k/D")); expect_iterator_items(i, 7, NULL, 7, NULL); git_iterator_free(i); cl_git_pass(git_iterator_for_workdir(&i, g_repo, flag, "k", "k/Z")); expect_iterator_items(i, 3, NULL, 3, NULL); git_iterator_free(i); /* auto expand with tree entries */ cl_git_pass(git_iterator_for_workdir( &i, g_repo, flag | GIT_ITERATOR_INCLUDE_TREES, "c", "k/D")); expect_iterator_items(i, 8, NULL, 8, NULL); git_iterator_free(i); cl_git_pass(git_iterator_for_workdir( &i, g_repo, flag | GIT_ITERATOR_INCLUDE_TREES, "k", "k/Z")); expect_iterator_items(i, 4, NULL, 4, NULL); git_iterator_free(i); /* no auto expand (implies trees included) */ cl_git_pass(git_iterator_for_workdir( &i, g_repo, flag | GIT_ITERATOR_DONT_AUTOEXPAND, "c", "k/D")); expect_iterator_items(i, 5, NULL, 8, NULL); git_iterator_free(i); cl_git_pass(git_iterator_for_workdir( &i, g_repo, flag | GIT_ITERATOR_DONT_AUTOEXPAND, "k", "k/Z")); expect_iterator_items(i, 1, NULL, 4, NULL); git_iterator_free(i); flag = GIT_ITERATOR_IGNORE_CASE; /* auto expand with no tree entries */ cl_git_pass(git_iterator_for_workdir(&i, g_repo, flag, "c", "k/D")); expect_iterator_items(i, 13, NULL, 13, NULL); git_iterator_free(i); cl_git_pass(git_iterator_for_workdir(&i, g_repo, flag, "k", "k/Z")); expect_iterator_items(i, 5, NULL, 5, NULL); git_iterator_free(i); /* auto expand with tree entries */ cl_git_pass(git_iterator_for_workdir( &i, g_repo, flag | GIT_ITERATOR_INCLUDE_TREES, "c", "k/D")); expect_iterator_items(i, 14, NULL, 14, NULL); git_iterator_free(i); cl_git_pass(git_iterator_for_workdir( &i, g_repo, flag | GIT_ITERATOR_INCLUDE_TREES, "k", "k/Z")); expect_iterator_items(i, 6, NULL, 6, NULL); git_iterator_free(i); /* no auto expand (implies trees included) */ cl_git_pass(git_iterator_for_workdir( &i, g_repo, flag | GIT_ITERATOR_DONT_AUTOEXPAND, "c", "k/D")); expect_iterator_items(i, 9, NULL, 14, NULL); git_iterator_free(i); cl_git_pass(git_iterator_for_workdir( &i, g_repo, flag | GIT_ITERATOR_DONT_AUTOEXPAND, "k", "k/Z")); expect_iterator_items(i, 1, NULL, 6, NULL); git_iterator_free(i); } static void build_workdir_tree(const char *root, int dirs, int subs) { int i, j; char buf[64], sub[64]; for (i = 0; i < dirs; ++i) { if (i % 2 == 0) { p_snprintf(buf, sizeof(buf), "%s/dir%02d", root, i); cl_git_pass(git_futils_mkdir(buf, NULL, 0775, GIT_MKDIR_PATH)); p_snprintf(buf, sizeof(buf), "%s/dir%02d/file", root, i); cl_git_mkfile(buf, buf); buf[strlen(buf) - 5] = '\0'; } else { p_snprintf(buf, sizeof(buf), "%s/DIR%02d", root, i); cl_git_pass(git_futils_mkdir(buf, NULL, 0775, GIT_MKDIR_PATH)); } for (j = 0; j < subs; ++j) { switch (j % 4) { case 0: p_snprintf(sub, sizeof(sub), "%s/sub%02d", buf, j); break; case 1: p_snprintf(sub, sizeof(sub), "%s/sUB%02d", buf, j); break; case 2: p_snprintf(sub, sizeof(sub), "%s/Sub%02d", buf, j); break; case 3: p_snprintf(sub, sizeof(sub), "%s/SUB%02d", buf, j); break; } cl_git_pass(git_futils_mkdir(sub, NULL, 0775, GIT_MKDIR_PATH)); if (j % 2 == 0) { size_t sublen = strlen(sub); memcpy(&sub[sublen], "/file", sizeof("/file")); cl_git_mkfile(sub, sub); sub[sublen] = '\0'; } } } } void test_repo_iterator__workdir_depth(void) { git_iterator *iter; g_repo = cl_git_sandbox_init("icase"); build_workdir_tree("icase", 10, 10); build_workdir_tree("icase/DIR01/sUB01", 50, 0); build_workdir_tree("icase/dir02/sUB01", 50, 0); /* auto expand with no tree entries */ cl_git_pass(git_iterator_for_workdir(&iter, g_repo, 0, NULL, NULL)); expect_iterator_items(iter, 125, NULL, 125, NULL); git_iterator_free(iter); /* auto expand with tree entries (empty dirs silently skipped) */ cl_git_pass(git_iterator_for_workdir( &iter, g_repo, GIT_ITERATOR_INCLUDE_TREES, NULL, NULL)); expect_iterator_items(iter, 337, NULL, 337, NULL); git_iterator_free(iter); } void test_repo_iterator__fs(void) { git_iterator *i; static const char *expect_base[] = { "DIR01/Sub02/file", "DIR01/sub00/file", "current_file", "dir00/Sub02/file", "dir00/file", "dir00/sub00/file", "modified_file", "new_file", NULL, }; static const char *expect_trees[] = { "DIR01/", "DIR01/SUB03/", "DIR01/Sub02/", "DIR01/Sub02/file", "DIR01/sUB01/", "DIR01/sub00/", "DIR01/sub00/file", "current_file", "dir00/", "dir00/SUB03/", "dir00/Sub02/", "dir00/Sub02/file", "dir00/file", "dir00/sUB01/", "dir00/sub00/", "dir00/sub00/file", "modified_file", "new_file", NULL, }; static const char *expect_noauto[] = { "DIR01/", "current_file", "dir00/", "modified_file", "new_file", NULL, }; g_repo = cl_git_sandbox_init("status"); build_workdir_tree("status/subdir", 2, 4); cl_git_pass(git_iterator_for_filesystem( &i, "status/subdir", 0, NULL, NULL)); expect_iterator_items(i, 8, expect_base, 8, expect_base); git_iterator_free(i); cl_git_pass(git_iterator_for_filesystem( &i, "status/subdir", GIT_ITERATOR_INCLUDE_TREES, NULL, NULL)); expect_iterator_items(i, 18, expect_trees, 18, expect_trees); git_iterator_free(i); cl_git_pass(git_iterator_for_filesystem( &i, "status/subdir", GIT_ITERATOR_DONT_AUTOEXPAND, NULL, NULL)); expect_iterator_items(i, 5, expect_noauto, 18, expect_trees); git_iterator_free(i); git__tsort((void **)expect_base, 8, (git__tsort_cmp)git__strcasecmp); git__tsort((void **)expect_trees, 18, (git__tsort_cmp)git__strcasecmp); git__tsort((void **)expect_noauto, 5, (git__tsort_cmp)git__strcasecmp); cl_git_pass(git_iterator_for_filesystem( &i, "status/subdir", GIT_ITERATOR_IGNORE_CASE, NULL, NULL)); expect_iterator_items(i, 8, expect_base, 8, expect_base); git_iterator_free(i); cl_git_pass(git_iterator_for_filesystem( &i, "status/subdir", GIT_ITERATOR_IGNORE_CASE | GIT_ITERATOR_INCLUDE_TREES, NULL, NULL)); expect_iterator_items(i, 18, expect_trees, 18, expect_trees); git_iterator_free(i); cl_git_pass(git_iterator_for_filesystem( &i, "status/subdir", GIT_ITERATOR_IGNORE_CASE | GIT_ITERATOR_DONT_AUTOEXPAND, NULL, NULL)); expect_iterator_items(i, 5, expect_noauto, 18, expect_trees); git_iterator_free(i); } void test_repo_iterator__fs2(void) { git_iterator *i; static const char *expect_base[] = { "heads/br2", "heads/dir", "heads/master", "heads/packed-test", "heads/subtrees", "heads/test", "tags/e90810b", "tags/foo/bar", "tags/foo/foo/bar", "tags/point_to_blob", "tags/test", NULL, }; g_repo = cl_git_sandbox_init("testrepo"); cl_git_pass(git_iterator_for_filesystem( &i, "testrepo/.git/refs", 0, NULL, NULL)); expect_iterator_items(i, 11, expect_base, 11, expect_base); git_iterator_free(i); } libgit2-0.19.0/tests-clar/repo/message.c000066400000000000000000000024521216214232500177540ustar00rootroot00000000000000#include "clar_libgit2.h" #include "buffer.h" #include "refs.h" #include "posix.h" static git_repository *_repo; static git_buf _path; static char *_actual; void test_repo_message__initialize(void) { _repo = cl_git_sandbox_init("testrepo.git"); } void test_repo_message__cleanup(void) { cl_git_sandbox_cleanup(); git_buf_free(&_path); git__free(_actual); _actual = NULL; } void test_repo_message__none(void) { cl_assert_equal_i(GIT_ENOTFOUND, git_repository_message(NULL, 0, _repo)); } void test_repo_message__message(void) { const char expected[] = "Test\n\nThis is a test of the emergency broadcast system\n"; ssize_t len; cl_git_pass(git_buf_joinpath(&_path, git_repository_path(_repo), "MERGE_MSG")); cl_git_mkfile(git_buf_cstr(&_path), expected); len = git_repository_message(NULL, 0, _repo); cl_assert(len > 0); _actual = git__malloc(len + 1); cl_assert(_actual != NULL); /* Test non truncation */ cl_assert(git_repository_message(_actual, len, _repo) > 0); cl_assert_equal_s(expected, _actual); /* Test truncation and that trailing NUL is inserted */ cl_assert(git_repository_message(_actual, 6, _repo) > 0); cl_assert_equal_s("Test\n", _actual); cl_git_pass(p_unlink(git_buf_cstr(&_path))); cl_assert_equal_i(GIT_ENOTFOUND, git_repository_message(NULL, 0, _repo)); } libgit2-0.19.0/tests-clar/repo/open.c000066400000000000000000000234601216214232500172730ustar00rootroot00000000000000#include "clar_libgit2.h" #include "fileops.h" #include void test_repo_open__cleanup(void) { cl_git_sandbox_cleanup(); if (git_path_isdir("alternate")) git_futils_rmdir_r("alternate", NULL, GIT_RMDIR_REMOVE_FILES); } void test_repo_open__bare_empty_repo(void) { git_repository *repo = cl_git_sandbox_init("empty_bare.git"); cl_assert(git_repository_path(repo) != NULL); cl_assert(git__suffixcmp(git_repository_path(repo), "/") == 0); cl_assert(git_repository_workdir(repo) == NULL); } void test_repo_open__standard_empty_repo_through_gitdir(void) { git_repository *repo; cl_git_pass(git_repository_open(&repo, cl_fixture("empty_standard_repo/.gitted"))); cl_assert(git_repository_path(repo) != NULL); cl_assert(git__suffixcmp(git_repository_path(repo), "/") == 0); cl_assert(git_repository_workdir(repo) != NULL); cl_assert(git__suffixcmp(git_repository_workdir(repo), "/") == 0); git_repository_free(repo); } void test_repo_open__standard_empty_repo_through_workdir(void) { git_repository *repo = cl_git_sandbox_init("empty_standard_repo"); cl_assert(git_repository_path(repo) != NULL); cl_assert(git__suffixcmp(git_repository_path(repo), "/") == 0); cl_assert(git_repository_workdir(repo) != NULL); cl_assert(git__suffixcmp(git_repository_workdir(repo), "/") == 0); } void test_repo_open__open_with_discover(void) { static const char *variants[] = { "attr", "attr/", "attr/.git", "attr/.git/", "attr/sub", "attr/sub/", "attr/sub/sub", "attr/sub/sub/", NULL }; git_repository *repo; const char **scan; cl_fixture_sandbox("attr"); cl_git_pass(p_rename("attr/.gitted", "attr/.git")); for (scan = variants; *scan != NULL; scan++) { cl_git_pass(git_repository_open_ext(&repo, *scan, 0, NULL)); cl_assert(git__suffixcmp(git_repository_path(repo), "attr/.git/") == 0); cl_assert(git__suffixcmp(git_repository_workdir(repo), "attr/") == 0); git_repository_free(repo); } cl_fixture_cleanup("attr"); } void test_repo_open__gitlinked(void) { /* need to have both repo dir and workdir set up correctly */ git_repository *repo = cl_git_sandbox_init("empty_standard_repo"); git_repository *repo2; cl_must_pass(p_mkdir("alternate", 0777)); cl_git_mkfile("alternate/.git", "gitdir: ../empty_standard_repo/.git"); cl_git_pass(git_repository_open(&repo2, "alternate")); cl_assert(git_repository_path(repo2) != NULL); cl_assert_(git__suffixcmp(git_repository_path(repo2), "empty_standard_repo/.git/") == 0, git_repository_path(repo2)); cl_assert_equal_s(git_repository_path(repo), git_repository_path(repo2)); cl_assert(git_repository_workdir(repo2) != NULL); cl_assert_(git__suffixcmp(git_repository_workdir(repo2), "alternate/") == 0, git_repository_workdir(repo2)); git_repository_free(repo2); } void test_repo_open__from_git_new_workdir(void) { /* The git-new-workdir script that ships with git sets up a bunch of * symlinks to create a second workdir that shares the object db with * another checkout. Libgit2 can open a repo that has been configured * this way. */ cl_git_sandbox_init("empty_standard_repo"); #ifndef GIT_WIN32 git_repository *repo2; git_buf link_tgt = GIT_BUF_INIT, link = GIT_BUF_INIT, body = GIT_BUF_INIT; const char **scan; int link_fd; static const char *links[] = { "config", "refs", "logs/refs", "objects", "info", "hooks", "packed-refs", "remotes", "rr-cache", "svn", NULL }; static const char *copies[] = { "HEAD", NULL }; cl_git_pass(p_mkdir("alternate", 0777)); cl_git_pass(p_mkdir("alternate/.git", 0777)); for (scan = links; *scan != NULL; scan++) { git_buf_joinpath(&link_tgt, "empty_standard_repo/.git", *scan); if (git_path_exists(link_tgt.ptr)) { git_buf_joinpath(&link_tgt, "../../empty_standard_repo/.git", *scan); git_buf_joinpath(&link, "alternate/.git", *scan); if (strchr(*scan, '/')) git_futils_mkpath2file(link.ptr, 0777); cl_assert_(symlink(link_tgt.ptr, link.ptr) == 0, strerror(errno)); } } for (scan = copies; *scan != NULL; scan++) { git_buf_joinpath(&link_tgt, "empty_standard_repo/.git", *scan); if (git_path_exists(link_tgt.ptr)) { git_buf_joinpath(&link, "alternate/.git", *scan); cl_git_pass(git_futils_readbuffer(&body, link_tgt.ptr)); cl_assert((link_fd = git_futils_creat_withpath(link.ptr, 0777, 0666)) >= 0); cl_must_pass(p_write(link_fd, body.ptr, body.size)); p_close(link_fd); } } git_buf_free(&link_tgt); git_buf_free(&link); git_buf_free(&body); cl_git_pass(git_repository_open(&repo2, "alternate")); cl_assert(git_repository_path(repo2) != NULL); cl_assert_(git__suffixcmp(git_repository_path(repo2), "alternate/.git/") == 0, git_repository_path(repo2)); cl_assert(git_repository_workdir(repo2) != NULL); cl_assert_(git__suffixcmp(git_repository_workdir(repo2), "alternate/") == 0, git_repository_workdir(repo2)); git_repository_free(repo2); #endif } void test_repo_open__failures(void) { git_repository *base, *repo; git_buf ceiling = GIT_BUF_INIT; base = cl_git_sandbox_init("attr"); cl_git_pass(git_buf_sets(&ceiling, git_repository_workdir(base))); /* fail with no searching */ cl_git_fail(git_repository_open(&repo, "attr/sub")); cl_git_fail(git_repository_open_ext( &repo, "attr/sub", GIT_REPOSITORY_OPEN_NO_SEARCH, NULL)); /* fail with ceiling too low */ cl_git_pass(git_buf_joinpath(&ceiling, ceiling.ptr, "sub")); cl_git_fail(git_repository_open_ext(&repo, "attr/sub", 0, ceiling.ptr)); /* fail with no repo */ cl_git_pass(p_mkdir("alternate", 0777)); cl_git_pass(p_mkdir("alternate/.git", 0777)); cl_git_fail(git_repository_open_ext(&repo, "alternate", 0, NULL)); cl_git_fail(git_repository_open_ext(&repo, "alternate/.git", 0, NULL)); git_buf_free(&ceiling); } void test_repo_open__bad_gitlinks(void) { git_repository *repo; static const char *bad_links[] = { "garbage\n", "gitdir", "gitdir:\n", "gitdir: foobar", "gitdir: ../invalid", "gitdir: ../invalid2", "gitdir: ../attr/.git with extra stuff", NULL }; const char **scan; cl_git_sandbox_init("attr"); cl_git_pass(p_mkdir("alternate", 0777)); cl_git_pass(p_mkdir("invalid", 0777)); cl_git_pass(git_futils_mkdir_r("invalid2/.git", NULL, 0777)); for (scan = bad_links; *scan != NULL; scan++) { cl_git_rewritefile("alternate/.git", *scan); cl_git_fail(git_repository_open_ext(&repo, "alternate", 0, NULL)); } git_futils_rmdir_r("invalid", NULL, GIT_RMDIR_REMOVE_FILES); git_futils_rmdir_r("invalid2", NULL, GIT_RMDIR_REMOVE_FILES); } #ifdef GIT_WIN32 static void unposix_path(git_buf *path) { char *src, *tgt; src = tgt = path->ptr; /* convert "/d/..." to "d:\..." */ if (src[0] == '/' && isalpha(src[1]) && src[2] == '/') { *tgt++ = src[1]; *tgt++ = ':'; *tgt++ = '\\'; src += 3; } while (*src) { *tgt++ = (*src == '/') ? '\\' : *src; src++; } *tgt = '\0'; } #endif void test_repo_open__win32_path(void) { #ifdef GIT_WIN32 git_repository *repo = cl_git_sandbox_init("empty_standard_repo"), *repo2; git_buf winpath = GIT_BUF_INIT; static const char *repo_path = "empty_standard_repo/.git/"; static const char *repo_wd = "empty_standard_repo/"; cl_assert(git__suffixcmp(git_repository_path(repo), repo_path) == 0); cl_assert(git__suffixcmp(git_repository_workdir(repo), repo_wd) == 0); cl_git_pass(git_buf_sets(&winpath, git_repository_path(repo))); unposix_path(&winpath); cl_git_pass(git_repository_open(&repo2, winpath.ptr)); cl_assert(git__suffixcmp(git_repository_path(repo2), repo_path) == 0); cl_assert(git__suffixcmp(git_repository_workdir(repo2), repo_wd) == 0); git_repository_free(repo2); cl_git_pass(git_buf_sets(&winpath, git_repository_path(repo))); git_buf_truncate(&winpath, winpath.size - 1); /* remove trailing '/' */ unposix_path(&winpath); cl_git_pass(git_repository_open(&repo2, winpath.ptr)); cl_assert(git__suffixcmp(git_repository_path(repo2), repo_path) == 0); cl_assert(git__suffixcmp(git_repository_workdir(repo2), repo_wd) == 0); git_repository_free(repo2); cl_git_pass(git_buf_sets(&winpath, git_repository_workdir(repo))); unposix_path(&winpath); cl_git_pass(git_repository_open(&repo2, winpath.ptr)); cl_assert(git__suffixcmp(git_repository_path(repo2), repo_path) == 0); cl_assert(git__suffixcmp(git_repository_workdir(repo2), repo_wd) == 0); git_repository_free(repo2); cl_git_pass(git_buf_sets(&winpath, git_repository_workdir(repo))); git_buf_truncate(&winpath, winpath.size - 1); /* remove trailing '/' */ unposix_path(&winpath); cl_git_pass(git_repository_open(&repo2, winpath.ptr)); cl_assert(git__suffixcmp(git_repository_path(repo2), repo_path) == 0); cl_assert(git__suffixcmp(git_repository_workdir(repo2), repo_wd) == 0); git_repository_free(repo2); git_buf_free(&winpath); #endif } void test_repo_open__opening_a_non_existing_repository_returns_ENOTFOUND(void) { git_repository *repo; cl_assert_equal_i(GIT_ENOTFOUND, git_repository_open(&repo, "i-do-not/exist")); } void test_repo_open__no_config(void) { git_buf path = GIT_BUF_INIT; git_repository *repo; git_config *config; cl_fixture_sandbox("empty_standard_repo"); cl_git_pass(cl_rename("empty_standard_repo/.gitted", "empty_standard_repo/.git")); /* remove local config */ cl_git_pass(git_futils_rmdir_r( "empty_standard_repo/.git/config", NULL, GIT_RMDIR_REMOVE_FILES)); /* isolate from system level configs */ cl_must_pass(p_mkdir("alternate", 0777)); cl_git_pass(git_path_prettify(&path, "alternate", NULL)); cl_git_pass(git_libgit2_opts( GIT_OPT_SET_SEARCH_PATH, GIT_CONFIG_LEVEL_GLOBAL, path.ptr)); cl_git_pass(git_libgit2_opts( GIT_OPT_SET_SEARCH_PATH, GIT_CONFIG_LEVEL_SYSTEM, path.ptr)); cl_git_pass(git_libgit2_opts( GIT_OPT_SET_SEARCH_PATH, GIT_CONFIG_LEVEL_XDG, path.ptr)); git_buf_free(&path); cl_git_pass(git_repository_open(&repo, "empty_standard_repo")); cl_git_pass(git_repository_config(&config, repo)); cl_git_pass(git_config_set_string(config, "test.set", "42")); git_config_free(config); git_repository_free(repo); cl_fixture_cleanup("empty_standard_repo"); } libgit2-0.19.0/tests-clar/repo/repo_helpers.c000066400000000000000000000010321216214232500210100ustar00rootroot00000000000000#include "clar_libgit2.h" #include "refs.h" #include "repo_helpers.h" #include "posix.h" void make_head_orphaned(git_repository* repo, const char *target) { git_reference *head; cl_git_pass(git_reference_symbolic_create(&head, repo, GIT_HEAD_FILE, target, 1)); git_reference_free(head); } void delete_head(git_repository* repo) { git_buf head_path = GIT_BUF_INIT; cl_git_pass(git_buf_joinpath(&head_path, git_repository_path(repo), GIT_HEAD_FILE)); cl_git_pass(p_unlink(git_buf_cstr(&head_path))); git_buf_free(&head_path); } libgit2-0.19.0/tests-clar/repo/repo_helpers.h000066400000000000000000000003041216214232500210160ustar00rootroot00000000000000#include "common.h" #define NON_EXISTING_HEAD "refs/heads/hide/and/seek" extern void make_head_orphaned(git_repository* repo, const char *target); extern void delete_head(git_repository* repo); libgit2-0.19.0/tests-clar/repo/setters.c000066400000000000000000000056751216214232500200330ustar00rootroot00000000000000#include "clar_libgit2.h" #include "git2/sys/repository.h" #include "buffer.h" #include "posix.h" #include "util.h" #include "path.h" #include "fileops.h" static git_repository *repo; void test_repo_setters__initialize(void) { cl_fixture_sandbox("testrepo.git"); cl_git_pass(git_repository_open(&repo, "testrepo.git")); cl_must_pass(p_mkdir("new_workdir", 0777)); } void test_repo_setters__cleanup(void) { git_repository_free(repo); repo = NULL; cl_fixture_cleanup("testrepo.git"); cl_fixture_cleanup("new_workdir"); } void test_repo_setters__setting_a_workdir_turns_a_bare_repository_into_a_standard_one(void) { cl_assert(git_repository_is_bare(repo) == 1); cl_assert(git_repository_workdir(repo) == NULL); cl_git_pass(git_repository_set_workdir(repo, "./new_workdir", false)); cl_assert(git_repository_workdir(repo) != NULL); cl_assert(git_repository_is_bare(repo) == 0); } void test_repo_setters__setting_a_workdir_prettifies_its_path(void) { cl_git_pass(git_repository_set_workdir(repo, "./new_workdir", false)); cl_assert(git__suffixcmp(git_repository_workdir(repo), "new_workdir/") == 0); } void test_repo_setters__setting_a_workdir_creates_a_gitlink(void) { git_config *cfg; const char *val; git_buf content = GIT_BUF_INIT; cl_git_pass(git_repository_set_workdir(repo, "./new_workdir", true)); cl_assert(git_path_isfile("./new_workdir/.git")); cl_git_pass(git_futils_readbuffer(&content, "./new_workdir/.git")); cl_assert(git__prefixcmp(git_buf_cstr(&content), "gitdir: ") == 0); cl_assert(git__suffixcmp(git_buf_cstr(&content), "testrepo.git/") == 0); git_buf_free(&content); cl_git_pass(git_repository_config(&cfg, repo)); cl_git_pass(git_config_get_string(&val, cfg, "core.worktree")); cl_assert(git__suffixcmp(val, "new_workdir/") == 0); git_config_free(cfg); } void test_repo_setters__setting_a_new_index_on_a_repo_which_has_already_loaded_one_properly_honors_the_refcount(void) { git_index *new_index; cl_git_pass(git_index_open(&new_index, "./my-index")); cl_assert(((git_refcount *)new_index)->refcount.val == 1); git_repository_set_index(repo, new_index); cl_assert(((git_refcount *)new_index)->refcount.val == 2); git_repository_free(repo); cl_assert(((git_refcount *)new_index)->refcount.val == 1); git_index_free(new_index); /* * Ensure the cleanup method won't try to free the repo as it's already been taken care of */ repo = NULL; } void test_repo_setters__setting_a_new_odb_on_a_repo_which_already_loaded_one_properly_honors_the_refcount(void) { git_odb *new_odb; cl_git_pass(git_odb_open(&new_odb, "./testrepo.git/objects")); cl_assert(((git_refcount *)new_odb)->refcount.val == 1); git_repository_set_odb(repo, new_odb); cl_assert(((git_refcount *)new_odb)->refcount.val == 2); git_repository_free(repo); cl_assert(((git_refcount *)new_odb)->refcount.val == 1); git_odb_free(new_odb); /* * Ensure the cleanup method won't try to free the repo as it's already been taken care of */ repo = NULL; } libgit2-0.19.0/tests-clar/repo/shallow.c000066400000000000000000000013031216214232500177730ustar00rootroot00000000000000#include "clar_libgit2.h" #include "fileops.h" static git_repository *g_repo; void test_repo_shallow__initialize(void) { } void test_repo_shallow__cleanup(void) { cl_git_sandbox_cleanup(); } void test_repo_shallow__no_shallow_file(void) { g_repo = cl_git_sandbox_init("testrepo.git"); cl_assert_equal_i(0, git_repository_is_shallow(g_repo)); } void test_repo_shallow__empty_shallow_file(void) { g_repo = cl_git_sandbox_init("testrepo.git"); cl_git_mkfile("testrepo.git/shallow", ""); cl_assert_equal_i(0, git_repository_is_shallow(g_repo)); } void test_repo_shallow__shallow_repo(void) { g_repo = cl_git_sandbox_init("shallow.git"); cl_assert_equal_i(1, git_repository_is_shallow(g_repo)); } libgit2-0.19.0/tests-clar/repo/state.c000066400000000000000000000043621216214232500174520ustar00rootroot00000000000000#include "clar_libgit2.h" #include "buffer.h" #include "refs.h" #include "posix.h" #include "fileops.h" static git_repository *_repo; static git_buf _path; void test_repo_state__initialize(void) { _repo = cl_git_sandbox_init("testrepo.git"); } void test_repo_state__cleanup(void) { cl_git_sandbox_cleanup(); git_buf_free(&_path); } static void setup_simple_state(const char *filename) { cl_git_pass(git_buf_joinpath(&_path, git_repository_path(_repo), filename)); git_futils_mkpath2file(git_buf_cstr(&_path), 0777); cl_git_mkfile(git_buf_cstr(&_path), "dummy"); } static void assert_repo_state(git_repository_state_t state) { cl_assert_equal_i(state, git_repository_state(_repo)); } void test_repo_state__none_with_HEAD_attached(void) { assert_repo_state(GIT_REPOSITORY_STATE_NONE); } void test_repo_state__none_with_HEAD_detached(void) { cl_git_pass(git_repository_detach_head(_repo)); assert_repo_state(GIT_REPOSITORY_STATE_NONE); } void test_repo_state__merge(void) { setup_simple_state(GIT_MERGE_HEAD_FILE); assert_repo_state(GIT_REPOSITORY_STATE_MERGE); } void test_repo_state__revert(void) { setup_simple_state(GIT_REVERT_HEAD_FILE); assert_repo_state(GIT_REPOSITORY_STATE_REVERT); } void test_repo_state__cherry_pick(void) { setup_simple_state(GIT_CHERRY_PICK_HEAD_FILE); assert_repo_state(GIT_REPOSITORY_STATE_CHERRY_PICK); } void test_repo_state__bisect(void) { setup_simple_state(GIT_BISECT_LOG_FILE); assert_repo_state(GIT_REPOSITORY_STATE_BISECT); } void test_repo_state__rebase_interactive(void) { setup_simple_state(GIT_REBASE_MERGE_INTERACTIVE_FILE); assert_repo_state(GIT_REPOSITORY_STATE_REBASE_INTERACTIVE); } void test_repo_state__rebase_merge(void) { setup_simple_state(GIT_REBASE_MERGE_DIR "whatever"); assert_repo_state(GIT_REPOSITORY_STATE_REBASE_MERGE); } void test_repo_state__rebase(void) { setup_simple_state(GIT_REBASE_APPLY_REBASING_FILE); assert_repo_state(GIT_REPOSITORY_STATE_REBASE); } void test_repo_state__apply_mailbox(void) { setup_simple_state(GIT_REBASE_APPLY_APPLYING_FILE); assert_repo_state(GIT_REPOSITORY_STATE_APPLY_MAILBOX); } void test_repo_state__apply_mailbox_or_rebase(void) { setup_simple_state(GIT_REBASE_APPLY_DIR "whatever"); assert_repo_state(GIT_REPOSITORY_STATE_APPLY_MAILBOX_OR_REBASE); } libgit2-0.19.0/tests-clar/reset/000077500000000000000000000000001216214232500163365ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/reset/default.c000066400000000000000000000111311216214232500201230ustar00rootroot00000000000000#include "clar_libgit2.h" #include "posix.h" #include "reset_helpers.h" #include "path.h" static git_repository *_repo; static git_object *_target; static git_strarray _pathspecs; static git_index *_index; static void initialize(const char *repo_name) { _repo = cl_git_sandbox_init(repo_name); cl_git_pass(git_repository_index(&_index, _repo)); _target = NULL; _pathspecs.strings = NULL; _pathspecs.count = 0; } void test_reset_default__initialize(void) { initialize("status"); } void test_reset_default__cleanup(void) { git_object_free(_target); _target = NULL; git_index_free(_index); _index = NULL; cl_git_sandbox_cleanup(); } static void assert_content_in_index( git_strarray *pathspecs, bool should_exist, git_strarray *expected_shas) { size_t i, pos; int error; for (i = 0; i < pathspecs->count; i++) { error = git_index_find(&pos, _index, pathspecs->strings[i]); if (should_exist) { const git_index_entry *entry; cl_assert(error != GIT_ENOTFOUND); entry = git_index_get_byindex(_index, pos); cl_assert(entry != NULL); if (!expected_shas) continue; cl_git_pass(git_oid_streq(&entry->oid, expected_shas->strings[i])); } else cl_assert_equal_i(should_exist, error != GIT_ENOTFOUND); } } void test_reset_default__resetting_filepaths_against_a_null_target_removes_them_from_the_index(void) { char *paths[] = { "staged_changes", "staged_new_file" }; _pathspecs.strings = paths; _pathspecs.count = 2; assert_content_in_index(&_pathspecs, true, NULL); cl_git_pass(git_reset_default(_repo, NULL, &_pathspecs)); assert_content_in_index(&_pathspecs, false, NULL); } /* * $ git ls-files --cached -s --abbrev=7 -- "staged*" * 100644 55d316c 0 staged_changes * 100644 a6be623 0 staged_changes_file_deleted * ... * * $ git reset 0017bd4 -- staged_changes staged_changes_file_deleted * Unstaged changes after reset: * ... * * $ git ls-files --cached -s --abbrev=7 -- "staged*" * 100644 32504b7 0 staged_changes * 100644 061d42a 0 staged_changes_file_deleted * ... */ void test_reset_default__resetting_filepaths_replaces_their_corresponding_index_entries(void) { git_strarray before, after; char *paths[] = { "staged_changes", "staged_changes_file_deleted" }; char *before_shas[] = { "55d316c9ba708999f1918e9677d01dfcae69c6b9", "a6be623522ce87a1d862128ac42672604f7b468b" }; char *after_shas[] = { "32504b727382542f9f089e24fddac5e78533e96c", "061d42a44cacde5726057b67558821d95db96f19" }; _pathspecs.strings = paths; _pathspecs.count = 2; before.strings = before_shas; before.count = 2; after.strings = after_shas; after.count = 2; cl_git_pass(git_revparse_single(&_target, _repo, "0017bd4")); assert_content_in_index(&_pathspecs, true, &before); cl_git_pass(git_reset_default(_repo, _target, &_pathspecs)); assert_content_in_index(&_pathspecs, true, &after); } /* * $ git ls-files --cached -s --abbrev=7 -- conflicts-one.txt * 100644 1f85ca5 1 conflicts-one.txt * 100644 6aea5f2 2 conflicts-one.txt * 100644 516bd85 3 conflicts-one.txt * * $ git reset 9a05ccb -- conflicts-one.txt * Unstaged changes after reset: * ... * * $ git ls-files --cached -s --abbrev=7 -- conflicts-one.txt * 100644 1f85ca5 0 conflicts-one.txt * */ void test_reset_default__resetting_filepaths_clears_previous_conflicts(void) { const git_index_entry *conflict_entry[3]; git_strarray after; char *paths[] = { "conflicts-one.txt" }; char *after_shas[] = { "1f85ca51b8e0aac893a621b61a9c2661d6aa6d81" }; test_reset_default__cleanup(); initialize("mergedrepo"); _pathspecs.strings = paths; _pathspecs.count = 1; after.strings = after_shas; after.count = 1; cl_git_pass(git_index_conflict_get(&conflict_entry[0], &conflict_entry[1], &conflict_entry[2], _index, "conflicts-one.txt")); cl_git_pass(git_revparse_single(&_target, _repo, "9a05ccb")); cl_git_pass(git_reset_default(_repo, _target, &_pathspecs)); assert_content_in_index(&_pathspecs, true, &after); cl_assert_equal_i(GIT_ENOTFOUND, git_index_conflict_get(&conflict_entry[0], &conflict_entry[1], &conflict_entry[2], _index, "conflicts-one.txt")); } /* $ git reset HEAD -- "I_am_not_there.txt" "me_neither.txt" Unstaged changes after reset: ... */ void test_reset_default__resetting_unknown_filepaths_does_not_fail(void) { char *paths[] = { "I_am_not_there.txt", "me_neither.txt" }; _pathspecs.strings = paths; _pathspecs.count = 2; assert_content_in_index(&_pathspecs, false, NULL); cl_git_pass(git_revparse_single(&_target, _repo, "HEAD")); cl_git_pass(git_reset_default(_repo, _target, &_pathspecs)); assert_content_in_index(&_pathspecs, false, NULL); } libgit2-0.19.0/tests-clar/reset/hard.c000066400000000000000000000126331216214232500174250ustar00rootroot00000000000000#include "clar_libgit2.h" #include "posix.h" #include "reset_helpers.h" #include "path.h" #include "fileops.h" static git_repository *repo; static git_object *target; void test_reset_hard__initialize(void) { repo = cl_git_sandbox_init("status"); target = NULL; } void test_reset_hard__cleanup(void) { if (target != NULL) { git_object_free(target); target = NULL; } cl_git_sandbox_cleanup(); } static int strequal_ignore_eol(const char *exp, const char *str) { while (*exp && *str) { if (*exp != *str) { while (*exp == '\r' || *exp == '\n') ++exp; while (*str == '\r' || *str == '\n') ++str; if (*exp != *str) return false; } else { exp++; str++; } } return (!*exp && !*str); } void test_reset_hard__resetting_reverts_modified_files(void) { git_buf path = GIT_BUF_INIT, content = GIT_BUF_INIT; int i; static const char *files[4] = { "current_file", "modified_file", "staged_new_file", "staged_changes_modified_file" }; static const char *before[4] = { "current_file\n", "modified_file\nmodified_file\n", "staged_new_file\n", "staged_changes_modified_file\nstaged_changes_modified_file\nstaged_changes_modified_file\n" }; static const char *after[4] = { "current_file\n", "modified_file\n", NULL, "staged_changes_modified_file\n" }; const char *wd = git_repository_workdir(repo); cl_assert(wd); for (i = 0; i < 4; ++i) { cl_git_pass(git_buf_joinpath(&path, wd, files[i])); cl_git_pass(git_futils_readbuffer(&content, path.ptr)); cl_assert_equal_s(before[i], content.ptr); } retrieve_target_from_oid( &target, repo, "26a125ee1bfc5df1e1b2e9441bbe63c8a7ae989f"); cl_git_pass(git_reset(repo, target, GIT_RESET_HARD)); for (i = 0; i < 4; ++i) { cl_git_pass(git_buf_joinpath(&path, wd, files[i])); if (after[i]) { cl_git_pass(git_futils_readbuffer(&content, path.ptr)); cl_assert(strequal_ignore_eol(after[i], content.ptr)); } else { cl_assert(!git_path_exists(path.ptr)); } } git_buf_free(&content); git_buf_free(&path); } void test_reset_hard__cannot_reset_in_a_bare_repository(void) { git_repository *bare; cl_git_pass(git_repository_open(&bare, cl_fixture("testrepo.git"))); cl_assert(git_repository_is_bare(bare) == true); retrieve_target_from_oid(&target, bare, KNOWN_COMMIT_IN_BARE_REPO); cl_assert_equal_i(GIT_EBAREREPO, git_reset(bare, target, GIT_RESET_HARD)); git_repository_free(bare); } static void index_entry_init(git_index *index, int side, git_oid *oid) { git_index_entry entry; memset(&entry, 0x0, sizeof(git_index_entry)); entry.path = "conflicting_file"; entry.flags = (side << GIT_IDXENTRY_STAGESHIFT); entry.mode = 0100644; git_oid_cpy(&entry.oid, oid); cl_git_pass(git_index_add(index, &entry)); } static void unmerged_index_init(git_index *index, int entries) { int write_ancestor = 1; int write_ours = 2; int write_theirs = 4; git_oid ancestor, ours, theirs; git_oid_fromstr(&ancestor, "6bb0d9f700543ba3d318ba7075fc3bd696b4287b"); git_oid_fromstr(&ours, "b19a1e93bec1317dc6097229e12afaffbfa74dc2"); git_oid_fromstr(&theirs, "950b81b7eee953d050aa05a641f8e056c85dd1bd"); cl_git_rewritefile("status/conflicting_file", "conflicting file\n"); if (entries & write_ancestor) index_entry_init(index, 1, &ancestor); if (entries & write_ours) index_entry_init(index, 2, &ours); if (entries & write_theirs) index_entry_init(index, 3, &theirs); } void test_reset_hard__resetting_reverts_unmerged(void) { git_index *index; int entries; /* Ensure every permutation of non-zero stage entries results in the * path being cleaned up. */ for (entries = 1; entries < 8; entries++) { cl_git_pass(git_repository_index(&index, repo)); unmerged_index_init(index, entries); cl_git_pass(git_index_write(index)); retrieve_target_from_oid(&target, repo, "26a125ee1bfc5df1e1b2e9441bbe63c8a7ae989f"); cl_git_pass(git_reset(repo, target, GIT_RESET_HARD)); cl_assert(git_path_exists("status/conflicting_file") == 0); git_object_free(target); target = NULL; git_index_free(index); } } void test_reset_hard__cleans_up_merge(void) { git_buf merge_head_path = GIT_BUF_INIT, merge_msg_path = GIT_BUF_INIT, merge_mode_path = GIT_BUF_INIT, orig_head_path = GIT_BUF_INIT; cl_git_pass(git_buf_joinpath(&merge_head_path, git_repository_path(repo), "MERGE_HEAD")); cl_git_mkfile(git_buf_cstr(&merge_head_path), "beefbeefbeefbeefbeefbeefbeefbeefbeefbeef\n"); cl_git_pass(git_buf_joinpath(&merge_msg_path, git_repository_path(repo), "MERGE_MSG")); cl_git_mkfile(git_buf_cstr(&merge_msg_path), "Merge commit 0017bd4ab1ec30440b17bae1680cff124ab5f1f6\n"); cl_git_pass(git_buf_joinpath(&merge_mode_path, git_repository_path(repo), "MERGE_MODE")); cl_git_mkfile(git_buf_cstr(&merge_mode_path), ""); cl_git_pass(git_buf_joinpath(&orig_head_path, git_repository_path(repo), "ORIG_HEAD")); cl_git_mkfile(git_buf_cstr(&orig_head_path), "0017bd4ab1ec30440b17bae1680cff124ab5f1f6"); retrieve_target_from_oid(&target, repo, "0017bd4ab1ec30440b17bae1680cff124ab5f1f6"); cl_git_pass(git_reset(repo, target, GIT_RESET_HARD)); cl_assert(!git_path_exists(git_buf_cstr(&merge_head_path))); cl_assert(!git_path_exists(git_buf_cstr(&merge_msg_path))); cl_assert(!git_path_exists(git_buf_cstr(&merge_mode_path))); cl_assert(git_path_exists(git_buf_cstr(&orig_head_path))); cl_git_pass(p_unlink(git_buf_cstr(&orig_head_path))); git_buf_free(&merge_head_path); git_buf_free(&merge_msg_path); git_buf_free(&merge_mode_path); git_buf_free(&orig_head_path); } libgit2-0.19.0/tests-clar/reset/mixed.c000066400000000000000000000022551216214232500176140ustar00rootroot00000000000000#include "clar_libgit2.h" #include "posix.h" #include "reset_helpers.h" #include "path.h" static git_repository *repo; static git_object *target; void test_reset_mixed__initialize(void) { repo = cl_git_sandbox_init("attr"); target = NULL; } void test_reset_mixed__cleanup(void) { git_object_free(target); target = NULL; cl_git_sandbox_cleanup(); } void test_reset_mixed__cannot_reset_in_a_bare_repository(void) { git_repository *bare; cl_git_pass(git_repository_open(&bare, cl_fixture("testrepo.git"))); cl_assert(git_repository_is_bare(bare) == true); retrieve_target_from_oid(&target, bare, KNOWN_COMMIT_IN_BARE_REPO); cl_assert_equal_i(GIT_EBAREREPO, git_reset(bare, target, GIT_RESET_MIXED)); git_repository_free(bare); } void test_reset_mixed__resetting_refreshes_the_index_to_the_commit_tree(void) { unsigned int status; cl_git_pass(git_status_file(&status, repo, "macro_bad")); cl_assert(status == GIT_STATUS_CURRENT); retrieve_target_from_oid(&target, repo, "605812ab7fe421fdd325a935d35cb06a9234a7d7"); cl_git_pass(git_reset(repo, target, GIT_RESET_MIXED)); cl_git_pass(git_status_file(&status, repo, "macro_bad")); cl_assert(status == GIT_STATUS_WT_NEW); } libgit2-0.19.0/tests-clar/reset/reset_helpers.c000066400000000000000000000004271216214232500213510ustar00rootroot00000000000000#include "clar_libgit2.h" #include "reset_helpers.h" void retrieve_target_from_oid(git_object **object_out, git_repository *repo, const char *sha) { git_oid oid; cl_git_pass(git_oid_fromstr(&oid, sha)); cl_git_pass(git_object_lookup(object_out, repo, &oid, GIT_OBJ_ANY)); } libgit2-0.19.0/tests-clar/reset/reset_helpers.h000066400000000000000000000004261216214232500213550ustar00rootroot00000000000000#include "common.h" #define KNOWN_COMMIT_IN_BARE_REPO "e90810b8df3e80c413d903f631643c716887138d" #define KNOWN_COMMIT_IN_ATTR_REPO "217878ab49e1314388ea2e32dc6fdb58a1b969e0" extern void retrieve_target_from_oid(git_object **object_out, git_repository *repo, const char *sha); libgit2-0.19.0/tests-clar/reset/soft.c000066400000000000000000000111661216214232500174620ustar00rootroot00000000000000#include "clar_libgit2.h" #include "posix.h" #include "reset_helpers.h" #include "path.h" #include "repo/repo_helpers.h" static git_repository *repo; static git_object *target; void test_reset_soft__initialize(void) { repo = cl_git_sandbox_init("testrepo.git"); } void test_reset_soft__cleanup(void) { git_object_free(target); target = NULL; cl_git_sandbox_cleanup(); } static void assert_reset_soft(bool should_be_detached) { git_oid oid; cl_git_pass(git_reference_name_to_id(&oid, repo, "HEAD")); cl_git_fail(git_oid_streq(&oid, KNOWN_COMMIT_IN_BARE_REPO)); retrieve_target_from_oid(&target, repo, KNOWN_COMMIT_IN_BARE_REPO); cl_assert(git_repository_head_detached(repo) == should_be_detached); cl_git_pass(git_reset(repo, target, GIT_RESET_SOFT)); cl_assert(git_repository_head_detached(repo) == should_be_detached); cl_git_pass(git_reference_name_to_id(&oid, repo, "HEAD")); cl_git_pass(git_oid_streq(&oid, KNOWN_COMMIT_IN_BARE_REPO)); } void test_reset_soft__can_reset_the_non_detached_Head_to_the_specified_commit(void) { assert_reset_soft(false); } void test_reset_soft__can_reset_the_detached_Head_to_the_specified_commit(void) { git_repository_detach_head(repo); assert_reset_soft(true); } void test_reset_soft__resetting_to_the_commit_pointed_at_by_the_Head_does_not_change_the_target_of_the_Head(void) { git_oid oid; char raw_head_oid[GIT_OID_HEXSZ + 1]; cl_git_pass(git_reference_name_to_id(&oid, repo, "HEAD")); git_oid_fmt(raw_head_oid, &oid); raw_head_oid[GIT_OID_HEXSZ] = '\0'; retrieve_target_from_oid(&target, repo, raw_head_oid); cl_git_pass(git_reset(repo, target, GIT_RESET_SOFT)); cl_git_pass(git_reference_name_to_id(&oid, repo, "HEAD")); cl_git_pass(git_oid_streq(&oid, raw_head_oid)); } void test_reset_soft__resetting_to_a_tag_sets_the_Head_to_the_peeled_commit(void) { git_oid oid; /* b25fa35 is a tag, pointing to another tag which points to commit e90810b */ retrieve_target_from_oid(&target, repo, "b25fa35b38051e4ae45d4222e795f9df2e43f1d1"); cl_git_pass(git_reset(repo, target, GIT_RESET_SOFT)); cl_assert(git_repository_head_detached(repo) == false); cl_git_pass(git_reference_name_to_id(&oid, repo, "HEAD")); cl_git_pass(git_oid_streq(&oid, KNOWN_COMMIT_IN_BARE_REPO)); } void test_reset_soft__cannot_reset_to_a_tag_not_pointing_at_a_commit(void) { /* 53fc32d is the tree of commit e90810b */ retrieve_target_from_oid(&target, repo, "53fc32d17276939fc79ed05badaef2db09990016"); cl_git_fail(git_reset(repo, target, GIT_RESET_SOFT)); git_object_free(target); /* 521d87c is an annotated tag pointing to a blob */ retrieve_target_from_oid(&target, repo, "521d87c1ec3aef9824daf6d96cc0ae3710766d91"); cl_git_fail(git_reset(repo, target, GIT_RESET_SOFT)); } void test_reset_soft__resetting_against_an_orphaned_head_repo_makes_the_head_no_longer_orphaned(void) { git_reference *head; retrieve_target_from_oid(&target, repo, KNOWN_COMMIT_IN_BARE_REPO); make_head_orphaned(repo, NON_EXISTING_HEAD); cl_assert_equal_i(true, git_repository_head_orphan(repo)); cl_git_pass(git_reset(repo, target, GIT_RESET_SOFT)); cl_assert_equal_i(false, git_repository_head_orphan(repo)); cl_git_pass(git_reference_lookup(&head, repo, NON_EXISTING_HEAD)); cl_assert_equal_i(0, git_oid_streq(git_reference_target(head), KNOWN_COMMIT_IN_BARE_REPO)); git_reference_free(head); } void test_reset_soft__fails_when_merging(void) { git_buf merge_head_path = GIT_BUF_INIT; cl_git_pass(git_repository_detach_head(repo)); cl_git_pass(git_buf_joinpath(&merge_head_path, git_repository_path(repo), "MERGE_HEAD")); cl_git_mkfile(git_buf_cstr(&merge_head_path), "beefbeefbeefbeefbeefbeefbeefbeefbeefbeef\n"); retrieve_target_from_oid(&target, repo, KNOWN_COMMIT_IN_BARE_REPO); cl_assert_equal_i(GIT_EUNMERGED, git_reset(repo, target, GIT_RESET_SOFT)); cl_git_pass(p_unlink(git_buf_cstr(&merge_head_path))); git_buf_free(&merge_head_path); } void test_reset_soft__fails_when_index_contains_conflicts_independently_of_MERGE_HEAD_file_existence(void) { git_index *index; git_reference *head; git_buf merge_head_path = GIT_BUF_INIT; cl_git_sandbox_cleanup(); repo = cl_git_sandbox_init("mergedrepo"); cl_git_pass(git_buf_joinpath(&merge_head_path, git_repository_path(repo), "MERGE_HEAD")); cl_git_pass(p_unlink(git_buf_cstr(&merge_head_path))); git_buf_free(&merge_head_path); cl_git_pass(git_repository_index(&index, repo)); cl_assert_equal_i(true, git_index_has_conflicts(index)); git_index_free(index); cl_git_pass(git_repository_head(&head, repo)); cl_git_pass(git_reference_peel(&target, head, GIT_OBJ_COMMIT)); git_reference_free(head); cl_assert_equal_i(GIT_EUNMERGED, git_reset(repo, target, GIT_RESET_SOFT)); } libgit2-0.19.0/tests-clar/resources/000077500000000000000000000000001216214232500172265ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/.gitattributes000066400000000000000000000000111216214232500221110ustar00rootroot00000000000000* binary libgit2-0.19.0/tests-clar/resources/.gitignore000066400000000000000000000000151216214232500212120ustar00rootroot00000000000000discover.git libgit2-0.19.0/tests-clar/resources/attr/000077500000000000000000000000001216214232500202005ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/attr/.gitted/000077500000000000000000000000001216214232500215365ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/attr/.gitted/HEAD000066400000000000000000000000271216214232500221610ustar00rootroot00000000000000ref: refs/heads/master libgit2-0.19.0/tests-clar/resources/attr/.gitted/config000066400000000000000000000001571216214232500227310ustar00rootroot00000000000000[core] repositoryformatversion = 0 filemode = true bare = false logallrefupdates = true ignorecase = true libgit2-0.19.0/tests-clar/resources/attr/.gitted/description000066400000000000000000000001111216214232500237750ustar00rootroot00000000000000Unnamed repository; edit this file 'description' to name the repository. libgit2-0.19.0/tests-clar/resources/attr/.gitted/index000066400000000000000000000035001216214232500225660ustar00rootroot00000000000000DIRCO NO N Uo{J\wܢ&attr0O NO N;tz]ҏjattr1O NO N(,fOwncAa,-attr2O NO N ąZJvlattr3O NO N!msĦ+ w7^binfileN0N094Z+@ŬYN6iJ gitattributesO NO N(X{2Zwomܧ macro_badO NO N)ic ?3A`ًH+ macro_testO NO N*EyxBŚc"" NKN= root_test1O NO N+=Mq=Ďk[ a:Vt] root_test2O NO N,{I ?rsn root_test3OO ݠ!zZ4΢g_[root_test4.txtO NO N0>BJf?%=lq>BIsub/abcO NO N3E6<ܜl{Wsub/fileO NO N8E6<ܜl{W sub/sub/fileO NO N9[G֨+0It#`Bsub/sub/subsub.txtO NO N:cGXFKvjIsub/subdir_test1O NO N; PgK7rU}xsub/subdir_test2.txtNN94bvoI"Ix^ʦŻgsubdir/.gitattributesNN94>BJf?%=lq>BI subdir/abcNN91cGXFKvjIsubdir/subdir_test1NN91 PgK7rU}xsubdir/subdir_test2.txtNN91F-=mjDAsubdir2/subdir2_test19*,+61fA libgit2-0.19.0/tests-clar/resources/attr/.gitted/info/000077500000000000000000000000001216214232500224715ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/attr/.gitted/info/attributes000066400000000000000000000001071216214232500246000ustar00rootroot00000000000000* repoattr a* foo !bar -baz sub/*.txt reposub sub/sub/*.txt reposubsub libgit2-0.19.0/tests-clar/resources/attr/.gitted/info/exclude000066400000000000000000000003601216214232500240440ustar00rootroot00000000000000# git ls-files --others --exclude-from=.git/info/exclude # Lines that start with '#' are comments. # For a project mostly in C, the following would be a good set of # exclude patterns (uncomment them if you want to use them): # *.[oa] # *~ libgit2-0.19.0/tests-clar/resources/attr/.gitted/logs/000077500000000000000000000000001216214232500225025ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/attr/.gitted/logs/HEAD000066400000000000000000000030311216214232500231230ustar00rootroot000000000000000000000000000000000000000000000000000000 6bab5c79cd5140d0f800917f550eb2a3dc32b0da Russell Belfer 1324416995 -0800 commit (initial): initial test data 6bab5c79cd5140d0f800917f550eb2a3dc32b0da 605812ab7fe421fdd325a935d35cb06a9234a7d7 Russell Belfer 1325143098 -0800 commit: latest test updates 605812ab7fe421fdd325a935d35cb06a9234a7d7 a5d76cad53f66f1312bd995909a5bab3c0820770 Russell Belfer 1325281762 -0800 commit: more macro tests a5d76cad53f66f1312bd995909a5bab3c0820770 370fe9ec224ce33e71f9e5ec2bd1142ce9937a6a Russell Belfer 1327611749 -0800 commit: Updating files so we can do diffs 370fe9ec224ce33e71f9e5ec2bd1142ce9937a6a f5b0af1fb4f5c0cd7aad880711d368a07333c307 Russell Belfer 1327621027 -0800 commit: Updating test data f5b0af1fb4f5c0cd7aad880711d368a07333c307 a97cc019851d401a4f1d091cb91a15890a0dd1ba Russell Belfer 1328653313 -0800 commit: Some whitespace only changes for testing purposes a97cc019851d401a4f1d091cb91a15890a0dd1ba 217878ab49e1314388ea2e32dc6fdb58a1b969e0 Russell Belfer 1332734901 -0700 commit: added files in sub/sub 217878ab49e1314388ea2e32dc6fdb58a1b969e0 24fa9a9fc4e202313e24b648087495441dab432b Russell Belfer 1332735555 -0700 commit: adding more files in sub for tree status 24fa9a9fc4e202313e24b648087495441dab432b 8d0b9df9bd30be7910ddda60548d485bc302b911 yorah 1341230701 +0200 commit: Updating test data so we can test inter-hunk-context libgit2-0.19.0/tests-clar/resources/attr/.gitted/logs/refs/000077500000000000000000000000001216214232500234415ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/attr/.gitted/logs/refs/heads/000077500000000000000000000000001216214232500245255ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/attr/.gitted/logs/refs/heads/master000066400000000000000000000030311216214232500257400ustar00rootroot000000000000000000000000000000000000000000000000000000 6bab5c79cd5140d0f800917f550eb2a3dc32b0da Russell Belfer 1324416995 -0800 commit (initial): initial test data 6bab5c79cd5140d0f800917f550eb2a3dc32b0da 605812ab7fe421fdd325a935d35cb06a9234a7d7 Russell Belfer 1325143098 -0800 commit: latest test updates 605812ab7fe421fdd325a935d35cb06a9234a7d7 a5d76cad53f66f1312bd995909a5bab3c0820770 Russell Belfer 1325281762 -0800 commit: more macro tests a5d76cad53f66f1312bd995909a5bab3c0820770 370fe9ec224ce33e71f9e5ec2bd1142ce9937a6a Russell Belfer 1327611749 -0800 commit: Updating files so we can do diffs 370fe9ec224ce33e71f9e5ec2bd1142ce9937a6a f5b0af1fb4f5c0cd7aad880711d368a07333c307 Russell Belfer 1327621027 -0800 commit: Updating test data f5b0af1fb4f5c0cd7aad880711d368a07333c307 a97cc019851d401a4f1d091cb91a15890a0dd1ba Russell Belfer 1328653313 -0800 commit: Some whitespace only changes for testing purposes a97cc019851d401a4f1d091cb91a15890a0dd1ba 217878ab49e1314388ea2e32dc6fdb58a1b969e0 Russell Belfer 1332734901 -0700 commit: added files in sub/sub 217878ab49e1314388ea2e32dc6fdb58a1b969e0 24fa9a9fc4e202313e24b648087495441dab432b Russell Belfer 1332735555 -0700 commit: adding more files in sub for tree status 24fa9a9fc4e202313e24b648087495441dab432b 8d0b9df9bd30be7910ddda60548d485bc302b911 yorah 1341230701 +0200 commit: Updating test data so we can test inter-hunk-context libgit2-0.19.0/tests-clar/resources/attr/.gitted/objects/000077500000000000000000000000001216214232500231675ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/attr/.gitted/objects/10/000077500000000000000000000000001216214232500234075ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/attr/.gitted/objects/10/8bb4e7fd7b16490dc33ff7d972151e73d7166e000066400000000000000000000002021216214232500305570ustar00rootroot00000000000000x%10Cs o HzT! ap< |2RșH )l$`zeK(Vv۰DC& ( Fɀj{c6ͫ :S/ 4libgit2-0.19.0/tests-clar/resources/attr/.gitted/objects/16/000077500000000000000000000000001216214232500234155ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/attr/.gitted/objects/16/983da6643656bb44c43965ecb6855c6d574512000066400000000000000000000006761216214232500303060ustar00rootroot00000000000000x+)JMU056c040031QH,))2`ibZ΢=m،vF.j1i#y˓9&H-ڣw I1ÑՏz-ۼly?ȁ*HKIeБ;XeG`fg\TZZ̠pt ~+.3;c̍^PrS"$^f6Z~O;QM*a#yΣgV UU_Rd*"Ud)J\~lU1˖͛{)XtU [=lf\uܺr'0DV`ĠyOC̗ns5n ݁libgit2-0.19.0/tests-clar/resources/attr/.gitted/objects/21/000077500000000000000000000000001216214232500234115ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/attr/.gitted/objects/21/7878ab49e1314388ea2e32dc6fdb58a1b969e0000066400000000000000000000002471216214232500305660ustar00rootroot00000000000000xQ 0D)nD#xmvJ߀7cx0Iۺ -+e"v☝pwcJH1x%HL>Dd xC\ʤzᔶd0Z#mغڰ y >{qKlibgit2-0.19.0/tests-clar/resources/attr/.gitted/objects/24/000077500000000000000000000000001216214232500234145ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/attr/.gitted/objects/24/fa9a9fc4e202313e24b648087495441dab432b000066400000000000000000000002641216214232500304020ustar00rootroot00000000000000xi1C*nYϵa !%ly30`{tH+@.JdLS.lb6'G*$MƙɅpvsYbR#Wk6VP.&n?8g!z׬G?eY'guCv%*ctү~S libgit2-0.19.0/tests-clar/resources/attr/.gitted/objects/29/000077500000000000000000000000001216214232500234215ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/attr/.gitted/objects/29/29de282ce999e95183aedac6451d3384559c4b000066400000000000000000000000721216214232500305240ustar00rootroot00000000000000x+)JMU01d040031Q(.MJ,2/I-.1dsꖛ5O5#libgit2-0.19.0/tests-clar/resources/attr/.gitted/objects/2b/000077500000000000000000000000001216214232500234725ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/attr/.gitted/objects/2b/40c5aca159b04ea8d20ffe36cdf8b09369b14a000066400000000000000000000004151216214232500310320ustar00rootroot00000000000000xmPj0=P8ZSc hR6{=ob"afv#3ά=7P%[8 yNlͣ>c;gӐkYX9b|D~Vؗ)vܕlibgit2-0.19.0/tests-clar/resources/attr/.gitted/objects/2c/000077500000000000000000000000001216214232500234735ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/attr/.gitted/objects/2c/66e14f77196ea763fb1e41612c1aa2bc2d8ed2000066400000000000000000000004741216214232500307040ustar00rootroot00000000000000xuQKO0 _mIkxrzmDTO m )pjjbG (ZUb@݀~ S[!+Xܦ 5VIяѓ99L"}Q[͸;~q&OЏ^]FqĖ^E ܞ5ܯaDH#`R)4KI 2$?&E[V۪Nf7؇5_O{_I-*HFܠ8sڊoig|e/$16Ksyy! g7/`P 7'ʹlibgit2-0.19.0/tests-clar/resources/attr/.gitted/objects/2d/000077500000000000000000000000001216214232500234745ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/attr/.gitted/objects/2d/e7dfe3588f3c7e9ad59e7d50ba90e3329df9d9000066400000000000000000000001741216214232500311160ustar00rootroot00000000000000x+)JMU042c040031QK,I,))L*-I-f8n9o$ ͗UwO,.MJ,*1dx|=5֯|S^IE >m>wEk+7libgit2-0.19.0/tests-clar/resources/attr/.gitted/objects/37/000077500000000000000000000000001216214232500234205ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/attr/.gitted/objects/37/0fe9ec224ce33e71f9e5ec2bd1142ce9937a6a000066400000000000000000000002611216214232500307750ustar00rootroot00000000000000xNi1̷8I'0! Xiwdܾ_ІCFƻ:.a OYnzj՞)3_^IP(&t}ucmV"fEx}<-KsW\XNR;t~˟! ɚ+]c>; )d*?BzSI8bB2libgit2-0.19.0/tests-clar/resources/attr/.gitted/objects/60/000077500000000000000000000000001216214232500234145ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/attr/.gitted/objects/60/5812ab7fe421fdd325a935d35cb06a9234a7d7000066400000000000000000000002421216214232500305370ustar00rootroot00000000000000xN 0;S˻BU J ?lٖygcáU RbacG;l㠝Dq֠ZʫAH<Ǒ3N=J2d3[0= }ۤI™jM"x/[TwU&[/k(tJLlibgit2-0.19.0/tests-clar/resources/attr/.gitted/objects/6b/000077500000000000000000000000001216214232500234765ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/attr/.gitted/objects/6b/ab5c79cd5140d0f800917f550eb2a3dc32b0da000066400000000000000000000002071216214232500307360ustar00rootroot00000000000000x 0 E)@d'~@(#tQiQn޷(Pm"Ř2hs L+d{"{Z`u O4Y[޷;@>MSOmʧh * <-libgit2-0.19.0/tests-clar/resources/attr/.gitted/objects/6d/000077500000000000000000000000001216214232500235005ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/attr/.gitted/objects/6d/968d62c89c7d9ea23a4c9a7b665d017c3d8ffd000066400000000000000000000006461216214232500310330ustar00rootroot00000000000000x+)JMU050c040031QH,))2`ibZ΢=m،vF.j1i#y˓9&H-ڣw I1ÑՏz-ۼly?ȁ*HKIeБ;XeG`fg\TZZ̠pt ~+.3;c̍^PrS"$^f6Z~O;QM*a#yΣgV UU_Rd*"Ud)J\~lU1˖͛{)XtU [=lf\uܺr'0DV`ĠyOC̗ns5n [Elibgit2-0.19.0/tests-clar/resources/attr/.gitted/objects/8d/000077500000000000000000000000001216214232500235025ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/attr/.gitted/objects/8d/0b9df9bd30be7910ddda60548d485bc302b911000066400000000000000000000002751216214232500307070ustar00rootroot00000000000000xKj1D)zoli _"hiK2LG!7ȪJ,EPXDS ] /)}/UwR. jp##:?:|;F9܋r=_ )ơN/A[l!q}<Lfx4H\\q֏cjTlibgit2-0.19.0/tests-clar/resources/attr/.gitted/objects/93/000077500000000000000000000000001216214232500234225ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/attr/.gitted/objects/93/61f40bb97239cf55811892e14de2e344168ba1000066400000000000000000000000551216214232500303370ustar00rootroot00000000000000x+)JMU06`01$?]=9F5=~#libgit2-0.19.0/tests-clar/resources/attr/.gitted/objects/94/000077500000000000000000000000001216214232500234235ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/attr/.gitted/objects/94/da4faa0a6bfb8ee6ccf7153801a69202b31857000066400000000000000000000001741216214232500307040ustar00rootroot00000000000000xe @C~Ez=%"2St(ԯ[P8]SurXex;r}$ND.^L/{:SiƤIH tK-O-瘨#hn%$ GZW?oV>z  )3/-3'CGbGis1gc\K s=c7^f-mAE%`E "R+JV¬]QReWRQ; }knyݳbQ  P(.MJ,b;3ϭ-wBMdF 4t^|ؼ1WY9cFlibgit2-0.19.0/tests-clar/resources/attr/.gitted/objects/a5/d76cad53f66f1312bd995909a5bab3c0820770000066400000000000000000000002431216214232500305450ustar00rootroot00000000000000x] !E{vB>!"ZB;u3Cm {.7Z4avfgBLEeP;NQڬBLAnŲI 5I)M6ZQ[ h3e:  }u};|)z&pbq?3TJ13JXlibgit2-0.19.0/tests-clar/resources/attr/.gitted/objects/a9/000077500000000000000000000000001216214232500235005ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/attr/.gitted/objects/a9/7cc019851d401a4f1d091cb91a15890a0dd1ba000066400000000000000000000002771216214232500306040ustar00rootroot00000000000000xQj0 DS[hc;PJ( $q޾ޠ_3oIK+BtI|Lgƈ ŐR4'=qFN64 J1FrzW[rV6-i7.eVW;X, mwl|]ṬMɢdRwC[W9sj~Wylibgit2-0.19.0/tests-clar/resources/attr/.gitted/objects/b4/000077500000000000000000000000001216214232500234745ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/attr/.gitted/objects/b4/35cd5689a0fb54afbeda4ac20368aa480e8f04000066400000000000000000000000501216214232500310310ustar00rootroot00000000000000xKOR06f00426153bdbfaecdBmlibgit2-0.19.0/tests-clar/resources/attr/.gitted/objects/c0/000077500000000000000000000000001216214232500234715ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/attr/.gitted/objects/c0/091889c0c77142b87a1fa5123a6398a61d33e7000066400000000000000000000004421216214232500303270ustar00rootroot00000000000000x+)JMU04g040031QK,I,))L*-I-fty(l f(BUT04Uy1Y]~gў͏6lFR``]rjs@KMSg5͘4 INCrɼɿuHQ{mP{G@Yb*"Ud)J\~lUʘ(U&z%% 7Fꖷ=/ޯ01Ҥ"Gͺ:6`ׄFsDV`ĠyOC̗ns5n Mןlibgit2-0.19.0/tests-clar/resources/attr/.gitted/objects/c4/000077500000000000000000000000001216214232500234755ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/attr/.gitted/objects/c4/85abe35abd4aa6fd83b076a78bbea9e2e7e06c000066400000000000000000000002011216214232500312600ustar00rootroot00000000000000x-ʱ 0Faܺr'0DV`ĠyOC̗ns5n z^libgit2-0.19.0/tests-clar/resources/attr/.gitted/objects/d8/000077500000000000000000000000001216214232500235025ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/attr/.gitted/objects/d8/00886d9c86731ae5c4a62b0b77c437015e00d2000066400000000000000000000000221216214232500303740ustar00rootroot00000000000000xKOR0f042libgit2-0.19.0/tests-clar/resources/attr/.gitted/objects/dc/000077500000000000000000000000001216214232500235555ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/attr/.gitted/objects/dc/cada462d3df8ac6de596fb8c896aba9344f941000066400000000000000000000000431216214232500312270ustar00rootroot00000000000000xKOR0dHWH+U(.MJ,2zlibgit2-0.19.0/tests-clar/resources/attr/.gitted/objects/de/000077500000000000000000000000001216214232500235575ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/attr/.gitted/objects/de/863bff4976c9ed7e17a4da0fd524908dc84049000066400000000000000000000100231216214232500307370ustar00rootroot00000000000000xblob 4094PNG  IHDR@@iq pHYs%%IR$IDATx[ >g0,Jm-5MAAZ`bKآVbbbikkQ!Zq . 03̼y?{3o=ɝ{ssk|)uV:Mt+9ψwGJB:%\ktd1?0hpDh~>i%{چL!Ap1ό10Rc(0!`4[t1oLhQ%wޑ7J3^ [c-07`1%g# ..~zco+tbMʩ^(;%Ou,է;d~*qIbRnky/\;cg 7KK] I9ܿgձ ȱ8d0>nQVN']s9 ]Z17' %tM*D`"wtWuMZF ̾OűH)Qn\J:^-#]hY8] k"}Zw)EtYKaPcP봟U<(>ۆ27}k=shˠX ]2 tXG Gg}9!Ic=EGs_su|k F< v`wˌ 8>P*,o[tsߚKPn$][R+м]Ny & 'dhɑOsg\ۘձ)}XwfD!m+x?8őb I%)# % 쟋jc;eDUiћ; wG+0xړT*ZuFuQ9f:+$'0z)s>ʰn6j n_s8UH12$*@`RX|Iwr3@vms\Snr7׮^-=>۝8ap_ i{XoײL5OY8 }w3 Zz1xC@t>,p E̓U6X~K\c굎8`q]Nc S×Aˡ`%x؁Sx=iX'D\ 0#LLT1Nβ ׳MYG~`߮0)\u[H.o)6VVa4ϘLÈ"r\kU"XkC)7K먂 |n60* :L {DåxCeu. uT>w@By(椼Q3`c8x@LI,gR9 YfQSa&vh}.ֿfkG1'9s fbH0O|EezIDp/9ڝ̫) *`XAyM[{uʼn@@M`'2Ԥ\4|,+Ts}.f|ZtɳMW2E#ϵT$U2u_kT_ of ]e0!/Th\,۠| L w<\qTQ~LҲZY}2]A' *_^fW(&PWi j_~1 RoIENDB`olibgit2-0.19.0/tests-clar/resources/attr/.gitted/objects/e5/000077500000000000000000000000001216214232500235005ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/attr/.gitted/objects/e5/63cf4758f0d646f1b14b76016aa17fa9e549a4000066400000000000000000000000471216214232500305610ustar00rootroot00000000000000xKOR02fHWH+U(HU(.MJ,h libgit2-0.19.0/tests-clar/resources/attr/.gitted/objects/ec/000077500000000000000000000000001216214232500235565ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/attr/.gitted/objects/ec/b97df2a174987475ac816e3847fc8e9f6c596b000066400000000000000000000002531216214232500307050ustar00rootroot00000000000000x+)JMU047g040031QHLJfs+~ vNP̜Tם̶۰wܙg{?M @4sWOtsO'3H+T7P:%($Điy>n.cZXLuFz%% 7Fꖷ=/ޯ!Llibgit2-0.19.0/tests-clar/resources/attr/.gitted/objects/ed/000077500000000000000000000000001216214232500235575ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/attr/.gitted/objects/ed/f3dcee4003d71f139777898882ccd097e34c53000066400000000000000000000142211216214232500306020ustar00rootroot00000000000000xyblob 6268PNG  IHDR@@iq pHYs%%IR$.IDATxZ pTוw[@H@`F&`l&)xf&R5q͒+v;8q!33%0, Bڐn{j-,ۻK&En/2xb|5y0|RѲ@g6T*0C3.R'ud2>ے;֣G;6}\h0l6M7&)G1 E$c1F8ŢW<: ԘLƇ,zj6L&A GW\'(ɋI0DR^bѨDh(v4D%cU濵8[1͢u:P6E\.q:0OV@+~#a 4"H(Ph4q݁Ll gfϹf $/zTrseve,rU mzdT\1"$>v)wklbB"p8$`PC ݙÇ/ŀW?d˱4pZHG/>]V/_.J)z~,Ԛ]qIpf!0 |Nu( gG]iE p07u:sr~I /0[aw:puAESȆ5kdb D:8GMf0LӲk>Q3 &2?u:̀9V9-fsN\1)Kkk0+ WC!lFhd2Q5h NZJ#ٳW?' 0p?֤55+[%n ks'|StxE?@k8&EQC)М1@L(z9tzB`B@|^Ç}Lx:iTTTX3_vot;6o$gLpRtfc׮OHN\{T#3Xf9.$ɄvuKSSSH{#A{Yμ<KM6ȌbɄ(^&x>BQ5-]$+DFxqqyR`͚:t\Tn}>8lzJ8C<4-H3k<'QMb4\pz \Ώ j _pYSi0&y d 4q9 Xb& _S<=5g.Ö#$Hϙ#Azz8=<}㒝DޘL` :HS +yM;!ޕ_d܊*!"cS==UH"Xbİ{n&b8wig5_m~`JѼ\ /G e5(ceįg 5f(' ?X=dOOo? fj@-aNfYItvX?g̠92,:1-H!/چǞd闭߰d31窐jDŽ"GXs]k07L)3SRdFv;0*Jʘ ^f99.I,63brZjX԰"`O$`X. WRHǂvgXx!۴0Y^ Bb#FI((͠X &aL mMzZV8'456ȞwGNpT_ + UΛ A)ȞvyX_/ 1Ua̹b*m"SN D3ŀQNbCEӖ āN>+?/|a\* uR@ CIJ&BJ<^wo|)ta9ALH}vw;+`1Fiիg,fTpSŘ P~ӲW_ZJbv C:O=BX eo+7mRb@_f#X67κ#^C}m6;K#G^g(Po[ z|1(,Dlq6w ^0a|و(X`<8 ~M?TUU!3ɢEF\?>p }[o?g, >m*L7NhߋдSJU޹slݺUniiAyͩ;Xgap>b!&b#04,6UIJBG,sKjr͛S(6innٳ>`+a8ݒw(h{| <'M7JWWn9`bg#4v0 1z((  U\S)z|x^_oS"5V'Xt$ʕ+iFy 魵e,uJՋ1)1Cc<%qCH +Q ++R@,Ĥ7hcj ao(%hF/ôXV+@1O<)Cp.:7T1 Hi4=OWT a <A0#9 Ѐ)Q FM؀V[k*DP RQF:ky|FVQ]<,W>g ٜSbRywx~0z~ @c,b#Fq`UOlO40c:4 ި$(GBkHT/Yehx5P͂ %â9OsCs#c4<1F")iOu5H_ $BcC864(9.o ` dqMtڮ>9r0 Dd72Ʊ4)@=9T޽^m۔:P$RMR!hEZZVW9(pwO97T!בò[Td+Ӛ !^hoX002…Q!甃CشUsNtiuiE:gvHA\$X]pJC%{$ư<:$DFJ[Cou\нРyciG2|UwN2DˆvvZPP$/]}?'J*l cۜILfX kˁ=E..g͜%V\- jwOG:lGѓJ9xD|Zp(d\%KR\Qnx`9 =q=0eɤ޾>U$xF: &m؝fZ#M3_`݋MMr6;̪c9vvg3zjQۍGwލ*S{PCW5x4]2 aãS}jA,{.w^N*E-'H3^!'=27Ѹ tj߾gMF4Ѵ057?L 0'!k6$6ܧƳ}<:Ti=6~y{IK1w ׸Qou_"x<"F&d&LQH߂­P1 hI)Ԓ$ҩ#Gb\),.PzI%6C9d4iBЀr{ sRGd N[.|H#"x~&CSB 0@avEnN1gp6|yI$$n ;~ [P[QV %A6lxKwߖ7^]^\#~U~7a.<:ʊ*|4YU%.3²M*&Y6 qhT `VPZZcϜԒE5@{ Y0=YXݐ(e/dGJ@^jMS=-)E bFҌN"g=XY:޽π.g",x<{Q'gL3A];!s{<Qll Z`Tw_L`gKv4Qa * ]g4T-o UXbn\r=2sqNŁtN6b:طPg9ϤSkMD'#ŵWV=P4s =_0HYt[X;a*=r )(G>8 =ܔl;ɽ{<4gsI3d5ئWVVW.Zye2%LI9[!,wR*S zuȅ֖3 >,#<?*IfgPv.%wϺ`L <$9v`#:-B+cUhďKmWLpd-ӦO\]%Lms}wO .\:Sq1@#|^S'eU*+](*ʱPK? z{olzkf8#)1:ܻv@*j55 `W& Q2cksW Tk,[ x542NkVW]ht# 8 G ՙY4]~Yۮ*Yg'3xkL0x7ރ8ϯj\@`Mܢfv`Nqrk1 gOé :0_9d2mq&IENDB`<libgit2-0.19.0/tests-clar/resources/attr/.gitted/objects/f2/000077500000000000000000000000001216214232500234765ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/attr/.gitted/objects/f2/c6d717cf4a5a3e6b02684155ab07b766982165000066400000000000000000000000541216214232500304140ustar00rootroot00000000000000xKOR05aR(/I,))1KRKt1\libgit2-0.19.0/tests-clar/resources/attr/.gitted/objects/f5/000077500000000000000000000000001216214232500235015ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/attr/.gitted/objects/f5/b0af1fb4f5c0cd7aad880711d368a07333c307000066400000000000000000000002451216214232500306700ustar00rootroot00000000000000xN[j1 ̷O 4RbPJ =;N A?y 1y~7Z(2be8uJanF.H" UD_HIsvZwL=0TZG_UbKo̮}cv?hYB'ۛ" ,\{ README.mdOO&FL4Γ'NRRd README.txtO|O|'!WEKWΩָ}߲ o-sub/sub/.gitattributesO5O5' Ye.4v 6؃Ē2̮'sub/sub/README.mdO3O3' Ye.4v 6؃Ē2̮'sub/sub/README.txtq)B Pwk<libgit2-0.19.0/tests-clar/resources/attr_index/.gitted/info/000077500000000000000000000000001216214232500236605ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/attr_index/.gitted/info/exclude000066400000000000000000000003601216214232500252330ustar00rootroot00000000000000# git ls-files --others --exclude-from=.git/info/exclude # Lines that start with '#' are comments. # For a project mostly in C, the following would be a good set of # exclude patterns (uncomment them if you want to use them): # *.[oa] # *~ libgit2-0.19.0/tests-clar/resources/attr_index/.gitted/info/refs000066400000000000000000000000731216214232500245420ustar00rootroot0000000000000058f7cf825b553ef7c26e5b9f8a23599c1a9ca296 refs/heads/master libgit2-0.19.0/tests-clar/resources/attr_index/.gitted/logs/000077500000000000000000000000001216214232500236715ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/attr_index/.gitted/logs/HEAD000066400000000000000000000012001216214232500243060ustar00rootroot000000000000000000000000000000000000000000000000000000 67c1640e91ccbaf0793591be09bf572cf40c9a53 Russell Belfer 1335817070 -0700 commit (initial): Initial commit 67c1640e91ccbaf0793591be09bf572cf40c9a53 d441d7d88f52c28c2b23940ce4c33756748425f9 Russell Belfer 1335817296 -0700 commit: Adding some files in subtrees d441d7d88f52c28c2b23940ce4c33756748425f9 67c1640e91ccbaf0793591be09bf572cf40c9a53 Russell Belfer 1335817353 -0700 HEAD^: updating HEAD 67c1640e91ccbaf0793591be09bf572cf40c9a53 58f7cf825b553ef7c26e5b9f8a23599c1a9ca296 Russell Belfer 1335817372 -0700 commit: Adding subtree data libgit2-0.19.0/tests-clar/resources/attr_index/.gitted/logs/refs/000077500000000000000000000000001216214232500246305ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/attr_index/.gitted/logs/refs/heads/000077500000000000000000000000001216214232500257145ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/attr_index/.gitted/logs/refs/heads/master000066400000000000000000000012001216214232500271230ustar00rootroot000000000000000000000000000000000000000000000000000000 67c1640e91ccbaf0793591be09bf572cf40c9a53 Russell Belfer 1335817070 -0700 commit (initial): Initial commit 67c1640e91ccbaf0793591be09bf572cf40c9a53 d441d7d88f52c28c2b23940ce4c33756748425f9 Russell Belfer 1335817296 -0700 commit: Adding some files in subtrees d441d7d88f52c28c2b23940ce4c33756748425f9 67c1640e91ccbaf0793591be09bf572cf40c9a53 Russell Belfer 1335817353 -0700 HEAD^: updating HEAD 67c1640e91ccbaf0793591be09bf572cf40c9a53 58f7cf825b553ef7c26e5b9f8a23599c1a9ca296 Russell Belfer 1335817372 -0700 commit: Adding subtree data libgit2-0.19.0/tests-clar/resources/attr_index/.gitted/objects/000077500000000000000000000000001216214232500243565ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/attr_index/.gitted/objects/38/000077500000000000000000000000001216214232500246105ustar00rootroot0000000000000012cfef36615db1788d4e63f90028007e17a348000066400000000000000000000002471216214232500314530ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/attr_index/.gitted/objects/38x[ E*@PJ ]&`w 'oMKDq45DF#!!=VZD.L:%L}!dCg*qв-LUkz~6閷W}}>g˾{f% Glibgit2-0.19.0/tests-clar/resources/attr_index/.gitted/objects/59/000077500000000000000000000000001216214232500246135ustar00rootroot00000000000000d942b8be2784bc96db9b22202c10815c9a077b000066400000000000000000000001101216214232500315730ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/attr_index/.gitted/objects/59x 0 @@kR@]GgXς[U>n[#YYe.4v 6؃Ē2̮'d*?^bЩWpgd̺y5 W, Sh0Leξjb28Nt]:/1Or_[L4Γ'NRRd2L ʭ|\晔(·H"ynP~vҗ8D-eELs{WEKWΩָ}߲ o-A؏RŒ+# 7Vt%/F5ZE_#^ikwxkKqfDE,|Ii/Av.Z#f V K}9c'pZzcuŠ~R>l|pack-4e6438607204ce78827e3885594b2c0bb4f13895.pack000066400000000000000000000021221216214232500340140ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/attr_index/.gitted/objects/packPACKx 0@ѻ@v` !:2Xʂl/ & 5Nh`c02ou)i&DMd IN>U^so^+k|NG}}o?Eks&h eev~~6zIH&x{Q(5U"")-$ %911 <405"9"dn>sy k`n`嘒P\6,%$  xA b?вj Rz5?PmӀY@_f1"&8瑜15!h>1{fG]k'77Yzm֑.Pv-"|To+Y4y x340031QK,I,))L*-I-f0Ii={7, !*\]|]rS[S1ꃚ#jߗBUTRQ#}ɻyM!+EP(&1̅]&9xRHJ,+(QHWrRS lM) I9EEI9\\d׽x @آ w'ɘh4, 50`WXi]NHx @ UlQ6p,JYg`vgуQ09Ռ5Ю`>!Kin/x31$޻JO+͝Ȣ]uʞ x340031QK,I,))L*-I-f}6\v2ěkQ몗g2fٍf#=g x340031QrutuMaL3zFIFYn*dexX:V K}9c'plibgit2-0.19.0/tests-clar/resources/attr_index/.gitted/packed-refs000066400000000000000000000001251216214232500250320ustar00rootroot00000000000000# pack-refs with: peeled 58f7cf825b553ef7c26e5b9f8a23599c1a9ca296 refs/heads/master libgit2-0.19.0/tests-clar/resources/attr_index/.gitted/refs/000077500000000000000000000000001216214232500236645ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/attr_index/.gitted/refs/heads/000077500000000000000000000000001216214232500247505ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/attr_index/.gitted/refs/heads/master000066400000000000000000000000511216214232500261620ustar00rootroot000000000000003812cfef36615db1788d4e63f90028007e17a348 libgit2-0.19.0/tests-clar/resources/attr_index/README.md000066400000000000000000000000761216214232500226510ustar00rootroot00000000000000This is contains tests for when the index and work dir differ libgit2-0.19.0/tests-clar/resources/attr_index/README.txt000066400000000000000000000001061216214232500230620ustar00rootroot00000000000000This contains files for testing when the index and the workdir differ libgit2-0.19.0/tests-clar/resources/attr_index/gitattributes000066400000000000000000000000601216214232500242000ustar00rootroot00000000000000* bar *.txt -foo beep=10 *.md blargh=goop -bar libgit2-0.19.0/tests-clar/resources/attr_index/sub/000077500000000000000000000000001216214232500221605ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/attr_index/sub/sub/000077500000000000000000000000001216214232500227515ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/attr_index/sub/sub/.gitattributes000066400000000000000000000000471216214232500256450ustar00rootroot00000000000000*.txt another=one again *.md bar=1234 libgit2-0.19.0/tests-clar/resources/attr_index/sub/sub/README.md000066400000000000000000000000151216214232500242240ustar00rootroot00000000000000More testing libgit2-0.19.0/tests-clar/resources/attr_index/sub/sub/README.txt000066400000000000000000000000151216214232500244430ustar00rootroot00000000000000More testing libgit2-0.19.0/tests-clar/resources/bad_tag.git/000077500000000000000000000000001216214232500213715ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/bad_tag.git/HEAD000066400000000000000000000000271216214232500220140ustar00rootroot00000000000000ref: refs/heads/master libgit2-0.19.0/tests-clar/resources/bad_tag.git/config000066400000000000000000000001671216214232500225650ustar00rootroot00000000000000[core] repositoryformatversion = 0 filemode = true bare = true logallrefupdates = true libgit2-0.19.0/tests-clar/resources/bad_tag.git/objects/000077500000000000000000000000001216214232500230225ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/bad_tag.git/objects/pack/000077500000000000000000000000001216214232500237405ustar00rootroot00000000000000pack-7a28f4e000a17f49a41d7a79fc2f762a8a7d9164.idx000066400000000000000000000023641216214232500326770ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/bad_tag.git/objects/packtOcf:I6qkS2rvǞ[ c6kȍ2:}f0mϛTVR3P$B =Њ 0*JNd>1dPx I-.KWHT(JMLM+(/W(OUHLIsRr2R2RR/x340031Q(JMLM+(aH6kɾzږgR[>ܵx I-.KWHT(JMLM+(Ug8RX~_H;libgit2-0.19.0/tests-clar/resources/bad_tag.git/packed-refs000066400000000000000000000003411216214232500234760ustar00rootroot00000000000000# pack-refs with: peeled eda9f45a2a98d4c17a09d681d88569fa4ea91755 refs/tags/e90810b ^e90810b8df3e80c413d903f631643c716887138d d3bacb8d3ff25876a961b1963b6515170d0151ab refs/tags/hello ^6dcf9bf7541ee10456529833502442f385010c3dlibgit2-0.19.0/tests-clar/resources/bad_tag.git/refs/000077500000000000000000000000001216214232500223305ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/bad_tag.git/refs/dummy-marker.txt000066400000000000000000000000001216214232500254710ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/big.index000066400000000000000000012166501216214232500210330ustar00rootroot00000000000000DIRC M7pM7p cxn9p^!bwW .documentM7pM7p c>f*8ڈu<6fKq7v1.gdbinitM7pM7p c(vH`cG(nA .gitignoreM7pM7p cjj zTUE*G7 .T .indent.proM7pM7p crU4[juDaF0BSDLM7pM7p c ȡE85\T(&vICOPYINGM7pM7p c[[Iős-AN`= COPYING.jaM7pM7p cSc$X# Z@>9IQn[ ChangeLogM7pM7p cFY[n|fva Js2YGPLM7pM7p cZ\MQVu|xljC KNOWNBUGS.rbM7pM7p cK=Wu"IhaDApLEGALM7pM7p c+Dźx"H'+=?Ş Makefile.inM7pM7p c ztr(|Yl INEWSM7pM7p cn=.cnM̃¹4READMEM7pM7p c ²-.dU6 README.EXTM7pM7p cyapؙ)^ Sbenchmark/bm_loop_for.rbM7pM7p c7\tLF*;=/Zbenchmark/bm_loop_generator.rbM7pM7p cRrvCE9r8QIbenchmark/bm_loop_times.rbM7pM7p c5C^1^VB|>6oλH5xbenchmark/bm_loop_whileloop.rbM7pM7p c5advx偫]Hbenchmark/bm_loop_whileloop2.rbM7pM7p c;}PV֮(qCo1obenchmark/bm_so_ackermann.rbM7pM7p c+Ώ8%0Y'benchmark/bm_so_array.rbM7pM7p cj&FUxL ԰ benchmark/bm_so_binary_trees.rbM7pM7p dJb$}hK+4)4benchmark/bm_so_concatenate.rbM7pM7p de3zJJ:#刴YKbenchmark/bm_so_count_words.rbM7pM7p dhشa) z)Bebenchmark/bm_so_exception.rbM7pM7p dp98=benchmark/bm_so_fannkuch.rbM7pM7p d^?uw}}Vbenchmark/bm_so_fasta.rbM7pM7p d-ڳnV9O8]benchmark/bm_so_k_nucleotide.rbM7pM7p d6R(b7*$,2XhUbenchmark/bm_so_lists.rbM7pM7p dhv3dNο0T1benchmark/bm_so_mandelbrot.rbM7pM7p d'Jlu=ʹ7ܤ\benchmark/bm_so_matrix.rbM7pM7p d S#j8}i!benchmark/bm_so_meteor_contest.rbM7pM7p d  Ża*HQD7x%benchmark/bm_so_nbody.rbM7pM7p d ɠQ?Gd uZJLbenchmark/bm_so_nested_loop.rbM7pM7p d \ǂ3v}. =*benchmark/bm_so_nsieve.rbM7pM7p d 7c¦g)w] e׺]benchmark/bm_so_nsieve_bits.rbM7pM7p d`|qEFd^benchmark/bm_so_object.rbM7pM7p dc Eˍq ){Sbenchmark/bm_so_partial_sums.rbM7pM7p d;M)hU~𽄍Nbenchmark/bm_so_pidigits.rbM7pM7p dӀ* rVl2benchmark/bm_so_random.rbM7pM7p dpfi/.,Oّ<#%benchmark/bm_so_reverse_complement.rbM7pM7p d⿦=Q[X?-benchmark/bm_so_sieve.rbM7pM7p dfk fј'QTYbenchmark/bm_so_spectralnorm.rbM7pM7p dJ-+}W.<)"1 benchmark/bm_vm1_block.rbM7pM7p dU>9]xwmp]g`B benchmark/bm_vm1_const.rbM7pM7p dh÷Z L g,-abenchmark/bm_vm1_ensure.rbM7pM7p dLM3i+'JE3tqbenchmark/bm_vm1_ivar.rbM7pM7p dFlj8Yg1ʐ,benchmark/bm_vm1_ivar_set.rbM7pM7p d^-} R192j_hbenchmark/bm_vm1_length.rbM7pM7p df!/ln)rf;vSbenchmark/bm_vm1_neq.rbM7pM7p dK9ؾ+XLbenchmark/bm_vm1_not.rbM7pM7p dF  zeBG^benchmark/bm_vm1_rescue.rbM7pM7p dIC=&|[漍 benchmark/bm_vm1_simplereturn.rbM7pM7p dJez{AF<㐫Ybenchmark/bm_vm1_swap.rbM7pM7p d O qs]/&Ycybenchmark/bm_vm2_array.rbM7pM7p d!J֒T_u`{67benchmark/bm_vm2_case.rbM7pM7p d"?7]F(g\ *Lxbenchmark/bm_vm2_eval.rbM7pM7p d#]̔= &!;E܁i3benchmark/bm_vm2_method.rbM7pM7p d$e6}r-z)7??Nbenchmark/bm_vm2_mutex.rbM7pM7p d%ԬS_Nq?ո䋪5benchmark/bm_vm2_poly_method.rbM7pM7p d&Յkafb%9F2"benchmark/bm_vm2_poly_method_ov.rbM7pM7p d'b [Dz An9benchmark/bm_vm2_proc.rbM7pM7p d(UD@.:yӏLbenchmark/bm_vm2_regexp.rbM7pM7p d)h l Stilbenchmark/bm_vm2_send.rbM7pM7p d*pk7or[`R1benchmark/bm_vm2_super.rbM7pM7p d+Q+ҭEId> DYԸbenchmark/bm_vm2_unif1.rbM7pM7p d,:uC}> r X_benchmark/bm_vm2_zsuper.rbM7pM7p d-X}D -'컢 Jbenchmark/bm_vm3_gc.rbM7pM7p d.I2ZfՇ{1rtWf&benchmark/bm_vm3_thread_create_join.rbM7pM7p d/dݬ&<b< benchmark/bm_vm3_thread_mutex.rbM7pM7p d0\ K!Y 7Qrybenchmark/bmx_temp.rbM7pM7p d1fh}&"϶H*$Fbenchmark/driver.rbM7pM7p d2~ׇ'3S Dw$benchmark/make_fasta_output.rbM7pM7p d4 "wUHTgAK9benchmark/other-lang/ack.plM7pM7p d5hv3eFF;benchmark/other-lang/ack.pyM7pM7p d6tQg 52vFUE덯ߛ=L}1g benchmark/other-lang/fib.pyM7pM7p d?MX~,~#/Imr~benchmark/other-lang/fib.rbM7pM7p d@i/%2ۗkrxw1benchmark/other-lang/fib.scmM7pM7p dA!'wI ):Q1<28benchmark/other-lang/loop.plM7pM7p dB!7I:2_oW:/~Pbenchmark/other-lang/loop.pyM7pM7p dC BPb*benchmark/prepare_so_reverse_complement.rbM7pM7p dMzRӞ}=-- KEbenchmark/report.rbM7pM7p dN en6BY}CgUO`M%[benchmark/run.rbM7pM7p dOvEf/xcy11NhPbenchmark/runc.rbM7pM7p dPA? x4benchmark/wc.input.baseM7pM7p dQe#014CY] mbignum.cM7pM7p dS-k"ROB&h)W/bin/erbM7pM7p dT"Āht.bin/gemM7pM7p dU6le,0ɼWJ/}bin/irbM7pM7p dV] +Seˉ9bin/rakeM7pM7p dWOBk~Ybin/rdocM7pM7p dXI$5W@')bootstraptest/test_fork.rbM7pM7p dghɄ^7)yt#TbSqbootstraptest/test_gc.rbM7pM7p dhws&!FPGlwKbootstraptest/test_io.rbM7pM7p di }=YmHcT+ubootstraptest/test_jump.rbM7pM7p dje,{Ow bootstraptest/test_literal.rbM7pM7p dk 4vmbbootstraptest/test_syntax.rbM7pM7p ds|$'@bootstraptest/test_thread.rbM7pM7p dtv"|˩KC+class.cM7pM7p du9_摎*n5 common.mkM7pM7p dverz%} compar.cM7pM7p dwH}Drߑڇ+*h compile.cM7pM7p dx\i-AvK&Y3q^)Z! complex.cM7pM7p dyc^ji+l$ h configure.inM7pM7p dz­ex]G@-uR< constant.hM7pM7p d{'{π󤹛 cont.cM7pM7p d} r}בjV1BIcygwin/GNUmakefile.inM7pM7p d~Jžnf'֕tdebug.cM7pM7p dGz52>WIrdebug.hM7pM7p dW kU_E@ defs/keywordsM7pM7p d< T;6m :defs/known_errors.defM7pM7p dW kU_E@defs/lex.c.srcM7pM7p dS:bï'defs/opt_insn_unif.defM7pM7p d\@(9-Rɶdefs/opt_operand.defM7pM7p de>_DVEUdir.cM7pM7p dװBL!tm#)dln.cM7pM7p dmXtXLBdln.hM7pM7p d(s%YpjE>PluV dln_find.cM7pM7p d,jtB+dmydln.cM7pM7p d2ni`uC~-?H1 dmyencoding.cM7pM7p dM'?ZsϴXL9wgdmyext.cM7pM7p d4'nZ{ K_ 7 dmyversion.cM7pM7p d `lO [-^n+Sj+vdoc/ChangeLog-1.8.0M7pM7p d']-2^)2cdoc/ChangeLog-1.9.3M7pM7p dB)vl-=/ьi doc/ChangeLog-YARVM7pM7p d72F |(@kl3E:Tdoc/NEWS-1.8.7M7pM7p d= %=f7F!doc/NEWS-1.9.1M7pM7p d/<̭t 2@u]])doc/NEWS-1.9.2M7pM7p dz޽4s%_Y9 doc/etc.rdM7pM7p d;9&XcPgN doc/etc.rd.jaM7pM7p d% Mֻ'bdoc/forwardable.rdM7pM7p dUHk$R#Tdoc/forwardable.rd.jaM7pM7p dp\A$doc/images/boottime-classes.pngM7pM7p dwn%Sedoc/irb/irb-tools.rd.jaM7pM7p d,h+sHyKdoc/irb/irb.rdM7pM7p d.SaVSr.Cldoc/irb/irb.rd.jaM7pM7p d 67XFf*QI:tdoc/pty/READMEM7pM7p d۶]z@0Ab82~CIdoc/pty/README.expectM7pM7p d}ۄi^Rulh> ppgdoc/pty/README.expect.jaM7pM7p d @*D*{U;VV@QJdoc/pty/README.jaM7pM7p d;;g9۴;&doc/rake/CHANGESM7pM7p dAf'WFp.Hʪ qdoc/rake/READMEM7pM7p d S#B/`:q doc/rake/command_line_usage.rdocM7pM7p d9ΰT1 w$doc/rake/example/Rakefile1M7pM7p dW51ε6u-Yf傯Vdoc/rake/example/Rakefile2M7pM7p dAbo!MmR(doc/rake/example/a.cM7pM7p dA$s2a%doc/rake/example/b.cM7pM7p dgEXQ3M7 +s&Hdoc/rake/example/main.cM7pM7p d7 :w/ScbK}doc/rake/glossary.rdocM7pM7p d,YCs4_Efdoc/rake/jamis.rbM7pM7p d 9`JC.doc/rake/proto_rake.rdocM7pM7p dF/r*ѸSQ doc/rake/rakefile.rdocM7pM7p dLA[w-i{^ddoc/rake/rational.rdocM7pM7p d ]N61r]&doc/rake/release_notes/rake-0.8.7.rdocM7pM7p dbS QdKax+"CG doc/re.rdocM7pM7p d1].gͬqLBZdoc/rubygems/ChangeLogM7pM7p dJMzdoc/rubygems/History.txtM7pM7p d ۈi@=oʛdoc/rubygems/LICENSE.txtM7pM7p dh%amS+b>doc/rubygems/READMEM7pM7p d|Z]ûE/ doc/shell.rdM7pM7p d3&ly95Adoc/shell.rd.jaM7pM7p d=1d?tXmienc/Makefile.inM7pM7p d=b(Z dد+E% enc/ascii.cM7pM7p d6;Ӈ j]IJK enc/big5.cM7pM7p d TCcūcK;V" enc/cp949.cM7pM7p dM饭9O'=k enc/dependM7pM7p d7$e `†DnA henc/emacs_mule.cM7pM7p d@@Γ1PKB [_ enc/encdb.cM7pM7p d0cE[} enc/gb18030.cM7pM7p doW5 ;=% enc/gb2312.cM7pM7p d >6gwؚdC` enc/gbk.cM7pM7p d~о]%6Fҕ enc/iso_2022_jp.hM7pM7p d$* vyv_>Eo{enc/iso_8859_1.cM7pM7p d$2C'W={+jaenc/iso_8859_10.cM7pM7p d%}?4bM޽benc/iso_8859_11.cM7pM7p d$n1 Xstenc/iso_8859_13.cM7pM7p d$_?0,"3~enc/iso_8859_14.cM7pM7p d$C.fw/Y5tUenc/iso_8859_15.cM7pM7p d$)=6_d8lM6Tenc/iso_8859_16.cM7pM7p d%9l -}=k%7urenc/iso_8859_2.cM7pM7p d#B2ڠ'84xenc/iso_8859_3.cM7pM7p d$#qļuAS@N!enc/trans/CP/CP932VDC@IBM%UCS.srcM7pM7p dzv qf9tJ\aG%enc/trans/CP/CP932VDC@NEC_IBM%UCS.srcM7pM7p dx~N)Qjn'APAenc/trans/CP/UCS%CP932UDA.srcM7pM7p dFx#|o!enc/trans/CP/UCS%CP932VDC@IBM.srcM7pM7p dnAgWfB:;ǿ*%9c%enc/trans/CP/UCS%CP932VDC@NEC_IBM.srcM7pM7p d)'iRu޽E+jju.enc/trans/EMOJI/EMOJI_ISO-2022-JP-KDDI%UCS.srcM7pM7p dW&$%=y,\!.enc/trans/EMOJI/EMOJI_SHIFT_JIS-DOCOMO%UCS.srcM7pM7p d)%uݸHD! ?CZ,enc/trans/EMOJI/EMOJI_SHIFT_JIS-KDDI%UCS.srcM7pM7p d)+e X9 790F\2enc/trans/EMOJI/EMOJI_SHIFT_JIS-KDDI-UNDOC%UCS.srcM7pM7p d QA? Vpl[86t90enc/trans/EMOJI/EMOJI_SHIFT_JIS-SOFTBANK%UCS.srcM7pM7p d)-V%4L)֛zOi a4enc/trans/EMOJI/UCS%EMOJI_ISO-2022-JP-KDDI-UNDOC.srcM7pM7p d)' {tZB2{.enc/trans/EMOJI/UCS%EMOJI_ISO-2022-JP-KDDI.srcM7pM7p dW,_:~5F:LФZ.enc/trans/EMOJI/UCS%EMOJI_SHIFT_JIS-DOCOMO.srcM7pM7p d)+=YbpM-,2enc/trans/EMOJI/UCS%EMOJI_SHIFT_JIS-KDDI-UNDOC.srcM7pM7p d)%]~J\A3ǽZr,enc/trans/EMOJI/UCS%EMOJI_SHIFT_JIS-KDDI.srcM7pM7p d  )Jս,c40enc/trans/EMOJI/UCS%EMOJI_SHIFT_JIS-SOFTBANK.srcM7pM7p d Aىa=denc/trans/GB/GB12345%UCS.srcM7pM7p dAі5Lc8-gr%enc/trans/GB/GB2312%UCS.srcM7pM7p d[18|{L e)a^enc/trans/GB/UCS%GB12345.srcM7pM7p dM2DdY]ƴztenc/trans/GB/UCS%GB2312.srcM7pM7p d [XGprz#enc/trans/JIS/JISX0201-KANA%UCS.srcM7pM7p dB.»j+΂#enc/trans/JIS/JISX0208@1990%UCS.srcM7pM7p d v]ru@p  F!enc/trans/JIS/JISX0208@MS%UCS.srcM7pM7p d;ݟ]@/KNiYŧݢ!enc/trans/JIS/JISX0208UDC%UCS.srcM7pM7p dK~z\%/}!^el5%enc/trans/JIS/JISX0208VDC@NEC%UCS.srcM7pM7p dN~b$"3Avenc/trans/JIS/JISX0212%UCS.srcM7pM7p e|Im:*>9 vEw!enc/trans/JIS/JISX0212@MS%UCS.srcM7pM7p e;|? •Q?R+!enc/trans/JIS/JISX0212UDC%UCS.srcM7pM7p eos6b Vʍ TV3%enc/trans/JIS/JISX0212VDC@IBM%UCS.srcM7pM7p e W;`qpyW#d#enc/trans/JIS/UCS%JISX0201-KANA.srcM7pM7p ezqq([=H@ӤZG:#enc/trans/JIS/UCS%JISX0208@1990.srcM7pM7p ebL0cv!enc/trans/JIS/UCS%JISX0208@MS.srcM7pM7p e;@ޠP[q5Q%!enc/trans/JIS/UCS%JISX0208UDC.srcM7pM7p ef z߀3JqL|W %enc/trans/JIS/UCS%JISX0208VDC@NEC.srcM7pM7p e@F#WACm!Fˋenc/trans/JIS/UCS%JISX0212.srcM7pM7p e |^ <<;7l1*eekbG!enc/trans/JIS/UCS%JISX0212@MS.srcM7pM7p e ;?}9w+ (ue[}ɉ !enc/trans/JIS/UCS%JISX0212UDC.srcM7pM7p e cP;F䞱Nw{%enc/trans/JIS/UCS%JISX0212VDC@IBM.srcM7pM7p e  a;UAV$'98#aenc/trans/big5-hkscs-tbl.rbM7pM7p e K)_ݥ dْJYR'Kenc/trans/big5-uao-tbl.rbM7pM7p e~?PUBv$(enc/trans/big5.transM7pM7p ebeeBenc/trans/chinese.transM7pM7p ea];% S:`gr18Menc/trans/cp850-tbl.rbM7pM7p e gcaNɵV>|enc/trans/cp852-tbl.rbM7pM7p e.rHښgw͞f 'enc/trans/cp855-tbl.rbM7pM7p eG58PSTJ*#0/"enc/trans/cp949-tbl.rbM7pM7p e#\光{5mK[enc/trans/emoji-exchange-tbl.rbM7pM7p e7C-Rm3 enc/trans/emoji.transM7pM7p ei*3BEenc/trans/euckr-tbl.rbM7pM7p eʐ@ije*enc/trans/gb18030-tbl.rbM7pM7p e>Ldi~;UVvenc/trans/gb18030.transM7pM7p eP&E8ckUenc/trans/gbk-tbl.rbM7pM7p e8 HT2tenc/trans/gbk.transM7pM7p e  ZMbU_e.8BՊenc/trans/ibm437-tbl.rbM7pM7p e!Vy -Mɐ Q},enc/trans/ibm775-tbl.rbM7pM7p e" lQπu_ihaJbenc/trans/ibm852-tbl.rbM7pM7p e#/~ O\V6 ,)9enc/trans/ibm855-tbl.rbM7pM7p e$[ Ӊ7=?}.Ienc/trans/ibm857-tbl.rbM7pM7p e%!xF9Ck0enc/trans/ibm860-tbl.rbM7pM7p e& @Bl; VX4C2,Wܒenc/trans/ibm861-tbl.rbM7pM7p e';1CYv]yg=Bienc/trans/ibm862-tbl.rbM7pM7p e(   f1=q{Nenc/trans/ibm863-tbl.rbM7pM7p e) ""1w ?r\'Menc/trans/ibm865-tbl.rbM7pM7p e*Gu4t;D|enc/trans/ibm866-tbl.rbM7pM7p e+C~A֤';(l}wITenc/trans/ibm869-tbl.rbM7pM7p e,9~dH.+-2Dhenc/trans/iso-8859-1-tbl.rbM7pM7p e-&9b7ɻ/4!}enc/trans/iso-8859-10-tbl.rbM7pM7p e.hf1”ļ;) 6Cenc/trans/iso-8859-11-tbl.rbM7pM7p e/-,^y'2Fenc/trans/iso-8859-13-tbl.rbM7pM7p e0\j\*NZ2|enc/trans/iso-8859-14-tbl.rbM7pM7p e1TR_VHI&enc/trans/iso-8859-15-tbl.rbM7pM7p e2F]_Pyenc/trans/iso-8859-2-tbl.rbM7pM7p e3oGQ d.sR 1enc/trans/iso-8859-3-tbl.rbM7pM7p e43!E7H%Ienc/trans/iso-8859-4-tbl.rbM7pM7p e56j']^eUenc/trans/iso-8859-5-tbl.rbM7pM7p e6IӇ7+H~B~qC}enc/trans/iso-8859-6-tbl.rbM7pM7p e7N^ЊBk~ z1enc/trans/iso-8859-7-tbl.rbM7pM7p e8ЀoE$^ph@Venc/trans/iso-8859-8-tbl.rbM7pM7p e9 -ahhb?ϚĦenc/trans/iso-8859-9-tbl.rbM7pM7p e:>"?@oF8\enc/trans/iso2022.transM7pM7p e;] iQ;lm*enc/trans/japanese.transM7pM7p e<vW^_u2*0^enc/trans/japanese_euc.transM7pM7p e='.9ׄ5;enc/trans/japanese_sjis.transM7pM7p e>I_'%)I6enc/trans/koi8-r-tbl.rbM7pM7p e?Az?sٍnCQenc/trans/koi8-u-tbl.rbM7pM7p e@ˎ<gv\enc/trans/korean.transM7pM7p eA5x%rug)uS r5]enc/trans/maccroatian-tbl.rbM7pM7p eB!7üI--kh7-enc/trans/maccyrillic-tbl.rbM7pM7p eCu ҵ&(>xgenc/trans/macgreek-tbl.rbM7pM7p eD΁"t_f+menc/trans/maciceland-tbl.rbM7pM7p eE؏trϕA~=ACPenc/trans/macroman-tbl.rbM7pM7p eFW!fLK'icjenc/trans/macromania-tbl.rbM7pM7p eG#Xg.yS-x\z•:\-enc/trans/macturkish-tbl.rbM7pM7p eH iAeMza=x'#82enc/trans/macukraine-tbl.rbM7pM7p eI Z關+|;enc/trans/newline.transM7pM7p eJ UC 2ah GJenc/trans/single_byte.transM7pM7p eKs bo}Iuenc/trans/tis-620-tbl.rbM7pM7p eL֬AgyTenc/trans/transdb.cM7pM7p eNLp/ʎkQ& lC"enc/trans/ucm/glibc-BIG5-2.3.3.ucmM7pM7p eOoʁU}0?8d l'enc/trans/ucm/glibc-BIG5HKSCS-2.3.3.ucmM7pM7p eP7I96\NaF"enc/trans/ucm/windows-950-2000.ucmM7pM7p eQ'vŠ}IH0r(enc/trans/ucm/windows-950_hkscs-2001.ucmM7pM7p eR` 4x>[V*g$enc/trans/utf8_mac-tbl.rbM7pM7p eS> iۤjPǂg >;renc/trans/utf8_mac.transM7pM7p eT;A_!|kenc/trans/utf_16_32.transM7pM7p eUR>Ob[S:?{enc/trans/windows-1250-tbl.rbM7pM7p eV qrLd lK[Njzenc/trans/windows-1257-tbl.rbM7pM7p e]4R=(pYtH^I@enc/trans/windows-874-tbl.rbM7pM7p e^ ? W˿<Փnϔ enc/unicode.cM7pM7p e`O^KHQR2GiEWenc/unicode/name2ctype.hM7pM7p eaO^KHQR2GiEWenc/unicode/name2ctype.h.bltM7pM7p eb'K.'un:;zܱ,enc/unicode/name2ctype.kwdM7pM7p ec'K.'un:;zܱ,enc/unicode/name2ctype.srcM7pM7p ed.8F@9AwCn7O]yWenc/us_ascii.cM7pM7p een(.ٲ{X>enc/utf_16_32.hM7pM7p efU3}^ܥ p+enc/utf_16be.cM7pM7p eg#%!g*ᘌenc/utf_16le.cM7pM7p eh!ateyA#enc/utf_32be.cM7pM7p eiA: A:R.'RbKs%nenc/utf_32le.cM7pM7p ejxϡrBA/k enc/utf_7.hM7pM7p ekDO Dgh1B2Q enc/utf_8.cM7pM7p el"rI`"?I.̱$.Jenc/windows_1251.cM7pM7p emɼQ+ enc/x_emoji.hM7pM7p en1*`gϒ&q encoding.cM7pM7p eo =5!^|.<$enum.cM7pM7p ep`GHTQ enumerator.cM7pM7p eq!w@مpUq.H.poerror.cM7pM7p er^O_mΘnfjeval.cM7pM7p es\} F[|N}o eval_error.cM7pM7p etʦ!J[&bR eval_intern.hM7pM7p eu \\c9>y eval_jump.cM7pM7p ey!S8:CGI@ext/-test-/add_suffix/bug.cM7pM7p ez2= != S =qMext/-test-/add_suffix/dependM7pM7p e{P:_ʩtmHS ext/-test-/add_suffix/extconf.rbM7pM7p e~'ex T32ݍK"ext/-test-/array/resize/extconf.rbM7pM7p e>z)zr]c=I ext/-test-/array/resize/resize.cM7pM7p erֽ!pi/ӂ!ext/-test-/bug-3571/bug.cM7pM7p e'c4 ؤ+麪kext/-test-/bug-3571/extconf.rbM7pM7p eu_ \EdHG ext/-test-/bug-3662/bug.cM7pM7p e'zs<Eq{(ext/-test-/bug-3662/extconf.rbM7pM7p em(Gvf19jv0[r!ext/-test-/load/dot.dot/dot.dot.cM7pM7p e/bk؇w3  "ext/-test-/load/dot.dot/extconf.rbM7pM7p eB Kxi\5U8L[aext/-test-/string/extconf.rbM7pM7p ey1Hx-fY,ext/-test-/string/init.cM7pM7p e<}x72$vxL/ext/-test-/string/set_len.cM7pM7p eoOfץtGk%) ext/.documentM7pM7p e{7f+Kf ext/SetupM7pM7p en B)rc|5ext/Setup.atheosM7pM7p e ޑ~T P6o ext/Setup.emxM7pM7p eWK P.e@9'| ext/Setup.ntM7pM7p e F3dW$|ւ e.ext/bigdecimal/READMEM7pM7p e Sg XfaoVext/bigdecimal/bigdecimal.cM7pM7p e$ƌq_jƮHĶRtext/bigdecimal/bigdecimal.hM7pM7p exkҢWkj~"7U|/!ext/bigdecimal/bigdecimal_en.htmlM7pM7p es7˻ 8+j_. !!ext/bigdecimal/bigdecimal_ja.htmlM7pM7p e9@,R٩©di\bext/bigdecimal/dependM7pM7p el־>XNG$ecext/bigdecimal/extconf.rbM7pM7p eB Xqi )ext/bigdecimal/lib/bigdecimal/jacobian.rbM7pM7p ebl)Lext/dbm/extconf.rbM7pM7p e *,:voH~X&ext/digest/bubblebabble/bubblebabble.cM7pM7p eH_ rOext/digest/bubblebabble/dependM7pM7p erS˃JGYVvd"ext/digest/bubblebabble/extconf.rbM7pM7p ew4dIfl^v[wp͖ext/digest/defs.hM7pM7p ekC` ?r61B|ext/digest/dependM7pM7p eADoI\S$ۼCy6ext/digest/digest.cM7pM7p eAnIYH9#nD;Rext/digest/digest.hM7pM7p e ֏sЋsy+ext/digest/extconf.rbM7pM7p elǐw)J  ext/digest/lib/digest.rbM7pM7p eiϢDQNž!Jext/digest/lib/digest/hmac.rbM7pM7p e# KI&!R(ext/digest/md5/dependM7pM7p ea.wѡ [ext/digest/md5/extconf.rbM7pM7p e3_Q9wM̏I|ext/digest/md5/md5.cM7pM7p e X>0x"ext/digest/md5/md5.hM7pM7p e"\ns\LP/Q|Lext/digest/md5/md5init.cM7pM7p eyJ/>R<|hBܾext/digest/md5/md5ossl.cM7pM7p eٺoAi MFext/digest/md5/md5ossl.hM7pM7p eOqn/0>a;خext/digest/rmd160/dependM7pM7p e6=+G{<V(ext/digest/rmd160/extconf.rbM7pM7p e9򈑇(Y DE Z9Pext/digest/rmd160/rmd160.cM7pM7p ej,в,\Vext/digest/rmd160/rmd160.hM7pM7p e 9 k+gLjpext/digest/rmd160/rmd160init.cM7pM7p eNc4*cO Ȟext/digest/rmd160/rmd160ossl.cM7pM7p e=Uΐ kext/digest/rmd160/rmd160ossl.hM7pM7p e@a`xDlX\%!ext/digest/sha1/dependM7pM7p eEC旴1zWQ$Uext/digest/sha1/extconf.rbM7pM7p e#akzNwRt9]xZext/digest/sha1/sha1.cM7pM7p eU~sKR1G%-ext/digest/sha1/sha1.hM7pM7p e7P?[zext/digest/sha1/sha1init.cM7pM7p eE,P|ʘw(ext/digest/sha1/sha1ossl.cM7pM7p edd̽Gݷ\?Q:ext/digest/sha1/sha1ossl.hM7pM7p e?~bvBv+fext/digest/sha2/dependM7pM7p e4Z}D(S=ext/digest/sha2/extconf.rbM7pM7p e`x;VŽ`z_Uext/digest/sha2/lib/sha2.rbM7pM7p ea{[z(:惟yUO ext/digest/sha2/sha2.cM7pM7p e{FS+">n7xext/digest/sha2/sha2.hM7pM7p eKxb{??%Ѕkext/digest/sha2/sha2init.cM7pM7p eNr5sqbn ext/digest/sha2/sha2ossl.cM7pM7p eB)LʼnL^ ^ext/digest/sha2/sha2ossl.hM7pM7p e+2uu@rjEMext/digest/test.shM7pM7p ezb Ap y{(lext/dl/callback/dependM7pM7p etl3g j@@dp#n ext/dl/callback/extconf.rbM7pM7p e"@r2%68`#ext/dl/callback/mkcallback.rbM7pM7p e:?@_azҼDzףWext/dl/cfunc.cM7pM7p e;h,$Y@j; ext/dl/cptr.cM7pM7p e,w4/RF ext/dl/dependM7pM7p e5yHo) "إHe埦 ext/dl/dl.cM7pM7p e+;~xs&,* ext/dl/dl.hM7pM7p eZ5{K_e 걄ext/dl/extconf.rbM7pM7p e!oqι /'ext/dl/handle.cM7pM7p ekhZza$xȓHۭext/dl/lib/dl.rbM7pM7p e c M)JL_5G+ext/dl/lib/dl/callback.rbM7pM7p e !4qYXyOTw3KM^ext/dl/lib/dl/cparser.rbM7pM7p e<"EJTEGXl}ext/dl/lib/dl/func.rbM7pM7p e *SIT0[ext/dl/lib/dl/import.rbM7pM7p e +R/-YF??ext/dl/lib/dl/pack.rbM7pM7p e "7IjlsJopeext/dl/lib/dl/stack.rbM7pM7p e޸̦\f`Φ84ext/dl/lib/dl/struct.rbM7pM7p fZȐwN*]n%ext/dl/lib/dl/types.rbM7pM7p f Qk);N}T2 VIxext/dl/lib/dl/value.rbM7pM7p fW,Hk<ext/dl/win32/extconf.rbM7pM7p fWImZyjVzcȽoext/dl/win32/lib/Win32API.rbM7pM7p fYn݅:(#v"ext/dl/win32/lib/win32/registry.rbM7pM7p f+eG(wYmUFi{LiGtd* ext/dl/win32/lib/win32/resolv.rbM7pM7p f )`"ߖPhd:K'h|uEext/dl/win32/lib/win32/sspi.rbM7pM7p f GpdwHZ,k(6ext/etc/dependM7pM7p f 9۟+EUgJ۶TB ext/etc/etc.cM7pM7p f gV ԞN"qϾЪext/etc/extconf.rbM7pM7p f;9HՏmU ext/extmk.rbM7pM7p fIJFDdB"sRext/fcntl/dependM7pM7p f(q}J[[Ր=YSpext/fcntl/extconf.rbM7pM7p f/00)\Hueext/fcntl/fcntl.cM7pM7p f)JJ϶Oext/fiber/extconf.rbM7pM7p fi;y ext/fiber/fiber.cM7pM7p f{Ff&xxd0'Ĭext/fiddle/closure.cM7pM7p fl"=+{/Tk/e^ext/fiddle/closure.hM7pM7p f SaUODw kext/fiddle/conversions.cM7pM7p fl]-?羖a|kwext/fiddle/conversions.hM7pM7p f'ee*|s~|ext/fiddle/extconf.rbM7pM7p f%S. 0@mo/ext/fiddle/fiddle.cM7pM7p fqe%D>w4DtѲext/fiddle/fiddle.hM7pM7p fw\`$*+)q>]ext/fiddle/function.cM7pM7p foFZO A5cn!І,ext/fiddle/function.hM7pM7p f!Cs]/|Vext/fiddle/lib/fiddle.rbM7pM7p f#L+ze8P^{F ext/fiddle/lib/fiddle/closure.rbM7pM7p f$>{sXtS;FS6 m!ext/fiddle/lib/fiddle/function.rbM7pM7p f&'z&hPjb_}ext/gdbm/READMEM7pM7p f'Gz܌ѣ$H&IZext/gdbm/dependM7pM7p f(Z I.^e7a>ext/gdbm/extconf.rbM7pM7p f)yCal:p?M0ퟏӆext/gdbm/gdbm.cM7pM7p f+ |Vz.P5dtJVQk͓ext/iconv/charset_alias.rbM7pM7p f,UU˿qO^:Iext/iconv/dependM7pM7p f-bĥ|` C<u"ext/iconv/extconf.rbM7pM7p f.~YSEÍK;pU|0ext/iconv/iconv.cM7pM7p f/RD r# 4W|ext/iconv/mkwrapper.rbM7pM7p f2-o@CZM"Y]R6{M6ext/io/console/console.cM7pM7p f3Wz@G\v˗uext/io/console/extconf.rbM7pM7p f5l?%p{eC`ext/io/nonblock/extconf.rbM7pM7p f6ᬎiX?E&$ext/io/nonblock/nonblock.cM7pM7p f8T1$)fImoext/io/wait/extconf.rbM7pM7p f9"%"$>|Qdext/io/wait/wait.cM7pM7p f;(C Text/json/extconf.rbM7pM7p f=%vd /^u&i-ext/json/generator/dependM7pM7p f>OqAX7ފ=NK8ext/json/generator/extconf.rbM7pM7p f?ǫuKЯWC8Ѭ5ext/json/generator/generator.cM7pM7p f@Գ.p EoA4_v4ext/json/generator/generator.hM7pM7p fBx FOYJlAext/json/lib/json.rbM7pM7p fE  /r ɭD;Cext/json/lib/json/add/core.rbM7pM7p fF4޽fmc@A~6_ ext/json/lib/json/common.rbM7pM7p fGWߵSɦUext/json/lib/json/ext.rbM7pM7p fH;U=Q[ext/json/lib/json/version.rbM7pM7p fJ^m@{%,Gext/json/parser/dependM7pM7p fKYdqjz=+QD̝L;ext/json/parser/extconf.rbM7pM7p fL^`2h$<v\ext/json/parser/parser.cM7pM7p fMh[a iLext/json/parser/parser.hM7pM7p fN_H_:T1[rfext/json/parser/parser.rlM7pM7p fOB-#"%M fq'4ext/json/parser/prereq.mkM7pM7p fRg䔕W.ŇQbf^?ext/mathn/complex/complex.cM7pM7p fS0O CA_e2ext/mathn/complex/extconf.rbM7pM7p fU1v0k{8Z6-9ext/mathn/rational/extconf.rbM7pM7p fVf*řFT.* eYext/mathn/rational/rational.cM7pM7p fX_k7`30.Sߞext/nkf/dependM7pM7p fY&qb Yy>X3šryext/nkf/extconf.rbM7pM7p f[Y_b{Bheext/nkf/lib/kconv.rbM7pM7p f])Q*QRTgO2a:@ext/nkf/nkf-utf8/config.hM7pM7p f^shw7I%n3Plmext/nkf/nkf-utf8/nkf.cM7pM7p f_ G\пMfDLext/nkf/nkf-utf8/nkf.hM7pM7p f` ];t%ګP̟:ext/nkf/nkf-utf8/utf8tbl.cM7pM7p fap~Fq!CO?ext/nkf/nkf-utf8/utf8tbl.hM7pM7p fb36d@Z Ia ext/nkf/nkf.cM7pM7p fdH#,L (5I>qVt(ext/objspace/extconf.rbM7pM7p febNext/openssl/ossl_bn.cM7pM7p f}Ö"{iCSv[ROgext/openssl/ossl_bn.hM7pM7p f~6$RcJeLXext/openssl/ossl_cipher.cM7pM7p fھ;V|S:jext/openssl/ossl_cipher.hM7pM7p fs0vO&J ^/oӡext/openssl/ossl_config.cM7pM7p f"k'OP&Ю'lext/openssl/ossl_config.hM7pM7p fK)7G I#VUG>%ext/openssl/ossl_digest.cM7pM7p fҌűVni_?6ext/openssl/ossl_digest.hM7pM7p f&;H'hkڽ ;|ext/openssl/ossl_engine.cM7pM7p f/%i + . f46\ext/openssl/ossl_engine.hM7pM7p fr Qff-_+ext/openssl/ossl_hmac.cM7pM7p f{)xY{ԗext/openssl/ossl_hmac.hM7pM7p f}%hl Q@ext/openssl/ossl_ns_spki.cM7pM7p fwZ(Wzl}ext/openssl/ossl_ns_spki.hM7pM7p fO$2aŒe:\[!ext/openssl/ossl_ocsp.cM7pM7p fe?lKC:/CȮ(ext/openssl/ossl_ocsp.hM7pM7p fQ.3xDJ훷ext/openssl/ossl_pkcs12.cM7pM7p f $]sgTѸxext/openssl/ossl_pkcs12.hM7pM7p f z_;SƳ牐ext/openssl/ossl_pkcs5.cM7pM7p fn2P&[]e iext/openssl/ossl_pkcs5.hM7pM7p fb)BAs L_H&ext/openssl/ossl_pkcs7.cM7pM7p f7B/D{text/openssl/ossl_pkcs7.hM7pM7p fV嗶~EYhĎ`.ext/openssl/ossl_pkey.cM7pM7p f gЃ"NF6¤ext/openssl/ossl_pkey.hM7pM7p f.n^uۘbU"Cext/openssl/ossl_pkey_dh.cM7pM7p f)5oN %: ext/openssl/ossl_pkey_dsa.cM7pM7p fn-S;+8x4S/ ext/openssl/ossl_pkey_ec.cM7pM7p f;L >lؽ)]1R 9ext/openssl/ossl_pkey_rsa.cM7pM7p fYtL~IWWߔlext/openssl/ossl_rand.cM7pM7p f*):Y6DI8ext/openssl/ossl_rand.hM7pM7p fjkeN6HՉum|rNext/openssl/ossl_ssl.cM7pM7p f_UD*s]K)υext/openssl/ossl_ssl.hM7pM7p fwH'b&H hλoext/openssl/ossl_ssl_session.cM7pM7p fX<갉+IԈ:Uֶext/openssl/ossl_version.hM7pM7p f Kl~h{ ōrrícext/openssl/ossl_x509.cM7pM7p fCVsMZt>r7cext/openssl/ossl_x509.hM7pM7p f6Ui3>t+/Pext/openssl/ossl_x509attr.cM7pM7p f<}&)Ԙ[text/openssl/ossl_x509cert.cM7pM7p f.:"M ͬext/openssl/ossl_x509crl.cM7pM7p f-Md`((S/V8t,ext/openssl/ossl_x509ext.cM7pM7p f$uA}'@79Yijext/openssl/ossl_x509name.cM7pM7p f&~6'vjpɚܕ%%ext/openssl/ossl_x509req.cM7pM7p fk;X2KŎ,/rext/openssl/ossl_x509revoked.cM7pM7p f91SJD͆èext/openssl/ossl_x509store.cM7pM7p f5do&l^4<24~ext/openssl/ruby_missing.hM7pM7p f+g >EZ(@U7ext/pathname/extconf.rbM7pM7p f8"Lg/nyޑKPext/pathname/lib/pathname.rbM7pM7p ftɖJ…񺶆.ext/pathname/pathname.cM7pM7p f/_^ʉ{G6@ext/psych/emitter.cM7pM7p fhVQ1T-=ext/psych/lib/psych/handler.rbM7pM7p fA*pd$/ext/psych/lib/psych/json.rbM7pM7p fXLMhD`?"ext/psych/lib/psych/json/stream.rbM7pM7p f&uʋ@FԷgN(ext/psych/lib/psych/json/tree_builder.rbM7pM7p f PYFکT2-͛ext/psych/lib/psych/nodes.rbM7pM7p f[ѱU^oֳt@"ext/psych/lib/psych/nodes/alias.rbM7pM7p f2M`ܐ1wRD~ JB%ext/psych/lib/psych/nodes/document.rbM7pM7p f[\ #=:KԎDZc$ext/psych/lib/psych/nodes/mapping.rbM7pM7p f|(0w؝D͒u!ext/psych/lib/psych/nodes/node.rbM7pM7p fG%6+9GF 8#ext/psych/lib/psych/nodes/scalar.rbM7pM7p f30a-cc %ext/psych/lib/psych/nodes/sequence.rbM7pM7p f|30#9;5ϩ#ext/psych/lib/psych/nodes/stream.rbM7pM7p f-b'>P|s'n]ext/psych/lib/psych/omap.rbM7pM7p f]u`]I 9s^t <&ext/psych/lib/psych/parser.rbM7pM7p f 7ǒ|kxlM3%ext/psych/lib/psych/scalar_scanner.rbM7pM7p f,ggjPٵ ext/psych/lib/psych/set.rbM7pM7p fPs9>O)Bʭext/psych/lib/psych/stream.rbM7pM7p f$N#NrW?#ext/psych/lib/psych/tree_builder.rbM7pM7p fLp1%^A-Text/psych/lib/psych/visitors.rbM7pM7p fK0a-F_{lל'ext/psych/lib/psych/visitors/emitter.rbM7pM7p f/i*Ή?)ext/psych/lib/psych/visitors/json_tree.rbM7pM7p fStS8cq0%KE.昲$'ext/psych/lib/psych/visitors/to_ruby.rbM7pM7p fIMwr(BSDig:l|'ext/psych/lib/psych/visitors/visitor.rbM7pM7p f'Wт[IHH X,#)ext/psych/lib/psych/visitors/yaml_tree.rbM7pM7p f& >[Z2oext/psych/parser.cM7pM7p fQ% k΄~8ext/psych/parser.hM7pM7p fi\^ଇ/ Dext/readline/README.jaM7pM7p fOepŠ6U!gQ ext/readline/dependM7pM7p f QY¨]6 &~oxext/readline/extconf.rbM7pM7p f^6եliF"+P϶Cext/readline/readline.cM7pM7p fq%;pNext/ripper/READMEM7pM7p f@MwlZd,sN~sext/ripper/dependM7pM7p f&+ 7W+NYDFO!3ڢ"ext/ripper/eventids2.cM7pM7p f#IxӢ"ǨL7ext/ripper/extconf.rbM7pM7p f[3JF-~ext/ripper/lib/ripper.rbM7pM7p f5TАQ3]֓J ext/ripper/lib/ripper/core.rbM7pM7p f9ext/ripper/lib/ripper/sexp.rbM7pM7p f3n\x)8 -\d~ )ext/ripper/tools/generate-param-macros.rbM7pM7p fa"ì\h>f/ext/ripper/tools/generate.rbM7pM7p fI9|/b˷,ext/ripper/tools/preproc.rbM7pM7p fϙA<6R_ĂYZ*ext/ripper/tools/strip.rbM7pM7p fN-yrk$BvD"˺h%iZext/sdbm/init.cM7pM7p gõ3R5M]y]J޸>ext/socket/getaddrinfo.cM7pM7p g lsnMc:LU0ext/socket/getnameinfo.cM7pM7p g1zP~b#f;["hext/socket/init.cM7pM7p g!~ Uۮ~A2ext/socket/ipsocket.cM7pM7p gYc׽v)߆4|ext/socket/lib/socket.rbM7pM7p g3G=z(UZext/socket/mkconstants.rbM7pM7p gnN5o \=5ޛext/socket/option.cM7pM7p gTm*^qcᤪ}t>Sext/socket/raddrinfo.cM7pM7p g!#`%o*bmIvext/socket/rubysocket.hM7pM7p gcXo67,Cjext/socket/socket.cM7pM7p gV_/E0cϝj*W܄?>ext/socket/sockport.hM7pM7p gky"q6V0Cuecext/socket/sockssocket.cM7pM7p gF{- _4 ext/socket/tcpserver.cM7pM7p gB]`ˀ2r匐[ext/socket/tcpsocket.cM7pM7p gyxR>-+" +6ɿ_ext/socket/udpsocket.cM7pM7p gOp0M)kROľext/socket/unixserver.cM7pM7p g1S%1/rX?sxXdext/socket/unixsocket.cM7pM7p gj#}[KcL0Text/stringio/READMEM7pM7p g 3)pu7>{Aext/stringio/dependM7pM7p g!+K75普ɻXext/stringio/extconf.rbM7pM7p g" nKƂ,5N=bext/stringio/stringio.cM7pM7p g$vోM* Xj%ext/syck/dependM7pM7p g*ј[%;W\Jx|ext/syck/emitter.cM7pM7p g+AlDp-BABVvext/syck/extconf.rbM7pM7p g,M1Qv9}Gext/syck/gram.cM7pM7p g-TqIK}c t}O'ext/syck/gram.hM7pM7p g. @'ȔLろKB@8ext/syck/handler.cM7pM7p g/.}@twVA(uԔ(Lext/syck/implicit.cM7pM7p g17wpDmext/syck/lib/syck.rbM7pM7p g3c^9Px,1`K ext/syck/lib/syck/baseemitter.rbM7pM7p g4]{YSzz0kext/syck/lib/syck/basenode.rbM7pM7p g5BN3~x9ext/syck/lib/syck/constants.rbM7pM7p g6bL)Ʃhq0^ext/syck/lib/syck/encoding.rbM7pM7p g7) $Lr'6B i0pT9ext/syck/lib/syck/error.rbM7pM7p g8(\S_ASl3 Zext/syck/lib/syck/loader.rbM7pM7p g99d">&xext/syck/lib/syck/rubytypes.rbM7pM7p g:w3ƋJj-LSc_u Mext/syck/lib/syck/stream.rbM7pM7p g;w'h hQ9-S,ext/syck/lib/syck/stringio.rbM7pM7p g<?F 0pΙ~C?dzext/syck/lib/syck/syck.rbM7pM7p g= ymySu-,q;_Qext/syck/lib/syck/tag.rbM7pM7p g>\ˤ^ +nZ|?ext/syck/lib/syck/types.rbM7pM7p g?/{nlʬJYext/syck/lib/syck/yamlnode.rbM7pM7p g@kMN{F$6rޭ8ext/syck/lib/syck/ypath.rbM7pM7p gB[]IN˧rfa KxeVext/syck/lib/yaml/syck.rbM7pM7p gC5QP wWX7C^ext/syck/node.cM7pM7p gDҥ*zg2Kzj_ext/syck/rubyext.cM7pM7p gE)juA,`J-ext/syck/syck.cM7pM7p gF0 :T v*@wext/syck/syck.hM7pM7p gGT!H)eh>j6|ext/syck/token.cM7pM7p gHNy ,̳sX;)ext/syck/yaml2byte.cM7pM7p gI7=p8]U?OEӃext/syck/yamlbyte.hM7pM7p gKbE): 8C LQIext/syslog/dependM7pM7p gL3T~Fe)4E9sext/syslog/extconf.rbM7pM7p gM$l 'yext/tk/README.tcltklibM7pM7p gXay~D:0* ext/tk/config_list.inM7pM7p gY2)ףpL5+V%N ext/tk/dependM7pM7p gZA8oxVN-Mext/tk/extconf.rbM7pM7p g\bYKi S9m+Wvext/tk/lib/READMEM7pM7p g] 5@lT?-@p{ext/tk/lib/multi-tk.rbM7pM7p g^8mD=f =;C{)j0ext/tk/lib/remote-tk.rbM7pM7p g_(;-zB@Q)Lxext/tk/lib/tcltk.rbM7pM7p g` |Rm6gZ ext/tk/lib/tk.rbM7pM7p gbUX!1 %Eext/tk/lib/tk/after.rbM7pM7p gcZ.$zu%+{ext/tk/lib/tk/autoload.rbM7pM7p gd*k'+I)8YFext/tk/lib/tk/bgerror.rbM7pM7p ge #údIQ]ext/tk/lib/tk/bindtag.rbM7pM7p gfO$Qbg xext/tk/lib/tk/busy.rbM7pM7p gge#< UA2 uxoNext/tk/lib/tk/button.rbM7pM7p ghWMu[l/)uF8Ҟ$Rext/tk/lib/tk/canvas.rbM7pM7p gi$I]!ߧD>2x㰠ext/tk/lib/tk/canvastag.rbM7pM7p gjDAQAD+J]^ext/tk/lib/tk/checkbutton.rbM7pM7p gk Z\(3(rext/tk/lib/tk/clipboard.rbM7pM7p gleN8LN1ěext/tk/lib/tk/clock.rbM7pM7p gm/{gǢ+L$#)?)qext/tk/lib/tk/composite.rbM7pM7p gndWYLϚ_6o,text/tk/lib/tk/console.rbM7pM7p go#~9P 5ykext/tk/lib/tk/dialog.rbM7pM7p gp/YS lqext/tk/lib/tk/encodedstr.rbM7pM7p gq OԪ#O 3,V"ext/tk/lib/tk/entry.rbM7pM7p grFN#"iFZ-^]9E/ext/tk/lib/tk/event.rbM7pM7p gsLۅxKƷFext/tk/lib/tk/font.rbM7pM7p gt5 /jH{$jTPext/tk/lib/tk/fontchooser.rbM7pM7p gu Q2d x& >^j1ext/tk/lib/tk/frame.rbM7pM7p gv|DHi召w66ӲGext/tk/lib/tk/grid.rbM7pM7p gw94xM(a{~>/ Cext/tk/lib/tk/image.rbM7pM7p gx܏9`H4ͳK*"ext/tk/lib/tk/itemconfig.rbM7pM7p gy%(O͕,i늠qtext/tk/lib/tk/itemfont.rbM7pM7p gz=?umjSFg:I~~Mext/tk/lib/tk/kinput.rbM7pM7p g{a0!PYCOext/tk/lib/tk/label.rbM7pM7p g|ogUjmpPda!ext/tk/lib/tk/labelframe.rbM7pM7p g}GgB,Wd^xGͺ#Zext/tk/lib/tk/listbox.rbM7pM7p g~<<H#Wjext/tk/lib/tk/macpkg.rbM7pM7p gP-Pm߭Gs  l#ext/tk/lib/tk/menu.rbM7pM7p gLUqp]2*9dext/tk/lib/tk/menubar.rbM7pM7p g7!WUTΪ=EVcj"ext/tk/lib/tk/menuspec.rbM7pM7p g_so=P8"ext/tk/lib/tk/message.rbM7pM7p g_O(9!Z%~Dext/tk/lib/tk/mngfocus.rbM7pM7p g!]J^jM0ext/tk/lib/tk/msgcat.rbM7pM7p g: J^Y j`jxext/tk/lib/tk/namespace.rbM7pM7p g-";Hf3Mpext/tk/lib/tk/optiondb.rbM7pM7p gx)mf<9 ext/tk/lib/tk/panedwindow.rbM7pM7p gooxfj0ext/tk/lib/tk/place.rbM7pM7p gb}&ٴQfSsͲext/tk/lib/tk/radiobutton.rbM7pM7p g% 5=֎cK/kext/tk/lib/tk/root.rbM7pM7p g  ~wext/tk/lib/tk/scale.rbM7pM7p gzKI&)&;ext/tk/lib/tk/scrollable.rbM7pM7p g Q6g[ext/tk/lib/tk/scrollbar.rbM7pM7p gBft٘]zcext/tk/lib/tk/scrollbox.rbM7pM7p gú oI n;@_[??ext/tk/lib/tk/selection.rbM7pM7p g %}`ʯRՉb,Aext/tk/lib/tk/spinbox.rbM7pM7p g[sH0mⳜext/tk/lib/tk/tagfont.rbM7pM7p g*]q~675ext/tk/lib/tk/text.rbM7pM7p gzd+B!Lext/tk/lib/tk/textimage.rbM7pM7p gш^T2y>_*1CUext/tk/lib/tk/textmark.rbM7pM7p gi }J]޴0.fdext/tk/lib/tk/texttag.rbM7pM7p g I2{,%@gZ|cext/tk/lib/tk/textwindow.rbM7pM7p g9AFsуb_j%jext/tk/lib/tk/timer.rbM7pM7p g05u3;3ext/tk/lib/tk/toplevel.rbM7pM7p g R"IpȂw% Hbext/tk/lib/tk/ttk_selector.rbM7pM7p gTmՒH(u:wext/tk/lib/tk/txtwin_abst.rbM7pM7p g&p\Q2Bj3@UKؤ:ext/tk/lib/tk/validation.rbM7pM7p g4C D&ql"_Uext/tk/lib/tk/variable.rbM7pM7p gRfqLMjext/tk/lib/tk/virtevent.rbM7pM7p g!m g`R#ext/tk/lib/tk/winfo.rbM7pM7p gzCjF|_wLext/tk/lib/tk/winpkg.rbM7pM7p g;Kj܀_HPì{*ext/tk/lib/tk/wm.rbM7pM7p g lQu Uglrext/tk/lib/tk/xim.rbM7pM7p g9YEL83R|}7$ext/tk/lib/tkafter.rbM7pM7p g?޺zW0QlBQȺext/tk/lib/tkbgerror.rbM7pM7p g<$aB[vMdoext/tk/lib/tkcanvas.rbM7pM7p gSցEc朱Q=eext/tk/lib/tkclass.rbM7pM7p g?`ݸj)iN;"ext/tk/lib/tkextlib/ICONS/setup.rbM7pM7p gk13^IrS5{"ext/tk/lib/tkextlib/SUPPORT_STATUSM7pM7p gċ.AТ+Vext/tk/lib/tkextlib/blt.rbM7pM7p gkY=Sٌ@#ext/tk/lib/tkextlib/blt/barchart.rbM7pM7p g 2T1m˥ߋ5i_!ext/tk/lib/tkextlib/blt/bitmap.rbM7pM7p gĵ(6.Ӛ]Fext/tk/lib/tkextlib/blt/busy.rbM7pM7p g("Fku)A*$ext/tk/lib/tkextlib/blt/component.rbM7pM7p g*ڜ "Y-f$ext/tk/lib/tkextlib/blt/container.rbM7pM7p gÝ $R=PXG$ext/tk/lib/tkextlib/blt/cutbuffer.rbM7pM7p gs\VT Lޓ#ext/tk/lib/tkextlib/blt/dragdrop.rbM7pM7p g O$% iext/tk/lib/tkextlib/blt/eps.rbM7pM7p gkB@e1 Eԛ;l ext/tk/lib/tkextlib/blt/graph.rbM7pM7p g T٘-TuPw5p ext/tk/lib/tkextlib/blt/htext.rbM7pM7p g<@llP$Un>j)iN; ext/tk/lib/tkextlib/blt/setup.rbM7pM7p gПuz92W#!ext/tk/lib/tkextlib/blt/spline.rbM7pM7p gt ?hK,b]8"N+%ext/tk/lib/tkextlib/blt/stripchart.rbM7pM7p g&] ^)ǟqX| ext/tk/lib/tkextlib/blt/table.rbM7pM7p g lgk{rw(&ext/tk/lib/tkextlib/blt/tabnotebook.rbM7pM7p g0qlsf?W&JP!ext/tk/lib/tkextlib/blt/tabset.rbM7pM7p gcSͪ=I,LY!":ext/tk/lib/tkextlib/blt/ted.rbM7pM7p g|0>]ܸ c:4ext/tk/lib/tkextlib/blt/tile.rbM7pM7p g;.cϾ?K>O:2&ext/tk/lib/tkextlib/blt/tile/button.rbM7pM7p gr# Y%x-DG͒+ext/tk/lib/tkextlib/blt/tile/checkbutton.rbM7pM7p g6T4KrD 'Kb 04%ext/tk/lib/tkextlib/blt/tile/frame.rbM7pM7p g6p@;0z}5/:%ext/tk/lib/tkextlib/blt/tile/label.rbM7pM7p grO\ĦP6ٕ~O+ext/tk/lib/tkextlib/blt/tile/radiobutton.rbM7pM7p gJ*qãƵKJ)ext/tk/lib/tkextlib/blt/tile/scrollbar.rbM7pM7p gEvkZM0^y}֤(ext/tk/lib/tkextlib/blt/tile/toplevel.rbM7pM7p gj&S5Pp* O\ܶext/tk/lib/tkextlib/blt/tree.rbM7pM7p goHl7 _FFՊ#ext/tk/lib/tkextlib/blt/treeview.rbM7pM7p gȑvDW ~>#ext/tk/lib/tkextlib/blt/unix_dnd.rbM7pM7p gt.>MˑKOb?!ext/tk/lib/tkextlib/blt/vector.rbM7pM7p ge)&#X:oxBviM ext/tk/lib/tkextlib/blt/watch.rbM7pM7p gzƠzLki#ۋ&ext/tk/lib/tkextlib/blt/win_printer.rbM7pM7p g ^i茺ϕ ext/tk/lib/tkextlib/blt/winop.rbM7pM7p gzQ؋ Ɋř ext/tk/lib/tkextlib/bwidget.rbM7pM7p gYMc87*ext/tk/lib/tkextlib/bwidget/arrowbutton.rbM7pM7p gl{Id?%ext/tk/lib/tkextlib/bwidget/bitmap.rbM7pM7p gE9gt*HGյ%ext/tk/lib/tkextlib/bwidget/button.rbM7pM7p g3 X\!&8&c(ext/tk/lib/tkextlib/bwidget/buttonbox.rbM7pM7p g=4a悋H'ext/tk/lib/tkextlib/bwidget/combobox.rbM7pM7p gB;V!JH׮j=hX%ext/tk/lib/tkextlib/bwidget/dialog.rbM7pM7p gmMMx #yW6 d3ҡa%'ext/tk/lib/tkextlib/bwidget/dragsite.rbM7pM7p g鏼QQlQX'ext/tk/lib/tkextlib/bwidget/dropsite.rbM7pM7p gӄnX-ЇT:r=>B*ext/tk/lib/tkextlib/bwidget/dynamichelp.rbM7pM7p g!Ia#*5SSQ$ext/tk/lib/tkextlib/bwidget/entry.rbM7pM7p g5,bw"Yu&1$ext/tk/lib/tkextlib/bwidget/label.rbM7pM7p gi3 u.O'_D )ext/tk/lib/tkextlib/bwidget/labelentry.rbM7pM7p g?̚9v pMd)ext/tk/lib/tkextlib/bwidget/labelframe.rbM7pM7p gKidfba.ķ&ext/tk/lib/tkextlib/bwidget/listbox.rbM7pM7p g %;?Fu~%(ext/tk/lib/tkextlib/bwidget/mainframe.rbM7pM7p g{baG7Qx ^)ext/tk/lib/tkextlib/bwidget/messagedlg.rbM7pM7p g P(jM-'ext/tk/lib/tkextlib/bwidget/notebook.rbM7pM7p g1{/3iӜ+ext/tk/lib/tkextlib/bwidget/pagesmanager.rbM7pM7p g>T1X7w/GDڸ& *ext/tk/lib/tkextlib/bwidget/panedwindow.rbM7pM7p gD%&эiJNJ1)ext/tk/lib/tkextlib/bwidget/panelframe.rbM7pM7p g&P|;yM:(ext/tk/lib/tkextlib/bwidget/passwddlg.rbM7pM7p gg4|Poo_h۳xU<*ext/tk/lib/tkextlib/bwidget/progressbar.rbM7pM7p g E@ӊԂ D6*ext/tk/lib/tkextlib/bwidget/progressdlg.rbM7pM7p g+[ hpmcId;z.ext/tk/lib/tkextlib/bwidget/scrollableframe.rbM7pM7p gZfhUcZچP-ext/tk/lib/tkextlib/bwidget/scrolledwindow.rbM7pM7p g'kߒ<{u)ext/tk/lib/tkextlib/bwidget/scrollview.rbM7pM7p gEau~եx*ext/tk/lib/tkextlib/bwidget/selectcolor.rbM7pM7p g#A(YT yO)ext/tk/lib/tkextlib/bwidget/selectfont.rbM7pM7p gm2<4ǶXx(ext/tk/lib/tkextlib/bwidget/separator.rbM7pM7p g<@llP$Un>j)iN;$ext/tk/lib/tkextlib/bwidget/setup.rbM7pM7p gu EE&oaI&ext/tk/lib/tkextlib/bwidget/spinbox.rbM7pM7p g\]?ccyɤ3(ext/tk/lib/tkextlib/bwidget/statusbar.rbM7pM7p gq<&Y"3$)ext/tk/lib/tkextlib/bwidget/titleframe.rbM7pM7p g)\H/A*.K R#ext/tk/lib/tkextlib/bwidget/tree.rbM7pM7p g m3dgj˅7X>VZX%ext/tk/lib/tkextlib/bwidget/widget.rbM7pM7p g"n?aVKyH7ext/tk/lib/tkextlib/itcl.rbM7pM7p gKk:k 025s8$ext/tk/lib/tkextlib/itcl/incr_tcl.rbM7pM7p gpId/]#g!ext/tk/lib/tkextlib/itcl/setup.rbM7pM7p gt>uwl9ext/tk/lib/tkextlib/itk.rbM7pM7p h+ۘ; w=Nvf"ext/tk/lib/tkextlib/itk/incr_tk.rbM7pM7p hTI&ਫ }=x:ml ext/tk/lib/tkextlib/itk/setup.rbM7pM7p h uH{/ext/tk/lib/tkextlib/iwidgets.rbM7pM7p h mR\RIMLw Y3x)ext/tk/lib/tkextlib/iwidgets/buttonbox.rbM7pM7p h YG|KUaini(ext/tk/lib/tkextlib/iwidgets/calendar.rbM7pM7p h9?b!RZʟMj.ext/tk/lib/tkextlib/iwidgets/canvasprintbox.rbM7pM7p hMT^Z`=HKF1ext/tk/lib/tkextlib/iwidgets/canvasprintdialog.rbM7pM7p h  rGlN[A(ext/tk/lib/tkextlib/iwidgets/checkbox.rbM7pM7p h ] 4%igmM$تRK"S(ext/tk/lib/tkextlib/iwidgets/combobox.rbM7pM7p h UE7lqzQ^)ext/tk/lib/tkextlib/iwidgets/dateentry.rbM7pM7p h P@Z;綽廔"s)ext/tk/lib/tkextlib/iwidgets/datefield.rbM7pM7p h -ULqJƴ;7 ]u'/&ext/tk/lib/tkextlib/iwidgets/dialog.rbM7pM7p h YE29P{SC+ext/tk/lib/tkextlib/iwidgets/dialogshell.rbM7pM7p h\X{(/ext/tk/lib/tkextlib/iwidgets/disjointlistbox.rbM7pM7p hE>qIbƮ ٙE*ext/tk/lib/tkextlib/iwidgets/entryfield.rbM7pM7p hDjɕ< V)ext/tk/lib/tkextlib/iwidgets/extbutton.rbM7pM7p h/[ ؽ@S:W3m3ext/tk/lib/tkextlib/iwidgets/extfileselectionbox.rbM7pM7p hP6##ٴ",2_I6ext/tk/lib/tkextlib/iwidgets/extfileselectiondialog.rbM7pM7p h{)L]tҏ rr(ext/tk/lib/tkextlib/iwidgets/feedback.rbM7pM7p h%;_Tk)le笾0ext/tk/lib/tkextlib/iwidgets/fileselectionbox.rbM7pM7p hͯ '.m Kt3ext/tk/lib/tkextlib/iwidgets/fileselectiondialog.rbM7pM7p hQ=R.3A*j;54#*ext/tk/lib/tkextlib/iwidgets/finddialog.rbM7pM7p h˓hӍx)ext/tk/lib/tkextlib/iwidgets/hierarchy.rbM7pM7p hae"&3Q@_^3&)ext/tk/lib/tkextlib/iwidgets/hyperhelp.rbM7pM7p he9'8pg_6Ӧ,ext/tk/lib/tkextlib/iwidgets/labeledframe.rbM7pM7p htmBO/}bB-ext/tk/lib/tkextlib/iwidgets/labeledwidget.rbM7pM7p h^!ەf*cc*ext/tk/lib/tkextlib/iwidgets/mainwindow.rbM7pM7p h} U>BK6p ș'ext/tk/lib/tkextlib/iwidgets/menubar.rbM7pM7p hjSAJtRn.Ype@~*ext/tk/lib/tkextlib/iwidgets/messagebox.rbM7pM7p hozEQf.E4-ext/tk/lib/tkextlib/iwidgets/messagedialog.rbM7pM7p h ~jM&(ext/tk/lib/tkextlib/iwidgets/notebook.rbM7pM7p h!W}+ݾ^zNj <.!*ext/tk/lib/tkextlib/iwidgets/optionmenu.rbM7pM7p h" ueFj)iN;%ext/tk/lib/tkextlib/iwidgets/setup.rbM7pM7p h0`)"6¿H2 $S%ext/tk/lib/tkextlib/iwidgets/shell.rbM7pM7p h1ޞى;D\%(ext/tk/lib/tkextlib/iwidgets/spindate.rbM7pM7p h2N; v1'ext/tk/lib/tkextlib/iwidgets/spinint.rbM7pM7p h3 `n"/~f$ltWp'ext/tk/lib/tkextlib/iwidgets/spinner.rbM7pM7p h4 z b1M!(ext/tk/lib/tkextlib/iwidgets/spintime.rbM7pM7p h5$n9 Wp+ext/tk/lib/tkextlib/iwidgets/tabnotebook.rbM7pM7p h6 PId*/㟲hx u&ext/tk/lib/tkextlib/iwidgets/tabset.rbM7pM7p h7Dı\Gt)ext/tk/lib/tkextlib/iwidgets/timeentry.rbM7pM7p h8B<\wdw* )ext/tk/lib/tkextlib/iwidgets/timefield.rbM7pM7p h9[GL8"ߠN 'ext/tk/lib/tkextlib/iwidgets/toolbar.rbM7pM7p h:/L Gq %a%ext/tk/lib/tkextlib/iwidgets/watch.rbM7pM7p h;ƿ18<ǞLnJ"ext/tk/lib/tkextlib/pkg_checker.rbM7pM7p h<0y^-vxôBext/tk/lib/tkextlib/setup.rbM7pM7p h= (1Y }dcƭext/tk/lib/tkextlib/tcllib.rbM7pM7p h?295H;3}*T*!ext/tk/lib/tkextlib/tcllib/READMEM7pM7p h@-YsL@EnlM q(ext/tk/lib/tkextlib/tcllib/autoscroll.rbM7pM7p hAv=vmK2j&ext/tk/lib/tkextlib/tcllib/calendar.rbM7pM7p hB ՕLᘱ *ext/tk/lib/tkextlib/tcllib/canvas_sqmap.rbM7pM7p hCR&߀[)ext/tk/lib/tkextlib/tcllib/canvas_zoom.rbM7pM7p hD ? (0Q]3IT7fp6(ext/tk/lib/tkextlib/tcllib/chatwidget.rbM7pM7p hE I6O Gy@#('ext/tk/lib/tkextlib/tcllib/crosshair.rbM7pM7p hF 0G3g笸% #ext/tk/lib/tkextlib/tcllib/ctext.rbM7pM7p hG n\Gp'(WHuz.$ext/tk/lib/tkextlib/tcllib/cursor.rbM7pM7p hHwHoIHAχP'ext/tk/lib/tkextlib/tcllib/dateentry.rbM7pM7p hIL.t[MٹN䮌+\}'ext/tk/lib/tkextlib/tcllib/datefield.rbM7pM7p hJK24kZ;qQN&ext/tk/lib/tkextlib/tcllib/diagrams.rbM7pM7p hK"i(;BAu{$ext/tk/lib/tkextlib/tcllib/dialog.rbM7pM7p hL 'Hq;f3!_b̜'ext/tk/lib/tkextlib/tcllib/getstring.rbM7pM7p hMNnqLS6yXBX%ext/tk/lib/tkextlib/tcllib/history.rbM7pM7p hNx6,k f; y? c!ext/tk/lib/tkextlib/tcllib/ico.rbM7pM7p hO-QG#fVwˬ T&ext/tk/lib/tkextlib/tcllib/ip_entry.rbM7pM7p hPgGi^!YS"ext/tk/lib/tkextlib/tcllib/khim.rbM7pM7p hQ/)\G:Xce"fĩg'ext/tk/lib/tkextlib/tcllib/menuentry.rbM7pM7p hR LxHqV0atlU00g#ext/tk/lib/tkextlib/tcllib/ntext.rbM7pM7p hS QWL 5ULo (ext/tk/lib/tkextlib/tcllib/panelframe.rbM7pM7p hTP~ۭNZ'ext/tk/lib/tkextlib/tcllib/plotchart.rbM7pM7p hU-S +z=*yvL#ext/tk/lib/tkextlib/tcllib/ruler.rbM7pM7p hV;u6mb@+܁+)ext/tk/lib/tkextlib/tcllib/screenruler.rbM7pM7p hWHF$ƴ0`t,ext/tk/lib/tkextlib/tcllib/scrolledwindow.rbM7pM7p hX/L4;ë'ext/tk/lib/tkextlib/tcllib/scrollwin.rbM7pM7p hY<@llP$Un>j)iN;#ext/tk/lib/tkextlib/tcllib/setup.rbM7pM7p hZpFضt,=B 0K'ext/tk/lib/tkextlib/tcllib/statusbar.rbM7pM7p h[iƑnFMK +i#ext/tk/lib/tkextlib/tcllib/style.rbM7pM7p h\pĭSy=1Ń3,F(ext/tk/lib/tkextlib/tcllib/superframe.rbM7pM7p h] vd49EKpL &ext/tk/lib/tkextlib/tcllib/swaplist.rbM7pM7p h^z[ߍ/BL)5~#d'ext/tk/lib/tkextlib/tcllib/tablelist.rbM7pM7p h_eEuE߳e->$z SI,ext/tk/lib/tkextlib/tcllib/tablelist_core.rbM7pM7p h` XA^ )ڕ ό,ext/tk/lib/tkextlib/tcllib/tablelist_tile.rbM7pM7p ha/nKDbA2}TNY͖(ext/tk/lib/tkextlib/tcllib/tkpiechart.rbM7pM7p hb bnNTP~.%ext/tk/lib/tkextlib/tcllib/toolbar.rbM7pM7p hcc5*ǻ7%ext/tk/lib/tkextlib/tcllib/tooltip.rbM7pM7p hd TWu^5.铡hkL$ext/tk/lib/tkextlib/tcllib/widget.rbM7pM7p he:OvDmjBX"ext/tk/lib/tkextlib/tclx.rbM7pM7p hg<@llP$Un>j)iN;!ext/tk/lib/tkextlib/tclx/setup.rbM7pM7p hhZ ,ٴ7<[` ext/tk/lib/tkextlib/tclx/tclx.rbM7pM7p hi3l7!j)iN;!ext/tk/lib/tkextlib/tile/setup.rbM7pM7p hmY @u/\/N6Ǥ$ext/tk/lib/tkextlib/tile/sizegrip.rbM7pM7p hn+pB|2ͼBϦ!ext/tk/lib/tkextlib/tile/style.rbM7pM7p hoKRHBu+WfĄ,#ext/tk/lib/tkextlib/tile/tbutton.rbM7pM7p hp7u7^SXJ]j(ext/tk/lib/tkextlib/tile/tcheckbutton.rbM7pM7p hqҵ~-MLQ %ext/tk/lib/tkextlib/tile/tcombobox.rbM7pM7p hr[&3t`mn_,µv̯"ext/tk/lib/tkextlib/tile/tentry.rbM7pM7p hs<1&(\>:"ext/tk/lib/tkextlib/tile/tframe.rbM7pM7p htj)iN;"ext/tk/lib/tkextlib/tkDND/setup.rbM7qM7q h @h3"u4|jj"ext/tk/lib/tkextlib/tkDND/shape.rbM7qM7q hݗħ]El%+QM"ext/tk/lib/tkextlib/tkDND/tkdnd.rbM7qM7q h!_r7W U9X!ext/tk/lib/tkextlib/tkHTML.rbM7qM7q h#COw@=(ext/tk/lib/tkextlib/tkHTML/htmlwidget.rbM7qM7q h<@llP$Un>j)iN;#ext/tk/lib/tkextlib/tkHTML/setup.rbM7qM7q hYEGK;dz[jext/tk/lib/tkextlib/tkimg.rbM7qM7q h`ece_e[F}& ext/tk/lib/tkextlib/tkimg/READMEM7qM7q hfMQV.}@ ext/tk/lib/tkextlib/tkimg/bmp.rbM7qM7q hgBuaFFbS_ ext/tk/lib/tkextlib/tkimg/gif.rbM7qM7q hgEƇ$ u)cs`W ext/tk/lib/tkextlib/tkimg/ico.rbM7qM7q hm!&aP>/\y"O!ext/tk/lib/tkextlib/tkimg/jpeg.rbM7qM7q hgh1[M3\p ext/tk/lib/tkextlib/tkimg/pcx.rbM7qM7q h v8C+؞Z~N#ext/tk/lib/tkextlib/tkimg/pixmap.rbM7qM7q hg\HҀ]s*XGMkᓖ ext/tk/lib/tkextlib/tkimg/png.rbM7qM7q hgϮF}ʥ"O Ԓb ext/tk/lib/tkextlib/tkimg/ppm.rbM7qM7q hahݡR^ҍext/tk/lib/tkextlib/tkimg/ps.rbM7qM7q h<@llP$Un>j)iN;"ext/tk/lib/tkextlib/tkimg/setup.rbM7qM7q hgp8, 2H ext/tk/lib/tkextlib/tkimg/sgi.rbM7qM7q hgedB֕ݳ ext/tk/lib/tkextlib/tkimg/sun.rbM7qM7q hg@| ΤcSj)iN;$ext/tk/lib/tkextlib/tktable/setup.rbM7qM7q hXWzl.P!}Y",o&ext/tk/lib/tkextlib/tktable/tktable.rbM7qM7q h;["5GkDext/tk/lib/tkextlib/tktrans.rbM7qM7q h<@llP$Un>j)iN;$ext/tk/lib/tkextlib/tktrans/setup.rbM7qM7q hQ5Kn~X&ext/tk/lib/tkextlib/tktrans/tktrans.rbM7qM7q h)DRF_ 3ext/tk/lib/tkextlib/treectrl.rbM7qM7q h<@llP$Un>j)iN;%ext/tk/lib/tkextlib/treectrl/setup.rbM7qM7q hIy1P m4/~]*ext/tk/lib/tkextlib/treectrl/tktreectrl.rbM7qM7q hY_*!_1ext/tk/lib/tkextlib/trofs.rbM7qM7q h<@llP$Un>j)iN;"ext/tk/lib/tkextlib/trofs/setup.rbM7qM7q hz&uL&܄OͿG"ext/tk/lib/tkextlib/trofs/trofs.rbM7qM7q h[KxTU(zMݓ)Next/tk/lib/tkextlib/version.rbM7qM7q h#Ndf|M ,Sext/tk/lib/tkextlib/vu.rbM7qM7q h%d%v~hV|O"ext/tk/lib/tkextlib/vu/bargraph.rbM7qM7q hiUAEZ0S<|o{ ext/tk/lib/tkextlib/vu/charts.rbM7qM7q hMJU׵޼ 2{(ň!ext/tk/lib/tkextlib/vu/dial.rbM7qM7q h k H]4IF &ext/tk/lib/tkextlib/vu/pie.rbM7qM7q h<@llP$Un>j)iN;ext/tk/lib/tkextlib/vu/setup.rbM7qM7q h}a]K7_ڕ-d!ext/tk/lib/tkextlib/vu/spinbox.rbM7qM7q hE{\RGehT}S1ext/tk/lib/tkextlib/winico.rbM7qM7q h<@llP$Un>j)iN;#ext/tk/lib/tkextlib/winico/setup.rbM7qM7q h`–%͍cW$ext/tk/lib/tkextlib/winico/winico.rbM7qM7q h68f3m,/Liext/tk/lib/tkfont.rbM7qM7q h<5Vx0ypUQ9:}>ext/tk/lib/tkmacpkg.rbM7qM7q h?p!OU7ـ%qext/tk/lib/tkmenubar.rbM7qM7q hBp%+pC(4ext/tk/lib/tkmngfocus.rbM7qM7q h?Vh~@j,:Aext/tk/lib/tkpalette.rbM7qM7q hE`J=_Etext/tk/lib/tkscrollbox.rbM7qM7q h6b ! /FzHQext/tk/lib/tktext.rbM7qM7q hE ɒݻcƙctFext/tk/lib/tkvirtevent.rbM7qM7q h<7Tm}/:aext/tk/lib/tkwinpkg.rbM7qM7q hu ,Fd cext/tk/old-README.tcltklib.eucjM7qM7q h4o: WnGbText/tk/old-extconf.rbM7qM7q h$)N @}#|ext/tk/sample/24hr_clock.rbM7qM7q hF<.Bv ND!o`ext/tk/sample/binding_sample.rbM7qM7q h3dh~p4r%k2ext/tk/sample/bindtag_sample.rbM7qM7q h^iw)?ext/tk/sample/binstr_usage.rbM7qM7q hL6ԖG[Rx ext/tk/sample/btn_with_frame.rbM7qM7q h ba#N7 Qext/tk/sample/cd_timer.rbM7qM7q h͍;Rz>ext/tk/sample/cmd_res_test.rbM7qM7q hđUF.`r1QYext/tk/sample/cmd_resourceM7qM7q h nl .]%g v@ ext/tk/sample/demos-en/ChangeLogM7qM7q h%Sl U񆏘s=DG%ext/tk/sample/demos-en/ChangeLog.prevM7qM7q h4)8:LB,tMext/tk/sample/demos-en/READMEM7qM7q h1#ALM4@ڠ!n!ext/tk/sample/demos-en/README.1stM7qM7q hvY>'8V t#(ext/tk/sample/demos-en/README.tkencodingM7qM7q h`Jҏe@fAY"ext/tk/sample/demos-en/anilabel.rbM7qM7q h WՁ9hDCS/!ext/tk/sample/demos-en/aniwave.rbM7qM7q h#lE!S uJNext/tk/sample/demos-en/arrow.rbM7qM7q h=‘s kAm׉6A ext/tk/sample/demos-en/bind.rbM7qM7q h} ;P^UG8`\ ext/tk/sample/demos-en/bitmap.rbM7qM7q hQZrlS` wY]text/tk/sample/demos-en/browse1M7qM7q h0*ۨ-ext/tk/sample/demos-en/browse2M7qM7q h:/;:Lj\Lj ext/tk/sample/demos-en/button.rbM7qM7q h sGjmdN(+jzdext/tk/sample/demos-en/check.rbM7qM7q h O{<@fi2K ext/tk/sample/demos-en/check2.rbM7qM7q h m0L'uHz"_!ext/tk/sample/demos-en/clrpick.rbM7qM7q h1.- K;X~% ext/tk/sample/demos-en/colors.rbM7qM7q h wv` \۔Q|#GR ext/tk/sample/demos-en/combo.rbM7qM7q hQ@ vvNZ-7N4!ext/tk/sample/demos-en/cscroll.rbM7qM7q hL(8YߐOJrext/tk/sample/demos-en/ctext.rbM7qM7q hwGn0Z"74Bi]!ext/tk/sample/demos-en/dialog1.rbM7qM7q hķ%kYx!ext/tk/sample/demos-en/dialog2.rbM7qM7q hg}3Ӷc\\SirG;%ext/tk/sample/demos-en/doc.org/READMEM7qM7q h5Bx_{Ncm(ext/tk/sample/demos-en/doc.org/README.JPM7qM7q hK}t Uqs _!*ext/tk/sample/demos-en/doc.org/README.tk80M7qM7q ho1.$IY ,ext/tk/sample/demos-en/doc.org/license.termsM7qM7q ho1.$IY 1ext/tk/sample/demos-en/doc.org/license.terms.tk80M7qM7q hC[{E ext/tk/sample/demos-en/entry1.rbM7qM7q h <$KȾ\~j ext/tk/sample/demos-en/entry2.rbM7qM7q hӼbQzz / ext/tk/sample/demos-en/entry3.rbM7qM7q h T (LRMwd_!ext/tk/sample/demos-en/filebox.rbM7qM7q hm#}N$XI/jext/tk/sample/demos-en/floor.rbM7qM7q hwd; +!(l/m5Y ext/tk/sample/demos-en/floor2.rbM7qM7q h nWlT8$H%ext/tk/sample/demos-en/form.rbM7qM7q heӕnSҫHq=Ј}"ext/tk/sample/demos-en/goldberg.rbM7qM7q h^~>/d5[ext/tk/sample/demos-en/helloM7qM7q hn`!ig;ȉA gp ext/tk/sample/demos-en/hscale.rbM7qM7q h k Ї7ҬHSGrext/tk/sample/demos-en/icon.rbM7qM7q h#VO<ιt޾1!ext/tk/sample/demos-en/ttkmenu.rbM7qM7q i  {6,Xk!ext/tk/sample/demos-en/ttknote.rbM7qM7q i!f޲ǀBM*hQ !ext/tk/sample/demos-en/ttkpane.rbM7qM7q i" A8_[;uDpX*NF%ext/tk/sample/demos-en/ttkprogress.rbM7qM7q i#&`Eд"Mlext/tk/sample/demos-en/twind.rbM7qM7q i$7s݂mH̑gm޾P ext/tk/sample/demos-en/twind2.rbM7qM7q i%{Zq+Z8o_>`$ext/tk/sample/demos-en/unicodeout.rbM7qM7q i&x^ rHV6O,$ ext/tk/sample/demos-en/vscale.rbM7qM7q i'p% X%!bƕöext/tk/sample/demos-en/widgetM7qM7q i) Bl`WJ<\{ext/tk/sample/demos-jp/READMEM7qM7q i*a`x׶bήReRh!ext/tk/sample/demos-jp/README.1stM7qM7q i+ A 0E03`hx"ext/tk/sample/demos-jp/anilabel.rbM7qM7q i, <鄽U%0_KR7!ext/tk/sample/demos-jp/aniwave.rbM7qM7q i-"iMz 5RZMF6ext/tk/sample/demos-jp/arrow.rbM7qM7q i.qT׳:>.ext/tk/sample/demos-jp/bind.rbM7qM7q i/$? B8C#T ext/tk/sample/demos-jp/bitmap.rbM7qM7q i0QZrlS` wY]text/tk/sample/demos-jp/browse1M7qM7q i10*ۨ-ext/tk/sample/demos-jp/browse2M7qM7q i2ևXܘ ~{ ext/tk/sample/demos-jp/button.rbM7qM7q i3gv+w:1Ádq-/*  1!ext/tk/sample/demos-jp/clrpick.rbM7qM7q i6Ɵ3Fz ٥N%P/5 ext/tk/sample/demos-jp/colors.rbM7qM7q i7 Yf-Hs̚.tr;ext/tk/sample/demos-jp/combo.rbM7qM7q i8" 1^lL`p8!ext/tk/sample/demos-jp/cscroll.rbM7qM7q i9pѧu^1]j]EbKext/tk/sample/demos-jp/ctext.rbM7qM7q i:,/GqMk!ext/tk/sample/demos-jp/dialog1.rbM7qM7q i;G֨އzX^!ext/tk/sample/demos-jp/dialog2.rbM7qM7q i=g}3Ӷc\\SirG;%ext/tk/sample/demos-jp/doc.org/READMEM7qM7q i>5Bx_{Ncm(ext/tk/sample/demos-jp/doc.org/README.JPM7qM7q i?K}t Uqs _!*ext/tk/sample/demos-jp/doc.org/README.tk80M7qM7q i@o1.$IY ,ext/tk/sample/demos-jp/doc.org/license.termsM7qM7q iAo1.$IY 1ext/tk/sample/demos-jp/doc.org/license.terms.tk80M7qM7q iBqz%(|f ͬ8N9 ext/tk/sample/demos-jp/entry1.rbM7qM7q iC z ~'"Q ext/tk/sample/demos-jp/entry2.rbM7qM7q iD'( s Q5Bd ext/tk/sample/demos-jp/entry3.rbM7qM7q iE [Rz89!ext/tk/sample/demos-jp/filebox.rbM7qM7q iFmx#E,1hL ext/tk/sample/demos-jp/floor.rbM7qM7q iGw$=]HٯW}Xe ext/tk/sample/demos-jp/floor2.rbM7qM7q iHވ׋\,xG!/ext/tk/sample/demos-jp/form.rbM7qM7q iI~R;QV׉e-"ext/tk/sample/demos-jp/goldberg.rbM7qM7q iJTԙp)\+nEext/tk/sample/demos-jp/helloM7qM7q iKVP5/o-kDY ext/tk/sample/demos-jp/hscale.rbM7qM7q iL ̓UC[nHt%*c6?ext/tk/sample/demos-jp/icon.rbM7qM7q iMl")!h7>o ext/tk/sample/demos-jp/image1.rbM7qM7q iN O>FKSw1cԱ9 ext/tk/sample/demos-jp/image2.rbM7qM7q iOb^i}/bݕc ext/tk/sample/demos-jp/image3.rbM7qM7q iP8lD@] ){S!naext/tk/sample/demos-jp/items.rbM7qM7q iQ0F7sp $GJ 2'9U|~ext/tk/sample/demos-jp/ixsetM7qM7q iR![n@.ê9}Qext/tk/sample/demos-jp/ixset2M7qM7q iS#n0h#Hn{W%ext/tk/sample/demos-jp/knightstour.rbM7qM7q iT^oqlgP}j9'ext/tk/sample/demos-jp/label.rbM7qM7q iU ٜJm{3~$ext/tk/sample/demos-jp/labelframe.rbM7qM7q iV 7ߨqwOcBA]R ext/tk/sample/demos-jp/mclist.rbM7qM7q iW"FpԭIKUOhext/tk/sample/demos-jp/menu.rbM7qM7q iX# HS(Щ:&G ext/tk/sample/demos-jp/menu84.rbM7qM7q iY&Ixm<qip ext/tk/sample/demos-jp/menu8x.rbM7qM7q iZ{xART FZJ>ʫE ext/tk/sample/demos-jp/menubu.rbM7qM7q i[ ]%.* *P$| ext/tk/sample/demos-jp/msgbox.rbM7qM7q i\ pl,NOqL2̈ ext/tk/sample/demos-jp/rolodex-jM7qM7q ih!Zj63(hrAext/tk/sample/demos-jp/ruler.rbM7qM7q ii  ů\JU ӧ)e !ext/tk/sample/demos-jp/sayings.rbM7qM7q ij):9tfHb5vs) ext/tk/sample/demos-jp/search.rbM7qM7q ik +2Lط+"+?”ext/tk/sample/demos-jp/spin.rbM7qM7q ilYe"ڹ/۞+T1ext/tk/sample/demos-jp/squareM7qM7q imTҍN"?dxnr ext/tk/sample/demos-jp/states.rbM7qM7q in'1 (y˒<ext/tk/sample/demos-jp/style.rbM7qM7q io.4~ft2ԑҷext/tk/sample/demos-jp/tcolorM7qM7q ipH0D'xnǔ(*ext/tk/sample/demos-jp/text.rbM7qM7q iq `O@jЯp)KV%$"ext/tk/sample/demos-jp/textpeer.rbM7qM7q ir RXОhhr:=ext/tk/sample/demos-jp/timerM7qM7q isUW RpOC[?4TEk|?!ext/tk/sample/demos-jp/toolbar.rbM7qM7q itW(++_G4]ext/tk/sample/demos-jp/tree.rbM7qM7q iut?[4N+th { ext/tk/sample/demos-jp/ttkbut.rbM7qM7q iv8xg))Ϗ#Y!ext/tk/sample/demos-jp/ttkmenu.rbM7qM7q iw% W1}?I\!ext/tk/sample/demos-jp/ttknote.rbM7qM7q ixX; Bq=!ext/tk/sample/demos-jp/ttkpane.rbM7qM7q iy ?d,1Q`Fz=%ext/tk/sample/demos-jp/ttkprogress.rbM7qM7q iz% TfHaDZyɟext/tk/sample/demos-jp/twind.rbM7qM7q i{8 \(s_J ext/tk/sample/demos-jp/twind2.rbM7qM7q i|_HWIE4Xg@- $ext/tk/sample/demos-jp/unicodeout.rbM7qM7q i} fͩ9IvW54 ext/tk/sample/demos-jp/vscale.rbM7qM7q i~ߪNt 9QSak҆"Jext/tk/sample/demos-jp/widgetM7qM7q i zE t 2:]|=!ext/tk/sample/editable_listbox.rbM7qM7q i9ܜ@&O$þߍ$ext/tk/sample/encstr_usage.rbM7qM7q i0C%aŋxQidext/tk/sample/figmemo_sample.rbM7qM7q i,"Q\L_ext/tk/sample/images/earth.gifM7qM7q iG7''cL!ext/tk/sample/images/earthris.gifM7qM7q i1)5LnjX͑.ext/tk/sample/images/face.xbmM7qM7q i^U%A]<@!?yC!ext/tk/sample/images/flagdown.xbmM7qM7q iXnF)b ҚmʕHkext/tk/sample/images/flagup.xbmM7qM7q i4 B3E{%ext/tk/sample/images/gray25.xbmM7qM7q i4 B3E{%ext/tk/sample/images/grey.25M7qM7q i7h|JD/ext/tk/sample/images/grey.5M7qM7q i[V :F ext/tk/sample/images/letters.xbmM7qM7q iaWtN6 hdI,Cخ!ext/tk/sample/images/noletter.xbmM7qM7q i1_Z9YL? ext/tk/sample/images/pattern.xbmM7qM7q i %FA}) ? ext/tk/sample/images/tcllogo.gifM7qM7q i>m}oj#ext/tk/sample/images/teapot.ppmM7qM7q ip3ꉵԭext/tk/sample/irbtk.rbM7qM7q i : "Et[8Eѡ%6ext/tk/sample/irbtkw.rbwM7qM7q i@.?*b^,2ext/tk/sample/iso2022-kr.txtM7qM7q i3YܼSK]ext/tk/sample/menubar1.rbM7qM7q ifh>~NsC'S=ext/tk/sample/menubar2.rbM7qM7q i wi7vYﹴCext/tk/sample/menubar3.rbM7qM7q iن1gT"i.X8ext/tk/sample/msgs_rb/READMEM7qM7q i *smp*+ Hrext/tk/sample/msgs_rb/cs.msgM7qM7q i (8tB&r}*)1/ext/tk/sample/msgs_rb/de.msgM7qM7q iNT*'/D^ext/tk/sample/msgs_rb/el.msgM7qM7q iwp#@d7TMr԰BbSext/tk/sample/msgs_rb/en.msgM7qM7q i~ʼnY%9wd{Vbext/tk/sample/msgs_rb/en_gb.msgM7qM7q i &0^`&.$~ext/tk/sample/msgs_rb/eo.msgM7qM7q i F '6)'hX:vext/tk/sample/msgs_rb/es.msgM7qM7q i 95 bXם0ext/tk/sample/msgs_rb/fr.msgM7qM7q i '| z䷥働ext/tk/sample/msgs_rb/it.msgM7qM7q i@X|I('9̗ext/tk/sample/msgs_rb/ja.msgM7qM7q i$j6=;Sext/tk/sample/msgs_rb2/READMEM7qM7q i  lGi q5|%ext/tk/sample/msgs_rb2/de.msgM7qM7q iC蚦{[;av*bext/tk/sample/msgs_rb2/ja.msgM7qM7q iB.:lf>֋ ext/tk/sample/msgs_tk/READMEM7qM7q iipp^fD}"EText/tk/sample/msgs_tk/cs.msgM7qM7q iNC.WQ ׮GHX;ext/tk/sample/msgs_tk/de.msgM7qM7q i%s:SGGQQP9ϫ6ext/tk/sample/msgs_tk/el.msgM7qM7q i MXm^AI''ext/tk/sample/msgs_tk/en.msgM7qM7q iC8|㍖]=p_ext/tk/sample/msgs_tk/en_gb.msgM7qM7q iɚ?69gkext/tk/sample/msgs_tk/eo.msgM7qM7q ib6?`@Aext/tk/sample/msgs_tk/es.msgM7qM7q ix뻤I i튘8&8ext/tk/sample/msgs_tk/fr.msgM7qM7q i±Ds;:b1(N &Mext/tk/sample/msgs_tk/it.msgM7qM7q i\DX9Ft7ext/tk/sample/msgs_tk/ja.msgM7qM7q io1.$IY #ext/tk/sample/msgs_tk/license.termsM7qM7q id.2ʕC'kext/tk/sample/msgs_tk/nl.msgM7qM7q iy&+ LOw?θ$ext/tk/sample/msgs_tk/pl.msgM7qM7q iG+p<-d;(i{ext/tk/sample/msgs_tk/ru.msgM7qM7q i -2wTZ8_ ext/tk/sample/multi-ip_sample.rbM7qM7q iyǍJ՛,x8@*!ext/tk/sample/multi-ip_sample2.rbM7qM7q i0%J(|T%Kn)Eext/tk/sample/optobj_sample.rbM7qM7q ifJr,eX^ext/tk/sample/propagate.rbM7qM7q i4ub00!ext/tk/sample/remote-ip_sample.rbM7qM7q i -i^2ˇ ext/tk/sample/tcltklib/batsu.gifM7qM7q iВXJK!ext/tk/sample/tcltklib/lines0.tclM7qM7q i!cwD-P)x O ext/tk/sample/tcltklib/lines1.rbM7qM7q iYXP !^t ext/tk/sample/tcltklib/lines2.rbM7qM7q iʥ7UG;Jϐ q ext/tk/sample/tcltklib/lines3.rbM7qM7q i\zu࢖^xȡL ext/tk/sample/tcltklib/lines4.rbM7qM7q i,.@l*\2/@2ext/tk/sample/tcltklib/maru.gifM7qM7q i ],`)y\<uP} ext/tk/sample/tcltklib/safeTk.rbM7qM7q iLi7EwS!ext/tk/sample/tcltklib/sample0.rbM7qM7q i[ex3ՙK߾+ADJR!ext/tk/sample/tcltklib/sample1.rbM7qM7q i2/!27Jў|!ext/tk/sample/tcltklib/sample2.rbM7qM7q iXXo`- i %N>ext/tk/sample/tkalignbox.rbM7qM7q iө # >fbاȨ~ext/tk/sample/tkballoonhelp.rbM7qM7q i :Y+rDE*iBtSext/tk/sample/tkbiff.rbM7qM7q iVը+h|nb]Oext/tk/sample/tkbrowse.rbM7qM7q i2YV_M7I o!= ext/tk/sample/tkcombobox.rbM7qM7q iG$=,OG./Mext/tk/sample/tkdialog.rbM7qM7q i qYU\]w݌zkJ-ext/tk/sample/tkextlib/ICONS/Orig_LICENSE.txtM7qM7q iѤ [,Ѫ IEt?8$ext/tk/sample/tkextlib/ICONS/tkIconsM7qM7q iQj\)/ext/tk/sample/tkextlib/ICONS/tkIcons-sample.kdeM7qM7q iѤ [,Ѫ IEt?8(ext/tk/sample/tkextlib/ICONS/tkIcons.kdeM7qM7q i%)vsЭ_ROB)ext/tk/sample/tkextlib/ICONS/viewIcons.rbM7qM7q i  g]MW9fH8('ext/tk/sample/tkextlib/blt/barchart5.rbM7qM7q i^@CpS-S#&ext/tk/sample/tkextlib/blt/calendar.rbM7qM7q i1 ,[cp$ext/tk/sample/tkextlib/blt/graph6.rbM7qM7q i1P=Ae$ext/tk/sample/tkextlib/blt/graph7.rbM7qM7q iƍv``^ ̀"^1A%ext/tk/sample/tkextlib/blt/graph7a.rbM7qM7q i]T[O00Gj%ext/tk/sample/tkextlib/blt/graph7b.rbM7qM7q ifC}$5^cR%ext/tk/sample/tkextlib/blt/graph7c.rbM7qM7q i׾by%qSM.ext/tk/sample/tkextlib/blt/images/buckskin.gifM7qM7q i0Қr!b ij'k+ext/tk/sample/tkextlib/blt/images/chalk.gifM7qM7q i sk{6oi^mSC0-ext/tk/sample/tkextlib/blt/images/qv100.t.gifM7qM7q i׻Ay9Fė] ZN*ext/tk/sample/tkextlib/blt/images/rain.gifM7qM7q i@Ì-Ht3E8^"N­,ext/tk/sample/tkextlib/blt/images/sample.gifM7qM7q i I,;+Uw$ext/tk/sample/tkextlib/blt/pareto.rbM7qM7q iD|uͪBO#ext/tk/sample/tkextlib/blt/plot1.rbM7qM7q ig6CH$ext/tk/sample/tkextlib/blt/winop2.rbM7qM7q i  LGSZ2HB/ext/tk/sample/tkextlib/bwidget/Orig_LICENSE.txtM7qM7q i  l6q^M'ext/tk/sample/tkextlib/bwidget/basic.rbM7qM7q i )TQT?܃ ƢbAd*ext/tk/sample/tkextlib/bwidget/bwidget.xbmM7qM7q i>0y)Sn)&ext/tk/sample/tkextlib/bwidget/demo.rbM7qM7q i`"|R!v%ext/tk/sample/tkextlib/bwidget/dnd.rbM7qM7q ia0 q%*)JF)ext/tk/sample/tkextlib/bwidget/manager.rbM7qM7q i1:$K=f!eWܪ(ext/tk/sample/tkextlib/bwidget/select.rbM7qM7q i%,xQobޓ)ext/tk/sample/tkextlib/bwidget/tmpldlg.rbM7qM7q i(Vh4׃y&ext/tk/sample/tkextlib/bwidget/tree.rbM7qM7q iHa76=>+x\%ext/tk/sample/tkextlib/bwidget/x1.xbmM7qM7q i 2"`a!XqP-Y=ext/tk/sample/tkextlib/iwidgets/catalog_demo/Orig_LICENSE.txtM7qM7q jt]~m+L;ext/tk/sample/tkextlib/iwidgets/catalog_demo/images/box.xbmM7qM7q jEbY:`""5=ext/tk/sample/tkextlib/iwidgets/catalog_demo/images/clear.gifM7qM7q jC .˄K=ext/tk/sample/tkextlib/iwidgets/catalog_demo/images/close.gifM7qM7q j sܰ֎8-76sext/tk/sample/tkextlib/iwidgets/catalog_demo/images/points.xbmM7qM7q j+Y[QU,$, ext/tk/sample/tkextlib/iwidgets/catalog_demo/images/select.gifM7qM7q jzhc{qV2"y;l]8ext/tk/sample/tkextlib/iwidgets/sample/canvasprintbox.rbM7qM7q jyc"oaCJF~;ext/tk/sample/tkextlib/iwidgets/sample/canvasprintdialog.rbM7qM7q j-:97}z_tG!CX}ҷi9ext/tk/sample/tkextlib/iwidgets/sample/disjointlistbox.rbM7qM7q j"cM? yT ok6ext/tk/sample/tkextlib/iwidgets/sample/entryfield-1.rbM7qM7q j#߅UۥlE6ext/tk/sample/tkextlib/iwidgets/sample/entryfield-2.rbM7qM7q j$2=}lNHV=ext/tk/sample/tkextlib/iwidgets/sample/extfileselectionbox.rbM7qM7q j'[ȣI &Q@ext/tk/sample/tkextlib/iwidgets/sample/extfileselectiondialog.rbM7qM7q j({) -lQ[2ext/tk/sample/tkextlib/iwidgets/sample/feedback.rbM7qM7q j):[Q;ށ]soq-P~:ext/tk/sample/tkextlib/iwidgets/sample/fileselectionbox.rbM7qM7q j*T"CMu24IoH=ext/tk/sample/tkextlib/iwidgets/sample/fileselectiondialog.rbM7qM7q j+WPv\ܝ`r4ext/tk/sample/tkextlib/iwidgets/sample/finddialog.rbM7qM7q j,PpRhIP)c_[#3ext/tk/sample/tkextlib/iwidgets/sample/hierarchy.rbM7qM7q j-C+ӨqVQ0kn3ext/tk/sample/tkextlib/iwidgets/sample/hyperhelp.rbM7qM7q j.N.!'t ٧ޔq6ext/tk/sample/tkextlib/iwidgets/sample/labeledframe.rbM7qM7q j/WuPUZk!{27ext/tk/sample/tkextlib/iwidgets/sample/labeledwidget.rbM7qM7q j0g"pab D4X,~4ext/tk/sample/tkextlib/iwidgets/sample/mainwindow.rbM7qM7q j1 .u!}8 uwXhر1ext/tk/sample/tkextlib/iwidgets/sample/menubar.rbM7qM7q j2G|nc-ȭ+hcT2ext/tk/sample/tkextlib/iwidgets/sample/menubar2.rbM7qM7q j3Ӊ9u@O֝ǺD5ext/tk/sample/tkextlib/iwidgets/sample/messagebox1.rbM7qM7q j4Rx5hASqI_}t5ext/tk/sample/tkextlib/iwidgets/sample/messagebox2.rbM7qM7q j5ERy liQh|Ѥ7ext/tk/sample/tkextlib/iwidgets/sample/messagedialog.rbM7qM7q j6S( pr`ff2ext/tk/sample/tkextlib/iwidgets/sample/notebook.rbM7qM7q j7A~YsaZ13ext/tk/sample/tkextlib/iwidgets/sample/notebook2.rbM7qM7q j8\+#2wIY4ext/tk/sample/tkextlib/iwidgets/sample/optionmenu.rbM7qM7q j9@%..=k*K5ext/tk/sample/tkextlib/iwidgets/sample/panedwindow.rbM7qM7q j:}R1b<6ext/tk/sample/tkextlib/iwidgets/sample/panedwindow2.rbM7qM7q j;*&J)*6ext/tk/sample/tkextlib/iwidgets/sample/promptdialog.rbM7qM7q j<mڈƭ$|B~4ext/tk/sample/tkextlib/iwidgets/sample/pushbutton.rbM7qM7q j=g֠tS%2ext/tk/sample/tkextlib/iwidgets/sample/radiobox.rbM7qM7q j>_K%Tu8ext/tk/sample/tkextlib/iwidgets/sample/scrolledcanvas.rbM7qM7q j?彐ˋkռv|u7ext/tk/sample/tkextlib/iwidgets/sample/scrolledframe.rbM7qM7q j@+g_,2{s01xZ6ext/tk/sample/tkextlib/iwidgets/sample/scrolledhtml.rbM7qM7q jA,`5[gьYߍK9ext/tk/sample/tkextlib/iwidgets/sample/scrolledlistbox.rbM7qM7q jB+AIg232/!6ext/tk/sample/tkextlib/iwidgets/sample/scrolledtext.rbM7qM7q jCthItH *Le{]&6ext/tk/sample/tkextlib/iwidgets/sample/selectionbox.rbM7qM7q jD3W+N&/銮$9ext/tk/sample/tkextlib/iwidgets/sample/selectiondialog.rbM7qM7q jEWm(A\Ŵ2=[/ext/tk/sample/tkextlib/iwidgets/sample/shell.rbM7qM7q jFzfz%8φP,Eh2ext/tk/sample/tkextlib/iwidgets/sample/spindate.rbM7qM7q jG̈K2RQ_*釔1ext/tk/sample/tkextlib/iwidgets/sample/spinint.rbM7qM7q jHj 뇏RKTԤzv1ext/tk/sample/tkextlib/iwidgets/sample/spinner.rbM7qM7q jI,Krk5L 0_2ext/tk/sample/tkextlib/iwidgets/sample/spintime.rbM7qM7q jJ8+4Cc%65ext/tk/sample/tkextlib/iwidgets/sample/tabnotebook.rbM7qM7q jKf&umhP]Z령6ext/tk/sample/tkextlib/iwidgets/sample/tabnotebook2.rbM7qM7q jLF ZGe _0ext/tk/sample/tkextlib/iwidgets/sample/tabset.rbM7qM7q jMlFY9{9@J4+;VIG3ext/tk/sample/tkextlib/iwidgets/sample/timeentry.rbM7qM7q jNûYEtB3ext/tk/sample/tkextlib/iwidgets/sample/timefield.rbM7qM7q jO` ,PN";kW1ext/tk/sample/tkextlib/iwidgets/sample/toolbar.rbM7qM7q jP*;;5E[Kdr0/ext/tk/sample/tkextlib/iwidgets/sample/watch.rbM7qM7q jR $'(S M3]K=ࣰi5.ext/tk/sample/tkextlib/tcllib/Orig_LICENSE.txtM7qM7q jS5P}#IpK ym*ext/tk/sample/tkextlib/tcllib/datefield.rbM7qM7q jT~5wz\AoW(ext/tk/sample/tkextlib/tile/repeater.tclM7qM7q j`7~o (EE>R0ext/tk/sample/tkextlib/tile/themes/blue/blue.tclM7qM7q jb;<؀' rv`Xmyr D4xPYL}j`P :ext/tk/sample/tkextlib/tile/themes/blue/blue/arrowleft.gifM7qM7q jhJ>K&SAK6FKzp`>=ext/tk/sample/tkextlib/tile/themes/blue/blue/arrowright-h.gifM7qM7q jiG"`bKR=ext/tk/sample/tkextlib/tile/themes/blue/blue/arrowright-p.gifM7qM7q jjD+{ۄKÐz)` ;ext/tk/sample/tkextlib/tile/themes/blue/blue/arrowright.gifM7qM7q jk5`Ys9X-6D:ext/tk/sample/tkextlib/tile/themes/blue/blue/arrowup-h.gifM7qM7q jl9 $+VG5^m:ext/tk/sample/tkextlib/tile/themes/blue/blue/arrowup-p.gifM7qM7q jm:XWab(CvvG/8ext/tk/sample/tkextlib/tile/themes/blue/blue/arrowup.gifM7qM7q jn G;$ODE͖qs9ext/tk/sample/tkextlib/tile/themes/blue/blue/button-h.gifM7qM7q joلRSD|M,l9ext/tk/sample/tkextlib/tile/themes/blue/blue/button-n.gifM7qM7q jpўaM?)Z9ext/tk/sample/tkextlib/tile/themes/blue/blue/button-n.xcfM7qM7q jqQo6*\3G N9ext/tk/sample/tkextlib/tile/themes/blue/blue/button-p.gifM7qM7q jrSF6EHjj e9ext/tk/sample/tkextlib/tile/themes/blue/blue/check-hc.gifM7qM7q jst۷å렦`W9ext/tk/sample/tkextlib/tile/themes/blue/blue/check-hu.gifM7qM7q jt=G1Əs(ח@9ext/tk/sample/tkextlib/tile/themes/blue/blue/check-nc.gifM7qM7q juo6bE ް[69ext/tk/sample/tkextlib/tile/themes/blue/blue/check-nu.gifM7qM7q jvJy$ǣ\Sfpfc9ext/tk/sample/tkextlib/tile/themes/blue/blue/radio-hc.gifM7qM7q jwrcAmq F19ext/tk/sample/tkextlib/tile/themes/blue/blue/radio-hu.gifM7qM7q jx7wI_z] s9ext/tk/sample/tkextlib/tile/themes/blue/blue/radio-nc.gifM7qM7q jyX`^6'YXf:ext/tk/sample/tkextlib/tile/themes/blue/blue/sb-vthumb.gifM7qM7q j~>&D9NaE9ext/tk/sample/tkextlib/tile/themes/blue/blue/slider-p.gifM7qM7q j|˚JҖϸ+7ext/tk/sample/tkextlib/tile/themes/blue/blue/slider.gifM7qM7q j7=#O[G:ext/tk/sample/tkextlib/tile/themes/blue/blue/vslider-p.gifM7qM7q jt\b$/|l.0N 8ext/tk/sample/tkextlib/tile/themes/blue/blue/vslider.gifM7qM7q jOp9tn:!_i(4ext/tk/sample/tkextlib/tile/themes/blue/pkgIndex.tclM7qM7q jqyNt+^v6ext/tk/sample/tkextlib/tile/themes/keramik/keramik.tclM7qM7q j-`.6!Y%Bext/tk/sample/tkextlib/tile/themes/keramik/keramik/arrowdown-n.gifM7qM7q jRu&AA-t4#捝Bext/tk/sample/tkextlib/tile/themes/keramik/keramik/arrowdown-p.gifM7qM7q j$0V`"+,Kb8Bext/tk/sample/tkextlib/tile/themes/keramik/keramik/arrowleft-n.gifM7qM7q j!Yt`2}YhAJ9dBext/tk/sample/tkextlib/tile/themes/keramik/keramik/arrowleft-p.gifM7qM7q j_LhO%j0wCext/tk/sample/tkextlib/tile/themes/keramik/keramik/arrowright-n.gifM7qM7q j#3/0t:}/bf:~b@<Cext/tk/sample/tkextlib/tile/themes/keramik/keramik/arrowright-p.gifM7qM7q j ܭ[rYU;@ext/tk/sample/tkextlib/tile/themes/keramik/keramik/arrowup-n.gifM7qM7q jiWpX^S27Z@ext/tk/sample/tkextlib/tile/themes/keramik/keramik/arrowup-p.gifM7qM7q j!:ѷd?ext/tk/sample/tkextlib/tile/themes/keramik/keramik/button-d.gifM7qM7q j!4Ѯ6%kاlJs:ɿ?ext/tk/sample/tkextlib/tile/themes/keramik/keramik/button-h.gifM7qM7q jq^TO=G ?ext/tk/sample/tkextlib/tile/themes/keramik/keramik/button-n.gifM7qM7q jqH Ubŷ>Q?ext/tk/sample/tkextlib/tile/themes/keramik/keramik/button-p.gifM7qM7q j[u]^.cjH|EŜ!?ext/tk/sample/tkextlib/tile/themes/keramik/keramik/button-s.gifM7qM7q jy]>&bdX>ext/tk/sample/tkextlib/tile/themes/keramik/keramik/check-c.gifM7qM7q j<-?ɸ>ext/tk/sample/tkextlib/tile/themes/keramik/keramik/check-u.gifM7qM7q jګYWѼ$dext/tk/sample/tkextlib/tile/themes/keramik/keramik/radio-c.gifM7qM7q j!ZspZEwt%7>ext/tk/sample/tkextlib/tile/themes/keramik/keramik/radio-u.gifM7qM7q j Oڗm霟sxJJ9ext/tk/sample/tkextlib/tile/themes/kroc/kroc/button-n.gifM7qM7q j$ )iۉi,؜+r9ext/tk/sample/tkextlib/tile/themes/kroc/kroc/button-p.gifM7qM7q jAP<^%`Cw̭9ext/tk/sample/tkextlib/tile/themes/kroc/kroc/check-hc.gifM7qM7q jgth]Z>f/9ext/tk/sample/tkextlib/tile/themes/kroc/kroc/check-hu.gifM7qM7q j/(Ι|oI`9ext/tk/sample/tkextlib/tile/themes/kroc/kroc/check-nc.gifM7qM7q j&\#w,0OAp9ext/tk/sample/tkextlib/tile/themes/kroc/kroc/check-nu.gifM7qM7q j5̋ k[L9ext/tk/sample/tkextlib/tile/themes/kroc/kroc/radio-hc.gifM7qM7q jFy&jFslRͦb9ext/tk/sample/tkextlib/tile/themes/kroc/kroc/radio-hu.gifM7qM7q jxd7:zI*xj+z9ext/tk/sample/tkextlib/tile/themes/kroc/kroc/radio-nc.gifM7qM7q jm-*o;Mmi\c9ext/tk/sample/tkextlib/tile/themes/kroc/kroc/radio-nu.gifM7qM7q jw|Оl %p"?4ext/tk/sample/tkextlib/tile/themes/kroc/pkgIndex.tclM7qM7q joD7aܾy@C: 7ext/tk/sample/tkextlib/tile/themes/plastik/pkgIndex.tclM7qM7q jmnAb.L||b6ext/tk/sample/tkextlib/tile/themes/plastik/plastik.tclM7qM7q jjӉhE2kYBext/tk/sample/tkextlib/tile/themes/plastik/plastik/arrowdown-n.gifM7qM7q jIt ?D_fBext/tk/sample/tkextlib/tile/themes/plastik/plastik/arrowdown-p.gifM7qM7q jz9PJ짏ed8Bext/tk/sample/tkextlib/tile/themes/plastik/plastik/arrowleft-n.gifM7qM7q j E.K`Zr0DBext/tk/sample/tkextlib/tile/themes/plastik/plastik/arrowleft-p.gifM7qM7q j{cKdˏf)JCext/tk/sample/tkextlib/tile/themes/plastik/plastik/arrowright-n.gifM7qM7q j TYd:ƺҘ(pݢ eCext/tk/sample/tkextlib/tile/themes/plastik/plastik/arrowright-p.gifM7qM7q jk͕rʎRo0A@ext/tk/sample/tkextlib/tile/themes/plastik/plastik/arrowup-n.gifM7qM7q jso9Q^ԗ?@ext/tk/sample/tkextlib/tile/themes/plastik/plastik/arrowup-p.gifM7qM7q jT7i54_^Bzn*ext/tk/sample/tkextlib/tkHTML/page1/image2M7qM7q j ߯z@tDqH*ext/tk/sample/tkextlib/tkHTML/page1/image3M7qM7q j_p崴}15>(y*ext/tk/sample/tkextlib/tkHTML/page1/image4M7qM7q jg׍nzLMCB;LE*ext/tk/sample/tkextlib/tkHTML/page1/image5M7qM7q j6cPZl*ext/tk/sample/tkextlib/tkHTML/page1/image6M7qM7q j懖V\8J's*ext/tk/sample/tkextlib/tkHTML/page1/image7M7qM7q jd|Oj.yK*ext/tk/sample/tkextlib/tkHTML/page1/image8M7qM7q j:wXY@,Tzd2*ext/tk/sample/tkextlib/tkHTML/page1/image9M7qM7q jƞ[1Gx3K.ext/tk/sample/tkextlib/tkHTML/page1/index.htmlM7qM7q j.+.@&c*ext/tk/sample/tkextlib/tkHTML/page2/image1M7qM7q j0!`#D_rN+ext/tk/sample/tkextlib/tkHTML/page2/image10M7qM7q jNA6fg]ԁFम[+ext/tk/sample/tkextlib/tkHTML/page2/image11M7qM7q jeZheA& gWG+ext/tk/sample/tkextlib/tkHTML/page2/image12M7qM7q jՕT%=!iS"qE4+ext/tk/sample/tkextlib/tkHTML/page2/image13M7qM7q jms<@{#5 ~+ext/tk/sample/tkextlib/tkHTML/page2/image14M7qM7q jD;+"pO['+ext/tk/sample/tkextlib/tkHTML/page2/image15M7qM7q j<֟;pF#4+ext/tk/sample/tkextlib/tkHTML/page2/image16M7qM7q jQo 76EX{Iv91^7+ext/tk/sample/tkextlib/tkHTML/page2/image20M7qM7q j4%Ա/d3xHz+ext/tk/sample/tkextlib/tkHTML/page2/image21M7qM7q jQlc*Mc\1+ext/tk/sample/tkextlib/tkHTML/page2/image22M7qM7q j:tV~s)Meΰ+ext/tk/sample/tkextlib/tkHTML/page2/image23M7qM7q jKIVx)j]pC +ext/tk/sample/tkextlib/tkHTML/page2/image24M7qM7q jVO0;g-[++ext/tk/sample/tkextlib/tkHTML/page2/image25M7qM7q jY֭èZVyDuyE+ext/tk/sample/tkextlib/tkHTML/page2/image26M7qM7q j5jt"}$}H<]+ext/tk/sample/tkextlib/tkHTML/page2/image27M7qM7q jΦRUy>+ext/tk/sample/tkextlib/tkHTML/page2/image28M7qM7q jypAKVxS|AȔɭ+ext/tk/sample/tkextlib/tkHTML/page2/image29M7qM7q k*S?>op~`)U*ext/tk/sample/tkextlib/tkHTML/page2/image3M7qM7q kJA4>0xQ;+ext/tk/sample/tkextlib/tkHTML/page2/image30M7qM7q kN`>d ,x,7¥dN+ext/tk/sample/tkextlib/tkHTML/page2/image31M7qM7q k,(xUefk?j8+ext/tk/sample/tkextlib/tkHTML/page2/image32M7qM7q kV"W,z+ext/tk/sample/tkextlib/tkHTML/page2/image33M7qM7q k=]vl!a#/wK+ext/tk/sample/tkextlib/tkHTML/page2/image34M7qM7q kԮO0vd!G(hA+ext/tk/sample/tkextlib/tkHTML/page2/image35M7qM7q k=2gwt'+ext/tk/sample/tkextlib/tkHTML/page2/image36M7qM7q k|lk+E!Je+ext/tk/sample/tkextlib/tkHTML/page2/image37M7qM7q k  K)͚Yi1(+ext/tk/sample/tkextlib/tkHTML/page2/image38M7qM7q k qn/LmbP*>9 +ext/tk/sample/tkextlib/tkHTML/page2/image39M7qM7q k  ^F剹zaQi2*ext/tk/sample/tkextlib/tkHTML/page2/image4M7qM7q k djmQQ$UJٵ*ext/tk/sample/tkextlib/tkHTML/page2/image5M7qM7q k } B4*ext/tk/sample/tkextlib/tkHTML/page2/image6M7qM7q k'j He]iT(?*ext/tk/sample/tkextlib/tkHTML/page2/image7M7qM7q kvVۨeE*ext/tk/sample/tkextlib/tkHTML/page2/image8M7qM7q k:;7s }85a*ext/tk/sample/tkextlib/tkHTML/page2/image9M7qM7q k~-,cZ\\^]:R.ext/tk/sample/tkextlib/tkHTML/page2/index.htmlM7qM7q kqMeJ}uxOi΍*ext/tk/sample/tkextlib/tkHTML/page3/image1M7qM7q kE# }Lj Dc%+ext/tk/sample/tkextlib/tkHTML/page3/image10M7qM7q k|L!pSuʨUr`f+ext/tk/sample/tkextlib/tkHTML/page3/image11M7qM7q k >sD7Ɂ Ԕy+ext/tk/sample/tkextlib/tkHTML/page3/image12M7qM7q k"mOhPW]{+ext/tk/sample/tkextlib/tkHTML/page3/image13M7qM7q kqLuKj#&7%+ext/tk/sample/tkextlib/tkHTML/page3/image14M7qM7q kJ-޳%贩(H9&g*ext/tk/sample/tkextlib/tkHTML/page3/image2M7qM7q kQ~A\~ m'5U*ext/tk/sample/tkextlib/tkHTML/page3/image3M7qM7q k eB3@%*ext/tk/sample/tkextlib/tkHTML/page3/image4M7qM7q k&LORi$~*ext/tk/sample/tkextlib/tkHTML/page3/image5M7qM7q kOk& @vxb=(4*ext/tk/sample/tkextlib/tkHTML/page3/image6M7qM7q kMǪ ODjvAǝ*ext/tk/sample/tkextlib/tkHTML/page3/image7M7qM7q k` teƬ(ՓLz-*ext/tk/sample/tkextlib/tkHTML/page3/image8M7qM7q k  KFn? N}*ext/tk/sample/tkextlib/tkHTML/page3/image9M7qM7q k!Β.T˙][7VN.ext/tk/sample/tkextlib/tkHTML/page3/index.htmlM7qM7q k#*& .*'>^Bzn*ext/tk/sample/tkextlib/tkHTML/page4/image1M7qM7q k$8vjU.E [z&.*ext/tk/sample/tkextlib/tkHTML/page4/image2M7qM7q k%EV)q,P&(Sa?*ext/tk/sample/tkextlib/tkHTML/page4/image3M7qM7q k&=N5GBihS6Û-*ext/tk/sample/tkextlib/tkHTML/page4/image4M7qM7q k'N'r&x8\dԽ|*ext/tk/sample/tkextlib/tkHTML/page4/image5M7qM7q k(&@ݢ~6*ext/tk/sample/tkextlib/tkHTML/page4/image6M7qM7q k) &OŸˤNr*ext/tk/sample/tkextlib/tkHTML/page4/image7M7qM7q k*ˋՎ'SM --浃*ext/tk/sample/tkextlib/tkHTML/page4/image8M7qM7q k+RҔD$iÕ#?)*ext/tk/sample/tkextlib/tkHTML/page4/image9M7qM7q k,-ǿ5" ^'^XZp.ext/tk/sample/tkextlib/tkHTML/page4/index.htmlM7qM7q k-*E}i4EvJӓ#ext/tk/sample/tkextlib/tkHTML/ss.rbM7qM7q k/@1SxrXxlEJq$ext/tk/sample/tkextlib/tkimg/demo.rbM7qM7q k0Q_y5|I-;ext/tk/sample/tkextlib/tkimg/license_terms_of_Img_extensionM7qM7q k1MtI,qUSxyj'ext/tk/sample/tkextlib/tkimg/readme.txtM7qM7q k3 j|{R fJE.D/ext/tk/sample/tkextlib/tktable/Orig_LICENSE.txtM7qM7q k4۷vzE_|[U H'ext/tk/sample/tkextlib/tktable/basic.rbM7qM7q k5\z(iƪ97|WC)ext/tk/sample/tkextlib/tktable/buttons.rbM7qM7q k6 o9_M6AF"ՒH)ext/tk/sample/tkextlib/tktable/command.rbM7qM7q k7 m[5>7<_iNVwx'ext/tk/sample/tkextlib/tktable/debug.rbM7qM7q k8 yr!J@}HsFI1*ext/tk/sample/tkextlib/tktable/dynarows.rbM7qM7q k9t6ĜV O;uCH@)ext/tk/sample/tkextlib/tktable/maxsize.rbM7qM7q k:)S|A;o-ext/tk/sample/tkextlib/tktable/spreadsheet.rbM7qM7q k; %FA}) ?*ext/tk/sample/tkextlib/tktable/tcllogo.gifM7qM7q k<qÅZ2h>~'ext/tk/sample/tkextlib/tktable/valid.rbM7qM7q k> 7[-ʴTe*ext/tk/sample/tkextlib/treectrl/bitmaps.rbM7qM7q k?VJ[#3عϬ{5Ğ'ext/tk/sample/tkextlib/treectrl/demo.rbM7qM7q k@6@*F4$c@n+ext/tk/sample/tkextlib/treectrl/explorer.rbM7qM7q kA2}1잳 H9KVI)'ext/tk/sample/tkextlib/treectrl/help.rbM7qM7q kBrNcPE=^)ext/tk/sample/tkextlib/treectrl/imovie.rbM7qM7q kCH*f+`XqHob)ext/tk/sample/tkextlib/treectrl/layout.rbM7qM7q kD*hQ!Pr$p)%-ext/tk/sample/tkextlib/treectrl/mailwasher.rbM7qM7q kEfxfjr+֗1D2ext/tk/sample/tkextlib/treectrl/outlook-folders.rbM7qM7q kFAn4R.\"L%ۘ0Z3ext/tk/sample/tkextlib/treectrl/outlook-newgroup.rbM7qM7q kH  &%1򼂃LqLy%0ext/tk/sample/tkextlib/treectrl/pics/big-dll.gifM7qM7q kIpᚬ-k {{:0ext/tk/sample/tkextlib/treectrl/pics/big-exe.gifM7qM7q kJlu#iNi/&'[;1ext/tk/sample/tkextlib/treectrl/pics/big-file.gifM7qM7q kKlI@]U!|^Γ 3ext/tk/sample/tkextlib/treectrl/pics/big-folder.gifM7qM7q kL4Xn*8b\0/o0ext/tk/sample/tkextlib/treectrl/pics/big-txt.gifM7qM7q kMN;j_tü-g,zG0ext/tk/sample/tkextlib/treectrl/pics/checked.gifM7qM7q kNL*b+T[`R-ext/tk/sample/tkextlib/treectrl/pics/file.gifM7qM7q kOo Cvu\+R6r#9ext/tk/sample/tkextlib/treectrl/pics/help-book-closed.gifM7qM7q kR@elQkяy e7ext/tk/sample/tkextlib/treectrl/pics/help-book-open.gifM7qM7q kSrVG1N'2ext/tk/sample/tkextlib/treectrl/pics/help-page.gifM7qM7q kT_!UQUF=r 'mF#2ext/tk/sample/tkextlib/treectrl/pics/imovie-01.gifM7qM7q kU=-UbTAC_a82ext/tk/sample/tkextlib/treectrl/pics/imovie-02.gifM7qM7q kVX+Q*mȒa9R[A2ext/tk/sample/tkextlib/treectrl/pics/imovie-03.gifM7qM7q kWQɻx|-< -އ62ext/tk/sample/tkextlib/treectrl/pics/imovie-04.gifM7qM7q kX 's5+6 2ext/tk/sample/tkextlib/treectrl/pics/imovie-05.gifM7qM7q kY #bc֑df&2ext/tk/sample/tkextlib/treectrl/pics/imovie-06.gifM7qM7q kZ+(~iߗ ӷF2ext/tk/sample/tkextlib/treectrl/pics/imovie-07.gifM7qM7q k[FHfzp/o;ext/tk/sample/tkextlib/treectrl/pics/internet-check-off.gifM7qM7q k\Le+I,<T2:ext/tk/sample/tkextlib/treectrl/pics/internet-check-on.gifM7qM7q k]|z[Bٷ)Hv7ext/tk/sample/tkextlib/treectrl/pics/internet-print.gifM7qM7q k^Db4u,W }1F;ext/tk/sample/tkextlib/treectrl/pics/internet-radio-off.gifM7qM7q k_GB=lz4 Uv2:ext/tk/sample/tkextlib/treectrl/pics/internet-radio-on.gifM7qM7q k`rw9SD/[u9[G8ext/tk/sample/tkextlib/treectrl/pics/internet-search.gifM7qM7q kalӔ7"0F=H&x~+lārc2ext/tk/sample/tkextlib/treectrl/pics/unchecked.gifM7qM7q k{;3C2\@;Z@)ext/tk/sample/tkextlib/treectrl/random.rbM7qM7q k|g&ɹyy1=*ext/tk/sample/tkextlib/treectrl/readme.txtM7qM7q k}))j>"6d)&'}.ext/tk/sample/tkextlib/treectrl/www-options.rbM7qM7q k Bpԁw 3e*ext/tk/sample/tkextlib/vu/Orig_LICENSE.txtM7qM7q k_7`$.@gb*$ext/tk/sample/tkextlib/vu/README.txtM7qM7q k 6Oa;վ%88&ext/tk/sample/tkextlib/vu/canvItems.rbM7qM7q kۅq> qnɠh@L(ext/tk/sample/tkextlib/vu/canvSticker.rbM7qM7q k=!DMKis}Q)ext/tk/sample/tkextlib/vu/canvSticker2.rbM7qM7q kuhO`%d9`&ext/tk/sample/tkextlib/vu/dial_demo.rbM7qM7q k1E^<^mmn&ext/tk/sample/tkextlib/vu/m128_000.xbmM7qM7q kN*I8j)ext/tk/sample/tkextlib/vu/oscilloscope.rbM7qM7q k'nN]AA ^8a ext/tk/sample/tkextlib/vu/pie.rbM7qM7q kH52I_|4Fo$ext/tk/sample/tkextlib/vu/vu_demo.rbM7qM7q k ]ؑ߆m|^gTۯ'ext/tk/sample/tkfrom.rbM7qM7q kY|bB: westwext/tk/sample/tkhello.rbM7qM7q k1$ Fֶa,gj)mmext/tk/sample/tkline.rbM7qM7q ku5%&*N`كext/tk/sample/tkmenubutton.rbM7qM7q k ext/tk/tcltklib.cM7qM7q kKc0{ڦ OSQext/tk/tkutil/dependM7qM7q kWޗ< 0UD?he2 ext/tk/tkutil/extconf.rbM7qM7q km/4l)RTe.ext/tk/tkutil/tkutil.cM7qM7q kQK[eba l./ext/win32ole/dependM7qM7q k)AhwJaZ4.Cext/win32ole/extconf.rbM7qM7q kόV/$72Y ;k;ext/win32ole/lib/win32ole.rbM7qM7q kj|@nF\ˤ%ext/win32ole/lib/win32ole/property.rbM7qM7q k-82&4 Fext/win32ole/sample/excel1.rbM7qM7q kQyqӿiext/win32ole/sample/excel2.rbM7qM7q kqpcO=|EcM |3ext/win32ole/sample/excel3.rbM7qM7q k܆ {;Y.?[,d8ext/win32ole/sample/ie.rbM7qM7q k,jz8<ʜAtl}~5Qext/win32ole/sample/ieconst.rbM7qM7q k'ڮj' bB(itext/win32ole/sample/ienavi.rbM7qM7q kg~(6*6*A?ext/win32ole/sample/ienavi2.rbM7qM7q kt۬=~L  .ext/win32ole/sample/oledirs.rbM7qM7q k NvP|dCp~ ext/win32ole/sample/olegen.rbM7qM7q kKTu4[fy6ext/win32ole/sample/xml.rbM7qM7q k=uZ~enext/win32ole/win32ole.cM7qM7q kwIUFF?6!*`y ext/zlib/extconf.rbM7qM7q kAƘyF2u^nÔext/zlib/zlib.cM7qM7q k*+Pj]4zefile.cM7qM7q kN98oJ>P" Qgc.cM7qM7q k p炭DE}>R{gc.hM7qM7q k'=EA2;'L(#gem_prelude.rbM7qM7q k 6Cc3S#:b{ngolf_prelude.rbM7qM7q keHY'+pܝ+;m3@einclude/ruby/backward/st.hM7qM7q kkG ܶ!ّޕ9|include/ruby/backward/util.hM7qM7q k-rn include/ruby/defines.hM7qM7q k25ɚ}Û1z?/include/ruby/encoding.hM7qM7q kym:I }xo;>+sʟOinclude/ruby/intern.hM7qM7q kɵȮ٨VQ:tinclude/ruby/io.hM7qM7q k+p5:b[PAinclude/ruby/missing.hM7qM7q kgw:i ދXųJinclude/ruby/oniguruma.hM7qM7q k@9Wv~̩ dinclude/ruby/re.hM7qM7q ksA ۅ^tY0_Fuinclude/ruby/regex.hM7qM7q k;NQsw;r^7Pinclude/ruby/ruby.hM7qM7q kV'N9}/*ÝqxEinclude/ruby/st.hM7qM7q kwlYțu%1kinclude/ruby/subst.hM7qM7q k%auE?Vluinclude/ruby/util.hM7qM7q kE sDRSKWӿinclude/ruby/version.hM7qM7q kFT&[򻛻¸pJ *include/ruby/vm.hM7qM7q kC=M]>*Tmm 0EJinclude/ruby/win32.hM7qM7q k{oFup>i^lib/irb/slex.rbM7qM7q l?ZLa椪NW.b)7lib/irb/src_encoding.rbM7qM7q l@b~3{$~=UVlib/irb/version.rbM7qM7q lA R.holib/irb/workspace.rbM7qM7q lB:0HGeN4TFlib/irb/ws-for-case-2.rbM7qM7q lCۼ@ Swjt[lib/irb/xmp.rbM7qM7q lDM kNb>V>J`4 lib/logger.rbM7qM7q lEqkH`-E砽Dg9 lib/mathn.rbM7qM7q lF ?zu[ibM lib/matrix.rbM7qM7q lHj[_jd iAlib/minitest/autorun.rbM7qM7q lI&Ht^ѐ1ŕOlib/minitest/benchmark.rbM7qM7q lJtUa_H]RP>Xlib/minitest/mock.rbM7qM7q lKplib/minitest/pride.rbM7qM7q lL!j$µ/EPZ!lib/minitest/spec.rbM7qM7q lM[ w!o:{ lib/minitest/unit.rbM7qM7q lN &̟XNNmWHC8 lib/mkmf.rbM7qM7q lOԿp4,ґ5[Mrlib/monitor.rbM7qM7q lP {c]yvW{ HSDlib/mutex_m.rbM7qM7q lRBc2~fQf7"@Slib/net/.documentM7qM7q lS]NQp} yS)1"lib/net/ftp.rbM7qM7q lTG )|A!8ۇlib/net/http.rbM7qM7q lUo- YJ0<lib/net/https.rbM7qM7q lV vJ*xƵa`mklib/net/imap.rbM7qM7q lWfvjE҄ġM#&lib/net/pop.rbM7qM7q lX_]{=lib/net/protocol.rbM7qM7q lYp*Pv_Llib/optparse/uri.rbM7qM7q ldvVBc>Xzl@glib/optparse/version.rbM7qM7q le Q#u]EU#!lib/ostruct.rbM7qM7q lf5>V&}VAvSq߭ lib/pp.rbM7qM7q lg#~,2X|,d.+wlib/prettyprint.rbM7qM7q lh5դ )|^C?# lib/prime.rbM7qM7q li*N`څM Vlib/profile.rbM7qM7q ljZ=kllib/profiler.rbM7qM7q lk?#e8/C. lib/pstore.rbM7qM7q lm,s{]^0$'Wlib/racc/parser.rbM7qM7q ln^4`0m6QJ/0 lib/rake.rbM7qM7q lpVflŒG?QVlib/rake/classic_namespace.rbM7qM7q lqb}WQ-f\$֯lib/rake/clean.rbM7qM7q ls^1 פT<>/ x'&lib/rake/contrib/compositepublisher.rbM7qM7q lt%: ~j lib/rake/contrib/ftptools.rbM7qM7q luiӦTƦ/pB6m llib/rake/contrib/publisher.rbM7qM7q lv.i6e;ٯi/K\cI&lib/rake/contrib/rubyforgepublisher.rbM7qM7q lw~yql{ X^S= lib/rake/contrib/sshpublisher.rbM7qM7q lx 2:+ ѐhXdlib/rake/gempackagetask.rbM7qM7q lz* P ;]p lib/rake/loaders/makefile.rbM7qM7q l{sEb$$7mlib/rake/packagetask.rbM7qM7q l|n}ڴP3lib/rdoc/generator/template/darkfish/filepage.rhtmlM7qM7q lxQ4Ffr!GhP>s?5lib/rdoc/generator/template/darkfish/images/brick.pngM7qM7q l:#fSeZsj~se:lib/rdoc/generator/template/darkfish/images/brick_link.pngM7qM7q l-_9G&j?u4F3lib/rdoc/generator/template/darkfish/images/bug.pngM7qM7q lWa 6iO ;ɷt(4lib/rdoc/generator/template/darkfish/images/find.pngM7qM7q l)H3L'/bXz@lib/rdoc/generator/template/darkfish/images/loadingAnimation.gifM7qM7q lG;2N&c3Ql;lib/rdoc/generator/template/darkfish/images/macFFBgHack.pngM7qM7q lU<*-tYe`h%7lib/rdoc/generator/template/darkfish/images/package.pngM7qM7q lmގ?u, e]]d/:lib/rdoc/generator/template/darkfish/images/page_green.pngM7qM7q lV?q/rl_ߍ/-h7?lib/rdoc/generator/template/darkfish/images/page_white_text.pngM7qM7q l5}>t\)ܐ~n2<@lib/rdoc/generator/template/darkfish/images/page_white_width.pngM7qM7q lOaZp_OY&6lib/rdoc/generator/template/darkfish/images/plugin.pngM7qM7q lPchuEĨ*(ϋW4lib/rdoc/generator/template/darkfish/images/ruby.pngM7qM7q leK3dM'&A9lib/rdoc/generator/template/darkfish/images/tag_green.pngM7qM7q lb\Cg.Y~86lib/rdoc/generator/template/darkfish/images/wrench.pngM7qM7q lHVZ0VZD4K=lib/rdoc/generator/template/darkfish/images/wrench_orange.pngM7qM7q lR_*~h%s4lib/rdoc/generator/template/darkfish/images/zoom.pngM7qM7q l1$o Rl>}0lib/rdoc/generator/template/darkfish/index.rhtmlM7qM7q l wV\-N#a!&@ 3lib/rdoc/generator/template/darkfish/js/darkfish.jsM7qM7q lܯLJ!%`1lib/rdoc/generator/template/darkfish/js/jquery.jsM7qM7q l p|>lib/rdoc/generator/template/darkfish/js/thickbox-compressed.jsM7qM7q l2#`բjeoCs6-lib/rdoc/generator/template/darkfish/rdoc.cssM7qM7q l+F&:ogVv<lib/rdoc/ghost_method.rbM7qM7q lp'Dlib/rdoc/include.rbM7qM7q l _Smn [plib/rdoc/known_classes.rbM7qM7q lKȑOS5 oEK=lib/rdoc/markup.rbM7qM7q l7.C ->/sB܍$lib/rdoc/markup/attribute_manager.rbM7qM7q li]120OQ6lib/rdoc/markup/blank_line.rbM7qM7q lh.,+ܗ +Mlib/rdoc/markup/document.rbM7qM7q l MVbҚ3rllib/rdoc/markup/formatter.rbM7qM7q l=u\U\ 2.b &lib/rdoc/markup/formatter_test_case.rbM7qM7q l:cw).TX8plib/rdoc/markup/heading.rbM7qM7q l }q1rP[#š}olib/rdoc/markup/inline.rbM7qM7q lV LE=[zJlib/rdoc/markup/list.rbM7qM7q lRÁ\}et6lib/rdoc/markup/list_item.rbM7qM7q l0vE~# 4i~$lib/rdoc/markup/paragraph.rbM7qM7q l1[<[5NU! ղglib/rdoc/markup/parser.rbM7qM7q lm'8#Dfm#Ulib/rdoc/markup/pre_process.rbM7qM7q lʇ|ylib/rexml/comment.rbM7qM7q lT Q8Plib/rexml/doctype.rbM7qM7q lhD2gUT +>2lib/rexml/document.rbM7qM7q l%^t:6-n^*rlib/rexml/dtd/attlistdecl.rbM7qM7q l'n9W!y p~lib/rexml/dtd/dtd.rbM7qM7q mdZe+*Hlib/rexml/dtd/elementdecl.rbM7qM7q m(k+xuSBUlib/rexml/dtd/entitydecl.rbM7qM7q m#ѹ)>fXV[Tlib/rexml/dtd/notationdecl.rbM7qM7q m+d[}plib/rexml/element.rbM7qM7q mG>{߶:Ś^fKe'glib/rexml/encoding.rbM7qM7q m=8&z4fЊ"Olib/rexml/entity.rbM7qM7q m 3AI}$cɼ(<(2lib/rexml/formatters/default.rbM7qM7q m9G9w(i;gUXOlib/rexml/formatters/pretty.rbM7qM7q m %lƐ"[<~͝"lib/rexml/formatters/transitive.rbM7qM7q m +zϟY"ck䉝>lib/rexml/functions.rbM7qM7q m  4AK*ZE<lib/rexml/instruction.rbM7qM7q m p:S 6k:v1lib/rexml/light/node.rbM7qM7q m]9sX缰qlib/rexml/namespace.rbM7qM7q mEЀ/zoL~#A%llib/rexml/node.rbM7qM7q mu/n@s bdފs7s!lib/rexml/output.rbM7qM7q mO Q lm'rlib/rexml/parent.rbM7qM7q m MUڢaH)nO@3 lib/rexml/parseexception.rbM7qM7q mL tIb4vAlib/rexml/parsers/baseparser.rbM7qM7q mʖIZ,[,fy lib/rexml/parsers/lightparser.rbM7qM7q mVh~|@h]Zd4lib/rexml/parsers/pullparser.rbM7qM7q m"7iNE/?a8v)lib/rexml/parsers/sax2parser.rbM7qM7q m?,!fpneY'!lib/rexml/parsers/streamparser.rbM7qM7q m a6Lx Us&Jlib/rexml/parsers/treeparser.rbM7qM7q mj]~zgje)r%lib/rexml/parsers/ultralightparser.rbM7qM7q mMzx1&q&SaIP lib/rexml/parsers/xpathparser.rbM7qM7q m!O`9o:KX%4lib/rexml/quickpath.rbM7qM7q mQ~kA= ,lib/rexml/rexml.rbM7qM7q mfh0H: x.*ך4)lib/rexml/sax2listener.rbM7qM7q mq"{ V} W*k4Քlib/rexml/source.rbM7qM7q m aRxaR>%VTdlib/rexml/streamlistener.rbM7qM7q m!`=6MKԶGlib/rexml/syncenumerator.rbM7qM7q m"5@4p> Qlib/rexml/text.rbM7qM7q m#ҎЩYo{>90?v^(lib/rexml/undefinednamespaceexception.rbM7qM7q m%:g$A{vuPP SOlib/rexml/validation/relaxng.rbM7qM7q m&=Bb_>H9߸"lib/rexml/validation/validation.rbM7qM7q m'G#T ̅7w]6,8+lib/rexml/validation/validationexception.rbM7qM7q m( w2'q¶aE lib/rexml/xmldecl.rbM7qM7q m)}貺bOҘ s_!(lib/rexml/xmltokens.rbM7qM7q m* v_~)bsReShY(~Xlib/rexml/xpath.rbM7qM7q m+d;ӉЬɄ_Y¬.lib/rexml/xpath_parser.rbM7qM7q m-Ywh:MxMlib/rinda/.documentM7qM7q m.℥DׄpT%V[Ulib/rinda/rinda.rbM7qM7q m/*;Y::1&v'Q2lib/rinda/ring.rbM7qM7q m07p:y1mqlib/rinda/tuplespace.rbM7qM7q m1k*_OȈN lib/rss.rbM7qM7q m3%t(vtб>Sva}!lib/rss/0.9.rbM7qM7q m4!/;G#,b=)Cܶlib/rss/1.0.rbM7qM7q m5 ("Ř:PLj\\䁏 ;ܹlib/rss/2.0.rbM7qM7q m6Kyw u9F/ⰩၬzO%lib/rss/atom.rbM7qM7q m7.)jU *,Kcvlib/rss/content.rbM7qM7q m9܅y06nhڸ'lib/rss/content/1.0.rbM7qM7q m:7sD@#lib/rss/content/2.0.rbM7qM7q m;x>y:/%!rڃRlib/rss/converter.rbM7qM7q m<Sp֣ԯ00lib/rss/dublincore.rbM7qM7q m>ԁpagwlib/rss/dublincore/1.0.rbM7qM7q m?e! U5Dlib/rss/dublincore/2.0.rbM7qM7q m@k>dTLülib/rss/dublincore/atom.rbM7qM7q mAL瞟^eb^j4ڎ`Yl}3lib/rss/image.rbM7qM7q mB'\.|TJ7KKlib/rss/itunes.rbM7qM7q mC{ 2+KL6yI_lib/rss/maker.rbM7qM7q mE/+Ø4>2 y5Q(_Elib/rss/maker/0.9.rbM7qM7q mF(|;yoiXQz^^Eglib/rss/maker/1.0.rbM7qM7q mG4*nlib/rss/maker/2.0.rbM7qM7q mH1͞k:$Dlib/rss/maker/atom.rbM7qM7q mI`Rd-)Ňd}Ylib/rss/maker/base.rbM7qM7q mJFđsI\"%a lib/rss/maker/content.rbM7qM7q mKq{OlM"/r=CJlib/rss/maker/dublincore.rbM7qM7q mLY6 ^Op lib/rss/maker/entry.rbM7qM7q mM1)! ZGT/an~Zclib/rss/maker/feed.rbM7qM7q mN bn  g@~lib/rss/maker/image.rbM7qM7q mO t jz *%mlib/rss/trackback.rbM7qM7q m[ su]EǯFG}HfsFlib/rss/utils.rbM7qM7q m\[ 1)rylib/rss/xml-stylesheet.rbM7qM7q m]xr6S"v)Hlib/rss/xml.rbM7qM7q m^2+k(. vplib/rss/xmlparser.rbM7qM7q m_j߁ÿcpiDl lib/rss/xmlscanner.rbM7qM7q m`~uoH3ܿFmR/yd=2|Q/9(lib/rubygems/commands/cleanup_command.rbM7qM7q mj B;]4+]d)lib/rubygems/commands/contents_command.rbM7qM7q mk 5rϋmFti>Ӱ!Zh8&lib/rubygems/commands/fetch_command.rbM7qM7q mnOY{Ea L:Z/lib/rubygems/commands/generate_index_command.rbM7qM7q mo7o8 V;Թ%lib/rubygems/commands/help_command.rbM7qM7q mprStnYWdn3=W@.(lib/rubygems/commands/install_command.rbM7qM7q mq&| 2Ucz%lib/rubygems/commands/list_command.rbM7qM7q mr }mz$-A-)vPd%lib/rubygems/commands/lock_command.rbM7qM7q msL g.Cϸܛ)lib/rubygems/commands/outdated_command.rbM7qM7q mt9woT}q5 QY>&lib/rubygems/commands/owner_command.rbM7qM7q mu d#OJAM,`)lib/rubygems/commands/pristine_command.rbM7qM7q mv+tpo7g%lib/rubygems/commands/push_command.rbM7qM7q mw_)0e$GEXs?&lib/rubygems/commands/query_command.rbM7qM7q mx =ב/yi> %lib/rubygems/commands/rdoc_command.rbM7qM7q myMqaQ.nMs~'lib/rubygems/commands/search_command.rbM7qM7q mz "y.lib/rubygems/commands/specification_command.rbM7qM7q m~OmK]PPhZf&lib/rubygems/commands/stale_command.rbM7qM7q m Rհ>ۻ0wotDF>;*lib/rubygems/commands/uninstall_command.rbM7qM7q m ^ 0 7sMtj5'lib/rubygems/commands/unpack_command.rbM7qM7q mS[RuY"]A4g;'lib/rubygems/commands/update_command.rbM7qM7q m <ߩ|c4Jf&lib/rubygems/commands/which_command.rbM7qM7q m%_Y9Ӗv0IđOlib/rubygems/config_file.rbM7qM7q mLLB 9.7lib/rubygems/custom_require.rbM7qM7q m c^*`T~0B:lib/rubygems/defaults.rbM7qM7q m5іcoC(ulib/rubygems/dependency.rbM7qM7q m&9km }yg$lib/rubygems/dependency_installer.rbM7qM7q m3d{=+|hVy1+lib/rubygems/dependency_list.rbM7qM7q mZ/? %C%i@lib/rubygems/doc_manager.rbM7qM7q m`AR&6WQ lib/rubygems/errors.rbM7qM7q m vh ,RRQ!lib/rubygems/exceptions.rbM7qM7q mŒzfp'ӰIllib/rubygems/ext.rbM7qM7q m׉$*S: 13՛aylib/rubygems/ext/builder.rbM7qM7q mlfp*&'ٹw0]ͤf%lib/rubygems/ext/configure_builder.rbM7qM7q mQ2u:]3~L^f$lib/rubygems/ext/ext_conf_builder.rbM7qM7q mӵ˧\1xοt"2 lib/rubygems/ext/rake_builder.rbM7qM7q mu{;}9w%qAlib/rubygems/format.rbM7qM7q m U\3?d|lib/rubygems/gem_openssl.rbM7qM7q m b" yעnv" sE!lib/rubygems/gem_path_searcher.rbM7qM7q m C+[Q$[olib/rubygems/gem_runner.rbM7qM7q m5hIW3ӄ#lib/rubygems/gemcutter_utilities.rbM7qM7q mD&\-4 @0lib/rubygems/package_task.rbM7qM7q mͶ`xVf8?lib/rubygems/platform.rbM7qM7q m/ c9(H=ovdlib/rubygems/remote_fetcher.rbM7qM7q ma oAKjN b4%lib/rubygems/require_paths_builder.rbM7qM7q mڊִo*`Yoppdlib/rubygems/requirement.rbM7qM7q mt=S({~#_t% Plib/rubygems/security.rbM7qM7q mXcv"RH7)+Dlib/rubygems/server.rbM7qM7q m#s|WU<!fllib/rubygems/source_index.rbM7qM7q mə\U4 a,flib/rubygems/spec_fetcher.rbM7qM7q m]VXJe5^^ZVKlib/rubygems/specification.rbM7qM7q m ˉ.M 8 J6^lib/rubygems/test_utilities.rbM7qM7q m' >ϭSVlib/rubygems/text.rbM7qM7q mY&I2}Yɇp lib/rubygems/uninstaller.rbM7qM7q m)GA]#͒eB] lib/rubygems/user_interaction.rbM7qM7q mu"8lib/rubygems/validator.rbM7qM7q m)IfQlib/rubygems/version.rbM7qM7q myڏNTFrcڷUlib/rubygems/version_option.rbM7qM7q mTzP-42y+:,:| lib/scanf.rbM7qM7q m BQg跼f:( /lib/securerandom.rbM7qM7q msVUc$ubsw_sP lib/set.rbM7qM7q m&ӳ5; ى lib/shell.rbM7qM7q m Nd"FP7~ lib/shell/builtin-command.rbM7qM7q m:XtܣNd49Elib/shell/command-processor.rbM7qM7q m,۷c󍐫w/X/lib/shell/error.rbM7qM7q m?#Eɛbelib/shell/filter.rbM7qM7q mH!Q0=ZN_O}flib/shell/process-controller.rbM7qM7q m 4Y8u=šlib/shell/system-command.rbM7qM7q mnLQF|6T(lib/shell/version.rbM7qM7q m0iEs^wp1lib/shellwords.rbM7qM7q mg<욽ݸY+?lib/singleton.rbM7qM7q mw[7ii %M(c\ lib/sync.rbM7qM7q m(T ⰀZ'~ulib/tempfile.rbM7qM7q mu\}.ʚp7#lib/test/unit.rbM7qM7q m(,I-2B:Wlib/test/unit/assertions.rbM7qM7q m"=6,!]!٤k·R{lib/test/unit/testcase.rbM7qM7q mو4PLN'[ kk: lib/thread.rbM7qM7q m і?Ѷd7Lׯ| lib/thwait.rbM7qM7q mCmymcai\`9 &rv)Cr lib/time.rbM7qM7q m ){vly21 _vCq[Ilib/timeout.rbM7qM7q mCPM2` lib/tmpdir.rbM7qM7q m 1%JU}"F5Fg/Oʆ6iȽ[[a,ss} lib/un.rbM7qM7q mA g]9kb@R lib/uri.rbM7qM7q m?!MP:0/p)eZlib/uri/.documentM7qM7q mg0̽FMW0PھbetP?lib/uri/common.rbM7qM7q mN33gcdUvlib/uri/ftp.rbM7qM7q me5N568]{>dlib/uri/generic.rbM7qM7q m $iehr{iZplib/uri/http.rbM7qM7q mȗaccngtlib/uri/https.rbM7qM7q m g9o#FLDIC#lib/uri/ldap.rbM7qM7q mm3-t2NH@nMlib/uri/ldaps.rbM7qM7q m>ڬjq}lib/uri/mailto.rbM7qM7q mR9$$E/iC-9ƞҿlib/weakref.rbM7qM7q m+ʁ^OI6q lib/webrick.rbM7qM7q m S?B9N'NOt4)ylib/webrick/accesslog.rbM7qM7q mnm d穡^a9slib/webrick/cgi.rbM7qM7q mw`@oL\Z\tVp[lib/webrick/compat.rbM7qM7q md' ͖ T)lib/webrick/config.rbM7qM7q m !NfECeu=KOl[lib/webrick/cookie.rbM7qM7q mHύT, CRs@lib/webrick/htmlutils.rbM7qM7q m=|м3n҂/ !lib/webrick/httpauth.rbM7qM7q m %?z(h`K 9h۠%lib/webrick/httpauth/authenticator.rbM7qM7q m! 1Ix{:v!lib/webrick/httpauth/basicauth.rbM7qM7q m3sNbg?q.C˫~A"lib/webrick/httpauth/digestauth.rbM7qM7q mw9Iuo+(rNdcyюUD lib/webrick/httpauth/htdigest.rbM7qM7q m' aK4'KW=Nlib/webrick/httpauth/htgroup.rbM7qM7q maw`z>6J!z lib/webrick/httpauth/htpasswd.rbM7qM7q mR{O@[lib/webrick/httpauth/userdb.rbM7qM7q m Ι]mp>#j8;M$lib/webrick/httpproxy.rbM7qM7q m.y]wTޏAi "lib/webrick/httprequest.rbM7qM7q m + )+-O z2aĆ;lib/webrick/httpresponse.rbM7qM7q mZݝk|#Lhlib/webrick/https.rbM7qM7q mjJR/޳]hlib/webrick/httpserver.rbM7qM7q m|+^%GWB"klib/webrick/httpservlet.rbM7qM7q m0 gr avb8#lib/webrick/httpservlet/abstract.rbM7qM7q m2<-j$Ty%lib/webrick/httpservlet/cgi_runner.rbM7qM7q m %viHA4 ލY%lib/webrick/httpservlet/cgihandler.rbM7qM7q m#c0fS)fߨlib/webrick/log.rbM7qM7q nh;{\y6ktykClib/webrick/server.rbM7qM7q nóz[= ZnQT)Ɉlib/webrick/ssl.rbM7qM7q n64A[={5C:Blib/webrick/utils.rbM7qM7q n_;xns84 Y rlib/webrick/version.rbM7qM7q n u>t&r65lib/xmlrpc/.documentM7qM7q n !"gRWi[ىlib/xmlrpc/README.rdocM7qM7q n Bر9 AT^nlib/xmlrpc/README.txtM7qM7q n h#mTSR6lib/xmlrpc/base64.rbM7qM7q n JPe Hitbglib/xmlrpc/client.rbM7qM7q n 4ûvדYP\@~lib/xmlrpc/config.rbM7qM7q n-8K0ކX2,lib/xmlrpc/create.rbM7qM7q n@ ,>K^F뎹lib/xmlrpc/datetime.rbM7qM7q n(`^z705ί}4lib/xmlrpc/httpserver.rbM7qM7q n!&INx;m++lib/xmlrpc/marshal.rbM7qM7q nLĄ0Vh.ɝ3lib/xmlrpc/parser.rbM7qM7q nVO4\mYU5ڙelib/xmlrpc/server.rbM7qM7q n e :nlxn¾YBlib/xmlrpc/utils.rbM7qM7q nZ'Ok!У'5,< lib/yaml.rbM7qM7q n>NJ'.^|$lib/yaml/dbm.rbM7qM7q ne}'|<]lib/yaml/store.rbM7qM7q nL]n 9v]4)= load.cM7qM7q nۥk6)g( main.cM7qM7q n )]) 3 4 man/erb.1M7qM7q n _X< man/goruby.1M7qM7q n E-m689iۊP+ man/irb.1M7qM7q nQ&94ss!#73v= man/rake.1M7qM7q n 4cx@}man/ri.1M7qM7q n!6~o%O&^=\T\ man/ruby.1M7qM7q n"*aH[0.#cb s marshal.cM7qM7q n#G㧏t>Lꡚ@K_femath.cM7qM7q n$ aU[Nɘxn method.hM7qM7q n&ސ8c o1] misc/READMEM7qM7q n';5TD-"V =misc/inf-ruby.elM7qM7q n(ɊY-fK6wI`+/misc/rb_optparse.bashM7qM7q n)i1p=g!vzN~misc/rb_optparse.zshM7qM7q n* >";2M XOpno&W1misc/rdoc-mode.elM7qM7q n+Kǵr="чЄmisc/ruby-electric.elM7qM7q n, : xO5{^N+qY7xmisc/ruby-mode.elM7qM7q n-<\ѫ8__xJ misc/ruby-style.elM7qM7q n.BeS.Nmisc/rubydb2x.elM7qM7q n/xk}ZKNs4?ri޴misc/rubydb3x.elM7qM7q n1\i[YD`u%z(missing/acosh.cM7qM7q n29*M8spmissing/alloca.cM7qM7q n338Fy4€ kmissing/cbrt.cM7qM7q n4ub[RSI@.missing/close.cM7qM7q n5tHD!Ztۤ[missing/crypt.cM7qM7q n6uTL]t,*}" ,missing/dup2.cM7qM7q n7 ,NN|+hM missing/erf.cM7qM7q n8ٜA0 = missing/ffs.cM7qM7q n9-IB;I,}missing/file.hM7qM7q n:̸gEgY_rC䷻ßmissing/fileblocks.cM7qM7q n;v1{BGXXWmissing/finite.cM7qM7q n< H/2?A\dNmissing/flock.cM7qM7q n=%vUMd>ﳙsfM^missing/hypot.cM7qM7q n>JQewrUamissing/isinf.cM7qM7q n?XFP MQ0'd^V|missing/isnan.cM7qM7q n@9YOZ(ArYq(Mmissing/langinfo.cM7qM7q nAKdʂ߲`[+R,missing/lgamma_r.cM7qM7q nBiBDpW]%;vCmissing/memcmp.cM7qM7q nCt~#f,WbWmissing/memmove.cM7qM7q nD ;4H/<^kW missing/os2.cM7qM7q nE/|CV6?o3missing/signbit.cM7qM7q nFF_C@=C}missing/strchr.cM7qM7q nG9{Z 1\hjoTmissing/strerror.cM7qM7q nH )N-|Zs4pڲo29rmissing/strlcat.cM7qM7q nI .89teaTCmissing/strlcpy.cM7qM7q nJ!a<]/:)_`w5}missing/strstr.cM7qM7q nK·sLJ[c*@missing/strtol.cM7qM7q nL ^0oC[$ ΃missing/tgamma.cM7qM7q nMm'%CΙ4yRmissing/x86_64-chkstk.sM7qM7q nNZ^` =c|C8vXnode.cM7qM7q nO;Qfd bG}Mnode.hM7qM7q nP*Xr˰q˾g% numeric.cM7rM7r nQWu,~gk#@.,object.cM7rM7r nR_EO'Exǀg!OI39pack.cM7rM7r nS](x\parse.yM7rM7r nTK6TK prelude.rbM7rM7r nU956^BfזH cproc.cM7rM7r nVD*j2YQO|{!?y process.cM7rM7r nWjقtM9gts#v[random.cM7rM7r nX_dfP2,ȯrange.cM7rM7r nYw BWb5-ya rational.cM7rM7r nZl!WdZ+I u*0re.cM7rM7r n[=ibJ춟fd7}c regcomp.cM7rM7r n\q2NvٷY;EbJH+ regenc.cM7rM7r n])b;gBBڇeregenc.hM7rM7r n^0vsample/cbreak.rbM7rM7r nk=iEjJ=ي \sample/clnt.rbM7rM7r nl^ oMy"sample/coverage.rbM7rM7r nm'89FF2!%+L sample/dir.rbM7rM7r no}\C ɽ=<sample/drb/README.rdM7rM7r np};`7keF;sample/drb/README.rd.jaM7rM7r nq˕tkҰPsample/drb/darray.rbM7rM7r nr&Yp,FKmosample/drb/darrayc.rbM7rM7r ns 2O8~sample/drb/dbiff.rbM7rM7r ntj$h 3VxE+ll'sample/drb/dcdbiff.rbM7rM7r nu5F6fO!sample/drb/dchatc.rbM7rM7r nvt-zBv{eVep sample/drb/dchats.rbM7rM7r nw_$xB2 ssample/drb/dhasen.rbM7rM7r nx'tZV#gY>g^`sample/drb/dhasenc.rbM7rM7r ny [ǵ YrݵP3.7sample/drb/dlogc.rbM7rM7r nzeV})dV]uS\sample/drb/dlogd.rbM7rM7r n{;ʨ <=ퟰÜsample/drb/dqin.rbM7rM7r n|u[x)16m`R sample/drb/dqlib.rbM7rM7r n} G\q:0osample/drb/dqout.rbM7rM7r n~6U)V0sample/drb/holderc.rbM7rM7r n=-t#Up+ȑӏsample/drb/holders.rbM7rM7r nvIRM/,CGsample/drb/http0.rbM7rM7r no kV])i¹sample/drb/http0serv.rbM7rM7r nxTNJgsample/drb/name.rbM7rM7r no0"5 , hLsample/drb/namec.rbM7rM7r n>.B >Asample/drb/old_tuplespace.rbM7rM7r no/\ `%UWsample/drb/rinda_ts.rbM7rM7r n>r ޯV 3鯞s@sample/drb/rindac.rbM7rM7r nA٭ڡÎDf|sample/drb/rindas.rbM7rM7r n3FV 8@?'sample/drb/ring_echo.rbM7rM7r np4+pzvA~CF[sample/drb/ring_inspect.rbM7rM7r n Z2d&Ȯsample/drb/ring_place.rbM7rM7r n: y7%ӤŠvUsample/drb/simpletuple.rbM7rM7r nb&ԍ|TՖa瞓sample/drb/speedc.rbM7rM7r nva`T&sample/drb/speeds.rbM7rM7r n)Ե~y&sample/dualstack-fetch.rbM7rM7r n tW143Usample/dualstack-httpd.rbM7rM7r nK|= Aʍ^E8sample/eval.rbM7rM7r n[_^aH1H\sample/export.rbM7rM7r nnvh 1m@ZTsample/exyacc.rbM7rM7r n}z@RbS1 xrsample/fact.rbM7rM7r ns~05!u4sample/fib.awkM7rM7r nZI)7=<{U2 sample/fib.plM7rM7r n$'fRs>sample/openssl/crlstore.rbM7rM7r nL!D:xZsample/openssl/echo_cli.rbM7rM7r n#q澄6'$Sl,sample/openssl/echo_svr.rbM7rM7r n!B(p+$+vY{sample/openssl/gen_csr.rbM7rM7r n9O5ǽtH"sample/webrick/demo-urlencoded.cgiM7rM7r n5$ m:o>NX(;Dsample/webrick/hello.cgiM7rM7r nMgh*Zp{Bj |sample/webrick/hello.rbM7rM7r nаuWX.)У<sample/webrick/httpd.rbM7rM7r nDF&W1n&zsample/webrick/httpproxy.rbM7rM7r n x,Zsample/webrick/httpsd.rbM7rM7r n^' Me7U#signal.cM7rM7r nexjbR |# c$2, spec/READMEM7rM7r n=ZF#A) \spec/default.mspecM7rM7r nG@>I3yv@T sprintf.cM7rM7r nzv( 1t=_4-/(st.cM7rM7r nw"(nԊ ,v\-֖ 'd strftime.cM7rM7r nn! upՃc8string.cM7rM7r nax6GZ@8struct.cM7rM7r n [P24q'Bp+6K9ӂsymbian/README.SYMBIANM7rM7r oX:5`||symbian/configure.batM7rM7r oרP9zisymbian/missing-aeabi.cM7rM7r oOdZȐ$l(symbian/missing-pips.cM7rM7r o M>K) Q9symbian/pre-buildM7rM7r o96t!jmpv<94Xo symbian/setupM7rM7r o';*(cF (h6template/yarvarch.jaM7rM7r ou@c(template/yasmdata.rb.tmplM7rM7r oRkZ L #2E'test/-ext-/array/test_resize.rbM7rM7r oオ_{>/˷ԣqptest/-ext-/load/test_dot_dot.rbM7rM7r oW˃"dkIe!test/-ext-/string/test_set_len.rbM7rM7r o  b`T(>\6EPtest/-ext-/test_add_suffix.rbM7rM7r o!C3 AugPFstest/-ext-/test_bug-3571.rbM7rM7r o"sirA`舝%test/-ext-/test_bug-3662.rbM7rM7r o$cLϘV]>ٶtest/base64/test_base64.rbM7rM7r o&m9X$1>,a|ͣ test/benchmark/test_benchmark.rbM7rM7r o(r0TW Tc)\<"test/bigdecimal/test_bigdecimal.rbM7rM7r o) )0ex'6yX4test/cgi/test_cgi_tag_helper.rbM7rM7r o3q辬=Bct#ocywtest/cgi/test_cgi_util.rbM7rM7r o56,96Ktv6Y ^test/cgi/testdata/file1.htmlM7rM7r o6b9oruiz$4test/cgi/testdata/large.pngM7rM7r o7Ru=X˿eB-Fi@HOtest/cgi/testdata/small.pngM7rM7r o92oYM0mUtest/coverage/test_coverage.rbM7rM7r o;zB&{sD\c#otest/csv/base.rbM7rM7r o<;9ri_iy='Mtest/csv/line_endings.gzM7rM7r o=UѾ ~MSDSסtest/csv/test_csv_parsing.rbM7rM7r o>pL}23++)>test/csv/test_features.rbM7rM7r oB @az,Jl4*lItest/csv/test_headers.rbM7rM7r oC ƒCgTꃥg#CR&n-test/csv/test_interface.rbM7rM7r oD!"4[z#BLB,x1ӛtest/csv/test_row.rbM7rM7r oE ۗ,/ٟzU8test/csv/test_serialization.rbM7rM7r oF+E\jY=ěrtest/csv/test_table.rbM7rM7r oGOF.80qtest/csv/ts_all.rbM7rM7r oI$͎zZÁMtest/date/test_date.rbM7rM7r oJ:t]lĪO`ojFhNtest/date/test_date_arith.rbM7rM7r oK Q&QCh%test/date/test_date_attr.rbM7rM7r oL8Ģf"VXζ^iq;test/date/test_date_base.rbM7rM7r oMtQg VYtest/date/test_date_compat.rbM7rM7r oN7Bi,{;z^test/date/test_date_conv.rbM7rM7r oOj/¡Af(F7test/date/test_date_marshal.rbM7rM7r oP x$r;{Etest/date/test_date_new.rbM7rM7r oQvஃ61eER> ֽtest/date/test_date_parse.rbM7rM7r oR4 ZJqE){Rtest/date/test_date_strftime.rbM7rM7r oSLِI9 ~wkfetest/date/test_date_strptime.rbM7rM7r oU2-u޼U#test/dbm/test_dbm.rbM7rM7r oWǬ=^aoSQg}&test/digest/test_digest.rbM7rM7r oX WפU&pz6c:%!test/digest/test_digest_extend.rbM7rM7r oYU>Vs-'test/erb/test_erb_m17n.rbM7rM7r o| z[Z|_J~test/etc/test_etc.rbM7rM7r o~ J.@/쭕qtest/fiddle/helper.rbM7rM7r opTf,3jF>test/fiddle/test_closure.rbM7rM7r obZ sR=|c\Btest/fiddle/test_fiddle.rbM7rM7r oPPZ(,Ȳĸ&test/fiddle/test_function.rbM7rM7r o 9~ szd_test/fileutils/fileasserts.rbM7rM7r o%ɴ__:!~rAtest/fileutils/test_dryrun.rbM7rM7r olIBճ:*rk test/fileutils/test_fileutils.rbM7rM7r oEu~01Tz&h-Ltest/fileutils/test_nowrite.rbM7rM7r oNK碅h=ŐLJF%test/fileutils/test_verbose.rbM7rM7r oEq\ E=иytest/gdbm/test_gdbm.rbM7rM7r oR%u.Y1 xWUtest/iconv/test_basic.rbM7rM7r ooI]&$retest/iconv/test_option.rbM7rM7r ow`p[% Ni-test/iconv/test_partial.rbM7rM7r o_r:H.XI堻9;test/iconv/utils.rbM7rM7r oF(sdSֈ>yߝatest/inlinetest.rbM7rM7r o #ٟ,59gYEc"test/io/console/test_io_console.rbM7rM7r o]Zg;wt\/vtest/io/nonblock/test_flush.rbM7rM7r oJ^);]Q9GCv/,3test/irb/test_option.rbM7rM7r or7L{wźWtest/json/fixtures/fail20.jsonM7rM7r o bGEs =ienYtest/json/fixtures/fail21.jsonM7rM7r o!u%RTtest/json/fixtures/fail22.jsonM7rM7r oIJ*4c'test/json/fixtures/fail23.jsonM7rM7r o#6)}( QI{*test/json/fixtures/fail24.jsonM7rM7r o-Y_LX}*?!test/json/fixtures/fail25.jsonM7rM7r okJ6`Gq[چ]test/json/fixtures/fail27.jsonM7rM7r obdE}zg|test/json/fixtures/fail28.jsonM7rM7r o%xS~nkgVMtest/json/fixtures/fail3.jsonM7rM7r oh4hD D#ftest/json/fixtures/fail4.jsonM7rM7r o=$ FpuEU]test/json/fixtures/fail5.jsonM7rM7r oXJu#uG"test/json/fixtures/fail6.jsonM7rM7r o>NAPMtest/json/fixtures/fail7.jsonM7rM7r oyi9Gtest/json/fixtures/fail8.jsonM7rM7r oXWO6>XϑWڻ@*utest/json/fixtures/fail9.jsonM7rM7r okx(7N7gqxHtest/json/fixtures/pass1.jsonM7rM7r o"viݢ??فm6test/json/fixtures/pass15.jsonM7rM7r o :†8.,W]+&Qtest/json/fixtures/pass16.jsonM7rM7r o"b!JJr 6 8test/json/fixtures/pass17.jsonM7rM7r o4OQU1_btest/net/http/utils.rbM7rM7r o q~hVN5=L7qNtest/net/imap/cacert.pemM7rM7r o kHj.r#CNbtest/net/imap/server.crtM7rM7r ow|WTnή 3W! Ɵ$test/net/imap/server.keyM7rM7r o+*'"W&h1%Xhtest/net/imap/test_imap.rbM7rM7r oEYGv/gWٙW(*test/net/imap/test_imap_response_parser.rbM7rM7r o ȪpmzH9test/net/pop/test_pop.rbM7rM7r o 8L5qptest/net/smtp/test_response.rbM7rM7r oL}S*HaVrhtest/net/smtp/test_smtp.rbM7rM7r of܋zb 74 test/net/smtp/test_ssl_socket.rbM7rM7r o k ΀:W܅˗Atest/nkf/test_kconv.rbM7rM7r o s)_U)$Bztest/nkf/test_nkf.rbM7rM7r o8qM9:8_test/objspace/test_objspace.rbM7rM7r o]ڵ+!BlNW'Ttest/open-uri/test_open-uri.rbM7rM7r o4(cFDFj$/Ftest/open-uri/test_ssl.rbM7rM7r oSӭU6Kl)0k%VL$test/openssl/test_hmac.rbM7rM7r o;>o+ dB%Ttest/openssl/test_ns_spki.rbM7rM7r oB~M2We#s _!test/openssl/test_ocsp.rbM7rM7r od3=P}\ctest/openssl/test_pair.rbM7rM7r o "4:9y)Oy6D^9test/openssl/test_pkcs12.rbM7rM7r o4#(B_m Gxatest/openssl/test_pkcs7.rbM7rM7r o]ٌ a>1'cwtest/openssl/test_pkey_rsa.rbM7rM7r oJ=(=W-~Hb>&test/openssl/test_ssl.rbM7rM7r oxnh.iJN test/openssl/test_x509cert.rbM7rM7r o ɖf~X8S D"m[>test/openssl/test_x509crl.rbM7rM7r pʼn\rpxN~test/openssl/test_x509ext.rbM7rM7r p&% *|v.؏ntest/openssl/test_x509name.rbM7rM7r pDf Q}?${Wtest/openssl/test_x509req.rbM7rM7r p$ ~՗X"Tv۩~test/openssl/test_x509store.rbM7rM7r pv !Cm] =X2$test/openssl/utils.rbM7rM7r pӺmg ʔ4LEOW%test/optparse/test_bash_completion.rbM7rM7r p""w ,test/optparse/test_getopts.rbM7rM7r p>n/x'/1(L$Ftest/optparse/test_noarg.rbM7rM7r p o Xq3+<ނ,&@test/optparse/test_optarg.rbM7rM7r p qjW)1 ߭3,.test/optparse/test_optparse.rbM7rM7r p dhFVa6Utest/optparse/test_placearg.rbM7rM7r p G騧x~ݜ2qtest/optparse/test_reqarg.rbM7rM7r p  g[;N ^r74CJtest/optparse/test_summary.rbM7rM7r pQ~[W>Šx v$test/optparse/test_zsh_completion.rbM7rM7r p\Ңs*~x<test/ostruct/test_ostruct.rbM7rM7r pM[J,uf4H2-cc< test/pathname/test_pathname.rbM7rM7r pT;>L>)8"bPJtest/profile_test_all.rbM7rM7r palhL&3#Ztest/psych/helper.rbM7rM7r pq$e/m;q]ƿPtest/psych/json/test_stream.rbM7rM7r p䌜jJ%\EEh'/( |#test/psych/test_alias_and_anchor.rbM7rM7r p"̆lD{n86shtest/psych/test_array.rbM7rM7r pV06j M`Atest/psych/test_boolean.rbM7rM7r pZ9J;ǁ Q78test/psych/test_class.rbM7rM7r pH =]AWp;<*test/psych/test_coder.rbM7rM7r p(fBC1;E~test/psych/test_date_time.rbM7rM7r p:r#2L:|&^test/psych/test_deprecated.rbM7rM7r p 5JlW״\T test/psych/test_document.rbM7rM7r p  <T_DI衆:Ntest/psych/test_emitter.rbM7rM7r p!f2Bv_ V?F,qLtest/psych/test_encoding.rbM7rM7r p"ڠ/ 4eHc2!test/psych/test_engine_manager.rbM7rM7r p#}jN`^test/psych/test_exception.rbM7rM7r p$悫*>7P lhtest/psych/test_hash.rbM7rM7r p%_ j7St8!:Kqtest/psych/test_json_tree.rbM7rM7r p&[[3DXS`Gtest/psych/test_omap.rbM7rM7r p*"M;l}RJ$E^test/psych/test_parser.rbM7rM7r p+с;dWɬUL&test/psych/test_psych.rbM7rM7r p,iuH$f49test/psych/test_scalar.rbM7rM7r p-ir6|kbP81%n!test/psych/test_scalar_scanner.rbM7rM7r p.&QY;6&kB'test/psych/test_serialize_subclasses.rbM7rM7r p/q(O@"뚪fRtest/psych/test_set.rbM7rM7r p0(~/gX-i?/P^dtest/psych/test_stream.rbM7rM7r p1"Wzg)M test/psych/test_string.rbM7rM7r p2/\nq0test/psych/test_struct.rbM7rM7r p3 +Dpф&H$^test/psych/test_symbol.rbM7rM7r p4y[H`5Coﴏz,^_4%test/psych/test_to_yaml_properties.rbM7rM7r p5BzؠDWJ1~ftest/psych/test_tree_builder.rbM7rM7r p6}E9v;F>ūp\=8test/psych/test_yaml.rbM7rM7r p8xGΣjU(Uwű(,#test/psych/visitors/test_emitter.rbM7rM7r p9(D=4[d_|-9>#test/psych/visitors/test_to_ruby.rbM7rM7r p:c}Qm#ך%test/psych/visitors/test_yaml_tree.rbM7rM7r p<vN/ixˡA[test/rake/capture_stdout.rbM7rM7r p=1eQi_ǐ)+= qhtest/rake/check_expansion.rbM7rM7r p>1${ ]cA~f^test/rake/check_no_expansion.rbM7rM7r p@Fq7]][Lo'test/rake/contrib/test_ftp.rbM7rM7r pC1WrLDS(hx}test/rake/data/chains/RakefileM7rM7r pE"^ ՠ%pw test/rake/data/default/RakefileM7rM7r pGn h,Q5@kLI6test/rake/data/dryrun/RakefileM7rM7r pIOdir8B9oF;Ez|*test/rake/data/file_creation_task/RakefileM7rM7r pKj`K[taVtest/rake/data/imports/RakefileM7rM7r pLd= j@UՆdtest/rake/data/imports/deps.mfM7rM7r pNSBH"J1͗٠{ [<!test/rake/data/multidesc/RakefileM7rM7r pPmL251v!test/rake/data/namespace/RakefileM7rM7r pR$A@;*Ypw6!test/rake/data/rakelib/test1.rakeM7rM7r pT!g3[mP}-)w,2=\B test/rake/data/rbext/rakefile.rbM7rM7r pUwEo{D ȿ'Ntest/rake/data/sample.mfM7rM7r pWGh0R@ROO䓱,s$test/rake/data/statusreturn/RakefileM7rM7r pY;HC (n7n test/rake/data/unittest/RakefileM7rM7r p[ַ2GHÙM܆CqM)test/rake/data/unittest/subdir/.gitignoreM7rM7r p\GrPxtf -test/rake/filecreation.rbM7rM7r p]@ɦ䉾a#{3test/rake/in_environment.rbM7rM7r p^ޔk@B 3mtest/rake/rake_test_setup.rbM7rM7r p_.SrTKfa%^ ե`2test/rake/reqfile.rbM7rM7r p`.e98OSVetest/rake/reqfile2.rbM7rM7r pa.~P!іtest/rake/reqfile3.rbM7rM7r pb1Xۊqf"h9-R>2]test/rake/shellcommand.rbM7rM7r pcGXheW'^KZtest/rake/test_application.rbM7rM7r pdFǩ b@Qytest/rake/test_clean.rbM7rM7r peIXq+b1{?test/rake/test_definitions.rbM7rM7r pf(fyAu`)mZCitest/rake/test_earlytime.rbM7rM7r pg4&dTxZt6ltest/rake/test_extension.rbM7rM7r ph,*|>+D?o8U$test/rake/test_file_creation_task.rbM7rM7r pi V*pj!pstest/rake/test_file_task.rbM7rM7r pjDEjMbŃB +test/rake/test_filelist.rbM7rM7r pkdKֽnM\utest/rake/test_fileutils.rbM7rM7r pl+I7s|{'ql"test/rake/test_invocation_chain.rbM7rM7r pm;3o8!test/rake/test_makefile_loader.rbM7rM7r pn~.3!E향 [test/rake/test_multitask.rbM7rM7r poQ;jRIhhtest/rake/test_namespace.rbM7rM7r pp Bgw124utest/rake/test_package_task.rbM7rM7r pq%u)^6F4&@test/rake/test_pathmap.rbM7rM7r pr sXXJeDwtest/rake/test_pseudo_status.rbM7rM7r psR#HM"!Ǟ 2ϛtest/rake/test_rake.rbM7rM7r ptn.[.e_/*dtest/rake/test_require.rbM7rM7r pu#-4~ŵ@L>btest/rake/test_rules.rbM7rM7r pv D_6^u  ?L test/rake/test_task_arguments.rbM7rM7r pw'_S<@VpD8test/rake/test_task_manager.rbM7rM7r pxȹͲCe^test/rake/test_tasklib.rbM7rM7r py#j5&otest/rake/test_tasks.rbM7rM7r pz*zM~8Dam,'test/rake/test_test_task.rbM7rM7r p{6(iF'%test/rake/test_top_level_functions.rbM7rM7r p|:T)37-/+}8test/rake/test_win32.rbM7rM7r p~NzwsFȋ0=Otest/rdoc/READMEM7rM7r p7PïV/ˆEw:test/rdoc/binary.datM7rM7r p$}`.4wH%test/rdoc/hidden.zip.txtM7rM7r p1isk;UYxpvtest/rdoc/test.ja.large.rdocM7rM7r p5ʳzjѭ%Êtest/rdoc/test.ja.rdocM7rM7r pۓlZS-nBtest/rdoc/test.ja.txtM7rM7r p O]test/rdoc/test.txtM7rM7r p%^:I&SdN#test/rdoc/test_attribute_manager.rbM7rM7r pIbvX7.:i:test/rdoc/test_rdoc_alias.rbM7rM7r p *z*^'Eg)n!test/rdoc/test_rdoc_any_method.rbM7rM7r pʗQ]xE〘ktest/rdoc/test_rdoc_attr.rbM7rM7r p^O(wq8[Sw#test/rdoc/test_rdoc_class_module.rbM7rM7r p عtrR޹"test/rdoc/test_rdoc_code_object.rbM7rM7r pzEa{&test/rdoc/test_rdoc_constant.rbM7rM7r p&Cia7hYh$FAtest/rdoc/test_rdoc_context.rbM7rM7r p|lx}@f.4test/rdoc/test_rdoc_encoding.rbM7rM7r p Gbu,Lyc@})test/rdoc/test_rdoc_generator_darkfish.rbM7rM7r px p)@ܪ#test/rdoc/test_rdoc_generator_ri.rbM7rM7r p fqÙ2yM,}test/rdoc/test_rdoc_include.rbM7rM7r pxfZ>=.MޟsO}e"c^L#test/rdoc/test_rdoc_markup_to_bs.rbM7rM7r p)q[yiKGa"test/rdoc/test_rdoc_method_attr.rbM7rM7r pB_DR#test/rdoc/test_rdoc_normal_class.rbM7rM7r pW 'e_jOA0>zVS&$test/rdoc/test_rdoc_normal_module.rbM7rM7r pG}DP⑆Btest/rdoc/test_rdoc_options.rbM7rM7r pKb7-2se2Yutest/rdoc/test_rdoc_parser.rbM7rM7r pR݅l϶'[Jj'>\Y]test/rdoc/test_rdoc_parser_c.rbM7rM7r pܯVic'%oеh$"test/rdoc/test_rdoc_parser_ruby.rbM7rM7r p pKXlg StUt$test/rdoc/test_rdoc_parser_simple.rbM7rM7r p^/4'L#ߌ !test/rdoc/test_rdoc_rdoc.rbM7rM7r pᷙZ{aMм+^1%`ktest/rdoc/test_rdoc_require.rbM7rM7r pLu7 5$4QYʷ test/rdoc/test_rdoc_ri_driver.rbM7rM7r p=}^Xf*.gN#test/rdoc/test_rdoc_ri_paths.rbM7rM7r p!|N wT%},gB$test/rdoc/test_rdoc_ri_store.rbM7rM7r pCWrN&ptest/rdoc/test_rdoc_ruby_lex.rbM7rM7r p2Vi%+nz=Ƴttest/rdoc/test_rdoc_stats.rbM7rM7r p+rTOݞXk&uutest/rdoc/test_rdoc_task.rbM7rM7r pR` PV:Эg0ȶtest/rdoc/test_rdoc_text.rbM7rM7r p x BzҴh03Vl3 test/rdoc/test_rdoc_top_level.rbM7rM7r p::V 4{test/rdoc/xref_data.rbM7rM7r pH0~3P|i|}>qStest/rdoc/xref_test_case.rbM7rM7r p# qb{TDz7][gbtest/readline/test_readline.rbM7rM7r p-ƆԜX@&O@&test/readline/test_readline_history.rbM7rM7r p-;-l۱ test/resolv/test_addr.rbM7rM7r p3 btRpc.|test/resolv/test_dns.rbM7rM7r ph Q!P>A {#test/rexml/data/LostineRiver.kml.gzM7rM7r p_p~2Lى%test/rexml/data/ProductionSupport.xmlM7rM7r pݼlWGbENK ]8test/rexml/data/axis.xmlM7rM7r plxo+Cm6;Bl(Ɇ$Ttest/rexml/data/bad.xmlM7rM7r p8_a$}ndղtest/rexml/data/basic.xmlM7rM7r pWX*jgU Ntest/rexml/data/basicupdate.xmlM7rM7r p]fHo-test/rexml/data/broken.rssM7rM7r p 5pDT k7eϮItest/rexml/data/google.2.xmlM7rM7r p}tms4U^test/rexml/data/id.xmlM7rM7r p^_Nɺ(0՚(8]test/rexml/data/iso8859-1.xmlM7rM7r pZgV جԿtest/rexml/data/jaxen24.xmlM7rM7r pJw#,i_IKt/wtest/rexml/data/jaxen3.xmlM7rM7r pI]\@7/mx\test/rexml/data/lang.xmlM7rM7r p+(;N[2EFRi>ntest/rexml/data/lang0.xmlM7rM7r p9;*!%v2lfO&.test/rexml/data/message.xmlM7rM7r p.68дCz%F)`#test/rexml/data/moreover.xmlM7rM7r pk۰kfh)͖gಿWtest/rexml/data/much_ado.xmlM7rM7r p;߃dK|*zkq:H~8Jtest/rexml/data/namespaces.xmlM7rM7r p &]ν7kztest/rexml/data/nitf.xmlM7rM7r py8wnH) %,test/rexml/data/numbers.xmlM7rM7r pwgkYzzY)test/rexml/data/ofbiz-issues-full-177.xmlM7rM7r p 2Bw῝Ltest/rexml/data/pi.xmlM7rM7r pPFP_(T*AItest/rexml/data/pi2.xmlM7rM7r pr%8 b9?2z%test/rexml/data/project.xmlM7rM7r pDG{,Qtest/rexml/data/simple.xmlM7rM7r pBmTU߫S"test/rexml/data/stream_accents.xmlM7rM7r pwC+f/ N KZZtest/rexml/data/t63-1.xmlM7rM7r p pl贮cL2NPtest/rexml/data/test/tests.xmlM7rM7r p6Y>d;q_ RWtest/rexml/data/test/tests.xslM7rM7r pP0kTE#;wCp>C"test/rexml/data/testNamespaces.xmlM7rM7r p ዢ )w=Rttest/rexml/data/testsrc.xmlM7rM7r pc\ywWO-_Ktest/rexml/data/text.xmlM7rM7r p*h ;=V]WQi$test/rexml/data/ticket_110_utf16.xmlM7rM7r p~KÜY|L%test/rexml/data/ticket_61.xmlM7rM7r pOzK椇'&{ lX4test/rexml/data/ticket_68.xmlM7rM7r pUCxM/H\f"%_&bQtest/rexml/data/tutorial.xmlM7rM7r pNFNPxUtest/rexml/data/underscore.xmlM7rM7r pP,rT?wÏz6test/rexml/data/web.xmlM7rM7r pZ}G7R^sZErtest/rexml/data/web2.xmlM7rM7r ptE0vt,}test/rexml/data/working.rssM7rM7r p9f~ ʝtest/rexml/data/xmlfile-bug.xmlM7rM7r peQ7%uߔ*X﯃'gm<34test/rexml/data/xp.tstM7rM7r p!1:@A)fA῵8I$test/rexml/data/yahoo.xmlM7rM7r p]9c>tn{test/rexml/listener.rbM7rM7r p{nsgMmG?-7q`?test/rexml/rexml_test_utils.rbM7rM7r pQwK;KZuK`^xtest/rexml/test_attributes.rbM7rM7r pPR= _#test/rexml/test_attributes_mixin.rbM7rM7r p j *Hx " $test/rexml/test_changing_encoding.rbM7rM7r pH!; XSeDzoktest/rexml/test_contrib.rbM7rM7r p?lck%J'q(test/rexml/test_core.rbM7rM7r p `?Sxki> Qtest/rexml/test_doctype.rbM7rM7r p NR_y$#mϐtest/rexml/test_document.rbM7rM7r p x!SgYX5VrXtest/rexml/test_elements.rbM7rM7r p )h!u!cFrTtest/rexml/test_encoding.rbM7rM7r p?.[X.r7Ӹ.test/rexml/test_encoding_2.rbM7rM7r p;2n) ,Ltest/rexml/test_entity.rbM7rM7r pB`Xao{݁ test/rexml/test_functions.rbM7rM7r p0HiQ'#test/rexml/test_functions_number.rbM7rM7r pp8,%[*test/rexml/test_jaxen.rbM7rM7r q s;t@Wtest/rexml/test_light.rbM7rM7r q33XkvPM|ޞtest/rexml/test_lightparser.rbM7rM7r q K|5`O'J}test/rexml/test_listener.rbM7rM7r q<)߈=x test/rexml/test_martin_fowler.rbM7rM7r qg!%4 5)%test/rexml/test_notationdecl_mixin.rbM7rM7r qtjI}\`?a)test/rexml/test_notationdecl_parsetest.rbM7rM7r q +fӫG^SZ9~jWZtest/rexml/test_order.rbM7rM7r qc.MvRD0$test/rexml/test_preceding_sibling.rbM7rM7r q EhC/H7test/rexml/test_pullparser.rbM7rM7r q wY]'K#test/rexml/test_rexml_issuezilla.rbM7rM7r q VpαGy1F^ktest/rexml/test_sax.rbM7rM7r q  n-p=aAYG{etest/rexml/test_stream.rbM7rM7r q b!1DW#1aγtest/rexml/test_ticket_80.rbM7rM7r q KX#cē_&Ԡ>!test/rexml/test_validation_rng.rbM7rM7r q[cۻZwz]1Xq81/test/rexml/test_xml_declaration_parent_child.rbM7rM7r q~׫ fI"xjtest/rexml/test_xpath.rbM7rM7r q C"1OnY 6a(test/rexml/test_xpath_attribute_query.rbM7rM7r qдt #a;aktest/rexml/test_xpath_msw.rbM7rM7r q7:V+ PDotest/rexml/test_xpath_pred.rbM7rM7r q U99˲Bthˆ*bktest/rexml/test_xpathtext.rbM7rM7r q1cx8Cg'7c*stest/rinda/test_rinda.rbM7rM7r q >0 X7u!T*@vtest/rinda/test_tuplebag.rbM7rM7r q #J6čN,E"test/ripper/dummyparser.rbM7rM7r qMR!wo3>uStest/ripper/test_files.rbM7rM7r qZ]31ڃDyڨtest/ripper/test_filter.rbM7rM7r qb|eFPԶYg ')L" !test/ripper/test_parser_events.rbM7rM7r qbk%>l]ArZl9 "test/ripper/test_scanner_events.rbM7rM7r qoi`/'w21test/rss/dot.pngM7rM7r qb݇1mֱ*+Pڮtest/rss/rss-assertions.rbM7rM7r q .jp4BAtest/rss/test_maker_taxo.rbM7rM7r q6*׌nMb test/rss/test_maker_trackback.rbM7rM7r q7oq;z:pKI.~c%test/rss/test_maker_xml-stylesheet.rbM7rM7r q8e.ӎ_}03Jtest/rss/test_parser.rbM7rM7r q90ܡo@G]bv`test/rss/test_parser_1.0.rbM7rM7r q: c$GskOY)EYcLtest/rss/test_parser_2.0.rbM7rM7r q;W-z;b?ؐda%~"test/rss/test_parser_atom_entry.rbM7rM7r q<CẌ꯸J`ք3wڃy!test/rss/test_parser_atom_feed.rbM7rM7r q=a W:c< test/rss/test_setup_maker_0.9.rbM7rM7r q>@{/X$Xo=e-c test/rss/test_setup_maker_1.0.rbM7rM7r q?#fخ@c@ test/rss/test_setup_maker_2.0.rbM7rM7r q@1So=_?jˆurT'test/rss/test_setup_maker_atom_entry.rbM7rM7r qA5<#+`|ts N=e&test/rss/test_setup_maker_atom_feed.rbM7rM7r qBr)M&8Y2#test/rss/test_setup_maker_itunes.rbM7rM7r qC[BM -mVytest/rss/test_trackback.rbM7rM7r qIgәcx k~"mtest/rss/test_version.rbM7rM7r qJ nT沥7$[7ZUtest/rss/test_xml-stylesheet.rbM7rM7r qLDlrqT test/ruby/allpairs.rbM7rM7r qMCl߱^v_.i۰ttest/ruby/beginmainend.rbM7rM7r qO*pH`puG\;test/ruby/enc/test_big5.rbM7rM7r qP-uǸ L ƙ ~a test/ruby/enc/test_cp949.rbM7rM7r qQEL*]x{伟test/ruby/enc/test_emoji.rbM7rM7r qRU̹ (*@!aetest/ruby/enc/test_euc_jp.rbM7rM7r qS/{Ǖ,;Ǜ> L:test/ruby/enc/test_euc_kr.rbM7rM7r qT/m˩o@b#Ctest/ruby/enc/test_euc_tw.rbM7rM7r qUyPMHZ±)ju6test/ruby/enc/test_gb18030.rbM7rM7r qV']mQ6HX]Qtest/ruby/enc/test_gbk.rbM7rM7r qWjd|m,̝'i%test/ruby/enc/test_iso_8859.rbM7rM7r qX/-%{ڣsƟz?Ytest/ruby/enc/test_koi8.rbM7rM7r qY5))i#9test/ruby/enc/test_shift_jis.rbM7rM7r qZ)1@ghל]/6;6test/ruby/enc/test_utf16.rbM7rM7r q[ =JE#Vl©N*=2test/ruby/enc/test_utf32.rbM7rM7r q\o1Y@ K`ӌ"test/ruby/enc/test_windows_1251.rbM7rM7r q]I{ſ7r[test/ruby/endblockwarn_rbM7rM7r q^!{#Qˣkg |Ctest/ruby/envutil.rbM7rM7r q_`xrvg5test/ruby/lbtest.rbM7rM7r q`-K9GdN/Eȇl$aptest/ruby/marshaltestlib.rbM7rM7r qaBAP-h)oyH .test/ruby/sentence.rbM7rM7r qbc 1J+wg^Btest/ruby/test_alias.rbM7rM7r qcGp M }g"4test/ruby/test_argf.rbM7rM7r qdvg$cF:vÎ39W֑nVtest/ruby/test_array.rbM7rM7r qe` z{bEag test/ruby/test_assignment.rbM7rM7r qfQW&Q:mOϝtest/ruby/test_autoload.rbM7rM7r qgE䧦BnM@ii8~J'#test/ruby/test_basicinstructions.rbM7rM7r qh@[,=Ȋtest/ruby/test_beginendblock.rbM7rM7r qi-&LhvPb㶵Cʎtest/ruby/test_bignum.rbM7rM7r qjJ=&htest/ruby/test_call.rbM7rM7r qkwgN+ ވS";[M test/ruby/test_case.rbM7rM7r ql?)NJY] test/ruby/test_class.rbM7rM7r qm'F@Z|W/58mtest/ruby/test_clone.rbM7rM7r qnkHZn ߏ]R^F-test/ruby/test_comparable.rbM7rM7r qo~Ld}T۝+`v<*ttest/ruby/test_complex.rbM7rM7r qp8N >6[s.)test/ruby/test_complex2.rbM7rM7r qq*CG5b'BNsX!test/ruby/test_complexrational.rbM7rM7r qr.3̦'j% -test/ruby/test_condition.rbM7rM7r qs7XPz!6xtest/ruby/test_const.rbM7rM7r qt,ی51 s~ˮttest/ruby/test_continuation.rbM7rM7r qu .H["H%5V$]test/ruby/test_defined.rbM7rM7r qv#oّ_݃ test/ruby/test_dir.rbM7rM7r qw"o&,YM4T test/ruby/test_dir_m17n.rbM7rM7r qxh/ì}sΉ\^Xutest/ruby/test_econv.rbM7rM7r qy Flʿz'"Kxc-Ctest/ruby/test_encoding.rbM7rM7r qz(5?h Y@ ,L9test/ruby/test_enum.rbM7rM7r q{ <؈Mtest/ruby/test_enumerator.rbM7rM7r q|$h!\#P&1<test/ruby/test_env.rbM7rM7r q}0)e4i2lQ{Jtest/ruby/test_eval.rbM7rM7r q~j[̴7w&rtest/ruby/test_exception.rbM7rM7r qd) s\NX\;Ӽh test/ruby/test_fiber.rbM7rM7r qPIhXiw}VFQtest/ruby/test_file.rbM7rM7r qbkE}mθ磔ao!test/ruby/test_file_exhaustive.rbM7rM7r q*eS+>s4.u{test/ruby/test_fixnum.rbM7rM7r q4zIp4a{ ! test/ruby/test_float.rbM7rM7r qjO<ҨNV(test/ruby/test_fnmatch.rbM7rM7r q%2rdN)_test/ruby/test_gc.rbM7rM7r qOL UhR^.8]ȼjtest/ruby/test_hash.rbM7rM7r q&yE F8HtjBvtest/ruby/test_ifunless.rbM7rM7r qpf%x(M[vtest/ruby/test_integer.rbM7rM7r q:2W޳olx(A[I *test/ruby/test_integer_comb.rbM7rM7r q(l‰_V<Rtest/ruby/test_io.rbM7rM7r q> [3lSta98<$]test/ruby/test_io_m17n.rbM7rM7r q)/6+,gVQ6:5!`Ѱ%test/ruby/test_iterator.rbM7rM7r q& rX`:}#<test/ruby/test_lambda.rbM7rM7r q1_)zC+U_4Fwݯtest/ruby/test_literal.rbM7rM7r q(Rw9omO4FXtest/ruby/test_m17n.rbM7rM7r qπ7qr+hΛ'test/ruby/test_m17n_comb.rbM7rM7r q.bw.aVF-ttest/ruby/test_marshal.rbM7rM7r q!W8!kwA$ot'*+test/ruby/test_math.rbM7rM7r qFc-MrnMf2 test/ruby/test_metaclass.rbM7rM7r q5K_\S8CWtest/ruby/test_method.rbM7rM7r q+W`pzFH+'test/ruby/test_mixed_unicode_escapes.rbM7rM7r q[^<Ϻٚq)test/ruby/test_module.rbM7rM7r q ]t:Dtest/ruby/test_notimp.rbM7rM7r q+giP5o +}ҹOtest/ruby/test_numeric.rbM7rM7r q4)c+եhآ<test/ruby/test_object.rbM7rM7r q2$szP־W Er+Vwtest/ruby/test_objectspace.rbM7rM7r qy`N{ßPps/>5ztest/ruby/test_optimization.rbM7rM7r qa[O%gEZ ,'E>7;bNtest/ruby/test_parse.rbM7rM7r q%@thIׁVt뫒 clBtest/ruby/test_path.rbM7rM7r q41F^_?x2Utest/ruby/test_pipe.rbM7rM7r qڷ38Y"4ueITtest/ruby/test_primitive.rbM7rM7r qvբiRy {Z_test/ruby/test_proc.rbM7rM7r qfUe v!ھ,~ \test/ruby/test_process.rbM7rM7r qCj_^hV:2L[Xtest/ruby/test_rand.rbM7rM7r q⢓YUޡϙ)؅S test/ruby/test_range.rbM7rM7r qy#P`MypA}Ytest/ruby/test_rational.rbM7rM7r q(b;j[">{@Ar18test/ruby/test_rational2.rbM7rM7r qiÆ,L(7F# Gtest/ruby/test_readpartial.rbM7rM7r qy,N$ ;,@test/ruby/test_regexp.rbM7rM7r q 2a>.U.HFtest/ruby/test_require.rbM7rM7r q@!ă& ytest/ruby/test_rubyoptions.rbM7rM7r q0WkM@`ՒD2*]dtest/ruby/test_settracefunc.rbM7rM7r q9߂ ȓPˏQtest/ruby/test_signal.rbM7rM7r qćbWvTʺEEײtest/ruby/test_sleep.rbM7rM7r q46!!N (|CEg{ test/ruby/test_sprintf.rbM7rM7r q-&2%CwXEQ}test/ruby/test_sprintf_comb.rbM7rM7r qa/2jp4v3-Ztest/ruby/test_string.rbM7rM7r q~DcL]ҫQ1W>test/ruby/test_stringchar.rbM7rM7r q^IES1Nlߑeѫtest/ruby/test_struct.rbM7rM7r qlf v?{/תгtest/ruby/test_super.rbM7rM7r q?a7Np dtest/ruby/test_symbol.rbM7rM7r qoZ_zɒUTx#M_test/ruby/test_syntax.rbM7rM7r q E7}cugbtWEtest/ruby/test_system.rbM7rM7r q(Ѽ p?]test/ruby/test_thread.rbM7rM7r q]S /@>$N test/ruby/test_time.rbM7rM7r q>^B`{EQ"Bnܽtest/ruby/test_time_tz.rbM7rM7r qTw\E#&A IbXsOtest/ruby/test_trace.rbM7rM7r qP&~ϐ٫cSmWtest/ruby/test_transcode.rbM7rM7r q,ɀvߜ_C dz,test/ruby/test_undef.rbM7rM7r q3HS._$ih test/ruby/test_unicode_escape.rbM7rM7r qRS+XQi:test/ruby/test_variable.rbM7rM7r qV(1|bDބy:k=Xbytest/ruby/test_whileuntil.rbM7rM7r q-h37x\pq $&test/ruby/test_yield.rbM7rM7r q η!Q5=Wx0Ntest/ruby/ut_eof.rbM7rM7r qT=N O&4".|_test/rubygems/bogussources.rbM7rM7r q>K͚7BWF&test/rubygems/data/gem-private_key.pemM7rM7r q[iS:M>&test/rubygems/data/gem-public_cert.pemM7rM7r q5}cFzA5Nke%test/rubygems/fake_certlib/openssl.rbM7rM7r qG(J"JP.tztest/rubygems/foo/discover.rbM7rM7r q Ukq1֘Heuݳtest/rubygems/functional.rbM7rM7r q kh~C9q˘f\m3-Ttest/rubygems/insure_session.rbM7rM7r qxRX?%jn̦CLtest/rubygems/mockgemui.rbM7rM7r qq^o?vt%|Vu1test/rubygems/plugin/exception/rubygems_plugin.rbM7rM7r qj2~+bJ#̽,test/rubygems/plugin/load/rubygems_plugin.rbM7rM7r qDwI*xr5test/rubygems/plugin/standarderror/rubygems_plugin.rbM7rM7r qv%-2ToC(TL_5test/rubygems/private_key.pemM7rM7r q|=0fdjŸ5.ytest/rubygems/public_cert.pemM7rM7r qJB{~ IjYY0test/rubygems/rubygems/commands/crash_command.rbM7rM7r qjJ?첕o 6~ test/rubygems/rubygems_plugin.rbM7rM7r qG(J"JP.tztest/rubygems/sff/discover.rbM7rM7r q^nG5^<~wtest/rubygems/simple_gem.rbM7rM7r qs9 +?J8~4=7test/rubygems/test_config.rbM7rM7r qSHmW\j`6;itest/rubygems/test_gem.rbM7rM7r qGTu%xA5p2Ad!test/rubygems/test_gem_builder.rbM7rM7r q7D9PUUv *ϰ'9test/rubygems/test_gem_commands_generate_index_command.rbM7rM7r q"RdH<2test/rubygems/test_gem_commands_install_command.rbM7rM7r qϭI?a7:,//test/rubygems/test_gem_commands_list_command.rbM7rM7r q+vC?K Ο/test/rubygems/test_gem_commands_lock_command.rbM7rM7r q-UVm~/Gf3test/rubygems/test_gem_commands_outdated_command.rbM7rM7r q sPaط=twܳ0test/rubygems/test_gem_commands_owner_command.rbM7rM7r q G.JD+<΋N3test/rubygems/test_gem_commands_pristine_command.rbM7rM7r q }}op!7҃|NC}&/test/rubygems/test_gem_commands_push_command.rbM7rM7r qJ> uBOL Ն~^0test/rubygems/test_gem_commands_query_command.rbM7rM7r qsܸK ZAj?q$1test/rubygems/test_gem_commands_server_command.rbM7rM7r q_GЇf~!趥= (2test/rubygems/test_gem_commands_sources_command.rbM7rM7r q ^3x _].g&8test/rubygems/test_gem_commands_specification_command.rbM7rM7r qK,0S!gV&0test/rubygems/test_gem_commands_stale_command.rbM7rM7r q˙\AO~j*]ﱬB.4test/rubygems/test_gem_commands_uninstall_command.rbM7rM7r q X]eF"{Rx-1test/rubygems/test_gem_commands_unpack_command.rbM7rM7r qD}`qQkaF.test/rubygems/test_gem_ext_ext_conf_builder.rbM7rM7r r:LC[B7ÃD*test/rubygems/test_gem_ext_rake_builder.rbM7rM7r rX7w!R test/rubygems/test_gem_format.rbM7rM7r rCRC}g+test/rubygems/test_gem_gem_path_searcher.rbM7rM7r rxM:57,R7$test/rubygems/test_gem_gem_runner.rbM7rM7r r  ^C#U 2kEn@-test/rubygems/test_gem_gemcutter_utilities.rbM7rM7r r G'rq=u&ss!test/rubygems/test_gem_indexer.rbM7rM7r r s_8vo)0test/rubygems/test_gem_install_update_options.rbM7rM7r r c}yE ľD#test/rubygems/test_gem_installer.rbM7rM7r r  k-)Y^~ 5?U.test/rubygems/test_gem_local_remote_options.rbM7rM7r r/I> 3R9i/vv1q+,test/rubygems/test_gem_package_tar_header.rbM7rM7r r 7|NE/z%nS}o +test/rubygems/test_gem_package_tar_input.rbM7rM7r r  (JO֯ ?,test/rubygems/test_gem_package_tar_output.rbM7rM7r r)SUm:Գ>5,{,test/rubygems/test_gem_package_tar_reader.rbM7rM7r r 9-kf@{ȕ3S+2test/rubygems/test_gem_package_tar_reader_entry.rbM7rM7r rLIыYs3O,test/rubygems/test_gem_package_tar_writer.rbM7rM7r ri+oqʆZNHNs&test/rubygems/test_gem_package_task.rbM7rM7r r)eznZWU"test/rubygems/test_gem_platform.rbM7rM7r rQu9җŁOj#test/rubygems/test_gem_validator.rbM7rM7r r!dO",eB }!test/rubygems/test_gem_version.rbM7rM7r r"WÀ@T lb(test/rubygems/test_gem_version_option.rbM7rM7r r#ܻpBm)Ttest/rubygems/test_kernel.rbM7rM7r r$%b.e{df~test/runner.rbM7rM7r r&50,WlNhkCÌm9test/scanf/data.txtM7rM7r r'2ɄxShgz&test/scanf/test_scanf.rbM7rM7r r(:TJW,S^j @test/scanf/test_scanfblocks.rbM7rM7r r)sbt +LjS&test/scanf/test_scanfio.rbM7rM7r r+0\ b36 !YBuS test/sdbm/test_sdbm.rbM7rM7r r-Kj0i7p5test/socket/test_addrinfo.rbM7rM7r r. <+ X!3,LT(ptest/socket/test_ancdata.rbM7rM7r r/#Y9:Tytest/socket/test_basicsocket.rbM7rM7r r0YO:Eb֋ Ttest/socket/test_nonblock.rbM7rM7r r10e* VTtest/socket/test_socket.rbM7rM7r r2n1y.~IpRm6Qtest/socket/test_sockopt.rbM7rM7r r3{&4Q杧 DƋtest/socket/test_tcp.rbM7rM7r r4z2\?^Yݸ\test/socket/test_udp.rbM7rM7r r53|#%>SNtest/socket/test_unix.rbM7rM7r r7.xq-;Ummytest/stringio/test_stringio.rbM7rM7r r9EMi#{IS,"test/strscan/test_stringscanner.rbM7rM7r r;@@OT9}test/syck/test_array.rbM7rM7r r<a[ lڰpC3XРtest/syck/test_boolean.rbM7rM7r r=-: $test/syck/test_class.rbM7rM7r r>$Rĝ8h}QDTgP_F test/syck/test_engine_manager.rbM7rM7r r?L\kG483vѤdtest/syck/test_exception.rbM7rM7r r@~EyM.".Jtest/syck/test_hash.rbM7rM7r rA&΅PV&ЗsIBtest/syck/test_null.rbM7rM7r rB-puz]ꨳЂtest/syck/test_omap.rbM7rM7r rC3Տ?IkHaD6-h`test/syck/test_set.rbM7rM7r rDV;uOR̔_WJtest/syck/test_string.rbM7rM7r rET|_-q%eه_#test/syck/test_struct.rbM7rM7r rF9 tx;test/syck/test_symbol.rbM7rM7r rG =z0Ϸu{ixd㷯gtest/syck/test_yaml.rbM7rM7r rHm-vwIǩgx+!test/syck/test_yaml_properties.rbM7rM7r rIJtZZ8m!l9ctest/syck/test_yamlstore.rbM7rM7r rJFW)a<j@ test/test_cmath.rbM7rM7r rK 5>byԳvtest/test_delegate.rbM7rM7r rL=Itۃ]}dXjSL Xtest/test_find.rbM7rM7r rMoKJHȂ Mtest/test_ipaddr.rbM7rM7r rNv*#qO/k[+XRtest/test_mathn.rbM7rM7r rO?DWWkf2=Ktest/test_mutex_m.rbM7rM7r rP8Xf"˸,t\{test/test_open3.rbM7rM7r rQe(}m%Po?test/test_pp.rbM7rM7r rR#kui]M8._{test/test_prettyprint.rbM7rM7r rS=Ѹ/|̈\84test/test_prime.rbM7rM7r rT J{>zHྌ test/test_pstore.rbM7rM7r rU 9\/Ar?>test/test_pty.rbM7rM7r rVoKJHȂ Mtest/test_set.rbM7rM7r rWԊȫ3t aX~LȜn!test/test_shellwords.rbM7rM7r rX \AFv0 "GZtest/test_singleton.rbM7rM7r rY 7\&VxJtest/test_syslog.rbM7rM7r rZ:UEaA 7љ*utest/test_tempfile.rbM7rM7r r[MFlCS\u Y[test/test_time.rbM7rM7r r\Wx~`mB/btest/test_timeout.rbM7rM7r r]T.nl!~Z:X^test/test_tracer.rbM7rM7r r^E8IpmDQ8v'vtest/test_tsort.rbM7rM7r r`c7Mn+܆hԤ ߃/test/testunit/test_assertion.rbM7rM7r rb8«E# _̩dG*test/thread/test_queue.rbM7rM7r rd+}QĘF"Ztest/uri/test_common.rbM7rM7r re vI{ mph镐ۿ#test/uri/test_ftp.rbM7rM7r rf] KޱXBZUyatest/uri/test_generic.rbM7rM7r rg#:y9\ޡrR͈test/uri/test_http.rbM7rM7r rh ͿuHqPRUtest/uri/test_ldap.rbM7rM7r rio`$1`A btest/uri/test_mailto.rbM7rM7r rj),ƹۍ ]/?8test/uri/test_parser.rbM7rM7r rl#ie3#A_6test/webrick/.htaccessM7rM7r rm1akc'$+Y®(#test/webrick/test_cgi.rbM7rM7r rn>wt]3Ltest/webrick/test_cookie.rbM7rM7r ro&rJ Btest/webrick/test_httpauth.rbM7rM7r rq*zʷ ] T5= %test/webrick/test_httpproxy.rbM7rM7r rr/bAY8:cZ/q test/webrick/test_httprequest.rbM7rM7r rs/@ENoӉ. Otest/webrick/test_httpserver.rbM7rM7r rt袸obw\;ވ<test/webrick/test_httputils.rbM7rM7r ruq&;VE_+Z test/webrick/test_httpversion.rbM7rM7r rvNIi+lJB~[TTtest/webrick/test_server.rbM7rM7r rwI>@ qٜ7htest/webrick/test_utils.rbM7rM7r rx6, g[^{z͡ʢtest/webrick/utils.rbM7rM7r rysrρiBtest/webrick/webrick.cgiM7rM7r rzsrρiB&test/webrick/webrick_long_filename.cgiM7rM7r r|{Ag.D8! test/win32ole/err_in_callback.rbM7rM7r r}!91ƭ U7aӅ2Rtest/win32ole/orig_data.csvM7rM7r r~6O|'$S }}70\B%test/win32ole/test_err_in_callback.rbM7rM7r r!6()/SgS+n,test/win32ole/test_folderitem2_invokeverb.rbM7rM7r r ߗ"?KT!test/win32ole/test_nil2vtempty.rbM7rM7r rІ(/͹h9v6R!test/win32ole/test_ole_methods.rbM7rM7r rO$E#vK e03C$test/win32ole/test_propertyputref.rbM7rM7r ru}IسcuFΉtest/win32ole/test_thread.rbM7rM7r r7,r'+s~?RڷWtest/win32ole/test_win32ole.rbM7rM7r r ~~"!.G,gzp$test/win32ole/test_win32ole_event.rbM7rM7r rha֭E^[{%test/win32ole/test_win32ole_method.rbM7rM7r r N^MBߨ$test/win32ole/test_win32ole_param.rbM7rM7r r$++,' <lt^B#test/win32ole/test_win32ole_type.rbM7rM7r r ,^% &H5&test/win32ole/test_win32ole_typelib.rbM7rM7r r_ܰ~L8"AT*!O'test/win32ole/test_win32ole_variable.rbM7rM7r r_eK$ $}fQ&test/win32ole/test_win32ole_variant.rbM7rM7r r k( mV(test/win32ole/test_win32ole_variant_m.rbM7rM7r r HH,͌=9 -test/win32ole/test_win32ole_variant_outarg.rbM7rM7r rmM\ Y?!-3PItest/win32ole/test_word.rbM7rM7r r;vߦlaϝҾ%T|test/with_different_ofs.rbM7rM7r r:iib/_QS"test/xmlrpc/data/bug_bool.expectedM7rM7r rpѷoDttest/xmlrpc/data/bug_bool.xmlM7rM7r r׆Q^Jr sgOM#test/xmlrpc/data/bug_cdata.expectedM7rM7r reg]֢test/xmlrpc/data/bug_cdata.xmlM7rM7r rD>J `מqtimev.hM7rM7r r<>"Lx -tool/asm_parse.rbM7rM7r rXqU0 WPZ~(SL0tool/build-transcodeM7rM7r r@Wuanahtool/change_maker.rbM7rM7r r֍D>qSz}?5tool/compile_prelude.rbM7rM7r r܄Ǝƥ xsLtool/config.guessM7rM7r rw*UQva0tool/config.subM7rM7r rP7U}|8Z,tool/enc-emoji-citrus-gen.rbM7rM7r r}E ET>tool/enc-emoji4unicode.rbM7rM7r r&Im%~I&:H{z0tool/enc-unicode.rbM7rM7r r DoفY=foZ tool/eval.rbM7rM7r r7)eojp'7tool/file2lastrev.rbM7rM7r r4k U䑦8Gtool/generic_erb.rbM7rM7r r|4 -HBrM tool/ifchangeM7rM7r r1pWgRǗnd3htool/insns2vm.rbM7rM7r rB}8 X]փ9;vwtool/install-shM7rM7r r'O{xغWfգ\tool/instruction.rbM7rM7r r0WH_AѻoDDE+ b)tool/jisx0208.rbM7rM7r r,@Ғ4˥=Otool/make-snapshotM7rM7r r% "GKG =Rw^E vm_method.cM7rM7r r5L@u'{&[ vm_opts.hM7rM7r rzyGqO?PR/8= vsnprintf.cM7rM7r rn*%M[^>H[#;uwin32/Makefile.subM7rM7r r7ݚΓ(1W\~. win32/README.win32M7rM7r rDe3yYqwin32/configure.batM7rM7r r( L;gI;$sN? win32/dir.hM7rM7r r8D4Z/Ey ޳auwin32/enc-setup.makM7rM7r r$|UԊOr?xSgMwin32/ifchange.batM7rM7r rݻjp} O ?@Wwin32/mkexports.rbM7rM7r r xn Q] o,win32/resource.rbM7rM7r r][Oc-c!O= c>9$ win32/rm.batM7rM7r rN0%}fe4+ Pwin32/rmall.batM7rM7r r,b{Ӽ\& win32/stub.cM7rM7r rޗId\iV' win32/win32.cM7rM7r rFz])ڌEAG#win32/winmain.c&K}dfUlibgit2-0.19.0/tests-clar/resources/binaryunicode/000077500000000000000000000000001216214232500220615ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/binaryunicode/.gitted/000077500000000000000000000000001216214232500234175ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/binaryunicode/.gitted/HEAD000066400000000000000000000000271216214232500240420ustar00rootroot00000000000000ref: refs/heads/master libgit2-0.19.0/tests-clar/resources/binaryunicode/.gitted/config000066400000000000000000000001551216214232500246100ustar00rootroot00000000000000[core] repositoryformatversion = 0 filemode = true bare = false autocrlf = true logallrefupdates = true libgit2-0.19.0/tests-clar/resources/binaryunicode/.gitted/description000066400000000000000000000001111216214232500256560ustar00rootroot00000000000000Unnamed repository; edit this file 'description' to name the repository. libgit2-0.19.0/tests-clar/resources/binaryunicode/.gitted/index000066400000000000000000000001501216214232500244450ustar00rootroot00000000000000DIRCP;:%P;:%R"U]M徨S-bOpKOxfile.txtoXK睭dfkkv/libgit2-0.19.0/tests-clar/resources/binaryunicode/.gitted/info/000077500000000000000000000000001216214232500243525ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/binaryunicode/.gitted/info/exclude000066400000000000000000000003601216214232500257250ustar00rootroot00000000000000# git ls-files --others --exclude-from=.git/info/exclude # Lines that start with '#' are comments. # For a project mostly in C, the following would be a good set of # exclude patterns (uncomment them if you want to use them): # *.[oa] # *~ libgit2-0.19.0/tests-clar/resources/binaryunicode/.gitted/info/refs000066400000000000000000000002631216214232500252350ustar00rootroot0000000000000039e046d1416a208265b754124d0d197b4c9c0c47 refs/heads/branch1 9e7d8bcd4d24dd57e3f1179aaf7afe648ff50e80 refs/heads/branch2 d2a291469f4c11f387600d189313b927ddfe891c refs/heads/master libgit2-0.19.0/tests-clar/resources/binaryunicode/.gitted/objects/000077500000000000000000000000001216214232500250505ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/binaryunicode/.gitted/objects/info/000077500000000000000000000000001216214232500260035ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/binaryunicode/.gitted/objects/info/packs000066400000000000000000000000661216214232500270310ustar00rootroot00000000000000P pack-c5bfca875b4995d7aba6e5abf36241f3c397327d.pack libgit2-0.19.0/tests-clar/resources/binaryunicode/.gitted/objects/pack/000077500000000000000000000000001216214232500257665ustar00rootroot00000000000000pack-c5bfca875b4995d7aba6e5abf36241f3c397327d.idx000066400000000000000000000025441216214232500351510ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/binaryunicode/.gitted/objects/packtOc "U]M徨S-bOpKOx(鎗mQ0)b}+SZg& 6$-ҵGhAJ9FAj eTM {L Go큔d'mz'(:ؐS^6r Nš["8BIj Z}M$WzdҢFL` 'C#O,xVn*AU uTP?Pi@)Y/J]f}MQcUuQ Q5 HA5yNr?[>B׬LvkGpack-c5bfca875b4995d7aba6e5abf36241f3c397327d.pack000066400000000000000000000506171216214232500353070ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/binaryunicode/.gitted/objects/packPACK xI 1yE!ADz =YHp6B<{'x+ F(x]%Bq9a,Ql8[GV8m@"چ#bQY)Ṕ\J%QkԽãp˒p>G׺2}* R|yhu[Ex{Q(5U %<"<(91-)$,%5189 qN)v"f \\NEy z\ǰ xI!@=v17&^DN opw??ys'D)Ψt"RV:4\)A":d9V7~ŏ[j-cv_G?qZ >9_.aX:Px340031QHI+(a0["$HWߗ; ՇxM,.I-RH*JKr Fz\\{_x340031QHI+(ao{8EԻOTOneQUеƄnl2+;BҒ4C̒䢜4Ӣ,:y>:s`G 5xM,.I-RH*JKr z\\{[ xweTL.[pwYCpn-wwNp kmO_}挽ϼ393oo;,E@ukG7GWkG'.v^ x`6`$ގ.a`4)aa_@ dE=F6[b"o Z/_;ֿ~!w} +?-\e? o?v wz]XX"<<"<<<"  ::_c`aab`bcacc'x$DĿhh=10ccbcc? Fg'`4l ,6mXW ?G@{ڐQP; /Kb0p0gA@Dՠ1uCN*¿nh~%t! N&2wf(4o I)r Mm7,0\zӳ(kY9% oY>IP;*cl7'(@*6_8A4Ix\ H}R .׻Z<7t(f2Dļ|$!) n:{EML ?CSW``ދi3'KiTUa "h!_qs1`1*0ښ_N_bH=E3H2^I~hQno5ea@CӴaNq>OF 6_=iͫQHT=0!s1JO4A].;KG>̍FZQ0g!=2| <53=.Qa(jAm\ƆMS-B|k @#PM9 T(TE ? }Ml^1Ng6Eԅ0bcXC \dj,zMV vLзRn "{Ac bnvPV:Aw7۰7Dnvp|$=G#}lA2~̝\ ΑI>$E[N[Y7{ fdvyR[zbz$,h \O)z T#uE[^_XAg헏hocl7˱ţzĎWnZDDZyX)& jY(lO/fE\[ŗ S&o!%ZEbR5l$Z7p{v4G&^Z[i xORN-^qL~{4Reʂ0om יiHكqk ]&BiZmP*{lf?^de* CO&E[7@m&U;̽aC¡N6y;e !4c{w'yxS}0"GJ''v<@"֎H! h@Ń}rJl@~oAGd }H] OGӈ8C-L.ǡB$5~WzI[9z,@cYK\,]>p}h/oRCh/ 3ù4?J[rsYeM<= =P[5~ׯuoBє-=V h-NH< Wq?1+ڳ1U0m2|0m$CnXX>ʉzX=GPR}ͺ[nb|(ERr*2X dcgcI"̝09m5`WչBА*#-fޕ65)떵%(7dL6%x85 8PmEEt0 /=R28 2S@IbDbK8^ak!a1ޛs"W(]q{71qoit?xYtN`|.B|W~snLS hmq:*TvZ?Powta"ϵ +5p.ݢdƀ.'1[660uy 1Z:'lU YLډfh9 "Gg*ԟZ9^PӰ.鉠`ĹGoc EZB'd?= `k e`TNk7 Ƒmj.]qNqp\{*1juZ-'#FګdeXP9!TmiVY(]Fʜ>/9a1Cz `ʣ']"~x~d plB&9qD2GfzZ:xPجFOKKM ^|g*&JbaTo{+z,,z8w!RV޹a gU(:;T(:,,) qf55Jm.β}G$|HfJM3C3~( ̹.>>\u䍈b jr23~y]dT6oN%U<6Hp+pE6 h'fĶ kFεIV{(/)MNIC\cfsJD\^_P JxԊ P!g`SG)2&ea-jF@]_|^G]8r'u9x2xhNM.^«!KI2 .vk@biv[wM |VMBM BzPBFFgŽ5u6N>q, JȚ{Mt^ncc04dxIAێĈ &?*^|Un:1 .N)p> ,BO%T9lW0;t}l#w@&1#Gk~iX= Tּ3`|KmWxUU5jA3OZOZMŲ-bTmzJN1Ԑ;ub!iuNz=3^~ h&"l%K&Q1+WD@Q"a!dDطqLZENw86Z_1侄?TOdak6 {*!b<:n#,=3K)@%gqCXBC+<X Y?=iq);$:9Jvx 3ȷ„=j,ⵀ~%,5/I9%}ٔ5BJUQű;ɟ}gGסb'^;6McƱ߉=˴49Q/S$ &FQ HG O iJlxV)mZBcE*X|_.\v ^,w6gQ5z(%, ݼ2H9> Uz $ p3zЕfŔK 5R+K-,鉵T-H:?'q6p!^]H76/tawo  _ 1j#;M N NXőg^f)kH̹NDO2̰w/ |tLv>҇Lzs9sd"qZJhȠ;9B{`ݴV*iNJǢd:P..I^qq:)[EDY);r.|99Da콮X߽XۋzkOGr5q94vϠ"[>kId ]A֨3f*_UVs+o Wʞgh<%jݧ g,Z 0̸t(:*E/-i\h2GΌaM&%g&ZK ) +5>1Hؚ¡#J2sKK!CM=? B/N4]WC!${Ipʱyaj?{rB{#>piUh3=V;ĝac#R'm֯N4XpG1 ާ^-4G;ŋ`В{ivM1t%.˭s;w)f#&a\&3{vd+pBVUDخ217[MSE4"W{{ YEhC(Ŀs*]2Z;ݾ ,/qnλ&?r͸U&=ef'r1SDfG4k;̊N)*y%dUg 5 4DeMP`%5DSVZ訑Onu\:KyKoђ&ρl]{w}իZSa04ت0ڤz̜[jllj:E$*( 0Ѵّ^flJZ+ߖ^ @{`!o^O8R-"< tQll ^?Cf+Z7N k /ؽY&LZ.O(/~ ᕤs}zݩ 2*KK!|ǒ,@rۘXWĿV _"ˢd$OupwjS]9VÁd7l(/X|a)-Og$E ($,92FFv0??TyW9oEęSk]{PLEdq#G1M @> C_M0&aEzj8lRDR۬&$'DY=Q)*]qK(Gт8+̿w22c,Wx !nߑ5-l9=}Z톦995yc;eRO4kIL&KT(W^8WPaG=vn54*Lcʉ(\>~GtyIol=4MxԨ25e?yny}̉~c #{\KC ¤CscϓdU]O^0E2  Fحf 5odL\"y:h[XxC[u[?" i<)dgM2P%̬$H6zuU ɕkhD2s-,E򯦋ӧr\k(kv6X-/6"^e^n.i$N" 8ˀ$2ak} u5M<fZ8&_F~;A`('>FUAL³[ &RƧJ y4JDc&'XڨB-Rf s^Jfd?ar_;g!SFwub`ǫS:|A s+,! Kļč:eO<%3 Ј^q/,: }_UKP$Ff&<it6g?# S>*`qU^i-3NQ @"ʑ(`EB['쨖f?#,_rM)2ĈX%j?- ܊ӭpʹy2BoSTDB<юRpk!@O}_:[ x߱SΈ}[Kujh"r&˄xެ/ItO[5YNK0a琇@gNȈ4m7yn39!Y h?>V?ZT[YY ~%a$u#~o!½6 ˘$,`~v(*>>i: BcfѩDGg˼< D =QTODHP.&7l I_aEGuLAjgVLĥ_ Q*^^E_LIҟ ϨnmF'ڸM4@b2Oe`;12H}jPDmilYq`4LZud.1Uoh F5U`(E;D4 2g \SuNQ]cMUũŽH^YCXTdX)( Ɏ(|h,Bƙնm| =K< QY@t-_qdfA 6 F.1GtG3 G.5EjXw:˭6ǘyjQJ\{ԳWdaqY\n!%yhIfۯES^96J(<@.p`T߷^EN'5'"'qW oĂ >bqq?U6ܽuV+\QSK12^rV_~$WqӶmf۾q]t0Stl}p%+Iْ҆5J'CʑZBt1U1ݭ<ܐ6 1 ļurh5| C;}룵ܦsudFpIc?B+X.xmܴ{-Ǒ#}2VOɜnL2U Sڜ+NSgkL{dߌ~9hNvXdi=b:|y).=>ī[GlEsC*nrq^ql]x|{fa׈yy%и1Sߞ?yP5#uwgyl jMZEKժ wˌ/aMxa ݀}_=R#5:I)5F؍l>%MyXd5E[. xϖ:Y0LD/a2+ҰПM\a⫓4¥H )ɂ&!a]B%x yuL{*W(.*SWށ҃z$N2ZYBP#+G_qGYu25RI(!k2!) x cétks3'"\_ PNl4CYL a3 }10pK*:phϬnb C"ҧ,? d#GPߕ4h<,7}1[ʑl^9\.]XY~[=6 2khT+[0#KȼI8GwDccjɓ Yxq.;.%H*60|T-9^GQesy"/qz^@aq0T+Beݨ]k#fd䓜Fjr,㰌k.?}i(?L3õqm{e +:6-EP}Fr Ơo;ܫu.<>빰x}дڼ50/ܝ] Dъ'i=%\Qfzo|KZl8 t'hqj]8k0X kC8F n(ܾ^?k'{5wffI.#WJDAMkg|^nE%EHRtq #L+ Ȫ{~\M#KpYlz4>{xQ٦Gu{F?.!q߻6fH %y6o'/ t#L|&<$FgF{nW`rzMW>faeo|nOjC؟v.Q6s60`fr#$6B죈57xjըɝ+ <^7A죔y.'gcELV\ dُW̑Qo7VAY"o ۉΧW=LA-?2)A.LGަ)G6IH;Xe4~EPZZ)8|DjX+qݏ__T7ټ\i%GIoNS*F:'t5FWf͛m:B)0@O_B` UVR>/!!O+on\V-%); @GPLzPqLVq]6k]F,spʮj0l%p89uB bp:Ri(wu& R)tJû"B%Յ ʞeKixAѹD(!\@Qk&aY,ӨC A:8)]ktgl\=7,ҍ4B$eb.MBShV}t|sU4-鼊8Ua9-aR B>m8|JkzO-Bـa0_R mY<}彶Ƣu+qPK?hxs2Sj$5otL7dhDT# '3( "Jz+8HQS\/-?&KLV ~&UGcu/ HH17'Y9HfEI' x)Ql~65ޣR~;Zs`hx2qRD{ $ΦF˝]-#']c)0[Wǔu\uq]lWKaJ9M"ܟzV٢6z6La "RpyL^4>U9bH7^B~pE"c3xmk{VڰL|qS/̌|nEb,>?x{e.Ϲ3VU9jL"\>E ;zLvlԬ3nK@sj}s=<A T:ΏɢR!4S)KYuHSh' S8B&!pv2[PvN-4M߷دP 6gyJ<#m}E9RjѾk9K1]ɳL`jW;3)KI5@Niٮg9ь9rDp k o=S k <3]K G\f-1jROWXP͉e&[iqPOt!8Wx%!1_͘DjʀEsl8>w8jPuj; m72꒶s 4tUAQ۪t4/f~sGdCOiϬ\R{^L-:uxK`ȳZ7fyJ YHZeMq-؍U\ \IX61dV햒޶^?xf$/cǪ+rbZIZKUt212 zEh#ZLB81^aoωi}Ϊ,|6c6~y^w*"οoIS kߖfN~rԼe/f?1GɉZڦ5vZ蔷e#(s@+ %w3/ߙ`{^boITԡ9xňZ1@h[ZݭۙgBR۟T+GpIH;&jHJ w%Uir5Sߚ1bnAn.&eqg n*ύݶeg]eU 8`ݜ*2ma^ǴP?B4]_=W cWaBԭKMc@N#AFsHFRa'|ba@29ϡgSfqDTz{./ҡ.RO~=#ae3\uThԂ-Ws_tww]aXVa9δVcFz"R紥~{z6kCsv@9 ӞLo;Q<۴IxB⍻9;/9'猷[p?ji@a.qjzzK".܊jth1ː^Ky.ň^8IHjM/ dZGGcES.|T2FX<۷I&4DU)D &84_cp8 H@ƺF?R}#58$Ozw_Ҡ;uy9>j,\TߍuP-h3Rѥʼn"?z1.f<ϙPp>!&FOa.B1ׯxb4*orAZ)sMɐٱ2<] oaaҮd0NQGDp}1d7vA=zpWjIfw QQV(?6w}ʻ*c*lWa`f@ҁX5^نфFwyh?̜0[H5&v7XJeNA SɡU4eMiPU8f}CiIZ7[eCWk4+̼vV~Б68;6%ajMƹDk`oC(0Y H=Q/)gj\f$R ;Gwrc_ƥ&)؏BVC"G5ﳩ9̂4:{ x1\B0ְbƥW̬ȐCj$:pLAWϛDueci֥W0k4M%W y=ySHnº8+ eD/ &/@ ^t҆d߁PZɬUz9q)صnz4LL9)_VeNfl@0~a?Y*;,M&b3Fh"k& T/hrю^К8g瘴KGa僧+F1}vULH-:$q^_>9C$#t)>^zyfF?d[n?G5@ z`K_]7@*^w6ƇW{F-&3 yEa 4)9 `-*T+vxQVFjv;٫3U$̲^)"Metac`K!=INF U(r΀Z;#S y^\w|NuoYv})EX- Wvr=DeE)p\֦Ns#f 8vo. R03@iB DTbkoS$]B5y{YZ=xL`7|DБtoX!vi6q"uj].Mڨ }y[47wNEO>̥fdx{wW:jffM3/|&Y"М&^)7>}]l&WEk\\?KTU(X>g9JU <g+m pVGi<^pYQWU<5p{Xt|hZ5 oy/ T)@u!U)~O=eW'X;px<kD[d0]r QRzjyx2;#yªe^^㱞%샕A9IǒBHNJ0p %e|͒CHQsM`0swW98Qsҳw_'{S4D~Q-MN,K\s.>xrm}iv%/5*8ZP`l5w }FTK dh$8 0swK8BڗI=2a7\\#ޒt.4 E:B$=أ{ssW#{0D;ox+$ s# KUm;Y TXst(ómjx2$ ! |ţ,)‹>2 6䋚Oz;+i* +#Hdkh /Ai. d-tcd_\8qw Sqs2ZyHkctD X#h! h# S5\`٫ꣅ )d4#^Oal/G--@R* ¡:׉d-2&=}Kbd>fGNY\=Pt4Ҕre ڪ;E9g/"Q5ÃLgDb}Nu;eZ6] C}Sw Th)N2Ȏ}iL.Fz`mWLϪb \S1ʍnT9#h~(m3J:I[٤R%\J Fp@Ϧ%e4+;n,|+d=ݣthF3\;EG+?ӘMEw⦡eߗW ~vtB\9Uk׺'dp>"9YObD1[xׁ9V=SgQ' Q7Ch`F0 yS顇5SBݬ#ޫ$c`cs@eo0$֊f,cNwBJ#s@*~9 Gli>oqKWh,fS,akC!q= [k. 1J棎)v}q1:㖾j 2ݺJZ-+gl(W%tJq#k3$3P`W[tgq5͚CPORvy)w|k^4p:ELB U3$@x{xē|8U-ō fZ3B<5&jfU4K 7oA&96FRԲhq3E! T , X6z49! 62Q7 a%eMdmcFTýʻ`"! vi+n S5åתN4v쥁jWtIlDx{Y`AxW^yi,2Nkl-aɫ%\T_.j]ZO$Å-.z`.e`)-$6!m KBPYlg h-rdK|$LA;콸$MƁɴ[fvx{ah>pso3Og5n P cG%:&Y6\NɼRRuFeJOt@|?Zk8 QkCScI&cPnӂ.MylQߟJq2 e$Se)Jw |\ʹu,*al"`8Ccf'VJ+I?SM͊29 H H#qZ(YpR \~kE)kr1/ ѺKzo#z~r⡖k<53:#5l0sO@})&(*gae4uECTW"[˗T,t`lzԧ\Z5lQlu.t)Sp ЅOG`%-5rS4K 4e,^i`2I`hIqkM[AWX߰Ȃ1NB Ф,xku8 ^QBKV=8LGA,M$%2@BpLj!&VQ|=5Wf^xքÐG ;]$qZЌDuYȕdNBo7tnT$$-EPl|"5:`'Ч$`X4$5@ .v4a*rR!]j/w w2M=R*َh=;+FZ~K.3'bI<?ǐI$#[a(AM)T,k! )Lnl}t̳/%e.u};eЏ:7ztm 19ㄨg9^zNlibgit2-0.19.0/tests-clar/resources/crlf/.gitted/objects/dc/000077500000000000000000000000001216214232500235315ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/crlf/.gitted/objects/dc/88e3b917de821e25962bea7ec1f55c4ce2112c000066400000000000000000000000401216214232500307410ustar00rootroot00000000000000xKOR02dx{N%@ libgit2-0.19.0/tests-clar/resources/crlf/.gitted/objects/ea/000077500000000000000000000000001216214232500235305ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/crlf/.gitted/objects/ea/030d3c6cec212069eca698cabaa5b4550f1511000066400000000000000000000000401216214232500307010ustar00rootroot00000000000000xKOR06`x{rQN/I2 \% `libgit2-0.19.0/tests-clar/resources/crlf/.gitted/objects/fe/000077500000000000000000000000001216214232500235355ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/crlf/.gitted/objects/fe/085d9ace90cc675b87df15e1aeed0c3a31407f000066400000000000000000000002131216214232500311010ustar00rootroot00000000000000x+)JMU043b040031QHM.I--I`Z:Aj -s,dt ))9ڍ*V3l8,7(W̼69o2,qj-*a&xS^4Wu<v@libgit2-0.19.0/tests-clar/resources/crlf/.gitted/refs/000077500000000000000000000000001216214232500224515ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/crlf/.gitted/refs/heads/000077500000000000000000000000001216214232500235355ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/crlf/.gitted/refs/heads/master000066400000000000000000000000511216214232500247470ustar00rootroot0000000000000012faf3c1ea55f572473cec9052fca468c3584ccb libgit2-0.19.0/tests-clar/resources/crlf/.gitted/refs/heads/utf8000066400000000000000000000000511216214232500243420ustar00rootroot00000000000000baaa042ab2976f8264e467988e6112ee518ec62e libgit2-0.19.0/tests-clar/resources/deprecated-mode.git/000077500000000000000000000000001216214232500230325ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/deprecated-mode.git/HEAD000066400000000000000000000000271216214232500234550ustar00rootroot00000000000000ref: refs/heads/master libgit2-0.19.0/tests-clar/resources/deprecated-mode.git/config000066400000000000000000000001571216214232500242250ustar00rootroot00000000000000[core] bare = true repositoryformatversion = 0 filemode = false logallrefupdates = true ignorecase = true libgit2-0.19.0/tests-clar/resources/deprecated-mode.git/description000066400000000000000000000001111216214232500252710ustar00rootroot00000000000000Unnamed repository; edit this file 'description' to name the repository. libgit2-0.19.0/tests-clar/resources/deprecated-mode.git/index000066400000000000000000000001601216214232500240610ustar00rootroot00000000000000DIRC= pT-ޙƭe! old_mode.txtqQ 0~.8z8ԭlibgit2-0.19.0/tests-clar/resources/deprecated-mode.git/info/000077500000000000000000000000001216214232500237655ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/deprecated-mode.git/info/exclude000066400000000000000000000001611216214232500253370ustar00rootroot00000000000000# File patterns to ignore; see `git help ignore` for more information. # Lines that start with '#' are comments. libgit2-0.19.0/tests-clar/resources/deprecated-mode.git/objects/000077500000000000000000000000001216214232500244635ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/deprecated-mode.git/objects/06/000077500000000000000000000000001216214232500247105ustar00rootroot00000000000000262edc257418e9987caf999f9a7a3e1547adff000066400000000000000000000001741216214232500321130ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/deprecated-mode.git/objects/06xK 0@]LO $Ii [:wUB~ޝo@,.It֫axqLtӞ}N~jH(Tv~}btNG'B ,)ԜSesO`eYOsjCSj<VoyR)lqdߔ[LK, %@KlӲܖcgq[o3Ԃ⒢\]C==#"_}zWm i孓U—#libgit2-0.19.0/tests-clar/resources/deprecated-mode.git/objects/1b/000077500000000000000000000000001216214232500247655ustar00rootroot0000000000000005fdaa881ee45b48cbaa5e9b037d667a47745e000066400000000000000000000000711216214232500322070ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/deprecated-mode.git/objects/1bx+)JMU01`040033QIOI+(a,xRD{3=Alibgit2-0.19.0/tests-clar/resources/deprecated-mode.git/objects/3d/000077500000000000000000000000001216214232500247715ustar00rootroot000000000000000970ec547fc41ef8a5882dde99c6adce65b021000066400000000000000000000000351216214232500322200ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/deprecated-mode.git/objects/3dxKOR04fTUO*I-IElibgit2-0.19.0/tests-clar/resources/deprecated-mode.git/refs/000077500000000000000000000000001216214232500237715ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/deprecated-mode.git/refs/heads/000077500000000000000000000000001216214232500250555ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/deprecated-mode.git/refs/heads/master000066400000000000000000000000511216214232500262670ustar00rootroot0000000000000006262edc257418e9987caf999f9a7a3e1547adff libgit2-0.19.0/tests-clar/resources/diff/000077500000000000000000000000001216214232500201365ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/diff/.gitted/000077500000000000000000000000001216214232500214745ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/diff/.gitted/HEAD000066400000000000000000000000271216214232500221170ustar00rootroot00000000000000ref: refs/heads/master libgit2-0.19.0/tests-clar/resources/diff/.gitted/config000066400000000000000000000001601216214232500226610ustar00rootroot00000000000000[core] repositoryformatversion = 0 filemode = true bare = false logallrefupdates = true ignorecase = false libgit2-0.19.0/tests-clar/resources/diff/.gitted/description000066400000000000000000000001111216214232500237330ustar00rootroot00000000000000Unnamed repository; edit this file 'description' to name the repository. libgit2-0.19.0/tests-clar/resources/diff/.gitted/index000066400000000000000000000003411216214232500225240ustar00rootroot00000000000000DIRCPR#PR#D-lTls_M\, *ɿ another.txtPR$PR$D- )pSM>, }e readme.txtTREE2 0 x C 1347559804 -0700 commit (initial): initial commit d70d245ed97ed2aa596dd1af6536e4bfdb047b69 7a9e0b02e63179929fed24f0a3e0f19168114d10 Russell Belfer 1347560491 -0700 commit: some changes libgit2-0.19.0/tests-clar/resources/diff/.gitted/logs/refs/000077500000000000000000000000001216214232500233775ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/diff/.gitted/logs/refs/heads/000077500000000000000000000000001216214232500244635ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/diff/.gitted/logs/refs/heads/master000066400000000000000000000004721216214232500257040ustar00rootroot000000000000000000000000000000000000000000000000000000 d70d245ed97ed2aa596dd1af6536e4bfdb047b69 Russell Belfer 1347559804 -0700 commit (initial): initial commit d70d245ed97ed2aa596dd1af6536e4bfdb047b69 7a9e0b02e63179929fed24f0a3e0f19168114d10 Russell Belfer 1347560491 -0700 commit: some changes libgit2-0.19.0/tests-clar/resources/diff/.gitted/objects/000077500000000000000000000000001216214232500231255ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/diff/.gitted/objects/29/000077500000000000000000000000001216214232500233575ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/diff/.gitted/objects/29/ab7053bb4dde0298e03e2c179e890b7dd465a7000066400000000000000000000013321216214232500305730ustar00rootroot00000000000000xMT˒@ l '8.p8˶\q9|!_BkT&Vw5mԖ^|uxm eBeB14`?pg(:Q:pF|+i%׻O.̩C:Ҥ}x/1%ud>Ѫ BKPԎ5]ljZi$,Be|B:p7n iAӎ&GpΠ#~+M+$B/g:OXCNSomI8]8k'+sMEܾa\飫㫠M FhP8V4]| GuY4pNxs%t|oLE<5;ҫz^pwԞB$Q8BOB7Y]:XȄ(fgP0S ~J$д)h %QCy ոE%mMŃǡ(C v1Bˍ5qu΅nqXAp)[T Bt~%c8pFw0i7ʼ؈m3 Hy@޺`U?)hehF ..j="Ⱦ*zK/U]N⫃VdP}hB:k Cː[D?ɾPx|N; 8X>@7bk_\^gSZ2a1pNM(ilibgit2-0.19.0/tests-clar/resources/diff/.gitted/objects/3e/000077500000000000000000000000001216214232500234345ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/diff/.gitted/objects/3e/5bcbad2a68e5bc60a53b8388eea53a1a7ab847000066400000000000000000000021241216214232500310550ustar00rootroot00000000000000xuUKo6bn(@@"9Y5E $R7) -^}߾Wep.'DxQNF=EC&NB,h.uʋ=W d%}Ƌ|ELeB CB%y rt$,*re$|L|1bzVez%86ăElqW<'̜dٕgrR-R$ ؙ$j[,a'AxfᜣuXjh[Mn*oXza8` 1-͜n4Hvc12XԽ1*5 ^C(7>@V|gi]Gv`k28Ю0 oE+7;<~8SLϪ 3D*wI€?G|+n3UeX@r,PtH]YFr؝?OPL~tB)C\޼H `<0~E {z;sG &&(:S;ke%6uy1P_A]`ژG_'h+kþ; Q-k Dop+]l 5vQ`UhUFmYemCE|sh!nAI;rl8(b1@g* @;'z ƶaMvBTpGV=2k%QfV /Uu:8^k&t-TJ"]ww*6B{`~ kUnNjelIUachȖOwkƅ ꥁk:O-`\h*p2libgit2-0.19.0/tests-clar/resources/diff/.gitted/objects/54/000077500000000000000000000000001216214232500233555ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/diff/.gitted/objects/54/6c735f16a3b44d9784075c2c0dab2ac9bf1989000066400000000000000000000021261216214232500305200ustar00rootroot00000000000000xuU]o63žE~-HZ u^<=5E $uwklK̰o޻B.Ӆs9'W&“p7b).2qfGFwua4āuʋ J(̙ą,*|v_J46"LLYU86I1:ƙc$3=K ;Fl ql±%R yN9+19?)4 )i[rH 3Iն&a'Axfᜣu54T47ø|sc/ ԙ{A;%Ӎn 4Fƚ.7F3uX%DErtݎ3V-&((..Y<λr3_^3F;|jj ۚN.HjJMW/z@P!뤯h`-Tq @@H!|f W6) !.0tP`'RVQk^"Ik)ݶVP[pCރLT7c*=9jzj譆!\j 6_`IDW{f\ؠ* פuvq[zаd`libgit2-0.19.0/tests-clar/resources/diff/.gitted/objects/7a/000077500000000000000000000000001216214232500234345ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/diff/.gitted/objects/7a/9e0b02e63179929fed24f0a3e0f19168114d10000066400000000000000000000002401216214232500303350ustar00rootroot00000000000000xA =fJb mkCNf)u]?їD`5Fh&g !jag-ꛚl8 r1\:Y/GH!}, doЖHQ:ORu(s&TuElibgit2-0.19.0/tests-clar/resources/diff/.gitted/objects/7b/000077500000000000000000000000001216214232500234355ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/diff/.gitted/objects/7b/808f723a8ca90df319682c221187235af76693000066400000000000000000000016321216214232500302300ustar00rootroot00000000000000xeUM6홿bn^-&$@#%-f)@R(G-zay8|>F]N~W?Uބ*'u*uU74}FaI}ҼQ{R@&\.ԏ!eA9ޅaOM-ٟqfT?LKa*z/mP>INS Y"AgGb'Qߏ;p` 3̀|#VpWHmذ6G6O0DM@yߜ{CQKKU?Uy8apLPvaPަ|Rä <6bZfgpezZi֌`Jbw_BEs|\VV+鞄ZIUp*+JMLMn/YY2CGI]9{dlibgit2-0.19.0/tests-clar/resources/diff/.gitted/objects/d7/000077500000000000000000000000001216214232500234375ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/diff/.gitted/objects/d7/0d245ed97ed2aa596dd1af6536e4bfdb047b69000066400000000000000000000002031216214232500310140ustar00rootroot00000000000000x !m_RB:XkVpWp 9{ ,^z#7JygԚA i1Y2VyR)𢒨'm[;-lO_#%v8libgit2-0.19.0/tests-clar/resources/diff/.gitted/refs/000077500000000000000000000000001216214232500224335ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/diff/.gitted/refs/heads/000077500000000000000000000000001216214232500235175ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/diff/.gitted/refs/heads/master000066400000000000000000000000511216214232500247310ustar00rootroot000000000000007a9e0b02e63179929fed24f0a3e0f19168114d10 libgit2-0.19.0/tests-clar/resources/diff/another.txt000066400000000000000000000036151216214232500223440ustar00rootroot00000000000000Git is fast. With Git, nearly all operations are performed locally, giving it an huge speed advantage on centralized systems that constantly have to communicate with a server somewh3r3. For testing, large AWS instances were set up in the same availability zone. Git and SVN were installed on both machines, the Ruby repository was copied to both Git and SVN servers, and common operations were performed on both. In some cases the commands don't match up exactly. Here, matching on the lowest common denominator was attempted. For example, the 'commit' tests also include the time to push for Git, though most of the time you would not actually be pushing to the server immediately after a commit where the two commands cannot be separated in SVN. Note that this is the best case scenario for SVN - a server with no load with an 80MB/s bandwidth connection to the client machine. Nearly all of these times would be even worse for SVN if that connection was slower, while many of the Git times would not be affected. Clearly, in many of these common version control operations, Git is one or two orders of magnitude faster than SVN, even under ideal conditions for SVN. Let's see how common operations stack up against Subversion, a common centralized version control system that is similar to CVS or Perforce. Smaller is faster. One place where Git is slower is in the initial clone operation. Here, Git One place where Git is slower is in the initial clone operation. Here, Git One place where Git is slower is in the initial clone operation. Here, Git seen in the above charts, it's not considerably slower for an operation that is only performed once. It's also interesting to note that the size of the data on the client side is very similar even though Git also has every version of every file for the entire history of the project. This illustrates how efficient it is at compressing and storing data on the client side.libgit2-0.19.0/tests-clar/resources/diff/readme.txt000066400000000000000000000032161216214232500221360ustar00rootroot00000000000000The Git feature that r3ally mak3s it stand apart from n3arly 3v3ry other SCM out there is its branching model. Git allows and encourages you to have multiple local branches that can be entirely independent of each other. The creation, merging, and deletion of those lines of development takes seconds. Git allows and encourages you to have multiple local branches that can be entirely independent of each other. The creation, merging, and deletion of those lines of development takes seconds. This means that you can do things like: Role-Bas3d Codelin3s. Have a branch that always contains only what goes to production, another that you merge work into for testing, and several smaller ones for day to day work. Feature Based Workflow. Create new branches for each new feature you're working on so you can seamlessly switch back and forth between them, then delete each branch when that feature gets merged into your main line. Disposable Experimentation. Create a branch to experiment in, realize it's not going to work, and just delete it - abandoning the work—with nobody else ever seeing it (even if you've pushed other branches in the meantime). Notably, when you push to a remote repository, you do not have to push all share it with others. Git allows and encourages you to have multiple local branches that can be entirely independent of each other. The creation, merging, and deletion of those lines of development takes seconds. There are ways to accomplish some of this with other systems, but the work involved is much more difficult and error-prone. Git makes this process incredibly easy and it changes the way most developers work when they learn it.! libgit2-0.19.0/tests-clar/resources/duplicate.git/000077500000000000000000000000001216214232500217625ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/duplicate.git/COMMIT_EDITMSG000066400000000000000000000000071216214232500240460ustar00rootroot00000000000000commit libgit2-0.19.0/tests-clar/resources/duplicate.git/HEAD000066400000000000000000000000271216214232500224050ustar00rootroot00000000000000ref: refs/heads/master libgit2-0.19.0/tests-clar/resources/duplicate.git/config000066400000000000000000000001341216214232500231500ustar00rootroot00000000000000[core] repositoryformatversion = 0 filemode = true bare = false logallrefupdates = true libgit2-0.19.0/tests-clar/resources/duplicate.git/description000066400000000000000000000001111216214232500242210ustar00rootroot00000000000000Unnamed repository; edit this file 'description' to name the repository. libgit2-0.19.0/tests-clar/resources/duplicate.git/index000066400000000000000000000001501216214232500230100ustar00rootroot00000000000000DIRCOO&76% ۩VFJfileq`/hrB8b6}libgit2-0.19.0/tests-clar/resources/duplicate.git/info/000077500000000000000000000000001216214232500227155ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/duplicate.git/info/exclude000066400000000000000000000003601216214232500242700ustar00rootroot00000000000000# git ls-files --others --exclude-from=.git/info/exclude # Lines that start with '#' are comments. # For a project mostly in C, the following would be a good set of # exclude patterns (uncomment them if you want to use them): # *.[oa] # *~ libgit2-0.19.0/tests-clar/resources/duplicate.git/info/refs000066400000000000000000000000731216214232500235770ustar00rootroot000000000000008d2f05c97ef29a4697b37c30fe81c248ef411a23 refs/heads/master libgit2-0.19.0/tests-clar/resources/duplicate.git/logs/000077500000000000000000000000001216214232500227265ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/duplicate.git/logs/HEAD000066400000000000000000000002401216214232500233460ustar00rootroot000000000000000000000000000000000000000000000000000000 8d2f05c97ef29a4697b37c30fe81c248ef411a23 Han-Wen Nienhuys 1336844322 -0300 commit (initial): commit libgit2-0.19.0/tests-clar/resources/duplicate.git/logs/refs/000077500000000000000000000000001216214232500236655ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/duplicate.git/logs/refs/heads/000077500000000000000000000000001216214232500247515ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/duplicate.git/logs/refs/heads/master000066400000000000000000000002401216214232500261630ustar00rootroot000000000000000000000000000000000000000000000000000000 8d2f05c97ef29a4697b37c30fe81c248ef411a23 Han-Wen Nienhuys 1336844322 -0300 commit (initial): commit libgit2-0.19.0/tests-clar/resources/duplicate.git/objects/000077500000000000000000000000001216214232500234135ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/duplicate.git/objects/ce/000077500000000000000000000000001216214232500240025ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/duplicate.git/objects/ce/013625030ba8dba906f756967f9e9ca394464a000066400000000000000000000000251216214232500307240ustar00rootroot00000000000000xKOR0cHlibgit2-0.19.0/tests-clar/resources/duplicate.git/objects/info/000077500000000000000000000000001216214232500243465ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/duplicate.git/objects/info/packs000066400000000000000000000000661216214232500253740ustar00rootroot00000000000000P pack-e87994ad581c9af946de0eb890175c08cd005f38.pack libgit2-0.19.0/tests-clar/resources/duplicate.git/objects/pack/000077500000000000000000000000001216214232500243315ustar00rootroot00000000000000pack-e87994ad581c9af946de0eb890175c08cd005f38.idx000066400000000000000000000022041216214232500333020ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/duplicate.git/objects/packtOc/~F|0HA#6% ۩VFJZc$1`[F=,omhf6R9* iwZMtOLJ ]K@oS 0pack-e87994ad581c9af946de0eb890175c08cd005f38.pack000066400000000000000000000003251216214232500334360ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/duplicate.git/objects/packPACK x˱ ݯR#R2vw̺@#i*΃EG. n OXX9X᩵8z1*mW_6+x340031QHIe8h̽JaY< 6xHKiwZMtOlibgit2-0.19.0/tests-clar/resources/duplicate.git/packed-refs000066400000000000000000000001251216214232500240670ustar00rootroot00000000000000# pack-refs with: peeled 8d2f05c97ef29a4697b37c30fe81c248ef411a23 refs/heads/master libgit2-0.19.0/tests-clar/resources/empty_bare.git/000077500000000000000000000000001216214232500221375ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/empty_bare.git/HEAD000066400000000000000000000000271216214232500225620ustar00rootroot00000000000000ref: refs/heads/master libgit2-0.19.0/tests-clar/resources/empty_bare.git/config000066400000000000000000000002031216214232500233220ustar00rootroot00000000000000[core] repositoryformatversion = 0 filemode = false bare = true symlinks = false ignorecase = true hideDotFiles = dotGitOnly libgit2-0.19.0/tests-clar/resources/empty_bare.git/description000066400000000000000000000001111216214232500243760ustar00rootroot00000000000000Unnamed repository; edit this file 'description' to name the repository. libgit2-0.19.0/tests-clar/resources/empty_bare.git/info/000077500000000000000000000000001216214232500230725ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/empty_bare.git/info/exclude000066400000000000000000000003601216214232500244450ustar00rootroot00000000000000# git ls-files --others --exclude-from=.git/info/exclude # Lines that start with '#' are comments. # For a project mostly in C, the following would be a good set of # exclude patterns (uncomment them if you want to use them): # *.[oa] # *~ libgit2-0.19.0/tests-clar/resources/empty_bare.git/objects/000077500000000000000000000000001216214232500235705ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/empty_bare.git/objects/info/000077500000000000000000000000001216214232500245235ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/empty_bare.git/objects/info/dummy-marker.txt000066400000000000000000000000001216214232500276640ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/empty_bare.git/objects/pack/000077500000000000000000000000001216214232500245065ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/empty_bare.git/objects/pack/dummy-marker.txt000066400000000000000000000000001216214232500276470ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/empty_bare.git/refs/000077500000000000000000000000001216214232500230765ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/empty_bare.git/refs/heads/000077500000000000000000000000001216214232500241625ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/empty_bare.git/refs/heads/dummy-marker.txt000066400000000000000000000000001216214232500273230ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/empty_bare.git/refs/tags/000077500000000000000000000000001216214232500240345ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/empty_bare.git/refs/tags/dummy-marker.txt000066400000000000000000000000001216214232500271750ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/empty_standard_repo/000077500000000000000000000000001216214232500232715ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/empty_standard_repo/.gitted/000077500000000000000000000000001216214232500246275ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/empty_standard_repo/.gitted/HEAD000066400000000000000000000000271216214232500252520ustar00rootroot00000000000000ref: refs/heads/master libgit2-0.19.0/tests-clar/resources/empty_standard_repo/.gitted/config000066400000000000000000000002351216214232500260170ustar00rootroot00000000000000[core] repositoryformatversion = 0 filemode = false bare = false logallrefupdates = true symlinks = false ignorecase = true hideDotFiles = dotGitOnly libgit2-0.19.0/tests-clar/resources/empty_standard_repo/.gitted/description000066400000000000000000000001111216214232500270660ustar00rootroot00000000000000Unnamed repository; edit this file 'description' to name the repository. libgit2-0.19.0/tests-clar/resources/empty_standard_repo/.gitted/info/000077500000000000000000000000001216214232500255625ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/empty_standard_repo/.gitted/info/exclude000066400000000000000000000003601216214232500271350ustar00rootroot00000000000000# git ls-files --others --exclude-from=.git/info/exclude # Lines that start with '#' are comments. # For a project mostly in C, the following would be a good set of # exclude patterns (uncomment them if you want to use them): # *.[oa] # *~ libgit2-0.19.0/tests-clar/resources/empty_standard_repo/.gitted/objects/000077500000000000000000000000001216214232500262605ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/empty_standard_repo/.gitted/objects/info/000077500000000000000000000000001216214232500272135ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/empty_standard_repo/.gitted/objects/info/dummy-marker.txt000066400000000000000000000000001216214232500323540ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/empty_standard_repo/.gitted/objects/pack/000077500000000000000000000000001216214232500271765ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/empty_standard_repo/.gitted/objects/pack/dummy-marker.txt000066400000000000000000000000001216214232500323370ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/empty_standard_repo/.gitted/refs/000077500000000000000000000000001216214232500255665ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/empty_standard_repo/.gitted/refs/heads/000077500000000000000000000000001216214232500266525ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/empty_standard_repo/.gitted/refs/heads/dummy-marker.txt000066400000000000000000000000001216214232500320130ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/empty_standard_repo/.gitted/refs/tags/000077500000000000000000000000001216214232500265245ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/empty_standard_repo/.gitted/refs/tags/dummy-marker.txt000066400000000000000000000000001216214232500316650ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/filemodes/000077500000000000000000000000001216214232500211755ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/filemodes/.gitted/000077500000000000000000000000001216214232500225335ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/filemodes/.gitted/HEAD000066400000000000000000000000271216214232500231560ustar00rootroot00000000000000ref: refs/heads/master libgit2-0.19.0/tests-clar/resources/filemodes/.gitted/config000066400000000000000000000001571216214232500237260ustar00rootroot00000000000000[core] repositoryformatversion = 0 filemode = true bare = false logallrefupdates = true ignorecase = true libgit2-0.19.0/tests-clar/resources/filemodes/.gitted/description000066400000000000000000000001111216214232500247720ustar00rootroot00000000000000Unnamed repository; edit this file 'description' to name the repository. libgit2-0.19.0/tests-clar/resources/filemodes/.gitted/index000066400000000000000000000010201216214232500235560ustar00rootroot00000000000000DIRCO1_O1_iѝaxexec_offO1O1_iѝaxexec_off2on_stagedO1_O1_iѝaxexec_off2on_workdirO1_O1_iѝaxexec_onO1O1_iѝaxexec_on2off_stagedO1_O1_iѝaxexec_on2off_workdirZzhK&NW libgit2-0.19.0/tests-clar/resources/filemodes/.gitted/info/000077500000000000000000000000001216214232500234665ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/filemodes/.gitted/info/exclude000066400000000000000000000003601216214232500250410ustar00rootroot00000000000000# git ls-files --others --exclude-from=.git/info/exclude # Lines that start with '#' are comments. # For a project mostly in C, the following would be a good set of # exclude patterns (uncomment them if you want to use them): # *.[oa] # *~ libgit2-0.19.0/tests-clar/resources/filemodes/.gitted/logs/000077500000000000000000000000001216214232500234775ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/filemodes/.gitted/logs/HEAD000066400000000000000000000002601216214232500241210ustar00rootroot000000000000000000000000000000000000000000000000000000 9962c8453ba6f0cf8dac7c5dcc2fa2897fa9964a Russell Belfer 1338847682 -0700 commit (initial): Initial commit of test data libgit2-0.19.0/tests-clar/resources/filemodes/.gitted/logs/refs/000077500000000000000000000000001216214232500244365ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/filemodes/.gitted/logs/refs/heads/000077500000000000000000000000001216214232500255225ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/filemodes/.gitted/logs/refs/heads/master000066400000000000000000000002601216214232500267360ustar00rootroot000000000000000000000000000000000000000000000000000000 9962c8453ba6f0cf8dac7c5dcc2fa2897fa9964a Russell Belfer 1338847682 -0700 commit (initial): Initial commit of test data libgit2-0.19.0/tests-clar/resources/filemodes/.gitted/objects/000077500000000000000000000000001216214232500241645ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/filemodes/.gitted/objects/99/000077500000000000000000000000001216214232500244255ustar00rootroot0000000000000062c8453ba6f0cf8dac7c5dcc2fa2897fa9964a000066400000000000000000000002131216214232500320130ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/filemodes/.gitted/objects/99xA E]sέ7:XZ&{臨E3fsu&huC`rF.E YvYZ> O;z||,{ MޑZc=@5k+RB_Z!0 =`libgit2-0.19.0/tests-clar/resources/filemodes/.gitted/objects/a5/000077500000000000000000000000001216214232500244715ustar00rootroot00000000000000c5dd0fc6c313159a69b1d19d7f61a9f978e8f1000066400000000000000000000000251216214232500316460ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/filemodes/.gitted/objects/a5xKOR0c/O_ libgit2-0.19.0/tests-clar/resources/filemodes/.gitted/objects/e7/000077500000000000000000000000001216214232500244775ustar00rootroot0000000000000048d196331bcb20267eaaee4ff3326cb73b8182000066400000000000000000000001431216214232500315420ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/filemodes/.gitted/objects/e7x+)JMU025g040031QHHMOKcXz.¢27^[gŋhjKSSU]_YK)yD(1:HU vlibgit2-0.19.0/tests-clar/resources/filemodes/.gitted/refs/000077500000000000000000000000001216214232500234725ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/filemodes/.gitted/refs/heads/000077500000000000000000000000001216214232500245565ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/filemodes/.gitted/refs/heads/master000066400000000000000000000000511216214232500257700ustar00rootroot000000000000009962c8453ba6f0cf8dac7c5dcc2fa2897fa9964a libgit2-0.19.0/tests-clar/resources/filemodes/exec_off000066400000000000000000000000061216214232500226720ustar00rootroot00000000000000Howdy libgit2-0.19.0/tests-clar/resources/filemodes/exec_off2on_staged000077500000000000000000000000061216214232500246430ustar00rootroot00000000000000Howdy libgit2-0.19.0/tests-clar/resources/filemodes/exec_off2on_workdir000077500000000000000000000000061216214232500250550ustar00rootroot00000000000000Howdy libgit2-0.19.0/tests-clar/resources/filemodes/exec_off_untracked000066400000000000000000000000061216214232500247320ustar00rootroot00000000000000Howdy libgit2-0.19.0/tests-clar/resources/filemodes/exec_on000077500000000000000000000000061216214232500225370ustar00rootroot00000000000000Howdy libgit2-0.19.0/tests-clar/resources/filemodes/exec_on2off_staged000066400000000000000000000000061216214232500246400ustar00rootroot00000000000000Howdy libgit2-0.19.0/tests-clar/resources/filemodes/exec_on2off_workdir000066400000000000000000000000061216214232500250520ustar00rootroot00000000000000Howdy libgit2-0.19.0/tests-clar/resources/filemodes/exec_on_untracked000077500000000000000000000000061216214232500245770ustar00rootroot00000000000000Howdy libgit2-0.19.0/tests-clar/resources/gitgit.index000066400000000000000000004072171216214232500215610ustar00rootroot00000000000000DIRCHIHIQ3kq]!HnY?fnMB.gitattributesHIHIQ[D#&lV1H(i .gitignoreHIHIQ 74v?qLGٙnIC.mailmapHcHc)QȖQȝ^xO;.projectHIHIQIco|FdCbW;_"yCOPYINGHIHIQݰ0}T?s\KDocumentation/.gitattributesHIHIQ[_Kce7W͏ Documentation/.gitignoreHIHIQu(Յ`A失+,Documentation/CodingGuidelinesHIHIQb&9[, *39~Documentation/MakefileHIHIQ[wΆM"֏7}"Documentation/RelNotes-1.5.0.1.txtHIHIQ a[^!@N,"Documentation/RelNotes-1.5.0.2.txtHIHIQ)P>(w\3}+"Documentation/RelNotes-1.5.0.3.txtHIHIQ mAO"Documentation/RelNotes-1.5.0.4.txtHIHIQa=safkH#C"Documentation/RelNotes-1.5.0.5.txtHIHIQ _S|"Documentation/RelNotes-1.5.0.6.txtHIHIQg +g |7ʬ^)"Documentation/RelNotes-1.5.0.7.txtHIHIQH׻$1s1vcD Documentation/RelNotes-1.5.0.txtHIHIQtG썕 V*"Documentation/RelNotes-1.5.1.1.txtHIHIQs؄V0lP=`O|3"Documentation/RelNotes-1.5.1.2.txtHIHIQdZAVz,,k"Documentation/RelNotes-1.5.1.3.txtHIHIQK/f̵Ҧ80n~ת_9"Documentation/RelNotes-1.5.1.4.txtHIHIQq̰SFxcKqڸ4"Documentation/RelNotes-1.5.1.5.txtHIHIQUBĻ2rNM"Documentation/RelNotes-1.5.1.6.txtHIHIQ36rpkGƭBXC< Documentation/RelNotes-1.5.1.txtHIHIQ0"BZP')_g"Documentation/RelNotes-1.5.2.1.txtHIHIQ%9?T[(f,"Documentation/RelNotes-1.5.2.2.txtHIHIQ"[NNSD9jy$"Documentation/RelNotes-1.5.2.3.txtHIHIQ"uuTd4> nuWb"Documentation/RelNotes-1.5.2.4.txtHIHIQ(r ,,AS`z{v"Documentation/RelNotes-1.5.2.5.txtHIHIQaq]NJ&ΚRd$Uy| Documentation/RelNotes-1.5.2.txtHIHIQFFC.uas>D"Documentation/RelNotes-1.5.3.1.txtHIHIQKʴmZ堧xK#"Documentation/RelNotes-1.5.3.2.txtHIHIQiQ=T4M$"Documentation/RelNotes-1.5.3.3.txtHIHIQK:EbRp[F"Documentation/RelNotes-1.5.3.4.txtHIHIQ 0c"˶qX"Documentation/RelNotes-1.5.3.5.txtHIHIQ+,/mw#%u"Documentation/RelNotes-1.5.3.6.txtHIHIQ0/i2Gy5F"Documentation/RelNotes-1.5.3.7.txtHIHIQ?F+2K#"Documentation/RelNotes-1.5.3.8.txtHIHIQ68&E |dӫb Documentation/RelNotes-1.5.3.txtHIHIQ K l}m]h"b"Documentation/RelNotes-1.5.4.1.txtHIHIQ!YHuтŪ"Documentation/RelNotes-1.5.4.2.txtHIHIQg*~10]7@!"Documentation/RelNotes-1.5.4.3.txtHIHIQ :mbM؃"Documentation/RelNotes-1.5.4.4.txtHIHIQ4}Z6Mc'ϳ"Documentation/RelNotes-1.5.4.5.txtHIHIQ><>Uu2HM"Documentation/RelNotes-1.5.4.6.txtHIHIQ8X2;atn85ud4 Documentation/RelNotes-1.5.4.txtHIHIQ}pwt{_颒"Documentation/RelNotes-1.5.5.1.txtHIHIQ9{-|'M*.u"Documentation/RelNotes-1.5.5.2.txtHIHIQ1/4!zjE=St݁u"Documentation/RelNotes-1.5.5.3.txtHIHIQ-yb*^%J[2"Documentation/RelNotes-1.5.5.4.txtHIHIQ06}ac!"Documentation/RelNotes-1.5.5.5.txtHIHIQ)2!$\>% Documentation/RelNotes-1.5.5.txtHIHIQHddET_Zn 3"Documentation/RelNotes-1.5.6.1.txtHIHIQYZxaÏL`g"Documentation/RelNotes-1.5.6.2.txtHIHIQ@&)YԽ %bz0Mb"Documentation/RelNotes-1.5.6.3.txtHIHIQ%ؖ0F8Xrg+"Documentation/RelNotes-1.5.6.4.txtHIHIQC/K]_' 3 Documentation/RelNotes-1.5.6.txtHIHIQ#%BS 5m Documentation/RelNotes-1.6.0.txtHIHIQDw%cp ryhDocumentation/SubmittingPatchesHIHIQU@;xl8'1T߼Documentation/asciidoc.confHIHIQ ^T(s,%}ߨ`@Documentation/blame-options.txtHIHIQȺB0*&z]枰ĪmDocumentation/build-docdep.perlHIHIQ!j6!6{Ԯ2PIUo.Documentation/callouts.xslHIHIQr3<PpG~h^Documentation/cat-texi.perlHIHIQxB)U vDocumentation/cmd-list.perlHIHIQav|+o+BFDocumentation/config.txtHIHIQ@ ; 'rg罸zt[Documentation/diff-format.txtHIHIQ9Q~{%Documentation/git-cvsexportcommit.txtHIHIQ  ay´,Documentation/git-cvsimport.txtHIHIQ/ 'N}{@0DDocumentation/git-cvsserver.txtHIHIQ&K\&|H^v_ R-Documentation/git-daemon.txtHIHIQݠK4y4T'ݧF |Documentation/git-describe.txtHIHIQ\6oHjx Documentation/git-diff-files.txtHIHIQ& Oc!?zH!G Documentation/git-diff-index.txtHIHIQ5b-U} $* SV3Documentation/git-diff.txtHIHIQ ʹt[ !i!Documentation/git-fast-export.txtHIHIQ Ү1rP!Documentation/git-fast-import.txtHIHIQ VGD.QX)q}q)~ Documentation/git-fetch-pack.txtHIHIQL\kl9% KDocumentation/git-fetch.txtHIHIQ0{ڵ/}$ހK#Documentation/git-filter-branch.txtHIHIQ$ymfծRƜݺSl#Documentation/git-fmt-merge-msg.txtHIHIQr}sT/[iE"Documentation/git-for-each-ref.txtHIHIQ C"1#.ar"Documentation/git-format-patch.txtHIHIQ0Zy}/O%@I"Documentation/git-fsck-objects.txtHIHIQէdrj^gnbA7~ôn:Documentation/git-fsck.txtHIHIQ*pJ86a6+ ^GDocumentation/git-gc.txtHIHIQ>%3o½҉'Documentation/git-get-tar-commit-id.txtHIHIQzM<e\ӔDocumentation/git-grep.txtHIHIQ $eI{V33JSDocumentation/git-gui.txtHIHIQ}uYZoNh{ !Documentation/git-hash-object.txtHIHIQX?Ďx__1l͝Documentation/git-help.txtHIHIQǖ_ D]Ĉ׀d Documentation/git-http-fetch.txtHIHIQ B`;wb r -pķDocumentation/git-http-push.txtHIHIQT3ds@‡ KWDocumentation/git-imap-send.txtHIHIQ K\t<_(+PW野 Documentation/git-index-pack.txtHIHIQ?&7[ 4᧙zDocumentation/git-init-db.txtHIHIQqt ڗYb$Documentation/git-init.txtHIHIQ ?"!Ob\CBX~ƒПDocumentation/git-instaweb.txtHIHIQ ˬVj6c6yODocumentation/git-log.txtHIHIQ@`+]Mdf"/HI3 Documentation/git-lost-found.txtHIHIQ< _֮M.e!E Documentation/git-ls-files.txtHIHIQ翟=$q) yzDocumentation/git-ls-remote.txtHIHI Q Lrb͂ʍc#78Documentation/git-ls-tree.txtHIHI Q1ΥFsIBB!3?Documentation/git-mailinfo.txtHIHI QK\N=0W|9YT9bDocumentation/git-mailsplit.txtHIHI Q~󓁰DzQ=&\ Documentation/git-merge-base.txtHIHI Q Ngz*6W(' Documentation/git-merge-file.txtHIHIQ i\)E'ݗB$=}KDocumentation/git-pack-refs.txtHIHIQXCtՕbr% 5TZ"Documentation/git-parse-remote.txtHIHIQEGw4V!J|Documentation/git-patch-id.txtHIHIQǂ+nzɂ6?!Documentation/git-peek-remote.txtHIHIQl&"TW%"#}"Documentation/git-prune-packed.txtHIHIQzTڳRu:u_kDocumentation/git-prune.txtHIHIQuxb>۩#/)qcDocumentation/git-pull.txtHIHI Q =s/LѐNDocumentation/git-push.txtHIHI!Q#}@ ̗N`!!Documentation/git-quiltimport.txtHIHI"Q6oK{PJ+9u Documentation/git-read-tree.txtHIHI#Q0Y! }mG6ZfDocumentation/git-rebase.txtHIHI$QAk/M)'pa6-Gf9"Documentation/git-receive-pack.txtHIHI%Q ْ6MR860@)HƬ$Documentation/git-reflog.txtHIHI&Q,%RgS8Bi+Documentation/git-relink.txtHIHI'QoYDpDocumentation/git-remote.txtHIHI(Q8`{p/cBDocumentation/git-repack.txtHIHI)Q彵S>ahxt64X!Documentation/git-repo-config.txtHIHI*Q3_ݮ+plׅ%Y\RVg"Documentation/git-request-pull.txtHIHI+Q!!*U_ Documentation/git-rerere.txtHIHI,QFjŒ 20oDocumentation/git-reset.txtHIHI-Q .4Yș(VL<Documentation/git-rev-list.txtHIHI.Q8)!2 +M'E@iDocumentation/git-rev-parse.txtHIHI/Qϣ~ |v(_qDocumentation/git-revert.txtHIHI0Q M I[H!eiV=rDocumentation/git-rm.txtHIHI1Q N)JFUuO Documentation/git-send-email.txtHIHI2Q9!,*\֧7~k[Documentation/git-send-pack.txtHIHI3QhK[N@13,Documentation/git-sh-setup.txtHIHI4Q4BRYv4`ڛ9vDocumentation/git-shell.txtHIHI5Q|15ef{T6$Documentation/git-shortlog.txtHIHI6QaX]Dm0dߙ!Documentation/git-show-branch.txtHIHI7QQ(Z1 iͰ:$<$ Documentation/git-show-index.txtHIHI8QACgc=w>(9:reRDocumentation/git-show-ref.txtHIHI9Q9B#j[WBgX BjDocumentation/git-show.txtHIHI:QN}PLɩE݂e 7Documentation/git-stash.txtHIHI;Qք4I@ʭ8kDocumentation/git-status.txtHIHI<QVu-, "fA{Q Documentation/git-stripspace.txtHIHI=Q850Vih8c@Documentation/git-submodule.txtHIHI>QX60ZT;cw'Documentation/git-svn.txtHIHI?Qu!,WvuNx*Y4,"Documentation/git-symbolic-ref.txtHIHI@QjT+@HȦqc͞7Documentation/git-tag.txtHIHIAQ ԥUq8g!iDocumentation/git-tar-tree.txtHIHIBQ kdˌ j 0rDocumentation/git-tools.txtHIHICQ\]-EED!Documentation/git-unpack-file.txtHIHIDQ6VE3+g)^'$Documentation/git-unpack-objects.txtHIHIEQ.3gz)b`"Documentation/git-update-index.txtHIHIFQ y9o i6'Bm Documentation/git-update-ref.txtHIHIGQ 5{ KzQ X(Documentation/git-update-server-info.txtHIHIHQauK f b΋tru: 5Documentation/howto/recover-corrupted-blob-object.txtHIHIfQ 1^pƥoGc$]W,Documentation/howto/revert-branch-rebase.txtHIHIgQ m>w|)1Documentation/howto/separating-topic-branches.txtHIHIhQ e@2tJ(tp a22Documentation/howto/setup-git-server-over-http.txtHIHIiQi}hPE[xD)xu-+Documentation/howto/update-hook-example.txtHIHIjQ!N/uagc<Ҷehp&Documentation/howto/use-git-daemon.txtHIHIkQ S i3iwL aߴ+Documentation/howto/using-merge-subtree.txtHIHIlQ }k"ԼmkLDocumentation/i18n.txtHIHImQ5@nт1m? "Documentation/install-doc-quick.shHIHInQ!5OVǙCyIvRadDocumentation/install-webdoc.shHIHIoQ@ez8s+PcTk?Documentation/manpage-1.72.xslHIHIpQHt|ՒBsXVn0Documentation/merge-config.txtHIHIqQSy /s%lTyxI:GDocumentation/merge-options.txtHIHIrQCvX@qmVn8%"Documentation/merge-strategies.txtHIHIsQIWqM $7P Documentation/pretty-formats.txtHIHItQmfLf" a2㏇ Documentation/pretty-options.txtHIHIuQ )G`%{Кȡm"Documentation/pull-fetch-param.txtHIHIvQ-:5 sp?""Documentation/rev-list-options.txtHIHIxQ&Zn`^"Documentation/technical/.gitignoreHIHIyQCsU%Tϴ/,rR2Documentation/technical/api-allocation-growing.txtHIHIzQ~dB'=o'Documentation/technical/api-builtin.txtHIHI{Q<RAls֣*CN(Documentation/technical/api-decorate.txtHIHI|Q $0gG9ϕp$Documentation/technical/api-diff.txtHIHI}Q[ fAl83T[U9v1Documentation/technical/api-directory-listing.txtHIHI~Q ڝ~f,LQ0-Documentation/technical/api-gitattributes.txtHIHIQLȖMX]|ЩQ$Documentation/technical/api-grep.txtHIHIQ0DŽ%7K]UEQU$Documentation/technical/api-hash.txtHIHIQGU!Ԭ(?%8-Documentation/technical/api-history-graph.txtHIHIQɭ]u~86!W-Documentation/technical/api-in-core-index.txtHIHIQ|90RFv*Documentation/technical/api-index-skel.txtHIHIQc?A1Xd`+Qhu$Documentation/technical/api-index.shHIHIQ ݉@C&:˓R(Documentation/technical/api-lockfile.txtHIHIQV akP2c\W -Documentation/technical/api-object-access.txtHIHIQSc J')ˬ5-Documentation/technical/api-parse-options.txtHIHIQ衼Nl[*+aл%Documentation/technical/api-quote.txtHIHIQ ;"Z~HU&Documentation/technical/api-remote.txtHIHIQ mP:ϣWQP0Documentation/technical/api-revision-walking.txtHIHIQu]I#NhW\+Documentation/technical/api-run-command.txtHIHIQOcM}xL(VW9%Documentation/technical/api-setup.txtHIHIQf_-+^AmH+&Documentation/technical/api-strbuf.txtHIHIQ);] nq~k3'B!+Documentation/technical/api-string-list.txtHIHIQ1zh*)˯bV,Documentation/technical/api-tree-walking.txtHIHIQbeQ?͂шJ3R/Documentation/technical/api-xdiff-interface.txtHIHIQNF_R'Documentation/technical/pack-format.txtHIHIQG=>ى4~G .!+Documentation/technical/pack-heuristics.txtHIHIQoԋHY~/ Vc)Documentation/technical/pack-protocol.txtHIHIQ!kK:\S$f$Documentation/technical/racy-git.txtHIHIQhBkV`K.Documentation/technical/send-pack-pipeline.txtHIHIQUcH_l3ق4*P#Documentation/technical/shallow.txtHIHIQ$Ay #0FNn]0)Documentation/technical/trivial-merge.txtHIHIQPJ;BV eiDocumentation/urls-remotes.txtHIHIQ A4tqDbDocumentation/urls.txtHIHIQ30ly\ 9Z^Documentation/user-manual.confHIHIQ%l|E>inDocumentation/user-manual.txtHIHIQ|Ե8'h KW-GIT-VERSION-GENHIHIQ} ,/]niuC3r>INSTALLHqHq=QpR|G$U\R&MakefileHIHIQsTB'ygzekRREADMEHqHq>Q <4f\+f;H4 ARelNotesHHQ VFX٧(D n abspath.cHثHQ̱C`5ڋoYalias.cHcHcQ!l#Tӌtyo?M6 builtin-mv.cHIHI.QՅa,MqF# @FTbuiltin-name-rev.cHIHI/Q-0fBH;builtin-pack-objects.cHIHI0QE4$mbs.oH-builtin-pack-refs.cHIHI1QtˍE.>cbuiltin-prune-packed.cHIHI2Q}%sأ':S?builtin-prune.cHIHI3Q h8sCƓM_R*cbuiltin-push.cHIHI4Qr0/r|ƘQ ?=g4׍JO+builtin-shortlog.cHIHI?QT#>I x&Ubuiltin-show-branch.cHIHI@Q}`u+\Cbuiltin-show-ref.cHIHIAQLjI87V%builtin-stripspace.cHIHIBQNjId&?:builtin-symbolic-ref.cHIHICQ'2[&2A!;UkN2 builtin-tag.cHIHIDQ"jTsB<^gDEUbuiltin-tar-tree.cHIHIEQ2娑fe[,ͬq[ٺJ builtin-unpack-objects.cHIHIFQL8S̺+Pֺ t$-builtin-update-index.cHIHIGQfVQۿV$U68builtin-update-ref.cHIHIHQ婰//7*h|V Ջ[*builtin-upload-archive.cHIHIIQ .YV1NBw2zbuiltin-verify-pack.cHIHIJQ rE~Nbuiltin-verify-tag.cHIHIKQRFR+xM(5builtin-write-tree.cHIHILQ?P-0^Oep8K builtin.hHIHIMQ%cOI5#1Ukwwbundle.cHIHINQs`֭msSHbundle.hHIHIOQ5_{F4d /ek cache-tree.cHIHIPQϋytĤ 6 #|ԥ= cache-tree.hHIHIQQv$uޟ7Yc(AW0CQcache.hHIHIRQLltlN2{check-builtins.shHIHISQ*cT4 check-racy.cHIHITQqE &+^ check_bindirHIHIUQ rY>KcrO@ ncolor.cHIHIVQlȊ8>ocolor.hHIHIWQjMafbUhMaycombine-diff.cHIHIXQ5>G&Cuu7`Ocommand-list.txtHIHIYQD3 [rEPcommit.cHIHIZQTwޖ!&+ʁvAcommit.hHIHIQ2nN_).L1compat/fnmatch.cHIHIQ >y@4|za&Mcompat/fnmatch.hHIHIQ/ 8_ecompat/fopen.cHIHIQU]~h7׈)K.compat/hstrerror.cHIHIQD%L*y큍oacompat/inet_ntop.cHIHIQ@xwʙ!Rkzpcompat/inet_pton.cHIHIQ sd/܀$jҼMcompat/memmem.cHIHIQ]w,Q ]&3y6{compat/mingw.cHIHIQ) o-yiP6Acompat/mingw.hHIHIQ4Դk+B˻+compat/mkdtemp.cHIHIQmBY*>*.sGZQpD compat/mmap.cHIHIQNk9T"7Qcompat/pread.cHIHIQ=,3.ATacompat/qsort.cHIHIQ->Fi{]٩9`~/icompat/regex.cHIHIQGnO [XRcompat/regex.hHIHIQ:"{uvrc~compat/setenv.cHIHIQX fj4U ~3<Wcompat/snprintf.cHIHIQ&mLSWĎ!4v7compat/strcasestr.cHIHIQ@$`0}X[ܻi#AIcompat/strlcpy.cHIHIQUA5:w-H/Q compat/strtoumax.cHIHIQ.)p @q.compat/unsetenv.cHIHIQNmou!=gBaٮ>f=compat/winansi.cHIHI[QjSJjruP*4e,OVyconfig.cHIHI\Qڷv1\f]n/ H config.mak.inHIHI]Q@|(V,^0p6X&contrib/completion/git-completion.bashHIHIQ0.@ QδP0&ſu#contrib/continuous/cidaemonHIHIQ{ FO:$$lƞ5΁(contrib/continuous/post-receive-cinotifyHIHIQ mz/قs4A)contrib/convert-objects/convert-objects.cHIHIQȗmm#7[yY/contrib/convert-objects/git-convert-objects.txtHIHIQ1نl";u8fcontrib/emacs/.gitignoreHIHIQ@+J F6ncontrib/emacs/MakefileHIHIQ contrib/examples/git-checkout.shHIHIQ^衚1_Gxbcontrib/examples/git-clean.shHIHIQ1Tr(<W] J"b,contrib/examples/git-clone.shHIHIQ8,J@b1|Q`Dju,contrib/examples/git-commit.shHIHIQ#{Jm~Dy8G contrib/examples/git-fetch.shHIHIQR?^V9H!@acontrib/examples/git-gc.shHIHIQ  P׫,c!contrib/examples/git-ls-remote.shHIHIQR)ۤ:W[0#ξx"contrib/examples/git-merge-ours.shHIHIQ1.X3[dц@Wcontrib/examples/git-merge.shHIHIQ(6TɅU>zN contrib/examples/git-remote.perlHIHIQ3Oi ;3ϘkɾӋDž8 contrib/examples/git-rerere.perlHIHIQ ,ё!zcontrib/examples/git-reset.shHIHIQ Ὁ˷%3@NԼcontrib/examples/git-resolve.shHIHIQhI!3Nx!@0contrib/examples/git-revert.shHIHIQa^;/$#bވ#contrib/examples/git-svnimport.perlHIHIQqش[,tl)!r*"contrib/examples/git-svnimport.txtHIHIQ(G,/l_ZA9contrib/examples/git-tag.shHIHIQ A#hV: ~"contrib/examples/git-verify-tag.shHIHIQ(ۺu^w`#contrib/fast-import/git-import.perlHIHIQ q.UoW3!contrib/fast-import/git-import.shHIHIQjB-C_9contrib/fast-import/git-p4HIHIQdY YHzcontrib/fast-import/git-p4.batHIHIQ j33ldnucontrib/fast-import/git-p4.txtHIHIQ #WU|FXhhL ~z$contrib/fast-import/import-tars.perlHIHIQt-\j~^B|mGP"contrib/fast-import/import-zips.pyHIHIQ@L߹4krB7=contrib/gitview/gitviewHIHIQ;wQ f4contrib/gitview/gitview.txtHIHIQ{ NхukXRhHcontrib/hg-to-git/hg-to-git.pyHIHIQzdc|L6Żcontrib/hg-to-git/hg-to-git.txtHIHIQGA6Pֲ!#  contrib/hooks/post-receive-emailHIHIQK{~ 1t.!contrib/hooks/pre-auto-gc-batteryHIHIQڷ㡂1{Zcontrib/hooks/setgitperms.perlHIHIQ-ы1{/ZwVQcontrib/hooks/update-paranoidHIHIQF+g |c=*~xecontrib/p4import/READMEHIHIQ)=~1reo]yRm contrib/p4import/git-p4import.pyHIHIQgX|4goX2!contrib/p4import/git-p4import.txtHIHIQsOJ^_Wf2contrib/patches/docbook-xsl-manpages-charmap.patchHIHIQjo(ށ˲ contrib/remotes2config.shHIHIQЈm_2ؘcontrib/stats/git-common-hashHIHIQ)K.$U$.4contrib/stats/mailmap.plHIHIQ,y,contrib/stats/packinfo.plHIHIQ9j$8k+mS 'contrib/thunderbird-patch-inline/READMEHIHIQzQ<XҞu6yF(contrib/thunderbird-patch-inline/appp.shHIHIQhx#|<5 9]@contrib/vim/READMEHIHIQ3!!TޟU6,w``9 contrib/vim/syntax/gitcommit.vimHIHIQdyYҋ0|T%L_Icontrib/workdir/git-new-workdirHIHI_Q8gx MdC6 convert.cHIHI`QMu̱#copy.cHIHIaQ hO^J.yL csum-file.cHIHIbQrHO^-Ưj csum-file.hHIHIcQyHsiV~[ctype.cHIHIdQmE@ZeIM}daemon.cHIHIeQJ,5%v>^@+4date.cHIHIfQf.Ls䧥` j decorate.cHIHIgQ~8K47 decorate.hHIHIhQ @_b@'Op$C delta.hHIHIiQ=N^B:dw=q diff-delta.cHIHIjQ3h̼ƒR,VE diff-lib.cHIHIkQj}hIbN>>ydiff-no-index.cHIHIlQaTTsŔ4s^/diff.cHIHImQ! ~aŸA.ԥeditor.cHIHIxQ`"*7KhRˈ0entry.cHIHIyQ4 m]lKJZJ environment.cHIHIzQ gAh+Yc{l/S exec_cmd.cHIHI{QYO$ " أ exec_cmd.hHIHI|QpBhJ}3 fast-import.cHIHI}Q̋%aM'̘jg< fetch-pack.hHIHI~Qcߤu62\ =Ah:TXfixup-builtinsHIHIQ ly~1x'DM.~7Xe*Љfsck.cHIHIɀQ#5i>2+%#?*fsck.hHIHIɁQ<*,W޶f+sKgenerate-cmdlist.shHIHIɂQ^Mv.dg #a9'git-add--interactive.perlHIHIɃQ1gj(˽7韮>o git-am.shHIHIɄQf ,Gޏ3git-archimport.perlHIHIɅQ-< y!rPě git-bisect.shHIHIɆQ#|ωY7rJptE\git-compat-util.hHIHIɇQ,4m4"ό=git-cvsexportcommit.perlHIHIɈQiYfN]G^ :ebbgit-cvsimport.perlHIHIɉQĆƈ%?9(]git-cvsserver.perlHIHIɊQ)("N!O:-ݣ@mgit-filter-branch.shH'H'Qad6`-b,`c0x-7ԙgit-gui/lib/branch_checkout.tclH'H'Qh8wLc [{Hhgit-gui/lib/branch_create.tclH'H'Q >0VkVNgit-gui/lib/branch_delete.tclH'H'Q e8Fu^+m>git-gui/lib/branch_rename.tclH'H'Q.G dV Ap! 8>git-gui/lib/browser.tclH'H'Q6ʈpfsuBJR24git-gui/lib/checkout_op.tclH'H'QVD;,bvZdwC0git-gui/lib/choose_font.tclH'H'Q[1xaXb- cj xZ!git-gui/lib/choose_repository.tclH'H'Q:ȂcPyM`\git-gui/lib/choose_rev.tclH'H'Q !A*!Abh̔xθogit-gui/lib/class.tclH'H'Q*@5WQnxQY+u2fgit-gui/lib/commit.tclH'H'QFNgpz?(lX_git-gui/lib/console.tclH'H'Q nȴ0chXRB+zgit-gui/lib/database.tclH'H'Q!)R4|git-gui/lib/date.tclH'H'Q1RJGl.Pj5*% git-gui/lib/diff.tclH'H'Q. ɆDu6hgit-gui/lib/encoding.tclH'H'Q ueWQMe m%jgit-gui/lib/error.tclH'H'Q63LZY g3 XJgit-gui/lib/git-gui.icoH'H'Q$<tubш _hgit-gui/lib/index.tclH'H' Q_fQ 8_Q=e1git-gui/lib/logo.tclH'H'!Q8\[ z"Egit-gui/lib/merge.tclH'H'"Q ;%H{Zc΂[git-gui/lib/option.tclH'H'#Qݬ uRݮҟ|9git-gui/lib/remote.tclH'H'$QIǸMFܥgGc$git-gui/lib/remote_branch_delete.tclH'H'%Q {82>Db git-gui/lib/shortcut.tclH'H'&Q%mxD4,Kk"I۽git-gui/lib/spellcheck.tclH'H''Q QuQ\oBY6}$git-gui/lib/status_bar.tclH'H'(Qj `^iԈKTgit-gui/lib/transport.tclH'H')Q0=]+:vb+Ysgit-gui/lib/win32.tclH'H'*Qxy# Ld1git-gui/lib/win32_shortcut.jsHH,Q,ݾc4Xkl3=SY; git-gui/macosx/AppMain.tclH'H'-QA&T`fDreU:Ogit-gui/macosx/Info.plistH'H'.Qpw؊wfg3\Wgȴ<git-gui/macosx/git-gui.icnsH'H'0Q IisqUteXegit-gui/po/.gitignoreH'H'1Q'^w#W05 git-gui/po/READMEH'H'2Q U + ȂmܓbJgit-gui/po/de.poH'H'3QĈհ4?eqgit-gui/po/fr.poH'H'4Q1$Etgit-gui/po/git-gui.potH'H'6Qt4'Qk{ԇgit-gui/po/glossary/MakefileH'H'7Q5vM"E8> 3.git-gui/po/glossary/de.poH'H'8Q'^~DΚNQgit-gui/po/glossary/fr.poH'H'9Q@>Ӑ&Uة6(git-gui/po/glossary/git-gui-glossary.potH'H':Q I1R^HMF}x¿!@(git-gui/po/glossary/git-gui-glossary.txtH'H';QPFkDj#J3~Awgit-gui/po/glossary/it.poH'H'<QI|Se諺(WwC!git-gui/po/glossary/txt-to-pot.shH'H'=Q56G5~a"rȻzgit-gui/po/glossary/zh_cn.poH'H'>QB(vx8Ӟ5OYR!git-gui/po/hu.poH'H'?Q;y^XδWwMJgit-gui/po/it.poH'H'@Qb($kZ )r{ git-gui/po/ja.poH'H'AQ Ŀ?=%pnIgit-gui/po/po2msg.shH'H'BQ?Uঘˡi2!.[+git-gui/po/ru.poH'H'CQMAGmԜ/Shgit-gui/po/sv.poH'H'DQƆfqcL0E)A5d)git-gui/po/zh_cn.poH'H'FQSéF96D^UO\pgit-gui/windows/git-gui.shHgHgQC7+W7bhcB ]Sgit-instaweb.shHgHgQ3άAϱRl^Mgit-lost-found.shHgHgQ od^G܈o+ Dtk+git-merge-octopus.shHgHg Q 2fF9j _?*A 'git-merge-one-file.shHgHg Q/]AbWx28x\git-merge-resolve.shHgHg Q&|0lw5( agit-mergetool.shHgHg QiZ@B04oо&git-parse-remote.shHgHg Q8uaXf=+E`eG1u git-pull.shHgHgQ κ5D/git-quiltimport.shHgHgQ6N3K0g9Ky^xgit-rebase--interactive.shHgHgQ+A.\:vS" git-rebase.shHgHgQ/|iHX;#p[Wgit-relink.perlHgHgQ ^h9`Mkt>h{.@Ұ  git-repack.shHgHgQ`:1LC0eV ogit-request-pull.shHgHgQjvDRD 3Bgit-send-email.perlHgHgQ FxFgit-sh-setup.shHgHgQ `nV`!Æ9 git-stash.shHgHgQ2qj,\"(aūgit-submodule.shHgHgQ/m's|q 1Du< git-svn.perlHgHgQ8AHĒnE2_"git-web--browse.shHgHgQ67jYTb@<git.cHgHgQ%7I.[v>5$bZ4/ git.spec.inHgHgHQV\Į W߂VIgitk-git/MakefileHgHgIQ,ܴXh9]~WJ gitk-git/gitkHgHgKQX5/\Z~wzMhgitk-git/po/.gitignoreHH+QHw{]yvgitk-git/po/de.poHgHgMQI,HbG#/a= ۓgitk-git/po/es.poHgHgNQH[mh#LۺJgitk-git/po/it.poHgHgOQ 2Hu+Gu/r@Tgitk-git/po/po2msg.shHgHgPQFcLAT2򂣌gitk-git/po/sv.poHgHgRQ"&~ ʎǙFu7ygitweb/INSTALLHgHgSQ>ÂQbTg M) gitweb/READMEHgHgTQc| bkQϋgitweb/git-favicon.pngHgHgUQS_cA9$QCQ:Dngitweb/git-logo.pngHgHgVQ6G3T;ͳgitweb/gitweb.cssHgHgWQz͙a5}^UUĉgitweb/gitweb.perlHgHgQoc?v{pmLi+?k3graph.cHgHgQQں)=N\>(wDgraph.hHgHgQ2}g_B8JzL;x_grep.cHgHgQ]R%&ٸf;M<֚grep.hHgHg Q FjRGZ`|?U hash-object.cHgHg!Q YK^nFvhash.cHgHg"Qi:GTဴWhash.hHgHg#QB$<(VY7{uhelp.cHgHg$Qh(W Е5ۈ1> http-push.cHgHg%Q^Ʋ{Ez)yPg ^o- http-walker.cHgHg&Q9/J1Gh - http.cHgHg'Q [F)wp\t_lޤhttp.hHgHg(QUUCts>Z&'ident.cHgHg)Qr1 ! ? VdXJ imap-send.cHgHg*QhhRKۻgЎ6=O index-pack.cHgHg+QŶjlC&V interpolate.cHgHg,QYw@~gܩ~Rtƞ.ti ; interpolate.hHgHg-Qȸ7^IyN`!z$ wŭK mailmap.hHgHg6Qm}n9Sk21,& match-trees.cHgHg7Q *5nTL7<) merge-file.cHgHg8Q tjS2Jj[Wz ; merge-index.cHgHg9Qv0pDMkmerge-recursive.hHgHg:Q #"S^|V?  merge-tree.cHgHg;Q\ 44q=Jn>U/[mktag.cHgHg<Q  ӧ7mǍfBmktree.cHgHgYQ?5gR'wt;Zmozilla-sha1/sha1.cHgHgZQ<0wrmozilla-sha1/sha1.hHgHg=Q 01׎-a 93Nؐ name-hash.cHgHg>QPRK& x =iobject.cHgHg?Q<koYm`6h.object.hHgHg@Q-^hVʣء4M pack-check.cHgHgAQ;p%D\ ٧,pack-redundant.cHgHgBQ ?1+,e<& cW pack-refs.cHgHgCQQϳpr9: pack-refs.hHgHgDQ)0 $ Rv!C=pack-revindex.cHgHgEQ6`~wyNP0pack-revindex.hHgHgFQ&6lޖ v7&$ pack-write.cHgHgGQv*T^|D,~h5lpack.hHgHgHQk\D8ݳDEMVpager.cHgHgIQ.fq+, wA n-parse-options.cHgHgJQ1~uzfAQTҎqparse-options.hHgHgKQ흸,,@۱] patch-delta.cHgHgLQ4IUEk7A|QO patch-id.cHgHgMQ;^ v ,l patch-ids.cHgHgNQ MYJ`. patch-ids.hHgHgOQ$0Gmϭ_ bG@path.cHܡHܡQ/Gr8O<perl/.gitignoreHܡHܡQzٞw.8ff pkt-line.hHgHgbQs6H"¦kv& ppc/sha1.cHgHgcQԇ\%| Wv ppc/sha1.hHgHgQ 2in+C" ppc/sha1ppc.SHgHgRQQ34gG&%O?9sOpretty.cHgHgSQCUhzWZ[F=!i progress.cHgHgTQaLMBJ &[,^ progress.hHgHgUQ&vjRU8NW+Jquote.cHgHgVQ-sP|4·quote.hHgHgWQ;`C|fL reachable.cHgHgXQ@uO c4r'>ѥ reachable.hHgHgYQ,0i Uz})_-Ϝ read-cache.cHgHgZQ0MLw=˪g彚receive-pack.cHgHg[QQ2FG 2O reflog-walk.cHgHg\Q|CMtRbƽ u- reflog-walk.hHgHg]Q98q\VDY2 =Arefs.cHgHg^Q &VaumBrefs.hHgHg_Q~:i`!ΤSDremote.cHgHg`Q M%_Y\remote.hHgHgaQ 2>I=F^9 L sha1_name.cHgHgnQ 5M 9z^oV shallow.cHgHgoQ2jH`Pq^ڸzHjshell.cHgHgpQ¼) _d aM_0F shortlog.hHgHgqQVESWs65ߔbހ show-index.cHgHgrQ wx˒i9Qd: .nβ sideband.cHgHgsQOKiǡ{_%@jD1 sideband.hHgHgtQtr7VR9rDstrbuf.cHgHguQ맺B:-:8>?fʉk1 symlinks.cHgHgfQ$F[}DhL\Pz0-Jt/.gitattributesHgHggQ~(zv̌4 'Dt/t0050-filesystem.shHgHgQnuRcb5}LP<8t/t0060-path-utils.shHgHgQBd:S5) et/t1000-read-tree-m-3way.shHgHgQ) KD1}jsY \.{OYt/t1001-read-tree-m-2way.shHgHgQ+ܪՀXـ얉ydXat/t1002-read-tree-m-u-2way.shHgHgQmghzm:{ t/t1003-read-tree-prefix.shHgHgQW 7)#ϐX=t/t1004-read-tree-m-u-wf.shHgHgQZGFes'Jt/t1005-read-tree-reset.shHgHgQطB{ԏCat/t1006-cat-file.shHgHgQ :SQ8+I|5F1_t/t1007-hash-object.shHgHgQ 8k3Z_J lo]1Nt/t1020-subdirectory.shHgHgQPg4mhŚ$ۗaMt/t1100-commit-tree-options.shHgHgQ 5ߖ]G!ϸ(t/t1200-tutorial.shHgHgQ:^dVM\?C32ͳzFat/t1300-repo-config.shHgHgQ ܅ \pGi.8?~,Gt/t1301-shared-repo.shHgHgQٍ0[Cr_~#t/t1302-repo-version.shHgHgQ2LQynozqVN!,Ot/t1303-wacky-config.shHgHgQ"9KnV{2^t/t1400-update-ref.shHgHgQs0#tQF[4^ yt/t1410-reflog.shHgHgQܞ@,UWMN8Fmt/t1420-lost-found.shHgHgQL~Ѹ!-9ۂt/t1500-rev-parse.shHgHgQ .荊1.ְzt/t1501-worktree.shHgHgQڙp n;ٛWt/t1502-rev-parse-parseopt.shHgHgQ 8$LTތXK@":Iot/t1503-rev-parse-verify.shHgHgQ3gq"Vhut/t1504-ceiling-dirs.shHgHgQ5솙ab t/t2000-checkout-cache-clash.shHgHgQ u2Q$EZ)t/t2001-checkout-cache-clash.shHgHgQp6n& 7LSI/-t/t2002-checkout-cache-u.shHgHgQ qK7Cѹ!˺7h /Ct/t2003-checkout-cache-mkdir.shHgHgQ9;zKVrsBnt/t2004-checkout-cache-temp.shHgHgQLZjh'SX?"t/t2005-checkout-index-symlinks.shHgHgQb&c'=Z ::t/t2007-checkout-symlink.shHgHgQy> D\!Gb ft/t2008-checkout-subdir.shHgHgQ ~'ʺo t/t2009-checkout-statinfo.shHgHgQI|X.]S4l?Zt/t2010-checkout-ambiguous.shHgHgQ7hצo\`=ãt/t2050-git-dir-relative.shHgHgQ,nΆ4V0y.t/t2100-update-cache-badpath.shHgHgQY`$Qj֣/NԚ t/t2101-update-index-reupdate.shHgHgQ$ЉM&zCz?l:}2 t/t2102-update-index-symlinks.shHgHgQ 3&Ӏы>ShN#&t/t2103-update-index-ignore-missing.shHgHgQ zn|;?Hd}t/t2200-add-update.shHgHgQ L}_Wm1 t/t2201-add-update-typechange.shHgHgQjQLV`֗(t/t2202-add-addremove.shHgHgQ 5 A3[Qc^Tt/t3000-ls-files-others.shHgHgQpPnbdt%6"t/t3001-ls-files-others-exclude.shHgHgQNAP5zzś,t/t3002-ls-files-dashpath.shHgHgQ*7Fgw;#t/t3010-ls-files-killed-modified.shHgHgQA!(≳6E["!t/t3020-ls-files-error-unmatch.shHgHgQ(X`0:yiXCt/t3030-merge-recursive.shHgHgQ >"J]7Ft/t3040-subprojects-basic.shHgHgQ Bad;T3ۼt/t3050-subprojects-fetch.shHgHgQ:< /,ϻ3yGt/t3060-ls-files-with-tree.shHgHgQonj%B'j8tU:<'t/t3100-ls-tree-restrict.shHgHgQM+b5hlt/t3101-ls-tree-dirname.shHgHgQG*zOkG]Yc:t/t3200-branch.shHgHgQoK6ݴj^9t/t3201-branch-contains.shHgHgQ|]_ vrw_t/t3202-show-branch-octopus.shHgHgQ 2 U^<ӍLN>t/t3210-pack-refs.shHgHgQtrUrk_}t/t3300-funny-names.shHgHgQ ^ / (vwt/t3400-rebase.shHgHgQ0mGL3!Qt/t3401-rebase-partial.shHgHgQ{}&_V#P {t/t3402-rebase-merge.shHgHgQ 3U~h&"y/t/t3403-rebase-skip.shHgHgQ(lݗVT⇕1i7Bt/t4001-diff-rename.shHgHgQ9ܤk)'e_X-~V{_t/t4002-diff-basic.shHgHgQR[_'(g$-t/t4003-diff-rename-1.shHgHgQ"=%zg > X:>|t/t4004-diff-rename-symlink.shHgHgQ Lf0sN!C"I:@t/t4005-diff-rename-2.shHgHgQN Uϼ9[S\ ot/t4006-diff-mode.shHgHgQ JNZda𰢤t/t4007-rename-3.shHgHgQ&e9'-q !t/t4008-diff-break-rewrite.shHgHgQ ^Ҵ^{,@X/Z)_$t/t4009-diff-rename-4.shHgHgQ=HEM.rh- ͪt/t4010-diff-pathspec.shHgHgQ6EpL.]@T_t/t4011-diff-symlink.shHgHgQ0usR# yjvt/t4012-diff-binary.shHgHgQf7d EH"lJt/t4013-diff-various.shHgHgQ5x+rCh(-UEIJ9t/t4013/diff.config_format.subjectprefix_DIFFERENT_PREFIXHgHgQ:xu U>t/t4013/diff.diff-tree_--cc_--patch-with-stat_--summary_masterHgHgQOc3Z (?6~] <1t/t4013/diff.diff-tree_--cc_--stat_--summary_sideHgHgQ2Ujš=e)t/t4013/diff.diff-tree_--cc_--stat_masterHgHgQM^NG&ezV`EN"t/t4013/diff.diff-tree_--cc_masterHgHgQ+zL~vQ_sٱ6/t/t4013/diff.diff-tree_--patch-with-raw_initialHgHgQ,[W0V-;Hџ0t/t4013/diff.diff-tree_--patch-with-stat_initialHgHgQ<{^>ꉴ\ 4H3R@t/t4013/diff.diff-tree_--pretty=oneline_--patch-with-raw_initialHgHgQ=V](t!aAt/t4013/diff.diff-tree_--pretty=oneline_--patch-with-stat_initialHgHgQ#y#9W7e*8Gt/t4013/diff.diff-tree_--pretty=oneline_--root_--patch-with-raw_initialHgHgQT3x@zl#<Ht/t4013/diff.diff-tree_--pretty=oneline_--root_--patch-with-stat_initialHgHgQE/ ,y?t/t4013/diff.diff-tree_--pretty_--root_--stat_--summary_initialHgHgQ)TMG6A5t/t4013/diff.diff-tree_--pretty_--root_--stat_initialHgHgQگw.WA&?y[;t/t4013/diff.diff-tree_--pretty_--root_--summary_-r_initialHgHgQXJƗv$c8t/t4013/diff.diff-tree_--pretty_--root_--summary_initialHgHgQ)Ad]MS'hI1t/t4013/diff.diff-tree_--pretty_--root_-p_initialHgHgQ..-dЭ.t/t4013/diff.diff-tree_--pretty_--root_initialHgHgQ4)JZ DB.8t/t4013/diff.diff-tree_--pretty_--stat_--summary_initialHgHgQ*L K-ݢA8z.t/t4013/diff.diff-tree_--pretty_--stat_initialHgHgQ- -РٻG$t/t4013/diff.diff-tree_--pretty_sideHgHg QZK*bbԖ[o{M.t/t4013/diff.diff-tree_--root_--abbrev_initialHgHg Q ҕu&8\^;,&n6t/t4013/diff.diff-tree_--root_--patch-with-raw_initialHgHg Q;b'_aB9O7t/t4013/diff.diff-tree_--root_--patch-with-stat_initialHgHg Q2/^´织ۚ (t/t4013/diff.diff-tree_--root_-p_initialHgHgQ SahTY$RpW$3t/t4013/diff.diff-tree_--root_-r_--abbrev=4_initialHgHgQǴ`W0 H1t/t4013/diff.diff-tree_--root_-r_--abbrev_initialHgHgQ5u ?o4c`n(t/t4013/diff.diff-tree_--root_-r_initialHgHgQhou|dcC%t/t4013/diff.diff-tree_--root_initialHgHgQҸ%0qz}{b-a]Y)t/t4013/diff.diff-tree_-c_--abbrev_masterHgHgQdr_3߻WwVO1t/t4013/diff.diff-tree_-c_--stat_--summary_masterHgHgQ*n%TMj/t/t4013/diff.diff-tree_-c_--stat_--summary_sideHgHgQj^ 1JES)'t/t4013/diff.diff-tree_-c_--stat_masterHgHgQ}һ&JȆF}ǣ>ϫ] t/t4013/diff.diff-tree_-c_masterHgHgQԶ uH Ph #t/t4013/diff.diff-tree_-p_-m_masterHgHgQ p*05 IDH!t/t4013/diff.diff-tree_-p_initialHgHgQ_? LQ t/t4013/diff.diff-tree_-p_masterHgHgQ(ţZhTL`bY,t/t4013/diff.diff-tree_-r_--abbrev=4_initialHgHgQ& hwCﭘ(t/t4013/diff.diff_--name-status_dir2_dirHgHg!Q9jGXGw\q)D3t/t4013/diff.diff_--no-index_--name-status_dir2_dirHgHg"Q5yZ)KVc$ b3t/t4013/diff.diff_--patch-with-raw_-r_initial..sideHgHg#Q]|ɹƺߛ&_r0t/t4013/diff.diff_--patch-with-raw_initial..sideHgHg$QJ{skaU퓔4t/t4013/diff.diff_--patch-with-stat_-r_initial..sideHgHg%QPbf8Qy땆r7I"21t/t4013/diff.diff_--patch-with-stat_initial..sideHgHg&Q1)BuoQ70&t/t4013/diff.diff_--stat_initial..sideHgHg'Q$R u(c/꧔)t/t4013/diff.diff_-r_--stat_initial..sideHgHg(Q[/( -Eڧx"t/t4013/diff.diff_-r_initial..sideHgHg)QȭYXcovɁ1crt/t4013/diff.diff_initial..sideHgHg*Q C4kC"oẗTaҪ;t/t4013/diff.format-patch_--attach_--stdout_initial..masterHgHg+Q >I ) =x9_>^虉 nSgEt/t4013/diff.format-patch_--stdout_--cover-letter_-n_initial..master^HgHg3Q䋈I'fI7N2t/t4013/diff.format-patch_--stdout_initial..masterHgHg4Q0G7܆PHxgP3t/t4013/diff.format-patch_--stdout_initial..master^HgHg5Qeu[6aq0t/t4013/diff.format-patch_--stdout_initial..sideHgHg6Qv~4x.m0t/t4013/diff.log_--root_--patch-with-stat_masterHgHg<Q &]NRpIpqt=t/t4013/diff.log_--root_-c_--patch-with-stat_--summary_masterHgHg=QN!z.qך6L])!t/t4013/diff.log_--root_-p_masterHgHg>Q|49='Vt/t4013/diff.log_--root_masterHgHg?Q^2CrA?X"t/t4013/diff.log_-SF_-p_masterHgHg@QY/Rq}i婖8t/t4013/diff.log_-SF_masterHgHgAQÆ7\Qi`t/t4013/diff.log_-p_masterHgHgBQ 俟 7t/t4013/diff.log_masterHgHgCQ"F,Nʰ"ޗ't/t4013/diff.show_--patch-with-raw_sideHgHgDQ7+{z4;)hZg$2t/t4013/diff.show_--patch-with-stat_--summary_sideHgHgEQ0ys T~u[P(t/t4013/diff.show_--patch-with-stat_sideHgHgFQlM / t/t4013/diff.show_--root_initialHgHgGQ3[՗v(iD2it/t4100/t-apply-6.patchHgHg~Q$M L$(t/t4100/t-apply-7.expectHgHgQ/XtZ׷:[t/t4100/t-apply-7.patchHgHgQS\)5Dt/t4100/t-apply-8.expectHgHgQ\>eG"Q֔ڈt/t4100/t-apply-8.patchHgHgQS\)5Dt/t4100/t-apply-9.expectHgHgQ]WgXz~M*w%t/t4100/t-apply-9.patchHgHgQ$ڊd셇$Yot/t4101-apply-nonl.shHgHgQ1G'7< FQZy͖ut/t4101/diff.0-1HgHgQM6F $:%mp t t/t4101/diff.0-2HgHgQP>[_I&eh4 褦:t/t4101/diff.0-3HgHgQ1'p x+cLt/t4101/diff.1-0HgHgQP*D \⭮S3c;j_t/t4101/diff.1-2HgHgQPauIC n?Nt/t4101/diff.1-3HgHgQMD282Pct/t4101/diff.2-0HgHgQPmӡ7.ZIρpɅt/t4101/diff.2-1HgHgQMV31 ԂȜ2<t/t4101/diff.2-3HgHgQPsJw Xt/t4101/diff.3-0HgHgQPǙ`$4lQKt/t4101/diff.3-1HgHgQMѺmFiS >d,pwt/t4101/diff.3-2HgHgQ*Y4?K٨,27 t/t4102-apply-rename.shHgHgQ p}v[nN5t/t4103-apply-binary.shHgHgQ =E̟v97W?b8dt/t4104-apply-boundary.shHgHgQ{2f9X% e*t/t4105-apply-fuzz.shHgHgQ(X?$ ^ٴ|t/t4109-apply-multifrag.shHgHgQMPE''dWj`t/t4109/expect-1HgHgQRAwWP51t/t4109/expect-2HgHgQ*G_"K i=`[t/t4109/expect-3HgHgQkA>|jt/t4109/patch1.patchHgHgQok6mxoR*,&t/t4109/patch2.patchHgHgQ֖Zu*imVn)0t/t4109/patch3.patchHgHgQKY `v7t/t4109/patch4.patchHgHgQ "A*].=%#)t/t4110-apply-scan.shHgHgQZI>ȠB<0$3]t/t4110/expectHgHgQVz9@6*qt/t4110/patch1.patchHgHgQpBG}% 0rf!t/t4110/patch2.patchHgHgQ&D' )?'Zat/t4110/patch3.patchHgHgQp-~.:홾>t/t4110/patch4.patchHgHgQuŬiӤfܧ5r1,t/t4110/patch5.patchHgHgQ 7XH ԻՙV,וt/t4112-apply-renames.shHgHgQfQY/n0J>t/t4113-apply-ending.shHgHgQ U3I'8d_J<it/t4114-apply-typechange.shHgHgQWzP̯ZJ:7嚝t/t4124-apply-ws-rule.shHgHgQ;Gd'Mѫt/t4125-apply-ws-fuzz.shHgHgQ ζ[&H!UV4Nt/t4126-apply-empty.shHgHgQ).t/t4127-apply-same-fn.shHgHgQ--_Ki w :52MƂnt/t4128-apply-root.shHgHgQnjY6DVږR1 t/t4150-am.shHgHgQ}}dR/X=>xr|t/t4151-am-abort.shHgHgQ)xJƽC6:t/t4200-rerere.shHgHgQ@[uu0ƱlNt/t4201-shortlog.shHgHgQyL_ME)¦'v >ot/t4202-log.shHgHgQN4!\ 0K{Dt/t5000-tar-tree.shHgHgQ,~XMmFiVA9t/t5100-mailinfo.shHgHgQ,>0bjLbs t/t5100/0010HgHgQf'wKFKrTt/t5100/info0001HgHgQjI2<+¥ d΃t/t5100/info0002HgHgQh !41Y9Bwst/t5100/info0003HgHgQal0#٪EJ!t/t5100/msg0004HgHgQݔ{R$:Oݛq\Yt/t5100/msg0005HgHgQ uv( Ӧ:pt/t5100/msg0006HgHgQ'q<6ۘ.Nsf(t/t5100/msg0007HgHgQC˗]$"ڽ^bIt/t5100/msg0008HgHgQ+ Ʊ,Vt/t5100/msg0009HgHgQکl#47@Dt/t5100/msg0010HgHgQր1NZ4PR;/t/t5100/nul-b64.expectHgHgQ T n0]-nt/t5100/nul-b64.inHgHgQ[=@iU3QJ$=!t/t5100/nul-plainHgHgQU}Qh9\1,F,ct/t5100/patch0001HgHgQU}Qh9\1,F,ct/t5100/patch0002HgHgQU}Qh9\1,F,ct/t5100/patch0003HgHgQdXNtR:»t/t5100/patch0004HgHgQ }$J<֝t/t5100/patch0005HgHgQU}Qh9\1,F,ct/t5100/patch0006HgHgQ⛲CK)wZSt/t5100/patch0007HgHgQ⛲CK)wZSt/t5100/patch0008HgHgQea\4n S.k`4Lt/t5100/patch0009HgHgQaUHVr>|%Q;;t/t5100/patch0010HgHgQ8|+3pon7t/t5100/sample.mboxHgHgQ&EdU){c Iā(.t/t5300-pack-object.shHgHgQ:=GKǶ"ct/t5301-sliding-window.shHgHgQg9w*V>y;ut/t5302-pack-index.shHgHgQ1 !< fK=Ɖp%t/t5303-pack-corruption-resilience.shHgHgQ jp3y! 1w3t/t5304-prune.shHgHgQKGƘ1$@~/kt/t5305-include-tag.shHgHgQih®h+n'b/Q.{t/t5400-send-pack.shHgHgQgvfqąMO$t/t5401-update-hooks.shHgHgQ ztv#BmY_;t/t5402-post-merge-hook.shHgHgQ .29QdՕlܲt/t5403-post-checkout-hook.shHgHgQ@V]cW"s3f,-W|t/t5404-tracking-branches.shHgHgQQ"qۚٞ4>$/t/t5405-send-pack-rewind.shHgHgQ Y ^S`{:ptMPt/t5406-remote-rejects.shHgHgQF6,( u)61x('t/t5500-fetch-pack.shHgHgQUkhfHivm˵`< t/t5502-quickfetch.shHgHgQ n@t?,zJ6~'1"K8t/t5503-tagfollow.shHgHgQ2oY ̇^1dEt/t5505-remote.shHgHgQ&lspnԋAt/t5510-fetch.shHgHgQ "84w^u<)JOVCt/t5511-refspec.shHgHgQ;ջ< xR/t/t5512-ls-remote.shHgHgQ+t'K?y˙:>c8t/t5513-fetch-track.shHgHgQ?8#q٣2 t/t5515-fetch-merge-logic.shHgHgQ0.o3k}!t/t5515/fetch.br-branches-defaultHgHgQ,ѴN>܌..wVX!'t/t5515/fetch.br-branches-default-mergeHgHgQ}|VB1 8t/t5515/fetch.br-branches-default-merge_branches-defaultHgHgQ9K~$-oUU]V*q)t/t5515/fetch.br-branches-default-octopusHgHgQk.${RkIͲ%:t/t5515/fetch.br-branches-default-octopus_branches-defaultHgHgQAJ+\tA}M+2t/t5515/fetch.br-branches-default_branches-defaultHgHgQ) ȩ@+qyqBt/t5515/fetch.br-branches-oneHgHgQ|\jKw#t/t5515/fetch.br-branches-one-mergeHgHgQ.}1X+K@I0t/t5515/fetch.br-branches-one-merge_branches-oneHgHgQoj->J(ZH@T%t/t5515/fetch.br-branches-one-octopusHgHgQ|U!>jo-Y2t/t5515/fetch.br-branches-one-octopus_branches-oneHgHgQ6(H-x\ gi >*t/t5515/fetch.br-branches-one_branches-oneHgHgQTd~F$P t/t5515/fetch.br-config-explicitHgHgQr1xu,$Ԇ#=&t/t5515/fetch.br-config-explicit-mergeHgHgQ(Tea0o|R?&6t/t5515/fetch.br-config-explicit-merge_config-explicitHgHg Q p@މeSUg(t/t5515/fetch.br-config-explicit-octopusHgHg QQqc7JF8t/t5515/fetch.br-config-explicit-octopus_config-explicitHgHg Q"#}nKеu1{W0t/t5515/fetch.br-config-explicit_config-explicitHgHg Q^+D 'YQt/t5515/fetch.br-config-globHgHg QΏs _SMA< "t/t5515/fetch.br-config-glob-mergeHgHgQ X|2I3,.t/t5515/fetch.br-config-glob-merge_config-globHgHgQ S-^hE&#$t/t5515/fetch.br-config-glob-octopusHgHgQ"[f[:Un0t/t5515/fetch.br-config-glob-octopus_config-globHgHgQ'np[(SKp(t/t5515/fetch.br-config-glob_config-globHgHgQSM.^0+8]I0 t/t5515/fetch.br-remote-explicitHgHgQMZVZ6&t/t5515/fetch.br-remote-explicit-mergeHgHgQ(s*7X#w ( Cp6t/t5515/fetch.br-remote-explicit-merge_remote-explicitHgHgQ )z3o-xwˉ(t/t5515/fetch.br-remote-explicit-octopusHgHgQwS@>*Y.{}S[8t/t5515/fetch.br-remote-explicit-octopus_remote-explicitHgHgQ"Qgv_Gyn&c0t/t5515/fetch.br-remote-explicit_remote-explicitHgHgQ1{R"@Q{Nt/t5515/fetch.br-remote-globHgHgQ 6.%VCB̵ʡgj"t/t5515/fetch.br-remote-glob-mergeHgHgQ . m ɭ/M.t/t5515/fetch.br-remote-glob-merge_remote-globHgHgQ aMܐC3%|oK$t/t5515/fetch.br-remote-glob-octopusHgHgQGG3\Ƿ30t/t5515/fetch.br-remote-glob-octopus_remote-globHgHgQ'dmp6D[(t/t5515/fetch.br-remote-glob_remote-globHgHgQemcw:XXYšt/t5515/fetch.br-unconfigHgHgQXh;{=ʉF(t/t5515/fetch.br-unconfig_--tags_.._.gitHgHg QD(Ka< A-@A!t/t5515/fetch.br-unconfig_.._.gitHgHg!QXZn-Rz >)QW%t/t5515/fetch.br-unconfig_.._.git_oneHgHg"QC+/|a(!^Dt/t5515/fetch.br-unconfig_.._.git_one_tag_tag-one_tag_tag-three-fileHgHg#Q?$k_]7l)t/t5515/fetch.br-unconfig_.._.git_one_twoHgHg$QA϶JáT5<Et/t5515/fetch.br-unconfig_.._.git_tag_tag-one-tree_tag_tag-three-fileHgHg%Q 3$Gt{;t/t5515/fetch.br-unconfig_.._.git_tag_tag-one_tag_tag-threeHgHg&Q9pA!PAzPN% I.*t/t5515/fetch.br-unconfig_branches-defaultHgHg'Q2Lt[X`Df&#bχ&t/t5515/fetch.br-unconfig_branches-oneHgHg(Q 7<6=[9)t/t5515/fetch.br-unconfig_config-explicitHgHg)Q$:Ul^Gl>56W%t/t5515/fetch.br-unconfig_config-globHgHg*Q!mV.IeMCV.)t/t5515/fetch.br-unconfig_remote-explicitHgHg+Q$\ Mhz:%t/t5515/fetch.br-unconfig_remote-globHgHg,Qx|x%<#j Et/t5515/fetch.masterHgHg-QY {^RY}::1Jo#t/t5515/fetch.master_--tags_.._.gitHgHg.Q?fѪݮlM(b't/t5515/fetch.master_.._.gitHgHg/QS5ݽ,ŒzPŒ=y t/t5515/fetch.master_.._.git_oneHgHg0Q>$@$>`dEh?t/t5515/fetch.master_.._.git_one_tag_tag-one_tag_tag-three-fileHgHg1Q5WȦjv1OA$t/t5515/fetch.master_.._.git_one_twoHgHg2Q.>)m)Eo˩Xk@t/t5515/fetch.master_.._.git_tag_tag-one-tree_tag_tag-three-fileHgHg3Q꒱@ȃM gK)Y6t/t5515/fetch.master_.._.git_tag_tag-one_tag_tag-threeHgHg4Q4`=m#1+jXZhXر %t/t5515/fetch.master_branches-defaultHgHg5Q-)QY4/b#!t/t5515/fetch.master_branches-oneHgHg6QK|uu%qjdZ$t/t5515/fetch.master_config-explicitHgHg7Q&~I{VKh¢s t/t5515/fetch.master_config-globHgHg8QDʄ)`y5n7E)I$ $t/t5515/fetch.master_remote-explicitHgHg9QrN3$gil5 t/t5515/fetch.master_remote-globHgHg:Q!|]q3Q@9TEey t/t5515/refs.br-branches-defaultHgHg;Q!|]q3Q@9TEey&t/t5515/refs.br-branches-default-mergeHgHg<Q!|]q3Q@9TEey7t/t5515/refs.br-branches-default-merge_branches-defaultHgHg=Q!|]q3Q@9TEey(t/t5515/refs.br-branches-default-octopusHgHg>Q!|]q3Q@9TEey9t/t5515/refs.br-branches-default-octopus_branches-defaultHgHg?Q!|]q3Q@9TEey1t/t5515/refs.br-branches-default_branches-defaultHgHg@QpZ]R2Uz"ot/t5515/refs.br-branches-oneHgHgAQpZ]R2Uz"o"t/t5515/refs.br-branches-one-mergeHgHgBQpZ]R2Uz"o/t/t5515/refs.br-branches-one-merge_branches-oneHgHgCQpZ]R2Uz"o$t/t5515/refs.br-branches-one-octopusHgHgDQpZ]R2Uz"o1t/t5515/refs.br-branches-one-octopus_branches-oneHgHgEQpZ]R2Uz"o)t/t5515/refs.br-branches-one_branches-oneHgHgFQ3)X&v;.uot/t5515/refs.br-config-explicitHgHgGQ3)X&v;.uo%t/t5515/refs.br-config-explicit-mergeHgHgHQ3)X&v;.uo5t/t5515/refs.br-config-explicit-merge_config-explicitHgHgIQ3)X&v;.uo't/t5515/refs.br-config-explicit-octopusHgHgJQ3)X&v;.uo7t/t5515/refs.br-config-explicit-octopus_config-explicitHgHgKQ3)X&v;.uo/t/t5515/refs.br-config-explicit_config-explicitHgHgLQ3)X&v;.uot/t5515/refs.br-config-globHgHgMQ3)X&v;.uo!t/t5515/refs.br-config-glob-mergeHgHgNQ3)X&v;.uo-t/t5515/refs.br-config-glob-merge_config-globHgHgOQ3)X&v;.uo#t/t5515/refs.br-config-glob-octopusHgHgPQ3)X&v;.uo/t/t5515/refs.br-config-glob-octopus_config-globHgHgQQ3)X&v;.uo't/t5515/refs.br-config-glob_config-globHgHgRQ3)X&v;.uot/t5515/refs.br-remote-explicitHgHgSQ3)X&v;.uo%t/t5515/refs.br-remote-explicit-mergeHgHgTQ3)X&v;.uo5t/t5515/refs.br-remote-explicit-merge_remote-explicitHgHgUQ3)X&v;.uo't/t5515/refs.br-remote-explicit-octopusHgHgVQ3)X&v;.uo7t/t5515/refs.br-remote-explicit-octopus_remote-explicitHgHgWQ3)X&v;.uo/t/t5515/refs.br-remote-explicit_remote-explicitHgHgXQ3)X&v;.uot/t5515/refs.br-remote-globHgHgYQ3)X&v;.uo!t/t5515/refs.br-remote-glob-mergeHgHgZQ3)X&v;.uo-t/t5515/refs.br-remote-glob-merge_remote-globHgHg[Q3)X&v;.uo#t/t5515/refs.br-remote-glob-octopusHgHg\Q3)X&v;.uo/t/t5515/refs.br-remote-glob-octopus_remote-globHgHg]Q3)X&v;.uo't/t5515/refs.br-remote-glob_remote-globHgHg^Q.FH) jt/t5515/refs.br-unconfigHgHg_Q.FH) j't/t5515/refs.br-unconfig_--tags_.._.gitHgHg`QKp.R>]Ʀ t/t5515/refs.br-unconfig_.._.gitHgHgaQKp.R>]Ʀ$t/t5515/refs.br-unconfig_.._.git_oneHgHgbQ.FH) jCt/t5515/refs.br-unconfig_.._.git_one_tag_tag-one_tag_tag-three-fileHgHgcQKp.R>]Ʀ(t/t5515/refs.br-unconfig_.._.git_one_twoHgHgdQ.FH) jDt/t5515/refs.br-unconfig_.._.git_tag_tag-one-tree_tag_tag-three-fileHgHgeQ.FH) j:t/t5515/refs.br-unconfig_.._.git_tag_tag-one_tag_tag-threeHgHgfQ!|]q3Q@9TEey)t/t5515/refs.br-unconfig_branches-defaultHgHggQpZ]R2Uz"o%t/t5515/refs.br-unconfig_branches-oneHgHghQ3)X&v;.uo(t/t5515/refs.br-unconfig_config-explicitHgHgiQ3)X&v;.uo$t/t5515/refs.br-unconfig_config-globHgHgjQ3)X&v;.uo(t/t5515/refs.br-unconfig_remote-explicitHgHgkQ3)X&v;.uo$t/t5515/refs.br-unconfig_remote-globHgHglQ.FH) jt/t5515/refs.masterHgHgmQ.FH) j"t/t5515/refs.master_--tags_.._.gitHgHgnQKp.R>]Ʀt/t5515/refs.master_.._.gitHgHgoQKp.R>]Ʀt/t5515/refs.master_.._.git_oneHgHgpQ.FH) j>t/t5515/refs.master_.._.git_one_tag_tag-one_tag_tag-three-fileHgHgqQKp.R>]Ʀ#t/t5515/refs.master_.._.git_one_twoHgHgrQ.FH) j?t/t5515/refs.master_.._.git_tag_tag-one-tree_tag_tag-three-fileHgHgsQ.FH) j5t/t5515/refs.master_.._.git_tag_tag-one_tag_tag-threeHgHgtQ!|]q3Q@9TEey$t/t5515/refs.master_branches-defaultHgHguQpZ]R2Uz"o t/t5515/refs.master_branches-oneHgHgvQ3)X&v;.uo#t/t5515/refs.master_config-explicitHgHgwQ3)X&v;.uot/t5515/refs.master_config-globHgHgxQ3)X&v;.uo#t/t5515/refs.master_remote-explicitHgHgyQ3)X&v;.uot/t5515/refs.master_remote-globHgHgzQ) JdxP>WkՀt/t5516-fetch-push.shHgHg{QIv+jY4<؞.8t/t5600-clone-fail-cleanup.shHgHgQׅxP}?gt/t5601-clone.shHgHgQg_nͼ/O aD_t/t5602-clone-remote-exec.shHgHgQ X`i '4QB_6t/t5700-clone-reference.shHgHgQ _En^lC54Nt/t5701-clone-local.shHgHgQ_2M3K.DU`t/t5702-clone-options.shHgHgQ q':IF'2t/t5710-info-alternate.shHgHgQ WV'Ah.rՊ"cD t/t6000lib.shHgHgQ 6͓/N+jƮt/t6001-rev-list-graft.shHgHgQ ]_os_rwat/t6002-rev-list-bisect.shHgHgQ" ] ̅kQ9eN Z:t/t6003-rev-list-topo-order.shHgHgQ]TŒœmgt/t6004-rev-list-path-optim.shHgHgQ d+!TOv<BA.t/t6005-rev-list-count.shHgHgQ9vHM"8.Ϲt/t6006-rev-list-format.shHgHgQK *b[7$t/t6007-rev-list-cherry-pick-file.shHgHgQ,į# ʎHTYqt/t6008-rev-list-submodule.shHgHgQȩjK`,͠H%t/t6009-rev-list-parent.shHgHgQ {$&r0W1RG*fʿJt/t6010-merge-base.shHgHgQZKuҵM%_z#t/t6011-rev-list-with-bad-commit.shHgHgQI(Wѥrd\s_t/t6020-merge-df.shHgHgQ\37}vB{{t/t6021-merge-criss-cross.shHgHgQ *F]Ӄˆ:_^ t/t6022-merge-rename.shHgHgQTtČ>;ZX1gT)t/t6023-merge-file.shHgHgQeHaƳ[t/t6023-merge-rename-nocruft.shHgHgQ V- 읶 扳Ot/t6024-recursive-merge.shHgHgQXEj`z\pt/t6025-merge-symlinks.shHgHgQ V4hY7؊Jt/t6026-merge-attr.shHgHgQlʾo68~ģt/t6027-merge-binary.shHgHgQ,FW1.Bmt/t6028-merge-up-to-date.shHgHgQ[N3tt/t6029-merge-subtree.shHgHgQ)/$Ob4xTt/t6030-bisect-porcelain.shHgHgQsﲬr/Wt/t6031-merge-recursive.shHgHgQ$O%5sz&t/t6032-merge-large-rename.shHgHgQu`-#Aa'T%?t/t6033-merge-crlf.shHgHgQj63ĩ8.7t/t6040-tracking-info.shHgHgQRUD0&2*njt/t6101-rev-parse-parents.shHgHgQ /rô:LTe?#rNHt/t6120-describe.shHgHgQ@t4XLCHک\:zt/t6200-fmt-merge-msg.shHgHgQ!Ȕrmw:t/t7005-editor.shHgHgQ اǘRW(_5t/t7010-setup.shHgHgQ t/lk?H7t/t7101-reset.shHgHgQ,x)gLHZԒZ]<[|t/t7102-reset.shHgHgQVǩ0F[*${vDt/t7103-reset-bare.shHgHgQ96{0 f% c۟t/t7104-reset.shHgHgQ5RJ1l t/t7201-co.shHgHgQ+Qثrz_8;.t/t7300-clean.shHgHgQLHyY¥Ԧ&t/t7400-submodule-basic.shHgHgQn0xP^S{-t/t7401-submodule-summary.shHgHgQM.,bvτrt/t7402-submodule-rebase.shHgHgQ؟-AJ4h)kt/t7500-commit.shHgHgQX.eȑqV.dTؚt/t7500/add-commentsHgHgQ//j!sf 2bt/t7500/add-contentHgHgQ?VmY;' a+t/t7500/add-signed-offHgHgQݝsB-t/t7502-commit.shHgHgQ8W 8ϡ>Jt/t7502-status.shHgHgQgi Ydȯ'at/t7503-pre-commit-hook.shHgHgQGhm+O#QK t/t7504-commit-msg-hook.shHgHgQ l|BLFē'r"t/t7505-prepare-commit-msg-hook.shHgHgQƧQ0ͻU|_O9r'At/t7506-status-submodule.shHgHgQ$^l+'Ղln+t/t7600-merge.shHgHgQ!Uk_'%[+ZO(]֨t/t7601-merge-pull-config.shHgHgQ(WFB!q=R}#t/t7602-merge-octopus-many.shHgHgQ +]&oDw3< &t/t7603-merge-reduce-heads.shHgHgQ`g}#Oˈp~tt/t7604-merge-custom-message.shHgHgQ![c%@Tzl%t/t7605-merge-resolve.shHgHgQG=xE&X]t/t7610-mergetool.shHgHgQ 1@8hJ)+d$t/t7701-repack-unpack-unreachable.shHgHgQWn/L Ԣt/t8001-annotate.shHgHgQoGpH~`\t/t8002-blame.shHgHgQkc3!Jt/t9101-git-svn-props.shHgHgQ|K%Hsp 1I\t/t9102-git-svn-deep-rmdir.shHgHgQXX]o-t/t9120-git-svn-clone-with-percent-escapes.shHgHgQx# qou,ᰦx^$t/t9121-git-svn-fetch-renamed-dir.shHgHgQ_'anp7t/t9121/renamed-dir.dumpHgHgQiWjewH未=t/t9122-git-svn-author.shHgHgQNxjeelXAs(+t/t9123-git-svn-rebuild-with-rewriteroot.shHgHgQ#Őolк4F%t/t9124-git-svn-dcommit-auto-props.shHgHgQ&R>2Nl$QiTt/t9200-git-cvsexportcommit.shHgHgQ\XlZ# T7U;yt/t9300-fast-import.shHgHgQ'J+Xk!CǨ8bo5ht/t9301-fast-export.shHgHgQ6K]]ip+t/t9400-git-cvsserver-server.shHgHgQ.z_e,$^*Nt/t9401-git-cvsserver-crlf.shHgHgQDCp>MWXa Qf/(G&t/t9500-gitweb-standalone-no-errors.shHgHgQ w04o#%mt/t9600-cvsimport.shHgHgQKWsi+^b| -t/t9700-perl-git.shHgHgQLM#Tv)A2t/t9700/test.plHgHgQ/p'WD)ʈ6 uE t/test-lib.shHgHgQ{λL=0"#t/test4012.pngHgHgQ{λL=0"#t/test9200a.pngHgHgQ"̽>:;8$k]t/test9200b.pngHgHgyQ Dpҿx CsHtag.cHgHgzQz  FI)btag.hHgHg{Q4gp^#s`y:X.CEtar.hHgHgQgY쿘  ݇itemplates/.gitignoreHgHgQ;?Rަ$6X templates/MakefileHgHgQ/ 6ld stemplates/branches--HgHgQċ*/OV=mM dq ~]trace.cHgHgňQOn[:E~Kc؃P transport.cHgHgʼnQе SF48gB2`$ transport.hHgHgŊQ.K&Fϲ ,, u tree-diff.cHgHgŋQUsr"_t] tree-walk.cHgHgŌQB F_Ѽd=穹.7 tree-walk.hHgHgōQl炩ʼ [YɟCtree.cHgHgŎQs/O"?] +(tree.hHgHgŏQ ܋;D:=Z1GXp unpack-file.cHgHgŐQ`ˠb_ Jounpack-trees.cHgHgőQMg&Z0\W9DNPMunpack-trees.hHgHgŒQ~ KCW7kō~}update-server-info.cHgHgœQ> {pMH upload-pack.cHgHgŔQΥNh#&hbTGF usage.cHgHgŕQ,h756O'<*M@\ 9\utf8.cHgHgŖQ8/~d)utf8.hHgHgŗQmrKz|PoW0var.cHgHgŘQhm./fDjf.walker.cHgHgřQ}NP[,]"&oHRwalker.hHgHgŚQV/&]-heg wrapper.cHgHgQL)%]7:՞ ʱ;@ write_or_die.cHgHgQyz0IBPn`hZŔlws.cHgHgQ0PIOp3`B wt-status.cHgHgQxЛ|r{s^ wt-status.hHgHgQea\Tpwkȝb4xdiff-interface.cHgHgQk4K|S xdiff-interface.hHHQ A070@Fk] xdiff/xdiff.hHgHgQ9b2 xDWxdiff/xdiffi.cHgHgQ> Ej ' ;xdiff/xdiffi.hHgHgQEBHcmwp)g xdiff/xemit.cHgHgQ?D sJ6Ϻan2)HN xdiff/xemit.hHgHgQRl4M#x;ޱ~hxdiff/xinclude.hHgHgQy2ϭFYqxdiff/xmacros.hHgHgQ0UW>zڌm:Jxe sxdiff/xmerge.cHgHgQ*z|e+V⠥hѲ~xdiff/xprepare.cHgHgQcjStQ3ZtC8xdiff/xprepare.hHgHgQ:%ؚ+j^F#kKkxdiff/xtypes.hHgHgQ(חM>a*#[ .x+Zxdiff/xutils.cHgHg Qނ^|6ĶWϘU xdiff/xutils.hTREE1437 13 iи™Uyt648 17 @R˯JE7EHt39005 0 L1(\ޏݝ.s*Lt4013115 0 g]hԐi@mft40201 0 :(|B!iO t410018 0 8ղ JK؂9kGM]t410112 0 [妕v1w)먜l+t41097 0 I3ٖc%j@t41106 0 4gFsڎ4t510035 0 FA1W~aa_t5515128 0 g]yywX4&|,ut70044 0 jY} g Kۃ#}вt75003 0 ?뢓#QyNjt91101 0 q\3]̹qtt91111 0 .}rBl.a+[st91151 0 M}+n:dt91211 0 owrôce_%t97001 0 Ԇ<5(completion1 0 whXg ]j(continuous2 0 ٕo&Z}5vfast-import7 0 e/FHFϮ[convert-objects2 0 SrFEnal1thunderbird-patch-inline2 0 YCzy wagit-gui61 4 2cRO5ofpo20 1 m lEuFYglossary8 0 xRbcꙁ0lib33 0 9e,(}* .' <macosx3 0 sILF+pG6windows1 0 G(JGn;(cBigitk-git8 1 aW2;^=̀GvZ0qU.! M%RVlibgit2-0.19.0/tests-clar/resources/icase/000077500000000000000000000000001216214232500203125ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/icase/.gitted/000077500000000000000000000000001216214232500216505ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/icase/.gitted/HEAD000066400000000000000000000000271216214232500222730ustar00rootroot00000000000000ref: refs/heads/master libgit2-0.19.0/tests-clar/resources/icase/.gitted/config000066400000000000000000000002121216214232500230330ustar00rootroot00000000000000[core] repositoryformatversion = 0 filemode = true bare = false logallrefupdates = true ignorecase = true precomposeunicode = false libgit2-0.19.0/tests-clar/resources/icase/.gitted/description000066400000000000000000000001111216214232500241070ustar00rootroot00000000000000Unnamed repository; edit this file 'description' to name the repository. libgit2-0.19.0/tests-clar/resources/icase/.gitted/index000066400000000000000000000025601216214232500227050ustar00rootroot00000000000000DIRCQQ N{\ѹ]`xiBQQ N{\ѹ]`xiDQ Q  N{\ѹ]`xiFQ Q  N{\ѹ]`xiHQQ N{\ѹ]`xiJQbQb !bRs#A2-IL/1QbQb #bRs#A2-IL/BQbQb %bRs#A2-IL/DQbQb "bRs#A2-IL/aQbQb $bRs#A2-IL/cQQ N{\ѹ]`xiaQQ N{\ѹ]`xicQQ N{\ѹ]`xieQ Q  N{\ѹ]`xigQQ N{\ѹ]`xiiQ.Q. bRs#A2-Ik/1Q4Q4 bRs#A2-Ik/BQ;Q; bRs#A2-Ik/DQ2Q2 bRs#A2-Ik/aQ:Q: bRs#A2-Ik/c8oplibgit2-0.19.0/tests-clar/resources/icase/.gitted/info/000077500000000000000000000000001216214232500226035ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/icase/.gitted/info/exclude000066400000000000000000000003601216214232500241560ustar00rootroot00000000000000# git ls-files --others --exclude-from=.git/info/exclude # Lines that start with '#' are comments. # For a project mostly in C, the following would be a good set of # exclude patterns (uncomment them if you want to use them): # *.[oa] # *~ libgit2-0.19.0/tests-clar/resources/icase/.gitted/logs/000077500000000000000000000000001216214232500226145ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/icase/.gitted/logs/HEAD000066400000000000000000000002431216214232500232370ustar00rootroot000000000000000000000000000000000000000000000000000000 76d6e1d231b1085fcce151427e9899335de74be6 Russell Belfer 1359157123 -0800 commit (initial): initial commit libgit2-0.19.0/tests-clar/resources/icase/.gitted/logs/refs/000077500000000000000000000000001216214232500235535ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/icase/.gitted/logs/refs/heads/000077500000000000000000000000001216214232500246375ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/icase/.gitted/logs/refs/heads/master000066400000000000000000000002431216214232500260540ustar00rootroot000000000000000000000000000000000000000000000000000000 76d6e1d231b1085fcce151427e9899335de74be6 Russell Belfer 1359157123 -0800 commit (initial): initial commit libgit2-0.19.0/tests-clar/resources/icase/.gitted/objects/000077500000000000000000000000001216214232500233015ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/icase/.gitted/objects/3e/000077500000000000000000000000001216214232500236105ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/icase/.gitted/objects/3e/257c57f136a1cb8f2b8e9a2e5bc8ec0258bdce000066400000000000000000000001621216214232500312440ustar00rootroot00000000000000x+)JMU061c040031Qpb'{vꘋ;cD'^\ *O >I/&@{ô;Z%_[L'Fd2>T|$3JBձ{6libgit2-0.19.0/tests-clar/resources/icase/.gitted/objects/4d/000077500000000000000000000000001216214232500236105ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/icase/.gitted/objects/4d/d6027d083575c7431396dc2a3174afeb393c93000066400000000000000000000000751216214232500305300ustar00rootroot00000000000000x+)JMU041e040031Q0dHz>7O*385jJ:t'O2$8%libgit2-0.19.0/tests-clar/resources/icase/.gitted/objects/62/000077500000000000000000000000001216214232500235305ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/icase/.gitted/objects/62/e0af52c199ec731fe4ad230041cd3286192d49000066400000000000000000000000231216214232500305660ustar00rootroot00000000000000xKOR0a(.MHlibgit2-0.19.0/tests-clar/resources/icase/.gitted/objects/76/000077500000000000000000000000001216214232500235355ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/icase/.gitted/objects/76/d6e1d231b1085fcce151427e9899335de74be6000066400000000000000000000002021216214232500306140ustar00rootroot00000000000000x 1ENӀc XdƉ&/usԛ8}2 SH, am1ЋEѷ9CJ$ nܷA bଃjO_SO9%)9libgit2-0.19.0/tests-clar/resources/icase/.gitted/objects/d4/000077500000000000000000000000001216214232500236105ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/icase/.gitted/objects/d4/4e18fb93b7107b5cd1b95d601591d77869a1b6000066400000000000000000000000251216214232500306120ustar00rootroot00000000000000xKOR0c(.I,*B.libgit2-0.19.0/tests-clar/resources/icase/.gitted/refs/000077500000000000000000000000001216214232500226075ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/icase/.gitted/refs/heads/000077500000000000000000000000001216214232500236735ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/icase/.gitted/refs/heads/master000066400000000000000000000000511216214232500251050ustar00rootroot0000000000000076d6e1d231b1085fcce151427e9899335de74be6 libgit2-0.19.0/tests-clar/resources/icase/B000066400000000000000000000000061216214232500204120ustar00rootroot00000000000000start libgit2-0.19.0/tests-clar/resources/icase/D000066400000000000000000000000061216214232500204140ustar00rootroot00000000000000start libgit2-0.19.0/tests-clar/resources/icase/F000066400000000000000000000000061216214232500204160ustar00rootroot00000000000000start libgit2-0.19.0/tests-clar/resources/icase/H000066400000000000000000000000061216214232500204200ustar00rootroot00000000000000start libgit2-0.19.0/tests-clar/resources/icase/J000066400000000000000000000000061216214232500204220ustar00rootroot00000000000000start libgit2-0.19.0/tests-clar/resources/icase/L/000077500000000000000000000000001216214232500205055ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/icase/L/1000066400000000000000000000000041216214232500205620ustar00rootroot00000000000000sub libgit2-0.19.0/tests-clar/resources/icase/L/B000066400000000000000000000000041216214232500206030ustar00rootroot00000000000000sub libgit2-0.19.0/tests-clar/resources/icase/L/D000066400000000000000000000000041216214232500206050ustar00rootroot00000000000000sub libgit2-0.19.0/tests-clar/resources/icase/L/a000066400000000000000000000000041216214232500206420ustar00rootroot00000000000000sub libgit2-0.19.0/tests-clar/resources/icase/L/c000066400000000000000000000000041216214232500206440ustar00rootroot00000000000000sub libgit2-0.19.0/tests-clar/resources/icase/a000066400000000000000000000000061216214232500204510ustar00rootroot00000000000000start libgit2-0.19.0/tests-clar/resources/icase/c000066400000000000000000000000061216214232500204530ustar00rootroot00000000000000start libgit2-0.19.0/tests-clar/resources/icase/e000066400000000000000000000000061216214232500204550ustar00rootroot00000000000000start libgit2-0.19.0/tests-clar/resources/icase/g000066400000000000000000000000061216214232500204570ustar00rootroot00000000000000start libgit2-0.19.0/tests-clar/resources/icase/i000066400000000000000000000000061216214232500204610ustar00rootroot00000000000000start libgit2-0.19.0/tests-clar/resources/icase/k/000077500000000000000000000000001216214232500205445ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/icase/k/1000066400000000000000000000000041216214232500206210ustar00rootroot00000000000000sub libgit2-0.19.0/tests-clar/resources/icase/k/B000066400000000000000000000000041216214232500206420ustar00rootroot00000000000000sub libgit2-0.19.0/tests-clar/resources/icase/k/D000066400000000000000000000000041216214232500206440ustar00rootroot00000000000000sub libgit2-0.19.0/tests-clar/resources/icase/k/a000066400000000000000000000000041216214232500207010ustar00rootroot00000000000000sub libgit2-0.19.0/tests-clar/resources/icase/k/c000066400000000000000000000000041216214232500207030ustar00rootroot00000000000000sub libgit2-0.19.0/tests-clar/resources/issue_1397/000077500000000000000000000000001216214232500210415ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/issue_1397/.gitted/000077500000000000000000000000001216214232500223775ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/issue_1397/.gitted/HEAD000066400000000000000000000000271216214232500230220ustar00rootroot00000000000000ref: refs/heads/master libgit2-0.19.0/tests-clar/resources/issue_1397/.gitted/config000066400000000000000000000001601216214232500235640ustar00rootroot00000000000000[core] bare = false repositoryformatversion = 0 filemode = false logallrefupdates = true ignorecase = true libgit2-0.19.0/tests-clar/resources/issue_1397/.gitted/index000066400000000000000000000003511216214232500234300ustar00rootroot00000000000000DIRCQ8Q8'|s+kÛQ crlf_file.txtQ8Q8 8t#XI<some_other_crlf_file.txtTREE2 0 -rW6^wJ}@l<[_Ұlibgit2-0.19.0/tests-clar/resources/issue_1397/.gitted/objects/000077500000000000000000000000001216214232500240305ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/issue_1397/.gitted/objects/7f/000077500000000000000000000000001216214232500243445ustar00rootroot00000000000000483a738f867e5b21c8f377d70311f011eb48b5000066400000000000000000000002471216214232500312120ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/issue_1397/.gitted/objects/7fxQN0 as !'nTBC+e\vӯǾofPPL8FΆ%_ċb4IܗtkULdeId<3/|0j1֣\Gcwe]~ߊS )GxEqsUڇ8mk~yIlibgit2-0.19.0/tests-clar/resources/issue_1397/.gitted/objects/83/000077500000000000000000000000001216214232500242625ustar00rootroot0000000000000012e0889a9cbab77c732b6bc39b51a683e3a318000066400000000000000000000000601216214232500313310ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/issue_1397/.gitted/objects/83xKOR0dH,*.QK*NMKrK23DrQNs!libgit2-0.19.0/tests-clar/resources/issue_1397/.gitted/objects/8a/000077500000000000000000000000001216214232500243405ustar00rootroot000000000000007ef047fc933edb62e84e7977b0612ec3f6f283000066400000000000000000000002151216214232500314420ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/issue_1397/.gitted/objects/8axK 0P9E4& g ̄[i\꺖7fYёՄޓڑbzakQ>ӛ0Vң>ÅP[N{h|&*;Xg1p(H߳w"&{Ԗ ,=6libgit2-0.19.0/tests-clar/resources/issue_1397/.gitted/objects/8e/000077500000000000000000000000001216214232500243445ustar00rootroot000000000000008f80088a9274fd23584992f587083ca1bcbbac000066400000000000000000000000771216214232500313630ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/issue_1397/.gitted/objects/8exKOR05cH,*.QK*NMKs3K2sS3ҁI@prQNlibgit2-0.19.0/tests-clar/resources/issue_1397/.gitted/objects/f2/000077500000000000000000000000001216214232500243375ustar00rootroot00000000000000c62dea0372a0578e053697d5c1ba1ac05e774a000066400000000000000000000001361216214232500313750ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/issue_1397/.gitted/objects/f2x+)JMU4f040031QH.IOI+(ahz1kή5هg.k~X8?75>$#(UO_Gפs,ܳ{ y(libgit2-0.19.0/tests-clar/resources/issue_1397/.gitted/objects/ff/000077500000000000000000000000001216214232500244235ustar00rootroot000000000000003578d64d199d5b48d92bbb569e0a273e411741000066400000000000000000000001111216214232500312640ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/issue_1397/.gitted/objects/ffx+)JMU4f040031QH.IOI+(ahz1kή5هg.k~X8?75>$#()libgit2-0.19.0/tests-clar/resources/issue_1397/.gitted/refs/000077500000000000000000000000001216214232500233365ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/issue_1397/.gitted/refs/heads/000077500000000000000000000000001216214232500244225ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/issue_1397/.gitted/refs/heads/master000066400000000000000000000000511216214232500256340ustar00rootroot000000000000007f483a738f867e5b21c8f377d70311f011eb48b5 libgit2-0.19.0/tests-clar/resources/issue_1397/crlf_file.txt000066400000000000000000000000471216214232500235300ustar00rootroot00000000000000first line second line both with crlflibgit2-0.19.0/tests-clar/resources/issue_1397/some_other_crlf_file.txt000066400000000000000000000000701216214232500257500ustar00rootroot00000000000000first line second line with some change both with crlflibgit2-0.19.0/tests-clar/resources/issue_592/000077500000000000000000000000001216214232500207555ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/issue_592/.gitted/000077500000000000000000000000001216214232500223135ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/issue_592/.gitted/COMMIT_EDITMSG000066400000000000000000000000171216214232500244000ustar00rootroot00000000000000Initial commit libgit2-0.19.0/tests-clar/resources/issue_592/.gitted/HEAD000066400000000000000000000000271216214232500227360ustar00rootroot00000000000000ref: refs/heads/master libgit2-0.19.0/tests-clar/resources/issue_592/.gitted/config000066400000000000000000000002351216214232500235030ustar00rootroot00000000000000[core] repositoryformatversion = 0 filemode = false bare = false logallrefupdates = true symlinks = false ignorecase = true hideDotFiles = dotGitOnly libgit2-0.19.0/tests-clar/resources/issue_592/.gitted/index000066400000000000000000000006101216214232500233420ustar00rootroot00000000000000DIRCO NO N c BoĹ lIKa.txtO NO N c BoĹ lIKc/a.txtO NO N c BoĹ lIKl.txtO NO N c BoĹ lIKt/a.txtO NO N c BoĹ lIKt/b.txt1nrr`0?zI`דlibgit2-0.19.0/tests-clar/resources/issue_592/.gitted/info/000077500000000000000000000000001216214232500232465ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/issue_592/.gitted/info/exclude000066400000000000000000000003601216214232500246210ustar00rootroot00000000000000# git ls-files --others --exclude-from=.git/info/exclude # Lines that start with '#' are comments. # For a project mostly in C, the following would be a good set of # exclude patterns (uncomment them if you want to use them): # *.[oa] # *~ libgit2-0.19.0/tests-clar/resources/issue_592/.gitted/logs/000077500000000000000000000000001216214232500232575ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/issue_592/.gitted/logs/HEAD000066400000000000000000000005161216214232500237050ustar00rootroot000000000000000000000000000000000000000000000000000000 4d383e87f0371ba8fa353f3912db6862b2625e85 nulltoken 1331989635 +0100 commit (initial): Initial commit 4d383e87f0371ba8fa353f3912db6862b2625e85 e38fcc7a6060f5eb5b876e836b52ae4769363f21 nulltoken 1332227062 +0100 commit (amend): Initial commit libgit2-0.19.0/tests-clar/resources/issue_592/.gitted/logs/refs/000077500000000000000000000000001216214232500242165ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/issue_592/.gitted/logs/refs/heads/000077500000000000000000000000001216214232500253025ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/issue_592/.gitted/logs/refs/heads/master000066400000000000000000000005161216214232500265220ustar00rootroot000000000000000000000000000000000000000000000000000000 4d383e87f0371ba8fa353f3912db6862b2625e85 nulltoken 1331989635 +0100 commit (initial): Initial commit 4d383e87f0371ba8fa353f3912db6862b2625e85 e38fcc7a6060f5eb5b876e836b52ae4769363f21 nulltoken 1332227062 +0100 commit (amend): Initial commit libgit2-0.19.0/tests-clar/resources/issue_592/.gitted/objects/000077500000000000000000000000001216214232500237445ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/issue_592/.gitted/objects/06/000077500000000000000000000000001216214232500241715ustar00rootroot0000000000000007ee9d4ccce8e4c4fa13c2c7d727e7faba4e0e000066400000000000000000000001271216214232500317660ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/issue_592/.gitted/objects/06x+)JMU042b040031QH+(a}iN)NGv>nb .Լkp7sYⓠsh.ĉ5 libgit2-0.19.0/tests-clar/resources/issue_592/.gitted/objects/49/000077500000000000000000000000001216214232500242005ustar00rootroot00000000000000363a72a90d9424240258cd3759f23788ecf1d8000066400000000000000000000000671216214232500307760ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/issue_592/.gitted/objects/49x+)JMU03c040031QH+(a}iN)NGv>US`libgit2-0.19.0/tests-clar/resources/issue_592/.gitted/objects/4d/000077500000000000000000000000001216214232500242535ustar00rootroot00000000000000383e87f0371ba8fa353f3912db6862b2625e85000066400000000000000000000002031216214232500311150ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/issue_592/.gitted/objects/4dxM 0]o/IDz bz H9v2t =k,p+͏>4U=^(tAF2̟3sL|%cYuZv{=r_G}K>libgit2-0.19.0/tests-clar/resources/issue_592/.gitted/objects/71/000077500000000000000000000000001216214232500241735ustar00rootroot0000000000000044be264b61825fbff68046fe999bdfe96a1792000066400000000000000000000000621216214232500313050ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/issue_592/.gitted/objects/71x+)JMU06f040031QH+(a}iN)NGv>galibgit2-0.19.0/tests-clar/resources/issue_592/.gitted/objects/be/000077500000000000000000000000001216214232500243325ustar00rootroot00000000000000de83ee10b5b3f00239660b00acec2d55fd0b84000066400000000000000000000001531216214232500315150ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/issue_592/.gitted/objects/bex+)JMU042b040031QH+(a}iN)NGv>nb .Լkp7sYⓠsh.a4*Z;EE)y'7oI3Llibgit2-0.19.0/tests-clar/resources/issue_592/.gitted/objects/e3/000077500000000000000000000000001216214232500242535ustar00rootroot000000000000008fcc7a6060f5eb5b876e836b52ae4769363f21000066400000000000000000000002111216214232500312620ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/issue_592/.gitted/objects/e3xI 1=}NbbD, f^ * t%rHb0AgDWk1 HQ%crNoV+uPYi6=/u]Aj-WZmQt2+hO^ ߎ=libgit2-0.19.0/tests-clar/resources/issue_592/.gitted/objects/f1/000077500000000000000000000000001216214232500242525ustar00rootroot00000000000000adef63cb08891a0942b76fc4b9c50c6c494bc7000066400000000000000000000000351216214232500314730ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/issue_592/.gitted/objects/f1xKOR04f/KWH-JL+libgit2-0.19.0/tests-clar/resources/issue_592/.gitted/refs/000077500000000000000000000000001216214232500232525ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/issue_592/.gitted/refs/heads/000077500000000000000000000000001216214232500243365ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/issue_592/.gitted/refs/heads/master000066400000000000000000000000511216214232500255500ustar00rootroot00000000000000e38fcc7a6060f5eb5b876e836b52ae4769363f21 libgit2-0.19.0/tests-clar/resources/issue_592/a.txt000066400000000000000000000000151216214232500217320ustar00rootroot00000000000000nothing here libgit2-0.19.0/tests-clar/resources/issue_592/c/000077500000000000000000000000001216214232500211775ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/issue_592/c/a.txt000066400000000000000000000000151216214232500221540ustar00rootroot00000000000000nothing here libgit2-0.19.0/tests-clar/resources/issue_592/l.txt000066400000000000000000000000151216214232500217450ustar00rootroot00000000000000nothing here libgit2-0.19.0/tests-clar/resources/issue_592/t/000077500000000000000000000000001216214232500212205ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/issue_592/t/a.txt000066400000000000000000000000151216214232500221750ustar00rootroot00000000000000nothing here libgit2-0.19.0/tests-clar/resources/issue_592/t/b.txt000066400000000000000000000000151216214232500221760ustar00rootroot00000000000000nothing here libgit2-0.19.0/tests-clar/resources/issue_592b/000077500000000000000000000000001216214232500211175ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/issue_592b/.gitted/000077500000000000000000000000001216214232500224555ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/issue_592b/.gitted/HEAD000066400000000000000000000000271216214232500231000ustar00rootroot00000000000000ref: refs/heads/master libgit2-0.19.0/tests-clar/resources/issue_592b/.gitted/config000066400000000000000000000001571216214232500236500ustar00rootroot00000000000000[core] repositoryformatversion = 0 filemode = true bare = false logallrefupdates = true ignorecase = true libgit2-0.19.0/tests-clar/resources/issue_592b/.gitted/description000066400000000000000000000001111216214232500247140ustar00rootroot00000000000000Unnamed repository; edit this file 'description' to name the repository. libgit2-0.19.0/tests-clar/resources/issue_592b/.gitted/index000066400000000000000000000005701216214232500235110ustar00rootroot00000000000000DIRCO$NO$Nt WMM,pթmR .gitignoreO#O#tjDUujChOignored/contained/tracked3.txtO$O$t ox>4ignored/tracked2.txtO$ O$ t ox>4 tracked1.txt !u#NYj]libgit2-0.19.0/tests-clar/resources/issue_592b/.gitted/info/000077500000000000000000000000001216214232500234105ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/issue_592b/.gitted/info/exclude000066400000000000000000000003601216214232500247630ustar00rootroot00000000000000# git ls-files --others --exclude-from=.git/info/exclude # Lines that start with '#' are comments. # For a project mostly in C, the following would be a good set of # exclude patterns (uncomment them if you want to use them): # *.[oa] # *~ libgit2-0.19.0/tests-clar/resources/issue_592b/.gitted/logs/000077500000000000000000000000001216214232500234215ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/issue_592b/.gitted/logs/HEAD000066400000000000000000000002431216214232500240440ustar00rootroot000000000000000000000000000000000000000000000000000000 3fbf1852f72fd268e36457b13a18cdd9a4c9ea35 Russell Belfer 1337205933 -0700 commit (initial): Initial commit libgit2-0.19.0/tests-clar/resources/issue_592b/.gitted/logs/refs/000077500000000000000000000000001216214232500243605ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/issue_592b/.gitted/logs/refs/heads/000077500000000000000000000000001216214232500254445ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/issue_592b/.gitted/logs/refs/heads/master000066400000000000000000000002431216214232500266610ustar00rootroot000000000000000000000000000000000000000000000000000000 3fbf1852f72fd268e36457b13a18cdd9a4c9ea35 Russell Belfer 1337205933 -0700 commit (initial): Initial commit libgit2-0.19.0/tests-clar/resources/issue_592b/.gitted/objects/000077500000000000000000000000001216214232500241065ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/issue_592b/.gitted/objects/3f/000077500000000000000000000000001216214232500244165ustar00rootroot00000000000000bf1852f72fd268e36457b13a18cdd9a4c9ea35000066400000000000000000000002021216214232500315550ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/issue_592b/.gitted/objects/3fxK 1]}%BwnAq xzVƃv ɂc&%9@9xdu.]".=EבO+ۘBEk\N_<>E U%9libgit2-0.19.0/tests-clar/resources/issue_592b/.gitted/objects/6f/000077500000000000000000000000001216214232500244215ustar00rootroot00000000000000a891d3e578c83e1c03bdb9e0fdd8e6e934157f000066400000000000000000000000341216214232500316550ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/issue_592b/.gitted/objects/6fxKOR04b/UNUMA!libgit2-0.19.0/tests-clar/resources/issue_592b/.gitted/objects/80/000077500000000000000000000000001216214232500243355ustar00rootroot0000000000000007d41d5794e6ce4d4d2c97e370d5a9aa6d5213000066400000000000000000000000301216214232500314070ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/issue_592b/.gitted/objects/80xKORdL/JM-jlibgit2-0.19.0/tests-clar/resources/issue_592b/.gitted/objects/a6/000077500000000000000000000000001216214232500244145ustar00rootroot000000000000005fb6583a7c425284142f285bc359a2d6565513000066400000000000000000000001351216214232500311150ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/issue_592b/.gitted/objects/a6x+)JMU07c01̼3yQk͝džf&& %E٩)Fz%% +&^~ZqNyo<{i"ZJg#zlibgit2-0.19.0/tests-clar/resources/issue_592b/.gitted/objects/ae/000077500000000000000000000000001216214232500244735ustar00rootroot00000000000000be7a55922c7097ef91ca3a7bc327a901d87c2c000066400000000000000000000001721216214232500316310ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/issue_592b/.gitted/objects/aex+)JMU044b040031QK,L/Jeh`">9__ \$lb ) EX8kD\t-,TjNIQbrvj^IE CVa޻^:/ libgit2-0.19.0/tests-clar/resources/issue_592b/.gitted/objects/b3/000077500000000000000000000000001216214232500244125ustar00rootroot0000000000000044b055867fcdc1f01eaa75056a43e868eb4fbc000066400000000000000000000000441216214232500316230ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/issue_592b/.gitted/objects/b3xKOR02`/UHLIIMQMUH̫/ #libgit2-0.19.0/tests-clar/resources/issue_592b/.gitted/objects/f7/000077500000000000000000000000001216214232500244225ustar00rootroot00000000000000d75fbfad8b1d2e307ced287ea78aad403cdce3000066400000000000000000000000711216214232500322070ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/issue_592b/.gitted/objects/f7x+)JMU01`040031Q()JLNM1+(a!rJY_d!libgit2-0.19.0/tests-clar/resources/issue_592b/.gitted/refs/000077500000000000000000000000001216214232500234145ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/issue_592b/.gitted/refs/heads/000077500000000000000000000000001216214232500245005ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/issue_592b/.gitted/refs/heads/master000066400000000000000000000000511216214232500257120ustar00rootroot000000000000003fbf1852f72fd268e36457b13a18cdd9a4c9ea35 libgit2-0.19.0/tests-clar/resources/issue_592b/gitignore000066400000000000000000000000111216214232500230210ustar00rootroot00000000000000ignored/ libgit2-0.19.0/tests-clar/resources/issue_592b/ignored/000077500000000000000000000000001216214232500225465ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/issue_592b/ignored/contained/000077500000000000000000000000001216214232500245125ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/issue_592b/ignored/contained/ignored3.txt000066400000000000000000000000141216214232500267600ustar00rootroot00000000000000I'm ignored libgit2-0.19.0/tests-clar/resources/issue_592b/ignored/contained/tracked3.txt000066400000000000000000000000241216214232500267470ustar00rootroot00000000000000You added me anyhow libgit2-0.19.0/tests-clar/resources/issue_592b/ignored/ignored2.txt000066400000000000000000000000141216214232500250130ustar00rootroot00000000000000I'm ignored libgit2-0.19.0/tests-clar/resources/issue_592b/ignored/tracked2.txt000066400000000000000000000000141216214232500250010ustar00rootroot00000000000000You like me libgit2-0.19.0/tests-clar/resources/issue_592b/ignored1.txt000066400000000000000000000000141216214232500233630ustar00rootroot00000000000000I'm ignored libgit2-0.19.0/tests-clar/resources/issue_592b/tracked1.txt000066400000000000000000000000141216214232500233510ustar00rootroot00000000000000You like me libgit2-0.19.0/tests-clar/resources/merge-resolve/000077500000000000000000000000001216214232500220025ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/000077500000000000000000000000001216214232500233405ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/COMMIT_EDITMSG000066400000000000000000000000271216214232500254260ustar00rootroot00000000000000rename conflict theirs libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/HEAD000066400000000000000000000000271216214232500237630ustar00rootroot00000000000000ref: refs/heads/master libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/ORIG_HEAD000066400000000000000000000000511216214232500246000ustar00rootroot000000000000002392a2dacc9efb562b8635d6579fb458751c7c5b libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/config000066400000000000000000000001571216214232500245330ustar00rootroot00000000000000[core] repositoryformatversion = 0 filemode = true bare = false logallrefupdates = true ignorecase = true libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/description000066400000000000000000000001111216214232500255770ustar00rootroot00000000000000Unnamed repository; edit this file 'description' to name the repository. libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/index000066400000000000000000000011601216214232500243700ustar00rootroot00000000000000DIRCQg*Qg*#< ɘ Koo5:q4added-in-master.txtQg*Qg*?  ed ,automergeable.txtQg*Qg*lDDKAk5>changed-in-branch.txtQg*Qg*ޫӦ9 -{fUchanged-in-master.txtQg*Qg**Nn`%)ʩcKѶconflicting.txtQg*Qg*+oTG0hkremoved-in-branch.txtQg*Qg*o.;Atg~<] unchanged.txt15FY;\libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/logs/000077500000000000000000000000001216214232500243045ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/logs/HEAD000066400000000000000000001237361216214232500247440ustar00rootroot000000000000000000000000000000000000000000000000000000 c607fc30883e335def28cd686b51f6cfa02b06ec Edward Thomson 1351563869 -0500 commit (initial): initial c607fc30883e335def28cd686b51f6cfa02b06ec c607fc30883e335def28cd686b51f6cfa02b06ec Edward Thomson 1351563886 -0500 checkout: moving from master to branch c607fc30883e335def28cd686b51f6cfa02b06ec 7cb63eed597130ba4abb87b3e544b85021905520 Edward Thomson 1351563965 -0500 commit: branch 7cb63eed597130ba4abb87b3e544b85021905520 c607fc30883e335def28cd686b51f6cfa02b06ec Edward Thomson 1351563968 -0500 checkout: moving from branch to master c607fc30883e335def28cd686b51f6cfa02b06ec 977c696519c5a3004c5f1d15d60c89dbeb8f235f Edward Thomson 1351564033 -0500 commit: master 977c696519c5a3004c5f1d15d60c89dbeb8f235f 977c696519c5a3004c5f1d15d60c89dbeb8f235f Edward Thomson 1351605785 -0500 checkout: moving from master to ff_branch 977c696519c5a3004c5f1d15d60c89dbeb8f235f 33d500f588fbbe65901d82b4e6b008e549064be0 Edward Thomson 1351605830 -0500 commit: fastforward 33d500f588fbbe65901d82b4e6b008e549064be0 977c696519c5a3004c5f1d15d60c89dbeb8f235f Edward Thomson 1351605889 -0500 checkout: moving from ff_branch to master 977c696519c5a3004c5f1d15d60c89dbeb8f235f 977c696519c5a3004c5f1d15d60c89dbeb8f235f Edward Thomson 1351874933 -0500 checkout: moving from master to octo1 977c696519c5a3004c5f1d15d60c89dbeb8f235f 16f825815cfd20a07a75c71554e82d8eede0b061 Edward Thomson 1351874954 -0500 commit: octo1 16f825815cfd20a07a75c71554e82d8eede0b061 977c696519c5a3004c5f1d15d60c89dbeb8f235f Edward Thomson 1351874957 -0500 checkout: moving from octo1 to master 977c696519c5a3004c5f1d15d60c89dbeb8f235f 977c696519c5a3004c5f1d15d60c89dbeb8f235f Edward Thomson 1351874960 -0500 checkout: moving from master to octo2 977c696519c5a3004c5f1d15d60c89dbeb8f235f 158dc7bedb202f5b26502bf3574faa7f4238d56c Edward Thomson 1351874974 -0500 commit: octo2 158dc7bedb202f5b26502bf3574faa7f4238d56c 977c696519c5a3004c5f1d15d60c89dbeb8f235f Edward Thomson 1351874976 -0500 checkout: moving from octo2 to master 977c696519c5a3004c5f1d15d60c89dbeb8f235f 977c696519c5a3004c5f1d15d60c89dbeb8f235f Edward Thomson 1351874980 -0500 checkout: moving from master to octo3 977c696519c5a3004c5f1d15d60c89dbeb8f235f 50ce7d7d01217679e26c55939eef119e0c93e272 Edward Thomson 1351874998 -0500 commit: octo3 50ce7d7d01217679e26c55939eef119e0c93e272 977c696519c5a3004c5f1d15d60c89dbeb8f235f Edward Thomson 1351875006 -0500 checkout: moving from octo3 to master 977c696519c5a3004c5f1d15d60c89dbeb8f235f 977c696519c5a3004c5f1d15d60c89dbeb8f235f Edward Thomson 1351875010 -0500 checkout: moving from master to octo4 977c696519c5a3004c5f1d15d60c89dbeb8f235f 54269b3f6ec3d7d4ede24dd350dd5d605495c3ae Edward Thomson 1351875023 -0500 commit: octo4 54269b3f6ec3d7d4ede24dd350dd5d605495c3ae 977c696519c5a3004c5f1d15d60c89dbeb8f235f Edward Thomson 1351875031 -0500 checkout: moving from octo4 to master 977c696519c5a3004c5f1d15d60c89dbeb8f235f 977c696519c5a3004c5f1d15d60c89dbeb8f235f Edward Thomson 1351875031 -0500 checkout: moving from master to octo5 977c696519c5a3004c5f1d15d60c89dbeb8f235f e4f618a2c3ed0669308735727df5ebf2447f022f Edward Thomson 1351875041 -0500 commit: octo5 e4f618a2c3ed0669308735727df5ebf2447f022f 977c696519c5a3004c5f1d15d60c89dbeb8f235f Edward Thomson 1351875046 -0500 checkout: moving from octo5 to master 977c696519c5a3004c5f1d15d60c89dbeb8f235f 977c696519c5a3004c5f1d15d60c89dbeb8f235f Edward Thomson 1351875046 -0500 checkout: moving from master to octo6 977c696519c5a3004c5f1d15d60c89dbeb8f235f 4ca408a8c88655f7586a1b580be6fad138121e98 Edward Thomson 1351875057 -0500 commit: octo5 4ca408a8c88655f7586a1b580be6fad138121e98 b6f610aef53bd343e6c96227de874c66f00ee8e8 Edward Thomson 1351875065 -0500 commit (amend): octo6 b6f610aef53bd343e6c96227de874c66f00ee8e8 977c696519c5a3004c5f1d15d60c89dbeb8f235f Edward Thomson 1351875071 -0500 checkout: moving from octo6 to master 977c696519c5a3004c5f1d15d60c89dbeb8f235f 4e0d9401aee78eb345a8685a859d37c8c3c0bbed Edward Thomson 1351875091 -0500 merge octo1 octo2 octo3 octo4: Merge made by the 'octopus' strategy. 4e0d9401aee78eb345a8685a859d37c8c3c0bbed 54269b3f6ec3d7d4ede24dd350dd5d605495c3ae Edward Thomson 1351875108 -0500 reset: moving to 54269b3f6ec3d7d4ede24dd350dd5d605495c3ae 54269b3f6ec3d7d4ede24dd350dd5d605495c3ae 977c696519c5a3004c5f1d15d60c89dbeb8f235f Edward Thomson 1351875584 -0500 reset: moving to 977c696519c5a3004c5f1d15d60c89dbeb8f235f bd593285fc7fe4ca18ccdbabf027f5d689101452 33d500f588fbbe65901d82b4e6b008e549064be0 Edward Thomson 1351990193 -0500 checkout: moving from master to ff_branch 33d500f588fbbe65901d82b4e6b008e549064be0 c607fc30883e335def28cd686b51f6cfa02b06ec Edward Thomson 1351990202 -0500 reset: moving to c607fc30883e335def28cd686b51f6cfa02b06ec c607fc30883e335def28cd686b51f6cfa02b06ec bd593285fc7fe4ca18ccdbabf027f5d689101452 Edward Thomson 1351990205 -0500 merge master: Fast-forward bd593285fc7fe4ca18ccdbabf027f5d689101452 fd89f8cffb663ac89095a0f9764902e93ceaca6a Edward Thomson 1351990229 -0500 commit: fastforward fd89f8cffb663ac89095a0f9764902e93ceaca6a bd593285fc7fe4ca18ccdbabf027f5d689101452 Edward Thomson 1351990233 -0500 checkout: moving from ff_branch to master bd593285fc7fe4ca18ccdbabf027f5d689101452 c607fc30883e335def28cd686b51f6cfa02b06ec Edward Thomson 1352091703 -0600 checkout: moving from master to trivial-2alt c607fc30883e335def28cd686b51f6cfa02b06ec c607fc30883e335def28cd686b51f6cfa02b06ec Edward Thomson 1352092411 -0600 checkout: moving from trivial-2alt to trivial-2alt-branch c607fc30883e335def28cd686b51f6cfa02b06ec c9174cef549ec94ecbc43ef03cdc775b4950becb Edward Thomson 1352092434 -0600 commit: 2alt-branch c9174cef549ec94ecbc43ef03cdc775b4950becb c607fc30883e335def28cd686b51f6cfa02b06ec Edward Thomson 1352092440 -0600 checkout: moving from trivial-2alt-branch to trivial-2alt c607fc30883e335def28cd686b51f6cfa02b06ec 566ab53c220a2eafc1212af1a024513230280ab9 Edward Thomson 1352092452 -0600 commit: 2alt bd593285fc7fe4ca18ccdbabf027f5d689101452 566ab53c220a2eafc1212af1a024513230280ab9 Edward Thomson 1352094476 -0600 checkout: moving from master to trivial-3alt 566ab53c220a2eafc1212af1a024513230280ab9 c607fc30883e335def28cd686b51f6cfa02b06ec Edward Thomson 1352094547 -0600 reset: moving to c607fc30883e335def28cd686b51f6cfa02b06ec c607fc30883e335def28cd686b51f6cfa02b06ec 5459c89aa0026d543ce8343bd89871bce543f9c2 Edward Thomson 1352094580 -0600 commit: 3alt 5459c89aa0026d543ce8343bd89871bce543f9c2 4c9fac0707f8d4195037ae5a681aa48626491541 Edward Thomson 1352094610 -0600 commit: 3alt-branch 4c9fac0707f8d4195037ae5a681aa48626491541 bd593285fc7fe4ca18ccdbabf027f5d689101452 Edward Thomson 1352094620 -0600 checkout: moving from trivial-3alt to master bd593285fc7fe4ca18ccdbabf027f5d689101452 566ab53c220a2eafc1212af1a024513230280ab9 Edward Thomson 1352094752 -0600 checkout: moving from master to trivial-4 566ab53c220a2eafc1212af1a024513230280ab9 c607fc30883e335def28cd686b51f6cfa02b06ec Edward Thomson 1352094764 -0600 reset: moving to c607fc30883e335def28cd686b51f6cfa02b06ec c607fc30883e335def28cd686b51f6cfa02b06ec cc3e3009134cb88014129fc8858d1101359e5e2f Edward Thomson 1352094815 -0600 commit: trivial-4 cc3e3009134cb88014129fc8858d1101359e5e2f c607fc30883e335def28cd686b51f6cfa02b06ec Edward Thomson 1352094843 -0600 checkout: moving from trivial-4 to trivial-4-branch c607fc30883e335def28cd686b51f6cfa02b06ec 183310e30fb1499af8c619108ffea4d300b5e778 Edward Thomson 1352094856 -0600 commit: trivial-4-branch 183310e30fb1499af8c619108ffea4d300b5e778 bd593285fc7fe4ca18ccdbabf027f5d689101452 Edward Thomson 1352094860 -0600 checkout: moving from trivial-4-branch to master bd593285fc7fe4ca18ccdbabf027f5d689101452 cc3e3009134cb88014129fc8858d1101359e5e2f Edward Thomson 1352096588 -0600 checkout: moving from master to trivial-4 cc3e3009134cb88014129fc8858d1101359e5e2f c607fc30883e335def28cd686b51f6cfa02b06ec Edward Thomson 1352096612 -0600 checkout: moving from trivial-4 to trivial-5alt-1 c607fc30883e335def28cd686b51f6cfa02b06ec 4fe93c0ec83eb6305cbace3dace88ecee1b63cb6 Edward Thomson 1352096643 -0600 commit: 5alt-1 4fe93c0ec83eb6305cbace3dace88ecee1b63cb6 c607fc30883e335def28cd686b51f6cfa02b06ec Edward Thomson 1352096661 -0600 checkout: moving from trivial-5alt-1 to trivial-5alt-1-branch c607fc30883e335def28cd686b51f6cfa02b06ec 4fe93c0ec83eb6305cbace3dace88ecee1b63cb6 Edward Thomson 1352096671 -0600 checkout: moving from trivial-5alt-1-branch to trivial-5alt-1 4fe93c0ec83eb6305cbace3dace88ecee1b63cb6 c607fc30883e335def28cd686b51f6cfa02b06ec Edward Thomson 1352096678 -0600 checkout: moving from trivial-5alt-1 to trivial-5alt-1-branch c607fc30883e335def28cd686b51f6cfa02b06ec 478172cb2f5ff9b514bc9d04d3bd5ef5840cb3b2 Edward Thomson 1352096689 -0600 commit: 5alt-1-branch 478172cb2f5ff9b514bc9d04d3bd5ef5840cb3b2 4fe93c0ec83eb6305cbace3dace88ecee1b63cb6 Edward Thomson 1352096701 -0600 checkout: moving from trivial-5alt-1-branch to trivial-5alt-1 4fe93c0ec83eb6305cbace3dace88ecee1b63cb6 c607fc30883e335def28cd686b51f6cfa02b06ec Edward Thomson 1352096715 -0600 checkout: moving from trivial-5alt-1 to trivial-5alt-2 c607fc30883e335def28cd686b51f6cfa02b06ec ebc09d0137cfb0c26697aed0109fb943ad906f3f Edward Thomson 1352096764 -0600 commit: existing file ebc09d0137cfb0c26697aed0109fb943ad906f3f 3b47b031b3e55ae11e14a05260b1c3ffd6838d55 Edward Thomson 1352096815 -0600 commit: 5alt-2 3b47b031b3e55ae11e14a05260b1c3ffd6838d55 ebc09d0137cfb0c26697aed0109fb943ad906f3f Edward Thomson 1352096840 -0600 checkout: moving from trivial-5alt-2 to trivial-5alt-2-branch ebc09d0137cfb0c26697aed0109fb943ad906f3f f48097eb340dc5a7cae55aabcf1faf4548aa821f Edward Thomson 1352096855 -0600 commit: 5alt-2-branch f48097eb340dc5a7cae55aabcf1faf4548aa821f bd593285fc7fe4ca18ccdbabf027f5d689101452 Edward Thomson 1352096858 -0600 checkout: moving from trivial-5alt-2-branch to master bd593285fc7fe4ca18ccdbabf027f5d689101452 c607fc30883e335def28cd686b51f6cfa02b06ec Edward Thomson 1352097377 -0600 checkout: moving from master to trivial-6 c607fc30883e335def28cd686b51f6cfa02b06ec f7c332bd4d4d4b777366cae4d24d1687477576bf Edward Thomson 1352097389 -0600 commit: 6 f7c332bd4d4d4b777366cae4d24d1687477576bf 99b4f7e4f24470fa06b980bc21f1095c2a9425c0 Edward Thomson 1352097404 -0600 commit: trivial-6 99b4f7e4f24470fa06b980bc21f1095c2a9425c0 f7c332bd4d4d4b777366cae4d24d1687477576bf Edward Thomson 1352097420 -0600 checkout: moving from trivial-6 to trivial-6-branch f7c332bd4d4d4b777366cae4d24d1687477576bf a43150a738849c59376cf30bb2a68348a83c8f48 Edward Thomson 1352097431 -0600 commit: 6-branch a43150a738849c59376cf30bb2a68348a83c8f48 bd593285fc7fe4ca18ccdbabf027f5d689101452 Edward Thomson 1352097442 -0600 checkout: moving from trivial-6-branch to master bd593285fc7fe4ca18ccdbabf027f5d689101452 99b4f7e4f24470fa06b980bc21f1095c2a9425c0 Edward Thomson 1352098040 -0600 checkout: moving from master to trivial-6 99b4f7e4f24470fa06b980bc21f1095c2a9425c0 bd593285fc7fe4ca18ccdbabf027f5d689101452 Edward Thomson 1352098057 -0600 checkout: moving from trivial-6 to master bd593285fc7fe4ca18ccdbabf027f5d689101452 cc3e3009134cb88014129fc8858d1101359e5e2f Edward Thomson 1352098792 -0600 checkout: moving from master to trivial-4 cc3e3009134cb88014129fc8858d1101359e5e2f c607fc30883e335def28cd686b51f6cfa02b06ec Edward Thomson 1352098818 -0600 checkout: moving from trivial-4 to trivial-8 c607fc30883e335def28cd686b51f6cfa02b06ec 75a811bf6bc57694adb3fe604786f3a4efd1cd1b Edward Thomson 1352098884 -0600 commit: trivial-8 75a811bf6bc57694adb3fe604786f3a4efd1cd1b 75a811bf6bc57694adb3fe604786f3a4efd1cd1b Edward Thomson 1352098947 -0600 checkout: moving from trivial-8 to trivial-8-branch 75a811bf6bc57694adb3fe604786f3a4efd1cd1b 52d8bc572af2b6d4ee0d5e62ed5d1fbad92210a9 Edward Thomson 1352098979 -0600 commit: trivial-8-branch 52d8bc572af2b6d4ee0d5e62ed5d1fbad92210a9 75a811bf6bc57694adb3fe604786f3a4efd1cd1b Edward Thomson 1352098982 -0600 checkout: moving from trivial-8-branch to trivial-8 75a811bf6bc57694adb3fe604786f3a4efd1cd1b 3575826c96a975031d2c14368529cc5c4353a8fd Edward Thomson 1352099000 -0600 commit: trivial-8 3575826c96a975031d2c14368529cc5c4353a8fd bd593285fc7fe4ca18ccdbabf027f5d689101452 Edward Thomson 1352099008 -0600 checkout: moving from trivial-8 to master bd593285fc7fe4ca18ccdbabf027f5d689101452 c607fc30883e335def28cd686b51f6cfa02b06ec Edward Thomson 1352099776 -0600 checkout: moving from master to trivial-7 c607fc30883e335def28cd686b51f6cfa02b06ec 092ce8682d7f3a2a3a769a6daca58950168ba5c4 Edward Thomson 1352099790 -0600 commit: trivial-7 092ce8682d7f3a2a3a769a6daca58950168ba5c4 092ce8682d7f3a2a3a769a6daca58950168ba5c4 Edward Thomson 1352099799 -0600 checkout: moving from trivial-7 to trivial-7-branch 092ce8682d7f3a2a3a769a6daca58950168ba5c4 73cbfdc4fe843169e5b2af8dcad03cbf3acf306c Edward Thomson 1352099812 -0600 commit: trivial-7-branch 73cbfdc4fe843169e5b2af8dcad03cbf3acf306c 092ce8682d7f3a2a3a769a6daca58950168ba5c4 Edward Thomson 1352099815 -0600 checkout: moving from trivial-7-branch to trivial-7 092ce8682d7f3a2a3a769a6daca58950168ba5c4 73cbfdc4fe843169e5b2af8dcad03cbf3acf306c Edward Thomson 1352099838 -0600 checkout: moving from trivial-7 to trivial-7-branch 73cbfdc4fe843169e5b2af8dcad03cbf3acf306c 092ce8682d7f3a2a3a769a6daca58950168ba5c4 Edward Thomson 1352099874 -0600 reset: moving to 092ce8682d7f3a2a3a769a6daca58950168ba5c4 092ce8682d7f3a2a3a769a6daca58950168ba5c4 009b9cab6fdac02915a88ecd078b7a792ed802d8 Edward Thomson 1352099921 -0600 commit: removed in 7 009b9cab6fdac02915a88ecd078b7a792ed802d8 5195a1b480f66691b667f10a9e41e70115a78351 Edward Thomson 1352099927 -0600 commit (amend): trivial-7-branch 5195a1b480f66691b667f10a9e41e70115a78351 092ce8682d7f3a2a3a769a6daca58950168ba5c4 Edward Thomson 1352099937 -0600 checkout: moving from trivial-7-branch to trivial-7 092ce8682d7f3a2a3a769a6daca58950168ba5c4 d874671ef5b20184836cb983bb273e5280384d0b Edward Thomson 1352099947 -0600 commit: trivial-7 d874671ef5b20184836cb983bb273e5280384d0b bd593285fc7fe4ca18ccdbabf027f5d689101452 Edward Thomson 1352099949 -0600 checkout: moving from trivial-7 to master bd593285fc7fe4ca18ccdbabf027f5d689101452 c607fc30883e335def28cd686b51f6cfa02b06ec Edward Thomson 1352100174 -0600 checkout: moving from master to trivial-10 c607fc30883e335def28cd686b51f6cfa02b06ec 53825f41ac8d640612f9423a2f03a69f3d96809a Edward Thomson 1352100193 -0600 commit: trivial-10 53825f41ac8d640612f9423a2f03a69f3d96809a 53825f41ac8d640612f9423a2f03a69f3d96809a Edward Thomson 1352100200 -0600 checkout: moving from trivial-10 to trivial-10-branch 53825f41ac8d640612f9423a2f03a69f3d96809a 11f4f3c08b737f5fd896cbefa1425ee63b21b2fa Edward Thomson 1352100211 -0600 commit: trivial-10-branch 11f4f3c08b737f5fd896cbefa1425ee63b21b2fa 53825f41ac8d640612f9423a2f03a69f3d96809a Edward Thomson 1352100214 -0600 checkout: moving from trivial-10-branch to trivial-10 53825f41ac8d640612f9423a2f03a69f3d96809a 0ec5f433959cd46177f745903353efb5be08d151 Edward Thomson 1352100223 -0600 commit: trivial-10 0ec5f433959cd46177f745903353efb5be08d151 bd593285fc7fe4ca18ccdbabf027f5d689101452 Edward Thomson 1352100225 -0600 checkout: moving from trivial-10 to master bd593285fc7fe4ca18ccdbabf027f5d689101452 c607fc30883e335def28cd686b51f6cfa02b06ec Edward Thomson 1352100270 -0600 checkout: moving from master to trivial-9 c607fc30883e335def28cd686b51f6cfa02b06ec f0053b8060bb3f0be5cbcc3147a07ece26bf097e Edward Thomson 1352100304 -0600 commit: trivial-9 f0053b8060bb3f0be5cbcc3147a07ece26bf097e f0053b8060bb3f0be5cbcc3147a07ece26bf097e Edward Thomson 1352100310 -0600 checkout: moving from trivial-9 to trivial-9-branch f0053b8060bb3f0be5cbcc3147a07ece26bf097e 13d1be4ea52a6ced1d7a1d832f0ee3c399348e5e Edward Thomson 1352100317 -0600 commit: trivial-9-branch 13d1be4ea52a6ced1d7a1d832f0ee3c399348e5e f0053b8060bb3f0be5cbcc3147a07ece26bf097e Edward Thomson 1352100319 -0600 checkout: moving from trivial-9-branch to trivial-9 f0053b8060bb3f0be5cbcc3147a07ece26bf097e c35dee9bcc0e989f3b0c40f68372a9a51b6c4e6a Edward Thomson 1352100333 -0600 commit: trivial-9 c35dee9bcc0e989f3b0c40f68372a9a51b6c4e6a bd593285fc7fe4ca18ccdbabf027f5d689101452 Edward Thomson 1352100335 -0600 checkout: moving from trivial-9 to master bd593285fc7fe4ca18ccdbabf027f5d689101452 c607fc30883e335def28cd686b51f6cfa02b06ec Edward Thomson 1352100576 -0600 checkout: moving from master to trivial-13 c607fc30883e335def28cd686b51f6cfa02b06ec 8f4433f8593ddd65b7dd43dd4564d841f4d9c8aa Edward Thomson 1352100589 -0600 commit: trivial-13 8f4433f8593ddd65b7dd43dd4564d841f4d9c8aa 8f4433f8593ddd65b7dd43dd4564d841f4d9c8aa Edward Thomson 1352100604 -0600 checkout: moving from trivial-13 to trivial-13-branch 8f4433f8593ddd65b7dd43dd4564d841f4d9c8aa 05f3c1a2a56ca95c3d2ef28dc9ddf32b5cd6c91c Edward Thomson 1352100610 -0600 commit: trivial-13-branch 05f3c1a2a56ca95c3d2ef28dc9ddf32b5cd6c91c 8f4433f8593ddd65b7dd43dd4564d841f4d9c8aa Edward Thomson 1352100612 -0600 checkout: moving from trivial-13-branch to trivial-13 8f4433f8593ddd65b7dd43dd4564d841f4d9c8aa a3fabece9eb8748da810e1e08266fef9b7136ad4 Edward Thomson 1352100625 -0600 commit: trivial-13 a3fabece9eb8748da810e1e08266fef9b7136ad4 bd593285fc7fe4ca18ccdbabf027f5d689101452 Edward Thomson 1352100627 -0600 checkout: moving from trivial-13 to master bd593285fc7fe4ca18ccdbabf027f5d689101452 c607fc30883e335def28cd686b51f6cfa02b06ec Edward Thomson 1352100936 -0600 checkout: moving from master to trivial-11 c607fc30883e335def28cd686b51f6cfa02b06ec 35632e43612c06a3ea924bfbacd48333da874c29 Edward Thomson 1352100958 -0600 commit: trivial-11 35632e43612c06a3ea924bfbacd48333da874c29 35632e43612c06a3ea924bfbacd48333da874c29 Edward Thomson 1352100964 -0600 checkout: moving from trivial-11 to trivial-11-branch 35632e43612c06a3ea924bfbacd48333da874c29 6718a45909532d1fcf5600d0877f7fe7e78f0b86 Edward Thomson 1352100978 -0600 commit: trivial-11-branch 6718a45909532d1fcf5600d0877f7fe7e78f0b86 35632e43612c06a3ea924bfbacd48333da874c29 Edward Thomson 1352100981 -0600 checkout: moving from trivial-11-branch to trivial-11 35632e43612c06a3ea924bfbacd48333da874c29 3168dca1a561889b045a6441909f4c56145e666d Edward Thomson 1352100992 -0600 commit: trivial-11 3168dca1a561889b045a6441909f4c56145e666d bd593285fc7fe4ca18ccdbabf027f5d689101452 Edward Thomson 1352100996 -0600 checkout: moving from trivial-11 to master bd593285fc7fe4ca18ccdbabf027f5d689101452 c607fc30883e335def28cd686b51f6cfa02b06ec Edward Thomson 1352101098 -0600 checkout: moving from master to trivial-14 c607fc30883e335def28cd686b51f6cfa02b06ec 596803b523203a4851c824c07366906f8353f4ad Edward Thomson 1352101113 -0600 commit: trivial-14 596803b523203a4851c824c07366906f8353f4ad 596803b523203a4851c824c07366906f8353f4ad Edward Thomson 1352101117 -0600 checkout: moving from trivial-14 to trivial-14-branch 596803b523203a4851c824c07366906f8353f4ad 8187117062b750eed4f93fd7e899f17b52ce554d Edward Thomson 1352101132 -0600 commit: trivial-14-branch 8187117062b750eed4f93fd7e899f17b52ce554d 596803b523203a4851c824c07366906f8353f4ad Edward Thomson 1352101135 -0600 checkout: moving from trivial-14-branch to trivial-14 596803b523203a4851c824c07366906f8353f4ad 7e2d058d5fedf8329db44db4fac610d6b1a89159 Edward Thomson 1352101141 -0600 commit: trivial-14 7e2d058d5fedf8329db44db4fac610d6b1a89159 bd593285fc7fe4ca18ccdbabf027f5d689101452 Edward Thomson 1352101145 -0600 checkout: moving from trivial-14 to master bd593285fc7fe4ca18ccdbabf027f5d689101452 c607fc30883e335def28cd686b51f6cfa02b06ec Edward Thomson 1353177749 -0600 checkout: moving from master to renames1 c607fc30883e335def28cd686b51f6cfa02b06ec 412b32fb66137366147f1801ecc962452757d48a Edward Thomson 1353177886 -0600 commit: renames 412b32fb66137366147f1801ecc962452757d48a bd593285fc7fe4ca18ccdbabf027f5d689101452 Edward Thomson 1353794607 -0600 checkout: moving from renames1 to master bd593285fc7fe4ca18ccdbabf027f5d689101452 bd593285fc7fe4ca18ccdbabf027f5d689101452 Edward Thomson 1353794647 -0600 checkout: moving from master to renames2 bd593285fc7fe4ca18ccdbabf027f5d689101452 c607fc30883e335def28cd686b51f6cfa02b06ec Edward Thomson 1353794677 -0600 reset: moving to c607fc30883e335def28cd686b51f6cfa02b06ec c607fc30883e335def28cd686b51f6cfa02b06ec ab40af3cb8a3ed2e2843e96d9aa7871336b94573 Edward Thomson 1353794852 -0600 commit: renames2 ab40af3cb8a3ed2e2843e96d9aa7871336b94573 bd593285fc7fe4ca18ccdbabf027f5d689101452 Edward Thomson 1353794883 -0600 checkout: moving from renames2 to master bd593285fc7fe4ca18ccdbabf027f5d689101452 bd593285fc7fe4ca18ccdbabf027f5d689101452 Edward Thomson 1354574697 -0600 checkout: moving from master to df_side1 bd593285fc7fe4ca18ccdbabf027f5d689101452 d4207f77243500bec335ab477f9227fcdb1e271a Edward Thomson 1354574962 -0600 commit: df_ancestor d4207f77243500bec335ab477f9227fcdb1e271a c94b27e41064c521120627e07e2035cca1d24ffa Edward Thomson 1354575027 -0600 commit: df_side1 c94b27e41064c521120627e07e2035cca1d24ffa d4207f77243500bec335ab477f9227fcdb1e271a Edward Thomson 1354575070 -0600 checkout: moving from df_side1 to df_side2 d4207f77243500bec335ab477f9227fcdb1e271a f8958bdf4d365a84a9a178b1f5f35ff1dacbd884 Edward Thomson 1354575206 -0600 commit: df_side2 f8958bdf4d365a84a9a178b1f5f35ff1dacbd884 bd593285fc7fe4ca18ccdbabf027f5d689101452 Edward Thomson 1354575381 -0600 checkout: moving from df_side2 to master bd593285fc7fe4ca18ccdbabf027f5d689101452 c94b27e41064c521120627e07e2035cca1d24ffa Edward Thomson 1355017614 -0600 checkout: moving from master to df_side1 c94b27e41064c521120627e07e2035cca1d24ffa a90bc3fb6f15181972a2959a921429efbd81a473 Edward Thomson 1355017650 -0600 commit: df_added a90bc3fb6f15181972a2959a921429efbd81a473 c94b27e41064c521120627e07e2035cca1d24ffa Edward Thomson 1355017673 -0600 checkout: moving from df_side1 to c94b27e c94b27e41064c521120627e07e2035cca1d24ffa d4207f77243500bec335ab477f9227fcdb1e271a Edward Thomson 1355017673 -0600 rebase -i (squash): updating HEAD d4207f77243500bec335ab477f9227fcdb1e271a 005b6fcc8fec71d2550bef8462d169b3c26aa14b Edward Thomson 1355017673 -0600 rebase -i (squash): df_side1 005b6fcc8fec71d2550bef8462d169b3c26aa14b 005b6fcc8fec71d2550bef8462d169b3c26aa14b Edward Thomson 1355017676 -0600 rebase -i (finish): returning to refs/heads/df_side1 005b6fcc8fec71d2550bef8462d169b3c26aa14b f8958bdf4d365a84a9a178b1f5f35ff1dacbd884 Edward Thomson 1355017715 -0600 reset: moving to df_side2 f8958bdf4d365a84a9a178b1f5f35ff1dacbd884 8c749d9968d4b10dcfb06c9f97d0e5d92d337071 Edward Thomson 1355017744 -0600 commit: df_added 8c749d9968d4b10dcfb06c9f97d0e5d92d337071 f8958bdf4d365a84a9a178b1f5f35ff1dacbd884 Edward Thomson 1355017754 -0600 checkout: moving from df_side1 to f8958bd f8958bdf4d365a84a9a178b1f5f35ff1dacbd884 d4207f77243500bec335ab477f9227fcdb1e271a Edward Thomson 1355017754 -0600 rebase -i (squash): updating HEAD d4207f77243500bec335ab477f9227fcdb1e271a 0204a84f822acbf6386b36d33f1f6bc68bbbf858 Edward Thomson 1355017754 -0600 rebase -i (squash): df_side2 0204a84f822acbf6386b36d33f1f6bc68bbbf858 0204a84f822acbf6386b36d33f1f6bc68bbbf858 Edward Thomson 1355017756 -0600 rebase -i (finish): returning to refs/heads/df_side1 0204a84f822acbf6386b36d33f1f6bc68bbbf858 005b6fcc8fec71d2550bef8462d169b3c26aa14b Edward Thomson 1355017793 -0600 reset: moving to 005b6fcc8fec71d2550bef8462d169b3c26aa14b 005b6fcc8fec71d2550bef8462d169b3c26aa14b 0204a84f822acbf6386b36d33f1f6bc68bbbf858 Edward Thomson 1355017826 -0600 reset: moving to 0204a84 0204a84f822acbf6386b36d33f1f6bc68bbbf858 bd593285fc7fe4ca18ccdbabf027f5d689101452 Edward Thomson 1355017847 -0600 checkout: moving from df_side1 to master bd593285fc7fe4ca18ccdbabf027f5d689101452 0204a84f822acbf6386b36d33f1f6bc68bbbf858 Edward Thomson 1355168677 -0600 checkout: moving from master to df_side1 005b6fcc8fec71d2550bef8462d169b3c26aa14b 005b6fcc8fec71d2550bef8462d169b3c26aa14b Edward Thomson 1355168829 -0600 checkout: moving from df_side1 to df_side1 005b6fcc8fec71d2550bef8462d169b3c26aa14b 005b6fcc8fec71d2550bef8462d169b3c26aa14b Edward Thomson 1355168838 -0600 checkout: moving from df_side1 to df_side1 005b6fcc8fec71d2550bef8462d169b3c26aa14b e8107f24196736b870a318a0e28f048e29f6feff Edward Thomson 1355169065 -0600 commit: df_side1 e8107f24196736b870a318a0e28f048e29f6feff 005b6fcc8fec71d2550bef8462d169b3c26aa14b Edward Thomson 1355169081 -0600 checkout: moving from df_side1 to 005b6fc 005b6fcc8fec71d2550bef8462d169b3c26aa14b d4207f77243500bec335ab477f9227fcdb1e271a Edward Thomson 1355169081 -0600 rebase -i (squash): updating HEAD d4207f77243500bec335ab477f9227fcdb1e271a 80a8fbb3abb1ba423d554e9630b8fc2e5698f86b Edward Thomson 1355169081 -0600 rebase -i (squash): df_side1 80a8fbb3abb1ba423d554e9630b8fc2e5698f86b 80a8fbb3abb1ba423d554e9630b8fc2e5698f86b Edward Thomson 1355169084 -0600 rebase -i (finish): returning to refs/heads/df_side1 80a8fbb3abb1ba423d554e9630b8fc2e5698f86b 0204a84f822acbf6386b36d33f1f6bc68bbbf858 Edward Thomson 1355169141 -0600 checkout: moving from df_side1 to df_side2 0204a84f822acbf6386b36d33f1f6bc68bbbf858 944f5dd1a867cab4c2bbcb896493435cae1dcc1a Edward Thomson 1355169174 -0600 commit: both 944f5dd1a867cab4c2bbcb896493435cae1dcc1a 0204a84f822acbf6386b36d33f1f6bc68bbbf858 Edward Thomson 1355169182 -0600 checkout: moving from df_side2 to 0204a84 0204a84f822acbf6386b36d33f1f6bc68bbbf858 d4207f77243500bec335ab477f9227fcdb1e271a Edward Thomson 1355169182 -0600 rebase -i (squash): updating HEAD d4207f77243500bec335ab477f9227fcdb1e271a 57079a46233ae2b6df62e9ade71c4948512abefb Edward Thomson 1355169182 -0600 rebase -i (squash): df_side2 57079a46233ae2b6df62e9ade71c4948512abefb 57079a46233ae2b6df62e9ade71c4948512abefb Edward Thomson 1355169185 -0600 rebase -i (finish): returning to refs/heads/df_side2 57079a46233ae2b6df62e9ade71c4948512abefb 80a8fbb3abb1ba423d554e9630b8fc2e5698f86b Edward Thomson 1355169241 -0600 checkout: moving from df_side2 to df_side1 80a8fbb3abb1ba423d554e9630b8fc2e5698f86b e65a9bb2af9f4c2d1c375dd0f8f8a46cf9c68812 Edward Thomson 1355169419 -0600 commit: side1 e65a9bb2af9f4c2d1c375dd0f8f8a46cf9c68812 80a8fbb3abb1ba423d554e9630b8fc2e5698f86b Edward Thomson 1355169431 -0600 checkout: moving from df_side1 to 80a8fbb 80a8fbb3abb1ba423d554e9630b8fc2e5698f86b d4207f77243500bec335ab477f9227fcdb1e271a Edward Thomson 1355169431 -0600 rebase -i (squash): updating HEAD d4207f77243500bec335ab477f9227fcdb1e271a 5dc1018e90b19654bee986b7a0c268804d39659d Edward Thomson 1355169431 -0600 rebase -i (squash): df_side1 5dc1018e90b19654bee986b7a0c268804d39659d 5dc1018e90b19654bee986b7a0c268804d39659d Edward Thomson 1355169435 -0600 rebase -i (finish): returning to refs/heads/df_side1 5dc1018e90b19654bee986b7a0c268804d39659d 57079a46233ae2b6df62e9ade71c4948512abefb Edward Thomson 1355169439 -0600 checkout: moving from df_side1 to df_side2 57079a46233ae2b6df62e9ade71c4948512abefb 58e853f66699fd02629fd50bde08082bc005933a Edward Thomson 1355169460 -0600 commit: side2 58e853f66699fd02629fd50bde08082bc005933a 57079a46233ae2b6df62e9ade71c4948512abefb Edward Thomson 1355169469 -0600 checkout: moving from df_side2 to 57079a4 57079a46233ae2b6df62e9ade71c4948512abefb d4207f77243500bec335ab477f9227fcdb1e271a Edward Thomson 1355169469 -0600 rebase -i (squash): updating HEAD d4207f77243500bec335ab477f9227fcdb1e271a fada9356aa3f74622327a3038ae9c6f92e1c5c1d Edward Thomson 1355169469 -0600 rebase -i (squash): df_side2 fada9356aa3f74622327a3038ae9c6f92e1c5c1d fada9356aa3f74622327a3038ae9c6f92e1c5c1d Edward Thomson 1355169471 -0600 rebase -i (finish): returning to refs/heads/df_side2 fada9356aa3f74622327a3038ae9c6f92e1c5c1d 5dc1018e90b19654bee986b7a0c268804d39659d Edward Thomson 1355169494 -0600 checkout: moving from df_side2 to df_side1 5dc1018e90b19654bee986b7a0c268804d39659d d4207f77243500bec335ab477f9227fcdb1e271a Edward Thomson 1355169663 -0600 checkout: moving from df_side1 to d4207f77243500bec335ab477f9227fcdb1e271a d4207f77243500bec335ab477f9227fcdb1e271a 849619b03ae540acee4d1edec96b86993da6b497 Edward Thomson 1355169683 -0600 commit: both_dirs 849619b03ae540acee4d1edec96b86993da6b497 d4207f77243500bec335ab477f9227fcdb1e271a Edward Thomson 1355169691 -0600 checkout: moving from 849619b03ae540acee4d1edec96b86993da6b497 to d4207f7 d4207f77243500bec335ab477f9227fcdb1e271a bd593285fc7fe4ca18ccdbabf027f5d689101452 Edward Thomson 1355169691 -0600 rebase -i (squash): updating HEAD bd593285fc7fe4ca18ccdbabf027f5d689101452 a765fb87eb2f7a1920b73b2d5a057f8f8476a42b Edward Thomson 1355169691 -0600 rebase -i (squash): df_ancestor a765fb87eb2f7a1920b73b2d5a057f8f8476a42b 5dc1018e90b19654bee986b7a0c268804d39659d Edward Thomson 1355169706 -0600 checkout: moving from a765fb87eb2f7a1920b73b2d5a057f8f8476a42b to df_side1 5dc1018e90b19654bee986b7a0c268804d39659d a765fb87eb2f7a1920b73b2d5a057f8f8476a42b Edward Thomson 1355169715 -0600 checkout: moving from df_side1 to a765fb87eb2f7a1920b73b2d5a057f8f8476a42b^0 a765fb87eb2f7a1920b73b2d5a057f8f8476a42b bc744705e1d8a019993cf88f62bc4020f1b80919 Edward Thomson 1355169801 -0600 commit: df_side1 bc744705e1d8a019993cf88f62bc4020f1b80919 bc744705e1d8a019993cf88f62bc4020f1b80919 Edward Thomson 1355169822 -0600 checkout: moving from bc744705e1d8a019993cf88f62bc4020f1b80919 to df_side1 bc744705e1d8a019993cf88f62bc4020f1b80919 fada9356aa3f74622327a3038ae9c6f92e1c5c1d Edward Thomson 1355169826 -0600 checkout: moving from df_side1 to df_side2 fada9356aa3f74622327a3038ae9c6f92e1c5c1d a765fb87eb2f7a1920b73b2d5a057f8f8476a42b Edward Thomson 1355169866 -0600 checkout: moving from df_side2 to a765fb87eb2f7a1920b73b2d5a057f8f8476a42b^0 a765fb87eb2f7a1920b73b2d5a057f8f8476a42b 95646149ab6b6ba6edc83cff678582538b457b2b Edward Thomson 1355169897 -0600 rebase: df_side2 95646149ab6b6ba6edc83cff678582538b457b2b 95646149ab6b6ba6edc83cff678582538b457b2b Edward Thomson 1355169897 -0600 rebase finished: returning to refs/heads/df_side2 95646149ab6b6ba6edc83cff678582538b457b2b bc744705e1d8a019993cf88f62bc4020f1b80919 Edward Thomson 1355169949 -0600 checkout: moving from df_side2 to df_side1 bc744705e1d8a019993cf88f62bc4020f1b80919 bd593285fc7fe4ca18ccdbabf027f5d689101452 Edward Thomson 1355170046 -0600 checkout: moving from df_side1 to master bd593285fc7fe4ca18ccdbabf027f5d689101452 bd593285fc7fe4ca18ccdbabf027f5d689101452 Edward Thomson 1355181639 -0600 checkout: moving from master to df_ancestor bd593285fc7fe4ca18ccdbabf027f5d689101452 2da538570bc1e5b2c3e855bf702f35248ad0735f Edward Thomson 1355181673 -0600 commit: df_ancestor 2da538570bc1e5b2c3e855bf702f35248ad0735f a7dbfcbfc1a60709cb80b5ca24539008456531d0 Edward Thomson 1355181715 -0600 commit: df_side1 a7dbfcbfc1a60709cb80b5ca24539008456531d0 a7dbfcbfc1a60709cb80b5ca24539008456531d0 Edward Thomson 1355181743 -0600 checkout: moving from df_ancestor to df_ancestor a7dbfcbfc1a60709cb80b5ca24539008456531d0 9a301fbe6fada7dcb74fcd7c20269b5c743459a7 Edward Thomson 1355181775 -0600 commit: df_side2 9a301fbe6fada7dcb74fcd7c20269b5c743459a7 a7dbfcbfc1a60709cb80b5ca24539008456531d0 Edward Thomson 1355181793 -0600 checkout: moving from df_ancestor to df_side1 a7dbfcbfc1a60709cb80b5ca24539008456531d0 9a301fbe6fada7dcb74fcd7c20269b5c743459a7 Edward Thomson 1355181797 -0600 checkout: moving from df_side1 to df_side2 9a301fbe6fada7dcb74fcd7c20269b5c743459a7 9a301fbe6fada7dcb74fcd7c20269b5c743459a7 Edward Thomson 1355182062 -0600 checkout: moving from df_side2 to df_ancestor 9a301fbe6fada7dcb74fcd7c20269b5c743459a7 2da538570bc1e5b2c3e855bf702f35248ad0735f Edward Thomson 1355182067 -0600 reset: moving to 2da538570bc1e5b2c3e855bf702f35248ad0735f 2da538570bc1e5b2c3e855bf702f35248ad0735f 2da538570bc1e5b2c3e855bf702f35248ad0735f Edward Thomson 1355182087 -0600 checkout: moving from df_ancestor to df_side2 2da538570bc1e5b2c3e855bf702f35248ad0735f fc90237dc4891fa6c69827fc465632225e391618 Edward Thomson 1355182104 -0600 commit: df_side2 fc90237dc4891fa6c69827fc465632225e391618 a7dbfcbfc1a60709cb80b5ca24539008456531d0 Edward Thomson 1355182111 -0600 checkout: moving from df_side2 to df_side1 a7dbfcbfc1a60709cb80b5ca24539008456531d0 fc90237dc4891fa6c69827fc465632225e391618 Edward Thomson 1355182115 -0600 checkout: moving from df_side1 to df_side2 fc90237dc4891fa6c69827fc465632225e391618 bd593285fc7fe4ca18ccdbabf027f5d689101452 Edward Thomson 1355182122 -0600 checkout: moving from df_side2 to master bd593285fc7fe4ca18ccdbabf027f5d689101452 d6cf6c7741b3316826af1314042550c97ded1d50 Edward Thomson 1358997543 -0600 checkout: moving from master to unrelated d6cf6c7741b3316826af1314042550c97ded1d50 55b4e4687e7a0d9ca367016ed930f385d4022e6f Edward Thomson 1358997664 -0600 commit: conflicting changes 55b4e4687e7a0d9ca367016ed930f385d4022e6f bd593285fc7fe4ca18ccdbabf027f5d689101452 Edward Thomson 1358997675 -0600 checkout: moving from unrelated to master bd593285fc7fe4ca18ccdbabf027f5d689101452 88e185910a15cd13bdf44854ad037f4842b03b29 Edward Thomson 1365714471 -0500 checkout: moving from master to rename_conflict_ours 88e185910a15cd13bdf44854ad037f4842b03b29 bef6e37b3ee632ba74159168836f382fed21d77d Edward Thomson 1365714516 -0500 checkout: moving from rename_conflict_ours to bef6e37b3ee632ba74159168836f382fed21d77d bef6e37b3ee632ba74159168836f382fed21d77d 01f149e1b8f84bd8896aaff6d6b22af88459ded0 Edward Thomson 1365714831 -0500 commit: rename ancestor 0000000000000000000000000000000000000000 2392a2dacc9efb562b8635d6579fb458751c7c5b Edward Thomson 1365714958 -0500 commit (initial): rename conflict ancestor 2392a2dacc9efb562b8635d6579fb458751c7c5b 88e185910a15cd13bdf44854ad037f4842b03b29 Edward Thomson 1365714980 -0500 checkout: moving from rename_conflict_ancestor to rename_conflict_ours 88e185910a15cd13bdf44854ad037f4842b03b29 7c2c5228c9e90170d4a35e6558e47163daf092e5 Edward Thomson 1365715250 -0500 commit: rename conflict ours 7c2c5228c9e90170d4a35e6558e47163daf092e5 2f4024ce528d36d8670c289cce5a7963e625bb0c Edward Thomson 1365715274 -0500 checkout: moving from rename_conflict_ours to rename_conflict_theirs 2f4024ce528d36d8670c289cce5a7963e625bb0c 56a638b76b75e068590ac999c2f8621e7f3e264c Edward Thomson 1365715362 -0500 commit: rename conflict theirs 56a638b76b75e068590ac999c2f8621e7f3e264c 2392a2dacc9efb562b8635d6579fb458751c7c5b Edward Thomson 1365715368 -0500 checkout: moving from rename_conflict_theirs to rename_conflict_ancestor 2392a2dacc9efb562b8635d6579fb458751c7c5b 56a638b76b75e068590ac999c2f8621e7f3e264c Edward Thomson 1365715371 -0500 checkout: moving from rename_conflict_ancestor to rename_conflict_theirs 56a638b76b75e068590ac999c2f8621e7f3e264c 2392a2dacc9efb562b8635d6579fb458751c7c5b Edward Thomson 1365715404 -0500 checkout: moving from rename_conflict_theirs to rename_conflict_ancestor 2392a2dacc9efb562b8635d6579fb458751c7c5b 2392a2dacc9efb562b8635d6579fb458751c7c5b Edward Thomson 1365715438 -0500 checkout: moving from rename_conflict_ancestor to rename_conflict_ours 2392a2dacc9efb562b8635d6579fb458751c7c5b 2392a2dacc9efb562b8635d6579fb458751c7c5b Edward Thomson 1365715480 -0500 checkout: moving from rename_conflict_ours to rename_conflict_ancestor 2392a2dacc9efb562b8635d6579fb458751c7c5b 2392a2dacc9efb562b8635d6579fb458751c7c5b Edward Thomson 1365715486 -0500 checkout: moving from rename_conflict_ancestor to rename_conflict_ours 2392a2dacc9efb562b8635d6579fb458751c7c5b f3293571dcd708b6a3faf03818cd2844d000e198 Edward Thomson 1365715538 -0500 commit: rename conflict ours f3293571dcd708b6a3faf03818cd2844d000e198 2392a2dacc9efb562b8635d6579fb458751c7c5b Edward Thomson 1365715546 -0500 checkout: moving from rename_conflict_ours to rename_conflict_ancestor 2392a2dacc9efb562b8635d6579fb458751c7c5b 2392a2dacc9efb562b8635d6579fb458751c7c5b Edward Thomson 1365715550 -0500 checkout: moving from rename_conflict_ancestor to rename_conflict_thiers 2392a2dacc9efb562b8635d6579fb458751c7c5b 2392a2dacc9efb562b8635d6579fb458751c7c5b Edward Thomson 1365715554 -0500 checkout: moving from rename_conflict_thiers to rename_conflict_ancestor 2392a2dacc9efb562b8635d6579fb458751c7c5b 2392a2dacc9efb562b8635d6579fb458751c7c5b Edward Thomson 1365715557 -0500 checkout: moving from rename_conflict_ancestor to rename_conflict_theirs 2392a2dacc9efb562b8635d6579fb458751c7c5b a802e06f1782a9645b9851bc7202cee74a8a4972 Edward Thomson 1365715572 -0500 commit: rename conflict theirs a802e06f1782a9645b9851bc7202cee74a8a4972 bd593285fc7fe4ca18ccdbabf027f5d689101452 Edward Thomson 1365715620 -0500 checkout: moving from rename_conflict_theirs to master libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/logs/refs/000077500000000000000000000000001216214232500252435ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/000077500000000000000000000000001216214232500263275ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/branch000066400000000000000000000005071216214232500275110ustar00rootroot000000000000000000000000000000000000000000000000000000 c607fc30883e335def28cd686b51f6cfa02b06ec Edward Thomson 1351563886 -0500 branch: Created from HEAD c607fc30883e335def28cd686b51f6cfa02b06ec 7cb63eed597130ba4abb87b3e544b85021905520 Edward Thomson 1351563965 -0500 commit: branch libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/df_ancestor000066400000000000000000000015251216214232500305440ustar00rootroot000000000000000000000000000000000000000000000000000000 bd593285fc7fe4ca18ccdbabf027f5d689101452 Edward Thomson 1355181639 -0600 branch: Created from HEAD bd593285fc7fe4ca18ccdbabf027f5d689101452 2da538570bc1e5b2c3e855bf702f35248ad0735f Edward Thomson 1355181673 -0600 commit: df_ancestor 2da538570bc1e5b2c3e855bf702f35248ad0735f a7dbfcbfc1a60709cb80b5ca24539008456531d0 Edward Thomson 1355181715 -0600 commit: df_side1 a7dbfcbfc1a60709cb80b5ca24539008456531d0 9a301fbe6fada7dcb74fcd7c20269b5c743459a7 Edward Thomson 1355181775 -0600 commit: df_side2 9a301fbe6fada7dcb74fcd7c20269b5c743459a7 2da538570bc1e5b2c3e855bf702f35248ad0735f Edward Thomson 1355182067 -0600 reset: moving to 2da538570bc1e5b2c3e855bf702f35248ad0735f libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/df_side1000066400000000000000000000046231216214232500277350ustar00rootroot000000000000000000000000000000000000000000000000000000 bd593285fc7fe4ca18ccdbabf027f5d689101452 Edward Thomson 1354574697 -0600 branch: Created from HEAD bd593285fc7fe4ca18ccdbabf027f5d689101452 d4207f77243500bec335ab477f9227fcdb1e271a Edward Thomson 1354574962 -0600 commit: df_ancestor d4207f77243500bec335ab477f9227fcdb1e271a c94b27e41064c521120627e07e2035cca1d24ffa Edward Thomson 1354575027 -0600 commit: df_side1 c94b27e41064c521120627e07e2035cca1d24ffa a90bc3fb6f15181972a2959a921429efbd81a473 Edward Thomson 1355017650 -0600 commit: df_added a90bc3fb6f15181972a2959a921429efbd81a473 005b6fcc8fec71d2550bef8462d169b3c26aa14b Edward Thomson 1355017676 -0600 rebase -i (finish): refs/heads/df_side1 onto c94b27e 005b6fcc8fec71d2550bef8462d169b3c26aa14b f8958bdf4d365a84a9a178b1f5f35ff1dacbd884 Edward Thomson 1355017715 -0600 reset: moving to df_side2 f8958bdf4d365a84a9a178b1f5f35ff1dacbd884 8c749d9968d4b10dcfb06c9f97d0e5d92d337071 Edward Thomson 1355017744 -0600 commit: df_added 8c749d9968d4b10dcfb06c9f97d0e5d92d337071 0204a84f822acbf6386b36d33f1f6bc68bbbf858 Edward Thomson 1355017756 -0600 rebase -i (finish): refs/heads/df_side1 onto f8958bd 0204a84f822acbf6386b36d33f1f6bc68bbbf858 005b6fcc8fec71d2550bef8462d169b3c26aa14b Edward Thomson 1355017793 -0600 reset: moving to 005b6fcc8fec71d2550bef8462d169b3c26aa14b 005b6fcc8fec71d2550bef8462d169b3c26aa14b 0204a84f822acbf6386b36d33f1f6bc68bbbf858 Edward Thomson 1355017826 -0600 reset: moving to 0204a84 005b6fcc8fec71d2550bef8462d169b3c26aa14b e8107f24196736b870a318a0e28f048e29f6feff Edward Thomson 1355169065 -0600 commit: df_side1 e8107f24196736b870a318a0e28f048e29f6feff 80a8fbb3abb1ba423d554e9630b8fc2e5698f86b Edward Thomson 1355169084 -0600 rebase -i (finish): refs/heads/df_side1 onto 005b6fc 80a8fbb3abb1ba423d554e9630b8fc2e5698f86b e65a9bb2af9f4c2d1c375dd0f8f8a46cf9c68812 Edward Thomson 1355169419 -0600 commit: side1 e65a9bb2af9f4c2d1c375dd0f8f8a46cf9c68812 5dc1018e90b19654bee986b7a0c268804d39659d Edward Thomson 1355169435 -0600 rebase -i (finish): refs/heads/df_side1 onto 80a8fbb libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/df_side2000066400000000000000000000031311216214232500277270ustar00rootroot000000000000000000000000000000000000000000000000000000 d4207f77243500bec335ab477f9227fcdb1e271a Edward Thomson 1354575051 -0600 branch: Created from d4207f77243500bec335ab477f9227fcdb1e271a d4207f77243500bec335ab477f9227fcdb1e271a f8958bdf4d365a84a9a178b1f5f35ff1dacbd884 Edward Thomson 1354575206 -0600 commit: df_side2 0204a84f822acbf6386b36d33f1f6bc68bbbf858 944f5dd1a867cab4c2bbcb896493435cae1dcc1a Edward Thomson 1355169174 -0600 commit: both 944f5dd1a867cab4c2bbcb896493435cae1dcc1a 57079a46233ae2b6df62e9ade71c4948512abefb Edward Thomson 1355169185 -0600 rebase -i (finish): refs/heads/df_side2 onto 0204a84 57079a46233ae2b6df62e9ade71c4948512abefb 58e853f66699fd02629fd50bde08082bc005933a Edward Thomson 1355169460 -0600 commit: side2 58e853f66699fd02629fd50bde08082bc005933a fada9356aa3f74622327a3038ae9c6f92e1c5c1d Edward Thomson 1355169471 -0600 rebase -i (finish): refs/heads/df_side2 onto 57079a4 fada9356aa3f74622327a3038ae9c6f92e1c5c1d 95646149ab6b6ba6edc83cff678582538b457b2b Edward Thomson 1355169897 -0600 rebase finished: refs/heads/df_side2 onto a765fb87eb2f7a1920b73b2d5a057f8f8476a42b 0000000000000000000000000000000000000000 2da538570bc1e5b2c3e855bf702f35248ad0735f Edward Thomson 1355182087 -0600 branch: Created from HEAD 2da538570bc1e5b2c3e855bf702f35248ad0735f fc90237dc4891fa6c69827fc465632225e391618 Edward Thomson 1355182104 -0600 commit: df_side2 libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/ff_branch000066400000000000000000000015421216214232500301640ustar00rootroot000000000000000000000000000000000000000000000000000000 977c696519c5a3004c5f1d15d60c89dbeb8f235f Edward Thomson 1351605785 -0500 branch: Created from HEAD 977c696519c5a3004c5f1d15d60c89dbeb8f235f 33d500f588fbbe65901d82b4e6b008e549064be0 Edward Thomson 1351605830 -0500 commit: fastforward 33d500f588fbbe65901d82b4e6b008e549064be0 c607fc30883e335def28cd686b51f6cfa02b06ec Edward Thomson 1351990202 -0500 reset: moving to c607fc30883e335def28cd686b51f6cfa02b06ec c607fc30883e335def28cd686b51f6cfa02b06ec bd593285fc7fe4ca18ccdbabf027f5d689101452 Edward Thomson 1351990205 -0500 merge master: Fast-forward bd593285fc7fe4ca18ccdbabf027f5d689101452 fd89f8cffb663ac89095a0f9764902e93ceaca6a Edward Thomson 1351990229 -0500 commit: fastforward libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/master000066400000000000000000000016551216214232500275540ustar00rootroot000000000000000000000000000000000000000000000000000000 c607fc30883e335def28cd686b51f6cfa02b06ec Edward Thomson 1351563869 -0500 commit (initial): initial c607fc30883e335def28cd686b51f6cfa02b06ec 977c696519c5a3004c5f1d15d60c89dbeb8f235f Edward Thomson 1351564033 -0500 commit: master 977c696519c5a3004c5f1d15d60c89dbeb8f235f 4e0d9401aee78eb345a8685a859d37c8c3c0bbed Edward Thomson 1351875091 -0500 merge octo1 octo2 octo3 octo4: Merge made by the 'octopus' strategy. 4e0d9401aee78eb345a8685a859d37c8c3c0bbed 54269b3f6ec3d7d4ede24dd350dd5d605495c3ae Edward Thomson 1351875108 -0500 reset: moving to 54269b3f6ec3d7d4ede24dd350dd5d605495c3ae 54269b3f6ec3d7d4ede24dd350dd5d605495c3ae 977c696519c5a3004c5f1d15d60c89dbeb8f235f Edward Thomson 1351875584 -0500 reset: moving to 977c696519c5a3004c5f1d15d60c89dbeb8f235f libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/octo1000066400000000000000000000005061216214232500273000ustar00rootroot000000000000000000000000000000000000000000000000000000 977c696519c5a3004c5f1d15d60c89dbeb8f235f Edward Thomson 1351874933 -0500 branch: Created from HEAD 977c696519c5a3004c5f1d15d60c89dbeb8f235f 16f825815cfd20a07a75c71554e82d8eede0b061 Edward Thomson 1351874954 -0500 commit: octo1 libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/octo2000066400000000000000000000005061216214232500273010ustar00rootroot000000000000000000000000000000000000000000000000000000 977c696519c5a3004c5f1d15d60c89dbeb8f235f Edward Thomson 1351874960 -0500 branch: Created from HEAD 977c696519c5a3004c5f1d15d60c89dbeb8f235f 158dc7bedb202f5b26502bf3574faa7f4238d56c Edward Thomson 1351874974 -0500 commit: octo2 libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/octo3000066400000000000000000000005061216214232500273020ustar00rootroot000000000000000000000000000000000000000000000000000000 977c696519c5a3004c5f1d15d60c89dbeb8f235f Edward Thomson 1351874980 -0500 branch: Created from HEAD 977c696519c5a3004c5f1d15d60c89dbeb8f235f 50ce7d7d01217679e26c55939eef119e0c93e272 Edward Thomson 1351874998 -0500 commit: octo3 libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/octo4000066400000000000000000000005061216214232500273030ustar00rootroot000000000000000000000000000000000000000000000000000000 977c696519c5a3004c5f1d15d60c89dbeb8f235f Edward Thomson 1351875010 -0500 branch: Created from HEAD 977c696519c5a3004c5f1d15d60c89dbeb8f235f 54269b3f6ec3d7d4ede24dd350dd5d605495c3ae Edward Thomson 1351875023 -0500 commit: octo4 libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/octo5000066400000000000000000000005061216214232500273040ustar00rootroot000000000000000000000000000000000000000000000000000000 977c696519c5a3004c5f1d15d60c89dbeb8f235f Edward Thomson 1351875031 -0500 branch: Created from HEAD 977c696519c5a3004c5f1d15d60c89dbeb8f235f e4f618a2c3ed0669308735727df5ebf2447f022f Edward Thomson 1351875041 -0500 commit: octo5 libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/octo6000066400000000000000000000007531216214232500273110ustar00rootroot000000000000000000000000000000000000000000000000000000 977c696519c5a3004c5f1d15d60c89dbeb8f235f Edward Thomson 1351875046 -0500 branch: Created from HEAD 977c696519c5a3004c5f1d15d60c89dbeb8f235f 4ca408a8c88655f7586a1b580be6fad138121e98 Edward Thomson 1351875057 -0500 commit: octo5 4ca408a8c88655f7586a1b580be6fad138121e98 b6f610aef53bd343e6c96227de874c66f00ee8e8 Edward Thomson 1351875065 -0500 commit (amend): octo6 libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/renames1000066400000000000000000000005541216214232500277710ustar00rootroot000000000000000000000000000000000000000000000000000000 c607fc30883e335def28cd686b51f6cfa02b06ec Edward Thomson 1353177745 -0600 branch: Created from c607fc30883e335def28cd686b51f6cfa02b06ec c607fc30883e335def28cd686b51f6cfa02b06ec 412b32fb66137366147f1801ecc962452757d48a Edward Thomson 1353177886 -0600 commit: renames libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/renames2000066400000000000000000000010221216214232500277610ustar00rootroot000000000000000000000000000000000000000000000000000000 bd593285fc7fe4ca18ccdbabf027f5d689101452 Edward Thomson 1353794647 -0600 branch: Created from HEAD bd593285fc7fe4ca18ccdbabf027f5d689101452 c607fc30883e335def28cd686b51f6cfa02b06ec Edward Thomson 1353794677 -0600 reset: moving to c607fc30883e335def28cd686b51f6cfa02b06ec c607fc30883e335def28cd686b51f6cfa02b06ec ab40af3cb8a3ed2e2843e96d9aa7871336b94573 Edward Thomson 1353794852 -0600 commit: renames2 libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-10000066400000000000000000000010211216214232500301340ustar00rootroot000000000000000000000000000000000000000000000000000000 c607fc30883e335def28cd686b51f6cfa02b06ec Edward Thomson 1352100171 -0600 branch: Created from c607fc30883e335def28cd686b51f6cfa02b06ec c607fc30883e335def28cd686b51f6cfa02b06ec 53825f41ac8d640612f9423a2f03a69f3d96809a Edward Thomson 1352100193 -0600 commit: trivial-10 53825f41ac8d640612f9423a2f03a69f3d96809a 0ec5f433959cd46177f745903353efb5be08d151 Edward Thomson 1352100223 -0600 commit: trivial-10 libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-10-branch000066400000000000000000000005221216214232500313740ustar00rootroot000000000000000000000000000000000000000000000000000000 53825f41ac8d640612f9423a2f03a69f3d96809a Edward Thomson 1352100200 -0600 branch: Created from HEAD 53825f41ac8d640612f9423a2f03a69f3d96809a 11f4f3c08b737f5fd896cbefa1425ee63b21b2fa Edward Thomson 1352100211 -0600 commit: trivial-10-branch libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-11000066400000000000000000000010211216214232500301350ustar00rootroot000000000000000000000000000000000000000000000000000000 c607fc30883e335def28cd686b51f6cfa02b06ec Edward Thomson 1352100930 -0600 branch: Created from c607fc30883e335def28cd686b51f6cfa02b06ec c607fc30883e335def28cd686b51f6cfa02b06ec 35632e43612c06a3ea924bfbacd48333da874c29 Edward Thomson 1352100958 -0600 commit: trivial-11 35632e43612c06a3ea924bfbacd48333da874c29 3168dca1a561889b045a6441909f4c56145e666d Edward Thomson 1352100992 -0600 commit: trivial-11 libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-11-branch000066400000000000000000000005221216214232500313750ustar00rootroot000000000000000000000000000000000000000000000000000000 35632e43612c06a3ea924bfbacd48333da874c29 Edward Thomson 1352100964 -0600 branch: Created from HEAD 35632e43612c06a3ea924bfbacd48333da874c29 6718a45909532d1fcf5600d0877f7fe7e78f0b86 Edward Thomson 1352100978 -0600 commit: trivial-11-branch libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-13000066400000000000000000000010211216214232500301370ustar00rootroot000000000000000000000000000000000000000000000000000000 c607fc30883e335def28cd686b51f6cfa02b06ec Edward Thomson 1352100559 -0600 branch: Created from c607fc30883e335def28cd686b51f6cfa02b06ec c607fc30883e335def28cd686b51f6cfa02b06ec 8f4433f8593ddd65b7dd43dd4564d841f4d9c8aa Edward Thomson 1352100589 -0600 commit: trivial-13 8f4433f8593ddd65b7dd43dd4564d841f4d9c8aa a3fabece9eb8748da810e1e08266fef9b7136ad4 Edward Thomson 1352100625 -0600 commit: trivial-13 libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-13-branch000066400000000000000000000005221216214232500313770ustar00rootroot000000000000000000000000000000000000000000000000000000 8f4433f8593ddd65b7dd43dd4564d841f4d9c8aa Edward Thomson 1352100604 -0600 branch: Created from HEAD 8f4433f8593ddd65b7dd43dd4564d841f4d9c8aa 05f3c1a2a56ca95c3d2ef28dc9ddf32b5cd6c91c Edward Thomson 1352100610 -0600 commit: trivial-13-branch libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-14000066400000000000000000000010211216214232500301400ustar00rootroot000000000000000000000000000000000000000000000000000000 c607fc30883e335def28cd686b51f6cfa02b06ec Edward Thomson 1352101083 -0600 branch: Created from c607fc30883e335def28cd686b51f6cfa02b06ec c607fc30883e335def28cd686b51f6cfa02b06ec 596803b523203a4851c824c07366906f8353f4ad Edward Thomson 1352101113 -0600 commit: trivial-14 596803b523203a4851c824c07366906f8353f4ad 7e2d058d5fedf8329db44db4fac610d6b1a89159 Edward Thomson 1352101141 -0600 commit: trivial-14 libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-14-branch000066400000000000000000000005221216214232500314000ustar00rootroot000000000000000000000000000000000000000000000000000000 596803b523203a4851c824c07366906f8353f4ad Edward Thomson 1352101117 -0600 branch: Created from HEAD 596803b523203a4851c824c07366906f8353f4ad 8187117062b750eed4f93fd7e899f17b52ce554d Edward Thomson 1352101132 -0600 commit: trivial-14-branch libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-2alt000066400000000000000000000005511216214232500305650ustar00rootroot000000000000000000000000000000000000000000000000000000 c607fc30883e335def28cd686b51f6cfa02b06ec Edward Thomson 1352091695 -0600 branch: Created from c607fc30883e335def28cd686b51f6cfa02b06ec c607fc30883e335def28cd686b51f6cfa02b06ec 566ab53c220a2eafc1212af1a024513230280ab9 Edward Thomson 1352092452 -0600 commit: 2alt libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-2alt-branch000066400000000000000000000005141216214232500320170ustar00rootroot000000000000000000000000000000000000000000000000000000 c607fc30883e335def28cd686b51f6cfa02b06ec Edward Thomson 1352092411 -0600 branch: Created from HEAD c607fc30883e335def28cd686b51f6cfa02b06ec c9174cef549ec94ecbc43ef03cdc775b4950becb Edward Thomson 1352092434 -0600 commit: 2alt-branch libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-3alt000066400000000000000000000010101216214232500305550ustar00rootroot00000000000000566ab53c220a2eafc1212af1a024513230280ab9 c607fc30883e335def28cd686b51f6cfa02b06ec Edward Thomson 1352094547 -0600 reset: moving to c607fc30883e335def28cd686b51f6cfa02b06ec c607fc30883e335def28cd686b51f6cfa02b06ec 5459c89aa0026d543ce8343bd89871bce543f9c2 Edward Thomson 1352094580 -0600 commit: 3alt 5459c89aa0026d543ce8343bd89871bce543f9c2 4c9fac0707f8d4195037ae5a681aa48626491541 Edward Thomson 1352094610 -0600 commit: 3alt-branch libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-3alt-branch000066400000000000000000000003151216214232500320170ustar00rootroot000000000000000000000000000000000000000000000000000000 c607fc30883e335def28cd686b51f6cfa02b06ec Edward Thomson 1352094594 -0600 branch: Created from c607fc30883e335def28cd686b51f6cfa02b06ec libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-4000066400000000000000000000005521216214232500300670ustar00rootroot00000000000000566ab53c220a2eafc1212af1a024513230280ab9 c607fc30883e335def28cd686b51f6cfa02b06ec Edward Thomson 1352094764 -0600 reset: moving to c607fc30883e335def28cd686b51f6cfa02b06ec c607fc30883e335def28cd686b51f6cfa02b06ec cc3e3009134cb88014129fc8858d1101359e5e2f Edward Thomson 1352094815 -0600 commit: trivial-4 libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-4-branch000066400000000000000000000005651216214232500313260ustar00rootroot000000000000000000000000000000000000000000000000000000 c607fc30883e335def28cd686b51f6cfa02b06ec Edward Thomson 1352094830 -0600 branch: Created from c607fc30883e335def28cd686b51f6cfa02b06ec c607fc30883e335def28cd686b51f6cfa02b06ec 183310e30fb1499af8c619108ffea4d300b5e778 Edward Thomson 1352094856 -0600 commit: trivial-4-branch libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-5alt-1000066400000000000000000000005531216214232500307300ustar00rootroot000000000000000000000000000000000000000000000000000000 c607fc30883e335def28cd686b51f6cfa02b06ec Edward Thomson 1352096606 -0600 branch: Created from c607fc30883e335def28cd686b51f6cfa02b06ec c607fc30883e335def28cd686b51f6cfa02b06ec 4fe93c0ec83eb6305cbace3dace88ecee1b63cb6 Edward Thomson 1352096643 -0600 commit: 5alt-1 libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-5alt-1-branch000066400000000000000000000005621216214232500321630ustar00rootroot000000000000000000000000000000000000000000000000000000 c607fc30883e335def28cd686b51f6cfa02b06ec Edward Thomson 1352096657 -0600 branch: Created from c607fc30883e335def28cd686b51f6cfa02b06ec c607fc30883e335def28cd686b51f6cfa02b06ec 478172cb2f5ff9b514bc9d04d3bd5ef5840cb3b2 Edward Thomson 1352096689 -0600 commit: 5alt-1-branch libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-5alt-2000066400000000000000000000010201216214232500307170ustar00rootroot000000000000000000000000000000000000000000000000000000 c607fc30883e335def28cd686b51f6cfa02b06ec Edward Thomson 1352096711 -0600 branch: Created from c607fc30883e335def28cd686b51f6cfa02b06ec c607fc30883e335def28cd686b51f6cfa02b06ec ebc09d0137cfb0c26697aed0109fb943ad906f3f Edward Thomson 1352096764 -0600 commit: existing file ebc09d0137cfb0c26697aed0109fb943ad906f3f 3b47b031b3e55ae11e14a05260b1c3ffd6838d55 Edward Thomson 1352096815 -0600 commit: 5alt-2 libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-5alt-2-branch000066400000000000000000000005211216214232500321570ustar00rootroot000000000000000000000000000000000000000000000000000000 ebc09d0137cfb0c26697aed0109fb943ad906f3f Edward Thomson 1352096833 -0600 branch: Created from ebc09d0 ebc09d0137cfb0c26697aed0109fb943ad906f3f f48097eb340dc5a7cae55aabcf1faf4548aa821f Edward Thomson 1352096855 -0600 commit: 5alt-2-branch libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-6000066400000000000000000000010071216214232500300650ustar00rootroot000000000000000000000000000000000000000000000000000000 c607fc30883e335def28cd686b51f6cfa02b06ec Edward Thomson 1352097371 -0600 branch: Created from c607fc30883e335def28cd686b51f6cfa02b06ec c607fc30883e335def28cd686b51f6cfa02b06ec f7c332bd4d4d4b777366cae4d24d1687477576bf Edward Thomson 1352097389 -0600 commit: 6 f7c332bd4d4d4b777366cae4d24d1687477576bf 99b4f7e4f24470fa06b980bc21f1095c2a9425c0 Edward Thomson 1352097404 -0600 commit: trivial-6 libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-6-branch000066400000000000000000000005551216214232500313270ustar00rootroot000000000000000000000000000000000000000000000000000000 f7c332bd4d4d4b777366cae4d24d1687477576bf Edward Thomson 1352097414 -0600 branch: Created from f7c332bd4d4d4b777366cae4d24d1687477576bf f7c332bd4d4d4b777366cae4d24d1687477576bf a43150a738849c59376cf30bb2a68348a83c8f48 Edward Thomson 1352097431 -0600 commit: 6-branch libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-7000066400000000000000000000010171216214232500300670ustar00rootroot000000000000000000000000000000000000000000000000000000 c607fc30883e335def28cd686b51f6cfa02b06ec Edward Thomson 1352099765 -0600 branch: Created from c607fc30883e335def28cd686b51f6cfa02b06ec c607fc30883e335def28cd686b51f6cfa02b06ec 092ce8682d7f3a2a3a769a6daca58950168ba5c4 Edward Thomson 1352099790 -0600 commit: trivial-7 092ce8682d7f3a2a3a769a6daca58950168ba5c4 d874671ef5b20184836cb983bb273e5280384d0b Edward Thomson 1352099947 -0600 commit: trivial-7 libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-7-branch000066400000000000000000000015561216214232500313320ustar00rootroot000000000000000000000000000000000000000000000000000000 092ce8682d7f3a2a3a769a6daca58950168ba5c4 Edward Thomson 1352099799 -0600 branch: Created from HEAD 092ce8682d7f3a2a3a769a6daca58950168ba5c4 73cbfdc4fe843169e5b2af8dcad03cbf3acf306c Edward Thomson 1352099812 -0600 commit: trivial-7-branch 73cbfdc4fe843169e5b2af8dcad03cbf3acf306c 092ce8682d7f3a2a3a769a6daca58950168ba5c4 Edward Thomson 1352099874 -0600 reset: moving to 092ce8682d7f3a2a3a769a6daca58950168ba5c4 092ce8682d7f3a2a3a769a6daca58950168ba5c4 009b9cab6fdac02915a88ecd078b7a792ed802d8 Edward Thomson 1352099921 -0600 commit: removed in 7 009b9cab6fdac02915a88ecd078b7a792ed802d8 5195a1b480f66691b667f10a9e41e70115a78351 Edward Thomson 1352099927 -0600 commit (amend): trivial-7-branch libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-8000066400000000000000000000010171216214232500300700ustar00rootroot000000000000000000000000000000000000000000000000000000 c607fc30883e335def28cd686b51f6cfa02b06ec Edward Thomson 1352098816 -0600 branch: Created from c607fc30883e335def28cd686b51f6cfa02b06ec c607fc30883e335def28cd686b51f6cfa02b06ec 75a811bf6bc57694adb3fe604786f3a4efd1cd1b Edward Thomson 1352098884 -0600 commit: trivial-8 75a811bf6bc57694adb3fe604786f3a4efd1cd1b 3575826c96a975031d2c14368529cc5c4353a8fd Edward Thomson 1352099000 -0600 commit: trivial-8 libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-8-branch000066400000000000000000000005211216214232500313220ustar00rootroot000000000000000000000000000000000000000000000000000000 75a811bf6bc57694adb3fe604786f3a4efd1cd1b Edward Thomson 1352098947 -0600 branch: Created from HEAD 75a811bf6bc57694adb3fe604786f3a4efd1cd1b 52d8bc572af2b6d4ee0d5e62ed5d1fbad92210a9 Edward Thomson 1352098979 -0600 commit: trivial-8-branch libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-9000066400000000000000000000010171216214232500300710ustar00rootroot000000000000000000000000000000000000000000000000000000 c607fc30883e335def28cd686b51f6cfa02b06ec Edward Thomson 1352100268 -0600 branch: Created from c607fc30883e335def28cd686b51f6cfa02b06ec c607fc30883e335def28cd686b51f6cfa02b06ec f0053b8060bb3f0be5cbcc3147a07ece26bf097e Edward Thomson 1352100304 -0600 commit: trivial-9 f0053b8060bb3f0be5cbcc3147a07ece26bf097e c35dee9bcc0e989f3b0c40f68372a9a51b6c4e6a Edward Thomson 1352100333 -0600 commit: trivial-9 libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-9-branch000066400000000000000000000005211216214232500313230ustar00rootroot000000000000000000000000000000000000000000000000000000 f0053b8060bb3f0be5cbcc3147a07ece26bf097e Edward Thomson 1352100310 -0600 branch: Created from HEAD f0053b8060bb3f0be5cbcc3147a07ece26bf097e 13d1be4ea52a6ced1d7a1d832f0ee3c399348e5e Edward Thomson 1352100317 -0600 commit: trivial-9-branch libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/unrelated000066400000000000000000000002531216214232500302350ustar00rootroot00000000000000d6cf6c7741b3316826af1314042550c97ded1d50 55b4e4687e7a0d9ca367016ed930f385d4022e6f Edward Thomson 1358997664 -0600 commit: conflicting changes libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/000077500000000000000000000000001216214232500247715ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/00/000077500000000000000000000000001216214232500252105ustar00rootroot000000000000005b6fcc8fec71d2550bef8462d169b3c26aa14b000066400000000000000000000002501216214232500324750ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/00x;0D} _:B4܀VR8F'\n4:u>Y&H@W{GY Ԧ ]f &6DCTaǶ[~%fy~ӕNՋDm% v H<)32zNR9b9cab6fdac02915a88ecd078b7a792ed802d8000066400000000000000000000002441216214232500325210ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/00x 0D9md;:zpy R]o" &qhK}fE01hvFM-K 8 diB&&kH[Yѣϵ%eε GG܁k9Ոh uZmt;դԧdXV wcPc7d33f1ffa79d19c2272b370fcaeaadba49c08000066400000000000000000000002231216214232500326320ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/00x+)JMU04`01 ݔ̢bS͌|f(%|ah``fb .liMz-Ɨ9\M,bh2))zu\slͳl2XWRQozHta%x57libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/01/000077500000000000000000000000001216214232500252115ustar00rootroot00000000000000f149e1b8f84bd8896aaff6d6b22af88459ded0000066400000000000000000000002461216214232500325430ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/01xI!=!1Ƌ?,Mf }7xԡRN@9f*b0-jeL ^q6!qu)if1E2׮j BTD|ϥxOKo{ʇѽyyɽ@igIRGBDZ1->_m.Nlibgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/02/000077500000000000000000000000001216214232500252125ustar00rootroot0000000000000004a84f822acbf6386b36d33f1f6bc68bbbf858000066400000000000000000000002501216214232500324340ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/02xA 1=2dv6 xdv#1]x뮆S[7U`8)AR"wb1EsK9 pa^0id %"rIyrȳ_kZG]^WIGKu>X)`0g!p~qˊ 1N251f990ca8e92e7ae61d3426163fa821c64001000066400000000000000000000004101216214232500320320ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/02x+)JMU067`040031QH,-M-JOMLI+(aH:,:C: o>ZC'g$楧f&%%g5qYeZokM2ԐX\ZDPC~^ZNfrIf^:XZHي1O(_,' jv^j9CoZF2/=2,ž5|PEe.*s!d v=θ}Sc3k=.X&+jRR`pC7Ms,Ia Ol?libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/03/000077500000000000000000000000001216214232500252135ustar00rootroot0000000000000021415405cb906c46869919af56d51dbbe5e85c000066400000000000000000000004171216214232500321440ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/03x+)JMU067f040031QH,-M-JOMLI+(aH:,:C: o>ZC'g$楧f&%%g5qYeZokM2ԐX\ZDPC~^ZNfrIf^:XZHي1O(_,' jvn~JfZ&5% aYy˷ =m\U__?i?>AƠm{w15 9>:c_fゅk/j(8N?!_z4ǒVf^,dC2ebc5ab85d9553bb187d3cd40875ff23a63ed0000066400000000000000000000000351216214232500324250ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/03xKOR04e(,V̜Tc.Wb87706555accbf874ccd410dbda01e8e70a67f000066400000000000000000000005411216214232500325050ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/03x+)JMU012c040031QHLIIMM,.I-+(aP<9 w|S7݅&0%E驉I9`8B߭)y'뜇*N/M,*f(/W}2(9#1/ℤļ s\pqwvSLk15 YjM}]nٱG:-LC~^ZNfrIf^:lUS+W ^oK= P2inIK>ZcsP2~n]׽IhŅ'7<\sv5TMQjn~w?J>\]3e߅j(z`gicIz_]xb3/ ydad1005e5d06d418f50b12e0bcd48ff2306a03000066400000000000000000000004101216214232500323020ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/03x+)JMU06d040031QH,-M-JOMLI+(aH:,:C: o>ZC'g$楧f&%%g5qYeZokM2ԐX\ZDPC~^ZNfrIf^:XZHي1O(_,' jvQjn~1`S> k*?j!EOLH*s!d v=θ}Sc3k=.X&+jRR`h7Ms,Ia Ol.Glibgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/05/000077500000000000000000000000001216214232500252155ustar00rootroot000000000000001ffd7901a442faf56b226161649074f15c7c47000066400000000000000000000004171216214232500320550ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/05x+)JMU06`040031QH,-M-JOMLI+(aH:,:C: o>ZC'g$楧f&%%g5qYeZokM2ԐX\ZDPC~^ZNfrIf^:XZHي1O(_,' jvn~JfZ&5&ؽ +gz43^2 I{| 2mg˾15ӿ,\})TC)0Xvz֛9MՅ'6b#8541fc37114bfc1dddf6bd6bffc7fae5c2e6fe000066400000000000000000000000771216214232500331030ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/05xKOR021g(,VHIU҉%E驉I9\G*9#1/=5E!3O!(1/9 ]"f3c1a2a56ca95c3d2ef28dc9ddf32b5cd6c91c000066400000000000000000000002521216214232500327250ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/05xQj0DSZiWVZ†*^?N .zT- 1%)yTI2i7ݺM1D$4H%!SN̆\?7׹/퓾U1l!"8;~3oaoy6|1Slibgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/07/000077500000000000000000000000001216214232500252175ustar00rootroot00000000000000a759da919f737221791d542f176ab49c88837f000066400000000000000000000002451216214232500320340ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/07xˍ1D9;Nv+2 O`gXmܪޓJŽcnr!)&jP$a>HCym{ c$!rE\|sh*?+~'OvMNZأCTNrF-}0)Qc514b04698e068892b31c8d352b85813b99c6e000066400000000000000000000000401216214232500320100ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/07xKOR04c(J/KMQSH/blibgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/09/000077500000000000000000000000001216214232500252215ustar00rootroot00000000000000055301463b7f2f8ee5d368f8ed5c0a40ad8515000066400000000000000000000000511216214232500322120ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/09xKOR02g,VHIUy y %Fz\ʽ 17bb159596aea4d295f4857da77e8f96b3c7dc000066400000000000000000000000441216214232500324110ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/09xKOR02b(,"̜TC. 2ce8682d7f3a2a3a769a6daca58950168ba5c4000066400000000000000000000002431216214232500323600ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/09x !D 81؁ ,/ jy eMD] %C4,Yd(#5v87e)6pƀi2e(ϵc~Qt˽^NVIq}=gQϙ.WoP3bebf072dd4bbba88833667d6ffe454df199e1000066400000000000000000000004121216214232500325330ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/09x+)JMU067g040031QH,-M-JOMLI+(aH:,:C: o>ZC'g$楧f&%%g5qYeZokM2ԐX\ZDPC~^ZNfrIf^:XZHي1O(_,' jvQjn~1967koZrO[L=H*s!d v=θ}Sb3k=.X&+jRR` 7Ms,Ia Olc 768bed22680cdb0859683fa9677ccc8d5a25c1000066400000000000000000000004231216214232500323170ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/09x+)JMU067f040031QH,-M-JOMLI+(aH:,:C: o>ZC'g$楧f&%%g5qYeZokM2ԐX\ZDPC~^ZNfrIf^:XZHي1O(_,' jvn~JfZ&5%ʼn?v rx\U__?i?>AƠm{w15 9>:c_fゅk/j(8N?!_z4ǒVf^,libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/0a/000077500000000000000000000000001216214232500252715ustar00rootroot0000000000000075d9aac1dc84fb5aa51f7325c0ab53242ddef7000066400000000000000000000004231216214232500326310ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/0ax+)JMU067f040031QH,-M-JOMLI+(aH:,:C: o>ZC'g$楧f&%%g5qYeZokM2ԐX\ZDPC~^ZNfrIf^:XZHي1O(_,' jvn~JfZ&5%ʼn{{{klɹڶնM@a8OګυO1h8^]L HX.W`ᚬKJ! O|׳4ͱ$nկ.< libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/0c/000077500000000000000000000000001216214232500252735ustar00rootroot00000000000000fd6c54ef6532d862408f562309dc9c74a401e8000066400000000000000000000000341216214232500322220ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/0cxKOR04bK-WS0N)@libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/0d/000077500000000000000000000000001216214232500252745ustar00rootroot0000000000000052e3a556e189ba0948ae56780918011c1b167d000066400000000000000000000003531216214232500320530ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/0dx+)JMU062e040031QH,-M-JOMLI+(aH:,:C: o>ZC'g$楧f&%%g5qYeZokM2ԐX\ZDPC~^ZNfrIf^:XZHي1O(_,' jvQjn~c?J>\]3eԀG~Ś_n ɊھCN9!_z4ǒVf^,=!872f8e871a30208305978ecbf9e66d864f1638000066400000000000000000000001311216214232500321040ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/0dxKOR011d(,V(QHJU(JKMMQS/-*JKQHM,df42RRSSt2KhrqaH?libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/0e/000077500000000000000000000000001216214232500252755ustar00rootroot00000000000000c5f433959cd46177f745903353efb5be08d151000066400000000000000000000002451216214232500321510ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/0ex !D ,Ab?v`˱K jy/Xy&!RT`mJCDٗ"\Lbԍ,]; 5<-x%Z$>/S~q|.z/+|ů:! , z@8qjk<٩G>z2Lva2)Veŏ:%˜{A|Ǽ5K@mg9jY _;n,YyPlibgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/13/000077500000000000000000000000001216214232500252145ustar00rootroot00000000000000d1be4ea52a6ced1d7a1d832f0ee3c399348e5e000066400000000000000000000002501216214232500325640ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/13x 0yY.i$xaKj%ڠ`} bϒ\en8ܵ*apF,9cbGC320UY,.s@$R^i.= G'+~@@j+7أENsFt]7bN)libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/16/000077500000000000000000000000001216214232500252175ustar00rootroot00000000000000f825815cfd20a07a75c71554e82d8eede0b061000066400000000000000000000002401216214232500322650ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/16xK!D]sObo hJqo6AJـT1h3'Lՠ.{ec,a`ZJT1#e+هJUi">\+ ץG_X6IvN;^bYgGMMlibgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/17/000077500000000000000000000000001216214232500252205ustar00rootroot000000000000008940b450f238a56c0d75b7955cb57b38191982000066400000000000000000000001011216214232500317250ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/17xKOR060g(,VHIU(QHJU(JKMMSH/PH*JKH-U hmlibgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/18/000077500000000000000000000000001216214232500252215ustar00rootroot000000000000003310e30fb1499af8c619108ffea4d300b5e778000066400000000000000000000002521216214232500322130ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/18xQj0 DS)r+ez,$ml 7 #u߷^z3Ҭ +*(@BL&f>ѽERBCjeL(PH ØL?ZonokovgگkRGX@nqm_ ӐRcb316b1cefa0f8a6946f0e201a8e1a6f845ab9000066400000000000000000000001041216214232500324770ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/18xKOR063f(,V(QHJU(JKMMQS/-*JKQHII-dfEFhƂlibgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/19/000077500000000000000000000000001216214232500252225ustar00rootroot00000000000000b7ac485269b672a101060894de3ba9c2a24dd1000066400000000000000000000000651216214232500322010ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/19xKOR01fJ/KMQSP7WWH*-QOL˄&%%gqlibgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/1c/000077500000000000000000000000001216214232500252745ustar00rootroot00000000000000ff9ec6a47a537380dedfdd17c9e76d74259a2b000066400000000000000000000000411216214232500326110ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/1cxKOR04gOLLMQSP74Ve[libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/1e/000077500000000000000000000000001216214232500252765ustar00rootroot000000000000004ff029aee68d0d69ef9eb6efa6cbf1ec732f99000066400000000000000000000000351216214232500330450ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/1exKOR04e(,V̜TC.Wlibgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/1f/000077500000000000000000000000001216214232500252775ustar00rootroot0000000000000081433e3161efbf250576c58fede7f6b836f3d3000066400000000000000000000004061216214232500323730ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/1fx+)JMU062f040031QHLIIMM,.I-+(aP<9 w|S7݅&0%E驉I9`8B߭)y'뜇*NHKTְ:e Ikwgi7˴SsftykXytB4d&d楃KPZC'g$楧f&%%g5qYeZokM2ԐX\ZDPC~^ZNfrIf^:XZHي1O(_,' jvn~JfZ&5&R2;G{[,, T_?i?>AƠm{w15 :c_fゅk/j( 8?!_z4ǒVf^,Ɨlibgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/21/000077500000000000000000000000001216214232500252135ustar00rootroot00000000000000671e290278286fb2ce4c63d01699b67adce331000066400000000000000000000001171216214232500321360ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/21x+)JMU07a040031QHI5+(a]18:E9ov$EF`E!e&뿐_g'Oh_libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/22/000077500000000000000000000000001216214232500252145ustar00rootroot000000000000007792b52aaa0b238bea00ec7e509b02623f168c000066400000000000000000000001461216214232500322450ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/22xA 0 =DF7xYؤ%agi8DQ1#=gFs7ޖD$b npXۯ_=libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/23/000077500000000000000000000000001216214232500252155ustar00rootroot000000000000003c0919c998ed110a4b6ff36f353aec8b713487000066400000000000000000000000531216214232500322230ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/23xKOR0d(,VHIU҉))) y %E\g ^92a2dacc9efb562b8635d6579fb458751c7c5b000066400000000000000000000002161216214232500323740ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/23x !}S6Y9Hc6-Kan{o2VA3T %} 99}pՈv<9*JJ&uɣsI+GҐMH ŇK>=>V#aHz};2lDlibgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/24/000077500000000000000000000000001216214232500252165ustar00rootroot000000000000001a1005cd9b980732741b74385b891142bcba28000066400000000000000000000001031216214232500317500ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/24xKOR010g(,V(QHJU(JKMMQS(H,*JKQHM,F>J2591eb280ee9eeb2ce63524b9a8b9bc4cb515d000066400000000000000000000000361216214232500325130ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/24xKOR04c(,VTC.^"90b9f1a079420870027deefb49f51d6656cf74000066400000000000000000000004141216214232500321500ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/24x+)JMU062`040031QH,-M-JOMLI+(axgpRnH;YYoX^7W̋-libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/25/000077500000000000000000000000001216214232500252175ustar00rootroot000000000000009d08ca43af9200e9ea9a098e44a5a350ebd9b3000066400000000000000000000005751216214232500324370ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/25x+)JMU013d040031QHLIIMM,.I-+(aP<9 w|S7݅&0%E驉I9`8B߭)y'71 ݔ̢bS͌|f(%|509#1/₤ļ s\pqwvSLk15 9YjM}]nٱG:-LC~^ZNfrIf^:lUS+W ^oK=Ҕxpx0 .ge^ejk`j2ڷLJJ^e*W[k !~N˄K;bڮ_t/]"1PRs0|'UB'zq/.TC)0Xvz֛9MՅ'6bc40b7660c08c8fb581f770312f41b9b03119d1000066400000000000000000000000371216214232500320370ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/25xKOR04eHLIIMQS(LI5Vlibgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/26/000077500000000000000000000000001216214232500252205ustar00rootroot00000000000000153a3ff3649b6c2bb652d3f06878c6e0a172f9000066400000000000000000000000601216214232500322160ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/26xKOR06bOLLMQSP/),L54M*JKP libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/27/000077500000000000000000000000001216214232500252215ustar00rootroot00000000000000133da702ba3c60af2a01e96c2555ff4045d692000066400000000000000000000000401216214232500321630ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/27xKOR04cHIOLIIMQHI_]libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/2b/000077500000000000000000000000001216214232500252745ustar00rootroot000000000000000de5dc27505dcdd83a75c8bf1fcd9462cd7add000066400000000000000000000002231216214232500330100ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/2bx+)JMU046g01 ݔ̢b%.QdrکOuĔUwY!3ӠJ24*47I 6s[՝džf&& i9z%% ]k-6*:I=L F65f1f181ee3b58ea751f5dd5d8f9b445520a136000066400000000000000000000000651216214232500323570ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/2bxKOR016a(,V(QHJU(JKMMQS(H,*tfEd0a343aeef7a2cf0d158478966a6e587ff3863000066400000000000000000000000701216214232500323710ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/2bxKOR01b(,VHIUy) y IEy y) %E\libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/2d/000077500000000000000000000000001216214232500252765ustar00rootroot00000000000000a538570bc1e5b2c3e855bf702f35248ad0735f000066400000000000000000000002441216214232500322660ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/2dxK 1D]N"n{t:L$ UEQ>~7:L D [5ɇ,y2eT@z*.([žunum_|Št@ apg%haJYծA8թ훠fN4;h[%cOuJWyΏ598248eeccfc27e5ca44d9d96383f6dfea7b16000066400000000000000000000004101216214232500326240ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/2fx+)JMU067c040031QH,-M-JOMLI+(aH:,:C: o>ZC'g$楧f&%%g5qYeZokM2ԐX\ZDPC~^ZNfrIf^:XZHي1O(_,' jvQjn~13zדm9Wu]:$I{| 2mg˾15ӿ,\})TC)0Pavz֛9MՅ'6blibgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/31/000077500000000000000000000000001216214232500252145ustar00rootroot0000000000000068dca1a561889b045a6441909f4c56145e666d000066400000000000000000000002441216214232500320060ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/31xQ 0D)rJMxMHz}xfރaRYipkUD $1fQ2q-=Y3R76ġg9e7 bw GJe*˽ |ůSY"5&Нƨng9Z3_;kdOd5472536041a83d986829240bbbdc897c6f8a6000066400000000000000000000000511216214232500320670ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/31xKOR02g,VHIUy y %z\ libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/32/000077500000000000000000000000001216214232500252155ustar00rootroot0000000000000021dd512b7e2dc4b5bd03046df6c81b2ab2070b000066400000000000000000000000571216214232500323700ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/32x+)JMU06d040031QK-g\AיUDxc;Ѣ#_ {libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/33/000077500000000000000000000000001216214232500252165ustar00rootroot0000000000000046d64325b39e5323733492cd55f808994a2475000066400000000000000000000000411216214232500315720ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/33xKOR04gK-WHIUSP74VbBd500f588fbbe65901d82b4e6b008e549064be0000066400000000000000000000002431216214232500322110ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/33xA E]s .hbo.Z x}[ ~kCA<:km`d̑d,!:𦐳P1P qHccHEO[zsK>y>隿ïm6*Rn>Olibgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/34/000077500000000000000000000000001216214232500252175ustar00rootroot00000000000000bfafff88eaf118402b44e6f3e2dbbf1a582b05000066400000000000000000000002611216214232500326430ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/34xKj1D) >`7A. $<`Morlm4G&dVd[j2JCъgu_Gu%2:3XزQ'";?wpkm׾&Pf! %QJ%:Cez=6q;iOlibgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/35/000077500000000000000000000000001216214232500252205ustar00rootroot000000000000000c6eb3010efc403a6bed682332635314e9ed58000066400000000000000000000001341216214232500321760ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/35x+)JMU4d040031QHLIIMM/+(aXα)xo@nU CW\jVz,@O;7J^'$411bfb77cd2cc431f3a03a2b4976ed94b5d241000066400000000000000000000000371216214232500323340ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/35xKOR04eHLIIMQS(LI5V4704d3613ad4228e4786fc76656b11e98236c4000066400000000000000000000000511216214232500317250ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/35xKOR02eOLLMQSP/),L54Ta A632e43612c06a3ea924bfbacd48333da874c29000066400000000000000000000002411216214232500322570ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/35xN !LdMb60^,40;iUFf+)1vB939fG(DIݸʵA$sk]l|L{Ig$m.N5y.\a/]|Ʋ@[g4< Hl?gTsˠzCP75826c96a975031d2c14368529cc5c4353a8fd000066400000000000000000000002431216214232500320110ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/35x] 0})rn"x/I6`Qoo0.7f ٌC$<0uYܨڥ3c1gUa y[i.S(ѧ9eyr (57 ^%.}AۮB5=+7Ms,Ia Old|libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/3e/000077500000000000000000000000001216214232500253005ustar00rootroot00000000000000f4d30382ca33fdeba9fda895a99e0891ba37aa000066400000000000000000000000441216214232500326560ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/3exKOR02b(,VTKԴM. f9bfe82f9635518ae89152322f3b46fd4ba25b000066400000000000000000000002541216214232500323720ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/3exM ]s .9S< +z_f}]Z]eO:wzރP.ިaNU6Olibgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/43/000077500000000000000000000000001216214232500252175ustar00rootroot00000000000000aafd43bea779ec74317dc361f45ae3f532a505000066400000000000000000000000451216214232500324250ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/43xKOR02f(,VT3M.2 c338656342227a3a3cd3aa85cbf784061f5425000066400000000000000000000004121216214232500320410ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/43x+)JMU064g040031QH,-M-JOMLI+(axgpRnH;YAƠm{wJ%O|׳4ͱ$nկ.< hlibgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/47/000077500000000000000000000000001216214232500252235ustar00rootroot000000000000006dbb3e207313d1d8aaa120c6ad204bf1295e53000066400000000000000000000010121216214232500323070ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/47x+)JMU03b040031Q0HMHKO+(a8v›SRMegkޝulLmnQjyQfIIjnfn~iQ1Xχs}m s>9dLO2L.0!Fk BbOܪxZx[C.D=)%./|Eyqv+~bNdn]ժa:@ރ[ ZoUXΞnT"]b)g#jK=ڷ<. ͠zmM/ktbio1[-$%1'%5'3t$Nf˼_cٔ|>>03gg{ ݺ F-Sf`#1%#'mZŭM]l${ \7WuliKǷUABS 5Tb4-5_ۚ 2ܡd83%Ui*g%GĦm_?9w%E hK=ĤIkWNGlƞrJP@ ?2KL *D9ijZ s@{K'.zf%lAHpњ0SP 8||usU6uu>{'mUmz$ 04n36Ҏvr+nπ.\YL +886e602529caa9ab11d71f86634bd1b6e0de10000066400000000000000000000000701216214232500323420ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/4exKOR01b(,VHIUy) y %E y) IEy\b04c9e79e88f6640d01ff5b25ca2a60764f216000066400000000000000000000000421216214232500322760ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/4exKOR0`HHKOMQSH*JKrlibgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/4f/000077500000000000000000000000001216214232500253025ustar00rootroot00000000000000e93c0ec83eb6305cbace3dace88ecee1b63cb6000066400000000000000000000002411216214232500331450ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/4fxQ 0D)r&lxfCkFxf HkwZbu@ǽB)w%BR̃7+CQCd4bզs~eAW~KazYz3&u|ENlibgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/50/000077500000000000000000000000001216214232500252155ustar00rootroot0000000000000012fd565b1393bdfda1805d4ec38ce6619e1fd1000066400000000000000000000000351216214232500324260ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/50xKOR04e(,VTs.W4f75ac95a71ef98051817618576a68505b92f9000066400000000000000000000001351216214232500317500ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/50x+)JMU`040031QK--+JI,IM1+(axGƟg:I F` S=gF?,I&G@mt;;ytޚNlibgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/51/000077500000000000000000000000001216214232500252165ustar00rootroot0000000000000095a1b480f66691b667f10a9e41e70115a78351000066400000000000000000000002521216214232500317140ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/51x 0D9 7d;:zQ"cP*6PYIUf: `\P:avd^!Yqk qp.SDŽ},٦R9fy(cThS//SYe'+~mrh\cQwFMQϙ]b5M Rlibgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/53/000077500000000000000000000000001216214232500252205ustar00rootroot00000000000000825f41ac8d640612f9423a2f03a69f3d96809a000066400000000000000000000002441216214232500320620ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/53x 1C94hM$ 3ѮD6(h耛lYsͮ7"N f!xkRsœIpF[aQhR&Q6&)2Km^%~Yj׍hЏ:7}ȅ2Rg;9z[N;P]libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/54/000077500000000000000000000000001216214232500252215ustar00rootroot00000000000000269b3f6ec3d7d4ede24dd350dd5d605495c3ae000066400000000000000000000002401216214232500325160ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/54xK 1D]I7 LӌL$FxwUAQj m'؍^v9 d- Ɯ \ ϽC'&`"Ĺ(֡9_sg}]Z}UF?\I&@mt;;ʟ3hzN59c89aa0026d543ce8343bd89871bce543f9c2000066400000000000000000000002371216214232500322350ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/54x !D ,,,,9O bl؁3%mY.C[LEtd`\ %aBH%TvB G%Qphq]nCgP3B(H14yS)W;IVsT^܋>myJ?(_kܖ6-$#-Zzvȟ3 :NqMB7607c690372fe81fab8e3bb44c530e129118fd000066400000000000000000000000721216214232500322160ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/54xKOR01a(,"̜T#.ļ<̔T#M.libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/55/000077500000000000000000000000001216214232500252225ustar00rootroot00000000000000b4e4687e7a0d9ca367016ed930f385d4022e6f000066400000000000000000000002551216214232500322300ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/55xQj0DSZvJ \N 7㷱d-{LX' vm*{Z`$U9-TN{,}Kyuۣ78A_Sv.EQgSsxZZX MNRilibgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/56/000077500000000000000000000000001216214232500252235ustar00rootroot000000000000006ab53c220a2eafc1212af1a024513230280ab9000066400000000000000000000002371216214232500321330ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/56x !D ,˱1؁ ,LD bl؁3%Ihft ١XvY`L2М՝܆NsIbRЧL3Ra$Is,S~qh7~QvՃ6!-Zzvȟ3 :9M&a638b76b75e068590ac999c2f8621e7f3e264c000066400000000000000000000002551216214232500321740ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/56xAj!Eu vuWB6s%6qΐ$^Rb[{=coj'|褯UjeKLnn5СPY|2`zzQ{libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/57/000077500000000000000000000000001216214232500252245ustar00rootroot00000000000000079a46233ae2b6df62e9ade71c4948512abefb000066400000000000000000000002501216214232500324350ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/57xI!E]s .bHq "݋n COuYACoD\Cq &tg[ @γghv5["RR C0&9J+ >oZ.[]FUW;\T"ÏF:vx`ǰ\ۜ O"libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/58/000077500000000000000000000000001216214232500252255ustar00rootroot0000000000000043febcb23480df0b5edb22a21c59c772bb8e29000066400000000000000000000001071216214232500325040ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/58xKOR026d0շTK-VH,JUSH*,VHJKsSSrR装`Se853f66699fd02629fd50bde08082bc005933a000066400000000000000000000002401216214232500321460ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/58x 0D9 7Z?JqX%1}n3IIktpMD cbgy"&9l=Hzpk?@Z˂1)gLrFoLQϵ[~q>ײUetS墍r~˟3j[z! NPlibgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/59/000077500000000000000000000000001216214232500252265ustar00rootroot000000000000006803b523203a4851c824c07366906f8353f4ad000066400000000000000000000002431216214232500316360ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/59x] 0})rn "x/n6`Qoo 2 Ce]&V%X90rMJ92#xђ'-Vޚ$>4kmg(>(GP8&m.U+$/sYeN-~iOe=JV! 8i?\u@# O libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/5c/000077500000000000000000000000001216214232500253005ustar00rootroot000000000000002411f8075f48a6b2fdb85ebc0d371747c4df15000066400000000000000000000000451216214232500323540ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/5cxKOR02f(,VTCM. 341ead2ba6f2af98ce5ec3fe84f6b6d2899c0d000066400000000000000000000000451216214232500327510ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/5cxKOR02f(,VT#M. 3b68a71fc4fa5d362fd3875e53137c6a5ab7a5000066400000000000000000000000501216214232500324320ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/5cxKOR02c(,V<". libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/5d/000077500000000000000000000000001216214232500253015ustar00rootroot00000000000000c1018e90b19654bee986b7a0c268804d39659d000066400000000000000000000002501216214232500321530ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/5dxM 0]ɴ $3]4 {?ʲMg2K"!v9GV z/$90#v(ՇB1`N5AWJ7zJ>e+UjRs0~'UB'zq/.TC)s`M>!_z4ǒVf^,)Ylibgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/5f/000077500000000000000000000000001216214232500253035ustar00rootroot00000000000000bfbdc04b4eca46f54f4853a3c5a1dce28f5165000066400000000000000000000004331216214232500326500ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/5fx+)JMU010c040031QHHKOMM*JK+(aXˤގ״eZӍ!7$̼t+6==cP8YNt2 I{| 2mg˾115ӿ,\})\C^b.S["dp;"E4TU. [2u}uFSi 1Usջor8o-UY _ppZC'g$楧f&%%g5qYeZokM2ԐX\Z xo5æ˾.fXʣ[!?/-'3$3/M-lEϘ'/NUZ_?i?>AƠm{w15 9&:c_fゅk/j(aSN|׳4ͱ$nկ.< /libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/61/000077500000000000000000000000001216214232500252175ustar00rootroot00000000000000340eeed7340fa6a8792def9a5938bb5d4434bb000066400000000000000000000001341216214232500324420ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/61x+)JMU4d040031QHLIIMM/+(ai@{tj陿=o+.LI5V=]pkC}ǝ %/o#78885b38fe96e825ac0f492c0a941f288b37f6000066400000000000000000000004411216214232500321730ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/61x+)JMU066d040031QH,54`as19F`,^#0cp^y7%D=jI9E]9O [aGc];/OddH:-fI;;_}f/OI5dVѯܓ6>uIKwrުvb:A] D z{vN -Qks2 *Lʒ<0irpk(mH@Ĕ᚛⯚#焬[bbQhlibgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/62/000077500000000000000000000000001216214232500252205ustar00rootroot0000000000000012c31dab5e482247d7977e4f0dd3601decf13b000066400000000000000000000000551216214232500323440ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/62xKOR021f(,VHIU҉%E驉I9\U -9\,269111c3b02a9355badcb9da8678b1bf41787b000066400000000000000000000004151216214232500322670ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/62x+)JMU062`040031QH,-M-JOMLI+(axgpRnH;Yڢ2 I{| 2mg˾ P د`O|׳4ͱ$nկ.< a2c4f6533c9a3894191fdcb96a3be935ade63f1a000066400000000000000000000000651216214232500324470ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/62x+)JMU06c040031QHI+(a([ͧ!Yw0]m-~78libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/63/000077500000000000000000000000001216214232500252215ustar00rootroot00000000000000247125386de9ec90a27ad36169307bf8a11a38000066400000000000000000000002171216214232500320560ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/63xݏ;1 D}AV\8HIVp|?LyOuN7C] ͥlt:iA(xip,O;o7 UYZ Bý]dUmyk[cͥ)!X{Zlibgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/67/000077500000000000000000000000001216214232500252255ustar00rootroot0000000000000018a45909532d1fcf5600d0877f7fe7e78f0b86000066400000000000000000000002531216214232500321710ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/67xM1 DNi`ǹDB~ǧ]ݠY74M8ZC'g$楧f&%%g5qYeZokM2ԐX\ZDPC~^ZNfrIf^:XZHي1O(_,' jv^jnb^nqb.&/(nr yyG#jRs0~'UB'zq/.$Xg,?+Lr{\pMVP '>YoX^7W̋!ۓlibgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/6b/000077500000000000000000000000001216214232500253005ustar00rootroot000000000000007e37be8ce0b897093f2878a9dcd8f396beda2c000066400000000000000000000000651216214232500326340ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/6bx+)JMU06c040031QHI+(aXfr۩]}g)Dylibgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/6c/000077500000000000000000000000001216214232500253015ustar00rootroot0000000000000006dcd163587c2cc18be44857e0b71116382aeb000066400000000000000000000000361216214232500322650ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/6cxKOR04aH/OLLMQ~'libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/6f/000077500000000000000000000000001216214232500253045ustar00rootroot0000000000000032739c3724d1d5f855299309f388606f407468000066400000000000000000000011661216214232500316240ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/6fx+)JMU0401f040031Q0HMHKO+(a8v›SRMegkޝulLmnJiANfrbIjnfn~iQ1XӇs}m s>9dBSQjyQfIIjeﲽxR]|/NB~v0=ɺ(zJ2R36?)$և [.}-'T!+y0{tSS2NE2wܸhu x"0#N#޻p%OÉ-Z 7LGЩ ;ZxL. Y'ܙgYr-z7KB3#d&d5w:l d4tԘMP Ƙ: e/lJ>TT~KN&f$  I[Vq+wbxS0)^fB7X'vwzNzya׏ `J.ΊzRVCeE} :S7ԅ)Xt>o8;zy s8EJE7U]N4Pj.()P$_n*lt]NsTř)F`6s篜\sgA X5UoQ:rTV~]LTeOa33014764bf1120a454eb8437ae098238e409b000066400000000000000000000002501216214232500320400ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/6fx+)JMU00c040031QH,-M-JOMLI+(aPwpa7kL_qx2{Tqr~^ZNfrIf^:X,%[}ISJRu3tKRsKRS Gb}ZC'g$楧f&%%g5qYeZokM2ԐX\ZDPC~^ZNfrIf^:XZHي1O(_,' jvQjn~1%6AFA;"wâ?i?>AƠm{w15 =:c_fゅk/j(8|.?!_z4ǒVf^,E>2ebba6669ea847d9829e4f1059d6c830c8b531000066400000000000000000000002301216214232500322320ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/71xA@E])8m\4< $S/F 62\/0@;)O-j΀Z7%};Laor>fNczzCO?")Ď`STr*Φ} F add2d7b93d55bf3600f8a1582beceebbd050c8000066400000000000000000000004101216214232500326340ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/71x+)JMU067c040031QH,-M-JOMLI+(aH:,:C: o>ZC'g$楧f&%%g5qYeZokM2ԐX\ZDPC~^ZNfrIf^:XZHي1O(_,' jvQjn~1ΙÝc|Ӎ-ݳ'2ajArǟW q cжqƽ컘c\ȯX3q5YQۗB5F`ןgicIz_]xb3/ˏlibgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/74/000077500000000000000000000000001216214232500252235ustar00rootroot00000000000000df13f0793afdaa972150bba976f7de8284914e000066400000000000000000000000321216214232500323670ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/74xKOR04`H/PH,*6libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/75/000077500000000000000000000000001216214232500252245ustar00rootroot00000000000000a811bf6bc57694adb3fe604786f3a4efd1cd1b000066400000000000000000000002421216214232500325760ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/75xK 1D]Hk "nH;̀3 UEQk7  !7Xdc2R[jtMv :q.cD* l(ң3Rc}|>J?$_k[Q,"Zz˟39 LOlibgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/76/000077500000000000000000000000001216214232500252255ustar00rootroot0000000000000063fce0130db092936b137cabd693ec234eb060000066400000000000000000000000611216214232500322520ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/76xKOR06e(,V̜T̴<M.0U ab0e2868197ec158ddd6c78d8a0d2fd73d38f9000066400000000000000000000000451216214232500324670ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/76xKOR02f(,VTKM.P libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/7a/000077500000000000000000000000001216214232500253005ustar00rootroot00000000000000a3edf2bcfee22398e6b55295aa56366b7aaf76000066400000000000000000000004171216214232500326100ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/7ax+)JMU067f040031QH,-M-JOMLI+(aH:,:C: o>ZC'g$楧f&%%g5qYeZokM2ԐX\ZDPC~^ZNfrIf^:XZHي1O(_,' jvn~JfZ&5%\}#O6.rH(57 ^%.}Aۮbj@r|ur#b/ dEm_ P p~Ci%u?~uͼXl[libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/7c/000077500000000000000000000000001216214232500253025ustar00rootroot000000000000002c5228c9e90170d4a35e6558e47163daf092e5000066400000000000000000000002541216214232500321460ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/7cxIN1 9ȉ,B\HgѴD(|7p+աTE8/k VQĥD:w><۱ f$JڙpHsd!m.|_7UyV8v?{zj_oEX8AxEA4FWG\y4(z,<NNb63eed597130ba4abb87b3e544b85021905520000066400000000000000000000002411216214232500321750ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/7cxK 1D]t'"nH:L$FxwUAQܖ6f7IT*zJ 1#;@rX]ꞺC3A F'aj#Tf acn]_+s[mG'+~m9i PFCQge"Nlibgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/7e/000077500000000000000000000000001216214232500253045ustar00rootroot000000000000002d058d5fedf8329db44db4fac610d6b1a89159000066400000000000000000000002451216214232500325260ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/7ex] 0})rn 7i~h6^(@e&u]TĻVSs#'Rg6RhK9@V|M[<zbhO18E6ffGm.U(/sYeǝҷ}(QfH(0~?gDsIMslibgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/7f/000077500000000000000000000000001216214232500253055ustar00rootroot000000000000007a2da58126226986d71c6ddfab4afba693280d000066400000000000000000000003071216214232500324420ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/7fxO;NE!ft '1 0x-FW`sr~9fM|pIlt -U.#r#A+QyʹtFj8&2גKUm+ хf"aNbP]*cLT?:N}/f;Ao!sK9e.3|\E}$`libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/80/000077500000000000000000000000001216214232500252205ustar00rootroot00000000000000a8fbb3abb1ba423d554e9630b8fc2e5698f86b000066400000000000000000000002501216214232500325150ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/80xK 1D]|:7d:=12F z:][Dt] I̝:f[RFQϼȣh$0[ƄH#*T})}և>Jt߰Γ$:g&$fӨ2{>N/libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/81/000077500000000000000000000000001216214232500252215ustar00rootroot0000000000000087117062b750eed4f93fd7e899f17b52ce554d000066400000000000000000000002521216214232500322460ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/81x[j0DUhPB~n@kl* 3g0- j f,!d!!%FX" ŦG2 9pfgb1Gϵ:_l\EB@dx38Em{lkB7_UPlibgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/83/000077500000000000000000000000001216214232500252235ustar00rootroot0000000000000007d93a155903a5c49576583f0ce1f6ff897c0e000066400000000000000000000000361216214232500321630ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/83xKOR04aK-WSH*JKP824a8c6658768e2013905219cc8c64cc3d9a2e000066400000000000000000000005761216214232500321040ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/83x+)JMU013`040031QHLIIMM,.I-+(aP<9 w|S7݅&0%E驉I9`8B߭)y'71 ݔ̢bBm~Gxۃ J.&B LHK (1/9lE/\&vܝn.ӚnL HNae_[vaѭN }Ӑ\6ۯ#/AUՂے/n{pOxpp0\Z N aWUYĠ.TO۪<6ڕ sL]R$my&z~2 I{| 2mg˾ P p Ci%u?~uͼXlibgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/84/000077500000000000000000000000001216214232500252245ustar00rootroot000000000000009619b03ae540acee4d1edec96b86993da6b497000066400000000000000000000002431216214232500324600ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/84xK 1D]v7t3L$ UEVP ?@}!ׯ 9Ag5 [!2/( S>0q 1f`7vlC&ZLm{r)`y]Y.սmIWN/)ei-+%&g1%y䶕[v7Vlibgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/8a/000077500000000000000000000000001216214232500253015ustar00rootroot00000000000000ad9d0ea334951da47b621a475b39cc6ed759bf000066400000000000000000000000631216214232500325200ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/8axKOR06g(,D̜T.ļ<̔TCM.D"ae714f7d939309d7f132b30646d96743134a9f000066400000000000000000000004151216214232500320750ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/8ax+)JMU06`040031QH,-M-JOMLI+(aH:,:C: o>ZC'g$楧f&%%g5qYeZokM2ԐX\ZDPC~^ZNfrIf^:XZHي1O(_,' jv^j9!Ɖ9%`<sBާHrS3d Ң2 wI{| 2mg˾15ӿ,\})TC)00avʉz֛9MՅ'6bGlibgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/8b/000077500000000000000000000000001216214232500253025ustar00rootroot00000000000000095d8fd01594f4d14454d073e3ac57b9ce485f000066400000000000000000000003111216214232500323070ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/8bx=N1 st9q~ !J:.`'K [YnHSoEH7Rs)H"Y\)QR$&OAS:yałbk&,|%*\;V!Fm^=ԒZaΔbbF6}j}Iգ`&yVu7la5b53cb2aa9ceb1139f5312fcfa3cc3c5a47c9a000066400000000000000000000001351216214232500327130ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/8bx퐱 0 S{"2d,0^?&SH[8눪E`фrZ*drl, cbF/'gвlibgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/8c/000077500000000000000000000000001216214232500253035ustar00rootroot00000000000000749d9968d4b10dcfb06c9f97d0e5d92d337071000066400000000000000000000002411216214232500323230ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/8cxAB!C]s .acxf`|_ bh5m^mzL`}$26#"8`s.`ԝܺ.!bH\< i",K8ٗ_X>MeЏ:7]AC40뭙Q]Q\.,VOlibgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/8f/000077500000000000000000000000001216214232500253065ustar00rootroot000000000000004433f8593ddd65b7dd43dd4564d841f4d9c8aa000066400000000000000000000002441216214232500324650ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/8fxQ 0D)r&D^`k$FU30\eniUՒ"(G?<^qD4Q`nT,G2H)h(}b)rLGʆm*՞EUy*˽\^WIG_rYvJ׳M1ϙ. UPlibgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/90/000077500000000000000000000000001216214232500252215ustar00rootroot00000000000000a336c7dacbe295159413559b0043b8bdc60d57000066400000000000000000000004171216214232500322100ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/90x+)JMU067d040031QH,-M-JOMLI+(aH:,:C: o>ZC'g$楧f&%%g5qYeZokM2ԐX\ZDPC~^ZNfrIf^:XZHي1O(_,' jvn~JfZ&5`2[R\p]sKTgiCUa8OګυO1h8^]L HNX.W`ᚬKJSN|׳4ͱ$nկ.< P/libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/91/000077500000000000000000000000001216214232500252225ustar00rootroot000000000000002b2d7819cf9c1029e414883857ed61d597a1a5000066400000000000000000000004471216214232500321040ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/91x+)JMU063a040031QHLIIMM,.I-+(aP<9 w|S7݅&0%E驉I9`8B߭)y'뜇*NHKTְ:e Ikwgi7˴Ssrg;1iKL.Kבyjjm='UZfZX><՗9dBSQjyQfIIjeﲽxR]|/NB~v0=ɺ(zJ2R36?)$և [.}-'T!+y0{tSS2NE2wܸhu x"0#N#޻p%OÉ-Z 7LGЩ ;ZxL. Y'ܙgYr-z7KB3#d&d5w:l d4tԘMP Ƙ: e/lJ>TT~KN&f$  I[Vq+wbxS0)^fB7X'vwzNzya׏ ` 7P$_l_ۚ 2ܡUo xgB5mɹWN.ṳ[[}vVlQ:rTV~]LAeFDlibgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/93/000077500000000000000000000000001216214232500252245ustar00rootroot0000000000000077fccdb210540b8c0520cc6e80eb632c20bd25000066400000000000000000000000651216214232500323250ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/93x+)JMU06c040031QHI+(aPQZM璃gu>r:0?libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/94/000077500000000000000000000000001216214232500252255ustar00rootroot000000000000004f5dd1a867cab4c2bbcb896493435cae1dcc1a000066400000000000000000000002371216214232500326510ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/94xK!D]s .z7 |2. bhWKVmH0~7z"P9`:Qi)QLEyq=oC*P6-"4l0StAHp%OÉ-Z 7LGn^j9V3؍JK,;cZxy [~?%TaTI%` [>Y,->5fkdT16wBP3ٞfnDC|}QT&Ԃ+8SR0";:s es蒚Y0n 3ذӖTo:zj.ȷ6-5BNV7~ok6h:l{SWsJT̔T]CpmQ:rTV~]Lj6s篜\sgA fCfe7723802d4305142eee177e018fee1572c4f4000066400000000000000000000000441216214232500322220ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/9exKOR02b(,VTcԴM. libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/9f/000077500000000000000000000000001216214232500253075ustar00rootroot0000000000000074397a3397b3585faf09e9926b110d7f654254000066400000000000000000000011551216214232500320340ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/9fx+)JMU0401f040031Q0HMHKO+(a8v›SRMegkޝulLmnJiANfrbIjnfn~iQ1XӇs}m s>9dBSQjyQfIIjeﲽxR]|/NB~v0=ɺ(zJ2R36?)$և [.}-'T!+y0{tSS2NE2wܸhu x"0#N#޻p%OÉ-Z 7LGЩ ;ZxL. Y'ܙgYr-z7KB3#d&d5w:l d4tԘMP Ƙ: e/lJ>TT~KN&f$  I[Vq+wbxS0)^fB7X'vwzNzya׏ `J.ΊzRVCeE} :S`ův ]:r- */LXTu91ӠB) f8Cݒ|]#Dv|[AWfۛ"t};T:Qug}OΝrr ϝ-cVE]YRZfqw3UOlibgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/a0/000077500000000000000000000000001216214232500252715ustar00rootroot0000000000000031a28ae70e33a641ce4b8a8f6317f1ab79dee4000066400000000000000000000000451216214232500325000ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/a0xKOR02f(,VTsM.< libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/a3/000077500000000000000000000000001216214232500252745ustar00rootroot000000000000009a620dae5bc8b4e771cd4d251b7d080401a21e000066400000000000000000000000351216214232500323770ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/a3xKOR04e(,V̜T#.Wfabece9eb8748da810e1e08266fef9b7136ad4000066400000000000000000000002441216214232500326650ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/a3xQ D\f] 1x/,MbIf&u]HVs16Rړ"&(nI7!39-ő;"YdjBɅ £ͥ3Beyz/<~蔿OSYj`5,n?5幄렌xJIOolibgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/a4/000077500000000000000000000000001216214232500252755ustar00rootroot000000000000001b1bb6d0be3c22fb654234c33b428e15c8cc27000066400000000000000000000001341216214232500323770ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/a4x+)JMU4d040031QHLIIMM/+(aX=i5Nmm5UN ]qqfJ!X:G ?/,{;e%G<$3150a738849c59376cf30bb2a68348a83c8f48000066400000000000000000000002421216214232500320710ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/a4xK 1D]H:Dx/O"xM+(*ZCjk3KUfCRTɫ^dHT#v^)Sm 'K,k,ky^miVy◎ճ d IRbRk^%Nlibgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/a5/000077500000000000000000000000001216214232500252765ustar00rootroot00000000000000563304ddf6caba25cb50323a2ea6f7dbfcadca000066400000000000000000000000601216214232500330320ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/a5xKOR06a(,VTs̴<ԴM.!T llibgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/a7/000077500000000000000000000000001216214232500253005ustar00rootroot0000000000000008b253bd507417ec42d1467a7fd2d7519c4956000066400000000000000000000000501216214232500321350ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/a7xKOR06cHLIIMQSH/Bigir>k 65fb87eb2f7a1920b73b2d5a057f8f8476a42b000066400000000000000000000002521216214232500323630ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/a7xI!E]s .)h!1ƍ7po.1 S^>y mߌ.a1H̹3Pr!0%P՝,Ci+*u)Wb10縶OE͏转G[܎|fB%oDž%͖)kmpKZß ]ײqGµBYDӤ]~PQ=?6Wڡ>Q87dd39ad3edd610fc9083dcb61e40ab50673d1000066400000000000000000000004251216214232500325070ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/a8x+)JMU067a040031QH,-M-JOMLI+(aH:,:C: o>ZC'g$楧f&%%g5qYeZokM2ԐX\ZDPC~^ZNfrIf^:XZHي1O(_,' jv^jnb^nJfZZjQj^ X#3|>^U:'A2R2 I{| 2mg˾15ӿ,\})TC)0H!vʉz֛9MՅ'6bGxlibgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/a9/000077500000000000000000000000001216214232500253025ustar00rootroot000000000000000bc3fb6f15181972a2959a921429efbd81a473000066400000000000000000000002401216214232500322160ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/a9xK 1D]};7d=oo^UQT\;hk6@g 5rѓ]uOMndgz&c圈'} NJ7p?(G\8CآGTg9x$faxN"libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/ab/000077500000000000000000000000001216214232500253535ustar00rootroot0000000000000040af3cb8a3ed2e2843e96d9aa7871336b94573000066400000000000000000000002411216214232500323570ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/abx !D p,ab?v`0EcͼIfj)]o%Id\rLyA'. D S&Ap5y3 3 } '$d<ϾԦ[ַă~ԅa>ug;YXx Pe6c44a2e84492ad4b41bb6bac87353e9d02ac8b000066400000000000000000000000411216214232500325510ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/abxKOR04g,LQ(J-,m929391ac42572f92110f3deeb4f0844a951e22000066400000000000000000000000501216214232500322010ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/abxKOR06cHLIIMQSH/(LI5B7 libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/ac/000077500000000000000000000000001216214232500253545ustar00rootroot000000000000004045f965119e6998f4340ed0f411decfb3ec05000066400000000000000000000000351216214232500323560ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/acxKOR04e(,V̜TS.Wlibgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/ad/000077500000000000000000000000001216214232500253555ustar00rootroot00000000000000a14492498136771f69dd451866cabcb0e9ef9a000066400000000000000000000000471216214232500323750ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/adxKOR02e(,ļ"r̜T. a55a45d14527dc3dfc714ea1c65d2e1e6fbe87000066400000000000000000000004161216214232500326500ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/adx+)JMU067d040031QH,-M-JOMLI+(aH:,:C: o>ZC'g$楧f&%%g5qYeZokM2ԐX\ZDPC~^ZNfrIf^:XZHي1O(_,' jvn~JfZ&5`nלU7 V.6t6L/R2 I{| 2mg˾15ӿ,\})TC)0<vʉz֛9MՅ'6bN*libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/b2/000077500000000000000000000000001216214232500252745ustar00rootroot00000000000000d399ae15224e1d58066e3c8df70ce37de7a656000066400000000000000000000002371216214232500323710ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/b2xQA1+xċϡ-kI*5f/z af!^/WJcܤ5Lƛ;+B6HZP|`h>\($sX@75}57K += ;g @!4!,\$\ \b/Hs#aQlibgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/b4/000077500000000000000000000000001216214232500252765ustar00rootroot000000000000002712cfe99a1a500b2a51fe984e0b8a7702ba11000066400000000000000000000001371216214232500323260ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/b4xA {B{M1 ߯>P3F֎7E02 X0̒,)$;:ܷ(:f610aef53bd343e6c96227de874c66f00ee8e8000066400000000000000000000002421216214232500324520ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/b6xK!D]s .i7 i2./9WKVmHm`7:  h@\*[6g#tI%K% IXTV-$O9rE/XDxuyг>]yo:o!zjA:γX4ѬUMalibgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/b7/000077500000000000000000000000001216214232500253015ustar00rootroot00000000000000a2576f9fc20024ac9ef17cb134acbd1ac73127000066400000000000000000000005001216214232500324640ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/b7x+)JMU0d040031QHLIIMM,.I-+(aP<9 w|S7݅&0%E驉I9`8B߭)y'뜇*NHKTְ:e Ikwgi7˴SsftykXytB4d&d楃KPAƠm{wJ^m'>YoX^7W̋slibgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/b8/000077500000000000000000000000001216214232500253025ustar00rootroot00000000000000a3a806d3950e8c0a03a34f234a92eff0e2c68d000066400000000000000000000004361216214232500324240ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/b8x+)JMU066d01"]CnaU8:YGa*BôSDg޴.~+ysL?Iu}u "-ZhulۻwVݙ,  :|<] 4Ff&& i9 r4=|?oe?)֟ˆa$u'libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/ba/000077500000000000000000000000001216214232500253535ustar00rootroot00000000000000cac9b3493509aa15e1730e1545fc0919d1dae0000066400000000000000000000000351216214232500324060ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/baxKOR04e(,V̜T.Wlibgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/bc/000077500000000000000000000000001216214232500253555ustar00rootroot00000000000000744705e1d8a019993cf88f62bc4020f1b80919000066400000000000000000000002421216214232500321410ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/bcxK 1D]}%%tYH& UJuj7:P(#F̄ģ1+k#vΚS8W|٨%Kpɯ3\Vv#MQg?wH@(c s9t 嶭{kO95c75d59386147d1e79a87c33068d8dbfd71f2000066400000000000000000000005341216214232500323330ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/bcx+)JMU015b040031QH,-M-JOMLI+(axgpRnH;YLF`n}O/gx尶US1XUwU3mMv=1؏ejMj?ͫ:!T`2OzYO-J/?i?>AƠm{wJ o'>YoX^7W̋絷libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/bd/000077500000000000000000000000001216214232500253565ustar00rootroot00000000000000593285fc7fe4ca18ccdbabf027f5d689101452000066400000000000000000000002371216214232500325200ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/bdx !=S hY11Ƌ 3Y,ؾhR-޵7fm`Ѳ'Ap&@ ]'4AYIqAN*>RWlYߖZ.-~j9k B8ƨĨQoO9867fbae2faa80b920b002b80b1c91bcade7784000066400000000000000000000000601216214232500326260ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/bdx+)JMU06d040031QK-gQlq{xݏ8 9cb4cd0a770cb9adcb5fce212142ef40ea1c35000066400000000000000000000000631216214232500327600ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/bdxKOR01aHHKOMQSM,.I-J)W@NKM*JKZlibgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/be/000077500000000000000000000000001216214232500253575ustar00rootroot00000000000000f6e37b3ee632ba74159168836f382fed21d77d000066400000000000000000000002171216214232500323770ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/bexK 1D]}3?Ač7p?$=`Ґx}Gރ`)+0ѮUh.NWޓ!Idljzlibgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/c4/000077500000000000000000000000001216214232500252775ustar00rootroot00000000000000efe31e9decccc8b2b4d3df9aac2cdfe2995618000066400000000000000000000010321216214232500331620ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/c4x+)JMU01e040031Q0HMHKO+(a8v›SRMegkޝulLmnJiANfrbIjnfn~iQ1XӇs}m s>9dBSQjyQfIIjeﲽxR]|/NB~v0=ɺ(zJ2R36?)$և [.}-'T!+y0{tSS2NE2wܸhu x"0#N#޻p%OÉ-Z 7LGЩ ;ZxL. Y'ܙgYr-z7KB3#d&d5w:l d4tԘMP Ƙ: e/lJ>TT~KN&f$  I[Vq+wbxS0)^fB7X'vwzNzya׏ ` -< uKu ƯmM_moqP 4CYkv/̟;;ZgǪ z*g%]Jlibgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/c5/000077500000000000000000000000001216214232500253005ustar00rootroot000000000000000d0f1cb60b8b0fe1615ad20ace557e9d68d7bd000066400000000000000000000002571216214232500326430ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/c5xKj1D)t4l|>-f 9UV61:̸ !>Z.P0x hhQ+t`1NZe,X[ =vyI_vJ^2$?I7o4{K>V!~|U=bbe550b9f09444bdddd3ecf3d97c0b42aa786c000066400000000000000000000004151216214232500327330ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/c5x+)JMU062`040031QH,-M-JOMLI+(axgpRnH;Y,af<EZȳ5%<'.v,;]=2tws-,w8@92ecf62007c0ac9fb26e2aa884de2933de15ed000066400000000000000000000000501216214232500325660ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/c6xKOR02aJ/KMQSP74M*JKP; libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/c8/000077500000000000000000000000001216214232500253035ustar00rootroot00000000000000f06f2e3bb2964174677e91f0abead0e43c9e5d000066400000000000000000000000551216214232500325230ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/c8xKOR06d(,VHIUҥyy) y I%\ 3libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/c9/000077500000000000000000000000001216214232500253045ustar00rootroot00000000000000174cef549ec94ecbc43ef03cdc775b4950becb000066400000000000000000000002431216214232500327460ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/c9xQ 0D)rfnSxfCHx}xfc,˵Y kUb8pu`%|@r3GtB;W]!z'%QiӐdT ?\=d/sYe';^r#l`6m Z7U^e6oVO4b27e41064c521120627e07e2035cca1d24ffa000066400000000000000000000002421216214232500321570ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/c9xK 1D]Ig@č7p/tYLze]VEtr 7gK,8Шro:Y]@A09Oc FWR%|M:u+w}N?,'mz@u6SRmK޽ONlibgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/ca/000077500000000000000000000000001216214232500253545ustar00rootroot00000000000000b2cf23998b40f1af2d9d9a756dc9e285a8df4b000066400000000000000000000000501216214232500326660ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/caxKOR05b(,VTSԴM.TQt.Alibgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/cb/000077500000000000000000000000001216214232500253555ustar00rootroot00000000000000491780d82e46dc88a065b965ab307a038f2bc2000066400000000000000000000002431216214232500322720ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/cbxK 1D]HӝDx/t12FxwUAQ[m=*)U f%H<`|HY{^64bt6rH3J\3HXXע/Ko~'+~mϽqhRHOj!ΨeʥHQoOk6693a788715b82440a54e0eacd19ba9f6ec559000066400000000000000000000000511216214232500323660ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/cbxKOR0d(NMUS0M)QHK3t3 libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/cc/000077500000000000000000000000001216214232500253565ustar00rootroot000000000000003e3009134cb88014129fc8858d1101359e5e2f000066400000000000000000000002441216214232500320500ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/ccx] 0})&_H -Fb[6}0L2wPzc*sXb Rt#G$[lvH$kf.ʧLF+ QHD|68Wl.S]uoNOu9Va0^ZF9^# Odlibgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/ce/000077500000000000000000000000001216214232500253605ustar00rootroot000000000000008860d49e3bea6fd745874a01b7c3e46da8cbc3000066400000000000000000000000601216214232500326010ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/cex+)JMU06d040031QK-g8nu*=u}oRe656c392ad0557b3aae0fb411475c206e2926f000066400000000000000000000000401216214232500323350ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/cexKOR04cJ/KMQSP7W]libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/cf/000077500000000000000000000000001216214232500253615ustar00rootroot000000000000008c5cc8a85a1ff5a4ba51e0bc7cf5665669924d000066400000000000000000000000351216214232500326070ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/cfxKOR04e(,VT3.Wlibgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/d0/000077500000000000000000000000001216214232500252745ustar00rootroot000000000000007ec190c306ec690bac349e87d01c4358e49bb2000066400000000000000000000001341216214232500323470ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/d0xՏ 0 3aOb%ǑS=HT@u:]uYG%LE;u`_?g~0Ҕ. ׋PӜxvXi ӭf!d4594e16f2e19107e3fa7ea63e7aaaff305ffb000066400000000000000000000000631216214232500326510ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/d0xKOR013a(,V(QHJU(JKMMQS/-*r@.libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/d2/000077500000000000000000000000001216214232500252765ustar00rootroot00000000000000f8637f2eab2507a1e13cbc9df4729ec386627e000066400000000000000000000004141216214232500324450ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/d2x+)JMU062`040031QH,-M-JOMLI+(axgpRnH;Y!_z4ǒVf^,r=libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/d4/000077500000000000000000000000001216214232500253005ustar00rootroot00000000000000207f77243500bec335ab477f9227fcdb1e271a000066400000000000000000000002451216214232500322630ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/d4xK 1D]O'7t:݌H&z:]oZBBXl(昭+d<"6^% A( J,% %5SSmR^؊Nu^뢏O:Wځ| DcFQEn6#Q27e0b2e138501a3d15cc376077a3631e15bd46000066400000000000000000000000461216214232500321070ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/d4xKOR02a(,VHIU҉ yi9%\ libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/d5/000077500000000000000000000000001216214232500253015ustar00rootroot00000000000000093787ef302b941b6aab081b99fb4880038bd8000066400000000000000000000000361216214232500322230ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/d5xKOR04aHLIIMQSH/Oha61b0b4992a4f0caa887fa08b52431e727bb6f000066400000000000000000000001211216214232500324160ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/d5x+)JMU07a040031QHI5+(a-:uں%~i]^?m;H 1axT< jo9 b6fc965c926a1bfc9ee456042b94088b5c5d21000066400000000000000000000004771216214232500323770ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/d5x+)JMU0d040031QHLIIMM,.I-+(aP<9 w|S7݅&0%E驉I9`8B߭)y'뜇*NHKTְ:e Ikwgi7˴SsftykXytB4d&d楃KPp%OÉ-Z 7LGn^j9V3؍JK,;cZxy [~?%TaTI%` [>Y,->5fkdT16wBP3ٞfnDC|}QT&Ԃ+8SR0";:s es蒚Y0n 3ذӖTo:zj) %F`U٠+M]>*PfЁ'̔T]C-B_Β 7Ïi VM`0rKx,?h~U?M462fa3f5292857db599c54aea2bf91616230c5000066400000000000000000000000601216214232500322210ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/d6x+)JMU06d040031QK-goʪ?krrꍦ Ucf6c7741b3316826af1314042550c97ded1d50000066400000000000000000000002041216214232500321170ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/d6xQ 1 D)r%i@oje[7̤ZʽMSLBNlm B~>-uY8ꠟt֯]Qa͠3f]>bl(A]libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/d8/000077500000000000000000000000001216214232500253045ustar00rootroot0000000000000074671ef5b20184836cb983bb273e5280384d0b000066400000000000000000000002421216214232500320620ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/d8xK 1D]H "nIZf1^Q\ezMDC V %Ą@lFSQ7nrfcˎS$3&!{ŏ>զŭT{Ꝭuk"IJ׳]Qϙ/CRo|Nfa77b6833082c1ea36b7828a582d4c43882450000066400000000000000000000001371216214232500320700ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/d8x1 DQkN1&6%lBknaa1kdI(Ur'7LA,+Wm9 I'U͹_ܰNlibgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/d9/000077500000000000000000000000001216214232500253055ustar00rootroot0000000000000063979c237d08b6ba39062ee7bf64c7d34a27f8000066400000000000000000000000601216214232500323200ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/d9xKOR06a(,V̜T#̴<ԴM.!Y klibgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/da/000077500000000000000000000000001216214232500253555ustar00rootroot00000000000000178208145ef585a1bd5ca5f4c9785d738df2cf000066400000000000000000000000511216214232500324500ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/daxKOR02g,VHIUy y %fz\ !libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/db/000077500000000000000000000000001216214232500253565ustar00rootroot000000000000006261a7c65c7fd678520c9bb6f2c47582ab9ed5000066400000000000000000000011601216214232500324510ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/dbx+)JMU0401g040031Q0HMHKO+(a8v›SRMegkޝulLmnQjyQfIIjnfn~iQ1XϦ3׉*F~y\|YLOnJiANfrbIj HSIFj&T~#Y'nU<-W!BUH v/Kf<k' Nl2L:0/1by)K(4N;YnbL#>p%OÉ-Z 7LGn^j9V3؍JK,;cZxy [~?%TaTI%` [>Y,->5fkdT16wBP3ٞfnDC|}QT&Ԃ+8SR0";:s es蒚Y0n 3ذӖTo:zj)qnˉg؛6sM[ L@O&p %˅^7ace1492648c9dc5701bad5c47af9d1b60c4e9000066400000000000000000000004101216214232500325120ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/e1x+)JMU06d040031QH,-M-JOMLI+(aH:,:C: o>ZC'g$楧f&%%g5qYeZokM2ԐX\ZDPC~^ZNfrIf^:XZHي1O(_,' jvQjn~1`xen+Z1C|/bErǟW q cжqƽ컘c\ȯX3q5YQۗB5C8`gicIz_]xb3/Flibgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/e2/000077500000000000000000000000001216214232500252775ustar00rootroot00000000000000c6abbd55fed5ac71a5f2751e29b4a34726a595000066400000000000000000000004161216214232500325130ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/e2x+)JMU067f040031QH,-M-JOMLI+(aH:,:C: o>ZC'g$楧f&%%g5qYeZokM2ԐX\ZDPC~^ZNfrIf^:XZHي1O(_,' jvn~JfZ&5%\N,5[e2 I{| 2mg˾15ӿ,\})TC)0Dvz֛9MՅ'6blibgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/e3/000077500000000000000000000000001216214232500253005ustar00rootroot000000000000001e7ad3ed298f24e383c4950f4671993ec078e4000066400000000000000000000003221216214232500322420ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/e3x+)JMU027c040031QH,-M-JOMLI+(aH:,:C: o>ZC'g$楧f&%%g5qYeZokM2ԐX\ZDPC~^ZNfrIf^:XZHي1O(_,' jvQjn~c?J>\]3e߅j(:~'>YoX^7W̋o76fbdd06ebf021c92724da9f26f44212734e3e000066400000000000000000000002211216214232500323460ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/e3xA@E]s `@ uH)M=Scz:ʊ(N+6ޛDFe𭭘Yg$+G&F pG 4mQ\85#FC~QERu);c6'jlibgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/e4/000077500000000000000000000000001216214232500253015ustar00rootroot000000000000009f917b448d1340b31d76e54ba388268fd4c922000066400000000000000000000000441216214232500321510ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/e4xKOR02b(,VTԴM. f618a2c3ed0669308735727df5ebf2447f022f000066400000000000000000000002371216214232500322310ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/e4xK!D]s .iOboi2. bhJQ6b`7:DN.%4uIQYcm`Q¨ aQYa@>ɗEc9%bhUytSj"P)?gĶd sO-libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/e8/000077500000000000000000000000001216214232500253055ustar00rootroot00000000000000107f24196736b870a318a0e28f048e29f6feff000066400000000000000000000002411216214232500322340ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/e8xK!D]s .i~=Lbo@dfE UTj)kښ]om5(3j&4߻ppiRI;9Qg_j -RVȃ~ҙTI*tr g;9#Rmkb%rLNlibgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/e9/000077500000000000000000000000001216214232500253065ustar00rootroot000000000000002cdb7017dc6c5aed25cb4202c5b0104b872246000066400000000000000000000000601216214232500323200ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/e9x+)JMU06d040031QK-g1[kR^/Tad6ec3e38364a3d07feda7c4197d4d845c53b5000066400000000000000000000000441216214232500325270ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/e9xKOR02b(,VT ԴM. f48beccc62d535739bfbdebe0a55ed716d8366000066400000000000000000000005761216214232500327060ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/e9x+)JMU013`040031QHLIIMM,.I-+(aP<9 w|S7݅&0%E驉I9`8B߭)y'71 ݔ̢b%.QdrکOuy$%%g ]ˤގ״eZӍɂV3lbvˎ5AƠm{wJ$O|׳4ͱ$nկ.< / Llibgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/eb/000077500000000000000000000000001216214232500253575ustar00rootroot00000000000000c09d0137cfb0c26697aed0109fb943ad906f3f000066400000000000000000000002461216214232500325120ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/ebx 0y$xa^.mPf-sqS@ .퉸Kmr01R:%Ai{ hא|}y΄G/Q9=iIpʴҏ:܎t8{-zDvʟ3J^Z yzMRblibgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/ec/000077500000000000000000000000001216214232500253605ustar00rootroot0000000000000067e5a86adff465359f1c8f995e12dbdfa08d8a000066400000000000000000000002461216214232500327110ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/ecxA0 D:@NҸn\ǡ OA܀{h.7aE'1!&%ب5Fsk!xѫ!kqQ2E-$MH*} -e˽pЍI?R#Xl; fٮ?Θdټ:Plibgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/ed/000077500000000000000000000000001216214232500253615ustar00rootroot000000000000009523e62e453e50dd9be1606af19399b96e397a000066400000000000000000000001271216214232500323240ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/edxKOR01d(,V(QHJU(JKMMQS(H,*JKQHM,4@9: % @ͨҚ\\d9H.(Elibgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/ee/000077500000000000000000000000001216214232500253625ustar00rootroot000000000000001d6f164893c1866a323f072eeed36b855656be000066400000000000000000000004431216214232500323160ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/eex+)JMU066d040031QH,54`xVs2r;XôSDg޴.~+ys:}=vLרXyin `rm)/Կ]~Dַ%&x+K/N}+qLe -3'UאAgm{73U1L>Gc.K6S_Rq%c#ŻuGefvBZk;7Y  \v@`jοg_WV")0e8בpe^?]q03fa1b8c00aff7fe02065fdb50864bb0d932ccf000066400000000000000000000001001216214232500327050ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/eexKOR021g(,VHIUy) y %E\(҉%E驉I9C[ Fq]@a9286df54245fea72c5b557291470eb825f38f000066400000000000000000000003531216214232500323220ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/eex+)JMU027c040031QH,-M-JOMLI+(a`muc.Gzz?ļ<ݤļ  >*_9\)f2ObrKRV,z2i5vst4d&d楃j_X}·i˞H*-J/8G~Ś_n Ɋھ`&gicIz_]xb3/btlibgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/ef/000077500000000000000000000000001216214232500253635ustar00rootroot0000000000000058fdd8086c243bdc81f99e379acacfd21d32d6000066400000000000000000000001001216214232500326640ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/efx 0О:JBݟOV y55jq!4{:p;c499524cf105d5264ac7fc54e07e95764e8075000066400000000000000000000000401216214232500322360ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/efxKOR04cK-WS0M*JK\ac9121fdedaf08ba180b53ebfbcf71bd488ed09000066400000000000000000000002401216214232500330660ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/efx;1 D} mK,9^>55˹̗M'څw흳!jM瑓U֘\AqS]K n $pBo+rz :\,݄a l[T@擳'+Slibgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/f0/000077500000000000000000000000001216214232500252765ustar00rootroot00000000000000053b8060bb3f0be5cbcc3147a07ece26bf097e000066400000000000000000000002431216214232500325450ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/f0xQ D\fBib? 6bͼI&Kkzw2I"MS Yqe1X@/n$:ް18i伋V%)ExTyW$/KwI'ǒRQ=D]707 Pkce2b8e4986084d9b308fb72709e414c23eb5e6000066400000000000000000000001751216214232500323140ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/f0xKAD]s `fc>aCә:0qGE*Vzb+ "X vRd>X#fz }>[ J_?q ExGkZI˃SP 6]e~3/Saxlibgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/f2/000077500000000000000000000000001216214232500253005ustar00rootroot000000000000000c9063fa0bda9a397c96947a7b687305c49753000066400000000000000000000000351216214232500321550ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/f2xKOR04e(,VT .W9e7fb590551095230c6149cbe72f2e9104a796000066400000000000000000000000511216214232500320640ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/f2xKOR02g,VHIUy y %&z\ libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/f3/000077500000000000000000000000001216214232500253015ustar00rootroot00000000000000293571dcd708b6a3faf03818cd2844d000e198000066400000000000000000000002551216214232500322140ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/f3xKj0)dZ!\@nI,3{XZ?F/\E12zc"#X1][_G&c+9XWKžiUtgS*O۹)u|oXp*" pӤtũ`9zKO\f1164b68b57b1995b658a828320e6df3081fae000066400000000000000000000004661216214232500322360ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/f3x+)JMU010a040031QHLIIMM,.I-+(aP<9 w|S7݅&Py IEy` s\pqwvSLk15 xo5æ˾.fXʣ[!?/-'3$3/l_G^橕˷%{_TiQjn~c?J>\]3e߅kKj05o&qD/ݧryUؒV}'3JKZ&_59d4R`pClz֛9MՅ'6bl}libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/f4/000077500000000000000000000000001216214232500253025ustar00rootroot0000000000000015caf3fcad16304cb424b67f0ee6b12dc03aae000066400000000000000000000005001216214232500326710ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/f4x+)JMU0d040031QHLIIMM,.I-+(aP<9 w|S7݅&0%E驉I9`8B߭)y'뜇*NHKTְ:e Ikwgi7˴SsftykXytB4d&d楃KPZC'g$楧f&%%g5qYeZokM2ԐX\ZDPC~^ZNfrIf^:XZHي1O(_,' fv~Afj XՉz֛9MՅ'6bRs NFrAur#b/ dEm_ א?i?>AƠm{wQ5t4libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/f6/000077500000000000000000000000001216214232500253045ustar00rootroot00000000000000be049e284c0f9dcbbc745543885be3502ea521000066400000000000000000000004111216214232500323520ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/f6x+)JMU06d040031QHLIIMM,.I-+(aP<9 w|S7݅&0%E驉I9`8B߭)y'뜇*NHKTְ:e Ikwgi7˴SsftykXytB4d&d楃KP\]3eEՀ\T"libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/f7/000077500000000000000000000000001216214232500253055ustar00rootroot00000000000000c332bd4d4d4b777366cae4d24d1687477576bf000066400000000000000000000002341216214232500323170ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/f7x !D=S6YXY 1Ƌ?K>Ai{dro:o۳K3ȌZϥrCZK{r]̈́ޓ"\srMBs.}(pYz{dt]"#g9XWLlibgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/f8/000077500000000000000000000000001216214232500253065ustar00rootroot00000000000000958bdf4d365a84a9a178b1f5f35ff1dacbd884000066400000000000000000000002411216214232500326210ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/f8xK 1D]}Iq K>f1x}xwUQv kv@`O;$Kșybh2癈sLA ?R\˷ץ(~Yïb-'Yǎp=Njq˟m[zO+libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/fa/000077500000000000000000000000001216214232500253575ustar00rootroot00000000000000c03f2c5139618d87d53614c153823bf1f31396000066400000000000000000000001141216214232500320500ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/faxKOR021e(,VHIUy) y %E\(҉%E驉I9R@U8373'dH[da9356aa3f74622327a3038ae9c6f92e1c5c1d000066400000000000000000000002501216214232500324250ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/faxM ]s .~7`vA1E {?y_^,9/Mjk2K>` A|0I&&:Gcub S$R-&yK*ӯ)|ʠEy@m7wHc[k Olibgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/fb/000077500000000000000000000000001216214232500253605ustar00rootroot00000000000000738a106cfd097a4acb96ce132ecb1ad6c46b03000066400000000000000000000004101216214232500326250ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/fbx+)JMU06d040031QH,-M-JOMLI+(aH:,:C: o>ZC'g$楧f&%%g5qYeZokM2ԐX\ZDPC~^ZNfrIf^:XZHي1O(_,' jvQjn~1`瞅5|EJ=^%.}Aۮbj@rxur#b/ dEm_ P prCi%u?~uͼXp5ulibgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/fc/000077500000000000000000000000001216214232500253615ustar00rootroot000000000000004c636d6515e9e261f9260dbcf3cc6eca97ea08000066400000000000000000000000351216214232500326050ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/fcxKOR04e(,VTK.W7d7b805f7a9428574f4f802b2e34cd20ab9d99000066400000000000000000000010771216214232500324040ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/fcx+)JMU4a040031Q0HMHKO+(a8v›SRMegkޝulLmnQjyQfIIjnfn~iQ1Xχs}m s>9dLO2L.0!Fk BbOܪxZx[C.D=)%./|Eyqv+~bNdn]ժa:@ރ[ ZoUXΞnT"]b)g#jK=ڷ<. ͠zmM/ktbio1[-$%1'%5'3t$Nf˼_cٔ|>>03gg{ ݺ F-Sf`#1%#'mZŭM]l${ \7WuliKǷUABS 587\.M6/˾Ĺ!YP" .'fTX(eu.(h[kʷ54|e+BǹC%USqfJ!Xu/gIpkUδK&M0rKx,?h~y90237dc4891fa6c69827fc465632225e391618000066400000000000000000000002431216214232500320220ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/fcxK0CYh2$S !6܀=gvQ OA܀,[m]_D7)Y2xa3Ɇ#.rߊ%e J0QZBDZ@TU|-R^q):ymw}~YrOX"h=xl?gTu* QBNblibgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/fd/000077500000000000000000000000001216214232500253625ustar00rootroot0000000000000057d2d6770fad8e9959124793a17f441b571e66000066400000000000000000000004271216214232500321740ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/fdx+)JMU067a040031QH,-M-JOMLI+(aH:,:C: o>ZC'g$楧f&%%g5qYeZokM2ԐX\ZDPC~^ZNfrIf^:XZHي1O(_,' jv^jnb^nJfZZjQj^ X RwzŔbiWRs0\'UB'zq/.$ HX.W`ᚬKJA!SN|׳4ͱ$nկ.< Z89f8cffb663ac89095a0f9764902e93ceaca6a000066400000000000000000000002431216214232500326270ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/fdxK!D]s .{`cx/ɸ`0 oURy|Y`dPA!4C2d=x#e`BgrubLffG@՗-}KԲUy=];)r0 R$(%o=׶OPwlibgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/fe/000077500000000000000000000000001216214232500253635ustar00rootroot000000000000005407fc50a53aecb41d1a6e9ea7b612e581af87000066400000000000000000000000601216214232500325640ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/fexKOR06bOLLMQSP/),L54M*JKP libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/ff/000077500000000000000000000000001216214232500253645ustar00rootroot0000000000000049d07869831ad761bbdaea026086f8789bcb00000066400000000000000000000000301216214232500323600ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/ffxKORdK-WS0+!b312248d607284c290023f9502eea010d34efd000066400000000000000000000001041216214232500321660ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/objects/ffxKOR4cHLIIMQSH/ಁWG.̔TCM.T%& Vke )i F\;Clibgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/refs/000077500000000000000000000000001216214232500242775ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/refs/heads/000077500000000000000000000000001216214232500253635ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/refs/heads/branch000066400000000000000000000000511216214232500265370ustar00rootroot000000000000007cb63eed597130ba4abb87b3e544b85021905520 libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/refs/heads/df_ancestor000066400000000000000000000000511216214232500275710ustar00rootroot000000000000002da538570bc1e5b2c3e855bf702f35248ad0735f libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/refs/heads/df_side1000066400000000000000000000000511216214232500267600ustar00rootroot00000000000000a7dbfcbfc1a60709cb80b5ca24539008456531d0 libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/refs/heads/df_side2000066400000000000000000000000511216214232500267610ustar00rootroot00000000000000fc90237dc4891fa6c69827fc465632225e391618 libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/refs/heads/ff_branch000066400000000000000000000000511216214232500272120ustar00rootroot00000000000000fd89f8cffb663ac89095a0f9764902e93ceaca6a libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/refs/heads/master000066400000000000000000000000511216214232500265750ustar00rootroot00000000000000bd593285fc7fe4ca18ccdbabf027f5d689101452 libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/refs/heads/octo1000066400000000000000000000000511216214232500263270ustar00rootroot0000000000000016f825815cfd20a07a75c71554e82d8eede0b061 libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/refs/heads/octo2000066400000000000000000000000511216214232500263300ustar00rootroot00000000000000158dc7bedb202f5b26502bf3574faa7f4238d56c libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/refs/heads/octo3000066400000000000000000000000511216214232500263310ustar00rootroot0000000000000050ce7d7d01217679e26c55939eef119e0c93e272 libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/refs/heads/octo4000066400000000000000000000000511216214232500263320ustar00rootroot0000000000000054269b3f6ec3d7d4ede24dd350dd5d605495c3ae libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/refs/heads/octo5000066400000000000000000000000511216214232500263330ustar00rootroot00000000000000e4f618a2c3ed0669308735727df5ebf2447f022f libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/refs/heads/octo6000066400000000000000000000000511216214232500263340ustar00rootroot00000000000000b6f610aef53bd343e6c96227de874c66f00ee8e8 libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/refs/heads/rename_conflict_ancestor000066400000000000000000000000511216214232500323300ustar00rootroot000000000000002392a2dacc9efb562b8635d6579fb458751c7c5b libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/refs/heads/rename_conflict_ours000066400000000000000000000000511216214232500315020ustar00rootroot0000000000000034bfafff88eaf118402b44e6f3e2dbbf1a582b05 libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/refs/heads/rename_conflict_theirs000066400000000000000000000000511216214232500320100ustar00rootroot00000000000000a802e06f1782a9645b9851bc7202cee74a8a4972 libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/refs/heads/renames1000066400000000000000000000000511216214232500270150ustar00rootroot00000000000000412b32fb66137366147f1801ecc962452757d48a libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/refs/heads/renames2000066400000000000000000000000511216214232500270160ustar00rootroot00000000000000ab40af3cb8a3ed2e2843e96d9aa7871336b94573 libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/refs/heads/trivial-10000066400000000000000000000000511216214232500271720ustar00rootroot000000000000000ec5f433959cd46177f745903353efb5be08d151 libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/refs/heads/trivial-10-branch000066400000000000000000000000511216214232500304250ustar00rootroot0000000000000011f4f3c08b737f5fd896cbefa1425ee63b21b2fa libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/refs/heads/trivial-11000066400000000000000000000000511216214232500271730ustar00rootroot000000000000003168dca1a561889b045a6441909f4c56145e666d libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/refs/heads/trivial-11-branch000066400000000000000000000000511216214232500304260ustar00rootroot000000000000006718a45909532d1fcf5600d0877f7fe7e78f0b86 libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/refs/heads/trivial-13000066400000000000000000000000511216214232500271750ustar00rootroot00000000000000a3fabece9eb8748da810e1e08266fef9b7136ad4 libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/refs/heads/trivial-13-branch000066400000000000000000000000511216214232500304300ustar00rootroot0000000000000005f3c1a2a56ca95c3d2ef28dc9ddf32b5cd6c91c libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/refs/heads/trivial-14000066400000000000000000000000511216214232500271760ustar00rootroot000000000000007e2d058d5fedf8329db44db4fac610d6b1a89159 libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/refs/heads/trivial-14-branch000066400000000000000000000000511216214232500304310ustar00rootroot000000000000008187117062b750eed4f93fd7e899f17b52ce554d libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/refs/heads/trivial-2alt000066400000000000000000000000511216214232500276140ustar00rootroot00000000000000566ab53c220a2eafc1212af1a024513230280ab9 libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/refs/heads/trivial-2alt-branch000066400000000000000000000000511216214232500310470ustar00rootroot00000000000000c9174cef549ec94ecbc43ef03cdc775b4950becb libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/refs/heads/trivial-3alt000066400000000000000000000000511216214232500276150ustar00rootroot000000000000004c9fac0707f8d4195037ae5a681aa48626491541 libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/refs/heads/trivial-3alt-branch000066400000000000000000000000511216214232500310500ustar00rootroot00000000000000c607fc30883e335def28cd686b51f6cfa02b06ec libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/refs/heads/trivial-4000066400000000000000000000000511216214232500271150ustar00rootroot00000000000000cc3e3009134cb88014129fc8858d1101359e5e2f libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/refs/heads/trivial-4-branch000066400000000000000000000000511216214232500303500ustar00rootroot00000000000000183310e30fb1499af8c619108ffea4d300b5e778 libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/refs/heads/trivial-5alt-1000066400000000000000000000000511216214232500277550ustar00rootroot000000000000004fe93c0ec83eb6305cbace3dace88ecee1b63cb6 libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/refs/heads/trivial-5alt-1-branch000066400000000000000000000000511216214232500312100ustar00rootroot00000000000000478172cb2f5ff9b514bc9d04d3bd5ef5840cb3b2 libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/refs/heads/trivial-5alt-2000066400000000000000000000000511216214232500277560ustar00rootroot000000000000003b47b031b3e55ae11e14a05260b1c3ffd6838d55 libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/refs/heads/trivial-5alt-2-branch000066400000000000000000000000511216214232500312110ustar00rootroot00000000000000f48097eb340dc5a7cae55aabcf1faf4548aa821f libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/refs/heads/trivial-6000066400000000000000000000000511216214232500271170ustar00rootroot0000000000000099b4f7e4f24470fa06b980bc21f1095c2a9425c0 libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/refs/heads/trivial-6-branch000066400000000000000000000000511216214232500303520ustar00rootroot00000000000000a43150a738849c59376cf30bb2a68348a83c8f48 libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/refs/heads/trivial-7000066400000000000000000000000511216214232500271200ustar00rootroot00000000000000d874671ef5b20184836cb983bb273e5280384d0b libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/refs/heads/trivial-7-branch000066400000000000000000000000511216214232500303530ustar00rootroot000000000000005195a1b480f66691b667f10a9e41e70115a78351 libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/refs/heads/trivial-8000066400000000000000000000000511216214232500271210ustar00rootroot000000000000003575826c96a975031d2c14368529cc5c4353a8fd libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/refs/heads/trivial-8-branch000066400000000000000000000000511216214232500303540ustar00rootroot0000000000000052d8bc572af2b6d4ee0d5e62ed5d1fbad92210a9 libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/refs/heads/trivial-9000066400000000000000000000000511216214232500271220ustar00rootroot00000000000000c35dee9bcc0e989f3b0c40f68372a9a51b6c4e6a libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/refs/heads/trivial-9-branch000066400000000000000000000000511216214232500303550ustar00rootroot0000000000000013d1be4ea52a6ced1d7a1d832f0ee3c399348e5e libgit2-0.19.0/tests-clar/resources/merge-resolve/.gitted/refs/heads/unrelated000066400000000000000000000000511216214232500272650ustar00rootroot0000000000000055b4e4687e7a0d9ca367016ed930f385d4022e6f libgit2-0.19.0/tests-clar/resources/merge-resolve/added-in-master.txt000066400000000000000000000000351216214232500254770ustar00rootroot00000000000000this file is added in master libgit2-0.19.0/tests-clar/resources/merge-resolve/automergeable.txt000066400000000000000000000003671216214232500253650ustar00rootroot00000000000000this file is changed in master this file is automergeable this file is automergeable this file is automergeable this file is automergeable this file is automergeable this file is automergeable this file is automergeable this file is automergeable libgit2-0.19.0/tests-clar/resources/merge-resolve/changed-in-branch.txt000066400000000000000000000000211216214232500257640ustar00rootroot00000000000000initial revision libgit2-0.19.0/tests-clar/resources/merge-resolve/changed-in-master.txt000066400000000000000000000000221216214232500260230ustar00rootroot00000000000000changed in master libgit2-0.19.0/tests-clar/resources/merge-resolve/conflicting.txt000066400000000000000000000000521216214232500250370ustar00rootroot00000000000000this file is changed in master and branch libgit2-0.19.0/tests-clar/resources/merge-resolve/removed-in-branch.txt000066400000000000000000000000321216214232500260360ustar00rootroot00000000000000this is removed in branch libgit2-0.19.0/tests-clar/resources/merge-resolve/unchanged.txt000066400000000000000000000000371216214232500244770ustar00rootroot00000000000000this file is unchanged in both libgit2-0.19.0/tests-clar/resources/mergedrepo/000077500000000000000000000000001216214232500213575ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/mergedrepo/.gitted/000077500000000000000000000000001216214232500227155ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/mergedrepo/.gitted/COMMIT_EDITMSG000066400000000000000000000000071216214232500250010ustar00rootroot00000000000000master libgit2-0.19.0/tests-clar/resources/mergedrepo/.gitted/HEAD000066400000000000000000000000271216214232500233400ustar00rootroot00000000000000ref: refs/heads/master libgit2-0.19.0/tests-clar/resources/mergedrepo/.gitted/MERGE_HEAD000066400000000000000000000000511216214232500242540ustar00rootroot00000000000000e2809157a7766f272e4cfe26e61ef2678a5357ff libgit2-0.19.0/tests-clar/resources/mergedrepo/.gitted/MERGE_MODE000066400000000000000000000000001216214232500242710ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/mergedrepo/.gitted/MERGE_MSG000066400000000000000000000001101216214232500241750ustar00rootroot00000000000000Merge branch 'branch' Conflicts: conflicts-one.txt conflicts-two.txt libgit2-0.19.0/tests-clar/resources/mergedrepo/.gitted/ORIG_HEAD000066400000000000000000000000511216214232500241550ustar00rootroot000000000000003a34580a35add43a4cf361e8e9a30060a905c876 libgit2-0.19.0/tests-clar/resources/mergedrepo/.gitted/config000066400000000000000000000001571216214232500241100ustar00rootroot00000000000000[core] repositoryformatversion = 0 filemode = true bare = false logallrefupdates = true ignorecase = true libgit2-0.19.0/tests-clar/resources/mergedrepo/.gitted/description000066400000000000000000000001111216214232500251540ustar00rootroot00000000000000Unnamed repository; edit this file 'description' to name the repository. libgit2-0.19.0/tests-clar/resources/mergedrepo/.gitted/index000066400000000000000000000015121216214232500237460ustar00rootroot00000000000000DIRCQȓ!&a֪mconflicts-one.txtj_)SaDnG# conflicts-one.txtQk_x V{PFrR0conflicts-one.txtb {w$?QUconflicts-two.txt?C@(%5bA>8oв conflicts-two.txt" &1z9ƹE!0conflicts-two.txtPMKPMK\Gug >{ĬEHone.txtPMKPMK\F{&:E+wa|YG_Kqtwo.txtREUCone.txt100644100644100644Gq8[98:h#ƳDXruZVDSrAeEaLOtwo.txt100644100644100644/z)L. ,<7W %{;]2@p>sL s`.!enalibgit2-0.19.0/tests-clar/resources/mergedrepo/.gitted/info/000077500000000000000000000000001216214232500236505ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/mergedrepo/.gitted/info/exclude000066400000000000000000000003601216214232500252230ustar00rootroot00000000000000# git ls-files --others --exclude-from=.git/info/exclude # Lines that start with '#' are comments. # For a project mostly in C, the following would be a good set of # exclude patterns (uncomment them if you want to use them): # *.[oa] # *~ libgit2-0.19.0/tests-clar/resources/mergedrepo/.gitted/logs/000077500000000000000000000000001216214232500236615ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/mergedrepo/.gitted/logs/HEAD000066400000000000000000000015211216214232500243040ustar00rootroot000000000000000000000000000000000000000000000000000000 9a05ccb4e0f948de03128e095f39dae6976751c5 Edward Thomson 1351371828 -0500 commit (initial): initial 9a05ccb4e0f948de03128e095f39dae6976751c5 9a05ccb4e0f948de03128e095f39dae6976751c5 Edward Thomson 1351371835 -0500 checkout: moving from master to branch 9a05ccb4e0f948de03128e095f39dae6976751c5 e2809157a7766f272e4cfe26e61ef2678a5357ff Edward Thomson 1351371872 -0500 commit: branch e2809157a7766f272e4cfe26e61ef2678a5357ff 9a05ccb4e0f948de03128e095f39dae6976751c5 Edward Thomson 1351371873 -0500 checkout: moving from branch to master 9a05ccb4e0f948de03128e095f39dae6976751c5 3a34580a35add43a4cf361e8e9a30060a905c876 Edward Thomson 1351372106 -0500 commit: master libgit2-0.19.0/tests-clar/resources/mergedrepo/.gitted/logs/refs/000077500000000000000000000000001216214232500246205ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/mergedrepo/.gitted/logs/refs/heads/000077500000000000000000000000001216214232500257045ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/mergedrepo/.gitted/logs/refs/heads/branch000066400000000000000000000005071216214232500270660ustar00rootroot000000000000000000000000000000000000000000000000000000 9a05ccb4e0f948de03128e095f39dae6976751c5 Edward Thomson 1351371835 -0500 branch: Created from HEAD 9a05ccb4e0f948de03128e095f39dae6976751c5 e2809157a7766f272e4cfe26e61ef2678a5357ff Edward Thomson 1351371872 -0500 commit: branch libgit2-0.19.0/tests-clar/resources/mergedrepo/.gitted/logs/refs/heads/master000066400000000000000000000005071216214232500271240ustar00rootroot000000000000000000000000000000000000000000000000000000 9a05ccb4e0f948de03128e095f39dae6976751c5 Edward Thomson 1351371828 -0500 commit (initial): initial 9a05ccb4e0f948de03128e095f39dae6976751c5 3a34580a35add43a4cf361e8e9a30060a905c876 Edward Thomson 1351372106 -0500 commit: master libgit2-0.19.0/tests-clar/resources/mergedrepo/.gitted/objects/000077500000000000000000000000001216214232500243465ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/mergedrepo/.gitted/objects/03/000077500000000000000000000000001216214232500245705ustar00rootroot00000000000000db1d37504ca0c4f7c26d7776b0e28bdea08712000066400000000000000000000002151216214232500317100ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/mergedrepo/.gitted/objects/03x+)JMU043`040031QHKL.)K+(azr8em$ET<!ē,/l*cϼm'J}r!fJ +i3jޗWAlibgit2-0.19.0/tests-clar/resources/mergedrepo/.gitted/objects/17/000077500000000000000000000000001216214232500245755ustar00rootroot000000000000000efc1023e0ed2390150bb4469c8456b63e8f91000066400000000000000000000002151216214232500315010ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/mergedrepo/.gitted/objects/17x+)JMU043`040031QHKL.)K+(a>x3KBڟa 'sb(.)+ *S]!k2NU 3trvY)jֻjKHtݻeAlibgit2-0.19.0/tests-clar/resources/mergedrepo/.gitted/objects/1f/000077500000000000000000000000001216214232500246545ustar00rootroot0000000000000085ca51b8e0aac893a621b61a9c2661d6aa6d81000066400000000000000000000000421216214232500317700ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/mergedrepo/.gitted/objects/1fxKOR02`,VDE.libgit2-0.19.0/tests-clar/resources/mergedrepo/.gitted/objects/22/000077500000000000000000000000001216214232500245715ustar00rootroot000000000000000bd62631c8cf7a83ef39c6b94595f00517211e000066400000000000000000000000521216214232500315060ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/mergedrepo/.gitted/objects/22xKOR0`,Vļ"EEE.܆ libgit2-0.19.0/tests-clar/resources/mergedrepo/.gitted/objects/32/000077500000000000000000000000001216214232500245725ustar00rootroot00000000000000d55d59265db86dd690f0a7fc563db43e2bc6a6000066400000000000000000000002371216214232500320220ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/mergedrepo/.gitted/objects/32xK 1D]ҝ4^ "F2oo<*ZoC*љ%zf4ZGi1Ey):߇6h %3hT ٢)v䝷ϱ./z׵խ'3_;VOE<=X1<;Oa~Mlibgit2-0.19.0/tests-clar/resources/mergedrepo/.gitted/objects/38/000077500000000000000000000000001216214232500246005ustar00rootroot00000000000000e2d82b9065a237904af4b780b4d68da6950534000066400000000000000000000001121216214232500314330ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/mergedrepo/.gitted/objects/38xKORdWGb JIM,IͩTHTHKL.Q䲅2$9EE.;PH*JK%libgit2-0.19.0/tests-clar/resources/mergedrepo/.gitted/objects/3a/000077500000000000000000000000001216214232500246515ustar00rootroot0000000000000034580a35add43a4cf361e8e9a30060a905c876000066400000000000000000000002371216214232500315570ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/mergedrepo/.gitted/objects/3axK 1D]}Dx/O"F2oo<*ZoљuIhhrl"r YT8'#vm0.¨.:.#+9R^nG~[=VjR"IjD۔7|N`libgit2-0.19.0/tests-clar/resources/mergedrepo/.gitted/objects/44/000077500000000000000000000000001216214232500245755ustar00rootroot0000000000000058b8bc9e72b6c8755ae456f60e9844d0538d8c000066400000000000000000000000471216214232500316320ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/mergedrepo/.gitted/objects/44xKOR00`,V̜TTE.tA'=libgit2-0.19.0/tests-clar/resources/mergedrepo/.gitted/objects/47/000077500000000000000000000000001216214232500246005ustar00rootroot000000000000008871385b9cd03908c5383acfd568bef023c6b3000066400000000000000000000000441216214232500316060ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/mergedrepo/.gitted/objects/47xKOR00`,V̜TT=/r=libgit2-0.19.0/tests-clar/resources/mergedrepo/.gitted/objects/51/000077500000000000000000000000001216214232500245735ustar00rootroot000000000000006bd85f78061e09ccc714561d7b504672cb52da000066400000000000000000000000441216214232500315660ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/mergedrepo/.gitted/objects/51xKOR02b,VDEEE.) libgit2-0.19.0/tests-clar/resources/mergedrepo/.gitted/objects/53/000077500000000000000000000000001216214232500245755ustar00rootroot00000000000000c1d95a01f4514b162066fc98564500c96c46ad000066400000000000000000000000551216214232500314250ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/mergedrepo/.gitted/objects/53xKOR06d,VԴ̼̒ԜJDE. #libgit2-0.19.0/tests-clar/resources/mergedrepo/.gitted/objects/6a/000077500000000000000000000000001216214232500246545ustar00rootroot00000000000000ea5f295304c36144ad6e9247a291b7f8112399000066400000000000000000000000611216214232500314340ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/mergedrepo/.gitted/objects/6axKOR06e,VԢ̼JDE.>libgit2-0.19.0/tests-clar/resources/mergedrepo/.gitted/objects/70/000077500000000000000000000000001216214232500245745ustar00rootroot0000000000000068e30a7f0090ae32db35dfa1e4189d8780fcb8000066400000000000000000000001251216214232500317300ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/mergedrepo/.gitted/objects/70xKOR040eWGb *+,M-.KLʩTH/H-RHKL.Q䲅 \vT$libgit2-0.19.0/tests-clar/resources/mergedrepo/.gitted/objects/75/000077500000000000000000000000001216214232500246015ustar00rootroot00000000000000938de1e367098b3e9a7b1ec3c4ac4548afffe4000066400000000000000000000000511216214232500321110ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/mergedrepo/.gitted/objects/75xKOR00`,V̜TTE.tA&=libgit2-0.19.0/tests-clar/resources/mergedrepo/.gitted/objects/7b/000077500000000000000000000000001216214232500246565ustar00rootroot0000000000000026923aaf452b1977eb08617c59475fb3f74b71000066400000000000000000000000511216214232500315240ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/mergedrepo/.gitted/objects/7bxKOR024c,V̜T|E.t!(QJlibgit2-0.19.0/tests-clar/resources/mergedrepo/.gitted/objects/84/000077500000000000000000000000001216214232500246015ustar00rootroot00000000000000af62840be1b1c47b778a8a249f3ff45155038c000066400000000000000000000000501216214232500315730ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/mergedrepo/.gitted/objects/84xKOR02c,Vļ"E. jlibgit2-0.19.0/tests-clar/resources/mergedrepo/.gitted/objects/88/000077500000000000000000000000001216214232500246055ustar00rootroot0000000000000071f7a2ee3addfc4ba39fbd0783c8e738d04cda000066400000000000000000000001021216214232500323130ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/mergedrepo/.gitted/objects/88xKOR027`,V̜T|E.t! b .\vT@ Yl7b153b165d32409c70163e0f734c090f12f673000066400000000000000000000000461216214232500312660ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/mergedrepo/.gitted/objects/88xKOR024c,V̜T|= yJlibgit2-0.19.0/tests-clar/resources/mergedrepo/.gitted/objects/8a/000077500000000000000000000000001216214232500246565ustar00rootroot00000000000000ad34cc83733590e74b93d0f7cf00375e2a735a000066400000000000000000000001161216214232500316460ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/mergedrepo/.gitted/objects/8axKOR4fWGb /.QHN-*I˩THTHKL.Q䲅R$9EE.;PH*JK libgit2-0.19.0/tests-clar/resources/mergedrepo/.gitted/objects/8b/000077500000000000000000000000001216214232500246575ustar00rootroot000000000000003f43d2402825c200f835ca1762413e386fd0b2000066400000000000000000000000711216214232500314060ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/mergedrepo/.gitted/objects/8bxKOR01f,V̒<ļ"E.R572416545c7e761b64cecad4f1686eae4078aa8000066400000000000000000000000461216214232500317440ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/mergedrepo/.gitted/objects/8bxKOR00`,V̜TT=.X=libgit2-0.19.0/tests-clar/resources/mergedrepo/.gitted/objects/8f/000077500000000000000000000000001216214232500246635ustar00rootroot000000000000003c06cff9a83757cec40c80bc9bf31a2582bde9000066400000000000000000000000471216214232500321640ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/mergedrepo/.gitted/objects/8fxKOR024c,V̜T|E.t!)kJfcc405925511824a2240a6d3686aa7f8c7ac50000066400000000000000000000002141216214232500315620ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/mergedrepo/.gitted/objects/8fx+)JMU043`040031QHKL.)K+(a̾_&yHlu[[K8_NשX堊au9ZWOػV@L5rS f_/<[libgit2-0.19.0/tests-clar/resources/mergedrepo/.gitted/objects/9a/000077500000000000000000000000001216214232500246575ustar00rootroot0000000000000005ccb4e0f948de03128e095f39dae6976751c5000066400000000000000000000002041216214232500316660ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/mergedrepo/.gitted/objects/9ax !Dm@ c6q##Ay/ ܁:#$ltH:闄*DXhV} ˷n[-K_;Z@J GԈbq3"go@Ilibgit2-0.19.0/tests-clar/resources/mergedrepo/.gitted/objects/9d/000077500000000000000000000000001216214232500246625ustar00rootroot0000000000000081f82fccc7dcd7de7a1ffead1815294c2e092c000066400000000000000000000000441216214232500323220ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/mergedrepo/.gitted/objects/9dxKOR024c,V̜T|=!ӓJlibgit2-0.19.0/tests-clar/resources/mergedrepo/.gitted/objects/b7/000077500000000000000000000000001216214232500246565ustar00rootroot00000000000000cedb8ad4cbb22b6363f9578cbd749797f7ef0d000066400000000000000000000001021216214232500322530ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/mergedrepo/.gitted/objects/b7xKOR026a,V̜TTE.tWG.[$;PH*JKPLXlibgit2-0.19.0/tests-clar/resources/mergedrepo/.gitted/objects/d0/000077500000000000000000000000001216214232500246515ustar00rootroot000000000000001885ea594926eae9ba5b54ad76692af5969f51000066400000000000000000000000671216214232500317100ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/mergedrepo/.gitted/objects/d0xKOR01d,VҼĤJļ"E.xlibgit2-0.19.0/tests-clar/resources/mergedrepo/.gitted/objects/e2/000077500000000000000000000000001216214232500246545ustar00rootroot00000000000000809157a7766f272e4cfe26e61ef2678a5357ff000066400000000000000000000002401216214232500316230ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/mergedrepo/.gitted/objects/e2xK 1D]t> xNq1(]{Pe mٍ.S0[Dcd ŅbMԝCgd@>glX].$!0*zu})/E_<ڪO:WځrơqѤh@mt;;5uZyVo\Mlibgit2-0.19.0/tests-clar/resources/mergedrepo/.gitted/objects/e6/000077500000000000000000000000001216214232500246605ustar00rootroot000000000000002cac5c88b9928f2695b934c70efa4285324478000066400000000000000000000001271216214232500315450ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/mergedrepo/.gitted/objects/e6xKOR040gWGb *,/-Q(,M-.SH/H-RHKL.Q䲅 \vT]'$libgit2-0.19.0/tests-clar/resources/mergedrepo/.gitted/objects/f7/000077500000000000000000000000001216214232500246625ustar00rootroot000000000000002784290c151092abf04ce6b875068547f70406000066400000000000000000000002151216214232500312760ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/mergedrepo/.gitted/objects/f7x+)JMU043`040031QHKL.)K+(ao=)nxmUn#|I-7.Ro%0f{GE G-_Af)s9~*k%D5}8u[Blibgit2-0.19.0/tests-clar/resources/mergedrepo/.gitted/refs/000077500000000000000000000000001216214232500236545ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/mergedrepo/.gitted/refs/heads/000077500000000000000000000000001216214232500247405ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/mergedrepo/.gitted/refs/heads/branch000066400000000000000000000000511216214232500261140ustar00rootroot00000000000000e2809157a7766f272e4cfe26e61ef2678a5357ff libgit2-0.19.0/tests-clar/resources/mergedrepo/.gitted/refs/heads/master000066400000000000000000000000511216214232500261520ustar00rootroot000000000000003a34580a35add43a4cf361e8e9a30060a905c876 libgit2-0.19.0/tests-clar/resources/mergedrepo/conflicts-one.txt000066400000000000000000000001351216214232500246620ustar00rootroot00000000000000<<<<<<< HEAD This is most certainly a conflict! ======= This is a conflict!!! >>>>>>> branch libgit2-0.19.0/tests-clar/resources/mergedrepo/conflicts-two.txt000066400000000000000000000001531216214232500247120ustar00rootroot00000000000000<<<<<<< HEAD This is without question another conflict! ======= This is another conflict!!! >>>>>>> branch libgit2-0.19.0/tests-clar/resources/mergedrepo/one.txt000066400000000000000000000002641216214232500227030ustar00rootroot00000000000000This is file one! This is file one. This is file one. This is file one. This is file one. This is file one. This is file one. This is file one. This is file one. This is file one! libgit2-0.19.0/tests-clar/resources/mergedrepo/two.txt000066400000000000000000000003301216214232500227250ustar00rootroot00000000000000This is file two! This is file two. This is file two. This is file two. This is file two. This is file two. This is file two. This is file two. This is file two. This is file two. This is file two. This is file two! libgit2-0.19.0/tests-clar/resources/partial-testrepo/000077500000000000000000000000001216214232500225255ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/partial-testrepo/.gitted/000077500000000000000000000000001216214232500240635ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/partial-testrepo/.gitted/HEAD000066400000000000000000000000241216214232500245030ustar00rootroot00000000000000ref: refs/heads/dir libgit2-0.19.0/tests-clar/resources/partial-testrepo/.gitted/config000066400000000000000000000001761216214232500252570ustar00rootroot00000000000000[core] repositoryformatversion = 0 filemode = true bare = false logallrefupdates = true ignorecase = true [branch "dir"] libgit2-0.19.0/tests-clar/resources/partial-testrepo/.gitted/index000066400000000000000000000005101216214232500251110ustar00rootroot00000000000000DIRCPPZ #1 p="READMEPPZf: 7gO{:G(5a/b.txtPPZE6<ܜl{Wbranch_file.txtPPZ ll@LVB1new.txtT" FW~=zQlibgit2-0.19.0/tests-clar/resources/partial-testrepo/.gitted/objects/000077500000000000000000000000001216214232500255145ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/partial-testrepo/.gitted/objects/13/000077500000000000000000000000001216214232500257375ustar00rootroot0000000000000085f264afb75a56a5bec74243be9b367ba4ca08000066400000000000000000000000231216214232500331460ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/partial-testrepo/.gitted/objects/13xKOR0aHSDlibgit2-0.19.0/tests-clar/resources/partial-testrepo/.gitted/objects/14/000077500000000000000000000000001216214232500257405ustar00rootroot000000000000004344043ba4d4a405da03de3844aa829ae8be0e000066400000000000000000000002431216214232500330440ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/partial-testrepo/.gitted/objects/14xA 0=e4DD 6ɮ-VjO6 L^j8m uYU:EGCJ;vͫ *j-1h^{,YS6.+dG[yKpN\StKBD}ÿj7libgit2-0.19.0/tests-clar/resources/partial-testrepo/.gitted/objects/5b/000077500000000000000000000000001216214232500260225ustar00rootroot000000000000005b025afb0b4c913b4c338a42934a3863bf3644000066400000000000000000000002361216214232500327170ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/partial-testrepo/.gitted/objects/5bx 1ENi@k2 "X$YW0YcÅszMD08!s Xgd::@X0Pw"F/RUzmZZV}|/o5I!1z:vUim}/> F-libgit2-0.19.0/tests-clar/resources/partial-testrepo/.gitted/objects/62/000077500000000000000000000000001216214232500257435ustar00rootroot00000000000000eb56dabb4b9929bc15dd9263c2c733b13d2dcc000066400000000000000000000000621216214232500333040ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/partial-testrepo/.gitted/objects/62x+)JMU06f040031QH+(aH)b>ÿj7{libgit2-0.19.0/tests-clar/resources/partial-testrepo/.gitted/objects/66/000077500000000000000000000000001216214232500257475ustar00rootroot000000000000003adb09143767984f7be83a91effa47e128c735000066400000000000000000000000231216214232500327620ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/partial-testrepo/.gitted/objects/66xKOR0aT/libgit2-0.19.0/tests-clar/resources/partial-testrepo/.gitted/objects/75/000077500000000000000000000000001216214232500257475ustar00rootroot00000000000000057dd4114e74cca1d750d0aee1647c903cb60a000066400000000000000000000001671216214232500330600ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/partial-testrepo/.gitted/objects/75x+)JMU044b040031Qrutuen~{T}ǝ6^r"(1/9#>-3'Uug>6wٞOpҼr_ʧ+O\\iy|tI/libgit2-0.19.0/tests-clar/resources/partial-testrepo/.gitted/objects/81/000077500000000000000000000000001216214232500257445ustar00rootroot000000000000004889a078c031f61ed08ab5fa863aea9314344d000066400000000000000000000001221216214232500327330ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/partial-testrepo/.gitted/objects/81x+)JMU0d040031QrutueXlmmAṃJ}G;UZWRQ°\erw solibgit2-0.19.0/tests-clar/resources/partial-testrepo/.gitted/objects/84/000077500000000000000000000000001216214232500257475ustar00rootroot0000000000000096071c1b46c854b31185ea97743be6a8774479000066400000000000000000000001761216214232500324750ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/partial-testrepo/.gitted/objects/84x 1Nۀn` V.`.pa Ô{StlH,_9$$cf&hXQ*g)cV~p~"Q@JnZuӶL 6libgit2-0.19.0/tests-clar/resources/partial-testrepo/.gitted/objects/9f/000077500000000000000000000000001216214232500260325ustar00rootroot00000000000000d738e8f7967c078dceed8190330fc8648ee56a000066400000000000000000000002401216214232500331470ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/partial-testrepo/.gitted/objects/9fx[ 0E*fդ "W0-Ft݁pS[Yx^ Db CLhut}8X*4ZsYUA X3RM) s6輢Mរ&Jm;}<\@ޏpĀv?jۺL?Hlibgit2-0.19.0/tests-clar/resources/partial-testrepo/.gitted/objects/a4/000077500000000000000000000000001216214232500260205ustar00rootroot00000000000000a7dce85cf63874e984719f4fdd239f5145052f000066400000000000000000000003101216214232500330460ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/partial-testrepo/.gitted/objects/a4x;j1Dmdǎ|M3`V{ >QvL0I?!4Z=!צ8F!rsQy9]$D&l6A>jFWҵ IKNiZ%S  U~̽>' w [ DGڡQ-M>dO}\8g_ШoYrlibgit2-0.19.0/tests-clar/resources/partial-testrepo/.gitted/objects/a7/000077500000000000000000000000001216214232500260235ustar00rootroot000000000000001586c1dfe8a71c6cbf6c129f404c5642ff31bd000066400000000000000000000000341216214232500332340ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/partial-testrepo/.gitted/objects/a7xKOR04bȭTK-WHIA=libgit2-0.19.0/tests-clar/resources/partial-testrepo/.gitted/objects/a8/000077500000000000000000000000001216214232500260245ustar00rootroot00000000000000233120f6ad708f843d861ce2b7228ec4e3dec6000066400000000000000000000000321216214232500330720ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/partial-testrepo/.gitted/objects/a8xKOR04`HT(H-J6libgit2-0.19.0/tests-clar/resources/partial-testrepo/.gitted/objects/c4/000077500000000000000000000000001216214232500260225ustar00rootroot000000000000007800c7266a2be04c571c04d5a6614691ea99bd000066400000000000000000000002411216214232500327270ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/partial-testrepo/.gitted/objects/c4xQ 0D)ʦI<'lR+FjEo0[TLU뒡32sRJ*J\w63nqgΞ9To*K-+Y.v29s;97 ̺<libgit2-0.19.0/tests-clar/resources/partial-testrepo/.gitted/objects/f6/000077500000000000000000000000001216214232500260275ustar00rootroot000000000000000079018b664e4e79329a7ef9559c8d9e0378d1000066400000000000000000000001221216214232500326370ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/partial-testrepo/.gitted/objects/f6x+)JMU0d040031Qrutuen~{T}ǝ6^r"/\F0|Z_8]nzlibgit2-0.19.0/tests-clar/resources/partial-testrepo/.gitted/objects/fa/000077500000000000000000000000001216214232500261025ustar00rootroot0000000000000049b077972391ad58037050f2a75f74e3671e92000066400000000000000000000000301216214232500325270ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/partial-testrepo/.gitted/objects/faxKORdK-WHI,D libgit2-0.19.0/tests-clar/resources/partial-testrepo/.gitted/objects/fd/000077500000000000000000000000001216214232500261055ustar00rootroot00000000000000093bff70906175335656e6ce6ae05783708765000066400000000000000000000001221216214232500325430ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/partial-testrepo/.gitted/objects/fdx+)JMU0d040031QrutueXlmmAṃJ}G;UZWRQsCtk# >-/y.7 libgit2-0.19.0/tests-clar/resources/partial-testrepo/.gitted/objects/pack/000077500000000000000000000000001216214232500264325ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/partial-testrepo/.gitted/objects/pack/.gitkeep000066400000000000000000000000001216214232500300510ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/partial-testrepo/.gitted/refs/000077500000000000000000000000001216214232500250225ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/partial-testrepo/.gitted/refs/heads/000077500000000000000000000000001216214232500261065ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/partial-testrepo/.gitted/refs/heads/dir000066400000000000000000000000511216214232500266030ustar00rootroot00000000000000144344043ba4d4a405da03de3844aa829ae8be0e libgit2-0.19.0/tests-clar/resources/peeled.git/000077500000000000000000000000001216214232500212465ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/peeled.git/HEAD000066400000000000000000000000271216214232500216710ustar00rootroot00000000000000ref: refs/heads/master libgit2-0.19.0/tests-clar/resources/peeled.git/config000066400000000000000000000002711216214232500224360ustar00rootroot00000000000000[core] repositoryformatversion = 0 filemode = true bare = true [remote "origin"] url = /home/peff/compile/libgit2/tests-clar/resources/peeled fetch = +refs/*:refs/* mirror = true libgit2-0.19.0/tests-clar/resources/peeled.git/objects/000077500000000000000000000000001216214232500226775ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/peeled.git/objects/info/000077500000000000000000000000001216214232500236325ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/peeled.git/objects/info/packs000066400000000000000000000000661216214232500246600ustar00rootroot00000000000000P pack-e84773eaf3fce1774755580e3dbb8d9f3a1adc45.pack libgit2-0.19.0/tests-clar/resources/peeled.git/objects/pack/000077500000000000000000000000001216214232500236155ustar00rootroot00000000000000pack-e84773eaf3fce1774755580e3dbb8d9f3a1adc45.idx000066400000000000000000000022041216214232500327760ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/peeled.git/objects/packtOc \!PK]Bn`K֒IYjX~&cA-߇.¶BX" }yBpe9 U<qh_>ypack-e84773eaf3fce1774755580e3dbb8d9f3a1adc45.pack000066400000000000000000000004221216214232500331300ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/peeled.git/objects/packPACK x10 @=@&uDBNQ6thSUG*JQKD R~m uQ>a* 16ϓvN-xK0 }N #!NvT&U n(gJjz|$}w:m5g@8mrKT3.?HH9Nps06Y&'M xyBpe9 Ulibgit2-0.19.0/tests-clar/resources/peeled.git/packed-refs000066400000000000000000000004741216214232500233620ustar00rootroot00000000000000# pack-refs with: peeled fully-peeled c2596aa0151888587ec5c0187f261e63412d9e11 refs/foo/tag-outside-tags ^0df1a5865c8abfc09f1f2182e6a31be550e99f07 0df1a5865c8abfc09f1f2182e6a31be550e99f07 refs/heads/master c2596aa0151888587ec5c0187f261e63412d9e11 refs/tags/tag-inside-tags ^0df1a5865c8abfc09f1f2182e6a31be550e99f07 libgit2-0.19.0/tests-clar/resources/peeled.git/refs/000077500000000000000000000000001216214232500222055ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/peeled.git/refs/heads/000077500000000000000000000000001216214232500232715ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/peeled.git/refs/heads/master000066400000000000000000000000511216214232500245030ustar00rootroot000000000000000df1a5865c8abfc09f1f2182e6a31be550e99f07 libgit2-0.19.0/tests-clar/resources/push.sh000066400000000000000000000031121216214232500205360ustar00rootroot00000000000000#!/bin/sh #creates push_src repo for libgit2 push tests. set -eu #Create src repo for push mkdir push_src pushd push_src git init echo a > a.txt git add . git commit -m 'added a.txt' mkdir fold echo b > fold/b.txt git add . git commit -m 'added fold and fold/b.txt' git branch b1 #b1 and b2 are the same git branch b2 git checkout -b b3 echo edit >> a.txt git add . git commit -m 'edited a.txt' git checkout -b b4 master echo edit >> fold\b.txt git add . git commit -m 'edited fold\b.txt' git checkout -b b5 master git submodule add ../testrepo.git submodule git commit -m "added submodule named 'submodule' pointing to '../testrepo.git'" git checkout master git merge -m "merge b3, b4, and b5 to master" b3 b4 b5 #Log commits to include in testcase git log --format=oneline --decorate --graph #*-. 951bbbb90e2259a4c8950db78946784fb53fcbce (HEAD, master) merge b3, b4, and b5 to master #|\ \ #| | * fa38b91f199934685819bea316186d8b008c52a2 (b5) added submodule named 'submodule' pointing to '../testrepo.git' #| * | 27b7ce66243eb1403862d05f958c002312df173d (b4) edited fold\b.txt #| |/ #* | d9b63a88223d8367516f50bd131a5f7349b7f3e4 (b3) edited a.txt #|/ #* a78705c3b2725f931d3ee05348d83cc26700f247 (b2, b1) added fold and fold/b.txt #* 5c0bb3d1b9449d1cc69d7519fd05166f01840915 added a.txt #fix paths so that we can add repo folders under libgit2 repo #rename .git to .gitted find . -name .git -exec mv -i '{}' '{}ted' \; mv -i .gitmodules gitmodules popd libgit2-0.19.0/tests-clar/resources/push_src/000077500000000000000000000000001216214232500210545ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/push_src/.gitted/000077500000000000000000000000001216214232500224125ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/push_src/.gitted/COMMIT_EDITMSG000066400000000000000000000001001216214232500244700ustar00rootroot00000000000000added submodule named 'submodule' pointing to '../testrepo.git' libgit2-0.19.0/tests-clar/resources/push_src/.gitted/HEAD000066400000000000000000000000271216214232500230350ustar00rootroot00000000000000ref: refs/heads/master libgit2-0.19.0/tests-clar/resources/push_src/.gitted/ORIG_HEAD000066400000000000000000000000511216214232500236520ustar00rootroot00000000000000a78705c3b2725f931d3ee05348d83cc26700f247 libgit2-0.19.0/tests-clar/resources/push_src/.gitted/config000066400000000000000000000003541216214232500236040ustar00rootroot00000000000000[core] repositoryformatversion = 0 filemode = false bare = false logallrefupdates = true symlinks = false ignorecase = true hideDotFiles = dotGitOnly [submodule "submodule"] url = m:/dd/libgit2/tests-clar/resources/testrepo.git libgit2-0.19.0/tests-clar/resources/push_src/.gitted/description000066400000000000000000000001111216214232500246510ustar00rootroot00000000000000Unnamed repository; edit this file 'description' to name the repository. libgit2-0.19.0/tests-clar/resources/push_src/.gitted/index000066400000000000000000000007261216214232500234510ustar00rootroot00000000000000DIRCPFPID1_IQbvI( .gitmodulesP@PG  jzu%P*/׶+wya.txtP@P@ax"-4ϽUV$r fold/b.txtPAPH6b& ʩYg3JT` foldb.txt_ӻn$MO_TwP submoduleTREE65 1 dU9^Vf9Mfold1 0 )7ΩW)Uv5zT ֕J+GqFlibgit2-0.19.0/tests-clar/resources/push_src/.gitted/info/000077500000000000000000000000001216214232500233455ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/push_src/.gitted/info/exclude000066400000000000000000000003601216214232500247200ustar00rootroot00000000000000# git ls-files --others --exclude-from=.git/info/exclude # Lines that start with '#' are comments. # For a project mostly in C, the following would be a good set of # exclude patterns (uncomment them if you want to use them): # *.[oa] # *~ libgit2-0.19.0/tests-clar/resources/push_src/.gitted/logs/000077500000000000000000000000001216214232500233565ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/push_src/.gitted/logs/HEAD000066400000000000000000000032051216214232500240020ustar00rootroot000000000000000000000000000000000000000000000000000000 5c0bb3d1b9449d1cc69d7519fd05166f01840915 Congyi Wu 1352923200 -0500 commit (initial): added a.txt 5c0bb3d1b9449d1cc69d7519fd05166f01840915 a78705c3b2725f931d3ee05348d83cc26700f247 Congyi Wu 1352923200 -0500 commit: added fold and fold/b.txt a78705c3b2725f931d3ee05348d83cc26700f247 a78705c3b2725f931d3ee05348d83cc26700f247 Congyi Wu 1352923201 -0500 checkout: moving from master to b3 a78705c3b2725f931d3ee05348d83cc26700f247 d9b63a88223d8367516f50bd131a5f7349b7f3e4 Congyi Wu 1352923201 -0500 commit: edited a.txt d9b63a88223d8367516f50bd131a5f7349b7f3e4 a78705c3b2725f931d3ee05348d83cc26700f247 Congyi Wu 1352923201 -0500 checkout: moving from b3 to b4 a78705c3b2725f931d3ee05348d83cc26700f247 27b7ce66243eb1403862d05f958c002312df173d Congyi Wu 1352923201 -0500 commit: edited fold\b.txt 27b7ce66243eb1403862d05f958c002312df173d a78705c3b2725f931d3ee05348d83cc26700f247 Congyi Wu 1352923201 -0500 checkout: moving from b4 to b5 a78705c3b2725f931d3ee05348d83cc26700f247 fa38b91f199934685819bea316186d8b008c52a2 Congyi Wu 1352923206 -0500 commit: added submodule named 'submodule' pointing to '../testrepo.git' fa38b91f199934685819bea316186d8b008c52a2 a78705c3b2725f931d3ee05348d83cc26700f247 Congyi Wu 1352923207 -0500 checkout: moving from b5 to master a78705c3b2725f931d3ee05348d83cc26700f247 951bbbb90e2259a4c8950db78946784fb53fcbce Congyi Wu 1352923207 -0500 merge b3 b4 b5: Merge made by the 'octopus' strategy. libgit2-0.19.0/tests-clar/resources/push_src/.gitted/logs/refs/000077500000000000000000000000001216214232500243155ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/push_src/.gitted/logs/refs/heads/000077500000000000000000000000001216214232500254015ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/push_src/.gitted/logs/refs/heads/b1000066400000000000000000000002361216214232500256270ustar00rootroot000000000000000000000000000000000000000000000000000000 a78705c3b2725f931d3ee05348d83cc26700f247 Congyi Wu 1352923200 -0500 branch: Created from master libgit2-0.19.0/tests-clar/resources/push_src/.gitted/logs/refs/heads/b2000066400000000000000000000002361216214232500256300ustar00rootroot000000000000000000000000000000000000000000000000000000 a78705c3b2725f931d3ee05348d83cc26700f247 Congyi Wu 1352923200 -0500 branch: Created from master libgit2-0.19.0/tests-clar/resources/push_src/.gitted/logs/refs/heads/b3000066400000000000000000000004631216214232500256330ustar00rootroot000000000000000000000000000000000000000000000000000000 a78705c3b2725f931d3ee05348d83cc26700f247 Congyi Wu 1352923201 -0500 branch: Created from HEAD a78705c3b2725f931d3ee05348d83cc26700f247 d9b63a88223d8367516f50bd131a5f7349b7f3e4 Congyi Wu 1352923201 -0500 commit: edited a.txt libgit2-0.19.0/tests-clar/resources/push_src/.gitted/logs/refs/heads/b4000066400000000000000000000004721216214232500256340ustar00rootroot000000000000000000000000000000000000000000000000000000 a78705c3b2725f931d3ee05348d83cc26700f247 Congyi Wu 1352923201 -0500 branch: Created from master a78705c3b2725f931d3ee05348d83cc26700f247 27b7ce66243eb1403862d05f958c002312df173d Congyi Wu 1352923201 -0500 commit: edited fold\b.txt libgit2-0.19.0/tests-clar/resources/push_src/.gitted/logs/refs/heads/b5000066400000000000000000000005501216214232500256320ustar00rootroot000000000000000000000000000000000000000000000000000000 a78705c3b2725f931d3ee05348d83cc26700f247 Congyi Wu 1352923201 -0500 branch: Created from master a78705c3b2725f931d3ee05348d83cc26700f247 fa38b91f199934685819bea316186d8b008c52a2 Congyi Wu 1352923206 -0500 commit: added submodule named 'submodule' pointing to '../testrepo.git' libgit2-0.19.0/tests-clar/resources/push_src/.gitted/logs/refs/heads/master000066400000000000000000000007741216214232500266270ustar00rootroot000000000000000000000000000000000000000000000000000000 5c0bb3d1b9449d1cc69d7519fd05166f01840915 Congyi Wu 1352923200 -0500 commit (initial): added a.txt 5c0bb3d1b9449d1cc69d7519fd05166f01840915 a78705c3b2725f931d3ee05348d83cc26700f247 Congyi Wu 1352923200 -0500 commit: added fold and fold/b.txt a78705c3b2725f931d3ee05348d83cc26700f247 951bbbb90e2259a4c8950db78946784fb53fcbce Congyi Wu 1352923207 -0500 merge b3 b4 b5: Merge made by the 'octopus' strategy. libgit2-0.19.0/tests-clar/resources/push_src/.gitted/modules/000077500000000000000000000000001216214232500240625ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/push_src/.gitted/modules/submodule/000077500000000000000000000000001216214232500260615ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/push_src/.gitted/modules/submodule/HEAD000066400000000000000000000000271216214232500265040ustar00rootroot00000000000000ref: refs/heads/master libgit2-0.19.0/tests-clar/resources/push_src/.gitted/modules/submodule/config000066400000000000000000000005601216214232500272520ustar00rootroot00000000000000[core] repositoryformatversion = 0 filemode = false bare = false logallrefupdates = true worktree = ../../../submodule symlinks = false ignorecase = true hideDotFiles = dotGitOnly [remote "origin"] fetch = +refs/heads/*:refs/remotes/origin/* url = m:/dd/libgit2/tests-clar/resources/testrepo.git [branch "master"] remote = origin merge = refs/heads/master libgit2-0.19.0/tests-clar/resources/push_src/.gitted/modules/submodule/description000066400000000000000000000001111216214232500303200ustar00rootroot00000000000000Unnamed repository; edit this file 'description' to name the repository. libgit2-0.19.0/tests-clar/resources/push_src/.gitted/modules/submodule/index000066400000000000000000000004001216214232500271050ustar00rootroot00000000000000DIRCPFPF #1 p="READMEPFPF 6KA=JqV"branch_file.txtPFPF ll@LVB1new.txtc1xNHGc?-Jlibgit2-0.19.0/tests-clar/resources/push_src/.gitted/modules/submodule/info/000077500000000000000000000000001216214232500270145ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/push_src/.gitted/modules/submodule/info/exclude000066400000000000000000000003601216214232500303670ustar00rootroot00000000000000# git ls-files --others --exclude-from=.git/info/exclude # Lines that start with '#' are comments. # For a project mostly in C, the following would be a good set of # exclude patterns (uncomment them if you want to use them): # *.[oa] # *~ libgit2-0.19.0/tests-clar/resources/push_src/.gitted/modules/submodule/logs/000077500000000000000000000000001216214232500270255ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/push_src/.gitted/modules/submodule/logs/HEAD000066400000000000000000000002761216214232500274560ustar00rootroot000000000000000000000000000000000000000000000000000000 a65fedf39aefe402d3bb6e24df4d4f5fe4547750 Congyi Wu 1352923205 -0500 clone: from m:/dd/libgit2/tests-clar/resources/testrepo.git libgit2-0.19.0/tests-clar/resources/push_src/.gitted/modules/submodule/logs/refs/000077500000000000000000000000001216214232500277645ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/push_src/.gitted/modules/submodule/logs/refs/heads/000077500000000000000000000000001216214232500310505ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/push_src/.gitted/modules/submodule/logs/refs/heads/master000066400000000000000000000002761216214232500322730ustar00rootroot000000000000000000000000000000000000000000000000000000 a65fedf39aefe402d3bb6e24df4d4f5fe4547750 Congyi Wu 1352923205 -0500 clone: from m:/dd/libgit2/tests-clar/resources/testrepo.git libgit2-0.19.0/tests-clar/resources/push_src/.gitted/modules/submodule/logs/refs/remotes/000077500000000000000000000000001216214232500314425ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/push_src/.gitted/modules/submodule/logs/refs/remotes/origin/000077500000000000000000000000001216214232500327315ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/push_src/.gitted/modules/submodule/logs/refs/remotes/origin/HEAD000066400000000000000000000002761216214232500333620ustar00rootroot000000000000000000000000000000000000000000000000000000 a65fedf39aefe402d3bb6e24df4d4f5fe4547750 Congyi Wu 1352923205 -0500 clone: from m:/dd/libgit2/tests-clar/resources/testrepo.git libgit2-0.19.0/tests-clar/resources/push_src/.gitted/modules/submodule/objects/000077500000000000000000000000001216214232500275125ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/push_src/.gitted/modules/submodule/objects/08/000077500000000000000000000000001216214232500277415ustar00rootroot00000000000000b041783f40edfe12bb406c9c9a8a040177c125000066400000000000000000000000661216214232500347160ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/push_src/.gitted/modules/submodule/objects/08xKOR01`0I6307L6L21K05I2640MM4771NJ5K2L-1 9libgit2-0.19.0/tests-clar/resources/push_src/.gitted/modules/submodule/objects/13/000077500000000000000000000000001216214232500277355ustar00rootroot0000000000000085f264afb75a56a5bec74243be9b367ba4ca08000066400000000000000000000000231216214232500351440ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/push_src/.gitted/modules/submodule/objects/13xKOR0aHSDlibgit2-0.19.0/tests-clar/resources/push_src/.gitted/modules/submodule/objects/18/000077500000000000000000000000001216214232500277425ustar00rootroot000000000000001037049a54a1eb5fab404658a3a250b44335d7000066400000000000000000000000631216214232500345440ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/push_src/.gitted/modules/submodule/objects/18x+)JMU06a040031Qrutuen~{T}ǝ6^rqh10dff58d8a660512d4832e740f692884338ccd000066400000000000000000000001671216214232500346200ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/push_src/.gitted/modules/submodule/objects/18x+)JMU044b040031QrutueXlmmAṃJ}G;UTWRQຳyv;slzC8Ti^j9XrѶ_,ٟ#4'^A0ulibgit2-0.19.0/tests-clar/resources/push_src/.gitted/modules/submodule/objects/1a/000077500000000000000000000000001216214232500300135ustar00rootroot00000000000000443023183e3f2bfbef8ac923cd81c1018a18fd000066400000000000000000000001721216214232500351320ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/push_src/.gitted/modules/submodule/objects/1axA 1 E] LMA M&C ڹGpyu|f@a5RP&)cDHc ̋QBryuxT-^ԲNj?_1 :Cu}4ylibgit2-0.19.0/tests-clar/resources/push_src/.gitted/modules/submodule/objects/1b/000077500000000000000000000000001216214232500300145ustar00rootroot000000000000008cbad43e867676df601306689fe7c3def5e689000066400000000000000000000000631216214232500351350ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/push_src/.gitted/modules/submodule/objects/1bx+)JMU06a040031QrutueXlmmAṃJ}G; %libgit2-0.19.0/tests-clar/resources/push_src/.gitted/modules/submodule/objects/1f/000077500000000000000000000000001216214232500300205ustar00rootroot0000000000000067fc4386b2d171e0d21be1c447e12660561f9b000066400000000000000000000000251216214232500347230ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/push_src/.gitted/modules/submodule/objects/1fxKOR0c0+(libgit2-0.19.0/tests-clar/resources/push_src/.gitted/modules/submodule/objects/25/000077500000000000000000000000001216214232500277405ustar00rootroot000000000000008f0e2a959a364e40ed6603d5d44fbb24765b10000066400000000000000000000002501216214232500347260ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/push_src/.gitted/modules/submodule/objects/25xM 0F]J_q\N ۦ<o e ݩn%;-Jk}EL  VxEb̮3ACd$Igւ* \nDi>rM,-*9p}HJ Ilibgit2-0.19.0/tests-clar/resources/push_src/.gitted/modules/submodule/objects/27/000077500000000000000000000000001216214232500277425ustar00rootroot000000000000000b8ea76056d5cad83af921837702d3e3c2924d000066400000000000000000000000251216214232500347330ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/push_src/.gitted/modules/submodule/objects/27xKOR0c0+(libgit2-0.19.0/tests-clar/resources/push_src/.gitted/modules/submodule/objects/2d/000077500000000000000000000000001216214232500300175ustar00rootroot0000000000000059075e0681f540482d4f6223a68e0fef790bc7000066400000000000000000000000541216214232500346700ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/push_src/.gitted/modules/submodule/objects/2dx+)JMU0d01 oͱ.[||Ndriplibgit2-0.19.0/tests-clar/resources/push_src/.gitted/modules/submodule/objects/32/000077500000000000000000000000001216214232500277365ustar00rootroot0000000000000059a6bd5b57fb9c1281bb7ed3167b50f224cb54000066400000000000000000000000621216214232500350650ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/push_src/.gitted/modules/submodule/objects/32x+)JMU06f040031Q0+(aOܶbK?TK elibgit2-0.19.0/tests-clar/resources/push_src/.gitted/modules/submodule/objects/36/000077500000000000000000000000001216214232500277425ustar00rootroot0000000000000097d64be941a53d4ae8f6a271e4e3fa56b022cc000066400000000000000000000000271216214232500351540ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/push_src/.gitted/modules/submodule/objects/36xKOR`JLU%$>libgit2-0.19.0/tests-clar/resources/push_src/.gitted/modules/submodule/objects/45/000077500000000000000000000000001216214232500277425ustar00rootroot00000000000000b983be36b73c0788dc9cbcb76cbb80fc7bb057000066400000000000000000000000221216214232500353210ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/push_src/.gitted/modules/submodule/objects/45xKOR0flibgit2-0.19.0/tests-clar/resources/push_src/.gitted/modules/submodule/objects/4a/000077500000000000000000000000001216214232500300165ustar00rootroot00000000000000202b346bb0fb0db7eff3cffeb3c70babbd2045000066400000000000000000000002401216214232500355460ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/push_src/.gitted/modules/submodule/objects/4axQ 0D)6ͦ "xO-FbEo0 Ǥ,ske[Pn8R,EpD?g}^3 <GhYK8ЖDA);gݧjp4-r;sGA4ۺ=(in7IKFElibgit2-0.19.0/tests-clar/resources/push_src/.gitted/modules/submodule/objects/4b/000077500000000000000000000000001216214232500300175ustar00rootroot0000000000000022b35d44b5a4f589edf3dc89196399771796ea000066400000000000000000000000541216214232500347750ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/push_src/.gitted/modules/submodule/objects/4bx+)JMU0d01K3Rgly02 #w [libgit2-0.19.0/tests-clar/resources/push_src/.gitted/modules/submodule/objects/52/000077500000000000000000000000001216214232500277405ustar00rootroot000000000000001d87c1ec3aef9824daf6d96cc0ae3710766d91000066400000000000000000000002301216214232500351600ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/push_src/.gitted/modules/submodule/objects/52x5A 0=۳P&i*^/Mܖ$+u={{8 NtnIQ1Cס m tmD+Bd+`),(6hIIxGʴαi>OTGΧk:{jԕyVpgpγT6libgit2-0.19.0/tests-clar/resources/push_src/.gitted/modules/submodule/objects/5b/000077500000000000000000000000001216214232500300205ustar00rootroot000000000000005b025afb0b4c913b4c338a42934a3863bf3644000066400000000000000000000002361216214232500347150ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/push_src/.gitted/modules/submodule/objects/5bx 1ENi@k2 "X$YW0YcÅszMD08!s Xgd::@X0Pw"F/RUzmZZV}|/o5I!1z:vUim}/> F-libgit2-0.19.0/tests-clar/resources/push_src/.gitted/modules/submodule/objects/75/000077500000000000000000000000001216214232500277455ustar00rootroot00000000000000057dd4114e74cca1d750d0aee1647c903cb60a000066400000000000000000000001671216214232500350560ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/push_src/.gitted/modules/submodule/objects/75x+)JMU044b040031Qrutuen~{T}ǝ6^r"(1/9#>-3'Uug>6wٞOpҼr_ʧ+O\\iy|tI/libgit2-0.19.0/tests-clar/resources/push_src/.gitted/modules/submodule/objects/76/000077500000000000000000000000001216214232500277465ustar00rootroot000000000000003d71aadf09a7951596c9746c024e7eece7c7af000066400000000000000000000002571216214232500352100ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/push_src/.gitted/modules/submodule/objects/76xAj!?009o}H6}jUPPZ&Y AԛpFdpz[fYPqLJ.,Z`Ů.`v q $5+9Ot>/DE/龡W*eVdf1>覭ěʙFThk.i^0?PR,libgit2-0.19.0/tests-clar/resources/push_src/.gitted/modules/submodule/objects/7b/000077500000000000000000000000001216214232500300225ustar00rootroot000000000000004384978d2493e851f9cca7858815fac9b10980000066400000000000000000000002211216214232500346330ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/push_src/.gitted/modules/submodule/objects/7bx-A0={7!] ,X@`5ds?0OhBR&*4]Mo ȡNɾ09(J|1$pD82$"GgvdjG]j7x22]s0libgit2-0.19.0/tests-clar/resources/push_src/.gitted/modules/submodule/objects/81/000077500000000000000000000000001216214232500277425ustar00rootroot000000000000004889a078c031f61ed08ab5fa863aea9314344d000066400000000000000000000001221216214232500347310ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/push_src/.gitted/modules/submodule/objects/81x+)JMU0d040031QrutueXlmmAṃJ}G;UZWRQ°\erw solibgit2-0.19.0/tests-clar/resources/push_src/.gitted/modules/submodule/objects/84/000077500000000000000000000000001216214232500277455ustar00rootroot0000000000000096071c1b46c854b31185ea97743be6a8774479000066400000000000000000000001761216214232500344730ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/push_src/.gitted/modules/submodule/objects/84x 1Nۀn` V.`.pa Ô{StlH,_9$$cf&hXQ*g)cV~p~"Q@JnZuӶL 69a5e34a26815e821f865b8479f5815a47af0fe000066400000000000000000000002061216214232500347060ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/push_src/.gitted/modules/submodule/objects/84xM F]s41x(IKݽ/_P@!8)es N&FGSƄh{+CZzvF7Z-kx\[P8GK/^ l>.4libgit2-0.19.0/tests-clar/resources/push_src/.gitted/modules/submodule/objects/94/000077500000000000000000000000001216214232500277465ustar00rootroot000000000000004c0f6e4dfa41595e6eb3ceecdb14f50fe18162000066400000000000000000000001671216214232500353240ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/push_src/.gitted/modules/submodule/objects/94x+)JMU044b040031QrutueXlmmAṃJ}G;UTWRQ`6Kǥ^/-*|W3Py`%E\&g|0{Ӎ1Xlibgit2-0.19.0/tests-clar/resources/push_src/.gitted/modules/submodule/objects/9a/000077500000000000000000000000001216214232500300235ustar00rootroot0000000000000003079b8a8ee85a0bee58bf9be3da8b62414ed4000066400000000000000000000000621216214232500353230ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/push_src/.gitted/modules/submodule/objects/9ax+)JMU06f040031Q0+(aP[v L libgit2-0.19.0/tests-clar/resources/push_src/.gitted/modules/submodule/objects/9f/000077500000000000000000000000001216214232500300305ustar00rootroot0000000000000013f7d0a9402c681f91dc590cf7b5470e6a77d2000066400000000000000000000002301216214232500350240ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/push_src/.gitted/modules/submodule/objects/9fxM 0F]d2;XEȎ5R AE &n}ZAd738e8f7967c078dceed8190330fc8648ee56a000066400000000000000000000002401216214232500351450ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/push_src/.gitted/modules/submodule/objects/9fx[ 0E*fդ "W0-Ft݁pS[Yx^ Db CLhut}8X*4ZsYUA X3RM) s6輢Mរ&Jm;}<\@ޏpĀv?jۺL?Hlibgit2-0.19.0/tests-clar/resources/push_src/.gitted/modules/submodule/objects/a4/000077500000000000000000000000001216214232500300165ustar00rootroot00000000000000a7dce85cf63874e984719f4fdd239f5145052f000066400000000000000000000003101216214232500350440ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/push_src/.gitted/modules/submodule/objects/a4x;j1Dmdǎ|M3`V{ >QvL0I?!4Z=!צ8F!rsQy9]$D&l6A>jFWҵ IKNiZ%S  U~̽>' w [ DGڡQ-M>dO}\8g_ШoYrlibgit2-0.19.0/tests-clar/resources/push_src/.gitted/modules/submodule/objects/a6/000077500000000000000000000000001216214232500300205ustar00rootroot000000000000005fedf39aefe402d3bb6e24df4d4f5fe4547750000066400000000000000000000002261216214232500354100ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/push_src/.gitted/modules/submodule/objects/a6xQ !@sBQ" ٱ r{:żW9гVlq=(1/9#>-3'Uug>6wٞOpҼr_ʧ+O\\iy|tI=&libgit2-0.19.0/tests-clar/resources/push_src/.gitted/modules/submodule/objects/b2/000077500000000000000000000000001216214232500300155ustar00rootroot000000000000005fa35b38051e4ae45d4222e795f9df2e43f1d1000066400000000000000000000002071216214232500350710ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/push_src/.gitted/modules/submodule/objects/b2xA 0a9I p'1Ѷv\x{cVpvWgǎ0x[ ]"g#{rD Cot N U $?9-p+1^Qx9O\C m'D {mV(+l,libgit2-0.19.0/tests-clar/resources/push_src/.gitted/modules/submodule/objects/b6/000077500000000000000000000000001216214232500300215ustar00rootroot00000000000000361fc6a97178d8fc8639fdeed71c775ab52593000066400000000000000000000001201216214232500351270ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/push_src/.gitted/modules/submodule/objects/b6x+)JMU03f040031Q0+(axeiwg26Eo(g0E.{PbTNilibgit2-0.19.0/tests-clar/resources/push_src/.gitted/modules/submodule/objects/be/000077500000000000000000000000001216214232500301005ustar00rootroot000000000000003563ae3f795b2b4353bcce3a527ad0a4f7f644000066400000000000000000000003021216214232500352220ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/push_src/.gitted/modules/submodule/objects/bexKj1D)zUB-0uV9<#+Wx: 賄1^POA_rC-%3Hgv܈@Epքʤ'S2JXDivYj@pLo_B-'hC4Q"n_#qLO1R5rn <[^{P !?slibgit2-0.19.0/tests-clar/resources/push_src/.gitted/modules/submodule/objects/d6/000077500000000000000000000000001216214232500300235ustar00rootroot00000000000000c93164c249c8000205dd4ec5cbca1b516d487f000066400000000000000000000000251216214232500350570ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/push_src/.gitted/modules/submodule/objects/d6xKOR0c0+(libgit2-0.19.0/tests-clar/resources/push_src/.gitted/modules/submodule/objects/d7/000077500000000000000000000000001216214232500300245ustar00rootroot000000000000001aab4f9b04b45ce09bcaa636a9be6231474759000066400000000000000000000001171216214232500351470ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/push_src/.gitted/modules/submodule/objects/d7x+)JMU03a040031Q007L6L21K05I2640MM4771NJ5K2L-868V;'!gά.libgit2-0.19.0/tests-clar/resources/push_src/.gitted/modules/submodule/objects/e6/000077500000000000000000000000001216214232500300245ustar00rootroot000000000000009de29bb2d1d6434b8b29ae775ad8c2e48c5391000066400000000000000000000000171216214232500351720ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/push_src/.gitted/modules/submodule/objects/e6xKOR0` libgit2-0.19.0/tests-clar/resources/push_src/.gitted/modules/submodule/objects/e7/000077500000000000000000000000001216214232500300255ustar00rootroot00000000000000b4ad382349ff96dd8199000580b9b1e2042eb0000066400000000000000000000000251216214232500347320ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/push_src/.gitted/modules/submodule/objects/e7xKOR0c0+(libgit2-0.19.0/tests-clar/resources/push_src/.gitted/modules/submodule/objects/f1/000077500000000000000000000000001216214232500300205ustar00rootroot00000000000000425cef211cc08caa31e7b545ffb232acb098c3000066400000000000000000000001471216214232500352670ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/push_src/.gitted/modules/submodule/objects/f1x+)JMU4`040031Q0+(av0 &ֻ~GO71dY쳻^Dq?$G+TmfVVfu򨭪V'5libgit2-0.19.0/tests-clar/resources/push_src/.gitted/modules/submodule/objects/f6/000077500000000000000000000000001216214232500300255ustar00rootroot000000000000000079018b664e4e79329a7ef9559c8d9e0378d1000066400000000000000000000001221216214232500346350ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/push_src/.gitted/modules/submodule/objects/f6x+)JMU0d040031Qrutuen~{T}ǝ6^r"/\F0|Z_8]nzlibgit2-0.19.0/tests-clar/resources/push_src/.gitted/modules/submodule/objects/fa/000077500000000000000000000000001216214232500301005ustar00rootroot0000000000000049b077972391ad58037050f2a75f74e3671e92000066400000000000000000000000301216214232500345250ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/push_src/.gitted/modules/submodule/objects/faxKORdK-WHI,D libgit2-0.19.0/tests-clar/resources/push_src/.gitted/modules/submodule/objects/fd/000077500000000000000000000000001216214232500301035ustar00rootroot00000000000000093bff70906175335656e6ce6ae05783708765000066400000000000000000000001221216214232500345410ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/push_src/.gitted/modules/submodule/objects/fdx+)JMU0d040031QrutueXlmmAṃJ}G;UZWRQsCtk# >-/y.7 4959ce7510db09d4d8217fa2d1780413e05a09000066400000000000000000000002301216214232500347270ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/push_src/.gitted/modules/submodule/objects/fdxA 1 E] /i #sGy_cvyBCȤ9ZDsGٌG`J͞cb@%X7^%HA"$Z\Z4uJv7l{ko178ԑNB6libgit2-0.19.0/tests-clar/resources/push_src/.gitted/modules/submodule/objects/pack/000077500000000000000000000000001216214232500304305ustar00rootroot00000000000000pack-a81e489679b7d3418f9ab594bda8ceb37dd4c695.idx000066400000000000000000001331001216214232500375510ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/push_src/.gitted/modules/submodule/objects/packtOc '*37AMS\fksx}  "'14?CDGNW\`fkorz ),16?CMOUY]dlr{#/27@FMQY_clqy $(35;<DKNW]aem}  "+3<DINZ_ailrx} ),17>CFINU\i%J7B5/РC%QK;QYC*˥ۤ?y~S7U.!7EL5ue].SO!ܸrX27*pls Žmݩ@4}`;N-Vvj%r=-]S:)_-V}E61n$Dm~]v^4I|xg6d%q[WX%hWʐ;髭Ҹ 8tCOPrd^VY% 6zg )G%O &!r: yz(>eėLp%_z-NG@' Ӿ%v4QD ɿ̎Ǡu8hPp3V?Maui-JYXX+|oCۻzQdƣ2A `rѲJ^ށ)΁9Րb-fqAkm+L=1b]GL仅 .z w i A3@/{UgM!& HZ.n}-|jSWˣ]0CF \g'pzU"O ;$b\k.$N(n!izal]3l @[5O)zsuPIt J n/<nU?,.C/xp߽aZ~sw]@hk]C<PLMn\|p"gXϋWfF'؋m1ÚKgoʚJ:| !-ij*=( pC֨h*]K@YJ{(wC5(;}鯂M ]FNBq?[if&hj_>y%!(HAìV\Qž еq0@ at|l+>/x%8e@NJ.i2{nU;:~"O5 Tun?dM3θ1k+}Vv 7SZdgǵwɌgm=Tj,SudzK-ZPq$ LX [*ns |mg-kh݂Rt0Q#٦V#{+uIϑ3 z4+cWkB Z=D]yߎǷϦ gTTҶI\  ^vE>Rq(?լq2 +@?] IWȼ( zR#䔟9` i^SUەmE$O .>o.7{Ęn yb`&`{ !qL܁w~E ҊCZȭHW dF kE{ B ILKR ,L m,`cE5pB3f ~ 1Nm0$FT~SЋd / SH2,ܙm1 ~ٹ/҄q= ͟&\͹ 'P7R cFdaKV< 0dO|Ėκ0q<{!r Y )F2k$'uHw yb5[M B׬. }g L.1 Rpuv1ȟ 7lH ~`yP dUbt $JjbZ m  VIML^&[&XDMBcVc'R)%q{"t1E7eP1n]QfmIljΎ()gTˣw9rfW  =M2u%sP{Wh5𺮇n0Âe@K+ CGkf'+P/{abU vvK(/YrO8&Z,:+lIػ)jr␳s.m=!ƾV@圉L~';K&I9}n:_edء;SGK0^q_>4p wd 7ɗ,QlmrV۬z4YhۿΟ'$VdRaZT&z1 %llV+mѷՙjkÌux'=ҙ|'| ݬͪu;/+J҂Y Ck^fw~!X"pÐ/aa|n ~9IʌIu[0ƢΣB/~LN\9Tz;=8òXޚCjRi9LOJ| 5"F\=VO㤥FMM]rlDȓ #9ߦ_o#8}:,ٟgrl1y) N!@%5z*+6qfNڶsb_ɞW2؊zHV6Ρ يawI9O5 <_-*64w<2f{ N+L6ZQsb穲S*y, ijS9qW<: aYK[67Ґ f>OcD18~M L IIaQq m@| J8 obG.36 Ħ>ا J ё > Ƽ &k_151d!>r ^,B.(!]IƀylʘU!dE5jImXY ي+=X"sX>}[Wm2"#l3޼A="_"uEyzf"nB kk1h@"><ܥ: ?x"󼗡VV{Qvp#Q;RBmP4G#nuyv;r p`/<#T]GzZQKƋ$m md}7!S*$4[ΙSA,Po$󡴕} I=BZ%no%-%%>JLee)1_%&?FIae0l&WS@%Z V jJT\%{FK?dI<>;%Ѣ }ˀ (&=s nPA'ƿ oZ, e'3ƭ%b_II''7d*jJDiJh 'v5Q,_k!]sk'x<> h4;(jx]Vd0L(vypMIo(w@Pn`eW@h(oZxHrYԲn)()(.Z 1Tu) :b7:O*ewko6 @5G*mǐhZ䱍1n *~gGBF=o$^*0X ̙ `YF+w:>9+zQMAgH+cYrxu:+ViF*I٨PG+?=9&ý#Sׁ`, 8#F4x2<t3,KwՑepW2>,0GMjص,WEDK-7F,W ԆJfKR,;9r4^,׈8Xp<8!v,ED#;P:Z}ѺC,%PjFO ,`8¾l`IH:?-8NsӦ]e h5TC}"-#aa[wy-$Ͽ_X>kSv3h.*F D=6 .>"._x HҁyQl҇!.gvt[*JBT ,M^aI(G2P!;%MF(]}TW0 2FFå" EA2ֹv~P/yr#g2LSPJ_ :s2M?YxEW3x?;1)xaR38{TkI\FB. 73E ݂3OTtlo#Y(}53jNF'Q,1;y>3j*@P>ch3*kCb\3΁'R@ݟXq.3=lTR6iP9}4:KRpѓ_%4BHn*>rX?4Xq\;q24ۥ*z# ü^v܍&'43x³~R ^#Z%~%5ivasi\nՕ5JI$BU=Q_5{#qmF h$O5S@.yʹ|y16 yxQYt0qRJ6z֞3p륱/yA6ͶfĹ6<*-ޚys T6Wxܛ3|ۘ6e(1Qܵ%Ǘb73Ef4pdt)yD|D7VIy(š Lm7 LP =y xoo/X7oIqE6DLD7?W tCG*)8=RwQ,N6A8dҪse1b70Ml8b!`0@ͽ1 S8'<[pښ9}^dIڞOLV9") (G7Pc\9X_VK16:*'g'p%0l:3dzUս0F%Id:a+;͍/#-bj:kpfKL[.m?;;T$:>d"FlIo :QN*( V9:LVCs"ק؏Z/:WrgT\ %ٹ] x;D67K|;Qo;59|J ԊI;k+8=WE8ۧ;?+uoJDI0;I>j3xPZZND;a6yCE@(=XӼM6t;k>VBmFE _٭Y>Bـ╕W.U \ 4_>3xCW[)nx;I>Y"4yV=$*+>f^իuşȶ3>`n5m>i J ?lSeS?ThjI*)[Xb?aWCbѐˋ? tIX1D ?Iq_?ۼ(܎ / h0-@3ָz"O@]Y_Mh@NRgIQ@cĪQ_+ͣc .@n?)$? II @rk\:v{S@x #q# {@ v6>ϘF@#ɺ~_A/ZL@zs*f)[Lt@_{ Fsi9R?@ᯃk&sҭhKmoA.䦧AVtLAA݃姹/p.ŦjA A ߆5g^(Aҏ8$ؖyVaA|!|t6k[MAX}\:Z? cAZpQFcKFA;"y2! B6tAD٬JC6'T]mB >_t7JB(~q7C$`3.NB.߆ҳd~%13ݟ4BZ,ipF~TbrB[<ՌzipzCJB`i7k12$XB`K F+Q`e64,Bua{*r,ҡ&MB|^pbbBE}BwP1wƩI(Y2RB@hyu1]"bCz0aϻ8*\C `NQ;N]^ζC$\mr~J}~c.C(3 PjE{GClڈGeIȝgC*˿[:S\oCC@.kJ(vÏFrD#l9KHŞ,Ö~vD(߷"c2x[D0! z<_0HDz|'IEa>DeLyQdCӷDSL®G hD!+ʌ'QHSNt1ED޽ĐCJPZ6v5EPK{^03o=*Euض24Z)yEQEBE'6ƂMTF+ӆmE6:E4~~*L"E8j( N"ژF3݁F$$c_}##s6F80~s{tڞU#kVF_UFSor F?mF@V_1HF]c6D4^F#O ID Fظe2fKb{YFwq='fg|mFB;[)'G\kkg6ZV+'4 GwӇ/YvGrm!M^GG0"BvW̏ynXG8$znG_:V@dw}!щG'2(a: *-MWGXN ן6tu {sG^uLQO:P:q%HzTҩ;%ץ;HCpmW)H]4j 5+YH.RDa)NQNIB~- 0Mm7IzC-O Dl8iI0kltGɒI^`_IBhsIhC3-:I#| E-J:+nQ. NUjJY?Oa+.!ʲDSoJeY./wm.LJ'4x8RD@M2JVV?QratjF5K #xw0* hK )>6Ip쭱KD#5}EI[K2y^FkeL;30kxd!,! LdQc赍gN՛*LeE1!F +r.֯"Lg_ {Re)L9s)BcGQLbr7y:M%vS `1 h-bgMP?J$P~tF<.9MRM[*!Qنb/]?wM`ESp?>3EMRwA5aaѠd#}N mM62 ؿ=؟3MNgi\2]NuVӘVN~`V3hN'Ⱦ}uΰ`w4rLmNYU|Sj IO o+kU7KzOU/r$]|On豳ȣI@-O9ߔ\*1)l[gx/f-f4?[̔Ixv&Cl[(N\ [a}RD\u.[ˠ@BRqڎ\l%'RQ$hmg Y\ѵcM wM|qBf]y)+D7)幺,]ef5챧+1Ɋ]@&^ċ%]y]>JbId]{0]U9ToA]蜽 C 6]Vx1NJ'ᶔD^m oyPc`^xGQmȝ^ l+t]b,d^4+/u$F (^טa̗k}ySeV7Ť _kgO#Hz%novk4lqҳhw5&lE C7fa2m j+C3m4*:>P-mdjMK:;HHmh9agRqJHm8CDPߠKimVgbǝmUh{7plSFEQn[X@.]@A%w+,n؟4UBPn+1N3MP֜Px,n^)޼ RY [n71rhIVnLކ[!c Bnݯ20e&o,)B5ӦfנoN,B0(o!xoj6 W'a o e8cO P?hr}$ްsrQzu/arN-̛W9Vy2v7s"d o4sP3z-ҡ_NjȞsc!J`s!?sV>rIϏjGs`*tr`RFsݒS'w×`DvКLjV 2-wܧ}u>x(7)?1eXuf^x2WӶ'-K;0QxE6hH!3~ xKup;D;x]?Z,"BF*Mşx'ErU̐Up#Ǹxe4x3 i_Y4yP{72u~y&͆m}u0 #X]y*.Fʴ y_Dr5]7"lylРk*sɉiտypm'f5` hZ}y.@<,p[z+ysu8UנZLjz;Oi`f>$;z2zl7V4dvU5,2{A"zu |2n} Kz-DR5P0zA9EvW枾nu{Qfѻ7{])2hO^^{!c{lln'n6GY7{ng얬A2Ճ{}9\|j̕z%m*kJI|%wQ,9q|lVM2(|)~(osS5l8 |kM-NY.U~xիJ ~Bk~|976HgMGD#.0~/!#p PJUTHf}LR kV1- Fl {(@(i#TaTW}K,Q9>L=D:2&=$]]wiUn-9NOq@b%}@AtYsGpcݷ+.jEySM톋d4;XM^.ey%$'=ؾ w>ͅopFw|hdQ5%qKȌbg0"1x :E> }Jܝ:kMAK-tc#j #Y였io`g[V;$coq!QNrW{Z[qf"e}#+r)Ǡ%ݸr<"W7tXW&6JtgfSnK 4vD—5L:ӫe,jH?r퓰@GQFOQ2Jyw]|v*흂;5L!r?GĬ̘c?ϺUk̃{&pgdcs#k뉃:սc {RSXz51=_@$δ~je/\ KHBW}-x1F<a8l,a9 ; cK44A_(Bv@WEt{zЄ,_i08E&g\!<f*a|=ɱ°kfNJl鬄#?D E߄,ɍ3S2^BxǞa99{MLɮ| NGJW7/88)d|N?4.!`DdyvF>TTCc-$5 UrUM Fvo  3Fsx|Jo$M4T7ې.iџVBJ!҆rlZ2A/v~ʚExxm y0#d|\w !meޕk8~;DwmÙ:69ah"~Ä {lz*؍f>6[O .҂ > G`O^Y"rA`=hYͫQ |6SV^"B? P6O*Y,uϽ9հ+y[ql3Uö͈D[DTmsFkP{uLX~/ Yҷo#=Is#ߏTk2EZ}npfIL38pPKZO8'4M[5et⿚,!}p)ɉF͹Oʉ)ςAL{dм؉+L>ሺ-_oD!*d8"|.JW܃&x$^|cqR\F ]Ӗ `ӮRW[/Imrs+S9M] #I܉?1fIF3ȢKʢGez<;p޹됉{M: ޔ'zeO_wM5'o\>UAm>@@[8k:ș 7ΉLgUϑ>ފo*;ώC7N\ AHM-ɈfKF|6S5x.t}mKC]kRO  DS }b_Srop=hmT󮽿Swv4#&Sh0dH/D郞 )$(j.3A<C^Vfoҏn72\ `LFy}pRhlY2Dh e7-Pк#Mu)||v^c A-D5t1#p>qˋVȪ 5𑗚bKTUwv8T}`*B9i<Í~WS_]z ~x3ajLh(e=lzm-an:ꌇλbZ*IAS7ȷŮ69z“Al+AQ!3 *l<ޒ v*O3"efe(w8:ҍ[~ MBGWyI4 KOT!6(Ǝz,Z[Z/smr济Én%-`egI|ـ̫q_|0[0ru#5#FB {PQ8᮫qD헺W(O۾ADɻFS,-| }kq%Wu;!b,0^_`&BAs"b|@v~ҴT1nxF)EnpX"IcY՝3 W3yk.# H9. cU.ۉ|ѿŠ4hOIskHwB/LdOݬW\n#RZ~},o6 uG#oIЄ'.|+x lTq8&eNB>M7(5wъ0GceWZӛR H)umP/(w|c9˜uqx-kɼ Cכ[`] k"5<\ |=Y,Q:irhV ԚzuAJa69<9!U B{h C睳<7vCWneޢ3k dmI]s?9 ! : M CV, VdJܪǿ0MקY.kkaA>ZR(FD٭ G=BGL m [Lv !i BdHhMA>`3ysw=/<V؞ρF:RmNA.e(5v 5x'W[̊F"F7ɄhvcQ";_U,Se ?jFQ*|AR0@V)}ci }g kg٬Y[oncbq񼡥^şb4U=*q MJONarpC;N h1LKJ7Fj1׋K,;^2XBFAa s:˹cd3%';#Z/R/ȫAOd)EZ_3.wVI_^*!{"%$2Z Ɯ9ä?9E=^7LUb{ݤ[;*Y5t#H-א?cmЈ2=j!W?^@m/cMUd5'@'ҳ'M[$ˤ'&A*[Vyy JsC}P}fh) O YU,R~[ab>6Y6 /-0m6ե= B^[^2c"9h \`#%ʤ*fQ`4![)D3ɉFfͨȦ})Ļ2>4DN {B3\Qpcw5"-ءk8ŪP uj2FV*dSVS"" ~|8̝\ f$~RԫLHCZopȆNUŔ?Ģ m:i\%q0ϧE_DU\n5~L%jv:2'!0#ZM %6svhGp_3\b) sFѣ姩ɲVnuT rc c9*o˨|rA?B@dZv!T+JN`)XEuG=!@@ cL 29vg]R+;i^Kl06o+s GSfwd۴?#N_3Bard'(PA]YmRT#i 4BQLֱ}yHyVl· 6yDYSSN 3|vث;a.w_" ūo0olcN<5h>!΍0Ǚ*k(cCpEn>e<M5*^|LE iWQ}%I=-Ab 09*<7፡uQsm/VܱK)zridb! /_ ɵR'~/뚰RKԩP |߷<`e讱9Q~D'Bh> d@Fnc"T4wyK0H1=~fђwi0SDu0),w*1Zt30ׯ;վ3 På̯U( ۆ寥'y^IABݰs,TG)ZL:9/wbC=Ӻga/*Kjp'8N1ن  ["˰VvcxMpnj冓srB#=5}tә XAKBuQu  >#tkBL@ ^'6ԟ}5ǮOi։7'mpnjA n[߷2>1:9m_uUL.gSv?v9͋b} fϊ0w`{` gVvHVp@/ŲJ@%CڲV%} mUo3B=1ޡgC#IF`Mqwc~$e Q̓k}j(lJ{iӳ4B;W'~Lk$N?-l!2"1aN,X4#U]*p^ŋ:t&VgpU!ޠ:=- i#q]TYiɒNqVid0bO#v)KT ]ywdġFR7{E/#C,*)N<EJ`4я}յP 1EiA9 ]~I.'յډg] 3w!j]3!Box$#%7چb{1F \޵*;v#&r(}#VG*AR} ;iv\F"AvU1y`C߼7Yѷ՟BI:JD @pOG/V4f-S撷~ٓ5pf)n,ټۼHgf_OrtkA,g@q%x=9pNکnJxd5$v ~%ɲ6j\Maѷ-;YM|=4n, ȑ)Ҙ#.HBpFj?5cdb>;gK Løc`ƞ#Bcָ+hxk {q#Dù#}nړL;y*sP_ЏCȹFPэ lNYB%!n%-K$K 01ּyNOXo ,̻d99yr[sa8M6z^@Ҍ+*/lܣ{h. Xپ??--%Y!jdb۝XxҚQ*dC#(`|~]o=3 W,n Jyb5\S@2I7L=g<]cASסfHu\"PXK6t;9%ǻ):iZCDɵ@ojSz,w{F[_ANoD®9ӽ"܃i ca<'<ưHzA[5g#ǜ3BQZT{/y8lI %bKlnڋG3`Ѣ^E^ZU` 'l62ېd3"U^x$7+_OZ1v'3S\[kI/3V΀+܃C߷UAQ.8I oc;mJwc BBL~ٟR_zҟx}?rQ zYxnam"g]Ac;"K㡘-  rF&L& YQ ѴZBFp8Trz<$);Us3zM'i1?@D,dH 6PiE, ;ؽjR`JLRLIR'~_H+py$X86/R4 9)HBcuV2کuz8lvLDO`Lݮ"3J||d!C8ˡ-2VHY,ug",v\V ƾٖ \!xb% qaI iY&Ѵ _MP1/+.5%'Hu3_QL,TzuCllW4 ѭۆv]*A 8_X`+QGe}gUƳ*~8A35+2U=YlU ~xM2G넧{DnmG☀+e9šN@C{E`I v ]!Aq弗}x]a!N2U N(oLFW+õ:5L[r'Ѝ<&h_I4.JFsh~Uy BxPIأNn=͇Hz3Lĵ/u i cG-?b?$HX`HCDP{ c0UPm-Ko1h \i\RLk:DUtnSffs¯@dG;_kΞɉ mqˬ dEꜤ \˜,5I*"L;퐻 Z}3cZdR"cB&3z=+kfQY9v_r5h?n r A)l)r:W8ly|秜_ !'PmAD5fKzo1߭{Izs%MEMu> us4sH tQ?VuFʖ&Gz#6}Х Р0h*&}mФK rZyT 66ˈP%aւ畝KaoZzY:_P'w Ǧ0}hD/TR6fUA2uYJ"i^`6{SHy ڠlS˖jE!^m]~{eJX?0#CպJM7%/P+G-^әA9o"O9OYdBOӲ>r58{EE4$@J*0ӫ4=^aދ>p1O Qm#&@Hķ3I1t,~(|9F7Y{".GD rd9us5ڢo`]Y8LF,R}!gϜYGG.r@gn"bzQ do35 kuԍQޡݎh,ԐE&.?g9e2BiԹvV?}" ԩ\؊ z^ՀKw?mʌHVpmP <<KGԸtj0?S1cjLx.EHhG^FRSYUwX ƄX'NiM/ ~hlǸFyI"Y\iklOVpDٹ܎@baH.m"0gUCJmc2'ZנtS/ s(x ׮bc&W0|3 >q _D:"~D_Ada/Bvq1AfW ENL `>ԯM +I=dN4Gع:ՇI^]g2~3m@_'sh{ِ70U^#VU >r٩e퍷 "&nzٻL;lQvRǰJ-Ic;@+CyHTUe/ަk\ rN IMPx ޱnϟy"L">y&>fgU5~0%hy[+saH pN:q5y߮n݊;@1b9"5Y'4FB|=r[{{OwEҝ|2c{GلfDhOhD_h5IE)A8WAc}߾|U|p Znvt:1oO t;Ӿ<,ΞglOtfg벾1z?VsM4vPo39äkzW/Ή'Eһ5Ts,NK=U7@RTN'0>N $f 6˹Sٜ[=ǷyEh'rķ-n6q{u'UE¾6kaPvf.`Co1$(b\)j=̧ڷ3h(Y68gQ1,blm6)ijGlS/#Q9۾'. :KhV$}8@f@q^M  ȫ(6`X^vQ4]'?_q4r jRt 2@|(WRդN?*~qU5~"N]}aދ;нG'A"@#0yV3GL5 z墅S] DWyʬ mDV2RϞ=-^,Oj"sK &tJEkn8ߏ";]8n,&Žb2gtėgV74K°1S?et^u3^Cu2KrwB\wtԪEV +\3 40B}cw!dEEA Df葛ɛvמt,#$7&@MK+ 1S},w芣g`Dy(z+2k6BMr*% hp*d6uEls""= !ܜl"r>"D#kL(k<*ߐ =$4l8M aՀ [-pEzИJhq^z-\(_G2 f[!<dC 6}1O1"BwB.{LV6ȷb/<Fs?2|Ar(C0H)Pސ, y^P#(v:C M WSF΂@yۥW=|#f ]DbW; RO% nmqO^_sfsMZbdLYrj&F^a6JzPnAӼn ~$1^55fynqt[Z'/튶/ ۳9Rez|S%?1f[4_jL?7Ck'8hT yTF{KxE{m&ꦢuV .Sp?# sVC0T"e)kDƠn5l.#؀Wd;?лp@Hs_Kn,%~ >[ɣ_jK]T/aM\9~OWtPw3 +ʍ aGaĕMVm)ˣEaĞS}$+$拏rjm6{ÝjdamBw &uuiՒ9VO} 8.֐zX99|*+FYav37K $v݂״k )7L+wJ-P#j`nM~Y0^dMZ-eAYdwBS6[OM'%O%d[u}M鉸_A.a$D[ۻo=PPlHF=Ake30i쁇L=j.}S<}%m$^I=,iGx=i51qUI4 ikp\!;򩊈3r}rk+[=A$Ҥn 8cUṾ0zTL vAwQ)<ʰY@krX!VQjǢ\.]HwՃqr?JO&N`g47 h}XG^6K;'ր.$% iq㽅Ec;lyn]-q@@|yn 0OJ@%\; ؘ!)G`~ Na,';iSж GklX<%6ώ%3z\vHǤ$WOc d)mk&Hq zbEfЄo."@Q$FdQrUA/_m9PuǾQ@a\rf SO/WcK[[yqATU'>U1 s\_3? < r3AQ!\ &qt4u}۪"3 #gv.a-] 5|XP- p8 39H2eF6å0LUG+EKNeV;H8a( ;ܩW2YbY5k"5<8:jB#pAez݇Gh}K3${ ,P(ld=iƩ|~30;顿i3c7ħp[40 ,3J(BrAZItAO-Փ/8$7JrLٕ}TV!l,qܪh:1Z tE၈9g KB\8r{YڶjU^3HHkk&UJl48w}cq/E.Wu 0qmiB9" 1{4b-@O~8ѐʨRJSϽŌ$ ^Qs*J<ɷ,F i:7& @uhEARN߱KFݹ`<-o^Hڐ٩3ͥ_ $OºMVC!!{hMbCmBalL* ۨcNa aۆrb-xkչ PnS&!x0RG?<g>|gg ^o&]mu' Y-wFdc] nB iؼjxE7k?=LKL4h8`.Qwav8QOީ؜1l)AySQC`8~x?|Z2ИǶ?pj}9 Wv9ii](Huf) [- o} L-={.dž]2ӛ6kR$h~7N;Iɶ%(24fJK\"Ucp<0'5onENW3nqۧu3eC}2iI\jU;_P 2(`#ki}zfzZt :$Ø1Rnۿ9N"!((d:"i$>Hwi搊aT y !6 +zjJyZWU`@^. lRZa@봜ԔNG!d33>`? \eňRп^`z檏+UVi%ҼRpZ73YF_JwC3mUHp{Nj(!5*]a94ӷ&R |hH#Ja(qSI_[IT݇xěZHP@؍j-@~@'4e\HFZW&e~3βDtaWcܒ1AC^A˜'Zvx' 5>ɲK;q@0J(w>&@[|SF쒚rrŃͿG[6jJQwahC?'C|Iت%RM'>)Q2C!X  ?%8ŠdžJ0 VR!TnxÈTuH,/MJSd"33:r3YH(ϴcŷv%n L6Ʀu7b"̍s b\elQvE}=I^8%!0Y.M~S3ⵜJe{reGNy%ʬЯXqM=|y/GB~i"y$W)y'EioJo/$f/PI%-*u7-? ty٫;M@u%$V| ^5pnCeUiR]7[[Ԣ+F+Ke˫_r; )oR{3) ``<QV`MhyGUAb-)mF(c `< w*붾10f%8E9$ fG6NUPSS9ZvPjFg4ȇo:%vXz룇^\ow/HfzE.0~=%9!Đ|lvF)Z\^X }x+y$姒 ]epGQ nNc?Ё</8%š%/ S%P7qWLhW9Ttwb iIGdRwdWolԝү,BtN;X?S;((ڼIRY:+!lR 4Fr]X3e,P筚E۠ݔ6c,$ Liϡ0]6JV jR*A'dKaDG ҏ`ha24bT<[&XɋIyoQBQbtTxdVz/ږ(8m~>6hcXbLX]u/mB}B[  $z,c=n&K-lƮF_a݇i؉[[,z iv9ELOm$$[hGE@DsvCѣ6/?rD՚~Zh:FЖJqTaΝe1ETJ3jC߃(NW noO uvJס&'}N >. ? !yg745!5ȿ/؏qbM 'qnt<,`5WkEXl^QoMlZDOz7 ѝ+o_D'aesOhi>>dB&E7oBJR]IiV=˃8%\7{|~^"/nO?J-s+2z  XF zʸ%EauG6sd],rWǽ b,LB0H ֊RnnR}ޫ!m0ԦAzAҷ}G!X!LYVt"3 =J)[Ƹk G#@ 2NLiJ/Ei؅rfo&Rc7WRݑi>ofݙ!-N9iYk)*V$*^~Vh|*wӍx^$YǚdƊJ\kJ6}|⚻~{dW?\2mO[_X}_`Tݞ)sR$=6 ޴ Թ/ dw j WbyǡgVaϪU,q#+D5$(d:W"S}YdʃPHV%2q&ɹ]nCJvSHhh-؏trTyh&[.˻0TCg6A4yeUCh240!u`x׍7A,TF]~Ms56 2 T4]}uWQ14\l Q?2UPW^rpr D{?-ye֨%pugY6yUS=hU0.xae˩l6du/dXm#bD 3=,r^l|zENsf<)£~Y7Z5`GbqnYHq48J JXV#-EI x"66\r%*apxc@d1MUgμx{{jTj82ycr-lmfLz(;}4] !h-:-/"3w@ *t4Jk-,uqC<ʶ`, K,…{VNUO\ۘxFp74:YP^DBb9lH%,3tV$SSwN1֨m6iz>0#yt煲oJ>\|7gI%4-%T?Degm;zļ#c,joπ'7y,ޓVHo_'OU&;4w)_d2&q ȵg4ˡf׭s= +w9!奡=>~/p!AubƂ. :[71)(7Y]yj"r8ҩѬ{8t6B)yn>ZZy (J#0ʗՕqTT@ZK\'8Kd ăU_!w>Wڔ`Kjpy9=RTPyts,s>c|lhH`KBحVi5\_eQυ[6AfM- 0tP(|)B˷̊"M@$zwʐ769-`ЈPg{'x(4{+  Mri)Aފ{r/6~L$L79[4bSt$ 3ZqYݸ4ykq *ZJt+Oi EfYmJaBr|}@'#Q;{zSfE})Gf' =:)Y`A(%R6nGͱlM^^-_8u#ɿmnOKx>wv  Ж !Fd)vzRSoR!W@~H9tF/x}3JEѡE Dx|?.ZAd !UQZIFqFvD~?'N AQ\%}}$iy(QȞqۈ}aURQ~E@aCKzp4y #}E|Ab^odfcNLzfr؀ӥl. 'c!nvDExFxR$xFbNnFnDR2;/^z=VW[xN&iFWuEWWvp1bkd}99Wg}rJ!yG[5(i`HKl|FU_Cy f-P~G 5+O]'Y{).̊ Pyi 1 Q{#X`{+Mzq7wc##A/ܪq+=EIvHkmr ֻ^xg|u{rn10`,aQ&/d{_|}<0gL oK"@'~fF*\ oiS jzBV*4bU#} %`7ЊsF7A`8b-zٝRĭb#iGHCya Px%?KL1?@]6vڇf Qy^- >p'\[6. m$R8yM|&P.OB?`fmbi:t2fm`DP8WrVO [+tyOiwN*li1``b000It VWK~R@cӈ{N|]P(x3"9Fa!%4:D8mj?>Mhߓ>>?IprKYg06q{nd(&<[JT_qm;rnscd+`2SQ-ܮy%}! e}Oq/?DP"gc\Mf>ng[Ë09p^~gSVrvüαw}Q uny}Xֈwza2i8T[ YO RXbYZNdMifQv `|fVBLFr],1X2 ?zV0RkOurWtHb<QH>3_B?B~9mwF^A^3#bFQeڴWyzį.,W[=hAz.VآvW*csiI dլH|.."%&LJiem[pIfh69|4[ Es#B|uO_/sFG!lw CLQ̓KivCbzoQ<t{p{?D"s<hO<e6Qz$t0IimOWWIevq@V vOV$=^4`E6~tvlsK n7ZX;wV:jFYU ^w _qgOTWaOЦkz.asanu@g|=Y|5.'^cOqx0 l0P>(D[2<jeGڒG|3Q~)lSjzdx! VYZpyzDllv<P?MmPvo_!JȁNQQx?2w 68@ #@%{/2,+[ItD`oK!htWL#\KtkQH-@W‡]oO&K O sGvd9'v~&,Pbn^V%x\T3usşxN~?O5B  7bIP}irV a+>ay{-4Zmkiv>ftSowhF\I9Im0keuu/,1H=Q}6 JH=:1pUWDԑ$?t~M]YpxKR[^EtL425{A?6\yqA{!!aYgN)#t`bJ.|trwqfIwP&'3 bO='{hpQ.a0?1n{?=BLkX7Y92{ZM.RGsW۰TL)rRb8y`DRE7 rbFnEm 3drv$TvVxj<HMw0e_iZuj3zr#}oi0KP&S:x.cK,g<'Ps4Za2%@ro*]}?&yJ<t{&P N+m`v<^M߽¥Q<.pLv,vQER]G>>%=K{6(9$ACY{0eHdZb{*yF E *#~|@skmsj'$Z?|bAwN'/.i|n_o`qJrzm@3x=/ՑeuM8&XTZ!2\u'(uMd|vl3W]xhM|a-ATVQUm`/ (Wk`=gGfИPT2z lyfq6@b9>EI`I,G_\e5dQ RbLD`-9FPo~c x`vC0p+هR0QnҗY>zYBd]eG&o9 jX'XR< aJb Z܍s[, m8vC|ȍ!JT;ysp[Ol "b}Y| 99K* -uxDwbpack-a81e489679b7d3418f9ab594bda8ceb37dd4c695.pack000066400000000000000000013620511216214232500377150ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/push_src/.gitted/modules/submodule/objects/packPACK\3xRn0<_hPDFP{i" K@Ru5RPcȻ2x D쇎.O!tTAGrKdBVEqw֩ny@/\4&|7w oLўw|'xN0EuZ&v!1i&ve;@lf1wι@(ZCB3[BV5Bi-D#Bf\NQMGo%s9oޮAq~8=A{u\#|)TbEo(;wB@d)Ca'%qr"Z3905^e\FmkC֜ěcScmY} bxVr6<_v+W/;J{!9d]@r(!&-+_(]_(FO̐lyvvmEZQ})+Z/r6i+-i/VUYl5bͳ<-z]U})9-7X*8wi?{sˡyfV)[fYFyO?Ynײk[cpAytIR54}:tD8owrBjj= K%+SS 94Z=?+y8)T;"8i P8@^ (ȵ2umNJD!څJ;(U&DN,K*4B)>}2a"@uU:8, *I,jׅ<앾 甿%Yԥ8Y7E`][rr|}awM4iB( VB$ VY;9J`p+ ]AG`>|Eޟ0@])X.бHXc34"?C)cA!xmW)K&U-ZӒPliܮ4MSӤ6ɀcgy d;$W\Ⱥ/\AðxR(neT@U˃c[ӟ_N .0< :1=w-$w}[ǡH?MF3=O֨P\9NW;1p*s8:.XcT8PⲧR-} " P<3Dʙ#x<if)~i)py"70!;(,qٌdK̋/>̰\l `\ZFNw?Dܶ??{+-xN0 y X`N;aWpbuN&Uꂆ'EղV‘ḪDMUlQխ41Ql[lpW VV(l++TiS٢j^؝knn0alvRU)\R3} UJi7T ¼LS 6k3`@0|'`>YÀ OO !_Fǀszv9?NXsk37=BM1^3}OTݔJmP/18x1O0w:@#q!CX+cĮ+bNO}%D3-m_׺7W#)P`,βN֩vC+rN1})&xfDIyzj J5 YqOJ({3eWaWфτ!/7l|xVm,3Y8q-d x^C̥SU cӥ3\d,Zob͏6:u7#x DZ0 Ђ&`Yl C!_e.DZ3Lu^e?` k QE"y#I4s3щp +JVY$Ya3j^C!ҝ/xR;o0_qZ$E%0!C.(IHE A{"t@=(;T]W}ӎn;p7 u3(n ۱Уp۱FƗ4?̲<$wq4ҟд|ۺfMJҮ_RY)CMiF8~{x$tx1.1BL>"|)4m,4.XU$X5t*^DI"Bԋ'qŵVk}E9D^[ƪ9FX xyuҟY/I@d4L3 ˳U׶69hc6g&8#mMEhy'i1g 4t]͞t~~Or!+d 8<ޮ7NSжE-2Lk~w,xn )C5fI}ZU0^ӵt߾JV/ 7f)p!VFKijnFʼnM%=-> }M{\U5 uMIt-9>Od9yD;_My ʺ,Y6%ڶM% e_b| 2RپBgoE ́."Xwlpg̥MW4p݈FgV'Ԛb̚RfmJwk^1٨N1.a W/Yv`q,y{60Ȉ!_I?dY(^m@zQSr{u|EJjW9.opH8j#O1`~0#pcp) 쯘IaXݿ&e?.&ضNJ $>of}L_wޘc>Lgx=O0 o NI 1!10!;Z&$G lzvD%aO֡SUZj[dWiu8b${W;RɮL)*mH72!<_d3CFaF}A+;Y5J-ت3Lu%|SJ)(2)e?z K|[:㉒/? lB!r:l)/! DKpVa&Ė 4_A>,pHqZb9\F`~dO7X|;3!{!xdwY#;'=xUn0O}n*aR+*ؓQbGے>U<<^l~7^`7v xEHQ՘D)Ou+5b[o̞Piqak6'zkPtLXP*K{GǸNyɬguh7-fŲO>Odq9]/.kqqM:)#hq_S~eG b|T|\6( xMK1EͯxKE*dt!ےil')L[EtQWsrB) u6ҙZqFJQ 27Ȥd VY+[wW E[ kiT!29Q ޽B\^ͽ#TLer\ qAZ'}@ dVim1ep>B=XJrBCsB&|^ onr6GW@?gWh@&̺\_,L%/+9KD|NsS}_%txƱ 0 0 vvN(I40iʆN `O;وQ 'R%⿄N0tozd2LՊ XsHDP?br圗}q!+/xn0S-) d-zjk"6H߾Kō\R]( gLdQ׺:5MYlqPUuC+,􍑺L)f -j}Qj|Vj}˲j+ [K: ׄ?- x j۵}-|.;ٔо{4gT|2>$0|Q[4=#E!~vozr 1E%L4p@s90Y7;6>}ĦGևӕmBu`2cA,0./YGc(G)?&pi'jxui;Kq,A8AX؏qkH<%qA}M]@i"&*($k:y)q…JCvk J9ZtЙ;e4s=9l.5]Ìy[iga']\+ Jp#uCcv'6׺HqrIX3:qnxaVOC2oj#By Oʹ9>δd9 ߷&~Txαj0^_} K+K!NHW>qg}H?:UJGޑ4gaUK]+[^:eɰ?M&Z᳠yO,CŤ(1 &3 R) $b$ˆ 1_#Vޑ. kyD4 g|zqvj->E,\s'x߾I5.4l=='QC8.ғk5ѳޝ88!urWImq "cKjI6@[ F,cj!\umƢ2|vz4XC<8僆X9uQ[*[0N|r1=_4/S*66 $Kj!oYw'$ʲ=_5n )!ex vtc:ڦMjKY UR*5/=84)*dR!{(!ES c1PX!VwJ@ ?3{₝S>.P ahW=aw]d@VG0cF ] 9MpF簯U~e.ۿZbz+$xQMo0 W[ԉTEwڰkAɔΑ Y?:A{QRzݡ譋k;j!6x-fBI7mMЇغCﱋުԱ]]Ww+ axLy8!OOOP7GXUF'qQy1 CsӇ 'ɰ9,`lŘu#na2p~8z0I|Y>蝵){-$no̷ u'X$2Ҫ os0|sY 74*qy{)+eXyC~cÿ~8'xN0 ),Ciτ<'$M-&S 'k4ɲs'5R뢒lTYTKEXjT:d Tb=YUXJt՚:Ӳ)MfeZUE)pMř==;c }|Xw=dyY(U2Ri_huoT<-2_06nF͍c!Oglڷc0b@xobF11+q6W2]NՅ5,Isunv:|LÉ/}&Aw0&[<9;$+\%rwj13% cO?єlh~8C|v@"ZhvK|cuK"xQKO0W̭j$A*BB >ǻ&qLXz3xպKk MEZm]kQ 3 Y®qNW:ijCU+]*.exn=`׌c/¥TJJQ^Lߢ\֕ Uw0Аz qa^" !gld)-g?,q ai/O#y21cb*۔ !FOLoq^YSJ=aޥDqk=`ZB:_b>^)s:)5ʈa[(:Oq[blR{jj xN!yy۰c[3RhlП L3|LDJJzݪk+=z/^;W\i΅l+봑Zu"qCH=vЊNv^*1˘'a8OS_y PZ^( 8gU݅R(2cgkWFJ5&>DǐCHي40\ SS!ϛݪ3LjKcpXn׌Ǵ-\Kܦy{E~aΏ-xOJ0+>Cē7/*^en`J}ڿw 03F\34 j] ߅m1:qУlGhccBC7j3N+yZ7xI7NpØ׷n\0ͧ~]nAַ^nZ $fUݧO-k, o+ s=0 Fy"mk= ^y/%۷@mv,};Bx@BTcY׹Vod0xQ~<En'aٻBb}jVvM-]˒)?6%_^H!&Ak@8]m\N2C ɫsYJֻh#ҫi:'p8S\P,~]]Ho耼2u].q?ExsidGʁ#t >L>l CLC00O 7:Yt*L%{ar# p2,t\(}~>N4,eđmw;u>ߤc/5q绿}&xJ0WnIOi^)ޅl3 IME|wӮ̉oLGMT Bw)+ Ni+Teʣ !Og²E]rF0:MQDMq<BZJJ1e#&hGk8rD \aB-23VڶryJT(8+CnZ#xn <]&J{쪪H)?ju:#`N>'u88߹#R!ʦEv3X5-mӶmUJvl|[v*ɵ7FBZUTJu>!nGK\vߎ( m/t((u˺m Ιۭ˙> 骦 ¾8y$\3}}gHW1S"ଝJ`qtѳ}t&>-۠⳧WG0<=bl>xarw!9R< #cq$E7,EL9Nɜ8ݻYkW^<ܖx;n0 ݧ^Đl= (ҡ:'D*1K>E+̠XtX !)DdԭX85bdvcPM(4ZhfRƑι .oW8dOԇ_AV+iNH!en <$*j Ǽbuv=< 3A]1ͧĴ1mr#fx ;0 Pl#LMƮg8E8vQ[ґ!q }wo)Dr|V̢"Y}qBJqN̑:E$i󁚸s58_/Pאaw}*ԓxνN0Oqwv u+;-퉀1;:s%o=&J #7BQQbrr"JyS쥏F`G%7:v|*^/%S]jTrKw;?h,i*!ɹ>+%$MZj Up4+%|QeUt&WsTU2b'*yFJ`ʢX.t6utCc|=qw~XDcgMl:,_E(f)|L4v>PzpN%]x<=g^<{ CLZcM1}E:2FBL@mrG۷cA8p 4(VM- k ɀX;"|;-xMk0C.I(gC{-ҋ,vؒG{7-R*Bü>#M 04ȅU-[Q^}N^vm^5@-Qu5K8]N B1$(,Fx|ňrE~}RtM]vU}x9SnMJَeO7EċUՒN}0?@Ո5mxl-T Û,N2Xc ~ &L鈠4eeZ1*j_U_`mEu2 1Qi''#* yWHj/JjBLPS8nΌ gr@ wuV"\Cf_nn r4L&^.Dh\ä}' s,ֻaT)$j'$xQMO0 WfkjB Ҕn$eۿ'0>{~l"m*\$*KDUo⨸Uh<䓪PDT(9rNqb#729%Yx;'f߯$')$N9\I3E}G צ(X#3sZO#8s\pVoABM]6mZ OxN];7m~P&4J DEcgո~lu#U,>xsdAj@@` GAiOCtktkv[T1|5cɞ%5e+o_7DDxSKo0Wzi+vCaW8+ʱ'!Dm=tm tFwQr749#Cߤvq;cUdC5pbbl0 Kv|ʭ֔gΏ):E>rc|KWOGs Z[m">'Xq"xN0E-%8NQ~[Ǝ<†b99!6RRoRsNhM٨ mk(pBJ#ļsi궫Ӷ25MLR{x Z^YbLk-pQf&P&obUEEz>k 'PK;k7*!㺈 xI=ɖqLHyG5a!a,dU驆ϛLe<:C;5=ɹ0CL8Mث_ѹKӿe_Sյ#x=o0 w niQ#[ ҡ: IsBϒ!IߗwIv˗$g"hƶFa ׃wvj"CG`Z;'7i?wMn|H٥|M ukj%ڧzuM;]3iOZ,2|/%Et־.ƍژ^V8'L5N1ȹLJDy G~9ԃX]R&e>Q.!i\| O>T[N0oѳ"نn+U +F+IRV^V,T-xVdY7]HzR,wtVJ Ks{]W=87x0~Q/ݒNT Z@bT96DRIU _bOGSz\#fz(.|U^ytr)*)si&SUTv%˼.4RT!uGrO']-5-fe.2*xI"4u=sƣ [9W@} xѕj.cAoL;Z 7m;vB|r>CI6=ږxVn^G>-M9L 9xeS& vЀuq~l-fb'o5a{L{!XnS8zռ4C [6tm)|鵊KM)DxS͎0)ݐqV Z@"&;v3NKV83OJAZBڵĎij)n%+6W6 [T˶jzѶRr٬Y*QzR)8PnD?z@F8s`H C&7*|ᓋ{vn2RH^%CcإѤG{4tSo0g˜p;n}mOwixN1{?*>P@A HY'>H((ΌjJBsf=3`tRQ% :- 5bQ)k7QS9Oj 1`mrXcq1nהQJLG_ & 6p9*cd$弫\[9O㈰~ЮpP+_+Ra y9`u43X7Vx*I-A c#ly?s+}_xϕ$xk0W#Y2Jc5s,jKA:7?[188}''"X7R4`۾];ܐ1nzgAk'LV^9= TתިvDr%S \x qx1Pn9U9cl珠֬UK%q=3%3'osnnT~s.\ ؘrb_3<B}xL3\K*Kg hSg#&#=~?|{}>=^U4 ,./pN}8GX )Zdroc~0Pq(-^N1N~"pbyIT @na_ܿ5xN0 {&i 88k2%boOa8 Ne}EY vO Coޑ Ov`0eXp@ƞGcG+:#9Rt)-.p-ذ,)6>5[FimO2*"gy{C:ȏmuSKy;x?`⏔+Tl`=qס䜲RKަzʜxνN0O5ݪBe```BbSĎѷ'&XΧszC!䤏s-wA ceØ&DhX: BkfEfs\E)\PS`19JlZ}=C뙞;]4:S.fLwL0Ftνc%6>ֵzE+~;eǑyi#+82ܠhJ蹖u %㡦tWG>(oxN0D|p'o D_"OSߓ* hg^I@Z[vPV [y@:SPZaSAjdgֺiLN2\gJñPi\{;ZBȺF/2<&orħxn9٩V?\|$K xyzi<݂0kyJ}Uv?|ODrxN0EwQ#qU:0!=9nOP`S 3'1uΣT՚FbĂSI'5}ש`Y^ `P൞s迱,5¾b4c4>O4u bKX+8&*+<5'#5+9NNil> 3&45B)1r?BnxN0Fw?Q/Y@boR bG )O9:24x~NrdQcpd{?TFXrn2q$dTQP; )*Av)=Pm ryk7w-*Q%9V kd8j9m'y)o՛</ȝOiwevc__)9fx1O!{~]޲-ɠ=Z=c.+ 6 R%+D'8tr<-{_;䤜s(GA(6wIs*S|k%ÁXVoie&-N<0W y:L9/kҶn~^B _Zp{r:+暨2R My>̾-trx?O0wJZ9v;Be jS.oׁN+zh{>dIq9D4a & m*- I\thAv@r =b*vC<~ښ8B#T%k.8gu;R(]0}&`K^uB}؃% %.q78XW!HBJ0؅^-Z}dʑ`Ts& JbZG.-cO~ d7ѹ~}ax=O0D{EQ@GD٬s%v8{i<ͫK`=g inѱ Y ƴ,V,*X?zizPӎ$Izalwz"}a/XjsŔoeZ0 ZtKJJqK <0nT"m[NpF4sF[gs|j^H8Ö4VwALGBL29qJP@GD/Vrvy{.@Ejl+D`0Ĉ@ё=:z˭\GxdG,47pK/5IuFp+|QN]cxj\-%4'LupazDױ:֨< O%Z m>u/O+c?{N4Y< 4Q3uO\pukgV9ƕ?+}sxN0E{Ŕ Qlg@+QR!1vclOT3έV+FeNi$i [FD/.&S@%bc(YGRcz39cܦ\쫉t=̋ ƥQ="ܵmŚ.V}&S9WJ7tHl }yOGg]5,%o 5%T1~ n8"SMF0Gļ}f (xvӞxMK1sSQt A-[I2mp7)IZx03)Y麣j\VTeFp*Fr :J4]-&bjDդƶUSZwM[W(ܦh;v#CpOY?J;ڏ0)E=]UpKY6% 0wHF VKMSDM)#dw`@;mf\_0X\]/Vwr3>Z!yHyI 3D8m XAVOD4Eihxez-]O=&{nr;So̩z=@Zxj0EY&[!deP1rDmJKNU=Ü)j*,}Ǥ8mTu\`mȬ3sתF7SRN:*rƠ7#R)[7YPtL00V6MP)xi]5B)]FSvYRcyL4cqz{I #PmENݢ5S͈_„y CDKu_N n(xQN0+jfs*"q52N&vdT{$nf&8DB4ꌖ-BE(/xKKʌ94J*VVu5jrVgr^"#왹aRaX紬:opYF":HÓ{k`pk*課UN?td'%;Zf$<6#}Fդ]`>ס`݌uts,N='?+6*N1 Eo8Sh~!.|`|E L[K6Mhd.h•s{:}Ǚ8$ב I {ѽAJuDfx1O0wQ#۱UƄ~\R]ٮO`:c=JZRd'5Ş;OV^bX-Zo!&Vz}vRڸ0 s{\+tPZ@ig:m bVpcf,pʁJIȇtM;gMv?x<~J!ΰ-9BII!^yܥi e'p|nU&x?s0 w~ lrq%$Kv^DԑT\P;C2@ID `T(VZ-xo;{.ag{fL +Dc^4mNZ[eL1ZvM.e ~9~`* <t~+5H߷ptMjJO$ ߒ9HqLgRN]}o4ꉠD($zsU߲p9/lj(aqaY!wnYÖuft"|n5o.A8:!#TzX7lߐ Ty8.ٟG4dg2DuB h6KZtYv͡x 3K]Fkog_я;f̩xN0D{-Ah#ۉ{BھI,6vx{̣v4gLnTo앲ޘN9B(X9J+)8M+lo{J]=*u{2 /}bKC^/ipn\ZnATZip9J 3w9mKHǴf/NUpyXCpU{ q x&Wxn80H~qg%>l]qRx=O1D{QN_%% 9; =vfp'wbĤ4uQ.&hBT賕↝*Ct҄@*{夑|"eu18%}aعtY\GPgZJka;ဧ^nvYaie_`mW$KTʇ,ߵOQgx=O0EwFP;Ƅb?']َON ^sN+D`s-^)4^ֺz'38b@^GD̠xPhuVbd9x {"sy0Bm[ a]9锯ͩ^%cgCͥB۷%V;߷θN6Sͩ4A LT%/7l#s]a7~]ˁ}x^zxϻN0O1=(=vVhDBBۓ"#[,O^S23uWL'i:nڡm;ˍiRXj%Kd!Sʔ2we/K}>Nq0W.-OдF7Pu-.J 39mKćb͡[{cpG2Z\לVB %>V 氕J0F4 ;{~ {-xAo0mnV*CC^=,n^î;C@üy#]sRż퐌:ӅirE13J7jET*WmޖJT뻖2y~9Ⱦcd>N` cSժ<69|ȏyIurHKt&!CUWWje)o2o~0v8ΆH q^D 3\ׇ&$q#tI0e2%' ܼI{i&@*[\Z|/Q~>1[aXvik ! xAO!9j K5FCaK܅ iVͼLq#m26]SVajVfZIEhcN)JЂچ+u׭mZ5]bvʇyӏ K{kʪ e.gMD9:RV _&y_$_ m1xRMo!+F䣍~'QGꡇJR0,_:n&)B001 Vebm6< :QvMdNj("#sh9fYyE+*eYRYgA1J$l &0cz`J/n!MI;,#vP!/Nqסּwvn*Zxd)dz693$lFk38i T‚2@=ONe+{| F4INPL'Qe"Y%`{YCydeA 3Y JjQPǥJ2YGohY{ q])(kT( JgUU ʐ8‹{B\yuFTÊx IZeuYEqQ8la[*rhB1oyrEI+w Crut" y*9"dr#&)6sdt7_HN`|Ўن0r]2sر-"D^Bnw\o Vέ~( ̷&d+a+k>lx~^)/屁7uexN1E{(+ۻ~EQR@GD? ֎l(=+31Ft^ю'1D-O֛x X9w簟'2ZRv4p$9Τ \*<=` syYOrNR.wpTZ+ȧr5C/LmW jthF3D hm;ƾ'")v¦7p$ {T,'eUÔ[s{t<0q3N*"Z9]0?}H.ҋ6l?JH 49Ҧ@m)yD wU'K33Ɲ&,m׎.%$#UR$I^{Fu/ V;N821Ω;Tzs|~*`6x)Ug7YTWm_K~2xJ1}%L2i .Ap' $C&UVqB*@TGd E#Z=(kČrG6(+)`Fѣs; )|eOX[M\~tZ2݁C(7RK)Z +5e)6H2Bߝ`C2Rv #!pld!^>S\xM|mÓxKj0D:E!1KF}*^}8x˦ךz츣N&q(0 dj=N{+ޑխwFbOd[ t *VucHy[ט 3}ɤ2aaz\cBLW`:EOv?lxAN0}N1JF6P`N0.RoO`O6҆X'&3v ˬaV, D"YrJ삱4.] |R9I}kGeɩ_ϯΌΌJJu%&`֜`rȫsJ[kTC!\6_+g8"xCόܽ{TN ]B_I;l[UpPx.c<oex1n0 Ew["([2RE:C4E%Bb) } "& [oN!L=;FԄlF8<+I pqXA ~{. 4 )_9I}yn9sw;Q;7FyIP֜`OrWUyra~ʩxvenU &K6+۫W0 S "0TWLJeR+k,\xdhuH]0U)Lܹ5]t҈1JsjmS= 9}Ntʖwr הQJlP+wDtBR;B^}x9^1 !89z@vejLeґ8S3 SٟcO]6Bva- 3|E՜xN0EQ7Ѥvb'N[1NMJ=)eHsLt]qP'T 5jjW8AjsJjxC%\ *]e&jJ8Gup{z[cM̧#.JYT{(%&O W5Wu@;_Z0TZOa:ys`nKs}"fu))ܬ$47wb(0xNvQü@Ok9! h\O|PӡL%x=O0w Fq @]eGZmmd;H{0Nǣ퉨yosQժFT7d#PռۢżD5]mB 1n5~qLLl/DQ(\<ϙtRUS;fOp7zIYǥyTo֫c/[S1@NEH ҽ!@LGe06q_3xJhHc-U$&1b.e &)DOonj,z\5o3xR;0+F[݉Mg;!@B; DWǎlg./@5IZcBִU%y/Z*ۆi]w=c-y>ԂVMk!贺t-X;ѻ {—lB>%~Rh|)C"sC۾EE0M6g$gmww%!M}:jXScShp6eVyȟHȻ>JpV)d8aǰĭ}7l)AQ[D":cw"|. #֡;cÀsȥf*a;9wsKW`r]d~ſ=Qhguj6;w:3?ncJXf&^."iVyCcZq 1L,c)6ά.MC *V0AqWdg;vqX-Kb jq'C- P\OOڥ-- ?ƻ]Qsَ_OWYww{hqFG{{U{i#>JBN7^ /a9xM0=b%٤IVV|+7V3iT>'8D(Py4]*2+eU"ydvܡ ꢪ¢ODi/E\Ue)$Cc|#|=vǯGI쬉H"MӲx'q̄:IVfyMקAM@(G ܀667"hk@FO=s@.T;IUۅoxB tn[L=K)"I6'upVȓE 4%t04Z4 ,ƳQ@޷aM]:# *8ng]82^[ l?׽n)tE}ݞx悸l鐽[n6= !$6~ 8FhWٜu\8Ky ak 1mڟMɴRH+0bcSk^oa@۵#9 wkK4'1(VE=_5z0xA0sbIWp c{Xmv_ϤJa7yߛ73.Su9+YF;akN`gՄBQםڶBZs(b=){KcYl \gЈJcߩƑPW8!&x 6f9x@.#ɺ޵[ k>U&/Xt`$3^>Z:o |6gʌ'ps0ǰQa+ G.Ngĸ'\v,oulVD9 f vq|'EeqagŇF_M2@އ?xr$u.xf~GZΫVFky`VVjX픪qݨ=q#m1S9GF\sCxzOZWMJse)zyZƎ`h~9א:4r>'02`3:ZV􅎬cDkK4ZLX]҃B'OWE

s :u0%t4bn^&%2y/YSǰ&p#~2p+8 a4mt8 B pYc?7 kxBĊFgH0aM0wkMBt8_}M}Pp68$<]=9xKn!# DQ/|A o9Aٙ!,c z!AaRlt@;k: >⪝ie&%,04'<'D8op9 h>}VEp(ɐ$[IWkì€Csޫlon%x{Bϯڊi5q94;");{ۖ|Hqѻ}'Y<^b%Ǯ}F|9<%_DXAUh+.{'wjtT2xЧ<85g2ӓ84R{[-~TҠ6xPn0 241lٲ( tj hR}r!H=%mT]CSuiIT^P6⌞lYkR`QcuXu(,YUS/\^Y Ѫb¸"_m'+\¸ecԺ\EvO'f1FCN3;Bo&dM汏I'[pB2BtZp!bvuz"_eW;7D >6-x>ݒqX=-w/%ԐxNAN0sGi2MBp/$SZZxb[-U6R VknN]xc9FQ#'sBm%eg]RS]ᕗRl>RKj HdwJuY#ǀwD= \lu6i8~%ĺA:I:t\DoRo{.^E}#o4xKN0D>ED!زk ')Z<:@KE{&"z1xjY  #&d>ftBwNh[63Ԫ,p7O.Jim{9~VJ^W_zJl)G&*hs)R/\%ZJ?'nxOJ1+.;=ED {qAϝtI,2~Vԣ0V2c 4hii肕C kuqKHa˨|b0+k;^pZpZxꈧZT(W5 "iʭ?Czo=< l \ [|m#mc>"1]]\_"Fnђx;n0D{bH &9?K$|L3b^_HQ0%$5t:8+R44Yc 1191YY 3oʍ6x\Oᐨr" PcPJA#"ZzBv"r^Rm_^;Zܷ^ xAi_G!>ʩQ:p·p;F|qux;N1ss#ۃڈNO{۫Gbn/)URonDWi.JiĤyΫF >7jPSJe:NNZ>I>/so4aĒľGҚuUZ)_cZFP9Dg~#| T< ; ^˥Q:OYdxj1Fy/q̌( hI$C+ vfкDkV٠m'RX85|ЃF$#ywFaPZҮNWؕ;ꈧ:7TV^R59sMsf4"pJ$$n,Z8獕Zhb'6*HER/)xyDK"#CmkWoR uxhļReu>A:iji 'DsBsBక ̴cpVR9uq靮!coThjξ6jؐx1N1E{b& zm%3NVam䝈 <}i̐GMt.ǝܘCO6hTظhΑ,by7V{i 6R1;m=*<ɡ6xy < ܵo{ϵlRݜ`sFM:ϓ3 8ani "j eeT \u|JL՜_'.pxn D|*`0z=%A!$_+siv"GhPON 7I 8hF8bg, 8`PsՠiB*4^õs\*='RwӒSrV O|syYbkObB? -^`W!oXc>lbi,)CKlG 2yr|{{pxAN0 E95[4U&iF puf* JR =__Oϭ0qJ. DAzc)&zgؑ©ڠ';AMCj*=5]r7\*nW8n%r~pr<1C8.M z\{iuDq rpcOF J;uŚ?χ2O_dgdCJn4H+նm,)yJV^_xG@$kyWOO3FB}fZVe{lX xAO0  [iBpH'7qڈ6 ؿ'$Kd{Ijݔ\ir UD;ٸVnT[1c-mm+v#5vbV5V) pρ8įCa8ހTJ7|i)?!u) ݇JZ@>#9! G2"ȧ䳙σ_r۞L^peFC08f5=Ƒp—7=f?5./a/rr 0G~VB>`q;γf nVds. !|^syOxAN0~QqB9x^%^KP76&b2/E8v>"'uMj^@3 &kdP@ϼ|S$kclfoQk])H4ͿY'xC(rh9ҡQꥼUIÍ 8Q}L fxNN0ۣȁ  ꍽE`;r=f3iUg{t=`&O2 Mj*b3i}d2Fo/SΥ3/XlpS.H*otOp%5gE%>u-A<Ӓ^av(I-K8O'fxN0E{h#+hBC~7nld;E͙hn+ # cƣAis\!RzR|؂,(e RVs-"H%rح͹]1'p[!]IFI !>S")B_ y- r \v5"\Wl kT2DUNtuUbל[U4)8c;|"| ke;L]&}6]>CqmڶyBq4)TeTu _D1d3io 'n/x!m,w`)A0AC7"$;۴⃕k,Yt2C`m"ЯRW=ɭ+ l'i J1$@aqOȣ t!eBng5;VgGwLͺv{޽f15,_v=hom6 59 3ey~E Q&9- /̆xms~M1zYH׃,(^L͐5f8d2[N~ޑ:x㿿.bkxMN0>Q"fBXqĕ"r{"z{7fI9!j(G*#+5^;D.y 1;IdfgvB ({mJˍ6x+ؾ'Ԙxx??nFxJJ범g-:=JDC 1|7349A.V$[9A3k^4x0~eWMપ[c  dKIӕzi/?S@U*u2֨JJ-Jܨ) RJkĤyu},TܞZ5Xy<5ieV =|c |#>t{H>k)/A+YU}:û\hi]J,eQ!1irCaR0W᪇.8ozF}AVa{x]!Eql{l/~6߃@at!|Sf1J>'L1.9l^7k? aMhMʅ[Ҙz+=~pjFA#1S2CZG0$lVO//lm:&;lhK纽왗M#a[xxal/'Cۆx EqGs k( &xn FAZ-!{eL#RJ]kZɥMLpN03 "|.ϥ, 2(SoM4u-+]!l}% ҁ Fe${^ D]pE3H*Λ=CP CxQ4zI Bo=؃T,K|ryI{Gc{c n4pJzp3z< P9̚/1)2dRSL~&\ۓPN~y~”*)ɒۋ(7£a0#`;VAY_[(Fwڦ*=e҇)CX tu&]Jw-|$~4Kjމjܜx1k0wٖe,i KO[ LI}UP:n}vm6Q12* Ut Z1,?57Jv+a"K:d=j_oq7N(+֔eyeLgxt:bwl">TLEixz  otFu!!jH4V r*M(ij_&5Xuڵ0Pޘb{߾V _ܔ*xQKo0Wve'NAU "hb7.^;NKL[ q`F'qg)E8fh^vVY93 jl+kZ;ݵփN)ç%2~搾cJxB&n@5S6RK)zRh3a}6ݶFix'Ɖ;k!Lu,g3 D|[*ZjXy-Ѭ-遇Lr3Y\N|V/⅄G61!D`2EƥK.+'8#y>R)ģxn}ʺuRYOpHvیOoq g;x_k0).}JXo2єu U-jKFe~Wq `˺=q.U-|]īU"P 1+xʲIRsfJUeʳN0JcVȓ Qs^׌CcyX.iu5ݒHbgM$l4|$͋8㤀qLخÀ6F:N סּKW/"o^Dz[Y~qw\r<[G?!4& ؃d^ (`}ooZ ZI7vTѶ`e(㔛ó<Ns=hPPK`$6F=satB`OF%Mζqsw{ycEiW-9x<;@}eh: :nz@П۞,0`vdجh(4oY@x'_?O댂|aZNjA/V@>Ηxj0Ew}M'ɲJBR@wYzJDcH2%_:]p8f"O}S3J+rbS#C"Kj7p뇻1U%t<[{fjyכ!xPKk1W 8f^PRB-f#[tY4Wvsʡc`{k=R7Vu_uUUg;4Tqc׷u?}aW:K8\NpMG^_9mlw[UL9GJmea[Ve {R >GgD8-/]!38/ ґ`ptK'`{9\dDpv7rD^)d]"džpx(.[=l̰YC \Hja7s&̋|!:?8v{qs~ť#~.}[(xر} W#4xA0scWmB6YVH{=i:v{&m"hOyo7艠h5MSTj2jrU` ]u+ňlYhVʪ+PUWnUb<|!:Kr=Tl*]:>B^e!o ,<˄tàc$ I诪'뛺E6%M[ e]ZtГDM'+r);,xBEWHX(p{ǀuLl~!B䢕\pΔG#yF,#]}rmUW2q2q,4Wڼ\i 2 Fm C٪h XHFZMj8qnGJ__*[%<)/0!)HpwC#HLfH譱޻6`ŒOq,Uw8?fƢx=N1ާeY럍" $8xg#D D4zIf9< #̽W7AOi$vd S'|PGHH!sTsN\aSn+dGM;@aZzkᮗ}/,sk\1QaT֜`'UvuV]:װwƵA#6&hXv* ?nm!BͻĴ1e_'jzxJ1^)f[J"*i2iCw%"}{*^Ws`R"%\]V DK",kɕlBG& UMAPRQbySS-,ZIpG Ggx<ݵ~JIM&nR-o.YƄG9t[k7MG.{)= z)AI G7h1Ao̮}p,#}Ne~&G_٘C4$z-tIb@A .6tbN ɥUj?_cNxJ1}"KE:"uBz$9iM2$)һwYW ODy#wmL 蒣#68әgق8͔{{z88gS6-|D&29TU>hchX'.\^4 ?G89xN1E{hW7RQЀ1`v{@EibδBe3*Zx1e&c##+n>j6QʎL';c..UؖkGZrC0HeJ":"e[L+t]vrH  /n %>v\ȹ4 b;]M{b,xn <(V-OJTjm\}DY |stlJڞ7EU!WR np%h@mVM'JJ:\)pME)TŻRr@%ꮯ%{`/M<9Y/  HcRN(x,q.xa쮼w7H$ bBgp31 H#& 6`_?uh9 p|ܲmzVm$w! v|@u60h)Lv> ϐ7@Z@^pbya =Slh>Ywv%c_ XhOl|hOLᇡP”xN1{?Ŗ E(4 :wQtPQe)f͕lL InhqqzMߣgڴl\ږPЏAz] LʡxO ^2Okj<* J.(HPI)3W8ᣁOJ 鲆7j=h 9,[xR3}_=CX =Դf!oJw>O{xn0DW cC"^Z5_`k*E}ISO=aF/'fyPݯ!CGNHؒA\M;kѴtFk,fhԦ!t0kbo3/fx>=U%CicRlwxs|&Y~>eLsmZC!q7:;t{9 aw@!.~ LEt/_?T|'x=o0 w /tl1%LĒ Y}tεC!Z(>c ݍ5aHjFu*F4$̀(V "H뾕C?r۾Qm#n)>Ow}سPwezu^sPZ'DN{mjѮlJM\m7qrzLfSjzmKWo6Ơ#~k\Ec> xi4gO,u #Um|в]r/G<1 N,,b:\eUJF)p]þ'ba&- ]tԞA]< Y*8A>~}|w*mvzJ>Z>9Ci52|z% ܏yW(]@P;t.1+=b6bjoNL 36(d~JgА DhJcAs0Bp`rw|q"xKn EmltI'y$׍:({t{tkFa ThZ=C}ߓd\+ :F)1Ϩc ?x\@̭N)m ^m1] ot^L[#t3hk d>VxkMvm@r@=X*nBw[R9%d}BhK~Yzx=n0{b.16`{I4 36m%w*Vf{9"ӖITX'&s{zFљN]G2Ȗz#W1hʱ\.ێDy ގey ?§^|.祶a}¡1hK)):Im^hi߬CF)QȫDG)Ä^p+d./;Qy.x͉a7tU2ߧ{m%xOn0  +ܥEDBkɐnNrr320j^[BV]-(O@|-9a|ӆC2;y{. &0VoҎ~Kd7COzp )#Vw %&7:a&JM9 x$g~Y)3!s*`=| 90Z;B.1 ?x'Ҵ' oR||IfB z\4yގMMwxCg]-xMk1slJB14arhWxWZ$mM}봐=ϼJ#Bٮo U^`^+!5EyUy%WZש`h#:6,\LVj-ʵN3va&@6\І#NDϻ[GuU[{ yv?5Vr?5uXe$I;yGpՕxH z}'F"tQĎ3=}/f)n?# g1;In@Г1xNqg,9u9R1alOFZ:ſ 7鮯k5u jx ƻ 0P%%,q,rw%%C8g(2D-^ ]O!3DƗjPVt,Ų$Ԑα}Lj;7Ch.94XyMP0]!M* lI_fiYpz5Wl'QRm͸ upC“(xQn0 )^a!ٕcESa=$:fK$7OQ3 ةP̑D\{iiz%G#صh̰$Jp"b$Ap/u:iVuir(\0ܲ ~ _fOoA4#abxyLeq9S'N5CZ0яC!`7 b=ܤ >d02F/J_vz+;Ȗ`hxuϷaڼ.x*"/ѕs?29.  b5RJv5py3T變6,yN"^7-[,~Z|bm|aA :R.m{qGOfiΟ:SAxPN0+R[IBNA*jmCG߳M8=Ǧ@U)k6屮PdkyHS53(2EJJI&/uAhju-DK}S_0h8oǟy{c^dm#6}d~]Jod @ myU.%?C5LfW@$NJN[P ?Hs)1qf8 e2Xi5fZ0S,#bʐ /N[piM8 0DC+\I~pE롅# aƹ`1e4#%dq~+Up`S$טzL579y~lr9H€^:U]ad܃֢0eYl&oXAɪlz3A.rc{đg?oʞe [VSXءwna2KrsRD XJo4*Vrt*!N@70xqGC\y+J˗dxTM6 WP @{h;%H%赲dHnK{ɭ=Z"CP)A/Θ墫º8ҾlJEyZ@jC yzԷkýt[mKQ:C`B:{2|u>9%5 jt/hPU!G!Wlj:z$n$5Ol-]m5:?$h067asN*Ta&Sj3X%&](ٺ9 `l]譓 zpZ0V $M +hqdWH'Q0bHo @e^0м/K/N됡o'IQ6momL+xæY?lۂF-AfYdIFڑI} P l(8s,p\'/2rEg7IUYq6ӊm?O_z>}y;[|Y+!OV"gn}]{zտ4ّ'xn0 w=Ƕ|AcJldH]$#Uk)u#{LRZjnOTiŊB9д=MݵjR LfQV<5^ !x<4>C9uKIJaRu>7k!e W&\WVteR̹Zg,-q$!~(0sG:2a,+Mg|Xw`9&W@d!DžF=[>Ú[ڑ4fo4n xV'A|9sY\'J"*vOXyc4^م)ALpŊWo;1 :W$NxMo0 dNz]{nq$jI$/Ϳ0d|H;" };IuNKYSӵoĂ\Zd}VR0Mۦk]/{5M>ӄG_0(q)7/׭'C¦*&%T,^ds#4^7B "s`(ar,%Aa0jSεBBf1 >;il0vLƻ(*(<` ^Q욻S%)ÄAg= {l~}ϴ9Fg+3GX#B,99+``gMJ&&2G֣a (ˁK%.C{>T8azx&ʬ Gy@t#J=)/2RP2F"*QW‰ $^܀&i/-0Q*,p4z1U5Y|"F%Om;Ȳ$PgYj-]1^}QpQٞ_sk!1 3^P>B<W F~4e2$\L'2'3:? yo P,xRj0}W yIBF/JKcydJ[I^Β {q8)? 6%o{RG0Eo@'ߞ/x>]cXG)DXHAۣqϐ*7 ~XWEQrJ8 I@)U9:OJ>neFg]Ly2i1Y捫s`|!O+fM);ۛ#]xc 9?`$~őxKj0EZ@>$R:괅ty d'iJG^8\5DjnqI{o'5J95,~T !:G;J͕FÈQ&FkSv|ky~o/ JH8p9 u]"{[nQny7nB-#>3B%R K[jA˷Pluہ*2ߟ&˾y)x=O0wik;q @N ^]KbHq[V,}H*^ !j/%uҊHΪ!&ԅTE6VJ3n[ktC"liΠ(ۈ9_{м9?B"5zxW!rs5e7$nJ_k;y9!ZۂB/7%sI%c7zE *~&5xOo0 N0 n=XX2ei%Cۏrma'۔{Jd-[R~l(JN6m}Ŋ\IC'iA}39HYnUV]k9"ac]um{[U}U ŦD l"lz>*2m/uo!smgk/O`#|53& (1%Xgtκ u@PǸSecn@VD*Lֻ`ٺr#4\F;ދ ݍXbLLZ0hޭރ ~昘Wzi/+,\,TDz(ts ~ NS\b7u@#0z^M2!0:mg W04:< 1r{qL7[`iOxۂ-hB :BD1+6첢z}c Flſ[ n ooICq v/qx[N0E@*;v@ @ Lj#t ވ Dry6S!*F yklT:xBmT&BMg6,ST>Jf(/? bKzmy5jtAz)E[ a-߁ze>8A,o¡2o7kVxn <+[UT^Z5Oo_+z)s~)Br/]+ϛ;K[`q#׆kT׻խ!hiDp-ř2=MqmׯhCE+b6NS(.x὆d y_c:ljWatpЌ%cA^D98CPk1S8}eW|9Ÿ~xn  &AM U~tjN-~۔BX7(Z[^)EcPBfD%mfN6I.u͕QrSNs1gs Q'4"xk t꾮kLX1@ w>Lc\ wa udoPBd _b:\{bŴ26'ٜ>{z{7$駀; 翽xPN0 )lJVIB 9FtɔL ۸ɖ??6"7ޠwnTr]YFk % I+6vgQȓhYWs/[x%,/ӭnsS;cti.'0Jij`FKv1Mx&"gorYxkӂli :G^ ITaR]E'39"QΟ~Bor{ۥ󦐍#xQN n-m1F`Mn0lIZhfw^Z7QOG D $G8եRI6[34MvxԄlQ\--ZN6n;MKhzz4o:;8J* c\v>j5RT%䜡ges`/ZyMtrlЯnUCLAav^&C]EG{,*IC?+vkEfa,YM⾶ [ti8:XH睆GiIpm3O@MCvq;ŦS@+0`S 4`͞70\8xKn W^UUUꪫVLh D@4ۗK".HjiQ(z"=[6L hnG>M!JZ-5퀽B0xi0MyLcTo1 8s6uuп}'XmE0= ^"P{"ʒYeXcy+A'\Kb {w_s04h^p+ˁ"8W)lKo@㉭8k;z,3IK 0vv@dnwj([,xn0E,,Q}Jf V FcwLZU_J {1lj"^닾ֆڮ򪱩;Z"jA9Asmmy M[ݰj-Fkˈ gBȆ!.ӏ9*ڦ,Nŭ( R6P_iƉ rSL`0R "7:{ԷEpd c!N()dq,sww/&ّ]w}sރ%!ܩ _<5$Q%1t 2RFY6 #Fd_R6U 1Wd0TL↙S;8xi0 =H뤔 Ztٖ@bۡdPN8(Rk80KqbU˾1nxv25ih5Ѳi ~;0x+7VV c e#D/gWGySy@@6n.//8#9M'6Og],`Vmn&fWΎlK}3; xJ1$RWn%?nhlҷ7ԫΜAvoТb%(k1^ eI& Z֝Z[mT (M M舜 <,eO鶼23ӎ\=D4hZ~7 fx[>VayyD )go@bft:2rY[Og$'ra{9oe(_ 0c:@QKO RTLiY%x-J2]Ag/˳n, uy[g (9xRj0)Kx7]R 䐦Ba,lueɌ8ۧHBH~gktHGU7]W1Dƨfd {)Q͑A]Sc߶v]K㈫ dE)>vwSp-G]0M6%O~#~10sAz -y˝i ,h |{ [ 2K(We^VF!T93fZѳ>&B]%YJ6MOOJJj)T?e&X&vg)bAz$/ )dY Z7UuW RJ03-٣T%e͉ܹM#fHDbXA6-8G%20X T)T#W1 aɿs WR;vSft)2&ZGLP$e+|)Xv8Yٔ00h%'sIlidjNR %a(whO:sݟ?2WW>h&xQMK0W~P܃G$6n$˲޴+ ¼ 7ޤ@Hd:㭐V\-ڪЂL;ݐ,a3r *.em8KBWe0 " >· -Li)ѿ 9@0c{N*E6I0@%5V1J7?#+^M;nV),Ăw`H`gk 1J@l /}La8Wb5E9 tWcOflOEH;wޘ<pxK0+MwI~qWXcyI^he{"aG"@ LEIe 2*2!KNń<,2%cTVd6bK5U٪\ZCCG-FCp;OG!vwJ2+&c}G9nM m3$  /n= iq%+;u_0{?5 SgL1n&p,֡s0(s~sy:OvvO7_H؜(xMk0@B)"!B S$2F-i]z-͈deYԘB7RV9e%& 0y*)"t}Ty[R~l by*EUdU3>{8E-~>tsY˼+˓BqlBCtS \08:h^FdQ/Go#=!bxj[x;>Dp1`qUhb4 tОB\2a0'9&c?HU7Y޼ymtśw$4&WÖKE90xn30,+wABo7ޘ}&ٙitTc؞Cy~zԵ$2aƬ٘{_ grB#x>Wr--=VȡJ?3ge 3ί8Ϊ(6If ydY&tFyL`xkn0 (IUUVNpT]ZKLDFZq{c4i.Q8V <[1S,`Wa7N$!m ߵe(S0LGA )@H{.OT\s\ a. e'$xx&6aM@qm=)@W=1v`")opK[h5#tnYF)cǣfl*y_oo~ϟxi0Eb2+9H l#yd ֒eBO[@rz7Ƈ(-ii`l`Xܤt mFHy%kXg |(|Km h2Pkm`@bݶܻO@C!նq, Գ*o߯+-~D?l +Yp% %l[G^3^gK_r]+ eT_0=-;X&oy}kOX@.]ne?ey֟xMN0>Q#'/PW݂83jjgBZn9UHMWFz߷xMVTdҚjˌ&oٚNm4Hh#{lJMkk*nɬljQk ¢̲\Y!Aa??y;_`x&q3' ΋j0NWh ȰƟ$WPlt ]`<|zDN GOJ } ր:JS#ȸ1\a9~kWw%#*r>,0d)Qzϴ ]i g8WxN0~DBDuPq@}{BˉS4Z (eNBF }^zme0䇠 [l.7{IR8" eSZO ^9'Z`_ph9CnGRq͵r 6lw8M^I3;dp"[WbYJɬiE]b-+̊UԫjC(^5 R5m,uY- H\rQUS91t1xq֠k7C"'qUl؂T.XM89Q)ff1oIVfct(#eѐV33/mĄ}ɴJaS;ݩFմ;YI4o S;;lu ޹9ׅsMU+Y,:.%^<<5vfw,Aĩ *$V {Z$Np(G\ʊMWf/'"0xZ9$QQMVR51Q P"]͛ZH)Qi iFp[0qHF>m8`kG0:S)AY /9gv3-#<L,v|!亂7Kwz|!qu@y*{̀Ҙ'@p{ٿrq`^}8DrUr^ʑxN0D=PulPp{FqB{BˉS23ZL$D)Ձ`Iq=w0FHLs2RRN /g9+vus9 6oiv7㵧ڥiVrps)Ʃp8k n]aum@#rPk\Nǩ}Jq&_|?ǻup+xQMo0W̱Q U=ٞWc3޵bld"}uڪ=/ODPեԶzJ,ڎ*hʶ)FdvVɲwԊZN.!&\k4mTEOC|]+ޗD.᱀QNus!m ~B|{@0D30' F/6]=j627Y=; ]6pZeN໛?RŜȾ084G*ȼE8s:4&vQ W) @$G8/1.g;naMeP?ZpdoC!ē={7Z>}4k fxP;N0}f=8!Z*{{


 T6YnV-ΰltg_ heԨ:vLNwJ]i|*"MtY#xR0D{}uTv,[0T08KXby$K*]}{W]ݏF^IP}+[]kĂh'rmSK lF2 O3VF c^.b?A4eFR _  ޏ3%a" 2(G*3p48Cb+8.@Ns B=.B%&L+b ^ʙyY&:/KBa}S9!YX zzf-~Ov˽y.g .C W`ϖ#aJd7ѹ͸q WxN0 S46K* CCbRv]U!0 Dޜ=<B:"vHTڢdB$h z}p@!E-F 1u7LndQBt0D"̯Nߵ6@4Lp0m?Kc'@f~`U+ņ"Eu֎qrRkܤ%uJ2ܥ(CEs&*^Jf%v9>}2_Uů"r cfruj .5Tj=S !9_>)/j 2K k9auZz%a_w!Tji#x ua#CwӃ8koӊ_˵#xAk1s/.ٍdEDě&Dԓs7> d[v5fJ֨d#.gV,boZ1JbGV׍k>[-xN0m+uE<_P] tJ/pa97|2F0Oǰ*`euga"m}{3 {H%Sī? i>{{rNӘ/xĿ~q 7w-2خ t@oSΎiR>A:2\ czU 8MK']71uZ0v"55eԙvNx:Aewӳ-|1|X~K*pNt~̈́aC=gCL.zt"{<]hT%xn0 E|l%Xbhv %Cbf' y"g"m:kιƐn`dƵl5oԂ"ö:56VΚ1s[S}]cʰ>x"#=Y֭5V K)~skx&̎,[]| tZ@UՉy>\a8EH0R`U} 1|È? J0#!~ )-`JOfTN3΁G(rRgp&0ᛝ( OEh*baB/jM(k%*|H{QFT֯* ê|u_c5xRK0W̭Y ~)lXtsHDĖ$7Ϳ٥ғm剞JUeخˢQE]VEePgjݮYUɺZ1'dQgQyC^Sdu)p'ag' Y"=^ yQ7Mn nL;·zI \9 ڢle2)h8(O+EDp4Q;ʟF Lw|q\?2qJD )MLBn~ptR3ŠO+ZAg,'I\ G4&=IG&o9 #ʳ6=qA<#/v/09H^L0RG%\>&cap F2^3?>>u {8\#{慂0II!pD6#E*5솗'aҚn}k`- mgrAɧķ ֙%tZ/Oѿ=} ו-xRKn0sֆD vM$' X$e׷HN7Y]>="jҴJ:isZR,\Kd]B贮Ty*յd1E֢)\`^D.q Gy{C h.!.J%|I4M4M=QzmA#F9ӆ 茠I#I^c~# no. Dp5!.+!?jw,op(5gђKD…m HVK-!BXUg_%W:G #/ NYD̚[CbO76!Jϣl;gY[Yk nGP&螸Gۓ1{u̻*&xQ yRdw]3c,muEfW3 j;[ٶlLV9=6c'hN+bP6 bkFi%Lr`m`ne J&rz>e JmQ>J%pqY|)yk'c^o>4:F6p]%N0~a2Cn;S[24=lf{Kl=ʉa`Lqe#4KVnMY_q>n>i&/v'Yݾ.(w,/~]q,TV卵] 'U+aP*Ig?cϸ_%xQj0)=46JB1$t#iYKFY;9P 4MD ;rPQZZj 5 V,gըVaG];k(46y  ~EgR Җ~@U]R]VR L=F cZn[xuNA!{&3|H3r%b&!'40\3[6 35^S8]D,1_)A?]6F)$ھ}6ȼ >G8HޠU.fLbf\DB=o޿\3;hY&mF6AX?7mEڞoxAJ1E9E$ݑAfBaNPI*'ix3^ftB\Շyj8)MlFTx>rF7L5$V* ~ҽj?Z$>8ɽAe8c zmK.pJ0U/՚yUwK9j % %x3Sq ^rIz@'"%x2CTob۳ qsb:~d9'vxN0 y ߡU,]&8'ph*@=p8XvID`)rzq1 ǎܙنBz5 [-9^( zN e % Oۜc)nBʽҦ7q9q]})2{^%886KH} 7U.~^}P͏#/m{|+8W`EG-3m %Z|us)+ Cb120 υЊ~t꜡C%{ŻK!ql??W'8nxj0DI%9z VޕmJ$#)}CSa0<^̠bM0J6hc18{Kwc߳0s0Mn$6G+Hv2( %e8Fʌ:"i¯z0RYxJJ1u3\™1O =۔'hkG"8a78;`$T#sZ| ZGo"e#SBh}d:Qtox 0P) ;sξ).oQE(``j*aVj6l JŃ 51#k:>tŲFs GF5k^C#3K·P^NW,ջ 'tx-0d~?;7wf)fzBF|0 0-1N-|Jt^ES+7̫?nQwkZR8Rt% J}fsCxc'n)xQn0+ )zK n\4{/Vb*IEp+">gggv'*YVy^ԅKjJo,٨FMZJ1'J\k*ҥjʪd!k^6*Gʬ-kc윇U0god=ңuHΫSI";Mad $rxb nZ0TuYTKRUS2>Ӂ0`{GHP55ms _e%ؔ(^ @p}xYK @PHA0ہ\$H~-24G_`=\Ce3E!ެc Dɺ Pkp63$Cmgn;RM X ~d` c&ԛ̊Ɵf .q;+{(i |a9G6rKr&Bp5c\C? *sÓ#]q,CW,+xA0 ͐8dRC)}Ql%1u`;_eвғ|x}STݡFj۽QTS[Bق| bo4j"Jj Ք]^Mk8ћ@s:FKJ%}ueQd٦DN^<|w  r{<;PP@^@s <E &Y?BDs'&B&1m`tܣ,`E!LVO9 Qxzڄ#%~0cllvv200^o"#~ Ȭ35r 8 Wll]<ʯ?E5[rH |=HTz{kza]1Ǔ;#d+dɎLÐouxAO0s(-1a4I/4n{qɃq.%ot kQQQ)y)*jS&{d}Yie\ ZiYY^2Fyg+*dJIXM%!BmD):A1,e30eQ1$h&T{~"v@p% : 8FiXqѪo7iS&,k r0ym% ,'3xV燜=SHo1φk*fxOK1s]w7+EHŃ=IL m$)ooԞg9kC﨣Eإ&YPFʆÆ7 }`#B1e":Н͞BfW#L2y*èG! ^1̰JK1 Wpx: =Lρ("^L?1ҧ uO=j!xϊ0 ~ ˴t'8&qRf d[N&`)3RHOOR`PI[ Zhb$8 zcoFk 68j{ҍM\|!dVc zBӶ;=hw#F*2=~Gp~u.ӛAgh8R;.V|%,RLr g)6Qy; 3qk^sG?~ͮxN0w?m ($NjЊKFUߞӝ>ߥ@wHhP2Z+يZRQ(0KP9)AW ّRPUVE-d# >0&XwDZ#݁.*$\s9x)Q'vA,.3p4epx3X\ow/i~ؼ.5 1{ %zpK@@0@0ZM.-lx # $lۃ>dO߷fz)x1o0w ʒ,dO kp"&H}ω@Љ޻6ں/ˮmvTKMMKUQx0e[ZJ1a$iQ]vuAC_UXԲU?tP#p6Dx:&xNaD?gpl )4 G>A #e˪K \u &BwmX,.[@V\Ps:e /)S_.iXa3ŐIePA)3WqnOns^ 37+*솣`&ੀ\k,x'oif|!a5Z9LL_چN^ٓcke7xRk0_qomiq:~Aeqζ,},)i_NJkI[MT]K]%Rدq}tD1K mSnFQnN6uV6l9>Ӂ0§`T-ҝUP7US] U]UBi2)Q݈{_V0(87woʇᝠoXV{Yfc)\S88QFv+8O c:Z #Ȝ`O\98V:_^v//Yx:/`6t4<`Zl.n&AC"-F8Gv0[m,@0^ R"Q6ɿuF+!^G|i# rqgve3&5R,GNn qȀ.p^-(1~9 S> VϚdI})PZ9Eۙ^_Ç?{h*xxN@ EDkP V hg*OZbX]ˏkp"iֵmeu55|_ ^ J̘(0JVzJVRk)uJ <O^r6H8ePZ7deQ*)L #^A&Ϸ`eLzQBvy~`01,0x<#1xc@絴2"wyc&̑r~x!D/J 11u5HbJV`UbZJ!!/0'߽!9&xQN0#☼VAAA@ &$Hv@{&Yh(V[X)Բ3ʦ6nFcĦj%󶗕X0K Bת3EJT)V51i 1z7Hw~)H jTe ٦D^Gp a7q9;a8\)Y+8 'Nd5B!}5$caX6id;- zwv';wͺa9LO>CBs lH|P8xR=o0+^2Vhٲ"(!CHƉMzvv_Zke0p)k<&Cprb:{٬X|{rLt\bJ}38P9 FJb @.q1F-c < ω ^pgo%ؖdH@iz9.A' (?z' DwJ^?01l]d@J"y,,00 hh מEJ7<D҅z>I+/={8,EdHhC|T"gZ,\(XT⤥\ 3/'W@v`>!/$<=h0KݔR\|ر~r?z|349‰ !fxj Z_Ȯs?Wo2xMk0 "e7݇(MFb迟"z$=FnytBb+Q(YJ) %L#4ѓ ZuQЪ*hQi@by8x Y!\恞@HY5U 7MC㗅^ !؅&?9wt\)Q+m78d!~?*{UXsZ Lv qY)ciL*5%' <` ,_' -cz<ӕu3f?Nޙ3vNڍ뺍<}I&xn <(u^cCObp'ڷ/n6A?G"P}'QԪSuu*Ma FH i4vI{ԈHaڞb)Dx&&N)xCzK[%Qrks<ۜ)ӄT0jlKBE@,`0oĴfҲyѐ;pY=Ã#Mrns$,-fzzGuX]bdq=gP,,25F?Upe~fE> ;5xMN0 9wMBX nLmR%)ܞV8"y%\K\ kdSZ;ʊ+E CC9RCiZ%ԨEz8xqrW ?~ч=T˶)P]Y2٦D hd'<;;$ʇ@*MW;YM@=PV?f): 499`Iq&3ۄj)t D7#BaP܂iYʳcŧF]<2vgGoa_잛xAN0~~ ؎R@nhm6Mh~B}fN3A7*9Xk\G)ktdI 8Nܳj u IZYdz:fx+aWrFz)E4J 8g;s O~ 5zq 'ԁ`).xf!vad&7ohxj0D&(V$˥^JIIRz ky Hr =Yؙ70)AQKTJ庩eBZU %mIkSnVB*FrQ*^lI SKNϰ* YJ-+ 9gƟ6%@)Y/of{=|6`](coecc߀K0 'hGg.C u0L̦H}!_u!Sn8 5xs6stfƻ޾q]qQmǿ~JBxAj1z|`YH!\rN/I3k-YCsOM7T EDS\m1$L"["ŋK_]ǡuV}/vƬ謶&VNe hV)nk2 ]fˠTh%I}*穉LohhxAn Eb.`&H=@+clPU}(HV-1$f*䐘$ Z\q0R`輞ufF4V7)9S oNk[aR g)EK_X#C >jk:s-;Úe܄8pjJ{|nH1`6#xPn  vUUr꩕X쵍b8I[ 0 yQ2IZeXĉIU+n d n8@Ռ{OO8gtjeQ_kиխWLLmWXX^zV{K˲#lFQzNa= arOpm^ui ƴi0+P BD(, уv]^7G210Sq584 F9UA793== l?&YD '+}bI"3 !Kp$9\'m5~6"w^xAj0E:싃cV)@7|y4do)9@oޯE mpD&h 8 GYB"Gq5ҍ)Gc]8H(ru,urY۶Gу֊Z忁ntW%@(ytp ɲטӏ$!4߾7X'f x[j0D:R(%-dErddݷkaވ@ ImLBAR M.ZEQp| wBMzOj@HiV0s6eɽӿة2]oH6Ϲ[]_amV %,1vs!jJC< l1xRM0W̭mդM"8‰jl!NNDPJw9[lup2XU:5v]w;5cZtvߴmwjXuƑ`+ԧQWmζj.</^|3a2^>>]LiXvi$d3Dy1@tJ}|Æן2ys!SJPgb}J W zk s h^6LI{kK_v.\k+uxMd-$7 eY俀K UZ3~NpmY$\{ZZXRʠsY*Χ[oNxAj0E:\a$YUB2r4Eb {mxkad#mB( k@#j;0/V**`';4*t#E:_G+=ڶՂu.Ka8ˏXP9p9v!R{DZug\g8n돜~ǀ8rjsͥrm_\o9=[Lԙ_ ]k&c]o.,fƗx]N0wb/jAq* Ă:q{~ӌޘ91:x%&ȆqcY]q셴'7 e?L6 =3Yѵ[J^pdjq{<6ftA;`@v>qVJo }e{!Zoe/[mwNeMdV_gxm0Db $\\J6lѠ޲fNʹ i1eo#do#k ِ+l<7>r8\@FeT8.SoHеM~>wT#ryܕ:*eG-5tI)b946Qk2).uMDXzb!qԕa}ZjfcxJ0E3Zrj""-ޛ4}amtL͎:9',Iذ1bƥ9)/mƌB1{)h&PE68^y\ vb!H=؞I9n+nOAoo0Kt$hՉAEG@AԸtЋ /(bǐ%58l?yoEѵ_jO"oj[_`zka@bݶ;[xZ kB[.+PIkX9:p>6@}ixAj0z~a%˒Ji_BֻĐXFVhBiUU)Edg"52%(. &V{cDb}S g%sp8_;V;XG0".ܚnc ]. }͘|ZTs7}`xAN0E>\ 8NbUv`SqE1nzXx"K61xbv8bGXb'Pd[d(v$4.[> io m4hyj w:0C E5zVR[Q^(3D *upSjixPn {)QUHZ` (GzmONID5֒ݷ։Hp's N# V\pvD֡Hf8=.#|nD sncR5:6圙8 ~CKp ;Z!UlrI)s"p),!`%ƾ|Ȱ ~uG jDMt[o W5aY:͙`ASw; q l4y9\FFߎ a`x[j0EـeYv-dadݗpNo"ZhI\L8'q&cFu&[$QsbƉ1Ji1VޗxjYq}O.&0 \׵w` O{MS]WhrE~_`q7ᡖ2χ[fxQj0b/ ,.zrjA-U %hf06giY,(%0Ǚhfvjt0 ^ĻhL(a8Gv_k˕ _oy}䩶 0hurd{3Q9vXsk<6=UK^K⡊ AdxKN0E^[;!hiT"RW<$WP!B]S2"Ԉ֘mMVM2:<%gq*Ƞ)jQ{'8I0v5rJ'>vhGxϿE#ԌF U34C)?Tep\n{n_u 1B8a(3LOa!]2,w!0T)]|@jxj0 ~ 7X$N:>@mqIb++}iy;I|@?'"@Tѭ׵5TEWTZ1Q`-* -7.2U[8[ovP7h1S5|&KrP(UWM-l6g t)M (Hr"tS_zB-apS& 3hdF|Ĉ,!3|S:_}p77?$©>t2[VV*wřxKj0:uUJJ 9@ +ܾ01Hz эP)o)Q\|!JmCB킣(ՓAZ^KDњI kmp^ٷ_~Cm$VV9M0En[}’G ~GnXr^Ry9 qK4yoixA 0y~%4tim"1"^ fN30% =SXцɛ@Q\`\3+B #/\#t{ -9 P!X4NJBqNB3 z4Y:LFPqa~l4EAOlșBshKR9W7ZeyƓjry!hƀL;g3[C$e#Bm}]T .4@\E qܟ5Ƿh<A G$ I[4?39SfS&IE)CQ|gӰ7ٞZbE)NQoPٰ%o//gg't m1J` @惽:<{t9xq8:89Ŷ?v{ghRop۫Jpj `z)JY+~&RN60K꟢xR?9xcO?P{;vcuuz7ћՕTѿ%i\ÉjfI`?Rq|; Q|ۍ䮳*c<πjFB0+ͦ:A~2np^UĢ<'Fb'lT\SF ["s%B`HzXŰ :ZӪ005Qf2T1IXĤy[]d TTd6ꁚUޣf ē5IGH(d<zQ͇G,,'jYZjET2NXm4:ݑ'|P1Z-@X3 %kI[!d&&g+ma(&PDc8Lm͚f hpPwڀw )0F˚)(t4 {cHHJλ&)*0NCy+vUR;B]4|Նj]&Dݚ0SErm*u&Kߜۄs#SMYv0k&t6h]fX5/{g=cB+5~shgԣ݆ҥKԕfZF.Kr/~B JwW,__ 0ښŽ r iqH2r&UIXFJP"}- FL^aSQ ̰~&P4hVq2 ̈́fnXe` sк2ggoX!#dQ8( -O[JĖYpe! W5R EiBG !Wy: `orڛٯ-6C\iFGDMڀoכdaiSA;Ipx@0(q҂Y>Av%#%QKU7Hw7t?}0wBw0CGb}N ȳekL5#a/X*IjA\u N sEQyǔaS-MS3[#<ҋMdmFAm}6Ci=[WIH58fL:/(Ft~tKqvD^ l@C8^?U{퀇yMsny>/ [~\(qM/>U/dɫm 6b|?8پD)p$]. h%>Ua֖ sBѰ{A3| K>BH{m fxRQ8(`;,nxo` p6Gw*h_Z&->,oCq|ܨoԣvp]Š4V!< ]D퟊+`ʲ=< @FU%{&WϟZWbsU80 6|*v?<'\ >5OS} ~}ҌƾS5! 0{F8Z'MH;J,nn Y,[n=kZ=d6bCMy֡iHv10RmC'yA;BewEjUd4$|L2 *--FHO$z"8MuK.LLW1y7,h1be7T!]ERa&m<(}`I0k1 F3aAz[Aظs((B!cq8 >Z\;N&Qn> 0"S0S F+ZlXn$&fG*b&S+_>ˮSm- INVk[ =QKKqa .tq@wg.ʆ|yT8Eƿ%>Myufkf]C]j% L*M̖0b^CƠ-0RCt*#{QlD)Qةӽ?W"_XbwĈQDr=w-|YeŎ%GV/9o՟f:`"pZ۰ofd-# L;(ouغ~gގ[Zf0ls(LVIZ(zB-#(vONGJ af:=ǖ?Pm愳+vqXikh`ʰBHndl_!0ԖZF7ѕZ>{k9ъIjU5EK5>sGܜ..YɖzϝT:g6 n:z/ 1‹l0S "O5'\!u &rޟJ?sK:[NLmPT'I(^ß(3q3%Q^,b8v|,0*gbŴ`遟3-41vK]4m^ D8) جF9E%Ԥyr(W/)nWZ|KgH1e45(ŷ^AY),Z)6)_hQ{3!NgNO^ mpx[b#"hlBn ,X : س 옟9֔w o`ueBY߾be[9{F9ɕ+,hIm8rSJɹq Jh՗62?}yZ!fg-cWbp5sF/~]%;aj<Ê. eAn{HtLMe,C+5K |lb|,,+[}d۩qiddDt=:,rB1/;.0mvX8kἿ45d T;1؜,i1L+f43i0As$eWgrcN~j5fاNkY&W‘ W܌BP< .f=L-iz-[VZ֨ ߳@aF-uL=yQ񁨵"tR6:»g9NpG@TxiS+ƭf|iՎdObTiNcf=ɞœ=MNSP|U=ȐϐX; ]K^RԚG(V/p}!w/ :O-׋@~gGf#ydox4ީ'{D\c OC Ø&}rFxwG5AO_#]*]Ou qLV(a[hd{,ˈy2|՜u*°ThBTwn|n\ȤwLc+ z6KUU+26+_fMq+/}:/GG:ǿ_^wt=EO# ;L(+ caE]i^O\5%M25LbejȸR L08 Y$}P'FW/,VĮRX_ 7EB}\ZfB9Pa!Ӱ.yhD]v+4'p< `iz"OqS%x;nOpw*Kj3 $+ 1IRitMޭYgKD|`uU@vx岮~0=#IHM5?o8Cg|j]ko>pӡzR=zzQ_# ]5]^<[F.en(Uʡ dVX+#ɳvZkF#F_K_U7w+vO4u}[)|q!i!0Tf{-'A/L޴EүU}73 ]Jqzts|&Nw D[3?9ܥNfQ%=崮*}ad&'đ6 Y!T䬸kqc9Zu~ K ?"e6,|)9ڱ `sjܷl)͈ 'sQ1 R*cr4!m›Jspx, >wm"Yv_VsJ17Ⱦa=n Wܴbr9?]&Xϕ"SgX$Ra}>RjՔ~ SdZyma6~(+N74H誔@Ɩ}]G-CeU)xW&uޯ3?z5O>,HVN!T mzH&|t+t"&$fx6.; 況nl^R߆AY19ɰ: 4n7yǟ1Pϝ"linqywF;p.d+ŒՕ&΁.*U|hbLXPghM^7J`L:7@|%EBHktgI#ڗ;ux=Q1`)?ht߫-xy+݊)_WzU(WaFuFCƼgA Rl;:?|h7GiCs`@U+-c?K"VHxu-(0fox1Og`4>y|,j'8_;Z1aᏵjT̷`=j\ _-BRcm{| WUPb ^Z}_KWvN8eO8:=̰-%2\_^u#{9,2BlO Ne{hkYsZ|Dx7FD2 Pyd*egazLznT{Ap:{GFxk|x ́Y7 I[2x;A f槥ŗL^&=لMh;MCp~,<ũE@_{gVN40= ՞a"/M9^$_ZQP\eř)Ѓq1ٓ+='3G*b|σX[xNɚi=GKK&O*,i K)N)*YsM# udw˜n=pȩɋC+'DLvce⬝™QkWhdz~IBi^N~rv|ZbfzDʨeT&hhBC5CUWFIOVP RP\YjlXm QX`d 1@{a6, h9"hRQjb6XS1 C1Ϝ SG(:k'r!Ĭ&wYs!h/"ah HH+յB R+oΏ N Z@8d~!pr~H" h0hvA~1$7?x |0D[9%6W]d_/x{> Y836f)ZysK *x{q^ 7ob|q,_xM&  &  E J3&~<?~<\ArA * KPqpl9(QkQ% X[xuVC$&G n>v\| N"xn 'yYJ* R'mgۜМ<J|Z\ũE%9y 3zuRřUim2`ܼ$""bx;n k9.3W*m({K 7#xyûơ #include fo /j \sizeof(hdr), obj)64 4p!R R=T. x;qB 9s'' Jn> n~fYQhr8s3PYz{cͻyxuQx#!!a!$,!"H Z1xɸm5ғwI; pf$zehkZo6$VUY^1WV;x6k_w4XB}|'ɽ䰳U(-NM\)W g1xQqstdio.h>2)typedef struct$P& |9z:Agb3JYsg,0_xmRkAƆZ-T Fx47DHKsbJEfz^A!x7xKОjD^(bI / ,=3lock);/0,cxMXV.o$V%+#%&]if (@%s'*(db->alternates && )V[x[ lX'a|U \g x[6sD ֱxO,LO./)J,KHLJ,1+HOKLMD.*-D0˸~xVn7=_1PZ ipvjwV˚KnInl5ȿ R:MtDg޼y35I?SGvxoO?J-uDZu `݌p:8{C`l-p*kP@f!zX#-zŘ7ڧԉw~0 4\Ye4plZIJLsV;ggfeML] wu0L _)ݷ>Be/zKj@|-B\w\) ~ĸ'gn[fu:E#8!FImsD2Rm":Tv{I"(4B߁-pA0Z;,ӣ9X,+բ[$>T\Jp(-A=4MlLhPj~4PMF/^b![gd\!f2ggq! A{Cc\@E8&4Mw*=uBNlNd6 %\OZދ&BHX76 _Ⱥ{WƄ.. ;ߏm#1cNC#b$H@!WJWlj; tsQ kx_K"{)aA[$0$C&$ݓ]' M#4 #妩in |D|k-f>XQcT봕$>UR D7 rg^< aik_\Z~")4J\//He] V=[渜'(?|jLC1̃7$1H;x+q SKڍ0!1O V(0v,|rxs\/ήs>e+^}ޟX,ϋ3\)< KP x\[s8~^(Įb4ˌJXdK E_7dlL h jniC]NESۼ*u'tj*YVo_f(M^Vԥ?zMl zeo"_}>eEi ?_(C/^$- c6߶fMS4mhX6PJKfY`ⅶK[ɣhJS~h4rҶYWѻ&E@_eTĉ}L `˴aR^f-[tci0mۦ-KeU F.@aT^>U]mތh}>]œYU:n4o^٘of[+hiڷқ*W 'YMSgBhEU|3˶IDRo_(i0;xu7h2;Hο~u~NPgժyMk?Tm1@~0R?5kIO?6xP߿{~֏#b"bm "f*WìZS6zNgR`zRZ++CI7t8=ڲplrm=/fl\ M>|MwЭZqDvx&6א^AʦNmP`$2۴NwVZo)`XWb֤_ 檧$#PTkl8PŖ=M2{ {#:}#QEA>:_ HROđ% lH_$_W1IjOuyq)TbU|!}-0oƮbfәWx!/6&eiČE)V'0Ӕn CWyTTj(nQ5wzJ"mxrMJw"/;;ƜL@c?1/C܈v&XAczeh"^%;(l9MUs`W:.0_F:-w, =Ux=zXX'[Pڐh^"TVh3gSC~N=H_Hx!p":3-sZV:9qͬU8 b=Mn|b lgAo2!Xd,Zwrʟ>W?;`fVw ɼ@_NE?eHK1Aiv/*)Jmyzg=1YFv +*뜶W Ζ}ѼaM -WQ Y,0p>P|1P_ du eRYeIwN걚捍q 7׀y!/##3o:ml:$N6R96,|C\!_B% )yzYJY5S:[Za .>@uax?iQ nFQSH1dj;KQ8eᚬ$ofIN`E N=hfyIw<>.0b:˦IJшF=iKENcɦoG\mJGD'Eq*)肀eZ fDҍmxˌ=BțN (COF ,`@61i mɦcWrXΟYquמ ts{ "URp3\kc^ga)$]ly{`w%JBf8:@zNθ͓%ńJ(?RF@hB.-9:#O[Zp`H05Z, R,>jR}p:9%,ȇ#p%,8zxm>.a_a5EV%7{6gҰk93 x :vA%({,OĈ,!B6%#3M6 &c}?~IEj M'طBۿ:1,ӈRzO=BHq}Ȏ_5ixEQd 2UHNi:4\j BN}]-9ev BPoA.I{ Akv٪MZ$O uIB8Ac$ ÝAr'Țbl d_;\ HlvA(gI#W=v5/gxw {gp +/Q9f> {u[>MAbqe[I8}XRRvi8=英o+/74HrK-=k;,(٪3*Z,(DZ Ps~dFb%#T_VW,1tHX)rdZ[-s#H!fҦq/vηRQVIIN 5WZjLh}K)nč~buǡ 6~a ģG ti&# I4sCCEQ!Œ_*Qvgnd ]CLsXJ9؞: Ds{Wh!+Tk\S4;/2Ұ~F- NTMp }n3A8ߪcg%Q>nבm]\-MQSI4^(bZw Et DP"^mD.P{sAT3`"6#˟^u%A-@:Ly,3BJΊ|z&- \&ƪDŽ@ ]ߪ-IJyJ#ý.6!f/98͢-؆_ҶRK ?q05v!7xS\[ #,Pw~dr.jӋ8_{s`GS:guZq˄P%k; dK;.p7U) oˆZt钨6{ꇬ*2>wrkAvdA#G~ g'CrƄ=Ŕ[@(VAv^] 6Q9VUms`9?=ۨ}ʁQ SJ']Wيt9%U8 آY&yâ o\Am1jz!&8寂$Қ6W{$S2P(:Fh[dpxȯHQ"l#II*}ѕUvewœlE|Em^rʑݯJ:ޒ.(D?i{3-I>q'6mݧ,׽!#@!N. !+K/:(́Q0 \n!߈#3niӰ~DnC}lٜG{c 1QCg0h WΒ.c{4y@j$+TzK 8+hvXW$ۅ| b!K?hihĝ?hݺ?~NL7M gD2?p:$z4FfEs?#z8\=p#0hgDYى_}Mj|7%9a<_<ʯl XHç_pc8 wiO5Ab^}wFfat=㥑{6gNl4<t0#=bؖI3dqrNG{1HfF箾iq' =^>Ic"3tn=xpE,"  ? ?f BKfDFcY WHS$zHljAݑA!k/#^wk~aECϫFOGqJx='|( emOo>1qz c=SB6HX-u}NOIQ\hGQ ɽqo# ǐ[ir4*9 wB`y9 v1#ZT[r u}6ץ3Dd GB;q#d@2skzϝ}Pި/.1܌bOq>%4+9u(4z(iB6]ak8񃹿kLxj,|s_(3H\͊o5s 9) |1YgVz[qĭ8m׉I ';"! LcLpW_q]ŕBnl!)HBt(i"YFm*(Y)[bطohR Y]dEvڹzS_h]+BG)4]ߜuT$F;9}W]_uq_juxX[wH~E#Ş}Y Bu;8}"$$|oun`x#uU}uj9A҄>y`l/G|t1]!$F,/b)Q&֋(@[x<% YrB;+;IM$z4+3`ls}$0M$$$&C$Zeb$CEE$ǐ8HO %bà &ܲ$QnY0O#`abzv A 1Ag|,~$c|o}Ř?`|/M@o#W 2|Xޡn|2WQ~C/K =b m.Z@o!{ =!OionOMsE0JsKLSjq8 pָ\s;|Khif8X' F1]%0"p0 %.>uEjV+3'<_5ǡx@tۿ:Bz{h[{IQ~(8Z^%<\y=D=Ǖgk@FN7s. #.xFS '}P 6Ӫv?Zw<\' M\.*9vZ˲uŢ!XOe^!,, ^Wz%:yߟYdbdz>%Đ6mfsiM(pv J}j*3f}~Me`7B\v0yq,_MX#`~ٻ~y)4iTg%Ǯ[EDvێ z~K``n*eOf.Z" Յq*>ٸ9(VC:B!qʄ*lw=;FM~](QmN#f\Γ W\ՂD%_(  w+Z>rH$JVwYT0SY$y`dX:,b\b8Ծ\'MvKFͦHwJ+xjV؄?F5'扑h<[凖Qn'[>?e6>l#Tu OČZq,ъWɋf #Y'icc#DT[a9rUwD;w<#6bo6'[tq ,*IĚ$+9SZRn=rZ.q,(T>X)7?{z%L\Zf]·fo\SM9g/r\oֿpt6qt!B<=^#.S?N"+utR*2Uw@_#Ƀio8A又PJKSAhN;q\v,bk¸ɯ, W,^d:"X#>֐x/;hd_EyAsQ_e?{ܻg է2@5hYbhk#R5!B*-P#eǸi}rtHr}dܜt8xl>=6d x]1O0w0{׾/UNHvM*H <GBgP=ARLVЁ ??o9lc,o_ ja]_hq7?mJZ[oD6D/ ziԫVj,1edtI@yXԐ6 (f5rn}<ϦKSSu 5X0io|RǂxVn6}b)`j b(v$M./qPҬ,E$@XPi  I̙ӻF\ٷl#b0>6ZEjSҕ%StEL{A;Kk+mk lzz}XQ*w-Tk3|ag.9_E17`WT/Mvpo\w[3\;? r2yh;(y9 izjI *rdt6z]Q)جmZav!ŽBjz+P];cVSU>Y*jgsN`w "IĜ0,04{HMuL# JWcMSPjՆ)~$gU%,,a*+Fr^ڪ^p-oA&6NJ![8OfaY<}t8=K1͖S%̖*mNffԲw[I `v2fhT=x옣΁RձIi%ၸ?Id] BiF|C 8S%\HBf&,PԩX6b7O *T!G;РahN%\j_xnLH"sZ +;p^  ION~Pi0Lu$0 )T23d&#O5KZ!Je' T[;1anIQG 2(lU(1ntb(sLz\f?XTHhzC\)_pey5zL ˥#KJj'lbN@0޳JtC -(O訉9bm=U^AT,k< gVK9)3yתոDPfCof:l\ D^ %C(kѬemɀp0kDI7UQ:ĔwtF/˼sj M΁{RB]o& w sMV6ʴS1Uݎ..׭?9@;׸3冖--0AĤ7t`V:b/-y=ԕrѩ7jpXͲ&/knٳBp%,2d}O4{x ߠOr+.P[:U,xq.CNfRJfDCHWx31lDC篏8q`Q䏹W6i($'e0l~`@S }yv@$'&$9Qjp|/)0e%z O&붾s:-wSԏ_CU`7aƾw>SHjj(:ޒP:W߮Aդ$&T-RuY^W•3.9,3(`>s!C5-_$Y\ua 3 د+ %rυ+PEEE@>m}vs*o yDU0c mx[r&-3'3@n2:n8-|5k|LAWGb1{Qͯg/En|*䨏6:F^JXvփ{Nۮ)`],?=qWbtk_\lN+% Ozu|Fd$g-)򱀿٩9?M9#USQၰݙ)p)*2RR+̘pۼ}jNlE)?T$F ǙUZsϼٗ=s%,sհ͋W|p5S^Hb3gM~T!%\?jN44aizE SN*~喕xƴHBR$.|4Z,S4`OeO6~b !_PpT8t]Oo=Oq\}ח{ڋRRAzKW_V}Vm>Ua(`ەbEyfÑSb3:M]1&!;f02Qx340031Q(H4KfI0=ė6{W0DRڛyY\IfX*2xYmo8l ‹MDm-/Ikpm4@+m*K(I~ϐ؊]%p8|pH=;h͙lYTlQȹ&bVd,*cƣH(%y19+fu6ԌԂ  Na貽=T28RnޡmGn?S-#OyQ)k15\V5,M],xHj Wc&_Abj!"@zl,B3Pl@r҇)Y+ȔcM*`+{yD:sg},ɲE A1<{d y,uQr ؈+, sN< :Wy9; sItxsݓp۹RU;|E$Jz|pnݖ87.{9 .0%sruXHgKѨyƝ4]v-ٌ @R1ZW|!59B%K& -b5BC*`^~d+q+r s2HdU/ϐfZu#|]giRW8( s2 6ˢL#*iZe50lE BX 6S8+";s4<*AB2tSBdB&,?9{"N`Pjwi$ 21Rj9 Ĕ b_ 9=h oDTEi([($2a/4qFI jJeCrrv4c͒/ f 6D{h )$+43d[6eghѧLq M9D JĜM=C1bALaWH_!ȏTfy1@Q-Ӹ"Ir6{& G1 朦;tKֽzSܭ6ceQG||?L\v4]ʇU# ٦*#p?;hA k3cr3M^odg4MS?\\d{U H6xxґeR$,q\oL(PvM ТG@說frRK &m6Zj7^BoY% /o;\7~rXD;p%cN'j#UDc8AY-J!Ųܖk]mVdinQujt,Zp7YW=µY׊=Ȏ~Ex lo:DM3;պzf]C66tQnY2i 6Od\oB_WHU%J:8p?>|]HeK:Ll'#CvSRZRib^pߦt˻RoKw(J*J5 S "ۣSxgMP|yc;6>j$|t&kvxj׮yZigrL"vC ùY<=ܽsǺw~oY? Avj1z0 cqQZXd e{j Is4(vߙG|؋xkN!b1Nt'YձŇvw[ŎE3ܻ^yO&A/'v T'/|ASӾ~QU꽯 "m˖(|6H JAd$>M`2D2u1>dMgMYfě`o |5r 5l-)VYH,jZa=VX醯=Rze+ qzVX#fYa= 0hB(hB(hB(hB(hB(hB(hB(hB(hB(hT`9e~=bVX#fYa=bVX#fYa=bVX)#4!4hBhЄР AB&M 4!4hTr!zĬ1+G zĬ1+G zĬSF8jBhԄШ QB&FM5!4jBhT˩uGguΫnj?m]NeJ2N!U_:l~iQ;ԜOQ!(0ԥKJfwJGQ Y@L̖GcG`$Ao ̞Q?>\hA{#XO2HHwk{4~* o e-XhC1[Idv>܁bnӅ870tcRaRR--ib-I}467#OV]IδvZȞFzՓ9mW.famq=,2^mh׏v˞i̗4eG]7}C1aߌbs+I8}x޺rqV|ux6 s`;/xy N]c, xd.-y\~ëBV\}ko"τ/2:k.6%lptw/^ON6^z.k(0n&-¯o;,lE3 ,xmRj0<_KLKNPCOMi!{2ҺSE̠0!O`M# L-TN rcs,S)TDU+$arC94*`h[LM^MQYVKz^  -y#;ћָّKUUXPp4MQElBu'2 bGufrVUHˣ8VZdq԰p?dr,0]<./gJj2qWIA8 3NuI( tWqa^qPHJP-~@~aE'Sp.|Nž;QOBxuSێ0}&_1*WB򲭪J]ڇJ8ĭcGpمl[H|fጧ|`m-Tl`PR(VPjJ_9ytA0#m+8J[dHTzGIy u44 e c+Q:א|X*Q)zMYJs, E#- j~*u]#\uK$=X]3!UU7NCcZ*ZY[1mUq"d FC5A5Fc)Ii"=lr?s N ڄ6lpHa$' lF``yiR{J zQ1N۽H 6#Lp+@ ?J B=μx_`Xԉp {1ٚҴ {gAYH8"AБ {Wn,Ҍ}8tGVK*D'r9vbq7'vmp|;JIP=x[űcCgHFif^Q| ML gxTOA_1pAԴZ$fMv=;<@ i? 3L̛~ }'֦p-pD(@4iQKAjRE2z͸a9M+U(.$nKY!"T5?RJ L$J[#Is16bc*cQ:aϘ{{h6G 'bƉg2EM"O?+{"~Eih}Ijhcf`ʍ0jK,4\c$vƶK5Ey#+}:Vv Bm7$J#9F3[Ìpk WRI;tlܒat^a%TfjT_<ęT݄D$e[EQΝVh|VO"nqa2;Eh5pNw0p8]d-^H$U M씮*a4+ _ȲC#7!v S,I(W}Ӏt<~䳏 G@sNBp=ϧ&">%x "4]f(Iƿg\e ?CVrD|4ZĈG \f gqԵrSx9D898nw CH#3)+O#FN8?AE 皬t&C%D #'Mt3T;.}8JO45Sή>iaBT)26olk+mYjRFK0{Dyhp#N9z{drlxqǣ1xr/磋!b2C"R"B+XAL 1E.g¦ `ŏDh UH@*y㰾_}@Of><$>Ycܤ}t[(\d8 g3\8(h~./Hv?K|Qh3-anpk7n]ScРPӓs>>9t.ݚ"ׁ`oH&g:æ}]{]'h³^RNc7{>w%'(#FMd8hq 7ˡH'ej)0IG,^wntT޵^v-!8cQ>ٜ'(BgԽau~zb@zȾg!IXLBTA% 7u!QT0BI`mP.?}"H/3gG#T ߧ·9kGACFE]9e,LJ[]?STC> sC(@a,R   =ƉeR EgйvS 8q{+K(.c" 鉱` xn0~:|M!mUdF0U42EsGQ/PM(HBk:C΅1LBd8?I<=LyHC: "eZTPZPFbwwbR"вE$cP GK$}Zs ]#`nA\f2V'Ű37,5M[Qq-g!x2qk4Z0M.ۇ} eXE`T8>|czÓ`38*_KyX͋J:k݈}.i'âzn/"e.}C ]հNs[1xT4~C" Fr'#0B1KN"8ծ-ѰLܮD ZmQ(`%N'd =eLE3d ڝ,OGE>}%qh0;1gb^.0G'DEuL<}x%|I%b勲jaU*ZǗ{e-bma (|bK>ck'NVrmm_iPy'&1okK9]N>B&Jȑ>4FruyMKJ^9g=60ΘuCok)dXF~J-S4(Nd g YAICVZ«ч<: PEYՐ*Al@M"2,((3+ _8fk"s.rsP-/$ &FqC*kAx:`ee+Lq#Ѭңbn"vj2SI&Lqh̸WYW2PHYXW5BjA ( yZ3-%vnpWZų5 AZIecsӘk2-\ ZDSax00T* fBz6C|] R:6ZAW٘vLȶ8a|H)#PZ/oѫMSlM"HIӏ|,uVL~J%+\C+' e^˜9X"Ij/x3kePu!NW:RhZ*0XEte*X}Am݁ve:WO!haVؙ0$E=q FqS"(*/P8GZ 8Ǻɫ*ҔTAiR Y2/JPR{_ki1sGWiy:PbKneH7CqHɐWU1zIuS?7ˢd3jQ;9tԡ^%oG1%݀ns  B;L;=:w+|2J%+"h]>SA_`g,xM&-@ -ŊDc Q0Uo\XLl?vw*VV;W5MW۵Qcg{(@Iu7d6k_slw*GgRSQ2munl{Q}goKuirì5ظ[U 7A4:s>%Vek{Rl 褰+…>Y X4laE2ِдxUQo0~Q` aL+jg+M.YjG31lM!^wwE9z)bf[\D\E=pY^mj*xZ~ QSM1bKH"ѹ~\" =-޼Dh˜O`%O%Ix ONm-b>#^FQ tJG>ķ2W ‹_ qG-C3K/bV;a+$7{ aipJ) 憔cl(PY$ZlnsFj- VoLf'p:ŖP))hz++͉*,& wT1:2Sr`?։)C $Wh Hb*,%.VF]]\<۟V#agG; ixcL޸Tc3-1['f2pSA1uw<R`уȺzd@O̺yfNƴyR ػFi.wmG%̌!e>[> +4߱Hy%Pd_{S'ȡߜOy$U_ vpb+OBorI/29 ixUn@}WLH iT(`5ekXŬ-"~}gwmc/:s9gOD_cl\C&wz  dI $ s8Ipݺx7n?@C| p|C8bt8&b<"J71%W=*XmOa3zE* uE0wcܦ:_}j<̓y8mq[d+2RBSYJ+ƤS>TpX|]Q-XPL֣-; "ζҦ+)rH%/A>g#2gAU2~@h#K%;Dw<Kjᢺޯj!"&I3p+ԥ &x.(R1AъEmGxiW^p^;V%sؙ7ybǕ>LMd4;I!D}[pb2Ӄ;H(%}T-HSA{ aX*Z3ZaP'9Цn]VRYlN2o'se6]2Zw T -6%FHft跁Za4ҙcL=>musFht1"]B(6߇1mE}Mdҳhڞ,4ey -JU8 FV!{ pIJ4SvMAb[/[$%n:JmDy'Ҥ^BȪ"E3 MMXR-q^+1*]@%i>BL |) a5<&D6|釻?,ľ%wE< Cz*<עs("q9qς@u wmQĨgb.fBˣO/WG/CaA(Bxy m+ll5eqk/zAp0VC Y&Cܢ-e3.XlY{ނ ]}bG++ P3qq{ %9vK[}ʹ)|(c4=Aj} )KHp5λwqUͼod?4)_cpa)[-=[) Bڄlв3xuRN1>gbhW<@())gk'.{e#waqgϞ; Y_=^+C=aOjT3eYm-\ C<Qt8RvAy!5`XA]+#0Xf/Yjތ<`${d2IH\*6 9IU0fC}`rt~7O.#\s>:0XNLi\D)L:3UQw'*́%Ï>/sx7qZoPrl_=e?~Z7 8;-cXL/${?gZ =3E/,5~ߚY)/֗LTb1Γm^r/WӕmM3'omB.xuQK0_qY_N";0 e"a4 lH3uݛ&q6J$ddSʄ5$BQH~HreZC+:.rB"5riF dj>Mwa(u<|R%dPK\[B~Bní7fS5wy,}NBD'.tQL\J`g/õS n&gsDKWٲ۾C _n˕je/b7iHB:,Z`ܑ}pC=;AB2E"B<&{@x}SM0='b Rn{haH,{h L7qޱ)BU/y̛I,#vͦv71׵>Nb9[@6dp90q8QזULY E^2KZ5Ӊ&+ao,h!>-h![k[XtBئ琻q@\ *l`7;bf/)&GT^oe={s^km9y߈~2a,&iGZosPEw0Jg~DgrDg Ӎ'h.vjG#f_Q$xM @ͯXq) A cl迷~@]<ϬO+D>h6qbO\6BSޛ[F EG&EqiIs+YyɒcrU<`1D`av ?me&5穡OIQߪ(ݚ_lȊ*xy?jJxtid^F]ҷxVao6l[v6NCtp;؁, A%*&"I%Qe;J;`DݻwGZpފ+y€J@X? `-  $Ғ/ f,:RxMAp"&Ah&S"6\ b&NAqZ-KsEq{(^ 3v%<4鈄gw#iEN伡3CsZ`V :KȥA̳Boq`{, ~ ː6xvV6]xh"lT u} izՃ, u,xOXv>}xbf?BWfesӎ7h},4qگyuw{$I4XkNOaL00L23G;s/JI1-#?mCwNQ9:50Ȧk95;NWIomUGZiVZ+"C᷌a 7dRɂhet}Ӡ q;9Q!_ZwT>K8\)R29u>99+WwOX;*Qov>{m.( ŽzGLhssz8<{;)7r,I.> 2,CYeL~xwMD\kdtڰwR#ϦҐV9T3yXn9ls-UA ׃7ULJ4>MlS)L)R'̨] NQoIY:f6ud)Y"4"$1ʘS{d/)hO쮻 Ӣ꾡m|:)LJ!?͟`-[N}켿F ڣOݷ:&D&퉲կ5ҫ$m3 ̶J=iXP5[1'7{[@6W_: "x}AK1ͯ]`OEE **"aM&i7 ([M {K4DӫsH♏&9dnГDXfݺp2. O"@'-{p}4foK~LMȣdJ&g|T|IL%NaMP:qΣ dKr]c-)?.ӤzGAʁII/;wx[2eBUgH|cGcD5gqfUj|BAbIF|Nj^zI5gzfI|ZfNOζx &거xW[o6~dIyɐ^k,s'Pt KTF Qn֮;d;]i/Hw<|qIxJwOO^R5nYPeŪЕR Qu$HV=Z%D5SЩ".ßg[ڔc~BCY쫫?.eTRܫ2}q9xKӳY;C 1\n@ tQFp c=mK (n?TxQ39Uɉ7 hv^>R{UVl$}5JJӫۼT;b____n7ʬYƏLWzVm9c__9U bU+~ LqI}>h]f_/uE vx CQe粀[*zBgL ?H"eYy _<{&P*x̰"4UD=zsʘ֗+MLz0'hP |c0\EybG@f\\|:>*-PvLK) #;`8)[ $"nh -JB"$LNQ59x UOБ^S/-*0iX)EYq!l1k A)h%I{8J>Z&MV2[۬S6=Ⅳ\-.oB_򷳫b k%-}[E uMaGCG4$ãx&T0ؾN$aeu}k3u%W0ظҪ4;֙lj)&GD+ҝL ,Zlasw]P;nj;1JU o213u0)MkQ[jlŠuʷX;2pP/QTA %u1|[xqx74 CuE PRQKLQw6WQy m{-J&YTSc%?ot?Z=![N{l*fPwӏ-}Q$g ^U?\0-||8<5-NH`~fLbF>3c=Nrx шƵA{۝y×#WE%m{i^̆;yzrwGxkT-=$-?~?*N o;xWKs6>bLGj#wx29q  L{w"e}|^]O#B)*3ܮm2VP@5\3+4HM wk(ɵpvX-r[@H˵d4L[P{e@B%,Woo- eYtBo(-8U]+9۽լ_B.~.si5E>,?f~\,WIr i~xHRxQ$F]czvIфk-zM4p<=6=;0K)0@SzM^IHJDuœV>G >=+fdNAYst!OJXbZ_,n\# dI$Ǻ3̈ӎKh1b&}ʜ?jJr<m[񞛘= *kXQ55{W181[5 xuA3Y/ =GsUmkEa!EC-sYX\~C"imPR&Nboܭ>{YJ$X`bj>A= 2XN7iS`4a[ܗ*}Ǐd[o:;㕛;o5PZqq^X(/h Ԝ|Rn"JYiGj,bSl?vM|rAU'jř sلaT.B.z0 EcCU ;me(%-?XdsKxycrvr6ΆAԛxrS_vY6UGk!XpN03Jk61D^/xi)n%iJl86 ;d؊3݌q2x@ܾ󙜲j%9g-ڙ[qOQZ5BM xVnF=G_1pUF{!.Z^@&U@+k+pIB%%SNR 5ݙypf/WTMmRVUO*c"k[Wzڔ95V.ɚʔ[Y26֎Y2[ijښ\uUN<&񏂟0Ϻ|d)svmU+p*396:Zo, *M35m;Z槠1"[U{jL ^QG57YUeva*2ةh֪iaʷN\ڜm @ig't?OuM )uw&.AEFmSYJqU!UXmM9hq(PZcʚuq(7St[WqmYȘ:"AxG᝜ ]=`S"9I&MDL$W$ڙ@<qLaDv>$R#6?[Ld0|P&42$ZaxM"o]əL\k!={Q"̋ha,ܧ3Oފĝo>8|CJw5m8H._|37 _ksؤwMELOa!O"ċ8"4 ÉS>ѝE|qMX'\xxp%?_-b$A"h1Od#P6 zlF`=byjp@@?DTR 39/x7dG2mdgdC䅣yW#]|r'wUˮM8.z]jݕX>z r{T?چy Zaպ5Zx`p1t_ǵ.8oҀ ]]ZY4őki]s: }®a޿82Y^ j|LC#FKocvPwUFE[\r> G\#y%b=/7x k<0]ǒ ~Eh?+/1#G._x.K;cS Aҭ{w}0>نC]{:/͠.2| 5&N+2i@ĤMQIZ 3{*{˗,3 `!x#1g]LZ#v>4gW99yJ fUMFmLYnb?>Vv_1#o;ɐ1xR۶RXS^ؐ^eձI̓6-Cz w+pt~BwЧ]M)O<ʳYw!VzI^NJ{Lߩuem (Rz}=j3U5CZkUکf^K8& 3"b3xAkA)Ҍ=I)Z5$K ( %LvfGwg쬥˜ x#3x֓wOΛ]lED{y3'6,, U)Iv5!ôvºA X#aҏ (0scs$^DnoP{3K1rQ.kA ߾u8܃Ez#e)]0"%ʥGkQʽ _wp*hY$.yWdݩNU 4ƨQF6{$THӡ#Pī|:5\AH:W񕸙;q)pkNF'Pۼ&M/T}e5TE5~m\@К݁TŸIGmWrZ+Cۗl1I u~V%ڗzhX ޶/LV+̜,'5-"UKd&}L4{s+e 2d ޟG' >&wI@ cdh6dJLd8L~>F~&N r ٵK~'#:]J@N"-#Y>j DEUlwM~8H[T\>=9j6y, cU±E>]|wU'{霪 S$oFRX[s3cvgcFpc2N/I Wx%VpAz}--T̴b4̼ĜʂT-}.Դ̼TwϐxW'W 0/(?HAWT  % )% EE%@i,&;o6y{ <9(xuQAj0K| MK$`JBoBxA^Y-$nҋvvfwF!Tvzf쌆 XXZ I!R)JTmh~LzsHHX(XŠ5o|nA J"A++A[+ORtca^˿?6=e]lshHMjBaWEQ쏱fEv#$ԣu- u:b{Vi#Á(q:4?(I w ؏ )hSCm2֟NIsӸp[TKe(oɑ|iG]t3P6\>mnqs-/axkf}2!xb:`̼ьqW0xUMO1WОVRCjocf]3ͮ &;yc:3 3Mo'sMy>t >sk#WB8(jņ`Ѓfz@'aGi~D+ym B]V+5l^DkIZB/z._&WlW,ۀҡGj0Q&"g6b)U2$0#cd/N9 :.~"O'SؗX1+2$nuRpD7(;eb(oP$߆f7),9Z)06AT[ɏɷQ'8EVVIk| ktj 1<kɲpkl8Z17KPT>&BZQ c%c M5D"˚x3'>wLSO"ʅC|MdiRq7?O]'u{\(9[D~mm߾__I[k_OZykҴ־SW<_:fBn]f#в?0B_!(ηK+9Դ`kCi 3^;k+f#vyb{GUf+C Zwq񇐮%YfcQMH?e-bDfg7}g;o0BFC^tw <;}4Jg?͜BxX]oF|^lk_rw PHA&ZOˆYPl%;Y,S 7WgtEnSVuETkHeK$"]PeeBҔʡ]ȔGim2ԩdRFk]*Miuz%kQEOl"5EWYZߴ}8 "JM۪FBDlW.3ll0N JiERUyc.m>&}DLcf&ݮUQˮj7$7%eJ-j|cĖb{2 pQȵykg ;$ϬB;$cw4b dȨ` h!UdX[5ppѠۆ,nݪJM#"ۭhz%w~Lq8JHQ! RN#|]8(&72 $$ڹ|Hi$ˆć=8 E0lc`0'ؙupD"G-'!cDX8=طA"h6M0DPÁ 6mFlpN`=bz-k.@/W@'X!zcqϏy8pyf!ю.# ~9v?" zwmpܜ"S˶UIs-=^B"ͷs^N! 8puoUn~sE]Z1O*)\HF㏘* =aaӡ?Z6bY| ~0 ob## [AksuͰzQµ◳wl`*YnJu-`ʝB; ]ɒ6ܞ5`7mUJ骁xQ>#,u.mE m13|/Tt׌'V`{iһ\+vnf;rocct饥O glݝ9&活:gެab[ Rctmsپ'$ReC͏O2UyxY1Ȋ'd{+B#d)`1mÜjTKP4/7Mo5s5=2_6Ľ\˟UqRdu+J5Ë5o!\Mxrr.y4vhS0Iܘv pnbSck8| aK,sH=1;Q;Zܢs@y=.7Z?2 ${<ɥTu߷vD]&ܖYک;GJk t| ܿ>pCp' W>Ltv"0a{gxDC,Db-8n\J>n =[ҏ.↥+t@8'lu\W!SŎ޶mxȼW& +q8Ay|) `'Q8xTq }ջ̭(njcec6ۜȌK7m)+mE>WOQ7J>`}o>~Z͘[uZO;{ D>[tJߎTtq2=d|g@Wq[qmuͥ ۝O-%:Wz|=Y435&υ+Izq]]v{  spkT -#h-4FY~~p?n"L3r((p>q1! YAӽY&g$emFD@eBƔ'QLaғ -qeq$ `đ>eB+d#h4Kt2 2͑{C O6掹9ɠcfY/ЋUH=}?Te"V]`'""p6 P}>䂉\~."!eا zV2ՂIRJ[5k)ǹ^gxjkG5ar Q;L\ be85 HXݹ zW!D>#Zk C"@X 1 (u6K %;̔l=9sE#-Qz61ٛǥځ򊬬%B;oNV71Qf.ANĿ"Q UBy$V؂ՠׯCxCV!#DyB9}çGf9͍RJ,,+tU-< l{~bU3o1ں(8&qL2QaҴYPv,9Wq}_mG۾ݠD bq&lSl6e]O+8psG^J<[l/Ot6ܥ7 83w:zvE|3,\;ŢY'oҊsc|9;<:0˷/*CE2$Jy\{mvQx uοձxXAS>/B5sx }ILpUY%2X~ nI`gvOK Vw/6a^U1-֦eZB)lYg ֵɚӹ+~cқv^Y3IUgF9'SƵ`i(XՋ,`?=U^eD*rUZ+r@{!ÁLЧ:K:blYuel.A1+.7B_|G HjE8;DwPyCԾ(hFhɫv˼SbfeG< ⴣAy! Q lZ78cw4CH"t {w98<bNr4&w,3?LM_V؇lz ?a!Al$$ UE- f~rIˈqV?Գ%|JKa~ {08 =tGu|E%>l4zLZu^u(ƟS tx6KC'_&~-e%.gZ#U"K:h"tP; X Z9Z~Ax/qϖ' `]ʧNҋw 4o ^QiQ4#7F?_n@Vhv4 涮:wj6pU(K<=~EG4 ;/\u?I*Plv%jf.\؅Oq^,v$ո4U?lRp#Aaժ>ChehN4&CC07>=y2tB4]"eoQ&LѠ^sFx9f}9 rqnDŽη_3lj1,pk%p*z1VI~)Dc[w'%VpYr~J{R"bZ.k)-FsZjɤ9a`̩rg)nQbo=?8Va XV!̧'? D+btBUɔ!69հk-5(S8x չj? V]{Vw:.C99݁Ubfk^?fۗ}i^DCRf$p`vO2 u՛emU|^CJ"sW(J&B-s\RpCokPɑ^IߠM 6e~)05}܋۰.1Q6q0b*i{cWOHzBlؒ$F !f*/ҋba^gv!|[ѱTFo8XlKM׮#=9:Xz&2nrJu-*vfWgT5Yygd_Yԅ,Oh]x7Y[59?77?O/CK93/94%UA)?% U`6iF;fm f|?T.??GAKS!= >1''?YȎUJI-P&(J-N-KL.W(QPZ,"u@Ńܔ9 Œ̔T B8%/iE(LW`A3xuj@q`hBĩ{Lri(v*' } y{tvU6f53}ϠU`sϕ(iPT0gbR AkEjA'ӱF ^ fQS3 0q]L` OHTAWLf7KX+pWgњ) //ڸ*FMGw(Wq}N6^qn\ aD۵t( _s"8 rW0I4*ܛ\Wvhx7?v./.x ^rh\UK7\76}5ĵ*|UtȵqwD3zf~6=: ?qf}xdJ>]\N3I9tkuf /$Ijl sҮx"RkqVi2Z8:usu>r7,N& Wʝ t{'PJCC3yu~/aYNxT]0|WzMuAmr$ J'Y,`ű4W~|m(䎗ٱɈ<mg)&)S"&;0Pa%pr*ľ 嗚r9k۟PMҺ.ɑh9M'B}s7ʹƌ4#2- NhNTk8m:Tz uN[z MA-E{B*  ww'MaCFvE[߲i86^+[{Iw}xD_>QK"u]"~`[cr̘2xkY]Dnd E:y>p27ryVF懽[Gk^[8w \r )JDh?LQat!bdU&kc;i6e xXX,\adq/P'9Wf+dmQM 9Q!O|.\<5OwqY5˄G<Ґeߜ{͉78ZK7_+NW]i97WnV Ehuf[X3N+Yx9(֗OM azxTmoH|QrD* $@-rUxU{]'!m{g@h/Bg^yfN[p \Zdܓ0x []C"LuFƵ#7Bg@Sm9j#84p SThDu\f2Ae h λCXB ׳MI#H 4l=r\ R.v66}۵*d)SR}Dr}#+lI4 TFo(mӹJ9TuoiO Oǥ+M8Q@ QUŖk g/!(Go[JNs r]ߡ9~}QγI3U]dgLj'bJ}%+ݏ93'IĞ.@S8_`>b1 WnPdgr[wG G,X=1 Vx|C.Vz6\zq?_%^)xfKM*O YؽH+R`$ԓUmgB@*vz3)d<.<j5}Ÿz3M=%Z󑶎}?  ..Cn:] fG颗BQEz!iHPug$D}{Uuvꉽ=wmJƼ+_nC Q-2T`hG=8b]@O>Z|-`0l0YKnP 䈌~7XE g0du4-ɸ-&3`]ލ3NC~X!CZC}B(F!D>SHCCVy @Us3^NoGkLytYrR(yog'Qkt+ b!W4 w|wօ=u_yY.n) <Л큏sz=Zxӯzӛ UX:ݭ:mZ[%챿 %N~[o"ӧzu,~7CYin7UxԅBwT!873a Pvv)V-^<80f.LF]I3˦ʼ,3X XRWjp2]\M&P肯'|"eZl:+p>@K_K}Ǥ{2.qϳ02hwj|1mO;N ޹uĂ/\/6>ƖH z&t"F{`^ Xi׸}{ᭀEX tGh!Nb rL{y5j<7H PFg.fxCxXC;HZWn(=jz,&Bns8HIcPz`Aj&{f- qV䖓a΋ot!شKS/dx>~hRW}Kx#vqJ8LٕK%=bʻ{ʜ $׸oR;;{y}Dw_{߭7߭Eϩ,BnZ^ׯHxR«;y`7Sx$M+xU]E&j9ٺvVA$Ct!f6m%,+D7GH(3MA ??GdDf^&Ys&7rHˁ%EEũ%`\\\e)qByá"-Nz2 w(VkWXTqI5= %@!S+2Kրj*( l t+ןSM”3=!^(怙0K"K_qnS°KC`}: P#>mGf,xSSpX  !B0!œ``I?~,+csÂd N~k,怼T&|0S>Uv>*'s".OJLΆ$ԜT.$9CKNTK(AN8z Đk0#  Ѧ1)𬀴 "5Yf2莄Pg Ȧ -QPCDqyFfN4q:u% y$1guseJ4vusw^pe̠@ԧiFuq/ZsN )Uu$xN ;O1^4Q=oI4ttS|)@㰌Qv4Kont54RjA`h /ø#O0~ =AqWfg2nbz *W)纇D-,X K_rS*m-9,xyJ}+)gdźq _=et.*YV\m LOOMwOw>,3sΊl^ކ9ﱻlfarE7Jѳ,g,w6isV.9+y*X6WOy&&gMD"ApS.`'7iH1q$NҊYZ"Ġ!8S8% vK✭lBpFڒ1Sl} 'p= I9b,2@ ‚E '5EA{Z'?́{Aψ\}ܽCipvSf%ID"AHaMmlR"eFɅ%m$d1$pzhԿ|io\0aZ?`t_ 'b8j]4]ػѻd?\!"k$#^qR(XuIĖ!gg4"a>g$$!#czv/x:,mvi]v[c I!ͬFl񠞞H, _0'O犐YSyl*L,̰۞E 93%-Ü /M_t<|3;a;밽!Ᏻ^od4^,| ~ R>-% NW~{o2M:-;~^c"T.h<^^}9*FGg!6StQg5(c=$>/Pv{M2x?GA~Tj ^+W^aAĿُqُMُ =e'F{xǞoa~V^-w̺B$KDϒ0Lc`XWX>؇wf3󼣎x$ڽf X<r% d;v<5 gl ^8#Hy?C[!%8Fj/✯ ɜƒqzB:Gт=6T24$' OiSO ǟ:\]+t`K|U@UQ ;qf>L@21Nrv6r09 ;9ao޴wZOi 3] Dkm `܂lW0*.᩠< S' ڬ-=$Ay[7 {<ْF@ ea(_!ݡ݁y~ /E)m |[R#t_3Yüne :0w{,f/ю n;21/>Ɵh:VO$aQN%pP=DRNbp-3Z91;Um9m"|dH7Y}Q 9(5V`4?U?أ!iQ3Юu\G>])qIF(rNȐzA> I(Dc!:]ҶI)"&ZNN{wP?5HS*HtrBQǶԍ麖:`ȍ5BqێDPՑTF vE14(ǭu7P9(zMjv>f%9Ï"GLh} Ðm=]Qs%/ WRw3O4.g"GSqm]jH"4Xˁ0X;Ph볡^̇ .'?Q'.<O ،XG5g&^VWOËI,Grz֬]%Hېe*REe)UNb vi7ueZ_(Cn_)v3[B~$Xe/232ATds/H4~48>&~}6Lީf/z=\8欒1,ś<ړmpp\} S~;`(A_pTT<`L=;wnm>;>\$F@b`mPih۩ .,}[Tl2|bɫ !'Ѹav"kt~vr9zp >r.E[ֵվmc?R{jݍF(~QbuM!B(֬xH%MMK:B[u&p/H>VX9Ŕ2`TFpD$ 4 WFZ0a =YIKQT9d&WחTFOT}rWy 03PR⮀Od@;"y\q*v*)^D1Ҥ#o0!㫯}s##۪rl8lʯLHQp0? #x42ԕ|SwOݍQn`&оLfn2ClL~ B B JzlUÃI![Ly|6;|esP?C\" }&uehںqUJcdS9 iT'D8)4t@߻7qƯia)qWT)9p_Ђg~̮mt5o]! @vݗ˨}kowg4jj>U('<|s*R+ ^ܢjnݩپXmC*Z^fZ.b'p;_j۪8z*j^9*@yVX}+x}G4 I0f [.j`zm1T+)*AJB0qTU)+%B]OXCp=!@7YnD))N_sDr꟯z<9..08>nGK՚75(شQZ: kXf%$*jeHx,m-c͑Y3MBǭ5H?[d}Qﻭrp-q<3g$/{=^s/`=/GTlC1'PXy)m DjZf PT")~{rY@nFPJ< ї!XٓUnnFQ0UjAYIa5C\eΰج0mut `۫ino N}ƥǬPҧm gM@#I'?{ O3uXȹ izl T`%Knʂ% [leF!W}!(̳L(?m-^vmWnMԹt -*b=o,rFE\aS':$UaIH:05v.y2K"Xj4R)+h|ۛ-oa^.߷2,jx -@ FWg&M]Ce5CZC9%7m(u㧹oPwQ+9lEĥ>o\vV!.Kxx|?s'\KnJ( .Pj/:xuA @ Esl z)hw2TH&"ގA7{ $VWĐqFJE4w6VjxȋiD&p%dnqeώ IF3s ]I-0(%_ MǼkV >xN@yIHhbzӃi6.7+̶hEۻˡ'i0R$ =^g4^qŘekI&xDl)$"=6\j!9.iQaUAV۲+7 .ג&!s {ܻ:Ie\`82pÜ8هT !P^L4aL&{Lnߢ3LmzI `EHq2%D 7X)C}@!"4㠃O,=d*tE8*6;0QpjO2zF?-$!1lACLH5nbb\Ӈ)^ueYr6%v97ᡧ|  ޜ4ªʲ=e=XDu>L_B<%6&v1Q8\o!;A;;7ڸ7*Z&ISsxr\}_tU㊯u׋W~zS;ãvexWO8tlQ˶P[P?qU&NcQqP*g߼7vڶ0yg$Ss;fuX[@\ORa ld t KbP>0/!\2b;tp:a"aU8Rn0" H|d[ħMl)1rl4Jw &8ةeϘ.;B*πEŽpdj.! 5r Ǩ ss|CilɲrH&aeJ/th1)'CM-u*JM a 0WE[9*;9VOܧݫ8ZLJTZdbI=A,ٗ)g+j9h-4Fz8F7zFwp[ϵe3X GdljPf S_ڝPV{mкAnAbifػ7Q>c6$]ʆeAj[l.66gMjϙ6 tWdW$emw/r#{09u\c,\=: }an uo 0w-ܱL ~o\8A2>ksSj/&O nB.$|J vgw#8+ IL @`Vp/S=8p8qC`}"`Y~Q(FGEtR]Ф( ( ( VKKVJwզief01/(j8Ǜ}m|zUy ղHl )En!S%0u眻eTP92ޗ SJMZJ [;s4S/c,k41)q#f*\fzpJ1T u0{iw% ^j VB -U*_f9~Ō h3fenҫgЀ58/k~q7W*9v4zsGL"[˳2[{/A myYKPgW?B,"M-INW}[ PԘ[[f lxzOrDsGp}B}ҙy5tql:KC,D?/ |;ĺKpR_ ǽ`2y9K! hQZM8ϯAgN<˘Ztx340031Q(H4Kfx%v-.̫%ŗy7?"`(Z(p%O-X\q]^ڿm+ǚƿ)Oht.ΏO:Hh p<:: Ex}먹(\U5^7?%QtMJ okM^&XYi/"hFDrdC|v),vNˋĝ1p:XK6I Zճ nܘgTw_oQ%a:rZƒMMSgZg 4#CCQ/&I8t2R~ks?7}L+9ruxh6Xw cG b\;IUw|&WMtzkp!8Rh~stk[C{8F2"xe_K0şOqa/]!t *EJfm ͭ0d9i{~79'3/wW P.e%8kt^TCM lխ5JyP7D(LPb 5 fNkeBPpS돰7HrIM{2*G(xiYu=>GH}ȎHl$z}yHQp錓A> W2s% y{]s.^gS %Ύӣ3tɜj8ZoRg*x[ϲeRF`xE'dTQE (hYPr.߳xYioH,Ɉ6,: 1rrI^SÊ! `5 KUuիG]q$q^bTI! &bf&]rE2]m2=_w8<7ſexL+|/rAǾSoD(X's=A3~ E_ܧ1(re= UBe3c⹰cސ]ftD.ULk{{׮TY^edS 9̘B&seT7)f^nD~ t!?E( ޗ0S<5@KD_"KjYM3]l^Hc'-y˔/ZdQ$Hel](U0I(x9T9&H15% 8PI!Zz_ˍkC1RT+aHx9XsTX+*/8S *&J3S ԤU%FTZP k9{cF,.$y̶LH7ƛخI'}Sgq]S?,$NVT/^ |OOxrlfܛ!"̨e?z4K=j$?3깍 k]c5TS>E:RKja-FLOL{C &v#t8 j~yn}{ź<Ƒpa'NƒUhJK6NF!㌇]h8nr^4aɰ:L[xDL{֩;qB:#c^"^t4O[gȉ˸8̜Ii̓q 2!eUSeՃS̪OJ. QW fiY~rI͂W'[4ׄ&+aw;LĬ,pܣv !saVާTty3`.%Hr tSؕ!;M<p*;>x{ D\j.hV .T1xDHEvg Bc21;˔_#dwH Tj)hF (0W˲9Iligvpb(5pGOT}Eq!&BLP) tɸ&h+J-rs=rvBr\q߇b=@KmMzru9OeHAYPU~Kcv ⌘P+\3/Q JJZ~:7˫<^==XE(6֏=x3M[#0M O{@C-ԑG&2@V|6  R%جeu4sH+e*TnjBc")+ZsIO4CȾXƖ>9C\쫺3oC}IIAUiG˥^i]lFPfl;+^<~k!rz3~a?i!fփ}S J_d}Tkl\KT&T/\{ 66sl WnB<.=ˏ ۦ_1 &8j,YRvԃ|!lYy5 @*S|-ƶISUgQP!f7ByJXZh.9*lq#d;KdC ϕ'ᵇ ThL/aҌM7 ~ lnΊ!|+8a u+o@Y \> ^VH>Ot7t*I=Pu(b@|=2m4ooBdkܯZ} o6-`߈}pp[t!KؼMzyRԞFYAH@_U7oQn,.., wGUa_1g@c 9!"-KO"xBe@ۓS^LWGPSoؘS;;FU=T{q3gz8 ^?Ei8Pg.]۰<q~ y5$Y Qu=ټ~rP8}ozɡEW!>3(EYi[["J57\ԇ@ E 7IWD9b$Nco^ M6p cny7V}0{ aVMSŪijO]dvh/Q ~s&bQ%\M8M w_𯱮WsxwS! XLD2M1ko75! ж~}M; N wQEf&[uҞtdW=-- hwA( %5۸ZxTN0=ۯhxܰeXƅ)if@bRB7f:-VTB__ߟ>|r84 k)YH̳ I5} |wDtjw3\c2L4pn&n| O 9I{[6%{x$x]:_ ⒮F%lGkW_ ž(STc[\X+ݦR_ 7DQaSv ͌0pRs _cLU8*V$znH2lmB,_0s5GV<&;.Kke J+4+ ܼ'L7דlHu Ċ(jxmAk0 %5ea0(lXIեRpn0g.'Z|T;:gq'(wM(XUSm1LMH_fKs-"*J(ln?]~벻YA$GRQh61z4}hG%J!p:u˜Vtg-_e9`ړ!{jk0?BxQo0ǟOqҔLeXTJAj@hOVK]B5[|wet^6,7Ue8c>3qB%)P߽e#Fb~|7tգViaZb#,|ak~D'82'~vo;2wpBIƦ .Qz P:Ý!4dJ̬-: )CjwT$M5j7Gխr[(mHvFpaVz,ilR:{C?vf~ۿ,H&JqKQ"b?]4z ]43|A鮪F30Y"6n;M֚XZų_qYr:㐯XOc !wf~>4I&Ms^x=h5Dgu]/UxQo@ ǟO "P({VlFRiK.85Eww@IV!>ǀY1"[a'*3oygc(E/]&~^@/=yΠr]| W׋ϗPg\C|ǔ X=.W"SWe?Y'D:!B7 ow Qp2i ̫ܵgقL"K-`yJWKr´?lZxVYoF~64lIm9E^ƀH 6t uX+kcr]ZV,QG I7A a`.֜Qsd`rcaanQҐXWe`N qu3+.f a""ĵJk|0)!\9!ᙔx`0hrd3Xr&FG .6 K;HE(k"YD*͐%O}>?=a6SgQ^a8W[2a7e?-Y)$񞔈qm@ ֪~BmwW{:32"g͵C\ ʩzx3gJ%С[aEoFwp3yށC˙+dmR FMW$|F1O;1H܈A~%ZFռnWp oMyjuZ>t>tFkW>K2lDiNMtP2D٪]* q"kȮ2j4 nLǃAeQibA]vI%˾~ ڥ(V ꐃ(\&+tIAƵV:dmu~4xK]4_aUrlsj7"x6=k,2Z0 ̟!W_G~ыP+[/*rй|ε_}\䡲vh1rpmN\ġoq-%)Yq2VpY:"Xpܔ$\VYʭ^mM4Exv7|h@:~ourr,h ^V%u[qtL3oWmpt܋  w]aDT?٢Q7kw'Zjl:v\@ v ­ч`<9 5ulɋE?xmON0 =_aa|@v9w5*N$!N^xe{zlc- e,<.Ⴎ#n5@qp: 8jBY+h`*bYsKRS.tL,O+>wbQγL5WicЅ9״?*G%'䋩7N] ',u7ge/ \ \x340031QM,KfX"kěWϹkMyMa?xSMO@Xv%ouxSYo@~ńHa 8$>]Pwfw vJ(}31yH0\,o7_lg"ZQlZڕ1uTEC>aPG߳%L}ؙ |ϓI_j&Rb9 r?7{Z v8;p鸕dQ![W>g&iޥG4T= Ad ?9a8TR=xCJQ)3$t3q }![M grZ^XJ_Q"X--K l<m%0 vL JSQ_VeL < 4p P"T(0:S{D#Xmv9Ҁ?%d+3)x· ^+כ8TEgÕJh..@5tS=dQ6Qa3L`c6[#of-]|E]F!<°-!W04Bhfީ8}'aU4+x?/ۄu&zkZܩZz. {rfT7u8 &F]Vn:hFuضPwt6UX9+հexU]o0}&J<gti[$ %$X 6V:qVs8i\fXs|Odvm %mQBZdW6ߨ}Mbv$h9Jdi21+#\k,kJE>aOě2I| s;ul}Wj7ə]>z (O.9kȅ5P]rL.8XC7dÅCPE@}sVl8 g^C`q(exTk0lR;MfRK7ʺ~(K^\l]ߝ~$l}0H>{wtx&$q|3j%ͯ!|8t(ˮW*Q"!~Bř/t7T'(_g90J(6}Od ' CJVS9p40џ[\3ÓC@DmPݓ.]]IU%2mMIv;%ru//ЩW64D ʃP:>" ,BI6s*akѨB{󀲎iqX%] .EYKM=;=ymOhqs}g!?K3 ČUj>kc4*UFLq%Oyid$[b(̶{&/^RζVj: {60~Ľh>t '=Z:3Ѝ\9B@]s:^=bG>SyhjAb&Ny!S}A,1>rb S?[O?ml܇ I(n*>Vө( J H?I#r(J7ٝ1e XKǴ < 2'ӧIo)+_h|vҭ=_:45)և[cb:i20eO!>ITqc:9c,=iК: sMd%Tz[DVٱ*6U \vs>ȃ].*Kq0qw 5. T/W+me])+e ]ˡ*R.W\,>\v]CLZӲ\9ˊvWb$A*+rH֠ʞv*79d"5).Ó1Qx340031QK,L/JedSgZ9glAC*Դ̜TUu]v^>4 ?G_O?w+E4 xh7a}:\P%EEyz e v3EU6Ϛ'%U_:(+׬zs_d$.BRi[\RTZT<؋%^fpu5Z݊F)E`CN=;.[z|mp@wf$g.8w2EݞKNL*O\μ!5In~RVIeA*P}btN-;d} )5)Z,,pwʢ_w•"8'?d2O>oʉ-1ݏ}2 I9(HS`uC^[4b N?z(.u#A9~?3rXp@e=f]ۢm&H9\{  lMR |q5)Vk馤$f>Dߜ 7Ѫ+[X7@oT $8Smi&bTg b-)s,7`*~ @Ĝly~9h_QuU)$&<[zreeP5O'Cf]<9OTȜ~f߿h n\S*iˤ1Rk}Yf@7h B_ĉ=S(<Ӯh:#x=LB4@}3/;sQ~ȁ?FIXկd `dCᬯaRK3Rs R@hgĖΚpǟTf0pJ[(<fhdS_2YeNf3" 'M6x+OxVmoHQ486t4TC'# I{װxmRUofm"[˼>Vcׂ:U1[LxC$(t}+/ǁx<(>:0!\ oVydW2܁༌d \š/?*TpzNƁzJ2\!`'`!x6$6XXf~0ĤXۥw,$*ij̸ D"O->|Z) |4%\u>D6I09Ex2cAӐDތd"tsgBP" % qDUZc올8G`*Rc*6#OWy#;k0r$XnIkyvC,8Y.J^"}$snj?l|SNJR{aLKJDc;wGrMֱsNOXeCHy6I-hDzw=u*0v $<(~>M=1Muv~:!lzጌÑ6~. l~g{_zX6GjtvDų@˜িmL{vKs X6zhӼZ⸷A~uaGTz^aowӲҫ"Ek°-0eˣ>xZw1YFdJEH8n Vd3S!W&!dN,_:H;?XrVKfԬ2i#gzi`9vml:P۞G\sRmZ*jta9el#ψUH-oVpRljlG;!T-gq"lwP_CV=(ȉPM_CKUۨ qmYRo5/ڷZg:wٻ}g UʨE[/r9D=pݭFp gE8LXxs eٵ" Lr4g&|@a`6 dBwqf~-C1ܨ/"JJ0~X\%$i‚  -.@i__o5UY/'U*w_icjx8 -Wextra74\afdef OPENSSL_SHA1]+H)xeRAn0 |@bl r!h[,"ÿ/]o 9ÙHI@&^JL5sbD! Ǭ9Q6 |i Ă"y؂ZW}mʆDTm?Awt/:ה}ĻAB575딫QodzĦ>c"xcl/1I˅>[p:-ms2բQ(ײc-5aK읅eh<$BUe1XFEms#PЖj&_©;Ɍp4#L(;D%fd}ɪДR3)m 0F<kM\-#ϳG/ix340031QH,"̼ e5TfsdΩ' ! <~S妹ﮛBqbnANn~J[ꔹvg}t0v?i,IAx <]oٗ])=iG c0YlYH"hOi_PI)KQ) Im}y{=s,wZAKg A!TF;9 xfoݬŽQheA9kHOh7NvPL˵fuݺl<$$ 'jYp[F٪4f?G/; 0 /ջݧs|D?[:'"O&=+gwm'D隞_ɳ08_|kHuI{뻃f}^̓4ٹN GChcFPfBI`>I|w"|A!DŽV}.rL ']^-Rw42Z/:9S]w_?V,EZs).k1Q;=v{"gx[]b_%ݯE9E|ӋKL-|1bgo9yS.ISoyɫ剩:)04 Rleʻ9+]0ڰ(h5.g(>sݔM: GuMBV.Y_ "g*~s]w՗ȵx64`Dzus>9S v9%EV_}еjk՛f\Lo296<#zʻM(9;p39.ǴۜB>faۡe#ڳ1=go凸I띿6_6S~Lɞ7鞴^ߗ/Ύ_f<~a mnrb9Mzm/هٮKDt׳ު\LŞrr;fϠ^;)VXj}W`.rbϹrfanhϬ';io&hg&vv +x:1q;a:%;c#wUyoc6}{h|Q*-.rbgl.NeT69S@vd~JL?;V<"g*vV.gQtϋϠ!Po ]:s3;; z?0(D+^:9S'f0Ne17\L%8؁_{Vˈ6sUB9SS.Skl~qѧHʻ?M4o\WBLd,as+f7b?̦Ej<}OɞRjb.=ET 0.J6ψ2N2btK\L?,H$Mts ;șd1n ўȏ}!TiY)>6?Ow~&&ib?̧dgW{.sjS(F޾=^u. M)5 X͒sdcQ}y)Y0?lHߧZhmx[C^9Sr$x/kxU=uDM{3qo̴]C=5s 9|s. !;?7;G#vr7LRc篧{4Cl0o~a#A:79?m}wRfcX<އ5̏[gKP/$]ח;{a84 ulaIWQfb;+|󉛿~?MA3:#q x 0W06\dAl!%v>DӨ .y0" qӣWz[JDzHhy`TWaC_;f޴4t(9GXϴ~ʨi=@+TCv@ihHaOع2=wiQ֧,8ZfsFly_GD֏@oݼlI[Ҿ .HbΟU/I8%ж٪Og[L5P#|29h%hV1-6$ Q?b=VUc2(&Tm2t7 ~0[QPU?ysnzxV}bSqXV׳ɧtc/VL*s5r_qRҰMޢRBu<~sl?C/r ʾEE>ۏ/Ir}lo ȧ}p\u[ .9xrӇna9?s.grbtUȃd<_\}2?l yJh@Zzӓئ寎\Xb ͂Sp # ^;󫹯"tf.z!m9 'Bkv9JNdK^Ζ" S ~q19\k%wD zHެ ?48)04 Do˘lctE26n;1'{sO3`OgJnVIR/0<Ƒa4)+GY\hV%D{s39 lC/Zӯ,B9em39I)#pC}?H8$c텦Qp8bg^ߥc'lŲ8UYL;W*[|Vn{LjQ(pcu@Ҟ -C'>HC0oO[uaUR%<}DN0ʜiЕSwDw K&3Ms'`8&gog[W9MG1m=F}Y v[xNs,Fso @"rN`=3mfa͜uޞ\qK8BSHzE*/X|1TzӐ7v~mx6|xka< ȿ\l'|nmo),4k>2fl:)Y'#u`Aϼ|3~6]j}@vvq+JWWq ӧ(K4C;ٮgNߖ)Q&(~84]N/`ȝmTgSE6}/#rH4FJ9Qri*)zgqR #8r MawJ#Q\> r@:E1` yQ.ps)q%zrE浹Y[l91q;,4ӔtyB5odC:8FMx88:,R_WфǹӜG?@-Vfj2%u]x4#G9L߸Ts9? ~Wm丏<ӌ\T2 Nt9Ϸ"/7ng>?Fa˞ԺkaX1ELM9'өv;_hh2CLت xvBʃHSjޑk\;w'zI?#ğjO͒<6Ͻvڷyfߟ '2o./[iu½?4OOܛG0_٤Qc|[tuOrD* FQz3ϣ͇A$?B pK/}&jJ& M9kʜdvѸ_UvH4qSF^^Xp[X~Ë_+j&l#| ce@CKQ@US8)MlViRV< NvOza"}>'7}]!K0~`D_*JȜFE]SAxuJ O+EUL)ytiYd?7Ci_u8ޖo mm5:[y~'1F(X&iN0| `fOzqt[n9ID)l?$qy]rg?bwxFhtw%X × q|{+I`i}0Oq6vU9x NP jvOڲyZj'T3'ϯ %DZ4 Jg9W]S *?Op|9i.^:&[BГU?Đ"OlqR5]L.y sĹɲۥ2v\ZN f0uj:uϴFzn9'N~6"aLd"}G"s{J^9谯@wbUtL/+J [2 ڋ|"s~Y_*}JC2/؆Ľ7/ HiWE}dAZgGzĄo/̗rd.pr7`*_ҏ24;6\}#|   wsOӅNyT<9ō9uᇷ 2l&qK)_Б3:}pUIRrZˎ^R58V:>u ܣEZ޶v^'UEs7 }KumSq{*[M] 8m G A1G*5N)8,rB3k<`ɢrNݷg<%0HUk'=9)x~|Fȕ#oƛk~x\ę`CgҶ=_5,0;<\o͙>09USK0b:~gr^Uq4P WM=ߞ#'`g;JQ/ ?5.jnT('{g_zbse&^}e;ݨ)RpT{?Cc˓Ow**yNzOra)?g{G#,cS8TǹiZb_ӗ R}9=0<(ָ>nvgs,gf9;_Sm˕?_$l7u]&L>ۺٛ5)YP(5[7Ga_,y𲄌~!Kf_B9s: g50Ηm pwkr<)b(ȵVW|'|y퇆r?7C-> 3AlS-_t^w|5,ׅ.t#Z͡|{q|i7sEZJ:E}N~<&gZa^dmbU ݀fGY;0rq C-JoQEg8. ce ^[cW?yR+!+ܥiTѾFLd.0}I۾ ڗM;2]e zs`  hw]F ԋ+дE cDsj7Cx0^ _lGd Wggz'6ea@6?W8T[Ӻ:8?f+*_;q]~y67 9hj YuqTZ̖'u|6够 6'ik\lcAnγֱs(eb gK,=af9C{s>8r^,@[c1~W0 6~ Y"೮&woG{O?$ CtLe}.Gv7jjE1֨O_z{`*l`W%Cb:4t>qg`U3N=eN-2n8HT*fn+;k{<n%[9$RT ܀,&Jhmڧs+Fq+6GZ j];8`е9bK3ESv ~ |h? )zZ-zxbtSqb&qb3;Yi?V./ا>0-|;Y+tBAecC~f?_]qgpĩ+1;mڿ eGv,ǛR:?"2xt^+?ʫyߐ3ODqٗoj5-pYUQ9;h sȇ},prl#s>}A/D`莆f6{(?=YE By="x,e1 s,1YnӖ'{i_ taI)t2 "yOO_` Oc^%ydz,C9ѩ덻%W!9CEPu@ƜQqd s$1dJyTXc,MhVޞMG+)9o" pGѣ{#-3MZ>2%>NZ&%sBhHI&ƅb)O~! ]tK1e\5 1y ' 9_\^_ 7<PZ-Q{~~QC7z?Jf&'/gZdA~Mq ߬]~8\?r7YlqahlzGx?r/(YyXGcX9D@ΐS_ָz,̾,68/a]FI%.?/&UFsҷH0F`x>؇V{Bmzq51e#c2 Xw„OSg~ r; _`;g.޽(@IJPu&ZyFi̲ ~xTO*pqV<9󮵬6v={VQLP$kݷ MQ0|:@Kz%p1ZJPO3ȉ)z f._P\BE<Pv9S)M_%xkgm"˹Cax,&p3Qa\(u̒cٵ OQr%CƣW#G!0MuTϧz֝+Ťty`.{z\t≬UUouMwL0D9z|/$}= 歀c0r"xŽ|wu_> +JP#]1lr|`EeӑC ;sE ^WqM_40^OdW;m(xIէT G;뺫fλ Mdۀ,ǟ FN vn8?_#̞1}KfZ ϟ1J`ߠb}[ ,ޗ]!ᚉ,Eb߂w\փ=3>W;|^.HYE57@>^je|GLW:8z7Mi}egZ'/*Ia r`D@ws.~p3L 4I](1X,տvX>[:se3sO# Ne0?K8vӑ{nFZ{rvy[/TIׂ 5wT|??c72<{Хַ;3^Ω:睼܏`\X<^b:54-q 䅎=(߯˛xa'>lUQO.\#ŒK.5&e'Glh$6 ۈpS8wcKʮk1:+*^Xeh<2D#a^~IcwՂ_Ij_Sֿ+p~`aSg!x_uZQ"o_r`EU[jh2<.~|BH|9;O#A7tK߹O\Ep'VPI-ϻÏÕW@0rZծ]Q.QaY|2;A{Vfi[Nw tH/{p{=/s߯@12J j S':S-Gn*ftLDQ>+x2AlD;Wp2q^ȨhU,t;VLwE.FChkѶ6mګBx96-1THI?G91 AZ'%O^ bӡI?8@}E5tO]fe0'\ T]a2"%Svy+sOãtٲt7,^8˨N7Km+55dd`=8 )` PNўC#uQ]޽Zu2|)|1?w#j,y@h5,?xWbQYesۋ& ̆'xW'n z| |-$&#UW<^=囪~ sp|`3q;@]¥^\c\u}|V%EhPfҼrbMIJ:}cq@[b* /?Tަ2mxUGy`UA@Ϳ |+-I}y(qT.}E_[݅OC\VuQ,"RRh/5owAG@JIUE/_/l,ȶ94Ϫ& J drTz~yHEG&yz(\$[n"m}[jY:Z^+--Zňt".y*<^ra'GH~QRM&UDO@߷JXX<-eSY~0V~||Qm}k +8ԟFLJ~9CXD\f&ϿcA/ի_0MfO!vVMY8=.sˎ&&r#a Df^2tҕ:BS|ﺏ _'UKDJ _Bú9M[l>xQC0p'| [k(lJoھ+aN*X.PgE'z4G$6r졥!\|bފ!\~XռY? "TLѼ:D,W䫾2;rw;^݁ 7쌞x-X}B]{H{v>7-ɤiAspSۣCj[YgU.?ilndՋsSV9lbjZv̧YbV\ެE wrf |^Ӣ*~.;eyW@.N6O->r~Mʗa.HKadT%P`ۖGݦRV[m~TG3Pw@ܥY|. '5.mUu\ P~wښB@KrEC,{^-]Fw}͟BU<)uxl̴ ]i^] :Ng!q M*&ŏ6ԝf,Nj>H5ȎڙԆ|o T+_j>VvۿѢaj/ϾNX<5R]}@!ʉf#xʞOf,r;OV.X*>'g5³ca@]A> R :Vo2o<:omI5G*_Wh:ed5j2o<xww4Ԫ#F^ *# |0ϻB^r+[ãi_NTsDQ3pm#WNj"\x׏l=MjܖU[>:޻~>Gxǯh5ֶ$ś \c9 Kyώ{zN6_7~۞.[Xm٫+ۺi q;ZmDtPY6?~c=k}3b~f {d3/ziޡ[3=Eǰ7#pnAﶸ1ᙧ[Xj +ho?[nTvA#+.U+@{{|wY&4.|nCӎ&e| Q{ޛ58Sw .fF^'p+ө]8kjkLXRk?x_Րŗezrj׾,iXze{W]KnC^-y&G;ϧ|y"$]D_uMzS3]1̱:dIgM~uh{y~a66ߣ6U9ư09|yN%rҫ -?0;i.;62x'?cϵh-kp+}> ͆9ǫ|?}sxv\O@B+w<gz,N8FXVf_j{.T o3c[f>bBbX Jz޳I ?+A\L+ wG6?"x,Mo>zjF,l+זF_.[፠`8N/zh97^N?tQmy(Reax;u%QW_΃MCu_09zqћ3{P[ݿ`ўꝘgmyz3 ޝ?o,]KԡR,97Rgy~U9$n!n tk;۫9ޑ8~Aq̹g0ä q,)n\y% mOg-Bj\It_nFo%V=_ڬݑ( q='ޅK94k4Vzg㘇&8p~:kD5b 9s|iݿ:Ÿod ЗH3Qyyþ%,S#~~ǜp*<v8#.,)UdCI#"g&8`g( GZ8o9 ~Ac<F~PH.A&+swy̤պ2a1IG.1\<4+/Pd:$8Bo\2D= !fnI{x)pƿ:ۜ_nYL/~/l6q"~!TsDrH聰~)29IdN Kf^7a@@F"@_* {uPm7#/ M02QgCg+Uopּ>cҺD]Q1:q͹ 3J8ew_XŽ3򽢣 'xb~:>kdy7]x$-Ʒ 4?o NnľgƢG FR@n¾6\;$Tvjk <>#)x"n1us]'VWsx?Pì?y8Fb8*`׿-yތt;ue f07X]\pȇi& G# P/_jٙJ>)fɳu'I'N 2p0Lk,`i<[w~"0uPW Pkw?5q cΧ\ہ:'|MWex|H(h(.F8LJ坈.* ,v13 @sE5փNֈ:i[ aȬ:ۊGʝg}ǐҞָTf/2p}[μ2?<:wcU<>.oO4}7r) pU mS/ QrvANj0rv><=ʧuI"|yn4kϴ D.o 1Tv]?F5?ϬjǵB,9D‚NS ymW>b͂As.} ́Of~hz9O$+hX9w|Zx~qB?2XY h$9#ED6R=*M/'$՚~ l#d'gtpe!yMƍ4oD.Um`/R^p8gY@Vd,;>!yv.<,dIM5[#/?g)sZi ?tvƍ۲^Va-Uwdn%u驪Hß;-h=c)s 4 ݏU*''x[ͭϊė\cʼn+c2~I f @Un9qOnϿ_{@*#kΔn])ﶷ>,yyoһ8b+CPVq Bra*YlUi} ?eu\R<(2]%${r/}yM ]>g]D=m>^{Q֝'7Cބ49'sG`Gn]e>v[by'ѵ8#C=;Ar8!, wTS gcJB_󧛮/3̫Y8 X""%0P%g2{=KHqCp6";_$K}yBrՕL,:߸(R㓂qRy5ǛuYeJ"q#; ?\>ՕI9ȧ>3:HzjbP[O7\t+[taN%[XrCx?fO5 1|V&y0p07@\)JjYQ%g`1鰂_7/{=ux=/!^kY2+c_ ⸼S/vrkrj]Mnˊ0r` bn^湧u~Jd/_ٿYq͸=8zc{;;R|*7 o, O(gDvҀ;o6}c^0WG~ u +V??-*<Nh9oM ^_;IJ[rd0..'rukf Vy&>d{ ~sہ!wXN@T׬AoU_\;ۭzc8X6NڱٟY~5g)>B|۷Z9u<c>2OX|PNVV`|U<:R})8X>>ok[OcW 4]13xYqbO1tfhp08>nSYJE,:nJl?I#|P ,o3D%(mJ9Y~.]<`?vάF$}x痪,B5C8A7?wed1h`iX|r7c!J,is}'ָNpG45Jsn6^_Q[ k\9?JY%CiOWA_U+/ >x1]z XuC*c݆07GO\P?hR  Su~Bc1ϐܱ"&c|Y?0_4r]׽&)ɆCgXv kQE"Bj9 7]n-o1x$-־(#AvL= ["E"Q.-k +䩛?pL%~+e:P/^DOR%YMu%ܞU-W|ewdu?N?'4fPcĢْ>*'OW ?<;>^US G7_ L.5HÄY3 >a?_yQLǫ=훿J%OR,.={gTz/[i> I˒/Qn1هOrgKeJU+= `I0s~.5[Vd&d% S^} R0<5cJ]ơ-![\ JYy8 C>9wؿN.ߛ:a {sPY! J,6? 鉎KA#<"iD{]fƹ3AZ_;fTɤ;[ U ]Z9e׽v/KdT9kj;n4ÕX;(\wY~Rp0<.Du]A[V;IWK,3j#)@5<{QfxF7^!VGA (to)"4Z䛟\ _@=c>5jw3骻*zhˏ0ƒbQwX8 1?@Bybc83Xotn $cLHu/*Rfb܇ ZySJh̒Uz?⯷kPa1.|+PftbꕟE<8;:䄶)ֽVGx4m~rzè꽍fbڏ(: JVgU-&oGl_pNP}w>ɐ_i8AP:y)ezVryn8ݧ I pxܼ%&effk\;A1@R?뒋q-|7A qӑ;-Mgl^X ~o1>>r,y}d8O 88[| ߖyG.!$!.0Pw\O'wݼoϟ6SFefTƱs'QPFIsZŸYд_omVzƝ&T./'t $7eha@b76;nr 2;w.Po6$K؝[gW{[q!H;Q0 ;"K^r `Y64ռ*F# !iawUmCy?p32|WuH-ht1E.%r]9?;G"z]g} i=7rb(qe\@}EӤ}U\DTɟ5[.a(1L ޥ{P&>Эt0y RPOyհ|ND|7$7Y,rjY'8O_Ɲ-qj=]\ď&U ip೾|7"1Y [;C0^=I?!%I͇uMhX)j[yWl }j?=`05byRrP&ǁ9Mߑ^x/59|An{gx!Dpv9#Sq():޹`냡aFEp:'|Es\vs$,ϿFI\;qٹƿT 2輼vw_\ݙ¼w%\@hh<]љs#bI>#5QΠPֵ:%$nA$?q`N@vtQDLM^eFn&n[wfUmۄ}{ڽݏG8ŏ?~-?':=h|vwNGWewe8(|Sw_WXH\O-|➜2#FŴ%˽D^V`ZD;;s}f;eVk^h_=SɸIq ^òu uפyΗOzl{q!oS'pooTV.ѫ߿ij+0fϛF@w3sxIO>s{ʹ3.(\v\Z ]n&]6ϴ7oH<< Fy:廥}kXHu;Z d?kAƄgRP #ߏpOeDy$/ڇx5FN=G"Ki1n@⒎IxXJqV58^zsݙ}"*Csp|EDz<Q9Tc [ 5ЁSd$ \~2G *DC^&Ͻܷ!lD!ea W>cCEk^؄%\)÷?byC%E}G6VE&o<%aPpVŢoуJV!-Ih .R\88Gi>H\ [c*fճp|>'1~{or| gQ^g,cq獬vZw }\Hgg||yk|؛K­L7\ q|ˣB8{øuyuY֍94˞Rr9ߌbUnL&9I\/~slʓlސ;لc;֗q2+QdcƮ*š%k sLy$AWbݿ@Tu'moij anMO+?>OTuG_b<>5wQ:w%W鴙qb9wU:w%mo‰X!h&>;cQ-^"_*S+J=l r˄WRC]/Юzky얩XZGKY?|~|]j(i]xZOs.)5 5hO}7>)yg[u?H9sݻ"sL!ƻÏd<'g!5'YZ=s7v* diwAJ6lQ3vĊ\pt8ރB|q.!$ׄ[Bmm'45~OgkEF7D_w(:asNt^G[q\ 4=n!/Xm͒N5& F8@l# bzkJ(k|}aoL=k}7gL?\f ['v2&4#4M̬aEfH/}}I9|YOR\fvw[Q/zR:v BPȤ'i5ɎT?7aeu/x-ky Y;:td7c봽!fbpgdp~m>\e^)M3NΚt*p^M]`a]HӬzs϶Z=X릛ƩI|I*[~ש/lkv IxBJA}AظDvԦlKi\bO?%>ׄ}Ϸjb{rMTT CsSפZ4o!1BCx5=azJ0f;\wb&I828P[/R*Җ%qt|xǮ8Pa)26xԾo9:.m ;<) _a}ܰx;`¯sEHjCƕZ1? ,<`g9Uvσ_<:( k |f> ma\wskpCLvvuJ}p>񦲽at.tѕK?@\^<\nߢ ˚áC-E77ahf8X~Unhj; ̣Gxdbp@yyl[,"n&GJ?Mdqx`>yyJM7R}KMrع/G^. p~&a^K8v|YS|YgׅY$!-[覌Yˡ) ,89 9CŶe|zT$!7YǑo5L7″LP7|DMa]Wj9BotK,Iui\B\}'p.®}(#Nui16[.;ϷAķ":L ' o[Ey+'nxKC魼 }>&` se-'k0< W 7>xf:ʛhһ27fh/ ^%.9aPRܻqʁ^ނӴ Z ?:${ ȐJ_gf#-?3n5Ї2pG ;1Uq4v'g@s~ޒ:q?W9o'ŅbXdܷM=óy2[Ly@>t$OGc.-]],+zހRI_п@ܐ[+s*nyBSWs;M@Ӟztv-~E VW5ZnwQ__OSZ:I>ϻ>~ <ߙr %ܽ/7>dGm6'Џ W Yuϥ vCXPk? jI~T! ͟UmX]#@UHǪ#;F5Wz|_R@{kP~tLL7v>0zSxtnY?Y5kX f'1弬kQ|0зu"o8Oc応<ρ2< /̆7vȼCKTs|6!HH0I.dME=V,dkX<\r Âq:jrז/oFnVߟ>>CWIj4t4AnJ?bWǒ8XUYPHߛuqu&gx@jٙvl],, dVHUuSiJPpS?6_Q SM㔧DV?p8HLɣ~(]@x s]BA՚zOh3^YYAɣ:>|0:Åz+"VGQ7c #| h?co.2-rh#;:ȅ!?-/ٷ0"eeW8d(@~2eFy.ClDǗ+m?>T6=[@ 62Eyߋ~eG卝{s,z<RjH Xp' &EcI/_}Z`q|<ć X|oѸ7FuLW#ۖ5 ~XEE[gLd~m`C,fv`RL< MEx/,z 4[tL_tѸ G8vގ_?i XߦUrԲ\G Y3ַhu㟮 jVy4 7(?L*~'-U|1t6vMg3:BBDh_|c}4 J;]SZKvk1*Vt~ B;9y:S`JS'΋+6\/x:o{qZDaS/ǜiZvY#ߙn;ګvx<,f_:GRr41e/*%T#F( oV pұ,qEu5~2WGfp8lZ?ݪkaqZ qs1rpQ894qA!^72qmrHC;QHJa WNm~c1<_nh ˺gT)$笣PrQ<#:ބsC/ɖ#t*$A`8qd×+IpD\ oGLX dXW6v;7o#1|B@>u=Qy]QS-perX ~>g.#K~E|vaK"/?_&7 T*ނ Nh#hc^k[R}W .L08OQG_Ryc|vڏ}ZS<_ X)jj-U^fG^5\e{TTM,ir.b;cƞ޹'Pr]2>W#}Rxǡg#s?3Tf=oSFE[pA"!tuԹǀvJۡk}Ъ[dž'w3#80a71E>gcWf2WA$`]ZX#%|F3c(ۗT;hdJ.WzФ\w(DzFz\:SYzK[٘Y&L彾= _qA'y/Iᾧ7o_/Y8z?W(qN)>X %a:qI^ kɑ񠈷/Bup i8;ӽ:[$js8(Eҗ;~(hTJ>)q-Jm׋ b\j#{Ex>!ōh  9K!ڱ"~>qv!DN.݋o?Ʀ9:Ey|h9%ȹH9| <Q1 `pS\UtDDH`V61E%~v?Kg 7V9փ)+({pʞ!/} AXʧil80y8Ex4<` W3T`sS@FK=2[]ZN0KĈLq`f;:9\J>mjzŹ̽ŴC+| O@WRۿ]W\5T9-RG(3RG-g/R)F?ПS^"}[TG,^{t$|yJ>1 ":[=ڛ/|^x>֋γ[rhXt웍oQtw>xE*q8{8SmK:9Aj%]#"O3x>%cRvpMGц "іm_'_>Aĭ9V+_rYp_)S0|kOm廓cf&abd$CgKW??¿3F.ˠ* oe!)%|&5A)Iikd[E ;5Gs/lu~a/''B"Є.o%0>yf .q5aS\(*` vtJ^BDu &Eae^f֯W}r+1~ Œ*K#p}G8,-![,lG^Ug oO;_~֝q`48+l% 8^ sIa_& :ӟFsW%`3o(Jb{8}0NE2 ۾J1z6Ml9r?*ʹwP;5[[RX,ّQut4[F#|M3 k P}6qPg{/Rwސ^tek; ?$E>09=fܮdQ;m}(PΎ.ѰxVDý SLlE> ,ǎo~e-6tUE-DS$q8 ^~1֫w9dPpK~'+sF .pc/>CU3-c^啉|!Wڹ[NM2i}S?/o4Nz*fnO\sryTy0@Z.RS˟m~NĨ p@3iWzD_tN..,meV]y~n3uqwJ. -dS!'`:.pu-qk/US}ӥFѫճ1B+;?Y3.kwE\UD?# -6cQϧwў;cq:< |޹`*gv {Z &L*6`[堼{ez<浵o2wh ۗ8V'r. Z^PGnH 9꼼`Mm.w]l /%E?71T.j6]#dgC{ƒWJ6 z~S}- 7|;0;Ֆ#qb =Z,7Egn$s1DB3tQrU{r[^{KI:آxn}|C< }6̥!p_]Ɩp(Y~mXw4P ĉg7W* 4W߉tg}LVPΉ=_ͥ "{]CQWmֵ"KMWzى?oZ٬ZniwnW(Ώa/΅<Ff'*:i^:v-;\ g<UK^9(/*X^(D ċ n}@;?+}4I^[BۥJ >e,ڤg*x=ٜ$.4"8In?`w*+O7s%۟<!p򏟖>>u{UDעNҸƐǟ#;@]vR&KUoIz |_c:0)OZȣy#W5+V\}z[MHjH_ Џ,tգlP4#Y:nՃ7QA]ו YD9L%1́p1m( O:iO~uMgk"n4v,/+I~k"ah=<&Ώ̗#|j`Jٲ,~QGh$SGz\N导}7]ת@ OwsmFAhE0^hl9ѐg@u- ~ ,'ln?A(,XRrgIwdRnxO}vŽ)<7!ϖIEЯtwo ݛ]"Ht \5 SPQ[JWF#BC?u ˪t|4=28 @"FCQ Ck EN;,d|i77 ]>6}+}B#ꌡ % <s[2_.]ZsQќP(oKE_6۞x*(eҮH xoѯ7$ţ AX}RFܭ/DȓHkww*˝"zҔ )5Շ2l_P $y A ]vh=7f.%s(V`P񦎞]kl2iɡ_Fukcrߕ;0;$G'@!P@ȫ%*vљ~TmZ&\~7b I㿆6~RԵRr Mw+@qUqRٗ@khO:P Ge,qmS?JMK@oAٮ_ߓl)MGT (_ܮ&MWPzI]C~43f{W߯yBYhNn /~n wa/hǝ^lC84x ]|eyqުV0 9: g^K.Ӥ^b;ġS^gC'g=ΆirkoqOyGеScűm-{7c0!O n@e+)xm]$.Ҿ8t>8O{q@BS'$&/Zu77^[7M%fuH#\l.#:t&m2E|:1eSg22Dǂ g]^ɟ|{S1~r".XorAXt@ȯ/R晿 rp"#P~bRODRO;_.9rR )Yk=j=+!8OqG:# YmvyyI W%1 ?HMl 3?R.'#o!% 9)uEϲ5|3cxeSY]¿g Q2%=WW^2(ܕy΁IP.6[w[WDх> 焎\)rKp~aKg h!(22TX^{!{pӓ oOU>PaDG2CC?c48BSN MoB)pXP&ӏt@KXGz:,z/C˪,]8̒ض1 u{OԇaUZrsjm;ŏn4S #GF|17M2? ȷ&?~ȷ3'?nʮs{/Q>5{ReJ,2Uen(-j-wHf#q o@oc!zqi!w^`}CMοC}Z:p=OkP0pDG-|[E1#7_ѷYF Z!vmܭү@ 6.mS Z 2_}K;*>'!l_y%B?[~~z^'Ca1[)S 8"ON)B`<[? iW*JP+<}2Ӻ-_yݑ o:=AGA(?DܳWAjBvmrc@]"% |>X> lҥJ GCGC~G5+U_;jn_3?&\] oʸ˸ ģf%|CpwD哛>8P爮9o$Ezm/2)==\~wD7mƬ.^JɆr~GԳ4@#m/=MuII7*?_&Ist(a$dp%1}Z&rGw֫N '%> @Ux0 R.xj`O,DPC5>=SSeR&FJE@66Ŋqt+^aLkX'.H[tezZC-ˊ ҃xppgxsWAL_9u4#_ܖ1W3& ^^wlOZ&n [.cGj"uIVv a\&@q947@=_3 6vor{-rY: s`H.媱Uwk P1KΊ gJMR13),p]A=Qo?nx}O@Uy7ԮX902Avܸ. Z;kƇHX x@:U =(J/1r_M|W[Q@~k ӗf6'W5i{m4 *P-ԏX,َgdDuV4 0{$%w%$tPӧEj^-4ea]:^BUD{y=\]\o_J.Ëe&wg] mY~z*5! 3th@.I w*UPi%'_Kbq^c۟_Ħdho"GĪPHA+3hLaΧ'>3!OOJ} K.{)қۿX'0/ ,^l[xN4kHf |CR_ۖ|[OnhV7iW?@~I+yCɢR'ε>4$G` P Z{yQ6G^t#FEf ;!p|Lbg>eFn[}9PSb 2W_;JIQV}hz9buL/[_Ywpˏj):a#.g:.{E |*U(|AXQ,޹X77y] ;^~fK՛nid_bҟf%^7 / t+t9 ~9`5jzpw`ژpҳ!g_L"ƕ1X,=%G 6cu E/=Mjg,yyȗs|}Lpeژr`zf9ɞq$@}7"."mOSL' v3K?._"\_lZie=^`vJzyۖdv<::wPxݙLLd}/pFn2 ȯB[8{ Tlš6#1y>MI׺_뗩\[O`| EY%Sx@>}ƽ{cLl=.:^ȲabK"~\AN _|R3ZuԆKep>}?T`>;N$\r[z=3X> ^IR;z"LL8D$Ci/'Q:3HGi3+Xw H[HQ GA[S ;T\¹#N۬QHZFx|+r/2.2q "ԅ"Tyu:-Q2M}ci<t$F1nbt=y`97Z 0}) tR>U|Zͯv)" %d^2D^S32fA^yȼgO̢g;x_V9<d^n?~9뙚 1p.^p/Q1*Tnʠ,΃y~!>h'SWDs\@3u1r\,;~D݃Sp= / whiD'on$(~b$Fs%qcxh+毗x}jֿ$<Ã@uo<,ƓGuSX*\l̄$=ݪvjtY\纽%FKeT<\"JHzsRW¶w$X$)#z7 Ӯv W,eLTR0SE'1MKyoi)Xg^:ί>~JʞO(?ArUu,~߰:©c URww90w`A!-~< 4ʬV&ȁb=SE'!sQ RrܙT{`.P_*SxHk g|G~)a_Lc_^9 'V0'o<\i݇}ĽuC+'5a^Ur h?q!`o@LcɎzOpLt#J.Gu=t=\f)8nH 7 {lÔ\.ϡn>'2܋9aA(*ԥἩ@Ɨxw(8UƓ9Dcpb6@ĪfLev9yTOCO NJP'+:<[_l#6$_&}m' ץHok€!&ty3O3-j `ߝޕ ;)O\?+O%VO?Py϶!6l]'}~lsx'֋AT`J?>a]T"t:Ix']kzR" ~Pghowi:@C\vڿ#O6R'Y"fB7hq!`qq6c*Z\nBz""\ϗt77,'}2ksڏVmxJC eVT7|ZRR9$eu!:SK^+P@G}i*k_W3l|)@jO \wөq.+8VXxU+}c*D'I.}}pV[^!T Ixޗ >){o"aarBv`C {v ޮ]W>A.?eRWxi"o$ΓQ{OSVZj?%pmqqز[\m#{d?ۤ"ȷM/ރ[u֗$hq4y@mz\[22!Q[ן6I|IC-/-tآb9,ȳMfMhD;6\.|Pҝ)#}/r~!\0߶ȪP\g|lDXEmE',o]0GΉQǃ9,=-Ta'~OQ+ltNonO_,P>kD΋NCe<(֓,%ziQMW!˛Q>DvP}0ֲd;Ih-`3U.)%%ʖ|dI XpgO9>9r^qXx.yg.Lݛ:{T5[c#Uʴ.?9d9h\Zԃ9B.D>=I1}̩G *.q3;T^9PvL 7 %{G|A=x[%g`MkJq  AQY7,~x!>~{уy҃@=UR+SZT31)` X=qw`f(| O?zEw ͊؍GA=X|IÞ_6ݻK6]6!p֗@m~O3V/ +^rFetq ϠsE3)&꒪ƱKg6xnO24j~0Fb<'9zҦKbr4Ycy&E'H4#e):E7rhh{Q^a:;,:S84Px$4ET̒Wh#{l(~<ý1EM Ι[-.-qe*P3ɹy7q⩇FԻƬ5n~}K;tOJH V Z@=k~j`Ԭ&mnKGYcw;FUe V]W:= TNk>q#t[oy^*N酋@b>fQx::R\^} U+ԥl8kKg/^]. (r2NT u@ijar:o*=Ixy,|9Ԙ[6hF3k(*T9?4Ojl XS?Ϻp ם'1GM[lRvú: Yv;S=ԛ~>'1j ǃZ Oi+qx41~=j Nj.k maǸi+4~:JaBɟcx|y[}7"O<{o~|x?·+$]pg;~ ̓~R|'|eUTɊ >* OS?B4xxS(tyG2xj''}‘S^5jN*4`xoqUh<>tw_r=b%{ \~8y-{B;@:pv\]˚wl|ja*CLDH4v\b¯  V/iP>Ì5^BM%7neSQ-P~| ,f} c}h$mxvD<0ۡzaRSsDx u$ uT3tBzw#^Hg6'SuOH_Ǘ}>4Hv\K>+-ӕU|F7[i'6#';ƝUSJB{VW:; /b':)J%o&kˈ/~nu&z@@O/ YzS[ҢGV2z(\Macnd0]i{K[nfBAp7 WZ,>R`HB^)N_'!}8  }uiwόL;yHW>H+tvDB른mҥmeCO*%r&|' گHwM{ֻ2ӗ5.w|ryQ.'&p:7* }j6^CQPux21q=iD:;>+?|ۗCgтGwZoRAꐘܘ`:z{r"8*}$d}OChAG=Ž+PrKǶW^>Z' be5#Sjz3F'.p@ 8IRY%?,=f`?^0 coÀ_"i+ ~f|zp z%>YΘDm+ӡ}ɵ6 ]gQԛo /H#/gYrhh8H\pO;W*ibt;f2GXK Ebٛ|w>?0CQԯ8=it`_Ov^!?+W#^J[y.̽tHy{pӀ\P0:8)zŢʥ/s6&c\_;`S݇zd̪:H Lh|ynKsu 3H\b5ϰ';ךxKK|)<@pSn"g^uL|=G$ ~)l/TLe䊒6={l_o|)lC'{qZOAxqDk-z6s;/>"Ma[=2y vOtʲ?'N~Dʺ9"O05Ѓdp @iGYb<~_x>5o^.4o/J;@⌛y#Oei9#u .-yEv\ALN1%)>"uӉ"E*E/=䭐RA"2A +,ukݖw\# j?p/VUzڣڠooCLiOWE:KjgӉC4>NcO)䰼K7Gp=yO iИK s/6;Winas|HfN? dRs;|R+>Y6?n$ iE Np<'ӌL鞳2\[FϴMO8~`] +.W,I~NnL=m2'dP($nQ-4;7rTx!qZSSĮBRjd?h']%ozGYV,If3“/y@V2gI̭ $˨KmY?f?ArQ?z6߉5L> o?gpN(F|%SEV^K(TL&@Lsx:+}Qq1e|\46BdoM r~:&o]$ ×P8?’اE=+lK_vD̒#>CNP}=0ahjb4-[b܇ϥ> L]**^ =macexofV[%Cɞa߲[tىU\ 0faw#'̣f.@X5G_Dc{C:,'^$ȚA`$}AAs}Ed1GHAy'Өh<@ɓ?ՙ[u(qHnpKہsլ}{0K,\t@k'ovzOa^~3Lh뼁 LTr -i]UmW ɝiA?yXoTosS:wT}ҭ_s 7gd2#s} ;-xz*9aN^9u\AօYttC|kc3\{3-p1ԫ[bxFWYY|B+ys$'t8x*y} BRT'HmᏦjOj^ޔG#y?)M}Óݓ5Jg~72jZ-͒ShdrD}~DȖkKk+ާׄYᾬC2|9s+ƅzG !wZ>;F;h@"ɋ%h`Au@(Պ})H?;䋶,5PoAJ35ٟ kz|[Ǵ XvgBlW$P\T+3]3sBz+ bu( .п`ZN3^.wF%we3.п.킰O\ڥCǵz@TӪ 2Pz{N˃aVy#TIX 'E60N _3ǹWN}+* rzSBP 8|2l[&mNS%.xF=D`~u6A}U }x_gp9znl84/^+ղoH "-t np H7<"ih+ɲSq5cxF88qQUdGWt`3%B~l:(Gv7}wxک k\E3ϭWw\=oj 77mC+OAҥ/J;X{>ؗmJ0g9.#]āuX=Pӣ_||eVEu!hlH>t\עȢ➓J%Y-z6FaKͼo[O5L<DM{>D'<ӵ`<yDVd y42y/S܏l2Fԡi`qڮy/I'|o퍃-]tckQ*Su$"ỷOdži.2$/O@/3Lkam? M}o} #]vw߬qV-uʫ?7~+u$iɷ/,:N`?<|w-FW"+uh툝gcꛉe 4S|x@_UYgߛվ]?9ZO%ڂk߉2%P #.K`Ǔ[ߚ@ tW8yͭ /O熷O葵=OjϹ^k:u4&ɓڣr|tͻMU0BȵlN/^ϴU{wt7-,Nr+~psS pzCg%~2Gd;3[ qeۦx\*']qujt w1!HƙHfh̓S/1ϒ"Mv/ՏŃϙxuՄ} Z>Qa7 8sOe^p!A*'C˶Z\G ')@*aA+rzYIbs?I8I~X3 83<_r)@(b}J 4Ɏq~Qj#{U!?F6_VY/FjSP¡I_ j/4.x{r7-QI^~/>鯏hrO! ߃}Ns:®F6\ʎi8{IiT"oz[XSʭ?w2C_?O,cWں6٪w ϗJxΧn8b? ?GuEnDh qSUs PqiJOc?zJ112S-ʡ۽?:mL,ecUnݙ-y潯uWL^ 18ϙA7ߎu_ |nAXR}V#gW$3p6 Yyŗ]i2o[b ]۲]Np6-3295j{2/'x`iЯ8} BZ;>_^&0 aNM;Bx{w L[|}hV`'#> y{1 n|\1~<{nv -\QA~F!C;[^) "IhrkW݂R:r}‡z~g֩d~ /$iJ)L,Iro+X_-iSĩY߽haJ"z E0rnxQwdx9ZߪZRZ*m[Oz"Q=j1j-Lȋ6N!b-sk۾LF$l\aZYeemʦ$F[xR wcDҙ k>~SyDt)^#Ӈb~ӈcsG£7(KW7H vxg+L?4(0JfC\pC/,˶UL @jL,lxWn7Q*Bu4~?H }\[VYH}_[1.}R?Ь`Kg~Fյl6)PE:2^<);]>JTY#U~)tM$nHg E~SoygmRڵT#fbG_y?\7m~rctxZ;>>8Zutu>aXy:GcٟdK" @xoڜnOɫɒ7;Dr %t8D)Tox'Ar׈. D) -}e_m+G H1t(~Ok$ۯ6('7EyiňdL@T#~D/T,%/N1&8#1 9ٷ;^87~NG` !jW('l,#UCxZ( !o;xLjٕDIhOb /`Nо4{ N*j[@G l٧Z Ԛ%M2$^`LZ2K>F̝]i-MF|H dnWcvƻEmjvv?Ϥ)7L>H\V_n8AjWu-8sVM%H"`z&i,Gk<-:3g%@MS#?ѭzEYƟE=P̠@ 5"9u@8^ xxf2`Ml䢠?mK {fբӏBcxy\L{Oie*-k9g:t-Kd 6jI nY.VBEe.B"⊬yDqDt[34sb~}r~'O| s+жZ?/c,Mܷl`JƒZico:nh15?QuofOnal1g0s] SE_zxyfKg?N=Efh1>S|}my][w!-߯~ӸwL/9[967Oz=Έhf5`2 f29Dc-<yd(T.I̕ ]VS`&8 w:; ܯ REDme o/?墸@wpbW* 5dm^_u󭆜ZcDvuv@>\iCܝMeG΄AfT6¦Ox@C4^^ :ù~jO.v[Ѥ M/o6XY$/bN6kfRţi! L U;̓^${>];F q Nٗ \ռڂ7NW_Y}E'˺];]vy,t}\91K!i+O;wO-yR}`όiI"g;oT1 uOœ2l̗Ӿ<3΋ٛv=rwk1TC c(u6rh A-Yԋ?p34x206ϼGAɧlцo'T_Q늊.& ^=`gxȝ!̒x z,2yd[$\܃]ƧzEfjw~eߌ:Z,k0~S[7]6vZu銛X9A;/ Nuq ނVC әHFUAӼs}* 2|WVy.C ^W^sm-XD7"}*,2/yz>Pi+\ռUr^m}AE'xW6ʮX`8 藖GZ|6n zPu? i^pxì\[YckoUsy.$ _{k^i3-v9zy/WD-Jzs=_8\MkO/O/ ^ -NW 10]Y%ܪSb??d*Kڼ>6=~az;58,8ujgі9yy;p?d |Hl~A{dz|ݺd|.?s!!u>}&J/jB}!*hqznΛg9׆jnk :2x2:Jlu]M:_zEGgtr~.gq]P겳S$/?Qtۑ7O{bxB2>ioCuiةMHS96RM^n|a |}-٥ΗPYLk15+2ǯYw>InGca\yϕ‹͉6s7[z^Yޒۅ.?ΗhY(,n}nM]ýƷÀsf&]'vT[;7ĝԷiU}nw3FݺOѴ-0zxżc񀋍iO߹[}_VJ6R)Ҽûͻrl͈Yvwм-Y 5H/ϏF g;xR. 5y>'/ fp-ui.w]g%^o6jAHa.Ϗ5;"BEGu5m m犅Uv[{nZ|W鍯:sO-r00`΅ý͵Jr]0Fe@.!{vҰW vh}^uڦMsZt6.cKi#NxX/UtZ`eޢ#%񦎴5Ie5ׇ\6N/.NyKGKZɅU\ >7q?'MV,^4)@6XuncdHVksɡ?,teq_s{zg;WunI'JqA1?.ԴO$" LIa A ZkkخCr ~խ"ι @ŜIQI0% LSHүOalS+rhaۇϼ[DAHH.4CR b UimdI !0<{n9?X@gm4ڢGI0hB0@ tq\U0CocVaovЭ/&XBK0\uesedHo+Sr9}H%qIDD$R &pIaİDB b!<}K,_&uuYG[GA(#e RK1g(t(mnvS7ڤGasŎdpr!0f.,0Ҙ!&vi%}oyjTn}@)1(L4 'cG! q eD2(PP*&qT#7@DlH+y#Ń' jϼ0xu=p-Fp60c1+}, Lڹt}2'yrWtp뇐i.!@!׍$$Q(UƴI˨Jywd~x{N2`տjι׃wqv Xïcjڟ/Uh\FTsP+S&$v`ɨne(7+IJ9I&r§(نN?ܯ?'.{}?1lz/ zdnɅ5}}~>r{LKO 5DyccAܲ5s VY埿q,FSf[N=S+W˳ݟ:|;^okXTd'w{\庯|u^MvU/}δ9-eQWU7=JӾH(+8c~v@PպuT2NJ3\ϓ&H_'vk3dxe3\Xwh4"}C+"\o:$_軾mxY"x31CcƝJN9oPrY<.,rvٓuF6qorQ "ib0yjOq7Ƭv5V*ȐiScDsy! 4Mb|^`Ղ&|mg}K~"inʠUe 뷖{m2Y|5"iapV?w]/*i؃ ;ۧ{:}/"i sqwo"hЮu7n۫fy.5q+C%.iNX؛ªsLυUJZ0h0)f2<SG ]ɤT:kK} U,o"lPzy .Zˑ+ny"jƐ%W3aɴs.oPJH1DIbCLi+MC%?~q˅۵wesJ0^`nqϮϪ#P"Y aCOOEo_m!ڢx340031Q0M323ILK27M45K4MJM67121NJL263OJ4IN4`8w[KDo'~Qx`>u? 'L .Lܤx340031Q040670L45I4LM2MKL21013H4N425H21166M1g0_$߲=H}9]!̄4SD33SC cTs43K# ) 5rmTG4T,x` 50K401006 (*-X*wʦjϝ긢.fB ܯ^xwx+)JMU044b040031QrutueXlmmAṃJ}G;UTWRQຳyv;slzC8Ti^j9XrѶ_,ٟ#4'^A0u.n9)x340031QH0NJ56K27N60HILNJN27KNJ0HK6OJ205gYrm٪_s-x`>u? ĉ'L Hx340031Q020J261KJ2HK2HI2OMK3NNKKM2N67HJLJJ1201e vObI<*/{ x_xQ 0D)6ͦ "xO-FbEo0 Ǥ,ske[Pn8R,EpD?g}^3 <GhYK8ЖDA);gݧjp4-r;sGA4ۺ=(in7IKFESNx340031Q0M202MLK2H2I44&F&fIi@e ?zY_N&_~q s xax 1ENi@k2 "X$YW0YcÅszMD08!s Xgd::@X0Pw"F/RUzmZZV}|/o5I!1z:vUim}/> F-GԢx340031Q005OI1144I57INN4L175H1HLM5431O40NN23Hdk_ 䬛׭Lk;yxwx+)JMU044b040031Qrutuen~{T}ǝ6^r"(1/9#>-3'Uug>6wٞOpҼr_ʧ+O\\iy|tI/8x340031Q0L40H606L33LM1HL2MK03NLM464161IaПg;)`*V3#/9/xRx+)JMU0d040031QrutueXlmmAṃJ}G;UZWRQ°\erw soT%Ԣx340031Q4307L6L21K05I2640MM4771NJ5K2L-b fx5uۦ0NJMfx~x 1Nۀn` V.`.pa Ô{StlH,_9$$cf&hXQ*g)cV~p~"Q@JnZuӶL 6̸u=-x340031QH17HH343O60HINMM04066HK03HM55KdX>M9jƙ?V<<j9 x_x[ 0E*fդ "W0-Ft݁pS[Yx^ Db CLhut}8X*4ZsYUA X3RM) s6輢Mរ&Jm;}<\@ޏpĀv?jۺL?HANТx340031QH4OIN0MN3307I017L3IKI12L3541505Jc6m9GUTn> x7x;j1Dmdǎ|M3`V{ >QvL0I?!4Z=!צ8F!rsQy9]$D&l6A>jFWҵ IKNiZ%S  U~̽>' w [ DGڡQ-M>dO}\8g_ШoYr`x340031Q040K6LIKH47L6KNJr,L LMLҌ R.\nlU{O]k}:x`>u?$ڐ޺x>ebpf x340031Q026642H3KL17H01N03LN5J272HM6I5NIM6cXMFUO,Ǜ_]q!i2Wźx`>u?$^OXW Yx340031Q0653NL5N34M2J2165NJNN5N452OL1H4I3O*cW}pߎMW)[- x=xKj1D)zUB-0uV9<#+Wu? s*M3x340031Q00040H233I5I546L4OM45LHL506H1d`.\%qqc~Q xRx+)JMU0d040031Qrutuen~{T}ǝ6^r"/\F0|Z_8]nzp#sx340031Q0L2074724LL1006705H3J47M37I5637L4bԜqEzҹ>0qU0mx`>u?hC opg<21踰C 5x340031Q04NJK3740347566535K5KN5KL505067073eogRpwc[_p.xRx+)JMU0d040031QrutueXlmmAṃJ}G;UZWRQsCtk# >-/y.7 Sd! x340031Q(HLM1O6KLIL3346H30101M20411H1LL4O4L5L2L`rRWd&8nntlCr f(9*6!ˋ8ݓ}}1Mx_0 @<0Ƭ#ÎM?߱ /7v}-W'=z|ִ3=Gu `\; 2/KKLԍb5:kxzl݉7z1?a=4kںŞy?Vx+`WƤ6Ũim`Jg=.'X300.W@< Nxg¥ޮSٵ%/u sIι|u5)L;o-cx ptf```bi|sr2h_ܵal3  y۶eHԎC݌,lEKX,ʺxC7+ͦ,>?rJXkGF㱘4yZO$etirCn;]Rwy}sIbe3κ= w3Oh߅rcy.Ӹb2a_{6A&5;ދ(Ü -&˄C7BMvify-pzeKY~*YnKI'Sl_{m>+>Y|ZR10iWj$8=+u G.e\p3mGWY[8#Sԫ2m)p͍sVL 8})6=9=tAB[31Hd޷x^ڟ7΂K]kK^׺x}= 0g+q1PCQ%D7XlC jǥO*uF>n󢤜yRiFsTL6;)\HrbU m+8N }#8FY;+ǵS&/kMj9x;ŴiF;F;xSK)MIUP*I-.LPR&ĸ\=C\C422KjSRDZQj&g:P(5-9D /JP+дF$_RTZŐƐ1X.1I8xj@S܎#b(]EQJAtQ*%LZ3ILB5Fp;'s ]3 +qƑ~f?j~wYm݅bx̕I[.]2BlL[4cR^RQ/8ʤzf+!HK$QL ѫTPSo_tLh9JhmKhIh%4Z7z:MVsy1 )H1 JEFUSֱPb[6IDCh&O?cAŴ5,_y_)5 hK%2"zR Vo>8],mJ[x`aVGH#Wl6LMvT؁`xWmo6l FE6)ewC7`^dhaMM!" IAzHJa{{HUbC%e\h{ZiL5 =OnKFYFjYmRIxf1MdBzKBRrNTLn*%deRܣhW?u\=$Ūu-՛ŜKʔŨ\s*m-ɈR5^ yJ2x2V}zwyq{ߟ=؉e A3-D ZDXrL( =Hs*)a`k%see)JČ@/8(7M^Ͻ]/e`@UHv}1<#}.3WPTdLf?y_,F&{I4?3[Mս4i{Y Z !9:Y4^ew*V/YQ<ᙨHq597<8 #2A")Q,lF 0Q,9&;Fp[!j+֓ XC+4Ά"]QoRjEWM&n]]&}ja:;[m lhG40$"0]t+"vFfFۆn* .8cr\l@d| &mYԜcsЩtoGi'CA"QWg:2ΰ _<=[`}O]4gK 7"}{M'\~%3iZ4K$]M2!"|T׷ߓs܄L;axoW7(†2@_Gߡ<4zda"͞ J3.@gI <m)xB\ /+GT}+}Upq]$+ OUh_d-ݱ=֯k3 l]ʭctbPȆeGa],TpIQkf|pV_asX }f ㋿̎Gb}EYb([ zGyy=㌫/^ ^6k@8";MVӨw+IjK.@x=F DrHAUEVFZtl1O8km.ÓE\GTu,֍_>+(xVW𖃉s_YqNNKO+)U#C Tp"d?AJ܇Ա[ cs RF/ 6} _(T\iJ~^I|rbNN|n*1M4I?YxS]@}M*|R냱1&>0Hi~{PʶJ9sϹܹ\"k0VX8|G{4cU6@jb*ŔL X |KK^qOvF9.w┆{Um\|/(t͖8y۩\r_SI1;zM+th}u|rmIJNCI=L±㒄755SFДePV1L^.a$ڋl[X^"d!kٰz'B-lA; *UX=d!3ˍWTDozwPIZ:2HaFw:BٵZ܄WGgov%9ӁF_Ivq8_:]"6x;7Lt9HkbrMRa: <ϥ7S FVfqxJFN=蜠>?01: &xYmOHi&1 NGD !UtoWYk{MVKv~38CޡVXwfg*t+$|e?Ԫ/U)Z}qzw]YMU+h`/FQ0-4fG~^~;?~?y6k+zaMnd5qmuSε?8$J `^[Ir~VP~s imմEQU*kQilt "U0/k 0QtҪT+ʃ>49?k J,Q]=*W46th.h%ϫ>'3~kUo%|r"+I4 j WA+WNWl{H\tjg v- ]c[-cL*3T8ifkN6u:]qhfۗzWZxQLA?"n7,CIj%hBiT=3S3v(Q?) 5O*Ԩ WfW'/@R8rBIҨޜ_Y;N2pxm(œ…!*CB,mxrx٩RSmb=CchY2 Uޮ֔ͦcݸ60jɎI$:Xךa/_v'/Nޫ-_RX| 9CƋ i-  ȴY$Y2C8kv4;$C맫H~g?:oR"pNxkJu7yXQHOVͨR?:xu!*D!ntWz T7s;/KmہWQH&a#49H|XT^rg&jS7h}o9 a#Cbu9H!OGcT~c| 6hz1N[业 Ve]b[.e`(\Md{-Z"7r^Ow>k<'\AMϭ4^81gkw?޼{y2a2nCv: KŠݤ`m6^3fޟ|ԇle1G98=2~O8UD1O{{d! SqbLi&]֢rKSX(TW:ӐMS5s٬&ш%蛲ctC`?N߽\ߟ~%S򸻾7>y<}9VMьiYtUGeT5ϻ*ƪ}rs۾zNc}N~Lҿl~YR[~- 0l~Z>gnVWi`jGG5S9LHA[lB89K+[NJo"ss ;MБ/QzS|Vt`AͺѓћZ!`E),70N64N%8׿5·G[ b~x6A{C6A{Pޖm qb|('mМz&+dߊ2juϬRe`2oe30pwky\fw@[3WYq]RQR੡l~,̀NB{qtI P @NK* D=- ik \10>ОqǕWMp14M̦&-õJSn4Msz|/O/_]l޾obUm0&G7uڲ\ Y;UU8eUYbI\A >s R8A*U(d)ΨfRCIjz3Hʢ50 I{K񌖠uIxyFW+Tߣ|rsZ夑{2)CxQ$֐L靹VLz<+}(:(6*)I%!;o$i `YL# %%ϭ[ʗ(/Lr Zc #IL䪒UpX˰Ao̅}y$ܛw:Ӻ%~컬h3Vw}_ueȆ4_ U:)Ul=lP! F.aH)PPSM* z)@`Gr^LZ_T+L_mNzU`7[Q{:]kԦ;E.5vad'5hYTA_l}z/qC.;Q!052|ֹq(~`u۲>!mղ2oc,+Hi$O'd<~HB[,IxP+Um6kuV8Eʦ/mL~ӪE!fT q#k-9=1{ՌoY3ETq,ھ*Z JAJA\I9,Ҙa+Ӷ э]Y:yU#D9Y[ ֎âW $ \w0l:H+Eoc#Y:8 ]o!! ˠ`8473G Lnšs(p隀ЂS),X4Vlw@8ٙ-J%LG(+יִ@|CjxtTA~J̐6LcJ#NXWr7ot0X q"N7F(F4 AX0"(XP6QMچlH!YE)GG?Wt(Hc+Y+ڤJzil-Eāa:L0%hW⯝V%Btb5K8nJ69r_u|2l7\) Pjo$yet+rFh،kô=MLJVȒ {0WN|יLU%k|D2J>M_欩:kYcr\U`wO3jniM :V#7KӘR;nw7/ӆE>2~}ϳ{c"=Nc )"Puur1yuL%:ʛz1^/[ÐښytJ0UjF:&Mˌ`& ٗ@NJ,b,5ӻeq\>w:sۉXP^4ӳd7=4 "s<~1y +nag\<n(&Ϳo`2}h: I<ԵGם5Wkۏ7W?9loW7Wo6?\H)B ӆYbj2@$&Gy#FcϋDU@&(a_ID3DqQAeTZ>T P_!41/lq ~{3N![Q+E]BKŷ߇kc[ۑ?tm}7w=9<R(M:@>!"7A]mzku.t)$=KSJP* T zҦz; ?!}B/ P~@">0]OuWY>|Qz_g[[rz]`2VLm]nx0ؾ>P\BHW˅jZUO?і+sm8OK=SlLdvs>^+YM~OLڽ^,&LM=Um~=~Λ㟽{sUƖ*]Q4[V?:'wۥu)drn&j,v|լ]Z#MԵh~Ѵbi̟,T}/ڪB;ê[V]6!ӏ4N3Q$eq`Wo)F5Лnn;kбlMNQ=w55 ( =,rRj#UyMFf 1{Yoo?>z+F~S7Pü7=x3ϼ23g7yN(= #Z7+1  T4) -Hˤ"iوfiNM}i~9)DMDNjJ~ьҳDgC^9)9FN5*9 "iuNRJ *]!mQRZ< k`?&Қl)O*ٖ"ui!7!mMAG7$hD:ihݰ`P@N+C.eąOaU:-Csz{y"UwhJ=qUM!?^»D,O#YDD\D9j\a5G+Ugonܾ{CxD.hexLU+i }fJ?DhbE4~ ro,Ƽf"P-C;Mѳ?ѤPEq9׫9m ^=Nw! ]PO O&X~\q.f }'> 09$ W"Z!GY~蟝u8h F=+oC_$%m?c`lTr*{nAp f@ᅠtUBܑW8J>x)?s9Ht.1#eN D A#i[lH@5,Rs|bpt2ɂjV@JnD6mb!DA9EJ\TH,tRpm:UL ,&:$fP\DP!n̬=RV) V/]݃r o!D; šG [y:ީ+&x_!UlΓQ.XG D2ԶI2\ܗ=/<7>r{ OX6J.v싗n䖨S9+ȟ0}1כuO2 }-1+,}'Y Ջe)4<WL^8f\._r_NTtW/])AP!)2G4: IM|W't7ʀ 4}K8wOxR!O<cg1Vhi h:qWpkx e' o pAi+RS`=.T`ơt72 S#vIu(F^B?p8#_ qX %w*NN6}E@319X|(B^@v)[ 1hb/hC*aAdM؈ ףmF]]n/pcGds ;ۀ] iA}E⨽]O F^w,{6Z!-l Cc G6)J$X_^Gn8fP=4-!c^IWtF_ Ti-bA4EtFmHg(7.Z!H˂[r#kZ@}^<th?eu œ]DԞ^&.PM q >p5,+Ӥyz %qHt;ݡ`}3>sb!@ x"5C1ZyMmQ! ?P6 w'^5B(Q  'DV)wo^-9(L 1@ﶵψtׇ;Mp%(. !(*)EGuUI` Wg.j P%hv!Ļ ›Ӊx+@p >9尣s;܌@YF|}˅kv-S*cvs:j MX#GZ.[>Yj^tpӺW2\yz92+טi 7yw_74?_s&jR][20դ~?gTC~X_f2ՋucMul`"_5_=Pw[GϿƢ^ڦ2N꓋W{ς_ WS- ~PS=z\3#M2<(6Bl8jA6RN@\\8½Yi?+|=8#qtM?%r`3lX6RC."s9p?*\BNq>z8|V*\0=]Sr\4$\`f>#C8?#=X)wAu`AHxEF"CD 1  5=siB!!a6FL , 2}gĈWL}U}֙_Ͽߞxx/~x|Ru߯k5}ѝi|ѓ>U}U9vdz,oI~dz/T3ȜxN2g35yNd?FWN^5%Ð'9=x?˜N7csC'9F2"T4m~.P4&`9ZJJnX@VeÊ)D>/|VC?"pxy?$l;h)d&޳7Z P b%oՑPm 0L] Ώȴ}i7$,F\YjV/WQ;ΞHݩqA>e(thWIE$uO,.$~@M joNOt-z[=L5|I2SIS4FHvm"U[T 3ufm)-I6HrQz8'n+nFlU4V*.xA[ۊG ).NiU4 $.wjUToĠ#y>Z(ɹ^Rk\?(&d%"W\xP06#"o2'jGմ+t paK=+LP?|愝1+(5ؠcAOʒ zcuJە@XibX\ftB)5obT^ӸIT\lJTYTTЉ]}_S.Ehjz)'e\z=~gvD|V[nil޵r_?`?xWnEVԀZ!%QUԉԎa\4 gY1㺡!,7\'@H ^1ggqKl)̙;}sدvCLPɲ㒢dvuMmR1ǨĈ϶hke~IWv: XgްP&e>r 碭:9SZ+gYN\`݉eiA_0(s',hu)J5iGF<#D.yGk2g3c`Z:w8t@\;AHo.lsGecqj@4j^rp5?рb)9.Kpm\v[WA O1th d])j}7nPGf+3f+ʯV{Zte 6p'1ǃEYpOjXfoFd֯j.Ωzr t5+fc}=5B /s<t5ƀzj-h4X̗ftskjA#* 67&Hj+f#=Wh?ؐQ^}4iAã?CJ}YV5ieZ i= pT햦+\lSXp45Wwơ:z.UБX^4l=ʏ5 F q;~B^G_c2)w]=C_A\$-ݢUn4mݵ/u x{wZҢb܂T9'>5a,"Cd/< &2nTL,*WJIR s@5LR`1[Ĝd$M̋E8!iE dd4XxTێ0}W [miJ< (M"KvWwvs .~S{Μ3gpgUBR g?MYv`Eٿes;[ZSuqޮl`}crsV_:BHh!7BbKaϹPgp9C* 8`û5@z&߿۝,Hl<Xs'!3VdV̪`8'gQ q  quдgVd+YldEI@3%99u^l* b?P^*` MJxUkOF_1=(+nĢ~dˉ~Dk{8mܹ̙sfȗR?s/Tl(26fT8޽_knFf:HTe+YDcS &0TyV*xl1TV]>P g)xe7kߠUA}2$06b(Dpz.~بMύL:hݫ,#pkz;X6s]r(UN_*IYZ5\'6nzNzf><Ï%FfKd}g9LfkJUw^p%kjZhj== ?7'c- UbqhCy Yd*l g[@2ǃs_Ma..Ow7ǩ} tsusqk,w! "ߧwU&žj$̫.KEOkatz/KW8px#tHpZҢb܂T$%k.}-.ΉG9'7g嬉lȨ99QHV2ssqj)&&*$d)$fglb2M`r&$^F̒x Z)I\^fBf SZV"bY&xjHq%lʊ sr5R4A&mbU7XU9''dvueY uP8]̲,8WBd~7+Bq'NLg[yI5諢D 2IWB?f38?sZ.fz[UխEK+0tϩTd^{':{6pmuJe"jeDtKwKT`,4 AAm%Qud`8d. a8GM)_ٷc#8b:heHtA2.PTKY*1n("$,{{a4{mSޖLeZ7IBҭYӆ'j \(HA`oT/֐L'[@۩iа^!S#BbQ~`q#xA=AC9FxSn0=㯘&&4٦G=T]U4=Ue`n#l,KRNü7oތ/e}paX^캺 hu,i]4U •0K0V.Dr)UOHI$[ {i"%O0SBȧ헯;~vOj.M 4#$Uk,x0 ҝ'2␔/ǽ5C<}KdHx)E5 t-sMLϐ;pތ' 7U`1/};\ #M i[!qBD@SNA‡1+dyH1N@ncU[8`^[wcR `H8~|;|AjK1aY fAE%9>P8(Lԭ=Ea&GqR1ra#YK뚹?#шI(Ln*fQ~ُhg_\QK|ս"ZFXZִ YN/.@͆U[Z 2ef,gݲ4'Wq>)9,'ſ⛟ ['mN?'# v}N#N+%HVJ-49nĞB8C%\ PztEЇ_{+8r|P ]ԓ˘6HrBlNjK8S}YjĈ ߑL>.%FԮjA(H#@D+So]t1\`vn2LPTwk 'F)8agB\0U8ٌx ( SN7&בj| X^8&; F|igfgEuoUOn}+WGʯ#'==tAu9zjBx}Sَ0}tQRuI#j4TTBP3َ؆NW /q}.ǽa③Rݜ;ZwT%#vy[K b4zu>7x4͕mJg\մh:hTe5Ƴ.&xr8шQ>9RPX~ !g>Ry_UT,>-p 59P*PjIQ*72Va a?=٦C#DmVàf*]2 PPg`d?)~voWU֔&%(:2?-+RFu5Jg2(#0RX$(Ǔ2&h r)Vp 0K ܊{e"Ra# HsJ3TB݈y-pZ8X 2nuszCc$cd΃"#ڠ|RG-M*_Z>UB4Y$_3YӇip=a87ѭO;usZr RY&JLR9!qQnoW~GX=HВW"I`ᴈIמʇx׃t0PӡCwL|=( FSd0ӫ&Wl8mH ۧMq K,C4G2'VV}ΜB89WT냩9YO/'so|ӁFU]G= Nf0{$b,8Jߔ{1^{l@6%9Dx̗͍5& <i{zhhj/x}Z}e 85bw 71Z1c UiV < p'KoSt.ɵ^ @3"wdF5#*H=li(VBٽb ݁ aPq,aXk~;hTp| _ܦ'4[q l.i5QAVmnd wGCcg1n}wQYojNKS-ZME^%cY55×ҙ(odA*~XNN (OA(;UI#-?>9'8U#-Ev/#d~65QNEE 2/sr=x}nbvBJfQjrI~QBjqB~JR3n3tF=N T Yޤ.0GQo:xBLfQw>Lz>O{~*e%Ce' JCvYBkqZK4 `ۯY63H_PN~vXh4@Q4*V~l/3*Ńt8϶;tOgMO;\lJ1ERFX)0n!Zu.֋ @$_3;i7ƒ~IӅ'Dh=ѧ?\\ao1}4‘qV$Hki֎ !&gn |gO 6ث|dL-Yt=q"hFbu8^ZP Dh j8V9=E{.D{ ,"`DU;,Y.* Bl |'0ƨR09B|}bޢ&d@"S X9/I3Bz)YR9V"*ob4j)^ K .}y0kHr5ܰL²/=+U%b˭h sM'Rl8ԉ#)l5YJ'JeRnOva0c \xYc&Ҥ,P_eO*C`.1/š{`=|t@ΠȽf;F<2|b?enE?]/woHc |ot֬⹻%η>AvsZE݌^-Ϙ==5'QH/|s8XNX^pκs^_֕*+k g_z;nw17":Sg 3ERb @(xNIAkQ цJIKCbXA\oEۉ+@Rh lD)ʳbf) EzӃ0ʷdQ͒,![ IT]nTZ.irYj=R֎Ԫmc$ vQt45۟m~84wnCx,OL U1wAg*bh8~bbߘFMhBuQ 3r/59붙xVmo8L~KijWn%څ.K+^Reؑ@1oZmgfyp LXH@O9X%3+]B댘0\jND"*\q[Щ+nr.E Csey n #` O`}g0)-L$LO)kA_@ JicY,TRa+{@*!z d-! ~ 1j.R 4&(~6,UBOuIܯp1Ng\}k%V[iSMh!Bu.xlR\;ey!q[aq0DnG~p]f\γUh<.cͲ'+ٮ91q)"-eIӯ)tG;wGΎ[k( DF oWL # tԛL?.4I1?1|l3xlu~ 2vmB:/۠O8cޫXΏD֎R&U?;T IHABٺNkǥ1\C -۟P҅F( (-7&z.>Y8gGA 6<4j7q1m=9*j *hWwޗz20[5.,"@\ǃzw' B=zDRNhla#4:(^۪sR_;뒰"d G;VH}i%FÛPR (૪O@gw[LS r){5Go7k@iD *D2g-^MR` k]ȓ7BJXz,Rs}_D0;WNoبRc!$A0#N6JNU[P>n󥖄 =W1ʌhwXV,wRF7$FKqzGI{Kw:>C %_ B3oGqLn }C+:@#|a=G_ }An -qZI$Q8oM`'dtt0Eoڑj vڸJ1\T[h#lvA\MFֵg]+".,;C%m_k9nzZ/q ~F &bܱw(I4<`d 8Z$kKI­#ë ծ-tv%&e#h|# ntզN뚭߯Qr &tU@a2 tOa8 {6Ax%Y&n j_8UE ǓK@ѥ(~0aGd[xg #qoͿ0G`;.{dzcc~>uXsg#-י)1TMlRx+5Gj +J 1fxuRMO@xٽF* 4Ę<'lZФlĿ?A{tܯϋRs4yo/jID3JDۋ!N.f<8^&<D.ͥuƹq-3Uap|呶PeBi)a4 L> sXܚ(]l^AY\U?'ӓ,$ 0GIK^v$I `0kALzhr`2\ !Bx8TYimtb=ci=22nxJL҃A9좡QW -՛F삎{t:W YBFl+&xL/JխLMKMMHMζrs󓲬UzZ\\\Xx\NuVӘVIkCx{cɜ,OVxiC HSWRI_ԟ3Y >kwxcCd]?x{wZSCsAx;$[pZSC9o xi HM[Y~B)OW*O`TҲ 6x] 6.GD rd9usJS7<顓q4Uʫ&ʳZ6100644 index.hJo$M4Ш&mxD 7?b8q݆]100644 index.h cL 29vg]R+yRxõkHRϛ4]t!TJcL 3ix{tiBix <ue].SO!ܸÓP vPHx{iBȴBNz\$-ʝ skYxkĿa;gx;8q=6sԴ̼Tx׈W?WԼJM(C.-'1X(\AM`mͶ6jgbIN-/lNJjqd#gQ jL|jEIj^Jj:Ku'б+H,ɈIK/+ňif=Q̼E]컘@NѴLS@64 UqYbebV楤¸%VF`vAbIF|Nj^zIАZbk..R TR(HLIKWH,Q[Y__]R )5$$?d";i@ xi Iן8}ڶ)h(3,UmfawO/QWطC"GxD 7 Q̓k}j(100644 index.he}#+r)Ǡ%ݸD\?xV[oEVJ ]zQRJ/Rbc;vb4miDc{]'M4oPUx'~7 gfήs}efw;/_ =wZY\YH]ު@'KL}G6u'sg׆؟o.iPuN؞ԞMHEn6zı [mx-! hk"A9;|)!`Ym{  s06~a@B^dy=Mdpx[Sft$iγKlr:X 8el2;7=¾.e AD*Ϩ3P=uϰPuQb=e I.Xt|gnC~:{Y`.l^n$qy[f-JBẼ ݑ}%6k[ajM7}Oߟesw5 j|5=(L-%䐶C\BΘ7 OZm=5&|[ !/0LbM~]ZF'IOTFήi&&iI&Il?`&q $r "J$vk(\ 9L3$ЍREz¦YoWGrmk$8߇de^]Q?PVt<1w2߽sF_^ 7q=1R)q'Un¯ SLt.cc5n$lzd; (ȆgU*v`.i,|O [znvDq _I%%o%V ^Y C]fM:DED~1DUq }'M'=>2P#M iG~[t>BǶ?LbthHeѫ ʯwx5|"u}Uqk8žO;ٌjNG|t@ggFq==Zf4;Ĕ|5=pW~zcɌ*0ſS?+ſys*^TjiޡddEľvHzNx! >p*d6uE>UWnkx#:Mt VY* x\O0[i!Q Dx! W(O۾ADɻFS>"FBax#Kp†70aa|o;uL xiC ê+݊38^[2 x340031QKI`XTdkgM]+溾L \x#OpBHn~RVjrI~f^Jj60aa|o;uLVx <cN"25w}IP &$ 3xS$q3 57I$'&gL~ ooPXTPRL-VTRpT+MJ-ROSH+)L-I0I Nﴤ-7yXIFBQ~~ t?Һ "rosp2+((L~a 7hݹG_,4xc7L7ofȮ 9~xiC HSWRI_ԟ3Y >)xi )7dV (G YTx! @mKFͲjTx{6bC$d~=55,; e7KTM*9YG^{, ,7DAer ?iEe/):o>i%Y'gm^oe#dxxi H& iR+uL`T LTx` :dHBdK(bi100644 filelock.hw9rfW @mKFͲD (x{.=Yj +Oy% řU% %9y% %E@gHwkD_5'TSAbIT5dC6+4 ̒Ԋb  )I PFt 6yl9ٺv`Ey9:`t-9SIbK`&ocCrPdvEPfȇm9$0 :gA\ S&+(OQd!$N8ws '3]\ FMNNƳPd,4y2T<nޫ7xi  L,zel)9Fկ 0?xD 7 cK44A_(100644 index.hCjRi9LO扳%&2x[1oCdEq~]wϐx_Lj=L98'_ݼÛq dK.\ ' l{=xɻtAͬuti&TjU($(xFĻE{FjZsMULS(յR 9Ȧ$d BIK/ɉ$$VV b-̠͌`MWbۜ2b%ڒRj{:(hZOvT)5Zf^JjҼ^QrhTOvҐ'`N]R̗I}fh) O YU,RJ36+cYrxu:100644 tree.hS*/F[=6A]c1ZkHx47i,hN _BFx"shG^FRSYB"9k x;ŵ}+m,Gs2xURPVXT2SV̌O,.KH,Ѵ޼IӵWU0#ɇis 'f H)QxmRJ0Qqa}8ڲ1/! :vmј6NJ >d.uI};''8Fe\ʩy)i\YcxiC RaW++9[{ݓ+v " wxV ȃ2;-8%E듿[[;z:jgP4~<]FNBq?[if&h8T-i"k~x˵!qr8^LZ'/e`WRɎ,ee2eeX&۱|賊D&N|Eur=+xi I֪.t1SGI P(I-.)fӚw΍g~۟V<|3hxw 8^şb100644 commit.hREpù[ZHEz3x(7)?1eXuf^ͳB.߆ҳd~%13ݟ4@%4%1/xR_kPu)M̶de6AX*J){(IRl~U؋m~ |o`n2<=sON{}zG?#w`:PIyxJkD eMvd7N=xQ񮰸"R>+<@'|Ҭ;R^T_"f(Ξ xx)|d7@5c'Bc&8q 3Q>Ť?͖:+oW.S7]Q  Y]Z-kqU&%-?1"d0'{ˤ:7b^UAgP zlSjx m}]æk&.:c?3^,J(Vo;^gS)KjKBOI jxi _-'(=sr" <x~ 8n0Âe@K+ CGkf'100644 commit.hP5rCyD+$ SIſ E%Ɏ+JKM?hc#+KޓF)J<y=7\x[:uBBN~bBIQjBf^IBr~nnfB~RVjrXao~<*x*{Bd,'3MˬVXT2Yʼnlr;2 -WSUX4Q^]ZV BA(M/QXAcY(+LKMQ(H,*NM2+< Ҽ̼Ԣ̼t ْԜJ b+#3kZkɅXgNgTQl-$w($g$)h%Mgf+)OȜ&;!lf zs?)+hi,M/QYsqNca,+LKMQ(H,*NM2T(NM̓K2JRRK2a%)9PǙB>!/x}{' sf^d^w9dT%xS;oA Ư6G&qL'[FtVEHɱa3hݕ4HtQPP/P× }+{nT /g?? g6Q0Z*ѵ[yeF_9s2TM驏$OK.iaLҘؕ1[հNekaFzs/2/L"͉je(TJ'\f1+JT0 נMP](XGmRK,cOqzso,ϋۢ{DH>20S*Y[oz-ݝ̬W;`;xM+ҒqR|e{_mʈ3$ak9`LqO%,IKc;3w*38{Jq{-U,1ٶrx.8Gӓ'ZOXB0̗;"E~*OGsLX4ЮNO(J5!fuMT~ ]:BV&oEP!f/ze^5nD)Qj3INjS|V1N%vq22߄{ x۠Nu>ĒdҤTĊĔ"[=3Sk..ɏYJ3RS2J8sSs *5Ԋt2St2St3R445E%Ey \\y'GqMQk6 MYAK"#}d454r3A*h+j*h;VsG#gHkPesk(x;}(L xi Bwo{9h3KBIjqI1ÆEmeM\ɳ'j xR |S%?1f屓W’.qB[TN,]õ:5L[r⓪'xXoEW&q\jv$'!v:R5MiJӖD+';[]w-me  bzCj蹪Pg9P$=!ݙG=8y>y_mї{ z+G E7@ ^YKgG*$~Qk &(ΝKilZяc裱iX6HDn8觱O),]\zo[B-+͊т LU3<) dL]7u C7h&Ӆ"xQ3 )x, *GG&DeW߼ kaDLVB*W7VɄ -, 9z8}梲~bM9~CDMv {0W,Oh@m8Fi)\0GAheZe&Z룄m5, wңx#-89t,ᖙ.,!Rh&@p1~f'z**qOWEK';p4ipq h*0Tj\'J2Vݨ֫jMuV6 j F_ELPmf$5*uG V :s^~gПѩm$l B _.1"X!ћ -a^j$36bL?ڸTlRY׬͚Knܰ|lVW~.Q4M3JĿт^%WH ܖ!dhDݍ\WDmk&aω)btY~E-?zGO?Q•<(C\qq1 kb*u(W%fAIuZS$;~7NKaH'^NŜ-aOvnv u# Z(Q)lۙ'.gYt}k8l.4:F(uPf. d$syA̅]dY]U;)Υ:F[3/b{!ӀϺMԤebKaqHYyx [edO 1~ȌL c;EJPO鷤ތ;R,%:m8IS^n?q.,vkLh9ޘ0ⲼJp)a%dworȅЫtYϚϳcFX?ȇ㐅 x+u#-YuzRE͚ڰg,jGT=&X@99@X=vc 3jMsӇq7=[8 I^(l=] ΌxVKo[EVq27v_ıqbשD!8H44I[%&Ir#׵ RJ btS! ]R3WP\!Xxn:O"&4=sv)?Y`@[Y-VKFJTk4d" x%hoO>?Df[wnGⅨGwrتxwnGx-Ün 55U[w`k\f^Yxqldz|-໶d;LqIMrO.a)h,^ 9ؓaZƉ&a[GzU}C{$&A j+uT?R/xUwo.I3^}Sa{*F;XF)X}g[+z9eԇa f KrgGā38nJ?x;x7Q? *f`yQ!P #5HD{>B?]8[k'vtx<_*h%&GQ_q{\"5S$5^D?r=G+#OlUF3cRqKӡ1 tE#t- ^#KVR^Jqx8݇jhF— oi-, /YXG;6 kVDMZD&mjԒDAmXg|yJd(zST-P۳ _6vwV#SA^xsoŢ7N_׋V'"S27lj$n-ؗ9RtS}+RjEpќMJvcH&1[J{1 ooxA]14--hn$d9͌-xra6u,X6'p*3j)xed&dV*$('e&(ho-5y43{RؑMrx;4ID!9?77D/A*|W!G&4q"Z7Qd5FigxUoH~Ũ} {(SI%d-޵$~3c5Uu13|߃>L}K)=R`*RʺR*M Ur 'WXR Nb\jY V.S,T$<*#BAl*czFx6  " Ѐl| "m3lR`teɯQԔIrڕTB99ҏl@b&9xofKq EimuccƦ"X=X<3 mPUCǡ؀(@h񸐑cHEEóAE >E8crtJ 8f)&&eܒ/2!˦gJ=eNMA Gr|VY;"2&Le^Oȭ|+ *+v̇?O׷dr/, 0dd zu")[׫UK'Tf[?-bHDLVqy1AX`lL_PyV.]=㮒EjƓ2G mڲ=,3h繨&o>~;:Z=_܈#Gux(tc$O< %.̼ҔTf~V~ͳ؎12*LNaϙ\ñtYLx}JA9"v2I "D Iawm5{;ޜA<=`%1r |??FcRj$4 Ksj,aa Oю [gv8b5(Ŭh{ɮ%Z4U;g?f }SC ew/fu#B]?O1ɧ_9d ^y٨+#m"9 QH=2!QJ!Od>qw9!A姌0ZN)N١5^J HnHtʶ[yʃBy5F4"5;|~ep.3ձ/ͼ9H.KP~N1#Ubxi H@~=A.(,g>9Q׳ KxuSru3 YpawÊ?zijPxHuɭ/zaJZ6C3dKk_6I]?*`a`ST5 e7+1vU|p'n5-o&}c/tstNA ^wMfyrLFW8Ti#)/J-OJM9ûyɘ^詒`ux BYybN6Цi7m|qdm')`~众j5ϊ35kwM U M/6Dz"zzy:lr_Zɉ,!8NY(SSb$҉/o'ǰ*XBxx;ySru3 8[/|GՂGfmT]x^|:xd %40000 block-sha1(oZxHrYԲn)%6l)r:W8low^KLO*6ʜ5j Y  s)lxsg;f>'&vqxSP^ ~.| sCAd4GZ3z4TSi<740000 testsDz|'IEa>O$nxx;~B}tfF3 +x [Pq2%{JEДo7k*xó d6 ?x}c̦Z;}fЈ mx}j%l\lɳuC^|Mx"_dC(Dv2 ){8nɲv ^Bx <.ۉ|ѿŠ4hOP po;x;sHyдNi%YiOx340031Q(H4Kfx0K_~`ymg Td0^ˢz?D~{x;i3ͯ7g*8yKL~ lx;̺uC>F'ftN,pw$j{ep&d#x\)iy p5)%{$ny9`.(bxºulcsH'gRNv<å0ُIarYLRn73xi HГL^Q*>T ڟ19Qݵ >mxRJ1xZ칶 (/ZD5uk"lED3n%afޛ^O{6۫XgEdyph,chS0"fX\Ewk@ $*IM]nbTRv.D +7e!z2я0ȂG̑jX{2EZp\N׍s+PbyajFoUĆ7c1q:mZ49I>T8wNH&%p ,x$d}*5!>[eWSo1[N9󼈵c2bT@ qNAګObCo.v&s~C!txk,g,͓sYO`˛\Ŗ5[UcsHB5'cYi $EtD<$,άJ/Q6Ck-6H!'xSLKIMSs uq/H4ψRfbJp)g)@$S4= 52sJSR A2Ss`h/H+.i˰*NE62)'?9[d(y)i\PZA_ é Z\~EA[xi ȁ:)<0 X-FҖ x340031Q(H4Kfbc$7^95C$ j|huϳ<lcxks.11!C x|H Ѕt7dh#.x-'&3 o src/*/*.o0 jxi jNU<[~| P(I-.)f0vz0k_MB|\w.*ax;ys+FWY/~S|k? ͒0tx[);OvInjnrAF~iBqIBgHKkDp=jr=|ax96&tJEkn8ߏ";JgH:Y:Ӑ^cPxkhrf^rNiJMqIJNfF,E/1nbd\0"l&!Fx[i4hF%̙y%3nb<9483=/5E!9#Hs2'%F͏YDxi [)gx+o%&o#% P(I-.)fϺg;e{D~xR aȔF(]nc᱓{lln'n6GY7^8*mǐhZ䱍1n ,&ax9  6mok9S;pQ04:c} e;^jjGx9 ρF:RmNʧIђa҄;mD3nz^jDxra6u,X6'pT@o0x[Zudm6Al1<6uxQqC J]&}+ u8bـ1қ@ sxb=CDP{ c0UPm-100644 t0403-lists.czBZM%X|a<uZOuK*y2l~Ѐm )qxJ=v=]|FXd|Mq100644 t0403-lists.cqATU'>U1 s=-LjxX{M}܂J.%%.. W(JKUHO,JJLOVX_!(?;5O!5/%'3/XpYo0$de702-**-(IMlylrHNPeU>y/+'6c )0+`aԟ¦ ųD$#X $_ ؞K_ z<6Fr@:e$gBQi,J+&!m-:x$^n7cxµ!qr8^L \ @0ّq,,f;oF Irx#JhC9Z&# m8y+6LOVe&cLj&eQݼ ucxi ɭw,-wBC P(I-.)fTɾRSw%yx Ixi ~5Nx@ɹc-x;ysȩ'%.l6e񮼪qYMlxra6u,1&^6+x[P{-ɷ/9h5 Yx <|yn 0OP lx[:Muh&Wxi ?٘(so7oԯKex;ysH'?I.5ӚM}ss# x[We.jQjIiQFi^qfz^jBf^ff]f5W-䍬›XOpm`c F%xi ɋm _d&Z-)JRKT;/^>3g^gL6Ix < s:˹cd3%'P q.xiC ȝGY6bF=j/x J@%\; ؘ!)Gݓx!Oֱ2bxxs|}/=,glmx͵i S.3kxi H2{krkcU߹:9Q5 o x;|yC>#sf^bH.^l2xi H=mWnUΝ;9Q Px;ys9Jg|Ӻ992UxrNe>ĒY6bQc.ٝ]./<8*UAK!7"*%>-1$Țkf>|fe/fxi /!C6q?x,~,Mmrγ Hx;ysȔmqq,9֊;gyʤiss# 4x;GekYC97s;3Axۣ[e VĤTM46`uy $:xi Iz2wocq[qj~O~BIjqI1̶[_NTjոju_7;ZIxi +۪ |2zm<>X339Q) p,xiC HjBK'z&Kzo8(xi H@Wrz+=R>9Q܌ )x;ysBŽv*5ܳKKl:Br~nnf^C+igf hTH|vcF=F^n{,]Md}p(.4/XyLPcRRA&_}.q֒K78#'d%3li2˟gf?DS 9#U!:lUL>_`x;yss±T?\8mś}g+640031Q(J-OJM.`iأwOZM.e9z Go=ZyW110e-ux;ysB/B_=4El~_+@wBr~nnf^Ë GtF=إ™bjyPL* ?_ݜ6P|%j|'\' Exd 8F#O ID 100644 commit.hv)s"W<ᱷ3~RԫLH9jԠ6\U100644 revwalk.h)ςAL{dмؓSI*xR R3B@l1sZu/;i^Kl06o+s^8*mǐhZ䱍1n ]'6~xm 2,7Kev xi H=C7ˉґHT8k=9Q h]x;ys~Ko/ynss#˿ ~xm 2,7}ga1&R-85&fMt]N?=$>?)+>9'8UC-9?7"iYZRZ`dOͩǤkkrd#͉"[y}:,5xۭFe&]+9o8\Axx_qs\ 6 \E%Ey !N^AA!.s8jX2e5 ixi )JN"mN}Ny?9Qӯ xi Hmo(7/7tr ^xUk[UgbӞ$Ms6fI]ՎRSA&~HN6d洽%ɽKnT*{n{r}0}EWpo~Ͻ!>~?g:}oODۢG7FC3iB;L^!^?BcWOA=P&JhOHV1K 3u,#[-,oe1v2J5oR)+Z LՉ.ZƗHMN;gQI}R< ]9H3~hoJT*_/Fpf\bD:[߮R R`]`v֬BXPtj C:!zk4!%dnmt8WuXcrEx3l%`Z\ ]mAgܔwgY[;T~Yst~DnѴ.0阥Qk'qo @%>@7~c@ [ʜWog!.j]C*WfikѣS0p&7fb!SoZf,fa7"(ضK9BR˳a[Z1n~rY~%٣ߋl/Gx64ƢΣB/~LN\9THw / SH2,ܙm1L3x&Ht,;KY~ffvFKq5NF} /xK~+;KY~fd;&q1)hLȥȯ``YZRZ79dN}NkZ..9\\959'ksB沜GpB.'df Tl>#,@#8)Nܜ)4rx9  fVvSո_n|0[0ru#5#FBc7KxI=[ T7}(|af?100644 t0403-lists.cL_y۾nKS Z Xx[ž}C9g_<Cg<++ͪy #K -x Oֱ2bxxs|}/ cV x <+sZ37דP kx9 Akm+L=1b]GL|0[0ru#5#FB)xk,YӊJ&q&xi E'^yj ם } 4x9 S^@nwM Vm&|0[0ru#5#FB<Axs'XUYR+J6Xɱb4#kZQ~^fymP*4x .>"㱓5)fx[}C=%x[4Ii*ɏ'e瘼K~ 'rlbxi ɹywOvr6n8fT )&@PZ\RΜgs+)sxE9:&Ix <"5<8P N"x[}C=װ`O_ɎғXJ%١r1n^WkKxSi 3W-o,x;˵sjvԼ4.-,ox;Bn["4ld98^2韛(3H]~@׳7wyt!\Ix <`{X6OoHpP )kx[ȾaLOf xi A.KIMRMaFo,4 nSx;ysBR)'9l춟2`r040031QH,`hq -e]޷{yLܺq1#w|=.x&V2y>5假u,  c$jlQjY~RVj2侅U:Q? [l+BYybN^2"ݕ;GS.SK߳nXf?_ _x;ysBx{ﮛΊ+w_lnqvzk&!ʿ V/y{BQjY~RVjr^C߱iKrJg-d{_3BYybN^2&/z-y;i&C4E "s?r^Zkҩ,_j?Hxxcd"BMBA~~]J"x6rmdgm[[x˵!K95/%3 ,xi [B^4nlsz39Q x`hCK\o&o,#amxEqC>BFi^qfz^jBf^ff|V#n Ox>}dfN..Լ4.2>x[)UjɿYM~PzF6 D&HL~qŬ(?ؚKl[];0O/#51,[\%5#]r~nnf&D1qPԊddo޵ y%'siM⚼KR (5Rʇ`3$d[kUi yy%E%y QRo6x|iBć"\Z%E%Erj%f8ZE@&g祦('dg[$ ?'?=391'8Кv.F+$jx;ƴi"̒ԢĒ"k. H,OR9% +.x <sP{Wh5𺮇P 6N x;cBE[ȋWr{“($fe0,8սaVǠe[nn(e+jmo޽sd'ܦ*|e0c5cZ #{~fBfdF&EޢԲ-YɖK95/%3 yl>x*NjCrl&rx <j Rji#P e&x`4W{ VkX󬹸 9?77D.-'1XV3$Hyxqgd*h$k*TuTH׎1 ،x!j蒓,8f[zfI<Ģx73SJ&o: fN>(&̮Q* fO`&s)N%W2+3MA,`k RKJ(քTr֘*R+@ C!`258̰#r * S#%P=d/y !kf x;u}BrrJjZf^gH/ vuS CM.,<<]\bUPd91Qdr# Z%e%@bZy%&>|1Qk`&;f1JdhgCtd(hM^"">D]xT/@dH MC^ ]]V6wr NGEC}{߼ޛ^]'%qMߒ:\)pЋa<5eGk'?zcjpAPkYxsI1!'SU*TZn97Yf6li U#Љ nswq#N$O[VlCԈ'Dj5M1hmuuIʈ1X}<UnJls_{G~ y[*k!?N-L@6;i?x;ƴi¡dLxi ƽ3u{fn OSxD$100644 commit.h'7d*jJDiJh $N~`V3hLViLxi H$y\-5J x;cB/ ʢ2ezucEmBk540031QH,`.H>J/~ok*w6nbr(OKf?_ӄS`mӴs}{h|QZV`߸աuA qQgשN>-5 Xx=C{'d/VsXC@_ D)h)yFZ)&e+&gT*d*$0M! @1l===j}.̜T 1FNnW+ѵK,)Q047s?cKkr0sB\>knx;>}?d6^x[#3MdSVɷ9'sLƦ89#tr5BBq~QXqBNfqBRbqjB~BybNB~QJjQf^:Fni֢ɂ|b:ꁆx%deegp)AfFA~~]&XA~_&XL@zfIQA|Qjqj X5\(( "XR+Jl &{pKOn*O>gO0xi )il6.^򶪓җ59Qș  x;cBE!K;ʺSN}׾D?JC3 ˾yc,UJXx;|vcFc1lYϘgnNzS(̹dκ#;FWY/~S|k? ɒ9z j?G:%OV=jmQjXQޗ7,T_u斖}3.MFx!ѭdMmu2;d|.0x]8A"@#0y100644 commit.hۚOO0{ 49Ԗ3rV۬z4Yhۿ|+kxC8پ??--%Y!j100644 commit.hM;_Z!9=ӐtQxcBEKSt˃3!'sfMch``fbYP骣kYg存_qD&i]ܟrqtӬݓPEe9@oV{WzsueJ&72d 9sxݤa;d.*iLeSťZ !.V  i % % 9E) ɉ@) y y΢Բhq PB~BN~bJf^PwZQ~.ش$}.0h ͺv)I: 'Ot|Kkwp Ʌ+Oϩ0;*7nb̧y-k61gJk0x;m? ixD$100644 commit.hY۫cыaop֍ŗw$N~`V3hL8hxscC U~viBBr~nnfBZQ~.WZYPPXTT2y5Y3Mvg< sx&/adgɇl<#|]@@K!4 85E!9?77D!?)+5^!<#(U!%_$#8$Vk钯P [ R W34!MeYONgfKNamv8migx;ƴi6x0]]3@0xkR&u? !.V  % y % y%`Բg!x;e“Ōno03rp)dq{l'x-\lXN(Qx{.s< %.̼ҔT%Xf H+9?D!=$>?3EA Āgh x Zɚ\\E%Ey jɺv)\\5#q _xƽaK}QjYybN^WzfI<_''k$SR48Q+*s!3R4R\i `'gQjIiQ_u8'H\hBJP1T$lUUqNZQj`7<&jtJjxrqBrf^rNiJMqIJNf^dFɯU i/x;θqB:Okaxi ɦ D+=#JRK9rVrU|=]Eaf;g<Hxi b>5iO{Dޭͳ?+<9Q Nl>x&M~nͿYs)PTx~mBHKٛ%L>"MtvɢO#gxeC9 ZOxi H&tP mkuor Fx&?]~nͿY/21rN9?G+#2y8\` "^Y Ǘw/gQjIiQ5W-ԝkx;~eAj.̒k.]byřy) Eũ)V:\3J0rp)dq@ xm1 0_hWЈ:JKMI'boRl xٴCK2(s.!(%D?`b6a..5A4j.fLf ]bix|ʁ7~Abx;xq:qNb+#3kZk..Լ4.k xD$100644 commit.h%r=-]S:$N~`V3hLNu)xi ɜWfUMyIbf;,M @$-g(W5ZfnvsKx340031QH,``Wz- '[m4D~;X@դs{Dwg3cP5)I@;Rb4w[^>XLAf P?BKX$h]+t޳u2TAQjYybN6PQu x ҒTDE>ϽěR;7*r2A.:}IC6Fi 7ϖhrxS#oIЄ'.|4sV>rIϏjG40000 tests"g]Ac;"K㡘V%%xuJ@IQt#^ji)խZ[,Vک 3efߢ] .ĭ/qέ/ 'M͙9w-?ʡ݆B&,A@k@h:7peb.'2BtqA-Pȭ8 zJ\nc4P׀IP% *b&㈊pHA1ySGiW?cZKOS[ jΨVJ EDcNYfma')X~`kVR4ECj=υ<ވE1z3K˰^2)%"ՌO+P?%_D x֣:os4 #kDHc{9LL *`'X4y`x'XbSR= 8!A ڶ Ez0INtI  R7858I9ٺ 3L&;Y=Ry'0jmVee ެk=~G,xQ}!EK_n!첓'Kl¾ .x{YeH?L3CGexz%40000 block-sha1:>d"FlIo %xKup;D; 1fлOJ{7X>e<M5*^ 3 x340031Q(H4Kfbc$7^95C$ ;R'YwM=3^0ˆqx340031Q(H4Kfx%v-.̫%ŗy7?"`8+ef͸T Y/A\ݷ.93f m.x ' xSLKIMSs uq/H4ψRfbJp)gt8{8r)+d%甦*($e(q)"K&'g낤dqAi}- up1lxvmHVI#KgM\vsׅA {0x"OdC(D8Z.lx'!e icxi ;eVX){nBk .xB5W{Z[qf"100644 odb.h/ [ BPzێ2Fpg0YTdz\}?ige\p0{zy<\;'8d楗#RLfl|;G0eH(i5Ϲ.Mql$[W8NsEH 298mUM+` 2S&HhD~r8׽S/0\AA2mi2vZZI0'dTI<)9;ƗAh2k?~=$(51E$3",zΠ$#I'E ;kt5i{  +ˬ``XTaobOfJN/)2hUR_r|s]#`p*X#TQ,{I_C(36b8ZyJ{C +d8dyxk5\u.[ˠ@BRqڎIZ_3ZR$Z@^ˇ[Z4SSN 3|v40000 tests@pW|/BʺL1ϵxO,LO./)J,KHLJ,1+HD.^zrJ"Se\ixvImC:fFLzUx'x^uBhFF׈ xg7GsxT4 N^o0֧)8{8rqB$m 3 Q@Z/h| 0t¬N)NbRN~rYlrlP6^07_AMc #xM8 cFdaKV<100644 common.h:k?`'aS2SI\[]R}5樂[40000 gitA>ZR(FD٭ lodb.c,-| }kqo?ThjI*)[XbÓZ @Il?x['Vff]fFn5bx340031QH,`>sj׭]&?ԢbyNvw(nQlq &?% bQJ̔\n 2)L*|Ao!{[]YmH*(J-+O*zʩ8>kWJ'f^trҒTDE>ϽěR;7*r2A.:}IC6Fi 72CmjJx(tKhm< %.̼ҔTf~\f5_n;x%tc$" l-w& xQJ@k}"(ت$z)T'!lmfCvS->94b,ܝ#J‹v)y{ȳ Qg%$/y1AkO&{zÑ*! ۶sN?vZ^`>9?~@T%tVrftn7`.w  $Gt UFZ7vJ &,xC<"gاxHIS7̞u[iAB)S#`@Eo̢ ̂miIoڭ,!c&p"2 e|/yYndx[#FnFFwy*oyx١!)3os2;*- x|a ;BzfI|QjYA|bIIe'/س9s)f.SɎ xlgDR OI 59F`w stss3'_|E&^29ADf7x{VjCf~`{ӹ3KSR6 J.xSMo1UCpʥTKq)H/5l֪^ަ{+~?'iZ{ޛ7oӴaF)_fa.v€C|pjZ* l[**#AƒNѠV)&{t^YG %W%LﳠJ-u `R!%Wy=(&FT!Lc2Z*'F%&a=IPCT5U&0W!K`ẻ/g77l&5Fۊi%\NQ[EM-{#vɅfcLAZekvpKLBFQnVSw9b"T8t|;or4`lVb54US~?d\:%{'grit#tTz.GxK.E#*9aBM1Azǃh-~xېCu޸߹,1: 'ZB.(S0HYE55 m)1hq2f]+qѼ42^Bs8uv{y |Х0w7*#t_eԱu1.Qsx[j yٶrznS&ՕD؝^|mj٪Z#x/>Y|]YDS23sJSR6Nd" , /x,>A|C;W~~BzfI,N UVαW(QPZ"~%H<#3%M\u/Ν TsMU9iex w$lk8x;sg*d56eGgexvmG!k/iYMrvm5]?}у]&0Zۋbڻ2C5t'"gh``fbPb`h`URYmsx$̂iUW9O<]5MN-AN׺O.T1c9/Ts>{wm@1%9E@34dj, ׬HhT&)1KmS̚/']a[89Iz ?w/˙Bcu~ P}lx"Gd?b&[x[ihF%̙y%3nb<9483=/5E!9#Hs3'(rvx["4ChB䇌v,:J8}}=C4u&s1*|Jr|kGw`]㘸'g1O1bhfhdl9y;+j-x;̱cƨNgxWjF%lZ؁] qشl'^HY;SvP7aҀ*{F6ƕMЇ},PhoC:#empjA{Νs^ɯ_i凲r!°hZ}Li::\)ht.|6GaB#;G XH?`u' wj}~v+@KCx*TȐE=a|4BAIJFcy_Dy]be h=-)b2|sCƥ.1j@6,23aY nbƝћ@ ];ȄToMd]XƏ2jcTI3Dnv I1Jjhf"7eaWa#vRf0Q5@Y{߷ m Qg*ωT :2ҳItE1eXkCXSތ:laӶ?eQ"˰3HN[I}GX]L+u g[lF~8hd t񤏹.s0Oܑ#}NrT9 }LqkP"ndQ/ޤurEG3Wr{g3ZmDm?%6A=>$)eڃHCk{&P?RIrȟ{'<'g6+3ڕCJĪvQ듣czVFE."g35|% -WCԨT,l P'9Y=H6 d= ,$jDW3[֢۞ZM6GG$Ţc)lBxuVfF;xQK0_|id]7yn0t2A|PHi56H>_sYک/ ؞Ϸ4*.ej<< ǣ蒐B%S T!S/F9D+H,) Zj,* +'lu+HqO5 eP`}S[ \n7YsXPд!Z1T٩UMg ~x_&SܐkǪnnr\׌^7˝ר<MIЇ8iv:q+qA ./x340031Q(H4Kfhz)dEW3UyQe"t }{Wݟ@!jcAxWmsH_sIF K*vL_(I h.B1o^wCMLOw;wG O0>qr'Dõ.|p1CWA?< `n*5; 2*w0`,p8,ES/U.CbMX^.\\zxud0dI"N"1Y$܅E \WX1wab[0hԽн n, ac8"kAr cKWN!#q'"}$f֋.b. iT[4/] vv`ÈOy H>ք!t}5@$ݝ'/Vpѐ-|C:!~ 9XCL3|*Yc͔9^A`ۍ6ntka>َ4t$iF}Uh{zJOO~@0rBD 'ίK1G8=|2YY w[i[}^RriHz!rr_HS1Kr v]J4m.X}d'fjEx _R!B⒇,V"@uԚ eRuOQU XEkr P!٣L#9WHZb7cگp#B CEhQQS)'#K\YRɑt@ OB!&ixğH/z4<2{س"A|?t[#m4βɱ׮qHI6GK4W|<ta W G9bD!9\\88]3G+`}Iүq;4!T 6ʬMG 6 Y + BL _H'tP6꣚mT5u}茂hsɪQgy pSE옾oQr_,!ܸ%F.5N,u\6i$u-i&u|Mr%v8>iI9rܞ|(2C@;hѿQ=|:;އئEr6,8 3Ɏ"ךxKj) 1q*I"6RҡㄸӾW dPщT F):< #dJL0*ʄCN1f(YX ^gLJ9Ĕxjkae۟/xAoP\nH>kr3RRAn״Y~n=KڋX&^UMz*Gz%^^Էra=ԏM؃z`J-m,6 G6!r,Xn̲,O1,e>sԨKgUBƵR]xHB|Qs9UPIl6B]>% QNQ,3c~,U_$tkXzDS|#v-׆a|410ӄ>1R~@G^oRtҵzV:έanv ऍyD5YԙKw*}ff[2E+lu/88Rc9Zf҄FiDjP!_̽,+軲}a'v[3>먘kgQ쨄[U~u+OXT& 53rL=J]P%J`U *ts7쟜q gc0m_z3.GMSGfoK\|j9g:XADTv % eN.+ɜfRWt *7A.]HiM;Q)<oE _?ّN`n23g?)8A_4 wro`m%2?=FpݢKPGaɌrNv16qmbjhqي`:zi"Rf]ә.qMd p Lm@l~?682R#b[,R[!#X)* Ț,'LBs%r)7V0q=w"Tv"riu۷ILKahQ]|5'@6HBoO//)(O,2_}n{gWXg;oz޻DNxDm,fo^v6 xP|E'6ƂMTF+ӆm 3iџVBJ!ғP 5$xaH!<6 ly<ԊݴN1QYC*˥ۤ?y 7J40000 sha1XpDIQ|»N(/PBq("kxx[>}CBfVfxi k0gbfoGcvr; g4x1cC5HaŇ=+\kE[yݙ ox.1;CxSHFQCDPxS"|xi ȶ ,x2Ud摓J Mx1cC5H2+p>pOG2nQһLM ix{ sXJ3J6gm2'1%m` Z0f4ע973es939ri嗖(*kYY;A"_7asaZ*qirqVf`VN.1y8n捽 Qox <:UAm>@YRx;Ly;$&6/f6fݛY7_a9}F  xvmHGoݚq⋪T$׍^|x#CpB5'1mnc4ٞ5Y7_afV F6 CŁk!d] 3 wDUfxi ějV+T#7+6ab %% kj|\gM(qYFƿGOxJ'100644 cc-compat.hfђwi0SDu0']Ŋ z Y&O#ʳ&5 l+xȽ!ycfM&8x[+VzC>䙌E$y8SrGxvmGCJr+GjH>oo 8 llxV!wD_"Zx<<4a\VyO3|u40000 tests ѭۆv]*$xQ{Y.ϲrn!#a>ѻ7b.5 'ƱٕjRbqj|Nj-LZJjNIOKќEL((G},7Y^/9&x93OTtlo#Y(}5;Grm!M^Gcj]x[i4hFWPxxi I" -i)+T٥gb %% o.ݾ)C<獵/vL{jcvxc'100644 cc-compat.hHCpmW)']$#%7چb{1F \ޓddy(r&2Z0z<)lWxya?̚L"dx[+s_zb O#sRtK3R5'Og bOI7 1IkJx/}Rz‡l7y!/xiƨQD_dTr1x 0t=vrD.xV>W$$UG!9#HA $Czs?f 0x7G3i߲Gё^m ̊Vq jdNVP GSkxkgy˼a%Ì.qDx! aGaĕMVm)ˣEaDx340031QH,`>sj׭]&? _!Af[?Oi﮹~ &(Ƽ'|%ӷpWwG@դeּi}Q|BS ;@-.xsL Ӹ7=yT{ԲĜlʏsSvtRiI-܁**(JML--9HETK);ߚ/x3X *'"7۷O>dcV͡| x]4p࣒zh7d(H+;odb.hX2d\ .QR0100644 oid.hր.$% iq㽅Ecq(K|xJ@%Z66QID5 $rֻºvN+//qs1S7r[M:_st9S ?Й&88< $.`U{eR~"):N#jAjʲ@B6el< Hr2N)c 3J$Jyp g>!-'pfJIeURReŶ|͂\mIaLpZ[ݼwdGx*xi fdJ?K)T,9Y8sr/ zxkHwՃqr?J*dC 6}1O1<.`>-`egI|ـ̫q_~ z4+cWkB|B2n"x̔7ٓ vx;n Ly˴CGY 4x';UvSN̼ͯ8W13;A\ur& nuxwoC"c\,+YeKxi f^ՙ.oh"dH8 !xǾ}HnJ~5yKZҿن; &xi t/bWO :L`TQ |x:_ޡgC#IF`MqwsmdjMK:;HH<)l,xkTAk. ]x3ѷ՟BI:JD @pOt J n/<]x{|[yCdG[xX;oxvmH) Lb6WN >WmF/>f Fx!(q$FG>39X(x <3*kCb\P 8x5b yh=8nڋG3`Ѣ^E^ox{zyBɩjxYsqV)9 ZUS2RJRSl 5LaY~fBQjyf6LT$ɇ(x340031QH,KfXbvVϵ[.ݨw -3'5sɱ]gH(7oN׊ g :k R'vx3Q?gd]FIkR2RJRSlzΌ\Ey~+#grN~q*;k;3xi Y''ۈo1YsrA  xr5S@.yʹ|y19]蜽 C 6100644 fileops.hF)EnpX೘f7!F/>f bx!)q$FG>34 zxl;ɄhvcQ";_100644 api.doxygenG3i߲GёE'6ƂMTF+ӆm 34pU{UfUgjKEz40000 testsiM/ ~hlǸA+xa'100644 cc-compat.hVI_^*!{"x[+JfW}--T3̪T<`=-}.Դ̼Tx7Ox7`אx'ϐ`Ɖ뜸+KK2&>132r@2Jl"drM1O>ΨĞ TYI@-x[%LfC#gHFf^nF/t]x{a xvmuM8g>7!D/s+Nk4wV<Ɗmyy/lb!(EO^_0#RKs22O9pk sNV oxV$S`S\Xaǵ/;gQjIiQ֬"%%: E Z%\Փy= YxtKi fYz+xO1>k9xZ[\GV(lp͂]{{#qb#(Υ$sY?!v$GyoOgϼRYL=3c= iyiJsMKGTMaL$4<W%-̈gD}IH4'Ɲ64ԔE5JF sR&s荜>kZէUrDuV!*)](V{ -I\QzNAY~L5R=)x[z;#)Zh%*'wg\FUCZMBG7$(#KR 4l9L܈AJN+E.Y ɞ~q:Z6,򘭫фEظ&e_y/~̖ d-T,",鼘(V#*Ӄ77v_3Z)-)7tֈINSUaBcuΚ'(|K W~ 8g?ۨ(+*.0ir+ $*Bǫy ^)oZqb FzX}X5Odlɓ;7+xd'2kƮPi2x/S$%J}JZ<9c5xJFrPPD7QZaǽg/\|Bt#%ޢ4,|(HHCPy;,VMR|6'( pEʠ:KW 9=ahjD撃!ўq]ُz챦}b֓" FĴ 1v K*x(5oE#G@ %*?gH1*,"U41M@LEWLHHךѐ]SD.O~#I:8 htgrEN'8O14Ѥ a4XC?z.?4{Om8d>…<&N8Bf%AtqhICE$)/=;Iq䋈lqUQ;X%OCKhŶĎF >8K-Bϥ!yjX_l!BQ9T90[dNbmWSP֨{$x/߅;E *#TVnfFA#@*Zzw뉣ߐtS:Җ pNX (w\AfP> ڙdXCGI*GpDʡVpӫ{^ ONP,:Nz7o(2- ۺShu|a&TD٦$wQ8Vt x/TgXhJq31{rNCh>"čT쿏fPYBtT}Q~|J-޺nP6ځa8f6GPc&Єř>qRڹJu >|{ХQ^?h7ʳ 闙M\lM+h8Qqw޽;ypMK nbp&Dkg,j1[X'i@7rA_]'/]o7ل߼K 5>xYW=\&,u˅B?K 8/~~sVCH 1]h='Y8#J G1A/Uy -v /8 `:rv~Dˁ _:p/=]*磇Z JdQ|g#ݷnDNx˪UI@  A1ݫoPqH:1r}% qıswWjQ2h^믿V|}W~ǧO>w;r={|pɜN, HFw\d\94g\,ذ) GFRoE^.R|/bqe=y/Kd1 YT6(a1!,co0TV{ ѦEl"zߪΑSʊl;"[eR%ż8}C[tu|kqβʀO3j,/p`x/ 2-jr` Cdb([4/HFGq9x9(Hkڰ=p!!d(LkD*!)Rb,)Wx, ʐ~D' ۈ! P\ E 3 ]RZE*uQ##&r*Mt3s^=p%#6wxՓk_W:[,2A]*-RY)1svG1x?z- ōQɟ2'!B}mNJ=\+mDzq& E=(3ʣO^L os=Bhy<k? YB9sB$ [[ {;Qi"t C[}>!'m }D-wؘ=qh.3,$7 "4_RpڷALWLYwm)RNJqZȕ' MIfVAZu$HI|1_B7Q_HFҘ/F}Ye$K&͎b q1is oP]l4\ FH[n`蒏2{0,UR%I`apQTTĹ!ZY+({3=O^ORze gzZpKZMU'w:H礭U=7H9* jg$AwՉ-Ȏ7(Dו=D(ixM:*2Eʨji*yz9Raj.'y\%B J:*L6` w59+2\%8p:d~1nP ,گԵw[O26J!iZ5AZA5@LᆧGc*ZK2Jpn%g0zZ( t4tn= 1_ر]<(oAo6EP]YC|OSj=!ݘiCL/b֧@m?yx~9ܺQߩsvTI?_+SfcHV[5X9c UkSM'l6Z'bLzOZK*ة LOa R#`\Re/)3٥n?.ԫ9|Vٛ@ev+(D tk1([JvKȬ54RգՙVOk٬A_(G98FNX]$2N/S/'jr2YvRfej^WroEax+uFrl'XD3Kss6s s Bgxi If7{OIf-b δX BIjqI1[Gze=n sj x:{nU;:~+hxk {q#Dó~@.|cx<4p࣒zh7d(H+odb.hX2d\ .QR0x⳯xV]o6}EbntۓۢR'` J,T\߹8׾ _srvҡZQ IR3+ԘT9oU\{y:=3J 8u*-\tdj+qVN^Z}!UlrRKg. S8OI#&TȮuj l"jhe]BʣPSHLY#{:5a+jvQ>'gK5k+J")>8}~e;h)Ci5|K9%.pRCku%(]@1Tu=8R6> @2g^Ĩm#>ڜQEAq">c|o Mh6Mw=^*Dо0e.w2.t2͌Ft;-z4f>s)w2 ǻ- TJ/Tv+Rie"!4U5?@la 䶵Z7w %GOXf7&7}BBGiaK!ea :gg#ib Z1P7,T$. mS}La~ *.&P -R #c .ֽSJ2?~Η/ъ >Dک5S ?_v  (h6;0;mQmQ'51W89yzHeucm-f&/9ƀ0&m7 G6hzmV&n|9ܫE&dz.;.ӽ&,&iz;W'u*jCNp{јJ6Io39%m! UaM>`tҽGCp> :O`cQL oT}r_ia|}B oA!RÛ&vsp1?C|</f1Ktu߀?41R(+=fW>̀@+šu|C>)7*@6!'ђ?BR`sVf?J]#n@h419S6-eT{bLfCCyd~Y8ڨ 0{׹HYrF%RڤI}Th uV Yѓ ldi O 9?W7#SI/ qDȬ as8t2"-iB3SC?y,3gnJjtF,)p%$fv/Βgbx*{]jC8/ .%xvm?yq? %9+#W xgNx[itX}aa L_xK5fwaw&)^V}0H2VFIZ߮n݊;@1b9"5Y*~gGBF=o$^ǰxO,LO./)J,KHLJ,1+HD. {^lZxTj^/2%x5fxvmHJr~?W\gb`@F/>f5x8ʿir S)SffjMlgzxiC Ⱥֹņ kdnPQ8MQ5}5KK>.IӅhͲʲ1]{˹,?Q͆\4+amZg(~}XC]^Xj%֚Z\("k!S x h+7 ߬npślHr,4Et:n#1Yq}Er!Fe^a_8h}Y*>|$' ?4|خ&+;8n>N{~ybm7ÝhAޣ S_liz6<g9߰HI rՃ٧{ `bD= &E>Fͩk"9sey:"!8zJ ݯ[2S]=x-?]r,*eVpmNgg|Eq[N}QBbAfJ~r1gQnVBqQ>J,13 alQ0vyf頢PZ\R DyEy%)E%E 9y\\%@U`'gs5u tĪVfQ{*!!N^ Pk+꧉Q،UTp  8 4r23'f1A3 lxmHS-rKwt|T,4q &%jx;gBƻ]>mef\n ~= eSxi ȣ*I1YgnNCbr/ #xǾ}Bȕe*J捓h~xk5fwaw&)^V}0H2VFIZ9հ+y[ql3Uö͑4}Ld640000 tests?B@dZv!T+N5IxH'100644 cc-compat.hʢGez<;p޹됑'XԹvV?}" ԩ\+k`x[ucdVgxi {zۻ]IY> 7xJ'100644 cc-compat.hAA݃姹/p.Ŧjȱ']tBS^tjpPp^'H&@RxiC 噎JS]p_ ?x9\\~o)f xRȧbQ&va\2 'Ax;#'us96 ~A!A~8X nxi Eo-ȑ >=-U !x6S}引#|I 6@NRgIQPsx[%3CfsFɴʼd̼Mj.΢ԒҢ<WO4es M.3x340031QH,KfXbvVϵ[.ݨw -3'5~)ޯOO|κmsߓr j3b7H}!s64X:"r(ix{DziD /Fxi HgPB+/O9 ߏ +x{'100644 cc-compat.h2M?YxEW'X2gD>T ,M^aI(G $nlp,p3 9r(z+2k6BMr<1kyx[uu~, PlxG 7=( <ޓtypedef int ssize_t;I cc-compat.h"vO?x;4iBT~J^CN) ֫#d0q$A`xk{ûy4>06561Ts+2r2RSRRӀ<wϐxO?O?WʂTMĒdbf#vOz}--Լ TIJ̜ĤTHf*hAAA ƚ\\ cKsJJ2RR4?Xhi&'qy(gٓq)J`xx;n UJJ|K')xi HԾy37-nfӛ)}c cxJ'100644 cc-compat.hAD٬JC6'T]m'_Z %_/~Uu< +x[uuC'2JNvdZW3^Q1cYrOR/٬ab %% g:Z7*[FOyt5.0xǾ}CtP %$J%0^vz/ol([-T"/.'Övz?kii3ņ5=ci3tEkaDL9҃(@-TnEUg:?3,x`b5gSQ;MF 2.xi IcjnM}W:(%ПKJRKԇ?jX0dg7{fx:=%w\aw}x͚Qlrk}ySeV7Ť _<&z!x$sodb.h󮽿Swv4#&6Zw_xUoE#TuB**Ķ"RBڀB*LwىvgYᇶ9υ#7 !C.H ?S{BěwQڋ5{j?Yp!OSz5:eaEqnK%tЋxjA64!p@ժ'^1Cmךw}}[|ܼ6{nqtknѝh>O߂ Xӟ7-{ny~c@3tקYIAWO^q26Y<o[fYxN/<"-6p'KRūvkNC?L/١ ;Q7;ݠOvw׽br6&Bg$TG%H%(;A 0(Eod(qDA(P+DcyDt{D(Ay=ܳQ`0 fYdO|36ﵐK*@@DG+.|۽!~Gg6eUAzH?zI0&wz ઝL1-+FmV };ARdK9( x;qB Y7۰%gVo^(4d{?'u mxc{:D ϕkT",Nwl8gr4fDgPxreC _xi HՑBl_띷ort DxF_9XP晩BxpK100644 fileops.hVd U-衑 YLy+}&USlKxS}~\l%x!Lz(}lx < ҊCZȭHWP 2x6ܧI+u{',BZ,ipF~Tbr0x!%AQ&(/_/ÎK93/94%U4/$(6Y$X UQIfn*PONfXQf^:XJfQj^ ~ۓ?1U*&($)hsqg(h$$Z+((k) I%`̪>: 9y: A!A.: A@vZBRjzf&Ж4 $3l43S4u ';rM֓4 AgY Z@%\\y a: 0͛Wp<KzMxrOyd)v4̒<wϐ WG1 >1OKQHJMTQ0l$5y" y@ZA h&W5'Ă<u9q7)sxi LmO9nd9<9QQ r&x!(ep'><ưH<sx;qB Y7۰uyEo~xiC &m*z};b"l x9xe4mÙ:69ahB.xZ[\GV(lp͂]{{#qb#(Υ$sY?!v$GyoOgϼRYL=3c= iyiJsMKGTMaL$4<W%-̈gD}IH4'Ɲ64ԔE5JF sR&s荜>kZէUrDuV!*)](V{ -I\QzNAY~L5R=)x[z;#)Zh%*'wg\FUCZMBG7$(#KR 4l9L܈AJN+E.Y ɞ~q:Z6,򘭫фEظ&e_y/~̖ d-T,",鼘(V#*Ӄ77v_3Z)-)7tֈINSUaBcuΚ'(|K W~ 8g?ۨ(+*.0ir+ $*Bǫy ^)oZqb FzX}X5Odlɓ;7+xd'2kƮPi2x/S$%J}JZ<9c5xJFrPPD7QZaǽg/\|Bt#%ޢ4,|(HHCPy;,VMR|6'( pEʠ:KW 9=ahjD撃!ўq]ُz챦}b֓" FĴ 1v K*x(5oE#G@ %*?gH1*,"U41M@LEWLHHךѐ]SD.O~#I:8 htgrEN'8O14Ѥ a4XC?z.?4{Om8d>…<&N8Bf%AtqhICE$)/=;Iq䋈lqUQ;X%OCKhŶĎF >8K-Bϥ!yjX_l!BQ9T90[dNbmWSP֨{$x/߅;E *#TVnfFA#@*Zzw뉣ߐtS:Җ pNX (w\AfP> ڙdXCGI*GpDʡVpӫ{^ ONP,:Nz7o(2- ۺShu|a&TD٦$wQ8Vt x/TgXhJq31{rNCh>"čT쿏fPYBtT}Q~|J-޺nP6ځa8f6GPc&Єř>qRڹJu >|{ХQ^?h7ʳ 闙M\lM+h8Qqw޽;ypMK nbp&Dkg,j1[X'i@7rA_]'/]o7ل߼K 5>xYW=\&,u˅B?K 8/~~sVCH 1]h='Y8#J G1A/Uy -v /8 `:rv~Dˁ _:p/=]*磇Z JdQ|g#ݷnUCNx˪UI@  A1ݫoPqH:1r}% qıswWjQ2h^믿V|}W~ǧO>w;r={|pɜN, HFw\d\94g\,ذ) GFRoE^.R|/bqe=y/Kd1 YT6(a1!,co0TV{ ѦEl"zߪΑSʊl;"[eR%ż8}C[tu|kqβʀO3j,/p`x/ 2-jr` Cdb([4/HFGq9x9(Hkڰ=p!!d(LkD*!)Rb,)Wx, ʐ~D' ۈ! P\ E 3 ]RZE*uQ##&r*Mt3s^=p%#6wxՓk_W:[,2A]*-RY)1svG1x?z- ōQɟ2'!B}mNJ=\+mDzq& E=(3ʣO^L os=Bhy<k? YB9sB$ [[ {;Qi"t C[}>!'m }D-wؘ=qh.3,$7 "4_RpڷALWLYwm)RNJqZȕ' MIfVAZu$HI|1_B7Q_HFҘ/F}Ye$K&͎b q1is oP]l4\ FH[n`蒏2{0,UR%I`apQTTĹ!ZY+({3=O^ORze gzZpKZMU'w:H礭U=7H9* jg$AwՉ-Ȏ7(Dו=D(ixM:*2Eʨji*yz9Raj.'y\%B J:*L6` w59+2\%8p:d~1nP ,گԵw[O26J!iZ5AZA5@LᆧGc*ZK2Jpn%g0zZ( t4tn= 1_ر]<(oAo6EP]YC|OSj=!ݘiCL/b֧@m?yx~9ܺQߩsvTI?_+SfcHV[5X9c UkSM'l6Z'bLzOZK*ة LOa R#`\Re/)3٥n?.ԫ9|Vٛ@ev+(D tk1([JvKȬ54RգՙVOk٬A_(G98FNX]$2N/S/'jr2YvRfej^Wrotxi rλA_ro>z;d#&@PZ\R /ڤݘ|O+7x!򩊈3r}rk+[ᴳ&l+x;*T|C), Ex{uTWykwm_aZCxmJ1D 3q\ nE: ֕! aAM!F}I[*'gV#%,[py4 +}X*`  ֧ˍ,<w`Լi;ơNS9x%ܶ%O LOvNQ< ]%tUxɼyi:G{` 8NJ!2?t #xtmRxԼ->ۭ!uR:.R0!A={߹>_}lxi MvL_YT8F bx8"sX>}[Wm2UgM!& HZ.n&lxu>͗&xx.A])7@/Ci!F!̢Լ ;..4ŔԴ̼ x'O?ǠHM.eLDK95/%3m~ۛŘgL~ksG 3, Bhx{.Dl*#RJfd Fٌ8S{Bx <lH\樸A^,Z{ܔP x9 w9X_VK16?ۼ(܎ / h0-ɜx340031QM,Kf͈)R YfH(c 5x7ʈb$UC;]4Ul @[5O)zsuPIP rqax@[9-lcrypto rm -f src/sha1vScr x|0_ 26iQ+Y R9aPvf.`Co1100644 fileops.h9Yc7- !-?%100644 fileops.h=ەYqpwKxMyrf^rNiJMqe~nnb^D E%%: )k72jHx@yFLxX"Aq FCBr~xiC };o ?aeJ{d{i6O zx{ʺu"&e|@5Ex3V?2 `Z,4hH)x,P{x;#Hn:ɇ7 f=wx{e"FߢĔTd'/tcҸXlB.?XR5];'1Aw$xVo@V+'B0J;JE!Z"@D( ƾb_,HY  V6f6Y'ޒ{ޝܤR|%zqvbJ_79Mg`,HhR′# K5 6@Jç`VK㺐;} @.RlƐ@ygJ-aIx]h0؁ϰw Y ][:VIDc %E Ra4ְDhJ(Bm)!3lN^-RG9q_ȥhܥY$hGGϖ)C-'owZ*IBY9i]^.?~lpc<em< >9ixrSc>=/yS \WGAqWfVӲB5~x;EFL0D-^uY{O/7UQjl9ɛnlʫ8zgyzQanVum-{ۡW|ndIߧI[RpdJ7C?d*Fv$Ȃx$țF?/Wj)>Is;Yk٨0t! Z#6h'q7!!,[XYZѱV^/bK Ė R5!;2'"[eR#E8}ζdj9{UgYev8u7 n⠥ŀZ╌pY-ÕalMT& P\ R|-zAvlsDe5Mdt~.t#Xtbb-_х!h;b\gt#DW E _O`-+T+_O@Q^\vРu2bht_RU W#cWI긚Ճw^ݻy˗7ol!&0XvuJ*SdFVaMKـ.9'/5-FꂋWS!*\yQu@vyj'JE^̡@tVBmJs/.Gqd 4Nfm Q"wԔ+xXmV>Ɲ@y*$Ex؅HMSti & /!m3\y'l0)FDI" VlD N@bj o!o?trɛuRh k}'H? ~m?6> ?et2ZrrGŏ@`:I揙AvO&3~˕2o;_?$P Y틔|2z$O֞[A2A+E<0GuAF 4]AY]"$4InnbG ֥JdO37obL+3 {DR9R^}i>CG9Fp2"T4~.P0&`9ZBJnX@٢2,!*bh|^r6p1vY^p w R{M%+Z P B%΀ZPm 0L] Ϗȴ]i3$,F\YjR/WQۓΖ@ݩqA>tWIE$u,.$~@u JgNtz<m`D%:)5k2W"" @ d^{b<Ь U(Ht(/3ts_@JI),OW4ySzZ&͆bPh4yqj)gF\h6F(6ЊA70MWR-#wKFQp:VkTĹevtW3w{3qϭH%WtGc-W^Chҁ.LA/c׺.ҁRtI{z܀@9)݄琂O;TB`*(2Ӓj"'-yFtRȬ߂ň)m@^.ZJ/R_dkX`C*J B'{\j)%6)栥@`w]sdlqt j2o0VLm~&ɠV%N!=صBVnQ5 M6%s4 &7ZJ\ۀF Y}z t\C.52WjPXXmM#sS/:8Vʓx"ݩVNDW1RB7k#?DzYK!ZSi?TƒE.k>1wΜu?-UӦa 2J7'UIaZ ]%%|Amvʮ(z (Fx(U&ŕPphȮSͮB+$Yf @E2["M Ut3,ܛG*+YDPeњj)둀 :oKɥ MM1gCS~N tkל-^,Fn1M?xi 0ɥ\9M~WŊ P 7xvypm'f5` hZ}95z*+6qf100644 fileops.h7L+wJ-P#j`wo,WEDK-7FC1*x{yYJ2KR&3J+奤)yq)+yy0R:L[)kAx|ydƕ  x <.z5$֦&(ƼP B xjHR} ?*)&4“Al+AQ!RO&N`g47  1#%I)N'X"@2x#UhC& L͓YV;l+xNy!ͧu)fx;˷oC d6m,L6AF|#xi Gܪ v0o[ <9Qs x˶mȗ)OU.{zަAAx|\yC.KY~f*Lp n`|_ ˃ *x7eՄ6GhWc훤[G0P{zY- BwP ]f1x;#_rBhM `PY19)}5\Y7cb5x9Pɇ7:$룧Yb8$IfF P x=>w%vZqSRQe-,3 Oᓷϓ;_xJ@/^'aT4ў[ "BAJY%H^xqv[Ӥ%avt>v˝2T 13Tv(HDŽ(T#ס~7\w@}HH*͉<5hS;|LRWW&~g*89E.z:2 +{Gcj !zMY\3}Zn6ԲH)ZVH*`=|0jȘf75طn(3ehMd}w Fј>HlFjd;j3.WH~V\-*n.Dr|'C0~߼MtYPE,;1u|xiC k ͛nt>6px pxMAOn豳ȣI@-100644 t0202-readloose.c1 Z=֗^-hݒsii"nx[wqM x\C\]]4 7~ٕ  'x;E #IŚGϣd` 0YXte!F"D 6$h!322~w`tw_UuΩώ}vo>z4n>{ݹw?[ݾqFsfvoٍI^[~zx/mw廼؞]=|{w=8ۏI^,۳9˰=}=2m)[뮐W|dII[RpeNB7]=gd"F,v$Uɂ xd7e~o9OR|/\簱w^%Q!ah$ jQ-\<9 qamJPZz[d`'4u^ 9ޑ8*~8m"*y,7E'[Wݓ:*=ݡՐX^F_ ,^ȈB7ar=\ދl6hKnHeR7AAS/ۆ`b?dq"靹 @=VXWt,Zw|D`1.`3 "@+mNfvjύ'0l pST*_@QV\LvA7jd 73v9-F&?xq1U'W;R^?rՕ # ˎNIY$*9&YUZS"'1u2I Jbj e)oEgSrμ\2 X[acc>Iu"'efWYdދQ6n^*]9oȕ,{~d ԏfm I*"Ә)[lZU>ƛ>y.*$Y䷗֘@cpiŀ F ' Hm)]yug[ɰ `bE5؈Xa: !*/V%XJk\7x&vLG~:yk_n(HH#WCHjg_;{'Oz@>2OpD;vBdo>Xʭmϳn|śԗJ4sP'!D'Gʞ))$쓵Z!MB0Q8oPWAvVA`CTx97ࣆlm\u%7ss"{ 匈SIR0_mn>C{%;Fq2*|/~QK1H`|r4xEaXB!*V+,PQ5& b욒NM@x*_5@,bBQ.P B)K _qI th2 "PY+$q[Yc.8u;E.ȧ4KC!yRAѴ t] 8o`}pܙCk'2%UkeNqM̅]$PצO"4 H`*.s=p7J0\. dTR,*=`-&C1DEz7\nnqPw#.@#r`h!gr*-[Fv#(8-+E*<}+șaz:++@/`Ciҁ.LA/C.4ҁRtI[z\@)i)1^!.wX =°9bQe% EN+k$H阤I]GSz2*]4F^D?ְtTNRrE7lR:AKсfD$pXPȟhPXGʷYE$jTHw`o2eEՀ0SG`P.%TtʭR2B:4INCgğԓ'NFrV-H%mVJ /h* z)]~UdTCdR-t$zjWb$oǭY.87ZJu VOC @Hn=(Y s3$jMմ*t pkk{PHWb ;6bP\N. Vǂd0*%J)q%+5(:$w*jw}ar $7],r- *cv}zG#ƕ,H⎤+h@H@IyO9Df_rBqO~Pƅg߱{,^]'w 2I#dی߹cCh!x <=ɱ°kfNJl鬓P 0x:+QGe}gUƳ*~QXP- p8 ȳ$"ix;4iBk@%xEcC1f+L,!񓕹 `n3[a|60txA 'x׈#[ ܚ"R[d$q'C SL(R,s' H޲xm+pe:e?[DmaL؉g]0iA^.1 DQjLYMi~戉PiԻIOOр!J.[ъtVAH]rܖɥfэ P%s &׷ pzɴd/.pťhDEԔ='Li"_}w2L`ox;ѿR%dyJ@KaF)fF-!-n\Ŭ ~-.wz}3 H %$tSg7ᥗ] sO{q2BAFZ}b};Χv'qqojE;.Iu%*U珝o~?͓+xDe<&shm84كhs e66O?O?ɡB*\\iEIYv)%\p_5W*!T]xSAkA"DmxIHS<`X"Bmd΄نx٫'? rBWvI˒{~?}]o:jGkuBp5-îu\n;z=xoG{Sm75hBw ՃKxod\& b/\L=Vhe`Np3BE$ }Yt ,0h_JUc͈NAi]A76o̰hfhtQਕPf7v]{{t~қYEmĞCl Sj8_ q|oڟAƙc88}|܂DI6ODHg㽗V'4zkOˬ䴧|VFC/cxd_NCf Uja tufW暂pc&{ȳ;OiF U M4vU dn7x[g&ΛY=r0rgxi H3@˓Gغ2RUx Dx!~|8̝\ f$$ADxi HJ,neي 49Qę !x6m3F0SW6COE5%M~ͿU,%xi H_ RKN\~V6mr4 |x!cY${IUY $K]x)d|N?4.!-^x/y^rX8rS2t &aiGpM^ƚgtH.PM¦,#6ـ.y[(VxϨ6%ld[$ lzx;/WrͧY9$sx72c{GلfԑgRW[/Imrs+2>Vx;/Hr70m>4ٗ9'3i"mǦ ggi&o@RwMu2?d'^H,x7:QN*( V9gRW[/Imrs+2>È_x[$Eb`Vvꜹ)E  *OaSĦ Ģ{ٔ&bSy&uulacMe1xiC Hm WTַ[:i; `xMAa-on{9100644 t0202-readloose.c$_ r |`;s E `x[zq5z̼ҔT⒔| ;.$TԢ<4ey@hZ+KK0EK* RA ,v56{ƈ1nNb4arv< 3y:lx=D5 $v%|X1Anh/D@p 5"$3 I@܀qtW7dUoU?yw9ʛi3ʜ|.2H3N$o{=8w KƹNBw~9n$C>we!FyfdMY@?bC+Fؑ3ÏRaAވѳ֮;Y)G &2%_Ճ2!xWvtP"ܘř&N$E0X#YH7qkb$'g y.qh Xf%"wv@`[rTMd{oXR&Cq6FZE~o4[ۏc` UOJ _zx:N=dHޑD>;$p/[R檠f$Pݢ<C4 F2ʓ~)h, 8P)Ngΰ V5d U &bLi i.8w R[gV'( HOڑF\苹 Ft>b40C-Mj-#r6Wv#(8m(*\ܨŕdѰLG gr7ZUJ+@/`ӓ!δ8t@%k W@9sYmkZ[}I\s6io`g[V100644 util.h KT?K=F1ӓgx}kf0^lMx;s{FLqn x{e&y ˘m}x~ѧl9E g|xȵ Exi %fSWr8jز>2brҵ Kcx6m *nB)XCO׷ϝqOj ~j x*4GhFnx <@+CyHT愓P joxvu¬o?q0xi ȑU^WdywfBF6 0x#+vDA+Bi8"{$4/,xs2mlQjMn6OIMOI56HI,ITVLѵL65TQ0TR0,άJ/QTUc U0402OW`9Fזq\=$&'˛)hVKK/-ΊDSXAW0VSsF QZ.]d'jZO3$(>y:5 T54J3RS34 @>M,DM hct7K1Z` Dhbif^0-H%&+!BL'7ȿ012PR@iR=sxi Hb* ;'[er԰ Cx5A.䦧AVtLWʐ;髭Ҹ 8l;x}k̖L{xi H͇fnElSyxE9RK}|B-q100644 fileops.hGQFOQ%!yxMOJ@I$B׿"! "ڕ\,af҄ILMO 9  ;)ܹfZAw}~Q4C˟Շ(\TKn2]SX+Ld<x6VFj)lte],'\Пk~$lJAjWLx5R`9LcEm !@IAȝ93Y/NnEz'#FRՏuHEP\ i ;M`,VXR|r7*x{ؤa(&.Ԋb"ĒĊRKJKK4@: jI2?+QH,IˏO,J+D,άJ/Q⋫ Ziye) Z:P4rĢtMj<[E@\.A Zx550K&Uʗo.s`dlï_Q x[$~,͢7[qd0;xi :ET{窽rη~Fm x[ͺuF6o( 9۩:w+w y`xۚ>k#sUf.mM5' xi s3ϒt) [ x9OݬW\n#R@.|pjjԼː_O8x <Aq弗}x]a!ɓP wx So."@QgDax)8ApC#g|s|?V7xi HL9'ٷy$?eg ux SuC#G陓gD~x)8QpC#g|s|,_nd fxi-psS-2Lgj|Ξ : x[ͺuFA b .'ts]+K_xi B*du|/~19QP [xE9gǵwɌgm=T100644 fileops.hrlZ2A/v%El8xkRܠa/}<" lx;?י>#fxi '6ҳX~X1v V /xVam^o(8R66QGbRQCu100644 util.hiS!=dR0N:X&%kPx|yC:z"nox{uL34lkx;sLk"Vgxi t+>|2YN-L)&@PZ\Rkn;";ˌͽ9U1eYuxcW]Sk.*>100644 fileops.h3jNF'Q,1;y>40000 gitR4 L,WLr%ԉCh1 '-x;ɿgd5:ʙy9) JEEEzJ\̜B%% @x34mw%)iyP<Ē bM .TE%P) "ugO>ά^3 :k4lJK@UrԢ 32/hT k7d͛EBx[sk"d%Ey y% %iyy% E Z%:`i9Ś\zRKphOIմl<{5f+X?.BxuSMo0 =׿pM}-͊EK f2 )e(cD{z]U;*c[t&>XP#uɳlQp ʼnR6V#vzd#Xdna!Mtd*sݭ/]-/n:T2HAS9(gs 4f KFP>^y/AwۋQfD9iE^x<J1ta`O#p%l% l$qbAk m{A K)dv\|n[ G~"eKًP/NIRhTjOfud_NS.r݂5 Lݲbr}`=9'q~h8#)/Z ;bF SYiDJ0- ͦ/Pa=^KهpRns{\ R-[lXj8x{IJe?3xi 4soU\ְ-쭉(3~ٶF9M!%/5GA'x>u6d绊݄2N100644 util.hiGx=i51qUhgnx{ϼ lQx;cf.fk&j x{2aƟSxDV2RϞRx"Q51'jbdFFUQ'`Oxg7G`+[][U7?` pA=xibV/~^巙X/abk hx(zJtF--66x٤6ww-Qxi y+ݺ)F܌ 'rx!x]?Z,"BF*Mşe-xi 4&`/g%{ߍ>]bb %% tNW[w3]&]qxx8{M: ޔ'zG¥Nf,pɦȒ/ÓgD֪7xȼyʼnO&3 M^LRIx(qt^rNiJRzf~IFQjbniIfN^d7oV )jx{yBƟssxi }#_Z X WHVN09QD Xxi;k+8=WE8ۧ4A]YmRT#i 4Tjr␳s.m=!ƾѓCQt;Ӿ<,ΞZ2AxȼyFɫy&WM|RZ39QfVFE Gx;tiH}w5lSS3LvJJ Kx{yc dmF1,!A.'cZ49Yvr/X4n?xiC h WĆ59bм( }x{̼y.kL QcQ@J7?)Kwov({RNHQjbdF8hr$c3oxi H)x i{K<]{{r -x[ͺut&|wI]ASCܞ(Y19x}6`Fɫ7321Pvxi ȷlٲfR< vx[ͺu{_w~>CY LLR2N>fmґ2vF/ZO]j2sR R.h8T>}u9 3˾{]=Y*Bzf Csgʅm-۾( qV˯c3c#^7Ckbxʾyrs jmxi*>Ux{M~d9L@T6(("%i%%Ii1+$3?QPRwRH-*/RHKKWҟEEFAC)MV!71''?Y#'5O{*~Ѭxl8ٛ=w^!22󀲩 e)U9Yl4YwL>o&K8x&E~!gHFY~ffg )x"E~7U89kj44Jl3Kssr5rR& MNe,?9-|M1 x;tiH`9k>Pt*[yk줉akCx{;wbJpx <MEMu> P T(x340031QHNM-H,`p-v\^ΗCbs ss3K1]x?oŝ$/*{z`󡧭)}]]a6Hjjl"K+Ԯ&ϘjR򋊁v&=#ѻYjݜlj2N>fmґ2vF/ZO]j2sR @y\*JLVخAS0r}{cw+}۾^ PH,a\ȫf'J=֗CH,Z.礻٫n}/ۑUd0l.<;3s>ڟ42TE~JЈY y]t} 7O)L*hc l29BK/*(J-+O*j:U'볇}: /OoXl &Z--iģJ2RStKK2s@wҵisła8DGlƦ2Ar~i:s7\vbb*AJ*\'_4`BJjQRYP\X Ulľ???G!=$(ȞK5x1xk+2BzfI|QjY5C>gHKrj^Jf>x+g$G6̒Բ {.E$ ]k'xsg}?X+"<1xRJ0xiN> m]PQ^t 6%I(!|—0IjmǼ$?~_!NAb!E>4#љ%J*!A2EH,rH !,<:FcvJ#k.$M%Ŋ2c c{B1g糙JphJZ2 !Z/19cl,J0tU5]fmBJ}PC&yV P,(b.Hꤝ̵Nv3ȇVƚ1[S͗lGm`3юƮk_-W^5]c;CwK맵w#r2BUlO5cx[4tfIa6Ĝd"̪TmCMS9Y'/VuBL J7x <+w:>9P Gx |" gTLГi^x{z(t/+KAbIV50krDh#V- ֜MJxi HV%U}<ӭr|)Ӛ6M~r Xxdd0Q}z=6o7c>yѲ kx;z t<<!~:xi İ,Otԩ[F Hx8{⷟ 7F2P!;%MF(]}TW0 57x[iBdOFLf Pr:x;3t7SfNy$xAmxi K)[5"m(3h8v`E'OkB\$xt8\[%*˧aAgT100644 errors.cH3ɫ ǾQxډg] 3CQ2P!;%MF(]}TW0 _42wAx[ʼiBdOFקLf Jox 'eŬ3y?d&͋1Ex <eO_wM5P Nx\9i Pm@LsפmP7100644 fileops.cEV +\3 4Ւ:Bxxq*#.̤b+]̢̤Zݜ#.紜tJuf^rNiJ*H Gqxi If?kx|VXBIjqI1Aʼ7cu{/:Fx9/hQE0Mk~a@h01CQ2>4DN {BAzxtDɾ6 D:J/'akx۩zWq! N.xzo3ܬrFjlxe~4!nc3#\vxS@cĪQ_+ͣc .4v1AK<*40000 testsYNuV-d](ll5x;%zPtC TTF Rk7xd=ʲqropjxe4xc;#BN$x <d2IE#[H\P Qx"ʧgn1HؒJK_R;x&C~;3KY~f}EX.l % x:5'x<> h4;IZ/3V΀+܃C߷R2>hxO,LO./)J,KHD.3 wnx;%IxmϘLff[29sd7 x;tibIC> -/v>cAx;%_`FNͧY'2ON\8ٍ+ 8  apxS-obRǾKE4\4GwӇ/Yv40000 tests yb5[M B׬.Ds%7Ox;%zY`F&4dt͓7feʹpW2{qAbQq*&IMlDx,[`CyL[Y# x9]]; @{2WA“%+=.(PM{1}JP7uqduFؾ ?)x;re>nw\_+ΌL #hx6}`DdyvF>TT.l-9Ѿ{fBzfIZfNz y) zz3 ?*x"qIbMlqLغ7bUqx gTTҶI\  >n.x;ti0o$Wm7Mk_nb %% ŗZ}qOn1bx9/]gIӚ|\#YC.5Ts,NK=U79W;x6}`DdyvF>TT. !i BqPMx"g—ɓ뙌 61]fڬͥv2Yx; "sN̒x ]X)h嗖($(g祦($g$)hirUsq&Tje(u3R`\\'gpxk#a x{xqdf^2CgjPoO9 yҞ=Bkx[~RffF!>SAx;ti0T`[yڃTݼdduF ^ x9/Yf\\'N1C.5Ts,NK=U7~'x;ti ^y/]%F)@Dhܬ +x;ž}33KJ~jdfIC)x7O &!r: yz\DeLyQdCӷ' Fdx9/E_DU\n5~L%C.5Ts,NK=U7Ux;tiHͳ;3g[['֏Ĩ׊ R[x[ž}.hJjBpcPkgp|PL#ܣ }lxNYU|Sj I𑷐ѻ/x{[&ĢO;Lx;ti0H͡6G=zZz"{duF Kx9/;D67K|;QoC.5Ts,NK=U7r x7ʘ@X{,\|owx;;`q/\N"" /2x{rGeU< %.̼ҔTYy b.xrMeC#& N[ l_ϸ4#_~RV|rN~qFzfId. "CxrCz$8a̼ҔT⒔$ Yyב [#x;ti0H={ZOW㑿a%>r: Zx{Wb[D8Qn}:V;100644 fileops.hVЈO#vVX40000 git)m_ҁ _?ؽ/q!C.5Ts,NK=U7I3bgx[+uAp j1x[ssBF.Ԣb ɿS&_grŜƸY Ai]x;4iBk@1x;ti0U52ܺxUȪ  zxE9YՒI100644 fileops.h2ֹv~P/yr#g% 7bg_x[+uu}& =`x[ų}BF.Ԣb ɿ'_cr8M tx7qb]Bs_2ÂVj\ i^SUەmE$O' $x;%:WpD;y{(*%g'eepq;y+hCdU45<\(%z2620 ah<)^AE M.N"Lsj׭]&?fB&=UmP{\&/-3]/C/3*[:7%U9~>2,,(hԅ ~=ސ]M|-=[.TM~JPku<%g׻kM{Z5k 2fJ4D.{y(3vxս3\ikK8\6.J-+O~Sq}j׮N*ͼ:;PE%E)%9 <˿#_^1su{B{k!?ʪLs߰Nbn*fR>QZ5BM xSLKIMSs uqO,OKLψReRK)MIUP;8;8e(RR2Ӹli3xrDz$#jxsgD6 x340031Q(ˬ`ph0;e=7*^ x340031Q(ˬKfRp]_dGڳKOo|Lw7)xj17$>©Тvںd6"ծ$N@I22BW}>LQA(ns?x(s9X. `J1+›.b mQ2H$W.tU o0>]?=ӣД -$.%ΓXm$M(+Y<}鴇wG$I)&X(NbckgLuaw \! [4pfȱG>'Rr>x-* 24%2?G[Ѯnd-[ @8&:JGq%]x.Lpr͏X37'3Nf,gtxBBL~< >U-x.4Spr͏X3''L~g2 NeC Kx;tiWi_;"OmW>,5;9$ gUx)I`C =xs! ?z#rj摶u$hx葛ɛvמWlx+8Qpf TVc+x;tibͣ:V{}=0QzJpu17Oj89u9:KxAwJ)!g?^maMjQYЭDFhF7xqlTx,^tU7Y(F^x[ͿuͷY2Nv @gx7db۝Xx\gԇҎ?X6l' b^lx/Z` ffsV",?xryBQT>~&@Y&~mŤ Xo?Vk-SEi&xqBzmex"ṿ0zTL vAA"Ek2x[žmO Z6Fx;ti03]fJUsOMbwc D Rxf$Jٵ1 A~&i\xxqBz%Iqx c?ϺUk̓' ]jCx> 31ubWFAbIqiRq^^FyfNJrbQBqQ^&ć"/X2Mdaws|y  nxx?!mc3&v=WGנEsXmWx:,ٟgrl1j=xx?!mck';Y]x7*p^ŋ:t&Vg\ԐE&.?g9e2Bi' Ҫx340031QH,KfP-:L @!=a=E3.znbB~JP{ߖxjsk3gG[d<21?XǏuRnC@/fkC 09g/(<1'h&O~ЂҒ̜bʓMs+Us8!w8g36 S-Kә$? &q^x-$100644 commit.hŮ69z$x;ti0(ג.J4'~~: gx.})ĻB~ jx4i¯*_ox^xGQmȝmlmxʷAy 8Ox340031Qputq bbՏ|~,q =E!TIzfIfz^~Q*ò~ ~ps:WDEή8Us'̂ξӊN\`,++ sg8qsg]t{| Դ̜T .vwP5z)y S5X_^RoߪYu,Pe@\XZ_T K~YGܚ~2sJSRnL 뷅r^rVų *6Ji[*nBdKRK/) sw\Y%cdݽxO,LO.K)MIO,OKLD NH` x7!=3/94%ubH?Y1YQIY,9?/-3]/%(XAV*9ѕfULg0biyB֗0,F7x31RΚWdo [x7 x340031QH,`ʡ̖lPi׶ņ5y@5 8{I}|Wm`槧|nph<0e)I@sZhk)XN~k70)@wrtt 7;L @!!ƫ nZH_[)TwQjYybN6ЄnZƣB+n|yG޵O.PEU9 G$KnUyv΢Olf?Onlx[ͿuͷY.0#` x340031QH,KfP-: !jS RNN~S_+~9;2 3!:~zw^jZPBĮmAl;L˃.J-+O0I'w7s- <sFMx{i8>gcLN?s{OyL @(a ou'軽v<ɞ Wx31vѩ@Di_Zc= x340031QH,`cVe/GG?y÷S&?Tq4\M^Zf^^f˶Ya¡ud@$jۣmb:aZuݸOdܝ; q3V01b7T?}k#Mm ˦PEe9@ζ{LoDfϑ/*9"Iv_rㅭʳs}b4(7pk1x%t]hCT*x,0GMjص;0Tx{yuj.̒$$kZk..@QjY5?dE,T |VILDx{i8ћ]_Y~mOd(%3|jk=+XdOFx31+S.N^T/굋 xx|3΁'R@ݟXq.ʑk;x31 B ILKR ,LEO,0GMjص*x;NhrX7QXCY x{i8ij?\׮ab[ܚڌv x31ak6*K%ikQ;p dx340031QH,`OD\i<D^ڞ&?Tq4\M^Zf^^f˶Ya¡ud@$M}8mV 7)ۦ4uK 3@T?m+7kU>11b7T?}k#Mm ˦PEe9@^ i|ɶѺ?aɒ/ULK*9{LB7Suz\إ<aolZx(t_h?,&Ԯx340031Qputq bbՏ|~,q =E!TIzfIfz^~Q*ò~ ~ps:WDEή8Us'̂ξӊN\`,++ sg8qsg]t{| Դ̜T .vwP5z)y S5X_^RoߪYu,&@S@Zڿ6׵kؖ|4(S.X_҅v %% ŗZ}qOn1"'.x(w|c9˜>.x31UeOW.jԉVS3 fxqg pxǴix5\5yӥJrL @(!\*u@⫤^eHi?9lZx31sA>V3\BLe|&7( xqBHM|ܥj]^kdܭmbxڤfV+FkSZ[x31y0#d|\w EO,0GMjصyj.x;﷊grXlYK&+z;sqki)&))$攤%+$%f$&)hsqg祦(#YsZOWd,ܡ7y{QjIiQd4'xǴi,xݾyiF&@P\6Kݤ⦅K/G|F&1*7ܮx31II;}nlyg%[Wr |xq.Ɗt)WN~^5c9U x340031Q(ˬ`^=GbW?l\x+3WjC֬ErO{YG)xo~ʚExxm %x340031Q(ˬKf(W8gcb+s-Zڣ #^xkX˿a6 MjQQ^^,Y52x340031Qputq bbՏ|~,q =E!TIzfIfz^~Q*ò~ ~ps:WDEή8Us'̂ξӊN\`,++ sg8qsg]t{| Դ̜T .vwP5z)y S5X_^RoߪYu,&@S:sYpc[|9gDEqQ2ïeB)wT'|"۴}ْbK-r>H']7WVMx31O|`+hﴱP_ .Gxrz<$);U%x340031Q(ˬ`a1at3uv[&22)x1N@E%@J@Q$((i+maw J) qE.Aͮ-+?ϭٲ鬨׷\bd@P(Q8j54Z&F.~}8sͼVwR%  `wGc*'hC"AZ3H_<:38aP/ Chk5ӅLf2PA5ncB C6Z\K):*&تQUN EhI&kCev(n3+O/a|J(;OgMh*47|}MZD(Zp="5bU|Cڡ9YgxoW 7vBK5ON%ڥx340031Q(ˬKfh4K^i% _3ͪɤ =x[˿g>̪!iE ֓H($hZsqrf)h)((Mɪ L++M(J-)-S(kj6 =&PB1`xǴi©M\ i?eyyH5(d%甦2nzW6Gm=8OCT%3Ln?i8ϨasoA%<Ȗ3|;mm8xHR4Pkux{|yJx31k_mV BxS4`r ˽ AwLHU1@zs*f)[Lt40000 os3cZdR"cB&%'lx+HtS{%x,MpC0kDkHEk..}--Z-}.wϐxW?xWg.Լ4.x340031Q(ˬ`0𧊨ӊЫO vl x&Hj;hVi#7? x[qBH@UJ'j]#c4'i tx;4id.c%&?FIae0l&WS@t8AZpQFcKF̑')gsx;)sB` gwx\/a=7 XxǴiH .eSz¬;¸t x9ن  ["ˑMsKonx;)3s6ܛ籬b3,IxǴi5k>%R qx;xqGf\mmt-} xŽ_$$>9?$5Xi V+YAiyy\ʙy9) h8RKJ j<Yxý#58$>yk8YZRZ``UD #x3ҚQ*dCsvD—5L:Œ<xw{C 7e&bU(I-.)񹉙yz\!񾎞~ \\*!>NVȒ9Iz *.A %!@U0`P) =! &'sq(8U*)H,).M*.QPQKQTCrGr~^Ij^I13Tg7Gwy9) .PGp5au2 *6)gqq*覡 XAB@m<"sr Fg{%|x;8qZȊw3'IS xǴisҊuHqg[`}3>{܉ x31-K\QȲw%t/:xqHה;_z%aND l xk#a>f/ x3c`ƞ#Bc֒*l%{wB;h->x31w/aedGvZS gxqȌ&oN:3r\|D Ȫ x340031Q(1d }{0Ͷٷy9+6*K-.Lb[xhv [lmJ{ K)fx3ugqQ3@V4lEƇ^Pvq= xpes:Z&wϐ"[B@x7zm-an:ꑷSlJ ~_UՓ 1))j]x}{F5&x[qB!%M^I4$qbQ sxk+ dqIQAlBBZQ~n|FjEd 7xǴi|nuzX}¶| jIv4x31mMnc~6iպq _x|UK&Bc (llxڦf>^ vNxN5x_Q "㭻 CIZQn!QF H5WتDX웒>^)xO,LO.K)MIO,OKLD.A |xu!WbNBNfRzf^"WrNjbgQnBB(Y_K/rS[L2V *N^z8U44́*ch52OVpDٹ܎@40000 src2؊zHV6Ρ w0xO,LO.D.0Kjx{2AkŦv'2VONcXˮx31=*ȥi:)z"q56 @ x340031QH,`y:=@~AcחG jj8MNq{H6T׍O7.UTz|K|9r&a9j STPՙy&jy=O TAQjYybN6Pk!/6Z',YqvExk.d&|!N~.>9\j2!E,$׺K>}`OW 3^8 STmzνu޴ϐ5ԲĜl3rZ-O_^zsUJeLx;#Mb|v.̒k58A")/`Y4VA~~Br~^qTd}ٓpIo~e8YG Rn^x&_tC\6q ʦŨy dii!pxVMOHW(3{\0 -;k;0"@0hv 04{u^U*Wň.+KjSRZTq{~UۮӦ*oZ77k]e͞6ٶczhg1QTfNT7f ?4ϺzdTfmUڧwεd6rS@o;eqS2Qe:1tK%hUu`3/3U凞)Ojûg /gG4ZߪY2 4:l_w 6mV(C:KTVg|S f+hMF!"g4-ZqU!6C*p ۚnpA(P՚Mq(V9+DpU(F&DދἈ;&xGXnR恈€5(Lc9YN'Hb ^JY]|p6&`P42d_5Y1ҭx9郵:i0‹S/^Lea?uğ{VvI܉0ƛE݇"F ;p֛̅3 ?G89& KA@\^0fv#ޭ7 e QEmvINzp'AUȡ,͐8FS JUujZN+3jeLW1*H}G_?oD 2D?GltvYAݯ^:F Ѥ Zos tޥ7]*zޮ JmkˬSšpJcc0d6o)^qsFT sW{mϰ@Y]>}i=v.}.7 }uZC$\WNzKLd}ٝ kzfh ъ>}qdɪƔ}XXxKdv:5Tޑ.~!OG2#lr~^wރŮ*k'߸hCc@.?T"ژP$zu|uxx(*!Qs{4fNN)&N̒Բ܊ mx[BcC~r~nn~^rf^rNiJRzfz6FkjxPn9oxRj@=F47_J =!P%KSpr(4v((E??tvqKvf̼d3rzL0NS2d>YΉD1f4V 4@vk7߶ך(7L܀IA/Ŧ('qQn"WiM2*u`On!"lbm&ZWike%l>͂+=V xі)i6%KeU"8^E5ŪY%]< @PfPCPH++RsaEUDzN`narTUuuZQÝYF4qYHB}xиܢ0p~qZ\gP 7*dg/./ށѐ*E>uxhBE-P@l %?:57eUE4W׬_)gWdx0;FRFo2o/x,rDdC~r~nn~^CZfNBzff6>ً͓2& rJL|:YP-9x[+VjC|6q1$ %.̼ҔTsؤ7`+e[3fx340031QH,Kfbfl0v?}*&?% .12}uNZ[d|.e[e>:-*(J-+O*`\d1q[٥% _U U8gxTn8 =oiiS`Vfs*\[iV -rf:Z("#囫\;ǧ07Ϧ{ I!x0zapoLy}_a|7$b8Ottcεvo0 pٶxOuqbGh\Zb]go ob8jdK{5% ۘ#}+)͡;#{'3QxgL$uؙ>oSqFz c/ͷl{;9lxgVzfI|r~n.L@58RKJԒu2Sjm=xg.d=6o$M0|xUs6=bK/ &dl16PNEPk,FtO2oz!i2 uMFly#S*+vFNDSQJR 7t7;A{mG;66uQWjJa1<FI:Y7UD8uUj!JT.(~F%*uؾ `kqN٧Ӈk1ݩRzP-Հ(E+)BͲ(2AS.L @'3\Yj(N\ i:N%ĵ(*r6Gi\u7Y-H>Fu6#5HaȠhM >vMl*X~Gݝ\=xj{q$K;oHR B ׶7(KfOJ<2 &EN$ Y63H<"Op73$6\,(I/W ~sy6AT<{ "9"sδɌ, {aqNouRhI?PC y=$#7[ ktƳ6c#ҟc>Eʖ;,Ɋi͓$tg,}˞m~v̨Ș:e<-2,qҴX<5<:Ɇ_I \am$F/l9f_ {3Çk ' ܆D{g.=|9S9Źx~UMYإWmu{=ecnx;7;Sfd1%x;Ŀ d7KKt83KSRXfdbMn>x.f=.F#JxV]O8}&}iK(0#i-!Z$Ueg{(f̓=c&{=zdTʻY]Q)*QDuTVu)o,r󔖕 SU,D[M2LRei)+R9I0LKA QfEJXz#32SIRU:/kjސ>J˪:[+xbQ^2&dEs)͢yf2e&ݟ2A S@jg2 gFLˆR"Yf"S+J*SRעzvǦs7(*"3P䈕 U"˖ FGmF> KEMnUVST^4!9{\Pb1*O׭ZD7$"B^[\xH]X#ǁl|(:,i^$mHV{~, ]<,/,4U:lwpoh0#r.cJO+րcfsa .+4; oa:Qo 9ٓ)$ ˆG|ȂsnX廾:SDc5LB-^Ă`2uqpB=-~U~0bİ({k@;ڌDUm% ]>dԮ.xȺP-_5Ӎm%~ӝsq+BAA{>p/2OK;Y2ݝm,FξFzMBp&OLquM_o{=WZth$`88z̨>kFmI;jч}l S[@m (i (m H4@dž>yuɾu~7>Z=[]㻱%86G1-]OQL;{U],옄,B]4-BJMbjNNKѫʚRg ]iȣ.{P}7zrwGc3M/H! c6OlxJ=j?2%'&a|kFWU;\,;'x!IbBzfI|~fJ|nvqIYq6/&J .x$Zb.f=K,Ly93[O#3xuPAN0! HȉBąS/qi-8 Pďx ^{wfgwvϿ.>ɈR/ _ˎ `Wηfd p`l+/+L#+߅/!,0EvP4Fv%$M Q!Ӽr^{r| L24>3>)  \<66-uCxH6^ #dLGko |ⵗvqBhYFob"ʬpK?g`({8~A L@-co.x/pM`CSfl3 x&pH`C 6ɫ|83KSR!ԲĒ"aUkPB(Oր0Y]JXA Ga m9$T7)cx;$o/mlL֓߳Isg$)h$M6fM [n2x·o.f=66F! x340031QK,L/JeP7>V%)~&O~ݺhQj񑕆o72٢al$/ؕASN;;2\B1cA&fe2tjo"3a.YeYI,KɯLOc:;{ځg-1KT8`tr9g̚k744~Rd~xk(sJuZfNj^bnjm|F|<rf^rNiJRzfI|r~nn~^PF_KSAKEaFN9'Kxb<(yKxՔX+ x{|y6sqQFrCx340031QH,O,Kfq}ƞ68%W\=s! =V?/N}aȖt`4uy@u'ox~ĭ䕅 wM8I]~Jҕ ɖLO)-qh22N>״KEvf!+Lpq {]UcÆc{6)`X/qQzo:@RTZV 4wq ?Nlp;m|b7 O=Enّkx&_t<V*x(* fNN)&N̒Բ܊wqUnzx$Zb7SffNLF+K x,rDdDً͓2& rJL|:Y wxxqQ^o٩MvKA}a s3x\<x3ajLh(e=lP=Iqٹ֋?NY100644 git_revwalk.hZ7(L`kEZq%[+!M(x9r jRt Mlbx(B`C#Nx39K )>6Ip쭱Mx)D.khO=@Pg/;x(ro\y) y % iE 9 %)% @A0'%)dƯ7`US_x340031QH,O,Kfx׺pˬ%Q|9o.uS>l[4uy@ujgۦv5"HVtr&Dzqdo^ vk 互ʂT+^MA/ra~i Z)I: yPet,* V)@ͻׂ e0#ȡDv.lxqJc[ؘ26q ͲA4+0]b6nx!^b7Sffn\F+opx,rJd'SffAN'F*nNx39` [cMuK 9đMxt_V:֞y M7 ;x(o\y) y % iE 9 %)% @A0'%)dU&%(4M$hBJfrbI*WqirrjqdW n. ִ̢,FH&a1J-*/SPpFLx6x340031QH,O,Kfx׺pˬ%Q|9o.uS>l[4uy@u}wX8O:oxO\.?% h𽐝jU3 yUlY6[P. !2o;I?]B-*I;N=xao6{SÎ)`08՛/,x?>$EEe9@Ӫkn۳IE1e, 3V sZjV\A %_E6Ol1xNc[y,3xx3ljΎ()gTˣ1q4`5aYznx_uq%xb<(y'kUSFm1xtiBH&BžuZ_~ʼnΤ$ox(Vt5d8X7R:(x3f*i& $aU57@E 㑔1Fwq='fg|m4l0xżycs{gqQjF @xǴqbW!iߟp<=Pt jrnS4k:x{+DtC\R/x9~xիJ ~BkM[lBx{wwnL"?5sx69~xիJ ~BkM3)ϝ&kF;ӓ'xE&x|ycs{gqQ@J_U/JHXIxxqQG5[_^-xĸq<OYhq@T ^xøqB ѵ_;X\~uuYm^fk/xyF}F{D!^rx@v~ҴT1nxCJxøqBHh_Q&/:-uNE^'we2N>+[aixĸqB;-Օܔ)Yf|P6eK[tN̫vUx̼yFNHwW?[.6iBcxĸq<jZEt_Zzߧ Z x340031QH,O`ŖOR1f~tC$dO8\?x(hj/)`89e朹a=3?nIx_{H(jځN={Bxe0ڬtɊ?g~vτ{DR!Tx;wHzfI|QjqiN_(51% 19;5E#DG!%IG!3ES((O3$>858ؚ &fBN~~q*\\S3=b}Y| 99pack-d7c6adf9f61318f041845b01440d09aa7a91e1b5.idx000066400000000000000000000023301216214232500373360ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/push_src/.gitted/modules/submodule/objects/packtOcA3ػGAi[l\of̌ŴnP) 4$ŀuuO|?-Y 21]iazošIn* 0ؒ!ZqSڥ : @0HD:3 w&Ⱦܠhq$neSՐ;dڧ/pack-d7c6adf9f61318f041845b01440d09aa7a91e1b5.pack000066400000000000000000000007531216214232500374770ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/push_src/.gitted/modules/submodule/objects/packPACKx] 0sk6 "xOnh+^ߢ7e>Ur;jes6dϝyUh]&A\jf${SbJ4c[McreG.bvFIUn/&~w3:Dc x[ 1 {\@K#x&ME5_7 *9`T*!5)inHMvHA˦…cÓp:߷<B,i| 6x>fOo{8x340031QH/H-+(aje+kt5eũy)`UoVc&'zhִu=ٱxL-QH/H-RHI:.;x+H,QHIx340031QH/H-+(aje+kt5V ?Ⱦܠhq$nepack-d85f5d483273108c9d8dd0e4728ccf0b2982423a.idx000066400000000000000000000023301216214232500373030ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/push_src/.gitted/modules/submodule/objects/packtOcf:I6qkS2rvǞ[ c6kȍ2:}f0mϛTVR3P$B =Њ 0*JNd>1dPx I-.KWHT(JMLM+(/W(OUHLIsRr2R2RR/x340031Q(JMLM+(aH6kɾzږgR[>ܵx I-.KWHT(JMLM+(UgGҚCWN(N,NJlibgit2-0.19.0/tests-clar/resources/push_src/.gitted/modules/submodule/packed-refs000066400000000000000000000026471216214232500302010ustar00rootroot00000000000000# pack-refs with: peeled a4a7dce85cf63874e984719f4fdd239f5145052f refs/remotes/origin/br2 a4a7dce85cf63874e984719f4fdd239f5145052f refs/remotes/origin/cannot-fetch e90810b8df3e80c413d903f631643c716887138d refs/remotes/origin/chomped 258f0e2a959a364e40ed6603d5d44fbb24765b10 refs/remotes/origin/haacked a65fedf39aefe402d3bb6e24df4d4f5fe4547750 refs/remotes/origin/master a65fedf39aefe402d3bb6e24df4d4f5fe4547750 refs/remotes/origin/not-good 41bc8c69075bbdb46c5c6f0566cc8cc5b46e8bd9 refs/remotes/origin/packed 4a202b346bb0fb0db7eff3cffeb3c70babbd2045 refs/remotes/origin/packed-test 763d71aadf09a7951596c9746c024e7eece7c7af refs/remotes/origin/subtrees e90810b8df3e80c413d903f631643c716887138d refs/remotes/origin/test 9fd738e8f7967c078dceed8190330fc8648ee56a refs/remotes/origin/track-local e90810b8df3e80c413d903f631643c716887138d refs/remotes/origin/trailing 521d87c1ec3aef9824daf6d96cc0ae3710766d91 refs/tags/annotated_tag_to_blob ^1385f264afb75a56a5bec74243be9b367ba4ca08 7b4384978d2493e851f9cca7858815fac9b10980 refs/tags/e90810b ^e90810b8df3e80c413d903f631643c716887138d 849a5e34a26815e821f865b8479f5815a47af0fe refs/tags/hard_tag ^a65fedf39aefe402d3bb6e24df4d4f5fe4547750 1385f264afb75a56a5bec74243be9b367ba4ca08 refs/tags/point_to_blob b25fa35b38051e4ae45d4222e795f9df2e43f1d1 refs/tags/test ^e90810b8df3e80c413d903f631643c716887138d 849a5e34a26815e821f865b8479f5815a47af0fe refs/tags/wrapped_tag ^a65fedf39aefe402d3bb6e24df4d4f5fe4547750 libgit2-0.19.0/tests-clar/resources/push_src/.gitted/modules/submodule/refs/000077500000000000000000000000001216214232500270205ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/push_src/.gitted/modules/submodule/refs/heads/000077500000000000000000000000001216214232500301045ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/push_src/.gitted/modules/submodule/refs/heads/master000066400000000000000000000000511216214232500313160ustar00rootroot00000000000000a65fedf39aefe402d3bb6e24df4d4f5fe4547750 libgit2-0.19.0/tests-clar/resources/push_src/.gitted/modules/submodule/refs/remotes/000077500000000000000000000000001216214232500304765ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/push_src/.gitted/modules/submodule/refs/remotes/origin/000077500000000000000000000000001216214232500317655ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/push_src/.gitted/modules/submodule/refs/remotes/origin/HEAD000066400000000000000000000000401216214232500324030ustar00rootroot00000000000000ref: refs/remotes/origin/master libgit2-0.19.0/tests-clar/resources/push_src/.gitted/objects/000077500000000000000000000000001216214232500240435ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/push_src/.gitted/objects/08/000077500000000000000000000000001216214232500242725ustar00rootroot00000000000000585692ce06452da6f82ae66b90d98b55536fca000066400000000000000000000000611216214232500313070ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/push_src/.gitted/objects/08x+)JMU06f040031QH+(a!h;AE3Z*libgit2-0.19.0/tests-clar/resources/push_src/.gitted/objects/27/000077500000000000000000000000001216214232500242735ustar00rootroot00000000000000b7ce66243eb1403862d05f958c002312df173d000066400000000000000000000002461216214232500311160ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/push_src/.gitted/objects/27xM 0F]sti<7тmxwKe D."mr1@9>RȞyE mH&Er7S!*u΄2>#\V8|Gt-ybhFU/J-|M}W+GKlibgit2-0.19.0/tests-clar/resources/push_src/.gitted/objects/28/000077500000000000000000000000001216214232500242745ustar00rootroot00000000000000905c54ea45a4bed8d7b90f51bd8bd81eec8840000066400000000000000000000001551216214232500316010ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/push_src/.gitted/objects/28x+)JMU040d040031QH+(a8)UU@Wm*M @!-?'u4_7?ݓpͿerRP $fIjs8Ռ^! J*rlibgit2-0.19.0/tests-clar/resources/push_src/.gitted/objects/36/000077500000000000000000000000001216214232500242735ustar00rootroot000000000000006226fb970ac0caa9d3f55967ab01334a548f60000066400000000000000000000000241216214232500312550ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/push_src/.gitted/objects/36xKOR0eHM,9libgit2-0.19.0/tests-clar/resources/push_src/.gitted/objects/5c/000077500000000000000000000000001216214232500243525ustar00rootroot000000000000000bb3d1b9449d1cc69d7519fd05166f01840915000066400000000000000000000002001216214232500311770ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/push_src/.gitted/objects/5cxA 0=vDy5` -00LlH;]s݁)=Ivn ٺ9µ=O[S_*1V0Z@ah64_I)'AjR7#libgit2-0.19.0/tests-clar/resources/push_src/.gitted/objects/61/000077500000000000000000000000001216214232500242715ustar00rootroot00000000000000780798228d17af2d34fce4cfbdf35556832472000066400000000000000000000000211216214232500312210ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/push_src/.gitted/objects/61xKOR0bHf^libgit2-0.19.0/tests-clar/resources/push_src/.gitted/objects/64/000077500000000000000000000000001216214232500242745ustar00rootroot00000000000000fd55f9b6390202db5e5666fd1fb339089fba4d000066400000000000000000000002601216214232500314430ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/push_src/.gitted/objects/64x+)JMU047g040031QK,O)I-fev"~q$Ԁ*K+(a8)UU@Wm*M @!-?'u4_7?ݓpͿerRP $fIjs8Ռ^! f`CK NaXO.S$<%Ilibgit2-0.19.0/tests-clar/resources/push_src/.gitted/objects/78/000077500000000000000000000000001216214232500243015ustar00rootroot00000000000000981922613b2afb6025042ff6bd878ac1994e85000066400000000000000000000000211216214232500311420ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/push_src/.gitted/objects/78xKOR0bHd]libgit2-0.19.0/tests-clar/resources/push_src/.gitted/objects/80/000077500000000000000000000000001216214232500242725ustar00rootroot000000000000005c54522e614f29f70d2413a0470247d8b424ac000066400000000000000000000002031216214232500310230ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/push_src/.gitted/objects/80xE;0Pjb{f%'71"2 Kq D1江ZȐ\0q(dFS . PV? -Ke9W8[! W_I`/QJ9? .libgit2-0.19.0/tests-clar/resources/push_src/.gitted/objects/95/000077500000000000000000000000001216214232500243005ustar00rootroot000000000000001bbbb90e2259a4c8950db78946784fb53fcbce000066400000000000000000000003401216214232500315250ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/push_src/.gitted/objects/95x[J0}*f2$Eim \8:DfZ &65^,%lm١~;KJRXT蕄(!{¯DZqPqsPӈB\;EEgs`IeoE(YMFC9uu>|#?i.׻qD90FEENzܶ<\,\a_a.gdlibgit2-0.19.0/tests-clar/resources/push_src/.gitted/objects/a7/000077500000000000000000000000001216214232500243525ustar00rootroot000000000000008705c3b2725f931d3ee05348d83cc26700f247000066400000000000000000000002461216214232500311320ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/push_src/.gitted/objects/a7x[ 0)n^m@D~'l#%EEO000\qhݴ9g`{*H2kzdܕUG1dR61 Py_zKu,p/>u}u<6j׿/U}ڵWSTJ libgit2-0.19.0/tests-clar/resources/push_src/.gitted/objects/b4/000077500000000000000000000000001216214232500243505ustar00rootroot0000000000000083ae7ba66decee9aee971f501221dea84b1498000066400000000000000000000002011216214232500316450ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/push_src/.gitted/objects/b4x5K 1D];1i"^'|d`d ooqQEͫ*Pݢ+ 3$, }%Rw+s9y輨r`+ܦ2p/[mp~u8-Sr=,?Z+ge1f2b375a64c1ccd40c5ff6aa8bc96839ba4fd000066400000000000000000000002241216214232500320020ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/push_src/.gitted/objects/b4x+)JMU041`040031QK,O)I-fev"~q$Ԁ*K+(a!h;AE3ZM @!-?'u4_7?ݓpͿerRf`$- ~ y*}㟄;zlibgit2-0.19.0/tests-clar/resources/push_src/.gitted/objects/c1/000077500000000000000000000000001216214232500243465ustar00rootroot000000000000000409136a7a75e025fa502a1b2fd7b62b77d279000066400000000000000000000000261216214232500312440ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/push_src/.gitted/objects/c1xKOR0gHJM, libgit2-0.19.0/tests-clar/resources/push_src/.gitted/objects/cd/000077500000000000000000000000001216214232500244315ustar00rootroot00000000000000881f90f2933db2e4cc26b8c71fe6037ac7fe4c000066400000000000000000000001201216214232500316500ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/push_src/.gitted/objects/cdx+)JMU03a040031QH+(a!h;AE3ZM @!-?'u4_7?ݓpͿerR#libgit2-0.19.0/tests-clar/resources/push_src/.gitted/objects/d9/000077500000000000000000000000001216214232500243575ustar00rootroot00000000000000b63a88223d8367516f50bd131a5f7349b7f3e4000066400000000000000000000002411216214232500312160ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/push_src/.gitted/objects/d9xA 0E]sd$ "xi2ՂmzwSErgj ![͎%wbY(zC/G\tw({r$C`Y[=DCu&V8!s=]8ޛT#|;ltWhfM}UQDMlibgit2-0.19.0/tests-clar/resources/push_src/.gitted/objects/dc/000077500000000000000000000000001216214232500244315ustar00rootroot00000000000000ab83249f6f9d1ed735d651352a80519339b591000066400000000000000000000001201216214232500312140ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/push_src/.gitted/objects/dcx+)JMU03a040031QH+(a8)UU@Wm*M @!-?'u4_7?ݓpͿerRx.libgit2-0.19.0/tests-clar/resources/push_src/.gitted/objects/f7/000077500000000000000000000000001216214232500243575ustar00rootroot000000000000008a3106c85fb549c65198b2a2086276c6174928000066400000000000000000000001011216214232500310030ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/push_src/.gitted/objects/f7xKOR03e..MO)IUP3b8 K2lb\E9@==⒢Ԃ|.hTlibgit2-0.19.0/tests-clar/resources/push_src/.gitted/objects/f8/000077500000000000000000000000001216214232500243605ustar00rootroot00000000000000f7aefc2900a3d737cea9eee45729fd55761e1a000066400000000000000000000000621216214232500316660ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/push_src/.gitted/objects/f8x+)JMU06f040031QH+(aH`+^ϓ{?5libgit2-0.19.0/tests-clar/resources/push_src/.gitted/objects/fa/000077500000000000000000000000001216214232500244315ustar00rootroot0000000000000038b91f199934685819bea316186d8b008c52a2000066400000000000000000000003031216214232500311410ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/push_src/.gitted/objects/faxJ15>urrneo {f[)_DmIi7 7Ĩ8ꔌ.n܃W)_T;x,(li[D\K墓XΓP?>W~|_Wؤxs6IcJNP}~ -מ/󄳭G Xlibgit2-0.19.0/tests-clar/resources/push_src/.gitted/objects/ff/000077500000000000000000000000001216214232500244365ustar00rootroot0000000000000083aa4c5e5d28e3bcba2f5c6e2adc61286a4e5e000066400000000000000000000002011216214232500320530ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/push_src/.gitted/objects/ffx5M 1 `=E4NA H ooq{/G@5=$+SO) nx[@4y h1ڄvmSyz' Wk-ziQc<ޢfS~pv+fe95c7fd0a37fa2ed702f8f93b56b2196b3925000066400000000000000000000001551216214232500316130ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/push_src/.gitted/objects/ffx+)JMU040d040031QH+(a!h;AE3ZM @!-?'u4_7?ݓpͿerRP $fIjs8Ռ^! *libgit2-0.19.0/tests-clar/resources/push_src/.gitted/objects/pack/000077500000000000000000000000001216214232500247615ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/push_src/.gitted/objects/pack/dummy000066400000000000000000000000001216214232500260250ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/push_src/.gitted/refs/000077500000000000000000000000001216214232500233515ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/push_src/.gitted/refs/heads/000077500000000000000000000000001216214232500244355ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/push_src/.gitted/refs/heads/b1000066400000000000000000000000511216214232500246560ustar00rootroot00000000000000a78705c3b2725f931d3ee05348d83cc26700f247 libgit2-0.19.0/tests-clar/resources/push_src/.gitted/refs/heads/b2000066400000000000000000000000511216214232500246570ustar00rootroot00000000000000a78705c3b2725f931d3ee05348d83cc26700f247 libgit2-0.19.0/tests-clar/resources/push_src/.gitted/refs/heads/b3000066400000000000000000000000511216214232500246600ustar00rootroot00000000000000d9b63a88223d8367516f50bd131a5f7349b7f3e4 libgit2-0.19.0/tests-clar/resources/push_src/.gitted/refs/heads/b4000066400000000000000000000000511216214232500246610ustar00rootroot0000000000000027b7ce66243eb1403862d05f958c002312df173d libgit2-0.19.0/tests-clar/resources/push_src/.gitted/refs/heads/b5000066400000000000000000000000511216214232500246620ustar00rootroot00000000000000fa38b91f199934685819bea316186d8b008c52a2 libgit2-0.19.0/tests-clar/resources/push_src/.gitted/refs/heads/b6000066400000000000000000000000511216214232500246630ustar00rootroot00000000000000951bbbb90e2259a4c8950db78946784fb53fcbce libgit2-0.19.0/tests-clar/resources/push_src/.gitted/refs/tags/000077500000000000000000000000001216214232500243075ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/push_src/.gitted/refs/tags/tag-blob000066400000000000000000000000511216214232500257150ustar00rootroot00000000000000b483ae7ba66decee9aee971f501221dea84b1498 libgit2-0.19.0/tests-clar/resources/push_src/.gitted/refs/tags/tag-commit000066400000000000000000000000511216214232500262670ustar00rootroot00000000000000805c54522e614f29f70d2413a0470247d8b424ac libgit2-0.19.0/tests-clar/resources/push_src/.gitted/refs/tags/tag-lightweight000066400000000000000000000000511216214232500273160ustar00rootroot00000000000000951bbbb90e2259a4c8950db78946784fb53fcbce libgit2-0.19.0/tests-clar/resources/push_src/.gitted/refs/tags/tag-tree000066400000000000000000000000511216214232500257360ustar00rootroot00000000000000ff83aa4c5e5d28e3bcba2f5c6e2adc61286a4e5e libgit2-0.19.0/tests-clar/resources/push_src/a.txt000066400000000000000000000000111216214232500220250ustar00rootroot00000000000000a edit libgit2-0.19.0/tests-clar/resources/push_src/fold/000077500000000000000000000000001216214232500220005ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/push_src/fold/b.txt000066400000000000000000000000021216214232500227520ustar00rootroot00000000000000b libgit2-0.19.0/tests-clar/resources/push_src/foldb.txt000066400000000000000000000000061216214232500226770ustar00rootroot00000000000000edit libgit2-0.19.0/tests-clar/resources/push_src/gitmodules000066400000000000000000000001041216214232500231460ustar00rootroot00000000000000[submodule "submodule"] path = submodule url = ../testrepo.git libgit2-0.19.0/tests-clar/resources/push_src/submodule/000077500000000000000000000000001216214232500230535ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/push_src/submodule/.gitted000066400000000000000000000000421216214232500243300ustar00rootroot00000000000000gitdir: ../.git/modules/submodule libgit2-0.19.0/tests-clar/resources/push_src/submodule/README000066400000000000000000000000131216214232500237250ustar00rootroot00000000000000hey there libgit2-0.19.0/tests-clar/resources/push_src/submodule/branch_file.txt000066400000000000000000000000121216214232500260410ustar00rootroot00000000000000hi bye! libgit2-0.19.0/tests-clar/resources/push_src/submodule/new.txt000066400000000000000000000000151216214232500244010ustar00rootroot00000000000000my new file libgit2-0.19.0/tests-clar/resources/renames/000077500000000000000000000000001216214232500206605ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/renames/.gitted/000077500000000000000000000000001216214232500222165ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/renames/.gitted/HEAD000066400000000000000000000000271216214232500226410ustar00rootroot00000000000000ref: refs/heads/master libgit2-0.19.0/tests-clar/resources/renames/.gitted/config000066400000000000000000000002121216214232500234010ustar00rootroot00000000000000[core] repositoryformatversion = 0 filemode = true bare = false logallrefupdates = true ignorecase = true precomposeunicode = false libgit2-0.19.0/tests-clar/resources/renames/.gitted/description000066400000000000000000000001111216214232500244550ustar00rootroot00000000000000Unnamed repository; edit this file 'description' to name the repository. libgit2-0.19.0/tests-clar/resources/renames/.gitted/index000066400000000000000000000005401216214232500232470ustar00rootroot00000000000000DIRCQ&zQ&z(R慅 6 ikeepsix.txtQ&Q& O!j7"]$C9ҵsixserving.txtQ&>Q&>BÐH3uRީsongof7cities.txtQ&0Q&0(Yi``l*T^+5 untimely.txtony(1 k C)^(%LnW&libgit2-0.19.0/tests-clar/resources/renames/.gitted/info/000077500000000000000000000000001216214232500231515ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/renames/.gitted/info/exclude000066400000000000000000000003601216214232500245240ustar00rootroot00000000000000# git ls-files --others --exclude-from=.git/info/exclude # Lines that start with '#' are comments. # For a project mostly in C, the following would be a good set of # exclude patterns (uncomment them if you want to use them): # *.[oa] # *~ libgit2-0.19.0/tests-clar/resources/renames/.gitted/logs/000077500000000000000000000000001216214232500231625ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/renames/.gitted/logs/HEAD000066400000000000000000000012541216214232500236100ustar00rootroot000000000000000000000000000000000000000000000000000000 31e47d8c1fa36d7f8d537b96158e3f024de0a9f2 Russell Belfer 1351024687 -0700 commit (initial): Initial commit 31e47d8c1fa36d7f8d537b96158e3f024de0a9f2 2bc7f351d20b53f1c72c16c4b036e491c478c49a Russell Belfer 1351024817 -0700 commit: copy and rename with no change 2bc7f351d20b53f1c72c16c4b036e491c478c49a 1c068dee5790ef1580cfc4cd670915b48d790084 Russell Belfer 1361485758 -0800 commit: rewrites, copies with changes, etc. 1c068dee5790ef1580cfc4cd670915b48d790084 19dd32dfb1520a64e5bbaae8dce6ef423dfa2f13 Russell Belfer 1361486360 -0800 commit: more renames and smallish modifications libgit2-0.19.0/tests-clar/resources/renames/.gitted/logs/refs/000077500000000000000000000000001216214232500241215ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/renames/.gitted/logs/refs/heads/000077500000000000000000000000001216214232500252055ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/renames/.gitted/logs/refs/heads/master000066400000000000000000000012541216214232500264250ustar00rootroot000000000000000000000000000000000000000000000000000000 31e47d8c1fa36d7f8d537b96158e3f024de0a9f2 Russell Belfer 1351024687 -0700 commit (initial): Initial commit 31e47d8c1fa36d7f8d537b96158e3f024de0a9f2 2bc7f351d20b53f1c72c16c4b036e491c478c49a Russell Belfer 1351024817 -0700 commit: copy and rename with no change 2bc7f351d20b53f1c72c16c4b036e491c478c49a 1c068dee5790ef1580cfc4cd670915b48d790084 Russell Belfer 1361485758 -0800 commit: rewrites, copies with changes, etc. 1c068dee5790ef1580cfc4cd670915b48d790084 19dd32dfb1520a64e5bbaae8dce6ef423dfa2f13 Russell Belfer 1361486360 -0800 commit: more renames and smallish modifications libgit2-0.19.0/tests-clar/resources/renames/.gitted/objects/000077500000000000000000000000001216214232500236475ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/renames/.gitted/objects/03/000077500000000000000000000000001216214232500240715ustar00rootroot00000000000000da7ad872536bd448da8d88eb7165338bf923a7000066400000000000000000000001321216214232500311650ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/renames/.gitted/objects/03x+)JMU0b040031Q(N-*K+(aXeMȊE|aP,5/9$34P>@.E_4twX!Qlibgit2-0.19.0/tests-clar/resources/renames/.gitted/objects/17/000077500000000000000000000000001216214232500240765ustar00rootroot0000000000000058bdd7c16a72ff7c17d8de0c957ced3ccad645000066400000000000000000000002041216214232500315430ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/renames/.gitted/objects/17xEͱ @QbWq H_&{]yYX`='흶=ZohzF MhBЄ&4 MhB3ьf4hF3юKxlibgit2-0.19.0/tests-clar/resources/renames/.gitted/objects/19/000077500000000000000000000000001216214232500241005ustar00rootroot00000000000000dd32dfb1520a64e5bbaae8dce6ef423dfa2f13000066400000000000000000000002601216214232500316470ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/renames/.gitted/objects/19xM!Ei@3ސc,\X K {Nrbo,xzYC<h[&?=fcvyCWo_Z \jKgο>MSO./Q8libgit2-0.19.0/tests-clar/resources/renames/.gitted/objects/35/000077500000000000000000000000001216214232500240765ustar00rootroot0000000000000092953ff3ea5e8ba700c429f3aefe33c8806754000066400000000000000000000001201216214232500311620ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/renames/.gitted/objects/35x+)JMU07a040031QpI,.6K.fpۤgߥ~/j,8+Mjq$*|Eݖ/'{x-z9mSlibgit2-0.19.0/tests-clar/resources/renames/.gitted/objects/36/000077500000000000000000000000001216214232500240775ustar00rootroot00000000000000020db6cdacaa93497f31edcd8f242ff9bc366d000066400000000000000000000006571216214232500315420ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/renames/.gitted/objects/36x}R0NVRšH (R&ؕ$G| c=ʉHQݝݙY]8/xh>xIGxR}E"\ <ߍzM(f^dt-ӷ3r 5aIFFY"\I7nG򢩬JܩL +KB$ -õ}aN5^"bge]G=<%`7j8J8GCGV MSJ@+⋙|WRJ]'Q<7\b%Hq4\$F*:'dזmk:}QKUs .Nۘbc(1\ħZ+B {& y #'6uHdl66-Ϊ?libgit2-0.19.0/tests-clar/resources/renames/.gitted/objects/3c/000077500000000000000000000000001216214232500241545ustar00rootroot0000000000000004741dd4b96c4ae4b00ec0f6e10c816a30aad2000066400000000000000000000002371216214232500313310ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/renames/.gitted/objects/3cx+)JMU04`040031QNM-(ά+(a0cvvͪɞoc UWZYZ Vf(ysz /vz:ݻ`J3+S2*V}8WZx +T私+YgW{5ˠ\̧!ΚBlibgit2-0.19.0/tests-clar/resources/renames/.gitted/objects/42/000077500000000000000000000000001216214232500240745ustar00rootroot0000000000000010ffd5c390b21dd5483375e75288dea9ede512000066400000000000000000000021711216214232500311610ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/renames/.gitted/objects/42xuUMoF Y 4i[qG% <8M6,#8i?,~ 陯7,Ǫ>IhNW+<)Kn&[qwWm^`f>ĔmrbLdzU*lINiuC ]FDCtξ`xhidm TSHp>Q>2pϽSýiuIy t|q38I{&I; <(!r1jG"l0"|0zD4SvpW&`r䕺0Έ$5e8dC ( z1e/3̖VhZii{Ga"Wrq0]'<%q"$n8ژYA> T8[:No=5&%)u50 \jY6(+Lۂ_<껂=YQԻEj1m#kM2I`@RJD Q8D'y;`(r"Z6oM4EIxzp%tdh$2g(bsDKBp3bDp'qawc6hS#h|ͣW*вHsGU E zQ Ń_L:`8d^R,d&gJaWv5{ W6@W 0 BV}AiFi/rI\Ǖ6{-61{q=,svG{6d~0SC:KMLy*{ަ!}1`,#jBr &t-Bg fwhVxnx{\'׵"FsYcqH~jO7Pk<}:2ggVt:~*Ʋ&MEO'œ)-#&ۨcPHu]]<^mqLM6|tD^X,Bu3 a{zl~)3 h;43aVX𣐾Z+FLP^̺*tԂQu1̡ ?cنv}0zޕRڻ8j`4xǞ/bELhӺsTl %libgit2-0.19.0/tests-clar/resources/renames/.gitted/objects/44/000077500000000000000000000000001216214232500240765ustar00rootroot000000000000004a76ed3e45b183753f49376af30da8c3fe276a000066400000000000000000000002071216214232500311640ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/renames/.gitted/objects/44x !}S6cc؁ Hn0/o2"Wf lp3qtqAL "g&JyqiuǦG7)jOI -}58C4Îq?){|n@/libgit2-0.19.0/tests-clar/resources/renames/.gitted/objects/47/000077500000000000000000000000001216214232500241015ustar00rootroot00000000000000184c1e7eb22abcbed2bf4ee87d4e38096f7951000066400000000000000000000003451216214232500314110ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/renames/.gitted/objects/47x]N0 9)|!BvB2q/j&%ڻP!_ON}3]|Uh*ER‘ď lє ٻ;vJ,k^d%!T&U"eBAƑ;ifeSG 9e7gU=6w l E:]s^t7uz0libgit2-0.19.0/tests-clar/resources/renames/.gitted/objects/4e/000077500000000000000000000000001216214232500241575ustar00rootroot000000000000004cae3e7dd56ed74bff39526d0469e554432953000066400000000000000000000007041216214232500312010ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/renames/.gitted/objects/4ex]R0SlGshN>N7lxޞiggƢ#}ͯ">{BiO)W*yJhp8+j~m5×StےUPjz«N$Ty|_~ $yH&eCXS 冕 p.]sdlūC'N9E> A*[x#ih:VFr#7 ?u+P\4>KٱKգH÷g=ՠ]1jXWaa }Iz t*? Fāb̓EO1Mp NÀVb,g`z/`libgit2-0.19.0/tests-clar/resources/renames/.gitted/objects/50/000077500000000000000000000000001216214232500240735ustar00rootroot00000000000000e90273af7d826ff0a95865bcd3ba8412c447d9000066400000000000000000000002511216214232500311630ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/renames/.gitted/objects/50xmM 0`9\@OdE@&4hLI"]c}bծaBORvΡ5" b0[kLopͭU˺SC; 8 hsF_le2}ɩ-!Dg4*IDO;!~)>m 䮔~*Dlibgit2-0.19.0/tests-clar/resources/renames/.gitted/objects/5e/000077500000000000000000000000001216214232500241605ustar00rootroot0000000000000026abc56a5a84d89790f45416648899cbe13109000066400000000000000000000002431216214232500307610ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/renames/.gitted/objects/5ex+)JMU043g040031QNM-(ά+(axeZ[_]nijPu@%ũEey`?y񝽯n_KXgK[a*̓3K2S_=Q.<6{; L=U>~L,H&m$+T Q3./vGL5#8;|WƨVq,H7&+sCZ@q P@r(tO~# əj?cJwq,{`,$^8u i^5Z=+9B/+Oxx&hclB^X4wʂy1Xl1eHeK֛ Rf9N}+,р𣐾 tQE|L/tޢ;c,6Fgl 6n*zRVۛL~"sQnzǺ/|ELИ}Gvh~Uտlibgit2-0.19.0/tests-clar/resources/renames/.gitted/objects/93/000077500000000000000000000000001216214232500241025ustar00rootroot00000000000000f538c45a57a87eb4c1e86f91c6ee41d66c7ba7000066400000000000000000000003451216214232500313440ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/renames/.gitted/objects/93x]N0 oQM,uNRqP3$#?7&o+jCyYMNjď lќFizw;w;g1DX8,RI%!TfU,eFQ;)0Z2Sѩj\ }Uc q+{*Bc'eQN6|~J:rn:VW+z1libgit2-0.19.0/tests-clar/resources/renames/.gitted/objects/9a/000077500000000000000000000000001216214232500241605ustar00rootroot0000000000000069d960ae94b060f56c2a8702545e2bb1abb935000066400000000000000000000007201216214232500311470ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/renames/.gitted/objects/9ax]R0؎(xB D7g 7Dpc'u?UzI{λW1+B9B"n;BV6};N'-Z|݋N(T&8THɻQ"@mUZK LDL MA;M])0hEk17 pQc!dMjjQQ3PU$X,ߴ'3'hAxS I1-Jsʁ6U==+W\;B6GXx {u4f aWRD7nyф+q>SC(Ze/ڽ\'/1LֲֳOsΉ&:&/(zI4.W"\3!nDپ(sbeM"< ~(rI1זj: PF9swj5 m ņ.^ۘ.O">Z$4N El+lv\H_nӱã8]>Slibgit2-0.19.0/tests-clar/resources/renames/.gitted/objects/b9/000077500000000000000000000000001216214232500241615ustar00rootroot0000000000000025b224cc91f897001a9993fbce169fdaa8858f000066400000000000000000000001141216214232500312560ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/renames/.gitted/objects/b9x+)JMU03c040031QH+(axu>psOK"nܺ@4TAXx׈߸3ͩk#ePlibgit2-0.19.0/tests-clar/resources/renames/.gitted/objects/d7/000077500000000000000000000000001216214232500241615ustar00rootroot000000000000009b202de198fa61b02424b9e25e840dc75e1323000066400000000000000000000006451216214232500310700ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/renames/.gitted/objects/d7xMM0Y)ެ{ iдf^;Jlű[W"S?/_rc޿'<=<|Ev?ac\%.QVV3`5Y~d.!Q2L)0aoBGY{-# ʈ8Kפ>Y̾xJĐT ﮰ+KLb";fotD]%RKqDpՎwLX ?fbF  SxJZ9B]v }Zu]'I f'Kցuj&.r #7S߭`d Ie{=Zݚw5aM X@;R.q63a!,R!-EaI>yo*4戁Rf m&eIA*!;dݬ Ho OUDyTVHpwqH7Ʒ.ts6{Z+X\)C5Q9 %t*&&v;|'4 Du[7he!NK*"C-=`#؎$Ee2T|@NBsslW|/0¬aȥJNv)-ڡiۤ3bbO:uWMNX7Tlibgit2-0.19.0/tests-clar/resources/renames/.gitted/objects/f9/000077500000000000000000000000001216214232500241655ustar00rootroot000000000000000d4fc20ecddf21eebe6a37e9225d244339d2b5000066400000000000000000000006711216214232500314530ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/renames/.gitted/objects/f9x]RN#1=RS9 +)瞤glǎy~~!_B' 9L(WU#QvD6=Fe']X9<4N{"̶AAKD;(&t,ACL8}fuWYQK| +0Az{HXqS+@# "pVFx\$S9b+,Fj꜕0[X3v2* 5(/> ̺i$`a%Yյ$ J&ң)o~DGI9A۟B@+r^P ƕG0;5! -( AteRU ŪqBu.bQ1tzG Qf$Y V?Hd8O`a@-@2~חA[.É.|pG7n;libgit2-0.19.0/tests-clar/resources/renames/.gitted/refs/000077500000000000000000000000001216214232500231555ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/renames/.gitted/refs/heads/000077500000000000000000000000001216214232500242415ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/renames/.gitted/refs/heads/master000066400000000000000000000000511216214232500254530ustar00rootroot0000000000000019dd32dfb1520a64e5bbaae8dce6ef423dfa2f13 libgit2-0.19.0/tests-clar/resources/renames/.gitted/refs/heads/renames_similar000066400000000000000000000000511216214232500273320ustar00rootroot00000000000000444a76ed3e45b183753f49376af30da8c3fe276a libgit2-0.19.0/tests-clar/resources/renames/.gitted/refs/heads/renames_similar_two000066400000000000000000000000511216214232500302230ustar00rootroot0000000000000050e90273af7d826ff0a95865bcd3ba8412c447d9 libgit2-0.19.0/tests-clar/resources/renames/ikeepsix.txt000066400000000000000000000013161216214232500232430ustar00rootroot00000000000000I Keep Six Honest Serving-Men ============================= She sends'em abroad on her own affairs, From the second she opens her eyes— One million Hows, two million Wheres, And seven million Whys! I let them rest from nine till five, For I am busy then, As well as breakfast, lunch, and tea, For they are hungry men. But different folk have different views; I know a person small— She keeps ten million serving-men, Who get no rest at all! -- Rudyard Kipling I KEEP six honest serving-men (They taught me all I knew); Their names are What and Why and When And How and Where and Who. I send them over land and sea, I send them east and west; But after they have worked for me, I give them all a rest. libgit2-0.19.0/tests-clar/resources/renames/sixserving.txt000066400000000000000000000014031216214232500236200ustar00rootroot00000000000000I KEEP six honest serving-men (They taught me all I knew); Their names are What and Why and When And How and Where and Who. I send them over land and sea, I send them east and west; But after they have worked for me, I give them all a rest. I let them rest from nine till five, For I am busy then, As well as breakfast, lunch, and tea, For they are hungry men. But different folk have different views; I know a person small— She keeps ten million serving-men, Who get no rest at all! She sends'em abroad on her own affairs, From the second she opens her eyes— One million Hows, two million Wheres, And seven million Whys! -- Rudyard Kipling libgit2-0.19.0/tests-clar/resources/renames/songof7cities.txt000066400000000000000000000042251216214232500242070ustar00rootroot00000000000000The Song of Seven Cities ------------------------ I WAS Lord of Cities very sumptuously builded. Seven roaring Cities paid me tribute from afar. Ivory their outposts were--the guardrooms of them gilded, And garrisoned with Amazons invincible in war. All the world went softly when it walked before my Cities-- Neither King nor Army vexed my peoples at their toil, Never horse nor chariot irked or overbore my Cities, Never Mob nor Ruler questioned whence they drew their spoil. Banded, mailed and arrogant from sunrise unto sunset; Singing while they sacked it, they possessed the land at large. Yet when men would rob them, they resisted, they made onset And pierced the smoke of battle with a thousand-sabred charge. So they warred and trafficked only yesterday, my Cities. To-day there is no mark or mound of where my Cities stood. For the River rose at midnight and it washed away my Cities. They are evened with Atlantis and the towns before the Flood. Rain on rain-gorged channels raised the water-levels round them, Freshet backed on freshet swelled and swept their world from sight, Till the emboldened floods linked arms and, flashing forward, drowned them-- Drowned my Seven Cities and their peoples in one night! Low among the alders lie their derelict foundations, The beams wherein they trusted and the plinths whereon they built-- My rulers and their treasure and their unborn populations, Dead, destroyed, aborted, and defiled with mud and silt! The Daughters of the Palace whom they cherished in my Cities, My silver-tongued Princesses, and the promise of their May-- Their bridegrooms of the June-tide--all have perished in my Cities, With the harsh envenomed virgins that can neither love nor play. I was Lord of Cities--I will build anew my Cities, Seven, set on rocks, above the wrath of any flood. Nor will I rest from search till I have filled anew my Cities With peoples undefeated of the dark, enduring blood. To the sound of trumpets shall their seed restore my Cities Wealthy and well-weaponed, that once more may I behold All the world go softly when it walks before my Cities, And the horses and the chariots fleeing from them as of old! -- Rudyard Kipling libgit2-0.19.0/tests-clar/resources/renames/untimely.txt000066400000000000000000000013641216214232500232730ustar00rootroot00000000000000Untimely ======== Nothing in life has been made by man for man's using But it was shown long since to man in ages Lost as the name of the maker of it, Who received oppression and shame for his wages-- Hate, avoidance, and scorn in his daily dealings-- Until he perished, wholly confounded More to be pitied than he are the wise Souls which foresaw the evil of loosing Knowledge or Art before time, and aborted Noble devices and deep-wrought healings, Lest offense should arise. Heaven delivers on earth the Hour that cannot be thwarted, Neither advanced, at the price of a world nor a soul, and its Prophet Comes through the blood of the vanguards who dreamed--too soon--it had sounded. -- Rudyard Kipling libgit2-0.19.0/tests-clar/resources/shallow.git/000077500000000000000000000000001216214232500214615ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/shallow.git/HEAD000066400000000000000000000000271216214232500221040ustar00rootroot00000000000000ref: refs/heads/master libgit2-0.19.0/tests-clar/resources/shallow.git/config000066400000000000000000000002351216214232500226510ustar00rootroot00000000000000[core] repositoryformatversion = 0 filemode = true bare = true ignorecase = true precomposeunicode = false [remote "origin"] url = file://testrepo.git libgit2-0.19.0/tests-clar/resources/shallow.git/objects/000077500000000000000000000000001216214232500231125ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/shallow.git/objects/pack/000077500000000000000000000000001216214232500240305ustar00rootroot00000000000000pack-706e49b161700946489570d96153e5be4dc31ad4.idx000066400000000000000000000024541216214232500324700ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/shallow.git/objects/packtOc fԃ.ti(36KA=JqV"E6<ܜl{W^4h!eGXzLnMAY^nb_ӻn$MO_TwPll@LVB1#1 p="ƾ5c?y[+CS:RzФD #39i9h:d )s;tY  Wra3wxġpack-706e49b161700946489570d96153e5be4dc31ad4.pack000066400000000000000000000014271216214232500326210ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/shallow.git/objects/packPACK x 1 NIS "#8AKYWA!RhjB!dlL%,GabÖK&b ܘ{}12_m׾ `#gWe u0?xMj1 F>vYH %'r&Й){B/=9̀I%x=/C}B鍃t.Y5!`WQRFDesaĤ[zQ̅4Wz cNU^;n[] =n[rstaged_new_file_deleted_fileMDMD)/eNstaged_new_file_modified_fileO NO Nu[ w##[(. subdir.txtO NO NwSEOxc3subdir/current_fileNNL|4[eI{`dY Xsubdir/deleted_fileNNL{ptmVP<*4tsubdir/modified_fileH37@w+9_BCzNgDlibgit2-0.19.0/tests-clar/resources/status/.gitted/info/000077500000000000000000000000001216214232500230425ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/status/.gitted/info/exclude000066400000000000000000000003721216214232500244200ustar00rootroot00000000000000# git ls-files --others --exclude-from=.git/info/exclude # Lines that start with '#' are comments. # For a project mostly in C, the following would be a good set of # exclude patterns (uncomment them if you want to use them): # *.[oa] # *~ ignored* libgit2-0.19.0/tests-clar/resources/status/.gitted/logs/000077500000000000000000000000001216214232500230535ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/status/.gitted/logs/HEAD000066400000000000000000000010631216214232500234770ustar00rootroot000000000000000000000000000000000000000000000000000000 0017bd4ab1ec30440b17bae1680cff124ab5f1f6 Jason Penny 1308050070 -0400 commit (initial): initial 0017bd4ab1ec30440b17bae1680cff124ab5f1f6 735b6a258cd196a8f7c9428419b02c1dca93fd75 Jason Penny 1308954538 -0400 commit: add subdir 735b6a258cd196a8f7c9428419b02c1dca93fd75 26a125ee1bfc5df1e1b2e9441bbe63c8a7ae989f nulltoken 1319911544 +0200 commit: Add a file which name should appear before the "subdir/" folder while being dealt with by the treewalker libgit2-0.19.0/tests-clar/resources/status/.gitted/logs/refs/000077500000000000000000000000001216214232500240125ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/status/.gitted/logs/refs/heads/000077500000000000000000000000001216214232500250765ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/status/.gitted/logs/refs/heads/master000066400000000000000000000010631216214232500263140ustar00rootroot000000000000000000000000000000000000000000000000000000 0017bd4ab1ec30440b17bae1680cff124ab5f1f6 Jason Penny 1308050070 -0400 commit (initial): initial 0017bd4ab1ec30440b17bae1680cff124ab5f1f6 735b6a258cd196a8f7c9428419b02c1dca93fd75 Jason Penny 1308954538 -0400 commit: add subdir 735b6a258cd196a8f7c9428419b02c1dca93fd75 26a125ee1bfc5df1e1b2e9441bbe63c8a7ae989f nulltoken 1319911544 +0200 commit: Add a file which name should appear before the "subdir/" folder while being dealt with by the treewalker libgit2-0.19.0/tests-clar/resources/status/.gitted/objects/000077500000000000000000000000001216214232500235405ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/status/.gitted/objects/00/000077500000000000000000000000001216214232500237575ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/status/.gitted/objects/00/17bd4ab1ec30440b17bae1680cff124ab5f1f6000066400000000000000000000002021216214232500312660ustar00rootroot00000000000000xA E]sfh)1] #STWpK^~9ܡ-"C'؅)Fvbv "wEk{nRί6#sO pD663WxV?9libgit2-0.19.0/tests-clar/resources/status/.gitted/objects/06/000077500000000000000000000000001216214232500237655ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/status/.gitted/objects/06/1d42a44cacde5726057b67558821d95db96f19000066400000000000000000000000541216214232500307750ustar00rootroot00000000000000xKOR0`(.ILOMOHKO-OIOII-IM libgit2-0.19.0/tests-clar/resources/status/.gitted/objects/18/000077500000000000000000000000001216214232500237705ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/status/.gitted/objects/18/88c805345ba265b0ee9449b8877b6064592058000066400000000000000000000000441216214232500305110ustar00rootroot00000000000000xKOR02`(.MJ,OII-IMOI libgit2-0.19.0/tests-clar/resources/status/.gitted/objects/19/000077500000000000000000000000001216214232500237715ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/status/.gitted/objects/19/d9cc8584ac2c7dcf57d2680375e80f099dc481000066400000000000000000000000261216214232500311520ustar00rootroot00000000000000xKOR0g(.ILOM"ylibgit2-0.19.0/tests-clar/resources/status/.gitted/objects/26/000077500000000000000000000000001216214232500237675ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/status/.gitted/objects/26/a125ee1bfc5df1e1b2e9441bbe63c8a7ae989f000066400000000000000000000003411216214232500315020ustar00rootroot00000000000000xMn )V (̀BD޾LЍRȷވ@,9̜tNj6f`M6Z;h Zp ڙY,37/;42x&gϟۉIm|jlibgit2-0.19.0/tests-clar/resources/status/.gitted/objects/32/000077500000000000000000000000001216214232500237645ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/status/.gitted/objects/32/504b727382542f9f089e24fddac5e78533e96c000066400000000000000000000000371216214232500310070ustar00rootroot00000000000000xKOR04e(.ILOMOHKO-\libgit2-0.19.0/tests-clar/resources/status/.gitted/objects/37/000077500000000000000000000000001216214232500237715ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/status/.gitted/objects/37/fcb02ccc1a85d1941e7f106d52dc3702dcf0d0000066400000000000000000000005131216214232500313120ustar00rootroot00000000000000x+)JMU015a040031QH.-*J+OIeXpÑ#2W zAՁSRsRKRSB.^xbT_Cde@ tsrz7rgJn=P $1,9#1/=()D><>o5~U%`KdZڡx3vg$vm+;y킂?l#ӷ>_Qm{S^M/gBSOaՅj٭=]?͏7maEm;`JR2J*J^|opr{L @a2G 53wX0Uvlibgit2-0.19.0/tests-clar/resources/status/.gitted/objects/45/000077500000000000000000000000001216214232500237705ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/status/.gitted/objects/45/2e4244b5d083ddf0460acf1ecc74db9dcfa11a000066400000000000000000000000361216214232500314550ustar00rootroot00000000000000xKOR04aOLLMOITbolibgit2-0.19.0/tests-clar/resources/status/.gitted/objects/52/000077500000000000000000000000001216214232500237665ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/status/.gitted/objects/52/9a16e8e762d4acb7b9636ff540a00831f9155a000066400000000000000000000000401216214232500310400ustar00rootroot00000000000000xKOR04c(.ILOMK-OIeQlibgit2-0.19.0/tests-clar/resources/status/.gitted/objects/53/000077500000000000000000000000001216214232500237675ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/status/.gitted/objects/53/ace0d1cc1145a5f4fe4f78a186a60263190733000066400000000000000000000000441216214232500310230ustar00rootroot00000000000000xKOR02`(.MJ,O.-*J+OI libgit2-0.19.0/tests-clar/resources/status/.gitted/objects/54/000077500000000000000000000000001216214232500237705ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/status/.gitted/objects/54/52d32f1dd538eb0405e8a83cc185f79e25e80f000066400000000000000000000000351216214232500311310ustar00rootroot00000000000000xKOR04fHIOII-IMLlibgit2-0.19.0/tests-clar/resources/status/.gitted/objects/55/000077500000000000000000000000001216214232500237715ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/status/.gitted/objects/55/d316c9ba708999f1918e9677d01dfcae69c6b9000066400000000000000000000000411216214232500311630ustar00rootroot00000000000000xKOR06`(.ILOMOHKO-B libgit2-0.19.0/tests-clar/resources/status/.gitted/objects/70/000077500000000000000000000000001216214232500237665ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/status/.gitted/objects/70/bd9443ada07063e7fbf0b3ff5c13f7494d89c2000066400000000000000000000000541216214232500312660ustar00rootroot00000000000000xKOR0d(.ILOMOHKO-OL er libgit2-0.19.0/tests-clar/resources/status/.gitted/objects/73/000077500000000000000000000000001216214232500237715ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/status/.gitted/objects/73/5b6a258cd196a8f7c9428419b02c1dca93fd75000066400000000000000000000002401216214232500311330ustar00rootroot00000000000000x90E}h;BT\9N1W/ҏK)s!CoD`!adl!r 9EҎO$R&KQmHʇёqsb$:lsipRN~(~~R.%I+-Q!᎓3l{Hsc_FI0libgit2-0.19.0/tests-clar/resources/status/.gitted/objects/75/000077500000000000000000000000001216214232500237735ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/status/.gitted/objects/75/6e27627e67bfbc048d01ece5819c6de733d7ea000066400000000000000000000004551216214232500313100ustar00rootroot00000000000000x+)JMU014c040031QH.-*J+OIeXpÑ#2W zAՁSRsRKRSB.^xbT_Cde@ tsrz7rgJn=P $1,9#1/=()D><>o5~U%`KdZڡx3vg$vm+;y킂?l#ӷ>_Qm{S^M/gBSOaՅj٭=]?͏7maEm;L @4)%a2G 53wX0U$5libgit2-0.19.0/tests-clar/resources/status/.gitted/objects/90/000077500000000000000000000000001216214232500237705ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/status/.gitted/objects/90/6ee7711f4f4928ddcb2a5f8fbc500deba0d2a8000066400000000000000000000000561216214232500315000ustar00rootroot00000000000000xKOR0`(.ILOMOHKO-OL er3libgit2-0.19.0/tests-clar/resources/status/.gitted/objects/90/b8c29d8ba39434d1c63e1b093daaa26e5bd972000066400000000000000000000000511216214232500312520ustar00rootroot00000000000000xKOR0d(.ILOMK-OIOII- 8\ libgit2-0.19.0/tests-clar/resources/status/.gitted/objects/9c/000077500000000000000000000000001216214232500240535ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/status/.gitted/objects/9c/2e02cdffa8d73e6c189074594477a6baf87960000066400000000000000000000004141216214232500311540ustar00rootroot00000000000000x+)JMU00f040031QH.-*J+OIeXpÑ#2W zAՁSRsRKRSB.^xbT_Cde@ tsrz7rgJn=P $1,9#1/=()D><>o5~U%`KdZڡx3vg$vm+;y킂?l#ӷ>_Qm{S^M/gBSOaՅj٭=]?͏7maEm;|libgit2-0.19.0/tests-clar/resources/status/.gitted/objects/a0/000077500000000000000000000000001216214232500240405ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/status/.gitted/objects/a0/de7e0ac200c489c41c59dfa910154a70264e6e000066400000000000000000000000351216214232500311570ustar00rootroot00000000000000xKOR04fH.-*J+OIM0libgit2-0.19.0/tests-clar/resources/status/.gitted/objects/a6/000077500000000000000000000000001216214232500240465ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/status/.gitted/objects/a6/191982709b746d5650e93c2acf34ef74e11504000066400000000000000000000000451216214232500307110ustar00rootroot00000000000000xKOR02d(.MJ,OLLMOI %libgit2-0.19.0/tests-clar/resources/status/.gitted/objects/a6/be623522ce87a1d862128ac42672604f7b468b000066400000000000000000000000561216214232500307620ustar00rootroot00000000000000xKOR05c(.ILOMOHKO-OIOII-IM's libgit2-0.19.0/tests-clar/resources/status/.gitted/objects/aa/000077500000000000000000000000001216214232500241215ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/status/.gitted/objects/aa/27a641456848200fdb7f7c99ba36f8a0952877000066400000000000000000000001701216214232500310010ustar00rootroot00000000000000x+)JMU042d040031QH.-*J+OIe^Aץ_W,l[Ɣ,n UZQ'q$zQwS@E*:" .gitmodulesPP_ZtѨ(fy\ README.txtPP${VZbϰX~just_a_dir/contentsPPBϹ\"[e^xx just_a_fileP<P<jH-(v[5iRTsm_added_and_uncommitedP׭P׭ͲH-(v[5iRTsm_changed_fileP׳P׳_H-(v[5iRTsm_changed_headPׯPׯH-(v[5iRTsm_changed_indexP׺P׺εH-(v[5iRTsm_changed_untracked_filePPH-(v[5iRTsm_missing_commitsPשPש]H-(v[5iRT sm_unchangedc++s4djlibgit2-0.19.0/tests-clar/resources/submod2/.gitted/info/000077500000000000000000000000001216214232500230725ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/info/exclude000066400000000000000000000003601216214232500244450ustar00rootroot00000000000000# git ls-files --others --exclude-from=.git/info/exclude # Lines that start with '#' are comments. # For a project mostly in C, the following would be a good set of # exclude patterns (uncomment them if you want to use them): # *.[oa] # *~ libgit2-0.19.0/tests-clar/resources/submod2/.gitted/logs/000077500000000000000000000000001216214232500231035ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/logs/HEAD000066400000000000000000000012101216214232500235210ustar00rootroot000000000000000000000000000000000000000000000000000000 14fe9ccf104058df25e0a08361c4494e167ef243 Russell Belfer 1342559771 -0700 commit (initial): Initial commit 14fe9ccf104058df25e0a08361c4494e167ef243 a9104bf89e911387244ef499413960ba472066d9 Russell Belfer 1342559831 -0700 commit: Adding a submodule a9104bf89e911387244ef499413960ba472066d9 5901da4f1c67756eeadc5121d206bec2431f253b Russell Belfer 1342560036 -0700 commit: Updating submodule 5901da4f1c67756eeadc5121d206bec2431f253b 7484482eb8db738cafa696993664607500a3f2b9 Russell Belfer 1342560288 -0700 commit: Adding a bunch more test content libgit2-0.19.0/tests-clar/resources/submod2/.gitted/logs/refs/000077500000000000000000000000001216214232500240425ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/logs/refs/heads/000077500000000000000000000000001216214232500251265ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/logs/refs/heads/master000066400000000000000000000012101216214232500263360ustar00rootroot000000000000000000000000000000000000000000000000000000 14fe9ccf104058df25e0a08361c4494e167ef243 Russell Belfer 1342559771 -0700 commit (initial): Initial commit 14fe9ccf104058df25e0a08361c4494e167ef243 a9104bf89e911387244ef499413960ba472066d9 Russell Belfer 1342559831 -0700 commit: Adding a submodule a9104bf89e911387244ef499413960ba472066d9 5901da4f1c67756eeadc5121d206bec2431f253b Russell Belfer 1342560036 -0700 commit: Updating submodule 5901da4f1c67756eeadc5121d206bec2431f253b 7484482eb8db738cafa696993664607500a3f2b9 Russell Belfer 1342560288 -0700 commit: Adding a bunch more test content libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/000077500000000000000000000000001216214232500236075ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_added_and_uncommited/000077500000000000000000000000001216214232500304155ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_added_and_uncommited/HEAD000066400000000000000000000000271216214232500310400ustar00rootroot00000000000000ref: refs/heads/master libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_added_and_uncommited/config000066400000000000000000000005321216214232500316050ustar00rootroot00000000000000[core] repositoryformatversion = 0 filemode = true bare = false logallrefupdates = true worktree = ../../../sm_added_and_uncommited ignorecase = true [remote "origin"] fetch = +refs/heads/*:refs/remotes/origin/* url = /Users/rb/src/libgit2/tests-clar/resources/submod2_target [branch "master"] remote = origin merge = refs/heads/master libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_added_and_uncommited/description000066400000000000000000000001111216214232500326540ustar00rootroot00000000000000Unnamed repository; edit this file 'description' to name the repository. libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_added_and_uncommited/index000066400000000000000000000003001216214232500314400ustar00rootroot00000000000000DIRCP<P<ϳjx swU:K-J README.txtP<P<ϴixڤwE8TUKfile_to_modify1/Դj^-sj 0ulibgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_added_and_uncommited/info/000077500000000000000000000000001216214232500313505ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_added_and_uncommited/info/exclude000066400000000000000000000003601216214232500327230ustar00rootroot00000000000000# git ls-files --others --exclude-from=.git/info/exclude # Lines that start with '#' are comments. # For a project mostly in C, the following would be a good set of # exclude patterns (uncomment them if you want to use them): # *.[oa] # *~ libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_added_and_uncommited/logs/000077500000000000000000000000001216214232500313615ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_added_and_uncommited/logs/HEAD000066400000000000000000000003101216214232500317770ustar00rootroot000000000000000000000000000000000000000000000000000000 480095882d281ed676fe5b863569520e54a7d5c0 Russell Belfer 1342560316 -0700 clone: from /Users/rb/src/libgit2/tests-clar/resources/submod2_target libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_added_and_uncommited/logs/refs/000077500000000000000000000000001216214232500323205ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_added_and_uncommited/logs/refs/heads/000077500000000000000000000000001216214232500334045ustar00rootroot00000000000000master000066400000000000000000000003101216214232500345350ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_added_and_uncommited/logs/refs/heads0000000000000000000000000000000000000000 480095882d281ed676fe5b863569520e54a7d5c0 Russell Belfer 1342560316 -0700 clone: from /Users/rb/src/libgit2/tests-clar/resources/submod2_target remotes/000077500000000000000000000000001216214232500337175ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_added_and_uncommited/logs/refsorigin/000077500000000000000000000000001216214232500352065ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_added_and_uncommited/logs/refs/remotesHEAD000066400000000000000000000003101216214232500356240ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_added_and_uncommited/logs/refs/remotes/origin0000000000000000000000000000000000000000 480095882d281ed676fe5b863569520e54a7d5c0 Russell Belfer 1342560316 -0700 clone: from /Users/rb/src/libgit2/tests-clar/resources/submod2_target libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_added_and_uncommited/objects/000077500000000000000000000000001216214232500320465ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_added_and_uncommited/objects/06/000077500000000000000000000000001216214232500322735ustar00rootroot00000000000000362fe2fdb7010d0e447b4fb450d405420479a1000066400000000000000000000000671216214232500371650ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_added_and_uncommited/objects/06x+)JMU0`040031Qrutu+(a-ŏ/C:sH[ blibgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_added_and_uncommited/objects/0e/000077500000000000000000000000001216214232500323525ustar00rootroot000000000000006a3ca48bd47cfe67681acf39aa0b10a0b92484000066400000000000000000000000651216214232500375540ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_added_and_uncommited/objects/0exKOR01`,VD̜T|̴J<$ 4' libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_added_and_uncommited/objects/17/000077500000000000000000000000001216214232500322755ustar00rootroot00000000000000d0ece6e96460a06592d9d9d000de37ba4232c5000066400000000000000000000001351216214232500373420ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_added_and_uncommited/objects/17x+)JMU0`040031Qrutu+(a-ŏ/C:sH[ *-3'5$?>7?%3/fIR-Wq ,ة!libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_added_and_uncommited/objects/41/000077500000000000000000000000001216214232500322725ustar00rootroot00000000000000bd4bc3df978de695f67ace64c560913da11653000066400000000000000000000002431216214232500374430ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_added_and_uncommited/objects/41x 0vh}K%ЁR8=͓u+CZD@%z1hrl b5Lꛊl|o57:anОщvQT:!oY)p/st7h Q QզTm*Ga^DFlibgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_added_and_uncommited/objects/48/000077500000000000000000000000001216214232500323015ustar00rootroot000000000000000095882d281ed676fe5b863569520e54a7d5c0000066400000000000000000000002431216214232500370760ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_added_and_uncommited/objects/48x[ >@QG(tˤ $NJ(e.212K${Ml-%E* Y]uk"IT&k,IC}J!pi9^\^;錷 (D"pNJuo)+C*ùXBElibgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_added_and_uncommited/objects/5e/000077500000000000000000000000001216214232500323575ustar00rootroot000000000000004963595a9774b90524d35a807169049de8ccad000066400000000000000000000002471216214232500371650ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_added_and_uncommited/objects/5ex[j0SRUȻ`A^߿Bu6|P# 2D:]Uk˽m IIz-WQة4VʌkHB Lw]1>y[ k_w'=T[߷4_0 Hlibgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_added_and_uncommited/objects/6b/000077500000000000000000000000001216214232500323555ustar00rootroot0000000000000031c659545507c381e9cd34ec508f16c04e149e000066400000000000000000000002031216214232500372140ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_added_and_uncommited/objects/6bxQ !Evoy*_@g#hOh^9wSòf1*[Ic Ԥpk Α\S߇l@.^QpF(:D5zr~ en8libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_added_and_uncommited/objects/73/000077500000000000000000000000001216214232500322775ustar00rootroot00000000000000ba924a80437097795ae839e66e187c55d3babf000066400000000000000000000001351216214232500373160ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_added_and_uncommited/objects/73x+)JMU0`040031Qrutu+(a-ŏ/C:sH[ *-3'5$?>7?%3b[,m*um:oLo#libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_added_and_uncommited/objects/78/000077500000000000000000000000001216214232500323045ustar00rootroot000000000000000d7397f5e8f8f477fb55b7af3accc2154b2d4a000066400000000000000000000001521216214232500376110ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_added_and_uncommited/objects/78x-10 Fa0p(N-ӡғq]>ks*? |m“i@mV'`).-1 x uxt(+9efbdadaa4a582778d4584385495559ea0994b000066400000000000000000000001471216214232500373400ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_added_and_uncommited/objects/78x 0 )?= NlOkj8&r qJW7B<fK8#Q1C-"e̫>'@libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_added_and_uncommited/objects/88/000077500000000000000000000000001216214232500323055ustar00rootroot0000000000000034b635dd468a83cb012f6feace968c1c9f5d6e000066400000000000000000000001211216214232500376100ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_added_and_uncommited/objects/88xKOR0d,VD̜T|̴J<$ 4'˳D!1(51R!#X8?7U$R vlibgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_added_and_uncommited/objects/d0/000077500000000000000000000000001216214232500323515ustar00rootroot000000000000005f2cd5cc77addf68ed6f50d622c9a4f732e6c5000066400000000000000000000001351216214232500377430ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_added_and_uncommited/objects/d0x+)JMU0`040031Qrutu+(a-ŏ/C:sH[ *-3'5$?>7?%3d]ӌM둙"libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_added_and_uncommited/packed-refs000066400000000000000000000001361216214232500325240ustar00rootroot00000000000000# pack-refs with: peeled 480095882d281ed676fe5b863569520e54a7d5c0 refs/remotes/origin/master libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_added_and_uncommited/refs/000077500000000000000000000000001216214232500313545ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_added_and_uncommited/refs/heads/000077500000000000000000000000001216214232500324405ustar00rootroot00000000000000master000066400000000000000000000000511216214232500335730ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_added_and_uncommited/refs/heads480095882d281ed676fe5b863569520e54a7d5c0 libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_added_and_uncommited/refs/remotes/000077500000000000000000000000001216214232500330325ustar00rootroot00000000000000origin/000077500000000000000000000000001216214232500342425ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_added_and_uncommited/refs/remotesHEAD000066400000000000000000000000401216214232500346600ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_added_and_uncommited/refs/remotes/originref: refs/remotes/origin/master libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_file/000077500000000000000000000000001216214232500266765ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_file/HEAD000066400000000000000000000000271216214232500273210ustar00rootroot00000000000000ref: refs/heads/master libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_file/config000066400000000000000000000005221216214232500300650ustar00rootroot00000000000000[core] repositoryformatversion = 0 filemode = true bare = false logallrefupdates = true worktree = ../../../sm_changed_file ignorecase = true [remote "origin"] fetch = +refs/heads/*:refs/remotes/origin/* url = /Users/rb/src/libgit2/tests-clar/resources/submod2_target [branch "master"] remote = origin merge = refs/heads/master libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_file/description000066400000000000000000000001111216214232500311350ustar00rootroot00000000000000Unnamed repository; edit this file 'description' to name the repository. libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_file/index000066400000000000000000000003001216214232500277210ustar00rootroot00000000000000DIRCP׭P׭jx swU:K-J README.txtP׭P׭ixڤwE8TUKfile_to_modifyhdݵ2w>libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_file/info/000077500000000000000000000000001216214232500276315ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_file/info/exclude000066400000000000000000000003601216214232500312040ustar00rootroot00000000000000# git ls-files --others --exclude-from=.git/info/exclude # Lines that start with '#' are comments. # For a project mostly in C, the following would be a good set of # exclude patterns (uncomment them if you want to use them): # *.[oa] # *~ libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_file/logs/000077500000000000000000000000001216214232500276425ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_file/logs/HEAD000066400000000000000000000003101216214232500302600ustar00rootroot000000000000000000000000000000000000000000000000000000 480095882d281ed676fe5b863569520e54a7d5c0 Russell Belfer 1342560173 -0700 clone: from /Users/rb/src/libgit2/tests-clar/resources/submod2_target libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_file/logs/refs/000077500000000000000000000000001216214232500306015ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_file/logs/refs/heads/000077500000000000000000000000001216214232500316655ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_file/logs/refs/heads/master000066400000000000000000000003101216214232500330750ustar00rootroot000000000000000000000000000000000000000000000000000000 480095882d281ed676fe5b863569520e54a7d5c0 Russell Belfer 1342560173 -0700 clone: from /Users/rb/src/libgit2/tests-clar/resources/submod2_target libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_file/logs/refs/remotes/000077500000000000000000000000001216214232500322575ustar00rootroot00000000000000origin/000077500000000000000000000000001216214232500334675ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_file/logs/refs/remotesHEAD000066400000000000000000000003101216214232500341050ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_file/logs/refs/remotes/origin0000000000000000000000000000000000000000 480095882d281ed676fe5b863569520e54a7d5c0 Russell Belfer 1342560173 -0700 clone: from /Users/rb/src/libgit2/tests-clar/resources/submod2_target libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_file/objects/000077500000000000000000000000001216214232500303275ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_file/objects/06/000077500000000000000000000000001216214232500305545ustar00rootroot00000000000000362fe2fdb7010d0e447b4fb450d405420479a1000066400000000000000000000000671216214232500354460ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_file/objects/06x+)JMU0`040031Qrutu+(a-ŏ/C:sH[ blibgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_file/objects/0e/000077500000000000000000000000001216214232500306335ustar00rootroot000000000000006a3ca48bd47cfe67681acf39aa0b10a0b92484000066400000000000000000000000651216214232500360350ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_file/objects/0exKOR01`,VD̜T|̴J<$ 4' libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_file/objects/17/000077500000000000000000000000001216214232500305565ustar00rootroot00000000000000d0ece6e96460a06592d9d9d000de37ba4232c5000066400000000000000000000001351216214232500356230ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_file/objects/17x+)JMU0`040031Qrutu+(a-ŏ/C:sH[ *-3'5$?>7?%3/fIR-Wq ,ة!libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_file/objects/41/000077500000000000000000000000001216214232500305535ustar00rootroot00000000000000bd4bc3df978de695f67ace64c560913da11653000066400000000000000000000002431216214232500357240ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_file/objects/41x 0vh}K%ЁR8=͓u+CZD@%z1hrl b5Lꛊl|o57:anОщvQT:!oY)p/st7h Q QզTm*Ga^DFlibgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_file/objects/48/000077500000000000000000000000001216214232500305625ustar00rootroot000000000000000095882d281ed676fe5b863569520e54a7d5c0000066400000000000000000000002431216214232500353570ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_file/objects/48x[ >@QG(tˤ $NJ(e.212K${Ml-%E* Y]uk"IT&k,IC}J!pi9^\^;錷 (D"pNJuo)+C*ùXBElibgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_file/objects/5e/000077500000000000000000000000001216214232500306405ustar00rootroot000000000000004963595a9774b90524d35a807169049de8ccad000066400000000000000000000002471216214232500354460ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_file/objects/5ex[j0SRUȻ`A^߿Bu6|P# 2D:]Uk˽m IIz-WQة4VʌkHB Lw]1>y[ k_w'=T[߷4_0 Hlibgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_file/objects/6b/000077500000000000000000000000001216214232500306365ustar00rootroot0000000000000031c659545507c381e9cd34ec508f16c04e149e000066400000000000000000000002031216214232500354750ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_file/objects/6bxQ !Evoy*_@g#hOh^9wSòf1*[Ic Ԥpk Α\S߇l@.^QpF(:D5zr~ en8libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_file/objects/73/000077500000000000000000000000001216214232500305605ustar00rootroot00000000000000ba924a80437097795ae839e66e187c55d3babf000066400000000000000000000001351216214232500355770ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_file/objects/73x+)JMU0`040031Qrutu+(a-ŏ/C:sH[ *-3'5$?>7?%3b[,m*um:oLo#libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_file/objects/78/000077500000000000000000000000001216214232500305655ustar00rootroot000000000000000d7397f5e8f8f477fb55b7af3accc2154b2d4a000066400000000000000000000001521216214232500360720ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_file/objects/78x-10 Fa0p(N-ӡғq]>ks*? |m“i@mV'`).-1 x uxt(+9efbdadaa4a582778d4584385495559ea0994b000066400000000000000000000001471216214232500356210ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_file/objects/78x 0 )?= NlOkj8&r qJW7B<fK8#Q1C-"e̫>'@libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_file/objects/88/000077500000000000000000000000001216214232500305665ustar00rootroot0000000000000034b635dd468a83cb012f6feace968c1c9f5d6e000066400000000000000000000001211216214232500360710ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_file/objects/88xKOR0d,VD̜T|̴J<$ 4'˳D!1(51R!#X8?7U$R vlibgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_file/objects/d0/000077500000000000000000000000001216214232500306325ustar00rootroot000000000000005f2cd5cc77addf68ed6f50d622c9a4f732e6c5000066400000000000000000000001351216214232500362240ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_file/objects/d0x+)JMU0`040031Qrutu+(a-ŏ/C:sH[ *-3'5$?>7?%3d]ӌM둙"libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_file/packed-refs000066400000000000000000000001361216214232500310050ustar00rootroot00000000000000# pack-refs with: peeled 480095882d281ed676fe5b863569520e54a7d5c0 refs/remotes/origin/master libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_file/refs/000077500000000000000000000000001216214232500276355ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_file/refs/heads/000077500000000000000000000000001216214232500307215ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_file/refs/heads/master000066400000000000000000000000511216214232500321330ustar00rootroot00000000000000480095882d281ed676fe5b863569520e54a7d5c0 libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_file/refs/remotes/000077500000000000000000000000001216214232500313135ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_file/refs/remotes/origin/000077500000000000000000000000001216214232500326025ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_file/refs/remotes/origin/HEAD000066400000000000000000000000401216214232500332200ustar00rootroot00000000000000ref: refs/remotes/origin/master libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_head/000077500000000000000000000000001216214232500266605ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_head/COMMIT_EDITMSG000066400000000000000000000000371216214232500307470ustar00rootroot00000000000000Making a change in a submodule libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_head/HEAD000066400000000000000000000000271216214232500273030ustar00rootroot00000000000000ref: refs/heads/master libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_head/config000066400000000000000000000005221216214232500300470ustar00rootroot00000000000000[core] repositoryformatversion = 0 filemode = true bare = false logallrefupdates = true worktree = ../../../sm_changed_head ignorecase = true [remote "origin"] fetch = +refs/heads/*:refs/remotes/origin/* url = /Users/rb/src/libgit2/tests-clar/resources/submod2_target [branch "master"] remote = origin merge = refs/heads/master libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_head/description000066400000000000000000000001111216214232500311170ustar00rootroot00000000000000Unnamed repository; edit this file 'description' to name the repository. libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_head/index000066400000000000000000000003001216214232500277030ustar00rootroot00000000000000DIRCP׳P׳Ψjx swU:K-J README.txtPأPأ$7EO 8 file_to_modify^|t+BQ9 &&+libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_head/info/000077500000000000000000000000001216214232500276135ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_head/info/exclude000066400000000000000000000003601216214232500311660ustar00rootroot00000000000000# git ls-files --others --exclude-from=.git/info/exclude # Lines that start with '#' are comments. # For a project mostly in C, the following would be a good set of # exclude patterns (uncomment them if you want to use them): # *.[oa] # *~ libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_head/logs/000077500000000000000000000000001216214232500276245ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_head/logs/HEAD000066400000000000000000000005611216214232500302520ustar00rootroot000000000000000000000000000000000000000000000000000000 480095882d281ed676fe5b863569520e54a7d5c0 Russell Belfer 1342560179 -0700 clone: from /Users/rb/src/libgit2/tests-clar/resources/submod2_target 480095882d281ed676fe5b863569520e54a7d5c0 3d9386c507f6b093471a3e324085657a3c2b4247 Russell Belfer 1342560431 -0700 commit: Making a change in a submodule libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_head/logs/refs/000077500000000000000000000000001216214232500305635ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_head/logs/refs/heads/000077500000000000000000000000001216214232500316475ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_head/logs/refs/heads/master000066400000000000000000000005611216214232500330670ustar00rootroot000000000000000000000000000000000000000000000000000000 480095882d281ed676fe5b863569520e54a7d5c0 Russell Belfer 1342560179 -0700 clone: from /Users/rb/src/libgit2/tests-clar/resources/submod2_target 480095882d281ed676fe5b863569520e54a7d5c0 3d9386c507f6b093471a3e324085657a3c2b4247 Russell Belfer 1342560431 -0700 commit: Making a change in a submodule libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_head/logs/refs/remotes/000077500000000000000000000000001216214232500322415ustar00rootroot00000000000000origin/000077500000000000000000000000001216214232500334515ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_head/logs/refs/remotesHEAD000066400000000000000000000003101216214232500340670ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_head/logs/refs/remotes/origin0000000000000000000000000000000000000000 480095882d281ed676fe5b863569520e54a7d5c0 Russell Belfer 1342560179 -0700 clone: from /Users/rb/src/libgit2/tests-clar/resources/submod2_target libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_head/objects/000077500000000000000000000000001216214232500303115ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_head/objects/06/000077500000000000000000000000001216214232500305365ustar00rootroot00000000000000362fe2fdb7010d0e447b4fb450d405420479a1000066400000000000000000000000671216214232500354300ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_head/objects/06x+)JMU0`040031Qrutu+(a-ŏ/C:sH[ blibgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_head/objects/0e/000077500000000000000000000000001216214232500306155ustar00rootroot000000000000006a3ca48bd47cfe67681acf39aa0b10a0b92484000066400000000000000000000000651216214232500360170ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_head/objects/0exKOR01`,VD̜T|̴J<$ 4' libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_head/objects/17/000077500000000000000000000000001216214232500305405ustar00rootroot00000000000000d0ece6e96460a06592d9d9d000de37ba4232c5000066400000000000000000000001351216214232500356050ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_head/objects/17x+)JMU0`040031Qrutu+(a-ŏ/C:sH[ *-3'5$?>7?%3/fIR-Wq ,ة!libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_head/objects/3d/000077500000000000000000000000001216214232500306175ustar00rootroot000000000000009386c507f6b093471a3e324085657a3c2b4247000066400000000000000000000002571216214232500352420ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_head/objects/3dxKj!E3vj#<<@Ouq .)ql osFa#v )g#{':Tl`b40 ;fr4 zU-/glm\'LjrhXG_+l ʚE`;=]Jlibgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_head/objects/41/000077500000000000000000000000001216214232500305355ustar00rootroot00000000000000bd4bc3df978de695f67ace64c560913da11653000066400000000000000000000002431216214232500357060ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_head/objects/41x 0vh}K%ЁR8=͓u+CZD@%z1hrl b5Lꛊl|o57:anОщvQT:!oY)p/st7h Q QզTm*Ga^DFlibgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_head/objects/48/000077500000000000000000000000001216214232500305445ustar00rootroot000000000000000095882d281ed676fe5b863569520e54a7d5c0000066400000000000000000000002431216214232500353410ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_head/objects/48x[ >@QG(tˤ $NJ(e.212K${Ml-%E* Y]uk"IT&k,IC}J!pi9^\^;錷 (D"pNJuo)+C*ùXBElibgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_head/objects/5e/000077500000000000000000000000001216214232500306225ustar00rootroot000000000000004963595a9774b90524d35a807169049de8ccad000066400000000000000000000002471216214232500354300ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_head/objects/5ex[j0SRUȻ`A^߿Bu6|P# 2D:]Uk˽m IIz-WQة4VʌkHB Lw]1>y[ k_w'=T[߷4_0 Hlibgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_head/objects/6b/000077500000000000000000000000001216214232500306205ustar00rootroot0000000000000031c659545507c381e9cd34ec508f16c04e149e000066400000000000000000000002031216214232500354570ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_head/objects/6bxQ !Evoy*_@g#hOh^9wSòf1*[Ic Ԥpk Α\S߇l@.^QpF(:D5zr~ en8libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_head/objects/73/000077500000000000000000000000001216214232500305425ustar00rootroot00000000000000ba924a80437097795ae839e66e187c55d3babf000066400000000000000000000001351216214232500355610ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_head/objects/73x+)JMU0`040031Qrutu+(a-ŏ/C:sH[ *-3'5$?>7?%3b[,m*um:oLo#libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_head/objects/77/000077500000000000000000000000001216214232500305465ustar00rootroot00000000000000fb0ed3e58568d6ad362c78de08ab8649d76e29000066400000000000000000000001351216214232500357350ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_head/objects/77x+)JMU0`040031Qrutu+(a-ŏ/C:sH[ *-3'5$?>7?%3o3Oks*? |m“i@mV'`).-1 x uxt(+9efbdadaa4a582778d4584385495559ea0994b000066400000000000000000000001471216214232500356030ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_head/objects/78x 0 )?= NlOkj8&r qJW7B<fK8#Q1C-"e̫>'@libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_head/objects/88/000077500000000000000000000000001216214232500305505ustar00rootroot0000000000000034b635dd468a83cb012f6feace968c1c9f5d6e000066400000000000000000000001211216214232500360530ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_head/objects/88xKOR0d,VD̜T|̴J<$ 4'˳D!1(51R!#X8?7U$R vlibgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_head/objects/8e/000077500000000000000000000000001216214232500306255ustar00rootroot00000000000000b1e637ed9fc8e5454fa20d38f809091f9395f4000066400000000000000000000002111216214232500356470ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_head/objects/8exMM; 1) ZPr3k lEnl!crz ,e +lEZxuPYx QC*fuLcfR3T0'үj~G^s1b2zVk]5<v'>libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_head/objects/d0/000077500000000000000000000000001216214232500306145ustar00rootroot000000000000005f2cd5cc77addf68ed6f50d622c9a4f732e6c5000066400000000000000000000001351216214232500362060ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_head/objects/d0x+)JMU0`040031Qrutu+(a-ŏ/C:sH[ *-3'5$?>7?%3d]ӌM둙"libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_head/packed-refs000066400000000000000000000001361216214232500307670ustar00rootroot00000000000000# pack-refs with: peeled 480095882d281ed676fe5b863569520e54a7d5c0 refs/remotes/origin/master libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_head/refs/000077500000000000000000000000001216214232500276175ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_head/refs/heads/000077500000000000000000000000001216214232500307035ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_head/refs/heads/master000066400000000000000000000000511216214232500321150ustar00rootroot000000000000003d9386c507f6b093471a3e324085657a3c2b4247 libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_head/refs/remotes/000077500000000000000000000000001216214232500312755ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_head/refs/remotes/origin/000077500000000000000000000000001216214232500325645ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_head/refs/remotes/origin/HEAD000066400000000000000000000000401216214232500332020ustar00rootroot00000000000000ref: refs/remotes/origin/master libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_index/000077500000000000000000000000001216214232500270665ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_index/HEAD000066400000000000000000000000271216214232500275110ustar00rootroot00000000000000ref: refs/heads/master libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_index/config000066400000000000000000000005231216214232500302560ustar00rootroot00000000000000[core] repositoryformatversion = 0 filemode = true bare = false logallrefupdates = true worktree = ../../../sm_changed_index ignorecase = true [remote "origin"] fetch = +refs/heads/*:refs/remotes/origin/* url = /Users/rb/src/libgit2/tests-clar/resources/submod2_target [branch "master"] remote = origin merge = refs/heads/master libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_index/description000066400000000000000000000001111216214232500313250ustar00rootroot00000000000000Unnamed repository; edit this file 'description' to name the repository. libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_index/index000066400000000000000000000003001216214232500301110ustar00rootroot00000000000000DIRCPׯPׯPjx swU:K-J README.txtP؇P؇-1wUGzᙲXfile_to_modifyxRV89c1>Pk.libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_index/info/000077500000000000000000000000001216214232500300215ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_index/info/exclude000066400000000000000000000003601216214232500313740ustar00rootroot00000000000000# git ls-files --others --exclude-from=.git/info/exclude # Lines that start with '#' are comments. # For a project mostly in C, the following would be a good set of # exclude patterns (uncomment them if you want to use them): # *.[oa] # *~ libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_index/logs/000077500000000000000000000000001216214232500300325ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_index/logs/HEAD000066400000000000000000000003101216214232500304500ustar00rootroot000000000000000000000000000000000000000000000000000000 480095882d281ed676fe5b863569520e54a7d5c0 Russell Belfer 1342560175 -0700 clone: from /Users/rb/src/libgit2/tests-clar/resources/submod2_target libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_index/logs/refs/000077500000000000000000000000001216214232500307715ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_index/logs/refs/heads/000077500000000000000000000000001216214232500320555ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_index/logs/refs/heads/master000066400000000000000000000003101216214232500332650ustar00rootroot000000000000000000000000000000000000000000000000000000 480095882d281ed676fe5b863569520e54a7d5c0 Russell Belfer 1342560175 -0700 clone: from /Users/rb/src/libgit2/tests-clar/resources/submod2_target libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_index/logs/refs/remotes/000077500000000000000000000000001216214232500324475ustar00rootroot00000000000000origin/000077500000000000000000000000001216214232500336575ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_index/logs/refs/remotesHEAD000066400000000000000000000003101216214232500342750ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_index/logs/refs/remotes/origin0000000000000000000000000000000000000000 480095882d281ed676fe5b863569520e54a7d5c0 Russell Belfer 1342560175 -0700 clone: from /Users/rb/src/libgit2/tests-clar/resources/submod2_target libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_index/objects/000077500000000000000000000000001216214232500305175ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_index/objects/06/000077500000000000000000000000001216214232500307445ustar00rootroot00000000000000362fe2fdb7010d0e447b4fb450d405420479a1000066400000000000000000000000671216214232500356360ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_index/objects/06x+)JMU0`040031Qrutu+(a-ŏ/C:sH[ blibgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_index/objects/0e/000077500000000000000000000000001216214232500310235ustar00rootroot000000000000006a3ca48bd47cfe67681acf39aa0b10a0b92484000066400000000000000000000000651216214232500362250ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_index/objects/0exKOR01`,VD̜T|̴J<$ 4' libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_index/objects/17/000077500000000000000000000000001216214232500307465ustar00rootroot00000000000000d0ece6e96460a06592d9d9d000de37ba4232c5000066400000000000000000000001351216214232500360130ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_index/objects/17x+)JMU0`040031Qrutu+(a-ŏ/C:sH[ *-3'5$?>7?%3/fIR-Wq ,ة!libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_index/objects/41/000077500000000000000000000000001216214232500307435ustar00rootroot00000000000000bd4bc3df978de695f67ace64c560913da11653000066400000000000000000000002431216214232500361140ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_index/objects/41x 0vh}K%ЁR8=͓u+CZD@%z1hrl b5Lꛊl|o57:anОщvQT:!oY)p/st7h Q QզTm*Ga^DFlibgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_index/objects/48/000077500000000000000000000000001216214232500307525ustar00rootroot000000000000000095882d281ed676fe5b863569520e54a7d5c0000066400000000000000000000002431216214232500355470ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_index/objects/48x[ >@QG(tˤ $NJ(e.212K${Ml-%E* Y]uk"IT&k,IC}J!pi9^\^;錷 (D"pNJuo)+C*ùXBElibgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_index/objects/5e/000077500000000000000000000000001216214232500310305ustar00rootroot000000000000004963595a9774b90524d35a807169049de8ccad000066400000000000000000000002471216214232500356360ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_index/objects/5ex[j0SRUȻ`A^߿Bu6|P# 2D:]Uk˽m IIz-WQة4VʌkHB Lw]1>y[ k_w'=T[߷4_0 Hlibgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_index/objects/6b/000077500000000000000000000000001216214232500310265ustar00rootroot0000000000000031c659545507c381e9cd34ec508f16c04e149e000066400000000000000000000002031216214232500356650ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_index/objects/6bxQ !Evoy*_@g#hOh^9wSòf1*[Ic Ԥpk Α\S߇l@.^QpF(:D5zr~ en8libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_index/objects/73/000077500000000000000000000000001216214232500307505ustar00rootroot00000000000000ba924a80437097795ae839e66e187c55d3babf000066400000000000000000000001351216214232500357670ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_index/objects/73x+)JMU0`040031Qrutu+(a-ŏ/C:sH[ *-3'5$?>7?%3b[,m*um:oLo#libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_index/objects/78/000077500000000000000000000000001216214232500307555ustar00rootroot000000000000000d7397f5e8f8f477fb55b7af3accc2154b2d4a000066400000000000000000000001521216214232500362620ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_index/objects/78x-10 Fa0p(N-ӡғq]>ks*? |m“i@mV'`).-1 x uxt(+9efbdadaa4a582778d4584385495559ea0994b000066400000000000000000000001471216214232500360110ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_index/objects/78x 0 )?= NlOkj8&r qJW7B<fK8#Q1C-"e̫>'@libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_index/objects/88/000077500000000000000000000000001216214232500307565ustar00rootroot0000000000000034b635dd468a83cb012f6feace968c1c9f5d6e000066400000000000000000000001211216214232500362610ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_index/objects/88xKOR0d,VD̜T|̴J<$ 4'˳D!1(51R!#X8?7U$R vlibgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_index/objects/a0/000077500000000000000000000000001216214232500310175ustar00rootroot000000000000002d31770687965547ab7a04cee199b29ee458d6000066400000000000000000000002061216214232500357020ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_index/objects/a0x%;1Cs `% n= $3K")An,+eDXStŦ։TІ734w\x"RCM`ˮu. YeH%PDXxq7vTXT:Dlibgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_index/objects/d0/000077500000000000000000000000001216214232500310225ustar00rootroot000000000000005f2cd5cc77addf68ed6f50d622c9a4f732e6c5000066400000000000000000000001351216214232500364140ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_index/objects/d0x+)JMU0`040031Qrutu+(a-ŏ/C:sH[ *-3'5$?>7?%3d]ӌM둙"libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_index/packed-refs000066400000000000000000000001361216214232500311750ustar00rootroot00000000000000# pack-refs with: peeled 480095882d281ed676fe5b863569520e54a7d5c0 refs/remotes/origin/master libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_index/refs/000077500000000000000000000000001216214232500300255ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_index/refs/heads/000077500000000000000000000000001216214232500311115ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_index/refs/heads/master000066400000000000000000000000511216214232500323230ustar00rootroot00000000000000480095882d281ed676fe5b863569520e54a7d5c0 libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_index/refs/remotes/000077500000000000000000000000001216214232500315035ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_index/refs/remotes/origin/000077500000000000000000000000001216214232500327725ustar00rootroot00000000000000HEAD000066400000000000000000000000401216214232500333310ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_index/refs/remotes/originref: refs/remotes/origin/master libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_untracked_file/000077500000000000000000000000001216214232500307365ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_untracked_file/HEAD000066400000000000000000000000271216214232500313610ustar00rootroot00000000000000ref: refs/heads/master libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_untracked_file/config000066400000000000000000000005341216214232500321300ustar00rootroot00000000000000[core] repositoryformatversion = 0 filemode = true bare = false logallrefupdates = true worktree = ../../../sm_changed_untracked_file ignorecase = true [remote "origin"] fetch = +refs/heads/*:refs/remotes/origin/* url = /Users/rb/src/libgit2/tests-clar/resources/submod2_target [branch "master"] remote = origin merge = refs/heads/master libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_untracked_file/description000066400000000000000000000001111216214232500331750ustar00rootroot00000000000000Unnamed repository; edit this file 'description' to name the repository. libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_untracked_file/index000066400000000000000000000003001216214232500317610ustar00rootroot00000000000000DIRCP׺P׺jx swU:K-J README.txtP׺P׺ixڤwE8TUKfile_to_modifykAӮW4c|libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_untracked_file/info/000077500000000000000000000000001216214232500316715ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_untracked_file/info/exclude000066400000000000000000000003601216214232500332440ustar00rootroot00000000000000# git ls-files --others --exclude-from=.git/info/exclude # Lines that start with '#' are comments. # For a project mostly in C, the following would be a good set of # exclude patterns (uncomment them if you want to use them): # *.[oa] # *~ libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_untracked_file/logs/000077500000000000000000000000001216214232500317025ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_untracked_file/logs/HEAD000066400000000000000000000003101216214232500323200ustar00rootroot000000000000000000000000000000000000000000000000000000 480095882d281ed676fe5b863569520e54a7d5c0 Russell Belfer 1342560186 -0700 clone: from /Users/rb/src/libgit2/tests-clar/resources/submod2_target libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_untracked_file/logs/refs/000077500000000000000000000000001216214232500326415ustar00rootroot00000000000000heads/000077500000000000000000000000001216214232500336465ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_untracked_file/logs/refsmaster000066400000000000000000000003101216214232500350560ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_untracked_file/logs/refs/heads0000000000000000000000000000000000000000 480095882d281ed676fe5b863569520e54a7d5c0 Russell Belfer 1342560186 -0700 clone: from /Users/rb/src/libgit2/tests-clar/resources/submod2_target remotes/000077500000000000000000000000001216214232500342405ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_untracked_file/logs/refsorigin/000077500000000000000000000000001216214232500355275ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_untracked_file/logs/refs/remotesHEAD000066400000000000000000000003101216214232500361450ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_untracked_file/logs/refs/remotes/origin0000000000000000000000000000000000000000 480095882d281ed676fe5b863569520e54a7d5c0 Russell Belfer 1342560186 -0700 clone: from /Users/rb/src/libgit2/tests-clar/resources/submod2_target libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_untracked_file/objects/000077500000000000000000000000001216214232500323675ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_untracked_file/objects/06/000077500000000000000000000000001216214232500326145ustar00rootroot00000000000000362fe2fdb7010d0e447b4fb450d405420479a1000066400000000000000000000000671216214232500375060ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_untracked_file/objects/06x+)JMU0`040031Qrutu+(a-ŏ/C:sH[ blibgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_untracked_file/objects/0e/000077500000000000000000000000001216214232500326735ustar00rootroot000000000000006a3ca48bd47cfe67681acf39aa0b10a0b92484000066400000000000000000000000651216214232500400750ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_untracked_file/objects/0exKOR01`,VD̜T|̴J<$ 4' libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_untracked_file/objects/17/000077500000000000000000000000001216214232500326165ustar00rootroot00000000000000d0ece6e96460a06592d9d9d000de37ba4232c5000066400000000000000000000001351216214232500376630ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_untracked_file/objects/17x+)JMU0`040031Qrutu+(a-ŏ/C:sH[ *-3'5$?>7?%3/fIR-Wq ,ة!libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_untracked_file/objects/41/000077500000000000000000000000001216214232500326135ustar00rootroot00000000000000bd4bc3df978de695f67ace64c560913da11653000066400000000000000000000002431216214232500377640ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_untracked_file/objects/41x 0vh}K%ЁR8=͓u+CZD@%z1hrl b5Lꛊl|o57:anОщvQT:!oY)p/st7h Q QզTm*Ga^DFlibgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_untracked_file/objects/48/000077500000000000000000000000001216214232500326225ustar00rootroot000000000000000095882d281ed676fe5b863569520e54a7d5c0000066400000000000000000000002431216214232500374170ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_untracked_file/objects/48x[ >@QG(tˤ $NJ(e.212K${Ml-%E* Y]uk"IT&k,IC}J!pi9^\^;錷 (D"pNJuo)+C*ùXBElibgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_untracked_file/objects/5e/000077500000000000000000000000001216214232500327005ustar00rootroot000000000000004963595a9774b90524d35a807169049de8ccad000066400000000000000000000002471216214232500375060ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_untracked_file/objects/5ex[j0SRUȻ`A^߿Bu6|P# 2D:]Uk˽m IIz-WQة4VʌkHB Lw]1>y[ k_w'=T[߷4_0 Hlibgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_untracked_file/objects/6b/000077500000000000000000000000001216214232500326765ustar00rootroot0000000000000031c659545507c381e9cd34ec508f16c04e149e000066400000000000000000000002031216214232500375350ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_untracked_file/objects/6bxQ !Evoy*_@g#hOh^9wSòf1*[Ic Ԥpk Α\S߇l@.^QpF(:D5zr~ en8libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_untracked_file/objects/73/000077500000000000000000000000001216214232500326205ustar00rootroot00000000000000ba924a80437097795ae839e66e187c55d3babf000066400000000000000000000001351216214232500376370ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_untracked_file/objects/73x+)JMU0`040031Qrutu+(a-ŏ/C:sH[ *-3'5$?>7?%3b[,m*um:oLo#libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_untracked_file/objects/78/000077500000000000000000000000001216214232500326255ustar00rootroot000000000000000d7397f5e8f8f477fb55b7af3accc2154b2d4a000066400000000000000000000001521216214232500401320ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_untracked_file/objects/78x-10 Fa0p(N-ӡғq]>ks*? |m“i@mV'`).-1 x uxt(+9efbdadaa4a582778d4584385495559ea0994b000066400000000000000000000001471216214232500376610ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_untracked_file/objects/78x 0 )?= NlOkj8&r qJW7B<fK8#Q1C-"e̫>'@libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_untracked_file/objects/88/000077500000000000000000000000001216214232500326265ustar00rootroot0000000000000034b635dd468a83cb012f6feace968c1c9f5d6e000066400000000000000000000001211216214232500401310ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_untracked_file/objects/88xKOR0d,VD̜T|̴J<$ 4'˳D!1(51R!#X8?7U$R vlibgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_untracked_file/objects/d0/000077500000000000000000000000001216214232500326725ustar00rootroot000000000000005f2cd5cc77addf68ed6f50d622c9a4f732e6c5000066400000000000000000000001351216214232500402640ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_untracked_file/objects/d0x+)JMU0`040031Qrutu+(a-ŏ/C:sH[ *-3'5$?>7?%3d]ӌM둙"libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_untracked_file/packed-refs000066400000000000000000000001361216214232500330450ustar00rootroot00000000000000# pack-refs with: peeled 480095882d281ed676fe5b863569520e54a7d5c0 refs/remotes/origin/master libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_untracked_file/refs/000077500000000000000000000000001216214232500316755ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_untracked_file/refs/heads/000077500000000000000000000000001216214232500327615ustar00rootroot00000000000000master000066400000000000000000000000511216214232500341140ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_untracked_file/refs/heads480095882d281ed676fe5b863569520e54a7d5c0 libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_untracked_file/refs/remotes/000077500000000000000000000000001216214232500333535ustar00rootroot00000000000000origin/000077500000000000000000000000001216214232500345635ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_untracked_file/refs/remotesHEAD000066400000000000000000000000401216214232500352010ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_changed_untracked_file/refs/remotes/originref: refs/remotes/origin/master libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_missing_commits/000077500000000000000000000000001216214232500275125ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_missing_commits/HEAD000066400000000000000000000000271216214232500301350ustar00rootroot00000000000000ref: refs/heads/master libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_missing_commits/config000066400000000000000000000005251216214232500307040ustar00rootroot00000000000000[core] repositoryformatversion = 0 filemode = true bare = false logallrefupdates = true worktree = ../../../sm_missing_commits ignorecase = true [remote "origin"] fetch = +refs/heads/*:refs/remotes/origin/* url = /Users/rb/src/libgit2/tests-clar/resources/submod2_target [branch "master"] remote = origin merge = refs/heads/master libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_missing_commits/description000066400000000000000000000001111216214232500317510ustar00rootroot00000000000000Unnamed repository; edit this file 'description' to name the repository. libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_missing_commits/index000066400000000000000000000003001216214232500305350ustar00rootroot00000000000000DIRCP4P4Zjx swU:K-J README.txtPAPAE45F/oΖ]nfile_to_modify7lױW$2=lZ: Llibgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_missing_commits/info/000077500000000000000000000000001216214232500304455ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_missing_commits/info/exclude000066400000000000000000000003601216214232500320200ustar00rootroot00000000000000# git ls-files --others --exclude-from=.git/info/exclude # Lines that start with '#' are comments. # For a project mostly in C, the following would be a good set of # exclude patterns (uncomment them if you want to use them): # *.[oa] # *~ libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_missing_commits/logs/000077500000000000000000000000001216214232500304565ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_missing_commits/logs/HEAD000066400000000000000000000003101216214232500310740ustar00rootroot000000000000000000000000000000000000000000000000000000 5e4963595a9774b90524d35a807169049de8ccad Russell Belfer 1342559796 -0700 clone: from /Users/rb/src/libgit2/tests-clar/resources/submod2_target libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_missing_commits/logs/refs/000077500000000000000000000000001216214232500314155ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_missing_commits/logs/refs/heads/000077500000000000000000000000001216214232500325015ustar00rootroot00000000000000master000066400000000000000000000003101216214232500336320ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_missing_commits/logs/refs/heads0000000000000000000000000000000000000000 5e4963595a9774b90524d35a807169049de8ccad Russell Belfer 1342559796 -0700 clone: from /Users/rb/src/libgit2/tests-clar/resources/submod2_target libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_missing_commits/logs/refs/remotes/000077500000000000000000000000001216214232500330735ustar00rootroot00000000000000origin/000077500000000000000000000000001216214232500343035ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_missing_commits/logs/refs/remotesHEAD000066400000000000000000000003101216214232500347210ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_missing_commits/logs/refs/remotes/origin0000000000000000000000000000000000000000 5e4963595a9774b90524d35a807169049de8ccad Russell Belfer 1342559796 -0700 clone: from /Users/rb/src/libgit2/tests-clar/resources/submod2_target libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_missing_commits/objects/000077500000000000000000000000001216214232500311435ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_missing_commits/objects/06/000077500000000000000000000000001216214232500313705ustar00rootroot00000000000000362fe2fdb7010d0e447b4fb450d405420479a1000066400000000000000000000000671216214232500362620ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_missing_commits/objects/06x+)JMU0`040031Qrutu+(a-ŏ/C:sH[ blibgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_missing_commits/objects/0e/000077500000000000000000000000001216214232500314475ustar00rootroot000000000000006a3ca48bd47cfe67681acf39aa0b10a0b92484000066400000000000000000000000651216214232500366510ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_missing_commits/objects/0exKOR01`,VD̜T|̴J<$ 4' libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_missing_commits/objects/17/000077500000000000000000000000001216214232500313725ustar00rootroot00000000000000d0ece6e96460a06592d9d9d000de37ba4232c5000066400000000000000000000001351216214232500364370ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_missing_commits/objects/17x+)JMU0`040031Qrutu+(a-ŏ/C:sH[ *-3'5$?>7?%3/fIR-Wq ,ة!libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_missing_commits/objects/41/000077500000000000000000000000001216214232500313675ustar00rootroot00000000000000bd4bc3df978de695f67ace64c560913da11653000066400000000000000000000002431216214232500365400ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_missing_commits/objects/41x 0vh}K%ЁR8=͓u+CZD@%z1hrl b5Lꛊl|o57:anОщvQT:!oY)p/st7h Q QզTm*Ga^DFlibgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_missing_commits/objects/5e/000077500000000000000000000000001216214232500314545ustar00rootroot000000000000004963595a9774b90524d35a807169049de8ccad000066400000000000000000000002471216214232500362620ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_missing_commits/objects/5ex[j0SRUȻ`A^߿Bu6|P# 2D:]Uk˽m IIz-WQة4VʌkHB Lw]1>y[ k_w'=T[߷4_0 Hlibgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_missing_commits/objects/6b/000077500000000000000000000000001216214232500314525ustar00rootroot0000000000000031c659545507c381e9cd34ec508f16c04e149e000066400000000000000000000002031216214232500363110ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_missing_commits/objects/6bxQ !Evoy*_@g#hOh^9wSòf1*[Ic Ԥpk Α\S߇l@.^QpF(:D5zr~ en8libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_missing_commits/objects/78/000077500000000000000000000000001216214232500314015ustar00rootroot000000000000000d7397f5e8f8f477fb55b7af3accc2154b2d4a000066400000000000000000000001521216214232500367060ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_missing_commits/objects/78x-10 Fa0p(N-ӡғq]>ks*? |m“i@mV'`).-1 x uxt(+libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_missing_commits/objects/88/000077500000000000000000000000001216214232500314025ustar00rootroot0000000000000034b635dd468a83cb012f6feace968c1c9f5d6e000066400000000000000000000001211216214232500367050ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_missing_commits/objects/88xKOR0d,VD̜T|̴J<$ 4'˳D!1(51R!#X8?7U$R vlibgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_missing_commits/objects/d0/000077500000000000000000000000001216214232500314465ustar00rootroot000000000000005f2cd5cc77addf68ed6f50d622c9a4f732e6c5000066400000000000000000000001351216214232500370400ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_missing_commits/objects/d0x+)JMU0`040031Qrutu+(a-ŏ/C:sH[ *-3'5$?>7?%3d]ӌM둙"libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_missing_commits/packed-refs000066400000000000000000000001361216214232500316210ustar00rootroot00000000000000# pack-refs with: peeled 5e4963595a9774b90524d35a807169049de8ccad refs/remotes/origin/master libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_missing_commits/refs/000077500000000000000000000000001216214232500304515ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_missing_commits/refs/heads/000077500000000000000000000000001216214232500315355ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_missing_commits/refs/heads/master000066400000000000000000000000511216214232500327470ustar00rootroot000000000000005e4963595a9774b90524d35a807169049de8ccad libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_missing_commits/refs/remotes/000077500000000000000000000000001216214232500321275ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_missing_commits/refs/remotes/origin/000077500000000000000000000000001216214232500334165ustar00rootroot00000000000000HEAD000066400000000000000000000000401216214232500337550ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_missing_commits/refs/remotes/originref: refs/remotes/origin/master libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_unchanged/000077500000000000000000000000001216214232500262425ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_unchanged/HEAD000066400000000000000000000000271216214232500266650ustar00rootroot00000000000000ref: refs/heads/master libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_unchanged/config000066400000000000000000000005171216214232500274350ustar00rootroot00000000000000[core] repositoryformatversion = 0 filemode = true bare = false logallrefupdates = true worktree = ../../../sm_unchanged ignorecase = true [remote "origin"] fetch = +refs/heads/*:refs/remotes/origin/* url = /Users/rb/src/libgit2/tests-clar/resources/submod2_target [branch "master"] remote = origin merge = refs/heads/master libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_unchanged/description000066400000000000000000000001111216214232500305010ustar00rootroot00000000000000Unnamed repository; edit this file 'description' to name the repository. libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_unchanged/index000066400000000000000000000003001216214232500272650ustar00rootroot00000000000000DIRCPשPשͦjx swU:K-J README.txtPשPשͧixڤwE8TUKfile_to_modifyT{a0ؙlibgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_unchanged/info/000077500000000000000000000000001216214232500271755ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_unchanged/info/exclude000066400000000000000000000003601216214232500305500ustar00rootroot00000000000000# git ls-files --others --exclude-from=.git/info/exclude # Lines that start with '#' are comments. # For a project mostly in C, the following would be a good set of # exclude patterns (uncomment them if you want to use them): # *.[oa] # *~ libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_unchanged/logs/000077500000000000000000000000001216214232500272065ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_unchanged/logs/HEAD000066400000000000000000000003101216214232500276240ustar00rootroot000000000000000000000000000000000000000000000000000000 480095882d281ed676fe5b863569520e54a7d5c0 Russell Belfer 1342560169 -0700 clone: from /Users/rb/src/libgit2/tests-clar/resources/submod2_target libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_unchanged/logs/refs/000077500000000000000000000000001216214232500301455ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_unchanged/logs/refs/heads/000077500000000000000000000000001216214232500312315ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_unchanged/logs/refs/heads/master000066400000000000000000000003101216214232500324410ustar00rootroot000000000000000000000000000000000000000000000000000000 480095882d281ed676fe5b863569520e54a7d5c0 Russell Belfer 1342560169 -0700 clone: from /Users/rb/src/libgit2/tests-clar/resources/submod2_target libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_unchanged/logs/refs/remotes/000077500000000000000000000000001216214232500316235ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_unchanged/logs/refs/remotes/origin/000077500000000000000000000000001216214232500331125ustar00rootroot00000000000000HEAD000066400000000000000000000003101216214232500334510ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_unchanged/logs/refs/remotes/origin0000000000000000000000000000000000000000 480095882d281ed676fe5b863569520e54a7d5c0 Russell Belfer 1342560169 -0700 clone: from /Users/rb/src/libgit2/tests-clar/resources/submod2_target libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_unchanged/objects/000077500000000000000000000000001216214232500276735ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_unchanged/objects/06/000077500000000000000000000000001216214232500301205ustar00rootroot00000000000000362fe2fdb7010d0e447b4fb450d405420479a1000066400000000000000000000000671216214232500350120ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_unchanged/objects/06x+)JMU0`040031Qrutu+(a-ŏ/C:sH[ blibgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_unchanged/objects/0e/000077500000000000000000000000001216214232500301775ustar00rootroot000000000000006a3ca48bd47cfe67681acf39aa0b10a0b92484000066400000000000000000000000651216214232500354010ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_unchanged/objects/0exKOR01`,VD̜T|̴J<$ 4' libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_unchanged/objects/17/000077500000000000000000000000001216214232500301225ustar00rootroot00000000000000d0ece6e96460a06592d9d9d000de37ba4232c5000066400000000000000000000001351216214232500351670ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_unchanged/objects/17x+)JMU0`040031Qrutu+(a-ŏ/C:sH[ *-3'5$?>7?%3/fIR-Wq ,ة!libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_unchanged/objects/41/000077500000000000000000000000001216214232500301175ustar00rootroot00000000000000bd4bc3df978de695f67ace64c560913da11653000066400000000000000000000002431216214232500352700ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_unchanged/objects/41x 0vh}K%ЁR8=͓u+CZD@%z1hrl b5Lꛊl|o57:anОщvQT:!oY)p/st7h Q QզTm*Ga^DFlibgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_unchanged/objects/48/000077500000000000000000000000001216214232500301265ustar00rootroot000000000000000095882d281ed676fe5b863569520e54a7d5c0000066400000000000000000000002431216214232500347230ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_unchanged/objects/48x[ >@QG(tˤ $NJ(e.212K${Ml-%E* Y]uk"IT&k,IC}J!pi9^\^;錷 (D"pNJuo)+C*ùXBElibgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_unchanged/objects/5e/000077500000000000000000000000001216214232500302045ustar00rootroot000000000000004963595a9774b90524d35a807169049de8ccad000066400000000000000000000002471216214232500350120ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_unchanged/objects/5ex[j0SRUȻ`A^߿Bu6|P# 2D:]Uk˽m IIz-WQة4VʌkHB Lw]1>y[ k_w'=T[߷4_0 Hlibgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_unchanged/objects/6b/000077500000000000000000000000001216214232500302025ustar00rootroot0000000000000031c659545507c381e9cd34ec508f16c04e149e000066400000000000000000000002031216214232500350410ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_unchanged/objects/6bxQ !Evoy*_@g#hOh^9wSòf1*[Ic Ԥpk Α\S߇l@.^QpF(:D5zr~ en8libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_unchanged/objects/73/000077500000000000000000000000001216214232500301245ustar00rootroot00000000000000ba924a80437097795ae839e66e187c55d3babf000066400000000000000000000001351216214232500351430ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_unchanged/objects/73x+)JMU0`040031Qrutu+(a-ŏ/C:sH[ *-3'5$?>7?%3b[,m*um:oLo#libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_unchanged/objects/78/000077500000000000000000000000001216214232500301315ustar00rootroot000000000000000d7397f5e8f8f477fb55b7af3accc2154b2d4a000066400000000000000000000001521216214232500354360ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_unchanged/objects/78x-10 Fa0p(N-ӡғq]>ks*? |m“i@mV'`).-1 x uxt(+9efbdadaa4a582778d4584385495559ea0994b000066400000000000000000000001471216214232500351650ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_unchanged/objects/78x 0 )?= NlOkj8&r qJW7B<fK8#Q1C-"e̫>'@libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_unchanged/objects/88/000077500000000000000000000000001216214232500301325ustar00rootroot0000000000000034b635dd468a83cb012f6feace968c1c9f5d6e000066400000000000000000000001211216214232500354350ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_unchanged/objects/88xKOR0d,VD̜T|̴J<$ 4'˳D!1(51R!#X8?7U$R vlibgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_unchanged/objects/d0/000077500000000000000000000000001216214232500301765ustar00rootroot000000000000005f2cd5cc77addf68ed6f50d622c9a4f732e6c5000066400000000000000000000001351216214232500355700ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_unchanged/objects/d0x+)JMU0`040031Qrutu+(a-ŏ/C:sH[ *-3'5$?>7?%3d]ӌM둙"libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_unchanged/packed-refs000066400000000000000000000001361216214232500303510ustar00rootroot00000000000000# pack-refs with: peeled 480095882d281ed676fe5b863569520e54a7d5c0 refs/remotes/origin/master libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_unchanged/refs/000077500000000000000000000000001216214232500272015ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_unchanged/refs/heads/000077500000000000000000000000001216214232500302655ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_unchanged/refs/heads/master000066400000000000000000000000511216214232500314770ustar00rootroot00000000000000480095882d281ed676fe5b863569520e54a7d5c0 libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_unchanged/refs/remotes/000077500000000000000000000000001216214232500306575ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_unchanged/refs/remotes/origin/000077500000000000000000000000001216214232500321465ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/modules/sm_unchanged/refs/remotes/origin/HEAD000066400000000000000000000000401216214232500325640ustar00rootroot00000000000000ref: refs/remotes/origin/master libgit2-0.19.0/tests-clar/resources/submod2/.gitted/objects/000077500000000000000000000000001216214232500235705ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/objects/09/000077500000000000000000000000001216214232500240205ustar00rootroot00000000000000460e5b6cbcb05a3e404593c32a3aa7221eca0e000066400000000000000000000003051216214232500311660ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/objects/09xM 0`)Jc `LZZ _2HbۮNotrP乷D6mg7Pyеf^Hţ@1)Zz}gCo_,lph1Xڿ,R(Ň3Zmt[yv$@b(bJcc"Pr5 <libgit2-0.19.0/tests-clar/resources/submod2/.gitted/objects/14/000077500000000000000000000000001216214232500240145ustar00rootroot00000000000000fe9ccf104058df25e0a08361c4494e167ef243000066400000000000000000000002041216214232500310050ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/objects/14xM F]sfhcc;ހ@I(_O{s%@> ^!F'!諲l_q4E޶RݏS'n>>m^\w^$X_迦xE_.9}libgit2-0.19.0/tests-clar/resources/submod2/.gitted/objects/22/000077500000000000000000000000001216214232500240135ustar00rootroot00000000000000ce3e0311dda73a5992d54a4a595518d3876ea7000066400000000000000000000002651216214232500310200ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/objects/22x 0Eݶ_Q. . W"!1 !3 >+.9=3W(n-:;j[" W{ޕQZW,2 iviyh T/={ !@b(bJcSPrŌ {`|%imp콡=IÿW26B@)|)glibgit2-0.19.0/tests-clar/resources/submod2/.gitted/objects/25/000077500000000000000000000000001216214232500240165ustar00rootroot000000000000005546424b0efb847b1bfc91dbf7348b277f8970000066400000000000000000000002351216214232500310330ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/objects/25xͻ 1aݧۻa%r\d&_񆫂؞ΧCbXͶ\u̶G=ON/(=Mp.}דAEKrZUrhw~Fb LΗ r s%qrN7'%Wlibgit2-0.19.0/tests-clar/resources/submod2/.gitted/objects/2a/000077500000000000000000000000001216214232500240725ustar00rootroot0000000000000030f1e6f94b20917005a21273f65b406d0f8bad000066400000000000000000000002201216214232500307570ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/objects/2ax 1m/_ϰ In+vf\No7Ցuj uK0.VfRu #KE}D[-e!809` QFdOk#cؙsL|Wgt libgit2-0.19.0/tests-clar/resources/submod2/.gitted/objects/42/000077500000000000000000000000001216214232500240155ustar00rootroot00000000000000cfb95cd01bf9225b659b5ee3edcc78e8eeb478000066400000000000000000000000501216214232500314720ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/objects/42xKOR02c,VD<̜T.O !libgit2-0.19.0/tests-clar/resources/submod2/.gitted/objects/57/000077500000000000000000000000001216214232500240235ustar00rootroot00000000000000958699c2dc394f81cfc76950e9c3ac3025c398000066400000000000000000000002101216214232500307700ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/objects/57x+)JMU042f040031QK,O)I-fGsW[?o],UEQ%Wh6#=-g?,Flibgit2-0.19.0/tests-clar/resources/submod2/.gitted/objects/60/000077500000000000000000000000001216214232500240155ustar00rootroot000000000000007d96653d4d0a4f733107f7890c2e67b55b620d000066400000000000000000000000651216214232500306640ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/objects/60x+)JMU06c040031QH+I+)f^rp쪨+DovN~libgit2-0.19.0/tests-clar/resources/submod2/.gitted/objects/74/000077500000000000000000000000001216214232500240225ustar00rootroot0000000000000084482eb8db738cafa696993664607500a3f2b9000066400000000000000000000002551216214232500307060ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/objects/74xM0vo %Ё>OZw4# }_7/2nt |Ns[/=  2qwmZpL)D4ƚfu`6%˘s'uLz\e6DmsWV7V[IuB )]M=libgit2-0.19.0/tests-clar/resources/submod2/.gitted/objects/7b/000077500000000000000000000000001216214232500241005ustar00rootroot00000000000000a4c5c3561daa5ab1a86215cfb0587e96d404d6000066400000000000000000000000601216214232500312150ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/objects/7bxKOR06c,VD̜T< 'Hd&Ur<libgit2-0.19.0/tests-clar/resources/submod2/.gitted/objects/87/000077500000000000000000000000001216214232500240265ustar00rootroot000000000000003585b94bdeabccea991ea5e3ec1a277895b698000066400000000000000000000002111216214232500313400ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/objects/87x+)JMU042f040031QK,O)I-fGsW[?o],UEQ%WhUWRQs¢+4df[q?2(d'Ƨd1$NK/6dɣ5:jTUZfN*1*EΎ{Lŋw[* 'g$楧ăz0LՐV/43/dJ3RSSZAҼlܒY\YRL<7Jlibgit2-0.19.0/tests-clar/resources/submod2/.gitted/objects/f5/000077500000000000000000000000001216214232500241025ustar00rootroot000000000000004414c25e6d24fe39f5c3f128d7c8a17bc23833000066400000000000000000000002041216214232500310750ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/.gitted/objects/f5xe 0aSbOz12 1342560358 -0700 commit (initial): Initial commit libgit2-0.19.0/tests-clar/resources/submod2/not-submodule/.gitted/logs/refs/000077500000000000000000000000001216214232500266375ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/not-submodule/.gitted/logs/refs/heads/000077500000000000000000000000001216214232500277235ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/not-submodule/.gitted/logs/refs/heads/master000066400000000000000000000002431216214232500311400ustar00rootroot000000000000000000000000000000000000000000000000000000 68e92c611b80ee1ed8f38314ff9577f0d15b2444 Russell Belfer 1342560358 -0700 commit (initial): Initial commit libgit2-0.19.0/tests-clar/resources/submod2/not-submodule/.gitted/objects/000077500000000000000000000000001216214232500263655ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/not-submodule/.gitted/objects/68/000077500000000000000000000000001216214232500266225ustar00rootroot00000000000000e92c611b80ee1ed8f38314ff9577f0d15b2444000066400000000000000000000002041216214232500336230ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2/not-submodule/.gitted/objects/68xA E]sf(LKc;`I@ yȅN2C@ivpɹUYM 1342559662 -0700 commit (initial): Initial commit 6b31c659545507c381e9cd34ec508f16c04e149e 41bd4bc3df978de695f67ace64c560913da11653 Russell Belfer 1342559709 -0700 commit: Adding test file 41bd4bc3df978de695f67ace64c560913da11653 5e4963595a9774b90524d35a807169049de8ccad Russell Belfer 1342559726 -0700 commit: Updating test file 5e4963595a9774b90524d35a807169049de8ccad 480095882d281ed676fe5b863569520e54a7d5c0 Russell Belfer 1342559925 -0700 commit: One more update libgit2-0.19.0/tests-clar/resources/submod2_target/.gitted/logs/refs/000077500000000000000000000000001216214232500254105ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2_target/.gitted/logs/refs/heads/000077500000000000000000000000001216214232500264745ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2_target/.gitted/logs/refs/heads/master000066400000000000000000000011651216214232500277150ustar00rootroot000000000000000000000000000000000000000000000000000000 6b31c659545507c381e9cd34ec508f16c04e149e Russell Belfer 1342559662 -0700 commit (initial): Initial commit 6b31c659545507c381e9cd34ec508f16c04e149e 41bd4bc3df978de695f67ace64c560913da11653 Russell Belfer 1342559709 -0700 commit: Adding test file 41bd4bc3df978de695f67ace64c560913da11653 5e4963595a9774b90524d35a807169049de8ccad Russell Belfer 1342559726 -0700 commit: Updating test file 5e4963595a9774b90524d35a807169049de8ccad 480095882d281ed676fe5b863569520e54a7d5c0 Russell Belfer 1342559925 -0700 commit: One more update libgit2-0.19.0/tests-clar/resources/submod2_target/.gitted/objects/000077500000000000000000000000001216214232500251365ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2_target/.gitted/objects/06/000077500000000000000000000000001216214232500253635ustar00rootroot00000000000000362fe2fdb7010d0e447b4fb450d405420479a1000066400000000000000000000000671216214232500322550ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2_target/.gitted/objects/06x+)JMU0`040031Qrutu+(a-ŏ/C:sH[ blibgit2-0.19.0/tests-clar/resources/submod2_target/.gitted/objects/0e/000077500000000000000000000000001216214232500254425ustar00rootroot000000000000006a3ca48bd47cfe67681acf39aa0b10a0b92484000066400000000000000000000000651216214232500326440ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2_target/.gitted/objects/0exKOR01`,VD̜T|̴J<$ 4' libgit2-0.19.0/tests-clar/resources/submod2_target/.gitted/objects/17/000077500000000000000000000000001216214232500253655ustar00rootroot00000000000000d0ece6e96460a06592d9d9d000de37ba4232c5000066400000000000000000000001351216214232500324320ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2_target/.gitted/objects/17x+)JMU0`040031Qrutu+(a-ŏ/C:sH[ *-3'5$?>7?%3/fIR-Wq ,ة!libgit2-0.19.0/tests-clar/resources/submod2_target/.gitted/objects/41/000077500000000000000000000000001216214232500253625ustar00rootroot00000000000000bd4bc3df978de695f67ace64c560913da11653000066400000000000000000000002431216214232500325330ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2_target/.gitted/objects/41x 0vh}K%ЁR8=͓u+CZD@%z1hrl b5Lꛊl|o57:anОщvQT:!oY)p/st7h Q QզTm*Ga^DFlibgit2-0.19.0/tests-clar/resources/submod2_target/.gitted/objects/48/000077500000000000000000000000001216214232500253715ustar00rootroot000000000000000095882d281ed676fe5b863569520e54a7d5c0000066400000000000000000000002431216214232500321660ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2_target/.gitted/objects/48x[ >@QG(tˤ $NJ(e.212K${Ml-%E* Y]uk"IT&k,IC}J!pi9^\^;錷 (D"pNJuo)+C*ùXBElibgit2-0.19.0/tests-clar/resources/submod2_target/.gitted/objects/5e/000077500000000000000000000000001216214232500254475ustar00rootroot000000000000004963595a9774b90524d35a807169049de8ccad000066400000000000000000000002471216214232500322550ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2_target/.gitted/objects/5ex[j0SRUȻ`A^߿Bu6|P# 2D:]Uk˽m IIz-WQة4VʌkHB Lw]1>y[ k_w'=T[߷4_0 Hlibgit2-0.19.0/tests-clar/resources/submod2_target/.gitted/objects/6b/000077500000000000000000000000001216214232500254455ustar00rootroot0000000000000031c659545507c381e9cd34ec508f16c04e149e000066400000000000000000000002031216214232500323040ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2_target/.gitted/objects/6bxQ !Evoy*_@g#hOh^9wSòf1*[Ic Ԥpk Α\S߇l@.^QpF(:D5zr~ en8libgit2-0.19.0/tests-clar/resources/submod2_target/.gitted/objects/73/000077500000000000000000000000001216214232500253675ustar00rootroot00000000000000ba924a80437097795ae839e66e187c55d3babf000066400000000000000000000001351216214232500324060ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2_target/.gitted/objects/73x+)JMU0`040031Qrutu+(a-ŏ/C:sH[ *-3'5$?>7?%3b[,m*um:oLo#libgit2-0.19.0/tests-clar/resources/submod2_target/.gitted/objects/78/000077500000000000000000000000001216214232500253745ustar00rootroot000000000000000d7397f5e8f8f477fb55b7af3accc2154b2d4a000066400000000000000000000001521216214232500327010ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2_target/.gitted/objects/78x-10 Fa0p(N-ӡғq]>ks*? |m“i@mV'`).-1 x uxt(+9efbdadaa4a582778d4584385495559ea0994b000066400000000000000000000001471216214232500324300ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2_target/.gitted/objects/78x 0 )?= NlOkj8&r qJW7B<fK8#Q1C-"e̫>'@libgit2-0.19.0/tests-clar/resources/submod2_target/.gitted/objects/88/000077500000000000000000000000001216214232500253755ustar00rootroot0000000000000034b635dd468a83cb012f6feace968c1c9f5d6e000066400000000000000000000001211216214232500327000ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2_target/.gitted/objects/88xKOR0d,VD̜T|̴J<$ 4'˳D!1(51R!#X8?7U$R vlibgit2-0.19.0/tests-clar/resources/submod2_target/.gitted/objects/d0/000077500000000000000000000000001216214232500254415ustar00rootroot000000000000005f2cd5cc77addf68ed6f50d622c9a4f732e6c5000066400000000000000000000001351216214232500330330ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2_target/.gitted/objects/d0x+)JMU0`040031Qrutu+(a-ŏ/C:sH[ *-3'5$?>7?%3d]ӌM둙"libgit2-0.19.0/tests-clar/resources/submod2_target/.gitted/refs/000077500000000000000000000000001216214232500244445ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2_target/.gitted/refs/heads/000077500000000000000000000000001216214232500255305ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submod2_target/.gitted/refs/heads/master000066400000000000000000000000511216214232500267420ustar00rootroot00000000000000480095882d281ed676fe5b863569520e54a7d5c0 libgit2-0.19.0/tests-clar/resources/submod2_target/README.txt000066400000000000000000000001521216214232500236430ustar00rootroot00000000000000This is the target for submod2 submodule links. Don't add commits casually because you make break tests. libgit2-0.19.0/tests-clar/resources/submod2_target/file_to_modify000066400000000000000000000001511216214232500250570ustar00rootroot00000000000000This is a file to modify in submodules It already has some history. You can add local changes as needed. libgit2-0.19.0/tests-clar/resources/submodules/000077500000000000000000000000001216214232500214105ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submodules/.gitted/000077500000000000000000000000001216214232500227465ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submodules/.gitted/HEAD000066400000000000000000000000271216214232500233710ustar00rootroot00000000000000ref: refs/heads/master libgit2-0.19.0/tests-clar/resources/submodules/.gitted/config000066400000000000000000000001571216214232500241410ustar00rootroot00000000000000[core] repositoryformatversion = 0 filemode = true bare = false logallrefupdates = true ignorecase = true libgit2-0.19.0/tests-clar/resources/submodules/.gitted/description000066400000000000000000000001111216214232500252050ustar00rootroot00000000000000Unnamed repository; edit this file 'description' to name the repository. libgit2-0.19.0/tests-clar/resources/submodules/.gitted/index000066400000000000000000000006301216214232500237770ustar00rootroot00000000000000DIRCOjckOjckPabx0QN%l}'=ysW .gitmodulesOoxOoxWg?tpuaddedOjGOjGO! +t݌"modifiedOjKOjKON̦_ӻn$MO_TwPtestrepoOoxOoxW +t݌" unmodified}JG libgit2-0.19.0/tests-clar/resources/submodules/.gitted/info/000077500000000000000000000000001216214232500237015ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submodules/.gitted/info/exclude000066400000000000000000000003711216214232500252560ustar00rootroot00000000000000# git ls-files --others --exclude-from=.git/info/exclude # Lines that start with '#' are comments. # For a project mostly in C, the following would be a good set of # exclude patterns (uncomment them if you want to use them): # *.[oa] # *~ ignored libgit2-0.19.0/tests-clar/resources/submodules/.gitted/info/refs000066400000000000000000000000731216214232500245630ustar00rootroot0000000000000009176a980273d801a3e37cc45c84af1366501ed9 refs/heads/master libgit2-0.19.0/tests-clar/resources/submodules/.gitted/logs/000077500000000000000000000000001216214232500237125ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submodules/.gitted/logs/HEAD000066400000000000000000000005131216214232500243350ustar00rootroot000000000000000000000000000000000000000000000000000000 09176a980273d801a3e37cc45c84af1366501ed9 Russell Belfer 1332365253 -0700 commit (initial): initial commit 09176a980273d801a3e37cc45c84af1366501ed9 97896810b3210244a62a82458b8e0819ecfc6850 Russell Belfer 1332780781 -0700 commit: Setting up gitmodules libgit2-0.19.0/tests-clar/resources/submodules/.gitted/logs/refs/000077500000000000000000000000001216214232500246515ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submodules/.gitted/logs/refs/heads/000077500000000000000000000000001216214232500257355ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submodules/.gitted/logs/refs/heads/master000066400000000000000000000005131216214232500271520ustar00rootroot000000000000000000000000000000000000000000000000000000 09176a980273d801a3e37cc45c84af1366501ed9 Russell Belfer 1332365253 -0700 commit (initial): initial commit 09176a980273d801a3e37cc45c84af1366501ed9 97896810b3210244a62a82458b8e0819ecfc6850 Russell Belfer 1332780781 -0700 commit: Setting up gitmodules libgit2-0.19.0/tests-clar/resources/submodules/.gitted/objects/000077500000000000000000000000001216214232500243775ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submodules/.gitted/objects/26/000077500000000000000000000000001216214232500246265ustar00rootroot00000000000000a3b32a9b7d97486c5557f5902e8ac94638145e000066400000000000000000000001371216214232500315130ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submodules/.gitted/objects/26x%= 0 F])0"I*|-t{?2ilV8$mvkk*F DA=(=|=6 DAv=A}&'O$=libgit2-0.19.0/tests-clar/resources/submodules/.gitted/objects/78/000077500000000000000000000000001216214232500246355ustar00rootroot00000000000000308c9251cf4eee8b25a76c7d2790c73d797357000066400000000000000000000001411216214232500315750ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submodules/.gitted/objects/78xKOR`..MO)IUP*I-.)J-W,H,PU qqũEEIE9I%F U@Ңb0dP %Mlibgit2-0.19.0/tests-clar/resources/submodules/.gitted/objects/97/000077500000000000000000000000001216214232500246365ustar00rootroot00000000000000896810b3210244a62a82458b8e0819ecfc6850000066400000000000000000000002511216214232500313330ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submodules/.gitted/objects/97x[ 0E*fʤS K4ݿwׅ9p2MCFP @u..p!OYdiYU'̕8XbPn6 ħԞ1[q}0qc[W#1fR:SZ+Y+{tdlvOmu_}5i` Klibgit2-0.19.0/tests-clar/resources/submodules/.gitted/objects/b6/000077500000000000000000000000001216214232500247065ustar00rootroot000000000000000fd986699ba4e9e68bea07cf8e793f323ef888000066400000000000000000000002121216214232500321160ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submodules/.gitted/objects/b6x+)JMU00a040031QK,O)I-f0x]Z m+áRRsRKRS8Ͼ_r !Qw}*K(3,y'LwR54II+O8libgit2-0.19.0/tests-clar/resources/submodules/.gitted/objects/d5/000077500000000000000000000000001216214232500247075ustar00rootroot00000000000000f7fc3f74f7dec08280f370a975b112e8f60818000066400000000000000000000000251216214232500317220ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submodules/.gitted/objects/d5xKOR0cHLIIMKlibgit2-0.19.0/tests-clar/resources/submodules/.gitted/objects/e3/000077500000000000000000000000001216214232500247065ustar00rootroot0000000000000050052cc767cd1fcb37e84e9a89e701925be4ae000066400000000000000000000001701216214232500320510ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submodules/.gitted/objects/e3xA @ EuN1xB]]IF'wDq'O㬿Zw<@\SI(H#:2(Ȯ`9)D*ط*k(NtOr~햰 Glibgit2-0.19.0/tests-clar/resources/submodules/.gitted/objects/info/000077500000000000000000000000001216214232500253325ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submodules/.gitted/objects/info/packs000066400000000000000000000000661216214232500263600ustar00rootroot00000000000000P pack-b69d04bb39ac274669e2184e45bd90015d02ef5b.pack libgit2-0.19.0/tests-clar/resources/submodules/.gitted/objects/pack/000077500000000000000000000000001216214232500253155ustar00rootroot00000000000000pack-b69d04bb39ac274669e2184e45bd90015d02ef5b.idx000066400000000000000000000022041216214232500342330ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submodules/.gitted/objects/packtOc js|\fP +t݌"XWN)ìO 1332366307 -0700 clone: from /Users/rb/src/libgit2/tests/resources/testrepo.git libgit2-0.19.0/tests-clar/resources/submodules/testrepo/.gitted/logs/refs/000077500000000000000000000000001216214232500265165ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submodules/testrepo/.gitted/logs/refs/heads/000077500000000000000000000000001216214232500276025ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submodules/testrepo/.gitted/logs/refs/heads/master000066400000000000000000000003051216214232500310160ustar00rootroot000000000000000000000000000000000000000000000000000000 a65fedf39aefe402d3bb6e24df4d4f5fe4547750 Russell Belfer 1332366307 -0700 clone: from /Users/rb/src/libgit2/tests/resources/testrepo.git libgit2-0.19.0/tests-clar/resources/submodules/testrepo/.gitted/objects/000077500000000000000000000000001216214232500262445ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submodules/testrepo/.gitted/objects/13/000077500000000000000000000000001216214232500264675ustar00rootroot0000000000000085f264afb75a56a5bec74243be9b367ba4ca08000066400000000000000000000000231216214232500336760ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submodules/testrepo/.gitted/objects/13xKOR0aHSDlibgit2-0.19.0/tests-clar/resources/submodules/testrepo/.gitted/objects/18/000077500000000000000000000000001216214232500264745ustar00rootroot000000000000001037049a54a1eb5fab404658a3a250b44335d7000066400000000000000000000000631216214232500332760ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submodules/testrepo/.gitted/objects/18x+)JMU06a040031Qrutuen~{T}ǝ6^rqh10dff58d8a660512d4832e740f692884338ccd000066400000000000000000000001671216214232500333520ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submodules/testrepo/.gitted/objects/18x+)JMU044b040031QrutueXlmmAṃJ}G;UTWRQຳyv;slzC8Ti^j9XrѶ_,ٟ#4'^A0ulibgit2-0.19.0/tests-clar/resources/submodules/testrepo/.gitted/objects/1f/000077500000000000000000000000001216214232500265525ustar00rootroot0000000000000067fc4386b2d171e0d21be1c447e12660561f9b000066400000000000000000000000251216214232500334550ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submodules/testrepo/.gitted/objects/1fxKOR0c0+(libgit2-0.19.0/tests-clar/resources/submodules/testrepo/.gitted/objects/27/000077500000000000000000000000001216214232500264745ustar00rootroot000000000000000b8ea76056d5cad83af921837702d3e3c2924d000066400000000000000000000000251216214232500334650ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submodules/testrepo/.gitted/objects/27xKOR0c0+(libgit2-0.19.0/tests-clar/resources/submodules/testrepo/.gitted/objects/32/000077500000000000000000000000001216214232500264705ustar00rootroot0000000000000059a6bd5b57fb9c1281bb7ed3167b50f224cb54000066400000000000000000000000621216214232500336170ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submodules/testrepo/.gitted/objects/32x+)JMU06f040031Q0+(aOܶbK?TK elibgit2-0.19.0/tests-clar/resources/submodules/testrepo/.gitted/objects/36/000077500000000000000000000000001216214232500264745ustar00rootroot0000000000000097d64be941a53d4ae8f6a271e4e3fa56b022cc000066400000000000000000000000271216214232500337060ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submodules/testrepo/.gitted/objects/36xKOR`JLU%$>libgit2-0.19.0/tests-clar/resources/submodules/testrepo/.gitted/objects/45/000077500000000000000000000000001216214232500264745ustar00rootroot00000000000000b983be36b73c0788dc9cbcb76cbb80fc7bb057000066400000000000000000000000221216214232500340530ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submodules/testrepo/.gitted/objects/45xKOR0flibgit2-0.19.0/tests-clar/resources/submodules/testrepo/.gitted/objects/4a/000077500000000000000000000000001216214232500265505ustar00rootroot00000000000000202b346bb0fb0db7eff3cffeb3c70babbd2045000066400000000000000000000002401216214232500343000ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submodules/testrepo/.gitted/objects/4axQ 0D)6ͦ "xO-FbEo0 Ǥ,ske[Pn8R,EpD?g}^3 <GhYK8ЖDA);gݧjp4-r;sGA4ۺ=(in7IKFElibgit2-0.19.0/tests-clar/resources/submodules/testrepo/.gitted/objects/5b/000077500000000000000000000000001216214232500265525ustar00rootroot000000000000005b025afb0b4c913b4c338a42934a3863bf3644000066400000000000000000000002361216214232500334470ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submodules/testrepo/.gitted/objects/5bx 1ENi@k2 "X$YW0YcÅszMD08!s Xgd::@X0Pw"F/RUzmZZV}|/o5I!1z:vUim}/> F-libgit2-0.19.0/tests-clar/resources/submodules/testrepo/.gitted/objects/75/000077500000000000000000000000001216214232500264775ustar00rootroot00000000000000057dd4114e74cca1d750d0aee1647c903cb60a000066400000000000000000000001671216214232500336100ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submodules/testrepo/.gitted/objects/75x+)JMU044b040031Qrutuen~{T}ǝ6^r"(1/9#>-3'Uug>6wٞOpҼr_ʧ+O\\iy|tI/libgit2-0.19.0/tests-clar/resources/submodules/testrepo/.gitted/objects/76/000077500000000000000000000000001216214232500265005ustar00rootroot000000000000003d71aadf09a7951596c9746c024e7eece7c7af000066400000000000000000000002571216214232500337420ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submodules/testrepo/.gitted/objects/76xAj!?009o}H6}jUPPZ&Y AԛpFdpz[fYPqLJ.,Z`Ů.`v q $5+9Ot>/DE/龡W*eVdf1>覭ěʙFThk.i^0?PR,libgit2-0.19.0/tests-clar/resources/submodules/testrepo/.gitted/objects/7b/000077500000000000000000000000001216214232500265545ustar00rootroot000000000000004384978d2493e851f9cca7858815fac9b10980000066400000000000000000000002211216214232500333650ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submodules/testrepo/.gitted/objects/7bx-A0={7!] ,X@`5ds?0OhBR&*4]Mo ȡNɾ09(J|1$pD82$"GgvdjG]j7x22]s0libgit2-0.19.0/tests-clar/resources/submodules/testrepo/.gitted/objects/81/000077500000000000000000000000001216214232500264745ustar00rootroot000000000000004889a078c031f61ed08ab5fa863aea9314344d000066400000000000000000000001221216214232500334630ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submodules/testrepo/.gitted/objects/81x+)JMU0d040031QrutueXlmmAṃJ}G;UZWRQ°\erw solibgit2-0.19.0/tests-clar/resources/submodules/testrepo/.gitted/objects/84/000077500000000000000000000000001216214232500264775ustar00rootroot0000000000000096071c1b46c854b31185ea97743be6a8774479000066400000000000000000000001761216214232500332250ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submodules/testrepo/.gitted/objects/84x 1Nۀn` V.`.pa Ô{StlH,_9$$cf&hXQ*g)cV~p~"Q@JnZuӶL 6libgit2-0.19.0/tests-clar/resources/submodules/testrepo/.gitted/objects/94/000077500000000000000000000000001216214232500265005ustar00rootroot000000000000004c0f6e4dfa41595e6eb3ceecdb14f50fe18162000066400000000000000000000001671216214232500340560ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submodules/testrepo/.gitted/objects/94x+)JMU044b040031QrutueXlmmAṃJ}G;UTWRQ`6Kǥ^/-*|W3Py`%E\&g|0{Ӎ1Xlibgit2-0.19.0/tests-clar/resources/submodules/testrepo/.gitted/objects/9a/000077500000000000000000000000001216214232500265555ustar00rootroot0000000000000003079b8a8ee85a0bee58bf9be3da8b62414ed4000066400000000000000000000000621216214232500340550ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submodules/testrepo/.gitted/objects/9ax+)JMU06f040031Q0+(aP[v L libgit2-0.19.0/tests-clar/resources/submodules/testrepo/.gitted/objects/9f/000077500000000000000000000000001216214232500265625ustar00rootroot00000000000000d738e8f7967c078dceed8190330fc8648ee56a000066400000000000000000000002401216214232500336770ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submodules/testrepo/.gitted/objects/9fx[ 0E*fդ "W0-Ft݁pS[Yx^ Db CLhut}8X*4ZsYUA X3RM) s6輢Mរ&Jm;}<\@ޏpĀv?jۺL?Hlibgit2-0.19.0/tests-clar/resources/submodules/testrepo/.gitted/objects/a4/000077500000000000000000000000001216214232500265505ustar00rootroot00000000000000a7dce85cf63874e984719f4fdd239f5145052f000066400000000000000000000003101216214232500335760ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submodules/testrepo/.gitted/objects/a4x;j1Dmdǎ|M3`V{ >QvL0I?!4Z=!צ8F!rsQy9]$D&l6A>jFWҵ IKNiZ%S  U~̽>' w [ DGڡQ-M>dO}\8g_ШoYrlibgit2-0.19.0/tests-clar/resources/submodules/testrepo/.gitted/objects/a6/000077500000000000000000000000001216214232500265525ustar00rootroot000000000000005fedf39aefe402d3bb6e24df4d4f5fe4547750000066400000000000000000000002261216214232500341420ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submodules/testrepo/.gitted/objects/a6xQ !@sBQ" ٱ r{:żW9гVlq=(1/9#>-3'Uug>6wٞOpҼr_ʧ+O\\iy|tI=&libgit2-0.19.0/tests-clar/resources/submodules/testrepo/.gitted/objects/b2/000077500000000000000000000000001216214232500265475ustar00rootroot000000000000005fa35b38051e4ae45d4222e795f9df2e43f1d1000066400000000000000000000002071216214232500336230ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submodules/testrepo/.gitted/objects/b2xA 0a9I p'1Ѷv\x{cVpvWgǎ0x[ ]"g#{rD Cot N U $?9-p+1^Qx9O\C m'D {mV(+l,libgit2-0.19.0/tests-clar/resources/submodules/testrepo/.gitted/objects/b6/000077500000000000000000000000001216214232500265535ustar00rootroot00000000000000361fc6a97178d8fc8639fdeed71c775ab52593000066400000000000000000000001201216214232500336610ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submodules/testrepo/.gitted/objects/b6x+)JMU03f040031Q0+(axeiwg26Eo(g0E.{PbTNilibgit2-0.19.0/tests-clar/resources/submodules/testrepo/.gitted/objects/be/000077500000000000000000000000001216214232500266325ustar00rootroot000000000000003563ae3f795b2b4353bcce3a527ad0a4f7f644000066400000000000000000000003021216214232500337540ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submodules/testrepo/.gitted/objects/bexKj1D)zUB-0uV9<#+W-/y.7 libgit2-0.19.0/tests-clar/resources/submodules/testrepo/.gitted/objects/pack/000077500000000000000000000000001216214232500271625ustar00rootroot00000000000000pack-a81e489679b7d3418f9ab594bda8ceb37dd4c695.idx000066400000000000000000001331001216214232500363030ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submodules/testrepo/.gitted/objects/packtOc '*37AMS\fksx}  "'14?CDGNW\`fkorz ),16?CMOUY]dlr{#/27@FMQY_clqy $(35;<DKNW]aem}  "+3<DINZ_ailrx} ),17>CFINU\i%J7B5/РC%QK;QYC*˥ۤ?y~S7U.!7EL5ue].SO!ܸrX27*pls Žmݩ@4}`;N-Vvj%r=-]S:)_-V}E61n$Dm~]v^4I|xg6d%q[WX%hWʐ;髭Ҹ 8tCOPrd^VY% 6zg )G%O &!r: yz(>eėLp%_z-NG@' Ӿ%v4QD ɿ̎Ǡu8hPp3V?Maui-JYXX+|oCۻzQdƣ2A `rѲJ^ށ)΁9Րb-fqAkm+L=1b]GL仅 .z w i A3@/{UgM!& HZ.n}-|jSWˣ]0CF \g'pzU"O ;$b\k.$N(n!izal]3l @[5O)zsuPIt J n/<nU?,.C/xp߽aZ~sw]@hk]C<PLMn\|p"gXϋWfF'؋m1ÚKgoʚJ:| !-ij*=( pC֨h*]K@YJ{(wC5(;}鯂M ]FNBq?[if&hj_>y%!(HAìV\Qž еq0@ at|l+>/x%8e@NJ.i2{nU;:~"O5 Tun?dM3θ1k+}Vv 7SZdgǵwɌgm=Tj,SudzK-ZPq$ LX [*ns |mg-kh݂Rt0Q#٦V#{+uIϑ3 z4+cWkB Z=D]yߎǷϦ gTTҶI\  ^vE>Rq(?լq2 +@?] IWȼ( zR#䔟9` i^SUەmE$O .>o.7{Ęn yb`&`{ !qL܁w~E ҊCZȭHW dF kE{ B ILKR ,L m,`cE5pB3f ~ 1Nm0$FT~SЋd / SH2,ܙm1 ~ٹ/҄q= ͟&\͹ 'P7R cFdaKV< 0dO|Ėκ0q<{!r Y )F2k$'uHw yb5[M B׬. }g L.1 Rpuv1ȟ 7lH ~`yP dUbt $JjbZ m  VIML^&[&XDMBcVc'R)%q{"t1E7eP1n]QfmIljΎ()gTˣw9rfW  =M2u%sP{Wh5𺮇n0Âe@K+ CGkf'+P/{abU vvK(/YrO8&Z,:+lIػ)jr␳s.m=!ƾV@圉L~';K&I9}n:_edء;SGK0^q_>4p wd 7ɗ,QlmrV۬z4YhۿΟ'$VdRaZT&z1 %llV+mѷՙjkÌux'=ҙ|'| ݬͪu;/+J҂Y Ck^fw~!X"pÐ/aa|n ~9IʌIu[0ƢΣB/~LN\9Tz;=8òXޚCjRi9LOJ| 5"F\=VO㤥FMM]rlDȓ #9ߦ_o#8}:,ٟgrl1y) N!@%5z*+6qfNڶsb_ɞW2؊zHV6Ρ يawI9O5 <_-*64w<2f{ N+L6ZQsb穲S*y, ijS9qW<: aYK[67Ґ f>OcD18~M L IIaQq m@| J8 obG.36 Ħ>ا J ё > Ƽ &k_151d!>r ^,B.(!]IƀylʘU!dE5jImXY ي+=X"sX>}[Wm2"#l3޼A="_"uEyzf"nB kk1h@"><ܥ: ?x"󼗡VV{Qvp#Q;RBmP4G#nuyv;r p`/<#T]GzZQKƋ$m md}7!S*$4[ΙSA,Po$󡴕} I=BZ%no%-%%>JLee)1_%&?FIae0l&WS@%Z V jJT\%{FK?dI<>;%Ѣ }ˀ (&=s nPA'ƿ oZ, e'3ƭ%b_II''7d*jJDiJh 'v5Q,_k!]sk'x<> h4;(jx]Vd0L(vypMIo(w@Pn`eW@h(oZxHrYԲn)()(.Z 1Tu) :b7:O*ewko6 @5G*mǐhZ䱍1n *~gGBF=o$^*0X ̙ `YF+w:>9+zQMAgH+cYrxu:+ViF*I٨PG+?=9&ý#Sׁ`, 8#F4x2<t3,KwՑepW2>,0GMjص,WEDK-7F,W ԆJfKR,;9r4^,׈8Xp<8!v,ED#;P:Z}ѺC,%PjFO ,`8¾l`IH:?-8NsӦ]e h5TC}"-#aa[wy-$Ͽ_X>kSv3h.*F D=6 .>"._x HҁyQl҇!.gvt[*JBT ,M^aI(G2P!;%MF(]}TW0 2FFå" EA2ֹv~P/yr#g2LSPJ_ :s2M?YxEW3x?;1)xaR38{TkI\FB. 73E ݂3OTtlo#Y(}53jNF'Q,1;y>3j*@P>ch3*kCb\3΁'R@ݟXq.3=lTR6iP9}4:KRpѓ_%4BHn*>rX?4Xq\;q24ۥ*z# ü^v܍&'43x³~R ^#Z%~%5ivasi\nՕ5JI$BU=Q_5{#qmF h$O5S@.yʹ|y16 yxQYt0qRJ6z֞3p륱/yA6ͶfĹ6<*-ޚys T6Wxܛ3|ۘ6e(1Qܵ%Ǘb73Ef4pdt)yD|D7VIy(š Lm7 LP =y xoo/X7oIqE6DLD7?W tCG*)8=RwQ,N6A8dҪse1b70Ml8b!`0@ͽ1 S8'<[pښ9}^dIڞOLV9") (G7Pc\9X_VK16:*'g'p%0l:3dzUս0F%Id:a+;͍/#-bj:kpfKL[.m?;;T$:>d"FlIo :QN*( V9:LVCs"ק؏Z/:WrgT\ %ٹ] x;D67K|;Qo;59|J ԊI;k+8=WE8ۧ;?+uoJDI0;I>j3xPZZND;a6yCE@(=XӼM6t;k>VBmFE _٭Y>Bـ╕W.U \ 4_>3xCW[)nx;I>Y"4yV=$*+>f^իuşȶ3>`n5m>i J ?lSeS?ThjI*)[Xb?aWCbѐˋ? tIX1D ?Iq_?ۼ(܎ / h0-@3ָz"O@]Y_Mh@NRgIQ@cĪQ_+ͣc .@n?)$? II @rk\:v{S@x #q# {@ v6>ϘF@#ɺ~_A/ZL@zs*f)[Lt@_{ Fsi9R?@ᯃk&sҭhKmoA.䦧AVtLAA݃姹/p.ŦjA A ߆5g^(Aҏ8$ؖyVaA|!|t6k[MAX}\:Z? cAZpQFcKFA;"y2! B6tAD٬JC6'T]mB >_t7JB(~q7C$`3.NB.߆ҳd~%13ݟ4BZ,ipF~TbrB[<ՌzipzCJB`i7k12$XB`K F+Q`e64,Bua{*r,ҡ&MB|^pbbBE}BwP1wƩI(Y2RB@hyu1]"bCz0aϻ8*\C `NQ;N]^ζC$\mr~J}~c.C(3 PjE{GClڈGeIȝgC*˿[:S\oCC@.kJ(vÏFrD#l9KHŞ,Ö~vD(߷"c2x[D0! z<_0HDz|'IEa>DeLyQdCӷDSL®G hD!+ʌ'QHSNt1ED޽ĐCJPZ6v5EPK{^03o=*Euض24Z)yEQEBE'6ƂMTF+ӆmE6:E4~~*L"E8j( N"ژF3݁F$$c_}##s6F80~s{tڞU#kVF_UFSor F?mF@V_1HF]c6D4^F#O ID Fظe2fKb{YFwq='fg|mFB;[)'G\kkg6ZV+'4 GwӇ/YvGrm!M^GG0"BvW̏ynXG8$znG_:V@dw}!щG'2(a: *-MWGXN ן6tu {sG^uLQO:P:q%HzTҩ;%ץ;HCpmW)H]4j 5+YH.RDa)NQNIB~- 0Mm7IzC-O Dl8iI0kltGɒI^`_IBhsIhC3-:I#| E-J:+nQ. NUjJY?Oa+.!ʲDSoJeY./wm.LJ'4x8RD@M2JVV?QratjF5K #xw0* hK )>6Ip쭱KD#5}EI[K2y^FkeL;30kxd!,! LdQc赍gN՛*LeE1!F +r.֯"Lg_ {Re)L9s)BcGQLbr7y:M%vS `1 h-bgMP?J$P~tF<.9MRM[*!Qنb/]?wM`ESp?>3EMRwA5aaѠd#}N mM62 ؿ=؟3MNgi\2]NuVӘVN~`V3hN'Ⱦ}uΰ`w4rLmNYU|Sj IO o+kU7KzOU/r$]|On豳ȣI@-O9ߔ\*1)l[gx/f-f4?[̔Ixv&Cl[(N\ [a}RD\u.[ˠ@BRqڎ\l%'RQ$hmg Y\ѵcM wM|qBf]y)+D7)幺,]ef5챧+1Ɋ]@&^ċ%]y]>JbId]{0]U9ToA]蜽 C 6]Vx1NJ'ᶔD^m oyPc`^xGQmȝ^ l+t]b,d^4+/u$F (^טa̗k}ySeV7Ť _kgO#Hz%novk4lqҳhw5&lE C7fa2m j+C3m4*:>P-mdjMK:;HHmh9agRqJHm8CDPߠKimVgbǝmUh{7plSFEQn[X@.]@A%w+,n؟4UBPn+1N3MP֜Px,n^)޼ RY [n71rhIVnLކ[!c Bnݯ20e&o,)B5ӦfנoN,B0(o!xoj6 W'a o e8cO P?hr}$ްsrQzu/arN-̛W9Vy2v7s"d o4sP3z-ҡ_NjȞsc!J`s!?sV>rIϏjGs`*tr`RFsݒS'w×`DvКLjV 2-wܧ}u>x(7)?1eXuf^x2WӶ'-K;0QxE6hH!3~ xKup;D;x]?Z,"BF*Mşx'ErU̐Up#Ǹxe4x3 i_Y4yP{72u~y&͆m}u0 #X]y*.Fʴ y_Dr5]7"lylРk*sɉiտypm'f5` hZ}y.@<,p[z+ysu8UנZLjz;Oi`f>$;z2zl7V4dvU5,2{A"zu |2n} Kz-DR5P0zA9EvW枾nu{Qfѻ7{])2hO^^{!c{lln'n6GY7{ng얬A2Ճ{}9\|j̕z%m*kJI|%wQ,9q|lVM2(|)~(osS5l8 |kM-NY.U~xիJ ~Bk~|976HgMGD#.0~/!#p PJUTHf}LR kV1- Fl {(@(i#TaTW}K,Q9>L=D:2&=$]]wiUn-9NOq@b%}@AtYsGpcݷ+.jEySM톋d4;XM^.ey%$'=ؾ w>ͅopFw|hdQ5%qKȌbg0"1x :E> }Jܝ:kMAK-tc#j #Y였io`g[V;$coq!QNrW{Z[qf"e}#+r)Ǡ%ݸr<"W7tXW&6JtgfSnK 4vD—5L:ӫe,jH?r퓰@GQFOQ2Jyw]|v*흂;5L!r?GĬ̘c?ϺUk̃{&pgdcs#k뉃:սc {RSXz51=_@$δ~je/\ KHBW}-x1F<a8l,a9 ; cK44A_(Bv@WEt{zЄ,_i08E&g\!<f*a|=ɱ°kfNJl鬄#?D E߄,ɍ3S2^BxǞa99{MLɮ| NGJW7/88)d|N?4.!`DdyvF>TTCc-$5 UrUM Fvo  3Fsx|Jo$M4T7ې.iџVBJ!҆rlZ2A/v~ʚExxm y0#d|\w !meޕk8~;DwmÙ:69ah"~Ä {lz*؍f>6[O .҂ > G`O^Y"rA`=hYͫQ |6SV^"B? P6O*Y,uϽ9հ+y[ql3Uö͈D[DTmsFkP{uLX~/ Yҷo#=Is#ߏTk2EZ}npfIL38pPKZO8'4M[5et⿚,!}p)ɉF͹Oʉ)ςAL{dм؉+L>ሺ-_oD!*d8"|.JW܃&x$^|cqR\F ]Ӗ `ӮRW[/Imrs+S9M] #I܉?1fIF3ȢKʢGez<;p޹됉{M: ޔ'zeO_wM5'o\>UAm>@@[8k:ș 7ΉLgUϑ>ފo*;ώC7N\ AHM-ɈfKF|6S5x.t}mKC]kRO  DS }b_Srop=hmT󮽿Swv4#&Sh0dH/D郞 )$(j.3A<C^Vfoҏn72\ `LFy}pRhlY2Dh e7-Pк#Mu)||v^c A-D5t1#p>qˋVȪ 5𑗚bKTUwv8T}`*B9i<Í~WS_]z ~x3ajLh(e=lzm-an:ꌇλbZ*IAS7ȷŮ69z“Al+AQ!3 *l<ޒ v*O3"efe(w8:ҍ[~ MBGWyI4 KOT!6(Ǝz,Z[Z/smr济Én%-`egI|ـ̫q_|0[0ru#5#FB {PQ8᮫qD헺W(O۾ADɻFS,-| }kq%Wu;!b,0^_`&BAs"b|@v~ҴT1nxF)EnpX"IcY՝3 W3yk.# H9. cU.ۉ|ѿŠ4hOIskHwB/LdOݬW\n#RZ~},o6 uG#oIЄ'.|+x lTq8&eNB>M7(5wъ0GceWZӛR H)umP/(w|c9˜uqx-kɼ Cכ[`] k"5<\ |=Y,Q:irhV ԚzuAJa69<9!U B{h C睳<7vCWneޢ3k dmI]s?9 ! : M CV, VdJܪǿ0MקY.kkaA>ZR(FD٭ G=BGL m [Lv !i BdHhMA>`3ysw=/<V؞ρF:RmNA.e(5v 5x'W[̊F"F7ɄhvcQ";_U,Se ?jFQ*|AR0@V)}ci }g kg٬Y[oncbq񼡥^şb4U=*q MJONarpC;N h1LKJ7Fj1׋K,;^2XBFAa s:˹cd3%';#Z/R/ȫAOd)EZ_3.wVI_^*!{"%$2Z Ɯ9ä?9E=^7LUb{ݤ[;*Y5t#H-א?cmЈ2=j!W?^@m/cMUd5'@'ҳ'M[$ˤ'&A*[Vyy JsC}P}fh) O YU,R~[ab>6Y6 /-0m6ե= B^[^2c"9h \`#%ʤ*fQ`4![)D3ɉFfͨȦ})Ļ2>4DN {B3\Qpcw5"-ءk8ŪP uj2FV*dSVS"" ~|8̝\ f$~RԫLHCZopȆNUŔ?Ģ m:i\%q0ϧE_DU\n5~L%jv:2'!0#ZM %6svhGp_3\b) sFѣ姩ɲVnuT rc c9*o˨|rA?B@dZv!T+JN`)XEuG=!@@ cL 29vg]R+;i^Kl06o+s GSfwd۴?#N_3Bard'(PA]YmRT#i 4BQLֱ}yHyVl· 6yDYSSN 3|vث;a.w_" ūo0olcN<5h>!΍0Ǚ*k(cCpEn>e<M5*^|LE iWQ}%I=-Ab 09*<7፡uQsm/VܱK)zridb! /_ ɵR'~/뚰RKԩP |߷<`e讱9Q~D'Bh> d@Fnc"T4wyK0H1=~fђwi0SDu0),w*1Zt30ׯ;վ3 På̯U( ۆ寥'y^IABݰs,TG)ZL:9/wbC=Ӻga/*Kjp'8N1ن  ["˰VvcxMpnj冓srB#=5}tә XAKBuQu  >#tkBL@ ^'6ԟ}5ǮOi։7'mpnjA n[߷2>1:9m_uUL.gSv?v9͋b} fϊ0w`{` gVvHVp@/ŲJ@%CڲV%} mUo3B=1ޡgC#IF`Mqwc~$e Q̓k}j(lJ{iӳ4B;W'~Lk$N?-l!2"1aN,X4#U]*p^ŋ:t&VgpU!ޠ:=- i#q]TYiɒNqVid0bO#v)KT ]ywdġFR7{E/#C,*)N<EJ`4я}յP 1EiA9 ]~I.'յډg] 3w!j]3!Box$#%7چb{1F \޵*;v#&r(}#VG*AR} ;iv\F"AvU1y`C߼7Yѷ՟BI:JD @pOG/V4f-S撷~ٓ5pf)n,ټۼHgf_OrtkA,g@q%x=9pNکnJxd5$v ~%ɲ6j\Maѷ-;YM|=4n, ȑ)Ҙ#.HBpFj?5cdb>;gK Løc`ƞ#Bcָ+hxk {q#Dù#}nړL;y*sP_ЏCȹFPэ lNYB%!n%-K$K 01ּyNOXo ,̻d99yr[sa8M6z^@Ҍ+*/lܣ{h. Xپ??--%Y!jdb۝XxҚQ*dC#(`|~]o=3 W,n Jyb5\S@2I7L=g<]cASסfHu\"PXK6t;9%ǻ):iZCDɵ@ojSz,w{F[_ANoD®9ӽ"܃i ca<'<ưHzA[5g#ǜ3BQZT{/y8lI %bKlnڋG3`Ѣ^E^ZU` 'l62ېd3"U^x$7+_OZ1v'3S\[kI/3V΀+܃C߷UAQ.8I oc;mJwc BBL~ٟR_zҟx}?rQ zYxnam"g]Ac;"K㡘-  rF&L& YQ ѴZBFp8Trz<$);Us3zM'i1?@D,dH 6PiE, ;ؽjR`JLRLIR'~_H+py$X86/R4 9)HBcuV2کuz8lvLDO`Lݮ"3J||d!C8ˡ-2VHY,ug",v\V ƾٖ \!xb% qaI iY&Ѵ _MP1/+.5%'Hu3_QL,TzuCllW4 ѭۆv]*A 8_X`+QGe}gUƳ*~8A35+2U=YlU ~xM2G넧{DnmG☀+e9šN@C{E`I v ]!Aq弗}x]a!N2U N(oLFW+õ:5L[r'Ѝ<&h_I4.JFsh~Uy BxPIأNn=͇Hz3Lĵ/u i cG-?b?$HX`HCDP{ c0UPm-Ko1h \i\RLk:DUtnSffs¯@dG;_kΞɉ mqˬ dEꜤ \˜,5I*"L;퐻 Z}3cZdR"cB&3z=+kfQY9v_r5h?n r A)l)r:W8ly|秜_ !'PmAD5fKzo1߭{Izs%MEMu> us4sH tQ?VuFʖ&Gz#6}Х Р0h*&}mФK rZyT 66ˈP%aւ畝KaoZzY:_P'w Ǧ0}hD/TR6fUA2uYJ"i^`6{SHy ڠlS˖jE!^m]~{eJX?0#CպJM7%/P+G-^әA9o"O9OYdBOӲ>r58{EE4$@J*0ӫ4=^aދ>p1O Qm#&@Hķ3I1t,~(|9F7Y{".GD rd9us5ڢo`]Y8LF,R}!gϜYGG.r@gn"bzQ do35 kuԍQޡݎh,ԐE&.?g9e2BiԹvV?}" ԩ\؊ z^ՀKw?mʌHVpmP <<KGԸtj0?S1cjLx.EHhG^FRSYUwX ƄX'NiM/ ~hlǸFyI"Y\iklOVpDٹ܎@baH.m"0gUCJmc2'ZנtS/ s(x ׮bc&W0|3 >q _D:"~D_Ada/Bvq1AfW ENL `>ԯM +I=dN4Gع:ՇI^]g2~3m@_'sh{ِ70U^#VU >r٩e퍷 "&nzٻL;lQvRǰJ-Ic;@+CyHTUe/ަk\ rN IMPx ޱnϟy"L">y&>fgU5~0%hy[+saH pN:q5y߮n݊;@1b9"5Y'4FB|=r[{{OwEҝ|2c{GلfDhOhD_h5IE)A8WAc}߾|U|p Znvt:1oO t;Ӿ<,ΞglOtfg벾1z?VsM4vPo39äkzW/Ή'Eһ5Ts,NK=U7@RTN'0>N $f 6˹Sٜ[=ǷyEh'rķ-n6q{u'UE¾6kaPvf.`Co1$(b\)j=̧ڷ3h(Y68gQ1,blm6)ijGlS/#Q9۾'. :KhV$}8@f@q^M  ȫ(6`X^vQ4]'?_q4r jRt 2@|(WRդN?*~qU5~"N]}aދ;нG'A"@#0yV3GL5 z墅S] DWyʬ mDV2RϞ=-^,Oj"sK &tJEkn8ߏ";]8n,&Žb2gtėgV74K°1S?et^u3^Cu2KrwB\wtԪEV +\3 40B}cw!dEEA Df葛ɛvמt,#$7&@MK+ 1S},w芣g`Dy(z+2k6BMr*% hp*d6uEls""= !ܜl"r>"D#kL(k<*ߐ =$4l8M aՀ [-pEzИJhq^z-\(_G2 f[!<dC 6}1O1"BwB.{LV6ȷb/<Fs?2|Ar(C0H)Pސ, y^P#(v:C M WSF΂@yۥW=|#f ]DbW; RO% nmqO^_sfsMZbdLYrj&F^a6JzPnAӼn ~$1^55fynqt[Z'/튶/ ۳9Rez|S%?1f[4_jL?7Ck'8hT yTF{KxE{m&ꦢuV .Sp?# sVC0T"e)kDƠn5l.#؀Wd;?лp@Hs_Kn,%~ >[ɣ_jK]T/aM\9~OWtPw3 +ʍ aGaĕMVm)ˣEaĞS}$+$拏rjm6{ÝjdamBw &uuiՒ9VO} 8.֐zX99|*+FYav37K $v݂״k )7L+wJ-P#j`nM~Y0^dMZ-eAYdwBS6[OM'%O%d[u}M鉸_A.a$D[ۻo=PPlHF=Ake30i쁇L=j.}S<}%m$^I=,iGx=i51qUI4 ikp\!;򩊈3r}rk+[=A$Ҥn 8cUṾ0zTL vAwQ)<ʰY@krX!VQjǢ\.]HwՃqr?JO&N`g47 h}XG^6K;'ր.$% iq㽅Ec;lyn]-q@@|yn 0OJ@%\; ؘ!)G`~ Na,';iSж GklX<%6ώ%3z\vHǤ$WOc d)mk&Hq zbEfЄo."@Q$FdQrUA/_m9PuǾQ@a\rf SO/WcK[[yqATU'>U1 s\_3? < r3AQ!\ &qt4u}۪"3 #gv.a-] 5|XP- p8 39H2eF6å0LUG+EKNeV;H8a( ;ܩW2YbY5k"5<8:jB#pAez݇Gh}K3${ ,P(ld=iƩ|~30;顿i3c7ħp[40 ,3J(BrAZItAO-Փ/8$7JrLٕ}TV!l,qܪh:1Z tE၈9g KB\8r{YڶjU^3HHkk&UJl48w}cq/E.Wu 0qmiB9" 1{4b-@O~8ѐʨRJSϽŌ$ ^Qs*J<ɷ,F i:7& @uhEARN߱KFݹ`<-o^Hڐ٩3ͥ_ $OºMVC!!{hMbCmBalL* ۨcNa aۆrb-xkչ PnS&!x0RG?<g>|gg ^o&]mu' Y-wFdc] nB iؼjxE7k?=LKL4h8`.Qwav8QOީ؜1l)AySQC`8~x?|Z2ИǶ?pj}9 Wv9ii](Huf) [- o} L-={.dž]2ӛ6kR$h~7N;Iɶ%(24fJK\"Ucp<0'5onENW3nqۧu3eC}2iI\jU;_P 2(`#ki}zfzZt :$Ø1Rnۿ9N"!((d:"i$>Hwi搊aT y !6 +zjJyZWU`@^. lRZa@봜ԔNG!d33>`? \eňRп^`z檏+UVi%ҼRpZ73YF_JwC3mUHp{Nj(!5*]a94ӷ&R |hH#Ja(qSI_[IT݇xěZHP@؍j-@~@'4e\HFZW&e~3βDtaWcܒ1AC^A˜'Zvx' 5>ɲK;q@0J(w>&@[|SF쒚rrŃͿG[6jJQwahC?'C|Iت%RM'>)Q2C!X  ?%8ŠdžJ0 VR!TnxÈTuH,/MJSd"33:r3YH(ϴcŷv%n L6Ʀu7b"̍s b\elQvE}=I^8%!0Y.M~S3ⵜJe{reGNy%ʬЯXqM=|y/GB~i"y$W)y'EioJo/$f/PI%-*u7-? ty٫;M@u%$V| ^5pnCeUiR]7[[Ԣ+F+Ke˫_r; )oR{3) ``<QV`MhyGUAb-)mF(c `< w*붾10f%8E9$ fG6NUPSS9ZvPjFg4ȇo:%vXz룇^\ow/HfzE.0~=%9!Đ|lvF)Z\^X }x+y$姒 ]epGQ nNc?Ё</8%š%/ S%P7qWLhW9Ttwb iIGdRwdWolԝү,BtN;X?S;((ڼIRY:+!lR 4Fr]X3e,P筚E۠ݔ6c,$ Liϡ0]6JV jR*A'dKaDG ҏ`ha24bT<[&XɋIyoQBQbtTxdVz/ږ(8m~>6hcXbLX]u/mB}B[  $z,c=n&K-lƮF_a݇i؉[[,z iv9ELOm$$[hGE@DsvCѣ6/?rD՚~Zh:FЖJqTaΝe1ETJ3jC߃(NW noO uvJס&'}N >. ? !yg745!5ȿ/؏qbM 'qnt<,`5WkEXl^QoMlZDOz7 ѝ+o_D'aesOhi>>dB&E7oBJR]IiV=˃8%\7{|~^"/nO?J-s+2z  XF zʸ%EauG6sd],rWǽ b,LB0H ֊RnnR}ޫ!m0ԦAzAҷ}G!X!LYVt"3 =J)[Ƹk G#@ 2NLiJ/Ei؅rfo&Rc7WRݑi>ofݙ!-N9iYk)*V$*^~Vh|*wӍx^$YǚdƊJ\kJ6}|⚻~{dW?\2mO[_X}_`Tݞ)sR$=6 ޴ Թ/ dw j WbyǡgVaϪU,q#+D5$(d:W"S}YdʃPHV%2q&ɹ]nCJvSHhh-؏trTyh&[.˻0TCg6A4yeUCh240!u`x׍7A,TF]~Ms56 2 T4]}uWQ14\l Q?2UPW^rpr D{?-ye֨%pugY6yUS=hU0.xae˩l6du/dXm#bD 3=,r^l|zENsf<)£~Y7Z5`GbqnYHq48J JXV#-EI x"66\r%*apxc@d1MUgμx{{jTj82ycr-lmfLz(;}4] !h-:-/"3w@ *t4Jk-,uqC<ʶ`, K,…{VNUO\ۘxFp74:YP^DBb9lH%,3tV$SSwN1֨m6iz>0#yt煲oJ>\|7gI%4-%T?Degm;zļ#c,joπ'7y,ޓVHo_'OU&;4w)_d2&q ȵg4ˡf׭s= +w9!奡=>~/p!AubƂ. :[71)(7Y]yj"r8ҩѬ{8t6B)yn>ZZy (J#0ʗՕqTT@ZK\'8Kd ăU_!w>Wڔ`Kjpy9=RTPyts,s>c|lhH`KBحVi5\_eQυ[6AfM- 0tP(|)B˷̊"M@$zwʐ769-`ЈPg{'x(4{+  Mri)Aފ{r/6~L$L79[4bSt$ 3ZqYݸ4ykq *ZJt+Oi EfYmJaBr|}@'#Q;{zSfE})Gf' =:)Y`A(%R6nGͱlM^^-_8u#ɿmnOKx>wv  Ж !Fd)vzRSoR!W@~H9tF/x}3JEѡE Dx|?.ZAd !UQZIFqFvD~?'N AQ\%}}$iy(QȞqۈ}aURQ~E@aCKzp4y #}E|Ab^odfcNLzfr؀ӥl. 'c!nvDExFxR$xFbNnFnDR2;/^z=VW[xN&iFWuEWWvp1bkd}99Wg}rJ!yG[5(i`HKl|FU_Cy f-P~G 5+O]'Y{).̊ Pyi 1 Q{#X`{+Mzq7wc##A/ܪq+=EIvHkmr ֻ^xg|u{rn10`,aQ&/d{_|}<0gL oK"@'~fF*\ oiS jzBV*4bU#} %`7ЊsF7A`8b-zٝRĭb#iGHCya Px%?KL1?@]6vڇf Qy^- >p'\[6. m$R8yM|&P.OB?`fmbi:t2fm`DP8WrVO [+tyOiwN*li1``b000It VWK~R@cӈ{N|]P(x3"9Fa!%4:D8mj?>Mhߓ>>?IprKYg06q{nd(&<[JT_qm;rnscd+`2SQ-ܮy%}! e}Oq/?DP"gc\Mf>ng[Ë09p^~gSVrvüαw}Q uny}Xֈwza2i8T[ YO RXbYZNdMifQv `|fVBLFr],1X2 ?zV0RkOurWtHb<QH>3_B?B~9mwF^A^3#bFQeڴWyzį.,W[=hAz.VآvW*csiI dլH|.."%&LJiem[pIfh69|4[ Es#B|uO_/sFG!lw CLQ̓KivCbzoQ<t{p{?D"s<hO<e6Qz$t0IimOWWIevq@V vOV$=^4`E6~tvlsK n7ZX;wV:jFYU ^w _qgOTWaOЦkz.asanu@g|=Y|5.'^cOqx0 l0P>(D[2<jeGڒG|3Q~)lSjzdx! VYZpyzDllv<P?MmPvo_!JȁNQQx?2w 68@ #@%{/2,+[ItD`oK!htWL#\KtkQH-@W‡]oO&K O sGvd9'v~&,Pbn^V%x\T3usşxN~?O5B  7bIP}irV a+>ay{-4Zmkiv>ftSowhF\I9Im0keuu/,1H=Q}6 JH=:1pUWDԑ$?t~M]YpxKR[^EtL425{A?6\yqA{!!aYgN)#t`bJ.|trwqfIwP&'3 bO='{hpQ.a0?1n{?=BLkX7Y92{ZM.RGsW۰TL)rRb8y`DRE7 rbFnEm 3drv$TvVxj<HMw0e_iZuj3zr#}oi0KP&S:x.cK,g<'Ps4Za2%@ro*]}?&yJ<t{&P N+m`v<^M߽¥Q<.pLv,vQER]G>>%=K{6(9$ACY{0eHdZb{*yF E *#~|@skmsj'$Z?|bAwN'/.i|n_o`qJrzm@3x=/ՑeuM8&XTZ!2\u'(uMd|vl3W]xhM|a-ATVQUm`/ (Wk`=gGfИPT2z lyfq6@b9>EI`I,G_\e5dQ RbLD`-9FPo~c x`vC0p+هR0QnҗY>zYBd]eG&o9 jX'XR< aJb Z܍s[, m8vC|ȍ!JT;ysp[Ol "b}Y| 99K* -uxDwbpack-a81e489679b7d3418f9ab594bda8ceb37dd4c695.pack000066400000000000000000013620511216214232500364470ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submodules/testrepo/.gitted/objects/packPACK\3xRn0<_hPDFP{i" K@Ru5RPcȻ2x D쇎.O!tTAGrKdBVEqw֩ny@/\4&|7w oLўw|'xN0EuZ&v!1i&ve;@lf1wι@(ZCB3[BV5Bi-D#Bf\NQMGo%s9oޮAq~8=A{u\#|)TbEo(;wB@d)Ca'%qr"Z3905^e\FmkC֜ěcScmY} bxVr6<_v+W/;J{!9d]@r(!&-+_(]_(FO̐lyvvmEZQ})+Z/r6i+-i/VUYl5bͳ<-z]U})9-7X*8wi?{sˡyfV)[fYFyO?Ynײk[cpAytIR54}:tD8owrBjj= K%+SS 94Z=?+y8)T;"8i P8@^ (ȵ2umNJD!څJ;(U&DN,K*4B)>}2a"@uU:8, *I,jׅ<앾 甿%Yԥ8Y7E`][rr|}awM4iB( VB$ VY;9J`p+ ]AG`>|Eޟ0@])X.бHXc34"?C)cA!xmW)K&U-ZӒPliܮ4MSӤ6ɀcgy d;$W\Ⱥ/\AðxR(neT@U˃c[ӟ_N .0< :1=w-$w}[ǡH?MF3=O֨P\9NW;1p*s8:.XcT8PⲧR-} " P<3Dʙ#x<if)~i)py"70!;(,qٌdK̋/>̰\l `\ZFNw?Dܶ??{+-xN0 y X`N;aWpbuN&Uꂆ'EղV‘ḪDMUlQխ41Ql[lpW VV(l++TiS٢j^؝knn0alvRU)\R3} UJi7T ¼LS 6k3`@0|'`>YÀ OO !_Fǀszv9?NXsk37=BM1^3}OTݔJmP/18x1O0w:@#q!CX+cĮ+bNO}%D3-m_׺7W#)P`,βN֩vC+rN1})&xfDIyzj J5 YqOJ({3eWaWфτ!/7l|xVm,3Y8q-d x^C̥SU cӥ3\d,Zob͏6:u7#x DZ0 Ђ&`Yl C!_e.DZ3Lu^e?` k QE"y#I4s3щp +JVY$Ya3j^C!ҝ/xR;o0_qZ$E%0!C.(IHE A{"t@=(;T]W}ӎn;p7 u3(n ۱Уp۱FƗ4?̲<$wq4ҟд|ۺfMJҮ_RY)CMiF8~{x$tx1.1BL>"|)4m,4.XU$X5t*^DI"Bԋ'qŵVk}E9D^[ƪ9FX xyuҟY/I@d4L3 ˳U׶69hc6g&8#mMEhy'i1g 4t]͞t~~Or!+d 8<ޮ7NSжE-2Lk~w,xn )C5fI}ZU0^ӵt߾JV/ 7f)p!VFKijnFʼnM%=-> }M{\U5 uMIt-9>Od9yD;_My ʺ,Y6%ڶM% e_b| 2RپBgoE ́."Xwlpg̥MW4p݈FgV'Ԛb̚RfmJwk^1٨N1.a W/Yv`q,y{60Ȉ!_I?dY(^m@zQSr{u|EJjW9.opH8j#O1`~0#pcp) 쯘IaXݿ&e?.&ضNJ $>of}L_wޘc>Lgx=O0 o NI 1!10!;Z&$G lzvD%aO֡SUZj[dWiu8b${W;RɮL)*mH72!<_d3CFaF}A+;Y5J-ت3Lu%|SJ)(2)e?z K|[:㉒/? lB!r:l)/! DKpVa&Ė 4_A>,pHqZb9\F`~dO7X|;3!{!xdwY#;'=xUn0O}n*aR+*ؓQbGے>U<<^l~7^`7v xEHQ՘D)Ou+5b[o̞Piqak6'zkPtLXP*K{GǸNyɬguh7-fŲO>Odq9]/.kqqM:)#hq_S~eG b|T|\6( xMK1EͯxKE*dt!ےil')L[EtQWsrB) u6ҙZqFJQ 27Ȥd VY+[wW E[ kiT!29Q ޽B\^ͽ#TLer\ qAZ'}@ dVim1ep>B=XJrBCsB&|^ onr6GW@?gWh@&̺\_,L%/+9KD|NsS}_%txƱ 0 0 vvN(I40iʆN `O;وQ 'R%⿄N0tozd2LՊ XsHDP?br圗}q!+/xn0S-) d-zjk"6H߾Kō\R]( gLdQ׺:5MYlqPUuC+,􍑺L)f -j}Qj|Vj}˲j+ [K: ׄ?- x j۵}-|.;ٔо{4gT|2>$0|Q[4=#E!~vozr 1E%L4p@s90Y7;6>}ĦGևӕmBu`2cA,0./YGc(G)?&pi'jxui;Kq,A8AX؏qkH<%qA}M]@i"&*($k:y)q…JCvk J9ZtЙ;e4s=9l.5]Ìy[iga']\+ Jp#uCcv'6׺HqrIX3:qnxaVOC2oj#By Oʹ9>δd9 ߷&~Txαj0^_} K+K!NHW>qg}H?:UJGޑ4gaUK]+[^:eɰ?M&Z᳠yO,CŤ(1 &3 R) $b$ˆ 1_#Vޑ. kyD4 g|zqvj->E,\s'x߾I5.4l=='QC8.ғk5ѳޝ88!urWImq "cKjI6@[ F,cj!\umƢ2|vz4XC<8僆X9uQ[*[0N|r1=_4/S*66 $Kj!oYw'$ʲ=_5n )!ex vtc:ڦMjKY UR*5/=84)*dR!{(!ES c1PX!VwJ@ ?3{₝S>.P ahW=aw]d@VG0cF ] 9MpF簯U~e.ۿZbz+$xQMo0 W[ԉTEwڰkAɔΑ Y?:A{QRzݡ譋k;j!6x-fBI7mMЇغCﱋުԱ]]Ww+ axLy8!OOOP7GXUF'qQy1 CsӇ 'ɰ9,`lŘu#na2p~8z0I|Y>蝵){-$no̷ u'X$2Ҫ os0|sY 74*qy{)+eXyC~cÿ~8'xN0 ),Ciτ<'$M-&S 'k4ɲs'5R뢒lTYTKEXjT:d Tb=YUXJt՚:Ӳ)MfeZUE)pMř==;c }|Xw=dyY(U2Ri_huoT<-2_06nF͍c!Oglڷc0b@xobF11+q6W2]NՅ5,Isunv:|LÉ/}&Aw0&[<9;$+\%rwj13% cO?єlh~8C|v@"ZhvK|cuK"xQKO0W̭j$A*BB >ǻ&qLXz3xպKk MEZm]kQ 3 Y®qNW:ijCU+]*.exn=`׌c/¥TJJQ^Lߢ\֕ Uw0Аz qa^" !gld)-g?,q ai/O#y21cb*۔ !FOLoq^YSJ=aޥDqk=`ZB:_b>^)s:)5ʈa[(:Oq[blR{jj xN!yy۰c[3RhlП L3|LDJJzݪk+=z/^;W\i΅l+봑Zu"qCH=vЊNv^*1˘'a8OS_y PZ^( 8gU݅R(2cgkWFJ5&>DǐCHي40\ SS!ϛݪ3LjKcpXn׌Ǵ-\Kܦy{E~aΏ-xOJ0+>Cē7/*^en`J}ڿw 03F\34 j] ߅m1:qУlGhccBC7j3N+yZ7xI7NpØ׷n\0ͧ~]nAַ^nZ $fUݧO-k, o+ s=0 Fy"mk= ^y/%۷@mv,};Bx@BTcY׹Vod0xQ~<En'aٻBb}jVvM-]˒)?6%_^H!&Ak@8]m\N2C ɫsYJֻh#ҫi:'p8S\P,~]]Ho耼2u].q?ExsidGʁ#t >L>l CLC00O 7:Yt*L%{ar# p2,t\(}~>N4,eđmw;u>ߤc/5q绿}&xJ0WnIOi^)ޅl3 IME|wӮ̉oLGMT Bw)+ Ni+Teʣ !Og²E]rF0:MQDMq<BZJJ1e#&hGk8rD \aB-23VڶryJT(8+CnZ#xn <]&J{쪪H)?ju:#`N>'u88߹#R!ʦEv3X5-mӶmUJvl|[v*ɵ7FBZUTJu>!nGK\vߎ( m/t((u˺m Ιۭ˙> 骦 ¾8y$\3}}gHW1S"ଝJ`qtѳ}t&>-۠⳧WG0<=bl>xarw!9R< #cq$E7,EL9Nɜ8ݻYkW^<ܖx;n0 ݧ^Đl= (ҡ:'D*1K>E+̠XtX !)DdԭX85bdvcPM(4ZhfRƑι .oW8dOԇ_AV+iNH!en <$*j Ǽbuv=< 3A]1ͧĴ1mr#fx ;0 Pl#LMƮg8E8vQ[ґ!q }wo)Dr|V̢"Y}qBJqN̑:E$i󁚸s58_/Pאaw}*ԓxνN0Oqwv u+;-퉀1;:s%o=&J #7BQQbrr"JyS쥏F`G%7:v|*^/%S]jTrKw;?h,i*!ɹ>+%$MZj Up4+%|QeUt&WsTU2b'*yFJ`ʢX.t6utCc|=qw~XDcgMl:,_E(f)|L4v>PzpN%]x<=g^<{ CLZcM1}E:2FBL@mrG۷cA8p 4(VM- k ɀX;"|;-xMk0C.I(gC{-ҋ,vؒG{7-R*Bü>#M 04ȅU-[Q^}N^vm^5@-Qu5K8]N B1$(,Fx|ňrE~}RtM]vU}x9SnMJَeO7EċUՒN}0?@Ո5mxl-T Û,N2Xc ~ &L鈠4eeZ1*j_U_`mEu2 1Qi''#* yWHj/JjBLPS8nΌ gr@ wuV"\Cf_nn r4L&^.Dh\ä}' s,ֻaT)$j'$xQMO0 WfkjB Ҕn$eۿ'0>{~l"m*\$*KDUo⨸Uh<䓪PDT(9rNqb#729%Yx;'f߯$')$N9\I3E}G צ(X#3sZO#8s\pVoABM]6mZ OxN];7m~P&4J DEcgո~lu#U,>xsdAj@@` GAiOCtktkv[T1|5cɞ%5e+o_7DDxSKo0Wzi+vCaW8+ʱ'!Dm=tm tFwQr749#Cߤvq;cUdC5pbbl0 Kv|ʭ֔gΏ):E>rc|KWOGs Z[m">'Xq"xN0E-%8NQ~[Ǝ<†b99!6RRoRsNhM٨ mk(pBJ#ļsi궫Ӷ25MLR{x Z^YbLk-pQf&P&obUEEz>k 'PK;k7*!㺈 xI=ɖqLHyG5a!a,dU驆ϛLe<:C;5=ɹ0CL8Mث_ѹKӿe_Sյ#x=o0 w niQ#[ ҡ: IsBϒ!IߗwIv˗$g"hƶFa ׃wvj"CG`Z;'7i?wMn|H٥|M ukj%ڧzuM;]3iOZ,2|/%Et־.ƍژ^V8'L5N1ȹLJDy G~9ԃX]R&e>Q.!i\| O>T[N0oѳ"نn+U +F+IRV^V,T-xVdY7]HzR,wtVJ Ks{]W=87x0~Q/ݒNT Z@bT96DRIU _bOGSz\#fz(.|U^ytr)*)si&SUTv%˼.4RT!uGrO']-5-fe.2*xI"4u=sƣ [9W@} xѕj.cAoL;Z 7m;vB|r>CI6=ږxVn^G>-M9L 9xeS& vЀuq~l-fb'o5a{L{!XnS8zռ4C [6tm)|鵊KM)DxS͎0)ݐqV Z@"&;v3NKV83OJAZBڵĎij)n%+6W6 [T˶jzѶRr٬Y*QzR)8PnD?z@F8s`H C&7*|ᓋ{vn2RH^%CcإѤG{4tSo0g˜p;n}mOwixN1{?*>P@A HY'>H((ΌjJBsf=3`tRQ% :- 5bQ)k7QS9Oj 1`mrXcq1nהQJLG_ & 6p9*cd$弫\[9O㈰~ЮpP+_+Ra y9`u43X7Vx*I-A c#ly?s+}_xϕ$xk0W#Y2Jc5s,jKA:7?[188}''"X7R4`۾];ܐ1nzgAk'LV^9= TתިvDr%S \x qx1Pn9U9cl珠֬UK%q=3%3'osnnT~s.\ ؘrb_3<B}xL3\K*Kg hSg#&#=~?|{}>=^U4 ,./pN}8GX )Zdroc~0Pq(-^N1N~"pbyIT @na_ܿ5xN0 {&i 88k2%boOa8 Ne}EY vO Coޑ Ov`0eXp@ƞGcG+:#9Rt)-.p-ذ,)6>5[FimO2*"gy{C:ȏmuSKy;x?`⏔+Tl`=qס䜲RKަzʜxνN0O5ݪBe```BbSĎѷ'&XΧszC!䤏s-wA ceØ&DhX: BkfEfs\E)\PS`19JlZ}=C뙞;]4:S.fLwL0Ftνc%6>ֵzE+~;eǑyi#+82ܠhJ蹖u %㡦tWG>(oxN0D|p'o D_"OSߓ* hg^I@Z[vPV [y@:SPZaSAjdgֺiLN2\gJñPi\{;ZBȺF/2<&orħxn9٩V?\|$K xyzi<݂0kyJ}Uv?|ODrxN0EwQ#qU:0!=9nOP`S 3'1uΣT՚FbĂSI'5}ש`Y^ `P൞s迱,5¾b4c4>O4u bKX+8&*+<5'#5+9NNil> 3&45B)1r?BnxN0Fw?Q/Y@boR bG )O9:24x~NrdQcpd{?TFXrn2q$dTQP; )*Av)=Pm ryk7w-*Q%9V kd8j9m'y)o՛</ȝOiwevc__)9fx1O!{~]޲-ɠ=Z=c.+ 6 R%+D'8tr<-{_;䤜s(GA(6wIs*S|k%ÁXVoie&-N<0W y:L9/kҶn~^B _Zp{r:+暨2R My>̾-trx?O0wJZ9v;Be jS.oׁN+zh{>dIq9D4a & m*- I\thAv@r =b*vC<~ښ8B#T%k.8gu;R(]0}&`K^uB}؃% %.q78XW!HBJ0؅^-Z}dʑ`Ts& JbZG.-cO~ d7ѹ~}ax=O0D{EQ@GD٬s%v8{i<ͫK`=g inѱ Y ƴ,V,*X?zizPӎ$Izalwz"}a/XjsŔoeZ0 ZtKJJqK <0nT"m[NpF4sF[gs|j^H8Ö4VwALGBL29qJP@GD/Vrvy{.@Ejl+D`0Ĉ@ё=:z˭\GxdG,47pK/5IuFp+|QN]cxj\-%4'LupazDױ:֨< O%Z m>u/O+c?{N4Y< 4Q3uO\pukgV9ƕ?+}sxN0E{Ŕ Qlg@+QR!1vclOT3έV+FeNi$i [FD/.&S@%bc(YGRcz39cܦ\쫉t=̋ ƥQ="ܵmŚ.V}&S9WJ7tHl }yOGg]5,%o 5%T1~ n8"SMF0Gļ}f (xvӞxMK1sSQt A-[I2mp7)IZx03)Y麣j\VTeFp*Fr :J4]-&bjDդƶUSZwM[W(ܦh;v#CpOY?J;ڏ0)E=]UpKY6% 0wHF VKMSDM)#dw`@;mf\_0X\]/Vwr3>Z!yHyI 3D8m XAVOD4Eihxez-]O=&{nr;So̩z=@Zxj0EY&[!deP1rDmJKNU=Ü)j*,}Ǥ8mTu\`mȬ3sתF7SRN:*rƠ7#R)[7YPtL00V6MP)xi]5B)]FSvYRcyL4cqz{I #PmENݢ5S͈_„y CDKu_N n(xQN0+jfs*"q52N&vdT{$nf&8DB4ꌖ-BE(/xKKʌ94J*VVu5jrVgr^"#왹aRaX紬:opYF":HÓ{k`pk*課UN?td'%;Zf$<6#}Fդ]`>ס`݌uts,N='?+6*N1 Eo8Sh~!.|`|E L[K6Mhd.h•s{:}Ǚ8$ב I {ѽAJuDfx1O0wQ#۱UƄ~\R]ٮO`:c=JZRd'5Ş;OV^bX-Zo!&Vz}vRڸ0 s{\+tPZ@ig:m bVpcf,pʁJIȇtM;gMv?x<~J!ΰ-9BII!^yܥi e'p|nU&x?s0 w~ lrq%$Kv^DԑT\P;C2@ID `T(VZ-xo;{.ag{fL +Dc^4mNZ[eL1ZvM.e ~9~`* <t~+5H߷ptMjJO$ ߒ9HqLgRN]}o4ꉠD($zsU߲p9/lj(aqaY!wnYÖuft"|n5o.A8:!#TzX7lߐ Ty8.ٟG4dg2DuB h6KZtYv͡x 3K]Fkog_я;f̩xN0D{-Ah#ۉ{BھI,6vx{̣v4gLnTo앲ޘN9B(X9J+)8M+lo{J]=*u{2 /}bKC^/ipn\ZnATZip9J 3w9mKHǴf/NUpyXCpU{ q x&Wxn80H~qg%>l]qRx=O1D{QN_%% 9; =vfp'wbĤ4uQ.&hBT賕↝*Ct҄@*{夑|"eu18%}aعtY\GPgZJka;ဧ^nvYaie_`mW$KTʇ,ߵOQgx=O0EwFP;Ƅb?']َON ^sN+D`s-^)4^ֺz'38b@^GD̠xPhuVbd9x {"sy0Bm[ a]9锯ͩ^%cgCͥB۷%V;߷θN6Sͩ4A LT%/7l#s]a7~]ˁ}x^zxϻN0O1=(=vVhDBBۓ"#[,O^S23uWL'i:nڡm;ˍiRXj%Kd!Sʔ2we/K}>Nq0W.-OдF7Pu-.J 39mKćb͡[{cpG2Z\לVB %>V 氕J0F4 ;{~ {-xAo0mnV*CC^=,n^î;C@üy#]sRż퐌:ӅirE13J7jET*WmޖJT뻖2y~9Ⱦcd>N` cSժ<69|ȏyIurHKt&!CUWWje)o2o~0v8ΆH q^D 3\ׇ&$q#tI0e2%' ܼI{i&@*[\Z|/Q~>1[aXvik ! xAO!9j K5FCaK܅ iVͼLq#m26]SVajVfZIEhcN)JЂچ+u׭mZ5]bvʇyӏ K{kʪ e.gMD9:RV _&y_$_ m1xRMo!+F䣍~'QGꡇJR0,_:n&)B001 Vebm6< :QvMdNj("#sh9fYyE+*eYRYgA1J$l &0cz`J/n!MI;,#vP!/Nqסּwvn*Zxd)dz693$lFk38i T‚2@=ONe+{| F4INPL'Qe"Y%`{YCydeA 3Y JjQPǥJ2YGohY{ q])(kT( JgUU ʐ8‹{B\yuFTÊx IZeuYEqQ8la[*rhB1oyrEI+w Crut" y*9"dr#&)6sdt7_HN`|Ўن0r]2sر-"D^Bnw\o Vέ~( ̷&d+a+k>lx~^)/屁7uexN1E{(+ۻ~EQR@GD? ֎l(=+31Ft^ю'1D-O֛x X9w簟'2ZRv4p$9Τ \*<=` syYOrNR.wpTZ+ȧr5C/LmW jthF3D hm;ƾ'")v¦7p$ {T,'eUÔ[s{t<0q3N*"Z9]0?}H.ҋ6l?JH 49Ҧ@m)yD wU'K33Ɲ&,m׎.%$#UR$I^{Fu/ V;N821Ω;Tzs|~*`6x)Ug7YTWm_K~2xJ1}%L2i .Ap' $C&UVqB*@TGd E#Z=(kČrG6(+)`Fѣs; )|eOX[M\~tZ2݁C(7RK)Z +5e)6H2Bߝ`C2Rv #!pld!^>S\xM|mÓxKj0D:E!1KF}*^}8x˦ךz츣N&q(0 dj=N{+ޑխwFbOd[ t *VucHy[ט 3}ɤ2aaz\cBLW`:EOv?lxAN0}N1JF6P`N0.RoO`O6҆X'&3v ˬaV, D"YrJ삱4.] |R9I}kGeɩ_ϯΌΌJJu%&`֜`rȫsJ[kTC!\6_+g8"xCόܽ{TN ]B_I;l[UpPx.c<oex1n0 Ew["([2RE:C4E%Bb) } "& [oN!L=;FԄlF8<+I pqXA ~{. 4 )_9I}yn9sw;Q;7FyIP֜`OrWUyra~ʩxvenU &K6+۫W0 S "0TWLJeR+k,\xdhuH]0U)Lܹ5]t҈1JsjmS= 9}Ntʖwr הQJlP+wDtBR;B^}x9^1 !89z@vejLeґ8S3 SٟcO]6Bva- 3|E՜xN0EQ7Ѥvb'N[1NMJ=)eHsLt]qP'T 5jjW8AjsJjxC%\ *]e&jJ8Gup{z[cM̧#.JYT{(%&O W5Wu@;_Z0TZOa:ys`nKs}"fu))ܬ$47wb(0xNvQü@Ok9! h\O|PӡL%x=O0w Fq @]eGZmmd;H{0Nǣ퉨yosQժFT7d#PռۢżD5]mB 1n5~qLLl/DQ(\<ϙtRUS;fOp7zIYǥyTo֫c/[S1@NEH ҽ!@LGe06q_3xJhHc-U$&1b.e &)DOonj,z\5o3xR;0+F[݉Mg;!@B; DWǎlg./@5IZcBִU%y/Z*ۆi]w=c-y>ԂVMk!贺t-X;ѻ {—lB>%~Rh|)C"sC۾EE0M6g$gmww%!M}:jXScShp6eVyȟHȻ>JpV)d8aǰĭ}7l)AQ[D":cw"|. #֡;cÀsȥf*a;9wsKW`r]d~ſ=Qhguj6;w:3?ncJXf&^."iVyCcZq 1L,c)6ά.MC *V0AqWdg;vqX-Kb jq'C- P\OOڥ-- ?ƻ]Qsَ_OWYww{hqFG{{U{i#>JBN7^ /a9xM0=b%٤IVV|+7V3iT>'8D(Py4]*2+eU"ydvܡ ꢪ¢ODi/E\Ue)$Cc|#|=vǯGI쬉H"MӲx'q̄:IVfyMקAM@(G ܀667"hk@FO=s@.T;IUۅoxB tn[L=K)"I6'upVȓE 4%t04Z4 ,ƳQ@޷aM]:# *8ng]82^[ l?׽n)tE}ݞx悸l鐽[n6= !$6~ 8FhWٜu\8Ky ak 1mڟMɴRH+0bcSk^oa@۵#9 wkK4'1(VE=_5z0xA0sbIWp c{Xmv_ϤJa7yߛ73.Su9+YF;akN`gՄBQםڶBZs(b=){KcYl \gЈJcߩƑPW8!&x 6f9x@.#ɺ޵[ k>U&/Xt`$3^>Z:o |6gʌ'ps0ǰQa+ G.Ngĸ'\v,oulVD9 f vq|'EeqagŇF_M2@އ?xr$u.xf~GZΫVFky`VVjX픪qݨ=q#m1S9GF\sCxzOZWMJse)zyZƎ`h~9א:4r>'02`3:ZV􅎬cDkK4ZLX]҃B'OWE

s :u0%t4bn^&%2y/YSǰ&p#~2p+8 a4mt8 B pYc?7 kxBĊFgH0aM0wkMBt8_}M}Pp68$<]=9xKn!# DQ/|A o9Aٙ!,c z!AaRlt@;k: >⪝ie&%,04'<'D8op9 h>}VEp(ɐ$[IWkì€Csޫlon%x{Bϯڊi5q94;");{ۖ|Hqѻ}'Y<^b%Ǯ}F|9<%_DXAUh+.{'wjtT2xЧ<85g2ӓ84R{[-~TҠ6xPn0 241lٲ( tj hR}r!H=%mT]CSuiIT^P6⌞lYkR`QcuXu(,YUS/\^Y Ѫb¸"_m'+\¸ecԺ\EvO'f1FCN3;Bo&dM汏I'[pB2BtZp!bvuz"_eW;7D >6-x>ݒqX=-w/%ԐxNAN0sGi2MBp/$SZZxb[-U6R VknN]xc9FQ#'sBm%eg]RS]ᕗRl>RKj HdwJuY#ǀwD= \lu6i8~%ĺA:I:t\DoRo{.^E}#o4xKN0D>ED!زk ')Z<:@KE{&"z1xjY  #&d>ftBwNh[63Ԫ,p7O.Jim{9~VJ^W_zJl)G&*hs)R/\%ZJ?'nxOJ1+.;=ED {qAϝtI,2~Vԣ0V2c 4hii肕C kuqKHa˨|b0+k;^pZpZxꈧZT(W5 "iʭ?Czo=< l \ [|m#mc>"1]]\_"Fnђx;n0D{bH &9?K$|L3b^_HQ0%$5t:8+R44Yc 1191YY 3oʍ6x\Oᐨr" PcPJA#"ZzBv"r^Rm_^;Zܷ^ xAi_G!>ʩQ:p·p;F|qux;N1ss#ۃڈNO{۫Gbn/)URonDWi.JiĤyΫF >7jPSJe:NNZ>I>/so4aĒľGҚuUZ)_cZFP9Dg~#| T< ; ^˥Q:OYdxj1Fy/q̌( hI$C+ vfкDkV٠m'RX85|ЃF$#ywFaPZҮNWؕ;ꈧ:7TV^R59sMsf4"pJ$$n,Z8獕Zhb'6*HER/)xyDK"#CmkWoR uxhļReu>A:iji 'DsBsBక ̴cpVR9uq靮!coThjξ6jؐx1N1E{b& zm%3NVam䝈 <}i̐GMt.ǝܘCO6hTظhΑ,by7V{i 6R1;m=*<ɡ6xy < ܵo{ϵlRݜ`sFM:ϓ3 8ani "j eeT \u|JL՜_'.pxn D|*`0z=%A!$_+siv"GhPON 7I 8hF8bg, 8`PsՠiB*4^õs\*='RwӒSrV O|syYbkObB? -^`W!oXc>lbi,)CKlG 2yr|{{pxAN0 E95[4U&iF puf* JR =__Oϭ0qJ. DAzc)&zgؑ©ڠ';AMCj*=5]r7\*nW8n%r~pr<1C8.M z\{iuDq rpcOF J;uŚ?χ2O_dgdCJn4H+նm,)yJV^_xG@$kyWOO3FB}fZVe{lX xAO0  [iBpH'7qڈ6 ؿ'$Kd{Ijݔ\ir UD;ٸVnT[1c-mm+v#5vbV5V) pρ8įCa8ހTJ7|i)?!u) ݇JZ@>#9! G2"ȧ䳙σ_r۞L^peFC08f5=Ƒp—7=f?5./a/rr 0G~VB>`q;γf nVds. !|^syOxAN0~QqB9x^%^KP76&b2/E8v>"'uMj^@3 &kdP@ϼ|S$kclfoQk])H4ͿY'xC(rh9ҡQꥼUIÍ 8Q}L fxNN0ۣȁ  ꍽE`;r=f3iUg{t=`&O2 Mj*b3i}d2Fo/SΥ3/XlpS.H*otOp%5gE%>u-A<Ӓ^av(I-K8O'fxN0E{h#+hBC~7nld;E͙hn+ # cƣAis\!RzR|؂,(e RVs-"H%rح͹]1'p[!]IFI !>S")B_ y- r \v5"\Wl kT2DUNtuUbל[U4)8c;|"| ke;L]&}6]>CqmڶyBq4)TeTu _D1d3io 'n/x!m,w`)A0AC7"$;۴⃕k,Yt2C`m"ЯRW=ɭ+ l'i J1$@aqOȣ t!eBng5;VgGwLͺv{޽f15,_v=hom6 59 3ey~E Q&9- /̆xms~M1zYH׃,(^L͐5f8d2[N~ޑ:x㿿.bkxMN0>Q"fBXqĕ"r{"z{7fI9!j(G*#+5^;D.y 1;IdfgvB ({mJˍ6x+ؾ'Ԙxx??nFxJJ범g-:=JDC 1|7349A.V$[9A3k^4x0~eWMપ[c  dKIӕzi/?S@U*u2֨JJ-Jܨ) RJkĤyu},TܞZ5Xy<5ieV =|c |#>t{H>k)/A+YU}:û\hi]J,eQ!1irCaR0W᪇.8ozF}AVa{x]!Eql{l/~6߃@at!|Sf1J>'L1.9l^7k? aMhMʅ[Ҙz+=~pjFA#1S2CZG0$lVO//lm:&;lhK纽왗M#a[xxal/'Cۆx EqGs k( &xn FAZ-!{eL#RJ]kZɥMLpN03 "|.ϥ, 2(SoM4u-+]!l}% ҁ Fe${^ D]pE3H*Λ=CP CxQ4zI Bo=؃T,K|ryI{Gc{c n4pJzp3z< P9̚/1)2dRSL~&\ۓPN~y~”*)ɒۋ(7£a0#`;VAY_[(Fwڦ*=e҇)CX tu&]Jw-|$~4Kjމjܜx1k0wٖe,i KO[ LI}UP:n}vm6Q12* Ut Z1,?57Jv+a"K:d=j_oq7N(+֔eyeLgxt:bwl">TLEixz  otFu!!jH4V r*M(ij_&5Xuڵ0Pޘb{߾V _ܔ*xQKo0Wve'NAU "hb7.^;NKL[ q`F'qg)E8fh^vVY93 jl+kZ;ݵփN)ç%2~搾cJxB&n@5S6RK)zRh3a}6ݶFix'Ɖ;k!Lu,g3 D|[*ZjXy-Ѭ-遇Lr3Y\N|V/⅄G61!D`2EƥK.+'8#y>R)ģxn}ʺuRYOpHvیOoq g;x_k0).}JXo2єu U-jKFe~Wq `˺=q.U-|]īU"P 1+xʲIRsfJUeʳN0JcVȓ Qs^׌CcyX.iu5ݒHbgM$l4|$͋8㤀qLخÀ6F:N סּKW/"o^Dz[Y~qw\r<[G?!4& ؃d^ (`}ooZ ZI7vTѶ`e(㔛ó<Ns=hPPK`$6F=satB`OF%Mζqsw{ycEiW-9x<;@}eh: :nz@П۞,0`vdجh(4oY@x'_?O댂|aZNjA/V@>Ηxj0Ew}M'ɲJBR@wYzJDcH2%_:]p8f"O}S3J+rbS#C"Kj7p뇻1U%t<[{fjyכ!xPKk1W 8f^PRB-f#[tY4Wvsʡc`{k=R7Vu_uUUg;4Tqc׷u?}aW:K8\NpMG^_9mlw[UL9GJmea[Ve {R >GgD8-/]!38/ ґ`ptK'`{9\dDpv7rD^)d]"džpx(.[=l̰YC \Hja7s&̋|!:?8v{qs~ť#~.}[(xر} W#4xA0scWmB6YVH{=i:v{&m"hOyo7艠h5MSTj2jrU` ]u+ňlYhVʪ+PUWnUb<|!:Kr=Tl*]:>B^e!o ,<˄tàc$ I诪'뛺E6%M[ e]ZtГDM'+r);,xBEWHX(p{ǀuLl~!B䢕\pΔG#yF,#]}rmUW2q2q,4Wڼ\i 2 Fm C٪h XHFZMj8qnGJ__*[%<)/0!)HpwC#HLfH譱޻6`ŒOq,Uw8?fƢx=N1ާeY럍" $8xg#D D4zIf9< #̽W7AOi$vd S'|PGHH!sTsN\aSn+dGM;@aZzkᮗ}/,sk\1QaT֜`'UvuV]:װwƵA#6&hXv* ?nm!BͻĴ1e_'jzxJ1^)f[J"*i2iCw%"}{*^Ws`R"%\]V DK",kɕlBG& UMAPRQbySS-,ZIpG Ggx<ݵ~JIM&nR-o.YƄG9t[k7MG.{)= z)AI G7h1Ao̮}p,#}Ne~&G_٘C4$z-tIb@A .6tbN ɥUj?_cNxJ1}"KE:"uBz$9iM2$)һwYW ODy#wmL 蒣#68әgق8͔{{z88gS6-|D&29TU>hchX'.\^4 ?G89xN1E{hW7RQЀ1`v{@EibδBe3*Zx1e&c##+n>j6QʎL';c..UؖkGZrC0HeJ":"e[L+t]vrH  /n %>v\ȹ4 b;]M{b,xn <(V-OJTjm\}DY |stlJڞ7EU!WR np%h@mVM'JJ:\)pME)TŻRr@%ꮯ%{`/M<9Y/  HcRN(x,q.xa쮼w7H$ bBgp31 H#& 6`_?uh9 p|ܲmzVm$w! v|@u60h)Lv> ϐ7@Z@^pbya =Slh>Ywv%c_ XhOl|hOLᇡP”xN1{?Ŗ E(4 :wQtPQe)f͕lL InhqqzMߣgڴl\ږPЏAz] LʡxO ^2Okj<* J.(HPI)3W8ᣁOJ 鲆7j=h 9,[xR3}_=CX =Դf!oJw>O{xn0DW cC"^Z5_`k*E}ISO=aF/'fyPݯ!CGNHؒA\M;kѴtFk,fhԦ!t0kbo3/fx>=U%CicRlwxs|&Y~>eLsmZC!q7:;t{9 aw@!.~ LEt/_?T|'x=o0 w /tl1%LĒ Y}tεC!Z(>c ݍ5aHjFu*F4$̀(V "H뾕C?r۾Qm#n)>Ow}سPwezu^sPZ'DN{mjѮlJM\m7qrzLfSjzmKWo6Ơ#~k\Ec> xi4gO,u #Um|в]r/G<1 N,,b:\eUJF)p]þ'ba&- ]tԞA]< Y*8A>~}|w*mvzJ>Z>9Ci52|z% ܏yW(]@P;t.1+=b6bjoNL 36(d~JgА DhJcAs0Bp`rw|q"xKn EmltI'y$׍:({t{tkFa ThZ=C}ߓd\+ :F)1Ϩc ?x\@̭N)m ^m1] ot^L[#t3hk d>VxkMvm@r@=X*nBw[R9%d}BhK~Yzx=n0{b.16`{I4 36m%w*Vf{9"ӖITX'&s{zFљN]G2Ȗz#W1hʱ\.ێDy ގey ?§^|.祶a}¡1hK)):Im^hi߬CF)QȫDG)Ä^p+d./;Qy.x͉a7tU2ߧ{m%xOn0  +ܥEDBkɐnNrr320j^[BV]-(O@|-9a|ӆC2;y{. &0VoҎ~Kd7COzp )#Vw %&7:a&JM9 x$g~Y)3!s*`=| 90Z;B.1 ?x'Ҵ' oR||IfB z\4yގMMwxCg]-xMk1slJB14arhWxWZ$mM}봐=ϼJ#Bٮo U^`^+!5EyUy%WZש`h#:6,\LVj-ʵN3va&@6\І#NDϻ[GuU[{ yv?5Vr?5uXe$I;yGpՕxH z}'F"tQĎ3=}/f)n?# g1;In@Г1xNqg,9u9R1alOFZ:ſ 7鮯k5u jx ƻ 0P%%,q,rw%%C8g(2D-^ ]O!3DƗjPVt,Ų$Ԑα}Lj;7Ch.94XyMP0]!M* lI_fiYpz5Wl'QRm͸ upC“(xQn0 )^a!ٕcESa=$:fK$7OQ3 ةP̑D\{iiz%G#صh̰$Jp"b$Ap/u:iVuir(\0ܲ ~ _fOoA4#abxyLeq9S'N5CZ0яC!`7 b=ܤ >d02F/J_vz+;Ȗ`hxuϷaڼ.x*"/ѕs?29.  b5RJv5py3T變6,yN"^7-[,~Z|bm|aA :R.m{qGOfiΟ:SAxPN0+R[IBNA*jmCG߳M8=Ǧ@U)k6屮PdkyHS53(2EJJI&/uAhju-DK}S_0h8oǟy{c^dm#6}d~]Jod @ myU.%?C5LfW@$NJN[P ?Hs)1qf8 e2Xi5fZ0S,#bʐ /N[piM8 0DC+\I~pE롅# aƹ`1e4#%dq~+Up`S$טzL579y~lr9H€^:U]ad܃֢0eYl&oXAɪlz3A.rc{đg?oʞe [VSXءwna2KrsRD XJo4*Vrt*!N@70xqGC\y+J˗dxTM6 WP @{h;%H%赲dHnK{ɭ=Z"CP)A/Θ墫º8ҾlJEyZ@jC yzԷkýt[mKQ:C`B:{2|u>9%5 jt/hPU!G!Wlj:z$n$5Ol-]m5:?$h067asN*Ta&Sj3X%&](ٺ9 `l]譓 zpZ0V $M +hqdWH'Q0bHo @e^0м/K/N됡o'IQ6momL+xæY?lۂF-AfYdIFڑI} P l(8s,p\'/2rEg7IUYq6ӊm?O_z>}y;[|Y+!OV"gn}]{zտ4ّ'xn0 w=Ƕ|AcJldH]$#Uk)u#{LRZjnOTiŊB9д=MݵjR LfQV<5^ !x<4>C9uKIJaRu>7k!e W&\WVteR̹Zg,-q$!~(0sG:2a,+Mg|Xw`9&W@d!DžF=[>Ú[ڑ4fo4n xV'A|9sY\'J"*vOXyc4^م)ALpŊWo;1 :W$NxMo0 dNz]{nq$jI$/Ϳ0d|H;" };IuNKYSӵoĂ\Zd}VR0Mۦk]/{5M>ӄG_0(q)7/׭'C¦*&%T,^ds#4^7B "s`(ar,%Aa0jSεBBf1 >;il0vLƻ(*(<` ^Q욻S%)ÄAg= {l~}ϴ9Fg+3GX#B,99+``gMJ&&2G֣a (ˁK%.C{>T8azx&ʬ Gy@t#J=)/2RP2F"*QW‰ $^܀&i/-0Q*,p4z1U5Y|"F%Om;Ȳ$PgYj-]1^}QpQٞ_sk!1 3^P>B<W F~4e2$\L'2'3:? yo P,xRj0}W yIBF/JKcydJ[I^Β {q8)? 6%o{RG0Eo@'ߞ/x>]cXG)DXHAۣqϐ*7 ~XWEQrJ8 I@)U9:OJ>neFg]Ly2i1Y捫s`|!O+fM);ۛ#]xc 9?`$~őxKj0EZ@>$R:괅ty d'iJG^8\5DjnqI{o'5J95,~T !:G;J͕FÈQ&FkSv|ky~o/ JH8p9 u]"{[nQny7nB-#>3B%R K[jA˷Pluہ*2ߟ&˾y)x=O0wik;q @N ^]KbHq[V,}H*^ !j/%uҊHΪ!&ԅTE6VJ3n[ktC"liΠ(ۈ9_{м9?B"5zxW!rs5e7$nJ_k;y9!ZۂB/7%sI%c7zE *~&5xOo0 N0 n=XX2ei%Cۏrma'۔{Jd-[R~l(JN6m}Ŋ\IC'iA}39HYnUV]k9"ac]um{[U}U ŦD l"lz>*2m/uo!smgk/O`#|53& (1%Xgtκ u@PǸSecn@VD*Lֻ`ٺr#4\F;ދ ݍXbLLZ0hޭރ ~昘Wzi/+,\,TDz(ts ~ NS\b7u@#0z^M2!0:mg W04:< 1r{qL7[`iOxۂ-hB :BD1+6첢z}c Flſ[ n ooICq v/qx[N0E@*;v@ @ Lj#t ވ Dry6S!*F yklT:xBmT&BMg6,ST>Jf(/? bKzmy5jtAz)E[ a-߁ze>8A,o¡2o7kVxn <+[UT^Z5Oo_+z)s~)Br/]+ϛ;K[`q#׆kT׻խ!hiDp-ř2=MqmׯhCE+b6NS(.x὆d y_c:ljWatpЌ%cA^D98CPk1S8}eW|9Ÿ~xn  &AM U~tjN-~۔BX7(Z[^)EcPBfD%mfN6I.u͕QrSNs1gs Q'4"xk t꾮kLX1@ w>Lc\ wa udoPBd _b:\{bŴ26'ٜ>{z{7$駀; 翽xPN0 )lJVIB 9FtɔL ۸ɖ??6"7ޠwnTr]YFk % I+6vgQȓhYWs/[x%,/ӭnsS;cti.'0Jij`FKv1Mx&"gorYxkӂli :G^ ITaR]E'39"QΟ~Bor{ۥ󦐍#xQN n-m1F`Mn0lIZhfw^Z7QOG D $G8եRI6[34MvxԄlQ\--ZN6n;MKhzz4o:;8J* c\v>j5RT%䜡ges`/ZyMtrlЯnUCLAav^&C]EG{,*IC?+vkEfa,YM⾶ [ti8:XH睆GiIpm3O@MCvq;ŦS@+0`S 4`͞70\8xKn W^UUUꪫVLh D@4ۗK".HjiQ(z"=[6L hnG>M!JZ-5퀽B0xi0MyLcTo1 8s6uuп}'XmE0= ^"P{"ʒYeXcy+A'\Kb {w_s04h^p+ˁ"8W)lKo@㉭8k;z,3IK 0vv@dnwj([,xn0E,,Q}Jf V FcwLZU_J {1lj"^닾ֆڮ򪱩;Z"jA9Asmmy M[ݰj-Fkˈ gBȆ!.ӏ9*ڦ,Nŭ( R6P_iƉ rSL`0R "7:{ԷEpd c!N()dq,sww/&ّ]w}sރ%!ܩ _<5$Q%1t 2RFY6 #Fd_R6U 1Wd0TL↙S;8xi0 =H뤔 Ztٖ@bۡdPN8(Rk80KqbU˾1nxv25ih5Ѳi ~;0x+7VV c e#D/gWGySy@@6n.//8#9M'6Og],`Vmn&fWΎlK}3; xJ1$RWn%?nhlҷ7ԫΜAvoТb%(k1^ eI& Z֝Z[mT (M M舜 <,eO鶼23ӎ\=D4hZ~7 fx[>VayyD )go@bft:2rY[Og$'ra{9oe(_ 0c:@QKO RTLiY%x-J2]Ag/˳n, uy[g (9xRj0)Kx7]R 䐦Ba,lueɌ8ۧHBH~gktHGU7]W1Dƨfd {)Q͑A]Sc߶v]K㈫ dE)>vwSp-G]0M6%O~#~10sAz -y˝i ,h |{ [ 2K(We^VF!T93fZѳ>&B]%YJ6MOOJJj)T?e&X&vg)bAz$/ )dY Z7UuW RJ03-٣T%e͉ܹM#fHDbXA6-8G%20X T)T#W1 aɿs WR;vSft)2&ZGLP$e+|)Xv8Yٔ00h%'sIlidjNR %a(whO:sݟ?2WW>h&xQMK0W~P܃G$6n$˲޴+ ¼ 7ޤ@Hd:㭐V\-ڪЂL;ݐ,a3r *.em8KBWe0 " >· -Li)ѿ 9@0c{N*E6I0@%5V1J7?#+^M;nV),Ăw`H`gk 1J@l /}La8Wb5E9 tWcOflOEH;wޘ<pxK0+MwI~qWXcyI^he{"aG"@ LEIe 2*2!KNń<,2%cTVd6bK5U٪\ZCCG-FCp;OG!vwJ2+&c}G9nM m3$  /n= iq%+;u_0{?5 SgL1n&p,֡s0(s~sy:OvvO7_H؜(xMk0@B)"!B S$2F-i]z-͈deYԘB7RV9e%& 0y*)"t}Ty[R~l by*EUdU3>{8E-~>tsY˼+˓BqlBCtS \08:h^FdQ/Go#=!bxj[x;>Dp1`qUhb4 tОB\2a0'9&c?HU7Y޼ymtśw$4&WÖKE90xn30,+wABo7ޘ}&ٙitTc؞Cy~zԵ$2aƬ٘{_ grB#x>Wr--=VȡJ?3ge 3ί8Ϊ(6If ydY&tFyL`xkn0 (IUUVNpT]ZKLDFZq{c4i.Q8V <[1S,`Wa7N$!m ߵe(S0LGA )@H{.OT\s\ a. e'$xx&6aM@qm=)@W=1v`")opK[h5#tnYF)cǣfl*y_oo~ϟxi0Eb2+9H l#yd ֒eBO[@rz7Ƈ(-ii`l`Xܤt mFHy%kXg |(|Km h2Pkm`@bݶܻO@C!նq, Գ*o߯+-~D?l +Yp% %l[G^3^gK_r]+ eT_0=-;X&oy}kOX@.]ne?ey֟xMN0>Q#'/PW݂83jjgBZn9UHMWFz߷xMVTdҚjˌ&oٚNm4Hh#{lJMkk*nɬljQk ¢̲\Y!Aa??y;_`x&q3' ΋j0NWh ȰƟ$WPlt ]`<|zDN GOJ } ր:JS#ȸ1\a9~kWw%#*r>,0d)Qzϴ ]i g8WxN0~DBDuPq@}{BˉS4Z (eNBF }^zme0䇠 [l.7{IR8" eSZO ^9'Z`_ph9CnGRq͵r 6lw8M^I3;dp"[WbYJɬiE]b-+̊UԫjC(^5 R5m,uY- H\rQUS91t1xq֠k7C"'qUl؂T.XM89Q)ff1oIVfct(#eѐV33/mĄ}ɴJaS;ݩFմ;YI4o S;;lu ޹9ׅsMU+Y,:.%^<<5vfw,Aĩ *$V {Z$Np(G\ʊMWf/'"0xZ9$QQMVR51Q P"]͛ZH)Qi iFp[0qHF>m8`kG0:S)AY /9gv3-#<L,v|!亂7Kwz|!qu@y*{̀Ҙ'@p{ٿrq`^}8DrUr^ʑxN0D=PulPp{FqB{BˉS23ZL$D)Ձ`Iq=w0FHLs2RRN /g9+vus9 6oiv7㵧ڥiVrps)Ʃp8k n]aum@#rPk\Nǩ}Jq&_|?ǻup+xQMo0W̱Q U=ٞWc3޵bld"}uڪ=/ODPեԶzJ,ڎ*hʶ)FdvVɲwԊZN.!&\k4mTEOC|]+ޗD.᱀QNus!m ~B|{@0D30' F/6]=j627Y=; ]6pZeN໛?RŜȾ084G*ȼE8s:4&vQ W) @$G8/1.g;naMeP?ZpdoC!ē={7Z>}4k fxP;N0}f=8!Z*{{


 T6YnV-ΰltg_ heԨ:vLNwJ]i|*"MtY#xR0D{}uTv,[0T08KXby$K*]}{W]ݏF^IP}+[]kĂh'rmSK lF2 O3VF c^.b?A4eFR _  ޏ3%a" 2(G*3p48Cb+8.@Ns B=.B%&L+b ^ʙyY&:/KBa}S9!YX zzf-~Ov˽y.g .C W`ϖ#aJd7ѹ͸q WxN0 S46K* CCbRv]U!0 Dޜ=<B:"vHTڢdB$h z}p@!E-F 1u7LndQBt0D"̯Nߵ6@4Lp0m?Kc'@f~`U+ņ"Eu֎qrRkܤ%uJ2ܥ(CEs&*^Jf%v9>}2_Uů"r cfruj .5Tj=S !9_>)/j 2K k9auZz%a_w!Tji#x ua#CwӃ8koӊ_˵#xAk1s/.ٍdEDě&Dԓs7> d[v5fJ֨d#.gV,boZ1JbGV׍k>[-xN0m+uE<_P] tJ/pa97|2F0Oǰ*`euga"m}{3 {H%Sī? i>{{rNӘ/xĿ~q 7w-2خ t@oSΎiR>A:2\ czU 8MK']71uZ0v"55eԙvNx:Aewӳ-|1|X~K*pNt~̈́aC=gCL.zt"{<]hT%xn0 E|l%Xbhv %Cbf' y"g"m:kιƐn`dƵl5oԂ"ö:56VΚ1s[S}]cʰ>x"#=Y֭5V K)~skx&̎,[]| tZ@UՉy>\a8EH0R`U} 1|È? J0#!~ )-`JOfTN3΁G(rRgp&0ᛝ( OEh*baB/jM(k%*|H{QFT֯* ê|u_c5xRK0W̭Y ~)lXtsHDĖ$7Ϳ٥ғm剞JUeخˢQE]VEePgjݮYUɺZ1'dQgQyC^Sdu)p'ag' Y"=^ yQ7Mn nL;·zI \9 ڢle2)h8(O+EDp4Q;ʟF Lw|q\?2qJD )MLBn~ptR3ŠO+ZAg,'I\ G4&=IG&o9 #ʳ6=qA<#/v/09H^L0RG%\>&cap F2^3?>>u {8\#{慂0II!pD6#E*5솗'aҚn}k`- mgrAɧķ ֙%tZ/Oѿ=} ו-xRKn0sֆD vM$' X$e׷HN7Y]>="jҴJ:isZR,\Kd]B贮Ty*յd1E֢)\`^D.q Gy{C h.!.J%|I4M4M=QzmA#F9ӆ 茠I#I^c~# no. Dp5!.+!?jw,op(5gђKD…m HVK-!BXUg_%W:G #/ NYD̚[CbO76!Jϣl;gY[Yk nGP&螸Gۓ1{u̻*&xQ yRdw]3c,muEfW3 j;[ٶlLV9=6c'hN+bP6 bkFi%Lr`m`ne J&rz>e JmQ>J%pqY|)yk'c^o>4:F6p]%N0~a2Cn;S[24=lf{Kl=ʉa`Lqe#4KVnMY_q>n>i&/v'Yݾ.(w,/~]q,TV卵] 'U+aP*Ig?cϸ_%xQj0)=46JB1$t#iYKFY;9P 4MD ;rPQZZj 5 V,gըVaG];k(46y  ~EgR Җ~@U]R]VR L=F cZn[xuNA!{&3|H3r%b&!'40\3[6 35^S8]D,1_)A?]6F)$ھ}6ȼ >G8HޠU.fLbf\DB=o޿\3;hY&mF6AX?7mEڞoxAJ1E9E$ݑAfBaNPI*'ix3^ftB\Շyj8)MlFTx>rF7L5$V* ~ҽj?Z$>8ɽAe8c zmK.pJ0U/՚yUwK9j % %x3Sq ^rIz@'"%x2CTob۳ qsb:~d9'vxN0 y ߡU,]&8'ph*@=p8XvID`)rzq1 ǎܙنBz5 [-9^( zN e % Oۜc)nBʽҦ7q9q]})2{^%886KH} 7U.~^}P͏#/m{|+8W`EG-3m %Z|us)+ Cb120 υЊ~t꜡C%{ŻK!ql??W'8nxj0DI%9z VޕmJ$#)}CSa0<^̠bM0J6hc18{Kwc߳0s0Mn$6G+Hv2( %e8Fʌ:"i¯z0RYxJJ1u3\™1O =۔'hkG"8a78;`$T#sZ| ZGo"e#SBh}d:Qtox 0P) ;sξ).oQE(``j*aVj6l JŃ 51#k:>tŲFs GF5k^C#3K·P^NW,ջ 'tx-0d~?;7wf)fzBF|0 0-1N-|Jt^ES+7̫?nQwkZR8Rt% J}fsCxc'n)xQn0+ )zK n\4{/Vb*IEp+">gggv'*YVy^ԅKjJo,٨FMZJ1'J\k*ҥjʪd!k^6*Gʬ-kc윇U0god=ңuHΫSI";Mad $rxb nZ0TuYTKRUS2>Ӂ0`{GHP55ms _e%ؔ(^ @p}xYK @PHA0ہ\$H~-24G_`=\Ce3E!ެc Dɺ Pkp63$Cmgn;RM X ~d` c&ԛ̊Ɵf .q;+{(i |a9G6rKr&Bp5c\C? *sÓ#]q,CW,+xA0 ͐8dRC)}Ql%1u`;_eвғ|x}STݡFj۽QTS[Bق| bo4j"Jj Ք]^Mk8ћ@s:FKJ%}ueQd٦DN^<|w  r{<;PP@^@s <E &Y?BDs'&B&1m`tܣ,`E!LVO9 Qxzڄ#%~0cllvv200^o"#~ Ȭ35r 8 Wll]<ʯ?E5[rH |=HTz{kza]1Ǔ;#d+dɎLÐouxAO0s(-1a4I/4n{qɃq.%ot kQQQ)y)*jS&{d}Yie\ ZiYY^2Fyg+*dJIXM%!BmD):A1,e30eQ1$h&T{~"v@p% : 8FiXqѪo7iS&,k r0ym% ,'3xV燜=SHo1φk*fxOK1s]w7+EHŃ=IL m$)ooԞg9kC﨣Eإ&YPFʆÆ7 }`#B1e":Н͞BfW#L2y*èG! ^1̰JK1 Wpx: =Lρ("^L?1ҧ uO=j!xϊ0 ~ ˴t'8&qRf d[N&`)3RHOOR`PI[ Zhb$8 zcoFk 68j{ҍM\|!dVc zBӶ;=hw#F*2=~Gp~u.ӛAgh8R;.V|%,RLr g)6Qy; 3qk^sG?~ͮxN0w?m ($NjЊKFUߞӝ>ߥ@wHhP2Z+يZRQ(0KP9)AW ّRPUVE-d# >0&XwDZ#݁.*$\s9x)Q'vA,.3p4epx3X\ow/i~ؼ.5 1{ %zpK@@0@0ZM.-lx # $lۃ>dO߷fz)x1o0w ʒ,dO kp"&H}ω@Љ޻6ں/ˮmvTKMMKUQx0e[ZJ1a$iQ]vuAC_UXԲU?tP#p6Dx:&xNaD?gpl )4 G>A #e˪K \u &BwmX,.[@V\Ps:e /)S_.iXa3ŐIePA)3WqnOns^ 37+*솣`&ੀ\k,x'oif|!a5Z9LL_چN^ٓcke7xRk0_qomiq:~Aeqζ,},)i_NJkI[MT]K]%Rدq}tD1K mSnFQnN6uV6l9>Ӂ0§`T-ҝUP7US] U]UBi2)Q݈{_V0(87woʇᝠoXV{Yfc)\S88QFv+8O c:Z #Ȝ`O\98V:_^v//Yx:/`6t4<`Zl.n&AC"-F8Gv0[m,@0^ R"Q6ɿuF+!^G|i# rqgve3&5R,GNn qȀ.p^-(1~9 S> VϚdI})PZ9Eۙ^_Ç?{h*xxN@ EDkP V hg*OZbX]ˏkp"iֵmeu55|_ ^ J̘(0JVzJVRk)uJ <O^r6H8ePZ7deQ*)L #^A&Ϸ`eLzQBvy~`01,0x<#1xc@絴2"wyc&̑r~x!D/J 11u5HbJV`UbZJ!!/0'߽!9&xQN0#☼VAAA@ &$Hv@{&Yh(V[X)Բ3ʦ6nFcĦj%󶗕X0K Bת3EJT)V51i 1z7Hw~)H jTe ٦D^Gp a7q9;a8\)Y+8 'Nd5B!}5$caX6id;- zwv';wͺa9LO>CBs lH|P8xR=o0+^2Vhٲ"(!CHƉMzvv_Zke0p)k<&Cprb:{٬X|{rLt\bJ}38P9 FJb @.q1F-c < ω ^pgo%ؖdH@iz9.A' (?z' DwJ^?01l]d@J"y,,00 hh מEJ7<D҅z>I+/={8,EdHhC|T"gZ,\(XT⤥\ 3/'W@v`>!/$<=h0KݔR\|ر~r?z|349‰ !fxj Z_Ȯs?Wo2xMk0 "e7݇(MFb迟"z$=FnytBb+Q(YJ) %L#4ѓ ZuQЪ*hQi@by8x Y!\恞@HY5U 7MC㗅^ !؅&?9wt\)Q+m78d!~?*{UXsZ Lv qY)ciL*5%' <` ,_' -cz<ӕu3f?Nޙ3vNڍ뺍<}I&xn <(u^cCObp'ڷ/n6A?G"P}'QԪSuu*Ma FH i4vI{ԈHaڞb)Dx&&N)xCzK[%Qrks<ۜ)ӄT0jlKBE@,`0oĴfҲyѐ;pY=Ã#Mrns$,-fzzGuX]bdq=gP,,25F?Upe~fE> ;5xMN0 9wMBX nLmR%)ܞV8"y%\K\ kdSZ;ʊ+E CC9RCiZ%ԨEz8xqrW ?~ч=T˶)P]Y2٦D hd'<;;$ʇ@*MW;YM@=PV?f): 499`Iq&3ۄj)t D7#BaP܂iYʳcŧF]<2vgGoa_잛xAN0~~ ؎R@nhm6Mh~B}fN3A7*9Xk\G)ktdI 8Nܳj u IZYdz:fx+aWrFz)E4J 8g;s O~ 5zq 'ԁ`).xf!vad&7ohxj0D&(V$˥^JIIRz ky Hr =Yؙ70)AQKTJ庩eBZU %mIkSnVB*FrQ*^lI SKNϰ* YJ-+ 9gƟ6%@)Y/of{=|6`](coecc߀K0 'hGg.C u0L̦H}!_u!Sn8 5xs6stfƻ޾q]qQmǿ~JBxAj1z|`YH!\rN/I3k-YCsOM7T EDS\m1$L"["ŋK_]ǡuV}/vƬ謶&VNe hV)nk2 ]fˠTh%I}*穉LohhxAn Eb.`&H=@+clPU}(HV-1$f*䐘$ Z\q0R`輞ufF4V7)9S oNk[aR g)EK_X#C >jk:s-;Úe܄8pjJ{|nH1`6#xPn  vUUr꩕X쵍b8I[ 0 yQ2IZeXĉIU+n d n8@Ռ{OO8gtjeQ_kиխWLLmWXX^zV{K˲#lFQzNa= arOpm^ui ƴi0+P BD(, уv]^7G210Sq584 F9UA793== l?&YD '+}bI"3 !Kp$9\'m5~6"w^xAj0E:싃cV)@7|y4do)9@oޯE mpD&h 8 GYB"Gq5ҍ)Gc]8H(ru,urY۶Gу֊Z忁ntW%@(ytp ɲטӏ$!4߾7X'f x[j0D:R(%-dErddݷkaވ@ ImLBAR M.ZEQp| wBMzOj@HiV0s6eɽӿة2]oH6Ϲ[]_amV %,1vs!jJC< l1xRM0W̭mդM"8‰jl!NNDPJw9[lup2XU:5v]w;5cZtvߴmwjXuƑ`+ԧQWmζj.</^|3a2^>>]LiXvi$d3Dy1@tJ}|Æן2ys!SJPgb}J W zk s h^6LI{kK_v.\k+uxMd-$7 eY俀K UZ3~NpmY$\{ZZXRʠsY*Χ[oNxAj0E:\a$YUB2r4Eb {mxkad#mB( k@#j;0/V**`';4*t#E:_G+=ڶՂu.Ka8ˏXP9p9v!R{DZug\g8n돜~ǀ8rjsͥrm_\o9=[Lԙ_ ]k&c]o.,fƗx]N0wb/jAq* Ă:q{~ӌޘ91:x%&ȆqcY]q셴'7 e?L6 =3Yѵ[J^pdjq{<6ftA;`@v>qVJo }e{!Zoe/[mwNeMdV_gxm0Db $\\J6lѠ޲fNʹ i1eo#do#k ِ+l<7>r8\@FeT8.SoHеM~>wT#ryܕ:*eG-5tI)b946Qk2).uMDXzb!qԕa}ZjfcxJ0E3Zrj""-ޛ4}amtL͎:9',Iذ1bƥ9)/mƌB1{)h&PE68^y\ vb!H=؞I9n+nOAoo0Kt$hՉAEG@AԸtЋ /(bǐ%58l?yoEѵ_jO"oj[_`zka@bݶ;[xZ kB[.+PIkX9:p>6@}ixAj0z~a%˒Ji_BֻĐXFVhBiUU)Edg"52%(. &V{cDb}S g%sp8_;V;XG0".ܚnc ]. }͘|ZTs7}`xAN0E>\ 8NbUv`SqE1nzXx"K61xbv8bGXb'Pd[d(v$4.[> io m4hyj w:0C E5zVR[Q^(3D *upSjixPn {)QUHZ` (GzmONID5֒ݷ։Hp's N# V\pvD֡Hf8=.#|nD sncR5:6圙8 ~CKp ;Z!UlrI)s"p),!`%ƾ|Ȱ ~uG jDMt[o W5aY:͙`ASw; q l4y9\FFߎ a`x[j0EـeYv-dadݗpNo"ZhI\L8'q&cFu&[$QsbƉ1Ji1VޗxjYq}O.&0 \׵w` O{MS]WhrE~_`q7ᡖ2χ[fxQj0b/ ,.zrjA-U %hf06giY,(%0Ǚhfvjt0 ^ĻhL(a8Gv_k˕ _oy}䩶 0hurd{3Q9vXsk<6=UK^K⡊ AdxKN0E^[;!hiT"RW<$WP!B]S2"Ԉ֘mMVM2:<%gq*Ƞ)jQ{'8I0v5rJ'>vhGxϿE#ԌF U34C)?Tep\n{n_u 1B8a(3LOa!]2,w!0T)]|@jxj0 ~ 7X$N:>@mqIb++}iy;I|@?'"@Tѭ׵5TEWTZ1Q`-* -7.2U[8[ovP7h1S5|&KrP(UWM-l6g t)M (Hr"tS_zB-apS& 3hdF|Ĉ,!3|S:_}p77?$©>t2[VV*wřxKj0:uUJJ 9@ +ܾ01Hz эP)o)Q\|!JmCB킣(ՓAZ^KDњI kmp^ٷ_~Cm$VV9M0En[}’G ~GnXr^Ry9 qK4yoixA 0y~%4tim"1"^ fN30% =SXцɛ@Q\`\3+B #/\#t{ -9 P!X4NJBqNB3 z4Y:LFPqa~l4EAOlșBshKR9W7ZeyƓjry!hƀL;g3[C$e#Bm}]T .4@\E qܟ5Ƿh<A G$ I[4?39SfS&IE)CQ|gӰ7ٞZbE)NQoPٰ%o//gg't m1J` @惽:<{t9xq8:89Ŷ?v{ghRop۫Jpj `z)JY+~&RN60K꟢xR?9xcO?P{;vcuuz7ћՕTѿ%i\ÉjfI`?Rq|; Q|ۍ䮳*c<πjFB0+ͦ:A~2np^UĢ<'Fb'lT\SF ["s%B`HzXŰ :ZӪ005Qf2T1IXĤy[]d TTd6ꁚUޣf ē5IGH(d<zQ͇G,,'jYZjET2NXm4:ݑ'|P1Z-@X3 %kI[!d&&g+ma(&PDc8Lm͚f hpPwڀw )0F˚)(t4 {cHHJλ&)*0NCy+vUR;B]4|Նj]&Dݚ0SErm*u&Kߜۄs#SMYv0k&t6h]fX5/{g=cB+5~shgԣ݆ҥKԕfZF.Kr/~B JwW,__ 0ښŽ r iqH2r&UIXFJP"}- FL^aSQ ̰~&P4hVq2 ̈́fnXe` sк2ggoX!#dQ8( -O[JĖYpe! W5R EiBG !Wy: `orڛٯ-6C\iFGDMڀoכdaiSA;Ipx@0(q҂Y>Av%#%QKU7Hw7t?}0wBw0CGb}N ȳekL5#a/X*IjA\u N sEQyǔaS-MS3[#<ҋMdmFAm}6Ci=[WIH58fL:/(Ft~tKqvD^ l@C8^?U{퀇yMsny>/ [~\(qM/>U/dɫm 6b|?8پD)p$]. h%>Ua֖ sBѰ{A3| K>BH{m fxRQ8(`;,nxo` p6Gw*h_Z&->,oCq|ܨoԣvp]Š4V!< ]D퟊+`ʲ=< @FU%{&WϟZWbsU80 6|*v?<'\ >5OS} ~}ҌƾS5! 0{F8Z'MH;J,nn Y,[n=kZ=d6bCMy֡iHv10RmC'yA;BewEjUd4$|L2 *--FHO$z"8MuK.LLW1y7,h1be7T!]ERa&m<(}`I0k1 F3aAz[Aظs((B!cq8 >Z\;N&Qn> 0"S0S F+ZlXn$&fG*b&S+_>ˮSm- INVk[ =QKKqa .tq@wg.ʆ|yT8Eƿ%>Myufkf]C]j% L*M̖0b^CƠ-0RCt*#{QlD)Qةӽ?W"_XbwĈQDr=w-|YeŎ%GV/9o՟f:`"pZ۰ofd-# L;(ouغ~gގ[Zf0ls(LVIZ(zB-#(vONGJ af:=ǖ?Pm愳+vqXikh`ʰBHndl_!0ԖZF7ѕZ>{k9ъIjU5EK5>sGܜ..YɖzϝT:g6 n:z/ 1‹l0S "O5'\!u &rޟJ?sK:[NLmPT'I(^ß(3q3%Q^,b8v|,0*gbŴ`遟3-41vK]4m^ D8) جF9E%Ԥyr(W/)nWZ|KgH1e45(ŷ^AY),Z)6)_hQ{3!NgNO^ mpx[b#"hlBn ,X : س 옟9֔w o`ueBY߾be[9{F9ɕ+,hIm8rSJɹq Jh՗62?}yZ!fg-cWbp5sF/~]%;aj<Ê. eAn{HtLMe,C+5K |lb|,,+[}d۩qiddDt=:,rB1/;.0mvX8kἿ45d T;1؜,i1L+f43i0As$eWgrcN~j5fاNkY&W‘ W܌BP< .f=L-iz-[VZ֨ ߳@aF-uL=yQ񁨵"tR6:»g9NpG@TxiS+ƭf|iՎdObTiNcf=ɞœ=MNSP|U=ȐϐX; ]K^RԚG(V/p}!w/ :O-׋@~gGf#ydox4ީ'{D\c OC Ø&}rFxwG5AO_#]*]Ou qLV(a[hd{,ˈy2|՜u*°ThBTwn|n\ȤwLc+ z6KUU+26+_fMq+/}:/GG:ǿ_^wt=EO# ;L(+ caE]i^O\5%M25LbejȸR L08 Y$}P'FW/,VĮRX_ 7EB}\ZfB9Pa!Ӱ.yhD]v+4'p< `iz"OqS%x;nOpw*Kj3 $+ 1IRitMޭYgKD|`uU@vx岮~0=#IHM5?o8Cg|j]ko>pӡzR=zzQ_# ]5]^<[F.en(Uʡ dVX+#ɳvZkF#F_K_U7w+vO4u}[)|q!i!0Tf{-'A/L޴EүU}73 ]Jqzts|&Nw D[3?9ܥNfQ%=崮*}ad&'đ6 Y!T䬸kqc9Zu~ K ?"e6,|)9ڱ `sjܷl)͈ 'sQ1 R*cr4!m›Jspx, >wm"Yv_VsJ17Ⱦa=n Wܴbr9?]&Xϕ"SgX$Ra}>RjՔ~ SdZyma6~(+N74H誔@Ɩ}]G-CeU)xW&uޯ3?z5O>,HVN!T mzH&|t+t"&$fx6.; 況nl^R߆AY19ɰ: 4n7yǟ1Pϝ"linqywF;p.d+ŒՕ&΁.*U|hbLXPghM^7J`L:7@|%EBHktgI#ڗ;ux=Q1`)?ht߫-xy+݊)_WzU(WaFuFCƼgA Rl;:?|h7GiCs`@U+-c?K"VHxu-(0fox1Og`4>y|,j'8_;Z1aᏵjT̷`=j\ _-BRcm{| WUPb ^Z}_KWvN8eO8:=̰-%2\_^u#{9,2BlO Ne{hkYsZ|Dx7FD2 Pyd*egazLznT{Ap:{GFxk|x ́Y7 I[2x;A f槥ŗL^&=لMh;MCp~,<ũE@_{gVN40= ՞a"/M9^$_ZQP\eř)Ѓq1ٓ+='3G*b|σX[xNɚi=GKK&O*,i K)N)*YsM# udw˜n=pȩɋC+'DLvce⬝™QkWhdz~IBi^N~rv|ZbfzDʨeT&hhBC5CUWFIOVP RP\YjlXm QX`d 1@{a6, h9"hRQjb6XS1 C1Ϝ SG(:k'r!Ĭ&wYs!h/"ah HH+յB R+oΏ N Z@8d~!pr~H" h0hvA~1$7?x |0D[9%6W]d_/x{> Y836f)ZysK *x{q^ 7ob|q,_xM&  &  E J3&~<?~<\ArA * KPqpl9(QkQ% X[xuVC$&G n>v\| N"xn 'yYJ* R'mgۜМ<J|Z\ũE%9y 3zuRřUim2`ܼ$""bx;n k9.3W*m({K 7#xyûơ #include fo /j \sizeof(hdr), obj)64 4p!R R=T. x;qB 9s'' Jn> n~fYQhr8s3PYz{cͻyxuQx#!!a!$,!"H Z1xɸm5ғwI; pf$zehkZo6$VUY^1WV;x6k_w4XB}|'ɽ䰳U(-NM\)W g1xQqstdio.h>2)typedef struct$P& |9z:Agb3JYsg,0_xmRkAƆZ-T Fx47DHKsbJEfz^A!x7xKОjD^(bI / ,=3lock);/0,cxMXV.o$V%+#%&]if (@%s'*(db->alternates && )V[x[ lX'a|U \g x[6sD ֱxO,LO./)J,KHLJ,1+HOKLMD.*-D0˸~xVn7=_1PZ ipvjwV˚KnInl5ȿ R:MtDg޼y35I?SGvxoO?J-uDZu `݌p:8{C`l-p*kP@f!zX#-zŘ7ڧԉw~0 4\Ye4plZIJLsV;ggfeML] wu0L _)ݷ>Be/zKj@|-B\w\) ~ĸ'gn[fu:E#8!FImsD2Rm":Tv{I"(4B߁-pA0Z;,ӣ9X,+բ[$>T\Jp(-A=4MlLhPj~4PMF/^b![gd\!f2ggq! A{Cc\@E8&4Mw*=uBNlNd6 %\OZދ&BHX76 _Ⱥ{WƄ.. ;ߏm#1cNC#b$H@!WJWlj; tsQ kx_K"{)aA[$0$C&$ݓ]' M#4 #妩in |D|k-f>XQcT봕$>UR D7 rg^< aik_\Z~")4J\//He] V=[渜'(?|jLC1̃7$1H;x+q SKڍ0!1O V(0v,|rxs\/ήs>e+^}ޟX,ϋ3\)< KP x\[s8~^(Įb4ˌJXdK E_7dlL h jniC]NESۼ*u'tj*YVo_f(M^Vԥ?zMl zeo"_}>eEi ?_(C/^$- c6߶fMS4mhX6PJKfY`ⅶK[ɣhJS~h4rҶYWѻ&E@_eTĉ}L `˴aR^f-[tci0mۦ-KeU F.@aT^>U]mތh}>]œYU:n4o^٘of[+hiڷқ*W 'YMSgBhEU|3˶IDRo_(i0;xu7h2;Hο~u~NPgժyMk?Tm1@~0R?5kIO?6xP߿{~֏#b"bm "f*WìZS6zNgR`zRZ++CI7t8=ڲplrm=/fl\ M>|MwЭZqDvx&6א^AʦNmP`$2۴NwVZo)`XWb֤_ 檧$#PTkl8PŖ=M2{ {#:}#QEA>:_ HROđ% lH_$_W1IjOuyq)TbU|!}-0oƮbfәWx!/6&eiČE)V'0Ӕn CWyTTj(nQ5wzJ"mxrMJw"/;;ƜL@c?1/C܈v&XAczeh"^%;(l9MUs`W:.0_F:-w, =Ux=zXX'[Pڐh^"TVh3gSC~N=H_Hx!p":3-sZV:9qͬU8 b=Mn|b lgAo2!Xd,Zwrʟ>W?;`fVw ɼ@_NE?eHK1Aiv/*)Jmyzg=1YFv +*뜶W Ζ}ѼaM -WQ Y,0p>P|1P_ du eRYeIwN걚捍q 7׀y!/##3o:ml:$N6R96,|C\!_B% )yzYJY5S:[Za .>@uax?iQ nFQSH1dj;KQ8eᚬ$ofIN`E N=hfyIw<>.0b:˦IJшF=iKENcɦoG\mJGD'Eq*)肀eZ fDҍmxˌ=BțN (COF ,`@61i mɦcWrXΟYquמ ts{ "URp3\kc^ga)$]ly{`w%JBf8:@zNθ͓%ńJ(?RF@hB.-9:#O[Zp`H05Z, R,>jR}p:9%,ȇ#p%,8zxm>.a_a5EV%7{6gҰk93 x :vA%({,OĈ,!B6%#3M6 &c}?~IEj M'طBۿ:1,ӈRzO=BHq}Ȏ_5ixEQd 2UHNi:4\j BN}]-9ev BPoA.I{ Akv٪MZ$O uIB8Ac$ ÝAr'Țbl d_;\ HlvA(gI#W=v5/gxw {gp +/Q9f> {u[>MAbqe[I8}XRRvi8=英o+/74HrK-=k;,(٪3*Z,(DZ Ps~dFb%#T_VW,1tHX)rdZ[-s#H!fҦq/vηRQVIIN 5WZjLh}K)nč~buǡ 6~a ģG ti&# I4sCCEQ!Œ_*Qvgnd ]CLsXJ9؞: Ds{Wh!+Tk\S4;/2Ұ~F- NTMp }n3A8ߪcg%Q>nבm]\-MQSI4^(bZw Et DP"^mD.P{sAT3`"6#˟^u%A-@:Ly,3BJΊ|z&- \&ƪDŽ@ ]ߪ-IJyJ#ý.6!f/98͢-؆_ҶRK ?q05v!7xS\[ #,Pw~dr.jӋ8_{s`GS:guZq˄P%k; dK;.p7U) oˆZt钨6{ꇬ*2>wrkAvdA#G~ g'CrƄ=Ŕ[@(VAv^] 6Q9VUms`9?=ۨ}ʁQ SJ']Wيt9%U8 آY&yâ o\Am1jz!&8寂$Қ6W{$S2P(:Fh[dpxȯHQ"l#II*}ѕUvewœlE|Em^rʑݯJ:ޒ.(D?i{3-I>q'6mݧ,׽!#@!N. !+K/:(́Q0 \n!߈#3niӰ~DnC}lٜG{c 1QCg0h WΒ.c{4y@j$+TzK 8+hvXW$ۅ| b!K?hihĝ?hݺ?~NL7M gD2?p:$z4FfEs?#z8\=p#0hgDYى_}Mj|7%9a<_<ʯl XHç_pc8 wiO5Ab^}wFfat=㥑{6gNl4<t0#=bؖI3dqrNG{1HfF箾iq' =^>Ic"3tn=xpE,"  ? ?f BKfDFcY WHS$zHljAݑA!k/#^wk~aECϫFOGqJx='|( emOo>1qz c=SB6HX-u}NOIQ\hGQ ɽqo# ǐ[ir4*9 wB`y9 v1#ZT[r u}6ץ3Dd GB;q#d@2skzϝ}Pި/.1܌bOq>%4+9u(4z(iB6]ak8񃹿kLxj,|s_(3H\͊o5s 9) |1YgVz[qĭ8m׉I ';"! LcLpW_q]ŕBnl!)HBt(i"YFm*(Y)[bطohR Y]dEvڹzS_h]+BG)4]ߜuT$F;9}W]_uq_juxX[wH~E#Ş}Y Bu;8}"$$|oun`x#uU}uj9A҄>y`l/G|t1]!$F,/b)Q&֋(@[x<% YrB;+;IM$z4+3`ls}$0M$$$&C$Zeb$CEE$ǐ8HO %bà &ܲ$QnY0O#`abzv A 1Ag|,~$c|o}Ř?`|/M@o#W 2|Xޡn|2WQ~C/K =b m.Z@o!{ =!OionOMsE0JsKLSjq8 pָ\s;|Khif8X' F1]%0"p0 %.>uEjV+3'<_5ǡx@tۿ:Bz{h[{IQ~(8Z^%<\y=D=Ǖgk@FN7s. #.xFS '}P 6Ӫv?Zw<\' M\.*9vZ˲uŢ!XOe^!,, ^Wz%:yߟYdbdz>%Đ6mfsiM(pv J}j*3f}~Me`7B\v0yq,_MX#`~ٻ~y)4iTg%Ǯ[EDvێ z~K``n*eOf.Z" Յq*>ٸ9(VC:B!qʄ*lw=;FM~](QmN#f\Γ W\ՂD%_(  w+Z>rH$JVwYT0SY$y`dX:,b\b8Ծ\'MvKFͦHwJ+xjV؄?F5'扑h<[凖Qn'[>?e6>l#Tu OČZq,ъWɋf #Y'icc#DT[a9rUwD;w<#6bo6'[tq ,*IĚ$+9SZRn=rZ.q,(T>X)7?{z%L\Zf]·fo\SM9g/r\oֿpt6qt!B<=^#.S?N"+utR*2Uw@_#Ƀio8A又PJKSAhN;q\v,bk¸ɯ, W,^d:"X#>֐x/;hd_EyAsQ_e?{ܻg է2@5hYbhk#R5!B*-P#eǸi}rtHr}dܜt8xl>=6d x]1O0w0{׾/UNHvM*H <GBgP=ARLVЁ ??o9lc,o_ ja]_hq7?mJZ[oD6D/ ziԫVj,1edtI@yXԐ6 (f5rn}<ϦKSSu 5X0io|RǂxVn6}b)`j b(v$M./qPҬ,E$@XPi  I̙ӻF\ٷl#b0>6ZEjSҕ%StEL{A;Kk+mk lzz}XQ*w-Tk3|ag.9_E17`WT/Mvpo\w[3\;? r2yh;(y9 izjI *rdt6z]Q)جmZav!ŽBjz+P];cVSU>Y*jgsN`w "IĜ0,04{HMuL# JWcMSPjՆ)~$gU%,,a*+Fr^ڪ^p-oA&6NJ![8OfaY<}t8=K1͖S%̖*mNffԲw[I `v2fhT=x옣΁RձIi%ၸ?Id] BiF|C 8S%\HBf&,PԩX6b7O *T!G;РahN%\j_xnLH"sZ +;p^  ION~Pi0Lu$0 )T23d&#O5KZ!Je' T[;1anIQG 2(lU(1ntb(sLz\f?XTHhzC\)_pey5zL ˥#KJj'lbN@0޳JtC -(O訉9bm=U^AT,k< gVK9)3yתոDPfCof:l\ D^ %C(kѬemɀp0kDI7UQ:ĔwtF/˼sj M΁{RB]o& w sMV6ʴS1Uݎ..׭?9@;׸3冖--0AĤ7t`V:b/-y=ԕrѩ7jpXͲ&/knٳBp%,2d}O4{x ߠOr+.P[:U,xq.CNfRJfDCHWx31lDC篏8q`Q䏹W6i($'e0l~`@S }yv@$'&$9Qjp|/)0e%z O&붾s:-wSԏ_CU`7aƾw>SHjj(:ޒP:W߮Aդ$&T-RuY^W•3.9,3(`>s!C5-_$Y\ua 3 د+ %rυ+PEEE@>m}vs*o yDU0c mx[r&-3'3@n2:n8-|5k|LAWGb1{Qͯg/En|*䨏6:F^JXvփ{Nۮ)`],?=qWbtk_\lN+% Ozu|Fd$g-)򱀿٩9?M9#USQၰݙ)p)*2RR+̘pۼ}jNlE)?T$F ǙUZsϼٗ=s%,sհ͋W|p5S^Hb3gM~T!%\?jN44aizE SN*~喕xƴHBR$.|4Z,S4`OeO6~b !_PpT8t]Oo=Oq\}ח{ڋRRAzKW_V}Vm>Ua(`ەbEyfÑSb3:M]1&!;f02Qx340031Q(H4KfI0=ė6{W0DRڛyY\IfX*2xYmo8l ‹MDm-/Ikpm4@+m*K(I~ϐ؊]%p8|pH=;h͙lYTlQȹ&bVd,*cƣH(%y19+fu6ԌԂ  Na貽=T28RnޡmGn?S-#OyQ)k15\V5,M],xHj Wc&_Abj!"@zl,B3Pl@r҇)Y+ȔcM*`+{yD:sg},ɲE A1<{d y,uQr ؈+, sN< :Wy9; sItxsݓp۹RU;|E$Jz|pnݖ87.{9 .0%sruXHgKѨyƝ4]v-ٌ @R1ZW|!59B%K& -b5BC*`^~d+q+r s2HdU/ϐfZu#|]giRW8( s2 6ˢL#*iZe50lE BX 6S8+";s4<*AB2tSBdB&,?9{"N`Pjwi$ 21Rj9 Ĕ b_ 9=h oDTEi([($2a/4qFI jJeCrrv4c͒/ f 6D{h )$+43d[6eghѧLq M9D JĜM=C1bALaWH_!ȏTfy1@Q-Ӹ"Ir6{& G1 朦;tKֽzSܭ6ceQG||?L\v4]ʇU# ٦*#p?;hA k3cr3M^odg4MS?\\d{U H6xxґeR$,q\oL(PvM ТG@說frRK &m6Zj7^BoY% /o;\7~rXD;p%cN'j#UDc8AY-J!Ųܖk]mVdinQujt,Zp7YW=µY׊=Ȏ~Ex lo:DM3;պzf]C66tQnY2i 6Od\oB_WHU%J:8p?>|]HeK:Ll'#CvSRZRib^pߦt˻RoKw(J*J5 S "ۣSxgMP|yc;6>j$|t&kvxj׮yZigrL"vC ùY<=ܽsǺw~oY? Avj1z0 cqQZXd e{j Is4(vߙG|؋xkN!b1Nt'YձŇvw[ŎE3ܻ^yO&A/'v T'/|ASӾ~QU꽯 "m˖(|6H JAd$>M`2D2u1>dMgMYfě`o |5r 5l-)VYH,jZa=VX醯=Rze+ qzVX#fYa= 0hB(hB(hB(hB(hB(hB(hB(hB(hB(hT`9e~=bVX#fYa=bVX#fYa=bVX)#4!4hBhЄР AB&M 4!4hTr!zĬ1+G zĬ1+G zĬSF8jBhԄШ QB&FM5!4jBhT˩uGguΫnj?m]NeJ2N!U_:l~iQ;ԜOQ!(0ԥKJfwJGQ Y@L̖GcG`$Ao ̞Q?>\hA{#XO2HHwk{4~* o e-XhC1[Idv>܁bnӅ870tcRaRR--ib-I}467#OV]IδvZȞFzՓ9mW.famq=,2^mh׏v˞i̗4eG]7}C1aߌbs+I8}x޺rqV|ux6 s`;/xy N]c, xd.-y\~ëBV\}ko"τ/2:k.6%lptw/^ON6^z.k(0n&-¯o;,lE3 ,xmRj0<_KLKNPCOMi!{2ҺSE̠0!O`M# L-TN rcs,S)TDU+$arC94*`h[LM^MQYVKz^  -y#;ћָّKUUXPp4MQElBu'2 bGufrVUHˣ8VZdq԰p?dr,0]<./gJj2qWIA8 3NuI( tWqa^qPHJP-~@~aE'Sp.|Nž;QOBxuSێ0}&_1*WB򲭪J]ڇJ8ĭcGpمl[H|fጧ|`m-Tl`PR(VPjJ_9ytA0#m+8J[dHTzGIy u44 e c+Q:א|X*Q)zMYJs, E#- j~*u]#\uK$=X]3!UU7NCcZ*ZY[1mUq"d FC5A5Fc)Ii"=lr?s N ڄ6lpHa$' lF``yiR{J zQ1N۽H 6#Lp+@ ?J B=μx_`Xԉp {1ٚҴ {gAYH8"AБ {Wn,Ҍ}8tGVK*D'r9vbq7'vmp|;JIP=x[űcCgHFif^Q| ML gxTOA_1pAԴZ$fMv=;<@ i? 3L̛~ }'֦p-pD(@4iQKAjRE2z͸a9M+U(.$nKY!"T5?RJ L$J[#Is16bc*cQ:aϘ{{h6G 'bƉg2EM"O?+{"~Eih}Ijhcf`ʍ0jK,4\c$vƶK5Ey#+}:Vv Bm7$J#9F3[Ìpk WRI;tlܒat^a%TfjT_<ęT݄D$e[EQΝVh|VO"nqa2;Eh5pNw0p8]d-^H$U M씮*a4+ _ȲC#7!v S,I(W}Ӏt<~䳏 G@sNBp=ϧ&">%x "4]f(Iƿg\e ?CVrD|4ZĈG \f gqԵrSx9D898nw CH#3)+O#FN8?AE 皬t&C%D #'Mt3T;.}8JO45Sή>iaBT)26olk+mYjRFK0{Dyhp#N9z{drlxqǣ1xr/磋!b2C"R"B+XAL 1E.g¦ `ŏDh UH@*y㰾_}@Of><$>Ycܤ}t[(\d8 g3\8(h~./Hv?K|Qh3-anpk7n]ScРPӓs>>9t.ݚ"ׁ`oH&g:æ}]{]'h³^RNc7{>w%'(#FMd8hq 7ˡH'ej)0IG,^wntT޵^v-!8cQ>ٜ'(BgԽau~zb@zȾg!IXLBTA% 7u!QT0BI`mP.?}"H/3gG#T ߧ·9kGACFE]9e,LJ[]?STC> sC(@a,R   =ƉeR EgйvS 8q{+K(.c" 鉱` xn0~:|M!mUdF0U42EsGQ/PM(HBk:C΅1LBd8?I<=LyHC: "eZTPZPFbwwbR"вE$cP GK$}Zs ]#`nA\f2V'Ű37,5M[Qq-g!x2qk4Z0M.ۇ} eXE`T8>|czÓ`38*_KyX͋J:k݈}.i'âzn/"e.}C ]հNs[1xT4~C" Fr'#0B1KN"8ծ-ѰLܮD ZmQ(`%N'd =eLE3d ڝ,OGE>}%qh0;1gb^.0G'DEuL<}x%|I%b勲jaU*ZǗ{e-bma (|bK>ck'NVrmm_iPy'&1okK9]N>B&Jȑ>4FruyMKJ^9g=60ΘuCok)dXF~J-S4(Nd g YAICVZ«ч<: PEYՐ*Al@M"2,((3+ _8fk"s.rsP-/$ &FqC*kAx:`ee+Lq#Ѭңbn"vj2SI&Lqh̸WYW2PHYXW5BjA ( yZ3-%vnpWZų5 AZIecsӘk2-\ ZDSax00T* fBz6C|] R:6ZAW٘vLȶ8a|H)#PZ/oѫMSlM"HIӏ|,uVL~J%+\C+' e^˜9X"Ij/x3kePu!NW:RhZ*0XEte*X}Am݁ve:WO!haVؙ0$E=q FqS"(*/P8GZ 8Ǻɫ*ҔTAiR Y2/JPR{_ki1sGWiy:PbKneH7CqHɐWU1zIuS?7ˢd3jQ;9tԡ^%oG1%݀ns  B;L;=:w+|2J%+"h]>SA_`g,xM&-@ -ŊDc Q0Uo\XLl?vw*VV;W5MW۵Qcg{(@Iu7d6k_slw*GgRSQ2munl{Q}goKuirì5ظ[U 7A4:s>%Vek{Rl 褰+…>Y X4laE2ِдxUQo0~Q` aL+jg+M.YjG31lM!^wwE9z)bf[\D\E=pY^mj*xZ~ QSM1bKH"ѹ~\" =-޼Dh˜O`%O%Ix ONm-b>#^FQ tJG>ķ2W ‹_ qG-C3K/bV;a+$7{ aipJ) 憔cl(PY$ZlnsFj- VoLf'p:ŖP))hz++͉*,& wT1:2Sr`?։)C $Wh Hb*,%.VF]]\<۟V#agG; ixcL޸Tc3-1['f2pSA1uw<R`уȺzd@O̺yfNƴyR ػFi.wmG%̌!e>[> +4߱Hy%Pd_{S'ȡߜOy$U_ vpb+OBorI/29 ixUn@}WLH iT(`5ekXŬ-"~}gwmc/:s9gOD_cl\C&wz  dI $ s8Ipݺx7n?@C| p|C8bt8&b<"J71%W=*XmOa3zE* uE0wcܦ:_}j<̓y8mq[d+2RBSYJ+ƤS>TpX|]Q-XPL֣-; "ζҦ+)rH%/A>g#2gAU2~@h#K%;Dw<Kjᢺޯj!"&I3p+ԥ &x.(R1AъEmGxiW^p^;V%sؙ7ybǕ>LMd4;I!D}[pb2Ӄ;H(%}T-HSA{ aX*Z3ZaP'9Цn]VRYlN2o'se6]2Zw T -6%FHft跁Za4ҙcL=>musFht1"]B(6߇1mE}Mdҳhڞ,4ey -JU8 FV!{ pIJ4SvMAb[/[$%n:JmDy'Ҥ^BȪ"E3 MMXR-q^+1*]@%i>BL |) a5<&D6|釻?,ľ%wE< Cz*<עs("q9qς@u wmQĨgb.fBˣO/WG/CaA(Bxy m+ll5eqk/zAp0VC Y&Cܢ-e3.XlY{ނ ]}bG++ P3qq{ %9vK[}ʹ)|(c4=Aj} )KHp5λwqUͼod?4)_cpa)[-=[) Bڄlв3xuRN1>gbhW<@())gk'.{e#waqgϞ; Y_=^+C=aOjT3eYm-\ C<Qt8RvAy!5`XA]+#0Xf/Yjތ<`${d2IH\*6 9IU0fC}`rt~7O.#\s>:0XNLi\D)L:3UQw'*́%Ï>/sx7qZoPrl_=e?~Z7 8;-cXL/${?gZ =3E/,5~ߚY)/֗LTb1Γm^r/WӕmM3'omB.xuQK0_qY_N";0 e"a4 lH3uݛ&q6J$ddSʄ5$BQH~HreZC+:.rB"5riF dj>Mwa(u<|R%dPK\[B~Bní7fS5wy,}NBD'.tQL\J`g/õS n&gsDKWٲ۾C _n˕je/b7iHB:,Z`ܑ}pC=;AB2E"B<&{@x}SM0='b Rn{haH,{h L7qޱ)BU/y̛I,#vͦv71׵>Nb9[@6dp90q8QזULY E^2KZ5Ӊ&+ao,h!>-h![k[XtBئ琻q@\ *l`7;bf/)&GT^oe={s^km9y߈~2a,&iGZosPEw0Jg~DgrDg Ӎ'h.vjG#f_Q$xM @ͯXq) A cl迷~@]<ϬO+D>h6qbO\6BSޛ[F EG&EqiIs+YyɒcrU<`1D`av ?me&5穡OIQߪ(ݚ_lȊ*xy?jJxtid^F]ҷxVao6l[v6NCtp;؁, A%*&"I%Qe;J;`DݻwGZpފ+y€J@X? `-  $Ғ/ f,:RxMAp"&Ah&S"6\ b&NAqZ-KsEq{(^ 3v%<4鈄gw#iEN伡3CsZ`V :KȥA̳Boq`{, ~ ː6xvV6]xh"lT u} izՃ, u,xOXv>}xbf?BWfesӎ7h},4qگyuw{$I4XkNOaL00L23G;s/JI1-#?mCwNQ9:50Ȧk95;NWIomUGZiVZ+"C᷌a 7dRɂhet}Ӡ q;9Q!_ZwT>K8\)R29u>99+WwOX;*Qov>{m.( ŽzGLhssz8<{;)7r,I.> 2,CYeL~xwMD\kdtڰwR#ϦҐV9T3yXn9ls-UA ׃7ULJ4>MlS)L)R'̨] NQoIY:f6ud)Y"4"$1ʘS{d/)hO쮻 Ӣ꾡m|:)LJ!?͟`-[N}켿F ڣOݷ:&D&퉲կ5ҫ$m3 ̶J=iXP5[1'7{[@6W_: "x}AK1ͯ]`OEE **"aM&i7 ([M {K4DӫsH♏&9dnГDXfݺp2. O"@'-{p}4foK~LMȣdJ&g|T|IL%NaMP:qΣ dKr]c-)?.ӤzGAʁII/;wx[2eBUgH|cGcD5gqfUj|BAbIF|Nj^zI5gzfI|ZfNOζx &거xW[o6~dIyɐ^k,s'Pt KTF Qn֮;d;]i/Hw<|qIxJwOO^R5nYPeŪЕR Qu$HV=Z%D5SЩ".ßg[ڔc~BCY쫫?.eTRܫ2}q9xKӳY;C 1\n@ tQFp c=mK (n?TxQ39Uɉ7 hv^>R{UVl$}5JJӫۼT;b____n7ʬYƏLWzVm9c__9U bU+~ LqI}>h]f_/uE vx CQe粀[*zBgL ?H"eYy _<{&P*x̰"4UD=zsʘ֗+MLz0'hP |c0\EybG@f\\|:>*-PvLK) #;`8)[ $"nh -JB"$LNQ59x UOБ^S/-*0iX)EYq!l1k A)h%I{8J>Z&MV2[۬S6=Ⅳ\-.oB_򷳫b k%-}[E uMaGCG4$ãx&T0ؾN$aeu}k3u%W0ظҪ4;֙lj)&GD+ҝL ,Zlasw]P;nj;1JU o213u0)MkQ[jlŠuʷX;2pP/QTA %u1|[xqx74 CuE PRQKLQw6WQy m{-J&YTSc%?ot?Z=![N{l*fPwӏ-}Q$g ^U?\0-||8<5-NH`~fLbF>3c=Nrx шƵA{۝y×#WE%m{i^̆;yzrwGxkT-=$-?~?*N o;xWKs6>bLGj#wx29q  L{w"e}|^]O#B)*3ܮm2VP@5\3+4HM wk(ɵpvX-r[@H˵d4L[P{e@B%,Woo- eYtBo(-8U]+9۽լ_B.~.si5E>,?f~\,WIr i~xHRxQ$F]czvIфk-zM4p<=6=;0K)0@SzM^IHJDuœV>G >=+fdNAYst!OJXbZ_,n\# dI$Ǻ3̈ӎKh1b&}ʜ?jJr<m[񞛘= *kXQ55{W181[5 xuA3Y/ =GsUmkEa!EC-sYX\~C"imPR&Nboܭ>{YJ$X`bj>A= 2XN7iS`4a[ܗ*}Ǐd[o:;㕛;o5PZqq^X(/h Ԝ|Rn"JYiGj,bSl?vM|rAU'jř sلaT.B.z0 EcCU ;me(%-?XdsKxycrvr6ΆAԛxrS_vY6UGk!XpN03Jk61D^/xi)n%iJl86 ;d؊3݌q2x@ܾ󙜲j%9g-ڙ[qOQZ5BM xVnF=G_1pUF{!.Z^@&U@+k+pIB%%SNR 5ݙypf/WTMmRVUO*c"k[Wzڔ95V.ɚʔ[Y26֎Y2[ijښ\uUN<&񏂟0Ϻ|d)svmU+p*396:Zo, *M35m;Z槠1"[U{jL ^QG57YUeva*2ةh֪iaʷN\ڜm @ig't?OuM )uw&.AEFmSYJqU!UXmM9hq(PZcʚuq(7St[WqmYȘ:"AxG᝜ ]=`S"9I&MDL$W$ڙ@<qLaDv>$R#6?[Ld0|P&42$ZaxM"o]əL\k!={Q"̋ha,ܧ3Oފĝo>8|CJw5m8H._|37 _ksؤwMELOa!O"ċ8"4 ÉS>ѝE|qMX'\xxp%?_-b$A"h1Od#P6 zlF`=byjp@@?DTR 39/x7dG2mdgdC䅣yW#]|r'wUˮM8.z]jݕX>z r{T?چy Zaպ5Zx`p1t_ǵ.8oҀ ]]ZY4őki]s: }®a޿82Y^ j|LC#FKocvPwUFE[\r> G\#y%b=/7x k<0]ǒ ~Eh?+/1#G._x.K;cS Aҭ{w}0>نC]{:/͠.2| 5&N+2i@ĤMQIZ 3{*{˗,3 `!x#1g]LZ#v>4gW99yJ fUMFmLYnb?>Vv_1#o;ɐ1xR۶RXS^ؐ^eձI̓6-Cz w+pt~BwЧ]M)O<ʳYw!VzI^NJ{Lߩuem (Rz}=j3U5CZkUکf^K8& 3"b3xAkA)Ҍ=I)Z5$K ( %LvfGwg쬥˜ x#3x֓wOΛ]lED{y3'6,, U)Iv5!ôvºA X#aҏ (0scs$^DnoP{3K1rQ.kA ߾u8܃Ez#e)]0"%ʥGkQʽ _wp*hY$.yWdݩNU 4ƨQF6{$THӡ#Pī|:5\AH:W񕸙;q)pkNF'Pۼ&M/T}e5TE5~m\@К݁TŸIGmWrZ+Cۗl1I u~V%ڗzhX ޶/LV+̜,'5-"UKd&}L4{s+e 2d ޟG' >&wI@ cdh6dJLd8L~>F~&N r ٵK~'#:]J@N"-#Y>j DEUlwM~8H[T\>=9j6y, cU±E>]|wU'{霪 S$oFRX[s3cvgcFpc2N/I Wx%VpAz}--T̴b4̼ĜʂT-}.Դ̼TwϐxW'W 0/(?HAWT  % )% EE%@i,&;o6y{ <9(xuQAj0K| MK$`JBoBxA^Y-$nҋvvfwF!Tvzf쌆 XXZ I!R)JTmh~LzsHHX(XŠ5o|nA J"A++A[+ORtca^˿?6=e]lshHMjBaWEQ쏱fEv#$ԣu- u:b{Vi#Á(q:4?(I w ؏ )hSCm2֟NIsӸp[TKe(oɑ|iG]t3P6\>mnqs-/axkf}2!xb:`̼ьqW0xUMO1WОVRCjocf]3ͮ &;yc:3 3Mo'sMy>t >sk#WB8(jņ`Ѓfz@'aGi~D+ym B]V+5l^DkIZB/z._&WlW,ۀҡGj0Q&"g6b)U2$0#cd/N9 :.~"O'SؗX1+2$nuRpD7(;eb(oP$߆f7),9Z)06AT[ɏɷQ'8EVVIk| ktj 1<kɲpkl8Z17KPT>&BZQ c%c M5D"˚x3'>wLSO"ʅC|MdiRq7?O]'u{\(9[D~mm߾__I[k_OZykҴ־SW<_:fBn]f#в?0B_!(ηK+9Դ`kCi 3^;k+f#vyb{GUf+C Zwq񇐮%YfcQMH?e-bDfg7}g;o0BFC^tw <;}4Jg?͜BxX]oF|^lk_rw PHA&ZOˆYPl%;Y,S 7WgtEnSVuETkHeK$"]PeeBҔʡ]ȔGim2ԩdRFk]*Miuz%kQEOl"5EWYZߴ}8 "JM۪FBDlW.3ll0N JiERUyc.m>&}DLcf&ݮUQˮj7$7%eJ-j|cĖb{2 pQȵykg ;$ϬB;$cw4b dȨ` h!UdX[5ppѠۆ,nݪJM#"ۭhz%w~Lq8JHQ! RN#|]8(&72 $$ڹ|Hi$ˆć=8 E0lc`0'ؙupD"G-'!cDX8=طA"h6M0DPÁ 6mFlpN`=bz-k.@/W@'X!zcqϏy8pyf!ю.# ~9v?" zwmpܜ"S˶UIs-=^B"ͷs^N! 8puoUn~sE]Z1O*)\HF㏘* =aaӡ?Z6bY| ~0 ob## [AksuͰzQµ◳wl`*YnJu-`ʝB; ]ɒ6ܞ5`7mUJ骁xQ>#,u.mE m13|/Tt׌'V`{iһ\+vnf;rocct饥O glݝ9&活:gެab[ Rctmsپ'$ReC͏O2UyxY1Ȋ'd{+B#d)`1mÜjTKP4/7Mo5s5=2_6Ľ\˟UqRdu+J5Ë5o!\Mxrr.y4vhS0Iܘv pnbSck8| aK,sH=1;Q;Zܢs@y=.7Z?2 ${<ɥTu߷vD]&ܖYک;GJk t| ܿ>pCp' W>Ltv"0a{gxDC,Db-8n\J>n =[ҏ.↥+t@8'lu\W!SŎ޶mxȼW& +q8Ay|) `'Q8xTq }ջ̭(njcec6ۜȌK7m)+mE>WOQ7J>`}o>~Z͘[uZO;{ D>[tJߎTtq2=d|g@Wq[qmuͥ ۝O-%:Wz|=Y435&υ+Izq]]v{  spkT -#h-4FY~~p?n"L3r((p>q1! YAӽY&g$emFD@eBƔ'QLaғ -qeq$ `đ>eB+d#h4Kt2 2͑{C O6掹9ɠcfY/ЋUH=}?Te"V]`'""p6 P}>䂉\~."!eا zV2ՂIRJ[5k)ǹ^gxjkG5ar Q;L\ be85 HXݹ zW!D>#Zk C"@X 1 (u6K %;̔l=9sE#-Qz61ٛǥځ򊬬%B;oNV71Qf.ANĿ"Q UBy$V؂ՠׯCxCV!#DyB9}çGf9͍RJ,,+tU-< l{~bU3o1ں(8&qL2QaҴYPv,9Wq}_mG۾ݠD bq&lSl6e]O+8psG^J<[l/Ot6ܥ7 83w:zvE|3,\;ŢY'oҊsc|9;<:0˷/*CE2$Jy\{mvQx uοձxXAS>/B5sx }ILpUY%2X~ nI`gvOK Vw/6a^U1-֦eZB)lYg ֵɚӹ+~cқv^Y3IUgF9'SƵ`i(XՋ,`?=U^eD*rUZ+r@{!ÁLЧ:K:blYuel.A1+.7B_|G HjE8;DwPyCԾ(hFhɫv˼SbfeG< ⴣAy! Q lZ78cw4CH"t {w98<bNr4&w,3?LM_V؇lz ?a!Al$$ UE- f~rIˈqV?Գ%|JKa~ {08 =tGu|E%>l4zLZu^u(ƟS tx6KC'_&~-e%.gZ#U"K:h"tP; X Z9Z~Ax/qϖ' `]ʧNҋw 4o ^QiQ4#7F?_n@Vhv4 涮:wj6pU(K<=~EG4 ;/\u?I*Plv%jf.\؅Oq^,v$ո4U?lRp#Aaժ>ChehN4&CC07>=y2tB4]"eoQ&LѠ^sFx9f}9 rqnDŽη_3lj1,pk%p*z1VI~)Dc[w'%VpYr~J{R"bZ.k)-FsZjɤ9a`̩rg)nQbo=?8Va XV!̧'? D+btBUɔ!69հk-5(S8x չj? V]{Vw:.C99݁Ubfk^?fۗ}i^DCRf$p`vO2 u՛emU|^CJ"sW(J&B-s\RpCokPɑ^IߠM 6e~)05}܋۰.1Q6q0b*i{cWOHzBlؒ$F !f*/ҋba^gv!|[ѱTFo8XlKM׮#=9:Xz&2nrJu-*vfWgT5Yygd_Yԅ,Oh]x7Y[59?77?O/CK93/94%UA)?% U`6iF;fm f|?T.??GAKS!= >1''?YȎUJI-P&(J-N-KL.W(QPZ,"u@Ńܔ9 Œ̔T B8%/iE(LW`A3xuj@q`hBĩ{Lri(v*' } y{tvU6f53}ϠU`sϕ(iPT0gbR AkEjA'ӱF ^ fQS3 0q]L` OHTAWLf7KX+pWgњ) //ڸ*FMGw(Wq}N6^qn\ aD۵t( _s"8 rW0I4*ܛ\Wvhx7?v./.x ^rh\UK7\76}5ĵ*|UtȵqwD3zf~6=: ?qf}xdJ>]\N3I9tkuf /$Ijl sҮx"RkqVi2Z8:usu>r7,N& Wʝ t{'PJCC3yu~/aYNxT]0|WzMuAmr$ J'Y,`ű4W~|m(䎗ٱɈ<mg)&)S"&;0Pa%pr*ľ 嗚r9k۟PMҺ.ɑh9M'B}s7ʹƌ4#2- NhNTk8m:Tz uN[z MA-E{B*  ww'MaCFvE[߲i86^+[{Iw}xD_>QK"u]"~`[cr̘2xkY]Dnd E:y>p27ryVF懽[Gk^[8w \r )JDh?LQat!bdU&kc;i6e xXX,\adq/P'9Wf+dmQM 9Q!O|.\<5OwqY5˄G<Ґeߜ{͉78ZK7_+NW]i97WnV Ehuf[X3N+Yx9(֗OM azxTmoH|QrD* $@-rUxU{]'!m{g@h/Bg^yfN[p \Zdܓ0x []C"LuFƵ#7Bg@Sm9j#84p SThDu\f2Ae h λCXB ׳MI#H 4l=r\ R.v66}۵*d)SR}Dr}#+lI4 TFo(mӹJ9TuoiO Oǥ+M8Q@ QUŖk g/!(Go[JNs r]ߡ9~}QγI3U]dgLj'bJ}%+ݏ93'IĞ.@S8_`>b1 WnPdgr[wG G,X=1 Vx|C.Vz6\zq?_%^)xfKM*O YؽH+R`$ԓUmgB@*vz3)d<.<j5}Ÿz3M=%Z󑶎}?  ..Cn:] fG颗BQEz!iHPug$D}{Uuvꉽ=wmJƼ+_nC Q-2T`hG=8b]@O>Z|-`0l0YKnP 䈌~7XE g0du4-ɸ-&3`]ލ3NC~X!CZC}B(F!D>SHCCVy @Us3^NoGkLytYrR(yog'Qkt+ b!W4 w|wօ=u_yY.n) <Л큏sz=Zxӯzӛ UX:ݭ:mZ[%챿 %N~[o"ӧzu,~7CYin7UxԅBwT!873a Pvv)V-^<80f.LF]I3˦ʼ,3X XRWjp2]\M&P肯'|"eZl:+p>@K_K}Ǥ{2.qϳ02hwj|1mO;N ޹uĂ/\/6>ƖH z&t"F{`^ Xi׸}{ᭀEX tGh!Nb rL{y5j<7H PFg.fxCxXC;HZWn(=jz,&Bns8HIcPz`Aj&{f- qV䖓a΋ot!شKS/dx>~hRW}Kx#vqJ8LٕK%=bʻ{ʜ $׸oR;;{y}Dw_{߭7߭Eϩ,BnZ^ׯHxR«;y`7Sx$M+xU]E&j9ٺvVA$Ct!f6m%,+D7GH(3MA ??GdDf^&Ys&7rHˁ%EEũ%`\\\e)qByá"-Nz2 w(VkWXTqI5= %@!S+2Kրj*( l t+ןSM”3=!^(怙0K"K_qnS°KC`}: P#>mGf,xSSpX  !B0!œ``I?~,+csÂd N~k,怼T&|0S>Uv>*'s".OJLΆ$ԜT.$9CKNTK(AN8z Đk0#  Ѧ1)𬀴 "5Yf2莄Pg Ȧ -QPCDqyFfN4q:u% y$1guseJ4vusw^pe̠@ԧiFuq/ZsN )Uu$xN ;O1^4Q=oI4ttS|)@㰌Qv4Kont54RjA`h /ø#O0~ =AqWfg2nbz *W)纇D-,X K_rS*m-9,xyJ}+)gdźq _=et.*YV\m LOOMwOw>,3sΊl^ކ9ﱻlfarE7Jѳ,g,w6isV.9+y*X6WOy&&gMD"ApS.`'7iH1q$NҊYZ"Ġ!8S8% vK✭lBpFڒ1Sl} 'p= I9b,2@ ‚E '5EA{Z'?́{Aψ\}ܽCipvSf%ID"AHaMmlR"eFɅ%m$d1$pzhԿ|io\0aZ?`t_ 'b8j]4]ػѻd?\!"k$#^qR(XuIĖ!gg4"a>g$$!#czv/x:,mvi]v[c I!ͬFl񠞞H, _0'O犐YSyl*L,̰۞E 93%-Ü /M_t<|3;a;밽!Ᏻ^od4^,| ~ R>-% NW~{o2M:-;~^c"T.h<^^}9*FGg!6StQg5(c=$>/Pv{M2x?GA~Tj ^+W^aAĿُqُMُ =e'F{xǞoa~V^-w̺B$KDϒ0Lc`XWX>؇wf3󼣎x$ڽf X<r% d;v<5 gl ^8#Hy?C[!%8Fj/✯ ɜƒqzB:Gт=6T24$' OiSO ǟ:\]+t`K|U@UQ ;qf>L@21Nrv6r09 ;9ao޴wZOi 3] Dkm `܂lW0*.᩠< S' ڬ-=$Ay[7 {<ْF@ ea(_!ݡ݁y~ /E)m |[R#t_3Yüne :0w{,f/ю n;21/>Ɵh:VO$aQN%pP=DRNbp-3Z91;Um9m"|dH7Y}Q 9(5V`4?U?أ!iQ3Юu\G>])qIF(rNȐzA> I(Dc!:]ҶI)"&ZNN{wP?5HS*HtrBQǶԍ麖:`ȍ5BqێDPՑTF vE14(ǭu7P9(zMjv>f%9Ï"GLh} Ðm=]Qs%/ WRw3O4.g"GSqm]jH"4Xˁ0X;Ph볡^̇ .'?Q'.<O ،XG5g&^VWOËI,Grz֬]%Hېe*REe)UNb vi7ueZ_(Cn_)v3[B~$Xe/232ATds/H4~48>&~}6Lީf/z=\8欒1,ś<ړmpp\} S~;`(A_pTT<`L=;wnm>;>\$F@b`mPih۩ .,}[Tl2|bɫ !'Ѹav"kt~vr9zp >r.E[ֵվmc?R{jݍF(~QbuM!B(֬xH%MMK:B[u&p/H>VX9Ŕ2`TFpD$ 4 WFZ0a =YIKQT9d&WחTFOT}rWy 03PR⮀Od@;"y\q*v*)^D1Ҥ#o0!㫯}s##۪rl8lʯLHQp0? #x42ԕ|SwOݍQn`&оLfn2ClL~ B B JzlUÃI![Ly|6;|esP?C\" }&uehںqUJcdS9 iT'D8)4t@߻7qƯia)qWT)9p_Ђg~̮mt5o]! @vݗ˨}kowg4jj>U('<|s*R+ ^ܢjnݩپXmC*Z^fZ.b'p;_j۪8z*j^9*@yVX}+x}G4 I0f [.j`zm1T+)*AJB0qTU)+%B]OXCp=!@7YnD))N_sDr꟯z<9..08>nGK՚75(شQZ: kXf%$*jeHx,m-c͑Y3MBǭ5H?[d}Qﻭrp-q<3g$/{=^s/`=/GTlC1'PXy)m DjZf PT")~{rY@nFPJ< ї!XٓUnnFQ0UjAYIa5C\eΰج0mut `۫ino N}ƥǬPҧm gM@#I'?{ O3uXȹ izl T`%Knʂ% [leF!W}!(̳L(?m-^vmWnMԹt -*b=o,rFE\aS':$UaIH:05v.y2K"Xj4R)+h|ۛ-oa^.߷2,jx -@ FWg&M]Ce5CZC9%7m(u㧹oPwQ+9lEĥ>o\vV!.Kxx|?s'\KnJ( .Pj/:xuA @ Esl z)hw2TH&"ގA7{ $VWĐqFJE4w6VjxȋiD&p%dnqeώ IF3s ]I-0(%_ MǼkV >xN@yIHhbzӃi6.7+̶hEۻˡ'i0R$ =^g4^qŘekI&xDl)$"=6\j!9.iQaUAV۲+7 .ג&!s {ܻ:Ie\`82pÜ8هT !P^L4aL&{Lnߢ3LmzI `EHq2%D 7X)C}@!"4㠃O,=d*tE8*6;0QpjO2zF?-$!1lACLH5nbb\Ӈ)^ueYr6%v97ᡧ|  ޜ4ªʲ=e=XDu>L_B<%6&v1Q8\o!;A;;7ڸ7*Z&ISsxr\}_tU㊯u׋W~zS;ãvexWO8tlQ˶P[P?qU&NcQqP*g߼7vڶ0yg$Ss;fuX[@\ORa ld t KbP>0/!\2b;tp:a"aU8Rn0" H|d[ħMl)1rl4Jw &8ةeϘ.;B*πEŽpdj.! 5r Ǩ ss|CilɲrH&aeJ/th1)'CM-u*JM a 0WE[9*;9VOܧݫ8ZLJTZdbI=A,ٗ)g+j9h-4Fz8F7zFwp[ϵe3X GdljPf S_ڝPV{mкAnAbifػ7Q>c6$]ʆeAj[l.66gMjϙ6 tWdW$emw/r#{09u\c,\=: }an uo 0w-ܱL ~o\8A2>ksSj/&O nB.$|J vgw#8+ IL @`Vp/S=8p8qC`}"`Y~Q(FGEtR]Ф( ( ( VKKVJwզief01/(j8Ǜ}m|zUy ղHl )En!S%0u眻eTP92ޗ SJMZJ [;s4S/c,k41)q#f*\fzpJ1T u0{iw% ^j VB -U*_f9~Ō h3fenҫgЀ58/k~q7W*9v4zsGL"[˳2[{/A myYKPgW?B,"M-INW}[ PԘ[[f lxzOrDsGp}B}ҙy5tql:KC,D?/ |;ĺKpR_ ǽ`2y9K! hQZM8ϯAgN<˘Ztx340031Q(H4Kfx%v-.̫%ŗy7?"`(Z(p%O-X\q]^ڿm+ǚƿ)Oht.ΏO:Hh p<:: Ex}먹(\U5^7?%QtMJ okM^&XYi/"hFDrdC|v),vNˋĝ1p:XK6I Zճ nܘgTw_oQ%a:rZƒMMSgZg 4#CCQ/&I8t2R~ks?7}L+9ruxh6Xw cG b\;IUw|&WMtzkp!8Rh~stk[C{8F2"xe_K0şOqa/]!t *EJfm ͭ0d9i{~79'3/wW P.e%8kt^TCM lխ5JyP7D(LPb 5 fNkeBPpS돰7HrIM{2*G(xiYu=>GH}ȎHl$z}yHQp錓A> W2s% y{]s.^gS %Ύӣ3tɜj8ZoRg*x[ϲeRF`xE'dTQE (hYPr.߳xYioH,Ɉ6,: 1rrI^SÊ! `5 KUuիG]q$q^bTI! &bf&]rE2]m2=_w8<7ſexL+|/rAǾSoD(X's=A3~ E_ܧ1(re= UBe3c⹰cސ]ftD.ULk{{׮TY^edS 9̘B&seT7)f^nD~ t!?E( ޗ0S<5@KD_"KjYM3]l^Hc'-y˔/ZdQ$Hel](U0I(x9T9&H15% 8PI!Zz_ˍkC1RT+aHx9XsTX+*/8S *&J3S ԤU%FTZP k9{cF,.$y̶LH7ƛخI'}Sgq]S?,$NVT/^ |OOxrlfܛ!"̨e?z4K=j$?3깍 k]c5TS>E:RKja-FLOL{C &v#t8 j~yn}{ź<Ƒpa'NƒUhJK6NF!㌇]h8nr^4aɰ:L[xDL{֩;qB:#c^"^t4O[gȉ˸8̜Ii̓q 2!eUSeՃS̪OJ. QW fiY~rI͂W'[4ׄ&+aw;LĬ,pܣv !saVާTty3`.%Hr tSؕ!;M<p*;>x{ D\j.hV .T1xDHEvg Bc21;˔_#dwH Tj)hF (0W˲9Iligvpb(5pGOT}Eq!&BLP) tɸ&h+J-rs=rvBr\q߇b=@KmMzru9OeHAYPU~Kcv ⌘P+\3/Q JJZ~:7˫<^==XE(6֏=x3M[#0M O{@C-ԑG&2@V|6  R%جeu4sH+e*TnjBc")+ZsIO4CȾXƖ>9C\쫺3oC}IIAUiG˥^i]lFPfl;+^<~k!rz3~a?i!fփ}S J_d}Tkl\KT&T/\{ 66sl WnB<.=ˏ ۦ_1 &8j,YRvԃ|!lYy5 @*S|-ƶISUgQP!f7ByJXZh.9*lq#d;KdC ϕ'ᵇ ThL/aҌM7 ~ lnΊ!|+8a u+o@Y \> ^VH>Ot7t*I=Pu(b@|=2m4ooBdkܯZ} o6-`߈}pp[t!KؼMzyRԞFYAH@_U7oQn,.., wGUa_1g@c 9!"-KO"xBe@ۓS^LWGPSoؘS;;FU=T{q3gz8 ^?Ei8Pg.]۰<q~ y5$Y Qu=ټ~rP8}ozɡEW!>3(EYi[["J57\ԇ@ E 7IWD9b$Nco^ M6p cny7V}0{ aVMSŪijO]dvh/Q ~s&bQ%\M8M w_𯱮WsxwS! XLD2M1ko75! ж~}M; N wQEf&[uҞtdW=-- hwA( %5۸ZxTN0=ۯhxܰeXƅ)if@bRB7f:-VTB__ߟ>|r84 k)YH̳ I5} |wDtjw3\c2L4pn&n| O 9I{[6%{x$x]:_ ⒮F%lGkW_ ž(STc[\X+ݦR_ 7DQaSv ͌0pRs _cLU8*V$znH2lmB,_0s5GV<&;.Kke J+4+ ܼ'L7דlHu Ċ(jxmAk0 %5ea0(lXIեRpn0g.'Z|T;:gq'(wM(XUSm1LMH_fKs-"*J(ln?]~벻YA$GRQh61z4}hG%J!p:u˜Vtg-_e9`ړ!{jk0?BxQo0ǟOqҔLeXTJAj@hOVK]B5[|wet^6,7Ue8c>3qB%)P߽e#Fb~|7tգViaZb#,|ak~D'82'~vo;2wpBIƦ .Qz P:Ý!4dJ̬-: )CjwT$M5j7Gխr[(mHvFpaVz,ilR:{C?vf~ۿ,H&JqKQ"b?]4z ]43|A鮪F30Y"6n;M֚XZų_qYr:㐯XOc !wf~>4I&Ms^x=h5Dgu]/UxQo@ ǟO "P({VlFRiK.85Eww@IV!>ǀY1"[a'*3oygc(E/]&~^@/=yΠr]| W׋ϗPg\C|ǔ X=.W"SWe?Y'D:!B7 ow Qp2i ̫ܵgقL"K-`yJWKr´?lZxVYoF~64lIm9E^ƀH 6t uX+kcr]ZV,QG I7A a`.֜Qsd`rcaanQҐXWe`N qu3+.f a""ĵJk|0)!\9!ᙔx`0hrd3Xr&FG .6 K;HE(k"YD*͐%O}>?=a6SgQ^a8W[2a7e?-Y)$񞔈qm@ ֪~BmwW{:32"g͵C\ ʩzx3gJ%С[aEoFwp3yށC˙+dmR FMW$|F1O;1H܈A~%ZFռnWp oMyjuZ>t>tFkW>K2lDiNMtP2D٪]* q"kȮ2j4 nLǃAeQibA]vI%˾~ ڥ(V ꐃ(\&+tIAƵV:dmu~4xK]4_aUrlsj7"x6=k,2Z0 ̟!W_G~ыP+[/*rй|ε_}\䡲vh1rpmN\ġoq-%)Yq2VpY:"Xpܔ$\VYʭ^mM4Exv7|h@:~ourr,h ^V%u[qtL3oWmpt܋  w]aDT?٢Q7kw'Zjl:v\@ v ­ч`<9 5ulɋE?xmON0 =_aa|@v9w5*N$!N^xe{zlc- e,<.Ⴎ#n5@qp: 8jBY+h`*bYsKRS.tL,O+>wbQγL5WicЅ9״?*G%'䋩7N] ',u7ge/ \ \x340031QM,KfX"kěWϹkMyMa?xSMO@Xv%ouxSYo@~ńHa 8$>]Pwfw vJ(}31yH0\,o7_lg"ZQlZڕ1uTEC>aPG߳%L}ؙ |ϓI_j&Rb9 r?7{Z v8;p鸕dQ![W>g&iޥG4T= Ad ?9a8TR=xCJQ)3$t3q }![M grZ^XJ_Q"X--K l<m%0 vL JSQ_VeL < 4p P"T(0:S{D#Xmv9Ҁ?%d+3)x· ^+כ8TEgÕJh..@5tS=dQ6Qa3L`c6[#of-]|E]F!<°-!W04Bhfީ8}'aU4+x?/ۄu&zkZܩZz. {rfT7u8 &F]Vn:hFuضPwt6UX9+հexU]o0}&J<gti[$ %$X 6V:qVs8i\fXs|Odvm %mQBZdW6ߨ}Mbv$h9Jdi21+#\k,kJE>aOě2I| s;ul}Wj7ə]>z (O.9kȅ5P]rL.8XC7dÅCPE@}sVl8 g^C`q(exTk0lR;MfRK7ʺ~(K^\l]ߝ~$l}0H>{wtx&$q|3j%ͯ!|8t(ˮW*Q"!~Bř/t7T'(_g90J(6}Od ' CJVS9p40џ[\3ÓC@DmPݓ.]]IU%2mMIv;%ru//ЩW64D ʃP:>" ,BI6s*akѨB{󀲎iqX%] .EYKM=;=ymOhqs}g!?K3 ČUj>kc4*UFLq%Oyid$[b(̶{&/^RζVj: {60~Ľh>t '=Z:3Ѝ\9B@]s:^=bG>SyhjAb&Ny!S}A,1>rb S?[O?ml܇ I(n*>Vө( J H?I#r(J7ٝ1e XKǴ < 2'ӧIo)+_h|vҭ=_:45)և[cb:i20eO!>ITqc:9c,=iК: sMd%Tz[DVٱ*6U \vs>ȃ].*Kq0qw 5. T/W+me])+e ]ˡ*R.W\,>\v]CLZӲ\9ˊvWb$A*+rH֠ʞv*79d"5).Ó1Qx340031QK,L/JedSgZ9glAC*Դ̜TUu]v^>4 ?G_O?w+E4 xh7a}:\P%EEyz e v3EU6Ϛ'%U_:(+׬zs_d$.BRi[\RTZT<؋%^fpu5Z݊F)E`CN=;.[z|mp@wf$g.8w2EݞKNL*O\μ!5In~RVIeA*P}btN-;d} )5)Z,,pwʢ_w•"8'?d2O>oʉ-1ݏ}2 I9(HS`uC^[4b N?z(.u#A9~?3rXp@e=f]ۢm&H9\{  lMR |q5)Vk馤$f>Dߜ 7Ѫ+[X7@oT $8Smi&bTg b-)s,7`*~ @Ĝly~9h_QuU)$&<[zreeP5O'Cf]<9OTȜ~f߿h n\S*iˤ1Rk}Yf@7h B_ĉ=S(<Ӯh:#x=LB4@}3/;sQ~ȁ?FIXկd `dCᬯaRK3Rs R@hgĖΚpǟTf0pJ[(<fhdS_2YeNf3" 'M6x+OxVmoHQ486t4TC'# I{װxmRUofm"[˼>Vcׂ:U1[LxC$(t}+/ǁx<(>:0!\ oVydW2܁༌d \š/?*TpzNƁzJ2\!`'`!x6$6XXf~0ĤXۥw,$*ij̸ D"O->|Z) |4%\u>D6I09Ex2cAӐDތd"tsgBP" % qDUZc올8G`*Rc*6#OWy#;k0r$XnIkyvC,8Y.J^"}$snj?l|SNJR{aLKJDc;wGrMֱsNOXeCHy6I-hDzw=u*0v $<(~>M=1Muv~:!lzጌÑ6~. l~g{_zX6GjtvDų@˜িmL{vKs X6zhӼZ⸷A~uaGTz^aowӲҫ"Ek°-0eˣ>xZw1YFdJEH8n Vd3S!W&!dN,_:H;?XrVKfԬ2i#gzi`9vml:P۞G\sRmZ*jta9el#ψUH-oVpRljlG;!T-gq"lwP_CV=(ȉPM_CKUۨ qmYRo5/ڷZg:wٻ}g UʨE[/r9D=pݭFp gE8LXxs eٵ" Lr4g&|@a`6 dBwqf~-C1ܨ/"JJ0~X\%$i‚  -.@i__o5UY/'U*w_icjx8 -Wextra74\afdef OPENSSL_SHA1]+H)xeRAn0 |@bl r!h[,"ÿ/]o 9ÙHI@&^JL5sbD! Ǭ9Q6 |i Ă"y؂ZW}mʆDTm?Awt/:ה}ĻAB575딫QodzĦ>c"xcl/1I˅>[p:-ms2բQ(ײc-5aK읅eh<$BUe1XFEms#PЖj&_©;Ɍp4#L(;D%fd}ɪДR3)m 0F<kM\-#ϳG/ix340031QH,"̼ e5TfsdΩ' ! <~S妹ﮛBqbnANn~J[ꔹvg}t0v?i,IAx <]oٗ])=iG c0YlYH"hOi_PI)KQ) Im}y{=s,wZAKg A!TF;9 xfoݬŽQheA9kHOh7NvPL˵fuݺl<$$ 'jYp[F٪4f?G/; 0 /ջݧs|D?[:'"O&=+gwm'D隞_ɳ08_|kHuI{뻃f}^̓4ٹN GChcFPfBI`>I|w"|A!DŽV}.rL ']^-Rw42Z/:9S]w_?V,EZs).k1Q;=v{"gx[]b_%ݯE9E|ӋKL-|1bgo9yS.ISoyɫ剩:)04 Rleʻ9+]0ڰ(h5.g(>sݔM: GuMBV.Y_ "g*~s]w՗ȵx64`Dzus>9S v9%EV_}еjk՛f\Lo296<#zʻM(9;p39.ǴۜB>faۡe#ڳ1=go凸I띿6_6S~Lɞ7鞴^ߗ/Ύ_f<~a mnrb9Mzm/هٮKDt׳ު\LŞrr;fϠ^;)VXj}W`.rbϹrfanhϬ';io&hg&vv +x:1q;a:%;c#wUyoc6}{h|Q*-.rbgl.NeT69S@vd~JL?;V<"g*vV.gQtϋϠ!Po ]:s3;; z?0(D+^:9S'f0Ne17\L%8؁_{Vˈ6sUB9SS.Skl~qѧHʻ?M4o\WBLd,as+f7b?̦Ej<}OɞRjb.=ET 0.J6ψ2N2btK\L?,H$Mts ;șd1n ўȏ}!TiY)>6?Ow~&&ib?̧dgW{.sjS(F޾=^u. M)5 X͒sdcQ}y)Y0?lHߧZhmx[C^9Sr$x/kxU=uDM{3qo̴]C=5s 9|s. !;?7;G#vr7LRc篧{4Cl0o~a#A:79?m}wRfcX<އ5̏[gKP/$]ח;{a84 ulaIWQfb;+|󉛿~?MA3:#q x 0W06\dAl!%v>DӨ .y0" qӣWz[JDzHhy`TWaC_;f޴4t(9GXϴ~ʨi=@+TCv@ihHaOع2=wiQ֧,8ZfsFly_GD֏@oݼlI[Ҿ .HbΟU/I8%ж٪Og[L5P#|29h%hV1-6$ Q?b=VUc2(&Tm2t7 ~0[QPU?ysnzxV}bSqXV׳ɧtc/VL*s5r_qRҰMޢRBu<~sl?C/r ʾEE>ۏ/Ir}lo ȧ}p\u[ .9xrӇna9?s.grbtUȃd<_\}2?l yJh@Zzӓئ寎\Xb ͂Sp # ^;󫹯"tf.z!m9 'Bkv9JNdK^Ζ" S ~q19\k%wD zHެ ?48)04 Do˘lctE26n;1'{sO3`OgJnVIR/0<Ƒa4)+GY\hV%D{s39 lC/Zӯ,B9em39I)#pC}?H8$c텦Qp8bg^ߥc'lŲ8UYL;W*[|Vn{LjQ(pcu@Ҟ -C'>HC0oO[uaUR%<}DN0ʜiЕSwDw K&3Ms'`8&gog[W9MG1m=F}Y v[xNs,Fso @"rN`=3mfa͜uޞ\qK8BSHzE*/X|1TzӐ7v~mx6|xka< ȿ\l'|nmo),4k>2fl:)Y'#u`Aϼ|3~6]j}@vvq+JWWq ӧ(K4C;ٮgNߖ)Q&(~84]N/`ȝmTgSE6}/#rH4FJ9Qri*)zgqR #8r MawJ#Q\> r@:E1` yQ.ps)q%zrE浹Y[l91q;,4ӔtyB5odC:8FMx88:,R_WфǹӜG?@-Vfj2%u]x4#G9L߸Ts9? ~Wm丏<ӌ\T2 Nt9Ϸ"/7ng>?Fa˞ԺkaX1ELM9'өv;_hh2CLت xvBʃHSjޑk\;w'zI?#ğjO͒<6Ͻvڷyfߟ '2o./[iu½?4OOܛG0_٤Qc|[tuOrD* FQz3ϣ͇A$?B pK/}&jJ& M9kʜdvѸ_UvH4qSF^^Xp[X~Ë_+j&l#| ce@CKQ@US8)MlViRV< NvOza"}>'7}]!K0~`D_*JȜFE]SAxuJ O+EUL)ytiYd?7Ci_u8ޖo mm5:[y~'1F(X&iN0| `fOzqt[n9ID)l?$qy]rg?bwxFhtw%X × q|{+I`i}0Oq6vU9x NP jvOڲyZj'T3'ϯ %DZ4 Jg9W]S *?Op|9i.^:&[BГU?Đ"OlqR5]L.y sĹɲۥ2v\ZN f0uj:uϴFzn9'N~6"aLd"}G"s{J^9谯@wbUtL/+J [2 ڋ|"s~Y_*}JC2/؆Ľ7/ HiWE}dAZgGzĄo/̗rd.pr7`*_ҏ24;6\}#|   wsOӅNyT<9ō9uᇷ 2l&qK)_Б3:}pUIRrZˎ^R58V:>u ܣEZ޶v^'UEs7 }KumSq{*[M] 8m G A1G*5N)8,rB3k<`ɢrNݷg<%0HUk'=9)x~|Fȕ#oƛk~x\ę`CgҶ=_5,0;<\o͙>09USK0b:~gr^Uq4P WM=ߞ#'`g;JQ/ ?5.jnT('{g_zbse&^}e;ݨ)RpT{?Cc˓Ow**yNzOra)?g{G#,cS8TǹiZb_ӗ R}9=0<(ָ>nvgs,gf9;_Sm˕?_$l7u]&L>ۺٛ5)YP(5[7Ga_,y𲄌~!Kf_B9s: g50Ηm pwkr<)b(ȵVW|'|y퇆r?7C-> 3AlS-_t^w|5,ׅ.t#Z͡|{q|i7sEZJ:E}N~<&gZa^dmbU ݀fGY;0rq C-JoQEg8. ce ^[cW?yR+!+ܥiTѾFLd.0}I۾ ڗM;2]e zs`  hw]F ԋ+дE cDsj7Cx0^ _lGd Wggz'6ea@6?W8T[Ӻ:8?f+*_;q]~y67 9hj YuqTZ̖'u|6够 6'ik\lcAnγֱs(eb gK,=af9C{s>8r^,@[c1~W0 6~ Y"೮&woG{O?$ CtLe}.Gv7jjE1֨O_z{`*l`W%Cb:4t>qg`U3N=eN-2n8HT*fn+;k{<n%[9$RT ܀,&Jhmڧs+Fq+6GZ j];8`е9bK3ESv ~ |h? )zZ-zxbtSqb&qb3;Yi?V./ا>0-|;Y+tBAecC~f?_]qgpĩ+1;mڿ eGv,ǛR:?"2xt^+?ʫyߐ3ODqٗoj5-pYUQ9;h sȇ},prl#s>}A/D`莆f6{(?=YE By="x,e1 s,1YnӖ'{i_ taI)t2 "yOO_` Oc^%ydz,C9ѩ덻%W!9CEPu@ƜQqd s$1dJyTXc,MhVޞMG+)9o" pGѣ{#-3MZ>2%>NZ&%sBhHI&ƅb)O~! ]tK1e\5 1y ' 9_\^_ 7<PZ-Q{~~QC7z?Jf&'/gZdA~Mq ߬]~8\?r7YlqahlzGx?r/(YyXGcX9D@ΐS_ָz,̾,68/a]FI%.?/&UFsҷH0F`x>؇V{Bmzq51e#c2 Xw„OSg~ r; _`;g.޽(@IJPu&ZyFi̲ ~xTO*pqV<9󮵬6v={VQLP$kݷ MQ0|:@Kz%p1ZJPO3ȉ)z f._P\BE<Pv9S)M_%xkgm"˹Cax,&p3Qa\(u̒cٵ OQr%CƣW#G!0MuTϧz֝+Ťty`.{z\t≬UUouMwL0D9z|/$}= 歀c0r"xŽ|wu_> +JP#]1lr|`EeӑC ;sE ^WqM_40^OdW;m(xIէT G;뺫fλ Mdۀ,ǟ FN vn8?_#̞1}KfZ ϟ1J`ߠb}[ ,ޗ]!ᚉ,Eb߂w\փ=3>W;|^.HYE57@>^je|GLW:8z7Mi}egZ'/*Ia r`D@ws.~p3L 4I](1X,տvX>[:se3sO# Ne0?K8vӑ{nFZ{rvy[/TIׂ 5wT|??c72<{Хַ;3^Ω:睼܏`\X<^b:54-q 䅎=(߯˛xa'>lUQO.\#ŒK.5&e'Glh$6 ۈpS8wcKʮk1:+*^Xeh<2D#a^~IcwՂ_Ij_Sֿ+p~`aSg!x_uZQ"o_r`EU[jh2<.~|BH|9;O#A7tK߹O\Ep'VPI-ϻÏÕW@0rZծ]Q.QaY|2;A{Vfi[Nw tH/{p{=/s߯@12J j S':S-Gn*ftLDQ>+x2AlD;Wp2q^ȨhU,t;VLwE.FChkѶ6mګBx96-1THI?G91 AZ'%O^ bӡI?8@}E5tO]fe0'\ T]a2"%Svy+sOãtٲt7,^8˨N7Km+55dd`=8 )` PNўC#uQ]޽Zu2|)|1?w#j,y@h5,?xWbQYesۋ& ̆'xW'n z| |-$&#UW<^=囪~ sp|`3q;@]¥^\c\u}|V%EhPfҼrbMIJ:}cq@[b* /?Tަ2mxUGy`UA@Ϳ |+-I}y(qT.}E_[݅OC\VuQ,"RRh/5owAG@JIUE/_/l,ȶ94Ϫ& J drTz~yHEG&yz(\$[n"m}[jY:Z^+--Zňt".y*<^ra'GH~QRM&UDO@߷JXX<-eSY~0V~||Qm}k +8ԟFLJ~9CXD\f&ϿcA/ի_0MfO!vVMY8=.sˎ&&r#a Df^2tҕ:BS|ﺏ _'UKDJ _Bú9M[l>xQC0p'| [k(lJoھ+aN*X.PgE'z4G$6r졥!\|bފ!\~XռY? "TLѼ:D,W䫾2;rw;^݁ 7쌞x-X}B]{H{v>7-ɤiAspSۣCj[YgU.?ilndՋsSV9lbjZv̧YbV\ެE wrf |^Ӣ*~.;eyW@.N6O->r~Mʗa.HKadT%P`ۖGݦRV[m~TG3Pw@ܥY|. '5.mUu\ P~wښB@KrEC,{^-]Fw}͟BU<)uxl̴ ]i^] :Ng!q M*&ŏ6ԝf,Nj>H5ȎڙԆ|o T+_j>VvۿѢaj/ϾNX<5R]}@!ʉf#xʞOf,r;OV.X*>'g5³ca@]A> R :Vo2o<:omI5G*_Wh:ed5j2o<xww4Ԫ#F^ *# |0ϻB^r+[ãi_NTsDQ3pm#WNj"\x׏l=MjܖU[>:޻~>Gxǯh5ֶ$ś \c9 Kyώ{zN6_7~۞.[Xm٫+ۺi q;ZmDtPY6?~c=k}3b~f {d3/ziޡ[3=Eǰ7#pnAﶸ1ᙧ[Xj +ho?[nTvA#+.U+@{{|wY&4.|nCӎ&e| Q{ޛ58Sw .fF^'p+ө]8kjkLXRk?x_Րŗezrj׾,iXze{W]KnC^-y&G;ϧ|y"$]D_uMzS3]1̱:dIgM~uh{y~a66ߣ6U9ư09|yN%rҫ -?0;i.;62x'?cϵh-kp+}> ͆9ǫ|?}sxv\O@B+w<gz,N8FXVf_j{.T o3c[f>bBbX Jz޳I ?+A\L+ wG6?"x,Mo>zjF,l+זF_.[፠`8N/zh97^N?tQmy(Reax;u%QW_΃MCu_09zqћ3{P[ݿ`ўꝘgmyz3 ޝ?o,]KԡR,97Rgy~U9$n!n tk;۫9ޑ8~Aq̹g0ä q,)n\y% mOg-Bj\It_nFo%V=_ڬݑ( q='ޅK94k4Vzg㘇&8p~:kD5b 9s|iݿ:Ÿod ЗH3Qyyþ%,S#~~ǜp*<v8#.,)UdCI#"g&8`g( GZ8o9 ~Ac<F~PH.A&+swy̤պ2a1IG.1\<4+/Pd:$8Bo\2D= !fnI{x)pƿ:ۜ_nYL/~/l6q"~!TsDrH聰~)29IdN Kf^7a@@F"@_* {uPm7#/ M02QgCg+Uopּ>cҺD]Q1:q͹ 3J8ew_XŽ3򽢣 'xb~:>kdy7]x$-Ʒ 4?o NnľgƢG FR@n¾6\;$Tvjk <>#)x"n1us]'VWsx?Pì?y8Fb8*`׿-yތt;ue f07X]\pȇi& G# P/_jٙJ>)fɳu'I'N 2p0Lk,`i<[w~"0uPW Pkw?5q cΧ\ہ:'|MWex|H(h(.F8LJ坈.* ,v13 @sE5փNֈ:i[ aȬ:ۊGʝg}ǐҞָTf/2p}[μ2?<:wcU<>.oO4}7r) pU mS/ QrvANj0rv><=ʧuI"|yn4kϴ D.o 1Tv]?F5?ϬjǵB,9D‚NS ymW>b͂As.} ́Of~hz9O$+hX9w|Zx~qB?2XY h$9#ED6R=*M/'$՚~ l#d'gtpe!yMƍ4oD.Um`/R^p8gY@Vd,;>!yv.<,dIM5[#/?g)sZi ?tvƍ۲^Va-Uwdn%u驪Hß;-h=c)s 4 ݏU*''x[ͭϊė\cʼn+c2~I f @Un9qOnϿ_{@*#kΔn])ﶷ>,yyoһ8b+CPVq Bra*YlUi} ?eu\R<(2]%${r/}yM ]>g]D=m>^{Q֝'7Cބ49'sG`Gn]e>v[by'ѵ8#C=;Ar8!, wTS gcJB_󧛮/3̫Y8 X""%0P%g2{=KHqCp6";_$K}yBrՕL,:߸(R㓂qRy5ǛuYeJ"q#; ?\>ՕI9ȧ>3:HzjbP[O7\t+[taN%[XrCx?fO5 1|V&y0p07@\)JjYQ%g`1鰂_7/{=ux=/!^kY2+c_ ⸼S/vrkrj]Mnˊ0r` bn^湧u~Jd/_ٿYq͸=8zc{;;R|*7 o, O(gDvҀ;o6}c^0WG~ u +V??-*<Nh9oM ^_;IJ[rd0..'rukf Vy&>d{ ~sہ!wXN@T׬AoU_\;ۭzc8X6NڱٟY~5g)>B|۷Z9u<c>2OX|PNVV`|U<:R})8X>>ok[OcW 4]13xYqbO1tfhp08>nSYJE,:nJl?I#|P ,o3D%(mJ9Y~.]<`?vάF$}x痪,B5C8A7?wed1h`iX|r7c!J,is}'ָNpG45Jsn6^_Q[ k\9?JY%CiOWA_U+/ >x1]z XuC*c݆07GO\P?hR  Su~Bc1ϐܱ"&c|Y?0_4r]׽&)ɆCgXv kQE"Bj9 7]n-o1x$-־(#AvL= ["E"Q.-k +䩛?pL%~+e:P/^DOR%YMu%ܞU-W|ewdu?N?'4fPcĢْ>*'OW ?<;>^US G7_ L.5HÄY3 >a?_yQLǫ=훿J%OR,.={gTz/[i> I˒/Qn1هOrgKeJU+= `I0s~.5[Vd&d% S^} R0<5cJ]ơ-![\ JYy8 C>9wؿN.ߛ:a {sPY! J,6? 鉎KA#<"iD{]fƹ3AZ_;fTɤ;[ U ]Z9e׽v/KdT9kj;n4ÕX;(\wY~Rp0<.Du]A[V;IWK,3j#)@5<{QfxF7^!VGA (to)"4Z䛟\ _@=c>5jw3骻*zhˏ0ƒbQwX8 1?@Bybc83Xotn $cLHu/*Rfb܇ ZySJh̒Uz?⯷kPa1.|+PftbꕟE<8;:䄶)ֽVGx4m~rzè꽍fbڏ(: JVgU-&oGl_pNP}w>ɐ_i8AP:y)ezVryn8ݧ I pxܼ%&effk\;A1@R?뒋q-|7A qӑ;-Mgl^X ~o1>>r,y}d8O 88[| ߖyG.!$!.0Pw\O'wݼoϟ6SFefTƱs'QPFIsZŸYд_omVzƝ&T./'t $7eha@b76;nr 2;w.Po6$K؝[gW{[q!H;Q0 ;"K^r `Y64ռ*F# !iawUmCy?p32|WuH-ht1E.%r]9?;G"z]g} i=7rb(qe\@}EӤ}U\DTɟ5[.a(1L ޥ{P&>Эt0y RPOyհ|ND|7$7Y,rjY'8O_Ɲ-qj=]\ď&U ip೾|7"1Y [;C0^=I?!%I͇uMhX)j[yWl }j?=`05byRrP&ǁ9Mߑ^x/59|An{gx!Dpv9#Sq():޹`냡aFEp:'|Es\vs$,ϿFI\;qٹƿT 2輼vw_\ݙ¼w%\@hh<]љs#bI>#5QΠPֵ:%$nA$?q`N@vtQDLM^eFn&n[wfUmۄ}{ڽݏG8ŏ?~-?':=h|vwNGWewe8(|Sw_WXH\O-|➜2#FŴ%˽D^V`ZD;;s}f;eVk^h_=SɸIq ^òu uפyΗOzl{q!oS'pooTV.ѫ߿ij+0fϛF@w3sxIO>s{ʹ3.(\v\Z ]n&]6ϴ7oH<< Fy:廥}kXHu;Z d?kAƄgRP #ߏpOeDy$/ڇx5FN=G"Ki1n@⒎IxXJqV58^zsݙ}"*Csp|EDz<Q9Tc [ 5ЁSd$ \~2G *DC^&Ͻܷ!lD!ea W>cCEk^؄%\)÷?byC%E}G6VE&o<%aPpVŢoуJV!-Ih .R\88Gi>H\ [c*fճp|>'1~{or| gQ^g,cq獬vZw }\Hgg||yk|؛K­L7\ q|ˣB8{øuyuY֍94˞Rr9ߌbUnL&9I\/~slʓlސ;لc;֗q2+QdcƮ*š%k sLy$AWbݿ@Tu'moij anMO+?>OTuG_b<>5wQ:w%W鴙qb9wU:w%mo‰X!h&>;cQ-^"_*S+J=l r˄WRC]/Юzky얩XZGKY?|~|]j(i]xZOs.)5 5hO}7>)yg[u?H9sݻ"sL!ƻÏd<'g!5'YZ=s7v* diwAJ6lQ3vĊ\pt8ރB|q.!$ׄ[Bmm'45~OgkEF7D_w(:asNt^G[q\ 4=n!/Xm͒N5& F8@l# bzkJ(k|}aoL=k}7gL?\f ['v2&4#4M̬aEfH/}}I9|YOR\fvw[Q/zR:v BPȤ'i5ɎT?7aeu/x-ky Y;:td7c봽!fbpgdp~m>\e^)M3NΚt*p^M]`a]HӬzs϶Z=X릛ƩI|I*[~ש/lkv IxBJA}AظDvԦlKi\bO?%>ׄ}Ϸjb{rMTT CsSפZ4o!1BCx5=azJ0f;\wb&I828P[/R*Җ%qt|xǮ8Pa)26xԾo9:.m ;<) _a}ܰx;`¯sEHjCƕZ1? ,<`g9Uvσ_<:( k |f> ma\wskpCLvvuJ}p>񦲽at.tѕK?@\^<\nߢ ˚áC-E77ahf8X~Unhj; ̣Gxdbp@yyl[,"n&GJ?Mdqx`>yyJM7R}KMrع/G^. p~&a^K8v|YS|YgׅY$!-[覌Yˡ) ,89 9CŶe|zT$!7YǑo5L7″LP7|DMa]Wj9BotK,Iui\B\}'p.®}(#Nui16[.;ϷAķ":L ' o[Ey+'nxKC魼 }>&` se-'k0< W 7>xf:ʛhһ27fh/ ^%.9aPRܻqʁ^ނӴ Z ?:${ ȐJ_gf#-?3n5Ї2pG ;1Uq4v'g@s~ޒ:q?W9o'ŅbXdܷM=óy2[Ly@>t$OGc.-]],+zހRI_п@ܐ[+s*nyBSWs;M@Ӟztv-~E VW5ZnwQ__OSZ:I>ϻ>~ <ߙr %ܽ/7>dGm6'Џ W Yuϥ vCXPk? jI~T! ͟UmX]#@UHǪ#;F5Wz|_R@{kP~tLL7v>0zSxtnY?Y5kX f'1弬kQ|0зu"o8Oc応<ρ2< /̆7vȼCKTs|6!HH0I.dME=V,dkX<\r Âq:jrז/oFnVߟ>>CWIj4t4AnJ?bWǒ8XUYPHߛuqu&gx@jٙvl],, dVHUuSiJPpS?6_Q SM㔧DV?p8HLɣ~(]@x s]BA՚zOh3^YYAɣ:>|0:Åz+"VGQ7c #| h?co.2-rh#;:ȅ!?-/ٷ0"eeW8d(@~2eFy.ClDǗ+m?>T6=[@ 62Eyߋ~eG卝{s,z<RjH Xp' &EcI/_}Z`q|<ć X|oѸ7FuLW#ۖ5 ~XEE[gLd~m`C,fv`RL< MEx/,z 4[tL_tѸ G8vގ_?i XߦUrԲ\G Y3ַhu㟮 jVy4 7(?L*~'-U|1t6vMg3:BBDh_|c}4 J;]SZKvk1*Vt~ B;9y:S`JS'΋+6\/x:o{qZDaS/ǜiZvY#ߙn;ګvx<,f_:GRr41e/*%T#F( oV pұ,qEu5~2WGfp8lZ?ݪkaqZ qs1rpQ894qA!^72qmrHC;QHJa WNm~c1<_nh ˺gT)$笣PrQ<#:ބsC/ɖ#t*$A`8qd×+IpD\ oGLX dXW6v;7o#1|B@>u=Qy]QS-perX ~>g.#K~E|vaK"/?_&7 T*ނ Nh#hc^k[R}W .L08OQG_Ryc|vڏ}ZS<_ X)jj-U^fG^5\e{TTM,ir.b;cƞ޹'Pr]2>W#}Rxǡg#s?3Tf=oSFE[pA"!tuԹǀvJۡk}Ъ[dž'w3#80a71E>gcWf2WA$`]ZX#%|F3c(ۗT;hdJ.WzФ\w(DzFz\:SYzK[٘Y&L彾= _qA'y/Iᾧ7o_/Y8z?W(qN)>X %a:qI^ kɑ񠈷/Bup i8;ӽ:[$js8(Eҗ;~(hTJ>)q-Jm׋ b\j#{Ex>!ōh  9K!ڱ"~>qv!DN.݋o?Ʀ9:Ey|h9%ȹH9| <Q1 `pS\UtDDH`V61E%~v?Kg 7V9փ)+({pʞ!/} AXʧil80y8Ex4<` W3T`sS@FK=2[]ZN0KĈLq`f;:9\J>mjzŹ̽ŴC+| O@WRۿ]W\5T9-RG(3RG-g/R)F?ПS^"}[TG,^{t$|yJ>1 ":[=ڛ/|^x>֋γ[rhXt웍oQtw>xE*q8{8SmK:9Aj%]#"O3x>%cRvpMGц "іm_'_>Aĭ9V+_rYp_)S0|kOm廓cf&abd$CgKW??¿3F.ˠ* oe!)%|&5A)Iikd[E ;5Gs/lu~a/''B"Є.o%0>yf .q5aS\(*` vtJ^BDu &Eae^f֯W}r+1~ Œ*K#p}G8,-![,lG^Ug oO;_~֝q`48+l% 8^ sIa_& :ӟFsW%`3o(Jb{8}0NE2 ۾J1z6Ml9r?*ʹwP;5[[RX,ّQut4[F#|M3 k P}6qPg{/Rwސ^tek; ?$E>09=fܮdQ;m}(PΎ.ѰxVDý SLlE> ,ǎo~e-6tUE-DS$q8 ^~1֫w9dPpK~'+sF .pc/>CU3-c^啉|!Wڹ[NM2i}S?/o4Nz*fnO\sryTy0@Z.RS˟m~NĨ p@3iWzD_tN..,meV]y~n3uqwJ. -dS!'`:.pu-qk/US}ӥFѫճ1B+;?Y3.kwE\UD?# -6cQϧwў;cq:< |޹`*gv {Z &L*6`[堼{ez<浵o2wh ۗ8V'r. Z^PGnH 9꼼`Mm.w]l /%E?71T.j6]#dgC{ƒWJ6 z~S}- 7|;0;Ֆ#qb =Z,7Egn$s1DB3tQrU{r[^{KI:آxn}|C< }6̥!p_]Ɩp(Y~mXw4P ĉg7W* 4W߉tg}LVPΉ=_ͥ "{]CQWmֵ"KMWzى?oZ٬ZniwnW(Ώa/΅<Ff'*:i^:v-;\ g<UK^9(/*X^(D ċ n}@;?+}4I^[BۥJ >e,ڤg*x=ٜ$.4"8In?`w*+O7s%۟<!p򏟖>>u{UDעNҸƐǟ#;@]vR&KUoIz |_c:0)OZȣy#W5+V\}z[MHjH_ Џ,tգlP4#Y:nՃ7QA]ו YD9L%1́p1m( O:iO~uMgk"n4v,/+I~k"ah=<&Ώ̗#|j`Jٲ,~QGh$SGz\N导}7]ת@ OwsmFAhE0^hl9ѐg@u- ~ ,'ln?A(,XRrgIwdRnxO}vŽ)<7!ϖIEЯtwo ݛ]"Ht \5 SPQ[JWF#BC?u ˪t|4=28 @"FCQ Ck EN;,d|i77 ]>6}+}B#ꌡ % <s[2_.]ZsQќP(oKE_6۞x*(eҮH xoѯ7$ţ AX}RFܭ/DȓHkww*˝"zҔ )5Շ2l_P $y A ]vh=7f.%s(V`P񦎞]kl2iɡ_Fukcrߕ;0;$G'@!P@ȫ%*vљ~TmZ&\~7b I㿆6~RԵRr Mw+@qUqRٗ@khO:P Ge,qmS?JMK@oAٮ_ߓl)MGT (_ܮ&MWPzI]C~43f{W߯yBYhNn /~n wa/hǝ^lC84x ]|eyqުV0 9: g^K.Ӥ^b;ġS^gC'g=ΆirkoqOyGеScűm-{7c0!O n@e+)xm]$.Ҿ8t>8O{q@BS'$&/Zu77^[7M%fuH#\l.#:t&m2E|:1eSg22Dǂ g]^ɟ|{S1~r".XorAXt@ȯ/R晿 rp"#P~bRODRO;_.9rR )Yk=j=+!8OqG:# YmvyyI W%1 ?HMl 3?R.'#o!% 9)uEϲ5|3cxeSY]¿g Q2%=WW^2(ܕy΁IP.6[w[WDх> 焎\)rKp~aKg h!(22TX^{!{pӓ oOU>PaDG2CC?c48BSN MoB)pXP&ӏt@KXGz:,z/C˪,]8̒ض1 u{OԇaUZrsjm;ŏn4S #GF|17M2? ȷ&?~ȷ3'?nʮs{/Q>5{ReJ,2Uen(-j-wHf#q o@oc!zqi!w^`}CMοC}Z:p=OkP0pDG-|[E1#7_ѷYF Z!vmܭү@ 6.mS Z 2_}K;*>'!l_y%B?[~~z^'Ca1[)S 8"ON)B`<[? iW*JP+<}2Ӻ-_yݑ o:=AGA(?DܳWAjBvmrc@]"% |>X> lҥJ GCGC~G5+U_;jn_3?&\] oʸ˸ ģf%|CpwD哛>8P爮9o$Ezm/2)==\~wD7mƬ.^JɆr~GԳ4@#m/=MuII7*?_&Ist(a$dp%1}Z&rGw֫N '%> @Ux0 R.xj`O,DPC5>=SSeR&FJE@66Ŋqt+^aLkX'.H[tezZC-ˊ ҃xppgxsWAL_9u4#_ܖ1W3& ^^wlOZ&n [.cGj"uIVv a\&@q947@=_3 6vor{-rY: s`H.媱Uwk P1KΊ gJMR13),p]A=Qo?nx}O@Uy7ԮX902Avܸ. Z;kƇHX x@:U =(J/1r_M|W[Q@~k ӗf6'W5i{m4 *P-ԏX,َgdDuV4 0{$%w%$tPӧEj^-4ea]:^BUD{y=\]\o_J.Ëe&wg] mY~z*5! 3th@.I w*UPi%'_Kbq^c۟_Ħdho"GĪPHA+3hLaΧ'>3!OOJ} K.{)қۿX'0/ ,^l[xN4kHf |CR_ۖ|[OnhV7iW?@~I+yCɢR'ε>4$G` P Z{yQ6G^t#FEf ;!p|Lbg>eFn[}9PSb 2W_;JIQV}hz9buL/[_Ywpˏj):a#.g:.{E |*U(|AXQ,޹X77y] ;^~fK՛nid_bҟf%^7 / t+t9 ~9`5jzpw`ژpҳ!g_L"ƕ1X,=%G 6cu E/=Mjg,yyȗs|}Lpeژr`zf9ɞq$@}7"."mOSL' v3K?._"\_lZie=^`vJzyۖdv<::wPxݙLLd}/pFn2 ȯB[8{ Tlš6#1y>MI׺_뗩\[O`| EY%Sx@>}ƽ{cLl=.:^ȲabK"~\AN _|R3ZuԆKep>}?T`>;N$\r[z=3X> ^IR;z"LL8D$Ci/'Q:3HGi3+Xw H[HQ GA[S ;T\¹#N۬QHZFx|+r/2.2q "ԅ"Tyu:-Q2M}ci<t$F1nbt=y`97Z 0}) tR>U|Zͯv)" %d^2D^S32fA^yȼgO̢g;x_V9<d^n?~9뙚 1p.^p/Q1*Tnʠ,΃y~!>h'SWDs\@3u1r\,;~D݃Sp= / whiD'on$(~b$Fs%qcxh+毗x}jֿ$<Ã@uo<,ƓGuSX*\l̄$=ݪvjtY\纽%FKeT<\"JHzsRW¶w$X$)#z7 Ӯv W,eLTR0SE'1MKyoi)Xg^:ί>~JʞO(?ArUu,~߰:©c URww90w`A!-~< 4ʬV&ȁb=SE'!sQ RrܙT{`.P_*SxHk g|G~)a_Lc_^9 'V0'o<\i݇}ĽuC+'5a^Ur h?q!`o@LcɎzOpLt#J.Gu=t=\f)8nH 7 {lÔ\.ϡn>'2܋9aA(*ԥἩ@Ɨxw(8UƓ9Dcpb6@ĪfLev9yTOCO NJP'+:<[_l#6$_&}m' ץHok€!&ty3O3-j `ߝޕ ;)O\?+O%VO?Py϶!6l]'}~lsx'֋AT`J?>a]T"t:Ix']kzR" ~Pghowi:@C\vڿ#O6R'Y"fB7hq!`qq6c*Z\nBz""\ϗt77,'}2ksڏVmxJC eVT7|ZRR9$eu!:SK^+P@G}i*k_W3l|)@jO \wөq.+8VXxU+}c*D'I.}}pV[^!T Ixޗ >){o"aarBv`C {v ޮ]W>A.?eRWxi"o$ΓQ{OSVZj?%pmqqز[\m#{d?ۤ"ȷM/ރ[u֗$hq4y@mz\[22!Q[ן6I|IC-/-tآb9,ȳMfMhD;6\.|Pҝ)#}/r~!\0߶ȪP\g|lDXEmE',o]0GΉQǃ9,=-Ta'~OQ+ltNonO_,P>kD΋NCe<(֓,%ziQMW!˛Q>DvP}0ֲd;Ih-`3U.)%%ʖ|dI XpgO9>9r^qXx.yg.Lݛ:{T5[c#Uʴ.?9d9h\Zԃ9B.D>=I1}̩G *.q3;T^9PvL 7 %{G|A=x[%g`MkJq  AQY7,~x!>~{уy҃@=UR+SZT31)` X=qw`f(| O?zEw ͊؍GA=X|IÞ_6ݻK6]6!p֗@m~O3V/ +^rFetq ϠsE3)&꒪ƱKg6xnO24j~0Fb<'9zҦKbr4Ycy&E'H4#e):E7rhh{Q^a:;,:S84Px$4ET̒Wh#{l(~<ý1EM Ι[-.-qe*P3ɹy7q⩇FԻƬ5n~}K;tOJH V Z@=k~j`Ԭ&mnKGYcw;FUe V]W:= TNk>q#t[oy^*N酋@b>fQx::R\^} U+ԥl8kKg/^]. (r2NT u@ijar:o*=Ixy,|9Ԙ[6hF3k(*T9?4Ojl XS?Ϻp ם'1GM[lRvú: Yv;S=ԛ~>'1j ǃZ Oi+qx41~=j Nj.k maǸi+4~:JaBɟcx|y[}7"O<{o~|x?·+$]pg;~ ̓~R|'|eUTɊ >* OS?B4xxS(tyG2xj''}‘S^5jN*4`xoqUh<>tw_r=b%{ \~8y-{B;@:pv\]˚wl|ja*CLDH4v\b¯  V/iP>Ì5^BM%7neSQ-P~| ,f} c}h$mxvD<0ۡzaRSsDx u$ uT3tBzw#^Hg6'SuOH_Ǘ}>4Hv\K>+-ӕU|F7[i'6#';ƝUSJB{VW:; /b':)J%o&kˈ/~nu&z@@O/ YzS[ҢGV2z(\Macnd0]i{K[nfBAp7 WZ,>R`HB^)N_'!}8  }uiwόL;yHW>H+tvDB른mҥmeCO*%r&|' گHwM{ֻ2ӗ5.w|ryQ.'&p:7* }j6^CQPux21q=iD:;>+?|ۗCgтGwZoRAꐘܘ`:z{r"8*}$d}OChAG=Ž+PrKǶW^>Z' be5#Sjz3F'.p@ 8IRY%?,=f`?^0 coÀ_"i+ ~f|zp z%>YΘDm+ӡ}ɵ6 ]gQԛo /H#/gYrhh8H\pO;W*ibt;f2GXK Ebٛ|w>?0CQԯ8=it`_Ov^!?+W#^J[y.̽tHy{pӀ\P0:8)zŢʥ/s6&c\_;`S݇zd̪:H Lh|ynKsu 3H\b5ϰ';ךxKK|)<@pSn"g^uL|=G$ ~)l/TLe䊒6={l_o|)lC'{qZOAxqDk-z6s;/>"Ma[=2y vOtʲ?'N~Dʺ9"O05Ѓdp @iGYb<~_x>5o^.4o/J;@⌛y#Oei9#u .-yEv\ALN1%)>"uӉ"E*E/=䭐RA"2A +,ukݖw\# j?p/VUzڣڠooCLiOWE:KjgӉC4>NcO)䰼K7Gp=yO iИK s/6;Winas|HfN? dRs;|R+>Y6?n$ iE Np<'ӌL鞳2\[FϴMO8~`] +.W,I~NnL=m2'dP($nQ-4;7rTx!qZSSĮBRjd?h']%ozGYV,If3“/y@V2gI̭ $˨KmY?f?ArQ?z6߉5L> o?gpN(F|%SEV^K(TL&@Lsx:+}Qq1e|\46BdoM r~:&o]$ ×P8?’اE=+lK_vD̒#>CNP}=0ahjb4-[b܇ϥ> L]**^ =macexofV[%Cɞa߲[tىU\ 0faw#'̣f.@X5G_Dc{C:,'^$ȚA`$}AAs}Ed1GHAy'Өh<@ɓ?ՙ[u(qHnpKہsլ}{0K,\t@k'ovzOa^~3Lh뼁 LTr -i]UmW ɝiA?yXoTosS:wT}ҭ_s 7gd2#s} ;-xz*9aN^9u\AօYttC|kc3\{3-p1ԫ[bxFWYY|B+ys$'t8x*y} BRT'HmᏦjOj^ޔG#y?)M}Óݓ5Jg~72jZ-͒ShdrD}~DȖkKk+ާׄYᾬC2|9s+ƅzG !wZ>;F;h@"ɋ%h`Au@(Պ})H?;䋶,5PoAJ35ٟ kz|[Ǵ XvgBlW$P\T+3]3sBz+ bu( .п`ZN3^.wF%we3.п.킰O\ڥCǵz@TӪ 2Pz{N˃aVy#TIX 'E60N _3ǹWN}+* rzSBP 8|2l[&mNS%.xF=D`~u6A}U }x_gp9znl84/^+ղoH "-t np H7<"ih+ɲSq5cxF88qQUdGWt`3%B~l:(Gv7}wxک k\E3ϭWw\=oj 77mC+OAҥ/J;X{>ؗmJ0g9.#]āuX=Pӣ_||eVEu!hlH>t\עȢ➓J%Y-z6FaKͼo[O5L<DM{>D'<ӵ`<yDVd y42y/S܏l2Fԡi`qڮy/I'|o퍃-]tckQ*Su$"ỷOdži.2$/O@/3Lkam? M}o} #]vw߬qV-uʫ?7~+u$iɷ/,:N`?<|w-FW"+uh툝gcꛉe 4S|x@_UYgߛվ]?9ZO%ڂk߉2%P #.K`Ǔ[ߚ@ tW8yͭ /O熷O葵=OjϹ^k:u4&ɓڣr|tͻMU0BȵlN/^ϴU{wt7-,Nr+~psS pzCg%~2Gd;3[ qeۦx\*']qujt w1!HƙHfh̓S/1ϒ"Mv/ՏŃϙxuՄ} Z>Qa7 8sOe^p!A*'C˶Z\G ')@*aA+rzYIbs?I8I~X3 83<_r)@(b}J 4Ɏq~Qj#{U!?F6_VY/FjSP¡I_ j/4.x{r7-QI^~/>鯏hrO! ߃}Ns:®F6\ʎi8{IiT"oz[XSʭ?w2C_?O,cWں6٪w ϗJxΧn8b? ?GuEnDh qSUs PqiJOc?zJ112S-ʡ۽?:mL,ecUnݙ-y潯uWL^ 18ϙA7ߎu_ |nAXR}V#gW$3p6 Yyŗ]i2o[b ]۲]Np6-3295j{2/'x`iЯ8} BZ;>_^&0 aNM;Bx{w L[|}hV`'#> y{1 n|\1~<{nv -\QA~F!C;[^) "IhrkW݂R:r}‡z~g֩d~ /$iJ)L,Iro+X_-iSĩY߽haJ"z E0rnxQwdx9ZߪZRZ*m[Oz"Q=j1j-Lȋ6N!b-sk۾LF$l\aZYeemʦ$F[xR wcDҙ k>~SyDt)^#Ӈb~ӈcsG£7(KW7H vxg+L?4(0JfC\pC/,˶UL @jL,lxWn7Q*Bu4~?H }\[VYH}_[1.}R?Ь`Kg~Fյl6)PE:2^<);]>JTY#U~)tM$nHg E~SoygmRڵT#fbG_y?\7m~rctxZ;>>8Zutu>aXy:GcٟdK" @xoڜnOɫɒ7;Dr %t8D)Tox'Ar׈. D) -}e_m+G H1t(~Ok$ۯ6('7EyiňdL@T#~D/T,%/N1&8#1 9ٷ;^87~NG` !jW('l,#UCxZ( !o;xLjٕDIhOb /`Nо4{ N*j[@G l٧Z Ԛ%M2$^`LZ2K>F̝]i-MF|H dnWcvƻEmjvv?Ϥ)7L>H\V_n8AjWu-8sVM%H"`z&i,Gk<-:3g%@MS#?ѭzEYƟE=P̠@ 5"9u@8^ xxf2`Ml䢠?mK {fբӏBcxy\L{Oie*-k9g:t-Kd 6jI nY.VBEe.B"⊬yDqDt[34sb~}r~'O| s+жZ?/c,Mܷl`JƒZico:nh15?QuofOnal1g0s] SE_zxyfKg?N=Efh1>S|}my][w!-߯~ӸwL/9[967Oz=Έhf5`2 f29Dc-<yd(T.I̕ ]VS`&8 w:; ܯ REDme o/?墸@wpbW* 5dm^_u󭆜ZcDvuv@>\iCܝMeG΄AfT6¦Ox@C4^^ :ù~jO.v[Ѥ M/o6XY$/bN6kfRţi! L U;̓^${>];F q Nٗ \ռڂ7NW_Y}E'˺];]vy,t}\91K!i+O;wO-yR}`όiI"g;oT1 uOœ2l̗Ӿ<3΋ٛv=rwk1TC c(u6rh A-Yԋ?p34x206ϼGAɧlцo'T_Q늊.& ^=`gxȝ!̒x z,2yd[$\܃]ƧzEfjw~eߌ:Z,k0~S[7]6vZu銛X9A;/ Nuq ނVC әHFUAӼs}* 2|WVy.C ^W^sm-XD7"}*,2/yz>Pi+\ռUr^m}AE'xW6ʮX`8 藖GZ|6n zPu? i^pxì\[YckoUsy.$ _{k^i3-v9zy/WD-Jzs=_8\MkO/O/ ^ -NW 10]Y%ܪSb??d*Kڼ>6=~az;58,8ujgі9yy;p?d |Hl~A{dz|ݺd|.?s!!u>}&J/jB}!*hqznΛg9׆jnk :2x2:Jlu]M:_zEGgtr~.gq]P겳S$/?Qtۑ7O{bxB2>ioCuiةMHS96RM^n|a |}-٥ΗPYLk15+2ǯYw>InGca\yϕ‹͉6s7[z^Yޒۅ.?ΗhY(,n}nM]ýƷÀsf&]'vT[;7ĝԷiU}nw3FݺOѴ-0zxżc񀋍iO߹[}_VJ6R)Ҽûͻrl͈Yvwм-Y 5H/ϏF g;xR. 5y>'/ fp-ui.w]g%^o6jAHa.Ϗ5;"BEGu5m m犅Uv[{nZ|W鍯:sO-r00`΅ý͵Jr]0Fe@.!{vҰW vh}^uڦMsZt6.cKi#NxX/UtZ`eޢ#%񦎴5Ie5ׇ\6N/.NyKGKZɅU\ >7q?'MV,^4)@6XuncdHVksɡ?,teq_s{zg;WunI'JqA1?.ԴO$" LIa A ZkkخCr ~խ"ι @ŜIQI0% LSHүOalS+rhaۇϼ[DAHH.4CR b UimdI !0<{n9?X@gm4ڢGI0hB0@ tq\U0CocVaovЭ/&XBK0\uesedHo+Sr9}H%qIDD$R &pIaİDB b!<}K,_&uuYG[GA(#e RK1g(t(mnvS7ڤGasŎdpr!0f.,0Ҙ!&vi%}oyjTn}@)1(L4 'cG! q eD2(PP*&qT#7@DlH+y#Ń' jϼ0xu=p-Fp60c1+}, Lڹt}2'yrWtp뇐i.!@!׍$$Q(UƴI˨Jywd~x{N2`տjι׃wqv Xïcjڟ/Uh\FTsP+S&$v`ɨne(7+IJ9I&r§(نN?ܯ?'.{}?1lz/ zdnɅ5}}~>r{LKO 5DyccAܲ5s VY埿q,FSf[N=S+W˳ݟ:|;^okXTd'w{\庯|u^MvU/}δ9-eQWU7=JӾH(+8c~v@PպuT2NJ3\ϓ&H_'vk3dxe3\Xwh4"}C+"\o:$_軾mxY"x31CcƝJN9oPrY<.,rvٓuF6qorQ "ib0yjOq7Ƭv5V*ȐiScDsy! 4Mb|^`Ղ&|mg}K~"inʠUe 뷖{m2Y|5"iapV?w]/*i؃ ;ۧ{:}/"i sqwo"hЮu7n۫fy.5q+C%.iNX؛ªsLυUJZ0h0)f2<SG ]ɤT:kK} U,o"lPzy .Zˑ+ny"jƐ%W3aɴs.oPJH1DIbCLi+MC%?~q˅۵wesJ0^`nqϮϪ#P"Y aCOOEo_m!ڢx340031Q0M323ILK27M45K4MJM67121NJL263OJ4IN4`8w[KDo'~Qx`>u? 'L .Lܤx340031Q040670L45I4LM2MKL21013H4N425H21166M1g0_$߲=H}9]!̄4SD33SC cTs43K# ) 5rmTG4T,x` 50K401006 (*-X*wʦjϝ긢.fB ܯ^xwx+)JMU044b040031QrutueXlmmAṃJ}G;UTWRQຳyv;slzC8Ti^j9XrѶ_,ٟ#4'^A0u.n9)x340031QH0NJ56K27N60HILNJN27KNJ0HK6OJ205gYrm٪_s-x`>u? ĉ'L Hx340031Q020J261KJ2HK2HI2OMK3NNKKM2N67HJLJJ1201e vObI<*/{ x_xQ 0D)6ͦ "xO-FbEo0 Ǥ,ske[Pn8R,EpD?g}^3 <GhYK8ЖDA);gݧjp4-r;sGA4ۺ=(in7IKFESNx340031Q0M202MLK2H2I44&F&fIi@e ?zY_N&_~q s xax 1ENi@k2 "X$YW0YcÅszMD08!s Xgd::@X0Pw"F/RUzmZZV}|/o5I!1z:vUim}/> F-GԢx340031Q005OI1144I57INN4L175H1HLM5431O40NN23Hdk_ 䬛׭Lk;yxwx+)JMU044b040031Qrutuen~{T}ǝ6^r"(1/9#>-3'Uug>6wٞOpҼr_ʧ+O\\iy|tI/8x340031Q0L40H606L33LM1HL2MK03NLM464161IaПg;)`*V3#/9/xRx+)JMU0d040031QrutueXlmmAṃJ}G;UZWRQ°\erw soT%Ԣx340031Q4307L6L21K05I2640MM4771NJ5K2L-b fx5uۦ0NJMfx~x 1Nۀn` V.`.pa Ô{StlH,_9$$cf&hXQ*g)cV~p~"Q@JnZuӶL 6̸u=-x340031QH17HH343O60HINMM04066HK03HM55KdX>M9jƙ?V<<j9 x_x[ 0E*fդ "W0-Ft݁pS[Yx^ Db CLhut}8X*4ZsYUA X3RM) s6輢Mរ&Jm;}<\@ޏpĀv?jۺL?HANТx340031QH4OIN0MN3307I017L3IKI12L3541505Jc6m9GUTn> x7x;j1Dmdǎ|M3`V{ >QvL0I?!4Z=!צ8F!rsQy9]$D&l6A>jFWҵ IKNiZ%S  U~̽>' w [ DGڡQ-M>dO}\8g_ШoYr`x340031Q040K6LIKH47L6KNJr,L LMLҌ R.\nlU{O]k}:x`>u?$ڐ޺x>ebpf x340031Q026642H3KL17H01N03LN5J272HM6I5NIM6cXMFUO,Ǜ_]q!i2Wźx`>u?$^OXW Yx340031Q0653NL5N34M2J2165NJNN5N452OL1H4I3O*cW}pߎMW)[- x=xKj1D)zUB-0uV9<#+Wu? s*M3x340031Q00040H233I5I546L4OM45LHL506H1d`.\%qqc~Q xRx+)JMU0d040031Qrutuen~{T}ǝ6^r"/\F0|Z_8]nzp#sx340031Q0L2074724LL1006705H3J47M37I5637L4bԜqEzҹ>0qU0mx`>u?hC opg<21踰C 5x340031Q04NJK3740347566535K5KN5KL505067073eogRpwc[_p.xRx+)JMU0d040031QrutueXlmmAṃJ}G;UZWRQsCtk# >-/y.7 Sd! x340031Q(HLM1O6KLIL3346H30101M20411H1LL4O4L5L2L`rRWd&8nntlCr f(9*6!ˋ8ݓ}}1Mx_0 @<0Ƭ#ÎM?߱ /7v}-W'=z|ִ3=Gu `\; 2/KKLԍb5:kxzl݉7z1?a=4kںŞy?Vx+`WƤ6Ũim`Jg=.'X300.W@< Nxg¥ޮSٵ%/u sIι|u5)L;o-cx ptf```bi|sr2h_ܵal3  y۶eHԎC݌,lEKX,ʺxC7+ͦ,>?rJXkGF㱘4yZO$etirCn;]Rwy}sIbe3κ= w3Oh߅rcy.Ӹb2a_{6A&5;ދ(Ü -&˄C7BMvify-pzeKY~*YnKI'Sl_{m>+>Y|ZR10iWj$8=+u G.e\p3mGWY[8#Sԫ2m)p͍sVL 8})6=9=tAB[31Hd޷x^ڟ7΂K]kK^׺x}= 0g+q1PCQ%D7XlC jǥO*uF>n󢤜yRiFsTL6;)\HrbU m+8N }#8FY;+ǵS&/kMj9x;ŴiF;F;xSK)MIUP*I-.LPR&ĸ\=C\C422KjSRDZQj&g:P(5-9D /JP+дF$_RTZŐƐ1X.1I8xj@S܎#b(]EQJAtQ*%LZ3ILB5Fp;'s ]3 +qƑ~f?j~wYm݅bx̕I[.]2BlL[4cR^RQ/8ʤzf+!HK$QL ѫTPSo_tLh9JhmKhIh%4Z7z:MVsy1 )H1 JEFUSֱPb[6IDCh&O?cAŴ5,_y_)5 hK%2"zR Vo>8],mJ[x`aVGH#Wl6LMvT؁`xWmo6l FE6)ewC7`^dhaMM!" IAzHJa{{HUbC%e\h{ZiL5 =OnKFYFjYmRIxf1MdBzKBRrNTLn*%deRܣhW?u\=$Ūu-՛ŜKʔŨ\s*m-ɈR5^ yJ2x2V}zwyq{ߟ=؉e A3-D ZDXrL( =Hs*)a`k%see)JČ@/8(7M^Ͻ]/e`@UHv}1<#}.3WPTdLf?y_,F&{I4?3[Mս4i{Y Z !9:Y4^ew*V/YQ<ᙨHq597<8 #2A")Q,lF 0Q,9&;Fp[!j+֓ XC+4Ά"]QoRjEWM&n]]&}ja:;[m lhG40$"0]t+"vFfFۆn* .8cr\l@d| &mYԜcsЩtoGi'CA"QWg:2ΰ _<=[`}O]4gK 7"}{M'\~%3iZ4K$]M2!"|T׷ߓs܄L;axoW7(†2@_Gߡ<4zda"͞ J3.@gI <m)xB\ /+GT}+}Upq]$+ OUh_d-ݱ=֯k3 l]ʭctbPȆeGa],TpIQkf|pV_asX }f ㋿̎Gb}EYb([ zGyy=㌫/^ ^6k@8";MVӨw+IjK.@x=F DrHAUEVFZtl1O8km.ÓE\GTu,֍_>+(xVW𖃉s_YqNNKO+)U#C Tp"d?AJ܇Ա[ cs RF/ 6} _(T\iJ~^I|rbNN|n*1M4I?YxS]@}M*|R냱1&>0Hi~{PʶJ9sϹܹ\"k0VX8|G{4cU6@jb*ŔL X |KK^qOvF9.w┆{Um\|/(t͖8y۩\r_SI1;zM+th}u|rmIJNCI=L±㒄755SFДePV1L^.a$ڋl[X^"d!kٰz'B-lA; *UX=d!3ˍWTDozwPIZ:2HaFw:BٵZ܄WGgov%9ӁF_Ivq8_:]"6x;7Lt9HkbrMRa: <ϥ7S FVfqxJFN=蜠>?01: &xYmOHi&1 NGD !UtoWYk{MVKv~38CޡVXwfg*t+$|e?Ԫ/U)Z}qzw]YMU+h`/FQ0-4fG~^~;?~?y6k+zaMnd5qmuSε?8$J `^[Ir~VP~s imմEQU*kQilt "U0/k 0QtҪT+ʃ>49?k J,Q]=*W46th.h%ϫ>'3~kUo%|r"+I4 j WA+WNWl{H\tjg v- ]c[-cL*3T8ifkN6u:]qhfۗzWZxQLA?"n7,CIj%hBiT=3S3v(Q?) 5O*Ԩ WfW'/@R8rBIҨޜ_Y;N2pxm(œ…!*CB,mxrx٩RSmb=CchY2 Uޮ֔ͦcݸ60jɎI$:Xךa/_v'/Nޫ-_RX| 9CƋ i-  ȴY$Y2C8kv4;$C맫H~g?:oR"pNxkJu7yXQHOVͨR?:xu!*D!ntWz T7s;/KmہWQH&a#49H|XT^rg&jS7h}o9 a#Cbu9H!OGcT~c| 6hz1N[业 Ve]b[.e`(\Md{-Z"7r^Ow>k<'\AMϭ4^81gkw?޼{y2a2nCv: KŠݤ`m6^3fޟ|ԇle1G98=2~O8UD1O{{d! SqbLi&]֢rKSX(TW:ӐMS5s٬&ш%蛲ctC`?N߽\ߟ~%S򸻾7>y<}9VMьiYtUGeT5ϻ*ƪ}rs۾zNc}N~Lҿl~YR[~- 0l~Z>gnVWi`jGG5S9LHA[lB89K+[NJo"ss ;MБ/QzS|Vt`AͺѓћZ!`E),70N64N%8׿5·G[ b~x6A{C6A{Pޖm qb|('mМz&+dߊ2juϬRe`2oe30pwky\fw@[3WYq]RQR੡l~,̀NB{qtI P @NK* D=- ik \10>ОqǕWMp14M̦&-õJSn4Msz|/O/_]l޾obUm0&G7uڲ\ Y;UU8eUYbI\A >s R8A*U(d)ΨfRCIjz3Hʢ50 I{K񌖠uIxyFW+Tߣ|rsZ夑{2)CxQ$֐L靹VLz<+}(:(6*)I%!;o$i `YL# %%ϭ[ʗ(/Lr Zc #IL䪒UpX˰Ao̅}y$ܛw:Ӻ%~컬h3Vw}_ueȆ4_ U:)Ul=lP! F.aH)PPSM* z)@`Gr^LZ_T+L_mNzU`7[Q{:]kԦ;E.5vad'5hYTA_l}z/qC.;Q!052|ֹq(~`u۲>!mղ2oc,+Hi$O'd<~HB[,IxP+Um6kuV8Eʦ/mL~ӪE!fT q#k-9=1{ՌoY3ETq,ھ*Z JAJA\I9,Ҙa+Ӷ э]Y:yU#D9Y[ ֎âW $ \w0l:H+Eoc#Y:8 ]o!! ˠ`8473G Lnšs(p隀ЂS),X4Vlw@8ٙ-J%LG(+יִ@|CjxtTA~J̐6LcJ#NXWr7ot0X q"N7F(F4 AX0"(XP6QMچlH!YE)GG?Wt(Hc+Y+ڤJzil-Eāa:L0%hW⯝V%Btb5K8nJ69r_u|2l7\) Pjo$yet+rFh،kô=MLJVȒ {0WN|יLU%k|D2J>M_欩:kYcr\U`wO3jniM :V#7KӘR;nw7/ӆE>2~}ϳ{c"=Nc )"Puur1yuL%:ʛz1^/[ÐښytJ0UjF:&Mˌ`& ٗ@NJ,b,5ӻeq\>w:sۉXP^4ӳd7=4 "s<~1y +nag\<n(&Ϳo`2}h: I<ԵGם5Wkۏ7W?9loW7Wo6?\H)B ӆYbj2@$&Gy#FcϋDU@&(a_ID3DqQAeTZ>T P_!41/lq ~{3N![Q+E]BKŷ߇kc[ۑ?tm}7w=9<R(M:@>!"7A]mzku.t)$=KSJP* T zҦz; ?!}B/ P~@">0]OuWY>|Qz_g[[rz]`2VLm]nx0ؾ>P\BHW˅jZUO?і+sm8OK=SlLdvs>^+YM~OLڽ^,&LM=Um~=~Λ㟽{sUƖ*]Q4[V?:'wۥu)drn&j,v|լ]Z#MԵh~Ѵbi̟,T}/ڪB;ê[V]6!ӏ4N3Q$eq`Wo)F5Лnn;kбlMNQ=w55 ( =,rRj#UyMFf 1{Yoo?>z+F~S7Pü7=x3ϼ23g7yN(= #Z7+1  T4) -Hˤ"iوfiNM}i~9)DMDNjJ~ьҳDgC^9)9FN5*9 "iuNRJ *]!mQRZ< k`?&Қl)O*ٖ"ui!7!mMAG7$hD:ihݰ`P@N+C.eąOaU:-Csz{y"UwhJ=qUM!?^»D,O#YDD\D9j\a5G+Ugonܾ{CxD.hexLU+i }fJ?DhbE4~ ro,Ƽf"P-C;Mѳ?ѤPEq9׫9m ^=Nw! ]PO O&X~\q.f }'> 09$ W"Z!GY~蟝u8h F=+oC_$%m?c`lTr*{nAp f@ᅠtUBܑW8J>x)?s9Ht.1#eN D A#i[lH@5,Rs|bpt2ɂjV@JnD6mb!DA9EJ\TH,tRpm:UL ,&:$fP\DP!n̬=RV) V/]݃r o!D; šG [y:ީ+&x_!UlΓQ.XG D2ԶI2\ܗ=/<7>r{ OX6J.v싗n䖨S9+ȟ0}1כuO2 }-1+,}'Y Ջe)4<WL^8f\._r_NTtW/])AP!)2G4: IM|W't7ʀ 4}K8wOxR!O<cg1Vhi h:qWpkx e' o pAi+RS`=.T`ơt72 S#vIu(F^B?p8#_ qX %w*NN6}E@319X|(B^@v)[ 1hb/hC*aAdM؈ ףmF]]n/pcGds ;ۀ] iA}E⨽]O F^w,{6Z!-l Cc G6)J$X_^Gn8fP=4-!c^IWtF_ Ti-bA4EtFmHg(7.Z!H˂[r#kZ@}^<th?eu œ]DԞ^&.PM q >p5,+Ӥyz %qHt;ݡ`}3>sb!@ x"5C1ZyMmQ! ?P6 w'^5B(Q  'DV)wo^-9(L 1@ﶵψtׇ;Mp%(. !(*)EGuUI` Wg.j P%hv!Ļ ›Ӊx+@p >9尣s;܌@YF|}˅kv-S*cvs:j MX#GZ.[>Yj^tpӺW2\yz92+טi 7yw_74?_s&jR][20դ~?gTC~X_f2ՋucMul`"_5_=Pw[GϿƢ^ڦ2N꓋W{ς_ WS- ~PS=z\3#M2<(6Bl8jA6RN@\\8½Yi?+|=8#qtM?%r`3lX6RC."s9p?*\BNq>z8|V*\0=]Sr\4$\`f>#C8?#=X)wAu`AHxEF"CD 1  5=siB!!a6FL , 2}gĈWL}U}֙_Ͽߞxx/~x|Ru߯k5}ѝi|ѓ>U}U9vdz,oI~dz/T3ȜxN2g35yNd?FWN^5%Ð'9=x?˜N7csC'9F2"T4m~.P4&`9ZJJnX@VeÊ)D>/|VC?"pxy?$l;h)d&޳7Z P b%oՑPm 0L] Ώȴ}i7$,F\YjV/WQ;ΞHݩqA>e(thWIE$uO,.$~@M joNOt-z[=L5|I2SIS4FHvm"U[T 3ufm)-I6HrQz8'n+nFlU4V*.xA[ۊG ).NiU4 $.wjUToĠ#y>Z(ɹ^Rk\?(&d%"W\xP06#"o2'jGմ+t paK=+LP?|愝1+(5ؠcAOʒ zcuJە@XibX\ftB)5obT^ӸIT\lJTYTTЉ]}_S.Ehjz)'e\z=~gvD|V[nil޵r_?`?xWnEVԀZ!%QUԉԎa\4 gY1㺡!,7\'@H ^1ggqKl)̙;}sدvCLPɲ㒢dvuMmR1ǨĈ϶hke~IWv: XgްP&e>r 碭:9SZ+gYN\`݉eiA_0(s',hu)J5iGF<#D.yGk2g3c`Z:w8t@\;AHo.lsGecqj@4j^rp5?рb)9.Kpm\v[WA O1th d])j}7nPGf+3f+ʯV{Zte 6p'1ǃEYpOjXfoFd֯j.Ωzr t5+fc}=5B /s<t5ƀzj-h4X̗ftskjA#* 67&Hj+f#=Wh?ؐQ^}4iAã?CJ}YV5ieZ i= pT햦+\lSXp45Wwơ:z.UБX^4l=ʏ5 F q;~B^G_c2)w]=C_A\$-ݢUn4mݵ/u x{wZҢb܂T9'>5a,"Cd/< &2nTL,*WJIR s@5LR`1[Ĝd$M̋E8!iE dd4XxTێ0}W [miJ< (M"KvWwvs .~S{Μ3gpgUBR g?MYv`Eٿes;[ZSuqޮl`}crsV_:BHh!7BbKaϹPgp9C* 8`û5@z&߿۝,Hl<Xs'!3VdV̪`8'gQ q  quдgVd+YldEI@3%99u^l* b?P^*` MJxUkOF_1=(+nĢ~dˉ~Dk{8mܹ̙sfȗR?s/Tl(26fT8޽_knFf:HTe+YDcS &0TyV*xl1TV]>P g)xe7kߠUA}2$06b(Dpz.~بMύL:hݫ,#pkz;X6s]r(UN_*IYZ5\'6nzNzf><Ï%FfKd}g9LfkJUw^p%kjZhj== ?7'c- UbqhCy Yd*l g[@2ǃs_Ma..Ow7ǩ} tsusqk,w! "ߧwU&žj$̫.KEOkatz/KW8px#tHpZҢb܂T$%k.}-.ΉG9'7g嬉lȨ99QHV2ssqj)&&*$d)$fglb2M`r&$^F̒x Z)I\^fBf SZV"bY&xjHq%lʊ sr5R4A&mbU7XU9''dvueY uP8]̲,8WBd~7+Bq'NLg[yI5諢D 2IWB?f38?sZ.fz[UխEK+0tϩTd^{':{6pmuJe"jeDtKwKT`,4 AAm%Qud`8d. a8GM)_ٷc#8b:heHtA2.PTKY*1n("$,{{a4{mSޖLeZ7IBҭYӆ'j \(HA`oT/֐L'[@۩iа^!S#BbQ~`q#xA=AC9FxSn0=㯘&&4٦G=T]U4=Ue`n#l,KRNü7oތ/e}paX^캺 hu,i]4U •0K0V.Dr)UOHI$[ {i"%O0SBȧ헯;~vOj.M 4#$Uk,x0 ҝ'2␔/ǽ5C<}KdHx)E5 t-sMLϐ;pތ' 7U`1/};\ #M i[!qBD@SNA‡1+dyH1N@ncU[8`^[wcR `H8~|;|AjK1aY fAE%9>P8(Lԭ=Ea&GqR1ra#YK뚹?#шI(Ln*fQ~ُhg_\QK|ս"ZFXZִ YN/.@͆U[Z 2ef,gݲ4'Wq>)9,'ſ⛟ ['mN?'# v}N#N+%HVJ-49nĞB8C%\ PztEЇ_{+8r|P ]ԓ˘6HrBlNjK8S}YjĈ ߑL>.%FԮjA(H#@D+So]t1\`vn2LPTwk 'F)8agB\0U8ٌx ( SN7&בj| X^8&; F|igfgEuoUOn}+WGʯ#'==tAu9zjBx}Sَ0}tQRuI#j4TTBP3َ؆NW /q}.ǽa③Rݜ;ZwT%#vy[K b4zu>7x4͕mJg\մh:hTe5Ƴ.&xr8шQ>9RPX~ !g>Ry_UT,>-p 59P*PjIQ*72Va a?=٦C#DmVàf*]2 PPg`d?)~voWU֔&%(:2?-+RFu5Jg2(#0RX$(Ǔ2&h r)Vp 0K ܊{e"Ra# HsJ3TB݈y-pZ8X 2nuszCc$cd΃"#ڠ|RG-M*_Z>UB4Y$_3YӇip=a87ѭO;usZr RY&JLR9!qQnoW~GX=HВW"I`ᴈIמʇx׃t0PӡCwL|=( FSd0ӫ&Wl8mH ۧMq K,C4G2'VV}ΜB89WT냩9YO/'so|ӁFU]G= Nf0{$b,8Jߔ{1^{l@6%9Dx̗͍5& <i{zhhj/x}Z}e 85bw 71Z1c UiV < p'KoSt.ɵ^ @3"wdF5#*H=li(VBٽb ݁ aPq,aXk~;hTp| _ܦ'4[q l.i5QAVmnd wGCcg1n}wQYojNKS-ZME^%cY55×ҙ(odA*~XNN (OA(;UI#-?>9'8U#-Ev/#d~65QNEE 2/sr=x}nbvBJfQjrI~QBjqB~JR3n3tF=N T Yޤ.0GQo:xBLfQw>Lz>O{~*e%Ce' JCvYBkqZK4 `ۯY63H_PN~vXh4@Q4*V~l/3*Ńt8϶;tOgMO;\lJ1ERFX)0n!Zu.֋ @$_3;i7ƒ~IӅ'Dh=ѧ?\\ao1}4‘qV$Hki֎ !&gn |gO 6ث|dL-Yt=q"hFbu8^ZP Dh j8V9=E{.D{ ,"`DU;,Y.* Bl |'0ƨR09B|}bޢ&d@"S X9/I3Bz)YR9V"*ob4j)^ K .}y0kHr5ܰL²/=+U%b˭h sM'Rl8ԉ#)l5YJ'JeRnOva0c \xYc&Ҥ,P_eO*C`.1/š{`=|t@ΠȽf;F<2|b?enE?]/woHc |ot֬⹻%η>AvsZE݌^-Ϙ==5'QH/|s8XNX^pκs^_֕*+k g_z;nw17":Sg 3ERb @(xNIAkQ цJIKCbXA\oEۉ+@Rh lD)ʳbf) EzӃ0ʷdQ͒,![ IT]nTZ.irYj=R֎Ԫmc$ vQt45۟m~84wnCx,OL U1wAg*bh8~bbߘFMhBuQ 3r/59붙xVmo8L~KijWn%څ.K+^Reؑ@1oZmgfyp LXH@O9X%3+]B댘0\jND"*\q[Щ+nr.E Csey n #` O`}g0)-L$LO)kA_@ JicY,TRa+{@*!z d-! ~ 1j.R 4&(~6,UBOuIܯp1Ng\}k%V[iSMh!Bu.xlR\;ey!q[aq0DnG~p]f\γUh<.cͲ'+ٮ91q)"-eIӯ)tG;wGΎ[k( DF oWL # tԛL?.4I1?1|l3xlu~ 2vmB:/۠O8cޫXΏD֎R&U?;T IHABٺNkǥ1\C -۟P҅F( (-7&z.>Y8gGA 6<4j7q1m=9*j *hWwޗz20[5.,"@\ǃzw' B=zDRNhla#4:(^۪sR_;뒰"d G;VH}i%FÛPR (૪O@gw[LS r){5Go7k@iD *D2g-^MR` k]ȓ7BJXz,Rs}_D0;WNoبRc!$A0#N6JNU[P>n󥖄 =W1ʌhwXV,wRF7$FKqzGI{Kw:>C %_ B3oGqLn }C+:@#|a=G_ }An -qZI$Q8oM`'dtt0Eoڑj vڸJ1\T[h#lvA\MFֵg]+".,;C%m_k9nzZ/q ~F &bܱw(I4<`d 8Z$kKI­#ë ծ-tv%&e#h|# ntզN뚭߯Qr &tU@a2 tOa8 {6Ax%Y&n j_8UE ǓK@ѥ(~0aGd[xg #qoͿ0G`;.{dzcc~>uXsg#-י)1TMlRx+5Gj +J 1fxuRMO@xٽF* 4Ę<'lZФlĿ?A{tܯϋRs4yo/jID3JDۋ!N.f<8^&<D.ͥuƹq-3Uap|呶PeBi)a4 L> sXܚ(]l^AY\U?'ӓ,$ 0GIK^v$I `0kALzhr`2\ !Bx8TYimtb=ci=22nxJL҃A9좡QW -՛F삎{t:W YBFl+&xL/JխLMKMMHMζrs󓲬UzZ\\\Xx\NuVӘVIkCx{cɜ,OVxiC HSWRI_ԟ3Y >kwxcCd]?x{wZSCsAx;$[pZSC9o xi HM[Y~B)OW*O`TҲ 6x] 6.GD rd9usJS7<顓q4Uʫ&ʳZ6100644 index.hJo$M4Ш&mxD 7?b8q݆]100644 index.h cL 29vg]R+yRxõkHRϛ4]t!TJcL 3ix{tiBix <ue].SO!ܸÓP vPHx{iBȴBNz\$-ʝ skYxkĿa;gx;8q=6sԴ̼Tx׈W?WԼJM(C.-'1X(\AM`mͶ6jgbIN-/lNJjqd#gQ jL|jEIj^Jj:Ku'б+H,ɈIK/+ňif=Q̼E]컘@NѴLS@64 UqYbebV楤¸%VF`vAbIF|Nj^zIАZbk..R TR(HLIKWH,Q[Y__]R )5$$?d";i@ xi Iן8}ڶ)h(3,UmfawO/QWطC"GxD 7 Q̓k}j(100644 index.he}#+r)Ǡ%ݸD\?xV[oEVJ ]zQRJ/Rbc;vb4miDc{]'M4oPUx'~7 gfήs}efw;/_ =wZY\YH]ު@'KL}G6u'sg׆؟o.iPuN؞ԞMHEn6zı [mx-! hk"A9;|)!`Ym{  s06~a@B^dy=Mdpx[Sft$iγKlr:X 8el2;7=¾.e AD*Ϩ3P=uϰPuQb=e I.Xt|gnC~:{Y`.l^n$qy[f-JBẼ ݑ}%6k[ajM7}Oߟesw5 j|5=(L-%䐶C\BΘ7 OZm=5&|[ !/0LbM~]ZF'IOTFήi&&iI&Il?`&q $r "J$vk(\ 9L3$ЍREz¦YoWGrmk$8߇de^]Q?PVt<1w2߽sF_^ 7q=1R)q'Un¯ SLt.cc5n$lzd; (ȆgU*v`.i,|O [znvDq _I%%o%V ^Y C]fM:DED~1DUq }'M'=>2P#M iG~[t>BǶ?LbthHeѫ ʯwx5|"u}Uqk8žO;ٌjNG|t@ggFq==Zf4;Ĕ|5=pW~zcɌ*0ſS?+ſys*^TjiޡddEľvHzNx! >p*d6uE>UWnkx#:Mt VY* x\O0[i!Q Dx! W(O۾ADɻFS>"FBax#Kp†70aa|o;uL xiC ê+݊38^[2 x340031QKI`XTdkgM]+溾L \x#OpBHn~RVjrI~f^Jj60aa|o;uLVx <cN"25w}IP &$ 3xS$q3 57I$'&gL~ ooPXTPRL-VTRpT+MJ-ROSH+)L-I0I Nﴤ-7yXIFBQ~~ t?Һ "rosp2+((L~a 7hݹG_,4xc7L7ofȮ 9~xiC HSWRI_ԟ3Y >)xi )7dV (G YTx! @mKFͲjTx{6bC$d~=55,; e7KTM*9YG^{, ,7DAer ?iEe/):o>i%Y'gm^oe#dxxi H& iR+uL`T LTx` :dHBdK(bi100644 filelock.hw9rfW @mKFͲD (x{.=Yj +Oy% řU% %9y% %E@gHwkD_5'TSAbIT5dC6+4 ̒Ԋb  )I PFt 6yl9ٺv`Ey9:`t-9SIbK`&ocCrPdvEPfȇm9$0 :gA\ S&+(OQd!$N8ws '3]\ FMNNƳPd,4y2T<nޫ7xi  L,zel)9Fկ 0?xD 7 cK44A_(100644 index.hCjRi9LO扳%&2x[1oCdEq~]wϐx_Lj=L98'_ݼÛq dK.\ ' l{=xɻtAͬuti&TjU($(xFĻE{FjZsMULS(յR 9Ȧ$d BIK/ɉ$$VV b-̠͌`MWbۜ2b%ڒRj{:(hZOvT)5Zf^JjҼ^QrhTOvҐ'`N]R̗I}fh) O YU,RJ36+cYrxu:100644 tree.hS*/F[=6A]c1ZkHx47i,hN _BFx"shG^FRSYB"9k x;ŵ}+m,Gs2xURPVXT2SV̌O,.KH,Ѵ޼IӵWU0#ɇis 'f H)QxmRJ0Qqa}8ڲ1/! :vmј6NJ >d.uI};''8Fe\ʩy)i\YcxiC RaW++9[{ݓ+v " wxV ȃ2;-8%E듿[[;z:jgP4~<]FNBq?[if&h8T-i"k~x˵!qr8^LZ'/e`WRɎ,ee2eeX&۱|賊D&N|Eur=+xi I֪.t1SGI P(I-.)fӚw΍g~۟V<|3hxw 8^şb100644 commit.hREpù[ZHEz3x(7)?1eXuf^ͳB.߆ҳd~%13ݟ4@%4%1/xR_kPu)M̶de6AX*J){(IRl~U؋m~ |o`n2<=sON{}zG?#w`:PIyxJkD eMvd7N=xQ񮰸"R>+<@'|Ҭ;R^T_"f(Ξ xx)|d7@5c'Bc&8q 3Q>Ť?͖:+oW.S7]Q  Y]Z-kqU&%-?1"d0'{ˤ:7b^UAgP zlSjx m}]æk&.:c?3^,J(Vo;^gS)KjKBOI jxi _-'(=sr" <x~ 8n0Âe@K+ CGkf'100644 commit.hP5rCyD+$ SIſ E%Ɏ+JKM?hc#+KޓF)J<y=7\x[:uBBN~bBIQjBf^IBr~nnfB~RVjrXao~<*x*{Bd,'3MˬVXT2Yʼnlr;2 -WSUX4Q^]ZV BA(M/QXAcY(+LKMQ(H,*NM2+< Ҽ̼Ԣ̼t ْԜJ b+#3kZkɅXgNgTQl-$w($g$)h%Mgf+)OȜ&;!lf zs?)+hi,M/QYsqNca,+LKMQ(H,*NM2T(NM̓K2JRRK2a%)9PǙB>!/x}{' sf^d^w9dT%xS;oA Ư6G&qL'[FtVEHɱa3hݕ4HtQPP/P× }+{nT /g?? g6Q0Z*ѵ[yeF_9s2TM驏$OK.iaLҘؕ1[հNekaFzs/2/L"͉je(TJ'\f1+JT0 נMP](XGmRK,cOqzso,ϋۢ{DH>20S*Y[oz-ݝ̬W;`;xM+ҒqR|e{_mʈ3$ak9`LqO%,IKc;3w*38{Jq{-U,1ٶrx.8Gӓ'ZOXB0̗;"E~*OGsLX4ЮNO(J5!fuMT~ ]:BV&oEP!f/ze^5nD)Qj3INjS|V1N%vq22߄{ x۠Nu>ĒdҤTĊĔ"[=3Sk..ɏYJ3RS2J8sSs *5Ԋt2St2St3R445E%Ey \\y'GqMQk6 MYAK"#}d454r3A*h+j*h;VsG#gHkPesk(x;}(L xi Bwo{9h3KBIjqI1ÆEmeM\ɳ'j xR |S%?1f屓W’.qB[TN,]õ:5L[r⓪'xXoEW&q\jv$'!v:R5MiJӖD+';[]w-me  bzCj蹪Pg9P$=!ݙG=8y>y_mї{ z+G E7@ ^YKgG*$~Qk &(ΝKilZяc裱iX6HDn8觱O),]\zo[B-+͊т LU3<) dL]7u C7h&Ӆ"xQ3 )x, *GG&DeW߼ kaDLVB*W7VɄ -, 9z8}梲~bM9~CDMv {0W,Oh@m8Fi)\0GAheZe&Z룄m5, wңx#-89t,ᖙ.,!Rh&@p1~f'z**qOWEK';p4ipq h*0Tj\'J2Vݨ֫jMuV6 j F_ELPmf$5*uG V :s^~gПѩm$l B _.1"X!ћ -a^j$36bL?ڸTlRY׬͚Knܰ|lVW~.Q4M3JĿт^%WH ܖ!dhDݍ\WDmk&aω)btY~E-?zGO?Q•<(C\qq1 kb*u(W%fAIuZS$;~7NKaH'^NŜ-aOvnv u# Z(Q)lۙ'.gYt}k8l.4:F(uPf. d$syA̅]dY]U;)Υ:F[3/b{!ӀϺMԤebKaqHYyx [edO 1~ȌL c;EJPO鷤ތ;R,%:m8IS^n?q.,vkLh9ޘ0ⲼJp)a%dworȅЫtYϚϳcFX?ȇ㐅 x+u#-YuzRE͚ڰg,jGT=&X@99@X=vc 3jMsӇq7=[8 I^(l=] ΌxVKo[EVq27v_ıqbשD!8H44I[%&Ir#׵ RJ btS! ]R3WP\!Xxn:O"&4=sv)?Y`@[Y-VKFJTk4d" x%hoO>?Df[wnGⅨGwrتxwnGx-Ün 55U[w`k\f^Yxqldz|-໶d;LqIMrO.a)h,^ 9ؓaZƉ&a[GzU}C{$&A j+uT?R/xUwo.I3^}Sa{*F;XF)X}g[+z9eԇa f KrgGā38nJ?x;x7Q? *f`yQ!P #5HD{>B?]8[k'vtx<_*h%&GQ_q{\"5S$5^D?r=G+#OlUF3cRqKӡ1 tE#t- ^#KVR^Jqx8݇jhF— oi-, /YXG;6 kVDMZD&mjԒDAmXg|yJd(zST-P۳ _6vwV#SA^xsoŢ7N_׋V'"S27lj$n-ؗ9RtS}+RjEpќMJvcH&1[J{1 ooxA]14--hn$d9͌-xra6u,X6'p*3j)xed&dV*$('e&(ho-5y43{RؑMrx;4ID!9?77D/A*|W!G&4q"Z7Qd5FigxUoH~Ũ} {(SI%d-޵$~3c5Uu13|߃>L}K)=R`*RʺR*M Ur 'WXR Nb\jY V.S,T$<*#BAl*czFx6  " Ѐl| "m3lR`teɯQԔIrڕTB99ҏl@b&9xofKq EimuccƦ"X=X<3 mPUCǡ؀(@h񸐑cHEEóAE >E8crtJ 8f)&&eܒ/2!˦gJ=eNMA Gr|VY;"2&Le^Oȭ|+ *+v̇?O׷dr/, 0dd zu")[׫UK'Tf[?-bHDLVqy1AX`lL_PyV.]=㮒EjƓ2G mڲ=,3h繨&o>~;:Z=_܈#Gux(tc$O< %.̼ҔTf~V~ͳ؎12*LNaϙ\ñtYLx}JA9"v2I "D Iawm5{;ޜA<=`%1r |??FcRj$4 Ksj,aa Oю [gv8b5(Ŭh{ɮ%Z4U;g?f }SC ew/fu#B]?O1ɧ_9d ^y٨+#m"9 QH=2!QJ!Od>qw9!A姌0ZN)N١5^J HnHtʶ[yʃBy5F4"5;|~ep.3ձ/ͼ9H.KP~N1#Ubxi H@~=A.(,g>9Q׳ KxuSru3 YpawÊ?zijPxHuɭ/zaJZ6C3dKk_6I]?*`a`ST5 e7+1vU|p'n5-o&}c/tstNA ^wMfyrLFW8Ti#)/J-OJM9ûyɘ^詒`ux BYybN6Цi7m|qdm')`~众j5ϊ35kwM U M/6Dz"zzy:lr_Zɉ,!8NY(SSb$҉/o'ǰ*XBxx;ySru3 8[/|GՂGfmT]x^|:xd %40000 block-sha1(oZxHrYԲn)%6l)r:W8low^KLO*6ʜ5j Y  s)lxsg;f>'&vqxSP^ ~.| sCAd4GZ3z4TSi<740000 testsDz|'IEa>O$nxx;~B}tfF3 +x [Pq2%{JEДo7k*xó d6 ?x}c̦Z;}fЈ mx}j%l\lɳuC^|Mx"_dC(Dv2 ){8nɲv ^Bx <.ۉ|ѿŠ4hOP po;x;sHyдNi%YiOx340031Q(H4Kfx0K_~`ymg Td0^ˢz?D~{x;i3ͯ7g*8yKL~ lx;̺uC>F'ftN,pw$j{ep&d#x\)iy p5)%{$ny9`.(bxºulcsH'gRNv<å0ُIarYLRn73xi HГL^Q*>T ڟ19Qݵ >mxRJ1xZ칶 (/ZD5uk"lED3n%afޛ^O{6۫XgEdyph,chS0"fX\Ewk@ $*IM]nbTRv.D +7e!z2я0ȂG̑jX{2EZp\N׍s+PbyajFoUĆ7c1q:mZ49I>T8wNH&%p ,x$d}*5!>[eWSo1[N9󼈵c2bT@ qNAګObCo.v&s~C!txk,g,͓sYO`˛\Ŗ5[UcsHB5'cYi $EtD<$,άJ/Q6Ck-6H!'xSLKIMSs uq/H4ψRfbJp)g)@$S4= 52sJSR A2Ss`h/H+.i˰*NE62)'?9[d(y)i\PZA_ é Z\~EA[xi ȁ:)<0 X-FҖ x340031Q(H4Kfbc$7^95C$ j|huϳ<lcxks.11!C x|H Ѕt7dh#.x-'&3 o src/*/*.o0 jxi jNU<[~| P(I-.)f0vz0k_MB|\w.*ax;ys+FWY/~S|k? ͒0tx[);OvInjnrAF~iBqIBgHKkDp=jr=|ax96&tJEkn8ߏ";JgH:Y:Ӑ^cPxkhrf^rNiJMqIJNfF,E/1nbd\0"l&!Fx[i4hF%̙y%3nb<9483=/5E!9#Hs2'%F͏YDxi [)gx+o%&o#% P(I-.)fϺg;e{D~xR aȔF(]nc᱓{lln'n6GY7^8*mǐhZ䱍1n ,&ax9  6mok9S;pQ04:c} e;^jjGx9 ρF:RmNʧIђa҄;mD3nz^jDxra6u,X6'pT@o0x[Zudm6Al1<6uxQqC J]&}+ u8bـ1қ@ sxb=CDP{ c0UPm-100644 t0403-lists.czBZM%X|a<uZOuK*y2l~Ѐm )qxJ=v=]|FXd|Mq100644 t0403-lists.cqATU'>U1 s=-LjxX{M}܂J.%%.. W(JKUHO,JJLOVX_!(?;5O!5/%'3/XpYo0$de702-**-(IMlylrHNPeU>y/+'6c )0+`aԟ¦ ųD$#X $_ ؞K_ z<6Fr@:e$gBQi,J+&!m-:x$^n7cxµ!qr8^L \ @0ّq,,f;oF Irx#JhC9Z&# m8y+6LOVe&cLj&eQݼ ucxi ɭw,-wBC P(I-.)fTɾRSw%yx Ixi ~5Nx@ɹc-x;ysȩ'%.l6e񮼪qYMlxra6u,1&^6+x[P{-ɷ/9h5 Yx <|yn 0OP lx[:Muh&Wxi ?٘(so7oԯKex;ysH'?I.5ӚM}ss# x[We.jQjIiQFi^qfz^jBf^ff]f5W-䍬›XOpm`c F%xi ɋm _d&Z-)JRKT;/^>3g^gL6Ix < s:˹cd3%'P q.xiC ȝGY6bF=j/x J@%\; ؘ!)Gݓx!Oֱ2bxxs|}/=,glmx͵i S.3kxi H2{krkcU߹:9Q5 o x;|yC>#sf^bH.^l2xi H=mWnUΝ;9Q Px;ys9Jg|Ӻ992UxrNe>ĒY6bQc.ٝ]./<8*UAK!7"*%>-1$Țkf>|fe/fxi /!C6q?x,~,Mmrγ Hx;ysȔmqq,9֊;gyʤiss# 4x;GekYC97s;3Axۣ[e VĤTM46`uy $:xi Iz2wocq[qj~O~BIjqI1̶[_NTjոju_7;ZIxi +۪ |2zm<>X339Q) p,xiC HjBK'z&Kzo8(xi H@Wrz+=R>9Q܌ )x;ysBŽv*5ܳKKl:Br~nnf^C+igf hTH|vcF=F^n{,]Md}p(.4/XyLPcRRA&_}.q֒K78#'d%3li2˟gf?DS 9#U!:lUL>_`x;yss±T?\8mś}g+640031Q(J-OJM.`iأwOZM.e9z Go=ZyW110e-ux;ysB/B_=4El~_+@wBr~nnf^Ë GtF=إ™bjyPL* ?_ݜ6P|%j|'\' Exd 8F#O ID 100644 commit.hv)s"W<ᱷ3~RԫLH9jԠ6\U100644 revwalk.h)ςAL{dмؓSI*xR R3B@l1sZu/;i^Kl06o+s^8*mǐhZ䱍1n ]'6~xm 2,7Kev xi H=C7ˉґHT8k=9Q h]x;ys~Ko/ynss#˿ ~xm 2,7}ga1&R-85&fMt]N?=$>?)+>9'8UC-9?7"iYZRZ`dOͩǤkkrd#͉"[y}:,5xۭFe&]+9o8\Axx_qs\ 6 \E%Ey !N^AA!.s8jX2e5 ixi )JN"mN}Ny?9Qӯ xi Hmo(7/7tr ^xUk[UgbӞ$Ms6fI]ՎRSA&~HN6d洽%ɽKnT*{n{r}0}EWpo~Ͻ!>~?g:}oODۢG7FC3iB;L^!^?BcWOA=P&JhOHV1K 3u,#[-,oe1v2J5oR)+Z LՉ.ZƗHMN;gQI}R< ]9H3~hoJT*_/Fpf\bD:[߮R R`]`v֬BXPtj C:!zk4!%dnmt8WuXcrEx3l%`Z\ ]mAgܔwgY[;T~Yst~DnѴ.0阥Qk'qo @%>@7~c@ [ʜWog!.j]C*WfikѣS0p&7fb!SoZf,fa7"(ضK9BR˳a[Z1n~rY~%٣ߋl/Gx64ƢΣB/~LN\9THw / SH2,ܙm1L3x&Ht,;KY~ffvFKq5NF} /xK~+;KY~fd;&q1)hLȥȯ``YZRZ79dN}NkZ..9\\959'ksB沜GpB.'df Tl>#,@#8)Nܜ)4rx9  fVvSո_n|0[0ru#5#FBc7KxI=[ T7}(|af?100644 t0403-lists.cL_y۾nKS Z Xx[ž}C9g_<Cg<++ͪy #K -x Oֱ2bxxs|}/ cV x <+sZ37דP kx9 Akm+L=1b]GL|0[0ru#5#FB)xk,YӊJ&q&xi E'^yj ם } 4x9 S^@nwM Vm&|0[0ru#5#FB<Axs'XUYR+J6Xɱb4#kZQ~^fymP*4x .>"㱓5)fx[}C=%x[4Ii*ɏ'e瘼K~ 'rlbxi ɹywOvr6n8fT )&@PZ\RΜgs+)sxE9:&Ix <"5<8P N"x[}C=װ`O_ɎғXJ%١r1n^WkKxSi 3W-o,x;˵sjvԼ4.-,ox;Bn["4ld98^2韛(3H]~@׳7wyt!\Ix <`{X6OoHpP )kx[ȾaLOf xi A.KIMRMaFo,4 nSx;ysBR)'9l춟2`r040031QH,`hq -e]޷{yLܺq1#w|=.x&V2y>5假u,  c$jlQjY~RVj2侅U:Q? [l+BYybN^2"ݕ;GS.SK߳nXf?_ _x;ysBx{ﮛΊ+w_lnqvzk&!ʿ V/y{BQjY~RVjr^C߱iKrJg-d{_3BYybN^2&/z-y;i&C4E "s?r^Zkҩ,_j?Hxxcd"BMBA~~]J"x6rmdgm[[x˵!K95/%3 ,xi [B^4nlsz39Q x`hCK\o&o,#amxEqC>BFi^qfz^jBf^ff|V#n Ox>}dfN..Լ4.2>x[)UjɿYM~PzF6 D&HL~qŬ(?ؚKl[];0O/#51,[\%5#]r~nnf&D1qPԊddo޵ y%'siM⚼KR (5Rʇ`3$d[kUi yy%E%y QRo6x|iBć"\Z%E%Erj%f8ZE@&g祦('dg[$ ?'?=391'8Кv.F+$jx;ƴi"̒ԢĒ"k. H,OR9% +.x <sP{Wh5𺮇P 6N x;cBE[ȋWr{“($fe0,8սaVǠe[nn(e+jmo޽sd'ܦ*|e0c5cZ #{~fBfdF&EޢԲ-YɖK95/%3 yl>x*NjCrl&rx <j Rji#P e&x`4W{ VkX󬹸 9?77D.-'1XV3$Hyxqgd*h$k*TuTH׎1 ،x!j蒓,8f[zfI<Ģx73SJ&o: fN>(&̮Q* fO`&s)N%W2+3MA,`k RKJ(քTr֘*R+@ C!`258̰#r * S#%P=d/y !kf x;u}BrrJjZf^gH/ vuS CM.,<<]\bUPd91Qdr# Z%e%@bZy%&>|1Qk`&;f1JdhgCtd(hM^"">D]xT/@dH MC^ ]]V6wr NGEC}{߼ޛ^]'%qMߒ:\)pЋa<5eGk'?zcjpAPkYxsI1!'SU*TZn97Yf6li U#Љ nswq#N$O[VlCԈ'Dj5M1hmuuIʈ1X}<UnJls_{G~ y[*k!?N-L@6;i?x;ƴi¡dLxi ƽ3u{fn OSxD$100644 commit.h'7d*jJDiJh $N~`V3hLViLxi H$y\-5J x;cB/ ʢ2ezucEmBk540031QH,`.H>J/~ok*w6nbr(OKf?_ӄS`mӴs}{h|QZV`߸աuA qQgשN>-5 Xx=C{'d/VsXC@_ D)h)yFZ)&e+&gT*d*$0M! @1l===j}.̜T 1FNnW+ѵK,)Q047s?cKkr0sB\>knx;>}?d6^x[#3MdSVɷ9'sLƦ89#tr5BBq~QXqBNfqBRbqjB~BybNB~QJjQf^:Fni֢ɂ|b:ꁆx%deegp)AfFA~~]&XA~_&XL@zfIQA|Qjqj X5\(( "XR+Jl &{pKOn*O>gO0xi )il6.^򶪓җ59Qș  x;cBE!K;ʺSN}׾D?JC3 ˾yc,UJXx;|vcFc1lYϘgnNzS(̹dκ#;FWY/~S|k? ɒ9z j?G:%OV=jmQjXQޗ7,T_u斖}3.MFx!ѭdMmu2;d|.0x]8A"@#0y100644 commit.hۚOO0{ 49Ԗ3rV۬z4Yhۿ|+kxC8پ??--%Y!j100644 commit.hM;_Z!9=ӐtQxcBEKSt˃3!'sfMch``fbYP骣kYg存_qD&i]ܟrqtӬݓPEe9@oV{WzsueJ&72d 9sxݤa;d.*iLeSťZ !.V  i % % 9E) ɉ@) y y΢Բhq PB~BN~bJf^PwZQ~.ش$}.0h ͺv)I: 'Ot|Kkwp Ʌ+Oϩ0;*7nb̧y-k61gJk0x;m? ixD$100644 commit.hY۫cыaop֍ŗw$N~`V3hL8hxscC U~viBBr~nnfBZQ~.WZYPPXTT2y5Y3Mvg< sx&/adgɇl<#|]@@K!4 85E!9?77D!?)+5^!<#(U!%_$#8$Vk钯P [ R W34!MeYONgfKNamv8migx;ƴi6x0]]3@0xkR&u? !.V  % y % y%`Բg!x;e“Ōno03rp)dq{l'x-\lXN(Qx{.s< %.̼ҔT%Xf H+9?D!=$>?3EA Āgh x Zɚ\\E%Ey jɺv)\\5#q _xƽaK}QjYybN^WzfI<_''k$SR48Q+*s!3R4R\i `'gQjIiQ_u8'H\hBJP1T$lUUqNZQj`7<&jtJjxrqBrf^rNiJMqIJNf^dFɯU i/x;θqB:Okaxi ɦ D+=#JRK9rVrU|=]Eaf;g<Hxi b>5iO{Dޭͳ?+<9Q Nl>x&M~nͿYs)PTx~mBHKٛ%L>"MtvɢO#gxeC9 ZOxi H&tP mkuor Fx&?]~nͿY/21rN9?G+#2y8\` "^Y Ǘw/gQjIiQ5W-ԝkx;~eAj.̒k.]byřy) Eũ)V:\3J0rp)dq@ xm1 0_hWЈ:JKMI'boRl xٴCK2(s.!(%D?`b6a..5A4j.fLf ]bix|ʁ7~Abx;xq:qNb+#3kZk..Լ4.k xD$100644 commit.h%r=-]S:$N~`V3hLNu)xi ɜWfUMyIbf;,M @$-g(W5ZfnvsKx340031QH,``Wz- '[m4D~;X@դs{Dwg3cP5)I@;Rb4w[^>XLAf P?BKX$h]+t޳u2TAQjYybN6PQu x ҒTDE>ϽěR;7*r2A.:}IC6Fi 7ϖhrxS#oIЄ'.|4sV>rIϏjG40000 tests"g]Ac;"K㡘V%%xuJ@IQt#^ji)խZ[,Vک 3efߢ] .ĭ/qέ/ 'M͙9w-?ʡ݆B&,A@k@h:7peb.'2BtqA-Pȭ8 zJ\nc4P׀IP% *b&㈊pHA1ySGiW?cZKOS[ jΨVJ EDcNYfma')X~`kVR4ECj=υ<ވE1z3K˰^2)%"ՌO+P?%_D x֣:os4 #kDHc{9LL *`'X4y`x'XbSR= 8!A ڶ Ez0INtI  R7858I9ٺ 3L&;Y=Ry'0jmVee ެk=~G,xQ}!EK_n!첓'Kl¾ .x{YeH?L3CGexz%40000 block-sha1:>d"FlIo %xKup;D; 1fлOJ{7X>e<M5*^ 3 x340031Q(H4Kfbc$7^95C$ ;R'YwM=3^0ˆqx340031Q(H4Kfx%v-.̫%ŗy7?"`8+ef͸T Y/A\ݷ.93f m.x ' xSLKIMSs uq/H4ψRfbJp)gt8{8r)+d%甦*($e(q)"K&'g낤dqAi}- up1lxvmHVI#KgM\vsׅA {0x"OdC(D8Z.lx'!e icxi ;eVX){nBk .xB5W{Z[qf"100644 odb.h/ [ BPzێ2Fpg0YTdz\}?ige\p0{zy<\;'8d楗#RLfl|;G0eH(i5Ϲ.Mql$[W8NsEH 298mUM+` 2S&HhD~r8׽S/0\AA2mi2vZZI0'dTI<)9;ƗAh2k?~=$(51E$3",zΠ$#I'E ;kt5i{  +ˬ``XTaobOfJN/)2hUR_r|s]#`p*X#TQ,{I_C(36b8ZyJ{C +d8dyxk5\u.[ˠ@BRqڎIZ_3ZR$Z@^ˇ[Z4SSN 3|v40000 tests@pW|/BʺL1ϵxO,LO./)J,KHLJ,1+HD.^zrJ"Se\ixvImC:fFLzUx'x^uBhFF׈ xg7GsxT4 N^o0֧)8{8rqB$m 3 Q@Z/h| 0t¬N)NbRN~rYlrlP6^07_AMc #xM8 cFdaKV<100644 common.h:k?`'aS2SI\[]R}5樂[40000 gitA>ZR(FD٭ lodb.c,-| }kqo?ThjI*)[XbÓZ @Il?x['Vff]fFn5bx340031QH,`>sj׭]&?ԢbyNvw(nQlq &?% bQJ̔\n 2)L*|Ao!{[]YmH*(J-+O*zʩ8>kWJ'f^trҒTDE>ϽěR;7*r2A.:}IC6Fi 72CmjJx(tKhm< %.̼ҔTf~\f5_n;x%tc$" l-w& xQJ@k}"(ت$z)T'!lmfCvS->94b,ܝ#J‹v)y{ȳ Qg%$/y1AkO&{zÑ*! ۶sN?vZ^`>9?~@T%tVrftn7`.w  $Gt UFZ7vJ &,xC<"gاxHIS7̞u[iAB)S#`@Eo̢ ̂miIoڭ,!c&p"2 e|/yYndx[#FnFFwy*oyx١!)3os2;*- x|a ;BzfI|QjYA|bIIe'/س9s)f.SɎ xlgDR OI 59F`w stss3'_|E&^29ADf7x{VjCf~`{ӹ3KSR6 J.xSMo1UCpʥTKq)H/5l֪^ަ{+~?'iZ{ޛ7oӴaF)_fa.v€C|pjZ* l[**#AƒNѠV)&{t^YG %W%LﳠJ-u `R!%Wy=(&FT!Lc2Z*'F%&a=IPCT5U&0W!K`ẻ/g77l&5Fۊi%\NQ[EM-{#vɅfcLAZekvpKLBFQnVSw9b"T8t|;or4`lVb54US~?d\:%{'grit#tTz.GxK.E#*9aBM1Azǃh-~xېCu޸߹,1: 'ZB.(S0HYE55 m)1hq2f]+qѼ42^Bs8uv{y |Х0w7*#t_eԱu1.Qsx[j yٶrznS&ՕD؝^|mj٪Z#x/>Y|]YDS23sJSR6Nd" , /x,>A|C;W~~BzfI,N UVαW(QPZ"~%H<#3%M\u/Ν TsMU9iex w$lk8x;sg*d56eGgexvmG!k/iYMrvm5]?}у]&0Zۋbڻ2C5t'"gh``fbPb`h`URYmsx$̂iUW9O<]5MN-AN׺O.T1c9/Ts>{wm@1%9E@34dj, ׬HhT&)1KmS̚/']a[89Iz ?w/˙Bcu~ P}lx"Gd?b&[x[ihF%̙y%3nb<9483=/5E!9#Hs3'(rvx["4ChB䇌v,:J8}}=C4u&s1*|Jr|kGw`]㘸'g1O1bhfhdl9y;+j-x;̱cƨNgxWjF%lZ؁] qشl'^HY;SvP7aҀ*{F6ƕMЇ},PhoC:#empjA{Νs^ɯ_i凲r!°hZ}Li::\)ht.|6GaB#;G XH?`u' wj}~v+@KCx*TȐE=a|4BAIJFcy_Dy]be h=-)b2|sCƥ.1j@6,23aY nbƝћ@ ];ȄToMd]XƏ2jcTI3Dnv I1Jjhf"7eaWa#vRf0Q5@Y{߷ m Qg*ωT :2ҳItE1eXkCXSތ:laӶ?eQ"˰3HN[I}GX]L+u g[lF~8hd t񤏹.s0Oܑ#}NrT9 }LqkP"ndQ/ޤurEG3Wr{g3ZmDm?%6A=>$)eڃHCk{&P?RIrȟ{'<'g6+3ڕCJĪvQ듣czVFE."g35|% -WCԨT,l P'9Y=H6 d= ,$jDW3[֢۞ZM6GG$Ţc)lBxuVfF;xQK0_|id]7yn0t2A|PHi56H>_sYک/ ؞Ϸ4*.ej<< ǣ蒐B%S T!S/F9D+H,) Zj,* +'lu+HqO5 eP`}S[ \n7YsXPд!Z1T٩UMg ~x_&SܐkǪnnr\׌^7˝ר<MIЇ8iv:q+qA ./x340031Q(H4Kfhz)dEW3UyQe"t }{Wݟ@!jcAxWmsH_sIF K*vL_(I h.B1o^wCMLOw;wG O0>qr'Dõ.|p1CWA?< `n*5; 2*w0`,p8,ES/U.CbMX^.\\zxud0dI"N"1Y$܅E \WX1wab[0hԽн n, ac8"kAr cKWN!#q'"}$f֋.b. iT[4/] vv`ÈOy H>ք!t}5@$ݝ'/Vpѐ-|C:!~ 9XCL3|*Yc͔9^A`ۍ6ntka>َ4t$iF}Uh{zJOO~@0rBD 'ίK1G8=|2YY w[i[}^RriHz!rr_HS1Kr v]J4m.X}d'fjEx _R!B⒇,V"@uԚ eRuOQU XEkr P!٣L#9WHZb7cگp#B CEhQQS)'#K\YRɑt@ OB!&ixğH/z4<2{س"A|?t[#m4βɱ׮qHI6GK4W|<ta W G9bD!9\\88]3G+`}Iүq;4!T 6ʬMG 6 Y + BL _H'tP6꣚mT5u}茂hsɪQgy pSE옾oQr_,!ܸ%F.5N,u\6i$u-i&u|Mr%v8>iI9rܞ|(2C@;hѿQ=|:;އئEr6,8 3Ɏ"ךxKj) 1q*I"6RҡㄸӾW dPщT F):< #dJL0*ʄCN1f(YX ^gLJ9Ĕxjkae۟/xAoP\nH>kr3RRAn״Y~n=KڋX&^UMz*Gz%^^Էra=ԏM؃z`J-m,6 G6!r,Xn̲,O1,e>sԨKgUBƵR]xHB|Qs9UPIl6B]>% QNQ,3c~,U_$tkXzDS|#v-׆a|410ӄ>1R~@G^oRtҵzV:έanv ऍyD5YԙKw*}ff[2E+lu/88Rc9Zf҄FiDjP!_̽,+軲}a'v[3>먘kgQ쨄[U~u+OXT& 53rL=J]P%J`U *ts7쟜q gc0m_z3.GMSGfoK\|j9g:XADTv % eN.+ɜfRWt *7A.]HiM;Q)<oE _?ّN`n23g?)8A_4 wro`m%2?=FpݢKPGaɌrNv16qmbjhqي`:zi"Rf]ә.qMd p Lm@l~?682R#b[,R[!#X)* Ț,'LBs%r)7V0q=w"Tv"riu۷ILKahQ]|5'@6HBoO//)(O,2_}n{gWXg;oz޻DNxDm,fo^v6 xP|E'6ƂMTF+ӆm 3iџVBJ!ғP 5$xaH!<6 ly<ԊݴN1QYC*˥ۤ?y 7J40000 sha1XpDIQ|»N(/PBq("kxx[>}CBfVfxi k0gbfoGcvr; g4x1cC5HaŇ=+\kE[yݙ ox.1;CxSHFQCDPxS"|xi ȶ ,x2Ud摓J Mx1cC5H2+p>pOG2nQһLM ix{ sXJ3J6gm2'1%m` Z0f4ע973es939ri嗖(*kYY;A"_7asaZ*qirqVf`VN.1y8n捽 Qox <:UAm>@YRx;Ly;$&6/f6fݛY7_a9}F  xvmHGoݚq⋪T$׍^|x#CpB5'1mnc4ٞ5Y7_afV F6 CŁk!d] 3 wDUfxi ějV+T#7+6ab %% kj|\gM(qYFƿGOxJ'100644 cc-compat.hfђwi0SDu0']Ŋ z Y&O#ʳ&5 l+xȽ!ycfM&8x[+VzC>䙌E$y8SrGxvmGCJr+GjH>oo 8 llxV!wD_"Zx<<4a\VyO3|u40000 tests ѭۆv]*$xQ{Y.ϲrn!#a>ѻ7b.5 'ƱٕjRbqj|Nj-LZJjNIOKќEL((G},7Y^/9&x93OTtlo#Y(}5;Grm!M^Gcj]x[i4hFWPxxi I" -i)+T٥gb %% o.ݾ)C<獵/vL{jcvxc'100644 cc-compat.hHCpmW)']$#%7چb{1F \ޓddy(r&2Z0z<)lWxya?̚L"dx[+s_zb O#sRtK3R5'Og bOI7 1IkJx/}Rz‡l7y!/xiƨQD_dTr1x 0t=vrD.xV>W$$UG!9#HA $Czs?f 0x7G3i߲Gё^m ̊Vq jdNVP GSkxkgy˼a%Ì.qDx! aGaĕMVm)ˣEaDx340031QH,`>sj׭]&? _!Af[?Oi﮹~ &(Ƽ'|%ӷpWwG@դeּi}Q|BS ;@-.xsL Ӹ7=yT{ԲĜlʏsSvtRiI-܁**(JML--9HETK);ߚ/x3X *'"7۷O>dcV͡| x]4p࣒zh7d(H+;odb.hX2d\ .QR0100644 oid.hր.$% iq㽅Ecq(K|xJ@%Z66QID5 $rֻºvN+//qs1S7r[M:_st9S ?Й&88< $.`U{eR~"):N#jAjʲ@B6el< Hr2N)c 3J$Jyp g>!-'pfJIeURReŶ|͂\mIaLpZ[ݼwdGx*xi fdJ?K)T,9Y8sr/ zxkHwՃqr?J*dC 6}1O1<.`>-`egI|ـ̫q_~ z4+cWkB|B2n"x̔7ٓ vx;n Ly˴CGY 4x';UvSN̼ͯ8W13;A\ur& nuxwoC"c\,+YeKxi f^ՙ.oh"dH8 !xǾ}HnJ~5yKZҿن; &xi t/bWO :L`TQ |x:_ޡgC#IF`MqwsmdjMK:;HH<)l,xkTAk. ]x3ѷ՟BI:JD @pOt J n/<]x{|[yCdG[xX;oxvmH) Lb6WN >WmF/>f Fx!(q$FG>39X(x <3*kCb\P 8x5b yh=8nڋG3`Ѣ^E^ox{zyBɩjxYsqV)9 ZUS2RJRSl 5LaY~fBQjyf6LT$ɇ(x340031QH,KfXbvVϵ[.ݨw -3'5sɱ]gH(7oN׊ g :k R'vx3Q?gd]FIkR2RJRSlzΌ\Ey~+#grN~q*;k;3xi Y''ۈo1YsrA  xr5S@.yʹ|y19]蜽 C 6100644 fileops.hF)EnpX೘f7!F/>f bx!)q$FG>34 zxl;ɄhvcQ";_100644 api.doxygenG3i߲GёE'6ƂMTF+ӆm 34pU{UfUgjKEz40000 testsiM/ ~hlǸA+xa'100644 cc-compat.hVI_^*!{"x[+JfW}--T3̪T<`=-}.Դ̼Tx7Ox7`אx'ϐ`Ɖ뜸+KK2&>132r@2Jl"drM1O>ΨĞ TYI@-x[%LfC#gHFf^nF/t]x{a xvmuM8g>7!D/s+Nk4wV<Ɗmyy/lb!(EO^_0#RKs22O9pk sNV oxV$S`S\Xaǵ/;gQjIiQ֬"%%: E Z%\Փy= YxtKi fYz+xO1>k9xZ[\GV(lp͂]{{#qb#(Υ$sY?!v$GyoOgϼRYL=3c= iyiJsMKGTMaL$4<W%-̈gD}IH4'Ɲ64ԔE5JF sR&s荜>kZէUrDuV!*)](V{ -I\QzNAY~L5R=)x[z;#)Zh%*'wg\FUCZMBG7$(#KR 4l9L܈AJN+E.Y ɞ~q:Z6,򘭫фEظ&e_y/~̖ d-T,",鼘(V#*Ӄ77v_3Z)-)7tֈINSUaBcuΚ'(|K W~ 8g?ۨ(+*.0ir+ $*Bǫy ^)oZqb FzX}X5Odlɓ;7+xd'2kƮPi2x/S$%J}JZ<9c5xJFrPPD7QZaǽg/\|Bt#%ޢ4,|(HHCPy;,VMR|6'( pEʠ:KW 9=ahjD撃!ўq]ُz챦}b֓" FĴ 1v K*x(5oE#G@ %*?gH1*,"U41M@LEWLHHךѐ]SD.O~#I:8 htgrEN'8O14Ѥ a4XC?z.?4{Om8d>…<&N8Bf%AtqhICE$)/=;Iq䋈lqUQ;X%OCKhŶĎF >8K-Bϥ!yjX_l!BQ9T90[dNbmWSP֨{$x/߅;E *#TVnfFA#@*Zzw뉣ߐtS:Җ pNX (w\AfP> ڙdXCGI*GpDʡVpӫ{^ ONP,:Nz7o(2- ۺShu|a&TD٦$wQ8Vt x/TgXhJq31{rNCh>"čT쿏fPYBtT}Q~|J-޺nP6ځa8f6GPc&Єř>qRڹJu >|{ХQ^?h7ʳ 闙M\lM+h8Qqw޽;ypMK nbp&Dkg,j1[X'i@7rA_]'/]o7ل߼K 5>xYW=\&,u˅B?K 8/~~sVCH 1]h='Y8#J G1A/Uy -v /8 `:rv~Dˁ _:p/=]*磇Z JdQ|g#ݷnDNx˪UI@  A1ݫoPqH:1r}% qıswWjQ2h^믿V|}W~ǧO>w;r={|pɜN, HFw\d\94g\,ذ) GFRoE^.R|/bqe=y/Kd1 YT6(a1!,co0TV{ ѦEl"zߪΑSʊl;"[eR%ż8}C[tu|kqβʀO3j,/p`x/ 2-jr` Cdb([4/HFGq9x9(Hkڰ=p!!d(LkD*!)Rb,)Wx, ʐ~D' ۈ! P\ E 3 ]RZE*uQ##&r*Mt3s^=p%#6wxՓk_W:[,2A]*-RY)1svG1x?z- ōQɟ2'!B}mNJ=\+mDzq& E=(3ʣO^L os=Bhy<k? YB9sB$ [[ {;Qi"t C[}>!'m }D-wؘ=qh.3,$7 "4_RpڷALWLYwm)RNJqZȕ' MIfVAZu$HI|1_B7Q_HFҘ/F}Ye$K&͎b q1is oP]l4\ FH[n`蒏2{0,UR%I`apQTTĹ!ZY+({3=O^ORze gzZpKZMU'w:H礭U=7H9* jg$AwՉ-Ȏ7(Dו=D(ixM:*2Eʨji*yz9Raj.'y\%B J:*L6` w59+2\%8p:d~1nP ,گԵw[O26J!iZ5AZA5@LᆧGc*ZK2Jpn%g0zZ( t4tn= 1_ر]<(oAo6EP]YC|OSj=!ݘiCL/b֧@m?yx~9ܺQߩsvTI?_+SfcHV[5X9c UkSM'l6Z'bLzOZK*ة LOa R#`\Re/)3٥n?.ԫ9|Vٛ@ev+(D tk1([JvKȬ54RգՙVOk٬A_(G98FNX]$2N/S/'jr2YvRfej^WroEax+uFrl'XD3Kss6s s Bgxi If7{OIf-b δX BIjqI1[Gze=n sj x:{nU;:~+hxk {q#Dó~@.|cx<4p࣒zh7d(H+odb.hX2d\ .QR0x⳯xV]o6}EbntۓۢR'` J,T\߹8׾ _srvҡZQ IR3+ԘT9oU\{y:=3J 8u*-\tdj+qVN^Z}!UlrRKg. S8OI#&TȮuj l"jhe]BʣPSHLY#{:5a+jvQ>'gK5k+J")>8}~e;h)Ci5|K9%.pRCku%(]@1Tu=8R6> @2g^Ĩm#>ڜQEAq">c|o Mh6Mw=^*Dо0e.w2.t2͌Ft;-z4f>s)w2 ǻ- TJ/Tv+Rie"!4U5?@la 䶵Z7w %GOXf7&7}BBGiaK!ea :gg#ib Z1P7,T$. mS}La~ *.&P -R #c .ֽSJ2?~Η/ъ >Dک5S ?_v  (h6;0;mQmQ'51W89yzHeucm-f&/9ƀ0&m7 G6hzmV&n|9ܫE&dz.;.ӽ&,&iz;W'u*jCNp{јJ6Io39%m! UaM>`tҽGCp> :O`cQL oT}r_ia|}B oA!RÛ&vsp1?C|</f1Ktu߀?41R(+=fW>̀@+šu|C>)7*@6!'ђ?BR`sVf?J]#n@h419S6-eT{bLfCCyd~Y8ڨ 0{׹HYrF%RڤI}Th uV Yѓ ldi O 9?W7#SI/ qDȬ as8t2"-iB3SC?y,3gnJjtF,)p%$fv/Βgbx*{]jC8/ .%xvm?yq? %9+#W xgNx[itX}aa L_xK5fwaw&)^V}0H2VFIZ߮n݊;@1b9"5Y*~gGBF=o$^ǰxO,LO./)J,KHLJ,1+HD. {^lZxTj^/2%x5fxvmHJr~?W\gb`@F/>f5x8ʿir S)SffjMlgzxiC Ⱥֹņ kdnPQ8MQ5}5KK>.IӅhͲʲ1]{˹,?Q͆\4+amZg(~}XC]^Xj%֚Z\("k!S x h+7 ߬npślHr,4Et:n#1Yq}Er!Fe^a_8h}Y*>|$' ?4|خ&+;8n>N{~ybm7ÝhAޣ S_liz6<g9߰HI rՃ٧{ `bD= &E>Fͩk"9sey:"!8zJ ݯ[2S]=x-?]r,*eVpmNgg|Eq[N}QBbAfJ~r1gQnVBqQ>J,13 alQ0vyf頢PZ\R DyEy%)E%E 9y\\%@U`'gs5u tĪVfQ{*!!N^ Pk+꧉Q،UTp  8 4r23'f1A3 lxmHS-rKwt|T,4q &%jx;gBƻ]>mef\n ~= eSxi ȣ*I1YgnNCbr/ #xǾ}Bȕe*J捓h~xk5fwaw&)^V}0H2VFIZ9հ+y[ql3Uö͑4}Ld640000 tests?B@dZv!T+N5IxH'100644 cc-compat.hʢGez<;p޹됑'XԹvV?}" ԩ\+k`x[ucdVgxi {zۻ]IY> 7xJ'100644 cc-compat.hAA݃姹/p.Ŧjȱ']tBS^tjpPp^'H&@RxiC 噎JS]p_ ?x9\\~o)f xRȧbQ&va\2 'Ax;#'us96 ~A!A~8X nxi Eo-ȑ >=-U !x6S}引#|I 6@NRgIQPsx[%3CfsFɴʼd̼Mj.΢ԒҢ<WO4es M.3x340031QH,KfXbvVϵ[.ݨw -3'5~)ޯOO|κmsߓr j3b7H}!s64X:"r(ix{DziD /Fxi HgPB+/O9 ߏ +x{'100644 cc-compat.h2M?YxEW'X2gD>T ,M^aI(G $nlp,p3 9r(z+2k6BMr<1kyx[uu~, PlxG 7=( <ޓtypedef int ssize_t;I cc-compat.h"vO?x;4iBT~J^CN) ֫#d0q$A`xk{ûy4>06561Ts+2r2RSRRӀ<wϐxO?O?WʂTMĒdbf#vOz}--Լ TIJ̜ĤTHf*hAAA ƚ\\ cKsJJ2RR4?Xhi&'qy(gٓq)J`xx;n UJJ|K')xi HԾy37-nfӛ)}c cxJ'100644 cc-compat.hAD٬JC6'T]m'_Z %_/~Uu< +x[uuC'2JNvdZW3^Q1cYrOR/٬ab %% g:Z7*[FOyt5.0xǾ}CtP %$J%0^vz/ol([-T"/.'Övz?kii3ņ5=ci3tEkaDL9҃(@-TnEUg:?3,x`b5gSQ;MF 2.xi IcjnM}W:(%ПKJRKԇ?jX0dg7{fx:=%w\aw}x͚Qlrk}ySeV7Ť _<&z!x$sodb.h󮽿Swv4#&6Zw_xUoE#TuB**Ķ"RBڀB*LwىvgYᇶ9υ#7 !C.H ?S{BěwQڋ5{j?Yp!OSz5:eaEqnK%tЋxjA64!p@ժ'^1Cmךw}}[|ܼ6{nqtknѝh>O߂ Xӟ7-{ny~c@3tקYIAWO^q26Y<o[fYxN/<"-6p'KRūvkNC?L/١ ;Q7;ݠOvw׽br6&Bg$TG%H%(;A 0(Eod(qDA(P+DcyDt{D(Ay=ܳQ`0 fYdO|36ﵐK*@@DG+.|۽!~Gg6eUAzH?zI0&wz ઝL1-+FmV };ARdK9( x;qB Y7۰%gVo^(4d{?'u mxc{:D ϕkT",Nwl8gr4fDgPxreC _xi HՑBl_띷ort DxF_9XP晩BxpK100644 fileops.hVd U-衑 YLy+}&USlKxS}~\l%x!Lz(}lx < ҊCZȭHWP 2x6ܧI+u{',BZ,ipF~Tbr0x!%AQ&(/_/ÎK93/94%U4/$(6Y$X UQIfn*PONfXQf^:XJfQj^ ~ۓ?1U*&($)hsqg(h$$Z+((k) I%`̪>: 9y: A!A.: A@vZBRjzf&Ж4 $3l43S4u ';rM֓4 AgY Z@%\\y a: 0͛Wp<KzMxrOyd)v4̒<wϐ WG1 >1OKQHJMTQ0l$5y" y@ZA h&W5'Ă<u9q7)sxi LmO9nd9<9QQ r&x!(ep'><ưH<sx;qB Y7۰uyEo~xiC &m*z};b"l x9xe4mÙ:69ahB.xZ[\GV(lp͂]{{#qb#(Υ$sY?!v$GyoOgϼRYL=3c= iyiJsMKGTMaL$4<W%-̈gD}IH4'Ɲ64ԔE5JF sR&s荜>kZէUrDuV!*)](V{ -I\QzNAY~L5R=)x[z;#)Zh%*'wg\FUCZMBG7$(#KR 4l9L܈AJN+E.Y ɞ~q:Z6,򘭫фEظ&e_y/~̖ d-T,",鼘(V#*Ӄ77v_3Z)-)7tֈINSUaBcuΚ'(|K W~ 8g?ۨ(+*.0ir+ $*Bǫy ^)oZqb FzX}X5Odlɓ;7+xd'2kƮPi2x/S$%J}JZ<9c5xJFrPPD7QZaǽg/\|Bt#%ޢ4,|(HHCPy;,VMR|6'( pEʠ:KW 9=ahjD撃!ўq]ُz챦}b֓" FĴ 1v K*x(5oE#G@ %*?gH1*,"U41M@LEWLHHךѐ]SD.O~#I:8 htgrEN'8O14Ѥ a4XC?z.?4{Om8d>…<&N8Bf%AtqhICE$)/=;Iq䋈lqUQ;X%OCKhŶĎF >8K-Bϥ!yjX_l!BQ9T90[dNbmWSP֨{$x/߅;E *#TVnfFA#@*Zzw뉣ߐtS:Җ pNX (w\AfP> ڙdXCGI*GpDʡVpӫ{^ ONP,:Nz7o(2- ۺShu|a&TD٦$wQ8Vt x/TgXhJq31{rNCh>"čT쿏fPYBtT}Q~|J-޺nP6ځa8f6GPc&Єř>qRڹJu >|{ХQ^?h7ʳ 闙M\lM+h8Qqw޽;ypMK nbp&Dkg,j1[X'i@7rA_]'/]o7ل߼K 5>xYW=\&,u˅B?K 8/~~sVCH 1]h='Y8#J G1A/Uy -v /8 `:rv~Dˁ _:p/=]*磇Z JdQ|g#ݷnUCNx˪UI@  A1ݫoPqH:1r}% qıswWjQ2h^믿V|}W~ǧO>w;r={|pɜN, HFw\d\94g\,ذ) GFRoE^.R|/bqe=y/Kd1 YT6(a1!,co0TV{ ѦEl"zߪΑSʊl;"[eR%ż8}C[tu|kqβʀO3j,/p`x/ 2-jr` Cdb([4/HFGq9x9(Hkڰ=p!!d(LkD*!)Rb,)Wx, ʐ~D' ۈ! P\ E 3 ]RZE*uQ##&r*Mt3s^=p%#6wxՓk_W:[,2A]*-RY)1svG1x?z- ōQɟ2'!B}mNJ=\+mDzq& E=(3ʣO^L os=Bhy<k? YB9sB$ [[ {;Qi"t C[}>!'m }D-wؘ=qh.3,$7 "4_RpڷALWLYwm)RNJqZȕ' MIfVAZu$HI|1_B7Q_HFҘ/F}Ye$K&͎b q1is oP]l4\ FH[n`蒏2{0,UR%I`apQTTĹ!ZY+({3=O^ORze gzZpKZMU'w:H礭U=7H9* jg$AwՉ-Ȏ7(Dו=D(ixM:*2Eʨji*yz9Raj.'y\%B J:*L6` w59+2\%8p:d~1nP ,گԵw[O26J!iZ5AZA5@LᆧGc*ZK2Jpn%g0zZ( t4tn= 1_ر]<(oAo6EP]YC|OSj=!ݘiCL/b֧@m?yx~9ܺQߩsvTI?_+SfcHV[5X9c UkSM'l6Z'bLzOZK*ة LOa R#`\Re/)3٥n?.ԫ9|Vٛ@ev+(D tk1([JvKȬ54RգՙVOk٬A_(G98FNX]$2N/S/'jr2YvRfej^Wrotxi rλA_ro>z;d#&@PZ\R /ڤݘ|O+7x!򩊈3r}rk+[ᴳ&l+x;*T|C), Ex{uTWykwm_aZCxmJ1D 3q\ nE: ֕! aAM!F}I[*'gV#%,[py4 +}X*`  ֧ˍ,<w`Լi;ơNS9x%ܶ%O LOvNQ< ]%tUxɼyi:G{` 8NJ!2?t #xtmRxԼ->ۭ!uR:.R0!A={߹>_}lxi MvL_YT8F bx8"sX>}[Wm2UgM!& HZ.n&lxu>͗&xx.A])7@/Ci!F!̢Լ ;..4ŔԴ̼ x'O?ǠHM.eLDK95/%3m~ۛŘgL~ksG 3, Bhx{.Dl*#RJfd Fٌ8S{Bx <lH\樸A^,Z{ܔP x9 w9X_VK16?ۼ(܎ / h0-ɜx340031QM,Kf͈)R YfH(c 5x7ʈb$UC;]4Ul @[5O)zsuPIP rqax@[9-lcrypto rm -f src/sha1vScr x|0_ 26iQ+Y R9aPvf.`Co1100644 fileops.h9Yc7- !-?%100644 fileops.h=ەYqpwKxMyrf^rNiJMqe~nnb^D E%%: )k72jHx@yFLxX"Aq FCBr~xiC };o ?aeJ{d{i6O zx{ʺu"&e|@5Ex3V?2 `Z,4hH)x,P{x;#Hn:ɇ7 f=wx{e"FߢĔTd'/tcҸXlB.?XR5];'1Aw$xVo@V+'B0J;JE!Z"@D( ƾb_,HY  V6f6Y'ޒ{ޝܤR|%zqvbJ_79Mg`,HhR′# K5 6@Jç`VK㺐;} @.RlƐ@ygJ-aIx]h0؁ϰw Y ][:VIDc %E Ra4ְDhJ(Bm)!3lN^-RG9q_ȥhܥY$hGGϖ)C-'owZ*IBY9i]^.?~lpc<em< >9ixrSc>=/yS \WGAqWfVӲB5~x;EFL0D-^uY{O/7UQjl9ɛnlʫ8zgyzQanVum-{ۡW|ndIߧI[RpdJ7C?d*Fv$Ȃx$țF?/Wj)>Is;Yk٨0t! Z#6h'q7!!,[XYZѱV^/bK Ė R5!;2'"[eR#E8}ζdj9{UgYev8u7 n⠥ŀZ╌pY-ÕalMT& P\ R|-zAvlsDe5Mdt~.t#Xtbb-_х!h;b\gt#DW E _O`-+T+_O@Q^\vРu2bht_RU W#cWI긚Ճw^ݻy˗7ol!&0XvuJ*SdFVaMKـ.9'/5-FꂋWS!*\yQu@vyj'JE^̡@tVBmJs/.Gqd 4Nfm Q"wԔ+xXmV>Ɲ@y*$Ex؅HMSti & /!m3\y'l0)FDI" VlD N@bj o!o?trɛuRh k}'H? ~m?6> ?et2ZrrGŏ@`:I揙AvO&3~˕2o;_?$P Y틔|2z$O֞[A2A+E<0GuAF 4]AY]"$4InnbG ֥JdO37obL+3 {DR9R^}i>CG9Fp2"T4~.P0&`9ZBJnX@٢2,!*bh|^r6p1vY^p w R{M%+Z P B%΀ZPm 0L] Ϗȴ]i3$,F\YjR/WQۓΖ@ݩqA>tWIE$u,.$~@u JgNtz<m`D%:)5k2W"" @ d^{b<Ь U(Ht(/3ts_@JI),OW4ySzZ&͆bPh4yqj)gF\h6F(6ЊA70MWR-#wKFQp:VkTĹevtW3w{3qϭH%WtGc-W^Chҁ.LA/c׺.ҁRtI{z܀@9)݄琂O;TB`*(2Ӓj"'-yFtRȬ߂ň)m@^.ZJ/R_dkX`C*J B'{\j)%6)栥@`w]sdlqt j2o0VLm~&ɠV%N!=صBVnQ5 M6%s4 &7ZJ\ۀF Y}z t\C.52WjPXXmM#sS/:8Vʓx"ݩVNDW1RB7k#?DzYK!ZSi?TƒE.k>1wΜu?-UӦa 2J7'UIaZ ]%%|Amvʮ(z (Fx(U&ŕPphȮSͮB+$Yf @E2["M Ut3,ܛG*+YDPeњj)둀 :oKɥ MM1gCS~N tkל-^,Fn1M?xi 0ɥ\9M~WŊ P 7xvypm'f5` hZ}95z*+6qf100644 fileops.h7L+wJ-P#j`wo,WEDK-7FC1*x{yYJ2KR&3J+奤)yq)+yy0R:L[)kAx|ydƕ  x <.z5$֦&(ƼP B xjHR} ?*)&4“Al+AQ!RO&N`g47  1#%I)N'X"@2x#UhC& L͓YV;l+xNy!ͧu)fx;˷oC d6m,L6AF|#xi Gܪ v0o[ <9Qs x˶mȗ)OU.{zަAAx|\yC.KY~f*Lp n`|_ ˃ *x7eՄ6GhWc훤[G0P{zY- BwP ]f1x;#_rBhM `PY19)}5\Y7cb5x9Pɇ7:$룧Yb8$IfF P x=>w%vZqSRQe-,3 Oᓷϓ;_xJ@/^'aT4ў[ "BAJY%H^xqv[Ӥ%avt>v˝2T 13Tv(HDŽ(T#ס~7\w@}HH*͉<5hS;|LRWW&~g*89E.z:2 +{Gcj !zMY\3}Zn6ԲH)ZVH*`=|0jȘf75طn(3ehMd}w Fј>HlFjd;j3.WH~V\-*n.Dr|'C0~߼MtYPE,;1u|xiC k ͛nt>6px pxMAOn豳ȣI@-100644 t0202-readloose.c1 Z=֗^-hݒsii"nx[wqM x\C\]]4 7~ٕ  'x;E #IŚGϣd` 0YXte!F"D 6$h!322~w`tw_UuΩώ}vo>z4n>{ݹw?[ݾqFsfvoٍI^[~zx/mw廼؞]=|{w=8ۏI^,۳9˰=}=2m)[뮐W|dII[RpeNB7]=gd"F,v$Uɂ xd7e~o9OR|/\簱w^%Q!ah$ jQ-\<9 qamJPZz[d`'4u^ 9ޑ8*~8m"*y,7E'[Wݓ:*=ݡՐX^F_ ,^ȈB7ar=\ދl6hKnHeR7AAS/ۆ`b?dq"靹 @=VXWt,Zw|D`1.`3 "@+mNfvjύ'0l pST*_@QV\LvA7jd 73v9-F&?xq1U'W;R^?rՕ # ˎNIY$*9&YUZS"'1u2I Jbj e)oEgSrμ\2 X[acc>Iu"'efWYdދQ6n^*]9oȕ,{~d ԏfm I*"Ә)[lZU>ƛ>y.*$Y䷗֘@cpiŀ F ' Hm)]yug[ɰ `bE5؈Xa: !*/V%XJk\7x&vLG~:yk_n(HH#WCHjg_;{'Oz@>2OpD;vBdo>Xʭmϳn|śԗJ4sP'!D'Gʞ))$쓵Z!MB0Q8oPWAvVA`CTx97ࣆlm\u%7ss"{ 匈SIR0_mn>C{%;Fq2*|/~QK1H`|r4xEaXB!*V+,PQ5& b욒NM@x*_5@,bBQ.P B)K _qI th2 "PY+$q[Yc.8u;E.ȧ4KC!yRAѴ t] 8o`}pܙCk'2%UkeNqM̅]$PצO"4 H`*.s=p7J0\. dTR,*=`-&C1DEz7\nnqPw#.@#r`h!gr*-[Fv#(8-+E*<}+șaz:++@/`Ciҁ.LA/C.4ҁRtI[z\@)i)1^!.wX =°9bQe% EN+k$H阤I]GSz2*]4F^D?ְtTNRrE7lR:AKсfD$pXPȟhPXGʷYE$jTHw`o2eEՀ0SG`P.%TtʭR2B:4INCgğԓ'NFrV-H%mVJ /h* z)]~UdTCdR-t$zjWb$oǭY.87ZJu VOC @Hn=(Y s3$jMմ*t pkk{PHWb ;6bP\N. Vǂd0*%J)q%+5(:$w*jw}ar $7],r- *cv}zG#ƕ,H⎤+h@H@IyO9Df_rBqO~Pƅg߱{,^]'w 2I#dی߹cCh!x <=ɱ°kfNJl鬓P 0x:+QGe}gUƳ*~QXP- p8 ȳ$"ix;4iBk@%xEcC1f+L,!񓕹 `n3[a|60txA 'x׈#[ ܚ"R[d$q'C SL(R,s' H޲xm+pe:e?[DmaL؉g]0iA^.1 DQjLYMi~戉PiԻIOOр!J.[ъtVAH]rܖɥfэ P%s &׷ pzɴd/.pťhDEԔ='Li"_}w2L`ox;ѿR%dyJ@KaF)fF-!-n\Ŭ ~-.wz}3 H %$tSg7ᥗ] sO{q2BAFZ}b};Χv'qqojE;.Iu%*U珝o~?͓+xDe<&shm84كhs e66O?O?ɡB*\\iEIYv)%\p_5W*!T]xSAkA"DmxIHS<`X"Bmd΄نx٫'? rBWvI˒{~?}]o:jGkuBp5-îu\n;z=xoG{Sm75hBw ՃKxod\& b/\L=Vhe`Np3BE$ }Yt ,0h_JUc͈NAi]A76o̰hfhtQਕPf7v]{{t~қYEmĞCl Sj8_ q|oڟAƙc88}|܂DI6ODHg㽗V'4zkOˬ䴧|VFC/cxd_NCf Uja tufW暂pc&{ȳ;OiF U M4vU dn7x[g&ΛY=r0rgxi H3@˓Gغ2RUx Dx!~|8̝\ f$$ADxi HJ,neي 49Qę !x6m3F0SW6COE5%M~ͿU,%xi H_ RKN\~V6mr4 |x!cY${IUY $K]x)d|N?4.!-^x/y^rX8rS2t &aiGpM^ƚgtH.PM¦,#6ـ.y[(VxϨ6%ld[$ lzx;/WrͧY9$sx72c{GلfԑgRW[/Imrs+2>Vx;/Hr70m>4ٗ9'3i"mǦ ggi&o@RwMu2?d'^H,x7:QN*( V9gRW[/Imrs+2>È_x[$Eb`Vvꜹ)E  *OaSĦ Ģ{ٔ&bSy&uulacMe1xiC Hm WTַ[:i; `xMAa-on{9100644 t0202-readloose.c$_ r |`;s E `x[zq5z̼ҔT⒔| ;.$TԢ<4ey@hZ+KK0EK* RA ,v56{ƈ1nNb4arv< 3y:lx=D5 $v%|X1Anh/D@p 5"$3 I@܀qtW7dUoU?yw9ʛi3ʜ|.2H3N$o{=8w KƹNBw~9n$C>we!FyfdMY@?bC+Fؑ3ÏRaAވѳ֮;Y)G &2%_Ճ2!xWvtP"ܘř&N$E0X#YH7qkb$'g y.qh Xf%"wv@`[rTMd{oXR&Cq6FZE~o4[ۏc` UOJ _zx:N=dHޑD>;$p/[R檠f$Pݢ<C4 F2ʓ~)h, 8P)Ngΰ V5d U &bLi i.8w R[gV'( HOڑF\苹 Ft>b40C-Mj-#r6Wv#(8m(*\ܨŕdѰLG gr7ZUJ+@/`ӓ!δ8t@%k W@9sYmkZ[}I\s6io`g[V100644 util.h KT?K=F1ӓgx}kf0^lMx;s{FLqn x{e&y ˘m}x~ѧl9E g|xȵ Exi %fSWr8jز>2brҵ Kcx6m *nB)XCO׷ϝqOj ~j x*4GhFnx <@+CyHT愓P joxvu¬o?q0xi ȑU^WdywfBF6 0x#+vDA+Bi8"{$4/,xs2mlQjMn6OIMOI56HI,ITVLѵL65TQ0TR0,άJ/QTUc U0402OW`9Fזq\=$&'˛)hVKK/-ΊDSXAW0VSsF QZ.]d'jZO3$(>y:5 T54J3RS34 @>M,DM hct7K1Z` Dhbif^0-H%&+!BL'7ȿ012PR@iR=sxi Hb* ;'[er԰ Cx5A.䦧AVtLWʐ;髭Ҹ 8l;x}k̖L{xi H͇fnElSyxE9RK}|B-q100644 fileops.hGQFOQ%!yxMOJ@I$B׿"! "ڕ\,af҄ILMO 9  ;)ܹfZAw}~Q4C˟Շ(\TKn2]SX+Ld<x6VFj)lte],'\Пk~$lJAjWLx5R`9LcEm !@IAȝ93Y/NnEz'#FRՏuHEP\ i ;M`,VXR|r7*x{ؤa(&.Ԋb"ĒĊRKJKK4@: jI2?+QH,IˏO,J+D,άJ/Q⋫ Ziye) Z:P4rĢtMj<[E@\.A Zx550K&Uʗo.s`dlï_Q x[$~,͢7[qd0;xi :ET{窽rη~Fm x[ͺuF6o( 9۩:w+w y`xۚ>k#sUf.mM5' xi s3ϒt) [ x9OݬW\n#R@.|pjjԼː_O8x <Aq弗}x]a!ɓP wx So."@QgDax)8ApC#g|s|?V7xi HL9'ٷy$?eg ux SuC#G陓gD~x)8QpC#g|s|,_nd fxi-psS-2Lgj|Ξ : x[ͺuFA b .'ts]+K_xi B*du|/~19QP [xE9gǵwɌgm=T100644 fileops.hrlZ2A/v%El8xkRܠa/}<" lx;?י>#fxi '6ҳX~X1v V /xVam^o(8R66QGbRQCu100644 util.hiS!=dR0N:X&%kPx|yC:z"nox{uL34lkx;sLk"Vgxi t+>|2YN-L)&@PZ\Rkn;";ˌͽ9U1eYuxcW]Sk.*>100644 fileops.h3jNF'Q,1;y>40000 gitR4 L,WLr%ԉCh1 '-x;ɿgd5:ʙy9) JEEEzJ\̜B%% @x34mw%)iyP<Ē bM .TE%P) "ugO>ά^3 :k4lJK@UrԢ 32/hT k7d͛EBx[sk"d%Ey y% %iyy% E Z%:`i9Ś\zRKphOIմl<{5f+X?.BxuSMo0 =׿pM}-͊EK f2 )e(cD{z]U;*c[t&>XP#uɳlQp ʼnR6V#vzd#Xdna!Mtd*sݭ/]-/n:T2HAS9(gs 4f KFP>^y/AwۋQfD9iE^x<J1ta`O#p%l% l$qbAk m{A K)dv\|n[ G~"eKًP/NIRhTjOfud_NS.r݂5 Lݲbr}`=9'q~h8#)/Z ;bF SYiDJ0- ͦ/Pa=^KهpRns{\ R-[lXj8x{IJe?3xi 4soU\ְ-쭉(3~ٶF9M!%/5GA'x>u6d绊݄2N100644 util.hiGx=i51qUhgnx{ϼ lQx;cf.fk&j x{2aƟSxDV2RϞRx"Q51'jbdFFUQ'`Oxg7G`+[][U7?` pA=xibV/~^巙X/abk hx(zJtF--66x٤6ww-Qxi y+ݺ)F܌ 'rx!x]?Z,"BF*Mşe-xi 4&`/g%{ߍ>]bb %% tNW[w3]&]qxx8{M: ޔ'zG¥Nf,pɦȒ/ÓgD֪7xȼyʼnO&3 M^LRIx(qt^rNiJRzf~IFQjbniIfN^d7oV )jx{yBƟssxi }#_Z X WHVN09QD Xxi;k+8=WE8ۧ4A]YmRT#i 4Tjr␳s.m=!ƾѓCQt;Ӿ<,ΞZ2AxȼyFɫy&WM|RZ39QfVFE Gx;tiH}w5lSS3LvJJ Kx{yc dmF1,!A.'cZ49Yvr/X4n?xiC h WĆ59bм( }x{̼y.kL QcQ@J7?)Kwov({RNHQjbdF8hr$c3oxi H)x i{K<]{{r -x[ͺut&|wI]ASCܞ(Y19x}6`Fɫ7321Pvxi ȷlٲfR< vx[ͺu{_w~>CY LLR2N>fmґ2vF/ZO]j2sR R.h8T>}u9 3˾{]=Y*Bzf Csgʅm-۾( qV˯c3c#^7Ckbxʾyrs jmxi*>Ux{M~d9L@T6(("%i%%Ii1+$3?QPRwRH-*/RHKKWҟEEFAC)MV!71''?Y#'5O{*~Ѭxl8ٛ=w^!22󀲩 e)U9Yl4YwL>o&K8x&E~!gHFY~ffg )x"E~7U89kj44Jl3Kssr5rR& MNe,?9-|M1 x;tiH`9k>Pt*[yk줉akCx{;wbJpx <MEMu> P T(x340031QHNM-H,`p-v\^ΗCbs ss3K1]x?oŝ$/*{z`󡧭)}]]a6Hjjl"K+Ԯ&ϘjR򋊁v&=#ѻYjݜlj2N>fmґ2vF/ZO]j2sR @y\*JLVخAS0r}{cw+}۾^ PH,a\ȫf'J=֗CH,Z.礻٫n}/ۑUd0l.<;3s>ڟ42TE~JЈY y]t} 7O)L*hc l29BK/*(J-+O*j:U'볇}: /OoXl &Z--iģJ2RStKK2s@wҵisła8DGlƦ2Ar~i:s7\vbb*AJ*\'_4`BJjQRYP\X Ulľ???G!=$(ȞK5x1xk+2BzfI|QjY5C>gHKrj^Jf>x+g$G6̒Բ {.E$ ]k'xsg}?X+"<1xRJ0xiN> m]PQ^t 6%I(!|—0IjmǼ$?~_!NAb!E>4#љ%J*!A2EH,rH !,<:FcvJ#k.$M%Ŋ2c c{B1g糙JphJZ2 !Z/19cl,J0tU5]fmBJ}PC&yV P,(b.Hꤝ̵Nv3ȇVƚ1[S͗lGm`3юƮk_-W^5]c;CwK맵w#r2BUlO5cx[4tfIa6Ĝd"̪TmCMS9Y'/VuBL J7x <+w:>9P Gx |" gTLГi^x{z(t/+KAbIV50krDh#V- ֜MJxi HV%U}<ӭr|)Ӛ6M~r Xxdd0Q}z=6o7c>yѲ kx;z t<<!~:xi İ,Otԩ[F Hx8{⷟ 7F2P!;%MF(]}TW0 57x[iBdOFLf Pr:x;3t7SfNy$xAmxi K)[5"m(3h8v`E'OkB\$xt8\[%*˧aAgT100644 errors.cH3ɫ ǾQxډg] 3CQ2P!;%MF(]}TW0 _42wAx[ʼiBdOFקLf Jox 'eŬ3y?d&͋1Ex <eO_wM5P Nx\9i Pm@LsפmP7100644 fileops.cEV +\3 4Ւ:Bxxq*#.̤b+]̢̤Zݜ#.紜tJuf^rNiJ*H Gqxi If?kx|VXBIjqI1Aʼ7cu{/:Fx9/hQE0Mk~a@h01CQ2>4DN {BAzxtDɾ6 D:J/'akx۩zWq! N.xzo3ܬrFjlxe~4!nc3#\vxS@cĪQ_+ͣc .4v1AK<*40000 testsYNuV-d](ll5x;%zPtC TTF Rk7xd=ʲqropjxe4xc;#BN$x <d2IE#[H\P Qx"ʧgn1HؒJK_R;x&C~;3KY~f}EX.l % x:5'x<> h4;IZ/3V΀+܃C߷R2>hxO,LO./)J,KHD.3 wnx;%IxmϘLff[29sd7 x;tibIC> -/v>cAx;%_`FNͧY'2ON\8ٍ+ 8  apxS-obRǾKE4\4GwӇ/Yv40000 tests yb5[M B׬.Ds%7Ox;%zY`F&4dt͓7feʹpW2{qAbQq*&IMlDx,[`CyL[Y# x9]]; @{2WA“%+=.(PM{1}JP7uqduFؾ ?)x;re>nw\_+ΌL #hx6}`DdyvF>TT.l-9Ѿ{fBzfIZfNz y) zz3 ?*x"qIbMlqLغ7bUqx gTTҶI\  >n.x;ti0o$Wm7Mk_nb %% ŗZ}qOn1bx9/]gIӚ|\#YC.5Ts,NK=U79W;x6}`DdyvF>TT. !i BqPMx"g—ɓ뙌 61]fڬͥv2Yx; "sN̒x ]X)h嗖($(g祦($g$)hirUsq&Tje(u3R`\\'gpxk#a x{xqdf^2CgjPoO9 yҞ=Bkx[~RffF!>SAx;ti0T`[yڃTݼdduF ^ x9/Yf\\'N1C.5Ts,NK=U7~'x;ti ^y/]%F)@Dhܬ +x;ž}33KJ~jdfIC)x7O &!r: yz\DeLyQdCӷ' Fdx9/E_DU\n5~L%C.5Ts,NK=U7Ux;tiHͳ;3g[['֏Ĩ׊ R[x[ž}.hJjBpcPkgp|PL#ܣ }lxNYU|Sj I𑷐ѻ/x{[&ĢO;Lx;ti0H͡6G=zZz"{duF Kx9/;D67K|;QoC.5Ts,NK=U7r x7ʘ@X{,\|owx;;`q/\N"" /2x{rGeU< %.̼ҔTYy b.xrMeC#& N[ l_ϸ4#_~RV|rN~qFzfId. "CxrCz$8a̼ҔT⒔$ Yyב [#x;ti0H={ZOW㑿a%>r: Zx{Wb[D8Qn}:V;100644 fileops.hVЈO#vVX40000 git)m_ҁ _?ؽ/q!C.5Ts,NK=U7I3bgx[+uAp j1x[ssBF.Ԣb ɿS&_grŜƸY Ai]x;4iBk@1x;ti0U52ܺxUȪ  zxE9YՒI100644 fileops.h2ֹv~P/yr#g% 7bg_x[+uu}& =`x[ų}BF.Ԣb ɿ'_cr8M tx7qb]Bs_2ÂVj\ i^SUەmE$O' $x;%:WpD;y{(*%g'eepq;y+hCdU45<\(%z2620 ah<)^AE M.N"Lsj׭]&?fB&=UmP{\&/-3]/C/3*[:7%U9~>2,,(hԅ ~=ސ]M|-=[.TM~JPku<%g׻kM{Z5k 2fJ4D.{y(3vxս3\ikK8\6.J-+O~Sq}j׮N*ͼ:;PE%E)%9 <˿#_^1su{B{k!?ʪLs߰Nbn*fR>QZ5BM xSLKIMSs uqO,OKLψReRK)MIUP;8;8e(RR2Ӹli3xrDz$#jxsgD6 x340031Q(ˬ`ph0;e=7*^ x340031Q(ˬKfRp]_dGڳKOo|Lw7)xj17$>©Тvںd6"ծ$N@I22BW}>LQA(ns?x(s9X. `J1+›.b mQ2H$W.tU o0>]?=ӣД -$.%ΓXm$M(+Y<}鴇wG$I)&X(NbckgLuaw \! [4pfȱG>'Rr>x-* 24%2?G[Ѯnd-[ @8&:JGq%]x.Lpr͏X37'3Nf,gtxBBL~< >U-x.4Spr͏X3''L~g2 NeC Kx;tiWi_;"OmW>,5;9$ gUx)I`C =xs! ?z#rj摶u$hx葛ɛvמWlx+8Qpf TVc+x;tibͣ:V{}=0QzJpu17Oj89u9:KxAwJ)!g?^maMjQYЭDFhF7xqlTx,^tU7Y(F^x[ͿuͷY2Nv @gx7db۝Xx\gԇҎ?X6l' b^lx/Z` ffsV",?xryBQT>~&@Y&~mŤ Xo?Vk-SEi&xqBzmex"ṿ0zTL vAA"Ek2x[žmO Z6Fx;ti03]fJUsOMbwc D Rxf$Jٵ1 A~&i\xxqBz%Iqx c?ϺUk̓' ]jCx> 31ubWFAbIqiRq^^FyfNJrbQBqQ^&ć"/X2Mdaws|y  nxx?!mc3&v=WGנEsXmWx:,ٟgrl1j=xx?!mck';Y]x7*p^ŋ:t&Vg\ԐE&.?g9e2Bi' Ҫx340031QH,KfP-:L @!=a=E3.znbB~JP{ߖxjsk3gG[d<21?XǏuRnC@/fkC 09g/(<1'h&O~ЂҒ̜bʓMs+Us8!w8g36 S-Kә$? &q^x-$100644 commit.hŮ69z$x;ti0(ג.J4'~~: gx.})ĻB~ jx4i¯*_ox^xGQmȝmlmxʷAy 8Ox340031Qputq bbՏ|~,q =E!TIzfIfz^~Q*ò~ ~ps:WDEή8Us'̂ξӊN\`,++ sg8qsg]t{| Դ̜T .vwP5z)y S5X_^RoߪYu,Pe@\XZ_T K~YGܚ~2sJSRnL 뷅r^rVų *6Ji[*nBdKRK/) sw\Y%cdݽxO,LO.K)MIO,OKLD NH` x7!=3/94%ubH?Y1YQIY,9?/-3]/%(XAV*9ѕfULg0biyB֗0,F7x31RΚWdo [x7 x340031QH,`ʡ̖lPi׶ņ5y@5 8{I}|Wm`槧|nph<0e)I@sZhk)XN~k70)@wrtt 7;L @!!ƫ nZH_[)TwQjYybN6ЄnZƣB+n|yG޵O.PEU9 G$KnUyv΢Olf?Onlx[ͿuͷY.0#` x340031QH,KfP-: !jS RNN~S_+~9;2 3!:~zw^jZPBĮmAl;L˃.J-+O0I'w7s- <sFMx{i8>gcLN?s{OyL @(a ou'軽v<ɞ Wx31vѩ@Di_Zc= x340031QH,`cVe/GG?y÷S&?Tq4\M^Zf^^f˶Ya¡ud@$jۣmb:aZuݸOdܝ; q3V01b7T?}k#Mm ˦PEe9@ζ{LoDfϑ/*9"Iv_rㅭʳs}b4(7pk1x%t]hCT*x,0GMjص;0Tx{yuj.̒$$kZk..@QjY5?dE,T |VILDx{i8ћ]_Y~mOd(%3|jk=+XdOFx31+S.N^T/굋 xx|3΁'R@ݟXq.ʑk;x31 B ILKR ,LEO,0GMjص*x;NhrX7QXCY x{i8ij?\׮ab[ܚڌv x31ak6*K%ikQ;p dx340031QH,`OD\i<D^ڞ&?Tq4\M^Zf^^f˶Ya¡ud@$M}8mV 7)ۦ4uK 3@T?m+7kU>11b7T?}k#Mm ˦PEe9@^ i|ɶѺ?aɒ/ULK*9{LB7Suz\إ<aolZx(t_h?,&Ԯx340031Qputq bbՏ|~,q =E!TIzfIfz^~Q*ò~ ~ps:WDEή8Us'̂ξӊN\`,++ sg8qsg]t{| Դ̜T .vwP5z)y S5X_^RoߪYu,&@S@Zڿ6׵kؖ|4(S.X_҅v %% ŗZ}qOn1"'.x(w|c9˜>.x31UeOW.jԉVS3 fxqg pxǴix5\5yӥJrL @(!\*u@⫤^eHi?9lZx31sA>V3\BLe|&7( xqBHM|ܥj]^kdܭmbxڤfV+FkSZ[x31y0#d|\w EO,0GMjصyj.x;﷊grXlYK&+z;sqki)&))$攤%+$%f$&)hsqg祦(#YsZOWd,ܡ7y{QjIiQd4'xǴi,xݾyiF&@P\6Kݤ⦅K/G|F&1*7ܮx31II;}nlyg%[Wr |xq.Ɗt)WN~^5c9U x340031Q(ˬ`^=GbW?l\x+3WjC֬ErO{YG)xo~ʚExxm %x340031Q(ˬKf(W8gcb+s-Zڣ #^xkX˿a6 MjQQ^^,Y52x340031Qputq bbՏ|~,q =E!TIzfIfz^~Q*ò~ ~ps:WDEή8Us'̂ξӊN\`,++ sg8qsg]t{| Դ̜T .vwP5z)y S5X_^RoߪYu,&@S:sYpc[|9gDEqQ2ïeB)wT'|"۴}ْbK-r>H']7WVMx31O|`+hﴱP_ .Gxrz<$);U%x340031Q(ˬ`a1at3uv[&22)x1N@E%@J@Q$((i+maw J) qE.Aͮ-+?ϭٲ鬨׷\bd@P(Q8j54Z&F.~}8sͼVwR%  `wGc*'hC"AZ3H_<:38aP/ Chk5ӅLf2PA5ncB C6Z\K):*&تQUN EhI&kCev(n3+O/a|J(;OgMh*47|}MZD(Zp="5bU|Cڡ9YgxoW 7vBK5ON%ڥx340031Q(ˬKfh4K^i% _3ͪɤ =x[˿g>̪!iE ֓H($hZsqrf)h)((Mɪ L++M(J-)-S(kj6 =&PB1`xǴi©M\ i?eyyH5(d%甦2nzW6Gm=8OCT%3Ln?i8ϨasoA%<Ȗ3|;mm8xHR4Pkux{|yJx31k_mV BxS4`r ˽ AwLHU1@zs*f)[Lt40000 os3cZdR"cB&%'lx+HtS{%x,MpC0kDkHEk..}--Z-}.wϐxW?xWg.Լ4.x340031Q(ˬ`0𧊨ӊЫO vl x&Hj;hVi#7? x[qBH@UJ'j]#c4'i tx;4id.c%&?FIae0l&WS@t8AZpQFcKF̑')gsx;)sB` gwx\/a=7 XxǴiH .eSz¬;¸t x9ن  ["ˑMsKonx;)3s6ܛ籬b3,IxǴi5k>%R qx;xqGf\mmt-} xŽ_$$>9?$5Xi V+YAiyy\ʙy9) h8RKJ j<Yxý#58$>yk8YZRZ``UD #x3ҚQ*dCsvD—5L:Œ<xw{C 7e&bU(I-.)񹉙yz\!񾎞~ \\*!>NVȒ9Iz *.A %!@U0`P) =! &'sq(8U*)H,).M*.QPQKQTCrGr~^Ij^I13Tg7Gwy9) .PGp5au2 *6)gqq*覡 XAB@m<"sr Fg{%|x;8qZȊw3'IS xǴisҊuHqg[`}3>{܉ x31-K\QȲw%t/:xqHה;_z%aND l xk#a>f/ x3c`ƞ#Bc֒*l%{wB;h->x31w/aedGvZS gxqȌ&oN:3r\|D Ȫ x340031Q(1d }{0Ͷٷy9+6*K-.Lb[xhv [lmJ{ K)fx3ugqQ3@V4lEƇ^Pvq= xpes:Z&wϐ"[B@x7zm-an:ꑷSlJ ~_UՓ 1))j]x}{F5&x[qB!%M^I4$qbQ sxk+ dqIQAlBBZQ~n|FjEd 7xǴi|nuzX}¶| jIv4x31mMnc~6iպq _x|UK&Bc (llxڦf>^ vNxN5x_Q "㭻 CIZQn!QF H5WتDX웒>^)xO,LO.K)MIO,OKLD.A |xu!WbNBNfRzf^"WrNjbgQnBB(Y_K/rS[L2V *N^z8U44́*ch52OVpDٹ܎@40000 src2؊zHV6Ρ w0xO,LO.D.0Kjx{2AkŦv'2VONcXˮx31=*ȥi:)z"q56 @ x340031QH,`y:=@~AcחG jj8MNq{H6T׍O7.UTz|K|9r&a9j STPՙy&jy=O TAQjYybN6Pk!/6Z',YqvExk.d&|!N~.>9\j2!E,$׺K>}`OW 3^8 STmzνu޴ϐ5ԲĜl3rZ-O_^zsUJeLx;#Mb|v.̒k58A")/`Y4VA~~Br~^qTd}ٓpIo~e8YG Rn^x&_tC\6q ʦŨy dii!pxVMOHW(3{\0 -;k;0"@0hv 04{u^U*Wň.+KjSRZTq{~UۮӦ*oZ77k]e͞6ٶczhg1QTfNT7f ?4ϺzdTfmUڧwεd6rS@o;eqS2Qe:1tK%hUu`3/3U凞)Ojûg /gG4ZߪY2 4:l_w 6mV(C:KTVg|S f+hMF!"g4-ZqU!6C*p ۚnpA(P՚Mq(V9+DpU(F&DދἈ;&xGXnR恈€5(Lc9YN'Hb ^JY]|p6&`P42d_5Y1ҭx9郵:i0‹S/^Lea?uğ{VvI܉0ƛE݇"F ;p֛̅3 ?G89& KA@\^0fv#ޭ7 e QEmvINzp'AUȡ,͐8FS JUujZN+3jeLW1*H}G_?oD 2D?GltvYAݯ^:F Ѥ Zos tޥ7]*zޮ JmkˬSšpJcc0d6o)^qsFT sW{mϰ@Y]>}i=v.}.7 }uZC$\WNzKLd}ٝ kzfh ъ>}qdɪƔ}XXxKdv:5Tޑ.~!OG2#lr~^wރŮ*k'߸hCc@.?T"ژP$zu|uxx(*!Qs{4fNN)&N̒Բ܊ mx[BcC~r~nn~^rf^rNiJRzfz6FkjxPn9oxRj@=F47_J =!P%KSpr(4v((E??tvqKvf̼d3rzL0NS2d>YΉD1f4V 4@vk7߶ך(7L܀IA/Ŧ('qQn"WiM2*u`On!"lbm&ZWike%l>͂+=V xі)i6%KeU"8^E5ŪY%]< @PfPCPH++RsaEUDzN`narTUuuZQÝYF4qYHB}xиܢ0p~qZ\gP 7*dg/./ށѐ*E>uxhBE-P@l %?:57eUE4W׬_)gWdx0;FRFo2o/x,rDdC~r~nn~^CZfNBzff6>ً͓2& rJL|:YP-9x[+VjC|6q1$ %.̼ҔTsؤ7`+e[3fx340031QH,Kfbfl0v?}*&?% .12}uNZ[d|.e[e>:-*(J-+O*`\d1q[٥% _U U8gxTn8 =oiiS`Vfs*\[iV -rf:Z("#囫\;ǧ07Ϧ{ I!x0zapoLy}_a|7$b8Ottcεvo0 pٶxOuqbGh\Zb]go ob8jdK{5% ۘ#}+)͡;#{'3QxgL$uؙ>oSqFz c/ͷl{;9lxgVzfI|r~n.L@58RKJԒu2Sjm=xg.d=6o$M0|xUs6=bK/ &dl16PNEPk,FtO2oz!i2 uMFly#S*+vFNDSQJR 7t7;A{mG;66uQWjJa1<FI:Y7UD8uUj!JT.(~F%*uؾ `kqN٧Ӈk1ݩRzP-Հ(E+)BͲ(2AS.L @'3\Yj(N\ i:N%ĵ(*r6Gi\u7Y-H>Fu6#5HaȠhM >vMl*X~Gݝ\=xj{q$K;oHR B ׶7(KfOJ<2 &EN$ Y63H<"Op73$6\,(I/W ~sy6AT<{ "9"sδɌ, {aqNouRhI?PC y=$#7[ ktƳ6c#ҟc>Eʖ;,Ɋi͓$tg,}˞m~v̨Ș:e<-2,qҴX<5<:Ɇ_I \am$F/l9f_ {3Çk ' ܆D{g.=|9S9Źx~UMYإWmu{=ecnx;7;Sfd1%x;Ŀ d7KKt83KSRXfdbMn>x.f=.F#JxV]O8}&}iK(0#i-!Z$Ueg{(f̓=c&{=zdTʻY]Q)*QDuTVu)o,r󔖕 SU,D[M2LRei)+R9I0LKA QfEJXz#32SIRU:/kjސ>J˪:[+xbQ^2&dEs)͢yf2e&ݟ2A S@jg2 gFLˆR"Yf"S+J*SRעzvǦs7(*"3P䈕 U"˖ FGmF> KEMnUVST^4!9{\Pb1*O׭ZD7$"B^[\xH]X#ǁl|(:,i^$mHV{~, ]<,/,4U:lwpoh0#r.cJO+րcfsa .+4; oa:Qo 9ٓ)$ ˆG|ȂsnX廾:SDc5LB-^Ă`2uqpB=-~U~0bİ({k@;ڌDUm% ]>dԮ.xȺP-_5Ӎm%~ӝsq+BAA{>p/2OK;Y2ݝm,FξFzMBp&OLquM_o{=WZth$`88z̨>kFmI;jч}l S[@m (i (m H4@dž>yuɾu~7>Z=[]㻱%86G1-]OQL;{U],옄,B]4-BJMbjNNKѫʚRg ]iȣ.{P}7zrwGc3M/H! c6OlxJ=j?2%'&a|kFWU;\,;'x!IbBzfI|~fJ|nvqIYq6/&J .x$Zb.f=K,Ly93[O#3xuPAN0! HȉBąS/qi-8 Pďx ^{wfgwvϿ.>ɈR/ _ˎ `Wηfd p`l+/+L#+߅/!,0EvP4Fv%$M Q!Ӽr^{r| L24>3>)  \<66-uCxH6^ #dLGko |ⵗvqBhYFob"ʬpK?g`({8~A L@-co.x/pM`CSfl3 x&pH`C 6ɫ|83KSR!ԲĒ"aUkPB(Oր0Y]JXA Ga m9$T7)cx;$o/mlL֓߳Isg$)h$M6fM [n2x·o.f=66F! x340031QK,L/JeP7>V%)~&O~ݺhQj񑕆o72٢al$/ؕASN;;2\B1cA&fe2tjo"3a.YeYI,KɯLOc:;{ځg-1KT8`tr9g̚k744~Rd~xk(sJuZfNj^bnjm|F|<rf^rNiJRzfI|r~nn~^PF_KSAKEaFN9'Kxb<(yKxՔX+ x{|y6sqQFrCx340031QH,O,Kfq}ƞ68%W\=s! =V?/N}aȖt`4uy@u'ox~ĭ䕅 wM8I]~Jҕ ɖLO)-qh22N>״KEvf!+Lpq {]UcÆc{6)`X/qQzo:@RTZV 4wq ?Nlp;m|b7 O=Enّkx&_t<V*x(* fNN)&N̒Բ܊wqUnzx$Zb7SffNLF+K x,rDdDً͓2& rJL|:Y wxxqQ^o٩MvKA}a s3x\<x3ajLh(e=lP=Iqٹ֋?NY100644 git_revwalk.hZ7(L`kEZq%[+!M(x9r jRt Mlbx(B`C#Nx39K )>6Ip쭱Mx)D.khO=@Pg/;x(ro\y) y % iE 9 %)% @A0'%)dƯ7`US_x340031QH,O,Kfx׺pˬ%Q|9o.uS>l[4uy@ujgۦv5"HVtr&Dzqdo^ vk 互ʂT+^MA/ra~i Z)I: yPet,* V)@ͻׂ e0#ȡDv.lxqJc[ؘ26q ͲA4+0]b6nx!^b7Sffn\F+opx,rJd'SffAN'F*nNx39` [cMuK 9đMxt_V:֞y M7 ;x(o\y) y % iE 9 %)% @A0'%)dU&%(4M$hBJfrbI*WqirrjqdW n. ִ̢,FH&a1J-*/SPpFLx6x340031QH,O,Kfx׺pˬ%Q|9o.uS>l[4uy@u}wX8O:oxO\.?% h𽐝jU3 yUlY6[P. !2o;I?]B-*I;N=xao6{SÎ)`08՛/,x?>$EEe9@Ӫkn۳IE1e, 3V sZjV\A %_E6Ol1xNc[y,3xx3ljΎ()gTˣ1q4`5aYznx_uq%xb<(y'kUSFm1xtiBH&BžuZ_~ʼnΤ$ox(Vt5d8X7R:(x3f*i& $aU57@E 㑔1Fwq='fg|m4l0xżycs{gqQjF @xǴqbW!iߟp<=Pt jrnS4k:x{+DtC\R/x9~xիJ ~BkM[lBx{wwnL"?5sx69~xիJ ~BkM3)ϝ&kF;ӓ'xE&x|ycs{gqQ@J_U/JHXIxxqQG5[_^-xĸq<OYhq@T ^xøqB ѵ_;X\~uuYm^fk/xyF}F{D!^rx@v~ҴT1nxCJxøqBHh_Q&/:-uNE^'we2N>+[aixĸqB;-Օܔ)Yf|P6eK[tN̫vUx̼yFNHwW?[.6iBcxĸq<jZEt_Zzߧ Z x340031QH,O`ŖOR1f~tC$dO8\?x(hj/)`89e朹a=3?nIx_{H(jځN={Bxe0ڬtɊ?g~vτ{DR!Tx;wHzfI|QjqiN_(51% 19;5E#DG!%IG!3ES((O3$>858ؚ &fBN~~q*\\S3=b}Y| 99pack-d7c6adf9f61318f041845b01440d09aa7a91e1b5.idx000066400000000000000000000023301216214232500360700ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submodules/testrepo/.gitted/objects/packtOcA3ػGAi[l\of̌ŴnP) 4$ŀuuO|?-Y 21]iazošIn* 0ؒ!ZqSڥ : @0HD:3 w&Ⱦܠhq$neSՐ;dڧ/pack-d7c6adf9f61318f041845b01440d09aa7a91e1b5.pack000066400000000000000000000007531216214232500362310ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submodules/testrepo/.gitted/objects/packPACKx] 0sk6 "xOnh+^ߢ7e>Ur;jes6dϝyUh]&A\jf${SbJ4c[McreG.bvFIUn/&~w3:Dc x[ 1 {\@K#x&ME5_7 *9`T*!5)inHMvHA˦…cÓp:߷<B,i| 6x>fOo{8x340031QH/H-+(aje+kt5eũy)`UoVc&'zhִu=ٱxL-QH/H-RHI:.;x+H,QHIx340031QH/H-+(aje+kt5V ?Ⱦܠhq$nepack-d85f5d483273108c9d8dd0e4728ccf0b2982423a.idx000066400000000000000000000023301216214232500360350ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submodules/testrepo/.gitted/objects/packtOcf:I6qkS2rvǞ[ c6kȍ2:}f0mϛTVR3P$B =Њ 0*JNd>1dPx I-.KWHT(JMLM+(/W(OUHLIsRr2R2RR/x340031Q(JMLM+(aH6kɾzږgR[>ܵx I-.KWHT(JMLM+(UgGҚCWN(N,NJlibgit2-0.19.0/tests-clar/resources/submodules/testrepo/.gitted/packed-refs000066400000000000000000000012741216214232500267260ustar00rootroot00000000000000# pack-refs with: peeled b25fa35b38051e4ae45d4222e795f9df2e43f1d1 refs/tags/test ^e90810b8df3e80c413d903f631643c716887138d 1385f264afb75a56a5bec74243be9b367ba4ca08 refs/tags/point_to_blob 7b4384978d2493e851f9cca7858815fac9b10980 refs/tags/e90810b ^e90810b8df3e80c413d903f631643c716887138d e90810b8df3e80c413d903f631643c716887138d refs/remotes/origin/test 763d71aadf09a7951596c9746c024e7eece7c7af refs/remotes/origin/subtrees 4a202b346bb0fb0db7eff3cffeb3c70babbd2045 refs/remotes/origin/packed-test 41bc8c69075bbdb46c5c6f0566cc8cc5b46e8bd9 refs/remotes/origin/packed a65fedf39aefe402d3bb6e24df4d4f5fe4547750 refs/remotes/origin/master a4a7dce85cf63874e984719f4fdd239f5145052f refs/remotes/origin/br2 libgit2-0.19.0/tests-clar/resources/submodules/testrepo/.gitted/refs/000077500000000000000000000000001216214232500255525ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submodules/testrepo/.gitted/refs/heads/000077500000000000000000000000001216214232500266365ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submodules/testrepo/.gitted/refs/heads/master000066400000000000000000000000511216214232500300500ustar00rootroot00000000000000a65fedf39aefe402d3bb6e24df4d4f5fe4547750 libgit2-0.19.0/tests-clar/resources/submodules/testrepo/.gitted/refs/remotes/000077500000000000000000000000001216214232500272305ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submodules/testrepo/.gitted/refs/remotes/origin/000077500000000000000000000000001216214232500305175ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/submodules/testrepo/.gitted/refs/remotes/origin/HEAD000066400000000000000000000000401216214232500311350ustar00rootroot00000000000000ref: refs/remotes/origin/master libgit2-0.19.0/tests-clar/resources/submodules/testrepo/README000066400000000000000000000000121216214232500241260ustar00rootroot00000000000000hey there libgit2-0.19.0/tests-clar/resources/submodules/testrepo/branch_file.txt000066400000000000000000000000101216214232500262410ustar00rootroot00000000000000hi bye! libgit2-0.19.0/tests-clar/resources/submodules/testrepo/new.txt000066400000000000000000000000141216214232500246020ustar00rootroot00000000000000my new file libgit2-0.19.0/tests-clar/resources/submodules/unmodified000066400000000000000000000000031216214232500234470ustar00rootroot00000000000000yo libgit2-0.19.0/tests-clar/resources/submodules/untracked000066400000000000000000000000031216214232500233040ustar00rootroot00000000000000yo libgit2-0.19.0/tests-clar/resources/template/000077500000000000000000000000001216214232500210415ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/template/branches/000077500000000000000000000000001216214232500226265ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/template/branches/.gitignore000066400000000000000000000001511216214232500246130ustar00rootroot00000000000000# This file should not be copied, nor should the # containing directory, since it is effectively "empty" libgit2-0.19.0/tests-clar/resources/template/description000066400000000000000000000000651216214232500233100ustar00rootroot00000000000000Edit this file 'description' to name the repository. libgit2-0.19.0/tests-clar/resources/template/hooks/000077500000000000000000000000001216214232500221645ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/template/hooks/link.sample000077700000000000000000000000001216214232500270042update.sampleustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/template/hooks/update.sample000077500000000000000000000005031216214232500246520ustar00rootroot00000000000000#!/bin/sh # # A sample hook to make sure that the `git_repository_init_ext()` function # can correctly copy a hook over and set it up with the correct permissions. # # To enable a hook, you copy the file and remove the ".sample" suffix, but # in this case, we're just making sure it gets copied correctly. echo "$GIT_DIR" libgit2-0.19.0/tests-clar/resources/template/info/000077500000000000000000000000001216214232500217745ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/template/info/exclude000066400000000000000000000003601216214232500233470ustar00rootroot00000000000000# git ls-files --others --exclude-from=.git/info/exclude # Lines that start with '#' are comments. # For a project mostly in C, the following would be a good set of # exclude patterns (uncomment them if you want to use them): # *.[oa] # *~ libgit2-0.19.0/tests-clar/resources/testrepo.git/000077500000000000000000000000001216214232500216555ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/testrepo.git/FETCH_HEAD000066400000000000000000000003171216214232500232130ustar00rootroot00000000000000a65fedf39aefe402d3bb6e24df4d4f5fe4547750 branch 'master' of git://example.com/git/testrepo.git 258f0e2a959a364e40ed6603d5d44fbb24765b10 not-for-merge branch 'haacked' of git://example.com/git/testrepo.git libgit2-0.19.0/tests-clar/resources/testrepo.git/HEAD000066400000000000000000000000271216214232500223000ustar00rootroot00000000000000ref: refs/heads/master libgit2-0.19.0/tests-clar/resources/testrepo.git/HEAD_TRACKER000066400000000000000000000000121216214232500234450ustar00rootroot00000000000000ref: HEAD libgit2-0.19.0/tests-clar/resources/testrepo.git/config000066400000000000000000000015501216214232500230460ustar00rootroot00000000000000[core] repositoryformatversion = 0 filemode = true bare = true logallrefupdates = true [remote "test"] url = git://github.com/libgit2/libgit2 fetch = +refs/heads/*:refs/remotes/test/* [remote "joshaber"] url = git://github.com/libgit2/libgit2 [remote "empty-remote-url"] url = [remote "test_with_pushurl"] url = git://github.com/libgit2/fetchlibgit2 pushurl = git://github.com/libgit2/pushlibgit2 fetch = +refs/heads/*:refs/remotes/test_with_pushurl/* [branch "master"] remote = test merge = refs/heads/master [branch "track-local"] remote = . merge = refs/heads/master [branch "cannot-fetch"] remote = joshaber merge = refs/heads/cannot-fetch [branch "remoteless"] remote = merge = refs/heads/master [branch "mergeless"] remote = test merge = [branch "mergeandremoteless"] remote = merge = libgit2-0.19.0/tests-clar/resources/testrepo.git/index000066400000000000000000000234711216214232500227160ustar00rootroot00000000000000DIRCmL?3L?3_0LUG+.HEADERL?3L?3_Q :GBG Je .gitignoreL?3L?3_ W\V8ܾfs"vw CONVENTIONSL?3L?3_IHoLFW+COPYINGL?3L?3_ȫVl· 6yDYMakefileL?3L?3_M%vS `1 h-bg api.doxygenL?3L?3_ j,SudzK-ZPgit.git-authorsL?3L?3_Bv@WEt{z libgit2.pc.inL?3L?3_!L`*B9i<Í~src/block-sha1/sha1.cL?3L?3_UjwCKj bʘ8!src/block-sha1/sha1.hL?3L?3_(蠫yQʇ^qM /6O src/bswap.hL?3L?3_tl)r:W8lsrc/cc-compat.hL?L?_1[aދ;нG' src/commit.cL?L?_U6e(1Qܵ%Ǘb src/commit.hL?3L?3_rDŽlW%qm ־ src/common.hL?3L?3_ IzC-O Dl8isrc/delta-apply.cL?3L?3_2I#| E-src/delta-apply.hL?3L?3_?rQ zYxnam src/dir.hL?3L?3_ }%m$^I=, src/errors.cL?3L?3_\ =Adx1t3 src/errors.hL?-L?-` dHBdK(bisrc/filelock.cL?-L?-`&w9rfW src/filelock.hL?3L?3_-eAYdwB src/fileops.cL?3L?3_-#aa[wy src/fileops.hL?xL?x_ m4*:>P-src/git/commit.hL?3L?3_%no%-src/git/common.hL?3L?3_eB>4 KOT!6(src/git/errors.hL?-L?-` ҖUcx4fRsrc/git/index.hL?3L?3_\X2d\ .QR0 src/git/odb.hL?3L?3_,?h src/util.hL?3L?3_QAìV\Qsrc/win32/dir.cL?3L?3_n5ڢo`]Y8src/win32/fileops.cL?3L?3_8b!`0@ͽ1 Ssrc/win32/map.cL?3L?3_i$}`_tests/.gitignoreL?3L?3_ G%%>JLee)1_tests/MakefileL?3L?3_r(C0H)Pސ, tests/NAMINGL?3L?3_6v^4I|tests/t0001-errno.cL?3L?3_拏rjm6{Ýjdamtests/t0002-refcnt.cL?3L?3_ HBW}-xtests/t0003-strutil.cL?3L?3_.gvt[*JB$1^55fytests/t0403-lists.cL?3L?3_*"L;퐻 Z}=tests/t0501-objects/13/85f264afb75a56a5bec74243be9b367ba4ca08L?3L?3_3oc@]e)_=tests/t0501-objects/18/1037049a54a1eb5fab404658a3a250b44335d7L?3L?3_w 01ּyNOX=tests/t0501-objects/18/10dff58d8a660512d4832e740f692884338ccdL?3L?3_|P@ k% {_ =tests/t0501-objects/45/b983be36b73c0788dc9cbcb76cbb80fc7bb057L?3L?3_S9M] #I=tests/t0501-objects/4a/202b346bb0fb0db7eff3cffeb3c70babbd2045L?3L?3_,TzuCllW4=tests/t0501-objects/5b/5b025afb0b4c913b4c338a42934a3863bf3644L?3L?3_w..l*̅f=tests/t0501-objects/75/057dd4114e74cca1d750d0aee1647c903cb60aL?3L?3_R/kn=P 64G:;Y=tests/t0501-objects/81/4889a078c031f61ed08ab5fa863aea9314344dL?3L?3_~]Vx1NJ'ᶔD=tests/t0501-objects/84/96071c1b46c854b31185ea97743be6a8774479L?3L?3_CZopȆNU=tests/t0501-objects/9f/d738e8f7967c078dceed8190330fc8648ee56aL?3L?3_X<%6ώ%3z=tests/t0501-objects/a4/a7dce85cf63874e984719f4fdd239f5145052fL?3L?3_66ˈP%aւ=tests/t0501-objects/a7/1586c1dfe8a71c6cbf6c129f404c5642ff31bdL?3L?3_)\H Xb=tests/t0501-objects/a8/233120f6ad708f843d861ce2b7228ec4e3dec6L?3L?3_"O5 Tun=tests/t0501-objects/be/3563ae3f795b2b4353bcce3a527ad0a4f7f644L?3L?3_uA ׃Ҙt˟nxYI=tests/t0501-objects/c4/7800c7266a2be04c571c04d5a6614691ea99bdL?3L?3_q#Cu[ďe=tests/t0501-objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391L?3L?3_Rw i A3@/{=tests/t0501-objects/f6/0079018b664e4e79329a7ef9559c8d9e0378d1L?3L?3_)%q{"t1E=tests/t0501-objects/fa/49b077972391ad58037050f2a75f74e3671e92L?3L?3_R_>4p wd 7=tests/t0501-objects/fd/093bff70906175335656e6ce6ae05783708765L?3L?3_ ؔ,vNAټuJtests/t0501-objects/pack/pack-d7c6adf9f61318f041845b01440d09aa7a91e1b5.idxL?3L?3_ tO:e}`jJL3gIKtests/t0501-objects/pack/pack-d7c6adf9f61318f041845b01440d09aa7a91e1b5.packL?L?_CS6[OM'%O%dtests/t0501-walk.cL?L?_n 7 l9yv{@ n0|tests/t0502-table.cL?L?_oaON# bW̾`[tests/t0503-tableit.cL?3L?3_ F@V_1Htests/test_helpers.cL?3L?3_, 8#F4x2<t3tests/test_helpers.hL?3L?3_ Z+DZ md<tests/test_lib.cL?3L?3_ x3 i_Y4tests/test_lib.hL?3L?3_CC@.kJ(vÏFrtests/test_main.cL?3L?3_5]@ƇZyLc@tests/tests.suppREUCasrc/git/index.h100644100644100644[QMX.pRmySM톋d4;XMQ/S8TC+psiιl|&!Blibgit2-0.19.0/tests-clar/resources/testrepo.git/logs/000077500000000000000000000000001216214232500226215ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/testrepo.git/logs/HEAD000066400000000000000000000022121216214232500232420ustar00rootroot000000000000000000000000000000000000000000000000000000 be3563ae3f795b2b4353bcce3a527ad0a4f7f644 Ben Straub 1335806563 -0700 clone: from /Users/ben/src/libgit2/tests/resources/testrepo.git be3563ae3f795b2b4353bcce3a527ad0a4f7f644 a65fedf39aefe402d3bb6e24df4d4f5fe4547750 Ben Straub 1335806603 -0900 commit: a65fedf39aefe402d3bb6e24df4d4f5fe4547750 5b5b025afb0b4c913b4c338a42934a3863bf3644 Ben Straub 1335806604 -0900 checkout: moving from master to 5b5b025 5b5b025afb0b4c913b4c338a42934a3863bf3644 a65fedf39aefe402d3bb6e24df4d4f5fe4547750 Ben Straub 1335806605 -0900 checkout: moving from 5b5b025 to master a65fedf39aefe402d3bb6e24df4d4f5fe4547750 c47800c7266a2be04c571c04d5a6614691ea99bd Ben Straub 1335806608 -0900 checkout: moving from master to br2 c47800c7266a2be04c571c04d5a6614691ea99bd a4a7dce85cf63874e984719f4fdd239f5145052f Ben Straub 1335806617 -0900 commit: checking in a4a7dce85cf63874e984719f4fdd239f5145052f a65fedf39aefe402d3bb6e24df4d4f5fe4547750 Ben Straub 1335806621 -0900 checkout: moving from br2 to master libgit2-0.19.0/tests-clar/resources/testrepo.git/logs/refs/000077500000000000000000000000001216214232500235605ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/testrepo.git/logs/refs/heads/000077500000000000000000000000001216214232500246445ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/testrepo.git/logs/refs/heads/br2000066400000000000000000000005071216214232500252560ustar00rootroot000000000000000000000000000000000000000000000000000000 c47800c7266a2be04c571c04d5a6614691ea99bd Ben Straub 1335806608 -0700 branch: Created from refs/remotes/origin/br2 a4a7dce85cf63874e984719f4fdd239f5145052f a4a7dce85cf63874e984719f4fdd239f5145052f Ben Straub 1335806617 -0700 commit: checking in libgit2-0.19.0/tests-clar/resources/testrepo.git/logs/refs/heads/master000066400000000000000000000005321216214232500260620ustar00rootroot000000000000000000000000000000000000000000000000000000 be3563ae3f795b2b4353bcce3a527ad0a4f7f644 Ben Straub 1335806563 -0800 clone: from /Users/ben/src/libgit2/tests/resources/testrepo.git be3563ae3f795b2b4353bcce3a527ad0a4f7f644 a65fedf39aefe402d3bb6e24df4d4f5fe4547750 Ben Straub 1335806603 -0800 commit: checking in libgit2-0.19.0/tests-clar/resources/testrepo.git/logs/refs/heads/not-good000066400000000000000000000002371216214232500263170ustar00rootroot000000000000000000000000000000000000000000000000000000 a65fedf39aefe402d3bb6e24df4d4f5fe4547750 Ben Straub 1336761944 -0700 branch: Created from master libgit2-0.19.0/tests-clar/resources/testrepo.git/logs/refs/remotes/000077500000000000000000000000001216214232500252365ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/testrepo.git/logs/refs/remotes/origin/000077500000000000000000000000001216214232500265255ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/testrepo.git/logs/refs/remotes/origin/HEAD000066400000000000000000000003031216214232500271450ustar00rootroot000000000000000000000000000000000000000000000000000000 be3563ae3f795b2b4353bcce3a527ad0a4f7f644 Ben Straub 1335806563 -0700 clone: from /Users/ben/src/libgit2/tests/resources/testrepo.git libgit2-0.19.0/tests-clar/resources/testrepo.git/logs/refs/remotes/test/000077500000000000000000000000001216214232500262155ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/testrepo.git/logs/refs/remotes/test/master000066400000000000000000000004441216214232500274350ustar00rootroot000000000000000000000000000000000000000000000000000000 a65fedf39aefe402d3bb6e24df4d4f5fe4547750 Ben Straub 1335806565 -0800 update by push a65fedf39aefe402d3bb6e24df4d4f5fe4547750 be3563ae3f795b2b4353bcce3a527ad0a4f7f644 Ben Straub 1335806688 -0800 update by push libgit2-0.19.0/tests-clar/resources/testrepo.git/objects/000077500000000000000000000000001216214232500233065ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/testrepo.git/objects/08/000077500000000000000000000000001216214232500235355ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/testrepo.git/objects/08/b041783f40edfe12bb406c9c9a8a040177c125000066400000000000000000000000661216214232500305710ustar00rootroot00000000000000xKOR01`0I6307L6L21K05I2640MM4771NJ5K2L-1 9libgit2-0.19.0/tests-clar/resources/testrepo.git/objects/13/000077500000000000000000000000001216214232500235315ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/testrepo.git/objects/13/85f264afb75a56a5bec74243be9b367ba4ca08000066400000000000000000000000231216214232500310170ustar00rootroot00000000000000xKOR0aHSDlibgit2-0.19.0/tests-clar/resources/testrepo.git/objects/18/000077500000000000000000000000001216214232500235365ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/testrepo.git/objects/18/1037049a54a1eb5fab404658a3a250b44335d7000066400000000000000000000000631216214232500304170ustar00rootroot00000000000000x+)JMU06a040031Qrutuen~{T}ǝ6^rqhlibgit2-0.19.0/tests-clar/resources/testrepo.git/objects/18/10dff58d8a660512d4832e740f692884338ccd000066400000000000000000000001671216214232500304730ustar00rootroot00000000000000x+)JMU044b040031QrutueXlmmAṃJ}G;UTWRQຳyv;slzC8Ti^j9XrѶ_,ٟ#4'^A0ulibgit2-0.19.0/tests-clar/resources/testrepo.git/objects/1a/000077500000000000000000000000001216214232500236075ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/testrepo.git/objects/1a/443023183e3f2bfbef8ac923cd81c1018a18fd000066400000000000000000000001721216214232500310050ustar00rootroot00000000000000xA 1 E] LMA M&C ڹGpyu|f@a5RP&)cDHc ̋QBryuxT-^ԲNj?_1 :Cu}4ylibgit2-0.19.0/tests-clar/resources/testrepo.git/objects/1b/000077500000000000000000000000001216214232500236105ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/testrepo.git/objects/1b/8cbad43e867676df601306689fe7c3def5e689000066400000000000000000000000631216214232500310100ustar00rootroot00000000000000x+)JMU06a040031QrutueXlmmAṃJ}G; %libgit2-0.19.0/tests-clar/resources/testrepo.git/objects/1f/000077500000000000000000000000001216214232500236145ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/testrepo.git/objects/1f/67fc4386b2d171e0d21be1c447e12660561f9b000066400000000000000000000000251216214232500305760ustar00rootroot00000000000000xKOR0c0+(libgit2-0.19.0/tests-clar/resources/testrepo.git/objects/25/000077500000000000000000000000001216214232500235345ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/testrepo.git/objects/25/8f0e2a959a364e40ed6603d5d44fbb24765b10000066400000000000000000000002501216214232500306010ustar00rootroot00000000000000xM 0F]J_q\N ۦ<o e ݩn%;-Jk}EL  VxEb̮3ACd$Igւ* \nDi>rM,-*9p}HJ Ilibgit2-0.19.0/tests-clar/resources/testrepo.git/objects/27/000077500000000000000000000000001216214232500235365ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/testrepo.git/objects/27/0b8ea76056d5cad83af921837702d3e3c2924d000066400000000000000000000000251216214232500306060ustar00rootroot00000000000000xKOR0c0+(libgit2-0.19.0/tests-clar/resources/testrepo.git/objects/2d/000077500000000000000000000000001216214232500236135ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/testrepo.git/objects/2d/59075e0681f540482d4f6223a68e0fef790bc7000066400000000000000000000000541216214232500305430ustar00rootroot00000000000000x+)JMU0d01 oͱ.[||Ndriplibgit2-0.19.0/tests-clar/resources/testrepo.git/objects/32/000077500000000000000000000000001216214232500235325ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/testrepo.git/objects/32/59a6bd5b57fb9c1281bb7ed3167b50f224cb54000066400000000000000000000000621216214232500307400ustar00rootroot00000000000000x+)JMU06f040031Q0+(aOܶbK?TK elibgit2-0.19.0/tests-clar/resources/testrepo.git/objects/36/000077500000000000000000000000001216214232500235365ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/testrepo.git/objects/36/97d64be941a53d4ae8f6a271e4e3fa56b022cc000066400000000000000000000000271216214232500310270ustar00rootroot00000000000000xKOR`JLU%$>libgit2-0.19.0/tests-clar/resources/testrepo.git/objects/45/000077500000000000000000000000001216214232500235365ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/testrepo.git/objects/45/b983be36b73c0788dc9cbcb76cbb80fc7bb057000066400000000000000000000000221216214232500311740ustar00rootroot00000000000000xKOR0flibgit2-0.19.0/tests-clar/resources/testrepo.git/objects/4a/000077500000000000000000000000001216214232500236125ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/testrepo.git/objects/4a/202b346bb0fb0db7eff3cffeb3c70babbd2045000066400000000000000000000002401216214232500314210ustar00rootroot00000000000000xQ 0D)6ͦ "xO-FbEo0 Ǥ,ske[Pn8R,EpD?g}^3 <GhYK8ЖDA);gݧjp4-r;sGA4ۺ=(in7IKFElibgit2-0.19.0/tests-clar/resources/testrepo.git/objects/4a/23e2e65ad4e31c4c9db7dc746650bfad082679000066400000000000000000000001231216214232500310260ustar00rootroot00000000000000x 1 @g^OTGΧk:{jԕyVpgpγT6libgit2-0.19.0/tests-clar/resources/testrepo.git/objects/5b/000077500000000000000000000000001216214232500236145ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/testrepo.git/objects/5b/5b025afb0b4c913b4c338a42934a3863bf3644000066400000000000000000000002361216214232500305700ustar00rootroot00000000000000x 1ENi@k2 "X$YW0YcÅszMD08!s Xgd::@X0Pw"F/RUzmZZV}|/o5I!1z:vUim}/> F-libgit2-0.19.0/tests-clar/resources/testrepo.git/objects/75/000077500000000000000000000000001216214232500235415ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/testrepo.git/objects/75/057dd4114e74cca1d750d0aee1647c903cb60a000066400000000000000000000001671216214232500307310ustar00rootroot00000000000000x+)JMU044b040031Qrutuen~{T}ǝ6^r"(1/9#>-3'Uug>6wٞOpҼr_ʧ+O\\iy|tI/libgit2-0.19.0/tests-clar/resources/testrepo.git/objects/76/000077500000000000000000000000001216214232500235425ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/testrepo.git/objects/76/3d71aadf09a7951596c9746c024e7eece7c7af000066400000000000000000000002571216214232500310630ustar00rootroot00000000000000xAj!?009o}H6}jUPPZ&Y AԛpFdpz[fYPqLJ.,Z`Ů.`v q $5+9Ot>/DE/龡W*eVdf1>覭ěʙFThk.i^0?PR,libgit2-0.19.0/tests-clar/resources/testrepo.git/objects/7b/000077500000000000000000000000001216214232500236165ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/testrepo.git/objects/7b/4384978d2493e851f9cca7858815fac9b10980000066400000000000000000000002211216214232500305060ustar00rootroot00000000000000x-A0={7!] ,X@`5ds?0OhBR&*4]Mo ȡNɾ09(J|1$pD82$"GgvdjG]j7x22]s0libgit2-0.19.0/tests-clar/resources/testrepo.git/objects/81/000077500000000000000000000000001216214232500235365ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/testrepo.git/objects/81/4889a078c031f61ed08ab5fa863aea9314344d000066400000000000000000000001221216214232500306040ustar00rootroot00000000000000x+)JMU0d040031QrutueXlmmAṃJ}G;UZWRQ°\erw solibgit2-0.19.0/tests-clar/resources/testrepo.git/objects/84/000077500000000000000000000000001216214232500235415ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/testrepo.git/objects/84/96071c1b46c854b31185ea97743be6a8774479000066400000000000000000000001761216214232500303460ustar00rootroot00000000000000x 1Nۀn` V.`.pa Ô{StlH,_9$$cf&hXQ*g)cV~p~"Q@JnZuӶL 6libgit2-0.19.0/tests-clar/resources/testrepo.git/objects/84/9a5e34a26815e821f865b8479f5815a47af0fe000066400000000000000000000002061216214232500305610ustar00rootroot00000000000000xM F]s41x(IKݽ/_P@!8)es N&FGSƄh{+CZzvF7Z-kx\[P8GK/^ l>.4libgit2-0.19.0/tests-clar/resources/testrepo.git/objects/94/000077500000000000000000000000001216214232500235425ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/testrepo.git/objects/94/4c0f6e4dfa41595e6eb3ceecdb14f50fe18162000066400000000000000000000001671216214232500311770ustar00rootroot00000000000000x+)JMU044b040031QrutueXlmmAṃJ}G;UTWRQ`6Kǥ^/-*|W3Py`%E\&g|0{Ӎ1Xlibgit2-0.19.0/tests-clar/resources/testrepo.git/objects/9a/000077500000000000000000000000001216214232500236175ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/testrepo.git/objects/9a/03079b8a8ee85a0bee58bf9be3da8b62414ed4000066400000000000000000000000621216214232500311760ustar00rootroot00000000000000x+)JMU06f040031Q0+(aP[v L libgit2-0.19.0/tests-clar/resources/testrepo.git/objects/9f/000077500000000000000000000000001216214232500236245ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/testrepo.git/objects/9f/13f7d0a9402c681f91dc590cf7b5470e6a77d2000066400000000000000000000002301216214232500306770ustar00rootroot00000000000000xM 0F]d2;XEȎ5R AE &n}ZAlibgit2-0.19.0/tests-clar/resources/testrepo.git/objects/9f/d738e8f7967c078dceed8190330fc8648ee56a000066400000000000000000000002401216214232500310200ustar00rootroot00000000000000x[ 0E*fդ "W0-Ft݁pS[Yx^ Db CLhut}8X*4ZsYUA X3RM) s6輢Mរ&Jm;}<\@ޏpĀv?jۺL?Hlibgit2-0.19.0/tests-clar/resources/testrepo.git/objects/a4/000077500000000000000000000000001216214232500236125ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/testrepo.git/objects/a4/a7dce85cf63874e984719f4fdd239f5145052f000066400000000000000000000003101216214232500307170ustar00rootroot00000000000000x;j1Dmdǎ|M3`V{ >QvL0I?!4Z=!צ8F!rsQy9]$D&l6A>jFWҵ IKNiZ%S  U~̽>' w [ DGڡQ-M>dO}\8g_ШoYrlibgit2-0.19.0/tests-clar/resources/testrepo.git/objects/a6/000077500000000000000000000000001216214232500236145ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/testrepo.git/objects/a6/5fedf39aefe402d3bb6e24df4d4f5fe4547750000066400000000000000000000002261216214232500312630ustar00rootroot00000000000000xQ !@sBQ" ٱ r{:żW9гVlq=(1/9#>-3'Uug>6wٞOpҼr_ʧ+O\\iy|tI=&libgit2-0.19.0/tests-clar/resources/testrepo.git/objects/b2/000077500000000000000000000000001216214232500236115ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/testrepo.git/objects/b2/5fa35b38051e4ae45d4222e795f9df2e43f1d1000066400000000000000000000002071216214232500307440ustar00rootroot00000000000000xA 0a9I p'1Ѷv\x{cVpvWgǎ0x[ ]"g#{rD Cot N U $?9-p+1^Qx9O\C m'D {mV(+l,libgit2-0.19.0/tests-clar/resources/testrepo.git/objects/b6/000077500000000000000000000000001216214232500236155ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/testrepo.git/objects/b6/361fc6a97178d8fc8639fdeed71c775ab52593000066400000000000000000000001201216214232500310020ustar00rootroot00000000000000x+)JMU03f040031Q0+(axeiwg26Eo(g0E.{PbTNilibgit2-0.19.0/tests-clar/resources/testrepo.git/objects/be/000077500000000000000000000000001216214232500236745ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/testrepo.git/objects/be/3563ae3f795b2b4353bcce3a527ad0a4f7f644000066400000000000000000000003021216214232500310750ustar00rootroot00000000000000xKj1D)zUB-0uV9<#+Wx: 賄1^POA_rC-%3Hgv܈@Epքʤ'S2JXDivYj@pLo_B-'hC4Q"n_#qLO1R5rn <[^{P !?slibgit2-0.19.0/tests-clar/resources/testrepo.git/objects/d6/000077500000000000000000000000001216214232500236175ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/testrepo.git/objects/d6/c93164c249c8000205dd4ec5cbca1b516d487f000066400000000000000000000000251216214232500307320ustar00rootroot00000000000000xKOR0c0+(libgit2-0.19.0/tests-clar/resources/testrepo.git/objects/d7/000077500000000000000000000000001216214232500236205ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/testrepo.git/objects/d7/1aab4f9b04b45ce09bcaa636a9be6231474759000066400000000000000000000001171216214232500310220ustar00rootroot00000000000000x+)JMU03a040031Q007L6L21K05I2640MM4771NJ5K2L-868V;'!gά.libgit2-0.19.0/tests-clar/resources/testrepo.git/objects/e6/000077500000000000000000000000001216214232500236205ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/testrepo.git/objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391000066400000000000000000000000171216214232500310450ustar00rootroot00000000000000xKOR0` libgit2-0.19.0/tests-clar/resources/testrepo.git/objects/e7/000077500000000000000000000000001216214232500236215ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/testrepo.git/objects/e7/b4ad382349ff96dd8199000580b9b1e2042eb0000066400000000000000000000000251216214232500306050ustar00rootroot00000000000000xKOR0c0+(libgit2-0.19.0/tests-clar/resources/testrepo.git/objects/f1/000077500000000000000000000000001216214232500236145ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/testrepo.git/objects/f1/425cef211cc08caa31e7b545ffb232acb098c3000066400000000000000000000001471216214232500311420ustar00rootroot00000000000000x+)JMU4`040031Q0+(av0 &ֻ~GO71dY쳻^Dq?$G+TmfVVfu򨭪V'5libgit2-0.19.0/tests-clar/resources/testrepo.git/objects/f6/000077500000000000000000000000001216214232500236215ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/testrepo.git/objects/f6/0079018b664e4e79329a7ef9559c8d9e0378d1000066400000000000000000000001221216214232500305100ustar00rootroot00000000000000x+)JMU0d040031Qrutuen~{T}ǝ6^r"/\F0|Z_8]nzlibgit2-0.19.0/tests-clar/resources/testrepo.git/objects/fa/000077500000000000000000000000001216214232500236745ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/testrepo.git/objects/fa/49b077972391ad58037050f2a75f74e3671e92000066400000000000000000000000301216214232500304000ustar00rootroot00000000000000xKORdK-WHI,D libgit2-0.19.0/tests-clar/resources/testrepo.git/objects/fd/000077500000000000000000000000001216214232500236775ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/testrepo.git/objects/fd/093bff70906175335656e6ce6ae05783708765000066400000000000000000000001221216214232500304140ustar00rootroot00000000000000x+)JMU0d040031QrutueXlmmAṃJ}G;UZWRQsCtk# >-/y.7 libgit2-0.19.0/tests-clar/resources/testrepo.git/objects/fd/4959ce7510db09d4d8217fa2d1780413e05a09000066400000000000000000000002301216214232500306020ustar00rootroot00000000000000xA 1 E] /i #sGy_cvyBCȤ9ZDsGٌG`J͞cb@%X7^%HA"$Z\Z4uJv7l{ko178ԑNB6libgit2-0.19.0/tests-clar/resources/testrepo.git/objects/pack/000077500000000000000000000000001216214232500242245ustar00rootroot00000000000000pack-a81e489679b7d3418f9ab594bda8ceb37dd4c695.idx000066400000000000000000001331001216214232500333450ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/testrepo.git/objects/packtOc '*37AMS\fksx}  "'14?CDGNW\`fkorz ),16?CMOUY]dlr{#/27@FMQY_clqy $(35;<DKNW]aem}  "+3<DINZ_ailrx} ),17>CFINU\i%J7B5/РC%QK;QYC*˥ۤ?y~S7U.!7EL5ue].SO!ܸrX27*pls Žmݩ@4}`;N-Vvj%r=-]S:)_-V}E61n$Dm~]v^4I|xg6d%q[WX%hWʐ;髭Ҹ 8tCOPrd^VY% 6zg )G%O &!r: yz(>eėLp%_z-NG@' Ӿ%v4QD ɿ̎Ǡu8hPp3V?Maui-JYXX+|oCۻzQdƣ2A `rѲJ^ށ)΁9Րb-fqAkm+L=1b]GL仅 .z w i A3@/{UgM!& HZ.n}-|jSWˣ]0CF \g'pzU"O ;$b\k.$N(n!izal]3l @[5O)zsuPIt J n/<nU?,.C/xp߽aZ~sw]@hk]C<PLMn\|p"gXϋWfF'؋m1ÚKgoʚJ:| !-ij*=( pC֨h*]K@YJ{(wC5(;}鯂M ]FNBq?[if&hj_>y%!(HAìV\Qž еq0@ at|l+>/x%8e@NJ.i2{nU;:~"O5 Tun?dM3θ1k+}Vv 7SZdgǵwɌgm=Tj,SudzK-ZPq$ LX [*ns |mg-kh݂Rt0Q#٦V#{+uIϑ3 z4+cWkB Z=D]yߎǷϦ gTTҶI\  ^vE>Rq(?լq2 +@?] IWȼ( zR#䔟9` i^SUەmE$O .>o.7{Ęn yb`&`{ !qL܁w~E ҊCZȭHW dF kE{ B ILKR ,L m,`cE5pB3f ~ 1Nm0$FT~SЋd / SH2,ܙm1 ~ٹ/҄q= ͟&\͹ 'P7R cFdaKV< 0dO|Ėκ0q<{!r Y )F2k$'uHw yb5[M B׬. }g L.1 Rpuv1ȟ 7lH ~`yP dUbt $JjbZ m  VIML^&[&XDMBcVc'R)%q{"t1E7eP1n]QfmIljΎ()gTˣw9rfW  =M2u%sP{Wh5𺮇n0Âe@K+ CGkf'+P/{abU vvK(/YrO8&Z,:+lIػ)jr␳s.m=!ƾV@圉L~';K&I9}n:_edء;SGK0^q_>4p wd 7ɗ,QlmrV۬z4YhۿΟ'$VdRaZT&z1 %llV+mѷՙjkÌux'=ҙ|'| ݬͪu;/+J҂Y Ck^fw~!X"pÐ/aa|n ~9IʌIu[0ƢΣB/~LN\9Tz;=8òXޚCjRi9LOJ| 5"F\=VO㤥FMM]rlDȓ #9ߦ_o#8}:,ٟgrl1y) N!@%5z*+6qfNڶsb_ɞW2؊zHV6Ρ يawI9O5 <_-*64w<2f{ N+L6ZQsb穲S*y, ijS9qW<: aYK[67Ґ f>OcD18~M L IIaQq m@| J8 obG.36 Ħ>ا J ё > Ƽ &k_151d!>r ^,B.(!]IƀylʘU!dE5jImXY ي+=X"sX>}[Wm2"#l3޼A="_"uEyzf"nB kk1h@"><ܥ: ?x"󼗡VV{Qvp#Q;RBmP4G#nuyv;r p`/<#T]GzZQKƋ$m md}7!S*$4[ΙSA,Po$󡴕} I=BZ%no%-%%>JLee)1_%&?FIae0l&WS@%Z V jJT\%{FK?dI<>;%Ѣ }ˀ (&=s nPA'ƿ oZ, e'3ƭ%b_II''7d*jJDiJh 'v5Q,_k!]sk'x<> h4;(jx]Vd0L(vypMIo(w@Pn`eW@h(oZxHrYԲn)()(.Z 1Tu) :b7:O*ewko6 @5G*mǐhZ䱍1n *~gGBF=o$^*0X ̙ `YF+w:>9+zQMAgH+cYrxu:+ViF*I٨PG+?=9&ý#Sׁ`, 8#F4x2<t3,KwՑepW2>,0GMjص,WEDK-7F,W ԆJfKR,;9r4^,׈8Xp<8!v,ED#;P:Z}ѺC,%PjFO ,`8¾l`IH:?-8NsӦ]e h5TC}"-#aa[wy-$Ͽ_X>kSv3h.*F D=6 .>"._x HҁyQl҇!.gvt[*JBT ,M^aI(G2P!;%MF(]}TW0 2FFå" EA2ֹv~P/yr#g2LSPJ_ :s2M?YxEW3x?;1)xaR38{TkI\FB. 73E ݂3OTtlo#Y(}53jNF'Q,1;y>3j*@P>ch3*kCb\3΁'R@ݟXq.3=lTR6iP9}4:KRpѓ_%4BHn*>rX?4Xq\;q24ۥ*z# ü^v܍&'43x³~R ^#Z%~%5ivasi\nՕ5JI$BU=Q_5{#qmF h$O5S@.yʹ|y16 yxQYt0qRJ6z֞3p륱/yA6ͶfĹ6<*-ޚys T6Wxܛ3|ۘ6e(1Qܵ%Ǘb73Ef4pdt)yD|D7VIy(š Lm7 LP =y xoo/X7oIqE6DLD7?W tCG*)8=RwQ,N6A8dҪse1b70Ml8b!`0@ͽ1 S8'<[pښ9}^dIڞOLV9") (G7Pc\9X_VK16:*'g'p%0l:3dzUս0F%Id:a+;͍/#-bj:kpfKL[.m?;;T$:>d"FlIo :QN*( V9:LVCs"ק؏Z/:WrgT\ %ٹ] x;D67K|;Qo;59|J ԊI;k+8=WE8ۧ;?+uoJDI0;I>j3xPZZND;a6yCE@(=XӼM6t;k>VBmFE _٭Y>Bـ╕W.U \ 4_>3xCW[)nx;I>Y"4yV=$*+>f^իuşȶ3>`n5m>i J ?lSeS?ThjI*)[Xb?aWCbѐˋ? tIX1D ?Iq_?ۼ(܎ / h0-@3ָz"O@]Y_Mh@NRgIQ@cĪQ_+ͣc .@n?)$? II @rk\:v{S@x #q# {@ v6>ϘF@#ɺ~_A/ZL@zs*f)[Lt@_{ Fsi9R?@ᯃk&sҭhKmoA.䦧AVtLAA݃姹/p.ŦjA A ߆5g^(Aҏ8$ؖyVaA|!|t6k[MAX}\:Z? cAZpQFcKFA;"y2! B6tAD٬JC6'T]mB >_t7JB(~q7C$`3.NB.߆ҳd~%13ݟ4BZ,ipF~TbrB[<ՌzipzCJB`i7k12$XB`K F+Q`e64,Bua{*r,ҡ&MB|^pbbBE}BwP1wƩI(Y2RB@hyu1]"bCz0aϻ8*\C `NQ;N]^ζC$\mr~J}~c.C(3 PjE{GClڈGeIȝgC*˿[:S\oCC@.kJ(vÏFrD#l9KHŞ,Ö~vD(߷"c2x[D0! z<_0HDz|'IEa>DeLyQdCӷDSL®G hD!+ʌ'QHSNt1ED޽ĐCJPZ6v5EPK{^03o=*Euض24Z)yEQEBE'6ƂMTF+ӆmE6:E4~~*L"E8j( N"ژF3݁F$$c_}##s6F80~s{tڞU#kVF_UFSor F?mF@V_1HF]c6D4^F#O ID Fظe2fKb{YFwq='fg|mFB;[)'G\kkg6ZV+'4 GwӇ/YvGrm!M^GG0"BvW̏ynXG8$znG_:V@dw}!щG'2(a: *-MWGXN ן6tu {sG^uLQO:P:q%HzTҩ;%ץ;HCpmW)H]4j 5+YH.RDa)NQNIB~- 0Mm7IzC-O Dl8iI0kltGɒI^`_IBhsIhC3-:I#| E-J:+nQ. NUjJY?Oa+.!ʲDSoJeY./wm.LJ'4x8RD@M2JVV?QratjF5K #xw0* hK )>6Ip쭱KD#5}EI[K2y^FkeL;30kxd!,! LdQc赍gN՛*LeE1!F +r.֯"Lg_ {Re)L9s)BcGQLbr7y:M%vS `1 h-bgMP?J$P~tF<.9MRM[*!Qنb/]?wM`ESp?>3EMRwA5aaѠd#}N mM62 ؿ=؟3MNgi\2]NuVӘVN~`V3hN'Ⱦ}uΰ`w4rLmNYU|Sj IO o+kU7KzOU/r$]|On豳ȣI@-O9ߔ\*1)l[gx/f-f4?[̔Ixv&Cl[(N\ [a}RD\u.[ˠ@BRqڎ\l%'RQ$hmg Y\ѵcM wM|qBf]y)+D7)幺,]ef5챧+1Ɋ]@&^ċ%]y]>JbId]{0]U9ToA]蜽 C 6]Vx1NJ'ᶔD^m oyPc`^xGQmȝ^ l+t]b,d^4+/u$F (^טa̗k}ySeV7Ť _kgO#Hz%novk4lqҳhw5&lE C7fa2m j+C3m4*:>P-mdjMK:;HHmh9agRqJHm8CDPߠKimVgbǝmUh{7plSFEQn[X@.]@A%w+,n؟4UBPn+1N3MP֜Px,n^)޼ RY [n71rhIVnLކ[!c Bnݯ20e&o,)B5ӦfנoN,B0(o!xoj6 W'a o e8cO P?hr}$ްsrQzu/arN-̛W9Vy2v7s"d o4sP3z-ҡ_NjȞsc!J`s!?sV>rIϏjGs`*tr`RFsݒS'w×`DvКLjV 2-wܧ}u>x(7)?1eXuf^x2WӶ'-K;0QxE6hH!3~ xKup;D;x]?Z,"BF*Mşx'ErU̐Up#Ǹxe4x3 i_Y4yP{72u~y&͆m}u0 #X]y*.Fʴ y_Dr5]7"lylРk*sɉiտypm'f5` hZ}y.@<,p[z+ysu8UנZLjz;Oi`f>$;z2zl7V4dvU5,2{A"zu |2n} Kz-DR5P0zA9EvW枾nu{Qfѻ7{])2hO^^{!c{lln'n6GY7{ng얬A2Ճ{}9\|j̕z%m*kJI|%wQ,9q|lVM2(|)~(osS5l8 |kM-NY.U~xիJ ~Bk~|976HgMGD#.0~/!#p PJUTHf}LR kV1- Fl {(@(i#TaTW}K,Q9>L=D:2&=$]]wiUn-9NOq@b%}@AtYsGpcݷ+.jEySM톋d4;XM^.ey%$'=ؾ w>ͅopFw|hdQ5%qKȌbg0"1x :E> }Jܝ:kMAK-tc#j #Y였io`g[V;$coq!QNrW{Z[qf"e}#+r)Ǡ%ݸr<"W7tXW&6JtgfSnK 4vD—5L:ӫe,jH?r퓰@GQFOQ2Jyw]|v*흂;5L!r?GĬ̘c?ϺUk̃{&pgdcs#k뉃:սc {RSXz51=_@$δ~je/\ KHBW}-x1F<a8l,a9 ; cK44A_(Bv@WEt{zЄ,_i08E&g\!<f*a|=ɱ°kfNJl鬄#?D E߄,ɍ3S2^BxǞa99{MLɮ| NGJW7/88)d|N?4.!`DdyvF>TTCc-$5 UrUM Fvo  3Fsx|Jo$M4T7ې.iџVBJ!҆rlZ2A/v~ʚExxm y0#d|\w !meޕk8~;DwmÙ:69ah"~Ä {lz*؍f>6[O .҂ > G`O^Y"rA`=hYͫQ |6SV^"B? P6O*Y,uϽ9հ+y[ql3Uö͈D[DTmsFkP{uLX~/ Yҷo#=Is#ߏTk2EZ}npfIL38pPKZO8'4M[5et⿚,!}p)ɉF͹Oʉ)ςAL{dм؉+L>ሺ-_oD!*d8"|.JW܃&x$^|cqR\F ]Ӗ `ӮRW[/Imrs+S9M] #I܉?1fIF3ȢKʢGez<;p޹됉{M: ޔ'zeO_wM5'o\>UAm>@@[8k:ș 7ΉLgUϑ>ފo*;ώC7N\ AHM-ɈfKF|6S5x.t}mKC]kRO  DS }b_Srop=hmT󮽿Swv4#&Sh0dH/D郞 )$(j.3A<C^Vfoҏn72\ `LFy}pRhlY2Dh e7-Pк#Mu)||v^c A-D5t1#p>qˋVȪ 5𑗚bKTUwv8T}`*B9i<Í~WS_]z ~x3ajLh(e=lzm-an:ꌇλbZ*IAS7ȷŮ69z“Al+AQ!3 *l<ޒ v*O3"efe(w8:ҍ[~ MBGWyI4 KOT!6(Ǝz,Z[Z/smr济Én%-`egI|ـ̫q_|0[0ru#5#FB {PQ8᮫qD헺W(O۾ADɻFS,-| }kq%Wu;!b,0^_`&BAs"b|@v~ҴT1nxF)EnpX"IcY՝3 W3yk.# H9. cU.ۉ|ѿŠ4hOIskHwB/LdOݬW\n#RZ~},o6 uG#oIЄ'.|+x lTq8&eNB>M7(5wъ0GceWZӛR H)umP/(w|c9˜uqx-kɼ Cכ[`] k"5<\ |=Y,Q:irhV ԚzuAJa69<9!U B{h C睳<7vCWneޢ3k dmI]s?9 ! : M CV, VdJܪǿ0MקY.kkaA>ZR(FD٭ G=BGL m [Lv !i BdHhMA>`3ysw=/<V؞ρF:RmNA.e(5v 5x'W[̊F"F7ɄhvcQ";_U,Se ?jFQ*|AR0@V)}ci }g kg٬Y[oncbq񼡥^şb4U=*q MJONarpC;N h1LKJ7Fj1׋K,;^2XBFAa s:˹cd3%';#Z/R/ȫAOd)EZ_3.wVI_^*!{"%$2Z Ɯ9ä?9E=^7LUb{ݤ[;*Y5t#H-א?cmЈ2=j!W?^@m/cMUd5'@'ҳ'M[$ˤ'&A*[Vyy JsC}P}fh) O YU,R~[ab>6Y6 /-0m6ե= B^[^2c"9h \`#%ʤ*fQ`4![)D3ɉFfͨȦ})Ļ2>4DN {B3\Qpcw5"-ءk8ŪP uj2FV*dSVS"" ~|8̝\ f$~RԫLHCZopȆNUŔ?Ģ m:i\%q0ϧE_DU\n5~L%jv:2'!0#ZM %6svhGp_3\b) sFѣ姩ɲVnuT rc c9*o˨|rA?B@dZv!T+JN`)XEuG=!@@ cL 29vg]R+;i^Kl06o+s GSfwd۴?#N_3Bard'(PA]YmRT#i 4BQLֱ}yHyVl· 6yDYSSN 3|vث;a.w_" ūo0olcN<5h>!΍0Ǚ*k(cCpEn>e<M5*^|LE iWQ}%I=-Ab 09*<7፡uQsm/VܱK)zridb! /_ ɵR'~/뚰RKԩP |߷<`e讱9Q~D'Bh> d@Fnc"T4wyK0H1=~fђwi0SDu0),w*1Zt30ׯ;վ3 På̯U( ۆ寥'y^IABݰs,TG)ZL:9/wbC=Ӻga/*Kjp'8N1ن  ["˰VvcxMpnj冓srB#=5}tә XAKBuQu  >#tkBL@ ^'6ԟ}5ǮOi։7'mpnjA n[߷2>1:9m_uUL.gSv?v9͋b} fϊ0w`{` gVvHVp@/ŲJ@%CڲV%} mUo3B=1ޡgC#IF`Mqwc~$e Q̓k}j(lJ{iӳ4B;W'~Lk$N?-l!2"1aN,X4#U]*p^ŋ:t&VgpU!ޠ:=- i#q]TYiɒNqVid0bO#v)KT ]ywdġFR7{E/#C,*)N<EJ`4я}յP 1EiA9 ]~I.'յډg] 3w!j]3!Box$#%7چb{1F \޵*;v#&r(}#VG*AR} ;iv\F"AvU1y`C߼7Yѷ՟BI:JD @pOG/V4f-S撷~ٓ5pf)n,ټۼHgf_OrtkA,g@q%x=9pNکnJxd5$v ~%ɲ6j\Maѷ-;YM|=4n, ȑ)Ҙ#.HBpFj?5cdb>;gK Løc`ƞ#Bcָ+hxk {q#Dù#}nړL;y*sP_ЏCȹFPэ lNYB%!n%-K$K 01ּyNOXo ,̻d99yr[sa8M6z^@Ҍ+*/lܣ{h. Xپ??--%Y!jdb۝XxҚQ*dC#(`|~]o=3 W,n Jyb5\S@2I7L=g<]cASסfHu\"PXK6t;9%ǻ):iZCDɵ@ojSz,w{F[_ANoD®9ӽ"܃i ca<'<ưHzA[5g#ǜ3BQZT{/y8lI %bKlnڋG3`Ѣ^E^ZU` 'l62ېd3"U^x$7+_OZ1v'3S\[kI/3V΀+܃C߷UAQ.8I oc;mJwc BBL~ٟR_zҟx}?rQ zYxnam"g]Ac;"K㡘-  rF&L& YQ ѴZBFp8Trz<$);Us3zM'i1?@D,dH 6PiE, ;ؽjR`JLRLIR'~_H+py$X86/R4 9)HBcuV2کuz8lvLDO`Lݮ"3J||d!C8ˡ-2VHY,ug",v\V ƾٖ \!xb% qaI iY&Ѵ _MP1/+.5%'Hu3_QL,TzuCllW4 ѭۆv]*A 8_X`+QGe}gUƳ*~8A35+2U=YlU ~xM2G넧{DnmG☀+e9šN@C{E`I v ]!Aq弗}x]a!N2U N(oLFW+õ:5L[r'Ѝ<&h_I4.JFsh~Uy BxPIأNn=͇Hz3Lĵ/u i cG-?b?$HX`HCDP{ c0UPm-Ko1h \i\RLk:DUtnSffs¯@dG;_kΞɉ mqˬ dEꜤ \˜,5I*"L;퐻 Z}3cZdR"cB&3z=+kfQY9v_r5h?n r A)l)r:W8ly|秜_ !'PmAD5fKzo1߭{Izs%MEMu> us4sH tQ?VuFʖ&Gz#6}Х Р0h*&}mФK rZyT 66ˈP%aւ畝KaoZzY:_P'w Ǧ0}hD/TR6fUA2uYJ"i^`6{SHy ڠlS˖jE!^m]~{eJX?0#CպJM7%/P+G-^әA9o"O9OYdBOӲ>r58{EE4$@J*0ӫ4=^aދ>p1O Qm#&@Hķ3I1t,~(|9F7Y{".GD rd9us5ڢo`]Y8LF,R}!gϜYGG.r@gn"bzQ do35 kuԍQޡݎh,ԐE&.?g9e2BiԹvV?}" ԩ\؊ z^ՀKw?mʌHVpmP <<KGԸtj0?S1cjLx.EHhG^FRSYUwX ƄX'NiM/ ~hlǸFyI"Y\iklOVpDٹ܎@baH.m"0gUCJmc2'ZנtS/ s(x ׮bc&W0|3 >q _D:"~D_Ada/Bvq1AfW ENL `>ԯM +I=dN4Gع:ՇI^]g2~3m@_'sh{ِ70U^#VU >r٩e퍷 "&nzٻL;lQvRǰJ-Ic;@+CyHTUe/ަk\ rN IMPx ޱnϟy"L">y&>fgU5~0%hy[+saH pN:q5y߮n݊;@1b9"5Y'4FB|=r[{{OwEҝ|2c{GلfDhOhD_h5IE)A8WAc}߾|U|p Znvt:1oO t;Ӿ<,ΞglOtfg벾1z?VsM4vPo39äkzW/Ή'Eһ5Ts,NK=U7@RTN'0>N $f 6˹Sٜ[=ǷyEh'rķ-n6q{u'UE¾6kaPvf.`Co1$(b\)j=̧ڷ3h(Y68gQ1,blm6)ijGlS/#Q9۾'. :KhV$}8@f@q^M  ȫ(6`X^vQ4]'?_q4r jRt 2@|(WRդN?*~qU5~"N]}aދ;нG'A"@#0yV3GL5 z墅S] DWyʬ mDV2RϞ=-^,Oj"sK &tJEkn8ߏ";]8n,&Žb2gtėgV74K°1S?et^u3^Cu2KrwB\wtԪEV +\3 40B}cw!dEEA Df葛ɛvמt,#$7&@MK+ 1S},w芣g`Dy(z+2k6BMr*% hp*d6uEls""= !ܜl"r>"D#kL(k<*ߐ =$4l8M aՀ [-pEzИJhq^z-\(_G2 f[!<dC 6}1O1"BwB.{LV6ȷb/<Fs?2|Ar(C0H)Pސ, y^P#(v:C M WSF΂@yۥW=|#f ]DbW; RO% nmqO^_sfsMZbdLYrj&F^a6JzPnAӼn ~$1^55fynqt[Z'/튶/ ۳9Rez|S%?1f[4_jL?7Ck'8hT yTF{KxE{m&ꦢuV .Sp?# sVC0T"e)kDƠn5l.#؀Wd;?лp@Hs_Kn,%~ >[ɣ_jK]T/aM\9~OWtPw3 +ʍ aGaĕMVm)ˣEaĞS}$+$拏rjm6{ÝjdamBw &uuiՒ9VO} 8.֐zX99|*+FYav37K $v݂״k )7L+wJ-P#j`nM~Y0^dMZ-eAYdwBS6[OM'%O%d[u}M鉸_A.a$D[ۻo=PPlHF=Ake30i쁇L=j.}S<}%m$^I=,iGx=i51qUI4 ikp\!;򩊈3r}rk+[=A$Ҥn 8cUṾ0zTL vAwQ)<ʰY@krX!VQjǢ\.]HwՃqr?JO&N`g47 h}XG^6K;'ր.$% iq㽅Ec;lyn]-q@@|yn 0OJ@%\; ؘ!)G`~ Na,';iSж GklX<%6ώ%3z\vHǤ$WOc d)mk&Hq zbEfЄo."@Q$FdQrUA/_m9PuǾQ@a\rf SO/WcK[[yqATU'>U1 s\_3? < r3AQ!\ &qt4u}۪"3 #gv.a-] 5|XP- p8 39H2eF6å0LUG+EKNeV;H8a( ;ܩW2YbY5k"5<8:jB#pAez݇Gh}K3${ ,P(ld=iƩ|~30;顿i3c7ħp[40 ,3J(BrAZItAO-Փ/8$7JrLٕ}TV!l,qܪh:1Z tE၈9g KB\8r{YڶjU^3HHkk&UJl48w}cq/E.Wu 0qmiB9" 1{4b-@O~8ѐʨRJSϽŌ$ ^Qs*J<ɷ,F i:7& @uhEARN߱KFݹ`<-o^Hڐ٩3ͥ_ $OºMVC!!{hMbCmBalL* ۨcNa aۆrb-xkչ PnS&!x0RG?<g>|gg ^o&]mu' Y-wFdc] nB iؼjxE7k?=LKL4h8`.Qwav8QOީ؜1l)AySQC`8~x?|Z2ИǶ?pj}9 Wv9ii](Huf) [- o} L-={.dž]2ӛ6kR$h~7N;Iɶ%(24fJK\"Ucp<0'5onENW3nqۧu3eC}2iI\jU;_P 2(`#ki}zfzZt :$Ø1Rnۿ9N"!((d:"i$>Hwi搊aT y !6 +zjJyZWU`@^. lRZa@봜ԔNG!d33>`? \eňRп^`z檏+UVi%ҼRpZ73YF_JwC3mUHp{Nj(!5*]a94ӷ&R |hH#Ja(qSI_[IT݇xěZHP@؍j-@~@'4e\HFZW&e~3βDtaWcܒ1AC^A˜'Zvx' 5>ɲK;q@0J(w>&@[|SF쒚rrŃͿG[6jJQwahC?'C|Iت%RM'>)Q2C!X  ?%8ŠdžJ0 VR!TnxÈTuH,/MJSd"33:r3YH(ϴcŷv%n L6Ʀu7b"̍s b\elQvE}=I^8%!0Y.M~S3ⵜJe{reGNy%ʬЯXqM=|y/GB~i"y$W)y'EioJo/$f/PI%-*u7-? ty٫;M@u%$V| ^5pnCeUiR]7[[Ԣ+F+Ke˫_r; )oR{3) ``<QV`MhyGUAb-)mF(c `< w*붾10f%8E9$ fG6NUPSS9ZvPjFg4ȇo:%vXz룇^\ow/HfzE.0~=%9!Đ|lvF)Z\^X }x+y$姒 ]epGQ nNc?Ё</8%š%/ S%P7qWLhW9Ttwb iIGdRwdWolԝү,BtN;X?S;((ڼIRY:+!lR 4Fr]X3e,P筚E۠ݔ6c,$ Liϡ0]6JV jR*A'dKaDG ҏ`ha24bT<[&XɋIyoQBQbtTxdVz/ږ(8m~>6hcXbLX]u/mB}B[  $z,c=n&K-lƮF_a݇i؉[[,z iv9ELOm$$[hGE@DsvCѣ6/?rD՚~Zh:FЖJqTaΝe1ETJ3jC߃(NW noO uvJס&'}N >. ? !yg745!5ȿ/؏qbM 'qnt<,`5WkEXl^QoMlZDOz7 ѝ+o_D'aesOhi>>dB&E7oBJR]IiV=˃8%\7{|~^"/nO?J-s+2z  XF zʸ%EauG6sd],rWǽ b,LB0H ֊RnnR}ޫ!m0ԦAzAҷ}G!X!LYVt"3 =J)[Ƹk G#@ 2NLiJ/Ei؅rfo&Rc7WRݑi>ofݙ!-N9iYk)*V$*^~Vh|*wӍx^$YǚdƊJ\kJ6}|⚻~{dW?\2mO[_X}_`Tݞ)sR$=6 ޴ Թ/ dw j WbyǡgVaϪU,q#+D5$(d:W"S}YdʃPHV%2q&ɹ]nCJvSHhh-؏trTyh&[.˻0TCg6A4yeUCh240!u`x׍7A,TF]~Ms56 2 T4]}uWQ14\l Q?2UPW^rpr D{?-ye֨%pugY6yUS=hU0.xae˩l6du/dXm#bD 3=,r^l|zENsf<)£~Y7Z5`GbqnYHq48J JXV#-EI x"66\r%*apxc@d1MUgμx{{jTj82ycr-lmfLz(;}4] !h-:-/"3w@ *t4Jk-,uqC<ʶ`, K,…{VNUO\ۘxFp74:YP^DBb9lH%,3tV$SSwN1֨m6iz>0#yt煲oJ>\|7gI%4-%T?Degm;zļ#c,joπ'7y,ޓVHo_'OU&;4w)_d2&q ȵg4ˡf׭s= +w9!奡=>~/p!AubƂ. :[71)(7Y]yj"r8ҩѬ{8t6B)yn>ZZy (J#0ʗՕqTT@ZK\'8Kd ăU_!w>Wڔ`Kjpy9=RTPyts,s>c|lhH`KBحVi5\_eQυ[6AfM- 0tP(|)B˷̊"M@$zwʐ769-`ЈPg{'x(4{+  Mri)Aފ{r/6~L$L79[4bSt$ 3ZqYݸ4ykq *ZJt+Oi EfYmJaBr|}@'#Q;{zSfE})Gf' =:)Y`A(%R6nGͱlM^^-_8u#ɿmnOKx>wv  Ж !Fd)vzRSoR!W@~H9tF/x}3JEѡE Dx|?.ZAd !UQZIFqFvD~?'N AQ\%}}$iy(QȞqۈ}aURQ~E@aCKzp4y #}E|Ab^odfcNLzfr؀ӥl. 'c!nvDExFxR$xFbNnFnDR2;/^z=VW[xN&iFWuEWWvp1bkd}99Wg}rJ!yG[5(i`HKl|FU_Cy f-P~G 5+O]'Y{).̊ Pyi 1 Q{#X`{+Mzq7wc##A/ܪq+=EIvHkmr ֻ^xg|u{rn10`,aQ&/d{_|}<0gL oK"@'~fF*\ oiS jzBV*4bU#} %`7ЊsF7A`8b-zٝRĭb#iGHCya Px%?KL1?@]6vڇf Qy^- >p'\[6. m$R8yM|&P.OB?`fmbi:t2fm`DP8WrVO [+tyOiwN*li1``b000It VWK~R@cӈ{N|]P(x3"9Fa!%4:D8mj?>Mhߓ>>?IprKYg06q{nd(&<[JT_qm;rnscd+`2SQ-ܮy%}! e}Oq/?DP"gc\Mf>ng[Ë09p^~gSVrvüαw}Q uny}Xֈwza2i8T[ YO RXbYZNdMifQv `|fVBLFr],1X2 ?zV0RkOurWtHb<QH>3_B?B~9mwF^A^3#bFQeڴWyzį.,W[=hAz.VآvW*csiI dլH|.."%&LJiem[pIfh69|4[ Es#B|uO_/sFG!lw CLQ̓KivCbzoQ<t{p{?D"s<hO<e6Qz$t0IimOWWIevq@V vOV$=^4`E6~tvlsK n7ZX;wV:jFYU ^w _qgOTWaOЦkz.asanu@g|=Y|5.'^cOqx0 l0P>(D[2<jeGڒG|3Q~)lSjzdx! VYZpyzDllv<P?MmPvo_!JȁNQQx?2w 68@ #@%{/2,+[ItD`oK!htWL#\KtkQH-@W‡]oO&K O sGvd9'v~&,Pbn^V%x\T3usşxN~?O5B  7bIP}irV a+>ay{-4Zmkiv>ftSowhF\I9Im0keuu/,1H=Q}6 JH=:1pUWDԑ$?t~M]YpxKR[^EtL425{A?6\yqA{!!aYgN)#t`bJ.|trwqfIwP&'3 bO='{hpQ.a0?1n{?=BLkX7Y92{ZM.RGsW۰TL)rRb8y`DRE7 rbFnEm 3drv$TvVxj<HMw0e_iZuj3zr#}oi0KP&S:x.cK,g<'Ps4Za2%@ro*]}?&yJ<t{&P N+m`v<^M߽¥Q<.pLv,vQER]G>>%=K{6(9$ACY{0eHdZb{*yF E *#~|@skmsj'$Z?|bAwN'/.i|n_o`qJrzm@3x=/ՑeuM8&XTZ!2\u'(uMd|vl3W]xhM|a-ATVQUm`/ (Wk`=gGfИPT2z lyfq6@b9>EI`I,G_\e5dQ RbLD`-9FPo~c x`vC0p+هR0QnҗY>zYBd]eG&o9 jX'XR< aJb Z܍s[, m8vC|ȍ!JT;ysp[Ol "b}Y| 99K* -uxDwbpack-a81e489679b7d3418f9ab594bda8ceb37dd4c695.pack000066400000000000000000013620511216214232500335110ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/testrepo.git/objects/packPACK\3xRn0<_hPDFP{i" K@Ru5RPcȻ2x D쇎.O!tTAGrKdBVEqw֩ny@/\4&|7w oLўw|'xN0EuZ&v!1i&ve;@lf1wι@(ZCB3[BV5Bi-D#Bf\NQMGo%s9oޮAq~8=A{u\#|)TbEo(;wB@d)Ca'%qr"Z3905^e\FmkC֜ěcScmY} bxVr6<_v+W/;J{!9d]@r(!&-+_(]_(FO̐lyvvmEZQ})+Z/r6i+-i/VUYl5bͳ<-z]U})9-7X*8wi?{sˡyfV)[fYFyO?Ynײk[cpAytIR54}:tD8owrBjj= K%+SS 94Z=?+y8)T;"8i P8@^ (ȵ2umNJD!څJ;(U&DN,K*4B)>}2a"@uU:8, *I,jׅ<앾 甿%Yԥ8Y7E`][rr|}awM4iB( VB$ VY;9J`p+ ]AG`>|Eޟ0@])X.бHXc34"?C)cA!xmW)K&U-ZӒPliܮ4MSӤ6ɀcgy d;$W\Ⱥ/\AðxR(neT@U˃c[ӟ_N .0< :1=w-$w}[ǡH?MF3=O֨P\9NW;1p*s8:.XcT8PⲧR-} " P<3Dʙ#x<if)~i)py"70!;(,qٌdK̋/>̰\l `\ZFNw?Dܶ??{+-xN0 y X`N;aWpbuN&Uꂆ'EղV‘ḪDMUlQխ41Ql[lpW VV(l++TiS٢j^؝knn0alvRU)\R3} UJi7T ¼LS 6k3`@0|'`>YÀ OO !_Fǀszv9?NXsk37=BM1^3}OTݔJmP/18x1O0w:@#q!CX+cĮ+bNO}%D3-m_׺7W#)P`,βN֩vC+rN1})&xfDIyzj J5 YqOJ({3eWaWфτ!/7l|xVm,3Y8q-d x^C̥SU cӥ3\d,Zob͏6:u7#x DZ0 Ђ&`Yl C!_e.DZ3Lu^e?` k QE"y#I4s3щp +JVY$Ya3j^C!ҝ/xR;o0_qZ$E%0!C.(IHE A{"t@=(;T]W}ӎn;p7 u3(n ۱Уp۱FƗ4?̲<$wq4ҟд|ۺfMJҮ_RY)CMiF8~{x$tx1.1BL>"|)4m,4.XU$X5t*^DI"Bԋ'qŵVk}E9D^[ƪ9FX xyuҟY/I@d4L3 ˳U׶69hc6g&8#mMEhy'i1g 4t]͞t~~Or!+d 8<ޮ7NSжE-2Lk~w,xn )C5fI}ZU0^ӵt߾JV/ 7f)p!VFKijnFʼnM%=-> }M{\U5 uMIt-9>Od9yD;_My ʺ,Y6%ڶM% e_b| 2RپBgoE ́."Xwlpg̥MW4p݈FgV'Ԛb̚RfmJwk^1٨N1.a W/Yv`q,y{60Ȉ!_I?dY(^m@zQSr{u|EJjW9.opH8j#O1`~0#pcp) 쯘IaXݿ&e?.&ضNJ $>of}L_wޘc>Lgx=O0 o NI 1!10!;Z&$G lzvD%aO֡SUZj[dWiu8b${W;RɮL)*mH72!<_d3CFaF}A+;Y5J-ت3Lu%|SJ)(2)e?z K|[:㉒/? lB!r:l)/! DKpVa&Ė 4_A>,pHqZb9\F`~dO7X|;3!{!xdwY#;'=xUn0O}n*aR+*ؓQbGے>U<<^l~7^`7v xEHQ՘D)Ou+5b[o̞Piqak6'zkPtLXP*K{GǸNyɬguh7-fŲO>Odq9]/.kqqM:)#hq_S~eG b|T|\6( xMK1EͯxKE*dt!ےil')L[EtQWsrB) u6ҙZqFJQ 27Ȥd VY+[wW E[ kiT!29Q ޽B\^ͽ#TLer\ qAZ'}@ dVim1ep>B=XJrBCsB&|^ onr6GW@?gWh@&̺\_,L%/+9KD|NsS}_%txƱ 0 0 vvN(I40iʆN `O;وQ 'R%⿄N0tozd2LՊ XsHDP?br圗}q!+/xn0S-) d-zjk"6H߾Kō\R]( gLdQ׺:5MYlqPUuC+,􍑺L)f -j}Qj|Vj}˲j+ [K: ׄ?- x j۵}-|.;ٔо{4gT|2>$0|Q[4=#E!~vozr 1E%L4p@s90Y7;6>}ĦGևӕmBu`2cA,0./YGc(G)?&pi'jxui;Kq,A8AX؏qkH<%qA}M]@i"&*($k:y)q…JCvk J9ZtЙ;e4s=9l.5]Ìy[iga']\+ Jp#uCcv'6׺HqrIX3:qnxaVOC2oj#By Oʹ9>δd9 ߷&~Txαj0^_} K+K!NHW>qg}H?:UJGޑ4gaUK]+[^:eɰ?M&Z᳠yO,CŤ(1 &3 R) $b$ˆ 1_#Vޑ. kyD4 g|zqvj->E,\s'x߾I5.4l=='QC8.ғk5ѳޝ88!urWImq "cKjI6@[ F,cj!\umƢ2|vz4XC<8僆X9uQ[*[0N|r1=_4/S*66 $Kj!oYw'$ʲ=_5n )!ex vtc:ڦMjKY UR*5/=84)*dR!{(!ES c1PX!VwJ@ ?3{₝S>.P ahW=aw]d@VG0cF ] 9MpF簯U~e.ۿZbz+$xQMo0 W[ԉTEwڰkAɔΑ Y?:A{QRzݡ譋k;j!6x-fBI7mMЇغCﱋުԱ]]Ww+ axLy8!OOOP7GXUF'qQy1 CsӇ 'ɰ9,`lŘu#na2p~8z0I|Y>蝵){-$no̷ u'X$2Ҫ os0|sY 74*qy{)+eXyC~cÿ~8'xN0 ),Ciτ<'$M-&S 'k4ɲs'5R뢒lTYTKEXjT:d Tb=YUXJt՚:Ӳ)MfeZUE)pMř==;c }|Xw=dyY(U2Ri_huoT<-2_06nF͍c!Oglڷc0b@xobF11+q6W2]NՅ5,Isunv:|LÉ/}&Aw0&[<9;$+\%rwj13% cO?єlh~8C|v@"ZhvK|cuK"xQKO0W̭j$A*BB >ǻ&qLXz3xպKk MEZm]kQ 3 Y®qNW:ijCU+]*.exn=`׌c/¥TJJQ^Lߢ\֕ Uw0Аz qa^" !gld)-g?,q ai/O#y21cb*۔ !FOLoq^YSJ=aޥDqk=`ZB:_b>^)s:)5ʈa[(:Oq[blR{jj xN!yy۰c[3RhlП L3|LDJJzݪk+=z/^;W\i΅l+봑Zu"qCH=vЊNv^*1˘'a8OS_y PZ^( 8gU݅R(2cgkWFJ5&>DǐCHي40\ SS!ϛݪ3LjKcpXn׌Ǵ-\Kܦy{E~aΏ-xOJ0+>Cē7/*^en`J}ڿw 03F\34 j] ߅m1:qУlGhccBC7j3N+yZ7xI7NpØ׷n\0ͧ~]nAַ^nZ $fUݧO-k, o+ s=0 Fy"mk= ^y/%۷@mv,};Bx@BTcY׹Vod0xQ~<En'aٻBb}jVvM-]˒)?6%_^H!&Ak@8]m\N2C ɫsYJֻh#ҫi:'p8S\P,~]]Ho耼2u].q?ExsidGʁ#t >L>l CLC00O 7:Yt*L%{ar# p2,t\(}~>N4,eđmw;u>ߤc/5q绿}&xJ0WnIOi^)ޅl3 IME|wӮ̉oLGMT Bw)+ Ni+Teʣ !Og²E]rF0:MQDMq<BZJJ1e#&hGk8rD \aB-23VڶryJT(8+CnZ#xn <]&J{쪪H)?ju:#`N>'u88߹#R!ʦEv3X5-mӶmUJvl|[v*ɵ7FBZUTJu>!nGK\vߎ( m/t((u˺m Ιۭ˙> 骦 ¾8y$\3}}gHW1S"ଝJ`qtѳ}t&>-۠⳧WG0<=bl>xarw!9R< #cq$E7,EL9Nɜ8ݻYkW^<ܖx;n0 ݧ^Đl= (ҡ:'D*1K>E+̠XtX !)DdԭX85bdvcPM(4ZhfRƑι .oW8dOԇ_AV+iNH!en <$*j Ǽbuv=< 3A]1ͧĴ1mr#fx ;0 Pl#LMƮg8E8vQ[ґ!q }wo)Dr|V̢"Y}qBJqN̑:E$i󁚸s58_/Pאaw}*ԓxνN0Oqwv u+;-퉀1;:s%o=&J #7BQQbrr"JyS쥏F`G%7:v|*^/%S]jTrKw;?h,i*!ɹ>+%$MZj Up4+%|QeUt&WsTU2b'*yFJ`ʢX.t6utCc|=qw~XDcgMl:,_E(f)|L4v>PzpN%]x<=g^<{ CLZcM1}E:2FBL@mrG۷cA8p 4(VM- k ɀX;"|;-xMk0C.I(gC{-ҋ,vؒG{7-R*Bü>#M 04ȅU-[Q^}N^vm^5@-Qu5K8]N B1$(,Fx|ňrE~}RtM]vU}x9SnMJَeO7EċUՒN}0?@Ո5mxl-T Û,N2Xc ~ &L鈠4eeZ1*j_U_`mEu2 1Qi''#* yWHj/JjBLPS8nΌ gr@ wuV"\Cf_nn r4L&^.Dh\ä}' s,ֻaT)$j'$xQMO0 WfkjB Ҕn$eۿ'0>{~l"m*\$*KDUo⨸Uh<䓪PDT(9rNqb#729%Yx;'f߯$')$N9\I3E}G צ(X#3sZO#8s\pVoABM]6mZ OxN];7m~P&4J DEcgո~lu#U,>xsdAj@@` GAiOCtktkv[T1|5cɞ%5e+o_7DDxSKo0Wzi+vCaW8+ʱ'!Dm=tm tFwQr749#Cߤvq;cUdC5pbbl0 Kv|ʭ֔gΏ):E>rc|KWOGs Z[m">'Xq"xN0E-%8NQ~[Ǝ<†b99!6RRoRsNhM٨ mk(pBJ#ļsi궫Ӷ25MLR{x Z^YbLk-pQf&P&obUEEz>k 'PK;k7*!㺈 xI=ɖqLHyG5a!a,dU驆ϛLe<:C;5=ɹ0CL8Mث_ѹKӿe_Sյ#x=o0 w niQ#[ ҡ: IsBϒ!IߗwIv˗$g"hƶFa ׃wvj"CG`Z;'7i?wMn|H٥|M ukj%ڧzuM;]3iOZ,2|/%Et־.ƍژ^V8'L5N1ȹLJDy G~9ԃX]R&e>Q.!i\| O>T[N0oѳ"نn+U +F+IRV^V,T-xVdY7]HzR,wtVJ Ks{]W=87x0~Q/ݒNT Z@bT96DRIU _bOGSz\#fz(.|U^ytr)*)si&SUTv%˼.4RT!uGrO']-5-fe.2*xI"4u=sƣ [9W@} xѕj.cAoL;Z 7m;vB|r>CI6=ږxVn^G>-M9L 9xeS& vЀuq~l-fb'o5a{L{!XnS8zռ4C [6tm)|鵊KM)DxS͎0)ݐqV Z@"&;v3NKV83OJAZBڵĎij)n%+6W6 [T˶jzѶRr٬Y*QzR)8PnD?z@F8s`H C&7*|ᓋ{vn2RH^%CcإѤG{4tSo0g˜p;n}mOwixN1{?*>P@A HY'>H((ΌjJBsf=3`tRQ% :- 5bQ)k7QS9Oj 1`mrXcq1nהQJLG_ & 6p9*cd$弫\[9O㈰~ЮpP+_+Ra y9`u43X7Vx*I-A c#ly?s+}_xϕ$xk0W#Y2Jc5s,jKA:7?[188}''"X7R4`۾];ܐ1nzgAk'LV^9= TתިvDr%S \x qx1Pn9U9cl珠֬UK%q=3%3'osnnT~s.\ ؘrb_3<B}xL3\K*Kg hSg#&#=~?|{}>=^U4 ,./pN}8GX )Zdroc~0Pq(-^N1N~"pbyIT @na_ܿ5xN0 {&i 88k2%boOa8 Ne}EY vO Coޑ Ov`0eXp@ƞGcG+:#9Rt)-.p-ذ,)6>5[FimO2*"gy{C:ȏmuSKy;x?`⏔+Tl`=qס䜲RKަzʜxνN0O5ݪBe```BbSĎѷ'&XΧszC!䤏s-wA ceØ&DhX: BkfEfs\E)\PS`19JlZ}=C뙞;]4:S.fLwL0Ftνc%6>ֵzE+~;eǑyi#+82ܠhJ蹖u %㡦tWG>(oxN0D|p'o D_"OSߓ* hg^I@Z[vPV [y@:SPZaSAjdgֺiLN2\gJñPi\{;ZBȺF/2<&orħxn9٩V?\|$K xyzi<݂0kyJ}Uv?|ODrxN0EwQ#qU:0!=9nOP`S 3'1uΣT՚FbĂSI'5}ש`Y^ `P൞s迱,5¾b4c4>O4u bKX+8&*+<5'#5+9NNil> 3&45B)1r?BnxN0Fw?Q/Y@boR bG )O9:24x~NrdQcpd{?TFXrn2q$dTQP; )*Av)=Pm ryk7w-*Q%9V kd8j9m'y)o՛</ȝOiwevc__)9fx1O!{~]޲-ɠ=Z=c.+ 6 R%+D'8tr<-{_;䤜s(GA(6wIs*S|k%ÁXVoie&-N<0W y:L9/kҶn~^B _Zp{r:+暨2R My>̾-trx?O0wJZ9v;Be jS.oׁN+zh{>dIq9D4a & m*- I\thAv@r =b*vC<~ښ8B#T%k.8gu;R(]0}&`K^uB}؃% %.q78XW!HBJ0؅^-Z}dʑ`Ts& JbZG.-cO~ d7ѹ~}ax=O0D{EQ@GD٬s%v8{i<ͫK`=g inѱ Y ƴ,V,*X?zizPӎ$Izalwz"}a/XjsŔoeZ0 ZtKJJqK <0nT"m[NpF4sF[gs|j^H8Ö4VwALGBL29qJP@GD/Vrvy{.@Ejl+D`0Ĉ@ё=:z˭\GxdG,47pK/5IuFp+|QN]cxj\-%4'LupazDױ:֨< O%Z m>u/O+c?{N4Y< 4Q3uO\pukgV9ƕ?+}sxN0E{Ŕ Qlg@+QR!1vclOT3έV+FeNi$i [FD/.&S@%bc(YGRcz39cܦ\쫉t=̋ ƥQ="ܵmŚ.V}&S9WJ7tHl }yOGg]5,%o 5%T1~ n8"SMF0Gļ}f (xvӞxMK1sSQt A-[I2mp7)IZx03)Y麣j\VTeFp*Fr :J4]-&bjDդƶUSZwM[W(ܦh;v#CpOY?J;ڏ0)E=]UpKY6% 0wHF VKMSDM)#dw`@;mf\_0X\]/Vwr3>Z!yHyI 3D8m XAVOD4Eihxez-]O=&{nr;So̩z=@Zxj0EY&[!deP1rDmJKNU=Ü)j*,}Ǥ8mTu\`mȬ3sתF7SRN:*rƠ7#R)[7YPtL00V6MP)xi]5B)]FSvYRcyL4cqz{I #PmENݢ5S͈_„y CDKu_N n(xQN0+jfs*"q52N&vdT{$nf&8DB4ꌖ-BE(/xKKʌ94J*VVu5jrVgr^"#왹aRaX紬:opYF":HÓ{k`pk*課UN?td'%;Zf$<6#}Fդ]`>ס`݌uts,N='?+6*N1 Eo8Sh~!.|`|E L[K6Mhd.h•s{:}Ǚ8$ב I {ѽAJuDfx1O0wQ#۱UƄ~\R]ٮO`:c=JZRd'5Ş;OV^bX-Zo!&Vz}vRڸ0 s{\+tPZ@ig:m bVpcf,pʁJIȇtM;gMv?x<~J!ΰ-9BII!^yܥi e'p|nU&x?s0 w~ lrq%$Kv^DԑT\P;C2@ID `T(VZ-xo;{.ag{fL +Dc^4mNZ[eL1ZvM.e ~9~`* <t~+5H߷ptMjJO$ ߒ9HqLgRN]}o4ꉠD($zsU߲p9/lj(aqaY!wnYÖuft"|n5o.A8:!#TzX7lߐ Ty8.ٟG4dg2DuB h6KZtYv͡x 3K]Fkog_я;f̩xN0D{-Ah#ۉ{BھI,6vx{̣v4gLnTo앲ޘN9B(X9J+)8M+lo{J]=*u{2 /}bKC^/ipn\ZnATZip9J 3w9mKHǴf/NUpyXCpU{ q x&Wxn80H~qg%>l]qRx=O1D{QN_%% 9; =vfp'wbĤ4uQ.&hBT賕↝*Ct҄@*{夑|"eu18%}aعtY\GPgZJka;ဧ^nvYaie_`mW$KTʇ,ߵOQgx=O0EwFP;Ƅb?']َON ^sN+D`s-^)4^ֺz'38b@^GD̠xPhuVbd9x {"sy0Bm[ a]9锯ͩ^%cgCͥB۷%V;߷θN6Sͩ4A LT%/7l#s]a7~]ˁ}x^zxϻN0O1=(=vVhDBBۓ"#[,O^S23uWL'i:nڡm;ˍiRXj%Kd!Sʔ2we/K}>Nq0W.-OдF7Pu-.J 39mKćb͡[{cpG2Z\לVB %>V 氕J0F4 ;{~ {-xAo0mnV*CC^=,n^î;C@üy#]sRż퐌:ӅirE13J7jET*WmޖJT뻖2y~9Ⱦcd>N` cSժ<69|ȏyIurHKt&!CUWWje)o2o~0v8ΆH q^D 3\ׇ&$q#tI0e2%' ܼI{i&@*[\Z|/Q~>1[aXvik ! xAO!9j K5FCaK܅ iVͼLq#m26]SVajVfZIEhcN)JЂچ+u׭mZ5]bvʇyӏ K{kʪ e.gMD9:RV _&y_$_ m1xRMo!+F䣍~'QGꡇJR0,_:n&)B001 Vebm6< :QvMdNj("#sh9fYyE+*eYRYgA1J$l &0cz`J/n!MI;,#vP!/Nqסּwvn*Zxd)dz693$lFk38i T‚2@=ONe+{| F4INPL'Qe"Y%`{YCydeA 3Y JjQPǥJ2YGohY{ q])(kT( JgUU ʐ8‹{B\yuFTÊx IZeuYEqQ8la[*rhB1oyrEI+w Crut" y*9"dr#&)6sdt7_HN`|Ўن0r]2sر-"D^Bnw\o Vέ~( ̷&d+a+k>lx~^)/屁7uexN1E{(+ۻ~EQR@GD? ֎l(=+31Ft^ю'1D-O֛x X9w簟'2ZRv4p$9Τ \*<=` syYOrNR.wpTZ+ȧr5C/LmW jthF3D hm;ƾ'")v¦7p$ {T,'eUÔ[s{t<0q3N*"Z9]0?}H.ҋ6l?JH 49Ҧ@m)yD wU'K33Ɲ&,m׎.%$#UR$I^{Fu/ V;N821Ω;Tzs|~*`6x)Ug7YTWm_K~2xJ1}%L2i .Ap' $C&UVqB*@TGd E#Z=(kČrG6(+)`Fѣs; )|eOX[M\~tZ2݁C(7RK)Z +5e)6H2Bߝ`C2Rv #!pld!^>S\xM|mÓxKj0D:E!1KF}*^}8x˦ךz츣N&q(0 dj=N{+ޑխwFbOd[ t *VucHy[ט 3}ɤ2aaz\cBLW`:EOv?lxAN0}N1JF6P`N0.RoO`O6҆X'&3v ˬaV, D"YrJ삱4.] |R9I}kGeɩ_ϯΌΌJJu%&`֜`rȫsJ[kTC!\6_+g8"xCόܽ{TN ]B_I;l[UpPx.c<oex1n0 Ew["([2RE:C4E%Bb) } "& [oN!L=;FԄlF8<+I pqXA ~{. 4 )_9I}yn9sw;Q;7FyIP֜`OrWUyra~ʩxvenU &K6+۫W0 S "0TWLJeR+k,\xdhuH]0U)Lܹ5]t҈1JsjmS= 9}Ntʖwr הQJlP+wDtBR;B^}x9^1 !89z@vejLeґ8S3 SٟcO]6Bva- 3|E՜xN0EQ7Ѥvb'N[1NMJ=)eHsLt]qP'T 5jjW8AjsJjxC%\ *]e&jJ8Gup{z[cM̧#.JYT{(%&O W5Wu@;_Z0TZOa:ys`nKs}"fu))ܬ$47wb(0xNvQü@Ok9! h\O|PӡL%x=O0w Fq @]eGZmmd;H{0Nǣ퉨yosQժFT7d#PռۢżD5]mB 1n5~qLLl/DQ(\<ϙtRUS;fOp7zIYǥyTo֫c/[S1@NEH ҽ!@LGe06q_3xJhHc-U$&1b.e &)DOonj,z\5o3xR;0+F[݉Mg;!@B; DWǎlg./@5IZcBִU%y/Z*ۆi]w=c-y>ԂVMk!贺t-X;ѻ {—lB>%~Rh|)C"sC۾EE0M6g$gmww%!M}:jXScShp6eVyȟHȻ>JpV)d8aǰĭ}7l)AQ[D":cw"|. #֡;cÀsȥf*a;9wsKW`r]d~ſ=Qhguj6;w:3?ncJXf&^."iVyCcZq 1L,c)6ά.MC *V0AqWdg;vqX-Kb jq'C- P\OOڥ-- ?ƻ]Qsَ_OWYww{hqFG{{U{i#>JBN7^ /a9xM0=b%٤IVV|+7V3iT>'8D(Py4]*2+eU"ydvܡ ꢪ¢ODi/E\Ue)$Cc|#|=vǯGI쬉H"MӲx'q̄:IVfyMקAM@(G ܀667"hk@FO=s@.T;IUۅoxB tn[L=K)"I6'upVȓE 4%t04Z4 ,ƳQ@޷aM]:# *8ng]82^[ l?׽n)tE}ݞx悸l鐽[n6= !$6~ 8FhWٜu\8Ky ak 1mڟMɴRH+0bcSk^oa@۵#9 wkK4'1(VE=_5z0xA0sbIWp c{Xmv_ϤJa7yߛ73.Su9+YF;akN`gՄBQםڶBZs(b=){KcYl \gЈJcߩƑPW8!&x 6f9x@.#ɺ޵[ k>U&/Xt`$3^>Z:o |6gʌ'ps0ǰQa+ G.Ngĸ'\v,oulVD9 f vq|'EeqagŇF_M2@އ?xr$u.xf~GZΫVFky`VVjX픪qݨ=q#m1S9GF\sCxzOZWMJse)zyZƎ`h~9א:4r>'02`3:ZV􅎬cDkK4ZLX]҃B'OWE

s :u0%t4bn^&%2y/YSǰ&p#~2p+8 a4mt8 B pYc?7 kxBĊFgH0aM0wkMBt8_}M}Pp68$<]=9xKn!# DQ/|A o9Aٙ!,c z!AaRlt@;k: >⪝ie&%,04'<'D8op9 h>}VEp(ɐ$[IWkì€Csޫlon%x{Bϯڊi5q94;");{ۖ|Hqѻ}'Y<^b%Ǯ}F|9<%_DXAUh+.{'wjtT2xЧ<85g2ӓ84R{[-~TҠ6xPn0 241lٲ( tj hR}r!H=%mT]CSuiIT^P6⌞lYkR`QcuXu(,YUS/\^Y Ѫb¸"_m'+\¸ecԺ\EvO'f1FCN3;Bo&dM汏I'[pB2BtZp!bvuz"_eW;7D >6-x>ݒqX=-w/%ԐxNAN0sGi2MBp/$SZZxb[-U6R VknN]xc9FQ#'sBm%eg]RS]ᕗRl>RKj HdwJuY#ǀwD= \lu6i8~%ĺA:I:t\DoRo{.^E}#o4xKN0D>ED!زk ')Z<:@KE{&"z1xjY  #&d>ftBwNh[63Ԫ,p7O.Jim{9~VJ^W_zJl)G&*hs)R/\%ZJ?'nxOJ1+.;=ED {qAϝtI,2~Vԣ0V2c 4hii肕C kuqKHa˨|b0+k;^pZpZxꈧZT(W5 "iʭ?Czo=< l \ [|m#mc>"1]]\_"Fnђx;n0D{bH &9?K$|L3b^_HQ0%$5t:8+R44Yc 1191YY 3oʍ6x\Oᐨr" PcPJA#"ZzBv"r^Rm_^;Zܷ^ xAi_G!>ʩQ:p·p;F|qux;N1ss#ۃڈNO{۫Gbn/)URonDWi.JiĤyΫF >7jPSJe:NNZ>I>/so4aĒľGҚuUZ)_cZFP9Dg~#| T< ; ^˥Q:OYdxj1Fy/q̌( hI$C+ vfкDkV٠m'RX85|ЃF$#ywFaPZҮNWؕ;ꈧ:7TV^R59sMsf4"pJ$$n,Z8獕Zhb'6*HER/)xyDK"#CmkWoR uxhļReu>A:iji 'DsBsBక ̴cpVR9uq靮!coThjξ6jؐx1N1E{b& zm%3NVam䝈 <}i̐GMt.ǝܘCO6hTظhΑ,by7V{i 6R1;m=*<ɡ6xy < ܵo{ϵlRݜ`sFM:ϓ3 8ani "j eeT \u|JL՜_'.pxn D|*`0z=%A!$_+siv"GhPON 7I 8hF8bg, 8`PsՠiB*4^õs\*='RwӒSrV O|syYbkObB? -^`W!oXc>lbi,)CKlG 2yr|{{pxAN0 E95[4U&iF puf* JR =__Oϭ0qJ. DAzc)&zgؑ©ڠ';AMCj*=5]r7\*nW8n%r~pr<1C8.M z\{iuDq rpcOF J;uŚ?χ2O_dgdCJn4H+նm,)yJV^_xG@$kyWOO3FB}fZVe{lX xAO0  [iBpH'7qڈ6 ؿ'$Kd{Ijݔ\ir UD;ٸVnT[1c-mm+v#5vbV5V) pρ8įCa8ހTJ7|i)?!u) ݇JZ@>#9! G2"ȧ䳙σ_r۞L^peFC08f5=Ƒp—7=f?5./a/rr 0G~VB>`q;γf nVds. !|^syOxAN0~QqB9x^%^KP76&b2/E8v>"'uMj^@3 &kdP@ϼ|S$kclfoQk])H4ͿY'xC(rh9ҡQꥼUIÍ 8Q}L fxNN0ۣȁ  ꍽE`;r=f3iUg{t=`&O2 Mj*b3i}d2Fo/SΥ3/XlpS.H*otOp%5gE%>u-A<Ӓ^av(I-K8O'fxN0E{h#+hBC~7nld;E͙hn+ # cƣAis\!RzR|؂,(e RVs-"H%rح͹]1'p[!]IFI !>S")B_ y- r \v5"\Wl kT2DUNtuUbל[U4)8c;|"| ke;L]&}6]>CqmڶyBq4)TeTu _D1d3io 'n/x!m,w`)A0AC7"$;۴⃕k,Yt2C`m"ЯRW=ɭ+ l'i J1$@aqOȣ t!eBng5;VgGwLͺv{޽f15,_v=hom6 59 3ey~E Q&9- /̆xms~M1zYH׃,(^L͐5f8d2[N~ޑ:x㿿.bkxMN0>Q"fBXqĕ"r{"z{7fI9!j(G*#+5^;D.y 1;IdfgvB ({mJˍ6x+ؾ'Ԙxx??nFxJJ범g-:=JDC 1|7349A.V$[9A3k^4x0~eWMપ[c  dKIӕzi/?S@U*u2֨JJ-Jܨ) RJkĤyu},TܞZ5Xy<5ieV =|c |#>t{H>k)/A+YU}:û\hi]J,eQ!1irCaR0W᪇.8ozF}AVa{x]!Eql{l/~6߃@at!|Sf1J>'L1.9l^7k? aMhMʅ[Ҙz+=~pjFA#1S2CZG0$lVO//lm:&;lhK纽왗M#a[xxal/'Cۆx EqGs k( &xn FAZ-!{eL#RJ]kZɥMLpN03 "|.ϥ, 2(SoM4u-+]!l}% ҁ Fe${^ D]pE3H*Λ=CP CxQ4zI Bo=؃T,K|ryI{Gc{c n4pJzp3z< P9̚/1)2dRSL~&\ۓPN~y~”*)ɒۋ(7£a0#`;VAY_[(Fwڦ*=e҇)CX tu&]Jw-|$~4Kjމjܜx1k0wٖe,i KO[ LI}UP:n}vm6Q12* Ut Z1,?57Jv+a"K:d=j_oq7N(+֔eyeLgxt:bwl">TLEixz  otFu!!jH4V r*M(ij_&5Xuڵ0Pޘb{߾V _ܔ*xQKo0Wve'NAU "hb7.^;NKL[ q`F'qg)E8fh^vVY93 jl+kZ;ݵփN)ç%2~搾cJxB&n@5S6RK)zRh3a}6ݶFix'Ɖ;k!Lu,g3 D|[*ZjXy-Ѭ-遇Lr3Y\N|V/⅄G61!D`2EƥK.+'8#y>R)ģxn}ʺuRYOpHvیOoq g;x_k0).}JXo2єu U-jKFe~Wq `˺=q.U-|]īU"P 1+xʲIRsfJUeʳN0JcVȓ Qs^׌CcyX.iu5ݒHbgM$l4|$͋8㤀qLخÀ6F:N סּKW/"o^Dz[Y~qw\r<[G?!4& ؃d^ (`}ooZ ZI7vTѶ`e(㔛ó<Ns=hPPK`$6F=satB`OF%Mζqsw{ycEiW-9x<;@}eh: :nz@П۞,0`vdجh(4oY@x'_?O댂|aZNjA/V@>Ηxj0Ew}M'ɲJBR@wYzJDcH2%_:]p8f"O}S3J+rbS#C"Kj7p뇻1U%t<[{fjyכ!xPKk1W 8f^PRB-f#[tY4Wvsʡc`{k=R7Vu_uUUg;4Tqc׷u?}aW:K8\NpMG^_9mlw[UL9GJmea[Ve {R >GgD8-/]!38/ ґ`ptK'`{9\dDpv7rD^)d]"džpx(.[=l̰YC \Hja7s&̋|!:?8v{qs~ť#~.}[(xر} W#4xA0scWmB6YVH{=i:v{&m"hOyo7艠h5MSTj2jrU` ]u+ňlYhVʪ+PUWnUb<|!:Kr=Tl*]:>B^e!o ,<˄tàc$ I诪'뛺E6%M[ e]ZtГDM'+r);,xBEWHX(p{ǀuLl~!B䢕\pΔG#yF,#]}rmUW2q2q,4Wڼ\i 2 Fm C٪h XHFZMj8qnGJ__*[%<)/0!)HpwC#HLfH譱޻6`ŒOq,Uw8?fƢx=N1ާeY럍" $8xg#D D4zIf9< #̽W7AOi$vd S'|PGHH!sTsN\aSn+dGM;@aZzkᮗ}/,sk\1QaT֜`'UvuV]:װwƵA#6&hXv* ?nm!BͻĴ1e_'jzxJ1^)f[J"*i2iCw%"}{*^Ws`R"%\]V DK",kɕlBG& UMAPRQbySS-,ZIpG Ggx<ݵ~JIM&nR-o.YƄG9t[k7MG.{)= z)AI G7h1Ao̮}p,#}Ne~&G_٘C4$z-tIb@A .6tbN ɥUj?_cNxJ1}"KE:"uBz$9iM2$)һwYW ODy#wmL 蒣#68әgق8͔{{z88gS6-|D&29TU>hchX'.\^4 ?G89xN1E{hW7RQЀ1`v{@EibδBe3*Zx1e&c##+n>j6QʎL';c..UؖkGZrC0HeJ":"e[L+t]vrH  /n %>v\ȹ4 b;]M{b,xn <(V-OJTjm\}DY |stlJڞ7EU!WR np%h@mVM'JJ:\)pME)TŻRr@%ꮯ%{`/M<9Y/  HcRN(x,q.xa쮼w7H$ bBgp31 H#& 6`_?uh9 p|ܲmzVm$w! v|@u60h)Lv> ϐ7@Z@^pbya =Slh>Ywv%c_ XhOl|hOLᇡP”xN1{?Ŗ E(4 :wQtPQe)f͕lL InhqqzMߣgڴl\ږPЏAz] LʡxO ^2Okj<* J.(HPI)3W8ᣁOJ 鲆7j=h 9,[xR3}_=CX =Դf!oJw>O{xn0DW cC"^Z5_`k*E}ISO=aF/'fyPݯ!CGNHؒA\M;kѴtFk,fhԦ!t0kbo3/fx>=U%CicRlwxs|&Y~>eLsmZC!q7:;t{9 aw@!.~ LEt/_?T|'x=o0 w /tl1%LĒ Y}tεC!Z(>c ݍ5aHjFu*F4$̀(V "H뾕C?r۾Qm#n)>Ow}سPwezu^sPZ'DN{mjѮlJM\m7qrzLfSjzmKWo6Ơ#~k\Ec> xi4gO,u #Um|в]r/G<1 N,,b:\eUJF)p]þ'ba&- ]tԞA]< Y*8A>~}|w*mvzJ>Z>9Ci52|z% ܏yW(]@P;t.1+=b6bjoNL 36(d~JgА DhJcAs0Bp`rw|q"xKn EmltI'y$׍:({t{tkFa ThZ=C}ߓd\+ :F)1Ϩc ?x\@̭N)m ^m1] ot^L[#t3hk d>VxkMvm@r@=X*nBw[R9%d}BhK~Yzx=n0{b.16`{I4 36m%w*Vf{9"ӖITX'&s{zFљN]G2Ȗz#W1hʱ\.ێDy ގey ?§^|.祶a}¡1hK)):Im^hi߬CF)QȫDG)Ä^p+d./;Qy.x͉a7tU2ߧ{m%xOn0  +ܥEDBkɐnNrr320j^[BV]-(O@|-9a|ӆC2;y{. &0VoҎ~Kd7COzp )#Vw %&7:a&JM9 x$g~Y)3!s*`=| 90Z;B.1 ?x'Ҵ' oR||IfB z\4yގMMwxCg]-xMk1slJB14arhWxWZ$mM}봐=ϼJ#Bٮo U^`^+!5EyUy%WZש`h#:6,\LVj-ʵN3va&@6\І#NDϻ[GuU[{ yv?5Vr?5uXe$I;yGpՕxH z}'F"tQĎ3=}/f)n?# g1;In@Г1xNqg,9u9R1alOFZ:ſ 7鮯k5u jx ƻ 0P%%,q,rw%%C8g(2D-^ ]O!3DƗjPVt,Ų$Ԑα}Lj;7Ch.94XyMP0]!M* lI_fiYpz5Wl'QRm͸ upC“(xQn0 )^a!ٕcESa=$:fK$7OQ3 ةP̑D\{iiz%G#صh̰$Jp"b$Ap/u:iVuir(\0ܲ ~ _fOoA4#abxyLeq9S'N5CZ0яC!`7 b=ܤ >d02F/J_vz+;Ȗ`hxuϷaڼ.x*"/ѕs?29.  b5RJv5py3T變6,yN"^7-[,~Z|bm|aA :R.m{qGOfiΟ:SAxPN0+R[IBNA*jmCG߳M8=Ǧ@U)k6屮PdkyHS53(2EJJI&/uAhju-DK}S_0h8oǟy{c^dm#6}d~]Jod @ myU.%?C5LfW@$NJN[P ?Hs)1qf8 e2Xi5fZ0S,#bʐ /N[piM8 0DC+\I~pE롅# aƹ`1e4#%dq~+Up`S$טzL579y~lr9H€^:U]ad܃֢0eYl&oXAɪlz3A.rc{đg?oʞe [VSXءwna2KrsRD XJo4*Vrt*!N@70xqGC\y+J˗dxTM6 WP @{h;%H%赲dHnK{ɭ=Z"CP)A/Θ墫º8ҾlJEyZ@jC yzԷkýt[mKQ:C`B:{2|u>9%5 jt/hPU!G!Wlj:z$n$5Ol-]m5:?$h067asN*Ta&Sj3X%&](ٺ9 `l]譓 zpZ0V $M +hqdWH'Q0bHo @e^0м/K/N됡o'IQ6momL+xæY?lۂF-AfYdIFڑI} P l(8s,p\'/2rEg7IUYq6ӊm?O_z>}y;[|Y+!OV"gn}]{zտ4ّ'xn0 w=Ƕ|AcJldH]$#Uk)u#{LRZjnOTiŊB9д=MݵjR LfQV<5^ !x<4>C9uKIJaRu>7k!e W&\WVteR̹Zg,-q$!~(0sG:2a,+Mg|Xw`9&W@d!DžF=[>Ú[ڑ4fo4n xV'A|9sY\'J"*vOXyc4^م)ALpŊWo;1 :W$NxMo0 dNz]{nq$jI$/Ϳ0d|H;" };IuNKYSӵoĂ\Zd}VR0Mۦk]/{5M>ӄG_0(q)7/׭'C¦*&%T,^ds#4^7B "s`(ar,%Aa0jSεBBf1 >;il0vLƻ(*(<` ^Q욻S%)ÄAg= {l~}ϴ9Fg+3GX#B,99+``gMJ&&2G֣a (ˁK%.C{>T8azx&ʬ Gy@t#J=)/2RP2F"*QW‰ $^܀&i/-0Q*,p4z1U5Y|"F%Om;Ȳ$PgYj-]1^}QpQٞ_sk!1 3^P>B<W F~4e2$\L'2'3:? yo P,xRj0}W yIBF/JKcydJ[I^Β {q8)? 6%o{RG0Eo@'ߞ/x>]cXG)DXHAۣqϐ*7 ~XWEQrJ8 I@)U9:OJ>neFg]Ly2i1Y捫s`|!O+fM);ۛ#]xc 9?`$~őxKj0EZ@>$R:괅ty d'iJG^8\5DjnqI{o'5J95,~T !:G;J͕FÈQ&FkSv|ky~o/ JH8p9 u]"{[nQny7nB-#>3B%R K[jA˷Pluہ*2ߟ&˾y)x=O0wik;q @N ^]KbHq[V,}H*^ !j/%uҊHΪ!&ԅTE6VJ3n[ktC"liΠ(ۈ9_{м9?B"5zxW!rs5e7$nJ_k;y9!ZۂB/7%sI%c7zE *~&5xOo0 N0 n=XX2ei%Cۏrma'۔{Jd-[R~l(JN6m}Ŋ\IC'iA}39HYnUV]k9"ac]um{[U}U ŦD l"lz>*2m/uo!smgk/O`#|53& (1%Xgtκ u@PǸSecn@VD*Lֻ`ٺr#4\F;ދ ݍXbLLZ0hޭރ ~昘Wzi/+,\,TDz(ts ~ NS\b7u@#0z^M2!0:mg W04:< 1r{qL7[`iOxۂ-hB :BD1+6첢z}c Flſ[ n ooICq v/qx[N0E@*;v@ @ Lj#t ވ Dry6S!*F yklT:xBmT&BMg6,ST>Jf(/? bKzmy5jtAz)E[ a-߁ze>8A,o¡2o7kVxn <+[UT^Z5Oo_+z)s~)Br/]+ϛ;K[`q#׆kT׻խ!hiDp-ř2=MqmׯhCE+b6NS(.x὆d y_c:ljWatpЌ%cA^D98CPk1S8}eW|9Ÿ~xn  &AM U~tjN-~۔BX7(Z[^)EcPBfD%mfN6I.u͕QrSNs1gs Q'4"xk t꾮kLX1@ w>Lc\ wa udoPBd _b:\{bŴ26'ٜ>{z{7$駀; 翽xPN0 )lJVIB 9FtɔL ۸ɖ??6"7ޠwnTr]YFk % I+6vgQȓhYWs/[x%,/ӭnsS;cti.'0Jij`FKv1Mx&"gorYxkӂli :G^ ITaR]E'39"QΟ~Bor{ۥ󦐍#xQN n-m1F`Mn0lIZhfw^Z7QOG D $G8եRI6[34MvxԄlQ\--ZN6n;MKhzz4o:;8J* c\v>j5RT%䜡ges`/ZyMtrlЯnUCLAav^&C]EG{,*IC?+vkEfa,YM⾶ [ti8:XH睆GiIpm3O@MCvq;ŦS@+0`S 4`͞70\8xKn W^UUUꪫVLh D@4ۗK".HjiQ(z"=[6L hnG>M!JZ-5퀽B0xi0MyLcTo1 8s6uuп}'XmE0= ^"P{"ʒYeXcy+A'\Kb {w_s04h^p+ˁ"8W)lKo@㉭8k;z,3IK 0vv@dnwj([,xn0E,,Q}Jf V FcwLZU_J {1lj"^닾ֆڮ򪱩;Z"jA9Asmmy M[ݰj-Fkˈ gBȆ!.ӏ9*ڦ,Nŭ( R6P_iƉ rSL`0R "7:{ԷEpd c!N()dq,sww/&ّ]w}sރ%!ܩ _<5$Q%1t 2RFY6 #Fd_R6U 1Wd0TL↙S;8xi0 =H뤔 Ztٖ@bۡdPN8(Rk80KqbU˾1nxv25ih5Ѳi ~;0x+7VV c e#D/gWGySy@@6n.//8#9M'6Og],`Vmn&fWΎlK}3; xJ1$RWn%?nhlҷ7ԫΜAvoТb%(k1^ eI& Z֝Z[mT (M M舜 <,eO鶼23ӎ\=D4hZ~7 fx[>VayyD )go@bft:2rY[Og$'ra{9oe(_ 0c:@QKO RTLiY%x-J2]Ag/˳n, uy[g (9xRj0)Kx7]R 䐦Ba,lueɌ8ۧHBH~gktHGU7]W1Dƨfd {)Q͑A]Sc߶v]K㈫ dE)>vwSp-G]0M6%O~#~10sAz -y˝i ,h |{ [ 2K(We^VF!T93fZѳ>&B]%YJ6MOOJJj)T?e&X&vg)bAz$/ )dY Z7UuW RJ03-٣T%e͉ܹM#fHDbXA6-8G%20X T)T#W1 aɿs WR;vSft)2&ZGLP$e+|)Xv8Yٔ00h%'sIlidjNR %a(whO:sݟ?2WW>h&xQMK0W~P܃G$6n$˲޴+ ¼ 7ޤ@Hd:㭐V\-ڪЂL;ݐ,a3r *.em8KBWe0 " >· -Li)ѿ 9@0c{N*E6I0@%5V1J7?#+^M;nV),Ăw`H`gk 1J@l /}La8Wb5E9 tWcOflOEH;wޘ<pxK0+MwI~qWXcyI^he{"aG"@ LEIe 2*2!KNń<,2%cTVd6bK5U٪\ZCCG-FCp;OG!vwJ2+&c}G9nM m3$  /n= iq%+;u_0{?5 SgL1n&p,֡s0(s~sy:OvvO7_H؜(xMk0@B)"!B S$2F-i]z-͈deYԘB7RV9e%& 0y*)"t}Ty[R~l by*EUdU3>{8E-~>tsY˼+˓BqlBCtS \08:h^FdQ/Go#=!bxj[x;>Dp1`qUhb4 tОB\2a0'9&c?HU7Y޼ymtśw$4&WÖKE90xn30,+wABo7ޘ}&ٙitTc؞Cy~zԵ$2aƬ٘{_ grB#x>Wr--=VȡJ?3ge 3ί8Ϊ(6If ydY&tFyL`xkn0 (IUUVNpT]ZKLDFZq{c4i.Q8V <[1S,`Wa7N$!m ߵe(S0LGA )@H{.OT\s\ a. e'$xx&6aM@qm=)@W=1v`")opK[h5#tnYF)cǣfl*y_oo~ϟxi0Eb2+9H l#yd ֒eBO[@rz7Ƈ(-ii`l`Xܤt mFHy%kXg |(|Km h2Pkm`@bݶܻO@C!նq, Գ*o߯+-~D?l +Yp% %l[G^3^gK_r]+ eT_0=-;X&oy}kOX@.]ne?ey֟xMN0>Q#'/PW݂83jjgBZn9UHMWFz߷xMVTdҚjˌ&oٚNm4Hh#{lJMkk*nɬljQk ¢̲\Y!Aa??y;_`x&q3' ΋j0NWh ȰƟ$WPlt ]`<|zDN GOJ } ր:JS#ȸ1\a9~kWw%#*r>,0d)Qzϴ ]i g8WxN0~DBDuPq@}{BˉS4Z (eNBF }^zme0䇠 [l.7{IR8" eSZO ^9'Z`_ph9CnGRq͵r 6lw8M^I3;dp"[WbYJɬiE]b-+̊UԫjC(^5 R5m,uY- H\rQUS91t1xq֠k7C"'qUl؂T.XM89Q)ff1oIVfct(#eѐV33/mĄ}ɴJaS;ݩFմ;YI4o S;;lu ޹9ׅsMU+Y,:.%^<<5vfw,Aĩ *$V {Z$Np(G\ʊMWf/'"0xZ9$QQMVR51Q P"]͛ZH)Qi iFp[0qHF>m8`kG0:S)AY /9gv3-#<L,v|!亂7Kwz|!qu@y*{̀Ҙ'@p{ٿrq`^}8DrUr^ʑxN0D=PulPp{FqB{BˉS23ZL$D)Ձ`Iq=w0FHLs2RRN /g9+vus9 6oiv7㵧ڥiVrps)Ʃp8k n]aum@#rPk\Nǩ}Jq&_|?ǻup+xQMo0W̱Q U=ٞWc3޵bld"}uڪ=/ODPեԶzJ,ڎ*hʶ)FdvVɲwԊZN.!&\k4mTEOC|]+ޗD.᱀QNus!m ~B|{@0D30' F/6]=j627Y=; ]6pZeN໛?RŜȾ084G*ȼE8s:4&vQ W) @$G8/1.g;naMeP?ZpdoC!ē={7Z>}4k fxP;N0}f=8!Z*{{


 T6YnV-ΰltg_ heԨ:vLNwJ]i|*"MtY#xR0D{}uTv,[0T08KXby$K*]}{W]ݏF^IP}+[]kĂh'rmSK lF2 O3VF c^.b?A4eFR _  ޏ3%a" 2(G*3p48Cb+8.@Ns B=.B%&L+b ^ʙyY&:/KBa}S9!YX zzf-~Ov˽y.g .C W`ϖ#aJd7ѹ͸q WxN0 S46K* CCbRv]U!0 Dޜ=<B:"vHTڢdB$h z}p@!E-F 1u7LndQBt0D"̯Nߵ6@4Lp0m?Kc'@f~`U+ņ"Eu֎qrRkܤ%uJ2ܥ(CEs&*^Jf%v9>}2_Uů"r cfruj .5Tj=S !9_>)/j 2K k9auZz%a_w!Tji#x ua#CwӃ8koӊ_˵#xAk1s/.ٍdEDě&Dԓs7> d[v5fJ֨d#.gV,boZ1JbGV׍k>[-xN0m+uE<_P] tJ/pa97|2F0Oǰ*`euga"m}{3 {H%Sī? i>{{rNӘ/xĿ~q 7w-2خ t@oSΎiR>A:2\ czU 8MK']71uZ0v"55eԙvNx:Aewӳ-|1|X~K*pNt~̈́aC=gCL.zt"{<]hT%xn0 E|l%Xbhv %Cbf' y"g"m:kιƐn`dƵl5oԂ"ö:56VΚ1s[S}]cʰ>x"#=Y֭5V K)~skx&̎,[]| tZ@UՉy>\a8EH0R`U} 1|È? J0#!~ )-`JOfTN3΁G(rRgp&0ᛝ( OEh*baB/jM(k%*|H{QFT֯* ê|u_c5xRK0W̭Y ~)lXtsHDĖ$7Ϳ٥ғm剞JUeخˢQE]VEePgjݮYUɺZ1'dQgQyC^Sdu)p'ag' Y"=^ yQ7Mn nL;·zI \9 ڢle2)h8(O+EDp4Q;ʟF Lw|q\?2qJD )MLBn~ptR3ŠO+ZAg,'I\ G4&=IG&o9 #ʳ6=qA<#/v/09H^L0RG%\>&cap F2^3?>>u {8\#{慂0II!pD6#E*5솗'aҚn}k`- mgrAɧķ ֙%tZ/Oѿ=} ו-xRKn0sֆD vM$' X$e׷HN7Y]>="jҴJ:isZR,\Kd]B贮Ty*յd1E֢)\`^D.q Gy{C h.!.J%|I4M4M=QzmA#F9ӆ 茠I#I^c~# no. Dp5!.+!?jw,op(5gђKD…m HVK-!BXUg_%W:G #/ NYD̚[CbO76!Jϣl;gY[Yk nGP&螸Gۓ1{u̻*&xQ yRdw]3c,muEfW3 j;[ٶlLV9=6c'hN+bP6 bkFi%Lr`m`ne J&rz>e JmQ>J%pqY|)yk'c^o>4:F6p]%N0~a2Cn;S[24=lf{Kl=ʉa`Lqe#4KVnMY_q>n>i&/v'Yݾ.(w,/~]q,TV卵] 'U+aP*Ig?cϸ_%xQj0)=46JB1$t#iYKFY;9P 4MD ;rPQZZj 5 V,gըVaG];k(46y  ~EgR Җ~@U]R]VR L=F cZn[xuNA!{&3|H3r%b&!'40\3[6 35^S8]D,1_)A?]6F)$ھ}6ȼ >G8HޠU.fLbf\DB=o޿\3;hY&mF6AX?7mEڞoxAJ1E9E$ݑAfBaNPI*'ix3^ftB\Շyj8)MlFTx>rF7L5$V* ~ҽj?Z$>8ɽAe8c zmK.pJ0U/՚yUwK9j % %x3Sq ^rIz@'"%x2CTob۳ qsb:~d9'vxN0 y ߡU,]&8'ph*@=p8XvID`)rzq1 ǎܙنBz5 [-9^( zN e % Oۜc)nBʽҦ7q9q]})2{^%886KH} 7U.~^}P͏#/m{|+8W`EG-3m %Z|us)+ Cb120 υЊ~t꜡C%{ŻK!ql??W'8nxj0DI%9z VޕmJ$#)}CSa0<^̠bM0J6hc18{Kwc߳0s0Mn$6G+Hv2( %e8Fʌ:"i¯z0RYxJJ1u3\™1O =۔'hkG"8a78;`$T#sZ| ZGo"e#SBh}d:Qtox 0P) ;sξ).oQE(``j*aVj6l JŃ 51#k:>tŲFs GF5k^C#3K·P^NW,ջ 'tx-0d~?;7wf)fzBF|0 0-1N-|Jt^ES+7̫?nQwkZR8Rt% J}fsCxc'n)xQn0+ )zK n\4{/Vb*IEp+">gggv'*YVy^ԅKjJo,٨FMZJ1'J\k*ҥjʪd!k^6*Gʬ-kc윇U0god=ңuHΫSI";Mad $rxb nZ0TuYTKRUS2>Ӂ0`{GHP55ms _e%ؔ(^ @p}xYK @PHA0ہ\$H~-24G_`=\Ce3E!ެc Dɺ Pkp63$Cmgn;RM X ~d` c&ԛ̊Ɵf .q;+{(i |a9G6rKr&Bp5c\C? *sÓ#]q,CW,+xA0 ͐8dRC)}Ql%1u`;_eвғ|x}STݡFj۽QTS[Bق| bo4j"Jj Ք]^Mk8ћ@s:FKJ%}ueQd٦DN^<|w  r{<;PP@^@s <E &Y?BDs'&B&1m`tܣ,`E!LVO9 Qxzڄ#%~0cllvv200^o"#~ Ȭ35r 8 Wll]<ʯ?E5[rH |=HTz{kza]1Ǔ;#d+dɎLÐouxAO0s(-1a4I/4n{qɃq.%ot kQQQ)y)*jS&{d}Yie\ ZiYY^2Fyg+*dJIXM%!BmD):A1,e30eQ1$h&T{~"v@p% : 8FiXqѪo7iS&,k r0ym% ,'3xV燜=SHo1φk*fxOK1s]w7+EHŃ=IL m$)ooԞg9kC﨣Eإ&YPFʆÆ7 }`#B1e":Н͞BfW#L2y*èG! ^1̰JK1 Wpx: =Lρ("^L?1ҧ uO=j!xϊ0 ~ ˴t'8&qRf d[N&`)3RHOOR`PI[ Zhb$8 zcoFk 68j{ҍM\|!dVc zBӶ;=hw#F*2=~Gp~u.ӛAgh8R;.V|%,RLr g)6Qy; 3qk^sG?~ͮxN0w?m ($NjЊKFUߞӝ>ߥ@wHhP2Z+يZRQ(0KP9)AW ّRPUVE-d# >0&XwDZ#݁.*$\s9x)Q'vA,.3p4epx3X\ow/i~ؼ.5 1{ %zpK@@0@0ZM.-lx # $lۃ>dO߷fz)x1o0w ʒ,dO kp"&H}ω@Љ޻6ں/ˮmvTKMMKUQx0e[ZJ1a$iQ]vuAC_UXԲU?tP#p6Dx:&xNaD?gpl )4 G>A #e˪K \u &BwmX,.[@V\Ps:e /)S_.iXa3ŐIePA)3WqnOns^ 37+*솣`&ੀ\k,x'oif|!a5Z9LL_چN^ٓcke7xRk0_qomiq:~Aeqζ,},)i_NJkI[MT]K]%Rدq}tD1K mSnFQnN6uV6l9>Ӂ0§`T-ҝUP7US] U]UBi2)Q݈{_V0(87woʇᝠoXV{Yfc)\S88QFv+8O c:Z #Ȝ`O\98V:_^v//Yx:/`6t4<`Zl.n&AC"-F8Gv0[m,@0^ R"Q6ɿuF+!^G|i# rqgve3&5R,GNn qȀ.p^-(1~9 S> VϚdI})PZ9Eۙ^_Ç?{h*xxN@ EDkP V hg*OZbX]ˏkp"iֵmeu55|_ ^ J̘(0JVzJVRk)uJ <O^r6H8ePZ7deQ*)L #^A&Ϸ`eLzQBvy~`01,0x<#1xc@絴2"wyc&̑r~x!D/J 11u5HbJV`UbZJ!!/0'߽!9&xQN0#☼VAAA@ &$Hv@{&Yh(V[X)Բ3ʦ6nFcĦj%󶗕X0K Bת3EJT)V51i 1z7Hw~)H jTe ٦D^Gp a7q9;a8\)Y+8 'Nd5B!}5$caX6id;- zwv';wͺa9LO>CBs lH|P8xR=o0+^2Vhٲ"(!CHƉMzvv_Zke0p)k<&Cprb:{٬X|{rLt\bJ}38P9 FJb @.q1F-c < ω ^pgo%ؖdH@iz9.A' (?z' DwJ^?01l]d@J"y,,00 hh מEJ7<D҅z>I+/={8,EdHhC|T"gZ,\(XT⤥\ 3/'W@v`>!/$<=h0KݔR\|ر~r?z|349‰ !fxj Z_Ȯs?Wo2xMk0 "e7݇(MFb迟"z$=FnytBb+Q(YJ) %L#4ѓ ZuQЪ*hQi@by8x Y!\恞@HY5U 7MC㗅^ !؅&?9wt\)Q+m78d!~?*{UXsZ Lv qY)ciL*5%' <` ,_' -cz<ӕu3f?Nޙ3vNڍ뺍<}I&xn <(u^cCObp'ڷ/n6A?G"P}'QԪSuu*Ma FH i4vI{ԈHaڞb)Dx&&N)xCzK[%Qrks<ۜ)ӄT0jlKBE@,`0oĴfҲyѐ;pY=Ã#Mrns$,-fzzGuX]bdq=gP,,25F?Upe~fE> ;5xMN0 9wMBX nLmR%)ܞV8"y%\K\ kdSZ;ʊ+E CC9RCiZ%ԨEz8xqrW ?~ч=T˶)P]Y2٦D hd'<;;$ʇ@*MW;YM@=PV?f): 499`Iq&3ۄj)t D7#BaP܂iYʳcŧF]<2vgGoa_잛xAN0~~ ؎R@nhm6Mh~B}fN3A7*9Xk\G)ktdI 8Nܳj u IZYdz:fx+aWrFz)E4J 8g;s O~ 5zq 'ԁ`).xf!vad&7ohxj0D&(V$˥^JIIRz ky Hr =Yؙ70)AQKTJ庩eBZU %mIkSnVB*FrQ*^lI SKNϰ* YJ-+ 9gƟ6%@)Y/of{=|6`](coecc߀K0 'hGg.C u0L̦H}!_u!Sn8 5xs6stfƻ޾q]qQmǿ~JBxAj1z|`YH!\rN/I3k-YCsOM7T EDS\m1$L"["ŋK_]ǡuV}/vƬ謶&VNe hV)nk2 ]fˠTh%I}*穉LohhxAn Eb.`&H=@+clPU}(HV-1$f*䐘$ Z\q0R`輞ufF4V7)9S oNk[aR g)EK_X#C >jk:s-;Úe܄8pjJ{|nH1`6#xPn  vUUr꩕X쵍b8I[ 0 yQ2IZeXĉIU+n d n8@Ռ{OO8gtjeQ_kиխWLLmWXX^zV{K˲#lFQzNa= arOpm^ui ƴi0+P BD(, уv]^7G210Sq584 F9UA793== l?&YD '+}bI"3 !Kp$9\'m5~6"w^xAj0E:싃cV)@7|y4do)9@oޯE mpD&h 8 GYB"Gq5ҍ)Gc]8H(ru,urY۶Gу֊Z忁ntW%@(ytp ɲטӏ$!4߾7X'f x[j0D:R(%-dErddݷkaވ@ ImLBAR M.ZEQp| wBMzOj@HiV0s6eɽӿة2]oH6Ϲ[]_amV %,1vs!jJC< l1xRM0W̭mդM"8‰jl!NNDPJw9[lup2XU:5v]w;5cZtvߴmwjXuƑ`+ԧQWmζj.</^|3a2^>>]LiXvi$d3Dy1@tJ}|Æן2ys!SJPgb}J W zk s h^6LI{kK_v.\k+uxMd-$7 eY俀K UZ3~NpmY$\{ZZXRʠsY*Χ[oNxAj0E:\a$YUB2r4Eb {mxkad#mB( k@#j;0/V**`';4*t#E:_G+=ڶՂu.Ka8ˏXP9p9v!R{DZug\g8n돜~ǀ8rjsͥrm_\o9=[Lԙ_ ]k&c]o.,fƗx]N0wb/jAq* Ă:q{~ӌޘ91:x%&ȆqcY]q셴'7 e?L6 =3Yѵ[J^pdjq{<6ftA;`@v>qVJo }e{!Zoe/[mwNeMdV_gxm0Db $\\J6lѠ޲fNʹ i1eo#do#k ِ+l<7>r8\@FeT8.SoHеM~>wT#ryܕ:*eG-5tI)b946Qk2).uMDXzb!qԕa}ZjfcxJ0E3Zrj""-ޛ4}amtL͎:9',Iذ1bƥ9)/mƌB1{)h&PE68^y\ vb!H=؞I9n+nOAoo0Kt$hՉAEG@AԸtЋ /(bǐ%58l?yoEѵ_jO"oj[_`zka@bݶ;[xZ kB[.+PIkX9:p>6@}ixAj0z~a%˒Ji_BֻĐXFVhBiUU)Edg"52%(. &V{cDb}S g%sp8_;V;XG0".ܚnc ]. }͘|ZTs7}`xAN0E>\ 8NbUv`SqE1nzXx"K61xbv8bGXb'Pd[d(v$4.[> io m4hyj w:0C E5zVR[Q^(3D *upSjixPn {)QUHZ` (GzmONID5֒ݷ։Hp's N# V\pvD֡Hf8=.#|nD sncR5:6圙8 ~CKp ;Z!UlrI)s"p),!`%ƾ|Ȱ ~uG jDMt[o W5aY:͙`ASw; q l4y9\FFߎ a`x[j0EـeYv-dadݗpNo"ZhI\L8'q&cFu&[$QsbƉ1Ji1VޗxjYq}O.&0 \׵w` O{MS]WhrE~_`q7ᡖ2χ[fxQj0b/ ,.zrjA-U %hf06giY,(%0Ǚhfvjt0 ^ĻhL(a8Gv_k˕ _oy}䩶 0hurd{3Q9vXsk<6=UK^K⡊ AdxKN0E^[;!hiT"RW<$WP!B]S2"Ԉ֘mMVM2:<%gq*Ƞ)jQ{'8I0v5rJ'>vhGxϿE#ԌF U34C)?Tep\n{n_u 1B8a(3LOa!]2,w!0T)]|@jxj0 ~ 7X$N:>@mqIb++}iy;I|@?'"@Tѭ׵5TEWTZ1Q`-* -7.2U[8[ovP7h1S5|&KrP(UWM-l6g t)M (Hr"tS_zB-apS& 3hdF|Ĉ,!3|S:_}p77?$©>t2[VV*wřxKj0:uUJJ 9@ +ܾ01Hz эP)o)Q\|!JmCB킣(ՓAZ^KDњI kmp^ٷ_~Cm$VV9M0En[}’G ~GnXr^Ry9 qK4yoixA 0y~%4tim"1"^ fN30% =SXцɛ@Q\`\3+B #/\#t{ -9 P!X4NJBqNB3 z4Y:LFPqa~l4EAOlșBshKR9W7ZeyƓjry!hƀL;g3[C$e#Bm}]T .4@\E qܟ5Ƿh<A G$ I[4?39SfS&IE)CQ|gӰ7ٞZbE)NQoPٰ%o//gg't m1J` @惽:<{t9xq8:89Ŷ?v{ghRop۫Jpj `z)JY+~&RN60K꟢xR?9xcO?P{;vcuuz7ћՕTѿ%i\ÉjfI`?Rq|; Q|ۍ䮳*c<πjFB0+ͦ:A~2np^UĢ<'Fb'lT\SF ["s%B`HzXŰ :ZӪ005Qf2T1IXĤy[]d TTd6ꁚUޣf ē5IGH(d<zQ͇G,,'jYZjET2NXm4:ݑ'|P1Z-@X3 %kI[!d&&g+ma(&PDc8Lm͚f hpPwڀw )0F˚)(t4 {cHHJλ&)*0NCy+vUR;B]4|Նj]&Dݚ0SErm*u&Kߜۄs#SMYv0k&t6h]fX5/{g=cB+5~shgԣ݆ҥKԕfZF.Kr/~B JwW,__ 0ښŽ r iqH2r&UIXFJP"}- FL^aSQ ̰~&P4hVq2 ̈́fnXe` sк2ggoX!#dQ8( -O[JĖYpe! W5R EiBG !Wy: `orڛٯ-6C\iFGDMڀoכdaiSA;Ipx@0(q҂Y>Av%#%QKU7Hw7t?}0wBw0CGb}N ȳekL5#a/X*IjA\u N sEQyǔaS-MS3[#<ҋMdmFAm}6Ci=[WIH58fL:/(Ft~tKqvD^ l@C8^?U{퀇yMsny>/ [~\(qM/>U/dɫm 6b|?8پD)p$]. h%>Ua֖ sBѰ{A3| K>BH{m fxRQ8(`;,nxo` p6Gw*h_Z&->,oCq|ܨoԣvp]Š4V!< ]D퟊+`ʲ=< @FU%{&WϟZWbsU80 6|*v?<'\ >5OS} ~}ҌƾS5! 0{F8Z'MH;J,nn Y,[n=kZ=d6bCMy֡iHv10RmC'yA;BewEjUd4$|L2 *--FHO$z"8MuK.LLW1y7,h1be7T!]ERa&m<(}`I0k1 F3aAz[Aظs((B!cq8 >Z\;N&Qn> 0"S0S F+ZlXn$&fG*b&S+_>ˮSm- INVk[ =QKKqa .tq@wg.ʆ|yT8Eƿ%>Myufkf]C]j% L*M̖0b^CƠ-0RCt*#{QlD)Qةӽ?W"_XbwĈQDr=w-|YeŎ%GV/9o՟f:`"pZ۰ofd-# L;(ouغ~gގ[Zf0ls(LVIZ(zB-#(vONGJ af:=ǖ?Pm愳+vqXikh`ʰBHndl_!0ԖZF7ѕZ>{k9ъIjU5EK5>sGܜ..YɖzϝT:g6 n:z/ 1‹l0S "O5'\!u &rޟJ?sK:[NLmPT'I(^ß(3q3%Q^,b8v|,0*gbŴ`遟3-41vK]4m^ D8) جF9E%Ԥyr(W/)nWZ|KgH1e45(ŷ^AY),Z)6)_hQ{3!NgNO^ mpx[b#"hlBn ,X : س 옟9֔w o`ueBY߾be[9{F9ɕ+,hIm8rSJɹq Jh՗62?}yZ!fg-cWbp5sF/~]%;aj<Ê. eAn{HtLMe,C+5K |lb|,,+[}d۩qiddDt=:,rB1/;.0mvX8kἿ45d T;1؜,i1L+f43i0As$eWgrcN~j5fاNkY&W‘ W܌BP< .f=L-iz-[VZ֨ ߳@aF-uL=yQ񁨵"tR6:»g9NpG@TxiS+ƭf|iՎdObTiNcf=ɞœ=MNSP|U=ȐϐX; ]K^RԚG(V/p}!w/ :O-׋@~gGf#ydox4ީ'{D\c OC Ø&}rFxwG5AO_#]*]Ou qLV(a[hd{,ˈy2|՜u*°ThBTwn|n\ȤwLc+ z6KUU+26+_fMq+/}:/GG:ǿ_^wt=EO# ;L(+ caE]i^O\5%M25LbejȸR L08 Y$}P'FW/,VĮRX_ 7EB}\ZfB9Pa!Ӱ.yhD]v+4'p< `iz"OqS%x;nOpw*Kj3 $+ 1IRitMޭYgKD|`uU@vx岮~0=#IHM5?o8Cg|j]ko>pӡzR=zzQ_# ]5]^<[F.en(Uʡ dVX+#ɳvZkF#F_K_U7w+vO4u}[)|q!i!0Tf{-'A/L޴EүU}73 ]Jqzts|&Nw D[3?9ܥNfQ%=崮*}ad&'đ6 Y!T䬸kqc9Zu~ K ?"e6,|)9ڱ `sjܷl)͈ 'sQ1 R*cr4!m›Jspx, >wm"Yv_VsJ17Ⱦa=n Wܴbr9?]&Xϕ"SgX$Ra}>RjՔ~ SdZyma6~(+N74H誔@Ɩ}]G-CeU)xW&uޯ3?z5O>,HVN!T mzH&|t+t"&$fx6.; 況nl^R߆AY19ɰ: 4n7yǟ1Pϝ"linqywF;p.d+ŒՕ&΁.*U|hbLXPghM^7J`L:7@|%EBHktgI#ڗ;ux=Q1`)?ht߫-xy+݊)_WzU(WaFuFCƼgA Rl;:?|h7GiCs`@U+-c?K"VHxu-(0fox1Og`4>y|,j'8_;Z1aᏵjT̷`=j\ _-BRcm{| WUPb ^Z}_KWvN8eO8:=̰-%2\_^u#{9,2BlO Ne{hkYsZ|Dx7FD2 Pyd*egazLznT{Ap:{GFxk|x ́Y7 I[2x;A f槥ŗL^&=لMh;MCp~,<ũE@_{gVN40= ՞a"/M9^$_ZQP\eř)Ѓq1ٓ+='3G*b|σX[xNɚi=GKK&O*,i K)N)*YsM# udw˜n=pȩɋC+'DLvce⬝™QkWhdz~IBi^N~rv|ZbfzDʨeT&hhBC5CUWFIOVP RP\YjlXm QX`d 1@{a6, h9"hRQjb6XS1 C1Ϝ SG(:k'r!Ĭ&wYs!h/"ah HH+յB R+oΏ N Z@8d~!pr~H" h0hvA~1$7?x |0D[9%6W]d_/x{> Y836f)ZysK *x{q^ 7ob|q,_xM&  &  E J3&~<?~<\ArA * KPqpl9(QkQ% X[xuVC$&G n>v\| N"xn 'yYJ* R'mgۜМ<J|Z\ũE%9y 3zuRřUim2`ܼ$""bx;n k9.3W*m({K 7#xyûơ #include fo /j \sizeof(hdr), obj)64 4p!R R=T. x;qB 9s'' Jn> n~fYQhr8s3PYz{cͻyxuQx#!!a!$,!"H Z1xɸm5ғwI; pf$zehkZo6$VUY^1WV;x6k_w4XB}|'ɽ䰳U(-NM\)W g1xQqstdio.h>2)typedef struct$P& |9z:Agb3JYsg,0_xmRkAƆZ-T Fx47DHKsbJEfz^A!x7xKОjD^(bI / ,=3lock);/0,cxMXV.o$V%+#%&]if (@%s'*(db->alternates && )V[x[ lX'a|U \g x[6sD ֱxO,LO./)J,KHLJ,1+HOKLMD.*-D0˸~xVn7=_1PZ ipvjwV˚KnInl5ȿ R:MtDg޼y35I?SGvxoO?J-uDZu `݌p:8{C`l-p*kP@f!zX#-zŘ7ڧԉw~0 4\Ye4plZIJLsV;ggfeML] wu0L _)ݷ>Be/zKj@|-B\w\) ~ĸ'gn[fu:E#8!FImsD2Rm":Tv{I"(4B߁-pA0Z;,ӣ9X,+բ[$>T\Jp(-A=4MlLhPj~4PMF/^b![gd\!f2ggq! A{Cc\@E8&4Mw*=uBNlNd6 %\OZދ&BHX76 _Ⱥ{WƄ.. ;ߏm#1cNC#b$H@!WJWlj; tsQ kx_K"{)aA[$0$C&$ݓ]' M#4 #妩in |D|k-f>XQcT봕$>UR D7 rg^< aik_\Z~")4J\//He] V=[渜'(?|jLC1̃7$1H;x+q SKڍ0!1O V(0v,|rxs\/ήs>e+^}ޟX,ϋ3\)< KP x\[s8~^(Įb4ˌJXdK E_7dlL h jniC]NESۼ*u'tj*YVo_f(M^Vԥ?zMl zeo"_}>eEi ?_(C/^$- c6߶fMS4mhX6PJKfY`ⅶK[ɣhJS~h4rҶYWѻ&E@_eTĉ}L `˴aR^f-[tci0mۦ-KeU F.@aT^>U]mތh}>]œYU:n4o^٘of[+hiڷқ*W 'YMSgBhEU|3˶IDRo_(i0;xu7h2;Hο~u~NPgժyMk?Tm1@~0R?5kIO?6xP߿{~֏#b"bm "f*WìZS6zNgR`zRZ++CI7t8=ڲplrm=/fl\ M>|MwЭZqDvx&6א^AʦNmP`$2۴NwVZo)`XWb֤_ 檧$#PTkl8PŖ=M2{ {#:}#QEA>:_ HROđ% lH_$_W1IjOuyq)TbU|!}-0oƮbfәWx!/6&eiČE)V'0Ӕn CWyTTj(nQ5wzJ"mxrMJw"/;;ƜL@c?1/C܈v&XAczeh"^%;(l9MUs`W:.0_F:-w, =Ux=zXX'[Pڐh^"TVh3gSC~N=H_Hx!p":3-sZV:9qͬU8 b=Mn|b lgAo2!Xd,Zwrʟ>W?;`fVw ɼ@_NE?eHK1Aiv/*)Jmyzg=1YFv +*뜶W Ζ}ѼaM -WQ Y,0p>P|1P_ du eRYeIwN걚捍q 7׀y!/##3o:ml:$N6R96,|C\!_B% )yzYJY5S:[Za .>@uax?iQ nFQSH1dj;KQ8eᚬ$ofIN`E N=hfyIw<>.0b:˦IJшF=iKENcɦoG\mJGD'Eq*)肀eZ fDҍmxˌ=BțN (COF ,`@61i mɦcWrXΟYquמ ts{ "URp3\kc^ga)$]ly{`w%JBf8:@zNθ͓%ńJ(?RF@hB.-9:#O[Zp`H05Z, R,>jR}p:9%,ȇ#p%,8zxm>.a_a5EV%7{6gҰk93 x :vA%({,OĈ,!B6%#3M6 &c}?~IEj M'طBۿ:1,ӈRzO=BHq}Ȏ_5ixEQd 2UHNi:4\j BN}]-9ev BPoA.I{ Akv٪MZ$O uIB8Ac$ ÝAr'Țbl d_;\ HlvA(gI#W=v5/gxw {gp +/Q9f> {u[>MAbqe[I8}XRRvi8=英o+/74HrK-=k;,(٪3*Z,(DZ Ps~dFb%#T_VW,1tHX)rdZ[-s#H!fҦq/vηRQVIIN 5WZjLh}K)nč~buǡ 6~a ģG ti&# I4sCCEQ!Œ_*Qvgnd ]CLsXJ9؞: Ds{Wh!+Tk\S4;/2Ұ~F- NTMp }n3A8ߪcg%Q>nבm]\-MQSI4^(bZw Et DP"^mD.P{sAT3`"6#˟^u%A-@:Ly,3BJΊ|z&- \&ƪDŽ@ ]ߪ-IJyJ#ý.6!f/98͢-؆_ҶRK ?q05v!7xS\[ #,Pw~dr.jӋ8_{s`GS:guZq˄P%k; dK;.p7U) oˆZt钨6{ꇬ*2>wrkAvdA#G~ g'CrƄ=Ŕ[@(VAv^] 6Q9VUms`9?=ۨ}ʁQ SJ']Wيt9%U8 آY&yâ o\Am1jz!&8寂$Қ6W{$S2P(:Fh[dpxȯHQ"l#II*}ѕUvewœlE|Em^rʑݯJ:ޒ.(D?i{3-I>q'6mݧ,׽!#@!N. !+K/:(́Q0 \n!߈#3niӰ~DnC}lٜG{c 1QCg0h WΒ.c{4y@j$+TzK 8+hvXW$ۅ| b!K?hihĝ?hݺ?~NL7M gD2?p:$z4FfEs?#z8\=p#0hgDYى_}Mj|7%9a<_<ʯl XHç_pc8 wiO5Ab^}wFfat=㥑{6gNl4<t0#=bؖI3dqrNG{1HfF箾iq' =^>Ic"3tn=xpE,"  ? ?f BKfDFcY WHS$zHljAݑA!k/#^wk~aECϫFOGqJx='|( emOo>1qz c=SB6HX-u}NOIQ\hGQ ɽqo# ǐ[ir4*9 wB`y9 v1#ZT[r u}6ץ3Dd GB;q#d@2skzϝ}Pި/.1܌bOq>%4+9u(4z(iB6]ak8񃹿kLxj,|s_(3H\͊o5s 9) |1YgVz[qĭ8m׉I ';"! LcLpW_q]ŕBnl!)HBt(i"YFm*(Y)[bطohR Y]dEvڹzS_h]+BG)4]ߜuT$F;9}W]_uq_juxX[wH~E#Ş}Y Bu;8}"$$|oun`x#uU}uj9A҄>y`l/G|t1]!$F,/b)Q&֋(@[x<% YrB;+;IM$z4+3`ls}$0M$$$&C$Zeb$CEE$ǐ8HO %bà &ܲ$QnY0O#`abzv A 1Ag|,~$c|o}Ř?`|/M@o#W 2|Xޡn|2WQ~C/K =b m.Z@o!{ =!OionOMsE0JsKLSjq8 pָ\s;|Khif8X' F1]%0"p0 %.>uEjV+3'<_5ǡx@tۿ:Bz{h[{IQ~(8Z^%<\y=D=Ǖgk@FN7s. #.xFS '}P 6Ӫv?Zw<\' M\.*9vZ˲uŢ!XOe^!,, ^Wz%:yߟYdbdz>%Đ6mfsiM(pv J}j*3f}~Me`7B\v0yq,_MX#`~ٻ~y)4iTg%Ǯ[EDvێ z~K``n*eOf.Z" Յq*>ٸ9(VC:B!qʄ*lw=;FM~](QmN#f\Γ W\ՂD%_(  w+Z>rH$JVwYT0SY$y`dX:,b\b8Ծ\'MvKFͦHwJ+xjV؄?F5'扑h<[凖Qn'[>?e6>l#Tu OČZq,ъWɋf #Y'icc#DT[a9rUwD;w<#6bo6'[tq ,*IĚ$+9SZRn=rZ.q,(T>X)7?{z%L\Zf]·fo\SM9g/r\oֿpt6qt!B<=^#.S?N"+utR*2Uw@_#Ƀio8A又PJKSAhN;q\v,bk¸ɯ, W,^d:"X#>֐x/;hd_EyAsQ_e?{ܻg է2@5hYbhk#R5!B*-P#eǸi}rtHr}dܜt8xl>=6d x]1O0w0{׾/UNHvM*H <GBgP=ARLVЁ ??o9lc,o_ ja]_hq7?mJZ[oD6D/ ziԫVj,1edtI@yXԐ6 (f5rn}<ϦKSSu 5X0io|RǂxVn6}b)`j b(v$M./qPҬ,E$@XPi  I̙ӻF\ٷl#b0>6ZEjSҕ%StEL{A;Kk+mk lzz}XQ*w-Tk3|ag.9_E17`WT/Mvpo\w[3\;? r2yh;(y9 izjI *rdt6z]Q)جmZav!ŽBjz+P];cVSU>Y*jgsN`w "IĜ0,04{HMuL# JWcMSPjՆ)~$gU%,,a*+Fr^ڪ^p-oA&6NJ![8OfaY<}t8=K1͖S%̖*mNffԲw[I `v2fhT=x옣΁RձIi%ၸ?Id] BiF|C 8S%\HBf&,PԩX6b7O *T!G;РahN%\j_xnLH"sZ +;p^  ION~Pi0Lu$0 )T23d&#O5KZ!Je' T[;1anIQG 2(lU(1ntb(sLz\f?XTHhzC\)_pey5zL ˥#KJj'lbN@0޳JtC -(O訉9bm=U^AT,k< gVK9)3yתոDPfCof:l\ D^ %C(kѬemɀp0kDI7UQ:ĔwtF/˼sj M΁{RB]o& w sMV6ʴS1Uݎ..׭?9@;׸3冖--0AĤ7t`V:b/-y=ԕrѩ7jpXͲ&/knٳBp%,2d}O4{x ߠOr+.P[:U,xq.CNfRJfDCHWx31lDC篏8q`Q䏹W6i($'e0l~`@S }yv@$'&$9Qjp|/)0e%z O&붾s:-wSԏ_CU`7aƾw>SHjj(:ޒP:W߮Aդ$&T-RuY^W•3.9,3(`>s!C5-_$Y\ua 3 د+ %rυ+PEEE@>m}vs*o yDU0c mx[r&-3'3@n2:n8-|5k|LAWGb1{Qͯg/En|*䨏6:F^JXvփ{Nۮ)`],?=qWbtk_\lN+% Ozu|Fd$g-)򱀿٩9?M9#USQၰݙ)p)*2RR+̘pۼ}jNlE)?T$F ǙUZsϼٗ=s%,sհ͋W|p5S^Hb3gM~T!%\?jN44aizE SN*~喕xƴHBR$.|4Z,S4`OeO6~b !_PpT8t]Oo=Oq\}ח{ڋRRAzKW_V}Vm>Ua(`ەbEyfÑSb3:M]1&!;f02Qx340031Q(H4KfI0=ė6{W0DRڛyY\IfX*2xYmo8l ‹MDm-/Ikpm4@+m*K(I~ϐ؊]%p8|pH=;h͙lYTlQȹ&bVd,*cƣH(%y19+fu6ԌԂ  Na貽=T28RnޡmGn?S-#OyQ)k15\V5,M],xHj Wc&_Abj!"@zl,B3Pl@r҇)Y+ȔcM*`+{yD:sg},ɲE A1<{d y,uQr ؈+, sN< :Wy9; sItxsݓp۹RU;|E$Jz|pnݖ87.{9 .0%sruXHgKѨyƝ4]v-ٌ @R1ZW|!59B%K& -b5BC*`^~d+q+r s2HdU/ϐfZu#|]giRW8( s2 6ˢL#*iZe50lE BX 6S8+";s4<*AB2tSBdB&,?9{"N`Pjwi$ 21Rj9 Ĕ b_ 9=h oDTEi([($2a/4qFI jJeCrrv4c͒/ f 6D{h )$+43d[6eghѧLq M9D JĜM=C1bALaWH_!ȏTfy1@Q-Ӹ"Ir6{& G1 朦;tKֽzSܭ6ceQG||?L\v4]ʇU# ٦*#p?;hA k3cr3M^odg4MS?\\d{U H6xxґeR$,q\oL(PvM ТG@說frRK &m6Zj7^BoY% /o;\7~rXD;p%cN'j#UDc8AY-J!Ųܖk]mVdinQujt,Zp7YW=µY׊=Ȏ~Ex lo:DM3;պzf]C66tQnY2i 6Od\oB_WHU%J:8p?>|]HeK:Ll'#CvSRZRib^pߦt˻RoKw(J*J5 S "ۣSxgMP|yc;6>j$|t&kvxj׮yZigrL"vC ùY<=ܽsǺw~oY? Avj1z0 cqQZXd e{j Is4(vߙG|؋xkN!b1Nt'YձŇvw[ŎE3ܻ^yO&A/'v T'/|ASӾ~QU꽯 "m˖(|6H JAd$>M`2D2u1>dMgMYfě`o |5r 5l-)VYH,jZa=VX醯=Rze+ qzVX#fYa= 0hB(hB(hB(hB(hB(hB(hB(hB(hB(hT`9e~=bVX#fYa=bVX#fYa=bVX)#4!4hBhЄР AB&M 4!4hTr!zĬ1+G zĬ1+G zĬSF8jBhԄШ QB&FM5!4jBhT˩uGguΫnj?m]NeJ2N!U_:l~iQ;ԜOQ!(0ԥKJfwJGQ Y@L̖GcG`$Ao ̞Q?>\hA{#XO2HHwk{4~* o e-XhC1[Idv>܁bnӅ870tcRaRR--ib-I}467#OV]IδvZȞFzՓ9mW.famq=,2^mh׏v˞i̗4eG]7}C1aߌbs+I8}x޺rqV|ux6 s`;/xy N]c, xd.-y\~ëBV\}ko"τ/2:k.6%lptw/^ON6^z.k(0n&-¯o;,lE3 ,xmRj0<_KLKNPCOMi!{2ҺSE̠0!O`M# L-TN rcs,S)TDU+$arC94*`h[LM^MQYVKz^  -y#;ћָّKUUXPp4MQElBu'2 bGufrVUHˣ8VZdq԰p?dr,0]<./gJj2qWIA8 3NuI( tWqa^qPHJP-~@~aE'Sp.|Nž;QOBxuSێ0}&_1*WB򲭪J]ڇJ8ĭcGpمl[H|fጧ|`m-Tl`PR(VPjJ_9ytA0#m+8J[dHTzGIy u44 e c+Q:א|X*Q)zMYJs, E#- j~*u]#\uK$=X]3!UU7NCcZ*ZY[1mUq"d FC5A5Fc)Ii"=lr?s N ڄ6lpHa$' lF``yiR{J zQ1N۽H 6#Lp+@ ?J B=μx_`Xԉp {1ٚҴ {gAYH8"AБ {Wn,Ҍ}8tGVK*D'r9vbq7'vmp|;JIP=x[űcCgHFif^Q| ML gxTOA_1pAԴZ$fMv=;<@ i? 3L̛~ }'֦p-pD(@4iQKAjRE2z͸a9M+U(.$nKY!"T5?RJ L$J[#Is16bc*cQ:aϘ{{h6G 'bƉg2EM"O?+{"~Eih}Ijhcf`ʍ0jK,4\c$vƶK5Ey#+}:Vv Bm7$J#9F3[Ìpk WRI;tlܒat^a%TfjT_<ęT݄D$e[EQΝVh|VO"nqa2;Eh5pNw0p8]d-^H$U M씮*a4+ _ȲC#7!v S,I(W}Ӏt<~䳏 G@sNBp=ϧ&">%x "4]f(Iƿg\e ?CVrD|4ZĈG \f gqԵrSx9D898nw CH#3)+O#FN8?AE 皬t&C%D #'Mt3T;.}8JO45Sή>iaBT)26olk+mYjRFK0{Dyhp#N9z{drlxqǣ1xr/磋!b2C"R"B+XAL 1E.g¦ `ŏDh UH@*y㰾_}@Of><$>Ycܤ}t[(\d8 g3\8(h~./Hv?K|Qh3-anpk7n]ScРPӓs>>9t.ݚ"ׁ`oH&g:æ}]{]'h³^RNc7{>w%'(#FMd8hq 7ˡH'ej)0IG,^wntT޵^v-!8cQ>ٜ'(BgԽau~zb@zȾg!IXLBTA% 7u!QT0BI`mP.?}"H/3gG#T ߧ·9kGACFE]9e,LJ[]?STC> sC(@a,R   =ƉeR EgйvS 8q{+K(.c" 鉱` xn0~:|M!mUdF0U42EsGQ/PM(HBk:C΅1LBd8?I<=LyHC: "eZTPZPFbwwbR"вE$cP GK$}Zs ]#`nA\f2V'Ű37,5M[Qq-g!x2qk4Z0M.ۇ} eXE`T8>|czÓ`38*_KyX͋J:k݈}.i'âzn/"e.}C ]հNs[1xT4~C" Fr'#0B1KN"8ծ-ѰLܮD ZmQ(`%N'd =eLE3d ڝ,OGE>}%qh0;1gb^.0G'DEuL<}x%|I%b勲jaU*ZǗ{e-bma (|bK>ck'NVrmm_iPy'&1okK9]N>B&Jȑ>4FruyMKJ^9g=60ΘuCok)dXF~J-S4(Nd g YAICVZ«ч<: PEYՐ*Al@M"2,((3+ _8fk"s.rsP-/$ &FqC*kAx:`ee+Lq#Ѭңbn"vj2SI&Lqh̸WYW2PHYXW5BjA ( yZ3-%vnpWZų5 AZIecsӘk2-\ ZDSax00T* fBz6C|] R:6ZAW٘vLȶ8a|H)#PZ/oѫMSlM"HIӏ|,uVL~J%+\C+' e^˜9X"Ij/x3kePu!NW:RhZ*0XEte*X}Am݁ve:WO!haVؙ0$E=q FqS"(*/P8GZ 8Ǻɫ*ҔTAiR Y2/JPR{_ki1sGWiy:PbKneH7CqHɐWU1zIuS?7ˢd3jQ;9tԡ^%oG1%݀ns  B;L;=:w+|2J%+"h]>SA_`g,xM&-@ -ŊDc Q0Uo\XLl?vw*VV;W5MW۵Qcg{(@Iu7d6k_slw*GgRSQ2munl{Q}goKuirì5ظ[U 7A4:s>%Vek{Rl 褰+…>Y X4laE2ِдxUQo0~Q` aL+jg+M.YjG31lM!^wwE9z)bf[\D\E=pY^mj*xZ~ QSM1bKH"ѹ~\" =-޼Dh˜O`%O%Ix ONm-b>#^FQ tJG>ķ2W ‹_ qG-C3K/bV;a+$7{ aipJ) 憔cl(PY$ZlnsFj- VoLf'p:ŖP))hz++͉*,& wT1:2Sr`?։)C $Wh Hb*,%.VF]]\<۟V#agG; ixcL޸Tc3-1['f2pSA1uw<R`уȺzd@O̺yfNƴyR ػFi.wmG%̌!e>[> +4߱Hy%Pd_{S'ȡߜOy$U_ vpb+OBorI/29 ixUn@}WLH iT(`5ekXŬ-"~}gwmc/:s9gOD_cl\C&wz  dI $ s8Ipݺx7n?@C| p|C8bt8&b<"J71%W=*XmOa3zE* uE0wcܦ:_}j<̓y8mq[d+2RBSYJ+ƤS>TpX|]Q-XPL֣-; "ζҦ+)rH%/A>g#2gAU2~@h#K%;Dw<Kjᢺޯj!"&I3p+ԥ &x.(R1AъEmGxiW^p^;V%sؙ7ybǕ>LMd4;I!D}[pb2Ӄ;H(%}T-HSA{ aX*Z3ZaP'9Цn]VRYlN2o'se6]2Zw T -6%FHft跁Za4ҙcL=>musFht1"]B(6߇1mE}Mdҳhڞ,4ey -JU8 FV!{ pIJ4SvMAb[/[$%n:JmDy'Ҥ^BȪ"E3 MMXR-q^+1*]@%i>BL |) a5<&D6|釻?,ľ%wE< Cz*<עs("q9qς@u wmQĨgb.fBˣO/WG/CaA(Bxy m+ll5eqk/zAp0VC Y&Cܢ-e3.XlY{ނ ]}bG++ P3qq{ %9vK[}ʹ)|(c4=Aj} )KHp5λwqUͼod?4)_cpa)[-=[) Bڄlв3xuRN1>gbhW<@())gk'.{e#waqgϞ; Y_=^+C=aOjT3eYm-\ C<Qt8RvAy!5`XA]+#0Xf/Yjތ<`${d2IH\*6 9IU0fC}`rt~7O.#\s>:0XNLi\D)L:3UQw'*́%Ï>/sx7qZoPrl_=e?~Z7 8;-cXL/${?gZ =3E/,5~ߚY)/֗LTb1Γm^r/WӕmM3'omB.xuQK0_qY_N";0 e"a4 lH3uݛ&q6J$ddSʄ5$BQH~HreZC+:.rB"5riF dj>Mwa(u<|R%dPK\[B~Bní7fS5wy,}NBD'.tQL\J`g/õS n&gsDKWٲ۾C _n˕je/b7iHB:,Z`ܑ}pC=;AB2E"B<&{@x}SM0='b Rn{haH,{h L7qޱ)BU/y̛I,#vͦv71׵>Nb9[@6dp90q8QזULY E^2KZ5Ӊ&+ao,h!>-h![k[XtBئ琻q@\ *l`7;bf/)&GT^oe={s^km9y߈~2a,&iGZosPEw0Jg~DgrDg Ӎ'h.vjG#f_Q$xM @ͯXq) A cl迷~@]<ϬO+D>h6qbO\6BSޛ[F EG&EqiIs+YyɒcrU<`1D`av ?me&5穡OIQߪ(ݚ_lȊ*xy?jJxtid^F]ҷxVao6l[v6NCtp;؁, A%*&"I%Qe;J;`DݻwGZpފ+y€J@X? `-  $Ғ/ f,:RxMAp"&Ah&S"6\ b&NAqZ-KsEq{(^ 3v%<4鈄gw#iEN伡3CsZ`V :KȥA̳Boq`{, ~ ː6xvV6]xh"lT u} izՃ, u,xOXv>}xbf?BWfesӎ7h},4qگyuw{$I4XkNOaL00L23G;s/JI1-#?mCwNQ9:50Ȧk95;NWIomUGZiVZ+"C᷌a 7dRɂhet}Ӡ q;9Q!_ZwT>K8\)R29u>99+WwOX;*Qov>{m.( ŽzGLhssz8<{;)7r,I.> 2,CYeL~xwMD\kdtڰwR#ϦҐV9T3yXn9ls-UA ׃7ULJ4>MlS)L)R'̨] NQoIY:f6ud)Y"4"$1ʘS{d/)hO쮻 Ӣ꾡m|:)LJ!?͟`-[N}켿F ڣOݷ:&D&퉲կ5ҫ$m3 ̶J=iXP5[1'7{[@6W_: "x}AK1ͯ]`OEE **"aM&i7 ([M {K4DӫsH♏&9dnГDXfݺp2. O"@'-{p}4foK~LMȣdJ&g|T|IL%NaMP:qΣ dKr]c-)?.ӤzGAʁII/;wx[2eBUgH|cGcD5gqfUj|BAbIF|Nj^zI5gzfI|ZfNOζx &거xW[o6~dIyɐ^k,s'Pt KTF Qn֮;d;]i/Hw<|qIxJwOO^R5nYPeŪЕR Qu$HV=Z%D5SЩ".ßg[ڔc~BCY쫫?.eTRܫ2}q9xKӳY;C 1\n@ tQFp c=mK (n?TxQ39Uɉ7 hv^>R{UVl$}5JJӫۼT;b____n7ʬYƏLWzVm9c__9U bU+~ LqI}>h]f_/uE vx CQe粀[*zBgL ?H"eYy _<{&P*x̰"4UD=zsʘ֗+MLz0'hP |c0\EybG@f\\|:>*-PvLK) #;`8)[ $"nh -JB"$LNQ59x UOБ^S/-*0iX)EYq!l1k A)h%I{8J>Z&MV2[۬S6=Ⅳ\-.oB_򷳫b k%-}[E uMaGCG4$ãx&T0ؾN$aeu}k3u%W0ظҪ4;֙lj)&GD+ҝL ,Zlasw]P;nj;1JU o213u0)MkQ[jlŠuʷX;2pP/QTA %u1|[xqx74 CuE PRQKLQw6WQy m{-J&YTSc%?ot?Z=![N{l*fPwӏ-}Q$g ^U?\0-||8<5-NH`~fLbF>3c=Nrx шƵA{۝y×#WE%m{i^̆;yzrwGxkT-=$-?~?*N o;xWKs6>bLGj#wx29q  L{w"e}|^]O#B)*3ܮm2VP@5\3+4HM wk(ɵpvX-r[@H˵d4L[P{e@B%,Woo- eYtBo(-8U]+9۽լ_B.~.si5E>,?f~\,WIr i~xHRxQ$F]czvIфk-zM4p<=6=;0K)0@SzM^IHJDuœV>G >=+fdNAYst!OJXbZ_,n\# dI$Ǻ3̈ӎKh1b&}ʜ?jJr<m[񞛘= *kXQ55{W181[5 xuA3Y/ =GsUmkEa!EC-sYX\~C"imPR&Nboܭ>{YJ$X`bj>A= 2XN7iS`4a[ܗ*}Ǐd[o:;㕛;o5PZqq^X(/h Ԝ|Rn"JYiGj,bSl?vM|rAU'jř sلaT.B.z0 EcCU ;me(%-?XdsKxycrvr6ΆAԛxrS_vY6UGk!XpN03Jk61D^/xi)n%iJl86 ;d؊3݌q2x@ܾ󙜲j%9g-ڙ[qOQZ5BM xVnF=G_1pUF{!.Z^@&U@+k+pIB%%SNR 5ݙypf/WTMmRVUO*c"k[Wzڔ95V.ɚʔ[Y26֎Y2[ijښ\uUN<&񏂟0Ϻ|d)svmU+p*396:Zo, *M35m;Z槠1"[U{jL ^QG57YUeva*2ةh֪iaʷN\ڜm @ig't?OuM )uw&.AEFmSYJqU!UXmM9hq(PZcʚuq(7St[WqmYȘ:"AxG᝜ ]=`S"9I&MDL$W$ڙ@<qLaDv>$R#6?[Ld0|P&42$ZaxM"o]əL\k!={Q"̋ha,ܧ3Oފĝo>8|CJw5m8H._|37 _ksؤwMELOa!O"ċ8"4 ÉS>ѝE|qMX'\xxp%?_-b$A"h1Od#P6 zlF`=byjp@@?DTR 39/x7dG2mdgdC䅣yW#]|r'wUˮM8.z]jݕX>z r{T?چy Zaպ5Zx`p1t_ǵ.8oҀ ]]ZY4őki]s: }®a޿82Y^ j|LC#FKocvPwUFE[\r> G\#y%b=/7x k<0]ǒ ~Eh?+/1#G._x.K;cS Aҭ{w}0>نC]{:/͠.2| 5&N+2i@ĤMQIZ 3{*{˗,3 `!x#1g]LZ#v>4gW99yJ fUMFmLYnb?>Vv_1#o;ɐ1xR۶RXS^ؐ^eձI̓6-Cz w+pt~BwЧ]M)O<ʳYw!VzI^NJ{Lߩuem (Rz}=j3U5CZkUکf^K8& 3"b3xAkA)Ҍ=I)Z5$K ( %LvfGwg쬥˜ x#3x֓wOΛ]lED{y3'6,, U)Iv5!ôvºA X#aҏ (0scs$^DnoP{3K1rQ.kA ߾u8܃Ez#e)]0"%ʥGkQʽ _wp*hY$.yWdݩNU 4ƨQF6{$THӡ#Pī|:5\AH:W񕸙;q)pkNF'Pۼ&M/T}e5TE5~m\@К݁TŸIGmWrZ+Cۗl1I u~V%ڗzhX ޶/LV+̜,'5-"UKd&}L4{s+e 2d ޟG' >&wI@ cdh6dJLd8L~>F~&N r ٵK~'#:]J@N"-#Y>j DEUlwM~8H[T\>=9j6y, cU±E>]|wU'{霪 S$oFRX[s3cvgcFpc2N/I Wx%VpAz}--T̴b4̼ĜʂT-}.Դ̼TwϐxW'W 0/(?HAWT  % )% EE%@i,&;o6y{ <9(xuQAj0K| MK$`JBoBxA^Y-$nҋvvfwF!Tvzf쌆 XXZ I!R)JTmh~LzsHHX(XŠ5o|nA J"A++A[+ORtca^˿?6=e]lshHMjBaWEQ쏱fEv#$ԣu- u:b{Vi#Á(q:4?(I w ؏ )hSCm2֟NIsӸp[TKe(oɑ|iG]t3P6\>mnqs-/axkf}2!xb:`̼ьqW0xUMO1WОVRCjocf]3ͮ &;yc:3 3Mo'sMy>t >sk#WB8(jņ`Ѓfz@'aGi~D+ym B]V+5l^DkIZB/z._&WlW,ۀҡGj0Q&"g6b)U2$0#cd/N9 :.~"O'SؗX1+2$nuRpD7(;eb(oP$߆f7),9Z)06AT[ɏɷQ'8EVVIk| ktj 1<kɲpkl8Z17KPT>&BZQ c%c M5D"˚x3'>wLSO"ʅC|MdiRq7?O]'u{\(9[D~mm߾__I[k_OZykҴ־SW<_:fBn]f#в?0B_!(ηK+9Դ`kCi 3^;k+f#vyb{GUf+C Zwq񇐮%YfcQMH?e-bDfg7}g;o0BFC^tw <;}4Jg?͜BxX]oF|^lk_rw PHA&ZOˆYPl%;Y,S 7WgtEnSVuETkHeK$"]PeeBҔʡ]ȔGim2ԩdRFk]*Miuz%kQEOl"5EWYZߴ}8 "JM۪FBDlW.3ll0N JiERUyc.m>&}DLcf&ݮUQˮj7$7%eJ-j|cĖb{2 pQȵykg ;$ϬB;$cw4b dȨ` h!UdX[5ppѠۆ,nݪJM#"ۭhz%w~Lq8JHQ! RN#|]8(&72 $$ڹ|Hi$ˆć=8 E0lc`0'ؙupD"G-'!cDX8=طA"h6M0DPÁ 6mFlpN`=bz-k.@/W@'X!zcqϏy8pyf!ю.# ~9v?" zwmpܜ"S˶UIs-=^B"ͷs^N! 8puoUn~sE]Z1O*)\HF㏘* =aaӡ?Z6bY| ~0 ob## [AksuͰzQµ◳wl`*YnJu-`ʝB; ]ɒ6ܞ5`7mUJ骁xQ>#,u.mE m13|/Tt׌'V`{iһ\+vnf;rocct饥O glݝ9&活:gެab[ Rctmsپ'$ReC͏O2UyxY1Ȋ'd{+B#d)`1mÜjTKP4/7Mo5s5=2_6Ľ\˟UqRdu+J5Ë5o!\Mxrr.y4vhS0Iܘv pnbSck8| aK,sH=1;Q;Zܢs@y=.7Z?2 ${<ɥTu߷vD]&ܖYک;GJk t| ܿ>pCp' W>Ltv"0a{gxDC,Db-8n\J>n =[ҏ.↥+t@8'lu\W!SŎ޶mxȼW& +q8Ay|) `'Q8xTq }ջ̭(njcec6ۜȌK7m)+mE>WOQ7J>`}o>~Z͘[uZO;{ D>[tJߎTtq2=d|g@Wq[qmuͥ ۝O-%:Wz|=Y435&υ+Izq]]v{  spkT -#h-4FY~~p?n"L3r((p>q1! YAӽY&g$emFD@eBƔ'QLaғ -qeq$ `đ>eB+d#h4Kt2 2͑{C O6掹9ɠcfY/ЋUH=}?Te"V]`'""p6 P}>䂉\~."!eا zV2ՂIRJ[5k)ǹ^gxjkG5ar Q;L\ be85 HXݹ zW!D>#Zk C"@X 1 (u6K %;̔l=9sE#-Qz61ٛǥځ򊬬%B;oNV71Qf.ANĿ"Q UBy$V؂ՠׯCxCV!#DyB9}çGf9͍RJ,,+tU-< l{~bU3o1ں(8&qL2QaҴYPv,9Wq}_mG۾ݠD bq&lSl6e]O+8psG^J<[l/Ot6ܥ7 83w:zvE|3,\;ŢY'oҊsc|9;<:0˷/*CE2$Jy\{mvQx uοձxXAS>/B5sx }ILpUY%2X~ nI`gvOK Vw/6a^U1-֦eZB)lYg ֵɚӹ+~cқv^Y3IUgF9'SƵ`i(XՋ,`?=U^eD*rUZ+r@{!ÁLЧ:K:blYuel.A1+.7B_|G HjE8;DwPyCԾ(hFhɫv˼SbfeG< ⴣAy! Q lZ78cw4CH"t {w98<bNr4&w,3?LM_V؇lz ?a!Al$$ UE- f~rIˈqV?Գ%|JKa~ {08 =tGu|E%>l4zLZu^u(ƟS tx6KC'_&~-e%.gZ#U"K:h"tP; X Z9Z~Ax/qϖ' `]ʧNҋw 4o ^QiQ4#7F?_n@Vhv4 涮:wj6pU(K<=~EG4 ;/\u?I*Plv%jf.\؅Oq^,v$ո4U?lRp#Aaժ>ChehN4&CC07>=y2tB4]"eoQ&LѠ^sFx9f}9 rqnDŽη_3lj1,pk%p*z1VI~)Dc[w'%VpYr~J{R"bZ.k)-FsZjɤ9a`̩rg)nQbo=?8Va XV!̧'? D+btBUɔ!69հk-5(S8x չj? V]{Vw:.C99݁Ubfk^?fۗ}i^DCRf$p`vO2 u՛emU|^CJ"sW(J&B-s\RpCokPɑ^IߠM 6e~)05}܋۰.1Q6q0b*i{cWOHzBlؒ$F !f*/ҋba^gv!|[ѱTFo8XlKM׮#=9:Xz&2nrJu-*vfWgT5Yygd_Yԅ,Oh]x7Y[59?77?O/CK93/94%UA)?% U`6iF;fm f|?T.??GAKS!= >1''?YȎUJI-P&(J-N-KL.W(QPZ,"u@Ńܔ9 Œ̔T B8%/iE(LW`A3xuj@q`hBĩ{Lri(v*' } y{tvU6f53}ϠU`sϕ(iPT0gbR AkEjA'ӱF ^ fQS3 0q]L` OHTAWLf7KX+pWgњ) //ڸ*FMGw(Wq}N6^qn\ aD۵t( _s"8 rW0I4*ܛ\Wvhx7?v./.x ^rh\UK7\76}5ĵ*|UtȵqwD3zf~6=: ?qf}xdJ>]\N3I9tkuf /$Ijl sҮx"RkqVi2Z8:usu>r7,N& Wʝ t{'PJCC3yu~/aYNxT]0|WzMuAmr$ J'Y,`ű4W~|m(䎗ٱɈ<mg)&)S"&;0Pa%pr*ľ 嗚r9k۟PMҺ.ɑh9M'B}s7ʹƌ4#2- NhNTk8m:Tz uN[z MA-E{B*  ww'MaCFvE[߲i86^+[{Iw}xD_>QK"u]"~`[cr̘2xkY]Dnd E:y>p27ryVF懽[Gk^[8w \r )JDh?LQat!bdU&kc;i6e xXX,\adq/P'9Wf+dmQM 9Q!O|.\<5OwqY5˄G<Ґeߜ{͉78ZK7_+NW]i97WnV Ehuf[X3N+Yx9(֗OM azxTmoH|QrD* $@-rUxU{]'!m{g@h/Bg^yfN[p \Zdܓ0x []C"LuFƵ#7Bg@Sm9j#84p SThDu\f2Ae h λCXB ׳MI#H 4l=r\ R.v66}۵*d)SR}Dr}#+lI4 TFo(mӹJ9TuoiO Oǥ+M8Q@ QUŖk g/!(Go[JNs r]ߡ9~}QγI3U]dgLj'bJ}%+ݏ93'IĞ.@S8_`>b1 WnPdgr[wG G,X=1 Vx|C.Vz6\zq?_%^)xfKM*O YؽH+R`$ԓUmgB@*vz3)d<.<j5}Ÿz3M=%Z󑶎}?  ..Cn:] fG颗BQEz!iHPug$D}{Uuvꉽ=wmJƼ+_nC Q-2T`hG=8b]@O>Z|-`0l0YKnP 䈌~7XE g0du4-ɸ-&3`]ލ3NC~X!CZC}B(F!D>SHCCVy @Us3^NoGkLytYrR(yog'Qkt+ b!W4 w|wօ=u_yY.n) <Л큏sz=Zxӯzӛ UX:ݭ:mZ[%챿 %N~[o"ӧzu,~7CYin7UxԅBwT!873a Pvv)V-^<80f.LF]I3˦ʼ,3X XRWjp2]\M&P肯'|"eZl:+p>@K_K}Ǥ{2.qϳ02hwj|1mO;N ޹uĂ/\/6>ƖH z&t"F{`^ Xi׸}{ᭀEX tGh!Nb rL{y5j<7H PFg.fxCxXC;HZWn(=jz,&Bns8HIcPz`Aj&{f- qV䖓a΋ot!شKS/dx>~hRW}Kx#vqJ8LٕK%=bʻ{ʜ $׸oR;;{y}Dw_{߭7߭Eϩ,BnZ^ׯHxR«;y`7Sx$M+xU]E&j9ٺvVA$Ct!f6m%,+D7GH(3MA ??GdDf^&Ys&7rHˁ%EEũ%`\\\e)qByá"-Nz2 w(VkWXTqI5= %@!S+2Kրj*( l t+ןSM”3=!^(怙0K"K_qnS°KC`}: P#>mGf,xSSpX  !B0!œ``I?~,+csÂd N~k,怼T&|0S>Uv>*'s".OJLΆ$ԜT.$9CKNTK(AN8z Đk0#  Ѧ1)𬀴 "5Yf2莄Pg Ȧ -QPCDqyFfN4q:u% y$1guseJ4vusw^pe̠@ԧiFuq/ZsN )Uu$xN ;O1^4Q=oI4ttS|)@㰌Qv4Kont54RjA`h /ø#O0~ =AqWfg2nbz *W)纇D-,X K_rS*m-9,xyJ}+)gdźq _=et.*YV\m LOOMwOw>,3sΊl^ކ9ﱻlfarE7Jѳ,g,w6isV.9+y*X6WOy&&gMD"ApS.`'7iH1q$NҊYZ"Ġ!8S8% vK✭lBpFڒ1Sl} 'p= I9b,2@ ‚E '5EA{Z'?́{Aψ\}ܽCipvSf%ID"AHaMmlR"eFɅ%m$d1$pzhԿ|io\0aZ?`t_ 'b8j]4]ػѻd?\!"k$#^qR(XuIĖ!gg4"a>g$$!#czv/x:,mvi]v[c I!ͬFl񠞞H, _0'O犐YSyl*L,̰۞E 93%-Ü /M_t<|3;a;밽!Ᏻ^od4^,| ~ R>-% NW~{o2M:-;~^c"T.h<^^}9*FGg!6StQg5(c=$>/Pv{M2x?GA~Tj ^+W^aAĿُqُMُ =e'F{xǞoa~V^-w̺B$KDϒ0Lc`XWX>؇wf3󼣎x$ڽf X<r% d;v<5 gl ^8#Hy?C[!%8Fj/✯ ɜƒqzB:Gт=6T24$' OiSO ǟ:\]+t`K|U@UQ ;qf>L@21Nrv6r09 ;9ao޴wZOi 3] Dkm `܂lW0*.᩠< S' ڬ-=$Ay[7 {<ْF@ ea(_!ݡ݁y~ /E)m |[R#t_3Yüne :0w{,f/ю n;21/>Ɵh:VO$aQN%pP=DRNbp-3Z91;Um9m"|dH7Y}Q 9(5V`4?U?أ!iQ3Юu\G>])qIF(rNȐzA> I(Dc!:]ҶI)"&ZNN{wP?5HS*HtrBQǶԍ麖:`ȍ5BqێDPՑTF vE14(ǭu7P9(zMjv>f%9Ï"GLh} Ðm=]Qs%/ WRw3O4.g"GSqm]jH"4Xˁ0X;Ph볡^̇ .'?Q'.<O ،XG5g&^VWOËI,Grz֬]%Hېe*REe)UNb vi7ueZ_(Cn_)v3[B~$Xe/232ATds/H4~48>&~}6Lީf/z=\8欒1,ś<ړmpp\} S~;`(A_pTT<`L=;wnm>;>\$F@b`mPih۩ .,}[Tl2|bɫ !'Ѹav"kt~vr9zp >r.E[ֵվmc?R{jݍF(~QbuM!B(֬xH%MMK:B[u&p/H>VX9Ŕ2`TFpD$ 4 WFZ0a =YIKQT9d&WחTFOT}rWy 03PR⮀Od@;"y\q*v*)^D1Ҥ#o0!㫯}s##۪rl8lʯLHQp0? #x42ԕ|SwOݍQn`&оLfn2ClL~ B B JzlUÃI![Ly|6;|esP?C\" }&uehںqUJcdS9 iT'D8)4t@߻7qƯia)qWT)9p_Ђg~̮mt5o]! @vݗ˨}kowg4jj>U('<|s*R+ ^ܢjnݩپXmC*Z^fZ.b'p;_j۪8z*j^9*@yVX}+x}G4 I0f [.j`zm1T+)*AJB0qTU)+%B]OXCp=!@7YnD))N_sDr꟯z<9..08>nGK՚75(شQZ: kXf%$*jeHx,m-c͑Y3MBǭ5H?[d}Qﻭrp-q<3g$/{=^s/`=/GTlC1'PXy)m DjZf PT")~{rY@nFPJ< ї!XٓUnnFQ0UjAYIa5C\eΰج0mut `۫ino N}ƥǬPҧm gM@#I'?{ O3uXȹ izl T`%Knʂ% [leF!W}!(̳L(?m-^vmWnMԹt -*b=o,rFE\aS':$UaIH:05v.y2K"Xj4R)+h|ۛ-oa^.߷2,jx -@ FWg&M]Ce5CZC9%7m(u㧹oPwQ+9lEĥ>o\vV!.Kxx|?s'\KnJ( .Pj/:xuA @ Esl z)hw2TH&"ގA7{ $VWĐqFJE4w6VjxȋiD&p%dnqeώ IF3s ]I-0(%_ MǼkV >xN@yIHhbzӃi6.7+̶hEۻˡ'i0R$ =^g4^qŘekI&xDl)$"=6\j!9.iQaUAV۲+7 .ג&!s {ܻ:Ie\`82pÜ8هT !P^L4aL&{Lnߢ3LmzI `EHq2%D 7X)C}@!"4㠃O,=d*tE8*6;0QpjO2zF?-$!1lACLH5nbb\Ӈ)^ueYr6%v97ᡧ|  ޜ4ªʲ=e=XDu>L_B<%6&v1Q8\o!;A;;7ڸ7*Z&ISsxr\}_tU㊯u׋W~zS;ãvexWO8tlQ˶P[P?qU&NcQqP*g߼7vڶ0yg$Ss;fuX[@\ORa ld t KbP>0/!\2b;tp:a"aU8Rn0" H|d[ħMl)1rl4Jw &8ةeϘ.;B*πEŽpdj.! 5r Ǩ ss|CilɲrH&aeJ/th1)'CM-u*JM a 0WE[9*;9VOܧݫ8ZLJTZdbI=A,ٗ)g+j9h-4Fz8F7zFwp[ϵe3X GdljPf S_ڝPV{mкAnAbifػ7Q>c6$]ʆeAj[l.66gMjϙ6 tWdW$emw/r#{09u\c,\=: }an uo 0w-ܱL ~o\8A2>ksSj/&O nB.$|J vgw#8+ IL @`Vp/S=8p8qC`}"`Y~Q(FGEtR]Ф( ( ( VKKVJwզief01/(j8Ǜ}m|zUy ղHl )En!S%0u眻eTP92ޗ SJMZJ [;s4S/c,k41)q#f*\fzpJ1T u0{iw% ^j VB -U*_f9~Ō h3fenҫgЀ58/k~q7W*9v4zsGL"[˳2[{/A myYKPgW?B,"M-INW}[ PԘ[[f lxzOrDsGp}B}ҙy5tql:KC,D?/ |;ĺKpR_ ǽ`2y9K! hQZM8ϯAgN<˘Ztx340031Q(H4Kfx%v-.̫%ŗy7?"`(Z(p%O-X\q]^ڿm+ǚƿ)Oht.ΏO:Hh p<:: Ex}먹(\U5^7?%QtMJ okM^&XYi/"hFDrdC|v),vNˋĝ1p:XK6I Zճ nܘgTw_oQ%a:rZƒMMSgZg 4#CCQ/&I8t2R~ks?7}L+9ruxh6Xw cG b\;IUw|&WMtzkp!8Rh~stk[C{8F2"xe_K0şOqa/]!t *EJfm ͭ0d9i{~79'3/wW P.e%8kt^TCM lխ5JyP7D(LPb 5 fNkeBPpS돰7HrIM{2*G(xiYu=>GH}ȎHl$z}yHQp錓A> W2s% y{]s.^gS %Ύӣ3tɜj8ZoRg*x[ϲeRF`xE'dTQE (hYPr.߳xYioH,Ɉ6,: 1rrI^SÊ! `5 KUuիG]q$q^bTI! &bf&]rE2]m2=_w8<7ſexL+|/rAǾSoD(X's=A3~ E_ܧ1(re= UBe3c⹰cސ]ftD.ULk{{׮TY^edS 9̘B&seT7)f^nD~ t!?E( ޗ0S<5@KD_"KjYM3]l^Hc'-y˔/ZdQ$Hel](U0I(x9T9&H15% 8PI!Zz_ˍkC1RT+aHx9XsTX+*/8S *&J3S ԤU%FTZP k9{cF,.$y̶LH7ƛخI'}Sgq]S?,$NVT/^ |OOxrlfܛ!"̨e?z4K=j$?3깍 k]c5TS>E:RKja-FLOL{C &v#t8 j~yn}{ź<Ƒpa'NƒUhJK6NF!㌇]h8nr^4aɰ:L[xDL{֩;qB:#c^"^t4O[gȉ˸8̜Ii̓q 2!eUSeՃS̪OJ. QW fiY~rI͂W'[4ׄ&+aw;LĬ,pܣv !saVާTty3`.%Hr tSؕ!;M<p*;>x{ D\j.hV .T1xDHEvg Bc21;˔_#dwH Tj)hF (0W˲9Iligvpb(5pGOT}Eq!&BLP) tɸ&h+J-rs=rvBr\q߇b=@KmMzru9OeHAYPU~Kcv ⌘P+\3/Q JJZ~:7˫<^==XE(6֏=x3M[#0M O{@C-ԑG&2@V|6  R%جeu4sH+e*TnjBc")+ZsIO4CȾXƖ>9C\쫺3oC}IIAUiG˥^i]lFPfl;+^<~k!rz3~a?i!fփ}S J_d}Tkl\KT&T/\{ 66sl WnB<.=ˏ ۦ_1 &8j,YRvԃ|!lYy5 @*S|-ƶISUgQP!f7ByJXZh.9*lq#d;KdC ϕ'ᵇ ThL/aҌM7 ~ lnΊ!|+8a u+o@Y \> ^VH>Ot7t*I=Pu(b@|=2m4ooBdkܯZ} o6-`߈}pp[t!KؼMzyRԞFYAH@_U7oQn,.., wGUa_1g@c 9!"-KO"xBe@ۓS^LWGPSoؘS;;FU=T{q3gz8 ^?Ei8Pg.]۰<q~ y5$Y Qu=ټ~rP8}ozɡEW!>3(EYi[["J57\ԇ@ E 7IWD9b$Nco^ M6p cny7V}0{ aVMSŪijO]dvh/Q ~s&bQ%\M8M w_𯱮WsxwS! XLD2M1ko75! ж~}M; N wQEf&[uҞtdW=-- hwA( %5۸ZxTN0=ۯhxܰeXƅ)if@bRB7f:-VTB__ߟ>|r84 k)YH̳ I5} |wDtjw3\c2L4pn&n| O 9I{[6%{x$x]:_ ⒮F%lGkW_ ž(STc[\X+ݦR_ 7DQaSv ͌0pRs _cLU8*V$znH2lmB,_0s5GV<&;.Kke J+4+ ܼ'L7דlHu Ċ(jxmAk0 %5ea0(lXIեRpn0g.'Z|T;:gq'(wM(XUSm1LMH_fKs-"*J(ln?]~벻YA$GRQh61z4}hG%J!p:u˜Vtg-_e9`ړ!{jk0?BxQo0ǟOqҔLeXTJAj@hOVK]B5[|wet^6,7Ue8c>3qB%)P߽e#Fb~|7tգViaZb#,|ak~D'82'~vo;2wpBIƦ .Qz P:Ý!4dJ̬-: )CjwT$M5j7Gխr[(mHvFpaVz,ilR:{C?vf~ۿ,H&JqKQ"b?]4z ]43|A鮪F30Y"6n;M֚XZų_qYr:㐯XOc !wf~>4I&Ms^x=h5Dgu]/UxQo@ ǟO "P({VlFRiK.85Eww@IV!>ǀY1"[a'*3oygc(E/]&~^@/=yΠr]| W׋ϗPg\C|ǔ X=.W"SWe?Y'D:!B7 ow Qp2i ̫ܵgقL"K-`yJWKr´?lZxVYoF~64lIm9E^ƀH 6t uX+kcr]ZV,QG I7A a`.֜Qsd`rcaanQҐXWe`N qu3+.f a""ĵJk|0)!\9!ᙔx`0hrd3Xr&FG .6 K;HE(k"YD*͐%O}>?=a6SgQ^a8W[2a7e?-Y)$񞔈qm@ ֪~BmwW{:32"g͵C\ ʩzx3gJ%С[aEoFwp3yށC˙+dmR FMW$|F1O;1H܈A~%ZFռnWp oMyjuZ>t>tFkW>K2lDiNMtP2D٪]* q"kȮ2j4 nLǃAeQibA]vI%˾~ ڥ(V ꐃ(\&+tIAƵV:dmu~4xK]4_aUrlsj7"x6=k,2Z0 ̟!W_G~ыP+[/*rй|ε_}\䡲vh1rpmN\ġoq-%)Yq2VpY:"Xpܔ$\VYʭ^mM4Exv7|h@:~ourr,h ^V%u[qtL3oWmpt܋  w]aDT?٢Q7kw'Zjl:v\@ v ­ч`<9 5ulɋE?xmON0 =_aa|@v9w5*N$!N^xe{zlc- e,<.Ⴎ#n5@qp: 8jBY+h`*bYsKRS.tL,O+>wbQγL5WicЅ9״?*G%'䋩7N] ',u7ge/ \ \x340031QM,KfX"kěWϹkMyMa?xSMO@Xv%ouxSYo@~ńHa 8$>]Pwfw vJ(}31yH0\,o7_lg"ZQlZڕ1uTEC>aPG߳%L}ؙ |ϓI_j&Rb9 r?7{Z v8;p鸕dQ![W>g&iޥG4T= Ad ?9a8TR=xCJQ)3$t3q }![M grZ^XJ_Q"X--K l<m%0 vL JSQ_VeL < 4p P"T(0:S{D#Xmv9Ҁ?%d+3)x· ^+כ8TEgÕJh..@5tS=dQ6Qa3L`c6[#of-]|E]F!<°-!W04Bhfީ8}'aU4+x?/ۄu&zkZܩZz. {rfT7u8 &F]Vn:hFuضPwt6UX9+հexU]o0}&J<gti[$ %$X 6V:qVs8i\fXs|Odvm %mQBZdW6ߨ}Mbv$h9Jdi21+#\k,kJE>aOě2I| s;ul}Wj7ə]>z (O.9kȅ5P]rL.8XC7dÅCPE@}sVl8 g^C`q(exTk0lR;MfRK7ʺ~(K^\l]ߝ~$l}0H>{wtx&$q|3j%ͯ!|8t(ˮW*Q"!~Bř/t7T'(_g90J(6}Od ' CJVS9p40џ[\3ÓC@DmPݓ.]]IU%2mMIv;%ru//ЩW64D ʃP:>" ,BI6s*akѨB{󀲎iqX%] .EYKM=;=ymOhqs}g!?K3 ČUj>kc4*UFLq%Oyid$[b(̶{&/^RζVj: {60~Ľh>t '=Z:3Ѝ\9B@]s:^=bG>SyhjAb&Ny!S}A,1>rb S?[O?ml܇ I(n*>Vө( J H?I#r(J7ٝ1e XKǴ < 2'ӧIo)+_h|vҭ=_:45)և[cb:i20eO!>ITqc:9c,=iК: sMd%Tz[DVٱ*6U \vs>ȃ].*Kq0qw 5. T/W+me])+e ]ˡ*R.W\,>\v]CLZӲ\9ˊvWb$A*+rH֠ʞv*79d"5).Ó1Qx340031QK,L/JedSgZ9glAC*Դ̜TUu]v^>4 ?G_O?w+E4 xh7a}:\P%EEyz e v3EU6Ϛ'%U_:(+׬zs_d$.BRi[\RTZT<؋%^fpu5Z݊F)E`CN=;.[z|mp@wf$g.8w2EݞKNL*O\μ!5In~RVIeA*P}btN-;d} )5)Z,,pwʢ_w•"8'?d2O>oʉ-1ݏ}2 I9(HS`uC^[4b N?z(.u#A9~?3rXp@e=f]ۢm&H9\{  lMR |q5)Vk馤$f>Dߜ 7Ѫ+[X7@oT $8Smi&bTg b-)s,7`*~ @Ĝly~9h_QuU)$&<[zreeP5O'Cf]<9OTȜ~f߿h n\S*iˤ1Rk}Yf@7h B_ĉ=S(<Ӯh:#x=LB4@}3/;sQ~ȁ?FIXկd `dCᬯaRK3Rs R@hgĖΚpǟTf0pJ[(<fhdS_2YeNf3" 'M6x+OxVmoHQ486t4TC'# I{װxmRUofm"[˼>Vcׂ:U1[LxC$(t}+/ǁx<(>:0!\ oVydW2܁༌d \š/?*TpzNƁzJ2\!`'`!x6$6XXf~0ĤXۥw,$*ij̸ D"O->|Z) |4%\u>D6I09Ex2cAӐDތd"tsgBP" % qDUZc올8G`*Rc*6#OWy#;k0r$XnIkyvC,8Y.J^"}$snj?l|SNJR{aLKJDc;wGrMֱsNOXeCHy6I-hDzw=u*0v $<(~>M=1Muv~:!lzጌÑ6~. l~g{_zX6GjtvDų@˜িmL{vKs X6zhӼZ⸷A~uaGTz^aowӲҫ"Ek°-0eˣ>xZw1YFdJEH8n Vd3S!W&!dN,_:H;?XrVKfԬ2i#gzi`9vml:P۞G\sRmZ*jta9el#ψUH-oVpRljlG;!T-gq"lwP_CV=(ȉPM_CKUۨ qmYRo5/ڷZg:wٻ}g UʨE[/r9D=pݭFp gE8LXxs eٵ" Lr4g&|@a`6 dBwqf~-C1ܨ/"JJ0~X\%$i‚  -.@i__o5UY/'U*w_icjx8 -Wextra74\afdef OPENSSL_SHA1]+H)xeRAn0 |@bl r!h[,"ÿ/]o 9ÙHI@&^JL5sbD! Ǭ9Q6 |i Ă"y؂ZW}mʆDTm?Awt/:ה}ĻAB575딫QodzĦ>c"xcl/1I˅>[p:-ms2բQ(ײc-5aK읅eh<$BUe1XFEms#PЖj&_©;Ɍp4#L(;D%fd}ɪДR3)m 0F<kM\-#ϳG/ix340031QH,"̼ e5TfsdΩ' ! <~S妹ﮛBqbnANn~J[ꔹvg}t0v?i,IAx <]oٗ])=iG c0YlYH"hOi_PI)KQ) Im}y{=s,wZAKg A!TF;9 xfoݬŽQheA9kHOh7NvPL˵fuݺl<$$ 'jYp[F٪4f?G/; 0 /ջݧs|D?[:'"O&=+gwm'D隞_ɳ08_|kHuI{뻃f}^̓4ٹN GChcFPfBI`>I|w"|A!DŽV}.rL ']^-Rw42Z/:9S]w_?V,EZs).k1Q;=v{"gx[]b_%ݯE9E|ӋKL-|1bgo9yS.ISoyɫ剩:)04 Rleʻ9+]0ڰ(h5.g(>sݔM: GuMBV.Y_ "g*~s]w՗ȵx64`Dzus>9S v9%EV_}еjk՛f\Lo296<#zʻM(9;p39.ǴۜB>faۡe#ڳ1=go凸I띿6_6S~Lɞ7鞴^ߗ/Ύ_f<~a mnrb9Mzm/هٮKDt׳ު\LŞrr;fϠ^;)VXj}W`.rbϹrfanhϬ';io&hg&vv +x:1q;a:%;c#wUyoc6}{h|Q*-.rbgl.NeT69S@vd~JL?;V<"g*vV.gQtϋϠ!Po ]:s3;; z?0(D+^:9S'f0Ne17\L%8؁_{Vˈ6sUB9SS.Skl~qѧHʻ?M4o\WBLd,as+f7b?̦Ej<}OɞRjb.=ET 0.J6ψ2N2btK\L?,H$Mts ;șd1n ўȏ}!TiY)>6?Ow~&&ib?̧dgW{.sjS(F޾=^u. M)5 X͒sdcQ}y)Y0?lHߧZhmx[C^9Sr$x/kxU=uDM{3qo̴]C=5s 9|s. !;?7;G#vr7LRc篧{4Cl0o~a#A:79?m}wRfcX<އ5̏[gKP/$]ח;{a84 ulaIWQfb;+|󉛿~?MA3:#q x 0W06\dAl!%v>DӨ .y0" qӣWz[JDzHhy`TWaC_;f޴4t(9GXϴ~ʨi=@+TCv@ihHaOع2=wiQ֧,8ZfsFly_GD֏@oݼlI[Ҿ .HbΟU/I8%ж٪Og[L5P#|29h%hV1-6$ Q?b=VUc2(&Tm2t7 ~0[QPU?ysnzxV}bSqXV׳ɧtc/VL*s5r_qRҰMޢRBu<~sl?C/r ʾEE>ۏ/Ir}lo ȧ}p\u[ .9xrӇna9?s.grbtUȃd<_\}2?l yJh@Zzӓئ寎\Xb ͂Sp # ^;󫹯"tf.z!m9 'Bkv9JNdK^Ζ" S ~q19\k%wD zHެ ?48)04 Do˘lctE26n;1'{sO3`OgJnVIR/0<Ƒa4)+GY\hV%D{s39 lC/Zӯ,B9em39I)#pC}?H8$c텦Qp8bg^ߥc'lŲ8UYL;W*[|Vn{LjQ(pcu@Ҟ -C'>HC0oO[uaUR%<}DN0ʜiЕSwDw K&3Ms'`8&gog[W9MG1m=F}Y v[xNs,Fso @"rN`=3mfa͜uޞ\qK8BSHzE*/X|1TzӐ7v~mx6|xka< ȿ\l'|nmo),4k>2fl:)Y'#u`Aϼ|3~6]j}@vvq+JWWq ӧ(K4C;ٮgNߖ)Q&(~84]N/`ȝmTgSE6}/#rH4FJ9Qri*)zgqR #8r MawJ#Q\> r@:E1` yQ.ps)q%zrE浹Y[l91q;,4ӔtyB5odC:8FMx88:,R_WфǹӜG?@-Vfj2%u]x4#G9L߸Ts9? ~Wm丏<ӌ\T2 Nt9Ϸ"/7ng>?Fa˞ԺkaX1ELM9'өv;_hh2CLت xvBʃHSjޑk\;w'zI?#ğjO͒<6Ͻvڷyfߟ '2o./[iu½?4OOܛG0_٤Qc|[tuOrD* FQz3ϣ͇A$?B pK/}&jJ& M9kʜdvѸ_UvH4qSF^^Xp[X~Ë_+j&l#| ce@CKQ@US8)MlViRV< NvOza"}>'7}]!K0~`D_*JȜFE]SAxuJ O+EUL)ytiYd?7Ci_u8ޖo mm5:[y~'1F(X&iN0| `fOzqt[n9ID)l?$qy]rg?bwxFhtw%X × q|{+I`i}0Oq6vU9x NP jvOڲyZj'T3'ϯ %DZ4 Jg9W]S *?Op|9i.^:&[BГU?Đ"OlqR5]L.y sĹɲۥ2v\ZN f0uj:uϴFzn9'N~6"aLd"}G"s{J^9谯@wbUtL/+J [2 ڋ|"s~Y_*}JC2/؆Ľ7/ HiWE}dAZgGzĄo/̗rd.pr7`*_ҏ24;6\}#|   wsOӅNyT<9ō9uᇷ 2l&qK)_Б3:}pUIRrZˎ^R58V:>u ܣEZ޶v^'UEs7 }KumSq{*[M] 8m G A1G*5N)8,rB3k<`ɢrNݷg<%0HUk'=9)x~|Fȕ#oƛk~x\ę`CgҶ=_5,0;<\o͙>09USK0b:~gr^Uq4P WM=ߞ#'`g;JQ/ ?5.jnT('{g_zbse&^}e;ݨ)RpT{?Cc˓Ow**yNzOra)?g{G#,cS8TǹiZb_ӗ R}9=0<(ָ>nvgs,gf9;_Sm˕?_$l7u]&L>ۺٛ5)YP(5[7Ga_,y𲄌~!Kf_B9s: g50Ηm pwkr<)b(ȵVW|'|y퇆r?7C-> 3AlS-_t^w|5,ׅ.t#Z͡|{q|i7sEZJ:E}N~<&gZa^dmbU ݀fGY;0rq C-JoQEg8. ce ^[cW?yR+!+ܥiTѾFLd.0}I۾ ڗM;2]e zs`  hw]F ԋ+дE cDsj7Cx0^ _lGd Wggz'6ea@6?W8T[Ӻ:8?f+*_;q]~y67 9hj YuqTZ̖'u|6够 6'ik\lcAnγֱs(eb gK,=af9C{s>8r^,@[c1~W0 6~ Y"೮&woG{O?$ CtLe}.Gv7jjE1֨O_z{`*l`W%Cb:4t>qg`U3N=eN-2n8HT*fn+;k{<n%[9$RT ܀,&Jhmڧs+Fq+6GZ j];8`е9bK3ESv ~ |h? )zZ-zxbtSqb&qb3;Yi?V./ا>0-|;Y+tBAecC~f?_]qgpĩ+1;mڿ eGv,ǛR:?"2xt^+?ʫyߐ3ODqٗoj5-pYUQ9;h sȇ},prl#s>}A/D`莆f6{(?=YE By="x,e1 s,1YnӖ'{i_ taI)t2 "yOO_` Oc^%ydz,C9ѩ덻%W!9CEPu@ƜQqd s$1dJyTXc,MhVޞMG+)9o" pGѣ{#-3MZ>2%>NZ&%sBhHI&ƅb)O~! ]tK1e\5 1y ' 9_\^_ 7<PZ-Q{~~QC7z?Jf&'/gZdA~Mq ߬]~8\?r7YlqahlzGx?r/(YyXGcX9D@ΐS_ָz,̾,68/a]FI%.?/&UFsҷH0F`x>؇V{Bmzq51e#c2 Xw„OSg~ r; _`;g.޽(@IJPu&ZyFi̲ ~xTO*pqV<9󮵬6v={VQLP$kݷ MQ0|:@Kz%p1ZJPO3ȉ)z f._P\BE<Pv9S)M_%xkgm"˹Cax,&p3Qa\(u̒cٵ OQr%CƣW#G!0MuTϧz֝+Ťty`.{z\t≬UUouMwL0D9z|/$}= 歀c0r"xŽ|wu_> +JP#]1lr|`EeӑC ;sE ^WqM_40^OdW;m(xIէT G;뺫fλ Mdۀ,ǟ FN vn8?_#̞1}KfZ ϟ1J`ߠb}[ ,ޗ]!ᚉ,Eb߂w\փ=3>W;|^.HYE57@>^je|GLW:8z7Mi}egZ'/*Ia r`D@ws.~p3L 4I](1X,տvX>[:se3sO# Ne0?K8vӑ{nFZ{rvy[/TIׂ 5wT|??c72<{Хַ;3^Ω:睼܏`\X<^b:54-q 䅎=(߯˛xa'>lUQO.\#ŒK.5&e'Glh$6 ۈpS8wcKʮk1:+*^Xeh<2D#a^~IcwՂ_Ij_Sֿ+p~`aSg!x_uZQ"o_r`EU[jh2<.~|BH|9;O#A7tK߹O\Ep'VPI-ϻÏÕW@0rZծ]Q.QaY|2;A{Vfi[Nw tH/{p{=/s߯@12J j S':S-Gn*ftLDQ>+x2AlD;Wp2q^ȨhU,t;VLwE.FChkѶ6mګBx96-1THI?G91 AZ'%O^ bӡI?8@}E5tO]fe0'\ T]a2"%Svy+sOãtٲt7,^8˨N7Km+55dd`=8 )` PNўC#uQ]޽Zu2|)|1?w#j,y@h5,?xWbQYesۋ& ̆'xW'n z| |-$&#UW<^=囪~ sp|`3q;@]¥^\c\u}|V%EhPfҼrbMIJ:}cq@[b* /?Tަ2mxUGy`UA@Ϳ |+-I}y(qT.}E_[݅OC\VuQ,"RRh/5owAG@JIUE/_/l,ȶ94Ϫ& J drTz~yHEG&yz(\$[n"m}[jY:Z^+--Zňt".y*<^ra'GH~QRM&UDO@߷JXX<-eSY~0V~||Qm}k +8ԟFLJ~9CXD\f&ϿcA/ի_0MfO!vVMY8=.sˎ&&r#a Df^2tҕ:BS|ﺏ _'UKDJ _Bú9M[l>xQC0p'| [k(lJoھ+aN*X.PgE'z4G$6r졥!\|bފ!\~XռY? "TLѼ:D,W䫾2;rw;^݁ 7쌞x-X}B]{H{v>7-ɤiAspSۣCj[YgU.?ilndՋsSV9lbjZv̧YbV\ެE wrf |^Ӣ*~.;eyW@.N6O->r~Mʗa.HKadT%P`ۖGݦRV[m~TG3Pw@ܥY|. '5.mUu\ P~wښB@KrEC,{^-]Fw}͟BU<)uxl̴ ]i^] :Ng!q M*&ŏ6ԝf,Nj>H5ȎڙԆ|o T+_j>VvۿѢaj/ϾNX<5R]}@!ʉf#xʞOf,r;OV.X*>'g5³ca@]A> R :Vo2o<:omI5G*_Wh:ed5j2o<xww4Ԫ#F^ *# |0ϻB^r+[ãi_NTsDQ3pm#WNj"\x׏l=MjܖU[>:޻~>Gxǯh5ֶ$ś \c9 Kyώ{zN6_7~۞.[Xm٫+ۺi q;ZmDtPY6?~c=k}3b~f {d3/ziޡ[3=Eǰ7#pnAﶸ1ᙧ[Xj +ho?[nTvA#+.U+@{{|wY&4.|nCӎ&e| Q{ޛ58Sw .fF^'p+ө]8kjkLXRk?x_Րŗezrj׾,iXze{W]KnC^-y&G;ϧ|y"$]D_uMzS3]1̱:dIgM~uh{y~a66ߣ6U9ư09|yN%rҫ -?0;i.;62x'?cϵh-kp+}> ͆9ǫ|?}sxv\O@B+w<gz,N8FXVf_j{.T o3c[f>bBbX Jz޳I ?+A\L+ wG6?"x,Mo>zjF,l+זF_.[፠`8N/zh97^N?tQmy(Reax;u%QW_΃MCu_09zqћ3{P[ݿ`ўꝘgmyz3 ޝ?o,]KԡR,97Rgy~U9$n!n tk;۫9ޑ8~Aq̹g0ä q,)n\y% mOg-Bj\It_nFo%V=_ڬݑ( q='ޅK94k4Vzg㘇&8p~:kD5b 9s|iݿ:Ÿod ЗH3Qyyþ%,S#~~ǜp*<v8#.,)UdCI#"g&8`g( GZ8o9 ~Ac<F~PH.A&+swy̤պ2a1IG.1\<4+/Pd:$8Bo\2D= !fnI{x)pƿ:ۜ_nYL/~/l6q"~!TsDrH聰~)29IdN Kf^7a@@F"@_* {uPm7#/ M02QgCg+Uopּ>cҺD]Q1:q͹ 3J8ew_XŽ3򽢣 'xb~:>kdy7]x$-Ʒ 4?o NnľgƢG FR@n¾6\;$Tvjk <>#)x"n1us]'VWsx?Pì?y8Fb8*`׿-yތt;ue f07X]\pȇi& G# P/_jٙJ>)fɳu'I'N 2p0Lk,`i<[w~"0uPW Pkw?5q cΧ\ہ:'|MWex|H(h(.F8LJ坈.* ,v13 @sE5փNֈ:i[ aȬ:ۊGʝg}ǐҞָTf/2p}[μ2?<:wcU<>.oO4}7r) pU mS/ QrvANj0rv><=ʧuI"|yn4kϴ D.o 1Tv]?F5?ϬjǵB,9D‚NS ymW>b͂As.} ́Of~hz9O$+hX9w|Zx~qB?2XY h$9#ED6R=*M/'$՚~ l#d'gtpe!yMƍ4oD.Um`/R^p8gY@Vd,;>!yv.<,dIM5[#/?g)sZi ?tvƍ۲^Va-Uwdn%u驪Hß;-h=c)s 4 ݏU*''x[ͭϊė\cʼn+c2~I f @Un9qOnϿ_{@*#kΔn])ﶷ>,yyoһ8b+CPVq Bra*YlUi} ?eu\R<(2]%${r/}yM ]>g]D=m>^{Q֝'7Cބ49'sG`Gn]e>v[by'ѵ8#C=;Ar8!, wTS gcJB_󧛮/3̫Y8 X""%0P%g2{=KHqCp6";_$K}yBrՕL,:߸(R㓂qRy5ǛuYeJ"q#; ?\>ՕI9ȧ>3:HzjbP[O7\t+[taN%[XrCx?fO5 1|V&y0p07@\)JjYQ%g`1鰂_7/{=ux=/!^kY2+c_ ⸼S/vrkrj]Mnˊ0r` bn^湧u~Jd/_ٿYq͸=8zc{;;R|*7 o, O(gDvҀ;o6}c^0WG~ u +V??-*<Nh9oM ^_;IJ[rd0..'rukf Vy&>d{ ~sہ!wXN@T׬AoU_\;ۭzc8X6NڱٟY~5g)>B|۷Z9u<c>2OX|PNVV`|U<:R})8X>>ok[OcW 4]13xYqbO1tfhp08>nSYJE,:nJl?I#|P ,o3D%(mJ9Y~.]<`?vάF$}x痪,B5C8A7?wed1h`iX|r7c!J,is}'ָNpG45Jsn6^_Q[ k\9?JY%CiOWA_U+/ >x1]z XuC*c݆07GO\P?hR  Su~Bc1ϐܱ"&c|Y?0_4r]׽&)ɆCgXv kQE"Bj9 7]n-o1x$-־(#AvL= ["E"Q.-k +䩛?pL%~+e:P/^DOR%YMu%ܞU-W|ewdu?N?'4fPcĢْ>*'OW ?<;>^US G7_ L.5HÄY3 >a?_yQLǫ=훿J%OR,.={gTz/[i> I˒/Qn1هOrgKeJU+= `I0s~.5[Vd&d% S^} R0<5cJ]ơ-![\ JYy8 C>9wؿN.ߛ:a {sPY! J,6? 鉎KA#<"iD{]fƹ3AZ_;fTɤ;[ U ]Z9e׽v/KdT9kj;n4ÕX;(\wY~Rp0<.Du]A[V;IWK,3j#)@5<{QfxF7^!VGA (to)"4Z䛟\ _@=c>5jw3骻*zhˏ0ƒbQwX8 1?@Bybc83Xotn $cLHu/*Rfb܇ ZySJh̒Uz?⯷kPa1.|+PftbꕟE<8;:䄶)ֽVGx4m~rzè꽍fbڏ(: JVgU-&oGl_pNP}w>ɐ_i8AP:y)ezVryn8ݧ I pxܼ%&effk\;A1@R?뒋q-|7A qӑ;-Mgl^X ~o1>>r,y}d8O 88[| ߖyG.!$!.0Pw\O'wݼoϟ6SFefTƱs'QPFIsZŸYд_omVzƝ&T./'t $7eha@b76;nr 2;w.Po6$K؝[gW{[q!H;Q0 ;"K^r `Y64ռ*F# !iawUmCy?p32|WuH-ht1E.%r]9?;G"z]g} i=7rb(qe\@}EӤ}U\DTɟ5[.a(1L ޥ{P&>Эt0y RPOyհ|ND|7$7Y,rjY'8O_Ɲ-qj=]\ď&U ip೾|7"1Y [;C0^=I?!%I͇uMhX)j[yWl }j?=`05byRrP&ǁ9Mߑ^x/59|An{gx!Dpv9#Sq():޹`냡aFEp:'|Es\vs$,ϿFI\;qٹƿT 2輼vw_\ݙ¼w%\@hh<]љs#bI>#5QΠPֵ:%$nA$?q`N@vtQDLM^eFn&n[wfUmۄ}{ڽݏG8ŏ?~-?':=h|vwNGWewe8(|Sw_WXH\O-|➜2#FŴ%˽D^V`ZD;;s}f;eVk^h_=SɸIq ^òu uפyΗOzl{q!oS'pooTV.ѫ߿ij+0fϛF@w3sxIO>s{ʹ3.(\v\Z ]n&]6ϴ7oH<< Fy:廥}kXHu;Z d?kAƄgRP #ߏpOeDy$/ڇx5FN=G"Ki1n@⒎IxXJqV58^zsݙ}"*Csp|EDz<Q9Tc [ 5ЁSd$ \~2G *DC^&Ͻܷ!lD!ea W>cCEk^؄%\)÷?byC%E}G6VE&o<%aPpVŢoуJV!-Ih .R\88Gi>H\ [c*fճp|>'1~{or| gQ^g,cq獬vZw }\Hgg||yk|؛K­L7\ q|ˣB8{øuyuY֍94˞Rr9ߌbUnL&9I\/~slʓlސ;لc;֗q2+QdcƮ*š%k sLy$AWbݿ@Tu'moij anMO+?>OTuG_b<>5wQ:w%W鴙qb9wU:w%mo‰X!h&>;cQ-^"_*S+J=l r˄WRC]/Юzky얩XZGKY?|~|]j(i]xZOs.)5 5hO}7>)yg[u?H9sݻ"sL!ƻÏd<'g!5'YZ=s7v* diwAJ6lQ3vĊ\pt8ރB|q.!$ׄ[Bmm'45~OgkEF7D_w(:asNt^G[q\ 4=n!/Xm͒N5& F8@l# bzkJ(k|}aoL=k}7gL?\f ['v2&4#4M̬aEfH/}}I9|YOR\fvw[Q/zR:v BPȤ'i5ɎT?7aeu/x-ky Y;:td7c봽!fbpgdp~m>\e^)M3NΚt*p^M]`a]HӬzs϶Z=X릛ƩI|I*[~ש/lkv IxBJA}AظDvԦlKi\bO?%>ׄ}Ϸjb{rMTT CsSפZ4o!1BCx5=azJ0f;\wb&I828P[/R*Җ%qt|xǮ8Pa)26xԾo9:.m ;<) _a}ܰx;`¯sEHjCƕZ1? ,<`g9Uvσ_<:( k |f> ma\wskpCLvvuJ}p>񦲽at.tѕK?@\^<\nߢ ˚áC-E77ahf8X~Unhj; ̣Gxdbp@yyl[,"n&GJ?Mdqx`>yyJM7R}KMrع/G^. p~&a^K8v|YS|YgׅY$!-[覌Yˡ) ,89 9CŶe|zT$!7YǑo5L7″LP7|DMa]Wj9BotK,Iui\B\}'p.®}(#Nui16[.;ϷAķ":L ' o[Ey+'nxKC魼 }>&` se-'k0< W 7>xf:ʛhһ27fh/ ^%.9aPRܻqʁ^ނӴ Z ?:${ ȐJ_gf#-?3n5Ї2pG ;1Uq4v'g@s~ޒ:q?W9o'ŅbXdܷM=óy2[Ly@>t$OGc.-]],+zހRI_п@ܐ[+s*nyBSWs;M@Ӟztv-~E VW5ZnwQ__OSZ:I>ϻ>~ <ߙr %ܽ/7>dGm6'Џ W Yuϥ vCXPk? jI~T! ͟UmX]#@UHǪ#;F5Wz|_R@{kP~tLL7v>0zSxtnY?Y5kX f'1弬kQ|0зu"o8Oc応<ρ2< /̆7vȼCKTs|6!HH0I.dME=V,dkX<\r Âq:jrז/oFnVߟ>>CWIj4t4AnJ?bWǒ8XUYPHߛuqu&gx@jٙvl],, dVHUuSiJPpS?6_Q SM㔧DV?p8HLɣ~(]@x s]BA՚zOh3^YYAɣ:>|0:Åz+"VGQ7c #| h?co.2-rh#;:ȅ!?-/ٷ0"eeW8d(@~2eFy.ClDǗ+m?>T6=[@ 62Eyߋ~eG卝{s,z<RjH Xp' &EcI/_}Z`q|<ć X|oѸ7FuLW#ۖ5 ~XEE[gLd~m`C,fv`RL< MEx/,z 4[tL_tѸ G8vގ_?i XߦUrԲ\G Y3ַhu㟮 jVy4 7(?L*~'-U|1t6vMg3:BBDh_|c}4 J;]SZKvk1*Vt~ B;9y:S`JS'΋+6\/x:o{qZDaS/ǜiZvY#ߙn;ګvx<,f_:GRr41e/*%T#F( oV pұ,qEu5~2WGfp8lZ?ݪkaqZ qs1rpQ894qA!^72qmrHC;QHJa WNm~c1<_nh ˺gT)$笣PrQ<#:ބsC/ɖ#t*$A`8qd×+IpD\ oGLX dXW6v;7o#1|B@>u=Qy]QS-perX ~>g.#K~E|vaK"/?_&7 T*ނ Nh#hc^k[R}W .L08OQG_Ryc|vڏ}ZS<_ X)jj-U^fG^5\e{TTM,ir.b;cƞ޹'Pr]2>W#}Rxǡg#s?3Tf=oSFE[pA"!tuԹǀvJۡk}Ъ[dž'w3#80a71E>gcWf2WA$`]ZX#%|F3c(ۗT;hdJ.WzФ\w(DzFz\:SYzK[٘Y&L彾= _qA'y/Iᾧ7o_/Y8z?W(qN)>X %a:qI^ kɑ񠈷/Bup i8;ӽ:[$js8(Eҗ;~(hTJ>)q-Jm׋ b\j#{Ex>!ōh  9K!ڱ"~>qv!DN.݋o?Ʀ9:Ey|h9%ȹH9| <Q1 `pS\UtDDH`V61E%~v?Kg 7V9փ)+({pʞ!/} AXʧil80y8Ex4<` W3T`sS@FK=2[]ZN0KĈLq`f;:9\J>mjzŹ̽ŴC+| O@WRۿ]W\5T9-RG(3RG-g/R)F?ПS^"}[TG,^{t$|yJ>1 ":[=ڛ/|^x>֋γ[rhXt웍oQtw>xE*q8{8SmK:9Aj%]#"O3x>%cRvpMGц "іm_'_>Aĭ9V+_rYp_)S0|kOm廓cf&abd$CgKW??¿3F.ˠ* oe!)%|&5A)Iikd[E ;5Gs/lu~a/''B"Є.o%0>yf .q5aS\(*` vtJ^BDu &Eae^f֯W}r+1~ Œ*K#p}G8,-![,lG^Ug oO;_~֝q`48+l% 8^ sIa_& :ӟFsW%`3o(Jb{8}0NE2 ۾J1z6Ml9r?*ʹwP;5[[RX,ّQut4[F#|M3 k P}6qPg{/Rwސ^tek; ?$E>09=fܮdQ;m}(PΎ.ѰxVDý SLlE> ,ǎo~e-6tUE-DS$q8 ^~1֫w9dPpK~'+sF .pc/>CU3-c^啉|!Wڹ[NM2i}S?/o4Nz*fnO\sryTy0@Z.RS˟m~NĨ p@3iWzD_tN..,meV]y~n3uqwJ. -dS!'`:.pu-qk/US}ӥFѫճ1B+;?Y3.kwE\UD?# -6cQϧwў;cq:< |޹`*gv {Z &L*6`[堼{ez<浵o2wh ۗ8V'r. Z^PGnH 9꼼`Mm.w]l /%E?71T.j6]#dgC{ƒWJ6 z~S}- 7|;0;Ֆ#qb =Z,7Egn$s1DB3tQrU{r[^{KI:آxn}|C< }6̥!p_]Ɩp(Y~mXw4P ĉg7W* 4W߉tg}LVPΉ=_ͥ "{]CQWmֵ"KMWzى?oZ٬ZniwnW(Ώa/΅<Ff'*:i^:v-;\ g<UK^9(/*X^(D ċ n}@;?+}4I^[BۥJ >e,ڤg*x=ٜ$.4"8In?`w*+O7s%۟<!p򏟖>>u{UDעNҸƐǟ#;@]vR&KUoIz |_c:0)OZȣy#W5+V\}z[MHjH_ Џ,tգlP4#Y:nՃ7QA]ו YD9L%1́p1m( O:iO~uMgk"n4v,/+I~k"ah=<&Ώ̗#|j`Jٲ,~QGh$SGz\N导}7]ת@ OwsmFAhE0^hl9ѐg@u- ~ ,'ln?A(,XRrgIwdRnxO}vŽ)<7!ϖIEЯtwo ݛ]"Ht \5 SPQ[JWF#BC?u ˪t|4=28 @"FCQ Ck EN;,d|i77 ]>6}+}B#ꌡ % <s[2_.]ZsQќP(oKE_6۞x*(eҮH xoѯ7$ţ AX}RFܭ/DȓHkww*˝"zҔ )5Շ2l_P $y A ]vh=7f.%s(V`P񦎞]kl2iɡ_Fukcrߕ;0;$G'@!P@ȫ%*vљ~TmZ&\~7b I㿆6~RԵRr Mw+@qUqRٗ@khO:P Ge,qmS?JMK@oAٮ_ߓl)MGT (_ܮ&MWPzI]C~43f{W߯yBYhNn /~n wa/hǝ^lC84x ]|eyqުV0 9: g^K.Ӥ^b;ġS^gC'g=ΆirkoqOyGеScűm-{7c0!O n@e+)xm]$.Ҿ8t>8O{q@BS'$&/Zu77^[7M%fuH#\l.#:t&m2E|:1eSg22Dǂ g]^ɟ|{S1~r".XorAXt@ȯ/R晿 rp"#P~bRODRO;_.9rR )Yk=j=+!8OqG:# YmvyyI W%1 ?HMl 3?R.'#o!% 9)uEϲ5|3cxeSY]¿g Q2%=WW^2(ܕy΁IP.6[w[WDх> 焎\)rKp~aKg h!(22TX^{!{pӓ oOU>PaDG2CC?c48BSN MoB)pXP&ӏt@KXGz:,z/C˪,]8̒ض1 u{OԇaUZrsjm;ŏn4S #GF|17M2? ȷ&?~ȷ3'?nʮs{/Q>5{ReJ,2Uen(-j-wHf#q o@oc!zqi!w^`}CMοC}Z:p=OkP0pDG-|[E1#7_ѷYF Z!vmܭү@ 6.mS Z 2_}K;*>'!l_y%B?[~~z^'Ca1[)S 8"ON)B`<[? iW*JP+<}2Ӻ-_yݑ o:=AGA(?DܳWAjBvmrc@]"% |>X> lҥJ GCGC~G5+U_;jn_3?&\] oʸ˸ ģf%|CpwD哛>8P爮9o$Ezm/2)==\~wD7mƬ.^JɆr~GԳ4@#m/=MuII7*?_&Ist(a$dp%1}Z&rGw֫N '%> @Ux0 R.xj`O,DPC5>=SSeR&FJE@66Ŋqt+^aLkX'.H[tezZC-ˊ ҃xppgxsWAL_9u4#_ܖ1W3& ^^wlOZ&n [.cGj"uIVv a\&@q947@=_3 6vor{-rY: s`H.媱Uwk P1KΊ gJMR13),p]A=Qo?nx}O@Uy7ԮX902Avܸ. Z;kƇHX x@:U =(J/1r_M|W[Q@~k ӗf6'W5i{m4 *P-ԏX,َgdDuV4 0{$%w%$tPӧEj^-4ea]:^BUD{y=\]\o_J.Ëe&wg] mY~z*5! 3th@.I w*UPi%'_Kbq^c۟_Ħdho"GĪPHA+3hLaΧ'>3!OOJ} K.{)қۿX'0/ ,^l[xN4kHf |CR_ۖ|[OnhV7iW?@~I+yCɢR'ε>4$G` P Z{yQ6G^t#FEf ;!p|Lbg>eFn[}9PSb 2W_;JIQV}hz9buL/[_Ywpˏj):a#.g:.{E |*U(|AXQ,޹X77y] ;^~fK՛nid_bҟf%^7 / t+t9 ~9`5jzpw`ژpҳ!g_L"ƕ1X,=%G 6cu E/=Mjg,yyȗs|}Lpeژr`zf9ɞq$@}7"."mOSL' v3K?._"\_lZie=^`vJzyۖdv<::wPxݙLLd}/pFn2 ȯB[8{ Tlš6#1y>MI׺_뗩\[O`| EY%Sx@>}ƽ{cLl=.:^ȲabK"~\AN _|R3ZuԆKep>}?T`>;N$\r[z=3X> ^IR;z"LL8D$Ci/'Q:3HGi3+Xw H[HQ GA[S ;T\¹#N۬QHZFx|+r/2.2q "ԅ"Tyu:-Q2M}ci<t$F1nbt=y`97Z 0}) tR>U|Zͯv)" %d^2D^S32fA^yȼgO̢g;x_V9<d^n?~9뙚 1p.^p/Q1*Tnʠ,΃y~!>h'SWDs\@3u1r\,;~D݃Sp= / whiD'on$(~b$Fs%qcxh+毗x}jֿ$<Ã@uo<,ƓGuSX*\l̄$=ݪvjtY\纽%FKeT<\"JHzsRW¶w$X$)#z7 Ӯv W,eLTR0SE'1MKyoi)Xg^:ί>~JʞO(?ArUu,~߰:©c URww90w`A!-~< 4ʬV&ȁb=SE'!sQ RrܙT{`.P_*SxHk g|G~)a_Lc_^9 'V0'o<\i݇}ĽuC+'5a^Ur h?q!`o@LcɎzOpLt#J.Gu=t=\f)8nH 7 {lÔ\.ϡn>'2܋9aA(*ԥἩ@Ɨxw(8UƓ9Dcpb6@ĪfLev9yTOCO NJP'+:<[_l#6$_&}m' ץHok€!&ty3O3-j `ߝޕ ;)O\?+O%VO?Py϶!6l]'}~lsx'֋AT`J?>a]T"t:Ix']kzR" ~Pghowi:@C\vڿ#O6R'Y"fB7hq!`qq6c*Z\nBz""\ϗt77,'}2ksڏVmxJC eVT7|ZRR9$eu!:SK^+P@G}i*k_W3l|)@jO \wөq.+8VXxU+}c*D'I.}}pV[^!T Ixޗ >){o"aarBv`C {v ޮ]W>A.?eRWxi"o$ΓQ{OSVZj?%pmqqز[\m#{d?ۤ"ȷM/ރ[u֗$hq4y@mz\[22!Q[ן6I|IC-/-tآb9,ȳMfMhD;6\.|Pҝ)#}/r~!\0߶ȪP\g|lDXEmE',o]0GΉQǃ9,=-Ta'~OQ+ltNonO_,P>kD΋NCe<(֓,%ziQMW!˛Q>DvP}0ֲd;Ih-`3U.)%%ʖ|dI XpgO9>9r^qXx.yg.Lݛ:{T5[c#Uʴ.?9d9h\Zԃ9B.D>=I1}̩G *.q3;T^9PvL 7 %{G|A=x[%g`MkJq  AQY7,~x!>~{уy҃@=UR+SZT31)` X=qw`f(| O?zEw ͊؍GA=X|IÞ_6ݻK6]6!p֗@m~O3V/ +^rFetq ϠsE3)&꒪ƱKg6xnO24j~0Fb<'9zҦKbr4Ycy&E'H4#e):E7rhh{Q^a:;,:S84Px$4ET̒Wh#{l(~<ý1EM Ι[-.-qe*P3ɹy7q⩇FԻƬ5n~}K;tOJH V Z@=k~j`Ԭ&mnKGYcw;FUe V]W:= TNk>q#t[oy^*N酋@b>fQx::R\^} U+ԥl8kKg/^]. (r2NT u@ijar:o*=Ixy,|9Ԙ[6hF3k(*T9?4Ojl XS?Ϻp ם'1GM[lRvú: Yv;S=ԛ~>'1j ǃZ Oi+qx41~=j Nj.k maǸi+4~:JaBɟcx|y[}7"O<{o~|x?·+$]pg;~ ̓~R|'|eUTɊ >* OS?B4xxS(tyG2xj''}‘S^5jN*4`xoqUh<>tw_r=b%{ \~8y-{B;@:pv\]˚wl|ja*CLDH4v\b¯  V/iP>Ì5^BM%7neSQ-P~| ,f} c}h$mxvD<0ۡzaRSsDx u$ uT3tBzw#^Hg6'SuOH_Ǘ}>4Hv\K>+-ӕU|F7[i'6#';ƝUSJB{VW:; /b':)J%o&kˈ/~nu&z@@O/ YzS[ҢGV2z(\Macnd0]i{K[nfBAp7 WZ,>R`HB^)N_'!}8  }uiwόL;yHW>H+tvDB른mҥmeCO*%r&|' گHwM{ֻ2ӗ5.w|ryQ.'&p:7* }j6^CQPux21q=iD:;>+?|ۗCgтGwZoRAꐘܘ`:z{r"8*}$d}OChAG=Ž+PrKǶW^>Z' be5#Sjz3F'.p@ 8IRY%?,=f`?^0 coÀ_"i+ ~f|zp z%>YΘDm+ӡ}ɵ6 ]gQԛo /H#/gYrhh8H\pO;W*ibt;f2GXK Ebٛ|w>?0CQԯ8=it`_Ov^!?+W#^J[y.̽tHy{pӀ\P0:8)zŢʥ/s6&c\_;`S݇zd̪:H Lh|ynKsu 3H\b5ϰ';ךxKK|)<@pSn"g^uL|=G$ ~)l/TLe䊒6={l_o|)lC'{qZOAxqDk-z6s;/>"Ma[=2y vOtʲ?'N~Dʺ9"O05Ѓdp @iGYb<~_x>5o^.4o/J;@⌛y#Oei9#u .-yEv\ALN1%)>"uӉ"E*E/=䭐RA"2A +,ukݖw\# j?p/VUzڣڠooCLiOWE:KjgӉC4>NcO)䰼K7Gp=yO iИK s/6;Winas|HfN? dRs;|R+>Y6?n$ iE Np<'ӌL鞳2\[FϴMO8~`] +.W,I~NnL=m2'dP($nQ-4;7rTx!qZSSĮBRjd?h']%ozGYV,If3“/y@V2gI̭ $˨KmY?f?ArQ?z6߉5L> o?gpN(F|%SEV^K(TL&@Lsx:+}Qq1e|\46BdoM r~:&o]$ ×P8?’اE=+lK_vD̒#>CNP}=0ahjb4-[b܇ϥ> L]**^ =macexofV[%Cɞa߲[tىU\ 0faw#'̣f.@X5G_Dc{C:,'^$ȚA`$}AAs}Ed1GHAy'Өh<@ɓ?ՙ[u(qHnpKہsլ}{0K,\t@k'ovzOa^~3Lh뼁 LTr -i]UmW ɝiA?yXoTosS:wT}ҭ_s 7gd2#s} ;-xz*9aN^9u\AօYttC|kc3\{3-p1ԫ[bxFWYY|B+ys$'t8x*y} BRT'HmᏦjOj^ޔG#y?)M}Óݓ5Jg~72jZ-͒ShdrD}~DȖkKk+ާׄYᾬC2|9s+ƅzG !wZ>;F;h@"ɋ%h`Au@(Պ})H?;䋶,5PoAJ35ٟ kz|[Ǵ XvgBlW$P\T+3]3sBz+ bu( .п`ZN3^.wF%we3.п.킰O\ڥCǵz@TӪ 2Pz{N˃aVy#TIX 'E60N _3ǹWN}+* rzSBP 8|2l[&mNS%.xF=D`~u6A}U }x_gp9znl84/^+ղoH "-t np H7<"ih+ɲSq5cxF88qQUdGWt`3%B~l:(Gv7}wxک k\E3ϭWw\=oj 77mC+OAҥ/J;X{>ؗmJ0g9.#]āuX=Pӣ_||eVEu!hlH>t\עȢ➓J%Y-z6FaKͼo[O5L<DM{>D'<ӵ`<yDVd y42y/S܏l2Fԡi`qڮy/I'|o퍃-]tckQ*Su$"ỷOdži.2$/O@/3Lkam? M}o} #]vw߬qV-uʫ?7~+u$iɷ/,:N`?<|w-FW"+uh툝gcꛉe 4S|x@_UYgߛվ]?9ZO%ڂk߉2%P #.K`Ǔ[ߚ@ tW8yͭ /O熷O葵=OjϹ^k:u4&ɓڣr|tͻMU0BȵlN/^ϴU{wt7-,Nr+~psS pzCg%~2Gd;3[ qeۦx\*']qujt w1!HƙHfh̓S/1ϒ"Mv/ՏŃϙxuՄ} Z>Qa7 8sOe^p!A*'C˶Z\G ')@*aA+rzYIbs?I8I~X3 83<_r)@(b}J 4Ɏq~Qj#{U!?F6_VY/FjSP¡I_ j/4.x{r7-QI^~/>鯏hrO! ߃}Ns:®F6\ʎi8{IiT"oz[XSʭ?w2C_?O,cWں6٪w ϗJxΧn8b? ?GuEnDh qSUs PqiJOc?zJ112S-ʡ۽?:mL,ecUnݙ-y潯uWL^ 18ϙA7ߎu_ |nAXR}V#gW$3p6 Yyŗ]i2o[b ]۲]Np6-3295j{2/'x`iЯ8} BZ;>_^&0 aNM;Bx{w L[|}hV`'#> y{1 n|\1~<{nv -\QA~F!C;[^) "IhrkW݂R:r}‡z~g֩d~ /$iJ)L,Iro+X_-iSĩY߽haJ"z E0rnxQwdx9ZߪZRZ*m[Oz"Q=j1j-Lȋ6N!b-sk۾LF$l\aZYeemʦ$F[xR wcDҙ k>~SyDt)^#Ӈb~ӈcsG£7(KW7H vxg+L?4(0JfC\pC/,˶UL @jL,lxWn7Q*Bu4~?H }\[VYH}_[1.}R?Ь`Kg~Fյl6)PE:2^<);]>JTY#U~)tM$nHg E~SoygmRڵT#fbG_y?\7m~rctxZ;>>8Zutu>aXy:GcٟdK" @xoڜnOɫɒ7;Dr %t8D)Tox'Ar׈. D) -}e_m+G H1t(~Ok$ۯ6('7EyiňdL@T#~D/T,%/N1&8#1 9ٷ;^87~NG` !jW('l,#UCxZ( !o;xLjٕDIhOb /`Nо4{ N*j[@G l٧Z Ԛ%M2$^`LZ2K>F̝]i-MF|H dnWcvƻEmjvv?Ϥ)7L>H\V_n8AjWu-8sVM%H"`z&i,Gk<-:3g%@MS#?ѭzEYƟE=P̠@ 5"9u@8^ xxf2`Ml䢠?mK {fբӏBcxy\L{Oie*-k9g:t-Kd 6jI nY.VBEe.B"⊬yDqDt[34sb~}r~'O| s+жZ?/c,Mܷl`JƒZico:nh15?QuofOnal1g0s] SE_zxyfKg?N=Efh1>S|}my][w!-߯~ӸwL/9[967Oz=Έhf5`2 f29Dc-<yd(T.I̕ ]VS`&8 w:; ܯ REDme o/?墸@wpbW* 5dm^_u󭆜ZcDvuv@>\iCܝMeG΄AfT6¦Ox@C4^^ :ù~jO.v[Ѥ M/o6XY$/bN6kfRţi! L U;̓^${>];F q Nٗ \ռڂ7NW_Y}E'˺];]vy,t}\91K!i+O;wO-yR}`όiI"g;oT1 uOœ2l̗Ӿ<3΋ٛv=rwk1TC c(u6rh A-Yԋ?p34x206ϼGAɧlцo'T_Q늊.& ^=`gxȝ!̒x z,2yd[$\܃]ƧzEfjw~eߌ:Z,k0~S[7]6vZu銛X9A;/ Nuq ނVC әHFUAӼs}* 2|WVy.C ^W^sm-XD7"}*,2/yz>Pi+\ռUr^m}AE'xW6ʮX`8 藖GZ|6n zPu? i^pxì\[YckoUsy.$ _{k^i3-v9zy/WD-Jzs=_8\MkO/O/ ^ -NW 10]Y%ܪSb??d*Kڼ>6=~az;58,8ujgі9yy;p?d |Hl~A{dz|ݺd|.?s!!u>}&J/jB}!*hqznΛg9׆jnk :2x2:Jlu]M:_zEGgtr~.gq]P겳S$/?Qtۑ7O{bxB2>ioCuiةMHS96RM^n|a |}-٥ΗPYLk15+2ǯYw>InGca\yϕ‹͉6s7[z^Yޒۅ.?ΗhY(,n}nM]ýƷÀsf&]'vT[;7ĝԷiU}nw3FݺOѴ-0zxżc񀋍iO߹[}_VJ6R)Ҽûͻrl͈Yvwм-Y 5H/ϏF g;xR. 5y>'/ fp-ui.w]g%^o6jAHa.Ϗ5;"BEGu5m m犅Uv[{nZ|W鍯:sO-r00`΅ý͵Jr]0Fe@.!{vҰW vh}^uڦMsZt6.cKi#NxX/UtZ`eޢ#%񦎴5Ie5ׇ\6N/.NyKGKZɅU\ >7q?'MV,^4)@6XuncdHVksɡ?,teq_s{zg;WunI'JqA1?.ԴO$" LIa A ZkkخCr ~խ"ι @ŜIQI0% LSHүOalS+rhaۇϼ[DAHH.4CR b UimdI !0<{n9?X@gm4ڢGI0hB0@ tq\U0CocVaovЭ/&XBK0\uesedHo+Sr9}H%qIDD$R &pIaİDB b!<}K,_&uuYG[GA(#e RK1g(t(mnvS7ڤGasŎdpr!0f.,0Ҙ!&vi%}oyjTn}@)1(L4 'cG! q eD2(PP*&qT#7@DlH+y#Ń' jϼ0xu=p-Fp60c1+}, Lڹt}2'yrWtp뇐i.!@!׍$$Q(UƴI˨Jywd~x{N2`տjι׃wqv Xïcjڟ/Uh\FTsP+S&$v`ɨne(7+IJ9I&r§(نN?ܯ?'.{}?1lz/ zdnɅ5}}~>r{LKO 5DyccAܲ5s VY埿q,FSf[N=S+W˳ݟ:|;^okXTd'w{\庯|u^MvU/}δ9-eQWU7=JӾH(+8c~v@PպuT2NJ3\ϓ&H_'vk3dxe3\Xwh4"}C+"\o:$_軾mxY"x31CcƝJN9oPrY<.,rvٓuF6qorQ "ib0yjOq7Ƭv5V*ȐiScDsy! 4Mb|^`Ղ&|mg}K~"inʠUe 뷖{m2Y|5"iapV?w]/*i؃ ;ۧ{:}/"i sqwo"hЮu7n۫fy.5q+C%.iNX؛ªsLυUJZ0h0)f2<SG ]ɤT:kK} U,o"lPzy .Zˑ+ny"jƐ%W3aɴs.oPJH1DIbCLi+MC%?~q˅۵wesJ0^`nqϮϪ#P"Y aCOOEo_m!ڢx340031Q0M323ILK27M45K4MJM67121NJL263OJ4IN4`8w[KDo'~Qx`>u? 'L .Lܤx340031Q040670L45I4LM2MKL21013H4N425H21166M1g0_$߲=H}9]!̄4SD33SC cTs43K# ) 5rmTG4T,x` 50K401006 (*-X*wʦjϝ긢.fB ܯ^xwx+)JMU044b040031QrutueXlmmAṃJ}G;UTWRQຳyv;slzC8Ti^j9XrѶ_,ٟ#4'^A0u.n9)x340031QH0NJ56K27N60HILNJN27KNJ0HK6OJ205gYrm٪_s-x`>u? ĉ'L Hx340031Q020J261KJ2HK2HI2OMK3NNKKM2N67HJLJJ1201e vObI<*/{ x_xQ 0D)6ͦ "xO-FbEo0 Ǥ,ske[Pn8R,EpD?g}^3 <GhYK8ЖDA);gݧjp4-r;sGA4ۺ=(in7IKFESNx340031Q0M202MLK2H2I44&F&fIi@e ?zY_N&_~q s xax 1ENi@k2 "X$YW0YcÅszMD08!s Xgd::@X0Pw"F/RUzmZZV}|/o5I!1z:vUim}/> F-GԢx340031Q005OI1144I57INN4L175H1HLM5431O40NN23Hdk_ 䬛׭Lk;yxwx+)JMU044b040031Qrutuen~{T}ǝ6^r"(1/9#>-3'Uug>6wٞOpҼr_ʧ+O\\iy|tI/8x340031Q0L40H606L33LM1HL2MK03NLM464161IaПg;)`*V3#/9/xRx+)JMU0d040031QrutueXlmmAṃJ}G;UZWRQ°\erw soT%Ԣx340031Q4307L6L21K05I2640MM4771NJ5K2L-b fx5uۦ0NJMfx~x 1Nۀn` V.`.pa Ô{StlH,_9$$cf&hXQ*g)cV~p~"Q@JnZuӶL 6̸u=-x340031QH17HH343O60HINMM04066HK03HM55KdX>M9jƙ?V<<j9 x_x[ 0E*fդ "W0-Ft݁pS[Yx^ Db CLhut}8X*4ZsYUA X3RM) s6輢Mរ&Jm;}<\@ޏpĀv?jۺL?HANТx340031QH4OIN0MN3307I017L3IKI12L3541505Jc6m9GUTn> x7x;j1Dmdǎ|M3`V{ >QvL0I?!4Z=!צ8F!rsQy9]$D&l6A>jFWҵ IKNiZ%S  U~̽>' w [ DGڡQ-M>dO}\8g_ШoYr`x340031Q040K6LIKH47L6KNJr,L LMLҌ R.\nlU{O]k}:x`>u?$ڐ޺x>ebpf x340031Q026642H3KL17H01N03LN5J272HM6I5NIM6cXMFUO,Ǜ_]q!i2Wźx`>u?$^OXW Yx340031Q0653NL5N34M2J2165NJNN5N452OL1H4I3O*cW}pߎMW)[- x=xKj1D)zUB-0uV9<#+Wu? s*M3x340031Q00040H233I5I546L4OM45LHL506H1d`.\%qqc~Q xRx+)JMU0d040031Qrutuen~{T}ǝ6^r"/\F0|Z_8]nzp#sx340031Q0L2074724LL1006705H3J47M37I5637L4bԜqEzҹ>0qU0mx`>u?hC opg<21踰C 5x340031Q04NJK3740347566535K5KN5KL505067073eogRpwc[_p.xRx+)JMU0d040031QrutueXlmmAṃJ}G;UZWRQsCtk# >-/y.7 Sd! x340031Q(HLM1O6KLIL3346H30101M20411H1LL4O4L5L2L`rRWd&8nntlCr f(9*6!ˋ8ݓ}}1Mx_0 @<0Ƭ#ÎM?߱ /7v}-W'=z|ִ3=Gu `\; 2/KKLԍb5:kxzl݉7z1?a=4kںŞy?Vx+`WƤ6Ũim`Jg=.'X300.W@< Nxg¥ޮSٵ%/u sIι|u5)L;o-cx ptf```bi|sr2h_ܵal3  y۶eHԎC݌,lEKX,ʺxC7+ͦ,>?rJXkGF㱘4yZO$etirCn;]Rwy}sIbe3κ= w3Oh߅rcy.Ӹb2a_{6A&5;ދ(Ü -&˄C7BMvify-pzeKY~*YnKI'Sl_{m>+>Y|ZR10iWj$8=+u G.e\p3mGWY[8#Sԫ2m)p͍sVL 8})6=9=tAB[31Hd޷x^ڟ7΂K]kK^׺x}= 0g+q1PCQ%D7XlC jǥO*uF>n󢤜yRiFsTL6;)\HrbU m+8N }#8FY;+ǵS&/kMj9x;ŴiF;F;xSK)MIUP*I-.LPR&ĸ\=C\C422KjSRDZQj&g:P(5-9D /JP+дF$_RTZŐƐ1X.1I8xj@S܎#b(]EQJAtQ*%LZ3ILB5Fp;'s ]3 +qƑ~f?j~wYm݅bx̕I[.]2BlL[4cR^RQ/8ʤzf+!HK$QL ѫTPSo_tLh9JhmKhIh%4Z7z:MVsy1 )H1 JEFUSֱPb[6IDCh&O?cAŴ5,_y_)5 hK%2"zR Vo>8],mJ[x`aVGH#Wl6LMvT؁`xWmo6l FE6)ewC7`^dhaMM!" IAzHJa{{HUbC%e\h{ZiL5 =OnKFYFjYmRIxf1MdBzKBRrNTLn*%deRܣhW?u\=$Ūu-՛ŜKʔŨ\s*m-ɈR5^ yJ2x2V}zwyq{ߟ=؉e A3-D ZDXrL( =Hs*)a`k%see)JČ@/8(7M^Ͻ]/e`@UHv}1<#}.3WPTdLf?y_,F&{I4?3[Mս4i{Y Z !9:Y4^ew*V/YQ<ᙨHq597<8 #2A")Q,lF 0Q,9&;Fp[!j+֓ XC+4Ά"]QoRjEWM&n]]&}ja:;[m lhG40$"0]t+"vFfFۆn* .8cr\l@d| &mYԜcsЩtoGi'CA"QWg:2ΰ _<=[`}O]4gK 7"}{M'\~%3iZ4K$]M2!"|T׷ߓs܄L;axoW7(†2@_Gߡ<4zda"͞ J3.@gI <m)xB\ /+GT}+}Upq]$+ OUh_d-ݱ=֯k3 l]ʭctbPȆeGa],TpIQkf|pV_asX }f ㋿̎Gb}EYb([ zGyy=㌫/^ ^6k@8";MVӨw+IjK.@x=F DrHAUEVFZtl1O8km.ÓE\GTu,֍_>+(xVW𖃉s_YqNNKO+)U#C Tp"d?AJ܇Ա[ cs RF/ 6} _(T\iJ~^I|rbNN|n*1M4I?YxS]@}M*|R냱1&>0Hi~{PʶJ9sϹܹ\"k0VX8|G{4cU6@jb*ŔL X |KK^qOvF9.w┆{Um\|/(t͖8y۩\r_SI1;zM+th}u|rmIJNCI=L±㒄755SFДePV1L^.a$ڋl[X^"d!kٰz'B-lA; *UX=d!3ˍWTDozwPIZ:2HaFw:BٵZ܄WGgov%9ӁF_Ivq8_:]"6x;7Lt9HkbrMRa: <ϥ7S FVfqxJFN=蜠>?01: &xYmOHi&1 NGD !UtoWYk{MVKv~38CޡVXwfg*t+$|e?Ԫ/U)Z}qzw]YMU+h`/FQ0-4fG~^~;?~?y6k+zaMnd5qmuSε?8$J `^[Ir~VP~s imմEQU*kQilt "U0/k 0QtҪT+ʃ>49?k J,Q]=*W46th.h%ϫ>'3~kUo%|r"+I4 j WA+WNWl{H\tjg v- ]c[-cL*3T8ifkN6u:]qhfۗzWZxQLA?"n7,CIj%hBiT=3S3v(Q?) 5O*Ԩ WfW'/@R8rBIҨޜ_Y;N2pxm(œ…!*CB,mxrx٩RSmb=CchY2 Uޮ֔ͦcݸ60jɎI$:Xךa/_v'/Nޫ-_RX| 9CƋ i-  ȴY$Y2C8kv4;$C맫H~g?:oR"pNxkJu7yXQHOVͨR?:xu!*D!ntWz T7s;/KmہWQH&a#49H|XT^rg&jS7h}o9 a#Cbu9H!OGcT~c| 6hz1N[业 Ve]b[.e`(\Md{-Z"7r^Ow>k<'\AMϭ4^81gkw?޼{y2a2nCv: KŠݤ`m6^3fޟ|ԇle1G98=2~O8UD1O{{d! SqbLi&]֢rKSX(TW:ӐMS5s٬&ш%蛲ctC`?N߽\ߟ~%S򸻾7>y<}9VMьiYtUGeT5ϻ*ƪ}rs۾zNc}N~Lҿl~YR[~- 0l~Z>gnVWi`jGG5S9LHA[lB89K+[NJo"ss ;MБ/QzS|Vt`AͺѓћZ!`E),70N64N%8׿5·G[ b~x6A{C6A{Pޖm qb|('mМz&+dߊ2juϬRe`2oe30pwky\fw@[3WYq]RQR੡l~,̀NB{qtI P @NK* D=- ik \10>ОqǕWMp14M̦&-õJSn4Msz|/O/_]l޾obUm0&G7uڲ\ Y;UU8eUYbI\A >s R8A*U(d)ΨfRCIjz3Hʢ50 I{K񌖠uIxyFW+Tߣ|rsZ夑{2)CxQ$֐L靹VLz<+}(:(6*)I%!;o$i `YL# %%ϭ[ʗ(/Lr Zc #IL䪒UpX˰Ao̅}y$ܛw:Ӻ%~컬h3Vw}_ueȆ4_ U:)Ul=lP! F.aH)PPSM* z)@`Gr^LZ_T+L_mNzU`7[Q{:]kԦ;E.5vad'5hYTA_l}z/qC.;Q!052|ֹq(~`u۲>!mղ2oc,+Hi$O'd<~HB[,IxP+Um6kuV8Eʦ/mL~ӪE!fT q#k-9=1{ՌoY3ETq,ھ*Z JAJA\I9,Ҙa+Ӷ э]Y:yU#D9Y[ ֎âW $ \w0l:H+Eoc#Y:8 ]o!! ˠ`8473G Lnšs(p隀ЂS),X4Vlw@8ٙ-J%LG(+יִ@|CjxtTA~J̐6LcJ#NXWr7ot0X q"N7F(F4 AX0"(XP6QMچlH!YE)GG?Wt(Hc+Y+ڤJzil-Eāa:L0%hW⯝V%Btb5K8nJ69r_u|2l7\) Pjo$yet+rFh،kô=MLJVȒ {0WN|יLU%k|D2J>M_欩:kYcr\U`wO3jniM :V#7KӘR;nw7/ӆE>2~}ϳ{c"=Nc )"Puur1yuL%:ʛz1^/[ÐښytJ0UjF:&Mˌ`& ٗ@NJ,b,5ӻeq\>w:sۉXP^4ӳd7=4 "s<~1y +nag\<n(&Ϳo`2}h: I<ԵGם5Wkۏ7W?9loW7Wo6?\H)B ӆYbj2@$&Gy#FcϋDU@&(a_ID3DqQAeTZ>T P_!41/lq ~{3N![Q+E]BKŷ߇kc[ۑ?tm}7w=9<R(M:@>!"7A]mzku.t)$=KSJP* T zҦz; ?!}B/ P~@">0]OuWY>|Qz_g[[rz]`2VLm]nx0ؾ>P\BHW˅jZUO?і+sm8OK=SlLdvs>^+YM~OLڽ^,&LM=Um~=~Λ㟽{sUƖ*]Q4[V?:'wۥu)drn&j,v|լ]Z#MԵh~Ѵbi̟,T}/ڪB;ê[V]6!ӏ4N3Q$eq`Wo)F5Лnn;kбlMNQ=w55 ( =,rRj#UyMFf 1{Yoo?>z+F~S7Pü7=x3ϼ23g7yN(= #Z7+1  T4) -Hˤ"iوfiNM}i~9)DMDNjJ~ьҳDgC^9)9FN5*9 "iuNRJ *]!mQRZ< k`?&Қl)O*ٖ"ui!7!mMAG7$hD:ihݰ`P@N+C.eąOaU:-Csz{y"UwhJ=qUM!?^»D,O#YDD\D9j\a5G+Ugonܾ{CxD.hexLU+i }fJ?DhbE4~ ro,Ƽf"P-C;Mѳ?ѤPEq9׫9m ^=Nw! ]PO O&X~\q.f }'> 09$ W"Z!GY~蟝u8h F=+oC_$%m?c`lTr*{nAp f@ᅠtUBܑW8J>x)?s9Ht.1#eN D A#i[lH@5,Rs|bpt2ɂjV@JnD6mb!DA9EJ\TH,tRpm:UL ,&:$fP\DP!n̬=RV) V/]݃r o!D; šG [y:ީ+&x_!UlΓQ.XG D2ԶI2\ܗ=/<7>r{ OX6J.v싗n䖨S9+ȟ0}1כuO2 }-1+,}'Y Ջe)4<WL^8f\._r_NTtW/])AP!)2G4: IM|W't7ʀ 4}K8wOxR!O<cg1Vhi h:qWpkx e' o pAi+RS`=.T`ơt72 S#vIu(F^B?p8#_ qX %w*NN6}E@319X|(B^@v)[ 1hb/hC*aAdM؈ ףmF]]n/pcGds ;ۀ] iA}E⨽]O F^w,{6Z!-l Cc G6)J$X_^Gn8fP=4-!c^IWtF_ Ti-bA4EtFmHg(7.Z!H˂[r#kZ@}^<th?eu œ]DԞ^&.PM q >p5,+Ӥyz %qHt;ݡ`}3>sb!@ x"5C1ZyMmQ! ?P6 w'^5B(Q  'DV)wo^-9(L 1@ﶵψtׇ;Mp%(. !(*)EGuUI` Wg.j P%hv!Ļ ›Ӊx+@p >9尣s;܌@YF|}˅kv-S*cvs:j MX#GZ.[>Yj^tpӺW2\yz92+טi 7yw_74?_s&jR][20դ~?gTC~X_f2ՋucMul`"_5_=Pw[GϿƢ^ڦ2N꓋W{ς_ WS- ~PS=z\3#M2<(6Bl8jA6RN@\\8½Yi?+|=8#qtM?%r`3lX6RC."s9p?*\BNq>z8|V*\0=]Sr\4$\`f>#C8?#=X)wAu`AHxEF"CD 1  5=siB!!a6FL , 2}gĈWL}U}֙_Ͽߞxx/~x|Ru߯k5}ѝi|ѓ>U}U9vdz,oI~dz/T3ȜxN2g35yNd?FWN^5%Ð'9=x?˜N7csC'9F2"T4m~.P4&`9ZJJnX@VeÊ)D>/|VC?"pxy?$l;h)d&޳7Z P b%oՑPm 0L] Ώȴ}i7$,F\YjV/WQ;ΞHݩqA>e(thWIE$uO,.$~@M joNOt-z[=L5|I2SIS4FHvm"U[T 3ufm)-I6HrQz8'n+nFlU4V*.xA[ۊG ).NiU4 $.wjUToĠ#y>Z(ɹ^Rk\?(&d%"W\xP06#"o2'jGմ+t paK=+LP?|愝1+(5ؠcAOʒ zcuJە@XibX\ftB)5obT^ӸIT\lJTYTTЉ]}_S.Ehjz)'e\z=~gvD|V[nil޵r_?`?xWnEVԀZ!%QUԉԎa\4 gY1㺡!,7\'@H ^1ggqKl)̙;}sدvCLPɲ㒢dvuMmR1ǨĈ϶hke~IWv: XgްP&e>r 碭:9SZ+gYN\`݉eiA_0(s',hu)J5iGF<#D.yGk2g3c`Z:w8t@\;AHo.lsGecqj@4j^rp5?рb)9.Kpm\v[WA O1th d])j}7nPGf+3f+ʯV{Zte 6p'1ǃEYpOjXfoFd֯j.Ωzr t5+fc}=5B /s<t5ƀzj-h4X̗ftskjA#* 67&Hj+f#=Wh?ؐQ^}4iAã?CJ}YV5ieZ i= pT햦+\lSXp45Wwơ:z.UБX^4l=ʏ5 F q;~B^G_c2)w]=C_A\$-ݢUn4mݵ/u x{wZҢb܂T9'>5a,"Cd/< &2nTL,*WJIR s@5LR`1[Ĝd$M̋E8!iE dd4XxTێ0}W [miJ< (M"KvWwvs .~S{Μ3gpgUBR g?MYv`Eٿes;[ZSuqޮl`}crsV_:BHh!7BbKaϹPgp9C* 8`û5@z&߿۝,Hl<Xs'!3VdV̪`8'gQ q  quдgVd+YldEI@3%99u^l* b?P^*` MJxUkOF_1=(+nĢ~dˉ~Dk{8mܹ̙sfȗR?s/Tl(26fT8޽_knFf:HTe+YDcS &0TyV*xl1TV]>P g)xe7kߠUA}2$06b(Dpz.~بMύL:hݫ,#pkz;X6s]r(UN_*IYZ5\'6nzNzf><Ï%FfKd}g9LfkJUw^p%kjZhj== ?7'c- UbqhCy Yd*l g[@2ǃs_Ma..Ow7ǩ} tsusqk,w! "ߧwU&žj$̫.KEOkatz/KW8px#tHpZҢb܂T$%k.}-.ΉG9'7g嬉lȨ99QHV2ssqj)&&*$d)$fglb2M`r&$^F̒x Z)I\^fBf SZV"bY&xjHq%lʊ sr5R4A&mbU7XU9''dvueY uP8]̲,8WBd~7+Bq'NLg[yI5諢D 2IWB?f38?sZ.fz[UխEK+0tϩTd^{':{6pmuJe"jeDtKwKT`,4 AAm%Qud`8d. a8GM)_ٷc#8b:heHtA2.PTKY*1n("$,{{a4{mSޖLeZ7IBҭYӆ'j \(HA`oT/֐L'[@۩iа^!S#BbQ~`q#xA=AC9FxSn0=㯘&&4٦G=T]U4=Ue`n#l,KRNü7oތ/e}paX^캺 hu,i]4U •0K0V.Dr)UOHI$[ {i"%O0SBȧ헯;~vOj.M 4#$Uk,x0 ҝ'2␔/ǽ5C<}KdHx)E5 t-sMLϐ;pތ' 7U`1/};\ #M i[!qBD@SNA‡1+dyH1N@ncU[8`^[wcR `H8~|;|AjK1aY fAE%9>P8(Lԭ=Ea&GqR1ra#YK뚹?#шI(Ln*fQ~ُhg_\QK|ս"ZFXZִ YN/.@͆U[Z 2ef,gݲ4'Wq>)9,'ſ⛟ ['mN?'# v}N#N+%HVJ-49nĞB8C%\ PztEЇ_{+8r|P ]ԓ˘6HrBlNjK8S}YjĈ ߑL>.%FԮjA(H#@D+So]t1\`vn2LPTwk 'F)8agB\0U8ٌx ( SN7&בj| X^8&; F|igfgEuoUOn}+WGʯ#'==tAu9zjBx}Sَ0}tQRuI#j4TTBP3َ؆NW /q}.ǽa③Rݜ;ZwT%#vy[K b4zu>7x4͕mJg\մh:hTe5Ƴ.&xr8шQ>9RPX~ !g>Ry_UT,>-p 59P*PjIQ*72Va a?=٦C#DmVàf*]2 PPg`d?)~voWU֔&%(:2?-+RFu5Jg2(#0RX$(Ǔ2&h r)Vp 0K ܊{e"Ra# HsJ3TB݈y-pZ8X 2nuszCc$cd΃"#ڠ|RG-M*_Z>UB4Y$_3YӇip=a87ѭO;usZr RY&JLR9!qQnoW~GX=HВW"I`ᴈIמʇx׃t0PӡCwL|=( FSd0ӫ&Wl8mH ۧMq K,C4G2'VV}ΜB89WT냩9YO/'so|ӁFU]G= Nf0{$b,8Jߔ{1^{l@6%9Dx̗͍5& <i{zhhj/x}Z}e 85bw 71Z1c UiV < p'KoSt.ɵ^ @3"wdF5#*H=li(VBٽb ݁ aPq,aXk~;hTp| _ܦ'4[q l.i5QAVmnd wGCcg1n}wQYojNKS-ZME^%cY55×ҙ(odA*~XNN (OA(;UI#-?>9'8U#-Ev/#d~65QNEE 2/sr=x}nbvBJfQjrI~QBjqB~JR3n3tF=N T Yޤ.0GQo:xBLfQw>Lz>O{~*e%Ce' JCvYBkqZK4 `ۯY63H_PN~vXh4@Q4*V~l/3*Ńt8϶;tOgMO;\lJ1ERFX)0n!Zu.֋ @$_3;i7ƒ~IӅ'Dh=ѧ?\\ao1}4‘qV$Hki֎ !&gn |gO 6ث|dL-Yt=q"hFbu8^ZP Dh j8V9=E{.D{ ,"`DU;,Y.* Bl |'0ƨR09B|}bޢ&d@"S X9/I3Bz)YR9V"*ob4j)^ K .}y0kHr5ܰL²/=+U%b˭h sM'Rl8ԉ#)l5YJ'JeRnOva0c \xYc&Ҥ,P_eO*C`.1/š{`=|t@ΠȽf;F<2|b?enE?]/woHc |ot֬⹻%η>AvsZE݌^-Ϙ==5'QH/|s8XNX^pκs^_֕*+k g_z;nw17":Sg 3ERb @(xNIAkQ цJIKCbXA\oEۉ+@Rh lD)ʳbf) EzӃ0ʷdQ͒,![ IT]nTZ.irYj=R֎Ԫmc$ vQt45۟m~84wnCx,OL U1wAg*bh8~bbߘFMhBuQ 3r/59붙xVmo8L~KijWn%څ.K+^Reؑ@1oZmgfyp LXH@O9X%3+]B댘0\jND"*\q[Щ+nr.E Csey n #` O`}g0)-L$LO)kA_@ JicY,TRa+{@*!z d-! ~ 1j.R 4&(~6,UBOuIܯp1Ng\}k%V[iSMh!Bu.xlR\;ey!q[aq0DnG~p]f\γUh<.cͲ'+ٮ91q)"-eIӯ)tG;wGΎ[k( DF oWL # tԛL?.4I1?1|l3xlu~ 2vmB:/۠O8cޫXΏD֎R&U?;T IHABٺNkǥ1\C -۟P҅F( (-7&z.>Y8gGA 6<4j7q1m=9*j *hWwޗz20[5.,"@\ǃzw' B=zDRNhla#4:(^۪sR_;뒰"d G;VH}i%FÛPR (૪O@gw[LS r){5Go7k@iD *D2g-^MR` k]ȓ7BJXz,Rs}_D0;WNoبRc!$A0#N6JNU[P>n󥖄 =W1ʌhwXV,wRF7$FKqzGI{Kw:>C %_ B3oGqLn }C+:@#|a=G_ }An -qZI$Q8oM`'dtt0Eoڑj vڸJ1\T[h#lvA\MFֵg]+".,;C%m_k9nzZ/q ~F &bܱw(I4<`d 8Z$kKI­#ë ծ-tv%&e#h|# ntզN뚭߯Qr &tU@a2 tOa8 {6Ax%Y&n j_8UE ǓK@ѥ(~0aGd[xg #qoͿ0G`;.{dzcc~>uXsg#-י)1TMlRx+5Gj +J 1fxuRMO@xٽF* 4Ę<'lZФlĿ?A{tܯϋRs4yo/jID3JDۋ!N.f<8^&<D.ͥuƹq-3Uap|呶PeBi)a4 L> sXܚ(]l^AY\U?'ӓ,$ 0GIK^v$I `0kALzhr`2\ !Bx8TYimtb=ci=22nxJL҃A9좡QW -՛F삎{t:W YBFl+&xL/JխLMKMMHMζrs󓲬UzZ\\\Xx\NuVӘVIkCx{cɜ,OVxiC HSWRI_ԟ3Y >kwxcCd]?x{wZSCsAx;$[pZSC9o xi HM[Y~B)OW*O`TҲ 6x] 6.GD rd9usJS7<顓q4Uʫ&ʳZ6100644 index.hJo$M4Ш&mxD 7?b8q݆]100644 index.h cL 29vg]R+yRxõkHRϛ4]t!TJcL 3ix{tiBix <ue].SO!ܸÓP vPHx{iBȴBNz\$-ʝ skYxkĿa;gx;8q=6sԴ̼Tx׈W?WԼJM(C.-'1X(\AM`mͶ6jgbIN-/lNJjqd#gQ jL|jEIj^Jj:Ku'б+H,ɈIK/+ňif=Q̼E]컘@NѴLS@64 UqYbebV楤¸%VF`vAbIF|Nj^zIАZbk..R TR(HLIKWH,Q[Y__]R )5$$?d";i@ xi Iן8}ڶ)h(3,UmfawO/QWطC"GxD 7 Q̓k}j(100644 index.he}#+r)Ǡ%ݸD\?xV[oEVJ ]zQRJ/Rbc;vb4miDc{]'M4oPUx'~7 gfήs}efw;/_ =wZY\YH]ު@'KL}G6u'sg׆؟o.iPuN؞ԞMHEn6zı [mx-! hk"A9;|)!`Ym{  s06~a@B^dy=Mdpx[Sft$iγKlr:X 8el2;7=¾.e AD*Ϩ3P=uϰPuQb=e I.Xt|gnC~:{Y`.l^n$qy[f-JBẼ ݑ}%6k[ajM7}Oߟesw5 j|5=(L-%䐶C\BΘ7 OZm=5&|[ !/0LbM~]ZF'IOTFήi&&iI&Il?`&q $r "J$vk(\ 9L3$ЍREz¦YoWGrmk$8߇de^]Q?PVt<1w2߽sF_^ 7q=1R)q'Un¯ SLt.cc5n$lzd; (ȆgU*v`.i,|O [znvDq _I%%o%V ^Y C]fM:DED~1DUq }'M'=>2P#M iG~[t>BǶ?LbthHeѫ ʯwx5|"u}Uqk8žO;ٌjNG|t@ggFq==Zf4;Ĕ|5=pW~zcɌ*0ſS?+ſys*^TjiޡddEľvHzNx! >p*d6uE>UWnkx#:Mt VY* x\O0[i!Q Dx! W(O۾ADɻFS>"FBax#Kp†70aa|o;uL xiC ê+݊38^[2 x340031QKI`XTdkgM]+溾L \x#OpBHn~RVjrI~f^Jj60aa|o;uLVx <cN"25w}IP &$ 3xS$q3 57I$'&gL~ ooPXTPRL-VTRpT+MJ-ROSH+)L-I0I Nﴤ-7yXIFBQ~~ t?Һ "rosp2+((L~a 7hݹG_,4xc7L7ofȮ 9~xiC HSWRI_ԟ3Y >)xi )7dV (G YTx! @mKFͲjTx{6bC$d~=55,; e7KTM*9YG^{, ,7DAer ?iEe/):o>i%Y'gm^oe#dxxi H& iR+uL`T LTx` :dHBdK(bi100644 filelock.hw9rfW @mKFͲD (x{.=Yj +Oy% řU% %9y% %E@gHwkD_5'TSAbIT5dC6+4 ̒Ԋb  )I PFt 6yl9ٺv`Ey9:`t-9SIbK`&ocCrPdvEPfȇm9$0 :gA\ S&+(OQd!$N8ws '3]\ FMNNƳPd,4y2T<nޫ7xi  L,zel)9Fկ 0?xD 7 cK44A_(100644 index.hCjRi9LO扳%&2x[1oCdEq~]wϐx_Lj=L98'_ݼÛq dK.\ ' l{=xɻtAͬuti&TjU($(xFĻE{FjZsMULS(յR 9Ȧ$d BIK/ɉ$$VV b-̠͌`MWbۜ2b%ڒRj{:(hZOvT)5Zf^JjҼ^QrhTOvҐ'`N]R̗I}fh) O YU,RJ36+cYrxu:100644 tree.hS*/F[=6A]c1ZkHx47i,hN _BFx"shG^FRSYB"9k x;ŵ}+m,Gs2xURPVXT2SV̌O,.KH,Ѵ޼IӵWU0#ɇis 'f H)QxmRJ0Qqa}8ڲ1/! :vmј6NJ >d.uI};''8Fe\ʩy)i\YcxiC RaW++9[{ݓ+v " wxV ȃ2;-8%E듿[[;z:jgP4~<]FNBq?[if&h8T-i"k~x˵!qr8^LZ'/e`WRɎ,ee2eeX&۱|賊D&N|Eur=+xi I֪.t1SGI P(I-.)fӚw΍g~۟V<|3hxw 8^şb100644 commit.hREpù[ZHEz3x(7)?1eXuf^ͳB.߆ҳd~%13ݟ4@%4%1/xR_kPu)M̶de6AX*J){(IRl~U؋m~ |o`n2<=sON{}zG?#w`:PIyxJkD eMvd7N=xQ񮰸"R>+<@'|Ҭ;R^T_"f(Ξ xx)|d7@5c'Bc&8q 3Q>Ť?͖:+oW.S7]Q  Y]Z-kqU&%-?1"d0'{ˤ:7b^UAgP zlSjx m}]æk&.:c?3^,J(Vo;^gS)KjKBOI jxi _-'(=sr" <x~ 8n0Âe@K+ CGkf'100644 commit.hP5rCyD+$ SIſ E%Ɏ+JKM?hc#+KޓF)J<y=7\x[:uBBN~bBIQjBf^IBr~nnfB~RVjrXao~<*x*{Bd,'3MˬVXT2Yʼnlr;2 -WSUX4Q^]ZV BA(M/QXAcY(+LKMQ(H,*NM2+< Ҽ̼Ԣ̼t ْԜJ b+#3kZkɅXgNgTQl-$w($g$)h%Mgf+)OȜ&;!lf zs?)+hi,M/QYsqNca,+LKMQ(H,*NM2T(NM̓K2JRRK2a%)9PǙB>!/x}{' sf^d^w9dT%xS;oA Ư6G&qL'[FtVEHɱa3hݕ4HtQPP/P× }+{nT /g?? g6Q0Z*ѵ[yeF_9s2TM驏$OK.iaLҘؕ1[հNekaFzs/2/L"͉je(TJ'\f1+JT0 נMP](XGmRK,cOqzso,ϋۢ{DH>20S*Y[oz-ݝ̬W;`;xM+ҒqR|e{_mʈ3$ak9`LqO%,IKc;3w*38{Jq{-U,1ٶrx.8Gӓ'ZOXB0̗;"E~*OGsLX4ЮNO(J5!fuMT~ ]:BV&oEP!f/ze^5nD)Qj3INjS|V1N%vq22߄{ x۠Nu>ĒdҤTĊĔ"[=3Sk..ɏYJ3RS2J8sSs *5Ԋt2St2St3R445E%Ey \\y'GqMQk6 MYAK"#}d454r3A*h+j*h;VsG#gHkPesk(x;}(L xi Bwo{9h3KBIjqI1ÆEmeM\ɳ'j xR |S%?1f屓W’.qB[TN,]õ:5L[r⓪'xXoEW&q\jv$'!v:R5MiJӖD+';[]w-me  bzCj蹪Pg9P$=!ݙG=8y>y_mї{ z+G E7@ ^YKgG*$~Qk &(ΝKilZяc裱iX6HDn8觱O),]\zo[B-+͊т LU3<) dL]7u C7h&Ӆ"xQ3 )x, *GG&DeW߼ kaDLVB*W7VɄ -, 9z8}梲~bM9~CDMv {0W,Oh@m8Fi)\0GAheZe&Z룄m5, wңx#-89t,ᖙ.,!Rh&@p1~f'z**qOWEK';p4ipq h*0Tj\'J2Vݨ֫jMuV6 j F_ELPmf$5*uG V :s^~gПѩm$l B _.1"X!ћ -a^j$36bL?ڸTlRY׬͚Knܰ|lVW~.Q4M3JĿт^%WH ܖ!dhDݍ\WDmk&aω)btY~E-?zGO?Q•<(C\qq1 kb*u(W%fAIuZS$;~7NKaH'^NŜ-aOvnv u# Z(Q)lۙ'.gYt}k8l.4:F(uPf. d$syA̅]dY]U;)Υ:F[3/b{!ӀϺMԤebKaqHYyx [edO 1~ȌL c;EJPO鷤ތ;R,%:m8IS^n?q.,vkLh9ޘ0ⲼJp)a%dworȅЫtYϚϳcFX?ȇ㐅 x+u#-YuzRE͚ڰg,jGT=&X@99@X=vc 3jMsӇq7=[8 I^(l=] ΌxVKo[EVq27v_ıqbשD!8H44I[%&Ir#׵ RJ btS! ]R3WP\!Xxn:O"&4=sv)?Y`@[Y-VKFJTk4d" x%hoO>?Df[wnGⅨGwrتxwnGx-Ün 55U[w`k\f^Yxqldz|-໶d;LqIMrO.a)h,^ 9ؓaZƉ&a[GzU}C{$&A j+uT?R/xUwo.I3^}Sa{*F;XF)X}g[+z9eԇa f KrgGā38nJ?x;x7Q? *f`yQ!P #5HD{>B?]8[k'vtx<_*h%&GQ_q{\"5S$5^D?r=G+#OlUF3cRqKӡ1 tE#t- ^#KVR^Jqx8݇jhF— oi-, /YXG;6 kVDMZD&mjԒDAmXg|yJd(zST-P۳ _6vwV#SA^xsoŢ7N_׋V'"S27lj$n-ؗ9RtS}+RjEpќMJvcH&1[J{1 ooxA]14--hn$d9͌-xra6u,X6'p*3j)xed&dV*$('e&(ho-5y43{RؑMrx;4ID!9?77D/A*|W!G&4q"Z7Qd5FigxUoH~Ũ} {(SI%d-޵$~3c5Uu13|߃>L}K)=R`*RʺR*M Ur 'WXR Nb\jY V.S,T$<*#BAl*czFx6  " Ѐl| "m3lR`teɯQԔIrڕTB99ҏl@b&9xofKq EimuccƦ"X=X<3 mPUCǡ؀(@h񸐑cHEEóAE >E8crtJ 8f)&&eܒ/2!˦gJ=eNMA Gr|VY;"2&Le^Oȭ|+ *+v̇?O׷dr/, 0dd zu")[׫UK'Tf[?-bHDLVqy1AX`lL_PyV.]=㮒EjƓ2G mڲ=,3h繨&o>~;:Z=_܈#Gux(tc$O< %.̼ҔTf~V~ͳ؎12*LNaϙ\ñtYLx}JA9"v2I "D Iawm5{;ޜA<=`%1r |??FcRj$4 Ksj,aa Oю [gv8b5(Ŭh{ɮ%Z4U;g?f }SC ew/fu#B]?O1ɧ_9d ^y٨+#m"9 QH=2!QJ!Od>qw9!A姌0ZN)N١5^J HnHtʶ[yʃBy5F4"5;|~ep.3ձ/ͼ9H.KP~N1#Ubxi H@~=A.(,g>9Q׳ KxuSru3 YpawÊ?zijPxHuɭ/zaJZ6C3dKk_6I]?*`a`ST5 e7+1vU|p'n5-o&}c/tstNA ^wMfyrLFW8Ti#)/J-OJM9ûyɘ^詒`ux BYybN6Цi7m|qdm')`~众j5ϊ35kwM U M/6Dz"zzy:lr_Zɉ,!8NY(SSb$҉/o'ǰ*XBxx;ySru3 8[/|GՂGfmT]x^|:xd %40000 block-sha1(oZxHrYԲn)%6l)r:W8low^KLO*6ʜ5j Y  s)lxsg;f>'&vqxSP^ ~.| sCAd4GZ3z4TSi<740000 testsDz|'IEa>O$nxx;~B}tfF3 +x [Pq2%{JEДo7k*xó d6 ?x}c̦Z;}fЈ mx}j%l\lɳuC^|Mx"_dC(Dv2 ){8nɲv ^Bx <.ۉ|ѿŠ4hOP po;x;sHyдNi%YiOx340031Q(H4Kfx0K_~`ymg Td0^ˢz?D~{x;i3ͯ7g*8yKL~ lx;̺uC>F'ftN,pw$j{ep&d#x\)iy p5)%{$ny9`.(bxºulcsH'gRNv<å0ُIarYLRn73xi HГL^Q*>T ڟ19Qݵ >mxRJ1xZ칶 (/ZD5uk"lED3n%afޛ^O{6۫XgEdyph,chS0"fX\Ewk@ $*IM]nbTRv.D +7e!z2я0ȂG̑jX{2EZp\N׍s+PbyajFoUĆ7c1q:mZ49I>T8wNH&%p ,x$d}*5!>[eWSo1[N9󼈵c2bT@ qNAګObCo.v&s~C!txk,g,͓sYO`˛\Ŗ5[UcsHB5'cYi $EtD<$,άJ/Q6Ck-6H!'xSLKIMSs uq/H4ψRfbJp)g)@$S4= 52sJSR A2Ss`h/H+.i˰*NE62)'?9[d(y)i\PZA_ é Z\~EA[xi ȁ:)<0 X-FҖ x340031Q(H4Kfbc$7^95C$ j|huϳ<lcxks.11!C x|H Ѕt7dh#.x-'&3 o src/*/*.o0 jxi jNU<[~| P(I-.)f0vz0k_MB|\w.*ax;ys+FWY/~S|k? ͒0tx[);OvInjnrAF~iBqIBgHKkDp=jr=|ax96&tJEkn8ߏ";JgH:Y:Ӑ^cPxkhrf^rNiJMqIJNfF,E/1nbd\0"l&!Fx[i4hF%̙y%3nb<9483=/5E!9#Hs2'%F͏YDxi [)gx+o%&o#% P(I-.)fϺg;e{D~xR aȔF(]nc᱓{lln'n6GY7^8*mǐhZ䱍1n ,&ax9  6mok9S;pQ04:c} e;^jjGx9 ρF:RmNʧIђa҄;mD3nz^jDxra6u,X6'pT@o0x[Zudm6Al1<6uxQqC J]&}+ u8bـ1қ@ sxb=CDP{ c0UPm-100644 t0403-lists.czBZM%X|a<uZOuK*y2l~Ѐm )qxJ=v=]|FXd|Mq100644 t0403-lists.cqATU'>U1 s=-LjxX{M}܂J.%%.. W(JKUHO,JJLOVX_!(?;5O!5/%'3/XpYo0$de702-**-(IMlylrHNPeU>y/+'6c )0+`aԟ¦ ųD$#X $_ ؞K_ z<6Fr@:e$gBQi,J+&!m-:x$^n7cxµ!qr8^L \ @0ّq,,f;oF Irx#JhC9Z&# m8y+6LOVe&cLj&eQݼ ucxi ɭw,-wBC P(I-.)fTɾRSw%yx Ixi ~5Nx@ɹc-x;ysȩ'%.l6e񮼪qYMlxra6u,1&^6+x[P{-ɷ/9h5 Yx <|yn 0OP lx[:Muh&Wxi ?٘(so7oԯKex;ysH'?I.5ӚM}ss# x[We.jQjIiQFi^qfz^jBf^ff]f5W-䍬›XOpm`c F%xi ɋm _d&Z-)JRKT;/^>3g^gL6Ix < s:˹cd3%'P q.xiC ȝGY6bF=j/x J@%\; ؘ!)Gݓx!Oֱ2bxxs|}/=,glmx͵i S.3kxi H2{krkcU߹:9Q5 o x;|yC>#sf^bH.^l2xi H=mWnUΝ;9Q Px;ys9Jg|Ӻ992UxrNe>ĒY6bQc.ٝ]./<8*UAK!7"*%>-1$Țkf>|fe/fxi /!C6q?x,~,Mmrγ Hx;ysȔmqq,9֊;gyʤiss# 4x;GekYC97s;3Axۣ[e VĤTM46`uy $:xi Iz2wocq[qj~O~BIjqI1̶[_NTjոju_7;ZIxi +۪ |2zm<>X339Q) p,xiC HjBK'z&Kzo8(xi H@Wrz+=R>9Q܌ )x;ysBŽv*5ܳKKl:Br~nnf^C+igf hTH|vcF=F^n{,]Md}p(.4/XyLPcRRA&_}.q֒K78#'d%3li2˟gf?DS 9#U!:lUL>_`x;yss±T?\8mś}g+640031Q(J-OJM.`iأwOZM.e9z Go=ZyW110e-ux;ysB/B_=4El~_+@wBr~nnf^Ë GtF=إ™bjyPL* ?_ݜ6P|%j|'\' Exd 8F#O ID 100644 commit.hv)s"W<ᱷ3~RԫLH9jԠ6\U100644 revwalk.h)ςAL{dмؓSI*xR R3B@l1sZu/;i^Kl06o+s^8*mǐhZ䱍1n ]'6~xm 2,7Kev xi H=C7ˉґHT8k=9Q h]x;ys~Ko/ynss#˿ ~xm 2,7}ga1&R-85&fMt]N?=$>?)+>9'8UC-9?7"iYZRZ`dOͩǤkkrd#͉"[y}:,5xۭFe&]+9o8\Axx_qs\ 6 \E%Ey !N^AA!.s8jX2e5 ixi )JN"mN}Ny?9Qӯ xi Hmo(7/7tr ^xUk[UgbӞ$Ms6fI]ՎRSA&~HN6d洽%ɽKnT*{n{r}0}EWpo~Ͻ!>~?g:}oODۢG7FC3iB;L^!^?BcWOA=P&JhOHV1K 3u,#[-,oe1v2J5oR)+Z LՉ.ZƗHMN;gQI}R< ]9H3~hoJT*_/Fpf\bD:[߮R R`]`v֬BXPtj C:!zk4!%dnmt8WuXcrEx3l%`Z\ ]mAgܔwgY[;T~Yst~DnѴ.0阥Qk'qo @%>@7~c@ [ʜWog!.j]C*WfikѣS0p&7fb!SoZf,fa7"(ضK9BR˳a[Z1n~rY~%٣ߋl/Gx64ƢΣB/~LN\9THw / SH2,ܙm1L3x&Ht,;KY~ffvFKq5NF} /xK~+;KY~fd;&q1)hLȥȯ``YZRZ79dN}NkZ..9\\959'ksB沜GpB.'df Tl>#,@#8)Nܜ)4rx9  fVvSո_n|0[0ru#5#FBc7KxI=[ T7}(|af?100644 t0403-lists.cL_y۾nKS Z Xx[ž}C9g_<Cg<++ͪy #K -x Oֱ2bxxs|}/ cV x <+sZ37דP kx9 Akm+L=1b]GL|0[0ru#5#FB)xk,YӊJ&q&xi E'^yj ם } 4x9 S^@nwM Vm&|0[0ru#5#FB<Axs'XUYR+J6Xɱb4#kZQ~^fymP*4x .>"㱓5)fx[}C=%x[4Ii*ɏ'e瘼K~ 'rlbxi ɹywOvr6n8fT )&@PZ\RΜgs+)sxE9:&Ix <"5<8P N"x[}C=װ`O_ɎғXJ%١r1n^WkKxSi 3W-o,x;˵sjvԼ4.-,ox;Bn["4ld98^2韛(3H]~@׳7wyt!\Ix <`{X6OoHpP )kx[ȾaLOf xi A.KIMRMaFo,4 nSx;ysBR)'9l춟2`r040031QH,`hq -e]޷{yLܺq1#w|=.x&V2y>5假u,  c$jlQjY~RVj2侅U:Q? [l+BYybN^2"ݕ;GS.SK߳nXf?_ _x;ysBx{ﮛΊ+w_lnqvzk&!ʿ V/y{BQjY~RVjr^C߱iKrJg-d{_3BYybN^2&/z-y;i&C4E "s?r^Zkҩ,_j?Hxxcd"BMBA~~]J"x6rmdgm[[x˵!K95/%3 ,xi [B^4nlsz39Q x`hCK\o&o,#amxEqC>BFi^qfz^jBf^ff|V#n Ox>}dfN..Լ4.2>x[)UjɿYM~PzF6 D&HL~qŬ(?ؚKl[];0O/#51,[\%5#]r~nnf&D1qPԊddo޵ y%'siM⚼KR (5Rʇ`3$d[kUi yy%E%y QRo6x|iBć"\Z%E%Erj%f8ZE@&g祦('dg[$ ?'?=391'8Кv.F+$jx;ƴi"̒ԢĒ"k. H,OR9% +.x <sP{Wh5𺮇P 6N x;cBE[ȋWr{“($fe0,8սaVǠe[nn(e+jmo޽sd'ܦ*|e0c5cZ #{~fBfdF&EޢԲ-YɖK95/%3 yl>x*NjCrl&rx <j Rji#P e&x`4W{ VkX󬹸 9?77D.-'1XV3$Hyxqgd*h$k*TuTH׎1 ،x!j蒓,8f[zfI<Ģx73SJ&o: fN>(&̮Q* fO`&s)N%W2+3MA,`k RKJ(քTr֘*R+@ C!`258̰#r * S#%P=d/y !kf x;u}BrrJjZf^gH/ vuS CM.,<<]\bUPd91Qdr# Z%e%@bZy%&>|1Qk`&;f1JdhgCtd(hM^"">D]xT/@dH MC^ ]]V6wr NGEC}{߼ޛ^]'%qMߒ:\)pЋa<5eGk'?zcjpAPkYxsI1!'SU*TZn97Yf6li U#Љ nswq#N$O[VlCԈ'Dj5M1hmuuIʈ1X}<UnJls_{G~ y[*k!?N-L@6;i?x;ƴi¡dLxi ƽ3u{fn OSxD$100644 commit.h'7d*jJDiJh $N~`V3hLViLxi H$y\-5J x;cB/ ʢ2ezucEmBk540031QH,`.H>J/~ok*w6nbr(OKf?_ӄS`mӴs}{h|QZV`߸աuA qQgשN>-5 Xx=C{'d/VsXC@_ D)h)yFZ)&e+&gT*d*$0M! @1l===j}.̜T 1FNnW+ѵK,)Q047s?cKkr0sB\>knx;>}?d6^x[#3MdSVɷ9'sLƦ89#tr5BBq~QXqBNfqBRbqjB~BybNB~QJjQf^:Fni֢ɂ|b:ꁆx%deegp)AfFA~~]&XA~_&XL@zfIQA|Qjqj X5\(( "XR+Jl &{pKOn*O>gO0xi )il6.^򶪓җ59Qș  x;cBE!K;ʺSN}׾D?JC3 ˾yc,UJXx;|vcFc1lYϘgnNzS(̹dκ#;FWY/~S|k? ɒ9z j?G:%OV=jmQjXQޗ7,T_u斖}3.MFx!ѭdMmu2;d|.0x]8A"@#0y100644 commit.hۚOO0{ 49Ԗ3rV۬z4Yhۿ|+kxC8پ??--%Y!j100644 commit.hM;_Z!9=ӐtQxcBEKSt˃3!'sfMch``fbYP骣kYg存_qD&i]ܟrqtӬݓPEe9@oV{WzsueJ&72d 9sxݤa;d.*iLeSťZ !.V  i % % 9E) ɉ@) y y΢Բhq PB~BN~bJf^PwZQ~.ش$}.0h ͺv)I: 'Ot|Kkwp Ʌ+Oϩ0;*7nb̧y-k61gJk0x;m? ixD$100644 commit.hY۫cыaop֍ŗw$N~`V3hL8hxscC U~viBBr~nnfBZQ~.WZYPPXTT2y5Y3Mvg< sx&/adgɇl<#|]@@K!4 85E!9?77D!?)+5^!<#(U!%_$#8$Vk钯P [ R W34!MeYONgfKNamv8migx;ƴi6x0]]3@0xkR&u? !.V  % y % y%`Բg!x;e“Ōno03rp)dq{l'x-\lXN(Qx{.s< %.̼ҔT%Xf H+9?D!=$>?3EA Āgh x Zɚ\\E%Ey jɺv)\\5#q _xƽaK}QjYybN^WzfI<_''k$SR48Q+*s!3R4R\i `'gQjIiQ_u8'H\hBJP1T$lUUqNZQj`7<&jtJjxrqBrf^rNiJMqIJNf^dFɯU i/x;θqB:Okaxi ɦ D+=#JRK9rVrU|=]Eaf;g<Hxi b>5iO{Dޭͳ?+<9Q Nl>x&M~nͿYs)PTx~mBHKٛ%L>"MtvɢO#gxeC9 ZOxi H&tP mkuor Fx&?]~nͿY/21rN9?G+#2y8\` "^Y Ǘw/gQjIiQ5W-ԝkx;~eAj.̒k.]byřy) Eũ)V:\3J0rp)dq@ xm1 0_hWЈ:JKMI'boRl xٴCK2(s.!(%D?`b6a..5A4j.fLf ]bix|ʁ7~Abx;xq:qNb+#3kZk..Լ4.k xD$100644 commit.h%r=-]S:$N~`V3hLNu)xi ɜWfUMyIbf;,M @$-g(W5ZfnvsKx340031QH,``Wz- '[m4D~;X@դs{Dwg3cP5)I@;Rb4w[^>XLAf P?BKX$h]+t޳u2TAQjYybN6PQu x ҒTDE>ϽěR;7*r2A.:}IC6Fi 7ϖhrxS#oIЄ'.|4sV>rIϏjG40000 tests"g]Ac;"K㡘V%%xuJ@IQt#^ji)խZ[,Vک 3efߢ] .ĭ/qέ/ 'M͙9w-?ʡ݆B&,A@k@h:7peb.'2BtqA-Pȭ8 zJ\nc4P׀IP% *b&㈊pHA1ySGiW?cZKOS[ jΨVJ EDcNYfma')X~`kVR4ECj=υ<ވE1z3K˰^2)%"ՌO+P?%_D x֣:os4 #kDHc{9LL *`'X4y`x'XbSR= 8!A ڶ Ez0INtI  R7858I9ٺ 3L&;Y=Ry'0jmVee ެk=~G,xQ}!EK_n!첓'Kl¾ .x{YeH?L3CGexz%40000 block-sha1:>d"FlIo %xKup;D; 1fлOJ{7X>e<M5*^ 3 x340031Q(H4Kfbc$7^95C$ ;R'YwM=3^0ˆqx340031Q(H4Kfx%v-.̫%ŗy7?"`8+ef͸T Y/A\ݷ.93f m.x ' xSLKIMSs uq/H4ψRfbJp)gt8{8r)+d%甦*($e(q)"K&'g낤dqAi}- up1lxvmHVI#KgM\vsׅA {0x"OdC(D8Z.lx'!e icxi ;eVX){nBk .xB5W{Z[qf"100644 odb.h/ [ BPzێ2Fpg0YTdz\}?ige\p0{zy<\;'8d楗#RLfl|;G0eH(i5Ϲ.Mql$[W8NsEH 298mUM+` 2S&HhD~r8׽S/0\AA2mi2vZZI0'dTI<)9;ƗAh2k?~=$(51E$3",zΠ$#I'E ;kt5i{  +ˬ``XTaobOfJN/)2hUR_r|s]#`p*X#TQ,{I_C(36b8ZyJ{C +d8dyxk5\u.[ˠ@BRqڎIZ_3ZR$Z@^ˇ[Z4SSN 3|v40000 tests@pW|/BʺL1ϵxO,LO./)J,KHLJ,1+HD.^zrJ"Se\ixvImC:fFLzUx'x^uBhFF׈ xg7GsxT4 N^o0֧)8{8rqB$m 3 Q@Z/h| 0t¬N)NbRN~rYlrlP6^07_AMc #xM8 cFdaKV<100644 common.h:k?`'aS2SI\[]R}5樂[40000 gitA>ZR(FD٭ lodb.c,-| }kqo?ThjI*)[XbÓZ @Il?x['Vff]fFn5bx340031QH,`>sj׭]&?ԢbyNvw(nQlq &?% bQJ̔\n 2)L*|Ao!{[]YmH*(J-+O*zʩ8>kWJ'f^trҒTDE>ϽěR;7*r2A.:}IC6Fi 72CmjJx(tKhm< %.̼ҔTf~\f5_n;x%tc$" l-w& xQJ@k}"(ت$z)T'!lmfCvS->94b,ܝ#J‹v)y{ȳ Qg%$/y1AkO&{zÑ*! ۶sN?vZ^`>9?~@T%tVrftn7`.w  $Gt UFZ7vJ &,xC<"gاxHIS7̞u[iAB)S#`@Eo̢ ̂miIoڭ,!c&p"2 e|/yYndx[#FnFFwy*oyx١!)3os2;*- x|a ;BzfI|QjYA|bIIe'/س9s)f.SɎ xlgDR OI 59F`w stss3'_|E&^29ADf7x{VjCf~`{ӹ3KSR6 J.xSMo1UCpʥTKq)H/5l֪^ަ{+~?'iZ{ޛ7oӴaF)_fa.v€C|pjZ* l[**#AƒNѠV)&{t^YG %W%LﳠJ-u `R!%Wy=(&FT!Lc2Z*'F%&a=IPCT5U&0W!K`ẻ/g77l&5Fۊi%\NQ[EM-{#vɅfcLAZekvpKLBFQnVSw9b"T8t|;or4`lVb54US~?d\:%{'grit#tTz.GxK.E#*9aBM1Azǃh-~xېCu޸߹,1: 'ZB.(S0HYE55 m)1hq2f]+qѼ42^Bs8uv{y |Х0w7*#t_eԱu1.Qsx[j yٶrznS&ՕD؝^|mj٪Z#x/>Y|]YDS23sJSR6Nd" , /x,>A|C;W~~BzfI,N UVαW(QPZ"~%H<#3%M\u/Ν TsMU9iex w$lk8x;sg*d56eGgexvmG!k/iYMrvm5]?}у]&0Zۋbڻ2C5t'"gh``fbPb`h`URYmsx$̂iUW9O<]5MN-AN׺O.T1c9/Ts>{wm@1%9E@34dj, ׬HhT&)1KmS̚/']a[89Iz ?w/˙Bcu~ P}lx"Gd?b&[x[ihF%̙y%3nb<9483=/5E!9#Hs3'(rvx["4ChB䇌v,:J8}}=C4u&s1*|Jr|kGw`]㘸'g1O1bhfhdl9y;+j-x;̱cƨNgxWjF%lZ؁] qشl'^HY;SvP7aҀ*{F6ƕMЇ},PhoC:#empjA{Νs^ɯ_i凲r!°hZ}Li::\)ht.|6GaB#;G XH?`u' wj}~v+@KCx*TȐE=a|4BAIJFcy_Dy]be h=-)b2|sCƥ.1j@6,23aY nbƝћ@ ];ȄToMd]XƏ2jcTI3Dnv I1Jjhf"7eaWa#vRf0Q5@Y{߷ m Qg*ωT :2ҳItE1eXkCXSތ:laӶ?eQ"˰3HN[I}GX]L+u g[lF~8hd t񤏹.s0Oܑ#}NrT9 }LqkP"ndQ/ޤurEG3Wr{g3ZmDm?%6A=>$)eڃHCk{&P?RIrȟ{'<'g6+3ڕCJĪvQ듣czVFE."g35|% -WCԨT,l P'9Y=H6 d= ,$jDW3[֢۞ZM6GG$Ţc)lBxuVfF;xQK0_|id]7yn0t2A|PHi56H>_sYک/ ؞Ϸ4*.ej<< ǣ蒐B%S T!S/F9D+H,) Zj,* +'lu+HqO5 eP`}S[ \n7YsXPд!Z1T٩UMg ~x_&SܐkǪnnr\׌^7˝ר<MIЇ8iv:q+qA ./x340031Q(H4Kfhz)dEW3UyQe"t }{Wݟ@!jcAxWmsH_sIF K*vL_(I h.B1o^wCMLOw;wG O0>qr'Dõ.|p1CWA?< `n*5; 2*w0`,p8,ES/U.CbMX^.\\zxud0dI"N"1Y$܅E \WX1wab[0hԽн n, ac8"kAr cKWN!#q'"}$f֋.b. iT[4/] vv`ÈOy H>ք!t}5@$ݝ'/Vpѐ-|C:!~ 9XCL3|*Yc͔9^A`ۍ6ntka>َ4t$iF}Uh{zJOO~@0rBD 'ίK1G8=|2YY w[i[}^RriHz!rr_HS1Kr v]J4m.X}d'fjEx _R!B⒇,V"@uԚ eRuOQU XEkr P!٣L#9WHZb7cگp#B CEhQQS)'#K\YRɑt@ OB!&ixğH/z4<2{س"A|?t[#m4βɱ׮qHI6GK4W|<ta W G9bD!9\\88]3G+`}Iүq;4!T 6ʬMG 6 Y + BL _H'tP6꣚mT5u}茂hsɪQgy pSE옾oQr_,!ܸ%F.5N,u\6i$u-i&u|Mr%v8>iI9rܞ|(2C@;hѿQ=|:;އئEr6,8 3Ɏ"ךxKj) 1q*I"6RҡㄸӾW dPщT F):< #dJL0*ʄCN1f(YX ^gLJ9Ĕxjkae۟/xAoP\nH>kr3RRAn״Y~n=KڋX&^UMz*Gz%^^Էra=ԏM؃z`J-m,6 G6!r,Xn̲,O1,e>sԨKgUBƵR]xHB|Qs9UPIl6B]>% QNQ,3c~,U_$tkXzDS|#v-׆a|410ӄ>1R~@G^oRtҵzV:έanv ऍyD5YԙKw*}ff[2E+lu/88Rc9Zf҄FiDjP!_̽,+軲}a'v[3>먘kgQ쨄[U~u+OXT& 53rL=J]P%J`U *ts7쟜q gc0m_z3.GMSGfoK\|j9g:XADTv % eN.+ɜfRWt *7A.]HiM;Q)<oE _?ّN`n23g?)8A_4 wro`m%2?=FpݢKPGaɌrNv16qmbjhqي`:zi"Rf]ә.qMd p Lm@l~?682R#b[,R[!#X)* Ț,'LBs%r)7V0q=w"Tv"riu۷ILKahQ]|5'@6HBoO//)(O,2_}n{gWXg;oz޻DNxDm,fo^v6 xP|E'6ƂMTF+ӆm 3iџVBJ!ғP 5$xaH!<6 ly<ԊݴN1QYC*˥ۤ?y 7J40000 sha1XpDIQ|»N(/PBq("kxx[>}CBfVfxi k0gbfoGcvr; g4x1cC5HaŇ=+\kE[yݙ ox.1;CxSHFQCDPxS"|xi ȶ ,x2Ud摓J Mx1cC5H2+p>pOG2nQһLM ix{ sXJ3J6gm2'1%m` Z0f4ע973es939ri嗖(*kYY;A"_7asaZ*qirqVf`VN.1y8n捽 Qox <:UAm>@YRx;Ly;$&6/f6fݛY7_a9}F  xvmHGoݚq⋪T$׍^|x#CpB5'1mnc4ٞ5Y7_afV F6 CŁk!d] 3 wDUfxi ějV+T#7+6ab %% kj|\gM(qYFƿGOxJ'100644 cc-compat.hfђwi0SDu0']Ŋ z Y&O#ʳ&5 l+xȽ!ycfM&8x[+VzC>䙌E$y8SrGxvmGCJr+GjH>oo 8 llxV!wD_"Zx<<4a\VyO3|u40000 tests ѭۆv]*$xQ{Y.ϲrn!#a>ѻ7b.5 'ƱٕjRbqj|Nj-LZJjNIOKќEL((G},7Y^/9&x93OTtlo#Y(}5;Grm!M^Gcj]x[i4hFWPxxi I" -i)+T٥gb %% o.ݾ)C<獵/vL{jcvxc'100644 cc-compat.hHCpmW)']$#%7چb{1F \ޓddy(r&2Z0z<)lWxya?̚L"dx[+s_zb O#sRtK3R5'Og bOI7 1IkJx/}Rz‡l7y!/xiƨQD_dTr1x 0t=vrD.xV>W$$UG!9#HA $Czs?f 0x7G3i߲Gё^m ̊Vq jdNVP GSkxkgy˼a%Ì.qDx! aGaĕMVm)ˣEaDx340031QH,`>sj׭]&? _!Af[?Oi﮹~ &(Ƽ'|%ӷpWwG@դeּi}Q|BS ;@-.xsL Ӹ7=yT{ԲĜlʏsSvtRiI-܁**(JML--9HETK);ߚ/x3X *'"7۷O>dcV͡| x]4p࣒zh7d(H+;odb.hX2d\ .QR0100644 oid.hր.$% iq㽅Ecq(K|xJ@%Z66QID5 $rֻºvN+//qs1S7r[M:_st9S ?Й&88< $.`U{eR~"):N#jAjʲ@B6el< Hr2N)c 3J$Jyp g>!-'pfJIeURReŶ|͂\mIaLpZ[ݼwdGx*xi fdJ?K)T,9Y8sr/ zxkHwՃqr?J*dC 6}1O1<.`>-`egI|ـ̫q_~ z4+cWkB|B2n"x̔7ٓ vx;n Ly˴CGY 4x';UvSN̼ͯ8W13;A\ur& nuxwoC"c\,+YeKxi f^ՙ.oh"dH8 !xǾ}HnJ~5yKZҿن; &xi t/bWO :L`TQ |x:_ޡgC#IF`MqwsmdjMK:;HH<)l,xkTAk. ]x3ѷ՟BI:JD @pOt J n/<]x{|[yCdG[xX;oxvmH) Lb6WN >WmF/>f Fx!(q$FG>39X(x <3*kCb\P 8x5b yh=8nڋG3`Ѣ^E^ox{zyBɩjxYsqV)9 ZUS2RJRSl 5LaY~fBQjyf6LT$ɇ(x340031QH,KfXbvVϵ[.ݨw -3'5sɱ]gH(7oN׊ g :k R'vx3Q?gd]FIkR2RJRSlzΌ\Ey~+#grN~q*;k;3xi Y''ۈo1YsrA  xr5S@.yʹ|y19]蜽 C 6100644 fileops.hF)EnpX೘f7!F/>f bx!)q$FG>34 zxl;ɄhvcQ";_100644 api.doxygenG3i߲GёE'6ƂMTF+ӆm 34pU{UfUgjKEz40000 testsiM/ ~hlǸA+xa'100644 cc-compat.hVI_^*!{"x[+JfW}--T3̪T<`=-}.Դ̼Tx7Ox7`אx'ϐ`Ɖ뜸+KK2&>132r@2Jl"drM1O>ΨĞ TYI@-x[%LfC#gHFf^nF/t]x{a xvmuM8g>7!D/s+Nk4wV<Ɗmyy/lb!(EO^_0#RKs22O9pk sNV oxV$S`S\Xaǵ/;gQjIiQ֬"%%: E Z%\Փy= YxtKi fYz+xO1>k9xZ[\GV(lp͂]{{#qb#(Υ$sY?!v$GyoOgϼRYL=3c= iyiJsMKGTMaL$4<W%-̈gD}IH4'Ɲ64ԔE5JF sR&s荜>kZէUrDuV!*)](V{ -I\QzNAY~L5R=)x[z;#)Zh%*'wg\FUCZMBG7$(#KR 4l9L܈AJN+E.Y ɞ~q:Z6,򘭫фEظ&e_y/~̖ d-T,",鼘(V#*Ӄ77v_3Z)-)7tֈINSUaBcuΚ'(|K W~ 8g?ۨ(+*.0ir+ $*Bǫy ^)oZqb FzX}X5Odlɓ;7+xd'2kƮPi2x/S$%J}JZ<9c5xJFrPPD7QZaǽg/\|Bt#%ޢ4,|(HHCPy;,VMR|6'( pEʠ:KW 9=ahjD撃!ўq]ُz챦}b֓" FĴ 1v K*x(5oE#G@ %*?gH1*,"U41M@LEWLHHךѐ]SD.O~#I:8 htgrEN'8O14Ѥ a4XC?z.?4{Om8d>…<&N8Bf%AtqhICE$)/=;Iq䋈lqUQ;X%OCKhŶĎF >8K-Bϥ!yjX_l!BQ9T90[dNbmWSP֨{$x/߅;E *#TVnfFA#@*Zzw뉣ߐtS:Җ pNX (w\AfP> ڙdXCGI*GpDʡVpӫ{^ ONP,:Nz7o(2- ۺShu|a&TD٦$wQ8Vt x/TgXhJq31{rNCh>"čT쿏fPYBtT}Q~|J-޺nP6ځa8f6GPc&Єř>qRڹJu >|{ХQ^?h7ʳ 闙M\lM+h8Qqw޽;ypMK nbp&Dkg,j1[X'i@7rA_]'/]o7ل߼K 5>xYW=\&,u˅B?K 8/~~sVCH 1]h='Y8#J G1A/Uy -v /8 `:rv~Dˁ _:p/=]*磇Z JdQ|g#ݷnDNx˪UI@  A1ݫoPqH:1r}% qıswWjQ2h^믿V|}W~ǧO>w;r={|pɜN, HFw\d\94g\,ذ) GFRoE^.R|/bqe=y/Kd1 YT6(a1!,co0TV{ ѦEl"zߪΑSʊl;"[eR%ż8}C[tu|kqβʀO3j,/p`x/ 2-jr` Cdb([4/HFGq9x9(Hkڰ=p!!d(LkD*!)Rb,)Wx, ʐ~D' ۈ! P\ E 3 ]RZE*uQ##&r*Mt3s^=p%#6wxՓk_W:[,2A]*-RY)1svG1x?z- ōQɟ2'!B}mNJ=\+mDzq& E=(3ʣO^L os=Bhy<k? YB9sB$ [[ {;Qi"t C[}>!'m }D-wؘ=qh.3,$7 "4_RpڷALWLYwm)RNJqZȕ' MIfVAZu$HI|1_B7Q_HFҘ/F}Ye$K&͎b q1is oP]l4\ FH[n`蒏2{0,UR%I`apQTTĹ!ZY+({3=O^ORze gzZpKZMU'w:H礭U=7H9* jg$AwՉ-Ȏ7(Dו=D(ixM:*2Eʨji*yz9Raj.'y\%B J:*L6` w59+2\%8p:d~1nP ,گԵw[O26J!iZ5AZA5@LᆧGc*ZK2Jpn%g0zZ( t4tn= 1_ر]<(oAo6EP]YC|OSj=!ݘiCL/b֧@m?yx~9ܺQߩsvTI?_+SfcHV[5X9c UkSM'l6Z'bLzOZK*ة LOa R#`\Re/)3٥n?.ԫ9|Vٛ@ev+(D tk1([JvKȬ54RգՙVOk٬A_(G98FNX]$2N/S/'jr2YvRfej^WroEax+uFrl'XD3Kss6s s Bgxi If7{OIf-b δX BIjqI1[Gze=n sj x:{nU;:~+hxk {q#Dó~@.|cx<4p࣒zh7d(H+odb.hX2d\ .QR0x⳯xV]o6}EbntۓۢR'` J,T\߹8׾ _srvҡZQ IR3+ԘT9oU\{y:=3J 8u*-\tdj+qVN^Z}!UlrRKg. S8OI#&TȮuj l"jhe]BʣPSHLY#{:5a+jvQ>'gK5k+J")>8}~e;h)Ci5|K9%.pRCku%(]@1Tu=8R6> @2g^Ĩm#>ڜQEAq">c|o Mh6Mw=^*Dо0e.w2.t2͌Ft;-z4f>s)w2 ǻ- TJ/Tv+Rie"!4U5?@la 䶵Z7w %GOXf7&7}BBGiaK!ea :gg#ib Z1P7,T$. mS}La~ *.&P -R #c .ֽSJ2?~Η/ъ >Dک5S ?_v  (h6;0;mQmQ'51W89yzHeucm-f&/9ƀ0&m7 G6hzmV&n|9ܫE&dz.;.ӽ&,&iz;W'u*jCNp{јJ6Io39%m! UaM>`tҽGCp> :O`cQL oT}r_ia|}B oA!RÛ&vsp1?C|</f1Ktu߀?41R(+=fW>̀@+šu|C>)7*@6!'ђ?BR`sVf?J]#n@h419S6-eT{bLfCCyd~Y8ڨ 0{׹HYrF%RڤI}Th uV Yѓ ldi O 9?W7#SI/ qDȬ as8t2"-iB3SC?y,3gnJjtF,)p%$fv/Βgbx*{]jC8/ .%xvm?yq? %9+#W xgNx[itX}aa L_xK5fwaw&)^V}0H2VFIZ߮n݊;@1b9"5Y*~gGBF=o$^ǰxO,LO./)J,KHLJ,1+HD. {^lZxTj^/2%x5fxvmHJr~?W\gb`@F/>f5x8ʿir S)SffjMlgzxiC Ⱥֹņ kdnPQ8MQ5}5KK>.IӅhͲʲ1]{˹,?Q͆\4+amZg(~}XC]^Xj%֚Z\("k!S x h+7 ߬npślHr,4Et:n#1Yq}Er!Fe^a_8h}Y*>|$' ?4|خ&+;8n>N{~ybm7ÝhAޣ S_liz6<g9߰HI rՃ٧{ `bD= &E>Fͩk"9sey:"!8zJ ݯ[2S]=x-?]r,*eVpmNgg|Eq[N}QBbAfJ~r1gQnVBqQ>J,13 alQ0vyf頢PZ\R DyEy%)E%E 9y\\%@U`'gs5u tĪVfQ{*!!N^ Pk+꧉Q،UTp  8 4r23'f1A3 lxmHS-rKwt|T,4q &%jx;gBƻ]>mef\n ~= eSxi ȣ*I1YgnNCbr/ #xǾ}Bȕe*J捓h~xk5fwaw&)^V}0H2VFIZ9հ+y[ql3Uö͑4}Ld640000 tests?B@dZv!T+N5IxH'100644 cc-compat.hʢGez<;p޹됑'XԹvV?}" ԩ\+k`x[ucdVgxi {zۻ]IY> 7xJ'100644 cc-compat.hAA݃姹/p.Ŧjȱ']tBS^tjpPp^'H&@RxiC 噎JS]p_ ?x9\\~o)f xRȧbQ&va\2 'Ax;#'us96 ~A!A~8X nxi Eo-ȑ >=-U !x6S}引#|I 6@NRgIQPsx[%3CfsFɴʼd̼Mj.΢ԒҢ<WO4es M.3x340031QH,KfXbvVϵ[.ݨw -3'5~)ޯOO|κmsߓr j3b7H}!s64X:"r(ix{DziD /Fxi HgPB+/O9 ߏ +x{'100644 cc-compat.h2M?YxEW'X2gD>T ,M^aI(G $nlp,p3 9r(z+2k6BMr<1kyx[uu~, PlxG 7=( <ޓtypedef int ssize_t;I cc-compat.h"vO?x;4iBT~J^CN) ֫#d0q$A`xk{ûy4>06561Ts+2r2RSRRӀ<wϐxO?O?WʂTMĒdbf#vOz}--Լ TIJ̜ĤTHf*hAAA ƚ\\ cKsJJ2RR4?Xhi&'qy(gٓq)J`xx;n UJJ|K')xi HԾy37-nfӛ)}c cxJ'100644 cc-compat.hAD٬JC6'T]m'_Z %_/~Uu< +x[uuC'2JNvdZW3^Q1cYrOR/٬ab %% g:Z7*[FOyt5.0xǾ}CtP %$J%0^vz/ol([-T"/.'Övz?kii3ņ5=ci3tEkaDL9҃(@-TnEUg:?3,x`b5gSQ;MF 2.xi IcjnM}W:(%ПKJRKԇ?jX0dg7{fx:=%w\aw}x͚Qlrk}ySeV7Ť _<&z!x$sodb.h󮽿Swv4#&6Zw_xUoE#TuB**Ķ"RBڀB*LwىvgYᇶ9υ#7 !C.H ?S{BěwQڋ5{j?Yp!OSz5:eaEqnK%tЋxjA64!p@ժ'^1Cmךw}}[|ܼ6{nqtknѝh>O߂ Xӟ7-{ny~c@3tקYIAWO^q26Y<o[fYxN/<"-6p'KRūvkNC?L/١ ;Q7;ݠOvw׽br6&Bg$TG%H%(;A 0(Eod(qDA(P+DcyDt{D(Ay=ܳQ`0 fYdO|36ﵐK*@@DG+.|۽!~Gg6eUAzH?zI0&wz ઝL1-+FmV };ARdK9( x;qB Y7۰%gVo^(4d{?'u mxc{:D ϕkT",Nwl8gr4fDgPxreC _xi HՑBl_띷ort DxF_9XP晩BxpK100644 fileops.hVd U-衑 YLy+}&USlKxS}~\l%x!Lz(}lx < ҊCZȭHWP 2x6ܧI+u{',BZ,ipF~Tbr0x!%AQ&(/_/ÎK93/94%U4/$(6Y$X UQIfn*PONfXQf^:XJfQj^ ~ۓ?1U*&($)hsqg(h$$Z+((k) I%`̪>: 9y: A!A.: A@vZBRjzf&Ж4 $3l43S4u ';rM֓4 AgY Z@%\\y a: 0͛Wp<KzMxrOyd)v4̒<wϐ WG1 >1OKQHJMTQ0l$5y" y@ZA h&W5'Ă<u9q7)sxi LmO9nd9<9QQ r&x!(ep'><ưH<sx;qB Y7۰uyEo~xiC &m*z};b"l x9xe4mÙ:69ahB.xZ[\GV(lp͂]{{#qb#(Υ$sY?!v$GyoOgϼRYL=3c= iyiJsMKGTMaL$4<W%-̈gD}IH4'Ɲ64ԔE5JF sR&s荜>kZէUrDuV!*)](V{ -I\QzNAY~L5R=)x[z;#)Zh%*'wg\FUCZMBG7$(#KR 4l9L܈AJN+E.Y ɞ~q:Z6,򘭫фEظ&e_y/~̖ d-T,",鼘(V#*Ӄ77v_3Z)-)7tֈINSUaBcuΚ'(|K W~ 8g?ۨ(+*.0ir+ $*Bǫy ^)oZqb FzX}X5Odlɓ;7+xd'2kƮPi2x/S$%J}JZ<9c5xJFrPPD7QZaǽg/\|Bt#%ޢ4,|(HHCPy;,VMR|6'( pEʠ:KW 9=ahjD撃!ўq]ُz챦}b֓" FĴ 1v K*x(5oE#G@ %*?gH1*,"U41M@LEWLHHךѐ]SD.O~#I:8 htgrEN'8O14Ѥ a4XC?z.?4{Om8d>…<&N8Bf%AtqhICE$)/=;Iq䋈lqUQ;X%OCKhŶĎF >8K-Bϥ!yjX_l!BQ9T90[dNbmWSP֨{$x/߅;E *#TVnfFA#@*Zzw뉣ߐtS:Җ pNX (w\AfP> ڙdXCGI*GpDʡVpӫ{^ ONP,:Nz7o(2- ۺShu|a&TD٦$wQ8Vt x/TgXhJq31{rNCh>"čT쿏fPYBtT}Q~|J-޺nP6ځa8f6GPc&Єř>qRڹJu >|{ХQ^?h7ʳ 闙M\lM+h8Qqw޽;ypMK nbp&Dkg,j1[X'i@7rA_]'/]o7ل߼K 5>xYW=\&,u˅B?K 8/~~sVCH 1]h='Y8#J G1A/Uy -v /8 `:rv~Dˁ _:p/=]*磇Z JdQ|g#ݷnUCNx˪UI@  A1ݫoPqH:1r}% qıswWjQ2h^믿V|}W~ǧO>w;r={|pɜN, HFw\d\94g\,ذ) GFRoE^.R|/bqe=y/Kd1 YT6(a1!,co0TV{ ѦEl"zߪΑSʊl;"[eR%ż8}C[tu|kqβʀO3j,/p`x/ 2-jr` Cdb([4/HFGq9x9(Hkڰ=p!!d(LkD*!)Rb,)Wx, ʐ~D' ۈ! P\ E 3 ]RZE*uQ##&r*Mt3s^=p%#6wxՓk_W:[,2A]*-RY)1svG1x?z- ōQɟ2'!B}mNJ=\+mDzq& E=(3ʣO^L os=Bhy<k? YB9sB$ [[ {;Qi"t C[}>!'m }D-wؘ=qh.3,$7 "4_RpڷALWLYwm)RNJqZȕ' MIfVAZu$HI|1_B7Q_HFҘ/F}Ye$K&͎b q1is oP]l4\ FH[n`蒏2{0,UR%I`apQTTĹ!ZY+({3=O^ORze gzZpKZMU'w:H礭U=7H9* jg$AwՉ-Ȏ7(Dו=D(ixM:*2Eʨji*yz9Raj.'y\%B J:*L6` w59+2\%8p:d~1nP ,گԵw[O26J!iZ5AZA5@LᆧGc*ZK2Jpn%g0zZ( t4tn= 1_ر]<(oAo6EP]YC|OSj=!ݘiCL/b֧@m?yx~9ܺQߩsvTI?_+SfcHV[5X9c UkSM'l6Z'bLzOZK*ة LOa R#`\Re/)3٥n?.ԫ9|Vٛ@ev+(D tk1([JvKȬ54RգՙVOk٬A_(G98FNX]$2N/S/'jr2YvRfej^Wrotxi rλA_ro>z;d#&@PZ\R /ڤݘ|O+7x!򩊈3r}rk+[ᴳ&l+x;*T|C), Ex{uTWykwm_aZCxmJ1D 3q\ nE: ֕! aAM!F}I[*'gV#%,[py4 +}X*`  ֧ˍ,<w`Լi;ơNS9x%ܶ%O LOvNQ< ]%tUxɼyi:G{` 8NJ!2?t #xtmRxԼ->ۭ!uR:.R0!A={߹>_}lxi MvL_YT8F bx8"sX>}[Wm2UgM!& HZ.n&lxu>͗&xx.A])7@/Ci!F!̢Լ ;..4ŔԴ̼ x'O?ǠHM.eLDK95/%3m~ۛŘgL~ksG 3, Bhx{.Dl*#RJfd Fٌ8S{Bx <lH\樸A^,Z{ܔP x9 w9X_VK16?ۼ(܎ / h0-ɜx340031QM,Kf͈)R YfH(c 5x7ʈb$UC;]4Ul @[5O)zsuPIP rqax@[9-lcrypto rm -f src/sha1vScr x|0_ 26iQ+Y R9aPvf.`Co1100644 fileops.h9Yc7- !-?%100644 fileops.h=ەYqpwKxMyrf^rNiJMqe~nnb^D E%%: )k72jHx@yFLxX"Aq FCBr~xiC };o ?aeJ{d{i6O zx{ʺu"&e|@5Ex3V?2 `Z,4hH)x,P{x;#Hn:ɇ7 f=wx{e"FߢĔTd'/tcҸXlB.?XR5];'1Aw$xVo@V+'B0J;JE!Z"@D( ƾb_,HY  V6f6Y'ޒ{ޝܤR|%zqvbJ_79Mg`,HhR′# K5 6@Jç`VK㺐;} @.RlƐ@ygJ-aIx]h0؁ϰw Y ][:VIDc %E Ra4ְDhJ(Bm)!3lN^-RG9q_ȥhܥY$hGGϖ)C-'owZ*IBY9i]^.?~lpc<em< >9ixrSc>=/yS \WGAqWfVӲB5~x;EFL0D-^uY{O/7UQjl9ɛnlʫ8zgyzQanVum-{ۡW|ndIߧI[RpdJ7C?d*Fv$Ȃx$țF?/Wj)>Is;Yk٨0t! Z#6h'q7!!,[XYZѱV^/bK Ė R5!;2'"[eR#E8}ζdj9{UgYev8u7 n⠥ŀZ╌pY-ÕalMT& P\ R|-zAvlsDe5Mdt~.t#Xtbb-_х!h;b\gt#DW E _O`-+T+_O@Q^\vРu2bht_RU W#cWI긚Ճw^ݻy˗7ol!&0XvuJ*SdFVaMKـ.9'/5-FꂋWS!*\yQu@vyj'JE^̡@tVBmJs/.Gqd 4Nfm Q"wԔ+xXmV>Ɲ@y*$Ex؅HMSti & /!m3\y'l0)FDI" VlD N@bj o!o?trɛuRh k}'H? ~m?6> ?et2ZrrGŏ@`:I揙AvO&3~˕2o;_?$P Y틔|2z$O֞[A2A+E<0GuAF 4]AY]"$4InnbG ֥JdO37obL+3 {DR9R^}i>CG9Fp2"T4~.P0&`9ZBJnX@٢2,!*bh|^r6p1vY^p w R{M%+Z P B%΀ZPm 0L] Ϗȴ]i3$,F\YjR/WQۓΖ@ݩqA>tWIE$u,.$~@u JgNtz<m`D%:)5k2W"" @ d^{b<Ь U(Ht(/3ts_@JI),OW4ySzZ&͆bPh4yqj)gF\h6F(6ЊA70MWR-#wKFQp:VkTĹevtW3w{3qϭH%WtGc-W^Chҁ.LA/c׺.ҁRtI{z܀@9)݄琂O;TB`*(2Ӓj"'-yFtRȬ߂ň)m@^.ZJ/R_dkX`C*J B'{\j)%6)栥@`w]sdlqt j2o0VLm~&ɠV%N!=صBVnQ5 M6%s4 &7ZJ\ۀF Y}z t\C.52WjPXXmM#sS/:8Vʓx"ݩVNDW1RB7k#?DzYK!ZSi?TƒE.k>1wΜu?-UӦa 2J7'UIaZ ]%%|Amvʮ(z (Fx(U&ŕPphȮSͮB+$Yf @E2["M Ut3,ܛG*+YDPeњj)둀 :oKɥ MM1gCS~N tkל-^,Fn1M?xi 0ɥ\9M~WŊ P 7xvypm'f5` hZ}95z*+6qf100644 fileops.h7L+wJ-P#j`wo,WEDK-7FC1*x{yYJ2KR&3J+奤)yq)+yy0R:L[)kAx|ydƕ  x <.z5$֦&(ƼP B xjHR} ?*)&4“Al+AQ!RO&N`g47  1#%I)N'X"@2x#UhC& L͓YV;l+xNy!ͧu)fx;˷oC d6m,L6AF|#xi Gܪ v0o[ <9Qs x˶mȗ)OU.{zަAAx|\yC.KY~f*Lp n`|_ ˃ *x7eՄ6GhWc훤[G0P{zY- BwP ]f1x;#_rBhM `PY19)}5\Y7cb5x9Pɇ7:$룧Yb8$IfF P x=>w%vZqSRQe-,3 Oᓷϓ;_xJ@/^'aT4ў[ "BAJY%H^xqv[Ӥ%avt>v˝2T 13Tv(HDŽ(T#ס~7\w@}HH*͉<5hS;|LRWW&~g*89E.z:2 +{Gcj !zMY\3}Zn6ԲH)ZVH*`=|0jȘf75طn(3ehMd}w Fј>HlFjd;j3.WH~V\-*n.Dr|'C0~߼MtYPE,;1u|xiC k ͛nt>6px pxMAOn豳ȣI@-100644 t0202-readloose.c1 Z=֗^-hݒsii"nx[wqM x\C\]]4 7~ٕ  'x;E #IŚGϣd` 0YXte!F"D 6$h!322~w`tw_UuΩώ}vo>z4n>{ݹw?[ݾqFsfvoٍI^[~zx/mw廼؞]=|{w=8ۏI^,۳9˰=}=2m)[뮐W|dII[RpeNB7]=gd"F,v$Uɂ xd7e~o9OR|/\簱w^%Q!ah$ jQ-\<9 qamJPZz[d`'4u^ 9ޑ8*~8m"*y,7E'[Wݓ:*=ݡՐX^F_ ,^ȈB7ar=\ދl6hKnHeR7AAS/ۆ`b?dq"靹 @=VXWt,Zw|D`1.`3 "@+mNfvjύ'0l pST*_@QV\LvA7jd 73v9-F&?xq1U'W;R^?rՕ # ˎNIY$*9&YUZS"'1u2I Jbj e)oEgSrμ\2 X[acc>Iu"'efWYdދQ6n^*]9oȕ,{~d ԏfm I*"Ә)[lZU>ƛ>y.*$Y䷗֘@cpiŀ F ' Hm)]yug[ɰ `bE5؈Xa: !*/V%XJk\7x&vLG~:yk_n(HH#WCHjg_;{'Oz@>2OpD;vBdo>Xʭmϳn|śԗJ4sP'!D'Gʞ))$쓵Z!MB0Q8oPWAvVA`CTx97ࣆlm\u%7ss"{ 匈SIR0_mn>C{%;Fq2*|/~QK1H`|r4xEaXB!*V+,PQ5& b욒NM@x*_5@,bBQ.P B)K _qI th2 "PY+$q[Yc.8u;E.ȧ4KC!yRAѴ t] 8o`}pܙCk'2%UkeNqM̅]$PצO"4 H`*.s=p7J0\. dTR,*=`-&C1DEz7\nnqPw#.@#r`h!gr*-[Fv#(8-+E*<}+șaz:++@/`Ciҁ.LA/C.4ҁRtI[z\@)i)1^!.wX =°9bQe% EN+k$H阤I]GSz2*]4F^D?ְtTNRrE7lR:AKсfD$pXPȟhPXGʷYE$jTHw`o2eEՀ0SG`P.%TtʭR2B:4INCgğԓ'NFrV-H%mVJ /h* z)]~UdTCdR-t$zjWb$oǭY.87ZJu VOC @Hn=(Y s3$jMմ*t pkk{PHWb ;6bP\N. Vǂd0*%J)q%+5(:$w*jw}ar $7],r- *cv}zG#ƕ,H⎤+h@H@IyO9Df_rBqO~Pƅg߱{,^]'w 2I#dی߹cCh!x <=ɱ°kfNJl鬓P 0x:+QGe}gUƳ*~QXP- p8 ȳ$"ix;4iBk@%xEcC1f+L,!񓕹 `n3[a|60txA 'x׈#[ ܚ"R[d$q'C SL(R,s' H޲xm+pe:e?[DmaL؉g]0iA^.1 DQjLYMi~戉PiԻIOOр!J.[ъtVAH]rܖɥfэ P%s &׷ pzɴd/.pťhDEԔ='Li"_}w2L`ox;ѿR%dyJ@KaF)fF-!-n\Ŭ ~-.wz}3 H %$tSg7ᥗ] sO{q2BAFZ}b};Χv'qqojE;.Iu%*U珝o~?͓+xDe<&shm84كhs e66O?O?ɡB*\\iEIYv)%\p_5W*!T]xSAkA"DmxIHS<`X"Bmd΄نx٫'? rBWvI˒{~?}]o:jGkuBp5-îu\n;z=xoG{Sm75hBw ՃKxod\& b/\L=Vhe`Np3BE$ }Yt ,0h_JUc͈NAi]A76o̰hfhtQਕPf7v]{{t~қYEmĞCl Sj8_ q|oڟAƙc88}|܂DI6ODHg㽗V'4zkOˬ䴧|VFC/cxd_NCf Uja tufW暂pc&{ȳ;OiF U M4vU dn7x[g&ΛY=r0rgxi H3@˓Gغ2RUx Dx!~|8̝\ f$$ADxi HJ,neي 49Qę !x6m3F0SW6COE5%M~ͿU,%xi H_ RKN\~V6mr4 |x!cY${IUY $K]x)d|N?4.!-^x/y^rX8rS2t &aiGpM^ƚgtH.PM¦,#6ـ.y[(VxϨ6%ld[$ lzx;/WrͧY9$sx72c{GلfԑgRW[/Imrs+2>Vx;/Hr70m>4ٗ9'3i"mǦ ggi&o@RwMu2?d'^H,x7:QN*( V9gRW[/Imrs+2>È_x[$Eb`Vvꜹ)E  *OaSĦ Ģ{ٔ&bSy&uulacMe1xiC Hm WTַ[:i; `xMAa-on{9100644 t0202-readloose.c$_ r |`;s E `x[zq5z̼ҔT⒔| ;.$TԢ<4ey@hZ+KK0EK* RA ,v56{ƈ1nNb4arv< 3y:lx=D5 $v%|X1Anh/D@p 5"$3 I@܀qtW7dUoU?yw9ʛi3ʜ|.2H3N$o{=8w KƹNBw~9n$C>we!FyfdMY@?bC+Fؑ3ÏRaAވѳ֮;Y)G &2%_Ճ2!xWvtP"ܘř&N$E0X#YH7qkb$'g y.qh Xf%"wv@`[rTMd{oXR&Cq6FZE~o4[ۏc` UOJ _zx:N=dHޑD>;$p/[R檠f$Pݢ<C4 F2ʓ~)h, 8P)Ngΰ V5d U &bLi i.8w R[gV'( HOڑF\苹 Ft>b40C-Mj-#r6Wv#(8m(*\ܨŕdѰLG gr7ZUJ+@/`ӓ!δ8t@%k W@9sYmkZ[}I\s6io`g[V100644 util.h KT?K=F1ӓgx}kf0^lMx;s{FLqn x{e&y ˘m}x~ѧl9E g|xȵ Exi %fSWr8jز>2brҵ Kcx6m *nB)XCO׷ϝqOj ~j x*4GhFnx <@+CyHT愓P joxvu¬o?q0xi ȑU^WdywfBF6 0x#+vDA+Bi8"{$4/,xs2mlQjMn6OIMOI56HI,ITVLѵL65TQ0TR0,άJ/QTUc U0402OW`9Fזq\=$&'˛)hVKK/-ΊDSXAW0VSsF QZ.]d'jZO3$(>y:5 T54J3RS34 @>M,DM hct7K1Z` Dhbif^0-H%&+!BL'7ȿ012PR@iR=sxi Hb* ;'[er԰ Cx5A.䦧AVtLWʐ;髭Ҹ 8l;x}k̖L{xi H͇fnElSyxE9RK}|B-q100644 fileops.hGQFOQ%!yxMOJ@I$B׿"! "ڕ\,af҄ILMO 9  ;)ܹfZAw}~Q4C˟Շ(\TKn2]SX+Ld<x6VFj)lte],'\Пk~$lJAjWLx5R`9LcEm !@IAȝ93Y/NnEz'#FRՏuHEP\ i ;M`,VXR|r7*x{ؤa(&.Ԋb"ĒĊRKJKK4@: jI2?+QH,IˏO,J+D,άJ/Q⋫ Ziye) Z:P4rĢtMj<[E@\.A Zx550K&Uʗo.s`dlï_Q x[$~,͢7[qd0;xi :ET{窽rη~Fm x[ͺuF6o( 9۩:w+w y`xۚ>k#sUf.mM5' xi s3ϒt) [ x9OݬW\n#R@.|pjjԼː_O8x <Aq弗}x]a!ɓP wx So."@QgDax)8ApC#g|s|?V7xi HL9'ٷy$?eg ux SuC#G陓gD~x)8QpC#g|s|,_nd fxi-psS-2Lgj|Ξ : x[ͺuFA b .'ts]+K_xi B*du|/~19QP [xE9gǵwɌgm=T100644 fileops.hrlZ2A/v%El8xkRܠa/}<" lx;?י>#fxi '6ҳX~X1v V /xVam^o(8R66QGbRQCu100644 util.hiS!=dR0N:X&%kPx|yC:z"nox{uL34lkx;sLk"Vgxi t+>|2YN-L)&@PZ\Rkn;";ˌͽ9U1eYuxcW]Sk.*>100644 fileops.h3jNF'Q,1;y>40000 gitR4 L,WLr%ԉCh1 '-x;ɿgd5:ʙy9) JEEEzJ\̜B%% @x34mw%)iyP<Ē bM .TE%P) "ugO>ά^3 :k4lJK@UrԢ 32/hT k7d͛EBx[sk"d%Ey y% %iyy% E Z%:`i9Ś\zRKphOIմl<{5f+X?.BxuSMo0 =׿pM}-͊EK f2 )e(cD{z]U;*c[t&>XP#uɳlQp ʼnR6V#vzd#Xdna!Mtd*sݭ/]-/n:T2HAS9(gs 4f KFP>^y/AwۋQfD9iE^x<J1ta`O#p%l% l$qbAk m{A K)dv\|n[ G~"eKًP/NIRhTjOfud_NS.r݂5 Lݲbr}`=9'q~h8#)/Z ;bF SYiDJ0- ͦ/Pa=^KهpRns{\ R-[lXj8x{IJe?3xi 4soU\ְ-쭉(3~ٶF9M!%/5GA'x>u6d绊݄2N100644 util.hiGx=i51qUhgnx{ϼ lQx;cf.fk&j x{2aƟSxDV2RϞRx"Q51'jbdFFUQ'`Oxg7G`+[][U7?` pA=xibV/~^巙X/abk hx(zJtF--66x٤6ww-Qxi y+ݺ)F܌ 'rx!x]?Z,"BF*Mşe-xi 4&`/g%{ߍ>]bb %% tNW[w3]&]qxx8{M: ޔ'zG¥Nf,pɦȒ/ÓgD֪7xȼyʼnO&3 M^LRIx(qt^rNiJRzf~IFQjbniIfN^d7oV )jx{yBƟssxi }#_Z X WHVN09QD Xxi;k+8=WE8ۧ4A]YmRT#i 4Tjr␳s.m=!ƾѓCQt;Ӿ<,ΞZ2AxȼyFɫy&WM|RZ39QfVFE Gx;tiH}w5lSS3LvJJ Kx{yc dmF1,!A.'cZ49Yvr/X4n?xiC h WĆ59bм( }x{̼y.kL QcQ@J7?)Kwov({RNHQjbdF8hr$c3oxi H)x i{K<]{{r -x[ͺut&|wI]ASCܞ(Y19x}6`Fɫ7321Pvxi ȷlٲfR< vx[ͺu{_w~>CY LLR2N>fmґ2vF/ZO]j2sR R.h8T>}u9 3˾{]=Y*Bzf Csgʅm-۾( qV˯c3c#^7Ckbxʾyrs jmxi*>Ux{M~d9L@T6(("%i%%Ii1+$3?QPRwRH-*/RHKKWҟEEFAC)MV!71''?Y#'5O{*~Ѭxl8ٛ=w^!22󀲩 e)U9Yl4YwL>o&K8x&E~!gHFY~ffg )x"E~7U89kj44Jl3Kssr5rR& MNe,?9-|M1 x;tiH`9k>Pt*[yk줉akCx{;wbJpx <MEMu> P T(x340031QHNM-H,`p-v\^ΗCbs ss3K1]x?oŝ$/*{z`󡧭)}]]a6Hjjl"K+Ԯ&ϘjR򋊁v&=#ѻYjݜlj2N>fmґ2vF/ZO]j2sR @y\*JLVخAS0r}{cw+}۾^ PH,a\ȫf'J=֗CH,Z.礻٫n}/ۑUd0l.<;3s>ڟ42TE~JЈY y]t} 7O)L*hc l29BK/*(J-+O*j:U'볇}: /OoXl &Z--iģJ2RStKK2s@wҵisła8DGlƦ2Ar~i:s7\vbb*AJ*\'_4`BJjQRYP\X Ulľ???G!=$(ȞK5x1xk+2BzfI|QjY5C>gHKrj^Jf>x+g$G6̒Բ {.E$ ]k'xsg}?X+"<1xRJ0xiN> m]PQ^t 6%I(!|—0IjmǼ$?~_!NAb!E>4#љ%J*!A2EH,rH !,<:FcvJ#k.$M%Ŋ2c c{B1g糙JphJZ2 !Z/19cl,J0tU5]fmBJ}PC&yV P,(b.Hꤝ̵Nv3ȇVƚ1[S͗lGm`3юƮk_-W^5]c;CwK맵w#r2BUlO5cx[4tfIa6Ĝd"̪TmCMS9Y'/VuBL J7x <+w:>9P Gx |" gTLГi^x{z(t/+KAbIV50krDh#V- ֜MJxi HV%U}<ӭr|)Ӛ6M~r Xxdd0Q}z=6o7c>yѲ kx;z t<<!~:xi İ,Otԩ[F Hx8{⷟ 7F2P!;%MF(]}TW0 57x[iBdOFLf Pr:x;3t7SfNy$xAmxi K)[5"m(3h8v`E'OkB\$xt8\[%*˧aAgT100644 errors.cH3ɫ ǾQxډg] 3CQ2P!;%MF(]}TW0 _42wAx[ʼiBdOFקLf Jox 'eŬ3y?d&͋1Ex <eO_wM5P Nx\9i Pm@LsפmP7100644 fileops.cEV +\3 4Ւ:Bxxq*#.̤b+]̢̤Zݜ#.紜tJuf^rNiJ*H Gqxi If?kx|VXBIjqI1Aʼ7cu{/:Fx9/hQE0Mk~a@h01CQ2>4DN {BAzxtDɾ6 D:J/'akx۩zWq! N.xzo3ܬrFjlxe~4!nc3#\vxS@cĪQ_+ͣc .4v1AK<*40000 testsYNuV-d](ll5x;%zPtC TTF Rk7xd=ʲqropjxe4xc;#BN$x <d2IE#[H\P Qx"ʧgn1HؒJK_R;x&C~;3KY~f}EX.l % x:5'x<> h4;IZ/3V΀+܃C߷R2>hxO,LO./)J,KHD.3 wnx;%IxmϘLff[29sd7 x;tibIC> -/v>cAx;%_`FNͧY'2ON\8ٍ+ 8  apxS-obRǾKE4\4GwӇ/Yv40000 tests yb5[M B׬.Ds%7Ox;%zY`F&4dt͓7feʹpW2{qAbQq*&IMlDx,[`CyL[Y# x9]]; @{2WA“%+=.(PM{1}JP7uqduFؾ ?)x;re>nw\_+ΌL #hx6}`DdyvF>TT.l-9Ѿ{fBzfIZfNz y) zz3 ?*x"qIbMlqLغ7bUqx gTTҶI\  >n.x;ti0o$Wm7Mk_nb %% ŗZ}qOn1bx9/]gIӚ|\#YC.5Ts,NK=U79W;x6}`DdyvF>TT. !i BqPMx"g—ɓ뙌 61]fڬͥv2Yx; "sN̒x ]X)h嗖($(g祦($g$)hirUsq&Tje(u3R`\\'gpxk#a x{xqdf^2CgjPoO9 yҞ=Bkx[~RffF!>SAx;ti0T`[yڃTݼdduF ^ x9/Yf\\'N1C.5Ts,NK=U7~'x;ti ^y/]%F)@Dhܬ +x;ž}33KJ~jdfIC)x7O &!r: yz\DeLyQdCӷ' Fdx9/E_DU\n5~L%C.5Ts,NK=U7Ux;tiHͳ;3g[['֏Ĩ׊ R[x[ž}.hJjBpcPkgp|PL#ܣ }lxNYU|Sj I𑷐ѻ/x{[&ĢO;Lx;ti0H͡6G=zZz"{duF Kx9/;D67K|;QoC.5Ts,NK=U7r x7ʘ@X{,\|owx;;`q/\N"" /2x{rGeU< %.̼ҔTYy b.xrMeC#& N[ l_ϸ4#_~RV|rN~qFzfId. "CxrCz$8a̼ҔT⒔$ Yyב [#x;ti0H={ZOW㑿a%>r: Zx{Wb[D8Qn}:V;100644 fileops.hVЈO#vVX40000 git)m_ҁ _?ؽ/q!C.5Ts,NK=U7I3bgx[+uAp j1x[ssBF.Ԣb ɿS&_grŜƸY Ai]x;4iBk@1x;ti0U52ܺxUȪ  zxE9YՒI100644 fileops.h2ֹv~P/yr#g% 7bg_x[+uu}& =`x[ų}BF.Ԣb ɿ'_cr8M tx7qb]Bs_2ÂVj\ i^SUەmE$O' $x;%:WpD;y{(*%g'eepq;y+hCdU45<\(%z2620 ah<)^AE M.N"Lsj׭]&?fB&=UmP{\&/-3]/C/3*[:7%U9~>2,,(hԅ ~=ސ]M|-=[.TM~JPku<%g׻kM{Z5k 2fJ4D.{y(3vxս3\ikK8\6.J-+O~Sq}j׮N*ͼ:;PE%E)%9 <˿#_^1su{B{k!?ʪLs߰Nbn*fR>QZ5BM xSLKIMSs uqO,OKLψReRK)MIUP;8;8e(RR2Ӹli3xrDz$#jxsgD6 x340031Q(ˬ`ph0;e=7*^ x340031Q(ˬKfRp]_dGڳKOo|Lw7)xj17$>©Тvںd6"ծ$N@I22BW}>LQA(ns?x(s9X. `J1+›.b mQ2H$W.tU o0>]?=ӣД -$.%ΓXm$M(+Y<}鴇wG$I)&X(NbckgLuaw \! [4pfȱG>'Rr>x-* 24%2?G[Ѯnd-[ @8&:JGq%]x.Lpr͏X37'3Nf,gtxBBL~< >U-x.4Spr͏X3''L~g2 NeC Kx;tiWi_;"OmW>,5;9$ gUx)I`C =xs! ?z#rj摶u$hx葛ɛvמWlx+8Qpf TVc+x;tibͣ:V{}=0QzJpu17Oj89u9:KxAwJ)!g?^maMjQYЭDFhF7xqlTx,^tU7Y(F^x[ͿuͷY2Nv @gx7db۝Xx\gԇҎ?X6l' b^lx/Z` ffsV",?xryBQT>~&@Y&~mŤ Xo?Vk-SEi&xqBzmex"ṿ0zTL vAA"Ek2x[žmO Z6Fx;ti03]fJUsOMbwc D Rxf$Jٵ1 A~&i\xxqBz%Iqx c?ϺUk̓' ]jCx> 31ubWFAbIqiRq^^FyfNJrbQBqQ^&ć"/X2Mdaws|y  nxx?!mc3&v=WGנEsXmWx:,ٟgrl1j=xx?!mck';Y]x7*p^ŋ:t&Vg\ԐE&.?g9e2Bi' Ҫx340031QH,KfP-:L @!=a=E3.znbB~JP{ߖxjsk3gG[d<21?XǏuRnC@/fkC 09g/(<1'h&O~ЂҒ̜bʓMs+Us8!w8g36 S-Kә$? &q^x-$100644 commit.hŮ69z$x;ti0(ג.J4'~~: gx.})ĻB~ jx4i¯*_ox^xGQmȝmlmxʷAy 8Ox340031Qputq bbՏ|~,q =E!TIzfIfz^~Q*ò~ ~ps:WDEή8Us'̂ξӊN\`,++ sg8qsg]t{| Դ̜T .vwP5z)y S5X_^RoߪYu,Pe@\XZ_T K~YGܚ~2sJSRnL 뷅r^rVų *6Ji[*nBdKRK/) sw\Y%cdݽxO,LO.K)MIO,OKLD NH` x7!=3/94%ubH?Y1YQIY,9?/-3]/%(XAV*9ѕfULg0biyB֗0,F7x31RΚWdo [x7 x340031QH,`ʡ̖lPi׶ņ5y@5 8{I}|Wm`槧|nph<0e)I@sZhk)XN~k70)@wrtt 7;L @!!ƫ nZH_[)TwQjYybN6ЄnZƣB+n|yG޵O.PEU9 G$KnUyv΢Olf?Onlx[ͿuͷY.0#` x340031QH,KfP-: !jS RNN~S_+~9;2 3!:~zw^jZPBĮmAl;L˃.J-+O0I'w7s- <sFMx{i8>gcLN?s{OyL @(a ou'軽v<ɞ Wx31vѩ@Di_Zc= x340031QH,`cVe/GG?y÷S&?Tq4\M^Zf^^f˶Ya¡ud@$jۣmb:aZuݸOdܝ; q3V01b7T?}k#Mm ˦PEe9@ζ{LoDfϑ/*9"Iv_rㅭʳs}b4(7pk1x%t]hCT*x,0GMjص;0Tx{yuj.̒$$kZk..@QjY5?dE,T |VILDx{i8ћ]_Y~mOd(%3|jk=+XdOFx31+S.N^T/굋 xx|3΁'R@ݟXq.ʑk;x31 B ILKR ,LEO,0GMjص*x;NhrX7QXCY x{i8ij?\׮ab[ܚڌv x31ak6*K%ikQ;p dx340031QH,`OD\i<D^ڞ&?Tq4\M^Zf^^f˶Ya¡ud@$M}8mV 7)ۦ4uK 3@T?m+7kU>11b7T?}k#Mm ˦PEe9@^ i|ɶѺ?aɒ/ULK*9{LB7Suz\إ<aolZx(t_h?,&Ԯx340031Qputq bbՏ|~,q =E!TIzfIfz^~Q*ò~ ~ps:WDEή8Us'̂ξӊN\`,++ sg8qsg]t{| Դ̜T .vwP5z)y S5X_^RoߪYu,&@S@Zڿ6׵kؖ|4(S.X_҅v %% ŗZ}qOn1"'.x(w|c9˜>.x31UeOW.jԉVS3 fxqg pxǴix5\5yӥJrL @(!\*u@⫤^eHi?9lZx31sA>V3\BLe|&7( xqBHM|ܥj]^kdܭmbxڤfV+FkSZ[x31y0#d|\w EO,0GMjصyj.x;﷊grXlYK&+z;sqki)&))$攤%+$%f$&)hsqg祦(#YsZOWd,ܡ7y{QjIiQd4'xǴi,xݾyiF&@P\6Kݤ⦅K/G|F&1*7ܮx31II;}nlyg%[Wr |xq.Ɗt)WN~^5c9U x340031Q(ˬ`^=GbW?l\x+3WjC֬ErO{YG)xo~ʚExxm %x340031Q(ˬKf(W8gcb+s-Zڣ #^xkX˿a6 MjQQ^^,Y52x340031Qputq bbՏ|~,q =E!TIzfIfz^~Q*ò~ ~ps:WDEή8Us'̂ξӊN\`,++ sg8qsg]t{| Դ̜T .vwP5z)y S5X_^RoߪYu,&@S:sYpc[|9gDEqQ2ïeB)wT'|"۴}ْbK-r>H']7WVMx31O|`+hﴱP_ .Gxrz<$);U%x340031Q(ˬ`a1at3uv[&22)x1N@E%@J@Q$((i+maw J) qE.Aͮ-+?ϭٲ鬨׷\bd@P(Q8j54Z&F.~}8sͼVwR%  `wGc*'hC"AZ3H_<:38aP/ Chk5ӅLf2PA5ncB C6Z\K):*&تQUN EhI&kCev(n3+O/a|J(;OgMh*47|}MZD(Zp="5bU|Cڡ9YgxoW 7vBK5ON%ڥx340031Q(ˬKfh4K^i% _3ͪɤ =x[˿g>̪!iE ֓H($hZsqrf)h)((Mɪ L++M(J-)-S(kj6 =&PB1`xǴi©M\ i?eyyH5(d%甦2nzW6Gm=8OCT%3Ln?i8ϨasoA%<Ȗ3|;mm8xHR4Pkux{|yJx31k_mV BxS4`r ˽ AwLHU1@zs*f)[Lt40000 os3cZdR"cB&%'lx+HtS{%x,MpC0kDkHEk..}--Z-}.wϐxW?xWg.Լ4.x340031Q(ˬ`0𧊨ӊЫO vl x&Hj;hVi#7? x[qBH@UJ'j]#c4'i tx;4id.c%&?FIae0l&WS@t8AZpQFcKF̑')gsx;)sB` gwx\/a=7 XxǴiH .eSz¬;¸t x9ن  ["ˑMsKonx;)3s6ܛ籬b3,IxǴi5k>%R qx;xqGf\mmt-} xŽ_$$>9?$5Xi V+YAiyy\ʙy9) h8RKJ j<Yxý#58$>yk8YZRZ``UD #x3ҚQ*dCsvD—5L:Œ<xw{C 7e&bU(I-.)񹉙yz\!񾎞~ \\*!>NVȒ9Iz *.A %!@U0`P) =! &'sq(8U*)H,).M*.QPQKQTCrGr~^Ij^I13Tg7Gwy9) .PGp5au2 *6)gqq*覡 XAB@m<"sr Fg{%|x;8qZȊw3'IS xǴisҊuHqg[`}3>{܉ x31-K\QȲw%t/:xqHה;_z%aND l xk#a>f/ x3c`ƞ#Bc֒*l%{wB;h->x31w/aedGvZS gxqȌ&oN:3r\|D Ȫ x340031Q(1d }{0Ͷٷy9+6*K-.Lb[xhv [lmJ{ K)fx3ugqQ3@V4lEƇ^Pvq= xpes:Z&wϐ"[B@x7zm-an:ꑷSlJ ~_UՓ 1))j]x}{F5&x[qB!%M^I4$qbQ sxk+ dqIQAlBBZQ~n|FjEd 7xǴi|nuzX}¶| jIv4x31mMnc~6iպq _x|UK&Bc (llxڦf>^ vNxN5x_Q "㭻 CIZQn!QF H5WتDX웒>^)xO,LO.K)MIO,OKLD.A |xu!WbNBNfRzf^"WrNjbgQnBB(Y_K/rS[L2V *N^z8U44́*ch52OVpDٹ܎@40000 src2؊zHV6Ρ w0xO,LO.D.0Kjx{2AkŦv'2VONcXˮx31=*ȥi:)z"q56 @ x340031QH,`y:=@~AcחG jj8MNq{H6T׍O7.UTz|K|9r&a9j STPՙy&jy=O TAQjYybN6Pk!/6Z',YqvExk.d&|!N~.>9\j2!E,$׺K>}`OW 3^8 STmzνu޴ϐ5ԲĜl3rZ-O_^zsUJeLx;#Mb|v.̒k58A")/`Y4VA~~Br~^qTd}ٓpIo~e8YG Rn^x&_tC\6q ʦŨy dii!pxVMOHW(3{\0 -;k;0"@0hv 04{u^U*Wň.+KjSRZTq{~UۮӦ*oZ77k]e͞6ٶczhg1QTfNT7f ?4ϺzdTfmUڧwεd6rS@o;eqS2Qe:1tK%hUu`3/3U凞)Ojûg /gG4ZߪY2 4:l_w 6mV(C:KTVg|S f+hMF!"g4-ZqU!6C*p ۚnpA(P՚Mq(V9+DpU(F&DދἈ;&xGXnR恈€5(Lc9YN'Hb ^JY]|p6&`P42d_5Y1ҭx9郵:i0‹S/^Lea?uğ{VvI܉0ƛE݇"F ;p֛̅3 ?G89& KA@\^0fv#ޭ7 e QEmvINzp'AUȡ,͐8FS JUujZN+3jeLW1*H}G_?oD 2D?GltvYAݯ^:F Ѥ Zos tޥ7]*zޮ JmkˬSšpJcc0d6o)^qsFT sW{mϰ@Y]>}i=v.}.7 }uZC$\WNzKLd}ٝ kzfh ъ>}qdɪƔ}XXxKdv:5Tޑ.~!OG2#lr~^wރŮ*k'߸hCc@.?T"ژP$zu|uxx(*!Qs{4fNN)&N̒Բ܊ mx[BcC~r~nn~^rf^rNiJRzfz6FkjxPn9oxRj@=F47_J =!P%KSpr(4v((E??tvqKvf̼d3rzL0NS2d>YΉD1f4V 4@vk7߶ך(7L܀IA/Ŧ('qQn"WiM2*u`On!"lbm&ZWike%l>͂+=V xі)i6%KeU"8^E5ŪY%]< @PfPCPH++RsaEUDzN`narTUuuZQÝYF4qYHB}xиܢ0p~qZ\gP 7*dg/./ށѐ*E>uxhBE-P@l %?:57eUE4W׬_)gWdx0;FRFo2o/x,rDdC~r~nn~^CZfNBzff6>ً͓2& rJL|:YP-9x[+VjC|6q1$ %.̼ҔTsؤ7`+e[3fx340031QH,Kfbfl0v?}*&?% .12}uNZ[d|.e[e>:-*(J-+O*`\d1q[٥% _U U8gxTn8 =oiiS`Vfs*\[iV -rf:Z("#囫\;ǧ07Ϧ{ I!x0zapoLy}_a|7$b8Ottcεvo0 pٶxOuqbGh\Zb]go ob8jdK{5% ۘ#}+)͡;#{'3QxgL$uؙ>oSqFz c/ͷl{;9lxgVzfI|r~n.L@58RKJԒu2Sjm=xg.d=6o$M0|xUs6=bK/ &dl16PNEPk,FtO2oz!i2 uMFly#S*+vFNDSQJR 7t7;A{mG;66uQWjJa1<FI:Y7UD8uUj!JT.(~F%*uؾ `kqN٧Ӈk1ݩRzP-Հ(E+)BͲ(2AS.L @'3\Yj(N\ i:N%ĵ(*r6Gi\u7Y-H>Fu6#5HaȠhM >vMl*X~Gݝ\=xj{q$K;oHR B ׶7(KfOJ<2 &EN$ Y63H<"Op73$6\,(I/W ~sy6AT<{ "9"sδɌ, {aqNouRhI?PC y=$#7[ ktƳ6c#ҟc>Eʖ;,Ɋi͓$tg,}˞m~v̨Ș:e<-2,qҴX<5<:Ɇ_I \am$F/l9f_ {3Çk ' ܆D{g.=|9S9Źx~UMYإWmu{=ecnx;7;Sfd1%x;Ŀ d7KKt83KSRXfdbMn>x.f=.F#JxV]O8}&}iK(0#i-!Z$Ueg{(f̓=c&{=zdTʻY]Q)*QDuTVu)o,r󔖕 SU,D[M2LRei)+R9I0LKA QfEJXz#32SIRU:/kjސ>J˪:[+xbQ^2&dEs)͢yf2e&ݟ2A S@jg2 gFLˆR"Yf"S+J*SRעzvǦs7(*"3P䈕 U"˖ FGmF> KEMnUVST^4!9{\Pb1*O׭ZD7$"B^[\xH]X#ǁl|(:,i^$mHV{~, ]<,/,4U:lwpoh0#r.cJO+րcfsa .+4; oa:Qo 9ٓ)$ ˆG|ȂsnX廾:SDc5LB-^Ă`2uqpB=-~U~0bİ({k@;ڌDUm% ]>dԮ.xȺP-_5Ӎm%~ӝsq+BAA{>p/2OK;Y2ݝm,FξFzMBp&OLquM_o{=WZth$`88z̨>kFmI;jч}l S[@m (i (m H4@dž>yuɾu~7>Z=[]㻱%86G1-]OQL;{U],옄,B]4-BJMbjNNKѫʚRg ]iȣ.{P}7zrwGc3M/H! c6OlxJ=j?2%'&a|kFWU;\,;'x!IbBzfI|~fJ|nvqIYq6/&J .x$Zb.f=K,Ly93[O#3xuPAN0! HȉBąS/qi-8 Pďx ^{wfgwvϿ.>ɈR/ _ˎ `Wηfd p`l+/+L#+߅/!,0EvP4Fv%$M Q!Ӽr^{r| L24>3>)  \<66-uCxH6^ #dLGko |ⵗvqBhYFob"ʬpK?g`({8~A L@-co.x/pM`CSfl3 x&pH`C 6ɫ|83KSR!ԲĒ"aUkPB(Oր0Y]JXA Ga m9$T7)cx;$o/mlL֓߳Isg$)h$M6fM [n2x·o.f=66F! x340031QK,L/JeP7>V%)~&O~ݺhQj񑕆o72٢al$/ؕASN;;2\B1cA&fe2tjo"3a.YeYI,KɯLOc:;{ځg-1KT8`tr9g̚k744~Rd~xk(sJuZfNj^bnjm|F|<rf^rNiJRzfI|r~nn~^PF_KSAKEaFN9'Kxb<(yKxՔX+ x{|y6sqQFrCx340031QH,O,Kfq}ƞ68%W\=s! =V?/N}aȖt`4uy@u'ox~ĭ䕅 wM8I]~Jҕ ɖLO)-qh22N>״KEvf!+Lpq {]UcÆc{6)`X/qQzo:@RTZV 4wq ?Nlp;m|b7 O=Enّkx&_t<V*x(* fNN)&N̒Բ܊wqUnzx$Zb7SffNLF+K x,rDdDً͓2& rJL|:Y wxxqQ^o٩MvKA}a s3x\<x3ajLh(e=lP=Iqٹ֋?NY100644 git_revwalk.hZ7(L`kEZq%[+!M(x9r jRt Mlbx(B`C#Nx39K )>6Ip쭱Mx)D.khO=@Pg/;x(ro\y) y % iE 9 %)% @A0'%)dƯ7`US_x340031QH,O,Kfx׺pˬ%Q|9o.uS>l[4uy@ujgۦv5"HVtr&Dzqdo^ vk 互ʂT+^MA/ra~i Z)I: yPet,* V)@ͻׂ e0#ȡDv.lxqJc[ؘ26q ͲA4+0]b6nx!^b7Sffn\F+opx,rJd'SffAN'F*nNx39` [cMuK 9đMxt_V:֞y M7 ;x(o\y) y % iE 9 %)% @A0'%)dU&%(4M$hBJfrbI*WqirrjqdW n. ִ̢,FH&a1J-*/SPpFLx6x340031QH,O,Kfx׺pˬ%Q|9o.uS>l[4uy@u}wX8O:oxO\.?% h𽐝jU3 yUlY6[P. !2o;I?]B-*I;N=xao6{SÎ)`08՛/,x?>$EEe9@Ӫkn۳IE1e, 3V sZjV\A %_E6Ol1xNc[y,3xx3ljΎ()gTˣ1q4`5aYznx_uq%xb<(y'kUSFm1xtiBH&BžuZ_~ʼnΤ$ox(Vt5d8X7R:(x3f*i& $aU57@E 㑔1Fwq='fg|m4l0xżycs{gqQjF @xǴqbW!iߟp<=Pt jrnS4k:x{+DtC\R/x9~xիJ ~BkM[lBx{wwnL"?5sx69~xիJ ~BkM3)ϝ&kF;ӓ'xE&x|ycs{gqQ@J_U/JHXIxxqQG5[_^-xĸq<OYhq@T ^xøqB ѵ_;X\~uuYm^fk/xyF}F{D!^rx@v~ҴT1nxCJxøqBHh_Q&/:-uNE^'we2N>+[aixĸqB;-Օܔ)Yf|P6eK[tN̫vUx̼yFNHwW?[.6iBcxĸq<jZEt_Zzߧ Z x340031QH,O`ŖOR1f~tC$dO8\?x(hj/)`89e朹a=3?nIx_{H(jځN={Bxe0ڬtɊ?g~vτ{DR!Tx;wHzfI|QjqiN_(51% 19;5E#DG!%IG!3ES((O3$>858ؚ &fBN~~q*\\S3=b}Y| 99pack-d7c6adf9f61318f041845b01440d09aa7a91e1b5.idx000066400000000000000000000023301216214232500331320ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/testrepo.git/objects/packtOcA3ػGAi[l\of̌ŴnP) 4$ŀuuO|?-Y 21]iazošIn* 0ؒ!ZqSڥ : @0HD:3 w&Ⱦܠhq$neSՐ;dڧ/pack-d7c6adf9f61318f041845b01440d09aa7a91e1b5.pack000066400000000000000000000007531216214232500332730ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/testrepo.git/objects/packPACKx] 0sk6 "xOnh+^ߢ7e>Ur;jes6dϝyUh]&A\jf${SbJ4c[McreG.bvFIUn/&~w3:Dc x[ 1 {\@K#x&ME5_7 *9`T*!5)inHMvHA˦…cÓp:߷<B,i| 6x>fOo{8x340031QH/H-+(aje+kt5eũy)`UoVc&'zhִu=ٱxL-QH/H-RHI:.;x+H,QHIx340031QH/H-+(aje+kt5V ?Ⱦܠhq$nepack-d85f5d483273108c9d8dd0e4728ccf0b2982423a.idx000066400000000000000000000023301216214232500330770ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/testrepo.git/objects/packtOcf:I6qkS2rvǞ[ c6kȍ2:}f0mϛTVR3P$B =Њ 0*JNd>1dPx I-.KWHT(JMLM+(/W(OUHLIsRr2R2RR/x340031Q(JMLM+(aH6kɾzږgR[>ܵx I-.KWHT(JMLM+(UgGҚCWN(N,NJlibgit2-0.19.0/tests-clar/resources/testrepo.git/packed-refs000066400000000000000000000002251216214232500237630ustar00rootroot00000000000000# pack-refs with: peeled 41bc8c69075bbdb46c5c6f0566cc8cc5b46e8bd9 refs/heads/packed 5b5b025afb0b4c913b4c338a42934a3863bf3644 refs/heads/packed-test libgit2-0.19.0/tests-clar/resources/testrepo.git/refs/000077500000000000000000000000001216214232500226145ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/testrepo.git/refs/heads/000077500000000000000000000000001216214232500237005ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/testrepo.git/refs/heads/br2000066400000000000000000000000511216214232500243040ustar00rootroot00000000000000a4a7dce85cf63874e984719f4fdd239f5145052f libgit2-0.19.0/tests-clar/resources/testrepo.git/refs/heads/cannot-fetch000066400000000000000000000000511216214232500261700ustar00rootroot00000000000000a4a7dce85cf63874e984719f4fdd239f5145052f libgit2-0.19.0/tests-clar/resources/testrepo.git/refs/heads/chomped000066400000000000000000000000501216214232500252350ustar00rootroot00000000000000e90810b8df3e80c413d903f631643c716887138dlibgit2-0.19.0/tests-clar/resources/testrepo.git/refs/heads/haacked000066400000000000000000000000511216214232500251770ustar00rootroot00000000000000258f0e2a959a364e40ed6603d5d44fbb24765b10 libgit2-0.19.0/tests-clar/resources/testrepo.git/refs/heads/master000066400000000000000000000000511216214232500251120ustar00rootroot00000000000000a65fedf39aefe402d3bb6e24df4d4f5fe4547750 libgit2-0.19.0/tests-clar/resources/testrepo.git/refs/heads/not-good000066400000000000000000000000511216214232500253450ustar00rootroot00000000000000a65fedf39aefe402d3bb6e24df4d4f5fe4547750 libgit2-0.19.0/tests-clar/resources/testrepo.git/refs/heads/packed-test000066400000000000000000000000511216214232500260230ustar00rootroot000000000000004a202b346bb0fb0db7eff3cffeb3c70babbd2045 libgit2-0.19.0/tests-clar/resources/testrepo.git/refs/heads/subtrees000066400000000000000000000000511216214232500254530ustar00rootroot00000000000000763d71aadf09a7951596c9746c024e7eece7c7af libgit2-0.19.0/tests-clar/resources/testrepo.git/refs/heads/test000066400000000000000000000000511216214232500245760ustar00rootroot00000000000000e90810b8df3e80c413d903f631643c716887138d libgit2-0.19.0/tests-clar/resources/testrepo.git/refs/heads/track-local000066400000000000000000000000511216214232500260130ustar00rootroot000000000000009fd738e8f7967c078dceed8190330fc8648ee56a libgit2-0.19.0/tests-clar/resources/testrepo.git/refs/heads/trailing000066400000000000000000000000521216214232500254310ustar00rootroot00000000000000e90810b8df3e80c413d903f631643c716887138d libgit2-0.19.0/tests-clar/resources/testrepo.git/refs/notes/000077500000000000000000000000001216214232500237445ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/testrepo.git/refs/notes/fanout000066400000000000000000000000511216214232500251570ustar00rootroot00000000000000d07b0f9a8c89f1d9e74dc4fce6421dec5ef8a659 libgit2-0.19.0/tests-clar/resources/testrepo.git/refs/remotes/000077500000000000000000000000001216214232500242725ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/testrepo.git/refs/remotes/test/000077500000000000000000000000001216214232500252515ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/testrepo.git/refs/remotes/test/master000066400000000000000000000000511216214232500264630ustar00rootroot00000000000000be3563ae3f795b2b4353bcce3a527ad0a4f7f644 libgit2-0.19.0/tests-clar/resources/testrepo.git/refs/tags/000077500000000000000000000000001216214232500235525ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/testrepo.git/refs/tags/annotated_tag_to_blob000066400000000000000000000000511216214232500300010ustar00rootroot00000000000000521d87c1ec3aef9824daf6d96cc0ae3710766d91 libgit2-0.19.0/tests-clar/resources/testrepo.git/refs/tags/e90810b000066400000000000000000000000511216214232500244610ustar00rootroot000000000000007b4384978d2493e851f9cca7858815fac9b10980 libgit2-0.19.0/tests-clar/resources/testrepo.git/refs/tags/hard_tag000066400000000000000000000000511216214232500252420ustar00rootroot00000000000000849a5e34a26815e821f865b8479f5815a47af0fe libgit2-0.19.0/tests-clar/resources/testrepo.git/refs/tags/point_to_blob000066400000000000000000000000511216214232500263220ustar00rootroot000000000000001385f264afb75a56a5bec74243be9b367ba4ca08 libgit2-0.19.0/tests-clar/resources/testrepo.git/refs/tags/taggerless000066400000000000000000000000511216214232500256310ustar00rootroot000000000000004a23e2e65ad4e31c4c9db7dc746650bfad082679 libgit2-0.19.0/tests-clar/resources/testrepo.git/refs/tags/test000066400000000000000000000000511216214232500244500ustar00rootroot00000000000000b25fa35b38051e4ae45d4222e795f9df2e43f1d1 libgit2-0.19.0/tests-clar/resources/testrepo.git/refs/tags/wrapped_tag000066400000000000000000000000511216214232500257660ustar00rootroot00000000000000849a5e34a26815e821f865b8479f5815a47af0fe libgit2-0.19.0/tests-clar/resources/testrepo/000077500000000000000000000000001216214232500210735ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/testrepo/.gitted/000077500000000000000000000000001216214232500224315ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/testrepo/.gitted/HEAD000066400000000000000000000000271216214232500230540ustar00rootroot00000000000000ref: refs/heads/master libgit2-0.19.0/tests-clar/resources/testrepo/.gitted/HEAD_TRACKER000066400000000000000000000000121216214232500242210ustar00rootroot00000000000000ref: HEAD libgit2-0.19.0/tests-clar/resources/testrepo/.gitted/config000066400000000000000000000003331216214232500236200ustar00rootroot00000000000000[core] repositoryformatversion = 0 filemode = true bare = false logallrefupdates = true [remote "test"] url = git://github.com/libgit2/libgit2 fetch = +refs/heads/*:refs/remotes/test/* libgit2-0.19.0/tests-clar/resources/testrepo/.gitted/index000066400000000000000000000234711216214232500234720ustar00rootroot00000000000000DIRCmL?3L?3_0LUG+.HEADERL?3L?3_Q :GBG Je .gitignoreL?3L?3_ W\V8ܾfs"vw CONVENTIONSL?3L?3_IHoLFW+COPYINGL?3L?3_ȫVl· 6yDYMakefileL?3L?3_M%vS `1 h-bg api.doxygenL?3L?3_ j,SudzK-ZPgit.git-authorsL?3L?3_Bv@WEt{z libgit2.pc.inL?3L?3_!L`*B9i<Í~src/block-sha1/sha1.cL?3L?3_UjwCKj bʘ8!src/block-sha1/sha1.hL?3L?3_(蠫yQʇ^qM /6O src/bswap.hL?3L?3_tl)r:W8lsrc/cc-compat.hL?L?_1[aދ;нG' src/commit.cL?L?_U6e(1Qܵ%Ǘb src/commit.hL?3L?3_rDŽlW%qm ־ src/common.hL?3L?3_ IzC-O Dl8isrc/delta-apply.cL?3L?3_2I#| E-src/delta-apply.hL?3L?3_?rQ zYxnam src/dir.hL?3L?3_ }%m$^I=, src/errors.cL?3L?3_\ =Adx1t3 src/errors.hL?-L?-` dHBdK(bisrc/filelock.cL?-L?-`&w9rfW src/filelock.hL?3L?3_-eAYdwB src/fileops.cL?3L?3_-#aa[wy src/fileops.hL?xL?x_ m4*:>P-src/git/commit.hL?3L?3_%no%-src/git/common.hL?3L?3_eB>4 KOT!6(src/git/errors.hL?-L?-` ҖUcx4fRsrc/git/index.hL?3L?3_\X2d\ .QR0 src/git/odb.hL?3L?3_,?h src/util.hL?3L?3_QAìV\Qsrc/win32/dir.cL?3L?3_n5ڢo`]Y8src/win32/fileops.cL?3L?3_8b!`0@ͽ1 Ssrc/win32/map.cL?3L?3_i$}`_tests/.gitignoreL?3L?3_ G%%>JLee)1_tests/MakefileL?3L?3_r(C0H)Pސ, tests/NAMINGL?3L?3_6v^4I|tests/t0001-errno.cL?3L?3_拏rjm6{Ýjdamtests/t0002-refcnt.cL?3L?3_ HBW}-xtests/t0003-strutil.cL?3L?3_.gvt[*JB$1^55fytests/t0403-lists.cL?3L?3_*"L;퐻 Z}=tests/t0501-objects/13/85f264afb75a56a5bec74243be9b367ba4ca08L?3L?3_3oc@]e)_=tests/t0501-objects/18/1037049a54a1eb5fab404658a3a250b44335d7L?3L?3_w 01ּyNOX=tests/t0501-objects/18/10dff58d8a660512d4832e740f692884338ccdL?3L?3_|P@ k% {_ =tests/t0501-objects/45/b983be36b73c0788dc9cbcb76cbb80fc7bb057L?3L?3_S9M] #I=tests/t0501-objects/4a/202b346bb0fb0db7eff3cffeb3c70babbd2045L?3L?3_,TzuCllW4=tests/t0501-objects/5b/5b025afb0b4c913b4c338a42934a3863bf3644L?3L?3_w..l*̅f=tests/t0501-objects/75/057dd4114e74cca1d750d0aee1647c903cb60aL?3L?3_R/kn=P 64G:;Y=tests/t0501-objects/81/4889a078c031f61ed08ab5fa863aea9314344dL?3L?3_~]Vx1NJ'ᶔD=tests/t0501-objects/84/96071c1b46c854b31185ea97743be6a8774479L?3L?3_CZopȆNU=tests/t0501-objects/9f/d738e8f7967c078dceed8190330fc8648ee56aL?3L?3_X<%6ώ%3z=tests/t0501-objects/a4/a7dce85cf63874e984719f4fdd239f5145052fL?3L?3_66ˈP%aւ=tests/t0501-objects/a7/1586c1dfe8a71c6cbf6c129f404c5642ff31bdL?3L?3_)\H Xb=tests/t0501-objects/a8/233120f6ad708f843d861ce2b7228ec4e3dec6L?3L?3_"O5 Tun=tests/t0501-objects/be/3563ae3f795b2b4353bcce3a527ad0a4f7f644L?3L?3_uA ׃Ҙt˟nxYI=tests/t0501-objects/c4/7800c7266a2be04c571c04d5a6614691ea99bdL?3L?3_q#Cu[ďe=tests/t0501-objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391L?3L?3_Rw i A3@/{=tests/t0501-objects/f6/0079018b664e4e79329a7ef9559c8d9e0378d1L?3L?3_)%q{"t1E=tests/t0501-objects/fa/49b077972391ad58037050f2a75f74e3671e92L?3L?3_R_>4p wd 7=tests/t0501-objects/fd/093bff70906175335656e6ce6ae05783708765L?3L?3_ ؔ,vNAټuJtests/t0501-objects/pack/pack-d7c6adf9f61318f041845b01440d09aa7a91e1b5.idxL?3L?3_ tO:e}`jJL3gIKtests/t0501-objects/pack/pack-d7c6adf9f61318f041845b01440d09aa7a91e1b5.packL?L?_CS6[OM'%O%dtests/t0501-walk.cL?L?_n 7 l9yv{@ n0|tests/t0502-table.cL?L?_oaON# bW̾`[tests/t0503-tableit.cL?3L?3_ F@V_1Htests/test_helpers.cL?3L?3_, 8#F4x2<t3tests/test_helpers.hL?3L?3_ Z+DZ md<tests/test_lib.cL?3L?3_ x3 i_Y4tests/test_lib.hL?3L?3_CC@.kJ(vÏFrtests/test_main.cL?3L?3_5]@ƇZyLc@tests/tests.suppREUCasrc/git/index.h100644100644100644[QMX.pRmySM톋d4;XMQ/S8TC+psiιl|&!Blibgit2-0.19.0/tests-clar/resources/testrepo/.gitted/objects/000077500000000000000000000000001216214232500240625ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/testrepo/.gitted/objects/09/000077500000000000000000000000001216214232500243125ustar00rootroot000000000000009fabac3a9ea935598528c27f866e34089c2eff000066400000000000000000000002411216214232500315020ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/testrepo/.gitted/objects/09xQ P9^@B!1F'J?#7KJhMVE,.3uVsH-;U,MPIɉ&Ĕ׍סKO.2µո$8Nݗr!lCTklUgf0sÓG(libgit2-0.19.0/tests-clar/resources/testrepo/.gitted/objects/13/000077500000000000000000000000001216214232500243055ustar00rootroot0000000000000085f264afb75a56a5bec74243be9b367ba4ca08000066400000000000000000000000231216214232500315140ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/testrepo/.gitted/objects/13xKOR0aHSDlibgit2-0.19.0/tests-clar/resources/testrepo/.gitted/objects/14/000077500000000000000000000000001216214232500243065ustar00rootroot000000000000004344043ba4d4a405da03de3844aa829ae8be0e000066400000000000000000000002431216214232500314120ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/testrepo/.gitted/objects/14xA 0=e4DD 6ɮ-VjO6 L^j8m uYU:EGCJ;vͫ *j-1h^{,YS6.+dG[yKpN\StKBD}libgit2-0.19.0/tests-clar/resources/testrepo/.gitted/objects/45/000077500000000000000000000000001216214232500243125ustar00rootroot00000000000000b983be36b73c0788dc9cbcb76cbb80fc7bb057000066400000000000000000000000221216214232500316710ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/testrepo/.gitted/objects/45xKOR0fdd856fdd4d89b884c340ba0e047752d9b085d6000066400000000000000000000002341216214232500314050ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/testrepo/.gitted/objects/45x+)JMU045e040031QrutueXlmmAṃJ}G;UTWRQ`6Kǥ^/-*|W3F@_ZVz ڙ=\JITmX.?GhOýfClibgit2-0.19.0/tests-clar/resources/testrepo/.gitted/objects/4a/000077500000000000000000000000001216214232500243665ustar00rootroot00000000000000202b346bb0fb0db7eff3cffeb3c70babbd2045000066400000000000000000000002401216214232500321160ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/testrepo/.gitted/objects/4axQ 0D)6ͦ "xO-FbEo0 Ǥ,ske[Pn8R,EpD?g}^3 <GhYK8ЖDA);gݧjp4-r;sGA4ۺ=(in7IKFElibgit2-0.19.0/tests-clar/resources/testrepo/.gitted/objects/4e/000077500000000000000000000000001216214232500243725ustar00rootroot000000000000000883eeeeebc1fb1735161cea82f7cb5fab7e63000066400000000000000000000000621216214232500320250ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/testrepo/.gitted/objects/4ex+)JMU06f040075UH+(aH)b>ÿj7libgit2-0.19.0/tests-clar/resources/testrepo/.gitted/objects/5b/000077500000000000000000000000001216214232500243705ustar00rootroot000000000000005b025afb0b4c913b4c338a42934a3863bf3644000066400000000000000000000002361216214232500312650ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/testrepo/.gitted/objects/5bx 1ENi@k2 "X$YW0YcÅszMD08!s Xgd::@X0Pw"F/RUzmZZV}|/o5I!1z:vUim}/> F-libgit2-0.19.0/tests-clar/resources/testrepo/.gitted/objects/62/000077500000000000000000000000001216214232500243115ustar00rootroot00000000000000eb56dabb4b9929bc15dd9263c2c733b13d2dcc000066400000000000000000000000621216214232500316520ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/testrepo/.gitted/objects/62x+)JMU06f040031QH+(aH)b>ÿj7{libgit2-0.19.0/tests-clar/resources/testrepo/.gitted/objects/66/000077500000000000000000000000001216214232500243155ustar00rootroot000000000000003adb09143767984f7be83a91effa47e128c735000066400000000000000000000000231216214232500313300ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/testrepo/.gitted/objects/66xKOR0aT/libgit2-0.19.0/tests-clar/resources/testrepo/.gitted/objects/75/000077500000000000000000000000001216214232500243155ustar00rootroot00000000000000057dd4114e74cca1d750d0aee1647c903cb60a000066400000000000000000000001671216214232500314260ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/testrepo/.gitted/objects/75x+)JMU044b040031Qrutuen~{T}ǝ6^r"(1/9#>-3'Uug>6wٞOpҼr_ʧ+O\\iy|tI/libgit2-0.19.0/tests-clar/resources/testrepo/.gitted/objects/76/000077500000000000000000000000001216214232500243165ustar00rootroot000000000000003d71aadf09a7951596c9746c024e7eece7c7af000066400000000000000000000002571216214232500315600ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/testrepo/.gitted/objects/76xAj!?009o}H6}jUPPZ&Y AԛpFdpz[fYPqLJ.,Z`Ů.`v q $5+9Ot>/DE/龡W*eVdf1>覭ěʙFThk.i^0?PR,libgit2-0.19.0/tests-clar/resources/testrepo/.gitted/objects/7b/000077500000000000000000000000001216214232500243725ustar00rootroot000000000000004384978d2493e851f9cca7858815fac9b10980000066400000000000000000000002211216214232500312030ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/testrepo/.gitted/objects/7bx-A0={7!] ,X@`5ds?0OhBR&*4]Mo ȡNɾ09(J|1$pD82$"GgvdjG]j7x22]s0libgit2-0.19.0/tests-clar/resources/testrepo/.gitted/objects/81/000077500000000000000000000000001216214232500243125ustar00rootroot000000000000004889a078c031f61ed08ab5fa863aea9314344d000066400000000000000000000001221216214232500313010ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/testrepo/.gitted/objects/81x+)JMU0d040031QrutueXlmmAṃJ}G;UZWRQ°\erw solibgit2-0.19.0/tests-clar/resources/testrepo/.gitted/objects/84/000077500000000000000000000000001216214232500243155ustar00rootroot0000000000000096071c1b46c854b31185ea97743be6a8774479000066400000000000000000000001761216214232500310430ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/testrepo/.gitted/objects/84x 1Nۀn` V.`.pa Ô{StlH,_9$$cf&hXQ*g)cV~p~"Q@JnZuӶL 6libgit2-0.19.0/tests-clar/resources/testrepo/.gitted/objects/87/000077500000000000000000000000001216214232500243205ustar00rootroot00000000000000380ae84009e9c503506c2f6143a4fc6c60bf80000066400000000000000000000002411216214232500312200ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/testrepo/.gitted/objects/87xQ P9^@BibzOE5~x{#7Kfs+hMZD,.1>zO!>+*gp2}$MN4q"6_*>Z_8z_nt#lCTmAՙ,EGlibgit2-0.19.0/tests-clar/resources/testrepo/.gitted/objects/94/000077500000000000000000000000001216214232500243165ustar00rootroot000000000000004c0f6e4dfa41595e6eb3ceecdb14f50fe18162000066400000000000000000000001671216214232500316740ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/testrepo/.gitted/objects/94x+)JMU044b040031QrutueXlmmAṃJ}G;UTWRQ`6Kǥ^/-*|W3Py`%E\&g|0{Ӎ1Xlibgit2-0.19.0/tests-clar/resources/testrepo/.gitted/objects/9a/000077500000000000000000000000001216214232500243735ustar00rootroot0000000000000003079b8a8ee85a0bee58bf9be3da8b62414ed4000066400000000000000000000000621216214232500316730ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/testrepo/.gitted/objects/9ax+)JMU06f040031Q0+(aP[v L libgit2-0.19.0/tests-clar/resources/testrepo/.gitted/objects/9f/000077500000000000000000000000001216214232500244005ustar00rootroot00000000000000d738e8f7967c078dceed8190330fc8648ee56a000066400000000000000000000002401216214232500315150ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/testrepo/.gitted/objects/9fx[ 0E*fդ "W0-Ft݁pS[Yx^ Db CLhut}8X*4ZsYUA X3RM) s6輢Mរ&Jm;}<\@ޏpĀv?jۺL?Hlibgit2-0.19.0/tests-clar/resources/testrepo/.gitted/objects/a4/000077500000000000000000000000001216214232500243665ustar00rootroot00000000000000a7dce85cf63874e984719f4fdd239f5145052f000066400000000000000000000003101216214232500314140ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/testrepo/.gitted/objects/a4x;j1Dmdǎ|M3`V{ >QvL0I?!4Z=!צ8F!rsQy9]$D&l6A>jFWҵ IKNiZ%S  U~̽>' w [ DGڡQ-M>dO}\8g_ШoYrlibgit2-0.19.0/tests-clar/resources/testrepo/.gitted/objects/a6/000077500000000000000000000000001216214232500243705ustar00rootroot000000000000005fedf39aefe402d3bb6e24df4d4f5fe4547750000066400000000000000000000002261216214232500317600ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/testrepo/.gitted/objects/a6xQ !@sBQ" ٱ r{:żW9гVlq=(1/9#>-3'Uug>6wٞOpҼr_ʧ+O\\iy|tI=&libgit2-0.19.0/tests-clar/resources/testrepo/.gitted/objects/b2/000077500000000000000000000000001216214232500243655ustar00rootroot000000000000005fa35b38051e4ae45d4222e795f9df2e43f1d1000066400000000000000000000002071216214232500314410ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/testrepo/.gitted/objects/b2xA 0a9I p'1Ѷv\x{cVpvWgǎ0x[ ]"g#{rD Cot N U $?9-p+1^Qx9O\C m'D {mV(+l,libgit2-0.19.0/tests-clar/resources/testrepo/.gitted/objects/b6/000077500000000000000000000000001216214232500243715ustar00rootroot00000000000000361fc6a97178d8fc8639fdeed71c775ab52593000066400000000000000000000001201216214232500314770ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/testrepo/.gitted/objects/b6x+)JMU03f040031Q0+(axeiwg26Eo(g0E.{PbTNilibgit2-0.19.0/tests-clar/resources/testrepo/.gitted/objects/be/000077500000000000000000000000001216214232500244505ustar00rootroot000000000000003563ae3f795b2b4353bcce3a527ad0a4f7f644000066400000000000000000000003021216214232500315720ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/testrepo/.gitted/objects/bexKj1D)zUB-0uV9<#+W[TLU뒡32sRJ*J\w63nqgΞ9To*K-+Y.v29s;97 ̺<libgit2-0.19.0/tests-clar/resources/testrepo/.gitted/objects/d6/000077500000000000000000000000001216214232500243735ustar00rootroot00000000000000c93164c249c8000205dd4ec5cbca1b516d487f000066400000000000000000000000251216214232500314270ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/testrepo/.gitted/objects/d6xKOR0c0+(libgit2-0.19.0/tests-clar/resources/testrepo/.gitted/objects/e6/000077500000000000000000000000001216214232500243745ustar00rootroot000000000000009de29bb2d1d6434b8b29ae775ad8c2e48c5391000066400000000000000000000000171216214232500315420ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/testrepo/.gitted/objects/e6xKOR0` libgit2-0.19.0/tests-clar/resources/testrepo/.gitted/objects/e7/000077500000000000000000000000001216214232500243755ustar00rootroot00000000000000b4ad382349ff96dd8199000580b9b1e2042eb0000066400000000000000000000000251216214232500313020ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/testrepo/.gitted/objects/e7xKOR0c0+(libgit2-0.19.0/tests-clar/resources/testrepo/.gitted/objects/f1/000077500000000000000000000000001216214232500243705ustar00rootroot00000000000000425cef211cc08caa31e7b545ffb232acb098c3000066400000000000000000000001471216214232500316370ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/testrepo/.gitted/objects/f1x+)JMU4`040031Q0+(av0 &ֻ~GO71dY쳻^Dq?$G+TmfVVfu򨭪V'5libgit2-0.19.0/tests-clar/resources/testrepo/.gitted/objects/f6/000077500000000000000000000000001216214232500243755ustar00rootroot000000000000000079018b664e4e79329a7ef9559c8d9e0378d1000066400000000000000000000001221216214232500312050ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/testrepo/.gitted/objects/f6x+)JMU0d040031Qrutuen~{T}ǝ6^r"/\F0|Z_8]nzlibgit2-0.19.0/tests-clar/resources/testrepo/.gitted/objects/fa/000077500000000000000000000000001216214232500244505ustar00rootroot0000000000000049b077972391ad58037050f2a75f74e3671e92000066400000000000000000000000301216214232500310750ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/testrepo/.gitted/objects/faxKORdK-WHI,D libgit2-0.19.0/tests-clar/resources/testrepo/.gitted/objects/fd/000077500000000000000000000000001216214232500244535ustar00rootroot00000000000000093bff70906175335656e6ce6ae05783708765000066400000000000000000000001221216214232500311110ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/testrepo/.gitted/objects/fdx+)JMU0d040031QrutueXlmmAṃJ}G;UZWRQsCtk# >-/y.7 libgit2-0.19.0/tests-clar/resources/testrepo/.gitted/objects/pack/000077500000000000000000000000001216214232500250005ustar00rootroot00000000000000pack-a81e489679b7d3418f9ab594bda8ceb37dd4c695.idx000066400000000000000000001331001216214232500341210ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/testrepo/.gitted/objects/packtOc '*37AMS\fksx}  "'14?CDGNW\`fkorz ),16?CMOUY]dlr{#/27@FMQY_clqy $(35;<DKNW]aem}  "+3<DINZ_ailrx} ),17>CFINU\i%J7B5/РC%QK;QYC*˥ۤ?y~S7U.!7EL5ue].SO!ܸrX27*pls Žmݩ@4}`;N-Vvj%r=-]S:)_-V}E61n$Dm~]v^4I|xg6d%q[WX%hWʐ;髭Ҹ 8tCOPrd^VY% 6zg )G%O &!r: yz(>eėLp%_z-NG@' Ӿ%v4QD ɿ̎Ǡu8hPp3V?Maui-JYXX+|oCۻzQdƣ2A `rѲJ^ށ)΁9Րb-fqAkm+L=1b]GL仅 .z w i A3@/{UgM!& HZ.n}-|jSWˣ]0CF \g'pzU"O ;$b\k.$N(n!izal]3l @[5O)zsuPIt J n/<nU?,.C/xp߽aZ~sw]@hk]C<PLMn\|p"gXϋWfF'؋m1ÚKgoʚJ:| !-ij*=( pC֨h*]K@YJ{(wC5(;}鯂M ]FNBq?[if&hj_>y%!(HAìV\Qž еq0@ at|l+>/x%8e@NJ.i2{nU;:~"O5 Tun?dM3θ1k+}Vv 7SZdgǵwɌgm=Tj,SudzK-ZPq$ LX [*ns |mg-kh݂Rt0Q#٦V#{+uIϑ3 z4+cWkB Z=D]yߎǷϦ gTTҶI\  ^vE>Rq(?լq2 +@?] IWȼ( zR#䔟9` i^SUەmE$O .>o.7{Ęn yb`&`{ !qL܁w~E ҊCZȭHW dF kE{ B ILKR ,L m,`cE5pB3f ~ 1Nm0$FT~SЋd / SH2,ܙm1 ~ٹ/҄q= ͟&\͹ 'P7R cFdaKV< 0dO|Ėκ0q<{!r Y )F2k$'uHw yb5[M B׬. }g L.1 Rpuv1ȟ 7lH ~`yP dUbt $JjbZ m  VIML^&[&XDMBcVc'R)%q{"t1E7eP1n]QfmIljΎ()gTˣw9rfW  =M2u%sP{Wh5𺮇n0Âe@K+ CGkf'+P/{abU vvK(/YrO8&Z,:+lIػ)jr␳s.m=!ƾV@圉L~';K&I9}n:_edء;SGK0^q_>4p wd 7ɗ,QlmrV۬z4YhۿΟ'$VdRaZT&z1 %llV+mѷՙjkÌux'=ҙ|'| ݬͪu;/+J҂Y Ck^fw~!X"pÐ/aa|n ~9IʌIu[0ƢΣB/~LN\9Tz;=8òXޚCjRi9LOJ| 5"F\=VO㤥FMM]rlDȓ #9ߦ_o#8}:,ٟgrl1y) N!@%5z*+6qfNڶsb_ɞW2؊zHV6Ρ يawI9O5 <_-*64w<2f{ N+L6ZQsb穲S*y, ijS9qW<: aYK[67Ґ f>OcD18~M L IIaQq m@| J8 obG.36 Ħ>ا J ё > Ƽ &k_151d!>r ^,B.(!]IƀylʘU!dE5jImXY ي+=X"sX>}[Wm2"#l3޼A="_"uEyzf"nB kk1h@"><ܥ: ?x"󼗡VV{Qvp#Q;RBmP4G#nuyv;r p`/<#T]GzZQKƋ$m md}7!S*$4[ΙSA,Po$󡴕} I=BZ%no%-%%>JLee)1_%&?FIae0l&WS@%Z V jJT\%{FK?dI<>;%Ѣ }ˀ (&=s nPA'ƿ oZ, e'3ƭ%b_II''7d*jJDiJh 'v5Q,_k!]sk'x<> h4;(jx]Vd0L(vypMIo(w@Pn`eW@h(oZxHrYԲn)()(.Z 1Tu) :b7:O*ewko6 @5G*mǐhZ䱍1n *~gGBF=o$^*0X ̙ `YF+w:>9+zQMAgH+cYrxu:+ViF*I٨PG+?=9&ý#Sׁ`, 8#F4x2<t3,KwՑepW2>,0GMjص,WEDK-7F,W ԆJfKR,;9r4^,׈8Xp<8!v,ED#;P:Z}ѺC,%PjFO ,`8¾l`IH:?-8NsӦ]e h5TC}"-#aa[wy-$Ͽ_X>kSv3h.*F D=6 .>"._x HҁyQl҇!.gvt[*JBT ,M^aI(G2P!;%MF(]}TW0 2FFå" EA2ֹv~P/yr#g2LSPJ_ :s2M?YxEW3x?;1)xaR38{TkI\FB. 73E ݂3OTtlo#Y(}53jNF'Q,1;y>3j*@P>ch3*kCb\3΁'R@ݟXq.3=lTR6iP9}4:KRpѓ_%4BHn*>rX?4Xq\;q24ۥ*z# ü^v܍&'43x³~R ^#Z%~%5ivasi\nՕ5JI$BU=Q_5{#qmF h$O5S@.yʹ|y16 yxQYt0qRJ6z֞3p륱/yA6ͶfĹ6<*-ޚys T6Wxܛ3|ۘ6e(1Qܵ%Ǘb73Ef4pdt)yD|D7VIy(š Lm7 LP =y xoo/X7oIqE6DLD7?W tCG*)8=RwQ,N6A8dҪse1b70Ml8b!`0@ͽ1 S8'<[pښ9}^dIڞOLV9") (G7Pc\9X_VK16:*'g'p%0l:3dzUս0F%Id:a+;͍/#-bj:kpfKL[.m?;;T$:>d"FlIo :QN*( V9:LVCs"ק؏Z/:WrgT\ %ٹ] x;D67K|;Qo;59|J ԊI;k+8=WE8ۧ;?+uoJDI0;I>j3xPZZND;a6yCE@(=XӼM6t;k>VBmFE _٭Y>Bـ╕W.U \ 4_>3xCW[)nx;I>Y"4yV=$*+>f^իuşȶ3>`n5m>i J ?lSeS?ThjI*)[Xb?aWCbѐˋ? tIX1D ?Iq_?ۼ(܎ / h0-@3ָz"O@]Y_Mh@NRgIQ@cĪQ_+ͣc .@n?)$? II @rk\:v{S@x #q# {@ v6>ϘF@#ɺ~_A/ZL@zs*f)[Lt@_{ Fsi9R?@ᯃk&sҭhKmoA.䦧AVtLAA݃姹/p.ŦjA A ߆5g^(Aҏ8$ؖyVaA|!|t6k[MAX}\:Z? cAZpQFcKFA;"y2! B6tAD٬JC6'T]mB >_t7JB(~q7C$`3.NB.߆ҳd~%13ݟ4BZ,ipF~TbrB[<ՌzipzCJB`i7k12$XB`K F+Q`e64,Bua{*r,ҡ&MB|^pbbBE}BwP1wƩI(Y2RB@hyu1]"bCz0aϻ8*\C `NQ;N]^ζC$\mr~J}~c.C(3 PjE{GClڈGeIȝgC*˿[:S\oCC@.kJ(vÏFrD#l9KHŞ,Ö~vD(߷"c2x[D0! z<_0HDz|'IEa>DeLyQdCӷDSL®G hD!+ʌ'QHSNt1ED޽ĐCJPZ6v5EPK{^03o=*Euض24Z)yEQEBE'6ƂMTF+ӆmE6:E4~~*L"E8j( N"ژF3݁F$$c_}##s6F80~s{tڞU#kVF_UFSor F?mF@V_1HF]c6D4^F#O ID Fظe2fKb{YFwq='fg|mFB;[)'G\kkg6ZV+'4 GwӇ/YvGrm!M^GG0"BvW̏ynXG8$znG_:V@dw}!щG'2(a: *-MWGXN ן6tu {sG^uLQO:P:q%HzTҩ;%ץ;HCpmW)H]4j 5+YH.RDa)NQNIB~- 0Mm7IzC-O Dl8iI0kltGɒI^`_IBhsIhC3-:I#| E-J:+nQ. NUjJY?Oa+.!ʲDSoJeY./wm.LJ'4x8RD@M2JVV?QratjF5K #xw0* hK )>6Ip쭱KD#5}EI[K2y^FkeL;30kxd!,! LdQc赍gN՛*LeE1!F +r.֯"Lg_ {Re)L9s)BcGQLbr7y:M%vS `1 h-bgMP?J$P~tF<.9MRM[*!Qنb/]?wM`ESp?>3EMRwA5aaѠd#}N mM62 ؿ=؟3MNgi\2]NuVӘVN~`V3hN'Ⱦ}uΰ`w4rLmNYU|Sj IO o+kU7KzOU/r$]|On豳ȣI@-O9ߔ\*1)l[gx/f-f4?[̔Ixv&Cl[(N\ [a}RD\u.[ˠ@BRqڎ\l%'RQ$hmg Y\ѵcM wM|qBf]y)+D7)幺,]ef5챧+1Ɋ]@&^ċ%]y]>JbId]{0]U9ToA]蜽 C 6]Vx1NJ'ᶔD^m oyPc`^xGQmȝ^ l+t]b,d^4+/u$F (^טa̗k}ySeV7Ť _kgO#Hz%novk4lqҳhw5&lE C7fa2m j+C3m4*:>P-mdjMK:;HHmh9agRqJHm8CDPߠKimVgbǝmUh{7plSFEQn[X@.]@A%w+,n؟4UBPn+1N3MP֜Px,n^)޼ RY [n71rhIVnLކ[!c Bnݯ20e&o,)B5ӦfנoN,B0(o!xoj6 W'a o e8cO P?hr}$ްsrQzu/arN-̛W9Vy2v7s"d o4sP3z-ҡ_NjȞsc!J`s!?sV>rIϏjGs`*tr`RFsݒS'w×`DvКLjV 2-wܧ}u>x(7)?1eXuf^x2WӶ'-K;0QxE6hH!3~ xKup;D;x]?Z,"BF*Mşx'ErU̐Up#Ǹxe4x3 i_Y4yP{72u~y&͆m}u0 #X]y*.Fʴ y_Dr5]7"lylРk*sɉiտypm'f5` hZ}y.@<,p[z+ysu8UנZLjz;Oi`f>$;z2zl7V4dvU5,2{A"zu |2n} Kz-DR5P0zA9EvW枾nu{Qfѻ7{])2hO^^{!c{lln'n6GY7{ng얬A2Ճ{}9\|j̕z%m*kJI|%wQ,9q|lVM2(|)~(osS5l8 |kM-NY.U~xիJ ~Bk~|976HgMGD#.0~/!#p PJUTHf}LR kV1- Fl {(@(i#TaTW}K,Q9>L=D:2&=$]]wiUn-9NOq@b%}@AtYsGpcݷ+.jEySM톋d4;XM^.ey%$'=ؾ w>ͅopFw|hdQ5%qKȌbg0"1x :E> }Jܝ:kMAK-tc#j #Y였io`g[V;$coq!QNrW{Z[qf"e}#+r)Ǡ%ݸr<"W7tXW&6JtgfSnK 4vD—5L:ӫe,jH?r퓰@GQFOQ2Jyw]|v*흂;5L!r?GĬ̘c?ϺUk̃{&pgdcs#k뉃:սc {RSXz51=_@$δ~je/\ KHBW}-x1F<a8l,a9 ; cK44A_(Bv@WEt{zЄ,_i08E&g\!<f*a|=ɱ°kfNJl鬄#?D E߄,ɍ3S2^BxǞa99{MLɮ| NGJW7/88)d|N?4.!`DdyvF>TTCc-$5 UrUM Fvo  3Fsx|Jo$M4T7ې.iџVBJ!҆rlZ2A/v~ʚExxm y0#d|\w !meޕk8~;DwmÙ:69ah"~Ä {lz*؍f>6[O .҂ > G`O^Y"rA`=hYͫQ |6SV^"B? P6O*Y,uϽ9հ+y[ql3Uö͈D[DTmsFkP{uLX~/ Yҷo#=Is#ߏTk2EZ}npfIL38pPKZO8'4M[5et⿚,!}p)ɉF͹Oʉ)ςAL{dм؉+L>ሺ-_oD!*d8"|.JW܃&x$^|cqR\F ]Ӗ `ӮRW[/Imrs+S9M] #I܉?1fIF3ȢKʢGez<;p޹됉{M: ޔ'zeO_wM5'o\>UAm>@@[8k:ș 7ΉLgUϑ>ފo*;ώC7N\ AHM-ɈfKF|6S5x.t}mKC]kRO  DS }b_Srop=hmT󮽿Swv4#&Sh0dH/D郞 )$(j.3A<C^Vfoҏn72\ `LFy}pRhlY2Dh e7-Pк#Mu)||v^c A-D5t1#p>qˋVȪ 5𑗚bKTUwv8T}`*B9i<Í~WS_]z ~x3ajLh(e=lzm-an:ꌇλbZ*IAS7ȷŮ69z“Al+AQ!3 *l<ޒ v*O3"efe(w8:ҍ[~ MBGWyI4 KOT!6(Ǝz,Z[Z/smr济Én%-`egI|ـ̫q_|0[0ru#5#FB {PQ8᮫qD헺W(O۾ADɻFS,-| }kq%Wu;!b,0^_`&BAs"b|@v~ҴT1nxF)EnpX"IcY՝3 W3yk.# H9. cU.ۉ|ѿŠ4hOIskHwB/LdOݬW\n#RZ~},o6 uG#oIЄ'.|+x lTq8&eNB>M7(5wъ0GceWZӛR H)umP/(w|c9˜uqx-kɼ Cכ[`] k"5<\ |=Y,Q:irhV ԚzuAJa69<9!U B{h C睳<7vCWneޢ3k dmI]s?9 ! : M CV, VdJܪǿ0MקY.kkaA>ZR(FD٭ G=BGL m [Lv !i BdHhMA>`3ysw=/<V؞ρF:RmNA.e(5v 5x'W[̊F"F7ɄhvcQ";_U,Se ?jFQ*|AR0@V)}ci }g kg٬Y[oncbq񼡥^şb4U=*q MJONarpC;N h1LKJ7Fj1׋K,;^2XBFAa s:˹cd3%';#Z/R/ȫAOd)EZ_3.wVI_^*!{"%$2Z Ɯ9ä?9E=^7LUb{ݤ[;*Y5t#H-א?cmЈ2=j!W?^@m/cMUd5'@'ҳ'M[$ˤ'&A*[Vyy JsC}P}fh) O YU,R~[ab>6Y6 /-0m6ե= B^[^2c"9h \`#%ʤ*fQ`4![)D3ɉFfͨȦ})Ļ2>4DN {B3\Qpcw5"-ءk8ŪP uj2FV*dSVS"" ~|8̝\ f$~RԫLHCZopȆNUŔ?Ģ m:i\%q0ϧE_DU\n5~L%jv:2'!0#ZM %6svhGp_3\b) sFѣ姩ɲVnuT rc c9*o˨|rA?B@dZv!T+JN`)XEuG=!@@ cL 29vg]R+;i^Kl06o+s GSfwd۴?#N_3Bard'(PA]YmRT#i 4BQLֱ}yHyVl· 6yDYSSN 3|vث;a.w_" ūo0olcN<5h>!΍0Ǚ*k(cCpEn>e<M5*^|LE iWQ}%I=-Ab 09*<7፡uQsm/VܱK)zridb! /_ ɵR'~/뚰RKԩP |߷<`e讱9Q~D'Bh> d@Fnc"T4wyK0H1=~fђwi0SDu0),w*1Zt30ׯ;վ3 På̯U( ۆ寥'y^IABݰs,TG)ZL:9/wbC=Ӻga/*Kjp'8N1ن  ["˰VvcxMpnj冓srB#=5}tә XAKBuQu  >#tkBL@ ^'6ԟ}5ǮOi։7'mpnjA n[߷2>1:9m_uUL.gSv?v9͋b} fϊ0w`{` gVvHVp@/ŲJ@%CڲV%} mUo3B=1ޡgC#IF`Mqwc~$e Q̓k}j(lJ{iӳ4B;W'~Lk$N?-l!2"1aN,X4#U]*p^ŋ:t&VgpU!ޠ:=- i#q]TYiɒNqVid0bO#v)KT ]ywdġFR7{E/#C,*)N<EJ`4я}յP 1EiA9 ]~I.'յډg] 3w!j]3!Box$#%7چb{1F \޵*;v#&r(}#VG*AR} ;iv\F"AvU1y`C߼7Yѷ՟BI:JD @pOG/V4f-S撷~ٓ5pf)n,ټۼHgf_OrtkA,g@q%x=9pNکnJxd5$v ~%ɲ6j\Maѷ-;YM|=4n, ȑ)Ҙ#.HBpFj?5cdb>;gK Løc`ƞ#Bcָ+hxk {q#Dù#}nړL;y*sP_ЏCȹFPэ lNYB%!n%-K$K 01ּyNOXo ,̻d99yr[sa8M6z^@Ҍ+*/lܣ{h. Xپ??--%Y!jdb۝XxҚQ*dC#(`|~]o=3 W,n Jyb5\S@2I7L=g<]cASסfHu\"PXK6t;9%ǻ):iZCDɵ@ojSz,w{F[_ANoD®9ӽ"܃i ca<'<ưHzA[5g#ǜ3BQZT{/y8lI %bKlnڋG3`Ѣ^E^ZU` 'l62ېd3"U^x$7+_OZ1v'3S\[kI/3V΀+܃C߷UAQ.8I oc;mJwc BBL~ٟR_zҟx}?rQ zYxnam"g]Ac;"K㡘-  rF&L& YQ ѴZBFp8Trz<$);Us3zM'i1?@D,dH 6PiE, ;ؽjR`JLRLIR'~_H+py$X86/R4 9)HBcuV2کuz8lvLDO`Lݮ"3J||d!C8ˡ-2VHY,ug",v\V ƾٖ \!xb% qaI iY&Ѵ _MP1/+.5%'Hu3_QL,TzuCllW4 ѭۆv]*A 8_X`+QGe}gUƳ*~8A35+2U=YlU ~xM2G넧{DnmG☀+e9šN@C{E`I v ]!Aq弗}x]a!N2U N(oLFW+õ:5L[r'Ѝ<&h_I4.JFsh~Uy BxPIأNn=͇Hz3Lĵ/u i cG-?b?$HX`HCDP{ c0UPm-Ko1h \i\RLk:DUtnSffs¯@dG;_kΞɉ mqˬ dEꜤ \˜,5I*"L;퐻 Z}3cZdR"cB&3z=+kfQY9v_r5h?n r A)l)r:W8ly|秜_ !'PmAD5fKzo1߭{Izs%MEMu> us4sH tQ?VuFʖ&Gz#6}Х Р0h*&}mФK rZyT 66ˈP%aւ畝KaoZzY:_P'w Ǧ0}hD/TR6fUA2uYJ"i^`6{SHy ڠlS˖jE!^m]~{eJX?0#CպJM7%/P+G-^әA9o"O9OYdBOӲ>r58{EE4$@J*0ӫ4=^aދ>p1O Qm#&@Hķ3I1t,~(|9F7Y{".GD rd9us5ڢo`]Y8LF,R}!gϜYGG.r@gn"bzQ do35 kuԍQޡݎh,ԐE&.?g9e2BiԹvV?}" ԩ\؊ z^ՀKw?mʌHVpmP <<KGԸtj0?S1cjLx.EHhG^FRSYUwX ƄX'NiM/ ~hlǸFyI"Y\iklOVpDٹ܎@baH.m"0gUCJmc2'ZנtS/ s(x ׮bc&W0|3 >q _D:"~D_Ada/Bvq1AfW ENL `>ԯM +I=dN4Gع:ՇI^]g2~3m@_'sh{ِ70U^#VU >r٩e퍷 "&nzٻL;lQvRǰJ-Ic;@+CyHTUe/ަk\ rN IMPx ޱnϟy"L">y&>fgU5~0%hy[+saH pN:q5y߮n݊;@1b9"5Y'4FB|=r[{{OwEҝ|2c{GلfDhOhD_h5IE)A8WAc}߾|U|p Znvt:1oO t;Ӿ<,ΞglOtfg벾1z?VsM4vPo39äkzW/Ή'Eһ5Ts,NK=U7@RTN'0>N $f 6˹Sٜ[=ǷyEh'rķ-n6q{u'UE¾6kaPvf.`Co1$(b\)j=̧ڷ3h(Y68gQ1,blm6)ijGlS/#Q9۾'. :KhV$}8@f@q^M  ȫ(6`X^vQ4]'?_q4r jRt 2@|(WRդN?*~qU5~"N]}aދ;нG'A"@#0yV3GL5 z墅S] DWyʬ mDV2RϞ=-^,Oj"sK &tJEkn8ߏ";]8n,&Žb2gtėgV74K°1S?et^u3^Cu2KrwB\wtԪEV +\3 40B}cw!dEEA Df葛ɛvמt,#$7&@MK+ 1S},w芣g`Dy(z+2k6BMr*% hp*d6uEls""= !ܜl"r>"D#kL(k<*ߐ =$4l8M aՀ [-pEzИJhq^z-\(_G2 f[!<dC 6}1O1"BwB.{LV6ȷb/<Fs?2|Ar(C0H)Pސ, y^P#(v:C M WSF΂@yۥW=|#f ]DbW; RO% nmqO^_sfsMZbdLYrj&F^a6JzPnAӼn ~$1^55fynqt[Z'/튶/ ۳9Rez|S%?1f[4_jL?7Ck'8hT yTF{KxE{m&ꦢuV .Sp?# sVC0T"e)kDƠn5l.#؀Wd;?лp@Hs_Kn,%~ >[ɣ_jK]T/aM\9~OWtPw3 +ʍ aGaĕMVm)ˣEaĞS}$+$拏rjm6{ÝjdamBw &uuiՒ9VO} 8.֐zX99|*+FYav37K $v݂״k )7L+wJ-P#j`nM~Y0^dMZ-eAYdwBS6[OM'%O%d[u}M鉸_A.a$D[ۻo=PPlHF=Ake30i쁇L=j.}S<}%m$^I=,iGx=i51qUI4 ikp\!;򩊈3r}rk+[=A$Ҥn 8cUṾ0zTL vAwQ)<ʰY@krX!VQjǢ\.]HwՃqr?JO&N`g47 h}XG^6K;'ր.$% iq㽅Ec;lyn]-q@@|yn 0OJ@%\; ؘ!)G`~ Na,';iSж GklX<%6ώ%3z\vHǤ$WOc d)mk&Hq zbEfЄo."@Q$FdQrUA/_m9PuǾQ@a\rf SO/WcK[[yqATU'>U1 s\_3? < r3AQ!\ &qt4u}۪"3 #gv.a-] 5|XP- p8 39H2eF6å0LUG+EKNeV;H8a( ;ܩW2YbY5k"5<8:jB#pAez݇Gh}K3${ ,P(ld=iƩ|~30;顿i3c7ħp[40 ,3J(BrAZItAO-Փ/8$7JrLٕ}TV!l,qܪh:1Z tE၈9g KB\8r{YڶjU^3HHkk&UJl48w}cq/E.Wu 0qmiB9" 1{4b-@O~8ѐʨRJSϽŌ$ ^Qs*J<ɷ,F i:7& @uhEARN߱KFݹ`<-o^Hڐ٩3ͥ_ $OºMVC!!{hMbCmBalL* ۨcNa aۆrb-xkչ PnS&!x0RG?<g>|gg ^o&]mu' Y-wFdc] nB iؼjxE7k?=LKL4h8`.Qwav8QOީ؜1l)AySQC`8~x?|Z2ИǶ?pj}9 Wv9ii](Huf) [- o} L-={.dž]2ӛ6kR$h~7N;Iɶ%(24fJK\"Ucp<0'5onENW3nqۧu3eC}2iI\jU;_P 2(`#ki}zfzZt :$Ø1Rnۿ9N"!((d:"i$>Hwi搊aT y !6 +zjJyZWU`@^. lRZa@봜ԔNG!d33>`? \eňRп^`z檏+UVi%ҼRpZ73YF_JwC3mUHp{Nj(!5*]a94ӷ&R |hH#Ja(qSI_[IT݇xěZHP@؍j-@~@'4e\HFZW&e~3βDtaWcܒ1AC^A˜'Zvx' 5>ɲK;q@0J(w>&@[|SF쒚rrŃͿG[6jJQwahC?'C|Iت%RM'>)Q2C!X  ?%8ŠdžJ0 VR!TnxÈTuH,/MJSd"33:r3YH(ϴcŷv%n L6Ʀu7b"̍s b\elQvE}=I^8%!0Y.M~S3ⵜJe{reGNy%ʬЯXqM=|y/GB~i"y$W)y'EioJo/$f/PI%-*u7-? ty٫;M@u%$V| ^5pnCeUiR]7[[Ԣ+F+Ke˫_r; )oR{3) ``<QV`MhyGUAb-)mF(c `< w*붾10f%8E9$ fG6NUPSS9ZvPjFg4ȇo:%vXz룇^\ow/HfzE.0~=%9!Đ|lvF)Z\^X }x+y$姒 ]epGQ nNc?Ё</8%š%/ S%P7qWLhW9Ttwb iIGdRwdWolԝү,BtN;X?S;((ڼIRY:+!lR 4Fr]X3e,P筚E۠ݔ6c,$ Liϡ0]6JV jR*A'dKaDG ҏ`ha24bT<[&XɋIyoQBQbtTxdVz/ږ(8m~>6hcXbLX]u/mB}B[  $z,c=n&K-lƮF_a݇i؉[[,z iv9ELOm$$[hGE@DsvCѣ6/?rD՚~Zh:FЖJqTaΝe1ETJ3jC߃(NW noO uvJס&'}N >. ? !yg745!5ȿ/؏qbM 'qnt<,`5WkEXl^QoMlZDOz7 ѝ+o_D'aesOhi>>dB&E7oBJR]IiV=˃8%\7{|~^"/nO?J-s+2z  XF zʸ%EauG6sd],rWǽ b,LB0H ֊RnnR}ޫ!m0ԦAzAҷ}G!X!LYVt"3 =J)[Ƹk G#@ 2NLiJ/Ei؅rfo&Rc7WRݑi>ofݙ!-N9iYk)*V$*^~Vh|*wӍx^$YǚdƊJ\kJ6}|⚻~{dW?\2mO[_X}_`Tݞ)sR$=6 ޴ Թ/ dw j WbyǡgVaϪU,q#+D5$(d:W"S}YdʃPHV%2q&ɹ]nCJvSHhh-؏trTyh&[.˻0TCg6A4yeUCh240!u`x׍7A,TF]~Ms56 2 T4]}uWQ14\l Q?2UPW^rpr D{?-ye֨%pugY6yUS=hU0.xae˩l6du/dXm#bD 3=,r^l|zENsf<)£~Y7Z5`GbqnYHq48J JXV#-EI x"66\r%*apxc@d1MUgμx{{jTj82ycr-lmfLz(;}4] !h-:-/"3w@ *t4Jk-,uqC<ʶ`, K,…{VNUO\ۘxFp74:YP^DBb9lH%,3tV$SSwN1֨m6iz>0#yt煲oJ>\|7gI%4-%T?Degm;zļ#c,joπ'7y,ޓVHo_'OU&;4w)_d2&q ȵg4ˡf׭s= +w9!奡=>~/p!AubƂ. :[71)(7Y]yj"r8ҩѬ{8t6B)yn>ZZy (J#0ʗՕqTT@ZK\'8Kd ăU_!w>Wڔ`Kjpy9=RTPyts,s>c|lhH`KBحVi5\_eQυ[6AfM- 0tP(|)B˷̊"M@$zwʐ769-`ЈPg{'x(4{+  Mri)Aފ{r/6~L$L79[4bSt$ 3ZqYݸ4ykq *ZJt+Oi EfYmJaBr|}@'#Q;{zSfE})Gf' =:)Y`A(%R6nGͱlM^^-_8u#ɿmnOKx>wv  Ж !Fd)vzRSoR!W@~H9tF/x}3JEѡE Dx|?.ZAd !UQZIFqFvD~?'N AQ\%}}$iy(QȞqۈ}aURQ~E@aCKzp4y #}E|Ab^odfcNLzfr؀ӥl. 'c!nvDExFxR$xFbNnFnDR2;/^z=VW[xN&iFWuEWWvp1bkd}99Wg}rJ!yG[5(i`HKl|FU_Cy f-P~G 5+O]'Y{).̊ Pyi 1 Q{#X`{+Mzq7wc##A/ܪq+=EIvHkmr ֻ^xg|u{rn10`,aQ&/d{_|}<0gL oK"@'~fF*\ oiS jzBV*4bU#} %`7ЊsF7A`8b-zٝRĭb#iGHCya Px%?KL1?@]6vڇf Qy^- >p'\[6. m$R8yM|&P.OB?`fmbi:t2fm`DP8WrVO [+tyOiwN*li1``b000It VWK~R@cӈ{N|]P(x3"9Fa!%4:D8mj?>Mhߓ>>?IprKYg06q{nd(&<[JT_qm;rnscd+`2SQ-ܮy%}! e}Oq/?DP"gc\Mf>ng[Ë09p^~gSVrvüαw}Q uny}Xֈwza2i8T[ YO RXbYZNdMifQv `|fVBLFr],1X2 ?zV0RkOurWtHb<QH>3_B?B~9mwF^A^3#bFQeڴWyzį.,W[=hAz.VآvW*csiI dլH|.."%&LJiem[pIfh69|4[ Es#B|uO_/sFG!lw CLQ̓KivCbzoQ<t{p{?D"s<hO<e6Qz$t0IimOWWIevq@V vOV$=^4`E6~tvlsK n7ZX;wV:jFYU ^w _qgOTWaOЦkz.asanu@g|=Y|5.'^cOqx0 l0P>(D[2<jeGڒG|3Q~)lSjzdx! VYZpyzDllv<P?MmPvo_!JȁNQQx?2w 68@ #@%{/2,+[ItD`oK!htWL#\KtkQH-@W‡]oO&K O sGvd9'v~&,Pbn^V%x\T3usşxN~?O5B  7bIP}irV a+>ay{-4Zmkiv>ftSowhF\I9Im0keuu/,1H=Q}6 JH=:1pUWDԑ$?t~M]YpxKR[^EtL425{A?6\yqA{!!aYgN)#t`bJ.|trwqfIwP&'3 bO='{hpQ.a0?1n{?=BLkX7Y92{ZM.RGsW۰TL)rRb8y`DRE7 rbFnEm 3drv$TvVxj<HMw0e_iZuj3zr#}oi0KP&S:x.cK,g<'Ps4Za2%@ro*]}?&yJ<t{&P N+m`v<^M߽¥Q<.pLv,vQER]G>>%=K{6(9$ACY{0eHdZb{*yF E *#~|@skmsj'$Z?|bAwN'/.i|n_o`qJrzm@3x=/ՑeuM8&XTZ!2\u'(uMd|vl3W]xhM|a-ATVQUm`/ (Wk`=gGfИPT2z lyfq6@b9>EI`I,G_\e5dQ RbLD`-9FPo~c x`vC0p+هR0QnҗY>zYBd]eG&o9 jX'XR< aJb Z܍s[, m8vC|ȍ!JT;ysp[Ol "b}Y| 99K* -uxDwbpack-a81e489679b7d3418f9ab594bda8ceb37dd4c695.pack000066400000000000000000013620511216214232500342650ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/testrepo/.gitted/objects/packPACK\3xRn0<_hPDFP{i" K@Ru5RPcȻ2x D쇎.O!tTAGrKdBVEqw֩ny@/\4&|7w oLўw|'xN0EuZ&v!1i&ve;@lf1wι@(ZCB3[BV5Bi-D#Bf\NQMGo%s9oޮAq~8=A{u\#|)TbEo(;wB@d)Ca'%qr"Z3905^e\FmkC֜ěcScmY} bxVr6<_v+W/;J{!9d]@r(!&-+_(]_(FO̐lyvvmEZQ})+Z/r6i+-i/VUYl5bͳ<-z]U})9-7X*8wi?{sˡyfV)[fYFyO?Ynײk[cpAytIR54}:tD8owrBjj= K%+SS 94Z=?+y8)T;"8i P8@^ (ȵ2umNJD!څJ;(U&DN,K*4B)>}2a"@uU:8, *I,jׅ<앾 甿%Yԥ8Y7E`][rr|}awM4iB( VB$ VY;9J`p+ ]AG`>|Eޟ0@])X.бHXc34"?C)cA!xmW)K&U-ZӒPliܮ4MSӤ6ɀcgy d;$W\Ⱥ/\AðxR(neT@U˃c[ӟ_N .0< :1=w-$w}[ǡH?MF3=O֨P\9NW;1p*s8:.XcT8PⲧR-} " P<3Dʙ#x<if)~i)py"70!;(,qٌdK̋/>̰\l `\ZFNw?Dܶ??{+-xN0 y X`N;aWpbuN&Uꂆ'EղV‘ḪDMUlQխ41Ql[lpW VV(l++TiS٢j^؝knn0alvRU)\R3} UJi7T ¼LS 6k3`@0|'`>YÀ OO !_Fǀszv9?NXsk37=BM1^3}OTݔJmP/18x1O0w:@#q!CX+cĮ+bNO}%D3-m_׺7W#)P`,βN֩vC+rN1})&xfDIyzj J5 YqOJ({3eWaWфτ!/7l|xVm,3Y8q-d x^C̥SU cӥ3\d,Zob͏6:u7#x DZ0 Ђ&`Yl C!_e.DZ3Lu^e?` k QE"y#I4s3щp +JVY$Ya3j^C!ҝ/xR;o0_qZ$E%0!C.(IHE A{"t@=(;T]W}ӎn;p7 u3(n ۱Уp۱FƗ4?̲<$wq4ҟд|ۺfMJҮ_RY)CMiF8~{x$tx1.1BL>"|)4m,4.XU$X5t*^DI"Bԋ'qŵVk}E9D^[ƪ9FX xyuҟY/I@d4L3 ˳U׶69hc6g&8#mMEhy'i1g 4t]͞t~~Or!+d 8<ޮ7NSжE-2Lk~w,xn )C5fI}ZU0^ӵt߾JV/ 7f)p!VFKijnFʼnM%=-> }M{\U5 uMIt-9>Od9yD;_My ʺ,Y6%ڶM% e_b| 2RپBgoE ́."Xwlpg̥MW4p݈FgV'Ԛb̚RfmJwk^1٨N1.a W/Yv`q,y{60Ȉ!_I?dY(^m@zQSr{u|EJjW9.opH8j#O1`~0#pcp) 쯘IaXݿ&e?.&ضNJ $>of}L_wޘc>Lgx=O0 o NI 1!10!;Z&$G lzvD%aO֡SUZj[dWiu8b${W;RɮL)*mH72!<_d3CFaF}A+;Y5J-ت3Lu%|SJ)(2)e?z K|[:㉒/? lB!r:l)/! DKpVa&Ė 4_A>,pHqZb9\F`~dO7X|;3!{!xdwY#;'=xUn0O}n*aR+*ؓQbGے>U<<^l~7^`7v xEHQ՘D)Ou+5b[o̞Piqak6'zkPtLXP*K{GǸNyɬguh7-fŲO>Odq9]/.kqqM:)#hq_S~eG b|T|\6( xMK1EͯxKE*dt!ےil')L[EtQWsrB) u6ҙZqFJQ 27Ȥd VY+[wW E[ kiT!29Q ޽B\^ͽ#TLer\ qAZ'}@ dVim1ep>B=XJrBCsB&|^ onr6GW@?gWh@&̺\_,L%/+9KD|NsS}_%txƱ 0 0 vvN(I40iʆN `O;وQ 'R%⿄N0tozd2LՊ XsHDP?br圗}q!+/xn0S-) d-zjk"6H߾Kō\R]( gLdQ׺:5MYlqPUuC+,􍑺L)f -j}Qj|Vj}˲j+ [K: ׄ?- x j۵}-|.;ٔо{4gT|2>$0|Q[4=#E!~vozr 1E%L4p@s90Y7;6>}ĦGևӕmBu`2cA,0./YGc(G)?&pi'jxui;Kq,A8AX؏qkH<%qA}M]@i"&*($k:y)q…JCvk J9ZtЙ;e4s=9l.5]Ìy[iga']\+ Jp#uCcv'6׺HqrIX3:qnxaVOC2oj#By Oʹ9>δd9 ߷&~Txαj0^_} K+K!NHW>qg}H?:UJGޑ4gaUK]+[^:eɰ?M&Z᳠yO,CŤ(1 &3 R) $b$ˆ 1_#Vޑ. kyD4 g|zqvj->E,\s'x߾I5.4l=='QC8.ғk5ѳޝ88!urWImq "cKjI6@[ F,cj!\umƢ2|vz4XC<8僆X9uQ[*[0N|r1=_4/S*66 $Kj!oYw'$ʲ=_5n )!ex vtc:ڦMjKY UR*5/=84)*dR!{(!ES c1PX!VwJ@ ?3{₝S>.P ahW=aw]d@VG0cF ] 9MpF簯U~e.ۿZbz+$xQMo0 W[ԉTEwڰkAɔΑ Y?:A{QRzݡ譋k;j!6x-fBI7mMЇغCﱋުԱ]]Ww+ axLy8!OOOP7GXUF'qQy1 CsӇ 'ɰ9,`lŘu#na2p~8z0I|Y>蝵){-$no̷ u'X$2Ҫ os0|sY 74*qy{)+eXyC~cÿ~8'xN0 ),Ciτ<'$M-&S 'k4ɲs'5R뢒lTYTKEXjT:d Tb=YUXJt՚:Ӳ)MfeZUE)pMř==;c }|Xw=dyY(U2Ri_huoT<-2_06nF͍c!Oglڷc0b@xobF11+q6W2]NՅ5,Isunv:|LÉ/}&Aw0&[<9;$+\%rwj13% cO?єlh~8C|v@"ZhvK|cuK"xQKO0W̭j$A*BB >ǻ&qLXz3xպKk MEZm]kQ 3 Y®qNW:ijCU+]*.exn=`׌c/¥TJJQ^Lߢ\֕ Uw0Аz qa^" !gld)-g?,q ai/O#y21cb*۔ !FOLoq^YSJ=aޥDqk=`ZB:_b>^)s:)5ʈa[(:Oq[blR{jj xN!yy۰c[3RhlП L3|LDJJzݪk+=z/^;W\i΅l+봑Zu"qCH=vЊNv^*1˘'a8OS_y PZ^( 8gU݅R(2cgkWFJ5&>DǐCHي40\ SS!ϛݪ3LjKcpXn׌Ǵ-\Kܦy{E~aΏ-xOJ0+>Cē7/*^en`J}ڿw 03F\34 j] ߅m1:qУlGhccBC7j3N+yZ7xI7NpØ׷n\0ͧ~]nAַ^nZ $fUݧO-k, o+ s=0 Fy"mk= ^y/%۷@mv,};Bx@BTcY׹Vod0xQ~<En'aٻBb}jVvM-]˒)?6%_^H!&Ak@8]m\N2C ɫsYJֻh#ҫi:'p8S\P,~]]Ho耼2u].q?ExsidGʁ#t >L>l CLC00O 7:Yt*L%{ar# p2,t\(}~>N4,eđmw;u>ߤc/5q绿}&xJ0WnIOi^)ޅl3 IME|wӮ̉oLGMT Bw)+ Ni+Teʣ !Og²E]rF0:MQDMq<BZJJ1e#&hGk8rD \aB-23VڶryJT(8+CnZ#xn <]&J{쪪H)?ju:#`N>'u88߹#R!ʦEv3X5-mӶmUJvl|[v*ɵ7FBZUTJu>!nGK\vߎ( m/t((u˺m Ιۭ˙> 骦 ¾8y$\3}}gHW1S"ଝJ`qtѳ}t&>-۠⳧WG0<=bl>xarw!9R< #cq$E7,EL9Nɜ8ݻYkW^<ܖx;n0 ݧ^Đl= (ҡ:'D*1K>E+̠XtX !)DdԭX85bdvcPM(4ZhfRƑι .oW8dOԇ_AV+iNH!en <$*j Ǽbuv=< 3A]1ͧĴ1mr#fx ;0 Pl#LMƮg8E8vQ[ґ!q }wo)Dr|V̢"Y}qBJqN̑:E$i󁚸s58_/Pאaw}*ԓxνN0Oqwv u+;-퉀1;:s%o=&J #7BQQbrr"JyS쥏F`G%7:v|*^/%S]jTrKw;?h,i*!ɹ>+%$MZj Up4+%|QeUt&WsTU2b'*yFJ`ʢX.t6utCc|=qw~XDcgMl:,_E(f)|L4v>PzpN%]x<=g^<{ CLZcM1}E:2FBL@mrG۷cA8p 4(VM- k ɀX;"|;-xMk0C.I(gC{-ҋ,vؒG{7-R*Bü>#M 04ȅU-[Q^}N^vm^5@-Qu5K8]N B1$(,Fx|ňrE~}RtM]vU}x9SnMJَeO7EċUՒN}0?@Ո5mxl-T Û,N2Xc ~ &L鈠4eeZ1*j_U_`mEu2 1Qi''#* yWHj/JjBLPS8nΌ gr@ wuV"\Cf_nn r4L&^.Dh\ä}' s,ֻaT)$j'$xQMO0 WfkjB Ҕn$eۿ'0>{~l"m*\$*KDUo⨸Uh<䓪PDT(9rNqb#729%Yx;'f߯$')$N9\I3E}G צ(X#3sZO#8s\pVoABM]6mZ OxN];7m~P&4J DEcgո~lu#U,>xsdAj@@` GAiOCtktkv[T1|5cɞ%5e+o_7DDxSKo0Wzi+vCaW8+ʱ'!Dm=tm tFwQr749#Cߤvq;cUdC5pbbl0 Kv|ʭ֔gΏ):E>rc|KWOGs Z[m">'Xq"xN0E-%8NQ~[Ǝ<†b99!6RRoRsNhM٨ mk(pBJ#ļsi궫Ӷ25MLR{x Z^YbLk-pQf&P&obUEEz>k 'PK;k7*!㺈 xI=ɖqLHyG5a!a,dU驆ϛLe<:C;5=ɹ0CL8Mث_ѹKӿe_Sյ#x=o0 w niQ#[ ҡ: IsBϒ!IߗwIv˗$g"hƶFa ׃wvj"CG`Z;'7i?wMn|H٥|M ukj%ڧzuM;]3iOZ,2|/%Et־.ƍژ^V8'L5N1ȹLJDy G~9ԃX]R&e>Q.!i\| O>T[N0oѳ"نn+U +F+IRV^V,T-xVdY7]HzR,wtVJ Ks{]W=87x0~Q/ݒNT Z@bT96DRIU _bOGSz\#fz(.|U^ytr)*)si&SUTv%˼.4RT!uGrO']-5-fe.2*xI"4u=sƣ [9W@} xѕj.cAoL;Z 7m;vB|r>CI6=ږxVn^G>-M9L 9xeS& vЀuq~l-fb'o5a{L{!XnS8zռ4C [6tm)|鵊KM)DxS͎0)ݐqV Z@"&;v3NKV83OJAZBڵĎij)n%+6W6 [T˶jzѶRr٬Y*QzR)8PnD?z@F8s`H C&7*|ᓋ{vn2RH^%CcإѤG{4tSo0g˜p;n}mOwixN1{?*>P@A HY'>H((ΌjJBsf=3`tRQ% :- 5bQ)k7QS9Oj 1`mrXcq1nהQJLG_ & 6p9*cd$弫\[9O㈰~ЮpP+_+Ra y9`u43X7Vx*I-A c#ly?s+}_xϕ$xk0W#Y2Jc5s,jKA:7?[188}''"X7R4`۾];ܐ1nzgAk'LV^9= TתިvDr%S \x qx1Pn9U9cl珠֬UK%q=3%3'osnnT~s.\ ؘrb_3<B}xL3\K*Kg hSg#&#=~?|{}>=^U4 ,./pN}8GX )Zdroc~0Pq(-^N1N~"pbyIT @na_ܿ5xN0 {&i 88k2%boOa8 Ne}EY vO Coޑ Ov`0eXp@ƞGcG+:#9Rt)-.p-ذ,)6>5[FimO2*"gy{C:ȏmuSKy;x?`⏔+Tl`=qס䜲RKަzʜxνN0O5ݪBe```BbSĎѷ'&XΧszC!䤏s-wA ceØ&DhX: BkfEfs\E)\PS`19JlZ}=C뙞;]4:S.fLwL0Ftνc%6>ֵzE+~;eǑyi#+82ܠhJ蹖u %㡦tWG>(oxN0D|p'o D_"OSߓ* hg^I@Z[vPV [y@:SPZaSAjdgֺiLN2\gJñPi\{;ZBȺF/2<&orħxn9٩V?\|$K xyzi<݂0kyJ}Uv?|ODrxN0EwQ#qU:0!=9nOP`S 3'1uΣT՚FbĂSI'5}ש`Y^ `P൞s迱,5¾b4c4>O4u bKX+8&*+<5'#5+9NNil> 3&45B)1r?BnxN0Fw?Q/Y@boR bG )O9:24x~NrdQcpd{?TFXrn2q$dTQP; )*Av)=Pm ryk7w-*Q%9V kd8j9m'y)o՛</ȝOiwevc__)9fx1O!{~]޲-ɠ=Z=c.+ 6 R%+D'8tr<-{_;䤜s(GA(6wIs*S|k%ÁXVoie&-N<0W y:L9/kҶn~^B _Zp{r:+暨2R My>̾-trx?O0wJZ9v;Be jS.oׁN+zh{>dIq9D4a & m*- I\thAv@r =b*vC<~ښ8B#T%k.8gu;R(]0}&`K^uB}؃% %.q78XW!HBJ0؅^-Z}dʑ`Ts& JbZG.-cO~ d7ѹ~}ax=O0D{EQ@GD٬s%v8{i<ͫK`=g inѱ Y ƴ,V,*X?zizPӎ$Izalwz"}a/XjsŔoeZ0 ZtKJJqK <0nT"m[NpF4sF[gs|j^H8Ö4VwALGBL29qJP@GD/Vrvy{.@Ejl+D`0Ĉ@ё=:z˭\GxdG,47pK/5IuFp+|QN]cxj\-%4'LupazDױ:֨< O%Z m>u/O+c?{N4Y< 4Q3uO\pukgV9ƕ?+}sxN0E{Ŕ Qlg@+QR!1vclOT3έV+FeNi$i [FD/.&S@%bc(YGRcz39cܦ\쫉t=̋ ƥQ="ܵmŚ.V}&S9WJ7tHl }yOGg]5,%o 5%T1~ n8"SMF0Gļ}f (xvӞxMK1sSQt A-[I2mp7)IZx03)Y麣j\VTeFp*Fr :J4]-&bjDդƶUSZwM[W(ܦh;v#CpOY?J;ڏ0)E=]UpKY6% 0wHF VKMSDM)#dw`@;mf\_0X\]/Vwr3>Z!yHyI 3D8m XAVOD4Eihxez-]O=&{nr;So̩z=@Zxj0EY&[!deP1rDmJKNU=Ü)j*,}Ǥ8mTu\`mȬ3sתF7SRN:*rƠ7#R)[7YPtL00V6MP)xi]5B)]FSvYRcyL4cqz{I #PmENݢ5S͈_„y CDKu_N n(xQN0+jfs*"q52N&vdT{$nf&8DB4ꌖ-BE(/xKKʌ94J*VVu5jrVgr^"#왹aRaX紬:opYF":HÓ{k`pk*課UN?td'%;Zf$<6#}Fդ]`>ס`݌uts,N='?+6*N1 Eo8Sh~!.|`|E L[K6Mhd.h•s{:}Ǚ8$ב I {ѽAJuDfx1O0wQ#۱UƄ~\R]ٮO`:c=JZRd'5Ş;OV^bX-Zo!&Vz}vRڸ0 s{\+tPZ@ig:m bVpcf,pʁJIȇtM;gMv?x<~J!ΰ-9BII!^yܥi e'p|nU&x?s0 w~ lrq%$Kv^DԑT\P;C2@ID `T(VZ-xo;{.ag{fL +Dc^4mNZ[eL1ZvM.e ~9~`* <t~+5H߷ptMjJO$ ߒ9HqLgRN]}o4ꉠD($zsU߲p9/lj(aqaY!wnYÖuft"|n5o.A8:!#TzX7lߐ Ty8.ٟG4dg2DuB h6KZtYv͡x 3K]Fkog_я;f̩xN0D{-Ah#ۉ{BھI,6vx{̣v4gLnTo앲ޘN9B(X9J+)8M+lo{J]=*u{2 /}bKC^/ipn\ZnATZip9J 3w9mKHǴf/NUpyXCpU{ q x&Wxn80H~qg%>l]qRx=O1D{QN_%% 9; =vfp'wbĤ4uQ.&hBT賕↝*Ct҄@*{夑|"eu18%}aعtY\GPgZJka;ဧ^nvYaie_`mW$KTʇ,ߵOQgx=O0EwFP;Ƅb?']َON ^sN+D`s-^)4^ֺz'38b@^GD̠xPhuVbd9x {"sy0Bm[ a]9锯ͩ^%cgCͥB۷%V;߷θN6Sͩ4A LT%/7l#s]a7~]ˁ}x^zxϻN0O1=(=vVhDBBۓ"#[,O^S23uWL'i:nڡm;ˍiRXj%Kd!Sʔ2we/K}>Nq0W.-OдF7Pu-.J 39mKćb͡[{cpG2Z\לVB %>V 氕J0F4 ;{~ {-xAo0mnV*CC^=,n^î;C@üy#]sRż퐌:ӅirE13J7jET*WmޖJT뻖2y~9Ⱦcd>N` cSժ<69|ȏyIurHKt&!CUWWje)o2o~0v8ΆH q^D 3\ׇ&$q#tI0e2%' ܼI{i&@*[\Z|/Q~>1[aXvik ! xAO!9j K5FCaK܅ iVͼLq#m26]SVajVfZIEhcN)JЂچ+u׭mZ5]bvʇyӏ K{kʪ e.gMD9:RV _&y_$_ m1xRMo!+F䣍~'QGꡇJR0,_:n&)B001 Vebm6< :QvMdNj("#sh9fYyE+*eYRYgA1J$l &0cz`J/n!MI;,#vP!/Nqסּwvn*Zxd)dz693$lFk38i T‚2@=ONe+{| F4INPL'Qe"Y%`{YCydeA 3Y JjQPǥJ2YGohY{ q])(kT( JgUU ʐ8‹{B\yuFTÊx IZeuYEqQ8la[*rhB1oyrEI+w Crut" y*9"dr#&)6sdt7_HN`|Ўن0r]2sر-"D^Bnw\o Vέ~( ̷&d+a+k>lx~^)/屁7uexN1E{(+ۻ~EQR@GD? ֎l(=+31Ft^ю'1D-O֛x X9w簟'2ZRv4p$9Τ \*<=` syYOrNR.wpTZ+ȧr5C/LmW jthF3D hm;ƾ'")v¦7p$ {T,'eUÔ[s{t<0q3N*"Z9]0?}H.ҋ6l?JH 49Ҧ@m)yD wU'K33Ɲ&,m׎.%$#UR$I^{Fu/ V;N821Ω;Tzs|~*`6x)Ug7YTWm_K~2xJ1}%L2i .Ap' $C&UVqB*@TGd E#Z=(kČrG6(+)`Fѣs; )|eOX[M\~tZ2݁C(7RK)Z +5e)6H2Bߝ`C2Rv #!pld!^>S\xM|mÓxKj0D:E!1KF}*^}8x˦ךz츣N&q(0 dj=N{+ޑխwFbOd[ t *VucHy[ט 3}ɤ2aaz\cBLW`:EOv?lxAN0}N1JF6P`N0.RoO`O6҆X'&3v ˬaV, D"YrJ삱4.] |R9I}kGeɩ_ϯΌΌJJu%&`֜`rȫsJ[kTC!\6_+g8"xCόܽ{TN ]B_I;l[UpPx.c<oex1n0 Ew["([2RE:C4E%Bb) } "& [oN!L=;FԄlF8<+I pqXA ~{. 4 )_9I}yn9sw;Q;7FyIP֜`OrWUyra~ʩxvenU &K6+۫W0 S "0TWLJeR+k,\xdhuH]0U)Lܹ5]t҈1JsjmS= 9}Ntʖwr הQJlP+wDtBR;B^}x9^1 !89z@vejLeґ8S3 SٟcO]6Bva- 3|E՜xN0EQ7Ѥvb'N[1NMJ=)eHsLt]qP'T 5jjW8AjsJjxC%\ *]e&jJ8Gup{z[cM̧#.JYT{(%&O W5Wu@;_Z0TZOa:ys`nKs}"fu))ܬ$47wb(0xNvQü@Ok9! h\O|PӡL%x=O0w Fq @]eGZmmd;H{0Nǣ퉨yosQժFT7d#PռۢżD5]mB 1n5~qLLl/DQ(\<ϙtRUS;fOp7zIYǥyTo֫c/[S1@NEH ҽ!@LGe06q_3xJhHc-U$&1b.e &)DOonj,z\5o3xR;0+F[݉Mg;!@B; DWǎlg./@5IZcBִU%y/Z*ۆi]w=c-y>ԂVMk!贺t-X;ѻ {—lB>%~Rh|)C"sC۾EE0M6g$gmww%!M}:jXScShp6eVyȟHȻ>JpV)d8aǰĭ}7l)AQ[D":cw"|. #֡;cÀsȥf*a;9wsKW`r]d~ſ=Qhguj6;w:3?ncJXf&^."iVyCcZq 1L,c)6ά.MC *V0AqWdg;vqX-Kb jq'C- P\OOڥ-- ?ƻ]Qsَ_OWYww{hqFG{{U{i#>JBN7^ /a9xM0=b%٤IVV|+7V3iT>'8D(Py4]*2+eU"ydvܡ ꢪ¢ODi/E\Ue)$Cc|#|=vǯGI쬉H"MӲx'q̄:IVfyMקAM@(G ܀667"hk@FO=s@.T;IUۅoxB tn[L=K)"I6'upVȓE 4%t04Z4 ,ƳQ@޷aM]:# *8ng]82^[ l?׽n)tE}ݞx悸l鐽[n6= !$6~ 8FhWٜu\8Ky ak 1mڟMɴRH+0bcSk^oa@۵#9 wkK4'1(VE=_5z0xA0sbIWp c{Xmv_ϤJa7yߛ73.Su9+YF;akN`gՄBQםڶBZs(b=){KcYl \gЈJcߩƑPW8!&x 6f9x@.#ɺ޵[ k>U&/Xt`$3^>Z:o |6gʌ'ps0ǰQa+ G.Ngĸ'\v,oulVD9 f vq|'EeqagŇF_M2@އ?xr$u.xf~GZΫVFky`VVjX픪qݨ=q#m1S9GF\sCxzOZWMJse)zyZƎ`h~9א:4r>'02`3:ZV􅎬cDkK4ZLX]҃B'OWE

s :u0%t4bn^&%2y/YSǰ&p#~2p+8 a4mt8 B pYc?7 kxBĊFgH0aM0wkMBt8_}M}Pp68$<]=9xKn!# DQ/|A o9Aٙ!,c z!AaRlt@;k: >⪝ie&%,04'<'D8op9 h>}VEp(ɐ$[IWkì€Csޫlon%x{Bϯڊi5q94;");{ۖ|Hqѻ}'Y<^b%Ǯ}F|9<%_DXAUh+.{'wjtT2xЧ<85g2ӓ84R{[-~TҠ6xPn0 241lٲ( tj hR}r!H=%mT]CSuiIT^P6⌞lYkR`QcuXu(,YUS/\^Y Ѫb¸"_m'+\¸ecԺ\EvO'f1FCN3;Bo&dM汏I'[pB2BtZp!bvuz"_eW;7D >6-x>ݒqX=-w/%ԐxNAN0sGi2MBp/$SZZxb[-U6R VknN]xc9FQ#'sBm%eg]RS]ᕗRl>RKj HdwJuY#ǀwD= \lu6i8~%ĺA:I:t\DoRo{.^E}#o4xKN0D>ED!زk ')Z<:@KE{&"z1xjY  #&d>ftBwNh[63Ԫ,p7O.Jim{9~VJ^W_zJl)G&*hs)R/\%ZJ?'nxOJ1+.;=ED {qAϝtI,2~Vԣ0V2c 4hii肕C kuqKHa˨|b0+k;^pZpZxꈧZT(W5 "iʭ?Czo=< l \ [|m#mc>"1]]\_"Fnђx;n0D{bH &9?K$|L3b^_HQ0%$5t:8+R44Yc 1191YY 3oʍ6x\Oᐨr" PcPJA#"ZzBv"r^Rm_^;Zܷ^ xAi_G!>ʩQ:p·p;F|qux;N1ss#ۃڈNO{۫Gbn/)URonDWi.JiĤyΫF >7jPSJe:NNZ>I>/so4aĒľGҚuUZ)_cZFP9Dg~#| T< ; ^˥Q:OYdxj1Fy/q̌( hI$C+ vfкDkV٠m'RX85|ЃF$#ywFaPZҮNWؕ;ꈧ:7TV^R59sMsf4"pJ$$n,Z8獕Zhb'6*HER/)xyDK"#CmkWoR uxhļReu>A:iji 'DsBsBక ̴cpVR9uq靮!coThjξ6jؐx1N1E{b& zm%3NVam䝈 <}i̐GMt.ǝܘCO6hTظhΑ,by7V{i 6R1;m=*<ɡ6xy < ܵo{ϵlRݜ`sFM:ϓ3 8ani "j eeT \u|JL՜_'.pxn D|*`0z=%A!$_+siv"GhPON 7I 8hF8bg, 8`PsՠiB*4^õs\*='RwӒSrV O|syYbkObB? -^`W!oXc>lbi,)CKlG 2yr|{{pxAN0 E95[4U&iF puf* JR =__Oϭ0qJ. DAzc)&zgؑ©ڠ';AMCj*=5]r7\*nW8n%r~pr<1C8.M z\{iuDq rpcOF J;uŚ?χ2O_dgdCJn4H+նm,)yJV^_xG@$kyWOO3FB}fZVe{lX xAO0  [iBpH'7qڈ6 ؿ'$Kd{Ijݔ\ir UD;ٸVnT[1c-mm+v#5vbV5V) pρ8įCa8ހTJ7|i)?!u) ݇JZ@>#9! G2"ȧ䳙σ_r۞L^peFC08f5=Ƒp—7=f?5./a/rr 0G~VB>`q;γf nVds. !|^syOxAN0~QqB9x^%^KP76&b2/E8v>"'uMj^@3 &kdP@ϼ|S$kclfoQk])H4ͿY'xC(rh9ҡQꥼUIÍ 8Q}L fxNN0ۣȁ  ꍽE`;r=f3iUg{t=`&O2 Mj*b3i}d2Fo/SΥ3/XlpS.H*otOp%5gE%>u-A<Ӓ^av(I-K8O'fxN0E{h#+hBC~7nld;E͙hn+ # cƣAis\!RzR|؂,(e RVs-"H%rح͹]1'p[!]IFI !>S")B_ y- r \v5"\Wl kT2DUNtuUbל[U4)8c;|"| ke;L]&}6]>CqmڶyBq4)TeTu _D1d3io 'n/x!m,w`)A0AC7"$;۴⃕k,Yt2C`m"ЯRW=ɭ+ l'i J1$@aqOȣ t!eBng5;VgGwLͺv{޽f15,_v=hom6 59 3ey~E Q&9- /̆xms~M1zYH׃,(^L͐5f8d2[N~ޑ:x㿿.bkxMN0>Q"fBXqĕ"r{"z{7fI9!j(G*#+5^;D.y 1;IdfgvB ({mJˍ6x+ؾ'Ԙxx??nFxJJ범g-:=JDC 1|7349A.V$[9A3k^4x0~eWMપ[c  dKIӕzi/?S@U*u2֨JJ-Jܨ) RJkĤyu},TܞZ5Xy<5ieV =|c |#>t{H>k)/A+YU}:û\hi]J,eQ!1irCaR0W᪇.8ozF}AVa{x]!Eql{l/~6߃@at!|Sf1J>'L1.9l^7k? aMhMʅ[Ҙz+=~pjFA#1S2CZG0$lVO//lm:&;lhK纽왗M#a[xxal/'Cۆx EqGs k( &xn FAZ-!{eL#RJ]kZɥMLpN03 "|.ϥ, 2(SoM4u-+]!l}% ҁ Fe${^ D]pE3H*Λ=CP CxQ4zI Bo=؃T,K|ryI{Gc{c n4pJzp3z< P9̚/1)2dRSL~&\ۓPN~y~”*)ɒۋ(7£a0#`;VAY_[(Fwڦ*=e҇)CX tu&]Jw-|$~4Kjމjܜx1k0wٖe,i KO[ LI}UP:n}vm6Q12* Ut Z1,?57Jv+a"K:d=j_oq7N(+֔eyeLgxt:bwl">TLEixz  otFu!!jH4V r*M(ij_&5Xuڵ0Pޘb{߾V _ܔ*xQKo0Wve'NAU "hb7.^;NKL[ q`F'qg)E8fh^vVY93 jl+kZ;ݵփN)ç%2~搾cJxB&n@5S6RK)zRh3a}6ݶFix'Ɖ;k!Lu,g3 D|[*ZjXy-Ѭ-遇Lr3Y\N|V/⅄G61!D`2EƥK.+'8#y>R)ģxn}ʺuRYOpHvیOoq g;x_k0).}JXo2єu U-jKFe~Wq `˺=q.U-|]īU"P 1+xʲIRsfJUeʳN0JcVȓ Qs^׌CcyX.iu5ݒHbgM$l4|$͋8㤀qLخÀ6F:N סּKW/"o^Dz[Y~qw\r<[G?!4& ؃d^ (`}ooZ ZI7vTѶ`e(㔛ó<Ns=hPPK`$6F=satB`OF%Mζqsw{ycEiW-9x<;@}eh: :nz@П۞,0`vdجh(4oY@x'_?O댂|aZNjA/V@>Ηxj0Ew}M'ɲJBR@wYzJDcH2%_:]p8f"O}S3J+rbS#C"Kj7p뇻1U%t<[{fjyכ!xPKk1W 8f^PRB-f#[tY4Wvsʡc`{k=R7Vu_uUUg;4Tqc׷u?}aW:K8\NpMG^_9mlw[UL9GJmea[Ve {R >GgD8-/]!38/ ґ`ptK'`{9\dDpv7rD^)d]"džpx(.[=l̰YC \Hja7s&̋|!:?8v{qs~ť#~.}[(xر} W#4xA0scWmB6YVH{=i:v{&m"hOyo7艠h5MSTj2jrU` ]u+ňlYhVʪ+PUWnUb<|!:Kr=Tl*]:>B^e!o ,<˄tàc$ I诪'뛺E6%M[ e]ZtГDM'+r);,xBEWHX(p{ǀuLl~!B䢕\pΔG#yF,#]}rmUW2q2q,4Wڼ\i 2 Fm C٪h XHFZMj8qnGJ__*[%<)/0!)HpwC#HLfH譱޻6`ŒOq,Uw8?fƢx=N1ާeY럍" $8xg#D D4zIf9< #̽W7AOi$vd S'|PGHH!sTsN\aSn+dGM;@aZzkᮗ}/,sk\1QaT֜`'UvuV]:װwƵA#6&hXv* ?nm!BͻĴ1e_'jzxJ1^)f[J"*i2iCw%"}{*^Ws`R"%\]V DK",kɕlBG& UMAPRQbySS-,ZIpG Ggx<ݵ~JIM&nR-o.YƄG9t[k7MG.{)= z)AI G7h1Ao̮}p,#}Ne~&G_٘C4$z-tIb@A .6tbN ɥUj?_cNxJ1}"KE:"uBz$9iM2$)һwYW ODy#wmL 蒣#68әgق8͔{{z88gS6-|D&29TU>hchX'.\^4 ?G89xN1E{hW7RQЀ1`v{@EibδBe3*Zx1e&c##+n>j6QʎL';c..UؖkGZrC0HeJ":"e[L+t]vrH  /n %>v\ȹ4 b;]M{b,xn <(V-OJTjm\}DY |stlJڞ7EU!WR np%h@mVM'JJ:\)pME)TŻRr@%ꮯ%{`/M<9Y/  HcRN(x,q.xa쮼w7H$ bBgp31 H#& 6`_?uh9 p|ܲmzVm$w! v|@u60h)Lv> ϐ7@Z@^pbya =Slh>Ywv%c_ XhOl|hOLᇡP”xN1{?Ŗ E(4 :wQtPQe)f͕lL InhqqzMߣgڴl\ږPЏAz] LʡxO ^2Okj<* J.(HPI)3W8ᣁOJ 鲆7j=h 9,[xR3}_=CX =Դf!oJw>O{xn0DW cC"^Z5_`k*E}ISO=aF/'fyPݯ!CGNHؒA\M;kѴtFk,fhԦ!t0kbo3/fx>=U%CicRlwxs|&Y~>eLsmZC!q7:;t{9 aw@!.~ LEt/_?T|'x=o0 w /tl1%LĒ Y}tεC!Z(>c ݍ5aHjFu*F4$̀(V "H뾕C?r۾Qm#n)>Ow}سPwezu^sPZ'DN{mjѮlJM\m7qrzLfSjzmKWo6Ơ#~k\Ec> xi4gO,u #Um|в]r/G<1 N,,b:\eUJF)p]þ'ba&- ]tԞA]< Y*8A>~}|w*mvzJ>Z>9Ci52|z% ܏yW(]@P;t.1+=b6bjoNL 36(d~JgА DhJcAs0Bp`rw|q"xKn EmltI'y$׍:({t{tkFa ThZ=C}ߓd\+ :F)1Ϩc ?x\@̭N)m ^m1] ot^L[#t3hk d>VxkMvm@r@=X*nBw[R9%d}BhK~Yzx=n0{b.16`{I4 36m%w*Vf{9"ӖITX'&s{zFљN]G2Ȗz#W1hʱ\.ێDy ގey ?§^|.祶a}¡1hK)):Im^hi߬CF)QȫDG)Ä^p+d./;Qy.x͉a7tU2ߧ{m%xOn0  +ܥEDBkɐnNrr320j^[BV]-(O@|-9a|ӆC2;y{. &0VoҎ~Kd7COzp )#Vw %&7:a&JM9 x$g~Y)3!s*`=| 90Z;B.1 ?x'Ҵ' oR||IfB z\4yގMMwxCg]-xMk1slJB14arhWxWZ$mM}봐=ϼJ#Bٮo U^`^+!5EyUy%WZש`h#:6,\LVj-ʵN3va&@6\І#NDϻ[GuU[{ yv?5Vr?5uXe$I;yGpՕxH z}'F"tQĎ3=}/f)n?# g1;In@Г1xNqg,9u9R1alOFZ:ſ 7鮯k5u jx ƻ 0P%%,q,rw%%C8g(2D-^ ]O!3DƗjPVt,Ų$Ԑα}Lj;7Ch.94XyMP0]!M* lI_fiYpz5Wl'QRm͸ upC“(xQn0 )^a!ٕcESa=$:fK$7OQ3 ةP̑D\{iiz%G#صh̰$Jp"b$Ap/u:iVuir(\0ܲ ~ _fOoA4#abxyLeq9S'N5CZ0яC!`7 b=ܤ >d02F/J_vz+;Ȗ`hxuϷaڼ.x*"/ѕs?29.  b5RJv5py3T變6,yN"^7-[,~Z|bm|aA :R.m{qGOfiΟ:SAxPN0+R[IBNA*jmCG߳M8=Ǧ@U)k6屮PdkyHS53(2EJJI&/uAhju-DK}S_0h8oǟy{c^dm#6}d~]Jod @ myU.%?C5LfW@$NJN[P ?Hs)1qf8 e2Xi5fZ0S,#bʐ /N[piM8 0DC+\I~pE롅# aƹ`1e4#%dq~+Up`S$טzL579y~lr9H€^:U]ad܃֢0eYl&oXAɪlz3A.rc{đg?oʞe [VSXءwna2KrsRD XJo4*Vrt*!N@70xqGC\y+J˗dxTM6 WP @{h;%H%赲dHnK{ɭ=Z"CP)A/Θ墫º8ҾlJEyZ@jC yzԷkýt[mKQ:C`B:{2|u>9%5 jt/hPU!G!Wlj:z$n$5Ol-]m5:?$h067asN*Ta&Sj3X%&](ٺ9 `l]譓 zpZ0V $M +hqdWH'Q0bHo @e^0м/K/N됡o'IQ6momL+xæY?lۂF-AfYdIFڑI} P l(8s,p\'/2rEg7IUYq6ӊm?O_z>}y;[|Y+!OV"gn}]{zտ4ّ'xn0 w=Ƕ|AcJldH]$#Uk)u#{LRZjnOTiŊB9д=MݵjR LfQV<5^ !x<4>C9uKIJaRu>7k!e W&\WVteR̹Zg,-q$!~(0sG:2a,+Mg|Xw`9&W@d!DžF=[>Ú[ڑ4fo4n xV'A|9sY\'J"*vOXyc4^م)ALpŊWo;1 :W$NxMo0 dNz]{nq$jI$/Ϳ0d|H;" };IuNKYSӵoĂ\Zd}VR0Mۦk]/{5M>ӄG_0(q)7/׭'C¦*&%T,^ds#4^7B "s`(ar,%Aa0jSεBBf1 >;il0vLƻ(*(<` ^Q욻S%)ÄAg= {l~}ϴ9Fg+3GX#B,99+``gMJ&&2G֣a (ˁK%.C{>T8azx&ʬ Gy@t#J=)/2RP2F"*QW‰ $^܀&i/-0Q*,p4z1U5Y|"F%Om;Ȳ$PgYj-]1^}QpQٞ_sk!1 3^P>B<W F~4e2$\L'2'3:? yo P,xRj0}W yIBF/JKcydJ[I^Β {q8)? 6%o{RG0Eo@'ߞ/x>]cXG)DXHAۣqϐ*7 ~XWEQrJ8 I@)U9:OJ>neFg]Ly2i1Y捫s`|!O+fM);ۛ#]xc 9?`$~őxKj0EZ@>$R:괅ty d'iJG^8\5DjnqI{o'5J95,~T !:G;J͕FÈQ&FkSv|ky~o/ JH8p9 u]"{[nQny7nB-#>3B%R K[jA˷Pluہ*2ߟ&˾y)x=O0wik;q @N ^]KbHq[V,}H*^ !j/%uҊHΪ!&ԅTE6VJ3n[ktC"liΠ(ۈ9_{м9?B"5zxW!rs5e7$nJ_k;y9!ZۂB/7%sI%c7zE *~&5xOo0 N0 n=XX2ei%Cۏrma'۔{Jd-[R~l(JN6m}Ŋ\IC'iA}39HYnUV]k9"ac]um{[U}U ŦD l"lz>*2m/uo!smgk/O`#|53& (1%Xgtκ u@PǸSecn@VD*Lֻ`ٺr#4\F;ދ ݍXbLLZ0hޭރ ~昘Wzi/+,\,TDz(ts ~ NS\b7u@#0z^M2!0:mg W04:< 1r{qL7[`iOxۂ-hB :BD1+6첢z}c Flſ[ n ooICq v/qx[N0E@*;v@ @ Lj#t ވ Dry6S!*F yklT:xBmT&BMg6,ST>Jf(/? bKzmy5jtAz)E[ a-߁ze>8A,o¡2o7kVxn <+[UT^Z5Oo_+z)s~)Br/]+ϛ;K[`q#׆kT׻խ!hiDp-ř2=MqmׯhCE+b6NS(.x὆d y_c:ljWatpЌ%cA^D98CPk1S8}eW|9Ÿ~xn  &AM U~tjN-~۔BX7(Z[^)EcPBfD%mfN6I.u͕QrSNs1gs Q'4"xk t꾮kLX1@ w>Lc\ wa udoPBd _b:\{bŴ26'ٜ>{z{7$駀; 翽xPN0 )lJVIB 9FtɔL ۸ɖ??6"7ޠwnTr]YFk % I+6vgQȓhYWs/[x%,/ӭnsS;cti.'0Jij`FKv1Mx&"gorYxkӂli :G^ ITaR]E'39"QΟ~Bor{ۥ󦐍#xQN n-m1F`Mn0lIZhfw^Z7QOG D $G8եRI6[34MvxԄlQ\--ZN6n;MKhzz4o:;8J* c\v>j5RT%䜡ges`/ZyMtrlЯnUCLAav^&C]EG{,*IC?+vkEfa,YM⾶ [ti8:XH睆GiIpm3O@MCvq;ŦS@+0`S 4`͞70\8xKn W^UUUꪫVLh D@4ۗK".HjiQ(z"=[6L hnG>M!JZ-5퀽B0xi0MyLcTo1 8s6uuп}'XmE0= ^"P{"ʒYeXcy+A'\Kb {w_s04h^p+ˁ"8W)lKo@㉭8k;z,3IK 0vv@dnwj([,xn0E,,Q}Jf V FcwLZU_J {1lj"^닾ֆڮ򪱩;Z"jA9Asmmy M[ݰj-Fkˈ gBȆ!.ӏ9*ڦ,Nŭ( R6P_iƉ rSL`0R "7:{ԷEpd c!N()dq,sww/&ّ]w}sރ%!ܩ _<5$Q%1t 2RFY6 #Fd_R6U 1Wd0TL↙S;8xi0 =H뤔 Ztٖ@bۡdPN8(Rk80KqbU˾1nxv25ih5Ѳi ~;0x+7VV c e#D/gWGySy@@6n.//8#9M'6Og],`Vmn&fWΎlK}3; xJ1$RWn%?nhlҷ7ԫΜAvoТb%(k1^ eI& Z֝Z[mT (M M舜 <,eO鶼23ӎ\=D4hZ~7 fx[>VayyD )go@bft:2rY[Og$'ra{9oe(_ 0c:@QKO RTLiY%x-J2]Ag/˳n, uy[g (9xRj0)Kx7]R 䐦Ba,lueɌ8ۧHBH~gktHGU7]W1Dƨfd {)Q͑A]Sc߶v]K㈫ dE)>vwSp-G]0M6%O~#~10sAz -y˝i ,h |{ [ 2K(We^VF!T93fZѳ>&B]%YJ6MOOJJj)T?e&X&vg)bAz$/ )dY Z7UuW RJ03-٣T%e͉ܹM#fHDbXA6-8G%20X T)T#W1 aɿs WR;vSft)2&ZGLP$e+|)Xv8Yٔ00h%'sIlidjNR %a(whO:sݟ?2WW>h&xQMK0W~P܃G$6n$˲޴+ ¼ 7ޤ@Hd:㭐V\-ڪЂL;ݐ,a3r *.em8KBWe0 " >· -Li)ѿ 9@0c{N*E6I0@%5V1J7?#+^M;nV),Ăw`H`gk 1J@l /}La8Wb5E9 tWcOflOEH;wޘ<pxK0+MwI~qWXcyI^he{"aG"@ LEIe 2*2!KNń<,2%cTVd6bK5U٪\ZCCG-FCp;OG!vwJ2+&c}G9nM m3$  /n= iq%+;u_0{?5 SgL1n&p,֡s0(s~sy:OvvO7_H؜(xMk0@B)"!B S$2F-i]z-͈deYԘB7RV9e%& 0y*)"t}Ty[R~l by*EUdU3>{8E-~>tsY˼+˓BqlBCtS \08:h^FdQ/Go#=!bxj[x;>Dp1`qUhb4 tОB\2a0'9&c?HU7Y޼ymtśw$4&WÖKE90xn30,+wABo7ޘ}&ٙitTc؞Cy~zԵ$2aƬ٘{_ grB#x>Wr--=VȡJ?3ge 3ί8Ϊ(6If ydY&tFyL`xkn0 (IUUVNpT]ZKLDFZq{c4i.Q8V <[1S,`Wa7N$!m ߵe(S0LGA )@H{.OT\s\ a. e'$xx&6aM@qm=)@W=1v`")opK[h5#tnYF)cǣfl*y_oo~ϟxi0Eb2+9H l#yd ֒eBO[@rz7Ƈ(-ii`l`Xܤt mFHy%kXg |(|Km h2Pkm`@bݶܻO@C!նq, Գ*o߯+-~D?l +Yp% %l[G^3^gK_r]+ eT_0=-;X&oy}kOX@.]ne?ey֟xMN0>Q#'/PW݂83jjgBZn9UHMWFz߷xMVTdҚjˌ&oٚNm4Hh#{lJMkk*nɬljQk ¢̲\Y!Aa??y;_`x&q3' ΋j0NWh ȰƟ$WPlt ]`<|zDN GOJ } ր:JS#ȸ1\a9~kWw%#*r>,0d)Qzϴ ]i g8WxN0~DBDuPq@}{BˉS4Z (eNBF }^zme0䇠 [l.7{IR8" eSZO ^9'Z`_ph9CnGRq͵r 6lw8M^I3;dp"[WbYJɬiE]b-+̊UԫjC(^5 R5m,uY- H\rQUS91t1xq֠k7C"'qUl؂T.XM89Q)ff1oIVfct(#eѐV33/mĄ}ɴJaS;ݩFմ;YI4o S;;lu ޹9ׅsMU+Y,:.%^<<5vfw,Aĩ *$V {Z$Np(G\ʊMWf/'"0xZ9$QQMVR51Q P"]͛ZH)Qi iFp[0qHF>m8`kG0:S)AY /9gv3-#<L,v|!亂7Kwz|!qu@y*{̀Ҙ'@p{ٿrq`^}8DrUr^ʑxN0D=PulPp{FqB{BˉS23ZL$D)Ձ`Iq=w0FHLs2RRN /g9+vus9 6oiv7㵧ڥiVrps)Ʃp8k n]aum@#rPk\Nǩ}Jq&_|?ǻup+xQMo0W̱Q U=ٞWc3޵bld"}uڪ=/ODPեԶzJ,ڎ*hʶ)FdvVɲwԊZN.!&\k4mTEOC|]+ޗD.᱀QNus!m ~B|{@0D30' F/6]=j627Y=; ]6pZeN໛?RŜȾ084G*ȼE8s:4&vQ W) @$G8/1.g;naMeP?ZpdoC!ē={7Z>}4k fxP;N0}f=8!Z*{{


 T6YnV-ΰltg_ heԨ:vLNwJ]i|*"MtY#xR0D{}uTv,[0T08KXby$K*]}{W]ݏF^IP}+[]kĂh'rmSK lF2 O3VF c^.b?A4eFR _  ޏ3%a" 2(G*3p48Cb+8.@Ns B=.B%&L+b ^ʙyY&:/KBa}S9!YX zzf-~Ov˽y.g .C W`ϖ#aJd7ѹ͸q WxN0 S46K* CCbRv]U!0 Dޜ=<B:"vHTڢdB$h z}p@!E-F 1u7LndQBt0D"̯Nߵ6@4Lp0m?Kc'@f~`U+ņ"Eu֎qrRkܤ%uJ2ܥ(CEs&*^Jf%v9>}2_Uů"r cfruj .5Tj=S !9_>)/j 2K k9auZz%a_w!Tji#x ua#CwӃ8koӊ_˵#xAk1s/.ٍdEDě&Dԓs7> d[v5fJ֨d#.gV,boZ1JbGV׍k>[-xN0m+uE<_P] tJ/pa97|2F0Oǰ*`euga"m}{3 {H%Sī? i>{{rNӘ/xĿ~q 7w-2خ t@oSΎiR>A:2\ czU 8MK']71uZ0v"55eԙvNx:Aewӳ-|1|X~K*pNt~̈́aC=gCL.zt"{<]hT%xn0 E|l%Xbhv %Cbf' y"g"m:kιƐn`dƵl5oԂ"ö:56VΚ1s[S}]cʰ>x"#=Y֭5V K)~skx&̎,[]| tZ@UՉy>\a8EH0R`U} 1|È? J0#!~ )-`JOfTN3΁G(rRgp&0ᛝ( OEh*baB/jM(k%*|H{QFT֯* ê|u_c5xRK0W̭Y ~)lXtsHDĖ$7Ϳ٥ғm剞JUeخˢQE]VEePgjݮYUɺZ1'dQgQyC^Sdu)p'ag' Y"=^ yQ7Mn nL;·zI \9 ڢle2)h8(O+EDp4Q;ʟF Lw|q\?2qJD )MLBn~ptR3ŠO+ZAg,'I\ G4&=IG&o9 #ʳ6=qA<#/v/09H^L0RG%\>&cap F2^3?>>u {8\#{慂0II!pD6#E*5솗'aҚn}k`- mgrAɧķ ֙%tZ/Oѿ=} ו-xRKn0sֆD vM$' X$e׷HN7Y]>="jҴJ:isZR,\Kd]B贮Ty*յd1E֢)\`^D.q Gy{C h.!.J%|I4M4M=QzmA#F9ӆ 茠I#I^c~# no. Dp5!.+!?jw,op(5gђKD…m HVK-!BXUg_%W:G #/ NYD̚[CbO76!Jϣl;gY[Yk nGP&螸Gۓ1{u̻*&xQ yRdw]3c,muEfW3 j;[ٶlLV9=6c'hN+bP6 bkFi%Lr`m`ne J&rz>e JmQ>J%pqY|)yk'c^o>4:F6p]%N0~a2Cn;S[24=lf{Kl=ʉa`Lqe#4KVnMY_q>n>i&/v'Yݾ.(w,/~]q,TV卵] 'U+aP*Ig?cϸ_%xQj0)=46JB1$t#iYKFY;9P 4MD ;rPQZZj 5 V,gըVaG];k(46y  ~EgR Җ~@U]R]VR L=F cZn[xuNA!{&3|H3r%b&!'40\3[6 35^S8]D,1_)A?]6F)$ھ}6ȼ >G8HޠU.fLbf\DB=o޿\3;hY&mF6AX?7mEڞoxAJ1E9E$ݑAfBaNPI*'ix3^ftB\Շyj8)MlFTx>rF7L5$V* ~ҽj?Z$>8ɽAe8c zmK.pJ0U/՚yUwK9j % %x3Sq ^rIz@'"%x2CTob۳ qsb:~d9'vxN0 y ߡU,]&8'ph*@=p8XvID`)rzq1 ǎܙنBz5 [-9^( zN e % Oۜc)nBʽҦ7q9q]})2{^%886KH} 7U.~^}P͏#/m{|+8W`EG-3m %Z|us)+ Cb120 υЊ~t꜡C%{ŻK!ql??W'8nxj0DI%9z VޕmJ$#)}CSa0<^̠bM0J6hc18{Kwc߳0s0Mn$6G+Hv2( %e8Fʌ:"i¯z0RYxJJ1u3\™1O =۔'hkG"8a78;`$T#sZ| ZGo"e#SBh}d:Qtox 0P) ;sξ).oQE(``j*aVj6l JŃ 51#k:>tŲFs GF5k^C#3K·P^NW,ջ 'tx-0d~?;7wf)fzBF|0 0-1N-|Jt^ES+7̫?nQwkZR8Rt% J}fsCxc'n)xQn0+ )zK n\4{/Vb*IEp+">gggv'*YVy^ԅKjJo,٨FMZJ1'J\k*ҥjʪd!k^6*Gʬ-kc윇U0god=ңuHΫSI";Mad $rxb nZ0TuYTKRUS2>Ӂ0`{GHP55ms _e%ؔ(^ @p}xYK @PHA0ہ\$H~-24G_`=\Ce3E!ެc Dɺ Pkp63$Cmgn;RM X ~d` c&ԛ̊Ɵf .q;+{(i |a9G6rKr&Bp5c\C? *sÓ#]q,CW,+xA0 ͐8dRC)}Ql%1u`;_eвғ|x}STݡFj۽QTS[Bق| bo4j"Jj Ք]^Mk8ћ@s:FKJ%}ueQd٦DN^<|w  r{<;PP@^@s <E &Y?BDs'&B&1m`tܣ,`E!LVO9 Qxzڄ#%~0cllvv200^o"#~ Ȭ35r 8 Wll]<ʯ?E5[rH |=HTz{kza]1Ǔ;#d+dɎLÐouxAO0s(-1a4I/4n{qɃq.%ot kQQQ)y)*jS&{d}Yie\ ZiYY^2Fyg+*dJIXM%!BmD):A1,e30eQ1$h&T{~"v@p% : 8FiXqѪo7iS&,k r0ym% ,'3xV燜=SHo1φk*fxOK1s]w7+EHŃ=IL m$)ooԞg9kC﨣Eإ&YPFʆÆ7 }`#B1e":Н͞BfW#L2y*èG! ^1̰JK1 Wpx: =Lρ("^L?1ҧ uO=j!xϊ0 ~ ˴t'8&qRf d[N&`)3RHOOR`PI[ Zhb$8 zcoFk 68j{ҍM\|!dVc zBӶ;=hw#F*2=~Gp~u.ӛAgh8R;.V|%,RLr g)6Qy; 3qk^sG?~ͮxN0w?m ($NjЊKFUߞӝ>ߥ@wHhP2Z+يZRQ(0KP9)AW ّRPUVE-d# >0&XwDZ#݁.*$\s9x)Q'vA,.3p4epx3X\ow/i~ؼ.5 1{ %zpK@@0@0ZM.-lx # $lۃ>dO߷fz)x1o0w ʒ,dO kp"&H}ω@Љ޻6ں/ˮmvTKMMKUQx0e[ZJ1a$iQ]vuAC_UXԲU?tP#p6Dx:&xNaD?gpl )4 G>A #e˪K \u &BwmX,.[@V\Ps:e /)S_.iXa3ŐIePA)3WqnOns^ 37+*솣`&ੀ\k,x'oif|!a5Z9LL_چN^ٓcke7xRk0_qomiq:~Aeqζ,},)i_NJkI[MT]K]%Rدq}tD1K mSnFQnN6uV6l9>Ӂ0§`T-ҝUP7US] U]UBi2)Q݈{_V0(87woʇᝠoXV{Yfc)\S88QFv+8O c:Z #Ȝ`O\98V:_^v//Yx:/`6t4<`Zl.n&AC"-F8Gv0[m,@0^ R"Q6ɿuF+!^G|i# rqgve3&5R,GNn qȀ.p^-(1~9 S> VϚdI})PZ9Eۙ^_Ç?{h*xxN@ EDkP V hg*OZbX]ˏkp"iֵmeu55|_ ^ J̘(0JVzJVRk)uJ <O^r6H8ePZ7deQ*)L #^A&Ϸ`eLzQBvy~`01,0x<#1xc@絴2"wyc&̑r~x!D/J 11u5HbJV`UbZJ!!/0'߽!9&xQN0#☼VAAA@ &$Hv@{&Yh(V[X)Բ3ʦ6nFcĦj%󶗕X0K Bת3EJT)V51i 1z7Hw~)H jTe ٦D^Gp a7q9;a8\)Y+8 'Nd5B!}5$caX6id;- zwv';wͺa9LO>CBs lH|P8xR=o0+^2Vhٲ"(!CHƉMzvv_Zke0p)k<&Cprb:{٬X|{rLt\bJ}38P9 FJb @.q1F-c < ω ^pgo%ؖdH@iz9.A' (?z' DwJ^?01l]d@J"y,,00 hh מEJ7<D҅z>I+/={8,EdHhC|T"gZ,\(XT⤥\ 3/'W@v`>!/$<=h0KݔR\|ر~r?z|349‰ !fxj Z_Ȯs?Wo2xMk0 "e7݇(MFb迟"z$=FnytBb+Q(YJ) %L#4ѓ ZuQЪ*hQi@by8x Y!\恞@HY5U 7MC㗅^ !؅&?9wt\)Q+m78d!~?*{UXsZ Lv qY)ciL*5%' <` ,_' -cz<ӕu3f?Nޙ3vNڍ뺍<}I&xn <(u^cCObp'ڷ/n6A?G"P}'QԪSuu*Ma FH i4vI{ԈHaڞb)Dx&&N)xCzK[%Qrks<ۜ)ӄT0jlKBE@,`0oĴfҲyѐ;pY=Ã#Mrns$,-fzzGuX]bdq=gP,,25F?Upe~fE> ;5xMN0 9wMBX nLmR%)ܞV8"y%\K\ kdSZ;ʊ+E CC9RCiZ%ԨEz8xqrW ?~ч=T˶)P]Y2٦D hd'<;;$ʇ@*MW;YM@=PV?f): 499`Iq&3ۄj)t D7#BaP܂iYʳcŧF]<2vgGoa_잛xAN0~~ ؎R@nhm6Mh~B}fN3A7*9Xk\G)ktdI 8Nܳj u IZYdz:fx+aWrFz)E4J 8g;s O~ 5zq 'ԁ`).xf!vad&7ohxj0D&(V$˥^JIIRz ky Hr =Yؙ70)AQKTJ庩eBZU %mIkSnVB*FrQ*^lI SKNϰ* YJ-+ 9gƟ6%@)Y/of{=|6`](coecc߀K0 'hGg.C u0L̦H}!_u!Sn8 5xs6stfƻ޾q]qQmǿ~JBxAj1z|`YH!\rN/I3k-YCsOM7T EDS\m1$L"["ŋK_]ǡuV}/vƬ謶&VNe hV)nk2 ]fˠTh%I}*穉LohhxAn Eb.`&H=@+clPU}(HV-1$f*䐘$ Z\q0R`輞ufF4V7)9S oNk[aR g)EK_X#C >jk:s-;Úe܄8pjJ{|nH1`6#xPn  vUUr꩕X쵍b8I[ 0 yQ2IZeXĉIU+n d n8@Ռ{OO8gtjeQ_kиխWLLmWXX^zV{K˲#lFQzNa= arOpm^ui ƴi0+P BD(, уv]^7G210Sq584 F9UA793== l?&YD '+}bI"3 !Kp$9\'m5~6"w^xAj0E:싃cV)@7|y4do)9@oޯE mpD&h 8 GYB"Gq5ҍ)Gc]8H(ru,urY۶Gу֊Z忁ntW%@(ytp ɲטӏ$!4߾7X'f x[j0D:R(%-dErddݷkaވ@ ImLBAR M.ZEQp| wBMzOj@HiV0s6eɽӿة2]oH6Ϲ[]_amV %,1vs!jJC< l1xRM0W̭mդM"8‰jl!NNDPJw9[lup2XU:5v]w;5cZtvߴmwjXuƑ`+ԧQWmζj.</^|3a2^>>]LiXvi$d3Dy1@tJ}|Æן2ys!SJPgb}J W zk s h^6LI{kK_v.\k+uxMd-$7 eY俀K UZ3~NpmY$\{ZZXRʠsY*Χ[oNxAj0E:\a$YUB2r4Eb {mxkad#mB( k@#j;0/V**`';4*t#E:_G+=ڶՂu.Ka8ˏXP9p9v!R{DZug\g8n돜~ǀ8rjsͥrm_\o9=[Lԙ_ ]k&c]o.,fƗx]N0wb/jAq* Ă:q{~ӌޘ91:x%&ȆqcY]q셴'7 e?L6 =3Yѵ[J^pdjq{<6ftA;`@v>qVJo }e{!Zoe/[mwNeMdV_gxm0Db $\\J6lѠ޲fNʹ i1eo#do#k ِ+l<7>r8\@FeT8.SoHеM~>wT#ryܕ:*eG-5tI)b946Qk2).uMDXzb!qԕa}ZjfcxJ0E3Zrj""-ޛ4}amtL͎:9',Iذ1bƥ9)/mƌB1{)h&PE68^y\ vb!H=؞I9n+nOAoo0Kt$hՉAEG@AԸtЋ /(bǐ%58l?yoEѵ_jO"oj[_`zka@bݶ;[xZ kB[.+PIkX9:p>6@}ixAj0z~a%˒Ji_BֻĐXFVhBiUU)Edg"52%(. &V{cDb}S g%sp8_;V;XG0".ܚnc ]. }͘|ZTs7}`xAN0E>\ 8NbUv`SqE1nzXx"K61xbv8bGXb'Pd[d(v$4.[> io m4hyj w:0C E5zVR[Q^(3D *upSjixPn {)QUHZ` (GzmONID5֒ݷ։Hp's N# V\pvD֡Hf8=.#|nD sncR5:6圙8 ~CKp ;Z!UlrI)s"p),!`%ƾ|Ȱ ~uG jDMt[o W5aY:͙`ASw; q l4y9\FFߎ a`x[j0EـeYv-dadݗpNo"ZhI\L8'q&cFu&[$QsbƉ1Ji1VޗxjYq}O.&0 \׵w` O{MS]WhrE~_`q7ᡖ2χ[fxQj0b/ ,.zrjA-U %hf06giY,(%0Ǚhfvjt0 ^ĻhL(a8Gv_k˕ _oy}䩶 0hurd{3Q9vXsk<6=UK^K⡊ AdxKN0E^[;!hiT"RW<$WP!B]S2"Ԉ֘mMVM2:<%gq*Ƞ)jQ{'8I0v5rJ'>vhGxϿE#ԌF U34C)?Tep\n{n_u 1B8a(3LOa!]2,w!0T)]|@jxj0 ~ 7X$N:>@mqIb++}iy;I|@?'"@Tѭ׵5TEWTZ1Q`-* -7.2U[8[ovP7h1S5|&KrP(UWM-l6g t)M (Hr"tS_zB-apS& 3hdF|Ĉ,!3|S:_}p77?$©>t2[VV*wřxKj0:uUJJ 9@ +ܾ01Hz эP)o)Q\|!JmCB킣(ՓAZ^KDњI kmp^ٷ_~Cm$VV9M0En[}’G ~GnXr^Ry9 qK4yoixA 0y~%4tim"1"^ fN30% =SXцɛ@Q\`\3+B #/\#t{ -9 P!X4NJBqNB3 z4Y:LFPqa~l4EAOlșBshKR9W7ZeyƓjry!hƀL;g3[C$e#Bm}]T .4@\E qܟ5Ƿh<A G$ I[4?39SfS&IE)CQ|gӰ7ٞZbE)NQoPٰ%o//gg't m1J` @惽:<{t9xq8:89Ŷ?v{ghRop۫Jpj `z)JY+~&RN60K꟢xR?9xcO?P{;vcuuz7ћՕTѿ%i\ÉjfI`?Rq|; Q|ۍ䮳*c<πjFB0+ͦ:A~2np^UĢ<'Fb'lT\SF ["s%B`HzXŰ :ZӪ005Qf2T1IXĤy[]d TTd6ꁚUޣf ē5IGH(d<zQ͇G,,'jYZjET2NXm4:ݑ'|P1Z-@X3 %kI[!d&&g+ma(&PDc8Lm͚f hpPwڀw )0F˚)(t4 {cHHJλ&)*0NCy+vUR;B]4|Նj]&Dݚ0SErm*u&Kߜۄs#SMYv0k&t6h]fX5/{g=cB+5~shgԣ݆ҥKԕfZF.Kr/~B JwW,__ 0ښŽ r iqH2r&UIXFJP"}- FL^aSQ ̰~&P4hVq2 ̈́fnXe` sк2ggoX!#dQ8( -O[JĖYpe! W5R EiBG !Wy: `orڛٯ-6C\iFGDMڀoכdaiSA;Ipx@0(q҂Y>Av%#%QKU7Hw7t?}0wBw0CGb}N ȳekL5#a/X*IjA\u N sEQyǔaS-MS3[#<ҋMdmFAm}6Ci=[WIH58fL:/(Ft~tKqvD^ l@C8^?U{퀇yMsny>/ [~\(qM/>U/dɫm 6b|?8پD)p$]. h%>Ua֖ sBѰ{A3| K>BH{m fxRQ8(`;,nxo` p6Gw*h_Z&->,oCq|ܨoԣvp]Š4V!< ]D퟊+`ʲ=< @FU%{&WϟZWbsU80 6|*v?<'\ >5OS} ~}ҌƾS5! 0{F8Z'MH;J,nn Y,[n=kZ=d6bCMy֡iHv10RmC'yA;BewEjUd4$|L2 *--FHO$z"8MuK.LLW1y7,h1be7T!]ERa&m<(}`I0k1 F3aAz[Aظs((B!cq8 >Z\;N&Qn> 0"S0S F+ZlXn$&fG*b&S+_>ˮSm- INVk[ =QKKqa .tq@wg.ʆ|yT8Eƿ%>Myufkf]C]j% L*M̖0b^CƠ-0RCt*#{QlD)Qةӽ?W"_XbwĈQDr=w-|YeŎ%GV/9o՟f:`"pZ۰ofd-# L;(ouغ~gގ[Zf0ls(LVIZ(zB-#(vONGJ af:=ǖ?Pm愳+vqXikh`ʰBHndl_!0ԖZF7ѕZ>{k9ъIjU5EK5>sGܜ..YɖzϝT:g6 n:z/ 1‹l0S "O5'\!u &rޟJ?sK:[NLmPT'I(^ß(3q3%Q^,b8v|,0*gbŴ`遟3-41vK]4m^ D8) جF9E%Ԥyr(W/)nWZ|KgH1e45(ŷ^AY),Z)6)_hQ{3!NgNO^ mpx[b#"hlBn ,X : س 옟9֔w o`ueBY߾be[9{F9ɕ+,hIm8rSJɹq Jh՗62?}yZ!fg-cWbp5sF/~]%;aj<Ê. eAn{HtLMe,C+5K |lb|,,+[}d۩qiddDt=:,rB1/;.0mvX8kἿ45d T;1؜,i1L+f43i0As$eWgrcN~j5fاNkY&W‘ W܌BP< .f=L-iz-[VZ֨ ߳@aF-uL=yQ񁨵"tR6:»g9NpG@TxiS+ƭf|iՎdObTiNcf=ɞœ=MNSP|U=ȐϐX; ]K^RԚG(V/p}!w/ :O-׋@~gGf#ydox4ީ'{D\c OC Ø&}rFxwG5AO_#]*]Ou qLV(a[hd{,ˈy2|՜u*°ThBTwn|n\ȤwLc+ z6KUU+26+_fMq+/}:/GG:ǿ_^wt=EO# ;L(+ caE]i^O\5%M25LbejȸR L08 Y$}P'FW/,VĮRX_ 7EB}\ZfB9Pa!Ӱ.yhD]v+4'p< `iz"OqS%x;nOpw*Kj3 $+ 1IRitMޭYgKD|`uU@vx岮~0=#IHM5?o8Cg|j]ko>pӡzR=zzQ_# ]5]^<[F.en(Uʡ dVX+#ɳvZkF#F_K_U7w+vO4u}[)|q!i!0Tf{-'A/L޴EүU}73 ]Jqzts|&Nw D[3?9ܥNfQ%=崮*}ad&'đ6 Y!T䬸kqc9Zu~ K ?"e6,|)9ڱ `sjܷl)͈ 'sQ1 R*cr4!m›Jspx, >wm"Yv_VsJ17Ⱦa=n Wܴbr9?]&Xϕ"SgX$Ra}>RjՔ~ SdZyma6~(+N74H誔@Ɩ}]G-CeU)xW&uޯ3?z5O>,HVN!T mzH&|t+t"&$fx6.; 況nl^R߆AY19ɰ: 4n7yǟ1Pϝ"linqywF;p.d+ŒՕ&΁.*U|hbLXPghM^7J`L:7@|%EBHktgI#ڗ;ux=Q1`)?ht߫-xy+݊)_WzU(WaFuFCƼgA Rl;:?|h7GiCs`@U+-c?K"VHxu-(0fox1Og`4>y|,j'8_;Z1aᏵjT̷`=j\ _-BRcm{| WUPb ^Z}_KWvN8eO8:=̰-%2\_^u#{9,2BlO Ne{hkYsZ|Dx7FD2 Pyd*egazLznT{Ap:{GFxk|x ́Y7 I[2x;A f槥ŗL^&=لMh;MCp~,<ũE@_{gVN40= ՞a"/M9^$_ZQP\eř)Ѓq1ٓ+='3G*b|σX[xNɚi=GKK&O*,i K)N)*YsM# udw˜n=pȩɋC+'DLvce⬝™QkWhdz~IBi^N~rv|ZbfzDʨeT&hhBC5CUWFIOVP RP\YjlXm QX`d 1@{a6, h9"hRQjb6XS1 C1Ϝ SG(:k'r!Ĭ&wYs!h/"ah HH+յB R+oΏ N Z@8d~!pr~H" h0hvA~1$7?x |0D[9%6W]d_/x{> Y836f)ZysK *x{q^ 7ob|q,_xM&  &  E J3&~<?~<\ArA * KPqpl9(QkQ% X[xuVC$&G n>v\| N"xn 'yYJ* R'mgۜМ<J|Z\ũE%9y 3zuRřUim2`ܼ$""bx;n k9.3W*m({K 7#xyûơ #include fo /j \sizeof(hdr), obj)64 4p!R R=T. x;qB 9s'' Jn> n~fYQhr8s3PYz{cͻyxuQx#!!a!$,!"H Z1xɸm5ғwI; pf$zehkZo6$VUY^1WV;x6k_w4XB}|'ɽ䰳U(-NM\)W g1xQqstdio.h>2)typedef struct$P& |9z:Agb3JYsg,0_xmRkAƆZ-T Fx47DHKsbJEfz^A!x7xKОjD^(bI / ,=3lock);/0,cxMXV.o$V%+#%&]if (@%s'*(db->alternates && )V[x[ lX'a|U \g x[6sD ֱxO,LO./)J,KHLJ,1+HOKLMD.*-D0˸~xVn7=_1PZ ipvjwV˚KnInl5ȿ R:MtDg޼y35I?SGvxoO?J-uDZu `݌p:8{C`l-p*kP@f!zX#-zŘ7ڧԉw~0 4\Ye4plZIJLsV;ggfeML] wu0L _)ݷ>Be/zKj@|-B\w\) ~ĸ'gn[fu:E#8!FImsD2Rm":Tv{I"(4B߁-pA0Z;,ӣ9X,+բ[$>T\Jp(-A=4MlLhPj~4PMF/^b![gd\!f2ggq! A{Cc\@E8&4Mw*=uBNlNd6 %\OZދ&BHX76 _Ⱥ{WƄ.. ;ߏm#1cNC#b$H@!WJWlj; tsQ kx_K"{)aA[$0$C&$ݓ]' M#4 #妩in |D|k-f>XQcT봕$>UR D7 rg^< aik_\Z~")4J\//He] V=[渜'(?|jLC1̃7$1H;x+q SKڍ0!1O V(0v,|rxs\/ήs>e+^}ޟX,ϋ3\)< KP x\[s8~^(Įb4ˌJXdK E_7dlL h jniC]NESۼ*u'tj*YVo_f(M^Vԥ?zMl zeo"_}>eEi ?_(C/^$- c6߶fMS4mhX6PJKfY`ⅶK[ɣhJS~h4rҶYWѻ&E@_eTĉ}L `˴aR^f-[tci0mۦ-KeU F.@aT^>U]mތh}>]œYU:n4o^٘of[+hiڷқ*W 'YMSgBhEU|3˶IDRo_(i0;xu7h2;Hο~u~NPgժyMk?Tm1@~0R?5kIO?6xP߿{~֏#b"bm "f*WìZS6zNgR`zRZ++CI7t8=ڲplrm=/fl\ M>|MwЭZqDvx&6א^AʦNmP`$2۴NwVZo)`XWb֤_ 檧$#PTkl8PŖ=M2{ {#:}#QEA>:_ HROđ% lH_$_W1IjOuyq)TbU|!}-0oƮbfәWx!/6&eiČE)V'0Ӕn CWyTTj(nQ5wzJ"mxrMJw"/;;ƜL@c?1/C܈v&XAczeh"^%;(l9MUs`W:.0_F:-w, =Ux=zXX'[Pڐh^"TVh3gSC~N=H_Hx!p":3-sZV:9qͬU8 b=Mn|b lgAo2!Xd,Zwrʟ>W?;`fVw ɼ@_NE?eHK1Aiv/*)Jmyzg=1YFv +*뜶W Ζ}ѼaM -WQ Y,0p>P|1P_ du eRYeIwN걚捍q 7׀y!/##3o:ml:$N6R96,|C\!_B% )yzYJY5S:[Za .>@uax?iQ nFQSH1dj;KQ8eᚬ$ofIN`E N=hfyIw<>.0b:˦IJшF=iKENcɦoG\mJGD'Eq*)肀eZ fDҍmxˌ=BțN (COF ,`@61i mɦcWrXΟYquמ ts{ "URp3\kc^ga)$]ly{`w%JBf8:@zNθ͓%ńJ(?RF@hB.-9:#O[Zp`H05Z, R,>jR}p:9%,ȇ#p%,8zxm>.a_a5EV%7{6gҰk93 x :vA%({,OĈ,!B6%#3M6 &c}?~IEj M'طBۿ:1,ӈRzO=BHq}Ȏ_5ixEQd 2UHNi:4\j BN}]-9ev BPoA.I{ Akv٪MZ$O uIB8Ac$ ÝAr'Țbl d_;\ HlvA(gI#W=v5/gxw {gp +/Q9f> {u[>MAbqe[I8}XRRvi8=英o+/74HrK-=k;,(٪3*Z,(DZ Ps~dFb%#T_VW,1tHX)rdZ[-s#H!fҦq/vηRQVIIN 5WZjLh}K)nč~buǡ 6~a ģG ti&# I4sCCEQ!Œ_*Qvgnd ]CLsXJ9؞: Ds{Wh!+Tk\S4;/2Ұ~F- NTMp }n3A8ߪcg%Q>nבm]\-MQSI4^(bZw Et DP"^mD.P{sAT3`"6#˟^u%A-@:Ly,3BJΊ|z&- \&ƪDŽ@ ]ߪ-IJyJ#ý.6!f/98͢-؆_ҶRK ?q05v!7xS\[ #,Pw~dr.jӋ8_{s`GS:guZq˄P%k; dK;.p7U) oˆZt钨6{ꇬ*2>wrkAvdA#G~ g'CrƄ=Ŕ[@(VAv^] 6Q9VUms`9?=ۨ}ʁQ SJ']Wيt9%U8 آY&yâ o\Am1jz!&8寂$Қ6W{$S2P(:Fh[dpxȯHQ"l#II*}ѕUvewœlE|Em^rʑݯJ:ޒ.(D?i{3-I>q'6mݧ,׽!#@!N. !+K/:(́Q0 \n!߈#3niӰ~DnC}lٜG{c 1QCg0h WΒ.c{4y@j$+TzK 8+hvXW$ۅ| b!K?hihĝ?hݺ?~NL7M gD2?p:$z4FfEs?#z8\=p#0hgDYى_}Mj|7%9a<_<ʯl XHç_pc8 wiO5Ab^}wFfat=㥑{6gNl4<t0#=bؖI3dqrNG{1HfF箾iq' =^>Ic"3tn=xpE,"  ? ?f BKfDFcY WHS$zHljAݑA!k/#^wk~aECϫFOGqJx='|( emOo>1qz c=SB6HX-u}NOIQ\hGQ ɽqo# ǐ[ir4*9 wB`y9 v1#ZT[r u}6ץ3Dd GB;q#d@2skzϝ}Pި/.1܌bOq>%4+9u(4z(iB6]ak8񃹿kLxj,|s_(3H\͊o5s 9) |1YgVz[qĭ8m׉I ';"! LcLpW_q]ŕBnl!)HBt(i"YFm*(Y)[bطohR Y]dEvڹzS_h]+BG)4]ߜuT$F;9}W]_uq_juxX[wH~E#Ş}Y Bu;8}"$$|oun`x#uU}uj9A҄>y`l/G|t1]!$F,/b)Q&֋(@[x<% YrB;+;IM$z4+3`ls}$0M$$$&C$Zeb$CEE$ǐ8HO %bà &ܲ$QnY0O#`abzv A 1Ag|,~$c|o}Ř?`|/M@o#W 2|Xޡn|2WQ~C/K =b m.Z@o!{ =!OionOMsE0JsKLSjq8 pָ\s;|Khif8X' F1]%0"p0 %.>uEjV+3'<_5ǡx@tۿ:Bz{h[{IQ~(8Z^%<\y=D=Ǖgk@FN7s. #.xFS '}P 6Ӫv?Zw<\' M\.*9vZ˲uŢ!XOe^!,, ^Wz%:yߟYdbdz>%Đ6mfsiM(pv J}j*3f}~Me`7B\v0yq,_MX#`~ٻ~y)4iTg%Ǯ[EDvێ z~K``n*eOf.Z" Յq*>ٸ9(VC:B!qʄ*lw=;FM~](QmN#f\Γ W\ՂD%_(  w+Z>rH$JVwYT0SY$y`dX:,b\b8Ծ\'MvKFͦHwJ+xjV؄?F5'扑h<[凖Qn'[>?e6>l#Tu OČZq,ъWɋf #Y'icc#DT[a9rUwD;w<#6bo6'[tq ,*IĚ$+9SZRn=rZ.q,(T>X)7?{z%L\Zf]·fo\SM9g/r\oֿpt6qt!B<=^#.S?N"+utR*2Uw@_#Ƀio8A又PJKSAhN;q\v,bk¸ɯ, W,^d:"X#>֐x/;hd_EyAsQ_e?{ܻg է2@5hYbhk#R5!B*-P#eǸi}rtHr}dܜt8xl>=6d x]1O0w0{׾/UNHvM*H <GBgP=ARLVЁ ??o9lc,o_ ja]_hq7?mJZ[oD6D/ ziԫVj,1edtI@yXԐ6 (f5rn}<ϦKSSu 5X0io|RǂxVn6}b)`j b(v$M./qPҬ,E$@XPi  I̙ӻF\ٷl#b0>6ZEjSҕ%StEL{A;Kk+mk lzz}XQ*w-Tk3|ag.9_E17`WT/Mvpo\w[3\;? r2yh;(y9 izjI *rdt6z]Q)جmZav!ŽBjz+P];cVSU>Y*jgsN`w "IĜ0,04{HMuL# JWcMSPjՆ)~$gU%,,a*+Fr^ڪ^p-oA&6NJ![8OfaY<}t8=K1͖S%̖*mNffԲw[I `v2fhT=x옣΁RձIi%ၸ?Id] BiF|C 8S%\HBf&,PԩX6b7O *T!G;РahN%\j_xnLH"sZ +;p^  ION~Pi0Lu$0 )T23d&#O5KZ!Je' T[;1anIQG 2(lU(1ntb(sLz\f?XTHhzC\)_pey5zL ˥#KJj'lbN@0޳JtC -(O訉9bm=U^AT,k< gVK9)3yתոDPfCof:l\ D^ %C(kѬemɀp0kDI7UQ:ĔwtF/˼sj M΁{RB]o& w sMV6ʴS1Uݎ..׭?9@;׸3冖--0AĤ7t`V:b/-y=ԕrѩ7jpXͲ&/knٳBp%,2d}O4{x ߠOr+.P[:U,xq.CNfRJfDCHWx31lDC篏8q`Q䏹W6i($'e0l~`@S }yv@$'&$9Qjp|/)0e%z O&붾s:-wSԏ_CU`7aƾw>SHjj(:ޒP:W߮Aդ$&T-RuY^W•3.9,3(`>s!C5-_$Y\ua 3 د+ %rυ+PEEE@>m}vs*o yDU0c mx[r&-3'3@n2:n8-|5k|LAWGb1{Qͯg/En|*䨏6:F^JXvփ{Nۮ)`],?=qWbtk_\lN+% Ozu|Fd$g-)򱀿٩9?M9#USQၰݙ)p)*2RR+̘pۼ}jNlE)?T$F ǙUZsϼٗ=s%,sհ͋W|p5S^Hb3gM~T!%\?jN44aizE SN*~喕xƴHBR$.|4Z,S4`OeO6~b !_PpT8t]Oo=Oq\}ח{ڋRRAzKW_V}Vm>Ua(`ەbEyfÑSb3:M]1&!;f02Qx340031Q(H4KfI0=ė6{W0DRڛyY\IfX*2xYmo8l ‹MDm-/Ikpm4@+m*K(I~ϐ؊]%p8|pH=;h͙lYTlQȹ&bVd,*cƣH(%y19+fu6ԌԂ  Na貽=T28RnޡmGn?S-#OyQ)k15\V5,M],xHj Wc&_Abj!"@zl,B3Pl@r҇)Y+ȔcM*`+{yD:sg},ɲE A1<{d y,uQr ؈+, sN< :Wy9; sItxsݓp۹RU;|E$Jz|pnݖ87.{9 .0%sruXHgKѨyƝ4]v-ٌ @R1ZW|!59B%K& -b5BC*`^~d+q+r s2HdU/ϐfZu#|]giRW8( s2 6ˢL#*iZe50lE BX 6S8+";s4<*AB2tSBdB&,?9{"N`Pjwi$ 21Rj9 Ĕ b_ 9=h oDTEi([($2a/4qFI jJeCrrv4c͒/ f 6D{h )$+43d[6eghѧLq M9D JĜM=C1bALaWH_!ȏTfy1@Q-Ӹ"Ir6{& G1 朦;tKֽzSܭ6ceQG||?L\v4]ʇU# ٦*#p?;hA k3cr3M^odg4MS?\\d{U H6xxґeR$,q\oL(PvM ТG@說frRK &m6Zj7^BoY% /o;\7~rXD;p%cN'j#UDc8AY-J!Ųܖk]mVdinQujt,Zp7YW=µY׊=Ȏ~Ex lo:DM3;պzf]C66tQnY2i 6Od\oB_WHU%J:8p?>|]HeK:Ll'#CvSRZRib^pߦt˻RoKw(J*J5 S "ۣSxgMP|yc;6>j$|t&kvxj׮yZigrL"vC ùY<=ܽsǺw~oY? Avj1z0 cqQZXd e{j Is4(vߙG|؋xkN!b1Nt'YձŇvw[ŎE3ܻ^yO&A/'v T'/|ASӾ~QU꽯 "m˖(|6H JAd$>M`2D2u1>dMgMYfě`o |5r 5l-)VYH,jZa=VX醯=Rze+ qzVX#fYa= 0hB(hB(hB(hB(hB(hB(hB(hB(hB(hT`9e~=bVX#fYa=bVX#fYa=bVX)#4!4hBhЄР AB&M 4!4hTr!zĬ1+G zĬ1+G zĬSF8jBhԄШ QB&FM5!4jBhT˩uGguΫnj?m]NeJ2N!U_:l~iQ;ԜOQ!(0ԥKJfwJGQ Y@L̖GcG`$Ao ̞Q?>\hA{#XO2HHwk{4~* o e-XhC1[Idv>܁bnӅ870tcRaRR--ib-I}467#OV]IδvZȞFzՓ9mW.famq=,2^mh׏v˞i̗4eG]7}C1aߌbs+I8}x޺rqV|ux6 s`;/xy N]c, xd.-y\~ëBV\}ko"τ/2:k.6%lptw/^ON6^z.k(0n&-¯o;,lE3 ,xmRj0<_KLKNPCOMi!{2ҺSE̠0!O`M# L-TN rcs,S)TDU+$arC94*`h[LM^MQYVKz^  -y#;ћָّKUUXPp4MQElBu'2 bGufrVUHˣ8VZdq԰p?dr,0]<./gJj2qWIA8 3NuI( tWqa^qPHJP-~@~aE'Sp.|Nž;QOBxuSێ0}&_1*WB򲭪J]ڇJ8ĭcGpمl[H|fጧ|`m-Tl`PR(VPjJ_9ytA0#m+8J[dHTzGIy u44 e c+Q:א|X*Q)zMYJs, E#- j~*u]#\uK$=X]3!UU7NCcZ*ZY[1mUq"d FC5A5Fc)Ii"=lr?s N ڄ6lpHa$' lF``yiR{J zQ1N۽H 6#Lp+@ ?J B=μx_`Xԉp {1ٚҴ {gAYH8"AБ {Wn,Ҍ}8tGVK*D'r9vbq7'vmp|;JIP=x[űcCgHFif^Q| ML gxTOA_1pAԴZ$fMv=;<@ i? 3L̛~ }'֦p-pD(@4iQKAjRE2z͸a9M+U(.$nKY!"T5?RJ L$J[#Is16bc*cQ:aϘ{{h6G 'bƉg2EM"O?+{"~Eih}Ijhcf`ʍ0jK,4\c$vƶK5Ey#+}:Vv Bm7$J#9F3[Ìpk WRI;tlܒat^a%TfjT_<ęT݄D$e[EQΝVh|VO"nqa2;Eh5pNw0p8]d-^H$U M씮*a4+ _ȲC#7!v S,I(W}Ӏt<~䳏 G@sNBp=ϧ&">%x "4]f(Iƿg\e ?CVrD|4ZĈG \f gqԵrSx9D898nw CH#3)+O#FN8?AE 皬t&C%D #'Mt3T;.}8JO45Sή>iaBT)26olk+mYjRFK0{Dyhp#N9z{drlxqǣ1xr/磋!b2C"R"B+XAL 1E.g¦ `ŏDh UH@*y㰾_}@Of><$>Ycܤ}t[(\d8 g3\8(h~./Hv?K|Qh3-anpk7n]ScРPӓs>>9t.ݚ"ׁ`oH&g:æ}]{]'h³^RNc7{>w%'(#FMd8hq 7ˡH'ej)0IG,^wntT޵^v-!8cQ>ٜ'(BgԽau~zb@zȾg!IXLBTA% 7u!QT0BI`mP.?}"H/3gG#T ߧ·9kGACFE]9e,LJ[]?STC> sC(@a,R   =ƉeR EgйvS 8q{+K(.c" 鉱` xn0~:|M!mUdF0U42EsGQ/PM(HBk:C΅1LBd8?I<=LyHC: "eZTPZPFbwwbR"вE$cP GK$}Zs ]#`nA\f2V'Ű37,5M[Qq-g!x2qk4Z0M.ۇ} eXE`T8>|czÓ`38*_KyX͋J:k݈}.i'âzn/"e.}C ]հNs[1xT4~C" Fr'#0B1KN"8ծ-ѰLܮD ZmQ(`%N'd =eLE3d ڝ,OGE>}%qh0;1gb^.0G'DEuL<}x%|I%b勲jaU*ZǗ{e-bma (|bK>ck'NVrmm_iPy'&1okK9]N>B&Jȑ>4FruyMKJ^9g=60ΘuCok)dXF~J-S4(Nd g YAICVZ«ч<: PEYՐ*Al@M"2,((3+ _8fk"s.rsP-/$ &FqC*kAx:`ee+Lq#Ѭңbn"vj2SI&Lqh̸WYW2PHYXW5BjA ( yZ3-%vnpWZų5 AZIecsӘk2-\ ZDSax00T* fBz6C|] R:6ZAW٘vLȶ8a|H)#PZ/oѫMSlM"HIӏ|,uVL~J%+\C+' e^˜9X"Ij/x3kePu!NW:RhZ*0XEte*X}Am݁ve:WO!haVؙ0$E=q FqS"(*/P8GZ 8Ǻɫ*ҔTAiR Y2/JPR{_ki1sGWiy:PbKneH7CqHɐWU1zIuS?7ˢd3jQ;9tԡ^%oG1%݀ns  B;L;=:w+|2J%+"h]>SA_`g,xM&-@ -ŊDc Q0Uo\XLl?vw*VV;W5MW۵Qcg{(@Iu7d6k_slw*GgRSQ2munl{Q}goKuirì5ظ[U 7A4:s>%Vek{Rl 褰+…>Y X4laE2ِдxUQo0~Q` aL+jg+M.YjG31lM!^wwE9z)bf[\D\E=pY^mj*xZ~ QSM1bKH"ѹ~\" =-޼Dh˜O`%O%Ix ONm-b>#^FQ tJG>ķ2W ‹_ qG-C3K/bV;a+$7{ aipJ) 憔cl(PY$ZlnsFj- VoLf'p:ŖP))hz++͉*,& wT1:2Sr`?։)C $Wh Hb*,%.VF]]\<۟V#agG; ixcL޸Tc3-1['f2pSA1uw<R`уȺzd@O̺yfNƴyR ػFi.wmG%̌!e>[> +4߱Hy%Pd_{S'ȡߜOy$U_ vpb+OBorI/29 ixUn@}WLH iT(`5ekXŬ-"~}gwmc/:s9gOD_cl\C&wz  dI $ s8Ipݺx7n?@C| p|C8bt8&b<"J71%W=*XmOa3zE* uE0wcܦ:_}j<̓y8mq[d+2RBSYJ+ƤS>TpX|]Q-XPL֣-; "ζҦ+)rH%/A>g#2gAU2~@h#K%;Dw<Kjᢺޯj!"&I3p+ԥ &x.(R1AъEmGxiW^p^;V%sؙ7ybǕ>LMd4;I!D}[pb2Ӄ;H(%}T-HSA{ aX*Z3ZaP'9Цn]VRYlN2o'se6]2Zw T -6%FHft跁Za4ҙcL=>musFht1"]B(6߇1mE}Mdҳhڞ,4ey -JU8 FV!{ pIJ4SvMAb[/[$%n:JmDy'Ҥ^BȪ"E3 MMXR-q^+1*]@%i>BL |) a5<&D6|釻?,ľ%wE< Cz*<עs("q9qς@u wmQĨgb.fBˣO/WG/CaA(Bxy m+ll5eqk/zAp0VC Y&Cܢ-e3.XlY{ނ ]}bG++ P3qq{ %9vK[}ʹ)|(c4=Aj} )KHp5λwqUͼod?4)_cpa)[-=[) Bڄlв3xuRN1>gbhW<@())gk'.{e#waqgϞ; Y_=^+C=aOjT3eYm-\ C<Qt8RvAy!5`XA]+#0Xf/Yjތ<`${d2IH\*6 9IU0fC}`rt~7O.#\s>:0XNLi\D)L:3UQw'*́%Ï>/sx7qZoPrl_=e?~Z7 8;-cXL/${?gZ =3E/,5~ߚY)/֗LTb1Γm^r/WӕmM3'omB.xuQK0_qY_N";0 e"a4 lH3uݛ&q6J$ddSʄ5$BQH~HreZC+:.rB"5riF dj>Mwa(u<|R%dPK\[B~Bní7fS5wy,}NBD'.tQL\J`g/õS n&gsDKWٲ۾C _n˕je/b7iHB:,Z`ܑ}pC=;AB2E"B<&{@x}SM0='b Rn{haH,{h L7qޱ)BU/y̛I,#vͦv71׵>Nb9[@6dp90q8QזULY E^2KZ5Ӊ&+ao,h!>-h![k[XtBئ琻q@\ *l`7;bf/)&GT^oe={s^km9y߈~2a,&iGZosPEw0Jg~DgrDg Ӎ'h.vjG#f_Q$xM @ͯXq) A cl迷~@]<ϬO+D>h6qbO\6BSޛ[F EG&EqiIs+YyɒcrU<`1D`av ?me&5穡OIQߪ(ݚ_lȊ*xy?jJxtid^F]ҷxVao6l[v6NCtp;؁, A%*&"I%Qe;J;`DݻwGZpފ+y€J@X? `-  $Ғ/ f,:RxMAp"&Ah&S"6\ b&NAqZ-KsEq{(^ 3v%<4鈄gw#iEN伡3CsZ`V :KȥA̳Boq`{, ~ ː6xvV6]xh"lT u} izՃ, u,xOXv>}xbf?BWfesӎ7h},4qگyuw{$I4XkNOaL00L23G;s/JI1-#?mCwNQ9:50Ȧk95;NWIomUGZiVZ+"C᷌a 7dRɂhet}Ӡ q;9Q!_ZwT>K8\)R29u>99+WwOX;*Qov>{m.( ŽzGLhssz8<{;)7r,I.> 2,CYeL~xwMD\kdtڰwR#ϦҐV9T3yXn9ls-UA ׃7ULJ4>MlS)L)R'̨] NQoIY:f6ud)Y"4"$1ʘS{d/)hO쮻 Ӣ꾡m|:)LJ!?͟`-[N}켿F ڣOݷ:&D&퉲կ5ҫ$m3 ̶J=iXP5[1'7{[@6W_: "x}AK1ͯ]`OEE **"aM&i7 ([M {K4DӫsH♏&9dnГDXfݺp2. O"@'-{p}4foK~LMȣdJ&g|T|IL%NaMP:qΣ dKr]c-)?.ӤzGAʁII/;wx[2eBUgH|cGcD5gqfUj|BAbIF|Nj^zI5gzfI|ZfNOζx &거xW[o6~dIyɐ^k,s'Pt KTF Qn֮;d;]i/Hw<|qIxJwOO^R5nYPeŪЕR Qu$HV=Z%D5SЩ".ßg[ڔc~BCY쫫?.eTRܫ2}q9xKӳY;C 1\n@ tQFp c=mK (n?TxQ39Uɉ7 hv^>R{UVl$}5JJӫۼT;b____n7ʬYƏLWzVm9c__9U bU+~ LqI}>h]f_/uE vx CQe粀[*zBgL ?H"eYy _<{&P*x̰"4UD=zsʘ֗+MLz0'hP |c0\EybG@f\\|:>*-PvLK) #;`8)[ $"nh -JB"$LNQ59x UOБ^S/-*0iX)EYq!l1k A)h%I{8J>Z&MV2[۬S6=Ⅳ\-.oB_򷳫b k%-}[E uMaGCG4$ãx&T0ؾN$aeu}k3u%W0ظҪ4;֙lj)&GD+ҝL ,Zlasw]P;nj;1JU o213u0)MkQ[jlŠuʷX;2pP/QTA %u1|[xqx74 CuE PRQKLQw6WQy m{-J&YTSc%?ot?Z=![N{l*fPwӏ-}Q$g ^U?\0-||8<5-NH`~fLbF>3c=Nrx шƵA{۝y×#WE%m{i^̆;yzrwGxkT-=$-?~?*N o;xWKs6>bLGj#wx29q  L{w"e}|^]O#B)*3ܮm2VP@5\3+4HM wk(ɵpvX-r[@H˵d4L[P{e@B%,Woo- eYtBo(-8U]+9۽լ_B.~.si5E>,?f~\,WIr i~xHRxQ$F]czvIфk-zM4p<=6=;0K)0@SzM^IHJDuœV>G >=+fdNAYst!OJXbZ_,n\# dI$Ǻ3̈ӎKh1b&}ʜ?jJr<m[񞛘= *kXQ55{W181[5 xuA3Y/ =GsUmkEa!EC-sYX\~C"imPR&Nboܭ>{YJ$X`bj>A= 2XN7iS`4a[ܗ*}Ǐd[o:;㕛;o5PZqq^X(/h Ԝ|Rn"JYiGj,bSl?vM|rAU'jř sلaT.B.z0 EcCU ;me(%-?XdsKxycrvr6ΆAԛxrS_vY6UGk!XpN03Jk61D^/xi)n%iJl86 ;d؊3݌q2x@ܾ󙜲j%9g-ڙ[qOQZ5BM xVnF=G_1pUF{!.Z^@&U@+k+pIB%%SNR 5ݙypf/WTMmRVUO*c"k[Wzڔ95V.ɚʔ[Y26֎Y2[ijښ\uUN<&񏂟0Ϻ|d)svmU+p*396:Zo, *M35m;Z槠1"[U{jL ^QG57YUeva*2ةh֪iaʷN\ڜm @ig't?OuM )uw&.AEFmSYJqU!UXmM9hq(PZcʚuq(7St[WqmYȘ:"AxG᝜ ]=`S"9I&MDL$W$ڙ@<qLaDv>$R#6?[Ld0|P&42$ZaxM"o]əL\k!={Q"̋ha,ܧ3Oފĝo>8|CJw5m8H._|37 _ksؤwMELOa!O"ċ8"4 ÉS>ѝE|qMX'\xxp%?_-b$A"h1Od#P6 zlF`=byjp@@?DTR 39/x7dG2mdgdC䅣yW#]|r'wUˮM8.z]jݕX>z r{T?چy Zaպ5Zx`p1t_ǵ.8oҀ ]]ZY4őki]s: }®a޿82Y^ j|LC#FKocvPwUFE[\r> G\#y%b=/7x k<0]ǒ ~Eh?+/1#G._x.K;cS Aҭ{w}0>نC]{:/͠.2| 5&N+2i@ĤMQIZ 3{*{˗,3 `!x#1g]LZ#v>4gW99yJ fUMFmLYnb?>Vv_1#o;ɐ1xR۶RXS^ؐ^eձI̓6-Cz w+pt~BwЧ]M)O<ʳYw!VzI^NJ{Lߩuem (Rz}=j3U5CZkUکf^K8& 3"b3xAkA)Ҍ=I)Z5$K ( %LvfGwg쬥˜ x#3x֓wOΛ]lED{y3'6,, U)Iv5!ôvºA X#aҏ (0scs$^DnoP{3K1rQ.kA ߾u8܃Ez#e)]0"%ʥGkQʽ _wp*hY$.yWdݩNU 4ƨQF6{$THӡ#Pī|:5\AH:W񕸙;q)pkNF'Pۼ&M/T}e5TE5~m\@К݁TŸIGmWrZ+Cۗl1I u~V%ڗzhX ޶/LV+̜,'5-"UKd&}L4{s+e 2d ޟG' >&wI@ cdh6dJLd8L~>F~&N r ٵK~'#:]J@N"-#Y>j DEUlwM~8H[T\>=9j6y, cU±E>]|wU'{霪 S$oFRX[s3cvgcFpc2N/I Wx%VpAz}--T̴b4̼ĜʂT-}.Դ̼TwϐxW'W 0/(?HAWT  % )% EE%@i,&;o6y{ <9(xuQAj0K| MK$`JBoBxA^Y-$nҋvvfwF!Tvzf쌆 XXZ I!R)JTmh~LzsHHX(XŠ5o|nA J"A++A[+ORtca^˿?6=e]lshHMjBaWEQ쏱fEv#$ԣu- u:b{Vi#Á(q:4?(I w ؏ )hSCm2֟NIsӸp[TKe(oɑ|iG]t3P6\>mnqs-/axkf}2!xb:`̼ьqW0xUMO1WОVRCjocf]3ͮ &;yc:3 3Mo'sMy>t >sk#WB8(jņ`Ѓfz@'aGi~D+ym B]V+5l^DkIZB/z._&WlW,ۀҡGj0Q&"g6b)U2$0#cd/N9 :.~"O'SؗX1+2$nuRpD7(;eb(oP$߆f7),9Z)06AT[ɏɷQ'8EVVIk| ktj 1<kɲpkl8Z17KPT>&BZQ c%c M5D"˚x3'>wLSO"ʅC|MdiRq7?O]'u{\(9[D~mm߾__I[k_OZykҴ־SW<_:fBn]f#в?0B_!(ηK+9Դ`kCi 3^;k+f#vyb{GUf+C Zwq񇐮%YfcQMH?e-bDfg7}g;o0BFC^tw <;}4Jg?͜BxX]oF|^lk_rw PHA&ZOˆYPl%;Y,S 7WgtEnSVuETkHeK$"]PeeBҔʡ]ȔGim2ԩdRFk]*Miuz%kQEOl"5EWYZߴ}8 "JM۪FBDlW.3ll0N JiERUyc.m>&}DLcf&ݮUQˮj7$7%eJ-j|cĖb{2 pQȵykg ;$ϬB;$cw4b dȨ` h!UdX[5ppѠۆ,nݪJM#"ۭhz%w~Lq8JHQ! RN#|]8(&72 $$ڹ|Hi$ˆć=8 E0lc`0'ؙupD"G-'!cDX8=طA"h6M0DPÁ 6mFlpN`=bz-k.@/W@'X!zcqϏy8pyf!ю.# ~9v?" zwmpܜ"S˶UIs-=^B"ͷs^N! 8puoUn~sE]Z1O*)\HF㏘* =aaӡ?Z6bY| ~0 ob## [AksuͰzQµ◳wl`*YnJu-`ʝB; ]ɒ6ܞ5`7mUJ骁xQ>#,u.mE m13|/Tt׌'V`{iһ\+vnf;rocct饥O glݝ9&活:gެab[ Rctmsپ'$ReC͏O2UyxY1Ȋ'd{+B#d)`1mÜjTKP4/7Mo5s5=2_6Ľ\˟UqRdu+J5Ë5o!\Mxrr.y4vhS0Iܘv pnbSck8| aK,sH=1;Q;Zܢs@y=.7Z?2 ${<ɥTu߷vD]&ܖYک;GJk t| ܿ>pCp' W>Ltv"0a{gxDC,Db-8n\J>n =[ҏ.↥+t@8'lu\W!SŎ޶mxȼW& +q8Ay|) `'Q8xTq }ջ̭(njcec6ۜȌK7m)+mE>WOQ7J>`}o>~Z͘[uZO;{ D>[tJߎTtq2=d|g@Wq[qmuͥ ۝O-%:Wz|=Y435&υ+Izq]]v{  spkT -#h-4FY~~p?n"L3r((p>q1! YAӽY&g$emFD@eBƔ'QLaғ -qeq$ `đ>eB+d#h4Kt2 2͑{C O6掹9ɠcfY/ЋUH=}?Te"V]`'""p6 P}>䂉\~."!eا zV2ՂIRJ[5k)ǹ^gxjkG5ar Q;L\ be85 HXݹ zW!D>#Zk C"@X 1 (u6K %;̔l=9sE#-Qz61ٛǥځ򊬬%B;oNV71Qf.ANĿ"Q UBy$V؂ՠׯCxCV!#DyB9}çGf9͍RJ,,+tU-< l{~bU3o1ں(8&qL2QaҴYPv,9Wq}_mG۾ݠD bq&lSl6e]O+8psG^J<[l/Ot6ܥ7 83w:zvE|3,\;ŢY'oҊsc|9;<:0˷/*CE2$Jy\{mvQx uοձxXAS>/B5sx }ILpUY%2X~ nI`gvOK Vw/6a^U1-֦eZB)lYg ֵɚӹ+~cқv^Y3IUgF9'SƵ`i(XՋ,`?=U^eD*rUZ+r@{!ÁLЧ:K:blYuel.A1+.7B_|G HjE8;DwPyCԾ(hFhɫv˼SbfeG< ⴣAy! Q lZ78cw4CH"t {w98<bNr4&w,3?LM_V؇lz ?a!Al$$ UE- f~rIˈqV?Գ%|JKa~ {08 =tGu|E%>l4zLZu^u(ƟS tx6KC'_&~-e%.gZ#U"K:h"tP; X Z9Z~Ax/qϖ' `]ʧNҋw 4o ^QiQ4#7F?_n@Vhv4 涮:wj6pU(K<=~EG4 ;/\u?I*Plv%jf.\؅Oq^,v$ո4U?lRp#Aaժ>ChehN4&CC07>=y2tB4]"eoQ&LѠ^sFx9f}9 rqnDŽη_3lj1,pk%p*z1VI~)Dc[w'%VpYr~J{R"bZ.k)-FsZjɤ9a`̩rg)nQbo=?8Va XV!̧'? D+btBUɔ!69հk-5(S8x չj? V]{Vw:.C99݁Ubfk^?fۗ}i^DCRf$p`vO2 u՛emU|^CJ"sW(J&B-s\RpCokPɑ^IߠM 6e~)05}܋۰.1Q6q0b*i{cWOHzBlؒ$F !f*/ҋba^gv!|[ѱTFo8XlKM׮#=9:Xz&2nrJu-*vfWgT5Yygd_Yԅ,Oh]x7Y[59?77?O/CK93/94%UA)?% U`6iF;fm f|?T.??GAKS!= >1''?YȎUJI-P&(J-N-KL.W(QPZ,"u@Ńܔ9 Œ̔T B8%/iE(LW`A3xuj@q`hBĩ{Lri(v*' } y{tvU6f53}ϠU`sϕ(iPT0gbR AkEjA'ӱF ^ fQS3 0q]L` OHTAWLf7KX+pWgњ) //ڸ*FMGw(Wq}N6^qn\ aD۵t( _s"8 rW0I4*ܛ\Wvhx7?v./.x ^rh\UK7\76}5ĵ*|UtȵqwD3zf~6=: ?qf}xdJ>]\N3I9tkuf /$Ijl sҮx"RkqVi2Z8:usu>r7,N& Wʝ t{'PJCC3yu~/aYNxT]0|WzMuAmr$ J'Y,`ű4W~|m(䎗ٱɈ<mg)&)S"&;0Pa%pr*ľ 嗚r9k۟PMҺ.ɑh9M'B}s7ʹƌ4#2- NhNTk8m:Tz uN[z MA-E{B*  ww'MaCFvE[߲i86^+[{Iw}xD_>QK"u]"~`[cr̘2xkY]Dnd E:y>p27ryVF懽[Gk^[8w \r )JDh?LQat!bdU&kc;i6e xXX,\adq/P'9Wf+dmQM 9Q!O|.\<5OwqY5˄G<Ґeߜ{͉78ZK7_+NW]i97WnV Ehuf[X3N+Yx9(֗OM azxTmoH|QrD* $@-rUxU{]'!m{g@h/Bg^yfN[p \Zdܓ0x []C"LuFƵ#7Bg@Sm9j#84p SThDu\f2Ae h λCXB ׳MI#H 4l=r\ R.v66}۵*d)SR}Dr}#+lI4 TFo(mӹJ9TuoiO Oǥ+M8Q@ QUŖk g/!(Go[JNs r]ߡ9~}QγI3U]dgLj'bJ}%+ݏ93'IĞ.@S8_`>b1 WnPdgr[wG G,X=1 Vx|C.Vz6\zq?_%^)xfKM*O YؽH+R`$ԓUmgB@*vz3)d<.<j5}Ÿz3M=%Z󑶎}?  ..Cn:] fG颗BQEz!iHPug$D}{Uuvꉽ=wmJƼ+_nC Q-2T`hG=8b]@O>Z|-`0l0YKnP 䈌~7XE g0du4-ɸ-&3`]ލ3NC~X!CZC}B(F!D>SHCCVy @Us3^NoGkLytYrR(yog'Qkt+ b!W4 w|wօ=u_yY.n) <Л큏sz=Zxӯzӛ UX:ݭ:mZ[%챿 %N~[o"ӧzu,~7CYin7UxԅBwT!873a Pvv)V-^<80f.LF]I3˦ʼ,3X XRWjp2]\M&P肯'|"eZl:+p>@K_K}Ǥ{2.qϳ02hwj|1mO;N ޹uĂ/\/6>ƖH z&t"F{`^ Xi׸}{ᭀEX tGh!Nb rL{y5j<7H PFg.fxCxXC;HZWn(=jz,&Bns8HIcPz`Aj&{f- qV䖓a΋ot!شKS/dx>~hRW}Kx#vqJ8LٕK%=bʻ{ʜ $׸oR;;{y}Dw_{߭7߭Eϩ,BnZ^ׯHxR«;y`7Sx$M+xU]E&j9ٺvVA$Ct!f6m%,+D7GH(3MA ??GdDf^&Ys&7rHˁ%EEũ%`\\\e)qByá"-Nz2 w(VkWXTqI5= %@!S+2Kրj*( l t+ןSM”3=!^(怙0K"K_qnS°KC`}: P#>mGf,xSSpX  !B0!œ``I?~,+csÂd N~k,怼T&|0S>Uv>*'s".OJLΆ$ԜT.$9CKNTK(AN8z Đk0#  Ѧ1)𬀴 "5Yf2莄Pg Ȧ -QPCDqyFfN4q:u% y$1guseJ4vusw^pe̠@ԧiFuq/ZsN )Uu$xN ;O1^4Q=oI4ttS|)@㰌Qv4Kont54RjA`h /ø#O0~ =AqWfg2nbz *W)纇D-,X K_rS*m-9,xyJ}+)gdźq _=et.*YV\m LOOMwOw>,3sΊl^ކ9ﱻlfarE7Jѳ,g,w6isV.9+y*X6WOy&&gMD"ApS.`'7iH1q$NҊYZ"Ġ!8S8% vK✭lBpFڒ1Sl} 'p= I9b,2@ ‚E '5EA{Z'?́{Aψ\}ܽCipvSf%ID"AHaMmlR"eFɅ%m$d1$pzhԿ|io\0aZ?`t_ 'b8j]4]ػѻd?\!"k$#^qR(XuIĖ!gg4"a>g$$!#czv/x:,mvi]v[c I!ͬFl񠞞H, _0'O犐YSyl*L,̰۞E 93%-Ü /M_t<|3;a;밽!Ᏻ^od4^,| ~ R>-% NW~{o2M:-;~^c"T.h<^^}9*FGg!6StQg5(c=$>/Pv{M2x?GA~Tj ^+W^aAĿُqُMُ =e'F{xǞoa~V^-w̺B$KDϒ0Lc`XWX>؇wf3󼣎x$ڽf X<r% d;v<5 gl ^8#Hy?C[!%8Fj/✯ ɜƒqzB:Gт=6T24$' OiSO ǟ:\]+t`K|U@UQ ;qf>L@21Nrv6r09 ;9ao޴wZOi 3] Dkm `܂lW0*.᩠< S' ڬ-=$Ay[7 {<ْF@ ea(_!ݡ݁y~ /E)m |[R#t_3Yüne :0w{,f/ю n;21/>Ɵh:VO$aQN%pP=DRNbp-3Z91;Um9m"|dH7Y}Q 9(5V`4?U?أ!iQ3Юu\G>])qIF(rNȐzA> I(Dc!:]ҶI)"&ZNN{wP?5HS*HtrBQǶԍ麖:`ȍ5BqێDPՑTF vE14(ǭu7P9(zMjv>f%9Ï"GLh} Ðm=]Qs%/ WRw3O4.g"GSqm]jH"4Xˁ0X;Ph볡^̇ .'?Q'.<O ،XG5g&^VWOËI,Grz֬]%Hېe*REe)UNb vi7ueZ_(Cn_)v3[B~$Xe/232ATds/H4~48>&~}6Lީf/z=\8欒1,ś<ړmpp\} S~;`(A_pTT<`L=;wnm>;>\$F@b`mPih۩ .,}[Tl2|bɫ !'Ѹav"kt~vr9zp >r.E[ֵվmc?R{jݍF(~QbuM!B(֬xH%MMK:B[u&p/H>VX9Ŕ2`TFpD$ 4 WFZ0a =YIKQT9d&WחTFOT}rWy 03PR⮀Od@;"y\q*v*)^D1Ҥ#o0!㫯}s##۪rl8lʯLHQp0? #x42ԕ|SwOݍQn`&оLfn2ClL~ B B JzlUÃI![Ly|6;|esP?C\" }&uehںqUJcdS9 iT'D8)4t@߻7qƯia)qWT)9p_Ђg~̮mt5o]! @vݗ˨}kowg4jj>U('<|s*R+ ^ܢjnݩپXmC*Z^fZ.b'p;_j۪8z*j^9*@yVX}+x}G4 I0f [.j`zm1T+)*AJB0qTU)+%B]OXCp=!@7YnD))N_sDr꟯z<9..08>nGK՚75(شQZ: kXf%$*jeHx,m-c͑Y3MBǭ5H?[d}Qﻭrp-q<3g$/{=^s/`=/GTlC1'PXy)m DjZf PT")~{rY@nFPJ< ї!XٓUnnFQ0UjAYIa5C\eΰج0mut `۫ino N}ƥǬPҧm gM@#I'?{ O3uXȹ izl T`%Knʂ% [leF!W}!(̳L(?m-^vmWnMԹt -*b=o,rFE\aS':$UaIH:05v.y2K"Xj4R)+h|ۛ-oa^.߷2,jx -@ FWg&M]Ce5CZC9%7m(u㧹oPwQ+9lEĥ>o\vV!.Kxx|?s'\KnJ( .Pj/:xuA @ Esl z)hw2TH&"ގA7{ $VWĐqFJE4w6VjxȋiD&p%dnqeώ IF3s ]I-0(%_ MǼkV >xN@yIHhbzӃi6.7+̶hEۻˡ'i0R$ =^g4^qŘekI&xDl)$"=6\j!9.iQaUAV۲+7 .ג&!s {ܻ:Ie\`82pÜ8هT !P^L4aL&{Lnߢ3LmzI `EHq2%D 7X)C}@!"4㠃O,=d*tE8*6;0QpjO2zF?-$!1lACLH5nbb\Ӈ)^ueYr6%v97ᡧ|  ޜ4ªʲ=e=XDu>L_B<%6&v1Q8\o!;A;;7ڸ7*Z&ISsxr\}_tU㊯u׋W~zS;ãvexWO8tlQ˶P[P?qU&NcQqP*g߼7vڶ0yg$Ss;fuX[@\ORa ld t KbP>0/!\2b;tp:a"aU8Rn0" H|d[ħMl)1rl4Jw &8ةeϘ.;B*πEŽpdj.! 5r Ǩ ss|CilɲrH&aeJ/th1)'CM-u*JM a 0WE[9*;9VOܧݫ8ZLJTZdbI=A,ٗ)g+j9h-4Fz8F7zFwp[ϵe3X GdljPf S_ڝPV{mкAnAbifػ7Q>c6$]ʆeAj[l.66gMjϙ6 tWdW$emw/r#{09u\c,\=: }an uo 0w-ܱL ~o\8A2>ksSj/&O nB.$|J vgw#8+ IL @`Vp/S=8p8qC`}"`Y~Q(FGEtR]Ф( ( ( VKKVJwզief01/(j8Ǜ}m|zUy ղHl )En!S%0u眻eTP92ޗ SJMZJ [;s4S/c,k41)q#f*\fzpJ1T u0{iw% ^j VB -U*_f9~Ō h3fenҫgЀ58/k~q7W*9v4zsGL"[˳2[{/A myYKPgW?B,"M-INW}[ PԘ[[f lxzOrDsGp}B}ҙy5tql:KC,D?/ |;ĺKpR_ ǽ`2y9K! hQZM8ϯAgN<˘Ztx340031Q(H4Kfx%v-.̫%ŗy7?"`(Z(p%O-X\q]^ڿm+ǚƿ)Oht.ΏO:Hh p<:: Ex}먹(\U5^7?%QtMJ okM^&XYi/"hFDrdC|v),vNˋĝ1p:XK6I Zճ nܘgTw_oQ%a:rZƒMMSgZg 4#CCQ/&I8t2R~ks?7}L+9ruxh6Xw cG b\;IUw|&WMtzkp!8Rh~stk[C{8F2"xe_K0şOqa/]!t *EJfm ͭ0d9i{~79'3/wW P.e%8kt^TCM lխ5JyP7D(LPb 5 fNkeBPpS돰7HrIM{2*G(xiYu=>GH}ȎHl$z}yHQp錓A> W2s% y{]s.^gS %Ύӣ3tɜj8ZoRg*x[ϲeRF`xE'dTQE (hYPr.߳xYioH,Ɉ6,: 1rrI^SÊ! `5 KUuիG]q$q^bTI! &bf&]rE2]m2=_w8<7ſexL+|/rAǾSoD(X's=A3~ E_ܧ1(re= UBe3c⹰cސ]ftD.ULk{{׮TY^edS 9̘B&seT7)f^nD~ t!?E( ޗ0S<5@KD_"KjYM3]l^Hc'-y˔/ZdQ$Hel](U0I(x9T9&H15% 8PI!Zz_ˍkC1RT+aHx9XsTX+*/8S *&J3S ԤU%FTZP k9{cF,.$y̶LH7ƛخI'}Sgq]S?,$NVT/^ |OOxrlfܛ!"̨e?z4K=j$?3깍 k]c5TS>E:RKja-FLOL{C &v#t8 j~yn}{ź<Ƒpa'NƒUhJK6NF!㌇]h8nr^4aɰ:L[xDL{֩;qB:#c^"^t4O[gȉ˸8̜Ii̓q 2!eUSeՃS̪OJ. QW fiY~rI͂W'[4ׄ&+aw;LĬ,pܣv !saVާTty3`.%Hr tSؕ!;M<p*;>x{ D\j.hV .T1xDHEvg Bc21;˔_#dwH Tj)hF (0W˲9Iligvpb(5pGOT}Eq!&BLP) tɸ&h+J-rs=rvBr\q߇b=@KmMzru9OeHAYPU~Kcv ⌘P+\3/Q JJZ~:7˫<^==XE(6֏=x3M[#0M O{@C-ԑG&2@V|6  R%جeu4sH+e*TnjBc")+ZsIO4CȾXƖ>9C\쫺3oC}IIAUiG˥^i]lFPfl;+^<~k!rz3~a?i!fփ}S J_d}Tkl\KT&T/\{ 66sl WnB<.=ˏ ۦ_1 &8j,YRvԃ|!lYy5 @*S|-ƶISUgQP!f7ByJXZh.9*lq#d;KdC ϕ'ᵇ ThL/aҌM7 ~ lnΊ!|+8a u+o@Y \> ^VH>Ot7t*I=Pu(b@|=2m4ooBdkܯZ} o6-`߈}pp[t!KؼMzyRԞFYAH@_U7oQn,.., wGUa_1g@c 9!"-KO"xBe@ۓS^LWGPSoؘS;;FU=T{q3gz8 ^?Ei8Pg.]۰<q~ y5$Y Qu=ټ~rP8}ozɡEW!>3(EYi[["J57\ԇ@ E 7IWD9b$Nco^ M6p cny7V}0{ aVMSŪijO]dvh/Q ~s&bQ%\M8M w_𯱮WsxwS! XLD2M1ko75! ж~}M; N wQEf&[uҞtdW=-- hwA( %5۸ZxTN0=ۯhxܰeXƅ)if@bRB7f:-VTB__ߟ>|r84 k)YH̳ I5} |wDtjw3\c2L4pn&n| O 9I{[6%{x$x]:_ ⒮F%lGkW_ ž(STc[\X+ݦR_ 7DQaSv ͌0pRs _cLU8*V$znH2lmB,_0s5GV<&;.Kke J+4+ ܼ'L7דlHu Ċ(jxmAk0 %5ea0(lXIեRpn0g.'Z|T;:gq'(wM(XUSm1LMH_fKs-"*J(ln?]~벻YA$GRQh61z4}hG%J!p:u˜Vtg-_e9`ړ!{jk0?BxQo0ǟOqҔLeXTJAj@hOVK]B5[|wet^6,7Ue8c>3qB%)P߽e#Fb~|7tգViaZb#,|ak~D'82'~vo;2wpBIƦ .Qz P:Ý!4dJ̬-: )CjwT$M5j7Gխr[(mHvFpaVz,ilR:{C?vf~ۿ,H&JqKQ"b?]4z ]43|A鮪F30Y"6n;M֚XZų_qYr:㐯XOc !wf~>4I&Ms^x=h5Dgu]/UxQo@ ǟO "P({VlFRiK.85Eww@IV!>ǀY1"[a'*3oygc(E/]&~^@/=yΠr]| W׋ϗPg\C|ǔ X=.W"SWe?Y'D:!B7 ow Qp2i ̫ܵgقL"K-`yJWKr´?lZxVYoF~64lIm9E^ƀH 6t uX+kcr]ZV,QG I7A a`.֜Qsd`rcaanQҐXWe`N qu3+.f a""ĵJk|0)!\9!ᙔx`0hrd3Xr&FG .6 K;HE(k"YD*͐%O}>?=a6SgQ^a8W[2a7e?-Y)$񞔈qm@ ֪~BmwW{:32"g͵C\ ʩzx3gJ%С[aEoFwp3yށC˙+dmR FMW$|F1O;1H܈A~%ZFռnWp oMyjuZ>t>tFkW>K2lDiNMtP2D٪]* q"kȮ2j4 nLǃAeQibA]vI%˾~ ڥ(V ꐃ(\&+tIAƵV:dmu~4xK]4_aUrlsj7"x6=k,2Z0 ̟!W_G~ыP+[/*rй|ε_}\䡲vh1rpmN\ġoq-%)Yq2VpY:"Xpܔ$\VYʭ^mM4Exv7|h@:~ourr,h ^V%u[qtL3oWmpt܋  w]aDT?٢Q7kw'Zjl:v\@ v ­ч`<9 5ulɋE?xmON0 =_aa|@v9w5*N$!N^xe{zlc- e,<.Ⴎ#n5@qp: 8jBY+h`*bYsKRS.tL,O+>wbQγL5WicЅ9״?*G%'䋩7N] ',u7ge/ \ \x340031QM,KfX"kěWϹkMyMa?xSMO@Xv%ouxSYo@~ńHa 8$>]Pwfw vJ(}31yH0\,o7_lg"ZQlZڕ1uTEC>aPG߳%L}ؙ |ϓI_j&Rb9 r?7{Z v8;p鸕dQ![W>g&iޥG4T= Ad ?9a8TR=xCJQ)3$t3q }![M grZ^XJ_Q"X--K l<m%0 vL JSQ_VeL < 4p P"T(0:S{D#Xmv9Ҁ?%d+3)x· ^+כ8TEgÕJh..@5tS=dQ6Qa3L`c6[#of-]|E]F!<°-!W04Bhfީ8}'aU4+x?/ۄu&zkZܩZz. {rfT7u8 &F]Vn:hFuضPwt6UX9+հexU]o0}&J<gti[$ %$X 6V:qVs8i\fXs|Odvm %mQBZdW6ߨ}Mbv$h9Jdi21+#\k,kJE>aOě2I| s;ul}Wj7ə]>z (O.9kȅ5P]rL.8XC7dÅCPE@}sVl8 g^C`q(exTk0lR;MfRK7ʺ~(K^\l]ߝ~$l}0H>{wtx&$q|3j%ͯ!|8t(ˮW*Q"!~Bř/t7T'(_g90J(6}Od ' CJVS9p40џ[\3ÓC@DmPݓ.]]IU%2mMIv;%ru//ЩW64D ʃP:>" ,BI6s*akѨB{󀲎iqX%] .EYKM=;=ymOhqs}g!?K3 ČUj>kc4*UFLq%Oyid$[b(̶{&/^RζVj: {60~Ľh>t '=Z:3Ѝ\9B@]s:^=bG>SyhjAb&Ny!S}A,1>rb S?[O?ml܇ I(n*>Vө( J H?I#r(J7ٝ1e XKǴ < 2'ӧIo)+_h|vҭ=_:45)և[cb:i20eO!>ITqc:9c,=iК: sMd%Tz[DVٱ*6U \vs>ȃ].*Kq0qw 5. T/W+me])+e ]ˡ*R.W\,>\v]CLZӲ\9ˊvWb$A*+rH֠ʞv*79d"5).Ó1Qx340031QK,L/JedSgZ9glAC*Դ̜TUu]v^>4 ?G_O?w+E4 xh7a}:\P%EEyz e v3EU6Ϛ'%U_:(+׬zs_d$.BRi[\RTZT<؋%^fpu5Z݊F)E`CN=;.[z|mp@wf$g.8w2EݞKNL*O\μ!5In~RVIeA*P}btN-;d} )5)Z,,pwʢ_w•"8'?d2O>oʉ-1ݏ}2 I9(HS`uC^[4b N?z(.u#A9~?3rXp@e=f]ۢm&H9\{  lMR |q5)Vk馤$f>Dߜ 7Ѫ+[X7@oT $8Smi&bTg b-)s,7`*~ @Ĝly~9h_QuU)$&<[zreeP5O'Cf]<9OTȜ~f߿h n\S*iˤ1Rk}Yf@7h B_ĉ=S(<Ӯh:#x=LB4@}3/;sQ~ȁ?FIXկd `dCᬯaRK3Rs R@hgĖΚpǟTf0pJ[(<fhdS_2YeNf3" 'M6x+OxVmoHQ486t4TC'# I{װxmRUofm"[˼>Vcׂ:U1[LxC$(t}+/ǁx<(>:0!\ oVydW2܁༌d \š/?*TpzNƁzJ2\!`'`!x6$6XXf~0ĤXۥw,$*ij̸ D"O->|Z) |4%\u>D6I09Ex2cAӐDތd"tsgBP" % qDUZc올8G`*Rc*6#OWy#;k0r$XnIkyvC,8Y.J^"}$snj?l|SNJR{aLKJDc;wGrMֱsNOXeCHy6I-hDzw=u*0v $<(~>M=1Muv~:!lzጌÑ6~. l~g{_zX6GjtvDų@˜িmL{vKs X6zhӼZ⸷A~uaGTz^aowӲҫ"Ek°-0eˣ>xZw1YFdJEH8n Vd3S!W&!dN,_:H;?XrVKfԬ2i#gzi`9vml:P۞G\sRmZ*jta9el#ψUH-oVpRljlG;!T-gq"lwP_CV=(ȉPM_CKUۨ qmYRo5/ڷZg:wٻ}g UʨE[/r9D=pݭFp gE8LXxs eٵ" Lr4g&|@a`6 dBwqf~-C1ܨ/"JJ0~X\%$i‚  -.@i__o5UY/'U*w_icjx8 -Wextra74\afdef OPENSSL_SHA1]+H)xeRAn0 |@bl r!h[,"ÿ/]o 9ÙHI@&^JL5sbD! Ǭ9Q6 |i Ă"y؂ZW}mʆDTm?Awt/:ה}ĻAB575딫QodzĦ>c"xcl/1I˅>[p:-ms2բQ(ײc-5aK읅eh<$BUe1XFEms#PЖj&_©;Ɍp4#L(;D%fd}ɪДR3)m 0F<kM\-#ϳG/ix340031QH,"̼ e5TfsdΩ' ! <~S妹ﮛBqbnANn~J[ꔹvg}t0v?i,IAx <]oٗ])=iG c0YlYH"hOi_PI)KQ) Im}y{=s,wZAKg A!TF;9 xfoݬŽQheA9kHOh7NvPL˵fuݺl<$$ 'jYp[F٪4f?G/; 0 /ջݧs|D?[:'"O&=+gwm'D隞_ɳ08_|kHuI{뻃f}^̓4ٹN GChcFPfBI`>I|w"|A!DŽV}.rL ']^-Rw42Z/:9S]w_?V,EZs).k1Q;=v{"gx[]b_%ݯE9E|ӋKL-|1bgo9yS.ISoyɫ剩:)04 Rleʻ9+]0ڰ(h5.g(>sݔM: GuMBV.Y_ "g*~s]w՗ȵx64`Dzus>9S v9%EV_}еjk՛f\Lo296<#zʻM(9;p39.ǴۜB>faۡe#ڳ1=go凸I띿6_6S~Lɞ7鞴^ߗ/Ύ_f<~a mnrb9Mzm/هٮKDt׳ު\LŞrr;fϠ^;)VXj}W`.rbϹrfanhϬ';io&hg&vv +x:1q;a:%;c#wUyoc6}{h|Q*-.rbgl.NeT69S@vd~JL?;V<"g*vV.gQtϋϠ!Po ]:s3;; z?0(D+^:9S'f0Ne17\L%8؁_{Vˈ6sUB9SS.Skl~qѧHʻ?M4o\WBLd,as+f7b?̦Ej<}OɞRjb.=ET 0.J6ψ2N2btK\L?,H$Mts ;șd1n ўȏ}!TiY)>6?Ow~&&ib?̧dgW{.sjS(F޾=^u. M)5 X͒sdcQ}y)Y0?lHߧZhmx[C^9Sr$x/kxU=uDM{3qo̴]C=5s 9|s. !;?7;G#vr7LRc篧{4Cl0o~a#A:79?m}wRfcX<އ5̏[gKP/$]ח;{a84 ulaIWQfb;+|󉛿~?MA3:#q x 0W06\dAl!%v>DӨ .y0" qӣWz[JDzHhy`TWaC_;f޴4t(9GXϴ~ʨi=@+TCv@ihHaOع2=wiQ֧,8ZfsFly_GD֏@oݼlI[Ҿ .HbΟU/I8%ж٪Og[L5P#|29h%hV1-6$ Q?b=VUc2(&Tm2t7 ~0[QPU?ysnzxV}bSqXV׳ɧtc/VL*s5r_qRҰMޢRBu<~sl?C/r ʾEE>ۏ/Ir}lo ȧ}p\u[ .9xrӇna9?s.grbtUȃd<_\}2?l yJh@Zzӓئ寎\Xb ͂Sp # ^;󫹯"tf.z!m9 'Bkv9JNdK^Ζ" S ~q19\k%wD zHެ ?48)04 Do˘lctE26n;1'{sO3`OgJnVIR/0<Ƒa4)+GY\hV%D{s39 lC/Zӯ,B9em39I)#pC}?H8$c텦Qp8bg^ߥc'lŲ8UYL;W*[|Vn{LjQ(pcu@Ҟ -C'>HC0oO[uaUR%<}DN0ʜiЕSwDw K&3Ms'`8&gog[W9MG1m=F}Y v[xNs,Fso @"rN`=3mfa͜uޞ\qK8BSHzE*/X|1TzӐ7v~mx6|xka< ȿ\l'|nmo),4k>2fl:)Y'#u`Aϼ|3~6]j}@vvq+JWWq ӧ(K4C;ٮgNߖ)Q&(~84]N/`ȝmTgSE6}/#rH4FJ9Qri*)zgqR #8r MawJ#Q\> r@:E1` yQ.ps)q%zrE浹Y[l91q;,4ӔtyB5odC:8FMx88:,R_WфǹӜG?@-Vfj2%u]x4#G9L߸Ts9? ~Wm丏<ӌ\T2 Nt9Ϸ"/7ng>?Fa˞ԺkaX1ELM9'өv;_hh2CLت xvBʃHSjޑk\;w'zI?#ğjO͒<6Ͻvڷyfߟ '2o./[iu½?4OOܛG0_٤Qc|[tuOrD* FQz3ϣ͇A$?B pK/}&jJ& M9kʜdvѸ_UvH4qSF^^Xp[X~Ë_+j&l#| ce@CKQ@US8)MlViRV< NvOza"}>'7}]!K0~`D_*JȜFE]SAxuJ O+EUL)ytiYd?7Ci_u8ޖo mm5:[y~'1F(X&iN0| `fOzqt[n9ID)l?$qy]rg?bwxFhtw%X × q|{+I`i}0Oq6vU9x NP jvOڲyZj'T3'ϯ %DZ4 Jg9W]S *?Op|9i.^:&[BГU?Đ"OlqR5]L.y sĹɲۥ2v\ZN f0uj:uϴFzn9'N~6"aLd"}G"s{J^9谯@wbUtL/+J [2 ڋ|"s~Y_*}JC2/؆Ľ7/ HiWE}dAZgGzĄo/̗rd.pr7`*_ҏ24;6\}#|   wsOӅNyT<9ō9uᇷ 2l&qK)_Б3:}pUIRrZˎ^R58V:>u ܣEZ޶v^'UEs7 }KumSq{*[M] 8m G A1G*5N)8,rB3k<`ɢrNݷg<%0HUk'=9)x~|Fȕ#oƛk~x\ę`CgҶ=_5,0;<\o͙>09USK0b:~gr^Uq4P WM=ߞ#'`g;JQ/ ?5.jnT('{g_zbse&^}e;ݨ)RpT{?Cc˓Ow**yNzOra)?g{G#,cS8TǹiZb_ӗ R}9=0<(ָ>nvgs,gf9;_Sm˕?_$l7u]&L>ۺٛ5)YP(5[7Ga_,y𲄌~!Kf_B9s: g50Ηm pwkr<)b(ȵVW|'|y퇆r?7C-> 3AlS-_t^w|5,ׅ.t#Z͡|{q|i7sEZJ:E}N~<&gZa^dmbU ݀fGY;0rq C-JoQEg8. ce ^[cW?yR+!+ܥiTѾFLd.0}I۾ ڗM;2]e zs`  hw]F ԋ+дE cDsj7Cx0^ _lGd Wggz'6ea@6?W8T[Ӻ:8?f+*_;q]~y67 9hj YuqTZ̖'u|6够 6'ik\lcAnγֱs(eb gK,=af9C{s>8r^,@[c1~W0 6~ Y"೮&woG{O?$ CtLe}.Gv7jjE1֨O_z{`*l`W%Cb:4t>qg`U3N=eN-2n8HT*fn+;k{<n%[9$RT ܀,&Jhmڧs+Fq+6GZ j];8`е9bK3ESv ~ |h? )zZ-zxbtSqb&qb3;Yi?V./ا>0-|;Y+tBAecC~f?_]qgpĩ+1;mڿ eGv,ǛR:?"2xt^+?ʫyߐ3ODqٗoj5-pYUQ9;h sȇ},prl#s>}A/D`莆f6{(?=YE By="x,e1 s,1YnӖ'{i_ taI)t2 "yOO_` Oc^%ydz,C9ѩ덻%W!9CEPu@ƜQqd s$1dJyTXc,MhVޞMG+)9o" pGѣ{#-3MZ>2%>NZ&%sBhHI&ƅb)O~! ]tK1e\5 1y ' 9_\^_ 7<PZ-Q{~~QC7z?Jf&'/gZdA~Mq ߬]~8\?r7YlqahlzGx?r/(YyXGcX9D@ΐS_ָz,̾,68/a]FI%.?/&UFsҷH0F`x>؇V{Bmzq51e#c2 Xw„OSg~ r; _`;g.޽(@IJPu&ZyFi̲ ~xTO*pqV<9󮵬6v={VQLP$kݷ MQ0|:@Kz%p1ZJPO3ȉ)z f._P\BE<Pv9S)M_%xkgm"˹Cax,&p3Qa\(u̒cٵ OQr%CƣW#G!0MuTϧz֝+Ťty`.{z\t≬UUouMwL0D9z|/$}= 歀c0r"xŽ|wu_> +JP#]1lr|`EeӑC ;sE ^WqM_40^OdW;m(xIէT G;뺫fλ Mdۀ,ǟ FN vn8?_#̞1}KfZ ϟ1J`ߠb}[ ,ޗ]!ᚉ,Eb߂w\փ=3>W;|^.HYE57@>^je|GLW:8z7Mi}egZ'/*Ia r`D@ws.~p3L 4I](1X,տvX>[:se3sO# Ne0?K8vӑ{nFZ{rvy[/TIׂ 5wT|??c72<{Хַ;3^Ω:睼܏`\X<^b:54-q 䅎=(߯˛xa'>lUQO.\#ŒK.5&e'Glh$6 ۈpS8wcKʮk1:+*^Xeh<2D#a^~IcwՂ_Ij_Sֿ+p~`aSg!x_uZQ"o_r`EU[jh2<.~|BH|9;O#A7tK߹O\Ep'VPI-ϻÏÕW@0rZծ]Q.QaY|2;A{Vfi[Nw tH/{p{=/s߯@12J j S':S-Gn*ftLDQ>+x2AlD;Wp2q^ȨhU,t;VLwE.FChkѶ6mګBx96-1THI?G91 AZ'%O^ bӡI?8@}E5tO]fe0'\ T]a2"%Svy+sOãtٲt7,^8˨N7Km+55dd`=8 )` PNўC#uQ]޽Zu2|)|1?w#j,y@h5,?xWbQYesۋ& ̆'xW'n z| |-$&#UW<^=囪~ sp|`3q;@]¥^\c\u}|V%EhPfҼrbMIJ:}cq@[b* /?Tަ2mxUGy`UA@Ϳ |+-I}y(qT.}E_[݅OC\VuQ,"RRh/5owAG@JIUE/_/l,ȶ94Ϫ& J drTz~yHEG&yz(\$[n"m}[jY:Z^+--Zňt".y*<^ra'GH~QRM&UDO@߷JXX<-eSY~0V~||Qm}k +8ԟFLJ~9CXD\f&ϿcA/ի_0MfO!vVMY8=.sˎ&&r#a Df^2tҕ:BS|ﺏ _'UKDJ _Bú9M[l>xQC0p'| [k(lJoھ+aN*X.PgE'z4G$6r졥!\|bފ!\~XռY? "TLѼ:D,W䫾2;rw;^݁ 7쌞x-X}B]{H{v>7-ɤiAspSۣCj[YgU.?ilndՋsSV9lbjZv̧YbV\ެE wrf |^Ӣ*~.;eyW@.N6O->r~Mʗa.HKadT%P`ۖGݦRV[m~TG3Pw@ܥY|. '5.mUu\ P~wښB@KrEC,{^-]Fw}͟BU<)uxl̴ ]i^] :Ng!q M*&ŏ6ԝf,Nj>H5ȎڙԆ|o T+_j>VvۿѢaj/ϾNX<5R]}@!ʉf#xʞOf,r;OV.X*>'g5³ca@]A> R :Vo2o<:omI5G*_Wh:ed5j2o<xww4Ԫ#F^ *# |0ϻB^r+[ãi_NTsDQ3pm#WNj"\x׏l=MjܖU[>:޻~>Gxǯh5ֶ$ś \c9 Kyώ{zN6_7~۞.[Xm٫+ۺi q;ZmDtPY6?~c=k}3b~f {d3/ziޡ[3=Eǰ7#pnAﶸ1ᙧ[Xj +ho?[nTvA#+.U+@{{|wY&4.|nCӎ&e| Q{ޛ58Sw .fF^'p+ө]8kjkLXRk?x_Րŗezrj׾,iXze{W]KnC^-y&G;ϧ|y"$]D_uMzS3]1̱:dIgM~uh{y~a66ߣ6U9ư09|yN%rҫ -?0;i.;62x'?cϵh-kp+}> ͆9ǫ|?}sxv\O@B+w<gz,N8FXVf_j{.T o3c[f>bBbX Jz޳I ?+A\L+ wG6?"x,Mo>zjF,l+זF_.[፠`8N/zh97^N?tQmy(Reax;u%QW_΃MCu_09zqћ3{P[ݿ`ўꝘgmyz3 ޝ?o,]KԡR,97Rgy~U9$n!n tk;۫9ޑ8~Aq̹g0ä q,)n\y% mOg-Bj\It_nFo%V=_ڬݑ( q='ޅK94k4Vzg㘇&8p~:kD5b 9s|iݿ:Ÿod ЗH3Qyyþ%,S#~~ǜp*<v8#.,)UdCI#"g&8`g( GZ8o9 ~Ac<F~PH.A&+swy̤պ2a1IG.1\<4+/Pd:$8Bo\2D= !fnI{x)pƿ:ۜ_nYL/~/l6q"~!TsDrH聰~)29IdN Kf^7a@@F"@_* {uPm7#/ M02QgCg+Uopּ>cҺD]Q1:q͹ 3J8ew_XŽ3򽢣 'xb~:>kdy7]x$-Ʒ 4?o NnľgƢG FR@n¾6\;$Tvjk <>#)x"n1us]'VWsx?Pì?y8Fb8*`׿-yތt;ue f07X]\pȇi& G# P/_jٙJ>)fɳu'I'N 2p0Lk,`i<[w~"0uPW Pkw?5q cΧ\ہ:'|MWex|H(h(.F8LJ坈.* ,v13 @sE5փNֈ:i[ aȬ:ۊGʝg}ǐҞָTf/2p}[μ2?<:wcU<>.oO4}7r) pU mS/ QrvANj0rv><=ʧuI"|yn4kϴ D.o 1Tv]?F5?ϬjǵB,9D‚NS ymW>b͂As.} ́Of~hz9O$+hX9w|Zx~qB?2XY h$9#ED6R=*M/'$՚~ l#d'gtpe!yMƍ4oD.Um`/R^p8gY@Vd,;>!yv.<,dIM5[#/?g)sZi ?tvƍ۲^Va-Uwdn%u驪Hß;-h=c)s 4 ݏU*''x[ͭϊė\cʼn+c2~I f @Un9qOnϿ_{@*#kΔn])ﶷ>,yyoһ8b+CPVq Bra*YlUi} ?eu\R<(2]%${r/}yM ]>g]D=m>^{Q֝'7Cބ49'sG`Gn]e>v[by'ѵ8#C=;Ar8!, wTS gcJB_󧛮/3̫Y8 X""%0P%g2{=KHqCp6";_$K}yBrՕL,:߸(R㓂qRy5ǛuYeJ"q#; ?\>ՕI9ȧ>3:HzjbP[O7\t+[taN%[XrCx?fO5 1|V&y0p07@\)JjYQ%g`1鰂_7/{=ux=/!^kY2+c_ ⸼S/vrkrj]Mnˊ0r` bn^湧u~Jd/_ٿYq͸=8zc{;;R|*7 o, O(gDvҀ;o6}c^0WG~ u +V??-*<Nh9oM ^_;IJ[rd0..'rukf Vy&>d{ ~sہ!wXN@T׬AoU_\;ۭzc8X6NڱٟY~5g)>B|۷Z9u<c>2OX|PNVV`|U<:R})8X>>ok[OcW 4]13xYqbO1tfhp08>nSYJE,:nJl?I#|P ,o3D%(mJ9Y~.]<`?vάF$}x痪,B5C8A7?wed1h`iX|r7c!J,is}'ָNpG45Jsn6^_Q[ k\9?JY%CiOWA_U+/ >x1]z XuC*c݆07GO\P?hR  Su~Bc1ϐܱ"&c|Y?0_4r]׽&)ɆCgXv kQE"Bj9 7]n-o1x$-־(#AvL= ["E"Q.-k +䩛?pL%~+e:P/^DOR%YMu%ܞU-W|ewdu?N?'4fPcĢْ>*'OW ?<;>^US G7_ L.5HÄY3 >a?_yQLǫ=훿J%OR,.={gTz/[i> I˒/Qn1هOrgKeJU+= `I0s~.5[Vd&d% S^} R0<5cJ]ơ-![\ JYy8 C>9wؿN.ߛ:a {sPY! J,6? 鉎KA#<"iD{]fƹ3AZ_;fTɤ;[ U ]Z9e׽v/KdT9kj;n4ÕX;(\wY~Rp0<.Du]A[V;IWK,3j#)@5<{QfxF7^!VGA (to)"4Z䛟\ _@=c>5jw3骻*zhˏ0ƒbQwX8 1?@Bybc83Xotn $cLHu/*Rfb܇ ZySJh̒Uz?⯷kPa1.|+PftbꕟE<8;:䄶)ֽVGx4m~rzè꽍fbڏ(: JVgU-&oGl_pNP}w>ɐ_i8AP:y)ezVryn8ݧ I pxܼ%&effk\;A1@R?뒋q-|7A qӑ;-Mgl^X ~o1>>r,y}d8O 88[| ߖyG.!$!.0Pw\O'wݼoϟ6SFefTƱs'QPFIsZŸYд_omVzƝ&T./'t $7eha@b76;nr 2;w.Po6$K؝[gW{[q!H;Q0 ;"K^r `Y64ռ*F# !iawUmCy?p32|WuH-ht1E.%r]9?;G"z]g} i=7rb(qe\@}EӤ}U\DTɟ5[.a(1L ޥ{P&>Эt0y RPOyհ|ND|7$7Y,rjY'8O_Ɲ-qj=]\ď&U ip೾|7"1Y [;C0^=I?!%I͇uMhX)j[yWl }j?=`05byRrP&ǁ9Mߑ^x/59|An{gx!Dpv9#Sq():޹`냡aFEp:'|Es\vs$,ϿFI\;qٹƿT 2輼vw_\ݙ¼w%\@hh<]љs#bI>#5QΠPֵ:%$nA$?q`N@vtQDLM^eFn&n[wfUmۄ}{ڽݏG8ŏ?~-?':=h|vwNGWewe8(|Sw_WXH\O-|➜2#FŴ%˽D^V`ZD;;s}f;eVk^h_=SɸIq ^òu uפyΗOzl{q!oS'pooTV.ѫ߿ij+0fϛF@w3sxIO>s{ʹ3.(\v\Z ]n&]6ϴ7oH<< Fy:廥}kXHu;Z d?kAƄgRP #ߏpOeDy$/ڇx5FN=G"Ki1n@⒎IxXJqV58^zsݙ}"*Csp|EDz<Q9Tc [ 5ЁSd$ \~2G *DC^&Ͻܷ!lD!ea W>cCEk^؄%\)÷?byC%E}G6VE&o<%aPpVŢoуJV!-Ih .R\88Gi>H\ [c*fճp|>'1~{or| gQ^g,cq獬vZw }\Hgg||yk|؛K­L7\ q|ˣB8{øuyuY֍94˞Rr9ߌbUnL&9I\/~slʓlސ;لc;֗q2+QdcƮ*š%k sLy$AWbݿ@Tu'moij anMO+?>OTuG_b<>5wQ:w%W鴙qb9wU:w%mo‰X!h&>;cQ-^"_*S+J=l r˄WRC]/Юzky얩XZGKY?|~|]j(i]xZOs.)5 5hO}7>)yg[u?H9sݻ"sL!ƻÏd<'g!5'YZ=s7v* diwAJ6lQ3vĊ\pt8ރB|q.!$ׄ[Bmm'45~OgkEF7D_w(:asNt^G[q\ 4=n!/Xm͒N5& F8@l# bzkJ(k|}aoL=k}7gL?\f ['v2&4#4M̬aEfH/}}I9|YOR\fvw[Q/zR:v BPȤ'i5ɎT?7aeu/x-ky Y;:td7c봽!fbpgdp~m>\e^)M3NΚt*p^M]`a]HӬzs϶Z=X릛ƩI|I*[~ש/lkv IxBJA}AظDvԦlKi\bO?%>ׄ}Ϸjb{rMTT CsSפZ4o!1BCx5=azJ0f;\wb&I828P[/R*Җ%qt|xǮ8Pa)26xԾo9:.m ;<) _a}ܰx;`¯sEHjCƕZ1? ,<`g9Uvσ_<:( k |f> ma\wskpCLvvuJ}p>񦲽at.tѕK?@\^<\nߢ ˚áC-E77ahf8X~Unhj; ̣Gxdbp@yyl[,"n&GJ?Mdqx`>yyJM7R}KMrع/G^. p~&a^K8v|YS|YgׅY$!-[覌Yˡ) ,89 9CŶe|zT$!7YǑo5L7″LP7|DMa]Wj9BotK,Iui\B\}'p.®}(#Nui16[.;ϷAķ":L ' o[Ey+'nxKC魼 }>&` se-'k0< W 7>xf:ʛhһ27fh/ ^%.9aPRܻqʁ^ނӴ Z ?:${ ȐJ_gf#-?3n5Ї2pG ;1Uq4v'g@s~ޒ:q?W9o'ŅbXdܷM=óy2[Ly@>t$OGc.-]],+zހRI_п@ܐ[+s*nyBSWs;M@Ӟztv-~E VW5ZnwQ__OSZ:I>ϻ>~ <ߙr %ܽ/7>dGm6'Џ W Yuϥ vCXPk? jI~T! ͟UmX]#@UHǪ#;F5Wz|_R@{kP~tLL7v>0zSxtnY?Y5kX f'1弬kQ|0зu"o8Oc応<ρ2< /̆7vȼCKTs|6!HH0I.dME=V,dkX<\r Âq:jrז/oFnVߟ>>CWIj4t4AnJ?bWǒ8XUYPHߛuqu&gx@jٙvl],, dVHUuSiJPpS?6_Q SM㔧DV?p8HLɣ~(]@x s]BA՚zOh3^YYAɣ:>|0:Åz+"VGQ7c #| h?co.2-rh#;:ȅ!?-/ٷ0"eeW8d(@~2eFy.ClDǗ+m?>T6=[@ 62Eyߋ~eG卝{s,z<RjH Xp' &EcI/_}Z`q|<ć X|oѸ7FuLW#ۖ5 ~XEE[gLd~m`C,fv`RL< MEx/,z 4[tL_tѸ G8vގ_?i XߦUrԲ\G Y3ַhu㟮 jVy4 7(?L*~'-U|1t6vMg3:BBDh_|c}4 J;]SZKvk1*Vt~ B;9y:S`JS'΋+6\/x:o{qZDaS/ǜiZvY#ߙn;ګvx<,f_:GRr41e/*%T#F( oV pұ,qEu5~2WGfp8lZ?ݪkaqZ qs1rpQ894qA!^72qmrHC;QHJa WNm~c1<_nh ˺gT)$笣PrQ<#:ބsC/ɖ#t*$A`8qd×+IpD\ oGLX dXW6v;7o#1|B@>u=Qy]QS-perX ~>g.#K~E|vaK"/?_&7 T*ނ Nh#hc^k[R}W .L08OQG_Ryc|vڏ}ZS<_ X)jj-U^fG^5\e{TTM,ir.b;cƞ޹'Pr]2>W#}Rxǡg#s?3Tf=oSFE[pA"!tuԹǀvJۡk}Ъ[dž'w3#80a71E>gcWf2WA$`]ZX#%|F3c(ۗT;hdJ.WzФ\w(DzFz\:SYzK[٘Y&L彾= _qA'y/Iᾧ7o_/Y8z?W(qN)>X %a:qI^ kɑ񠈷/Bup i8;ӽ:[$js8(Eҗ;~(hTJ>)q-Jm׋ b\j#{Ex>!ōh  9K!ڱ"~>qv!DN.݋o?Ʀ9:Ey|h9%ȹH9| <Q1 `pS\UtDDH`V61E%~v?Kg 7V9փ)+({pʞ!/} AXʧil80y8Ex4<` W3T`sS@FK=2[]ZN0KĈLq`f;:9\J>mjzŹ̽ŴC+| O@WRۿ]W\5T9-RG(3RG-g/R)F?ПS^"}[TG,^{t$|yJ>1 ":[=ڛ/|^x>֋γ[rhXt웍oQtw>xE*q8{8SmK:9Aj%]#"O3x>%cRvpMGц "іm_'_>Aĭ9V+_rYp_)S0|kOm廓cf&abd$CgKW??¿3F.ˠ* oe!)%|&5A)Iikd[E ;5Gs/lu~a/''B"Є.o%0>yf .q5aS\(*` vtJ^BDu &Eae^f֯W}r+1~ Œ*K#p}G8,-![,lG^Ug oO;_~֝q`48+l% 8^ sIa_& :ӟFsW%`3o(Jb{8}0NE2 ۾J1z6Ml9r?*ʹwP;5[[RX,ّQut4[F#|M3 k P}6qPg{/Rwސ^tek; ?$E>09=fܮdQ;m}(PΎ.ѰxVDý SLlE> ,ǎo~e-6tUE-DS$q8 ^~1֫w9dPpK~'+sF .pc/>CU3-c^啉|!Wڹ[NM2i}S?/o4Nz*fnO\sryTy0@Z.RS˟m~NĨ p@3iWzD_tN..,meV]y~n3uqwJ. -dS!'`:.pu-qk/US}ӥFѫճ1B+;?Y3.kwE\UD?# -6cQϧwў;cq:< |޹`*gv {Z &L*6`[堼{ez<浵o2wh ۗ8V'r. Z^PGnH 9꼼`Mm.w]l /%E?71T.j6]#dgC{ƒWJ6 z~S}- 7|;0;Ֆ#qb =Z,7Egn$s1DB3tQrU{r[^{KI:آxn}|C< }6̥!p_]Ɩp(Y~mXw4P ĉg7W* 4W߉tg}LVPΉ=_ͥ "{]CQWmֵ"KMWzى?oZ٬ZniwnW(Ώa/΅<Ff'*:i^:v-;\ g<UK^9(/*X^(D ċ n}@;?+}4I^[BۥJ >e,ڤg*x=ٜ$.4"8In?`w*+O7s%۟<!p򏟖>>u{UDעNҸƐǟ#;@]vR&KUoIz |_c:0)OZȣy#W5+V\}z[MHjH_ Џ,tգlP4#Y:nՃ7QA]ו YD9L%1́p1m( O:iO~uMgk"n4v,/+I~k"ah=<&Ώ̗#|j`Jٲ,~QGh$SGz\N导}7]ת@ OwsmFAhE0^hl9ѐg@u- ~ ,'ln?A(,XRrgIwdRnxO}vŽ)<7!ϖIEЯtwo ݛ]"Ht \5 SPQ[JWF#BC?u ˪t|4=28 @"FCQ Ck EN;,d|i77 ]>6}+}B#ꌡ % <s[2_.]ZsQќP(oKE_6۞x*(eҮH xoѯ7$ţ AX}RFܭ/DȓHkww*˝"zҔ )5Շ2l_P $y A ]vh=7f.%s(V`P񦎞]kl2iɡ_Fukcrߕ;0;$G'@!P@ȫ%*vљ~TmZ&\~7b I㿆6~RԵRr Mw+@qUqRٗ@khO:P Ge,qmS?JMK@oAٮ_ߓl)MGT (_ܮ&MWPzI]C~43f{W߯yBYhNn /~n wa/hǝ^lC84x ]|eyqުV0 9: g^K.Ӥ^b;ġS^gC'g=ΆirkoqOyGеScűm-{7c0!O n@e+)xm]$.Ҿ8t>8O{q@BS'$&/Zu77^[7M%fuH#\l.#:t&m2E|:1eSg22Dǂ g]^ɟ|{S1~r".XorAXt@ȯ/R晿 rp"#P~bRODRO;_.9rR )Yk=j=+!8OqG:# YmvyyI W%1 ?HMl 3?R.'#o!% 9)uEϲ5|3cxeSY]¿g Q2%=WW^2(ܕy΁IP.6[w[WDх> 焎\)rKp~aKg h!(22TX^{!{pӓ oOU>PaDG2CC?c48BSN MoB)pXP&ӏt@KXGz:,z/C˪,]8̒ض1 u{OԇaUZrsjm;ŏn4S #GF|17M2? ȷ&?~ȷ3'?nʮs{/Q>5{ReJ,2Uen(-j-wHf#q o@oc!zqi!w^`}CMοC}Z:p=OkP0pDG-|[E1#7_ѷYF Z!vmܭү@ 6.mS Z 2_}K;*>'!l_y%B?[~~z^'Ca1[)S 8"ON)B`<[? iW*JP+<}2Ӻ-_yݑ o:=AGA(?DܳWAjBvmrc@]"% |>X> lҥJ GCGC~G5+U_;jn_3?&\] oʸ˸ ģf%|CpwD哛>8P爮9o$Ezm/2)==\~wD7mƬ.^JɆr~GԳ4@#m/=MuII7*?_&Ist(a$dp%1}Z&rGw֫N '%> @Ux0 R.xj`O,DPC5>=SSeR&FJE@66Ŋqt+^aLkX'.H[tezZC-ˊ ҃xppgxsWAL_9u4#_ܖ1W3& ^^wlOZ&n [.cGj"uIVv a\&@q947@=_3 6vor{-rY: s`H.媱Uwk P1KΊ gJMR13),p]A=Qo?nx}O@Uy7ԮX902Avܸ. Z;kƇHX x@:U =(J/1r_M|W[Q@~k ӗf6'W5i{m4 *P-ԏX,َgdDuV4 0{$%w%$tPӧEj^-4ea]:^BUD{y=\]\o_J.Ëe&wg] mY~z*5! 3th@.I w*UPi%'_Kbq^c۟_Ħdho"GĪPHA+3hLaΧ'>3!OOJ} K.{)қۿX'0/ ,^l[xN4kHf |CR_ۖ|[OnhV7iW?@~I+yCɢR'ε>4$G` P Z{yQ6G^t#FEf ;!p|Lbg>eFn[}9PSb 2W_;JIQV}hz9buL/[_Ywpˏj):a#.g:.{E |*U(|AXQ,޹X77y] ;^~fK՛nid_bҟf%^7 / t+t9 ~9`5jzpw`ژpҳ!g_L"ƕ1X,=%G 6cu E/=Mjg,yyȗs|}Lpeژr`zf9ɞq$@}7"."mOSL' v3K?._"\_lZie=^`vJzyۖdv<::wPxݙLLd}/pFn2 ȯB[8{ Tlš6#1y>MI׺_뗩\[O`| EY%Sx@>}ƽ{cLl=.:^ȲabK"~\AN _|R3ZuԆKep>}?T`>;N$\r[z=3X> ^IR;z"LL8D$Ci/'Q:3HGi3+Xw H[HQ GA[S ;T\¹#N۬QHZFx|+r/2.2q "ԅ"Tyu:-Q2M}ci<t$F1nbt=y`97Z 0}) tR>U|Zͯv)" %d^2D^S32fA^yȼgO̢g;x_V9<d^n?~9뙚 1p.^p/Q1*Tnʠ,΃y~!>h'SWDs\@3u1r\,;~D݃Sp= / whiD'on$(~b$Fs%qcxh+毗x}jֿ$<Ã@uo<,ƓGuSX*\l̄$=ݪvjtY\纽%FKeT<\"JHzsRW¶w$X$)#z7 Ӯv W,eLTR0SE'1MKyoi)Xg^:ί>~JʞO(?ArUu,~߰:©c URww90w`A!-~< 4ʬV&ȁb=SE'!sQ RrܙT{`.P_*SxHk g|G~)a_Lc_^9 'V0'o<\i݇}ĽuC+'5a^Ur h?q!`o@LcɎzOpLt#J.Gu=t=\f)8nH 7 {lÔ\.ϡn>'2܋9aA(*ԥἩ@Ɨxw(8UƓ9Dcpb6@ĪfLev9yTOCO NJP'+:<[_l#6$_&}m' ץHok€!&ty3O3-j `ߝޕ ;)O\?+O%VO?Py϶!6l]'}~lsx'֋AT`J?>a]T"t:Ix']kzR" ~Pghowi:@C\vڿ#O6R'Y"fB7hq!`qq6c*Z\nBz""\ϗt77,'}2ksڏVmxJC eVT7|ZRR9$eu!:SK^+P@G}i*k_W3l|)@jO \wөq.+8VXxU+}c*D'I.}}pV[^!T Ixޗ >){o"aarBv`C {v ޮ]W>A.?eRWxi"o$ΓQ{OSVZj?%pmqqز[\m#{d?ۤ"ȷM/ރ[u֗$hq4y@mz\[22!Q[ן6I|IC-/-tآb9,ȳMfMhD;6\.|Pҝ)#}/r~!\0߶ȪP\g|lDXEmE',o]0GΉQǃ9,=-Ta'~OQ+ltNonO_,P>kD΋NCe<(֓,%ziQMW!˛Q>DvP}0ֲd;Ih-`3U.)%%ʖ|dI XpgO9>9r^qXx.yg.Lݛ:{T5[c#Uʴ.?9d9h\Zԃ9B.D>=I1}̩G *.q3;T^9PvL 7 %{G|A=x[%g`MkJq  AQY7,~x!>~{уy҃@=UR+SZT31)` X=qw`f(| O?zEw ͊؍GA=X|IÞ_6ݻK6]6!p֗@m~O3V/ +^rFetq ϠsE3)&꒪ƱKg6xnO24j~0Fb<'9zҦKbr4Ycy&E'H4#e):E7rhh{Q^a:;,:S84Px$4ET̒Wh#{l(~<ý1EM Ι[-.-qe*P3ɹy7q⩇FԻƬ5n~}K;tOJH V Z@=k~j`Ԭ&mnKGYcw;FUe V]W:= TNk>q#t[oy^*N酋@b>fQx::R\^} U+ԥl8kKg/^]. (r2NT u@ijar:o*=Ixy,|9Ԙ[6hF3k(*T9?4Ojl XS?Ϻp ם'1GM[lRvú: Yv;S=ԛ~>'1j ǃZ Oi+qx41~=j Nj.k maǸi+4~:JaBɟcx|y[}7"O<{o~|x?·+$]pg;~ ̓~R|'|eUTɊ >* OS?B4xxS(tyG2xj''}‘S^5jN*4`xoqUh<>tw_r=b%{ \~8y-{B;@:pv\]˚wl|ja*CLDH4v\b¯  V/iP>Ì5^BM%7neSQ-P~| ,f} c}h$mxvD<0ۡzaRSsDx u$ uT3tBzw#^Hg6'SuOH_Ǘ}>4Hv\K>+-ӕU|F7[i'6#';ƝUSJB{VW:; /b':)J%o&kˈ/~nu&z@@O/ YzS[ҢGV2z(\Macnd0]i{K[nfBAp7 WZ,>R`HB^)N_'!}8  }uiwόL;yHW>H+tvDB른mҥmeCO*%r&|' گHwM{ֻ2ӗ5.w|ryQ.'&p:7* }j6^CQPux21q=iD:;>+?|ۗCgтGwZoRAꐘܘ`:z{r"8*}$d}OChAG=Ž+PrKǶW^>Z' be5#Sjz3F'.p@ 8IRY%?,=f`?^0 coÀ_"i+ ~f|zp z%>YΘDm+ӡ}ɵ6 ]gQԛo /H#/gYrhh8H\pO;W*ibt;f2GXK Ebٛ|w>?0CQԯ8=it`_Ov^!?+W#^J[y.̽tHy{pӀ\P0:8)zŢʥ/s6&c\_;`S݇zd̪:H Lh|ynKsu 3H\b5ϰ';ךxKK|)<@pSn"g^uL|=G$ ~)l/TLe䊒6={l_o|)lC'{qZOAxqDk-z6s;/>"Ma[=2y vOtʲ?'N~Dʺ9"O05Ѓdp @iGYb<~_x>5o^.4o/J;@⌛y#Oei9#u .-yEv\ALN1%)>"uӉ"E*E/=䭐RA"2A +,ukݖw\# j?p/VUzڣڠooCLiOWE:KjgӉC4>NcO)䰼K7Gp=yO iИK s/6;Winas|HfN? dRs;|R+>Y6?n$ iE Np<'ӌL鞳2\[FϴMO8~`] +.W,I~NnL=m2'dP($nQ-4;7rTx!qZSSĮBRjd?h']%ozGYV,If3“/y@V2gI̭ $˨KmY?f?ArQ?z6߉5L> o?gpN(F|%SEV^K(TL&@Lsx:+}Qq1e|\46BdoM r~:&o]$ ×P8?’اE=+lK_vD̒#>CNP}=0ahjb4-[b܇ϥ> L]**^ =macexofV[%Cɞa߲[tىU\ 0faw#'̣f.@X5G_Dc{C:,'^$ȚA`$}AAs}Ed1GHAy'Өh<@ɓ?ՙ[u(qHnpKہsլ}{0K,\t@k'ovzOa^~3Lh뼁 LTr -i]UmW ɝiA?yXoTosS:wT}ҭ_s 7gd2#s} ;-xz*9aN^9u\AօYttC|kc3\{3-p1ԫ[bxFWYY|B+ys$'t8x*y} BRT'HmᏦjOj^ޔG#y?)M}Óݓ5Jg~72jZ-͒ShdrD}~DȖkKk+ާׄYᾬC2|9s+ƅzG !wZ>;F;h@"ɋ%h`Au@(Պ})H?;䋶,5PoAJ35ٟ kz|[Ǵ XvgBlW$P\T+3]3sBz+ bu( .п`ZN3^.wF%we3.п.킰O\ڥCǵz@TӪ 2Pz{N˃aVy#TIX 'E60N _3ǹWN}+* rzSBP 8|2l[&mNS%.xF=D`~u6A}U }x_gp9znl84/^+ղoH "-t np H7<"ih+ɲSq5cxF88qQUdGWt`3%B~l:(Gv7}wxک k\E3ϭWw\=oj 77mC+OAҥ/J;X{>ؗmJ0g9.#]āuX=Pӣ_||eVEu!hlH>t\עȢ➓J%Y-z6FaKͼo[O5L<DM{>D'<ӵ`<yDVd y42y/S܏l2Fԡi`qڮy/I'|o퍃-]tckQ*Su$"ỷOdži.2$/O@/3Lkam? M}o} #]vw߬qV-uʫ?7~+u$iɷ/,:N`?<|w-FW"+uh툝gcꛉe 4S|x@_UYgߛվ]?9ZO%ڂk߉2%P #.K`Ǔ[ߚ@ tW8yͭ /O熷O葵=OjϹ^k:u4&ɓڣr|tͻMU0BȵlN/^ϴU{wt7-,Nr+~psS pzCg%~2Gd;3[ qeۦx\*']qujt w1!HƙHfh̓S/1ϒ"Mv/ՏŃϙxuՄ} Z>Qa7 8sOe^p!A*'C˶Z\G ')@*aA+rzYIbs?I8I~X3 83<_r)@(b}J 4Ɏq~Qj#{U!?F6_VY/FjSP¡I_ j/4.x{r7-QI^~/>鯏hrO! ߃}Ns:®F6\ʎi8{IiT"oz[XSʭ?w2C_?O,cWں6٪w ϗJxΧn8b? ?GuEnDh qSUs PqiJOc?zJ112S-ʡ۽?:mL,ecUnݙ-y潯uWL^ 18ϙA7ߎu_ |nAXR}V#gW$3p6 Yyŗ]i2o[b ]۲]Np6-3295j{2/'x`iЯ8} BZ;>_^&0 aNM;Bx{w L[|}hV`'#> y{1 n|\1~<{nv -\QA~F!C;[^) "IhrkW݂R:r}‡z~g֩d~ /$iJ)L,Iro+X_-iSĩY߽haJ"z E0rnxQwdx9ZߪZRZ*m[Oz"Q=j1j-Lȋ6N!b-sk۾LF$l\aZYeemʦ$F[xR wcDҙ k>~SyDt)^#Ӈb~ӈcsG£7(KW7H vxg+L?4(0JfC\pC/,˶UL @jL,lxWn7Q*Bu4~?H }\[VYH}_[1.}R?Ь`Kg~Fյl6)PE:2^<);]>JTY#U~)tM$nHg E~SoygmRڵT#fbG_y?\7m~rctxZ;>>8Zutu>aXy:GcٟdK" @xoڜnOɫɒ7;Dr %t8D)Tox'Ar׈. D) -}e_m+G H1t(~Ok$ۯ6('7EyiňdL@T#~D/T,%/N1&8#1 9ٷ;^87~NG` !jW('l,#UCxZ( !o;xLjٕDIhOb /`Nо4{ N*j[@G l٧Z Ԛ%M2$^`LZ2K>F̝]i-MF|H dnWcvƻEmjvv?Ϥ)7L>H\V_n8AjWu-8sVM%H"`z&i,Gk<-:3g%@MS#?ѭzEYƟE=P̠@ 5"9u@8^ xxf2`Ml䢠?mK {fբӏBcxy\L{Oie*-k9g:t-Kd 6jI nY.VBEe.B"⊬yDqDt[34sb~}r~'O| s+жZ?/c,Mܷl`JƒZico:nh15?QuofOnal1g0s] SE_zxyfKg?N=Efh1>S|}my][w!-߯~ӸwL/9[967Oz=Έhf5`2 f29Dc-<yd(T.I̕ ]VS`&8 w:; ܯ REDme o/?墸@wpbW* 5dm^_u󭆜ZcDvuv@>\iCܝMeG΄AfT6¦Ox@C4^^ :ù~jO.v[Ѥ M/o6XY$/bN6kfRţi! L U;̓^${>];F q Nٗ \ռڂ7NW_Y}E'˺];]vy,t}\91K!i+O;wO-yR}`όiI"g;oT1 uOœ2l̗Ӿ<3΋ٛv=rwk1TC c(u6rh A-Yԋ?p34x206ϼGAɧlцo'T_Q늊.& ^=`gxȝ!̒x z,2yd[$\܃]ƧzEfjw~eߌ:Z,k0~S[7]6vZu銛X9A;/ Nuq ނVC әHFUAӼs}* 2|WVy.C ^W^sm-XD7"}*,2/yz>Pi+\ռUr^m}AE'xW6ʮX`8 藖GZ|6n zPu? i^pxì\[YckoUsy.$ _{k^i3-v9zy/WD-Jzs=_8\MkO/O/ ^ -NW 10]Y%ܪSb??d*Kڼ>6=~az;58,8ujgі9yy;p?d |Hl~A{dz|ݺd|.?s!!u>}&J/jB}!*hqznΛg9׆jnk :2x2:Jlu]M:_zEGgtr~.gq]P겳S$/?Qtۑ7O{bxB2>ioCuiةMHS96RM^n|a |}-٥ΗPYLk15+2ǯYw>InGca\yϕ‹͉6s7[z^Yޒۅ.?ΗhY(,n}nM]ýƷÀsf&]'vT[;7ĝԷiU}nw3FݺOѴ-0zxżc񀋍iO߹[}_VJ6R)Ҽûͻrl͈Yvwм-Y 5H/ϏF g;xR. 5y>'/ fp-ui.w]g%^o6jAHa.Ϗ5;"BEGu5m m犅Uv[{nZ|W鍯:sO-r00`΅ý͵Jr]0Fe@.!{vҰW vh}^uڦMsZt6.cKi#NxX/UtZ`eޢ#%񦎴5Ie5ׇ\6N/.NyKGKZɅU\ >7q?'MV,^4)@6XuncdHVksɡ?,teq_s{zg;WunI'JqA1?.ԴO$" LIa A ZkkخCr ~խ"ι @ŜIQI0% LSHүOalS+rhaۇϼ[DAHH.4CR b UimdI !0<{n9?X@gm4ڢGI0hB0@ tq\U0CocVaovЭ/&XBK0\uesedHo+Sr9}H%qIDD$R &pIaİDB b!<}K,_&uuYG[GA(#e RK1g(t(mnvS7ڤGasŎdpr!0f.,0Ҙ!&vi%}oyjTn}@)1(L4 'cG! q eD2(PP*&qT#7@DlH+y#Ń' jϼ0xu=p-Fp60c1+}, Lڹt}2'yrWtp뇐i.!@!׍$$Q(UƴI˨Jywd~x{N2`տjι׃wqv Xïcjڟ/Uh\FTsP+S&$v`ɨne(7+IJ9I&r§(نN?ܯ?'.{}?1lz/ zdnɅ5}}~>r{LKO 5DyccAܲ5s VY埿q,FSf[N=S+W˳ݟ:|;^okXTd'w{\庯|u^MvU/}δ9-eQWU7=JӾH(+8c~v@PպuT2NJ3\ϓ&H_'vk3dxe3\Xwh4"}C+"\o:$_軾mxY"x31CcƝJN9oPrY<.,rvٓuF6qorQ "ib0yjOq7Ƭv5V*ȐiScDsy! 4Mb|^`Ղ&|mg}K~"inʠUe 뷖{m2Y|5"iapV?w]/*i؃ ;ۧ{:}/"i sqwo"hЮu7n۫fy.5q+C%.iNX؛ªsLυUJZ0h0)f2<SG ]ɤT:kK} U,o"lPzy .Zˑ+ny"jƐ%W3aɴs.oPJH1DIbCLi+MC%?~q˅۵wesJ0^`nqϮϪ#P"Y aCOOEo_m!ڢx340031Q0M323ILK27M45K4MJM67121NJL263OJ4IN4`8w[KDo'~Qx`>u? 'L .Lܤx340031Q040670L45I4LM2MKL21013H4N425H21166M1g0_$߲=H}9]!̄4SD33SC cTs43K# ) 5rmTG4T,x` 50K401006 (*-X*wʦjϝ긢.fB ܯ^xwx+)JMU044b040031QrutueXlmmAṃJ}G;UTWRQຳyv;slzC8Ti^j9XrѶ_,ٟ#4'^A0u.n9)x340031QH0NJ56K27N60HILNJN27KNJ0HK6OJ205gYrm٪_s-x`>u? ĉ'L Hx340031Q020J261KJ2HK2HI2OMK3NNKKM2N67HJLJJ1201e vObI<*/{ x_xQ 0D)6ͦ "xO-FbEo0 Ǥ,ske[Pn8R,EpD?g}^3 <GhYK8ЖDA);gݧjp4-r;sGA4ۺ=(in7IKFESNx340031Q0M202MLK2H2I44&F&fIi@e ?zY_N&_~q s xax 1ENi@k2 "X$YW0YcÅszMD08!s Xgd::@X0Pw"F/RUzmZZV}|/o5I!1z:vUim}/> F-GԢx340031Q005OI1144I57INN4L175H1HLM5431O40NN23Hdk_ 䬛׭Lk;yxwx+)JMU044b040031Qrutuen~{T}ǝ6^r"(1/9#>-3'Uug>6wٞOpҼr_ʧ+O\\iy|tI/8x340031Q0L40H606L33LM1HL2MK03NLM464161IaПg;)`*V3#/9/xRx+)JMU0d040031QrutueXlmmAṃJ}G;UZWRQ°\erw soT%Ԣx340031Q4307L6L21K05I2640MM4771NJ5K2L-b fx5uۦ0NJMfx~x 1Nۀn` V.`.pa Ô{StlH,_9$$cf&hXQ*g)cV~p~"Q@JnZuӶL 6̸u=-x340031QH17HH343O60HINMM04066HK03HM55KdX>M9jƙ?V<<j9 x_x[ 0E*fդ "W0-Ft݁pS[Yx^ Db CLhut}8X*4ZsYUA X3RM) s6輢Mរ&Jm;}<\@ޏpĀv?jۺL?HANТx340031QH4OIN0MN3307I017L3IKI12L3541505Jc6m9GUTn> x7x;j1Dmdǎ|M3`V{ >QvL0I?!4Z=!צ8F!rsQy9]$D&l6A>jFWҵ IKNiZ%S  U~̽>' w [ DGڡQ-M>dO}\8g_ШoYr`x340031Q040K6LIKH47L6KNJr,L LMLҌ R.\nlU{O]k}:x`>u?$ڐ޺x>ebpf x340031Q026642H3KL17H01N03LN5J272HM6I5NIM6cXMFUO,Ǜ_]q!i2Wźx`>u?$^OXW Yx340031Q0653NL5N34M2J2165NJNN5N452OL1H4I3O*cW}pߎMW)[- x=xKj1D)zUB-0uV9<#+Wu? s*M3x340031Q00040H233I5I546L4OM45LHL506H1d`.\%qqc~Q xRx+)JMU0d040031Qrutuen~{T}ǝ6^r"/\F0|Z_8]nzp#sx340031Q0L2074724LL1006705H3J47M37I5637L4bԜqEzҹ>0qU0mx`>u?hC opg<21踰C 5x340031Q04NJK3740347566535K5KN5KL505067073eogRpwc[_p.xRx+)JMU0d040031QrutueXlmmAṃJ}G;UZWRQsCtk# >-/y.7 Sd! x340031Q(HLM1O6KLIL3346H30101M20411H1LL4O4L5L2L`rRWd&8nntlCr f(9*6!ˋ8ݓ}}1Mx_0 @<0Ƭ#ÎM?߱ /7v}-W'=z|ִ3=Gu `\; 2/KKLԍb5:kxzl݉7z1?a=4kںŞy?Vx+`WƤ6Ũim`Jg=.'X300.W@< Nxg¥ޮSٵ%/u sIι|u5)L;o-cx ptf```bi|sr2h_ܵal3  y۶eHԎC݌,lEKX,ʺxC7+ͦ,>?rJXkGF㱘4yZO$etirCn;]Rwy}sIbe3κ= w3Oh߅rcy.Ӹb2a_{6A&5;ދ(Ü -&˄C7BMvify-pzeKY~*YnKI'Sl_{m>+>Y|ZR10iWj$8=+u G.e\p3mGWY[8#Sԫ2m)p͍sVL 8})6=9=tAB[31Hd޷x^ڟ7΂K]kK^׺x}= 0g+q1PCQ%D7XlC jǥO*uF>n󢤜yRiFsTL6;)\HrbU m+8N }#8FY;+ǵS&/kMj9x;ŴiF;F;xSK)MIUP*I-.LPR&ĸ\=C\C422KjSRDZQj&g:P(5-9D /JP+дF$_RTZŐƐ1X.1I8xj@S܎#b(]EQJAtQ*%LZ3ILB5Fp;'s ]3 +qƑ~f?j~wYm݅bx̕I[.]2BlL[4cR^RQ/8ʤzf+!HK$QL ѫTPSo_tLh9JhmKhIh%4Z7z:MVsy1 )H1 JEFUSֱPb[6IDCh&O?cAŴ5,_y_)5 hK%2"zR Vo>8],mJ[x`aVGH#Wl6LMvT؁`xWmo6l FE6)ewC7`^dhaMM!" IAzHJa{{HUbC%e\h{ZiL5 =OnKFYFjYmRIxf1MdBzKBRrNTLn*%deRܣhW?u\=$Ūu-՛ŜKʔŨ\s*m-ɈR5^ yJ2x2V}zwyq{ߟ=؉e A3-D ZDXrL( =Hs*)a`k%see)JČ@/8(7M^Ͻ]/e`@UHv}1<#}.3WPTdLf?y_,F&{I4?3[Mս4i{Y Z !9:Y4^ew*V/YQ<ᙨHq597<8 #2A")Q,lF 0Q,9&;Fp[!j+֓ XC+4Ά"]QoRjEWM&n]]&}ja:;[m lhG40$"0]t+"vFfFۆn* .8cr\l@d| &mYԜcsЩtoGi'CA"QWg:2ΰ _<=[`}O]4gK 7"}{M'\~%3iZ4K$]M2!"|T׷ߓs܄L;axoW7(†2@_Gߡ<4zda"͞ J3.@gI <m)xB\ /+GT}+}Upq]$+ OUh_d-ݱ=֯k3 l]ʭctbPȆeGa],TpIQkf|pV_asX }f ㋿̎Gb}EYb([ zGyy=㌫/^ ^6k@8";MVӨw+IjK.@x=F DrHAUEVFZtl1O8km.ÓE\GTu,֍_>+(xVW𖃉s_YqNNKO+)U#C Tp"d?AJ܇Ա[ cs RF/ 6} _(T\iJ~^I|rbNN|n*1M4I?YxS]@}M*|R냱1&>0Hi~{PʶJ9sϹܹ\"k0VX8|G{4cU6@jb*ŔL X |KK^qOvF9.w┆{Um\|/(t͖8y۩\r_SI1;zM+th}u|rmIJNCI=L±㒄755SFДePV1L^.a$ڋl[X^"d!kٰz'B-lA; *UX=d!3ˍWTDozwPIZ:2HaFw:BٵZ܄WGgov%9ӁF_Ivq8_:]"6x;7Lt9HkbrMRa: <ϥ7S FVfqxJFN=蜠>?01: &xYmOHi&1 NGD !UtoWYk{MVKv~38CޡVXwfg*t+$|e?Ԫ/U)Z}qzw]YMU+h`/FQ0-4fG~^~;?~?y6k+zaMnd5qmuSε?8$J `^[Ir~VP~s imմEQU*kQilt "U0/k 0QtҪT+ʃ>49?k J,Q]=*W46th.h%ϫ>'3~kUo%|r"+I4 j WA+WNWl{H\tjg v- ]c[-cL*3T8ifkN6u:]qhfۗzWZxQLA?"n7,CIj%hBiT=3S3v(Q?) 5O*Ԩ WfW'/@R8rBIҨޜ_Y;N2pxm(œ…!*CB,mxrx٩RSmb=CchY2 Uޮ֔ͦcݸ60jɎI$:Xךa/_v'/Nޫ-_RX| 9CƋ i-  ȴY$Y2C8kv4;$C맫H~g?:oR"pNxkJu7yXQHOVͨR?:xu!*D!ntWz T7s;/KmہWQH&a#49H|XT^rg&jS7h}o9 a#Cbu9H!OGcT~c| 6hz1N[业 Ve]b[.e`(\Md{-Z"7r^Ow>k<'\AMϭ4^81gkw?޼{y2a2nCv: KŠݤ`m6^3fޟ|ԇle1G98=2~O8UD1O{{d! SqbLi&]֢rKSX(TW:ӐMS5s٬&ш%蛲ctC`?N߽\ߟ~%S򸻾7>y<}9VMьiYtUGeT5ϻ*ƪ}rs۾zNc}N~Lҿl~YR[~- 0l~Z>gnVWi`jGG5S9LHA[lB89K+[NJo"ss ;MБ/QzS|Vt`AͺѓћZ!`E),70N64N%8׿5·G[ b~x6A{C6A{Pޖm qb|('mМz&+dߊ2juϬRe`2oe30pwky\fw@[3WYq]RQR੡l~,̀NB{qtI P @NK* D=- ik \10>ОqǕWMp14M̦&-õJSn4Msz|/O/_]l޾obUm0&G7uڲ\ Y;UU8eUYbI\A >s R8A*U(d)ΨfRCIjz3Hʢ50 I{K񌖠uIxyFW+Tߣ|rsZ夑{2)CxQ$֐L靹VLz<+}(:(6*)I%!;o$i `YL# %%ϭ[ʗ(/Lr Zc #IL䪒UpX˰Ao̅}y$ܛw:Ӻ%~컬h3Vw}_ueȆ4_ U:)Ul=lP! F.aH)PPSM* z)@`Gr^LZ_T+L_mNzU`7[Q{:]kԦ;E.5vad'5hYTA_l}z/qC.;Q!052|ֹq(~`u۲>!mղ2oc,+Hi$O'd<~HB[,IxP+Um6kuV8Eʦ/mL~ӪE!fT q#k-9=1{ՌoY3ETq,ھ*Z JAJA\I9,Ҙa+Ӷ э]Y:yU#D9Y[ ֎âW $ \w0l:H+Eoc#Y:8 ]o!! ˠ`8473G Lnšs(p隀ЂS),X4Vlw@8ٙ-J%LG(+יִ@|CjxtTA~J̐6LcJ#NXWr7ot0X q"N7F(F4 AX0"(XP6QMچlH!YE)GG?Wt(Hc+Y+ڤJzil-Eāa:L0%hW⯝V%Btb5K8nJ69r_u|2l7\) Pjo$yet+rFh،kô=MLJVȒ {0WN|יLU%k|D2J>M_欩:kYcr\U`wO3jniM :V#7KӘR;nw7/ӆE>2~}ϳ{c"=Nc )"Puur1yuL%:ʛz1^/[ÐښytJ0UjF:&Mˌ`& ٗ@NJ,b,5ӻeq\>w:sۉXP^4ӳd7=4 "s<~1y +nag\<n(&Ϳo`2}h: I<ԵGם5Wkۏ7W?9loW7Wo6?\H)B ӆYbj2@$&Gy#FcϋDU@&(a_ID3DqQAeTZ>T P_!41/lq ~{3N![Q+E]BKŷ߇kc[ۑ?tm}7w=9<R(M:@>!"7A]mzku.t)$=KSJP* T zҦz; ?!}B/ P~@">0]OuWY>|Qz_g[[rz]`2VLm]nx0ؾ>P\BHW˅jZUO?і+sm8OK=SlLdvs>^+YM~OLڽ^,&LM=Um~=~Λ㟽{sUƖ*]Q4[V?:'wۥu)drn&j,v|լ]Z#MԵh~Ѵbi̟,T}/ڪB;ê[V]6!ӏ4N3Q$eq`Wo)F5Лnn;kбlMNQ=w55 ( =,rRj#UyMFf 1{Yoo?>z+F~S7Pü7=x3ϼ23g7yN(= #Z7+1  T4) -Hˤ"iوfiNM}i~9)DMDNjJ~ьҳDgC^9)9FN5*9 "iuNRJ *]!mQRZ< k`?&Қl)O*ٖ"ui!7!mMAG7$hD:ihݰ`P@N+C.eąOaU:-Csz{y"UwhJ=qUM!?^»D,O#YDD\D9j\a5G+Ugonܾ{CxD.hexLU+i }fJ?DhbE4~ ro,Ƽf"P-C;Mѳ?ѤPEq9׫9m ^=Nw! ]PO O&X~\q.f }'> 09$ W"Z!GY~蟝u8h F=+oC_$%m?c`lTr*{nAp f@ᅠtUBܑW8J>x)?s9Ht.1#eN D A#i[lH@5,Rs|bpt2ɂjV@JnD6mb!DA9EJ\TH,tRpm:UL ,&:$fP\DP!n̬=RV) V/]݃r o!D; šG [y:ީ+&x_!UlΓQ.XG D2ԶI2\ܗ=/<7>r{ OX6J.v싗n䖨S9+ȟ0}1כuO2 }-1+,}'Y Ջe)4<WL^8f\._r_NTtW/])AP!)2G4: IM|W't7ʀ 4}K8wOxR!O<cg1Vhi h:qWpkx e' o pAi+RS`=.T`ơt72 S#vIu(F^B?p8#_ qX %w*NN6}E@319X|(B^@v)[ 1hb/hC*aAdM؈ ףmF]]n/pcGds ;ۀ] iA}E⨽]O F^w,{6Z!-l Cc G6)J$X_^Gn8fP=4-!c^IWtF_ Ti-bA4EtFmHg(7.Z!H˂[r#kZ@}^<th?eu œ]DԞ^&.PM q >p5,+Ӥyz %qHt;ݡ`}3>sb!@ x"5C1ZyMmQ! ?P6 w'^5B(Q  'DV)wo^-9(L 1@ﶵψtׇ;Mp%(. !(*)EGuUI` Wg.j P%hv!Ļ ›Ӊx+@p >9尣s;܌@YF|}˅kv-S*cvs:j MX#GZ.[>Yj^tpӺW2\yz92+טi 7yw_74?_s&jR][20դ~?gTC~X_f2ՋucMul`"_5_=Pw[GϿƢ^ڦ2N꓋W{ς_ WS- ~PS=z\3#M2<(6Bl8jA6RN@\\8½Yi?+|=8#qtM?%r`3lX6RC."s9p?*\BNq>z8|V*\0=]Sr\4$\`f>#C8?#=X)wAu`AHxEF"CD 1  5=siB!!a6FL , 2}gĈWL}U}֙_Ͽߞxx/~x|Ru߯k5}ѝi|ѓ>U}U9vdz,oI~dz/T3ȜxN2g35yNd?FWN^5%Ð'9=x?˜N7csC'9F2"T4m~.P4&`9ZJJnX@VeÊ)D>/|VC?"pxy?$l;h)d&޳7Z P b%oՑPm 0L] Ώȴ}i7$,F\YjV/WQ;ΞHݩqA>e(thWIE$uO,.$~@M joNOt-z[=L5|I2SIS4FHvm"U[T 3ufm)-I6HrQz8'n+nFlU4V*.xA[ۊG ).NiU4 $.wjUToĠ#y>Z(ɹ^Rk\?(&d%"W\xP06#"o2'jGմ+t paK=+LP?|愝1+(5ؠcAOʒ zcuJە@XibX\ftB)5obT^ӸIT\lJTYTTЉ]}_S.Ehjz)'e\z=~gvD|V[nil޵r_?`?xWnEVԀZ!%QUԉԎa\4 gY1㺡!,7\'@H ^1ggqKl)̙;}sدvCLPɲ㒢dvuMmR1ǨĈ϶hke~IWv: XgްP&e>r 碭:9SZ+gYN\`݉eiA_0(s',hu)J5iGF<#D.yGk2g3c`Z:w8t@\;AHo.lsGecqj@4j^rp5?рb)9.Kpm\v[WA O1th d])j}7nPGf+3f+ʯV{Zte 6p'1ǃEYpOjXfoFd֯j.Ωzr t5+fc}=5B /s<t5ƀzj-h4X̗ftskjA#* 67&Hj+f#=Wh?ؐQ^}4iAã?CJ}YV5ieZ i= pT햦+\lSXp45Wwơ:z.UБX^4l=ʏ5 F q;~B^G_c2)w]=C_A\$-ݢUn4mݵ/u x{wZҢb܂T9'>5a,"Cd/< &2nTL,*WJIR s@5LR`1[Ĝd$M̋E8!iE dd4XxTێ0}W [miJ< (M"KvWwvs .~S{Μ3gpgUBR g?MYv`Eٿes;[ZSuqޮl`}crsV_:BHh!7BbKaϹPgp9C* 8`û5@z&߿۝,Hl<Xs'!3VdV̪`8'gQ q  quдgVd+YldEI@3%99u^l* b?P^*` MJxUkOF_1=(+nĢ~dˉ~Dk{8mܹ̙sfȗR?s/Tl(26fT8޽_knFf:HTe+YDcS &0TyV*xl1TV]>P g)xe7kߠUA}2$06b(Dpz.~بMύL:hݫ,#pkz;X6s]r(UN_*IYZ5\'6nzNzf><Ï%FfKd}g9LfkJUw^p%kjZhj== ?7'c- UbqhCy Yd*l g[@2ǃs_Ma..Ow7ǩ} tsusqk,w! "ߧwU&žj$̫.KEOkatz/KW8px#tHpZҢb܂T$%k.}-.ΉG9'7g嬉lȨ99QHV2ssqj)&&*$d)$fglb2M`r&$^F̒x Z)I\^fBf SZV"bY&xjHq%lʊ sr5R4A&mbU7XU9''dvueY uP8]̲,8WBd~7+Bq'NLg[yI5諢D 2IWB?f38?sZ.fz[UխEK+0tϩTd^{':{6pmuJe"jeDtKwKT`,4 AAm%Qud`8d. a8GM)_ٷc#8b:heHtA2.PTKY*1n("$,{{a4{mSޖLeZ7IBҭYӆ'j \(HA`oT/֐L'[@۩iа^!S#BbQ~`q#xA=AC9FxSn0=㯘&&4٦G=T]U4=Ue`n#l,KRNü7oތ/e}paX^캺 hu,i]4U •0K0V.Dr)UOHI$[ {i"%O0SBȧ헯;~vOj.M 4#$Uk,x0 ҝ'2␔/ǽ5C<}KdHx)E5 t-sMLϐ;pތ' 7U`1/};\ #M i[!qBD@SNA‡1+dyH1N@ncU[8`^[wcR `H8~|;|AjK1aY fAE%9>P8(Lԭ=Ea&GqR1ra#YK뚹?#шI(Ln*fQ~ُhg_\QK|ս"ZFXZִ YN/.@͆U[Z 2ef,gݲ4'Wq>)9,'ſ⛟ ['mN?'# v}N#N+%HVJ-49nĞB8C%\ PztEЇ_{+8r|P ]ԓ˘6HrBlNjK8S}YjĈ ߑL>.%FԮjA(H#@D+So]t1\`vn2LPTwk 'F)8agB\0U8ٌx ( SN7&בj| X^8&; F|igfgEuoUOn}+WGʯ#'==tAu9zjBx}Sَ0}tQRuI#j4TTBP3َ؆NW /q}.ǽa③Rݜ;ZwT%#vy[K b4zu>7x4͕mJg\մh:hTe5Ƴ.&xr8шQ>9RPX~ !g>Ry_UT,>-p 59P*PjIQ*72Va a?=٦C#DmVàf*]2 PPg`d?)~voWU֔&%(:2?-+RFu5Jg2(#0RX$(Ǔ2&h r)Vp 0K ܊{e"Ra# HsJ3TB݈y-pZ8X 2nuszCc$cd΃"#ڠ|RG-M*_Z>UB4Y$_3YӇip=a87ѭO;usZr RY&JLR9!qQnoW~GX=HВW"I`ᴈIמʇx׃t0PӡCwL|=( FSd0ӫ&Wl8mH ۧMq K,C4G2'VV}ΜB89WT냩9YO/'so|ӁFU]G= Nf0{$b,8Jߔ{1^{l@6%9Dx̗͍5& <i{zhhj/x}Z}e 85bw 71Z1c UiV < p'KoSt.ɵ^ @3"wdF5#*H=li(VBٽb ݁ aPq,aXk~;hTp| _ܦ'4[q l.i5QAVmnd wGCcg1n}wQYojNKS-ZME^%cY55×ҙ(odA*~XNN (OA(;UI#-?>9'8U#-Ev/#d~65QNEE 2/sr=x}nbvBJfQjrI~QBjqB~JR3n3tF=N T Yޤ.0GQo:xBLfQw>Lz>O{~*e%Ce' JCvYBkqZK4 `ۯY63H_PN~vXh4@Q4*V~l/3*Ńt8϶;tOgMO;\lJ1ERFX)0n!Zu.֋ @$_3;i7ƒ~IӅ'Dh=ѧ?\\ao1}4‘qV$Hki֎ !&gn |gO 6ث|dL-Yt=q"hFbu8^ZP Dh j8V9=E{.D{ ,"`DU;,Y.* Bl |'0ƨR09B|}bޢ&d@"S X9/I3Bz)YR9V"*ob4j)^ K .}y0kHr5ܰL²/=+U%b˭h sM'Rl8ԉ#)l5YJ'JeRnOva0c \xYc&Ҥ,P_eO*C`.1/š{`=|t@ΠȽf;F<2|b?enE?]/woHc |ot֬⹻%η>AvsZE݌^-Ϙ==5'QH/|s8XNX^pκs^_֕*+k g_z;nw17":Sg 3ERb @(xNIAkQ цJIKCbXA\oEۉ+@Rh lD)ʳbf) EzӃ0ʷdQ͒,![ IT]nTZ.irYj=R֎Ԫmc$ vQt45۟m~84wnCx,OL U1wAg*bh8~bbߘFMhBuQ 3r/59붙xVmo8L~KijWn%څ.K+^Reؑ@1oZmgfyp LXH@O9X%3+]B댘0\jND"*\q[Щ+nr.E Csey n #` O`}g0)-L$LO)kA_@ JicY,TRa+{@*!z d-! ~ 1j.R 4&(~6,UBOuIܯp1Ng\}k%V[iSMh!Bu.xlR\;ey!q[aq0DnG~p]f\γUh<.cͲ'+ٮ91q)"-eIӯ)tG;wGΎ[k( DF oWL # tԛL?.4I1?1|l3xlu~ 2vmB:/۠O8cޫXΏD֎R&U?;T IHABٺNkǥ1\C -۟P҅F( (-7&z.>Y8gGA 6<4j7q1m=9*j *hWwޗz20[5.,"@\ǃzw' B=zDRNhla#4:(^۪sR_;뒰"d G;VH}i%FÛPR (૪O@gw[LS r){5Go7k@iD *D2g-^MR` k]ȓ7BJXz,Rs}_D0;WNoبRc!$A0#N6JNU[P>n󥖄 =W1ʌhwXV,wRF7$FKqzGI{Kw:>C %_ B3oGqLn }C+:@#|a=G_ }An -qZI$Q8oM`'dtt0Eoڑj vڸJ1\T[h#lvA\MFֵg]+".,;C%m_k9nzZ/q ~F &bܱw(I4<`d 8Z$kKI­#ë ծ-tv%&e#h|# ntզN뚭߯Qr &tU@a2 tOa8 {6Ax%Y&n j_8UE ǓK@ѥ(~0aGd[xg #qoͿ0G`;.{dzcc~>uXsg#-י)1TMlRx+5Gj +J 1fxuRMO@xٽF* 4Ę<'lZФlĿ?A{tܯϋRs4yo/jID3JDۋ!N.f<8^&<D.ͥuƹq-3Uap|呶PeBi)a4 L> sXܚ(]l^AY\U?'ӓ,$ 0GIK^v$I `0kALzhr`2\ !Bx8TYimtb=ci=22nxJL҃A9좡QW -՛F삎{t:W YBFl+&xL/JխLMKMMHMζrs󓲬UzZ\\\Xx\NuVӘVIkCx{cɜ,OVxiC HSWRI_ԟ3Y >kwxcCd]?x{wZSCsAx;$[pZSC9o xi HM[Y~B)OW*O`TҲ 6x] 6.GD rd9usJS7<顓q4Uʫ&ʳZ6100644 index.hJo$M4Ш&mxD 7?b8q݆]100644 index.h cL 29vg]R+yRxõkHRϛ4]t!TJcL 3ix{tiBix <ue].SO!ܸÓP vPHx{iBȴBNz\$-ʝ skYxkĿa;gx;8q=6sԴ̼Tx׈W?WԼJM(C.-'1X(\AM`mͶ6jgbIN-/lNJjqd#gQ jL|jEIj^Jj:Ku'б+H,ɈIK/+ňif=Q̼E]컘@NѴLS@64 UqYbebV楤¸%VF`vAbIF|Nj^zIАZbk..R TR(HLIKWH,Q[Y__]R )5$$?d";i@ xi Iן8}ڶ)h(3,UmfawO/QWطC"GxD 7 Q̓k}j(100644 index.he}#+r)Ǡ%ݸD\?xV[oEVJ ]zQRJ/Rbc;vb4miDc{]'M4oPUx'~7 gfήs}efw;/_ =wZY\YH]ު@'KL}G6u'sg׆؟o.iPuN؞ԞMHEn6zı [mx-! hk"A9;|)!`Ym{  s06~a@B^dy=Mdpx[Sft$iγKlr:X 8el2;7=¾.e AD*Ϩ3P=uϰPuQb=e I.Xt|gnC~:{Y`.l^n$qy[f-JBẼ ݑ}%6k[ajM7}Oߟesw5 j|5=(L-%䐶C\BΘ7 OZm=5&|[ !/0LbM~]ZF'IOTFήi&&iI&Il?`&q $r "J$vk(\ 9L3$ЍREz¦YoWGrmk$8߇de^]Q?PVt<1w2߽sF_^ 7q=1R)q'Un¯ SLt.cc5n$lzd; (ȆgU*v`.i,|O [znvDq _I%%o%V ^Y C]fM:DED~1DUq }'M'=>2P#M iG~[t>BǶ?LbthHeѫ ʯwx5|"u}Uqk8žO;ٌjNG|t@ggFq==Zf4;Ĕ|5=pW~zcɌ*0ſS?+ſys*^TjiޡddEľvHzNx! >p*d6uE>UWnkx#:Mt VY* x\O0[i!Q Dx! W(O۾ADɻFS>"FBax#Kp†70aa|o;uL xiC ê+݊38^[2 x340031QKI`XTdkgM]+溾L \x#OpBHn~RVjrI~f^Jj60aa|o;uLVx <cN"25w}IP &$ 3xS$q3 57I$'&gL~ ooPXTPRL-VTRpT+MJ-ROSH+)L-I0I Nﴤ-7yXIFBQ~~ t?Һ "rosp2+((L~a 7hݹG_,4xc7L7ofȮ 9~xiC HSWRI_ԟ3Y >)xi )7dV (G YTx! @mKFͲjTx{6bC$d~=55,; e7KTM*9YG^{, ,7DAer ?iEe/):o>i%Y'gm^oe#dxxi H& iR+uL`T LTx` :dHBdK(bi100644 filelock.hw9rfW @mKFͲD (x{.=Yj +Oy% řU% %9y% %E@gHwkD_5'TSAbIT5dC6+4 ̒Ԋb  )I PFt 6yl9ٺv`Ey9:`t-9SIbK`&ocCrPdvEPfȇm9$0 :gA\ S&+(OQd!$N8ws '3]\ FMNNƳPd,4y2T<nޫ7xi  L,zel)9Fկ 0?xD 7 cK44A_(100644 index.hCjRi9LO扳%&2x[1oCdEq~]wϐx_Lj=L98'_ݼÛq dK.\ ' l{=xɻtAͬuti&TjU($(xFĻE{FjZsMULS(յR 9Ȧ$d BIK/ɉ$$VV b-̠͌`MWbۜ2b%ڒRj{:(hZOvT)5Zf^JjҼ^QrhTOvҐ'`N]R̗I}fh) O YU,RJ36+cYrxu:100644 tree.hS*/F[=6A]c1ZkHx47i,hN _BFx"shG^FRSYB"9k x;ŵ}+m,Gs2xURPVXT2SV̌O,.KH,Ѵ޼IӵWU0#ɇis 'f H)QxmRJ0Qqa}8ڲ1/! :vmј6NJ >d.uI};''8Fe\ʩy)i\YcxiC RaW++9[{ݓ+v " wxV ȃ2;-8%E듿[[;z:jgP4~<]FNBq?[if&h8T-i"k~x˵!qr8^LZ'/e`WRɎ,ee2eeX&۱|賊D&N|Eur=+xi I֪.t1SGI P(I-.)fӚw΍g~۟V<|3hxw 8^şb100644 commit.hREpù[ZHEz3x(7)?1eXuf^ͳB.߆ҳd~%13ݟ4@%4%1/xR_kPu)M̶de6AX*J){(IRl~U؋m~ |o`n2<=sON{}zG?#w`:PIyxJkD eMvd7N=xQ񮰸"R>+<@'|Ҭ;R^T_"f(Ξ xx)|d7@5c'Bc&8q 3Q>Ť?͖:+oW.S7]Q  Y]Z-kqU&%-?1"d0'{ˤ:7b^UAgP zlSjx m}]æk&.:c?3^,J(Vo;^gS)KjKBOI jxi _-'(=sr" <x~ 8n0Âe@K+ CGkf'100644 commit.hP5rCyD+$ SIſ E%Ɏ+JKM?hc#+KޓF)J<y=7\x[:uBBN~bBIQjBf^IBr~nnfB~RVjrXao~<*x*{Bd,'3MˬVXT2Yʼnlr;2 -WSUX4Q^]ZV BA(M/QXAcY(+LKMQ(H,*NM2+< Ҽ̼Ԣ̼t ْԜJ b+#3kZkɅXgNgTQl-$w($g$)h%Mgf+)OȜ&;!lf zs?)+hi,M/QYsqNca,+LKMQ(H,*NM2T(NM̓K2JRRK2a%)9PǙB>!/x}{' sf^d^w9dT%xS;oA Ư6G&qL'[FtVEHɱa3hݕ4HtQPP/P× }+{nT /g?? g6Q0Z*ѵ[yeF_9s2TM驏$OK.iaLҘؕ1[հNekaFzs/2/L"͉je(TJ'\f1+JT0 נMP](XGmRK,cOqzso,ϋۢ{DH>20S*Y[oz-ݝ̬W;`;xM+ҒqR|e{_mʈ3$ak9`LqO%,IKc;3w*38{Jq{-U,1ٶrx.8Gӓ'ZOXB0̗;"E~*OGsLX4ЮNO(J5!fuMT~ ]:BV&oEP!f/ze^5nD)Qj3INjS|V1N%vq22߄{ x۠Nu>ĒdҤTĊĔ"[=3Sk..ɏYJ3RS2J8sSs *5Ԋt2St2St3R445E%Ey \\y'GqMQk6 MYAK"#}d454r3A*h+j*h;VsG#gHkPesk(x;}(L xi Bwo{9h3KBIjqI1ÆEmeM\ɳ'j xR |S%?1f屓W’.qB[TN,]õ:5L[r⓪'xXoEW&q\jv$'!v:R5MiJӖD+';[]w-me  bzCj蹪Pg9P$=!ݙG=8y>y_mї{ z+G E7@ ^YKgG*$~Qk &(ΝKilZяc裱iX6HDn8觱O),]\zo[B-+͊т LU3<) dL]7u C7h&Ӆ"xQ3 )x, *GG&DeW߼ kaDLVB*W7VɄ -, 9z8}梲~bM9~CDMv {0W,Oh@m8Fi)\0GAheZe&Z룄m5, wңx#-89t,ᖙ.,!Rh&@p1~f'z**qOWEK';p4ipq h*0Tj\'J2Vݨ֫jMuV6 j F_ELPmf$5*uG V :s^~gПѩm$l B _.1"X!ћ -a^j$36bL?ڸTlRY׬͚Knܰ|lVW~.Q4M3JĿт^%WH ܖ!dhDݍ\WDmk&aω)btY~E-?zGO?Q•<(C\qq1 kb*u(W%fAIuZS$;~7NKaH'^NŜ-aOvnv u# Z(Q)lۙ'.gYt}k8l.4:F(uPf. d$syA̅]dY]U;)Υ:F[3/b{!ӀϺMԤebKaqHYyx [edO 1~ȌL c;EJPO鷤ތ;R,%:m8IS^n?q.,vkLh9ޘ0ⲼJp)a%dworȅЫtYϚϳcFX?ȇ㐅 x+u#-YuzRE͚ڰg,jGT=&X@99@X=vc 3jMsӇq7=[8 I^(l=] ΌxVKo[EVq27v_ıqbשD!8H44I[%&Ir#׵ RJ btS! ]R3WP\!Xxn:O"&4=sv)?Y`@[Y-VKFJTk4d" x%hoO>?Df[wnGⅨGwrتxwnGx-Ün 55U[w`k\f^Yxqldz|-໶d;LqIMrO.a)h,^ 9ؓaZƉ&a[GzU}C{$&A j+uT?R/xUwo.I3^}Sa{*F;XF)X}g[+z9eԇa f KrgGā38nJ?x;x7Q? *f`yQ!P #5HD{>B?]8[k'vtx<_*h%&GQ_q{\"5S$5^D?r=G+#OlUF3cRqKӡ1 tE#t- ^#KVR^Jqx8݇jhF— oi-, /YXG;6 kVDMZD&mjԒDAmXg|yJd(zST-P۳ _6vwV#SA^xsoŢ7N_׋V'"S27lj$n-ؗ9RtS}+RjEpќMJvcH&1[J{1 ooxA]14--hn$d9͌-xra6u,X6'p*3j)xed&dV*$('e&(ho-5y43{RؑMrx;4ID!9?77D/A*|W!G&4q"Z7Qd5FigxUoH~Ũ} {(SI%d-޵$~3c5Uu13|߃>L}K)=R`*RʺR*M Ur 'WXR Nb\jY V.S,T$<*#BAl*czFx6  " Ѐl| "m3lR`teɯQԔIrڕTB99ҏl@b&9xofKq EimuccƦ"X=X<3 mPUCǡ؀(@h񸐑cHEEóAE >E8crtJ 8f)&&eܒ/2!˦gJ=eNMA Gr|VY;"2&Le^Oȭ|+ *+v̇?O׷dr/, 0dd zu")[׫UK'Tf[?-bHDLVqy1AX`lL_PyV.]=㮒EjƓ2G mڲ=,3h繨&o>~;:Z=_܈#Gux(tc$O< %.̼ҔTf~V~ͳ؎12*LNaϙ\ñtYLx}JA9"v2I "D Iawm5{;ޜA<=`%1r |??FcRj$4 Ksj,aa Oю [gv8b5(Ŭh{ɮ%Z4U;g?f }SC ew/fu#B]?O1ɧ_9d ^y٨+#m"9 QH=2!QJ!Od>qw9!A姌0ZN)N١5^J HnHtʶ[yʃBy5F4"5;|~ep.3ձ/ͼ9H.KP~N1#Ubxi H@~=A.(,g>9Q׳ KxuSru3 YpawÊ?zijPxHuɭ/zaJZ6C3dKk_6I]?*`a`ST5 e7+1vU|p'n5-o&}c/tstNA ^wMfyrLFW8Ti#)/J-OJM9ûyɘ^詒`ux BYybN6Цi7m|qdm')`~众j5ϊ35kwM U M/6Dz"zzy:lr_Zɉ,!8NY(SSb$҉/o'ǰ*XBxx;ySru3 8[/|GՂGfmT]x^|:xd %40000 block-sha1(oZxHrYԲn)%6l)r:W8low^KLO*6ʜ5j Y  s)lxsg;f>'&vqxSP^ ~.| sCAd4GZ3z4TSi<740000 testsDz|'IEa>O$nxx;~B}tfF3 +x [Pq2%{JEДo7k*xó d6 ?x}c̦Z;}fЈ mx}j%l\lɳuC^|Mx"_dC(Dv2 ){8nɲv ^Bx <.ۉ|ѿŠ4hOP po;x;sHyдNi%YiOx340031Q(H4Kfx0K_~`ymg Td0^ˢz?D~{x;i3ͯ7g*8yKL~ lx;̺uC>F'ftN,pw$j{ep&d#x\)iy p5)%{$ny9`.(bxºulcsH'gRNv<å0ُIarYLRn73xi HГL^Q*>T ڟ19Qݵ >mxRJ1xZ칶 (/ZD5uk"lED3n%afޛ^O{6۫XgEdyph,chS0"fX\Ewk@ $*IM]nbTRv.D +7e!z2я0ȂG̑jX{2EZp\N׍s+PbyajFoUĆ7c1q:mZ49I>T8wNH&%p ,x$d}*5!>[eWSo1[N9󼈵c2bT@ qNAګObCo.v&s~C!txk,g,͓sYO`˛\Ŗ5[UcsHB5'cYi $EtD<$,άJ/Q6Ck-6H!'xSLKIMSs uq/H4ψRfbJp)g)@$S4= 52sJSR A2Ss`h/H+.i˰*NE62)'?9[d(y)i\PZA_ é Z\~EA[xi ȁ:)<0 X-FҖ x340031Q(H4Kfbc$7^95C$ j|huϳ<lcxks.11!C x|H Ѕt7dh#.x-'&3 o src/*/*.o0 jxi jNU<[~| P(I-.)f0vz0k_MB|\w.*ax;ys+FWY/~S|k? ͒0tx[);OvInjnrAF~iBqIBgHKkDp=jr=|ax96&tJEkn8ߏ";JgH:Y:Ӑ^cPxkhrf^rNiJMqIJNfF,E/1nbd\0"l&!Fx[i4hF%̙y%3nb<9483=/5E!9#Hs2'%F͏YDxi [)gx+o%&o#% P(I-.)fϺg;e{D~xR aȔF(]nc᱓{lln'n6GY7^8*mǐhZ䱍1n ,&ax9  6mok9S;pQ04:c} e;^jjGx9 ρF:RmNʧIђa҄;mD3nz^jDxra6u,X6'pT@o0x[Zudm6Al1<6uxQqC J]&}+ u8bـ1қ@ sxb=CDP{ c0UPm-100644 t0403-lists.czBZM%X|a<uZOuK*y2l~Ѐm )qxJ=v=]|FXd|Mq100644 t0403-lists.cqATU'>U1 s=-LjxX{M}܂J.%%.. W(JKUHO,JJLOVX_!(?;5O!5/%'3/XpYo0$de702-**-(IMlylrHNPeU>y/+'6c )0+`aԟ¦ ųD$#X $_ ؞K_ z<6Fr@:e$gBQi,J+&!m-:x$^n7cxµ!qr8^L \ @0ّq,,f;oF Irx#JhC9Z&# m8y+6LOVe&cLj&eQݼ ucxi ɭw,-wBC P(I-.)fTɾRSw%yx Ixi ~5Nx@ɹc-x;ysȩ'%.l6e񮼪qYMlxra6u,1&^6+x[P{-ɷ/9h5 Yx <|yn 0OP lx[:Muh&Wxi ?٘(so7oԯKex;ysH'?I.5ӚM}ss# x[We.jQjIiQFi^qfz^jBf^ff]f5W-䍬›XOpm`c F%xi ɋm _d&Z-)JRKT;/^>3g^gL6Ix < s:˹cd3%'P q.xiC ȝGY6bF=j/x J@%\; ؘ!)Gݓx!Oֱ2bxxs|}/=,glmx͵i S.3kxi H2{krkcU߹:9Q5 o x;|yC>#sf^bH.^l2xi H=mWnUΝ;9Q Px;ys9Jg|Ӻ992UxrNe>ĒY6bQc.ٝ]./<8*UAK!7"*%>-1$Țkf>|fe/fxi /!C6q?x,~,Mmrγ Hx;ysȔmqq,9֊;gyʤiss# 4x;GekYC97s;3Axۣ[e VĤTM46`uy $:xi Iz2wocq[qj~O~BIjqI1̶[_NTjոju_7;ZIxi +۪ |2zm<>X339Q) p,xiC HjBK'z&Kzo8(xi H@Wrz+=R>9Q܌ )x;ysBŽv*5ܳKKl:Br~nnf^C+igf hTH|vcF=F^n{,]Md}p(.4/XyLPcRRA&_}.q֒K78#'d%3li2˟gf?DS 9#U!:lUL>_`x;yss±T?\8mś}g+640031Q(J-OJM.`iأwOZM.e9z Go=ZyW110e-ux;ysB/B_=4El~_+@wBr~nnf^Ë GtF=إ™bjyPL* ?_ݜ6P|%j|'\' Exd 8F#O ID 100644 commit.hv)s"W<ᱷ3~RԫLH9jԠ6\U100644 revwalk.h)ςAL{dмؓSI*xR R3B@l1sZu/;i^Kl06o+s^8*mǐhZ䱍1n ]'6~xm 2,7Kev xi H=C7ˉґHT8k=9Q h]x;ys~Ko/ynss#˿ ~xm 2,7}ga1&R-85&fMt]N?=$>?)+>9'8UC-9?7"iYZRZ`dOͩǤkkrd#͉"[y}:,5xۭFe&]+9o8\Axx_qs\ 6 \E%Ey !N^AA!.s8jX2e5 ixi )JN"mN}Ny?9Qӯ xi Hmo(7/7tr ^xUk[UgbӞ$Ms6fI]ՎRSA&~HN6d洽%ɽKnT*{n{r}0}EWpo~Ͻ!>~?g:}oODۢG7FC3iB;L^!^?BcWOA=P&JhOHV1K 3u,#[-,oe1v2J5oR)+Z LՉ.ZƗHMN;gQI}R< ]9H3~hoJT*_/Fpf\bD:[߮R R`]`v֬BXPtj C:!zk4!%dnmt8WuXcrEx3l%`Z\ ]mAgܔwgY[;T~Yst~DnѴ.0阥Qk'qo @%>@7~c@ [ʜWog!.j]C*WfikѣS0p&7fb!SoZf,fa7"(ضK9BR˳a[Z1n~rY~%٣ߋl/Gx64ƢΣB/~LN\9THw / SH2,ܙm1L3x&Ht,;KY~ffvFKq5NF} /xK~+;KY~fd;&q1)hLȥȯ``YZRZ79dN}NkZ..9\\959'ksB沜GpB.'df Tl>#,@#8)Nܜ)4rx9  fVvSո_n|0[0ru#5#FBc7KxI=[ T7}(|af?100644 t0403-lists.cL_y۾nKS Z Xx[ž}C9g_<Cg<++ͪy #K -x Oֱ2bxxs|}/ cV x <+sZ37דP kx9 Akm+L=1b]GL|0[0ru#5#FB)xk,YӊJ&q&xi E'^yj ם } 4x9 S^@nwM Vm&|0[0ru#5#FB<Axs'XUYR+J6Xɱb4#kZQ~^fymP*4x .>"㱓5)fx[}C=%x[4Ii*ɏ'e瘼K~ 'rlbxi ɹywOvr6n8fT )&@PZ\RΜgs+)sxE9:&Ix <"5<8P N"x[}C=װ`O_ɎғXJ%١r1n^WkKxSi 3W-o,x;˵sjvԼ4.-,ox;Bn["4ld98^2韛(3H]~@׳7wyt!\Ix <`{X6OoHpP )kx[ȾaLOf xi A.KIMRMaFo,4 nSx;ysBR)'9l춟2`r040031QH,`hq -e]޷{yLܺq1#w|=.x&V2y>5假u,  c$jlQjY~RVj2侅U:Q? [l+BYybN^2"ݕ;GS.SK߳nXf?_ _x;ysBx{ﮛΊ+w_lnqvzk&!ʿ V/y{BQjY~RVjr^C߱iKrJg-d{_3BYybN^2&/z-y;i&C4E "s?r^Zkҩ,_j?Hxxcd"BMBA~~]J"x6rmdgm[[x˵!K95/%3 ,xi [B^4nlsz39Q x`hCK\o&o,#amxEqC>BFi^qfz^jBf^ff|V#n Ox>}dfN..Լ4.2>x[)UjɿYM~PzF6 D&HL~qŬ(?ؚKl[];0O/#51,[\%5#]r~nnf&D1qPԊddo޵ y%'siM⚼KR (5Rʇ`3$d[kUi yy%E%y QRo6x|iBć"\Z%E%Erj%f8ZE@&g祦('dg[$ ?'?=391'8Кv.F+$jx;ƴi"̒ԢĒ"k. H,OR9% +.x <sP{Wh5𺮇P 6N x;cBE[ȋWr{“($fe0,8սaVǠe[nn(e+jmo޽sd'ܦ*|e0c5cZ #{~fBfdF&EޢԲ-YɖK95/%3 yl>x*NjCrl&rx <j Rji#P e&x`4W{ VkX󬹸 9?77D.-'1XV3$Hyxqgd*h$k*TuTH׎1 ،x!j蒓,8f[zfI<Ģx73SJ&o: fN>(&̮Q* fO`&s)N%W2+3MA,`k RKJ(քTr֘*R+@ C!`258̰#r * S#%P=d/y !kf x;u}BrrJjZf^gH/ vuS CM.,<<]\bUPd91Qdr# Z%e%@bZy%&>|1Qk`&;f1JdhgCtd(hM^"">D]xT/@dH MC^ ]]V6wr NGEC}{߼ޛ^]'%qMߒ:\)pЋa<5eGk'?zcjpAPkYxsI1!'SU*TZn97Yf6li U#Љ nswq#N$O[VlCԈ'Dj5M1hmuuIʈ1X}<UnJls_{G~ y[*k!?N-L@6;i?x;ƴi¡dLxi ƽ3u{fn OSxD$100644 commit.h'7d*jJDiJh $N~`V3hLViLxi H$y\-5J x;cB/ ʢ2ezucEmBk540031QH,`.H>J/~ok*w6nbr(OKf?_ӄS`mӴs}{h|QZV`߸աuA qQgשN>-5 Xx=C{'d/VsXC@_ D)h)yFZ)&e+&gT*d*$0M! @1l===j}.̜T 1FNnW+ѵK,)Q047s?cKkr0sB\>knx;>}?d6^x[#3MdSVɷ9'sLƦ89#tr5BBq~QXqBNfqBRbqjB~BybNB~QJjQf^:Fni֢ɂ|b:ꁆx%deegp)AfFA~~]&XA~_&XL@zfIQA|Qjqj X5\(( "XR+Jl &{pKOn*O>gO0xi )il6.^򶪓җ59Qș  x;cBE!K;ʺSN}׾D?JC3 ˾yc,UJXx;|vcFc1lYϘgnNzS(̹dκ#;FWY/~S|k? ɒ9z j?G:%OV=jmQjXQޗ7,T_u斖}3.MFx!ѭdMmu2;d|.0x]8A"@#0y100644 commit.hۚOO0{ 49Ԗ3rV۬z4Yhۿ|+kxC8پ??--%Y!j100644 commit.hM;_Z!9=ӐtQxcBEKSt˃3!'sfMch``fbYP骣kYg存_qD&i]ܟrqtӬݓPEe9@oV{WzsueJ&72d 9sxݤa;d.*iLeSťZ !.V  i % % 9E) ɉ@) y y΢Բhq PB~BN~bJf^PwZQ~.ش$}.0h ͺv)I: 'Ot|Kkwp Ʌ+Oϩ0;*7nb̧y-k61gJk0x;m? ixD$100644 commit.hY۫cыaop֍ŗw$N~`V3hL8hxscC U~viBBr~nnfBZQ~.WZYPPXTT2y5Y3Mvg< sx&/adgɇl<#|]@@K!4 85E!9?77D!?)+5^!<#(U!%_$#8$Vk钯P [ R W34!MeYONgfKNamv8migx;ƴi6x0]]3@0xkR&u? !.V  % y % y%`Բg!x;e“Ōno03rp)dq{l'x-\lXN(Qx{.s< %.̼ҔT%Xf H+9?D!=$>?3EA Āgh x Zɚ\\E%Ey jɺv)\\5#q _xƽaK}QjYybN^WzfI<_''k$SR48Q+*s!3R4R\i `'gQjIiQ_u8'H\hBJP1T$lUUqNZQj`7<&jtJjxrqBrf^rNiJMqIJNf^dFɯU i/x;θqB:Okaxi ɦ D+=#JRK9rVrU|=]Eaf;g<Hxi b>5iO{Dޭͳ?+<9Q Nl>x&M~nͿYs)PTx~mBHKٛ%L>"MtvɢO#gxeC9 ZOxi H&tP mkuor Fx&?]~nͿY/21rN9?G+#2y8\` "^Y Ǘw/gQjIiQ5W-ԝkx;~eAj.̒k.]byřy) Eũ)V:\3J0rp)dq@ xm1 0_hWЈ:JKMI'boRl xٴCK2(s.!(%D?`b6a..5A4j.fLf ]bix|ʁ7~Abx;xq:qNb+#3kZk..Լ4.k xD$100644 commit.h%r=-]S:$N~`V3hLNu)xi ɜWfUMyIbf;,M @$-g(W5ZfnvsKx340031QH,``Wz- '[m4D~;X@դs{Dwg3cP5)I@;Rb4w[^>XLAf P?BKX$h]+t޳u2TAQjYybN6PQu x ҒTDE>ϽěR;7*r2A.:}IC6Fi 7ϖhrxS#oIЄ'.|4sV>rIϏjG40000 tests"g]Ac;"K㡘V%%xuJ@IQt#^ji)խZ[,Vک 3efߢ] .ĭ/qέ/ 'M͙9w-?ʡ݆B&,A@k@h:7peb.'2BtqA-Pȭ8 zJ\nc4P׀IP% *b&㈊pHA1ySGiW?cZKOS[ jΨVJ EDcNYfma')X~`kVR4ECj=υ<ވE1z3K˰^2)%"ՌO+P?%_D x֣:os4 #kDHc{9LL *`'X4y`x'XbSR= 8!A ڶ Ez0INtI  R7858I9ٺ 3L&;Y=Ry'0jmVee ެk=~G,xQ}!EK_n!첓'Kl¾ .x{YeH?L3CGexz%40000 block-sha1:>d"FlIo %xKup;D; 1fлOJ{7X>e<M5*^ 3 x340031Q(H4Kfbc$7^95C$ ;R'YwM=3^0ˆqx340031Q(H4Kfx%v-.̫%ŗy7?"`8+ef͸T Y/A\ݷ.93f m.x ' xSLKIMSs uq/H4ψRfbJp)gt8{8r)+d%甦*($e(q)"K&'g낤dqAi}- up1lxvmHVI#KgM\vsׅA {0x"OdC(D8Z.lx'!e icxi ;eVX){nBk .xB5W{Z[qf"100644 odb.h/ [ BPzێ2Fpg0YTdz\}?ige\p0{zy<\;'8d楗#RLfl|;G0eH(i5Ϲ.Mql$[W8NsEH 298mUM+` 2S&HhD~r8׽S/0\AA2mi2vZZI0'dTI<)9;ƗAh2k?~=$(51E$3",zΠ$#I'E ;kt5i{  +ˬ``XTaobOfJN/)2hUR_r|s]#`p*X#TQ,{I_C(36b8ZyJ{C +d8dyxk5\u.[ˠ@BRqڎIZ_3ZR$Z@^ˇ[Z4SSN 3|v40000 tests@pW|/BʺL1ϵxO,LO./)J,KHLJ,1+HD.^zrJ"Se\ixvImC:fFLzUx'x^uBhFF׈ xg7GsxT4 N^o0֧)8{8rqB$m 3 Q@Z/h| 0t¬N)NbRN~rYlrlP6^07_AMc #xM8 cFdaKV<100644 common.h:k?`'aS2SI\[]R}5樂[40000 gitA>ZR(FD٭ lodb.c,-| }kqo?ThjI*)[XbÓZ @Il?x['Vff]fFn5bx340031QH,`>sj׭]&?ԢbyNvw(nQlq &?% bQJ̔\n 2)L*|Ao!{[]YmH*(J-+O*zʩ8>kWJ'f^trҒTDE>ϽěR;7*r2A.:}IC6Fi 72CmjJx(tKhm< %.̼ҔTf~\f5_n;x%tc$" l-w& xQJ@k}"(ت$z)T'!lmfCvS->94b,ܝ#J‹v)y{ȳ Qg%$/y1AkO&{zÑ*! ۶sN?vZ^`>9?~@T%tVrftn7`.w  $Gt UFZ7vJ &,xC<"gاxHIS7̞u[iAB)S#`@Eo̢ ̂miIoڭ,!c&p"2 e|/yYndx[#FnFFwy*oyx١!)3os2;*- x|a ;BzfI|QjYA|bIIe'/س9s)f.SɎ xlgDR OI 59F`w stss3'_|E&^29ADf7x{VjCf~`{ӹ3KSR6 J.xSMo1UCpʥTKq)H/5l֪^ަ{+~?'iZ{ޛ7oӴaF)_fa.v€C|pjZ* l[**#AƒNѠV)&{t^YG %W%LﳠJ-u `R!%Wy=(&FT!Lc2Z*'F%&a=IPCT5U&0W!K`ẻ/g77l&5Fۊi%\NQ[EM-{#vɅfcLAZekvpKLBFQnVSw9b"T8t|;or4`lVb54US~?d\:%{'grit#tTz.GxK.E#*9aBM1Azǃh-~xېCu޸߹,1: 'ZB.(S0HYE55 m)1hq2f]+qѼ42^Bs8uv{y |Х0w7*#t_eԱu1.Qsx[j yٶrznS&ՕD؝^|mj٪Z#x/>Y|]YDS23sJSR6Nd" , /x,>A|C;W~~BzfI,N UVαW(QPZ"~%H<#3%M\u/Ν TsMU9iex w$lk8x;sg*d56eGgexvmG!k/iYMrvm5]?}у]&0Zۋbڻ2C5t'"gh``fbPb`h`URYmsx$̂iUW9O<]5MN-AN׺O.T1c9/Ts>{wm@1%9E@34dj, ׬HhT&)1KmS̚/']a[89Iz ?w/˙Bcu~ P}lx"Gd?b&[x[ihF%̙y%3nb<9483=/5E!9#Hs3'(rvx["4ChB䇌v,:J8}}=C4u&s1*|Jr|kGw`]㘸'g1O1bhfhdl9y;+j-x;̱cƨNgxWjF%lZ؁] qشl'^HY;SvP7aҀ*{F6ƕMЇ},PhoC:#empjA{Νs^ɯ_i凲r!°hZ}Li::\)ht.|6GaB#;G XH?`u' wj}~v+@KCx*TȐE=a|4BAIJFcy_Dy]be h=-)b2|sCƥ.1j@6,23aY nbƝћ@ ];ȄToMd]XƏ2jcTI3Dnv I1Jjhf"7eaWa#vRf0Q5@Y{߷ m Qg*ωT :2ҳItE1eXkCXSތ:laӶ?eQ"˰3HN[I}GX]L+u g[lF~8hd t񤏹.s0Oܑ#}NrT9 }LqkP"ndQ/ޤurEG3Wr{g3ZmDm?%6A=>$)eڃHCk{&P?RIrȟ{'<'g6+3ڕCJĪvQ듣czVFE."g35|% -WCԨT,l P'9Y=H6 d= ,$jDW3[֢۞ZM6GG$Ţc)lBxuVfF;xQK0_|id]7yn0t2A|PHi56H>_sYک/ ؞Ϸ4*.ej<< ǣ蒐B%S T!S/F9D+H,) Zj,* +'lu+HqO5 eP`}S[ \n7YsXPд!Z1T٩UMg ~x_&SܐkǪnnr\׌^7˝ר<MIЇ8iv:q+qA ./x340031Q(H4Kfhz)dEW3UyQe"t }{Wݟ@!jcAxWmsH_sIF K*vL_(I h.B1o^wCMLOw;wG O0>qr'Dõ.|p1CWA?< `n*5; 2*w0`,p8,ES/U.CbMX^.\\zxud0dI"N"1Y$܅E \WX1wab[0hԽн n, ac8"kAr cKWN!#q'"}$f֋.b. iT[4/] vv`ÈOy H>ք!t}5@$ݝ'/Vpѐ-|C:!~ 9XCL3|*Yc͔9^A`ۍ6ntka>َ4t$iF}Uh{zJOO~@0rBD 'ίK1G8=|2YY w[i[}^RriHz!rr_HS1Kr v]J4m.X}d'fjEx _R!B⒇,V"@uԚ eRuOQU XEkr P!٣L#9WHZb7cگp#B CEhQQS)'#K\YRɑt@ OB!&ixğH/z4<2{س"A|?t[#m4βɱ׮qHI6GK4W|<ta W G9bD!9\\88]3G+`}Iүq;4!T 6ʬMG 6 Y + BL _H'tP6꣚mT5u}茂hsɪQgy pSE옾oQr_,!ܸ%F.5N,u\6i$u-i&u|Mr%v8>iI9rܞ|(2C@;hѿQ=|:;އئEr6,8 3Ɏ"ךxKj) 1q*I"6RҡㄸӾW dPщT F):< #dJL0*ʄCN1f(YX ^gLJ9Ĕxjkae۟/xAoP\nH>kr3RRAn״Y~n=KڋX&^UMz*Gz%^^Էra=ԏM؃z`J-m,6 G6!r,Xn̲,O1,e>sԨKgUBƵR]xHB|Qs9UPIl6B]>% QNQ,3c~,U_$tkXzDS|#v-׆a|410ӄ>1R~@G^oRtҵzV:έanv ऍyD5YԙKw*}ff[2E+lu/88Rc9Zf҄FiDjP!_̽,+軲}a'v[3>먘kgQ쨄[U~u+OXT& 53rL=J]P%J`U *ts7쟜q gc0m_z3.GMSGfoK\|j9g:XADTv % eN.+ɜfRWt *7A.]HiM;Q)<oE _?ّN`n23g?)8A_4 wro`m%2?=FpݢKPGaɌrNv16qmbjhqي`:zi"Rf]ә.qMd p Lm@l~?682R#b[,R[!#X)* Ț,'LBs%r)7V0q=w"Tv"riu۷ILKahQ]|5'@6HBoO//)(O,2_}n{gWXg;oz޻DNxDm,fo^v6 xP|E'6ƂMTF+ӆm 3iџVBJ!ғP 5$xaH!<6 ly<ԊݴN1QYC*˥ۤ?y 7J40000 sha1XpDIQ|»N(/PBq("kxx[>}CBfVfxi k0gbfoGcvr; g4x1cC5HaŇ=+\kE[yݙ ox.1;CxSHFQCDPxS"|xi ȶ ,x2Ud摓J Mx1cC5H2+p>pOG2nQһLM ix{ sXJ3J6gm2'1%m` Z0f4ע973es939ri嗖(*kYY;A"_7asaZ*qirqVf`VN.1y8n捽 Qox <:UAm>@YRx;Ly;$&6/f6fݛY7_a9}F  xvmHGoݚq⋪T$׍^|x#CpB5'1mnc4ٞ5Y7_afV F6 CŁk!d] 3 wDUfxi ějV+T#7+6ab %% kj|\gM(qYFƿGOxJ'100644 cc-compat.hfђwi0SDu0']Ŋ z Y&O#ʳ&5 l+xȽ!ycfM&8x[+VzC>䙌E$y8SrGxvmGCJr+GjH>oo 8 llxV!wD_"Zx<<4a\VyO3|u40000 tests ѭۆv]*$xQ{Y.ϲrn!#a>ѻ7b.5 'ƱٕjRbqj|Nj-LZJjNIOKќEL((G},7Y^/9&x93OTtlo#Y(}5;Grm!M^Gcj]x[i4hFWPxxi I" -i)+T٥gb %% o.ݾ)C<獵/vL{jcvxc'100644 cc-compat.hHCpmW)']$#%7چb{1F \ޓddy(r&2Z0z<)lWxya?̚L"dx[+s_zb O#sRtK3R5'Og bOI7 1IkJx/}Rz‡l7y!/xiƨQD_dTr1x 0t=vrD.xV>W$$UG!9#HA $Czs?f 0x7G3i߲Gё^m ̊Vq jdNVP GSkxkgy˼a%Ì.qDx! aGaĕMVm)ˣEaDx340031QH,`>sj׭]&? _!Af[?Oi﮹~ &(Ƽ'|%ӷpWwG@դeּi}Q|BS ;@-.xsL Ӹ7=yT{ԲĜlʏsSvtRiI-܁**(JML--9HETK);ߚ/x3X *'"7۷O>dcV͡| x]4p࣒zh7d(H+;odb.hX2d\ .QR0100644 oid.hր.$% iq㽅Ecq(K|xJ@%Z66QID5 $rֻºvN+//qs1S7r[M:_st9S ?Й&88< $.`U{eR~"):N#jAjʲ@B6el< Hr2N)c 3J$Jyp g>!-'pfJIeURReŶ|͂\mIaLpZ[ݼwdGx*xi fdJ?K)T,9Y8sr/ zxkHwՃqr?J*dC 6}1O1<.`>-`egI|ـ̫q_~ z4+cWkB|B2n"x̔7ٓ vx;n Ly˴CGY 4x';UvSN̼ͯ8W13;A\ur& nuxwoC"c\,+YeKxi f^ՙ.oh"dH8 !xǾ}HnJ~5yKZҿن; &xi t/bWO :L`TQ |x:_ޡgC#IF`MqwsmdjMK:;HH<)l,xkTAk. ]x3ѷ՟BI:JD @pOt J n/<]x{|[yCdG[xX;oxvmH) Lb6WN >WmF/>f Fx!(q$FG>39X(x <3*kCb\P 8x5b yh=8nڋG3`Ѣ^E^ox{zyBɩjxYsqV)9 ZUS2RJRSl 5LaY~fBQjyf6LT$ɇ(x340031QH,KfXbvVϵ[.ݨw -3'5sɱ]gH(7oN׊ g :k R'vx3Q?gd]FIkR2RJRSlzΌ\Ey~+#grN~q*;k;3xi Y''ۈo1YsrA  xr5S@.yʹ|y19]蜽 C 6100644 fileops.hF)EnpX೘f7!F/>f bx!)q$FG>34 zxl;ɄhvcQ";_100644 api.doxygenG3i߲GёE'6ƂMTF+ӆm 34pU{UfUgjKEz40000 testsiM/ ~hlǸA+xa'100644 cc-compat.hVI_^*!{"x[+JfW}--T3̪T<`=-}.Դ̼Tx7Ox7`אx'ϐ`Ɖ뜸+KK2&>132r@2Jl"drM1O>ΨĞ TYI@-x[%LfC#gHFf^nF/t]x{a xvmuM8g>7!D/s+Nk4wV<Ɗmyy/lb!(EO^_0#RKs22O9pk sNV oxV$S`S\Xaǵ/;gQjIiQ֬"%%: E Z%\Փy= YxtKi fYz+xO1>k9xZ[\GV(lp͂]{{#qb#(Υ$sY?!v$GyoOgϼRYL=3c= iyiJsMKGTMaL$4<W%-̈gD}IH4'Ɲ64ԔE5JF sR&s荜>kZէUrDuV!*)](V{ -I\QzNAY~L5R=)x[z;#)Zh%*'wg\FUCZMBG7$(#KR 4l9L܈AJN+E.Y ɞ~q:Z6,򘭫фEظ&e_y/~̖ d-T,",鼘(V#*Ӄ77v_3Z)-)7tֈINSUaBcuΚ'(|K W~ 8g?ۨ(+*.0ir+ $*Bǫy ^)oZqb FzX}X5Odlɓ;7+xd'2kƮPi2x/S$%J}JZ<9c5xJFrPPD7QZaǽg/\|Bt#%ޢ4,|(HHCPy;,VMR|6'( pEʠ:KW 9=ahjD撃!ўq]ُz챦}b֓" FĴ 1v K*x(5oE#G@ %*?gH1*,"U41M@LEWLHHךѐ]SD.O~#I:8 htgrEN'8O14Ѥ a4XC?z.?4{Om8d>…<&N8Bf%AtqhICE$)/=;Iq䋈lqUQ;X%OCKhŶĎF >8K-Bϥ!yjX_l!BQ9T90[dNbmWSP֨{$x/߅;E *#TVnfFA#@*Zzw뉣ߐtS:Җ pNX (w\AfP> ڙdXCGI*GpDʡVpӫ{^ ONP,:Nz7o(2- ۺShu|a&TD٦$wQ8Vt x/TgXhJq31{rNCh>"čT쿏fPYBtT}Q~|J-޺nP6ځa8f6GPc&Єř>qRڹJu >|{ХQ^?h7ʳ 闙M\lM+h8Qqw޽;ypMK nbp&Dkg,j1[X'i@7rA_]'/]o7ل߼K 5>xYW=\&,u˅B?K 8/~~sVCH 1]h='Y8#J G1A/Uy -v /8 `:rv~Dˁ _:p/=]*磇Z JdQ|g#ݷnDNx˪UI@  A1ݫoPqH:1r}% qıswWjQ2h^믿V|}W~ǧO>w;r={|pɜN, HFw\d\94g\,ذ) GFRoE^.R|/bqe=y/Kd1 YT6(a1!,co0TV{ ѦEl"zߪΑSʊl;"[eR%ż8}C[tu|kqβʀO3j,/p`x/ 2-jr` Cdb([4/HFGq9x9(Hkڰ=p!!d(LkD*!)Rb,)Wx, ʐ~D' ۈ! P\ E 3 ]RZE*uQ##&r*Mt3s^=p%#6wxՓk_W:[,2A]*-RY)1svG1x?z- ōQɟ2'!B}mNJ=\+mDzq& E=(3ʣO^L os=Bhy<k? YB9sB$ [[ {;Qi"t C[}>!'m }D-wؘ=qh.3,$7 "4_RpڷALWLYwm)RNJqZȕ' MIfVAZu$HI|1_B7Q_HFҘ/F}Ye$K&͎b q1is oP]l4\ FH[n`蒏2{0,UR%I`apQTTĹ!ZY+({3=O^ORze gzZpKZMU'w:H礭U=7H9* jg$AwՉ-Ȏ7(Dו=D(ixM:*2Eʨji*yz9Raj.'y\%B J:*L6` w59+2\%8p:d~1nP ,گԵw[O26J!iZ5AZA5@LᆧGc*ZK2Jpn%g0zZ( t4tn= 1_ر]<(oAo6EP]YC|OSj=!ݘiCL/b֧@m?yx~9ܺQߩsvTI?_+SfcHV[5X9c UkSM'l6Z'bLzOZK*ة LOa R#`\Re/)3٥n?.ԫ9|Vٛ@ev+(D tk1([JvKȬ54RգՙVOk٬A_(G98FNX]$2N/S/'jr2YvRfej^WroEax+uFrl'XD3Kss6s s Bgxi If7{OIf-b δX BIjqI1[Gze=n sj x:{nU;:~+hxk {q#Dó~@.|cx<4p࣒zh7d(H+odb.hX2d\ .QR0x⳯xV]o6}EbntۓۢR'` J,T\߹8׾ _srvҡZQ IR3+ԘT9oU\{y:=3J 8u*-\tdj+qVN^Z}!UlrRKg. S8OI#&TȮuj l"jhe]BʣPSHLY#{:5a+jvQ>'gK5k+J")>8}~e;h)Ci5|K9%.pRCku%(]@1Tu=8R6> @2g^Ĩm#>ڜQEAq">c|o Mh6Mw=^*Dо0e.w2.t2͌Ft;-z4f>s)w2 ǻ- TJ/Tv+Rie"!4U5?@la 䶵Z7w %GOXf7&7}BBGiaK!ea :gg#ib Z1P7,T$. mS}La~ *.&P -R #c .ֽSJ2?~Η/ъ >Dک5S ?_v  (h6;0;mQmQ'51W89yzHeucm-f&/9ƀ0&m7 G6hzmV&n|9ܫE&dz.;.ӽ&,&iz;W'u*jCNp{јJ6Io39%m! UaM>`tҽGCp> :O`cQL oT}r_ia|}B oA!RÛ&vsp1?C|</f1Ktu߀?41R(+=fW>̀@+šu|C>)7*@6!'ђ?BR`sVf?J]#n@h419S6-eT{bLfCCyd~Y8ڨ 0{׹HYrF%RڤI}Th uV Yѓ ldi O 9?W7#SI/ qDȬ as8t2"-iB3SC?y,3gnJjtF,)p%$fv/Βgbx*{]jC8/ .%xvm?yq? %9+#W xgNx[itX}aa L_xK5fwaw&)^V}0H2VFIZ߮n݊;@1b9"5Y*~gGBF=o$^ǰxO,LO./)J,KHLJ,1+HD. {^lZxTj^/2%x5fxvmHJr~?W\gb`@F/>f5x8ʿir S)SffjMlgzxiC Ⱥֹņ kdnPQ8MQ5}5KK>.IӅhͲʲ1]{˹,?Q͆\4+amZg(~}XC]^Xj%֚Z\("k!S x h+7 ߬npślHr,4Et:n#1Yq}Er!Fe^a_8h}Y*>|$' ?4|خ&+;8n>N{~ybm7ÝhAޣ S_liz6<g9߰HI rՃ٧{ `bD= &E>Fͩk"9sey:"!8zJ ݯ[2S]=x-?]r,*eVpmNgg|Eq[N}QBbAfJ~r1gQnVBqQ>J,13 alQ0vyf頢PZ\R DyEy%)E%E 9y\\%@U`'gs5u tĪVfQ{*!!N^ Pk+꧉Q،UTp  8 4r23'f1A3 lxmHS-rKwt|T,4q &%jx;gBƻ]>mef\n ~= eSxi ȣ*I1YgnNCbr/ #xǾ}Bȕe*J捓h~xk5fwaw&)^V}0H2VFIZ9հ+y[ql3Uö͑4}Ld640000 tests?B@dZv!T+N5IxH'100644 cc-compat.hʢGez<;p޹됑'XԹvV?}" ԩ\+k`x[ucdVgxi {zۻ]IY> 7xJ'100644 cc-compat.hAA݃姹/p.Ŧjȱ']tBS^tjpPp^'H&@RxiC 噎JS]p_ ?x9\\~o)f xRȧbQ&va\2 'Ax;#'us96 ~A!A~8X nxi Eo-ȑ >=-U !x6S}引#|I 6@NRgIQPsx[%3CfsFɴʼd̼Mj.΢ԒҢ<WO4es M.3x340031QH,KfXbvVϵ[.ݨw -3'5~)ޯOO|κmsߓr j3b7H}!s64X:"r(ix{DziD /Fxi HgPB+/O9 ߏ +x{'100644 cc-compat.h2M?YxEW'X2gD>T ,M^aI(G $nlp,p3 9r(z+2k6BMr<1kyx[uu~, PlxG 7=( <ޓtypedef int ssize_t;I cc-compat.h"vO?x;4iBT~J^CN) ֫#d0q$A`xk{ûy4>06561Ts+2r2RSRRӀ<wϐxO?O?WʂTMĒdbf#vOz}--Լ TIJ̜ĤTHf*hAAA ƚ\\ cKsJJ2RR4?Xhi&'qy(gٓq)J`xx;n UJJ|K')xi HԾy37-nfӛ)}c cxJ'100644 cc-compat.hAD٬JC6'T]m'_Z %_/~Uu< +x[uuC'2JNvdZW3^Q1cYrOR/٬ab %% g:Z7*[FOyt5.0xǾ}CtP %$J%0^vz/ol([-T"/.'Övz?kii3ņ5=ci3tEkaDL9҃(@-TnEUg:?3,x`b5gSQ;MF 2.xi IcjnM}W:(%ПKJRKԇ?jX0dg7{fx:=%w\aw}x͚Qlrk}ySeV7Ť _<&z!x$sodb.h󮽿Swv4#&6Zw_xUoE#TuB**Ķ"RBڀB*LwىvgYᇶ9υ#7 !C.H ?S{BěwQڋ5{j?Yp!OSz5:eaEqnK%tЋxjA64!p@ժ'^1Cmךw}}[|ܼ6{nqtknѝh>O߂ Xӟ7-{ny~c@3tקYIAWO^q26Y<o[fYxN/<"-6p'KRūvkNC?L/١ ;Q7;ݠOvw׽br6&Bg$TG%H%(;A 0(Eod(qDA(P+DcyDt{D(Ay=ܳQ`0 fYdO|36ﵐK*@@DG+.|۽!~Gg6eUAzH?zI0&wz ઝL1-+FmV };ARdK9( x;qB Y7۰%gVo^(4d{?'u mxc{:D ϕkT",Nwl8gr4fDgPxreC _xi HՑBl_띷ort DxF_9XP晩BxpK100644 fileops.hVd U-衑 YLy+}&USlKxS}~\l%x!Lz(}lx < ҊCZȭHWP 2x6ܧI+u{',BZ,ipF~Tbr0x!%AQ&(/_/ÎK93/94%U4/$(6Y$X UQIfn*PONfXQf^:XJfQj^ ~ۓ?1U*&($)hsqg(h$$Z+((k) I%`̪>: 9y: A!A.: A@vZBRjzf&Ж4 $3l43S4u ';rM֓4 AgY Z@%\\y a: 0͛Wp<KzMxrOyd)v4̒<wϐ WG1 >1OKQHJMTQ0l$5y" y@ZA h&W5'Ă<u9q7)sxi LmO9nd9<9QQ r&x!(ep'><ưH<sx;qB Y7۰uyEo~xiC &m*z};b"l x9xe4mÙ:69ahB.xZ[\GV(lp͂]{{#qb#(Υ$sY?!v$GyoOgϼRYL=3c= iyiJsMKGTMaL$4<W%-̈gD}IH4'Ɲ64ԔE5JF sR&s荜>kZէUrDuV!*)](V{ -I\QzNAY~L5R=)x[z;#)Zh%*'wg\FUCZMBG7$(#KR 4l9L܈AJN+E.Y ɞ~q:Z6,򘭫фEظ&e_y/~̖ d-T,",鼘(V#*Ӄ77v_3Z)-)7tֈINSUaBcuΚ'(|K W~ 8g?ۨ(+*.0ir+ $*Bǫy ^)oZqb FzX}X5Odlɓ;7+xd'2kƮPi2x/S$%J}JZ<9c5xJFrPPD7QZaǽg/\|Bt#%ޢ4,|(HHCPy;,VMR|6'( pEʠ:KW 9=ahjD撃!ўq]ُz챦}b֓" FĴ 1v K*x(5oE#G@ %*?gH1*,"U41M@LEWLHHךѐ]SD.O~#I:8 htgrEN'8O14Ѥ a4XC?z.?4{Om8d>…<&N8Bf%AtqhICE$)/=;Iq䋈lqUQ;X%OCKhŶĎF >8K-Bϥ!yjX_l!BQ9T90[dNbmWSP֨{$x/߅;E *#TVnfFA#@*Zzw뉣ߐtS:Җ pNX (w\AfP> ڙdXCGI*GpDʡVpӫ{^ ONP,:Nz7o(2- ۺShu|a&TD٦$wQ8Vt x/TgXhJq31{rNCh>"čT쿏fPYBtT}Q~|J-޺nP6ځa8f6GPc&Єř>qRڹJu >|{ХQ^?h7ʳ 闙M\lM+h8Qqw޽;ypMK nbp&Dkg,j1[X'i@7rA_]'/]o7ل߼K 5>xYW=\&,u˅B?K 8/~~sVCH 1]h='Y8#J G1A/Uy -v /8 `:rv~Dˁ _:p/=]*磇Z JdQ|g#ݷnUCNx˪UI@  A1ݫoPqH:1r}% qıswWjQ2h^믿V|}W~ǧO>w;r={|pɜN, HFw\d\94g\,ذ) GFRoE^.R|/bqe=y/Kd1 YT6(a1!,co0TV{ ѦEl"zߪΑSʊl;"[eR%ż8}C[tu|kqβʀO3j,/p`x/ 2-jr` Cdb([4/HFGq9x9(Hkڰ=p!!d(LkD*!)Rb,)Wx, ʐ~D' ۈ! P\ E 3 ]RZE*uQ##&r*Mt3s^=p%#6wxՓk_W:[,2A]*-RY)1svG1x?z- ōQɟ2'!B}mNJ=\+mDzq& E=(3ʣO^L os=Bhy<k? YB9sB$ [[ {;Qi"t C[}>!'m }D-wؘ=qh.3,$7 "4_RpڷALWLYwm)RNJqZȕ' MIfVAZu$HI|1_B7Q_HFҘ/F}Ye$K&͎b q1is oP]l4\ FH[n`蒏2{0,UR%I`apQTTĹ!ZY+({3=O^ORze gzZpKZMU'w:H礭U=7H9* jg$AwՉ-Ȏ7(Dו=D(ixM:*2Eʨji*yz9Raj.'y\%B J:*L6` w59+2\%8p:d~1nP ,گԵw[O26J!iZ5AZA5@LᆧGc*ZK2Jpn%g0zZ( t4tn= 1_ر]<(oAo6EP]YC|OSj=!ݘiCL/b֧@m?yx~9ܺQߩsvTI?_+SfcHV[5X9c UkSM'l6Z'bLzOZK*ة LOa R#`\Re/)3٥n?.ԫ9|Vٛ@ev+(D tk1([JvKȬ54RգՙVOk٬A_(G98FNX]$2N/S/'jr2YvRfej^Wrotxi rλA_ro>z;d#&@PZ\R /ڤݘ|O+7x!򩊈3r}rk+[ᴳ&l+x;*T|C), Ex{uTWykwm_aZCxmJ1D 3q\ nE: ֕! aAM!F}I[*'gV#%,[py4 +}X*`  ֧ˍ,<w`Լi;ơNS9x%ܶ%O LOvNQ< ]%tUxɼyi:G{` 8NJ!2?t #xtmRxԼ->ۭ!uR:.R0!A={߹>_}lxi MvL_YT8F bx8"sX>}[Wm2UgM!& HZ.n&lxu>͗&xx.A])7@/Ci!F!̢Լ ;..4ŔԴ̼ x'O?ǠHM.eLDK95/%3m~ۛŘgL~ksG 3, Bhx{.Dl*#RJfd Fٌ8S{Bx <lH\樸A^,Z{ܔP x9 w9X_VK16?ۼ(܎ / h0-ɜx340031QM,Kf͈)R YfH(c 5x7ʈb$UC;]4Ul @[5O)zsuPIP rqax@[9-lcrypto rm -f src/sha1vScr x|0_ 26iQ+Y R9aPvf.`Co1100644 fileops.h9Yc7- !-?%100644 fileops.h=ەYqpwKxMyrf^rNiJMqe~nnb^D E%%: )k72jHx@yFLxX"Aq FCBr~xiC };o ?aeJ{d{i6O zx{ʺu"&e|@5Ex3V?2 `Z,4hH)x,P{x;#Hn:ɇ7 f=wx{e"FߢĔTd'/tcҸXlB.?XR5];'1Aw$xVo@V+'B0J;JE!Z"@D( ƾb_,HY  V6f6Y'ޒ{ޝܤR|%zqvbJ_79Mg`,HhR′# K5 6@Jç`VK㺐;} @.RlƐ@ygJ-aIx]h0؁ϰw Y ][:VIDc %E Ra4ְDhJ(Bm)!3lN^-RG9q_ȥhܥY$hGGϖ)C-'owZ*IBY9i]^.?~lpc<em< >9ixrSc>=/yS \WGAqWfVӲB5~x;EFL0D-^uY{O/7UQjl9ɛnlʫ8zgyzQanVum-{ۡW|ndIߧI[RpdJ7C?d*Fv$Ȃx$țF?/Wj)>Is;Yk٨0t! Z#6h'q7!!,[XYZѱV^/bK Ė R5!;2'"[eR#E8}ζdj9{UgYev8u7 n⠥ŀZ╌pY-ÕalMT& P\ R|-zAvlsDe5Mdt~.t#Xtbb-_х!h;b\gt#DW E _O`-+T+_O@Q^\vРu2bht_RU W#cWI긚Ճw^ݻy˗7ol!&0XvuJ*SdFVaMKـ.9'/5-FꂋWS!*\yQu@vyj'JE^̡@tVBmJs/.Gqd 4Nfm Q"wԔ+xXmV>Ɲ@y*$Ex؅HMSti & /!m3\y'l0)FDI" VlD N@bj o!o?trɛuRh k}'H? ~m?6> ?et2ZrrGŏ@`:I揙AvO&3~˕2o;_?$P Y틔|2z$O֞[A2A+E<0GuAF 4]AY]"$4InnbG ֥JdO37obL+3 {DR9R^}i>CG9Fp2"T4~.P0&`9ZBJnX@٢2,!*bh|^r6p1vY^p w R{M%+Z P B%΀ZPm 0L] Ϗȴ]i3$,F\YjR/WQۓΖ@ݩqA>tWIE$u,.$~@u JgNtz<m`D%:)5k2W"" @ d^{b<Ь U(Ht(/3ts_@JI),OW4ySzZ&͆bPh4yqj)gF\h6F(6ЊA70MWR-#wKFQp:VkTĹevtW3w{3qϭH%WtGc-W^Chҁ.LA/c׺.ҁRtI{z܀@9)݄琂O;TB`*(2Ӓj"'-yFtRȬ߂ň)m@^.ZJ/R_dkX`C*J B'{\j)%6)栥@`w]sdlqt j2o0VLm~&ɠV%N!=صBVnQ5 M6%s4 &7ZJ\ۀF Y}z t\C.52WjPXXmM#sS/:8Vʓx"ݩVNDW1RB7k#?DzYK!ZSi?TƒE.k>1wΜu?-UӦa 2J7'UIaZ ]%%|Amvʮ(z (Fx(U&ŕPphȮSͮB+$Yf @E2["M Ut3,ܛG*+YDPeњj)둀 :oKɥ MM1gCS~N tkל-^,Fn1M?xi 0ɥ\9M~WŊ P 7xvypm'f5` hZ}95z*+6qf100644 fileops.h7L+wJ-P#j`wo,WEDK-7FC1*x{yYJ2KR&3J+奤)yq)+yy0R:L[)kAx|ydƕ  x <.z5$֦&(ƼP B xjHR} ?*)&4“Al+AQ!RO&N`g47  1#%I)N'X"@2x#UhC& L͓YV;l+xNy!ͧu)fx;˷oC d6m,L6AF|#xi Gܪ v0o[ <9Qs x˶mȗ)OU.{zަAAx|\yC.KY~f*Lp n`|_ ˃ *x7eՄ6GhWc훤[G0P{zY- BwP ]f1x;#_rBhM `PY19)}5\Y7cb5x9Pɇ7:$룧Yb8$IfF P x=>w%vZqSRQe-,3 Oᓷϓ;_xJ@/^'aT4ў[ "BAJY%H^xqv[Ӥ%avt>v˝2T 13Tv(HDŽ(T#ס~7\w@}HH*͉<5hS;|LRWW&~g*89E.z:2 +{Gcj !zMY\3}Zn6ԲH)ZVH*`=|0jȘf75طn(3ehMd}w Fј>HlFjd;j3.WH~V\-*n.Dr|'C0~߼MtYPE,;1u|xiC k ͛nt>6px pxMAOn豳ȣI@-100644 t0202-readloose.c1 Z=֗^-hݒsii"nx[wqM x\C\]]4 7~ٕ  'x;E #IŚGϣd` 0YXte!F"D 6$h!322~w`tw_UuΩώ}vo>z4n>{ݹw?[ݾqFsfvoٍI^[~zx/mw廼؞]=|{w=8ۏI^,۳9˰=}=2m)[뮐W|dII[RpeNB7]=gd"F,v$Uɂ xd7e~o9OR|/\簱w^%Q!ah$ jQ-\<9 qamJPZz[d`'4u^ 9ޑ8*~8m"*y,7E'[Wݓ:*=ݡՐX^F_ ,^ȈB7ar=\ދl6hKnHeR7AAS/ۆ`b?dq"靹 @=VXWt,Zw|D`1.`3 "@+mNfvjύ'0l pST*_@QV\LvA7jd 73v9-F&?xq1U'W;R^?rՕ # ˎNIY$*9&YUZS"'1u2I Jbj e)oEgSrμ\2 X[acc>Iu"'efWYdދQ6n^*]9oȕ,{~d ԏfm I*"Ә)[lZU>ƛ>y.*$Y䷗֘@cpiŀ F ' Hm)]yug[ɰ `bE5؈Xa: !*/V%XJk\7x&vLG~:yk_n(HH#WCHjg_;{'Oz@>2OpD;vBdo>Xʭmϳn|śԗJ4sP'!D'Gʞ))$쓵Z!MB0Q8oPWAvVA`CTx97ࣆlm\u%7ss"{ 匈SIR0_mn>C{%;Fq2*|/~QK1H`|r4xEaXB!*V+,PQ5& b욒NM@x*_5@,bBQ.P B)K _qI th2 "PY+$q[Yc.8u;E.ȧ4KC!yRAѴ t] 8o`}pܙCk'2%UkeNqM̅]$PצO"4 H`*.s=p7J0\. dTR,*=`-&C1DEz7\nnqPw#.@#r`h!gr*-[Fv#(8-+E*<}+șaz:++@/`Ciҁ.LA/C.4ҁRtI[z\@)i)1^!.wX =°9bQe% EN+k$H阤I]GSz2*]4F^D?ְtTNRrE7lR:AKсfD$pXPȟhPXGʷYE$jTHw`o2eEՀ0SG`P.%TtʭR2B:4INCgğԓ'NFrV-H%mVJ /h* z)]~UdTCdR-t$zjWb$oǭY.87ZJu VOC @Hn=(Y s3$jMմ*t pkk{PHWb ;6bP\N. Vǂd0*%J)q%+5(:$w*jw}ar $7],r- *cv}zG#ƕ,H⎤+h@H@IyO9Df_rBqO~Pƅg߱{,^]'w 2I#dی߹cCh!x <=ɱ°kfNJl鬓P 0x:+QGe}gUƳ*~QXP- p8 ȳ$"ix;4iBk@%xEcC1f+L,!񓕹 `n3[a|60txA 'x׈#[ ܚ"R[d$q'C SL(R,s' H޲xm+pe:e?[DmaL؉g]0iA^.1 DQjLYMi~戉PiԻIOOр!J.[ъtVAH]rܖɥfэ P%s &׷ pzɴd/.pťhDEԔ='Li"_}w2L`ox;ѿR%dyJ@KaF)fF-!-n\Ŭ ~-.wz}3 H %$tSg7ᥗ] sO{q2BAFZ}b};Χv'qqojE;.Iu%*U珝o~?͓+xDe<&shm84كhs e66O?O?ɡB*\\iEIYv)%\p_5W*!T]xSAkA"DmxIHS<`X"Bmd΄نx٫'? rBWvI˒{~?}]o:jGkuBp5-îu\n;z=xoG{Sm75hBw ՃKxod\& b/\L=Vhe`Np3BE$ }Yt ,0h_JUc͈NAi]A76o̰hfhtQਕPf7v]{{t~қYEmĞCl Sj8_ q|oڟAƙc88}|܂DI6ODHg㽗V'4zkOˬ䴧|VFC/cxd_NCf Uja tufW暂pc&{ȳ;OiF U M4vU dn7x[g&ΛY=r0rgxi H3@˓Gغ2RUx Dx!~|8̝\ f$$ADxi HJ,neي 49Qę !x6m3F0SW6COE5%M~ͿU,%xi H_ RKN\~V6mr4 |x!cY${IUY $K]x)d|N?4.!-^x/y^rX8rS2t &aiGpM^ƚgtH.PM¦,#6ـ.y[(VxϨ6%ld[$ lzx;/WrͧY9$sx72c{GلfԑgRW[/Imrs+2>Vx;/Hr70m>4ٗ9'3i"mǦ ggi&o@RwMu2?d'^H,x7:QN*( V9gRW[/Imrs+2>È_x[$Eb`Vvꜹ)E  *OaSĦ Ģ{ٔ&bSy&uulacMe1xiC Hm WTַ[:i; `xMAa-on{9100644 t0202-readloose.c$_ r |`;s E `x[zq5z̼ҔT⒔| ;.$TԢ<4ey@hZ+KK0EK* RA ,v56{ƈ1nNb4arv< 3y:lx=D5 $v%|X1Anh/D@p 5"$3 I@܀qtW7dUoU?yw9ʛi3ʜ|.2H3N$o{=8w KƹNBw~9n$C>we!FyfdMY@?bC+Fؑ3ÏRaAވѳ֮;Y)G &2%_Ճ2!xWvtP"ܘř&N$E0X#YH7qkb$'g y.qh Xf%"wv@`[rTMd{oXR&Cq6FZE~o4[ۏc` UOJ _zx:N=dHޑD>;$p/[R檠f$Pݢ<C4 F2ʓ~)h, 8P)Ngΰ V5d U &bLi i.8w R[gV'( HOڑF\苹 Ft>b40C-Mj-#r6Wv#(8m(*\ܨŕdѰLG gr7ZUJ+@/`ӓ!δ8t@%k W@9sYmkZ[}I\s6io`g[V100644 util.h KT?K=F1ӓgx}kf0^lMx;s{FLqn x{e&y ˘m}x~ѧl9E g|xȵ Exi %fSWr8jز>2brҵ Kcx6m *nB)XCO׷ϝqOj ~j x*4GhFnx <@+CyHT愓P joxvu¬o?q0xi ȑU^WdywfBF6 0x#+vDA+Bi8"{$4/,xs2mlQjMn6OIMOI56HI,ITVLѵL65TQ0TR0,άJ/QTUc U0402OW`9Fזq\=$&'˛)hVKK/-ΊDSXAW0VSsF QZ.]d'jZO3$(>y:5 T54J3RS34 @>M,DM hct7K1Z` Dhbif^0-H%&+!BL'7ȿ012PR@iR=sxi Hb* ;'[er԰ Cx5A.䦧AVtLWʐ;髭Ҹ 8l;x}k̖L{xi H͇fnElSyxE9RK}|B-q100644 fileops.hGQFOQ%!yxMOJ@I$B׿"! "ڕ\,af҄ILMO 9  ;)ܹfZAw}~Q4C˟Շ(\TKn2]SX+Ld<x6VFj)lte],'\Пk~$lJAjWLx5R`9LcEm !@IAȝ93Y/NnEz'#FRՏuHEP\ i ;M`,VXR|r7*x{ؤa(&.Ԋb"ĒĊRKJKK4@: jI2?+QH,IˏO,J+D,άJ/Q⋫ Ziye) Z:P4rĢtMj<[E@\.A Zx550K&Uʗo.s`dlï_Q x[$~,͢7[qd0;xi :ET{窽rη~Fm x[ͺuF6o( 9۩:w+w y`xۚ>k#sUf.mM5' xi s3ϒt) [ x9OݬW\n#R@.|pjjԼː_O8x <Aq弗}x]a!ɓP wx So."@QgDax)8ApC#g|s|?V7xi HL9'ٷy$?eg ux SuC#G陓gD~x)8QpC#g|s|,_nd fxi-psS-2Lgj|Ξ : x[ͺuFA b .'ts]+K_xi B*du|/~19QP [xE9gǵwɌgm=T100644 fileops.hrlZ2A/v%El8xkRܠa/}<" lx;?י>#fxi '6ҳX~X1v V /xVam^o(8R66QGbRQCu100644 util.hiS!=dR0N:X&%kPx|yC:z"nox{uL34lkx;sLk"Vgxi t+>|2YN-L)&@PZ\Rkn;";ˌͽ9U1eYuxcW]Sk.*>100644 fileops.h3jNF'Q,1;y>40000 gitR4 L,WLr%ԉCh1 '-x;ɿgd5:ʙy9) JEEEzJ\̜B%% @x34mw%)iyP<Ē bM .TE%P) "ugO>ά^3 :k4lJK@UrԢ 32/hT k7d͛EBx[sk"d%Ey y% %iyy% E Z%:`i9Ś\zRKphOIմl<{5f+X?.BxuSMo0 =׿pM}-͊EK f2 )e(cD{z]U;*c[t&>XP#uɳlQp ʼnR6V#vzd#Xdna!Mtd*sݭ/]-/n:T2HAS9(gs 4f KFP>^y/AwۋQfD9iE^x<J1ta`O#p%l% l$qbAk m{A K)dv\|n[ G~"eKًP/NIRhTjOfud_NS.r݂5 Lݲbr}`=9'q~h8#)/Z ;bF SYiDJ0- ͦ/Pa=^KهpRns{\ R-[lXj8x{IJe?3xi 4soU\ְ-쭉(3~ٶF9M!%/5GA'x>u6d绊݄2N100644 util.hiGx=i51qUhgnx{ϼ lQx;cf.fk&j x{2aƟSxDV2RϞRx"Q51'jbdFFUQ'`Oxg7G`+[][U7?` pA=xibV/~^巙X/abk hx(zJtF--66x٤6ww-Qxi y+ݺ)F܌ 'rx!x]?Z,"BF*Mşe-xi 4&`/g%{ߍ>]bb %% tNW[w3]&]qxx8{M: ޔ'zG¥Nf,pɦȒ/ÓgD֪7xȼyʼnO&3 M^LRIx(qt^rNiJRzf~IFQjbniIfN^d7oV )jx{yBƟssxi }#_Z X WHVN09QD Xxi;k+8=WE8ۧ4A]YmRT#i 4Tjr␳s.m=!ƾѓCQt;Ӿ<,ΞZ2AxȼyFɫy&WM|RZ39QfVFE Gx;tiH}w5lSS3LvJJ Kx{yc dmF1,!A.'cZ49Yvr/X4n?xiC h WĆ59bм( }x{̼y.kL QcQ@J7?)Kwov({RNHQjbdF8hr$c3oxi H)x i{K<]{{r -x[ͺut&|wI]ASCܞ(Y19x}6`Fɫ7321Pvxi ȷlٲfR< vx[ͺu{_w~>CY LLR2N>fmґ2vF/ZO]j2sR R.h8T>}u9 3˾{]=Y*Bzf Csgʅm-۾( qV˯c3c#^7Ckbxʾyrs jmxi*>Ux{M~d9L@T6(("%i%%Ii1+$3?QPRwRH-*/RHKKWҟEEFAC)MV!71''?Y#'5O{*~Ѭxl8ٛ=w^!22󀲩 e)U9Yl4YwL>o&K8x&E~!gHFY~ffg )x"E~7U89kj44Jl3Kssr5rR& MNe,?9-|M1 x;tiH`9k>Pt*[yk줉akCx{;wbJpx <MEMu> P T(x340031QHNM-H,`p-v\^ΗCbs ss3K1]x?oŝ$/*{z`󡧭)}]]a6Hjjl"K+Ԯ&ϘjR򋊁v&=#ѻYjݜlj2N>fmґ2vF/ZO]j2sR @y\*JLVخAS0r}{cw+}۾^ PH,a\ȫf'J=֗CH,Z.礻٫n}/ۑUd0l.<;3s>ڟ42TE~JЈY y]t} 7O)L*hc l29BK/*(J-+O*j:U'볇}: /OoXl &Z--iģJ2RStKK2s@wҵisła8DGlƦ2Ar~i:s7\vbb*AJ*\'_4`BJjQRYP\X Ulľ???G!=$(ȞK5x1xk+2BzfI|QjY5C>gHKrj^Jf>x+g$G6̒Բ {.E$ ]k'xsg}?X+"<1xRJ0xiN> m]PQ^t 6%I(!|—0IjmǼ$?~_!NAb!E>4#љ%J*!A2EH,rH !,<:FcvJ#k.$M%Ŋ2c c{B1g糙JphJZ2 !Z/19cl,J0tU5]fmBJ}PC&yV P,(b.Hꤝ̵Nv3ȇVƚ1[S͗lGm`3юƮk_-W^5]c;CwK맵w#r2BUlO5cx[4tfIa6Ĝd"̪TmCMS9Y'/VuBL J7x <+w:>9P Gx |" gTLГi^x{z(t/+KAbIV50krDh#V- ֜MJxi HV%U}<ӭr|)Ӛ6M~r Xxdd0Q}z=6o7c>yѲ kx;z t<<!~:xi İ,Otԩ[F Hx8{⷟ 7F2P!;%MF(]}TW0 57x[iBdOFLf Pr:x;3t7SfNy$xAmxi K)[5"m(3h8v`E'OkB\$xt8\[%*˧aAgT100644 errors.cH3ɫ ǾQxډg] 3CQ2P!;%MF(]}TW0 _42wAx[ʼiBdOFקLf Jox 'eŬ3y?d&͋1Ex <eO_wM5P Nx\9i Pm@LsפmP7100644 fileops.cEV +\3 4Ւ:Bxxq*#.̤b+]̢̤Zݜ#.紜tJuf^rNiJ*H Gqxi If?kx|VXBIjqI1Aʼ7cu{/:Fx9/hQE0Mk~a@h01CQ2>4DN {BAzxtDɾ6 D:J/'akx۩zWq! N.xzo3ܬrFjlxe~4!nc3#\vxS@cĪQ_+ͣc .4v1AK<*40000 testsYNuV-d](ll5x;%zPtC TTF Rk7xd=ʲqropjxe4xc;#BN$x <d2IE#[H\P Qx"ʧgn1HؒJK_R;x&C~;3KY~f}EX.l % x:5'x<> h4;IZ/3V΀+܃C߷R2>hxO,LO./)J,KHD.3 wnx;%IxmϘLff[29sd7 x;tibIC> -/v>cAx;%_`FNͧY'2ON\8ٍ+ 8  apxS-obRǾKE4\4GwӇ/Yv40000 tests yb5[M B׬.Ds%7Ox;%zY`F&4dt͓7feʹpW2{qAbQq*&IMlDx,[`CyL[Y# x9]]; @{2WA“%+=.(PM{1}JP7uqduFؾ ?)x;re>nw\_+ΌL #hx6}`DdyvF>TT.l-9Ѿ{fBzfIZfNz y) zz3 ?*x"qIbMlqLغ7bUqx gTTҶI\  >n.x;ti0o$Wm7Mk_nb %% ŗZ}qOn1bx9/]gIӚ|\#YC.5Ts,NK=U79W;x6}`DdyvF>TT. !i BqPMx"g—ɓ뙌 61]fڬͥv2Yx; "sN̒x ]X)h嗖($(g祦($g$)hirUsq&Tje(u3R`\\'gpxk#a x{xqdf^2CgjPoO9 yҞ=Bkx[~RffF!>SAx;ti0T`[yڃTݼdduF ^ x9/Yf\\'N1C.5Ts,NK=U7~'x;ti ^y/]%F)@Dhܬ +x;ž}33KJ~jdfIC)x7O &!r: yz\DeLyQdCӷ' Fdx9/E_DU\n5~L%C.5Ts,NK=U7Ux;tiHͳ;3g[['֏Ĩ׊ R[x[ž}.hJjBpcPkgp|PL#ܣ }lxNYU|Sj I𑷐ѻ/x{[&ĢO;Lx;ti0H͡6G=zZz"{duF Kx9/;D67K|;QoC.5Ts,NK=U7r x7ʘ@X{,\|owx;;`q/\N"" /2x{rGeU< %.̼ҔTYy b.xrMeC#& N[ l_ϸ4#_~RV|rN~qFzfId. "CxrCz$8a̼ҔT⒔$ Yyב [#x;ti0H={ZOW㑿a%>r: Zx{Wb[D8Qn}:V;100644 fileops.hVЈO#vVX40000 git)m_ҁ _?ؽ/q!C.5Ts,NK=U7I3bgx[+uAp j1x[ssBF.Ԣb ɿS&_grŜƸY Ai]x;4iBk@1x;ti0U52ܺxUȪ  zxE9YՒI100644 fileops.h2ֹv~P/yr#g% 7bg_x[+uu}& =`x[ų}BF.Ԣb ɿ'_cr8M tx7qb]Bs_2ÂVj\ i^SUەmE$O' $x;%:WpD;y{(*%g'eepq;y+hCdU45<\(%z2620 ah<)^AE M.N"Lsj׭]&?fB&=UmP{\&/-3]/C/3*[:7%U9~>2,,(hԅ ~=ސ]M|-=[.TM~JPku<%g׻kM{Z5k 2fJ4D.{y(3vxս3\ikK8\6.J-+O~Sq}j׮N*ͼ:;PE%E)%9 <˿#_^1su{B{k!?ʪLs߰Nbn*fR>QZ5BM xSLKIMSs uqO,OKLψReRK)MIUP;8;8e(RR2Ӹli3xrDz$#jxsgD6 x340031Q(ˬ`ph0;e=7*^ x340031Q(ˬKfRp]_dGڳKOo|Lw7)xj17$>©Тvںd6"ծ$N@I22BW}>LQA(ns?x(s9X. `J1+›.b mQ2H$W.tU o0>]?=ӣД -$.%ΓXm$M(+Y<}鴇wG$I)&X(NbckgLuaw \! [4pfȱG>'Rr>x-* 24%2?G[Ѯnd-[ @8&:JGq%]x.Lpr͏X37'3Nf,gtxBBL~< >U-x.4Spr͏X3''L~g2 NeC Kx;tiWi_;"OmW>,5;9$ gUx)I`C =xs! ?z#rj摶u$hx葛ɛvמWlx+8Qpf TVc+x;tibͣ:V{}=0QzJpu17Oj89u9:KxAwJ)!g?^maMjQYЭDFhF7xqlTx,^tU7Y(F^x[ͿuͷY2Nv @gx7db۝Xx\gԇҎ?X6l' b^lx/Z` ffsV",?xryBQT>~&@Y&~mŤ Xo?Vk-SEi&xqBzmex"ṿ0zTL vAA"Ek2x[žmO Z6Fx;ti03]fJUsOMbwc D Rxf$Jٵ1 A~&i\xxqBz%Iqx c?ϺUk̓' ]jCx> 31ubWFAbIqiRq^^FyfNJrbQBqQ^&ć"/X2Mdaws|y  nxx?!mc3&v=WGנEsXmWx:,ٟgrl1j=xx?!mck';Y]x7*p^ŋ:t&Vg\ԐE&.?g9e2Bi' Ҫx340031QH,KfP-:L @!=a=E3.znbB~JP{ߖxjsk3gG[d<21?XǏuRnC@/fkC 09g/(<1'h&O~ЂҒ̜bʓMs+Us8!w8g36 S-Kә$? &q^x-$100644 commit.hŮ69z$x;ti0(ג.J4'~~: gx.})ĻB~ jx4i¯*_ox^xGQmȝmlmxʷAy 8Ox340031Qputq bbՏ|~,q =E!TIzfIfz^~Q*ò~ ~ps:WDEή8Us'̂ξӊN\`,++ sg8qsg]t{| Դ̜T .vwP5z)y S5X_^RoߪYu,Pe@\XZ_T K~YGܚ~2sJSRnL 뷅r^rVų *6Ji[*nBdKRK/) sw\Y%cdݽxO,LO.K)MIO,OKLD NH` x7!=3/94%ubH?Y1YQIY,9?/-3]/%(XAV*9ѕfULg0biyB֗0,F7x31RΚWdo [x7 x340031QH,`ʡ̖lPi׶ņ5y@5 8{I}|Wm`槧|nph<0e)I@sZhk)XN~k70)@wrtt 7;L @!!ƫ nZH_[)TwQjYybN6ЄnZƣB+n|yG޵O.PEU9 G$KnUyv΢Olf?Onlx[ͿuͷY.0#` x340031QH,KfP-: !jS RNN~S_+~9;2 3!:~zw^jZPBĮmAl;L˃.J-+O0I'w7s- <sFMx{i8>gcLN?s{OyL @(a ou'軽v<ɞ Wx31vѩ@Di_Zc= x340031QH,`cVe/GG?y÷S&?Tq4\M^Zf^^f˶Ya¡ud@$jۣmb:aZuݸOdܝ; q3V01b7T?}k#Mm ˦PEe9@ζ{LoDfϑ/*9"Iv_rㅭʳs}b4(7pk1x%t]hCT*x,0GMjص;0Tx{yuj.̒$$kZk..@QjY5?dE,T |VILDx{i8ћ]_Y~mOd(%3|jk=+XdOFx31+S.N^T/굋 xx|3΁'R@ݟXq.ʑk;x31 B ILKR ,LEO,0GMjص*x;NhrX7QXCY x{i8ij?\׮ab[ܚڌv x31ak6*K%ikQ;p dx340031QH,`OD\i<D^ڞ&?Tq4\M^Zf^^f˶Ya¡ud@$M}8mV 7)ۦ4uK 3@T?m+7kU>11b7T?}k#Mm ˦PEe9@^ i|ɶѺ?aɒ/ULK*9{LB7Suz\إ<aolZx(t_h?,&Ԯx340031Qputq bbՏ|~,q =E!TIzfIfz^~Q*ò~ ~ps:WDEή8Us'̂ξӊN\`,++ sg8qsg]t{| Դ̜T .vwP5z)y S5X_^RoߪYu,&@S@Zڿ6׵kؖ|4(S.X_҅v %% ŗZ}qOn1"'.x(w|c9˜>.x31UeOW.jԉVS3 fxqg pxǴix5\5yӥJrL @(!\*u@⫤^eHi?9lZx31sA>V3\BLe|&7( xqBHM|ܥj]^kdܭmbxڤfV+FkSZ[x31y0#d|\w EO,0GMjصyj.x;﷊grXlYK&+z;sqki)&))$攤%+$%f$&)hsqg祦(#YsZOWd,ܡ7y{QjIiQd4'xǴi,xݾyiF&@P\6Kݤ⦅K/G|F&1*7ܮx31II;}nlyg%[Wr |xq.Ɗt)WN~^5c9U x340031Q(ˬ`^=GbW?l\x+3WjC֬ErO{YG)xo~ʚExxm %x340031Q(ˬKf(W8gcb+s-Zڣ #^xkX˿a6 MjQQ^^,Y52x340031Qputq bbՏ|~,q =E!TIzfIfz^~Q*ò~ ~ps:WDEή8Us'̂ξӊN\`,++ sg8qsg]t{| Դ̜T .vwP5z)y S5X_^RoߪYu,&@S:sYpc[|9gDEqQ2ïeB)wT'|"۴}ْbK-r>H']7WVMx31O|`+hﴱP_ .Gxrz<$);U%x340031Q(ˬ`a1at3uv[&22)x1N@E%@J@Q$((i+maw J) qE.Aͮ-+?ϭٲ鬨׷\bd@P(Q8j54Z&F.~}8sͼVwR%  `wGc*'hC"AZ3H_<:38aP/ Chk5ӅLf2PA5ncB C6Z\K):*&تQUN EhI&kCev(n3+O/a|J(;OgMh*47|}MZD(Zp="5bU|Cڡ9YgxoW 7vBK5ON%ڥx340031Q(ˬKfh4K^i% _3ͪɤ =x[˿g>̪!iE ֓H($hZsqrf)h)((Mɪ L++M(J-)-S(kj6 =&PB1`xǴi©M\ i?eyyH5(d%甦2nzW6Gm=8OCT%3Ln?i8ϨasoA%<Ȗ3|;mm8xHR4Pkux{|yJx31k_mV BxS4`r ˽ AwLHU1@zs*f)[Lt40000 os3cZdR"cB&%'lx+HtS{%x,MpC0kDkHEk..}--Z-}.wϐxW?xWg.Լ4.x340031Q(ˬ`0𧊨ӊЫO vl x&Hj;hVi#7? x[qBH@UJ'j]#c4'i tx;4id.c%&?FIae0l&WS@t8AZpQFcKF̑')gsx;)sB` gwx\/a=7 XxǴiH .eSz¬;¸t x9ن  ["ˑMsKonx;)3s6ܛ籬b3,IxǴi5k>%R qx;xqGf\mmt-} xŽ_$$>9?$5Xi V+YAiyy\ʙy9) h8RKJ j<Yxý#58$>yk8YZRZ``UD #x3ҚQ*dCsvD—5L:Œ<xw{C 7e&bU(I-.)񹉙yz\!񾎞~ \\*!>NVȒ9Iz *.A %!@U0`P) =! &'sq(8U*)H,).M*.QPQKQTCrGr~^Ij^I13Tg7Gwy9) .PGp5au2 *6)gqq*覡 XAB@m<"sr Fg{%|x;8qZȊw3'IS xǴisҊuHqg[`}3>{܉ x31-K\QȲw%t/:xqHה;_z%aND l xk#a>f/ x3c`ƞ#Bc֒*l%{wB;h->x31w/aedGvZS gxqȌ&oN:3r\|D Ȫ x340031Q(1d }{0Ͷٷy9+6*K-.Lb[xhv [lmJ{ K)fx3ugqQ3@V4lEƇ^Pvq= xpes:Z&wϐ"[B@x7zm-an:ꑷSlJ ~_UՓ 1))j]x}{F5&x[qB!%M^I4$qbQ sxk+ dqIQAlBBZQ~n|FjEd 7xǴi|nuzX}¶| jIv4x31mMnc~6iպq _x|UK&Bc (llxڦf>^ vNxN5x_Q "㭻 CIZQn!QF H5WتDX웒>^)xO,LO.K)MIO,OKLD.A |xu!WbNBNfRzf^"WrNjbgQnBB(Y_K/rS[L2V *N^z8U44́*ch52OVpDٹ܎@40000 src2؊zHV6Ρ w0xO,LO.D.0Kjx{2AkŦv'2VONcXˮx31=*ȥi:)z"q56 @ x340031QH,`y:=@~AcחG jj8MNq{H6T׍O7.UTz|K|9r&a9j STPՙy&jy=O TAQjYybN6Pk!/6Z',YqvExk.d&|!N~.>9\j2!E,$׺K>}`OW 3^8 STmzνu޴ϐ5ԲĜl3rZ-O_^zsUJeLx;#Mb|v.̒k58A")/`Y4VA~~Br~^qTd}ٓpIo~e8YG Rn^x&_tC\6q ʦŨy dii!pxVMOHW(3{\0 -;k;0"@0hv 04{u^U*Wň.+KjSRZTq{~UۮӦ*oZ77k]e͞6ٶczhg1QTfNT7f ?4ϺzdTfmUڧwεd6rS@o;eqS2Qe:1tK%hUu`3/3U凞)Ojûg /gG4ZߪY2 4:l_w 6mV(C:KTVg|S f+hMF!"g4-ZqU!6C*p ۚnpA(P՚Mq(V9+DpU(F&DދἈ;&xGXnR恈€5(Lc9YN'Hb ^JY]|p6&`P42d_5Y1ҭx9郵:i0‹S/^Lea?uğ{VvI܉0ƛE݇"F ;p֛̅3 ?G89& KA@\^0fv#ޭ7 e QEmvINzp'AUȡ,͐8FS JUujZN+3jeLW1*H}G_?oD 2D?GltvYAݯ^:F Ѥ Zos tޥ7]*zޮ JmkˬSšpJcc0d6o)^qsFT sW{mϰ@Y]>}i=v.}.7 }uZC$\WNzKLd}ٝ kzfh ъ>}qdɪƔ}XXxKdv:5Tޑ.~!OG2#lr~^wރŮ*k'߸hCc@.?T"ژP$zu|uxx(*!Qs{4fNN)&N̒Բ܊ mx[BcC~r~nn~^rf^rNiJRzfz6FkjxPn9oxRj@=F47_J =!P%KSpr(4v((E??tvqKvf̼d3rzL0NS2d>YΉD1f4V 4@vk7߶ך(7L܀IA/Ŧ('qQn"WiM2*u`On!"lbm&ZWike%l>͂+=V xі)i6%KeU"8^E5ŪY%]< @PfPCPH++RsaEUDzN`narTUuuZQÝYF4qYHB}xиܢ0p~qZ\gP 7*dg/./ށѐ*E>uxhBE-P@l %?:57eUE4W׬_)gWdx0;FRFo2o/x,rDdC~r~nn~^CZfNBzff6>ً͓2& rJL|:YP-9x[+VjC|6q1$ %.̼ҔTsؤ7`+e[3fx340031QH,Kfbfl0v?}*&?% .12}uNZ[d|.e[e>:-*(J-+O*`\d1q[٥% _U U8gxTn8 =oiiS`Vfs*\[iV -rf:Z("#囫\;ǧ07Ϧ{ I!x0zapoLy}_a|7$b8Ottcεvo0 pٶxOuqbGh\Zb]go ob8jdK{5% ۘ#}+)͡;#{'3QxgL$uؙ>oSqFz c/ͷl{;9lxgVzfI|r~n.L@58RKJԒu2Sjm=xg.d=6o$M0|xUs6=bK/ &dl16PNEPk,FtO2oz!i2 uMFly#S*+vFNDSQJR 7t7;A{mG;66uQWjJa1<FI:Y7UD8uUj!JT.(~F%*uؾ `kqN٧Ӈk1ݩRzP-Հ(E+)BͲ(2AS.L @'3\Yj(N\ i:N%ĵ(*r6Gi\u7Y-H>Fu6#5HaȠhM >vMl*X~Gݝ\=xj{q$K;oHR B ׶7(KfOJ<2 &EN$ Y63H<"Op73$6\,(I/W ~sy6AT<{ "9"sδɌ, {aqNouRhI?PC y=$#7[ ktƳ6c#ҟc>Eʖ;,Ɋi͓$tg,}˞m~v̨Ș:e<-2,qҴX<5<:Ɇ_I \am$F/l9f_ {3Çk ' ܆D{g.=|9S9Źx~UMYإWmu{=ecnx;7;Sfd1%x;Ŀ d7KKt83KSRXfdbMn>x.f=.F#JxV]O8}&}iK(0#i-!Z$Ueg{(f̓=c&{=zdTʻY]Q)*QDuTVu)o,r󔖕 SU,D[M2LRei)+R9I0LKA QfEJXz#32SIRU:/kjސ>J˪:[+xbQ^2&dEs)͢yf2e&ݟ2A S@jg2 gFLˆR"Yf"S+J*SRעzvǦs7(*"3P䈕 U"˖ FGmF> KEMnUVST^4!9{\Pb1*O׭ZD7$"B^[\xH]X#ǁl|(:,i^$mHV{~, ]<,/,4U:lwpoh0#r.cJO+րcfsa .+4; oa:Qo 9ٓ)$ ˆG|ȂsnX廾:SDc5LB-^Ă`2uqpB=-~U~0bİ({k@;ڌDUm% ]>dԮ.xȺP-_5Ӎm%~ӝsq+BAA{>p/2OK;Y2ݝm,FξFzMBp&OLquM_o{=WZth$`88z̨>kFmI;jч}l S[@m (i (m H4@dž>yuɾu~7>Z=[]㻱%86G1-]OQL;{U],옄,B]4-BJMbjNNKѫʚRg ]iȣ.{P}7zrwGc3M/H! c6OlxJ=j?2%'&a|kFWU;\,;'x!IbBzfI|~fJ|nvqIYq6/&J .x$Zb.f=K,Ly93[O#3xuPAN0! HȉBąS/qi-8 Pďx ^{wfgwvϿ.>ɈR/ _ˎ `Wηfd p`l+/+L#+߅/!,0EvP4Fv%$M Q!Ӽr^{r| L24>3>)  \<66-uCxH6^ #dLGko |ⵗvqBhYFob"ʬpK?g`({8~A L@-co.x/pM`CSfl3 x&pH`C 6ɫ|83KSR!ԲĒ"aUkPB(Oր0Y]JXA Ga m9$T7)cx;$o/mlL֓߳Isg$)h$M6fM [n2x·o.f=66F! x340031QK,L/JeP7>V%)~&O~ݺhQj񑕆o72٢al$/ؕASN;;2\B1cA&fe2tjo"3a.YeYI,KɯLOc:;{ځg-1KT8`tr9g̚k744~Rd~xk(sJuZfNj^bnjm|F|<rf^rNiJRzfI|r~nn~^PF_KSAKEaFN9'Kxb<(yKxՔX+ x{|y6sqQFrCx340031QH,O,Kfq}ƞ68%W\=s! =V?/N}aȖt`4uy@u'ox~ĭ䕅 wM8I]~Jҕ ɖLO)-qh22N>״KEvf!+Lpq {]UcÆc{6)`X/qQzo:@RTZV 4wq ?Nlp;m|b7 O=Enّkx&_t<V*x(* fNN)&N̒Բ܊wqUnzx$Zb7SffNLF+K x,rDdDً͓2& rJL|:Y wxxqQ^o٩MvKA}a s3x\<x3ajLh(e=lP=Iqٹ֋?NY100644 git_revwalk.hZ7(L`kEZq%[+!M(x9r jRt Mlbx(B`C#Nx39K )>6Ip쭱Mx)D.khO=@Pg/;x(ro\y) y % iE 9 %)% @A0'%)dƯ7`US_x340031QH,O,Kfx׺pˬ%Q|9o.uS>l[4uy@ujgۦv5"HVtr&Dzqdo^ vk 互ʂT+^MA/ra~i Z)I: yPet,* V)@ͻׂ e0#ȡDv.lxqJc[ؘ26q ͲA4+0]b6nx!^b7Sffn\F+opx,rJd'SffAN'F*nNx39` [cMuK 9đMxt_V:֞y M7 ;x(o\y) y % iE 9 %)% @A0'%)dU&%(4M$hBJfrbI*WqirrjqdW n. ִ̢,FH&a1J-*/SPpFLx6x340031QH,O,Kfx׺pˬ%Q|9o.uS>l[4uy@u}wX8O:oxO\.?% h𽐝jU3 yUlY6[P. !2o;I?]B-*I;N=xao6{SÎ)`08՛/,x?>$EEe9@Ӫkn۳IE1e, 3V sZjV\A %_E6Ol1xNc[y,3xx3ljΎ()gTˣ1q4`5aYznx_uq%xb<(y'kUSFm1xtiBH&BžuZ_~ʼnΤ$ox(Vt5d8X7R:(x3f*i& $aU57@E 㑔1Fwq='fg|m4l0xżycs{gqQjF @xǴqbW!iߟp<=Pt jrnS4k:x{+DtC\R/x9~xիJ ~BkM[lBx{wwnL"?5sx69~xիJ ~BkM3)ϝ&kF;ӓ'xE&x|ycs{gqQ@J_U/JHXIxxqQG5[_^-xĸq<OYhq@T ^xøqB ѵ_;X\~uuYm^fk/xyF}F{D!^rx@v~ҴT1nxCJxøqBHh_Q&/:-uNE^'we2N>+[aixĸqB;-Օܔ)Yf|P6eK[tN̫vUx̼yFNHwW?[.6iBcxĸq<jZEt_Zzߧ Z x340031QH,O`ŖOR1f~tC$dO8\?x(hj/)`89e朹a=3?nIx_{H(jځN={Bxe0ڬtɊ?g~vτ{DR!Tx;wHzfI|QjqiN_(51% 19;5E#DG!%IG!3ES((O3$>858ؚ &fBN~~q*\\S3=b}Y| 99pack-d7c6adf9f61318f041845b01440d09aa7a91e1b5.idx000066400000000000000000000023301216214232500337060ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/testrepo/.gitted/objects/packtOcA3ػGAi[l\of̌ŴnP) 4$ŀuuO|?-Y 21]iazošIn* 0ؒ!ZqSڥ : @0HD:3 w&Ⱦܠhq$neSՐ;dڧ/pack-d7c6adf9f61318f041845b01440d09aa7a91e1b5.pack000066400000000000000000000007531216214232500340470ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/testrepo/.gitted/objects/packPACKx] 0sk6 "xOnh+^ߢ7e>Ur;jes6dϝyUh]&A\jf${SbJ4c[McreG.bvFIUn/&~w3:Dc x[ 1 {\@K#x&ME5_7 *9`T*!5)inHMvHA˦…cÓp:߷<B,i| 6x>fOo{8x340031QH/H-+(aje+kt5eũy)`UoVc&'zhִu=ٱxL-QH/H-RHI:.;x+H,QHIx340031QH/H-+(aje+kt5V ?Ⱦܠhq$nepack-d85f5d483273108c9d8dd0e4728ccf0b2982423a.idx000066400000000000000000000023301216214232500336530ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/testrepo/.gitted/objects/packtOcf:I6qkS2rvǞ[ c6kȍ2:}f0mϛTVR3P$B =Њ 0*JNd>1dPx I-.KWHT(JMLM+(/W(OUHLIsRr2R2RR/x340031Q(JMLM+(aH6kɾzږgR[>ܵx I-.KWHT(JMLM+(UgGҚCWN(N,NJlibgit2-0.19.0/tests-clar/resources/testrepo/.gitted/packed-refs000066400000000000000000000003231216214232500245360ustar00rootroot00000000000000# pack-refs with: peeled 41bc8c69075bbdb46c5c6f0566cc8cc5b46e8bd9 refs/heads/packed 5b5b025afb0b4c913b4c338a42934a3863bf3644 refs/heads/packed-test b25fa35b38051e4ae45d4222e795f9df2e43f1d1 refs/tags/packed-tag libgit2-0.19.0/tests-clar/resources/testrepo/.gitted/refs/000077500000000000000000000000001216214232500233705ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/testrepo/.gitted/refs/heads/000077500000000000000000000000001216214232500244545ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/testrepo/.gitted/refs/heads/br2000066400000000000000000000000511216214232500250600ustar00rootroot00000000000000a4a7dce85cf63874e984719f4fdd239f5145052f libgit2-0.19.0/tests-clar/resources/testrepo/.gitted/refs/heads/dir000066400000000000000000000000511216214232500251510ustar00rootroot00000000000000144344043ba4d4a405da03de3844aa829ae8be0e libgit2-0.19.0/tests-clar/resources/testrepo/.gitted/refs/heads/master000066400000000000000000000000511216214232500256660ustar00rootroot00000000000000099fabac3a9ea935598528c27f866e34089c2eff libgit2-0.19.0/tests-clar/resources/testrepo/.gitted/refs/heads/packed-test000066400000000000000000000000511216214232500265770ustar00rootroot000000000000004a202b346bb0fb0db7eff3cffeb3c70babbd2045 libgit2-0.19.0/tests-clar/resources/testrepo/.gitted/refs/heads/subtrees000066400000000000000000000000511216214232500262270ustar00rootroot00000000000000763d71aadf09a7951596c9746c024e7eece7c7af libgit2-0.19.0/tests-clar/resources/testrepo/.gitted/refs/heads/test000066400000000000000000000000511216214232500253520ustar00rootroot00000000000000e90810b8df3e80c413d903f631643c716887138d libgit2-0.19.0/tests-clar/resources/testrepo/.gitted/refs/tags/000077500000000000000000000000001216214232500243265ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/testrepo/.gitted/refs/tags/e90810b000066400000000000000000000000511216214232500252350ustar00rootroot000000000000007b4384978d2493e851f9cca7858815fac9b10980 libgit2-0.19.0/tests-clar/resources/testrepo/.gitted/refs/tags/foo/000077500000000000000000000000001216214232500251115ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/testrepo/.gitted/refs/tags/foo/bar000066400000000000000000000000511216214232500255740ustar00rootroot00000000000000b25fa35b38051e4ae45d4222e795f9df2e43f1d1 libgit2-0.19.0/tests-clar/resources/testrepo/.gitted/refs/tags/foo/foo/000077500000000000000000000000001216214232500256745ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/testrepo/.gitted/refs/tags/foo/foo/bar000066400000000000000000000000511216214232500263570ustar00rootroot00000000000000b25fa35b38051e4ae45d4222e795f9df2e43f1d1 libgit2-0.19.0/tests-clar/resources/testrepo/.gitted/refs/tags/point_to_blob000066400000000000000000000000511216214232500270760ustar00rootroot000000000000001385f264afb75a56a5bec74243be9b367ba4ca08 libgit2-0.19.0/tests-clar/resources/testrepo/.gitted/refs/tags/test000066400000000000000000000000511216214232500252240ustar00rootroot00000000000000b25fa35b38051e4ae45d4222e795f9df2e43f1d1 libgit2-0.19.0/tests-clar/resources/testrepo2/000077500000000000000000000000001216214232500211555ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/testrepo2/.gitted/000077500000000000000000000000001216214232500225135ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/testrepo2/.gitted/HEAD000066400000000000000000000000271216214232500231360ustar00rootroot00000000000000ref: refs/heads/master libgit2-0.19.0/tests-clar/resources/testrepo2/.gitted/config000066400000000000000000000005021216214232500237000ustar00rootroot00000000000000[core] repositoryformatversion = 0 filemode = true bare = false logallrefupdates = true ignorecase = true precomposeunicode = false [remote "origin"] url = https://github.com/libgit2/false.git fetch = +refs/heads/*:refs/remotes/origin/* [branch "master"] remote = origin merge = refs/heads/master rebase = true libgit2-0.19.0/tests-clar/resources/testrepo2/.gitted/description000066400000000000000000000001111216214232500247520ustar00rootroot00000000000000Unnamed repository; edit this file 'description' to name the repository. libgit2-0.19.0/tests-clar/resources/testrepo2/.gitted/index000066400000000000000000000010001216214232500235340ustar00rootroot00000000000000DIRCQDQD JdZVBC6{READMEQDQD J Iw#XpP_tgnew.txtQDQD JdZVBC6{ subdir/READMEQDQD J Iw#XpP_tgsubdir/new.txtQDQD JdZVBC6{subdir/subdir2/READMEQDQD J Iw#XpP_tgsubdir/subdir2/new.txt`{0<=4Clibgit2-0.19.0/tests-clar/resources/testrepo2/.gitted/info/000077500000000000000000000000001216214232500234465ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/testrepo2/.gitted/info/exclude000066400000000000000000000003601216214232500250210ustar00rootroot00000000000000# git ls-files --others --exclude-from=.git/info/exclude # Lines that start with '#' are comments. # For a project mostly in C, the following would be a good set of # exclude patterns (uncomment them if you want to use them): # *.[oa] # *~ libgit2-0.19.0/tests-clar/resources/testrepo2/.gitted/logs/000077500000000000000000000000001216214232500234575ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/testrepo2/.gitted/logs/HEAD000066400000000000000000000003441216214232500241040ustar00rootroot000000000000000000000000000000000000000000000000000000 36060c58702ed4c2a40832c51758d5344201d89a Russell Belfer 1368278260 -0700 clone: from /Users/rb/src/libgit2/tests-clar/resources/../../../rugged/test/fixtures/testrepo.git libgit2-0.19.0/tests-clar/resources/testrepo2/.gitted/logs/refs/000077500000000000000000000000001216214232500244165ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/testrepo2/.gitted/logs/refs/heads/000077500000000000000000000000001216214232500255025ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/testrepo2/.gitted/logs/refs/heads/master000066400000000000000000000003441216214232500267210ustar00rootroot000000000000000000000000000000000000000000000000000000 36060c58702ed4c2a40832c51758d5344201d89a Russell Belfer 1368278260 -0700 clone: from /Users/rb/src/libgit2/tests-clar/resources/../../../rugged/test/fixtures/testrepo.git libgit2-0.19.0/tests-clar/resources/testrepo2/.gitted/logs/refs/remotes/000077500000000000000000000000001216214232500260745ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/testrepo2/.gitted/logs/refs/remotes/origin/000077500000000000000000000000001216214232500273635ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/testrepo2/.gitted/logs/refs/remotes/origin/HEAD000066400000000000000000000003441216214232500300100ustar00rootroot000000000000000000000000000000000000000000000000000000 36060c58702ed4c2a40832c51758d5344201d89a Russell Belfer 1368278260 -0700 clone: from /Users/rb/src/libgit2/tests-clar/resources/../../../rugged/test/fixtures/testrepo.git libgit2-0.19.0/tests-clar/resources/testrepo2/.gitted/objects/000077500000000000000000000000001216214232500241445ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/testrepo2/.gitted/objects/0c/000077500000000000000000000000001216214232500244465ustar00rootroot0000000000000037a5391bbff43c37f0d0371823a5509eed5b1d000066400000000000000000000002061216214232500315100ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/testrepo2/.gitted/objects/0cxA 0=KݖD vC+0 P呢(X?"V(;ÄDd%U vpUwrɅГ38shhj 8'-libgit2-0.19.0/tests-clar/resources/testrepo2/.gitted/objects/13/000077500000000000000000000000001216214232500243675ustar00rootroot0000000000000085f264afb75a56a5bec74243be9b367ba4ca08000066400000000000000000000000231216214232500315760ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/testrepo2/.gitted/objects/13xKOR0aHSDlibgit2-0.19.0/tests-clar/resources/testrepo2/.gitted/objects/18/000077500000000000000000000000001216214232500243745ustar00rootroot000000000000001037049a54a1eb5fab404658a3a250b44335d7000066400000000000000000000000631216214232500311760ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/testrepo2/.gitted/objects/18x+)JMU06a040031Qrutuen~{T}ǝ6^rqh10dff58d8a660512d4832e740f692884338ccd000066400000000000000000000001671216214232500312520ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/testrepo2/.gitted/objects/18x+)JMU044b040031QrutueXlmmAṃJ}G;UTWRQຳyv;slzC8Ti^j9XrѶ_,ٟ#4'^A0ulibgit2-0.19.0/tests-clar/resources/testrepo2/.gitted/objects/2d/000077500000000000000000000000001216214232500244515ustar00rootroot000000000000002eff63372b08adf0a9eb84109ccf7d19e2f3a2000066400000000000000000000001751216214232500317470ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/testrepo2/.gitted/objects/2dx[ 0)t7AD<&m4Ьxo0պ('D%g1Z'v3Y >1m&BhsQ*3µܧ\Z"b9xWUPwd=5libgit2-0.19.0/tests-clar/resources/testrepo2/.gitted/objects/36/000077500000000000000000000000001216214232500243745ustar00rootroot00000000000000060c58702ed4c2a40832c51758d5344201d89a000066400000000000000000000002421216214232500310520ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/testrepo2/.gitted/objects/36xQ 0)reݴ $ۭ-F-00𸖲?iL#HSS#q2D據jC|HSL8$)a#2i׹6js?JZftΞUiͶqiZ"_/H6libgit2-0.19.0/tests-clar/resources/testrepo2/.gitted/objects/45/000077500000000000000000000000001216214232500243745ustar00rootroot00000000000000b983be36b73c0788dc9cbcb76cbb80fc7bb057000066400000000000000000000000221216214232500317530ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/testrepo2/.gitted/objects/45xKOR0flibgit2-0.19.0/tests-clar/resources/testrepo2/.gitted/objects/4a/000077500000000000000000000000001216214232500244505ustar00rootroot00000000000000202b346bb0fb0db7eff3cffeb3c70babbd2045000066400000000000000000000002401216214232500322000ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/testrepo2/.gitted/objects/4axQ 0D)6ͦ "xO-FbEo0 Ǥ,ske[Pn8R,EpD?g}^3 <GhYK8ЖDA);gݧjp4-r;sGA4ۺ=(in7IKFElibgit2-0.19.0/tests-clar/resources/testrepo2/.gitted/objects/5b/000077500000000000000000000000001216214232500244525ustar00rootroot000000000000005b025afb0b4c913b4c338a42934a3863bf3644000066400000000000000000000002361216214232500313470ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/testrepo2/.gitted/objects/5bx 1ENi@k2 "X$YW0YcÅszMD08!s Xgd::@X0Pw"F/RUzmZZV}|/o5I!1z:vUim}/> F-libgit2-0.19.0/tests-clar/resources/testrepo2/.gitted/objects/61/000077500000000000000000000000001216214232500243725ustar00rootroot000000000000009f9935957e010c419cb9d15621916ddfcc0b96000066400000000000000000000001641216214232500313310ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/testrepo2/.gitted/objects/61x+)JMU040f040031Qrutuen~{T}ǝ6^r"/\F0|Z_8]n(&d1|cdN4U3tN<抋͸*libgit2-0.19.0/tests-clar/resources/testrepo2/.gitted/objects/75/000077500000000000000000000000001216214232500243775ustar00rootroot00000000000000057dd4114e74cca1d750d0aee1647c903cb60a000066400000000000000000000001671216214232500315100ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/testrepo2/.gitted/objects/75x+)JMU044b040031Qrutuen~{T}ǝ6^r"(1/9#>-3'Uug>6wٞOpҼr_ʧ+O\\iy|tI/libgit2-0.19.0/tests-clar/resources/testrepo2/.gitted/objects/7f/000077500000000000000000000000001216214232500244605ustar00rootroot00000000000000043268ea43ce18e3540acaabf9e090c91965b0000066400000000000000000000000671216214232500315240ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/testrepo2/.gitted/objects/7fx+)JMU0`040031Qrutu+(an~{T}ǝ6^rQlibgit2-0.19.0/tests-clar/resources/testrepo2/.gitted/objects/81/000077500000000000000000000000001216214232500243745ustar00rootroot000000000000004889a078c031f61ed08ab5fa863aea9314344d000066400000000000000000000001221216214232500313630ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/testrepo2/.gitted/objects/81x+)JMU0d040031QrutueXlmmAṃJ}G;UZWRQ°\erw solibgit2-0.19.0/tests-clar/resources/testrepo2/.gitted/objects/84/000077500000000000000000000000001216214232500243775ustar00rootroot0000000000000096071c1b46c854b31185ea97743be6a8774479000066400000000000000000000001761216214232500311250ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/testrepo2/.gitted/objects/84x 1Nۀn` V.`.pa Ô{StlH,_9$$cf&hXQ*g)cV~p~"Q@JnZuӶL 6libgit2-0.19.0/tests-clar/resources/testrepo2/.gitted/objects/9f/000077500000000000000000000000001216214232500244625ustar00rootroot00000000000000d738e8f7967c078dceed8190330fc8648ee56a000066400000000000000000000002401216214232500315770ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/testrepo2/.gitted/objects/9fx[ 0E*fդ "W0-Ft݁pS[Yx^ Db CLhut}8X*4ZsYUA X3RM) s6輢Mរ&Jm;}<\@ޏpĀv?jۺL?Hlibgit2-0.19.0/tests-clar/resources/testrepo2/.gitted/objects/a4/000077500000000000000000000000001216214232500244505ustar00rootroot00000000000000a7dce85cf63874e984719f4fdd239f5145052f000066400000000000000000000003101216214232500314760ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/testrepo2/.gitted/objects/a4x;j1Dmdǎ|M3`V{ >QvL0I?!4Z=!צ8F!rsQy9]$D&l6A>jFWҵ IKNiZ%S  U~̽>' w [ DGڡQ-M>dO}\8g_ШoYrlibgit2-0.19.0/tests-clar/resources/testrepo2/.gitted/objects/a7/000077500000000000000000000000001216214232500244535ustar00rootroot000000000000001586c1dfe8a71c6cbf6c129f404c5642ff31bd000066400000000000000000000000341216214232500316640ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/testrepo2/.gitted/objects/a7xKOR04bȭTK-WHIA=libgit2-0.19.0/tests-clar/resources/testrepo2/.gitted/objects/a8/000077500000000000000000000000001216214232500244545ustar00rootroot00000000000000233120f6ad708f843d861ce2b7228ec4e3dec6000066400000000000000000000000321216214232500315220ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/testrepo2/.gitted/objects/a8xKOR04`HT(H-J6libgit2-0.19.0/tests-clar/resources/testrepo2/.gitted/objects/be/000077500000000000000000000000001216214232500245325ustar00rootroot000000000000003563ae3f795b2b4353bcce3a527ad0a4f7f644000066400000000000000000000003021216214232500316540ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/testrepo2/.gitted/objects/bexKj1D)zUB-0uV9<#+W-/y.7 libgit2-0.19.0/tests-clar/resources/testrepo2/.gitted/objects/pack/000077500000000000000000000000001216214232500250625ustar00rootroot00000000000000pack-d7c6adf9f61318f041845b01440d09aa7a91e1b5.idx000066400000000000000000000023301216214232500337700ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/testrepo2/.gitted/objects/packtOcA3ػGAi[l\of̌ŴnP) 4$ŀuuO|?-Y 21]iazošIn* 0ؒ!ZqSڥ : @0HD:3 w&Ⱦܠhq$neSՐ;dڧ/pack-d7c6adf9f61318f041845b01440d09aa7a91e1b5.pack000066400000000000000000000007531216214232500341310ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/testrepo2/.gitted/objects/packPACKx] 0sk6 "xOnh+^ߢ7e>Ur;jes6dϝyUh]&A\jf${SbJ4c[McreG.bvFIUn/&~w3:Dc x[ 1 {\@K#x&ME5_7 *9`T*!5)inHMvHA˦…cÓp:߷<B,i| 6x>fOo{8x340031QH/H-+(aje+kt5eũy)`UoVc&'zhִu=ٱxL-QH/H-RHI:.;x+H,QHIx340031QH/H-+(aje+kt5V ?Ⱦܠhq$nelibgit2-0.19.0/tests-clar/resources/testrepo2/.gitted/packed-refs000066400000000000000000000005111216214232500246170ustar00rootroot00000000000000# pack-refs with: peeled fully-peeled 36060c58702ed4c2a40832c51758d5344201d89a refs/remotes/origin/master 41bc8c69075bbdb46c5c6f0566cc8cc5b46e8bd9 refs/remotes/origin/packed 5b5b025afb0b4c913b4c338a42934a3863bf3644 refs/tags/v0.9 0c37a5391bbff43c37f0d0371823a5509eed5b1d refs/tags/v1.0 ^5b5b025afb0b4c913b4c338a42934a3863bf3644 libgit2-0.19.0/tests-clar/resources/testrepo2/.gitted/refs/000077500000000000000000000000001216214232500234525ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/testrepo2/.gitted/refs/heads/000077500000000000000000000000001216214232500245365ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/testrepo2/.gitted/refs/heads/master000066400000000000000000000000511216214232500257500ustar00rootroot0000000000000036060c58702ed4c2a40832c51758d5344201d89a libgit2-0.19.0/tests-clar/resources/testrepo2/.gitted/refs/remotes/000077500000000000000000000000001216214232500251305ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/testrepo2/.gitted/refs/remotes/origin/000077500000000000000000000000001216214232500264175ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/testrepo2/.gitted/refs/remotes/origin/HEAD000066400000000000000000000000401216214232500270350ustar00rootroot00000000000000ref: refs/remotes/origin/master libgit2-0.19.0/tests-clar/resources/testrepo2/README000066400000000000000000000000041216214232500220270ustar00rootroot00000000000000hey libgit2-0.19.0/tests-clar/resources/testrepo2/new.txt000066400000000000000000000000111216214232500224770ustar00rootroot00000000000000new file libgit2-0.19.0/tests-clar/resources/testrepo2/subdir/000077500000000000000000000000001216214232500224455ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/testrepo2/subdir/README000066400000000000000000000000041216214232500233170ustar00rootroot00000000000000hey libgit2-0.19.0/tests-clar/resources/testrepo2/subdir/new.txt000066400000000000000000000000111216214232500237670ustar00rootroot00000000000000new file libgit2-0.19.0/tests-clar/resources/testrepo2/subdir/subdir2/000077500000000000000000000000001216214232500240175ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/testrepo2/subdir/subdir2/README000066400000000000000000000000041216214232500246710ustar00rootroot00000000000000hey libgit2-0.19.0/tests-clar/resources/testrepo2/subdir/subdir2/new.txt000066400000000000000000000000111216214232500253410ustar00rootroot00000000000000new file libgit2-0.19.0/tests-clar/resources/twowaymerge.git/000077500000000000000000000000001216214232500223625ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/twowaymerge.git/HEAD000066400000000000000000000000271216214232500230050ustar00rootroot00000000000000ref: refs/heads/master libgit2-0.19.0/tests-clar/resources/twowaymerge.git/config000066400000000000000000000001251216214232500235500ustar00rootroot00000000000000[core] repositoryformatversion = 0 filemode = true bare = true ignorecase = true libgit2-0.19.0/tests-clar/resources/twowaymerge.git/description000066400000000000000000000001111216214232500246210ustar00rootroot00000000000000Unnamed repository; edit this file 'description' to name the repository. libgit2-0.19.0/tests-clar/resources/twowaymerge.git/info/000077500000000000000000000000001216214232500233155ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/twowaymerge.git/info/exclude000066400000000000000000000003601216214232500246700ustar00rootroot00000000000000# git ls-files --others --exclude-from=.git/info/exclude # Lines that start with '#' are comments. # For a project mostly in C, the following would be a good set of # exclude patterns (uncomment them if you want to use them): # *.[oa] # *~ libgit2-0.19.0/tests-clar/resources/twowaymerge.git/objects/000077500000000000000000000000001216214232500240135ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/twowaymerge.git/objects/0c/000077500000000000000000000000001216214232500243155ustar00rootroot000000000000008a3f1f3d5f421cf83048c7c73ee3b55a5e0f29000066400000000000000000000002351216214232500314560ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/twowaymerge.git/objects/0cxK 0]4w[OoFjz0@ć LIQqQ钳F$ۯy 8ULkefdǔkD#=6R >?.ӣ[bgJ3-Elibgit2-0.19.0/tests-clar/resources/twowaymerge.git/objects/10/000077500000000000000000000000001216214232500242335ustar00rootroot000000000000002dce8e3081f398e4bdd9fd894dc85ac3ca6a67000066400000000000000000000000661216214232500316370ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/twowaymerge.git/objects/10x+)JMU0g040031QHdx6M9{wk+qIODd6>+}libgit2-0.19.0/tests-clar/resources/twowaymerge.git/objects/17/000077500000000000000000000000001216214232500242425ustar00rootroot000000000000007d8634a28e26ec7819284752757ebe01a479d5000066400000000000000000000001201216214232500310410ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/twowaymerge.git/objects/17x+)JMU06d040031QHdx6M9{wk+qIODd>4|$3If'O2d.><EClibgit2-0.19.0/tests-clar/resources/twowaymerge.git/objects/1c/000077500000000000000000000000001216214232500243165ustar00rootroot0000000000000030b88f5f3ee66d78df6520a7de9e89b890818b000066400000000000000000000002371216214232500314420ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/twowaymerge.git/objects/1cxM 0F]s zIi^{<>TKy4`6 ,y9jGJ8b\f5/ ^8v'˜`SƝ%[ T[[,psL6oK5;n-=Dlibgit2-0.19.0/tests-clar/resources/twowaymerge.git/objects/1f/000077500000000000000000000000001216214232500243215ustar00rootroot000000000000004c0311a24b63f6fc209a59a1e404942d4a5006000066400000000000000000000002001216214232500311130ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/twowaymerge.git/objects/1fx=0 @aM6BlH m!RqO7[ r5gNXű)Eg]DY2c R8x7 TRo8~Ӣ[#uj;`7libgit2-0.19.0/tests-clar/resources/twowaymerge.git/objects/22/000077500000000000000000000000001216214232500242365ustar00rootroot0000000000000024e191514cb4bd8c566d80dac22dfcb1e9bb83000066400000000000000000000002361216214232500315220ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/twowaymerge.git/objects/22xK 0@]sK& z4HMobY1t[JblɈ4vɡL '՛V`B . Im 1ZǠxcKh^^+\>?2a.M,tTBp^kucjV_sFhlibgit2-0.19.0/tests-clar/resources/twowaymerge.git/objects/29/000077500000000000000000000000001216214232500242455ustar00rootroot000000000000006e56023cdc034d2735fee8c0d85a659d1b07f4000066400000000000000000000000631216214232500313210ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/twowaymerge.git/objects/29x+)JMU0`040031QHdx6M9{wk+qIODdVI{libgit2-0.19.0/tests-clar/resources/twowaymerge.git/objects/31/000077500000000000000000000000001216214232500242365ustar00rootroot0000000000000051880ae2b363f1c262cf98b750c1f169a0d432000066400000000000000000000001041216214232500311340ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/twowaymerge.git/objects/31x+)JMU020f040031QHdx6M9{wk+qIODd>d|)$SIL* lblibgit2-0.19.0/tests-clar/resources/twowaymerge.git/objects/3b/000077500000000000000000000000001216214232500243175ustar00rootroot00000000000000287f8730c81d0b763c2d294618a5e32b67b4f8000066400000000000000000000000661216214232500311710ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/twowaymerge.git/objects/3bx+)JMU0g040031QHdx6M9{wk+qIODd>4^+nlibgit2-0.19.0/tests-clar/resources/twowaymerge.git/objects/42/000077500000000000000000000000001216214232500242405ustar00rootroot00000000000000b7311aa626e712891940c1ec5d5cba201946a4000066400000000000000000000002361216214232500311330ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/twowaymerge.git/objects/42xν 0@ajOq c"!DDK1 h_ZʣAC[saȞpI#lBq׼4Z"(yGFd#y[ X[[J/psL6oAXሂo7ԸEclibgit2-0.19.0/tests-clar/resources/twowaymerge.git/objects/49/000077500000000000000000000000001216214232500242475ustar00rootroot000000000000006d6428b9cf92981dc9495211e6e1120fb6f2ba000066400000000000000000000000561216214232500312550ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/twowaymerge.git/objects/49x+)JMU0d040031QHdx6M9{wk+qIODlibgit2-0.19.0/tests-clar/resources/twowaymerge.git/objects/59/000077500000000000000000000000001216214232500242505ustar00rootroot00000000000000b0cf7d74659e1cdb13305319d6d4ce2733c118000066400000000000000000000001011216214232500312260ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/twowaymerge.git/objects/59x+)JMU047a040031QHdx6M9{wk+qIODd>4|$3Ifb*Tlibgit2-0.19.0/tests-clar/resources/twowaymerge.git/objects/6a/000077500000000000000000000000001216214232500243215ustar00rootroot00000000000000b5d28acbf3c3bdff276f7ccfdf29c1520e542f000066400000000000000000000002361216214232500320370ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/twowaymerge.git/objects/6axM0@a=\@2cܙeRܾŗǵRԶ@(i$uO 19Ro" 9x- @cc3;-KvH+9Fe{O{]b +\>oܦ}踖+Hm z(zl7 F-libgit2-0.19.0/tests-clar/resources/twowaymerge.git/objects/6c/000077500000000000000000000000001216214232500243235ustar00rootroot00000000000000fca542b55b8b37017e6125a4b8f59a6eae6f11000066400000000000000000000001041216214232500314460ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/twowaymerge.git/objects/6cx+)JMU020f040031QHdx6M9{wk+qIODd>4|$3If* qblibgit2-0.19.0/tests-clar/resources/twowaymerge.git/objects/76/000077500000000000000000000000001216214232500242475ustar00rootroot000000000000005b32c65d38f04c4f287abda055818ec0f26912000066400000000000000000000000661216214232500312420ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/twowaymerge.git/objects/76x+)JMU0g040031QHdx6M9{wk+qIODd>d+klibgit2-0.19.0/tests-clar/resources/twowaymerge.git/objects/7b/000077500000000000000000000000001216214232500243235ustar00rootroot000000000000008c336c45fc6895c1c60827260fe5d798e5d247000066400000000000000000000002371216214232500312150ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/twowaymerge.git/objects/7bxA @Qלb.`3 S(1LzB[TzܾϏe D|kJC3fȵu L>YGMVeMK9Z5H#{EJ: ϲp:ne>6-sH GծfMS}ZElibgit2-0.19.0/tests-clar/resources/twowaymerge.git/objects/82/000077500000000000000000000000001216214232500242445ustar00rootroot00000000000000bf9a1a10a4b25c1f14c9607b60970705e92545000066400000000000000000000002361216214232500310650ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/twowaymerge.git/objects/82x 09mh_BܐRןc1-pyPKy4RږDGFJvFE>1#q joimbvSYSbErQ"e{+ޖ=6b+>?/-;3hC#gXyFlibgit2-0.19.0/tests-clar/resources/twowaymerge.git/objects/8b/000077500000000000000000000000001216214232500243245ustar00rootroot0000000000000082fb1794cb1c8c7f172ec730a4c2db0ae3e650000066400000000000000000000002351216214232500315240ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/twowaymerge.git/objects/8bxν 0@ajOq 7BtHLp%A8FٟW<= x"ʎ$%1dcDNL:Yv=7yic l$\b{DbOd9x+ 6T[{ ??yqnӖ:cQZ]͖7Hlibgit2-0.19.0/tests-clar/resources/twowaymerge.git/objects/9a/000077500000000000000000000000001216214232500243245ustar00rootroot0000000000000040a2f11c191f180c47e54b11567cb3c1e89b30000066400000000000000000000000761216214232500312170ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/twowaymerge.git/objects/9ax+)JMU041e040031QHdx6M9{wk+qIODd6>|$JqG1libgit2-0.19.0/tests-clar/resources/twowaymerge.git/objects/9b/000077500000000000000000000000001216214232500243255ustar00rootroot00000000000000219343610c88a1187c996d0dc58330b55cee28000066400000000000000000000003271216214232500311100ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/twowaymerge.git/objects/9bxKj1ЬFj}Z3 VdFA#?\ zu]FSo"J& ^,9$GEd)7|&[6(FU"&h< Fc4Aƿ>"ZQ;m9\;KP%1b9k93Gkwni[uZ h"RYC[]=0IrKpO: pʯ _(clibgit2-0.19.0/tests-clar/resources/twowaymerge.git/objects/9f/000077500000000000000000000000001216214232500243315ustar00rootroot00000000000000e06a50f4d1634d6c6879854d01d80857388706000066400000000000000000000001011216214232500307620ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/twowaymerge.git/objects/9fx+)JMU047a040031QHdx6M9{wk+qIODd>d|)$Ic'9Tlibgit2-0.19.0/tests-clar/resources/twowaymerge.git/objects/a4/000077500000000000000000000000001216214232500243175ustar00rootroot000000000000001a49f8f5cd9b6cb14a076bf8394881ed0b4d19000066400000000000000000000002361216214232500314710ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/twowaymerge.git/objects/a4xν 0@ajOq 7'!DD A$FٟW<=<5Z 8N(CzDž$'2!>[):#Dzǵ, z M d=tNŭ= wk}9.p9^Ʃ=I@Y =ulDlibgit2-0.19.0/tests-clar/resources/twowaymerge.git/objects/a9/000077500000000000000000000000001216214232500243245ustar00rootroot0000000000000053a018c5b10b20c86e69fef55ebc8ad4c5a417000066400000000000000000000003161216214232500315300ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/twowaymerge.git/objects/a9xJ0])nV3$is"ONŶɼ\|8!dz dXG/ޫϹp*CX@Z8|f[V0HDHE]6gI#g*9UEHH!MḦhRuo.{zSײ|үwȾ>14C8;rn8qۿ7kNui~M^cce3cd1b3efbda5b1f4a6dcc3f1570b2d3d74c000066400000000000000000000000721216214232500321510ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/twowaymerge.git/objects/a9x+)JMU044c040031QHdx6M9{wk+qIODd6>|X%>9jlibgit2-0.19.0/tests-clar/resources/twowaymerge.git/objects/bd/000077500000000000000000000000001216214232500244005ustar00rootroot000000000000001732c43c68d712ad09e1d872b9be6d4b9efdc4000066400000000000000000000002361216214232500316240ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/twowaymerge.git/objects/bdxA0=ɶۥkb7,-`,uy*8uM B9m'g'!v}DfkO֙w\RU"e,^4hcvdVDzCKpoV^8~9\[h/`=Ihvow5_Elibgit2-0.19.0/tests-clar/resources/twowaymerge.git/objects/c3/000077500000000000000000000000001216214232500243205ustar00rootroot000000000000007a783c20d92ac92362a78a32860f7eebf938ef000066400000000000000000000002361216214232500314160ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/twowaymerge.git/objects/c3xM0@a=\@2$Ƹ3q aP~'eB<&; u4PDgвd';T9!w^2I ;L^l16I[ w)­kysZs:m2\ȌoV;`:)Elibgit2-0.19.0/tests-clar/resources/twowaymerge.git/objects/cb/000077500000000000000000000000001216214232500243775ustar00rootroot00000000000000dd40facab1682754eb67f7a43f29e672903cf6000066400000000000000000000000631216214232500315440ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/twowaymerge.git/objects/cbx+)JMU0`040031QHdx6M9{wk+qIODd6VI|libgit2-0.19.0/tests-clar/resources/twowaymerge.git/objects/cd/000077500000000000000000000000001216214232500244015ustar00rootroot00000000000000f97fd3bb48eb3827638bb33d208f5fd32d0aa6000066400000000000000000000002361216214232500316220ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/twowaymerge.git/objects/cdxA = dib7`YF/x&õ1VHqb$Ao ,3^]CQoZei YhN jbL9N֦ƒkkpV_<8irޞFZMQ}H$libgit2-0.19.0/tests-clar/resources/twowaymerge.git/objects/d6/000077500000000000000000000000001216214232500243245ustar00rootroot00000000000000f10d549cb335b9e6d38afc1f0088be69b50494000066400000000000000000000000761216214232500314130ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/twowaymerge.git/objects/d6x+)JMU041e040031QHdx6M9{wk+qIODd>4|$3JjwGlibgit2-0.19.0/tests-clar/resources/twowaymerge.git/objects/d9/000077500000000000000000000000001216214232500243275ustar00rootroot00000000000000acdc7ae7632adfeec67fa73c1e343cf4d1f47e000066400000000000000000000000721216214232500321240ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/twowaymerge.git/objects/d9x+)JMU044c040031QHdx6M9{wk+qIODd>4|X%:79Ulibgit2-0.19.0/tests-clar/resources/twowaymerge.git/objects/e6/000077500000000000000000000000001216214232500243255ustar00rootroot000000000000009de29bb2d1d6434b8b29ae775ad8c2e48c5391000066400000000000000000000000171216214232500314730ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/twowaymerge.git/objects/e6xKOR0` libgit2-0.19.0/tests-clar/resources/twowaymerge.git/objects/ef/000077500000000000000000000000001216214232500244055ustar00rootroot000000000000000488f0b722f0be8bcb90a7730ac7efafd1d694000066400000000000000000000002371216214232500317010ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/twowaymerge.git/objects/efxM F]s0_cܙ@H1_ۗ}yh@mK 8Y4Ѩt^'`lPىڠd|i$ӱJi>Glibgit2-0.19.0/tests-clar/resources/twowaymerge.git/refs/000077500000000000000000000000001216214232500233215ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/twowaymerge.git/refs/heads/000077500000000000000000000000001216214232500244055ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/twowaymerge.git/refs/heads/first-branch000066400000000000000000000000511216214232500267060ustar00rootroot000000000000002224e191514cb4bd8c566d80dac22dfcb1e9bb83 libgit2-0.19.0/tests-clar/resources/twowaymerge.git/refs/heads/master000066400000000000000000000000511216214232500256170ustar00rootroot000000000000001c30b88f5f3ee66d78df6520a7de9e89b890818b libgit2-0.19.0/tests-clar/resources/twowaymerge.git/refs/heads/second-branch000066400000000000000000000000511216214232500270320ustar00rootroot000000000000009b219343610c88a1187c996d0dc58330b55cee28 libgit2-0.19.0/tests-clar/resources/typechanges/000077500000000000000000000000001216214232500215405ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/typechanges/.gitted/000077500000000000000000000000001216214232500230765ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/typechanges/.gitted/HEAD000066400000000000000000000000271216214232500235210ustar00rootroot00000000000000ref: refs/heads/master libgit2-0.19.0/tests-clar/resources/typechanges/.gitted/config000066400000000000000000000005611216214232500242700ustar00rootroot00000000000000[core] repositoryformatversion = 0 filemode = true bare = false logallrefupdates = true ignorecase = true [submodule "e"] url = /Users/rb/src/libgit2/tests-clar/resources/submod2_target/.git [submodule "d"] url = /Users/rb/src/libgit2/tests-clar/resources/submod2_target/.git [submodule "b"] url = /Users/rb/src/libgit2/tests-clar/resources/submod2_target/.git libgit2-0.19.0/tests-clar/resources/typechanges/.gitted/description000066400000000000000000000001111216214232500253350ustar00rootroot00000000000000Unnamed repository; edit this file 'description' to name the repository. libgit2-0.19.0/tests-clar/resources/typechanges/.gitted/index000066400000000000000000000002701216214232500241270ustar00rootroot00000000000000DIRCPlPlW$⛲CK)wZS .gitmodulesPksPksW躹 AP+ README.mdQ@pʆI|libgit2-0.19.0/tests-clar/resources/typechanges/.gitted/info/000077500000000000000000000000001216214232500240315ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/typechanges/.gitted/info/exclude000066400000000000000000000003601216214232500254040ustar00rootroot00000000000000# git ls-files --others --exclude-from=.git/info/exclude # Lines that start with '#' are comments. # For a project mostly in C, the following would be a good set of # exclude patterns (uncomment them if you want to use them): # *.[oa] # *~ libgit2-0.19.0/tests-clar/resources/typechanges/.gitted/modules/000077500000000000000000000000001216214232500245465ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/typechanges/.gitted/modules/b/000077500000000000000000000000001216214232500247675ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/typechanges/.gitted/modules/b/HEAD000066400000000000000000000000271216214232500254120ustar00rootroot00000000000000ref: refs/heads/master libgit2-0.19.0/tests-clar/resources/typechanges/.gitted/modules/b/config000066400000000000000000000005111216214232500261540ustar00rootroot00000000000000[core] repositoryformatversion = 0 filemode = true bare = false logallrefupdates = true worktree = ../../../b ignorecase = true [remote "origin"] fetch = +refs/heads/*:refs/remotes/origin/* url = /Users/rb/src/libgit2/tests-clar/resources/submod2_target/.git [branch "master"] remote = origin merge = refs/heads/master libgit2-0.19.0/tests-clar/resources/typechanges/.gitted/modules/b/description000066400000000000000000000001111216214232500272260ustar00rootroot00000000000000Unnamed repository; edit this file 'description' to name the repository. libgit2-0.19.0/tests-clar/resources/typechanges/.gitted/modules/b/index000066400000000000000000000003001216214232500260120ustar00rootroot00000000000000DIRCPkpPkpWjx swU:K-J README.txtPkpPkpWixڤwE8TUKfile_to_modifyŋ:7K;qCWlibgit2-0.19.0/tests-clar/resources/typechanges/.gitted/modules/b/info/000077500000000000000000000000001216214232500257225ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/typechanges/.gitted/modules/b/info/exclude000066400000000000000000000003601216214232500272750ustar00rootroot00000000000000# git ls-files --others --exclude-from=.git/info/exclude # Lines that start with '#' are comments. # For a project mostly in C, the following would be a good set of # exclude patterns (uncomment them if you want to use them): # *.[oa] # *~ libgit2-0.19.0/tests-clar/resources/typechanges/.gitted/modules/b/objects/000077500000000000000000000000001216214232500264205ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/typechanges/.gitted/modules/b/objects/06/000077500000000000000000000000001216214232500266455ustar00rootroot00000000000000362fe2fdb7010d0e447b4fb450d405420479a1000066400000000000000000000000671216214232500335370ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/typechanges/.gitted/modules/b/objects/06x+)JMU0`040031Qrutu+(a-ŏ/C:sH[ blibgit2-0.19.0/tests-clar/resources/typechanges/.gitted/modules/b/objects/0e/000077500000000000000000000000001216214232500267245ustar00rootroot000000000000006a3ca48bd47cfe67681acf39aa0b10a0b92484000066400000000000000000000000651216214232500341260ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/typechanges/.gitted/modules/b/objects/0exKOR01`,VD̜T|̴J<$ 4' libgit2-0.19.0/tests-clar/resources/typechanges/.gitted/modules/b/objects/17/000077500000000000000000000000001216214232500266475ustar00rootroot00000000000000d0ece6e96460a06592d9d9d000de37ba4232c5000066400000000000000000000001351216214232500337140ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/typechanges/.gitted/modules/b/objects/17x+)JMU0`040031Qrutu+(a-ŏ/C:sH[ *-3'5$?>7?%3/fIR-Wq ,ة!libgit2-0.19.0/tests-clar/resources/typechanges/.gitted/modules/b/objects/41/000077500000000000000000000000001216214232500266445ustar00rootroot00000000000000bd4bc3df978de695f67ace64c560913da11653000066400000000000000000000002431216214232500340150ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/typechanges/.gitted/modules/b/objects/41x 0vh}K%ЁR8=͓u+CZD@%z1hrl b5Lꛊl|o57:anОщvQT:!oY)p/st7h Q QզTm*Ga^DFlibgit2-0.19.0/tests-clar/resources/typechanges/.gitted/modules/b/objects/48/000077500000000000000000000000001216214232500266535ustar00rootroot000000000000000095882d281ed676fe5b863569520e54a7d5c0000066400000000000000000000002431216214232500334500ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/typechanges/.gitted/modules/b/objects/48x[ >@QG(tˤ $NJ(e.212K${Ml-%E* Y]uk"IT&k,IC}J!pi9^\^;錷 (D"pNJuo)+C*ùXBElibgit2-0.19.0/tests-clar/resources/typechanges/.gitted/modules/b/objects/5e/000077500000000000000000000000001216214232500267315ustar00rootroot000000000000004963595a9774b90524d35a807169049de8ccad000066400000000000000000000002471216214232500335370ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/typechanges/.gitted/modules/b/objects/5ex[j0SRUȻ`A^߿Bu6|P# 2D:]Uk˽m IIz-WQة4VʌkHB Lw]1>y[ k_w'=T[߷4_0 Hlibgit2-0.19.0/tests-clar/resources/typechanges/.gitted/modules/b/objects/6b/000077500000000000000000000000001216214232500267275ustar00rootroot0000000000000031c659545507c381e9cd34ec508f16c04e149e000066400000000000000000000002031216214232500335660ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/typechanges/.gitted/modules/b/objects/6bxQ !Evoy*_@g#hOh^9wSòf1*[Ic Ԥpk Α\S߇l@.^QpF(:D5zr~ en8libgit2-0.19.0/tests-clar/resources/typechanges/.gitted/modules/b/objects/73/000077500000000000000000000000001216214232500266515ustar00rootroot00000000000000ba924a80437097795ae839e66e187c55d3babf000066400000000000000000000001351216214232500336700ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/typechanges/.gitted/modules/b/objects/73x+)JMU0`040031Qrutu+(a-ŏ/C:sH[ *-3'5$?>7?%3b[,m*um:oLo#libgit2-0.19.0/tests-clar/resources/typechanges/.gitted/modules/b/objects/78/000077500000000000000000000000001216214232500266565ustar00rootroot000000000000000d7397f5e8f8f477fb55b7af3accc2154b2d4a000066400000000000000000000001521216214232500341630ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/typechanges/.gitted/modules/b/objects/78x-10 Fa0p(N-ӡғq]>ks*? |m“i@mV'`).-1 x uxt(+9efbdadaa4a582778d4584385495559ea0994b000066400000000000000000000001471216214232500337120ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/typechanges/.gitted/modules/b/objects/78x 0 )?= NlOkj8&r qJW7B<fK8#Q1C-"e̫>'@libgit2-0.19.0/tests-clar/resources/typechanges/.gitted/modules/b/objects/88/000077500000000000000000000000001216214232500266575ustar00rootroot0000000000000034b635dd468a83cb012f6feace968c1c9f5d6e000066400000000000000000000001211216214232500341620ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/typechanges/.gitted/modules/b/objects/88xKOR0d,VD̜T|̴J<$ 4'˳D!1(51R!#X8?7U$R vlibgit2-0.19.0/tests-clar/resources/typechanges/.gitted/modules/b/objects/d0/000077500000000000000000000000001216214232500267235ustar00rootroot000000000000005f2cd5cc77addf68ed6f50d622c9a4f732e6c5000066400000000000000000000001351216214232500343150ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/typechanges/.gitted/modules/b/objects/d0x+)JMU0`040031Qrutu+(a-ŏ/C:sH[ *-3'5$?>7?%3d]ӌM둙"libgit2-0.19.0/tests-clar/resources/typechanges/.gitted/modules/b/packed-refs000066400000000000000000000001361216214232500270760ustar00rootroot00000000000000# pack-refs with: peeled 480095882d281ed676fe5b863569520e54a7d5c0 refs/remotes/origin/master libgit2-0.19.0/tests-clar/resources/typechanges/.gitted/modules/b/refs/000077500000000000000000000000001216214232500257265ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/typechanges/.gitted/modules/b/refs/heads/000077500000000000000000000000001216214232500270125ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/typechanges/.gitted/modules/b/refs/heads/master000066400000000000000000000000511216214232500302240ustar00rootroot00000000000000480095882d281ed676fe5b863569520e54a7d5c0 libgit2-0.19.0/tests-clar/resources/typechanges/.gitted/modules/b/refs/remotes/000077500000000000000000000000001216214232500274045ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/typechanges/.gitted/modules/b/refs/remotes/origin/000077500000000000000000000000001216214232500306735ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/typechanges/.gitted/modules/b/refs/remotes/origin/HEAD000066400000000000000000000000401216214232500313110ustar00rootroot00000000000000ref: refs/remotes/origin/master libgit2-0.19.0/tests-clar/resources/typechanges/.gitted/modules/d/000077500000000000000000000000001216214232500247715ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/typechanges/.gitted/modules/d/HEAD000066400000000000000000000000271216214232500254140ustar00rootroot00000000000000ref: refs/heads/master libgit2-0.19.0/tests-clar/resources/typechanges/.gitted/modules/d/config000066400000000000000000000005111216214232500261560ustar00rootroot00000000000000[core] repositoryformatversion = 0 filemode = true bare = false logallrefupdates = true worktree = ../../../d ignorecase = true [remote "origin"] fetch = +refs/heads/*:refs/remotes/origin/* url = /Users/rb/src/libgit2/tests-clar/resources/submod2_target/.git [branch "master"] remote = origin merge = refs/heads/master libgit2-0.19.0/tests-clar/resources/typechanges/.gitted/modules/d/description000066400000000000000000000001111216214232500272300ustar00rootroot00000000000000Unnamed repository; edit this file 'description' to name the repository. libgit2-0.19.0/tests-clar/resources/typechanges/.gitted/modules/d/index000066400000000000000000000003001216214232500260140ustar00rootroot00000000000000DIRCPkrCPkrCWjx swU:K-J README.txtPkrCPkrCWixڤwE8TUKfile_to_modifyfHS@'0`,M$flibgit2-0.19.0/tests-clar/resources/typechanges/.gitted/modules/d/info/000077500000000000000000000000001216214232500257245ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/typechanges/.gitted/modules/d/info/exclude000066400000000000000000000003601216214232500272770ustar00rootroot00000000000000# git ls-files --others --exclude-from=.git/info/exclude # Lines that start with '#' are comments. # For a project mostly in C, the following would be a good set of # exclude patterns (uncomment them if you want to use them): # *.[oa] # *~ libgit2-0.19.0/tests-clar/resources/typechanges/.gitted/modules/d/objects/000077500000000000000000000000001216214232500264225ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/typechanges/.gitted/modules/d/objects/06/000077500000000000000000000000001216214232500266475ustar00rootroot00000000000000362fe2fdb7010d0e447b4fb450d405420479a1000066400000000000000000000000671216214232500335410ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/typechanges/.gitted/modules/d/objects/06x+)JMU0`040031Qrutu+(a-ŏ/C:sH[ blibgit2-0.19.0/tests-clar/resources/typechanges/.gitted/modules/d/objects/0e/000077500000000000000000000000001216214232500267265ustar00rootroot000000000000006a3ca48bd47cfe67681acf39aa0b10a0b92484000066400000000000000000000000651216214232500341300ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/typechanges/.gitted/modules/d/objects/0exKOR01`,VD̜T|̴J<$ 4' libgit2-0.19.0/tests-clar/resources/typechanges/.gitted/modules/d/objects/17/000077500000000000000000000000001216214232500266515ustar00rootroot00000000000000d0ece6e96460a06592d9d9d000de37ba4232c5000066400000000000000000000001351216214232500337160ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/typechanges/.gitted/modules/d/objects/17x+)JMU0`040031Qrutu+(a-ŏ/C:sH[ *-3'5$?>7?%3/fIR-Wq ,ة!libgit2-0.19.0/tests-clar/resources/typechanges/.gitted/modules/d/objects/41/000077500000000000000000000000001216214232500266465ustar00rootroot00000000000000bd4bc3df978de695f67ace64c560913da11653000066400000000000000000000002431216214232500340170ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/typechanges/.gitted/modules/d/objects/41x 0vh}K%ЁR8=͓u+CZD@%z1hrl b5Lꛊl|o57:anОщvQT:!oY)p/st7h Q QզTm*Ga^DFlibgit2-0.19.0/tests-clar/resources/typechanges/.gitted/modules/d/objects/48/000077500000000000000000000000001216214232500266555ustar00rootroot000000000000000095882d281ed676fe5b863569520e54a7d5c0000066400000000000000000000002431216214232500334520ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/typechanges/.gitted/modules/d/objects/48x[ >@QG(tˤ $NJ(e.212K${Ml-%E* Y]uk"IT&k,IC}J!pi9^\^;錷 (D"pNJuo)+C*ùXBElibgit2-0.19.0/tests-clar/resources/typechanges/.gitted/modules/d/objects/5e/000077500000000000000000000000001216214232500267335ustar00rootroot000000000000004963595a9774b90524d35a807169049de8ccad000066400000000000000000000002471216214232500335410ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/typechanges/.gitted/modules/d/objects/5ex[j0SRUȻ`A^߿Bu6|P# 2D:]Uk˽m IIz-WQة4VʌkHB Lw]1>y[ k_w'=T[߷4_0 Hlibgit2-0.19.0/tests-clar/resources/typechanges/.gitted/modules/d/objects/6b/000077500000000000000000000000001216214232500267315ustar00rootroot0000000000000031c659545507c381e9cd34ec508f16c04e149e000066400000000000000000000002031216214232500335700ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/typechanges/.gitted/modules/d/objects/6bxQ !Evoy*_@g#hOh^9wSòf1*[Ic Ԥpk Α\S߇l@.^QpF(:D5zr~ en8libgit2-0.19.0/tests-clar/resources/typechanges/.gitted/modules/d/objects/73/000077500000000000000000000000001216214232500266535ustar00rootroot00000000000000ba924a80437097795ae839e66e187c55d3babf000066400000000000000000000001351216214232500336720ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/typechanges/.gitted/modules/d/objects/73x+)JMU0`040031Qrutu+(a-ŏ/C:sH[ *-3'5$?>7?%3b[,m*um:oLo#libgit2-0.19.0/tests-clar/resources/typechanges/.gitted/modules/d/objects/78/000077500000000000000000000000001216214232500266605ustar00rootroot000000000000000d7397f5e8f8f477fb55b7af3accc2154b2d4a000066400000000000000000000001521216214232500341650ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/typechanges/.gitted/modules/d/objects/78x-10 Fa0p(N-ӡғq]>ks*? |m“i@mV'`).-1 x uxt(+9efbdadaa4a582778d4584385495559ea0994b000066400000000000000000000001471216214232500337140ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/typechanges/.gitted/modules/d/objects/78x 0 )?= NlOkj8&r qJW7B<fK8#Q1C-"e̫>'@libgit2-0.19.0/tests-clar/resources/typechanges/.gitted/modules/d/objects/88/000077500000000000000000000000001216214232500266615ustar00rootroot0000000000000034b635dd468a83cb012f6feace968c1c9f5d6e000066400000000000000000000001211216214232500341640ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/typechanges/.gitted/modules/d/objects/88xKOR0d,VD̜T|̴J<$ 4'˳D!1(51R!#X8?7U$R vlibgit2-0.19.0/tests-clar/resources/typechanges/.gitted/modules/d/objects/d0/000077500000000000000000000000001216214232500267255ustar00rootroot000000000000005f2cd5cc77addf68ed6f50d622c9a4f732e6c5000066400000000000000000000001351216214232500343170ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/typechanges/.gitted/modules/d/objects/d0x+)JMU0`040031Qrutu+(a-ŏ/C:sH[ *-3'5$?>7?%3d]ӌM둙"libgit2-0.19.0/tests-clar/resources/typechanges/.gitted/modules/d/packed-refs000066400000000000000000000001361216214232500271000ustar00rootroot00000000000000# pack-refs with: peeled 480095882d281ed676fe5b863569520e54a7d5c0 refs/remotes/origin/master libgit2-0.19.0/tests-clar/resources/typechanges/.gitted/modules/d/refs/000077500000000000000000000000001216214232500257305ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/typechanges/.gitted/modules/d/refs/heads/000077500000000000000000000000001216214232500270145ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/typechanges/.gitted/modules/d/refs/heads/master000066400000000000000000000000511216214232500302260ustar00rootroot00000000000000480095882d281ed676fe5b863569520e54a7d5c0 libgit2-0.19.0/tests-clar/resources/typechanges/.gitted/modules/d/refs/remotes/000077500000000000000000000000001216214232500274065ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/typechanges/.gitted/modules/d/refs/remotes/origin/000077500000000000000000000000001216214232500306755ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/typechanges/.gitted/modules/d/refs/remotes/origin/HEAD000066400000000000000000000000401216214232500313130ustar00rootroot00000000000000ref: refs/remotes/origin/master libgit2-0.19.0/tests-clar/resources/typechanges/.gitted/modules/e/000077500000000000000000000000001216214232500247725ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/typechanges/.gitted/modules/e/HEAD000066400000000000000000000000271216214232500254150ustar00rootroot00000000000000ref: refs/heads/master libgit2-0.19.0/tests-clar/resources/typechanges/.gitted/modules/e/config000066400000000000000000000005111216214232500261570ustar00rootroot00000000000000[core] repositoryformatversion = 0 filemode = true bare = false logallrefupdates = true worktree = ../../../e ignorecase = true [remote "origin"] fetch = +refs/heads/*:refs/remotes/origin/* url = /Users/rb/src/libgit2/tests-clar/resources/submod2_target/.git [branch "master"] remote = origin merge = refs/heads/master libgit2-0.19.0/tests-clar/resources/typechanges/.gitted/modules/e/description000066400000000000000000000001111216214232500272310ustar00rootroot00000000000000Unnamed repository; edit this file 'description' to name the repository. libgit2-0.19.0/tests-clar/resources/typechanges/.gitted/modules/e/index000066400000000000000000000003001216214232500260150ustar00rootroot00000000000000DIRCPksPksWjx swU:K-J README.txtPksPksWixڤwE8TUKfile_to_modifygzT0`libgit2-0.19.0/tests-clar/resources/typechanges/.gitted/modules/e/info/000077500000000000000000000000001216214232500257255ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/typechanges/.gitted/modules/e/info/exclude000066400000000000000000000003601216214232500273000ustar00rootroot00000000000000# git ls-files --others --exclude-from=.git/info/exclude # Lines that start with '#' are comments. # For a project mostly in C, the following would be a good set of # exclude patterns (uncomment them if you want to use them): # *.[oa] # *~ libgit2-0.19.0/tests-clar/resources/typechanges/.gitted/modules/e/objects/000077500000000000000000000000001216214232500264235ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/typechanges/.gitted/modules/e/objects/06/000077500000000000000000000000001216214232500266505ustar00rootroot00000000000000362fe2fdb7010d0e447b4fb450d405420479a1000066400000000000000000000000671216214232500335420ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/typechanges/.gitted/modules/e/objects/06x+)JMU0`040031Qrutu+(a-ŏ/C:sH[ blibgit2-0.19.0/tests-clar/resources/typechanges/.gitted/modules/e/objects/0e/000077500000000000000000000000001216214232500267275ustar00rootroot000000000000006a3ca48bd47cfe67681acf39aa0b10a0b92484000066400000000000000000000000651216214232500341310ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/typechanges/.gitted/modules/e/objects/0exKOR01`,VD̜T|̴J<$ 4' libgit2-0.19.0/tests-clar/resources/typechanges/.gitted/modules/e/objects/17/000077500000000000000000000000001216214232500266525ustar00rootroot00000000000000d0ece6e96460a06592d9d9d000de37ba4232c5000066400000000000000000000001351216214232500337170ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/typechanges/.gitted/modules/e/objects/17x+)JMU0`040031Qrutu+(a-ŏ/C:sH[ *-3'5$?>7?%3/fIR-Wq ,ة!libgit2-0.19.0/tests-clar/resources/typechanges/.gitted/modules/e/objects/41/000077500000000000000000000000001216214232500266475ustar00rootroot00000000000000bd4bc3df978de695f67ace64c560913da11653000066400000000000000000000002431216214232500340200ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/typechanges/.gitted/modules/e/objects/41x 0vh}K%ЁR8=͓u+CZD@%z1hrl b5Lꛊl|o57:anОщvQT:!oY)p/st7h Q QզTm*Ga^DFlibgit2-0.19.0/tests-clar/resources/typechanges/.gitted/modules/e/objects/48/000077500000000000000000000000001216214232500266565ustar00rootroot000000000000000095882d281ed676fe5b863569520e54a7d5c0000066400000000000000000000002431216214232500334530ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/typechanges/.gitted/modules/e/objects/48x[ >@QG(tˤ $NJ(e.212K${Ml-%E* Y]uk"IT&k,IC}J!pi9^\^;錷 (D"pNJuo)+C*ùXBElibgit2-0.19.0/tests-clar/resources/typechanges/.gitted/modules/e/objects/5e/000077500000000000000000000000001216214232500267345ustar00rootroot000000000000004963595a9774b90524d35a807169049de8ccad000066400000000000000000000002471216214232500335420ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/typechanges/.gitted/modules/e/objects/5ex[j0SRUȻ`A^߿Bu6|P# 2D:]Uk˽m IIz-WQة4VʌkHB Lw]1>y[ k_w'=T[߷4_0 Hlibgit2-0.19.0/tests-clar/resources/typechanges/.gitted/modules/e/objects/6b/000077500000000000000000000000001216214232500267325ustar00rootroot0000000000000031c659545507c381e9cd34ec508f16c04e149e000066400000000000000000000002031216214232500335710ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/typechanges/.gitted/modules/e/objects/6bxQ !Evoy*_@g#hOh^9wSòf1*[Ic Ԥpk Α\S߇l@.^QpF(:D5zr~ en8libgit2-0.19.0/tests-clar/resources/typechanges/.gitted/modules/e/objects/73/000077500000000000000000000000001216214232500266545ustar00rootroot00000000000000ba924a80437097795ae839e66e187c55d3babf000066400000000000000000000001351216214232500336730ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/typechanges/.gitted/modules/e/objects/73x+)JMU0`040031Qrutu+(a-ŏ/C:sH[ *-3'5$?>7?%3b[,m*um:oLo#libgit2-0.19.0/tests-clar/resources/typechanges/.gitted/modules/e/objects/78/000077500000000000000000000000001216214232500266615ustar00rootroot000000000000000d7397f5e8f8f477fb55b7af3accc2154b2d4a000066400000000000000000000001521216214232500341660ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/typechanges/.gitted/modules/e/objects/78x-10 Fa0p(N-ӡғq]>ks*? |m“i@mV'`).-1 x uxt(+9efbdadaa4a582778d4584385495559ea0994b000066400000000000000000000001471216214232500337150ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/typechanges/.gitted/modules/e/objects/78x 0 )?= NlOkj8&r qJW7B<fK8#Q1C-"e̫>'@libgit2-0.19.0/tests-clar/resources/typechanges/.gitted/modules/e/objects/88/000077500000000000000000000000001216214232500266625ustar00rootroot0000000000000034b635dd468a83cb012f6feace968c1c9f5d6e000066400000000000000000000001211216214232500341650ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/typechanges/.gitted/modules/e/objects/88xKOR0d,VD̜T|̴J<$ 4'˳D!1(51R!#X8?7U$R vlibgit2-0.19.0/tests-clar/resources/typechanges/.gitted/modules/e/objects/d0/000077500000000000000000000000001216214232500267265ustar00rootroot000000000000005f2cd5cc77addf68ed6f50d622c9a4f732e6c5000066400000000000000000000001351216214232500343200ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/typechanges/.gitted/modules/e/objects/d0x+)JMU0`040031Qrutu+(a-ŏ/C:sH[ *-3'5$?>7?%3d]ӌM둙"libgit2-0.19.0/tests-clar/resources/typechanges/.gitted/modules/e/packed-refs000066400000000000000000000001361216214232500271010ustar00rootroot00000000000000# pack-refs with: peeled 480095882d281ed676fe5b863569520e54a7d5c0 refs/remotes/origin/master libgit2-0.19.0/tests-clar/resources/typechanges/.gitted/modules/e/refs/000077500000000000000000000000001216214232500257315ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/typechanges/.gitted/modules/e/refs/heads/000077500000000000000000000000001216214232500270155ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/typechanges/.gitted/modules/e/refs/heads/master000066400000000000000000000000511216214232500302270ustar00rootroot00000000000000480095882d281ed676fe5b863569520e54a7d5c0 libgit2-0.19.0/tests-clar/resources/typechanges/.gitted/modules/e/refs/remotes/000077500000000000000000000000001216214232500274075ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/typechanges/.gitted/modules/e/refs/remotes/origin/000077500000000000000000000000001216214232500306765ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/typechanges/.gitted/modules/e/refs/remotes/origin/HEAD000066400000000000000000000000401216214232500313140ustar00rootroot00000000000000ref: refs/remotes/origin/master libgit2-0.19.0/tests-clar/resources/typechanges/.gitted/objects/000077500000000000000000000000001216214232500245275ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/typechanges/.gitted/objects/0d/000077500000000000000000000000001216214232500250325ustar00rootroot0000000000000078578795b7ca49fd8df6c4b6d27c5c02d991d8000066400000000000000000000001141216214232500321510ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/typechanges/.gitted/objects/0dxKOR044b..MO)IUPJR,H,PUH,-2!JKSK3K K!%libgit2-0.19.0/tests-clar/resources/typechanges/.gitted/objects/0e/000077500000000000000000000000001216214232500250335ustar00rootroot000000000000007ed140b514b8cae23254cb8656fe1674403aff000066400000000000000000000002421216214232500320770ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/typechanges/.gitted/objects/0ex[j0S,E%-Zie(| f`򾮯7U`sE"B(. b["a@|bV*`SĢ-a-ٱIgqS Mӫϧ|}F |`/674oDllibgit2-0.19.0/tests-clar/resources/typechanges/.gitted/objects/0f/000077500000000000000000000000001216214232500250345ustar00rootroot00000000000000f461da9689266f482d8f6654a4400b4e33c586000066400000000000000000000007461216214232500316450ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/typechanges/.gitted/objects/0fxm݊0{M|˲)4Фn1M6PldO֦]C65!wɴRE @? =>[8<5N[=;78@_Pֺ{AFg;Ҿ$DYB6enG)Zʲ)]o RB=dCù t$"U)vykQ[Ӷ4gxH_t74 Bx4sZY0Ƌ}bcO ";vTEWc.X,(cKI:NZHK[$"*9z%cp%N(ARPp@ UcÕI/0 ʙj) UHr6, dUP*@6V7*$ X2HFW3mFu{$HFG2=mUHhGGGGZ_m`libgit2-0.19.0/tests-clar/resources/typechanges/.gitted/objects/18/000077500000000000000000000000001216214232500247575ustar00rootroot00000000000000aa7e45bbe4c3cc24a0b079696c59d36675af97000066400000000000000000000001311216214232500321220ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/typechanges/.gitted/objects/18x+)JMU07c040031QK,O)I-fx6M9{wk+qIOD WG_W& ׆:}~WdvC?!Olibgit2-0.19.0/tests-clar/resources/typechanges/.gitted/objects/1b/000077500000000000000000000000001216214232500250315ustar00rootroot0000000000000063caae4a5ca96f78e8dfefc376c6a39a142475000066400000000000000000000002411216214232500323410ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/typechanges/.gitted/objects/1bx] 0})|VMڸ "zoIwB$Mo 7mY ҩd QM -ņCQCjYګslkRKׄrlV e2|}y*9>Gmy:O .6Xkj[JE} ;SrDlibgit2-0.19.0/tests-clar/resources/typechanges/.gitted/objects/1e/000077500000000000000000000000001216214232500250345ustar00rootroot00000000000000abe82aa3b2365a394f6108f24435df6e193d02000066400000000000000000000010451216214232500320160ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/typechanges/.gitted/objects/1exmR]0~B_KQhIb\oAg>l]yvfvVfiqǧscQk=#c~BQƎ5ZPt s[BK{|_C ޞOL%#˖Pi,\B7fAIwye@+/Y3-~`9(9)Jl]E_t;4cӵ0tbiyc_E}`l].80:,o_i'sŭT@!&R ui Xsu* ö=C׎J&-<+CH_KH_+H_GV#5!8L>M1, d^bƒWe!R.G;pf:b%wR4"420KE(N"UȣX Uuq_c4Wii.wo FX ^X ֬3GdnJ΍p%GD.9"r%77>Z]T]T]T]ֿwlibgit2-0.19.0/tests-clar/resources/typechanges/.gitted/objects/42/000077500000000000000000000000001216214232500247545ustar00rootroot00000000000000061c01a1c70097d1e4579f29a5adf40abdec95000066400000000000000000000000301216214232500320650ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/typechanges/.gitted/objects/42xKORdrutuM(Ilibgit2-0.19.0/tests-clar/resources/typechanges/.gitted/objects/46/000077500000000000000000000000001216214232500247605ustar00rootroot000000000000002838cee476a87e7cff32196b66fa18ed756592000066400000000000000000000001141216214232500320130ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/typechanges/.gitted/objects/46xKOR044b..MO)IUPJU,H,PUH,-2!JKSK3K K!%libgit2-0.19.0/tests-clar/resources/typechanges/.gitted/objects/63/000077500000000000000000000000001216214232500247575ustar00rootroot00000000000000499e4ea8e096b831515ceb1d5a7593e4d87ae5000066400000000000000000000000221216214232500320520ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/typechanges/.gitted/objects/63xKOR0eHR\8libgit2-0.19.0/tests-clar/resources/typechanges/.gitted/objects/68/000077500000000000000000000000001216214232500247645ustar00rootroot000000000000001af94e10eaf262f3ab7cb9b8fd5f4158ba4d3e000066400000000000000000000000301216214232500324060ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/typechanges/.gitted/objects/68xKORd/I-(.libgit2-0.19.0/tests-clar/resources/typechanges/.gitted/objects/6a/000077500000000000000000000000001216214232500250355ustar00rootroot000000000000009008602b811e69a9b7a2d83496f39a794fdeeb000066400000000000000000000011321216214232500320530ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/typechanges/.gitted/objects/6axmR]k@.) 54ZLKc:R݊EcAp[q08=4߷G8gyyD _McEhI܀/T?099jw{5 Yo?^jZ|@1nn 8ʶ=r?yϘޒ}C_\7Sw0x $ISxS?KA1idaێwG$Ssn!Zk2zHiA K,X!pV6&ڒj-I`VK Z/VkXa}DVE=+4wX DlsZ6x+iBeЙ;.L&"@KBsoUp(4wUAQZs!MM!q\1q\zyȥ2t$xUY'ƖNK"XTEC5|$B$͘svza16J9jcCl(g/]4Yrĕ ͜iMR4唢l fs< ao X!eYcga=t= (!0Y8Ť.¾+tK) ac130Q^" \.ƞ<Y9d<3灞9y0$"ѱ  KrY*\ڎ~h.(4f]_éuܰܰܰ2libgit2-0.19.0/tests-clar/resources/typechanges/.gitted/objects/75/000077500000000000000000000000001216214232500247625ustar00rootroot0000000000000056c1d893a4c0ca85ac8ac51de47ff399758729000066400000000000000000000003421216214232500320650ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/typechanges/.gitted/objects/75x+)JMU022`040031QK,O)I-f]i.`a&A:0I5S-C?-d6 PHd@:scr5c[ B HbH1eJ'?Q(injPTε]˼j뵆F`cSdg~I|ͥkp}3 ,0CWCZٿ6 WXlibgit2-0.19.0/tests-clar/resources/typechanges/.gitted/objects/76/000077500000000000000000000000001216214232500247635ustar00rootroot00000000000000fef844064c26d5e06c2508240dae661e7231b2000066400000000000000000000001021216214232500316560ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/typechanges/.gitted/objects/76xKOR05c..MO)IUPJR,H,PUH,-2!JKSK3K}libgit2-0.19.0/tests-clar/resources/typechanges/.gitted/objects/79/000077500000000000000000000000001216214232500247665ustar00rootroot00000000000000b9f23e85f55ea36a472a902e875bc1121a94cb000066400000000000000000000002041216214232500320340ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/typechanges/.gitted/objects/79xA E]sfJbq `I@ yH;ZeBr6LPY%8&v4Jm֢^*qpJµ;Z Ơ3ZD1)"%%38_libgit2-0.19.0/tests-clar/resources/typechanges/.gitted/objects/85/000077500000000000000000000000001216214232500247635ustar00rootroot0000000000000028da0ea65eacf1f74f9ed6696adbac547963ad000066400000000000000000000007031216214232500324340ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/typechanges/.gitted/objects/85xmj@{O1BŒ%%*]1g-A${feWTwvΌTt{|(Z=~%Y- l IېZLAHm3SݖJ->ӑl[ZKPp{&wJ8|˷n5;gt|p.-~f\XvI2"Oz~g_ŗ6#4Mx.?殡k K7./8Mwi&6R4#O qbX5IL)ڎʟ;s4W.Oε>\Um.-lzOP~F#P~1pbz9YL / 8W@X qt. T"DaHF^]@\F\F0rat1.#ˈ2blibgit2-0.19.0/tests-clar/resources/typechanges/.gitted/objects/8b/000077500000000000000000000000001216214232500250405ustar00rootroot000000000000003726b365824ad5a07c537247f4bc73ed7d37ea000066400000000000000000000001141216214232500320350ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/typechanges/.gitted/objects/8bxKOR044b..MO)IUPJQ,H,PUH,-2!JKSK3K"K%m%libgit2-0.19.0/tests-clar/resources/typechanges/.gitted/objects/93/000077500000000000000000000000001216214232500247625ustar00rootroot000000000000003e28c1c8a68838a763d250bdf0b2c6068289c3000066400000000000000000000003421216214232500317030ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/typechanges/.gitted/objects/93x+)JMU022`040031QK,O)I-fȷ|{Q# ٻlez,U/7z䤻LrBkuT\;kTDdy~+LaZ6tUO榦 I E\hڕ̫Z^khd Nl2 3L$|ҵ_jhLa`ڡ!w_tif_Lr YG~nLf̳vtA\=[Olibgit2-0.19.0/tests-clar/resources/typechanges/.gitted/objects/96/000077500000000000000000000000001216214232500247655ustar00rootroot000000000000002710fe5b4e453e9e827945b3487c525968ec4a000066400000000000000000000001141216214232500316460ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/typechanges/.gitted/objects/96xKOR044b..MO)IUPJQ,H,PUH,-2!JKSK3K%!K"%6cf1b3598e195b31b2cde3784f9a19f0728a6f000066400000000000000000000003421216214232500320600ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/typechanges/.gitted/objects/96x+)JMU022`040031QK,O)I-fȷ|{Q# ٻlez,U/7a#Ow]Irh;PE ɞV<00lT'7%MMjٹs+wWmzcdg~I|ͥkp}3 ,0CWCZٿ6 WR>ܘe͘gt;\libgit2-0.19.0/tests-clar/resources/typechanges/.gitted/objects/99/000077500000000000000000000000001216214232500247705ustar00rootroot00000000000000e8bab9ece009f0fba7eb41f850f4c12bedb9b7000066400000000000000000000012751216214232500325650ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/typechanges/.gitted/objects/99xmT]k1~h_}T!q4N oA %i}Wr°X, >P.Xv;O t =p >-a tP vth\Y,z4D &no3!첝__WO|l8.n c3f"W;8;l)@h5cVQ cz>-j*SZppz~[puCo_>2N97gR`%)!~m~{4O /5R+qe!5xijwLmt L܇~31*QOԈxGS4\Hi9)x烆x@n 7r}}Aj cQ*2k6+`J5  '(NLj>\Rң])c 2d#3ʈ \5yf5kY=(ƂMrKK hqC4)p?Лbޞ~Z57575750*cTk.*fVE[/w_?ktoۺO+| Plibgit2-0.19.0/tests-clar/resources/typechanges/.gitted/objects/9b/000077500000000000000000000000001216214232500250415ustar00rootroot0000000000000019edf33a03a0c59cdfc113bfa5c06179bf9b1a000066400000000000000000000002411216214232500323700ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/typechanges/.gitted/objects/9bxI 1E]LT AJЃ7WpyӶ,ZѩUf cXcR C43Y2"NN:HɈo6,sjf#kG cys MGm2B .K)k֑w8CCdb75b73836a99e3dbeea640a81de81031fdc29000066400000000000000000000002421216214232500322570ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/typechanges/.gitted/objects/9bxm0 )@ @݀&Bw,1̀IzEdZK̄"t{ b $%S abZvݷ67p~\!1c'Aq-O7q>F#libgit2-0.19.0/tests-clar/resources/typechanges/.gitted/objects/9d/000077500000000000000000000000001216214232500250435ustar00rootroot000000000000000235c7a7edc0889a18f97a42ee6db9fe688447000066400000000000000000000002401216214232500321510ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/typechanges/.gitted/objects/9dxI 1= dH& ^*V3b IV(&*,`I|c㥃dEYrdm9:[+MUĽkm to%S<vj]+fAZlibgit2-0.19.0/tests-clar/resources/typechanges/.gitted/objects/a0/000077500000000000000000000000001216214232500250275ustar00rootroot00000000000000a9bad6f6f40325198f938a0e3ae981622d7707000066400000000000000000000000661216214232500317630ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/typechanges/.gitted/objects/a0x+)JMU06g040031QrutuMahոŷ,nef^RC^libgit2-0.19.0/tests-clar/resources/typechanges/.gitted/objects/b1/000077500000000000000000000000001216214232500250315ustar00rootroot00000000000000977dc4e573b812d4619754c98138c56999dc0d000066400000000000000000000010061216214232500316500ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/typechanges/.gitted/objects/b1xmR]0~B_v\hIb\oA7gS:lݕC.5%tg4dIlha''3@ֆ`D-ШPjX^! "`3t5p4/syB(yĞ^n P'8!ÏqzݗPbb*(Ty1Sr[N<P.V?Z3=nߧTHn]bOM>(J|mE_LC6зg/I mwa^/_V\= 7'O͙n쵖24y%$fLJcYmɹ&We@mz%Aso- Z9As hx:KTfs"D&3K^Rl5>6xC~v&v3#W\٬4(wBJTC `79b9f23e85f55ea36a472a902e875bc1121a94cb` * `a(1->2) b(1->3) c(1->4) d(1->5) e(1->6)` **Create content**
`9bdb75b73836a99e3dbeea640a81de81031fdc29` * `a(2->3) b(3->4) c(4->5) d(5->6) e(6->2)` **Changes #1**
`0e7ed140b514b8cae23254cb8656fe1674403aff` * `a(3->5) b(4->6) c(5->2) d(6->3) e(2->4)` **Changes #2**
`9d0235c7a7edc0889a18f97a42ee6db9fe688447` * `a(5->3) b(6->4) c(2->5) d(3->6) e(4->2)` **Changes #3**
`9b19edf33a03a0c59cdfc113bfa5c06179bf9b1a` * `a(3->2) b(4->3) c(5->4) d(6->5) e(2->6)` **Changes #4**
`1b63caae4a5ca96f78e8dfefc376c6a39a142475`
Matches **Changes #1** except README.md * `a(2->1) b(3->1) c(4->1) d(5->1) e(6->1)` **Changes #5**
`6eae26c90e8ccc4d16208972119c40635489c6f0`
Matches **Initial commit** except README.md and .gitmodules libgit2-0.19.0/tests-clar/resources/typechanges/gitmodules000066400000000000000000000000001216214232500236250ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/unsymlinked.git/000077500000000000000000000000001216214232500223525ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/unsymlinked.git/HEAD000066400000000000000000000000271216214232500227750ustar00rootroot00000000000000ref: refs/heads/master libgit2-0.19.0/tests-clar/resources/unsymlinked.git/config000066400000000000000000000001571216214232500235450ustar00rootroot00000000000000[core] bare = true repositoryformatversion = 0 filemode = false logallrefupdates = true ignorecase = true libgit2-0.19.0/tests-clar/resources/unsymlinked.git/description000066400000000000000000000001111216214232500246110ustar00rootroot00000000000000Unnamed repository; edit this file 'description' to name the repository. libgit2-0.19.0/tests-clar/resources/unsymlinked.git/info/000077500000000000000000000000001216214232500233055ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/unsymlinked.git/info/exclude000066400000000000000000000001611216214232500246570ustar00rootroot00000000000000# File patterns to ignore; see `git help ignore` for more information. # Lines that start with '#' are comments. libgit2-0.19.0/tests-clar/resources/unsymlinked.git/objects/000077500000000000000000000000001216214232500240035ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/unsymlinked.git/objects/08/000077500000000000000000000000001216214232500242325ustar00rootroot000000000000008b64704e0d6b8bd061dea879418cb5442a3fbf000066400000000000000000000000611216214232500313640ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/unsymlinked.git/objects/08x+)JMU06b040075U+`,L}=.5W8 Qlibgit2-0.19.0/tests-clar/resources/unsymlinked.git/objects/13/000077500000000000000000000000001216214232500242265ustar00rootroot00000000000000a5e939bca25940c069fd2169d993dba328e30b000066400000000000000000000000541216214232500313070ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/unsymlinked.git/objects/13x+)JMU0d01R}>+\dZSh`{1 libgit2-0.19.0/tests-clar/resources/unsymlinked.git/objects/19/000077500000000000000000000000001216214232500242345ustar00rootroot00000000000000bf568e59e3a0b363cafb4106226e62d4a4c41c000066400000000000000000000000351216214232500313500ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/unsymlinked.git/objects/19xKOR04ed}R JMblibgit2-0.19.0/tests-clar/resources/unsymlinked.git/objects/58/000077500000000000000000000000001216214232500242375ustar00rootroot000000000000001fadd35b4cf320d102a152f918729011604773000066400000000000000000000000571216214232500307670ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/unsymlinked.git/objects/58x+)JMU06b042R a}lN>ۑM)/ʒ#2libgit2-0.19.0/tests-clar/resources/unsymlinked.git/objects/5c/000077500000000000000000000000001216214232500243125ustar00rootroot0000000000000087b6791e8b13da658a14d1ef7e09b5dc3bac8c000066400000000000000000000001161216214232500316130ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/unsymlinked.git/objects/5cx+)JMU03e01̼ҔT/-,t8W1ۋ5sCT'e%3zEkg؊ZNlj =8libgit2-0.19.0/tests-clar/resources/unsymlinked.git/objects/6f/000077500000000000000000000000001216214232500243165ustar00rootroot00000000000000e5f5398af85fb3de8a6aba0339b6d3bfa26a27000066400000000000000000000000611216214232500316730ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/unsymlinked.git/objects/6fx+)JMU06a01̼ҔTZd o e&0~ libgit2-0.19.0/tests-clar/resources/unsymlinked.git/objects/7f/000077500000000000000000000000001216214232500243175ustar00rootroot00000000000000ccd75616ec188b8f1b23d67506a334cc34a49d000066400000000000000000000002041216214232500313700ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/unsymlinked.git/objects/7fx; B1s텐>]:٬$h Xx{xaV'ws0# ɇE3&mrY-ZdR$$߳ kc8γ`I@Ekꠔ춛w(uG}ޥ 7qlibgit2-0.19.0/tests-clar/resources/unsymlinked.git/objects/80/000077500000000000000000000000001216214232500242325ustar00rootroot000000000000006999882bf91d24241e4077906b9017605eb1f3000066400000000000000000000002521216214232500306670ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/unsymlinked.git/objects/80xKj1)zo !֓g B 9AV%"ǚ`Sn$GNovKګ0[,LRi)D!&皻ֵqkS并s?n{mr/29Lm{ Zrh?I&GzJlibgit2-0.19.0/tests-clar/resources/unsymlinked.git/objects/83/000077500000000000000000000000001216214232500242355ustar00rootroot000000000000007d176303c5005505ec1e4a30231c40930c0230000066400000000000000000000000541216214232500305740ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/unsymlinked.git/objects/83x+)JMU0d01R? VT:luѲ libgit2-0.19.0/tests-clar/resources/unsymlinked.git/objects/a8/000077500000000000000000000000001216214232500243135ustar00rootroot00000000000000595ccca04f40818ae0155c8f9c77a230e597b6000066400000000000000000000002561216214232500313210ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/unsymlinked.git/objects/a8x[ 0E*_y݀{4ShZ))| N[ks=KߙŚ[Q"4&&M*i/޴!1S*AGt)-'Um7O ccչ=z崵;(PY+*Dq^E!*/0}Z?<P慥Jplibgit2-0.19.0/tests-clar/resources/unsymlinked.git/objects/cf/000077500000000000000000000000001216214232500243735ustar00rootroot000000000000008f1cf5cce859c438d6cc067284cb5e161206e7000066400000000000000000000000611216214232500314610ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/unsymlinked.git/objects/cfx+)JMU06b040031Q+`,L}=.5W8c Nlibgit2-0.19.0/tests-clar/resources/unsymlinked.git/objects/d5/000077500000000000000000000000001216214232500243135ustar00rootroot00000000000000278d05c8607ec420bfee4cf219fbc0eeebfd6a000066400000000000000000000000611216214232500320230ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/unsymlinked.git/objects/d5x+)JMU06a01̼ҔT/󷧚EJ9:Nae$BMlibgit2-0.19.0/tests-clar/resources/unsymlinked.git/objects/f4/000077500000000000000000000000001216214232500243145ustar00rootroot00000000000000e16fb76536591a41454194058d048d8e4dd2e9000066400000000000000000000000541216214232500311070ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/resources/unsymlinked.git/objects/f4x+)JMU0d01R2_ϼ 14 */ cl_assert(i == 14); } void test_revwalk_basic__push_head(void) { int i = 0; git_oid oid; cl_git_pass(git_revwalk_push_head(_walk)); while (git_revwalk_next(&oid, _walk) == 0) { i++; } /* git log HEAD --oneline | wc -l => 7 */ cl_assert(i == 7); } void test_revwalk_basic__push_head_hide_ref(void) { int i = 0; git_oid oid; cl_git_pass(git_revwalk_push_head(_walk)); cl_git_pass(git_revwalk_hide_ref(_walk, "refs/heads/packed-test")); while (git_revwalk_next(&oid, _walk) == 0) { i++; } /* git log HEAD --oneline --not refs/heads/packed-test | wc -l => 4 */ cl_assert(i == 4); } void test_revwalk_basic__push_head_hide_ref_nobase(void) { int i = 0; git_oid oid; cl_git_pass(git_revwalk_push_head(_walk)); cl_git_pass(git_revwalk_hide_ref(_walk, "refs/heads/packed")); while (git_revwalk_next(&oid, _walk) == 0) { i++; } /* git log HEAD --oneline --not refs/heads/packed | wc -l => 7 */ cl_assert(i == 7); } void test_revwalk_basic__disallow_non_commit(void) { git_oid oid; cl_git_pass(git_oid_fromstr(&oid, "521d87c1ec3aef9824daf6d96cc0ae3710766d91")); cl_git_fail(git_revwalk_push(_walk, &oid)); } void test_revwalk_basic__push_range(void) { git_revwalk_reset(_walk); git_revwalk_sorting(_walk, 0); cl_git_pass(git_revwalk_push_range(_walk, "9fd738e~2..9fd738e")); cl_git_pass(test_walk_only(_walk, commit_sorting_segment, 1)); } libgit2-0.19.0/tests-clar/revwalk/mergebase.c000066400000000000000000000277531216214232500210030ustar00rootroot00000000000000#include "clar_libgit2.h" #include "vector.h" #include static git_repository *_repo; static git_repository *_repo2; void test_revwalk_mergebase__initialize(void) { cl_git_pass(git_repository_open(&_repo, cl_fixture("testrepo.git"))); cl_git_pass(git_repository_open(&_repo2, cl_fixture("twowaymerge.git"))); } void test_revwalk_mergebase__cleanup(void) { git_repository_free(_repo); _repo = NULL; git_repository_free(_repo2); _repo2 = NULL; } void test_revwalk_mergebase__single1(void) { git_oid result, one, two, expected; size_t ahead, behind; cl_git_pass(git_oid_fromstr(&one, "c47800c7266a2be04c571c04d5a6614691ea99bd ")); cl_git_pass(git_oid_fromstr(&two, "9fd738e8f7967c078dceed8190330fc8648ee56a")); cl_git_pass(git_oid_fromstr(&expected, "5b5b025afb0b4c913b4c338a42934a3863bf3644")); cl_git_pass(git_merge_base(&result, _repo, &one, &two)); cl_assert(git_oid_cmp(&result, &expected) == 0); cl_git_pass(git_graph_ahead_behind(&ahead, &behind, _repo, &one, &two)); cl_assert_equal_sz(ahead, 2); cl_assert_equal_sz(behind, 1); cl_git_pass(git_graph_ahead_behind(&ahead, &behind, _repo, &two, &one)); cl_assert_equal_sz(ahead, 1); cl_assert_equal_sz(behind, 2); } void test_revwalk_mergebase__single2(void) { git_oid result, one, two, expected; size_t ahead, behind; cl_git_pass(git_oid_fromstr(&one, "763d71aadf09a7951596c9746c024e7eece7c7af")); cl_git_pass(git_oid_fromstr(&two, "a65fedf39aefe402d3bb6e24df4d4f5fe4547750")); cl_git_pass(git_oid_fromstr(&expected, "c47800c7266a2be04c571c04d5a6614691ea99bd")); cl_git_pass(git_merge_base(&result, _repo, &one, &two)); cl_assert(git_oid_cmp(&result, &expected) == 0); cl_git_pass(git_graph_ahead_behind( &ahead, &behind, _repo, &one, &two)); cl_assert_equal_sz(ahead, 4); cl_assert_equal_sz(behind, 1); cl_git_pass(git_graph_ahead_behind( &ahead, &behind, _repo, &two, &one)); cl_assert_equal_sz(ahead, 1); cl_assert_equal_sz(behind, 4); } void test_revwalk_mergebase__merged_branch(void) { git_oid result, one, two, expected; size_t ahead, behind; cl_git_pass(git_oid_fromstr(&one, "a65fedf39aefe402d3bb6e24df4d4f5fe4547750")); cl_git_pass(git_oid_fromstr(&two, "9fd738e8f7967c078dceed8190330fc8648ee56a")); cl_git_pass(git_oid_fromstr(&expected, "9fd738e8f7967c078dceed8190330fc8648ee56a")); cl_git_pass(git_merge_base(&result, _repo, &one, &two)); cl_assert(git_oid_cmp(&result, &expected) == 0); cl_git_pass(git_merge_base(&result, _repo, &two, &one)); cl_assert(git_oid_cmp(&result, &expected) == 0); cl_git_pass(git_graph_ahead_behind(&ahead, &behind, _repo, &one, &two)); cl_assert_equal_sz(ahead, 0); cl_assert_equal_sz(behind, 3); cl_git_pass(git_graph_ahead_behind(&ahead, &behind, _repo, &two, &one)); cl_assert_equal_sz(ahead, 3); cl_assert_equal_sz(behind, 0); } void test_revwalk_mergebase__two_way_merge(void) { git_oid one, two; size_t ahead, behind; cl_git_pass(git_oid_fromstr(&one, "9b219343610c88a1187c996d0dc58330b55cee28")); cl_git_pass(git_oid_fromstr(&two, "a953a018c5b10b20c86e69fef55ebc8ad4c5a417")); cl_git_pass(git_graph_ahead_behind(&ahead, &behind, _repo2, &one, &two)); cl_assert_equal_sz(ahead, 2); cl_assert_equal_sz(behind, 8); cl_git_pass(git_graph_ahead_behind(&ahead, &behind, _repo2, &two, &one)); cl_assert_equal_sz(ahead, 8); cl_assert_equal_sz(behind, 2); } void test_revwalk_mergebase__no_common_ancestor_returns_ENOTFOUND(void) { git_oid result, one, two; size_t ahead, behind; int error; cl_git_pass(git_oid_fromstr(&one, "763d71aadf09a7951596c9746c024e7eece7c7af")); cl_git_pass(git_oid_fromstr(&two, "e90810b8df3e80c413d903f631643c716887138d")); error = git_merge_base(&result, _repo, &one, &two); cl_git_fail(error); cl_assert_equal_i(GIT_ENOTFOUND, error); cl_git_pass(git_graph_ahead_behind(&ahead, &behind, _repo, &one, &two)); cl_assert_equal_sz(2, ahead); cl_assert_equal_sz(4, behind); } void test_revwalk_mergebase__no_off_by_one_missing(void) { git_oid result, one, two; cl_git_pass(git_oid_fromstr(&one, "1a443023183e3f2bfbef8ac923cd81c1018a18fd")); cl_git_pass(git_oid_fromstr(&two, "9f13f7d0a9402c681f91dc590cf7b5470e6a77d2")); cl_git_pass(git_merge_base(&result, _repo, &one, &two)); } static void assert_mergebase_many(const char *expected_sha, int count, ...) { va_list ap; int i; git_oid *oids; git_oid oid, expected; char *partial_oid; git_object *object; oids = git__malloc(count * sizeof(git_oid)); cl_assert(oids != NULL); memset(oids, 0x0, count * sizeof(git_oid)); va_start(ap, count); for (i = 0; i < count; ++i) { partial_oid = va_arg(ap, char *); cl_git_pass(git_oid_fromstrn(&oid, partial_oid, strlen(partial_oid))); cl_git_pass(git_object_lookup_prefix(&object, _repo, &oid, strlen(partial_oid), GIT_OBJ_COMMIT)); git_oid_cpy(&oids[i], git_object_id(object)); git_object_free(object); } va_end(ap); if (expected_sha == NULL) cl_assert_equal_i(GIT_ENOTFOUND, git_merge_base_many(&oid, _repo, oids, count)); else { cl_git_pass(git_merge_base_many(&oid, _repo, oids, count)); cl_git_pass(git_oid_fromstr(&expected, expected_sha)); cl_assert(git_oid_cmp(&expected, &oid) == 0); } git__free(oids); } void test_revwalk_mergebase__many_no_common_ancestor_returns_ENOTFOUND(void) { assert_mergebase_many(NULL, 3, "41bc8c", "e90810", "a65fed"); assert_mergebase_many(NULL, 3, "e90810", "41bc8c", "a65fed"); assert_mergebase_many(NULL, 3, "e90810", "a65fed", "41bc8c"); assert_mergebase_many(NULL, 3, "a65fed", "e90810", "41bc8c"); assert_mergebase_many(NULL, 3, "a65fed", "e90810", "41bc8c"); assert_mergebase_many(NULL, 3, "a65fed", "41bc8c", "e90810"); assert_mergebase_many(NULL, 3, "e90810", "763d71", "a65fed"); } void test_revwalk_mergebase__many_merge_branch(void) { assert_mergebase_many("c47800c7266a2be04c571c04d5a6614691ea99bd", 3, "a65fed", "763d71", "849607"); assert_mergebase_many("c47800c7266a2be04c571c04d5a6614691ea99bd", 3, "763d71", "e90810", "a65fed"); assert_mergebase_many("c47800c7266a2be04c571c04d5a6614691ea99bd", 3, "763d71", "a65fed", "e90810"); assert_mergebase_many("c47800c7266a2be04c571c04d5a6614691ea99bd", 3, "a65fed", "763d71", "849607"); assert_mergebase_many("c47800c7266a2be04c571c04d5a6614691ea99bd", 3, "a65fed", "849607", "763d71"); assert_mergebase_many("8496071c1b46c854b31185ea97743be6a8774479", 3, "849607", "a65fed", "763d71"); assert_mergebase_many("5b5b025afb0b4c913b4c338a42934a3863bf3644", 5, "5b5b02", "763d71", "a4a7dc", "a65fed", "41bc8c"); } /* * testrepo.git $ git log --graph --all * * commit 763d71aadf09a7951596c9746c024e7eece7c7af * | Author: nulltoken * | Date: Sun Oct 9 12:54:47 2011 +0200 * | * | Add some files into subdirectories * | * | * commit a65fedf39aefe402d3bb6e24df4d4f5fe4547750 * | | Author: Scott Chacon * | | Date: Tue Aug 9 19:33:46 2011 -0700 * | | * | * commit be3563ae3f795b2b4353bcce3a527ad0a4f7f644 * | |\ Merge: 9fd738e c47800c * | |/ Author: Scott Chacon * |/| Date: Tue May 25 11:58:27 2010 -0700 * | | * | | Merge branch 'br2' * | | * | | * commit e90810b8df3e80c413d903f631643c716887138d * | | | Author: Vicent Marti * | | | Date: Thu Aug 5 18:42:20 2010 +0200 * | | | * | | | Test commit 2 * | | | * | | * commit 6dcf9bf7541ee10456529833502442f385010c3d * | | Author: Vicent Marti * | | Date: Thu Aug 5 18:41:33 2010 +0200 * | | * | | Test commit 1 * | | * | | * commit a4a7dce85cf63874e984719f4fdd239f5145052f * | | |\ Merge: c47800c 9fd738e * | |/ / Author: Scott Chacon * |/| / Date: Tue May 25 12:00:23 2010 -0700 * | |/ * | | Merge branch 'master' into br2 * | | * | * commit 9fd738e8f7967c078dceed8190330fc8648ee56a * | | Author: Scott Chacon * | | Date: Mon May 24 10:19:19 2010 -0700 * | | * | | a fourth commit * | | * | * commit 4a202b346bb0fb0db7eff3cffeb3c70babbd2045 * | | Author: Scott Chacon * | | Date: Mon May 24 10:19:04 2010 -0700 * | | * | | a third commit * | | * * | commit c47800c7266a2be04c571c04d5a6614691ea99bd * |/ Author: Scott Chacon * | Date: Tue May 25 11:58:14 2010 -0700 * | * | branch commit one * | * * commit 5b5b025afb0b4c913b4c338a42934a3863bf3644 * | Author: Scott Chacon * | Date: Tue May 11 13:38:42 2010 -0700 * | * | another commit * | * * commit 8496071c1b46c854b31185ea97743be6a8774479 * Author: Scott Chacon * Date: Sat May 8 16:13:06 2010 -0700 * * testing * * * commit 41bc8c69075bbdb46c5c6f0566cc8cc5b46e8bd9 * | Author: Scott Chacon * | Date: Tue May 11 13:40:41 2010 -0700 * | * | packed commit two * | * * commit 5001298e0c09ad9c34e4249bc5801c75e9754fa5 * Author: Scott Chacon * Date: Tue May 11 13:40:23 2010 -0700 * * packed commit one */ /* * twowaymerge.git $ git log --graph --all * * commit 9b219343610c88a1187c996d0dc58330b55cee28 * |\ Merge: c37a783 2224e19 * | | Author: Scott J. Goldman * | | Date: Tue Nov 27 20:31:04 2012 -0800 * | | * | | Merge branch 'first-branch' into second-branch * | | * | * commit 2224e191514cb4bd8c566d80dac22dfcb1e9bb83 * | | Author: Scott J. Goldman * | | Date: Tue Nov 27 20:28:51 2012 -0800 * | | * | | j * | | * | * commit a41a49f8f5cd9b6cb14a076bf8394881ed0b4d19 * | | Author: Scott J. Goldman * | | Date: Tue Nov 27 20:28:39 2012 -0800 * | | * | | i * | | * | * commit 82bf9a1a10a4b25c1f14c9607b60970705e92545 * | | Author: Scott J. Goldman * | | Date: Tue Nov 27 20:28:28 2012 -0800 * | | * | | h * | | * * | commit c37a783c20d92ac92362a78a32860f7eebf938ef * | | Author: Scott J. Goldman * | | Date: Tue Nov 27 20:30:57 2012 -0800 * | | * | | n * | | * * | commit 8b82fb1794cb1c8c7f172ec730a4c2db0ae3e650 * | | Author: Scott J. Goldman * | | Date: Tue Nov 27 20:30:43 2012 -0800 * | | * | | m * | | * * | commit 6ab5d28acbf3c3bdff276f7ccfdf29c1520e542f * | | Author: Scott J. Goldman * | | Date: Tue Nov 27 20:30:38 2012 -0800 * | | * | | l * | | * * | commit 7b8c336c45fc6895c1c60827260fe5d798e5d247 * | | Author: Scott J. Goldman * | | Date: Tue Nov 27 20:30:24 2012 -0800 * | | * | | k * | | * | | * commit 1c30b88f5f3ee66d78df6520a7de9e89b890818b * | | | Author: Scott J. Goldman * | | | Date: Tue Nov 27 20:28:10 2012 -0800 * | | | * | | | e * | | | * | | * commit 42b7311aa626e712891940c1ec5d5cba201946a4 * | | | Author: Scott J. Goldman * | | | Date: Tue Nov 27 20:28:06 2012 -0800 * | | | * | | | d * | | | * | | * commit a953a018c5b10b20c86e69fef55ebc8ad4c5a417 * | | |\ Merge: bd1732c cdf97fd * | | |/ Author: Scott J. Goldman * | |/| Date: Tue Nov 27 20:26:43 2012 -0800 * | | | * | | | Merge branch 'first-branch' * | | | * | * | commit cdf97fd3bb48eb3827638bb33d208f5fd32d0aa6 * | | | Author: Scott J. Goldman * | | | Date: Tue Nov 27 20:24:46 2012 -0800 * | | | * | | | g * | | | * | * | commit ef0488f0b722f0be8bcb90a7730ac7efafd1d694 * | | | Author: Scott J. Goldman * | | | Date: Tue Nov 27 20:24:39 2012 -0800 * | | | * | | | f * | | | * | | * commit bd1732c43c68d712ad09e1d872b9be6d4b9efdc4 * | |/ Author: Scott J. Goldman * | | Date: Tue Nov 27 17:43:58 2012 -0800 * | | * | | c * | | * | * commit 0c8a3f1f3d5f421cf83048c7c73ee3b55a5e0f29 * |/ Author: Scott J. Goldman * | Date: Tue Nov 27 17:43:48 2012 -0800 * | * | b * | * * commit 1f4c0311a24b63f6fc209a59a1e404942d4a5006 * Author: Scott J. Goldman * Date: Tue Nov 27 17:43:41 2012 -0800 * * a */ libgit2-0.19.0/tests-clar/revwalk/signatureparsing.c000066400000000000000000000024651216214232500224270ustar00rootroot00000000000000#include "clar_libgit2.h" static git_repository *_repo; static git_revwalk *_walk; void test_revwalk_signatureparsing__initialize(void) { cl_git_pass(git_repository_open(&_repo, cl_fixture("testrepo.git"))); cl_git_pass(git_revwalk_new(&_walk, _repo)); } void test_revwalk_signatureparsing__cleanup(void) { git_revwalk_free(_walk); _walk = NULL; git_repository_free(_repo); _repo = NULL; } void test_revwalk_signatureparsing__do_not_choke_when_name_contains_angle_brackets(void) { git_reference *ref; git_oid commit_oid; git_commit *commit; const git_signature *signature; /* * The branch below points at a commit with angle brackets in the committer/author name * committer 1323847743 +0100 */ cl_git_pass(git_reference_lookup(&ref, _repo, "refs/heads/haacked")); git_revwalk_push(_walk, git_reference_target(ref)); cl_git_pass(git_revwalk_next(&commit_oid, _walk)); cl_git_pass(git_commit_lookup(&commit, _repo, git_reference_target(ref))); signature = git_commit_committer(commit); cl_assert_equal_s("foo@example.com", signature->email); cl_assert_equal_s("", signature->name); cl_assert_equal_i(1323847743, (int)signature->when.time); cl_assert_equal_i(60, signature->when.offset); git_commit_free(commit); git_reference_free(ref); } libgit2-0.19.0/tests-clar/stash/000077500000000000000000000000001216214232500163365ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/stash/drop.c000066400000000000000000000110561216214232500174510ustar00rootroot00000000000000#include "clar_libgit2.h" #include "fileops.h" #include "stash_helpers.h" #include "refs.h" static git_repository *repo; static git_signature *signature; void test_stash_drop__initialize(void) { cl_git_pass(git_repository_init(&repo, "stash", 0)); cl_git_pass(git_signature_new(&signature, "nulltoken", "emeric.fermas@gmail.com", 1323847743, 60)); /* Wed Dec 14 08:29:03 2011 +0100 */ } void test_stash_drop__cleanup(void) { git_signature_free(signature); signature = NULL; git_repository_free(repo); repo = NULL; cl_git_pass(git_futils_rmdir_r("stash", NULL, GIT_RMDIR_REMOVE_FILES)); } void test_stash_drop__cannot_drop_from_an_empty_stash(void) { cl_git_fail_with(git_stash_drop(repo, 0), GIT_ENOTFOUND); } static void push_three_states(void) { git_oid oid; git_index *index; cl_git_mkfile("stash/zero.txt", "content\n"); cl_git_pass(git_repository_index(&index, repo)); cl_git_pass(git_index_add_bypath(index, "zero.txt")); commit_staged_files(&oid, index, signature); cl_assert(git_path_exists("stash/zero.txt")); cl_git_mkfile("stash/one.txt", "content\n"); cl_git_pass(git_stash_save(&oid, repo, signature, "First", GIT_STASH_INCLUDE_UNTRACKED)); cl_assert(!git_path_exists("stash/one.txt")); cl_assert(git_path_exists("stash/zero.txt")); cl_git_mkfile("stash/two.txt", "content\n"); cl_git_pass(git_stash_save(&oid, repo, signature, "Second", GIT_STASH_INCLUDE_UNTRACKED)); cl_assert(!git_path_exists("stash/two.txt")); cl_assert(git_path_exists("stash/zero.txt")); cl_git_mkfile("stash/three.txt", "content\n"); cl_git_pass(git_stash_save(&oid, repo, signature, "Third", GIT_STASH_INCLUDE_UNTRACKED)); cl_assert(!git_path_exists("stash/three.txt")); cl_assert(git_path_exists("stash/zero.txt")); git_index_free(index); } void test_stash_drop__cannot_drop_a_non_existing_stashed_state(void) { push_three_states(); cl_git_fail_with(git_stash_drop(repo, 666), GIT_ENOTFOUND); cl_git_fail_with(git_stash_drop(repo, 42), GIT_ENOTFOUND); cl_git_fail_with(git_stash_drop(repo, 3), GIT_ENOTFOUND); } void test_stash_drop__can_purge_the_stash_from_the_top(void) { push_three_states(); cl_git_pass(git_stash_drop(repo, 0)); cl_git_pass(git_stash_drop(repo, 0)); cl_git_pass(git_stash_drop(repo, 0)); cl_git_fail_with(git_stash_drop(repo, 0), GIT_ENOTFOUND); } void test_stash_drop__can_purge_the_stash_from_the_bottom(void) { push_three_states(); cl_git_pass(git_stash_drop(repo, 2)); cl_git_pass(git_stash_drop(repo, 1)); cl_git_pass(git_stash_drop(repo, 0)); cl_git_fail_with(git_stash_drop(repo, 0), GIT_ENOTFOUND); } void test_stash_drop__dropping_an_entry_rewrites_reflog_history(void) { git_reference *stash; git_reflog *reflog; const git_reflog_entry *entry; git_oid oid; size_t count; push_three_states(); cl_git_pass(git_reference_lookup(&stash, repo, GIT_REFS_STASH_FILE)); cl_git_pass(git_reflog_read(&reflog, stash)); entry = git_reflog_entry_byindex(reflog, 1); git_oid_cpy(&oid, git_reflog_entry_id_old(entry)); count = git_reflog_entrycount(reflog); git_reflog_free(reflog); cl_git_pass(git_stash_drop(repo, 1)); cl_git_pass(git_reflog_read(&reflog, stash)); entry = git_reflog_entry_byindex(reflog, 0); cl_assert_equal_i(0, git_oid_cmp(&oid, git_reflog_entry_id_old(entry))); cl_assert_equal_sz(count - 1, git_reflog_entrycount(reflog)); git_reflog_free(reflog); git_reference_free(stash); } void test_stash_drop__dropping_the_last_entry_removes_the_stash(void) { git_reference *stash; push_three_states(); cl_git_pass(git_reference_lookup(&stash, repo, GIT_REFS_STASH_FILE)); git_reference_free(stash); cl_git_pass(git_stash_drop(repo, 0)); cl_git_pass(git_stash_drop(repo, 0)); cl_git_pass(git_stash_drop(repo, 0)); cl_git_fail_with( git_reference_lookup(&stash, repo, GIT_REFS_STASH_FILE), GIT_ENOTFOUND); } void retrieve_top_stash_id(git_oid *out) { git_object *top_stash; cl_git_pass(git_revparse_single(&top_stash, repo, "stash@{0}")); cl_git_pass(git_reference_name_to_id(out, repo, GIT_REFS_STASH_FILE)); cl_assert_equal_i(true, git_oid_cmp(out, git_object_id(top_stash)) == 0); git_object_free(top_stash); } void test_stash_drop__dropping_the_top_stash_updates_the_stash_reference(void) { git_object *next_top_stash; git_oid oid; push_three_states(); retrieve_top_stash_id(&oid); cl_git_pass(git_revparse_single(&next_top_stash, repo, "stash@{1}")); cl_assert_equal_i(false, git_oid_cmp(&oid, git_object_id(next_top_stash)) == 0); cl_git_pass(git_stash_drop(repo, 0)); retrieve_top_stash_id(&oid); cl_git_pass(git_oid_cmp(&oid, git_object_id(next_top_stash))); git_object_free(next_top_stash); } libgit2-0.19.0/tests-clar/stash/foreach.c000066400000000000000000000050331216214232500201120ustar00rootroot00000000000000#include "clar_libgit2.h" #include "fileops.h" #include "stash_helpers.h" struct callback_data { char **oids; int invokes; }; static git_repository *repo; static git_signature *signature; static git_oid stash_tip_oid; struct callback_data data; #define REPO_NAME "stash" void test_stash_foreach__initialize(void) { cl_git_pass(git_signature_new( &signature, "nulltoken", "emeric.fermas@gmail.com", 1323847743, 60)); /* Wed Dec 14 08:29:03 2011 +0100 */ memset(&data, 0, sizeof(struct callback_data)); } void test_stash_foreach__cleanup(void) { git_signature_free(signature); signature = NULL; git_repository_free(repo); repo = NULL; cl_git_pass(git_futils_rmdir_r(REPO_NAME, NULL, GIT_RMDIR_REMOVE_FILES)); } static int callback_cb( size_t index, const char* message, const git_oid *stash_oid, void *payload) { struct callback_data *data = (struct callback_data *)payload; GIT_UNUSED(index); GIT_UNUSED(message); cl_assert_equal_i(0, git_oid_streq(stash_oid, data->oids[data->invokes++])); return 0; } void test_stash_foreach__enumerating_a_empty_repository_doesnt_fail(void) { char *oids[] = { NULL }; data.oids = oids; cl_git_pass(git_repository_init(&repo, REPO_NAME, 0)); cl_git_pass(git_stash_foreach(repo, callback_cb, &data)); cl_assert_equal_i(0, data.invokes); } void test_stash_foreach__can_enumerate_a_repository(void) { char *oids_default[] = { "1d91c842a7cdfc25872b3a763e5c31add8816c25", NULL }; char *oids_untracked[] = { "7f89a8b15c878809c5c54d1ff8f8c9674154017b", "1d91c842a7cdfc25872b3a763e5c31add8816c25", NULL }; char *oids_ignored[] = { "c95599a8fef20a7e57582c6727b1a0d02e0a5828", "7f89a8b15c878809c5c54d1ff8f8c9674154017b", "1d91c842a7cdfc25872b3a763e5c31add8816c25", NULL }; cl_git_pass(git_repository_init(&repo, REPO_NAME, 0)); setup_stash(repo, signature); cl_git_pass(git_stash_save( &stash_tip_oid, repo, signature, NULL, GIT_STASH_DEFAULT)); data.oids = oids_default; cl_git_pass(git_stash_foreach(repo, callback_cb, &data)); cl_assert_equal_i(1, data.invokes); data.oids = oids_untracked; data.invokes = 0; cl_git_pass(git_stash_save( &stash_tip_oid, repo, signature, NULL, GIT_STASH_INCLUDE_UNTRACKED)); cl_git_pass(git_stash_foreach(repo, callback_cb, &data)); cl_assert_equal_i(2, data.invokes); data.oids = oids_ignored; data.invokes = 0; cl_git_pass(git_stash_save( &stash_tip_oid, repo, signature, NULL, GIT_STASH_INCLUDE_IGNORED)); cl_git_pass(git_stash_foreach(repo, callback_cb, &data)); cl_assert_equal_i(3, data.invokes); } libgit2-0.19.0/tests-clar/stash/save.c000066400000000000000000000307011216214232500174410ustar00rootroot00000000000000#include "clar_libgit2.h" #include "fileops.h" #include "stash_helpers.h" static git_repository *repo; static git_signature *signature; static git_oid stash_tip_oid; /* * Friendly reminder, in order to ease the reading of the following tests: * * "stash" points to the worktree commit * "stash^1" points to the base commit (HEAD when the stash was created) * "stash^2" points to the index commit * "stash^3" points to the untracked commit */ void test_stash_save__initialize(void) { cl_git_pass(git_repository_init(&repo, "stash", 0)); cl_git_pass(git_signature_new(&signature, "nulltoken", "emeric.fermas@gmail.com", 1323847743, 60)); /* Wed Dec 14 08:29:03 2011 +0100 */ setup_stash(repo, signature); } void test_stash_save__cleanup(void) { git_signature_free(signature); signature = NULL; git_repository_free(repo); repo = NULL; cl_git_pass(git_futils_rmdir_r("stash", NULL, GIT_RMDIR_REMOVE_FILES)); cl_fixture_cleanup("sorry-it-is-a-non-bare-only-party"); } static void assert_object_oid(const char* revision, const char* expected_oid, git_otype type) { int result; git_object *obj; result = git_revparse_single(&obj, repo, revision); if (!expected_oid) { cl_assert_equal_i(GIT_ENOTFOUND, result); return; } else cl_assert_equal_i(0, result); cl_git_pass(git_oid_streq(git_object_id(obj), expected_oid)); cl_assert_equal_i(type, git_object_type(obj)); git_object_free(obj); } static void assert_blob_oid(const char* revision, const char* expected_oid) { assert_object_oid(revision, expected_oid, GIT_OBJ_BLOB); } void test_stash_save__does_not_keep_index_by_default(void) { /* $ git stash $ git show refs/stash:what see you later $ git show refs/stash:how not so small and $ git show refs/stash:who funky world $ git show refs/stash:when fatal: Path 'when' exists on disk, but not in 'stash'. $ git show refs/stash^2:what goodbye $ git show refs/stash^2:how not so small and $ git show refs/stash^2:who world $ git show refs/stash^2:when fatal: Path 'when' exists on disk, but not in 'stash^2'. $ git status --short ?? when */ unsigned int status; cl_git_pass(git_stash_save(&stash_tip_oid, repo, signature, NULL, GIT_STASH_DEFAULT)); cl_git_pass(git_status_file(&status, repo, "when")); assert_blob_oid("refs/stash:what", "bc99dc98b3eba0e9157e94769cd4d49cb49de449"); /* see you later */ assert_blob_oid("refs/stash:how", "e6d64adb2c7f3eb8feb493b556cc8070dca379a3"); /* not so small and */ assert_blob_oid("refs/stash:who", "a0400d4954659306a976567af43125a0b1aa8595"); /* funky world */ assert_blob_oid("refs/stash:when", NULL); assert_blob_oid("refs/stash:just.ignore", NULL); assert_blob_oid("refs/stash^2:what", "dd7e1c6f0fefe118f0b63d9f10908c460aa317a6"); /* goodbye */ assert_blob_oid("refs/stash^2:how", "e6d64adb2c7f3eb8feb493b556cc8070dca379a3"); /* not so small and */ assert_blob_oid("refs/stash^2:who", "cc628ccd10742baea8241c5924df992b5c019f71"); /* world */ assert_blob_oid("refs/stash^2:when", NULL); assert_blob_oid("refs/stash^2:just.ignore", NULL); assert_blob_oid("refs/stash^3", NULL); cl_assert_equal_i(GIT_STATUS_WT_NEW, status); } static void assert_status( const char *path, int status_flags) { unsigned int status; int error; error = git_status_file(&status, repo, path); if (status_flags < 0) { cl_assert_equal_i(status_flags, error); return; } cl_assert_equal_i(0, error); cl_assert_equal_i((unsigned int)status_flags, status); } void test_stash_save__can_keep_index(void) { cl_git_pass(git_stash_save(&stash_tip_oid, repo, signature, NULL, GIT_STASH_KEEP_INDEX)); assert_status("what", GIT_STATUS_INDEX_MODIFIED); assert_status("how", GIT_STATUS_INDEX_MODIFIED); assert_status("who", GIT_STATUS_CURRENT); assert_status("when", GIT_STATUS_WT_NEW); assert_status("just.ignore", GIT_STATUS_IGNORED); } static void assert_commit_message_contains(const char *revision, const char *fragment) { git_commit *commit; cl_git_pass(git_revparse_single((git_object**)&commit, repo, revision)); cl_assert(strstr(git_commit_message(commit), fragment) != NULL); git_commit_free(commit); } void test_stash_save__can_include_untracked_files(void) { cl_git_pass(git_stash_save(&stash_tip_oid, repo, signature, NULL, GIT_STASH_INCLUDE_UNTRACKED)); assert_commit_message_contains("refs/stash^3", "untracked files on master: "); assert_blob_oid("refs/stash^3:what", NULL); assert_blob_oid("refs/stash^3:how", NULL); assert_blob_oid("refs/stash^3:who", NULL); assert_blob_oid("refs/stash^3:when", "b6ed15e81e2593d7bb6265eb4a991d29dc3e628b"); assert_blob_oid("refs/stash^3:just.ignore", NULL); } void test_stash_save__can_include_untracked_and_ignored_files(void) { cl_git_pass(git_stash_save(&stash_tip_oid, repo, signature, NULL, GIT_STASH_INCLUDE_UNTRACKED | GIT_STASH_INCLUDE_IGNORED)); assert_commit_message_contains("refs/stash^3", "untracked files on master: "); assert_blob_oid("refs/stash^3:what", NULL); assert_blob_oid("refs/stash^3:how", NULL); assert_blob_oid("refs/stash^3:who", NULL); assert_blob_oid("refs/stash^3:when", "b6ed15e81e2593d7bb6265eb4a991d29dc3e628b"); assert_blob_oid("refs/stash^3:just.ignore", "78925fb1236b98b37a35e9723033e627f97aa88b"); } #define MESSAGE "Look Ma! I'm on TV!" void test_stash_save__can_accept_a_message(void) { cl_git_pass(git_stash_save(&stash_tip_oid, repo, signature, MESSAGE, GIT_STASH_DEFAULT)); assert_commit_message_contains("refs/stash^2", "index on master: "); assert_commit_message_contains("refs/stash", "On master: " MESSAGE); } void test_stash_save__cannot_stash_against_an_unborn_branch(void) { git_reference *head; cl_git_pass(git_reference_symbolic_create(&head, repo, "HEAD", "refs/heads/unborn", 1)); cl_assert_equal_i(GIT_EORPHANEDHEAD, git_stash_save(&stash_tip_oid, repo, signature, NULL, GIT_STASH_DEFAULT)); git_reference_free(head); } void test_stash_save__cannot_stash_against_a_bare_repository(void) { git_repository *local; cl_git_pass(git_repository_init(&local, "sorry-it-is-a-non-bare-only-party", 1)); cl_assert_equal_i(GIT_EBAREREPO, git_stash_save(&stash_tip_oid, local, signature, NULL, GIT_STASH_DEFAULT)); git_repository_free(local); } void test_stash_save__can_stash_against_a_detached_head(void) { git_repository_detach_head(repo); cl_git_pass(git_stash_save(&stash_tip_oid, repo, signature, NULL, GIT_STASH_DEFAULT)); assert_commit_message_contains("refs/stash^2", "index on (no branch): "); assert_commit_message_contains("refs/stash", "WIP on (no branch): "); } void test_stash_save__stashing_updates_the_reflog(void) { char *sha; assert_object_oid("refs/stash@{0}", NULL, GIT_OBJ_COMMIT); cl_git_pass(git_stash_save(&stash_tip_oid, repo, signature, NULL, GIT_STASH_DEFAULT)); sha = git_oid_allocfmt(&stash_tip_oid); assert_object_oid("refs/stash@{0}", sha, GIT_OBJ_COMMIT); assert_object_oid("refs/stash@{1}", NULL, GIT_OBJ_COMMIT); git__free(sha); } void test_stash_save__cannot_stash_when_there_are_no_local_change(void) { git_index *index; git_oid commit_oid, stash_tip_oid; cl_git_pass(git_repository_index(&index, repo)); /* * 'what' and 'who' are being committed. * 'when' remain untracked. */ cl_git_pass(git_index_add_bypath(index, "what")); cl_git_pass(git_index_add_bypath(index, "who")); cl_git_pass(git_index_write(index)); commit_staged_files(&commit_oid, index, signature); git_index_free(index); cl_assert_equal_i(GIT_ENOTFOUND, git_stash_save(&stash_tip_oid, repo, signature, NULL, GIT_STASH_DEFAULT)); p_unlink("stash/when"); cl_assert_equal_i(GIT_ENOTFOUND, git_stash_save(&stash_tip_oid, repo, signature, NULL, GIT_STASH_INCLUDE_UNTRACKED)); } void test_stash_save__can_stage_normal_then_stage_untracked(void) { /* * $ git ls-tree stash@{1}^0 * 100644 blob ac4d88de61733173d9959e4b77c69b9f17a00980 .gitignore * 100644 blob e6d64adb2c7f3eb8feb493b556cc8070dca379a3 how * 100644 blob bc99dc98b3eba0e9157e94769cd4d49cb49de449 what * 100644 blob a0400d4954659306a976567af43125a0b1aa8595 who * * $ git ls-tree stash@{1}^1 * 100644 blob ac4d88de61733173d9959e4b77c69b9f17a00980 .gitignore * 100644 blob ac790413e2d7a26c3767e78c57bb28716686eebc how * 100644 blob ce013625030ba8dba906f756967f9e9ca394464a what * 100644 blob cc628ccd10742baea8241c5924df992b5c019f71 who * * $ git ls-tree stash@{1}^2 * 100644 blob ac4d88de61733173d9959e4b77c69b9f17a00980 .gitignore * 100644 blob e6d64adb2c7f3eb8feb493b556cc8070dca379a3 how * 100644 blob dd7e1c6f0fefe118f0b63d9f10908c460aa317a6 what * 100644 blob cc628ccd10742baea8241c5924df992b5c019f71 who * * $ git ls-tree stash@{1}^3 * fatal: Not a valid object name stash@{1}^3 * * $ git ls-tree stash@{0}^0 * 100644 blob ac4d88de61733173d9959e4b77c69b9f17a00980 .gitignore * 100644 blob ac790413e2d7a26c3767e78c57bb28716686eebc how * 100644 blob ce013625030ba8dba906f756967f9e9ca394464a what * 100644 blob cc628ccd10742baea8241c5924df992b5c019f71 who * * $ git ls-tree stash@{0}^1 * 100644 blob ac4d88de61733173d9959e4b77c69b9f17a00980 .gitignore * 100644 blob ac790413e2d7a26c3767e78c57bb28716686eebc how * 100644 blob ce013625030ba8dba906f756967f9e9ca394464a what * 100644 blob cc628ccd10742baea8241c5924df992b5c019f71 who * * $ git ls-tree stash@{0}^2 * 100644 blob ac4d88de61733173d9959e4b77c69b9f17a00980 .gitignore * 100644 blob ac790413e2d7a26c3767e78c57bb28716686eebc how * 100644 blob ce013625030ba8dba906f756967f9e9ca394464a what * 100644 blob cc628ccd10742baea8241c5924df992b5c019f71 who * * $ git ls-tree stash@{0}^3 * 100644 blob b6ed15e81e2593d7bb6265eb4a991d29dc3e628b when */ assert_status("what", GIT_STATUS_WT_MODIFIED | GIT_STATUS_INDEX_MODIFIED); assert_status("how", GIT_STATUS_INDEX_MODIFIED); assert_status("who", GIT_STATUS_WT_MODIFIED); assert_status("when", GIT_STATUS_WT_NEW); assert_status("just.ignore", GIT_STATUS_IGNORED); cl_git_pass(git_stash_save(&stash_tip_oid, repo, signature, NULL, GIT_STASH_DEFAULT)); assert_status("what", GIT_STATUS_CURRENT); assert_status("how", GIT_STATUS_CURRENT); assert_status("who", GIT_STATUS_CURRENT); assert_status("when", GIT_STATUS_WT_NEW); assert_status("just.ignore", GIT_STATUS_IGNORED); cl_git_pass(git_stash_save(&stash_tip_oid, repo, signature, NULL, GIT_STASH_INCLUDE_UNTRACKED)); assert_status("what", GIT_STATUS_CURRENT); assert_status("how", GIT_STATUS_CURRENT); assert_status("who", GIT_STATUS_CURRENT); assert_status("when", GIT_ENOTFOUND); assert_status("just.ignore", GIT_STATUS_IGNORED); assert_blob_oid("stash@{1}^0:what", "bc99dc98b3eba0e9157e94769cd4d49cb49de449"); /* see you later */ assert_blob_oid("stash@{1}^0:how", "e6d64adb2c7f3eb8feb493b556cc8070dca379a3"); /* not so small and */ assert_blob_oid("stash@{1}^0:who", "a0400d4954659306a976567af43125a0b1aa8595"); /* funky world */ assert_blob_oid("stash@{1}^0:when", NULL); assert_blob_oid("stash@{1}^2:what", "dd7e1c6f0fefe118f0b63d9f10908c460aa317a6"); /* goodbye */ assert_blob_oid("stash@{1}^2:how", "e6d64adb2c7f3eb8feb493b556cc8070dca379a3"); /* not so small and */ assert_blob_oid("stash@{1}^2:who", "cc628ccd10742baea8241c5924df992b5c019f71"); /* world */ assert_blob_oid("stash@{1}^2:when", NULL); assert_object_oid("stash@{1}^3", NULL, GIT_OBJ_COMMIT); assert_blob_oid("stash@{0}^0:what", "ce013625030ba8dba906f756967f9e9ca394464a"); /* hello */ assert_blob_oid("stash@{0}^0:how", "ac790413e2d7a26c3767e78c57bb28716686eebc"); /* small */ assert_blob_oid("stash@{0}^0:who", "cc628ccd10742baea8241c5924df992b5c019f71"); /* world */ assert_blob_oid("stash@{0}^0:when", NULL); assert_blob_oid("stash@{0}^2:what", "ce013625030ba8dba906f756967f9e9ca394464a"); /* hello */ assert_blob_oid("stash@{0}^2:how", "ac790413e2d7a26c3767e78c57bb28716686eebc"); /* small */ assert_blob_oid("stash@{0}^2:who", "cc628ccd10742baea8241c5924df992b5c019f71"); /* world */ assert_blob_oid("stash@{0}^2:when", NULL); assert_blob_oid("stash@{0}^3:when", "b6ed15e81e2593d7bb6265eb4a991d29dc3e628b"); /* now */ } #define EMPTY_TREE "4b825dc642cb6eb9a060e54bf8d69288fbee4904" void test_stash_save__including_untracked_without_any_untracked_file_creates_an_empty_tree(void) { cl_git_pass(p_unlink("stash/when")); assert_status("what", GIT_STATUS_WT_MODIFIED | GIT_STATUS_INDEX_MODIFIED); assert_status("how", GIT_STATUS_INDEX_MODIFIED); assert_status("who", GIT_STATUS_WT_MODIFIED); assert_status("when", GIT_ENOTFOUND); assert_status("just.ignore", GIT_STATUS_IGNORED); cl_git_pass(git_stash_save(&stash_tip_oid, repo, signature, NULL, GIT_STASH_INCLUDE_UNTRACKED)); assert_object_oid("stash^3^{tree}", EMPTY_TREE, GIT_OBJ_TREE); } libgit2-0.19.0/tests-clar/stash/stash_helpers.c000066400000000000000000000040141216214232500213450ustar00rootroot00000000000000#include "clar_libgit2.h" #include "fileops.h" #include "stash_helpers.h" void commit_staged_files( git_oid *commit_oid, git_index *index, git_signature *signature) { git_tree *tree; git_oid tree_oid; git_repository *repo; repo = git_index_owner(index); cl_git_pass(git_index_write_tree(&tree_oid, index)); cl_git_pass(git_tree_lookup(&tree, repo, &tree_oid)); cl_git_pass(git_commit_create_v( commit_oid, repo, "HEAD", signature, signature, NULL, "Initial commit", tree, 0)); git_tree_free(tree); } void setup_stash(git_repository *repo, git_signature *signature) { git_oid commit_oid; git_index *index; cl_git_pass(git_repository_index(&index, repo)); cl_git_mkfile("stash/what", "hello\n"); /* ce013625030ba8dba906f756967f9e9ca394464a */ cl_git_mkfile("stash/how", "small\n"); /* ac790413e2d7a26c3767e78c57bb28716686eebc */ cl_git_mkfile("stash/who", "world\n"); /* cc628ccd10742baea8241c5924df992b5c019f71 */ cl_git_mkfile("stash/when", "now\n"); /* b6ed15e81e2593d7bb6265eb4a991d29dc3e628b */ cl_git_mkfile("stash/just.ignore", "me\n"); /* 78925fb1236b98b37a35e9723033e627f97aa88b */ cl_git_mkfile("stash/.gitignore", "*.ignore\n"); cl_git_pass(git_index_add_bypath(index, "what")); cl_git_pass(git_index_add_bypath(index, "how")); cl_git_pass(git_index_add_bypath(index, "who")); cl_git_pass(git_index_add_bypath(index, ".gitignore")); cl_git_pass(git_index_write(index)); commit_staged_files(&commit_oid, index, signature); cl_git_rewritefile("stash/what", "goodbye\n"); /* dd7e1c6f0fefe118f0b63d9f10908c460aa317a6 */ cl_git_rewritefile("stash/how", "not so small and\n"); /* e6d64adb2c7f3eb8feb493b556cc8070dca379a3 */ cl_git_rewritefile("stash/who", "funky world\n"); /* a0400d4954659306a976567af43125a0b1aa8595 */ cl_git_pass(git_index_add_bypath(index, "what")); cl_git_pass(git_index_add_bypath(index, "how")); cl_git_pass(git_index_write(index)); cl_git_rewritefile("stash/what", "see you later\n"); /* bc99dc98b3eba0e9157e94769cd4d49cb49de449 */ git_index_free(index); } libgit2-0.19.0/tests-clar/stash/stash_helpers.h000066400000000000000000000002441216214232500213530ustar00rootroot00000000000000void setup_stash( git_repository *repo, git_signature *signature); void commit_staged_files( git_oid *commit_oid, git_index *index, git_signature *signature);libgit2-0.19.0/tests-clar/status/000077500000000000000000000000001216214232500165375ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/status/ignore.c000066400000000000000000000345461216214232500202020ustar00rootroot00000000000000#include "clar_libgit2.h" #include "fileops.h" #include "git2/attr.h" #include "ignore.h" #include "attr.h" #include "status_helpers.h" static git_repository *g_repo = NULL; void test_status_ignore__initialize(void) { } void test_status_ignore__cleanup(void) { cl_git_sandbox_cleanup(); } void test_status_ignore__0(void) { struct { const char *path; int expected; } test_cases[] = { /* pattern "ign" from .gitignore */ { "file", 0 }, { "ign", 1 }, { "sub", 0 }, { "sub/file", 0 }, { "sub/ign", 1 }, { "sub/ign/file", 1 }, { "sub/ign/sub", 1 }, { "sub/ign/sub/file", 1 }, { "sub/sub", 0 }, { "sub/sub/file", 0 }, { "sub/sub/ign", 1 }, { "sub/sub/sub", 0 }, /* pattern "dir/" from .gitignore */ { "dir", 1 }, { "dir/", 1 }, { "sub/dir", 1 }, { "sub/dir/", 1 }, { "sub/dir/file", 1 }, /* contained in ignored parent */ { "sub/sub/dir", 0 }, /* dir is not actually a dir, but a file */ { NULL, 0 } }, *one_test; g_repo = cl_git_sandbox_init("attr"); for (one_test = test_cases; one_test->path != NULL; one_test++) { int ignored; cl_git_pass(git_status_should_ignore(&ignored, g_repo, one_test->path)); cl_assert_(ignored == one_test->expected, one_test->path); } /* confirm that ignore files were cached */ cl_assert(git_attr_cache__is_cached(g_repo, 0, ".git/info/exclude")); cl_assert(git_attr_cache__is_cached(g_repo, 0, ".gitignore")); } void test_status_ignore__1(void) { int ignored; g_repo = cl_git_sandbox_init("attr"); cl_git_rewritefile("attr/.gitignore", "/*.txt\n/dir/\n"); git_attr_cache_flush(g_repo); cl_git_pass(git_status_should_ignore(&ignored, g_repo, "root_test4.txt")); cl_assert(ignored); cl_git_pass(git_status_should_ignore(&ignored, g_repo, "sub/subdir_test2.txt")); cl_assert(!ignored); cl_git_pass(git_status_should_ignore(&ignored, g_repo, "dir")); cl_assert(ignored); cl_git_pass(git_status_should_ignore(&ignored, g_repo, "dir/")); cl_assert(ignored); cl_git_pass(git_status_should_ignore(&ignored, g_repo, "sub/dir")); cl_assert(!ignored); cl_git_pass(git_status_should_ignore(&ignored, g_repo, "sub/dir/")); cl_assert(!ignored); } void test_status_ignore__empty_repo_with_gitignore_rewrite(void) { status_entry_single st; int ignored; g_repo = cl_git_sandbox_init("empty_standard_repo"); cl_git_mkfile( "empty_standard_repo/look-ma.txt", "I'm going to be ignored!"); memset(&st, 0, sizeof(st)); cl_git_pass(git_status_foreach(g_repo, cb_status__single, &st)); cl_assert(st.count == 1); cl_assert(st.status == GIT_STATUS_WT_NEW); cl_git_pass(git_status_file(&st.status, g_repo, "look-ma.txt")); cl_assert(st.status == GIT_STATUS_WT_NEW); cl_git_pass(git_status_should_ignore(&ignored, g_repo, "look-ma.txt")); cl_assert(!ignored); cl_git_rewritefile("empty_standard_repo/.gitignore", "*.nomatch\n"); memset(&st, 0, sizeof(st)); cl_git_pass(git_status_foreach(g_repo, cb_status__single, &st)); cl_assert(st.count == 2); cl_assert(st.status == GIT_STATUS_WT_NEW); cl_git_pass(git_status_file(&st.status, g_repo, "look-ma.txt")); cl_assert(st.status == GIT_STATUS_WT_NEW); cl_git_pass(git_status_should_ignore(&ignored, g_repo, "look-ma.txt")); cl_assert(!ignored); cl_git_rewritefile("empty_standard_repo/.gitignore", "*.txt\n"); memset(&st, 0, sizeof(st)); cl_git_pass(git_status_foreach(g_repo, cb_status__single, &st)); cl_assert(st.count == 2); cl_assert(st.status == GIT_STATUS_IGNORED); cl_git_pass(git_status_file(&st.status, g_repo, "look-ma.txt")); cl_assert(st.status == GIT_STATUS_IGNORED); cl_git_pass(git_status_should_ignore(&ignored, g_repo, "look-ma.txt")); cl_assert(ignored); } void test_status_ignore__ignore_pattern_contains_space(void) { unsigned int flags; const mode_t mode = 0777; g_repo = cl_git_sandbox_init("empty_standard_repo"); cl_git_rewritefile("empty_standard_repo/.gitignore", "foo bar.txt\n"); cl_git_mkfile( "empty_standard_repo/foo bar.txt", "I'm going to be ignored!"); cl_git_pass(git_status_file(&flags, g_repo, "foo bar.txt")); cl_assert(flags == GIT_STATUS_IGNORED); cl_git_pass(git_futils_mkdir_r("empty_standard_repo/foo", NULL, mode)); cl_git_mkfile("empty_standard_repo/foo/look-ma.txt", "I'm not going to be ignored!"); cl_git_pass(git_status_file(&flags, g_repo, "foo/look-ma.txt")); cl_assert(flags == GIT_STATUS_WT_NEW); } void test_status_ignore__ignore_pattern_ignorecase(void) { unsigned int flags; bool ignore_case; git_index *index; g_repo = cl_git_sandbox_init("empty_standard_repo"); cl_git_rewritefile("empty_standard_repo/.gitignore", "a.txt\n"); cl_git_mkfile("empty_standard_repo/A.txt", "Differs in case"); cl_git_pass(git_repository_index(&index, g_repo)); ignore_case = (git_index_caps(index) & GIT_INDEXCAP_IGNORE_CASE) != 0; git_index_free(index); cl_git_pass(git_status_file(&flags, g_repo, "A.txt")); cl_assert(flags == ignore_case ? GIT_STATUS_IGNORED : GIT_STATUS_WT_NEW); } void test_status_ignore__subdirectories(void) { status_entry_single st; int ignored; g_repo = cl_git_sandbox_init("empty_standard_repo"); cl_git_mkfile( "empty_standard_repo/ignore_me", "I'm going to be ignored!"); cl_git_rewritefile("empty_standard_repo/.gitignore", "ignore_me\n"); memset(&st, 0, sizeof(st)); cl_git_pass(git_status_foreach(g_repo, cb_status__single, &st)); cl_assert_equal_i(2, st.count); cl_assert(st.status == GIT_STATUS_IGNORED); cl_git_pass(git_status_file(&st.status, g_repo, "ignore_me")); cl_assert(st.status == GIT_STATUS_IGNORED); cl_git_pass(git_status_should_ignore(&ignored, g_repo, "ignore_me")); cl_assert(ignored); /* I've changed libgit2 so that the behavior here now differs from * core git but seems to make more sense. In core git, the following * items are skipped completed, even if --ignored is passed to status. * It you mirror these steps and run "git status -uall --ignored" then * you will not see "test/ignore_me/" in the results. * * However, we had a couple reports of this as a bug, plus there is a * similar circumstance where we were differing for core git when you * used a rooted path for an ignore, so I changed this behavior. */ cl_git_pass(git_futils_mkdir_r( "empty_standard_repo/test/ignore_me", NULL, 0775)); cl_git_mkfile( "empty_standard_repo/test/ignore_me/file", "I'm going to be ignored!"); cl_git_mkfile( "empty_standard_repo/test/ignore_me/file2", "Me, too!"); memset(&st, 0, sizeof(st)); cl_git_pass(git_status_foreach(g_repo, cb_status__single, &st)); cl_assert_equal_i(3, st.count); cl_git_pass(git_status_file(&st.status, g_repo, "test/ignore_me/file")); cl_assert(st.status == GIT_STATUS_IGNORED); cl_git_pass( git_status_should_ignore(&ignored, g_repo, "test/ignore_me/file")); cl_assert(ignored); } void test_status_ignore__subdirectories_recursion(void) { /* Let's try again with recursing into ignored dirs turned on */ git_status_options opts = GIT_STATUS_OPTIONS_INIT; status_entry_counts counts; static const char *paths_r[] = { ".gitignore", "ignore_also/file", "ignore_me", "test/ignore_me/and_me/file", "test/ignore_me/file", "test/ignore_me/file2", }; static const unsigned int statuses_r[] = { GIT_STATUS_WT_NEW, GIT_STATUS_IGNORED, GIT_STATUS_IGNORED, GIT_STATUS_IGNORED, GIT_STATUS_IGNORED, GIT_STATUS_IGNORED, }; static const char *paths_nr[] = { ".gitignore", "ignore_also/", "ignore_me", "test/ignore_me/", }; static const unsigned int statuses_nr[] = { GIT_STATUS_WT_NEW, GIT_STATUS_IGNORED, GIT_STATUS_IGNORED, GIT_STATUS_IGNORED, }; g_repo = cl_git_sandbox_init("empty_standard_repo"); cl_git_rewritefile("empty_standard_repo/.gitignore", "ignore_me\n/ignore_also\n"); cl_git_mkfile( "empty_standard_repo/ignore_me", "I'm going to be ignored!"); cl_git_pass(git_futils_mkdir_r( "empty_standard_repo/test/ignore_me", NULL, 0775)); cl_git_mkfile( "empty_standard_repo/test/ignore_me/file", "I'm going to be ignored!"); cl_git_mkfile( "empty_standard_repo/test/ignore_me/file2", "Me, too!"); cl_git_pass(git_futils_mkdir_r( "empty_standard_repo/test/ignore_me/and_me", NULL, 0775)); cl_git_mkfile( "empty_standard_repo/test/ignore_me/and_me/file", "Deeply ignored"); cl_git_pass(git_futils_mkdir_r( "empty_standard_repo/ignore_also", NULL, 0775)); cl_git_mkfile( "empty_standard_repo/ignore_also/file", "I'm going to be ignored!"); memset(&counts, 0x0, sizeof(status_entry_counts)); counts.expected_entry_count = 6; counts.expected_paths = paths_r; counts.expected_statuses = statuses_r; opts.flags = GIT_STATUS_OPT_DEFAULTS | GIT_STATUS_OPT_RECURSE_IGNORED_DIRS; cl_git_pass(git_status_foreach_ext( g_repo, &opts, cb_status__normal, &counts)); cl_assert_equal_i(counts.expected_entry_count, counts.entry_count); cl_assert_equal_i(0, counts.wrong_status_flags_count); cl_assert_equal_i(0, counts.wrong_sorted_path); memset(&counts, 0x0, sizeof(status_entry_counts)); counts.expected_entry_count = 4; counts.expected_paths = paths_nr; counts.expected_statuses = statuses_nr; opts.flags = GIT_STATUS_OPT_DEFAULTS; cl_git_pass(git_status_foreach_ext( g_repo, &opts, cb_status__normal, &counts)); cl_assert_equal_i(counts.expected_entry_count, counts.entry_count); cl_assert_equal_i(0, counts.wrong_status_flags_count); cl_assert_equal_i(0, counts.wrong_sorted_path); } void test_status_ignore__adding_internal_ignores(void) { int ignored; g_repo = cl_git_sandbox_init("empty_standard_repo"); cl_git_pass(git_status_should_ignore(&ignored, g_repo, "one.txt")); cl_assert(!ignored); cl_git_pass(git_status_should_ignore(&ignored, g_repo, "two.bar")); cl_assert(!ignored); cl_git_pass(git_ignore_add_rule(g_repo, "*.nomatch\n")); cl_git_pass(git_status_should_ignore(&ignored, g_repo, "one.txt")); cl_assert(!ignored); cl_git_pass(git_status_should_ignore(&ignored, g_repo, "two.bar")); cl_assert(!ignored); cl_git_pass(git_ignore_add_rule(g_repo, "*.txt\n")); cl_git_pass(git_status_should_ignore(&ignored, g_repo, "one.txt")); cl_assert(ignored); cl_git_pass(git_status_should_ignore(&ignored, g_repo, "two.bar")); cl_assert(!ignored); cl_git_pass(git_ignore_add_rule(g_repo, "*.bar\n")); cl_git_pass(git_status_should_ignore(&ignored, g_repo, "one.txt")); cl_assert(ignored); cl_git_pass(git_status_should_ignore(&ignored, g_repo, "two.bar")); cl_assert(ignored); cl_git_pass(git_ignore_clear_internal_rules(g_repo)); cl_git_pass(git_status_should_ignore(&ignored, g_repo, "one.txt")); cl_assert(!ignored); cl_git_pass(git_status_should_ignore(&ignored, g_repo, "two.bar")); cl_assert(!ignored); cl_git_pass(git_ignore_add_rule( g_repo, "multiple\n*.rules\n# comment line\n*.bar\n")); cl_git_pass(git_status_should_ignore(&ignored, g_repo, "one.txt")); cl_assert(!ignored); cl_git_pass(git_status_should_ignore(&ignored, g_repo, "two.bar")); cl_assert(ignored); } void test_status_ignore__add_internal_as_first_thing(void) { int ignored; const char *add_me = "\n#################\n## Eclipse\n#################\n\n*.pydevproject\n.project\n.metadata\nbin/\ntmp/\n*.tmp\n\n"; g_repo = cl_git_sandbox_init("empty_standard_repo"); cl_git_pass(git_ignore_add_rule(g_repo, add_me)); cl_git_pass(git_status_should_ignore(&ignored, g_repo, "one.tmp")); cl_assert(ignored); cl_git_pass(git_status_should_ignore(&ignored, g_repo, "two.bar")); cl_assert(!ignored); } void test_status_ignore__internal_ignores_inside_deep_paths(void) { int ignored; const char *add_me = "Debug\nthis/is/deep\npatterned*/dir\n"; g_repo = cl_git_sandbox_init("empty_standard_repo"); cl_git_pass(git_ignore_add_rule(g_repo, add_me)); cl_git_pass(git_status_should_ignore(&ignored, g_repo, "Debug")); cl_assert(ignored); cl_git_pass(git_status_should_ignore(&ignored, g_repo, "and/Debug")); cl_assert(ignored); cl_git_pass(git_status_should_ignore(&ignored, g_repo, "really/Debug/this/file")); cl_assert(ignored); cl_git_pass(git_status_should_ignore(&ignored, g_repo, "Debug/what/I/say")); cl_assert(ignored); cl_git_pass(git_status_should_ignore(&ignored, g_repo, "and/NoDebug")); cl_assert(!ignored); cl_git_pass(git_status_should_ignore(&ignored, g_repo, "NoDebug/this")); cl_assert(!ignored); cl_git_pass(git_status_should_ignore(&ignored, g_repo, "please/NoDebug/this")); cl_assert(!ignored); cl_git_pass(git_status_should_ignore(&ignored, g_repo, "this/is/deep")); cl_assert(ignored); /* pattern containing slash gets FNM_PATHNAME so all slashes must match */ cl_git_pass(git_status_should_ignore(&ignored, g_repo, "and/this/is/deep")); cl_assert(!ignored); cl_git_pass(git_status_should_ignore(&ignored, g_repo, "this/is/deep/too")); cl_assert(ignored); /* pattern containing slash gets FNM_PATHNAME so all slashes must match */ cl_git_pass(git_status_should_ignore(&ignored, g_repo, "but/this/is/deep/and/ignored")); cl_assert(!ignored); cl_git_pass(git_status_should_ignore(&ignored, g_repo, "this/is/not/deep")); cl_assert(!ignored); cl_git_pass(git_status_should_ignore(&ignored, g_repo, "is/this/not/as/deep")); cl_assert(!ignored); cl_git_pass(git_status_should_ignore(&ignored, g_repo, "this/is/deepish")); cl_assert(!ignored); cl_git_pass(git_status_should_ignore(&ignored, g_repo, "xthis/is/deep")); cl_assert(!ignored); } void test_status_ignore__automatically_ignore_bad_files(void) { int ignored; g_repo = cl_git_sandbox_init("empty_standard_repo"); cl_git_pass(git_status_should_ignore(&ignored, g_repo, ".git")); cl_assert(ignored); cl_git_pass(git_status_should_ignore(&ignored, g_repo, "this/file/.")); cl_assert(ignored); cl_git_pass(git_status_should_ignore(&ignored, g_repo, "path/../funky")); cl_assert(ignored); cl_git_pass(git_status_should_ignore(&ignored, g_repo, "path/whatever.c")); cl_assert(!ignored); cl_git_pass(git_ignore_add_rule(g_repo, "*.c\n")); cl_git_pass(git_status_should_ignore(&ignored, g_repo, ".git")); cl_assert(ignored); cl_git_pass(git_status_should_ignore(&ignored, g_repo, "this/file/.")); cl_assert(ignored); cl_git_pass(git_status_should_ignore(&ignored, g_repo, "path/../funky")); cl_assert(ignored); cl_git_pass(git_status_should_ignore(&ignored, g_repo, "path/whatever.c")); cl_assert(ignored); cl_git_pass(git_ignore_clear_internal_rules(g_repo)); cl_git_pass(git_status_should_ignore(&ignored, g_repo, ".git")); cl_assert(ignored); cl_git_pass(git_status_should_ignore(&ignored, g_repo, "this/file/.")); cl_assert(ignored); cl_git_pass(git_status_should_ignore(&ignored, g_repo, "path/../funky")); cl_assert(ignored); cl_git_pass(git_status_should_ignore(&ignored, g_repo, "path/whatever.c")); cl_assert(!ignored); } libgit2-0.19.0/tests-clar/status/renames.c000066400000000000000000000307751216214232500203510ustar00rootroot00000000000000#include "clar_libgit2.h" #include "buffer.h" #include "path.h" #include "posix.h" #include "status_helpers.h" #include "util.h" #include "status.h" static git_repository *g_repo = NULL; void test_status_renames__initialize(void) { g_repo = cl_git_sandbox_init("renames"); } void test_status_renames__cleanup(void) { cl_git_sandbox_cleanup(); } static void rename_file(git_repository *repo, const char *oldname, const char *newname) { git_buf oldpath = GIT_BUF_INIT, newpath = GIT_BUF_INIT; git_buf_joinpath(&oldpath, git_repository_workdir(repo), oldname); git_buf_joinpath(&newpath, git_repository_workdir(repo), newname); cl_git_pass(p_rename(oldpath.ptr, newpath.ptr)); git_buf_free(&oldpath); git_buf_free(&newpath); } static void rename_and_edit_file(git_repository *repo, const char *oldname, const char *newname) { git_buf oldpath = GIT_BUF_INIT, newpath = GIT_BUF_INIT; git_buf_joinpath(&oldpath, git_repository_workdir(repo), oldname); git_buf_joinpath(&newpath, git_repository_workdir(repo), newname); cl_git_pass(p_rename(oldpath.ptr, newpath.ptr)); cl_git_append2file(newpath.ptr, "Added at the end to keep similarity!"); git_buf_free(&oldpath); git_buf_free(&newpath); } struct status_entry { git_status_t status; const char *oldname; const char *newname; }; static void test_status( git_status_list *status_list, struct status_entry *expected_list, size_t expected_len) { const git_status_entry *actual; const struct status_entry *expected; const char *oldname, *newname; size_t i; cl_assert_equal_sz(expected_len, git_status_list_entrycount(status_list)); for (i = 0; i < expected_len; i++) { actual = git_status_byindex(status_list, i); expected = &expected_list[i]; cl_assert_equal_i((int)expected->status, (int)actual->status); oldname = actual->head_to_index ? actual->head_to_index->old_file.path : actual->index_to_workdir ? actual->index_to_workdir->old_file.path : NULL; newname = actual->index_to_workdir ? actual->index_to_workdir->new_file.path : actual->head_to_index ? actual->head_to_index->new_file.path : NULL; if (oldname) cl_assert(git__strcmp(oldname, expected->oldname) == 0); else cl_assert(expected->oldname == NULL); if (newname) cl_assert(git__strcmp(newname, expected->newname) == 0); else cl_assert(expected->newname == NULL); } } void test_status_renames__head2index_one(void) { git_index *index; git_status_list *statuslist; git_status_options opts = GIT_STATUS_OPTIONS_INIT; struct status_entry expected[] = { { GIT_STATUS_INDEX_RENAMED, "ikeepsix.txt", "newname.txt" }, }; opts.flags |= GIT_STATUS_OPT_RENAMES_HEAD_TO_INDEX; cl_git_pass(git_repository_index(&index, g_repo)); rename_file(g_repo, "ikeepsix.txt", "newname.txt"); cl_git_pass(git_index_remove_bypath(index, "ikeepsix.txt")); cl_git_pass(git_index_add_bypath(index, "newname.txt")); cl_git_pass(git_index_write(index)); cl_git_pass(git_status_list_new(&statuslist, g_repo, &opts)); test_status(statuslist, expected, 1); git_status_list_free(statuslist); git_index_free(index); } void test_status_renames__head2index_two(void) { git_index *index; git_status_list *statuslist; git_status_options opts = GIT_STATUS_OPTIONS_INIT; struct status_entry expected[] = { { GIT_STATUS_INDEX_RENAMED | GIT_STATUS_INDEX_MODIFIED, "sixserving.txt", "aaa.txt" }, { GIT_STATUS_INDEX_RENAMED | GIT_STATUS_INDEX_MODIFIED, "untimely.txt", "bbb.txt" }, { GIT_STATUS_INDEX_RENAMED, "songof7cities.txt", "ccc.txt" }, { GIT_STATUS_INDEX_RENAMED, "ikeepsix.txt", "ddd.txt" }, }; opts.flags |= GIT_STATUS_OPT_RENAMES_HEAD_TO_INDEX; cl_git_pass(git_repository_index(&index, g_repo)); rename_file(g_repo, "ikeepsix.txt", "ddd.txt"); rename_and_edit_file(g_repo, "sixserving.txt", "aaa.txt"); rename_file(g_repo, "songof7cities.txt", "ccc.txt"); rename_and_edit_file(g_repo, "untimely.txt", "bbb.txt"); cl_git_pass(git_index_remove_bypath(index, "ikeepsix.txt")); cl_git_pass(git_index_remove_bypath(index, "sixserving.txt")); cl_git_pass(git_index_remove_bypath(index, "songof7cities.txt")); cl_git_pass(git_index_remove_bypath(index, "untimely.txt")); cl_git_pass(git_index_add_bypath(index, "ddd.txt")); cl_git_pass(git_index_add_bypath(index, "aaa.txt")); cl_git_pass(git_index_add_bypath(index, "ccc.txt")); cl_git_pass(git_index_add_bypath(index, "bbb.txt")); cl_git_pass(git_index_write(index)); cl_git_pass(git_status_list_new(&statuslist, g_repo, &opts)); test_status(statuslist, expected, 4); git_status_list_free(statuslist); git_index_free(index); } void test_status_renames__index2workdir_one(void) { git_status_list *statuslist; git_status_options opts = GIT_STATUS_OPTIONS_INIT; struct status_entry expected[] = { { GIT_STATUS_WT_RENAMED, "ikeepsix.txt", "newname.txt" }, }; opts.flags |= GIT_STATUS_OPT_INCLUDE_UNTRACKED; opts.flags |= GIT_STATUS_OPT_RENAMES_INDEX_TO_WORKDIR; rename_file(g_repo, "ikeepsix.txt", "newname.txt"); cl_git_pass(git_status_list_new(&statuslist, g_repo, &opts)); test_status(statuslist, expected, 1); git_status_list_free(statuslist); } void test_status_renames__index2workdir_two(void) { git_status_list *statuslist; git_status_options opts = GIT_STATUS_OPTIONS_INIT; struct status_entry expected[] = { { GIT_STATUS_WT_RENAMED | GIT_STATUS_WT_MODIFIED, "sixserving.txt", "aaa.txt" }, { GIT_STATUS_WT_RENAMED | GIT_STATUS_WT_MODIFIED, "untimely.txt", "bbb.txt" }, { GIT_STATUS_WT_RENAMED, "songof7cities.txt", "ccc.txt" }, { GIT_STATUS_WT_RENAMED, "ikeepsix.txt", "ddd.txt" }, }; opts.flags |= GIT_STATUS_OPT_INCLUDE_UNTRACKED; opts.flags |= GIT_STATUS_OPT_RENAMES_INDEX_TO_WORKDIR; rename_file(g_repo, "ikeepsix.txt", "ddd.txt"); rename_and_edit_file(g_repo, "sixserving.txt", "aaa.txt"); rename_file(g_repo, "songof7cities.txt", "ccc.txt"); rename_and_edit_file(g_repo, "untimely.txt", "bbb.txt"); cl_git_pass(git_status_list_new(&statuslist, g_repo, &opts)); test_status(statuslist, expected, 4); git_status_list_free(statuslist); } void test_status_renames__both_one(void) { git_index *index; git_status_list *statuslist; git_status_options opts = GIT_STATUS_OPTIONS_INIT; struct status_entry expected[] = { { GIT_STATUS_INDEX_RENAMED | GIT_STATUS_WT_RENAMED, "ikeepsix.txt", "newname-workdir.txt" }, }; opts.flags |= GIT_STATUS_OPT_INCLUDE_UNTRACKED; opts.flags |= GIT_STATUS_OPT_RENAMES_HEAD_TO_INDEX; opts.flags |= GIT_STATUS_OPT_RENAMES_INDEX_TO_WORKDIR; cl_git_pass(git_repository_index(&index, g_repo)); rename_file(g_repo, "ikeepsix.txt", "newname-index.txt"); cl_git_pass(git_index_remove_bypath(index, "ikeepsix.txt")); cl_git_pass(git_index_add_bypath(index, "newname-index.txt")); cl_git_pass(git_index_write(index)); rename_file(g_repo, "newname-index.txt", "newname-workdir.txt"); cl_git_pass(git_status_list_new(&statuslist, g_repo, &opts)); test_status(statuslist, expected, 1); git_status_list_free(statuslist); git_index_free(index); } void test_status_renames__both_two(void) { git_index *index; git_status_list *statuslist; git_status_options opts = GIT_STATUS_OPTIONS_INIT; struct status_entry expected[] = { { GIT_STATUS_INDEX_RENAMED | GIT_STATUS_INDEX_MODIFIED | GIT_STATUS_WT_RENAMED | GIT_STATUS_WT_MODIFIED, "ikeepsix.txt", "ikeepsix-both.txt" }, { GIT_STATUS_INDEX_RENAMED | GIT_STATUS_INDEX_MODIFIED, "sixserving.txt", "sixserving-index.txt" }, { GIT_STATUS_WT_RENAMED | GIT_STATUS_WT_MODIFIED, "songof7cities.txt", "songof7cities-workdir.txt" }, { GIT_STATUS_INDEX_RENAMED | GIT_STATUS_WT_RENAMED, "untimely.txt", "untimely-both.txt" }, }; opts.flags |= GIT_STATUS_OPT_INCLUDE_UNTRACKED; opts.flags |= GIT_STATUS_OPT_RENAMES_HEAD_TO_INDEX; opts.flags |= GIT_STATUS_OPT_RENAMES_INDEX_TO_WORKDIR; cl_git_pass(git_repository_index(&index, g_repo)); rename_and_edit_file(g_repo, "ikeepsix.txt", "ikeepsix-index.txt"); rename_and_edit_file(g_repo, "sixserving.txt", "sixserving-index.txt"); rename_file(g_repo, "untimely.txt", "untimely-index.txt"); cl_git_pass(git_index_remove_bypath(index, "ikeepsix.txt")); cl_git_pass(git_index_remove_bypath(index, "sixserving.txt")); cl_git_pass(git_index_remove_bypath(index, "untimely.txt")); cl_git_pass(git_index_add_bypath(index, "ikeepsix-index.txt")); cl_git_pass(git_index_add_bypath(index, "sixserving-index.txt")); cl_git_pass(git_index_add_bypath(index, "untimely-index.txt")); cl_git_pass(git_index_write(index)); rename_and_edit_file(g_repo, "ikeepsix-index.txt", "ikeepsix-both.txt"); rename_and_edit_file(g_repo, "songof7cities.txt", "songof7cities-workdir.txt"); rename_file(g_repo, "untimely-index.txt", "untimely-both.txt"); cl_git_pass(git_status_list_new(&statuslist, g_repo, &opts)); test_status(statuslist, expected, 4); git_status_list_free(statuslist); git_index_free(index); } void test_status_renames__both_casechange_one(void) { git_index *index; git_status_list *statuslist; git_status_options opts = GIT_STATUS_OPTIONS_INIT; int index_caps; struct status_entry expected_icase[] = { { GIT_STATUS_INDEX_RENAMED, "ikeepsix.txt", "IKeepSix.txt" }, }; struct status_entry expected_case[] = { { GIT_STATUS_INDEX_RENAMED | GIT_STATUS_WT_RENAMED, "ikeepsix.txt", "IKEEPSIX.txt" }, }; opts.flags |= GIT_STATUS_OPT_INCLUDE_UNTRACKED; opts.flags |= GIT_STATUS_OPT_RENAMES_HEAD_TO_INDEX; opts.flags |= GIT_STATUS_OPT_RENAMES_INDEX_TO_WORKDIR; cl_git_pass(git_repository_index(&index, g_repo)); index_caps = git_index_caps(index); rename_file(g_repo, "ikeepsix.txt", "IKeepSix.txt"); cl_git_pass(git_index_remove_bypath(index, "ikeepsix.txt")); cl_git_pass(git_index_add_bypath(index, "IKeepSix.txt")); cl_git_pass(git_index_write(index)); /* on a case-insensitive file system, this change won't matter. * on a case-sensitive one, it will. */ rename_file(g_repo, "IKeepSix.txt", "IKEEPSIX.txt"); cl_git_pass(git_status_list_new(&statuslist, g_repo, &opts)); test_status(statuslist, (index_caps & GIT_INDEXCAP_IGNORE_CASE) ? expected_icase : expected_case, 1); git_status_list_free(statuslist); git_index_free(index); } void test_status_renames__both_casechange_two(void) { git_index *index; git_status_list *statuslist; git_status_options opts = GIT_STATUS_OPTIONS_INIT; int index_caps; struct status_entry expected_icase[] = { { GIT_STATUS_INDEX_RENAMED | GIT_STATUS_INDEX_MODIFIED | GIT_STATUS_WT_MODIFIED, "ikeepsix.txt", "IKeepSix.txt" }, { GIT_STATUS_INDEX_MODIFIED, "sixserving.txt", "sixserving.txt" }, { GIT_STATUS_INDEX_RENAMED | GIT_STATUS_WT_MODIFIED, "songof7cities.txt", "songof7.txt" }, { GIT_STATUS_INDEX_RENAMED | GIT_STATUS_WT_RENAMED, "untimely.txt", "untimeliest.txt" } }; struct status_entry expected_case[] = { { GIT_STATUS_INDEX_RENAMED | GIT_STATUS_INDEX_MODIFIED | GIT_STATUS_WT_RENAMED | GIT_STATUS_WT_MODIFIED, "ikeepsix.txt", "ikeepsix.txt" }, { GIT_STATUS_INDEX_MODIFIED | GIT_STATUS_WT_RENAMED, "sixserving.txt", "SixServing.txt" }, { GIT_STATUS_INDEX_RENAMED | GIT_STATUS_WT_MODIFIED | GIT_STATUS_WT_RENAMED, "songof7cities.txt", "SONGOF7.txt" }, { GIT_STATUS_INDEX_RENAMED | GIT_STATUS_WT_RENAMED, "untimely.txt", "untimeliest.txt" } }; opts.flags |= GIT_STATUS_OPT_INCLUDE_UNTRACKED; opts.flags |= GIT_STATUS_OPT_RENAMES_HEAD_TO_INDEX; opts.flags |= GIT_STATUS_OPT_RENAMES_INDEX_TO_WORKDIR; cl_git_pass(git_repository_index(&index, g_repo)); index_caps = git_index_caps(index); rename_and_edit_file(g_repo, "ikeepsix.txt", "IKeepSix.txt"); rename_and_edit_file(g_repo, "sixserving.txt", "sixserving.txt"); rename_file(g_repo, "songof7cities.txt", "songof7.txt"); rename_file(g_repo, "untimely.txt", "untimelier.txt"); cl_git_pass(git_index_remove_bypath(index, "ikeepsix.txt")); cl_git_pass(git_index_remove_bypath(index, "sixserving.txt")); cl_git_pass(git_index_remove_bypath(index, "songof7cities.txt")); cl_git_pass(git_index_remove_bypath(index, "untimely.txt")); cl_git_pass(git_index_add_bypath(index, "IKeepSix.txt")); cl_git_pass(git_index_add_bypath(index, "sixserving.txt")); cl_git_pass(git_index_add_bypath(index, "songof7.txt")); cl_git_pass(git_index_add_bypath(index, "untimelier.txt")); cl_git_pass(git_index_write(index)); rename_and_edit_file(g_repo, "IKeepSix.txt", "ikeepsix.txt"); rename_file(g_repo, "sixserving.txt", "SixServing.txt"); rename_and_edit_file(g_repo, "songof7.txt", "SONGOF7.txt"); rename_file(g_repo, "untimelier.txt", "untimeliest.txt"); cl_git_pass(git_status_list_new(&statuslist, g_repo, &opts)); test_status(statuslist, (index_caps & GIT_INDEXCAP_IGNORE_CASE) ? expected_icase : expected_case, 4); git_status_list_free(statuslist); git_index_free(index); } libgit2-0.19.0/tests-clar/status/single.c000066400000000000000000000025261216214232500201710ustar00rootroot00000000000000#include "clar_libgit2.h" #include "posix.h" static void cleanup__remove_file(void *_file) { cl_must_pass(p_unlink((char *)_file)); } /* test retrieving OID from a file apart from the ODB */ void test_status_single__hash_single_file(void) { static const char file_name[] = "new_file"; static const char file_contents[] = "new_file\n"; static const char file_hash[] = "d4fa8600b4f37d7516bef4816ae2c64dbf029e3a"; git_oid expected_id, actual_id; /* initialization */ git_oid_fromstr(&expected_id, file_hash); cl_git_mkfile(file_name, file_contents); cl_set_cleanup(&cleanup__remove_file, (void *)file_name); cl_git_pass(git_odb_hashfile(&actual_id, file_name, GIT_OBJ_BLOB)); cl_assert(git_oid_cmp(&expected_id, &actual_id) == 0); } /* test retrieving OID from an empty file apart from the ODB */ void test_status_single__hash_single_empty_file(void) { static const char file_name[] = "new_empty_file"; static const char file_contents[] = ""; static const char file_hash[] = "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391"; git_oid expected_id, actual_id; /* initialization */ git_oid_fromstr(&expected_id, file_hash); cl_git_mkfile(file_name, file_contents); cl_set_cleanup(&cleanup__remove_file, (void *)file_name); cl_git_pass(git_odb_hashfile(&actual_id, file_name, GIT_OBJ_BLOB)); cl_assert(git_oid_cmp(&expected_id, &actual_id) == 0); } libgit2-0.19.0/tests-clar/status/status_data.h000066400000000000000000000141111216214232500212220ustar00rootroot00000000000000#include "status_helpers.h" /* entries for a plain copy of tests/resources/status */ static const char *entry_paths0[] = { "file_deleted", "ignored_file", "modified_file", "new_file", "staged_changes", "staged_changes_file_deleted", "staged_changes_modified_file", "staged_delete_file_deleted", "staged_delete_modified_file", "staged_new_file", "staged_new_file_deleted_file", "staged_new_file_modified_file", "subdir/deleted_file", "subdir/modified_file", "subdir/new_file", "\xe8\xbf\x99", }; static const unsigned int entry_statuses0[] = { GIT_STATUS_WT_DELETED, GIT_STATUS_IGNORED, GIT_STATUS_WT_MODIFIED, GIT_STATUS_WT_NEW, GIT_STATUS_INDEX_MODIFIED, GIT_STATUS_INDEX_MODIFIED | GIT_STATUS_WT_DELETED, GIT_STATUS_INDEX_MODIFIED | GIT_STATUS_WT_MODIFIED, GIT_STATUS_INDEX_DELETED, GIT_STATUS_INDEX_DELETED | GIT_STATUS_WT_NEW, GIT_STATUS_INDEX_NEW, GIT_STATUS_INDEX_NEW | GIT_STATUS_WT_DELETED, GIT_STATUS_INDEX_NEW | GIT_STATUS_WT_MODIFIED, GIT_STATUS_WT_DELETED, GIT_STATUS_WT_MODIFIED, GIT_STATUS_WT_NEW, GIT_STATUS_WT_NEW, }; static const int entry_count0 = 16; /* entries for a copy of tests/resources/status with all content * deleted from the working directory */ static const char *entry_paths2[] = { "current_file", "file_deleted", "modified_file", "staged_changes", "staged_changes_file_deleted", "staged_changes_modified_file", "staged_delete_file_deleted", "staged_delete_modified_file", "staged_new_file", "staged_new_file_deleted_file", "staged_new_file_modified_file", "subdir.txt", "subdir/current_file", "subdir/deleted_file", "subdir/modified_file", }; static const unsigned int entry_statuses2[] = { GIT_STATUS_WT_DELETED, GIT_STATUS_WT_DELETED, GIT_STATUS_WT_DELETED, GIT_STATUS_WT_DELETED | GIT_STATUS_INDEX_MODIFIED, GIT_STATUS_WT_DELETED | GIT_STATUS_INDEX_MODIFIED, GIT_STATUS_WT_DELETED | GIT_STATUS_INDEX_MODIFIED, GIT_STATUS_INDEX_DELETED, GIT_STATUS_INDEX_DELETED, GIT_STATUS_WT_DELETED | GIT_STATUS_INDEX_NEW, GIT_STATUS_WT_DELETED | GIT_STATUS_INDEX_NEW, GIT_STATUS_WT_DELETED | GIT_STATUS_INDEX_NEW, GIT_STATUS_WT_DELETED, GIT_STATUS_WT_DELETED, GIT_STATUS_WT_DELETED, GIT_STATUS_WT_DELETED, }; static const int entry_count2 = 15; /* entries for a copy of tests/resources/status with some mods */ static const char *entry_paths3_icase[] = { ".HEADER", "42-is-not-prime.sigh", "current_file", "current_file/", "file_deleted", "ignored_file", "modified_file", "new_file", "README.md", "staged_changes", "staged_changes_file_deleted", "staged_changes_modified_file", "staged_delete_file_deleted", "staged_delete_modified_file", "staged_new_file", "staged_new_file_deleted_file", "staged_new_file_modified_file", "subdir", "subdir/current_file", "subdir/deleted_file", "subdir/modified_file", "\xe8\xbf\x99", }; static const unsigned int entry_statuses3_icase[] = { GIT_STATUS_WT_NEW, GIT_STATUS_WT_NEW, GIT_STATUS_WT_DELETED, GIT_STATUS_WT_NEW, GIT_STATUS_WT_DELETED, GIT_STATUS_IGNORED, GIT_STATUS_WT_MODIFIED, GIT_STATUS_WT_NEW, GIT_STATUS_WT_NEW, GIT_STATUS_INDEX_MODIFIED, GIT_STATUS_WT_DELETED | GIT_STATUS_INDEX_MODIFIED, GIT_STATUS_WT_MODIFIED | GIT_STATUS_INDEX_MODIFIED, GIT_STATUS_INDEX_DELETED, GIT_STATUS_WT_NEW | GIT_STATUS_INDEX_DELETED, GIT_STATUS_INDEX_NEW, GIT_STATUS_WT_DELETED | GIT_STATUS_INDEX_NEW, GIT_STATUS_WT_MODIFIED | GIT_STATUS_INDEX_NEW, GIT_STATUS_WT_NEW, GIT_STATUS_WT_DELETED, GIT_STATUS_WT_DELETED, GIT_STATUS_WT_DELETED, GIT_STATUS_WT_NEW, }; static const char *entry_paths3[] = { ".HEADER", "42-is-not-prime.sigh", "README.md", "current_file", "current_file/", "file_deleted", "ignored_file", "modified_file", "new_file", "staged_changes", "staged_changes_file_deleted", "staged_changes_modified_file", "staged_delete_file_deleted", "staged_delete_modified_file", "staged_new_file", "staged_new_file_deleted_file", "staged_new_file_modified_file", "subdir", "subdir/current_file", "subdir/deleted_file", "subdir/modified_file", "\xe8\xbf\x99", }; static const unsigned int entry_statuses3[] = { GIT_STATUS_WT_NEW, GIT_STATUS_WT_NEW, GIT_STATUS_WT_NEW, GIT_STATUS_WT_DELETED, GIT_STATUS_WT_NEW, GIT_STATUS_WT_DELETED, GIT_STATUS_IGNORED, GIT_STATUS_WT_MODIFIED, GIT_STATUS_WT_NEW, GIT_STATUS_INDEX_MODIFIED, GIT_STATUS_WT_DELETED | GIT_STATUS_INDEX_MODIFIED, GIT_STATUS_WT_MODIFIED | GIT_STATUS_INDEX_MODIFIED, GIT_STATUS_INDEX_DELETED, GIT_STATUS_WT_NEW | GIT_STATUS_INDEX_DELETED, GIT_STATUS_INDEX_NEW, GIT_STATUS_WT_DELETED | GIT_STATUS_INDEX_NEW, GIT_STATUS_WT_MODIFIED | GIT_STATUS_INDEX_NEW, GIT_STATUS_WT_NEW, GIT_STATUS_WT_DELETED, GIT_STATUS_WT_DELETED, GIT_STATUS_WT_DELETED, GIT_STATUS_WT_NEW, }; static const int entry_count3 = 22; /* entries for a copy of tests/resources/status with some mods * and different options to the status call */ static const char *entry_paths4[] = { ".new_file", "current_file", "current_file/current_file", "current_file/modified_file", "current_file/new_file", "file_deleted", "modified_file", "new_file", "staged_changes", "staged_changes_file_deleted", "staged_changes_modified_file", "staged_delete_file_deleted", "staged_delete_modified_file", "staged_new_file", "staged_new_file_deleted_file", "staged_new_file_modified_file", "subdir", "subdir/current_file", "subdir/deleted_file", "subdir/modified_file", "zzz_new_dir/new_file", "zzz_new_file", "\xe8\xbf\x99", }; static const unsigned int entry_statuses4[] = { GIT_STATUS_WT_NEW, GIT_STATUS_WT_DELETED, GIT_STATUS_WT_NEW, GIT_STATUS_WT_NEW, GIT_STATUS_WT_NEW, GIT_STATUS_WT_DELETED, GIT_STATUS_WT_MODIFIED, GIT_STATUS_WT_NEW, GIT_STATUS_INDEX_MODIFIED, GIT_STATUS_WT_DELETED | GIT_STATUS_INDEX_MODIFIED, GIT_STATUS_WT_MODIFIED | GIT_STATUS_INDEX_MODIFIED, GIT_STATUS_INDEX_DELETED, GIT_STATUS_WT_NEW | GIT_STATUS_INDEX_DELETED, GIT_STATUS_INDEX_NEW, GIT_STATUS_WT_DELETED | GIT_STATUS_INDEX_NEW, GIT_STATUS_WT_MODIFIED | GIT_STATUS_INDEX_NEW, GIT_STATUS_WT_NEW, GIT_STATUS_WT_DELETED, GIT_STATUS_WT_DELETED, GIT_STATUS_WT_DELETED, GIT_STATUS_WT_NEW, GIT_STATUS_WT_NEW, GIT_STATUS_WT_NEW, }; static const int entry_count4 = 23; libgit2-0.19.0/tests-clar/status/status_helpers.c000066400000000000000000000041711216214232500217530ustar00rootroot00000000000000#include "clar_libgit2.h" #include "status_helpers.h" int cb_status__normal( const char *path, unsigned int status_flags, void *payload) { status_entry_counts *counts = payload; if (counts->debug) cb_status__print(path, status_flags, NULL); if (counts->entry_count >= counts->expected_entry_count) { counts->wrong_status_flags_count++; goto exit; } if (strcmp(path, counts->expected_paths[counts->entry_count])) { counts->wrong_sorted_path++; goto exit; } if (status_flags != counts->expected_statuses[counts->entry_count]) counts->wrong_status_flags_count++; exit: counts->entry_count++; return 0; } int cb_status__count(const char *p, unsigned int s, void *payload) { volatile int *count = (int *)payload; GIT_UNUSED(p); GIT_UNUSED(s); (*count)++; return 0; } int cb_status__single(const char *p, unsigned int s, void *payload) { status_entry_single *data = (status_entry_single *)payload; if (data->debug) fprintf(stderr, "%02d: %s (%04x)\n", data->count, p, s); data->count++; data->status = s; return 0; } int cb_status__print( const char *path, unsigned int status_flags, void *payload) { char istatus = ' ', wstatus = ' '; int icount = 0, wcount = 0; if (status_flags & GIT_STATUS_INDEX_NEW) { istatus = 'A'; icount++; } if (status_flags & GIT_STATUS_INDEX_MODIFIED) { istatus = 'M'; icount++; } if (status_flags & GIT_STATUS_INDEX_DELETED) { istatus = 'D'; icount++; } if (status_flags & GIT_STATUS_INDEX_RENAMED) { istatus = 'R'; icount++; } if (status_flags & GIT_STATUS_INDEX_TYPECHANGE) { istatus = 'T'; icount++; } if (status_flags & GIT_STATUS_WT_NEW) { wstatus = 'A'; wcount++; } if (status_flags & GIT_STATUS_WT_MODIFIED) { wstatus = 'M'; wcount++; } if (status_flags & GIT_STATUS_WT_DELETED) { wstatus = 'D'; wcount++; } if (status_flags & GIT_STATUS_WT_TYPECHANGE) { wstatus = 'T'; wcount++; } if (status_flags & GIT_STATUS_IGNORED) { wstatus = 'I'; wcount++; } fprintf(stderr, "%c%c %s (%d/%d%s)\n", istatus, wstatus, path, icount, wcount, (icount > 1 || wcount > 1) ? " INVALID COMBO" : ""); if (payload) *((int *)payload) += 1; return 0; } libgit2-0.19.0/tests-clar/status/status_helpers.h000066400000000000000000000016771216214232500217700ustar00rootroot00000000000000#ifndef INCLUDE_cl_status_helpers_h__ #define INCLUDE_cl_status_helpers_h__ typedef struct { int wrong_status_flags_count; int wrong_sorted_path; int entry_count; const unsigned int* expected_statuses; const char** expected_paths; int expected_entry_count; bool debug; } status_entry_counts; /* cb_status__normal takes payload of "status_entry_counts *" */ extern int cb_status__normal( const char *path, unsigned int status_flags, void *payload); /* cb_status__count takes payload of "int *" */ extern int cb_status__count(const char *p, unsigned int s, void *payload); typedef struct { int count; unsigned int status; bool debug; } status_entry_single; /* cb_status__single takes payload of "status_entry_single *" */ extern int cb_status__single(const char *p, unsigned int s, void *payload); /* cb_status__print takes optional payload of "int *" */ extern int cb_status__print(const char *p, unsigned int s, void *payload); #endif libgit2-0.19.0/tests-clar/status/submodules.c000066400000000000000000000130141216214232500210640ustar00rootroot00000000000000#include "clar_libgit2.h" #include "buffer.h" #include "path.h" #include "posix.h" #include "status_helpers.h" #include "../submodule/submodule_helpers.h" static git_repository *g_repo = NULL; void test_status_submodules__initialize(void) { g_repo = cl_git_sandbox_init("submodules"); cl_fixture_sandbox("testrepo.git"); rewrite_gitmodules(git_repository_workdir(g_repo)); p_rename("submodules/testrepo/.gitted", "submodules/testrepo/.git"); } void test_status_submodules__cleanup(void) { cl_git_sandbox_cleanup(); cl_fixture_cleanup("testrepo.git"); } void test_status_submodules__api(void) { git_submodule *sm; cl_assert(git_submodule_lookup(NULL, g_repo, "nonexistent") == GIT_ENOTFOUND); cl_assert(git_submodule_lookup(NULL, g_repo, "modified") == GIT_ENOTFOUND); cl_git_pass(git_submodule_lookup(&sm, g_repo, "testrepo")); cl_assert(sm != NULL); cl_assert_equal_s("testrepo", git_submodule_name(sm)); cl_assert_equal_s("testrepo", git_submodule_path(sm)); } void test_status_submodules__0(void) { int counts = 0; cl_assert(git_path_isdir("submodules/.git")); cl_assert(git_path_isdir("submodules/testrepo/.git")); cl_assert(git_path_isfile("submodules/.gitmodules")); cl_git_pass( git_status_foreach(g_repo, cb_status__count, &counts) ); cl_assert_equal_i(6, counts); } static const char *expected_files[] = { ".gitmodules", "added", "deleted", "ignored", "modified", "untracked" }; static unsigned int expected_status[] = { GIT_STATUS_WT_MODIFIED, GIT_STATUS_INDEX_NEW, GIT_STATUS_INDEX_DELETED, GIT_STATUS_IGNORED, GIT_STATUS_WT_MODIFIED, GIT_STATUS_WT_NEW }; static int cb_status__match(const char *p, unsigned int s, void *payload) { status_entry_counts *counts = payload; int idx = counts->entry_count++; cl_assert_equal_s(counts->expected_paths[idx], p); cl_assert(counts->expected_statuses[idx] == s); return 0; } void test_status_submodules__1(void) { status_entry_counts counts; cl_assert(git_path_isdir("submodules/.git")); cl_assert(git_path_isdir("submodules/testrepo/.git")); cl_assert(git_path_isfile("submodules/.gitmodules")); memset(&counts, 0, sizeof(counts)); counts.expected_paths = expected_files; counts.expected_statuses = expected_status; cl_git_pass( git_status_foreach(g_repo, cb_status__match, &counts) ); cl_assert_equal_i(6, counts.entry_count); } void test_status_submodules__single_file(void) { unsigned int status = 0; cl_git_pass( git_status_file(&status, g_repo, "testrepo") ); cl_assert(!status); } void test_status_submodules__moved_head(void) { git_submodule *sm; git_repository *smrepo; git_oid oid; git_status_options opts = GIT_STATUS_OPTIONS_INIT; status_entry_counts counts; static const char *expected_files_with_sub[] = { ".gitmodules", "added", "deleted", "ignored", "modified", "testrepo", "untracked" }; static unsigned int expected_status_with_sub[] = { GIT_STATUS_WT_MODIFIED, GIT_STATUS_INDEX_NEW, GIT_STATUS_INDEX_DELETED, GIT_STATUS_IGNORED, GIT_STATUS_WT_MODIFIED, GIT_STATUS_WT_MODIFIED, GIT_STATUS_WT_NEW }; cl_git_pass(git_submodule_lookup(&sm, g_repo, "testrepo")); cl_git_pass(git_submodule_open(&smrepo, sm)); /* move submodule HEAD to c47800c7266a2be04c571c04d5a6614691ea99bd */ cl_git_pass( git_oid_fromstr(&oid, "c47800c7266a2be04c571c04d5a6614691ea99bd")); cl_git_pass(git_repository_set_head_detached(smrepo, &oid)); /* first do a normal status, which should now include the submodule */ memset(&counts, 0, sizeof(counts)); counts.expected_paths = expected_files_with_sub; counts.expected_statuses = expected_status_with_sub; opts.flags = GIT_STATUS_OPT_DEFAULTS; cl_git_pass( git_status_foreach_ext(g_repo, &opts, cb_status__match, &counts)); cl_assert_equal_i(7, counts.entry_count); /* try again with EXCLUDE_SUBMODULES which should skip it */ memset(&counts, 0, sizeof(counts)); counts.expected_paths = expected_files; counts.expected_statuses = expected_status; opts.flags = GIT_STATUS_OPT_DEFAULTS | GIT_STATUS_OPT_EXCLUDE_SUBMODULES; cl_git_pass( git_status_foreach_ext(g_repo, &opts, cb_status__match, &counts)); cl_assert_equal_i(6, counts.entry_count); git_repository_free(smrepo); } void test_status_submodules__dirty_workdir_only(void) { git_status_options opts = GIT_STATUS_OPTIONS_INIT; status_entry_counts counts; static const char *expected_files_with_sub[] = { ".gitmodules", "added", "deleted", "ignored", "modified", "testrepo", "untracked" }; static unsigned int expected_status_with_sub[] = { GIT_STATUS_WT_MODIFIED, GIT_STATUS_INDEX_NEW, GIT_STATUS_INDEX_DELETED, GIT_STATUS_IGNORED, GIT_STATUS_WT_MODIFIED, GIT_STATUS_WT_MODIFIED, GIT_STATUS_WT_NEW }; cl_git_rewritefile("submodules/testrepo/README", "heyheyhey"); cl_git_mkfile("submodules/testrepo/all_new.txt", "never seen before"); /* first do a normal status, which should now include the submodule */ memset(&counts, 0, sizeof(counts)); counts.expected_paths = expected_files_with_sub; counts.expected_statuses = expected_status_with_sub; opts.flags = GIT_STATUS_OPT_DEFAULTS; cl_git_pass( git_status_foreach_ext(g_repo, &opts, cb_status__match, &counts)); cl_assert_equal_i(7, counts.entry_count); /* try again with EXCLUDE_SUBMODULES which should skip it */ memset(&counts, 0, sizeof(counts)); counts.expected_paths = expected_files; counts.expected_statuses = expected_status; opts.flags = GIT_STATUS_OPT_DEFAULTS | GIT_STATUS_OPT_EXCLUDE_SUBMODULES; cl_git_pass( git_status_foreach_ext(g_repo, &opts, cb_status__match, &counts)); cl_assert_equal_i(6, counts.entry_count); } libgit2-0.19.0/tests-clar/status/worktree.c000066400000000000000000000575051216214232500205610ustar00rootroot00000000000000#include "clar_libgit2.h" #include "fileops.h" #include "ignore.h" #include "status_data.h" #include "posix.h" #include "util.h" #include "path.h" /** * Cleanup * * This will be called once after each test finishes, even * if the test failed */ void test_status_worktree__cleanup(void) { cl_git_sandbox_cleanup(); } /** * Tests - Status determination on a working tree */ /* this test is equivalent to t18-status.c:statuscb0 */ void test_status_worktree__whole_repository(void) { status_entry_counts counts; git_repository *repo = cl_git_sandbox_init("status"); memset(&counts, 0x0, sizeof(status_entry_counts)); counts.expected_entry_count = entry_count0; counts.expected_paths = entry_paths0; counts.expected_statuses = entry_statuses0; cl_git_pass( git_status_foreach(repo, cb_status__normal, &counts) ); cl_assert_equal_i(counts.expected_entry_count, counts.entry_count); cl_assert_equal_i(0, counts.wrong_status_flags_count); cl_assert_equal_i(0, counts.wrong_sorted_path); } /* this test is equivalent to t18-status.c:statuscb1 */ void test_status_worktree__empty_repository(void) { int count = 0; git_repository *repo = cl_git_sandbox_init("empty_standard_repo"); cl_git_pass(git_status_foreach(repo, cb_status__count, &count)); cl_assert_equal_i(0, count); } static int remove_file_cb(void *data, git_buf *file) { const char *filename = git_buf_cstr(file); GIT_UNUSED(data); if (git__suffixcmp(filename, ".git") == 0) return 0; if (git_path_isdir(filename)) cl_git_pass(git_futils_rmdir_r(filename, NULL, GIT_RMDIR_REMOVE_FILES)); else cl_git_pass(p_unlink(git_buf_cstr(file))); return 0; } /* this test is equivalent to t18-status.c:statuscb2 */ void test_status_worktree__purged_worktree(void) { status_entry_counts counts; git_repository *repo = cl_git_sandbox_init("status"); git_buf workdir = GIT_BUF_INIT; /* first purge the contents of the worktree */ cl_git_pass(git_buf_sets(&workdir, git_repository_workdir(repo))); cl_git_pass(git_path_direach(&workdir, remove_file_cb, NULL)); git_buf_free(&workdir); /* now get status */ memset(&counts, 0x0, sizeof(status_entry_counts)); counts.expected_entry_count = entry_count2; counts.expected_paths = entry_paths2; counts.expected_statuses = entry_statuses2; cl_git_pass( git_status_foreach(repo, cb_status__normal, &counts) ); cl_assert_equal_i(counts.expected_entry_count, counts.entry_count); cl_assert_equal_i(0, counts.wrong_status_flags_count); cl_assert_equal_i(0, counts.wrong_sorted_path); } /* this test is similar to t18-status.c:statuscb3 */ void test_status_worktree__swap_subdir_and_file(void) { status_entry_counts counts; git_repository *repo = cl_git_sandbox_init("status"); git_index *index; git_status_options opts = GIT_STATUS_OPTIONS_INIT; bool ignore_case; cl_git_pass(git_repository_index(&index, repo)); ignore_case = (git_index_caps(index) & GIT_INDEXCAP_IGNORE_CASE) != 0; git_index_free(index); /* first alter the contents of the worktree */ cl_git_pass(p_rename("status/current_file", "status/swap")); cl_git_pass(p_rename("status/subdir", "status/current_file")); cl_git_pass(p_rename("status/swap", "status/subdir")); cl_git_mkfile("status/.HEADER", "dummy"); cl_git_mkfile("status/42-is-not-prime.sigh", "dummy"); cl_git_mkfile("status/README.md", "dummy"); /* now get status */ memset(&counts, 0x0, sizeof(status_entry_counts)); counts.expected_entry_count = entry_count3; counts.expected_paths = ignore_case ? entry_paths3_icase : entry_paths3; counts.expected_statuses = ignore_case ? entry_statuses3_icase : entry_statuses3; opts.flags = GIT_STATUS_OPT_INCLUDE_UNTRACKED | GIT_STATUS_OPT_INCLUDE_IGNORED; cl_git_pass( git_status_foreach_ext(repo, &opts, cb_status__normal, &counts) ); cl_assert_equal_i(counts.expected_entry_count, counts.entry_count); cl_assert_equal_i(0, counts.wrong_status_flags_count); cl_assert_equal_i(0, counts.wrong_sorted_path); } void test_status_worktree__swap_subdir_with_recurse_and_pathspec(void) { status_entry_counts counts; git_repository *repo = cl_git_sandbox_init("status"); git_status_options opts = GIT_STATUS_OPTIONS_INIT; /* first alter the contents of the worktree */ cl_git_pass(p_rename("status/current_file", "status/swap")); cl_git_pass(p_rename("status/subdir", "status/current_file")); cl_git_pass(p_rename("status/swap", "status/subdir")); cl_git_mkfile("status/.new_file", "dummy"); cl_git_pass(git_futils_mkdir_r("status/zzz_new_dir", NULL, 0777)); cl_git_mkfile("status/zzz_new_dir/new_file", "dummy"); cl_git_mkfile("status/zzz_new_file", "dummy"); /* now get status */ memset(&counts, 0x0, sizeof(status_entry_counts)); counts.expected_entry_count = entry_count4; counts.expected_paths = entry_paths4; counts.expected_statuses = entry_statuses4; opts.flags = GIT_STATUS_OPT_INCLUDE_UNTRACKED | GIT_STATUS_OPT_RECURSE_UNTRACKED_DIRS; /* TODO: set pathspec to "current_file" eventually */ cl_git_pass( git_status_foreach_ext(repo, &opts, cb_status__normal, &counts) ); cl_assert_equal_i(counts.expected_entry_count, counts.entry_count); cl_assert_equal_i(0, counts.wrong_status_flags_count); cl_assert_equal_i(0, counts.wrong_sorted_path); } /* this test is equivalent to t18-status.c:singlestatus0 */ void test_status_worktree__single_file(void) { int i; unsigned int status_flags; git_repository *repo = cl_git_sandbox_init("status"); for (i = 0; i < (int)entry_count0; i++) { cl_git_pass( git_status_file(&status_flags, repo, entry_paths0[i]) ); cl_assert(entry_statuses0[i] == status_flags); } } /* this test is equivalent to t18-status.c:singlestatus1 */ void test_status_worktree__single_nonexistent_file(void) { int error; unsigned int status_flags; git_repository *repo = cl_git_sandbox_init("status"); error = git_status_file(&status_flags, repo, "nonexistent"); cl_git_fail(error); cl_assert(error == GIT_ENOTFOUND); } /* this test is equivalent to t18-status.c:singlestatus2 */ void test_status_worktree__single_nonexistent_file_empty_repo(void) { int error; unsigned int status_flags; git_repository *repo = cl_git_sandbox_init("empty_standard_repo"); error = git_status_file(&status_flags, repo, "nonexistent"); cl_git_fail(error); cl_assert(error == GIT_ENOTFOUND); } /* this test is equivalent to t18-status.c:singlestatus3 */ void test_status_worktree__single_file_empty_repo(void) { unsigned int status_flags; git_repository *repo = cl_git_sandbox_init("empty_standard_repo"); cl_git_mkfile("empty_standard_repo/new_file", "new_file\n"); cl_git_pass(git_status_file(&status_flags, repo, "new_file")); cl_assert(status_flags == GIT_STATUS_WT_NEW); } /* this test is equivalent to t18-status.c:singlestatus4 */ void test_status_worktree__single_folder(void) { int error; unsigned int status_flags; git_repository *repo = cl_git_sandbox_init("status"); error = git_status_file(&status_flags, repo, "subdir"); cl_git_fail(error); cl_assert(error != GIT_ENOTFOUND); } void test_status_worktree__ignores(void) { int i, ignored; git_repository *repo = cl_git_sandbox_init("status"); for (i = 0; i < (int)entry_count0; i++) { cl_git_pass( git_status_should_ignore(&ignored, repo, entry_paths0[i]) ); cl_assert(ignored == (entry_statuses0[i] == GIT_STATUS_IGNORED)); } cl_git_pass( git_status_should_ignore(&ignored, repo, "nonexistent_file") ); cl_assert(!ignored); cl_git_pass( git_status_should_ignore(&ignored, repo, "ignored_nonexistent_file") ); cl_assert(ignored); } static int cb_status__check_592(const char *p, unsigned int s, void *payload) { if (s != GIT_STATUS_WT_DELETED || (payload != NULL && strcmp(p, (const char *)payload) != 0)) return -1; return 0; } void test_status_worktree__issue_592(void) { git_repository *repo; git_buf path = GIT_BUF_INIT; repo = cl_git_sandbox_init("issue_592"); cl_git_pass(git_buf_joinpath(&path, git_repository_workdir(repo), "l.txt")); cl_git_pass(p_unlink(git_buf_cstr(&path))); cl_assert(!git_path_exists("issue_592/l.txt")); cl_git_pass(git_status_foreach(repo, cb_status__check_592, "l.txt")); git_buf_free(&path); } void test_status_worktree__issue_592_2(void) { git_repository *repo; git_buf path = GIT_BUF_INIT; repo = cl_git_sandbox_init("issue_592"); cl_git_pass(git_buf_joinpath(&path, git_repository_workdir(repo), "c/a.txt")); cl_git_pass(p_unlink(git_buf_cstr(&path))); cl_assert(!git_path_exists("issue_592/c/a.txt")); cl_git_pass(git_status_foreach(repo, cb_status__check_592, "c/a.txt")); git_buf_free(&path); } void test_status_worktree__issue_592_3(void) { git_repository *repo; git_buf path = GIT_BUF_INIT; repo = cl_git_sandbox_init("issue_592"); cl_git_pass(git_buf_joinpath(&path, git_repository_workdir(repo), "c")); cl_git_pass(git_futils_rmdir_r(git_buf_cstr(&path), NULL, GIT_RMDIR_REMOVE_FILES)); cl_assert(!git_path_exists("issue_592/c/a.txt")); cl_git_pass(git_status_foreach(repo, cb_status__check_592, "c/a.txt")); git_buf_free(&path); } void test_status_worktree__issue_592_4(void) { git_repository *repo; git_buf path = GIT_BUF_INIT; repo = cl_git_sandbox_init("issue_592"); cl_git_pass(git_buf_joinpath(&path, git_repository_workdir(repo), "t/b.txt")); cl_git_pass(p_unlink(git_buf_cstr(&path))); cl_git_pass(git_status_foreach(repo, cb_status__check_592, "t/b.txt")); git_buf_free(&path); } void test_status_worktree__issue_592_5(void) { git_repository *repo; git_buf path = GIT_BUF_INIT; repo = cl_git_sandbox_init("issue_592"); cl_git_pass(git_buf_joinpath(&path, git_repository_workdir(repo), "t")); cl_git_pass(git_futils_rmdir_r(git_buf_cstr(&path), NULL, GIT_RMDIR_REMOVE_FILES)); cl_git_pass(p_mkdir(git_buf_cstr(&path), 0777)); cl_git_pass(git_status_foreach(repo, cb_status__check_592, NULL)); git_buf_free(&path); } void test_status_worktree__issue_592_ignores_0(void) { int count = 0; status_entry_single st; git_repository *repo = cl_git_sandbox_init("issue_592"); cl_git_pass(git_status_foreach(repo, cb_status__count, &count)); cl_assert_equal_i(0, count); cl_git_rewritefile("issue_592/.gitignore", ".gitignore\n*.txt\nc/\n[tT]*/\n"); cl_git_pass(git_status_foreach(repo, cb_status__count, &count)); cl_assert_equal_i(1, count); /* This is a situation where the behavior of libgit2 is * different from core git. Core git will show ignored.txt * in the list of ignored files, even though the directory * "t" is ignored and the file is untracked because we have * the explicit "*.txt" ignore rule. Libgit2 just excludes * all untracked files that are contained within ignored * directories without explicitly listing them. */ cl_git_rewritefile("issue_592/t/ignored.txt", "ping"); memset(&st, 0, sizeof(st)); cl_git_pass(git_status_foreach(repo, cb_status__single, &st)); cl_assert_equal_i(1, st.count); cl_assert(st.status == GIT_STATUS_IGNORED); cl_git_rewritefile("issue_592/c/ignored_by_dir", "ping"); memset(&st, 0, sizeof(st)); cl_git_pass(git_status_foreach(repo, cb_status__single, &st)); cl_assert_equal_i(1, st.count); cl_assert(st.status == GIT_STATUS_IGNORED); cl_git_rewritefile("issue_592/t/ignored_by_dir_pattern", "ping"); memset(&st, 0, sizeof(st)); cl_git_pass(git_status_foreach(repo, cb_status__single, &st)); cl_assert_equal_i(1, st.count); cl_assert(st.status == GIT_STATUS_IGNORED); } void test_status_worktree__issue_592_ignored_dirs_with_tracked_content(void) { int count = 0; git_repository *repo = cl_git_sandbox_init("issue_592b"); cl_git_pass(git_status_foreach(repo, cb_status__count, &count)); cl_assert_equal_i(1, count); /* if we are really mimicking core git, then only ignored1.txt * at the top level will show up in the ignores list here. * everything else will be unmodified or skipped completely. */ } void test_status_worktree__conflict_with_diff3(void) { git_repository *repo = cl_git_sandbox_init("status"); git_index *index; unsigned int status; git_index_entry ancestor_entry, our_entry, their_entry; memset(&ancestor_entry, 0x0, sizeof(git_index_entry)); memset(&our_entry, 0x0, sizeof(git_index_entry)); memset(&their_entry, 0x0, sizeof(git_index_entry)); ancestor_entry.path = "modified_file"; git_oid_fromstr(&ancestor_entry.oid, "452e4244b5d083ddf0460acf1ecc74db9dcfa11a"); our_entry.path = "modified_file"; git_oid_fromstr(&our_entry.oid, "452e4244b5d083ddf0460acf1ecc74db9dcfa11a"); their_entry.path = "modified_file"; git_oid_fromstr(&their_entry.oid, "452e4244b5d083ddf0460acf1ecc74db9dcfa11a"); cl_git_pass(git_status_file(&status, repo, "modified_file")); cl_assert_equal_i(GIT_STATUS_WT_MODIFIED, status); cl_git_pass(git_repository_index(&index, repo)); cl_git_pass(git_index_remove(index, "modified_file", 0)); cl_git_pass(git_index_conflict_add(index, &ancestor_entry, &our_entry, &their_entry)); cl_git_pass(git_status_file(&status, repo, "modified_file")); cl_assert_equal_i(GIT_STATUS_INDEX_DELETED | GIT_STATUS_WT_NEW, status); git_index_free(index); } static const char *filemode_paths[] = { "exec_off", "exec_off2on_staged", "exec_off2on_workdir", "exec_off_untracked", "exec_on", "exec_on2off_staged", "exec_on2off_workdir", "exec_on_untracked", }; static unsigned int filemode_statuses[] = { GIT_STATUS_CURRENT, GIT_STATUS_INDEX_MODIFIED, GIT_STATUS_WT_MODIFIED, GIT_STATUS_WT_NEW, GIT_STATUS_CURRENT, GIT_STATUS_INDEX_MODIFIED, GIT_STATUS_WT_MODIFIED, GIT_STATUS_WT_NEW }; static const int filemode_count = 8; void test_status_worktree__filemode_changes(void) { git_repository *repo = cl_git_sandbox_init("filemodes"); status_entry_counts counts; git_status_options opts = GIT_STATUS_OPTIONS_INIT; /* overwrite stored filemode with platform appropriate value */ if (cl_is_chmod_supported()) cl_repo_set_bool(repo, "core.filemode", true); else { int i; cl_repo_set_bool(repo, "core.filemode", false); /* won't trust filesystem mode diffs, so these will appear unchanged */ for (i = 0; i < filemode_count; ++i) if (filemode_statuses[i] == GIT_STATUS_WT_MODIFIED) filemode_statuses[i] = GIT_STATUS_CURRENT; } opts.flags = GIT_STATUS_OPT_INCLUDE_UNTRACKED | GIT_STATUS_OPT_INCLUDE_IGNORED | GIT_STATUS_OPT_INCLUDE_UNMODIFIED; memset(&counts, 0, sizeof(counts)); counts.expected_entry_count = filemode_count; counts.expected_paths = filemode_paths; counts.expected_statuses = filemode_statuses; cl_git_pass( git_status_foreach_ext(repo, &opts, cb_status__normal, &counts) ); cl_assert_equal_i(counts.expected_entry_count, counts.entry_count); cl_assert_equal_i(0, counts.wrong_status_flags_count); cl_assert_equal_i(0, counts.wrong_sorted_path); } static int cb_status__interrupt(const char *p, unsigned int s, void *payload) { volatile int *count = (int *)payload; GIT_UNUSED(p); GIT_UNUSED(s); (*count)++; return (*count == 8); } void test_status_worktree__interruptable_foreach(void) { int count = 0; git_repository *repo = cl_git_sandbox_init("status"); cl_assert_equal_i( GIT_EUSER, git_status_foreach(repo, cb_status__interrupt, &count) ); cl_assert_equal_i(8, count); } void test_status_worktree__line_endings_dont_count_as_changes_with_autocrlf(void) { git_repository *repo = cl_git_sandbox_init("status"); unsigned int status; cl_repo_set_bool(repo, "core.autocrlf", true); cl_git_rewritefile("status/current_file", "current_file\r\n"); cl_git_pass(git_status_file(&status, repo, "current_file")); cl_assert_equal_i(GIT_STATUS_CURRENT, status); } void test_status_worktree__line_endings_dont_count_as_changes_with_autocrlf_issue_1397(void) { git_repository *repo = cl_git_sandbox_init("issue_1397"); unsigned int status; cl_repo_set_bool(repo, "core.autocrlf", true); cl_git_pass(git_status_file(&status, repo, "crlf_file.txt")); cl_assert_equal_i(GIT_STATUS_CURRENT, status); } void test_status_worktree__conflicted_item(void) { git_repository *repo = cl_git_sandbox_init("status"); git_index *index; unsigned int status; git_index_entry ancestor_entry, our_entry, their_entry; memset(&ancestor_entry, 0x0, sizeof(git_index_entry)); memset(&our_entry, 0x0, sizeof(git_index_entry)); memset(&their_entry, 0x0, sizeof(git_index_entry)); ancestor_entry.path = "modified_file"; git_oid_fromstr(&ancestor_entry.oid, "452e4244b5d083ddf0460acf1ecc74db9dcfa11a"); our_entry.path = "modified_file"; git_oid_fromstr(&our_entry.oid, "452e4244b5d083ddf0460acf1ecc74db9dcfa11a"); their_entry.path = "modified_file"; git_oid_fromstr(&their_entry.oid, "452e4244b5d083ddf0460acf1ecc74db9dcfa11a"); cl_git_pass(git_status_file(&status, repo, "modified_file")); cl_assert_equal_i(GIT_STATUS_WT_MODIFIED, status); cl_git_pass(git_repository_index(&index, repo)); cl_git_pass(git_index_conflict_add(index, &ancestor_entry, &our_entry, &their_entry)); cl_git_pass(git_status_file(&status, repo, "modified_file")); cl_assert_equal_i(GIT_STATUS_WT_MODIFIED, status); git_index_free(index); } static void stage_and_commit(git_repository *repo, const char *path) { git_oid tree_oid, commit_oid; git_tree *tree; git_signature *signature; git_index *index; cl_git_pass(git_repository_index(&index, repo)); cl_git_pass(git_index_add_bypath(index, path)); cl_git_pass(git_index_write(index)); cl_git_pass(git_index_write_tree(&tree_oid, index)); git_index_free(index); cl_git_pass(git_tree_lookup(&tree, repo, &tree_oid)); cl_git_pass(git_signature_new(&signature, "nulltoken", "emeric.fermas@gmail.com", 1323847743, 60)); cl_git_pass(git_commit_create_v( &commit_oid, repo, "HEAD", signature, signature, NULL, "Initial commit\n\0", tree, 0)); git_tree_free(tree); git_signature_free(signature); } static void assert_ignore_case( bool should_ignore_case, int expected_lower_cased_file_status, int expected_camel_cased_file_status) { unsigned int status; git_buf lower_case_path = GIT_BUF_INIT, camel_case_path = GIT_BUF_INIT; git_repository *repo, *repo2; repo = cl_git_sandbox_init("empty_standard_repo"); cl_git_remove_placeholders(git_repository_path(repo), "dummy-marker.txt"); cl_repo_set_bool(repo, "core.ignorecase", should_ignore_case); cl_git_pass(git_buf_joinpath(&lower_case_path, git_repository_workdir(repo), "plop")); cl_git_mkfile(git_buf_cstr(&lower_case_path), ""); stage_and_commit(repo, "plop"); cl_git_pass(git_repository_open(&repo2, "./empty_standard_repo")); cl_git_pass(git_status_file(&status, repo2, "plop")); cl_assert_equal_i(GIT_STATUS_CURRENT, status); cl_git_pass(git_buf_joinpath(&camel_case_path, git_repository_workdir(repo), "Plop")); cl_git_pass(p_rename(git_buf_cstr(&lower_case_path), git_buf_cstr(&camel_case_path))); cl_git_pass(git_status_file(&status, repo2, "plop")); cl_assert_equal_i(expected_lower_cased_file_status, status); cl_git_pass(git_status_file(&status, repo2, "Plop")); cl_assert_equal_i(expected_camel_cased_file_status, status); git_repository_free(repo2); git_buf_free(&lower_case_path); git_buf_free(&camel_case_path); } void test_status_worktree__file_status_honors_core_ignorecase_true(void) { assert_ignore_case(true, GIT_STATUS_CURRENT, GIT_STATUS_CURRENT); } void test_status_worktree__file_status_honors_core_ignorecase_false(void) { assert_ignore_case(false, GIT_STATUS_WT_DELETED, GIT_STATUS_WT_NEW); } void test_status_worktree__file_status_honors_case_ignorecase_regarding_untracked_files(void) { git_repository *repo = cl_git_sandbox_init("status"); unsigned int status; git_index *index; cl_repo_set_bool(repo, "core.ignorecase", false); repo = cl_git_sandbox_reopen(); /* Actually returns GIT_STATUS_IGNORED on Windows */ cl_git_fail_with(git_status_file(&status, repo, "NEW_FILE"), GIT_ENOTFOUND); cl_git_pass(git_repository_index(&index, repo)); cl_git_pass(git_index_add_bypath(index, "new_file")); cl_git_pass(git_index_write(index)); git_index_free(index); /* Actually returns GIT_STATUS_IGNORED on Windows */ cl_git_fail_with(git_status_file(&status, repo, "NEW_FILE"), GIT_ENOTFOUND); } void test_status_worktree__simple_delete(void) { git_repository *repo = cl_git_sandbox_init("renames"); git_status_options opts = GIT_STATUS_OPTIONS_INIT; int count; opts.flags = GIT_STATUS_OPT_INCLUDE_UNTRACKED | GIT_STATUS_OPT_DISABLE_PATHSPEC_MATCH | GIT_STATUS_OPT_EXCLUDE_SUBMODULES | GIT_STATUS_OPT_RECURSE_UNTRACKED_DIRS; count = 0; cl_git_pass( git_status_foreach_ext(repo, &opts, cb_status__count, &count) ); cl_assert_equal_i(0, count); cl_must_pass(p_unlink("renames/untimely.txt")); count = 0; cl_git_pass( git_status_foreach_ext(repo, &opts, cb_status__count, &count) ); cl_assert_equal_i(1, count); } void test_status_worktree__simple_delete_indexed(void) { git_repository *repo = cl_git_sandbox_init("renames"); git_status_options opts = GIT_STATUS_OPTIONS_INIT; git_status_list *status; opts.flags = GIT_STATUS_OPT_INCLUDE_UNTRACKED | GIT_STATUS_OPT_DISABLE_PATHSPEC_MATCH | GIT_STATUS_OPT_EXCLUDE_SUBMODULES | GIT_STATUS_OPT_RECURSE_UNTRACKED_DIRS; cl_git_pass(git_status_list_new(&status, repo, &opts)); cl_assert_equal_sz(0, git_status_list_entrycount(status)); git_status_list_free(status); cl_must_pass(p_unlink("renames/untimely.txt")); cl_git_pass(git_status_list_new(&status, repo, &opts)); cl_assert_equal_sz(1, git_status_list_entrycount(status)); cl_assert_equal_i( GIT_STATUS_WT_DELETED, git_status_byindex(status, 0)->status); git_status_list_free(status); } static const char *icase_paths[] = { "B", "c", "g", "H" }; static unsigned int icase_statuses[] = { GIT_STATUS_WT_MODIFIED, GIT_STATUS_WT_DELETED, GIT_STATUS_WT_MODIFIED, GIT_STATUS_WT_DELETED, }; static const char *case_paths[] = { "B", "H", "c", "g" }; static unsigned int case_statuses[] = { GIT_STATUS_WT_MODIFIED, GIT_STATUS_WT_DELETED, GIT_STATUS_WT_DELETED, GIT_STATUS_WT_MODIFIED, }; void test_status_worktree__sorting_by_case(void) { git_repository *repo = cl_git_sandbox_init("icase"); git_index *index; git_status_options opts = GIT_STATUS_OPTIONS_INIT; bool native_ignore_case; status_entry_counts counts; cl_git_pass(git_repository_index(&index, repo)); native_ignore_case = (git_index_caps(index) & GIT_INDEXCAP_IGNORE_CASE) != 0; git_index_free(index); memset(&counts, 0, sizeof(counts)); counts.expected_entry_count = 0; counts.expected_paths = NULL; counts.expected_statuses = NULL; cl_git_pass( git_status_foreach_ext(repo, &opts, cb_status__normal, &counts)); cl_assert_equal_i(counts.expected_entry_count, counts.entry_count); cl_assert_equal_i(0, counts.wrong_status_flags_count); cl_assert_equal_i(0, counts.wrong_sorted_path); cl_git_rewritefile("icase/B", "new stuff"); cl_must_pass(p_unlink("icase/c")); cl_git_rewritefile("icase/g", "new stuff"); cl_must_pass(p_unlink("icase/H")); memset(&counts, 0, sizeof(counts)); counts.expected_entry_count = 4; if (native_ignore_case) { counts.expected_paths = icase_paths; counts.expected_statuses = icase_statuses; } else { counts.expected_paths = case_paths; counts.expected_statuses = case_statuses; } cl_git_pass( git_status_foreach_ext(repo, &opts, cb_status__normal, &counts)); cl_assert_equal_i(counts.expected_entry_count, counts.entry_count); cl_assert_equal_i(0, counts.wrong_status_flags_count); cl_assert_equal_i(0, counts.wrong_sorted_path); opts.flags = GIT_STATUS_OPT_SORT_CASE_SENSITIVELY; memset(&counts, 0, sizeof(counts)); counts.expected_entry_count = 4; counts.expected_paths = case_paths; counts.expected_statuses = case_statuses; cl_git_pass( git_status_foreach_ext(repo, &opts, cb_status__normal, &counts)); cl_assert_equal_i(counts.expected_entry_count, counts.entry_count); cl_assert_equal_i(0, counts.wrong_status_flags_count); cl_assert_equal_i(0, counts.wrong_sorted_path); opts.flags = GIT_STATUS_OPT_SORT_CASE_INSENSITIVELY; memset(&counts, 0, sizeof(counts)); counts.expected_entry_count = 4; counts.expected_paths = icase_paths; counts.expected_statuses = icase_statuses; cl_git_pass( git_status_foreach_ext(repo, &opts, cb_status__normal, &counts)); cl_assert_equal_i(counts.expected_entry_count, counts.entry_count); cl_assert_equal_i(0, counts.wrong_status_flags_count); cl_assert_equal_i(0, counts.wrong_sorted_path); } libgit2-0.19.0/tests-clar/status/worktree_init.c000066400000000000000000000235751216214232500216040ustar00rootroot00000000000000#include "clar_libgit2.h" #include "git2/sys/repository.h" #include "fileops.h" #include "ignore.h" #include "status_helpers.h" #include "posix.h" #include "util.h" #include "path.h" static void cleanup_new_repo(void *path) { cl_fixture_cleanup((char *)path); } void test_status_worktree_init__cannot_retrieve_the_status_of_a_bare_repository(void) { git_repository *repo; unsigned int status = 0; cl_git_pass(git_repository_open(&repo, cl_fixture("testrepo.git"))); cl_assert_equal_i(GIT_EBAREREPO, git_status_file(&status, repo, "dummy")); git_repository_free(repo); } void test_status_worktree_init__first_commit_in_progress(void) { git_repository *repo; git_index *index; status_entry_single result; cl_set_cleanup(&cleanup_new_repo, "getting_started"); cl_git_pass(git_repository_init(&repo, "getting_started", 0)); cl_git_mkfile("getting_started/testfile.txt", "content\n"); memset(&result, 0, sizeof(result)); cl_git_pass(git_status_foreach(repo, cb_status__single, &result)); cl_assert_equal_i(1, result.count); cl_assert(result.status == GIT_STATUS_WT_NEW); cl_git_pass(git_repository_index(&index, repo)); cl_git_pass(git_index_add_bypath(index, "testfile.txt")); cl_git_pass(git_index_write(index)); memset(&result, 0, sizeof(result)); cl_git_pass(git_status_foreach(repo, cb_status__single, &result)); cl_assert_equal_i(1, result.count); cl_assert(result.status == GIT_STATUS_INDEX_NEW); git_index_free(index); git_repository_free(repo); } void test_status_worktree_init__status_file_without_index_or_workdir(void) { git_repository *repo; unsigned int status = 0; git_index *index; cl_git_pass(p_mkdir("wd", 0777)); cl_git_pass(git_repository_open(&repo, cl_fixture("testrepo.git"))); cl_git_pass(git_repository_set_workdir(repo, "wd", false)); cl_git_pass(git_index_open(&index, "empty-index")); cl_assert_equal_i(0, (int)git_index_entrycount(index)); git_repository_set_index(repo, index); cl_git_pass(git_status_file(&status, repo, "branch_file.txt")); cl_assert_equal_i(GIT_STATUS_INDEX_DELETED, status); git_repository_free(repo); git_index_free(index); cl_git_pass(p_rmdir("wd")); } static void fill_index_wth_head_entries(git_repository *repo, git_index *index) { git_oid oid; git_commit *commit; git_tree *tree; cl_git_pass(git_reference_name_to_id(&oid, repo, "HEAD")); cl_git_pass(git_commit_lookup(&commit, repo, &oid)); cl_git_pass(git_commit_tree(&tree, commit)); cl_git_pass(git_index_read_tree(index, tree)); cl_git_pass(git_index_write(index)); git_tree_free(tree); git_commit_free(commit); } void test_status_worktree_init__status_file_with_clean_index_and_empty_workdir(void) { git_repository *repo; unsigned int status = 0; git_index *index; cl_git_pass(p_mkdir("wd", 0777)); cl_git_pass(git_repository_open(&repo, cl_fixture("testrepo.git"))); cl_git_pass(git_repository_set_workdir(repo, "wd", false)); cl_git_pass(git_index_open(&index, "my-index")); fill_index_wth_head_entries(repo, index); git_repository_set_index(repo, index); cl_git_pass(git_status_file(&status, repo, "branch_file.txt")); cl_assert_equal_i(GIT_STATUS_WT_DELETED, status); git_repository_free(repo); git_index_free(index); cl_git_pass(p_rmdir("wd")); cl_git_pass(p_unlink("my-index")); } void test_status_worktree_init__bracket_in_filename(void) { git_repository *repo; git_index *index; status_entry_single result; unsigned int status_flags; int error; #define FILE_WITH_BRACKET "LICENSE[1].md" #define FILE_WITHOUT_BRACKET "LICENSE1.md" cl_set_cleanup(&cleanup_new_repo, "with_bracket"); cl_git_pass(git_repository_init(&repo, "with_bracket", 0)); cl_git_mkfile("with_bracket/" FILE_WITH_BRACKET, "I have a bracket in my name\n"); /* file is new to working directory */ memset(&result, 0, sizeof(result)); cl_git_pass(git_status_foreach(repo, cb_status__single, &result)); cl_assert_equal_i(1, result.count); cl_assert(result.status == GIT_STATUS_WT_NEW); cl_git_pass(git_status_file(&status_flags, repo, FILE_WITH_BRACKET)); cl_assert(status_flags == GIT_STATUS_WT_NEW); /* ignore the file */ cl_git_rewritefile("with_bracket/.gitignore", "*.md\n.gitignore\n"); memset(&result, 0, sizeof(result)); cl_git_pass(git_status_foreach(repo, cb_status__single, &result)); cl_assert_equal_i(2, result.count); cl_assert(result.status == GIT_STATUS_IGNORED); cl_git_pass(git_status_file(&status_flags, repo, FILE_WITH_BRACKET)); cl_assert(status_flags == GIT_STATUS_IGNORED); /* don't ignore the file */ cl_git_rewritefile("with_bracket/.gitignore", ".gitignore\n"); memset(&result, 0, sizeof(result)); cl_git_pass(git_status_foreach(repo, cb_status__single, &result)); cl_assert_equal_i(2, result.count); cl_assert(result.status == GIT_STATUS_WT_NEW); cl_git_pass(git_status_file(&status_flags, repo, FILE_WITH_BRACKET)); cl_assert(status_flags == GIT_STATUS_WT_NEW); /* add the file to the index */ cl_git_pass(git_repository_index(&index, repo)); cl_git_pass(git_index_add_bypath(index, FILE_WITH_BRACKET)); cl_git_pass(git_index_write(index)); memset(&result, 0, sizeof(result)); cl_git_pass(git_status_foreach(repo, cb_status__single, &result)); cl_assert_equal_i(2, result.count); cl_assert(result.status == GIT_STATUS_INDEX_NEW); cl_git_pass(git_status_file(&status_flags, repo, FILE_WITH_BRACKET)); cl_assert(status_flags == GIT_STATUS_INDEX_NEW); /* Create file without bracket */ cl_git_mkfile("with_bracket/" FILE_WITHOUT_BRACKET, "I have no bracket in my name!\n"); cl_git_pass(git_status_file(&status_flags, repo, FILE_WITHOUT_BRACKET)); cl_assert(status_flags == GIT_STATUS_WT_NEW); cl_git_pass(git_status_file(&status_flags, repo, "LICENSE\\[1\\].md")); cl_assert(status_flags == GIT_STATUS_INDEX_NEW); error = git_status_file(&status_flags, repo, FILE_WITH_BRACKET); cl_git_fail(error); cl_assert_equal_i(GIT_EAMBIGUOUS, error); git_index_free(index); git_repository_free(repo); } void test_status_worktree_init__space_in_filename(void) { git_repository *repo; git_index *index; status_entry_single result; unsigned int status_flags; #define FILE_WITH_SPACE "LICENSE - copy.md" cl_set_cleanup(&cleanup_new_repo, "with_space"); cl_git_pass(git_repository_init(&repo, "with_space", 0)); cl_git_mkfile("with_space/" FILE_WITH_SPACE, "I have a space in my name\n"); /* file is new to working directory */ memset(&result, 0, sizeof(result)); cl_git_pass(git_status_foreach(repo, cb_status__single, &result)); cl_assert_equal_i(1, result.count); cl_assert(result.status == GIT_STATUS_WT_NEW); cl_git_pass(git_status_file(&status_flags, repo, FILE_WITH_SPACE)); cl_assert(status_flags == GIT_STATUS_WT_NEW); /* ignore the file */ cl_git_rewritefile("with_space/.gitignore", "*.md\n.gitignore\n"); memset(&result, 0, sizeof(result)); cl_git_pass(git_status_foreach(repo, cb_status__single, &result)); cl_assert_equal_i(2, result.count); cl_assert(result.status == GIT_STATUS_IGNORED); cl_git_pass(git_status_file(&status_flags, repo, FILE_WITH_SPACE)); cl_assert(status_flags == GIT_STATUS_IGNORED); /* don't ignore the file */ cl_git_rewritefile("with_space/.gitignore", ".gitignore\n"); memset(&result, 0, sizeof(result)); cl_git_pass(git_status_foreach(repo, cb_status__single, &result)); cl_assert_equal_i(2, result.count); cl_assert(result.status == GIT_STATUS_WT_NEW); cl_git_pass(git_status_file(&status_flags, repo, FILE_WITH_SPACE)); cl_assert(status_flags == GIT_STATUS_WT_NEW); /* add the file to the index */ cl_git_pass(git_repository_index(&index, repo)); cl_git_pass(git_index_add_bypath(index, FILE_WITH_SPACE)); cl_git_pass(git_index_write(index)); memset(&result, 0, sizeof(result)); cl_git_pass(git_status_foreach(repo, cb_status__single, &result)); cl_assert_equal_i(2, result.count); cl_assert(result.status == GIT_STATUS_INDEX_NEW); cl_git_pass(git_status_file(&status_flags, repo, FILE_WITH_SPACE)); cl_assert(status_flags == GIT_STATUS_INDEX_NEW); git_index_free(index); git_repository_free(repo); } static int cb_status__expected_path(const char *p, unsigned int s, void *payload) { const char *expected_path = (const char *)payload; GIT_UNUSED(s); if (payload == NULL) cl_fail("Unexpected path"); cl_assert_equal_s(expected_path, p); return 0; } void test_status_worktree_init__disable_pathspec_match(void) { git_repository *repo; git_status_options opts = GIT_STATUS_OPTIONS_INIT; char *file_with_bracket = "LICENSE[1].md", *imaginary_file_with_bracket = "LICENSE[1-2].md"; cl_set_cleanup(&cleanup_new_repo, "pathspec"); cl_git_pass(git_repository_init(&repo, "pathspec", 0)); cl_git_mkfile("pathspec/LICENSE[1].md", "screaming bracket\n"); cl_git_mkfile("pathspec/LICENSE1.md", "no bracket\n"); opts.flags = GIT_STATUS_OPT_INCLUDE_UNTRACKED | GIT_STATUS_OPT_DISABLE_PATHSPEC_MATCH; opts.pathspec.count = 1; opts.pathspec.strings = &file_with_bracket; cl_git_pass( git_status_foreach_ext(repo, &opts, cb_status__expected_path, file_with_bracket) ); /* Test passing a pathspec matching files in the workdir. */ /* Must not match because pathspecs are disabled. */ opts.pathspec.strings = &imaginary_file_with_bracket; cl_git_pass( git_status_foreach_ext(repo, &opts, cb_status__expected_path, NULL) ); git_repository_free(repo); } void test_status_worktree_init__new_staged_file_must_handle_crlf(void) { git_repository *repo; git_index *index; unsigned int status; cl_set_cleanup(&cleanup_new_repo, "getting_started"); cl_git_pass(git_repository_init(&repo, "getting_started", 0)); /* Ensure that repo has core.autocrlf=true */ cl_repo_set_bool(repo, "core.autocrlf", true); cl_git_mkfile("getting_started/testfile.txt", "content\r\n"); /* Content with CRLF */ cl_git_pass(git_repository_index(&index, repo)); cl_git_pass(git_index_add_bypath(index, "testfile.txt")); cl_git_pass(git_index_write(index)); cl_git_pass(git_status_file(&status, repo, "testfile.txt")); cl_assert_equal_i(GIT_STATUS_INDEX_NEW, status); git_index_free(index); git_repository_free(repo); } libgit2-0.19.0/tests-clar/submodule/000077500000000000000000000000001216214232500172135ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/submodule/lookup.c000066400000000000000000000075321216214232500206770ustar00rootroot00000000000000#include "clar_libgit2.h" #include "submodule_helpers.h" #include "posix.h" static git_repository *g_repo = NULL; void test_submodule_lookup__initialize(void) { g_repo = cl_git_sandbox_init("submod2"); cl_fixture_sandbox("submod2_target"); p_rename("submod2_target/.gitted", "submod2_target/.git"); /* must create submod2_target before rewrite so prettify will work */ rewrite_gitmodules(git_repository_workdir(g_repo)); p_rename("submod2/not-submodule/.gitted", "submod2/not-submodule/.git"); } void test_submodule_lookup__cleanup(void) { cl_git_sandbox_cleanup(); cl_fixture_cleanup("submod2_target"); } void test_submodule_lookup__simple_lookup(void) { git_submodule *sm; /* lookup existing */ cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_unchanged")); cl_assert(sm); /* lookup pending change in .gitmodules that is not in HEAD */ cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_added_and_uncommited")); cl_assert(sm); /* lookup pending change in .gitmodules that is neither in HEAD nor index */ cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_gitmodules_only")); cl_assert(sm); /* lookup git repo subdir that is not added as submodule */ cl_assert(git_submodule_lookup(&sm, g_repo, "not-submodule") == GIT_EEXISTS); /* lookup existing directory that is not a submodule */ cl_assert(git_submodule_lookup(&sm, g_repo, "just_a_dir") == GIT_ENOTFOUND); /* lookup existing file that is not a submodule */ cl_assert(git_submodule_lookup(&sm, g_repo, "just_a_file") == GIT_ENOTFOUND); /* lookup non-existent item */ cl_assert(git_submodule_lookup(&sm, g_repo, "no_such_file") == GIT_ENOTFOUND); } void test_submodule_lookup__accessors(void) { git_submodule *sm; const char *oid = "480095882d281ed676fe5b863569520e54a7d5c0"; cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_unchanged")); cl_assert(git_submodule_owner(sm) == g_repo); cl_assert_equal_s("sm_unchanged", git_submodule_name(sm)); cl_assert(git__suffixcmp(git_submodule_path(sm), "sm_unchanged") == 0); cl_assert(git__suffixcmp(git_submodule_url(sm), "/submod2_target") == 0); cl_assert(git_oid_streq(git_submodule_index_id(sm), oid) == 0); cl_assert(git_oid_streq(git_submodule_head_id(sm), oid) == 0); cl_assert(git_oid_streq(git_submodule_wd_id(sm), oid) == 0); cl_assert(git_submodule_ignore(sm) == GIT_SUBMODULE_IGNORE_NONE); cl_assert(git_submodule_update(sm) == GIT_SUBMODULE_UPDATE_CHECKOUT); cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_changed_head")); cl_assert_equal_s("sm_changed_head", git_submodule_name(sm)); cl_assert(git_oid_streq(git_submodule_index_id(sm), oid) == 0); cl_assert(git_oid_streq(git_submodule_head_id(sm), oid) == 0); cl_assert(git_oid_streq(git_submodule_wd_id(sm), "3d9386c507f6b093471a3e324085657a3c2b4247") == 0); cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_added_and_uncommited")); cl_assert_equal_s("sm_added_and_uncommited", git_submodule_name(sm)); cl_assert(git_oid_streq(git_submodule_index_id(sm), oid) == 0); cl_assert(git_submodule_head_id(sm) == NULL); cl_assert(git_oid_streq(git_submodule_wd_id(sm), oid) == 0); cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_missing_commits")); cl_assert_equal_s("sm_missing_commits", git_submodule_name(sm)); cl_assert(git_oid_streq(git_submodule_index_id(sm), oid) == 0); cl_assert(git_oid_streq(git_submodule_head_id(sm), oid) == 0); cl_assert(git_oid_streq(git_submodule_wd_id(sm), "5e4963595a9774b90524d35a807169049de8ccad") == 0); } typedef struct { int count; } sm_lookup_data; static int sm_lookup_cb(git_submodule *sm, const char *name, void *payload) { sm_lookup_data *data = payload; data->count += 1; cl_assert_equal_s(git_submodule_name(sm), name); return 0; } void test_submodule_lookup__foreach(void) { sm_lookup_data data; memset(&data, 0, sizeof(data)); cl_git_pass(git_submodule_foreach(g_repo, sm_lookup_cb, &data)); cl_assert_equal_i(8, data.count); } libgit2-0.19.0/tests-clar/submodule/modify.c000066400000000000000000000220261216214232500206500ustar00rootroot00000000000000#include "clar_libgit2.h" #include "posix.h" #include "path.h" #include "submodule_helpers.h" static git_repository *g_repo = NULL; #define SM_LIBGIT2_URL "https://github.com/libgit2/libgit2.git" #define SM_LIBGIT2 "sm_libgit2" #define SM_LIBGIT2B "sm_libgit2b" void test_submodule_modify__initialize(void) { g_repo = cl_git_sandbox_init("submod2"); cl_fixture_sandbox("submod2_target"); p_rename("submod2_target/.gitted", "submod2_target/.git"); /* must create submod2_target before rewrite so prettify will work */ rewrite_gitmodules(git_repository_workdir(g_repo)); p_rename("submod2/not-submodule/.gitted", "submod2/not-submodule/.git"); } void test_submodule_modify__cleanup(void) { cl_git_sandbox_cleanup(); cl_fixture_cleanup("submod2_target"); } void test_submodule_modify__add(void) { git_submodule *sm; git_config *cfg; const char *s; /* re-add existing submodule */ cl_assert( git_submodule_add_setup(NULL, g_repo, "whatever", "sm_unchanged", 1) == GIT_EEXISTS ); /* add a submodule using a gitlink */ cl_git_pass( git_submodule_add_setup(&sm, g_repo, SM_LIBGIT2_URL, SM_LIBGIT2, 1) ); cl_assert(git_path_isfile("submod2/" SM_LIBGIT2 "/.git")); cl_assert(git_path_isdir("submod2/.git/modules")); cl_assert(git_path_isdir("submod2/.git/modules/" SM_LIBGIT2)); cl_assert(git_path_isfile("submod2/.git/modules/" SM_LIBGIT2 "/HEAD")); cl_git_pass(git_repository_config(&cfg, g_repo)); cl_git_pass( git_config_get_string(&s, cfg, "submodule." SM_LIBGIT2 ".url")); cl_assert_equal_s(s, SM_LIBGIT2_URL); git_config_free(cfg); /* add a submodule not using a gitlink */ cl_git_pass( git_submodule_add_setup(&sm, g_repo, SM_LIBGIT2_URL, SM_LIBGIT2B, 0) ); cl_assert(git_path_isdir("submod2/" SM_LIBGIT2B "/.git")); cl_assert(git_path_isfile("submod2/" SM_LIBGIT2B "/.git/HEAD")); cl_assert(!git_path_exists("submod2/.git/modules/" SM_LIBGIT2B)); cl_git_pass(git_repository_config(&cfg, g_repo)); cl_git_pass( git_config_get_string(&s, cfg, "submodule." SM_LIBGIT2B ".url")); cl_assert_equal_s(s, SM_LIBGIT2_URL); git_config_free(cfg); } static int delete_one_config(const git_config_entry *entry, void *payload) { git_config *cfg = payload; return git_config_delete_entry(cfg, entry->name); } static int init_one_submodule( git_submodule *sm, const char *name, void *payload) { GIT_UNUSED(name); GIT_UNUSED(payload); return git_submodule_init(sm, false); } void test_submodule_modify__init(void) { git_config *cfg; const char *str; /* erase submodule data from .git/config */ cl_git_pass(git_repository_config(&cfg, g_repo)); cl_git_pass( git_config_foreach_match(cfg, "submodule\\..*", delete_one_config, cfg)); git_config_free(cfg); /* confirm no submodule data in config */ cl_git_pass(git_repository_config(&cfg, g_repo)); cl_git_fail(git_config_get_string(&str, cfg, "submodule.sm_unchanged.url")); cl_git_fail(git_config_get_string(&str, cfg, "submodule.sm_changed_head.url")); cl_git_fail(git_config_get_string(&str, cfg, "submodule.sm_added_and_uncommited.url")); git_config_free(cfg); /* call init and see that settings are copied */ cl_git_pass(git_submodule_foreach(g_repo, init_one_submodule, NULL)); git_submodule_reload_all(g_repo); /* confirm submodule data in config */ cl_git_pass(git_repository_config(&cfg, g_repo)); cl_git_pass(git_config_get_string(&str, cfg, "submodule.sm_unchanged.url")); cl_assert(git__suffixcmp(str, "/submod2_target") == 0); cl_git_pass(git_config_get_string(&str, cfg, "submodule.sm_changed_head.url")); cl_assert(git__suffixcmp(str, "/submod2_target") == 0); cl_git_pass(git_config_get_string(&str, cfg, "submodule.sm_added_and_uncommited.url")); cl_assert(git__suffixcmp(str, "/submod2_target") == 0); git_config_free(cfg); } static int sync_one_submodule( git_submodule *sm, const char *name, void *payload) { GIT_UNUSED(name); GIT_UNUSED(payload); return git_submodule_sync(sm); } void test_submodule_modify__sync(void) { git_submodule *sm1, *sm2, *sm3; git_config *cfg; const char *str; #define SM1 "sm_unchanged" #define SM2 "sm_changed_head" #define SM3 "sm_added_and_uncommited" /* look up some submodules */ cl_git_pass(git_submodule_lookup(&sm1, g_repo, SM1)); cl_git_pass(git_submodule_lookup(&sm2, g_repo, SM2)); cl_git_pass(git_submodule_lookup(&sm3, g_repo, SM3)); /* At this point, the .git/config URLs for the submodules have * not be rewritten with the absolute paths (although the * .gitmodules have. Let's confirm that they DO NOT match * yet, then we can do a sync to make them match... */ /* check submodule info does not match before sync */ cl_git_pass(git_repository_config(&cfg, g_repo)); cl_git_pass(git_config_get_string(&str, cfg, "submodule."SM1".url")); cl_assert(strcmp(git_submodule_url(sm1), str) != 0); cl_git_pass(git_config_get_string(&str, cfg, "submodule."SM2".url")); cl_assert(strcmp(git_submodule_url(sm2), str) != 0); cl_git_pass(git_config_get_string(&str, cfg, "submodule."SM3".url")); cl_assert(strcmp(git_submodule_url(sm3), str) != 0); git_config_free(cfg); /* sync all the submodules */ cl_git_pass(git_submodule_foreach(g_repo, sync_one_submodule, NULL)); /* check that submodule config is updated */ cl_git_pass(git_repository_config(&cfg, g_repo)); cl_git_pass(git_config_get_string(&str, cfg, "submodule."SM1".url")); cl_assert_equal_s(git_submodule_url(sm1), str); cl_git_pass(git_config_get_string(&str, cfg, "submodule."SM2".url")); cl_assert_equal_s(git_submodule_url(sm2), str); cl_git_pass(git_config_get_string(&str, cfg, "submodule."SM3".url")); cl_assert_equal_s(git_submodule_url(sm3), str); git_config_free(cfg); } void test_submodule_modify__edit_and_save(void) { git_submodule *sm1, *sm2; char *old_url; git_submodule_ignore_t old_ignore; git_submodule_update_t old_update; git_repository *r2; int old_fetchrecurse; cl_git_pass(git_submodule_lookup(&sm1, g_repo, "sm_changed_head")); old_url = git__strdup(git_submodule_url(sm1)); /* modify properties of submodule */ cl_git_pass(git_submodule_set_url(sm1, SM_LIBGIT2_URL)); old_ignore = git_submodule_set_ignore(sm1, GIT_SUBMODULE_IGNORE_UNTRACKED); old_update = git_submodule_set_update(sm1, GIT_SUBMODULE_UPDATE_REBASE); old_fetchrecurse = git_submodule_set_fetch_recurse_submodules(sm1, 1); cl_assert_equal_s(SM_LIBGIT2_URL, git_submodule_url(sm1)); cl_assert_equal_i( (int)GIT_SUBMODULE_IGNORE_UNTRACKED, (int)git_submodule_ignore(sm1)); cl_assert_equal_i( (int)GIT_SUBMODULE_UPDATE_REBASE, (int)git_submodule_update(sm1)); cl_assert_equal_i(1, git_submodule_fetch_recurse_submodules(sm1)); /* revert without saving (and confirm setters return old value) */ cl_git_pass(git_submodule_set_url(sm1, old_url)); cl_assert_equal_i( (int)GIT_SUBMODULE_IGNORE_UNTRACKED, (int)git_submodule_set_ignore(sm1, GIT_SUBMODULE_IGNORE_DEFAULT)); cl_assert_equal_i( (int)GIT_SUBMODULE_UPDATE_REBASE, (int)git_submodule_set_update(sm1, GIT_SUBMODULE_UPDATE_DEFAULT)); cl_assert_equal_i( 1, git_submodule_set_fetch_recurse_submodules(sm1, old_fetchrecurse)); /* check that revert was successful */ cl_assert_equal_s(old_url, git_submodule_url(sm1)); cl_assert_equal_i((int)old_ignore, (int)git_submodule_ignore(sm1)); cl_assert_equal_i((int)old_update, (int)git_submodule_update(sm1)); cl_assert_equal_i( old_fetchrecurse, git_submodule_fetch_recurse_submodules(sm1)); /* modify properties of submodule (again) */ cl_git_pass(git_submodule_set_url(sm1, SM_LIBGIT2_URL)); git_submodule_set_ignore(sm1, GIT_SUBMODULE_IGNORE_UNTRACKED); git_submodule_set_update(sm1, GIT_SUBMODULE_UPDATE_REBASE); git_submodule_set_fetch_recurse_submodules(sm1, 1); /* call save */ cl_git_pass(git_submodule_save(sm1)); /* attempt to "revert" values */ git_submodule_set_ignore(sm1, GIT_SUBMODULE_IGNORE_DEFAULT); git_submodule_set_update(sm1, GIT_SUBMODULE_UPDATE_DEFAULT); /* but ignore and update should NOT revert because the DEFAULT * should now be the newly saved value... */ cl_assert_equal_i( (int)GIT_SUBMODULE_IGNORE_UNTRACKED, (int)git_submodule_ignore(sm1)); cl_assert_equal_i( (int)GIT_SUBMODULE_UPDATE_REBASE, (int)git_submodule_update(sm1)); cl_assert_equal_i(1, git_submodule_fetch_recurse_submodules(sm1)); /* call reload and check that the new values are loaded */ cl_git_pass(git_submodule_reload(sm1)); cl_assert_equal_s(SM_LIBGIT2_URL, git_submodule_url(sm1)); cl_assert_equal_i( (int)GIT_SUBMODULE_IGNORE_UNTRACKED, (int)git_submodule_ignore(sm1)); cl_assert_equal_i( (int)GIT_SUBMODULE_UPDATE_REBASE, (int)git_submodule_update(sm1)); cl_assert_equal_i(1, git_submodule_fetch_recurse_submodules(sm1)); /* open a second copy of the repo and compare submodule */ cl_git_pass(git_repository_open(&r2, "submod2")); cl_git_pass(git_submodule_lookup(&sm2, r2, "sm_changed_head")); cl_assert_equal_s(SM_LIBGIT2_URL, git_submodule_url(sm2)); cl_assert_equal_i( (int)GIT_SUBMODULE_IGNORE_UNTRACKED, (int)git_submodule_ignore(sm2)); cl_assert_equal_i( (int)GIT_SUBMODULE_UPDATE_REBASE, (int)git_submodule_update(sm2)); cl_assert_equal_i(1, git_submodule_fetch_recurse_submodules(sm2)); git_repository_free(r2); git__free(old_url); } libgit2-0.19.0/tests-clar/submodule/status.c000066400000000000000000000350671216214232500207150ustar00rootroot00000000000000#include "clar_libgit2.h" #include "posix.h" #include "path.h" #include "submodule_helpers.h" #include "fileops.h" #include "iterator.h" static git_repository *g_repo = NULL; void test_submodule_status__initialize(void) { g_repo = cl_git_sandbox_init("submod2"); cl_fixture_sandbox("submod2_target"); p_rename("submod2_target/.gitted", "submod2_target/.git"); /* must create submod2_target before rewrite so prettify will work */ rewrite_gitmodules(git_repository_workdir(g_repo)); p_rename("submod2/not-submodule/.gitted", "submod2/not-submodule/.git"); p_rename("submod2/not/.gitted", "submod2/not/.git"); } void test_submodule_status__cleanup(void) { cl_git_sandbox_cleanup(); cl_fixture_cleanup("submod2_target"); } void test_submodule_status__unchanged(void) { unsigned int status, expected; git_submodule *sm; cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_unchanged")); cl_git_pass(git_submodule_status(&status, sm)); cl_assert(GIT_SUBMODULE_STATUS_IS_UNMODIFIED(status)); expected = GIT_SUBMODULE_STATUS_IN_HEAD | GIT_SUBMODULE_STATUS_IN_INDEX | GIT_SUBMODULE_STATUS_IN_CONFIG | GIT_SUBMODULE_STATUS_IN_WD; cl_assert(status == expected); } /* 4 values of GIT_SUBMODULE_IGNORE to check */ void test_submodule_status__ignore_none(void) { unsigned int status; git_submodule *sm; git_buf path = GIT_BUF_INIT; cl_git_pass(git_buf_joinpath(&path, git_repository_workdir(g_repo), "sm_unchanged")); cl_git_pass(git_futils_rmdir_r(git_buf_cstr(&path), NULL, GIT_RMDIR_REMOVE_FILES)); cl_assert_equal_i(GIT_ENOTFOUND, git_submodule_lookup(&sm, g_repo, "just_a_dir")); cl_assert_equal_i(GIT_EEXISTS, git_submodule_lookup(&sm, g_repo, "not-submodule")); cl_assert_equal_i(GIT_EEXISTS, git_submodule_lookup(&sm, g_repo, "not")); cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_changed_index")); cl_git_pass(git_submodule_status(&status, sm)); cl_assert((status & GIT_SUBMODULE_STATUS_WD_INDEX_MODIFIED) != 0); cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_changed_head")); cl_git_pass(git_submodule_status(&status, sm)); cl_assert((status & GIT_SUBMODULE_STATUS_WD_MODIFIED) != 0); cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_changed_file")); cl_git_pass(git_submodule_status(&status, sm)); cl_assert((status & GIT_SUBMODULE_STATUS_WD_WD_MODIFIED) != 0); cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_changed_untracked_file")); cl_git_pass(git_submodule_status(&status, sm)); cl_assert((status & GIT_SUBMODULE_STATUS_WD_UNTRACKED) != 0); cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_missing_commits")); cl_git_pass(git_submodule_status(&status, sm)); cl_assert((status & GIT_SUBMODULE_STATUS_WD_MODIFIED) != 0); cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_added_and_uncommited")); cl_git_pass(git_submodule_status(&status, sm)); cl_assert((status & GIT_SUBMODULE_STATUS_INDEX_ADDED) != 0); /* removed sm_unchanged for deleted workdir */ cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_unchanged")); cl_git_pass(git_submodule_status(&status, sm)); cl_assert((status & GIT_SUBMODULE_STATUS_WD_DELETED) != 0); /* now mkdir sm_unchanged to test uninitialized */ cl_git_pass(git_futils_mkdir(git_buf_cstr(&path), NULL, 0755, 0)); cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_unchanged")); cl_git_pass(git_submodule_reload(sm)); cl_git_pass(git_submodule_status(&status, sm)); cl_assert((status & GIT_SUBMODULE_STATUS_WD_UNINITIALIZED) != 0); /* update sm_changed_head in index */ cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_changed_head")); cl_git_pass(git_submodule_add_to_index(sm, true)); /* reload is not needed because add_to_index updates the submodule data */ cl_git_pass(git_submodule_status(&status, sm)); cl_assert((status & GIT_SUBMODULE_STATUS_INDEX_MODIFIED) != 0); /* remove sm_changed_head from index */ { git_index *index; size_t pos; cl_git_pass(git_repository_index(&index, g_repo)); cl_assert(!git_index_find(&pos, index, "sm_changed_head")); cl_git_pass(git_index_remove(index, "sm_changed_head", 0)); cl_git_pass(git_index_write(index)); git_index_free(index); } cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_changed_head")); cl_git_pass(git_submodule_reload(sm)); cl_git_pass(git_submodule_status(&status, sm)); cl_assert((status & GIT_SUBMODULE_STATUS_INDEX_DELETED) != 0); git_buf_free(&path); } static int set_sm_ignore(git_submodule *sm, const char *name, void *payload) { git_submodule_ignore_t ignore = *(git_submodule_ignore_t *)payload; GIT_UNUSED(name); git_submodule_set_ignore(sm, ignore); return 0; } void test_submodule_status__ignore_untracked(void) { unsigned int status; git_submodule *sm; git_buf path = GIT_BUF_INIT; git_submodule_ignore_t ign = GIT_SUBMODULE_IGNORE_UNTRACKED; cl_git_pass(git_buf_joinpath(&path, git_repository_workdir(g_repo), "sm_unchanged")); cl_git_pass(git_futils_rmdir_r(git_buf_cstr(&path), NULL, GIT_RMDIR_REMOVE_FILES)); cl_git_pass(git_submodule_foreach(g_repo, set_sm_ignore, &ign)); cl_git_fail(git_submodule_lookup(&sm, g_repo, "not-submodule")); cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_changed_index")); cl_git_pass(git_submodule_status(&status, sm)); cl_assert((status & GIT_SUBMODULE_STATUS_WD_INDEX_MODIFIED) != 0); cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_changed_head")); cl_git_pass(git_submodule_status(&status, sm)); cl_assert((status & GIT_SUBMODULE_STATUS_WD_MODIFIED) != 0); cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_changed_file")); cl_git_pass(git_submodule_status(&status, sm)); cl_assert((status & GIT_SUBMODULE_STATUS_WD_WD_MODIFIED) != 0); cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_changed_untracked_file")); cl_git_pass(git_submodule_status(&status, sm)); cl_assert(GIT_SUBMODULE_STATUS_IS_UNMODIFIED(status)); cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_missing_commits")); cl_git_pass(git_submodule_status(&status, sm)); cl_assert((status & GIT_SUBMODULE_STATUS_WD_MODIFIED) != 0); cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_added_and_uncommited")); cl_git_pass(git_submodule_status(&status, sm)); cl_assert((status & GIT_SUBMODULE_STATUS_INDEX_ADDED) != 0); /* removed sm_unchanged for deleted workdir */ cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_unchanged")); cl_git_pass(git_submodule_status(&status, sm)); cl_assert((status & GIT_SUBMODULE_STATUS_WD_DELETED) != 0); /* now mkdir sm_unchanged to test uninitialized */ cl_git_pass(git_futils_mkdir(git_buf_cstr(&path), NULL, 0755, 0)); cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_unchanged")); cl_git_pass(git_submodule_reload(sm)); cl_git_pass(git_submodule_status(&status, sm)); cl_assert((status & GIT_SUBMODULE_STATUS_WD_UNINITIALIZED) != 0); /* update sm_changed_head in index */ cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_changed_head")); cl_git_pass(git_submodule_add_to_index(sm, true)); /* reload is not needed because add_to_index updates the submodule data */ cl_git_pass(git_submodule_status(&status, sm)); cl_assert((status & GIT_SUBMODULE_STATUS_INDEX_MODIFIED) != 0); git_buf_free(&path); } void test_submodule_status__ignore_dirty(void) { unsigned int status; git_submodule *sm; git_buf path = GIT_BUF_INIT; git_submodule_ignore_t ign = GIT_SUBMODULE_IGNORE_DIRTY; cl_git_pass(git_buf_joinpath(&path, git_repository_workdir(g_repo), "sm_unchanged")); cl_git_pass(git_futils_rmdir_r(git_buf_cstr(&path), NULL, GIT_RMDIR_REMOVE_FILES)); cl_git_pass(git_submodule_foreach(g_repo, set_sm_ignore, &ign)); cl_assert_equal_i(GIT_ENOTFOUND, git_submodule_lookup(&sm, g_repo, "just_a_dir")); cl_assert_equal_i(GIT_EEXISTS, git_submodule_lookup(&sm, g_repo, "not-submodule")); cl_assert_equal_i(GIT_EEXISTS, git_submodule_lookup(&sm, g_repo, "not")); cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_changed_index")); cl_git_pass(git_submodule_status(&status, sm)); cl_assert(GIT_SUBMODULE_STATUS_IS_UNMODIFIED(status)); cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_changed_head")); cl_git_pass(git_submodule_status(&status, sm)); cl_assert((status & GIT_SUBMODULE_STATUS_WD_MODIFIED) != 0); cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_changed_file")); cl_git_pass(git_submodule_status(&status, sm)); cl_assert(GIT_SUBMODULE_STATUS_IS_UNMODIFIED(status)); cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_changed_untracked_file")); cl_git_pass(git_submodule_status(&status, sm)); cl_assert(GIT_SUBMODULE_STATUS_IS_UNMODIFIED(status)); cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_missing_commits")); cl_git_pass(git_submodule_status(&status, sm)); cl_assert((status & GIT_SUBMODULE_STATUS_WD_MODIFIED) != 0); cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_added_and_uncommited")); cl_git_pass(git_submodule_status(&status, sm)); cl_assert((status & GIT_SUBMODULE_STATUS_INDEX_ADDED) != 0); /* removed sm_unchanged for deleted workdir */ cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_unchanged")); cl_git_pass(git_submodule_status(&status, sm)); cl_assert((status & GIT_SUBMODULE_STATUS_WD_DELETED) != 0); /* now mkdir sm_unchanged to test uninitialized */ cl_git_pass(git_futils_mkdir(git_buf_cstr(&path), NULL, 0755, 0)); cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_unchanged")); cl_git_pass(git_submodule_reload(sm)); cl_git_pass(git_submodule_status(&status, sm)); cl_assert((status & GIT_SUBMODULE_STATUS_WD_UNINITIALIZED) != 0); /* update sm_changed_head in index */ cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_changed_head")); cl_git_pass(git_submodule_add_to_index(sm, true)); /* reload is not needed because add_to_index updates the submodule data */ cl_git_pass(git_submodule_status(&status, sm)); cl_assert((status & GIT_SUBMODULE_STATUS_INDEX_MODIFIED) != 0); git_buf_free(&path); } void test_submodule_status__ignore_all(void) { unsigned int status; git_submodule *sm; git_buf path = GIT_BUF_INIT; git_submodule_ignore_t ign = GIT_SUBMODULE_IGNORE_ALL; cl_git_pass(git_buf_joinpath(&path, git_repository_workdir(g_repo), "sm_unchanged")); cl_git_pass(git_futils_rmdir_r(git_buf_cstr(&path), NULL, GIT_RMDIR_REMOVE_FILES)); cl_git_pass(git_submodule_foreach(g_repo, set_sm_ignore, &ign)); cl_assert_equal_i(GIT_ENOTFOUND, git_submodule_lookup(&sm, g_repo, "just_a_dir")); cl_assert_equal_i(GIT_EEXISTS, git_submodule_lookup(&sm, g_repo, "not-submodule")); cl_assert_equal_i(GIT_EEXISTS, git_submodule_lookup(&sm, g_repo, "not")); cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_changed_index")); cl_git_pass(git_submodule_status(&status, sm)); cl_assert(GIT_SUBMODULE_STATUS_IS_UNMODIFIED(status)); cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_changed_head")); cl_git_pass(git_submodule_status(&status, sm)); cl_assert(GIT_SUBMODULE_STATUS_IS_UNMODIFIED(status)); cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_changed_file")); cl_git_pass(git_submodule_status(&status, sm)); cl_assert(GIT_SUBMODULE_STATUS_IS_UNMODIFIED(status)); cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_changed_untracked_file")); cl_git_pass(git_submodule_status(&status, sm)); cl_assert(GIT_SUBMODULE_STATUS_IS_UNMODIFIED(status)); cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_missing_commits")); cl_git_pass(git_submodule_status(&status, sm)); cl_assert(GIT_SUBMODULE_STATUS_IS_UNMODIFIED(status)); cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_added_and_uncommited")); cl_git_pass(git_submodule_status(&status, sm)); cl_assert(GIT_SUBMODULE_STATUS_IS_UNMODIFIED(status)); /* removed sm_unchanged for deleted workdir */ cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_unchanged")); cl_git_pass(git_submodule_status(&status, sm)); cl_assert(GIT_SUBMODULE_STATUS_IS_UNMODIFIED(status)); /* now mkdir sm_unchanged to test uninitialized */ cl_git_pass(git_futils_mkdir(git_buf_cstr(&path), NULL, 0755, 0)); cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_unchanged")); cl_git_pass(git_submodule_reload(sm)); cl_git_pass(git_submodule_status(&status, sm)); cl_assert(GIT_SUBMODULE_STATUS_IS_UNMODIFIED(status)); /* update sm_changed_head in index */ cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_changed_head")); cl_git_pass(git_submodule_add_to_index(sm, true)); /* reload is not needed because add_to_index updates the submodule data */ cl_git_pass(git_submodule_status(&status, sm)); cl_assert(GIT_SUBMODULE_STATUS_IS_UNMODIFIED(status)); git_buf_free(&path); } typedef struct { size_t counter; const char **paths; } submodule_expectations; static int confirm_submodule_status( const char *path, unsigned int status_flags, void *payload) { submodule_expectations *exp = payload; while (git__suffixcmp(exp->paths[exp->counter], "/") == 0) exp->counter++; cl_assert_equal_s(exp->paths[exp->counter++], path); GIT_UNUSED(status_flags); return 0; } void test_submodule_status__iterator(void) { git_iterator *iter; const git_index_entry *entry; size_t i; static const char *expected[] = { ".gitmodules", "just_a_dir/", "just_a_dir/contents", "just_a_file", "not", "not-submodule", "README.txt", "sm_added_and_uncommited", "sm_changed_file", "sm_changed_head", "sm_changed_index", "sm_changed_untracked_file", "sm_missing_commits", "sm_unchanged", NULL }; submodule_expectations exp = { 0, expected }; git_status_options opts = GIT_STATUS_OPTIONS_INIT; cl_git_pass(git_iterator_for_workdir(&iter, g_repo, GIT_ITERATOR_IGNORE_CASE | GIT_ITERATOR_INCLUDE_TREES, NULL, NULL)); for (i = 0; !git_iterator_advance(&entry, iter); ++i) cl_assert_equal_s(expected[i], entry->path); git_iterator_free(iter); opts.flags = GIT_STATUS_OPT_INCLUDE_UNTRACKED | GIT_STATUS_OPT_INCLUDE_UNMODIFIED | GIT_STATUS_OPT_RECURSE_UNTRACKED_DIRS; cl_git_pass(git_status_foreach_ext( g_repo, &opts, confirm_submodule_status, &exp)); } void test_submodule_status__untracked_dirs_containing_ignored_files(void) { git_buf path = GIT_BUF_INIT; unsigned int status, expected; git_submodule *sm; cl_git_pass(git_buf_joinpath(&path, git_repository_path(g_repo), "modules/sm_unchanged/info/exclude")); cl_git_append2file(git_buf_cstr(&path), "\n*.ignored\n"); cl_git_pass(git_buf_joinpath(&path, git_repository_workdir(g_repo), "sm_unchanged/directory")); cl_git_pass(git_futils_mkdir(git_buf_cstr(&path), NULL, 0755, 0)); cl_git_pass(git_buf_joinpath(&path, git_buf_cstr(&path), "i_am.ignored")); cl_git_mkfile(git_buf_cstr(&path), "ignored this file, please\n"); cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_unchanged")); cl_git_pass(git_submodule_status(&status, sm)); cl_assert(GIT_SUBMODULE_STATUS_IS_UNMODIFIED(status)); expected = GIT_SUBMODULE_STATUS_IN_HEAD | GIT_SUBMODULE_STATUS_IN_INDEX | GIT_SUBMODULE_STATUS_IN_CONFIG | GIT_SUBMODULE_STATUS_IN_WD; cl_assert(status == expected); git_buf_free(&path); } libgit2-0.19.0/tests-clar/submodule/submodule_helpers.c000066400000000000000000000041101216214232500230740ustar00rootroot00000000000000#include "clar_libgit2.h" #include "buffer.h" #include "path.h" #include "util.h" #include "posix.h" #include "submodule_helpers.h" /* rewrite gitmodules -> .gitmodules * rewrite the empty or relative urls inside each module * rename the .gitted directory inside any submodule to .git */ void rewrite_gitmodules(const char *workdir) { git_buf in_f = GIT_BUF_INIT, out_f = GIT_BUF_INIT, path = GIT_BUF_INIT; FILE *in, *out; char line[256]; cl_git_pass(git_buf_joinpath(&in_f, workdir, "gitmodules")); cl_git_pass(git_buf_joinpath(&out_f, workdir, ".gitmodules")); cl_assert((in = fopen(in_f.ptr, "r")) != NULL); cl_assert((out = fopen(out_f.ptr, "w")) != NULL); while (fgets(line, sizeof(line), in) != NULL) { char *scan = line; while (*scan == ' ' || *scan == '\t') scan++; /* rename .gitted -> .git in submodule directories */ if (git__prefixcmp(scan, "path =") == 0) { scan += strlen("path ="); while (*scan == ' ') scan++; git_buf_joinpath(&path, workdir, scan); git_buf_rtrim(&path); git_buf_joinpath(&path, path.ptr, ".gitted"); if (!git_buf_oom(&path) && p_access(path.ptr, F_OK) == 0) { git_buf_joinpath(&out_f, workdir, scan); git_buf_rtrim(&out_f); git_buf_joinpath(&out_f, out_f.ptr, ".git"); if (!git_buf_oom(&out_f)) p_rename(path.ptr, out_f.ptr); } } /* copy non-"url =" lines verbatim */ if (git__prefixcmp(scan, "url =") != 0) { fputs(line, out); continue; } /* convert relative URLs in "url =" lines */ scan += strlen("url ="); while (*scan == ' ') scan++; if (*scan == '.') { git_buf_joinpath(&path, workdir, scan); git_buf_rtrim(&path); } else if (!*scan || *scan == '\n') { git_buf_joinpath(&path, workdir, "../testrepo.git"); } else { fputs(line, out); continue; } git_path_prettify(&path, path.ptr, NULL); git_buf_putc(&path, '\n'); cl_assert(!git_buf_oom(&path)); fwrite(line, scan - line, sizeof(char), out); fputs(path.ptr, out); } fclose(in); fclose(out); cl_must_pass(p_unlink(in_f.ptr)); git_buf_free(&in_f); git_buf_free(&out_f); git_buf_free(&path); } libgit2-0.19.0/tests-clar/submodule/submodule_helpers.h000066400000000000000000000000661216214232500231070ustar00rootroot00000000000000extern void rewrite_gitmodules(const char *workdir); libgit2-0.19.0/tests-clar/threads/000077500000000000000000000000001216214232500166465ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/threads/basic.c000066400000000000000000000005521216214232500200750ustar00rootroot00000000000000#include "clar_libgit2.h" #include "cache.h" static git_repository *g_repo; void test_threads_basic__initialize(void) { g_repo = cl_git_sandbox_init("testrepo"); } void test_threads_basic__cleanup(void) { cl_git_sandbox_cleanup(); } void test_threads_basic__cache(void) { // run several threads polling the cache at the same time cl_assert(1 == 1); } libgit2-0.19.0/tests-clar/trace/000077500000000000000000000000001216214232500163125ustar00rootroot00000000000000libgit2-0.19.0/tests-clar/trace/trace.c000066400000000000000000000033161216214232500175570ustar00rootroot00000000000000#include "clar_libgit2.h" #include "trace.h" static int written = 0; static void trace_callback(git_trace_level_t level, const char *message) { GIT_UNUSED(level); cl_assert(strcmp(message, "Hello world!") == 0); written = 1; } void test_trace_trace__initialize(void) { git_trace_set(GIT_TRACE_INFO, trace_callback); written = 0; } void test_trace_trace__cleanup(void) { git_trace_set(GIT_TRACE_NONE, NULL); } void test_trace_trace__sets(void) { #ifdef GIT_TRACE cl_assert(git_trace_level() == GIT_TRACE_INFO); #endif } void test_trace_trace__can_reset(void) { #ifdef GIT_TRACE cl_assert(git_trace_level() == GIT_TRACE_INFO); cl_git_pass(git_trace_set(GIT_TRACE_ERROR, trace_callback)); cl_assert(written == 0); git_trace(GIT_TRACE_INFO, "Hello %s!", "world"); cl_assert(written == 0); git_trace(GIT_TRACE_ERROR, "Hello %s!", "world"); cl_assert(written == 1); #endif } void test_trace_trace__can_unset(void) { #ifdef GIT_TRACE cl_assert(git_trace_level() == GIT_TRACE_INFO); cl_git_pass(git_trace_set(GIT_TRACE_NONE, NULL)); cl_assert(git_trace_level() == GIT_TRACE_NONE); cl_assert(written == 0); git_trace(GIT_TRACE_FATAL, "Hello %s!", "world"); cl_assert(written == 0); #endif } void test_trace_trace__skips_higher_level(void) { #ifdef GIT_TRACE cl_assert(written == 0); git_trace(GIT_TRACE_DEBUG, "Hello %s!", "world"); cl_assert(written == 0); #endif } void test_trace_trace__writes(void) { #ifdef GIT_TRACE cl_assert(written == 0); git_trace(GIT_TRACE_INFO, "Hello %s!", "world"); cl_assert(written == 1); #endif } void test_trace_trace__writes_lower_level(void) { #ifdef GIT_TRACE cl_assert(written == 0); git_trace(GIT_TRACE_ERROR, "Hello %s!", "world"); cl_assert(written == 1); #endif } libgit2-0.19.0/tests-clar/valgrind-supp-mac.txt000066400000000000000000000040741216214232500213130ustar00rootroot00000000000000{ libgit2-giterr-set-buffer Memcheck:Leak ... fun:git__realloc fun:git_buf_try_grow fun:git_buf_grow fun:git_buf_vprintf fun:giterr_set } { mac-setenv-leak-1 Memcheck:Leak fun:malloc_zone_malloc fun:__setenv fun:setenv } { mac-setenv-leak-2 Memcheck:Leak fun:malloc_zone_malloc fun:malloc_set_zone_name ... fun:init__zone0 fun:setenv } { mac-dyld-initializer-leak Memcheck:Leak fun:malloc ... fun:dyld_register_image_state_change_handler fun:_dyld_initializer } { mac-tz-leak-1 Memcheck:Leak ... fun:token_table_add fun:notify_register_check fun:notify_register_tz } { mac-tz-leak-2 Memcheck:Leak fun:malloc fun:tzload } { mac-tz-leak-3 Memcheck:Leak fun:malloc fun:tzsetwall_basic } { mac-tz-leak-4 Memcheck:Leak fun:malloc fun:gmtsub } { mac-system-init-leak-1 Memcheck:Leak ... fun:_libxpc_initializer fun:libSystem_initializer } { mac-system-init-leak-2 Memcheck:Leak ... fun:__keymgr_initializer fun:libSystem_initializer } { mac-puts-leak Memcheck:Leak fun:malloc fun:__smakebuf ... fun:puts } { mac-ssl-uninitialized-1 Memcheck:Cond obj:/usr/lib/libcrypto.0.9.8.dylib ... fun:ssl23_connect } { mac-ssl-uninitialized-2 Memcheck:Cond ... obj:/usr/lib/libssl.0.9.8.dylib ... fun:ssl23_connect } { mac-ssl-uninitialized-3 Memcheck:Value8 obj:/usr/lib/libcrypto.0.9.8.dylib ... fun:ssl23_connect } { mac-ssl-uninitialized-4 Memcheck:Param ... obj:/usr/lib/libcrypto.0.9.8.dylib ... fun:ssl23_connect } { mac-ssl-leak-1 Memcheck:Leak ... fun:ERR_load_strings } { mac-ssl-leak-2 Memcheck:Leak ... fun:SSL_library_init } { mac-ssl-leak-3 Memcheck:Leak ... fun:si_module_with_name fun:getaddrinfo } { mac-ssl-leak-4 Memcheck:Leak fun:malloc fun:CRYPTO_malloc ... fun:ssl3_get_server_certificate } { mac-ssl-leak-5 Memcheck:Leak fun:malloc fun:CRYPTO_malloc ... fun:ERR_put_error } { clar-printf-buf Memcheck:Leak fun:malloc fun:__smakebuf ... fun:printf fun:clar_print_init }