From 4b3ec53c78a8a7c512c9ad6d8695c568edb952db Mon Sep 17 00:00:00 2001 From: Ximin Luo Date: Fri, 10 Aug 2018 19:43:40 -0700 Subject: [PATCH] New upstream version 0.27.4+dfsg.1 --- .travis.yml | 1 + CHANGELOG.md | 83 +++- CMakeLists.txt | 2 +- appveyor.yml | 5 + cmake/Modules/FindPkgLibraries.cmake | 28 ++ examples/CMakeLists.txt | 1 - include/git2/version.h | 4 +- src/CMakeLists.txt | 12 +- src/attr_file.c | 5 + src/checkout.c | 4 +- src/delta.c | 58 +-- src/diff_print.c | 1 + src/hash/sha1dc/sha1.c | 90 +++- src/ignore.c | 10 - src/index.c | 40 +- src/odb_mempack.c | 1 + src/path.c | 202 ++++++++- src/path.h | 73 ++++ src/refdb_fs.c | 6 +- src/refs.c | 3 + src/refs.h | 4 + src/refspec.c | 5 +- src/remote.c | 2 +- src/revwalk.c | 33 +- src/streams/openssl.c | 3 +- src/streams/openssl.h | 3 +- src/submodule.c | 113 +++-- src/submodule.h | 13 + src/transports/local.c | 8 +- src/transports/smart_pkt.c | 10 +- src/transports/ssh.c | 3 +- src/tree.c | 2 +- src/util.c | 5 + src/worktree.c | 2 +- tests/CMakeLists.txt | 2 +- tests/attr/ignore.c | 16 + tests/checkout/nasty.c | 12 + tests/checkout/typechange.c | 26 ++ tests/delta/apply.c | 21 + tests/diff/binary.c | 1 + tests/diff/stats.c | 2 +- tests/fetchhead/nonetwork.c | 23 + tests/path/core.c | 394 +++++++++--------- tests/path/dotgit.c | 119 ++++++ tests/refs/dup.c | 2 + .../07/f9d4d85b75187e4db5b9cbcad3e6218582bd57 | Bin 0 -> 93 bytes .../2a/9eb82c733e31ae312cee349084dcbc6f69639a | Bin 0 -> 26 bytes .../42/1376db9e8aee847e9d774891e73098a7415e94 | Bin 0 -> 21 bytes .../e3/0b60b120761f44ebd0f0a7b0e9445ce8e11d68 | Bin 0 -> 146 bytes .../.gitted/refs/heads/gitmodules-symlink | 1 + tests/resources/revwalk.git/HEAD | 1 + tests/resources/revwalk.git/config | 6 + tests/resources/revwalk.git/description | 1 + .../resources/revwalk.git/objects/info/packs | 2 + ...dacb9971981a1a3264fd473da5b800f2715959.idx | Bin 0 -> 1520 bytes ...acb9971981a1a3264fd473da5b800f2715959.pack | Bin 0 -> 1862 bytes tests/resources/revwalk.git/packed-refs | 7 + tests/resources/revwalk.git/refs/.gitkeep | 0 tests/revwalk/basic.c | 27 ++ tests/submodule/escape.c | 98 +++++ tests/submodule/lookup.c | 45 +- tests/worktree/reflog.c | 26 ++ tests/worktree/repository.c | 1 + 63 files changed, 1289 insertions(+), 379 deletions(-) create mode 100644 cmake/Modules/FindPkgLibraries.cmake create mode 100644 tests/delta/apply.c create mode 100644 tests/path/dotgit.c create mode 100644 tests/resources/nasty/.gitted/objects/07/f9d4d85b75187e4db5b9cbcad3e6218582bd57 create mode 100644 tests/resources/nasty/.gitted/objects/2a/9eb82c733e31ae312cee349084dcbc6f69639a create mode 100644 tests/resources/nasty/.gitted/objects/42/1376db9e8aee847e9d774891e73098a7415e94 create mode 100644 tests/resources/nasty/.gitted/objects/e3/0b60b120761f44ebd0f0a7b0e9445ce8e11d68 create mode 100644 tests/resources/nasty/.gitted/refs/heads/gitmodules-symlink create mode 100644 tests/resources/revwalk.git/HEAD create mode 100644 tests/resources/revwalk.git/config create mode 100644 tests/resources/revwalk.git/description create mode 100644 tests/resources/revwalk.git/objects/info/packs create mode 100644 tests/resources/revwalk.git/objects/pack/pack-9adacb9971981a1a3264fd473da5b800f2715959.idx create mode 100644 tests/resources/revwalk.git/objects/pack/pack-9adacb9971981a1a3264fd473da5b800f2715959.pack create mode 100644 tests/resources/revwalk.git/packed-refs create mode 100644 tests/resources/revwalk.git/refs/.gitkeep create mode 100644 tests/submodule/escape.c diff --git a/.travis.yml b/.travis.yml index a4c8e91df..3a55e86b0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -21,6 +21,7 @@ env: - OPTIONS="-DTHREADSAFE=OFF -DBUILD_EXAMPLES=ON -DENABLE_WERROR=ON" dist: trusty +osx_image: xcode8.3 sudo: false addons: diff --git a/CHANGELOG.md b/CHANGELOG.md index ba0cb4ea8..be62aa63d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,13 +1,88 @@ -v0.27 + 1 +v0.27.4 +------- + +This is a security release fixing out-of-bounds reads when +processing smart-protocol "ng" packets. + +When parsing an "ng" packet, we keep track of both the current position +as well as the remaining length of the packet itself. But instead of +taking care not to exceed the length, we pass the current pointer's +position to `strchr`, which will search for a certain character until +hitting NUL. It is thus possible to create a crafted packet which +doesn't contain a NUL byte to trigger an out-of-bounds read. + +The issue was discovered by the oss-fuzz project, issue 9406. + +v0.27.3 +------- + +This is a security release fixing out-of-bounds reads when +reading objects from a packfile. This corresponds to +CVE-2018-10887 and CVE-2018-10888, which were both reported by +Riccardo Schirone. + +When packing objects into a single so-called packfile, objects +may not get stored as complete copies but instead as deltas +against another object "base". A specially crafted delta object +could trigger an integer overflow and thus bypass our input +validation, which may result in copying memory before or after +the base object into the final deflated object. This may lead to +objects containing copies of system memory being written into the +object database. As the hash of those objects cannot be easily +controlled by the attacker, it is unlikely that any of those +objects will be valid and referenced by the commit graph. + +Note that the error could also be triggered by the function +`git_apply__patch`. But as this function is not in use outside of +our test suite, it is not a possible attack vector. + +v0.27.2 --------- ### Changes or improvements -### API additions +* Fix builds with LibreSSL 2.7. -### API removals +* Fix for `git_diff_status_char()` not returning the correct mapping for + `GIT_DELTA_TYPECHANGE`. -### Breaking API changes +* Fix for the submodules API not reporting errors when parsing the ".gitmodules" + file. + +* Fix for accepting a ".gitmodules" file where two submodules have the same + path. + +* Fix for hiding references in a graph walk not always limiting the graph + correctly. + +* Fix for directory patterns with trailing spaces in attribute files not being + handled correctly. + +* Fix SSH transports not properly disconnecting from the server. + +* Fix reading HEAD reflog in worktrees. + +* Update our copy of SHA1DC to fix errors with endianess on some platforms. + +v0.27.1 +--------- + +This is a security release fixing insufficient validation of submodule names +(CVE-2018-11235, reported by Etienne Stalmans) and disallows `.gitmodules` files +as symlinks. + +While submodule names come from the untrusted ".gitmodules" file, we blindly +append the name to "$GIT_DIR/modules" to construct the final path of the +submodule repository. In case the name contains e.g. "../", an adversary would +be able to escape your repository and write data at arbitrary paths. In +accordance with git, we now enforce some rules for submodule names which will +cause libgit2 to ignore these malicious names. + +Adding a symlink as `.gitmodules` into the index from the workdir or checking +out such files is not allowed as this can make a Git implementation write +outside of the repository and bypass the `fsck` checks for CVE-2018-11235. + +libgit2 is not susceptible to CVE-2018-11233. v0.27 --------- diff --git a/CMakeLists.txt b/CMakeLists.txt index 2ca5354a7..7c1590271 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -29,7 +29,7 @@ INCLUDE(CheckFunctionExists) INCLUDE(CheckSymbolExists) INCLUDE(CheckStructHasMember) INCLUDE(AddCFlagIfSupported) -INCLUDE(FindPkgConfig) +INCLUDE(FindPkgLibraries) INCLUDE(FindThreads) INCLUDE(FindStatNsec) INCLUDE(IdeSplitSources) diff --git a/appveyor.yml b/appveyor.yml index 9b14a9c81..f76830cb4 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -43,6 +43,11 @@ build_script: if "%GENERATOR%"=="MSYS Makefiles" (C:\MinGW\msys\1.0\bin\sh --login /c/projects/libgit2/script/appveyor-mingw.sh) test_script: - ps: | + # Disable DHE key exchange to fix intermittent build failures ("A buffer + # provided was too small") due to SChannel bug. See e.g. + # - https://github.com/aws/aws-sdk-cpp/issues/671 + # - https://github.com/dotnet/corefx/issues/7812 + New-Item HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\KeyExchangeAlgorithms\Diffie-Hellman -Force | New-ItemProperty -Name Enabled -Value 0 -Force $ErrorActionPreference="Stop" Start-FileDownload https://github.com/ethomson/poxyproxy/releases/download/v0.1.0/poxyproxy-0.1.0.jar -FileName poxyproxy.jar # Run this early so we know it's ready by the time we need it diff --git a/cmake/Modules/FindPkgLibraries.cmake b/cmake/Modules/FindPkgLibraries.cmake new file mode 100644 index 000000000..49311c382 --- /dev/null +++ b/cmake/Modules/FindPkgLibraries.cmake @@ -0,0 +1,28 @@ +INCLUDE(FindPkgConfig) + +# This function will find and set up a pkg-config based module. +# If a pc-file was found, it will resolve library paths to +# absolute paths. Furthermore, the function will automatically +# fall back to use static libraries in case no dynamic libraries +# were found. +FUNCTION(FIND_PKGLIBRARIES prefix package) + PKG_CHECK_MODULES(${prefix} ${package}) + IF(NOT ${prefix}_FOUND) + RETURN() + ENDIF() + + FOREACH(LIBRARY ${${prefix}_LIBRARIES}) + FIND_LIBRARY(${LIBRARY}_RESOLVED ${LIBRARY} PATHS ${${prefix}_LIBRARY_DIRS}) + IF(${${LIBRARY}_RESOLVED} STREQUAL "${LIBRARY}_RESOLVED-NOTFOUND") + MESSAGE(FATAL_ERROR "could not resolve ${LIBRARY}") + ENDIF() + LIST(APPEND RESOLVED_LIBRARIES ${${LIBRARY}_RESOLVED}) + ENDFOREACH(LIBRARY) + + SET(${prefix}_FOUND 1 PARENT_SCOPE) + SET(${prefix}_LIBRARIES ${RESOLVED_LIBRARIES} PARENT_SCOPE) + SET(${prefix}_INCLUDE_DIRS ${${prefix}_INCLUDE_DIRS} PARENT_SCOPE) + SET(${prefix}_LDFLAGS ${${prefix}_LDFLAGS} PARENT_SCOPE) + + MESSAGE(STATUS " Resolved libraries: ${RESOLVED_LIBRARIES}") +ENDFUNCTION() diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 99e2ba9c1..ca7515e5d 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -1,4 +1,3 @@ -LINK_DIRECTORIES(${LIBGIT2_LIBDIRS}) INCLUDE_DIRECTORIES(${LIBGIT2_INCLUDES}) FILE(GLOB_RECURSE SRC_EXAMPLE_GIT2 network/*.c network/*.h common.?) diff --git a/include/git2/version.h b/include/git2/version.h index 746bf4230..7c4242657 100644 --- a/include/git2/version.h +++ b/include/git2/version.h @@ -7,10 +7,10 @@ #ifndef INCLUDE_git_version_h__ #define INCLUDE_git_version_h__ -#define LIBGIT2_VERSION "0.27.0" +#define LIBGIT2_VERSION "0.27.4" #define LIBGIT2_VER_MAJOR 0 #define LIBGIT2_VER_MINOR 27 -#define LIBGIT2_VER_REVISION 0 +#define LIBGIT2_VER_REVISION 4 #define LIBGIT2_VER_PATCH 0 #define LIBGIT2_SOVERSION 27 diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index b03b96af9..4cfb2d311 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -17,7 +17,6 @@ SET(LIBGIT2_INCLUDES "${libgit2_SOURCE_DIR}/src" "${libgit2_SOURCE_DIR}/include") SET(LIBGIT2_LIBS "") -SET(LIBGIT2_LIBDIRS "") # Installation paths # @@ -109,7 +108,6 @@ IF (WIN32 AND WINHTTP) ADD_SUBDIRECTORY("${libgit2_SOURCE_DIR}/deps/winhttp" "${libgit2_BINARY_DIR}/deps/winhttp") LIST(APPEND LIBGIT2_LIBS winhttp) LIST(APPEND LIBGIT2_INCLUDES "${libgit2_SOURCE_DIR}/deps/winhttp") - LIST(APPEND LIBGIT2_LIBDIRS ${LIBWINHTTP_PATH}) ELSE() LIST(APPEND LIBGIT2_LIBS "winhttp") LIST(APPEND LIBGIT2_PC_LIBS "-lwinhttp") @@ -119,13 +117,11 @@ IF (WIN32 AND WINHTTP) LIST(APPEND LIBGIT2_PC_LIBS "-lrpcrt4" "-lcrypt32" "-lole32") ELSE () IF (CURL) - PKG_CHECK_MODULES(CURL libcurl) + FIND_PKGLIBRARIES(CURL libcurl) ENDIF () - IF (CURL_FOUND) SET(GIT_CURL 1) LIST(APPEND LIBGIT2_INCLUDES ${CURL_INCLUDE_DIRS}) - LIST(APPEND LIBGIT2_LIBDIRS ${CURL_LIBRARY_DIRS}) LIST(APPEND LIBGIT2_LIBS ${CURL_LIBRARIES}) LIST(APPEND LIBGIT2_PC_LIBS ${CURL_LDFLAGS}) ENDIF() @@ -282,15 +278,13 @@ ENDIF() # Optional external dependency: libssh2 IF (USE_SSH) - PKG_CHECK_MODULES(LIBSSH2 libssh2) + FIND_PKGLIBRARIES(LIBSSH2 libssh2) ENDIF() IF (LIBSSH2_FOUND) SET(GIT_SSH 1) LIST(APPEND LIBGIT2_INCLUDES ${LIBSSH2_INCLUDE_DIRS}) LIST(APPEND LIBGIT2_LIBS ${LIBSSH2_LIBRARIES}) - LIST(APPEND LIBGIT2_LIBDIRS ${LIBSSH2_LIBRARY_DIRS}) LIST(APPEND LIBGIT2_PC_LIBS ${LIBSSH2_LDFLAGS}) - #SET(LIBGIT2_PC_LIBS "${LIBGIT2_PC_LIBS} ${LIBSSH2_LDFLAGS}") CHECK_LIBRARY_EXISTS("${LIBSSH2_LIBRARIES}" libssh2_userauth_publickey_frommemory "${LIBSSH2_LIBRARY_DIRS}" HAVE_LIBSSH2_MEMORY_CREDENTIALS) IF (HAVE_LIBSSH2_MEMORY_CREDENTIALS) @@ -404,7 +398,6 @@ ENDIF() SET(LIBGIT2_OBJECTS ${LIBGIT2_OBJECTS} PARENT_SCOPE) SET(LIBGIT2_INCLUDES ${LIBGIT2_INCLUDES} PARENT_SCOPE) SET(LIBGIT2_LIBS ${LIBGIT2_LIBS} PARENT_SCOPE) -SET(LIBGIT2_LIBDIRS ${LIBGIT2_LIBDIRS} PARENT_SCOPE) IF(XCODE_VERSION) # This is required for Xcode to actually link the libgit2 library @@ -414,7 +407,6 @@ IF(XCODE_VERSION) ENDIF() # Compile and link libgit2 -LINK_DIRECTORIES(${LIBGIT2_LIBDIRS}) ADD_LIBRARY(git2 ${WIN_RC} ${LIBGIT2_OBJECTS}) TARGET_LINK_LIBRARIES(git2 ${LIBGIT2_LIBS}) diff --git a/src/attr_file.c b/src/attr_file.c index 55d0c3865..f46cce3de 100644 --- a/src/attr_file.c +++ b/src/attr_file.c @@ -633,6 +633,11 @@ int git_attr_fnmatch__parse( if (--spec->length == 0) return GIT_ENOTFOUND; + /* Remove trailing spaces. */ + while (pattern[spec->length - 1] == ' ' || pattern[spec->length - 1] == '\t') + if (--spec->length == 0) + return GIT_ENOTFOUND; + if (pattern[spec->length - 1] == '/') { spec->length--; spec->flags = spec->flags | GIT_ATTR_FNMATCH_DIRECTORY; diff --git a/src/checkout.c b/src/checkout.c index 8ff5d897b..debdbe95b 100644 --- a/src/checkout.c +++ b/src/checkout.c @@ -1276,14 +1276,14 @@ static int checkout_verify_paths( unsigned int flags = GIT_PATH_REJECT_WORKDIR_DEFAULTS; if (action & CHECKOUT_ACTION__REMOVE) { - if (!git_path_isvalid(repo, delta->old_file.path, flags)) { + if (!git_path_isvalid(repo, delta->old_file.path, delta->old_file.mode, flags)) { giterr_set(GITERR_CHECKOUT, "cannot remove invalid path '%s'", delta->old_file.path); return -1; } } if (action & ~CHECKOUT_ACTION__REMOVE) { - if (!git_path_isvalid(repo, delta->new_file.path, flags)) { + if (!git_path_isvalid(repo, delta->new_file.path, delta->new_file.mode, flags)) { giterr_set(GITERR_CHECKOUT, "cannot checkout to invalid path '%s'", delta->new_file.path); return -1; } diff --git a/src/delta.c b/src/delta.c index 073cba7c6..b9352b8ee 100644 --- a/src/delta.c +++ b/src/delta.c @@ -539,10 +539,11 @@ int git_delta_apply( *out = NULL; *out_len = 0; - /* 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. - */ + /* + * 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; @@ -564,31 +565,34 @@ int git_delta_apply( 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++ << 8UL; - if (cmd & 0x04) off |= *delta++ << 16UL; - if (cmd & 0x08) off |= *delta++ << 24UL; - - if (cmd & 0x10) len = *delta++; - if (cmd & 0x20) len |= *delta++ << 8UL; - if (cmd & 0x40) len |= *delta++ << 16UL; - if (!len) len = 0x10000; - - if (base_len < off + len || res_sz < len) + /* cmd is a copy instruction; copy from the base. */ + size_t off = 0, len = 0, end; + +#define ADD_DELTA(o, shift) { if (delta < delta_end) (o) |= ((unsigned) *delta++ << shift); else goto fail; } + if (cmd & 0x01) ADD_DELTA(off, 0UL); + if (cmd & 0x02) ADD_DELTA(off, 8UL); + if (cmd & 0x04) ADD_DELTA(off, 16UL); + if (cmd & 0x08) ADD_DELTA(off, 24UL); + + if (cmd & 0x10) ADD_DELTA(len, 0UL); + if (cmd & 0x20) ADD_DELTA(len, 8UL); + if (cmd & 0x40) ADD_DELTA(len, 16UL); + if (!len) len = 0x10000; +#undef ADD_DELTA + + if (GIT_ADD_SIZET_OVERFLOW(&end, off, len) || + base_len < end || 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. - */ + } 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); @@ -596,10 +600,8 @@ int git_delta_apply( res_dp += cmd; res_sz -= cmd; - } - else { - /* cmd == 0 is reserved for future encodings. - */ + } else { + /* cmd == 0 is reserved for future encodings. */ goto fail; } } diff --git a/src/diff_print.c b/src/diff_print.c index 28ae38424..5e535482c 100644 --- a/src/diff_print.c +++ b/src/diff_print.c @@ -130,6 +130,7 @@ char git_diff_status_char(git_delta_t status) case GIT_DELTA_COPIED: code = 'C'; break; case GIT_DELTA_IGNORED: code = 'I'; break; case GIT_DELTA_UNTRACKED: code = '?'; break; + case GIT_DELTA_TYPECHANGE: code = 'T'; break; case GIT_DELTA_UNREADABLE: code = 'X'; break; default: code = ' '; break; } diff --git a/src/hash/sha1dc/sha1.c b/src/hash/sha1dc/sha1.c index facea1bb5..25eded139 100644 --- a/src/hash/sha1dc/sha1.c +++ b/src/hash/sha1dc/sha1.c @@ -10,6 +10,9 @@ #include #include #include +#ifdef __unix__ +#include /* make sure macros like _BIG_ENDIAN visible */ +#endif #endif #ifdef SHA1DC_CUSTOM_INCLUDE_SHA1_C @@ -23,6 +26,13 @@ #include "sha1.h" #include "ubc_check.h" +#if (defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64) || \ + defined(i386) || defined(__i386) || defined(__i386__) || defined(__i486__) || \ + defined(__i586__) || defined(__i686__) || defined(_M_IX86) || defined(__X86__) || \ + defined(_X86_) || defined(__THW_INTEL__) || defined(__I86__) || defined(__INTEL__) || \ + defined(__386) || defined(_M_X64) || defined(_M_AMD64)) +#define SHA1DC_ON_INTEL_LIKE_PROCESSOR +#endif /* Because Little-Endian architectures are most common, @@ -32,29 +42,70 @@ If you are compiling on a big endian platform and your compiler does not define one of these, you will have to add whatever macros your tool chain defines to indicate Big-Endianness. */ -#ifdef SHA1DC_BIGENDIAN -#undef SHA1DC_BIGENDIAN -#endif -#if (defined(_BYTE_ORDER) || defined(__BYTE_ORDER) || defined(__BYTE_ORDER__)) - -#if ((defined(_BYTE_ORDER) && (_BYTE_ORDER == _BIG_ENDIAN)) || \ - (defined(__BYTE_ORDER) && (__BYTE_ORDER == __BIG_ENDIAN)) || \ - (defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __BIG_ENDIAN__)) ) +#if defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) +/* + * Should detect Big Endian under GCC since at least 4.6.0 (gcc svn + * rev #165881). See + * https://gcc.gnu.org/onlinedocs/cpp/Common-Predefined-Macros.html + * + * This also works under clang since 3.2, it copied the GCC-ism. See + * clang.git's 3b198a97d2 ("Preprocessor: add __BYTE_ORDER__ + * predefined macro", 2012-07-27) + */ +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ #define SHA1DC_BIGENDIAN #endif -#else - -#if (defined(_BIG_ENDIAN) || defined(__BIG_ENDIAN) || defined(__BIG_ENDIAN__) || \ - defined(__ARMEB__) || defined(__THUMBEB__) || defined(__AARCH64EB__) || \ - defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || \ - defined(__sparc)) +/* Not under GCC-alike */ +#elif defined(__BYTE_ORDER) && defined(__BIG_ENDIAN) +/* + * Should detect Big Endian under glibc.git since 14245eb70e ("entered + * into RCS", 1992-11-25). Defined in which will have been + * brought in by standard headers. See glibc.git and + * https://sourceforge.net/p/predef/wiki/Endianness/ + */ +#if __BYTE_ORDER == __BIG_ENDIAN #define SHA1DC_BIGENDIAN #endif +/* Not under GCC-alike or glibc */ +#elif defined(_BYTE_ORDER) && defined(_BIG_ENDIAN) && defined(_LITTLE_ENDIAN) +/* + * *BSD and newlib (embeded linux, cygwin, etc). + * the defined(_BIG_ENDIAN) && defined(_LITTLE_ENDIAN) part prevents + * this condition from matching with Solaris/sparc. + * (Solaris defines only one endian macro) + */ +#if _BYTE_ORDER == _BIG_ENDIAN +#define SHA1DC_BIGENDIAN #endif +/* Not under GCC-alike or glibc or *BSD or newlib */ +#elif (defined(__ARMEB__) || defined(__THUMBEB__) || defined(__AARCH64EB__) || \ + defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || \ + defined(__sparc)) +/* + * Should define Big Endian for a whitelist of known processors. See + * https://sourceforge.net/p/predef/wiki/Endianness/ and + * http://www.oracle.com/technetwork/server-storage/solaris/portingtosolaris-138514.html + */ +#define SHA1DC_BIGENDIAN + +/* Not under GCC-alike or glibc or *BSD or newlib or */ +#elif defined(SHA1DC_ON_INTEL_LIKE_PROCESSOR) +/* + * As a last resort before we do anything else we're not 100% sure + * about below, we blacklist specific processors here. We could add + * more, see e.g. https://wiki.debian.org/ArchitectureSpecificsMemo + */ +#else /* Not under GCC-alike or glibc or *BSD or newlib or or */ + +/* We do nothing more here for now */ +/*#error "Uncomment this to see if you fall through all the detection"*/ + +#endif /* Big Endian detection */ + #if (defined(SHA1DC_FORCE_LITTLEENDIAN) && defined(SHA1DC_BIGENDIAN)) #undef SHA1DC_BIGENDIAN #endif @@ -63,15 +114,8 @@ #endif /*ENDIANNESS SELECTION*/ -#if (defined SHA1DC_FORCE_UNALIGNED_ACCESS || \ - defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64) || \ - defined(i386) || defined(__i386) || defined(__i386__) || defined(__i486__) || \ - defined(__i586__) || defined(__i686__) || defined(_M_IX86) || defined(__X86__) || \ - defined(_X86_) || defined(__THW_INTEL__) || defined(__I86__) || defined(__INTEL__) || \ - defined(__386) || defined(_M_X64) || defined(_M_AMD64)) - +#if defined(SHA1DC_FORCE_UNALIGNED_ACCESS) || defined(SHA1DC_ON_INTEL_LIKE_PROCESSOR) #define SHA1DC_ALLOW_UNALIGNED_ACCESS - #endif /*UNALIGNMENT DETECTION*/ @@ -918,7 +962,7 @@ static void sha1recompress_fast_ ## t (uint32_t ihvin[5], uint32_t ihvout[5], co #ifdef _MSC_VER #pragma warning(push) -#pragma warning(disable: 4127) /* Complier complains about the checks in the above macro being constant. */ +#pragma warning(disable: 4127) /* Compiler complains about the checks in the above macro being constant. */ #endif #ifdef DOSTORESTATE0 diff --git a/src/ignore.c b/src/ignore.c index dddd7e81e..76b997245 100644 --- a/src/ignore.c +++ b/src/ignore.c @@ -213,16 +213,6 @@ static int parse_ignore_file( if (ignore_case) match->flags |= GIT_ATTR_FNMATCH_ICASE; - while (match->length > 0) { - if (match->pattern[match->length - 1] == ' ' || - match->pattern[match->length - 1] == '\t') { - match->pattern[match->length - 1] = 0; - match->length --; - } else { - break; - } - } - scan = git__next_line(scan); /* diff --git a/src/index.c b/src/index.c index a867547fb..09313ebed 100644 --- a/src/index.c +++ b/src/index.c @@ -884,11 +884,13 @@ static int index_entry_create( git_index_entry **out, git_repository *repo, const char *path, + struct stat *st, bool from_workdir) { size_t pathlen = strlen(path), alloclen; struct entry_internal *entry; unsigned int path_valid_flags = GIT_PATH_REJECT_INDEX_DEFAULTS; + uint16_t mode = 0; /* always reject placing `.git` in the index and directory traversal. * when requested, disallow platform-specific filenames and upgrade to @@ -896,8 +898,10 @@ static int index_entry_create( */ if (from_workdir) path_valid_flags |= GIT_PATH_REJECT_WORKDIR_DEFAULTS; + if (st) + mode = st->st_mode; - if (!git_path_isvalid(repo, path, path_valid_flags)) { + if (!git_path_isvalid(repo, path, mode, path_valid_flags)) { giterr_set(GITERR_INDEX, "invalid path: '%s'", path); return -1; } @@ -922,15 +926,35 @@ static int index_entry_init( { int error = 0; git_index_entry *entry = NULL; + git_buf path = GIT_BUF_INIT; struct stat st; git_oid oid; + git_repository *repo; if (INDEX_OWNER(index) == NULL) return create_index_error(-1, "could not initialize index entry. " "Index is not backed up by an existing repository."); - if (index_entry_create(&entry, INDEX_OWNER(index), rel_path, true) < 0) + /* + * FIXME: this is duplicated with the work in + * git_blob__create_from_paths. It should accept an optional stat + * structure so we can pass in the one we have to do here. + */ + repo = INDEX_OWNER(index); + if (git_repository__ensure_not_bare(repo, "create blob from file") < 0) + return GIT_EBAREREPO; + + if (git_buf_joinpath(&path, git_repository_workdir(repo), rel_path) < 0) + return -1; + + error = git_path_lstat(path.ptr, &st); + git_buf_free(&path); + + if (error < 0) + return error; + + if (index_entry_create(&entry, INDEX_OWNER(index), rel_path, &st, true) < 0) return -1; /* write the blob to disk and get the oid and stat info */ @@ -1016,7 +1040,7 @@ static int index_entry_dup( git_index *index, const git_index_entry *src) { - if (index_entry_create(out, INDEX_OWNER(index), src->path, false) < 0) + if (index_entry_create(out, INDEX_OWNER(index), src->path, NULL, false) < 0) return -1; index_entry_cpy(*out, src); @@ -1038,7 +1062,7 @@ static int index_entry_dup_nocache( git_index *index, const git_index_entry *src) { - if (index_entry_create(out, INDEX_OWNER(index), src->path, false) < 0) + if (index_entry_create(out, INDEX_OWNER(index), src->path, NULL, false) < 0) return -1; index_entry_cpy_nocache(*out, src); @@ -1461,9 +1485,6 @@ static int add_repo_as_submodule(git_index_entry **out, git_index *index, const struct stat st; int error; - if (index_entry_create(&entry, INDEX_OWNER(index), path, true) < 0) - return -1; - if ((error = git_buf_joinpath(&abspath, git_repository_workdir(repo), path)) < 0) return error; @@ -1472,6 +1493,9 @@ static int add_repo_as_submodule(git_index_entry **out, git_index *index, const return -1; } + if (index_entry_create(&entry, INDEX_OWNER(index), path, &st, true) < 0) + return -1; + git_index_entry__init_from_stat(entry, &st, !index->distrust_filemode); if ((error = git_repository_open(&sub, abspath.ptr)) < 0) @@ -2965,7 +2989,7 @@ static int read_tree_cb( if (git_buf_joinpath(&path, root, tentry->filename) < 0) return -1; - if (index_entry_create(&entry, INDEX_OWNER(data->index), path.ptr, false) < 0) + if (index_entry_create(&entry, INDEX_OWNER(data->index), path.ptr, NULL, false) < 0) return -1; entry->mode = tentry->attr; diff --git a/src/odb_mempack.c b/src/odb_mempack.c index a81716ee3..e351d4df9 100644 --- a/src/odb_mempack.c +++ b/src/odb_mempack.c @@ -157,6 +157,7 @@ static void impl__free(git_odb_backend *_backend) { struct memory_packer_db *db = (struct memory_packer_db *)_backend; + git_mempack_reset(_backend); git_oidmap_free(db->objects); git__free(db); } diff --git a/src/path.c b/src/path.c index ea0a3c3f6..58a5aaf4a 100644 --- a/src/path.c +++ b/src/path.c @@ -1561,18 +1561,31 @@ static int32_t next_hfs_char(const char **in, size_t *len) return 0; /* NULL byte -- end of string */ } -static bool verify_dotgit_hfs(const char *path, size_t len) +static bool verify_dotgit_hfs_generic(const char *path, size_t len, const char *needle, size_t needle_len) { - if (next_hfs_char(&path, &len) != '.' || - next_hfs_char(&path, &len) != 'g' || - next_hfs_char(&path, &len) != 'i' || - next_hfs_char(&path, &len) != 't' || - next_hfs_char(&path, &len) != 0) + size_t i; + char c; + + if (next_hfs_char(&path, &len) != '.') + return true; + + for (i = 0; i < needle_len; i++) { + c = next_hfs_char(&path, &len); + if (c != needle[i]) + return true; + } + + if (next_hfs_char(&path, &len) != '\0') return true; return false; } +static bool verify_dotgit_hfs(const char *path, size_t len) +{ + return verify_dotgit_hfs_generic(path, len, "git", CONST_STRLEN("git")); +} + GIT_INLINE(bool) verify_dotgit_ntfs(git_repository *repo, const char *path, size_t len) { git_buf *reserved = git_repository__reserved_names_win32; @@ -1608,6 +1621,57 @@ GIT_INLINE(bool) verify_dotgit_ntfs(git_repository *repo, const char *path, size return false; } +GIT_INLINE(bool) only_spaces_and_dots(const char *path) +{ + const char *c = path; + + for (;; c++) { + if (*c == '\0') + return true; + if (*c != ' ' && *c != '.') + return false; + } + + return true; +} + +GIT_INLINE(bool) verify_dotgit_ntfs_generic(const char *name, size_t len, const char *dotgit_name, size_t dotgit_len, const char *shortname_pfix) +{ + int i, saw_tilde; + + if (name[0] == '.' && len >= dotgit_len && + !strncasecmp(name + 1, dotgit_name, dotgit_len)) { + return !only_spaces_and_dots(name + dotgit_len + 1); + } + + /* Detect the basic NTFS shortname with the first six chars */ + if (!strncasecmp(name, dotgit_name, 6) && name[6] == '~' && + name[7] >= '1' && name[7] <= '4') + return !only_spaces_and_dots(name + 8); + + /* Catch fallback names */ + for (i = 0, saw_tilde = 0; i < 8; i++) { + if (name[i] == '\0') { + return true; + } else if (saw_tilde) { + if (name[i] < '0' || name[i] > '9') + return true; + } else if (name[i] == '~') { + if (name[i+1] < '1' || name[i+1] > '9') + return true; + saw_tilde = 1; + } else if (i >= 6) { + return true; + } else if (name[i] < 0) { + return true; + } else if (git__tolower(name[i]) != shortname_pfix[i]) { + return true; + } + } + + return !only_spaces_and_dots(name + i); +} + GIT_INLINE(bool) verify_char(unsigned char c, unsigned int flags) { if ((flags & GIT_PATH_REJECT_BACKSLASH) && c == '\\') @@ -1635,6 +1699,24 @@ GIT_INLINE(bool) verify_char(unsigned char c, unsigned int flags) return true; } +/* + * Return the length of the common prefix between str and prefix, comparing them + * case-insensitively (must be ASCII to match). + */ +GIT_INLINE(size_t) common_prefix_icase(const char *str, size_t len, const char *prefix) +{ + size_t count = 0; + + while (len >0 && tolower(*str) == tolower(*prefix)) { + count++; + str++; + prefix++; + len--; + } + + return count; +} + /* * We fundamentally don't like some paths when dealing with user-inputted * strings (in checkout or ref names): we don't want dot or dot-dot @@ -1648,6 +1730,7 @@ static bool verify_component( git_repository *repo, const char *component, size_t len, + uint16_t mode, unsigned int flags) { if (len == 0) @@ -1680,26 +1763,38 @@ static bool verify_component( return false; } - if (flags & GIT_PATH_REJECT_DOT_GIT_HFS && - !verify_dotgit_hfs(component, len)) - return false; + if (flags & GIT_PATH_REJECT_DOT_GIT_HFS) { + if (!verify_dotgit_hfs(component, len)) + return false; + if (S_ISLNK(mode) && git_path_is_hfs_dotgit_modules(component, len)) + return false; + } - if (flags & GIT_PATH_REJECT_DOT_GIT_NTFS && - !verify_dotgit_ntfs(repo, component, len)) - return false; + if (flags & GIT_PATH_REJECT_DOT_GIT_NTFS) { + if (!verify_dotgit_ntfs(repo, component, len)) + return false; + if (S_ISLNK(mode) && git_path_is_ntfs_dotgit_modules(component, len)) + return false; + } /* don't bother rerunning the `.git` test if we ran the HFS or NTFS * specific tests, they would have already rejected `.git`. */ if ((flags & GIT_PATH_REJECT_DOT_GIT_HFS) == 0 && - (flags & GIT_PATH_REJECT_DOT_GIT_NTFS) == 0 && - (flags & GIT_PATH_REJECT_DOT_GIT_LITERAL) && - len == 4 && - component[0] == '.' && - (component[1] == 'g' || component[1] == 'G') && - (component[2] == 'i' || component[2] == 'I') && - (component[3] == 't' || component[3] == 'T')) - return false; + (flags & GIT_PATH_REJECT_DOT_GIT_NTFS) == 0 && + (flags & GIT_PATH_REJECT_DOT_GIT_LITERAL)) { + if (len >= 4 && + component[0] == '.' && + (component[1] == 'g' || component[1] == 'G') && + (component[2] == 'i' || component[2] == 'I') && + (component[3] == 't' || component[3] == 'T')) { + if (len == 4) + return false; + + if (S_ISLNK(mode) && common_prefix_icase(component, len, ".gitmodules") == len) + return false; + } + } return true; } @@ -1737,6 +1832,7 @@ GIT_INLINE(unsigned int) dotgit_flags( bool git_path_isvalid( git_repository *repo, const char *path, + uint16_t mode, unsigned int flags) { const char *start, *c; @@ -1750,14 +1846,14 @@ bool git_path_isvalid( return false; if (*c == '/') { - if (!verify_component(repo, start, (c - start), flags)) + if (!verify_component(repo, start, (c - start), mode, flags)) return false; start = c+1; } } - return verify_component(repo, start, (c - start), flags); + return verify_component(repo, start, (c - start), mode, flags); } int git_path_normalize_slashes(git_buf *out, const char *path) @@ -1775,3 +1871,65 @@ int git_path_normalize_slashes(git_buf *out, const char *path) return 0; } + +static int verify_dotgit_generic(const char *name, size_t len, const char *dotgit_name, size_t dotgit_len, const char *shortname_pfix) +{ + if (!verify_dotgit_ntfs_generic(name, len, dotgit_name, dotgit_len, shortname_pfix)) + return false; + + return verify_dotgit_hfs_generic(name, len, dotgit_name, dotgit_len); +} + +int git_path_is_ntfs_dotgit_modules(const char *name, size_t len) +{ + return !verify_dotgit_ntfs_generic(name, len, "gitmodules", CONST_STRLEN("gitmodules"), "gi7eba"); +} + +int git_path_is_hfs_dotgit_modules(const char *name, size_t len) +{ + return !verify_dotgit_hfs_generic(name, len, "gitmodules", CONST_STRLEN("gitmodules")); +} + +int git_path_is_dotgit_modules(const char *name, size_t len) +{ + if (git_path_is_hfs_dotgit_modules(name, len)) + return 1; + + return git_path_is_ntfs_dotgit_modules(name, len); +} + +int git_path_is_ntfs_dotgit_ignore(const char *name, size_t len) +{ + return !verify_dotgit_ntfs_generic(name, len, "gitignore", CONST_STRLEN("gitignore"), "gi250a"); +} + +int git_path_is_hfs_dotgit_ignore(const char *name, size_t len) +{ + return !verify_dotgit_hfs_generic(name, len, "gitignore", CONST_STRLEN("gitignore")); +} + +int git_path_is_dotgit_ignore(const char *name, size_t len) +{ + if (git_path_is_hfs_dotgit_ignore(name, len)) + return 1; + + return git_path_is_ntfs_dotgit_ignore(name, len); +} + +int git_path_is_hfs_dotgit_attributes(const char *name, size_t len) +{ + return !verify_dotgit_hfs_generic(name, len, "gitattributes", CONST_STRLEN("gitattributes")); +} + +int git_path_is_ntfs_dotgit_attributes(const char *name, size_t len) +{ + return !verify_dotgit_ntfs_generic(name, len, "gitattributes", CONST_STRLEN("gitattributes"), "gi7d29"); +} + +int git_path_is_dotgit_attributes(const char *name, size_t len) +{ + if (git_path_is_hfs_dotgit_attributes(name, len)) + return 1; + + return git_path_is_ntfs_dotgit_attributes(name, len); +} diff --git a/src/path.h b/src/path.h index aa24bcd2f..fd515c8a2 100644 --- a/src/path.h +++ b/src/path.h @@ -637,6 +637,7 @@ extern int git_path_from_url_or_path(git_buf *local_path_out, const char *url_or extern bool git_path_isvalid( git_repository *repo, const char *path, + uint16_t mode, unsigned int flags); /** @@ -644,4 +645,76 @@ extern bool git_path_isvalid( */ int git_path_normalize_slashes(git_buf *out, const char *path); +/** + * Check whether a path component corresponds to a .gitmodules file + * + * @param name the path component to check + * @param len the length of `name` + */ +extern int git_path_is_dotgit_modules(const char *name, size_t len); + +/** + * Check whether a path component corresponds to a .gitmodules file in NTFS + * + * @param name the path component to check + * @param len the length of `name` + */ +extern int git_path_is_ntfs_dotgit_modules(const char *name, size_t len); + +/** + * Check whether a path component corresponds to a .gitmodules file in HFS+ + * + * @param name the path component to check + * @param len the length of `name` + */ +extern int git_path_is_hfs_dotgit_modules(const char *name, size_t len); + +/** + * Check whether a path component corresponds to a .gitignore file + * + * @param name the path component to check + * @param len the length of `name` + */ +extern int git_path_is_dotgit_ignore(const char *name, size_t len); + +/** + * Check whether a path component corresponds to a .gitignore file in NTFS + * + * @param name the path component to check + * @param len the length of `name` + */ +extern int git_path_is_ntfs_dotgit_ignore(const char *name, size_t len); + +/** + * Check whether a path component corresponds to a .gitignore file in HFS+ + * + * @param name the path component to check + * @param len the length of `name` + */ +extern int git_path_is_hfs_dotgit_ignore(const char *name, size_t len); + +/** + * Check whether a path component corresponds to a .gitignore file + * + * @param name the path component to check + * @param len the length of `name` + */ +extern int git_path_is_dotgit_attributes(const char *name, size_t len); + +/** + * Check whether a path component corresponds to a .gitattributes file in NTFS + * + * @param name the path component to check + * @param len the length of `name` + */ +extern int git_path_is_ntfs_dotgit_attributes(const char *name, size_t len); + +/** + * Check whether a path component corresponds to a .gitattributes file in HFS+ + * + * @param name the path component to check + * @param len the length of `name` + */ +extern int git_path_is_hfs_dotgit_attributes(const char *name, size_t len); + #endif diff --git a/src/refdb_fs.c b/src/refdb_fs.c index 140879d23..83174e8cd 100644 --- a/src/refdb_fs.c +++ b/src/refdb_fs.c @@ -744,7 +744,7 @@ static int loose_lock(git_filebuf *file, refdb_fs_backend *backend, const char * assert(file && backend && name); - if (!git_path_isvalid(backend->repo, name, GIT_PATH_REJECT_FILESYSTEM_DEFAULTS)) { + if (!git_path_isvalid(backend->repo, name, 0, GIT_PATH_REJECT_FILESYSTEM_DEFAULTS)) { giterr_set(GITERR_INVALID, "invalid reference name '%s'", name); return GIT_EINVALIDSPEC; } @@ -1603,6 +1603,8 @@ static int create_new_reflog_file(const char *filepath) GIT_INLINE(int) retrieve_reflog_path(git_buf *path, git_repository *repo, const char *name) { + if (strcmp(name, GIT_HEAD_FILE) == 0) + return git_buf_join3(path, '/', repo->gitdir, GIT_REFLOG_DIR, name); return git_buf_join3(path, '/', repo->commondir, GIT_REFLOG_DIR, name); } @@ -1740,7 +1742,7 @@ static int lock_reflog(git_filebuf *file, refdb_fs_backend *backend, const char repo = backend->repo; - if (!git_path_isvalid(backend->repo, refname, GIT_PATH_REJECT_FILESYSTEM_DEFAULTS)) { + if (!git_path_isvalid(backend->repo, refname, 0, GIT_PATH_REJECT_FILESYSTEM_DEFAULTS)) { giterr_set(GITERR_INVALID, "invalid reference name '%s'", refname); return GIT_EINVALIDSPEC; } diff --git a/src/refs.c b/src/refs.c index 550963e56..c42968359 100644 --- a/src/refs.c +++ b/src/refs.c @@ -115,6 +115,9 @@ int git_reference_dup(git_reference **dest, git_reference *source) GITERR_CHECK_ALLOC(*dest); + (*dest)->db = source->db; + GIT_REFCOUNT_INC((*dest)->db); + return 0; } diff --git a/src/refs.h b/src/refs.h index 5149c7547..84daf8b53 100644 --- a/src/refs.h +++ b/src/refs.h @@ -116,6 +116,10 @@ int git_reference_lookup_resolved( * with the given name pointing to the reference pointed to by * the file. If it is not a symbolic reference, it will return * the resolved reference. + * + * Note that because the refdb is not involved for symbolic references, they + * won't be owned, hence you should either not make the returned reference + * 'externally visible', or perform the lookup before returning it to the user. */ int git_reference__read_head( git_reference **out, diff --git a/src/refspec.c b/src/refspec.c index 01a77c97f..943a9c76a 100644 --- a/src/refspec.c +++ b/src/refspec.c @@ -304,6 +304,7 @@ int git_refspec__dwim_one(git_vector *out, git_refspec *spec, git_vector *refs) git_buf buf = GIT_BUF_INIT; size_t j, pos; git_remote_head key; + git_refspec *cur; const char* formatters[] = { GIT_REFS_DIR "%s", @@ -312,7 +313,9 @@ int git_refspec__dwim_one(git_vector *out, git_refspec *spec, git_vector *refs) NULL }; - git_refspec *cur = git__calloc(1, sizeof(git_refspec)); + assert(out && spec && refs); + + cur = git__calloc(1, sizeof(git_refspec)); GITERR_CHECK_ALLOC(cur); cur->force = spec->force; diff --git a/src/remote.c b/src/remote.c index 4d675af82..d8a6b991d 100644 --- a/src/remote.c +++ b/src/remote.c @@ -237,7 +237,7 @@ static int create_internal(git_remote **out, git_repository *repo, const char *n goto on_error; /* only write for non-anonymous remotes */ - if (name && (error = write_add_refspec(repo, name, fetch, true)) < 0) + if (repo && name && (error = write_add_refspec(repo, name, fetch, true)) < 0) goto on_error; if (repo && (error = lookup_remote_prune_config(remote, config_ro, name)) < 0) diff --git a/src/revwalk.c b/src/revwalk.c index b1aa8f91a..eb228a522 100644 --- a/src/revwalk.c +++ b/src/revwalk.c @@ -375,20 +375,6 @@ static int add_parents_to_list(git_revwalk *walk, git_commit_list_node *commit, return 0; } -static int everybody_uninteresting(git_commit_list *orig) -{ - git_commit_list *list = orig; - - while (list) { - git_commit_list_node *commit = list->item; - list = list->next; - if (!commit->uninteresting) - return 0; - } - - return 1; -} - /* How many unintersting commits we want to look at after we run out of interesting ones */ #define SLOP 5 @@ -398,16 +384,15 @@ static int still_interesting(git_commit_list *list, int64_t time, int slop) if (!list) return 0; - /* - * If the destination list has commits with an earlier date - * than our source we want to continue looking. - */ - if (time <= list->item->time) - return SLOP; - - /* If we find interesting commits, we reset the slop count */ - if (!everybody_uninteresting(list)) - return SLOP; + for (; list; list = list->next) { + /* + * If the destination list has commits with an earlier date than + * our source or if it still contains interesting commits we + * want to continue looking. + */ + if (!list->item->uninteresting || list->item->time > time) + return SLOP; + } /* Everything's uninteresting, reduce the count */ return slop - 1; diff --git a/src/streams/openssl.c b/src/streams/openssl.c index 9cbb2746f..adcb7f14e 100644 --- a/src/streams/openssl.c +++ b/src/streams/openssl.c @@ -104,7 +104,8 @@ int git_openssl_stream_global_init(void) ssl_opts |= SSL_OP_NO_COMPRESSION; #endif -#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER) +#if OPENSSL_VERSION_NUMBER < 0x10100000L || \ + (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x20700000L) SSL_load_error_strings(); OpenSSL_add_ssl_algorithms(); #else diff --git a/src/streams/openssl.h b/src/streams/openssl.h index 2bbad7c68..44329ec90 100644 --- a/src/streams/openssl.h +++ b/src/streams/openssl.h @@ -31,7 +31,8 @@ extern int git_openssl__set_cert_location(const char *file, const char *path); -# if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER) +# if OPENSSL_VERSION_NUMBER < 0x10100000L || \ + (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x20700000L) GIT_INLINE(BIO_METHOD*) BIO_meth_new(int type, const char *name) { diff --git a/src/submodule.c b/src/submodule.c index 3ec0307b3..4bf74dcfb 100644 --- a/src/submodule.c +++ b/src/submodule.c @@ -91,7 +91,7 @@ __KHASH_IMPL( static int submodule_alloc(git_submodule **out, git_repository *repo, const char *name); static git_config_backend *open_gitmodules(git_repository *repo, int gitmod); -static git_config *gitmodules_snapshot(git_repository *repo); +static int gitmodules_snapshot(git_config **snap, git_repository *repo); static int get_url_base(git_buf *url, git_repository *repo); static int lookup_head_remote_key(git_buf *remote_key, git_repository *repo); static int lookup_default_remote(git_remote **remote, git_repository *repo); @@ -169,13 +169,13 @@ static void free_submodule_names(git_strmap *names) * TODO: for some use-cases, this might need case-folding on a * case-insensitive filesystem */ -static int load_submodule_names(git_strmap *out, git_config *cfg) +static int load_submodule_names(git_strmap *out, git_repository *repo, git_config *cfg) { const char *key = "submodule\\..*\\.path"; git_config_iterator *iter; git_config_entry *entry; git_buf buf = GIT_BUF_INIT; - int rval; + int rval, isvalid; int error = 0; if ((error = git_config_iterator_glob_new(&iter, cfg, key)) < 0) @@ -186,16 +186,36 @@ static int load_submodule_names(git_strmap *out, git_config *cfg) fdot = strchr(entry->name, '.'); ldot = strrchr(entry->name, '.'); + if (git_strmap_exists(out, entry->value)) { + giterr_set(GITERR_SUBMODULE, + "duplicated submodule path '%s'", entry->value); + error = -1; + goto out; + } + + git_buf_clear(&buf); git_buf_put(&buf, fdot + 1, ldot - fdot - 1); + isvalid = git_submodule_name_is_valid(repo, buf.ptr, 0); + if (isvalid < 0) { + error = isvalid; + goto out; + } + if (!isvalid) + continue; + git_strmap_insert(out, entry->value, git_buf_detach(&buf), &rval); if (rval < 0) { giterr_set(GITERR_NOMEMORY, "error inserting submodule into hash table"); return -1; } } + if (error == GIT_ITEROVER) + error = 0; +out: + git_buf_free(&buf); git_config_iterator_free(iter); - return 0; + return error; } int git_submodule_lookup( @@ -314,6 +334,28 @@ int git_submodule_lookup( return 0; } +int git_submodule_name_is_valid(git_repository *repo, const char *name, int flags) +{ + git_buf buf = GIT_BUF_INIT; + int error, isvalid; + + if (flags == 0) + flags = GIT_PATH_REJECT_FILESYSTEM_DEFAULTS; + + /* Avoid allocating a new string if we can avoid it */ + if (strchr(name, '\\') != NULL) { + if ((error = git_path_normalize_slashes(&buf, name)) < 0) + return error; + } else { + git_buf_attach_notowned(&buf, name, strlen(name)); + } + + isvalid = git_path_isvalid(repo, buf.ptr, 0, flags); + git_buf_free(&buf); + + return isvalid; +} + static void submodule_free_dup(void *sm) { git_submodule_free(sm); @@ -359,7 +401,7 @@ static int submodules_from_index(git_strmap *map, git_index *idx, git_config *cf git_strmap *names = 0; git_strmap_alloc(&names); - if ((error = load_submodule_names(names, cfg))) + if ((error = load_submodule_names(names, git_index_owner(idx), cfg))) goto done; if ((error = git_iterator_for_index(&i, git_index_owner(idx), idx, NULL)) < 0) @@ -411,7 +453,7 @@ static int submodules_from_head(git_strmap *map, git_tree *head, git_config *cfg const git_index_entry *entry; git_strmap *names = 0; git_strmap_alloc(&names); - if ((error = load_submodule_names(names, cfg))) + if ((error = load_submodule_names(names, git_tree_owner(head), cfg))) goto done; if ((error = git_iterator_for_tree(&i, head, NULL)) < 0) @@ -509,8 +551,11 @@ int git_submodule__map(git_repository *repo, git_strmap *map) data.map = map; data.repo = repo; - if ((mods = gitmodules_snapshot(repo)) == NULL) + if ((error = gitmodules_snapshot(&mods, repo)) < 0) { + if (error == GIT_ENOTFOUND) + error = 0; goto cleanup; + } data.mods = mods; if ((error = git_config_foreach( @@ -1502,16 +1547,23 @@ static int submodule_update_head(git_submodule *submodule) int git_submodule_reload(git_submodule *sm, int force) { - int error = 0; + int error = 0, isvalid; git_config *mods; GIT_UNUSED(force); assert(sm); + isvalid = git_submodule_name_is_valid(sm->repo, sm->name, 0); + if (isvalid <= 0) { + /* This should come with a warning, but we've no API for that */ + return isvalid; + } + if (!git_repository_is_bare(sm->repo)) { /* refresh config data */ - mods = gitmodules_snapshot(sm->repo); + if ((error = gitmodules_snapshot(&mods, sm->repo)) < 0 && error != GIT_ENOTFOUND) + return error; if (mods != NULL) { error = submodule_read_config(sm, mods); git_config_free(mods); @@ -1849,7 +1901,7 @@ static int submodule_load_each(const git_config_entry *entry, void *payload) git_strmap *map = data->map; git_buf name = GIT_BUF_INIT; git_submodule *sm; - int error; + int error, isvalid; if (git__prefixcmp(entry->name, "submodule.") != 0) return 0; @@ -1865,6 +1917,12 @@ static int submodule_load_each(const git_config_entry *entry, void *payload) if ((error = git_buf_set(&name, namestart, property - namestart -1)) < 0) return error; + isvalid = git_submodule_name_is_valid(data->repo, name.ptr, 0); + if (isvalid <= 0) { + error = isvalid; + goto done; + } + /* * Now that we have the submodule's name, we can use that to * figure out whether it's in the map. If it's not, we create @@ -1915,32 +1973,37 @@ static int submodule_load_from_wd_lite(git_submodule *sm) } /** - * Returns a snapshot of $WORK_TREE/.gitmodules. + * Requests a snapshot of $WORK_TREE/.gitmodules. * - * We ignore any errors and just pretend the file isn't there. + * Returns GIT_ENOTFOUND in case no .gitmodules file exist */ -static git_config *gitmodules_snapshot(git_repository *repo) +static int gitmodules_snapshot(git_config **snap, git_repository *repo) { const char *workdir = git_repository_workdir(repo); - git_config *mods = NULL, *snap = NULL; + git_config *mods = NULL; git_buf path = GIT_BUF_INIT; + int error; - if (workdir != NULL) { - if (git_buf_joinpath(&path, workdir, GIT_MODULES_FILE) != 0) - return NULL; + if (!workdir) + return GIT_ENOTFOUND; - if (git_config_open_ondisk(&mods, path.ptr) < 0) - mods = NULL; - } + if ((error = git_buf_joinpath(&path, workdir, GIT_MODULES_FILE)) < 0) + return error; - git_buf_free(&path); + if ((error = git_config_open_ondisk(&mods, path.ptr)) < 0) + goto cleanup; + + if ((error = git_config_snapshot(snap, mods)) < 0) + goto cleanup; - if (mods) { - git_config_snapshot(&snap, mods); + error = 0; + +cleanup: + if (mods) git_config_free(mods); - } + git_buf_free(&path); - return snap; + return error; } static git_config_backend *open_gitmodules( diff --git a/src/submodule.h b/src/submodule.h index 72867a322..91a4e1223 100644 --- a/src/submodule.h +++ b/src/submodule.h @@ -148,4 +148,17 @@ extern int git_submodule_parse_update( extern int git_submodule__map( git_repository *repo, git_strmap *map); + +/** + * Check whether a submodule's name is valid. + * + * Check the path against the path validity rules, either the filesystem + * defaults (like checkout does) or whichever you want to compare against. + * + * @param repo the repository which contains the submodule + * @param name the name to check + * @param flags the `GIT_PATH` flags to use for the check (0 to use filesystem defaults) + */ +extern int git_submodule_name_is_valid(git_repository *repo, const char *name, int flags); + #endif diff --git a/src/transports/local.c b/src/transports/local.c index 740cf36a9..541c552f6 100644 --- a/src/transports/local.c +++ b/src/transports/local.c @@ -510,8 +510,14 @@ static int local_counting(int stage, unsigned int current, unsigned int total, v static int foreach_reference_cb(git_reference *reference, void *payload) { git_revwalk *walk = (git_revwalk *)payload; + int error; + + if (git_reference_type(reference) != GIT_REF_OID) { + git_reference_free(reference); + return 0; + } - int error = git_revwalk_hide(walk, git_reference_target(reference)); + error = git_revwalk_hide(walk, git_reference_target(reference)); /* The reference is in the local repository, so the target may not * exist on the remote. It also may not be a commit. */ if (error == GIT_ENOTFOUND || error == GITERR_INVALID) { diff --git a/src/transports/smart_pkt.c b/src/transports/smart_pkt.c index a661dfe13..d10d6c68f 100644 --- a/src/transports/smart_pkt.c +++ b/src/transports/smart_pkt.c @@ -299,8 +299,11 @@ static int ng_pkt(git_pkt **out, const char *line, size_t len) pkt->ref = NULL; pkt->type = GIT_PKT_NG; + if (len < 3) + goto out_err; line += 3; /* skip "ng " */ - if (!(ptr = strchr(line, ' '))) + len -= 3; + if (!(ptr = memchr(line, ' ', len))) goto out_err; len = ptr - line; @@ -311,8 +314,11 @@ static int ng_pkt(git_pkt **out, const char *line, size_t len) memcpy(pkt->ref, line, len); pkt->ref[len] = '\0'; + if (len < 1) + goto out_err; line = ptr + 1; - if (!(ptr = strchr(line, '\n'))) + len -= 1; + if (!(ptr = memchr(line, '\n', len))) goto out_err; len = ptr - line; diff --git a/src/transports/ssh.c b/src/transports/ssh.c index dcd9b5e27..23c643346 100644 --- a/src/transports/ssh.c +++ b/src/transports/ssh.c @@ -212,6 +212,7 @@ static void ssh_stream_free(git_smart_subtransport_stream *stream) } if (s->session) { + libssh2_session_disconnect(s->session, "closing transport"); libssh2_session_free(s->session); s->session = NULL; } @@ -489,7 +490,7 @@ static int _git_ssh_session_create( } do { - rc = libssh2_session_startup(s, socket->s); + rc = libssh2_session_handshake(s, socket->s); } while (LIBSSH2_ERROR_EAGAIN == rc || LIBSSH2_ERROR_TIMEOUT == rc); if (rc != LIBSSH2_ERROR_NONE) { diff --git a/src/tree.c b/src/tree.c index fdf36f850..12622975a 100644 --- a/src/tree.c +++ b/src/tree.c @@ -54,7 +54,7 @@ GIT_INLINE(git_filemode_t) normalize_filemode(git_filemode_t filemode) static int valid_entry_name(git_repository *repo, const char *filename) { return *filename != '\0' && - git_path_isvalid(repo, filename, + git_path_isvalid(repo, filename, 0, GIT_PATH_REJECT_TRAVERSAL | GIT_PATH_REJECT_DOT_GIT | GIT_PATH_REJECT_SLASH); } diff --git a/src/util.c b/src/util.c index 34841df4f..2955b7ca0 100644 --- a/src/util.c +++ b/src/util.c @@ -10,7 +10,12 @@ #include "common.h" #ifdef GIT_WIN32 +# include "win32/utf-conv.h" # include "win32/w32_buffer.h" + +# ifdef HAVE_QSORT_S +# include +# endif #endif #ifdef _MSC_VER diff --git a/src/worktree.c b/src/worktree.c index 4b18db7d6..91527663e 100644 --- a/src/worktree.c +++ b/src/worktree.c @@ -131,7 +131,7 @@ static int open_worktree_dir(git_worktree **out, const char *parent, const char goto out; } - if ((wt = git__calloc(1, sizeof(struct git_repository))) == NULL) { + if ((wt = git__calloc(1, sizeof(*wt))) == NULL) { error = -1; goto out; } diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 775f33f2d..82bf6d0d7 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -9,6 +9,7 @@ SET(CLAR_FIXTURES "${CMAKE_CURRENT_SOURCE_DIR}/resources/") SET(CLAR_PATH "${CMAKE_CURRENT_SOURCE_DIR}") ADD_DEFINITIONS(-DCLAR_FIXTURE_PATH=\"${CLAR_FIXTURES}\") ADD_DEFINITIONS(-DCLAR_TMPDIR=\"libgit2_tests\") +ADD_DEFINITIONS(-D_FILE_OFFSET_BITS=64) INCLUDE_DIRECTORIES(${CLAR_PATH} ${libgit2_BINARY_DIR}/src) FILE(GLOB_RECURSE SRC_TEST ${CLAR_PATH}/*/*.c ${CLAR_PATH}/*/*.h) @@ -30,7 +31,6 @@ SET_SOURCE_FILES_PROPERTIES( ${CLAR_PATH}/clar.c PROPERTIES OBJECT_DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/clar.suite) -LINK_DIRECTORIES(${LIBGIT2_LIBDIRS}) INCLUDE_DIRECTORIES(${LIBGIT2_INCLUDES}) ADD_EXECUTABLE(libgit2_clar ${SRC_CLAR} ${SRC_TEST} ${LIBGIT2_OBJECTS}) diff --git a/tests/attr/ignore.c b/tests/attr/ignore.c index d241c03b5..165e2ba09 100644 --- a/tests/attr/ignore.c +++ b/tests/attr/ignore.c @@ -61,6 +61,22 @@ void test_attr_ignore__ignore_space(void) assert_is_ignored(true, "NewFolder/NewFolder/File.txt"); } +void test_attr_ignore__ignore_dir(void) +{ + cl_git_rewritefile("attr/.gitignore", "dir/\n"); + + assert_is_ignored(true, "dir"); + assert_is_ignored(true, "dir/file"); +} + +void test_attr_ignore__ignore_dir_with_trailing_space(void) +{ + cl_git_rewritefile("attr/.gitignore", "dir/ \n"); + + assert_is_ignored(true, "dir"); + assert_is_ignored(true, "dir/file"); +} + void test_attr_ignore__ignore_root(void) { cl_git_rewritefile("attr/.gitignore", "/\n\n/NewFolder\n/NewFolder/NewFolder"); diff --git a/tests/checkout/nasty.c b/tests/checkout/nasty.c index 952a6a112..d4d3c8fa4 100644 --- a/tests/checkout/nasty.c +++ b/tests/checkout/nasty.c @@ -364,3 +364,15 @@ void test_checkout_nasty__symlink3(void) test_checkout_passes("refs/heads/symlink3", ".git/foobar"); } +void test_checkout_nasty__gitmodules_symlink(void) +{ + cl_repo_set_bool(repo, "core.protectHFS", true); + test_checkout_fails("refs/heads/gitmodules-symlink", ".gitmodules"); + cl_repo_set_bool(repo, "core.protectHFS", false); + + cl_repo_set_bool(repo, "core.protectNTFS", true); + test_checkout_fails("refs/heads/gitmodules-symlink", ".gitmodules"); + cl_repo_set_bool(repo, "core.protectNTFS", false); + + test_checkout_fails("refs/heads/gitmodules-symlink", ".gitmodules"); +} diff --git a/tests/checkout/typechange.c b/tests/checkout/typechange.c index 8a5110caa..647b534b1 100644 --- a/tests/checkout/typechange.c +++ b/tests/checkout/typechange.c @@ -1,4 +1,5 @@ #include "clar_libgit2.h" +#include "diff_generate.h" #include "git2/checkout.h" #include "path.h" #include "posix.h" @@ -307,3 +308,28 @@ void test_checkout_typechange__checkout_with_conflicts(void) git_object_free(obj); } } + +void test_checkout_typechange__status_char(void) +{ + size_t i; + git_oid oid; + git_commit *commit; + git_diff *diff; + const git_diff_delta *delta; + git_diff_options diffopts = GIT_DIFF_OPTIONS_INIT; + char expected[8] = {'M', 'M', 'R', 'T', 'D', 'R', 'A', 'R'}; + + git_oid_fromstr(&oid, "9b19edf33a03a0c59cdfc113bfa5c06179bf9b1a"); + cl_git_pass(git_commit_lookup(&commit, g_repo, &oid)); + diffopts.flags |= GIT_DIFF_INCLUDE_TYPECHANGE; + cl_git_pass(git_diff__commit(&diff, g_repo, commit, &diffopts)); + cl_git_pass(git_diff_find_similar(diff, NULL)); + + for (i = 0; i < git_diff_num_deltas(diff); i++) { + delta = git_diff_get_delta(diff, i); + cl_assert_equal_i(expected[i], git_diff_status_char(delta->status)); + } + + git_diff_free(diff); + git_commit_free(commit); +} diff --git a/tests/delta/apply.c b/tests/delta/apply.c new file mode 100644 index 000000000..5bb95a283 --- /dev/null +++ b/tests/delta/apply.c @@ -0,0 +1,21 @@ +#include "clar_libgit2.h" + +#include "delta.h" + +void test_delta_apply__read_at_off(void) +{ + unsigned char base[16] = { 0 }, delta[] = { 0x10, 0x10, 0xff, 0xff, 0xff, 0xff, 0xff, 0x10, 0x00, 0x00 }; + void *out; + size_t outlen; + + cl_git_fail(git_delta_apply(&out, &outlen, base, sizeof(base), delta, sizeof(delta))); +} + +void test_delta_apply__read_after_limit(void) +{ + unsigned char base[16] = { 0 }, delta[] = { 0x10, 0x70, 0xff }; + void *out; + size_t outlen; + + cl_git_fail(git_delta_apply(&out, &outlen, base, sizeof(base), delta, sizeof(delta))); +} diff --git a/tests/diff/binary.c b/tests/diff/binary.c index 173a5994e..c17ba5ef4 100644 --- a/tests/diff/binary.c +++ b/tests/diff/binary.c @@ -3,6 +3,7 @@ #include "git2/sys/diff.h" #include "buffer.h" +#include "delta.h" #include "filebuf.h" #include "repository.h" diff --git a/tests/diff/stats.c b/tests/diff/stats.c index 3171a4486..347d0d757 100644 --- a/tests/diff/stats.c +++ b/tests/diff/stats.c @@ -254,7 +254,7 @@ void test_diff_stats__rename_nochanges_no_find(void) git_buf_free(&buf); } -void test_diff_stats__rename_and_modifiy_no_find(void) +void test_diff_stats__rename_and_modify_no_find(void) { git_buf buf = GIT_BUF_INIT; const char *stat = diff --git a/tests/fetchhead/nonetwork.c b/tests/fetchhead/nonetwork.c index 4dabb577e..a6394600a 100644 --- a/tests/fetchhead/nonetwork.c +++ b/tests/fetchhead/nonetwork.c @@ -343,6 +343,29 @@ void test_fetchhead_nonetwork__unborn_with_upstream(void) cl_fixture_cleanup("./repowithunborn"); } +void test_fetchhead_nonetwork__fetch_into_repo_with_symrefs(void) +{ + git_repository *repo; + git_remote *remote; + git_reference *symref; + + repo = cl_git_sandbox_init("empty_standard_repo"); + + /* + * Testing for a specific constellation where the repository has at + * least one symbolic reference in its refdb. + */ + cl_git_pass(git_reference_symbolic_create(&symref, repo, "refs/heads/symref", "refs/heads/master", 0, NULL)); + + cl_git_pass(git_remote_set_url(repo, "origin", cl_fixture("testrepo.git"))); + cl_git_pass(git_remote_lookup(&remote, repo, "origin")); + cl_git_pass(git_remote_fetch(remote, NULL, NULL, NULL)); + + git_remote_free(remote); + git_reference_free(symref); + cl_git_sandbox_cleanup(); +} + void test_fetchhead_nonetwork__quote_in_branch_name(void) { cl_set_cleanup(&cleanup_repository, "./test1"); diff --git a/tests/path/core.c b/tests/path/core.c index 3dccfe5fb..0ab41ea50 100644 --- a/tests/path/core.c +++ b/tests/path/core.c @@ -54,256 +54,256 @@ void test_path_core__make_relative(void) void test_path_core__isvalid_standard(void) { - cl_assert_equal_b(true, git_path_isvalid(NULL, "foo/bar", 0)); - cl_assert_equal_b(true, git_path_isvalid(NULL, "foo/bar/file.txt", 0)); - cl_assert_equal_b(true, git_path_isvalid(NULL, "foo/bar/.file", 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "foo/bar", 0, 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "foo/bar/file.txt", 0, 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "foo/bar/.file", 0, 0)); } void test_path_core__isvalid_empty_dir_component(void) { - cl_assert_equal_b(false, git_path_isvalid(NULL, "foo//bar", 0)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "foo//bar", 0, 0)); /* leading slash */ - cl_assert_equal_b(false, git_path_isvalid(NULL, "/", 0)); - cl_assert_equal_b(false, git_path_isvalid(NULL, "/foo", 0)); - cl_assert_equal_b(false, git_path_isvalid(NULL, "/foo/bar", 0)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "/", 0, 0)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "/foo", 0, 0)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "/foo/bar", 0, 0)); /* trailing slash */ - cl_assert_equal_b(false, git_path_isvalid(NULL, "foo/", 0)); - cl_assert_equal_b(false, git_path_isvalid(NULL, "foo/bar/", 0)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "foo/", 0, 0)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "foo/bar/", 0, 0)); } void test_path_core__isvalid_dot_and_dotdot(void) { - cl_assert_equal_b(true, git_path_isvalid(NULL, ".", 0)); - cl_assert_equal_b(true, git_path_isvalid(NULL, "./foo", 0)); - cl_assert_equal_b(true, git_path_isvalid(NULL, "foo/.", 0)); - cl_assert_equal_b(true, git_path_isvalid(NULL, "./foo", 0)); - - cl_assert_equal_b(true, git_path_isvalid(NULL, "..", 0)); - cl_assert_equal_b(true, git_path_isvalid(NULL, "../foo", 0)); - cl_assert_equal_b(true, git_path_isvalid(NULL, "foo/..", 0)); - cl_assert_equal_b(true, git_path_isvalid(NULL, "../foo", 0)); - - cl_assert_equal_b(false, git_path_isvalid(NULL, ".", GIT_PATH_REJECT_TRAVERSAL)); - cl_assert_equal_b(false, git_path_isvalid(NULL, "./foo", GIT_PATH_REJECT_TRAVERSAL)); - cl_assert_equal_b(false, git_path_isvalid(NULL, "foo/.", GIT_PATH_REJECT_TRAVERSAL)); - cl_assert_equal_b(false, git_path_isvalid(NULL, "./foo", GIT_PATH_REJECT_TRAVERSAL)); - - cl_assert_equal_b(false, git_path_isvalid(NULL, "..", GIT_PATH_REJECT_TRAVERSAL)); - cl_assert_equal_b(false, git_path_isvalid(NULL, "../foo", GIT_PATH_REJECT_TRAVERSAL)); - cl_assert_equal_b(false, git_path_isvalid(NULL, "foo/..", GIT_PATH_REJECT_TRAVERSAL)); - cl_assert_equal_b(false, git_path_isvalid(NULL, "../foo", GIT_PATH_REJECT_TRAVERSAL)); + cl_assert_equal_b(true, git_path_isvalid(NULL, ".", 0, 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "./foo", 0, 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "foo/.", 0, 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "./foo", 0, 0)); + + cl_assert_equal_b(true, git_path_isvalid(NULL, "..", 0, 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "../foo", 0, 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "foo/..", 0, 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "../foo", 0, 0)); + + cl_assert_equal_b(false, git_path_isvalid(NULL, ".", 0, GIT_PATH_REJECT_TRAVERSAL)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "./foo", 0, GIT_PATH_REJECT_TRAVERSAL)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "foo/.", 0, GIT_PATH_REJECT_TRAVERSAL)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "./foo", 0, GIT_PATH_REJECT_TRAVERSAL)); + + cl_assert_equal_b(false, git_path_isvalid(NULL, "..", 0, GIT_PATH_REJECT_TRAVERSAL)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "../foo", 0, GIT_PATH_REJECT_TRAVERSAL)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "foo/..", 0, GIT_PATH_REJECT_TRAVERSAL)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "../foo", 0, GIT_PATH_REJECT_TRAVERSAL)); } void test_path_core__isvalid_dot_git(void) { - cl_assert_equal_b(true, git_path_isvalid(NULL, ".git", 0)); - cl_assert_equal_b(true, git_path_isvalid(NULL, ".git/foo", 0)); - cl_assert_equal_b(true, git_path_isvalid(NULL, "foo/.git", 0)); - cl_assert_equal_b(true, git_path_isvalid(NULL, "foo/.git/bar", 0)); - cl_assert_equal_b(true, git_path_isvalid(NULL, "foo/.GIT/bar", 0)); - cl_assert_equal_b(true, git_path_isvalid(NULL, "foo/bar/.Git", 0)); - - cl_assert_equal_b(false, git_path_isvalid(NULL, ".git", GIT_PATH_REJECT_DOT_GIT_LITERAL)); - cl_assert_equal_b(false, git_path_isvalid(NULL, ".git/foo", GIT_PATH_REJECT_DOT_GIT_LITERAL)); - cl_assert_equal_b(false, git_path_isvalid(NULL, "foo/.git", GIT_PATH_REJECT_DOT_GIT_LITERAL)); - cl_assert_equal_b(false, git_path_isvalid(NULL, "foo/.git/bar", GIT_PATH_REJECT_DOT_GIT_LITERAL)); - cl_assert_equal_b(false, git_path_isvalid(NULL, "foo/.GIT/bar", GIT_PATH_REJECT_DOT_GIT_LITERAL)); - cl_assert_equal_b(false, git_path_isvalid(NULL, "foo/bar/.Git", GIT_PATH_REJECT_DOT_GIT_LITERAL)); - - cl_assert_equal_b(true, git_path_isvalid(NULL, "!git", 0)); - cl_assert_equal_b(true, git_path_isvalid(NULL, "foo/!git", 0)); - cl_assert_equal_b(true, git_path_isvalid(NULL, "!git/bar", 0)); - cl_assert_equal_b(true, git_path_isvalid(NULL, ".tig", 0)); - cl_assert_equal_b(true, git_path_isvalid(NULL, "foo/.tig", 0)); - cl_assert_equal_b(true, git_path_isvalid(NULL, ".tig/bar", 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, ".git", 0, 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, ".git/foo", 0, 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "foo/.git", 0, 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "foo/.git/bar", 0, 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "foo/.GIT/bar", 0, 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "foo/bar/.Git", 0, 0)); + + cl_assert_equal_b(false, git_path_isvalid(NULL, ".git", 0, GIT_PATH_REJECT_DOT_GIT_LITERAL)); + cl_assert_equal_b(false, git_path_isvalid(NULL, ".git/foo", 0, GIT_PATH_REJECT_DOT_GIT_LITERAL)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "foo/.git", 0, GIT_PATH_REJECT_DOT_GIT_LITERAL)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "foo/.git/bar", 0, GIT_PATH_REJECT_DOT_GIT_LITERAL)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "foo/.GIT/bar", 0, GIT_PATH_REJECT_DOT_GIT_LITERAL)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "foo/bar/.Git", 0, GIT_PATH_REJECT_DOT_GIT_LITERAL)); + + cl_assert_equal_b(true, git_path_isvalid(NULL, "!git", 0, 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "foo/!git", 0, 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "!git/bar", 0, 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, ".tig", 0, 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "foo/.tig", 0, 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, ".tig/bar", 0, 0)); } void test_path_core__isvalid_backslash(void) { - cl_assert_equal_b(true, git_path_isvalid(NULL, "foo\\file.txt", 0)); - cl_assert_equal_b(true, git_path_isvalid(NULL, "foo/bar\\file.txt", 0)); - cl_assert_equal_b(true, git_path_isvalid(NULL, "foo/bar\\", 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "foo\\file.txt", 0, 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "foo/bar\\file.txt", 0, 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "foo/bar\\", 0, 0)); - cl_assert_equal_b(false, git_path_isvalid(NULL, "foo\\file.txt", GIT_PATH_REJECT_BACKSLASH)); - cl_assert_equal_b(false, git_path_isvalid(NULL, "foo/bar\\file.txt", GIT_PATH_REJECT_BACKSLASH)); - cl_assert_equal_b(false, git_path_isvalid(NULL, "foo/bar\\", GIT_PATH_REJECT_BACKSLASH)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "foo\\file.txt", 0, GIT_PATH_REJECT_BACKSLASH)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "foo/bar\\file.txt", 0, GIT_PATH_REJECT_BACKSLASH)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "foo/bar\\", 0, GIT_PATH_REJECT_BACKSLASH)); } void test_path_core__isvalid_trailing_dot(void) { - cl_assert_equal_b(true, git_path_isvalid(NULL, "foo.", 0)); - cl_assert_equal_b(true, git_path_isvalid(NULL, "foo...", 0)); - cl_assert_equal_b(true, git_path_isvalid(NULL, "foo/bar.", 0)); - cl_assert_equal_b(true, git_path_isvalid(NULL, "foo./bar", 0)); - - cl_assert_equal_b(false, git_path_isvalid(NULL, "foo.", GIT_PATH_REJECT_TRAILING_DOT)); - cl_assert_equal_b(false, git_path_isvalid(NULL, "foo...", GIT_PATH_REJECT_TRAILING_DOT)); - cl_assert_equal_b(false, git_path_isvalid(NULL, "foo/bar.", GIT_PATH_REJECT_TRAILING_DOT)); - cl_assert_equal_b(false, git_path_isvalid(NULL, "foo./bar", GIT_PATH_REJECT_TRAILING_DOT)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "foo.", 0, 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "foo...", 0, 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "foo/bar.", 0, 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "foo./bar", 0, 0)); + + cl_assert_equal_b(false, git_path_isvalid(NULL, "foo.", 0, GIT_PATH_REJECT_TRAILING_DOT)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "foo...", 0, GIT_PATH_REJECT_TRAILING_DOT)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "foo/bar.", 0, GIT_PATH_REJECT_TRAILING_DOT)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "foo./bar", 0, GIT_PATH_REJECT_TRAILING_DOT)); } void test_path_core__isvalid_trailing_space(void) { - cl_assert_equal_b(true, git_path_isvalid(NULL, "foo ", 0)); - cl_assert_equal_b(true, git_path_isvalid(NULL, "foo ", 0)); - cl_assert_equal_b(true, git_path_isvalid(NULL, "foo/bar ", 0)); - cl_assert_equal_b(true, git_path_isvalid(NULL, " ", 0)); - cl_assert_equal_b(true, git_path_isvalid(NULL, "foo /bar", 0)); - - cl_assert_equal_b(false, git_path_isvalid(NULL, "foo ", GIT_PATH_REJECT_TRAILING_SPACE)); - cl_assert_equal_b(false, git_path_isvalid(NULL, "foo ", GIT_PATH_REJECT_TRAILING_SPACE)); - cl_assert_equal_b(false, git_path_isvalid(NULL, "foo/bar ", GIT_PATH_REJECT_TRAILING_SPACE)); - cl_assert_equal_b(false, git_path_isvalid(NULL, " ", GIT_PATH_REJECT_TRAILING_SPACE)); - cl_assert_equal_b(false, git_path_isvalid(NULL, "foo /bar", GIT_PATH_REJECT_TRAILING_SPACE)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "foo ", 0, 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "foo ", 0, 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "foo/bar ", 0, 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, " ", 0, 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "foo /bar", 0, 0)); + + cl_assert_equal_b(false, git_path_isvalid(NULL, "foo ", 0, GIT_PATH_REJECT_TRAILING_SPACE)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "foo ", 0, GIT_PATH_REJECT_TRAILING_SPACE)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "foo/bar ", 0, GIT_PATH_REJECT_TRAILING_SPACE)); + cl_assert_equal_b(false, git_path_isvalid(NULL, " ", 0, GIT_PATH_REJECT_TRAILING_SPACE)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "foo /bar", 0, GIT_PATH_REJECT_TRAILING_SPACE)); } void test_path_core__isvalid_trailing_colon(void) { - cl_assert_equal_b(true, git_path_isvalid(NULL, "foo:", 0)); - cl_assert_equal_b(true, git_path_isvalid(NULL, "foo/bar:", 0)); - cl_assert_equal_b(true, git_path_isvalid(NULL, ":", 0)); - cl_assert_equal_b(true, git_path_isvalid(NULL, "foo:/bar", 0)); - - cl_assert_equal_b(false, git_path_isvalid(NULL, "foo:", GIT_PATH_REJECT_TRAILING_COLON)); - cl_assert_equal_b(false, git_path_isvalid(NULL, "foo/bar:", GIT_PATH_REJECT_TRAILING_COLON)); - cl_assert_equal_b(false, git_path_isvalid(NULL, ":", GIT_PATH_REJECT_TRAILING_COLON)); - cl_assert_equal_b(false, git_path_isvalid(NULL, "foo:/bar", GIT_PATH_REJECT_TRAILING_COLON)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "foo:", 0, 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "foo/bar:", 0, 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, ":", 0, 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "foo:/bar", 0, 0)); + + cl_assert_equal_b(false, git_path_isvalid(NULL, "foo:", 0, GIT_PATH_REJECT_TRAILING_COLON)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "foo/bar:", 0, GIT_PATH_REJECT_TRAILING_COLON)); + cl_assert_equal_b(false, git_path_isvalid(NULL, ":", 0, GIT_PATH_REJECT_TRAILING_COLON)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "foo:/bar", 0, GIT_PATH_REJECT_TRAILING_COLON)); } void test_path_core__isvalid_dotgit_ntfs(void) { - cl_assert_equal_b(true, git_path_isvalid(NULL, ".git", 0)); - cl_assert_equal_b(true, git_path_isvalid(NULL, ".git ", 0)); - cl_assert_equal_b(true, git_path_isvalid(NULL, ".git.", 0)); - cl_assert_equal_b(true, git_path_isvalid(NULL, ".git.. .", 0)); - - cl_assert_equal_b(true, git_path_isvalid(NULL, "git~1", 0)); - cl_assert_equal_b(true, git_path_isvalid(NULL, "git~1 ", 0)); - cl_assert_equal_b(true, git_path_isvalid(NULL, "git~1.", 0)); - cl_assert_equal_b(true, git_path_isvalid(NULL, "git~1.. .", 0)); - - cl_assert_equal_b(false, git_path_isvalid(NULL, ".git", GIT_PATH_REJECT_DOT_GIT_NTFS)); - cl_assert_equal_b(false, git_path_isvalid(NULL, ".git ", GIT_PATH_REJECT_DOT_GIT_NTFS)); - cl_assert_equal_b(false, git_path_isvalid(NULL, ".git.", GIT_PATH_REJECT_DOT_GIT_NTFS)); - cl_assert_equal_b(false, git_path_isvalid(NULL, ".git.. .", GIT_PATH_REJECT_DOT_GIT_NTFS)); - - cl_assert_equal_b(false, git_path_isvalid(NULL, "git~1", GIT_PATH_REJECT_DOT_GIT_NTFS)); - cl_assert_equal_b(false, git_path_isvalid(NULL, "git~1 ", GIT_PATH_REJECT_DOT_GIT_NTFS)); - cl_assert_equal_b(false, git_path_isvalid(NULL, "git~1.", GIT_PATH_REJECT_DOT_GIT_NTFS)); - cl_assert_equal_b(false, git_path_isvalid(NULL, "git~1.. .", GIT_PATH_REJECT_DOT_GIT_NTFS)); + cl_assert_equal_b(true, git_path_isvalid(NULL, ".git", 0, 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, ".git ", 0, 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, ".git.", 0, 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, ".git.. .", 0, 0)); + + cl_assert_equal_b(true, git_path_isvalid(NULL, "git~1", 0, 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "git~1 ", 0, 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "git~1.", 0, 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "git~1.. .", 0, 0)); + + cl_assert_equal_b(false, git_path_isvalid(NULL, ".git", 0, GIT_PATH_REJECT_DOT_GIT_NTFS)); + cl_assert_equal_b(false, git_path_isvalid(NULL, ".git ", 0, GIT_PATH_REJECT_DOT_GIT_NTFS)); + cl_assert_equal_b(false, git_path_isvalid(NULL, ".git.", 0, GIT_PATH_REJECT_DOT_GIT_NTFS)); + cl_assert_equal_b(false, git_path_isvalid(NULL, ".git.. .", 0, GIT_PATH_REJECT_DOT_GIT_NTFS)); + + cl_assert_equal_b(false, git_path_isvalid(NULL, "git~1", 0, GIT_PATH_REJECT_DOT_GIT_NTFS)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "git~1 ", 0, GIT_PATH_REJECT_DOT_GIT_NTFS)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "git~1.", 0, GIT_PATH_REJECT_DOT_GIT_NTFS)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "git~1.. .", 0, GIT_PATH_REJECT_DOT_GIT_NTFS)); } void test_path_core__isvalid_dos_paths(void) { - cl_assert_equal_b(true, git_path_isvalid(NULL, "aux", 0)); - cl_assert_equal_b(true, git_path_isvalid(NULL, "aux.", 0)); - cl_assert_equal_b(true, git_path_isvalid(NULL, "aux:", 0)); - cl_assert_equal_b(true, git_path_isvalid(NULL, "aux.asdf", 0)); - cl_assert_equal_b(true, git_path_isvalid(NULL, "aux.asdf\\zippy", 0)); - cl_assert_equal_b(true, git_path_isvalid(NULL, "aux:asdf\\foobar", 0)); - cl_assert_equal_b(true, git_path_isvalid(NULL, "con", 0)); - cl_assert_equal_b(true, git_path_isvalid(NULL, "prn", 0)); - cl_assert_equal_b(true, git_path_isvalid(NULL, "nul", 0)); - - cl_assert_equal_b(false, git_path_isvalid(NULL, "aux", GIT_PATH_REJECT_DOS_PATHS)); - cl_assert_equal_b(false, git_path_isvalid(NULL, "aux.", GIT_PATH_REJECT_DOS_PATHS)); - cl_assert_equal_b(false, git_path_isvalid(NULL, "aux:", GIT_PATH_REJECT_DOS_PATHS)); - cl_assert_equal_b(false, git_path_isvalid(NULL, "aux.asdf", GIT_PATH_REJECT_DOS_PATHS)); - cl_assert_equal_b(false, git_path_isvalid(NULL, "aux.asdf\\zippy", GIT_PATH_REJECT_DOS_PATHS)); - cl_assert_equal_b(false, git_path_isvalid(NULL, "aux:asdf\\foobar", GIT_PATH_REJECT_DOS_PATHS)); - cl_assert_equal_b(false, git_path_isvalid(NULL, "con", GIT_PATH_REJECT_DOS_PATHS)); - cl_assert_equal_b(false, git_path_isvalid(NULL, "prn", GIT_PATH_REJECT_DOS_PATHS)); - cl_assert_equal_b(false, git_path_isvalid(NULL, "nul", GIT_PATH_REJECT_DOS_PATHS)); - - cl_assert_equal_b(true, git_path_isvalid(NULL, "aux1", 0)); - cl_assert_equal_b(true, git_path_isvalid(NULL, "aux1", GIT_PATH_REJECT_DOS_PATHS)); - cl_assert_equal_b(true, git_path_isvalid(NULL, "auxn", GIT_PATH_REJECT_DOS_PATHS)); - cl_assert_equal_b(true, git_path_isvalid(NULL, "aux\\foo", GIT_PATH_REJECT_DOS_PATHS)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "aux", 0, 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "aux.", 0, 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "aux:", 0, 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "aux.asdf", 0, 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "aux.asdf\\zippy", 0, 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "aux:asdf\\foobar", 0, 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "con", 0, 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "prn", 0, 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "nul", 0, 0)); + + cl_assert_equal_b(false, git_path_isvalid(NULL, "aux", 0, GIT_PATH_REJECT_DOS_PATHS)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "aux.", 0, GIT_PATH_REJECT_DOS_PATHS)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "aux:", 0, GIT_PATH_REJECT_DOS_PATHS)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "aux.asdf", 0, GIT_PATH_REJECT_DOS_PATHS)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "aux.asdf\\zippy", 0, GIT_PATH_REJECT_DOS_PATHS)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "aux:asdf\\foobar", 0, GIT_PATH_REJECT_DOS_PATHS)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "con", 0, GIT_PATH_REJECT_DOS_PATHS)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "prn", 0, GIT_PATH_REJECT_DOS_PATHS)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "nul", 0, GIT_PATH_REJECT_DOS_PATHS)); + + cl_assert_equal_b(true, git_path_isvalid(NULL, "aux1", 0, 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "aux1", 0, GIT_PATH_REJECT_DOS_PATHS)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "auxn", 0, GIT_PATH_REJECT_DOS_PATHS)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "aux\\foo", 0, GIT_PATH_REJECT_DOS_PATHS)); } void test_path_core__isvalid_dos_paths_withnum(void) { - cl_assert_equal_b(true, git_path_isvalid(NULL, "com1", 0)); - cl_assert_equal_b(true, git_path_isvalid(NULL, "com1.", 0)); - cl_assert_equal_b(true, git_path_isvalid(NULL, "com1:", 0)); - cl_assert_equal_b(true, git_path_isvalid(NULL, "com1.asdf", 0)); - cl_assert_equal_b(true, git_path_isvalid(NULL, "com1.asdf\\zippy", 0)); - cl_assert_equal_b(true, git_path_isvalid(NULL, "com1:asdf\\foobar", 0)); - cl_assert_equal_b(true, git_path_isvalid(NULL, "com1\\foo", 0)); - cl_assert_equal_b(true, git_path_isvalid(NULL, "lpt1", 0)); - - cl_assert_equal_b(false, git_path_isvalid(NULL, "com1", GIT_PATH_REJECT_DOS_PATHS)); - cl_assert_equal_b(false, git_path_isvalid(NULL, "com1.", GIT_PATH_REJECT_DOS_PATHS)); - cl_assert_equal_b(false, git_path_isvalid(NULL, "com1:", GIT_PATH_REJECT_DOS_PATHS)); - cl_assert_equal_b(false, git_path_isvalid(NULL, "com1.asdf", GIT_PATH_REJECT_DOS_PATHS)); - cl_assert_equal_b(false, git_path_isvalid(NULL, "com1.asdf\\zippy", GIT_PATH_REJECT_DOS_PATHS)); - cl_assert_equal_b(false, git_path_isvalid(NULL, "com1:asdf\\foobar", GIT_PATH_REJECT_DOS_PATHS)); - cl_assert_equal_b(false, git_path_isvalid(NULL, "com1/foo", GIT_PATH_REJECT_DOS_PATHS)); - cl_assert_equal_b(false, git_path_isvalid(NULL, "lpt1", GIT_PATH_REJECT_DOS_PATHS)); - - cl_assert_equal_b(true, git_path_isvalid(NULL, "com0", 0)); - cl_assert_equal_b(true, git_path_isvalid(NULL, "com0", GIT_PATH_REJECT_DOS_PATHS)); - cl_assert_equal_b(true, git_path_isvalid(NULL, "com10", 0)); - cl_assert_equal_b(true, git_path_isvalid(NULL, "com10", GIT_PATH_REJECT_DOS_PATHS)); - cl_assert_equal_b(true, git_path_isvalid(NULL, "comn", GIT_PATH_REJECT_DOS_PATHS)); - cl_assert_equal_b(true, git_path_isvalid(NULL, "com1\\foo", GIT_PATH_REJECT_DOS_PATHS)); - cl_assert_equal_b(true, git_path_isvalid(NULL, "lpt0", GIT_PATH_REJECT_DOS_PATHS)); - cl_assert_equal_b(true, git_path_isvalid(NULL, "lpt10", GIT_PATH_REJECT_DOS_PATHS)); - cl_assert_equal_b(true, git_path_isvalid(NULL, "lptn", GIT_PATH_REJECT_DOS_PATHS)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "com1", 0, 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "com1.", 0, 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "com1:", 0, 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "com1.asdf", 0, 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "com1.asdf\\zippy", 0, 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "com1:asdf\\foobar", 0, 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "com1\\foo", 0, 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "lpt1", 0, 0)); + + cl_assert_equal_b(false, git_path_isvalid(NULL, "com1", 0, GIT_PATH_REJECT_DOS_PATHS)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "com1.", 0, GIT_PATH_REJECT_DOS_PATHS)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "com1:", 0, GIT_PATH_REJECT_DOS_PATHS)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "com1.asdf", 0, GIT_PATH_REJECT_DOS_PATHS)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "com1.asdf\\zippy", 0, GIT_PATH_REJECT_DOS_PATHS)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "com1:asdf\\foobar", 0, GIT_PATH_REJECT_DOS_PATHS)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "com1/foo", 0, GIT_PATH_REJECT_DOS_PATHS)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "lpt1", 0, GIT_PATH_REJECT_DOS_PATHS)); + + cl_assert_equal_b(true, git_path_isvalid(NULL, "com0", 0, 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "com0", 0, GIT_PATH_REJECT_DOS_PATHS)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "com10", 0, 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "com10", 0, GIT_PATH_REJECT_DOS_PATHS)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "comn", 0, GIT_PATH_REJECT_DOS_PATHS)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "com1\\foo", 0, GIT_PATH_REJECT_DOS_PATHS)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "lpt0", 0, GIT_PATH_REJECT_DOS_PATHS)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "lpt10", 0, GIT_PATH_REJECT_DOS_PATHS)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "lptn", 0, GIT_PATH_REJECT_DOS_PATHS)); } void test_path_core__isvalid_nt_chars(void) { - cl_assert_equal_b(true, git_path_isvalid(NULL, "asdf\001foo", 0)); - cl_assert_equal_b(true, git_path_isvalid(NULL, "asdf\037bar", 0)); - cl_assert_equal_b(true, git_path_isvalid(NULL, "asdffoo", 0)); - cl_assert_equal_b(true, git_path_isvalid(NULL, "asdf:foo", 0)); - cl_assert_equal_b(true, git_path_isvalid(NULL, "asdf\"bar", 0)); - cl_assert_equal_b(true, git_path_isvalid(NULL, "asdf|foo", 0)); - cl_assert_equal_b(true, git_path_isvalid(NULL, "asdf?bar", 0)); - cl_assert_equal_b(true, git_path_isvalid(NULL, "asdf*bar", 0)); - - cl_assert_equal_b(false, git_path_isvalid(NULL, "asdf\001foo", GIT_PATH_REJECT_NT_CHARS)); - cl_assert_equal_b(false, git_path_isvalid(NULL, "asdf\037bar", GIT_PATH_REJECT_NT_CHARS)); - cl_assert_equal_b(false, git_path_isvalid(NULL, "asdffoo", GIT_PATH_REJECT_NT_CHARS)); - cl_assert_equal_b(false, git_path_isvalid(NULL, "asdf:foo", GIT_PATH_REJECT_NT_CHARS)); - cl_assert_equal_b(false, git_path_isvalid(NULL, "asdf\"bar", GIT_PATH_REJECT_NT_CHARS)); - cl_assert_equal_b(false, git_path_isvalid(NULL, "asdf|foo", GIT_PATH_REJECT_NT_CHARS)); - cl_assert_equal_b(false, git_path_isvalid(NULL, "asdf?bar", GIT_PATH_REJECT_NT_CHARS)); - cl_assert_equal_b(false, git_path_isvalid(NULL, "asdf*bar", GIT_PATH_REJECT_NT_CHARS)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "asdf\001foo", 0, 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "asdf\037bar", 0, 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "asdffoo", 0, 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "asdf:foo", 0, 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "asdf\"bar", 0, 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "asdf|foo", 0, 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "asdf?bar", 0, 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "asdf*bar", 0, 0)); + + cl_assert_equal_b(false, git_path_isvalid(NULL, "asdf\001foo", 0, GIT_PATH_REJECT_NT_CHARS)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "asdf\037bar", 0, GIT_PATH_REJECT_NT_CHARS)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "asdffoo", 0, GIT_PATH_REJECT_NT_CHARS)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "asdf:foo", 0, GIT_PATH_REJECT_NT_CHARS)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "asdf\"bar", 0, GIT_PATH_REJECT_NT_CHARS)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "asdf|foo", 0, GIT_PATH_REJECT_NT_CHARS)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "asdf?bar", 0, GIT_PATH_REJECT_NT_CHARS)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "asdf*bar", 0, GIT_PATH_REJECT_NT_CHARS)); } void test_path_core__isvalid_dotgit_with_hfs_ignorables(void) { - cl_assert_equal_b(false, git_path_isvalid(NULL, ".git", GIT_PATH_REJECT_DOT_GIT_HFS)); - cl_assert_equal_b(false, git_path_isvalid(NULL, ".git\xe2\x80\x8c", GIT_PATH_REJECT_DOT_GIT_HFS)); - cl_assert_equal_b(false, git_path_isvalid(NULL, ".gi\xe2\x80\x8dT", GIT_PATH_REJECT_DOT_GIT_HFS)); - cl_assert_equal_b(false, git_path_isvalid(NULL, ".g\xe2\x80\x8eIt", GIT_PATH_REJECT_DOT_GIT_HFS)); - cl_assert_equal_b(false, git_path_isvalid(NULL, ".\xe2\x80\x8fgIt", GIT_PATH_REJECT_DOT_GIT_HFS)); - cl_assert_equal_b(false, git_path_isvalid(NULL, "\xe2\x80\xaa.gIt", GIT_PATH_REJECT_DOT_GIT_HFS)); - - cl_assert_equal_b(false, git_path_isvalid(NULL, "\xe2\x80\xab.\xe2\x80\xacG\xe2\x80\xadI\xe2\x80\xaet", GIT_PATH_REJECT_DOT_GIT_HFS)); - cl_assert_equal_b(false, git_path_isvalid(NULL, "\xe2\x81\xab.\xe2\x80\xaaG\xe2\x81\xabI\xe2\x80\xact", GIT_PATH_REJECT_DOT_GIT_HFS)); - cl_assert_equal_b(false, git_path_isvalid(NULL, "\xe2\x81\xad.\xe2\x80\xaeG\xef\xbb\xbfIT", GIT_PATH_REJECT_DOT_GIT_HFS)); - - cl_assert_equal_b(true, git_path_isvalid(NULL, ".", GIT_PATH_REJECT_DOT_GIT_HFS)); - cl_assert_equal_b(true, git_path_isvalid(NULL, ".g", GIT_PATH_REJECT_DOT_GIT_HFS)); - cl_assert_equal_b(true, git_path_isvalid(NULL, ".gi", GIT_PATH_REJECT_DOT_GIT_HFS)); - cl_assert_equal_b(true, git_path_isvalid(NULL, " .git", GIT_PATH_REJECT_DOT_GIT_HFS)); - cl_assert_equal_b(true, git_path_isvalid(NULL, "..git\xe2\x80\x8c", GIT_PATH_REJECT_DOT_GIT_HFS)); - cl_assert_equal_b(true, git_path_isvalid(NULL, ".gi\xe2\x80\x8dT.", GIT_PATH_REJECT_DOT_GIT_HFS)); - cl_assert_equal_b(true, git_path_isvalid(NULL, ".g\xe2\x80It", GIT_PATH_REJECT_DOT_GIT_HFS)); - cl_assert_equal_b(true, git_path_isvalid(NULL, ".\xe2gIt", GIT_PATH_REJECT_DOT_GIT_HFS)); - cl_assert_equal_b(true, git_path_isvalid(NULL, "\xe2\x80\xaa.gi", GIT_PATH_REJECT_DOT_GIT_HFS)); - cl_assert_equal_b(true, git_path_isvalid(NULL, ".gi\x80\x8dT", GIT_PATH_REJECT_DOT_GIT_HFS)); - cl_assert_equal_b(true, git_path_isvalid(NULL, ".gi\x8dT", GIT_PATH_REJECT_DOT_GIT_HFS)); - cl_assert_equal_b(true, git_path_isvalid(NULL, ".g\xe2i\x80T\x8e", GIT_PATH_REJECT_DOT_GIT_HFS)); - cl_assert_equal_b(true, git_path_isvalid(NULL, ".git\xe2\x80\xbf", GIT_PATH_REJECT_DOT_GIT_HFS)); - cl_assert_equal_b(true, git_path_isvalid(NULL, ".git\xe2\xab\x81", GIT_PATH_REJECT_DOT_GIT_HFS)); + cl_assert_equal_b(false, git_path_isvalid(NULL, ".git", 0, GIT_PATH_REJECT_DOT_GIT_HFS)); + cl_assert_equal_b(false, git_path_isvalid(NULL, ".git\xe2\x80\x8c", 0, GIT_PATH_REJECT_DOT_GIT_HFS)); + cl_assert_equal_b(false, git_path_isvalid(NULL, ".gi\xe2\x80\x8dT", 0, GIT_PATH_REJECT_DOT_GIT_HFS)); + cl_assert_equal_b(false, git_path_isvalid(NULL, ".g\xe2\x80\x8eIt", 0, GIT_PATH_REJECT_DOT_GIT_HFS)); + cl_assert_equal_b(false, git_path_isvalid(NULL, ".\xe2\x80\x8fgIt", 0, GIT_PATH_REJECT_DOT_GIT_HFS)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "\xe2\x80\xaa.gIt", 0, GIT_PATH_REJECT_DOT_GIT_HFS)); + + cl_assert_equal_b(false, git_path_isvalid(NULL, "\xe2\x80\xab.\xe2\x80\xacG\xe2\x80\xadI\xe2\x80\xaet", 0, GIT_PATH_REJECT_DOT_GIT_HFS)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "\xe2\x81\xab.\xe2\x80\xaaG\xe2\x81\xabI\xe2\x80\xact", 0, GIT_PATH_REJECT_DOT_GIT_HFS)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "\xe2\x81\xad.\xe2\x80\xaeG\xef\xbb\xbfIT", 0, GIT_PATH_REJECT_DOT_GIT_HFS)); + + cl_assert_equal_b(true, git_path_isvalid(NULL, ".", 0, GIT_PATH_REJECT_DOT_GIT_HFS)); + cl_assert_equal_b(true, git_path_isvalid(NULL, ".g", 0, GIT_PATH_REJECT_DOT_GIT_HFS)); + cl_assert_equal_b(true, git_path_isvalid(NULL, ".gi", 0, GIT_PATH_REJECT_DOT_GIT_HFS)); + cl_assert_equal_b(true, git_path_isvalid(NULL, " .git", 0, GIT_PATH_REJECT_DOT_GIT_HFS)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "..git\xe2\x80\x8c", 0, GIT_PATH_REJECT_DOT_GIT_HFS)); + cl_assert_equal_b(true, git_path_isvalid(NULL, ".gi\xe2\x80\x8dT.", 0, GIT_PATH_REJECT_DOT_GIT_HFS)); + cl_assert_equal_b(true, git_path_isvalid(NULL, ".g\xe2\x80It", 0, GIT_PATH_REJECT_DOT_GIT_HFS)); + cl_assert_equal_b(true, git_path_isvalid(NULL, ".\xe2gIt", 0, GIT_PATH_REJECT_DOT_GIT_HFS)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "\xe2\x80\xaa.gi", 0, GIT_PATH_REJECT_DOT_GIT_HFS)); + cl_assert_equal_b(true, git_path_isvalid(NULL, ".gi\x80\x8dT", 0, GIT_PATH_REJECT_DOT_GIT_HFS)); + cl_assert_equal_b(true, git_path_isvalid(NULL, ".gi\x8dT", 0, GIT_PATH_REJECT_DOT_GIT_HFS)); + cl_assert_equal_b(true, git_path_isvalid(NULL, ".g\xe2i\x80T\x8e", 0, GIT_PATH_REJECT_DOT_GIT_HFS)); + cl_assert_equal_b(true, git_path_isvalid(NULL, ".git\xe2\x80\xbf", 0, GIT_PATH_REJECT_DOT_GIT_HFS)); + cl_assert_equal_b(true, git_path_isvalid(NULL, ".git\xe2\xab\x81", 0, GIT_PATH_REJECT_DOT_GIT_HFS)); } static void test_join_unrooted( diff --git a/tests/path/dotgit.c b/tests/path/dotgit.c new file mode 100644 index 000000000..20e585edb --- /dev/null +++ b/tests/path/dotgit.c @@ -0,0 +1,119 @@ +#include "clar_libgit2.h" +#include "path.h" + +static char *gitmodules_altnames[] = { + ".gitmodules", + + /* + * Equivalent to the ".git\u200cmodules" string from git but hard-coded + * as a UTF-8 sequence + */ + ".git\xe2\x80\x8cmodules", + + ".Gitmodules", + ".gitmoduleS", + + ".gitmodules ", + ".gitmodules.", + ".gitmodules ", + ".gitmodules. ", + ".gitmodules .", + ".gitmodules..", + ".gitmodules ", + ".gitmodules. ", + ".gitmodules . ", + ".gitmodules .", + + ".Gitmodules ", + ".Gitmodules.", + ".Gitmodules ", + ".Gitmodules. ", + ".Gitmodules .", + ".Gitmodules..", + ".Gitmodules ", + ".Gitmodules. ", + ".Gitmodules . ", + ".Gitmodules .", + + "GITMOD~1", + "gitmod~1", + "GITMOD~2", + "gitmod~3", + "GITMOD~4", + + "GITMOD~1 ", + "gitmod~2.", + "GITMOD~3 ", + "gitmod~4. ", + "GITMOD~1 .", + "gitmod~2 ", + "GITMOD~3. ", + "gitmod~4 . ", + + "GI7EBA~1", + "gi7eba~9", + + "GI7EB~10", + "GI7EB~11", + "GI7EB~99", + "GI7EB~10", + "GI7E~100", + "GI7E~101", + "GI7E~999", + "~1000000", + "~9999999", +}; + +static char *gitmodules_not_altnames[] = { + ".gitmodules x", + ".gitmodules .x", + + " .gitmodules", + + "..gitmodules", + + "gitmodules", + + ".gitmodule", + + ".gitmodules x ", + ".gitmodules .x", + + "GI7EBA~", + "GI7EBA~0", + "GI7EBA~~1", + "GI7EBA~X", + "Gx7EBA~1", + "GI7EBX~1", + + "GI7EB~1", + "GI7EB~01", + "GI7EB~1", +}; + +void test_path_dotgit__dotgit_modules(void) +{ + size_t i; + cl_assert_equal_i(1, git_path_is_dotgit_modules(".gitmodules", strlen(".gitmodules"))); + cl_assert_equal_i(1, git_path_is_dotgit_modules(".git\xe2\x80\x8cmodules", strlen(".git\xe2\x80\x8cmodules"))); + + for (i = 0; i < ARRAY_SIZE(gitmodules_altnames); i++) { + const char *name = gitmodules_altnames[i]; + if (!git_path_is_dotgit_modules(name, strlen(name))) + cl_fail(name); + } + + for (i = 0; i < ARRAY_SIZE(gitmodules_not_altnames); i++) { + const char *name = gitmodules_not_altnames[i]; + if (git_path_is_dotgit_modules(name, strlen(name))) + cl_fail(name); + } + +} + +void test_path_dotgit__dotgit_modules_symlink(void) +{ + cl_assert_equal_b(true, git_path_isvalid(NULL, ".gitmodules", 0, GIT_PATH_REJECT_DOT_GIT_HFS|GIT_PATH_REJECT_DOT_GIT_NTFS)); + cl_assert_equal_b(false, git_path_isvalid(NULL, ".gitmodules", S_IFLNK, GIT_PATH_REJECT_DOT_GIT_HFS)); + cl_assert_equal_b(false, git_path_isvalid(NULL, ".gitmodules", S_IFLNK, GIT_PATH_REJECT_DOT_GIT_NTFS)); +} diff --git a/tests/refs/dup.c b/tests/refs/dup.c index 0fc635a7a..8a89cd95c 100644 --- a/tests/refs/dup.c +++ b/tests/refs/dup.c @@ -21,6 +21,7 @@ void test_refs_dup__direct(void) cl_git_pass(git_reference_dup(&b, a)); cl_assert(git_reference_cmp(a, b) == 0); + cl_assert(git_reference_owner(b) == g_repo); git_reference_free(b); git_reference_free(a); @@ -34,6 +35,7 @@ void test_refs_dup__symbolic(void) cl_git_pass(git_reference_dup(&b, a)); cl_assert(git_reference_cmp(a, b) == 0); + cl_assert(git_reference_owner(b) == g_repo); git_reference_free(b); git_reference_free(a); diff --git a/tests/resources/nasty/.gitted/objects/07/f9d4d85b75187e4db5b9cbcad3e6218582bd57 b/tests/resources/nasty/.gitted/objects/07/f9d4d85b75187e4db5b9cbcad3e6218582bd57 new file mode 100644 index 0000000000000000000000000000000000000000..f040922a4b13f1d0b0c2cfbaccf5c70736e08bdb GIT binary patch literal 93 zcmV-j0HXhR0V^p=O;s>AXD~D}00ITQ^vsgn{FKt1)M5s$c{_B9?F`o$>bx_V&~j%_ zerED4Ljwad6BC7$(%jri-L%Y{R0b#EvfJ~z-nG=tE%%uC++fCX$G9l~@ERbcrtU5E literal 0 HcmV?d00001 diff --git a/tests/resources/nasty/.gitted/objects/2a/9eb82c733e31ae312cee349084dcbc6f69639a b/tests/resources/nasty/.gitted/objects/2a/9eb82c733e31ae312cee349084dcbc6f69639a new file mode 100644 index 0000000000000000000000000000000000000000..c4717d5ce6a73c51601363b27b45feebcc431793 GIT binary patch literal 26 icmb>1@i;d(+dj#?HW>;)&964`;PEq0vjg%E8f3CHA?6) zJDX%hcyG=8PrD}FHM=Z-;|6EDfPvM6uLgp9w?FHjx%bHw6VJ~%GKO8wXZwY?;&ZKR zmioRpSaBux`gW~Q@21#ePN(yBE=YLl{o~rCj^FP*SxSs&Y*D>-NbK7ARgWvOqmP(b zT0JeX5)+V4Sy)o*CtkOmUx(wjp!0)D?ghWj=U-&boE776R`S-R^8cP^8{?AZ-&km$>?$J>e|nAsg7OIDf)D=6za!ZZGz*t*h<17p(q&)~q#rE^lY& z3q=_!d|WxH=VYpL>LiIBI`0BlM5P`a`JtWpyKqNId75|r#eKJB<7~RU|?YT0W6mKfV4fZ=ve~Hx|$3OjMst1j4qIt2h!Vs z#qcX2P5{bF0@a-arm<;2xs^bgXV$ILGYe-(Ng1X5b+=u*gW*$QWTgKxk20Zi%cX6( P<{Ez1{9v(h>iw$#Mmgs^ literal 0 HcmV?d00001 diff --git a/tests/resources/revwalk.git/objects/pack/pack-9adacb9971981a1a3264fd473da5b800f2715959.pack b/tests/resources/revwalk.git/objects/pack/pack-9adacb9971981a1a3264fd473da5b800f2715959.pack new file mode 100644 index 0000000000000000000000000000000000000000..2a61f94032e627a829af0ce7ae2c34a4299ce965 GIT binary patch literal 1862 zcmZ{le>BtkAICp;vsf+HM%?YX-Q~xw`7wm)-qP`F*tBojWy&fxnY)l*{a6j7D8$z- z<;S*b5)+XUam$IBb#ZBovs_6=Zt31kt`O#4Tb*<7b-v#}-v2+&^Zj@|p8+0T{r~`g z)}F!lFt#AK+hZfh5$4{Xymwz5){jT@0&mwVv6w1<#i+S*hO4`G>{t8UvHA;sREOBB z(3^MoRt{`TR7AL#!uv5F$Y|2%_TJbc=yY{F2EB`eUbDO^QCJIDO4}k*pDbw(PE)-- z^Md&eu2B`Wr?dHp74Q}YMVp@DKAz$#K_StFu`+tM4u~Rvb$3tExgq9$COi4jbYz-Ne&m z%DF-*HM_sS`#KeKZI86fMtE8U4pGG&Za#{v92T0)c!1s-8z?ik_S-Ed^{}|o>G_+= zv8heE5AY4^B7tio88F@e-$fiC_DlC;->vGGwDpE2jhZsscvjItMIT7g8Y{@#D+UL1 zoa#A+^g5_+9rKe*$urX13I64m`95{ngdDRP`N8)+zF+p8x$v%&{B!f*!%%U4U;9OL zJJPLe=k%&zV6}aEbs%nb4)W}s_&5$kF*~U(d_q5AT6L*}6aRj3S`tT0U4rAj9 zk7d2Rw)+C`&N@JS0n|~;o&C=MiLU$@I$T`n9Fx6OL8|(*X%S>Eap-x)Y(uSt)Zdm_ ziyW_&*4DTfW$jL{W}04lw(|sMb7o1Eg>6AYz-YBJnuMr~H9A7AwJEzlhs;x4ySHJv zgZypli<1Y_S{5VVKIu+~GX6XEf9c%b>D32H??uQ(nrn-2)4!b31c-T44$WM1>di-| zq=wD!FUt6mFDUSkrtYkxbo-;7ucEBUcq)P=b;F8g>XkAmLv$$-A8P5#A_r9~Uef}D z;i3DTZ6F*OM-$*5u1^>ffy*gr8AS{Wk92cfrjoPplVH_Eze#xhTnaGmhA$H8Ye>W- zh{kSp5%tXdX9O$t>GUIK`;s;c%sL z8-wVH$Yj&Vt_iEU;A8m5g{McJlL$VZgw$EsmaqrY>cm>MUaX3He^-}1Y1&JhBJw)jN&-Po5LlyJ5!Op5T#j)Oq2+@)i0?Ts>2*^B!_{WpXVN;OLjy0rn1 z`5!1e(GM^UO2c~dOE!kfdC;gXDm4vOaKl;AVwPybYykb(1mlqR-mz{*Z_I3#Dv|KAa=)CbW+gZ3nPc+mFKhAoz_@Obe)Cso^jciEO;WszRqo?-S=ZZ5+) zcPL3JF^qROKI!yjviomeD9l~$CMe4(klAstrPk(u9AU`AtBd#z>p(Q$!y|@oG&}nh zYe45vj(NrCbMZ%+Z7GI5hl&F}r`c@z%=X*Fse=I>eB_qWnOl;>PNeQf`&;}WgcEUz znEtz#T?Aw!$G;(csW>mj`}sZgFNskn1jlK0j@u?K`vK!{g!_46{u@0VVZeeLp{)WUucUm+zh8Qn@>*@TR!X+#>Awa*zRFS`J~v_QVQB)p zF-r93bP6bjL52Orr;tm$)X{q=JNlIu;hWRX7V~{tep(yhsnUanbXzuquk=}$*|k{ z+_ZXkf;cE7duRtX_^i%-pL=Fi4D6%oJD$g5QA@msA&`A~HGYb8YzM+3szC1jB=wgX zilwjc{VR!9*l<*#V&P_}13gs$tRRg)2)n8k7TS8k*mdZIwjZC$nuYP6oA0J&treu5 zBRV3iv@|B{yRbItq(I2$A1Eu0)&uU_Ln9_Zsb8}NPh~^09Uid^!LIzYuC+$p2Q~zQ zAu(VtFc^n>xiT`+gMdVU0kIJ@AI%nk*G3Zfgg5+iaeNU9wf%_N*R7%%n2kSh;4gD( BY9;^x literal 0 HcmV?d00001 diff --git a/tests/resources/revwalk.git/packed-refs b/tests/resources/revwalk.git/packed-refs new file mode 100644 index 000000000..905a3db51 --- /dev/null +++ b/tests/resources/revwalk.git/packed-refs @@ -0,0 +1,7 @@ +# pack-refs with: peeled fully-peeled sorted +3ae0f53011bdb7e68f99bde4943449f36c1c318a refs/heads/A +061978578d7c9ff2ba92dd36d31fd8d809871030 refs/heads/B +743398b425d6c216d6cfaae3786b5bc436393ae5 refs/heads/C +790ba0facf6fd103699a5c40cd19dad277ff49cd refs/heads/D +d3d783066cf7d95def6844b9c5118c1e7bcce7df refs/heads/E +d3d783066cf7d95def6844b9c5118c1e7bcce7df refs/heads/master diff --git a/tests/resources/revwalk.git/refs/.gitkeep b/tests/resources/revwalk.git/refs/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/tests/revwalk/basic.c b/tests/revwalk/basic.c index 6a23701f3..1106bf4ce 100644 --- a/tests/revwalk/basic.c +++ b/tests/revwalk/basic.c @@ -555,3 +555,30 @@ void test_revwalk_basic__old_hidden_commit_two(void) cl_git_fail_with(GIT_ITEROVER, git_revwalk_next(&oid, _walk)); } + +/* + * Ensure that we correctly hide all parent commits of a newer + * commit when first hiding older commits. + * + * % git rev-list D ^B ^A ^E + * 790ba0facf6fd103699a5c40cd19dad277ff49cd + * b82cee5004151ae0c4f82b69fb71b87477664b6f + */ +void test_revwalk_basic__newer_hidden_commit_hides_old_commits(void) +{ + git_oid oid; + + revwalk_basic_setup_walk("revwalk.git"); + + cl_git_pass(git_revwalk_push_ref(_walk, "refs/heads/D")); + cl_git_pass(git_revwalk_hide_ref(_walk, "refs/heads/B")); + cl_git_pass(git_revwalk_hide_ref(_walk, "refs/heads/A")); + cl_git_pass(git_revwalk_hide_ref(_walk, "refs/heads/E")); + + cl_git_pass(git_revwalk_next(&oid, _walk)); + cl_assert(git_oid_streq(&oid, "b82cee5004151ae0c4f82b69fb71b87477664b6f")); + cl_git_pass(git_revwalk_next(&oid, _walk)); + cl_assert(git_oid_streq(&oid, "790ba0facf6fd103699a5c40cd19dad277ff49cd")); + + cl_git_fail_with(GIT_ITEROVER, git_revwalk_next(&oid, _walk)); +} diff --git a/tests/submodule/escape.c b/tests/submodule/escape.c new file mode 100644 index 000000000..f5c3cd4cd --- /dev/null +++ b/tests/submodule/escape.c @@ -0,0 +1,98 @@ +#include "clar_libgit2.h" +#include "posix.h" +#include "path.h" +#include "submodule_helpers.h" +#include "fileops.h" +#include "repository.h" + +static git_repository *g_repo = NULL; + +void test_submodule_escape__cleanup(void) +{ + cl_git_sandbox_cleanup(); +} + +#define EVIL_SM_NAME "../../modules/evil" +#define EVIL_SM_NAME_WINDOWS "..\\\\..\\\\modules\\\\evil" +#define EVIL_SM_NAME_WINDOWS_UNESC "..\\..\\modules\\evil" + +static int find_evil(git_submodule *sm, const char *name, void *payload) +{ + int *foundit = (int *) payload; + + GIT_UNUSED(sm); + + if (!git__strcmp(EVIL_SM_NAME, name) || + !git__strcmp(EVIL_SM_NAME_WINDOWS_UNESC, name)) + *foundit = true; + + return 0; +} + +void test_submodule_escape__from_gitdir(void) +{ + int foundit; + git_submodule *sm; + git_buf buf = GIT_BUF_INIT; + unsigned int sm_location; + + g_repo = setup_fixture_submodule_simple(); + + cl_git_pass(git_buf_joinpath(&buf, git_repository_workdir(g_repo), ".gitmodules")); + cl_git_rewritefile(buf.ptr, + "[submodule \"" EVIL_SM_NAME "\"]\n" + " path = testrepo\n" + " url = ../testrepo.git\n"); + git_buf_free(&buf); + + /* Find it all the different ways we know about it */ + foundit = 0; + cl_git_pass(git_submodule_foreach(g_repo, find_evil, &foundit)); + cl_assert_equal_i(0, foundit); + cl_git_fail_with(GIT_ENOTFOUND, git_submodule_lookup(&sm, g_repo, EVIL_SM_NAME)); + /* + * We do know about this as it's in the index and HEAD, but the data is + * incomplete as there is no configured data for it (we pretend it + * doesn't exist). This leaves us with an odd situation but it's + * consistent with what we would do if we did add a submodule with no + * configuration. + */ + cl_git_pass(git_submodule_lookup(&sm, g_repo, "testrepo")); + cl_git_pass(git_submodule_location(&sm_location, sm)); + cl_assert_equal_i(GIT_SUBMODULE_STATUS_IN_INDEX | GIT_SUBMODULE_STATUS_IN_HEAD, sm_location); + git_submodule_free(sm); +} + +void test_submodule_escape__from_gitdir_windows(void) +{ + int foundit; + git_submodule *sm; + git_buf buf = GIT_BUF_INIT; + unsigned int sm_location; + + g_repo = setup_fixture_submodule_simple(); + + cl_git_pass(git_buf_joinpath(&buf, git_repository_workdir(g_repo), ".gitmodules")); + cl_git_rewritefile(buf.ptr, + "[submodule \"" EVIL_SM_NAME_WINDOWS "\"]\n" + " path = testrepo\n" + " url = ../testrepo.git\n"); + git_buf_free(&buf); + + /* Find it all the different ways we know about it */ + foundit = 0; + cl_git_pass(git_submodule_foreach(g_repo, find_evil, &foundit)); + cl_assert_equal_i(0, foundit); + cl_git_fail_with(GIT_ENOTFOUND, git_submodule_lookup(&sm, g_repo, EVIL_SM_NAME_WINDOWS_UNESC)); + /* + * We do know about this as it's in the index and HEAD, but the data is + * incomplete as there is no configured data for it (we pretend it + * doesn't exist). This leaves us with an odd situation but it's + * consistent with what we would do if we did add a submodule with no + * configuration. + */ + cl_git_pass(git_submodule_lookup(&sm, g_repo, "testrepo")); + cl_git_pass(git_submodule_location(&sm_location, sm)); + cl_assert_equal_i(GIT_SUBMODULE_STATUS_IN_INDEX | GIT_SUBMODULE_STATUS_IN_HEAD, sm_location); + git_submodule_free(sm); +} diff --git a/tests/submodule/lookup.c b/tests/submodule/lookup.c index f84f07c60..f73ca2679 100644 --- a/tests/submodule/lookup.c +++ b/tests/submodule/lookup.c @@ -132,6 +132,27 @@ void test_submodule_lookup__foreach(void) cl_assert_equal_i(8, data.count); } +static int foreach_cb(git_submodule *sm, const char *name, void *payload) +{ + GIT_UNUSED(sm); + GIT_UNUSED(name); + GIT_UNUSED(payload); + return 0; +} + +void test_submodule_lookup__duplicated_path(void) +{ + cl_git_rewritefile("submod2/.gitmodules", + "[submodule \"sm1\"]\n" + " path = duplicated-path\n" + " url = sm1\n" + "[submodule \"sm2\"]\n" + " path = duplicated-path\n" + " url = sm2\n"); + + cl_git_fail(git_submodule_foreach(g_repo, foreach_cb, NULL)); +} + void test_submodule_lookup__lookup_even_with_unborn_head(void) { git_reference *head; @@ -430,14 +451,6 @@ void test_submodule_lookup__lookup_in_bare_repository_fails(void) cl_git_fail(git_submodule_lookup(&sm, g_repo, "nonexisting")); } -static int foreach_cb(git_submodule *sm, const char *name, void *payload) -{ - GIT_UNUSED(sm); - GIT_UNUSED(name); - GIT_UNUSED(payload); - return 0; -} - void test_submodule_lookup__foreach_in_bare_repository_fails(void) { cl_git_sandbox_cleanup(); @@ -445,3 +458,19 @@ void test_submodule_lookup__foreach_in_bare_repository_fails(void) cl_git_fail(git_submodule_foreach(g_repo, foreach_cb, NULL)); } + +void test_submodule_lookup__fail_invalid_gitmodules(void) +{ + git_submodule *sm; + sm_lookup_data data; + memset(&data, 0, sizeof(data)); + + cl_git_rewritefile("submod2/.gitmodules", + "[submodule \"Test_App\"\n" + " path = Test_App\n" + " url = ../Test_App\n"); + + cl_git_fail(git_submodule_lookup(&sm, g_repo, "Test_App")); + + cl_git_fail(git_submodule_foreach(g_repo, sm_lookup_cb, &data)); +} diff --git a/tests/worktree/reflog.c b/tests/worktree/reflog.c index 6152eb385..a68e72dcf 100644 --- a/tests/worktree/reflog.c +++ b/tests/worktree/reflog.c @@ -22,6 +22,32 @@ void test_worktree_reflog__cleanup(void) cleanup_fixture_worktree(&fixture); } +void test_worktree_reflog__read_worktree_HEAD(void) +{ + git_reflog *reflog; + const git_reflog_entry *entry; + + cl_git_pass(git_reflog_read(&reflog, fixture.worktree, "HEAD")); + cl_assert_equal_i(1, git_reflog_entrycount(reflog)); + + entry = git_reflog_entry_byindex(reflog, 0); + cl_assert(entry != NULL); + cl_assert_equal_s("checkout: moving from 099fabac3a9ea935598528c27f866e34089c2eff to testrepo-worktree", git_reflog_entry_message(entry)); + + git_reflog_free(reflog); +} + +void test_worktree_reflog__read_parent_HEAD(void) +{ + git_reflog *reflog; + + cl_git_pass(git_reflog_read(&reflog, fixture.repo, "HEAD")); + /* there is no logs/HEAD in the parent repo */ + cl_assert_equal_i(0, git_reflog_entrycount(reflog)); + + git_reflog_free(reflog); +} + void test_worktree_reflog__read(void) { git_reflog *reflog; diff --git a/tests/worktree/repository.c b/tests/worktree/repository.c index 5c7595c64..ca56413b7 100644 --- a/tests/worktree/repository.c +++ b/tests/worktree/repository.c @@ -27,6 +27,7 @@ void test_worktree_repository__head(void) cl_git_pass(git_reference_lookup(&ref, fixture.repo, "refs/heads/testrepo-worktree")); cl_git_pass(git_repository_head_for_worktree(&head, fixture.repo, "testrepo-worktree")); cl_assert(git_reference_cmp(ref, head) == 0); + cl_assert(git_reference_owner(ref) == fixture.repo); git_reference_free(ref); git_reference_free(head); -- 2.39.2