]> git.proxmox.com Git - libgit2.git/commitdiff
New upstream version 0.27.4+dfsg.1
authorXimin Luo <infinity0@debian.org>
Sat, 11 Aug 2018 02:43:40 +0000 (19:43 -0700)
committerXimin Luo <infinity0@debian.org>
Sat, 11 Aug 2018 02:43:40 +0000 (19:43 -0700)
63 files changed:
.travis.yml
CHANGELOG.md
CMakeLists.txt
appveyor.yml
cmake/Modules/FindPkgLibraries.cmake [new file with mode: 0644]
examples/CMakeLists.txt
include/git2/version.h
src/CMakeLists.txt
src/attr_file.c
src/checkout.c
src/delta.c
src/diff_print.c
src/hash/sha1dc/sha1.c
src/ignore.c
src/index.c
src/odb_mempack.c
src/path.c
src/path.h
src/refdb_fs.c
src/refs.c
src/refs.h
src/refspec.c
src/remote.c
src/revwalk.c
src/streams/openssl.c
src/streams/openssl.h
src/submodule.c
src/submodule.h
src/transports/local.c
src/transports/smart_pkt.c
src/transports/ssh.c
src/tree.c
src/util.c
src/worktree.c
tests/CMakeLists.txt
tests/attr/ignore.c
tests/checkout/nasty.c
tests/checkout/typechange.c
tests/delta/apply.c [new file with mode: 0644]
tests/diff/binary.c
tests/diff/stats.c
tests/fetchhead/nonetwork.c
tests/path/core.c
tests/path/dotgit.c [new file with mode: 0644]
tests/refs/dup.c
tests/resources/nasty/.gitted/objects/07/f9d4d85b75187e4db5b9cbcad3e6218582bd57 [new file with mode: 0644]
tests/resources/nasty/.gitted/objects/2a/9eb82c733e31ae312cee349084dcbc6f69639a [new file with mode: 0644]
tests/resources/nasty/.gitted/objects/42/1376db9e8aee847e9d774891e73098a7415e94 [new file with mode: 0644]
tests/resources/nasty/.gitted/objects/e3/0b60b120761f44ebd0f0a7b0e9445ce8e11d68 [new file with mode: 0644]
tests/resources/nasty/.gitted/refs/heads/gitmodules-symlink [new file with mode: 0644]
tests/resources/revwalk.git/HEAD [new file with mode: 0644]
tests/resources/revwalk.git/config [new file with mode: 0644]
tests/resources/revwalk.git/description [new file with mode: 0644]
tests/resources/revwalk.git/objects/info/packs [new file with mode: 0644]
tests/resources/revwalk.git/objects/pack/pack-9adacb9971981a1a3264fd473da5b800f2715959.idx [new file with mode: 0644]
tests/resources/revwalk.git/objects/pack/pack-9adacb9971981a1a3264fd473da5b800f2715959.pack [new file with mode: 0644]
tests/resources/revwalk.git/packed-refs [new file with mode: 0644]
tests/resources/revwalk.git/refs/.gitkeep [new file with mode: 0644]
tests/revwalk/basic.c
tests/submodule/escape.c [new file with mode: 0644]
tests/submodule/lookup.c
tests/worktree/reflog.c
tests/worktree/repository.c

index a4c8e91dfb57791f1fe10af4e4ce0504a7733d00..3a55e86b04042cb1cb4362480344438e568acfa2 100644 (file)
@@ -21,6 +21,7 @@ env:
   - OPTIONS="-DTHREADSAFE=OFF -DBUILD_EXAMPLES=ON -DENABLE_WERROR=ON"
 
 dist: trusty
+osx_image: xcode8.3
 sudo: false
 
 addons:
index ba0cb4ea89e869a1dbc7438578b2d05021a3b007..be62aa63d20f8c5ee233d4adf38e1f15188da428 100644 (file)
@@ -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
 ---------
index 2ca5354a7f999ff9cacafb07f590c016e9aca40d..7c159027102b5a1f3fbf002603128c68f0fd8e89 100644 (file)
@@ -29,7 +29,7 @@ INCLUDE(CheckFunctionExists)
 INCLUDE(CheckSymbolExists)
 INCLUDE(CheckStructHasMember)
 INCLUDE(AddCFlagIfSupported)
-INCLUDE(FindPkgConfig)
+INCLUDE(FindPkgLibraries)
 INCLUDE(FindThreads)
 INCLUDE(FindStatNsec)
 INCLUDE(IdeSplitSources)
index 9b14a9c81c4fc03c36770315c117f654e4f5aff6..f76830cb417ee414557d8076596f733175be4878 100644 (file)
@@ -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 (file)
index 0000000..49311c3
--- /dev/null
@@ -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()
index 99e2ba9c15c096d6a3e646c561dfc086f580e316..ca7515e5d6d6cd8b26df6614cb97c38caecefeed 100644 (file)
@@ -1,4 +1,3 @@
-LINK_DIRECTORIES(${LIBGIT2_LIBDIRS})
 INCLUDE_DIRECTORIES(${LIBGIT2_INCLUDES})
 
 FILE(GLOB_RECURSE SRC_EXAMPLE_GIT2 network/*.c network/*.h common.?)
index 746bf4230492fc023d2b1e19889ca1304a609386..7c42426572778a726c9300b124e1acea6f0479a2 100644 (file)
@@ -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
index b03b96af93af3538033c85a255fcb036fc807bcc..4cfb2d3117cc30e6f77e05c73b3f87e1938ba371 100644 (file)
@@ -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})
 
index 55d0c3865f2ba430ba8cca29393aad24864389c2..f46cce3de55bb827154e477b45a8fc2a368e50a4 100644 (file)
@@ -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;
index 8ff5d897bbd66ed86725de1a706f263ab23e55c0..debdbe95b53765572a63616022eb422e964cf4c9 100644 (file)
@@ -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;
                }
index 073cba7c674fc1164cd37ab9714805190a60472f..b9352b8ee0d62f44ef97b8805c2de16f283e4b09 100644 (file)
@@ -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;
                }
        }
index 28ae384243049845c1fe72afc1aab8c533887207..5e535482ca901ed397b84ff95d99e3622e9a34d5 100644 (file)
@@ -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;
        }
index facea1bb560b57bbe7419dd1cce49f6b1172ddca..25eded1399a8c3ae1532074ccdd388b24e660071 100644 (file)
@@ -10,6 +10,9 @@
 #include <memory.h>
 #include <stdio.h>
 #include <stdlib.h>
+#ifdef __unix__
+#include <sys/types.h> /* make sure macros like _BIG_ENDIAN visible */
+#endif
 #endif
 
 #ifdef SHA1DC_CUSTOM_INCLUDE_SHA1_C
 #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,
    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 <endian.h> 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 <processor whitelist> */
+#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 <processor whitelist>  or <processor blacklist> */
+
+/* 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
 #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
index dddd7e81eb21f04aeee4bb6a80df4d2f921475f2..76b997245f23e82d40472744c0f24a77f80564f3 100644 (file)
@@ -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);
 
                        /*
index a867547fbbadf5b836e1bab5fc81e75148ba7f69..09313ebeda9af68a2c6dd7130e5eeb147cfd2550 100644 (file)
@@ -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;
index a81716ee3290c725acf5bab5cd25c9e874d4302e..e351d4df944ccbfa9d18c523594d1dd9bb4c3b0c 100644 (file)
@@ -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);
 }
index ea0a3c3f685ff9e7cc3fba7b982d3f9507222fe5..58a5aaf4a4aca2e53a5d4b974bba55d57fa5bf25 100644 (file)
@@ -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);
+}
index aa24bcd2fec59c66812af28bfa02d7677c31f04e..fd515c8a260aefe96d7953dfcd79fc76eab00727 100644 (file)
@@ -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
index 140879d2335ed6ad8b96fd9c40db8dfa8edea09b..83174e8cde9e273d562969b0c2be0c5d53dfeda1 100644 (file)
@@ -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;
        }
index 550963e56f98f50ef41c17ff7134e404891aedbf..c42968359b56ad21ecd23a346a69d3bcee3bfc71 100644 (file)
@@ -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;
 }
 
index 5149c75477e37c07535cc40475711ab067f3f1c0..84daf8b53bd4540a307fd991c2dc3c6e6a414974 100644 (file)
@@ -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,
index 01a77c97facde0f3f9faf3eb79aee2639e4c0ffd..943a9c76adfd061fb3fff4369956f098d2ff0c9c 100644 (file)
@@ -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;
index 4d675af822d103240ed38e8ff722e1c29e933968..d8a6b991de40891436501f6372a9aa21d6ba9f05 100644 (file)
@@ -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)
index b1aa8f91af028eb8c632f68fc9583aca4cf93b00..eb228a52254952cffe0933fad7af41c722616612 100644 (file)
@@ -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;
index 9cbb2746fd5062e1525a2eecc3f05fd721e15de7..adcb7f14ef65d160ee23a4a71061356b51a12905 100644 (file)
@@ -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
index 2bbad7c682d5d8e1291380b24945c271767dcfe9..44329ec904dddf4e327c19a6f96049f3de163c8b 100644 (file)
@@ -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)
 {
index 3ec0307b3428226e923c175fa58de82c212b5cf1..4bf74dcfb62030d0b37202dbe59dd4ac0e0677d5 100644 (file)
@@ -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(
index 72867a32258d87eff7b80c68291de72a6c4eb5bf..91a4e12232912cd57924b752fe059a91d26731eb 100644 (file)
@@ -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
index 740cf36a9cc9823448f548fe6e07dc4232326d38..541c552f655ef5d664d7674451bcae67fad5a411 100644 (file)
@@ -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) {
index a661dfe1366063367eae87e2760a9cfc86a9a8c1..d10d6c68faea8abc28669ea0bd6cb5570cd82377 100644 (file)
@@ -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;
 
index dcd9b5e27b81a36c2276842d7c267fa8f40afaeb..23c6433463e4759f1bfbe2ed406ef02cbd8a896d 100644 (file)
@@ -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) {
index fdf36f850ca6fe4b2afc13e02c3cfeae860ac90a..12622975abb4706222035120c802f1436dff0a3d 100644 (file)
@@ -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);
 }
 
index 34841df4f1f73a24882600985235dc69c802fca6..2955b7ca0c5b4192c40cbe865a816d4d998e5785 100644 (file)
 #include "common.h"
 
 #ifdef GIT_WIN32
+# include "win32/utf-conv.h"
 # include "win32/w32_buffer.h"
+
+# ifdef HAVE_QSORT_S
+#  include <search.h>
+# endif
 #endif
 
 #ifdef _MSC_VER
index 4b18db7d6a17cb7a04c6fe02e2a0e3a8e691ad4e..91527663e6f104792753ac6c2e1bee37c798cb99 100644 (file)
@@ -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;
        }
index 775f33f2dc6867c6cf7ea7bfb7d9a629028554bd..82bf6d0d719a5a5f79c3ee2600203e9c35b2227f 100644 (file)
@@ -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})
index d241c03b558748d60c0e615ab7d3810b7d0c158e..165e2ba0905df5a1ca1f6384a447dc092f76d248 100644 (file)
@@ -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");
index 952a6a1127afbbb676bc55b6fb31595ea83bc8d7..d4d3c8fa466da8be4b086a24f8828a04481818f8 100644 (file)
@@ -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");
+}
index 8a5110caaf8e8f67438af1dc8e8a41612117b1e2..647b534b1e561b8361552dc54907a6b21dd90eb7 100644 (file)
@@ -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 (file)
index 0000000..5bb95a2
--- /dev/null
@@ -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)));
+}
index 173a5994e599b6b622e833409ef5ac60c161d410..c17ba5ef4e6ee7e832a1f1de65b3d828b4144ba8 100644 (file)
@@ -3,6 +3,7 @@
 #include "git2/sys/diff.h"
 
 #include "buffer.h"
+#include "delta.h"
 #include "filebuf.h"
 #include "repository.h"
 
index 3171a4486d57b9c4c2b3e12191edde267949b7d0..347d0d75701964f7e13cd58e9a1874f0850cc0a1 100644 (file)
@@ -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 =
index 4dabb577e3de1a6dad9767102775d4d8574ab3f6..a6394600af3c82bd9de278490426fd1b8d90d6cc 100644 (file)
@@ -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");
index 3dccfe5fbdaaa276412c1bf28a4e99485e192b85..0ab41ea503aa36c9cf655e9e5a027baeee001140 100644 (file)
@@ -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, "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: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, "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: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, "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: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, "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: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 (file)
index 0000000..20e585e
--- /dev/null
@@ -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));
+}
index 0fc635a7aa5c7dbc9d408a167d27905efdc4f566..8a89cd95c5ef6e974823fb4de49b0aa12374c013 100644 (file)
@@ -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 (file)
index 0000000..f040922
Binary files /dev/null and b/tests/resources/nasty/.gitted/objects/07/f9d4d85b75187e4db5b9cbcad3e6218582bd57 differ
diff --git a/tests/resources/nasty/.gitted/objects/2a/9eb82c733e31ae312cee349084dcbc6f69639a b/tests/resources/nasty/.gitted/objects/2a/9eb82c733e31ae312cee349084dcbc6f69639a
new file mode 100644 (file)
index 0000000..c4717d5
Binary files /dev/null and b/tests/resources/nasty/.gitted/objects/2a/9eb82c733e31ae312cee349084dcbc6f69639a differ
diff --git a/tests/resources/nasty/.gitted/objects/42/1376db9e8aee847e9d774891e73098a7415e94 b/tests/resources/nasty/.gitted/objects/42/1376db9e8aee847e9d774891e73098a7415e94
new file mode 100644 (file)
index 0000000..0666ba7
Binary files /dev/null and b/tests/resources/nasty/.gitted/objects/42/1376db9e8aee847e9d774891e73098a7415e94 differ
diff --git a/tests/resources/nasty/.gitted/objects/e3/0b60b120761f44ebd0f0a7b0e9445ce8e11d68 b/tests/resources/nasty/.gitted/objects/e3/0b60b120761f44ebd0f0a7b0e9445ce8e11d68
new file mode 100644 (file)
index 0000000..1c1be16
Binary files /dev/null and b/tests/resources/nasty/.gitted/objects/e3/0b60b120761f44ebd0f0a7b0e9445ce8e11d68 differ
diff --git a/tests/resources/nasty/.gitted/refs/heads/gitmodules-symlink b/tests/resources/nasty/.gitted/refs/heads/gitmodules-symlink
new file mode 100644 (file)
index 0000000..3a2499f
--- /dev/null
@@ -0,0 +1 @@
+e30b60b120761f44ebd0f0a7b0e9445ce8e11d68
diff --git a/tests/resources/revwalk.git/HEAD b/tests/resources/revwalk.git/HEAD
new file mode 100644 (file)
index 0000000..cb089cd
--- /dev/null
@@ -0,0 +1 @@
+ref: refs/heads/master
diff --git a/tests/resources/revwalk.git/config b/tests/resources/revwalk.git/config
new file mode 100644 (file)
index 0000000..7c968c3
--- /dev/null
@@ -0,0 +1,6 @@
+[core]
+       bare = true
+       repositoryformatversion = 0
+       filemode = false
+       symlinks = false
+       ignorecase = true
diff --git a/tests/resources/revwalk.git/description b/tests/resources/revwalk.git/description
new file mode 100644 (file)
index 0000000..498b267
--- /dev/null
@@ -0,0 +1 @@
+Unnamed repository; edit this file 'description' to name the repository.
diff --git a/tests/resources/revwalk.git/objects/info/packs b/tests/resources/revwalk.git/objects/info/packs
new file mode 100644 (file)
index 0000000..d8d85b8
--- /dev/null
@@ -0,0 +1,2 @@
+P pack-9adacb9971981a1a3264fd473da5b800f2715959.pack
+
diff --git a/tests/resources/revwalk.git/objects/pack/pack-9adacb9971981a1a3264fd473da5b800f2715959.idx b/tests/resources/revwalk.git/objects/pack/pack-9adacb9971981a1a3264fd473da5b800f2715959.idx
new file mode 100644 (file)
index 0000000..e157b38
Binary files /dev/null and b/tests/resources/revwalk.git/objects/pack/pack-9adacb9971981a1a3264fd473da5b800f2715959.idx differ
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 (file)
index 0000000..2a61f94
Binary files /dev/null and b/tests/resources/revwalk.git/objects/pack/pack-9adacb9971981a1a3264fd473da5b800f2715959.pack differ
diff --git a/tests/resources/revwalk.git/packed-refs b/tests/resources/revwalk.git/packed-refs
new file mode 100644 (file)
index 0000000..905a3db
--- /dev/null
@@ -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 (file)
index 0000000..e69de29
index 6a23701f3b1199ba85cbc206b2dc90cd3602853e..1106bf4ce6e601919f6fef030c1e897de0295947 100644 (file)
@@ -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 (file)
index 0000000..f5c3cd4
--- /dev/null
@@ -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);
+}
index f84f07c60b47c0bc6be706137b4af495ed4a4158..f73ca2679c931a2f695ee6279458090b25f8d928 100644 (file)
@@ -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));
+}
index 6152eb385383968fd4b0fb53512caccb4c0deb00..a68e72dcfe606d31882477d8235fd66d442453c4 100644 (file)
@@ -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;
index 5c7595c6401708a74937c597d062753e6becdd19..ca56413b7ee7f54d08598ce359a15e84824d3b9c 100644 (file)
@@ -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);