diff --git a/CHANGELOG.md b/CHANGELOG.md index 8544ac451..24ecba426 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,5 @@ -v0.25 + 1 -------- +v0.26 + 1 +--------- ### Changes or improvements @@ -9,6 +9,102 @@ v0.25 + 1 ### Breaking API changes +v0.26 +----- + +### Changes or improvements + +* Support for opening, creating and modifying worktrees. + +* We can now detect SHA1 collisions resulting from the SHAttered attack. These + checks can be enabled at build time via `-DUSE_SHA1DC`. + +* Fix for missing implementation of `git_merge_driver_source` getters. + +* Fix for installed pkg-config file being broken when the prefix contains + spaces. + +* We now detect when the hashsum of on-disk objects does not match their + expected hashsum. + +* We now support open-ended ranges (e.g. "master..", "...master") in our + revision range parsing code. + +* We now correctly compute ignores with leading "/" in subdirectories. + +* We now optionally call `fsync` on loose objects, packfiles and their indexes, + loose references and packed reference files. + +* We can now build against OpenSSL v1.1 and against LibreSSL. + +* `GIT_MERGE_OPTIONS_INIT` now includes a setting to perform rename detection. + This aligns this structure with the default by `git_merge` and + `git_merge_trees` when `NULL` was provided for the options. + +* Improvements for reading index v4 files. + +* Perform additional retries for filesystem operations on Windows when files + are temporarily locked by other processes. + +### API additions + +* New family of functions to handle worktrees: + + * `git_worktree_list()` lets you look up worktrees for a repository. + * `git_worktree_lookup()` lets you get a specific worktree. + * `git_worktree_open_from_repository()` lets you get the associated worktree + of a repository. + a worktree. + * `git_worktree_add` lets you create new worktrees. + * `git_worktree_prune` lets you remove worktrees from disk. + * `git_worktree_lock()` and `git_worktree_unlock()` let you lock + respectively unlock a worktree. + * `git_repository_open_from_worktree()` lets you open a repository via + * `git_repository_head_for_worktree()` lets you get the current `HEAD` for a + linked worktree. + * `git_repository_head_detached_for_worktree()` lets you check whether a + linked worktree is in detached HEAD mode. + +* `git_repository_item_path()` lets you retrieve paths for various repository + files. + +* `git_repository_commondir()` lets you retrieve the common directory of a + repository. + +* `git_branch_is_checked_out()` allows you to check whether a branch is checked + out in a repository or any of its worktrees. + +* `git_repository_submodule_cache_all()` and + `git_repository_submodule_cache_clear()` functions allow you to prime or clear + the submodule cache of a repository. + +* You can disable strict hash verifications via the + `GIT_OPT_ENABLE_STRICT_HASH_VERIFICATION` option with `git_libgit2_opts()`. + +* You can enable us calling `fsync` for various files inside the ".git" + directory by setting the `GIT_OPT_ENABLE_FSYNC_GITDIR` option with + `git_libgit2_opts()`. + +* You can now enable "offset deltas" when creating packfiles and negotiating + packfiles with a remote server by setting `GIT_OPT_ENABLE_OFS_DELTA` option + with `GIT_libgit2_opts()`. + +* You can now set the default share mode on Windows for opening files using + `GIT_OPT_SET_WINDOWS_SHAREMODE` option with `git_libgit2_opts()`. + You can query the current share mode with `GIT_OPT_GET_WINDOWS_SHAREMODE`. + +* `git_transport_smart_proxy_options()' enables you to get the proxy options for + smart transports. + +* The `GIT_FILTER_INIT` macro and the `git_filter_init` function are provided + to initialize a `git_filter` structure. + +### Breaking API changes + +* `clone_checkout_strategy` has been removed from + `git_submodule_update_option`. The checkout strategy used to clone will + be the same strategy specified in `checkout_opts`. + v0.25 ------- @@ -150,7 +246,12 @@ v0.25 If this is `NULL`, then it will not be called and the `exists` function will be used instead. -* `git_remote_connect()` now accepts proxy options. +* `git_remote_connect()` now accepts `git_proxy_options` argument, and + `git_fetch_options` and `git_push_options` each have a `proxy_opts` field. + +* `git_merge_options` now provides a `default_driver` that can be used + to provide the name of a merge driver to be used to handle files changed + during a merge. v0.24 ------- @@ -227,10 +328,6 @@ v0.24 ### Breaking API changes -* `git_merge_options` now provides a `default_driver` that can be used - to provide the name of a merge driver to be used to handle files changed - during a merge. - * The `git_merge_tree_flag_t` is now `git_merge_flag_t`. Subsequently, its members are no longer prefixed with `GIT_MERGE_TREE_FLAG` but are now prefixed with `GIT_MERGE_FLAG`, and the `tree_flags` field of the diff --git a/CMakeLists.txt b/CMakeLists.txt index f26f46879..4783e3ef9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -37,6 +37,7 @@ OPTION( PROFILE "Generate profiling information" OFF ) OPTION( ENABLE_TRACE "Enables tracing support" OFF ) OPTION( LIBGIT2_FILENAME "Name of the produced binary" OFF ) +OPTION( USE_SHA1DC "Use SHA-1 with collision detection" OFF ) OPTION( USE_ICONV "Link with and use iconv library" OFF ) OPTION( USE_SSH "Link with libssh to enable SSH support" ON ) OPTION( USE_GSSAPI "Link with libgssapi for SPNEGO auth" OFF ) @@ -237,8 +238,7 @@ ENDIF() IF (WIN32 AND WINHTTP) ADD_DEFINITIONS(-DGIT_WINHTTP) - INCLUDE_DIRECTORIES(deps/http-parser) - FILE(GLOB SRC_HTTP deps/http-parser/*.c deps/http-parser/*.h) + ADD_DEFINITIONS(-DGIT_HTTPS) # Since MinGW does not come with headers or an import library for winhttp, # we have to include a private header and generate our own import library @@ -291,27 +291,22 @@ ELSE () LINK_LIBRARIES(${CURL_LIBRARIES}) LIST(APPEND LIBGIT2_PC_LIBS ${CURL_LDFLAGS}) ENDIF() - - FIND_PACKAGE(HTTP_Parser) - IF (HTTP_PARSER_FOUND AND HTTP_PARSER_VERSION_MAJOR EQUAL 2) - INCLUDE_DIRECTORIES(${HTTP_PARSER_INCLUDE_DIRS}) - LINK_LIBRARIES(${HTTP_PARSER_LIBRARIES}) - LIST(APPEND LIBGIT2_PC_LIBS "-lhttp_parser") - ELSE() - MESSAGE(STATUS "http-parser was not found or is too old; using bundled 3rd-party sources.") - INCLUDE_DIRECTORIES(deps/http-parser) - FILE(GLOB SRC_HTTP deps/http-parser/*.c deps/http-parser/*.h) - ENDIF() ENDIF() # Specify sha1 implementation -IF (WIN32 AND NOT MINGW AND NOT SHA1_TYPE STREQUAL "builtin") - ADD_DEFINITIONS(-DWIN32_SHA1) +IF (USE_SHA1DC) + ADD_DEFINITIONS(-DGIT_SHA1_COLLISIONDETECT) + ADD_DEFINITIONS(-DSHA1DC_NO_STANDARD_INCLUDES=1) + ADD_DEFINITIONS(-DSHA1DC_CUSTOM_INCLUDE_SHA1_C=\"common.h\") + ADD_DEFINITIONS(-DSHA1DC_CUSTOM_INCLUDE_UBC_CHECK_C=\"common.h\") + FILE(GLOB SRC_SHA1 src/hash/hash_collisiondetect.c src/hash/sha1dc/*) +ELSEIF (WIN32 AND NOT MINGW) + ADD_DEFINITIONS(-DGIT_SHA1_WIN32) FILE(GLOB SRC_SHA1 src/hash/hash_win32.c) ELSEIF (${CMAKE_SYSTEM_NAME} MATCHES "Darwin") - ADD_DEFINITIONS(-DGIT_COMMON_CRYPTO) -ELSEIF (OPENSSL_FOUND AND NOT SHA1_TYPE STREQUAL "builtin") - ADD_DEFINITIONS(-DOPENSSL_SHA1) + ADD_DEFINITIONS(-DGIT_SHA1_COMMON_CRYPTO) +ELSEIF (OPENSSL_FOUND) + ADD_DEFINITIONS(-DGIT_SHA1_OPENSSL) IF (CMAKE_SYSTEM_NAME MATCHES "FreeBSD") LIST(APPEND LIBGIT2_PC_LIBS "-lssl") ELSE() @@ -332,6 +327,18 @@ IF(WIN32 OR AMIGA OR CMAKE_SYSTEM_NAME MATCHES "(Solaris|SunOS)") SET(SRC_REGEX deps/regex/regex.c) ENDIF() +# Optional external dependency: http-parser +FIND_PACKAGE(HTTP_Parser) +IF (HTTP_PARSER_FOUND AND HTTP_PARSER_VERSION_MAJOR EQUAL 2) + INCLUDE_DIRECTORIES(${HTTP_PARSER_INCLUDE_DIRS}) + LINK_LIBRARIES(${HTTP_PARSER_LIBRARIES}) + LIST(APPEND LIBGIT2_PC_LIBS "-lhttp_parser") +ELSE() + MESSAGE(STATUS "http-parser version 2 was not found; using bundled 3rd-party sources.") + INCLUDE_DIRECTORIES(deps/http-parser) + FILE(GLOB SRC_HTTP deps/http-parser/*.c deps/http-parser/*.h) +ENDIF() + # Optional external dependency: zlib FIND_PACKAGE(ZLIB) IF (ZLIB_FOUND) @@ -461,19 +468,17 @@ IF (MSVC) SET(CMAKE_SHARED_LINKER_FLAGS_MINSIZEREL "${CMAKE_EXE_LINKER_FLAGS_MINSIZEREL}") SET(WIN_RC "src/win32/git2.rc") - - # Precompiled headers - ELSE () - SET(CMAKE_C_FLAGS "-D_GNU_SOURCE -Wall -Wextra ${CMAKE_C_FLAGS}") + SET(CMAKE_C_FLAGS "-D_GNU_SOURCE ${CMAKE_C_FLAGS}") + + ADD_C_FLAG_IF_SUPPORTED(-Wall) + ADD_C_FLAG_IF_SUPPORTED(-Wextra) IF (CMAKE_SYSTEM_NAME MATCHES "(Solaris|SunOS)") SET(CMAKE_C_FLAGS "-std=c99 -D_POSIX_C_SOURCE=200112L -D__EXTENSIONS__ -D_POSIX_PTHREAD_SEMANTICS ${CMAKE_C_FLAGS}") ENDIF() - IF (WIN32 AND NOT CYGWIN) - SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -D_DEBUG") - ENDIF () + SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -D_DEBUG -O0") IF (MINGW OR MSYS) # MinGW and MSYS always do PIC and complain if we tell them to STRING(REGEX REPLACE "-fPIC" "" CMAKE_SHARED_LIBRARY_C_FLAGS "${CMAKE_SHARED_LIBRARY_C_FLAGS}") @@ -540,11 +545,13 @@ ENDIF() IF (SECURITY_FOUND) ADD_DEFINITIONS(-DGIT_SECURE_TRANSPORT) + ADD_DEFINITIONS(-DGIT_HTTPS) INCLUDE_DIRECTORIES(${SECURITY_INCLUDE_DIR}) ENDIF () IF (OPENSSL_FOUND) ADD_DEFINITIONS(-DGIT_OPENSSL) + ADD_DEFINITIONS(-DGIT_HTTPS) INCLUDE_DIRECTORIES(${OPENSSL_INCLUDE_DIR}) SET(SSL_LIBRARIES ${OPENSSL_LIBRARIES}) ENDIF() @@ -697,9 +704,9 @@ IF (BUILD_CLAR) ENABLE_TESTING() IF (WINHTTP OR OPENSSL_FOUND OR SECURITY_FOUND) - ADD_TEST(libgit2_clar libgit2_clar -ionline) + ADD_TEST(libgit2_clar libgit2_clar -ionline -xclone::local::git_style_unc_paths -xclone::local::standard_unc_paths_are_written_git_style) ELSE () - ADD_TEST(libgit2_clar libgit2_clar -v) + ADD_TEST(libgit2_clar libgit2_clar -v -xclone::local::git_style_unc_paths -xclone::local::standard_unc_paths_are_written_git_style) ENDIF () # Add a test target which runs the cred callback tests, to be diff --git a/CONVENTIONS.md b/CONVENTIONS.md index 0be4b33cc..ffb696a4d 100644 --- a/CONVENTIONS.md +++ b/CONVENTIONS.md @@ -18,11 +18,11 @@ other's toes. - If a function returns an object as a return value, that function is a getter and the object's lifetime is tied to the parent object. Objects which are returned as the first argument as a - pointer-to-pointer are owned by the caller and it is repsponsible + pointer-to-pointer are owned by the caller and it is responsible for freeing it. Strings are returned via `git_buf` in order to allow for re-use and safe freeing. - - Most of what libgit2 does relates to I/O so you as a general rule + - Most of what libgit2 does relates to I/O so as a general rule you should assume that any function can fail due to errors as even getting data from the filesystem can result in all sorts of errors and complex failure cases. diff --git a/COPYING b/COPYING index 1b88b9b8e..da695ebdb 100644 --- a/COPYING +++ b/COPYING @@ -958,3 +958,36 @@ necessary. Here is a sample; alter the names: That's all there is to it! ---------------------------------------------------------------------- + +The bundled SHA1 collision detection code is licensed under the MIT license: + +MIT License + +Copyright (c) 2017: + Marc Stevens + Cryptology Group + Centrum Wiskunde & Informatica + P.O. Box 94079, 1090 GB Amsterdam, Netherlands + marc@marc-stevens.nl + + Dan Shumow + Microsoft Research + danshu@microsoft.com + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md index 19d24dea1..1bbd37134 100644 --- a/README.md +++ b/README.md @@ -43,10 +43,9 @@ We ask that you not open a GitHub Issue for help, only for bug reports. What It Can Do ============== -The goal of this library is to allow its users the ability to handle Git data in -their applications from their programming language of choice, as is used in -production for many applications including the GitHub.com site, in Plastic SCM -and also powering Microsoft's Visual Studio tools for Git. +libgit2 provides you with the ability to manage Git repositories in the +programming language of your choice. It's used in production to power many +applications including GitHub.com, Plastic SCM and Visual Studio Team Services. It does not aim to replace the git tool or its user-facing commands. Some APIs resemble the plumbing commands as those align closely with the concepts of the @@ -68,6 +67,16 @@ The library provides: * descriptive and detailed error messages * ...and more (over 175 different API calls) +As libgit2 is purely a consumer of the Git system, we have to +adjust to changes made upstream. This has two major consequences: + +* Some changes may require us to change provided interfaces. While we try to + implement functions in a generic way so that no future changes are required, + we cannot promise a completely stable API. +* As we have to keep up with changes in behavior made upstream, we may lag + behind in some areas. We usually to document these incompatibilities in our + issue tracker with the label "git change". + Optional dependencies ===================== @@ -124,6 +133,14 @@ On most systems you can build the library using the following commands Alternatively you can point the CMake GUI tool to the CMakeLists.txt file and generate platform specific build project or IDE workspace. +Once built, you can run the tests from the `build` directory with the command + + $ make test + +Alternatively you can run the test suite directly using, + + $ ./libgit2_clar + To install the library you can specify the install prefix by setting: $ cmake .. -DCMAKE_INSTALL_PREFIX=/install/prefix diff --git a/appveyor.yml b/appveyor.yml index 9e94c0726..fb3fff7dd 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -2,6 +2,7 @@ version: '{build}' branches: only: - master + - appveyor - /^maint.*/ environment: GITTEST_INVASIVE_FS_STRUCTURE: 1 diff --git a/deps/http-parser/LICENSE-MIT b/deps/http-parser/LICENSE-MIT deleted file mode 100644 index 58010b388..000000000 --- a/deps/http-parser/LICENSE-MIT +++ /dev/null @@ -1,23 +0,0 @@ -http_parser.c is based on src/http/ngx_http_parse.c from NGINX copyright -Igor Sysoev. - -Additional changes are licensed under the same terms as NGINX and -copyright Joyent, Inc. and other Node contributors. All rights reserved. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to -deal in the Software without restriction, including without limitation the -rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -sell copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -IN THE SOFTWARE. diff --git a/deps/http-parser/http_parser.c b/deps/http-parser/http_parser.c deleted file mode 100644 index 27bdd2081..000000000 --- a/deps/http-parser/http_parser.c +++ /dev/null @@ -1,2177 +0,0 @@ -/* Based on src/http/ngx_http_parse.c from NGINX copyright Igor Sysoev - * - * Additional changes are licensed under the same terms as NGINX and - * copyright Joyent, Inc. and other Node contributors. All rights reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to - * deal in the Software without restriction, including without limitation the - * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or - * sell copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - */ -#include "http_parser.h" -#include -#include -#include -#include -#include -#include - -#ifndef ULLONG_MAX -# define ULLONG_MAX ((uint64_t) -1) /* 2^64-1 */ -#endif - -#ifndef MIN -# define MIN(a,b) ((a) < (b) ? (a) : (b)) -#endif - -#ifndef ARRAY_SIZE -# define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) -#endif - -#ifndef BIT_AT -# define BIT_AT(a, i) \ - (!!((unsigned int) (a)[(unsigned int) (i) >> 3] & \ - (1 << ((unsigned int) (i) & 7)))) -#endif - -#ifndef ELEM_AT -# define ELEM_AT(a, i, v) ((unsigned int) (i) < ARRAY_SIZE(a) ? (a)[(i)] : (v)) -#endif - -#define SET_ERRNO(e) \ -do { \ - parser->http_errno = (e); \ -} while(0) - - -/* Run the notify callback FOR, returning ER if it fails */ -#define CALLBACK_NOTIFY_(FOR, ER) \ -do { \ - assert(HTTP_PARSER_ERRNO(parser) == HPE_OK); \ - \ - if (settings->on_##FOR) { \ - if (0 != settings->on_##FOR(parser)) { \ - SET_ERRNO(HPE_CB_##FOR); \ - } \ - \ - /* We either errored above or got paused; get out */ \ - if (HTTP_PARSER_ERRNO(parser) != HPE_OK) { \ - return (ER); \ - } \ - } \ -} while (0) - -/* Run the notify callback FOR and consume the current byte */ -#define CALLBACK_NOTIFY(FOR) CALLBACK_NOTIFY_(FOR, p - data + 1) - -/* Run the notify callback FOR and don't consume the current byte */ -#define CALLBACK_NOTIFY_NOADVANCE(FOR) CALLBACK_NOTIFY_(FOR, p - data) - -/* Run data callback FOR with LEN bytes, returning ER if it fails */ -#define CALLBACK_DATA_(FOR, LEN, ER) \ -do { \ - assert(HTTP_PARSER_ERRNO(parser) == HPE_OK); \ - \ - if (FOR##_mark) { \ - if (settings->on_##FOR) { \ - if (0 != settings->on_##FOR(parser, FOR##_mark, (LEN))) { \ - SET_ERRNO(HPE_CB_##FOR); \ - } \ - \ - /* We either errored above or got paused; get out */ \ - if (HTTP_PARSER_ERRNO(parser) != HPE_OK) { \ - return (ER); \ - } \ - } \ - FOR##_mark = NULL; \ - } \ -} while (0) - -/* Run the data callback FOR and consume the current byte */ -#define CALLBACK_DATA(FOR) \ - CALLBACK_DATA_(FOR, p - FOR##_mark, p - data + 1) - -/* Run the data callback FOR and don't consume the current byte */ -#define CALLBACK_DATA_NOADVANCE(FOR) \ - CALLBACK_DATA_(FOR, p - FOR##_mark, p - data) - -/* Set the mark FOR; non-destructive if mark is already set */ -#define MARK(FOR) \ -do { \ - if (!FOR##_mark) { \ - FOR##_mark = p; \ - } \ -} while (0) - - -#define PROXY_CONNECTION "proxy-connection" -#define CONNECTION "connection" -#define CONTENT_LENGTH "content-length" -#define TRANSFER_ENCODING "transfer-encoding" -#define UPGRADE "upgrade" -#define CHUNKED "chunked" -#define KEEP_ALIVE "keep-alive" -#define CLOSE "close" - - -static const char *method_strings[] = - { -#define XX(num, name, string) #string, - HTTP_METHOD_MAP(XX) -#undef XX - }; - - -/* Tokens as defined by rfc 2616. Also lowercases them. - * token = 1* - * separators = "(" | ")" | "<" | ">" | "@" - * | "," | ";" | ":" | "\" | <"> - * | "/" | "[" | "]" | "?" | "=" - * | "{" | "}" | SP | HT - */ -static const char tokens[256] = { -/* 0 nul 1 soh 2 stx 3 etx 4 eot 5 enq 6 ack 7 bel */ - 0, 0, 0, 0, 0, 0, 0, 0, -/* 8 bs 9 ht 10 nl 11 vt 12 np 13 cr 14 so 15 si */ - 0, 0, 0, 0, 0, 0, 0, 0, -/* 16 dle 17 dc1 18 dc2 19 dc3 20 dc4 21 nak 22 syn 23 etb */ - 0, 0, 0, 0, 0, 0, 0, 0, -/* 24 can 25 em 26 sub 27 esc 28 fs 29 gs 30 rs 31 us */ - 0, 0, 0, 0, 0, 0, 0, 0, -/* 32 sp 33 ! 34 " 35 # 36 $ 37 % 38 & 39 ' */ - 0, '!', 0, '#', '$', '%', '&', '\'', -/* 40 ( 41 ) 42 * 43 + 44 , 45 - 46 . 47 / */ - 0, 0, '*', '+', 0, '-', '.', 0, -/* 48 0 49 1 50 2 51 3 52 4 53 5 54 6 55 7 */ - '0', '1', '2', '3', '4', '5', '6', '7', -/* 56 8 57 9 58 : 59 ; 60 < 61 = 62 > 63 ? */ - '8', '9', 0, 0, 0, 0, 0, 0, -/* 64 @ 65 A 66 B 67 C 68 D 69 E 70 F 71 G */ - 0, 'a', 'b', 'c', 'd', 'e', 'f', 'g', -/* 72 H 73 I 74 J 75 K 76 L 77 M 78 N 79 O */ - 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', -/* 80 P 81 Q 82 R 83 S 84 T 85 U 86 V 87 W */ - 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', -/* 88 X 89 Y 90 Z 91 [ 92 \ 93 ] 94 ^ 95 _ */ - 'x', 'y', 'z', 0, 0, 0, '^', '_', -/* 96 ` 97 a 98 b 99 c 100 d 101 e 102 f 103 g */ - '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', -/* 104 h 105 i 106 j 107 k 108 l 109 m 110 n 111 o */ - 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', -/* 112 p 113 q 114 r 115 s 116 t 117 u 118 v 119 w */ - 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', -/* 120 x 121 y 122 z 123 { 124 | 125 } 126 ~ 127 del */ - 'x', 'y', 'z', 0, '|', 0, '~', 0 }; - - -static const int8_t unhex[256] = - {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 - ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 - ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 - , 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,-1,-1,-1,-1,-1,-1 - ,-1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1 - ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 - ,-1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1 - ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 - }; - - -#if HTTP_PARSER_STRICT -# define T(v) 0 -#else -# define T(v) v -#endif - - -static const uint8_t normal_url_char[32] = { -/* 0 nul 1 soh 2 stx 3 etx 4 eot 5 enq 6 ack 7 bel */ - 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0, -/* 8 bs 9 ht 10 nl 11 vt 12 np 13 cr 14 so 15 si */ - 0 | T(2) | 0 | 0 | T(16) | 0 | 0 | 0, -/* 16 dle 17 dc1 18 dc2 19 dc3 20 dc4 21 nak 22 syn 23 etb */ - 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0, -/* 24 can 25 em 26 sub 27 esc 28 fs 29 gs 30 rs 31 us */ - 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0, -/* 32 sp 33 ! 34 " 35 # 36 $ 37 % 38 & 39 ' */ - 0 | 2 | 4 | 0 | 16 | 32 | 64 | 128, -/* 40 ( 41 ) 42 * 43 + 44 , 45 - 46 . 47 / */ - 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, -/* 48 0 49 1 50 2 51 3 52 4 53 5 54 6 55 7 */ - 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, -/* 56 8 57 9 58 : 59 ; 60 < 61 = 62 > 63 ? */ - 1 | 2 | 4 | 8 | 16 | 32 | 64 | 0, -/* 64 @ 65 A 66 B 67 C 68 D 69 E 70 F 71 G */ - 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, -/* 72 H 73 I 74 J 75 K 76 L 77 M 78 N 79 O */ - 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, -/* 80 P 81 Q 82 R 83 S 84 T 85 U 86 V 87 W */ - 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, -/* 88 X 89 Y 90 Z 91 [ 92 \ 93 ] 94 ^ 95 _ */ - 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, -/* 96 ` 97 a 98 b 99 c 100 d 101 e 102 f 103 g */ - 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, -/* 104 h 105 i 106 j 107 k 108 l 109 m 110 n 111 o */ - 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, -/* 112 p 113 q 114 r 115 s 116 t 117 u 118 v 119 w */ - 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, -/* 120 x 121 y 122 z 123 { 124 | 125 } 126 ~ 127 del */ - 1 | 2 | 4 | 8 | 16 | 32 | 64 | 0, }; - -#undef T - -enum state - { s_dead = 1 /* important that this is > 0 */ - - , s_start_req_or_res - , s_res_or_resp_H - , s_start_res - , s_res_H - , s_res_HT - , s_res_HTT - , s_res_HTTP - , s_res_first_http_major - , s_res_http_major - , s_res_first_http_minor - , s_res_http_minor - , s_res_first_status_code - , s_res_status_code - , s_res_status - , s_res_line_almost_done - - , s_start_req - - , s_req_method - , s_req_spaces_before_url - , s_req_schema - , s_req_schema_slash - , s_req_schema_slash_slash - , s_req_server_start - , s_req_server - , s_req_server_with_at - , s_req_path - , s_req_query_string_start - , s_req_query_string - , s_req_fragment_start - , s_req_fragment - , s_req_http_start - , s_req_http_H - , s_req_http_HT - , s_req_http_HTT - , s_req_http_HTTP - , s_req_first_http_major - , s_req_http_major - , s_req_first_http_minor - , s_req_http_minor - , s_req_line_almost_done - - , s_header_field_start - , s_header_field - , s_header_value_start - , s_header_value - , s_header_value_lws - - , s_header_almost_done - - , s_chunk_size_start - , s_chunk_size - , s_chunk_parameters - , s_chunk_size_almost_done - - , s_headers_almost_done - , s_headers_done - - /* Important: 's_headers_done' must be the last 'header' state. All - * states beyond this must be 'body' states. It is used for overflow - * checking. See the PARSING_HEADER() macro. - */ - - , s_chunk_data - , s_chunk_data_almost_done - , s_chunk_data_done - - , s_body_identity - , s_body_identity_eof - - , s_message_done - }; - - -#define PARSING_HEADER(state) (state <= s_headers_done) - - -enum header_states - { h_general = 0 - , h_C - , h_CO - , h_CON - - , h_matching_connection - , h_matching_proxy_connection - , h_matching_content_length - , h_matching_transfer_encoding - , h_matching_upgrade - - , h_connection - , h_content_length - , h_transfer_encoding - , h_upgrade - - , h_matching_transfer_encoding_chunked - , h_matching_connection_keep_alive - , h_matching_connection_close - - , h_transfer_encoding_chunked - , h_connection_keep_alive - , h_connection_close - }; - -enum http_host_state - { - s_http_host_dead = 1 - , s_http_userinfo_start - , s_http_userinfo - , s_http_host_start - , s_http_host_v6_start - , s_http_host - , s_http_host_v6 - , s_http_host_v6_end - , s_http_host_port_start - , s_http_host_port -}; - -/* Macros for character classes; depends on strict-mode */ -#define CR '\r' -#define LF '\n' -#define LOWER(c) (unsigned char)(c | 0x20) -#define IS_ALPHA(c) (LOWER(c) >= 'a' && LOWER(c) <= 'z') -#define IS_NUM(c) ((c) >= '0' && (c) <= '9') -#define IS_ALPHANUM(c) (IS_ALPHA(c) || IS_NUM(c)) -#define IS_HEX(c) (IS_NUM(c) || (LOWER(c) >= 'a' && LOWER(c) <= 'f')) -#define IS_MARK(c) ((c) == '-' || (c) == '_' || (c) == '.' || \ - (c) == '!' || (c) == '~' || (c) == '*' || (c) == '\'' || (c) == '(' || \ - (c) == ')') -#define IS_USERINFO_CHAR(c) (IS_ALPHANUM(c) || IS_MARK(c) || (c) == '%' || \ - (c) == ';' || (c) == ':' || (c) == '&' || (c) == '=' || (c) == '+' || \ - (c) == '$' || (c) == ',') - -#if HTTP_PARSER_STRICT -#define TOKEN(c) (tokens[(unsigned char)c]) -#define IS_URL_CHAR(c) (BIT_AT(normal_url_char, (unsigned char)c)) -#define IS_HOST_CHAR(c) (IS_ALPHANUM(c) || (c) == '.' || (c) == '-') -#else -#define TOKEN(c) ((c == ' ') ? ' ' : tokens[(unsigned char)c]) -#define IS_URL_CHAR(c) \ - (BIT_AT(normal_url_char, (unsigned char)c) || ((c) & 0x80)) -#define IS_HOST_CHAR(c) \ - (IS_ALPHANUM(c) || (c) == '.' || (c) == '-' || (c) == '_') -#endif - - -#define start_state (parser->type == HTTP_REQUEST ? s_start_req : s_start_res) - - -#if HTTP_PARSER_STRICT -# define STRICT_CHECK(cond) \ -do { \ - if (cond) { \ - SET_ERRNO(HPE_STRICT); \ - goto error; \ - } \ -} while (0) -# define NEW_MESSAGE() (http_should_keep_alive(parser) ? start_state : s_dead) -#else -# define STRICT_CHECK(cond) -# define NEW_MESSAGE() start_state -#endif - - -/* Map errno values to strings for human-readable output */ -#define HTTP_STRERROR_GEN(n, s) { "HPE_" #n, s }, -static struct { - const char *name; - const char *description; -} http_strerror_tab[] = { - HTTP_ERRNO_MAP(HTTP_STRERROR_GEN) -}; -#undef HTTP_STRERROR_GEN - -int http_message_needs_eof(const http_parser *parser); - -/* Our URL parser. - * - * This is designed to be shared by http_parser_execute() for URL validation, - * hence it has a state transition + byte-for-byte interface. In addition, it - * is meant to be embedded in http_parser_parse_url(), which does the dirty - * work of turning state transitions URL components for its API. - * - * This function should only be invoked with non-space characters. It is - * assumed that the caller cares about (and can detect) the transition between - * URL and non-URL states by looking for these. - */ -static enum state -parse_url_char(enum state s, const char ch) -{ - if (ch == ' ' || ch == '\r' || ch == '\n') { - return s_dead; - } - -#if HTTP_PARSER_STRICT - if (ch == '\t' || ch == '\f') { - return s_dead; - } -#endif - - switch (s) { - case s_req_spaces_before_url: - /* Proxied requests are followed by scheme of an absolute URI (alpha). - * All methods except CONNECT are followed by '/' or '*'. - */ - - if (ch == '/' || ch == '*') { - return s_req_path; - } - - /* The schema must start with an alpha character. After that, it may - * consist of digits, '+', '-' or '.', followed by a ':'. - */ - if (IS_ALPHA(ch)) { - return s_req_schema; - } - - break; - - case s_req_schema: - if (IS_ALPHANUM(ch) || ch == '+' || ch == '-' || ch == '.') { - return s; - } - - if (ch == ':') { - return s_req_schema_slash; - } - - break; - - case s_req_schema_slash: - if (ch == '/') { - return s_req_schema_slash_slash; - } - - break; - - case s_req_schema_slash_slash: - if (ch == '/') { - return s_req_server_start; - } - - break; - - case s_req_server_with_at: - if (ch == '@') { - return s_dead; - } - - /* FALLTHROUGH */ - case s_req_server_start: - case s_req_server: - if (ch == '/') { - return s_req_path; - } - - if (ch == '?') { - return s_req_query_string_start; - } - - if (ch == '@') { - return s_req_server_with_at; - } - - if (IS_USERINFO_CHAR(ch) || ch == '[' || ch == ']') { - return s_req_server; - } - - break; - - case s_req_path: - if (IS_URL_CHAR(ch)) { - return s; - } - - switch (ch) { - case '?': - return s_req_query_string_start; - - case '#': - return s_req_fragment_start; - } - - break; - - case s_req_query_string_start: - case s_req_query_string: - if (IS_URL_CHAR(ch)) { - return s_req_query_string; - } - - switch (ch) { - case '?': - /* allow extra '?' in query string */ - return s_req_query_string; - - case '#': - return s_req_fragment_start; - } - - break; - - case s_req_fragment_start: - if (IS_URL_CHAR(ch)) { - return s_req_fragment; - } - - switch (ch) { - case '?': - return s_req_fragment; - - case '#': - return s; - } - - break; - - case s_req_fragment: - if (IS_URL_CHAR(ch)) { - return s; - } - - switch (ch) { - case '?': - case '#': - return s; - } - - break; - - default: - break; - } - - /* We should never fall out of the switch above unless there's an error */ - return s_dead; -} - -size_t http_parser_execute (http_parser *parser, - const http_parser_settings *settings, - const char *data, - size_t len) -{ - char c, ch; - int8_t unhex_val; - const char *p = data; - const char *header_field_mark = 0; - const char *header_value_mark = 0; - const char *url_mark = 0; - const char *body_mark = 0; - - /* We're in an error state. Don't bother doing anything. */ - if (HTTP_PARSER_ERRNO(parser) != HPE_OK) { - return 0; - } - - if (len == 0) { - switch (parser->state) { - case s_body_identity_eof: - /* Use of CALLBACK_NOTIFY() here would erroneously return 1 byte read if - * we got paused. - */ - CALLBACK_NOTIFY_NOADVANCE(message_complete); - return 0; - - case s_dead: - case s_start_req_or_res: - case s_start_res: - case s_start_req: - return 0; - - default: - SET_ERRNO(HPE_INVALID_EOF_STATE); - return 1; - } - } - - - if (parser->state == s_header_field) - header_field_mark = data; - if (parser->state == s_header_value) - header_value_mark = data; - switch (parser->state) { - case s_req_path: - case s_req_schema: - case s_req_schema_slash: - case s_req_schema_slash_slash: - case s_req_server_start: - case s_req_server: - case s_req_server_with_at: - case s_req_query_string_start: - case s_req_query_string: - case s_req_fragment_start: - case s_req_fragment: - url_mark = data; - break; - } - - for (p=data; p != data + len; p++) { - ch = *p; - - if (PARSING_HEADER(parser->state)) { - ++parser->nread; - /* Buffer overflow attack */ - if (parser->nread > HTTP_MAX_HEADER_SIZE) { - SET_ERRNO(HPE_HEADER_OVERFLOW); - goto error; - } - } - - reexecute_byte: - switch (parser->state) { - - case s_dead: - /* this state is used after a 'Connection: close' message - * the parser will error out if it reads another message - */ - if (ch == CR || ch == LF) - break; - - SET_ERRNO(HPE_CLOSED_CONNECTION); - goto error; - - case s_start_req_or_res: - { - if (ch == CR || ch == LF) - break; - parser->flags = 0; - parser->content_length = ULLONG_MAX; - - if (ch == 'H') { - parser->state = s_res_or_resp_H; - - CALLBACK_NOTIFY(message_begin); - } else { - parser->type = HTTP_REQUEST; - parser->state = s_start_req; - goto reexecute_byte; - } - - break; - } - - case s_res_or_resp_H: - if (ch == 'T') { - parser->type = HTTP_RESPONSE; - parser->state = s_res_HT; - } else { - if (ch != 'E') { - SET_ERRNO(HPE_INVALID_CONSTANT); - goto error; - } - - parser->type = HTTP_REQUEST; - parser->method = HTTP_HEAD; - parser->index = 2; - parser->state = s_req_method; - } - break; - - case s_start_res: - { - parser->flags = 0; - parser->content_length = ULLONG_MAX; - - switch (ch) { - case 'H': - parser->state = s_res_H; - break; - - case CR: - case LF: - break; - - default: - SET_ERRNO(HPE_INVALID_CONSTANT); - goto error; - } - - CALLBACK_NOTIFY(message_begin); - break; - } - - case s_res_H: - STRICT_CHECK(ch != 'T'); - parser->state = s_res_HT; - break; - - case s_res_HT: - STRICT_CHECK(ch != 'T'); - parser->state = s_res_HTT; - break; - - case s_res_HTT: - STRICT_CHECK(ch != 'P'); - parser->state = s_res_HTTP; - break; - - case s_res_HTTP: - STRICT_CHECK(ch != '/'); - parser->state = s_res_first_http_major; - break; - - case s_res_first_http_major: - if (ch < '0' || ch > '9') { - SET_ERRNO(HPE_INVALID_VERSION); - goto error; - } - - parser->http_major = ch - '0'; - parser->state = s_res_http_major; - break; - - /* major HTTP version or dot */ - case s_res_http_major: - { - if (ch == '.') { - parser->state = s_res_first_http_minor; - break; - } - - if (!IS_NUM(ch)) { - SET_ERRNO(HPE_INVALID_VERSION); - goto error; - } - - parser->http_major *= 10; - parser->http_major += ch - '0'; - - if (parser->http_major > 999) { - SET_ERRNO(HPE_INVALID_VERSION); - goto error; - } - - break; - } - - /* first digit of minor HTTP version */ - case s_res_first_http_minor: - if (!IS_NUM(ch)) { - SET_ERRNO(HPE_INVALID_VERSION); - goto error; - } - - parser->http_minor = ch - '0'; - parser->state = s_res_http_minor; - break; - - /* minor HTTP version or end of request line */ - case s_res_http_minor: - { - if (ch == ' ') { - parser->state = s_res_first_status_code; - break; - } - - if (!IS_NUM(ch)) { - SET_ERRNO(HPE_INVALID_VERSION); - goto error; - } - - parser->http_minor *= 10; - parser->http_minor += ch - '0'; - - if (parser->http_minor > 999) { - SET_ERRNO(HPE_INVALID_VERSION); - goto error; - } - - break; - } - - case s_res_first_status_code: - { - if (!IS_NUM(ch)) { - if (ch == ' ') { - break; - } - - SET_ERRNO(HPE_INVALID_STATUS); - goto error; - } - parser->status_code = ch - '0'; - parser->state = s_res_status_code; - break; - } - - case s_res_status_code: - { - if (!IS_NUM(ch)) { - switch (ch) { - case ' ': - parser->state = s_res_status; - break; - case CR: - parser->state = s_res_line_almost_done; - break; - case LF: - parser->state = s_header_field_start; - break; - default: - SET_ERRNO(HPE_INVALID_STATUS); - goto error; - } - break; - } - - parser->status_code *= 10; - parser->status_code += ch - '0'; - - if (parser->status_code > 999) { - SET_ERRNO(HPE_INVALID_STATUS); - goto error; - } - - break; - } - - case s_res_status: - /* the human readable status. e.g. "NOT FOUND" - * we are not humans so just ignore this */ - if (ch == CR) { - parser->state = s_res_line_almost_done; - break; - } - - if (ch == LF) { - parser->state = s_header_field_start; - break; - } - break; - - case s_res_line_almost_done: - STRICT_CHECK(ch != LF); - parser->state = s_header_field_start; - break; - - case s_start_req: - { - if (ch == CR || ch == LF) - break; - parser->flags = 0; - parser->content_length = ULLONG_MAX; - - if (!IS_ALPHA(ch)) { - SET_ERRNO(HPE_INVALID_METHOD); - goto error; - } - - parser->method = (enum http_method) 0; - parser->index = 1; - switch (ch) { - case 'C': parser->method = HTTP_CONNECT; /* or COPY, CHECKOUT */ break; - case 'D': parser->method = HTTP_DELETE; break; - case 'G': parser->method = HTTP_GET; break; - case 'H': parser->method = HTTP_HEAD; break; - case 'L': parser->method = HTTP_LOCK; break; - case 'M': parser->method = HTTP_MKCOL; /* or MOVE, MKACTIVITY, MERGE, M-SEARCH */ break; - case 'N': parser->method = HTTP_NOTIFY; break; - case 'O': parser->method = HTTP_OPTIONS; break; - case 'P': parser->method = HTTP_POST; - /* or PROPFIND|PROPPATCH|PUT|PATCH|PURGE */ - break; - case 'R': parser->method = HTTP_REPORT; break; - case 'S': parser->method = HTTP_SUBSCRIBE; /* or SEARCH */ break; - case 'T': parser->method = HTTP_TRACE; break; - case 'U': parser->method = HTTP_UNLOCK; /* or UNSUBSCRIBE */ break; - default: - SET_ERRNO(HPE_INVALID_METHOD); - goto error; - } - parser->state = s_req_method; - - CALLBACK_NOTIFY(message_begin); - - break; - } - - case s_req_method: - { - const char *matcher; - if (ch == '\0') { - SET_ERRNO(HPE_INVALID_METHOD); - goto error; - } - - matcher = method_strings[parser->method]; - if (ch == ' ' && matcher[parser->index] == '\0') { - parser->state = s_req_spaces_before_url; - } else if (ch == matcher[parser->index]) { - ; /* nada */ - } else if (parser->method == HTTP_CONNECT) { - if (parser->index == 1 && ch == 'H') { - parser->method = HTTP_CHECKOUT; - } else if (parser->index == 2 && ch == 'P') { - parser->method = HTTP_COPY; - } else { - goto error; - } - } else if (parser->method == HTTP_MKCOL) { - if (parser->index == 1 && ch == 'O') { - parser->method = HTTP_MOVE; - } else if (parser->index == 1 && ch == 'E') { - parser->method = HTTP_MERGE; - } else if (parser->index == 1 && ch == '-') { - parser->method = HTTP_MSEARCH; - } else if (parser->index == 2 && ch == 'A') { - parser->method = HTTP_MKACTIVITY; - } else { - goto error; - } - } else if (parser->method == HTTP_SUBSCRIBE) { - if (parser->index == 1 && ch == 'E') { - parser->method = HTTP_SEARCH; - } else { - goto error; - } - } else if (parser->index == 1 && parser->method == HTTP_POST) { - if (ch == 'R') { - parser->method = HTTP_PROPFIND; /* or HTTP_PROPPATCH */ - } else if (ch == 'U') { - parser->method = HTTP_PUT; /* or HTTP_PURGE */ - } else if (ch == 'A') { - parser->method = HTTP_PATCH; - } else { - goto error; - } - } else if (parser->index == 2) { - if (parser->method == HTTP_PUT) { - if (ch == 'R') parser->method = HTTP_PURGE; - } else if (parser->method == HTTP_UNLOCK) { - if (ch == 'S') parser->method = HTTP_UNSUBSCRIBE; - } - } else if (parser->index == 4 && parser->method == HTTP_PROPFIND && ch == 'P') { - parser->method = HTTP_PROPPATCH; - } else { - SET_ERRNO(HPE_INVALID_METHOD); - goto error; - } - - ++parser->index; - break; - } - - case s_req_spaces_before_url: - { - if (ch == ' ') break; - - MARK(url); - if (parser->method == HTTP_CONNECT) { - parser->state = s_req_server_start; - } - - parser->state = parse_url_char((enum state)parser->state, ch); - if (parser->state == s_dead) { - SET_ERRNO(HPE_INVALID_URL); - goto error; - } - - break; - } - - case s_req_schema: - case s_req_schema_slash: - case s_req_schema_slash_slash: - case s_req_server_start: - { - switch (ch) { - /* No whitespace allowed here */ - case ' ': - case CR: - case LF: - SET_ERRNO(HPE_INVALID_URL); - goto error; - default: - parser->state = parse_url_char((enum state)parser->state, ch); - if (parser->state == s_dead) { - SET_ERRNO(HPE_INVALID_URL); - goto error; - } - } - - break; - } - - case s_req_server: - case s_req_server_with_at: - case s_req_path: - case s_req_query_string_start: - case s_req_query_string: - case s_req_fragment_start: - case s_req_fragment: - { - switch (ch) { - case ' ': - parser->state = s_req_http_start; - CALLBACK_DATA(url); - break; - case CR: - case LF: - parser->http_major = 0; - parser->http_minor = 9; - parser->state = (ch == CR) ? - s_req_line_almost_done : - s_header_field_start; - CALLBACK_DATA(url); - break; - default: - parser->state = parse_url_char((enum state)parser->state, ch); - if (parser->state == s_dead) { - SET_ERRNO(HPE_INVALID_URL); - goto error; - } - } - break; - } - - case s_req_http_start: - switch (ch) { - case 'H': - parser->state = s_req_http_H; - break; - case ' ': - break; - default: - SET_ERRNO(HPE_INVALID_CONSTANT); - goto error; - } - break; - - case s_req_http_H: - STRICT_CHECK(ch != 'T'); - parser->state = s_req_http_HT; - break; - - case s_req_http_HT: - STRICT_CHECK(ch != 'T'); - parser->state = s_req_http_HTT; - break; - - case s_req_http_HTT: - STRICT_CHECK(ch != 'P'); - parser->state = s_req_http_HTTP; - break; - - case s_req_http_HTTP: - STRICT_CHECK(ch != '/'); - parser->state = s_req_first_http_major; - break; - - /* first digit of major HTTP version */ - case s_req_first_http_major: - if (ch < '1' || ch > '9') { - SET_ERRNO(HPE_INVALID_VERSION); - goto error; - } - - parser->http_major = ch - '0'; - parser->state = s_req_http_major; - break; - - /* major HTTP version or dot */ - case s_req_http_major: - { - if (ch == '.') { - parser->state = s_req_first_http_minor; - break; - } - - if (!IS_NUM(ch)) { - SET_ERRNO(HPE_INVALID_VERSION); - goto error; - } - - parser->http_major *= 10; - parser->http_major += ch - '0'; - - if (parser->http_major > 999) { - SET_ERRNO(HPE_INVALID_VERSION); - goto error; - } - - break; - } - - /* first digit of minor HTTP version */ - case s_req_first_http_minor: - if (!IS_NUM(ch)) { - SET_ERRNO(HPE_INVALID_VERSION); - goto error; - } - - parser->http_minor = ch - '0'; - parser->state = s_req_http_minor; - break; - - /* minor HTTP version or end of request line */ - case s_req_http_minor: - { - if (ch == CR) { - parser->state = s_req_line_almost_done; - break; - } - - if (ch == LF) { - parser->state = s_header_field_start; - break; - } - - /* XXX allow spaces after digit? */ - - if (!IS_NUM(ch)) { - SET_ERRNO(HPE_INVALID_VERSION); - goto error; - } - - parser->http_minor *= 10; - parser->http_minor += ch - '0'; - - if (parser->http_minor > 999) { - SET_ERRNO(HPE_INVALID_VERSION); - goto error; - } - - break; - } - - /* end of request line */ - case s_req_line_almost_done: - { - if (ch != LF) { - SET_ERRNO(HPE_LF_EXPECTED); - goto error; - } - - parser->state = s_header_field_start; - break; - } - - case s_header_field_start: - { - if (ch == CR) { - parser->state = s_headers_almost_done; - break; - } - - if (ch == LF) { - /* they might be just sending \n instead of \r\n so this would be - * the second \n to denote the end of headers*/ - parser->state = s_headers_almost_done; - goto reexecute_byte; - } - - c = TOKEN(ch); - - if (!c) { - SET_ERRNO(HPE_INVALID_HEADER_TOKEN); - goto error; - } - - MARK(header_field); - - parser->index = 0; - parser->state = s_header_field; - - switch (c) { - case 'c': - parser->header_state = h_C; - break; - - case 'p': - parser->header_state = h_matching_proxy_connection; - break; - - case 't': - parser->header_state = h_matching_transfer_encoding; - break; - - case 'u': - parser->header_state = h_matching_upgrade; - break; - - default: - parser->header_state = h_general; - break; - } - break; - } - - case s_header_field: - { - c = TOKEN(ch); - - if (c) { - switch (parser->header_state) { - case h_general: - break; - - case h_C: - parser->index++; - parser->header_state = (c == 'o' ? h_CO : h_general); - break; - - case h_CO: - parser->index++; - parser->header_state = (c == 'n' ? h_CON : h_general); - break; - - case h_CON: - parser->index++; - switch (c) { - case 'n': - parser->header_state = h_matching_connection; - break; - case 't': - parser->header_state = h_matching_content_length; - break; - default: - parser->header_state = h_general; - break; - } - break; - - /* connection */ - - case h_matching_connection: - parser->index++; - if (parser->index > sizeof(CONNECTION)-1 - || c != CONNECTION[parser->index]) { - parser->header_state = h_general; - } else if (parser->index == sizeof(CONNECTION)-2) { - parser->header_state = h_connection; - } - break; - - /* proxy-connection */ - - case h_matching_proxy_connection: - parser->index++; - if (parser->index > sizeof(PROXY_CONNECTION)-1 - || c != PROXY_CONNECTION[parser->index]) { - parser->header_state = h_general; - } else if (parser->index == sizeof(PROXY_CONNECTION)-2) { - parser->header_state = h_connection; - } - break; - - /* content-length */ - - case h_matching_content_length: - parser->index++; - if (parser->index > sizeof(CONTENT_LENGTH)-1 - || c != CONTENT_LENGTH[parser->index]) { - parser->header_state = h_general; - } else if (parser->index == sizeof(CONTENT_LENGTH)-2) { - parser->header_state = h_content_length; - } - break; - - /* transfer-encoding */ - - case h_matching_transfer_encoding: - parser->index++; - if (parser->index > sizeof(TRANSFER_ENCODING)-1 - || c != TRANSFER_ENCODING[parser->index]) { - parser->header_state = h_general; - } else if (parser->index == sizeof(TRANSFER_ENCODING)-2) { - parser->header_state = h_transfer_encoding; - } - break; - - /* upgrade */ - - case h_matching_upgrade: - parser->index++; - if (parser->index > sizeof(UPGRADE)-1 - || c != UPGRADE[parser->index]) { - parser->header_state = h_general; - } else if (parser->index == sizeof(UPGRADE)-2) { - parser->header_state = h_upgrade; - } - break; - - case h_connection: - case h_content_length: - case h_transfer_encoding: - case h_upgrade: - if (ch != ' ') parser->header_state = h_general; - break; - - default: - assert(0 && "Unknown header_state"); - break; - } - break; - } - - if (ch == ':') { - parser->state = s_header_value_start; - CALLBACK_DATA(header_field); - break; - } - - if (ch == CR) { - parser->state = s_header_almost_done; - CALLBACK_DATA(header_field); - break; - } - - if (ch == LF) { - parser->state = s_header_field_start; - CALLBACK_DATA(header_field); - break; - } - - SET_ERRNO(HPE_INVALID_HEADER_TOKEN); - goto error; - } - - case s_header_value_start: - { - if (ch == ' ' || ch == '\t') break; - - MARK(header_value); - - parser->state = s_header_value; - parser->index = 0; - - if (ch == CR) { - parser->header_state = h_general; - parser->state = s_header_almost_done; - CALLBACK_DATA(header_value); - break; - } - - if (ch == LF) { - parser->state = s_header_field_start; - CALLBACK_DATA(header_value); - break; - } - - c = LOWER(ch); - - switch (parser->header_state) { - case h_upgrade: - parser->flags |= F_UPGRADE; - parser->header_state = h_general; - break; - - case h_transfer_encoding: - /* looking for 'Transfer-Encoding: chunked' */ - if ('c' == c) { - parser->header_state = h_matching_transfer_encoding_chunked; - } else { - parser->header_state = h_general; - } - break; - - case h_content_length: - if (!IS_NUM(ch)) { - SET_ERRNO(HPE_INVALID_CONTENT_LENGTH); - goto error; - } - - parser->content_length = ch - '0'; - break; - - case h_connection: - /* looking for 'Connection: keep-alive' */ - if (c == 'k') { - parser->header_state = h_matching_connection_keep_alive; - /* looking for 'Connection: close' */ - } else if (c == 'c') { - parser->header_state = h_matching_connection_close; - } else { - parser->header_state = h_general; - } - break; - - default: - parser->header_state = h_general; - break; - } - break; - } - - case s_header_value: - { - - if (ch == CR) { - parser->state = s_header_almost_done; - CALLBACK_DATA(header_value); - break; - } - - if (ch == LF) { - parser->state = s_header_almost_done; - CALLBACK_DATA_NOADVANCE(header_value); - goto reexecute_byte; - } - - c = LOWER(ch); - - switch (parser->header_state) { - case h_general: - break; - - case h_connection: - case h_transfer_encoding: - assert(0 && "Shouldn't get here."); - break; - - case h_content_length: - { - uint64_t t; - - if (ch == ' ') break; - - if (!IS_NUM(ch)) { - SET_ERRNO(HPE_INVALID_CONTENT_LENGTH); - goto error; - } - - t = parser->content_length; - t *= 10; - t += ch - '0'; - - /* Overflow? */ - if (t < parser->content_length || t == ULLONG_MAX) { - SET_ERRNO(HPE_INVALID_CONTENT_LENGTH); - goto error; - } - - parser->content_length = t; - break; - } - - /* Transfer-Encoding: chunked */ - case h_matching_transfer_encoding_chunked: - parser->index++; - if (parser->index > sizeof(CHUNKED)-1 - || c != CHUNKED[parser->index]) { - parser->header_state = h_general; - } else if (parser->index == sizeof(CHUNKED)-2) { - parser->header_state = h_transfer_encoding_chunked; - } - break; - - /* looking for 'Connection: keep-alive' */ - case h_matching_connection_keep_alive: - parser->index++; - if (parser->index > sizeof(KEEP_ALIVE)-1 - || c != KEEP_ALIVE[parser->index]) { - parser->header_state = h_general; - } else if (parser->index == sizeof(KEEP_ALIVE)-2) { - parser->header_state = h_connection_keep_alive; - } - break; - - /* looking for 'Connection: close' */ - case h_matching_connection_close: - parser->index++; - if (parser->index > sizeof(CLOSE)-1 || c != CLOSE[parser->index]) { - parser->header_state = h_general; - } else if (parser->index == sizeof(CLOSE)-2) { - parser->header_state = h_connection_close; - } - break; - - case h_transfer_encoding_chunked: - case h_connection_keep_alive: - case h_connection_close: - if (ch != ' ') parser->header_state = h_general; - break; - - default: - parser->state = s_header_value; - parser->header_state = h_general; - break; - } - break; - } - - case s_header_almost_done: - { - STRICT_CHECK(ch != LF); - - parser->state = s_header_value_lws; - - switch (parser->header_state) { - case h_connection_keep_alive: - parser->flags |= F_CONNECTION_KEEP_ALIVE; - break; - case h_connection_close: - parser->flags |= F_CONNECTION_CLOSE; - break; - case h_transfer_encoding_chunked: - parser->flags |= F_CHUNKED; - break; - default: - break; - } - - break; - } - - case s_header_value_lws: - { - if (ch == ' ' || ch == '\t') - parser->state = s_header_value_start; - else - { - parser->state = s_header_field_start; - goto reexecute_byte; - } - break; - } - - case s_headers_almost_done: - { - STRICT_CHECK(ch != LF); - - if (parser->flags & F_TRAILING) { - /* End of a chunked request */ - parser->state = NEW_MESSAGE(); - CALLBACK_NOTIFY(message_complete); - break; - } - - parser->state = s_headers_done; - - /* Set this here so that on_headers_complete() callbacks can see it */ - parser->upgrade = - (parser->flags & F_UPGRADE || parser->method == HTTP_CONNECT); - - /* Here we call the headers_complete callback. This is somewhat - * different than other callbacks because if the user returns 1, we - * will interpret that as saying that this message has no body. This - * is needed for the annoying case of recieving a response to a HEAD - * request. - * - * We'd like to use CALLBACK_NOTIFY_NOADVANCE() here but we cannot, so - * we have to simulate it by handling a change in errno below. - */ - if (settings->on_headers_complete) { - switch (settings->on_headers_complete(parser)) { - case 0: - break; - - case 1: - parser->flags |= F_SKIPBODY; - break; - - default: - SET_ERRNO(HPE_CB_headers_complete); - return p - data; /* Error */ - } - } - - if (HTTP_PARSER_ERRNO(parser) != HPE_OK) { - return p - data; - } - - goto reexecute_byte; - } - - case s_headers_done: - { - STRICT_CHECK(ch != LF); - - parser->nread = 0; - - /* Exit, the rest of the connect is in a different protocol. */ - if (parser->upgrade) { - parser->state = NEW_MESSAGE(); - CALLBACK_NOTIFY(message_complete); - return (p - data) + 1; - } - - if (parser->flags & F_SKIPBODY) { - parser->state = NEW_MESSAGE(); - CALLBACK_NOTIFY(message_complete); - } else if (parser->flags & F_CHUNKED) { - /* chunked encoding - ignore Content-Length header */ - parser->state = s_chunk_size_start; - } else { - if (parser->content_length == 0) { - /* Content-Length header given but zero: Content-Length: 0\r\n */ - parser->state = NEW_MESSAGE(); - CALLBACK_NOTIFY(message_complete); - } else if (parser->content_length != ULLONG_MAX) { - /* Content-Length header given and non-zero */ - parser->state = s_body_identity; - } else { - if (parser->type == HTTP_REQUEST || - !http_message_needs_eof(parser)) { - /* Assume content-length 0 - read the next */ - parser->state = NEW_MESSAGE(); - CALLBACK_NOTIFY(message_complete); - } else { - /* Read body until EOF */ - parser->state = s_body_identity_eof; - } - } - } - - break; - } - - case s_body_identity: - { - uint64_t to_read = MIN(parser->content_length, - (uint64_t) ((data + len) - p)); - - assert(parser->content_length != 0 - && parser->content_length != ULLONG_MAX); - - /* The difference between advancing content_length and p is because - * the latter will automaticaly advance on the next loop iteration. - * Further, if content_length ends up at 0, we want to see the last - * byte again for our message complete callback. - */ - MARK(body); - parser->content_length -= to_read; - p += to_read - 1; - - if (parser->content_length == 0) { - parser->state = s_message_done; - - /* Mimic CALLBACK_DATA_NOADVANCE() but with one extra byte. - * - * The alternative to doing this is to wait for the next byte to - * trigger the data callback, just as in every other case. The - * problem with this is that this makes it difficult for the test - * harness to distinguish between complete-on-EOF and - * complete-on-length. It's not clear that this distinction is - * important for applications, but let's keep it for now. - */ - CALLBACK_DATA_(body, p - body_mark + 1, p - data); - goto reexecute_byte; - } - - break; - } - - /* read until EOF */ - case s_body_identity_eof: - MARK(body); - p = data + len - 1; - - break; - - case s_message_done: - parser->state = NEW_MESSAGE(); - CALLBACK_NOTIFY(message_complete); - break; - - case s_chunk_size_start: - { - assert(parser->nread == 1); - assert(parser->flags & F_CHUNKED); - - unhex_val = unhex[(unsigned char)ch]; - if (unhex_val == -1) { - SET_ERRNO(HPE_INVALID_CHUNK_SIZE); - goto error; - } - - parser->content_length = unhex_val; - parser->state = s_chunk_size; - break; - } - - case s_chunk_size: - { - uint64_t t; - - assert(parser->flags & F_CHUNKED); - - if (ch == CR) { - parser->state = s_chunk_size_almost_done; - break; - } - - unhex_val = unhex[(unsigned char)ch]; - - if (unhex_val == -1) { - if (ch == ';' || ch == ' ') { - parser->state = s_chunk_parameters; - break; - } - - SET_ERRNO(HPE_INVALID_CHUNK_SIZE); - goto error; - } - - t = parser->content_length; - t *= 16; - t += unhex_val; - - /* Overflow? */ - if (t < parser->content_length || t == ULLONG_MAX) { - SET_ERRNO(HPE_INVALID_CONTENT_LENGTH); - goto error; - } - - parser->content_length = t; - break; - } - - case s_chunk_parameters: - { - assert(parser->flags & F_CHUNKED); - /* just ignore this. TODO check for overflow */ - if (ch == CR) { - parser->state = s_chunk_size_almost_done; - break; - } - break; - } - - case s_chunk_size_almost_done: - { - assert(parser->flags & F_CHUNKED); - STRICT_CHECK(ch != LF); - - parser->nread = 0; - - if (parser->content_length == 0) { - parser->flags |= F_TRAILING; - parser->state = s_header_field_start; - } else { - parser->state = s_chunk_data; - } - break; - } - - case s_chunk_data: - { - uint64_t to_read = MIN(parser->content_length, - (uint64_t) ((data + len) - p)); - - assert(parser->flags & F_CHUNKED); - assert(parser->content_length != 0 - && parser->content_length != ULLONG_MAX); - - /* See the explanation in s_body_identity for why the content - * length and data pointers are managed this way. - */ - MARK(body); - parser->content_length -= to_read; - p += to_read - 1; - - if (parser->content_length == 0) { - parser->state = s_chunk_data_almost_done; - } - - break; - } - - case s_chunk_data_almost_done: - assert(parser->flags & F_CHUNKED); - assert(parser->content_length == 0); - STRICT_CHECK(ch != CR); - parser->state = s_chunk_data_done; - CALLBACK_DATA(body); - break; - - case s_chunk_data_done: - assert(parser->flags & F_CHUNKED); - STRICT_CHECK(ch != LF); - parser->nread = 0; - parser->state = s_chunk_size_start; - break; - - default: - assert(0 && "unhandled state"); - SET_ERRNO(HPE_INVALID_INTERNAL_STATE); - goto error; - } - } - - /* Run callbacks for any marks that we have leftover after we ran our of - * bytes. There should be at most one of these set, so it's OK to invoke - * them in series (unset marks will not result in callbacks). - * - * We use the NOADVANCE() variety of callbacks here because 'p' has already - * overflowed 'data' and this allows us to correct for the off-by-one that - * we'd otherwise have (since CALLBACK_DATA() is meant to be run with a 'p' - * value that's in-bounds). - */ - - assert(((header_field_mark ? 1 : 0) + - (header_value_mark ? 1 : 0) + - (url_mark ? 1 : 0) + - (body_mark ? 1 : 0)) <= 1); - - CALLBACK_DATA_NOADVANCE(header_field); - CALLBACK_DATA_NOADVANCE(header_value); - CALLBACK_DATA_NOADVANCE(url); - CALLBACK_DATA_NOADVANCE(body); - - return len; - -error: - if (HTTP_PARSER_ERRNO(parser) == HPE_OK) { - SET_ERRNO(HPE_UNKNOWN); - } - - return (p - data); -} - - -/* Does the parser need to see an EOF to find the end of the message? */ -int -http_message_needs_eof (const http_parser *parser) -{ - if (parser->type == HTTP_REQUEST) { - return 0; - } - - /* See RFC 2616 section 4.4 */ - if (parser->status_code / 100 == 1 || /* 1xx e.g. Continue */ - parser->status_code == 204 || /* No Content */ - parser->status_code == 304 || /* Not Modified */ - parser->flags & F_SKIPBODY) { /* response to a HEAD request */ - return 0; - } - - if ((parser->flags & F_CHUNKED) || parser->content_length != ULLONG_MAX) { - return 0; - } - - return 1; -} - - -int -http_should_keep_alive (const http_parser *parser) -{ - if (parser->http_major > 0 && parser->http_minor > 0) { - /* HTTP/1.1 */ - if (parser->flags & F_CONNECTION_CLOSE) { - return 0; - } - } else { - /* HTTP/1.0 or earlier */ - if (!(parser->flags & F_CONNECTION_KEEP_ALIVE)) { - return 0; - } - } - - return !http_message_needs_eof(parser); -} - - -const char * -http_method_str (enum http_method m) -{ - return ELEM_AT(method_strings, m, ""); -} - - -void -http_parser_init (http_parser *parser, enum http_parser_type t) -{ - void *data = parser->data; /* preserve application data */ - memset(parser, 0, sizeof(*parser)); - parser->data = data; - parser->type = t; - parser->state = (t == HTTP_REQUEST ? s_start_req : (t == HTTP_RESPONSE ? s_start_res : s_start_req_or_res)); - parser->http_errno = HPE_OK; -} - -const char * -http_errno_name(enum http_errno err) { - assert(err < (sizeof(http_strerror_tab)/sizeof(http_strerror_tab[0]))); - return http_strerror_tab[err].name; -} - -const char * -http_errno_description(enum http_errno err) { - assert(err < (sizeof(http_strerror_tab)/sizeof(http_strerror_tab[0]))); - return http_strerror_tab[err].description; -} - -static enum http_host_state -http_parse_host_char(enum http_host_state s, const char ch) { - switch(s) { - case s_http_userinfo: - case s_http_userinfo_start: - if (ch == '@') { - return s_http_host_start; - } - - if (IS_USERINFO_CHAR(ch)) { - return s_http_userinfo; - } - break; - - case s_http_host_start: - if (ch == '[') { - return s_http_host_v6_start; - } - - if (IS_HOST_CHAR(ch)) { - return s_http_host; - } - - break; - - case s_http_host: - if (IS_HOST_CHAR(ch)) { - return s_http_host; - } - - /* FALLTHROUGH */ - case s_http_host_v6_end: - if (ch == ':') { - return s_http_host_port_start; - } - - break; - - case s_http_host_v6: - if (ch == ']') { - return s_http_host_v6_end; - } - - /* FALLTHROUGH */ - case s_http_host_v6_start: - if (IS_HEX(ch) || ch == ':') { - return s_http_host_v6; - } - - break; - - case s_http_host_port: - case s_http_host_port_start: - if (IS_NUM(ch)) { - return s_http_host_port; - } - - break; - - default: - break; - } - return s_http_host_dead; -} - -static int -http_parse_host(const char * buf, struct http_parser_url *u, int found_at) { - enum http_host_state s; - - const char *p; - size_t buflen = u->field_data[UF_HOST].off + u->field_data[UF_HOST].len; - - u->field_data[UF_HOST].len = 0; - - s = found_at ? s_http_userinfo_start : s_http_host_start; - - for (p = buf + u->field_data[UF_HOST].off; p < buf + buflen; p++) { - enum http_host_state new_s = http_parse_host_char(s, *p); - - if (new_s == s_http_host_dead) { - return 1; - } - - switch(new_s) { - case s_http_host: - if (s != s_http_host) { - u->field_data[UF_HOST].off = p - buf; - } - u->field_data[UF_HOST].len++; - break; - - case s_http_host_v6: - if (s != s_http_host_v6) { - u->field_data[UF_HOST].off = p - buf; - } - u->field_data[UF_HOST].len++; - break; - - case s_http_host_port: - if (s != s_http_host_port) { - u->field_data[UF_PORT].off = p - buf; - u->field_data[UF_PORT].len = 0; - u->field_set |= (1 << UF_PORT); - } - u->field_data[UF_PORT].len++; - break; - - case s_http_userinfo: - if (s != s_http_userinfo) { - u->field_data[UF_USERINFO].off = p - buf ; - u->field_data[UF_USERINFO].len = 0; - u->field_set |= (1 << UF_USERINFO); - } - u->field_data[UF_USERINFO].len++; - break; - - default: - break; - } - s = new_s; - } - - /* Make sure we don't end somewhere unexpected */ - switch (s) { - case s_http_host_start: - case s_http_host_v6_start: - case s_http_host_v6: - case s_http_host_port_start: - case s_http_userinfo: - case s_http_userinfo_start: - return 1; - default: - break; - } - - return 0; -} - -int -http_parser_parse_url(const char *buf, size_t buflen, int is_connect, - struct http_parser_url *u) -{ - enum state s; - const char *p; - enum http_parser_url_fields uf, old_uf; - int found_at = 0; - - u->port = u->field_set = 0; - s = is_connect ? s_req_server_start : s_req_spaces_before_url; - uf = old_uf = UF_MAX; - - for (p = buf; p < buf + buflen; p++) { - s = parse_url_char(s, *p); - - /* Figure out the next field that we're operating on */ - switch (s) { - case s_dead: - return 1; - - /* Skip delimeters */ - case s_req_schema_slash: - case s_req_schema_slash_slash: - case s_req_server_start: - case s_req_query_string_start: - case s_req_fragment_start: - continue; - - case s_req_schema: - uf = UF_SCHEMA; - break; - - case s_req_server_with_at: - found_at = 1; - - /* FALLTROUGH */ - case s_req_server: - uf = UF_HOST; - break; - - case s_req_path: - uf = UF_PATH; - break; - - case s_req_query_string: - uf = UF_QUERY; - break; - - case s_req_fragment: - uf = UF_FRAGMENT; - break; - - default: - assert(!"Unexpected state"); - return 1; - } - - /* Nothing's changed; soldier on */ - if (uf == old_uf) { - u->field_data[uf].len++; - continue; - } - - u->field_data[uf].off = p - buf; - u->field_data[uf].len = 1; - - u->field_set |= (1 << uf); - old_uf = uf; - } - - /* host must be present if there is a schema */ - /* parsing http:///toto will fail */ - if ((u->field_set & ((1 << UF_SCHEMA) | (1 << UF_HOST))) != 0) { - if (http_parse_host(buf, u, found_at) != 0) { - return 1; - } - } - - /* CONNECT requests can only contain "hostname:port" */ - if (is_connect && u->field_set != ((1 << UF_HOST)|(1 << UF_PORT))) { - return 1; - } - - if (u->field_set & (1 << UF_PORT)) { - /* Don't bother with endp; we've already validated the string */ - unsigned long v = strtoul(buf + u->field_data[UF_PORT].off, NULL, 10); - - /* Ports have a max value of 2^16 */ - if (v > 0xffff) { - return 1; - } - - u->port = (uint16_t) v; - } - - return 0; -} - -void -http_parser_pause(http_parser *parser, int paused) { - /* Users should only be pausing/unpausing a parser that is not in an error - * state. In non-debug builds, there's not much that we can do about this - * other than ignore it. - */ - if (HTTP_PARSER_ERRNO(parser) == HPE_OK || - HTTP_PARSER_ERRNO(parser) == HPE_PAUSED) { - SET_ERRNO((paused) ? HPE_PAUSED : HPE_OK); - } else { - assert(0 && "Attempting to pause parser in error state"); - } -} - -int -http_body_is_final(const struct http_parser *parser) { - return parser->state == s_message_done; -} diff --git a/deps/http-parser/http_parser.h b/deps/http-parser/http_parser.h deleted file mode 100644 index 67e1d95dd..000000000 --- a/deps/http-parser/http_parser.h +++ /dev/null @@ -1,305 +0,0 @@ -/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to - * deal in the Software without restriction, including without limitation the - * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or - * sell copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - */ -#ifndef http_parser_h -#define http_parser_h -#ifdef __cplusplus -extern "C" { -#endif - -#define HTTP_PARSER_VERSION_MAJOR 2 -#define HTTP_PARSER_VERSION_MINOR 0 - -#include -#if defined(_WIN32) && !defined(__MINGW32__) && (!defined(_MSC_VER) || _MSC_VER<1600) -#include -typedef __int8 int8_t; -typedef unsigned __int8 uint8_t; -typedef __int16 int16_t; -typedef unsigned __int16 uint16_t; -typedef __int32 int32_t; -typedef unsigned __int32 uint32_t; -typedef __int64 int64_t; -typedef unsigned __int64 uint64_t; -typedef SIZE_T size_t; -typedef SSIZE_T ssize_t; -#elif defined(__sun) || defined(__sun__) -#include -#else -#include -#endif - -/* Compile with -DHTTP_PARSER_STRICT=0 to make less checks, but run - * faster - */ -#ifndef HTTP_PARSER_STRICT -# define HTTP_PARSER_STRICT 1 -#endif - -/* Maximium header size allowed */ -#define HTTP_MAX_HEADER_SIZE (80*1024) - - -typedef struct http_parser http_parser; -typedef struct http_parser_settings http_parser_settings; - - -/* Callbacks should return non-zero to indicate an error. The parser will - * then halt execution. - * - * The one exception is on_headers_complete. In a HTTP_RESPONSE parser - * returning '1' from on_headers_complete will tell the parser that it - * should not expect a body. This is used when receiving a response to a - * HEAD request which may contain 'Content-Length' or 'Transfer-Encoding: - * chunked' headers that indicate the presence of a body. - * - * http_data_cb does not return data chunks. It will be call arbitrarally - * many times for each string. E.G. you might get 10 callbacks for "on_url" - * each providing just a few characters more data. - */ -typedef int (*http_data_cb) (http_parser*, const char *at, size_t length); -typedef int (*http_cb) (http_parser*); - - -/* Request Methods */ -#define HTTP_METHOD_MAP(XX) \ - XX(0, DELETE, DELETE) \ - XX(1, GET, GET) \ - XX(2, HEAD, HEAD) \ - XX(3, POST, POST) \ - XX(4, PUT, PUT) \ - /* pathological */ \ - XX(5, CONNECT, CONNECT) \ - XX(6, OPTIONS, OPTIONS) \ - XX(7, TRACE, TRACE) \ - /* webdav */ \ - XX(8, COPY, COPY) \ - XX(9, LOCK, LOCK) \ - XX(10, MKCOL, MKCOL) \ - XX(11, MOVE, MOVE) \ - XX(12, PROPFIND, PROPFIND) \ - XX(13, PROPPATCH, PROPPATCH) \ - XX(14, SEARCH, SEARCH) \ - XX(15, UNLOCK, UNLOCK) \ - /* subversion */ \ - XX(16, REPORT, REPORT) \ - XX(17, MKACTIVITY, MKACTIVITY) \ - XX(18, CHECKOUT, CHECKOUT) \ - XX(19, MERGE, MERGE) \ - /* upnp */ \ - XX(20, MSEARCH, M-SEARCH) \ - XX(21, NOTIFY, NOTIFY) \ - XX(22, SUBSCRIBE, SUBSCRIBE) \ - XX(23, UNSUBSCRIBE, UNSUBSCRIBE) \ - /* RFC-5789 */ \ - XX(24, PATCH, PATCH) \ - XX(25, PURGE, PURGE) \ - -enum http_method - { -#define XX(num, name, string) HTTP_##name = num, - HTTP_METHOD_MAP(XX) -#undef XX - }; - - -enum http_parser_type { HTTP_REQUEST, HTTP_RESPONSE, HTTP_BOTH }; - - -/* Flag values for http_parser.flags field */ -enum flags - { F_CHUNKED = 1 << 0 - , F_CONNECTION_KEEP_ALIVE = 1 << 1 - , F_CONNECTION_CLOSE = 1 << 2 - , F_TRAILING = 1 << 3 - , F_UPGRADE = 1 << 4 - , F_SKIPBODY = 1 << 5 - }; - - -/* Map for errno-related constants - * - * The provided argument should be a macro that takes 2 arguments. - */ -#define HTTP_ERRNO_MAP(XX) \ - /* No error */ \ - XX(OK, "success") \ - \ - /* Callback-related errors */ \ - XX(CB_message_begin, "the on_message_begin callback failed") \ - XX(CB_url, "the on_url callback failed") \ - XX(CB_header_field, "the on_header_field callback failed") \ - XX(CB_header_value, "the on_header_value callback failed") \ - XX(CB_headers_complete, "the on_headers_complete callback failed") \ - XX(CB_body, "the on_body callback failed") \ - XX(CB_message_complete, "the on_message_complete callback failed") \ - \ - /* Parsing-related errors */ \ - XX(INVALID_EOF_STATE, "stream ended at an unexpected time") \ - XX(HEADER_OVERFLOW, \ - "too many header bytes seen; overflow detected") \ - XX(CLOSED_CONNECTION, \ - "data received after completed connection: close message") \ - XX(INVALID_VERSION, "invalid HTTP version") \ - XX(INVALID_STATUS, "invalid HTTP status code") \ - XX(INVALID_METHOD, "invalid HTTP method") \ - XX(INVALID_URL, "invalid URL") \ - XX(INVALID_HOST, "invalid host") \ - XX(INVALID_PORT, "invalid port") \ - XX(INVALID_PATH, "invalid path") \ - XX(INVALID_QUERY_STRING, "invalid query string") \ - XX(INVALID_FRAGMENT, "invalid fragment") \ - XX(LF_EXPECTED, "LF character expected") \ - XX(INVALID_HEADER_TOKEN, "invalid character in header") \ - XX(INVALID_CONTENT_LENGTH, \ - "invalid character in content-length header") \ - XX(INVALID_CHUNK_SIZE, \ - "invalid character in chunk size header") \ - XX(INVALID_CONSTANT, "invalid constant string") \ - XX(INVALID_INTERNAL_STATE, "encountered unexpected internal state")\ - XX(STRICT, "strict mode assertion failed") \ - XX(PAUSED, "parser is paused") \ - XX(UNKNOWN, "an unknown error occurred") - - -/* Define HPE_* values for each errno value above */ -#define HTTP_ERRNO_GEN(n, s) HPE_##n, -enum http_errno { - HTTP_ERRNO_MAP(HTTP_ERRNO_GEN) -}; -#undef HTTP_ERRNO_GEN - - -/* Get an http_errno value from an http_parser */ -#define HTTP_PARSER_ERRNO(p) ((enum http_errno) (p)->http_errno) - - -struct http_parser { - /** PRIVATE **/ - unsigned char type : 2; /* enum http_parser_type */ - unsigned char flags : 6; /* F_* values from 'flags' enum; semi-public */ - unsigned char state; /* enum state from http_parser.c */ - unsigned char header_state; /* enum header_state from http_parser.c */ - unsigned char index; /* index into current matcher */ - - uint32_t nread; /* # bytes read in various scenarios */ - uint64_t content_length; /* # bytes in body (0 if no Content-Length header) */ - - /** READ-ONLY **/ - unsigned short http_major; - unsigned short http_minor; - unsigned short status_code; /* responses only */ - unsigned char method; /* requests only */ - unsigned char http_errno : 7; - - /* 1 = Upgrade header was present and the parser has exited because of that. - * 0 = No upgrade header present. - * Should be checked when http_parser_execute() returns in addition to - * error checking. - */ - unsigned char upgrade : 1; - - /** PUBLIC **/ - void *data; /* A pointer to get hook to the "connection" or "socket" object */ -}; - - -struct http_parser_settings { - http_cb on_message_begin; - http_data_cb on_url; - http_data_cb on_header_field; - http_data_cb on_header_value; - http_cb on_headers_complete; - http_data_cb on_body; - http_cb on_message_complete; -}; - - -enum http_parser_url_fields - { UF_SCHEMA = 0 - , UF_HOST = 1 - , UF_PORT = 2 - , UF_PATH = 3 - , UF_QUERY = 4 - , UF_FRAGMENT = 5 - , UF_USERINFO = 6 - , UF_MAX = 7 - }; - - -/* Result structure for http_parser_parse_url(). - * - * Callers should index into field_data[] with UF_* values iff field_set - * has the relevant (1 << UF_*) bit set. As a courtesy to clients (and - * because we probably have padding left over), we convert any port to - * a uint16_t. - */ -struct http_parser_url { - uint16_t field_set; /* Bitmask of (1 << UF_*) values */ - uint16_t port; /* Converted UF_PORT string */ - - struct { - uint16_t off; /* Offset into buffer in which field starts */ - uint16_t len; /* Length of run in buffer */ - } field_data[UF_MAX]; -}; - - -void http_parser_init(http_parser *parser, enum http_parser_type type); - - -size_t http_parser_execute(http_parser *parser, - const http_parser_settings *settings, - const char *data, - size_t len); - - -/* If http_should_keep_alive() in the on_headers_complete or - * on_message_complete callback returns 0, then this should be - * the last message on the connection. - * If you are the server, respond with the "Connection: close" header. - * If you are the client, close the connection. - */ -int http_should_keep_alive(const http_parser *parser); - -/* Returns a string version of the HTTP method. */ -const char *http_method_str(enum http_method m); - -/* Return a string name of the given error */ -const char *http_errno_name(enum http_errno err); - -/* Return a string description of the given error */ -const char *http_errno_description(enum http_errno err); - -/* Parse a URL; return nonzero on failure */ -int http_parser_parse_url(const char *buf, size_t buflen, - int is_connect, - struct http_parser_url *u); - -/* Pause or un-pause the parser; a nonzero value pauses */ -void http_parser_pause(http_parser *parser, int paused); - -/* Checks if this is the final chunk of the body. */ -int http_body_is_final(const http_parser *parser); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/deps/regex/config.h b/deps/regex/config.h deleted file mode 100644 index 95370690e..000000000 --- a/deps/regex/config.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef _REGEX_CONFIG_H_ -#define _REGEX_CONFIG_H_ - -# define GAWK -# define NO_MBSUPPORT - -#endif diff --git a/deps/regex/regcomp.c b/deps/regex/regcomp.c deleted file mode 100644 index 43bffbc21..000000000 --- a/deps/regex/regcomp.c +++ /dev/null @@ -1,3857 +0,0 @@ -/* Extended regular expression matching and search library. - Copyright (C) 2002-2007,2009,2010 Free Software Foundation, Inc. - This file is part of the GNU C Library. - Contributed by Isamu Hasegawa . - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, write to the Free - Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301 USA. */ - -static reg_errcode_t re_compile_internal (regex_t *preg, const char * pattern, - size_t length, reg_syntax_t syntax); -static void re_compile_fastmap_iter (regex_t *bufp, - const re_dfastate_t *init_state, - char *fastmap); -static reg_errcode_t init_dfa (re_dfa_t *dfa, size_t pat_len); -#ifdef RE_ENABLE_I18N -static void free_charset (re_charset_t *cset); -#endif /* RE_ENABLE_I18N */ -static void free_workarea_compile (regex_t *preg); -static reg_errcode_t create_initial_state (re_dfa_t *dfa); -#ifdef RE_ENABLE_I18N -static void optimize_utf8 (re_dfa_t *dfa); -#endif -static reg_errcode_t analyze (regex_t *preg); -static reg_errcode_t preorder (bin_tree_t *root, - reg_errcode_t (fn (void *, bin_tree_t *)), - void *extra); -static reg_errcode_t postorder (bin_tree_t *root, - reg_errcode_t (fn (void *, bin_tree_t *)), - void *extra); -static reg_errcode_t optimize_subexps (void *extra, bin_tree_t *node); -static reg_errcode_t lower_subexps (void *extra, bin_tree_t *node); -static bin_tree_t *lower_subexp (reg_errcode_t *err, regex_t *preg, - bin_tree_t *node); -static reg_errcode_t calc_first (void *extra, bin_tree_t *node); -static reg_errcode_t calc_next (void *extra, bin_tree_t *node); -static reg_errcode_t link_nfa_nodes (void *extra, bin_tree_t *node); -static int duplicate_node (re_dfa_t *dfa, int org_idx, unsigned int constraint); -static int search_duplicated_node (const re_dfa_t *dfa, int org_node, - unsigned int constraint); -static reg_errcode_t calc_eclosure (re_dfa_t *dfa); -static reg_errcode_t calc_eclosure_iter (re_node_set *new_set, re_dfa_t *dfa, - int node, int root); -static reg_errcode_t calc_inveclosure (re_dfa_t *dfa); -static int fetch_number (re_string_t *input, re_token_t *token, - reg_syntax_t syntax); -static int peek_token (re_token_t *token, re_string_t *input, - reg_syntax_t syntax) internal_function; -static bin_tree_t *parse (re_string_t *regexp, regex_t *preg, - reg_syntax_t syntax, reg_errcode_t *err); -static bin_tree_t *parse_reg_exp (re_string_t *regexp, regex_t *preg, - re_token_t *token, reg_syntax_t syntax, - int nest, reg_errcode_t *err); -static bin_tree_t *parse_branch (re_string_t *regexp, regex_t *preg, - re_token_t *token, reg_syntax_t syntax, - int nest, reg_errcode_t *err); -static bin_tree_t *parse_expression (re_string_t *regexp, regex_t *preg, - re_token_t *token, reg_syntax_t syntax, - int nest, reg_errcode_t *err); -static bin_tree_t *parse_sub_exp (re_string_t *regexp, regex_t *preg, - re_token_t *token, reg_syntax_t syntax, - int nest, reg_errcode_t *err); -static bin_tree_t *parse_dup_op (bin_tree_t *dup_elem, re_string_t *regexp, - re_dfa_t *dfa, re_token_t *token, - reg_syntax_t syntax, reg_errcode_t *err); -static bin_tree_t *parse_bracket_exp (re_string_t *regexp, re_dfa_t *dfa, - re_token_t *token, reg_syntax_t syntax, - reg_errcode_t *err); -static reg_errcode_t parse_bracket_element (bracket_elem_t *elem, - re_string_t *regexp, - re_token_t *token, int token_len, - re_dfa_t *dfa, - reg_syntax_t syntax, - int accept_hyphen); -static reg_errcode_t parse_bracket_symbol (bracket_elem_t *elem, - re_string_t *regexp, - re_token_t *token); -#ifdef RE_ENABLE_I18N -static reg_errcode_t build_equiv_class (bitset_t sbcset, - re_charset_t *mbcset, - int *equiv_class_alloc, - const unsigned char *name); -static reg_errcode_t build_charclass (RE_TRANSLATE_TYPE trans, - bitset_t sbcset, - re_charset_t *mbcset, - int *char_class_alloc, - const char *class_name, - reg_syntax_t syntax); -#else /* not RE_ENABLE_I18N */ -static reg_errcode_t build_equiv_class (bitset_t sbcset, - const unsigned char *name); -static reg_errcode_t build_charclass (RE_TRANSLATE_TYPE trans, - bitset_t sbcset, - const char *class_name, - reg_syntax_t syntax); -#endif /* not RE_ENABLE_I18N */ -static bin_tree_t *build_charclass_op (re_dfa_t *dfa, - RE_TRANSLATE_TYPE trans, - const char *class_name, - const char *extra, - int non_match, reg_errcode_t *err); -static bin_tree_t *create_tree (re_dfa_t *dfa, - bin_tree_t *left, bin_tree_t *right, - re_token_type_t type); -static bin_tree_t *create_token_tree (re_dfa_t *dfa, - bin_tree_t *left, bin_tree_t *right, - const re_token_t *token); -static bin_tree_t *duplicate_tree (const bin_tree_t *src, re_dfa_t *dfa); -static void free_token (re_token_t *node); -static reg_errcode_t free_tree (void *extra, bin_tree_t *node); -static reg_errcode_t mark_opt_subexp (void *extra, bin_tree_t *node); - -/* This table gives an error message for each of the error codes listed - in regex.h. Obviously the order here has to be same as there. - POSIX doesn't require that we do anything for REG_NOERROR, - but why not be nice? */ - -const char __re_error_msgid[] attribute_hidden = - { -#define REG_NOERROR_IDX 0 - gettext_noop ("Success") /* REG_NOERROR */ - "\0" -#define REG_NOMATCH_IDX (REG_NOERROR_IDX + sizeof "Success") - gettext_noop ("No match") /* REG_NOMATCH */ - "\0" -#define REG_BADPAT_IDX (REG_NOMATCH_IDX + sizeof "No match") - gettext_noop ("Invalid regular expression") /* REG_BADPAT */ - "\0" -#define REG_ECOLLATE_IDX (REG_BADPAT_IDX + sizeof "Invalid regular expression") - gettext_noop ("Invalid collation character") /* REG_ECOLLATE */ - "\0" -#define REG_ECTYPE_IDX (REG_ECOLLATE_IDX + sizeof "Invalid collation character") - gettext_noop ("Invalid character class name") /* REG_ECTYPE */ - "\0" -#define REG_EESCAPE_IDX (REG_ECTYPE_IDX + sizeof "Invalid character class name") - gettext_noop ("Trailing backslash") /* REG_EESCAPE */ - "\0" -#define REG_ESUBREG_IDX (REG_EESCAPE_IDX + sizeof "Trailing backslash") - gettext_noop ("Invalid back reference") /* REG_ESUBREG */ - "\0" -#define REG_EBRACK_IDX (REG_ESUBREG_IDX + sizeof "Invalid back reference") - gettext_noop ("Unmatched [ or [^") /* REG_EBRACK */ - "\0" -#define REG_EPAREN_IDX (REG_EBRACK_IDX + sizeof "Unmatched [ or [^") - gettext_noop ("Unmatched ( or \\(") /* REG_EPAREN */ - "\0" -#define REG_EBRACE_IDX (REG_EPAREN_IDX + sizeof "Unmatched ( or \\(") - gettext_noop ("Unmatched \\{") /* REG_EBRACE */ - "\0" -#define REG_BADBR_IDX (REG_EBRACE_IDX + sizeof "Unmatched \\{") - gettext_noop ("Invalid content of \\{\\}") /* REG_BADBR */ - "\0" -#define REG_ERANGE_IDX (REG_BADBR_IDX + sizeof "Invalid content of \\{\\}") - gettext_noop ("Invalid range end") /* REG_ERANGE */ - "\0" -#define REG_ESPACE_IDX (REG_ERANGE_IDX + sizeof "Invalid range end") - gettext_noop ("Memory exhausted") /* REG_ESPACE */ - "\0" -#define REG_BADRPT_IDX (REG_ESPACE_IDX + sizeof "Memory exhausted") - gettext_noop ("Invalid preceding regular expression") /* REG_BADRPT */ - "\0" -#define REG_EEND_IDX (REG_BADRPT_IDX + sizeof "Invalid preceding regular expression") - gettext_noop ("Premature end of regular expression") /* REG_EEND */ - "\0" -#define REG_ESIZE_IDX (REG_EEND_IDX + sizeof "Premature end of regular expression") - gettext_noop ("Regular expression too big") /* REG_ESIZE */ - "\0" -#define REG_ERPAREN_IDX (REG_ESIZE_IDX + sizeof "Regular expression too big") - gettext_noop ("Unmatched ) or \\)") /* REG_ERPAREN */ - }; - -const size_t __re_error_msgid_idx[] attribute_hidden = - { - REG_NOERROR_IDX, - REG_NOMATCH_IDX, - REG_BADPAT_IDX, - REG_ECOLLATE_IDX, - REG_ECTYPE_IDX, - REG_EESCAPE_IDX, - REG_ESUBREG_IDX, - REG_EBRACK_IDX, - REG_EPAREN_IDX, - REG_EBRACE_IDX, - REG_BADBR_IDX, - REG_ERANGE_IDX, - REG_ESPACE_IDX, - REG_BADRPT_IDX, - REG_EEND_IDX, - REG_ESIZE_IDX, - REG_ERPAREN_IDX - }; - -/* Entry points for GNU code. */ - - -#ifdef ZOS_USS - -/* For ZOS USS we must define btowc */ - -wchar_t -btowc (int c) -{ - wchar_t wtmp[2]; - char tmp[2]; - - tmp[0] = c; - tmp[1] = 0; - - mbtowc (wtmp, tmp, 1); - return wtmp[0]; -} -#endif - -/* re_compile_pattern is the GNU regular expression compiler: it - compiles PATTERN (of length LENGTH) and puts the result in BUFP. - Returns 0 if the pattern was valid, otherwise an error string. - - Assumes the `allocated' (and perhaps `buffer') and `translate' fields - are set in BUFP on entry. */ - -const char * -re_compile_pattern (const char *pattern, - size_t length, - struct re_pattern_buffer *bufp) -{ - reg_errcode_t ret; - - /* And GNU code determines whether or not to get register information - by passing null for the REGS argument to re_match, etc., not by - setting no_sub, unless RE_NO_SUB is set. */ - bufp->no_sub = !!(re_syntax_options & RE_NO_SUB); - - /* Match anchors at newline. */ - bufp->newline_anchor = 1; - - ret = re_compile_internal (bufp, pattern, length, re_syntax_options); - - if (!ret) - return NULL; - return gettext (__re_error_msgid + __re_error_msgid_idx[(int) ret]); -} -#ifdef _LIBC -weak_alias (__re_compile_pattern, re_compile_pattern) -#endif - -/* Set by `re_set_syntax' to the current regexp syntax to recognize. Can - also be assigned to arbitrarily: each pattern buffer stores its own - syntax, so it can be changed between regex compilations. */ -/* This has no initializer because initialized variables in Emacs - become read-only after dumping. */ -reg_syntax_t re_syntax_options; - - -/* Specify the precise syntax of regexps for compilation. This provides - for compatibility for various utilities which historically have - different, incompatible syntaxes. - - The argument SYNTAX is a bit mask comprised of the various bits - defined in regex.h. We return the old syntax. */ - -reg_syntax_t -re_set_syntax (reg_syntax_t syntax) -{ - reg_syntax_t ret = re_syntax_options; - - re_syntax_options = syntax; - return ret; -} -#ifdef _LIBC -weak_alias (__re_set_syntax, re_set_syntax) -#endif - -int -re_compile_fastmap (struct re_pattern_buffer *bufp) -{ - re_dfa_t *dfa = (re_dfa_t *) bufp->buffer; - char *fastmap = bufp->fastmap; - - memset (fastmap, '\0', sizeof (char) * SBC_MAX); - re_compile_fastmap_iter (bufp, dfa->init_state, fastmap); - if (dfa->init_state != dfa->init_state_word) - re_compile_fastmap_iter (bufp, dfa->init_state_word, fastmap); - if (dfa->init_state != dfa->init_state_nl) - re_compile_fastmap_iter (bufp, dfa->init_state_nl, fastmap); - if (dfa->init_state != dfa->init_state_begbuf) - re_compile_fastmap_iter (bufp, dfa->init_state_begbuf, fastmap); - bufp->fastmap_accurate = 1; - return 0; -} -#ifdef _LIBC -weak_alias (__re_compile_fastmap, re_compile_fastmap) -#endif - -static inline void -__attribute ((always_inline)) -re_set_fastmap (char *fastmap, int icase, int ch) -{ - fastmap[ch] = 1; - if (icase) - fastmap[tolower (ch)] = 1; -} - -/* Helper function for re_compile_fastmap. - Compile fastmap for the initial_state INIT_STATE. */ - -static void -re_compile_fastmap_iter (regex_t *bufp, const re_dfastate_t *init_state, - char *fastmap) -{ - volatile re_dfa_t *dfa = (re_dfa_t *) bufp->buffer; - int node_cnt; - int icase = (dfa->mb_cur_max == 1 && (bufp->syntax & RE_ICASE)); - for (node_cnt = 0; node_cnt < init_state->nodes.nelem; ++node_cnt) - { - int node = init_state->nodes.elems[node_cnt]; - re_token_type_t type = dfa->nodes[node].type; - - if (type == CHARACTER) - { - re_set_fastmap (fastmap, icase, dfa->nodes[node].opr.c); -#ifdef RE_ENABLE_I18N - if ((bufp->syntax & RE_ICASE) && dfa->mb_cur_max > 1) - { - unsigned char *buf = re_malloc (unsigned char, dfa->mb_cur_max), *p; - wchar_t wc; - mbstate_t state; - - p = buf; - *p++ = dfa->nodes[node].opr.c; - while (++node < dfa->nodes_len - && dfa->nodes[node].type == CHARACTER - && dfa->nodes[node].mb_partial) - *p++ = dfa->nodes[node].opr.c; - memset (&state, '\0', sizeof (state)); - if (__mbrtowc (&wc, (const char *) buf, p - buf, - &state) == p - buf - && (__wcrtomb ((char *) buf, towlower (wc), &state) - != (size_t) -1)) - re_set_fastmap (fastmap, 0, buf[0]); - re_free (buf); - } -#endif - } - else if (type == SIMPLE_BRACKET) - { - int i, ch; - for (i = 0, ch = 0; i < BITSET_WORDS; ++i) - { - int j; - bitset_word_t w = dfa->nodes[node].opr.sbcset[i]; - for (j = 0; j < BITSET_WORD_BITS; ++j, ++ch) - if (w & ((bitset_word_t) 1 << j)) - re_set_fastmap (fastmap, icase, ch); - } - } -#ifdef RE_ENABLE_I18N - else if (type == COMPLEX_BRACKET) - { - re_charset_t *cset = dfa->nodes[node].opr.mbcset; - int i; - -# ifdef _LIBC - /* See if we have to try all bytes which start multiple collation - elements. - e.g. In da_DK, we want to catch 'a' since "aa" is a valid - collation element, and don't catch 'b' since 'b' is - the only collation element which starts from 'b' (and - it is caught by SIMPLE_BRACKET). */ - if (_NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES) != 0 - && (cset->ncoll_syms || cset->nranges)) - { - const int32_t *table = (const int32_t *) - _NL_CURRENT (LC_COLLATE, _NL_COLLATE_TABLEMB); - for (i = 0; i < SBC_MAX; ++i) - if (table[i] < 0) - re_set_fastmap (fastmap, icase, i); - } -# endif /* _LIBC */ - - /* See if we have to start the match at all multibyte characters, - i.e. where we would not find an invalid sequence. This only - applies to multibyte character sets; for single byte character - sets, the SIMPLE_BRACKET again suffices. */ - if (dfa->mb_cur_max > 1 - && (cset->nchar_classes || cset->non_match || cset->nranges -# ifdef _LIBC - || cset->nequiv_classes -# endif /* _LIBC */ - )) - { - unsigned char c = 0; - do - { - mbstate_t mbs; - memset (&mbs, 0, sizeof (mbs)); - if (__mbrtowc (NULL, (char *) &c, 1, &mbs) == (size_t) -2) - re_set_fastmap (fastmap, false, (int) c); - } - while (++c != 0); - } - - else - { - /* ... Else catch all bytes which can start the mbchars. */ - for (i = 0; i < cset->nmbchars; ++i) - { - char buf[256]; - mbstate_t state; - memset (&state, '\0', sizeof (state)); - if (__wcrtomb (buf, cset->mbchars[i], &state) != (size_t) -1) - re_set_fastmap (fastmap, icase, *(unsigned char *) buf); - if ((bufp->syntax & RE_ICASE) && dfa->mb_cur_max > 1) - { - if (__wcrtomb (buf, towlower (cset->mbchars[i]), &state) - != (size_t) -1) - re_set_fastmap (fastmap, false, *(unsigned char *) buf); - } - } - } - } -#endif /* RE_ENABLE_I18N */ - else if (type == OP_PERIOD -#ifdef RE_ENABLE_I18N - || type == OP_UTF8_PERIOD -#endif /* RE_ENABLE_I18N */ - || type == END_OF_RE) - { - memset (fastmap, '\1', sizeof (char) * SBC_MAX); - if (type == END_OF_RE) - bufp->can_be_null = 1; - return; - } - } -} - -/* Entry point for POSIX code. */ -/* regcomp takes a regular expression as a string and compiles it. - - PREG is a regex_t *. We do not expect any fields to be initialized, - since POSIX says we shouldn't. Thus, we set - - `buffer' to the compiled pattern; - `used' to the length of the compiled pattern; - `syntax' to RE_SYNTAX_POSIX_EXTENDED if the - REG_EXTENDED bit in CFLAGS is set; otherwise, to - RE_SYNTAX_POSIX_BASIC; - `newline_anchor' to REG_NEWLINE being set in CFLAGS; - `fastmap' to an allocated space for the fastmap; - `fastmap_accurate' to zero; - `re_nsub' to the number of subexpressions in PATTERN. - - PATTERN is the address of the pattern string. - - CFLAGS is a series of bits which affect compilation. - - If REG_EXTENDED is set, we use POSIX extended syntax; otherwise, we - use POSIX basic syntax. - - If REG_NEWLINE is set, then . and [^...] don't match newline. - Also, regexec will try a match beginning after every newline. - - If REG_ICASE is set, then we considers upper- and lowercase - versions of letters to be equivalent when matching. - - If REG_NOSUB is set, then when PREG is passed to regexec, that - routine will report only success or failure, and nothing about the - registers. - - It returns 0 if it succeeds, nonzero if it doesn't. (See regex.h for - the return codes and their meanings.) */ - -int -regcomp (regex_t *__restrict preg, - const char *__restrict pattern, - int cflags) -{ - reg_errcode_t ret; - reg_syntax_t syntax = ((cflags & REG_EXTENDED) ? RE_SYNTAX_POSIX_EXTENDED - : RE_SYNTAX_POSIX_BASIC); - - preg->buffer = NULL; - preg->allocated = 0; - preg->used = 0; - - /* Try to allocate space for the fastmap. */ - preg->fastmap = re_malloc (char, SBC_MAX); - if (BE (preg->fastmap == NULL, 0)) - return REG_ESPACE; - - syntax |= (cflags & REG_ICASE) ? RE_ICASE : 0; - - /* If REG_NEWLINE is set, newlines are treated differently. */ - if (cflags & REG_NEWLINE) - { /* REG_NEWLINE implies neither . nor [^...] match newline. */ - syntax &= ~RE_DOT_NEWLINE; - syntax |= RE_HAT_LISTS_NOT_NEWLINE; - /* It also changes the matching behavior. */ - preg->newline_anchor = 1; - } - else - preg->newline_anchor = 0; - preg->no_sub = !!(cflags & REG_NOSUB); - preg->translate = NULL; - - ret = re_compile_internal (preg, pattern, strlen (pattern), syntax); - - /* POSIX doesn't distinguish between an unmatched open-group and an - unmatched close-group: both are REG_EPAREN. */ - if (ret == REG_ERPAREN) - ret = REG_EPAREN; - - /* We have already checked preg->fastmap != NULL. */ - if (BE (ret == REG_NOERROR, 1)) - /* Compute the fastmap now, since regexec cannot modify the pattern - buffer. This function never fails in this implementation. */ - (void) re_compile_fastmap (preg); - else - { - /* Some error occurred while compiling the expression. */ - re_free (preg->fastmap); - preg->fastmap = NULL; - } - - return (int) ret; -} -#ifdef _LIBC -weak_alias (__regcomp, regcomp) -#endif - -/* Returns a message corresponding to an error code, ERRCODE, returned - from either regcomp or regexec. We don't use PREG here. */ - -size_t -regerror(int errcode, UNUSED const regex_t *__restrict preg, - char *__restrict errbuf, size_t errbuf_size) -{ - const char *msg; - size_t msg_size; - - if (BE (errcode < 0 - || errcode >= (int) (sizeof (__re_error_msgid_idx) - / sizeof (__re_error_msgid_idx[0])), 0)) - /* Only error codes returned by the rest of the code should be passed - to this routine. If we are given anything else, or if other regex - code generates an invalid error code, then the program has a bug. - Dump core so we can fix it. */ - abort (); - - msg = gettext (__re_error_msgid + __re_error_msgid_idx[errcode]); - - msg_size = strlen (msg) + 1; /* Includes the null. */ - - if (BE (errbuf_size != 0, 1)) - { - if (BE (msg_size > errbuf_size, 0)) - { - memcpy (errbuf, msg, errbuf_size - 1); - errbuf[errbuf_size - 1] = 0; - } - else - memcpy (errbuf, msg, msg_size); - } - - return msg_size; -} -#ifdef _LIBC -weak_alias (__regerror, regerror) -#endif - - -#ifdef RE_ENABLE_I18N -/* This static array is used for the map to single-byte characters when - UTF-8 is used. Otherwise we would allocate memory just to initialize - it the same all the time. UTF-8 is the preferred encoding so this is - a worthwhile optimization. */ -#if __GNUC__ >= 3 -static const bitset_t utf8_sb_map = { - /* Set the first 128 bits. */ - [0 ... 0x80 / BITSET_WORD_BITS - 1] = BITSET_WORD_MAX -}; -#else /* ! (__GNUC__ >= 3) */ -static bitset_t utf8_sb_map; -#endif /* __GNUC__ >= 3 */ -#endif /* RE_ENABLE_I18N */ - - -static void -free_dfa_content (re_dfa_t *dfa) -{ - unsigned int i; - int j; - - if (dfa->nodes) - for (i = 0; i < dfa->nodes_len; ++i) - free_token (dfa->nodes + i); - re_free (dfa->nexts); - for (i = 0; i < dfa->nodes_len; ++i) - { - if (dfa->eclosures != NULL) - re_node_set_free (dfa->eclosures + i); - if (dfa->inveclosures != NULL) - re_node_set_free (dfa->inveclosures + i); - if (dfa->edests != NULL) - re_node_set_free (dfa->edests + i); - } - re_free (dfa->edests); - re_free (dfa->eclosures); - re_free (dfa->inveclosures); - re_free (dfa->nodes); - - if (dfa->state_table) - for (i = 0; i <= dfa->state_hash_mask; ++i) - { - struct re_state_table_entry *entry = dfa->state_table + i; - for (j = 0; j < entry->num; ++j) - { - re_dfastate_t *state = entry->array[j]; - free_state (state); - } - re_free (entry->array); - } - re_free (dfa->state_table); -#ifdef RE_ENABLE_I18N - if (dfa->sb_char != utf8_sb_map) - re_free (dfa->sb_char); -#endif - re_free (dfa->subexp_map); -#ifdef DEBUG - re_free (dfa->re_str); -#endif - - re_free (dfa); -} - - -/* Free dynamically allocated space used by PREG. */ - -void -regfree (regex_t *preg) -{ - re_dfa_t *dfa = (re_dfa_t *) preg->buffer; - if (BE (dfa != NULL, 1)) - free_dfa_content (dfa); - preg->buffer = NULL; - preg->allocated = 0; - - re_free (preg->fastmap); - preg->fastmap = NULL; - - re_free (preg->translate); - preg->translate = NULL; -} -#ifdef _LIBC -weak_alias (__regfree, regfree) -#endif - -/* Entry points compatible with 4.2 BSD regex library. We don't define - them unless specifically requested. */ - -#if defined _REGEX_RE_COMP || defined _LIBC - -/* BSD has one and only one pattern buffer. */ -static struct re_pattern_buffer re_comp_buf; - -char * -# ifdef _LIBC -/* Make these definitions weak in libc, so POSIX programs can redefine - these names if they don't use our functions, and still use - regcomp/regexec above without link errors. */ -weak_function -# endif -re_comp (s) - const char *s; -{ - reg_errcode_t ret; - char *fastmap; - - if (!s) - { - if (!re_comp_buf.buffer) - return gettext ("No previous regular expression"); - return 0; - } - - if (re_comp_buf.buffer) - { - fastmap = re_comp_buf.fastmap; - re_comp_buf.fastmap = NULL; - __regfree (&re_comp_buf); - memset (&re_comp_buf, '\0', sizeof (re_comp_buf)); - re_comp_buf.fastmap = fastmap; - } - - if (re_comp_buf.fastmap == NULL) - { - re_comp_buf.fastmap = (char *) malloc (SBC_MAX); - if (re_comp_buf.fastmap == NULL) - return (char *) gettext (__re_error_msgid - + __re_error_msgid_idx[(int) REG_ESPACE]); - } - - /* Since `re_exec' always passes NULL for the `regs' argument, we - don't need to initialize the pattern buffer fields which affect it. */ - - /* Match anchors at newlines. */ - re_comp_buf.newline_anchor = 1; - - ret = re_compile_internal (&re_comp_buf, s, strlen (s), re_syntax_options); - - if (!ret) - return NULL; - - /* Yes, we're discarding `const' here if !HAVE_LIBINTL. */ - return (char *) gettext (__re_error_msgid + __re_error_msgid_idx[(int) ret]); -} - -#ifdef _LIBC -libc_freeres_fn (free_mem) -{ - __regfree (&re_comp_buf); -} -#endif - -#endif /* _REGEX_RE_COMP */ - -/* Internal entry point. - Compile the regular expression PATTERN, whose length is LENGTH. - SYNTAX indicate regular expression's syntax. */ - -static reg_errcode_t -re_compile_internal (regex_t *preg, const char * pattern, size_t length, - reg_syntax_t syntax) -{ - reg_errcode_t err = REG_NOERROR; - re_dfa_t *dfa; - re_string_t regexp; - - /* Initialize the pattern buffer. */ - preg->fastmap_accurate = 0; - preg->syntax = syntax; - preg->not_bol = preg->not_eol = 0; - preg->used = 0; - preg->re_nsub = 0; - preg->can_be_null = 0; - preg->regs_allocated = REGS_UNALLOCATED; - - /* Initialize the dfa. */ - dfa = (re_dfa_t *) preg->buffer; - if (BE (preg->allocated < sizeof (re_dfa_t), 0)) - { - /* If zero allocated, but buffer is non-null, try to realloc - enough space. This loses if buffer's address is bogus, but - that is the user's responsibility. If ->buffer is NULL this - is a simple allocation. */ - dfa = re_realloc (preg->buffer, re_dfa_t, 1); - if (dfa == NULL) - return REG_ESPACE; - preg->allocated = sizeof (re_dfa_t); - preg->buffer = (unsigned char *) dfa; - } - preg->used = sizeof (re_dfa_t); - - err = init_dfa (dfa, length); - if (BE (err != REG_NOERROR, 0)) - { - free_dfa_content (dfa); - preg->buffer = NULL; - preg->allocated = 0; - return err; - } -#ifdef DEBUG - /* Note: length+1 will not overflow since it is checked in init_dfa. */ - dfa->re_str = re_malloc (char, length + 1); - strncpy (dfa->re_str, pattern, length + 1); -#endif - - __libc_lock_init (dfa->lock); - - err = re_string_construct (®exp, pattern, length, preg->translate, - syntax & RE_ICASE, dfa); - if (BE (err != REG_NOERROR, 0)) - { - re_compile_internal_free_return: - free_workarea_compile (preg); - re_string_destruct (®exp); - free_dfa_content (dfa); - preg->buffer = NULL; - preg->allocated = 0; - return err; - } - - /* Parse the regular expression, and build a structure tree. */ - preg->re_nsub = 0; - dfa->str_tree = parse (®exp, preg, syntax, &err); - if (BE (dfa->str_tree == NULL, 0)) - goto re_compile_internal_free_return; - - /* Analyze the tree and create the nfa. */ - err = analyze (preg); - if (BE (err != REG_NOERROR, 0)) - goto re_compile_internal_free_return; - -#ifdef RE_ENABLE_I18N - /* If possible, do searching in single byte encoding to speed things up. */ - if (dfa->is_utf8 && !(syntax & RE_ICASE) && preg->translate == NULL) - optimize_utf8 (dfa); -#endif - - /* Then create the initial state of the dfa. */ - err = create_initial_state (dfa); - - /* Release work areas. */ - free_workarea_compile (preg); - re_string_destruct (®exp); - - if (BE (err != REG_NOERROR, 0)) - { - free_dfa_content (dfa); - preg->buffer = NULL; - preg->allocated = 0; - } - - return err; -} - -/* Initialize DFA. We use the length of the regular expression PAT_LEN - as the initial length of some arrays. */ - -static reg_errcode_t -init_dfa (re_dfa_t *dfa, size_t pat_len) -{ - unsigned int table_size; - - memset (dfa, '\0', sizeof (re_dfa_t)); - - /* Force allocation of str_tree_storage the first time. */ - dfa->str_tree_storage_idx = BIN_TREE_STORAGE_SIZE; - - /* Avoid overflows. */ - if (pat_len == SIZE_MAX) - return REG_ESPACE; - - dfa->nodes_alloc = pat_len + 1; - dfa->nodes = re_malloc (re_token_t, dfa->nodes_alloc); - - /* table_size = 2 ^ ceil(log pat_len) */ - for (table_size = 1; ; table_size <<= 1) - if (table_size > pat_len) - break; - - dfa->state_table = calloc (sizeof (struct re_state_table_entry), table_size); - dfa->state_hash_mask = table_size - 1; - - dfa->mb_cur_max = MB_CUR_MAX; -#ifdef _LIBC - if (dfa->mb_cur_max == 6 - && strcmp (_NL_CURRENT (LC_CTYPE, _NL_CTYPE_CODESET_NAME), "UTF-8") == 0) - dfa->is_utf8 = 1; - dfa->map_notascii = (_NL_CURRENT_WORD (LC_CTYPE, _NL_CTYPE_MAP_TO_NONASCII) - != 0); -#else - dfa->is_utf8 = 1; - /* We check exhaustively in the loop below if this charset is a - superset of ASCII. */ - dfa->map_notascii = 0; -#endif - -#ifdef RE_ENABLE_I18N - if (dfa->mb_cur_max > 1) - { - if (dfa->is_utf8) - { -#if !defined(__GNUC__) || __GNUC__ < 3 - static short utf8_sb_map_inited = 0; - - if (! utf8_sb_map_inited) - { - int i; - - utf8_sb_map_inited = 0; - for (i = 0; i <= 0x80 / BITSET_WORD_BITS - 1; i++) - utf8_sb_map[i] = BITSET_WORD_MAX; - } -#endif - dfa->sb_char = (re_bitset_ptr_t) utf8_sb_map; - } - else - { - int i, j, ch; - - dfa->sb_char = (re_bitset_ptr_t) calloc (sizeof (bitset_t), 1); - if (BE (dfa->sb_char == NULL, 0)) - return REG_ESPACE; - - /* Set the bits corresponding to single byte chars. */ - for (i = 0, ch = 0; i < BITSET_WORDS; ++i) - for (j = 0; j < BITSET_WORD_BITS; ++j, ++ch) - { - wint_t wch = __btowc (ch); - if (wch != WEOF) - dfa->sb_char[i] |= (bitset_word_t) 1 << j; -# ifndef _LIBC - if (isascii (ch) && wch != ch) - dfa->map_notascii = 1; -# endif - } - } - } -#endif - - if (BE (dfa->nodes == NULL || dfa->state_table == NULL, 0)) - return REG_ESPACE; - return REG_NOERROR; -} - -/* Initialize WORD_CHAR table, which indicate which character is - "word". In this case "word" means that it is the word construction - character used by some operators like "\<", "\>", etc. */ - -static void -internal_function -init_word_char (re_dfa_t *dfa) -{ - int i, j, ch; - dfa->word_ops_used = 1; - for (i = 0, ch = 0; i < BITSET_WORDS; ++i) - for (j = 0; j < BITSET_WORD_BITS; ++j, ++ch) - if (isalnum (ch) || ch == '_') - dfa->word_char[i] |= (bitset_word_t) 1 << j; -} - -/* Free the work area which are only used while compiling. */ - -static void -free_workarea_compile (regex_t *preg) -{ - re_dfa_t *dfa = (re_dfa_t *) preg->buffer; - bin_tree_storage_t *storage, *next; - for (storage = dfa->str_tree_storage; storage; storage = next) - { - next = storage->next; - re_free (storage); - } - dfa->str_tree_storage = NULL; - dfa->str_tree_storage_idx = BIN_TREE_STORAGE_SIZE; - dfa->str_tree = NULL; - re_free (dfa->org_indices); - dfa->org_indices = NULL; -} - -/* Create initial states for all contexts. */ - -static reg_errcode_t -create_initial_state (re_dfa_t *dfa) -{ - int first, i; - reg_errcode_t err; - re_node_set init_nodes; - - /* Initial states have the epsilon closure of the node which is - the first node of the regular expression. */ - first = dfa->str_tree->first->node_idx; - dfa->init_node = first; - err = re_node_set_init_copy (&init_nodes, dfa->eclosures + first); - if (BE (err != REG_NOERROR, 0)) - return err; - - /* The back-references which are in initial states can epsilon transit, - since in this case all of the subexpressions can be null. - Then we add epsilon closures of the nodes which are the next nodes of - the back-references. */ - if (dfa->nbackref > 0) - for (i = 0; i < init_nodes.nelem; ++i) - { - int node_idx = init_nodes.elems[i]; - re_token_type_t type = dfa->nodes[node_idx].type; - - int clexp_idx; - if (type != OP_BACK_REF) - continue; - for (clexp_idx = 0; clexp_idx < init_nodes.nelem; ++clexp_idx) - { - re_token_t *clexp_node; - clexp_node = dfa->nodes + init_nodes.elems[clexp_idx]; - if (clexp_node->type == OP_CLOSE_SUBEXP - && clexp_node->opr.idx == dfa->nodes[node_idx].opr.idx) - break; - } - if (clexp_idx == init_nodes.nelem) - continue; - - if (type == OP_BACK_REF) - { - int dest_idx = dfa->edests[node_idx].elems[0]; - if (!re_node_set_contains (&init_nodes, dest_idx)) - { - reg_errcode_t err = re_node_set_merge (&init_nodes, - dfa->eclosures - + dest_idx); - if (err != REG_NOERROR) - return err; - i = 0; - } - } - } - - /* It must be the first time to invoke acquire_state. */ - dfa->init_state = re_acquire_state_context (&err, dfa, &init_nodes, 0); - /* We don't check ERR here, since the initial state must not be NULL. */ - if (BE (dfa->init_state == NULL, 0)) - return err; - if (dfa->init_state->has_constraint) - { - dfa->init_state_word = re_acquire_state_context (&err, dfa, &init_nodes, - CONTEXT_WORD); - dfa->init_state_nl = re_acquire_state_context (&err, dfa, &init_nodes, - CONTEXT_NEWLINE); - dfa->init_state_begbuf = re_acquire_state_context (&err, dfa, - &init_nodes, - CONTEXT_NEWLINE - | CONTEXT_BEGBUF); - if (BE (dfa->init_state_word == NULL || dfa->init_state_nl == NULL - || dfa->init_state_begbuf == NULL, 0)) - return err; - } - else - dfa->init_state_word = dfa->init_state_nl - = dfa->init_state_begbuf = dfa->init_state; - - re_node_set_free (&init_nodes); - return REG_NOERROR; -} - -#ifdef RE_ENABLE_I18N -/* If it is possible to do searching in single byte encoding instead of UTF-8 - to speed things up, set dfa->mb_cur_max to 1, clear is_utf8 and change - DFA nodes where needed. */ - -static void -optimize_utf8 (re_dfa_t *dfa) -{ - int node, i, mb_chars = 0, has_period = 0; - - for (node = 0; node < dfa->nodes_len; ++node) - switch (dfa->nodes[node].type) - { - case CHARACTER: - if (dfa->nodes[node].opr.c >= 0x80) - mb_chars = 1; - break; - case ANCHOR: - switch (dfa->nodes[node].opr.ctx_type) - { - case LINE_FIRST: - case LINE_LAST: - case BUF_FIRST: - case BUF_LAST: - break; - default: - /* Word anchors etc. cannot be handled. It's okay to test - opr.ctx_type since constraints (for all DFA nodes) are - created by ORing one or more opr.ctx_type values. */ - return; - } - break; - case OP_PERIOD: - has_period = 1; - break; - case OP_BACK_REF: - case OP_ALT: - case END_OF_RE: - case OP_DUP_ASTERISK: - case OP_OPEN_SUBEXP: - case OP_CLOSE_SUBEXP: - break; - case COMPLEX_BRACKET: - return; - case SIMPLE_BRACKET: - /* Just double check. The non-ASCII range starts at 0x80. */ - assert (0x80 % BITSET_WORD_BITS == 0); - for (i = 0x80 / BITSET_WORD_BITS; i < BITSET_WORDS; ++i) - if (dfa->nodes[node].opr.sbcset[i]) - return; - break; - default: - abort (); - } - - if (mb_chars || has_period) - for (node = 0; node < dfa->nodes_len; ++node) - { - if (dfa->nodes[node].type == CHARACTER - && dfa->nodes[node].opr.c >= 0x80) - dfa->nodes[node].mb_partial = 0; - else if (dfa->nodes[node].type == OP_PERIOD) - dfa->nodes[node].type = OP_UTF8_PERIOD; - } - - /* The search can be in single byte locale. */ - dfa->mb_cur_max = 1; - dfa->is_utf8 = 0; - dfa->has_mb_node = dfa->nbackref > 0 || has_period; -} -#endif - -/* Analyze the structure tree, and calculate "first", "next", "edest", - "eclosure", and "inveclosure". */ - -static reg_errcode_t -analyze (regex_t *preg) -{ - re_dfa_t *dfa = (re_dfa_t *) preg->buffer; - reg_errcode_t ret; - - /* Allocate arrays. */ - dfa->nexts = re_malloc (int, dfa->nodes_alloc); - dfa->org_indices = re_malloc (int, dfa->nodes_alloc); - dfa->edests = re_malloc (re_node_set, dfa->nodes_alloc); - dfa->eclosures = re_malloc (re_node_set, dfa->nodes_alloc); - if (BE (dfa->nexts == NULL || dfa->org_indices == NULL || dfa->edests == NULL - || dfa->eclosures == NULL, 0)) - return REG_ESPACE; - - dfa->subexp_map = re_malloc (int, preg->re_nsub); - if (dfa->subexp_map != NULL) - { - unsigned int i; - for (i = 0; i < preg->re_nsub; i++) - dfa->subexp_map[i] = i; - preorder (dfa->str_tree, optimize_subexps, dfa); - for (i = 0; i < preg->re_nsub; i++) - if (dfa->subexp_map[i] != (int)i) - break; - if (i == preg->re_nsub) - { - free (dfa->subexp_map); - dfa->subexp_map = NULL; - } - } - - ret = postorder (dfa->str_tree, lower_subexps, preg); - if (BE (ret != REG_NOERROR, 0)) - return ret; - ret = postorder (dfa->str_tree, calc_first, dfa); - if (BE (ret != REG_NOERROR, 0)) - return ret; - preorder (dfa->str_tree, calc_next, dfa); - ret = preorder (dfa->str_tree, link_nfa_nodes, dfa); - if (BE (ret != REG_NOERROR, 0)) - return ret; - ret = calc_eclosure (dfa); - if (BE (ret != REG_NOERROR, 0)) - return ret; - - /* We only need this during the prune_impossible_nodes pass in regexec.c; - skip it if p_i_n will not run, as calc_inveclosure can be quadratic. */ - if ((!preg->no_sub && preg->re_nsub > 0 && dfa->has_plural_match) - || dfa->nbackref) - { - dfa->inveclosures = re_malloc (re_node_set, dfa->nodes_len); - if (BE (dfa->inveclosures == NULL, 0)) - return REG_ESPACE; - ret = calc_inveclosure (dfa); - } - - return ret; -} - -/* Our parse trees are very unbalanced, so we cannot use a stack to - implement parse tree visits. Instead, we use parent pointers and - some hairy code in these two functions. */ -static reg_errcode_t -postorder (bin_tree_t *root, reg_errcode_t (fn (void *, bin_tree_t *)), - void *extra) -{ - bin_tree_t *node, *prev; - - for (node = root; ; ) - { - /* Descend down the tree, preferably to the left (or to the right - if that's the only child). */ - while (node->left || node->right) - if (node->left) - node = node->left; - else - node = node->right; - - do - { - reg_errcode_t err = fn (extra, node); - if (BE (err != REG_NOERROR, 0)) - return err; - if (node->parent == NULL) - return REG_NOERROR; - prev = node; - node = node->parent; - } - /* Go up while we have a node that is reached from the right. */ - while (node->right == prev || node->right == NULL); - node = node->right; - } -} - -static reg_errcode_t -preorder (bin_tree_t *root, reg_errcode_t (fn (void *, bin_tree_t *)), - void *extra) -{ - bin_tree_t *node; - - for (node = root; ; ) - { - reg_errcode_t err = fn (extra, node); - if (BE (err != REG_NOERROR, 0)) - return err; - - /* Go to the left node, or up and to the right. */ - if (node->left) - node = node->left; - else - { - bin_tree_t *prev = NULL; - while (node->right == prev || node->right == NULL) - { - prev = node; - node = node->parent; - if (!node) - return REG_NOERROR; - } - node = node->right; - } - } -} - -/* Optimization pass: if a SUBEXP is entirely contained, strip it and tell - re_search_internal to map the inner one's opr.idx to this one's. Adjust - backreferences as well. Requires a preorder visit. */ -static reg_errcode_t -optimize_subexps (void *extra, bin_tree_t *node) -{ - re_dfa_t *dfa = (re_dfa_t *) extra; - - if (node->token.type == OP_BACK_REF && dfa->subexp_map) - { - int idx = node->token.opr.idx; - node->token.opr.idx = dfa->subexp_map[idx]; - dfa->used_bkref_map |= 1 << node->token.opr.idx; - } - - else if (node->token.type == SUBEXP - && node->left && node->left->token.type == SUBEXP) - { - int other_idx = node->left->token.opr.idx; - - node->left = node->left->left; - if (node->left) - node->left->parent = node; - - dfa->subexp_map[other_idx] = dfa->subexp_map[node->token.opr.idx]; - if (other_idx < BITSET_WORD_BITS) - dfa->used_bkref_map &= ~((bitset_word_t) 1 << other_idx); - } - - return REG_NOERROR; -} - -/* Lowering pass: Turn each SUBEXP node into the appropriate concatenation - of OP_OPEN_SUBEXP, the body of the SUBEXP (if any) and OP_CLOSE_SUBEXP. */ -static reg_errcode_t -lower_subexps (void *extra, bin_tree_t *node) -{ - regex_t *preg = (regex_t *) extra; - reg_errcode_t err = REG_NOERROR; - - if (node->left && node->left->token.type == SUBEXP) - { - node->left = lower_subexp (&err, preg, node->left); - if (node->left) - node->left->parent = node; - } - if (node->right && node->right->token.type == SUBEXP) - { - node->right = lower_subexp (&err, preg, node->right); - if (node->right) - node->right->parent = node; - } - - return err; -} - -static bin_tree_t * -lower_subexp (reg_errcode_t *err, regex_t *preg, bin_tree_t *node) -{ - re_dfa_t *dfa = (re_dfa_t *) preg->buffer; - bin_tree_t *body = node->left; - bin_tree_t *op, *cls, *tree1, *tree; - - if (preg->no_sub - /* We do not optimize empty subexpressions, because otherwise we may - have bad CONCAT nodes with NULL children. This is obviously not - very common, so we do not lose much. An example that triggers - this case is the sed "script" /\(\)/x. */ - && node->left != NULL - && (node->token.opr.idx >= BITSET_WORD_BITS - || !(dfa->used_bkref_map - & ((bitset_word_t) 1 << node->token.opr.idx)))) - return node->left; - - /* Convert the SUBEXP node to the concatenation of an - OP_OPEN_SUBEXP, the contents, and an OP_CLOSE_SUBEXP. */ - op = create_tree (dfa, NULL, NULL, OP_OPEN_SUBEXP); - cls = create_tree (dfa, NULL, NULL, OP_CLOSE_SUBEXP); - tree1 = body ? create_tree (dfa, body, cls, CONCAT) : cls; - tree = create_tree (dfa, op, tree1, CONCAT); - if (BE (tree == NULL || tree1 == NULL || op == NULL || cls == NULL, 0)) - { - *err = REG_ESPACE; - return NULL; - } - - op->token.opr.idx = cls->token.opr.idx = node->token.opr.idx; - op->token.opt_subexp = cls->token.opt_subexp = node->token.opt_subexp; - return tree; -} - -/* Pass 1 in building the NFA: compute FIRST and create unlinked automaton - nodes. Requires a postorder visit. */ -static reg_errcode_t -calc_first (void *extra, bin_tree_t *node) -{ - re_dfa_t *dfa = (re_dfa_t *) extra; - if (node->token.type == CONCAT) - { - node->first = node->left->first; - node->node_idx = node->left->node_idx; - } - else - { - node->first = node; - node->node_idx = re_dfa_add_node (dfa, node->token); - if (BE (node->node_idx == -1, 0)) - return REG_ESPACE; - if (node->token.type == ANCHOR) - dfa->nodes[node->node_idx].constraint = node->token.opr.ctx_type; - } - return REG_NOERROR; -} - -/* Pass 2: compute NEXT on the tree. Preorder visit. */ -static reg_errcode_t -calc_next (UNUSED void *extra, bin_tree_t *node) -{ - switch (node->token.type) - { - case OP_DUP_ASTERISK: - node->left->next = node; - break; - case CONCAT: - node->left->next = node->right->first; - node->right->next = node->next; - break; - default: - if (node->left) - node->left->next = node->next; - if (node->right) - node->right->next = node->next; - break; - } - return REG_NOERROR; -} - -/* Pass 3: link all DFA nodes to their NEXT node (any order will do). */ -static reg_errcode_t -link_nfa_nodes (void *extra, bin_tree_t *node) -{ - re_dfa_t *dfa = (re_dfa_t *) extra; - int idx = node->node_idx; - reg_errcode_t err = REG_NOERROR; - - switch (node->token.type) - { - case CONCAT: - break; - - case END_OF_RE: - assert (node->next == NULL); - break; - - case OP_DUP_ASTERISK: - case OP_ALT: - { - int left, right; - dfa->has_plural_match = 1; - if (node->left != NULL) - left = node->left->first->node_idx; - else - left = node->next->node_idx; - if (node->right != NULL) - right = node->right->first->node_idx; - else - right = node->next->node_idx; - assert (left > -1); - assert (right > -1); - err = re_node_set_init_2 (dfa->edests + idx, left, right); - } - break; - - case ANCHOR: - case OP_OPEN_SUBEXP: - case OP_CLOSE_SUBEXP: - err = re_node_set_init_1 (dfa->edests + idx, node->next->node_idx); - break; - - case OP_BACK_REF: - dfa->nexts[idx] = node->next->node_idx; - if (node->token.type == OP_BACK_REF) - err = re_node_set_init_1 (dfa->edests + idx, dfa->nexts[idx]); - break; - - default: - assert (!IS_EPSILON_NODE (node->token.type)); - dfa->nexts[idx] = node->next->node_idx; - break; - } - - return err; -} - -/* Duplicate the epsilon closure of the node ROOT_NODE. - Note that duplicated nodes have constraint INIT_CONSTRAINT in addition - to their own constraint. */ - -static reg_errcode_t -internal_function -duplicate_node_closure (re_dfa_t *dfa, int top_org_node, int top_clone_node, - int root_node, unsigned int init_constraint) -{ - int org_node, clone_node, ret; - unsigned int constraint = init_constraint; - for (org_node = top_org_node, clone_node = top_clone_node;;) - { - int org_dest, clone_dest; - if (dfa->nodes[org_node].type == OP_BACK_REF) - { - /* If the back reference epsilon-transit, its destination must - also have the constraint. Then duplicate the epsilon closure - of the destination of the back reference, and store it in - edests of the back reference. */ - org_dest = dfa->nexts[org_node]; - re_node_set_empty (dfa->edests + clone_node); - clone_dest = duplicate_node (dfa, org_dest, constraint); - if (BE (clone_dest == -1, 0)) - return REG_ESPACE; - dfa->nexts[clone_node] = dfa->nexts[org_node]; - ret = re_node_set_insert (dfa->edests + clone_node, clone_dest); - if (BE (ret < 0, 0)) - return REG_ESPACE; - } - else if (dfa->edests[org_node].nelem == 0) - { - /* In case of the node can't epsilon-transit, don't duplicate the - destination and store the original destination as the - destination of the node. */ - dfa->nexts[clone_node] = dfa->nexts[org_node]; - break; - } - else if (dfa->edests[org_node].nelem == 1) - { - /* In case of the node can epsilon-transit, and it has only one - destination. */ - org_dest = dfa->edests[org_node].elems[0]; - re_node_set_empty (dfa->edests + clone_node); - /* If the node is root_node itself, it means the epsilon clsoure - has a loop. Then tie it to the destination of the root_node. */ - if (org_node == root_node && clone_node != org_node) - { - ret = re_node_set_insert (dfa->edests + clone_node, org_dest); - if (BE (ret < 0, 0)) - return REG_ESPACE; - break; - } - /* In case of the node has another constraint, add it. */ - constraint |= dfa->nodes[org_node].constraint; - clone_dest = duplicate_node (dfa, org_dest, constraint); - if (BE (clone_dest == -1, 0)) - return REG_ESPACE; - ret = re_node_set_insert (dfa->edests + clone_node, clone_dest); - if (BE (ret < 0, 0)) - return REG_ESPACE; - } - else /* dfa->edests[org_node].nelem == 2 */ - { - /* In case of the node can epsilon-transit, and it has two - destinations. In the bin_tree_t and DFA, that's '|' and '*'. */ - org_dest = dfa->edests[org_node].elems[0]; - re_node_set_empty (dfa->edests + clone_node); - /* Search for a duplicated node which satisfies the constraint. */ - clone_dest = search_duplicated_node (dfa, org_dest, constraint); - if (clone_dest == -1) - { - /* There is no such duplicated node, create a new one. */ - reg_errcode_t err; - clone_dest = duplicate_node (dfa, org_dest, constraint); - if (BE (clone_dest == -1, 0)) - return REG_ESPACE; - ret = re_node_set_insert (dfa->edests + clone_node, clone_dest); - if (BE (ret < 0, 0)) - return REG_ESPACE; - err = duplicate_node_closure (dfa, org_dest, clone_dest, - root_node, constraint); - if (BE (err != REG_NOERROR, 0)) - return err; - } - else - { - /* There is a duplicated node which satisfies the constraint, - use it to avoid infinite loop. */ - ret = re_node_set_insert (dfa->edests + clone_node, clone_dest); - if (BE (ret < 0, 0)) - return REG_ESPACE; - } - - org_dest = dfa->edests[org_node].elems[1]; - clone_dest = duplicate_node (dfa, org_dest, constraint); - if (BE (clone_dest == -1, 0)) - return REG_ESPACE; - ret = re_node_set_insert (dfa->edests + clone_node, clone_dest); - if (BE (ret < 0, 0)) - return REG_ESPACE; - } - org_node = org_dest; - clone_node = clone_dest; - } - return REG_NOERROR; -} - -/* Search for a node which is duplicated from the node ORG_NODE, and - satisfies the constraint CONSTRAINT. */ - -static int -search_duplicated_node (const re_dfa_t *dfa, int org_node, - unsigned int constraint) -{ - int idx; - for (idx = dfa->nodes_len - 1; dfa->nodes[idx].duplicated && idx > 0; --idx) - { - if (org_node == dfa->org_indices[idx] - && constraint == dfa->nodes[idx].constraint) - return idx; /* Found. */ - } - return -1; /* Not found. */ -} - -/* Duplicate the node whose index is ORG_IDX and set the constraint CONSTRAINT. - Return the index of the new node, or -1 if insufficient storage is - available. */ - -static int -duplicate_node (re_dfa_t *dfa, int org_idx, unsigned int constraint) -{ - int dup_idx = re_dfa_add_node (dfa, dfa->nodes[org_idx]); - if (BE (dup_idx != -1, 1)) - { - dfa->nodes[dup_idx].constraint = constraint; - dfa->nodes[dup_idx].constraint |= dfa->nodes[org_idx].constraint; - dfa->nodes[dup_idx].duplicated = 1; - - /* Store the index of the original node. */ - dfa->org_indices[dup_idx] = org_idx; - } - return dup_idx; -} - -static reg_errcode_t -calc_inveclosure (re_dfa_t *dfa) -{ - int ret; - unsigned int src, idx; - for (idx = 0; idx < dfa->nodes_len; ++idx) - re_node_set_init_empty (dfa->inveclosures + idx); - - for (src = 0; src < dfa->nodes_len; ++src) - { - int *elems = dfa->eclosures[src].elems; - int idx; - for (idx = 0; idx < dfa->eclosures[src].nelem; ++idx) - { - ret = re_node_set_insert_last (dfa->inveclosures + elems[idx], src); - if (BE (ret == -1, 0)) - return REG_ESPACE; - } - } - - return REG_NOERROR; -} - -/* Calculate "eclosure" for all the node in DFA. */ - -static reg_errcode_t -calc_eclosure (re_dfa_t *dfa) -{ - size_t node_idx; - int incomplete; -#ifdef DEBUG - assert (dfa->nodes_len > 0); -#endif - incomplete = 0; - /* For each nodes, calculate epsilon closure. */ - for (node_idx = 0; ; ++node_idx) - { - reg_errcode_t err; - re_node_set eclosure_elem; - if (node_idx == dfa->nodes_len) - { - if (!incomplete) - break; - incomplete = 0; - node_idx = 0; - } - -#ifdef DEBUG - assert (dfa->eclosures[node_idx].nelem != -1); -#endif - - /* If we have already calculated, skip it. */ - if (dfa->eclosures[node_idx].nelem != 0) - continue; - /* Calculate epsilon closure of `node_idx'. */ - err = calc_eclosure_iter (&eclosure_elem, dfa, node_idx, 1); - if (BE (err != REG_NOERROR, 0)) - return err; - - if (dfa->eclosures[node_idx].nelem == 0) - { - incomplete = 1; - re_node_set_free (&eclosure_elem); - } - } - return REG_NOERROR; -} - -/* Calculate epsilon closure of NODE. */ - -static reg_errcode_t -calc_eclosure_iter (re_node_set *new_set, re_dfa_t *dfa, int node, int root) -{ - reg_errcode_t err; - int i; - re_node_set eclosure; - int ret; - int incomplete = 0; - err = re_node_set_alloc (&eclosure, dfa->edests[node].nelem + 1); - if (BE (err != REG_NOERROR, 0)) - return err; - - /* This indicates that we are calculating this node now. - We reference this value to avoid infinite loop. */ - dfa->eclosures[node].nelem = -1; - - /* If the current node has constraints, duplicate all nodes - since they must inherit the constraints. */ - if (dfa->nodes[node].constraint - && dfa->edests[node].nelem - && !dfa->nodes[dfa->edests[node].elems[0]].duplicated) - { - err = duplicate_node_closure (dfa, node, node, node, - dfa->nodes[node].constraint); - if (BE (err != REG_NOERROR, 0)) - return err; - } - - /* Expand each epsilon destination nodes. */ - if (IS_EPSILON_NODE(dfa->nodes[node].type)) - for (i = 0; i < dfa->edests[node].nelem; ++i) - { - re_node_set eclosure_elem; - int edest = dfa->edests[node].elems[i]; - /* If calculating the epsilon closure of `edest' is in progress, - return intermediate result. */ - if (dfa->eclosures[edest].nelem == -1) - { - incomplete = 1; - continue; - } - /* If we haven't calculated the epsilon closure of `edest' yet, - calculate now. Otherwise use calculated epsilon closure. */ - if (dfa->eclosures[edest].nelem == 0) - { - err = calc_eclosure_iter (&eclosure_elem, dfa, edest, 0); - if (BE (err != REG_NOERROR, 0)) - return err; - } - else - eclosure_elem = dfa->eclosures[edest]; - /* Merge the epsilon closure of `edest'. */ - err = re_node_set_merge (&eclosure, &eclosure_elem); - if (BE (err != REG_NOERROR, 0)) - return err; - /* If the epsilon closure of `edest' is incomplete, - the epsilon closure of this node is also incomplete. */ - if (dfa->eclosures[edest].nelem == 0) - { - incomplete = 1; - re_node_set_free (&eclosure_elem); - } - } - - /* An epsilon closure includes itself. */ - ret = re_node_set_insert (&eclosure, node); - if (BE (ret < 0, 0)) - return REG_ESPACE; - if (incomplete && !root) - dfa->eclosures[node].nelem = 0; - else - dfa->eclosures[node] = eclosure; - *new_set = eclosure; - return REG_NOERROR; -} - -/* Functions for token which are used in the parser. */ - -/* Fetch a token from INPUT. - We must not use this function inside bracket expressions. */ - -static void -internal_function -fetch_token (re_token_t *result, re_string_t *input, reg_syntax_t syntax) -{ - re_string_skip_bytes (input, peek_token (result, input, syntax)); -} - -/* Peek a token from INPUT, and return the length of the token. - We must not use this function inside bracket expressions. */ - -static int -internal_function -peek_token (re_token_t *token, re_string_t *input, reg_syntax_t syntax) -{ - unsigned char c; - - if (re_string_eoi (input)) - { - token->type = END_OF_RE; - return 0; - } - - c = re_string_peek_byte (input, 0); - token->opr.c = c; - - token->word_char = 0; -#ifdef RE_ENABLE_I18N - token->mb_partial = 0; - if (input->mb_cur_max > 1 && - !re_string_first_byte (input, re_string_cur_idx (input))) - { - token->type = CHARACTER; - token->mb_partial = 1; - return 1; - } -#endif - if (c == '\\') - { - unsigned char c2; - if (re_string_cur_idx (input) + 1 >= re_string_length (input)) - { - token->type = BACK_SLASH; - return 1; - } - - c2 = re_string_peek_byte_case (input, 1); - token->opr.c = c2; - token->type = CHARACTER; -#ifdef RE_ENABLE_I18N - if (input->mb_cur_max > 1) - { - wint_t wc = re_string_wchar_at (input, - re_string_cur_idx (input) + 1); - token->word_char = IS_WIDE_WORD_CHAR (wc) != 0; - } - else -#endif - token->word_char = IS_WORD_CHAR (c2) != 0; - - switch (c2) - { - case '|': - if (!(syntax & RE_LIMITED_OPS) && !(syntax & RE_NO_BK_VBAR)) - token->type = OP_ALT; - break; - case '1': case '2': case '3': case '4': case '5': - case '6': case '7': case '8': case '9': - if (!(syntax & RE_NO_BK_REFS)) - { - token->type = OP_BACK_REF; - token->opr.idx = c2 - '1'; - } - break; - case '<': - if (!(syntax & RE_NO_GNU_OPS)) - { - token->type = ANCHOR; - token->opr.ctx_type = WORD_FIRST; - } - break; - case '>': - if (!(syntax & RE_NO_GNU_OPS)) - { - token->type = ANCHOR; - token->opr.ctx_type = WORD_LAST; - } - break; - case 'b': - if (!(syntax & RE_NO_GNU_OPS)) - { - token->type = ANCHOR; - token->opr.ctx_type = WORD_DELIM; - } - break; - case 'B': - if (!(syntax & RE_NO_GNU_OPS)) - { - token->type = ANCHOR; - token->opr.ctx_type = NOT_WORD_DELIM; - } - break; - case 'w': - if (!(syntax & RE_NO_GNU_OPS)) - token->type = OP_WORD; - break; - case 'W': - if (!(syntax & RE_NO_GNU_OPS)) - token->type = OP_NOTWORD; - break; - case 's': - if (!(syntax & RE_NO_GNU_OPS)) - token->type = OP_SPACE; - break; - case 'S': - if (!(syntax & RE_NO_GNU_OPS)) - token->type = OP_NOTSPACE; - break; - case '`': - if (!(syntax & RE_NO_GNU_OPS)) - { - token->type = ANCHOR; - token->opr.ctx_type = BUF_FIRST; - } - break; - case '\'': - if (!(syntax & RE_NO_GNU_OPS)) - { - token->type = ANCHOR; - token->opr.ctx_type = BUF_LAST; - } - break; - case '(': - if (!(syntax & RE_NO_BK_PARENS)) - token->type = OP_OPEN_SUBEXP; - break; - case ')': - if (!(syntax & RE_NO_BK_PARENS)) - token->type = OP_CLOSE_SUBEXP; - break; - case '+': - if (!(syntax & RE_LIMITED_OPS) && (syntax & RE_BK_PLUS_QM)) - token->type = OP_DUP_PLUS; - break; - case '?': - if (!(syntax & RE_LIMITED_OPS) && (syntax & RE_BK_PLUS_QM)) - token->type = OP_DUP_QUESTION; - break; - case '{': - if ((syntax & RE_INTERVALS) && (!(syntax & RE_NO_BK_BRACES))) - token->type = OP_OPEN_DUP_NUM; - break; - case '}': - if ((syntax & RE_INTERVALS) && (!(syntax & RE_NO_BK_BRACES))) - token->type = OP_CLOSE_DUP_NUM; - break; - default: - break; - } - return 2; - } - - token->type = CHARACTER; -#ifdef RE_ENABLE_I18N - if (input->mb_cur_max > 1) - { - wint_t wc = re_string_wchar_at (input, re_string_cur_idx (input)); - token->word_char = IS_WIDE_WORD_CHAR (wc) != 0; - } - else -#endif - token->word_char = IS_WORD_CHAR (token->opr.c); - - switch (c) - { - case '\n': - if (syntax & RE_NEWLINE_ALT) - token->type = OP_ALT; - break; - case '|': - if (!(syntax & RE_LIMITED_OPS) && (syntax & RE_NO_BK_VBAR)) - token->type = OP_ALT; - break; - case '*': - token->type = OP_DUP_ASTERISK; - break; - case '+': - if (!(syntax & RE_LIMITED_OPS) && !(syntax & RE_BK_PLUS_QM)) - token->type = OP_DUP_PLUS; - break; - case '?': - if (!(syntax & RE_LIMITED_OPS) && !(syntax & RE_BK_PLUS_QM)) - token->type = OP_DUP_QUESTION; - break; - case '{': - if ((syntax & RE_INTERVALS) && (syntax & RE_NO_BK_BRACES)) - token->type = OP_OPEN_DUP_NUM; - break; - case '}': - if ((syntax & RE_INTERVALS) && (syntax & RE_NO_BK_BRACES)) - token->type = OP_CLOSE_DUP_NUM; - break; - case '(': - if (syntax & RE_NO_BK_PARENS) - token->type = OP_OPEN_SUBEXP; - break; - case ')': - if (syntax & RE_NO_BK_PARENS) - token->type = OP_CLOSE_SUBEXP; - break; - case '[': - token->type = OP_OPEN_BRACKET; - break; - case '.': - token->type = OP_PERIOD; - break; - case '^': - if (!(syntax & (RE_CONTEXT_INDEP_ANCHORS | RE_CARET_ANCHORS_HERE)) && - re_string_cur_idx (input) != 0) - { - char prev = re_string_peek_byte (input, -1); - if (!(syntax & RE_NEWLINE_ALT) || prev != '\n') - break; - } - token->type = ANCHOR; - token->opr.ctx_type = LINE_FIRST; - break; - case '$': - if (!(syntax & RE_CONTEXT_INDEP_ANCHORS) && - re_string_cur_idx (input) + 1 != re_string_length (input)) - { - re_token_t next; - re_string_skip_bytes (input, 1); - peek_token (&next, input, syntax); - re_string_skip_bytes (input, -1); - if (next.type != OP_ALT && next.type != OP_CLOSE_SUBEXP) - break; - } - token->type = ANCHOR; - token->opr.ctx_type = LINE_LAST; - break; - default: - break; - } - return 1; -} - -/* Peek a token from INPUT, and return the length of the token. - We must not use this function out of bracket expressions. */ - -static int -internal_function -peek_token_bracket (re_token_t *token, re_string_t *input, reg_syntax_t syntax) -{ - unsigned char c; - if (re_string_eoi (input)) - { - token->type = END_OF_RE; - return 0; - } - c = re_string_peek_byte (input, 0); - token->opr.c = c; - -#ifdef RE_ENABLE_I18N - if (input->mb_cur_max > 1 && - !re_string_first_byte (input, re_string_cur_idx (input))) - { - token->type = CHARACTER; - return 1; - } -#endif /* RE_ENABLE_I18N */ - - if (c == '\\' && (syntax & RE_BACKSLASH_ESCAPE_IN_LISTS) - && re_string_cur_idx (input) + 1 < re_string_length (input)) - { - /* In this case, '\' escape a character. */ - unsigned char c2; - re_string_skip_bytes (input, 1); - c2 = re_string_peek_byte (input, 0); - token->opr.c = c2; - token->type = CHARACTER; - return 1; - } - if (c == '[') /* '[' is a special char in a bracket exps. */ - { - unsigned char c2; - int token_len; - if (re_string_cur_idx (input) + 1 < re_string_length (input)) - c2 = re_string_peek_byte (input, 1); - else - c2 = 0; - token->opr.c = c2; - token_len = 2; - switch (c2) - { - case '.': - token->type = OP_OPEN_COLL_ELEM; - break; - case '=': - token->type = OP_OPEN_EQUIV_CLASS; - break; - case ':': - if (syntax & RE_CHAR_CLASSES) - { - token->type = OP_OPEN_CHAR_CLASS; - break; - } - /* else fall through. */ - default: - token->type = CHARACTER; - token->opr.c = c; - token_len = 1; - break; - } - return token_len; - } - switch (c) - { - case '-': - token->type = OP_CHARSET_RANGE; - break; - case ']': - token->type = OP_CLOSE_BRACKET; - break; - case '^': - token->type = OP_NON_MATCH_LIST; - break; - default: - token->type = CHARACTER; - } - return 1; -} - -/* Functions for parser. */ - -/* Entry point of the parser. - Parse the regular expression REGEXP and return the structure tree. - If an error is occured, ERR is set by error code, and return NULL. - This function build the following tree, from regular expression : - CAT - / \ - / \ - EOR - - CAT means concatenation. - EOR means end of regular expression. */ - -static bin_tree_t * -parse (re_string_t *regexp, regex_t *preg, reg_syntax_t syntax, - reg_errcode_t *err) -{ - re_dfa_t *dfa = (re_dfa_t *) preg->buffer; - bin_tree_t *tree, *eor, *root; - re_token_t current_token; - dfa->syntax = syntax; - fetch_token (¤t_token, regexp, syntax | RE_CARET_ANCHORS_HERE); - tree = parse_reg_exp (regexp, preg, ¤t_token, syntax, 0, err); - if (BE (*err != REG_NOERROR && tree == NULL, 0)) - return NULL; - eor = create_tree (dfa, NULL, NULL, END_OF_RE); - if (tree != NULL) - root = create_tree (dfa, tree, eor, CONCAT); - else - root = eor; - if (BE (eor == NULL || root == NULL, 0)) - { - *err = REG_ESPACE; - return NULL; - } - return root; -} - -/* This function build the following tree, from regular expression - |: - ALT - / \ - / \ - - - ALT means alternative, which represents the operator `|'. */ - -static bin_tree_t * -parse_reg_exp (re_string_t *regexp, regex_t *preg, re_token_t *token, - reg_syntax_t syntax, int nest, reg_errcode_t *err) -{ - re_dfa_t *dfa = (re_dfa_t *) preg->buffer; - bin_tree_t *tree, *branch = NULL; - tree = parse_branch (regexp, preg, token, syntax, nest, err); - if (BE (*err != REG_NOERROR && tree == NULL, 0)) - return NULL; - - while (token->type == OP_ALT) - { - fetch_token (token, regexp, syntax | RE_CARET_ANCHORS_HERE); - if (token->type != OP_ALT && token->type != END_OF_RE - && (nest == 0 || token->type != OP_CLOSE_SUBEXP)) - { - branch = parse_branch (regexp, preg, token, syntax, nest, err); - if (BE (*err != REG_NOERROR && branch == NULL, 0)) - return NULL; - } - else - branch = NULL; - tree = create_tree (dfa, tree, branch, OP_ALT); - if (BE (tree == NULL, 0)) - { - *err = REG_ESPACE; - return NULL; - } - } - return tree; -} - -/* This function build the following tree, from regular expression - : - CAT - / \ - / \ - - - CAT means concatenation. */ - -static bin_tree_t * -parse_branch (re_string_t *regexp, regex_t *preg, re_token_t *token, - reg_syntax_t syntax, int nest, reg_errcode_t *err) -{ - bin_tree_t *tree, *exp; - re_dfa_t *dfa = (re_dfa_t *) preg->buffer; - tree = parse_expression (regexp, preg, token, syntax, nest, err); - if (BE (*err != REG_NOERROR && tree == NULL, 0)) - return NULL; - - while (token->type != OP_ALT && token->type != END_OF_RE - && (nest == 0 || token->type != OP_CLOSE_SUBEXP)) - { - exp = parse_expression (regexp, preg, token, syntax, nest, err); - if (BE (*err != REG_NOERROR && exp == NULL, 0)) - { - return NULL; - } - if (tree != NULL && exp != NULL) - { - tree = create_tree (dfa, tree, exp, CONCAT); - if (tree == NULL) - { - *err = REG_ESPACE; - return NULL; - } - } - else if (tree == NULL) - tree = exp; - /* Otherwise exp == NULL, we don't need to create new tree. */ - } - return tree; -} - -/* This function build the following tree, from regular expression a*: - * - | - a -*/ - -static bin_tree_t * -parse_expression (re_string_t *regexp, regex_t *preg, re_token_t *token, - reg_syntax_t syntax, int nest, reg_errcode_t *err) -{ - re_dfa_t *dfa = (re_dfa_t *) preg->buffer; - bin_tree_t *tree; - switch (token->type) - { - case CHARACTER: - tree = create_token_tree (dfa, NULL, NULL, token); - if (BE (tree == NULL, 0)) - { - *err = REG_ESPACE; - return NULL; - } -#ifdef RE_ENABLE_I18N - if (dfa->mb_cur_max > 1) - { - while (!re_string_eoi (regexp) - && !re_string_first_byte (regexp, re_string_cur_idx (regexp))) - { - bin_tree_t *mbc_remain; - fetch_token (token, regexp, syntax); - mbc_remain = create_token_tree (dfa, NULL, NULL, token); - tree = create_tree (dfa, tree, mbc_remain, CONCAT); - if (BE (mbc_remain == NULL || tree == NULL, 0)) - { - *err = REG_ESPACE; - return NULL; - } - } - } -#endif - break; - case OP_OPEN_SUBEXP: - tree = parse_sub_exp (regexp, preg, token, syntax, nest + 1, err); - if (BE (*err != REG_NOERROR && tree == NULL, 0)) - return NULL; - break; - case OP_OPEN_BRACKET: - tree = parse_bracket_exp (regexp, dfa, token, syntax, err); - if (BE (*err != REG_NOERROR && tree == NULL, 0)) - return NULL; - break; - case OP_BACK_REF: - if (!BE (dfa->completed_bkref_map & (1 << token->opr.idx), 1)) - { - *err = REG_ESUBREG; - return NULL; - } - dfa->used_bkref_map |= 1 << token->opr.idx; - tree = create_token_tree (dfa, NULL, NULL, token); - if (BE (tree == NULL, 0)) - { - *err = REG_ESPACE; - return NULL; - } - ++dfa->nbackref; - dfa->has_mb_node = 1; - break; - case OP_OPEN_DUP_NUM: - if (syntax & RE_CONTEXT_INVALID_DUP) - { - *err = REG_BADRPT; - return NULL; - } - /* FALLTHROUGH */ - case OP_DUP_ASTERISK: - case OP_DUP_PLUS: - case OP_DUP_QUESTION: - if (syntax & RE_CONTEXT_INVALID_OPS) - { - *err = REG_BADRPT; - return NULL; - } - else if (syntax & RE_CONTEXT_INDEP_OPS) - { - fetch_token (token, regexp, syntax); - return parse_expression (regexp, preg, token, syntax, nest, err); - } - /* else fall through */ - case OP_CLOSE_SUBEXP: - if ((token->type == OP_CLOSE_SUBEXP) && - !(syntax & RE_UNMATCHED_RIGHT_PAREN_ORD)) - { - *err = REG_ERPAREN; - return NULL; - } - /* else fall through */ - case OP_CLOSE_DUP_NUM: - /* We treat it as a normal character. */ - - /* Then we can these characters as normal characters. */ - token->type = CHARACTER; - /* mb_partial and word_char bits should be initialized already - by peek_token. */ - tree = create_token_tree (dfa, NULL, NULL, token); - if (BE (tree == NULL, 0)) - { - *err = REG_ESPACE; - return NULL; - } - break; - case ANCHOR: - if ((token->opr.ctx_type - & (WORD_DELIM | NOT_WORD_DELIM | WORD_FIRST | WORD_LAST)) - && dfa->word_ops_used == 0) - init_word_char (dfa); - if (token->opr.ctx_type == WORD_DELIM - || token->opr.ctx_type == NOT_WORD_DELIM) - { - bin_tree_t *tree_first, *tree_last; - if (token->opr.ctx_type == WORD_DELIM) - { - token->opr.ctx_type = WORD_FIRST; - tree_first = create_token_tree (dfa, NULL, NULL, token); - token->opr.ctx_type = WORD_LAST; - } - else - { - token->opr.ctx_type = INSIDE_WORD; - tree_first = create_token_tree (dfa, NULL, NULL, token); - token->opr.ctx_type = INSIDE_NOTWORD; - } - tree_last = create_token_tree (dfa, NULL, NULL, token); - tree = create_tree (dfa, tree_first, tree_last, OP_ALT); - if (BE (tree_first == NULL || tree_last == NULL || tree == NULL, 0)) - { - *err = REG_ESPACE; - return NULL; - } - } - else - { - tree = create_token_tree (dfa, NULL, NULL, token); - if (BE (tree == NULL, 0)) - { - *err = REG_ESPACE; - return NULL; - } - } - /* We must return here, since ANCHORs can't be followed - by repetition operators. - eg. RE"^*" is invalid or "", - it must not be "". */ - fetch_token (token, regexp, syntax); - return tree; - case OP_PERIOD: - tree = create_token_tree (dfa, NULL, NULL, token); - if (BE (tree == NULL, 0)) - { - *err = REG_ESPACE; - return NULL; - } - if (dfa->mb_cur_max > 1) - dfa->has_mb_node = 1; - break; - case OP_WORD: - case OP_NOTWORD: - tree = build_charclass_op (dfa, regexp->trans, - "alnum", - "_", - token->type == OP_NOTWORD, err); - if (BE (*err != REG_NOERROR && tree == NULL, 0)) - return NULL; - break; - case OP_SPACE: - case OP_NOTSPACE: - tree = build_charclass_op (dfa, regexp->trans, - "space", - "", - token->type == OP_NOTSPACE, err); - if (BE (*err != REG_NOERROR && tree == NULL, 0)) - return NULL; - break; - case OP_ALT: - case END_OF_RE: - return NULL; - case BACK_SLASH: - *err = REG_EESCAPE; - return NULL; - default: - /* Must not happen? */ -#ifdef DEBUG - assert (0); -#endif - return NULL; - } - fetch_token (token, regexp, syntax); - - while (token->type == OP_DUP_ASTERISK || token->type == OP_DUP_PLUS - || token->type == OP_DUP_QUESTION || token->type == OP_OPEN_DUP_NUM) - { - tree = parse_dup_op (tree, regexp, dfa, token, syntax, err); - if (BE (*err != REG_NOERROR && tree == NULL, 0)) - return NULL; - /* In BRE consecutive duplications are not allowed. */ - if ((syntax & RE_CONTEXT_INVALID_DUP) - && (token->type == OP_DUP_ASTERISK - || token->type == OP_OPEN_DUP_NUM)) - { - *err = REG_BADRPT; - return NULL; - } - } - - return tree; -} - -/* This function build the following tree, from regular expression - (): - SUBEXP - | - -*/ - -static bin_tree_t * -parse_sub_exp (re_string_t *regexp, regex_t *preg, re_token_t *token, - reg_syntax_t syntax, int nest, reg_errcode_t *err) -{ - re_dfa_t *dfa = (re_dfa_t *) preg->buffer; - bin_tree_t *tree; - size_t cur_nsub; - cur_nsub = preg->re_nsub++; - - fetch_token (token, regexp, syntax | RE_CARET_ANCHORS_HERE); - - /* The subexpression may be a null string. */ - if (token->type == OP_CLOSE_SUBEXP) - tree = NULL; - else - { - tree = parse_reg_exp (regexp, preg, token, syntax, nest, err); - if (BE (*err == REG_NOERROR && token->type != OP_CLOSE_SUBEXP, 0)) - *err = REG_EPAREN; - if (BE (*err != REG_NOERROR, 0)) - return NULL; - } - - if (cur_nsub <= '9' - '1') - dfa->completed_bkref_map |= 1 << cur_nsub; - - tree = create_tree (dfa, tree, NULL, SUBEXP); - if (BE (tree == NULL, 0)) - { - *err = REG_ESPACE; - return NULL; - } - tree->token.opr.idx = cur_nsub; - return tree; -} - -/* This function parse repetition operators like "*", "+", "{1,3}" etc. */ - -static bin_tree_t * -parse_dup_op (bin_tree_t *elem, re_string_t *regexp, re_dfa_t *dfa, - re_token_t *token, reg_syntax_t syntax, reg_errcode_t *err) -{ - bin_tree_t *tree = NULL, *old_tree = NULL; - int i, start, end, start_idx = re_string_cur_idx (regexp); -#ifndef RE_TOKEN_INIT_BUG - re_token_t start_token = *token; -#else - re_token_t start_token; - - memcpy ((void *) &start_token, (void *) token, sizeof start_token); -#endif - - if (token->type == OP_OPEN_DUP_NUM) - { - end = 0; - start = fetch_number (regexp, token, syntax); - if (start == -1) - { - if (token->type == CHARACTER && token->opr.c == ',') - start = 0; /* We treat "{,m}" as "{0,m}". */ - else - { - *err = REG_BADBR; /* {} is invalid. */ - return NULL; - } - } - if (BE (start != -2, 1)) - { - /* We treat "{n}" as "{n,n}". */ - end = ((token->type == OP_CLOSE_DUP_NUM) ? start - : ((token->type == CHARACTER && token->opr.c == ',') - ? fetch_number (regexp, token, syntax) : -2)); - } - if (BE (start == -2 || end == -2, 0)) - { - /* Invalid sequence. */ - if (BE (!(syntax & RE_INVALID_INTERVAL_ORD), 0)) - { - if (token->type == END_OF_RE) - *err = REG_EBRACE; - else - *err = REG_BADBR; - - return NULL; - } - - /* If the syntax bit is set, rollback. */ - re_string_set_index (regexp, start_idx); - *token = start_token; - token->type = CHARACTER; - /* mb_partial and word_char bits should be already initialized by - peek_token. */ - return elem; - } - - if (BE ((end != -1 && start > end) || token->type != OP_CLOSE_DUP_NUM, 0)) - { - /* First number greater than second. */ - *err = REG_BADBR; - return NULL; - } - } - else - { - start = (token->type == OP_DUP_PLUS) ? 1 : 0; - end = (token->type == OP_DUP_QUESTION) ? 1 : -1; - } - - fetch_token (token, regexp, syntax); - - if (BE (elem == NULL, 0)) - return NULL; - if (BE (start == 0 && end == 0, 0)) - { - postorder (elem, free_tree, NULL); - return NULL; - } - - /* Extract "{n,m}" to "...{0,}". */ - if (BE (start > 0, 0)) - { - tree = elem; - for (i = 2; i <= start; ++i) - { - elem = duplicate_tree (elem, dfa); - tree = create_tree (dfa, tree, elem, CONCAT); - if (BE (elem == NULL || tree == NULL, 0)) - goto parse_dup_op_espace; - } - - if (start == end) - return tree; - - /* Duplicate ELEM before it is marked optional. */ - elem = duplicate_tree (elem, dfa); - old_tree = tree; - } - else - old_tree = NULL; - - if (elem->token.type == SUBEXP) - postorder (elem, mark_opt_subexp, (void *) (long) elem->token.opr.idx); - - tree = create_tree (dfa, elem, NULL, (end == -1 ? OP_DUP_ASTERISK : OP_ALT)); - if (BE (tree == NULL, 0)) - goto parse_dup_op_espace; - - /* This loop is actually executed only when end != -1, - to rewrite {0,n} as ((...?)?)?... We have - already created the start+1-th copy. */ - for (i = start + 2; i <= end; ++i) - { - elem = duplicate_tree (elem, dfa); - tree = create_tree (dfa, tree, elem, CONCAT); - if (BE (elem == NULL || tree == NULL, 0)) - goto parse_dup_op_espace; - - tree = create_tree (dfa, tree, NULL, OP_ALT); - if (BE (tree == NULL, 0)) - goto parse_dup_op_espace; - } - - if (old_tree) - tree = create_tree (dfa, old_tree, tree, CONCAT); - - return tree; - - parse_dup_op_espace: - *err = REG_ESPACE; - return NULL; -} - -/* Size of the names for collating symbol/equivalence_class/character_class. - I'm not sure, but maybe enough. */ -#define BRACKET_NAME_BUF_SIZE 32 - -#ifndef _LIBC - /* Local function for parse_bracket_exp only used in case of NOT _LIBC. - Build the range expression which starts from START_ELEM, and ends - at END_ELEM. The result are written to MBCSET and SBCSET. - RANGE_ALLOC is the allocated size of mbcset->range_starts, and - mbcset->range_ends, is a pointer argument sinse we may - update it. */ - -static reg_errcode_t -internal_function -# ifdef RE_ENABLE_I18N -build_range_exp (bitset_t sbcset, re_charset_t *mbcset, int *range_alloc, - bracket_elem_t *start_elem, bracket_elem_t *end_elem) -# else /* not RE_ENABLE_I18N */ -build_range_exp (bitset_t sbcset, bracket_elem_t *start_elem, - bracket_elem_t *end_elem) -# endif /* not RE_ENABLE_I18N */ -{ - unsigned int start_ch, end_ch; - /* Equivalence Classes and Character Classes can't be a range start/end. */ - if (BE (start_elem->type == EQUIV_CLASS || start_elem->type == CHAR_CLASS - || end_elem->type == EQUIV_CLASS || end_elem->type == CHAR_CLASS, - 0)) - return REG_ERANGE; - - /* We can handle no multi character collating elements without libc - support. */ - if (BE ((start_elem->type == COLL_SYM - && strlen ((char *) start_elem->opr.name) > 1) - || (end_elem->type == COLL_SYM - && strlen ((char *) end_elem->opr.name) > 1), 0)) - return REG_ECOLLATE; - -# ifdef RE_ENABLE_I18N - { - wchar_t wc; - wint_t start_wc; - wint_t end_wc; - wchar_t cmp_buf[6] = {L'\0', L'\0', L'\0', L'\0', L'\0', L'\0'}; - - start_ch = ((start_elem->type == SB_CHAR) ? start_elem->opr.ch - : ((start_elem->type == COLL_SYM) ? start_elem->opr.name[0] - : 0)); - end_ch = ((end_elem->type == SB_CHAR) ? end_elem->opr.ch - : ((end_elem->type == COLL_SYM) ? end_elem->opr.name[0] - : 0)); -#ifdef GAWK - /* - * Fedora Core 2, maybe others, have broken `btowc' that returns -1 - * for any value > 127. Sigh. Note that `start_ch' and `end_ch' are - * unsigned, so we don't have sign extension problems. - */ - start_wc = ((start_elem->type == SB_CHAR || start_elem->type == COLL_SYM) - ? start_ch : start_elem->opr.wch); - end_wc = ((end_elem->type == SB_CHAR || end_elem->type == COLL_SYM) - ? end_ch : end_elem->opr.wch); -#else - start_wc = ((start_elem->type == SB_CHAR || start_elem->type == COLL_SYM) - ? __btowc (start_ch) : start_elem->opr.wch); - end_wc = ((end_elem->type == SB_CHAR || end_elem->type == COLL_SYM) - ? __btowc (end_ch) : end_elem->opr.wch); -#endif - if (start_wc == WEOF || end_wc == WEOF) - return REG_ECOLLATE; - cmp_buf[0] = start_wc; - cmp_buf[4] = end_wc; - if (wcscoll (cmp_buf, cmp_buf + 4) > 0) - return REG_ERANGE; - - /* Got valid collation sequence values, add them as a new entry. - However, for !_LIBC we have no collation elements: if the - character set is single byte, the single byte character set - that we build below suffices. parse_bracket_exp passes - no MBCSET if dfa->mb_cur_max == 1. */ - if (mbcset) - { - /* Check the space of the arrays. */ - if (BE (*range_alloc == mbcset->nranges, 0)) - { - /* There is not enough space, need realloc. */ - wchar_t *new_array_start, *new_array_end; - int new_nranges; - - /* +1 in case of mbcset->nranges is 0. */ - new_nranges = 2 * mbcset->nranges + 1; - /* Use realloc since mbcset->range_starts and mbcset->range_ends - are NULL if *range_alloc == 0. */ - new_array_start = re_realloc (mbcset->range_starts, wchar_t, - new_nranges); - new_array_end = re_realloc (mbcset->range_ends, wchar_t, - new_nranges); - - if (BE (new_array_start == NULL || new_array_end == NULL, 0)) - return REG_ESPACE; - - mbcset->range_starts = new_array_start; - mbcset->range_ends = new_array_end; - *range_alloc = new_nranges; - } - - mbcset->range_starts[mbcset->nranges] = start_wc; - mbcset->range_ends[mbcset->nranges++] = end_wc; - } - - /* Build the table for single byte characters. */ - for (wc = 0; wc < SBC_MAX; ++wc) - { - cmp_buf[2] = wc; - if (wcscoll (cmp_buf, cmp_buf + 2) <= 0 - && wcscoll (cmp_buf + 2, cmp_buf + 4) <= 0) - bitset_set (sbcset, wc); - } - } -# else /* not RE_ENABLE_I18N */ - { - unsigned int ch; - start_ch = ((start_elem->type == SB_CHAR ) ? start_elem->opr.ch - : ((start_elem->type == COLL_SYM) ? start_elem->opr.name[0] - : 0)); - end_ch = ((end_elem->type == SB_CHAR ) ? end_elem->opr.ch - : ((end_elem->type == COLL_SYM) ? end_elem->opr.name[0] - : 0)); - if (start_ch > end_ch) - return REG_ERANGE; - /* Build the table for single byte characters. */ - for (ch = 0; ch < SBC_MAX; ++ch) - if (start_ch <= ch && ch <= end_ch) - bitset_set (sbcset, ch); - } -# endif /* not RE_ENABLE_I18N */ - return REG_NOERROR; -} -#endif /* not _LIBC */ - -#ifndef _LIBC -/* Helper function for parse_bracket_exp only used in case of NOT _LIBC.. - Build the collating element which is represented by NAME. - The result are written to MBCSET and SBCSET. - COLL_SYM_ALLOC is the allocated size of mbcset->coll_sym, is a - pointer argument since we may update it. */ - -static reg_errcode_t -internal_function -# ifdef RE_ENABLE_I18N -build_collating_symbol (bitset_t sbcset, re_charset_t *mbcset, - int *coll_sym_alloc, const unsigned char *name) -# else /* not RE_ENABLE_I18N */ -build_collating_symbol (bitset_t sbcset, const unsigned char *name) -# endif /* not RE_ENABLE_I18N */ -{ - size_t name_len = strlen ((const char *) name); - if (BE (name_len != 1, 0)) - return REG_ECOLLATE; - else - { - bitset_set (sbcset, name[0]); - return REG_NOERROR; - } -} -#endif /* not _LIBC */ - -/* This function parse bracket expression like "[abc]", "[a-c]", - "[[.a-a.]]" etc. */ - -static bin_tree_t * -parse_bracket_exp (re_string_t *regexp, re_dfa_t *dfa, re_token_t *token, - reg_syntax_t syntax, reg_errcode_t *err) -{ -#ifdef _LIBC - const unsigned char *collseqmb; - const char *collseqwc; - uint32_t nrules; - int32_t table_size; - const int32_t *symb_table; - const unsigned char *extra; - - /* Local function for parse_bracket_exp used in _LIBC environement. - Seek the collating symbol entry correspondings to NAME. - Return the index of the symbol in the SYMB_TABLE. */ - - auto inline int32_t - __attribute ((always_inline)) - seek_collating_symbol_entry (name, name_len) - const unsigned char *name; - size_t name_len; - { - int32_t hash = elem_hash ((const char *) name, name_len); - int32_t elem = hash % table_size; - if (symb_table[2 * elem] != 0) - { - int32_t second = hash % (table_size - 2) + 1; - - do - { - /* First compare the hashing value. */ - if (symb_table[2 * elem] == hash - /* Compare the length of the name. */ - && name_len == extra[symb_table[2 * elem + 1]] - /* Compare the name. */ - && memcmp (name, &extra[symb_table[2 * elem + 1] + 1], - name_len) == 0) - { - /* Yep, this is the entry. */ - break; - } - - /* Next entry. */ - elem += second; - } - while (symb_table[2 * elem] != 0); - } - return elem; - } - - /* Local function for parse_bracket_exp used in _LIBC environment. - Look up the collation sequence value of BR_ELEM. - Return the value if succeeded, UINT_MAX otherwise. */ - - auto inline unsigned int - __attribute ((always_inline)) - lookup_collation_sequence_value (br_elem) - bracket_elem_t *br_elem; - { - if (br_elem->type == SB_CHAR) - { - /* - if (MB_CUR_MAX == 1) - */ - if (nrules == 0) - return collseqmb[br_elem->opr.ch]; - else - { - wint_t wc = __btowc (br_elem->opr.ch); - return __collseq_table_lookup (collseqwc, wc); - } - } - else if (br_elem->type == MB_CHAR) - { - if (nrules != 0) - return __collseq_table_lookup (collseqwc, br_elem->opr.wch); - } - else if (br_elem->type == COLL_SYM) - { - size_t sym_name_len = strlen ((char *) br_elem->opr.name); - if (nrules != 0) - { - int32_t elem, idx; - elem = seek_collating_symbol_entry (br_elem->opr.name, - sym_name_len); - if (symb_table[2 * elem] != 0) - { - /* We found the entry. */ - idx = symb_table[2 * elem + 1]; - /* Skip the name of collating element name. */ - idx += 1 + extra[idx]; - /* Skip the byte sequence of the collating element. */ - idx += 1 + extra[idx]; - /* Adjust for the alignment. */ - idx = (idx + 3) & ~3; - /* Skip the multibyte collation sequence value. */ - idx += sizeof (unsigned int); - /* Skip the wide char sequence of the collating element. */ - idx += sizeof (unsigned int) * - (1 + *(unsigned int *) (extra + idx)); - /* Return the collation sequence value. */ - return *(unsigned int *) (extra + idx); - } - else if (symb_table[2 * elem] == 0 && sym_name_len == 1) - { - /* No valid character. Match it as a single byte - character. */ - return collseqmb[br_elem->opr.name[0]]; - } - } - else if (sym_name_len == 1) - return collseqmb[br_elem->opr.name[0]]; - } - return UINT_MAX; - } - - /* Local function for parse_bracket_exp used in _LIBC environement. - Build the range expression which starts from START_ELEM, and ends - at END_ELEM. The result are written to MBCSET and SBCSET. - RANGE_ALLOC is the allocated size of mbcset->range_starts, and - mbcset->range_ends, is a pointer argument sinse we may - update it. */ - - auto inline reg_errcode_t - __attribute ((always_inline)) - build_range_exp (sbcset, mbcset, range_alloc, start_elem, end_elem) - re_charset_t *mbcset; - int *range_alloc; - bitset_t sbcset; - bracket_elem_t *start_elem, *end_elem; - { - unsigned int ch; - uint32_t start_collseq; - uint32_t end_collseq; - - /* Equivalence Classes and Character Classes can't be a range - start/end. */ - if (BE (start_elem->type == EQUIV_CLASS || start_elem->type == CHAR_CLASS - || end_elem->type == EQUIV_CLASS || end_elem->type == CHAR_CLASS, - 0)) - return REG_ERANGE; - - start_collseq = lookup_collation_sequence_value (start_elem); - end_collseq = lookup_collation_sequence_value (end_elem); - /* Check start/end collation sequence values. */ - if (BE (start_collseq == UINT_MAX || end_collseq == UINT_MAX, 0)) - return REG_ECOLLATE; - if (BE ((syntax & RE_NO_EMPTY_RANGES) && start_collseq > end_collseq, 0)) - return REG_ERANGE; - - /* Got valid collation sequence values, add them as a new entry. - However, if we have no collation elements, and the character set - is single byte, the single byte character set that we - build below suffices. */ - if (nrules > 0 || dfa->mb_cur_max > 1) - { - /* Check the space of the arrays. */ - if (BE (*range_alloc == mbcset->nranges, 0)) - { - /* There is not enough space, need realloc. */ - uint32_t *new_array_start; - uint32_t *new_array_end; - int new_nranges; - - /* +1 in case of mbcset->nranges is 0. */ - new_nranges = 2 * mbcset->nranges + 1; - new_array_start = re_realloc (mbcset->range_starts, uint32_t, - new_nranges); - new_array_end = re_realloc (mbcset->range_ends, uint32_t, - new_nranges); - - if (BE (new_array_start == NULL || new_array_end == NULL, 0)) - return REG_ESPACE; - - mbcset->range_starts = new_array_start; - mbcset->range_ends = new_array_end; - *range_alloc = new_nranges; - } - - mbcset->range_starts[mbcset->nranges] = start_collseq; - mbcset->range_ends[mbcset->nranges++] = end_collseq; - } - - /* Build the table for single byte characters. */ - for (ch = 0; ch < SBC_MAX; ch++) - { - uint32_t ch_collseq; - /* - if (MB_CUR_MAX == 1) - */ - if (nrules == 0) - ch_collseq = collseqmb[ch]; - else - ch_collseq = __collseq_table_lookup (collseqwc, __btowc (ch)); - if (start_collseq <= ch_collseq && ch_collseq <= end_collseq) - bitset_set (sbcset, ch); - } - return REG_NOERROR; - } - - /* Local function for parse_bracket_exp used in _LIBC environement. - Build the collating element which is represented by NAME. - The result are written to MBCSET and SBCSET. - COLL_SYM_ALLOC is the allocated size of mbcset->coll_sym, is a - pointer argument sinse we may update it. */ - - auto inline reg_errcode_t - __attribute ((always_inline)) - build_collating_symbol (sbcset, mbcset, coll_sym_alloc, name) - re_charset_t *mbcset; - int *coll_sym_alloc; - bitset_t sbcset; - const unsigned char *name; - { - int32_t elem, idx; - size_t name_len = strlen ((const char *) name); - if (nrules != 0) - { - elem = seek_collating_symbol_entry (name, name_len); - if (symb_table[2 * elem] != 0) - { - /* We found the entry. */ - idx = symb_table[2 * elem + 1]; - /* Skip the name of collating element name. */ - idx += 1 + extra[idx]; - } - else if (symb_table[2 * elem] == 0 && name_len == 1) - { - /* No valid character, treat it as a normal - character. */ - bitset_set (sbcset, name[0]); - return REG_NOERROR; - } - else - return REG_ECOLLATE; - - /* Got valid collation sequence, add it as a new entry. */ - /* Check the space of the arrays. */ - if (BE (*coll_sym_alloc == mbcset->ncoll_syms, 0)) - { - /* Not enough, realloc it. */ - /* +1 in case of mbcset->ncoll_syms is 0. */ - int new_coll_sym_alloc = 2 * mbcset->ncoll_syms + 1; - /* Use realloc since mbcset->coll_syms is NULL - if *alloc == 0. */ - int32_t *new_coll_syms = re_realloc (mbcset->coll_syms, int32_t, - new_coll_sym_alloc); - if (BE (new_coll_syms == NULL, 0)) - return REG_ESPACE; - mbcset->coll_syms = new_coll_syms; - *coll_sym_alloc = new_coll_sym_alloc; - } - mbcset->coll_syms[mbcset->ncoll_syms++] = idx; - return REG_NOERROR; - } - else - { - if (BE (name_len != 1, 0)) - return REG_ECOLLATE; - else - { - bitset_set (sbcset, name[0]); - return REG_NOERROR; - } - } - } -#endif - - re_token_t br_token; - re_bitset_ptr_t sbcset; -#ifdef RE_ENABLE_I18N - re_charset_t *mbcset; - int coll_sym_alloc = 0, range_alloc = 0, mbchar_alloc = 0; - int equiv_class_alloc = 0, char_class_alloc = 0; -#endif /* not RE_ENABLE_I18N */ - int non_match = 0; - bin_tree_t *work_tree; - int token_len; - int first_round = 1; -#ifdef _LIBC - collseqmb = (const unsigned char *) - _NL_CURRENT (LC_COLLATE, _NL_COLLATE_COLLSEQMB); - nrules = _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES); - if (nrules) - { - /* - if (MB_CUR_MAX > 1) - */ - collseqwc = _NL_CURRENT (LC_COLLATE, _NL_COLLATE_COLLSEQWC); - table_size = _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_SYMB_HASH_SIZEMB); - symb_table = (const int32_t *) _NL_CURRENT (LC_COLLATE, - _NL_COLLATE_SYMB_TABLEMB); - extra = (const unsigned char *) _NL_CURRENT (LC_COLLATE, - _NL_COLLATE_SYMB_EXTRAMB); - } -#endif - sbcset = (re_bitset_ptr_t) calloc (sizeof (bitset_t), 1); -#ifdef RE_ENABLE_I18N - mbcset = (re_charset_t *) calloc (sizeof (re_charset_t), 1); -#endif /* RE_ENABLE_I18N */ -#ifdef RE_ENABLE_I18N - if (BE (sbcset == NULL || mbcset == NULL, 0)) -#else - if (BE (sbcset == NULL, 0)) -#endif /* RE_ENABLE_I18N */ - { - *err = REG_ESPACE; - return NULL; - } - - token_len = peek_token_bracket (token, regexp, syntax); - if (BE (token->type == END_OF_RE, 0)) - { - *err = REG_BADPAT; - goto parse_bracket_exp_free_return; - } - if (token->type == OP_NON_MATCH_LIST) - { -#ifdef RE_ENABLE_I18N - mbcset->non_match = 1; -#endif /* not RE_ENABLE_I18N */ - non_match = 1; - if (syntax & RE_HAT_LISTS_NOT_NEWLINE) - bitset_set (sbcset, '\n'); - re_string_skip_bytes (regexp, token_len); /* Skip a token. */ - token_len = peek_token_bracket (token, regexp, syntax); - if (BE (token->type == END_OF_RE, 0)) - { - *err = REG_BADPAT; - goto parse_bracket_exp_free_return; - } - } - - /* We treat the first ']' as a normal character. */ - if (token->type == OP_CLOSE_BRACKET) - token->type = CHARACTER; - - while (1) - { - bracket_elem_t start_elem, end_elem; - unsigned char start_name_buf[BRACKET_NAME_BUF_SIZE]; - unsigned char end_name_buf[BRACKET_NAME_BUF_SIZE]; - reg_errcode_t ret; - int token_len2 = 0, is_range_exp = 0; - re_token_t token2; - - start_elem.opr.name = start_name_buf; - ret = parse_bracket_element (&start_elem, regexp, token, token_len, dfa, - syntax, first_round); - if (BE (ret != REG_NOERROR, 0)) - { - *err = ret; - goto parse_bracket_exp_free_return; - } - first_round = 0; - - /* Get information about the next token. We need it in any case. */ - token_len = peek_token_bracket (token, regexp, syntax); - - /* Do not check for ranges if we know they are not allowed. */ - if (start_elem.type != CHAR_CLASS && start_elem.type != EQUIV_CLASS) - { - if (BE (token->type == END_OF_RE, 0)) - { - *err = REG_EBRACK; - goto parse_bracket_exp_free_return; - } - if (token->type == OP_CHARSET_RANGE) - { - re_string_skip_bytes (regexp, token_len); /* Skip '-'. */ - token_len2 = peek_token_bracket (&token2, regexp, syntax); - if (BE (token2.type == END_OF_RE, 0)) - { - *err = REG_EBRACK; - goto parse_bracket_exp_free_return; - } - if (token2.type == OP_CLOSE_BRACKET) - { - /* We treat the last '-' as a normal character. */ - re_string_skip_bytes (regexp, -token_len); - token->type = CHARACTER; - } - else - is_range_exp = 1; - } - } - - if (is_range_exp == 1) - { - end_elem.opr.name = end_name_buf; - ret = parse_bracket_element (&end_elem, regexp, &token2, token_len2, - dfa, syntax, 1); - if (BE (ret != REG_NOERROR, 0)) - { - *err = ret; - goto parse_bracket_exp_free_return; - } - - token_len = peek_token_bracket (token, regexp, syntax); - -#ifdef _LIBC - *err = build_range_exp (sbcset, mbcset, &range_alloc, - &start_elem, &end_elem); -#else -# ifdef RE_ENABLE_I18N - *err = build_range_exp (sbcset, - dfa->mb_cur_max > 1 ? mbcset : NULL, - &range_alloc, &start_elem, &end_elem); -# else - *err = build_range_exp (sbcset, &start_elem, &end_elem); -# endif -#endif /* RE_ENABLE_I18N */ - if (BE (*err != REG_NOERROR, 0)) - goto parse_bracket_exp_free_return; - } - else - { - switch (start_elem.type) - { - case SB_CHAR: - bitset_set (sbcset, start_elem.opr.ch); - break; -#ifdef RE_ENABLE_I18N - case MB_CHAR: - /* Check whether the array has enough space. */ - if (BE (mbchar_alloc == mbcset->nmbchars, 0)) - { - wchar_t *new_mbchars; - /* Not enough, realloc it. */ - /* +1 in case of mbcset->nmbchars is 0. */ - mbchar_alloc = 2 * mbcset->nmbchars + 1; - /* Use realloc since array is NULL if *alloc == 0. */ - new_mbchars = re_realloc (mbcset->mbchars, wchar_t, - mbchar_alloc); - if (BE (new_mbchars == NULL, 0)) - goto parse_bracket_exp_espace; - mbcset->mbchars = new_mbchars; - } - mbcset->mbchars[mbcset->nmbchars++] = start_elem.opr.wch; - break; -#endif /* RE_ENABLE_I18N */ - case EQUIV_CLASS: - *err = build_equiv_class (sbcset, -#ifdef RE_ENABLE_I18N - mbcset, &equiv_class_alloc, -#endif /* RE_ENABLE_I18N */ - start_elem.opr.name); - if (BE (*err != REG_NOERROR, 0)) - goto parse_bracket_exp_free_return; - break; - case COLL_SYM: - *err = build_collating_symbol (sbcset, -#ifdef RE_ENABLE_I18N - mbcset, &coll_sym_alloc, -#endif /* RE_ENABLE_I18N */ - start_elem.opr.name); - if (BE (*err != REG_NOERROR, 0)) - goto parse_bracket_exp_free_return; - break; - case CHAR_CLASS: - *err = build_charclass (regexp->trans, sbcset, -#ifdef RE_ENABLE_I18N - mbcset, &char_class_alloc, -#endif /* RE_ENABLE_I18N */ - (const char *) start_elem.opr.name, syntax); - if (BE (*err != REG_NOERROR, 0)) - goto parse_bracket_exp_free_return; - break; - default: - assert (0); - break; - } - } - if (BE (token->type == END_OF_RE, 0)) - { - *err = REG_EBRACK; - goto parse_bracket_exp_free_return; - } - if (token->type == OP_CLOSE_BRACKET) - break; - } - - re_string_skip_bytes (regexp, token_len); /* Skip a token. */ - - /* If it is non-matching list. */ - if (non_match) - bitset_not (sbcset); - -#ifdef RE_ENABLE_I18N - /* Ensure only single byte characters are set. */ - if (dfa->mb_cur_max > 1) - bitset_mask (sbcset, dfa->sb_char); - - if (mbcset->nmbchars || mbcset->ncoll_syms || mbcset->nequiv_classes - || mbcset->nranges || (dfa->mb_cur_max > 1 && (mbcset->nchar_classes - || mbcset->non_match))) - { - bin_tree_t *mbc_tree; - int sbc_idx; - /* Build a tree for complex bracket. */ - dfa->has_mb_node = 1; - br_token.type = COMPLEX_BRACKET; - br_token.opr.mbcset = mbcset; - mbc_tree = create_token_tree (dfa, NULL, NULL, &br_token); - if (BE (mbc_tree == NULL, 0)) - goto parse_bracket_exp_espace; - for (sbc_idx = 0; sbc_idx < BITSET_WORDS; ++sbc_idx) - if (sbcset[sbc_idx]) - break; - /* If there are no bits set in sbcset, there is no point - of having both SIMPLE_BRACKET and COMPLEX_BRACKET. */ - if (sbc_idx < BITSET_WORDS) - { - /* Build a tree for simple bracket. */ - br_token.type = SIMPLE_BRACKET; - br_token.opr.sbcset = sbcset; - work_tree = create_token_tree (dfa, NULL, NULL, &br_token); - if (BE (work_tree == NULL, 0)) - goto parse_bracket_exp_espace; - - /* Then join them by ALT node. */ - work_tree = create_tree (dfa, work_tree, mbc_tree, OP_ALT); - if (BE (work_tree == NULL, 0)) - goto parse_bracket_exp_espace; - } - else - { - re_free (sbcset); - work_tree = mbc_tree; - } - } - else -#endif /* not RE_ENABLE_I18N */ - { -#ifdef RE_ENABLE_I18N - free_charset (mbcset); -#endif - /* Build a tree for simple bracket. */ - br_token.type = SIMPLE_BRACKET; - br_token.opr.sbcset = sbcset; - work_tree = create_token_tree (dfa, NULL, NULL, &br_token); - if (BE (work_tree == NULL, 0)) - goto parse_bracket_exp_espace; - } - return work_tree; - - parse_bracket_exp_espace: - *err = REG_ESPACE; - parse_bracket_exp_free_return: - re_free (sbcset); -#ifdef RE_ENABLE_I18N - free_charset (mbcset); -#endif /* RE_ENABLE_I18N */ - return NULL; -} - -/* Parse an element in the bracket expression. */ - -static reg_errcode_t -parse_bracket_element (bracket_elem_t *elem, re_string_t *regexp, - re_token_t *token, int token_len, UNUSED re_dfa_t *dfa, - reg_syntax_t syntax, int accept_hyphen) -{ -#ifdef RE_ENABLE_I18N - int cur_char_size; - cur_char_size = re_string_char_size_at (regexp, re_string_cur_idx (regexp)); - if (cur_char_size > 1) - { - elem->type = MB_CHAR; - elem->opr.wch = re_string_wchar_at (regexp, re_string_cur_idx (regexp)); - re_string_skip_bytes (regexp, cur_char_size); - return REG_NOERROR; - } -#endif /* RE_ENABLE_I18N */ - re_string_skip_bytes (regexp, token_len); /* Skip a token. */ - if (token->type == OP_OPEN_COLL_ELEM || token->type == OP_OPEN_CHAR_CLASS - || token->type == OP_OPEN_EQUIV_CLASS) - return parse_bracket_symbol (elem, regexp, token); - if (BE (token->type == OP_CHARSET_RANGE, 0) && !accept_hyphen) - { - /* A '-' must only appear as anything but a range indicator before - the closing bracket. Everything else is an error. */ - re_token_t token2; - (void) peek_token_bracket (&token2, regexp, syntax); - if (token2.type != OP_CLOSE_BRACKET) - /* The actual error value is not standardized since this whole - case is undefined. But ERANGE makes good sense. */ - return REG_ERANGE; - } - elem->type = SB_CHAR; - elem->opr.ch = token->opr.c; - return REG_NOERROR; -} - -/* Parse a bracket symbol in the bracket expression. Bracket symbols are - such as [::], [..], and - [==]. */ - -static reg_errcode_t -parse_bracket_symbol (bracket_elem_t *elem, re_string_t *regexp, - re_token_t *token) -{ - unsigned char ch, delim = token->opr.c; - int i = 0; - if (re_string_eoi(regexp)) - return REG_EBRACK; - for (;; ++i) - { - if (i >= BRACKET_NAME_BUF_SIZE) - return REG_EBRACK; - if (token->type == OP_OPEN_CHAR_CLASS) - ch = re_string_fetch_byte_case (regexp); - else - ch = re_string_fetch_byte (regexp); - if (re_string_eoi(regexp)) - return REG_EBRACK; - if (ch == delim && re_string_peek_byte (regexp, 0) == ']') - break; - elem->opr.name[i] = ch; - } - re_string_skip_bytes (regexp, 1); - elem->opr.name[i] = '\0'; - switch (token->type) - { - case OP_OPEN_COLL_ELEM: - elem->type = COLL_SYM; - break; - case OP_OPEN_EQUIV_CLASS: - elem->type = EQUIV_CLASS; - break; - case OP_OPEN_CHAR_CLASS: - elem->type = CHAR_CLASS; - break; - default: - break; - } - return REG_NOERROR; -} - - /* Helper function for parse_bracket_exp. - Build the equivalence class which is represented by NAME. - The result are written to MBCSET and SBCSET. - EQUIV_CLASS_ALLOC is the allocated size of mbcset->equiv_classes, - is a pointer argument sinse we may update it. */ - -static reg_errcode_t -#ifdef RE_ENABLE_I18N -build_equiv_class (bitset_t sbcset, re_charset_t *mbcset, - int *equiv_class_alloc, const unsigned char *name) -#else /* not RE_ENABLE_I18N */ -build_equiv_class (bitset_t sbcset, const unsigned char *name) -#endif /* not RE_ENABLE_I18N */ -{ -#ifdef _LIBC - uint32_t nrules = _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES); - if (nrules != 0) - { - const int32_t *table, *indirect; - const unsigned char *weights, *extra, *cp; - unsigned char char_buf[2]; - int32_t idx1, idx2; - unsigned int ch; - size_t len; - /* This #include defines a local function! */ -# include - /* Calculate the index for equivalence class. */ - cp = name; - table = (const int32_t *) _NL_CURRENT (LC_COLLATE, _NL_COLLATE_TABLEMB); - weights = (const unsigned char *) _NL_CURRENT (LC_COLLATE, - _NL_COLLATE_WEIGHTMB); - extra = (const unsigned char *) _NL_CURRENT (LC_COLLATE, - _NL_COLLATE_EXTRAMB); - indirect = (const int32_t *) _NL_CURRENT (LC_COLLATE, - _NL_COLLATE_INDIRECTMB); - idx1 = findidx (&cp); - if (BE (idx1 == 0 || cp < name + strlen ((const char *) name), 0)) - /* This isn't a valid character. */ - return REG_ECOLLATE; - - /* Build single byte matcing table for this equivalence class. */ - char_buf[1] = (unsigned char) '\0'; - len = weights[idx1 & 0xffffff]; - for (ch = 0; ch < SBC_MAX; ++ch) - { - char_buf[0] = ch; - cp = char_buf; - idx2 = findidx (&cp); -/* - idx2 = table[ch]; -*/ - if (idx2 == 0) - /* This isn't a valid character. */ - continue; - /* Compare only if the length matches and the collation rule - index is the same. */ - if (len == weights[idx2 & 0xffffff] && (idx1 >> 24) == (idx2 >> 24)) - { - int cnt = 0; - - while (cnt <= len && - weights[(idx1 & 0xffffff) + 1 + cnt] - == weights[(idx2 & 0xffffff) + 1 + cnt]) - ++cnt; - - if (cnt > len) - bitset_set (sbcset, ch); - } - } - /* Check whether the array has enough space. */ - if (BE (*equiv_class_alloc == mbcset->nequiv_classes, 0)) - { - /* Not enough, realloc it. */ - /* +1 in case of mbcset->nequiv_classes is 0. */ - int new_equiv_class_alloc = 2 * mbcset->nequiv_classes + 1; - /* Use realloc since the array is NULL if *alloc == 0. */ - int32_t *new_equiv_classes = re_realloc (mbcset->equiv_classes, - int32_t, - new_equiv_class_alloc); - if (BE (new_equiv_classes == NULL, 0)) - return REG_ESPACE; - mbcset->equiv_classes = new_equiv_classes; - *equiv_class_alloc = new_equiv_class_alloc; - } - mbcset->equiv_classes[mbcset->nequiv_classes++] = idx1; - } - else -#endif /* _LIBC */ - { - if (BE (strlen ((const char *) name) != 1, 0)) - return REG_ECOLLATE; - bitset_set (sbcset, *name); - } - return REG_NOERROR; -} - - /* Helper function for parse_bracket_exp. - Build the character class which is represented by NAME. - The result are written to MBCSET and SBCSET. - CHAR_CLASS_ALLOC is the allocated size of mbcset->char_classes, - is a pointer argument sinse we may update it. */ - -static reg_errcode_t -#ifdef RE_ENABLE_I18N -build_charclass (RE_TRANSLATE_TYPE trans, bitset_t sbcset, - re_charset_t *mbcset, int *char_class_alloc, - const char *class_name, reg_syntax_t syntax) -#else /* not RE_ENABLE_I18N */ -build_charclass (RE_TRANSLATE_TYPE trans, bitset_t sbcset, - const char *class_name, reg_syntax_t syntax) -#endif /* not RE_ENABLE_I18N */ -{ - int i; - - /* In case of REG_ICASE "upper" and "lower" match the both of - upper and lower cases. */ - if ((syntax & RE_ICASE) - && (strcmp (class_name, "upper") == 0 || strcmp (class_name, "lower") == 0)) - class_name = "alpha"; - -#ifdef RE_ENABLE_I18N - /* Check the space of the arrays. */ - if (BE (*char_class_alloc == mbcset->nchar_classes, 0)) - { - /* Not enough, realloc it. */ - /* +1 in case of mbcset->nchar_classes is 0. */ - int new_char_class_alloc = 2 * mbcset->nchar_classes + 1; - /* Use realloc since array is NULL if *alloc == 0. */ - wctype_t *new_char_classes = re_realloc (mbcset->char_classes, wctype_t, - new_char_class_alloc); - if (BE (new_char_classes == NULL, 0)) - return REG_ESPACE; - mbcset->char_classes = new_char_classes; - *char_class_alloc = new_char_class_alloc; - } - mbcset->char_classes[mbcset->nchar_classes++] = __wctype (class_name); -#endif /* RE_ENABLE_I18N */ - -#define BUILD_CHARCLASS_LOOP(ctype_func) \ - do { \ - if (BE (trans != NULL, 0)) \ - { \ - for (i = 0; i < SBC_MAX; ++i) \ - if (ctype_func (i)) \ - bitset_set (sbcset, trans[i]); \ - } \ - else \ - { \ - for (i = 0; i < SBC_MAX; ++i) \ - if (ctype_func (i)) \ - bitset_set (sbcset, i); \ - } \ - } while (0) - - if (strcmp (class_name, "alnum") == 0) - BUILD_CHARCLASS_LOOP (isalnum); - else if (strcmp (class_name, "cntrl") == 0) - BUILD_CHARCLASS_LOOP (iscntrl); - else if (strcmp (class_name, "lower") == 0) - BUILD_CHARCLASS_LOOP (islower); - else if (strcmp (class_name, "space") == 0) - BUILD_CHARCLASS_LOOP (isspace); - else if (strcmp (class_name, "alpha") == 0) - BUILD_CHARCLASS_LOOP (isalpha); - else if (strcmp (class_name, "digit") == 0) - BUILD_CHARCLASS_LOOP (isdigit); - else if (strcmp (class_name, "print") == 0) - BUILD_CHARCLASS_LOOP (isprint); - else if (strcmp (class_name, "upper") == 0) - BUILD_CHARCLASS_LOOP (isupper); - else if (strcmp (class_name, "blank") == 0) -#ifndef GAWK - BUILD_CHARCLASS_LOOP (isblank); -#else - /* see comments above */ - BUILD_CHARCLASS_LOOP (is_blank); -#endif - else if (strcmp (class_name, "graph") == 0) - BUILD_CHARCLASS_LOOP (isgraph); - else if (strcmp (class_name, "punct") == 0) - BUILD_CHARCLASS_LOOP (ispunct); - else if (strcmp (class_name, "xdigit") == 0) - BUILD_CHARCLASS_LOOP (isxdigit); - else - return REG_ECTYPE; - - return REG_NOERROR; -} - -static bin_tree_t * -build_charclass_op (re_dfa_t *dfa, RE_TRANSLATE_TYPE trans, - const char *class_name, - const char *extra, int non_match, - reg_errcode_t *err) -{ - re_bitset_ptr_t sbcset; -#ifdef RE_ENABLE_I18N - re_charset_t *mbcset; - int alloc = 0; -#endif /* not RE_ENABLE_I18N */ - reg_errcode_t ret; - re_token_t br_token; - bin_tree_t *tree; - - sbcset = (re_bitset_ptr_t) calloc (sizeof (bitset_t), 1); -#ifdef RE_ENABLE_I18N - mbcset = (re_charset_t *) calloc (sizeof (re_charset_t), 1); -#endif /* RE_ENABLE_I18N */ - -#ifdef RE_ENABLE_I18N - if (BE (sbcset == NULL || mbcset == NULL, 0)) -#else /* not RE_ENABLE_I18N */ - if (BE (sbcset == NULL, 0)) -#endif /* not RE_ENABLE_I18N */ - { - *err = REG_ESPACE; - return NULL; - } - - if (non_match) - { -#ifdef RE_ENABLE_I18N - mbcset->non_match = 1; -#endif /* not RE_ENABLE_I18N */ - } - - /* We don't care the syntax in this case. */ - ret = build_charclass (trans, sbcset, -#ifdef RE_ENABLE_I18N - mbcset, &alloc, -#endif /* RE_ENABLE_I18N */ - class_name, 0); - - if (BE (ret != REG_NOERROR, 0)) - { - re_free (sbcset); -#ifdef RE_ENABLE_I18N - free_charset (mbcset); -#endif /* RE_ENABLE_I18N */ - *err = ret; - return NULL; - } - /* \w match '_' also. */ - for (; *extra; extra++) - bitset_set (sbcset, *extra); - - /* If it is non-matching list. */ - if (non_match) - bitset_not (sbcset); - -#ifdef RE_ENABLE_I18N - /* Ensure only single byte characters are set. */ - if (dfa->mb_cur_max > 1) - bitset_mask (sbcset, dfa->sb_char); -#endif - - /* Build a tree for simple bracket. */ - br_token.type = SIMPLE_BRACKET; - br_token.opr.sbcset = sbcset; - tree = create_token_tree (dfa, NULL, NULL, &br_token); - if (BE (tree == NULL, 0)) - goto build_word_op_espace; - -#ifdef RE_ENABLE_I18N - if (dfa->mb_cur_max > 1) - { - bin_tree_t *mbc_tree; - /* Build a tree for complex bracket. */ - br_token.type = COMPLEX_BRACKET; - br_token.opr.mbcset = mbcset; - dfa->has_mb_node = 1; - mbc_tree = create_token_tree (dfa, NULL, NULL, &br_token); - if (BE (mbc_tree == NULL, 0)) - goto build_word_op_espace; - /* Then join them by ALT node. */ - tree = create_tree (dfa, tree, mbc_tree, OP_ALT); - if (BE (mbc_tree != NULL, 1)) - return tree; - } - else - { - free_charset (mbcset); - return tree; - } -#else /* not RE_ENABLE_I18N */ - return tree; -#endif /* not RE_ENABLE_I18N */ - - build_word_op_espace: - re_free (sbcset); -#ifdef RE_ENABLE_I18N - free_charset (mbcset); -#endif /* RE_ENABLE_I18N */ - *err = REG_ESPACE; - return NULL; -} - -/* This is intended for the expressions like "a{1,3}". - Fetch a number from `input', and return the number. - Return -1, if the number field is empty like "{,1}". - Return -2, If an error is occured. */ - -static int -fetch_number (re_string_t *input, re_token_t *token, reg_syntax_t syntax) -{ - int num = -1; - unsigned char c; - while (1) - { - fetch_token (token, input, syntax); - c = token->opr.c; - if (BE (token->type == END_OF_RE, 0)) - return -2; - if (token->type == OP_CLOSE_DUP_NUM || c == ',') - break; - num = ((token->type != CHARACTER || c < '0' || '9' < c || num == -2) - ? -2 : ((num == -1) ? c - '0' : num * 10 + c - '0')); - num = (num > RE_DUP_MAX) ? -2 : num; - } - return num; -} - -#ifdef RE_ENABLE_I18N -static void -free_charset (re_charset_t *cset) -{ - re_free (cset->mbchars); -# ifdef _LIBC - re_free (cset->coll_syms); - re_free (cset->equiv_classes); - re_free (cset->range_starts); - re_free (cset->range_ends); -# endif - re_free (cset->char_classes); - re_free (cset); -} -#endif /* RE_ENABLE_I18N */ - -/* Functions for binary tree operation. */ - -/* Create a tree node. */ - -static bin_tree_t * -create_tree (re_dfa_t *dfa, bin_tree_t *left, bin_tree_t *right, - re_token_type_t type) -{ - re_token_t t; - t.type = type; - return create_token_tree (dfa, left, right, &t); -} - -static bin_tree_t * -create_token_tree (re_dfa_t *dfa, bin_tree_t *left, bin_tree_t *right, - const re_token_t *token) -{ - bin_tree_t *tree; - if (BE (dfa->str_tree_storage_idx == BIN_TREE_STORAGE_SIZE, 0)) - { - bin_tree_storage_t *storage = re_malloc (bin_tree_storage_t, 1); - - if (storage == NULL) - return NULL; - storage->next = dfa->str_tree_storage; - dfa->str_tree_storage = storage; - dfa->str_tree_storage_idx = 0; - } - tree = &dfa->str_tree_storage->data[dfa->str_tree_storage_idx++]; - - tree->parent = NULL; - tree->left = left; - tree->right = right; - tree->token = *token; - tree->token.duplicated = 0; - tree->token.opt_subexp = 0; - tree->first = NULL; - tree->next = NULL; - tree->node_idx = -1; - - if (left != NULL) - left->parent = tree; - if (right != NULL) - right->parent = tree; - return tree; -} - -/* Mark the tree SRC as an optional subexpression. - To be called from preorder or postorder. */ - -static reg_errcode_t -mark_opt_subexp (void *extra, bin_tree_t *node) -{ - int idx = (int) (long) extra; - if (node->token.type == SUBEXP && node->token.opr.idx == idx) - node->token.opt_subexp = 1; - - return REG_NOERROR; -} - -/* Free the allocated memory inside NODE. */ - -static void -free_token (re_token_t *node) -{ -#ifdef RE_ENABLE_I18N - if (node->type == COMPLEX_BRACKET && node->duplicated == 0) - free_charset (node->opr.mbcset); - else -#endif /* RE_ENABLE_I18N */ - if (node->type == SIMPLE_BRACKET && node->duplicated == 0) - re_free (node->opr.sbcset); -} - -/* Worker function for tree walking. Free the allocated memory inside NODE - and its children. */ - -static reg_errcode_t -free_tree (UNUSED void *extra, bin_tree_t *node) -{ - free_token (&node->token); - return REG_NOERROR; -} - - -/* Duplicate the node SRC, and return new node. This is a preorder - visit similar to the one implemented by the generic visitor, but - we need more infrastructure to maintain two parallel trees --- so, - it's easier to duplicate. */ - -static bin_tree_t * -duplicate_tree (const bin_tree_t *root, re_dfa_t *dfa) -{ - const bin_tree_t *node; - bin_tree_t *dup_root; - bin_tree_t **p_new = &dup_root, *dup_node = root->parent; - - for (node = root; ; ) - { - /* Create a new tree and link it back to the current parent. */ - *p_new = create_token_tree (dfa, NULL, NULL, &node->token); - if (*p_new == NULL) - return NULL; - (*p_new)->parent = dup_node; - (*p_new)->token.duplicated = 1; - dup_node = *p_new; - - /* Go to the left node, or up and to the right. */ - if (node->left) - { - node = node->left; - p_new = &dup_node->left; - } - else - { - const bin_tree_t *prev = NULL; - while (node->right == prev || node->right == NULL) - { - prev = node; - node = node->parent; - dup_node = dup_node->parent; - if (!node) - return dup_root; - } - node = node->right; - p_new = &dup_node->right; - } - } -} diff --git a/deps/regex/regex.c b/deps/regex/regex.c deleted file mode 100644 index 225a001ee..000000000 --- a/deps/regex/regex.c +++ /dev/null @@ -1,92 +0,0 @@ -/* Extended regular expression matching and search library. - Copyright (C) 2002, 2003, 2005 Free Software Foundation, Inc. - This file is part of the GNU C Library. - Contributed by Isamu Hasegawa . - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, write to the Free - Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301 USA. */ - -#include "config.h" - -/* Make sure noone compiles this code with a C++ compiler. */ -#ifdef __cplusplus -# error "This is C code, use a C compiler" -#endif - -#ifdef _LIBC -/* We have to keep the namespace clean. */ -# define regfree(preg) __regfree (preg) -# define regexec(pr, st, nm, pm, ef) __regexec (pr, st, nm, pm, ef) -# define regcomp(preg, pattern, cflags) __regcomp (preg, pattern, cflags) -# define regerror(errcode, preg, errbuf, errbuf_size) \ - __regerror(errcode, preg, errbuf, errbuf_size) -# define re_set_registers(bu, re, nu, st, en) \ - __re_set_registers (bu, re, nu, st, en) -# define re_match_2(bufp, string1, size1, string2, size2, pos, regs, stop) \ - __re_match_2 (bufp, string1, size1, string2, size2, pos, regs, stop) -# define re_match(bufp, string, size, pos, regs) \ - __re_match (bufp, string, size, pos, regs) -# define re_search(bufp, string, size, startpos, range, regs) \ - __re_search (bufp, string, size, startpos, range, regs) -# define re_compile_pattern(pattern, length, bufp) \ - __re_compile_pattern (pattern, length, bufp) -# define re_set_syntax(syntax) __re_set_syntax (syntax) -# define re_search_2(bufp, st1, s1, st2, s2, startpos, range, regs, stop) \ - __re_search_2 (bufp, st1, s1, st2, s2, startpos, range, regs, stop) -# define re_compile_fastmap(bufp) __re_compile_fastmap (bufp) - -# include "../locale/localeinfo.h" -#endif - -#if defined (_MSC_VER) -#include /* for size_t */ -#endif - -/* On some systems, limits.h sets RE_DUP_MAX to a lower value than - GNU regex allows. Include it before , which correctly - #undefs RE_DUP_MAX and sets it to the right value. */ -#include - -#ifdef GAWK -#undef alloca -#define alloca alloca_is_bad_you_should_never_use_it -#endif -#include -#include "regex_internal.h" - -#include "regex_internal.c" - -#ifdef GAWK -# define bool int - -# ifndef true -# define true (1) -# endif - -# ifndef false -# define false (0) -# endif -#endif -#include "regcomp.c" -#include "regexec.c" - -/* Binary backward compatibility. */ -#if _LIBC -# include -# if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_3) -link_warning (re_max_failures, "the 're_max_failures' variable is obsolete and will go away.") -int re_max_failures = 2000; -# endif -#endif diff --git a/deps/regex/regex.h b/deps/regex/regex.h deleted file mode 100644 index 61c968387..000000000 --- a/deps/regex/regex.h +++ /dev/null @@ -1,582 +0,0 @@ -#include -#include - -/* Definitions for data structures and routines for the regular - expression library. - Copyright (C) 1985,1989-93,1995-98,2000,2001,2002,2003,2005,2006,2008 - Free Software Foundation, Inc. - This file is part of the GNU C Library. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, write to the Free - Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301 USA. */ - -#ifndef _REGEX_H -#define _REGEX_H 1 - -#ifdef HAVE_STDDEF_H -#include -#endif - -#ifdef HAVE_SYS_TYPES_H -#include -#endif - -#ifndef _LIBC -#define __USE_GNU 1 -#endif - -/* Allow the use in C++ code. */ -#ifdef __cplusplus -extern "C" { -#endif - -/* The following two types have to be signed and unsigned integer type - wide enough to hold a value of a pointer. For most ANSI compilers - ptrdiff_t and size_t should be likely OK. Still size of these two - types is 2 for Microsoft C. Ugh... */ -typedef long int s_reg_t; -typedef unsigned long int active_reg_t; - -/* The following bits are used to determine the regexp syntax we - recognize. The set/not-set meanings are chosen so that Emacs syntax - remains the value 0. The bits are given in alphabetical order, and - the definitions shifted by one from the previous bit; thus, when we - add or remove a bit, only one other definition need change. */ -typedef unsigned long int reg_syntax_t; - -#ifdef __USE_GNU -/* If this bit is not set, then \ inside a bracket expression is literal. - If set, then such a \ quotes the following character. */ -# define RE_BACKSLASH_ESCAPE_IN_LISTS ((unsigned long int) 1) - -/* If this bit is not set, then + and ? are operators, and \+ and \? are - literals. - If set, then \+ and \? are operators and + and ? are literals. */ -# define RE_BK_PLUS_QM (RE_BACKSLASH_ESCAPE_IN_LISTS << 1) - -/* If this bit is set, then character classes are supported. They are: - [:alpha:], [:upper:], [:lower:], [:digit:], [:alnum:], [:xdigit:], - [:space:], [:print:], [:punct:], [:graph:], and [:cntrl:]. - If not set, then character classes are not supported. */ -# define RE_CHAR_CLASSES (RE_BK_PLUS_QM << 1) - -/* If this bit is set, then ^ and $ are always anchors (outside bracket - expressions, of course). - If this bit is not set, then it depends: - ^ is an anchor if it is at the beginning of a regular - expression or after an open-group or an alternation operator; - $ is an anchor if it is at the end of a regular expression, or - before a close-group or an alternation operator. - - This bit could be (re)combined with RE_CONTEXT_INDEP_OPS, because - POSIX draft 11.2 says that * etc. in leading positions is undefined. - We already implemented a previous draft which made those constructs - invalid, though, so we haven't changed the code back. */ -# define RE_CONTEXT_INDEP_ANCHORS (RE_CHAR_CLASSES << 1) - -/* If this bit is set, then special characters are always special - regardless of where they are in the pattern. - If this bit is not set, then special characters are special only in - some contexts; otherwise they are ordinary. Specifically, - * + ? and intervals are only special when not after the beginning, - open-group, or alternation operator. */ -# define RE_CONTEXT_INDEP_OPS (RE_CONTEXT_INDEP_ANCHORS << 1) - -/* If this bit is set, then *, +, ?, and { cannot be first in an re or - immediately after an alternation or begin-group operator. */ -# define RE_CONTEXT_INVALID_OPS (RE_CONTEXT_INDEP_OPS << 1) - -/* If this bit is set, then . matches newline. - If not set, then it doesn't. */ -# define RE_DOT_NEWLINE (RE_CONTEXT_INVALID_OPS << 1) - -/* If this bit is set, then . doesn't match NUL. - If not set, then it does. */ -# define RE_DOT_NOT_NULL (RE_DOT_NEWLINE << 1) - -/* If this bit is set, nonmatching lists [^...] do not match newline. - If not set, they do. */ -# define RE_HAT_LISTS_NOT_NEWLINE (RE_DOT_NOT_NULL << 1) - -/* If this bit is set, either \{...\} or {...} defines an - interval, depending on RE_NO_BK_BRACES. - If not set, \{, \}, {, and } are literals. */ -# define RE_INTERVALS (RE_HAT_LISTS_NOT_NEWLINE << 1) - -/* If this bit is set, +, ? and | aren't recognized as operators. - If not set, they are. */ -# define RE_LIMITED_OPS (RE_INTERVALS << 1) - -/* If this bit is set, newline is an alternation operator. - If not set, newline is literal. */ -# define RE_NEWLINE_ALT (RE_LIMITED_OPS << 1) - -/* If this bit is set, then `{...}' defines an interval, and \{ and \} - are literals. - If not set, then `\{...\}' defines an interval. */ -# define RE_NO_BK_BRACES (RE_NEWLINE_ALT << 1) - -/* If this bit is set, (...) defines a group, and \( and \) are literals. - If not set, \(...\) defines a group, and ( and ) are literals. */ -# define RE_NO_BK_PARENS (RE_NO_BK_BRACES << 1) - -/* If this bit is set, then \ matches . - If not set, then \ is a back-reference. */ -# define RE_NO_BK_REFS (RE_NO_BK_PARENS << 1) - -/* If this bit is set, then | is an alternation operator, and \| is literal. - If not set, then \| is an alternation operator, and | is literal. */ -# define RE_NO_BK_VBAR (RE_NO_BK_REFS << 1) - -/* If this bit is set, then an ending range point collating higher - than the starting range point, as in [z-a], is invalid. - If not set, then when ending range point collates higher than the - starting range point, the range is ignored. */ -# define RE_NO_EMPTY_RANGES (RE_NO_BK_VBAR << 1) - -/* If this bit is set, then an unmatched ) is ordinary. - If not set, then an unmatched ) is invalid. */ -# define RE_UNMATCHED_RIGHT_PAREN_ORD (RE_NO_EMPTY_RANGES << 1) - -/* If this bit is set, succeed as soon as we match the whole pattern, - without further backtracking. */ -# define RE_NO_POSIX_BACKTRACKING (RE_UNMATCHED_RIGHT_PAREN_ORD << 1) - -/* If this bit is set, do not process the GNU regex operators. - If not set, then the GNU regex operators are recognized. */ -# define RE_NO_GNU_OPS (RE_NO_POSIX_BACKTRACKING << 1) - -/* If this bit is set, a syntactically invalid interval is treated as - a string of ordinary characters. For example, the ERE 'a{1' is - treated as 'a\{1'. */ -# define RE_INVALID_INTERVAL_ORD (RE_NO_GNU_OPS << 1) - -/* If this bit is set, then ignore case when matching. - If not set, then case is significant. */ -# define RE_ICASE (RE_INVALID_INTERVAL_ORD << 1) - -/* This bit is used internally like RE_CONTEXT_INDEP_ANCHORS but only - for ^, because it is difficult to scan the regex backwards to find - whether ^ should be special. */ -# define RE_CARET_ANCHORS_HERE (RE_ICASE << 1) - -/* If this bit is set, then \{ cannot be first in an bre or - immediately after an alternation or begin-group operator. */ -# define RE_CONTEXT_INVALID_DUP (RE_CARET_ANCHORS_HERE << 1) - -/* If this bit is set, then no_sub will be set to 1 during - re_compile_pattern. */ -#define RE_NO_SUB (RE_CONTEXT_INVALID_DUP << 1) -#endif - -/* This global variable defines the particular regexp syntax to use (for - some interfaces). When a regexp is compiled, the syntax used is - stored in the pattern buffer, so changing this does not affect - already-compiled regexps. */ -extern reg_syntax_t re_syntax_options; - -#ifdef __USE_GNU -/* Define combinations of the above bits for the standard possibilities. - (The [[[ comments delimit what gets put into the Texinfo file, so - don't delete them!) */ -/* [[[begin syntaxes]]] */ -#define RE_SYNTAX_EMACS 0 - -#define RE_SYNTAX_AWK \ - (RE_BACKSLASH_ESCAPE_IN_LISTS | RE_DOT_NOT_NULL \ - | RE_NO_BK_PARENS | RE_NO_BK_REFS \ - | RE_NO_BK_VBAR | RE_NO_EMPTY_RANGES \ - | RE_DOT_NEWLINE | RE_CONTEXT_INDEP_ANCHORS \ - | RE_UNMATCHED_RIGHT_PAREN_ORD | RE_NO_GNU_OPS) - -#define RE_SYNTAX_GNU_AWK \ - ((RE_SYNTAX_POSIX_EXTENDED | RE_BACKSLASH_ESCAPE_IN_LISTS \ - | RE_INVALID_INTERVAL_ORD) \ - & ~(RE_DOT_NOT_NULL | RE_CONTEXT_INDEP_OPS \ - | RE_CONTEXT_INVALID_OPS )) - -#define RE_SYNTAX_POSIX_AWK \ - (RE_SYNTAX_POSIX_EXTENDED | RE_BACKSLASH_ESCAPE_IN_LISTS \ - | RE_INTERVALS | RE_NO_GNU_OPS \ - | RE_INVALID_INTERVAL_ORD) - -#define RE_SYNTAX_GREP \ - (RE_BK_PLUS_QM | RE_CHAR_CLASSES \ - | RE_HAT_LISTS_NOT_NEWLINE | RE_INTERVALS \ - | RE_NEWLINE_ALT) - -#define RE_SYNTAX_EGREP \ - (RE_CHAR_CLASSES | RE_CONTEXT_INDEP_ANCHORS \ - | RE_CONTEXT_INDEP_OPS | RE_HAT_LISTS_NOT_NEWLINE \ - | RE_NEWLINE_ALT | RE_NO_BK_PARENS \ - | RE_NO_BK_VBAR) - -#define RE_SYNTAX_POSIX_EGREP \ - (RE_SYNTAX_EGREP | RE_INTERVALS | RE_NO_BK_BRACES \ - | RE_INVALID_INTERVAL_ORD) - -/* P1003.2/D11.2, section 4.20.7.1, lines 5078ff. */ -#define RE_SYNTAX_ED RE_SYNTAX_POSIX_BASIC - -#define RE_SYNTAX_SED RE_SYNTAX_POSIX_BASIC - -/* Syntax bits common to both basic and extended POSIX regex syntax. */ -#define _RE_SYNTAX_POSIX_COMMON \ - (RE_CHAR_CLASSES | RE_DOT_NEWLINE | RE_DOT_NOT_NULL \ - | RE_INTERVALS | RE_NO_EMPTY_RANGES) - -#define RE_SYNTAX_POSIX_BASIC \ - (_RE_SYNTAX_POSIX_COMMON | RE_BK_PLUS_QM | RE_CONTEXT_INVALID_DUP) - -/* Differs from ..._POSIX_BASIC only in that RE_BK_PLUS_QM becomes - RE_LIMITED_OPS, i.e., \? \+ \| are not recognized. Actually, this - isn't minimal, since other operators, such as \`, aren't disabled. */ -#define RE_SYNTAX_POSIX_MINIMAL_BASIC \ - (_RE_SYNTAX_POSIX_COMMON | RE_LIMITED_OPS) - -#define RE_SYNTAX_POSIX_EXTENDED \ - (_RE_SYNTAX_POSIX_COMMON | RE_CONTEXT_INDEP_ANCHORS \ - | RE_CONTEXT_INDEP_OPS | RE_NO_BK_BRACES \ - | RE_NO_BK_PARENS | RE_NO_BK_VBAR \ - | RE_CONTEXT_INVALID_OPS | RE_UNMATCHED_RIGHT_PAREN_ORD) - -/* Differs from ..._POSIX_EXTENDED in that RE_CONTEXT_INDEP_OPS is - removed and RE_NO_BK_REFS is added. */ -#define RE_SYNTAX_POSIX_MINIMAL_EXTENDED \ - (_RE_SYNTAX_POSIX_COMMON | RE_CONTEXT_INDEP_ANCHORS \ - | RE_CONTEXT_INVALID_OPS | RE_NO_BK_BRACES \ - | RE_NO_BK_PARENS | RE_NO_BK_REFS \ - | RE_NO_BK_VBAR | RE_UNMATCHED_RIGHT_PAREN_ORD) -/* [[[end syntaxes]]] */ - -/* Maximum number of duplicates an interval can allow. Some systems - (erroneously) define this in other header files, but we want our - value, so remove any previous define. */ -# ifdef RE_DUP_MAX -# undef RE_DUP_MAX -# endif -/* If sizeof(int) == 2, then ((1 << 15) - 1) overflows. */ -# define RE_DUP_MAX (0x7fff) -#endif - - -/* POSIX `cflags' bits (i.e., information for `regcomp'). */ - -/* If this bit is set, then use extended regular expression syntax. - If not set, then use basic regular expression syntax. */ -#define REG_EXTENDED 1 - -/* If this bit is set, then ignore case when matching. - If not set, then case is significant. */ -#define REG_ICASE (REG_EXTENDED << 1) - -/* If this bit is set, then anchors do not match at newline - characters in the string. - If not set, then anchors do match at newlines. */ -#define REG_NEWLINE (REG_ICASE << 1) - -/* If this bit is set, then report only success or fail in regexec. - If not set, then returns differ between not matching and errors. */ -#define REG_NOSUB (REG_NEWLINE << 1) - - -/* POSIX `eflags' bits (i.e., information for regexec). */ - -/* If this bit is set, then the beginning-of-line operator doesn't match - the beginning of the string (presumably because it's not the - beginning of a line). - If not set, then the beginning-of-line operator does match the - beginning of the string. */ -#define REG_NOTBOL 1 - -/* Like REG_NOTBOL, except for the end-of-line. */ -#define REG_NOTEOL (1 << 1) - -/* Use PMATCH[0] to delimit the start and end of the search in the - buffer. */ -#define REG_STARTEND (1 << 2) - - -/* If any error codes are removed, changed, or added, update the - `re_error_msg' table in regex.c. */ -typedef enum -{ -#if defined _XOPEN_SOURCE || defined __USE_XOPEN2K - REG_ENOSYS = -1, /* This will never happen for this implementation. */ -#endif - - REG_NOERROR = 0, /* Success. */ - REG_NOMATCH, /* Didn't find a match (for regexec). */ - - /* POSIX regcomp return error codes. (In the order listed in the - standard.) */ - REG_BADPAT, /* Invalid pattern. */ - REG_ECOLLATE, /* Inalid collating element. */ - REG_ECTYPE, /* Invalid character class name. */ - REG_EESCAPE, /* Trailing backslash. */ - REG_ESUBREG, /* Invalid back reference. */ - REG_EBRACK, /* Unmatched left bracket. */ - REG_EPAREN, /* Parenthesis imbalance. */ - REG_EBRACE, /* Unmatched \{. */ - REG_BADBR, /* Invalid contents of \{\}. */ - REG_ERANGE, /* Invalid range end. */ - REG_ESPACE, /* Ran out of memory. */ - REG_BADRPT, /* No preceding re for repetition op. */ - - /* Error codes we've added. */ - REG_EEND, /* Premature end. */ - REG_ESIZE, /* Compiled pattern bigger than 2^16 bytes. */ - REG_ERPAREN /* Unmatched ) or \); not returned from regcomp. */ -} reg_errcode_t; - -/* This data structure represents a compiled pattern. Before calling - the pattern compiler, the fields `buffer', `allocated', `fastmap', - `translate', and `no_sub' can be set. After the pattern has been - compiled, the `re_nsub' field is available. All other fields are - private to the regex routines. */ - -#ifndef RE_TRANSLATE_TYPE -# define __RE_TRANSLATE_TYPE unsigned char * -# ifdef __USE_GNU -# define RE_TRANSLATE_TYPE __RE_TRANSLATE_TYPE -# endif -#endif - -#ifdef __USE_GNU -# define __REPB_PREFIX(name) name -#else -# define __REPB_PREFIX(name) __##name -#endif - -struct re_pattern_buffer -{ - /* Space that holds the compiled pattern. It is declared as - `unsigned char *' because its elements are sometimes used as - array indexes. */ - unsigned char *__REPB_PREFIX(buffer); - - /* Number of bytes to which `buffer' points. */ - unsigned long int __REPB_PREFIX(allocated); - - /* Number of bytes actually used in `buffer'. */ - unsigned long int __REPB_PREFIX(used); - - /* Syntax setting with which the pattern was compiled. */ - reg_syntax_t __REPB_PREFIX(syntax); - - /* Pointer to a fastmap, if any, otherwise zero. re_search uses the - fastmap, if there is one, to skip over impossible starting points - for matches. */ - char *__REPB_PREFIX(fastmap); - - /* Either a translate table to apply to all characters before - comparing them, or zero for no translation. The translation is - applied to a pattern when it is compiled and to a string when it - is matched. */ - __RE_TRANSLATE_TYPE __REPB_PREFIX(translate); - - /* Number of subexpressions found by the compiler. */ - size_t re_nsub; - - /* Zero if this pattern cannot match the empty string, one else. - Well, in truth it's used only in `re_search_2', to see whether or - not we should use the fastmap, so we don't set this absolutely - perfectly; see `re_compile_fastmap' (the `duplicate' case). */ - unsigned __REPB_PREFIX(can_be_null) : 1; - - /* If REGS_UNALLOCATED, allocate space in the `regs' structure - for `max (RE_NREGS, re_nsub + 1)' groups. - If REGS_REALLOCATE, reallocate space if necessary. - If REGS_FIXED, use what's there. */ -#ifdef __USE_GNU -# define REGS_UNALLOCATED 0 -# define REGS_REALLOCATE 1 -# define REGS_FIXED 2 -#endif - unsigned __REPB_PREFIX(regs_allocated) : 2; - - /* Set to zero when `regex_compile' compiles a pattern; set to one - by `re_compile_fastmap' if it updates the fastmap. */ - unsigned __REPB_PREFIX(fastmap_accurate) : 1; - - /* If set, `re_match_2' does not return information about - subexpressions. */ - unsigned __REPB_PREFIX(no_sub) : 1; - - /* If set, a beginning-of-line anchor doesn't match at the beginning - of the string. */ - unsigned __REPB_PREFIX(not_bol) : 1; - - /* Similarly for an end-of-line anchor. */ - unsigned __REPB_PREFIX(not_eol) : 1; - - /* If true, an anchor at a newline matches. */ - unsigned __REPB_PREFIX(newline_anchor) : 1; -}; - -typedef struct re_pattern_buffer regex_t; - -/* Type for byte offsets within the string. POSIX mandates this. */ -typedef int regoff_t; - - -#ifdef __USE_GNU -/* This is the structure we store register match data in. See - regex.texinfo for a full description of what registers match. */ -struct re_registers -{ - unsigned num_regs; - regoff_t *start; - regoff_t *end; -}; - - -/* If `regs_allocated' is REGS_UNALLOCATED in the pattern buffer, - `re_match_2' returns information about at least this many registers - the first time a `regs' structure is passed. */ -# ifndef RE_NREGS -# define RE_NREGS 30 -# endif -#endif - - -/* POSIX specification for registers. Aside from the different names than - `re_registers', POSIX uses an array of structures, instead of a - structure of arrays. */ -typedef struct -{ - regoff_t rm_so; /* Byte offset from string's start to substring's start. */ - regoff_t rm_eo; /* Byte offset from string's start to substring's end. */ -} regmatch_t; - -/* Declarations for routines. */ - -#ifdef __USE_GNU -/* Sets the current default syntax to SYNTAX, and return the old syntax. - You can also simply assign to the `re_syntax_options' variable. */ -extern reg_syntax_t re_set_syntax (reg_syntax_t __syntax); - -/* Compile the regular expression PATTERN, with length LENGTH - and syntax given by the global `re_syntax_options', into the buffer - BUFFER. Return NULL if successful, and an error string if not. */ -extern const char *re_compile_pattern (const char *__pattern, size_t __length, - struct re_pattern_buffer *__buffer); - - -/* Compile a fastmap for the compiled pattern in BUFFER; used to - accelerate searches. Return 0 if successful and -2 if was an - internal error. */ -extern int re_compile_fastmap (struct re_pattern_buffer *__buffer); - - -/* Search in the string STRING (with length LENGTH) for the pattern - compiled into BUFFER. Start searching at position START, for RANGE - characters. Return the starting position of the match, -1 for no - match, or -2 for an internal error. Also return register - information in REGS (if REGS and BUFFER->no_sub are nonzero). */ -extern int re_search (struct re_pattern_buffer *__buffer, const char *__cstring, - int __length, int __start, int __range, - struct re_registers *__regs); - - -/* Like `re_search', but search in the concatenation of STRING1 and - STRING2. Also, stop searching at index START + STOP. */ -extern int re_search_2 (struct re_pattern_buffer *__buffer, - const char *__string1, int __length1, - const char *__string2, int __length2, int __start, - int __range, struct re_registers *__regs, int __stop); - - -/* Like `re_search', but return how many characters in STRING the regexp - in BUFFER matched, starting at position START. */ -extern int re_match (struct re_pattern_buffer *__buffer, const char *__cstring, - int __length, int __start, struct re_registers *__regs); - - -/* Relates to `re_match' as `re_search_2' relates to `re_search'. */ -extern int re_match_2 (struct re_pattern_buffer *__buffer, - const char *__string1, int __length1, - const char *__string2, int __length2, int __start, - struct re_registers *__regs, int __stop); - - -/* Set REGS to hold NUM_REGS registers, storing them in STARTS and - ENDS. Subsequent matches using BUFFER and REGS will use this memory - for recording register information. STARTS and ENDS must be - allocated with malloc, and must each be at least `NUM_REGS * sizeof - (regoff_t)' bytes long. - - If NUM_REGS == 0, then subsequent matches should allocate their own - register data. - - Unless this function is called, the first search or match using - PATTERN_BUFFER will allocate its own register data, without - freeing the old data. */ -extern void re_set_registers (struct re_pattern_buffer *__buffer, - struct re_registers *__regs, - unsigned int __num_regs, - regoff_t *__starts, regoff_t *__ends); -#endif /* Use GNU */ - -#if defined _REGEX_RE_COMP || (defined _LIBC && defined __USE_BSD) -# ifndef _CRAY -/* 4.2 bsd compatibility. */ -extern char *re_comp (const char *); -extern int re_exec (const char *); -# endif -#endif - -/* GCC 2.95 and later have "__restrict"; C99 compilers have - "restrict", and "configure" may have defined "restrict". */ -#ifndef __restrict -# if ! (2 < __GNUC__ || (2 == __GNUC__ && 95 <= __GNUC_MINOR__)) -# if defined restrict || 199901L <= __STDC_VERSION__ -# define __restrict restrict -# else -# define __restrict -# endif -# endif -#endif -/* gcc 3.1 and up support the [restrict] syntax. */ -#ifndef __restrict_arr -# if (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1)) \ - && !defined __GNUG__ -# define __restrict_arr __restrict -# else -# define __restrict_arr -# endif -#endif - -/* POSIX compatibility. */ -extern int regcomp (regex_t *__restrict __preg, - const char *__restrict __pattern, - int __cflags); - -extern int regexec (const regex_t *__restrict __preg, - const char *__restrict __cstring, size_t __nmatch, - regmatch_t __pmatch[__restrict_arr], - int __eflags); - -extern size_t regerror (int __errcode, const regex_t *__restrict __preg, - char *__restrict __errbuf, size_t __errbuf_size); - -extern void regfree (regex_t *__preg); - - -#ifdef __cplusplus -} -#endif /* C++ */ - -#endif /* regex.h */ diff --git a/deps/regex/regex_internal.c b/deps/regex/regex_internal.c deleted file mode 100644 index ad57c20dd..000000000 --- a/deps/regex/regex_internal.c +++ /dev/null @@ -1,1744 +0,0 @@ -/* Extended regular expression matching and search library. - Copyright (C) 2002-2006, 2010 Free Software Foundation, Inc. - This file is part of the GNU C Library. - Contributed by Isamu Hasegawa . - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, write to the Free - Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301 USA. */ - -static void re_string_construct_common (const char *str, int len, - re_string_t *pstr, - RE_TRANSLATE_TYPE trans, int icase, - const re_dfa_t *dfa) internal_function; -static re_dfastate_t *create_ci_newstate (const re_dfa_t *dfa, - const re_node_set *nodes, - unsigned int hash) internal_function; -static re_dfastate_t *create_cd_newstate (const re_dfa_t *dfa, - const re_node_set *nodes, - unsigned int context, - unsigned int hash) internal_function; - -#ifdef GAWK -#undef MAX /* safety */ -static size_t -MAX(size_t a, size_t b) -{ - return (a > b ? a : b); -} -#endif - -/* Functions for string operation. */ - -/* This function allocate the buffers. It is necessary to call - re_string_reconstruct before using the object. */ - -static reg_errcode_t -internal_function -re_string_allocate (re_string_t *pstr, const char *str, int len, int init_len, - RE_TRANSLATE_TYPE trans, int icase, const re_dfa_t *dfa) -{ - reg_errcode_t ret; - int init_buf_len; - - /* Ensure at least one character fits into the buffers. */ - if (init_len < dfa->mb_cur_max) - init_len = dfa->mb_cur_max; - init_buf_len = (len + 1 < init_len) ? len + 1: init_len; - re_string_construct_common (str, len, pstr, trans, icase, dfa); - - ret = re_string_realloc_buffers (pstr, init_buf_len); - if (BE (ret != REG_NOERROR, 0)) - return ret; - - pstr->word_char = dfa->word_char; - pstr->word_ops_used = dfa->word_ops_used; - pstr->mbs = pstr->mbs_allocated ? pstr->mbs : (unsigned char *) str; - pstr->valid_len = (pstr->mbs_allocated || dfa->mb_cur_max > 1) ? 0 : len; - pstr->valid_raw_len = pstr->valid_len; - return REG_NOERROR; -} - -/* This function allocate the buffers, and initialize them. */ - -static reg_errcode_t -internal_function -re_string_construct (re_string_t *pstr, const char *str, int len, - RE_TRANSLATE_TYPE trans, int icase, const re_dfa_t *dfa) -{ - reg_errcode_t ret; - memset (pstr, '\0', sizeof (re_string_t)); - re_string_construct_common (str, len, pstr, trans, icase, dfa); - - if (len > 0) - { - ret = re_string_realloc_buffers (pstr, len + 1); - if (BE (ret != REG_NOERROR, 0)) - return ret; - } - pstr->mbs = pstr->mbs_allocated ? pstr->mbs : (unsigned char *) str; - - if (icase) - { -#ifdef RE_ENABLE_I18N - if (dfa->mb_cur_max > 1) - { - while (1) - { - ret = build_wcs_upper_buffer (pstr); - if (BE (ret != REG_NOERROR, 0)) - return ret; - if (pstr->valid_raw_len >= len) - break; - if (pstr->bufs_len > pstr->valid_len + dfa->mb_cur_max) - break; - ret = re_string_realloc_buffers (pstr, pstr->bufs_len * 2); - if (BE (ret != REG_NOERROR, 0)) - return ret; - } - } - else -#endif /* RE_ENABLE_I18N */ - build_upper_buffer (pstr); - } - else - { -#ifdef RE_ENABLE_I18N - if (dfa->mb_cur_max > 1) - build_wcs_buffer (pstr); - else -#endif /* RE_ENABLE_I18N */ - { - if (trans != NULL) - re_string_translate_buffer (pstr); - else - { - pstr->valid_len = pstr->bufs_len; - pstr->valid_raw_len = pstr->bufs_len; - } - } - } - - return REG_NOERROR; -} - -/* Helper functions for re_string_allocate, and re_string_construct. */ - -static reg_errcode_t -internal_function -re_string_realloc_buffers (re_string_t *pstr, int new_buf_len) -{ -#ifdef RE_ENABLE_I18N - if (pstr->mb_cur_max > 1) - { - wint_t *new_wcs; - - /* Avoid overflow in realloc. */ - const size_t max_object_size = MAX (sizeof (wint_t), sizeof (int)); - if (BE (SIZE_MAX / max_object_size < new_buf_len, 0)) - return REG_ESPACE; - - new_wcs = re_realloc (pstr->wcs, wint_t, new_buf_len); - if (BE (new_wcs == NULL, 0)) - return REG_ESPACE; - pstr->wcs = new_wcs; - if (pstr->offsets != NULL) - { - int *new_offsets = re_realloc (pstr->offsets, int, new_buf_len); - if (BE (new_offsets == NULL, 0)) - return REG_ESPACE; - pstr->offsets = new_offsets; - } - } -#endif /* RE_ENABLE_I18N */ - if (pstr->mbs_allocated) - { - unsigned char *new_mbs = re_realloc (pstr->mbs, unsigned char, - new_buf_len); - if (BE (new_mbs == NULL, 0)) - return REG_ESPACE; - pstr->mbs = new_mbs; - } - pstr->bufs_len = new_buf_len; - return REG_NOERROR; -} - - -static void -internal_function -re_string_construct_common (const char *str, int len, re_string_t *pstr, - RE_TRANSLATE_TYPE trans, int icase, - const re_dfa_t *dfa) -{ - pstr->raw_mbs = (const unsigned char *) str; - pstr->len = len; - pstr->raw_len = len; - pstr->trans = trans; - pstr->icase = icase ? 1 : 0; - pstr->mbs_allocated = (trans != NULL || icase); - pstr->mb_cur_max = dfa->mb_cur_max; - pstr->is_utf8 = dfa->is_utf8; - pstr->map_notascii = dfa->map_notascii; - pstr->stop = pstr->len; - pstr->raw_stop = pstr->stop; -} - -#ifdef RE_ENABLE_I18N - -/* Build wide character buffer PSTR->WCS. - If the byte sequence of the string are: - (0), (1), (0), (1), - Then wide character buffer will be: - , WEOF , , WEOF , - We use WEOF for padding, they indicate that the position isn't - a first byte of a multibyte character. - - Note that this function assumes PSTR->VALID_LEN elements are already - built and starts from PSTR->VALID_LEN. */ - -static void -internal_function -build_wcs_buffer (re_string_t *pstr) -{ -#ifdef _LIBC - unsigned char buf[MB_LEN_MAX]; - assert (MB_LEN_MAX >= pstr->mb_cur_max); -#else - unsigned char buf[64]; -#endif - mbstate_t prev_st; - int byte_idx, end_idx, remain_len; - size_t mbclen; - - /* Build the buffers from pstr->valid_len to either pstr->len or - pstr->bufs_len. */ - end_idx = (pstr->bufs_len > pstr->len) ? pstr->len : pstr->bufs_len; - for (byte_idx = pstr->valid_len; byte_idx < end_idx;) - { - wchar_t wc; - const char *p; - - remain_len = end_idx - byte_idx; - prev_st = pstr->cur_state; - /* Apply the translation if we need. */ - if (BE (pstr->trans != NULL, 0)) - { - int i, ch; - - for (i = 0; i < pstr->mb_cur_max && i < remain_len; ++i) - { - ch = pstr->raw_mbs [pstr->raw_mbs_idx + byte_idx + i]; - buf[i] = pstr->mbs[byte_idx + i] = pstr->trans[ch]; - } - p = (const char *) buf; - } - else - p = (const char *) pstr->raw_mbs + pstr->raw_mbs_idx + byte_idx; - mbclen = __mbrtowc (&wc, p, remain_len, &pstr->cur_state); - if (BE (mbclen == (size_t) -2, 0)) - { - /* The buffer doesn't have enough space, finish to build. */ - pstr->cur_state = prev_st; - break; - } - else if (BE (mbclen == (size_t) -1 || mbclen == 0, 0)) - { - /* We treat these cases as a singlebyte character. */ - mbclen = 1; - wc = (wchar_t) pstr->raw_mbs[pstr->raw_mbs_idx + byte_idx]; - if (BE (pstr->trans != NULL, 0)) - wc = pstr->trans[wc]; - pstr->cur_state = prev_st; - } - - /* Write wide character and padding. */ - pstr->wcs[byte_idx++] = wc; - /* Write paddings. */ - for (remain_len = byte_idx + mbclen - 1; byte_idx < remain_len ;) - pstr->wcs[byte_idx++] = WEOF; - } - pstr->valid_len = byte_idx; - pstr->valid_raw_len = byte_idx; -} - -/* Build wide character buffer PSTR->WCS like build_wcs_buffer, - but for REG_ICASE. */ - -static reg_errcode_t -internal_function -build_wcs_upper_buffer (re_string_t *pstr) -{ - mbstate_t prev_st; - int src_idx, byte_idx, end_idx, remain_len; - size_t mbclen; -#ifdef _LIBC - char buf[MB_LEN_MAX]; - assert (MB_LEN_MAX >= pstr->mb_cur_max); -#else - char buf[64]; -#endif - - byte_idx = pstr->valid_len; - end_idx = (pstr->bufs_len > pstr->len) ? pstr->len : pstr->bufs_len; - - /* The following optimization assumes that ASCII characters can be - mapped to wide characters with a simple cast. */ - if (! pstr->map_notascii && pstr->trans == NULL && !pstr->offsets_needed) - { - while (byte_idx < end_idx) - { - wchar_t wc; - - if (isascii (pstr->raw_mbs[pstr->raw_mbs_idx + byte_idx]) - && mbsinit (&pstr->cur_state)) - { - /* In case of a singlebyte character. */ - pstr->mbs[byte_idx] - = toupper (pstr->raw_mbs[pstr->raw_mbs_idx + byte_idx]); - /* The next step uses the assumption that wchar_t is encoded - ASCII-safe: all ASCII values can be converted like this. */ - pstr->wcs[byte_idx] = (wchar_t) pstr->mbs[byte_idx]; - ++byte_idx; - continue; - } - - remain_len = end_idx - byte_idx; - prev_st = pstr->cur_state; - mbclen = __mbrtowc (&wc, - ((const char *) pstr->raw_mbs + pstr->raw_mbs_idx - + byte_idx), remain_len, &pstr->cur_state); - if (BE (mbclen + 2 > 2, 1)) - { - wchar_t wcu = wc; - if (iswlower (wc)) - { - size_t mbcdlen; - - wcu = towupper (wc); - mbcdlen = wcrtomb (buf, wcu, &prev_st); - if (BE (mbclen == mbcdlen, 1)) - memcpy (pstr->mbs + byte_idx, buf, mbclen); - else - { - src_idx = byte_idx; - goto offsets_needed; - } - } - else - memcpy (pstr->mbs + byte_idx, - pstr->raw_mbs + pstr->raw_mbs_idx + byte_idx, mbclen); - pstr->wcs[byte_idx++] = wcu; - /* Write paddings. */ - for (remain_len = byte_idx + mbclen - 1; byte_idx < remain_len ;) - pstr->wcs[byte_idx++] = WEOF; - } - else if (mbclen == (size_t) -1 || mbclen == 0) - { - /* It is an invalid character or '\0'. Just use the byte. */ - int ch = pstr->raw_mbs[pstr->raw_mbs_idx + byte_idx]; - pstr->mbs[byte_idx] = ch; - /* And also cast it to wide char. */ - pstr->wcs[byte_idx++] = (wchar_t) ch; - if (BE (mbclen == (size_t) -1, 0)) - pstr->cur_state = prev_st; - } - else - { - /* The buffer doesn't have enough space, finish to build. */ - pstr->cur_state = prev_st; - break; - } - } - pstr->valid_len = byte_idx; - pstr->valid_raw_len = byte_idx; - return REG_NOERROR; - } - else - for (src_idx = pstr->valid_raw_len; byte_idx < end_idx;) - { - wchar_t wc; - const char *p; - offsets_needed: - remain_len = end_idx - byte_idx; - prev_st = pstr->cur_state; - if (BE (pstr->trans != NULL, 0)) - { - int i, ch; - - for (i = 0; i < pstr->mb_cur_max && i < remain_len; ++i) - { - ch = pstr->raw_mbs [pstr->raw_mbs_idx + src_idx + i]; - buf[i] = pstr->trans[ch]; - } - p = (const char *) buf; - } - else - p = (const char *) pstr->raw_mbs + pstr->raw_mbs_idx + src_idx; - mbclen = __mbrtowc (&wc, p, remain_len, &pstr->cur_state); - if (BE (mbclen + 2 > 2, 1)) - { - wchar_t wcu = wc; - if (iswlower (wc)) - { - size_t mbcdlen; - - wcu = towupper (wc); - mbcdlen = wcrtomb ((char *) buf, wcu, &prev_st); - if (BE (mbclen == mbcdlen, 1)) - memcpy (pstr->mbs + byte_idx, buf, mbclen); - else if (mbcdlen != (size_t) -1) - { - size_t i; - - if (byte_idx + mbcdlen > pstr->bufs_len) - { - pstr->cur_state = prev_st; - break; - } - - if (pstr->offsets == NULL) - { - pstr->offsets = re_malloc (int, pstr->bufs_len); - - if (pstr->offsets == NULL) - return REG_ESPACE; - } - if (!pstr->offsets_needed) - { - for (i = 0; i < (size_t) byte_idx; ++i) - pstr->offsets[i] = i; - pstr->offsets_needed = 1; - } - - memcpy (pstr->mbs + byte_idx, buf, mbcdlen); - pstr->wcs[byte_idx] = wcu; - pstr->offsets[byte_idx] = src_idx; - for (i = 1; i < mbcdlen; ++i) - { - pstr->offsets[byte_idx + i] - = src_idx + (i < mbclen ? i : mbclen - 1); - pstr->wcs[byte_idx + i] = WEOF; - } - pstr->len += mbcdlen - mbclen; - if (pstr->raw_stop > src_idx) - pstr->stop += mbcdlen - mbclen; - end_idx = (pstr->bufs_len > pstr->len) - ? pstr->len : pstr->bufs_len; - byte_idx += mbcdlen; - src_idx += mbclen; - continue; - } - else - memcpy (pstr->mbs + byte_idx, p, mbclen); - } - else - memcpy (pstr->mbs + byte_idx, p, mbclen); - - if (BE (pstr->offsets_needed != 0, 0)) - { - size_t i; - for (i = 0; i < mbclen; ++i) - pstr->offsets[byte_idx + i] = src_idx + i; - } - src_idx += mbclen; - - pstr->wcs[byte_idx++] = wcu; - /* Write paddings. */ - for (remain_len = byte_idx + mbclen - 1; byte_idx < remain_len ;) - pstr->wcs[byte_idx++] = WEOF; - } - else if (mbclen == (size_t) -1 || mbclen == 0) - { - /* It is an invalid character or '\0'. Just use the byte. */ - int ch = pstr->raw_mbs[pstr->raw_mbs_idx + src_idx]; - - if (BE (pstr->trans != NULL, 0)) - ch = pstr->trans [ch]; - pstr->mbs[byte_idx] = ch; - - if (BE (pstr->offsets_needed != 0, 0)) - pstr->offsets[byte_idx] = src_idx; - ++src_idx; - - /* And also cast it to wide char. */ - pstr->wcs[byte_idx++] = (wchar_t) ch; - if (BE (mbclen == (size_t) -1, 0)) - pstr->cur_state = prev_st; - } - else - { - /* The buffer doesn't have enough space, finish to build. */ - pstr->cur_state = prev_st; - break; - } - } - pstr->valid_len = byte_idx; - pstr->valid_raw_len = src_idx; - return REG_NOERROR; -} - -/* Skip characters until the index becomes greater than NEW_RAW_IDX. - Return the index. */ - -static int -internal_function -re_string_skip_chars (re_string_t *pstr, int new_raw_idx, wint_t *last_wc) -{ - mbstate_t prev_st; - int rawbuf_idx; - size_t mbclen; - wint_t wc = WEOF; - - /* Skip the characters which are not necessary to check. */ - for (rawbuf_idx = pstr->raw_mbs_idx + pstr->valid_raw_len; - rawbuf_idx < new_raw_idx;) - { - wchar_t wc2; - int remain_len = pstr->len - rawbuf_idx; - prev_st = pstr->cur_state; - mbclen = __mbrtowc (&wc2, (const char *) pstr->raw_mbs + rawbuf_idx, - remain_len, &pstr->cur_state); - if (BE (mbclen == (size_t) -2 || mbclen == (size_t) -1 || mbclen == 0, 0)) - { - /* We treat these cases as a single byte character. */ - if (mbclen == 0 || remain_len == 0) - wc = L'\0'; - else - wc = *(unsigned char *) (pstr->raw_mbs + rawbuf_idx); - mbclen = 1; - pstr->cur_state = prev_st; - } - else - wc = (wint_t) wc2; - /* Then proceed the next character. */ - rawbuf_idx += mbclen; - } - *last_wc = (wint_t) wc; - return rawbuf_idx; -} -#endif /* RE_ENABLE_I18N */ - -/* Build the buffer PSTR->MBS, and apply the translation if we need. - This function is used in case of REG_ICASE. */ - -static void -internal_function -build_upper_buffer (re_string_t *pstr) -{ - int char_idx, end_idx; - end_idx = (pstr->bufs_len > pstr->len) ? pstr->len : pstr->bufs_len; - - for (char_idx = pstr->valid_len; char_idx < end_idx; ++char_idx) - { - int ch = pstr->raw_mbs[pstr->raw_mbs_idx + char_idx]; - if (BE (pstr->trans != NULL, 0)) - ch = pstr->trans[ch]; - if (islower (ch)) - pstr->mbs[char_idx] = toupper (ch); - else - pstr->mbs[char_idx] = ch; - } - pstr->valid_len = char_idx; - pstr->valid_raw_len = char_idx; -} - -/* Apply TRANS to the buffer in PSTR. */ - -static void -internal_function -re_string_translate_buffer (re_string_t *pstr) -{ - int buf_idx, end_idx; - end_idx = (pstr->bufs_len > pstr->len) ? pstr->len : pstr->bufs_len; - - for (buf_idx = pstr->valid_len; buf_idx < end_idx; ++buf_idx) - { - int ch = pstr->raw_mbs[pstr->raw_mbs_idx + buf_idx]; - pstr->mbs[buf_idx] = pstr->trans[ch]; - } - - pstr->valid_len = buf_idx; - pstr->valid_raw_len = buf_idx; -} - -/* This function re-construct the buffers. - Concretely, convert to wide character in case of pstr->mb_cur_max > 1, - convert to upper case in case of REG_ICASE, apply translation. */ - -static reg_errcode_t -internal_function -re_string_reconstruct (re_string_t *pstr, int idx, int eflags) -{ - int offset = idx - pstr->raw_mbs_idx; - if (BE (offset < 0, 0)) - { - /* Reset buffer. */ -#ifdef RE_ENABLE_I18N - if (pstr->mb_cur_max > 1) - memset (&pstr->cur_state, '\0', sizeof (mbstate_t)); -#endif /* RE_ENABLE_I18N */ - pstr->len = pstr->raw_len; - pstr->stop = pstr->raw_stop; - pstr->valid_len = 0; - pstr->raw_mbs_idx = 0; - pstr->valid_raw_len = 0; - pstr->offsets_needed = 0; - pstr->tip_context = ((eflags & REG_NOTBOL) ? CONTEXT_BEGBUF - : CONTEXT_NEWLINE | CONTEXT_BEGBUF); - if (!pstr->mbs_allocated) - pstr->mbs = (unsigned char *) pstr->raw_mbs; - offset = idx; - } - - if (BE (offset != 0, 1)) - { - /* Should the already checked characters be kept? */ - if (BE (offset < pstr->valid_raw_len, 1)) - { - /* Yes, move them to the front of the buffer. */ -#ifdef RE_ENABLE_I18N - if (BE (pstr->offsets_needed, 0)) - { - int low = 0, high = pstr->valid_len, mid; - do - { - mid = (high + low) / 2; - if (pstr->offsets[mid] > offset) - high = mid; - else if (pstr->offsets[mid] < offset) - low = mid + 1; - else - break; - } - while (low < high); - if (pstr->offsets[mid] < offset) - ++mid; - pstr->tip_context = re_string_context_at (pstr, mid - 1, - eflags); - /* This can be quite complicated, so handle specially - only the common and easy case where the character with - different length representation of lower and upper - case is present at or after offset. */ - if (pstr->valid_len > offset - && mid == offset && pstr->offsets[mid] == offset) - { - memmove (pstr->wcs, pstr->wcs + offset, - (pstr->valid_len - offset) * sizeof (wint_t)); - memmove (pstr->mbs, pstr->mbs + offset, pstr->valid_len - offset); - pstr->valid_len -= offset; - pstr->valid_raw_len -= offset; - for (low = 0; low < pstr->valid_len; low++) - pstr->offsets[low] = pstr->offsets[low + offset] - offset; - } - else - { - /* Otherwise, just find out how long the partial multibyte - character at offset is and fill it with WEOF/255. */ - pstr->len = pstr->raw_len - idx + offset; - pstr->stop = pstr->raw_stop - idx + offset; - pstr->offsets_needed = 0; - while (mid > 0 && pstr->offsets[mid - 1] == offset) - --mid; - while (mid < pstr->valid_len) - if (pstr->wcs[mid] != WEOF) - break; - else - ++mid; - if (mid == pstr->valid_len) - pstr->valid_len = 0; - else - { - pstr->valid_len = pstr->offsets[mid] - offset; - if (pstr->valid_len) - { - for (low = 0; low < pstr->valid_len; ++low) - pstr->wcs[low] = WEOF; - memset (pstr->mbs, 255, pstr->valid_len); - } - } - pstr->valid_raw_len = pstr->valid_len; - } - } - else -#endif - { - pstr->tip_context = re_string_context_at (pstr, offset - 1, - eflags); -#ifdef RE_ENABLE_I18N - if (pstr->mb_cur_max > 1) - memmove (pstr->wcs, pstr->wcs + offset, - (pstr->valid_len - offset) * sizeof (wint_t)); -#endif /* RE_ENABLE_I18N */ - if (BE (pstr->mbs_allocated, 0)) - memmove (pstr->mbs, pstr->mbs + offset, - pstr->valid_len - offset); - pstr->valid_len -= offset; - pstr->valid_raw_len -= offset; -#if DEBUG - assert (pstr->valid_len > 0); -#endif - } - } - else - { -#ifdef RE_ENABLE_I18N - /* No, skip all characters until IDX. */ - int prev_valid_len = pstr->valid_len; - - if (BE (pstr->offsets_needed, 0)) - { - pstr->len = pstr->raw_len - idx + offset; - pstr->stop = pstr->raw_stop - idx + offset; - pstr->offsets_needed = 0; - } -#endif - pstr->valid_len = 0; -#ifdef RE_ENABLE_I18N - if (pstr->mb_cur_max > 1) - { - int wcs_idx; - wint_t wc = WEOF; - - if (pstr->is_utf8) - { - const unsigned char *raw, *p, *end; - - /* Special case UTF-8. Multi-byte chars start with any - byte other than 0x80 - 0xbf. */ - raw = pstr->raw_mbs + pstr->raw_mbs_idx; - end = raw + (offset - pstr->mb_cur_max); - if (end < pstr->raw_mbs) - end = pstr->raw_mbs; - p = raw + offset - 1; -#ifdef _LIBC - /* We know the wchar_t encoding is UCS4, so for the simple - case, ASCII characters, skip the conversion step. */ - if (isascii (*p) && BE (pstr->trans == NULL, 1)) - { - memset (&pstr->cur_state, '\0', sizeof (mbstate_t)); - /* pstr->valid_len = 0; */ - wc = (wchar_t) *p; - } - else -#endif - for (; p >= end; --p) - if ((*p & 0xc0) != 0x80) - { - mbstate_t cur_state; - wchar_t wc2; - int mlen = raw + pstr->len - p; - unsigned char buf[6]; - size_t mbclen; - - if (BE (pstr->trans != NULL, 0)) - { - int i = mlen < 6 ? mlen : 6; - while (--i >= 0) - buf[i] = pstr->trans[p[i]]; - } - /* XXX Don't use mbrtowc, we know which conversion - to use (UTF-8 -> UCS4). */ - memset (&cur_state, 0, sizeof (cur_state)); - mbclen = __mbrtowc (&wc2, (const char *) p, mlen, - &cur_state); - if (raw + offset - p <= mbclen - && mbclen < (size_t) -2) - { - memset (&pstr->cur_state, '\0', - sizeof (mbstate_t)); - pstr->valid_len = mbclen - (raw + offset - p); - wc = wc2; - } - break; - } - } - - if (wc == WEOF) - pstr->valid_len = re_string_skip_chars (pstr, idx, &wc) - idx; - if (wc == WEOF) - pstr->tip_context - = re_string_context_at (pstr, prev_valid_len - 1, eflags); - else - pstr->tip_context = ((BE (pstr->word_ops_used != 0, 0) - && IS_WIDE_WORD_CHAR (wc)) - ? CONTEXT_WORD - : ((IS_WIDE_NEWLINE (wc) - && pstr->newline_anchor) - ? CONTEXT_NEWLINE : 0)); - if (BE (pstr->valid_len, 0)) - { - for (wcs_idx = 0; wcs_idx < pstr->valid_len; ++wcs_idx) - pstr->wcs[wcs_idx] = WEOF; - if (pstr->mbs_allocated) - memset (pstr->mbs, 255, pstr->valid_len); - } - pstr->valid_raw_len = pstr->valid_len; - } - else -#endif /* RE_ENABLE_I18N */ - { - int c = pstr->raw_mbs[pstr->raw_mbs_idx + offset - 1]; - pstr->valid_raw_len = 0; - if (pstr->trans) - c = pstr->trans[c]; - pstr->tip_context = (bitset_contain (pstr->word_char, c) - ? CONTEXT_WORD - : ((IS_NEWLINE (c) && pstr->newline_anchor) - ? CONTEXT_NEWLINE : 0)); - } - } - if (!BE (pstr->mbs_allocated, 0)) - pstr->mbs += offset; - } - pstr->raw_mbs_idx = idx; - pstr->len -= offset; - pstr->stop -= offset; - - /* Then build the buffers. */ -#ifdef RE_ENABLE_I18N - if (pstr->mb_cur_max > 1) - { - if (pstr->icase) - { - reg_errcode_t ret = build_wcs_upper_buffer (pstr); - if (BE (ret != REG_NOERROR, 0)) - return ret; - } - else - build_wcs_buffer (pstr); - } - else -#endif /* RE_ENABLE_I18N */ - if (BE (pstr->mbs_allocated, 0)) - { - if (pstr->icase) - build_upper_buffer (pstr); - else if (pstr->trans != NULL) - re_string_translate_buffer (pstr); - } - else - pstr->valid_len = pstr->len; - - pstr->cur_idx = 0; - return REG_NOERROR; -} - -static unsigned char -internal_function __attribute ((pure)) -re_string_peek_byte_case (const re_string_t *pstr, int idx) -{ - int ch, off; - - /* Handle the common (easiest) cases first. */ - if (BE (!pstr->mbs_allocated, 1)) - return re_string_peek_byte (pstr, idx); - -#ifdef RE_ENABLE_I18N - if (pstr->mb_cur_max > 1 - && ! re_string_is_single_byte_char (pstr, pstr->cur_idx + idx)) - return re_string_peek_byte (pstr, idx); -#endif - - off = pstr->cur_idx + idx; -#ifdef RE_ENABLE_I18N - if (pstr->offsets_needed) - off = pstr->offsets[off]; -#endif - - ch = pstr->raw_mbs[pstr->raw_mbs_idx + off]; - -#ifdef RE_ENABLE_I18N - /* Ensure that e.g. for tr_TR.UTF-8 BACKSLASH DOTLESS SMALL LETTER I - this function returns CAPITAL LETTER I instead of first byte of - DOTLESS SMALL LETTER I. The latter would confuse the parser, - since peek_byte_case doesn't advance cur_idx in any way. */ - if (pstr->offsets_needed && !isascii (ch)) - return re_string_peek_byte (pstr, idx); -#endif - - return ch; -} - -static unsigned char -internal_function __attribute ((pure)) -re_string_fetch_byte_case (re_string_t *pstr) -{ - if (BE (!pstr->mbs_allocated, 1)) - return re_string_fetch_byte (pstr); - -#ifdef RE_ENABLE_I18N - if (pstr->offsets_needed) - { - int off, ch; - - /* For tr_TR.UTF-8 [[:islower:]] there is - [[: CAPITAL LETTER I WITH DOT lower:]] in mbs. Skip - in that case the whole multi-byte character and return - the original letter. On the other side, with - [[: DOTLESS SMALL LETTER I return [[:I, as doing - anything else would complicate things too much. */ - - if (!re_string_first_byte (pstr, pstr->cur_idx)) - return re_string_fetch_byte (pstr); - - off = pstr->offsets[pstr->cur_idx]; - ch = pstr->raw_mbs[pstr->raw_mbs_idx + off]; - - if (! isascii (ch)) - return re_string_fetch_byte (pstr); - - re_string_skip_bytes (pstr, - re_string_char_size_at (pstr, pstr->cur_idx)); - return ch; - } -#endif - - return pstr->raw_mbs[pstr->raw_mbs_idx + pstr->cur_idx++]; -} - -static void -internal_function -re_string_destruct (re_string_t *pstr) -{ -#ifdef RE_ENABLE_I18N - re_free (pstr->wcs); - re_free (pstr->offsets); -#endif /* RE_ENABLE_I18N */ - if (pstr->mbs_allocated) - re_free (pstr->mbs); -} - -/* Return the context at IDX in INPUT. */ - -static unsigned int -internal_function -re_string_context_at (const re_string_t *input, int idx, int eflags) -{ - int c; - if (BE (idx < 0, 0)) - /* In this case, we use the value stored in input->tip_context, - since we can't know the character in input->mbs[-1] here. */ - return input->tip_context; - if (BE (idx == input->len, 0)) - return ((eflags & REG_NOTEOL) ? CONTEXT_ENDBUF - : CONTEXT_NEWLINE | CONTEXT_ENDBUF); -#ifdef RE_ENABLE_I18N - if (input->mb_cur_max > 1) - { - wint_t wc; - int wc_idx = idx; - while(input->wcs[wc_idx] == WEOF) - { -#ifdef DEBUG - /* It must not happen. */ - assert (wc_idx >= 0); -#endif - --wc_idx; - if (wc_idx < 0) - return input->tip_context; - } - wc = input->wcs[wc_idx]; - if (BE (input->word_ops_used != 0, 0) && IS_WIDE_WORD_CHAR (wc)) - return CONTEXT_WORD; - return (IS_WIDE_NEWLINE (wc) && input->newline_anchor - ? CONTEXT_NEWLINE : 0); - } - else -#endif - { - c = re_string_byte_at (input, idx); - if (bitset_contain (input->word_char, c)) - return CONTEXT_WORD; - return IS_NEWLINE (c) && input->newline_anchor ? CONTEXT_NEWLINE : 0; - } -} - -/* Functions for set operation. */ - -static reg_errcode_t -internal_function -re_node_set_alloc (re_node_set *set, int size) -{ - /* - * ADR: valgrind says size can be 0, which then doesn't - * free the block of size 0. Harumph. This seems - * to work ok, though. - */ - if (size == 0) - { - memset(set, 0, sizeof(*set)); - return REG_NOERROR; - } - set->alloc = size; - set->nelem = 0; - set->elems = re_malloc (int, size); - if (BE (set->elems == NULL, 0)) - return REG_ESPACE; - return REG_NOERROR; -} - -static reg_errcode_t -internal_function -re_node_set_init_1 (re_node_set *set, int elem) -{ - set->alloc = 1; - set->nelem = 1; - set->elems = re_malloc (int, 1); - if (BE (set->elems == NULL, 0)) - { - set->alloc = set->nelem = 0; - return REG_ESPACE; - } - set->elems[0] = elem; - return REG_NOERROR; -} - -static reg_errcode_t -internal_function -re_node_set_init_2 (re_node_set *set, int elem1, int elem2) -{ - set->alloc = 2; - set->elems = re_malloc (int, 2); - if (BE (set->elems == NULL, 0)) - return REG_ESPACE; - if (elem1 == elem2) - { - set->nelem = 1; - set->elems[0] = elem1; - } - else - { - set->nelem = 2; - if (elem1 < elem2) - { - set->elems[0] = elem1; - set->elems[1] = elem2; - } - else - { - set->elems[0] = elem2; - set->elems[1] = elem1; - } - } - return REG_NOERROR; -} - -static reg_errcode_t -internal_function -re_node_set_init_copy (re_node_set *dest, const re_node_set *src) -{ - dest->nelem = src->nelem; - if (src->nelem > 0) - { - dest->alloc = dest->nelem; - dest->elems = re_malloc (int, dest->alloc); - if (BE (dest->elems == NULL, 0)) - { - dest->alloc = dest->nelem = 0; - return REG_ESPACE; - } - memcpy (dest->elems, src->elems, src->nelem * sizeof (int)); - } - else - re_node_set_init_empty (dest); - return REG_NOERROR; -} - -/* Calculate the intersection of the sets SRC1 and SRC2. And merge it to - DEST. Return value indicate the error code or REG_NOERROR if succeeded. - Note: We assume dest->elems is NULL, when dest->alloc is 0. */ - -static reg_errcode_t -internal_function -re_node_set_add_intersect (re_node_set *dest, const re_node_set *src1, - const re_node_set *src2) -{ - int i1, i2, is, id, delta, sbase; - if (src1->nelem == 0 || src2->nelem == 0) - return REG_NOERROR; - - /* We need dest->nelem + 2 * elems_in_intersection; this is a - conservative estimate. */ - if (src1->nelem + src2->nelem + dest->nelem > dest->alloc) - { - int new_alloc = src1->nelem + src2->nelem + dest->alloc; - int *new_elems = re_realloc (dest->elems, int, new_alloc); - if (BE (new_elems == NULL, 0)) - return REG_ESPACE; - dest->elems = new_elems; - dest->alloc = new_alloc; - } - - /* Find the items in the intersection of SRC1 and SRC2, and copy - into the top of DEST those that are not already in DEST itself. */ - sbase = dest->nelem + src1->nelem + src2->nelem; - i1 = src1->nelem - 1; - i2 = src2->nelem - 1; - id = dest->nelem - 1; - for (;;) - { - if (src1->elems[i1] == src2->elems[i2]) - { - /* Try to find the item in DEST. Maybe we could binary search? */ - while (id >= 0 && dest->elems[id] > src1->elems[i1]) - --id; - - if (id < 0 || dest->elems[id] != src1->elems[i1]) - dest->elems[--sbase] = src1->elems[i1]; - - if (--i1 < 0 || --i2 < 0) - break; - } - - /* Lower the highest of the two items. */ - else if (src1->elems[i1] < src2->elems[i2]) - { - if (--i2 < 0) - break; - } - else - { - if (--i1 < 0) - break; - } - } - - id = dest->nelem - 1; - is = dest->nelem + src1->nelem + src2->nelem - 1; - delta = is - sbase + 1; - - /* Now copy. When DELTA becomes zero, the remaining - DEST elements are already in place; this is more or - less the same loop that is in re_node_set_merge. */ - dest->nelem += delta; - if (delta > 0 && id >= 0) - for (;;) - { - if (dest->elems[is] > dest->elems[id]) - { - /* Copy from the top. */ - dest->elems[id + delta--] = dest->elems[is--]; - if (delta == 0) - break; - } - else - { - /* Slide from the bottom. */ - dest->elems[id + delta] = dest->elems[id]; - if (--id < 0) - break; - } - } - - /* Copy remaining SRC elements. */ - memcpy (dest->elems, dest->elems + sbase, delta * sizeof (int)); - - return REG_NOERROR; -} - -/* Calculate the union set of the sets SRC1 and SRC2. And store it to - DEST. Return value indicate the error code or REG_NOERROR if succeeded. */ - -static reg_errcode_t -internal_function -re_node_set_init_union (re_node_set *dest, const re_node_set *src1, - const re_node_set *src2) -{ - int i1, i2, id; - if (src1 != NULL && src1->nelem > 0 && src2 != NULL && src2->nelem > 0) - { - dest->alloc = src1->nelem + src2->nelem; - dest->elems = re_malloc (int, dest->alloc); - if (BE (dest->elems == NULL, 0)) - return REG_ESPACE; - } - else - { - if (src1 != NULL && src1->nelem > 0) - return re_node_set_init_copy (dest, src1); - else if (src2 != NULL && src2->nelem > 0) - return re_node_set_init_copy (dest, src2); - else - re_node_set_init_empty (dest); - return REG_NOERROR; - } - for (i1 = i2 = id = 0 ; i1 < src1->nelem && i2 < src2->nelem ;) - { - if (src1->elems[i1] > src2->elems[i2]) - { - dest->elems[id++] = src2->elems[i2++]; - continue; - } - if (src1->elems[i1] == src2->elems[i2]) - ++i2; - dest->elems[id++] = src1->elems[i1++]; - } - if (i1 < src1->nelem) - { - memcpy (dest->elems + id, src1->elems + i1, - (src1->nelem - i1) * sizeof (int)); - id += src1->nelem - i1; - } - else if (i2 < src2->nelem) - { - memcpy (dest->elems + id, src2->elems + i2, - (src2->nelem - i2) * sizeof (int)); - id += src2->nelem - i2; - } - dest->nelem = id; - return REG_NOERROR; -} - -/* Calculate the union set of the sets DEST and SRC. And store it to - DEST. Return value indicate the error code or REG_NOERROR if succeeded. */ - -static reg_errcode_t -internal_function -re_node_set_merge (re_node_set *dest, const re_node_set *src) -{ - int is, id, sbase, delta; - if (src == NULL || src->nelem == 0) - return REG_NOERROR; - if (dest->alloc < 2 * src->nelem + dest->nelem) - { - int new_alloc = 2 * (src->nelem + dest->alloc); - int *new_buffer = re_realloc (dest->elems, int, new_alloc); - if (BE (new_buffer == NULL, 0)) - return REG_ESPACE; - dest->elems = new_buffer; - dest->alloc = new_alloc; - } - - if (BE (dest->nelem == 0, 0)) - { - dest->nelem = src->nelem; - memcpy (dest->elems, src->elems, src->nelem * sizeof (int)); - return REG_NOERROR; - } - - /* Copy into the top of DEST the items of SRC that are not - found in DEST. Maybe we could binary search in DEST? */ - for (sbase = dest->nelem + 2 * src->nelem, - is = src->nelem - 1, id = dest->nelem - 1; is >= 0 && id >= 0; ) - { - if (dest->elems[id] == src->elems[is]) - is--, id--; - else if (dest->elems[id] < src->elems[is]) - dest->elems[--sbase] = src->elems[is--]; - else /* if (dest->elems[id] > src->elems[is]) */ - --id; - } - - if (is >= 0) - { - /* If DEST is exhausted, the remaining items of SRC must be unique. */ - sbase -= is + 1; - memcpy (dest->elems + sbase, src->elems, (is + 1) * sizeof (int)); - } - - id = dest->nelem - 1; - is = dest->nelem + 2 * src->nelem - 1; - delta = is - sbase + 1; - if (delta == 0) - return REG_NOERROR; - - /* Now copy. When DELTA becomes zero, the remaining - DEST elements are already in place. */ - dest->nelem += delta; - for (;;) - { - if (dest->elems[is] > dest->elems[id]) - { - /* Copy from the top. */ - dest->elems[id + delta--] = dest->elems[is--]; - if (delta == 0) - break; - } - else - { - /* Slide from the bottom. */ - dest->elems[id + delta] = dest->elems[id]; - if (--id < 0) - { - /* Copy remaining SRC elements. */ - memcpy (dest->elems, dest->elems + sbase, - delta * sizeof (int)); - break; - } - } - } - - return REG_NOERROR; -} - -/* Insert the new element ELEM to the re_node_set* SET. - SET should not already have ELEM. - return -1 if an error is occured, return 1 otherwise. */ - -static int -internal_function -re_node_set_insert (re_node_set *set, int elem) -{ - int idx; - /* In case the set is empty. */ - if (set->alloc == 0) - { - if (BE (re_node_set_init_1 (set, elem) == REG_NOERROR, 1)) - return 1; - else - return -1; - } - - if (BE (set->nelem, 0) == 0) - { - /* We already guaranteed above that set->alloc != 0. */ - set->elems[0] = elem; - ++set->nelem; - return 1; - } - - /* Realloc if we need. */ - if (set->alloc == set->nelem) - { - int *new_elems; - set->alloc = set->alloc * 2; - new_elems = re_realloc (set->elems, int, set->alloc); - if (BE (new_elems == NULL, 0)) - return -1; - set->elems = new_elems; - } - - /* Move the elements which follows the new element. Test the - first element separately to skip a check in the inner loop. */ - if (elem < set->elems[0]) - { - idx = 0; - for (idx = set->nelem; idx > 0; idx--) - set->elems[idx] = set->elems[idx - 1]; - } - else - { - for (idx = set->nelem; set->elems[idx - 1] > elem; idx--) - set->elems[idx] = set->elems[idx - 1]; - } - - /* Insert the new element. */ - set->elems[idx] = elem; - ++set->nelem; - return 1; -} - -/* Insert the new element ELEM to the re_node_set* SET. - SET should not already have any element greater than or equal to ELEM. - Return -1 if an error is occured, return 1 otherwise. */ - -static int -internal_function -re_node_set_insert_last (re_node_set *set, int elem) -{ - /* Realloc if we need. */ - if (set->alloc == set->nelem) - { - int *new_elems; - set->alloc = (set->alloc + 1) * 2; - new_elems = re_realloc (set->elems, int, set->alloc); - if (BE (new_elems == NULL, 0)) - return -1; - set->elems = new_elems; - } - - /* Insert the new element. */ - set->elems[set->nelem++] = elem; - return 1; -} - -/* Compare two node sets SET1 and SET2. - return 1 if SET1 and SET2 are equivalent, return 0 otherwise. */ - -static int -internal_function __attribute ((pure)) -re_node_set_compare (const re_node_set *set1, const re_node_set *set2) -{ - int i; - if (set1 == NULL || set2 == NULL || set1->nelem != set2->nelem) - return 0; - for (i = set1->nelem ; --i >= 0 ; ) - if (set1->elems[i] != set2->elems[i]) - return 0; - return 1; -} - -/* Return (idx + 1) if SET contains the element ELEM, return 0 otherwise. */ - -static int -internal_function __attribute ((pure)) -re_node_set_contains (const re_node_set *set, int elem) -{ - unsigned int idx, right, mid; - if (set->nelem <= 0) - return 0; - - /* Binary search the element. */ - idx = 0; - right = set->nelem - 1; - while (idx < right) - { - mid = (idx + right) / 2; - if (set->elems[mid] < elem) - idx = mid + 1; - else - right = mid; - } - return set->elems[idx] == elem ? idx + 1 : 0; -} - -static void -internal_function -re_node_set_remove_at (re_node_set *set, int idx) -{ - if (idx < 0 || idx >= set->nelem) - return; - --set->nelem; - for (; idx < set->nelem; idx++) - set->elems[idx] = set->elems[idx + 1]; -} - - -/* Add the token TOKEN to dfa->nodes, and return the index of the token. - Or return -1, if an error will be occured. */ - -static int -internal_function -re_dfa_add_node (re_dfa_t *dfa, re_token_t token) -{ - if (BE (dfa->nodes_len >= dfa->nodes_alloc, 0)) - { - size_t new_nodes_alloc = dfa->nodes_alloc * 2; - int *new_nexts, *new_indices; - re_node_set *new_edests, *new_eclosures; - re_token_t *new_nodes; - - /* Avoid overflows in realloc. */ - const size_t max_object_size = MAX (sizeof (re_token_t), - MAX (sizeof (re_node_set), - sizeof (int))); - if (BE (SIZE_MAX / max_object_size < new_nodes_alloc, 0)) - return -1; - - new_nodes = re_realloc (dfa->nodes, re_token_t, new_nodes_alloc); - if (BE (new_nodes == NULL, 0)) - return -1; - dfa->nodes = new_nodes; - new_nexts = re_realloc (dfa->nexts, int, new_nodes_alloc); - new_indices = re_realloc (dfa->org_indices, int, new_nodes_alloc); - new_edests = re_realloc (dfa->edests, re_node_set, new_nodes_alloc); - new_eclosures = re_realloc (dfa->eclosures, re_node_set, new_nodes_alloc); - if (BE (new_nexts == NULL || new_indices == NULL - || new_edests == NULL || new_eclosures == NULL, 0)) - return -1; - dfa->nexts = new_nexts; - dfa->org_indices = new_indices; - dfa->edests = new_edests; - dfa->eclosures = new_eclosures; - dfa->nodes_alloc = new_nodes_alloc; - } - dfa->nodes[dfa->nodes_len] = token; - dfa->nodes[dfa->nodes_len].constraint = 0; -#ifdef RE_ENABLE_I18N - dfa->nodes[dfa->nodes_len].accept_mb = - (token.type == OP_PERIOD && dfa->mb_cur_max > 1) || token.type == COMPLEX_BRACKET; -#endif - dfa->nexts[dfa->nodes_len] = -1; - re_node_set_init_empty (dfa->edests + dfa->nodes_len); - re_node_set_init_empty (dfa->eclosures + dfa->nodes_len); - return dfa->nodes_len++; -} - -static inline unsigned int -internal_function -calc_state_hash (const re_node_set *nodes, unsigned int context) -{ - unsigned int hash = nodes->nelem + context; - int i; - for (i = 0 ; i < nodes->nelem ; i++) - hash += nodes->elems[i]; - return hash; -} - -/* Search for the state whose node_set is equivalent to NODES. - Return the pointer to the state, if we found it in the DFA. - Otherwise create the new one and return it. In case of an error - return NULL and set the error code in ERR. - Note: - We assume NULL as the invalid state, then it is possible that - return value is NULL and ERR is REG_NOERROR. - - We never return non-NULL value in case of any errors, it is for - optimization. */ - -static re_dfastate_t * -internal_function -re_acquire_state (reg_errcode_t *err, const re_dfa_t *dfa, - const re_node_set *nodes) -{ - unsigned int hash; - re_dfastate_t *new_state; - struct re_state_table_entry *spot; - int i; - if (BE (nodes->nelem == 0, 0)) - { - *err = REG_NOERROR; - return NULL; - } - hash = calc_state_hash (nodes, 0); - spot = dfa->state_table + (hash & dfa->state_hash_mask); - - for (i = 0 ; i < spot->num ; i++) - { - re_dfastate_t *state = spot->array[i]; - if (hash != state->hash) - continue; - if (re_node_set_compare (&state->nodes, nodes)) - return state; - } - - /* There are no appropriate state in the dfa, create the new one. */ - new_state = create_ci_newstate (dfa, nodes, hash); - if (BE (new_state == NULL, 0)) - *err = REG_ESPACE; - - return new_state; -} - -/* Search for the state whose node_set is equivalent to NODES and - whose context is equivalent to CONTEXT. - Return the pointer to the state, if we found it in the DFA. - Otherwise create the new one and return it. In case of an error - return NULL and set the error code in ERR. - Note: - We assume NULL as the invalid state, then it is possible that - return value is NULL and ERR is REG_NOERROR. - - We never return non-NULL value in case of any errors, it is for - optimization. */ - -static re_dfastate_t * -internal_function -re_acquire_state_context (reg_errcode_t *err, const re_dfa_t *dfa, - const re_node_set *nodes, unsigned int context) -{ - unsigned int hash; - re_dfastate_t *new_state; - struct re_state_table_entry *spot; - int i; - if (nodes->nelem == 0) - { - *err = REG_NOERROR; - return NULL; - } - hash = calc_state_hash (nodes, context); - spot = dfa->state_table + (hash & dfa->state_hash_mask); - - for (i = 0 ; i < spot->num ; i++) - { - re_dfastate_t *state = spot->array[i]; - if (state->hash == hash - && state->context == context - && re_node_set_compare (state->entrance_nodes, nodes)) - return state; - } - /* There are no appropriate state in `dfa', create the new one. */ - new_state = create_cd_newstate (dfa, nodes, context, hash); - if (BE (new_state == NULL, 0)) - *err = REG_ESPACE; - - return new_state; -} - -/* Finish initialization of the new state NEWSTATE, and using its hash value - HASH put in the appropriate bucket of DFA's state table. Return value - indicates the error code if failed. */ - -static reg_errcode_t -register_state (const re_dfa_t *dfa, re_dfastate_t *newstate, - unsigned int hash) -{ - struct re_state_table_entry *spot; - reg_errcode_t err; - int i; - - newstate->hash = hash; - err = re_node_set_alloc (&newstate->non_eps_nodes, newstate->nodes.nelem); - if (BE (err != REG_NOERROR, 0)) - return REG_ESPACE; - for (i = 0; i < newstate->nodes.nelem; i++) - { - int elem = newstate->nodes.elems[i]; - if (!IS_EPSILON_NODE (dfa->nodes[elem].type)) - if (re_node_set_insert_last (&newstate->non_eps_nodes, elem) < 0) - return REG_ESPACE; - } - - spot = dfa->state_table + (hash & dfa->state_hash_mask); - if (BE (spot->alloc <= spot->num, 0)) - { - int new_alloc = 2 * spot->num + 2; - re_dfastate_t **new_array = re_realloc (spot->array, re_dfastate_t *, - new_alloc); - if (BE (new_array == NULL, 0)) - return REG_ESPACE; - spot->array = new_array; - spot->alloc = new_alloc; - } - spot->array[spot->num++] = newstate; - return REG_NOERROR; -} - -static void -free_state (re_dfastate_t *state) -{ - re_node_set_free (&state->non_eps_nodes); - re_node_set_free (&state->inveclosure); - if (state->entrance_nodes != &state->nodes) - { - re_node_set_free (state->entrance_nodes); - re_free (state->entrance_nodes); - } - re_node_set_free (&state->nodes); - re_free (state->word_trtable); - re_free (state->trtable); - re_free (state); -} - -/* Create the new state which is independ of contexts. - Return the new state if succeeded, otherwise return NULL. */ - -static re_dfastate_t * -internal_function -create_ci_newstate (const re_dfa_t *dfa, const re_node_set *nodes, - unsigned int hash) -{ - int i; - reg_errcode_t err; - re_dfastate_t *newstate; - - newstate = (re_dfastate_t *) calloc (sizeof (re_dfastate_t), 1); - if (BE (newstate == NULL, 0)) - return NULL; - err = re_node_set_init_copy (&newstate->nodes, nodes); - if (BE (err != REG_NOERROR, 0)) - { - re_free (newstate); - return NULL; - } - - newstate->entrance_nodes = &newstate->nodes; - for (i = 0 ; i < nodes->nelem ; i++) - { - re_token_t *node = dfa->nodes + nodes->elems[i]; - re_token_type_t type = node->type; - if (type == CHARACTER && !node->constraint) - continue; -#ifdef RE_ENABLE_I18N - newstate->accept_mb |= node->accept_mb; -#endif /* RE_ENABLE_I18N */ - - /* If the state has the halt node, the state is a halt state. */ - if (type == END_OF_RE) - newstate->halt = 1; - else if (type == OP_BACK_REF) - newstate->has_backref = 1; - else if (type == ANCHOR || node->constraint) - newstate->has_constraint = 1; - } - err = register_state (dfa, newstate, hash); - if (BE (err != REG_NOERROR, 0)) - { - free_state (newstate); - newstate = NULL; - } - return newstate; -} - -/* Create the new state which is depend on the context CONTEXT. - Return the new state if succeeded, otherwise return NULL. */ - -static re_dfastate_t * -internal_function -create_cd_newstate (const re_dfa_t *dfa, const re_node_set *nodes, - unsigned int context, unsigned int hash) -{ - int i, nctx_nodes = 0; - reg_errcode_t err; - re_dfastate_t *newstate; - - newstate = (re_dfastate_t *) calloc (sizeof (re_dfastate_t), 1); - if (BE (newstate == NULL, 0)) - return NULL; - err = re_node_set_init_copy (&newstate->nodes, nodes); - if (BE (err != REG_NOERROR, 0)) - { - re_free (newstate); - return NULL; - } - - newstate->context = context; - newstate->entrance_nodes = &newstate->nodes; - - for (i = 0 ; i < nodes->nelem ; i++) - { - re_token_t *node = dfa->nodes + nodes->elems[i]; - re_token_type_t type = node->type; - unsigned int constraint = node->constraint; - - if (type == CHARACTER && !constraint) - continue; -#ifdef RE_ENABLE_I18N - newstate->accept_mb |= node->accept_mb; -#endif /* RE_ENABLE_I18N */ - - /* If the state has the halt node, the state is a halt state. */ - if (type == END_OF_RE) - newstate->halt = 1; - else if (type == OP_BACK_REF) - newstate->has_backref = 1; - - if (constraint) - { - if (newstate->entrance_nodes == &newstate->nodes) - { - newstate->entrance_nodes = re_malloc (re_node_set, 1); - if (BE (newstate->entrance_nodes == NULL, 0)) - { - free_state (newstate); - return NULL; - } - if (re_node_set_init_copy (newstate->entrance_nodes, nodes) - != REG_NOERROR) - return NULL; - nctx_nodes = 0; - newstate->has_constraint = 1; - } - - if (NOT_SATISFY_PREV_CONSTRAINT (constraint,context)) - { - re_node_set_remove_at (&newstate->nodes, i - nctx_nodes); - ++nctx_nodes; - } - } - } - err = register_state (dfa, newstate, hash); - if (BE (err != REG_NOERROR, 0)) - { - free_state (newstate); - newstate = NULL; - } - return newstate; -} diff --git a/deps/regex/regex_internal.h b/deps/regex/regex_internal.h deleted file mode 100644 index 53ccebecd..000000000 --- a/deps/regex/regex_internal.h +++ /dev/null @@ -1,819 +0,0 @@ -/* Extended regular expression matching and search library. - Copyright (C) 2002-2005, 2007, 2008, 2010 Free Software Foundation, Inc. - This file is part of the GNU C Library. - Contributed by Isamu Hasegawa . - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, write to the Free - Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307 USA. */ - -#ifndef _REGEX_INTERNAL_H -#define _REGEX_INTERNAL_H 1 - -#include -#include -#include -#include -#include - -#ifndef UNUSED -# ifdef __GNUC__ -# define UNUSED __attribute__((unused)) -# else -# define UNUSED -# endif -#endif - -#if defined HAVE_LANGINFO_H || defined HAVE_LANGINFO_CODESET || defined _LIBC -# include -#endif -#if defined HAVE_LOCALE_H || defined _LIBC -# include -#endif -#if defined HAVE_WCHAR_H || defined _LIBC -# include -#endif /* HAVE_WCHAR_H || _LIBC */ -#if defined HAVE_WCTYPE_H || defined _LIBC -# include -#endif /* HAVE_WCTYPE_H || _LIBC */ -#if defined HAVE_STDBOOL_H || defined _LIBC -# include -#endif /* HAVE_STDBOOL_H || _LIBC */ -#if !defined(ZOS_USS) -#if defined HAVE_STDINT_H || defined _LIBC -# include -#endif /* HAVE_STDINT_H || _LIBC */ -#endif /* !ZOS_USS */ -#if defined _LIBC -# include -#else -# define __libc_lock_define(CLASS,NAME) -# define __libc_lock_init(NAME) do { } while (0) -# define __libc_lock_lock(NAME) do { } while (0) -# define __libc_lock_unlock(NAME) do { } while (0) -#endif - -#ifndef GAWK -/* In case that the system doesn't have isblank(). */ -#if !defined _LIBC && !defined HAVE_ISBLANK && !defined isblank -# define isblank(ch) ((ch) == ' ' || (ch) == '\t') -#endif -#else /* GAWK */ -/* - * This is a mess. On glibc systems you have to define - * a magic constant to get isblank() out of , since it's - * a C99 function. To heck with all that and borrow a page from - * dfa.c's book. - */ - -static int -is_blank (int c) -{ - return (c == ' ' || c == '\t'); -} -#endif /* GAWK */ - -#ifdef _LIBC -# ifndef _RE_DEFINE_LOCALE_FUNCTIONS -# define _RE_DEFINE_LOCALE_FUNCTIONS 1 -# include -# include -# include -# endif -#endif - -/* This is for other GNU distributions with internationalized messages. */ -#if (HAVE_LIBINTL_H && ENABLE_NLS) || defined _LIBC -# include -# ifdef _LIBC -# undef gettext -# define gettext(msgid) \ - INTUSE(__dcgettext) (_libc_intl_domainname, msgid, LC_MESSAGES) -# endif -#else -# define gettext(msgid) (msgid) -#endif - -#ifndef gettext_noop -/* This define is so xgettext can find the internationalizable - strings. */ -# define gettext_noop(String) String -#endif - -/* For loser systems without the definition. */ -#ifndef SIZE_MAX -# define SIZE_MAX ((size_t) -1) -#endif - -#ifndef NO_MBSUPPORT -#include "mbsupport.h" /* gawk */ -#endif -#ifndef MB_CUR_MAX -#define MB_CUR_MAX 1 -#endif - -#if (defined MBS_SUPPORT) || _LIBC -# define RE_ENABLE_I18N -#endif - -#if __GNUC__ >= 3 -# define BE(expr, val) __builtin_expect (expr, val) -#else -# define BE(expr, val) (expr) -# ifdef inline -# undef inline -# endif -# define inline -#endif - -/* Number of single byte character. */ -#define SBC_MAX 256 - -#define COLL_ELEM_LEN_MAX 8 - -/* The character which represents newline. */ -#define NEWLINE_CHAR '\n' -#define WIDE_NEWLINE_CHAR L'\n' - -/* Rename to standard API for using out of glibc. */ -#ifndef _LIBC -# ifdef __wctype -# undef __wctype -# endif -# define __wctype wctype -# ifdef __iswctype -# undef __iswctype -# endif -# define __iswctype iswctype -# define __btowc btowc -# define __mbrtowc mbrtowc -#undef __mempcpy /* GAWK */ -# define __mempcpy mempcpy -# define __wcrtomb wcrtomb -# define __regfree regfree -# define attribute_hidden -#endif /* not _LIBC */ - -#ifdef __GNUC__ -# define __attribute(arg) __attribute__ (arg) -#else -# define __attribute(arg) -#endif - -extern const char __re_error_msgid[] attribute_hidden; -extern const size_t __re_error_msgid_idx[] attribute_hidden; - -/* An integer used to represent a set of bits. It must be unsigned, - and must be at least as wide as unsigned int. */ -typedef unsigned long int bitset_word_t; -/* All bits set in a bitset_word_t. */ -#define BITSET_WORD_MAX ULONG_MAX -/* Number of bits in a bitset_word_t. Cast to int as most code use it - * like that for counting */ -#define BITSET_WORD_BITS ((int)(sizeof (bitset_word_t) * CHAR_BIT)) -/* Number of bitset_word_t in a bit_set. */ -#define BITSET_WORDS (SBC_MAX / BITSET_WORD_BITS) -typedef bitset_word_t bitset_t[BITSET_WORDS]; -typedef bitset_word_t *re_bitset_ptr_t; -typedef const bitset_word_t *re_const_bitset_ptr_t; - -#define bitset_set(set,i) \ - (set[i / BITSET_WORD_BITS] |= (bitset_word_t) 1 << i % BITSET_WORD_BITS) -#define bitset_clear(set,i) \ - (set[i / BITSET_WORD_BITS] &= ~((bitset_word_t) 1 << i % BITSET_WORD_BITS)) -#define bitset_contain(set,i) \ - (set[i / BITSET_WORD_BITS] & ((bitset_word_t) 1 << i % BITSET_WORD_BITS)) -#define bitset_empty(set) memset (set, '\0', sizeof (bitset_t)) -#define bitset_set_all(set) memset (set, '\xff', sizeof (bitset_t)) -#define bitset_copy(dest,src) memcpy (dest, src, sizeof (bitset_t)) - -#define PREV_WORD_CONSTRAINT 0x0001 -#define PREV_NOTWORD_CONSTRAINT 0x0002 -#define NEXT_WORD_CONSTRAINT 0x0004 -#define NEXT_NOTWORD_CONSTRAINT 0x0008 -#define PREV_NEWLINE_CONSTRAINT 0x0010 -#define NEXT_NEWLINE_CONSTRAINT 0x0020 -#define PREV_BEGBUF_CONSTRAINT 0x0040 -#define NEXT_ENDBUF_CONSTRAINT 0x0080 -#define WORD_DELIM_CONSTRAINT 0x0100 -#define NOT_WORD_DELIM_CONSTRAINT 0x0200 - -typedef enum -{ - INSIDE_WORD = PREV_WORD_CONSTRAINT | NEXT_WORD_CONSTRAINT, - WORD_FIRST = PREV_NOTWORD_CONSTRAINT | NEXT_WORD_CONSTRAINT, - WORD_LAST = PREV_WORD_CONSTRAINT | NEXT_NOTWORD_CONSTRAINT, - INSIDE_NOTWORD = PREV_NOTWORD_CONSTRAINT | NEXT_NOTWORD_CONSTRAINT, - LINE_FIRST = PREV_NEWLINE_CONSTRAINT, - LINE_LAST = NEXT_NEWLINE_CONSTRAINT, - BUF_FIRST = PREV_BEGBUF_CONSTRAINT, - BUF_LAST = NEXT_ENDBUF_CONSTRAINT, - WORD_DELIM = WORD_DELIM_CONSTRAINT, - NOT_WORD_DELIM = NOT_WORD_DELIM_CONSTRAINT -} re_context_type; - -typedef struct -{ - int alloc; - int nelem; - int *elems; -} re_node_set; - -typedef enum -{ - NON_TYPE = 0, - - /* Node type, These are used by token, node, tree. */ - CHARACTER = 1, - END_OF_RE = 2, - SIMPLE_BRACKET = 3, - OP_BACK_REF = 4, - OP_PERIOD = 5, -#ifdef RE_ENABLE_I18N - COMPLEX_BRACKET = 6, - OP_UTF8_PERIOD = 7, -#endif /* RE_ENABLE_I18N */ - - /* We define EPSILON_BIT as a macro so that OP_OPEN_SUBEXP is used - when the debugger shows values of this enum type. */ -#define EPSILON_BIT 8 - OP_OPEN_SUBEXP = EPSILON_BIT | 0, - OP_CLOSE_SUBEXP = EPSILON_BIT | 1, - OP_ALT = EPSILON_BIT | 2, - OP_DUP_ASTERISK = EPSILON_BIT | 3, - ANCHOR = EPSILON_BIT | 4, - - /* Tree type, these are used only by tree. */ - CONCAT = 16, - SUBEXP = 17, - - /* Token type, these are used only by token. */ - OP_DUP_PLUS = 18, - OP_DUP_QUESTION, - OP_OPEN_BRACKET, - OP_CLOSE_BRACKET, - OP_CHARSET_RANGE, - OP_OPEN_DUP_NUM, - OP_CLOSE_DUP_NUM, - OP_NON_MATCH_LIST, - OP_OPEN_COLL_ELEM, - OP_CLOSE_COLL_ELEM, - OP_OPEN_EQUIV_CLASS, - OP_CLOSE_EQUIV_CLASS, - OP_OPEN_CHAR_CLASS, - OP_CLOSE_CHAR_CLASS, - OP_WORD, - OP_NOTWORD, - OP_SPACE, - OP_NOTSPACE, - BACK_SLASH - -} re_token_type_t; - -#ifdef RE_ENABLE_I18N -typedef struct -{ - /* Multibyte characters. */ - wchar_t *mbchars; - - /* Collating symbols. */ -# ifdef _LIBC - int32_t *coll_syms; -# endif - - /* Equivalence classes. */ -# ifdef _LIBC - int32_t *equiv_classes; -# endif - - /* Range expressions. */ -# ifdef _LIBC - uint32_t *range_starts; - uint32_t *range_ends; -# else /* not _LIBC */ - wchar_t *range_starts; - wchar_t *range_ends; -# endif /* not _LIBC */ - - /* Character classes. */ - wctype_t *char_classes; - - /* If this character set is the non-matching list. */ - unsigned int non_match : 1; - - /* # of multibyte characters. */ - int nmbchars; - - /* # of collating symbols. */ - int ncoll_syms; - - /* # of equivalence classes. */ - int nequiv_classes; - - /* # of range expressions. */ - int nranges; - - /* # of character classes. */ - int nchar_classes; -} re_charset_t; -#endif /* RE_ENABLE_I18N */ - -typedef struct -{ - union - { - unsigned char c; /* for CHARACTER */ - re_bitset_ptr_t sbcset; /* for SIMPLE_BRACKET */ -#ifdef RE_ENABLE_I18N - re_charset_t *mbcset; /* for COMPLEX_BRACKET */ -#endif /* RE_ENABLE_I18N */ - int idx; /* for BACK_REF */ - re_context_type ctx_type; /* for ANCHOR */ - } opr; -#if __GNUC__ >= 2 - re_token_type_t type : 8; -#else - re_token_type_t type; -#endif - unsigned int constraint : 10; /* context constraint */ - unsigned int duplicated : 1; - unsigned int opt_subexp : 1; -#ifdef RE_ENABLE_I18N - unsigned int accept_mb : 1; - /* These 2 bits can be moved into the union if needed (e.g. if running out - of bits; move opr.c to opr.c.c and move the flags to opr.c.flags). */ - unsigned int mb_partial : 1; -#endif - unsigned int word_char : 1; -} re_token_t; - -#define IS_EPSILON_NODE(type) ((type) & EPSILON_BIT) - -struct re_string_t -{ - /* Indicate the raw buffer which is the original string passed as an - argument of regexec(), re_search(), etc.. */ - const unsigned char *raw_mbs; - /* Store the multibyte string. In case of "case insensitive mode" like - REG_ICASE, upper cases of the string are stored, otherwise MBS points - the same address that RAW_MBS points. */ - unsigned char *mbs; -#ifdef RE_ENABLE_I18N - /* Store the wide character string which is corresponding to MBS. */ - wint_t *wcs; - int *offsets; - mbstate_t cur_state; -#endif - /* Index in RAW_MBS. Each character mbs[i] corresponds to - raw_mbs[raw_mbs_idx + i]. */ - int raw_mbs_idx; - /* The length of the valid characters in the buffers. */ - int valid_len; - /* The corresponding number of bytes in raw_mbs array. */ - int valid_raw_len; - /* The length of the buffers MBS and WCS. */ - int bufs_len; - /* The index in MBS, which is updated by re_string_fetch_byte. */ - int cur_idx; - /* length of RAW_MBS array. */ - int raw_len; - /* This is RAW_LEN - RAW_MBS_IDX + VALID_LEN - VALID_RAW_LEN. */ - int len; - /* End of the buffer may be shorter than its length in the cases such - as re_match_2, re_search_2. Then, we use STOP for end of the buffer - instead of LEN. */ - int raw_stop; - /* This is RAW_STOP - RAW_MBS_IDX adjusted through OFFSETS. */ - int stop; - - /* The context of mbs[0]. We store the context independently, since - the context of mbs[0] may be different from raw_mbs[0], which is - the beginning of the input string. */ - unsigned int tip_context; - /* The translation passed as a part of an argument of re_compile_pattern. */ - RE_TRANSLATE_TYPE trans; - /* Copy of re_dfa_t's word_char. */ - re_const_bitset_ptr_t word_char; - /* 1 if REG_ICASE. */ - unsigned char icase; - unsigned char is_utf8; - unsigned char map_notascii; - unsigned char mbs_allocated; - unsigned char offsets_needed; - unsigned char newline_anchor; - unsigned char word_ops_used; - int mb_cur_max; -}; -typedef struct re_string_t re_string_t; - - -struct re_dfa_t; -typedef struct re_dfa_t re_dfa_t; - -#ifndef _LIBC -# ifdef __i386__ -# define internal_function __attribute ((regparm (3), stdcall)) -# else -# define internal_function -# endif -#endif - -#ifndef NOT_IN_libc -static reg_errcode_t re_string_realloc_buffers (re_string_t *pstr, - int new_buf_len) - internal_function; -# ifdef RE_ENABLE_I18N -static void build_wcs_buffer (re_string_t *pstr) internal_function; -static reg_errcode_t build_wcs_upper_buffer (re_string_t *pstr) - internal_function; -# endif /* RE_ENABLE_I18N */ -static void build_upper_buffer (re_string_t *pstr) internal_function; -static void re_string_translate_buffer (re_string_t *pstr) internal_function; -static unsigned int re_string_context_at (const re_string_t *input, int idx, - int eflags) - internal_function __attribute ((pure)); -#endif -#define re_string_peek_byte(pstr, offset) \ - ((pstr)->mbs[(pstr)->cur_idx + offset]) -#define re_string_fetch_byte(pstr) \ - ((pstr)->mbs[(pstr)->cur_idx++]) -#define re_string_first_byte(pstr, idx) \ - ((idx) == (pstr)->valid_len || (pstr)->wcs[idx] != WEOF) -#define re_string_is_single_byte_char(pstr, idx) \ - ((pstr)->wcs[idx] != WEOF && ((pstr)->valid_len == (idx) + 1 \ - || (pstr)->wcs[(idx) + 1] != WEOF)) -#define re_string_eoi(pstr) ((pstr)->stop <= (pstr)->cur_idx) -#define re_string_cur_idx(pstr) ((pstr)->cur_idx) -#define re_string_get_buffer(pstr) ((pstr)->mbs) -#define re_string_length(pstr) ((pstr)->len) -#define re_string_byte_at(pstr,idx) ((pstr)->mbs[idx]) -#define re_string_skip_bytes(pstr,idx) ((pstr)->cur_idx += (idx)) -#define re_string_set_index(pstr,idx) ((pstr)->cur_idx = (idx)) - -#ifndef _LIBC -# if HAVE_ALLOCA -# if (_MSC_VER) -# include -# define __libc_use_alloca(n) 0 -# else -# include -/* The OS usually guarantees only one guard page at the bottom of the stack, - and a page size can be as small as 4096 bytes. So we cannot safely - allocate anything larger than 4096 bytes. Also care for the possibility - of a few compiler-allocated temporary stack slots. */ -# define __libc_use_alloca(n) ((n) < 4032) -# endif -# else -/* alloca is implemented with malloc, so just use malloc. */ -# define __libc_use_alloca(n) 0 -# endif -#endif - -#define re_malloc(t,n) ((t *) malloc ((n) * sizeof (t))) -/* SunOS 4.1.x realloc doesn't accept null pointers: pre-Standard C. Sigh. */ -#define re_realloc(p,t,n) ((p != NULL) ? (t *) realloc (p,(n)*sizeof(t)) : (t *) calloc(n,sizeof(t))) -#define re_free(p) free (p) - -struct bin_tree_t -{ - struct bin_tree_t *parent; - struct bin_tree_t *left; - struct bin_tree_t *right; - struct bin_tree_t *first; - struct bin_tree_t *next; - - re_token_t token; - - /* `node_idx' is the index in dfa->nodes, if `type' == 0. - Otherwise `type' indicate the type of this node. */ - int node_idx; -}; -typedef struct bin_tree_t bin_tree_t; - -#define BIN_TREE_STORAGE_SIZE \ - ((1024 - sizeof (void *)) / sizeof (bin_tree_t)) - -struct bin_tree_storage_t -{ - struct bin_tree_storage_t *next; - bin_tree_t data[BIN_TREE_STORAGE_SIZE]; -}; -typedef struct bin_tree_storage_t bin_tree_storage_t; - -#define CONTEXT_WORD 1 -#define CONTEXT_NEWLINE (CONTEXT_WORD << 1) -#define CONTEXT_BEGBUF (CONTEXT_NEWLINE << 1) -#define CONTEXT_ENDBUF (CONTEXT_BEGBUF << 1) - -#define IS_WORD_CONTEXT(c) ((c) & CONTEXT_WORD) -#define IS_NEWLINE_CONTEXT(c) ((c) & CONTEXT_NEWLINE) -#define IS_BEGBUF_CONTEXT(c) ((c) & CONTEXT_BEGBUF) -#define IS_ENDBUF_CONTEXT(c) ((c) & CONTEXT_ENDBUF) -#define IS_ORDINARY_CONTEXT(c) ((c) == 0) - -#define IS_WORD_CHAR(ch) (isalnum (ch) || (ch) == '_') -#define IS_NEWLINE(ch) ((ch) == NEWLINE_CHAR) -#define IS_WIDE_WORD_CHAR(ch) (iswalnum (ch) || (ch) == L'_') -#define IS_WIDE_NEWLINE(ch) ((ch) == WIDE_NEWLINE_CHAR) - -#define NOT_SATISFY_PREV_CONSTRAINT(constraint,context) \ - ((((constraint) & PREV_WORD_CONSTRAINT) && !IS_WORD_CONTEXT (context)) \ - || ((constraint & PREV_NOTWORD_CONSTRAINT) && IS_WORD_CONTEXT (context)) \ - || ((constraint & PREV_NEWLINE_CONSTRAINT) && !IS_NEWLINE_CONTEXT (context))\ - || ((constraint & PREV_BEGBUF_CONSTRAINT) && !IS_BEGBUF_CONTEXT (context))) - -#define NOT_SATISFY_NEXT_CONSTRAINT(constraint,context) \ - ((((constraint) & NEXT_WORD_CONSTRAINT) && !IS_WORD_CONTEXT (context)) \ - || (((constraint) & NEXT_NOTWORD_CONSTRAINT) && IS_WORD_CONTEXT (context)) \ - || (((constraint) & NEXT_NEWLINE_CONSTRAINT) && !IS_NEWLINE_CONTEXT (context)) \ - || (((constraint) & NEXT_ENDBUF_CONSTRAINT) && !IS_ENDBUF_CONTEXT (context))) - -struct re_dfastate_t -{ - unsigned int hash; - re_node_set nodes; - re_node_set non_eps_nodes; - re_node_set inveclosure; - re_node_set *entrance_nodes; - struct re_dfastate_t **trtable, **word_trtable; - unsigned int context : 4; - unsigned int halt : 1; - /* If this state can accept `multi byte'. - Note that we refer to multibyte characters, and multi character - collating elements as `multi byte'. */ - unsigned int accept_mb : 1; - /* If this state has backreference node(s). */ - unsigned int has_backref : 1; - unsigned int has_constraint : 1; -}; -typedef struct re_dfastate_t re_dfastate_t; - -struct re_state_table_entry -{ - int num; - int alloc; - re_dfastate_t **array; -}; - -/* Array type used in re_sub_match_last_t and re_sub_match_top_t. */ - -typedef struct -{ - int next_idx; - int alloc; - re_dfastate_t **array; -} state_array_t; - -/* Store information about the node NODE whose type is OP_CLOSE_SUBEXP. */ - -typedef struct -{ - int node; - int str_idx; /* The position NODE match at. */ - state_array_t path; -} re_sub_match_last_t; - -/* Store information about the node NODE whose type is OP_OPEN_SUBEXP. - And information about the node, whose type is OP_CLOSE_SUBEXP, - corresponding to NODE is stored in LASTS. */ - -typedef struct -{ - int str_idx; - int node; - state_array_t *path; - int alasts; /* Allocation size of LASTS. */ - int nlasts; /* The number of LASTS. */ - re_sub_match_last_t **lasts; -} re_sub_match_top_t; - -struct re_backref_cache_entry -{ - int node; - int str_idx; - int subexp_from; - int subexp_to; - char more; - char unused; - unsigned short int eps_reachable_subexps_map; -}; - -typedef struct -{ - /* The string object corresponding to the input string. */ - re_string_t input; -#if defined _LIBC || (defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L) - const re_dfa_t *const dfa; -#else - const re_dfa_t *dfa; -#endif - /* EFLAGS of the argument of regexec. */ - int eflags; - /* Where the matching ends. */ - int match_last; - int last_node; - /* The state log used by the matcher. */ - re_dfastate_t **state_log; - int state_log_top; - /* Back reference cache. */ - int nbkref_ents; - int abkref_ents; - struct re_backref_cache_entry *bkref_ents; - int max_mb_elem_len; - int nsub_tops; - int asub_tops; - re_sub_match_top_t **sub_tops; -} re_match_context_t; - -typedef struct -{ - re_dfastate_t **sifted_states; - re_dfastate_t **limited_states; - int last_node; - int last_str_idx; - re_node_set limits; -} re_sift_context_t; - -struct re_fail_stack_ent_t -{ - int idx; - int node; - regmatch_t *regs; - re_node_set eps_via_nodes; -}; - -struct re_fail_stack_t -{ - int num; - int alloc; - struct re_fail_stack_ent_t *stack; -}; - -struct re_dfa_t -{ - re_token_t *nodes; - size_t nodes_alloc; - size_t nodes_len; - int *nexts; - int *org_indices; - re_node_set *edests; - re_node_set *eclosures; - re_node_set *inveclosures; - struct re_state_table_entry *state_table; - re_dfastate_t *init_state; - re_dfastate_t *init_state_word; - re_dfastate_t *init_state_nl; - re_dfastate_t *init_state_begbuf; - bin_tree_t *str_tree; - bin_tree_storage_t *str_tree_storage; - re_bitset_ptr_t sb_char; - int str_tree_storage_idx; - - /* number of subexpressions `re_nsub' is in regex_t. */ - unsigned int state_hash_mask; - int init_node; - int nbackref; /* The number of backreference in this dfa. */ - - /* Bitmap expressing which backreference is used. */ - bitset_word_t used_bkref_map; - bitset_word_t completed_bkref_map; - - unsigned int has_plural_match : 1; - /* If this dfa has "multibyte node", which is a backreference or - a node which can accept multibyte character or multi character - collating element. */ - unsigned int has_mb_node : 1; - unsigned int is_utf8 : 1; - unsigned int map_notascii : 1; - unsigned int word_ops_used : 1; - int mb_cur_max; - bitset_t word_char; - reg_syntax_t syntax; - int *subexp_map; -#ifdef DEBUG - char* re_str; -#endif -#if defined _LIBC - __libc_lock_define (, lock) -#endif -}; - -#define re_node_set_init_empty(set) memset (set, '\0', sizeof (re_node_set)) -#define re_node_set_remove(set,id) \ - (re_node_set_remove_at (set, re_node_set_contains (set, id) - 1)) -#define re_node_set_empty(p) ((p)->nelem = 0) -#define re_node_set_free(set) re_free ((set)->elems) - - -typedef enum -{ - SB_CHAR, - MB_CHAR, - EQUIV_CLASS, - COLL_SYM, - CHAR_CLASS -} bracket_elem_type; - -typedef struct -{ - bracket_elem_type type; - union - { - unsigned char ch; - unsigned char *name; - wchar_t wch; - } opr; -} bracket_elem_t; - - -/* Inline functions for bitset operation. */ -static inline void -bitset_not (bitset_t set) -{ - int bitset_i; - for (bitset_i = 0; bitset_i < BITSET_WORDS; ++bitset_i) - set[bitset_i] = ~set[bitset_i]; -} - -static inline void -bitset_merge (bitset_t dest, const bitset_t src) -{ - int bitset_i; - for (bitset_i = 0; bitset_i < BITSET_WORDS; ++bitset_i) - dest[bitset_i] |= src[bitset_i]; -} - -static inline void -bitset_mask (bitset_t dest, const bitset_t src) -{ - int bitset_i; - for (bitset_i = 0; bitset_i < BITSET_WORDS; ++bitset_i) - dest[bitset_i] &= src[bitset_i]; -} - -#ifdef RE_ENABLE_I18N -/* Inline functions for re_string. */ -static inline int -internal_function __attribute ((pure)) -re_string_char_size_at (const re_string_t *pstr, int idx) -{ - int byte_idx; - if (pstr->mb_cur_max == 1) - return 1; - for (byte_idx = 1; idx + byte_idx < pstr->valid_len; ++byte_idx) - if (pstr->wcs[idx + byte_idx] != WEOF) - break; - return byte_idx; -} - -static inline wint_t -internal_function __attribute ((pure)) -re_string_wchar_at (const re_string_t *pstr, int idx) -{ - if (pstr->mb_cur_max == 1) - return (wint_t) pstr->mbs[idx]; - return (wint_t) pstr->wcs[idx]; -} - -# ifndef NOT_IN_libc -static int -internal_function __attribute ((pure)) -re_string_elem_size_at (const re_string_t *pstr, int idx) -{ -# ifdef _LIBC - const unsigned char *p, *extra; - const int32_t *table, *indirect; - int32_t tmp; -# include - uint_fast32_t nrules = _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES); - - if (nrules != 0) - { - table = (const int32_t *) _NL_CURRENT (LC_COLLATE, _NL_COLLATE_TABLEMB); - extra = (const unsigned char *) - _NL_CURRENT (LC_COLLATE, _NL_COLLATE_EXTRAMB); - indirect = (const int32_t *) _NL_CURRENT (LC_COLLATE, - _NL_COLLATE_INDIRECTMB); - p = pstr->mbs + idx; - tmp = findidx (&p); - return p - pstr->mbs - idx; - } - else -# endif /* _LIBC */ - return 1; -} -# endif -#endif /* RE_ENABLE_I18N */ - -#endif /* _REGEX_INTERNAL_H */ diff --git a/deps/regex/regexec.c b/deps/regex/regexec.c deleted file mode 100644 index 0a1602e5a..000000000 --- a/deps/regex/regexec.c +++ /dev/null @@ -1,4369 +0,0 @@ -/* Extended regular expression matching and search library. - Copyright (C) 2002-2005, 2007, 2009, 2010 Free Software Foundation, Inc. - This file is part of the GNU C Library. - Contributed by Isamu Hasegawa . - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, write to the Free - Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301 USA. */ - -static reg_errcode_t match_ctx_init (re_match_context_t *cache, int eflags, - int n) internal_function; -static void match_ctx_clean (re_match_context_t *mctx) internal_function; -static void match_ctx_free (re_match_context_t *cache) internal_function; -static reg_errcode_t match_ctx_add_entry (re_match_context_t *cache, int node, - int str_idx, int from, int to) - internal_function; -static int search_cur_bkref_entry (const re_match_context_t *mctx, int str_idx) - internal_function; -static reg_errcode_t match_ctx_add_subtop (re_match_context_t *mctx, int node, - int str_idx) internal_function; -static re_sub_match_last_t * match_ctx_add_sublast (re_sub_match_top_t *subtop, - int node, int str_idx) - internal_function; -static void sift_ctx_init (re_sift_context_t *sctx, re_dfastate_t **sifted_sts, - re_dfastate_t **limited_sts, int last_node, - int last_str_idx) - internal_function; -static reg_errcode_t re_search_internal (const regex_t *preg, - const char *string, int length, - int start, int range, int stop, - size_t nmatch, regmatch_t pmatch[], - int eflags); -static int re_search_2_stub (struct re_pattern_buffer *bufp, - const char *string1, int length1, - const char *string2, int length2, - int start, int range, struct re_registers *regs, - int stop, int ret_len); -static int re_search_stub (struct re_pattern_buffer *bufp, - const char *string, int length, int start, - int range, int stop, struct re_registers *regs, - int ret_len); -static unsigned re_copy_regs (struct re_registers *regs, regmatch_t *pmatch, - unsigned int nregs, int regs_allocated); -static reg_errcode_t prune_impossible_nodes (re_match_context_t *mctx); -static int check_matching (re_match_context_t *mctx, int fl_longest_match, - int *p_match_first) internal_function; -static int check_halt_state_context (const re_match_context_t *mctx, - const re_dfastate_t *state, int idx) - internal_function; -static void update_regs (const re_dfa_t *dfa, regmatch_t *pmatch, - regmatch_t *prev_idx_match, int cur_node, - int cur_idx, int nmatch) internal_function; -static reg_errcode_t push_fail_stack (struct re_fail_stack_t *fs, - int str_idx, int dest_node, int nregs, - regmatch_t *regs, - re_node_set *eps_via_nodes) - internal_function; -static reg_errcode_t set_regs (const regex_t *preg, - const re_match_context_t *mctx, - size_t nmatch, regmatch_t *pmatch, - int fl_backtrack) internal_function; -static reg_errcode_t free_fail_stack_return (struct re_fail_stack_t *fs) - internal_function; - -#ifdef RE_ENABLE_I18N -static int sift_states_iter_mb (const re_match_context_t *mctx, - re_sift_context_t *sctx, - int node_idx, int str_idx, int max_str_idx) - internal_function; -#endif /* RE_ENABLE_I18N */ -static reg_errcode_t sift_states_backward (const re_match_context_t *mctx, - re_sift_context_t *sctx) - internal_function; -static reg_errcode_t build_sifted_states (const re_match_context_t *mctx, - re_sift_context_t *sctx, int str_idx, - re_node_set *cur_dest) - internal_function; -static reg_errcode_t update_cur_sifted_state (const re_match_context_t *mctx, - re_sift_context_t *sctx, - int str_idx, - re_node_set *dest_nodes) - internal_function; -static reg_errcode_t add_epsilon_src_nodes (const re_dfa_t *dfa, - re_node_set *dest_nodes, - const re_node_set *candidates) - internal_function; -static int check_dst_limits (const re_match_context_t *mctx, - re_node_set *limits, - int dst_node, int dst_idx, int src_node, - int src_idx) internal_function; -static int check_dst_limits_calc_pos_1 (const re_match_context_t *mctx, - int boundaries, int subexp_idx, - int from_node, int bkref_idx) - internal_function; -static int check_dst_limits_calc_pos (const re_match_context_t *mctx, - int limit, int subexp_idx, - int node, int str_idx, - int bkref_idx) internal_function; -static reg_errcode_t check_subexp_limits (const re_dfa_t *dfa, - re_node_set *dest_nodes, - const re_node_set *candidates, - re_node_set *limits, - struct re_backref_cache_entry *bkref_ents, - int str_idx) internal_function; -static reg_errcode_t sift_states_bkref (const re_match_context_t *mctx, - re_sift_context_t *sctx, - int str_idx, const re_node_set *candidates) - internal_function; -static reg_errcode_t merge_state_array (const re_dfa_t *dfa, - re_dfastate_t **dst, - re_dfastate_t **src, int num) - internal_function; -static re_dfastate_t *find_recover_state (reg_errcode_t *err, - re_match_context_t *mctx) internal_function; -static re_dfastate_t *transit_state (reg_errcode_t *err, - re_match_context_t *mctx, - re_dfastate_t *state) internal_function; -static re_dfastate_t *merge_state_with_log (reg_errcode_t *err, - re_match_context_t *mctx, - re_dfastate_t *next_state) - internal_function; -static reg_errcode_t check_subexp_matching_top (re_match_context_t *mctx, - re_node_set *cur_nodes, - int str_idx) internal_function; -#if 0 -static re_dfastate_t *transit_state_sb (reg_errcode_t *err, - re_match_context_t *mctx, - re_dfastate_t *pstate) - internal_function; -#endif -#ifdef RE_ENABLE_I18N -static reg_errcode_t transit_state_mb (re_match_context_t *mctx, - re_dfastate_t *pstate) - internal_function; -#endif /* RE_ENABLE_I18N */ -static reg_errcode_t transit_state_bkref (re_match_context_t *mctx, - const re_node_set *nodes) - internal_function; -static reg_errcode_t get_subexp (re_match_context_t *mctx, - int bkref_node, int bkref_str_idx) - internal_function; -static reg_errcode_t get_subexp_sub (re_match_context_t *mctx, - const re_sub_match_top_t *sub_top, - re_sub_match_last_t *sub_last, - int bkref_node, int bkref_str) - internal_function; -static int find_subexp_node (const re_dfa_t *dfa, const re_node_set *nodes, - int subexp_idx, int type) internal_function; -static reg_errcode_t check_arrival (re_match_context_t *mctx, - state_array_t *path, int top_node, - int top_str, int last_node, int last_str, - int type) internal_function; -static reg_errcode_t check_arrival_add_next_nodes (re_match_context_t *mctx, - int str_idx, - re_node_set *cur_nodes, - re_node_set *next_nodes) - internal_function; -static reg_errcode_t check_arrival_expand_ecl (const re_dfa_t *dfa, - re_node_set *cur_nodes, - int ex_subexp, int type) - internal_function; -static reg_errcode_t check_arrival_expand_ecl_sub (const re_dfa_t *dfa, - re_node_set *dst_nodes, - int target, int ex_subexp, - int type) internal_function; -static reg_errcode_t expand_bkref_cache (re_match_context_t *mctx, - re_node_set *cur_nodes, int cur_str, - int subexp_num, int type) - internal_function; -static int build_trtable (const re_dfa_t *dfa, - re_dfastate_t *state) internal_function; -#ifdef RE_ENABLE_I18N -static int check_node_accept_bytes (const re_dfa_t *dfa, int node_idx, - const re_string_t *input, int idx) - internal_function; -# ifdef _LIBC -static unsigned int find_collation_sequence_value (const unsigned char *mbs, - size_t name_len) - internal_function; -# endif /* _LIBC */ -#endif /* RE_ENABLE_I18N */ -static int group_nodes_into_DFAstates (const re_dfa_t *dfa, - const re_dfastate_t *state, - re_node_set *states_node, - bitset_t *states_ch) internal_function; -static int check_node_accept (const re_match_context_t *mctx, - const re_token_t *node, int idx) - internal_function; -static reg_errcode_t extend_buffers (re_match_context_t *mctx) - internal_function; - -/* Entry point for POSIX code. */ - -/* regexec searches for a given pattern, specified by PREG, in the - string STRING. - - If NMATCH is zero or REG_NOSUB was set in the cflags argument to - `regcomp', we ignore PMATCH. Otherwise, we assume PMATCH has at - least NMATCH elements, and we set them to the offsets of the - corresponding matched substrings. - - EFLAGS specifies `execution flags' which affect matching: if - REG_NOTBOL is set, then ^ does not match at the beginning of the - string; if REG_NOTEOL is set, then $ does not match at the end. - - We return 0 if we find a match and REG_NOMATCH if not. */ - -int -regexec ( - const regex_t *__restrict preg, - const char *__restrict string, - size_t nmatch, - regmatch_t pmatch[], - int eflags) -{ - reg_errcode_t err; - int start, length; - - if (eflags & ~(REG_NOTBOL | REG_NOTEOL | REG_STARTEND)) - return REG_BADPAT; - - if (eflags & REG_STARTEND) - { - start = pmatch[0].rm_so; - length = pmatch[0].rm_eo; - } - else - { - start = 0; - length = strlen (string); - } - - __libc_lock_lock (dfa->lock); - if (preg->no_sub) - err = re_search_internal (preg, string, length, start, length - start, - length, 0, NULL, eflags); - else - err = re_search_internal (preg, string, length, start, length - start, - length, nmatch, pmatch, eflags); - __libc_lock_unlock (dfa->lock); - return err != REG_NOERROR; -} - -#ifdef _LIBC -# include -versioned_symbol (libc, __regexec, regexec, GLIBC_2_3_4); - -# if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_3_4) -__typeof__ (__regexec) __compat_regexec; - -int -attribute_compat_text_section -__compat_regexec (const regex_t *__restrict preg, - const char *__restrict string, size_t nmatch, - regmatch_t pmatch[], int eflags) -{ - return regexec (preg, string, nmatch, pmatch, - eflags & (REG_NOTBOL | REG_NOTEOL)); -} -compat_symbol (libc, __compat_regexec, regexec, GLIBC_2_0); -# endif -#endif - -/* Entry points for GNU code. */ - -/* re_match, re_search, re_match_2, re_search_2 - - The former two functions operate on STRING with length LENGTH, - while the later two operate on concatenation of STRING1 and STRING2 - with lengths LENGTH1 and LENGTH2, respectively. - - re_match() matches the compiled pattern in BUFP against the string, - starting at index START. - - re_search() first tries matching at index START, then it tries to match - starting from index START + 1, and so on. The last start position tried - is START + RANGE. (Thus RANGE = 0 forces re_search to operate the same - way as re_match().) - - The parameter STOP of re_{match,search}_2 specifies that no match exceeding - the first STOP characters of the concatenation of the strings should be - concerned. - - If REGS is not NULL, and BUFP->no_sub is not set, the offsets of the match - and all groups is stroed in REGS. (For the "_2" variants, the offsets are - computed relative to the concatenation, not relative to the individual - strings.) - - On success, re_match* functions return the length of the match, re_search* - return the position of the start of the match. Return value -1 means no - match was found and -2 indicates an internal error. */ - -int -re_match (struct re_pattern_buffer *bufp, - const char *string, - int length, - int start, - struct re_registers *regs) -{ - return re_search_stub (bufp, string, length, start, 0, length, regs, 1); -} -#ifdef _LIBC -weak_alias (__re_match, re_match) -#endif - -int -re_search (struct re_pattern_buffer *bufp, - const char *string, - int length, int start, int range, - struct re_registers *regs) -{ - return re_search_stub (bufp, string, length, start, range, length, regs, 0); -} -#ifdef _LIBC -weak_alias (__re_search, re_search) -#endif - -int -re_match_2 (struct re_pattern_buffer *bufp, - const char *string1, int length1, - const char *string2, int length2, int start, - struct re_registers *regs, int stop) -{ - return re_search_2_stub (bufp, string1, length1, string2, length2, - start, 0, regs, stop, 1); -} -#ifdef _LIBC -weak_alias (__re_match_2, re_match_2) -#endif - -int -re_search_2 (struct re_pattern_buffer *bufp, - const char *string1, int length1, - const char *string2, int length2, int start, - int range, struct re_registers *regs, int stop) -{ - return re_search_2_stub (bufp, string1, length1, string2, length2, - start, range, regs, stop, 0); -} -#ifdef _LIBC -weak_alias (__re_search_2, re_search_2) -#endif - -static int -re_search_2_stub (struct re_pattern_buffer *bufp, - const char *string1, int length1, - const char *string2, int length2, int start, - int range, struct re_registers *regs, - int stop, int ret_len) -{ - const char *str; - int rval; - int len = length1 + length2; - int free_str = 0; - - if (BE (length1 < 0 || length2 < 0 || stop < 0, 0)) - return -2; - - /* Concatenate the strings. */ - if (length2 > 0) - if (length1 > 0) - { - char *s = re_malloc (char, len); - - if (BE (s == NULL, 0)) - return -2; - memcpy (s, string1, length1); - memcpy (s + length1, string2, length2); - str = s; - free_str = 1; - } - else - str = string2; - else - str = string1; - - rval = re_search_stub (bufp, str, len, start, range, stop, regs, ret_len); - if (free_str) - re_free ((char *) str); - return rval; -} - -/* The parameters have the same meaning as those of re_search. - Additional parameters: - If RET_LEN is nonzero the length of the match is returned (re_match style); - otherwise the position of the match is returned. */ - -static int -re_search_stub (struct re_pattern_buffer *bufp, - const char *string, int length, int start, - int range, int stop, - struct re_registers *regs, int ret_len) -{ - reg_errcode_t result; - regmatch_t *pmatch; - int nregs, rval; - int eflags = 0; - - /* Check for out-of-range. */ - if (BE (start < 0 || start > length, 0)) - return -1; - if (BE (start + range > length, 0)) - range = length - start; - else if (BE (start + range < 0, 0)) - range = -start; - - __libc_lock_lock (dfa->lock); - - eflags |= (bufp->not_bol) ? REG_NOTBOL : 0; - eflags |= (bufp->not_eol) ? REG_NOTEOL : 0; - - /* Compile fastmap if we haven't yet. */ - if (range > 0 && bufp->fastmap != NULL && !bufp->fastmap_accurate) - re_compile_fastmap (bufp); - - if (BE (bufp->no_sub, 0)) - regs = NULL; - - /* We need at least 1 register. */ - if (regs == NULL) - nregs = 1; - else if (BE (bufp->regs_allocated == REGS_FIXED && - regs->num_regs < bufp->re_nsub + 1, 0)) - { - nregs = regs->num_regs; - if (BE (nregs < 1, 0)) - { - /* Nothing can be copied to regs. */ - regs = NULL; - nregs = 1; - } - } - else - nregs = bufp->re_nsub + 1; - pmatch = re_malloc (regmatch_t, nregs); - if (BE (pmatch == NULL, 0)) - { - rval = -2; - goto out; - } - - result = re_search_internal (bufp, string, length, start, range, stop, - nregs, pmatch, eflags); - - rval = 0; - - /* I hope we needn't fill ther regs with -1's when no match was found. */ - if (result != REG_NOERROR) - rval = -1; - else if (regs != NULL) - { - /* If caller wants register contents data back, copy them. */ - bufp->regs_allocated = re_copy_regs (regs, pmatch, nregs, - bufp->regs_allocated); - if (BE (bufp->regs_allocated == REGS_UNALLOCATED, 0)) - rval = -2; - } - - if (BE (rval == 0, 1)) - { - if (ret_len) - { - assert (pmatch[0].rm_so == start); - rval = pmatch[0].rm_eo - start; - } - else - rval = pmatch[0].rm_so; - } - re_free (pmatch); - out: - __libc_lock_unlock (dfa->lock); - return rval; -} - -static unsigned -re_copy_regs (struct re_registers *regs, - regmatch_t *pmatch, - unsigned int nregs, int regs_allocated) -{ - int rval = REGS_REALLOCATE; - unsigned int i; - unsigned int need_regs = nregs + 1; - /* We need one extra element beyond `num_regs' for the `-1' marker GNU code - uses. */ - - /* Have the register data arrays been allocated? */ - if (regs_allocated == REGS_UNALLOCATED) - { /* No. So allocate them with malloc. */ - regs->start = re_malloc (regoff_t, need_regs); - if (BE (regs->start == NULL, 0)) - return REGS_UNALLOCATED; - regs->end = re_malloc (regoff_t, need_regs); - if (BE (regs->end == NULL, 0)) - { - re_free (regs->start); - return REGS_UNALLOCATED; - } - regs->num_regs = need_regs; - } - else if (regs_allocated == REGS_REALLOCATE) - { /* Yes. If we need more elements than were already - allocated, reallocate them. If we need fewer, just - leave it alone. */ - if (BE (need_regs > regs->num_regs, 0)) - { - regoff_t *new_start = re_realloc (regs->start, regoff_t, need_regs); - regoff_t *new_end; - if (BE (new_start == NULL, 0)) - return REGS_UNALLOCATED; - new_end = re_realloc (regs->end, regoff_t, need_regs); - if (BE (new_end == NULL, 0)) - { - re_free (new_start); - return REGS_UNALLOCATED; - } - regs->start = new_start; - regs->end = new_end; - regs->num_regs = need_regs; - } - } - else - { - assert (regs_allocated == REGS_FIXED); - /* This function may not be called with REGS_FIXED and nregs too big. */ - assert (regs->num_regs >= nregs); - rval = REGS_FIXED; - } - - /* Copy the regs. */ - for (i = 0; i < nregs; ++i) - { - regs->start[i] = pmatch[i].rm_so; - regs->end[i] = pmatch[i].rm_eo; - } - for ( ; i < regs->num_regs; ++i) - regs->start[i] = regs->end[i] = -1; - - return rval; -} - -/* Set REGS to hold NUM_REGS registers, storing them in STARTS and - ENDS. Subsequent matches using PATTERN_BUFFER and REGS will use - this memory for recording register information. STARTS and ENDS - must be allocated using the malloc library routine, and must each - be at least NUM_REGS * sizeof (regoff_t) bytes long. - - If NUM_REGS == 0, then subsequent matches should allocate their own - register data. - - Unless this function is called, the first search or match using - PATTERN_BUFFER will allocate its own register data, without - freeing the old data. */ - -void -re_set_registers (struct re_pattern_buffer *bufp, - struct re_registers *regs, - unsigned num_regs, - regoff_t *starts, - regoff_t *ends) -{ - if (num_regs) - { - bufp->regs_allocated = REGS_REALLOCATE; - regs->num_regs = num_regs; - regs->start = starts; - regs->end = ends; - } - else - { - bufp->regs_allocated = REGS_UNALLOCATED; - regs->num_regs = 0; - regs->start = regs->end = (regoff_t *) 0; - } -} -#ifdef _LIBC -weak_alias (__re_set_registers, re_set_registers) -#endif - -/* Entry points compatible with 4.2 BSD regex library. We don't define - them unless specifically requested. */ - -#if defined _REGEX_RE_COMP || defined _LIBC -int -# ifdef _LIBC -weak_function -# endif -re_exec (s) - const char *s; -{ - return 0 == regexec (&re_comp_buf, s, 0, NULL, 0); -} -#endif /* _REGEX_RE_COMP */ - -/* Internal entry point. */ - -/* Searches for a compiled pattern PREG in the string STRING, whose - length is LENGTH. NMATCH, PMATCH, and EFLAGS have the same - mingings with regexec. START, and RANGE have the same meanings - with re_search. - Return REG_NOERROR if we find a match, and REG_NOMATCH if not, - otherwise return the error code. - Note: We assume front end functions already check ranges. - (START + RANGE >= 0 && START + RANGE <= LENGTH) */ - -static reg_errcode_t -re_search_internal (const regex_t *preg, - const char *string, - int length, int start, int range, int stop, - size_t nmatch, regmatch_t pmatch[], - int eflags) -{ - reg_errcode_t err; - const re_dfa_t *dfa = (const re_dfa_t *) preg->buffer; - int left_lim, right_lim, incr; - int fl_longest_match, match_first, match_kind, match_last = -1; - unsigned int extra_nmatch; - int sb, ch; -#if defined _LIBC || (defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L) - re_match_context_t mctx = { .dfa = dfa }; -#else - re_match_context_t mctx; -#endif - char *fastmap = (preg->fastmap != NULL && preg->fastmap_accurate - && range && !preg->can_be_null) ? preg->fastmap : NULL; - RE_TRANSLATE_TYPE t = preg->translate; - -#if !(defined _LIBC || (defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L)) - memset (&mctx, '\0', sizeof (re_match_context_t)); - mctx.dfa = dfa; -#endif - - extra_nmatch = (nmatch > preg->re_nsub) ? nmatch - (preg->re_nsub + 1) : 0; - nmatch -= extra_nmatch; - - /* Check if the DFA haven't been compiled. */ - if (BE (preg->used == 0 || dfa->init_state == NULL - || dfa->init_state_word == NULL || dfa->init_state_nl == NULL - || dfa->init_state_begbuf == NULL, 0)) - return REG_NOMATCH; - -#ifdef DEBUG - /* We assume front-end functions already check them. */ - assert (start + range >= 0 && start + range <= length); -#endif - - /* If initial states with non-begbuf contexts have no elements, - the regex must be anchored. If preg->newline_anchor is set, - we'll never use init_state_nl, so do not check it. */ - if (dfa->init_state->nodes.nelem == 0 - && dfa->init_state_word->nodes.nelem == 0 - && (dfa->init_state_nl->nodes.nelem == 0 - || !preg->newline_anchor)) - { - if (start != 0 && start + range != 0) - return REG_NOMATCH; - start = range = 0; - } - - /* We must check the longest matching, if nmatch > 0. */ - fl_longest_match = (nmatch != 0 || dfa->nbackref); - - err = re_string_allocate (&mctx.input, string, length, dfa->nodes_len + 1, - preg->translate, preg->syntax & RE_ICASE, dfa); - if (BE (err != REG_NOERROR, 0)) - goto free_return; - mctx.input.stop = stop; - mctx.input.raw_stop = stop; - mctx.input.newline_anchor = preg->newline_anchor; - - err = match_ctx_init (&mctx, eflags, dfa->nbackref * 2); - if (BE (err != REG_NOERROR, 0)) - goto free_return; - - /* We will log all the DFA states through which the dfa pass, - if nmatch > 1, or this dfa has "multibyte node", which is a - back-reference or a node which can accept multibyte character or - multi character collating element. */ - if (nmatch > 1 || dfa->has_mb_node) - { - /* Avoid overflow. */ - if (BE (SIZE_MAX / sizeof (re_dfastate_t *) <= (size_t)mctx.input.bufs_len, 0)) - { - err = REG_ESPACE; - goto free_return; - } - - mctx.state_log = re_malloc (re_dfastate_t *, mctx.input.bufs_len + 1); - if (BE (mctx.state_log == NULL, 0)) - { - err = REG_ESPACE; - goto free_return; - } - } - else - mctx.state_log = NULL; - - match_first = start; - mctx.input.tip_context = (eflags & REG_NOTBOL) ? CONTEXT_BEGBUF - : CONTEXT_NEWLINE | CONTEXT_BEGBUF; - - /* Check incrementally whether of not the input string match. */ - incr = (range < 0) ? -1 : 1; - left_lim = (range < 0) ? start + range : start; - right_lim = (range < 0) ? start : start + range; - sb = dfa->mb_cur_max == 1; - match_kind = - (fastmap - ? ((sb || !(preg->syntax & RE_ICASE || t) ? 4 : 0) - | (range >= 0 ? 2 : 0) - | (t != NULL ? 1 : 0)) - : 8); - - for (;; match_first += incr) - { - err = REG_NOMATCH; - if (match_first < left_lim || right_lim < match_first) - goto free_return; - - /* Advance as rapidly as possible through the string, until we - find a plausible place to start matching. This may be done - with varying efficiency, so there are various possibilities: - only the most common of them are specialized, in order to - save on code size. We use a switch statement for speed. */ - switch (match_kind) - { - case 8: - /* No fastmap. */ - break; - - case 7: - /* Fastmap with single-byte translation, match forward. */ - while (BE (match_first < right_lim, 1) - && !fastmap[t[(unsigned char) string[match_first]]]) - ++match_first; - goto forward_match_found_start_or_reached_end; - - case 6: - /* Fastmap without translation, match forward. */ - while (BE (match_first < right_lim, 1) - && !fastmap[(unsigned char) string[match_first]]) - ++match_first; - - forward_match_found_start_or_reached_end: - if (BE (match_first == right_lim, 0)) - { - ch = match_first >= length - ? 0 : (unsigned char) string[match_first]; - if (!fastmap[t ? t[ch] : ch]) - goto free_return; - } - break; - - case 4: - case 5: - /* Fastmap without multi-byte translation, match backwards. */ - while (match_first >= left_lim) - { - ch = match_first >= length - ? 0 : (unsigned char) string[match_first]; - if (fastmap[t ? t[ch] : ch]) - break; - --match_first; - } - if (match_first < left_lim) - goto free_return; - break; - - default: - /* In this case, we can't determine easily the current byte, - since it might be a component byte of a multibyte - character. Then we use the constructed buffer instead. */ - for (;;) - { - /* If MATCH_FIRST is out of the valid range, reconstruct the - buffers. */ - unsigned int offset = match_first - mctx.input.raw_mbs_idx; - if (BE (offset >= (unsigned int) mctx.input.valid_raw_len, 0)) - { - err = re_string_reconstruct (&mctx.input, match_first, - eflags); - if (BE (err != REG_NOERROR, 0)) - goto free_return; - - offset = match_first - mctx.input.raw_mbs_idx; - } - /* If MATCH_FIRST is out of the buffer, leave it as '\0'. - Note that MATCH_FIRST must not be smaller than 0. */ - ch = (match_first >= length - ? 0 : re_string_byte_at (&mctx.input, offset)); - if (fastmap[ch]) - break; - match_first += incr; - if (match_first < left_lim || match_first > right_lim) - { - err = REG_NOMATCH; - goto free_return; - } - } - break; - } - - /* Reconstruct the buffers so that the matcher can assume that - the matching starts from the beginning of the buffer. */ - err = re_string_reconstruct (&mctx.input, match_first, eflags); - if (BE (err != REG_NOERROR, 0)) - goto free_return; - -#ifdef RE_ENABLE_I18N - /* Don't consider this char as a possible match start if it part, - yet isn't the head, of a multibyte character. */ - if (!sb && !re_string_first_byte (&mctx.input, 0)) - continue; -#endif - - /* It seems to be appropriate one, then use the matcher. */ - /* We assume that the matching starts from 0. */ - mctx.state_log_top = mctx.nbkref_ents = mctx.max_mb_elem_len = 0; - match_last = check_matching (&mctx, fl_longest_match, - range >= 0 ? &match_first : NULL); - if (match_last != -1) - { - if (BE (match_last == -2, 0)) - { - err = REG_ESPACE; - goto free_return; - } - else - { - mctx.match_last = match_last; - if ((!preg->no_sub && nmatch > 1) || dfa->nbackref) - { - re_dfastate_t *pstate = mctx.state_log[match_last]; - mctx.last_node = check_halt_state_context (&mctx, pstate, - match_last); - } - if ((!preg->no_sub && nmatch > 1 && dfa->has_plural_match) - || dfa->nbackref) - { - err = prune_impossible_nodes (&mctx); - if (err == REG_NOERROR) - break; - if (BE (err != REG_NOMATCH, 0)) - goto free_return; - match_last = -1; - } - else - break; /* We found a match. */ - } - } - - match_ctx_clean (&mctx); - } - -#ifdef DEBUG - assert (match_last != -1); - assert (err == REG_NOERROR); -#endif - - /* Set pmatch[] if we need. */ - if (nmatch > 0) - { - unsigned int reg_idx; - - /* Initialize registers. */ - for (reg_idx = 1; reg_idx < nmatch; ++reg_idx) - pmatch[reg_idx].rm_so = pmatch[reg_idx].rm_eo = -1; - - /* Set the points where matching start/end. */ - pmatch[0].rm_so = 0; - pmatch[0].rm_eo = mctx.match_last; - - if (!preg->no_sub && nmatch > 1) - { - err = set_regs (preg, &mctx, nmatch, pmatch, - dfa->has_plural_match && dfa->nbackref > 0); - if (BE (err != REG_NOERROR, 0)) - goto free_return; - } - - /* At last, add the offset to the each registers, since we slided - the buffers so that we could assume that the matching starts - from 0. */ - for (reg_idx = 0; reg_idx < nmatch; ++reg_idx) - if (pmatch[reg_idx].rm_so != -1) - { -#ifdef RE_ENABLE_I18N - if (BE (mctx.input.offsets_needed != 0, 0)) - { - pmatch[reg_idx].rm_so = - (pmatch[reg_idx].rm_so == mctx.input.valid_len - ? mctx.input.valid_raw_len - : mctx.input.offsets[pmatch[reg_idx].rm_so]); - pmatch[reg_idx].rm_eo = - (pmatch[reg_idx].rm_eo == mctx.input.valid_len - ? mctx.input.valid_raw_len - : mctx.input.offsets[pmatch[reg_idx].rm_eo]); - } -#else - assert (mctx.input.offsets_needed == 0); -#endif - pmatch[reg_idx].rm_so += match_first; - pmatch[reg_idx].rm_eo += match_first; - } - for (reg_idx = 0; reg_idx < extra_nmatch; ++reg_idx) - { - pmatch[nmatch + reg_idx].rm_so = -1; - pmatch[nmatch + reg_idx].rm_eo = -1; - } - - if (dfa->subexp_map) - for (reg_idx = 0; reg_idx + 1 < nmatch; reg_idx++) - if (dfa->subexp_map[reg_idx] != (int)reg_idx) - { - pmatch[reg_idx + 1].rm_so - = pmatch[dfa->subexp_map[reg_idx] + 1].rm_so; - pmatch[reg_idx + 1].rm_eo - = pmatch[dfa->subexp_map[reg_idx] + 1].rm_eo; - } - } - - free_return: - re_free (mctx.state_log); - if (dfa->nbackref) - match_ctx_free (&mctx); - re_string_destruct (&mctx.input); - return err; -} - -static reg_errcode_t -prune_impossible_nodes (re_match_context_t *mctx) -{ - const re_dfa_t *const dfa = mctx->dfa; - int halt_node, match_last; - reg_errcode_t ret; - re_dfastate_t **sifted_states; - re_dfastate_t **lim_states = NULL; - re_sift_context_t sctx; -#ifdef DEBUG - assert (mctx->state_log != NULL); -#endif - match_last = mctx->match_last; - halt_node = mctx->last_node; - - /* Avoid overflow. */ - if (BE (SIZE_MAX / sizeof (re_dfastate_t *) <= (size_t)match_last, 0)) - return REG_ESPACE; - - sifted_states = re_malloc (re_dfastate_t *, match_last + 1); - if (BE (sifted_states == NULL, 0)) - { - ret = REG_ESPACE; - goto free_return; - } - if (dfa->nbackref) - { - lim_states = re_malloc (re_dfastate_t *, match_last + 1); - if (BE (lim_states == NULL, 0)) - { - ret = REG_ESPACE; - goto free_return; - } - while (1) - { - memset (lim_states, '\0', - sizeof (re_dfastate_t *) * (match_last + 1)); - sift_ctx_init (&sctx, sifted_states, lim_states, halt_node, - match_last); - ret = sift_states_backward (mctx, &sctx); - re_node_set_free (&sctx.limits); - if (BE (ret != REG_NOERROR, 0)) - goto free_return; - if (sifted_states[0] != NULL || lim_states[0] != NULL) - break; - do - { - --match_last; - if (match_last < 0) - { - ret = REG_NOMATCH; - goto free_return; - } - } while (mctx->state_log[match_last] == NULL - || !mctx->state_log[match_last]->halt); - halt_node = check_halt_state_context (mctx, - mctx->state_log[match_last], - match_last); - } - ret = merge_state_array (dfa, sifted_states, lim_states, - match_last + 1); - re_free (lim_states); - lim_states = NULL; - if (BE (ret != REG_NOERROR, 0)) - goto free_return; - } - else - { - sift_ctx_init (&sctx, sifted_states, lim_states, halt_node, match_last); - ret = sift_states_backward (mctx, &sctx); - re_node_set_free (&sctx.limits); - if (BE (ret != REG_NOERROR, 0)) - goto free_return; - if (sifted_states[0] == NULL) - { - ret = REG_NOMATCH; - goto free_return; - } - } - re_free (mctx->state_log); - mctx->state_log = sifted_states; - sifted_states = NULL; - mctx->last_node = halt_node; - mctx->match_last = match_last; - ret = REG_NOERROR; - free_return: - re_free (sifted_states); - re_free (lim_states); - return ret; -} - -/* Acquire an initial state and return it. - We must select appropriate initial state depending on the context, - since initial states may have constraints like "\<", "^", etc.. */ - -static inline re_dfastate_t * -__attribute ((always_inline)) internal_function -acquire_init_state_context (reg_errcode_t *err, const re_match_context_t *mctx, - int idx) -{ - const re_dfa_t *const dfa = mctx->dfa; - if (dfa->init_state->has_constraint) - { - unsigned int context; - context = re_string_context_at (&mctx->input, idx - 1, mctx->eflags); - if (IS_WORD_CONTEXT (context)) - return dfa->init_state_word; - else if (IS_ORDINARY_CONTEXT (context)) - return dfa->init_state; - else if (IS_BEGBUF_CONTEXT (context) && IS_NEWLINE_CONTEXT (context)) - return dfa->init_state_begbuf; - else if (IS_NEWLINE_CONTEXT (context)) - return dfa->init_state_nl; - else if (IS_BEGBUF_CONTEXT (context)) - { - /* It is relatively rare case, then calculate on demand. */ - return re_acquire_state_context (err, dfa, - dfa->init_state->entrance_nodes, - context); - } - else - /* Must not happen? */ - return dfa->init_state; - } - else - return dfa->init_state; -} - -/* Check whether the regular expression match input string INPUT or not, - and return the index where the matching end, return -1 if not match, - or return -2 in case of an error. - FL_LONGEST_MATCH means we want the POSIX longest matching. - If P_MATCH_FIRST is not NULL, and the match fails, it is set to the - next place where we may want to try matching. - Note that the matcher assume that the maching starts from the current - index of the buffer. */ - -static int -internal_function -check_matching (re_match_context_t *mctx, int fl_longest_match, - int *p_match_first) -{ - const re_dfa_t *const dfa = mctx->dfa; - reg_errcode_t err; - int match = 0; - int match_last = -1; - int cur_str_idx = re_string_cur_idx (&mctx->input); - re_dfastate_t *cur_state; - int at_init_state = p_match_first != NULL; - int next_start_idx = cur_str_idx; - - err = REG_NOERROR; - cur_state = acquire_init_state_context (&err, mctx, cur_str_idx); - /* An initial state must not be NULL (invalid). */ - if (BE (cur_state == NULL, 0)) - { - assert (err == REG_ESPACE); - return -2; - } - - if (mctx->state_log != NULL) - { - mctx->state_log[cur_str_idx] = cur_state; - - /* Check OP_OPEN_SUBEXP in the initial state in case that we use them - later. E.g. Processing back references. */ - if (BE (dfa->nbackref, 0)) - { - at_init_state = 0; - err = check_subexp_matching_top (mctx, &cur_state->nodes, 0); - if (BE (err != REG_NOERROR, 0)) - return err; - - if (cur_state->has_backref) - { - err = transit_state_bkref (mctx, &cur_state->nodes); - if (BE (err != REG_NOERROR, 0)) - return err; - } - } - } - - /* If the RE accepts NULL string. */ - if (BE (cur_state->halt, 0)) - { - if (!cur_state->has_constraint - || check_halt_state_context (mctx, cur_state, cur_str_idx)) - { - if (!fl_longest_match) - return cur_str_idx; - else - { - match_last = cur_str_idx; - match = 1; - } - } - } - - while (!re_string_eoi (&mctx->input)) - { - re_dfastate_t *old_state = cur_state; - int next_char_idx = re_string_cur_idx (&mctx->input) + 1; - - if (BE (next_char_idx >= mctx->input.bufs_len, 0) - || (BE (next_char_idx >= mctx->input.valid_len, 0) - && mctx->input.valid_len < mctx->input.len)) - { - err = extend_buffers (mctx); - if (BE (err != REG_NOERROR, 0)) - { - assert (err == REG_ESPACE); - return -2; - } - } - - cur_state = transit_state (&err, mctx, cur_state); - if (mctx->state_log != NULL) - cur_state = merge_state_with_log (&err, mctx, cur_state); - - if (cur_state == NULL) - { - /* Reached the invalid state or an error. Try to recover a valid - state using the state log, if available and if we have not - already found a valid (even if not the longest) match. */ - if (BE (err != REG_NOERROR, 0)) - return -2; - - if (mctx->state_log == NULL - || (match && !fl_longest_match) - || (cur_state = find_recover_state (&err, mctx)) == NULL) - break; - } - - if (BE (at_init_state, 0)) - { - if (old_state == cur_state) - next_start_idx = next_char_idx; - else - at_init_state = 0; - } - - if (cur_state->halt) - { - /* Reached a halt state. - Check the halt state can satisfy the current context. */ - if (!cur_state->has_constraint - || check_halt_state_context (mctx, cur_state, - re_string_cur_idx (&mctx->input))) - { - /* We found an appropriate halt state. */ - match_last = re_string_cur_idx (&mctx->input); - match = 1; - - /* We found a match, do not modify match_first below. */ - p_match_first = NULL; - if (!fl_longest_match) - break; - } - } - } - - if (p_match_first) - *p_match_first += next_start_idx; - - return match_last; -} - -/* Check NODE match the current context. */ - -static int -internal_function -check_halt_node_context (const re_dfa_t *dfa, int node, unsigned int context) -{ - re_token_type_t type = dfa->nodes[node].type; - unsigned int constraint = dfa->nodes[node].constraint; - if (type != END_OF_RE) - return 0; - if (!constraint) - return 1; - if (NOT_SATISFY_NEXT_CONSTRAINT (constraint, context)) - return 0; - return 1; -} - -/* Check the halt state STATE match the current context. - Return 0 if not match, if the node, STATE has, is a halt node and - match the context, return the node. */ - -static int -internal_function -check_halt_state_context (const re_match_context_t *mctx, - const re_dfastate_t *state, int idx) -{ - int i; - unsigned int context; -#ifdef DEBUG - assert (state->halt); -#endif - context = re_string_context_at (&mctx->input, idx, mctx->eflags); - for (i = 0; i < state->nodes.nelem; ++i) - if (check_halt_node_context (mctx->dfa, state->nodes.elems[i], context)) - return state->nodes.elems[i]; - return 0; -} - -/* Compute the next node to which "NFA" transit from NODE("NFA" is a NFA - corresponding to the DFA). - Return the destination node, and update EPS_VIA_NODES, return -1 in case - of errors. */ - -static int -internal_function -proceed_next_node (const re_match_context_t *mctx, int nregs, regmatch_t *regs, - int *pidx, int node, re_node_set *eps_via_nodes, - struct re_fail_stack_t *fs) -{ - const re_dfa_t *const dfa = mctx->dfa; - int i, err; - if (IS_EPSILON_NODE (dfa->nodes[node].type)) - { - re_node_set *cur_nodes = &mctx->state_log[*pidx]->nodes; - re_node_set *edests = &dfa->edests[node]; - int dest_node; - err = re_node_set_insert (eps_via_nodes, node); - if (BE (err < 0, 0)) - return -2; - /* Pick up a valid destination, or return -1 if none is found. */ - for (dest_node = -1, i = 0; i < edests->nelem; ++i) - { - int candidate = edests->elems[i]; - if (!re_node_set_contains (cur_nodes, candidate)) - continue; - if (dest_node == -1) - dest_node = candidate; - - else - { - /* In order to avoid infinite loop like "(a*)*", return the second - epsilon-transition if the first was already considered. */ - if (re_node_set_contains (eps_via_nodes, dest_node)) - return candidate; - - /* Otherwise, push the second epsilon-transition on the fail stack. */ - else if (fs != NULL - && push_fail_stack (fs, *pidx, candidate, nregs, regs, - eps_via_nodes)) - return -2; - - /* We know we are going to exit. */ - break; - } - } - return dest_node; - } - else - { - int naccepted = 0; - re_token_type_t type = dfa->nodes[node].type; - -#ifdef RE_ENABLE_I18N - if (dfa->nodes[node].accept_mb) - naccepted = check_node_accept_bytes (dfa, node, &mctx->input, *pidx); - else -#endif /* RE_ENABLE_I18N */ - if (type == OP_BACK_REF) - { - int subexp_idx = dfa->nodes[node].opr.idx + 1; - naccepted = regs[subexp_idx].rm_eo - regs[subexp_idx].rm_so; - if (fs != NULL) - { - if (regs[subexp_idx].rm_so == -1 || regs[subexp_idx].rm_eo == -1) - return -1; - else if (naccepted) - { - char *buf = (char *) re_string_get_buffer (&mctx->input); - if (memcmp (buf + regs[subexp_idx].rm_so, buf + *pidx, - naccepted) != 0) - return -1; - } - } - - if (naccepted == 0) - { - int dest_node; - err = re_node_set_insert (eps_via_nodes, node); - if (BE (err < 0, 0)) - return -2; - dest_node = dfa->edests[node].elems[0]; - if (re_node_set_contains (&mctx->state_log[*pidx]->nodes, - dest_node)) - return dest_node; - } - } - - if (naccepted != 0 - || check_node_accept (mctx, dfa->nodes + node, *pidx)) - { - int dest_node = dfa->nexts[node]; - *pidx = (naccepted == 0) ? *pidx + 1 : *pidx + naccepted; - if (fs && (*pidx > mctx->match_last || mctx->state_log[*pidx] == NULL - || !re_node_set_contains (&mctx->state_log[*pidx]->nodes, - dest_node))) - return -1; - re_node_set_empty (eps_via_nodes); - return dest_node; - } - } - return -1; -} - -static reg_errcode_t -internal_function -push_fail_stack (struct re_fail_stack_t *fs, int str_idx, int dest_node, - int nregs, regmatch_t *regs, re_node_set *eps_via_nodes) -{ - reg_errcode_t err; - int num = fs->num++; - if (fs->num == fs->alloc) - { - struct re_fail_stack_ent_t *new_array; - new_array = realloc (fs->stack, (sizeof (struct re_fail_stack_ent_t) - * fs->alloc * 2)); - if (new_array == NULL) - return REG_ESPACE; - fs->alloc *= 2; - fs->stack = new_array; - } - fs->stack[num].idx = str_idx; - fs->stack[num].node = dest_node; - fs->stack[num].regs = re_malloc (regmatch_t, nregs); - if (fs->stack[num].regs == NULL) - return REG_ESPACE; - memcpy (fs->stack[num].regs, regs, sizeof (regmatch_t) * nregs); - err = re_node_set_init_copy (&fs->stack[num].eps_via_nodes, eps_via_nodes); - return err; -} - -static int -internal_function -pop_fail_stack (struct re_fail_stack_t *fs, int *pidx, int nregs, - regmatch_t *regs, re_node_set *eps_via_nodes) -{ - int num = --fs->num; - assert (num >= 0); - *pidx = fs->stack[num].idx; - memcpy (regs, fs->stack[num].regs, sizeof (regmatch_t) * nregs); - re_node_set_free (eps_via_nodes); - re_free (fs->stack[num].regs); - *eps_via_nodes = fs->stack[num].eps_via_nodes; - return fs->stack[num].node; -} - -/* Set the positions where the subexpressions are starts/ends to registers - PMATCH. - Note: We assume that pmatch[0] is already set, and - pmatch[i].rm_so == pmatch[i].rm_eo == -1 for 0 < i < nmatch. */ - -static reg_errcode_t -internal_function -set_regs (const regex_t *preg, const re_match_context_t *mctx, size_t nmatch, - regmatch_t *pmatch, int fl_backtrack) -{ - const re_dfa_t *dfa = (const re_dfa_t *) preg->buffer; - int idx, cur_node; - re_node_set eps_via_nodes; - struct re_fail_stack_t *fs; - struct re_fail_stack_t fs_body = { 0, 2, NULL }; - regmatch_t *prev_idx_match; - int prev_idx_match_malloced = 0; - -#ifdef DEBUG - assert (nmatch > 1); - assert (mctx->state_log != NULL); -#endif - if (fl_backtrack) - { - fs = &fs_body; - fs->stack = re_malloc (struct re_fail_stack_ent_t, fs->alloc); - if (fs->stack == NULL) - return REG_ESPACE; - } - else - fs = NULL; - - cur_node = dfa->init_node; - re_node_set_init_empty (&eps_via_nodes); - -#ifdef HAVE_ALLOCA - if (__libc_use_alloca (nmatch * sizeof (regmatch_t))) - prev_idx_match = (regmatch_t *) alloca (nmatch * sizeof (regmatch_t)); - else -#endif - { - prev_idx_match = re_malloc (regmatch_t, nmatch); - if (prev_idx_match == NULL) - { - free_fail_stack_return (fs); - return REG_ESPACE; - } - prev_idx_match_malloced = 1; - } - memcpy (prev_idx_match, pmatch, sizeof (regmatch_t) * nmatch); - - for (idx = pmatch[0].rm_so; idx <= pmatch[0].rm_eo ;) - { - update_regs (dfa, pmatch, prev_idx_match, cur_node, idx, nmatch); - - if (idx == pmatch[0].rm_eo && cur_node == mctx->last_node) - { - unsigned int reg_idx; - if (fs) - { - for (reg_idx = 0; reg_idx < nmatch; ++reg_idx) - if (pmatch[reg_idx].rm_so > -1 && pmatch[reg_idx].rm_eo == -1) - break; - if (reg_idx == nmatch) - { - re_node_set_free (&eps_via_nodes); - if (prev_idx_match_malloced) - re_free (prev_idx_match); - return free_fail_stack_return (fs); - } - cur_node = pop_fail_stack (fs, &idx, nmatch, pmatch, - &eps_via_nodes); - } - else - { - re_node_set_free (&eps_via_nodes); - if (prev_idx_match_malloced) - re_free (prev_idx_match); - return REG_NOERROR; - } - } - - /* Proceed to next node. */ - cur_node = proceed_next_node (mctx, nmatch, pmatch, &idx, cur_node, - &eps_via_nodes, fs); - - if (BE (cur_node < 0, 0)) - { - if (BE (cur_node == -2, 0)) - { - re_node_set_free (&eps_via_nodes); - if (prev_idx_match_malloced) - re_free (prev_idx_match); - free_fail_stack_return (fs); - return REG_ESPACE; - } - if (fs) - cur_node = pop_fail_stack (fs, &idx, nmatch, pmatch, - &eps_via_nodes); - else - { - re_node_set_free (&eps_via_nodes); - if (prev_idx_match_malloced) - re_free (prev_idx_match); - return REG_NOMATCH; - } - } - } - re_node_set_free (&eps_via_nodes); - if (prev_idx_match_malloced) - re_free (prev_idx_match); - return free_fail_stack_return (fs); -} - -static reg_errcode_t -internal_function -free_fail_stack_return (struct re_fail_stack_t *fs) -{ - if (fs) - { - int fs_idx; - for (fs_idx = 0; fs_idx < fs->num; ++fs_idx) - { - re_node_set_free (&fs->stack[fs_idx].eps_via_nodes); - re_free (fs->stack[fs_idx].regs); - } - re_free (fs->stack); - } - return REG_NOERROR; -} - -static void -internal_function -update_regs (const re_dfa_t *dfa, regmatch_t *pmatch, - regmatch_t *prev_idx_match, int cur_node, int cur_idx, int nmatch) -{ - int type = dfa->nodes[cur_node].type; - if (type == OP_OPEN_SUBEXP) - { - int reg_num = dfa->nodes[cur_node].opr.idx + 1; - - /* We are at the first node of this sub expression. */ - if (reg_num < nmatch) - { - pmatch[reg_num].rm_so = cur_idx; - pmatch[reg_num].rm_eo = -1; - } - } - else if (type == OP_CLOSE_SUBEXP) - { - int reg_num = dfa->nodes[cur_node].opr.idx + 1; - if (reg_num < nmatch) - { - /* We are at the last node of this sub expression. */ - if (pmatch[reg_num].rm_so < cur_idx) - { - pmatch[reg_num].rm_eo = cur_idx; - /* This is a non-empty match or we are not inside an optional - subexpression. Accept this right away. */ - memcpy (prev_idx_match, pmatch, sizeof (regmatch_t) * nmatch); - } - else - { - if (dfa->nodes[cur_node].opt_subexp - && prev_idx_match[reg_num].rm_so != -1) - /* We transited through an empty match for an optional - subexpression, like (a?)*, and this is not the subexp's - first match. Copy back the old content of the registers - so that matches of an inner subexpression are undone as - well, like in ((a?))*. */ - memcpy (pmatch, prev_idx_match, sizeof (regmatch_t) * nmatch); - else - /* We completed a subexpression, but it may be part of - an optional one, so do not update PREV_IDX_MATCH. */ - pmatch[reg_num].rm_eo = cur_idx; - } - } - } -} - -/* This function checks the STATE_LOG from the SCTX->last_str_idx to 0 - and sift the nodes in each states according to the following rules. - Updated state_log will be wrote to STATE_LOG. - - Rules: We throw away the Node `a' in the STATE_LOG[STR_IDX] if... - 1. When STR_IDX == MATCH_LAST(the last index in the state_log): - If `a' isn't the LAST_NODE and `a' can't epsilon transit to - the LAST_NODE, we throw away the node `a'. - 2. When 0 <= STR_IDX < MATCH_LAST and `a' accepts - string `s' and transit to `b': - i. If 'b' isn't in the STATE_LOG[STR_IDX+strlen('s')], we throw - away the node `a'. - ii. If 'b' is in the STATE_LOG[STR_IDX+strlen('s')] but 'b' is - thrown away, we throw away the node `a'. - 3. When 0 <= STR_IDX < MATCH_LAST and 'a' epsilon transit to 'b': - i. If 'b' isn't in the STATE_LOG[STR_IDX], we throw away the - node `a'. - ii. If 'b' is in the STATE_LOG[STR_IDX] but 'b' is thrown away, - we throw away the node `a'. */ - -#define STATE_NODE_CONTAINS(state,node) \ - ((state) != NULL && re_node_set_contains (&(state)->nodes, node)) - -static reg_errcode_t -internal_function -sift_states_backward (const re_match_context_t *mctx, re_sift_context_t *sctx) -{ - reg_errcode_t err; - int null_cnt = 0; - int str_idx = sctx->last_str_idx; - re_node_set cur_dest; - -#ifdef DEBUG - assert (mctx->state_log != NULL && mctx->state_log[str_idx] != NULL); -#endif - - /* Build sifted state_log[str_idx]. It has the nodes which can epsilon - transit to the last_node and the last_node itself. */ - err = re_node_set_init_1 (&cur_dest, sctx->last_node); - if (BE (err != REG_NOERROR, 0)) - return err; - err = update_cur_sifted_state (mctx, sctx, str_idx, &cur_dest); - if (BE (err != REG_NOERROR, 0)) - goto free_return; - - /* Then check each states in the state_log. */ - while (str_idx > 0) - { - /* Update counters. */ - null_cnt = (sctx->sifted_states[str_idx] == NULL) ? null_cnt + 1 : 0; - if (null_cnt > mctx->max_mb_elem_len) - { - memset (sctx->sifted_states, '\0', - sizeof (re_dfastate_t *) * str_idx); - re_node_set_free (&cur_dest); - return REG_NOERROR; - } - re_node_set_empty (&cur_dest); - --str_idx; - - if (mctx->state_log[str_idx]) - { - err = build_sifted_states (mctx, sctx, str_idx, &cur_dest); - if (BE (err != REG_NOERROR, 0)) - goto free_return; - } - - /* Add all the nodes which satisfy the following conditions: - - It can epsilon transit to a node in CUR_DEST. - - It is in CUR_SRC. - And update state_log. */ - err = update_cur_sifted_state (mctx, sctx, str_idx, &cur_dest); - if (BE (err != REG_NOERROR, 0)) - goto free_return; - } - err = REG_NOERROR; - free_return: - re_node_set_free (&cur_dest); - return err; -} - -static reg_errcode_t -internal_function -build_sifted_states (const re_match_context_t *mctx, re_sift_context_t *sctx, - int str_idx, re_node_set *cur_dest) -{ - const re_dfa_t *const dfa = mctx->dfa; - const re_node_set *cur_src = &mctx->state_log[str_idx]->non_eps_nodes; - int i; - - /* Then build the next sifted state. - We build the next sifted state on `cur_dest', and update - `sifted_states[str_idx]' with `cur_dest'. - Note: - `cur_dest' is the sifted state from `state_log[str_idx + 1]'. - `cur_src' points the node_set of the old `state_log[str_idx]' - (with the epsilon nodes pre-filtered out). */ - for (i = 0; i < cur_src->nelem; i++) - { - int prev_node = cur_src->elems[i]; - int naccepted = 0; - int ret; - -#ifdef DEBUG - re_token_type_t type = dfa->nodes[prev_node].type; - assert (!IS_EPSILON_NODE (type)); -#endif -#ifdef RE_ENABLE_I18N - /* If the node may accept `multi byte'. */ - if (dfa->nodes[prev_node].accept_mb) - naccepted = sift_states_iter_mb (mctx, sctx, prev_node, - str_idx, sctx->last_str_idx); -#endif /* RE_ENABLE_I18N */ - - /* We don't check backreferences here. - See update_cur_sifted_state(). */ - if (!naccepted - && check_node_accept (mctx, dfa->nodes + prev_node, str_idx) - && STATE_NODE_CONTAINS (sctx->sifted_states[str_idx + 1], - dfa->nexts[prev_node])) - naccepted = 1; - - if (naccepted == 0) - continue; - - if (sctx->limits.nelem) - { - int to_idx = str_idx + naccepted; - if (check_dst_limits (mctx, &sctx->limits, - dfa->nexts[prev_node], to_idx, - prev_node, str_idx)) - continue; - } - ret = re_node_set_insert (cur_dest, prev_node); - if (BE (ret == -1, 0)) - return REG_ESPACE; - } - - return REG_NOERROR; -} - -/* Helper functions. */ - -static reg_errcode_t -internal_function -clean_state_log_if_needed (re_match_context_t *mctx, int next_state_log_idx) -{ - int top = mctx->state_log_top; - - if (next_state_log_idx >= mctx->input.bufs_len - || (next_state_log_idx >= mctx->input.valid_len - && mctx->input.valid_len < mctx->input.len)) - { - reg_errcode_t err; - err = extend_buffers (mctx); - if (BE (err != REG_NOERROR, 0)) - return err; - } - - if (top < next_state_log_idx) - { - memset (mctx->state_log + top + 1, '\0', - sizeof (re_dfastate_t *) * (next_state_log_idx - top)); - mctx->state_log_top = next_state_log_idx; - } - return REG_NOERROR; -} - -static reg_errcode_t -internal_function -merge_state_array (const re_dfa_t *dfa, re_dfastate_t **dst, - re_dfastate_t **src, int num) -{ - int st_idx; - reg_errcode_t err; - for (st_idx = 0; st_idx < num; ++st_idx) - { - if (dst[st_idx] == NULL) - dst[st_idx] = src[st_idx]; - else if (src[st_idx] != NULL) - { - re_node_set merged_set; - err = re_node_set_init_union (&merged_set, &dst[st_idx]->nodes, - &src[st_idx]->nodes); - if (BE (err != REG_NOERROR, 0)) - return err; - dst[st_idx] = re_acquire_state (&err, dfa, &merged_set); - re_node_set_free (&merged_set); - if (BE (err != REG_NOERROR, 0)) - return err; - } - } - return REG_NOERROR; -} - -static reg_errcode_t -internal_function -update_cur_sifted_state (const re_match_context_t *mctx, - re_sift_context_t *sctx, int str_idx, - re_node_set *dest_nodes) -{ - const re_dfa_t *const dfa = mctx->dfa; - reg_errcode_t err = REG_NOERROR; - const re_node_set *candidates; - candidates = ((mctx->state_log[str_idx] == NULL) ? NULL - : &mctx->state_log[str_idx]->nodes); - - if (dest_nodes->nelem == 0) - sctx->sifted_states[str_idx] = NULL; - else - { - if (candidates) - { - /* At first, add the nodes which can epsilon transit to a node in - DEST_NODE. */ - err = add_epsilon_src_nodes (dfa, dest_nodes, candidates); - if (BE (err != REG_NOERROR, 0)) - return err; - - /* Then, check the limitations in the current sift_context. */ - if (sctx->limits.nelem) - { - err = check_subexp_limits (dfa, dest_nodes, candidates, &sctx->limits, - mctx->bkref_ents, str_idx); - if (BE (err != REG_NOERROR, 0)) - return err; - } - } - - sctx->sifted_states[str_idx] = re_acquire_state (&err, dfa, dest_nodes); - if (BE (err != REG_NOERROR, 0)) - return err; - } - - if (candidates && mctx->state_log[str_idx]->has_backref) - { - err = sift_states_bkref (mctx, sctx, str_idx, candidates); - if (BE (err != REG_NOERROR, 0)) - return err; - } - return REG_NOERROR; -} - -static reg_errcode_t -internal_function -add_epsilon_src_nodes (const re_dfa_t *dfa, re_node_set *dest_nodes, - const re_node_set *candidates) -{ - reg_errcode_t err = REG_NOERROR; - int i; - - re_dfastate_t *state = re_acquire_state (&err, dfa, dest_nodes); - if (BE (err != REG_NOERROR, 0)) - return err; - - if (!state->inveclosure.alloc) - { - err = re_node_set_alloc (&state->inveclosure, dest_nodes->nelem); - if (BE (err != REG_NOERROR, 0)) - return REG_ESPACE; - for (i = 0; i < dest_nodes->nelem; i++) - { - err = re_node_set_merge (&state->inveclosure, - dfa->inveclosures + dest_nodes->elems[i]); - if (BE (err != REG_NOERROR, 0)) - return REG_ESPACE; - } - } - return re_node_set_add_intersect (dest_nodes, candidates, - &state->inveclosure); -} - -static reg_errcode_t -internal_function -sub_epsilon_src_nodes (const re_dfa_t *dfa, int node, re_node_set *dest_nodes, - const re_node_set *candidates) -{ - int ecl_idx; - reg_errcode_t err; - re_node_set *inv_eclosure = dfa->inveclosures + node; - re_node_set except_nodes; - re_node_set_init_empty (&except_nodes); - for (ecl_idx = 0; ecl_idx < inv_eclosure->nelem; ++ecl_idx) - { - int cur_node = inv_eclosure->elems[ecl_idx]; - if (cur_node == node) - continue; - if (IS_EPSILON_NODE (dfa->nodes[cur_node].type)) - { - int edst1 = dfa->edests[cur_node].elems[0]; - int edst2 = ((dfa->edests[cur_node].nelem > 1) - ? dfa->edests[cur_node].elems[1] : -1); - if ((!re_node_set_contains (inv_eclosure, edst1) - && re_node_set_contains (dest_nodes, edst1)) - || (edst2 > 0 - && !re_node_set_contains (inv_eclosure, edst2) - && re_node_set_contains (dest_nodes, edst2))) - { - err = re_node_set_add_intersect (&except_nodes, candidates, - dfa->inveclosures + cur_node); - if (BE (err != REG_NOERROR, 0)) - { - re_node_set_free (&except_nodes); - return err; - } - } - } - } - for (ecl_idx = 0; ecl_idx < inv_eclosure->nelem; ++ecl_idx) - { - int cur_node = inv_eclosure->elems[ecl_idx]; - if (!re_node_set_contains (&except_nodes, cur_node)) - { - int idx = re_node_set_contains (dest_nodes, cur_node) - 1; - re_node_set_remove_at (dest_nodes, idx); - } - } - re_node_set_free (&except_nodes); - return REG_NOERROR; -} - -static int -internal_function -check_dst_limits (const re_match_context_t *mctx, re_node_set *limits, - int dst_node, int dst_idx, int src_node, int src_idx) -{ - const re_dfa_t *const dfa = mctx->dfa; - int lim_idx, src_pos, dst_pos; - - int dst_bkref_idx = search_cur_bkref_entry (mctx, dst_idx); - int src_bkref_idx = search_cur_bkref_entry (mctx, src_idx); - for (lim_idx = 0; lim_idx < limits->nelem; ++lim_idx) - { - int subexp_idx; - struct re_backref_cache_entry *ent; - ent = mctx->bkref_ents + limits->elems[lim_idx]; - subexp_idx = dfa->nodes[ent->node].opr.idx; - - dst_pos = check_dst_limits_calc_pos (mctx, limits->elems[lim_idx], - subexp_idx, dst_node, dst_idx, - dst_bkref_idx); - src_pos = check_dst_limits_calc_pos (mctx, limits->elems[lim_idx], - subexp_idx, src_node, src_idx, - src_bkref_idx); - - /* In case of: - ( ) - ( ) - ( ) */ - if (src_pos == dst_pos) - continue; /* This is unrelated limitation. */ - else - return 1; - } - return 0; -} - -static int -internal_function -check_dst_limits_calc_pos_1 (const re_match_context_t *mctx, int boundaries, - int subexp_idx, int from_node, int bkref_idx) -{ - const re_dfa_t *const dfa = mctx->dfa; - const re_node_set *eclosures = dfa->eclosures + from_node; - int node_idx; - - /* Else, we are on the boundary: examine the nodes on the epsilon - closure. */ - for (node_idx = 0; node_idx < eclosures->nelem; ++node_idx) - { - int node = eclosures->elems[node_idx]; - switch (dfa->nodes[node].type) - { - case OP_BACK_REF: - if (bkref_idx != -1) - { - struct re_backref_cache_entry *ent = mctx->bkref_ents + bkref_idx; - do - { - int dst, cpos; - - if (ent->node != node) - continue; - - if (subexp_idx < BITSET_WORD_BITS - && !(ent->eps_reachable_subexps_map - & ((bitset_word_t) 1 << subexp_idx))) - continue; - - /* Recurse trying to reach the OP_OPEN_SUBEXP and - OP_CLOSE_SUBEXP cases below. But, if the - destination node is the same node as the source - node, don't recurse because it would cause an - infinite loop: a regex that exhibits this behavior - is ()\1*\1* */ - dst = dfa->edests[node].elems[0]; - if (dst == from_node) - { - if (boundaries & 1) - return -1; - else /* if (boundaries & 2) */ - return 0; - } - - cpos = - check_dst_limits_calc_pos_1 (mctx, boundaries, subexp_idx, - dst, bkref_idx); - if (cpos == -1 /* && (boundaries & 1) */) - return -1; - if (cpos == 0 && (boundaries & 2)) - return 0; - - if (subexp_idx < BITSET_WORD_BITS) - ent->eps_reachable_subexps_map - &= ~((bitset_word_t) 1 << subexp_idx); - } - while (ent++->more); - } - break; - - case OP_OPEN_SUBEXP: - if ((boundaries & 1) && subexp_idx == dfa->nodes[node].opr.idx) - return -1; - break; - - case OP_CLOSE_SUBEXP: - if ((boundaries & 2) && subexp_idx == dfa->nodes[node].opr.idx) - return 0; - break; - - default: - break; - } - } - - return (boundaries & 2) ? 1 : 0; -} - -static int -internal_function -check_dst_limits_calc_pos (const re_match_context_t *mctx, int limit, - int subexp_idx, int from_node, int str_idx, - int bkref_idx) -{ - struct re_backref_cache_entry *lim = mctx->bkref_ents + limit; - int boundaries; - - /* If we are outside the range of the subexpression, return -1 or 1. */ - if (str_idx < lim->subexp_from) - return -1; - - if (lim->subexp_to < str_idx) - return 1; - - /* If we are within the subexpression, return 0. */ - boundaries = (str_idx == lim->subexp_from); - boundaries |= (str_idx == lim->subexp_to) << 1; - if (boundaries == 0) - return 0; - - /* Else, examine epsilon closure. */ - return check_dst_limits_calc_pos_1 (mctx, boundaries, subexp_idx, - from_node, bkref_idx); -} - -/* Check the limitations of sub expressions LIMITS, and remove the nodes - which are against limitations from DEST_NODES. */ - -static reg_errcode_t -internal_function -check_subexp_limits (const re_dfa_t *dfa, re_node_set *dest_nodes, - const re_node_set *candidates, re_node_set *limits, - struct re_backref_cache_entry *bkref_ents, int str_idx) -{ - reg_errcode_t err; - int node_idx, lim_idx; - - for (lim_idx = 0; lim_idx < limits->nelem; ++lim_idx) - { - int subexp_idx; - struct re_backref_cache_entry *ent; - ent = bkref_ents + limits->elems[lim_idx]; - - if (str_idx <= ent->subexp_from || ent->str_idx < str_idx) - continue; /* This is unrelated limitation. */ - - subexp_idx = dfa->nodes[ent->node].opr.idx; - if (ent->subexp_to == str_idx) - { - int ops_node = -1; - int cls_node = -1; - for (node_idx = 0; node_idx < dest_nodes->nelem; ++node_idx) - { - int node = dest_nodes->elems[node_idx]; - re_token_type_t type = dfa->nodes[node].type; - if (type == OP_OPEN_SUBEXP - && subexp_idx == dfa->nodes[node].opr.idx) - ops_node = node; - else if (type == OP_CLOSE_SUBEXP - && subexp_idx == dfa->nodes[node].opr.idx) - cls_node = node; - } - - /* Check the limitation of the open subexpression. */ - /* Note that (ent->subexp_to = str_idx != ent->subexp_from). */ - if (ops_node >= 0) - { - err = sub_epsilon_src_nodes (dfa, ops_node, dest_nodes, - candidates); - if (BE (err != REG_NOERROR, 0)) - return err; - } - - /* Check the limitation of the close subexpression. */ - if (cls_node >= 0) - for (node_idx = 0; node_idx < dest_nodes->nelem; ++node_idx) - { - int node = dest_nodes->elems[node_idx]; - if (!re_node_set_contains (dfa->inveclosures + node, - cls_node) - && !re_node_set_contains (dfa->eclosures + node, - cls_node)) - { - /* It is against this limitation. - Remove it form the current sifted state. */ - err = sub_epsilon_src_nodes (dfa, node, dest_nodes, - candidates); - if (BE (err != REG_NOERROR, 0)) - return err; - --node_idx; - } - } - } - else /* (ent->subexp_to != str_idx) */ - { - for (node_idx = 0; node_idx < dest_nodes->nelem; ++node_idx) - { - int node = dest_nodes->elems[node_idx]; - re_token_type_t type = dfa->nodes[node].type; - if (type == OP_CLOSE_SUBEXP || type == OP_OPEN_SUBEXP) - { - if (subexp_idx != dfa->nodes[node].opr.idx) - continue; - /* It is against this limitation. - Remove it form the current sifted state. */ - err = sub_epsilon_src_nodes (dfa, node, dest_nodes, - candidates); - if (BE (err != REG_NOERROR, 0)) - return err; - } - } - } - } - return REG_NOERROR; -} - -static reg_errcode_t -internal_function -sift_states_bkref (const re_match_context_t *mctx, re_sift_context_t *sctx, - int str_idx, const re_node_set *candidates) -{ - const re_dfa_t *const dfa = mctx->dfa; - reg_errcode_t err; - int node_idx, node; - re_sift_context_t local_sctx; - int first_idx = search_cur_bkref_entry (mctx, str_idx); - - if (first_idx == -1) - return REG_NOERROR; - - local_sctx.sifted_states = NULL; /* Mark that it hasn't been initialized. */ - - for (node_idx = 0; node_idx < candidates->nelem; ++node_idx) - { - int enabled_idx; - re_token_type_t type; - struct re_backref_cache_entry *entry; - node = candidates->elems[node_idx]; - type = dfa->nodes[node].type; - /* Avoid infinite loop for the REs like "()\1+". */ - if (node == sctx->last_node && str_idx == sctx->last_str_idx) - continue; - if (type != OP_BACK_REF) - continue; - - entry = mctx->bkref_ents + first_idx; - enabled_idx = first_idx; - do - { - int subexp_len; - int to_idx; - int dst_node; - int ret; - re_dfastate_t *cur_state; - - if (entry->node != node) - continue; - subexp_len = entry->subexp_to - entry->subexp_from; - to_idx = str_idx + subexp_len; - dst_node = (subexp_len ? dfa->nexts[node] - : dfa->edests[node].elems[0]); - - if (to_idx > sctx->last_str_idx - || sctx->sifted_states[to_idx] == NULL - || !STATE_NODE_CONTAINS (sctx->sifted_states[to_idx], dst_node) - || check_dst_limits (mctx, &sctx->limits, node, - str_idx, dst_node, to_idx)) - continue; - - if (local_sctx.sifted_states == NULL) - { - local_sctx = *sctx; - err = re_node_set_init_copy (&local_sctx.limits, &sctx->limits); - if (BE (err != REG_NOERROR, 0)) - goto free_return; - } - local_sctx.last_node = node; - local_sctx.last_str_idx = str_idx; - ret = re_node_set_insert (&local_sctx.limits, enabled_idx); - if (BE (ret < 0, 0)) - { - err = REG_ESPACE; - goto free_return; - } - cur_state = local_sctx.sifted_states[str_idx]; - err = sift_states_backward (mctx, &local_sctx); - if (BE (err != REG_NOERROR, 0)) - goto free_return; - if (sctx->limited_states != NULL) - { - err = merge_state_array (dfa, sctx->limited_states, - local_sctx.sifted_states, - str_idx + 1); - if (BE (err != REG_NOERROR, 0)) - goto free_return; - } - local_sctx.sifted_states[str_idx] = cur_state; - re_node_set_remove (&local_sctx.limits, enabled_idx); - - /* mctx->bkref_ents may have changed, reload the pointer. */ - entry = mctx->bkref_ents + enabled_idx; - } - while (enabled_idx++, entry++->more); - } - err = REG_NOERROR; - free_return: - if (local_sctx.sifted_states != NULL) - { - re_node_set_free (&local_sctx.limits); - } - - return err; -} - - -#ifdef RE_ENABLE_I18N -static int -internal_function -sift_states_iter_mb (const re_match_context_t *mctx, re_sift_context_t *sctx, - int node_idx, int str_idx, int max_str_idx) -{ - const re_dfa_t *const dfa = mctx->dfa; - int naccepted; - /* Check the node can accept `multi byte'. */ - naccepted = check_node_accept_bytes (dfa, node_idx, &mctx->input, str_idx); - if (naccepted > 0 && str_idx + naccepted <= max_str_idx && - !STATE_NODE_CONTAINS (sctx->sifted_states[str_idx + naccepted], - dfa->nexts[node_idx])) - /* The node can't accept the `multi byte', or the - destination was already thrown away, then the node - could't accept the current input `multi byte'. */ - naccepted = 0; - /* Otherwise, it is sure that the node could accept - `naccepted' bytes input. */ - return naccepted; -} -#endif /* RE_ENABLE_I18N */ - - -/* Functions for state transition. */ - -/* Return the next state to which the current state STATE will transit by - accepting the current input byte, and update STATE_LOG if necessary. - If STATE can accept a multibyte char/collating element/back reference - update the destination of STATE_LOG. */ - -static re_dfastate_t * -internal_function -transit_state (reg_errcode_t *err, re_match_context_t *mctx, - re_dfastate_t *state) -{ - re_dfastate_t **trtable; - unsigned char ch; - -#ifdef RE_ENABLE_I18N - /* If the current state can accept multibyte. */ - if (BE (state->accept_mb, 0)) - { - *err = transit_state_mb (mctx, state); - if (BE (*err != REG_NOERROR, 0)) - return NULL; - } -#endif /* RE_ENABLE_I18N */ - - /* Then decide the next state with the single byte. */ -#if 0 - if (0) - /* don't use transition table */ - return transit_state_sb (err, mctx, state); -#endif - - /* Use transition table */ - ch = re_string_fetch_byte (&mctx->input); - for (;;) - { - trtable = state->trtable; - if (BE (trtable != NULL, 1)) - return trtable[ch]; - - trtable = state->word_trtable; - if (BE (trtable != NULL, 1)) - { - unsigned int context; - context - = re_string_context_at (&mctx->input, - re_string_cur_idx (&mctx->input) - 1, - mctx->eflags); - if (IS_WORD_CONTEXT (context)) - return trtable[ch + SBC_MAX]; - else - return trtable[ch]; - } - - if (!build_trtable (mctx->dfa, state)) - { - *err = REG_ESPACE; - return NULL; - } - - /* Retry, we now have a transition table. */ - } -} - -/* Update the state_log if we need */ -re_dfastate_t * -internal_function -merge_state_with_log (reg_errcode_t *err, re_match_context_t *mctx, - re_dfastate_t *next_state) -{ - const re_dfa_t *const dfa = mctx->dfa; - int cur_idx = re_string_cur_idx (&mctx->input); - - if (cur_idx > mctx->state_log_top) - { - mctx->state_log[cur_idx] = next_state; - mctx->state_log_top = cur_idx; - } - else if (mctx->state_log[cur_idx] == 0) - { - mctx->state_log[cur_idx] = next_state; - } - else - { - re_dfastate_t *pstate; - unsigned int context; - re_node_set next_nodes, *log_nodes, *table_nodes = NULL; - /* If (state_log[cur_idx] != 0), it implies that cur_idx is - the destination of a multibyte char/collating element/ - back reference. Then the next state is the union set of - these destinations and the results of the transition table. */ - pstate = mctx->state_log[cur_idx]; - log_nodes = pstate->entrance_nodes; - if (next_state != NULL) - { - table_nodes = next_state->entrance_nodes; - *err = re_node_set_init_union (&next_nodes, table_nodes, - log_nodes); - if (BE (*err != REG_NOERROR, 0)) - return NULL; - } - else - next_nodes = *log_nodes; - /* Note: We already add the nodes of the initial state, - then we don't need to add them here. */ - - context = re_string_context_at (&mctx->input, - re_string_cur_idx (&mctx->input) - 1, - mctx->eflags); - next_state = mctx->state_log[cur_idx] - = re_acquire_state_context (err, dfa, &next_nodes, context); - /* We don't need to check errors here, since the return value of - this function is next_state and ERR is already set. */ - - if (table_nodes != NULL) - re_node_set_free (&next_nodes); - } - - if (BE (dfa->nbackref, 0) && next_state != NULL) - { - /* Check OP_OPEN_SUBEXP in the current state in case that we use them - later. We must check them here, since the back references in the - next state might use them. */ - *err = check_subexp_matching_top (mctx, &next_state->nodes, - cur_idx); - if (BE (*err != REG_NOERROR, 0)) - return NULL; - - /* If the next state has back references. */ - if (next_state->has_backref) - { - *err = transit_state_bkref (mctx, &next_state->nodes); - if (BE (*err != REG_NOERROR, 0)) - return NULL; - next_state = mctx->state_log[cur_idx]; - } - } - - return next_state; -} - -/* Skip bytes in the input that correspond to part of a - multi-byte match, then look in the log for a state - from which to restart matching. */ -re_dfastate_t * -internal_function -find_recover_state (reg_errcode_t *err, re_match_context_t *mctx) -{ - re_dfastate_t *cur_state; - do - { - int max = mctx->state_log_top; - int cur_str_idx = re_string_cur_idx (&mctx->input); - - do - { - if (++cur_str_idx > max) - return NULL; - re_string_skip_bytes (&mctx->input, 1); - } - while (mctx->state_log[cur_str_idx] == NULL); - - cur_state = merge_state_with_log (err, mctx, NULL); - } - while (*err == REG_NOERROR && cur_state == NULL); - return cur_state; -} - -/* Helper functions for transit_state. */ - -/* From the node set CUR_NODES, pick up the nodes whose types are - OP_OPEN_SUBEXP and which have corresponding back references in the regular - expression. And register them to use them later for evaluating the - correspoding back references. */ - -static reg_errcode_t -internal_function -check_subexp_matching_top (re_match_context_t *mctx, re_node_set *cur_nodes, - int str_idx) -{ - const re_dfa_t *const dfa = mctx->dfa; - int node_idx; - reg_errcode_t err; - - /* TODO: This isn't efficient. - Because there might be more than one nodes whose types are - OP_OPEN_SUBEXP and whose index is SUBEXP_IDX, we must check all - nodes. - E.g. RE: (a){2} */ - for (node_idx = 0; node_idx < cur_nodes->nelem; ++node_idx) - { - int node = cur_nodes->elems[node_idx]; - if (dfa->nodes[node].type == OP_OPEN_SUBEXP - && dfa->nodes[node].opr.idx < BITSET_WORD_BITS - && (dfa->used_bkref_map - & ((bitset_word_t) 1 << dfa->nodes[node].opr.idx))) - { - err = match_ctx_add_subtop (mctx, node, str_idx); - if (BE (err != REG_NOERROR, 0)) - return err; - } - } - return REG_NOERROR; -} - -#if 0 -/* Return the next state to which the current state STATE will transit by - accepting the current input byte. */ - -static re_dfastate_t * -transit_state_sb (reg_errcode_t *err, re_match_context_t *mctx, - re_dfastate_t *state) -{ - const re_dfa_t *const dfa = mctx->dfa; - re_node_set next_nodes; - re_dfastate_t *next_state; - int node_cnt, cur_str_idx = re_string_cur_idx (&mctx->input); - unsigned int context; - - *err = re_node_set_alloc (&next_nodes, state->nodes.nelem + 1); - if (BE (*err != REG_NOERROR, 0)) - return NULL; - for (node_cnt = 0; node_cnt < state->nodes.nelem; ++node_cnt) - { - int cur_node = state->nodes.elems[node_cnt]; - if (check_node_accept (mctx, dfa->nodes + cur_node, cur_str_idx)) - { - *err = re_node_set_merge (&next_nodes, - dfa->eclosures + dfa->nexts[cur_node]); - if (BE (*err != REG_NOERROR, 0)) - { - re_node_set_free (&next_nodes); - return NULL; - } - } - } - context = re_string_context_at (&mctx->input, cur_str_idx, mctx->eflags); - next_state = re_acquire_state_context (err, dfa, &next_nodes, context); - /* We don't need to check errors here, since the return value of - this function is next_state and ERR is already set. */ - - re_node_set_free (&next_nodes); - re_string_skip_bytes (&mctx->input, 1); - return next_state; -} -#endif - -#ifdef RE_ENABLE_I18N -static reg_errcode_t -internal_function -transit_state_mb (re_match_context_t *mctx, re_dfastate_t *pstate) -{ - const re_dfa_t *const dfa = mctx->dfa; - reg_errcode_t err; - int i; - - for (i = 0; i < pstate->nodes.nelem; ++i) - { - re_node_set dest_nodes, *new_nodes; - int cur_node_idx = pstate->nodes.elems[i]; - int naccepted, dest_idx; - unsigned int context; - re_dfastate_t *dest_state; - - if (!dfa->nodes[cur_node_idx].accept_mb) - continue; - - if (dfa->nodes[cur_node_idx].constraint) - { - context = re_string_context_at (&mctx->input, - re_string_cur_idx (&mctx->input), - mctx->eflags); - if (NOT_SATISFY_NEXT_CONSTRAINT (dfa->nodes[cur_node_idx].constraint, - context)) - continue; - } - - /* How many bytes the node can accept? */ - naccepted = check_node_accept_bytes (dfa, cur_node_idx, &mctx->input, - re_string_cur_idx (&mctx->input)); - if (naccepted == 0) - continue; - - /* The node can accepts `naccepted' bytes. */ - dest_idx = re_string_cur_idx (&mctx->input) + naccepted; - mctx->max_mb_elem_len = ((mctx->max_mb_elem_len < naccepted) ? naccepted - : mctx->max_mb_elem_len); - err = clean_state_log_if_needed (mctx, dest_idx); - if (BE (err != REG_NOERROR, 0)) - return err; -#ifdef DEBUG - assert (dfa->nexts[cur_node_idx] != -1); -#endif - new_nodes = dfa->eclosures + dfa->nexts[cur_node_idx]; - - dest_state = mctx->state_log[dest_idx]; - if (dest_state == NULL) - dest_nodes = *new_nodes; - else - { - err = re_node_set_init_union (&dest_nodes, - dest_state->entrance_nodes, new_nodes); - if (BE (err != REG_NOERROR, 0)) - return err; - } - context = re_string_context_at (&mctx->input, dest_idx - 1, - mctx->eflags); - mctx->state_log[dest_idx] - = re_acquire_state_context (&err, dfa, &dest_nodes, context); - if (dest_state != NULL) - re_node_set_free (&dest_nodes); - if (BE (mctx->state_log[dest_idx] == NULL && err != REG_NOERROR, 0)) - return err; - } - return REG_NOERROR; -} -#endif /* RE_ENABLE_I18N */ - -static reg_errcode_t -internal_function -transit_state_bkref (re_match_context_t *mctx, const re_node_set *nodes) -{ - const re_dfa_t *const dfa = mctx->dfa; - reg_errcode_t err; - int i; - int cur_str_idx = re_string_cur_idx (&mctx->input); - - for (i = 0; i < nodes->nelem; ++i) - { - int dest_str_idx, prev_nelem, bkc_idx; - int node_idx = nodes->elems[i]; - unsigned int context; - const re_token_t *node = dfa->nodes + node_idx; - re_node_set *new_dest_nodes; - - /* Check whether `node' is a backreference or not. */ - if (node->type != OP_BACK_REF) - continue; - - if (node->constraint) - { - context = re_string_context_at (&mctx->input, cur_str_idx, - mctx->eflags); - if (NOT_SATISFY_NEXT_CONSTRAINT (node->constraint, context)) - continue; - } - - /* `node' is a backreference. - Check the substring which the substring matched. */ - bkc_idx = mctx->nbkref_ents; - err = get_subexp (mctx, node_idx, cur_str_idx); - if (BE (err != REG_NOERROR, 0)) - goto free_return; - - /* And add the epsilon closures (which is `new_dest_nodes') of - the backreference to appropriate state_log. */ -#ifdef DEBUG - assert (dfa->nexts[node_idx] != -1); -#endif - for (; bkc_idx < mctx->nbkref_ents; ++bkc_idx) - { - int subexp_len; - re_dfastate_t *dest_state; - struct re_backref_cache_entry *bkref_ent; - bkref_ent = mctx->bkref_ents + bkc_idx; - if (bkref_ent->node != node_idx || bkref_ent->str_idx != cur_str_idx) - continue; - subexp_len = bkref_ent->subexp_to - bkref_ent->subexp_from; - new_dest_nodes = (subexp_len == 0 - ? dfa->eclosures + dfa->edests[node_idx].elems[0] - : dfa->eclosures + dfa->nexts[node_idx]); - dest_str_idx = (cur_str_idx + bkref_ent->subexp_to - - bkref_ent->subexp_from); - context = re_string_context_at (&mctx->input, dest_str_idx - 1, - mctx->eflags); - dest_state = mctx->state_log[dest_str_idx]; - prev_nelem = ((mctx->state_log[cur_str_idx] == NULL) ? 0 - : mctx->state_log[cur_str_idx]->nodes.nelem); - /* Add `new_dest_node' to state_log. */ - if (dest_state == NULL) - { - mctx->state_log[dest_str_idx] - = re_acquire_state_context (&err, dfa, new_dest_nodes, - context); - if (BE (mctx->state_log[dest_str_idx] == NULL - && err != REG_NOERROR, 0)) - goto free_return; - } - else - { - re_node_set dest_nodes; - err = re_node_set_init_union (&dest_nodes, - dest_state->entrance_nodes, - new_dest_nodes); - if (BE (err != REG_NOERROR, 0)) - { - re_node_set_free (&dest_nodes); - goto free_return; - } - mctx->state_log[dest_str_idx] - = re_acquire_state_context (&err, dfa, &dest_nodes, context); - re_node_set_free (&dest_nodes); - if (BE (mctx->state_log[dest_str_idx] == NULL - && err != REG_NOERROR, 0)) - goto free_return; - } - /* We need to check recursively if the backreference can epsilon - transit. */ - if (subexp_len == 0 - && mctx->state_log[cur_str_idx]->nodes.nelem > prev_nelem) - { - err = check_subexp_matching_top (mctx, new_dest_nodes, - cur_str_idx); - if (BE (err != REG_NOERROR, 0)) - goto free_return; - err = transit_state_bkref (mctx, new_dest_nodes); - if (BE (err != REG_NOERROR, 0)) - goto free_return; - } - } - } - err = REG_NOERROR; - free_return: - return err; -} - -/* Enumerate all the candidates which the backreference BKREF_NODE can match - at BKREF_STR_IDX, and register them by match_ctx_add_entry(). - Note that we might collect inappropriate candidates here. - However, the cost of checking them strictly here is too high, then we - delay these checking for prune_impossible_nodes(). */ - -static reg_errcode_t -internal_function -get_subexp (re_match_context_t *mctx, int bkref_node, int bkref_str_idx) -{ - const re_dfa_t *const dfa = mctx->dfa; - int subexp_num, sub_top_idx; - const char *buf = (const char *) re_string_get_buffer (&mctx->input); - /* Return if we have already checked BKREF_NODE at BKREF_STR_IDX. */ - int cache_idx = search_cur_bkref_entry (mctx, bkref_str_idx); - if (cache_idx != -1) - { - const struct re_backref_cache_entry *entry - = mctx->bkref_ents + cache_idx; - do - if (entry->node == bkref_node) - return REG_NOERROR; /* We already checked it. */ - while (entry++->more); - } - - subexp_num = dfa->nodes[bkref_node].opr.idx; - - /* For each sub expression */ - for (sub_top_idx = 0; sub_top_idx < mctx->nsub_tops; ++sub_top_idx) - { - reg_errcode_t err; - re_sub_match_top_t *sub_top = mctx->sub_tops[sub_top_idx]; - re_sub_match_last_t *sub_last; - int sub_last_idx, sl_str, bkref_str_off; - - if (dfa->nodes[sub_top->node].opr.idx != subexp_num) - continue; /* It isn't related. */ - - sl_str = sub_top->str_idx; - bkref_str_off = bkref_str_idx; - /* At first, check the last node of sub expressions we already - evaluated. */ - for (sub_last_idx = 0; sub_last_idx < sub_top->nlasts; ++sub_last_idx) - { - int sl_str_diff; - sub_last = sub_top->lasts[sub_last_idx]; - sl_str_diff = sub_last->str_idx - sl_str; - /* The matched string by the sub expression match with the substring - at the back reference? */ - if (sl_str_diff > 0) - { - if (BE (bkref_str_off + sl_str_diff > mctx->input.valid_len, 0)) - { - /* Not enough chars for a successful match. */ - if (bkref_str_off + sl_str_diff > mctx->input.len) - break; - - err = clean_state_log_if_needed (mctx, - bkref_str_off - + sl_str_diff); - if (BE (err != REG_NOERROR, 0)) - return err; - buf = (const char *) re_string_get_buffer (&mctx->input); - } - if (memcmp (buf + bkref_str_off, buf + sl_str, sl_str_diff) != 0) - /* We don't need to search this sub expression any more. */ - break; - } - bkref_str_off += sl_str_diff; - sl_str += sl_str_diff; - err = get_subexp_sub (mctx, sub_top, sub_last, bkref_node, - bkref_str_idx); - - /* Reload buf, since the preceding call might have reallocated - the buffer. */ - buf = (const char *) re_string_get_buffer (&mctx->input); - - if (err == REG_NOMATCH) - continue; - if (BE (err != REG_NOERROR, 0)) - return err; - } - - if (sub_last_idx < sub_top->nlasts) - continue; - if (sub_last_idx > 0) - ++sl_str; - /* Then, search for the other last nodes of the sub expression. */ - for (; sl_str <= bkref_str_idx; ++sl_str) - { - int cls_node, sl_str_off; - const re_node_set *nodes; - sl_str_off = sl_str - sub_top->str_idx; - /* The matched string by the sub expression match with the substring - at the back reference? */ - if (sl_str_off > 0) - { - if (BE (bkref_str_off >= mctx->input.valid_len, 0)) - { - /* If we are at the end of the input, we cannot match. */ - if (bkref_str_off >= mctx->input.len) - break; - - err = extend_buffers (mctx); - if (BE (err != REG_NOERROR, 0)) - return err; - - buf = (const char *) re_string_get_buffer (&mctx->input); - } - if (buf [bkref_str_off++] != buf[sl_str - 1]) - break; /* We don't need to search this sub expression - any more. */ - } - if (mctx->state_log[sl_str] == NULL) - continue; - /* Does this state have a ')' of the sub expression? */ - nodes = &mctx->state_log[sl_str]->nodes; - cls_node = find_subexp_node (dfa, nodes, subexp_num, - OP_CLOSE_SUBEXP); - if (cls_node == -1) - continue; /* No. */ - if (sub_top->path == NULL) - { - sub_top->path = calloc (sizeof (state_array_t), - sl_str - sub_top->str_idx + 1); - if (sub_top->path == NULL) - return REG_ESPACE; - } - /* Can the OP_OPEN_SUBEXP node arrive the OP_CLOSE_SUBEXP node - in the current context? */ - err = check_arrival (mctx, sub_top->path, sub_top->node, - sub_top->str_idx, cls_node, sl_str, - OP_CLOSE_SUBEXP); - if (err == REG_NOMATCH) - continue; - if (BE (err != REG_NOERROR, 0)) - return err; - sub_last = match_ctx_add_sublast (sub_top, cls_node, sl_str); - if (BE (sub_last == NULL, 0)) - return REG_ESPACE; - err = get_subexp_sub (mctx, sub_top, sub_last, bkref_node, - bkref_str_idx); - if (err == REG_NOMATCH) - continue; - } - } - return REG_NOERROR; -} - -/* Helper functions for get_subexp(). */ - -/* Check SUB_LAST can arrive to the back reference BKREF_NODE at BKREF_STR. - If it can arrive, register the sub expression expressed with SUB_TOP - and SUB_LAST. */ - -static reg_errcode_t -internal_function -get_subexp_sub (re_match_context_t *mctx, const re_sub_match_top_t *sub_top, - re_sub_match_last_t *sub_last, int bkref_node, int bkref_str) -{ - reg_errcode_t err; - int to_idx; - /* Can the subexpression arrive the back reference? */ - err = check_arrival (mctx, &sub_last->path, sub_last->node, - sub_last->str_idx, bkref_node, bkref_str, - OP_OPEN_SUBEXP); - if (err != REG_NOERROR) - return err; - err = match_ctx_add_entry (mctx, bkref_node, bkref_str, sub_top->str_idx, - sub_last->str_idx); - if (BE (err != REG_NOERROR, 0)) - return err; - to_idx = bkref_str + sub_last->str_idx - sub_top->str_idx; - return clean_state_log_if_needed (mctx, to_idx); -} - -/* Find the first node which is '(' or ')' and whose index is SUBEXP_IDX. - Search '(' if FL_OPEN, or search ')' otherwise. - TODO: This function isn't efficient... - Because there might be more than one nodes whose types are - OP_OPEN_SUBEXP and whose index is SUBEXP_IDX, we must check all - nodes. - E.g. RE: (a){2} */ - -static int -internal_function -find_subexp_node (const re_dfa_t *dfa, const re_node_set *nodes, - int subexp_idx, int type) -{ - int cls_idx; - for (cls_idx = 0; cls_idx < nodes->nelem; ++cls_idx) - { - int cls_node = nodes->elems[cls_idx]; - const re_token_t *node = dfa->nodes + cls_node; - if (node->type == type - && node->opr.idx == subexp_idx) - return cls_node; - } - return -1; -} - -/* Check whether the node TOP_NODE at TOP_STR can arrive to the node - LAST_NODE at LAST_STR. We record the path onto PATH since it will be - heavily reused. - Return REG_NOERROR if it can arrive, or REG_NOMATCH otherwise. */ - -static reg_errcode_t -internal_function -check_arrival (re_match_context_t *mctx, state_array_t *path, int top_node, - int top_str, int last_node, int last_str, int type) -{ - const re_dfa_t *const dfa = mctx->dfa; - reg_errcode_t err = REG_NOERROR; - int subexp_num, backup_cur_idx, str_idx, null_cnt; - re_dfastate_t *cur_state = NULL; - re_node_set *cur_nodes, next_nodes; - re_dfastate_t **backup_state_log; - unsigned int context; - - subexp_num = dfa->nodes[top_node].opr.idx; - /* Extend the buffer if we need. */ - if (BE (path->alloc < last_str + mctx->max_mb_elem_len + 1, 0)) - { - re_dfastate_t **new_array; - int old_alloc = path->alloc; - path->alloc += last_str + mctx->max_mb_elem_len + 1; - new_array = re_realloc (path->array, re_dfastate_t *, path->alloc); - if (BE (new_array == NULL, 0)) - { - path->alloc = old_alloc; - return REG_ESPACE; - } - path->array = new_array; - memset (new_array + old_alloc, '\0', - sizeof (re_dfastate_t *) * (path->alloc - old_alloc)); - } - - str_idx = path->next_idx ? path->next_idx : top_str; - - /* Temporary modify MCTX. */ - backup_state_log = mctx->state_log; - backup_cur_idx = mctx->input.cur_idx; - mctx->state_log = path->array; - mctx->input.cur_idx = str_idx; - - /* Setup initial node set. */ - context = re_string_context_at (&mctx->input, str_idx - 1, mctx->eflags); - if (str_idx == top_str) - { - err = re_node_set_init_1 (&next_nodes, top_node); - if (BE (err != REG_NOERROR, 0)) - return err; - err = check_arrival_expand_ecl (dfa, &next_nodes, subexp_num, type); - if (BE (err != REG_NOERROR, 0)) - { - re_node_set_free (&next_nodes); - return err; - } - } - else - { - cur_state = mctx->state_log[str_idx]; - if (cur_state && cur_state->has_backref) - { - err = re_node_set_init_copy (&next_nodes, &cur_state->nodes); - if (BE (err != REG_NOERROR, 0)) - return err; - } - else - re_node_set_init_empty (&next_nodes); - } - if (str_idx == top_str || (cur_state && cur_state->has_backref)) - { - if (next_nodes.nelem) - { - err = expand_bkref_cache (mctx, &next_nodes, str_idx, - subexp_num, type); - if (BE (err != REG_NOERROR, 0)) - { - re_node_set_free (&next_nodes); - return err; - } - } - cur_state = re_acquire_state_context (&err, dfa, &next_nodes, context); - if (BE (cur_state == NULL && err != REG_NOERROR, 0)) - { - re_node_set_free (&next_nodes); - return err; - } - mctx->state_log[str_idx] = cur_state; - } - - for (null_cnt = 0; str_idx < last_str && null_cnt <= mctx->max_mb_elem_len;) - { - re_node_set_empty (&next_nodes); - if (mctx->state_log[str_idx + 1]) - { - err = re_node_set_merge (&next_nodes, - &mctx->state_log[str_idx + 1]->nodes); - if (BE (err != REG_NOERROR, 0)) - { - re_node_set_free (&next_nodes); - return err; - } - } - if (cur_state) - { - err = check_arrival_add_next_nodes (mctx, str_idx, - &cur_state->non_eps_nodes, - &next_nodes); - if (BE (err != REG_NOERROR, 0)) - { - re_node_set_free (&next_nodes); - return err; - } - } - ++str_idx; - if (next_nodes.nelem) - { - err = check_arrival_expand_ecl (dfa, &next_nodes, subexp_num, type); - if (BE (err != REG_NOERROR, 0)) - { - re_node_set_free (&next_nodes); - return err; - } - err = expand_bkref_cache (mctx, &next_nodes, str_idx, - subexp_num, type); - if (BE (err != REG_NOERROR, 0)) - { - re_node_set_free (&next_nodes); - return err; - } - } - context = re_string_context_at (&mctx->input, str_idx - 1, mctx->eflags); - cur_state = re_acquire_state_context (&err, dfa, &next_nodes, context); - if (BE (cur_state == NULL && err != REG_NOERROR, 0)) - { - re_node_set_free (&next_nodes); - return err; - } - mctx->state_log[str_idx] = cur_state; - null_cnt = cur_state == NULL ? null_cnt + 1 : 0; - } - re_node_set_free (&next_nodes); - cur_nodes = (mctx->state_log[last_str] == NULL ? NULL - : &mctx->state_log[last_str]->nodes); - path->next_idx = str_idx; - - /* Fix MCTX. */ - mctx->state_log = backup_state_log; - mctx->input.cur_idx = backup_cur_idx; - - /* Then check the current node set has the node LAST_NODE. */ - if (cur_nodes != NULL && re_node_set_contains (cur_nodes, last_node)) - return REG_NOERROR; - - return REG_NOMATCH; -} - -/* Helper functions for check_arrival. */ - -/* Calculate the destination nodes of CUR_NODES at STR_IDX, and append them - to NEXT_NODES. - TODO: This function is similar to the functions transit_state*(), - however this function has many additional works. - Can't we unify them? */ - -static reg_errcode_t -internal_function -check_arrival_add_next_nodes (re_match_context_t *mctx, int str_idx, - re_node_set *cur_nodes, re_node_set *next_nodes) -{ - const re_dfa_t *const dfa = mctx->dfa; - int result; - int cur_idx; -#ifdef RE_ENABLE_I18N - reg_errcode_t err = REG_NOERROR; -#endif - re_node_set union_set; - re_node_set_init_empty (&union_set); - for (cur_idx = 0; cur_idx < cur_nodes->nelem; ++cur_idx) - { - int naccepted = 0; - int cur_node = cur_nodes->elems[cur_idx]; -#ifdef DEBUG - re_token_type_t type = dfa->nodes[cur_node].type; - assert (!IS_EPSILON_NODE (type)); -#endif -#ifdef RE_ENABLE_I18N - /* If the node may accept `multi byte'. */ - if (dfa->nodes[cur_node].accept_mb) - { - naccepted = check_node_accept_bytes (dfa, cur_node, &mctx->input, - str_idx); - if (naccepted > 1) - { - re_dfastate_t *dest_state; - int next_node = dfa->nexts[cur_node]; - int next_idx = str_idx + naccepted; - dest_state = mctx->state_log[next_idx]; - re_node_set_empty (&union_set); - if (dest_state) - { - err = re_node_set_merge (&union_set, &dest_state->nodes); - if (BE (err != REG_NOERROR, 0)) - { - re_node_set_free (&union_set); - return err; - } - } - result = re_node_set_insert (&union_set, next_node); - if (BE (result < 0, 0)) - { - re_node_set_free (&union_set); - return REG_ESPACE; - } - mctx->state_log[next_idx] = re_acquire_state (&err, dfa, - &union_set); - if (BE (mctx->state_log[next_idx] == NULL - && err != REG_NOERROR, 0)) - { - re_node_set_free (&union_set); - return err; - } - } - } -#endif /* RE_ENABLE_I18N */ - if (naccepted - || check_node_accept (mctx, dfa->nodes + cur_node, str_idx)) - { - result = re_node_set_insert (next_nodes, dfa->nexts[cur_node]); - if (BE (result < 0, 0)) - { - re_node_set_free (&union_set); - return REG_ESPACE; - } - } - } - re_node_set_free (&union_set); - return REG_NOERROR; -} - -/* For all the nodes in CUR_NODES, add the epsilon closures of them to - CUR_NODES, however exclude the nodes which are: - - inside the sub expression whose number is EX_SUBEXP, if FL_OPEN. - - out of the sub expression whose number is EX_SUBEXP, if !FL_OPEN. -*/ - -static reg_errcode_t -internal_function -check_arrival_expand_ecl (const re_dfa_t *dfa, re_node_set *cur_nodes, - int ex_subexp, int type) -{ - reg_errcode_t err; - int idx, outside_node; - re_node_set new_nodes; -#ifdef DEBUG - assert (cur_nodes->nelem); -#endif - err = re_node_set_alloc (&new_nodes, cur_nodes->nelem); - if (BE (err != REG_NOERROR, 0)) - return err; - /* Create a new node set NEW_NODES with the nodes which are epsilon - closures of the node in CUR_NODES. */ - - for (idx = 0; idx < cur_nodes->nelem; ++idx) - { - int cur_node = cur_nodes->elems[idx]; - const re_node_set *eclosure = dfa->eclosures + cur_node; - outside_node = find_subexp_node (dfa, eclosure, ex_subexp, type); - if (outside_node == -1) - { - /* There are no problematic nodes, just merge them. */ - err = re_node_set_merge (&new_nodes, eclosure); - if (BE (err != REG_NOERROR, 0)) - { - re_node_set_free (&new_nodes); - return err; - } - } - else - { - /* There are problematic nodes, re-calculate incrementally. */ - err = check_arrival_expand_ecl_sub (dfa, &new_nodes, cur_node, - ex_subexp, type); - if (BE (err != REG_NOERROR, 0)) - { - re_node_set_free (&new_nodes); - return err; - } - } - } - re_node_set_free (cur_nodes); - *cur_nodes = new_nodes; - return REG_NOERROR; -} - -/* Helper function for check_arrival_expand_ecl. - Check incrementally the epsilon closure of TARGET, and if it isn't - problematic append it to DST_NODES. */ - -static reg_errcode_t -internal_function -check_arrival_expand_ecl_sub (const re_dfa_t *dfa, re_node_set *dst_nodes, - int target, int ex_subexp, int type) -{ - int cur_node; - for (cur_node = target; !re_node_set_contains (dst_nodes, cur_node);) - { - int err; - - if (dfa->nodes[cur_node].type == type - && dfa->nodes[cur_node].opr.idx == ex_subexp) - { - if (type == OP_CLOSE_SUBEXP) - { - err = re_node_set_insert (dst_nodes, cur_node); - if (BE (err == -1, 0)) - return REG_ESPACE; - } - break; - } - err = re_node_set_insert (dst_nodes, cur_node); - if (BE (err == -1, 0)) - return REG_ESPACE; - if (dfa->edests[cur_node].nelem == 0) - break; - if (dfa->edests[cur_node].nelem == 2) - { - err = check_arrival_expand_ecl_sub (dfa, dst_nodes, - dfa->edests[cur_node].elems[1], - ex_subexp, type); - if (BE (err != REG_NOERROR, 0)) - return err; - } - cur_node = dfa->edests[cur_node].elems[0]; - } - return REG_NOERROR; -} - - -/* For all the back references in the current state, calculate the - destination of the back references by the appropriate entry - in MCTX->BKREF_ENTS. */ - -static reg_errcode_t -internal_function -expand_bkref_cache (re_match_context_t *mctx, re_node_set *cur_nodes, - int cur_str, int subexp_num, int type) -{ - const re_dfa_t *const dfa = mctx->dfa; - reg_errcode_t err; - int cache_idx_start = search_cur_bkref_entry (mctx, cur_str); - struct re_backref_cache_entry *ent; - - if (cache_idx_start == -1) - return REG_NOERROR; - - restart: - ent = mctx->bkref_ents + cache_idx_start; - do - { - int to_idx, next_node; - - /* Is this entry ENT is appropriate? */ - if (!re_node_set_contains (cur_nodes, ent->node)) - continue; /* No. */ - - to_idx = cur_str + ent->subexp_to - ent->subexp_from; - /* Calculate the destination of the back reference, and append it - to MCTX->STATE_LOG. */ - if (to_idx == cur_str) - { - /* The backreference did epsilon transit, we must re-check all the - node in the current state. */ - re_node_set new_dests; - reg_errcode_t err2, err3; - next_node = dfa->edests[ent->node].elems[0]; - if (re_node_set_contains (cur_nodes, next_node)) - continue; - err = re_node_set_init_1 (&new_dests, next_node); - err2 = check_arrival_expand_ecl (dfa, &new_dests, subexp_num, type); - err3 = re_node_set_merge (cur_nodes, &new_dests); - re_node_set_free (&new_dests); - if (BE (err != REG_NOERROR || err2 != REG_NOERROR - || err3 != REG_NOERROR, 0)) - { - err = (err != REG_NOERROR ? err - : (err2 != REG_NOERROR ? err2 : err3)); - return err; - } - /* TODO: It is still inefficient... */ - goto restart; - } - else - { - re_node_set union_set; - next_node = dfa->nexts[ent->node]; - if (mctx->state_log[to_idx]) - { - int ret; - if (re_node_set_contains (&mctx->state_log[to_idx]->nodes, - next_node)) - continue; - err = re_node_set_init_copy (&union_set, - &mctx->state_log[to_idx]->nodes); - ret = re_node_set_insert (&union_set, next_node); - if (BE (err != REG_NOERROR || ret < 0, 0)) - { - re_node_set_free (&union_set); - err = err != REG_NOERROR ? err : REG_ESPACE; - return err; - } - } - else - { - err = re_node_set_init_1 (&union_set, next_node); - if (BE (err != REG_NOERROR, 0)) - return err; - } - mctx->state_log[to_idx] = re_acquire_state (&err, dfa, &union_set); - re_node_set_free (&union_set); - if (BE (mctx->state_log[to_idx] == NULL - && err != REG_NOERROR, 0)) - return err; - } - } - while (ent++->more); - return REG_NOERROR; -} - -/* Build transition table for the state. - Return 1 if succeeded, otherwise return NULL. */ - -static int -internal_function -build_trtable (const re_dfa_t *dfa, re_dfastate_t *state) -{ - reg_errcode_t err; - int i, j, ch, need_word_trtable = 0; - bitset_word_t elem, mask; - bool dests_node_malloced = false; - bool dest_states_malloced = false; - int ndests; /* Number of the destination states from `state'. */ - re_dfastate_t **trtable; - re_dfastate_t **dest_states = NULL, **dest_states_word, **dest_states_nl; - re_node_set follows, *dests_node; - bitset_t *dests_ch; - bitset_t acceptable; - - struct dests_alloc - { - re_node_set dests_node[SBC_MAX]; - bitset_t dests_ch[SBC_MAX]; - } *dests_alloc; - - /* We build DFA states which corresponds to the destination nodes - from `state'. `dests_node[i]' represents the nodes which i-th - destination state contains, and `dests_ch[i]' represents the - characters which i-th destination state accepts. */ -#ifdef HAVE_ALLOCA - if (__libc_use_alloca (sizeof (struct dests_alloc))) - dests_alloc = (struct dests_alloc *) alloca (sizeof (struct dests_alloc)); - else -#endif - { - dests_alloc = re_malloc (struct dests_alloc, 1); - if (BE (dests_alloc == NULL, 0)) - return 0; - dests_node_malloced = true; - } - dests_node = dests_alloc->dests_node; - dests_ch = dests_alloc->dests_ch; - - /* Initialize transiton table. */ - state->word_trtable = state->trtable = NULL; - - /* At first, group all nodes belonging to `state' into several - destinations. */ - ndests = group_nodes_into_DFAstates (dfa, state, dests_node, dests_ch); - if (BE (ndests <= 0, 0)) - { - if (dests_node_malloced) - free (dests_alloc); - /* Return 0 in case of an error, 1 otherwise. */ - if (ndests == 0) - { - state->trtable = (re_dfastate_t **) - calloc (sizeof (re_dfastate_t *), SBC_MAX); - return 1; - } - return 0; - } - - err = re_node_set_alloc (&follows, ndests + 1); - if (BE (err != REG_NOERROR, 0)) - goto out_free; - - /* Avoid arithmetic overflow in size calculation. */ - if (BE ((((SIZE_MAX - (sizeof (re_node_set) + sizeof (bitset_t)) * SBC_MAX) - / (3 * sizeof (re_dfastate_t *))) - < (size_t)ndests), - 0)) - goto out_free; - -#ifdef HAVE_ALLOCA - if (__libc_use_alloca ((sizeof (re_node_set) + sizeof (bitset_t)) * SBC_MAX - + ndests * 3 * sizeof (re_dfastate_t *))) - dest_states = (re_dfastate_t **) - alloca (ndests * 3 * sizeof (re_dfastate_t *)); - else -#endif - { - dest_states = (re_dfastate_t **) - malloc (ndests * 3 * sizeof (re_dfastate_t *)); - if (BE (dest_states == NULL, 0)) - { -out_free: - if (dest_states_malloced) - free (dest_states); - re_node_set_free (&follows); - for (i = 0; i < ndests; ++i) - re_node_set_free (dests_node + i); - if (dests_node_malloced) - free (dests_alloc); - return 0; - } - dest_states_malloced = true; - } - dest_states_word = dest_states + ndests; - dest_states_nl = dest_states_word + ndests; - bitset_empty (acceptable); - - /* Then build the states for all destinations. */ - for (i = 0; i < ndests; ++i) - { - int next_node; - re_node_set_empty (&follows); - /* Merge the follows of this destination states. */ - for (j = 0; j < dests_node[i].nelem; ++j) - { - next_node = dfa->nexts[dests_node[i].elems[j]]; - if (next_node != -1) - { - err = re_node_set_merge (&follows, dfa->eclosures + next_node); - if (BE (err != REG_NOERROR, 0)) - goto out_free; - } - } - dest_states[i] = re_acquire_state_context (&err, dfa, &follows, 0); - if (BE (dest_states[i] == NULL && err != REG_NOERROR, 0)) - goto out_free; - /* If the new state has context constraint, - build appropriate states for these contexts. */ - if (dest_states[i]->has_constraint) - { - dest_states_word[i] = re_acquire_state_context (&err, dfa, &follows, - CONTEXT_WORD); - if (BE (dest_states_word[i] == NULL && err != REG_NOERROR, 0)) - goto out_free; - - if (dest_states[i] != dest_states_word[i] && dfa->mb_cur_max > 1) - need_word_trtable = 1; - - dest_states_nl[i] = re_acquire_state_context (&err, dfa, &follows, - CONTEXT_NEWLINE); - if (BE (dest_states_nl[i] == NULL && err != REG_NOERROR, 0)) - goto out_free; - } - else - { - dest_states_word[i] = dest_states[i]; - dest_states_nl[i] = dest_states[i]; - } - bitset_merge (acceptable, dests_ch[i]); - } - - if (!BE (need_word_trtable, 0)) - { - /* We don't care about whether the following character is a word - character, or we are in a single-byte character set so we can - discern by looking at the character code: allocate a - 256-entry transition table. */ - trtable = state->trtable = - (re_dfastate_t **) calloc (sizeof (re_dfastate_t *), SBC_MAX); - if (BE (trtable == NULL, 0)) - goto out_free; - - /* For all characters ch...: */ - for (i = 0; i < BITSET_WORDS; ++i) - for (ch = i * BITSET_WORD_BITS, elem = acceptable[i], mask = 1; - elem; - mask <<= 1, elem >>= 1, ++ch) - if (BE (elem & 1, 0)) - { - /* There must be exactly one destination which accepts - character ch. See group_nodes_into_DFAstates. */ - for (j = 0; (dests_ch[j][i] & mask) == 0; ++j) - ; - - /* j-th destination accepts the word character ch. */ - if (dfa->word_char[i] & mask) - trtable[ch] = dest_states_word[j]; - else - trtable[ch] = dest_states[j]; - } - } - else - { - /* We care about whether the following character is a word - character, and we are in a multi-byte character set: discern - by looking at the character code: build two 256-entry - transition tables, one starting at trtable[0] and one - starting at trtable[SBC_MAX]. */ - trtable = state->word_trtable = - (re_dfastate_t **) calloc (sizeof (re_dfastate_t *), 2 * SBC_MAX); - if (BE (trtable == NULL, 0)) - goto out_free; - - /* For all characters ch...: */ - for (i = 0; i < BITSET_WORDS; ++i) - for (ch = i * BITSET_WORD_BITS, elem = acceptable[i], mask = 1; - elem; - mask <<= 1, elem >>= 1, ++ch) - if (BE (elem & 1, 0)) - { - /* There must be exactly one destination which accepts - character ch. See group_nodes_into_DFAstates. */ - for (j = 0; (dests_ch[j][i] & mask) == 0; ++j) - ; - - /* j-th destination accepts the word character ch. */ - trtable[ch] = dest_states[j]; - trtable[ch + SBC_MAX] = dest_states_word[j]; - } - } - - /* new line */ - if (bitset_contain (acceptable, NEWLINE_CHAR)) - { - /* The current state accepts newline character. */ - for (j = 0; j < ndests; ++j) - if (bitset_contain (dests_ch[j], NEWLINE_CHAR)) - { - /* k-th destination accepts newline character. */ - trtable[NEWLINE_CHAR] = dest_states_nl[j]; - if (need_word_trtable) - trtable[NEWLINE_CHAR + SBC_MAX] = dest_states_nl[j]; - /* There must be only one destination which accepts - newline. See group_nodes_into_DFAstates. */ - break; - } - } - - if (dest_states_malloced) - free (dest_states); - - re_node_set_free (&follows); - for (i = 0; i < ndests; ++i) - re_node_set_free (dests_node + i); - - if (dests_node_malloced) - free (dests_alloc); - - return 1; -} - -/* Group all nodes belonging to STATE into several destinations. - Then for all destinations, set the nodes belonging to the destination - to DESTS_NODE[i] and set the characters accepted by the destination - to DEST_CH[i]. This function return the number of destinations. */ - -static int -internal_function -group_nodes_into_DFAstates (const re_dfa_t *dfa, const re_dfastate_t *state, - re_node_set *dests_node, bitset_t *dests_ch) -{ - reg_errcode_t err; - int result; - int i, j, k; - int ndests; /* Number of the destinations from `state'. */ - bitset_t accepts; /* Characters a node can accept. */ - const re_node_set *cur_nodes = &state->nodes; - bitset_empty (accepts); - ndests = 0; - - /* For all the nodes belonging to `state', */ - for (i = 0; i < cur_nodes->nelem; ++i) - { - re_token_t *node = &dfa->nodes[cur_nodes->elems[i]]; - re_token_type_t type = node->type; - unsigned int constraint = node->constraint; - - /* Enumerate all single byte character this node can accept. */ - if (type == CHARACTER) - bitset_set (accepts, node->opr.c); - else if (type == SIMPLE_BRACKET) - { - bitset_merge (accepts, node->opr.sbcset); - } - else if (type == OP_PERIOD) - { -#ifdef RE_ENABLE_I18N - if (dfa->mb_cur_max > 1) - bitset_merge (accepts, dfa->sb_char); - else -#endif - bitset_set_all (accepts); - if (!(dfa->syntax & RE_DOT_NEWLINE)) - bitset_clear (accepts, '\n'); - if (dfa->syntax & RE_DOT_NOT_NULL) - bitset_clear (accepts, '\0'); - } -#ifdef RE_ENABLE_I18N - else if (type == OP_UTF8_PERIOD) - { - memset (accepts, '\xff', sizeof (bitset_t) / 2); - if (!(dfa->syntax & RE_DOT_NEWLINE)) - bitset_clear (accepts, '\n'); - if (dfa->syntax & RE_DOT_NOT_NULL) - bitset_clear (accepts, '\0'); - } -#endif - else - continue; - - /* Check the `accepts' and sift the characters which are not - match it the context. */ - if (constraint) - { - if (constraint & NEXT_NEWLINE_CONSTRAINT) - { - bool accepts_newline = bitset_contain (accepts, NEWLINE_CHAR); - bitset_empty (accepts); - if (accepts_newline) - bitset_set (accepts, NEWLINE_CHAR); - else - continue; - } - if (constraint & NEXT_ENDBUF_CONSTRAINT) - { - bitset_empty (accepts); - continue; - } - - if (constraint & NEXT_WORD_CONSTRAINT) - { - bitset_word_t any_set = 0; - if (type == CHARACTER && !node->word_char) - { - bitset_empty (accepts); - continue; - } -#ifdef RE_ENABLE_I18N - if (dfa->mb_cur_max > 1) - for (j = 0; j < BITSET_WORDS; ++j) - any_set |= (accepts[j] &= (dfa->word_char[j] | ~dfa->sb_char[j])); - else -#endif - for (j = 0; j < BITSET_WORDS; ++j) - any_set |= (accepts[j] &= dfa->word_char[j]); - if (!any_set) - continue; - } - if (constraint & NEXT_NOTWORD_CONSTRAINT) - { - bitset_word_t any_set = 0; - if (type == CHARACTER && node->word_char) - { - bitset_empty (accepts); - continue; - } -#ifdef RE_ENABLE_I18N - if (dfa->mb_cur_max > 1) - for (j = 0; j < BITSET_WORDS; ++j) - any_set |= (accepts[j] &= ~(dfa->word_char[j] & dfa->sb_char[j])); - else -#endif - for (j = 0; j < BITSET_WORDS; ++j) - any_set |= (accepts[j] &= ~dfa->word_char[j]); - if (!any_set) - continue; - } - } - - /* Then divide `accepts' into DFA states, or create a new - state. Above, we make sure that accepts is not empty. */ - for (j = 0; j < ndests; ++j) - { - bitset_t intersec; /* Intersection sets, see below. */ - bitset_t remains; - /* Flags, see below. */ - bitset_word_t has_intersec, not_subset, not_consumed; - - /* Optimization, skip if this state doesn't accept the character. */ - if (type == CHARACTER && !bitset_contain (dests_ch[j], node->opr.c)) - continue; - - /* Enumerate the intersection set of this state and `accepts'. */ - has_intersec = 0; - for (k = 0; k < BITSET_WORDS; ++k) - has_intersec |= intersec[k] = accepts[k] & dests_ch[j][k]; - /* And skip if the intersection set is empty. */ - if (!has_intersec) - continue; - - /* Then check if this state is a subset of `accepts'. */ - not_subset = not_consumed = 0; - for (k = 0; k < BITSET_WORDS; ++k) - { - not_subset |= remains[k] = ~accepts[k] & dests_ch[j][k]; - not_consumed |= accepts[k] = accepts[k] & ~dests_ch[j][k]; - } - - /* If this state isn't a subset of `accepts', create a - new group state, which has the `remains'. */ - if (not_subset) - { - bitset_copy (dests_ch[ndests], remains); - bitset_copy (dests_ch[j], intersec); - err = re_node_set_init_copy (dests_node + ndests, &dests_node[j]); - if (BE (err != REG_NOERROR, 0)) - goto error_return; - ++ndests; - } - - /* Put the position in the current group. */ - result = re_node_set_insert (&dests_node[j], cur_nodes->elems[i]); - if (BE (result < 0, 0)) - goto error_return; - - /* If all characters are consumed, go to next node. */ - if (!not_consumed) - break; - } - /* Some characters remain, create a new group. */ - if (j == ndests) - { - bitset_copy (dests_ch[ndests], accepts); - err = re_node_set_init_1 (dests_node + ndests, cur_nodes->elems[i]); - if (BE (err != REG_NOERROR, 0)) - goto error_return; - ++ndests; - bitset_empty (accepts); - } - } - return ndests; - error_return: - for (j = 0; j < ndests; ++j) - re_node_set_free (dests_node + j); - return -1; -} - -#ifdef RE_ENABLE_I18N -/* Check how many bytes the node `dfa->nodes[node_idx]' accepts. - Return the number of the bytes the node accepts. - STR_IDX is the current index of the input string. - - This function handles the nodes which can accept one character, or - one collating element like '.', '[a-z]', opposite to the other nodes - can only accept one byte. */ - -static int -internal_function -check_node_accept_bytes (const re_dfa_t *dfa, int node_idx, - const re_string_t *input, int str_idx) -{ - const re_token_t *node = dfa->nodes + node_idx; - int char_len, elem_len; - int i; - wint_t wc; - - if (BE (node->type == OP_UTF8_PERIOD, 0)) - { - unsigned char c = re_string_byte_at (input, str_idx), d; - if (BE (c < 0xc2, 1)) - return 0; - - if (str_idx + 2 > input->len) - return 0; - - d = re_string_byte_at (input, str_idx + 1); - if (c < 0xe0) - return (d < 0x80 || d > 0xbf) ? 0 : 2; - else if (c < 0xf0) - { - char_len = 3; - if (c == 0xe0 && d < 0xa0) - return 0; - } - else if (c < 0xf8) - { - char_len = 4; - if (c == 0xf0 && d < 0x90) - return 0; - } - else if (c < 0xfc) - { - char_len = 5; - if (c == 0xf8 && d < 0x88) - return 0; - } - else if (c < 0xfe) - { - char_len = 6; - if (c == 0xfc && d < 0x84) - return 0; - } - else - return 0; - - if (str_idx + char_len > input->len) - return 0; - - for (i = 1; i < char_len; ++i) - { - d = re_string_byte_at (input, str_idx + i); - if (d < 0x80 || d > 0xbf) - return 0; - } - return char_len; - } - - char_len = re_string_char_size_at (input, str_idx); - if (node->type == OP_PERIOD) - { - if (char_len <= 1) - return 0; - /* FIXME: I don't think this if is needed, as both '\n' - and '\0' are char_len == 1. */ - /* '.' accepts any one character except the following two cases. */ - if ((!(dfa->syntax & RE_DOT_NEWLINE) && - re_string_byte_at (input, str_idx) == '\n') || - ((dfa->syntax & RE_DOT_NOT_NULL) && - re_string_byte_at (input, str_idx) == '\0')) - return 0; - return char_len; - } - - elem_len = re_string_elem_size_at (input, str_idx); - wc = __btowc(*(input->mbs+str_idx)); - if (((elem_len <= 1 && char_len <= 1) || char_len == 0) && (wc != WEOF && wc < SBC_MAX)) - return 0; - - if (node->type == COMPLEX_BRACKET) - { - const re_charset_t *cset = node->opr.mbcset; -# ifdef _LIBC - const unsigned char *pin - = ((const unsigned char *) re_string_get_buffer (input) + str_idx); - int j; - uint32_t nrules; -# endif /* _LIBC */ - int match_len = 0; - wchar_t wc = ((cset->nranges || cset->nchar_classes || cset->nmbchars) - ? re_string_wchar_at (input, str_idx) : 0); - - /* match with multibyte character? */ - for (i = 0; i < cset->nmbchars; ++i) - if (wc == cset->mbchars[i]) - { - match_len = char_len; - goto check_node_accept_bytes_match; - } - /* match with character_class? */ - for (i = 0; i < cset->nchar_classes; ++i) - { - wctype_t wt = cset->char_classes[i]; - if (__iswctype (wc, wt)) - { - match_len = char_len; - goto check_node_accept_bytes_match; - } - } - -# ifdef _LIBC - nrules = _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES); - if (nrules != 0) - { - unsigned int in_collseq = 0; - const int32_t *table, *indirect; - const unsigned char *weights, *extra; - const char *collseqwc; - /* This #include defines a local function! */ -# include - - /* match with collating_symbol? */ - if (cset->ncoll_syms) - extra = (const unsigned char *) - _NL_CURRENT (LC_COLLATE, _NL_COLLATE_SYMB_EXTRAMB); - for (i = 0; i < cset->ncoll_syms; ++i) - { - const unsigned char *coll_sym = extra + cset->coll_syms[i]; - /* Compare the length of input collating element and - the length of current collating element. */ - if (*coll_sym != elem_len) - continue; - /* Compare each bytes. */ - for (j = 0; j < *coll_sym; j++) - if (pin[j] != coll_sym[1 + j]) - break; - if (j == *coll_sym) - { - /* Match if every bytes is equal. */ - match_len = j; - goto check_node_accept_bytes_match; - } - } - - if (cset->nranges) - { - if (elem_len <= char_len) - { - collseqwc = _NL_CURRENT (LC_COLLATE, _NL_COLLATE_COLLSEQWC); - in_collseq = __collseq_table_lookup (collseqwc, wc); - } - else - in_collseq = find_collation_sequence_value (pin, elem_len); - } - /* match with range expression? */ - for (i = 0; i < cset->nranges; ++i) - if (cset->range_starts[i] <= in_collseq - && in_collseq <= cset->range_ends[i]) - { - match_len = elem_len; - goto check_node_accept_bytes_match; - } - - /* match with equivalence_class? */ - if (cset->nequiv_classes) - { - const unsigned char *cp = pin; - table = (const int32_t *) - _NL_CURRENT (LC_COLLATE, _NL_COLLATE_TABLEMB); - weights = (const unsigned char *) - _NL_CURRENT (LC_COLLATE, _NL_COLLATE_WEIGHTMB); - extra = (const unsigned char *) - _NL_CURRENT (LC_COLLATE, _NL_COLLATE_EXTRAMB); - indirect = (const int32_t *) - _NL_CURRENT (LC_COLLATE, _NL_COLLATE_INDIRECTMB); - int32_t idx = findidx (&cp); - if (idx > 0) - for (i = 0; i < cset->nequiv_classes; ++i) - { - int32_t equiv_class_idx = cset->equiv_classes[i]; - size_t weight_len = weights[idx & 0xffffff]; - if (weight_len == weights[equiv_class_idx & 0xffffff] - && (idx >> 24) == (equiv_class_idx >> 24)) - { - int cnt = 0; - - idx &= 0xffffff; - equiv_class_idx &= 0xffffff; - - while (cnt <= weight_len - && (weights[equiv_class_idx + 1 + cnt] - == weights[idx + 1 + cnt])) - ++cnt; - if (cnt > weight_len) - { - match_len = elem_len; - goto check_node_accept_bytes_match; - } - } - } - } - } - else -# endif /* _LIBC */ - { - /* match with range expression? */ -#if __GNUC__ >= 2 - wchar_t cmp_buf[] = {L'\0', L'\0', wc, L'\0', L'\0', L'\0'}; -#else - wchar_t cmp_buf[] = {L'\0', L'\0', L'\0', L'\0', L'\0', L'\0'}; - cmp_buf[2] = wc; -#endif - for (i = 0; i < cset->nranges; ++i) - { - cmp_buf[0] = cset->range_starts[i]; - cmp_buf[4] = cset->range_ends[i]; - if (wcscoll (cmp_buf, cmp_buf + 2) <= 0 - && wcscoll (cmp_buf + 2, cmp_buf + 4) <= 0) - { - match_len = char_len; - goto check_node_accept_bytes_match; - } - } - } - check_node_accept_bytes_match: - if (!cset->non_match) - return match_len; - else - { - if (match_len > 0) - return 0; - else - return (elem_len > char_len) ? elem_len : char_len; - } - } - return 0; -} - -# ifdef _LIBC -static unsigned int -internal_function -find_collation_sequence_value (const unsigned char *mbs, size_t mbs_len) -{ - uint32_t nrules = _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES); - if (nrules == 0) - { - if (mbs_len == 1) - { - /* No valid character. Match it as a single byte character. */ - const unsigned char *collseq = (const unsigned char *) - _NL_CURRENT (LC_COLLATE, _NL_COLLATE_COLLSEQMB); - return collseq[mbs[0]]; - } - return UINT_MAX; - } - else - { - int32_t idx; - const unsigned char *extra = (const unsigned char *) - _NL_CURRENT (LC_COLLATE, _NL_COLLATE_SYMB_EXTRAMB); - int32_t extrasize = (const unsigned char *) - _NL_CURRENT (LC_COLLATE, _NL_COLLATE_SYMB_EXTRAMB + 1) - extra; - - for (idx = 0; idx < extrasize;) - { - int mbs_cnt, found = 0; - int32_t elem_mbs_len; - /* Skip the name of collating element name. */ - idx = idx + extra[idx] + 1; - elem_mbs_len = extra[idx++]; - if (mbs_len == elem_mbs_len) - { - for (mbs_cnt = 0; mbs_cnt < elem_mbs_len; ++mbs_cnt) - if (extra[idx + mbs_cnt] != mbs[mbs_cnt]) - break; - if (mbs_cnt == elem_mbs_len) - /* Found the entry. */ - found = 1; - } - /* Skip the byte sequence of the collating element. */ - idx += elem_mbs_len; - /* Adjust for the alignment. */ - idx = (idx + 3) & ~3; - /* Skip the collation sequence value. */ - idx += sizeof (uint32_t); - /* Skip the wide char sequence of the collating element. */ - idx = idx + sizeof (uint32_t) * (extra[idx] + 1); - /* If we found the entry, return the sequence value. */ - if (found) - return *(uint32_t *) (extra + idx); - /* Skip the collation sequence value. */ - idx += sizeof (uint32_t); - } - return UINT_MAX; - } -} -# endif /* _LIBC */ -#endif /* RE_ENABLE_I18N */ - -/* Check whether the node accepts the byte which is IDX-th - byte of the INPUT. */ - -static int -internal_function -check_node_accept (const re_match_context_t *mctx, const re_token_t *node, - int idx) -{ - unsigned char ch; - ch = re_string_byte_at (&mctx->input, idx); - switch (node->type) - { - case CHARACTER: - if (node->opr.c != ch) - return 0; - break; - - case SIMPLE_BRACKET: - if (!bitset_contain (node->opr.sbcset, ch)) - return 0; - break; - -#ifdef RE_ENABLE_I18N - case OP_UTF8_PERIOD: - if (ch >= 0x80) - return 0; - /* FALLTHROUGH */ -#endif - case OP_PERIOD: - if ((ch == '\n' && !(mctx->dfa->syntax & RE_DOT_NEWLINE)) - || (ch == '\0' && (mctx->dfa->syntax & RE_DOT_NOT_NULL))) - return 0; - break; - - default: - return 0; - } - - if (node->constraint) - { - /* The node has constraints. Check whether the current context - satisfies the constraints. */ - unsigned int context = re_string_context_at (&mctx->input, idx, - mctx->eflags); - if (NOT_SATISFY_NEXT_CONSTRAINT (node->constraint, context)) - return 0; - } - - return 1; -} - -/* Extend the buffers, if the buffers have run out. */ - -static reg_errcode_t -internal_function -extend_buffers (re_match_context_t *mctx) -{ - reg_errcode_t ret; - re_string_t *pstr = &mctx->input; - - /* Avoid overflow. */ - if (BE (INT_MAX / 2 / sizeof (re_dfastate_t *) <= (size_t)pstr->bufs_len, 0)) - return REG_ESPACE; - - /* Double the lengthes of the buffers. */ - ret = re_string_realloc_buffers (pstr, pstr->bufs_len * 2); - if (BE (ret != REG_NOERROR, 0)) - return ret; - - if (mctx->state_log != NULL) - { - /* And double the length of state_log. */ - /* XXX We have no indication of the size of this buffer. If this - allocation fail we have no indication that the state_log array - does not have the right size. */ - re_dfastate_t **new_array = re_realloc (mctx->state_log, re_dfastate_t *, - pstr->bufs_len + 1); - if (BE (new_array == NULL, 0)) - return REG_ESPACE; - mctx->state_log = new_array; - } - - /* Then reconstruct the buffers. */ - if (pstr->icase) - { -#ifdef RE_ENABLE_I18N - if (pstr->mb_cur_max > 1) - { - ret = build_wcs_upper_buffer (pstr); - if (BE (ret != REG_NOERROR, 0)) - return ret; - } - else -#endif /* RE_ENABLE_I18N */ - build_upper_buffer (pstr); - } - else - { -#ifdef RE_ENABLE_I18N - if (pstr->mb_cur_max > 1) - build_wcs_buffer (pstr); - else -#endif /* RE_ENABLE_I18N */ - { - if (pstr->trans != NULL) - re_string_translate_buffer (pstr); - } - } - return REG_NOERROR; -} - - -/* Functions for matching context. */ - -/* Initialize MCTX. */ - -static reg_errcode_t -internal_function -match_ctx_init (re_match_context_t *mctx, int eflags, int n) -{ - mctx->eflags = eflags; - mctx->match_last = -1; - if (n > 0) - { - mctx->bkref_ents = re_malloc (struct re_backref_cache_entry, n); - mctx->sub_tops = re_malloc (re_sub_match_top_t *, n); - if (BE (mctx->bkref_ents == NULL || mctx->sub_tops == NULL, 0)) - return REG_ESPACE; - } - /* Already zero-ed by the caller. - else - mctx->bkref_ents = NULL; - mctx->nbkref_ents = 0; - mctx->nsub_tops = 0; */ - mctx->abkref_ents = n; - mctx->max_mb_elem_len = 1; - mctx->asub_tops = n; - return REG_NOERROR; -} - -/* Clean the entries which depend on the current input in MCTX. - This function must be invoked when the matcher changes the start index - of the input, or changes the input string. */ - -static void -internal_function -match_ctx_clean (re_match_context_t *mctx) -{ - int st_idx; - for (st_idx = 0; st_idx < mctx->nsub_tops; ++st_idx) - { - int sl_idx; - re_sub_match_top_t *top = mctx->sub_tops[st_idx]; - for (sl_idx = 0; sl_idx < top->nlasts; ++sl_idx) - { - re_sub_match_last_t *last = top->lasts[sl_idx]; - re_free (last->path.array); - re_free (last); - } - re_free (top->lasts); - if (top->path) - { - re_free (top->path->array); - re_free (top->path); - } - free (top); - } - - mctx->nsub_tops = 0; - mctx->nbkref_ents = 0; -} - -/* Free all the memory associated with MCTX. */ - -static void -internal_function -match_ctx_free (re_match_context_t *mctx) -{ - /* First, free all the memory associated with MCTX->SUB_TOPS. */ - match_ctx_clean (mctx); - re_free (mctx->sub_tops); - re_free (mctx->bkref_ents); -} - -/* Add a new backreference entry to MCTX. - Note that we assume that caller never call this function with duplicate - entry, and call with STR_IDX which isn't smaller than any existing entry. -*/ - -static reg_errcode_t -internal_function -match_ctx_add_entry (re_match_context_t *mctx, int node, int str_idx, int from, - int to) -{ - if (mctx->nbkref_ents >= mctx->abkref_ents) - { - struct re_backref_cache_entry* new_entry; - new_entry = re_realloc (mctx->bkref_ents, struct re_backref_cache_entry, - mctx->abkref_ents * 2); - if (BE (new_entry == NULL, 0)) - { - re_free (mctx->bkref_ents); - return REG_ESPACE; - } - mctx->bkref_ents = new_entry; - memset (mctx->bkref_ents + mctx->nbkref_ents, '\0', - sizeof (struct re_backref_cache_entry) * mctx->abkref_ents); - mctx->abkref_ents *= 2; - } - if (mctx->nbkref_ents > 0 - && mctx->bkref_ents[mctx->nbkref_ents - 1].str_idx == str_idx) - mctx->bkref_ents[mctx->nbkref_ents - 1].more = 1; - - mctx->bkref_ents[mctx->nbkref_ents].node = node; - mctx->bkref_ents[mctx->nbkref_ents].str_idx = str_idx; - mctx->bkref_ents[mctx->nbkref_ents].subexp_from = from; - mctx->bkref_ents[mctx->nbkref_ents].subexp_to = to; - - /* This is a cache that saves negative results of check_dst_limits_calc_pos. - If bit N is clear, means that this entry won't epsilon-transition to - an OP_OPEN_SUBEXP or OP_CLOSE_SUBEXP for the N+1-th subexpression. If - it is set, check_dst_limits_calc_pos_1 will recurse and try to find one - such node. - - A backreference does not epsilon-transition unless it is empty, so set - to all zeros if FROM != TO. */ - mctx->bkref_ents[mctx->nbkref_ents].eps_reachable_subexps_map - = (from == to ? ~0 : 0); - - mctx->bkref_ents[mctx->nbkref_ents++].more = 0; - if (mctx->max_mb_elem_len < to - from) - mctx->max_mb_elem_len = to - from; - return REG_NOERROR; -} - -/* Search for the first entry which has the same str_idx, or -1 if none is - found. Note that MCTX->BKREF_ENTS is already sorted by MCTX->STR_IDX. */ - -static int -internal_function -search_cur_bkref_entry (const re_match_context_t *mctx, int str_idx) -{ - int left, right, mid, last; - last = right = mctx->nbkref_ents; - for (left = 0; left < right;) - { - mid = (left + right) / 2; - if (mctx->bkref_ents[mid].str_idx < str_idx) - left = mid + 1; - else - right = mid; - } - if (left < last && mctx->bkref_ents[left].str_idx == str_idx) - return left; - else - return -1; -} - -/* Register the node NODE, whose type is OP_OPEN_SUBEXP, and which matches - at STR_IDX. */ - -static reg_errcode_t -internal_function -match_ctx_add_subtop (re_match_context_t *mctx, int node, int str_idx) -{ -#ifdef DEBUG - assert (mctx->sub_tops != NULL); - assert (mctx->asub_tops > 0); -#endif - if (BE (mctx->nsub_tops == mctx->asub_tops, 0)) - { - int new_asub_tops = mctx->asub_tops * 2; - re_sub_match_top_t **new_array = re_realloc (mctx->sub_tops, - re_sub_match_top_t *, - new_asub_tops); - if (BE (new_array == NULL, 0)) - return REG_ESPACE; - mctx->sub_tops = new_array; - mctx->asub_tops = new_asub_tops; - } - mctx->sub_tops[mctx->nsub_tops] = calloc (1, sizeof (re_sub_match_top_t)); - if (BE (mctx->sub_tops[mctx->nsub_tops] == NULL, 0)) - return REG_ESPACE; - mctx->sub_tops[mctx->nsub_tops]->node = node; - mctx->sub_tops[mctx->nsub_tops++]->str_idx = str_idx; - return REG_NOERROR; -} - -/* Register the node NODE, whose type is OP_CLOSE_SUBEXP, and which matches - at STR_IDX, whose corresponding OP_OPEN_SUBEXP is SUB_TOP. */ - -static re_sub_match_last_t * -internal_function -match_ctx_add_sublast (re_sub_match_top_t *subtop, int node, int str_idx) -{ - re_sub_match_last_t *new_entry; - if (BE (subtop->nlasts == subtop->alasts, 0)) - { - int new_alasts = 2 * subtop->alasts + 1; - re_sub_match_last_t **new_array = re_realloc (subtop->lasts, - re_sub_match_last_t *, - new_alasts); - if (BE (new_array == NULL, 0)) - return NULL; - subtop->lasts = new_array; - subtop->alasts = new_alasts; - } - new_entry = calloc (1, sizeof (re_sub_match_last_t)); - if (BE (new_entry != NULL, 1)) - { - subtop->lasts[subtop->nlasts] = new_entry; - new_entry->node = node; - new_entry->str_idx = str_idx; - ++subtop->nlasts; - } - return new_entry; -} - -static void -internal_function -sift_ctx_init (re_sift_context_t *sctx, re_dfastate_t **sifted_sts, - re_dfastate_t **limited_sts, int last_node, int last_str_idx) -{ - sctx->sifted_states = sifted_sts; - sctx->limited_states = limited_sts; - sctx->last_node = last_node; - sctx->last_str_idx = last_str_idx; - re_node_set_init_empty (&sctx->limits); -} diff --git a/deps/winhttp/urlmon.h b/deps/winhttp/urlmon.h deleted file mode 100644 index 4143d501e..000000000 --- a/deps/winhttp/urlmon.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (C) the libgit2 contributors. All rights reserved. - * - * This file is part of libgit2, distributed under the GNU GPL v2 with - * a Linking Exception. For full terms see the included COPYING file. - */ - -#if defined(__MINGW_VERSION) || defined(__MINGW32_VERSION) - -#ifndef __CUSTOM_URLMON_H -#define __CUSTOM_URLMON_H - -typedef struct IInternetSecurityManager IInternetSecurityManager; - -typedef struct IInternetSecurityManagerVtbl -{ - HRESULT(STDMETHODCALLTYPE *QueryInterface)(IInternetSecurityManager *, REFIID, void **); - ULONG(STDMETHODCALLTYPE *AddRef)(IInternetSecurityManager *); - ULONG(STDMETHODCALLTYPE *Release)(IInternetSecurityManager *); - LPVOID SetSecuritySite; - LPVOID GetSecuritySite; - HRESULT(STDMETHODCALLTYPE *MapUrlToZone)(IInternetSecurityManager *, LPCWSTR, DWORD *, DWORD); - LPVOID GetSecurityId; - LPVOID ProcessUrlAction; - LPVOID QueryCustomPolicy; - LPVOID SetZoneMapping; - LPVOID GetZoneMappings; -} IInternetSecurityManagerVtbl; - -struct IInternetSecurityManager -{ - CONST_VTBL struct IInternetSecurityManagerVtbl *lpVtbl; -}; - -#define URLZONE_LOCAL_MACHINE 0 -#define URLZONE_INTRANET 1 -#define URLZONE_TRUSTED 2 - -#endif /* __CUSTOM_URLMON_H */ - -#else - -#include_next - -#endif diff --git a/deps/winhttp/winhttp.def b/deps/winhttp/winhttp.def deleted file mode 100644 index eecce59c3..000000000 --- a/deps/winhttp/winhttp.def +++ /dev/null @@ -1,29 +0,0 @@ -LIBRARY WINHTTP -EXPORTS -WinHttpAddRequestHeaders@16 -WinHttpCheckPlatform@0 -WinHttpCloseHandle@4 -WinHttpConnect@16 -WinHttpCrackUrl@16 -WinHttpCreateUrl@16 -WinHttpDetectAutoProxyConfigUrl@8 -WinHttpGetDefaultProxyConfiguration@4 -WinHttpGetIEProxyConfigForCurrentUser@4 -WinHttpGetProxyForUrl@16 -WinHttpOpen@20 -WinHttpOpenRequest@28 -WinHttpQueryAuthSchemes@16 -WinHttpQueryDataAvailable@8 -WinHttpQueryHeaders@24 -WinHttpQueryOption@16 -WinHttpReadData@16 -WinHttpReceiveResponse@8 -WinHttpSendRequest@28 -WinHttpSetCredentials@24 -WinHttpSetDefaultProxyConfiguration@4 -WinHttpSetOption@16 -WinHttpSetStatusCallback@16 -WinHttpSetTimeouts@20 -WinHttpTimeFromSystemTime@8 -WinHttpTimeToSystemTime@8 -WinHttpWriteData@16 diff --git a/deps/winhttp/winhttp.h b/deps/winhttp/winhttp.h deleted file mode 100644 index dd1986a66..000000000 --- a/deps/winhttp/winhttp.h +++ /dev/null @@ -1,592 +0,0 @@ -/* - * Copyright (C) 2007 Francois Gouget - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - */ - -#if defined(__MINGW_VERSION) || defined(__MINGW32_VERSION) - -#ifndef __WINE_WINHTTP_H -#define __WINE_WINHTTP_H - -#ifdef _WIN64 -#include -#else -#include -#endif - -#define WINHTTPAPI -#define BOOLAPI WINHTTPAPI BOOL WINAPI - - -typedef LPVOID HINTERNET; -typedef HINTERNET *LPHINTERNET; - -#define INTERNET_DEFAULT_PORT 0 -#define INTERNET_DEFAULT_HTTP_PORT 80 -#define INTERNET_DEFAULT_HTTPS_PORT 443 -typedef WORD INTERNET_PORT; -typedef INTERNET_PORT *LPINTERNET_PORT; - -#define INTERNET_SCHEME_HTTP 1 -#define INTERNET_SCHEME_HTTPS 2 -typedef int INTERNET_SCHEME, *LPINTERNET_SCHEME; - -#define ICU_ESCAPE 0x80000000 - -/* flags for WinHttpOpen */ -#define WINHTTP_FLAG_ASYNC 0x10000000 - -/* flags for WinHttpOpenRequest */ -#define WINHTTP_FLAG_ESCAPE_PERCENT 0x00000004 -#define WINHTTP_FLAG_NULL_CODEPAGE 0x00000008 -#define WINHTTP_FLAG_ESCAPE_DISABLE 0x00000040 -#define WINHTTP_FLAG_ESCAPE_DISABLE_QUERY 0x00000080 -#define WINHTTP_FLAG_BYPASS_PROXY_CACHE 0x00000100 -#define WINHTTP_FLAG_REFRESH WINHTTP_FLAG_BYPASS_PROXY_CACHE -#define WINHTTP_FLAG_SECURE 0x00800000 - -#define WINHTTP_ACCESS_TYPE_DEFAULT_PROXY 0 -#define WINHTTP_ACCESS_TYPE_NO_PROXY 1 -#define WINHTTP_ACCESS_TYPE_NAMED_PROXY 3 - -#define WINHTTP_NO_PROXY_NAME NULL -#define WINHTTP_NO_PROXY_BYPASS NULL - -#define WINHTTP_NO_REFERER NULL -#define WINHTTP_DEFAULT_ACCEPT_TYPES NULL - -#define WINHTTP_NO_ADDITIONAL_HEADERS NULL -#define WINHTTP_NO_REQUEST_DATA NULL - -#define WINHTTP_HEADER_NAME_BY_INDEX NULL -#define WINHTTP_NO_OUTPUT_BUFFER NULL -#define WINHTTP_NO_HEADER_INDEX NULL - -#define WINHTTP_ADDREQ_INDEX_MASK 0x0000FFFF -#define WINHTTP_ADDREQ_FLAGS_MASK 0xFFFF0000 -#define WINHTTP_ADDREQ_FLAG_ADD_IF_NEW 0x10000000 -#define WINHTTP_ADDREQ_FLAG_ADD 0x20000000 -#define WINHTTP_ADDREQ_FLAG_COALESCE_WITH_COMMA 0x40000000 -#define WINHTTP_ADDREQ_FLAG_COALESCE_WITH_SEMICOLON 0x01000000 -#define WINHTTP_ADDREQ_FLAG_COALESCE WINHTTP_ADDREQ_FLAG_COALESCE_WITH_COMMA -#define WINHTTP_ADDREQ_FLAG_REPLACE 0x80000000 - -#define WINHTTP_IGNORE_REQUEST_TOTAL_LENGTH 0 - -/* flags for WinHttp{Set/Query}Options */ -#define WINHTTP_FIRST_OPTION WINHTTP_OPTION_CALLBACK -#define WINHTTP_OPTION_CALLBACK 1 -#define WINHTTP_OPTION_RESOLVE_TIMEOUT 2 -#define WINHTTP_OPTION_CONNECT_TIMEOUT 3 -#define WINHTTP_OPTION_CONNECT_RETRIES 4 -#define WINHTTP_OPTION_SEND_TIMEOUT 5 -#define WINHTTP_OPTION_RECEIVE_TIMEOUT 6 -#define WINHTTP_OPTION_RECEIVE_RESPONSE_TIMEOUT 7 -#define WINHTTP_OPTION_HANDLE_TYPE 9 -#define WINHTTP_OPTION_READ_BUFFER_SIZE 12 -#define WINHTTP_OPTION_WRITE_BUFFER_SIZE 13 -#define WINHTTP_OPTION_PARENT_HANDLE 21 -#define WINHTTP_OPTION_EXTENDED_ERROR 24 -#define WINHTTP_OPTION_SECURITY_FLAGS 31 -#define WINHTTP_OPTION_SECURITY_CERTIFICATE_STRUCT 32 -#define WINHTTP_OPTION_URL 34 -#define WINHTTP_OPTION_SECURITY_KEY_BITNESS 36 -#define WINHTTP_OPTION_PROXY 38 -#define WINHTTP_OPTION_USER_AGENT 41 -#define WINHTTP_OPTION_CONTEXT_VALUE 45 -#define WINHTTP_OPTION_CLIENT_CERT_CONTEXT 47 -#define WINHTTP_OPTION_REQUEST_PRIORITY 58 -#define WINHTTP_OPTION_HTTP_VERSION 59 -#define WINHTTP_OPTION_DISABLE_FEATURE 63 -#define WINHTTP_OPTION_CODEPAGE 68 -#define WINHTTP_OPTION_MAX_CONNS_PER_SERVER 73 -#define WINHTTP_OPTION_MAX_CONNS_PER_1_0_SERVER 74 -#define WINHTTP_OPTION_AUTOLOGON_POLICY 77 -#define WINHTTP_OPTION_SERVER_CERT_CONTEXT 78 -#define WINHTTP_OPTION_ENABLE_FEATURE 79 -#define WINHTTP_OPTION_WORKER_THREAD_COUNT 80 -#define WINHTTP_OPTION_PASSPORT_COBRANDING_TEXT 81 -#define WINHTTP_OPTION_PASSPORT_COBRANDING_URL 82 -#define WINHTTP_OPTION_CONFIGURE_PASSPORT_AUTH 83 -#define WINHTTP_OPTION_SECURE_PROTOCOLS 84 -#define WINHTTP_OPTION_ENABLETRACING 85 -#define WINHTTP_OPTION_PASSPORT_SIGN_OUT 86 -#define WINHTTP_OPTION_PASSPORT_RETURN_URL 87 -#define WINHTTP_OPTION_REDIRECT_POLICY 88 -#define WINHTTP_OPTION_MAX_HTTP_AUTOMATIC_REDIRECTS 89 -#define WINHTTP_OPTION_MAX_HTTP_STATUS_CONTINUE 90 -#define WINHTTP_OPTION_MAX_RESPONSE_HEADER_SIZE 91 -#define WINHTTP_OPTION_MAX_RESPONSE_DRAIN_SIZE 92 -#define WINHTTP_OPTION_CONNECTION_INFO 93 -#define WINHTTP_OPTION_CLIENT_CERT_ISSUER_LIST 94 -#define WINHTTP_OPTION_SPN 96 -#define WINHTTP_OPTION_GLOBAL_PROXY_CREDS 97 -#define WINHTTP_OPTION_GLOBAL_SERVER_CREDS 98 -#define WINHTTP_OPTION_UNLOAD_NOTIFY_EVENT 99 -#define WINHTTP_OPTION_REJECT_USERPWD_IN_URL 100 -#define WINHTTP_OPTION_USE_GLOBAL_SERVER_CREDENTIALS 101 -#define WINHTTP_LAST_OPTION WINHTTP_OPTION_USE_GLOBAL_SERVER_CREDENTIALS -#define WINHTTP_OPTION_USERNAME 0x1000 -#define WINHTTP_OPTION_PASSWORD 0x1001 -#define WINHTTP_OPTION_PROXY_USERNAME 0x1002 -#define WINHTTP_OPTION_PROXY_PASSWORD 0x1003 - -#define WINHTTP_CONNS_PER_SERVER_UNLIMITED 0xFFFFFFFF - -#define WINHTTP_AUTOLOGON_SECURITY_LEVEL_MEDIUM 0 -#define WINHTTP_AUTOLOGON_SECURITY_LEVEL_LOW 1 -#define WINHTTP_AUTOLOGON_SECURITY_LEVEL_HIGH 2 -#define WINHTTP_AUTOLOGON_SECURITY_LEVEL_DEFAULT WINHTTP_AUTOLOGON_SECURITY_LEVEL_MEDIUM - -#define WINHTTP_OPTION_REDIRECT_POLICY_NEVER 0 -#define WINHTTP_OPTION_REDIRECT_POLICY_DISALLOW_HTTPS_TO_HTTP 1 -#define WINHTTP_OPTION_REDIRECT_POLICY_ALWAYS 2 -#define WINHTTP_OPTION_REDIRECT_POLICY_LAST WINHTTP_OPTION_REDIRECT_POLICY_ALWAYS -#define WINHTTP_OPTION_REDIRECT_POLICY_DEFAULT WINHTTP_OPTION_REDIRECT_POLICY_DISALLOW_HTTPS_TO_HTTP - -#define WINHTTP_DISABLE_PASSPORT_AUTH 0x00000000 -#define WINHTTP_ENABLE_PASSPORT_AUTH 0x10000000 -#define WINHTTP_DISABLE_PASSPORT_KEYRING 0x20000000 -#define WINHTTP_ENABLE_PASSPORT_KEYRING 0x40000000 - -#define WINHTTP_DISABLE_COOKIES 0x00000001 -#define WINHTTP_DISABLE_REDIRECTS 0x00000002 -#define WINHTTP_DISABLE_AUTHENTICATION 0x00000004 -#define WINHTTP_DISABLE_KEEP_ALIVE 0x00000008 -#define WINHTTP_ENABLE_SSL_REVOCATION 0x00000001 -#define WINHTTP_ENABLE_SSL_REVERT_IMPERSONATION 0x00000002 -#define WINHTTP_DISABLE_SPN_SERVER_PORT 0x00000000 -#define WINHTTP_ENABLE_SPN_SERVER_PORT 0x00000001 -#define WINHTTP_OPTION_SPN_MASK WINHTTP_ENABLE_SPN_SERVER_PORT - -/* Options for WinHttpOpenRequest */ -#define WINHTTP_NO_REFERER NULL -#define WINHTTP_DEFAULT_ACCEPT_TYPES NULL - -/* Options for WinHttpSendRequest */ -#define WINHTTP_NO_ADDITIONAL_HEADERS NULL -#define WINHTTP_NO_REQUEST_DATA NULL - -/* WinHTTP error codes */ -#define WINHTTP_ERROR_BASE 12000 -#define ERROR_WINHTTP_OUT_OF_HANDLES (WINHTTP_ERROR_BASE + 1) -#define ERROR_WINHTTP_TIMEOUT (WINHTTP_ERROR_BASE + 2) -#define ERROR_WINHTTP_INTERNAL_ERROR (WINHTTP_ERROR_BASE + 4) -#define ERROR_WINHTTP_INVALID_URL (WINHTTP_ERROR_BASE + 5) -#define ERROR_WINHTTP_UNRECOGNIZED_SCHEME (WINHTTP_ERROR_BASE + 6) -#define ERROR_WINHTTP_NAME_NOT_RESOLVED (WINHTTP_ERROR_BASE + 7) -#define ERROR_WINHTTP_INVALID_OPTION (WINHTTP_ERROR_BASE + 9) -#define ERROR_WINHTTP_OPTION_NOT_SETTABLE (WINHTTP_ERROR_BASE + 11) -#define ERROR_WINHTTP_SHUTDOWN (WINHTTP_ERROR_BASE + 12) -#define ERROR_WINHTTP_LOGIN_FAILURE (WINHTTP_ERROR_BASE + 15) -#define ERROR_WINHTTP_OPERATION_CANCELLED (WINHTTP_ERROR_BASE + 17) -#define ERROR_WINHTTP_INCORRECT_HANDLE_TYPE (WINHTTP_ERROR_BASE + 18) -#define ERROR_WINHTTP_INCORRECT_HANDLE_STATE (WINHTTP_ERROR_BASE + 19) -#define ERROR_WINHTTP_CANNOT_CONNECT (WINHTTP_ERROR_BASE + 29) -#define ERROR_WINHTTP_CONNECTION_ERROR (WINHTTP_ERROR_BASE + 30) -#define ERROR_WINHTTP_RESEND_REQUEST (WINHTTP_ERROR_BASE + 32) -#define ERROR_WINHTTP_SECURE_CERT_DATE_INVALID (WINHTTP_ERROR_BASE + 37) -#define ERROR_WINHTTP_SECURE_CERT_CN_INVALID (WINHTTP_ERROR_BASE + 38) -#define ERROR_WINHTTP_CLIENT_AUTH_CERT_NEEDED (WINHTTP_ERROR_BASE + 44) -#define ERROR_WINHTTP_SECURE_INVALID_CA (WINHTTP_ERROR_BASE + 45) -#define ERROR_WINHTTP_SECURE_CERT_REV_FAILED (WINHTTP_ERROR_BASE + 57) -#define ERROR_WINHTTP_CANNOT_CALL_BEFORE_OPEN (WINHTTP_ERROR_BASE + 100) -#define ERROR_WINHTTP_CANNOT_CALL_BEFORE_SEND (WINHTTP_ERROR_BASE + 101) -#define ERROR_WINHTTP_CANNOT_CALL_AFTER_SEND (WINHTTP_ERROR_BASE + 102) -#define ERROR_WINHTTP_CANNOT_CALL_AFTER_OPEN (WINHTTP_ERROR_BASE + 103) -#define ERROR_WINHTTP_HEADER_NOT_FOUND (WINHTTP_ERROR_BASE + 150) -#define ERROR_WINHTTP_INVALID_SERVER_RESPONSE (WINHTTP_ERROR_BASE + 152) -#define ERROR_WINHTTP_INVALID_HEADER (WINHTTP_ERROR_BASE + 153) -#define ERROR_WINHTTP_INVALID_QUERY_REQUEST (WINHTTP_ERROR_BASE + 154) -#define ERROR_WINHTTP_HEADER_ALREADY_EXISTS (WINHTTP_ERROR_BASE + 155) -#define ERROR_WINHTTP_REDIRECT_FAILED (WINHTTP_ERROR_BASE + 156) -#define ERROR_WINHTTP_SECURE_CHANNEL_ERROR (WINHTTP_ERROR_BASE + 157) -#define ERROR_WINHTTP_BAD_AUTO_PROXY_SCRIPT (WINHTTP_ERROR_BASE + 166) -#define ERROR_WINHTTP_UNABLE_TO_DOWNLOAD_SCRIPT (WINHTTP_ERROR_BASE + 167) -#define ERROR_WINHTTP_SECURE_INVALID_CERT (WINHTTP_ERROR_BASE + 169) -#define ERROR_WINHTTP_SECURE_CERT_REVOKED (WINHTTP_ERROR_BASE + 170) -#define ERROR_WINHTTP_NOT_INITIALIZED (WINHTTP_ERROR_BASE + 172) -#define ERROR_WINHTTP_SECURE_FAILURE (WINHTTP_ERROR_BASE + 175) -#define ERROR_WINHTTP_AUTO_PROXY_SERVICE_ERROR (WINHTTP_ERROR_BASE + 178) -#define ERROR_WINHTTP_SECURE_CERT_WRONG_USAGE (WINHTTP_ERROR_BASE + 179) -#define ERROR_WINHTTP_AUTODETECTION_FAILED (WINHTTP_ERROR_BASE + 180) -#define ERROR_WINHTTP_HEADER_COUNT_EXCEEDED (WINHTTP_ERROR_BASE + 181) -#define ERROR_WINHTTP_HEADER_SIZE_OVERFLOW (WINHTTP_ERROR_BASE + 182) -#define ERROR_WINHTTP_CHUNKED_ENCODING_HEADER_SIZE_OVERFLOW (WINHTTP_ERROR_BASE + 183) -#define ERROR_WINHTTP_RESPONSE_DRAIN_OVERFLOW (WINHTTP_ERROR_BASE + 184) -#define ERROR_WINHTTP_CLIENT_CERT_NO_PRIVATE_KEY (WINHTTP_ERROR_BASE + 185) -#define ERROR_WINHTTP_CLIENT_CERT_NO_ACCESS_PRIVATE_KEY (WINHTTP_ERROR_BASE + 186) -#define WINHTTP_ERROR_LAST (WINHTTP_ERROR_BASE + 186) - -/* WinHttp status codes */ -#define HTTP_STATUS_CONTINUE 100 -#define HTTP_STATUS_SWITCH_PROTOCOLS 101 -#define HTTP_STATUS_OK 200 -#define HTTP_STATUS_CREATED 201 -#define HTTP_STATUS_ACCEPTED 202 -#define HTTP_STATUS_PARTIAL 203 -#define HTTP_STATUS_NO_CONTENT 204 -#define HTTP_STATUS_RESET_CONTENT 205 -#define HTTP_STATUS_PARTIAL_CONTENT 206 -#define HTTP_STATUS_WEBDAV_MULTI_STATUS 207 -#define HTTP_STATUS_AMBIGUOUS 300 -#define HTTP_STATUS_MOVED 301 -#define HTTP_STATUS_REDIRECT 302 -#define HTTP_STATUS_REDIRECT_METHOD 303 -#define HTTP_STATUS_NOT_MODIFIED 304 -#define HTTP_STATUS_USE_PROXY 305 -#define HTTP_STATUS_REDIRECT_KEEP_VERB 307 -#define HTTP_STATUS_BAD_REQUEST 400 -#define HTTP_STATUS_DENIED 401 -#define HTTP_STATUS_PAYMENT_REQ 402 -#define HTTP_STATUS_FORBIDDEN 403 -#define HTTP_STATUS_NOT_FOUND 404 -#define HTTP_STATUS_BAD_METHOD 405 -#define HTTP_STATUS_NONE_ACCEPTABLE 406 -#define HTTP_STATUS_PROXY_AUTH_REQ 407 -#define HTTP_STATUS_REQUEST_TIMEOUT 408 -#define HTTP_STATUS_CONFLICT 409 -#define HTTP_STATUS_GONE 410 -#define HTTP_STATUS_LENGTH_REQUIRED 411 -#define HTTP_STATUS_PRECOND_FAILED 412 -#define HTTP_STATUS_REQUEST_TOO_LARGE 413 -#define HTTP_STATUS_URI_TOO_LONG 414 -#define HTTP_STATUS_UNSUPPORTED_MEDIA 415 -#define HTTP_STATUS_RETRY_WITH 449 -#define HTTP_STATUS_SERVER_ERROR 500 -#define HTTP_STATUS_NOT_SUPPORTED 501 -#define HTTP_STATUS_BAD_GATEWAY 502 -#define HTTP_STATUS_SERVICE_UNAVAIL 503 -#define HTTP_STATUS_GATEWAY_TIMEOUT 504 -#define HTTP_STATUS_VERSION_NOT_SUP 505 -#define HTTP_STATUS_FIRST HTTP_STATUS_CONTINUE -#define HTTP_STATUS_LAST HTTP_STATUS_VERSION_NOT_SUP - -#define SECURITY_FLAG_IGNORE_UNKNOWN_CA 0x00000100 -#define SECURITY_FLAG_IGNORE_CERT_DATE_INVALID 0x00002000 -#define SECURITY_FLAG_IGNORE_CERT_CN_INVALID 0x00001000 -#define SECURITY_FLAG_IGNORE_CERT_WRONG_USAGE 0x00000200 -#define SECURITY_FLAG_SECURE 0x00000001 -#define SECURITY_FLAG_STRENGTH_WEAK 0x10000000 -#define SECURITY_FLAG_STRENGTH_MEDIUM 0x40000000 -#define SECURITY_FLAG_STRENGTH_STRONG 0x20000000 - -#define ICU_NO_ENCODE 0x20000000 -#define ICU_DECODE 0x10000000 -#define ICU_NO_META 0x08000000 -#define ICU_ENCODE_SPACES_ONLY 0x04000000 -#define ICU_BROWSER_MODE 0x02000000 -#define ICU_ENCODE_PERCENT 0x00001000 - -/* Query flags */ -#define WINHTTP_QUERY_MIME_VERSION 0 -#define WINHTTP_QUERY_CONTENT_TYPE 1 -#define WINHTTP_QUERY_CONTENT_TRANSFER_ENCODING 2 -#define WINHTTP_QUERY_CONTENT_ID 3 -#define WINHTTP_QUERY_CONTENT_DESCRIPTION 4 -#define WINHTTP_QUERY_CONTENT_LENGTH 5 -#define WINHTTP_QUERY_CONTENT_LANGUAGE 6 -#define WINHTTP_QUERY_ALLOW 7 -#define WINHTTP_QUERY_PUBLIC 8 -#define WINHTTP_QUERY_DATE 9 -#define WINHTTP_QUERY_EXPIRES 10 -#define WINHTTP_QUERY_LAST_MODIFIED 11 -#define WINHTTP_QUERY_MESSAGE_ID 12 -#define WINHTTP_QUERY_URI 13 -#define WINHTTP_QUERY_DERIVED_FROM 14 -#define WINHTTP_QUERY_COST 15 -#define WINHTTP_QUERY_LINK 16 -#define WINHTTP_QUERY_PRAGMA 17 -#define WINHTTP_QUERY_VERSION 18 -#define WINHTTP_QUERY_STATUS_CODE 19 -#define WINHTTP_QUERY_STATUS_TEXT 20 -#define WINHTTP_QUERY_RAW_HEADERS 21 -#define WINHTTP_QUERY_RAW_HEADERS_CRLF 22 -#define WINHTTP_QUERY_CONNECTION 23 -#define WINHTTP_QUERY_ACCEPT 24 -#define WINHTTP_QUERY_ACCEPT_CHARSET 25 -#define WINHTTP_QUERY_ACCEPT_ENCODING 26 -#define WINHTTP_QUERY_ACCEPT_LANGUAGE 27 -#define WINHTTP_QUERY_AUTHORIZATION 28 -#define WINHTTP_QUERY_CONTENT_ENCODING 29 -#define WINHTTP_QUERY_FORWARDED 30 -#define WINHTTP_QUERY_FROM 31 -#define WINHTTP_QUERY_IF_MODIFIED_SINCE 32 -#define WINHTTP_QUERY_LOCATION 33 -#define WINHTTP_QUERY_ORIG_URI 34 -#define WINHTTP_QUERY_REFERER 35 -#define WINHTTP_QUERY_RETRY_AFTER 36 -#define WINHTTP_QUERY_SERVER 37 -#define WINHTTP_QUERY_TITLE 38 -#define WINHTTP_QUERY_USER_AGENT 39 -#define WINHTTP_QUERY_WWW_AUTHENTICATE 40 -#define WINHTTP_QUERY_PROXY_AUTHENTICATE 41 -#define WINHTTP_QUERY_ACCEPT_RANGES 42 -#define WINHTTP_QUERY_SET_COOKIE 43 -#define WINHTTP_QUERY_COOKIE 44 -#define WINHTTP_QUERY_REQUEST_METHOD 45 -#define WINHTTP_QUERY_REFRESH 46 -#define WINHTTP_QUERY_CONTENT_DISPOSITION 47 -#define WINHTTP_QUERY_AGE 48 -#define WINHTTP_QUERY_CACHE_CONTROL 49 -#define WINHTTP_QUERY_CONTENT_BASE 50 -#define WINHTTP_QUERY_CONTENT_LOCATION 51 -#define WINHTTP_QUERY_CONTENT_MD5 52 -#define WINHTTP_QUERY_CONTENT_RANGE 53 -#define WINHTTP_QUERY_ETAG 54 -#define WINHTTP_QUERY_HOST 55 -#define WINHTTP_QUERY_IF_MATCH 56 -#define WINHTTP_QUERY_IF_NONE_MATCH 57 -#define WINHTTP_QUERY_IF_RANGE 58 -#define WINHTTP_QUERY_IF_UNMODIFIED_SINCE 59 -#define WINHTTP_QUERY_MAX_FORWARDS 60 -#define WINHTTP_QUERY_PROXY_AUTHORIZATION 61 -#define WINHTTP_QUERY_RANGE 62 -#define WINHTTP_QUERY_TRANSFER_ENCODING 63 -#define WINHTTP_QUERY_UPGRADE 64 -#define WINHTTP_QUERY_VARY 65 -#define WINHTTP_QUERY_VIA 66 -#define WINHTTP_QUERY_WARNING 67 -#define WINHTTP_QUERY_EXPECT 68 -#define WINHTTP_QUERY_PROXY_CONNECTION 69 -#define WINHTTP_QUERY_UNLESS_MODIFIED_SINCE 70 -#define WINHTTP_QUERY_PROXY_SUPPORT 75 -#define WINHTTP_QUERY_AUTHENTICATION_INFO 76 -#define WINHTTP_QUERY_PASSPORT_URLS 77 -#define WINHTTP_QUERY_PASSPORT_CONFIG 78 -#define WINHTTP_QUERY_MAX 78 -#define WINHTTP_QUERY_CUSTOM 65535 -#define WINHTTP_QUERY_FLAG_REQUEST_HEADERS 0x80000000 -#define WINHTTP_QUERY_FLAG_SYSTEMTIME 0x40000000 -#define WINHTTP_QUERY_FLAG_NUMBER 0x20000000 - -/* Callback options */ -#define WINHTTP_CALLBACK_STATUS_RESOLVING_NAME 0x00000001 -#define WINHTTP_CALLBACK_STATUS_NAME_RESOLVED 0x00000002 -#define WINHTTP_CALLBACK_STATUS_CONNECTING_TO_SERVER 0x00000004 -#define WINHTTP_CALLBACK_STATUS_CONNECTED_TO_SERVER 0x00000008 -#define WINHTTP_CALLBACK_STATUS_SENDING_REQUEST 0x00000010 -#define WINHTTP_CALLBACK_STATUS_REQUEST_SENT 0x00000020 -#define WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE 0x00000040 -#define WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED 0x00000080 -#define WINHTTP_CALLBACK_STATUS_CLOSING_CONNECTION 0x00000100 -#define WINHTTP_CALLBACK_STATUS_CONNECTION_CLOSED 0x00000200 -#define WINHTTP_CALLBACK_STATUS_HANDLE_CREATED 0x00000400 -#define WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING 0x00000800 -#define WINHTTP_CALLBACK_STATUS_DETECTING_PROXY 0x00001000 -#define WINHTTP_CALLBACK_STATUS_REDIRECT 0x00004000 -#define WINHTTP_CALLBACK_STATUS_INTERMEDIATE_RESPONSE 0x00008000 -#define WINHTTP_CALLBACK_STATUS_SECURE_FAILURE 0x00010000 -#define WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE 0x00020000 -#define WINHTTP_CALLBACK_STATUS_DATA_AVAILABLE 0x00040000 -#define WINHTTP_CALLBACK_STATUS_READ_COMPLETE 0x00080000 -#define WINHTTP_CALLBACK_STATUS_WRITE_COMPLETE 0x00100000 -#define WINHTTP_CALLBACK_STATUS_REQUEST_ERROR 0x00200000 -#define WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE 0x00400000 -#define WINHTTP_CALLBACK_FLAG_RESOLVE_NAME (WINHTTP_CALLBACK_STATUS_RESOLVING_NAME | WINHTTP_CALLBACK_STATUS_NAME_RESOLVED) -#define WINHTTP_CALLBACK_FLAG_CONNECT_TO_SERVER (WINHTTP_CALLBACK_STATUS_CONNECTING_TO_SERVER | WINHTTP_CALLBACK_STATUS_CONNECTED_TO_SERVER) -#define WINHTTP_CALLBACK_FLAG_SEND_REQUEST (WINHTTP_CALLBACK_STATUS_SENDING_REQUEST | WINHTTP_CALLBACK_STATUS_REQUEST_SENT) -#define WINHTTP_CALLBACK_FLAG_RECEIVE_RESPONSE (WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE | WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED) -#define WINHTTP_CALLBACK_FLAG_CLOSE_CONNECTION (WINHTTP_CALLBACK_STATUS_CLOSING_CONNECTION | WINHTTP_CALLBACK_STATUS_CONNECTION_CLOSED) -#define WINHTTP_CALLBACK_FLAG_HANDLES (WINHTTP_CALLBACK_STATUS_HANDLE_CREATED | WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING) -#define WINHTTP_CALLBACK_FLAG_DETECTING_PROXY WINHTTP_CALLBACK_STATUS_DETECTING_PROXY -#define WINHTTP_CALLBACK_FLAG_REDIRECT WINHTTP_CALLBACK_STATUS_REDIRECT -#define WINHTTP_CALLBACK_FLAG_INTERMEDIATE_RESPONSE WINHTTP_CALLBACK_STATUS_INTERMEDIATE_RESPONSE -#define WINHTTP_CALLBACK_FLAG_SECURE_FAILURE WINHTTP_CALLBACK_STATUS_SECURE_FAILURE -#define WINHTTP_CALLBACK_FLAG_SENDREQUEST_COMPLETE WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE -#define WINHTTP_CALLBACK_FLAG_HEADERS_AVAILABLE WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE -#define WINHTTP_CALLBACK_FLAG_DATA_AVAILABLE WINHTTP_CALLBACK_STATUS_DATA_AVAILABLE -#define WINHTTP_CALLBACK_FLAG_READ_COMPLETE WINHTTP_CALLBACK_STATUS_READ_COMPLETE -#define WINHTTP_CALLBACK_FLAG_WRITE_COMPLETE WINHTTP_CALLBACK_STATUS_WRITE_COMPLETE -#define WINHTTP_CALLBACK_FLAG_REQUEST_ERROR WINHTTP_CALLBACK_STATUS_REQUEST_ERROR -#define WINHTTP_CALLBACK_FLAG_ALL_COMPLETIONS (WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE | WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE \ - | WINHTTP_CALLBACK_STATUS_DATA_AVAILABLE | WINHTTP_CALLBACK_STATUS_READ_COMPLETE \ - | WINHTTP_CALLBACK_STATUS_WRITE_COMPLETE | WINHTTP_CALLBACK_STATUS_REQUEST_ERROR) -#define WINHTTP_CALLBACK_FLAG_ALL_NOTIFICATIONS 0xffffffff -#define WINHTTP_INVALID_STATUS_CALLBACK ((WINHTTP_STATUS_CALLBACK)(-1)) - -#define API_RECEIVE_RESPONSE (1) -#define API_QUERY_DATA_AVAILABLE (2) -#define API_READ_DATA (3) -#define API_WRITE_DATA (4) -#define API_SEND_REQUEST (5) - -#define WINHTTP_HANDLE_TYPE_SESSION 1 -#define WINHTTP_HANDLE_TYPE_CONNECT 2 -#define WINHTTP_HANDLE_TYPE_REQUEST 3 - -#define WINHTTP_CALLBACK_STATUS_FLAG_CERT_REV_FAILED 0x00000001 -#define WINHTTP_CALLBACK_STATUS_FLAG_INVALID_CERT 0x00000002 -#define WINHTTP_CALLBACK_STATUS_FLAG_CERT_REVOKED 0x00000004 -#define WINHTTP_CALLBACK_STATUS_FLAG_INVALID_CA 0x00000008 -#define WINHTTP_CALLBACK_STATUS_FLAG_CERT_CN_INVALID 0x00000010 -#define WINHTTP_CALLBACK_STATUS_FLAG_CERT_DATE_INVALID 0x00000020 -#define WINHTTP_CALLBACK_STATUS_FLAG_CERT_WRONG_USAGE 0x00000040 -#define WINHTTP_CALLBACK_STATUS_FLAG_SECURITY_CHANNEL_ERROR 0x80000000 - -#define WINHTTP_FLAG_SECURE_PROTOCOL_SSL2 0x00000008 -#define WINHTTP_FLAG_SECURE_PROTOCOL_SSL3 0x00000020 -#define WINHTTP_FLAG_SECURE_PROTOCOL_TLS1 0x00000080 -#define WINHTTP_FLAG_SECURE_PROTOCOL_ALL (WINHTTP_FLAG_SECURE_PROTOCOL_SSL2 | WINHTTP_FLAG_SECURE_PROTOCOL_SSL3 | WINHTTP_FLAG_SECURE_PROTOCOL_TLS1) - -#define WINHTTP_AUTH_SCHEME_BASIC 0x00000001 -#define WINHTTP_AUTH_SCHEME_NTLM 0x00000002 -#define WINHTTP_AUTH_SCHEME_PASSPORT 0x00000004 -#define WINHTTP_AUTH_SCHEME_DIGEST 0x00000008 -#define WINHTTP_AUTH_SCHEME_NEGOTIATE 0x00000010 - -#define WINHTTP_AUTH_TARGET_SERVER 0x00000000 -#define WINHTTP_AUTH_TARGET_PROXY 0x00000001 - -#define WINHTTP_TIME_FORMAT_BUFSIZE 62 - -typedef struct -{ - DWORD dwStructSize; - LPWSTR lpszScheme; - DWORD dwSchemeLength; - INTERNET_SCHEME nScheme; - LPWSTR lpszHostName; - DWORD dwHostNameLength; - INTERNET_PORT nPort; - LPWSTR lpszUserName; - DWORD dwUserNameLength; - LPWSTR lpszPassword; - DWORD dwPasswordLength; - LPWSTR lpszUrlPath; - DWORD dwUrlPathLength; - LPWSTR lpszExtraInfo; - DWORD dwExtraInfoLength; -} URL_COMPONENTS, *LPURL_COMPONENTS; -typedef URL_COMPONENTS URL_COMPONENTSW; -typedef LPURL_COMPONENTS LPURL_COMPONENTSW; - -typedef struct -{ - DWORD_PTR dwResult; - DWORD dwError; -} WINHTTP_ASYNC_RESULT, *LPWINHTTP_ASYNC_RESULT; - -typedef struct -{ - FILETIME ftExpiry; - FILETIME ftStart; - LPWSTR lpszSubjectInfo; - LPWSTR lpszIssuerInfo; - LPWSTR lpszProtocolName; - LPWSTR lpszSignatureAlgName; - LPWSTR lpszEncryptionAlgName; - DWORD dwKeySize; -} WINHTTP_CERTIFICATE_INFO; - -typedef struct -{ - DWORD dwAccessType; - LPWSTR lpszProxy; - LPWSTR lpszProxyBypass; -} WINHTTP_PROXY_INFO, *LPWINHTTP_PROXY_INFO; -typedef WINHTTP_PROXY_INFO WINHTTP_PROXY_INFOW; -typedef LPWINHTTP_PROXY_INFO LPWINHTTP_PROXY_INFOW; - -typedef struct -{ - BOOL fAutoDetect; - LPWSTR lpszAutoConfigUrl; - LPWSTR lpszProxy; - LPWSTR lpszProxyBypass; -} WINHTTP_CURRENT_USER_IE_PROXY_CONFIG; - -typedef VOID (CALLBACK *WINHTTP_STATUS_CALLBACK)(HINTERNET,DWORD_PTR,DWORD,LPVOID,DWORD); - -#define WINHTTP_AUTO_DETECT_TYPE_DHCP 0x00000001 -#define WINHTTP_AUTO_DETECT_TYPE_DNS_A 0x00000002 - -#define WINHTTP_AUTOPROXY_AUTO_DETECT 0x00000001 -#define WINHTTP_AUTOPROXY_CONFIG_URL 0x00000002 -#define WINHTTP_AUTOPROXY_RUN_INPROCESS 0x00010000 -#define WINHTTP_AUTOPROXY_RUN_OUTPROCESS_ONLY 0x00020000 - -typedef struct -{ - DWORD dwFlags; - DWORD dwAutoDetectFlags; - LPCWSTR lpszAutoConfigUrl; - LPVOID lpvReserved; - DWORD dwReserved; - BOOL fAutoLogonIfChallenged; -} WINHTTP_AUTOPROXY_OPTIONS; - -typedef struct -{ - DWORD dwMajorVersion; - DWORD dwMinorVersion; -} HTTP_VERSION_INFO, *LPHTTP_VERSION_INFO; - -#ifdef _WS2DEF_ -typedef struct -{ - DWORD cbSize; - SOCKADDR_STORAGE LocalAddress; - SOCKADDR_STORAGE RemoteAddress; -} WINHTTP_CONNECTION_INFO; -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -BOOL WINAPI WinHttpAddRequestHeaders(HINTERNET,LPCWSTR,DWORD,DWORD); -BOOL WINAPI WinHttpDetectAutoProxyConfigUrl(DWORD,LPWSTR*); -BOOL WINAPI WinHttpCheckPlatform(void); -BOOL WINAPI WinHttpCloseHandle(HINTERNET); -HINTERNET WINAPI WinHttpConnect(HINTERNET,LPCWSTR,INTERNET_PORT,DWORD); -BOOL WINAPI WinHttpCrackUrl(LPCWSTR,DWORD,DWORD,LPURL_COMPONENTS); -BOOL WINAPI WinHttpCreateUrl(LPURL_COMPONENTS,DWORD,LPWSTR,LPDWORD); -BOOL WINAPI WinHttpGetDefaultProxyConfiguration(WINHTTP_PROXY_INFO*); -BOOL WINAPI WinHttpGetIEProxyConfigForCurrentUser(WINHTTP_CURRENT_USER_IE_PROXY_CONFIG*); -BOOL WINAPI WinHttpGetProxyForUrl(HINTERNET,LPCWSTR,WINHTTP_AUTOPROXY_OPTIONS*,WINHTTP_PROXY_INFO*); -HINTERNET WINAPI WinHttpOpen(LPCWSTR,DWORD,LPCWSTR,LPCWSTR,DWORD); -HINTERNET WINAPI WinHttpOpenRequest(HINTERNET,LPCWSTR,LPCWSTR,LPCWSTR,LPCWSTR,LPCWSTR*,DWORD); -BOOL WINAPI WinHttpQueryAuthParams(HINTERNET,DWORD,LPVOID*); -BOOL WINAPI WinHttpQueryAuthSchemes(HINTERNET,LPDWORD,LPDWORD,LPDWORD); -BOOL WINAPI WinHttpQueryDataAvailable(HINTERNET,LPDWORD); -BOOL WINAPI WinHttpQueryHeaders(HINTERNET,DWORD,LPCWSTR,LPVOID,LPDWORD,LPDWORD); -BOOL WINAPI WinHttpQueryOption(HINTERNET,DWORD,LPVOID,LPDWORD); -BOOL WINAPI WinHttpReadData(HINTERNET,LPVOID,DWORD,LPDWORD); -BOOL WINAPI WinHttpReceiveResponse(HINTERNET,LPVOID); -BOOL WINAPI WinHttpSendRequest(HINTERNET,LPCWSTR,DWORD,LPVOID,DWORD,DWORD,DWORD_PTR); -BOOL WINAPI WinHttpSetDefaultProxyConfiguration(WINHTTP_PROXY_INFO*); -BOOL WINAPI WinHttpSetCredentials(HINTERNET,DWORD,DWORD,LPCWSTR,LPCWSTR,LPVOID); -BOOL WINAPI WinHttpSetOption(HINTERNET,DWORD,LPVOID,DWORD); -WINHTTP_STATUS_CALLBACK WINAPI WinHttpSetStatusCallback(HINTERNET,WINHTTP_STATUS_CALLBACK,DWORD,DWORD_PTR); -BOOL WINAPI WinHttpSetTimeouts(HINTERNET,int,int,int,int); -BOOL WINAPI WinHttpTimeFromSystemTime(const SYSTEMTIME *,LPWSTR); -BOOL WINAPI WinHttpTimeToSystemTime(LPCWSTR,SYSTEMTIME*); -BOOL WINAPI WinHttpWriteData(HINTERNET,LPCVOID,DWORD,LPDWORD); - -#ifdef __cplusplus -} -#endif - -#include - -#endif /* __WINE_WINHTTP_H */ - -#else - -#include_next - -#endif diff --git a/deps/winhttp/winhttp64.def b/deps/winhttp/winhttp64.def deleted file mode 100644 index bfad3a0ce..000000000 --- a/deps/winhttp/winhttp64.def +++ /dev/null @@ -1,29 +0,0 @@ -LIBRARY WINHTTP -EXPORTS -WinHttpAddRequestHeaders -WinHttpCheckPlatform -WinHttpCloseHandle -WinHttpConnect -WinHttpCrackUrl -WinHttpCreateUrl -WinHttpDetectAutoProxyConfigUrl -WinHttpGetDefaultProxyConfiguration -WinHttpGetIEProxyConfigForCurrentUser -WinHttpGetProxyForUrl -WinHttpOpen -WinHttpOpenRequest -WinHttpQueryAuthSchemes -WinHttpQueryDataAvailable -WinHttpQueryHeaders -WinHttpQueryOption -WinHttpReadData -WinHttpReceiveResponse -WinHttpSendRequest -WinHttpSetCredentials -WinHttpSetDefaultProxyConfiguration -WinHttpSetOption -WinHttpSetStatusCallback -WinHttpSetTimeouts -WinHttpTimeFromSystemTime -WinHttpTimeToSystemTime -WinHttpWriteData diff --git a/deps/zlib/adler32.c b/deps/zlib/adler32.c deleted file mode 100644 index a868f073d..000000000 --- a/deps/zlib/adler32.c +++ /dev/null @@ -1,179 +0,0 @@ -/* adler32.c -- compute the Adler-32 checksum of a data stream - * Copyright (C) 1995-2011 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* @(#) $Id$ */ - -#include "zutil.h" - -#define local static - -local uLong adler32_combine_ OF((uLong adler1, uLong adler2, z_off64_t len2)); - -#define BASE 65521 /* largest prime smaller than 65536 */ -#define NMAX 5552 -/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */ - -#define DO1(buf,i) {adler += (buf)[i]; sum2 += adler;} -#define DO2(buf,i) DO1(buf,i); DO1(buf,i+1); -#define DO4(buf,i) DO2(buf,i); DO2(buf,i+2); -#define DO8(buf,i) DO4(buf,i); DO4(buf,i+4); -#define DO16(buf) DO8(buf,0); DO8(buf,8); - -/* use NO_DIVIDE if your processor does not do division in hardware -- - try it both ways to see which is faster */ -#ifdef NO_DIVIDE -/* note that this assumes BASE is 65521, where 65536 % 65521 == 15 - (thank you to John Reiser for pointing this out) */ -# define CHOP(a) \ - do { \ - unsigned long tmp = a >> 16; \ - a &= 0xffffUL; \ - a += (tmp << 4) - tmp; \ - } while (0) -# define MOD28(a) \ - do { \ - CHOP(a); \ - if (a >= BASE) a -= BASE; \ - } while (0) -# define MOD(a) \ - do { \ - CHOP(a); \ - MOD28(a); \ - } while (0) -# define MOD63(a) \ - do { /* this assumes a is not negative */ \ - z_off64_t tmp = a >> 32; \ - a &= 0xffffffffL; \ - a += (tmp << 8) - (tmp << 5) + tmp; \ - tmp = a >> 16; \ - a &= 0xffffL; \ - a += (tmp << 4) - tmp; \ - tmp = a >> 16; \ - a &= 0xffffL; \ - a += (tmp << 4) - tmp; \ - if (a >= BASE) a -= BASE; \ - } while (0) -#else -# define MOD(a) a %= BASE -# define MOD28(a) a %= BASE -# define MOD63(a) a %= BASE -#endif - -/* ========================================================================= */ -uLong ZEXPORT adler32(adler, buf, len) - uLong adler; - const Bytef *buf; - uInt len; -{ - unsigned long sum2; - unsigned n; - - /* split Adler-32 into component sums */ - sum2 = (adler >> 16) & 0xffff; - adler &= 0xffff; - - /* in case user likes doing a byte at a time, keep it fast */ - if (len == 1) { - adler += buf[0]; - if (adler >= BASE) - adler -= BASE; - sum2 += adler; - if (sum2 >= BASE) - sum2 -= BASE; - return adler | (sum2 << 16); - } - - /* initial Adler-32 value (deferred check for len == 1 speed) */ - if (buf == Z_NULL) - return 1L; - - /* in case short lengths are provided, keep it somewhat fast */ - if (len < 16) { - while (len--) { - adler += *buf++; - sum2 += adler; - } - if (adler >= BASE) - adler -= BASE; - MOD28(sum2); /* only added so many BASE's */ - return adler | (sum2 << 16); - } - - /* do length NMAX blocks -- requires just one modulo operation */ - while (len >= NMAX) { - len -= NMAX; - n = NMAX / 16; /* NMAX is divisible by 16 */ - do { - DO16(buf); /* 16 sums unrolled */ - buf += 16; - } while (--n); - MOD(adler); - MOD(sum2); - } - - /* do remaining bytes (less than NMAX, still just one modulo) */ - if (len) { /* avoid modulos if none remaining */ - while (len >= 16) { - len -= 16; - DO16(buf); - buf += 16; - } - while (len--) { - adler += *buf++; - sum2 += adler; - } - MOD(adler); - MOD(sum2); - } - - /* return recombined sums */ - return adler | (sum2 << 16); -} - -/* ========================================================================= */ -local uLong adler32_combine_(adler1, adler2, len2) - uLong adler1; - uLong adler2; - z_off64_t len2; -{ - unsigned long sum1; - unsigned long sum2; - unsigned rem; - - /* for negative len, return invalid adler32 as a clue for debugging */ - if (len2 < 0) - return 0xffffffffUL; - - /* the derivation of this formula is left as an exercise for the reader */ - MOD63(len2); /* assumes len2 >= 0 */ - rem = (unsigned)len2; - sum1 = adler1 & 0xffff; - sum2 = rem * sum1; - MOD(sum2); - sum1 += (adler2 & 0xffff) + BASE - 1; - sum2 += ((adler1 >> 16) & 0xffff) + ((adler2 >> 16) & 0xffff) + BASE - rem; - if (sum1 >= BASE) sum1 -= BASE; - if (sum1 >= BASE) sum1 -= BASE; - if (sum2 >= (BASE << 1)) sum2 -= (BASE << 1); - if (sum2 >= BASE) sum2 -= BASE; - return sum1 | (sum2 << 16); -} - -/* ========================================================================= */ -uLong ZEXPORT adler32_combine(adler1, adler2, len2) - uLong adler1; - uLong adler2; - z_off_t len2; -{ - return adler32_combine_(adler1, adler2, len2); -} - -uLong ZEXPORT adler32_combine64(adler1, adler2, len2) - uLong adler1; - uLong adler2; - z_off64_t len2; -{ - return adler32_combine_(adler1, adler2, len2); -} diff --git a/deps/zlib/crc32.c b/deps/zlib/crc32.c deleted file mode 100644 index 979a7190a..000000000 --- a/deps/zlib/crc32.c +++ /dev/null @@ -1,425 +0,0 @@ -/* crc32.c -- compute the CRC-32 of a data stream - * Copyright (C) 1995-2006, 2010, 2011, 2012 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - * - * Thanks to Rodney Brown for his contribution of faster - * CRC methods: exclusive-oring 32 bits of data at a time, and pre-computing - * tables for updating the shift register in one step with three exclusive-ors - * instead of four steps with four exclusive-ors. This results in about a - * factor of two increase in speed on a Power PC G4 (PPC7455) using gcc -O3. - */ - -/* @(#) $Id$ */ - -/* - Note on the use of DYNAMIC_CRC_TABLE: there is no mutex or semaphore - protection on the static variables used to control the first-use generation - of the crc tables. Therefore, if you #define DYNAMIC_CRC_TABLE, you should - first call get_crc_table() to initialize the tables before allowing more than - one thread to use crc32(). - - DYNAMIC_CRC_TABLE and MAKECRCH can be #defined to write out crc32.h. - */ - -#ifdef MAKECRCH -# include -# ifndef DYNAMIC_CRC_TABLE -# define DYNAMIC_CRC_TABLE -# endif /* !DYNAMIC_CRC_TABLE */ -#endif /* MAKECRCH */ - -#include "zutil.h" /* for STDC and FAR definitions */ - -#define local static - -/* Definitions for doing the crc four data bytes at a time. */ -#if !defined(NOBYFOUR) && defined(Z_U4) -# define BYFOUR -#endif -#ifdef BYFOUR - local unsigned long crc32_little OF((unsigned long, - const unsigned char FAR *, unsigned)); - local unsigned long crc32_big OF((unsigned long, - const unsigned char FAR *, unsigned)); -# define TBLS 8 -#else -# define TBLS 1 -#endif /* BYFOUR */ - -/* Local functions for crc concatenation */ -local unsigned long gf2_matrix_times OF((unsigned long *mat, - unsigned long vec)); -local void gf2_matrix_square OF((unsigned long *square, unsigned long *mat)); -local uLong crc32_combine_ OF((uLong crc1, uLong crc2, z_off64_t len2)); - - -#ifdef DYNAMIC_CRC_TABLE - -local volatile int crc_table_empty = 1; -local z_crc_t FAR crc_table[TBLS][256]; -local void make_crc_table OF((void)); -#ifdef MAKECRCH - local void write_table OF((FILE *, const z_crc_t FAR *)); -#endif /* MAKECRCH */ -/* - Generate tables for a byte-wise 32-bit CRC calculation on the polynomial: - x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1. - - Polynomials over GF(2) are represented in binary, one bit per coefficient, - with the lowest powers in the most significant bit. Then adding polynomials - is just exclusive-or, and multiplying a polynomial by x is a right shift by - one. If we call the above polynomial p, and represent a byte as the - polynomial q, also with the lowest power in the most significant bit (so the - byte 0xb1 is the polynomial x^7+x^3+x+1), then the CRC is (q*x^32) mod p, - where a mod b means the remainder after dividing a by b. - - This calculation is done using the shift-register method of multiplying and - taking the remainder. The register is initialized to zero, and for each - incoming bit, x^32 is added mod p to the register if the bit is a one (where - x^32 mod p is p+x^32 = x^26+...+1), and the register is multiplied mod p by - x (which is shifting right by one and adding x^32 mod p if the bit shifted - out is a one). We start with the highest power (least significant bit) of - q and repeat for all eight bits of q. - - The first table is simply the CRC of all possible eight bit values. This is - all the information needed to generate CRCs on data a byte at a time for all - combinations of CRC register values and incoming bytes. The remaining tables - allow for word-at-a-time CRC calculation for both big-endian and little- - endian machines, where a word is four bytes. -*/ -local void make_crc_table() -{ - z_crc_t c; - int n, k; - z_crc_t poly; /* polynomial exclusive-or pattern */ - /* terms of polynomial defining this crc (except x^32): */ - static volatile int first = 1; /* flag to limit concurrent making */ - static const unsigned char p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26}; - - /* See if another task is already doing this (not thread-safe, but better - than nothing -- significantly reduces duration of vulnerability in - case the advice about DYNAMIC_CRC_TABLE is ignored) */ - if (first) { - first = 0; - - /* make exclusive-or pattern from polynomial (0xedb88320UL) */ - poly = 0; - for (n = 0; n < (int)(sizeof(p)/sizeof(unsigned char)); n++) - poly |= (z_crc_t)1 << (31 - p[n]); - - /* generate a crc for every 8-bit value */ - for (n = 0; n < 256; n++) { - c = (z_crc_t)n; - for (k = 0; k < 8; k++) - c = c & 1 ? poly ^ (c >> 1) : c >> 1; - crc_table[0][n] = c; - } - -#ifdef BYFOUR - /* generate crc for each value followed by one, two, and three zeros, - and then the byte reversal of those as well as the first table */ - for (n = 0; n < 256; n++) { - c = crc_table[0][n]; - crc_table[4][n] = ZSWAP32(c); - for (k = 1; k < 4; k++) { - c = crc_table[0][c & 0xff] ^ (c >> 8); - crc_table[k][n] = c; - crc_table[k + 4][n] = ZSWAP32(c); - } - } -#endif /* BYFOUR */ - - crc_table_empty = 0; - } - else { /* not first */ - /* wait for the other guy to finish (not efficient, but rare) */ - while (crc_table_empty) - ; - } - -#ifdef MAKECRCH - /* write out CRC tables to crc32.h */ - { - FILE *out; - - out = fopen("crc32.h", "w"); - if (out == NULL) return; - fprintf(out, "/* crc32.h -- tables for rapid CRC calculation\n"); - fprintf(out, " * Generated automatically by crc32.c\n */\n\n"); - fprintf(out, "local const z_crc_t FAR "); - fprintf(out, "crc_table[TBLS][256] =\n{\n {\n"); - write_table(out, crc_table[0]); -# ifdef BYFOUR - fprintf(out, "#ifdef BYFOUR\n"); - for (k = 1; k < 8; k++) { - fprintf(out, " },\n {\n"); - write_table(out, crc_table[k]); - } - fprintf(out, "#endif\n"); -# endif /* BYFOUR */ - fprintf(out, " }\n};\n"); - fclose(out); - } -#endif /* MAKECRCH */ -} - -#ifdef MAKECRCH -local void write_table(out, table) - FILE *out; - const z_crc_t FAR *table; -{ - int n; - - for (n = 0; n < 256; n++) - fprintf(out, "%s0x%08lxUL%s", n % 5 ? "" : " ", - (unsigned long)(table[n]), - n == 255 ? "\n" : (n % 5 == 4 ? ",\n" : ", ")); -} -#endif /* MAKECRCH */ - -#else /* !DYNAMIC_CRC_TABLE */ -/* ======================================================================== - * Tables of CRC-32s of all single-byte values, made by make_crc_table(). - */ -#include "crc32.h" -#endif /* DYNAMIC_CRC_TABLE */ - -/* ========================================================================= - * This function can be used by asm versions of crc32() - */ -const z_crc_t FAR * ZEXPORT get_crc_table() -{ -#ifdef DYNAMIC_CRC_TABLE - if (crc_table_empty) - make_crc_table(); -#endif /* DYNAMIC_CRC_TABLE */ - return (const z_crc_t FAR *)crc_table; -} - -/* ========================================================================= */ -#define DO1 crc = crc_table[0][((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8) -#define DO8 DO1; DO1; DO1; DO1; DO1; DO1; DO1; DO1 - -/* ========================================================================= */ -unsigned long ZEXPORT crc32(crc, buf, len) - unsigned long crc; - const unsigned char FAR *buf; - uInt len; -{ - if (buf == Z_NULL) return 0UL; - -#ifdef DYNAMIC_CRC_TABLE - if (crc_table_empty) - make_crc_table(); -#endif /* DYNAMIC_CRC_TABLE */ - -#ifdef BYFOUR - if (sizeof(void *) == sizeof(ptrdiff_t)) { - z_crc_t endian; - - endian = 1; - if (*((unsigned char *)(&endian))) - return crc32_little(crc, buf, len); - else - return crc32_big(crc, buf, len); - } -#endif /* BYFOUR */ - crc = crc ^ 0xffffffffUL; - while (len >= 8) { - DO8; - len -= 8; - } - if (len) do { - DO1; - } while (--len); - return crc ^ 0xffffffffUL; -} - -#ifdef BYFOUR - -/* ========================================================================= */ -#define DOLIT4 c ^= *buf4++; \ - c = crc_table[3][c & 0xff] ^ crc_table[2][(c >> 8) & 0xff] ^ \ - crc_table[1][(c >> 16) & 0xff] ^ crc_table[0][c >> 24] -#define DOLIT32 DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4 - -/* ========================================================================= */ -local unsigned long crc32_little(crc, buf, len) - unsigned long crc; - const unsigned char FAR *buf; - unsigned len; -{ - register z_crc_t c; - register const z_crc_t FAR *buf4; - - c = (z_crc_t)crc; - c = ~c; - while (len && ((ptrdiff_t)buf & 3)) { - c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8); - len--; - } - - buf4 = (const z_crc_t FAR *)(const void FAR *)buf; - while (len >= 32) { - DOLIT32; - len -= 32; - } - while (len >= 4) { - DOLIT4; - len -= 4; - } - buf = (const unsigned char FAR *)buf4; - - if (len) do { - c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8); - } while (--len); - c = ~c; - return (unsigned long)c; -} - -/* ========================================================================= */ -#define DOBIG4 c ^= *++buf4; \ - c = crc_table[4][c & 0xff] ^ crc_table[5][(c >> 8) & 0xff] ^ \ - crc_table[6][(c >> 16) & 0xff] ^ crc_table[7][c >> 24] -#define DOBIG32 DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4 - -/* ========================================================================= */ -local unsigned long crc32_big(crc, buf, len) - unsigned long crc; - const unsigned char FAR *buf; - unsigned len; -{ - register z_crc_t c; - register const z_crc_t FAR *buf4; - - c = ZSWAP32((z_crc_t)crc); - c = ~c; - while (len && ((ptrdiff_t)buf & 3)) { - c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8); - len--; - } - - buf4 = (const z_crc_t FAR *)(const void FAR *)buf; - buf4--; - while (len >= 32) { - DOBIG32; - len -= 32; - } - while (len >= 4) { - DOBIG4; - len -= 4; - } - buf4++; - buf = (const unsigned char FAR *)buf4; - - if (len) do { - c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8); - } while (--len); - c = ~c; - return (unsigned long)(ZSWAP32(c)); -} - -#endif /* BYFOUR */ - -#define GF2_DIM 32 /* dimension of GF(2) vectors (length of CRC) */ - -/* ========================================================================= */ -local unsigned long gf2_matrix_times(mat, vec) - unsigned long *mat; - unsigned long vec; -{ - unsigned long sum; - - sum = 0; - while (vec) { - if (vec & 1) - sum ^= *mat; - vec >>= 1; - mat++; - } - return sum; -} - -/* ========================================================================= */ -local void gf2_matrix_square(square, mat) - unsigned long *square; - unsigned long *mat; -{ - int n; - - for (n = 0; n < GF2_DIM; n++) - square[n] = gf2_matrix_times(mat, mat[n]); -} - -/* ========================================================================= */ -local uLong crc32_combine_(crc1, crc2, len2) - uLong crc1; - uLong crc2; - z_off64_t len2; -{ - int n; - unsigned long row; - unsigned long even[GF2_DIM]; /* even-power-of-two zeros operator */ - unsigned long odd[GF2_DIM]; /* odd-power-of-two zeros operator */ - - /* degenerate case (also disallow negative lengths) */ - if (len2 <= 0) - return crc1; - - /* put operator for one zero bit in odd */ - odd[0] = 0xedb88320UL; /* CRC-32 polynomial */ - row = 1; - for (n = 1; n < GF2_DIM; n++) { - odd[n] = row; - row <<= 1; - } - - /* put operator for two zero bits in even */ - gf2_matrix_square(even, odd); - - /* put operator for four zero bits in odd */ - gf2_matrix_square(odd, even); - - /* apply len2 zeros to crc1 (first square will put the operator for one - zero byte, eight zero bits, in even) */ - do { - /* apply zeros operator for this bit of len2 */ - gf2_matrix_square(even, odd); - if (len2 & 1) - crc1 = gf2_matrix_times(even, crc1); - len2 >>= 1; - - /* if no more bits set, then done */ - if (len2 == 0) - break; - - /* another iteration of the loop with odd and even swapped */ - gf2_matrix_square(odd, even); - if (len2 & 1) - crc1 = gf2_matrix_times(odd, crc1); - len2 >>= 1; - - /* if no more bits set, then done */ - } while (len2 != 0); - - /* return combined crc */ - crc1 ^= crc2; - return crc1; -} - -/* ========================================================================= */ -uLong ZEXPORT crc32_combine(crc1, crc2, len2) - uLong crc1; - uLong crc2; - z_off_t len2; -{ - return crc32_combine_(crc1, crc2, len2); -} - -uLong ZEXPORT crc32_combine64(crc1, crc2, len2) - uLong crc1; - uLong crc2; - z_off64_t len2; -{ - return crc32_combine_(crc1, crc2, len2); -} diff --git a/deps/zlib/crc32.h b/deps/zlib/crc32.h deleted file mode 100644 index 9e0c77810..000000000 --- a/deps/zlib/crc32.h +++ /dev/null @@ -1,441 +0,0 @@ -/* crc32.h -- tables for rapid CRC calculation - * Generated automatically by crc32.c - */ - -local const z_crc_t FAR crc_table[TBLS][256] = -{ - { - 0x00000000UL, 0x77073096UL, 0xee0e612cUL, 0x990951baUL, 0x076dc419UL, - 0x706af48fUL, 0xe963a535UL, 0x9e6495a3UL, 0x0edb8832UL, 0x79dcb8a4UL, - 0xe0d5e91eUL, 0x97d2d988UL, 0x09b64c2bUL, 0x7eb17cbdUL, 0xe7b82d07UL, - 0x90bf1d91UL, 0x1db71064UL, 0x6ab020f2UL, 0xf3b97148UL, 0x84be41deUL, - 0x1adad47dUL, 0x6ddde4ebUL, 0xf4d4b551UL, 0x83d385c7UL, 0x136c9856UL, - 0x646ba8c0UL, 0xfd62f97aUL, 0x8a65c9ecUL, 0x14015c4fUL, 0x63066cd9UL, - 0xfa0f3d63UL, 0x8d080df5UL, 0x3b6e20c8UL, 0x4c69105eUL, 0xd56041e4UL, - 0xa2677172UL, 0x3c03e4d1UL, 0x4b04d447UL, 0xd20d85fdUL, 0xa50ab56bUL, - 0x35b5a8faUL, 0x42b2986cUL, 0xdbbbc9d6UL, 0xacbcf940UL, 0x32d86ce3UL, - 0x45df5c75UL, 0xdcd60dcfUL, 0xabd13d59UL, 0x26d930acUL, 0x51de003aUL, - 0xc8d75180UL, 0xbfd06116UL, 0x21b4f4b5UL, 0x56b3c423UL, 0xcfba9599UL, - 0xb8bda50fUL, 0x2802b89eUL, 0x5f058808UL, 0xc60cd9b2UL, 0xb10be924UL, - 0x2f6f7c87UL, 0x58684c11UL, 0xc1611dabUL, 0xb6662d3dUL, 0x76dc4190UL, - 0x01db7106UL, 0x98d220bcUL, 0xefd5102aUL, 0x71b18589UL, 0x06b6b51fUL, - 0x9fbfe4a5UL, 0xe8b8d433UL, 0x7807c9a2UL, 0x0f00f934UL, 0x9609a88eUL, - 0xe10e9818UL, 0x7f6a0dbbUL, 0x086d3d2dUL, 0x91646c97UL, 0xe6635c01UL, - 0x6b6b51f4UL, 0x1c6c6162UL, 0x856530d8UL, 0xf262004eUL, 0x6c0695edUL, - 0x1b01a57bUL, 0x8208f4c1UL, 0xf50fc457UL, 0x65b0d9c6UL, 0x12b7e950UL, - 0x8bbeb8eaUL, 0xfcb9887cUL, 0x62dd1ddfUL, 0x15da2d49UL, 0x8cd37cf3UL, - 0xfbd44c65UL, 0x4db26158UL, 0x3ab551ceUL, 0xa3bc0074UL, 0xd4bb30e2UL, - 0x4adfa541UL, 0x3dd895d7UL, 0xa4d1c46dUL, 0xd3d6f4fbUL, 0x4369e96aUL, - 0x346ed9fcUL, 0xad678846UL, 0xda60b8d0UL, 0x44042d73UL, 0x33031de5UL, - 0xaa0a4c5fUL, 0xdd0d7cc9UL, 0x5005713cUL, 0x270241aaUL, 0xbe0b1010UL, - 0xc90c2086UL, 0x5768b525UL, 0x206f85b3UL, 0xb966d409UL, 0xce61e49fUL, - 0x5edef90eUL, 0x29d9c998UL, 0xb0d09822UL, 0xc7d7a8b4UL, 0x59b33d17UL, - 0x2eb40d81UL, 0xb7bd5c3bUL, 0xc0ba6cadUL, 0xedb88320UL, 0x9abfb3b6UL, - 0x03b6e20cUL, 0x74b1d29aUL, 0xead54739UL, 0x9dd277afUL, 0x04db2615UL, - 0x73dc1683UL, 0xe3630b12UL, 0x94643b84UL, 0x0d6d6a3eUL, 0x7a6a5aa8UL, - 0xe40ecf0bUL, 0x9309ff9dUL, 0x0a00ae27UL, 0x7d079eb1UL, 0xf00f9344UL, - 0x8708a3d2UL, 0x1e01f268UL, 0x6906c2feUL, 0xf762575dUL, 0x806567cbUL, - 0x196c3671UL, 0x6e6b06e7UL, 0xfed41b76UL, 0x89d32be0UL, 0x10da7a5aUL, - 0x67dd4accUL, 0xf9b9df6fUL, 0x8ebeeff9UL, 0x17b7be43UL, 0x60b08ed5UL, - 0xd6d6a3e8UL, 0xa1d1937eUL, 0x38d8c2c4UL, 0x4fdff252UL, 0xd1bb67f1UL, - 0xa6bc5767UL, 0x3fb506ddUL, 0x48b2364bUL, 0xd80d2bdaUL, 0xaf0a1b4cUL, - 0x36034af6UL, 0x41047a60UL, 0xdf60efc3UL, 0xa867df55UL, 0x316e8eefUL, - 0x4669be79UL, 0xcb61b38cUL, 0xbc66831aUL, 0x256fd2a0UL, 0x5268e236UL, - 0xcc0c7795UL, 0xbb0b4703UL, 0x220216b9UL, 0x5505262fUL, 0xc5ba3bbeUL, - 0xb2bd0b28UL, 0x2bb45a92UL, 0x5cb36a04UL, 0xc2d7ffa7UL, 0xb5d0cf31UL, - 0x2cd99e8bUL, 0x5bdeae1dUL, 0x9b64c2b0UL, 0xec63f226UL, 0x756aa39cUL, - 0x026d930aUL, 0x9c0906a9UL, 0xeb0e363fUL, 0x72076785UL, 0x05005713UL, - 0x95bf4a82UL, 0xe2b87a14UL, 0x7bb12baeUL, 0x0cb61b38UL, 0x92d28e9bUL, - 0xe5d5be0dUL, 0x7cdcefb7UL, 0x0bdbdf21UL, 0x86d3d2d4UL, 0xf1d4e242UL, - 0x68ddb3f8UL, 0x1fda836eUL, 0x81be16cdUL, 0xf6b9265bUL, 0x6fb077e1UL, - 0x18b74777UL, 0x88085ae6UL, 0xff0f6a70UL, 0x66063bcaUL, 0x11010b5cUL, - 0x8f659effUL, 0xf862ae69UL, 0x616bffd3UL, 0x166ccf45UL, 0xa00ae278UL, - 0xd70dd2eeUL, 0x4e048354UL, 0x3903b3c2UL, 0xa7672661UL, 0xd06016f7UL, - 0x4969474dUL, 0x3e6e77dbUL, 0xaed16a4aUL, 0xd9d65adcUL, 0x40df0b66UL, - 0x37d83bf0UL, 0xa9bcae53UL, 0xdebb9ec5UL, 0x47b2cf7fUL, 0x30b5ffe9UL, - 0xbdbdf21cUL, 0xcabac28aUL, 0x53b39330UL, 0x24b4a3a6UL, 0xbad03605UL, - 0xcdd70693UL, 0x54de5729UL, 0x23d967bfUL, 0xb3667a2eUL, 0xc4614ab8UL, - 0x5d681b02UL, 0x2a6f2b94UL, 0xb40bbe37UL, 0xc30c8ea1UL, 0x5a05df1bUL, - 0x2d02ef8dUL -#ifdef BYFOUR - }, - { - 0x00000000UL, 0x191b3141UL, 0x32366282UL, 0x2b2d53c3UL, 0x646cc504UL, - 0x7d77f445UL, 0x565aa786UL, 0x4f4196c7UL, 0xc8d98a08UL, 0xd1c2bb49UL, - 0xfaefe88aUL, 0xe3f4d9cbUL, 0xacb54f0cUL, 0xb5ae7e4dUL, 0x9e832d8eUL, - 0x87981ccfUL, 0x4ac21251UL, 0x53d92310UL, 0x78f470d3UL, 0x61ef4192UL, - 0x2eaed755UL, 0x37b5e614UL, 0x1c98b5d7UL, 0x05838496UL, 0x821b9859UL, - 0x9b00a918UL, 0xb02dfadbUL, 0xa936cb9aUL, 0xe6775d5dUL, 0xff6c6c1cUL, - 0xd4413fdfUL, 0xcd5a0e9eUL, 0x958424a2UL, 0x8c9f15e3UL, 0xa7b24620UL, - 0xbea97761UL, 0xf1e8e1a6UL, 0xe8f3d0e7UL, 0xc3de8324UL, 0xdac5b265UL, - 0x5d5daeaaUL, 0x44469febUL, 0x6f6bcc28UL, 0x7670fd69UL, 0x39316baeUL, - 0x202a5aefUL, 0x0b07092cUL, 0x121c386dUL, 0xdf4636f3UL, 0xc65d07b2UL, - 0xed705471UL, 0xf46b6530UL, 0xbb2af3f7UL, 0xa231c2b6UL, 0x891c9175UL, - 0x9007a034UL, 0x179fbcfbUL, 0x0e848dbaUL, 0x25a9de79UL, 0x3cb2ef38UL, - 0x73f379ffUL, 0x6ae848beUL, 0x41c51b7dUL, 0x58de2a3cUL, 0xf0794f05UL, - 0xe9627e44UL, 0xc24f2d87UL, 0xdb541cc6UL, 0x94158a01UL, 0x8d0ebb40UL, - 0xa623e883UL, 0xbf38d9c2UL, 0x38a0c50dUL, 0x21bbf44cUL, 0x0a96a78fUL, - 0x138d96ceUL, 0x5ccc0009UL, 0x45d73148UL, 0x6efa628bUL, 0x77e153caUL, - 0xbabb5d54UL, 0xa3a06c15UL, 0x888d3fd6UL, 0x91960e97UL, 0xded79850UL, - 0xc7cca911UL, 0xece1fad2UL, 0xf5facb93UL, 0x7262d75cUL, 0x6b79e61dUL, - 0x4054b5deUL, 0x594f849fUL, 0x160e1258UL, 0x0f152319UL, 0x243870daUL, - 0x3d23419bUL, 0x65fd6ba7UL, 0x7ce65ae6UL, 0x57cb0925UL, 0x4ed03864UL, - 0x0191aea3UL, 0x188a9fe2UL, 0x33a7cc21UL, 0x2abcfd60UL, 0xad24e1afUL, - 0xb43fd0eeUL, 0x9f12832dUL, 0x8609b26cUL, 0xc94824abUL, 0xd05315eaUL, - 0xfb7e4629UL, 0xe2657768UL, 0x2f3f79f6UL, 0x362448b7UL, 0x1d091b74UL, - 0x04122a35UL, 0x4b53bcf2UL, 0x52488db3UL, 0x7965de70UL, 0x607eef31UL, - 0xe7e6f3feUL, 0xfefdc2bfUL, 0xd5d0917cUL, 0xcccba03dUL, 0x838a36faUL, - 0x9a9107bbUL, 0xb1bc5478UL, 0xa8a76539UL, 0x3b83984bUL, 0x2298a90aUL, - 0x09b5fac9UL, 0x10aecb88UL, 0x5fef5d4fUL, 0x46f46c0eUL, 0x6dd93fcdUL, - 0x74c20e8cUL, 0xf35a1243UL, 0xea412302UL, 0xc16c70c1UL, 0xd8774180UL, - 0x9736d747UL, 0x8e2de606UL, 0xa500b5c5UL, 0xbc1b8484UL, 0x71418a1aUL, - 0x685abb5bUL, 0x4377e898UL, 0x5a6cd9d9UL, 0x152d4f1eUL, 0x0c367e5fUL, - 0x271b2d9cUL, 0x3e001cddUL, 0xb9980012UL, 0xa0833153UL, 0x8bae6290UL, - 0x92b553d1UL, 0xddf4c516UL, 0xc4eff457UL, 0xefc2a794UL, 0xf6d996d5UL, - 0xae07bce9UL, 0xb71c8da8UL, 0x9c31de6bUL, 0x852aef2aUL, 0xca6b79edUL, - 0xd37048acUL, 0xf85d1b6fUL, 0xe1462a2eUL, 0x66de36e1UL, 0x7fc507a0UL, - 0x54e85463UL, 0x4df36522UL, 0x02b2f3e5UL, 0x1ba9c2a4UL, 0x30849167UL, - 0x299fa026UL, 0xe4c5aeb8UL, 0xfdde9ff9UL, 0xd6f3cc3aUL, 0xcfe8fd7bUL, - 0x80a96bbcUL, 0x99b25afdUL, 0xb29f093eUL, 0xab84387fUL, 0x2c1c24b0UL, - 0x350715f1UL, 0x1e2a4632UL, 0x07317773UL, 0x4870e1b4UL, 0x516bd0f5UL, - 0x7a468336UL, 0x635db277UL, 0xcbfad74eUL, 0xd2e1e60fUL, 0xf9ccb5ccUL, - 0xe0d7848dUL, 0xaf96124aUL, 0xb68d230bUL, 0x9da070c8UL, 0x84bb4189UL, - 0x03235d46UL, 0x1a386c07UL, 0x31153fc4UL, 0x280e0e85UL, 0x674f9842UL, - 0x7e54a903UL, 0x5579fac0UL, 0x4c62cb81UL, 0x8138c51fUL, 0x9823f45eUL, - 0xb30ea79dUL, 0xaa1596dcUL, 0xe554001bUL, 0xfc4f315aUL, 0xd7626299UL, - 0xce7953d8UL, 0x49e14f17UL, 0x50fa7e56UL, 0x7bd72d95UL, 0x62cc1cd4UL, - 0x2d8d8a13UL, 0x3496bb52UL, 0x1fbbe891UL, 0x06a0d9d0UL, 0x5e7ef3ecUL, - 0x4765c2adUL, 0x6c48916eUL, 0x7553a02fUL, 0x3a1236e8UL, 0x230907a9UL, - 0x0824546aUL, 0x113f652bUL, 0x96a779e4UL, 0x8fbc48a5UL, 0xa4911b66UL, - 0xbd8a2a27UL, 0xf2cbbce0UL, 0xebd08da1UL, 0xc0fdde62UL, 0xd9e6ef23UL, - 0x14bce1bdUL, 0x0da7d0fcUL, 0x268a833fUL, 0x3f91b27eUL, 0x70d024b9UL, - 0x69cb15f8UL, 0x42e6463bUL, 0x5bfd777aUL, 0xdc656bb5UL, 0xc57e5af4UL, - 0xee530937UL, 0xf7483876UL, 0xb809aeb1UL, 0xa1129ff0UL, 0x8a3fcc33UL, - 0x9324fd72UL - }, - { - 0x00000000UL, 0x01c26a37UL, 0x0384d46eUL, 0x0246be59UL, 0x0709a8dcUL, - 0x06cbc2ebUL, 0x048d7cb2UL, 0x054f1685UL, 0x0e1351b8UL, 0x0fd13b8fUL, - 0x0d9785d6UL, 0x0c55efe1UL, 0x091af964UL, 0x08d89353UL, 0x0a9e2d0aUL, - 0x0b5c473dUL, 0x1c26a370UL, 0x1de4c947UL, 0x1fa2771eUL, 0x1e601d29UL, - 0x1b2f0bacUL, 0x1aed619bUL, 0x18abdfc2UL, 0x1969b5f5UL, 0x1235f2c8UL, - 0x13f798ffUL, 0x11b126a6UL, 0x10734c91UL, 0x153c5a14UL, 0x14fe3023UL, - 0x16b88e7aUL, 0x177ae44dUL, 0x384d46e0UL, 0x398f2cd7UL, 0x3bc9928eUL, - 0x3a0bf8b9UL, 0x3f44ee3cUL, 0x3e86840bUL, 0x3cc03a52UL, 0x3d025065UL, - 0x365e1758UL, 0x379c7d6fUL, 0x35dac336UL, 0x3418a901UL, 0x3157bf84UL, - 0x3095d5b3UL, 0x32d36beaUL, 0x331101ddUL, 0x246be590UL, 0x25a98fa7UL, - 0x27ef31feUL, 0x262d5bc9UL, 0x23624d4cUL, 0x22a0277bUL, 0x20e69922UL, - 0x2124f315UL, 0x2a78b428UL, 0x2bbade1fUL, 0x29fc6046UL, 0x283e0a71UL, - 0x2d711cf4UL, 0x2cb376c3UL, 0x2ef5c89aUL, 0x2f37a2adUL, 0x709a8dc0UL, - 0x7158e7f7UL, 0x731e59aeUL, 0x72dc3399UL, 0x7793251cUL, 0x76514f2bUL, - 0x7417f172UL, 0x75d59b45UL, 0x7e89dc78UL, 0x7f4bb64fUL, 0x7d0d0816UL, - 0x7ccf6221UL, 0x798074a4UL, 0x78421e93UL, 0x7a04a0caUL, 0x7bc6cafdUL, - 0x6cbc2eb0UL, 0x6d7e4487UL, 0x6f38fadeUL, 0x6efa90e9UL, 0x6bb5866cUL, - 0x6a77ec5bUL, 0x68315202UL, 0x69f33835UL, 0x62af7f08UL, 0x636d153fUL, - 0x612bab66UL, 0x60e9c151UL, 0x65a6d7d4UL, 0x6464bde3UL, 0x662203baUL, - 0x67e0698dUL, 0x48d7cb20UL, 0x4915a117UL, 0x4b531f4eUL, 0x4a917579UL, - 0x4fde63fcUL, 0x4e1c09cbUL, 0x4c5ab792UL, 0x4d98dda5UL, 0x46c49a98UL, - 0x4706f0afUL, 0x45404ef6UL, 0x448224c1UL, 0x41cd3244UL, 0x400f5873UL, - 0x4249e62aUL, 0x438b8c1dUL, 0x54f16850UL, 0x55330267UL, 0x5775bc3eUL, - 0x56b7d609UL, 0x53f8c08cUL, 0x523aaabbUL, 0x507c14e2UL, 0x51be7ed5UL, - 0x5ae239e8UL, 0x5b2053dfUL, 0x5966ed86UL, 0x58a487b1UL, 0x5deb9134UL, - 0x5c29fb03UL, 0x5e6f455aUL, 0x5fad2f6dUL, 0xe1351b80UL, 0xe0f771b7UL, - 0xe2b1cfeeUL, 0xe373a5d9UL, 0xe63cb35cUL, 0xe7fed96bUL, 0xe5b86732UL, - 0xe47a0d05UL, 0xef264a38UL, 0xeee4200fUL, 0xeca29e56UL, 0xed60f461UL, - 0xe82fe2e4UL, 0xe9ed88d3UL, 0xebab368aUL, 0xea695cbdUL, 0xfd13b8f0UL, - 0xfcd1d2c7UL, 0xfe976c9eUL, 0xff5506a9UL, 0xfa1a102cUL, 0xfbd87a1bUL, - 0xf99ec442UL, 0xf85cae75UL, 0xf300e948UL, 0xf2c2837fUL, 0xf0843d26UL, - 0xf1465711UL, 0xf4094194UL, 0xf5cb2ba3UL, 0xf78d95faUL, 0xf64fffcdUL, - 0xd9785d60UL, 0xd8ba3757UL, 0xdafc890eUL, 0xdb3ee339UL, 0xde71f5bcUL, - 0xdfb39f8bUL, 0xddf521d2UL, 0xdc374be5UL, 0xd76b0cd8UL, 0xd6a966efUL, - 0xd4efd8b6UL, 0xd52db281UL, 0xd062a404UL, 0xd1a0ce33UL, 0xd3e6706aUL, - 0xd2241a5dUL, 0xc55efe10UL, 0xc49c9427UL, 0xc6da2a7eUL, 0xc7184049UL, - 0xc25756ccUL, 0xc3953cfbUL, 0xc1d382a2UL, 0xc011e895UL, 0xcb4dafa8UL, - 0xca8fc59fUL, 0xc8c97bc6UL, 0xc90b11f1UL, 0xcc440774UL, 0xcd866d43UL, - 0xcfc0d31aUL, 0xce02b92dUL, 0x91af9640UL, 0x906dfc77UL, 0x922b422eUL, - 0x93e92819UL, 0x96a63e9cUL, 0x976454abUL, 0x9522eaf2UL, 0x94e080c5UL, - 0x9fbcc7f8UL, 0x9e7eadcfUL, 0x9c381396UL, 0x9dfa79a1UL, 0x98b56f24UL, - 0x99770513UL, 0x9b31bb4aUL, 0x9af3d17dUL, 0x8d893530UL, 0x8c4b5f07UL, - 0x8e0de15eUL, 0x8fcf8b69UL, 0x8a809decUL, 0x8b42f7dbUL, 0x89044982UL, - 0x88c623b5UL, 0x839a6488UL, 0x82580ebfUL, 0x801eb0e6UL, 0x81dcdad1UL, - 0x8493cc54UL, 0x8551a663UL, 0x8717183aUL, 0x86d5720dUL, 0xa9e2d0a0UL, - 0xa820ba97UL, 0xaa6604ceUL, 0xaba46ef9UL, 0xaeeb787cUL, 0xaf29124bUL, - 0xad6fac12UL, 0xacadc625UL, 0xa7f18118UL, 0xa633eb2fUL, 0xa4755576UL, - 0xa5b73f41UL, 0xa0f829c4UL, 0xa13a43f3UL, 0xa37cfdaaUL, 0xa2be979dUL, - 0xb5c473d0UL, 0xb40619e7UL, 0xb640a7beUL, 0xb782cd89UL, 0xb2cddb0cUL, - 0xb30fb13bUL, 0xb1490f62UL, 0xb08b6555UL, 0xbbd72268UL, 0xba15485fUL, - 0xb853f606UL, 0xb9919c31UL, 0xbcde8ab4UL, 0xbd1ce083UL, 0xbf5a5edaUL, - 0xbe9834edUL - }, - { - 0x00000000UL, 0xb8bc6765UL, 0xaa09c88bUL, 0x12b5afeeUL, 0x8f629757UL, - 0x37def032UL, 0x256b5fdcUL, 0x9dd738b9UL, 0xc5b428efUL, 0x7d084f8aUL, - 0x6fbde064UL, 0xd7018701UL, 0x4ad6bfb8UL, 0xf26ad8ddUL, 0xe0df7733UL, - 0x58631056UL, 0x5019579fUL, 0xe8a530faUL, 0xfa109f14UL, 0x42acf871UL, - 0xdf7bc0c8UL, 0x67c7a7adUL, 0x75720843UL, 0xcdce6f26UL, 0x95ad7f70UL, - 0x2d111815UL, 0x3fa4b7fbUL, 0x8718d09eUL, 0x1acfe827UL, 0xa2738f42UL, - 0xb0c620acUL, 0x087a47c9UL, 0xa032af3eUL, 0x188ec85bUL, 0x0a3b67b5UL, - 0xb28700d0UL, 0x2f503869UL, 0x97ec5f0cUL, 0x8559f0e2UL, 0x3de59787UL, - 0x658687d1UL, 0xdd3ae0b4UL, 0xcf8f4f5aUL, 0x7733283fUL, 0xeae41086UL, - 0x525877e3UL, 0x40edd80dUL, 0xf851bf68UL, 0xf02bf8a1UL, 0x48979fc4UL, - 0x5a22302aUL, 0xe29e574fUL, 0x7f496ff6UL, 0xc7f50893UL, 0xd540a77dUL, - 0x6dfcc018UL, 0x359fd04eUL, 0x8d23b72bUL, 0x9f9618c5UL, 0x272a7fa0UL, - 0xbafd4719UL, 0x0241207cUL, 0x10f48f92UL, 0xa848e8f7UL, 0x9b14583dUL, - 0x23a83f58UL, 0x311d90b6UL, 0x89a1f7d3UL, 0x1476cf6aUL, 0xaccaa80fUL, - 0xbe7f07e1UL, 0x06c36084UL, 0x5ea070d2UL, 0xe61c17b7UL, 0xf4a9b859UL, - 0x4c15df3cUL, 0xd1c2e785UL, 0x697e80e0UL, 0x7bcb2f0eUL, 0xc377486bUL, - 0xcb0d0fa2UL, 0x73b168c7UL, 0x6104c729UL, 0xd9b8a04cUL, 0x446f98f5UL, - 0xfcd3ff90UL, 0xee66507eUL, 0x56da371bUL, 0x0eb9274dUL, 0xb6054028UL, - 0xa4b0efc6UL, 0x1c0c88a3UL, 0x81dbb01aUL, 0x3967d77fUL, 0x2bd27891UL, - 0x936e1ff4UL, 0x3b26f703UL, 0x839a9066UL, 0x912f3f88UL, 0x299358edUL, - 0xb4446054UL, 0x0cf80731UL, 0x1e4da8dfUL, 0xa6f1cfbaUL, 0xfe92dfecUL, - 0x462eb889UL, 0x549b1767UL, 0xec277002UL, 0x71f048bbUL, 0xc94c2fdeUL, - 0xdbf98030UL, 0x6345e755UL, 0x6b3fa09cUL, 0xd383c7f9UL, 0xc1366817UL, - 0x798a0f72UL, 0xe45d37cbUL, 0x5ce150aeUL, 0x4e54ff40UL, 0xf6e89825UL, - 0xae8b8873UL, 0x1637ef16UL, 0x048240f8UL, 0xbc3e279dUL, 0x21e91f24UL, - 0x99557841UL, 0x8be0d7afUL, 0x335cb0caUL, 0xed59b63bUL, 0x55e5d15eUL, - 0x47507eb0UL, 0xffec19d5UL, 0x623b216cUL, 0xda874609UL, 0xc832e9e7UL, - 0x708e8e82UL, 0x28ed9ed4UL, 0x9051f9b1UL, 0x82e4565fUL, 0x3a58313aUL, - 0xa78f0983UL, 0x1f336ee6UL, 0x0d86c108UL, 0xb53aa66dUL, 0xbd40e1a4UL, - 0x05fc86c1UL, 0x1749292fUL, 0xaff54e4aUL, 0x322276f3UL, 0x8a9e1196UL, - 0x982bbe78UL, 0x2097d91dUL, 0x78f4c94bUL, 0xc048ae2eUL, 0xd2fd01c0UL, - 0x6a4166a5UL, 0xf7965e1cUL, 0x4f2a3979UL, 0x5d9f9697UL, 0xe523f1f2UL, - 0x4d6b1905UL, 0xf5d77e60UL, 0xe762d18eUL, 0x5fdeb6ebUL, 0xc2098e52UL, - 0x7ab5e937UL, 0x680046d9UL, 0xd0bc21bcUL, 0x88df31eaUL, 0x3063568fUL, - 0x22d6f961UL, 0x9a6a9e04UL, 0x07bda6bdUL, 0xbf01c1d8UL, 0xadb46e36UL, - 0x15080953UL, 0x1d724e9aUL, 0xa5ce29ffUL, 0xb77b8611UL, 0x0fc7e174UL, - 0x9210d9cdUL, 0x2aacbea8UL, 0x38191146UL, 0x80a57623UL, 0xd8c66675UL, - 0x607a0110UL, 0x72cfaefeUL, 0xca73c99bUL, 0x57a4f122UL, 0xef189647UL, - 0xfdad39a9UL, 0x45115eccUL, 0x764dee06UL, 0xcef18963UL, 0xdc44268dUL, - 0x64f841e8UL, 0xf92f7951UL, 0x41931e34UL, 0x5326b1daUL, 0xeb9ad6bfUL, - 0xb3f9c6e9UL, 0x0b45a18cUL, 0x19f00e62UL, 0xa14c6907UL, 0x3c9b51beUL, - 0x842736dbUL, 0x96929935UL, 0x2e2efe50UL, 0x2654b999UL, 0x9ee8defcUL, - 0x8c5d7112UL, 0x34e11677UL, 0xa9362eceUL, 0x118a49abUL, 0x033fe645UL, - 0xbb838120UL, 0xe3e09176UL, 0x5b5cf613UL, 0x49e959fdUL, 0xf1553e98UL, - 0x6c820621UL, 0xd43e6144UL, 0xc68bceaaUL, 0x7e37a9cfUL, 0xd67f4138UL, - 0x6ec3265dUL, 0x7c7689b3UL, 0xc4caeed6UL, 0x591dd66fUL, 0xe1a1b10aUL, - 0xf3141ee4UL, 0x4ba87981UL, 0x13cb69d7UL, 0xab770eb2UL, 0xb9c2a15cUL, - 0x017ec639UL, 0x9ca9fe80UL, 0x241599e5UL, 0x36a0360bUL, 0x8e1c516eUL, - 0x866616a7UL, 0x3eda71c2UL, 0x2c6fde2cUL, 0x94d3b949UL, 0x090481f0UL, - 0xb1b8e695UL, 0xa30d497bUL, 0x1bb12e1eUL, 0x43d23e48UL, 0xfb6e592dUL, - 0xe9dbf6c3UL, 0x516791a6UL, 0xccb0a91fUL, 0x740cce7aUL, 0x66b96194UL, - 0xde0506f1UL - }, - { - 0x00000000UL, 0x96300777UL, 0x2c610eeeUL, 0xba510999UL, 0x19c46d07UL, - 0x8ff46a70UL, 0x35a563e9UL, 0xa395649eUL, 0x3288db0eUL, 0xa4b8dc79UL, - 0x1ee9d5e0UL, 0x88d9d297UL, 0x2b4cb609UL, 0xbd7cb17eUL, 0x072db8e7UL, - 0x911dbf90UL, 0x6410b71dUL, 0xf220b06aUL, 0x4871b9f3UL, 0xde41be84UL, - 0x7dd4da1aUL, 0xebe4dd6dUL, 0x51b5d4f4UL, 0xc785d383UL, 0x56986c13UL, - 0xc0a86b64UL, 0x7af962fdUL, 0xecc9658aUL, 0x4f5c0114UL, 0xd96c0663UL, - 0x633d0ffaUL, 0xf50d088dUL, 0xc8206e3bUL, 0x5e10694cUL, 0xe44160d5UL, - 0x727167a2UL, 0xd1e4033cUL, 0x47d4044bUL, 0xfd850dd2UL, 0x6bb50aa5UL, - 0xfaa8b535UL, 0x6c98b242UL, 0xd6c9bbdbUL, 0x40f9bcacUL, 0xe36cd832UL, - 0x755cdf45UL, 0xcf0dd6dcUL, 0x593dd1abUL, 0xac30d926UL, 0x3a00de51UL, - 0x8051d7c8UL, 0x1661d0bfUL, 0xb5f4b421UL, 0x23c4b356UL, 0x9995bacfUL, - 0x0fa5bdb8UL, 0x9eb80228UL, 0x0888055fUL, 0xb2d90cc6UL, 0x24e90bb1UL, - 0x877c6f2fUL, 0x114c6858UL, 0xab1d61c1UL, 0x3d2d66b6UL, 0x9041dc76UL, - 0x0671db01UL, 0xbc20d298UL, 0x2a10d5efUL, 0x8985b171UL, 0x1fb5b606UL, - 0xa5e4bf9fUL, 0x33d4b8e8UL, 0xa2c90778UL, 0x34f9000fUL, 0x8ea80996UL, - 0x18980ee1UL, 0xbb0d6a7fUL, 0x2d3d6d08UL, 0x976c6491UL, 0x015c63e6UL, - 0xf4516b6bUL, 0x62616c1cUL, 0xd8306585UL, 0x4e0062f2UL, 0xed95066cUL, - 0x7ba5011bUL, 0xc1f40882UL, 0x57c40ff5UL, 0xc6d9b065UL, 0x50e9b712UL, - 0xeab8be8bUL, 0x7c88b9fcUL, 0xdf1ddd62UL, 0x492dda15UL, 0xf37cd38cUL, - 0x654cd4fbUL, 0x5861b24dUL, 0xce51b53aUL, 0x7400bca3UL, 0xe230bbd4UL, - 0x41a5df4aUL, 0xd795d83dUL, 0x6dc4d1a4UL, 0xfbf4d6d3UL, 0x6ae96943UL, - 0xfcd96e34UL, 0x468867adUL, 0xd0b860daUL, 0x732d0444UL, 0xe51d0333UL, - 0x5f4c0aaaUL, 0xc97c0dddUL, 0x3c710550UL, 0xaa410227UL, 0x10100bbeUL, - 0x86200cc9UL, 0x25b56857UL, 0xb3856f20UL, 0x09d466b9UL, 0x9fe461ceUL, - 0x0ef9de5eUL, 0x98c9d929UL, 0x2298d0b0UL, 0xb4a8d7c7UL, 0x173db359UL, - 0x810db42eUL, 0x3b5cbdb7UL, 0xad6cbac0UL, 0x2083b8edUL, 0xb6b3bf9aUL, - 0x0ce2b603UL, 0x9ad2b174UL, 0x3947d5eaUL, 0xaf77d29dUL, 0x1526db04UL, - 0x8316dc73UL, 0x120b63e3UL, 0x843b6494UL, 0x3e6a6d0dUL, 0xa85a6a7aUL, - 0x0bcf0ee4UL, 0x9dff0993UL, 0x27ae000aUL, 0xb19e077dUL, 0x44930ff0UL, - 0xd2a30887UL, 0x68f2011eUL, 0xfec20669UL, 0x5d5762f7UL, 0xcb676580UL, - 0x71366c19UL, 0xe7066b6eUL, 0x761bd4feUL, 0xe02bd389UL, 0x5a7ada10UL, - 0xcc4add67UL, 0x6fdfb9f9UL, 0xf9efbe8eUL, 0x43beb717UL, 0xd58eb060UL, - 0xe8a3d6d6UL, 0x7e93d1a1UL, 0xc4c2d838UL, 0x52f2df4fUL, 0xf167bbd1UL, - 0x6757bca6UL, 0xdd06b53fUL, 0x4b36b248UL, 0xda2b0dd8UL, 0x4c1b0aafUL, - 0xf64a0336UL, 0x607a0441UL, 0xc3ef60dfUL, 0x55df67a8UL, 0xef8e6e31UL, - 0x79be6946UL, 0x8cb361cbUL, 0x1a8366bcUL, 0xa0d26f25UL, 0x36e26852UL, - 0x95770cccUL, 0x03470bbbUL, 0xb9160222UL, 0x2f260555UL, 0xbe3bbac5UL, - 0x280bbdb2UL, 0x925ab42bUL, 0x046ab35cUL, 0xa7ffd7c2UL, 0x31cfd0b5UL, - 0x8b9ed92cUL, 0x1daede5bUL, 0xb0c2649bUL, 0x26f263ecUL, 0x9ca36a75UL, - 0x0a936d02UL, 0xa906099cUL, 0x3f360eebUL, 0x85670772UL, 0x13570005UL, - 0x824abf95UL, 0x147ab8e2UL, 0xae2bb17bUL, 0x381bb60cUL, 0x9b8ed292UL, - 0x0dbed5e5UL, 0xb7efdc7cUL, 0x21dfdb0bUL, 0xd4d2d386UL, 0x42e2d4f1UL, - 0xf8b3dd68UL, 0x6e83da1fUL, 0xcd16be81UL, 0x5b26b9f6UL, 0xe177b06fUL, - 0x7747b718UL, 0xe65a0888UL, 0x706a0fffUL, 0xca3b0666UL, 0x5c0b0111UL, - 0xff9e658fUL, 0x69ae62f8UL, 0xd3ff6b61UL, 0x45cf6c16UL, 0x78e20aa0UL, - 0xeed20dd7UL, 0x5483044eUL, 0xc2b30339UL, 0x612667a7UL, 0xf71660d0UL, - 0x4d476949UL, 0xdb776e3eUL, 0x4a6ad1aeUL, 0xdc5ad6d9UL, 0x660bdf40UL, - 0xf03bd837UL, 0x53aebca9UL, 0xc59ebbdeUL, 0x7fcfb247UL, 0xe9ffb530UL, - 0x1cf2bdbdUL, 0x8ac2bacaUL, 0x3093b353UL, 0xa6a3b424UL, 0x0536d0baUL, - 0x9306d7cdUL, 0x2957de54UL, 0xbf67d923UL, 0x2e7a66b3UL, 0xb84a61c4UL, - 0x021b685dUL, 0x942b6f2aUL, 0x37be0bb4UL, 0xa18e0cc3UL, 0x1bdf055aUL, - 0x8def022dUL - }, - { - 0x00000000UL, 0x41311b19UL, 0x82623632UL, 0xc3532d2bUL, 0x04c56c64UL, - 0x45f4777dUL, 0x86a75a56UL, 0xc796414fUL, 0x088ad9c8UL, 0x49bbc2d1UL, - 0x8ae8effaUL, 0xcbd9f4e3UL, 0x0c4fb5acUL, 0x4d7eaeb5UL, 0x8e2d839eUL, - 0xcf1c9887UL, 0x5112c24aUL, 0x1023d953UL, 0xd370f478UL, 0x9241ef61UL, - 0x55d7ae2eUL, 0x14e6b537UL, 0xd7b5981cUL, 0x96848305UL, 0x59981b82UL, - 0x18a9009bUL, 0xdbfa2db0UL, 0x9acb36a9UL, 0x5d5d77e6UL, 0x1c6c6cffUL, - 0xdf3f41d4UL, 0x9e0e5acdUL, 0xa2248495UL, 0xe3159f8cUL, 0x2046b2a7UL, - 0x6177a9beUL, 0xa6e1e8f1UL, 0xe7d0f3e8UL, 0x2483dec3UL, 0x65b2c5daUL, - 0xaaae5d5dUL, 0xeb9f4644UL, 0x28cc6b6fUL, 0x69fd7076UL, 0xae6b3139UL, - 0xef5a2a20UL, 0x2c09070bUL, 0x6d381c12UL, 0xf33646dfUL, 0xb2075dc6UL, - 0x715470edUL, 0x30656bf4UL, 0xf7f32abbUL, 0xb6c231a2UL, 0x75911c89UL, - 0x34a00790UL, 0xfbbc9f17UL, 0xba8d840eUL, 0x79dea925UL, 0x38efb23cUL, - 0xff79f373UL, 0xbe48e86aUL, 0x7d1bc541UL, 0x3c2ade58UL, 0x054f79f0UL, - 0x447e62e9UL, 0x872d4fc2UL, 0xc61c54dbUL, 0x018a1594UL, 0x40bb0e8dUL, - 0x83e823a6UL, 0xc2d938bfUL, 0x0dc5a038UL, 0x4cf4bb21UL, 0x8fa7960aUL, - 0xce968d13UL, 0x0900cc5cUL, 0x4831d745UL, 0x8b62fa6eUL, 0xca53e177UL, - 0x545dbbbaUL, 0x156ca0a3UL, 0xd63f8d88UL, 0x970e9691UL, 0x5098d7deUL, - 0x11a9ccc7UL, 0xd2fae1ecUL, 0x93cbfaf5UL, 0x5cd76272UL, 0x1de6796bUL, - 0xdeb55440UL, 0x9f844f59UL, 0x58120e16UL, 0x1923150fUL, 0xda703824UL, - 0x9b41233dUL, 0xa76bfd65UL, 0xe65ae67cUL, 0x2509cb57UL, 0x6438d04eUL, - 0xa3ae9101UL, 0xe29f8a18UL, 0x21cca733UL, 0x60fdbc2aUL, 0xafe124adUL, - 0xeed03fb4UL, 0x2d83129fUL, 0x6cb20986UL, 0xab2448c9UL, 0xea1553d0UL, - 0x29467efbUL, 0x687765e2UL, 0xf6793f2fUL, 0xb7482436UL, 0x741b091dUL, - 0x352a1204UL, 0xf2bc534bUL, 0xb38d4852UL, 0x70de6579UL, 0x31ef7e60UL, - 0xfef3e6e7UL, 0xbfc2fdfeUL, 0x7c91d0d5UL, 0x3da0cbccUL, 0xfa368a83UL, - 0xbb07919aUL, 0x7854bcb1UL, 0x3965a7a8UL, 0x4b98833bUL, 0x0aa99822UL, - 0xc9fab509UL, 0x88cbae10UL, 0x4f5def5fUL, 0x0e6cf446UL, 0xcd3fd96dUL, - 0x8c0ec274UL, 0x43125af3UL, 0x022341eaUL, 0xc1706cc1UL, 0x804177d8UL, - 0x47d73697UL, 0x06e62d8eUL, 0xc5b500a5UL, 0x84841bbcUL, 0x1a8a4171UL, - 0x5bbb5a68UL, 0x98e87743UL, 0xd9d96c5aUL, 0x1e4f2d15UL, 0x5f7e360cUL, - 0x9c2d1b27UL, 0xdd1c003eUL, 0x120098b9UL, 0x533183a0UL, 0x9062ae8bUL, - 0xd153b592UL, 0x16c5f4ddUL, 0x57f4efc4UL, 0x94a7c2efUL, 0xd596d9f6UL, - 0xe9bc07aeUL, 0xa88d1cb7UL, 0x6bde319cUL, 0x2aef2a85UL, 0xed796bcaUL, - 0xac4870d3UL, 0x6f1b5df8UL, 0x2e2a46e1UL, 0xe136de66UL, 0xa007c57fUL, - 0x6354e854UL, 0x2265f34dUL, 0xe5f3b202UL, 0xa4c2a91bUL, 0x67918430UL, - 0x26a09f29UL, 0xb8aec5e4UL, 0xf99fdefdUL, 0x3accf3d6UL, 0x7bfde8cfUL, - 0xbc6ba980UL, 0xfd5ab299UL, 0x3e099fb2UL, 0x7f3884abUL, 0xb0241c2cUL, - 0xf1150735UL, 0x32462a1eUL, 0x73773107UL, 0xb4e17048UL, 0xf5d06b51UL, - 0x3683467aUL, 0x77b25d63UL, 0x4ed7facbUL, 0x0fe6e1d2UL, 0xccb5ccf9UL, - 0x8d84d7e0UL, 0x4a1296afUL, 0x0b238db6UL, 0xc870a09dUL, 0x8941bb84UL, - 0x465d2303UL, 0x076c381aUL, 0xc43f1531UL, 0x850e0e28UL, 0x42984f67UL, - 0x03a9547eUL, 0xc0fa7955UL, 0x81cb624cUL, 0x1fc53881UL, 0x5ef42398UL, - 0x9da70eb3UL, 0xdc9615aaUL, 0x1b0054e5UL, 0x5a314ffcUL, 0x996262d7UL, - 0xd85379ceUL, 0x174fe149UL, 0x567efa50UL, 0x952dd77bUL, 0xd41ccc62UL, - 0x138a8d2dUL, 0x52bb9634UL, 0x91e8bb1fUL, 0xd0d9a006UL, 0xecf37e5eUL, - 0xadc26547UL, 0x6e91486cUL, 0x2fa05375UL, 0xe836123aUL, 0xa9070923UL, - 0x6a542408UL, 0x2b653f11UL, 0xe479a796UL, 0xa548bc8fUL, 0x661b91a4UL, - 0x272a8abdUL, 0xe0bccbf2UL, 0xa18dd0ebUL, 0x62defdc0UL, 0x23efe6d9UL, - 0xbde1bc14UL, 0xfcd0a70dUL, 0x3f838a26UL, 0x7eb2913fUL, 0xb924d070UL, - 0xf815cb69UL, 0x3b46e642UL, 0x7a77fd5bUL, 0xb56b65dcUL, 0xf45a7ec5UL, - 0x370953eeUL, 0x763848f7UL, 0xb1ae09b8UL, 0xf09f12a1UL, 0x33cc3f8aUL, - 0x72fd2493UL - }, - { - 0x00000000UL, 0x376ac201UL, 0x6ed48403UL, 0x59be4602UL, 0xdca80907UL, - 0xebc2cb06UL, 0xb27c8d04UL, 0x85164f05UL, 0xb851130eUL, 0x8f3bd10fUL, - 0xd685970dUL, 0xe1ef550cUL, 0x64f91a09UL, 0x5393d808UL, 0x0a2d9e0aUL, - 0x3d475c0bUL, 0x70a3261cUL, 0x47c9e41dUL, 0x1e77a21fUL, 0x291d601eUL, - 0xac0b2f1bUL, 0x9b61ed1aUL, 0xc2dfab18UL, 0xf5b56919UL, 0xc8f23512UL, - 0xff98f713UL, 0xa626b111UL, 0x914c7310UL, 0x145a3c15UL, 0x2330fe14UL, - 0x7a8eb816UL, 0x4de47a17UL, 0xe0464d38UL, 0xd72c8f39UL, 0x8e92c93bUL, - 0xb9f80b3aUL, 0x3cee443fUL, 0x0b84863eUL, 0x523ac03cUL, 0x6550023dUL, - 0x58175e36UL, 0x6f7d9c37UL, 0x36c3da35UL, 0x01a91834UL, 0x84bf5731UL, - 0xb3d59530UL, 0xea6bd332UL, 0xdd011133UL, 0x90e56b24UL, 0xa78fa925UL, - 0xfe31ef27UL, 0xc95b2d26UL, 0x4c4d6223UL, 0x7b27a022UL, 0x2299e620UL, - 0x15f32421UL, 0x28b4782aUL, 0x1fdeba2bUL, 0x4660fc29UL, 0x710a3e28UL, - 0xf41c712dUL, 0xc376b32cUL, 0x9ac8f52eUL, 0xada2372fUL, 0xc08d9a70UL, - 0xf7e75871UL, 0xae591e73UL, 0x9933dc72UL, 0x1c259377UL, 0x2b4f5176UL, - 0x72f11774UL, 0x459bd575UL, 0x78dc897eUL, 0x4fb64b7fUL, 0x16080d7dUL, - 0x2162cf7cUL, 0xa4748079UL, 0x931e4278UL, 0xcaa0047aUL, 0xfdcac67bUL, - 0xb02ebc6cUL, 0x87447e6dUL, 0xdefa386fUL, 0xe990fa6eUL, 0x6c86b56bUL, - 0x5bec776aUL, 0x02523168UL, 0x3538f369UL, 0x087faf62UL, 0x3f156d63UL, - 0x66ab2b61UL, 0x51c1e960UL, 0xd4d7a665UL, 0xe3bd6464UL, 0xba032266UL, - 0x8d69e067UL, 0x20cbd748UL, 0x17a11549UL, 0x4e1f534bUL, 0x7975914aUL, - 0xfc63de4fUL, 0xcb091c4eUL, 0x92b75a4cUL, 0xa5dd984dUL, 0x989ac446UL, - 0xaff00647UL, 0xf64e4045UL, 0xc1248244UL, 0x4432cd41UL, 0x73580f40UL, - 0x2ae64942UL, 0x1d8c8b43UL, 0x5068f154UL, 0x67023355UL, 0x3ebc7557UL, - 0x09d6b756UL, 0x8cc0f853UL, 0xbbaa3a52UL, 0xe2147c50UL, 0xd57ebe51UL, - 0xe839e25aUL, 0xdf53205bUL, 0x86ed6659UL, 0xb187a458UL, 0x3491eb5dUL, - 0x03fb295cUL, 0x5a456f5eUL, 0x6d2fad5fUL, 0x801b35e1UL, 0xb771f7e0UL, - 0xeecfb1e2UL, 0xd9a573e3UL, 0x5cb33ce6UL, 0x6bd9fee7UL, 0x3267b8e5UL, - 0x050d7ae4UL, 0x384a26efUL, 0x0f20e4eeUL, 0x569ea2ecUL, 0x61f460edUL, - 0xe4e22fe8UL, 0xd388ede9UL, 0x8a36abebUL, 0xbd5c69eaUL, 0xf0b813fdUL, - 0xc7d2d1fcUL, 0x9e6c97feUL, 0xa90655ffUL, 0x2c101afaUL, 0x1b7ad8fbUL, - 0x42c49ef9UL, 0x75ae5cf8UL, 0x48e900f3UL, 0x7f83c2f2UL, 0x263d84f0UL, - 0x115746f1UL, 0x944109f4UL, 0xa32bcbf5UL, 0xfa958df7UL, 0xcdff4ff6UL, - 0x605d78d9UL, 0x5737bad8UL, 0x0e89fcdaUL, 0x39e33edbUL, 0xbcf571deUL, - 0x8b9fb3dfUL, 0xd221f5ddUL, 0xe54b37dcUL, 0xd80c6bd7UL, 0xef66a9d6UL, - 0xb6d8efd4UL, 0x81b22dd5UL, 0x04a462d0UL, 0x33cea0d1UL, 0x6a70e6d3UL, - 0x5d1a24d2UL, 0x10fe5ec5UL, 0x27949cc4UL, 0x7e2adac6UL, 0x494018c7UL, - 0xcc5657c2UL, 0xfb3c95c3UL, 0xa282d3c1UL, 0x95e811c0UL, 0xa8af4dcbUL, - 0x9fc58fcaUL, 0xc67bc9c8UL, 0xf1110bc9UL, 0x740744ccUL, 0x436d86cdUL, - 0x1ad3c0cfUL, 0x2db902ceUL, 0x4096af91UL, 0x77fc6d90UL, 0x2e422b92UL, - 0x1928e993UL, 0x9c3ea696UL, 0xab546497UL, 0xf2ea2295UL, 0xc580e094UL, - 0xf8c7bc9fUL, 0xcfad7e9eUL, 0x9613389cUL, 0xa179fa9dUL, 0x246fb598UL, - 0x13057799UL, 0x4abb319bUL, 0x7dd1f39aUL, 0x3035898dUL, 0x075f4b8cUL, - 0x5ee10d8eUL, 0x698bcf8fUL, 0xec9d808aUL, 0xdbf7428bUL, 0x82490489UL, - 0xb523c688UL, 0x88649a83UL, 0xbf0e5882UL, 0xe6b01e80UL, 0xd1dadc81UL, - 0x54cc9384UL, 0x63a65185UL, 0x3a181787UL, 0x0d72d586UL, 0xa0d0e2a9UL, - 0x97ba20a8UL, 0xce0466aaUL, 0xf96ea4abUL, 0x7c78ebaeUL, 0x4b1229afUL, - 0x12ac6fadUL, 0x25c6adacUL, 0x1881f1a7UL, 0x2feb33a6UL, 0x765575a4UL, - 0x413fb7a5UL, 0xc429f8a0UL, 0xf3433aa1UL, 0xaafd7ca3UL, 0x9d97bea2UL, - 0xd073c4b5UL, 0xe71906b4UL, 0xbea740b6UL, 0x89cd82b7UL, 0x0cdbcdb2UL, - 0x3bb10fb3UL, 0x620f49b1UL, 0x55658bb0UL, 0x6822d7bbUL, 0x5f4815baUL, - 0x06f653b8UL, 0x319c91b9UL, 0xb48adebcUL, 0x83e01cbdUL, 0xda5e5abfUL, - 0xed3498beUL - }, - { - 0x00000000UL, 0x6567bcb8UL, 0x8bc809aaUL, 0xeeafb512UL, 0x5797628fUL, - 0x32f0de37UL, 0xdc5f6b25UL, 0xb938d79dUL, 0xef28b4c5UL, 0x8a4f087dUL, - 0x64e0bd6fUL, 0x018701d7UL, 0xb8bfd64aUL, 0xddd86af2UL, 0x3377dfe0UL, - 0x56106358UL, 0x9f571950UL, 0xfa30a5e8UL, 0x149f10faUL, 0x71f8ac42UL, - 0xc8c07bdfUL, 0xada7c767UL, 0x43087275UL, 0x266fcecdUL, 0x707fad95UL, - 0x1518112dUL, 0xfbb7a43fUL, 0x9ed01887UL, 0x27e8cf1aUL, 0x428f73a2UL, - 0xac20c6b0UL, 0xc9477a08UL, 0x3eaf32a0UL, 0x5bc88e18UL, 0xb5673b0aUL, - 0xd00087b2UL, 0x6938502fUL, 0x0c5fec97UL, 0xe2f05985UL, 0x8797e53dUL, - 0xd1878665UL, 0xb4e03addUL, 0x5a4f8fcfUL, 0x3f283377UL, 0x8610e4eaUL, - 0xe3775852UL, 0x0dd8ed40UL, 0x68bf51f8UL, 0xa1f82bf0UL, 0xc49f9748UL, - 0x2a30225aUL, 0x4f579ee2UL, 0xf66f497fUL, 0x9308f5c7UL, 0x7da740d5UL, - 0x18c0fc6dUL, 0x4ed09f35UL, 0x2bb7238dUL, 0xc518969fUL, 0xa07f2a27UL, - 0x1947fdbaUL, 0x7c204102UL, 0x928ff410UL, 0xf7e848a8UL, 0x3d58149bUL, - 0x583fa823UL, 0xb6901d31UL, 0xd3f7a189UL, 0x6acf7614UL, 0x0fa8caacUL, - 0xe1077fbeUL, 0x8460c306UL, 0xd270a05eUL, 0xb7171ce6UL, 0x59b8a9f4UL, - 0x3cdf154cUL, 0x85e7c2d1UL, 0xe0807e69UL, 0x0e2fcb7bUL, 0x6b4877c3UL, - 0xa20f0dcbUL, 0xc768b173UL, 0x29c70461UL, 0x4ca0b8d9UL, 0xf5986f44UL, - 0x90ffd3fcUL, 0x7e5066eeUL, 0x1b37da56UL, 0x4d27b90eUL, 0x284005b6UL, - 0xc6efb0a4UL, 0xa3880c1cUL, 0x1ab0db81UL, 0x7fd76739UL, 0x9178d22bUL, - 0xf41f6e93UL, 0x03f7263bUL, 0x66909a83UL, 0x883f2f91UL, 0xed589329UL, - 0x546044b4UL, 0x3107f80cUL, 0xdfa84d1eUL, 0xbacff1a6UL, 0xecdf92feUL, - 0x89b82e46UL, 0x67179b54UL, 0x027027ecUL, 0xbb48f071UL, 0xde2f4cc9UL, - 0x3080f9dbUL, 0x55e74563UL, 0x9ca03f6bUL, 0xf9c783d3UL, 0x176836c1UL, - 0x720f8a79UL, 0xcb375de4UL, 0xae50e15cUL, 0x40ff544eUL, 0x2598e8f6UL, - 0x73888baeUL, 0x16ef3716UL, 0xf8408204UL, 0x9d273ebcUL, 0x241fe921UL, - 0x41785599UL, 0xafd7e08bUL, 0xcab05c33UL, 0x3bb659edUL, 0x5ed1e555UL, - 0xb07e5047UL, 0xd519ecffUL, 0x6c213b62UL, 0x094687daUL, 0xe7e932c8UL, - 0x828e8e70UL, 0xd49eed28UL, 0xb1f95190UL, 0x5f56e482UL, 0x3a31583aUL, - 0x83098fa7UL, 0xe66e331fUL, 0x08c1860dUL, 0x6da63ab5UL, 0xa4e140bdUL, - 0xc186fc05UL, 0x2f294917UL, 0x4a4ef5afUL, 0xf3762232UL, 0x96119e8aUL, - 0x78be2b98UL, 0x1dd99720UL, 0x4bc9f478UL, 0x2eae48c0UL, 0xc001fdd2UL, - 0xa566416aUL, 0x1c5e96f7UL, 0x79392a4fUL, 0x97969f5dUL, 0xf2f123e5UL, - 0x05196b4dUL, 0x607ed7f5UL, 0x8ed162e7UL, 0xebb6de5fUL, 0x528e09c2UL, - 0x37e9b57aUL, 0xd9460068UL, 0xbc21bcd0UL, 0xea31df88UL, 0x8f566330UL, - 0x61f9d622UL, 0x049e6a9aUL, 0xbda6bd07UL, 0xd8c101bfUL, 0x366eb4adUL, - 0x53090815UL, 0x9a4e721dUL, 0xff29cea5UL, 0x11867bb7UL, 0x74e1c70fUL, - 0xcdd91092UL, 0xa8beac2aUL, 0x46111938UL, 0x2376a580UL, 0x7566c6d8UL, - 0x10017a60UL, 0xfeaecf72UL, 0x9bc973caUL, 0x22f1a457UL, 0x479618efUL, - 0xa939adfdUL, 0xcc5e1145UL, 0x06ee4d76UL, 0x6389f1ceUL, 0x8d2644dcUL, - 0xe841f864UL, 0x51792ff9UL, 0x341e9341UL, 0xdab12653UL, 0xbfd69aebUL, - 0xe9c6f9b3UL, 0x8ca1450bUL, 0x620ef019UL, 0x07694ca1UL, 0xbe519b3cUL, - 0xdb362784UL, 0x35999296UL, 0x50fe2e2eUL, 0x99b95426UL, 0xfcdee89eUL, - 0x12715d8cUL, 0x7716e134UL, 0xce2e36a9UL, 0xab498a11UL, 0x45e63f03UL, - 0x208183bbUL, 0x7691e0e3UL, 0x13f65c5bUL, 0xfd59e949UL, 0x983e55f1UL, - 0x2106826cUL, 0x44613ed4UL, 0xaace8bc6UL, 0xcfa9377eUL, 0x38417fd6UL, - 0x5d26c36eUL, 0xb389767cUL, 0xd6eecac4UL, 0x6fd61d59UL, 0x0ab1a1e1UL, - 0xe41e14f3UL, 0x8179a84bUL, 0xd769cb13UL, 0xb20e77abUL, 0x5ca1c2b9UL, - 0x39c67e01UL, 0x80fea99cUL, 0xe5991524UL, 0x0b36a036UL, 0x6e511c8eUL, - 0xa7166686UL, 0xc271da3eUL, 0x2cde6f2cUL, 0x49b9d394UL, 0xf0810409UL, - 0x95e6b8b1UL, 0x7b490da3UL, 0x1e2eb11bUL, 0x483ed243UL, 0x2d596efbUL, - 0xc3f6dbe9UL, 0xa6916751UL, 0x1fa9b0ccUL, 0x7ace0c74UL, 0x9461b966UL, - 0xf10605deUL -#endif - } -}; diff --git a/deps/zlib/deflate.c b/deps/zlib/deflate.c deleted file mode 100644 index 696957705..000000000 --- a/deps/zlib/deflate.c +++ /dev/null @@ -1,1967 +0,0 @@ -/* deflate.c -- compress data using the deflation algorithm - * Copyright (C) 1995-2013 Jean-loup Gailly and Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* - * ALGORITHM - * - * The "deflation" process depends on being able to identify portions - * of the input text which are identical to earlier input (within a - * sliding window trailing behind the input currently being processed). - * - * The most straightforward technique turns out to be the fastest for - * most input files: try all possible matches and select the longest. - * The key feature of this algorithm is that insertions into the string - * dictionary are very simple and thus fast, and deletions are avoided - * completely. Insertions are performed at each input character, whereas - * string matches are performed only when the previous match ends. So it - * is preferable to spend more time in matches to allow very fast string - * insertions and avoid deletions. The matching algorithm for small - * strings is inspired from that of Rabin & Karp. A brute force approach - * is used to find longer strings when a small match has been found. - * A similar algorithm is used in comic (by Jan-Mark Wams) and freeze - * (by Leonid Broukhis). - * A previous version of this file used a more sophisticated algorithm - * (by Fiala and Greene) which is guaranteed to run in linear amortized - * time, but has a larger average cost, uses more memory and is patented. - * However the F&G algorithm may be faster for some highly redundant - * files if the parameter max_chain_length (described below) is too large. - * - * ACKNOWLEDGEMENTS - * - * The idea of lazy evaluation of matches is due to Jan-Mark Wams, and - * I found it in 'freeze' written by Leonid Broukhis. - * Thanks to many people for bug reports and testing. - * - * REFERENCES - * - * Deutsch, L.P.,"DEFLATE Compressed Data Format Specification". - * Available in http://tools.ietf.org/html/rfc1951 - * - * A description of the Rabin and Karp algorithm is given in the book - * "Algorithms" by R. Sedgewick, Addison-Wesley, p252. - * - * Fiala,E.R., and Greene,D.H. - * Data Compression with Finite Windows, Comm.ACM, 32,4 (1989) 490-595 - * - */ - -/* @(#) $Id$ */ - -#include "deflate.h" - -const char deflate_copyright[] = - " deflate 1.2.8 Copyright 1995-2013 Jean-loup Gailly and Mark Adler "; -/* - If you use the zlib library in a product, an acknowledgment is welcome - in the documentation of your product. If for some reason you cannot - include such an acknowledgment, I would appreciate that you keep this - copyright string in the executable of your product. - */ - -/* =========================================================================== - * Function prototypes. - */ -typedef enum { - need_more, /* block not completed, need more input or more output */ - block_done, /* block flush performed */ - finish_started, /* finish started, need only more output at next deflate */ - finish_done /* finish done, accept no more input or output */ -} block_state; - -typedef block_state (*compress_func) OF((deflate_state *s, int flush)); -/* Compression function. Returns the block state after the call. */ - -local void fill_window OF((deflate_state *s)); -local block_state deflate_stored OF((deflate_state *s, int flush)); -local block_state deflate_fast OF((deflate_state *s, int flush)); -#ifndef FASTEST -local block_state deflate_slow OF((deflate_state *s, int flush)); -#endif -local block_state deflate_rle OF((deflate_state *s, int flush)); -local block_state deflate_huff OF((deflate_state *s, int flush)); -local void lm_init OF((deflate_state *s)); -local void putShortMSB OF((deflate_state *s, uInt b)); -local void flush_pending OF((z_streamp strm)); -local int read_buf OF((z_streamp strm, Bytef *buf, unsigned size)); -#ifdef ASMV - void match_init OF((void)); /* asm code initialization */ - uInt longest_match OF((deflate_state *s, IPos cur_match)); -#else -local uInt longest_match OF((deflate_state *s, IPos cur_match)); -#endif - -#ifdef DEBUG -local void check_match OF((deflate_state *s, IPos start, IPos match, - int length)); -#endif - -/* =========================================================================== - * Local data - */ - -#define NIL 0 -/* Tail of hash chains */ - -#ifndef TOO_FAR -# define TOO_FAR 4096 -#endif -/* Matches of length 3 are discarded if their distance exceeds TOO_FAR */ - -/* Values for max_lazy_match, good_match and max_chain_length, depending on - * the desired pack level (0..9). The values given below have been tuned to - * exclude worst case performance for pathological files. Better values may be - * found for specific files. - */ -typedef struct config_s { - ush good_length; /* reduce lazy search above this match length */ - ush max_lazy; /* do not perform lazy search above this match length */ - ush nice_length; /* quit search above this match length */ - ush max_chain; - compress_func func; -} config; - -#ifdef FASTEST -local const config configuration_table[2] = { -/* good lazy nice chain */ -/* 0 */ {0, 0, 0, 0, deflate_stored}, /* store only */ -/* 1 */ {4, 4, 8, 4, deflate_fast}}; /* max speed, no lazy matches */ -#else -local const config configuration_table[10] = { -/* good lazy nice chain */ -/* 0 */ {0, 0, 0, 0, deflate_stored}, /* store only */ -/* 1 */ {4, 4, 8, 4, deflate_fast}, /* max speed, no lazy matches */ -/* 2 */ {4, 5, 16, 8, deflate_fast}, -/* 3 */ {4, 6, 32, 32, deflate_fast}, - -/* 4 */ {4, 4, 16, 16, deflate_slow}, /* lazy matches */ -/* 5 */ {8, 16, 32, 32, deflate_slow}, -/* 6 */ {8, 16, 128, 128, deflate_slow}, -/* 7 */ {8, 32, 128, 256, deflate_slow}, -/* 8 */ {32, 128, 258, 1024, deflate_slow}, -/* 9 */ {32, 258, 258, 4096, deflate_slow}}; /* max compression */ -#endif - -/* Note: the deflate() code requires max_lazy >= MIN_MATCH and max_chain >= 4 - * For deflate_fast() (levels <= 3) good is ignored and lazy has a different - * meaning. - */ - -#define EQUAL 0 -/* result of memcmp for equal strings */ - -#ifndef NO_DUMMY_DECL -struct static_tree_desc_s {int dummy;}; /* for buggy compilers */ -#endif - -/* rank Z_BLOCK between Z_NO_FLUSH and Z_PARTIAL_FLUSH */ -#define RANK(f) (((f) << 1) - ((f) > 4 ? 9 : 0)) - -/* =========================================================================== - * Update a hash value with the given input byte - * IN assertion: all calls to to UPDATE_HASH are made with consecutive - * input characters, so that a running hash key can be computed from the - * previous key instead of complete recalculation each time. - */ -#define UPDATE_HASH(s,h,c) (h = (((h)<hash_shift) ^ (c)) & s->hash_mask) - - -/* =========================================================================== - * Insert string str in the dictionary and set match_head to the previous head - * of the hash chain (the most recent string with same hash key). Return - * the previous length of the hash chain. - * If this file is compiled with -DFASTEST, the compression level is forced - * to 1, and no hash chains are maintained. - * IN assertion: all calls to to INSERT_STRING are made with consecutive - * input characters and the first MIN_MATCH bytes of str are valid - * (except for the last MIN_MATCH-1 bytes of the input file). - */ -#ifdef FASTEST -#define INSERT_STRING(s, str, match_head) \ - (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \ - match_head = s->head[s->ins_h], \ - s->head[s->ins_h] = (Pos)(str)) -#else -#define INSERT_STRING(s, str, match_head) \ - (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \ - match_head = s->prev[(str) & s->w_mask] = s->head[s->ins_h], \ - s->head[s->ins_h] = (Pos)(str)) -#endif - -/* =========================================================================== - * Initialize the hash table (avoiding 64K overflow for 16 bit systems). - * prev[] will be initialized on the fly. - */ -#define CLEAR_HASH(s) \ - s->head[s->hash_size-1] = NIL; \ - zmemzero((Bytef *)s->head, (unsigned)(s->hash_size-1)*sizeof(*s->head)); - -/* ========================================================================= */ -int ZEXPORT deflateInit_(strm, level, version, stream_size) - z_streamp strm; - int level; - const char *version; - int stream_size; -{ - return deflateInit2_(strm, level, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL, - Z_DEFAULT_STRATEGY, version, stream_size); - /* To do: ignore strm->next_in if we use it as window */ -} - -/* ========================================================================= */ -int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy, - version, stream_size) - z_streamp strm; - int level; - int method; - int windowBits; - int memLevel; - int strategy; - const char *version; - int stream_size; -{ - deflate_state *s; - int wrap = 1; - static const char my_version[] = ZLIB_VERSION; - - ushf *overlay; - /* We overlay pending_buf and d_buf+l_buf. This works since the average - * output size for (length,distance) codes is <= 24 bits. - */ - - if (version == Z_NULL || version[0] != my_version[0] || - stream_size != sizeof(z_stream)) { - return Z_VERSION_ERROR; - } - if (strm == Z_NULL) return Z_STREAM_ERROR; - - strm->msg = Z_NULL; - if (strm->zalloc == (alloc_func)0) { -#ifdef Z_SOLO - return Z_STREAM_ERROR; -#else - strm->zalloc = zcalloc; - strm->opaque = (voidpf)0; -#endif - } - if (strm->zfree == (free_func)0) -#ifdef Z_SOLO - return Z_STREAM_ERROR; -#else - strm->zfree = zcfree; -#endif - -#ifdef FASTEST - if (level != 0) level = 1; -#else - if (level == Z_DEFAULT_COMPRESSION) level = 6; -#endif - - if (windowBits < 0) { /* suppress zlib wrapper */ - wrap = 0; - windowBits = -windowBits; - } -#ifdef GZIP - else if (windowBits > 15) { - wrap = 2; /* write gzip wrapper instead */ - windowBits -= 16; - } -#endif - if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method != Z_DEFLATED || - windowBits < 8 || windowBits > 15 || level < 0 || level > 9 || - strategy < 0 || strategy > Z_FIXED) { - return Z_STREAM_ERROR; - } - if (windowBits == 8) windowBits = 9; /* until 256-byte window bug fixed */ - s = (deflate_state *) ZALLOC(strm, 1, sizeof(deflate_state)); - if (s == Z_NULL) return Z_MEM_ERROR; - strm->state = (struct internal_state FAR *)s; - s->strm = strm; - - s->wrap = wrap; - s->gzhead = Z_NULL; - s->w_bits = windowBits; - s->w_size = 1 << s->w_bits; - s->w_mask = s->w_size - 1; - - s->hash_bits = memLevel + 7; - s->hash_size = 1 << s->hash_bits; - s->hash_mask = s->hash_size - 1; - s->hash_shift = ((s->hash_bits+MIN_MATCH-1)/MIN_MATCH); - - s->window = (Bytef *) ZALLOC(strm, s->w_size, 2*sizeof(Byte)); - s->prev = (Posf *) ZALLOC(strm, s->w_size, sizeof(Pos)); - s->head = (Posf *) ZALLOC(strm, s->hash_size, sizeof(Pos)); - - s->high_water = 0; /* nothing written to s->window yet */ - - s->lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */ - - overlay = (ushf *) ZALLOC(strm, s->lit_bufsize, sizeof(ush)+2); - s->pending_buf = (uchf *) overlay; - s->pending_buf_size = (ulg)s->lit_bufsize * (sizeof(ush)+2L); - - if (s->window == Z_NULL || s->prev == Z_NULL || s->head == Z_NULL || - s->pending_buf == Z_NULL) { - s->status = FINISH_STATE; - strm->msg = ERR_MSG(Z_MEM_ERROR); - deflateEnd (strm); - return Z_MEM_ERROR; - } - s->d_buf = overlay + s->lit_bufsize/sizeof(ush); - s->l_buf = s->pending_buf + (1+sizeof(ush))*s->lit_bufsize; - - s->level = level; - s->strategy = strategy; - s->method = (Byte)method; - - return deflateReset(strm); -} - -/* ========================================================================= */ -int ZEXPORT deflateSetDictionary (strm, dictionary, dictLength) - z_streamp strm; - const Bytef *dictionary; - uInt dictLength; -{ - deflate_state *s; - uInt str, n; - int wrap; - unsigned avail; - z_const unsigned char *next; - - if (strm == Z_NULL || strm->state == Z_NULL || dictionary == Z_NULL) - return Z_STREAM_ERROR; - s = strm->state; - wrap = s->wrap; - if (wrap == 2 || (wrap == 1 && s->status != INIT_STATE) || s->lookahead) - return Z_STREAM_ERROR; - - /* when using zlib wrappers, compute Adler-32 for provided dictionary */ - if (wrap == 1) - strm->adler = adler32(strm->adler, dictionary, dictLength); - s->wrap = 0; /* avoid computing Adler-32 in read_buf */ - - /* if dictionary would fill window, just replace the history */ - if (dictLength >= s->w_size) { - if (wrap == 0) { /* already empty otherwise */ - CLEAR_HASH(s); - s->strstart = 0; - s->block_start = 0L; - s->insert = 0; - } - dictionary += dictLength - s->w_size; /* use the tail */ - dictLength = s->w_size; - } - - /* insert dictionary into window and hash */ - avail = strm->avail_in; - next = strm->next_in; - strm->avail_in = dictLength; - strm->next_in = (z_const Bytef *)dictionary; - fill_window(s); - while (s->lookahead >= MIN_MATCH) { - str = s->strstart; - n = s->lookahead - (MIN_MATCH-1); - do { - UPDATE_HASH(s, s->ins_h, s->window[str + MIN_MATCH-1]); -#ifndef FASTEST - s->prev[str & s->w_mask] = s->head[s->ins_h]; -#endif - s->head[s->ins_h] = (Pos)str; - str++; - } while (--n); - s->strstart = str; - s->lookahead = MIN_MATCH-1; - fill_window(s); - } - s->strstart += s->lookahead; - s->block_start = (long)s->strstart; - s->insert = s->lookahead; - s->lookahead = 0; - s->match_length = s->prev_length = MIN_MATCH-1; - s->match_available = 0; - strm->next_in = next; - strm->avail_in = avail; - s->wrap = wrap; - return Z_OK; -} - -/* ========================================================================= */ -int ZEXPORT deflateResetKeep (strm) - z_streamp strm; -{ - deflate_state *s; - - if (strm == Z_NULL || strm->state == Z_NULL || - strm->zalloc == (alloc_func)0 || strm->zfree == (free_func)0) { - return Z_STREAM_ERROR; - } - - strm->total_in = strm->total_out = 0; - strm->msg = Z_NULL; /* use zfree if we ever allocate msg dynamically */ - strm->data_type = Z_UNKNOWN; - - s = (deflate_state *)strm->state; - s->pending = 0; - s->pending_out = s->pending_buf; - - if (s->wrap < 0) { - s->wrap = -s->wrap; /* was made negative by deflate(..., Z_FINISH); */ - } - s->status = s->wrap ? INIT_STATE : BUSY_STATE; - strm->adler = -#ifdef GZIP - s->wrap == 2 ? crc32(0L, Z_NULL, 0) : -#endif - adler32(0L, Z_NULL, 0); - s->last_flush = Z_NO_FLUSH; - - _tr_init(s); - - return Z_OK; -} - -/* ========================================================================= */ -int ZEXPORT deflateReset (strm) - z_streamp strm; -{ - int ret; - - ret = deflateResetKeep(strm); - if (ret == Z_OK) - lm_init(strm->state); - return ret; -} - -/* ========================================================================= */ -int ZEXPORT deflateSetHeader (strm, head) - z_streamp strm; - gz_headerp head; -{ - if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; - if (strm->state->wrap != 2) return Z_STREAM_ERROR; - strm->state->gzhead = head; - return Z_OK; -} - -/* ========================================================================= */ -int ZEXPORT deflatePending (strm, pending, bits) - unsigned *pending; - int *bits; - z_streamp strm; -{ - if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; - if (pending != Z_NULL) - *pending = strm->state->pending; - if (bits != Z_NULL) - *bits = strm->state->bi_valid; - return Z_OK; -} - -/* ========================================================================= */ -int ZEXPORT deflatePrime (strm, bits, value) - z_streamp strm; - int bits; - int value; -{ - deflate_state *s; - int put; - - if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; - s = strm->state; - if ((Bytef *)(s->d_buf) < s->pending_out + ((Buf_size + 7) >> 3)) - return Z_BUF_ERROR; - do { - put = Buf_size - s->bi_valid; - if (put > bits) - put = bits; - s->bi_buf |= (ush)((value & ((1 << put) - 1)) << s->bi_valid); - s->bi_valid += put; - _tr_flush_bits(s); - value >>= put; - bits -= put; - } while (bits); - return Z_OK; -} - -/* ========================================================================= */ -int ZEXPORT deflateParams(strm, level, strategy) - z_streamp strm; - int level; - int strategy; -{ - deflate_state *s; - compress_func func; - int err = Z_OK; - - if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; - s = strm->state; - -#ifdef FASTEST - if (level != 0) level = 1; -#else - if (level == Z_DEFAULT_COMPRESSION) level = 6; -#endif - if (level < 0 || level > 9 || strategy < 0 || strategy > Z_FIXED) { - return Z_STREAM_ERROR; - } - func = configuration_table[s->level].func; - - if ((strategy != s->strategy || func != configuration_table[level].func) && - strm->total_in != 0) { - /* Flush the last buffer: */ - err = deflate(strm, Z_BLOCK); - if (err == Z_BUF_ERROR && s->pending == 0) - err = Z_OK; - } - if (s->level != level) { - s->level = level; - s->max_lazy_match = configuration_table[level].max_lazy; - s->good_match = configuration_table[level].good_length; - s->nice_match = configuration_table[level].nice_length; - s->max_chain_length = configuration_table[level].max_chain; - } - s->strategy = strategy; - return err; -} - -/* ========================================================================= */ -int ZEXPORT deflateTune(strm, good_length, max_lazy, nice_length, max_chain) - z_streamp strm; - int good_length; - int max_lazy; - int nice_length; - int max_chain; -{ - deflate_state *s; - - if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; - s = strm->state; - s->good_match = good_length; - s->max_lazy_match = max_lazy; - s->nice_match = nice_length; - s->max_chain_length = max_chain; - return Z_OK; -} - -/* ========================================================================= - * For the default windowBits of 15 and memLevel of 8, this function returns - * a close to exact, as well as small, upper bound on the compressed size. - * They are coded as constants here for a reason--if the #define's are - * changed, then this function needs to be changed as well. The return - * value for 15 and 8 only works for those exact settings. - * - * For any setting other than those defaults for windowBits and memLevel, - * the value returned is a conservative worst case for the maximum expansion - * resulting from using fixed blocks instead of stored blocks, which deflate - * can emit on compressed data for some combinations of the parameters. - * - * This function could be more sophisticated to provide closer upper bounds for - * every combination of windowBits and memLevel. But even the conservative - * upper bound of about 14% expansion does not seem onerous for output buffer - * allocation. - */ -uLong ZEXPORT deflateBound(strm, sourceLen) - z_streamp strm; - uLong sourceLen; -{ - deflate_state *s; - uLong complen, wraplen; - Bytef *str; - - /* conservative upper bound for compressed data */ - complen = sourceLen + - ((sourceLen + 7) >> 3) + ((sourceLen + 63) >> 6) + 5; - - /* if can't get parameters, return conservative bound plus zlib wrapper */ - if (strm == Z_NULL || strm->state == Z_NULL) - return complen + 6; - - /* compute wrapper length */ - s = strm->state; - switch (s->wrap) { - case 0: /* raw deflate */ - wraplen = 0; - break; - case 1: /* zlib wrapper */ - wraplen = 6 + (s->strstart ? 4 : 0); - break; - case 2: /* gzip wrapper */ - wraplen = 18; - if (s->gzhead != Z_NULL) { /* user-supplied gzip header */ - if (s->gzhead->extra != Z_NULL) - wraplen += 2 + s->gzhead->extra_len; - str = s->gzhead->name; - if (str != Z_NULL) - do { - wraplen++; - } while (*str++); - str = s->gzhead->comment; - if (str != Z_NULL) - do { - wraplen++; - } while (*str++); - if (s->gzhead->hcrc) - wraplen += 2; - } - break; - default: /* for compiler happiness */ - wraplen = 6; - } - - /* if not default parameters, return conservative bound */ - if (s->w_bits != 15 || s->hash_bits != 8 + 7) - return complen + wraplen; - - /* default settings: return tight bound for that case */ - return sourceLen + (sourceLen >> 12) + (sourceLen >> 14) + - (sourceLen >> 25) + 13 - 6 + wraplen; -} - -/* ========================================================================= - * Put a short in the pending buffer. The 16-bit value is put in MSB order. - * IN assertion: the stream state is correct and there is enough room in - * pending_buf. - */ -local void putShortMSB (s, b) - deflate_state *s; - uInt b; -{ - put_byte(s, (Byte)(b >> 8)); - put_byte(s, (Byte)(b & 0xff)); -} - -/* ========================================================================= - * Flush as much pending output as possible. All deflate() output goes - * through this function so some applications may wish to modify it - * to avoid allocating a large strm->next_out buffer and copying into it. - * (See also read_buf()). - */ -local void flush_pending(strm) - z_streamp strm; -{ - unsigned len; - deflate_state *s = strm->state; - - _tr_flush_bits(s); - len = s->pending; - if (len > strm->avail_out) len = strm->avail_out; - if (len == 0) return; - - zmemcpy(strm->next_out, s->pending_out, len); - strm->next_out += len; - s->pending_out += len; - strm->total_out += len; - strm->avail_out -= len; - s->pending -= len; - if (s->pending == 0) { - s->pending_out = s->pending_buf; - } -} - -/* ========================================================================= */ -int ZEXPORT deflate (strm, flush) - z_streamp strm; - int flush; -{ - int old_flush; /* value of flush param for previous deflate call */ - deflate_state *s; - - if (strm == Z_NULL || strm->state == Z_NULL || - flush > Z_BLOCK || flush < 0) { - return Z_STREAM_ERROR; - } - s = strm->state; - - if (strm->next_out == Z_NULL || - (strm->next_in == Z_NULL && strm->avail_in != 0) || - (s->status == FINISH_STATE && flush != Z_FINISH)) { - ERR_RETURN(strm, Z_STREAM_ERROR); - } - if (strm->avail_out == 0) ERR_RETURN(strm, Z_BUF_ERROR); - - s->strm = strm; /* just in case */ - old_flush = s->last_flush; - s->last_flush = flush; - - /* Write the header */ - if (s->status == INIT_STATE) { -#ifdef GZIP - if (s->wrap == 2) { - strm->adler = crc32(0L, Z_NULL, 0); - put_byte(s, 31); - put_byte(s, 139); - put_byte(s, 8); - if (s->gzhead == Z_NULL) { - put_byte(s, 0); - put_byte(s, 0); - put_byte(s, 0); - put_byte(s, 0); - put_byte(s, 0); - put_byte(s, s->level == 9 ? 2 : - (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ? - 4 : 0)); - put_byte(s, OS_CODE); - s->status = BUSY_STATE; - } - else { - put_byte(s, (s->gzhead->text ? 1 : 0) + - (s->gzhead->hcrc ? 2 : 0) + - (s->gzhead->extra == Z_NULL ? 0 : 4) + - (s->gzhead->name == Z_NULL ? 0 : 8) + - (s->gzhead->comment == Z_NULL ? 0 : 16) - ); - put_byte(s, (Byte)(s->gzhead->time & 0xff)); - put_byte(s, (Byte)((s->gzhead->time >> 8) & 0xff)); - put_byte(s, (Byte)((s->gzhead->time >> 16) & 0xff)); - put_byte(s, (Byte)((s->gzhead->time >> 24) & 0xff)); - put_byte(s, s->level == 9 ? 2 : - (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ? - 4 : 0)); - put_byte(s, s->gzhead->os & 0xff); - if (s->gzhead->extra != Z_NULL) { - put_byte(s, s->gzhead->extra_len & 0xff); - put_byte(s, (s->gzhead->extra_len >> 8) & 0xff); - } - if (s->gzhead->hcrc) - strm->adler = crc32(strm->adler, s->pending_buf, - s->pending); - s->gzindex = 0; - s->status = EXTRA_STATE; - } - } - else -#endif - { - uInt header = (Z_DEFLATED + ((s->w_bits-8)<<4)) << 8; - uInt level_flags; - - if (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2) - level_flags = 0; - else if (s->level < 6) - level_flags = 1; - else if (s->level == 6) - level_flags = 2; - else - level_flags = 3; - header |= (level_flags << 6); - if (s->strstart != 0) header |= PRESET_DICT; - header += 31 - (header % 31); - - s->status = BUSY_STATE; - putShortMSB(s, header); - - /* Save the adler32 of the preset dictionary: */ - if (s->strstart != 0) { - putShortMSB(s, (uInt)(strm->adler >> 16)); - putShortMSB(s, (uInt)(strm->adler & 0xffff)); - } - strm->adler = adler32(0L, Z_NULL, 0); - } - } -#ifdef GZIP - if (s->status == EXTRA_STATE) { - if (s->gzhead->extra != Z_NULL) { - uInt beg = s->pending; /* start of bytes to update crc */ - - while (s->gzindex < (s->gzhead->extra_len & 0xffff)) { - if (s->pending == s->pending_buf_size) { - if (s->gzhead->hcrc && s->pending > beg) - strm->adler = crc32(strm->adler, s->pending_buf + beg, - s->pending - beg); - flush_pending(strm); - beg = s->pending; - if (s->pending == s->pending_buf_size) - break; - } - put_byte(s, s->gzhead->extra[s->gzindex]); - s->gzindex++; - } - if (s->gzhead->hcrc && s->pending > beg) - strm->adler = crc32(strm->adler, s->pending_buf + beg, - s->pending - beg); - if (s->gzindex == s->gzhead->extra_len) { - s->gzindex = 0; - s->status = NAME_STATE; - } - } - else - s->status = NAME_STATE; - } - if (s->status == NAME_STATE) { - if (s->gzhead->name != Z_NULL) { - uInt beg = s->pending; /* start of bytes to update crc */ - int val; - - do { - if (s->pending == s->pending_buf_size) { - if (s->gzhead->hcrc && s->pending > beg) - strm->adler = crc32(strm->adler, s->pending_buf + beg, - s->pending - beg); - flush_pending(strm); - beg = s->pending; - if (s->pending == s->pending_buf_size) { - val = 1; - break; - } - } - val = s->gzhead->name[s->gzindex++]; - put_byte(s, val); - } while (val != 0); - if (s->gzhead->hcrc && s->pending > beg) - strm->adler = crc32(strm->adler, s->pending_buf + beg, - s->pending - beg); - if (val == 0) { - s->gzindex = 0; - s->status = COMMENT_STATE; - } - } - else - s->status = COMMENT_STATE; - } - if (s->status == COMMENT_STATE) { - if (s->gzhead->comment != Z_NULL) { - uInt beg = s->pending; /* start of bytes to update crc */ - int val; - - do { - if (s->pending == s->pending_buf_size) { - if (s->gzhead->hcrc && s->pending > beg) - strm->adler = crc32(strm->adler, s->pending_buf + beg, - s->pending - beg); - flush_pending(strm); - beg = s->pending; - if (s->pending == s->pending_buf_size) { - val = 1; - break; - } - } - val = s->gzhead->comment[s->gzindex++]; - put_byte(s, val); - } while (val != 0); - if (s->gzhead->hcrc && s->pending > beg) - strm->adler = crc32(strm->adler, s->pending_buf + beg, - s->pending - beg); - if (val == 0) - s->status = HCRC_STATE; - } - else - s->status = HCRC_STATE; - } - if (s->status == HCRC_STATE) { - if (s->gzhead->hcrc) { - if (s->pending + 2 > s->pending_buf_size) - flush_pending(strm); - if (s->pending + 2 <= s->pending_buf_size) { - put_byte(s, (Byte)(strm->adler & 0xff)); - put_byte(s, (Byte)((strm->adler >> 8) & 0xff)); - strm->adler = crc32(0L, Z_NULL, 0); - s->status = BUSY_STATE; - } - } - else - s->status = BUSY_STATE; - } -#endif - - /* Flush as much pending output as possible */ - if (s->pending != 0) { - flush_pending(strm); - if (strm->avail_out == 0) { - /* Since avail_out is 0, deflate will be called again with - * more output space, but possibly with both pending and - * avail_in equal to zero. There won't be anything to do, - * but this is not an error situation so make sure we - * return OK instead of BUF_ERROR at next call of deflate: - */ - s->last_flush = -1; - return Z_OK; - } - - /* Make sure there is something to do and avoid duplicate consecutive - * flushes. For repeated and useless calls with Z_FINISH, we keep - * returning Z_STREAM_END instead of Z_BUF_ERROR. - */ - } else if (strm->avail_in == 0 && RANK(flush) <= RANK(old_flush) && - flush != Z_FINISH) { - ERR_RETURN(strm, Z_BUF_ERROR); - } - - /* User must not provide more input after the first FINISH: */ - if (s->status == FINISH_STATE && strm->avail_in != 0) { - ERR_RETURN(strm, Z_BUF_ERROR); - } - - /* Start a new block or continue the current one. - */ - if (strm->avail_in != 0 || s->lookahead != 0 || - (flush != Z_NO_FLUSH && s->status != FINISH_STATE)) { - block_state bstate; - - bstate = s->strategy == Z_HUFFMAN_ONLY ? deflate_huff(s, flush) : - (s->strategy == Z_RLE ? deflate_rle(s, flush) : - (*(configuration_table[s->level].func))(s, flush)); - - if (bstate == finish_started || bstate == finish_done) { - s->status = FINISH_STATE; - } - if (bstate == need_more || bstate == finish_started) { - if (strm->avail_out == 0) { - s->last_flush = -1; /* avoid BUF_ERROR next call, see above */ - } - return Z_OK; - /* If flush != Z_NO_FLUSH && avail_out == 0, the next call - * of deflate should use the same flush parameter to make sure - * that the flush is complete. So we don't have to output an - * empty block here, this will be done at next call. This also - * ensures that for a very small output buffer, we emit at most - * one empty block. - */ - } - if (bstate == block_done) { - if (flush == Z_PARTIAL_FLUSH) { - _tr_align(s); - } else if (flush != Z_BLOCK) { /* FULL_FLUSH or SYNC_FLUSH */ - _tr_stored_block(s, (char*)0, 0L, 0); - /* For a full flush, this empty block will be recognized - * as a special marker by inflate_sync(). - */ - if (flush == Z_FULL_FLUSH) { - CLEAR_HASH(s); /* forget history */ - if (s->lookahead == 0) { - s->strstart = 0; - s->block_start = 0L; - s->insert = 0; - } - } - } - flush_pending(strm); - if (strm->avail_out == 0) { - s->last_flush = -1; /* avoid BUF_ERROR at next call, see above */ - return Z_OK; - } - } - } - Assert(strm->avail_out > 0, "bug2"); - - if (flush != Z_FINISH) return Z_OK; - if (s->wrap <= 0) return Z_STREAM_END; - - /* Write the trailer */ -#ifdef GZIP - if (s->wrap == 2) { - put_byte(s, (Byte)(strm->adler & 0xff)); - put_byte(s, (Byte)((strm->adler >> 8) & 0xff)); - put_byte(s, (Byte)((strm->adler >> 16) & 0xff)); - put_byte(s, (Byte)((strm->adler >> 24) & 0xff)); - put_byte(s, (Byte)(strm->total_in & 0xff)); - put_byte(s, (Byte)((strm->total_in >> 8) & 0xff)); - put_byte(s, (Byte)((strm->total_in >> 16) & 0xff)); - put_byte(s, (Byte)((strm->total_in >> 24) & 0xff)); - } - else -#endif - { - putShortMSB(s, (uInt)(strm->adler >> 16)); - putShortMSB(s, (uInt)(strm->adler & 0xffff)); - } - flush_pending(strm); - /* If avail_out is zero, the application will call deflate again - * to flush the rest. - */ - if (s->wrap > 0) s->wrap = -s->wrap; /* write the trailer only once! */ - return s->pending != 0 ? Z_OK : Z_STREAM_END; -} - -/* ========================================================================= */ -int ZEXPORT deflateEnd (strm) - z_streamp strm; -{ - int status; - - if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; - - status = strm->state->status; - if (status != INIT_STATE && - status != EXTRA_STATE && - status != NAME_STATE && - status != COMMENT_STATE && - status != HCRC_STATE && - status != BUSY_STATE && - status != FINISH_STATE) { - return Z_STREAM_ERROR; - } - - /* Deallocate in reverse order of allocations: */ - TRY_FREE(strm, strm->state->pending_buf); - TRY_FREE(strm, strm->state->head); - TRY_FREE(strm, strm->state->prev); - TRY_FREE(strm, strm->state->window); - - ZFREE(strm, strm->state); - strm->state = Z_NULL; - - return status == BUSY_STATE ? Z_DATA_ERROR : Z_OK; -} - -/* ========================================================================= - * Copy the source state to the destination state. - * To simplify the source, this is not supported for 16-bit MSDOS (which - * doesn't have enough memory anyway to duplicate compression states). - */ -int ZEXPORT deflateCopy (dest, source) - z_streamp dest; - z_streamp source; -{ -#ifdef MAXSEG_64K - return Z_STREAM_ERROR; -#else - deflate_state *ds; - deflate_state *ss; - ushf *overlay; - - - if (source == Z_NULL || dest == Z_NULL || source->state == Z_NULL) { - return Z_STREAM_ERROR; - } - - ss = source->state; - - zmemcpy((voidpf)dest, (voidpf)source, sizeof(z_stream)); - - ds = (deflate_state *) ZALLOC(dest, 1, sizeof(deflate_state)); - if (ds == Z_NULL) return Z_MEM_ERROR; - dest->state = (struct internal_state FAR *) ds; - zmemcpy((voidpf)ds, (voidpf)ss, sizeof(deflate_state)); - ds->strm = dest; - - ds->window = (Bytef *) ZALLOC(dest, ds->w_size, 2*sizeof(Byte)); - ds->prev = (Posf *) ZALLOC(dest, ds->w_size, sizeof(Pos)); - ds->head = (Posf *) ZALLOC(dest, ds->hash_size, sizeof(Pos)); - overlay = (ushf *) ZALLOC(dest, ds->lit_bufsize, sizeof(ush)+2); - ds->pending_buf = (uchf *) overlay; - - if (ds->window == Z_NULL || ds->prev == Z_NULL || ds->head == Z_NULL || - ds->pending_buf == Z_NULL) { - deflateEnd (dest); - return Z_MEM_ERROR; - } - /* following zmemcpy do not work for 16-bit MSDOS */ - zmemcpy(ds->window, ss->window, ds->w_size * 2 * sizeof(Byte)); - zmemcpy((voidpf)ds->prev, (voidpf)ss->prev, ds->w_size * sizeof(Pos)); - zmemcpy((voidpf)ds->head, (voidpf)ss->head, ds->hash_size * sizeof(Pos)); - zmemcpy(ds->pending_buf, ss->pending_buf, (uInt)ds->pending_buf_size); - - ds->pending_out = ds->pending_buf + (ss->pending_out - ss->pending_buf); - ds->d_buf = overlay + ds->lit_bufsize/sizeof(ush); - ds->l_buf = ds->pending_buf + (1+sizeof(ush))*ds->lit_bufsize; - - ds->l_desc.dyn_tree = ds->dyn_ltree; - ds->d_desc.dyn_tree = ds->dyn_dtree; - ds->bl_desc.dyn_tree = ds->bl_tree; - - return Z_OK; -#endif /* MAXSEG_64K */ -} - -/* =========================================================================== - * Read a new buffer from the current input stream, update the adler32 - * and total number of bytes read. All deflate() input goes through - * this function so some applications may wish to modify it to avoid - * allocating a large strm->next_in buffer and copying from it. - * (See also flush_pending()). - */ -local int read_buf(strm, buf, size) - z_streamp strm; - Bytef *buf; - unsigned size; -{ - unsigned len = strm->avail_in; - - if (len > size) len = size; - if (len == 0) return 0; - - strm->avail_in -= len; - - zmemcpy(buf, strm->next_in, len); - if (strm->state->wrap == 1) { - strm->adler = adler32(strm->adler, buf, len); - } -#ifdef GZIP - else if (strm->state->wrap == 2) { - strm->adler = crc32(strm->adler, buf, len); - } -#endif - strm->next_in += len; - strm->total_in += len; - - return (int)len; -} - -/* =========================================================================== - * Initialize the "longest match" routines for a new zlib stream - */ -local void lm_init (s) - deflate_state *s; -{ - s->window_size = (ulg)2L*s->w_size; - - CLEAR_HASH(s); - - /* Set the default configuration parameters: - */ - s->max_lazy_match = configuration_table[s->level].max_lazy; - s->good_match = configuration_table[s->level].good_length; - s->nice_match = configuration_table[s->level].nice_length; - s->max_chain_length = configuration_table[s->level].max_chain; - - s->strstart = 0; - s->block_start = 0L; - s->lookahead = 0; - s->insert = 0; - s->match_length = s->prev_length = MIN_MATCH-1; - s->match_available = 0; - s->ins_h = 0; -#ifndef FASTEST -#ifdef ASMV - match_init(); /* initialize the asm code */ -#endif -#endif -} - -#ifndef FASTEST -/* =========================================================================== - * Set match_start to the longest match starting at the given string and - * return its length. Matches shorter or equal to prev_length are discarded, - * in which case the result is equal to prev_length and match_start is - * garbage. - * IN assertions: cur_match is the head of the hash chain for the current - * string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1 - * OUT assertion: the match length is not greater than s->lookahead. - */ -#ifndef ASMV -/* For 80x86 and 680x0, an optimized version will be provided in match.asm or - * match.S. The code will be functionally equivalent. - */ -local uInt longest_match(s, cur_match) - deflate_state *s; - IPos cur_match; /* current match */ -{ - unsigned chain_length = s->max_chain_length;/* max hash chain length */ - register Bytef *scan = s->window + s->strstart; /* current string */ - register Bytef *match; /* matched string */ - register int len; /* length of current match */ - int best_len = s->prev_length; /* best match length so far */ - int nice_match = s->nice_match; /* stop if match long enough */ - IPos limit = s->strstart > (IPos)MAX_DIST(s) ? - s->strstart - (IPos)MAX_DIST(s) : NIL; - /* Stop when cur_match becomes <= limit. To simplify the code, - * we prevent matches with the string of window index 0. - */ - Posf *prev = s->prev; - uInt wmask = s->w_mask; - -#ifdef UNALIGNED_OK - /* Compare two bytes at a time. Note: this is not always beneficial. - * Try with and without -DUNALIGNED_OK to check. - */ - register Bytef *strend = s->window + s->strstart + MAX_MATCH - 1; - register ush scan_start = *(ushf*)scan; - register ush scan_end = *(ushf*)(scan+best_len-1); -#else - register Bytef *strend = s->window + s->strstart + MAX_MATCH; - register Byte scan_end1 = scan[best_len-1]; - register Byte scan_end = scan[best_len]; -#endif - - /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. - * It is easy to get rid of this optimization if necessary. - */ - Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever"); - - /* Do not waste too much time if we already have a good match: */ - if (s->prev_length >= s->good_match) { - chain_length >>= 2; - } - /* Do not look for matches beyond the end of the input. This is necessary - * to make deflate deterministic. - */ - if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead; - - Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead"); - - do { - Assert(cur_match < s->strstart, "no future"); - match = s->window + cur_match; - - /* Skip to next match if the match length cannot increase - * or if the match length is less than 2. Note that the checks below - * for insufficient lookahead only occur occasionally for performance - * reasons. Therefore uninitialized memory will be accessed, and - * conditional jumps will be made that depend on those values. - * However the length of the match is limited to the lookahead, so - * the output of deflate is not affected by the uninitialized values. - */ -#if (defined(UNALIGNED_OK) && MAX_MATCH == 258) - /* This code assumes sizeof(unsigned short) == 2. Do not use - * UNALIGNED_OK if your compiler uses a different size. - */ - if (*(ushf*)(match+best_len-1) != scan_end || - *(ushf*)match != scan_start) continue; - - /* It is not necessary to compare scan[2] and match[2] since they are - * always equal when the other bytes match, given that the hash keys - * are equal and that HASH_BITS >= 8. Compare 2 bytes at a time at - * strstart+3, +5, ... up to strstart+257. We check for insufficient - * lookahead only every 4th comparison; the 128th check will be made - * at strstart+257. If MAX_MATCH-2 is not a multiple of 8, it is - * necessary to put more guard bytes at the end of the window, or - * to check more often for insufficient lookahead. - */ - Assert(scan[2] == match[2], "scan[2]?"); - scan++, match++; - do { - } while (*(ushf*)(scan+=2) == *(ushf*)(match+=2) && - *(ushf*)(scan+=2) == *(ushf*)(match+=2) && - *(ushf*)(scan+=2) == *(ushf*)(match+=2) && - *(ushf*)(scan+=2) == *(ushf*)(match+=2) && - scan < strend); - /* The funny "do {}" generates better code on most compilers */ - - /* Here, scan <= window+strstart+257 */ - Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); - if (*scan == *match) scan++; - - len = (MAX_MATCH - 1) - (int)(strend-scan); - scan = strend - (MAX_MATCH-1); - -#else /* UNALIGNED_OK */ - - if (match[best_len] != scan_end || - match[best_len-1] != scan_end1 || - *match != *scan || - *++match != scan[1]) continue; - - /* The check at best_len-1 can be removed because it will be made - * again later. (This heuristic is not always a win.) - * It is not necessary to compare scan[2] and match[2] since they - * are always equal when the other bytes match, given that - * the hash keys are equal and that HASH_BITS >= 8. - */ - scan += 2, match++; - Assert(*scan == *match, "match[2]?"); - - /* We check for insufficient lookahead only every 8th comparison; - * the 256th check will be made at strstart+258. - */ - do { - } while (*++scan == *++match && *++scan == *++match && - *++scan == *++match && *++scan == *++match && - *++scan == *++match && *++scan == *++match && - *++scan == *++match && *++scan == *++match && - scan < strend); - - Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); - - len = MAX_MATCH - (int)(strend - scan); - scan = strend - MAX_MATCH; - -#endif /* UNALIGNED_OK */ - - if (len > best_len) { - s->match_start = cur_match; - best_len = len; - if (len >= nice_match) break; -#ifdef UNALIGNED_OK - scan_end = *(ushf*)(scan+best_len-1); -#else - scan_end1 = scan[best_len-1]; - scan_end = scan[best_len]; -#endif - } - } while ((cur_match = prev[cur_match & wmask]) > limit - && --chain_length != 0); - - if ((uInt)best_len <= s->lookahead) return (uInt)best_len; - return s->lookahead; -} -#endif /* ASMV */ - -#else /* FASTEST */ - -/* --------------------------------------------------------------------------- - * Optimized version for FASTEST only - */ -local uInt longest_match(s, cur_match) - deflate_state *s; - IPos cur_match; /* current match */ -{ - register Bytef *scan = s->window + s->strstart; /* current string */ - register Bytef *match; /* matched string */ - register int len; /* length of current match */ - register Bytef *strend = s->window + s->strstart + MAX_MATCH; - - /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. - * It is easy to get rid of this optimization if necessary. - */ - Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever"); - - Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead"); - - Assert(cur_match < s->strstart, "no future"); - - match = s->window + cur_match; - - /* Return failure if the match length is less than 2: - */ - if (match[0] != scan[0] || match[1] != scan[1]) return MIN_MATCH-1; - - /* The check at best_len-1 can be removed because it will be made - * again later. (This heuristic is not always a win.) - * It is not necessary to compare scan[2] and match[2] since they - * are always equal when the other bytes match, given that - * the hash keys are equal and that HASH_BITS >= 8. - */ - scan += 2, match += 2; - Assert(*scan == *match, "match[2]?"); - - /* We check for insufficient lookahead only every 8th comparison; - * the 256th check will be made at strstart+258. - */ - do { - } while (*++scan == *++match && *++scan == *++match && - *++scan == *++match && *++scan == *++match && - *++scan == *++match && *++scan == *++match && - *++scan == *++match && *++scan == *++match && - scan < strend); - - Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); - - len = MAX_MATCH - (int)(strend - scan); - - if (len < MIN_MATCH) return MIN_MATCH - 1; - - s->match_start = cur_match; - return (uInt)len <= s->lookahead ? (uInt)len : s->lookahead; -} - -#endif /* FASTEST */ - -#ifdef DEBUG -/* =========================================================================== - * Check that the match at match_start is indeed a match. - */ -local void check_match(s, start, match, length) - deflate_state *s; - IPos start, match; - int length; -{ - /* check that the match is indeed a match */ - if (zmemcmp(s->window + match, - s->window + start, length) != EQUAL) { - fprintf(stderr, " start %u, match %u, length %d\n", - start, match, length); - do { - fprintf(stderr, "%c%c", s->window[match++], s->window[start++]); - } while (--length != 0); - z_error("invalid match"); - } - if (z_verbose > 1) { - fprintf(stderr,"\\[%d,%d]", start-match, length); - do { putc(s->window[start++], stderr); } while (--length != 0); - } -} -#else -# define check_match(s, start, match, length) -#endif /* DEBUG */ - -/* =========================================================================== - * Fill the window when the lookahead becomes insufficient. - * Updates strstart and lookahead. - * - * IN assertion: lookahead < MIN_LOOKAHEAD - * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD - * At least one byte has been read, or avail_in == 0; reads are - * performed for at least two bytes (required for the zip translate_eol - * option -- not supported here). - */ -local void fill_window(s) - deflate_state *s; -{ - register unsigned n, m; - register Posf *p; - unsigned more; /* Amount of free space at the end of the window. */ - uInt wsize = s->w_size; - - Assert(s->lookahead < MIN_LOOKAHEAD, "already enough lookahead"); - - do { - more = (unsigned)(s->window_size -(ulg)s->lookahead -(ulg)s->strstart); - - /* Deal with !@#$% 64K limit: */ - if (sizeof(int) <= 2) { - if (more == 0 && s->strstart == 0 && s->lookahead == 0) { - more = wsize; - - } else if (more == (unsigned)(-1)) { - /* Very unlikely, but possible on 16 bit machine if - * strstart == 0 && lookahead == 1 (input done a byte at time) - */ - more--; - } - } - - /* If the window is almost full and there is insufficient lookahead, - * move the upper half to the lower one to make room in the upper half. - */ - if (s->strstart >= wsize+MAX_DIST(s)) { - - zmemcpy(s->window, s->window+wsize, (unsigned)wsize); - s->match_start -= wsize; - s->strstart -= wsize; /* we now have strstart >= MAX_DIST */ - s->block_start -= (long) wsize; - - /* Slide the hash table (could be avoided with 32 bit values - at the expense of memory usage). We slide even when level == 0 - to keep the hash table consistent if we switch back to level > 0 - later. (Using level 0 permanently is not an optimal usage of - zlib, so we don't care about this pathological case.) - */ - n = s->hash_size; - p = &s->head[n]; - do { - m = *--p; - *p = (Pos)(m >= wsize ? m-wsize : NIL); - } while (--n); - - n = wsize; -#ifndef FASTEST - p = &s->prev[n]; - do { - m = *--p; - *p = (Pos)(m >= wsize ? m-wsize : NIL); - /* If n is not on any hash chain, prev[n] is garbage but - * its value will never be used. - */ - } while (--n); -#endif - more += wsize; - } - if (s->strm->avail_in == 0) break; - - /* If there was no sliding: - * strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 && - * more == window_size - lookahead - strstart - * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1) - * => more >= window_size - 2*WSIZE + 2 - * In the BIG_MEM or MMAP case (not yet supported), - * window_size == input_size + MIN_LOOKAHEAD && - * strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD. - * Otherwise, window_size == 2*WSIZE so more >= 2. - * If there was sliding, more >= WSIZE. So in all cases, more >= 2. - */ - Assert(more >= 2, "more < 2"); - - n = read_buf(s->strm, s->window + s->strstart + s->lookahead, more); - s->lookahead += n; - - /* Initialize the hash value now that we have some input: */ - if (s->lookahead + s->insert >= MIN_MATCH) { - uInt str = s->strstart - s->insert; - s->ins_h = s->window[str]; - UPDATE_HASH(s, s->ins_h, s->window[str + 1]); -#if MIN_MATCH != 3 - Call UPDATE_HASH() MIN_MATCH-3 more times -#endif - while (s->insert) { - UPDATE_HASH(s, s->ins_h, s->window[str + MIN_MATCH-1]); -#ifndef FASTEST - s->prev[str & s->w_mask] = s->head[s->ins_h]; -#endif - s->head[s->ins_h] = (Pos)str; - str++; - s->insert--; - if (s->lookahead + s->insert < MIN_MATCH) - break; - } - } - /* If the whole input has less than MIN_MATCH bytes, ins_h is garbage, - * but this is not important since only literal bytes will be emitted. - */ - - } while (s->lookahead < MIN_LOOKAHEAD && s->strm->avail_in != 0); - - /* If the WIN_INIT bytes after the end of the current data have never been - * written, then zero those bytes in order to avoid memory check reports of - * the use of uninitialized (or uninitialised as Julian writes) bytes by - * the longest match routines. Update the high water mark for the next - * time through here. WIN_INIT is set to MAX_MATCH since the longest match - * routines allow scanning to strstart + MAX_MATCH, ignoring lookahead. - */ - if (s->high_water < s->window_size) { - ulg curr = s->strstart + (ulg)(s->lookahead); - ulg init; - - if (s->high_water < curr) { - /* Previous high water mark below current data -- zero WIN_INIT - * bytes or up to end of window, whichever is less. - */ - init = s->window_size - curr; - if (init > WIN_INIT) - init = WIN_INIT; - zmemzero(s->window + curr, (unsigned)init); - s->high_water = curr + init; - } - else if (s->high_water < (ulg)curr + WIN_INIT) { - /* High water mark at or above current data, but below current data - * plus WIN_INIT -- zero out to current data plus WIN_INIT, or up - * to end of window, whichever is less. - */ - init = (ulg)curr + WIN_INIT - s->high_water; - if (init > s->window_size - s->high_water) - init = s->window_size - s->high_water; - zmemzero(s->window + s->high_water, (unsigned)init); - s->high_water += init; - } - } - - Assert((ulg)s->strstart <= s->window_size - MIN_LOOKAHEAD, - "not enough room for search"); -} - -/* =========================================================================== - * Flush the current block, with given end-of-file flag. - * IN assertion: strstart is set to the end of the current match. - */ -#define FLUSH_BLOCK_ONLY(s, last) { \ - _tr_flush_block(s, (s->block_start >= 0L ? \ - (charf *)&s->window[(unsigned)s->block_start] : \ - (charf *)Z_NULL), \ - (ulg)((long)s->strstart - s->block_start), \ - (last)); \ - s->block_start = s->strstart; \ - flush_pending(s->strm); \ - Tracev((stderr,"[FLUSH]")); \ -} - -/* Same but force premature exit if necessary. */ -#define FLUSH_BLOCK(s, last) { \ - FLUSH_BLOCK_ONLY(s, last); \ - if (s->strm->avail_out == 0) return (last) ? finish_started : need_more; \ -} - -/* =========================================================================== - * Copy without compression as much as possible from the input stream, return - * the current block state. - * This function does not insert new strings in the dictionary since - * uncompressible data is probably not useful. This function is used - * only for the level=0 compression option. - * NOTE: this function should be optimized to avoid extra copying from - * window to pending_buf. - */ -local block_state deflate_stored(s, flush) - deflate_state *s; - int flush; -{ - /* Stored blocks are limited to 0xffff bytes, pending_buf is limited - * to pending_buf_size, and each stored block has a 5 byte header: - */ - ulg max_block_size = 0xffff; - ulg max_start; - - if (max_block_size > s->pending_buf_size - 5) { - max_block_size = s->pending_buf_size - 5; - } - - /* Copy as much as possible from input to output: */ - for (;;) { - /* Fill the window as much as possible: */ - if (s->lookahead <= 1) { - - Assert(s->strstart < s->w_size+MAX_DIST(s) || - s->block_start >= (long)s->w_size, "slide too late"); - - fill_window(s); - if (s->lookahead == 0 && flush == Z_NO_FLUSH) return need_more; - - if (s->lookahead == 0) break; /* flush the current block */ - } - Assert(s->block_start >= 0L, "block gone"); - - s->strstart += s->lookahead; - s->lookahead = 0; - - /* Emit a stored block if pending_buf will be full: */ - max_start = s->block_start + max_block_size; - if (s->strstart == 0 || (ulg)s->strstart >= max_start) { - /* strstart == 0 is possible when wraparound on 16-bit machine */ - s->lookahead = (uInt)(s->strstart - max_start); - s->strstart = (uInt)max_start; - FLUSH_BLOCK(s, 0); - } - /* Flush if we may have to slide, otherwise block_start may become - * negative and the data will be gone: - */ - if (s->strstart - (uInt)s->block_start >= MAX_DIST(s)) { - FLUSH_BLOCK(s, 0); - } - } - s->insert = 0; - if (flush == Z_FINISH) { - FLUSH_BLOCK(s, 1); - return finish_done; - } - if ((long)s->strstart > s->block_start) - FLUSH_BLOCK(s, 0); - return block_done; -} - -/* =========================================================================== - * Compress as much as possible from the input stream, return the current - * block state. - * This function does not perform lazy evaluation of matches and inserts - * new strings in the dictionary only for unmatched strings or for short - * matches. It is used only for the fast compression options. - */ -local block_state deflate_fast(s, flush) - deflate_state *s; - int flush; -{ - IPos hash_head; /* head of the hash chain */ - int bflush; /* set if current block must be flushed */ - - for (;;) { - /* Make sure that we always have enough lookahead, except - * at the end of the input file. We need MAX_MATCH bytes - * for the next match, plus MIN_MATCH bytes to insert the - * string following the next match. - */ - if (s->lookahead < MIN_LOOKAHEAD) { - fill_window(s); - if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) { - return need_more; - } - if (s->lookahead == 0) break; /* flush the current block */ - } - - /* Insert the string window[strstart .. strstart+2] in the - * dictionary, and set hash_head to the head of the hash chain: - */ - hash_head = NIL; - if (s->lookahead >= MIN_MATCH) { - INSERT_STRING(s, s->strstart, hash_head); - } - - /* Find the longest match, discarding those <= prev_length. - * At this point we have always match_length < MIN_MATCH - */ - if (hash_head != NIL && s->strstart - hash_head <= MAX_DIST(s)) { - /* To simplify the code, we prevent matches with the string - * of window index 0 (in particular we have to avoid a match - * of the string with itself at the start of the input file). - */ - s->match_length = longest_match (s, hash_head); - /* longest_match() sets match_start */ - } - if (s->match_length >= MIN_MATCH) { - check_match(s, s->strstart, s->match_start, s->match_length); - - _tr_tally_dist(s, s->strstart - s->match_start, - s->match_length - MIN_MATCH, bflush); - - s->lookahead -= s->match_length; - - /* Insert new strings in the hash table only if the match length - * is not too large. This saves time but degrades compression. - */ -#ifndef FASTEST - if (s->match_length <= s->max_insert_length && - s->lookahead >= MIN_MATCH) { - s->match_length--; /* string at strstart already in table */ - do { - s->strstart++; - INSERT_STRING(s, s->strstart, hash_head); - /* strstart never exceeds WSIZE-MAX_MATCH, so there are - * always MIN_MATCH bytes ahead. - */ - } while (--s->match_length != 0); - s->strstart++; - } else -#endif - { - s->strstart += s->match_length; - s->match_length = 0; - s->ins_h = s->window[s->strstart]; - UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]); -#if MIN_MATCH != 3 - Call UPDATE_HASH() MIN_MATCH-3 more times -#endif - /* If lookahead < MIN_MATCH, ins_h is garbage, but it does not - * matter since it will be recomputed at next deflate call. - */ - } - } else { - /* No match, output a literal byte */ - Tracevv((stderr,"%c", s->window[s->strstart])); - _tr_tally_lit (s, s->window[s->strstart], bflush); - s->lookahead--; - s->strstart++; - } - if (bflush) FLUSH_BLOCK(s, 0); - } - s->insert = s->strstart < MIN_MATCH-1 ? s->strstart : MIN_MATCH-1; - if (flush == Z_FINISH) { - FLUSH_BLOCK(s, 1); - return finish_done; - } - if (s->last_lit) - FLUSH_BLOCK(s, 0); - return block_done; -} - -#ifndef FASTEST -/* =========================================================================== - * Same as above, but achieves better compression. We use a lazy - * evaluation for matches: a match is finally adopted only if there is - * no better match at the next window position. - */ -local block_state deflate_slow(s, flush) - deflate_state *s; - int flush; -{ - IPos hash_head; /* head of hash chain */ - int bflush; /* set if current block must be flushed */ - - /* Process the input block. */ - for (;;) { - /* Make sure that we always have enough lookahead, except - * at the end of the input file. We need MAX_MATCH bytes - * for the next match, plus MIN_MATCH bytes to insert the - * string following the next match. - */ - if (s->lookahead < MIN_LOOKAHEAD) { - fill_window(s); - if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) { - return need_more; - } - if (s->lookahead == 0) break; /* flush the current block */ - } - - /* Insert the string window[strstart .. strstart+2] in the - * dictionary, and set hash_head to the head of the hash chain: - */ - hash_head = NIL; - if (s->lookahead >= MIN_MATCH) { - INSERT_STRING(s, s->strstart, hash_head); - } - - /* Find the longest match, discarding those <= prev_length. - */ - s->prev_length = s->match_length, s->prev_match = s->match_start; - s->match_length = MIN_MATCH-1; - - if (hash_head != NIL && s->prev_length < s->max_lazy_match && - s->strstart - hash_head <= MAX_DIST(s)) { - /* To simplify the code, we prevent matches with the string - * of window index 0 (in particular we have to avoid a match - * of the string with itself at the start of the input file). - */ - s->match_length = longest_match (s, hash_head); - /* longest_match() sets match_start */ - - if (s->match_length <= 5 && (s->strategy == Z_FILTERED -#if TOO_FAR <= 32767 - || (s->match_length == MIN_MATCH && - s->strstart - s->match_start > TOO_FAR) -#endif - )) { - - /* If prev_match is also MIN_MATCH, match_start is garbage - * but we will ignore the current match anyway. - */ - s->match_length = MIN_MATCH-1; - } - } - /* If there was a match at the previous step and the current - * match is not better, output the previous match: - */ - if (s->prev_length >= MIN_MATCH && s->match_length <= s->prev_length) { - uInt max_insert = s->strstart + s->lookahead - MIN_MATCH; - /* Do not insert strings in hash table beyond this. */ - - check_match(s, s->strstart-1, s->prev_match, s->prev_length); - - _tr_tally_dist(s, s->strstart -1 - s->prev_match, - s->prev_length - MIN_MATCH, bflush); - - /* Insert in hash table all strings up to the end of the match. - * strstart-1 and strstart are already inserted. If there is not - * enough lookahead, the last two strings are not inserted in - * the hash table. - */ - s->lookahead -= s->prev_length-1; - s->prev_length -= 2; - do { - if (++s->strstart <= max_insert) { - INSERT_STRING(s, s->strstart, hash_head); - } - } while (--s->prev_length != 0); - s->match_available = 0; - s->match_length = MIN_MATCH-1; - s->strstart++; - - if (bflush) FLUSH_BLOCK(s, 0); - - } else if (s->match_available) { - /* If there was no match at the previous position, output a - * single literal. If there was a match but the current match - * is longer, truncate the previous match to a single literal. - */ - Tracevv((stderr,"%c", s->window[s->strstart-1])); - _tr_tally_lit(s, s->window[s->strstart-1], bflush); - if (bflush) { - FLUSH_BLOCK_ONLY(s, 0); - } - s->strstart++; - s->lookahead--; - if (s->strm->avail_out == 0) return need_more; - } else { - /* There is no previous match to compare with, wait for - * the next step to decide. - */ - s->match_available = 1; - s->strstart++; - s->lookahead--; - } - } - Assert (flush != Z_NO_FLUSH, "no flush?"); - if (s->match_available) { - Tracevv((stderr,"%c", s->window[s->strstart-1])); - _tr_tally_lit(s, s->window[s->strstart-1], bflush); - s->match_available = 0; - } - s->insert = s->strstart < MIN_MATCH-1 ? s->strstart : MIN_MATCH-1; - if (flush == Z_FINISH) { - FLUSH_BLOCK(s, 1); - return finish_done; - } - if (s->last_lit) - FLUSH_BLOCK(s, 0); - return block_done; -} -#endif /* FASTEST */ - -/* =========================================================================== - * For Z_RLE, simply look for runs of bytes, generate matches only of distance - * one. Do not maintain a hash table. (It will be regenerated if this run of - * deflate switches away from Z_RLE.) - */ -local block_state deflate_rle(s, flush) - deflate_state *s; - int flush; -{ - int bflush; /* set if current block must be flushed */ - uInt prev; /* byte at distance one to match */ - Bytef *scan, *strend; /* scan goes up to strend for length of run */ - - for (;;) { - /* Make sure that we always have enough lookahead, except - * at the end of the input file. We need MAX_MATCH bytes - * for the longest run, plus one for the unrolled loop. - */ - if (s->lookahead <= MAX_MATCH) { - fill_window(s); - if (s->lookahead <= MAX_MATCH && flush == Z_NO_FLUSH) { - return need_more; - } - if (s->lookahead == 0) break; /* flush the current block */ - } - - /* See how many times the previous byte repeats */ - s->match_length = 0; - if (s->lookahead >= MIN_MATCH && s->strstart > 0) { - scan = s->window + s->strstart - 1; - prev = *scan; - if (prev == *++scan && prev == *++scan && prev == *++scan) { - strend = s->window + s->strstart + MAX_MATCH; - do { - } while (prev == *++scan && prev == *++scan && - prev == *++scan && prev == *++scan && - prev == *++scan && prev == *++scan && - prev == *++scan && prev == *++scan && - scan < strend); - s->match_length = MAX_MATCH - (int)(strend - scan); - if (s->match_length > s->lookahead) - s->match_length = s->lookahead; - } - Assert(scan <= s->window+(uInt)(s->window_size-1), "wild scan"); - } - - /* Emit match if have run of MIN_MATCH or longer, else emit literal */ - if (s->match_length >= MIN_MATCH) { - check_match(s, s->strstart, s->strstart - 1, s->match_length); - - _tr_tally_dist(s, 1, s->match_length - MIN_MATCH, bflush); - - s->lookahead -= s->match_length; - s->strstart += s->match_length; - s->match_length = 0; - } else { - /* No match, output a literal byte */ - Tracevv((stderr,"%c", s->window[s->strstart])); - _tr_tally_lit (s, s->window[s->strstart], bflush); - s->lookahead--; - s->strstart++; - } - if (bflush) FLUSH_BLOCK(s, 0); - } - s->insert = 0; - if (flush == Z_FINISH) { - FLUSH_BLOCK(s, 1); - return finish_done; - } - if (s->last_lit) - FLUSH_BLOCK(s, 0); - return block_done; -} - -/* =========================================================================== - * For Z_HUFFMAN_ONLY, do not look for matches. Do not maintain a hash table. - * (It will be regenerated if this run of deflate switches away from Huffman.) - */ -local block_state deflate_huff(s, flush) - deflate_state *s; - int flush; -{ - int bflush; /* set if current block must be flushed */ - - for (;;) { - /* Make sure that we have a literal to write. */ - if (s->lookahead == 0) { - fill_window(s); - if (s->lookahead == 0) { - if (flush == Z_NO_FLUSH) - return need_more; - break; /* flush the current block */ - } - } - - /* Output a literal byte */ - s->match_length = 0; - Tracevv((stderr,"%c", s->window[s->strstart])); - _tr_tally_lit (s, s->window[s->strstart], bflush); - s->lookahead--; - s->strstart++; - if (bflush) FLUSH_BLOCK(s, 0); - } - s->insert = 0; - if (flush == Z_FINISH) { - FLUSH_BLOCK(s, 1); - return finish_done; - } - if (s->last_lit) - FLUSH_BLOCK(s, 0); - return block_done; -} diff --git a/deps/zlib/deflate.h b/deps/zlib/deflate.h deleted file mode 100644 index a17c8365c..000000000 --- a/deps/zlib/deflate.h +++ /dev/null @@ -1,346 +0,0 @@ -/* deflate.h -- internal compression state - * Copyright (C) 1995-2012 Jean-loup Gailly - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* WARNING: this file should *not* be used by applications. It is - part of the implementation of the compression library and is - subject to change. Applications should only use zlib.h. - */ - -/* @(#) $Id$ */ - -#ifndef DEFLATE_H -#define DEFLATE_H - -#include "zutil.h" - -/* define NO_GZIP when compiling if you want to disable gzip header and - trailer creation by deflate(). NO_GZIP would be used to avoid linking in - the crc code when it is not needed. For shared libraries, gzip encoding - should be left enabled. */ -#ifndef NO_GZIP -# define GZIP -#endif - -/* =========================================================================== - * Internal compression state. - */ - -#define LENGTH_CODES 29 -/* number of length codes, not counting the special END_BLOCK code */ - -#define LITERALS 256 -/* number of literal bytes 0..255 */ - -#define L_CODES (LITERALS+1+LENGTH_CODES) -/* number of Literal or Length codes, including the END_BLOCK code */ - -#define D_CODES 30 -/* number of distance codes */ - -#define BL_CODES 19 -/* number of codes used to transfer the bit lengths */ - -#define HEAP_SIZE (2*L_CODES+1) -/* maximum heap size */ - -#define MAX_BITS 15 -/* All codes must not exceed MAX_BITS bits */ - -#define Buf_size 16 -/* size of bit buffer in bi_buf */ - -#define INIT_STATE 42 -#define EXTRA_STATE 69 -#define NAME_STATE 73 -#define COMMENT_STATE 91 -#define HCRC_STATE 103 -#define BUSY_STATE 113 -#define FINISH_STATE 666 -/* Stream status */ - - -/* Data structure describing a single value and its code string. */ -typedef struct ct_data_s { - union { - ush freq; /* frequency count */ - ush code; /* bit string */ - } fc; - union { - ush dad; /* father node in Huffman tree */ - ush len; /* length of bit string */ - } dl; -} FAR ct_data; - -#define Freq fc.freq -#define Code fc.code -#define Dad dl.dad -#define Len dl.len - -typedef struct static_tree_desc_s static_tree_desc; - -typedef struct tree_desc_s { - ct_data *dyn_tree; /* the dynamic tree */ - int max_code; /* largest code with non zero frequency */ - static_tree_desc *stat_desc; /* the corresponding static tree */ -} FAR tree_desc; - -typedef ush Pos; -typedef Pos FAR Posf; -typedef unsigned IPos; - -/* A Pos is an index in the character window. We use short instead of int to - * save space in the various tables. IPos is used only for parameter passing. - */ - -typedef struct internal_state { - z_streamp strm; /* pointer back to this zlib stream */ - int status; /* as the name implies */ - Bytef *pending_buf; /* output still pending */ - ulg pending_buf_size; /* size of pending_buf */ - Bytef *pending_out; /* next pending byte to output to the stream */ - uInt pending; /* nb of bytes in the pending buffer */ - int wrap; /* bit 0 true for zlib, bit 1 true for gzip */ - gz_headerp gzhead; /* gzip header information to write */ - uInt gzindex; /* where in extra, name, or comment */ - Byte method; /* can only be DEFLATED */ - int last_flush; /* value of flush param for previous deflate call */ - - /* used by deflate.c: */ - - uInt w_size; /* LZ77 window size (32K by default) */ - uInt w_bits; /* log2(w_size) (8..16) */ - uInt w_mask; /* w_size - 1 */ - - Bytef *window; - /* Sliding window. Input bytes are read into the second half of the window, - * and move to the first half later to keep a dictionary of at least wSize - * bytes. With this organization, matches are limited to a distance of - * wSize-MAX_MATCH bytes, but this ensures that IO is always - * performed with a length multiple of the block size. Also, it limits - * the window size to 64K, which is quite useful on MSDOS. - * To do: use the user input buffer as sliding window. - */ - - ulg window_size; - /* Actual size of window: 2*wSize, except when the user input buffer - * is directly used as sliding window. - */ - - Posf *prev; - /* Link to older string with same hash index. To limit the size of this - * array to 64K, this link is maintained only for the last 32K strings. - * An index in this array is thus a window index modulo 32K. - */ - - Posf *head; /* Heads of the hash chains or NIL. */ - - uInt ins_h; /* hash index of string to be inserted */ - uInt hash_size; /* number of elements in hash table */ - uInt hash_bits; /* log2(hash_size) */ - uInt hash_mask; /* hash_size-1 */ - - uInt hash_shift; - /* Number of bits by which ins_h must be shifted at each input - * step. It must be such that after MIN_MATCH steps, the oldest - * byte no longer takes part in the hash key, that is: - * hash_shift * MIN_MATCH >= hash_bits - */ - - long block_start; - /* Window position at the beginning of the current output block. Gets - * negative when the window is moved backwards. - */ - - uInt match_length; /* length of best match */ - IPos prev_match; /* previous match */ - int match_available; /* set if previous match exists */ - uInt strstart; /* start of string to insert */ - uInt match_start; /* start of matching string */ - uInt lookahead; /* number of valid bytes ahead in window */ - - uInt prev_length; - /* Length of the best match at previous step. Matches not greater than this - * are discarded. This is used in the lazy match evaluation. - */ - - uInt max_chain_length; - /* To speed up deflation, hash chains are never searched beyond this - * length. A higher limit improves compression ratio but degrades the - * speed. - */ - - uInt max_lazy_match; - /* Attempt to find a better match only when the current match is strictly - * smaller than this value. This mechanism is used only for compression - * levels >= 4. - */ -# define max_insert_length max_lazy_match - /* Insert new strings in the hash table only if the match length is not - * greater than this length. This saves time but degrades compression. - * max_insert_length is used only for compression levels <= 3. - */ - - int level; /* compression level (1..9) */ - int strategy; /* favor or force Huffman coding*/ - - uInt good_match; - /* Use a faster search when the previous match is longer than this */ - - int nice_match; /* Stop searching when current match exceeds this */ - - /* used by trees.c: */ - /* Didn't use ct_data typedef below to suppress compiler warning */ - struct ct_data_s dyn_ltree[HEAP_SIZE]; /* literal and length tree */ - struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */ - struct ct_data_s bl_tree[2*BL_CODES+1]; /* Huffman tree for bit lengths */ - - struct tree_desc_s l_desc; /* desc. for literal tree */ - struct tree_desc_s d_desc; /* desc. for distance tree */ - struct tree_desc_s bl_desc; /* desc. for bit length tree */ - - ush bl_count[MAX_BITS+1]; - /* number of codes at each bit length for an optimal tree */ - - int heap[2*L_CODES+1]; /* heap used to build the Huffman trees */ - int heap_len; /* number of elements in the heap */ - int heap_max; /* element of largest frequency */ - /* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used. - * The same heap array is used to build all trees. - */ - - uch depth[2*L_CODES+1]; - /* Depth of each subtree used as tie breaker for trees of equal frequency - */ - - uchf *l_buf; /* buffer for literals or lengths */ - - uInt lit_bufsize; - /* Size of match buffer for literals/lengths. There are 4 reasons for - * limiting lit_bufsize to 64K: - * - frequencies can be kept in 16 bit counters - * - if compression is not successful for the first block, all input - * data is still in the window so we can still emit a stored block even - * when input comes from standard input. (This can also be done for - * all blocks if lit_bufsize is not greater than 32K.) - * - if compression is not successful for a file smaller than 64K, we can - * even emit a stored file instead of a stored block (saving 5 bytes). - * This is applicable only for zip (not gzip or zlib). - * - creating new Huffman trees less frequently may not provide fast - * adaptation to changes in the input data statistics. (Take for - * example a binary file with poorly compressible code followed by - * a highly compressible string table.) Smaller buffer sizes give - * fast adaptation but have of course the overhead of transmitting - * trees more frequently. - * - I can't count above 4 - */ - - uInt last_lit; /* running index in l_buf */ - - ushf *d_buf; - /* Buffer for distances. To simplify the code, d_buf and l_buf have - * the same number of elements. To use different lengths, an extra flag - * array would be necessary. - */ - - ulg opt_len; /* bit length of current block with optimal trees */ - ulg static_len; /* bit length of current block with static trees */ - uInt matches; /* number of string matches in current block */ - uInt insert; /* bytes at end of window left to insert */ - -#ifdef DEBUG - ulg compressed_len; /* total bit length of compressed file mod 2^32 */ - ulg bits_sent; /* bit length of compressed data sent mod 2^32 */ -#endif - - ush bi_buf; - /* Output buffer. bits are inserted starting at the bottom (least - * significant bits). - */ - int bi_valid; - /* Number of valid bits in bi_buf. All bits above the last valid bit - * are always zero. - */ - - ulg high_water; - /* High water mark offset in window for initialized bytes -- bytes above - * this are set to zero in order to avoid memory check warnings when - * longest match routines access bytes past the input. This is then - * updated to the new high water mark. - */ - -} FAR deflate_state; - -/* Output a byte on the stream. - * IN assertion: there is enough room in pending_buf. - */ -#define put_byte(s, c) {s->pending_buf[s->pending++] = (c);} - - -#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1) -/* Minimum amount of lookahead, except at the end of the input file. - * See deflate.c for comments about the MIN_MATCH+1. - */ - -#define MAX_DIST(s) ((s)->w_size-MIN_LOOKAHEAD) -/* In order to simplify the code, particularly on 16 bit machines, match - * distances are limited to MAX_DIST instead of WSIZE. - */ - -#define WIN_INIT MAX_MATCH -/* Number of bytes after end of data in window to initialize in order to avoid - memory checker errors from longest match routines */ - - /* in trees.c */ -void ZLIB_INTERNAL _tr_init OF((deflate_state *s)); -int ZLIB_INTERNAL _tr_tally OF((deflate_state *s, unsigned dist, unsigned lc)); -void ZLIB_INTERNAL _tr_flush_block OF((deflate_state *s, charf *buf, - ulg stored_len, int last)); -void ZLIB_INTERNAL _tr_flush_bits OF((deflate_state *s)); -void ZLIB_INTERNAL _tr_align OF((deflate_state *s)); -void ZLIB_INTERNAL _tr_stored_block OF((deflate_state *s, charf *buf, - ulg stored_len, int last)); - -#define d_code(dist) \ - ((dist) < 256 ? _dist_code[dist] : _dist_code[256+((dist)>>7)]) -/* Mapping from a distance to a distance code. dist is the distance - 1 and - * must not have side effects. _dist_code[256] and _dist_code[257] are never - * used. - */ - -#ifndef DEBUG -/* Inline versions of _tr_tally for speed: */ - -#if defined(GEN_TREES_H) || !defined(STDC) - extern uch ZLIB_INTERNAL _length_code[]; - extern uch ZLIB_INTERNAL _dist_code[]; -#else - extern const uch ZLIB_INTERNAL _length_code[]; - extern const uch ZLIB_INTERNAL _dist_code[]; -#endif - -# define _tr_tally_lit(s, c, flush) \ - { uch cc = (uch)(c); \ - s->d_buf[s->last_lit] = 0; \ - s->l_buf[s->last_lit++] = cc; \ - s->dyn_ltree[cc].Freq++; \ - flush = (s->last_lit == s->lit_bufsize-1); \ - } -# define _tr_tally_dist(s, distance, length, flush) \ - { uch len = (uch)(length); \ - ush dist = (ush)(distance); \ - s->d_buf[s->last_lit] = dist; \ - s->l_buf[s->last_lit++] = len; \ - dist--; \ - s->dyn_ltree[_length_code[len]+LITERALS+1].Freq++; \ - s->dyn_dtree[d_code(dist)].Freq++; \ - flush = (s->last_lit == s->lit_bufsize-1); \ - } -#else -# define _tr_tally_lit(s, c, flush) flush = _tr_tally(s, 0, c) -# define _tr_tally_dist(s, distance, length, flush) \ - flush = _tr_tally(s, distance, length) -#endif - -#endif /* DEFLATE_H */ diff --git a/deps/zlib/infback.c b/deps/zlib/infback.c deleted file mode 100644 index f3833c2e4..000000000 --- a/deps/zlib/infback.c +++ /dev/null @@ -1,640 +0,0 @@ -/* infback.c -- inflate using a call-back interface - * Copyright (C) 1995-2011 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* - This code is largely copied from inflate.c. Normally either infback.o or - inflate.o would be linked into an application--not both. The interface - with inffast.c is retained so that optimized assembler-coded versions of - inflate_fast() can be used with either inflate.c or infback.c. - */ - -#include "zutil.h" -#include "inftrees.h" -#include "inflate.h" -#include "inffast.h" - -/* function prototypes */ -local void fixedtables OF((struct inflate_state FAR *state)); - -/* - strm provides memory allocation functions in zalloc and zfree, or - Z_NULL to use the library memory allocation functions. - - windowBits is in the range 8..15, and window is a user-supplied - window and output buffer that is 2**windowBits bytes. - */ -int ZEXPORT inflateBackInit_(strm, windowBits, window, version, stream_size) -z_streamp strm; -int windowBits; -unsigned char FAR *window; -const char *version; -int stream_size; -{ - struct inflate_state FAR *state; - - if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || - stream_size != (int)(sizeof(z_stream))) - return Z_VERSION_ERROR; - if (strm == Z_NULL || window == Z_NULL || - windowBits < 8 || windowBits > 15) - return Z_STREAM_ERROR; - strm->msg = Z_NULL; /* in case we return an error */ - if (strm->zalloc == (alloc_func)0) { -#ifdef Z_SOLO - return Z_STREAM_ERROR; -#else - strm->zalloc = zcalloc; - strm->opaque = (voidpf)0; -#endif - } - if (strm->zfree == (free_func)0) -#ifdef Z_SOLO - return Z_STREAM_ERROR; -#else - strm->zfree = zcfree; -#endif - state = (struct inflate_state FAR *)ZALLOC(strm, 1, - sizeof(struct inflate_state)); - if (state == Z_NULL) return Z_MEM_ERROR; - Tracev((stderr, "inflate: allocated\n")); - strm->state = (struct internal_state FAR *)state; - state->dmax = 32768U; - state->wbits = windowBits; - state->wsize = 1U << windowBits; - state->window = window; - state->wnext = 0; - state->whave = 0; - return Z_OK; -} - -/* - Return state with length and distance decoding tables and index sizes set to - fixed code decoding. Normally this returns fixed tables from inffixed.h. - If BUILDFIXED is defined, then instead this routine builds the tables the - first time it's called, and returns those tables the first time and - thereafter. This reduces the size of the code by about 2K bytes, in - exchange for a little execution time. However, BUILDFIXED should not be - used for threaded applications, since the rewriting of the tables and virgin - may not be thread-safe. - */ -local void fixedtables(state) -struct inflate_state FAR *state; -{ -#ifdef BUILDFIXED - static int virgin = 1; - static code *lenfix, *distfix; - static code fixed[544]; - - /* build fixed huffman tables if first call (may not be thread safe) */ - if (virgin) { - unsigned sym, bits; - static code *next; - - /* literal/length table */ - sym = 0; - while (sym < 144) state->lens[sym++] = 8; - while (sym < 256) state->lens[sym++] = 9; - while (sym < 280) state->lens[sym++] = 7; - while (sym < 288) state->lens[sym++] = 8; - next = fixed; - lenfix = next; - bits = 9; - inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work); - - /* distance table */ - sym = 0; - while (sym < 32) state->lens[sym++] = 5; - distfix = next; - bits = 5; - inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work); - - /* do this just once */ - virgin = 0; - } -#else /* !BUILDFIXED */ -# include "inffixed.h" -#endif /* BUILDFIXED */ - state->lencode = lenfix; - state->lenbits = 9; - state->distcode = distfix; - state->distbits = 5; -} - -/* Macros for inflateBack(): */ - -/* Load returned state from inflate_fast() */ -#define LOAD() \ - do { \ - put = strm->next_out; \ - left = strm->avail_out; \ - next = strm->next_in; \ - have = strm->avail_in; \ - hold = state->hold; \ - bits = state->bits; \ - } while (0) - -/* Set state from registers for inflate_fast() */ -#define RESTORE() \ - do { \ - strm->next_out = put; \ - strm->avail_out = left; \ - strm->next_in = next; \ - strm->avail_in = have; \ - state->hold = hold; \ - state->bits = bits; \ - } while (0) - -/* Clear the input bit accumulator */ -#define INITBITS() \ - do { \ - hold = 0; \ - bits = 0; \ - } while (0) - -/* Assure that some input is available. If input is requested, but denied, - then return a Z_BUF_ERROR from inflateBack(). */ -#define PULL() \ - do { \ - if (have == 0) { \ - have = in(in_desc, &next); \ - if (have == 0) { \ - next = Z_NULL; \ - ret = Z_BUF_ERROR; \ - goto inf_leave; \ - } \ - } \ - } while (0) - -/* Get a byte of input into the bit accumulator, or return from inflateBack() - with an error if there is no input available. */ -#define PULLBYTE() \ - do { \ - PULL(); \ - have--; \ - hold += (unsigned long)(*next++) << bits; \ - bits += 8; \ - } while (0) - -/* Assure that there are at least n bits in the bit accumulator. If there is - not enough available input to do that, then return from inflateBack() with - an error. */ -#define NEEDBITS(n) \ - do { \ - while (bits < (unsigned)(n)) \ - PULLBYTE(); \ - } while (0) - -/* Return the low n bits of the bit accumulator (n < 16) */ -#define BITS(n) \ - ((unsigned)hold & ((1U << (n)) - 1)) - -/* Remove n bits from the bit accumulator */ -#define DROPBITS(n) \ - do { \ - hold >>= (n); \ - bits -= (unsigned)(n); \ - } while (0) - -/* Remove zero to seven bits as needed to go to a byte boundary */ -#define BYTEBITS() \ - do { \ - hold >>= bits & 7; \ - bits -= bits & 7; \ - } while (0) - -/* Assure that some output space is available, by writing out the window - if it's full. If the write fails, return from inflateBack() with a - Z_BUF_ERROR. */ -#define ROOM() \ - do { \ - if (left == 0) { \ - put = state->window; \ - left = state->wsize; \ - state->whave = left; \ - if (out(out_desc, put, left)) { \ - ret = Z_BUF_ERROR; \ - goto inf_leave; \ - } \ - } \ - } while (0) - -/* - strm provides the memory allocation functions and window buffer on input, - and provides information on the unused input on return. For Z_DATA_ERROR - returns, strm will also provide an error message. - - in() and out() are the call-back input and output functions. When - inflateBack() needs more input, it calls in(). When inflateBack() has - filled the window with output, or when it completes with data in the - window, it calls out() to write out the data. The application must not - change the provided input until in() is called again or inflateBack() - returns. The application must not change the window/output buffer until - inflateBack() returns. - - in() and out() are called with a descriptor parameter provided in the - inflateBack() call. This parameter can be a structure that provides the - information required to do the read or write, as well as accumulated - information on the input and output such as totals and check values. - - in() should return zero on failure. out() should return non-zero on - failure. If either in() or out() fails, than inflateBack() returns a - Z_BUF_ERROR. strm->next_in can be checked for Z_NULL to see whether it - was in() or out() that caused in the error. Otherwise, inflateBack() - returns Z_STREAM_END on success, Z_DATA_ERROR for an deflate format - error, or Z_MEM_ERROR if it could not allocate memory for the state. - inflateBack() can also return Z_STREAM_ERROR if the input parameters - are not correct, i.e. strm is Z_NULL or the state was not initialized. - */ -int ZEXPORT inflateBack(strm, in, in_desc, out, out_desc) -z_streamp strm; -in_func in; -void FAR *in_desc; -out_func out; -void FAR *out_desc; -{ - struct inflate_state FAR *state; - z_const unsigned char FAR *next; /* next input */ - unsigned char FAR *put; /* next output */ - unsigned have, left; /* available input and output */ - unsigned long hold; /* bit buffer */ - unsigned bits; /* bits in bit buffer */ - unsigned copy; /* number of stored or match bytes to copy */ - unsigned char FAR *from; /* where to copy match bytes from */ - code here; /* current decoding table entry */ - code last; /* parent table entry */ - unsigned len; /* length to copy for repeats, bits to drop */ - int ret; /* return code */ - static const unsigned short order[19] = /* permutation of code lengths */ - {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; - - /* Check that the strm exists and that the state was initialized */ - if (strm == Z_NULL || strm->state == Z_NULL) - return Z_STREAM_ERROR; - state = (struct inflate_state FAR *)strm->state; - - /* Reset the state */ - strm->msg = Z_NULL; - state->mode = TYPE; - state->last = 0; - state->whave = 0; - next = strm->next_in; - have = next != Z_NULL ? strm->avail_in : 0; - hold = 0; - bits = 0; - put = state->window; - left = state->wsize; - - /* Inflate until end of block marked as last */ - for (;;) - switch (state->mode) { - case TYPE: - /* determine and dispatch block type */ - if (state->last) { - BYTEBITS(); - state->mode = DONE; - break; - } - NEEDBITS(3); - state->last = BITS(1); - DROPBITS(1); - switch (BITS(2)) { - case 0: /* stored block */ - Tracev((stderr, "inflate: stored block%s\n", - state->last ? " (last)" : "")); - state->mode = STORED; - break; - case 1: /* fixed block */ - fixedtables(state); - Tracev((stderr, "inflate: fixed codes block%s\n", - state->last ? " (last)" : "")); - state->mode = LEN; /* decode codes */ - break; - case 2: /* dynamic block */ - Tracev((stderr, "inflate: dynamic codes block%s\n", - state->last ? " (last)" : "")); - state->mode = TABLE; - break; - case 3: - strm->msg = (char *)"invalid block type"; - state->mode = BAD; - } - DROPBITS(2); - break; - - case STORED: - /* get and verify stored block length */ - BYTEBITS(); /* go to byte boundary */ - NEEDBITS(32); - if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) { - strm->msg = (char *)"invalid stored block lengths"; - state->mode = BAD; - break; - } - state->length = (unsigned)hold & 0xffff; - Tracev((stderr, "inflate: stored length %u\n", - state->length)); - INITBITS(); - - /* copy stored block from input to output */ - while (state->length != 0) { - copy = state->length; - PULL(); - ROOM(); - if (copy > have) copy = have; - if (copy > left) copy = left; - zmemcpy(put, next, copy); - have -= copy; - next += copy; - left -= copy; - put += copy; - state->length -= copy; - } - Tracev((stderr, "inflate: stored end\n")); - state->mode = TYPE; - break; - - case TABLE: - /* get dynamic table entries descriptor */ - NEEDBITS(14); - state->nlen = BITS(5) + 257; - DROPBITS(5); - state->ndist = BITS(5) + 1; - DROPBITS(5); - state->ncode = BITS(4) + 4; - DROPBITS(4); -#ifndef PKZIP_BUG_WORKAROUND - if (state->nlen > 286 || state->ndist > 30) { - strm->msg = (char *)"too many length or distance symbols"; - state->mode = BAD; - break; - } -#endif - Tracev((stderr, "inflate: table sizes ok\n")); - - /* get code length code lengths (not a typo) */ - state->have = 0; - while (state->have < state->ncode) { - NEEDBITS(3); - state->lens[order[state->have++]] = (unsigned short)BITS(3); - DROPBITS(3); - } - while (state->have < 19) - state->lens[order[state->have++]] = 0; - state->next = state->codes; - state->lencode = (code const FAR *)(state->next); - state->lenbits = 7; - ret = inflate_table(CODES, state->lens, 19, &(state->next), - &(state->lenbits), state->work); - if (ret) { - strm->msg = (char *)"invalid code lengths set"; - state->mode = BAD; - break; - } - Tracev((stderr, "inflate: code lengths ok\n")); - - /* get length and distance code code lengths */ - state->have = 0; - while (state->have < state->nlen + state->ndist) { - for (;;) { - here = state->lencode[BITS(state->lenbits)]; - if ((unsigned)(here.bits) <= bits) break; - PULLBYTE(); - } - if (here.val < 16) { - DROPBITS(here.bits); - state->lens[state->have++] = here.val; - } - else { - if (here.val == 16) { - NEEDBITS(here.bits + 2); - DROPBITS(here.bits); - if (state->have == 0) { - strm->msg = (char *)"invalid bit length repeat"; - state->mode = BAD; - break; - } - len = (unsigned)(state->lens[state->have - 1]); - copy = 3 + BITS(2); - DROPBITS(2); - } - else if (here.val == 17) { - NEEDBITS(here.bits + 3); - DROPBITS(here.bits); - len = 0; - copy = 3 + BITS(3); - DROPBITS(3); - } - else { - NEEDBITS(here.bits + 7); - DROPBITS(here.bits); - len = 0; - copy = 11 + BITS(7); - DROPBITS(7); - } - if (state->have + copy > state->nlen + state->ndist) { - strm->msg = (char *)"invalid bit length repeat"; - state->mode = BAD; - break; - } - while (copy--) - state->lens[state->have++] = (unsigned short)len; - } - } - - /* handle error breaks in while */ - if (state->mode == BAD) break; - - /* check for end-of-block code (better have one) */ - if (state->lens[256] == 0) { - strm->msg = (char *)"invalid code -- missing end-of-block"; - state->mode = BAD; - break; - } - - /* build code tables -- note: do not change the lenbits or distbits - values here (9 and 6) without reading the comments in inftrees.h - concerning the ENOUGH constants, which depend on those values */ - state->next = state->codes; - state->lencode = (code const FAR *)(state->next); - state->lenbits = 9; - ret = inflate_table(LENS, state->lens, state->nlen, &(state->next), - &(state->lenbits), state->work); - if (ret) { - strm->msg = (char *)"invalid literal/lengths set"; - state->mode = BAD; - break; - } - state->distcode = (code const FAR *)(state->next); - state->distbits = 6; - ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist, - &(state->next), &(state->distbits), state->work); - if (ret) { - strm->msg = (char *)"invalid distances set"; - state->mode = BAD; - break; - } - Tracev((stderr, "inflate: codes ok\n")); - state->mode = LEN; - - case LEN: - /* use inflate_fast() if we have enough input and output */ - if (have >= 6 && left >= 258) { - RESTORE(); - if (state->whave < state->wsize) - state->whave = state->wsize - left; - inflate_fast(strm, state->wsize); - LOAD(); - break; - } - - /* get a literal, length, or end-of-block code */ - for (;;) { - here = state->lencode[BITS(state->lenbits)]; - if ((unsigned)(here.bits) <= bits) break; - PULLBYTE(); - } - if (here.op && (here.op & 0xf0) == 0) { - last = here; - for (;;) { - here = state->lencode[last.val + - (BITS(last.bits + last.op) >> last.bits)]; - if ((unsigned)(last.bits + here.bits) <= bits) break; - PULLBYTE(); - } - DROPBITS(last.bits); - } - DROPBITS(here.bits); - state->length = (unsigned)here.val; - - /* process literal */ - if (here.op == 0) { - Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ? - "inflate: literal '%c'\n" : - "inflate: literal 0x%02x\n", here.val)); - ROOM(); - *put++ = (unsigned char)(state->length); - left--; - state->mode = LEN; - break; - } - - /* process end of block */ - if (here.op & 32) { - Tracevv((stderr, "inflate: end of block\n")); - state->mode = TYPE; - break; - } - - /* invalid code */ - if (here.op & 64) { - strm->msg = (char *)"invalid literal/length code"; - state->mode = BAD; - break; - } - - /* length code -- get extra bits, if any */ - state->extra = (unsigned)(here.op) & 15; - if (state->extra != 0) { - NEEDBITS(state->extra); - state->length += BITS(state->extra); - DROPBITS(state->extra); - } - Tracevv((stderr, "inflate: length %u\n", state->length)); - - /* get distance code */ - for (;;) { - here = state->distcode[BITS(state->distbits)]; - if ((unsigned)(here.bits) <= bits) break; - PULLBYTE(); - } - if ((here.op & 0xf0) == 0) { - last = here; - for (;;) { - here = state->distcode[last.val + - (BITS(last.bits + last.op) >> last.bits)]; - if ((unsigned)(last.bits + here.bits) <= bits) break; - PULLBYTE(); - } - DROPBITS(last.bits); - } - DROPBITS(here.bits); - if (here.op & 64) { - strm->msg = (char *)"invalid distance code"; - state->mode = BAD; - break; - } - state->offset = (unsigned)here.val; - - /* get distance extra bits, if any */ - state->extra = (unsigned)(here.op) & 15; - if (state->extra != 0) { - NEEDBITS(state->extra); - state->offset += BITS(state->extra); - DROPBITS(state->extra); - } - if (state->offset > state->wsize - (state->whave < state->wsize ? - left : 0)) { - strm->msg = (char *)"invalid distance too far back"; - state->mode = BAD; - break; - } - Tracevv((stderr, "inflate: distance %u\n", state->offset)); - - /* copy match from window to output */ - do { - ROOM(); - copy = state->wsize - state->offset; - if (copy < left) { - from = put + copy; - copy = left - copy; - } - else { - from = put - state->offset; - copy = left; - } - if (copy > state->length) copy = state->length; - state->length -= copy; - left -= copy; - do { - *put++ = *from++; - } while (--copy); - } while (state->length != 0); - break; - - case DONE: - /* inflate stream terminated properly -- write leftover output */ - ret = Z_STREAM_END; - if (left < state->wsize) { - if (out(out_desc, state->window, state->wsize - left)) - ret = Z_BUF_ERROR; - } - goto inf_leave; - - case BAD: - ret = Z_DATA_ERROR; - goto inf_leave; - - default: /* can't happen, but makes compilers happy */ - ret = Z_STREAM_ERROR; - goto inf_leave; - } - - /* Return unused input */ - inf_leave: - strm->next_in = next; - strm->avail_in = have; - return ret; -} - -int ZEXPORT inflateBackEnd(strm) -z_streamp strm; -{ - if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0) - return Z_STREAM_ERROR; - ZFREE(strm, strm->state); - strm->state = Z_NULL; - Tracev((stderr, "inflate: end\n")); - return Z_OK; -} diff --git a/deps/zlib/inffast.c b/deps/zlib/inffast.c deleted file mode 100644 index bda59ceb6..000000000 --- a/deps/zlib/inffast.c +++ /dev/null @@ -1,340 +0,0 @@ -/* inffast.c -- fast decoding - * Copyright (C) 1995-2008, 2010, 2013 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -#include "zutil.h" -#include "inftrees.h" -#include "inflate.h" -#include "inffast.h" - -#ifndef ASMINF - -/* Allow machine dependent optimization for post-increment or pre-increment. - Based on testing to date, - Pre-increment preferred for: - - PowerPC G3 (Adler) - - MIPS R5000 (Randers-Pehrson) - Post-increment preferred for: - - none - No measurable difference: - - Pentium III (Anderson) - - M68060 (Nikl) - */ -#ifdef POSTINC -# define OFF 0 -# define PUP(a) *(a)++ -#else -# define OFF 1 -# define PUP(a) *++(a) -#endif - -/* - Decode literal, length, and distance codes and write out the resulting - literal and match bytes until either not enough input or output is - available, an end-of-block is encountered, or a data error is encountered. - When large enough input and output buffers are supplied to inflate(), for - example, a 16K input buffer and a 64K output buffer, more than 95% of the - inflate execution time is spent in this routine. - - Entry assumptions: - - state->mode == LEN - strm->avail_in >= 6 - strm->avail_out >= 258 - start >= strm->avail_out - state->bits < 8 - - On return, state->mode is one of: - - LEN -- ran out of enough output space or enough available input - TYPE -- reached end of block code, inflate() to interpret next block - BAD -- error in block data - - Notes: - - - The maximum input bits used by a length/distance pair is 15 bits for the - length code, 5 bits for the length extra, 15 bits for the distance code, - and 13 bits for the distance extra. This totals 48 bits, or six bytes. - Therefore if strm->avail_in >= 6, then there is enough input to avoid - checking for available input while decoding. - - - The maximum bytes that a single length/distance pair can output is 258 - bytes, which is the maximum length that can be coded. inflate_fast() - requires strm->avail_out >= 258 for each loop to avoid checking for - output space. - */ -void ZLIB_INTERNAL inflate_fast(strm, start) -z_streamp strm; -unsigned start; /* inflate()'s starting value for strm->avail_out */ -{ - struct inflate_state FAR *state; - z_const unsigned char FAR *in; /* local strm->next_in */ - z_const unsigned char FAR *last; /* have enough input while in < last */ - unsigned char FAR *out; /* local strm->next_out */ - unsigned char FAR *beg; /* inflate()'s initial strm->next_out */ - unsigned char FAR *end; /* while out < end, enough space available */ -#ifdef INFLATE_STRICT - unsigned dmax; /* maximum distance from zlib header */ -#endif - unsigned wsize; /* window size or zero if not using window */ - unsigned whave; /* valid bytes in the window */ - unsigned wnext; /* window write index */ - unsigned char FAR *window; /* allocated sliding window, if wsize != 0 */ - unsigned long hold; /* local strm->hold */ - unsigned bits; /* local strm->bits */ - code const FAR *lcode; /* local strm->lencode */ - code const FAR *dcode; /* local strm->distcode */ - unsigned lmask; /* mask for first level of length codes */ - unsigned dmask; /* mask for first level of distance codes */ - code here; /* retrieved table entry */ - unsigned op; /* code bits, operation, extra bits, or */ - /* window position, window bytes to copy */ - unsigned len; /* match length, unused bytes */ - unsigned dist; /* match distance */ - unsigned char FAR *from; /* where to copy match from */ - - /* copy state to local variables */ - state = (struct inflate_state FAR *)strm->state; - in = strm->next_in - OFF; - last = in + (strm->avail_in - 5); - out = strm->next_out - OFF; - beg = out - (start - strm->avail_out); - end = out + (strm->avail_out - 257); -#ifdef INFLATE_STRICT - dmax = state->dmax; -#endif - wsize = state->wsize; - whave = state->whave; - wnext = state->wnext; - window = state->window; - hold = state->hold; - bits = state->bits; - lcode = state->lencode; - dcode = state->distcode; - lmask = (1U << state->lenbits) - 1; - dmask = (1U << state->distbits) - 1; - - /* decode literals and length/distances until end-of-block or not enough - input data or output space */ - do { - if (bits < 15) { - hold += (unsigned long)(PUP(in)) << bits; - bits += 8; - hold += (unsigned long)(PUP(in)) << bits; - bits += 8; - } - here = lcode[hold & lmask]; - dolen: - op = (unsigned)(here.bits); - hold >>= op; - bits -= op; - op = (unsigned)(here.op); - if (op == 0) { /* literal */ - Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ? - "inflate: literal '%c'\n" : - "inflate: literal 0x%02x\n", here.val)); - PUP(out) = (unsigned char)(here.val); - } - else if (op & 16) { /* length base */ - len = (unsigned)(here.val); - op &= 15; /* number of extra bits */ - if (op) { - if (bits < op) { - hold += (unsigned long)(PUP(in)) << bits; - bits += 8; - } - len += (unsigned)hold & ((1U << op) - 1); - hold >>= op; - bits -= op; - } - Tracevv((stderr, "inflate: length %u\n", len)); - if (bits < 15) { - hold += (unsigned long)(PUP(in)) << bits; - bits += 8; - hold += (unsigned long)(PUP(in)) << bits; - bits += 8; - } - here = dcode[hold & dmask]; - dodist: - op = (unsigned)(here.bits); - hold >>= op; - bits -= op; - op = (unsigned)(here.op); - if (op & 16) { /* distance base */ - dist = (unsigned)(here.val); - op &= 15; /* number of extra bits */ - if (bits < op) { - hold += (unsigned long)(PUP(in)) << bits; - bits += 8; - if (bits < op) { - hold += (unsigned long)(PUP(in)) << bits; - bits += 8; - } - } - dist += (unsigned)hold & ((1U << op) - 1); -#ifdef INFLATE_STRICT - if (dist > dmax) { - strm->msg = (char *)"invalid distance too far back"; - state->mode = BAD; - break; - } -#endif - hold >>= op; - bits -= op; - Tracevv((stderr, "inflate: distance %u\n", dist)); - op = (unsigned)(out - beg); /* max distance in output */ - if (dist > op) { /* see if copy from window */ - op = dist - op; /* distance back in window */ - if (op > whave) { - if (state->sane) { - strm->msg = - (char *)"invalid distance too far back"; - state->mode = BAD; - break; - } -#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR - if (len <= op - whave) { - do { - PUP(out) = 0; - } while (--len); - continue; - } - len -= op - whave; - do { - PUP(out) = 0; - } while (--op > whave); - if (op == 0) { - from = out - dist; - do { - PUP(out) = PUP(from); - } while (--len); - continue; - } -#endif - } - from = window - OFF; - if (wnext == 0) { /* very common case */ - from += wsize - op; - if (op < len) { /* some from window */ - len -= op; - do { - PUP(out) = PUP(from); - } while (--op); - from = out - dist; /* rest from output */ - } - } - else if (wnext < op) { /* wrap around window */ - from += wsize + wnext - op; - op -= wnext; - if (op < len) { /* some from end of window */ - len -= op; - do { - PUP(out) = PUP(from); - } while (--op); - from = window - OFF; - if (wnext < len) { /* some from start of window */ - op = wnext; - len -= op; - do { - PUP(out) = PUP(from); - } while (--op); - from = out - dist; /* rest from output */ - } - } - } - else { /* contiguous in window */ - from += wnext - op; - if (op < len) { /* some from window */ - len -= op; - do { - PUP(out) = PUP(from); - } while (--op); - from = out - dist; /* rest from output */ - } - } - while (len > 2) { - PUP(out) = PUP(from); - PUP(out) = PUP(from); - PUP(out) = PUP(from); - len -= 3; - } - if (len) { - PUP(out) = PUP(from); - if (len > 1) - PUP(out) = PUP(from); - } - } - else { - from = out - dist; /* copy direct from output */ - do { /* minimum length is three */ - PUP(out) = PUP(from); - PUP(out) = PUP(from); - PUP(out) = PUP(from); - len -= 3; - } while (len > 2); - if (len) { - PUP(out) = PUP(from); - if (len > 1) - PUP(out) = PUP(from); - } - } - } - else if ((op & 64) == 0) { /* 2nd level distance code */ - here = dcode[here.val + (hold & ((1U << op) - 1))]; - goto dodist; - } - else { - strm->msg = (char *)"invalid distance code"; - state->mode = BAD; - break; - } - } - else if ((op & 64) == 0) { /* 2nd level length code */ - here = lcode[here.val + (hold & ((1U << op) - 1))]; - goto dolen; - } - else if (op & 32) { /* end-of-block */ - Tracevv((stderr, "inflate: end of block\n")); - state->mode = TYPE; - break; - } - else { - strm->msg = (char *)"invalid literal/length code"; - state->mode = BAD; - break; - } - } while (in < last && out < end); - - /* return unused bytes (on entry, bits < 8, so in won't go too far back) */ - len = bits >> 3; - in -= len; - bits -= len << 3; - hold &= (1U << bits) - 1; - - /* update state and return */ - strm->next_in = in + OFF; - strm->next_out = out + OFF; - strm->avail_in = (unsigned)(in < last ? 5 + (last - in) : 5 - (in - last)); - strm->avail_out = (unsigned)(out < end ? - 257 + (end - out) : 257 - (out - end)); - state->hold = hold; - state->bits = bits; - return; -} - -/* - inflate_fast() speedups that turned out slower (on a PowerPC G3 750CXe): - - Using bit fields for code structure - - Different op definition to avoid & for extra bits (do & for table bits) - - Three separate decoding do-loops for direct, window, and wnext == 0 - - Special case for distance > 1 copies to do overlapped load and store copy - - Explicit branch predictions (based on measured branch probabilities) - - Deferring match copy and interspersed it with decoding subsequent codes - - Swapping literal/length else - - Swapping window/direct else - - Larger unrolled copy loops (three is about right) - - Moving len -= 3 statement into middle of loop - */ - -#endif /* !ASMINF */ diff --git a/deps/zlib/inffast.h b/deps/zlib/inffast.h deleted file mode 100644 index e5c1aa4ca..000000000 --- a/deps/zlib/inffast.h +++ /dev/null @@ -1,11 +0,0 @@ -/* inffast.h -- header to use inffast.c - * Copyright (C) 1995-2003, 2010 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* WARNING: this file should *not* be used by applications. It is - part of the implementation of the compression library and is - subject to change. Applications should only use zlib.h. - */ - -void ZLIB_INTERNAL inflate_fast OF((z_streamp strm, unsigned start)); diff --git a/deps/zlib/inffixed.h b/deps/zlib/inffixed.h deleted file mode 100644 index d62832776..000000000 --- a/deps/zlib/inffixed.h +++ /dev/null @@ -1,94 +0,0 @@ - /* inffixed.h -- table for decoding fixed codes - * Generated automatically by makefixed(). - */ - - /* WARNING: this file should *not* be used by applications. - It is part of the implementation of this library and is - subject to change. Applications should only use zlib.h. - */ - - static const code lenfix[512] = { - {96,7,0},{0,8,80},{0,8,16},{20,8,115},{18,7,31},{0,8,112},{0,8,48}, - {0,9,192},{16,7,10},{0,8,96},{0,8,32},{0,9,160},{0,8,0},{0,8,128}, - {0,8,64},{0,9,224},{16,7,6},{0,8,88},{0,8,24},{0,9,144},{19,7,59}, - {0,8,120},{0,8,56},{0,9,208},{17,7,17},{0,8,104},{0,8,40},{0,9,176}, - {0,8,8},{0,8,136},{0,8,72},{0,9,240},{16,7,4},{0,8,84},{0,8,20}, - {21,8,227},{19,7,43},{0,8,116},{0,8,52},{0,9,200},{17,7,13},{0,8,100}, - {0,8,36},{0,9,168},{0,8,4},{0,8,132},{0,8,68},{0,9,232},{16,7,8}, - {0,8,92},{0,8,28},{0,9,152},{20,7,83},{0,8,124},{0,8,60},{0,9,216}, - {18,7,23},{0,8,108},{0,8,44},{0,9,184},{0,8,12},{0,8,140},{0,8,76}, - {0,9,248},{16,7,3},{0,8,82},{0,8,18},{21,8,163},{19,7,35},{0,8,114}, - {0,8,50},{0,9,196},{17,7,11},{0,8,98},{0,8,34},{0,9,164},{0,8,2}, - {0,8,130},{0,8,66},{0,9,228},{16,7,7},{0,8,90},{0,8,26},{0,9,148}, - {20,7,67},{0,8,122},{0,8,58},{0,9,212},{18,7,19},{0,8,106},{0,8,42}, - {0,9,180},{0,8,10},{0,8,138},{0,8,74},{0,9,244},{16,7,5},{0,8,86}, - {0,8,22},{64,8,0},{19,7,51},{0,8,118},{0,8,54},{0,9,204},{17,7,15}, - {0,8,102},{0,8,38},{0,9,172},{0,8,6},{0,8,134},{0,8,70},{0,9,236}, - {16,7,9},{0,8,94},{0,8,30},{0,9,156},{20,7,99},{0,8,126},{0,8,62}, - {0,9,220},{18,7,27},{0,8,110},{0,8,46},{0,9,188},{0,8,14},{0,8,142}, - {0,8,78},{0,9,252},{96,7,0},{0,8,81},{0,8,17},{21,8,131},{18,7,31}, - {0,8,113},{0,8,49},{0,9,194},{16,7,10},{0,8,97},{0,8,33},{0,9,162}, - {0,8,1},{0,8,129},{0,8,65},{0,9,226},{16,7,6},{0,8,89},{0,8,25}, - {0,9,146},{19,7,59},{0,8,121},{0,8,57},{0,9,210},{17,7,17},{0,8,105}, - {0,8,41},{0,9,178},{0,8,9},{0,8,137},{0,8,73},{0,9,242},{16,7,4}, - {0,8,85},{0,8,21},{16,8,258},{19,7,43},{0,8,117},{0,8,53},{0,9,202}, - {17,7,13},{0,8,101},{0,8,37},{0,9,170},{0,8,5},{0,8,133},{0,8,69}, - {0,9,234},{16,7,8},{0,8,93},{0,8,29},{0,9,154},{20,7,83},{0,8,125}, - {0,8,61},{0,9,218},{18,7,23},{0,8,109},{0,8,45},{0,9,186},{0,8,13}, - {0,8,141},{0,8,77},{0,9,250},{16,7,3},{0,8,83},{0,8,19},{21,8,195}, - {19,7,35},{0,8,115},{0,8,51},{0,9,198},{17,7,11},{0,8,99},{0,8,35}, - {0,9,166},{0,8,3},{0,8,131},{0,8,67},{0,9,230},{16,7,7},{0,8,91}, - {0,8,27},{0,9,150},{20,7,67},{0,8,123},{0,8,59},{0,9,214},{18,7,19}, - {0,8,107},{0,8,43},{0,9,182},{0,8,11},{0,8,139},{0,8,75},{0,9,246}, - {16,7,5},{0,8,87},{0,8,23},{64,8,0},{19,7,51},{0,8,119},{0,8,55}, - {0,9,206},{17,7,15},{0,8,103},{0,8,39},{0,9,174},{0,8,7},{0,8,135}, - {0,8,71},{0,9,238},{16,7,9},{0,8,95},{0,8,31},{0,9,158},{20,7,99}, - {0,8,127},{0,8,63},{0,9,222},{18,7,27},{0,8,111},{0,8,47},{0,9,190}, - {0,8,15},{0,8,143},{0,8,79},{0,9,254},{96,7,0},{0,8,80},{0,8,16}, - {20,8,115},{18,7,31},{0,8,112},{0,8,48},{0,9,193},{16,7,10},{0,8,96}, - {0,8,32},{0,9,161},{0,8,0},{0,8,128},{0,8,64},{0,9,225},{16,7,6}, - {0,8,88},{0,8,24},{0,9,145},{19,7,59},{0,8,120},{0,8,56},{0,9,209}, - {17,7,17},{0,8,104},{0,8,40},{0,9,177},{0,8,8},{0,8,136},{0,8,72}, - {0,9,241},{16,7,4},{0,8,84},{0,8,20},{21,8,227},{19,7,43},{0,8,116}, - {0,8,52},{0,9,201},{17,7,13},{0,8,100},{0,8,36},{0,9,169},{0,8,4}, - {0,8,132},{0,8,68},{0,9,233},{16,7,8},{0,8,92},{0,8,28},{0,9,153}, - {20,7,83},{0,8,124},{0,8,60},{0,9,217},{18,7,23},{0,8,108},{0,8,44}, - {0,9,185},{0,8,12},{0,8,140},{0,8,76},{0,9,249},{16,7,3},{0,8,82}, - {0,8,18},{21,8,163},{19,7,35},{0,8,114},{0,8,50},{0,9,197},{17,7,11}, - {0,8,98},{0,8,34},{0,9,165},{0,8,2},{0,8,130},{0,8,66},{0,9,229}, - {16,7,7},{0,8,90},{0,8,26},{0,9,149},{20,7,67},{0,8,122},{0,8,58}, - {0,9,213},{18,7,19},{0,8,106},{0,8,42},{0,9,181},{0,8,10},{0,8,138}, - {0,8,74},{0,9,245},{16,7,5},{0,8,86},{0,8,22},{64,8,0},{19,7,51}, - {0,8,118},{0,8,54},{0,9,205},{17,7,15},{0,8,102},{0,8,38},{0,9,173}, - {0,8,6},{0,8,134},{0,8,70},{0,9,237},{16,7,9},{0,8,94},{0,8,30}, - {0,9,157},{20,7,99},{0,8,126},{0,8,62},{0,9,221},{18,7,27},{0,8,110}, - {0,8,46},{0,9,189},{0,8,14},{0,8,142},{0,8,78},{0,9,253},{96,7,0}, - {0,8,81},{0,8,17},{21,8,131},{18,7,31},{0,8,113},{0,8,49},{0,9,195}, - {16,7,10},{0,8,97},{0,8,33},{0,9,163},{0,8,1},{0,8,129},{0,8,65}, - {0,9,227},{16,7,6},{0,8,89},{0,8,25},{0,9,147},{19,7,59},{0,8,121}, - {0,8,57},{0,9,211},{17,7,17},{0,8,105},{0,8,41},{0,9,179},{0,8,9}, - {0,8,137},{0,8,73},{0,9,243},{16,7,4},{0,8,85},{0,8,21},{16,8,258}, - {19,7,43},{0,8,117},{0,8,53},{0,9,203},{17,7,13},{0,8,101},{0,8,37}, - {0,9,171},{0,8,5},{0,8,133},{0,8,69},{0,9,235},{16,7,8},{0,8,93}, - {0,8,29},{0,9,155},{20,7,83},{0,8,125},{0,8,61},{0,9,219},{18,7,23}, - {0,8,109},{0,8,45},{0,9,187},{0,8,13},{0,8,141},{0,8,77},{0,9,251}, - {16,7,3},{0,8,83},{0,8,19},{21,8,195},{19,7,35},{0,8,115},{0,8,51}, - {0,9,199},{17,7,11},{0,8,99},{0,8,35},{0,9,167},{0,8,3},{0,8,131}, - {0,8,67},{0,9,231},{16,7,7},{0,8,91},{0,8,27},{0,9,151},{20,7,67}, - {0,8,123},{0,8,59},{0,9,215},{18,7,19},{0,8,107},{0,8,43},{0,9,183}, - {0,8,11},{0,8,139},{0,8,75},{0,9,247},{16,7,5},{0,8,87},{0,8,23}, - {64,8,0},{19,7,51},{0,8,119},{0,8,55},{0,9,207},{17,7,15},{0,8,103}, - {0,8,39},{0,9,175},{0,8,7},{0,8,135},{0,8,71},{0,9,239},{16,7,9}, - {0,8,95},{0,8,31},{0,9,159},{20,7,99},{0,8,127},{0,8,63},{0,9,223}, - {18,7,27},{0,8,111},{0,8,47},{0,9,191},{0,8,15},{0,8,143},{0,8,79}, - {0,9,255} - }; - - static const code distfix[32] = { - {16,5,1},{23,5,257},{19,5,17},{27,5,4097},{17,5,5},{25,5,1025}, - {21,5,65},{29,5,16385},{16,5,3},{24,5,513},{20,5,33},{28,5,8193}, - {18,5,9},{26,5,2049},{22,5,129},{64,5,0},{16,5,2},{23,5,385}, - {19,5,25},{27,5,6145},{17,5,7},{25,5,1537},{21,5,97},{29,5,24577}, - {16,5,4},{24,5,769},{20,5,49},{28,5,12289},{18,5,13},{26,5,3073}, - {22,5,193},{64,5,0} - }; diff --git a/deps/zlib/inflate.c b/deps/zlib/inflate.c deleted file mode 100644 index 870f89bb4..000000000 --- a/deps/zlib/inflate.c +++ /dev/null @@ -1,1512 +0,0 @@ -/* inflate.c -- zlib decompression - * Copyright (C) 1995-2012 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* - * Change history: - * - * 1.2.beta0 24 Nov 2002 - * - First version -- complete rewrite of inflate to simplify code, avoid - * creation of window when not needed, minimize use of window when it is - * needed, make inffast.c even faster, implement gzip decoding, and to - * improve code readability and style over the previous zlib inflate code - * - * 1.2.beta1 25 Nov 2002 - * - Use pointers for available input and output checking in inffast.c - * - Remove input and output counters in inffast.c - * - Change inffast.c entry and loop from avail_in >= 7 to >= 6 - * - Remove unnecessary second byte pull from length extra in inffast.c - * - Unroll direct copy to three copies per loop in inffast.c - * - * 1.2.beta2 4 Dec 2002 - * - Change external routine names to reduce potential conflicts - * - Correct filename to inffixed.h for fixed tables in inflate.c - * - Make hbuf[] unsigned char to match parameter type in inflate.c - * - Change strm->next_out[-state->offset] to *(strm->next_out - state->offset) - * to avoid negation problem on Alphas (64 bit) in inflate.c - * - * 1.2.beta3 22 Dec 2002 - * - Add comments on state->bits assertion in inffast.c - * - Add comments on op field in inftrees.h - * - Fix bug in reuse of allocated window after inflateReset() - * - Remove bit fields--back to byte structure for speed - * - Remove distance extra == 0 check in inflate_fast()--only helps for lengths - * - Change post-increments to pre-increments in inflate_fast(), PPC biased? - * - Add compile time option, POSTINC, to use post-increments instead (Intel?) - * - Make MATCH copy in inflate() much faster for when inflate_fast() not used - * - Use local copies of stream next and avail values, as well as local bit - * buffer and bit count in inflate()--for speed when inflate_fast() not used - * - * 1.2.beta4 1 Jan 2003 - * - Split ptr - 257 statements in inflate_table() to avoid compiler warnings - * - Move a comment on output buffer sizes from inffast.c to inflate.c - * - Add comments in inffast.c to introduce the inflate_fast() routine - * - Rearrange window copies in inflate_fast() for speed and simplification - * - Unroll last copy for window match in inflate_fast() - * - Use local copies of window variables in inflate_fast() for speed - * - Pull out common wnext == 0 case for speed in inflate_fast() - * - Make op and len in inflate_fast() unsigned for consistency - * - Add FAR to lcode and dcode declarations in inflate_fast() - * - Simplified bad distance check in inflate_fast() - * - Added inflateBackInit(), inflateBack(), and inflateBackEnd() in new - * source file infback.c to provide a call-back interface to inflate for - * programs like gzip and unzip -- uses window as output buffer to avoid - * window copying - * - * 1.2.beta5 1 Jan 2003 - * - Improved inflateBack() interface to allow the caller to provide initial - * input in strm. - * - Fixed stored blocks bug in inflateBack() - * - * 1.2.beta6 4 Jan 2003 - * - Added comments in inffast.c on effectiveness of POSTINC - * - Typecasting all around to reduce compiler warnings - * - Changed loops from while (1) or do {} while (1) to for (;;), again to - * make compilers happy - * - Changed type of window in inflateBackInit() to unsigned char * - * - * 1.2.beta7 27 Jan 2003 - * - Changed many types to unsigned or unsigned short to avoid warnings - * - Added inflateCopy() function - * - * 1.2.0 9 Mar 2003 - * - Changed inflateBack() interface to provide separate opaque descriptors - * for the in() and out() functions - * - Changed inflateBack() argument and in_func typedef to swap the length - * and buffer address return values for the input function - * - Check next_in and next_out for Z_NULL on entry to inflate() - * - * The history for versions after 1.2.0 are in ChangeLog in zlib distribution. - */ - -#include "zutil.h" -#include "inftrees.h" -#include "inflate.h" -#include "inffast.h" - -#ifdef MAKEFIXED -# ifndef BUILDFIXED -# define BUILDFIXED -# endif -#endif - -/* function prototypes */ -local void fixedtables OF((struct inflate_state FAR *state)); -local int updatewindow OF((z_streamp strm, const unsigned char FAR *end, - unsigned copy)); -#ifdef BUILDFIXED - void makefixed OF((void)); -#endif -local unsigned syncsearch OF((unsigned FAR *have, const unsigned char FAR *buf, - unsigned len)); - -int ZEXPORT inflateResetKeep(strm) -z_streamp strm; -{ - struct inflate_state FAR *state; - - if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; - state = (struct inflate_state FAR *)strm->state; - strm->total_in = strm->total_out = state->total = 0; - strm->msg = Z_NULL; - if (state->wrap) /* to support ill-conceived Java test suite */ - strm->adler = state->wrap & 1; - state->mode = HEAD; - state->last = 0; - state->havedict = 0; - state->dmax = 32768U; - state->head = Z_NULL; - state->hold = 0; - state->bits = 0; - state->lencode = state->distcode = state->next = state->codes; - state->sane = 1; - state->back = -1; - Tracev((stderr, "inflate: reset\n")); - return Z_OK; -} - -int ZEXPORT inflateReset(strm) -z_streamp strm; -{ - struct inflate_state FAR *state; - - if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; - state = (struct inflate_state FAR *)strm->state; - state->wsize = 0; - state->whave = 0; - state->wnext = 0; - return inflateResetKeep(strm); -} - -int ZEXPORT inflateReset2(strm, windowBits) -z_streamp strm; -int windowBits; -{ - int wrap; - struct inflate_state FAR *state; - - /* get the state */ - if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; - state = (struct inflate_state FAR *)strm->state; - - /* extract wrap request from windowBits parameter */ - if (windowBits < 0) { - wrap = 0; - windowBits = -windowBits; - } - else { - wrap = (windowBits >> 4) + 1; -#ifdef GUNZIP - if (windowBits < 48) - windowBits &= 15; -#endif - } - - /* set number of window bits, free window if different */ - if (windowBits && (windowBits < 8 || windowBits > 15)) - return Z_STREAM_ERROR; - if (state->window != Z_NULL && state->wbits != (unsigned)windowBits) { - ZFREE(strm, state->window); - state->window = Z_NULL; - } - - /* update state and reset the rest of it */ - state->wrap = wrap; - state->wbits = (unsigned)windowBits; - return inflateReset(strm); -} - -int ZEXPORT inflateInit2_(strm, windowBits, version, stream_size) -z_streamp strm; -int windowBits; -const char *version; -int stream_size; -{ - int ret; - struct inflate_state FAR *state; - - if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || - stream_size != (int)(sizeof(z_stream))) - return Z_VERSION_ERROR; - if (strm == Z_NULL) return Z_STREAM_ERROR; - strm->msg = Z_NULL; /* in case we return an error */ - if (strm->zalloc == (alloc_func)0) { -#ifdef Z_SOLO - return Z_STREAM_ERROR; -#else - strm->zalloc = zcalloc; - strm->opaque = (voidpf)0; -#endif - } - if (strm->zfree == (free_func)0) -#ifdef Z_SOLO - return Z_STREAM_ERROR; -#else - strm->zfree = zcfree; -#endif - state = (struct inflate_state FAR *) - ZALLOC(strm, 1, sizeof(struct inflate_state)); - if (state == Z_NULL) return Z_MEM_ERROR; - Tracev((stderr, "inflate: allocated\n")); - strm->state = (struct internal_state FAR *)state; - state->window = Z_NULL; - ret = inflateReset2(strm, windowBits); - if (ret != Z_OK) { - ZFREE(strm, state); - strm->state = Z_NULL; - } - return ret; -} - -int ZEXPORT inflateInit_(strm, version, stream_size) -z_streamp strm; -const char *version; -int stream_size; -{ - return inflateInit2_(strm, DEF_WBITS, version, stream_size); -} - -int ZEXPORT inflatePrime(strm, bits, value) -z_streamp strm; -int bits; -int value; -{ - struct inflate_state FAR *state; - - if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; - state = (struct inflate_state FAR *)strm->state; - if (bits < 0) { - state->hold = 0; - state->bits = 0; - return Z_OK; - } - if (bits > 16 || state->bits + bits > 32) return Z_STREAM_ERROR; - value &= (1L << bits) - 1; - state->hold += value << state->bits; - state->bits += bits; - return Z_OK; -} - -/* - Return state with length and distance decoding tables and index sizes set to - fixed code decoding. Normally this returns fixed tables from inffixed.h. - If BUILDFIXED is defined, then instead this routine builds the tables the - first time it's called, and returns those tables the first time and - thereafter. This reduces the size of the code by about 2K bytes, in - exchange for a little execution time. However, BUILDFIXED should not be - used for threaded applications, since the rewriting of the tables and virgin - may not be thread-safe. - */ -local void fixedtables(state) -struct inflate_state FAR *state; -{ -#ifdef BUILDFIXED - static int virgin = 1; - static code *lenfix, *distfix; - static code fixed[544]; - - /* build fixed huffman tables if first call (may not be thread safe) */ - if (virgin) { - unsigned sym, bits; - static code *next; - - /* literal/length table */ - sym = 0; - while (sym < 144) state->lens[sym++] = 8; - while (sym < 256) state->lens[sym++] = 9; - while (sym < 280) state->lens[sym++] = 7; - while (sym < 288) state->lens[sym++] = 8; - next = fixed; - lenfix = next; - bits = 9; - inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work); - - /* distance table */ - sym = 0; - while (sym < 32) state->lens[sym++] = 5; - distfix = next; - bits = 5; - inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work); - - /* do this just once */ - virgin = 0; - } -#else /* !BUILDFIXED */ -# include "inffixed.h" -#endif /* BUILDFIXED */ - state->lencode = lenfix; - state->lenbits = 9; - state->distcode = distfix; - state->distbits = 5; -} - -#ifdef MAKEFIXED -#include - -/* - Write out the inffixed.h that is #include'd above. Defining MAKEFIXED also - defines BUILDFIXED, so the tables are built on the fly. makefixed() writes - those tables to stdout, which would be piped to inffixed.h. A small program - can simply call makefixed to do this: - - void makefixed(void); - - int main(void) - { - makefixed(); - return 0; - } - - Then that can be linked with zlib built with MAKEFIXED defined and run: - - a.out > inffixed.h - */ -void makefixed() -{ - unsigned low, size; - struct inflate_state state; - - fixedtables(&state); - puts(" /* inffixed.h -- table for decoding fixed codes"); - puts(" * Generated automatically by makefixed()."); - puts(" */"); - puts(""); - puts(" /* WARNING: this file should *not* be used by applications."); - puts(" It is part of the implementation of this library and is"); - puts(" subject to change. Applications should only use zlib.h."); - puts(" */"); - puts(""); - size = 1U << 9; - printf(" static const code lenfix[%u] = {", size); - low = 0; - for (;;) { - if ((low % 7) == 0) printf("\n "); - printf("{%u,%u,%d}", (low & 127) == 99 ? 64 : state.lencode[low].op, - state.lencode[low].bits, state.lencode[low].val); - if (++low == size) break; - putchar(','); - } - puts("\n };"); - size = 1U << 5; - printf("\n static const code distfix[%u] = {", size); - low = 0; - for (;;) { - if ((low % 6) == 0) printf("\n "); - printf("{%u,%u,%d}", state.distcode[low].op, state.distcode[low].bits, - state.distcode[low].val); - if (++low == size) break; - putchar(','); - } - puts("\n };"); -} -#endif /* MAKEFIXED */ - -/* - Update the window with the last wsize (normally 32K) bytes written before - returning. If window does not exist yet, create it. This is only called - when a window is already in use, or when output has been written during this - inflate call, but the end of the deflate stream has not been reached yet. - It is also called to create a window for dictionary data when a dictionary - is loaded. - - Providing output buffers larger than 32K to inflate() should provide a speed - advantage, since only the last 32K of output is copied to the sliding window - upon return from inflate(), and since all distances after the first 32K of - output will fall in the output data, making match copies simpler and faster. - The advantage may be dependent on the size of the processor's data caches. - */ -local int updatewindow(strm, end, copy) -z_streamp strm; -const Bytef *end; -unsigned copy; -{ - struct inflate_state FAR *state; - unsigned dist; - - state = (struct inflate_state FAR *)strm->state; - - /* if it hasn't been done already, allocate space for the window */ - if (state->window == Z_NULL) { - state->window = (unsigned char FAR *) - ZALLOC(strm, 1U << state->wbits, - sizeof(unsigned char)); - if (state->window == Z_NULL) return 1; - } - - /* if window not in use yet, initialize */ - if (state->wsize == 0) { - state->wsize = 1U << state->wbits; - state->wnext = 0; - state->whave = 0; - } - - /* copy state->wsize or less output bytes into the circular window */ - if (copy >= state->wsize) { - zmemcpy(state->window, end - state->wsize, state->wsize); - state->wnext = 0; - state->whave = state->wsize; - } - else { - dist = state->wsize - state->wnext; - if (dist > copy) dist = copy; - zmemcpy(state->window + state->wnext, end - copy, dist); - copy -= dist; - if (copy) { - zmemcpy(state->window, end - copy, copy); - state->wnext = copy; - state->whave = state->wsize; - } - else { - state->wnext += dist; - if (state->wnext == state->wsize) state->wnext = 0; - if (state->whave < state->wsize) state->whave += dist; - } - } - return 0; -} - -/* Macros for inflate(): */ - -/* check function to use adler32() for zlib or crc32() for gzip */ -#ifdef GUNZIP -# define UPDATE(check, buf, len) \ - (state->flags ? crc32(check, buf, len) : adler32(check, buf, len)) -#else -# define UPDATE(check, buf, len) adler32(check, buf, len) -#endif - -/* check macros for header crc */ -#ifdef GUNZIP -# define CRC2(check, word) \ - do { \ - hbuf[0] = (unsigned char)(word); \ - hbuf[1] = (unsigned char)((word) >> 8); \ - check = crc32(check, hbuf, 2); \ - } while (0) - -# define CRC4(check, word) \ - do { \ - hbuf[0] = (unsigned char)(word); \ - hbuf[1] = (unsigned char)((word) >> 8); \ - hbuf[2] = (unsigned char)((word) >> 16); \ - hbuf[3] = (unsigned char)((word) >> 24); \ - check = crc32(check, hbuf, 4); \ - } while (0) -#endif - -/* Load registers with state in inflate() for speed */ -#define LOAD() \ - do { \ - put = strm->next_out; \ - left = strm->avail_out; \ - next = strm->next_in; \ - have = strm->avail_in; \ - hold = state->hold; \ - bits = state->bits; \ - } while (0) - -/* Restore state from registers in inflate() */ -#define RESTORE() \ - do { \ - strm->next_out = put; \ - strm->avail_out = left; \ - strm->next_in = next; \ - strm->avail_in = have; \ - state->hold = hold; \ - state->bits = bits; \ - } while (0) - -/* Clear the input bit accumulator */ -#define INITBITS() \ - do { \ - hold = 0; \ - bits = 0; \ - } while (0) - -/* Get a byte of input into the bit accumulator, or return from inflate() - if there is no input available. */ -#define PULLBYTE() \ - do { \ - if (have == 0) goto inf_leave; \ - have--; \ - hold += (unsigned long)(*next++) << bits; \ - bits += 8; \ - } while (0) - -/* Assure that there are at least n bits in the bit accumulator. If there is - not enough available input to do that, then return from inflate(). */ -#define NEEDBITS(n) \ - do { \ - while (bits < (unsigned)(n)) \ - PULLBYTE(); \ - } while (0) - -/* Return the low n bits of the bit accumulator (n < 16) */ -#define BITS(n) \ - ((unsigned)hold & ((1U << (n)) - 1)) - -/* Remove n bits from the bit accumulator */ -#define DROPBITS(n) \ - do { \ - hold >>= (n); \ - bits -= (unsigned)(n); \ - } while (0) - -/* Remove zero to seven bits as needed to go to a byte boundary */ -#define BYTEBITS() \ - do { \ - hold >>= bits & 7; \ - bits -= bits & 7; \ - } while (0) - -/* - inflate() uses a state machine to process as much input data and generate as - much output data as possible before returning. The state machine is - structured roughly as follows: - - for (;;) switch (state) { - ... - case STATEn: - if (not enough input data or output space to make progress) - return; - ... make progress ... - state = STATEm; - break; - ... - } - - so when inflate() is called again, the same case is attempted again, and - if the appropriate resources are provided, the machine proceeds to the - next state. The NEEDBITS() macro is usually the way the state evaluates - whether it can proceed or should return. NEEDBITS() does the return if - the requested bits are not available. The typical use of the BITS macros - is: - - NEEDBITS(n); - ... do something with BITS(n) ... - DROPBITS(n); - - where NEEDBITS(n) either returns from inflate() if there isn't enough - input left to load n bits into the accumulator, or it continues. BITS(n) - gives the low n bits in the accumulator. When done, DROPBITS(n) drops - the low n bits off the accumulator. INITBITS() clears the accumulator - and sets the number of available bits to zero. BYTEBITS() discards just - enough bits to put the accumulator on a byte boundary. After BYTEBITS() - and a NEEDBITS(8), then BITS(8) would return the next byte in the stream. - - NEEDBITS(n) uses PULLBYTE() to get an available byte of input, or to return - if there is no input available. The decoding of variable length codes uses - PULLBYTE() directly in order to pull just enough bytes to decode the next - code, and no more. - - Some states loop until they get enough input, making sure that enough - state information is maintained to continue the loop where it left off - if NEEDBITS() returns in the loop. For example, want, need, and keep - would all have to actually be part of the saved state in case NEEDBITS() - returns: - - case STATEw: - while (want < need) { - NEEDBITS(n); - keep[want++] = BITS(n); - DROPBITS(n); - } - state = STATEx; - case STATEx: - - As shown above, if the next state is also the next case, then the break - is omitted. - - A state may also return if there is not enough output space available to - complete that state. Those states are copying stored data, writing a - literal byte, and copying a matching string. - - When returning, a "goto inf_leave" is used to update the total counters, - update the check value, and determine whether any progress has been made - during that inflate() call in order to return the proper return code. - Progress is defined as a change in either strm->avail_in or strm->avail_out. - When there is a window, goto inf_leave will update the window with the last - output written. If a goto inf_leave occurs in the middle of decompression - and there is no window currently, goto inf_leave will create one and copy - output to the window for the next call of inflate(). - - In this implementation, the flush parameter of inflate() only affects the - return code (per zlib.h). inflate() always writes as much as possible to - strm->next_out, given the space available and the provided input--the effect - documented in zlib.h of Z_SYNC_FLUSH. Furthermore, inflate() always defers - the allocation of and copying into a sliding window until necessary, which - provides the effect documented in zlib.h for Z_FINISH when the entire input - stream available. So the only thing the flush parameter actually does is: - when flush is set to Z_FINISH, inflate() cannot return Z_OK. Instead it - will return Z_BUF_ERROR if it has not reached the end of the stream. - */ - -int ZEXPORT inflate(strm, flush) -z_streamp strm; -int flush; -{ - struct inflate_state FAR *state; - z_const unsigned char FAR *next; /* next input */ - unsigned char FAR *put; /* next output */ - unsigned have, left; /* available input and output */ - unsigned long hold; /* bit buffer */ - unsigned bits; /* bits in bit buffer */ - unsigned in, out; /* save starting available input and output */ - unsigned copy; /* number of stored or match bytes to copy */ - unsigned char FAR *from; /* where to copy match bytes from */ - code here; /* current decoding table entry */ - code last; /* parent table entry */ - unsigned len; /* length to copy for repeats, bits to drop */ - int ret; /* return code */ -#ifdef GUNZIP - unsigned char hbuf[4]; /* buffer for gzip header crc calculation */ -#endif - static const unsigned short order[19] = /* permutation of code lengths */ - {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; - - if (strm == Z_NULL || strm->state == Z_NULL || strm->next_out == Z_NULL || - (strm->next_in == Z_NULL && strm->avail_in != 0)) - return Z_STREAM_ERROR; - - state = (struct inflate_state FAR *)strm->state; - if (state->mode == TYPE) state->mode = TYPEDO; /* skip check */ - LOAD(); - in = have; - out = left; - ret = Z_OK; - for (;;) - switch (state->mode) { - case HEAD: - if (state->wrap == 0) { - state->mode = TYPEDO; - break; - } - NEEDBITS(16); -#ifdef GUNZIP - if ((state->wrap & 2) && hold == 0x8b1f) { /* gzip header */ - state->check = crc32(0L, Z_NULL, 0); - CRC2(state->check, hold); - INITBITS(); - state->mode = FLAGS; - break; - } - state->flags = 0; /* expect zlib header */ - if (state->head != Z_NULL) - state->head->done = -1; - if (!(state->wrap & 1) || /* check if zlib header allowed */ -#else - if ( -#endif - ((BITS(8) << 8) + (hold >> 8)) % 31) { - strm->msg = (char *)"incorrect header check"; - state->mode = BAD; - break; - } - if (BITS(4) != Z_DEFLATED) { - strm->msg = (char *)"unknown compression method"; - state->mode = BAD; - break; - } - DROPBITS(4); - len = BITS(4) + 8; - if (state->wbits == 0) - state->wbits = len; - else if (len > state->wbits) { - strm->msg = (char *)"invalid window size"; - state->mode = BAD; - break; - } - state->dmax = 1U << len; - Tracev((stderr, "inflate: zlib header ok\n")); - strm->adler = state->check = adler32(0L, Z_NULL, 0); - state->mode = hold & 0x200 ? DICTID : TYPE; - INITBITS(); - break; -#ifdef GUNZIP - case FLAGS: - NEEDBITS(16); - state->flags = (int)(hold); - if ((state->flags & 0xff) != Z_DEFLATED) { - strm->msg = (char *)"unknown compression method"; - state->mode = BAD; - break; - } - if (state->flags & 0xe000) { - strm->msg = (char *)"unknown header flags set"; - state->mode = BAD; - break; - } - if (state->head != Z_NULL) - state->head->text = (int)((hold >> 8) & 1); - if (state->flags & 0x0200) CRC2(state->check, hold); - INITBITS(); - state->mode = TIME; - case TIME: - NEEDBITS(32); - if (state->head != Z_NULL) - state->head->time = hold; - if (state->flags & 0x0200) CRC4(state->check, hold); - INITBITS(); - state->mode = OS; - case OS: - NEEDBITS(16); - if (state->head != Z_NULL) { - state->head->xflags = (int)(hold & 0xff); - state->head->os = (int)(hold >> 8); - } - if (state->flags & 0x0200) CRC2(state->check, hold); - INITBITS(); - state->mode = EXLEN; - case EXLEN: - if (state->flags & 0x0400) { - NEEDBITS(16); - state->length = (unsigned)(hold); - if (state->head != Z_NULL) - state->head->extra_len = (unsigned)hold; - if (state->flags & 0x0200) CRC2(state->check, hold); - INITBITS(); - } - else if (state->head != Z_NULL) - state->head->extra = Z_NULL; - state->mode = EXTRA; - case EXTRA: - if (state->flags & 0x0400) { - copy = state->length; - if (copy > have) copy = have; - if (copy) { - if (state->head != Z_NULL && - state->head->extra != Z_NULL) { - len = state->head->extra_len - state->length; - zmemcpy(state->head->extra + len, next, - len + copy > state->head->extra_max ? - state->head->extra_max - len : copy); - } - if (state->flags & 0x0200) - state->check = crc32(state->check, next, copy); - have -= copy; - next += copy; - state->length -= copy; - } - if (state->length) goto inf_leave; - } - state->length = 0; - state->mode = NAME; - case NAME: - if (state->flags & 0x0800) { - if (have == 0) goto inf_leave; - copy = 0; - do { - len = (unsigned)(next[copy++]); - if (state->head != Z_NULL && - state->head->name != Z_NULL && - state->length < state->head->name_max) - state->head->name[state->length++] = len; - } while (len && copy < have); - if (state->flags & 0x0200) - state->check = crc32(state->check, next, copy); - have -= copy; - next += copy; - if (len) goto inf_leave; - } - else if (state->head != Z_NULL) - state->head->name = Z_NULL; - state->length = 0; - state->mode = COMMENT; - case COMMENT: - if (state->flags & 0x1000) { - if (have == 0) goto inf_leave; - copy = 0; - do { - len = (unsigned)(next[copy++]); - if (state->head != Z_NULL && - state->head->comment != Z_NULL && - state->length < state->head->comm_max) - state->head->comment[state->length++] = len; - } while (len && copy < have); - if (state->flags & 0x0200) - state->check = crc32(state->check, next, copy); - have -= copy; - next += copy; - if (len) goto inf_leave; - } - else if (state->head != Z_NULL) - state->head->comment = Z_NULL; - state->mode = HCRC; - case HCRC: - if (state->flags & 0x0200) { - NEEDBITS(16); - if (hold != (state->check & 0xffff)) { - strm->msg = (char *)"header crc mismatch"; - state->mode = BAD; - break; - } - INITBITS(); - } - if (state->head != Z_NULL) { - state->head->hcrc = (int)((state->flags >> 9) & 1); - state->head->done = 1; - } - strm->adler = state->check = crc32(0L, Z_NULL, 0); - state->mode = TYPE; - break; -#endif - case DICTID: - NEEDBITS(32); - strm->adler = state->check = ZSWAP32(hold); - INITBITS(); - state->mode = DICT; - case DICT: - if (state->havedict == 0) { - RESTORE(); - return Z_NEED_DICT; - } - strm->adler = state->check = adler32(0L, Z_NULL, 0); - state->mode = TYPE; - case TYPE: - if (flush == Z_BLOCK || flush == Z_TREES) goto inf_leave; - case TYPEDO: - if (state->last) { - BYTEBITS(); - state->mode = CHECK; - break; - } - NEEDBITS(3); - state->last = BITS(1); - DROPBITS(1); - switch (BITS(2)) { - case 0: /* stored block */ - Tracev((stderr, "inflate: stored block%s\n", - state->last ? " (last)" : "")); - state->mode = STORED; - break; - case 1: /* fixed block */ - fixedtables(state); - Tracev((stderr, "inflate: fixed codes block%s\n", - state->last ? " (last)" : "")); - state->mode = LEN_; /* decode codes */ - if (flush == Z_TREES) { - DROPBITS(2); - goto inf_leave; - } - break; - case 2: /* dynamic block */ - Tracev((stderr, "inflate: dynamic codes block%s\n", - state->last ? " (last)" : "")); - state->mode = TABLE; - break; - case 3: - strm->msg = (char *)"invalid block type"; - state->mode = BAD; - } - DROPBITS(2); - break; - case STORED: - BYTEBITS(); /* go to byte boundary */ - NEEDBITS(32); - if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) { - strm->msg = (char *)"invalid stored block lengths"; - state->mode = BAD; - break; - } - state->length = (unsigned)hold & 0xffff; - Tracev((stderr, "inflate: stored length %u\n", - state->length)); - INITBITS(); - state->mode = COPY_; - if (flush == Z_TREES) goto inf_leave; - case COPY_: - state->mode = COPY; - case COPY: - copy = state->length; - if (copy) { - if (copy > have) copy = have; - if (copy > left) copy = left; - if (copy == 0) goto inf_leave; - zmemcpy(put, next, copy); - have -= copy; - next += copy; - left -= copy; - put += copy; - state->length -= copy; - break; - } - Tracev((stderr, "inflate: stored end\n")); - state->mode = TYPE; - break; - case TABLE: - NEEDBITS(14); - state->nlen = BITS(5) + 257; - DROPBITS(5); - state->ndist = BITS(5) + 1; - DROPBITS(5); - state->ncode = BITS(4) + 4; - DROPBITS(4); -#ifndef PKZIP_BUG_WORKAROUND - if (state->nlen > 286 || state->ndist > 30) { - strm->msg = (char *)"too many length or distance symbols"; - state->mode = BAD; - break; - } -#endif - Tracev((stderr, "inflate: table sizes ok\n")); - state->have = 0; - state->mode = LENLENS; - case LENLENS: - while (state->have < state->ncode) { - NEEDBITS(3); - state->lens[order[state->have++]] = (unsigned short)BITS(3); - DROPBITS(3); - } - while (state->have < 19) - state->lens[order[state->have++]] = 0; - state->next = state->codes; - state->lencode = (const code FAR *)(state->next); - state->lenbits = 7; - ret = inflate_table(CODES, state->lens, 19, &(state->next), - &(state->lenbits), state->work); - if (ret) { - strm->msg = (char *)"invalid code lengths set"; - state->mode = BAD; - break; - } - Tracev((stderr, "inflate: code lengths ok\n")); - state->have = 0; - state->mode = CODELENS; - case CODELENS: - while (state->have < state->nlen + state->ndist) { - for (;;) { - here = state->lencode[BITS(state->lenbits)]; - if ((unsigned)(here.bits) <= bits) break; - PULLBYTE(); - } - if (here.val < 16) { - DROPBITS(here.bits); - state->lens[state->have++] = here.val; - } - else { - if (here.val == 16) { - NEEDBITS(here.bits + 2); - DROPBITS(here.bits); - if (state->have == 0) { - strm->msg = (char *)"invalid bit length repeat"; - state->mode = BAD; - break; - } - len = state->lens[state->have - 1]; - copy = 3 + BITS(2); - DROPBITS(2); - } - else if (here.val == 17) { - NEEDBITS(here.bits + 3); - DROPBITS(here.bits); - len = 0; - copy = 3 + BITS(3); - DROPBITS(3); - } - else { - NEEDBITS(here.bits + 7); - DROPBITS(here.bits); - len = 0; - copy = 11 + BITS(7); - DROPBITS(7); - } - if (state->have + copy > state->nlen + state->ndist) { - strm->msg = (char *)"invalid bit length repeat"; - state->mode = BAD; - break; - } - while (copy--) - state->lens[state->have++] = (unsigned short)len; - } - } - - /* handle error breaks in while */ - if (state->mode == BAD) break; - - /* check for end-of-block code (better have one) */ - if (state->lens[256] == 0) { - strm->msg = (char *)"invalid code -- missing end-of-block"; - state->mode = BAD; - break; - } - - /* build code tables -- note: do not change the lenbits or distbits - values here (9 and 6) without reading the comments in inftrees.h - concerning the ENOUGH constants, which depend on those values */ - state->next = state->codes; - state->lencode = (const code FAR *)(state->next); - state->lenbits = 9; - ret = inflate_table(LENS, state->lens, state->nlen, &(state->next), - &(state->lenbits), state->work); - if (ret) { - strm->msg = (char *)"invalid literal/lengths set"; - state->mode = BAD; - break; - } - state->distcode = (const code FAR *)(state->next); - state->distbits = 6; - ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist, - &(state->next), &(state->distbits), state->work); - if (ret) { - strm->msg = (char *)"invalid distances set"; - state->mode = BAD; - break; - } - Tracev((stderr, "inflate: codes ok\n")); - state->mode = LEN_; - if (flush == Z_TREES) goto inf_leave; - case LEN_: - state->mode = LEN; - case LEN: - if (have >= 6 && left >= 258) { - RESTORE(); - inflate_fast(strm, out); - LOAD(); - if (state->mode == TYPE) - state->back = -1; - break; - } - state->back = 0; - for (;;) { - here = state->lencode[BITS(state->lenbits)]; - if ((unsigned)(here.bits) <= bits) break; - PULLBYTE(); - } - if (here.op && (here.op & 0xf0) == 0) { - last = here; - for (;;) { - here = state->lencode[last.val + - (BITS(last.bits + last.op) >> last.bits)]; - if ((unsigned)(last.bits + here.bits) <= bits) break; - PULLBYTE(); - } - DROPBITS(last.bits); - state->back += last.bits; - } - DROPBITS(here.bits); - state->back += here.bits; - state->length = (unsigned)here.val; - if ((int)(here.op) == 0) { - Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ? - "inflate: literal '%c'\n" : - "inflate: literal 0x%02x\n", here.val)); - state->mode = LIT; - break; - } - if (here.op & 32) { - Tracevv((stderr, "inflate: end of block\n")); - state->back = -1; - state->mode = TYPE; - break; - } - if (here.op & 64) { - strm->msg = (char *)"invalid literal/length code"; - state->mode = BAD; - break; - } - state->extra = (unsigned)(here.op) & 15; - state->mode = LENEXT; - case LENEXT: - if (state->extra) { - NEEDBITS(state->extra); - state->length += BITS(state->extra); - DROPBITS(state->extra); - state->back += state->extra; - } - Tracevv((stderr, "inflate: length %u\n", state->length)); - state->was = state->length; - state->mode = DIST; - case DIST: - for (;;) { - here = state->distcode[BITS(state->distbits)]; - if ((unsigned)(here.bits) <= bits) break; - PULLBYTE(); - } - if ((here.op & 0xf0) == 0) { - last = here; - for (;;) { - here = state->distcode[last.val + - (BITS(last.bits + last.op) >> last.bits)]; - if ((unsigned)(last.bits + here.bits) <= bits) break; - PULLBYTE(); - } - DROPBITS(last.bits); - state->back += last.bits; - } - DROPBITS(here.bits); - state->back += here.bits; - if (here.op & 64) { - strm->msg = (char *)"invalid distance code"; - state->mode = BAD; - break; - } - state->offset = (unsigned)here.val; - state->extra = (unsigned)(here.op) & 15; - state->mode = DISTEXT; - case DISTEXT: - if (state->extra) { - NEEDBITS(state->extra); - state->offset += BITS(state->extra); - DROPBITS(state->extra); - state->back += state->extra; - } -#ifdef INFLATE_STRICT - if (state->offset > state->dmax) { - strm->msg = (char *)"invalid distance too far back"; - state->mode = BAD; - break; - } -#endif - Tracevv((stderr, "inflate: distance %u\n", state->offset)); - state->mode = MATCH; - case MATCH: - if (left == 0) goto inf_leave; - copy = out - left; - if (state->offset > copy) { /* copy from window */ - copy = state->offset - copy; - if (copy > state->whave) { - if (state->sane) { - strm->msg = (char *)"invalid distance too far back"; - state->mode = BAD; - break; - } -#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR - Trace((stderr, "inflate.c too far\n")); - copy -= state->whave; - if (copy > state->length) copy = state->length; - if (copy > left) copy = left; - left -= copy; - state->length -= copy; - do { - *put++ = 0; - } while (--copy); - if (state->length == 0) state->mode = LEN; - break; -#endif - } - if (copy > state->wnext) { - copy -= state->wnext; - from = state->window + (state->wsize - copy); - } - else - from = state->window + (state->wnext - copy); - if (copy > state->length) copy = state->length; - } - else { /* copy from output */ - from = put - state->offset; - copy = state->length; - } - if (copy > left) copy = left; - left -= copy; - state->length -= copy; - do { - *put++ = *from++; - } while (--copy); - if (state->length == 0) state->mode = LEN; - break; - case LIT: - if (left == 0) goto inf_leave; - *put++ = (unsigned char)(state->length); - left--; - state->mode = LEN; - break; - case CHECK: - if (state->wrap) { - NEEDBITS(32); - out -= left; - strm->total_out += out; - state->total += out; - if (out) - strm->adler = state->check = - UPDATE(state->check, put - out, out); - out = left; - if (( -#ifdef GUNZIP - state->flags ? hold : -#endif - ZSWAP32(hold)) != state->check) { - strm->msg = (char *)"incorrect data check"; - state->mode = BAD; - break; - } - INITBITS(); - Tracev((stderr, "inflate: check matches trailer\n")); - } -#ifdef GUNZIP - state->mode = LENGTH; - case LENGTH: - if (state->wrap && state->flags) { - NEEDBITS(32); - if (hold != (state->total & 0xffffffffUL)) { - strm->msg = (char *)"incorrect length check"; - state->mode = BAD; - break; - } - INITBITS(); - Tracev((stderr, "inflate: length matches trailer\n")); - } -#endif - state->mode = DONE; - case DONE: - ret = Z_STREAM_END; - goto inf_leave; - case BAD: - ret = Z_DATA_ERROR; - goto inf_leave; - case MEM: - return Z_MEM_ERROR; - case SYNC: - default: - return Z_STREAM_ERROR; - } - - /* - Return from inflate(), updating the total counts and the check value. - If there was no progress during the inflate() call, return a buffer - error. Call updatewindow() to create and/or update the window state. - Note: a memory error from inflate() is non-recoverable. - */ - inf_leave: - RESTORE(); - if (state->wsize || (out != strm->avail_out && state->mode < BAD && - (state->mode < CHECK || flush != Z_FINISH))) - if (updatewindow(strm, strm->next_out, out - strm->avail_out)) { - state->mode = MEM; - return Z_MEM_ERROR; - } - in -= strm->avail_in; - out -= strm->avail_out; - strm->total_in += in; - strm->total_out += out; - state->total += out; - if (state->wrap && out) - strm->adler = state->check = - UPDATE(state->check, strm->next_out - out, out); - strm->data_type = state->bits + (state->last ? 64 : 0) + - (state->mode == TYPE ? 128 : 0) + - (state->mode == LEN_ || state->mode == COPY_ ? 256 : 0); - if (((in == 0 && out == 0) || flush == Z_FINISH) && ret == Z_OK) - ret = Z_BUF_ERROR; - return ret; -} - -int ZEXPORT inflateEnd(strm) -z_streamp strm; -{ - struct inflate_state FAR *state; - if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0) - return Z_STREAM_ERROR; - state = (struct inflate_state FAR *)strm->state; - if (state->window != Z_NULL) ZFREE(strm, state->window); - ZFREE(strm, strm->state); - strm->state = Z_NULL; - Tracev((stderr, "inflate: end\n")); - return Z_OK; -} - -int ZEXPORT inflateGetDictionary(strm, dictionary, dictLength) -z_streamp strm; -Bytef *dictionary; -uInt *dictLength; -{ - struct inflate_state FAR *state; - - /* check state */ - if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; - state = (struct inflate_state FAR *)strm->state; - - /* copy dictionary */ - if (state->whave && dictionary != Z_NULL) { - zmemcpy(dictionary, state->window + state->wnext, - state->whave - state->wnext); - zmemcpy(dictionary + state->whave - state->wnext, - state->window, state->wnext); - } - if (dictLength != Z_NULL) - *dictLength = state->whave; - return Z_OK; -} - -int ZEXPORT inflateSetDictionary(strm, dictionary, dictLength) -z_streamp strm; -const Bytef *dictionary; -uInt dictLength; -{ - struct inflate_state FAR *state; - unsigned long dictid; - int ret; - - /* check state */ - if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; - state = (struct inflate_state FAR *)strm->state; - if (state->wrap != 0 && state->mode != DICT) - return Z_STREAM_ERROR; - - /* check for correct dictionary identifier */ - if (state->mode == DICT) { - dictid = adler32(0L, Z_NULL, 0); - dictid = adler32(dictid, dictionary, dictLength); - if (dictid != state->check) - return Z_DATA_ERROR; - } - - /* copy dictionary to window using updatewindow(), which will amend the - existing dictionary if appropriate */ - ret = updatewindow(strm, dictionary + dictLength, dictLength); - if (ret) { - state->mode = MEM; - return Z_MEM_ERROR; - } - state->havedict = 1; - Tracev((stderr, "inflate: dictionary set\n")); - return Z_OK; -} - -int ZEXPORT inflateGetHeader(strm, head) -z_streamp strm; -gz_headerp head; -{ - struct inflate_state FAR *state; - - /* check state */ - if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; - state = (struct inflate_state FAR *)strm->state; - if ((state->wrap & 2) == 0) return Z_STREAM_ERROR; - - /* save header structure */ - state->head = head; - head->done = 0; - return Z_OK; -} - -/* - Search buf[0..len-1] for the pattern: 0, 0, 0xff, 0xff. Return when found - or when out of input. When called, *have is the number of pattern bytes - found in order so far, in 0..3. On return *have is updated to the new - state. If on return *have equals four, then the pattern was found and the - return value is how many bytes were read including the last byte of the - pattern. If *have is less than four, then the pattern has not been found - yet and the return value is len. In the latter case, syncsearch() can be - called again with more data and the *have state. *have is initialized to - zero for the first call. - */ -local unsigned syncsearch(have, buf, len) -unsigned FAR *have; -const unsigned char FAR *buf; -unsigned len; -{ - unsigned got; - unsigned next; - - got = *have; - next = 0; - while (next < len && got < 4) { - if ((int)(buf[next]) == (got < 2 ? 0 : 0xff)) - got++; - else if (buf[next]) - got = 0; - else - got = 4 - got; - next++; - } - *have = got; - return next; -} - -int ZEXPORT inflateSync(strm) -z_streamp strm; -{ - unsigned len; /* number of bytes to look at or looked at */ - unsigned long in, out; /* temporary to save total_in and total_out */ - unsigned char buf[4]; /* to restore bit buffer to byte string */ - struct inflate_state FAR *state; - - /* check parameters */ - if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; - state = (struct inflate_state FAR *)strm->state; - if (strm->avail_in == 0 && state->bits < 8) return Z_BUF_ERROR; - - /* if first time, start search in bit buffer */ - if (state->mode != SYNC) { - state->mode = SYNC; - state->hold <<= state->bits & 7; - state->bits -= state->bits & 7; - len = 0; - while (state->bits >= 8) { - buf[len++] = (unsigned char)(state->hold); - state->hold >>= 8; - state->bits -= 8; - } - state->have = 0; - syncsearch(&(state->have), buf, len); - } - - /* search available input */ - len = syncsearch(&(state->have), strm->next_in, strm->avail_in); - strm->avail_in -= len; - strm->next_in += len; - strm->total_in += len; - - /* return no joy or set up to restart inflate() on a new block */ - if (state->have != 4) return Z_DATA_ERROR; - in = strm->total_in; out = strm->total_out; - inflateReset(strm); - strm->total_in = in; strm->total_out = out; - state->mode = TYPE; - return Z_OK; -} - -/* - Returns true if inflate is currently at the end of a block generated by - Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP - implementation to provide an additional safety check. PPP uses - Z_SYNC_FLUSH but removes the length bytes of the resulting empty stored - block. When decompressing, PPP checks that at the end of input packet, - inflate is waiting for these length bytes. - */ -int ZEXPORT inflateSyncPoint(strm) -z_streamp strm; -{ - struct inflate_state FAR *state; - - if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; - state = (struct inflate_state FAR *)strm->state; - return state->mode == STORED && state->bits == 0; -} - -int ZEXPORT inflateCopy(dest, source) -z_streamp dest; -z_streamp source; -{ - struct inflate_state FAR *state; - struct inflate_state FAR *copy; - unsigned char FAR *window; - unsigned wsize; - - /* check input */ - if (dest == Z_NULL || source == Z_NULL || source->state == Z_NULL || - source->zalloc == (alloc_func)0 || source->zfree == (free_func)0) - return Z_STREAM_ERROR; - state = (struct inflate_state FAR *)source->state; - - /* allocate space */ - copy = (struct inflate_state FAR *) - ZALLOC(source, 1, sizeof(struct inflate_state)); - if (copy == Z_NULL) return Z_MEM_ERROR; - window = Z_NULL; - if (state->window != Z_NULL) { - window = (unsigned char FAR *) - ZALLOC(source, 1U << state->wbits, sizeof(unsigned char)); - if (window == Z_NULL) { - ZFREE(source, copy); - return Z_MEM_ERROR; - } - } - - /* copy state */ - zmemcpy((voidpf)dest, (voidpf)source, sizeof(z_stream)); - zmemcpy((voidpf)copy, (voidpf)state, sizeof(struct inflate_state)); - if (state->lencode >= state->codes && - state->lencode <= state->codes + ENOUGH - 1) { - copy->lencode = copy->codes + (state->lencode - state->codes); - copy->distcode = copy->codes + (state->distcode - state->codes); - } - copy->next = copy->codes + (state->next - state->codes); - if (window != Z_NULL) { - wsize = 1U << state->wbits; - zmemcpy(window, state->window, wsize); - } - copy->window = window; - dest->state = (struct internal_state FAR *)copy; - return Z_OK; -} - -int ZEXPORT inflateUndermine(strm, subvert) -z_streamp strm; -int subvert; -{ - struct inflate_state FAR *state; - - if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; - state = (struct inflate_state FAR *)strm->state; - state->sane = !subvert; -#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR - return Z_OK; -#else - state->sane = 1; - return Z_DATA_ERROR; -#endif -} - -long ZEXPORT inflateMark(strm) -z_streamp strm; -{ - struct inflate_state FAR *state; - - if (strm == Z_NULL || strm->state == Z_NULL) return -1L << 16; - state = (struct inflate_state FAR *)strm->state; - return ((long)(state->back) << 16) + - (state->mode == COPY ? state->length : - (state->mode == MATCH ? state->was - state->length : 0)); -} diff --git a/deps/zlib/inflate.h b/deps/zlib/inflate.h deleted file mode 100644 index 95f4986d4..000000000 --- a/deps/zlib/inflate.h +++ /dev/null @@ -1,122 +0,0 @@ -/* inflate.h -- internal inflate state definition - * Copyright (C) 1995-2009 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* WARNING: this file should *not* be used by applications. It is - part of the implementation of the compression library and is - subject to change. Applications should only use zlib.h. - */ - -/* define NO_GZIP when compiling if you want to disable gzip header and - trailer decoding by inflate(). NO_GZIP would be used to avoid linking in - the crc code when it is not needed. For shared libraries, gzip decoding - should be left enabled. */ -#ifndef NO_GZIP -# define GUNZIP -#endif - -/* Possible inflate modes between inflate() calls */ -typedef enum { - HEAD, /* i: waiting for magic header */ - FLAGS, /* i: waiting for method and flags (gzip) */ - TIME, /* i: waiting for modification time (gzip) */ - OS, /* i: waiting for extra flags and operating system (gzip) */ - EXLEN, /* i: waiting for extra length (gzip) */ - EXTRA, /* i: waiting for extra bytes (gzip) */ - NAME, /* i: waiting for end of file name (gzip) */ - COMMENT, /* i: waiting for end of comment (gzip) */ - HCRC, /* i: waiting for header crc (gzip) */ - DICTID, /* i: waiting for dictionary check value */ - DICT, /* waiting for inflateSetDictionary() call */ - TYPE, /* i: waiting for type bits, including last-flag bit */ - TYPEDO, /* i: same, but skip check to exit inflate on new block */ - STORED, /* i: waiting for stored size (length and complement) */ - COPY_, /* i/o: same as COPY below, but only first time in */ - COPY, /* i/o: waiting for input or output to copy stored block */ - TABLE, /* i: waiting for dynamic block table lengths */ - LENLENS, /* i: waiting for code length code lengths */ - CODELENS, /* i: waiting for length/lit and distance code lengths */ - LEN_, /* i: same as LEN below, but only first time in */ - LEN, /* i: waiting for length/lit/eob code */ - LENEXT, /* i: waiting for length extra bits */ - DIST, /* i: waiting for distance code */ - DISTEXT, /* i: waiting for distance extra bits */ - MATCH, /* o: waiting for output space to copy string */ - LIT, /* o: waiting for output space to write literal */ - CHECK, /* i: waiting for 32-bit check value */ - LENGTH, /* i: waiting for 32-bit length (gzip) */ - DONE, /* finished check, done -- remain here until reset */ - BAD, /* got a data error -- remain here until reset */ - MEM, /* got an inflate() memory error -- remain here until reset */ - SYNC /* looking for synchronization bytes to restart inflate() */ -} inflate_mode; - -/* - State transitions between above modes - - - (most modes can go to BAD or MEM on error -- not shown for clarity) - - Process header: - HEAD -> (gzip) or (zlib) or (raw) - (gzip) -> FLAGS -> TIME -> OS -> EXLEN -> EXTRA -> NAME -> COMMENT -> - HCRC -> TYPE - (zlib) -> DICTID or TYPE - DICTID -> DICT -> TYPE - (raw) -> TYPEDO - Read deflate blocks: - TYPE -> TYPEDO -> STORED or TABLE or LEN_ or CHECK - STORED -> COPY_ -> COPY -> TYPE - TABLE -> LENLENS -> CODELENS -> LEN_ - LEN_ -> LEN - Read deflate codes in fixed or dynamic block: - LEN -> LENEXT or LIT or TYPE - LENEXT -> DIST -> DISTEXT -> MATCH -> LEN - LIT -> LEN - Process trailer: - CHECK -> LENGTH -> DONE - */ - -/* state maintained between inflate() calls. Approximately 10K bytes. */ -struct inflate_state { - inflate_mode mode; /* current inflate mode */ - int last; /* true if processing last block */ - int wrap; /* bit 0 true for zlib, bit 1 true for gzip */ - int havedict; /* true if dictionary provided */ - int flags; /* gzip header method and flags (0 if zlib) */ - unsigned dmax; /* zlib header max distance (INFLATE_STRICT) */ - unsigned long check; /* protected copy of check value */ - unsigned long total; /* protected copy of output count */ - gz_headerp head; /* where to save gzip header information */ - /* sliding window */ - unsigned wbits; /* log base 2 of requested window size */ - unsigned wsize; /* window size or zero if not using window */ - unsigned whave; /* valid bytes in the window */ - unsigned wnext; /* window write index */ - unsigned char FAR *window; /* allocated sliding window, if needed */ - /* bit accumulator */ - unsigned long hold; /* input bit accumulator */ - unsigned bits; /* number of bits in "in" */ - /* for string and stored block copying */ - unsigned length; /* literal or length of data to copy */ - unsigned offset; /* distance back to copy string from */ - /* for table and code decoding */ - unsigned extra; /* extra bits needed */ - /* fixed and dynamic code tables */ - code const FAR *lencode; /* starting table for length/literal codes */ - code const FAR *distcode; /* starting table for distance codes */ - unsigned lenbits; /* index bits for lencode */ - unsigned distbits; /* index bits for distcode */ - /* dynamic table building */ - unsigned ncode; /* number of code length code lengths */ - unsigned nlen; /* number of length code lengths */ - unsigned ndist; /* number of distance code lengths */ - unsigned have; /* number of code lengths in lens[] */ - code FAR *next; /* next available space in codes[] */ - unsigned short lens[320]; /* temporary storage for code lengths */ - unsigned short work[288]; /* work area for code table building */ - code codes[ENOUGH]; /* space for code tables */ - int sane; /* if false, allow invalid distance too far */ - int back; /* bits back of last unprocessed length/lit */ - unsigned was; /* initial length of match */ -}; diff --git a/deps/zlib/inftrees.c b/deps/zlib/inftrees.c deleted file mode 100644 index 44d89cf24..000000000 --- a/deps/zlib/inftrees.c +++ /dev/null @@ -1,306 +0,0 @@ -/* inftrees.c -- generate Huffman trees for efficient decoding - * Copyright (C) 1995-2013 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -#include "zutil.h" -#include "inftrees.h" - -#define MAXBITS 15 - -const char inflate_copyright[] = - " inflate 1.2.8 Copyright 1995-2013 Mark Adler "; -/* - If you use the zlib library in a product, an acknowledgment is welcome - in the documentation of your product. If for some reason you cannot - include such an acknowledgment, I would appreciate that you keep this - copyright string in the executable of your product. - */ - -/* - Build a set of tables to decode the provided canonical Huffman code. - The code lengths are lens[0..codes-1]. The result starts at *table, - whose indices are 0..2^bits-1. work is a writable array of at least - lens shorts, which is used as a work area. type is the type of code - to be generated, CODES, LENS, or DISTS. On return, zero is success, - -1 is an invalid code, and +1 means that ENOUGH isn't enough. table - on return points to the next available entry's address. bits is the - requested root table index bits, and on return it is the actual root - table index bits. It will differ if the request is greater than the - longest code or if it is less than the shortest code. - */ -int ZLIB_INTERNAL inflate_table(type, lens, codes, table, bits, work) -codetype type; -unsigned short FAR *lens; -unsigned codes; -code FAR * FAR *table; -unsigned FAR *bits; -unsigned short FAR *work; -{ - unsigned len; /* a code's length in bits */ - unsigned sym; /* index of code symbols */ - unsigned min, max; /* minimum and maximum code lengths */ - unsigned root; /* number of index bits for root table */ - unsigned curr; /* number of index bits for current table */ - unsigned drop; /* code bits to drop for sub-table */ - int left; /* number of prefix codes available */ - unsigned used; /* code entries in table used */ - unsigned huff; /* Huffman code */ - unsigned incr; /* for incrementing code, index */ - unsigned fill; /* index for replicating entries */ - unsigned low; /* low bits for current root entry */ - unsigned mask; /* mask for low root bits */ - code here; /* table entry for duplication */ - code FAR *next; /* next available space in table */ - const unsigned short FAR *base; /* base value table to use */ - const unsigned short FAR *extra; /* extra bits table to use */ - int end; /* use base and extra for symbol > end */ - unsigned short count[MAXBITS+1]; /* number of codes of each length */ - unsigned short offs[MAXBITS+1]; /* offsets in table for each length */ - static const unsigned short lbase[31] = { /* Length codes 257..285 base */ - 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, - 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0}; - static const unsigned short lext[31] = { /* Length codes 257..285 extra */ - 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, - 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 72, 78}; - static const unsigned short dbase[32] = { /* Distance codes 0..29 base */ - 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, - 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, - 8193, 12289, 16385, 24577, 0, 0}; - static const unsigned short dext[32] = { /* Distance codes 0..29 extra */ - 16, 16, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, - 23, 23, 24, 24, 25, 25, 26, 26, 27, 27, - 28, 28, 29, 29, 64, 64}; - - /* - Process a set of code lengths to create a canonical Huffman code. The - code lengths are lens[0..codes-1]. Each length corresponds to the - symbols 0..codes-1. The Huffman code is generated by first sorting the - symbols by length from short to long, and retaining the symbol order - for codes with equal lengths. Then the code starts with all zero bits - for the first code of the shortest length, and the codes are integer - increments for the same length, and zeros are appended as the length - increases. For the deflate format, these bits are stored backwards - from their more natural integer increment ordering, and so when the - decoding tables are built in the large loop below, the integer codes - are incremented backwards. - - This routine assumes, but does not check, that all of the entries in - lens[] are in the range 0..MAXBITS. The caller must assure this. - 1..MAXBITS is interpreted as that code length. zero means that that - symbol does not occur in this code. - - The codes are sorted by computing a count of codes for each length, - creating from that a table of starting indices for each length in the - sorted table, and then entering the symbols in order in the sorted - table. The sorted table is work[], with that space being provided by - the caller. - - The length counts are used for other purposes as well, i.e. finding - the minimum and maximum length codes, determining if there are any - codes at all, checking for a valid set of lengths, and looking ahead - at length counts to determine sub-table sizes when building the - decoding tables. - */ - - /* accumulate lengths for codes (assumes lens[] all in 0..MAXBITS) */ - for (len = 0; len <= MAXBITS; len++) - count[len] = 0; - for (sym = 0; sym < codes; sym++) - count[lens[sym]]++; - - /* bound code lengths, force root to be within code lengths */ - root = *bits; - for (max = MAXBITS; max >= 1; max--) - if (count[max] != 0) break; - if (root > max) root = max; - if (max == 0) { /* no symbols to code at all */ - here.op = (unsigned char)64; /* invalid code marker */ - here.bits = (unsigned char)1; - here.val = (unsigned short)0; - *(*table)++ = here; /* make a table to force an error */ - *(*table)++ = here; - *bits = 1; - return 0; /* no symbols, but wait for decoding to report error */ - } - for (min = 1; min < max; min++) - if (count[min] != 0) break; - if (root < min) root = min; - - /* check for an over-subscribed or incomplete set of lengths */ - left = 1; - for (len = 1; len <= MAXBITS; len++) { - left <<= 1; - left -= count[len]; - if (left < 0) return -1; /* over-subscribed */ - } - if (left > 0 && (type == CODES || max != 1)) - return -1; /* incomplete set */ - - /* generate offsets into symbol table for each length for sorting */ - offs[1] = 0; - for (len = 1; len < MAXBITS; len++) - offs[len + 1] = offs[len] + count[len]; - - /* sort symbols by length, by symbol order within each length */ - for (sym = 0; sym < codes; sym++) - if (lens[sym] != 0) work[offs[lens[sym]]++] = (unsigned short)sym; - - /* - Create and fill in decoding tables. In this loop, the table being - filled is at next and has curr index bits. The code being used is huff - with length len. That code is converted to an index by dropping drop - bits off of the bottom. For codes where len is less than drop + curr, - those top drop + curr - len bits are incremented through all values to - fill the table with replicated entries. - - root is the number of index bits for the root table. When len exceeds - root, sub-tables are created pointed to by the root entry with an index - of the low root bits of huff. This is saved in low to check for when a - new sub-table should be started. drop is zero when the root table is - being filled, and drop is root when sub-tables are being filled. - - When a new sub-table is needed, it is necessary to look ahead in the - code lengths to determine what size sub-table is needed. The length - counts are used for this, and so count[] is decremented as codes are - entered in the tables. - - used keeps track of how many table entries have been allocated from the - provided *table space. It is checked for LENS and DIST tables against - the constants ENOUGH_LENS and ENOUGH_DISTS to guard against changes in - the initial root table size constants. See the comments in inftrees.h - for more information. - - sym increments through all symbols, and the loop terminates when - all codes of length max, i.e. all codes, have been processed. This - routine permits incomplete codes, so another loop after this one fills - in the rest of the decoding tables with invalid code markers. - */ - - /* set up for code type */ - switch (type) { - case CODES: - base = extra = work; /* dummy value--not used */ - end = 19; - break; - case LENS: - base = lbase; - base -= 257; - extra = lext; - extra -= 257; - end = 256; - break; - default: /* DISTS */ - base = dbase; - extra = dext; - end = -1; - } - - /* initialize state for loop */ - huff = 0; /* starting code */ - sym = 0; /* starting code symbol */ - len = min; /* starting code length */ - next = *table; /* current table to fill in */ - curr = root; /* current table index bits */ - drop = 0; /* current bits to drop from code for index */ - low = (unsigned)(-1); /* trigger new sub-table when len > root */ - used = 1U << root; /* use root table entries */ - mask = used - 1; /* mask for comparing low */ - - /* check available table space */ - if ((type == LENS && used > ENOUGH_LENS) || - (type == DISTS && used > ENOUGH_DISTS)) - return 1; - - /* process all codes and make table entries */ - for (;;) { - /* create table entry */ - here.bits = (unsigned char)(len - drop); - if ((int)(work[sym]) < end) { - here.op = (unsigned char)0; - here.val = work[sym]; - } - else if ((int)(work[sym]) > end) { - here.op = (unsigned char)(extra[work[sym]]); - here.val = base[work[sym]]; - } - else { - here.op = (unsigned char)(32 + 64); /* end of block */ - here.val = 0; - } - - /* replicate for those indices with low len bits equal to huff */ - incr = 1U << (len - drop); - fill = 1U << curr; - min = fill; /* save offset to next table */ - do { - fill -= incr; - next[(huff >> drop) + fill] = here; - } while (fill != 0); - - /* backwards increment the len-bit code huff */ - incr = 1U << (len - 1); - while (huff & incr) - incr >>= 1; - if (incr != 0) { - huff &= incr - 1; - huff += incr; - } - else - huff = 0; - - /* go to next symbol, update count, len */ - sym++; - if (--(count[len]) == 0) { - if (len == max) break; - len = lens[work[sym]]; - } - - /* create new sub-table if needed */ - if (len > root && (huff & mask) != low) { - /* if first time, transition to sub-tables */ - if (drop == 0) - drop = root; - - /* increment past last table */ - next += min; /* here min is 1 << curr */ - - /* determine length of next table */ - curr = len - drop; - left = (int)(1 << curr); - while (curr + drop < max) { - left -= count[curr + drop]; - if (left <= 0) break; - curr++; - left <<= 1; - } - - /* check for enough space */ - used += 1U << curr; - if ((type == LENS && used > ENOUGH_LENS) || - (type == DISTS && used > ENOUGH_DISTS)) - return 1; - - /* point entry in root table to sub-table */ - low = huff & mask; - (*table)[low].op = (unsigned char)curr; - (*table)[low].bits = (unsigned char)root; - (*table)[low].val = (unsigned short)(next - *table); - } - } - - /* fill in remaining table entry if code is incomplete (guaranteed to have - at most one remaining entry, since if the code is incomplete, the - maximum code length that was allowed to get this far is one bit) */ - if (huff != 0) { - here.op = (unsigned char)64; /* invalid code marker */ - here.bits = (unsigned char)(len - drop); - here.val = (unsigned short)0; - next[huff] = here; - } - - /* set return parameters */ - *table += used; - *bits = root; - return 0; -} diff --git a/deps/zlib/inftrees.h b/deps/zlib/inftrees.h deleted file mode 100644 index baa53a0b1..000000000 --- a/deps/zlib/inftrees.h +++ /dev/null @@ -1,62 +0,0 @@ -/* inftrees.h -- header to use inftrees.c - * Copyright (C) 1995-2005, 2010 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* WARNING: this file should *not* be used by applications. It is - part of the implementation of the compression library and is - subject to change. Applications should only use zlib.h. - */ - -/* Structure for decoding tables. Each entry provides either the - information needed to do the operation requested by the code that - indexed that table entry, or it provides a pointer to another - table that indexes more bits of the code. op indicates whether - the entry is a pointer to another table, a literal, a length or - distance, an end-of-block, or an invalid code. For a table - pointer, the low four bits of op is the number of index bits of - that table. For a length or distance, the low four bits of op - is the number of extra bits to get after the code. bits is - the number of bits in this code or part of the code to drop off - of the bit buffer. val is the actual byte to output in the case - of a literal, the base length or distance, or the offset from - the current table to the next table. Each entry is four bytes. */ -typedef struct { - unsigned char op; /* operation, extra bits, table bits */ - unsigned char bits; /* bits in this part of the code */ - unsigned short val; /* offset in table or code value */ -} code; - -/* op values as set by inflate_table(): - 00000000 - literal - 0000tttt - table link, tttt != 0 is the number of table index bits - 0001eeee - length or distance, eeee is the number of extra bits - 01100000 - end of block - 01000000 - invalid code - */ - -/* Maximum size of the dynamic table. The maximum number of code structures is - 1444, which is the sum of 852 for literal/length codes and 592 for distance - codes. These values were found by exhaustive searches using the program - examples/enough.c found in the zlib distribtution. The arguments to that - program are the number of symbols, the initial root table size, and the - maximum bit length of a code. "enough 286 9 15" for literal/length codes - returns returns 852, and "enough 30 6 15" for distance codes returns 592. - The initial root table size (9 or 6) is found in the fifth argument of the - inflate_table() calls in inflate.c and infback.c. If the root table size is - changed, then these maximum sizes would be need to be recalculated and - updated. */ -#define ENOUGH_LENS 852 -#define ENOUGH_DISTS 592 -#define ENOUGH (ENOUGH_LENS+ENOUGH_DISTS) - -/* Type of code to build for inflate_table() */ -typedef enum { - CODES, - LENS, - DISTS -} codetype; - -int ZLIB_INTERNAL inflate_table OF((codetype type, unsigned short FAR *lens, - unsigned codes, code FAR * FAR *table, - unsigned FAR *bits, unsigned short FAR *work)); diff --git a/deps/zlib/trees.c b/deps/zlib/trees.c deleted file mode 100644 index bb866f012..000000000 --- a/deps/zlib/trees.c +++ /dev/null @@ -1,1226 +0,0 @@ -/* trees.c -- output deflated data using Huffman coding - * Copyright (C) 1995-2012 Jean-loup Gailly - * detect_data_type() function provided freely by Cosmin Truta, 2006 - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* - * ALGORITHM - * - * The "deflation" process uses several Huffman trees. The more - * common source values are represented by shorter bit sequences. - * - * Each code tree is stored in a compressed form which is itself - * a Huffman encoding of the lengths of all the code strings (in - * ascending order by source values). The actual code strings are - * reconstructed from the lengths in the inflate process, as described - * in the deflate specification. - * - * REFERENCES - * - * Deutsch, L.P.,"'Deflate' Compressed Data Format Specification". - * Available in ftp.uu.net:/pub/archiving/zip/doc/deflate-1.1.doc - * - * Storer, James A. - * Data Compression: Methods and Theory, pp. 49-50. - * Computer Science Press, 1988. ISBN 0-7167-8156-5. - * - * Sedgewick, R. - * Algorithms, p290. - * Addison-Wesley, 1983. ISBN 0-201-06672-6. - */ - -/* @(#) $Id$ */ - -/* #define GEN_TREES_H */ - -#include "deflate.h" - -#ifdef DEBUG -# include -#endif - -/* =========================================================================== - * Constants - */ - -#define MAX_BL_BITS 7 -/* Bit length codes must not exceed MAX_BL_BITS bits */ - -#define END_BLOCK 256 -/* end of block literal code */ - -#define REP_3_6 16 -/* repeat previous bit length 3-6 times (2 bits of repeat count) */ - -#define REPZ_3_10 17 -/* repeat a zero length 3-10 times (3 bits of repeat count) */ - -#define REPZ_11_138 18 -/* repeat a zero length 11-138 times (7 bits of repeat count) */ - -local const int extra_lbits[LENGTH_CODES] /* extra bits for each length code */ - = {0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0}; - -local const int extra_dbits[D_CODES] /* extra bits for each distance code */ - = {0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13}; - -local const int extra_blbits[BL_CODES]/* extra bits for each bit length code */ - = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7}; - -local const uch bl_order[BL_CODES] - = {16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15}; -/* The lengths of the bit length codes are sent in order of decreasing - * probability, to avoid transmitting the lengths for unused bit length codes. - */ - -/* =========================================================================== - * Local data. These are initialized only once. - */ - -#define DIST_CODE_LEN 512 /* see definition of array dist_code below */ - -#if defined(GEN_TREES_H) || !defined(STDC) -/* non ANSI compilers may not accept trees.h */ - -local ct_data static_ltree[L_CODES+2]; -/* The static literal tree. Since the bit lengths are imposed, there is no - * need for the L_CODES extra codes used during heap construction. However - * The codes 286 and 287 are needed to build a canonical tree (see _tr_init - * below). - */ - -local ct_data static_dtree[D_CODES]; -/* The static distance tree. (Actually a trivial tree since all codes use - * 5 bits.) - */ - -uch _dist_code[DIST_CODE_LEN]; -/* Distance codes. The first 256 values correspond to the distances - * 3 .. 258, the last 256 values correspond to the top 8 bits of - * the 15 bit distances. - */ - -uch _length_code[MAX_MATCH-MIN_MATCH+1]; -/* length code for each normalized match length (0 == MIN_MATCH) */ - -local int base_length[LENGTH_CODES]; -/* First normalized length for each code (0 = MIN_MATCH) */ - -local int base_dist[D_CODES]; -/* First normalized distance for each code (0 = distance of 1) */ - -#else -# include "trees.h" -#endif /* GEN_TREES_H */ - -struct static_tree_desc_s { - const ct_data *static_tree; /* static tree or NULL */ - const intf *extra_bits; /* extra bits for each code or NULL */ - int extra_base; /* base index for extra_bits */ - int elems; /* max number of elements in the tree */ - int max_length; /* max bit length for the codes */ -}; - -local static_tree_desc static_l_desc = -{static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS}; - -local static_tree_desc static_d_desc = -{static_dtree, extra_dbits, 0, D_CODES, MAX_BITS}; - -local static_tree_desc static_bl_desc = -{(const ct_data *)0, extra_blbits, 0, BL_CODES, MAX_BL_BITS}; - -/* =========================================================================== - * Local (static) routines in this file. - */ - -local void tr_static_init OF((void)); -local void init_block OF((deflate_state *s)); -local void pqdownheap OF((deflate_state *s, ct_data *tree, int k)); -local void gen_bitlen OF((deflate_state *s, tree_desc *desc)); -local void gen_codes OF((ct_data *tree, int max_code, ushf *bl_count)); -local void build_tree OF((deflate_state *s, tree_desc *desc)); -local void scan_tree OF((deflate_state *s, ct_data *tree, int max_code)); -local void send_tree OF((deflate_state *s, ct_data *tree, int max_code)); -local int build_bl_tree OF((deflate_state *s)); -local void send_all_trees OF((deflate_state *s, int lcodes, int dcodes, - int blcodes)); -local void compress_block OF((deflate_state *s, const ct_data *ltree, - const ct_data *dtree)); -local int detect_data_type OF((deflate_state *s)); -local unsigned bi_reverse OF((unsigned value, int length)); -local void bi_windup OF((deflate_state *s)); -local void bi_flush OF((deflate_state *s)); -local void copy_block OF((deflate_state *s, charf *buf, unsigned len, - int header)); - -#ifdef GEN_TREES_H -local void gen_trees_header OF((void)); -#endif - -#ifndef DEBUG -# define send_code(s, c, tree) send_bits(s, tree[c].Code, tree[c].Len) - /* Send a code of the given tree. c and tree must not have side effects */ - -#else /* DEBUG */ -# define send_code(s, c, tree) \ - { if (z_verbose>2) fprintf(stderr,"\ncd %3d ",(c)); \ - send_bits(s, tree[c].Code, tree[c].Len); } -#endif - -/* =========================================================================== - * Output a short LSB first on the stream. - * IN assertion: there is enough room in pendingBuf. - */ -#define put_short(s, w) { \ - put_byte(s, (uch)((w) & 0xff)); \ - put_byte(s, (uch)((ush)(w) >> 8)); \ -} - -/* =========================================================================== - * Send a value on a given number of bits. - * IN assertion: length <= 16 and value fits in length bits. - */ -#ifdef DEBUG -local void send_bits OF((deflate_state *s, int value, int length)); - -local void send_bits(s, value, length) - deflate_state *s; - int value; /* value to send */ - int length; /* number of bits */ -{ - Tracevv((stderr," l %2d v %4x ", length, value)); - Assert(length > 0 && length <= 15, "invalid length"); - s->bits_sent += (ulg)length; - - /* If not enough room in bi_buf, use (valid) bits from bi_buf and - * (16 - bi_valid) bits from value, leaving (width - (16-bi_valid)) - * unused bits in value. - */ - if (s->bi_valid > (int)Buf_size - length) { - s->bi_buf |= (ush)value << s->bi_valid; - put_short(s, s->bi_buf); - s->bi_buf = (ush)value >> (Buf_size - s->bi_valid); - s->bi_valid += length - Buf_size; - } else { - s->bi_buf |= (ush)value << s->bi_valid; - s->bi_valid += length; - } -} -#else /* !DEBUG */ - -#define send_bits(s, value, length) \ -{ int len = length;\ - if (s->bi_valid > (int)Buf_size - len) {\ - int val = value;\ - s->bi_buf |= (ush)val << s->bi_valid;\ - put_short(s, s->bi_buf);\ - s->bi_buf = (ush)val >> (Buf_size - s->bi_valid);\ - s->bi_valid += len - Buf_size;\ - } else {\ - s->bi_buf |= (ush)(value) << s->bi_valid;\ - s->bi_valid += len;\ - }\ -} -#endif /* DEBUG */ - - -/* the arguments must not have side effects */ - -/* =========================================================================== - * Initialize the various 'constant' tables. - */ -local void tr_static_init() -{ -#if defined(GEN_TREES_H) || !defined(STDC) - static int static_init_done = 0; - int n; /* iterates over tree elements */ - int bits; /* bit counter */ - int length; /* length value */ - int code; /* code value */ - int dist; /* distance index */ - ush bl_count[MAX_BITS+1]; - /* number of codes at each bit length for an optimal tree */ - - if (static_init_done) return; - - /* For some embedded targets, global variables are not initialized: */ -#ifdef NO_INIT_GLOBAL_POINTERS - static_l_desc.static_tree = static_ltree; - static_l_desc.extra_bits = extra_lbits; - static_d_desc.static_tree = static_dtree; - static_d_desc.extra_bits = extra_dbits; - static_bl_desc.extra_bits = extra_blbits; -#endif - - /* Initialize the mapping length (0..255) -> length code (0..28) */ - length = 0; - for (code = 0; code < LENGTH_CODES-1; code++) { - base_length[code] = length; - for (n = 0; n < (1< dist code (0..29) */ - dist = 0; - for (code = 0 ; code < 16; code++) { - base_dist[code] = dist; - for (n = 0; n < (1<>= 7; /* from now on, all distances are divided by 128 */ - for ( ; code < D_CODES; code++) { - base_dist[code] = dist << 7; - for (n = 0; n < (1<<(extra_dbits[code]-7)); n++) { - _dist_code[256 + dist++] = (uch)code; - } - } - Assert (dist == 256, "tr_static_init: 256+dist != 512"); - - /* Construct the codes of the static literal tree */ - for (bits = 0; bits <= MAX_BITS; bits++) bl_count[bits] = 0; - n = 0; - while (n <= 143) static_ltree[n++].Len = 8, bl_count[8]++; - while (n <= 255) static_ltree[n++].Len = 9, bl_count[9]++; - while (n <= 279) static_ltree[n++].Len = 7, bl_count[7]++; - while (n <= 287) static_ltree[n++].Len = 8, bl_count[8]++; - /* Codes 286 and 287 do not exist, but we must include them in the - * tree construction to get a canonical Huffman tree (longest code - * all ones) - */ - gen_codes((ct_data *)static_ltree, L_CODES+1, bl_count); - - /* The static distance tree is trivial: */ - for (n = 0; n < D_CODES; n++) { - static_dtree[n].Len = 5; - static_dtree[n].Code = bi_reverse((unsigned)n, 5); - } - static_init_done = 1; - -# ifdef GEN_TREES_H - gen_trees_header(); -# endif -#endif /* defined(GEN_TREES_H) || !defined(STDC) */ -} - -/* =========================================================================== - * Genererate the file trees.h describing the static trees. - */ -#ifdef GEN_TREES_H -# ifndef DEBUG -# include -# endif - -# define SEPARATOR(i, last, width) \ - ((i) == (last)? "\n};\n\n" : \ - ((i) % (width) == (width)-1 ? ",\n" : ", ")) - -void gen_trees_header() -{ - FILE *header = fopen("trees.h", "w"); - int i; - - Assert (header != NULL, "Can't open trees.h"); - fprintf(header, - "/* header created automatically with -DGEN_TREES_H */\n\n"); - - fprintf(header, "local const ct_data static_ltree[L_CODES+2] = {\n"); - for (i = 0; i < L_CODES+2; i++) { - fprintf(header, "{{%3u},{%3u}}%s", static_ltree[i].Code, - static_ltree[i].Len, SEPARATOR(i, L_CODES+1, 5)); - } - - fprintf(header, "local const ct_data static_dtree[D_CODES] = {\n"); - for (i = 0; i < D_CODES; i++) { - fprintf(header, "{{%2u},{%2u}}%s", static_dtree[i].Code, - static_dtree[i].Len, SEPARATOR(i, D_CODES-1, 5)); - } - - fprintf(header, "const uch ZLIB_INTERNAL _dist_code[DIST_CODE_LEN] = {\n"); - for (i = 0; i < DIST_CODE_LEN; i++) { - fprintf(header, "%2u%s", _dist_code[i], - SEPARATOR(i, DIST_CODE_LEN-1, 20)); - } - - fprintf(header, - "const uch ZLIB_INTERNAL _length_code[MAX_MATCH-MIN_MATCH+1]= {\n"); - for (i = 0; i < MAX_MATCH-MIN_MATCH+1; i++) { - fprintf(header, "%2u%s", _length_code[i], - SEPARATOR(i, MAX_MATCH-MIN_MATCH, 20)); - } - - fprintf(header, "local const int base_length[LENGTH_CODES] = {\n"); - for (i = 0; i < LENGTH_CODES; i++) { - fprintf(header, "%1u%s", base_length[i], - SEPARATOR(i, LENGTH_CODES-1, 20)); - } - - fprintf(header, "local const int base_dist[D_CODES] = {\n"); - for (i = 0; i < D_CODES; i++) { - fprintf(header, "%5u%s", base_dist[i], - SEPARATOR(i, D_CODES-1, 10)); - } - - fclose(header); -} -#endif /* GEN_TREES_H */ - -/* =========================================================================== - * Initialize the tree data structures for a new zlib stream. - */ -void ZLIB_INTERNAL _tr_init(s) - deflate_state *s; -{ - tr_static_init(); - - s->l_desc.dyn_tree = s->dyn_ltree; - s->l_desc.stat_desc = &static_l_desc; - - s->d_desc.dyn_tree = s->dyn_dtree; - s->d_desc.stat_desc = &static_d_desc; - - s->bl_desc.dyn_tree = s->bl_tree; - s->bl_desc.stat_desc = &static_bl_desc; - - s->bi_buf = 0; - s->bi_valid = 0; -#ifdef DEBUG - s->compressed_len = 0L; - s->bits_sent = 0L; -#endif - - /* Initialize the first block of the first file: */ - init_block(s); -} - -/* =========================================================================== - * Initialize a new block. - */ -local void init_block(s) - deflate_state *s; -{ - int n; /* iterates over tree elements */ - - /* Initialize the trees. */ - for (n = 0; n < L_CODES; n++) s->dyn_ltree[n].Freq = 0; - for (n = 0; n < D_CODES; n++) s->dyn_dtree[n].Freq = 0; - for (n = 0; n < BL_CODES; n++) s->bl_tree[n].Freq = 0; - - s->dyn_ltree[END_BLOCK].Freq = 1; - s->opt_len = s->static_len = 0L; - s->last_lit = s->matches = 0; -} - -#define SMALLEST 1 -/* Index within the heap array of least frequent node in the Huffman tree */ - - -/* =========================================================================== - * Remove the smallest element from the heap and recreate the heap with - * one less element. Updates heap and heap_len. - */ -#define pqremove(s, tree, top) \ -{\ - top = s->heap[SMALLEST]; \ - s->heap[SMALLEST] = s->heap[s->heap_len--]; \ - pqdownheap(s, tree, SMALLEST); \ -} - -/* =========================================================================== - * Compares to subtrees, using the tree depth as tie breaker when - * the subtrees have equal frequency. This minimizes the worst case length. - */ -#define smaller(tree, n, m, depth) \ - (tree[n].Freq < tree[m].Freq || \ - (tree[n].Freq == tree[m].Freq && depth[n] <= depth[m])) - -/* =========================================================================== - * Restore the heap property by moving down the tree starting at node k, - * exchanging a node with the smallest of its two sons if necessary, stopping - * when the heap property is re-established (each father smaller than its - * two sons). - */ -local void pqdownheap(s, tree, k) - deflate_state *s; - ct_data *tree; /* the tree to restore */ - int k; /* node to move down */ -{ - int v = s->heap[k]; - int j = k << 1; /* left son of k */ - while (j <= s->heap_len) { - /* Set j to the smallest of the two sons: */ - if (j < s->heap_len && - smaller(tree, s->heap[j+1], s->heap[j], s->depth)) { - j++; - } - /* Exit if v is smaller than both sons */ - if (smaller(tree, v, s->heap[j], s->depth)) break; - - /* Exchange v with the smallest son */ - s->heap[k] = s->heap[j]; k = j; - - /* And continue down the tree, setting j to the left son of k */ - j <<= 1; - } - s->heap[k] = v; -} - -/* =========================================================================== - * Compute the optimal bit lengths for a tree and update the total bit length - * for the current block. - * IN assertion: the fields freq and dad are set, heap[heap_max] and - * above are the tree nodes sorted by increasing frequency. - * OUT assertions: the field len is set to the optimal bit length, the - * array bl_count contains the frequencies for each bit length. - * The length opt_len is updated; static_len is also updated if stree is - * not null. - */ -local void gen_bitlen(s, desc) - deflate_state *s; - tree_desc *desc; /* the tree descriptor */ -{ - ct_data *tree = desc->dyn_tree; - int max_code = desc->max_code; - const ct_data *stree = desc->stat_desc->static_tree; - const intf *extra = desc->stat_desc->extra_bits; - int base = desc->stat_desc->extra_base; - int max_length = desc->stat_desc->max_length; - int h; /* heap index */ - int n, m; /* iterate over the tree elements */ - int bits; /* bit length */ - int xbits; /* extra bits */ - ush f; /* frequency */ - int overflow = 0; /* number of elements with bit length too large */ - - for (bits = 0; bits <= MAX_BITS; bits++) s->bl_count[bits] = 0; - - /* In a first pass, compute the optimal bit lengths (which may - * overflow in the case of the bit length tree). - */ - tree[s->heap[s->heap_max]].Len = 0; /* root of the heap */ - - for (h = s->heap_max+1; h < HEAP_SIZE; h++) { - n = s->heap[h]; - bits = tree[tree[n].Dad].Len + 1; - if (bits > max_length) bits = max_length, overflow++; - tree[n].Len = (ush)bits; - /* We overwrite tree[n].Dad which is no longer needed */ - - if (n > max_code) continue; /* not a leaf node */ - - s->bl_count[bits]++; - xbits = 0; - if (n >= base) xbits = extra[n-base]; - f = tree[n].Freq; - s->opt_len += (ulg)f * (bits + xbits); - if (stree) s->static_len += (ulg)f * (stree[n].Len + xbits); - } - if (overflow == 0) return; - - Trace((stderr,"\nbit length overflow\n")); - /* This happens for example on obj2 and pic of the Calgary corpus */ - - /* Find the first bit length which could increase: */ - do { - bits = max_length-1; - while (s->bl_count[bits] == 0) bits--; - s->bl_count[bits]--; /* move one leaf down the tree */ - s->bl_count[bits+1] += 2; /* move one overflow item as its brother */ - s->bl_count[max_length]--; - /* The brother of the overflow item also moves one step up, - * but this does not affect bl_count[max_length] - */ - overflow -= 2; - } while (overflow > 0); - - /* Now recompute all bit lengths, scanning in increasing frequency. - * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all - * lengths instead of fixing only the wrong ones. This idea is taken - * from 'ar' written by Haruhiko Okumura.) - */ - for (bits = max_length; bits != 0; bits--) { - n = s->bl_count[bits]; - while (n != 0) { - m = s->heap[--h]; - if (m > max_code) continue; - if ((unsigned) tree[m].Len != (unsigned) bits) { - Trace((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits)); - s->opt_len += ((long)bits - (long)tree[m].Len) - *(long)tree[m].Freq; - tree[m].Len = (ush)bits; - } - n--; - } - } -} - -/* =========================================================================== - * Generate the codes for a given tree and bit counts (which need not be - * optimal). - * IN assertion: the array bl_count contains the bit length statistics for - * the given tree and the field len is set for all tree elements. - * OUT assertion: the field code is set for all tree elements of non - * zero code length. - */ -local void gen_codes (tree, max_code, bl_count) - ct_data *tree; /* the tree to decorate */ - int max_code; /* largest code with non zero frequency */ - ushf *bl_count; /* number of codes at each bit length */ -{ - ush next_code[MAX_BITS+1]; /* next code value for each bit length */ - ush code = 0; /* running code value */ - int bits; /* bit index */ - int n; /* code index */ - - /* The distribution counts are first used to generate the code values - * without bit reversal. - */ - for (bits = 1; bits <= MAX_BITS; bits++) { - next_code[bits] = code = (code + bl_count[bits-1]) << 1; - } - /* Check that the bit counts in bl_count are consistent. The last code - * must be all ones. - */ - Assert (code + bl_count[MAX_BITS]-1 == (1<dyn_tree; - const ct_data *stree = desc->stat_desc->static_tree; - int elems = desc->stat_desc->elems; - int n, m; /* iterate over heap elements */ - int max_code = -1; /* largest code with non zero frequency */ - int node; /* new node being created */ - - /* Construct the initial heap, with least frequent element in - * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1]. - * heap[0] is not used. - */ - s->heap_len = 0, s->heap_max = HEAP_SIZE; - - for (n = 0; n < elems; n++) { - if (tree[n].Freq != 0) { - s->heap[++(s->heap_len)] = max_code = n; - s->depth[n] = 0; - } else { - tree[n].Len = 0; - } - } - - /* The pkzip format requires that at least one distance code exists, - * and that at least one bit should be sent even if there is only one - * possible code. So to avoid special checks later on we force at least - * two codes of non zero frequency. - */ - while (s->heap_len < 2) { - node = s->heap[++(s->heap_len)] = (max_code < 2 ? ++max_code : 0); - tree[node].Freq = 1; - s->depth[node] = 0; - s->opt_len--; if (stree) s->static_len -= stree[node].Len; - /* node is 0 or 1 so it does not have extra bits */ - } - desc->max_code = max_code; - - /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree, - * establish sub-heaps of increasing lengths: - */ - for (n = s->heap_len/2; n >= 1; n--) pqdownheap(s, tree, n); - - /* Construct the Huffman tree by repeatedly combining the least two - * frequent nodes. - */ - node = elems; /* next internal node of the tree */ - do { - pqremove(s, tree, n); /* n = node of least frequency */ - m = s->heap[SMALLEST]; /* m = node of next least frequency */ - - s->heap[--(s->heap_max)] = n; /* keep the nodes sorted by frequency */ - s->heap[--(s->heap_max)] = m; - - /* Create a new node father of n and m */ - tree[node].Freq = tree[n].Freq + tree[m].Freq; - s->depth[node] = (uch)((s->depth[n] >= s->depth[m] ? - s->depth[n] : s->depth[m]) + 1); - tree[n].Dad = tree[m].Dad = (ush)node; -#ifdef DUMP_BL_TREE - if (tree == s->bl_tree) { - fprintf(stderr,"\nnode %d(%d), sons %d(%d) %d(%d)", - node, tree[node].Freq, n, tree[n].Freq, m, tree[m].Freq); - } -#endif - /* and insert the new node in the heap */ - s->heap[SMALLEST] = node++; - pqdownheap(s, tree, SMALLEST); - - } while (s->heap_len >= 2); - - s->heap[--(s->heap_max)] = s->heap[SMALLEST]; - - /* At this point, the fields freq and dad are set. We can now - * generate the bit lengths. - */ - gen_bitlen(s, (tree_desc *)desc); - - /* The field len is now set, we can generate the bit codes */ - gen_codes ((ct_data *)tree, max_code, s->bl_count); -} - -/* =========================================================================== - * Scan a literal or distance tree to determine the frequencies of the codes - * in the bit length tree. - */ -local void scan_tree (s, tree, max_code) - deflate_state *s; - ct_data *tree; /* the tree to be scanned */ - int max_code; /* and its largest code of non zero frequency */ -{ - int n; /* iterates over all tree elements */ - int prevlen = -1; /* last emitted length */ - int curlen; /* length of current code */ - int nextlen = tree[0].Len; /* length of next code */ - int count = 0; /* repeat count of the current code */ - int max_count = 7; /* max repeat count */ - int min_count = 4; /* min repeat count */ - - if (nextlen == 0) max_count = 138, min_count = 3; - tree[max_code+1].Len = (ush)0xffff; /* guard */ - - for (n = 0; n <= max_code; n++) { - curlen = nextlen; nextlen = tree[n+1].Len; - if (++count < max_count && curlen == nextlen) { - continue; - } else if (count < min_count) { - s->bl_tree[curlen].Freq += (ush)count; - } else if (curlen != 0) { - if (curlen != prevlen) s->bl_tree[curlen].Freq++; - s->bl_tree[REP_3_6].Freq++; - } else if (count <= 10) { - s->bl_tree[REPZ_3_10].Freq++; - } else { - s->bl_tree[REPZ_11_138].Freq++; - } - count = 0; prevlen = curlen; - if (nextlen == 0) { - max_count = 138, min_count = 3; - } else if (curlen == nextlen) { - max_count = 6, min_count = 3; - } else { - max_count = 7, min_count = 4; - } - } -} - -/* =========================================================================== - * Send a literal or distance tree in compressed form, using the codes in - * bl_tree. - */ -local void send_tree (s, tree, max_code) - deflate_state *s; - ct_data *tree; /* the tree to be scanned */ - int max_code; /* and its largest code of non zero frequency */ -{ - int n; /* iterates over all tree elements */ - int prevlen = -1; /* last emitted length */ - int curlen; /* length of current code */ - int nextlen = tree[0].Len; /* length of next code */ - int count = 0; /* repeat count of the current code */ - int max_count = 7; /* max repeat count */ - int min_count = 4; /* min repeat count */ - - /* tree[max_code+1].Len = -1; */ /* guard already set */ - if (nextlen == 0) max_count = 138, min_count = 3; - - for (n = 0; n <= max_code; n++) { - curlen = nextlen; nextlen = tree[n+1].Len; - if (++count < max_count && curlen == nextlen) { - continue; - } else if (count < min_count) { - do { send_code(s, curlen, s->bl_tree); } while (--count != 0); - - } else if (curlen != 0) { - if (curlen != prevlen) { - send_code(s, curlen, s->bl_tree); count--; - } - Assert(count >= 3 && count <= 6, " 3_6?"); - send_code(s, REP_3_6, s->bl_tree); send_bits(s, count-3, 2); - - } else if (count <= 10) { - send_code(s, REPZ_3_10, s->bl_tree); send_bits(s, count-3, 3); - - } else { - send_code(s, REPZ_11_138, s->bl_tree); send_bits(s, count-11, 7); - } - count = 0; prevlen = curlen; - if (nextlen == 0) { - max_count = 138, min_count = 3; - } else if (curlen == nextlen) { - max_count = 6, min_count = 3; - } else { - max_count = 7, min_count = 4; - } - } -} - -/* =========================================================================== - * Construct the Huffman tree for the bit lengths and return the index in - * bl_order of the last bit length code to send. - */ -local int build_bl_tree(s) - deflate_state *s; -{ - int max_blindex; /* index of last bit length code of non zero freq */ - - /* Determine the bit length frequencies for literal and distance trees */ - scan_tree(s, (ct_data *)s->dyn_ltree, s->l_desc.max_code); - scan_tree(s, (ct_data *)s->dyn_dtree, s->d_desc.max_code); - - /* Build the bit length tree: */ - build_tree(s, (tree_desc *)(&(s->bl_desc))); - /* opt_len now includes the length of the tree representations, except - * the lengths of the bit lengths codes and the 5+5+4 bits for the counts. - */ - - /* Determine the number of bit length codes to send. The pkzip format - * requires that at least 4 bit length codes be sent. (appnote.txt says - * 3 but the actual value used is 4.) - */ - for (max_blindex = BL_CODES-1; max_blindex >= 3; max_blindex--) { - if (s->bl_tree[bl_order[max_blindex]].Len != 0) break; - } - /* Update opt_len to include the bit length tree and counts */ - s->opt_len += 3*(max_blindex+1) + 5+5+4; - Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld", - s->opt_len, s->static_len)); - - return max_blindex; -} - -/* =========================================================================== - * Send the header for a block using dynamic Huffman trees: the counts, the - * lengths of the bit length codes, the literal tree and the distance tree. - * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4. - */ -local void send_all_trees(s, lcodes, dcodes, blcodes) - deflate_state *s; - int lcodes, dcodes, blcodes; /* number of codes for each tree */ -{ - int rank; /* index in bl_order */ - - Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes"); - Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES, - "too many codes"); - Tracev((stderr, "\nbl counts: ")); - send_bits(s, lcodes-257, 5); /* not +255 as stated in appnote.txt */ - send_bits(s, dcodes-1, 5); - send_bits(s, blcodes-4, 4); /* not -3 as stated in appnote.txt */ - for (rank = 0; rank < blcodes; rank++) { - Tracev((stderr, "\nbl code %2d ", bl_order[rank])); - send_bits(s, s->bl_tree[bl_order[rank]].Len, 3); - } - Tracev((stderr, "\nbl tree: sent %ld", s->bits_sent)); - - send_tree(s, (ct_data *)s->dyn_ltree, lcodes-1); /* literal tree */ - Tracev((stderr, "\nlit tree: sent %ld", s->bits_sent)); - - send_tree(s, (ct_data *)s->dyn_dtree, dcodes-1); /* distance tree */ - Tracev((stderr, "\ndist tree: sent %ld", s->bits_sent)); -} - -/* =========================================================================== - * Send a stored block - */ -void ZLIB_INTERNAL _tr_stored_block(s, buf, stored_len, last) - deflate_state *s; - charf *buf; /* input block */ - ulg stored_len; /* length of input block */ - int last; /* one if this is the last block for a file */ -{ - send_bits(s, (STORED_BLOCK<<1)+last, 3); /* send block type */ -#ifdef DEBUG - s->compressed_len = (s->compressed_len + 3 + 7) & (ulg)~7L; - s->compressed_len += (stored_len + 4) << 3; -#endif - copy_block(s, buf, (unsigned)stored_len, 1); /* with header */ -} - -/* =========================================================================== - * Flush the bits in the bit buffer to pending output (leaves at most 7 bits) - */ -void ZLIB_INTERNAL _tr_flush_bits(s) - deflate_state *s; -{ - bi_flush(s); -} - -/* =========================================================================== - * Send one empty static block to give enough lookahead for inflate. - * This takes 10 bits, of which 7 may remain in the bit buffer. - */ -void ZLIB_INTERNAL _tr_align(s) - deflate_state *s; -{ - send_bits(s, STATIC_TREES<<1, 3); - send_code(s, END_BLOCK, static_ltree); -#ifdef DEBUG - s->compressed_len += 10L; /* 3 for block type, 7 for EOB */ -#endif - bi_flush(s); -} - -/* =========================================================================== - * Determine the best encoding for the current block: dynamic trees, static - * trees or store, and output the encoded block to the zip file. - */ -void ZLIB_INTERNAL _tr_flush_block(s, buf, stored_len, last) - deflate_state *s; - charf *buf; /* input block, or NULL if too old */ - ulg stored_len; /* length of input block */ - int last; /* one if this is the last block for a file */ -{ - ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */ - int max_blindex = 0; /* index of last bit length code of non zero freq */ - - /* Build the Huffman trees unless a stored block is forced */ - if (s->level > 0) { - - /* Check if the file is binary or text */ - if (s->strm->data_type == Z_UNKNOWN) - s->strm->data_type = detect_data_type(s); - - /* Construct the literal and distance trees */ - build_tree(s, (tree_desc *)(&(s->l_desc))); - Tracev((stderr, "\nlit data: dyn %ld, stat %ld", s->opt_len, - s->static_len)); - - build_tree(s, (tree_desc *)(&(s->d_desc))); - Tracev((stderr, "\ndist data: dyn %ld, stat %ld", s->opt_len, - s->static_len)); - /* At this point, opt_len and static_len are the total bit lengths of - * the compressed block data, excluding the tree representations. - */ - - /* Build the bit length tree for the above two trees, and get the index - * in bl_order of the last bit length code to send. - */ - max_blindex = build_bl_tree(s); - - /* Determine the best encoding. Compute the block lengths in bytes. */ - opt_lenb = (s->opt_len+3+7)>>3; - static_lenb = (s->static_len+3+7)>>3; - - Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ", - opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len, - s->last_lit)); - - if (static_lenb <= opt_lenb) opt_lenb = static_lenb; - - } else { - Assert(buf != (char*)0, "lost buf"); - opt_lenb = static_lenb = stored_len + 5; /* force a stored block */ - } - -#ifdef FORCE_STORED - if (buf != (char*)0) { /* force stored block */ -#else - if (stored_len+4 <= opt_lenb && buf != (char*)0) { - /* 4: two words for the lengths */ -#endif - /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE. - * Otherwise we can't have processed more than WSIZE input bytes since - * the last block flush, because compression would have been - * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to - * transform a block into a stored block. - */ - _tr_stored_block(s, buf, stored_len, last); - -#ifdef FORCE_STATIC - } else if (static_lenb >= 0) { /* force static trees */ -#else - } else if (s->strategy == Z_FIXED || static_lenb == opt_lenb) { -#endif - send_bits(s, (STATIC_TREES<<1)+last, 3); - compress_block(s, (const ct_data *)static_ltree, - (const ct_data *)static_dtree); -#ifdef DEBUG - s->compressed_len += 3 + s->static_len; -#endif - } else { - send_bits(s, (DYN_TREES<<1)+last, 3); - send_all_trees(s, s->l_desc.max_code+1, s->d_desc.max_code+1, - max_blindex+1); - compress_block(s, (const ct_data *)s->dyn_ltree, - (const ct_data *)s->dyn_dtree); -#ifdef DEBUG - s->compressed_len += 3 + s->opt_len; -#endif - } - Assert (s->compressed_len == s->bits_sent, "bad compressed size"); - /* The above check is made mod 2^32, for files larger than 512 MB - * and uLong implemented on 32 bits. - */ - init_block(s); - - if (last) { - bi_windup(s); -#ifdef DEBUG - s->compressed_len += 7; /* align on byte boundary */ -#endif - } - Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len>>3, - s->compressed_len-7*last)); -} - -/* =========================================================================== - * Save the match info and tally the frequency counts. Return true if - * the current block must be flushed. - */ -int ZLIB_INTERNAL _tr_tally (s, dist, lc) - deflate_state *s; - unsigned dist; /* distance of matched string */ - unsigned lc; /* match length-MIN_MATCH or unmatched char (if dist==0) */ -{ - s->d_buf[s->last_lit] = (ush)dist; - s->l_buf[s->last_lit++] = (uch)lc; - if (dist == 0) { - /* lc is the unmatched char */ - s->dyn_ltree[lc].Freq++; - } else { - s->matches++; - /* Here, lc is the match length - MIN_MATCH */ - dist--; /* dist = match distance - 1 */ - Assert((ush)dist < (ush)MAX_DIST(s) && - (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) && - (ush)d_code(dist) < (ush)D_CODES, "_tr_tally: bad match"); - - s->dyn_ltree[_length_code[lc]+LITERALS+1].Freq++; - s->dyn_dtree[d_code(dist)].Freq++; - } - -#ifdef TRUNCATE_BLOCK - /* Try to guess if it is profitable to stop the current block here */ - if ((s->last_lit & 0x1fff) == 0 && s->level > 2) { - /* Compute an upper bound for the compressed length */ - ulg out_length = (ulg)s->last_lit*8L; - ulg in_length = (ulg)((long)s->strstart - s->block_start); - int dcode; - for (dcode = 0; dcode < D_CODES; dcode++) { - out_length += (ulg)s->dyn_dtree[dcode].Freq * - (5L+extra_dbits[dcode]); - } - out_length >>= 3; - Tracev((stderr,"\nlast_lit %u, in %ld, out ~%ld(%ld%%) ", - s->last_lit, in_length, out_length, - 100L - out_length*100L/in_length)); - if (s->matches < s->last_lit/2 && out_length < in_length/2) return 1; - } -#endif - return (s->last_lit == s->lit_bufsize-1); - /* We avoid equality with lit_bufsize because of wraparound at 64K - * on 16 bit machines and because stored blocks are restricted to - * 64K-1 bytes. - */ -} - -/* =========================================================================== - * Send the block data compressed using the given Huffman trees - */ -local void compress_block(s, ltree, dtree) - deflate_state *s; - const ct_data *ltree; /* literal tree */ - const ct_data *dtree; /* distance tree */ -{ - unsigned dist; /* distance of matched string */ - int lc; /* match length or unmatched char (if dist == 0) */ - unsigned lx = 0; /* running index in l_buf */ - unsigned code; /* the code to send */ - int extra; /* number of extra bits to send */ - - if (s->last_lit != 0) do { - dist = s->d_buf[lx]; - lc = s->l_buf[lx++]; - if (dist == 0) { - send_code(s, lc, ltree); /* send a literal byte */ - Tracecv(isgraph(lc), (stderr," '%c' ", lc)); - } else { - /* Here, lc is the match length - MIN_MATCH */ - code = _length_code[lc]; - send_code(s, code+LITERALS+1, ltree); /* send the length code */ - extra = extra_lbits[code]; - if (extra != 0) { - lc -= base_length[code]; - send_bits(s, lc, extra); /* send the extra length bits */ - } - dist--; /* dist is now the match distance - 1 */ - code = d_code(dist); - Assert (code < D_CODES, "bad d_code"); - - send_code(s, code, dtree); /* send the distance code */ - extra = extra_dbits[code]; - if (extra != 0) { - dist -= base_dist[code]; - send_bits(s, dist, extra); /* send the extra distance bits */ - } - } /* literal or match pair ? */ - - /* Check that the overlay between pending_buf and d_buf+l_buf is ok: */ - Assert((uInt)(s->pending) < s->lit_bufsize + 2*lx, - "pendingBuf overflow"); - - } while (lx < s->last_lit); - - send_code(s, END_BLOCK, ltree); -} - -/* =========================================================================== - * Check if the data type is TEXT or BINARY, using the following algorithm: - * - TEXT if the two conditions below are satisfied: - * a) There are no non-portable control characters belonging to the - * "black list" (0..6, 14..25, 28..31). - * b) There is at least one printable character belonging to the - * "white list" (9 {TAB}, 10 {LF}, 13 {CR}, 32..255). - * - BINARY otherwise. - * - The following partially-portable control characters form a - * "gray list" that is ignored in this detection algorithm: - * (7 {BEL}, 8 {BS}, 11 {VT}, 12 {FF}, 26 {SUB}, 27 {ESC}). - * IN assertion: the fields Freq of dyn_ltree are set. - */ -local int detect_data_type(s) - deflate_state *s; -{ - /* black_mask is the bit mask of black-listed bytes - * set bits 0..6, 14..25, and 28..31 - * 0xf3ffc07f = binary 11110011111111111100000001111111 - */ - unsigned long black_mask = 0xf3ffc07fUL; - int n; - - /* Check for non-textual ("black-listed") bytes. */ - for (n = 0; n <= 31; n++, black_mask >>= 1) - if ((black_mask & 1) && (s->dyn_ltree[n].Freq != 0)) - return Z_BINARY; - - /* Check for textual ("white-listed") bytes. */ - if (s->dyn_ltree[9].Freq != 0 || s->dyn_ltree[10].Freq != 0 - || s->dyn_ltree[13].Freq != 0) - return Z_TEXT; - for (n = 32; n < LITERALS; n++) - if (s->dyn_ltree[n].Freq != 0) - return Z_TEXT; - - /* There are no "black-listed" or "white-listed" bytes: - * this stream either is empty or has tolerated ("gray-listed") bytes only. - */ - return Z_BINARY; -} - -/* =========================================================================== - * Reverse the first len bits of a code, using straightforward code (a faster - * method would use a table) - * IN assertion: 1 <= len <= 15 - */ -local unsigned bi_reverse(code, len) - unsigned code; /* the value to invert */ - int len; /* its bit length */ -{ - register unsigned res = 0; - do { - res |= code & 1; - code >>= 1, res <<= 1; - } while (--len > 0); - return res >> 1; -} - -/* =========================================================================== - * Flush the bit buffer, keeping at most 7 bits in it. - */ -local void bi_flush(s) - deflate_state *s; -{ - if (s->bi_valid == 16) { - put_short(s, s->bi_buf); - s->bi_buf = 0; - s->bi_valid = 0; - } else if (s->bi_valid >= 8) { - put_byte(s, (Byte)s->bi_buf); - s->bi_buf >>= 8; - s->bi_valid -= 8; - } -} - -/* =========================================================================== - * Flush the bit buffer and align the output on a byte boundary - */ -local void bi_windup(s) - deflate_state *s; -{ - if (s->bi_valid > 8) { - put_short(s, s->bi_buf); - } else if (s->bi_valid > 0) { - put_byte(s, (Byte)s->bi_buf); - } - s->bi_buf = 0; - s->bi_valid = 0; -#ifdef DEBUG - s->bits_sent = (s->bits_sent+7) & ~7; -#endif -} - -/* =========================================================================== - * Copy a stored block, storing first the length and its - * one's complement if requested. - */ -local void copy_block(s, buf, len, header) - deflate_state *s; - charf *buf; /* the input data */ - unsigned len; /* its length */ - int header; /* true if block header must be written */ -{ - bi_windup(s); /* align on byte boundary */ - - if (header) { - put_short(s, (ush)len); - put_short(s, (ush)~len); -#ifdef DEBUG - s->bits_sent += 2*16; -#endif - } -#ifdef DEBUG - s->bits_sent += (ulg)len<<3; -#endif - while (len--) { - put_byte(s, *buf++); - } -} diff --git a/deps/zlib/trees.h b/deps/zlib/trees.h deleted file mode 100644 index d35639d82..000000000 --- a/deps/zlib/trees.h +++ /dev/null @@ -1,128 +0,0 @@ -/* header created automatically with -DGEN_TREES_H */ - -local const ct_data static_ltree[L_CODES+2] = { -{{ 12},{ 8}}, {{140},{ 8}}, {{ 76},{ 8}}, {{204},{ 8}}, {{ 44},{ 8}}, -{{172},{ 8}}, {{108},{ 8}}, {{236},{ 8}}, {{ 28},{ 8}}, {{156},{ 8}}, -{{ 92},{ 8}}, {{220},{ 8}}, {{ 60},{ 8}}, {{188},{ 8}}, {{124},{ 8}}, -{{252},{ 8}}, {{ 2},{ 8}}, {{130},{ 8}}, {{ 66},{ 8}}, {{194},{ 8}}, -{{ 34},{ 8}}, {{162},{ 8}}, {{ 98},{ 8}}, {{226},{ 8}}, {{ 18},{ 8}}, -{{146},{ 8}}, {{ 82},{ 8}}, {{210},{ 8}}, {{ 50},{ 8}}, {{178},{ 8}}, -{{114},{ 8}}, {{242},{ 8}}, {{ 10},{ 8}}, {{138},{ 8}}, {{ 74},{ 8}}, -{{202},{ 8}}, {{ 42},{ 8}}, {{170},{ 8}}, {{106},{ 8}}, {{234},{ 8}}, -{{ 26},{ 8}}, {{154},{ 8}}, {{ 90},{ 8}}, {{218},{ 8}}, {{ 58},{ 8}}, -{{186},{ 8}}, {{122},{ 8}}, {{250},{ 8}}, {{ 6},{ 8}}, {{134},{ 8}}, -{{ 70},{ 8}}, {{198},{ 8}}, {{ 38},{ 8}}, {{166},{ 8}}, {{102},{ 8}}, -{{230},{ 8}}, {{ 22},{ 8}}, {{150},{ 8}}, {{ 86},{ 8}}, {{214},{ 8}}, -{{ 54},{ 8}}, {{182},{ 8}}, {{118},{ 8}}, {{246},{ 8}}, {{ 14},{ 8}}, -{{142},{ 8}}, {{ 78},{ 8}}, {{206},{ 8}}, {{ 46},{ 8}}, {{174},{ 8}}, -{{110},{ 8}}, {{238},{ 8}}, {{ 30},{ 8}}, {{158},{ 8}}, {{ 94},{ 8}}, -{{222},{ 8}}, {{ 62},{ 8}}, {{190},{ 8}}, {{126},{ 8}}, {{254},{ 8}}, -{{ 1},{ 8}}, {{129},{ 8}}, {{ 65},{ 8}}, {{193},{ 8}}, {{ 33},{ 8}}, -{{161},{ 8}}, {{ 97},{ 8}}, {{225},{ 8}}, {{ 17},{ 8}}, {{145},{ 8}}, -{{ 81},{ 8}}, {{209},{ 8}}, {{ 49},{ 8}}, {{177},{ 8}}, {{113},{ 8}}, -{{241},{ 8}}, {{ 9},{ 8}}, {{137},{ 8}}, {{ 73},{ 8}}, {{201},{ 8}}, -{{ 41},{ 8}}, {{169},{ 8}}, {{105},{ 8}}, {{233},{ 8}}, {{ 25},{ 8}}, -{{153},{ 8}}, {{ 89},{ 8}}, {{217},{ 8}}, {{ 57},{ 8}}, {{185},{ 8}}, -{{121},{ 8}}, {{249},{ 8}}, {{ 5},{ 8}}, {{133},{ 8}}, {{ 69},{ 8}}, -{{197},{ 8}}, {{ 37},{ 8}}, {{165},{ 8}}, {{101},{ 8}}, {{229},{ 8}}, -{{ 21},{ 8}}, {{149},{ 8}}, {{ 85},{ 8}}, {{213},{ 8}}, {{ 53},{ 8}}, -{{181},{ 8}}, {{117},{ 8}}, {{245},{ 8}}, {{ 13},{ 8}}, {{141},{ 8}}, -{{ 77},{ 8}}, {{205},{ 8}}, {{ 45},{ 8}}, {{173},{ 8}}, {{109},{ 8}}, -{{237},{ 8}}, {{ 29},{ 8}}, {{157},{ 8}}, {{ 93},{ 8}}, {{221},{ 8}}, -{{ 61},{ 8}}, {{189},{ 8}}, {{125},{ 8}}, {{253},{ 8}}, {{ 19},{ 9}}, -{{275},{ 9}}, {{147},{ 9}}, {{403},{ 9}}, {{ 83},{ 9}}, {{339},{ 9}}, -{{211},{ 9}}, {{467},{ 9}}, {{ 51},{ 9}}, {{307},{ 9}}, {{179},{ 9}}, -{{435},{ 9}}, {{115},{ 9}}, {{371},{ 9}}, {{243},{ 9}}, {{499},{ 9}}, -{{ 11},{ 9}}, {{267},{ 9}}, {{139},{ 9}}, {{395},{ 9}}, {{ 75},{ 9}}, -{{331},{ 9}}, {{203},{ 9}}, {{459},{ 9}}, {{ 43},{ 9}}, {{299},{ 9}}, -{{171},{ 9}}, {{427},{ 9}}, {{107},{ 9}}, {{363},{ 9}}, {{235},{ 9}}, -{{491},{ 9}}, {{ 27},{ 9}}, {{283},{ 9}}, {{155},{ 9}}, {{411},{ 9}}, -{{ 91},{ 9}}, {{347},{ 9}}, {{219},{ 9}}, {{475},{ 9}}, {{ 59},{ 9}}, -{{315},{ 9}}, {{187},{ 9}}, {{443},{ 9}}, {{123},{ 9}}, {{379},{ 9}}, -{{251},{ 9}}, {{507},{ 9}}, {{ 7},{ 9}}, {{263},{ 9}}, {{135},{ 9}}, -{{391},{ 9}}, {{ 71},{ 9}}, {{327},{ 9}}, {{199},{ 9}}, {{455},{ 9}}, -{{ 39},{ 9}}, {{295},{ 9}}, {{167},{ 9}}, {{423},{ 9}}, {{103},{ 9}}, -{{359},{ 9}}, {{231},{ 9}}, {{487},{ 9}}, {{ 23},{ 9}}, {{279},{ 9}}, -{{151},{ 9}}, {{407},{ 9}}, {{ 87},{ 9}}, {{343},{ 9}}, {{215},{ 9}}, -{{471},{ 9}}, {{ 55},{ 9}}, {{311},{ 9}}, {{183},{ 9}}, {{439},{ 9}}, -{{119},{ 9}}, {{375},{ 9}}, {{247},{ 9}}, {{503},{ 9}}, {{ 15},{ 9}}, -{{271},{ 9}}, {{143},{ 9}}, {{399},{ 9}}, {{ 79},{ 9}}, {{335},{ 9}}, -{{207},{ 9}}, {{463},{ 9}}, {{ 47},{ 9}}, {{303},{ 9}}, {{175},{ 9}}, -{{431},{ 9}}, {{111},{ 9}}, {{367},{ 9}}, {{239},{ 9}}, {{495},{ 9}}, -{{ 31},{ 9}}, {{287},{ 9}}, {{159},{ 9}}, {{415},{ 9}}, {{ 95},{ 9}}, -{{351},{ 9}}, {{223},{ 9}}, {{479},{ 9}}, {{ 63},{ 9}}, {{319},{ 9}}, -{{191},{ 9}}, {{447},{ 9}}, {{127},{ 9}}, {{383},{ 9}}, {{255},{ 9}}, -{{511},{ 9}}, {{ 0},{ 7}}, {{ 64},{ 7}}, {{ 32},{ 7}}, {{ 96},{ 7}}, -{{ 16},{ 7}}, {{ 80},{ 7}}, {{ 48},{ 7}}, {{112},{ 7}}, {{ 8},{ 7}}, -{{ 72},{ 7}}, {{ 40},{ 7}}, {{104},{ 7}}, {{ 24},{ 7}}, {{ 88},{ 7}}, -{{ 56},{ 7}}, {{120},{ 7}}, {{ 4},{ 7}}, {{ 68},{ 7}}, {{ 36},{ 7}}, -{{100},{ 7}}, {{ 20},{ 7}}, {{ 84},{ 7}}, {{ 52},{ 7}}, {{116},{ 7}}, -{{ 3},{ 8}}, {{131},{ 8}}, {{ 67},{ 8}}, {{195},{ 8}}, {{ 35},{ 8}}, -{{163},{ 8}}, {{ 99},{ 8}}, {{227},{ 8}} -}; - -local const ct_data static_dtree[D_CODES] = { -{{ 0},{ 5}}, {{16},{ 5}}, {{ 8},{ 5}}, {{24},{ 5}}, {{ 4},{ 5}}, -{{20},{ 5}}, {{12},{ 5}}, {{28},{ 5}}, {{ 2},{ 5}}, {{18},{ 5}}, -{{10},{ 5}}, {{26},{ 5}}, {{ 6},{ 5}}, {{22},{ 5}}, {{14},{ 5}}, -{{30},{ 5}}, {{ 1},{ 5}}, {{17},{ 5}}, {{ 9},{ 5}}, {{25},{ 5}}, -{{ 5},{ 5}}, {{21},{ 5}}, {{13},{ 5}}, {{29},{ 5}}, {{ 3},{ 5}}, -{{19},{ 5}}, {{11},{ 5}}, {{27},{ 5}}, {{ 7},{ 5}}, {{23},{ 5}} -}; - -const uch ZLIB_INTERNAL _dist_code[DIST_CODE_LEN] = { - 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, - 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, -10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, -11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, -12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, -13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, -13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, -14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, -14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, -14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, -15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, -15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, -15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 16, 17, -18, 18, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, -23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, -24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, -26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, -26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, -27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, -27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, -28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, -28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, -28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, -29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, -29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, -29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29 -}; - -const uch ZLIB_INTERNAL _length_code[MAX_MATCH-MIN_MATCH+1]= { - 0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 12, 12, -13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, -17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, -19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, -21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, -22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, -23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, -24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, -25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, -25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, -26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, -26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, -27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28 -}; - -local const int base_length[LENGTH_CODES] = { -0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56, -64, 80, 96, 112, 128, 160, 192, 224, 0 -}; - -local const int base_dist[D_CODES] = { - 0, 1, 2, 3, 4, 6, 8, 12, 16, 24, - 32, 48, 64, 96, 128, 192, 256, 384, 512, 768, - 1024, 1536, 2048, 3072, 4096, 6144, 8192, 12288, 16384, 24576 -}; - diff --git a/deps/zlib/zconf.h b/deps/zlib/zconf.h deleted file mode 100644 index 229c40024..000000000 --- a/deps/zlib/zconf.h +++ /dev/null @@ -1,58 +0,0 @@ -/* zconf.h -- configuration of the zlib compression library - * Copyright (C) 1995-2010 Jean-loup Gailly. - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* @(#) $Id$ */ - -#ifndef ZCONF_H -#define ZCONF_H - -#include "../../src/common.h" - -/* Jeez, don't complain about non-prototype - * forms, we didn't write zlib */ -#if defined(_MSC_VER) -# pragma warning( disable : 4131 ) -# pragma warning( disable : 4142 ) /* benign redefinition of type */ -#endif - -/* Maximum value for memLevel in deflateInit2 */ -#define MAX_MEM_LEVEL 9 - -/* Maximum value for windowBits in deflateInit2 and inflateInit2. - * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files - * created by gzip. (Files created by minigzip can still be extracted by - * gzip.) - */ -#define MAX_WBITS 15 /* 32K LZ77 window */ - -#define ZEXTERN extern -#define ZEXPORT -#define ZEXPORTVA -#ifndef FAR -# define FAR -#endif -#define OF(args) args -#define Z_ARG(args) args - -typedef unsigned char Byte; /* 8 bits */ -typedef unsigned int uInt; /* 16 bits or more */ -typedef unsigned long uLong; /* 32 bits or more */ -typedef unsigned long z_crc_t; - -typedef Byte FAR Bytef; -typedef char FAR charf; -typedef int FAR intf; -typedef uInt FAR uIntf; -typedef uLong FAR uLongf; - -typedef void const *voidpc; -typedef void FAR *voidpf; -typedef void *voidp; - -#define z_off_t git_off_t -#define z_off64_t z_off_t -#define z_const const - -#endif /* ZCONF_H */ diff --git a/deps/zlib/zlib.h b/deps/zlib/zlib.h deleted file mode 100644 index 3e0c7672a..000000000 --- a/deps/zlib/zlib.h +++ /dev/null @@ -1,1768 +0,0 @@ -/* zlib.h -- interface of the 'zlib' general purpose compression library - version 1.2.8, April 28th, 2013 - - Copyright (C) 1995-2013 Jean-loup Gailly and Mark Adler - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. - - Jean-loup Gailly Mark Adler - jloup@gzip.org madler@alumni.caltech.edu - - - The data format used by the zlib library is described by RFCs (Request for - Comments) 1950 to 1952 in the files http://tools.ietf.org/html/rfc1950 - (zlib format), rfc1951 (deflate format) and rfc1952 (gzip format). -*/ - -#ifndef ZLIB_H -#define ZLIB_H - -#include "zconf.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#define ZLIB_VERSION "1.2.8" -#define ZLIB_VERNUM 0x1280 -#define ZLIB_VER_MAJOR 1 -#define ZLIB_VER_MINOR 2 -#define ZLIB_VER_REVISION 8 -#define ZLIB_VER_SUBREVISION 0 - -/* - The 'zlib' compression library provides in-memory compression and - decompression functions, including integrity checks of the uncompressed data. - This version of the library supports only one compression method (deflation) - but other algorithms will be added later and will have the same stream - interface. - - Compression can be done in a single step if the buffers are large enough, - or can be done by repeated calls of the compression function. In the latter - case, the application must provide more input and/or consume the output - (providing more output space) before each call. - - The compressed data format used by default by the in-memory functions is - the zlib format, which is a zlib wrapper documented in RFC 1950, wrapped - around a deflate stream, which is itself documented in RFC 1951. - - The library also supports reading and writing files in gzip (.gz) format - with an interface similar to that of stdio using the functions that start - with "gz". The gzip format is different from the zlib format. gzip is a - gzip wrapper, documented in RFC 1952, wrapped around a deflate stream. - - This library can optionally read and write gzip streams in memory as well. - - The zlib format was designed to be compact and fast for use in memory - and on communications channels. The gzip format was designed for single- - file compression on file systems, has a larger header than zlib to maintain - directory information, and uses a different, slower check method than zlib. - - The library does not install any signal handler. The decoder checks - the consistency of the compressed data, so the library should never crash - even in case of corrupted input. -*/ - -typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size)); -typedef void (*free_func) OF((voidpf opaque, voidpf address)); - -struct internal_state; - -typedef struct z_stream_s { - z_const Bytef *next_in; /* next input byte */ - uInt avail_in; /* number of bytes available at next_in */ - uLong total_in; /* total number of input bytes read so far */ - - Bytef *next_out; /* next output byte should be put there */ - uInt avail_out; /* remaining free space at next_out */ - uLong total_out; /* total number of bytes output so far */ - - z_const char *msg; /* last error message, NULL if no error */ - struct internal_state FAR *state; /* not visible by applications */ - - alloc_func zalloc; /* used to allocate the internal state */ - free_func zfree; /* used to free the internal state */ - voidpf opaque; /* private data object passed to zalloc and zfree */ - - int data_type; /* best guess about the data type: binary or text */ - uLong adler; /* adler32 value of the uncompressed data */ - uLong reserved; /* reserved for future use */ -} z_stream; - -typedef z_stream FAR *z_streamp; - -/* - gzip header information passed to and from zlib routines. See RFC 1952 - for more details on the meanings of these fields. -*/ -typedef struct gz_header_s { - int text; /* true if compressed data believed to be text */ - uLong time; /* modification time */ - int xflags; /* extra flags (not used when writing a gzip file) */ - int os; /* operating system */ - Bytef *extra; /* pointer to extra field or Z_NULL if none */ - uInt extra_len; /* extra field length (valid if extra != Z_NULL) */ - uInt extra_max; /* space at extra (only when reading header) */ - Bytef *name; /* pointer to zero-terminated file name or Z_NULL */ - uInt name_max; /* space at name (only when reading header) */ - Bytef *comment; /* pointer to zero-terminated comment or Z_NULL */ - uInt comm_max; /* space at comment (only when reading header) */ - int hcrc; /* true if there was or will be a header crc */ - int done; /* true when done reading gzip header (not used - when writing a gzip file) */ -} gz_header; - -typedef gz_header FAR *gz_headerp; - -/* - The application must update next_in and avail_in when avail_in has dropped - to zero. It must update next_out and avail_out when avail_out has dropped - to zero. The application must initialize zalloc, zfree and opaque before - calling the init function. All other fields are set by the compression - library and must not be updated by the application. - - The opaque value provided by the application will be passed as the first - parameter for calls of zalloc and zfree. This can be useful for custom - memory management. The compression library attaches no meaning to the - opaque value. - - zalloc must return Z_NULL if there is not enough memory for the object. - If zlib is used in a multi-threaded application, zalloc and zfree must be - thread safe. - - On 16-bit systems, the functions zalloc and zfree must be able to allocate - exactly 65536 bytes, but will not be required to allocate more than this if - the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS, pointers - returned by zalloc for objects of exactly 65536 bytes *must* have their - offset normalized to zero. The default allocation function provided by this - library ensures this (see zutil.c). To reduce memory requirements and avoid - any allocation of 64K objects, at the expense of compression ratio, compile - the library with -DMAX_WBITS=14 (see zconf.h). - - The fields total_in and total_out can be used for statistics or progress - reports. After compression, total_in holds the total size of the - uncompressed data and may be saved for use in the decompressor (particularly - if the decompressor wants to decompress everything in a single step). -*/ - - /* constants */ - -#define Z_NO_FLUSH 0 -#define Z_PARTIAL_FLUSH 1 -#define Z_SYNC_FLUSH 2 -#define Z_FULL_FLUSH 3 -#define Z_FINISH 4 -#define Z_BLOCK 5 -#define Z_TREES 6 -/* Allowed flush values; see deflate() and inflate() below for details */ - -#define Z_OK 0 -#define Z_STREAM_END 1 -#define Z_NEED_DICT 2 -#define Z_ERRNO (-1) -#define Z_STREAM_ERROR (-2) -#define Z_DATA_ERROR (-3) -#define Z_MEM_ERROR (-4) -#define Z_BUF_ERROR (-5) -#define Z_VERSION_ERROR (-6) -/* Return codes for the compression/decompression functions. Negative values - * are errors, positive values are used for special but normal events. - */ - -#define Z_NO_COMPRESSION 0 -#define Z_BEST_SPEED 1 -#define Z_BEST_COMPRESSION 9 -#define Z_DEFAULT_COMPRESSION (-1) -/* compression levels */ - -#define Z_FILTERED 1 -#define Z_HUFFMAN_ONLY 2 -#define Z_RLE 3 -#define Z_FIXED 4 -#define Z_DEFAULT_STRATEGY 0 -/* compression strategy; see deflateInit2() below for details */ - -#define Z_BINARY 0 -#define Z_TEXT 1 -#define Z_ASCII Z_TEXT /* for compatibility with 1.2.2 and earlier */ -#define Z_UNKNOWN 2 -/* Possible values of the data_type field (though see inflate()) */ - -#define Z_DEFLATED 8 -/* The deflate compression method (the only one supported in this version) */ - -#define Z_NULL 0 /* for initializing zalloc, zfree, opaque */ - -#define zlib_version zlibVersion() -/* for compatibility with versions < 1.0.2 */ - - - /* basic functions */ - -ZEXTERN const char * ZEXPORT zlibVersion OF((void)); -/* The application can compare zlibVersion and ZLIB_VERSION for consistency. - If the first character differs, the library code actually used is not - compatible with the zlib.h header file used by the application. This check - is automatically made by deflateInit and inflateInit. - */ - -/* -ZEXTERN int ZEXPORT deflateInit OF((z_streamp strm, int level)); - - Initializes the internal stream state for compression. The fields - zalloc, zfree and opaque must be initialized before by the caller. If - zalloc and zfree are set to Z_NULL, deflateInit updates them to use default - allocation functions. - - The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9: - 1 gives best speed, 9 gives best compression, 0 gives no compression at all - (the input data is simply copied a block at a time). Z_DEFAULT_COMPRESSION - requests a default compromise between speed and compression (currently - equivalent to level 6). - - deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough - memory, Z_STREAM_ERROR if level is not a valid compression level, or - Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible - with the version assumed by the caller (ZLIB_VERSION). msg is set to null - if there is no error message. deflateInit does not perform any compression: - this will be done by deflate(). -*/ - - -ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush)); -/* - deflate compresses as much data as possible, and stops when the input - buffer becomes empty or the output buffer becomes full. It may introduce - some output latency (reading input without producing any output) except when - forced to flush. - - The detailed semantics are as follows. deflate performs one or both of the - following actions: - - - Compress more input starting at next_in and update next_in and avail_in - accordingly. If not all input can be processed (because there is not - enough room in the output buffer), next_in and avail_in are updated and - processing will resume at this point for the next call of deflate(). - - - Provide more output starting at next_out and update next_out and avail_out - accordingly. This action is forced if the parameter flush is non zero. - Forcing flush frequently degrades the compression ratio, so this parameter - should be set only when necessary (in interactive applications). Some - output may be provided even if flush is not set. - - Before the call of deflate(), the application should ensure that at least - one of the actions is possible, by providing more input and/or consuming more - output, and updating avail_in or avail_out accordingly; avail_out should - never be zero before the call. The application can consume the compressed - output when it wants, for example when the output buffer is full (avail_out - == 0), or after each call of deflate(). If deflate returns Z_OK and with - zero avail_out, it must be called again after making room in the output - buffer because there might be more output pending. - - Normally the parameter flush is set to Z_NO_FLUSH, which allows deflate to - decide how much data to accumulate before producing output, in order to - maximize compression. - - If the parameter flush is set to Z_SYNC_FLUSH, all pending output is - flushed to the output buffer and the output is aligned on a byte boundary, so - that the decompressor can get all input data available so far. (In - particular avail_in is zero after the call if enough output space has been - provided before the call.) Flushing may degrade compression for some - compression algorithms and so it should be used only when necessary. This - completes the current deflate block and follows it with an empty stored block - that is three bits plus filler bits to the next byte, followed by four bytes - (00 00 ff ff). - - If flush is set to Z_PARTIAL_FLUSH, all pending output is flushed to the - output buffer, but the output is not aligned to a byte boundary. All of the - input data so far will be available to the decompressor, as for Z_SYNC_FLUSH. - This completes the current deflate block and follows it with an empty fixed - codes block that is 10 bits long. This assures that enough bytes are output - in order for the decompressor to finish the block before the empty fixed code - block. - - If flush is set to Z_BLOCK, a deflate block is completed and emitted, as - for Z_SYNC_FLUSH, but the output is not aligned on a byte boundary, and up to - seven bits of the current block are held to be written as the next byte after - the next deflate block is completed. In this case, the decompressor may not - be provided enough bits at this point in order to complete decompression of - the data provided so far to the compressor. It may need to wait for the next - block to be emitted. This is for advanced applications that need to control - the emission of deflate blocks. - - If flush is set to Z_FULL_FLUSH, all output is flushed as with - Z_SYNC_FLUSH, and the compression state is reset so that decompression can - restart from this point if previous compressed data has been damaged or if - random access is desired. Using Z_FULL_FLUSH too often can seriously degrade - compression. - - If deflate returns with avail_out == 0, this function must be called again - with the same value of the flush parameter and more output space (updated - avail_out), until the flush is complete (deflate returns with non-zero - avail_out). In the case of a Z_FULL_FLUSH or Z_SYNC_FLUSH, make sure that - avail_out is greater than six to avoid repeated flush markers due to - avail_out == 0 on return. - - If the parameter flush is set to Z_FINISH, pending input is processed, - pending output is flushed and deflate returns with Z_STREAM_END if there was - enough output space; if deflate returns with Z_OK, this function must be - called again with Z_FINISH and more output space (updated avail_out) but no - more input data, until it returns with Z_STREAM_END or an error. After - deflate has returned Z_STREAM_END, the only possible operations on the stream - are deflateReset or deflateEnd. - - Z_FINISH can be used immediately after deflateInit if all the compression - is to be done in a single step. In this case, avail_out must be at least the - value returned by deflateBound (see below). Then deflate is guaranteed to - return Z_STREAM_END. If not enough output space is provided, deflate will - not return Z_STREAM_END, and it must be called again as described above. - - deflate() sets strm->adler to the adler32 checksum of all input read - so far (that is, total_in bytes). - - deflate() may update strm->data_type if it can make a good guess about - the input data type (Z_BINARY or Z_TEXT). In doubt, the data is considered - binary. This field is only for information purposes and does not affect the - compression algorithm in any manner. - - deflate() returns Z_OK if some progress has been made (more input - processed or more output produced), Z_STREAM_END if all input has been - consumed and all output has been produced (only when flush is set to - Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example - if next_in or next_out was Z_NULL), Z_BUF_ERROR if no progress is possible - (for example avail_in or avail_out was zero). Note that Z_BUF_ERROR is not - fatal, and deflate() can be called again with more input and more output - space to continue compressing. -*/ - - -ZEXTERN int ZEXPORT deflateEnd OF((z_streamp strm)); -/* - All dynamically allocated data structures for this stream are freed. - This function discards any unprocessed input and does not flush any pending - output. - - deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the - stream state was inconsistent, Z_DATA_ERROR if the stream was freed - prematurely (some input or output was discarded). In the error case, msg - may be set but then points to a static string (which must not be - deallocated). -*/ - - -/* -ZEXTERN int ZEXPORT inflateInit OF((z_streamp strm)); - - Initializes the internal stream state for decompression. The fields - next_in, avail_in, zalloc, zfree and opaque must be initialized before by - the caller. If next_in is not Z_NULL and avail_in is large enough (the - exact value depends on the compression method), inflateInit determines the - compression method from the zlib header and allocates all data structures - accordingly; otherwise the allocation will be deferred to the first call of - inflate. If zalloc and zfree are set to Z_NULL, inflateInit updates them to - use default allocation functions. - - inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough - memory, Z_VERSION_ERROR if the zlib library version is incompatible with the - version assumed by the caller, or Z_STREAM_ERROR if the parameters are - invalid, such as a null pointer to the structure. msg is set to null if - there is no error message. inflateInit does not perform any decompression - apart from possibly reading the zlib header if present: actual decompression - will be done by inflate(). (So next_in and avail_in may be modified, but - next_out and avail_out are unused and unchanged.) The current implementation - of inflateInit() does not process any header information -- that is deferred - until inflate() is called. -*/ - - -ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush)); -/* - inflate decompresses as much data as possible, and stops when the input - buffer becomes empty or the output buffer becomes full. It may introduce - some output latency (reading input without producing any output) except when - forced to flush. - - The detailed semantics are as follows. inflate performs one or both of the - following actions: - - - Decompress more input starting at next_in and update next_in and avail_in - accordingly. If not all input can be processed (because there is not - enough room in the output buffer), next_in is updated and processing will - resume at this point for the next call of inflate(). - - - Provide more output starting at next_out and update next_out and avail_out - accordingly. inflate() provides as much output as possible, until there is - no more input data or no more space in the output buffer (see below about - the flush parameter). - - Before the call of inflate(), the application should ensure that at least - one of the actions is possible, by providing more input and/or consuming more - output, and updating the next_* and avail_* values accordingly. The - application can consume the uncompressed output when it wants, for example - when the output buffer is full (avail_out == 0), or after each call of - inflate(). If inflate returns Z_OK and with zero avail_out, it must be - called again after making room in the output buffer because there might be - more output pending. - - The flush parameter of inflate() can be Z_NO_FLUSH, Z_SYNC_FLUSH, Z_FINISH, - Z_BLOCK, or Z_TREES. Z_SYNC_FLUSH requests that inflate() flush as much - output as possible to the output buffer. Z_BLOCK requests that inflate() - stop if and when it gets to the next deflate block boundary. When decoding - the zlib or gzip format, this will cause inflate() to return immediately - after the header and before the first block. When doing a raw inflate, - inflate() will go ahead and process the first block, and will return when it - gets to the end of that block, or when it runs out of data. - - The Z_BLOCK option assists in appending to or combining deflate streams. - Also to assist in this, on return inflate() will set strm->data_type to the - number of unused bits in the last byte taken from strm->next_in, plus 64 if - inflate() is currently decoding the last block in the deflate stream, plus - 128 if inflate() returned immediately after decoding an end-of-block code or - decoding the complete header up to just before the first byte of the deflate - stream. The end-of-block will not be indicated until all of the uncompressed - data from that block has been written to strm->next_out. The number of - unused bits may in general be greater than seven, except when bit 7 of - data_type is set, in which case the number of unused bits will be less than - eight. data_type is set as noted here every time inflate() returns for all - flush options, and so can be used to determine the amount of currently - consumed input in bits. - - The Z_TREES option behaves as Z_BLOCK does, but it also returns when the - end of each deflate block header is reached, before any actual data in that - block is decoded. This allows the caller to determine the length of the - deflate block header for later use in random access within a deflate block. - 256 is added to the value of strm->data_type when inflate() returns - immediately after reaching the end of the deflate block header. - - inflate() should normally be called until it returns Z_STREAM_END or an - error. However if all decompression is to be performed in a single step (a - single call of inflate), the parameter flush should be set to Z_FINISH. In - this case all pending input is processed and all pending output is flushed; - avail_out must be large enough to hold all of the uncompressed data for the - operation to complete. (The size of the uncompressed data may have been - saved by the compressor for this purpose.) The use of Z_FINISH is not - required to perform an inflation in one step. However it may be used to - inform inflate that a faster approach can be used for the single inflate() - call. Z_FINISH also informs inflate to not maintain a sliding window if the - stream completes, which reduces inflate's memory footprint. If the stream - does not complete, either because not all of the stream is provided or not - enough output space is provided, then a sliding window will be allocated and - inflate() can be called again to continue the operation as if Z_NO_FLUSH had - been used. - - In this implementation, inflate() always flushes as much output as - possible to the output buffer, and always uses the faster approach on the - first call. So the effects of the flush parameter in this implementation are - on the return value of inflate() as noted below, when inflate() returns early - when Z_BLOCK or Z_TREES is used, and when inflate() avoids the allocation of - memory for a sliding window when Z_FINISH is used. - - If a preset dictionary is needed after this call (see inflateSetDictionary - below), inflate sets strm->adler to the Adler-32 checksum of the dictionary - chosen by the compressor and returns Z_NEED_DICT; otherwise it sets - strm->adler to the Adler-32 checksum of all output produced so far (that is, - total_out bytes) and returns Z_OK, Z_STREAM_END or an error code as described - below. At the end of the stream, inflate() checks that its computed adler32 - checksum is equal to that saved by the compressor and returns Z_STREAM_END - only if the checksum is correct. - - inflate() can decompress and check either zlib-wrapped or gzip-wrapped - deflate data. The header type is detected automatically, if requested when - initializing with inflateInit2(). Any information contained in the gzip - header is not retained, so applications that need that information should - instead use raw inflate, see inflateInit2() below, or inflateBack() and - perform their own processing of the gzip header and trailer. When processing - gzip-wrapped deflate data, strm->adler32 is set to the CRC-32 of the output - producted so far. The CRC-32 is checked against the gzip trailer. - - inflate() returns Z_OK if some progress has been made (more input processed - or more output produced), Z_STREAM_END if the end of the compressed data has - been reached and all uncompressed output has been produced, Z_NEED_DICT if a - preset dictionary is needed at this point, Z_DATA_ERROR if the input data was - corrupted (input stream not conforming to the zlib format or incorrect check - value), Z_STREAM_ERROR if the stream structure was inconsistent (for example - next_in or next_out was Z_NULL), Z_MEM_ERROR if there was not enough memory, - Z_BUF_ERROR if no progress is possible or if there was not enough room in the - output buffer when Z_FINISH is used. Note that Z_BUF_ERROR is not fatal, and - inflate() can be called again with more input and more output space to - continue decompressing. If Z_DATA_ERROR is returned, the application may - then call inflateSync() to look for a good compression block if a partial - recovery of the data is desired. -*/ - - -ZEXTERN int ZEXPORT inflateEnd OF((z_streamp strm)); -/* - All dynamically allocated data structures for this stream are freed. - This function discards any unprocessed input and does not flush any pending - output. - - inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state - was inconsistent. In the error case, msg may be set but then points to a - static string (which must not be deallocated). -*/ - - - /* Advanced functions */ - -/* - The following functions are needed only in some special applications. -*/ - -/* -ZEXTERN int ZEXPORT deflateInit2 OF((z_streamp strm, - int level, - int method, - int windowBits, - int memLevel, - int strategy)); - - This is another version of deflateInit with more compression options. The - fields next_in, zalloc, zfree and opaque must be initialized before by the - caller. - - The method parameter is the compression method. It must be Z_DEFLATED in - this version of the library. - - The windowBits parameter is the base two logarithm of the window size - (the size of the history buffer). It should be in the range 8..15 for this - version of the library. Larger values of this parameter result in better - compression at the expense of memory usage. The default value is 15 if - deflateInit is used instead. - - windowBits can also be -8..-15 for raw deflate. In this case, -windowBits - determines the window size. deflate() will then generate raw deflate data - with no zlib header or trailer, and will not compute an adler32 check value. - - windowBits can also be greater than 15 for optional gzip encoding. Add - 16 to windowBits to write a simple gzip header and trailer around the - compressed data instead of a zlib wrapper. The gzip header will have no - file name, no extra data, no comment, no modification time (set to zero), no - header crc, and the operating system will be set to 255 (unknown). If a - gzip stream is being written, strm->adler is a crc32 instead of an adler32. - - The memLevel parameter specifies how much memory should be allocated - for the internal compression state. memLevel=1 uses minimum memory but is - slow and reduces compression ratio; memLevel=9 uses maximum memory for - optimal speed. The default value is 8. See zconf.h for total memory usage - as a function of windowBits and memLevel. - - The strategy parameter is used to tune the compression algorithm. Use the - value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a - filter (or predictor), Z_HUFFMAN_ONLY to force Huffman encoding only (no - string match), or Z_RLE to limit match distances to one (run-length - encoding). Filtered data consists mostly of small values with a somewhat - random distribution. In this case, the compression algorithm is tuned to - compress them better. The effect of Z_FILTERED is to force more Huffman - coding and less string matching; it is somewhat intermediate between - Z_DEFAULT_STRATEGY and Z_HUFFMAN_ONLY. Z_RLE is designed to be almost as - fast as Z_HUFFMAN_ONLY, but give better compression for PNG image data. The - strategy parameter only affects the compression ratio but not the - correctness of the compressed output even if it is not set appropriately. - Z_FIXED prevents the use of dynamic Huffman codes, allowing for a simpler - decoder for special applications. - - deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough - memory, Z_STREAM_ERROR if any parameter is invalid (such as an invalid - method), or Z_VERSION_ERROR if the zlib library version (zlib_version) is - incompatible with the version assumed by the caller (ZLIB_VERSION). msg is - set to null if there is no error message. deflateInit2 does not perform any - compression: this will be done by deflate(). -*/ - -ZEXTERN int ZEXPORT deflateSetDictionary OF((z_streamp strm, - const Bytef *dictionary, - uInt dictLength)); -/* - Initializes the compression dictionary from the given byte sequence - without producing any compressed output. When using the zlib format, this - function must be called immediately after deflateInit, deflateInit2 or - deflateReset, and before any call of deflate. When doing raw deflate, this - function must be called either before any call of deflate, or immediately - after the completion of a deflate block, i.e. after all input has been - consumed and all output has been delivered when using any of the flush - options Z_BLOCK, Z_PARTIAL_FLUSH, Z_SYNC_FLUSH, or Z_FULL_FLUSH. The - compressor and decompressor must use exactly the same dictionary (see - inflateSetDictionary). - - The dictionary should consist of strings (byte sequences) that are likely - to be encountered later in the data to be compressed, with the most commonly - used strings preferably put towards the end of the dictionary. Using a - dictionary is most useful when the data to be compressed is short and can be - predicted with good accuracy; the data can then be compressed better than - with the default empty dictionary. - - Depending on the size of the compression data structures selected by - deflateInit or deflateInit2, a part of the dictionary may in effect be - discarded, for example if the dictionary is larger than the window size - provided in deflateInit or deflateInit2. Thus the strings most likely to be - useful should be put at the end of the dictionary, not at the front. In - addition, the current implementation of deflate will use at most the window - size minus 262 bytes of the provided dictionary. - - Upon return of this function, strm->adler is set to the adler32 value - of the dictionary; the decompressor may later use this value to determine - which dictionary has been used by the compressor. (The adler32 value - applies to the whole dictionary even if only a subset of the dictionary is - actually used by the compressor.) If a raw deflate was requested, then the - adler32 value is not computed and strm->adler is not set. - - deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a - parameter is invalid (e.g. dictionary being Z_NULL) or the stream state is - inconsistent (for example if deflate has already been called for this stream - or if not at a block boundary for raw deflate). deflateSetDictionary does - not perform any compression: this will be done by deflate(). -*/ - -ZEXTERN int ZEXPORT deflateCopy OF((z_streamp dest, - z_streamp source)); -/* - Sets the destination stream as a complete copy of the source stream. - - This function can be useful when several compression strategies will be - tried, for example when there are several ways of pre-processing the input - data with a filter. The streams that will be discarded should then be freed - by calling deflateEnd. Note that deflateCopy duplicates the internal - compression state which can be quite large, so this strategy is slow and can - consume lots of memory. - - deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not - enough memory, Z_STREAM_ERROR if the source stream state was inconsistent - (such as zalloc being Z_NULL). msg is left unchanged in both source and - destination. -*/ - -ZEXTERN int ZEXPORT deflateReset OF((z_streamp strm)); -/* - This function is equivalent to deflateEnd followed by deflateInit, - but does not free and reallocate all the internal compression state. The - stream will keep the same compression level and any other attributes that - may have been set by deflateInit2. - - deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source - stream state was inconsistent (such as zalloc or state being Z_NULL). -*/ - -ZEXTERN int ZEXPORT deflateParams OF((z_streamp strm, - int level, - int strategy)); -/* - Dynamically update the compression level and compression strategy. The - interpretation of level and strategy is as in deflateInit2. This can be - used to switch between compression and straight copy of the input data, or - to switch to a different kind of input data requiring a different strategy. - If the compression level is changed, the input available so far is - compressed with the old level (and may be flushed); the new level will take - effect only at the next call of deflate(). - - Before the call of deflateParams, the stream state must be set as for - a call of deflate(), since the currently available input may have to be - compressed and flushed. In particular, strm->avail_out must be non-zero. - - deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source - stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR if - strm->avail_out was zero. -*/ - -ZEXTERN int ZEXPORT deflateTune OF((z_streamp strm, - int good_length, - int max_lazy, - int nice_length, - int max_chain)); -/* - Fine tune deflate's internal compression parameters. This should only be - used by someone who understands the algorithm used by zlib's deflate for - searching for the best matching string, and even then only by the most - fanatic optimizer trying to squeeze out the last compressed bit for their - specific input data. Read the deflate.c source code for the meaning of the - max_lazy, good_length, nice_length, and max_chain parameters. - - deflateTune() can be called after deflateInit() or deflateInit2(), and - returns Z_OK on success, or Z_STREAM_ERROR for an invalid deflate stream. - */ - -ZEXTERN uLong ZEXPORT deflateBound OF((z_streamp strm, - uLong sourceLen)); -/* - deflateBound() returns an upper bound on the compressed size after - deflation of sourceLen bytes. It must be called after deflateInit() or - deflateInit2(), and after deflateSetHeader(), if used. This would be used - to allocate an output buffer for deflation in a single pass, and so would be - called before deflate(). If that first deflate() call is provided the - sourceLen input bytes, an output buffer allocated to the size returned by - deflateBound(), and the flush value Z_FINISH, then deflate() is guaranteed - to return Z_STREAM_END. Note that it is possible for the compressed size to - be larger than the value returned by deflateBound() if flush options other - than Z_FINISH or Z_NO_FLUSH are used. -*/ - -ZEXTERN int ZEXPORT deflatePending OF((z_streamp strm, - unsigned *pending, - int *bits)); -/* - deflatePending() returns the number of bytes and bits of output that have - been generated, but not yet provided in the available output. The bytes not - provided would be due to the available output space having being consumed. - The number of bits of output not provided are between 0 and 7, where they - await more bits to join them in order to fill out a full byte. If pending - or bits are Z_NULL, then those values are not set. - - deflatePending returns Z_OK if success, or Z_STREAM_ERROR if the source - stream state was inconsistent. - */ - -ZEXTERN int ZEXPORT deflatePrime OF((z_streamp strm, - int bits, - int value)); -/* - deflatePrime() inserts bits in the deflate output stream. The intent - is that this function is used to start off the deflate output with the bits - leftover from a previous deflate stream when appending to it. As such, this - function can only be used for raw deflate, and must be used before the first - deflate() call after a deflateInit2() or deflateReset(). bits must be less - than or equal to 16, and that many of the least significant bits of value - will be inserted in the output. - - deflatePrime returns Z_OK if success, Z_BUF_ERROR if there was not enough - room in the internal buffer to insert the bits, or Z_STREAM_ERROR if the - source stream state was inconsistent. -*/ - -ZEXTERN int ZEXPORT deflateSetHeader OF((z_streamp strm, - gz_headerp head)); -/* - deflateSetHeader() provides gzip header information for when a gzip - stream is requested by deflateInit2(). deflateSetHeader() may be called - after deflateInit2() or deflateReset() and before the first call of - deflate(). The text, time, os, extra field, name, and comment information - in the provided gz_header structure are written to the gzip header (xflag is - ignored -- the extra flags are set according to the compression level). The - caller must assure that, if not Z_NULL, name and comment are terminated with - a zero byte, and that if extra is not Z_NULL, that extra_len bytes are - available there. If hcrc is true, a gzip header crc is included. Note that - the current versions of the command-line version of gzip (up through version - 1.3.x) do not support header crc's, and will report that it is a "multi-part - gzip file" and give up. - - If deflateSetHeader is not used, the default gzip header has text false, - the time set to zero, and os set to 255, with no extra, name, or comment - fields. The gzip header is returned to the default state by deflateReset(). - - deflateSetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source - stream state was inconsistent. -*/ - -/* -ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm, - int windowBits)); - - This is another version of inflateInit with an extra parameter. The - fields next_in, avail_in, zalloc, zfree and opaque must be initialized - before by the caller. - - The windowBits parameter is the base two logarithm of the maximum window - size (the size of the history buffer). It should be in the range 8..15 for - this version of the library. The default value is 15 if inflateInit is used - instead. windowBits must be greater than or equal to the windowBits value - provided to deflateInit2() while compressing, or it must be equal to 15 if - deflateInit2() was not used. If a compressed stream with a larger window - size is given as input, inflate() will return with the error code - Z_DATA_ERROR instead of trying to allocate a larger window. - - windowBits can also be zero to request that inflate use the window size in - the zlib header of the compressed stream. - - windowBits can also be -8..-15 for raw inflate. In this case, -windowBits - determines the window size. inflate() will then process raw deflate data, - not looking for a zlib or gzip header, not generating a check value, and not - looking for any check values for comparison at the end of the stream. This - is for use with other formats that use the deflate compressed data format - such as zip. Those formats provide their own check values. If a custom - format is developed using the raw deflate format for compressed data, it is - recommended that a check value such as an adler32 or a crc32 be applied to - the uncompressed data as is done in the zlib, gzip, and zip formats. For - most applications, the zlib format should be used as is. Note that comments - above on the use in deflateInit2() applies to the magnitude of windowBits. - - windowBits can also be greater than 15 for optional gzip decoding. Add - 32 to windowBits to enable zlib and gzip decoding with automatic header - detection, or add 16 to decode only the gzip format (the zlib format will - return a Z_DATA_ERROR). If a gzip stream is being decoded, strm->adler is a - crc32 instead of an adler32. - - inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough - memory, Z_VERSION_ERROR if the zlib library version is incompatible with the - version assumed by the caller, or Z_STREAM_ERROR if the parameters are - invalid, such as a null pointer to the structure. msg is set to null if - there is no error message. inflateInit2 does not perform any decompression - apart from possibly reading the zlib header if present: actual decompression - will be done by inflate(). (So next_in and avail_in may be modified, but - next_out and avail_out are unused and unchanged.) The current implementation - of inflateInit2() does not process any header information -- that is - deferred until inflate() is called. -*/ - -ZEXTERN int ZEXPORT inflateSetDictionary OF((z_streamp strm, - const Bytef *dictionary, - uInt dictLength)); -/* - Initializes the decompression dictionary from the given uncompressed byte - sequence. This function must be called immediately after a call of inflate, - if that call returned Z_NEED_DICT. The dictionary chosen by the compressor - can be determined from the adler32 value returned by that call of inflate. - The compressor and decompressor must use exactly the same dictionary (see - deflateSetDictionary). For raw inflate, this function can be called at any - time to set the dictionary. If the provided dictionary is smaller than the - window and there is already data in the window, then the provided dictionary - will amend what's there. The application must insure that the dictionary - that was used for compression is provided. - - inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a - parameter is invalid (e.g. dictionary being Z_NULL) or the stream state is - inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the - expected one (incorrect adler32 value). inflateSetDictionary does not - perform any decompression: this will be done by subsequent calls of - inflate(). -*/ - -ZEXTERN int ZEXPORT inflateGetDictionary OF((z_streamp strm, - Bytef *dictionary, - uInt *dictLength)); -/* - Returns the sliding dictionary being maintained by inflate. dictLength is - set to the number of bytes in the dictionary, and that many bytes are copied - to dictionary. dictionary must have enough space, where 32768 bytes is - always enough. If inflateGetDictionary() is called with dictionary equal to - Z_NULL, then only the dictionary length is returned, and nothing is copied. - Similary, if dictLength is Z_NULL, then it is not set. - - inflateGetDictionary returns Z_OK on success, or Z_STREAM_ERROR if the - stream state is inconsistent. -*/ - -ZEXTERN int ZEXPORT inflateSync OF((z_streamp strm)); -/* - Skips invalid compressed data until a possible full flush point (see above - for the description of deflate with Z_FULL_FLUSH) can be found, or until all - available input is skipped. No output is provided. - - inflateSync searches for a 00 00 FF FF pattern in the compressed data. - All full flush points have this pattern, but not all occurrences of this - pattern are full flush points. - - inflateSync returns Z_OK if a possible full flush point has been found, - Z_BUF_ERROR if no more input was provided, Z_DATA_ERROR if no flush point - has been found, or Z_STREAM_ERROR if the stream structure was inconsistent. - In the success case, the application may save the current current value of - total_in which indicates where valid compressed data was found. In the - error case, the application may repeatedly call inflateSync, providing more - input each time, until success or end of the input data. -*/ - -ZEXTERN int ZEXPORT inflateCopy OF((z_streamp dest, - z_streamp source)); -/* - Sets the destination stream as a complete copy of the source stream. - - This function can be useful when randomly accessing a large stream. The - first pass through the stream can periodically record the inflate state, - allowing restarting inflate at those points when randomly accessing the - stream. - - inflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not - enough memory, Z_STREAM_ERROR if the source stream state was inconsistent - (such as zalloc being Z_NULL). msg is left unchanged in both source and - destination. -*/ - -ZEXTERN int ZEXPORT inflateReset OF((z_streamp strm)); -/* - This function is equivalent to inflateEnd followed by inflateInit, - but does not free and reallocate all the internal decompression state. The - stream will keep attributes that may have been set by inflateInit2. - - inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source - stream state was inconsistent (such as zalloc or state being Z_NULL). -*/ - -ZEXTERN int ZEXPORT inflateReset2 OF((z_streamp strm, - int windowBits)); -/* - This function is the same as inflateReset, but it also permits changing - the wrap and window size requests. The windowBits parameter is interpreted - the same as it is for inflateInit2. - - inflateReset2 returns Z_OK if success, or Z_STREAM_ERROR if the source - stream state was inconsistent (such as zalloc or state being Z_NULL), or if - the windowBits parameter is invalid. -*/ - -ZEXTERN int ZEXPORT inflatePrime OF((z_streamp strm, - int bits, - int value)); -/* - This function inserts bits in the inflate input stream. The intent is - that this function is used to start inflating at a bit position in the - middle of a byte. The provided bits will be used before any bytes are used - from next_in. This function should only be used with raw inflate, and - should be used before the first inflate() call after inflateInit2() or - inflateReset(). bits must be less than or equal to 16, and that many of the - least significant bits of value will be inserted in the input. - - If bits is negative, then the input stream bit buffer is emptied. Then - inflatePrime() can be called again to put bits in the buffer. This is used - to clear out bits leftover after feeding inflate a block description prior - to feeding inflate codes. - - inflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source - stream state was inconsistent. -*/ - -ZEXTERN long ZEXPORT inflateMark OF((z_streamp strm)); -/* - This function returns two values, one in the lower 16 bits of the return - value, and the other in the remaining upper bits, obtained by shifting the - return value down 16 bits. If the upper value is -1 and the lower value is - zero, then inflate() is currently decoding information outside of a block. - If the upper value is -1 and the lower value is non-zero, then inflate is in - the middle of a stored block, with the lower value equaling the number of - bytes from the input remaining to copy. If the upper value is not -1, then - it is the number of bits back from the current bit position in the input of - the code (literal or length/distance pair) currently being processed. In - that case the lower value is the number of bytes already emitted for that - code. - - A code is being processed if inflate is waiting for more input to complete - decoding of the code, or if it has completed decoding but is waiting for - more output space to write the literal or match data. - - inflateMark() is used to mark locations in the input data for random - access, which may be at bit positions, and to note those cases where the - output of a code may span boundaries of random access blocks. The current - location in the input stream can be determined from avail_in and data_type - as noted in the description for the Z_BLOCK flush parameter for inflate. - - inflateMark returns the value noted above or -1 << 16 if the provided - source stream state was inconsistent. -*/ - -ZEXTERN int ZEXPORT inflateGetHeader OF((z_streamp strm, - gz_headerp head)); -/* - inflateGetHeader() requests that gzip header information be stored in the - provided gz_header structure. inflateGetHeader() may be called after - inflateInit2() or inflateReset(), and before the first call of inflate(). - As inflate() processes the gzip stream, head->done is zero until the header - is completed, at which time head->done is set to one. If a zlib stream is - being decoded, then head->done is set to -1 to indicate that there will be - no gzip header information forthcoming. Note that Z_BLOCK or Z_TREES can be - used to force inflate() to return immediately after header processing is - complete and before any actual data is decompressed. - - The text, time, xflags, and os fields are filled in with the gzip header - contents. hcrc is set to true if there is a header CRC. (The header CRC - was valid if done is set to one.) If extra is not Z_NULL, then extra_max - contains the maximum number of bytes to write to extra. Once done is true, - extra_len contains the actual extra field length, and extra contains the - extra field, or that field truncated if extra_max is less than extra_len. - If name is not Z_NULL, then up to name_max characters are written there, - terminated with a zero unless the length is greater than name_max. If - comment is not Z_NULL, then up to comm_max characters are written there, - terminated with a zero unless the length is greater than comm_max. When any - of extra, name, or comment are not Z_NULL and the respective field is not - present in the header, then that field is set to Z_NULL to signal its - absence. This allows the use of deflateSetHeader() with the returned - structure to duplicate the header. However if those fields are set to - allocated memory, then the application will need to save those pointers - elsewhere so that they can be eventually freed. - - If inflateGetHeader is not used, then the header information is simply - discarded. The header is always checked for validity, including the header - CRC if present. inflateReset() will reset the process to discard the header - information. The application would need to call inflateGetHeader() again to - retrieve the header from the next gzip stream. - - inflateGetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source - stream state was inconsistent. -*/ - -/* -ZEXTERN int ZEXPORT inflateBackInit OF((z_streamp strm, int windowBits, - unsigned char FAR *window)); - - Initialize the internal stream state for decompression using inflateBack() - calls. The fields zalloc, zfree and opaque in strm must be initialized - before the call. If zalloc and zfree are Z_NULL, then the default library- - derived memory allocation routines are used. windowBits is the base two - logarithm of the window size, in the range 8..15. window is a caller - supplied buffer of that size. Except for special applications where it is - assured that deflate was used with small window sizes, windowBits must be 15 - and a 32K byte window must be supplied to be able to decompress general - deflate streams. - - See inflateBack() for the usage of these routines. - - inflateBackInit will return Z_OK on success, Z_STREAM_ERROR if any of - the parameters are invalid, Z_MEM_ERROR if the internal state could not be - allocated, or Z_VERSION_ERROR if the version of the library does not match - the version of the header file. -*/ - -typedef unsigned (*in_func) OF((void FAR *, - z_const unsigned char FAR * FAR *)); -typedef int (*out_func) OF((void FAR *, unsigned char FAR *, unsigned)); - -ZEXTERN int ZEXPORT inflateBack OF((z_streamp strm, - in_func in, void FAR *in_desc, - out_func out, void FAR *out_desc)); -/* - inflateBack() does a raw inflate with a single call using a call-back - interface for input and output. This is potentially more efficient than - inflate() for file i/o applications, in that it avoids copying between the - output and the sliding window by simply making the window itself the output - buffer. inflate() can be faster on modern CPUs when used with large - buffers. inflateBack() trusts the application to not change the output - buffer passed by the output function, at least until inflateBack() returns. - - inflateBackInit() must be called first to allocate the internal state - and to initialize the state with the user-provided window buffer. - inflateBack() may then be used multiple times to inflate a complete, raw - deflate stream with each call. inflateBackEnd() is then called to free the - allocated state. - - A raw deflate stream is one with no zlib or gzip header or trailer. - This routine would normally be used in a utility that reads zip or gzip - files and writes out uncompressed files. The utility would decode the - header and process the trailer on its own, hence this routine expects only - the raw deflate stream to decompress. This is different from the normal - behavior of inflate(), which expects either a zlib or gzip header and - trailer around the deflate stream. - - inflateBack() uses two subroutines supplied by the caller that are then - called by inflateBack() for input and output. inflateBack() calls those - routines until it reads a complete deflate stream and writes out all of the - uncompressed data, or until it encounters an error. The function's - parameters and return types are defined above in the in_func and out_func - typedefs. inflateBack() will call in(in_desc, &buf) which should return the - number of bytes of provided input, and a pointer to that input in buf. If - there is no input available, in() must return zero--buf is ignored in that - case--and inflateBack() will return a buffer error. inflateBack() will call - out(out_desc, buf, len) to write the uncompressed data buf[0..len-1]. out() - should return zero on success, or non-zero on failure. If out() returns - non-zero, inflateBack() will return with an error. Neither in() nor out() - are permitted to change the contents of the window provided to - inflateBackInit(), which is also the buffer that out() uses to write from. - The length written by out() will be at most the window size. Any non-zero - amount of input may be provided by in(). - - For convenience, inflateBack() can be provided input on the first call by - setting strm->next_in and strm->avail_in. If that input is exhausted, then - in() will be called. Therefore strm->next_in must be initialized before - calling inflateBack(). If strm->next_in is Z_NULL, then in() will be called - immediately for input. If strm->next_in is not Z_NULL, then strm->avail_in - must also be initialized, and then if strm->avail_in is not zero, input will - initially be taken from strm->next_in[0 .. strm->avail_in - 1]. - - The in_desc and out_desc parameters of inflateBack() is passed as the - first parameter of in() and out() respectively when they are called. These - descriptors can be optionally used to pass any information that the caller- - supplied in() and out() functions need to do their job. - - On return, inflateBack() will set strm->next_in and strm->avail_in to - pass back any unused input that was provided by the last in() call. The - return values of inflateBack() can be Z_STREAM_END on success, Z_BUF_ERROR - if in() or out() returned an error, Z_DATA_ERROR if there was a format error - in the deflate stream (in which case strm->msg is set to indicate the nature - of the error), or Z_STREAM_ERROR if the stream was not properly initialized. - In the case of Z_BUF_ERROR, an input or output error can be distinguished - using strm->next_in which will be Z_NULL only if in() returned an error. If - strm->next_in is not Z_NULL, then the Z_BUF_ERROR was due to out() returning - non-zero. (in() will always be called before out(), so strm->next_in is - assured to be defined if out() returns non-zero.) Note that inflateBack() - cannot return Z_OK. -*/ - -ZEXTERN int ZEXPORT inflateBackEnd OF((z_streamp strm)); -/* - All memory allocated by inflateBackInit() is freed. - - inflateBackEnd() returns Z_OK on success, or Z_STREAM_ERROR if the stream - state was inconsistent. -*/ - -ZEXTERN uLong ZEXPORT zlibCompileFlags OF((void)); -/* Return flags indicating compile-time options. - - Type sizes, two bits each, 00 = 16 bits, 01 = 32, 10 = 64, 11 = other: - 1.0: size of uInt - 3.2: size of uLong - 5.4: size of voidpf (pointer) - 7.6: size of z_off_t - - Compiler, assembler, and debug options: - 8: DEBUG - 9: ASMV or ASMINF -- use ASM code - 10: ZLIB_WINAPI -- exported functions use the WINAPI calling convention - 11: 0 (reserved) - - One-time table building (smaller code, but not thread-safe if true): - 12: BUILDFIXED -- build static block decoding tables when needed - 13: DYNAMIC_CRC_TABLE -- build CRC calculation tables when needed - 14,15: 0 (reserved) - - Library content (indicates missing functionality): - 16: NO_GZCOMPRESS -- gz* functions cannot compress (to avoid linking - deflate code when not needed) - 17: NO_GZIP -- deflate can't write gzip streams, and inflate can't detect - and decode gzip streams (to avoid linking crc code) - 18-19: 0 (reserved) - - Operation variations (changes in library functionality): - 20: PKZIP_BUG_WORKAROUND -- slightly more permissive inflate - 21: FASTEST -- deflate algorithm with only one, lowest compression level - 22,23: 0 (reserved) - - The sprintf variant used by gzprintf (zero is best): - 24: 0 = vs*, 1 = s* -- 1 means limited to 20 arguments after the format - 25: 0 = *nprintf, 1 = *printf -- 1 means gzprintf() not secure! - 26: 0 = returns value, 1 = void -- 1 means inferred string length returned - - Remainder: - 27-31: 0 (reserved) - */ - -#ifndef Z_SOLO - - /* utility functions */ - -/* - The following utility functions are implemented on top of the basic - stream-oriented functions. To simplify the interface, some default options - are assumed (compression level and memory usage, standard memory allocation - functions). The source code of these utility functions can be modified if - you need special options. -*/ - -ZEXTERN int ZEXPORT compress OF((Bytef *dest, uLongf *destLen, - const Bytef *source, uLong sourceLen)); -/* - Compresses the source buffer into the destination buffer. sourceLen is - the byte length of the source buffer. Upon entry, destLen is the total size - of the destination buffer, which must be at least the value returned by - compressBound(sourceLen). Upon exit, destLen is the actual size of the - compressed buffer. - - compress returns Z_OK if success, Z_MEM_ERROR if there was not - enough memory, Z_BUF_ERROR if there was not enough room in the output - buffer. -*/ - -ZEXTERN int ZEXPORT compress2 OF((Bytef *dest, uLongf *destLen, - const Bytef *source, uLong sourceLen, - int level)); -/* - Compresses the source buffer into the destination buffer. The level - parameter has the same meaning as in deflateInit. sourceLen is the byte - length of the source buffer. Upon entry, destLen is the total size of the - destination buffer, which must be at least the value returned by - compressBound(sourceLen). Upon exit, destLen is the actual size of the - compressed buffer. - - compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough - memory, Z_BUF_ERROR if there was not enough room in the output buffer, - Z_STREAM_ERROR if the level parameter is invalid. -*/ - -ZEXTERN uLong ZEXPORT compressBound OF((uLong sourceLen)); -/* - compressBound() returns an upper bound on the compressed size after - compress() or compress2() on sourceLen bytes. It would be used before a - compress() or compress2() call to allocate the destination buffer. -*/ - -ZEXTERN int ZEXPORT uncompress OF((Bytef *dest, uLongf *destLen, - const Bytef *source, uLong sourceLen)); -/* - Decompresses the source buffer into the destination buffer. sourceLen is - the byte length of the source buffer. Upon entry, destLen is the total size - of the destination buffer, which must be large enough to hold the entire - uncompressed data. (The size of the uncompressed data must have been saved - previously by the compressor and transmitted to the decompressor by some - mechanism outside the scope of this compression library.) Upon exit, destLen - is the actual size of the uncompressed buffer. - - uncompress returns Z_OK if success, Z_MEM_ERROR if there was not - enough memory, Z_BUF_ERROR if there was not enough room in the output - buffer, or Z_DATA_ERROR if the input data was corrupted or incomplete. In - the case where there is not enough room, uncompress() will fill the output - buffer with the uncompressed data up to that point. -*/ - - /* gzip file access functions */ - -/* - This library supports reading and writing files in gzip (.gz) format with - an interface similar to that of stdio, using the functions that start with - "gz". The gzip format is different from the zlib format. gzip is a gzip - wrapper, documented in RFC 1952, wrapped around a deflate stream. -*/ - -typedef struct gzFile_s *gzFile; /* semi-opaque gzip file descriptor */ - -/* -ZEXTERN gzFile ZEXPORT gzopen OF((const char *path, const char *mode)); - - Opens a gzip (.gz) file for reading or writing. The mode parameter is as - in fopen ("rb" or "wb") but can also include a compression level ("wb9") or - a strategy: 'f' for filtered data as in "wb6f", 'h' for Huffman-only - compression as in "wb1h", 'R' for run-length encoding as in "wb1R", or 'F' - for fixed code compression as in "wb9F". (See the description of - deflateInit2 for more information about the strategy parameter.) 'T' will - request transparent writing or appending with no compression and not using - the gzip format. - - "a" can be used instead of "w" to request that the gzip stream that will - be written be appended to the file. "+" will result in an error, since - reading and writing to the same gzip file is not supported. The addition of - "x" when writing will create the file exclusively, which fails if the file - already exists. On systems that support it, the addition of "e" when - reading or writing will set the flag to close the file on an execve() call. - - These functions, as well as gzip, will read and decode a sequence of gzip - streams in a file. The append function of gzopen() can be used to create - such a file. (Also see gzflush() for another way to do this.) When - appending, gzopen does not test whether the file begins with a gzip stream, - nor does it look for the end of the gzip streams to begin appending. gzopen - will simply append a gzip stream to the existing file. - - gzopen can be used to read a file which is not in gzip format; in this - case gzread will directly read from the file without decompression. When - reading, this will be detected automatically by looking for the magic two- - byte gzip header. - - gzopen returns NULL if the file could not be opened, if there was - insufficient memory to allocate the gzFile state, or if an invalid mode was - specified (an 'r', 'w', or 'a' was not provided, or '+' was provided). - errno can be checked to determine if the reason gzopen failed was that the - file could not be opened. -*/ - -ZEXTERN gzFile ZEXPORT gzdopen OF((int fd, const char *mode)); -/* - gzdopen associates a gzFile with the file descriptor fd. File descriptors - are obtained from calls like open, dup, creat, pipe or fileno (if the file - has been previously opened with fopen). The mode parameter is as in gzopen. - - The next call of gzclose on the returned gzFile will also close the file - descriptor fd, just like fclose(fdopen(fd, mode)) closes the file descriptor - fd. If you want to keep fd open, use fd = dup(fd_keep); gz = gzdopen(fd, - mode);. The duplicated descriptor should be saved to avoid a leak, since - gzdopen does not close fd if it fails. If you are using fileno() to get the - file descriptor from a FILE *, then you will have to use dup() to avoid - double-close()ing the file descriptor. Both gzclose() and fclose() will - close the associated file descriptor, so they need to have different file - descriptors. - - gzdopen returns NULL if there was insufficient memory to allocate the - gzFile state, if an invalid mode was specified (an 'r', 'w', or 'a' was not - provided, or '+' was provided), or if fd is -1. The file descriptor is not - used until the next gz* read, write, seek, or close operation, so gzdopen - will not detect if fd is invalid (unless fd is -1). -*/ - -ZEXTERN int ZEXPORT gzbuffer OF((gzFile file, unsigned size)); -/* - Set the internal buffer size used by this library's functions. The - default buffer size is 8192 bytes. This function must be called after - gzopen() or gzdopen(), and before any other calls that read or write the - file. The buffer memory allocation is always deferred to the first read or - write. Two buffers are allocated, either both of the specified size when - writing, or one of the specified size and the other twice that size when - reading. A larger buffer size of, for example, 64K or 128K bytes will - noticeably increase the speed of decompression (reading). - - The new buffer size also affects the maximum length for gzprintf(). - - gzbuffer() returns 0 on success, or -1 on failure, such as being called - too late. -*/ - -ZEXTERN int ZEXPORT gzsetparams OF((gzFile file, int level, int strategy)); -/* - Dynamically update the compression level or strategy. See the description - of deflateInit2 for the meaning of these parameters. - - gzsetparams returns Z_OK if success, or Z_STREAM_ERROR if the file was not - opened for writing. -*/ - -ZEXTERN int ZEXPORT gzread OF((gzFile file, voidp buf, unsigned len)); -/* - Reads the given number of uncompressed bytes from the compressed file. If - the input file is not in gzip format, gzread copies the given number of - bytes into the buffer directly from the file. - - After reaching the end of a gzip stream in the input, gzread will continue - to read, looking for another gzip stream. Any number of gzip streams may be - concatenated in the input file, and will all be decompressed by gzread(). - If something other than a gzip stream is encountered after a gzip stream, - that remaining trailing garbage is ignored (and no error is returned). - - gzread can be used to read a gzip file that is being concurrently written. - Upon reaching the end of the input, gzread will return with the available - data. If the error code returned by gzerror is Z_OK or Z_BUF_ERROR, then - gzclearerr can be used to clear the end of file indicator in order to permit - gzread to be tried again. Z_OK indicates that a gzip stream was completed - on the last gzread. Z_BUF_ERROR indicates that the input file ended in the - middle of a gzip stream. Note that gzread does not return -1 in the event - of an incomplete gzip stream. This error is deferred until gzclose(), which - will return Z_BUF_ERROR if the last gzread ended in the middle of a gzip - stream. Alternatively, gzerror can be used before gzclose to detect this - case. - - gzread returns the number of uncompressed bytes actually read, less than - len for end of file, or -1 for error. -*/ - -ZEXTERN int ZEXPORT gzwrite OF((gzFile file, - voidpc buf, unsigned len)); -/* - Writes the given number of uncompressed bytes into the compressed file. - gzwrite returns the number of uncompressed bytes written or 0 in case of - error. -*/ - -ZEXTERN int ZEXPORTVA gzprintf Z_ARG((gzFile file, const char *format, ...)); -/* - Converts, formats, and writes the arguments to the compressed file under - control of the format string, as in fprintf. gzprintf returns the number of - uncompressed bytes actually written, or 0 in case of error. The number of - uncompressed bytes written is limited to 8191, or one less than the buffer - size given to gzbuffer(). The caller should assure that this limit is not - exceeded. If it is exceeded, then gzprintf() will return an error (0) with - nothing written. In this case, there may also be a buffer overflow with - unpredictable consequences, which is possible only if zlib was compiled with - the insecure functions sprintf() or vsprintf() because the secure snprintf() - or vsnprintf() functions were not available. This can be determined using - zlibCompileFlags(). -*/ - -ZEXTERN int ZEXPORT gzputs OF((gzFile file, const char *s)); -/* - Writes the given null-terminated string to the compressed file, excluding - the terminating null character. - - gzputs returns the number of characters written, or -1 in case of error. -*/ - -ZEXTERN char * ZEXPORT gzgets OF((gzFile file, char *buf, int len)); -/* - Reads bytes from the compressed file until len-1 characters are read, or a - newline character is read and transferred to buf, or an end-of-file - condition is encountered. If any characters are read or if len == 1, the - string is terminated with a null character. If no characters are read due - to an end-of-file or len < 1, then the buffer is left untouched. - - gzgets returns buf which is a null-terminated string, or it returns NULL - for end-of-file or in case of error. If there was an error, the contents at - buf are indeterminate. -*/ - -ZEXTERN int ZEXPORT gzputc OF((gzFile file, int c)); -/* - Writes c, converted to an unsigned char, into the compressed file. gzputc - returns the value that was written, or -1 in case of error. -*/ - -ZEXTERN int ZEXPORT gzgetc OF((gzFile file)); -/* - Reads one byte from the compressed file. gzgetc returns this byte or -1 - in case of end of file or error. This is implemented as a macro for speed. - As such, it does not do all of the checking the other functions do. I.e. - it does not check to see if file is NULL, nor whether the structure file - points to has been clobbered or not. -*/ - -ZEXTERN int ZEXPORT gzungetc OF((int c, gzFile file)); -/* - Push one character back onto the stream to be read as the first character - on the next read. At least one character of push-back is allowed. - gzungetc() returns the character pushed, or -1 on failure. gzungetc() will - fail if c is -1, and may fail if a character has been pushed but not read - yet. If gzungetc is used immediately after gzopen or gzdopen, at least the - output buffer size of pushed characters is allowed. (See gzbuffer above.) - The pushed character will be discarded if the stream is repositioned with - gzseek() or gzrewind(). -*/ - -ZEXTERN int ZEXPORT gzflush OF((gzFile file, int flush)); -/* - Flushes all pending output into the compressed file. The parameter flush - is as in the deflate() function. The return value is the zlib error number - (see function gzerror below). gzflush is only permitted when writing. - - If the flush parameter is Z_FINISH, the remaining data is written and the - gzip stream is completed in the output. If gzwrite() is called again, a new - gzip stream will be started in the output. gzread() is able to read such - concatented gzip streams. - - gzflush should be called only when strictly necessary because it will - degrade compression if called too often. -*/ - -/* -ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile file, - z_off_t offset, int whence)); - - Sets the starting position for the next gzread or gzwrite on the given - compressed file. The offset represents a number of bytes in the - uncompressed data stream. The whence parameter is defined as in lseek(2); - the value SEEK_END is not supported. - - If the file is opened for reading, this function is emulated but can be - extremely slow. If the file is opened for writing, only forward seeks are - supported; gzseek then compresses a sequence of zeroes up to the new - starting position. - - gzseek returns the resulting offset location as measured in bytes from - the beginning of the uncompressed stream, or -1 in case of error, in - particular if the file is opened for writing and the new starting position - would be before the current position. -*/ - -ZEXTERN int ZEXPORT gzrewind OF((gzFile file)); -/* - Rewinds the given file. This function is supported only for reading. - - gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET) -*/ - -/* -ZEXTERN z_off_t ZEXPORT gztell OF((gzFile file)); - - Returns the starting position for the next gzread or gzwrite on the given - compressed file. This position represents a number of bytes in the - uncompressed data stream, and is zero when starting, even if appending or - reading a gzip stream from the middle of a file using gzdopen(). - - gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR) -*/ - -/* -ZEXTERN z_off_t ZEXPORT gzoffset OF((gzFile file)); - - Returns the current offset in the file being read or written. This offset - includes the count of bytes that precede the gzip stream, for example when - appending or when using gzdopen() for reading. When reading, the offset - does not include as yet unused buffered input. This information can be used - for a progress indicator. On error, gzoffset() returns -1. -*/ - -ZEXTERN int ZEXPORT gzeof OF((gzFile file)); -/* - Returns true (1) if the end-of-file indicator has been set while reading, - false (0) otherwise. Note that the end-of-file indicator is set only if the - read tried to go past the end of the input, but came up short. Therefore, - just like feof(), gzeof() may return false even if there is no more data to - read, in the event that the last read request was for the exact number of - bytes remaining in the input file. This will happen if the input file size - is an exact multiple of the buffer size. - - If gzeof() returns true, then the read functions will return no more data, - unless the end-of-file indicator is reset by gzclearerr() and the input file - has grown since the previous end of file was detected. -*/ - -ZEXTERN int ZEXPORT gzdirect OF((gzFile file)); -/* - Returns true (1) if file is being copied directly while reading, or false - (0) if file is a gzip stream being decompressed. - - If the input file is empty, gzdirect() will return true, since the input - does not contain a gzip stream. - - If gzdirect() is used immediately after gzopen() or gzdopen() it will - cause buffers to be allocated to allow reading the file to determine if it - is a gzip file. Therefore if gzbuffer() is used, it should be called before - gzdirect(). - - When writing, gzdirect() returns true (1) if transparent writing was - requested ("wT" for the gzopen() mode), or false (0) otherwise. (Note: - gzdirect() is not needed when writing. Transparent writing must be - explicitly requested, so the application already knows the answer. When - linking statically, using gzdirect() will include all of the zlib code for - gzip file reading and decompression, which may not be desired.) -*/ - -ZEXTERN int ZEXPORT gzclose OF((gzFile file)); -/* - Flushes all pending output if necessary, closes the compressed file and - deallocates the (de)compression state. Note that once file is closed, you - cannot call gzerror with file, since its structures have been deallocated. - gzclose must not be called more than once on the same file, just as free - must not be called more than once on the same allocation. - - gzclose will return Z_STREAM_ERROR if file is not valid, Z_ERRNO on a - file operation error, Z_MEM_ERROR if out of memory, Z_BUF_ERROR if the - last read ended in the middle of a gzip stream, or Z_OK on success. -*/ - -ZEXTERN int ZEXPORT gzclose_r OF((gzFile file)); -ZEXTERN int ZEXPORT gzclose_w OF((gzFile file)); -/* - Same as gzclose(), but gzclose_r() is only for use when reading, and - gzclose_w() is only for use when writing or appending. The advantage to - using these instead of gzclose() is that they avoid linking in zlib - compression or decompression code that is not used when only reading or only - writing respectively. If gzclose() is used, then both compression and - decompression code will be included the application when linking to a static - zlib library. -*/ - -ZEXTERN const char * ZEXPORT gzerror OF((gzFile file, int *errnum)); -/* - Returns the error message for the last error which occurred on the given - compressed file. errnum is set to zlib error number. If an error occurred - in the file system and not in the compression library, errnum is set to - Z_ERRNO and the application may consult errno to get the exact error code. - - The application must not modify the returned string. Future calls to - this function may invalidate the previously returned string. If file is - closed, then the string previously returned by gzerror will no longer be - available. - - gzerror() should be used to distinguish errors from end-of-file for those - functions above that do not distinguish those cases in their return values. -*/ - -ZEXTERN void ZEXPORT gzclearerr OF((gzFile file)); -/* - Clears the error and end-of-file flags for file. This is analogous to the - clearerr() function in stdio. This is useful for continuing to read a gzip - file that is being written concurrently. -*/ - -#endif /* !Z_SOLO */ - - /* checksum functions */ - -/* - These functions are not related to compression but are exported - anyway because they might be useful in applications using the compression - library. -*/ - -ZEXTERN uLong ZEXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len)); -/* - Update a running Adler-32 checksum with the bytes buf[0..len-1] and - return the updated checksum. If buf is Z_NULL, this function returns the - required initial value for the checksum. - - An Adler-32 checksum is almost as reliable as a CRC32 but can be computed - much faster. - - Usage example: - - uLong adler = adler32(0L, Z_NULL, 0); - - while (read_buffer(buffer, length) != EOF) { - adler = adler32(adler, buffer, length); - } - if (adler != original_adler) error(); -*/ - -/* -ZEXTERN uLong ZEXPORT adler32_combine OF((uLong adler1, uLong adler2, - z_off_t len2)); - - Combine two Adler-32 checksums into one. For two sequences of bytes, seq1 - and seq2 with lengths len1 and len2, Adler-32 checksums were calculated for - each, adler1 and adler2. adler32_combine() returns the Adler-32 checksum of - seq1 and seq2 concatenated, requiring only adler1, adler2, and len2. Note - that the z_off_t type (like off_t) is a signed integer. If len2 is - negative, the result has no meaning or utility. -*/ - -ZEXTERN uLong ZEXPORT crc32 OF((uLong crc, const Bytef *buf, uInt len)); -/* - Update a running CRC-32 with the bytes buf[0..len-1] and return the - updated CRC-32. If buf is Z_NULL, this function returns the required - initial value for the crc. Pre- and post-conditioning (one's complement) is - performed within this function so it shouldn't be done by the application. - - Usage example: - - uLong crc = crc32(0L, Z_NULL, 0); - - while (read_buffer(buffer, length) != EOF) { - crc = crc32(crc, buffer, length); - } - if (crc != original_crc) error(); -*/ - -/* -ZEXTERN uLong ZEXPORT crc32_combine OF((uLong crc1, uLong crc2, z_off_t len2)); - - Combine two CRC-32 check values into one. For two sequences of bytes, - seq1 and seq2 with lengths len1 and len2, CRC-32 check values were - calculated for each, crc1 and crc2. crc32_combine() returns the CRC-32 - check value of seq1 and seq2 concatenated, requiring only crc1, crc2, and - len2. -*/ - - - /* various hacks, don't look :) */ - -/* deflateInit and inflateInit are macros to allow checking the zlib version - * and the compiler's view of z_stream: - */ -ZEXTERN int ZEXPORT deflateInit_ OF((z_streamp strm, int level, - const char *version, int stream_size)); -ZEXTERN int ZEXPORT inflateInit_ OF((z_streamp strm, - const char *version, int stream_size)); -ZEXTERN int ZEXPORT deflateInit2_ OF((z_streamp strm, int level, int method, - int windowBits, int memLevel, - int strategy, const char *version, - int stream_size)); -ZEXTERN int ZEXPORT inflateInit2_ OF((z_streamp strm, int windowBits, - const char *version, int stream_size)); -ZEXTERN int ZEXPORT inflateBackInit_ OF((z_streamp strm, int windowBits, - unsigned char FAR *window, - const char *version, - int stream_size)); -#define deflateInit(strm, level) \ - deflateInit_((strm), (level), ZLIB_VERSION, (int)sizeof(z_stream)) -#define inflateInit(strm) \ - inflateInit_((strm), ZLIB_VERSION, (int)sizeof(z_stream)) -#define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \ - deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\ - (strategy), ZLIB_VERSION, (int)sizeof(z_stream)) -#define inflateInit2(strm, windowBits) \ - inflateInit2_((strm), (windowBits), ZLIB_VERSION, \ - (int)sizeof(z_stream)) -#define inflateBackInit(strm, windowBits, window) \ - inflateBackInit_((strm), (windowBits), (window), \ - ZLIB_VERSION, (int)sizeof(z_stream)) - -#ifndef Z_SOLO - -/* gzgetc() macro and its supporting function and exposed data structure. Note - * that the real internal state is much larger than the exposed structure. - * This abbreviated structure exposes just enough for the gzgetc() macro. The - * user should not mess with these exposed elements, since their names or - * behavior could change in the future, perhaps even capriciously. They can - * only be used by the gzgetc() macro. You have been warned. - */ -struct gzFile_s { - unsigned have; - unsigned char *next; - z_off64_t pos; -}; -ZEXTERN int ZEXPORT gzgetc_ OF((gzFile file)); /* backward compatibility */ -#ifdef Z_PREFIX_SET -# undef z_gzgetc -# define z_gzgetc(g) \ - ((g)->have ? ((g)->have--, (g)->pos++, *((g)->next)++) : gzgetc(g)) -#else -# define gzgetc(g) \ - ((g)->have ? ((g)->have--, (g)->pos++, *((g)->next)++) : gzgetc(g)) -#endif - -/* provide 64-bit offset functions if _LARGEFILE64_SOURCE defined, and/or - * change the regular functions to 64 bits if _FILE_OFFSET_BITS is 64 (if - * both are true, the application gets the *64 functions, and the regular - * functions are changed to 64 bits) -- in case these are set on systems - * without large file support, _LFS64_LARGEFILE must also be true - */ -#ifdef Z_LARGE64 - ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *)); - ZEXTERN z_off64_t ZEXPORT gzseek64 OF((gzFile, z_off64_t, int)); - ZEXTERN z_off64_t ZEXPORT gztell64 OF((gzFile)); - ZEXTERN z_off64_t ZEXPORT gzoffset64 OF((gzFile)); - ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off64_t)); - ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off64_t)); -#endif - -#if !defined(ZLIB_INTERNAL) && defined(Z_WANT64) -# ifdef Z_PREFIX_SET -# define z_gzopen z_gzopen64 -# define z_gzseek z_gzseek64 -# define z_gztell z_gztell64 -# define z_gzoffset z_gzoffset64 -# define z_adler32_combine z_adler32_combine64 -# define z_crc32_combine z_crc32_combine64 -# else -# define gzopen gzopen64 -# define gzseek gzseek64 -# define gztell gztell64 -# define gzoffset gzoffset64 -# define adler32_combine adler32_combine64 -# define crc32_combine crc32_combine64 -# endif -# ifndef Z_LARGE64 - ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *)); - ZEXTERN z_off_t ZEXPORT gzseek64 OF((gzFile, z_off_t, int)); - ZEXTERN z_off_t ZEXPORT gztell64 OF((gzFile)); - ZEXTERN z_off_t ZEXPORT gzoffset64 OF((gzFile)); - ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off_t)); - ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off_t)); -# endif -#else - ZEXTERN gzFile ZEXPORT gzopen OF((const char *, const char *)); - ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile, z_off_t, int)); - ZEXTERN z_off_t ZEXPORT gztell OF((gzFile)); - ZEXTERN z_off_t ZEXPORT gzoffset OF((gzFile)); - ZEXTERN uLong ZEXPORT adler32_combine OF((uLong, uLong, z_off_t)); - ZEXTERN uLong ZEXPORT crc32_combine OF((uLong, uLong, z_off_t)); -#endif - -#else /* Z_SOLO */ - - ZEXTERN uLong ZEXPORT adler32_combine OF((uLong, uLong, z_off_t)); - ZEXTERN uLong ZEXPORT crc32_combine OF((uLong, uLong, z_off_t)); - -#endif /* !Z_SOLO */ - -/* hack for buggy compilers */ -#if !defined(ZUTIL_H) && !defined(NO_DUMMY_DECL) - struct internal_state {int dummy;}; -#endif - -/* undocumented functions */ -ZEXTERN const char * ZEXPORT zError OF((int)); -ZEXTERN int ZEXPORT inflateSyncPoint OF((z_streamp)); -ZEXTERN const z_crc_t FAR * ZEXPORT get_crc_table OF((void)); -ZEXTERN int ZEXPORT inflateUndermine OF((z_streamp, int)); -ZEXTERN int ZEXPORT inflateResetKeep OF((z_streamp)); -ZEXTERN int ZEXPORT deflateResetKeep OF((z_streamp)); -#if defined(_WIN32) && !defined(Z_SOLO) -ZEXTERN gzFile ZEXPORT gzopen_w OF((const wchar_t *path, - const char *mode)); -#endif -#if defined(STDC) || defined(Z_HAVE_STDARG_H) -# ifndef Z_SOLO -ZEXTERN int ZEXPORTVA gzvprintf Z_ARG((gzFile file, - const char *format, - va_list va)); -# endif -#endif - -#ifdef __cplusplus -} -#endif - -#endif /* ZLIB_H */ diff --git a/deps/zlib/zutil.c b/deps/zlib/zutil.c deleted file mode 100644 index 2fe2a7140..000000000 --- a/deps/zlib/zutil.c +++ /dev/null @@ -1,321 +0,0 @@ -/* zutil.c -- target dependent utility functions for the compression library - * Copyright (C) 1995-2005, 2010, 2011, 2012 Jean-loup Gailly. - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* @(#) $Id$ */ - -#include "zutil.h" - -#ifndef NO_DUMMY_DECL -struct internal_state {int dummy;}; /* for buggy compilers */ -#endif - -z_const char * const z_errmsg[10] = { -"need dictionary", /* Z_NEED_DICT 2 */ -"stream end", /* Z_STREAM_END 1 */ -"", /* Z_OK 0 */ -"file error", /* Z_ERRNO (-1) */ -"stream error", /* Z_STREAM_ERROR (-2) */ -"data error", /* Z_DATA_ERROR (-3) */ -"insufficient memory", /* Z_MEM_ERROR (-4) */ -"buffer error", /* Z_BUF_ERROR (-5) */ -"incompatible version",/* Z_VERSION_ERROR (-6) */ -""}; - - -const char * ZEXPORT zlibVersion() -{ - return ZLIB_VERSION; -} - -uLong ZEXPORT zlibCompileFlags() -{ - uLong flags; - - flags = 0; - switch ((int)(sizeof(uInt))) { - case 2: break; - case 4: flags += 1; break; - case 8: flags += 2; break; - default: flags += 3; - } - switch ((int)(sizeof(uLong))) { - case 2: break; - case 4: flags += 1 << 2; break; - case 8: flags += 2 << 2; break; - default: flags += 3 << 2; - } - switch ((int)(sizeof(voidpf))) { - case 2: break; - case 4: flags += 1 << 4; break; - case 8: flags += 2 << 4; break; - default: flags += 3 << 4; - } - switch ((int)(sizeof(z_off_t))) { - case 2: break; - case 4: flags += 1 << 6; break; - case 8: flags += 2 << 6; break; - default: flags += 3 << 6; - } -#ifdef DEBUG - flags += 1 << 8; -#endif -#if defined(ASMV) || defined(ASMINF) - flags += 1 << 9; -#endif -#ifdef ZLIB_WINAPI - flags += 1 << 10; -#endif -#ifdef BUILDFIXED - flags += 1 << 12; -#endif -#ifdef DYNAMIC_CRC_TABLE - flags += 1 << 13; -#endif -#ifdef NO_GZCOMPRESS - flags += 1L << 16; -#endif -#ifdef NO_GZIP - flags += 1L << 17; -#endif -#ifdef PKZIP_BUG_WORKAROUND - flags += 1L << 20; -#endif -#ifdef FASTEST - flags += 1L << 21; -#endif -#if defined(STDC) || defined(Z_HAVE_STDARG_H) -# ifdef NO_vsnprintf - flags += 1L << 25; -# ifdef HAS_vsprintf_void - flags += 1L << 26; -# endif -# else -# ifdef HAS_vsnprintf_void - flags += 1L << 26; -# endif -# endif -#else - flags += 1L << 24; -# ifdef NO_snprintf - flags += 1L << 25; -# ifdef HAS_sprintf_void - flags += 1L << 26; -# endif -# else -# ifdef HAS_snprintf_void - flags += 1L << 26; -# endif -# endif -#endif - return flags; -} - -#ifdef DEBUG - -# ifndef verbose -# define verbose 0 -# endif -int ZLIB_INTERNAL z_verbose = verbose; - -void ZLIB_INTERNAL z_error (m) - char *m; -{ - fprintf(stderr, "%s\n", m); - exit(1); -} -#endif - -/* exported to allow conversion of error code to string for compress() and - * uncompress() - */ -const char * ZEXPORT zError(err) - int err; -{ - return ERR_MSG(err); -} - -#if defined(_WIN32_WCE) - /* The Microsoft C Run-Time Library for Windows CE doesn't have - * errno. We define it as a global variable to simplify porting. - * Its value is always 0 and should not be used. - */ - int errno = 0; -#endif - -#ifndef HAVE_MEMCPY - -void ZLIB_INTERNAL zmemcpy(dest, source, len) - Bytef* dest; - const Bytef* source; - uInt len; -{ - if (len == 0) return; - do { - *dest++ = *source++; /* ??? to be unrolled */ - } while (--len != 0); -} - -int ZLIB_INTERNAL zmemcmp(s1, s2, len) - const Bytef* s1; - const Bytef* s2; - uInt len; -{ - uInt j; - - for (j = 0; j < len; j++) { - if (s1[j] != s2[j]) return 2*(s1[j] > s2[j])-1; - } - return 0; -} - -void ZLIB_INTERNAL zmemzero(dest, len) - Bytef* dest; - uInt len; -{ - if (len == 0) return; - do { - *dest++ = 0; /* ??? to be unrolled */ - } while (--len != 0); -} -#endif - -#ifndef Z_SOLO - -#ifdef SYS16BIT - -#ifdef __TURBOC__ -/* Turbo C in 16-bit mode */ - -# define MY_ZCALLOC - -/* Turbo C malloc() does not allow dynamic allocation of 64K bytes - * and farmalloc(64K) returns a pointer with an offset of 8, so we - * must fix the pointer. Warning: the pointer must be put back to its - * original form in order to free it, use zcfree(). - */ - -#define MAX_PTR 10 -/* 10*64K = 640K */ - -local int next_ptr = 0; - -typedef struct ptr_table_s { - voidpf org_ptr; - voidpf new_ptr; -} ptr_table; - -local ptr_table table[MAX_PTR]; -/* This table is used to remember the original form of pointers - * to large buffers (64K). Such pointers are normalized with a zero offset. - * Since MSDOS is not a preemptive multitasking OS, this table is not - * protected from concurrent access. This hack doesn't work anyway on - * a protected system like OS/2. Use Microsoft C instead. - */ - -voidpf ZLIB_INTERNAL zcalloc (voidpf opaque, unsigned items, unsigned size) -{ - voidpf buf = opaque; /* just to make some compilers happy */ - ulg bsize = (ulg)items*size; - - /* If we allocate less than 65520 bytes, we assume that farmalloc - * will return a usable pointer which doesn't have to be normalized. - */ - if (bsize < 65520L) { - buf = farmalloc(bsize); - if (*(ush*)&buf != 0) return buf; - } else { - buf = farmalloc(bsize + 16L); - } - if (buf == NULL || next_ptr >= MAX_PTR) return NULL; - table[next_ptr].org_ptr = buf; - - /* Normalize the pointer to seg:0 */ - *((ush*)&buf+1) += ((ush)((uch*)buf-0) + 15) >> 4; - *(ush*)&buf = 0; - table[next_ptr++].new_ptr = buf; - return buf; -} - -void ZLIB_INTERNAL zcfree (voidpf opaque, voidpf ptr) -{ - int n; - if (*(ush*)&ptr != 0) { /* object < 64K */ - farfree(ptr); - return; - } - /* Find the original pointer */ - for (n = 0; n < next_ptr; n++) { - if (ptr != table[n].new_ptr) continue; - - farfree(table[n].org_ptr); - while (++n < next_ptr) { - table[n-1] = table[n]; - } - next_ptr--; - return; - } - ptr = opaque; /* just to make some compilers happy */ - Assert(0, "zcfree: ptr not found"); -} - -#endif /* __TURBOC__ */ - - -#ifdef M_I86 -/* Microsoft C in 16-bit mode */ - -# define MY_ZCALLOC - -#if (!defined(_MSC_VER) || (_MSC_VER <= 600)) -# define _halloc halloc -# define _hfree hfree -#endif - -voidpf ZLIB_INTERNAL zcalloc (voidpf opaque, uInt items, uInt size) -{ - if (opaque) opaque = 0; /* to make compiler happy */ - return _halloc((long)items, size); -} - -void ZLIB_INTERNAL zcfree (voidpf opaque, voidpf ptr) -{ - if (opaque) opaque = 0; /* to make compiler happy */ - _hfree(ptr); -} - -#endif /* M_I86 */ - -#endif /* SYS16BIT */ - - -#ifndef MY_ZCALLOC /* Any system without a special alloc function */ - -#ifndef STDC -extern voidp malloc OF((uInt size)); -extern voidp calloc OF((uInt items, uInt size)); -extern void free OF((voidpf ptr)); -#endif - -voidpf ZLIB_INTERNAL zcalloc (opaque, items, size) - voidpf opaque; - unsigned items; - unsigned size; -{ - if (opaque) items += size - size; /* make compiler happy */ - return sizeof(uInt) > 2 ? (voidpf)malloc(items * size) : - (voidpf)calloc(items, size); -} - -void ZLIB_INTERNAL zcfree (opaque, ptr) - voidpf opaque; - voidpf ptr; -{ - free(ptr); - if (opaque) return; /* make compiler happy */ -} - -#endif /* MY_ZCALLOC */ - -#endif /* !Z_SOLO */ diff --git a/deps/zlib/zutil.h b/deps/zlib/zutil.h deleted file mode 100644 index 24ab06b1c..000000000 --- a/deps/zlib/zutil.h +++ /dev/null @@ -1,253 +0,0 @@ -/* zutil.h -- internal interface and configuration of the compression library - * Copyright (C) 1995-2013 Jean-loup Gailly. - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* WARNING: this file should *not* be used by applications. It is - part of the implementation of the compression library and is - subject to change. Applications should only use zlib.h. - */ - -/* @(#) $Id$ */ - -#ifndef ZUTIL_H -#define ZUTIL_H - -#ifdef HAVE_HIDDEN -# define ZLIB_INTERNAL __attribute__((visibility ("hidden"))) -#else -# define ZLIB_INTERNAL -#endif - -#include "zlib.h" - -#if defined(STDC) && !defined(Z_SOLO) -# if !(defined(_WIN32_WCE) && defined(_MSC_VER)) -# include -# endif -# include -# include -#endif - -#ifdef Z_SOLO - typedef long ptrdiff_t; /* guess -- will be caught if guess is wrong */ -#endif - -#ifndef local -# define local static -#endif -/* compile with -Dlocal if your debugger can't find static symbols */ - -typedef unsigned char uch; -typedef uch FAR uchf; -typedef unsigned short ush; -typedef ush FAR ushf; -typedef unsigned long ulg; - -extern z_const char * const z_errmsg[10]; /* indexed by 2-zlib_error */ -/* (size given to avoid silly warnings with Visual C++) */ - -#define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)] - -#define ERR_RETURN(strm,err) \ - return (strm->msg = ERR_MSG(err), (err)) -/* To be used only when the state is known to be valid */ - - /* common constants */ - -#ifndef DEF_WBITS -# define DEF_WBITS MAX_WBITS -#endif -/* default windowBits for decompression. MAX_WBITS is for compression only */ - -#if MAX_MEM_LEVEL >= 8 -# define DEF_MEM_LEVEL 8 -#else -# define DEF_MEM_LEVEL MAX_MEM_LEVEL -#endif -/* default memLevel */ - -#define STORED_BLOCK 0 -#define STATIC_TREES 1 -#define DYN_TREES 2 -/* The three kinds of block type */ - -#define MIN_MATCH 3 -#define MAX_MATCH 258 -/* The minimum and maximum match lengths */ - -#define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */ - - /* target dependencies */ - -#if defined(MSDOS) || (defined(WINDOWS) && !defined(WIN32)) -# define OS_CODE 0x00 -# ifndef Z_SOLO -# if defined(__TURBOC__) || defined(__BORLANDC__) -# if (__STDC__ == 1) && (defined(__LARGE__) || defined(__COMPACT__)) - /* Allow compilation with ANSI keywords only enabled */ - void _Cdecl farfree( void *block ); - void *_Cdecl farmalloc( unsigned long nbytes ); -# else -# include -# endif -# else /* MSC or DJGPP */ -# include -# endif -# endif -#endif - -#ifdef AMIGA -# define OS_CODE 0x01 -#endif - -#if defined(VAXC) || defined(VMS) -# define OS_CODE 0x02 -# define F_OPEN(name, mode) \ - fopen((name), (mode), "mbc=60", "ctx=stm", "rfm=fix", "mrs=512") -#endif - -#if defined(ATARI) || defined(atarist) -# define OS_CODE 0x05 -#endif - -#ifdef OS2 -# define OS_CODE 0x06 -# if defined(M_I86) && !defined(Z_SOLO) -# include -# endif -#endif - -#if defined(MACOS) || defined(TARGET_OS_MAC) -# define OS_CODE 0x07 -# ifndef Z_SOLO -# if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os -# include /* for fdopen */ -# else -# ifndef fdopen -# define fdopen(fd,mode) NULL /* No fdopen() */ -# endif -# endif -# endif -#endif - -#ifdef TOPS20 -# define OS_CODE 0x0a -#endif - -#ifdef WIN32 -# ifndef __CYGWIN__ /* Cygwin is Unix, not Win32 */ -# define OS_CODE 0x0b -# endif -#endif - -#ifdef __50SERIES /* Prime/PRIMOS */ -# define OS_CODE 0x0f -#endif - -#if defined(_BEOS_) || defined(RISCOS) -# define fdopen(fd,mode) NULL /* No fdopen() */ -#endif - -#if (defined(_MSC_VER) && (_MSC_VER > 600)) && !defined __INTERIX -# if defined(_WIN32_WCE) -# define fdopen(fd,mode) NULL /* No fdopen() */ -# ifndef _PTRDIFF_T_DEFINED - typedef int ptrdiff_t; -# define _PTRDIFF_T_DEFINED -# endif -# else -# define fdopen(fd,type) _fdopen(fd,type) -# endif -#endif - -#if defined(__BORLANDC__) && !defined(MSDOS) - #pragma warn -8004 - #pragma warn -8008 - #pragma warn -8066 -#endif - -/* provide prototypes for these when building zlib without LFS */ -#if !defined(_WIN32) && \ - (!defined(_LARGEFILE64_SOURCE) || _LFS64_LARGEFILE-0 == 0) - ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off_t)); - ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off_t)); -#endif - - /* common defaults */ - -#ifndef OS_CODE -# define OS_CODE 0x03 /* assume Unix */ -#endif - -#ifndef F_OPEN -# define F_OPEN(name, mode) fopen((name), (mode)) -#endif - - /* functions */ - -#if defined(pyr) || defined(Z_SOLO) -# define NO_MEMCPY -#endif -#if defined(SMALL_MEDIUM) && !defined(_MSC_VER) && !defined(__SC__) - /* Use our own functions for small and medium model with MSC <= 5.0. - * You may have to use the same strategy for Borland C (untested). - * The __SC__ check is for Symantec. - */ -# define NO_MEMCPY -#endif -#if defined(STDC) && !defined(HAVE_MEMCPY) && !defined(NO_MEMCPY) -# define HAVE_MEMCPY -#endif -#ifdef HAVE_MEMCPY -# ifdef SMALL_MEDIUM /* MSDOS small or medium model */ -# define zmemcpy _fmemcpy -# define zmemcmp _fmemcmp -# define zmemzero(dest, len) _fmemset(dest, 0, len) -# else -# define zmemcpy memcpy -# define zmemcmp memcmp -# define zmemzero(dest, len) memset(dest, 0, len) -# endif -#else - void ZLIB_INTERNAL zmemcpy OF((Bytef* dest, const Bytef* source, uInt len)); - int ZLIB_INTERNAL zmemcmp OF((const Bytef* s1, const Bytef* s2, uInt len)); - void ZLIB_INTERNAL zmemzero OF((Bytef* dest, uInt len)); -#endif - -/* Diagnostic functions */ -#ifdef DEBUG -# include - extern int ZLIB_INTERNAL z_verbose; - extern void ZLIB_INTERNAL z_error OF((char *m)); -# define Assert(cond,msg) {if(!(cond)) z_error(msg);} -# define Trace(x) {if (z_verbose>=0) fprintf x ;} -# define Tracev(x) {if (z_verbose>0) fprintf x ;} -# define Tracevv(x) {if (z_verbose>1) fprintf x ;} -# define Tracec(c,x) {if (z_verbose>0 && (c)) fprintf x ;} -# define Tracecv(c,x) {if (z_verbose>1 && (c)) fprintf x ;} -#else -# define Assert(cond,msg) -# define Trace(x) -# define Tracev(x) -# define Tracevv(x) -# define Tracec(c,x) -# define Tracecv(c,x) -#endif - -#ifndef Z_SOLO - voidpf ZLIB_INTERNAL zcalloc OF((voidpf opaque, unsigned items, - unsigned size)); - void ZLIB_INTERNAL zcfree OF((voidpf opaque, voidpf ptr)); -#endif - -#define ZALLOC(strm, items, size) \ - (*((strm)->zalloc))((strm)->opaque, (items), (size)) -#define ZFREE(strm, addr) (*((strm)->zfree))((strm)->opaque, (voidpf)(addr)) -#define TRY_FREE(s, p) {if (p) ZFREE(s, p);} - -/* Reverse the bytes in a 32-bit value */ -#define ZSWAP32(q) ((((q) >> 24) & 0xff) + (((q) >> 8) & 0xff00) + \ - (((q) & 0xff00) << 8) + (((q) & 0xff) << 24)) - -#endif /* ZUTIL_H */ diff --git a/examples/general.c b/examples/general.c index 7c05d8712..ff984a36c 100644 --- a/examples/general.c +++ b/examples/general.c @@ -57,7 +57,7 @@ static void blob_parsing(git_repository *repo); static void revwalking(git_repository *repo); static void index_walking(git_repository *repo); static void reference_listing(git_repository *repo); -static void config_files(const char *repo_path); +static void config_files(const char *repo_path, git_repository *repo); /** * Almost all libgit2 functions return 0 on success or negative on error. @@ -115,7 +115,7 @@ int main (int argc, char** argv) revwalking(repo); index_walking(repo); reference_listing(repo); - config_files(repo_path); + config_files(repo_path, repo); /** * Finally, when you're done with the repository, you can free it as well. @@ -247,6 +247,11 @@ static void object_database(git_repository *repo, git_oid *oid) */ git_oid_fmt(oid_hex, oid); printf("Written Object: %s\n", oid_hex); + + /** + * Free the object database after usage. + */ + git_odb_free(odb); } /** @@ -264,7 +269,7 @@ static void commit_writing(git_repository *repo) git_oid tree_id, parent_id, commit_id; git_tree *tree; git_commit *parent; - const git_signature *author, *cmtter; + git_signature *author, *committer; char oid_hex[GIT_OID_HEXSZ+1] = { 0 }; printf("\n*Commit Writing*\n"); @@ -276,9 +281,9 @@ static void commit_writing(git_repository *repo) * `user.email` configuration options. See the `config` section of this * example file to see how to access config values. */ - git_signature_new((git_signature **)&author, + git_signature_new(&author, "Scott Chacon", "schacon@gmail.com", 123456789, 60); - git_signature_new((git_signature **)&cmtter, + git_signature_new(&committer, "Scott A Chacon", "scott@github.com", 987654321, 90); /** @@ -301,7 +306,7 @@ static void commit_writing(git_repository *repo) repo, NULL, /* do not update the HEAD */ author, - cmtter, + committer, NULL, /* use default message encoding */ "example commit", tree, @@ -312,6 +317,14 @@ static void commit_writing(git_repository *repo) */ git_oid_fmt(oid_hex, &commit_id); printf("New Commit: %s\n", oid_hex); + + /** + * Free all objects used in the meanwhile. + */ + git_tree_free(tree); + git_commit_free(parent); + git_signature_free(author); + git_signature_free(committer); } /** @@ -431,7 +444,11 @@ static void tag_parsing(git_repository *repo) printf("Tag Name: %s\nTag Type: %s\nTag Message: %s\n", name, git_object_type2string(type), message); + /** + * Free both the commit and tag after usage. + */ git_commit_free(commit); + git_tag_free(tag); } /** @@ -485,9 +502,10 @@ static void tree_parsing(git_repository *repo) git_tree_entry_to_object(&obj, repo, entry); /* blob */ /** - * Remember to close the looked-up object once you are done using it + * Remember to close the looked-up object and tree once you are done using it */ git_object_free(obj); + git_tree_free(tree); } /** @@ -522,6 +540,11 @@ static void blob_parsing(git_repository *repo) * */ printf("Blob Size: %ld\n", (long)git_blob_rawsize(blob)); /* 8 */ git_blob_rawcontent(blob); /* "content" */ + + /** + * Free the blob after usage. + */ + git_blob_free(blob); } /** @@ -644,10 +667,7 @@ static void index_walking(git_repository *repo) static void reference_listing(git_repository *repo) { git_strarray ref_list; - const char *refname; - git_reference *ref; unsigned i; - char oid_hex[GIT_OID_HEXSZ+1]; printf("\n*Reference Listing*\n"); @@ -662,7 +682,10 @@ static void reference_listing(git_repository *repo) git_reference_list(&ref_list, repo); for (i = 0; i < ref_list.count; ++i) { - memset(oid_hex, 0, sizeof(oid_hex)); + git_reference *ref; + char oid_hex[GIT_OID_HEXSZ+1] = GIT_OID_HEX_ZERO; + const char *refname; + refname = ref_list.strings[i]; git_reference_lookup(&ref, repo, refname); @@ -679,6 +702,8 @@ static void reference_listing(git_repository *repo) fprintf(stderr, "Unexpected reference type\n"); exit(1); } + + git_reference_free(ref); } git_strarray_free(&ref_list); @@ -692,12 +717,13 @@ static void reference_listing(git_repository *repo) * * [config]: http://libgit2.github.com/libgit2/#HEAD/group/config */ -static void config_files(const char *repo_path) +static void config_files(const char *repo_path, git_repository* repo) { const char *email; char config_path[256]; - int32_t j; + int32_t autocorrect; git_config *cfg; + git_config *snap_cfg; printf("\n*Config Listing*\n"); @@ -707,9 +733,16 @@ static void config_files(const char *repo_path) sprintf(config_path, "%s/config", repo_path); check_error(git_config_open_ondisk(&cfg, config_path), "opening config"); - git_config_get_int32(&j, cfg, "help.autocorrect"); - printf("Autocorrect: %d\n", j); + if (git_config_get_int32(&autocorrect, cfg, "help.autocorrect") == 0) + printf("Autocorrect: %d\n", autocorrect); - git_config_get_string(&email, cfg, "user.email"); + check_error(git_repository_config_snapshot(&snap_cfg, repo), "config snapshot"); + git_config_get_string(&email, snap_cfg, "user.email"); printf("Email: %s\n", email); + + /** + * Remember to free the configurations after usage. + */ + git_config_free(cfg); + git_config_free(snap_cfg); } diff --git a/examples/network/clone.c b/examples/network/clone.c index caf41cca8..540000bfd 100644 --- a/examples/network/clone.c +++ b/examples/network/clone.c @@ -50,7 +50,7 @@ static int sideband_progress(const char *str, int len, void *payload) { (void)payload; // unused - printf("remote: %*s", len, str); + printf("remote: %.*s", len, str); fflush(stdout); return 0; } diff --git a/examples/network/common.c b/examples/network/common.c index d123eedbd..1a81a10f8 100644 --- a/examples/network/common.c +++ b/examples/network/common.c @@ -1,5 +1,7 @@ #include "common.h" #include +#include +#include /* Shamelessly borrowed from http://stackoverflow.com/questions/3417837/ * with permission of the original author, Martin Pool. @@ -20,15 +22,27 @@ int cred_acquire_cb(git_cred **out, unsigned int UNUSED(allowed_types), void * UNUSED(payload)) { - char username[128] = {0}; - char password[128] = {0}; + char *username = NULL, *password = NULL; + int error; printf("Username: "); - scanf("%s", username); + if (getline(&username, NULL, stdin) < 0) { + fprintf(stderr, "Unable to read username: %s", strerror(errno)); + return -1; + } /* Yup. Right there on your terminal. Careful where you copy/paste output. */ printf("Password: "); - scanf("%s", password); + if (getline(&password, NULL, stdin) < 0) { + fprintf(stderr, "Unable to read password: %s", strerror(errno)); + free(username); + return -1; + } - return git_cred_userpass_plaintext_new(out, username, password); + error = git_cred_userpass_plaintext_new(out, username, password); + + free(username); + free(password); + + return error; } diff --git a/include/git2/branch.h b/include/git2/branch.h index 34354f4e5..88fe723a0 100644 --- a/include/git2/branch.h +++ b/include/git2/branch.h @@ -245,6 +245,18 @@ GIT_EXTERN(int) git_branch_upstream_name( GIT_EXTERN(int) git_branch_is_head( const git_reference *branch); +/** + * Determine if the current branch is checked out in any linked + * repository. + * + * @param branch Reference to the branch. + * + * @return 1 if branch is checked out, 0 if it isn't, + * error code otherwise. + */ +GIT_EXTERN(int) git_branch_is_checked_out( + const git_reference *branch); + /** * Return the name of remote that the remote tracking branch belongs to. * diff --git a/include/git2/commit.h b/include/git2/commit.h index 4cc637466..692b3bdd9 100644 --- a/include/git2/commit.h +++ b/include/git2/commit.h @@ -255,7 +255,8 @@ GIT_EXTERN(int) git_commit_nth_gen_ancestor( /** * Get an arbitrary header field * - * @param out the buffer to fill + * @param out the buffer to fill; existing content will be + * overwritten * @param commit the commit to look in * @param field the header field to return * @return 0 on succeess, GIT_ENOTFOUND if the field does not exist, @@ -270,8 +271,10 @@ GIT_EXTERN(int) git_commit_header_field(git_buf *out, const git_commit *commit, * `GITERR_INVALID`. If the commit does not have a signature, the * error class will be `GITERR_OBJECT`. * - * @param signature the signature block - * @param signed_data signed data; this is the commit contents minus the signature block + * @param signature the signature block; existing content will be + * overwritten + * @param signed_data signed data; this is the commit contents minus the signature block; + * existing content will be overwritten * @param repo the repository in which the commit exists * @param commit_id the commit from which to extract the data * @param field the name of the header field containing the signature diff --git a/include/git2/common.h b/include/git2/common.h index 99c99812b..f65cfdd01 100644 --- a/include/git2/common.h +++ b/include/git2/common.h @@ -175,8 +175,14 @@ typedef enum { GIT_OPT_SET_SSL_CERT_LOCATIONS, GIT_OPT_SET_USER_AGENT, GIT_OPT_ENABLE_STRICT_OBJECT_CREATION, + GIT_OPT_ENABLE_STRICT_SYMBOLIC_REF_CREATION, GIT_OPT_SET_SSL_CIPHERS, GIT_OPT_GET_USER_AGENT, + GIT_OPT_ENABLE_OFS_DELTA, + GIT_OPT_ENABLE_FSYNC_GITDIR, + GIT_OPT_GET_WINDOWS_SHAREMODE, + GIT_OPT_SET_WINDOWS_SHAREMODE, + GIT_OPT_ENABLE_STRICT_HASH_VERIFICATION, } git_libgit2_opt_t; /** @@ -281,6 +287,17 @@ typedef enum { * > - `user_agent` is the value that will be delivered as the * > User-Agent header on HTTP requests. * + * * opts(GIT_OPT_SET_WINDOWS_SHAREMODE, unsigned long value) + * + * > Set the share mode used when opening files on Windows. + * > For more information, see the documentation for CreateFile. + * > The default is: FILE_SHARE_READ | FILE_SHARE_WRITE. This is + * > ignored and unused on non-Windows platforms. + * + * * opts(GIT_OPT_GET_WINDOWS_SHAREMODE, unsigned long *value) + * + * > Get the share mode used when opening files on Windows. + * * * opts(GIT_OPT_ENABLE_STRICT_OBJECT_CREATION, int enabled) * * > Enable strict input validation when creating new objects @@ -289,12 +306,45 @@ typedef enum { * > will be validated when creating a new commit. This defaults * > to enabled. * + * * opts(GIT_OPT_ENABLE_STRICT_SYMBOLIC_REF_CREATION, int enabled) + * + * > Validate the target of a symbolic ref when creating it. For + * > example, `foobar` is not a valid ref, therefore `foobar` is + * > not a valid target for a symbolic ref by default, whereas + * > `refs/heads/foobar` is. Disabling this bypasses validation + * > so that an arbitrary strings such as `foobar` can be used + * > for a symbolic ref target. This defaults to enabled. + * * * opts(GIT_OPT_SET_SSL_CIPHERS, const char *ciphers) * * > Set the SSL ciphers use for HTTPS connections. * > * > - `ciphers` is the list of ciphers that are eanbled. * + * * opts(GIT_OPT_ENABLE_OFS_DELTA, int enabled) + * + * > Enable or disable the use of "offset deltas" when creating packfiles, + * > and the negotiation of them when talking to a remote server. + * > Offset deltas store a delta base location as an offset into the + * > packfile from the current location, which provides a shorter encoding + * > and thus smaller resultant packfiles. + * > Packfiles containing offset deltas can still be read. + * > This defaults to enabled. + * + * * opts(GIT_OPT_ENABLE_FSYNC_GITDIR, int enabled) + * + * > Enable synchronized writes of files in the gitdir using `fsync` + * > (or the platform equivalent) to ensure that new object data + * > is written to permanent storage, not simply cached. This + * > defaults to disabled. + * + * opts(GIT_OPT_ENABLE_STRICT_HASH_VERIFICATION, int enabled) + * + * > Enable strict verification of object hashsums when reading + * > objects from disk. This may impact performance due to an + * > additional checksum calculation on each object. This defaults + * > to enabled. + * * @param option Option key * @param ... value to set the option * @return 0 on success, <0 on failure diff --git a/include/git2/errors.h b/include/git2/errors.h index e959ffd8a..6f5580253 100644 --- a/include/git2/errors.h +++ b/include/git2/errors.h @@ -53,6 +53,8 @@ typedef enum { GIT_PASSTHROUGH = -30, /**< Internal only */ GIT_ITEROVER = -31, /**< Signals end of iteration with iterator */ + GIT_RETRY = -32, /**< Internal only */ + GIT_EMISMATCH = -33, /**< Hashsum mismatch in object */ } git_error_code; /** @@ -100,6 +102,8 @@ typedef enum { GITERR_REBASE, GITERR_FILESYSTEM, GITERR_PATCH, + GITERR_WORKTREE, + GITERR_SHA1 } git_error_t; /** diff --git a/include/git2/global.h b/include/git2/global.h index ce5bdf444..2a87e10c6 100644 --- a/include/git2/global.h +++ b/include/git2/global.h @@ -14,7 +14,7 @@ GIT_BEGIN_DECL /** * Init the global state * - * This function must the called before any other libgit2 function in + * This function must be called before any other libgit2 function in * order to set up global state and threading. * * This function may be called multiple times - it will return the number diff --git a/include/git2/index.h b/include/git2/index.h index e58b3287e..35af2e5bf 100644 --- a/include/git2/index.h +++ b/include/git2/index.h @@ -575,15 +575,16 @@ GIT_EXTERN(int) git_index_remove_bypath(git_index *index, const char *path); * This method will fail in bare index instances. * * The `pathspec` is a list of file names or shell glob patterns that will - * matched against files in the repository's working directory. Each file - * that matches will be added to the index (either updating an existing - * entry or adding a new entry). You can disable glob expansion and force - * exact matching with the `GIT_INDEX_ADD_DISABLE_PATHSPEC_MATCH` flag. + * be matched against files in the repository's working directory. Each + * file that matches will be added to the index (either updating an + * existing entry or adding a new entry). You can disable glob expansion + * and force exact matching with the `GIT_INDEX_ADD_DISABLE_PATHSPEC_MATCH` + * flag. * * Files that are ignored will be skipped (unlike `git_index_add_bypath`). * If a file is already tracked in the index, then it *will* be updated - * even if it is ignored. Pass the `GIT_INDEX_ADD_FORCE` flag to - * skip the checking of ignore rules. + * even if it is ignored. Pass the `GIT_INDEX_ADD_FORCE` flag to skip + * the checking of ignore rules. * * To emulate `git add -A` and generate an error if the pathspec contains * the exact path of an ignored file (when not using FORCE), add the diff --git a/include/git2/merge.h b/include/git2/merge.h index c6f6cba6c..94ac8b5c5 100644 --- a/include/git2/merge.h +++ b/include/git2/merge.h @@ -290,7 +290,8 @@ typedef struct { } git_merge_options; #define GIT_MERGE_OPTIONS_VERSION 1 -#define GIT_MERGE_OPTIONS_INIT {GIT_MERGE_OPTIONS_VERSION} +#define GIT_MERGE_OPTIONS_INIT { \ + GIT_MERGE_OPTIONS_VERSION, GIT_MERGE_FIND_RENAMES } /** * Initializes a `git_merge_options` with default values. Equivalent to diff --git a/include/git2/odb.h b/include/git2/odb.h index b3ed2706c..b7dc0c5f3 100644 --- a/include/git2/odb.h +++ b/include/git2/odb.h @@ -488,7 +488,7 @@ GIT_EXTERN(git_otype) git_odb_object_type(git_odb_object *object); * The backends are checked in relative ordering, based on the * value of the `priority` parameter. * - * Read for more information. + * Read for more information. * * @param odb database to add the backend to * @param backend pointer to a git_odb_backend instance @@ -509,7 +509,7 @@ GIT_EXTERN(int) git_odb_add_backend(git_odb *odb, git_odb_backend *backend, int * * Writing is disabled on alternate backends. * - * Read for more information. + * Read for more information. * * @param odb database to add the backend to * @param backend pointer to a git_odb_backend instance diff --git a/include/git2/odb_backend.h b/include/git2/odb_backend.h index b17cfd8ba..9199538ce 100644 --- a/include/git2/odb_backend.h +++ b/include/git2/odb_backend.h @@ -39,7 +39,7 @@ GIT_EXTERN(int) git_odb_backend_pack(git_odb_backend **out, const char *objects_ * @param out location to store the odb backend pointer * @param objects_dir the Git repository's objects directory * @param compression_level zlib compression level to use - * @param do_fsync whether to do an fsync() after writing (currently ignored) + * @param do_fsync whether to do an fsync() after writing * @param dir_mode permissions to use creating a directory or 0 for defaults * @param file_mode permissions to use creating a file or 0 for defaults * diff --git a/include/git2/oid.h b/include/git2/oid.h index 8ad51c8ba..aaa678cc0 100644 --- a/include/git2/oid.h +++ b/include/git2/oid.h @@ -50,17 +50,16 @@ GIT_EXTERN(int) git_oid_fromstr(git_oid *out, const char *str); * Parse a hex formatted null-terminated string into a git_oid. * * @param out oid structure the result is written into. - * @param str input hex string; must be at least 4 characters - * long and null-terminated. + * @param str input hex string; must be null-terminated. * @return 0 or an error code */ GIT_EXTERN(int) git_oid_fromstrp(git_oid *out, const char *str); /** - * Parse N characters of a hex formatted object id into a git_oid + * Parse N characters of a hex formatted object id into a git_oid. * - * If N is odd, N-1 characters will be parsed instead. - * The remaining space in the git_oid will be set to zero. + * If N is odd, the last byte's high nibble will be read in and the + * low nibble set to zero. * * @param out oid structure the result is written into. * @param str input hex string of at least size `length` diff --git a/include/git2/remote.h b/include/git2/remote.h index 691114172..e9e4e5b65 100644 --- a/include/git2/remote.h +++ b/include/git2/remote.h @@ -715,8 +715,8 @@ GIT_EXTERN(int) git_remote_prune(git_remote *remote, const git_remote_callbacks * Peform all the steps from a push. * * @param remote the remote to push to - * @param refspecs the refspecs to use for pushing. If none are - * passed, the configured refspecs will be used + * @param refspecs the refspecs to use for pushing. If NULL or an empty + * array, the configured refspecs will be used * @param opts options to use for this push */ GIT_EXTERN(int) git_remote_push(git_remote *remote, @@ -796,7 +796,7 @@ GIT_EXTERN(int) git_remote_is_valid_name(const char *remote_name); * for the remote will be removed. * * @param repo the repository in which to act -* @param name the name of the remove to delete +* @param name the name of the remote to delete * @return 0 on success, or an error code. */ GIT_EXTERN(int) git_remote_delete(git_repository *repo, const char *name); diff --git a/include/git2/repository.h b/include/git2/repository.h index 3d70d1b89..8aac0b3f7 100644 --- a/include/git2/repository.h +++ b/include/git2/repository.h @@ -35,6 +35,17 @@ GIT_BEGIN_DECL * @return 0 or an error code */ GIT_EXTERN(int) git_repository_open(git_repository **out, const char *path); +/** + * Open working tree as a repository + * + * Open the working directory of the working tree as a normal + * repository that can then be worked on. + * + * @param out Output pointer containing opened repository + * @param wt Working tree to open + * @return 0 or an error code + */ +GIT_EXTERN(int) git_repository_open_from_worktree(git_repository **out, git_worktree *wt); /** * Create a "fake" repository to wrap an object database @@ -334,6 +345,17 @@ GIT_EXTERN(int) git_repository_init_ext( */ GIT_EXTERN(int) git_repository_head(git_reference **out, git_repository *repo); +/** + * Retrieve the referenced HEAD for the worktree + * + * @param out pointer to the reference which will be retrieved + * @param repo a repository object + * @param name name of the worktree to retrieve HEAD for + * @return 0 when successful, error-code otherwise + */ +GIT_EXTERN(int) git_repository_head_for_worktree(git_reference **out, git_repository *repo, + const char *name); + /** * Check if a repository's HEAD is detached * @@ -346,6 +368,20 @@ GIT_EXTERN(int) git_repository_head(git_reference **out, git_repository *repo); */ GIT_EXTERN(int) git_repository_head_detached(git_repository *repo); +/* + * Check if a worktree's HEAD is detached + * + * A worktree's HEAD is detached when it points directly to a + * commit instead of a branch. + * + * @param repo a repository object + * @param name name of the worktree to retrieve HEAD for + * @return 1 if HEAD is detached, 0 if its not; error code if + * there was an error + */ +GIT_EXTERN(int) git_repository_head_detached_for_worktree(git_repository *repo, + const char *name); + /** * Check if the current branch is unborn * @@ -370,6 +406,42 @@ GIT_EXTERN(int) git_repository_head_unborn(git_repository *repo); */ GIT_EXTERN(int) git_repository_is_empty(git_repository *repo); +/** + * List of items which belong to the git repository layout + */ +typedef enum { + GIT_REPOSITORY_ITEM_GITDIR, + GIT_REPOSITORY_ITEM_WORKDIR, + GIT_REPOSITORY_ITEM_COMMONDIR, + GIT_REPOSITORY_ITEM_INDEX, + GIT_REPOSITORY_ITEM_OBJECTS, + GIT_REPOSITORY_ITEM_REFS, + GIT_REPOSITORY_ITEM_PACKED_REFS, + GIT_REPOSITORY_ITEM_REMOTES, + GIT_REPOSITORY_ITEM_CONFIG, + GIT_REPOSITORY_ITEM_INFO, + GIT_REPOSITORY_ITEM_HOOKS, + GIT_REPOSITORY_ITEM_LOGS, + GIT_REPOSITORY_ITEM_MODULES, + GIT_REPOSITORY_ITEM_WORKTREES +} git_repository_item_t; + +/** + * Get the location of a specific repository file or directory + * + * This function will retrieve the path of a specific repository + * item. It will thereby honor things like the repository's + * common directory, gitdir, etc. In case a file path cannot + * exist for a given item (e.g. the working directory of a bare + * repository), GIT_ENOTFOUND is returned. + * + * @param out Buffer to store the path at + * @param repo Repository to get path for + * @param item The repository item for which to retrieve the path + * @return 0, GIT_ENOTFOUND if the path cannot exist or an error code + */ +GIT_EXTERN(int) git_repository_item_path(git_buf *out, git_repository *repo, git_repository_item_t item); + /** * Get the path of this repository * @@ -392,6 +464,17 @@ GIT_EXTERN(const char *) git_repository_path(git_repository *repo); */ GIT_EXTERN(const char *) git_repository_workdir(git_repository *repo); +/** + * Get the path of the shared common directory for this repository + * + * If the repository is bare is not a worktree, the git directory + * path is returned. + * + * @param repo A repository object + * @return the path to the common dir + */ +GIT_EXTERN(const char *) git_repository_commondir(git_repository *repo); + /** * Set the path to the working directory for this repository * @@ -420,6 +503,14 @@ GIT_EXTERN(int) git_repository_set_workdir( */ GIT_EXTERN(int) git_repository_is_bare(git_repository *repo); +/** + * Check if a repository is a linked work tree + * + * @param repo Repo to test + * @return 1 if the repository is a linked work tree, 0 otherwise. + */ +GIT_EXTERN(int) git_repository_is_worktree(git_repository *repo); + /** * Get the configuration file for this repository. * diff --git a/include/git2/reset.h b/include/git2/reset.h index 79075291f..bd29c69e4 100644 --- a/include/git2/reset.h +++ b/include/git2/reset.h @@ -53,7 +53,7 @@ typedef enum { * * @param reset_type Kind of reset operation to perform. * - * @param checkout_opts Checkout options to be used for a HARD reset. + * @param checkout_opts Optional checkout options to be used for a HARD reset. * The checkout_strategy field will be overridden (based on reset_type). * This parameter can be used to propagate notify and progress callbacks. * diff --git a/include/git2/revert.h b/include/git2/revert.h index 2de194219..82dbadcfc 100644 --- a/include/git2/revert.h +++ b/include/git2/revert.h @@ -75,7 +75,7 @@ GIT_EXTERN(int) git_revert_commit( * * @param repo the repository to revert * @param commit the commit to revert - * @param given_opts merge flags + * @param given_opts the revert options (or null for defaults) * @return zero on success, -1 on failure. */ GIT_EXTERN(int) git_revert( diff --git a/include/git2/stash.h b/include/git2/stash.h index 733d75a7f..3af9cde38 100644 --- a/include/git2/stash.h +++ b/include/git2/stash.h @@ -173,7 +173,7 @@ GIT_EXTERN(int) git_stash_apply_init_options( * @param repo The owning repository. * @param index The position within the stash list. 0 points to the * most recent stashed state. - * @param options Options to control how stashes are applied. + * @param options Optional options to control how stashes are applied. * * @return 0 on success, GIT_ENOTFOUND if there's no stashed state for the * given index, GIT_EMERGECONFLICT if changes exist in the working @@ -242,7 +242,7 @@ GIT_EXTERN(int) git_stash_drop( * @param repo The owning repository. * @param index The position within the stash list. 0 points to the * most recent stashed state. - * @param options Options to control how stashes are applied. + * @param options Optional options to control how stashes are applied. * * @return 0 on success, GIT_ENOTFOUND if there's no stashed state for the given * index, or error code. (see git_stash_apply() above for details) diff --git a/include/git2/submodule.h b/include/git2/submodule.h index 540ecf5c7..b2b3039fe 100644 --- a/include/git2/submodule.h +++ b/include/git2/submodule.h @@ -134,9 +134,7 @@ typedef struct git_submodule_update_options { * checkout, set the `checkout_strategy` to * `GIT_CHECKOUT_NONE`. Generally you will want the use * GIT_CHECKOUT_SAFE to update files in the working - * directory. Use the `clone_checkout_strategy` field - * to set the checkout strategy that will be used in - * the case where update needs to clone the repository. + * directory. */ git_checkout_options checkout_opts; @@ -148,13 +146,6 @@ typedef struct git_submodule_update_options { */ git_fetch_options fetch_opts; - /** - * The checkout strategy to use when the sub repository needs to - * be cloned. Use GIT_CHECKOUT_SAFE to create all files - * in the working directory for the newly cloned repository. - */ - unsigned int clone_checkout_strategy; - /** * Allow fetching from the submodule's default remote if the target * commit isn't found. Enabled by default. @@ -166,7 +157,7 @@ typedef struct git_submodule_update_options { #define GIT_SUBMODULE_UPDATE_OPTIONS_INIT \ { GIT_SUBMODULE_UPDATE_OPTIONS_VERSION, \ { GIT_CHECKOUT_OPTIONS_VERSION, GIT_CHECKOUT_SAFE }, \ - GIT_FETCH_OPTIONS_INIT, GIT_CHECKOUT_SAFE, 1 } + GIT_FETCH_OPTIONS_INIT, 1 } /** * Initializes a `git_submodule_update_options` with default values. diff --git a/include/git2/sys/filter.h b/include/git2/sys/filter.h index d0e5d4d6f..6d575d4fd 100644 --- a/include/git2/sys/filter.h +++ b/include/git2/sys/filter.h @@ -271,6 +271,17 @@ struct git_filter { }; #define GIT_FILTER_VERSION 1 +#define GIT_FILTER_INIT {GIT_FILTER_VERSION} + +/** + * Initializes a `git_filter` with default values. Equivalent to + * creating an instance with GIT_FILTER_INIT. + * + * @param filter the `git_filter` struct to initialize. + * @param version Version the struct; pass `GIT_FILTER_VERSION` + * @return Zero on success; -1 on failure. + */ +GIT_EXTERN(int) git_filter_init(git_filter *filter, unsigned int version); /** * Register a filter under a given name with a given priority. diff --git a/include/git2/sys/merge.h b/include/git2/sys/merge.h index 031941042..eed106c07 100644 --- a/include/git2/sys/merge.h +++ b/include/git2/sys/merge.h @@ -36,23 +36,23 @@ GIT_EXTERN(git_merge_driver *) git_merge_driver_lookup(const char *name); typedef struct git_merge_driver_source git_merge_driver_source; /** Get the repository that the source data is coming from. */ -GIT_EXTERN(git_repository *) git_merge_driver_source_repo( +GIT_EXTERN(const git_repository *) git_merge_driver_source_repo( const git_merge_driver_source *src); /** Gets the ancestor of the file to merge. */ -GIT_EXTERN(git_index_entry *) git_merge_driver_source_ancestor( +GIT_EXTERN(const git_index_entry *) git_merge_driver_source_ancestor( const git_merge_driver_source *src); /** Gets the ours side of the file to merge. */ -GIT_EXTERN(git_index_entry *) git_merge_driver_source_ours( +GIT_EXTERN(const git_index_entry *) git_merge_driver_source_ours( const git_merge_driver_source *src); /** Gets the theirs side of the file to merge. */ -GIT_EXTERN(git_index_entry *) git_merge_driver_source_theirs( +GIT_EXTERN(const git_index_entry *) git_merge_driver_source_theirs( const git_merge_driver_source *src); /** Gets the merge file options that the merge was invoked with */ -GIT_EXTERN(git_merge_file_options *) git_merge_driver_source_file_options( +GIT_EXTERN(const git_merge_file_options *) git_merge_driver_source_file_options( const git_merge_driver_source *src); diff --git a/include/git2/sys/repository.h b/include/git2/sys/repository.h index 800396c86..0c9142143 100644 --- a/include/git2/sys/repository.h +++ b/include/git2/sys/repository.h @@ -135,6 +135,35 @@ GIT_EXTERN(void) git_repository_set_index(git_repository *repo, git_index *index */ GIT_EXTERN(int) git_repository_set_bare(git_repository *repo); +/** + * Load and cache all submodules. + * + * Because the `.gitmodules` file is unstructured, loading submodules is an + * O(N) operation. Any operation (such as `git_rebase_init`) that requires + * accessing all submodules is O(N^2) in the number of submodules, if it + * has to look each one up individually. This function loads all submodules + * and caches them so that subsequent calls to `git_submodule_lookup` are O(1). + * + * @param repo the repository whose submodules will be cached. + */ +GIT_EXTERN(int) git_repository_submodule_cache_all( + git_repository *repo); + +/** + * Clear the submodule cache. + * + * Clear the submodule cache populated by `git_repository_submodule_cache_all`. + * If there is no cache, do nothing. + * + * The cache incorporates data from the repository's configuration, as well + * as the state of the working tree, the index, and HEAD. So any time any + * of these has changed, the cache might become invalid. + * + * @param repo the repository whose submodule cache will be cleared + */ +GIT_EXTERN(int) git_repository_submodule_cache_clear( + git_repository *repo); + /** @} */ GIT_END_DECL #endif diff --git a/include/git2/sys/transport.h b/include/git2/sys/transport.h index 60e38b21a..a395de5ed 100644 --- a/include/git2/sys/transport.h +++ b/include/git2/sys/transport.h @@ -241,6 +241,16 @@ GIT_EXTERN(int) git_transport_smart_certificate_check(git_transport *transport, */ GIT_EXTERN(int) git_transport_smart_credentials(git_cred **out, git_transport *transport, const char *user, int methods); +/** + * Get a copy of the proxy options + * + * The url is copied and must be freed by the caller. + * + * @param out options struct to fill + * @param transport the transport to extract the data from. + */ +GIT_EXTERN(int) git_transport_smart_proxy_options(git_proxy_options *out, git_transport *transport); + /* *** End of base transport interface *** *** Begin interface for subtransports for the smart transport *** diff --git a/include/git2/transport.h b/include/git2/transport.h index 0ec241699..0c371bf4b 100644 --- a/include/git2/transport.h +++ b/include/git2/transport.h @@ -321,13 +321,13 @@ GIT_EXTERN(void) git_cred_free(git_cred *cred); /** * Signature of a function which acquires a credential object. * - * - cred: The newly created credential object. - * - url: The resource for which we are demanding a credential. - * - username_from_url: The username that was embedded in a "user\@host" + * @param cred The newly created credential object. + * @param url The resource for which we are demanding a credential. + * @param username_from_url The username that was embedded in a "user\@host" * remote url, or NULL if not included. - * - allowed_types: A bitmask stating which cred types are OK to return. - * - payload: The payload provided when specifying this callback. - * - returns 0 for success, < 0 to indicate an error, > 0 to indicate + * @param allowed_types A bitmask stating which cred types are OK to return. + * @param payload The payload provided when specifying this callback. + * @return 0 for success, < 0 to indicate an error, > 0 to indicate * no credential was acquired */ typedef int (*git_cred_acquire_cb)( diff --git a/include/git2/tree.h b/include/git2/tree.h index 2e4735c4b..4740b1ffa 100644 --- a/include/git2/tree.h +++ b/include/git2/tree.h @@ -375,6 +375,19 @@ GIT_EXTERN(void) git_treebuilder_filter( GIT_EXTERN(int) git_treebuilder_write( git_oid *id, git_treebuilder *bld); +/** + * Write the contents of the tree builder as a tree object + * using a shared git_buf. + * + * @see git_treebuilder_write + * + * @param oid Pointer to store the OID of the newly written tree + * @param bld Tree builder to write + * @param tree Shared buffer for writing the tree. Will be grown as necessary. + * @return 0 or an error code + */ +GIT_EXTERN(int) git_treebuilder_write_with_buffer( + git_oid *oid, git_treebuilder *bld, git_buf *tree); /** Callback for the tree traversal method */ typedef int (*git_treewalk_cb)( diff --git a/include/git2/types.h b/include/git2/types.h index 6f41014b3..dfdaa2920 100644 --- a/include/git2/types.h +++ b/include/git2/types.h @@ -104,6 +104,9 @@ typedef struct git_refdb_backend git_refdb_backend; */ typedef struct git_repository git_repository; +/** Representation of a working tree */ +typedef struct git_worktree git_worktree; + /** Representation of a generic object in a repository */ typedef struct git_object git_object; diff --git a/include/git2/version.h b/include/git2/version.h index d190893fe..becf97bd5 100644 --- a/include/git2/version.h +++ b/include/git2/version.h @@ -7,12 +7,12 @@ #ifndef INCLUDE_git_version_h__ #define INCLUDE_git_version_h__ -#define LIBGIT2_VERSION "0.25.1" +#define LIBGIT2_VERSION "0.26.0" #define LIBGIT2_VER_MAJOR 0 -#define LIBGIT2_VER_MINOR 25 -#define LIBGIT2_VER_REVISION 1 +#define LIBGIT2_VER_MINOR 26 +#define LIBGIT2_VER_REVISION 0 #define LIBGIT2_VER_PATCH 0 -#define LIBGIT2_SOVERSION 25 +#define LIBGIT2_SOVERSION 26 #endif diff --git a/include/git2/worktree.h b/include/git2/worktree.h new file mode 100644 index 000000000..d3fa88e3f --- /dev/null +++ b/include/git2/worktree.h @@ -0,0 +1,220 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ +#ifndef INCLUDE_git_worktree_h__ +#define INCLUDE_git_worktree_h__ + +#include "common.h" +#include "buffer.h" +#include "types.h" +#include "strarray.h" + +/** + * @file git2/worktrees.h + * @brief Git worktree related functions + * @defgroup git_commit Git worktree related functions + * @ingroup Git + * @{ + */ +GIT_BEGIN_DECL + +/** + * List names of linked working trees + * + * The returned list should be released with `git_strarray_free` + * when no longer needed. + * + * @param out pointer to the array of working tree names + * @param repo the repo to use when listing working trees + * @return 0 or an error code + */ +GIT_EXTERN(int) git_worktree_list(git_strarray *out, git_repository *repo); + +/** + * Lookup a working tree by its name for a given repository + * + * @param out Output pointer to looked up worktree or `NULL` + * @param repo The repository containing worktrees + * @param name Name of the working tree to look up + * @return 0 or an error code + */ +GIT_EXTERN(int) git_worktree_lookup(git_worktree **out, git_repository *repo, const char *name); + +/** + * Open a worktree of a given repository + * + * If a repository is not the main tree but a worktree, this + * function will look up the worktree inside the parent + * repository and create a new `git_worktree` structure. + * + * @param out Out-pointer for the newly allocated worktree + * @param repo Repository to look up worktree for + */ +GIT_EXTERN(int) git_worktree_open_from_repository(git_worktree **out, git_repository *repo); + +/** + * Free a previously allocated worktree + * + * @param wt worktree handle to close. If NULL nothing occurs. + */ +GIT_EXTERN(void) git_worktree_free(git_worktree *wt); + +/** + * Check if worktree is valid + * + * A valid worktree requires both the git data structures inside + * the linked parent repository and the linked working copy to be + * present. + * + * @param wt Worktree to check + * @return 0 when worktree is valid, error-code otherwise + */ +GIT_EXTERN(int) git_worktree_validate(const git_worktree *wt); + +typedef struct git_worktree_add_options { + unsigned int version; + + int lock; /**< lock newly created worktree */ +} git_worktree_add_options; + +#define GIT_WORKTREE_ADD_OPTIONS_VERSION 1 +#define GIT_WORKTREE_ADD_OPTIONS_INIT {GIT_WORKTREE_ADD_OPTIONS_VERSION,0} + +/** + * Initializes a `git_worktree_add_options` with default vaules. + * Equivalent to creating an instance with + * GIT_WORKTREE_ADD_OPTIONS_INIT. + * + * @param opts the struct to initialize + * @param version Verison of struct; pass `GIT_WORKTREE_ADD_OPTIONS_VERSION` + * @return Zero on success; -1 on failure. + */ +int git_worktree_add_init_options(git_worktree_add_options *opts, + unsigned int version); + +/** + * Add a new working tree + * + * Add a new working tree for the repository, that is create the + * required data structures inside the repository and check out + * the current HEAD at `path` + * + * @param out Output pointer containing new working tree + * @param repo Repository to create working tree for + * @param name Name of the working tree + * @param path Path to create working tree at + * @param opts Options to modify default behavior. May be NULL + * @return 0 or an error code + */ +GIT_EXTERN(int) git_worktree_add(git_worktree **out, git_repository *repo, + const char *name, const char *path, + const git_worktree_add_options *opts); + +/** + * Lock worktree if not already locked + * + * Lock a worktree, optionally specifying a reason why the linked + * working tree is being locked. + * + * @param wt Worktree to lock + * @param reason Reason why the working tree is being locked + * @return 0 on success, non-zero otherwise + */ +GIT_EXTERN(int) git_worktree_lock(git_worktree *wt, char *reason); + +/** + * Unlock a locked worktree + * + * @param wt Worktree to unlock + * @return 0 on success, 1 if worktree was not locked, error-code + * otherwise + */ +GIT_EXTERN(int) git_worktree_unlock(git_worktree *wt); + +/** + * Check if worktree is locked + * + * A worktree may be locked if the linked working tree is stored + * on a portable device which is not available. + * + * @param reason Buffer to store reason in. If NULL no reason is stored. + * @param wt Worktree to check + * @return 0 when the working tree not locked, a value greater + * than zero if it is locked, less than zero if there was an + * error + */ +GIT_EXTERN(int) git_worktree_is_locked(git_buf *reason, const git_worktree *wt); + +/** + * Flags which can be passed to git_worktree_prune to alter its + * behavior. + */ +typedef enum { + /* Prune working tree even if working tree is valid */ + GIT_WORKTREE_PRUNE_VALID = 1u << 0, + /* Prune working tree even if it is locked */ + GIT_WORKTREE_PRUNE_LOCKED = 1u << 1, + /* Prune checked out working tree */ + GIT_WORKTREE_PRUNE_WORKING_TREE = 1u << 2, +} git_worktree_prune_t; + +typedef struct git_worktree_prune_options { + unsigned int version; + + uint32_t flags; +} git_worktree_prune_options; + +#define GIT_WORKTREE_PRUNE_OPTIONS_VERSION 1 +#define GIT_WORKTREE_PRUNE_OPTIONS_INIT {GIT_WORKTREE_PRUNE_OPTIONS_VERSION,0} + +/** + * Initializes a `git_worktree_prune_options` with default vaules. + * Equivalent to creating an instance with + * GIT_WORKTREE_PRUNE_OPTIONS_INIT. + * + * @param opts the struct to initialize + * @param version Verison of struct; pass `GIT_WORKTREE_PRUNE_OPTIONS_VERSION` + * @return Zero on success; -1 on failure. + */ +GIT_EXTERN(int) git_worktree_prune_init_options( + git_worktree_prune_options *opts, + unsigned int version); + +/** + * Is the worktree prunable with the given options? + * + * A worktree is not prunable in the following scenarios: + * + * - the worktree is linking to a valid on-disk worktree. The + * `valid` member will cause this check to be ignored. + * - the worktree is locked. The `locked` flag will cause this + * check to be ignored. + * + * If the worktree is not valid and not locked or if the above + * flags have been passed in, this function will return a + * positive value. + */ +GIT_EXTERN(int) git_worktree_is_prunable(git_worktree *wt, + git_worktree_prune_options *opts); + +/** + * Prune working tree + * + * Prune the working tree, that is remove the git data + * structures on disk. The repository will only be pruned of + * `git_worktree_is_prunable` succeeds. + * + * @param wt Worktree to prune + * @param opts Specifies which checks to override. See + * `git_worktree_is_prunable`. May be NULL + * @return 0 or an error code + */ +GIT_EXTERN(int) git_worktree_prune(git_worktree *wt, + git_worktree_prune_options *opts); + +/** @} */ +GIT_END_DECL +#endif diff --git a/libgit2.pc.in b/libgit2.pc.in index 329a560a7..96b965955 100644 --- a/libgit2.pc.in +++ b/libgit2.pc.in @@ -1,4 +1,4 @@ -prefix=@PKGCONFIG_PREFIX@ +prefix="@PKGCONFIG_PREFIX@" libdir=@PKGCONFIG_LIBDIR@ includedir=@PKGCONFIG_INCLUDEDIR@ @@ -6,7 +6,7 @@ Name: libgit2 Description: The git library, take 2 Version: @LIBGIT2_VERSION_STRING@ -Libs: -L"${libdir}" -lgit2 +Libs: -L${libdir} -lgit2 Libs.private: @LIBGIT2_PC_LIBS@ Requires.private: @LIBGIT2_PC_REQUIRES@ diff --git a/script/appveyor-mingw.sh b/script/appveyor-mingw.sh index 198801875..d171a72d5 100755 --- a/script/appveyor-mingw.sh +++ b/script/appveyor-mingw.sh @@ -7,15 +7,17 @@ if [ "$ARCH" = "i686" ]; then curl -LsSO http://sourceforge.net/projects/mingw-w64/files/Toolchains%20targetting%20Win32/Personal%20Builds/mingw-builds/4.9.2/threads-win32/sjlj/$f fi 7z x $f > /dev/null - mv mingw32 /MinGW + export PATH=`pwd`/mingw32/bin:$PATH else f=x86_64-4.9.2-release-win32-seh-rt_v3-rev1.7z if ! [ -e $f ]; then curl -LsSO http://sourceforge.net/projects/mingw-w64/files/Toolchains%20targetting%20Win64/Personal%20Builds/mingw-builds/4.9.2/threads-win32/seh/$f fi 7z x $f > /dev/null - mv mingw64 /MinGW + export PATH=`pwd`/mingw64/bin:$PATH fi cd build +gcc --version +cmake --version cmake -D ENABLE_TRACE=ON -D BUILD_CLAR=ON .. -G"$GENERATOR" cmake --build . --config RelWithDebInfo diff --git a/script/install-deps-osx.sh b/script/install-deps-osx.sh index 4b8393b19..94314dbaa 100755 --- a/script/install-deps-osx.sh +++ b/script/install-deps-osx.sh @@ -3,6 +3,7 @@ set -x brew update -brew install homebrew/dupes/zlib +brew install zlib brew install curl +brew install openssl brew install libssh2 diff --git a/src/apply.c b/src/apply.c index 635934299..595f5f300 100644 --- a/src/apply.c +++ b/src/apply.c @@ -173,7 +173,7 @@ static int apply_hunk( git_diff_line *line = git_array_get(patch->lines, linenum); if (!line) { - error = apply_err("Preimage does not contain line %"PRIuZ, linenum); + error = apply_err("preimage does not contain line %"PRIuZ, linenum); goto done; } @@ -193,7 +193,7 @@ static int apply_hunk( line_num = hunk->hunk.new_start ? hunk->hunk.new_start - 1 : 0; if (!find_hunk_linenum(&line_num, image, &preimage, line_num)) { - error = apply_err("Hunk at line %d did not apply", + error = apply_err("hunk at line %d did not apply", hunk->hunk.new_start); goto done; } diff --git a/src/attr.c b/src/attr.c index d43a15f50..999f41318 100644 --- a/src/attr.c +++ b/src/attr.c @@ -7,8 +7,6 @@ #include "git2/oid.h" #include -GIT__USE_STRMAP - const char *git_attr__true = "[internal]__TRUE__"; const char *git_attr__false = "[internal]__FALSE__"; const char *git_attr__unset = "[internal]__UNSET__"; @@ -209,7 +207,7 @@ int git_attr_foreach( if (git_strmap_exists(seen, assign->name)) continue; - git_strmap_insert(seen, assign->name, assign, error); + git_strmap_insert(seen, assign->name, assign, &error); if (error < 0) goto cleanup; @@ -292,7 +290,7 @@ static int attr_setup(git_repository *repo, git_attr_session *attr_session) int error = 0; const char *workdir = git_repository_workdir(repo); git_index *idx = NULL; - git_buf sys = GIT_BUF_INIT; + git_buf path = GIT_BUF_INIT; if (attr_session && attr_session->init_setup) return 0; @@ -304,40 +302,45 @@ static int attr_setup(git_repository *repo, git_attr_session *attr_session) * definitions will be available for later file parsing */ - error = system_attr_file(&sys, attr_session); + error = system_attr_file(&path, attr_session); if (error == 0) error = preload_attr_file( - repo, attr_session, GIT_ATTR_FILE__FROM_FILE, NULL, sys.ptr); + repo, attr_session, GIT_ATTR_FILE__FROM_FILE, NULL, path.ptr); if (error != GIT_ENOTFOUND) - return error; - - git_buf_free(&sys); + goto out; if ((error = preload_attr_file( repo, attr_session, GIT_ATTR_FILE__FROM_FILE, NULL, git_repository_attr_cache(repo)->cfg_attr_file)) < 0) - return error; + goto out; + + if ((error = git_repository_item_path(&path, + repo, GIT_REPOSITORY_ITEM_INFO)) < 0) + goto out; if ((error = preload_attr_file( repo, attr_session, GIT_ATTR_FILE__FROM_FILE, - git_repository_path(repo), GIT_ATTR_FILE_INREPO)) < 0) - return error; + path.ptr, GIT_ATTR_FILE_INREPO)) < 0) + goto out; if (workdir != NULL && (error = preload_attr_file( repo, attr_session, GIT_ATTR_FILE__FROM_FILE, workdir, GIT_ATTR_FILE)) < 0) - return error; + goto out; if ((error = git_repository_index__weakptr(&idx, repo)) < 0 || (error = preload_attr_file( repo, attr_session, GIT_ATTR_FILE__FROM_INDEX, NULL, GIT_ATTR_FILE)) < 0) - return error; + goto out; if (attr_session) attr_session->init_setup = 1; +out: + git_buf_free(&path); + return error; } @@ -472,7 +475,7 @@ static int collect_attr_files( git_vector *files) { int error = 0; - git_buf dir = GIT_BUF_INIT; + git_buf dir = GIT_BUF_INIT, attrfile = GIT_BUF_INIT; const char *workdir = git_repository_workdir(repo); attr_walk_up_info info = { NULL }; @@ -494,9 +497,13 @@ static int collect_attr_files( * - $GIT_PREFIX/etc/gitattributes */ + error = git_repository_item_path(&attrfile, repo, GIT_REPOSITORY_ITEM_INFO); + if (error < 0) + goto cleanup; + error = push_attr_file( repo, attr_session, files, GIT_ATTR_FILE__FROM_FILE, - git_repository_path(repo), GIT_ATTR_FILE_INREPO); + attrfile.ptr, GIT_ATTR_FILE_INREPO); if (error < 0) goto cleanup; @@ -538,6 +545,7 @@ static int collect_attr_files( cleanup: if (error < 0) release_attr_files(files); + git_buf_free(&attrfile); git_buf_free(&dir); return error; diff --git a/src/attr_file.c b/src/attr_file.c index 11d149358..e30ea5e0c 100644 --- a/src/attr_file.c +++ b/src/attr_file.c @@ -30,7 +30,7 @@ int git_attr_file__new( GITERR_CHECK_ALLOC(attrs); if (git_mutex_init(&attrs->lock) < 0) { - giterr_set(GITERR_OS, "Failed to initialize lock"); + giterr_set(GITERR_OS, "failed to initialize lock"); git__free(attrs); return -1; } @@ -49,7 +49,7 @@ int git_attr_file__clear_rules(git_attr_file *file, bool need_lock) git_attr_rule *rule; if (need_lock && git_mutex_lock(&file->lock) < 0) { - giterr_set(GITERR_OS, "Failed to lock attribute file"); + giterr_set(GITERR_OS, "failed to lock attribute file"); return -1; } @@ -140,7 +140,7 @@ int git_attr_file__load( break; } default: - giterr_set(GITERR_INVALID, "Unknown file source %d", source); + giterr_set(GITERR_INVALID, "unknown file source %d", source); return -1; } @@ -212,7 +212,7 @@ int git_attr_file__out_of_date( } default: - giterr_set(GITERR_INVALID, "Invalid file type %d", file->source); + giterr_set(GITERR_INVALID, "invalid file type %d", file->source); return -1; } } @@ -238,7 +238,7 @@ int git_attr_file__parse_buffer( context = attrs->entry->path; if (git_mutex_lock(&attrs->lock) < 0) { - giterr_set(GITERR_OS, "Failed to lock attribute file"); + giterr_set(GITERR_OS, "failed to lock attribute file"); return -1; } @@ -395,9 +395,13 @@ bool git_attr_fnmatch__match( if ((match->flags & GIT_ATTR_FNMATCH_DIRECTORY) && !path->is_dir) { bool samename; - /* for attribute checks or root ignore checks, fail match */ + /* + * for attribute checks or checks at the root of this match's + * containing_dir (or root of the repository if no containing_dir), + * do not match. + */ if (!(match->flags & GIT_ATTR_FNMATCH_IGNORE) || - path->basename == path->path) + path->basename == relpath) return false; flags |= FNM_LEADING_DIR; diff --git a/src/attr_file.h b/src/attr_file.h index 388ecf4c0..a9af2403a 100644 --- a/src/attr_file.h +++ b/src/attr_file.h @@ -15,7 +15,7 @@ #include "fileops.h" #define GIT_ATTR_FILE ".gitattributes" -#define GIT_ATTR_FILE_INREPO "info/attributes" +#define GIT_ATTR_FILE_INREPO "attributes" #define GIT_ATTR_FILE_SYSTEM "gitattributes" #define GIT_ATTR_FILE_XDG "attributes" diff --git a/src/attrcache.c b/src/attrcache.c index a57110684..54161894b 100644 --- a/src/attrcache.c +++ b/src/attrcache.c @@ -5,14 +5,12 @@ #include "sysdir.h" #include "ignore.h" -GIT__USE_STRMAP - GIT_INLINE(int) attr_cache_lock(git_attr_cache *cache) { GIT_UNUSED(cache); /* avoid warning if threading is off */ if (git_mutex_lock(&cache->lock) < 0) { - giterr_set(GITERR_OS, "Unable to get attr cache lock"); + giterr_set(GITERR_OS, "unable to get attr cache lock"); return -1; } return 0; @@ -82,7 +80,7 @@ static int attr_cache_make_entry( &entry, git_repository_workdir(repo), path, &cache->pool); if (!error) { - git_strmap_insert(cache->files, entry->path, entry, error); + git_strmap_insert(cache->files, entry->path, entry, &error); if (error > 0) error = 0; } @@ -105,8 +103,11 @@ static int attr_cache_upsert(git_attr_cache *cache, git_attr_file *file) GIT_REFCOUNT_OWN(file, entry); GIT_REFCOUNT_INC(file); - old = git__compare_and_swap( - &entry->file[file->source], entry->file[file->source], file); + /* + * Replace the existing value if another thread has + * created it in the meantime. + */ + old = git__swap(entry->file[file->source], file); if (old) { GIT_REFCOUNT_OWN(old, NULL); @@ -121,20 +122,22 @@ static int attr_cache_remove(git_attr_cache *cache, git_attr_file *file) { int error = 0; git_attr_file_entry *entry; + git_attr_file *old = NULL; if (!file) return 0; + if ((error = attr_cache_lock(cache)) < 0) return error; if ((entry = attr_cache_lookup_entry(cache, file->entry->path)) != NULL) - file = git__compare_and_swap(&entry->file[file->source], file, NULL); + old = git__compare_and_swap(&entry->file[file->source], file, NULL); attr_cache_unlock(cache); - if (file) { - GIT_REFCOUNT_OWN(file, NULL); - git_attr_file__free(file); + if (old) { + GIT_REFCOUNT_OWN(old, NULL); + git_attr_file__free(old); } return error; @@ -287,14 +290,16 @@ static int attr_cache__lookup_path( const char *cfgval = entry->value; /* expand leading ~/ as needed */ - if (cfgval && cfgval[0] == '~' && cfgval[1] == '/' && - !git_sysdir_find_global_file(&buf, &cfgval[2])) - *out = git_buf_detach(&buf); - else if (cfgval) + if (cfgval && cfgval[0] == '~' && cfgval[1] == '/') { + if (! (error = git_sysdir_expand_global_file(&buf, &cfgval[2]))) + *out = git_buf_detach(&buf); + } else if (cfgval) { *out = git__strdup(cfgval); + } } - else if (!git_sysdir_find_xdg_file(&buf, fallback)) + else if (!git_sysdir_find_xdg_file(&buf, fallback)) { *out = git_buf_detach(&buf); + } git_config_entry_free(entry); git_buf_free(&buf); @@ -309,7 +314,7 @@ static void attr_cache__free(git_attr_cache *cache) if (!cache) return; - unlock = (git_mutex_lock(&cache->lock) == 0); + unlock = (attr_cache_lock(cache) == 0); if (cache->files != NULL) { git_attr_file_entry *entry; @@ -345,13 +350,13 @@ static void attr_cache__free(git_attr_cache *cache) cache->cfg_excl_file = NULL; if (unlock) - git_mutex_unlock(&cache->lock); + attr_cache_unlock(cache); git_mutex_free(&cache->lock); git__free(cache); } -int git_attr_cache__do_init(git_repository *repo) +int git_attr_cache__init(git_repository *repo) { int ret = 0; git_attr_cache *cache = git_repository_attr_cache(repo); @@ -365,7 +370,7 @@ int git_attr_cache__do_init(git_repository *repo) /* set up lock */ if (git_mutex_init(&cache->lock) < 0) { - giterr_set(GITERR_OS, "Unable to initialize lock for attr cache"); + giterr_set(GITERR_OS, "unable to initialize lock for attr cache"); git__free(cache); return -1; } @@ -429,11 +434,11 @@ int git_attr_cache__insert_macro(git_repository *repo, git_attr_rule *macro) if (macro->assigns.length == 0) return 0; - if (git_mutex_lock(&cache->lock) < 0) { - giterr_set(GITERR_OS, "Unable to get attr cache lock"); + if (attr_cache_lock(cache) < 0) { + giterr_set(GITERR_OS, "unable to get attr cache lock"); error = -1; } else { - git_strmap_insert(macros, macro->match.pattern, macro, error); + git_strmap_insert(macros, macro->match.pattern, macro, &error); git_mutex_unlock(&cache->lock); } diff --git a/src/attrcache.h b/src/attrcache.h index 44e1ffdce..b91edd3e8 100644 --- a/src/attrcache.h +++ b/src/attrcache.h @@ -22,10 +22,7 @@ typedef struct { git_pool pool; } git_attr_cache; -extern int git_attr_cache__do_init(git_repository *repo); - -#define git_attr_cache__init(REPO) \ - (git_repository_attr_cache(REPO) ? 0 : git_attr_cache__do_init(REPO)) +extern int git_attr_cache__init(git_repository *repo); /* get file - loading and reload as needed */ extern int git_attr_cache__get( diff --git a/src/blame_git.c b/src/blame_git.c index 96785c75b..13f5cb47c 100644 --- a/src/blame_git.c +++ b/src/blame_git.c @@ -478,14 +478,15 @@ cleanup: * The blobs of origin and porigin exactly match, so everything origin is * suspected for can be blamed on the parent. */ -static void pass_whole_blame(git_blame *blame, +static int pass_whole_blame(git_blame *blame, git_blame__origin *origin, git_blame__origin *porigin) { git_blame__entry *e; - if (!porigin->blob) - git_object_lookup((git_object**)&porigin->blob, blame->repository, - git_blob_id(origin->blob), GIT_OBJ_BLOB); + if (!porigin->blob && + git_object_lookup((git_object**)&porigin->blob, blame->repository, + git_blob_id(origin->blob), GIT_OBJ_BLOB) < 0) + return -1; for (e=blame->ent; e; e=e->next) { if (!same_suspect(e->suspect, origin)) continue; @@ -493,6 +494,8 @@ static void pass_whole_blame(git_blame *blame, origin_decref(e->suspect); e->suspect = porigin; } + + return 0; } static int pass_blame(git_blame *blame, git_blame__origin *origin, uint32_t opt) @@ -514,11 +517,12 @@ static int pass_blame(git_blame *blame, git_blame__origin *origin, uint32_t opt) if (!num_parents) { git_oid_cpy(&blame->options.oldest_commit, git_commit_id(commit)); goto finish; - } - else if (num_parents < (int)ARRAY_SIZE(sg_buf)) + } else if (num_parents < (int)ARRAY_SIZE(sg_buf)) memset(sg_buf, 0, sizeof(sg_buf)); - else + else { sg_origin = git__calloc(num_parents, sizeof(*sg_origin)); + GITERR_CHECK_ALLOC(sg_origin); + } for (i=0; iblob && origin->blob && !git_oid_cmp(git_blob_id(porigin->blob), git_blob_id(origin->blob))) { - pass_whole_blame(blame, origin, porigin); + error = pass_whole_blame(blame, origin, porigin); origin_decref(porigin); goto finish; } diff --git a/src/blob.c b/src/blob.c index 1926c9e58..19d3039fb 100644 --- a/src/blob.c +++ b/src/blob.c @@ -96,7 +96,7 @@ static int write_file_stream( p_close(fd); if (written != file_size || read_len < 0) { - giterr_set(GITERR_OS, "Failed to read file into stream"); + giterr_set(GITERR_OS, "failed to read file into stream"); error = -1; } @@ -142,7 +142,7 @@ static int write_symlink( read_len = p_readlink(path, link_data, link_size); if (read_len != (ssize_t)link_size) { - giterr_set(GITERR_OS, "Failed to create blob. Can't read symlink '%s'", path); + giterr_set(GITERR_OS, "failed to create blob: cannot read symlink '%s'", path); git__free(link_data); return -1; } @@ -186,7 +186,7 @@ int git_blob__create_from_paths( goto done; if (S_ISDIR(st.st_mode)) { - giterr_set(GITERR_ODB, "cannot create blob from '%s'; it is a directory", content_path); + giterr_set(GITERR_ODB, "cannot create blob from '%s': it is a directory", content_path); error = GIT_EDIRECTORY; goto done; } @@ -326,8 +326,8 @@ int git_blob_create_fromstream(git_writestream **out, git_repository *repo, cons stream->parent.close = blob_writestream_close; stream->parent.free = blob_writestream_free; - if ((error = git_buf_joinpath(&path, - git_repository_path(repo), GIT_OBJECTS_DIR "streamed")) < 0) + if ((error = git_repository_item_path(&path, repo, GIT_REPOSITORY_ITEM_OBJECTS)) < 0 + || (error = git_buf_joinpath(&path, path.ptr, "streamed")) < 0) goto cleanup; if ((error = git_filebuf_open_withsize(&stream->fbuf, git_buf_cstr(&path), GIT_FILEBUF_TEMPORARY, diff --git a/src/branch.c b/src/branch.c index 8d1ed6577..fe4955ad6 100644 --- a/src/branch.c +++ b/src/branch.c @@ -13,6 +13,7 @@ #include "refs.h" #include "remote.h" #include "annotated_commit.h" +#include "worktree.h" #include "git2/branch.h" @@ -33,7 +34,7 @@ static int retrieve_branch_reference( /* OOM */; else if ((error = git_reference_lookup(&branch, repo, ref_name.ptr)) < 0) giterr_set( - GITERR_REFERENCE, "Cannot locate %s branch '%s'", + GITERR_REFERENCE, "cannot locate %s branch '%s'", is_remote ? "remote-tracking" : "local", branch_name); *branch_reference_out = branch; /* will be NULL on error */ @@ -46,7 +47,7 @@ static int not_a_local_branch(const char *reference_name) { giterr_set( GITERR_INVALID, - "Reference '%s' is not a local branch.", reference_name); + "reference '%s' is not a local branch.", reference_name); return -1; } @@ -80,7 +81,7 @@ static int create_branch( } if (is_unmovable_head && force) { - giterr_set(GITERR_REFERENCE, "Cannot force update branch '%s' as it is " + giterr_set(GITERR_REFERENCE, "cannot force update branch '%s' as it is " "the current HEAD of the repository.", branch_name); error = -1; goto cleanup; @@ -126,6 +127,31 @@ int git_branch_create_from_annotated( repository, branch_name, commit->commit, commit->description, force); } +static int branch_equals(git_repository *repo, const char *path, void *payload) +{ + git_reference *branch = (git_reference *) payload; + git_reference *head = NULL; + int equal = 0; + + if (git_reference__read_head(&head, repo, path) < 0 || + git_reference_type(head) != GIT_REF_SYMBOLIC) + goto done; + + equal = !git__strcmp(head->target.symbolic, branch->name); + +done: + git_reference_free(head); + return equal; +} + +int git_branch_is_checked_out(const git_reference *branch) +{ + assert(branch && git_reference_is_branch(branch)); + + return git_repository_foreach_head(git_reference_owner(branch), + branch_equals, (void *) branch) == 1; +} + int git_branch_delete(git_reference *branch) { int is_head; @@ -135,7 +161,7 @@ int git_branch_delete(git_reference *branch) assert(branch); if (!git_reference_is_branch(branch) && !git_reference_is_remote(branch)) { - giterr_set(GITERR_INVALID, "Reference '%s' is not a valid branch.", + giterr_set(GITERR_INVALID, "reference '%s' is not a valid branch.", git_reference_name(branch)); return GIT_ENOTFOUND; } @@ -144,11 +170,17 @@ int git_branch_delete(git_reference *branch) return is_head; if (is_head) { - giterr_set(GITERR_REFERENCE, "Cannot delete branch '%s' as it is " + giterr_set(GITERR_REFERENCE, "cannot delete branch '%s' as it is " "the current HEAD of the repository.", git_reference_name(branch)); return -1; } + if (git_reference_is_branch(branch) && git_branch_is_checked_out(branch)) { + giterr_set(GITERR_REFERENCE, "Cannot delete branch '%s' as it is " + "the current HEAD of a linked repository.", git_reference_name(branch)); + return -1; + } + if (git_buf_join(&config_section, '.', "branch", git_reference_name(branch) + strlen(GIT_REFS_HEADS_DIR)) < 0) goto on_error; @@ -306,7 +338,7 @@ int git_branch_name( branch_name += strlen(GIT_REFS_REMOTES_DIR); } else { giterr_set(GITERR_INVALID, - "Reference '%s' is neither a local nor a remote branch.", ref->name); + "reference '%s' is neither a local nor a remote branch.", ref->name); return -1; } *out = branch_name; @@ -436,7 +468,7 @@ int git_branch_remote_name(git_buf *buf, git_repository *repo, const char *refna /* Verify that this is a remote branch */ if (!git_reference__is_remote(refname)) { - giterr_set(GITERR_INVALID, "Reference '%s' is not a remote branch.", + giterr_set(GITERR_INVALID, "reference '%s' is not a remote branch.", refname); error = GIT_ERROR; goto cleanup; @@ -463,7 +495,7 @@ int git_branch_remote_name(git_buf *buf, git_repository *repo, const char *refna git_remote_free(remote); giterr_set(GITERR_REFERENCE, - "Reference '%s' is ambiguous", refname); + "reference '%s' is ambiguous", refname); error = GIT_EAMBIGUOUS; goto cleanup; } @@ -477,7 +509,7 @@ int git_branch_remote_name(git_buf *buf, git_repository *repo, const char *refna error = git_buf_puts(buf, remote_name); } else { giterr_set(GITERR_REFERENCE, - "Could not determine remote for '%s'", refname); + "could not determine remote for '%s'", refname); error = GIT_ENOTFOUND; } @@ -566,7 +598,7 @@ int git_branch_set_upstream(git_reference *branch, const char *upstream_name) local = 0; else { giterr_set(GITERR_REFERENCE, - "Cannot set upstream for branch '%s'", shortname); + "cannot set upstream for branch '%s'", shortname); return GIT_ENOTFOUND; } diff --git a/src/buffer.c b/src/buffer.c index d135ebe4a..6dfcbfbe6 100644 --- a/src/buffer.c +++ b/src/buffer.c @@ -18,18 +18,19 @@ char git_buf__initbuf[1]; char git_buf__oom[1]; #define ENSURE_SIZE(b, d) \ - if ((d) > buf->asize && git_buf_grow(b, (d)) < 0)\ + if ((d) > (b)->asize && git_buf_grow((b), (d)) < 0)\ return -1; -void git_buf_init(git_buf *buf, size_t initial_size) +int git_buf_init(git_buf *buf, size_t initial_size) { buf->asize = 0; buf->size = 0; buf->ptr = git_buf__initbuf; - if (initial_size) - git_buf_grow(buf, initial_size); + ENSURE_SIZE(buf, initial_size); + + return 0; } int git_buf_try_grow( @@ -577,7 +578,7 @@ char *git_buf_detach(git_buf *buf) return data; } -void git_buf_attach(git_buf *buf, char *ptr, size_t asize) +int git_buf_attach(git_buf *buf, char *ptr, size_t asize) { git_buf_free(buf); @@ -588,9 +589,10 @@ void git_buf_attach(git_buf *buf, char *ptr, size_t asize) buf->asize = (asize < buf->size) ? buf->size + 1 : asize; else /* pass 0 to fall back on strlen + 1 */ buf->asize = buf->size + 1; - } else { - git_buf_grow(buf, asize); } + + ENSURE_SIZE(buf, asize); + return 0; } void git_buf_attach_notowned(git_buf *buf, const char *ptr, size_t size) @@ -724,9 +726,7 @@ int git_buf_join( GITERR_CHECK_ALLOC_ADD(&alloc_len, strlen_a, strlen_b); GITERR_CHECK_ALLOC_ADD(&alloc_len, alloc_len, need_sep); GITERR_CHECK_ALLOC_ADD(&alloc_len, alloc_len, 1); - if (git_buf_grow(buf, alloc_len) < 0) - return -1; - assert(buf->ptr); + ENSURE_SIZE(buf, alloc_len); /* fix up internal pointers */ if (offset_a >= 0) @@ -780,8 +780,7 @@ int git_buf_join3( GITERR_CHECK_ALLOC_ADD(&len_total, len_total, sep_b); GITERR_CHECK_ALLOC_ADD(&len_total, len_total, len_c); GITERR_CHECK_ALLOC_ADD(&len_total, len_total, 1); - if (git_buf_grow(buf, len_total) < 0) - return -1; + ENSURE_SIZE(buf, len_total); tgt = buf->ptr; @@ -962,14 +961,14 @@ int git_buf_unquote(git_buf *buf) case '0': case '1': case '2': case '3': if (j == buf->size-3) { giterr_set(GITERR_INVALID, - "Truncated quoted character \\%c", ch); + "truncated quoted character \\%c", ch); return -1; } if (buf->ptr[j+1] < '0' || buf->ptr[j+1] > '7' || buf->ptr[j+2] < '0' || buf->ptr[j+2] > '7') { giterr_set(GITERR_INVALID, - "Truncated quoted character \\%c%c%c", + "truncated quoted character \\%c%c%c", buf->ptr[j], buf->ptr[j+1], buf->ptr[j+2]); return -1; } @@ -981,7 +980,7 @@ int git_buf_unquote(git_buf *buf) break; default: - giterr_set(GITERR_INVALID, "Invalid quoted character \\%c", ch); + giterr_set(GITERR_INVALID, "invalid quoted character \\%c", ch); return -1; } } @@ -995,6 +994,6 @@ int git_buf_unquote(git_buf *buf) return 0; invalid: - giterr_set(GITERR_INVALID, "Invalid quoted line"); + giterr_set(GITERR_INVALID, "invalid quoted line"); return -1; } diff --git a/src/buffer.h b/src/buffer.h index cdfca6d99..b0aece488 100644 --- a/src/buffer.h +++ b/src/buffer.h @@ -34,7 +34,7 @@ GIT_INLINE(bool) git_buf_is_allocated(const git_buf *buf) * For the cases where GIT_BUF_INIT cannot be used to do static * initialization. */ -extern void git_buf_init(git_buf *buf, size_t initial_size); +extern int git_buf_init(git_buf *buf, size_t initial_size); /** * Resize the buffer allocation to make more space. @@ -66,13 +66,14 @@ extern int git_buf_try_grow( * library, when providing git_buf's, may wish to provide a NULL ptr for * ease of handling. The buffer routines, however, expect a non-NULL ptr * always. This helper method simply handles NULL input, converting to a - * git_buf__initbuf. + * git_buf__initbuf. If a buffer with a non-NULL ptr is passed in, this method + * assures that the buffer is '\0'-terminated. */ extern void git_buf_sanitize(git_buf *buf); extern void git_buf_swap(git_buf *buf_a, git_buf *buf_b); extern char *git_buf_detach(git_buf *buf); -extern void git_buf_attach(git_buf *buf, char *ptr, size_t asize); +extern int git_buf_attach(git_buf *buf, char *ptr, size_t asize); /* Populates a `git_buf` where the contents are not "owned" by the * buffer, and calls to `git_buf_free` will not free the given buf. diff --git a/src/cache.c b/src/cache.c index ca5173c0d..c92a3a78a 100644 --- a/src/cache.c +++ b/src/cache.c @@ -15,8 +15,6 @@ #include "object.h" #include "git2/oid.h" -GIT__USE_OIDMAP - bool git_cache__enabled = true; ssize_t git_cache__max_storage = (256 * 1024 * 1024); git_atomic_ssize git_cache__current_storage = {0}; @@ -47,13 +45,13 @@ void git_cache_dump_stats(git_cache *cache) { git_cached_obj *object; - if (kh_size(cache->map) == 0) + if (git_cache_size(cache) == 0) return; - printf("Cache %p: %d items cached, %"PRIdZ" bytes\n", - cache, kh_size(cache->map), cache->used_memory); + printf("Cache %p: %"PRIuZ" items cached, %"PRIdZ" bytes\n", + cache, git_cache_size(cache), cache->used_memory); - kh_foreach_value(cache->map, object, { + git_oidmap_foreach_value(cache->map, object, { char oid_str[9]; printf(" %s%c %s (%"PRIuZ")\n", git_object_type2string(object->type), @@ -70,7 +68,7 @@ int git_cache_init(git_cache *cache) cache->map = git_oidmap_alloc(); GITERR_CHECK_ALLOC(cache->map); if (git_rwlock_init(&cache->lock)) { - giterr_set(GITERR_OS, "Failed to initialize cache rwlock"); + giterr_set(GITERR_OS, "failed to initialize cache rwlock"); return -1; } return 0; @@ -81,14 +79,14 @@ static void clear_cache(git_cache *cache) { git_cached_obj *evict = NULL; - if (kh_size(cache->map) == 0) + if (git_cache_size(cache) == 0) return; - kh_foreach_value(cache->map, evict, { + git_oidmap_foreach_value(cache->map, evict, { git_cached_obj_decref(evict); }); - kh_clear(oid, cache->map); + git_oidmap_clear(cache->map); git_atomic_ssize_add(&git_cache__current_storage, -cache->used_memory); cache->used_memory = 0; } @@ -119,22 +117,22 @@ static void cache_evict_entries(git_cache *cache) ssize_t evicted_memory = 0; /* do not infinite loop if there's not enough entries to evict */ - if (evict_count > kh_size(cache->map)) { + if (evict_count > git_cache_size(cache)) { clear_cache(cache); return; } while (evict_count > 0) { - khiter_t pos = seed++ % kh_end(cache->map); + khiter_t pos = seed++ % git_oidmap_end(cache->map); - if (kh_exist(cache->map, pos)) { - git_cached_obj *evict = kh_val(cache->map, pos); + if (git_oidmap_has_data(cache->map, pos)) { + git_cached_obj *evict = git_oidmap_value_at(cache->map, pos); evict_count--; evicted_memory += evict->size; git_cached_obj_decref(evict); - kh_del(oid, cache->map, pos); + git_oidmap_delete_at(cache->map, pos); } } @@ -156,9 +154,9 @@ static void *cache_get(git_cache *cache, const git_oid *oid, unsigned int flags) if (!git_cache__enabled || git_rwlock_rdlock(&cache->lock) < 0) return NULL; - pos = kh_get(oid, cache->map, oid); - if (pos != kh_end(cache->map)) { - entry = kh_val(cache->map, pos); + pos = git_oidmap_lookup_index(cache->map, oid); + if (git_oidmap_valid_index(cache->map, pos)) { + entry = git_oidmap_value_at(cache->map, pos); if (flags && entry->flags != flags) { entry = NULL; @@ -193,16 +191,14 @@ static void *cache_store(git_cache *cache, git_cached_obj *entry) if (git_cache__current_storage.val > git_cache__max_storage) cache_evict_entries(cache); - pos = kh_get(oid, cache->map, &entry->oid); + pos = git_oidmap_lookup_index(cache->map, &entry->oid); /* not found */ - if (pos == kh_end(cache->map)) { + if (!git_oidmap_valid_index(cache->map, pos)) { int rval; - pos = kh_put(oid, cache->map, &entry->oid, &rval); + git_oidmap_insert(cache->map, &entry->oid, entry, &rval); if (rval >= 0) { - kh_key(cache->map, pos) = &entry->oid; - kh_val(cache->map, pos) = entry; git_cached_obj_incref(entry); cache->used_memory += entry->size; git_atomic_ssize_add(&git_cache__current_storage, (ssize_t)entry->size); @@ -210,7 +206,7 @@ static void *cache_store(git_cache *cache, git_cached_obj *entry) } /* found */ else { - git_cached_obj *stored_entry = kh_val(cache->map, pos); + git_cached_obj *stored_entry = git_oidmap_value_at(cache->map, pos); if (stored_entry->flags == entry->flags) { git_cached_obj_decref(entry); @@ -221,8 +217,8 @@ static void *cache_store(git_cache *cache, git_cached_obj *entry) git_cached_obj_decref(stored_entry); git_cached_obj_incref(entry); - kh_key(cache->map, pos) = &entry->oid; - kh_val(cache->map, pos) = entry; + git_oidmap_set_key_at(cache->map, pos, &entry->oid); + git_oidmap_set_value_at(cache->map, pos, entry); } else { /* NO OP */ } diff --git a/src/cache.h b/src/cache.h index 697123739..0f0bfcf5d 100644 --- a/src/cache.h +++ b/src/cache.h @@ -53,7 +53,7 @@ void *git_cache_get_any(git_cache *cache, const git_oid *oid); GIT_INLINE(size_t) git_cache_size(git_cache *cache) { - return (size_t)kh_size(cache->map); + return (size_t)git_oidmap_size(cache->map); } GIT_INLINE(void) git_cached_obj_incref(void *_obj) diff --git a/src/checkout.c b/src/checkout.c index 62950913e..25018d291 100644 --- a/src/checkout.c +++ b/src/checkout.c @@ -35,8 +35,6 @@ #include "pool.h" #include "strmap.h" -GIT__USE_STRMAP - /* See docs/checkout-internals.md for more information */ enum { @@ -372,10 +370,8 @@ static int checkout_action_wd_only( */ const git_index_entry *e = git_index_get_byindex(data->index, pos); - if (e != NULL && data->diff->pfxcomp(e->path, wd->path) == 0) { - notify = GIT_CHECKOUT_NOTIFY_DIRTY; - remove = ((data->strategy & GIT_CHECKOUT_FORCE) != 0); - } + if (e != NULL && data->diff->pfxcomp(e->path, wd->path) == 0) + return git_iterator_advance_into(wditem, workdir); } } @@ -1021,13 +1017,13 @@ static int checkout_conflicts_load_byname_entry( *theirs_out = NULL; if (!name_entry->ancestor) { - giterr_set(GITERR_INDEX, "A NAME entry exists without an ancestor"); + giterr_set(GITERR_INDEX, "a NAME entry exists without an ancestor"); error = -1; goto done; } if (!name_entry->ours && !name_entry->theirs) { - giterr_set(GITERR_INDEX, "A NAME entry exists without an ours or theirs"); + giterr_set(GITERR_INDEX, "a NAME entry exists without an ours or theirs"); error = -1; goto done; } @@ -1035,7 +1031,7 @@ static int checkout_conflicts_load_byname_entry( if ((ancestor = checkout_conflicts_search_ancestor(data, name_entry->ancestor)) == NULL) { giterr_set(GITERR_INDEX, - "A NAME entry referenced ancestor entry '%s' which does not exist in the main index", + "a NAME entry referenced ancestor entry '%s' which does not exist in the main index", name_entry->ancestor); error = -1; goto done; @@ -1047,7 +1043,7 @@ static int checkout_conflicts_load_byname_entry( else if ((ours = checkout_conflicts_search_branch(data, name_entry->ours)) == NULL || ours->ours == NULL) { giterr_set(GITERR_INDEX, - "A NAME entry referenced our entry '%s' which does not exist in the main index", + "a NAME entry referenced our entry '%s' which does not exist in the main index", name_entry->ours); error = -1; goto done; @@ -1062,7 +1058,7 @@ static int checkout_conflicts_load_byname_entry( else if ((theirs = checkout_conflicts_search_branch(data, name_entry->theirs)) == NULL || theirs->theirs == NULL) { giterr_set(GITERR_INDEX, - "A NAME entry referenced their entry '%s' which does not exist in the main index", + "a NAME entry referenced their entry '%s' which does not exist in the main index", name_entry->theirs); error = -1; goto done; @@ -1161,7 +1157,7 @@ static int checkout_conflicts_mark_directoryfile( if ((error = git_index_find(&j, index, path)) < 0) { if (error == GIT_ENOTFOUND) giterr_set(GITERR_INDEX, - "Index inconsistency, could not find entry for expected conflict '%s'", path); + "index inconsistency, could not find entry for expected conflict '%s'", path); goto done; } @@ -1169,7 +1165,7 @@ static int checkout_conflicts_mark_directoryfile( for (; j < len; j++) { if ((entry = git_index_get_byindex(index, j)) == NULL) { giterr_set(GITERR_INDEX, - "Index inconsistency, truncated index while loading expected conflict '%s'", path); + "index inconsistency, truncated index while loading expected conflict '%s'", path); error = -1; goto done; } @@ -1254,14 +1250,14 @@ static int checkout_verify_paths( if (action & CHECKOUT_ACTION__REMOVE) { if (!git_path_isvalid(repo, delta->old_file.path, flags)) { - giterr_set(GITERR_CHECKOUT, "Cannot remove invalid path '%s'", delta->old_file.path); + 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)) { - giterr_set(GITERR_CHECKOUT, "Cannot checkout to invalid path '%s'", delta->new_file.path); + giterr_set(GITERR_CHECKOUT, "cannot checkout to invalid path '%s'", delta->new_file.path); return -1; } } @@ -1430,7 +1426,7 @@ static int mkpath2file( */ error = git_futils_rmdir_r(path, NULL, GIT_RMDIR_REMOVE_FILES); } else if (errno != ENOENT) { - giterr_set(GITERR_OS, "Failed to stat file '%s'", path); + giterr_set(GITERR_OS, "failed to stat '%s'", path); return GIT_EEXISTS; } else { giterr_clear(); @@ -1454,7 +1450,7 @@ static int checkout_stream_write( int ret; if ((ret = p_write(stream->fd, buffer, len)) < 0) - giterr_set(GITERR_OS, "Could not write to '%s'", stream->path); + giterr_set(GITERR_OS, "could not write to '%s'", stream->path); return ret; } @@ -1503,7 +1499,7 @@ static int blob_content_to_file( mode = GIT_FILEMODE_BLOB; if ((fd = p_open(path, flags, mode)) < 0) { - giterr_set(GITERR_OS, "Could not open '%s' for writing", path); + giterr_set(GITERR_OS, "could not open '%s' for writing", path); return fd; } @@ -1540,7 +1536,7 @@ static int blob_content_to_file( data->perfdata.stat_calls++; if ((error = p_stat(path, st)) < 0) { - giterr_set(GITERR_OS, "Error statting '%s'", path); + giterr_set(GITERR_OS, "failed to stat '%s'", path); return error; } @@ -1567,7 +1563,7 @@ static int blob_content_to_link( if (data->can_symlink) { if ((error = p_symlink(git_buf_cstr(&linktarget), path)) < 0) - giterr_set(GITERR_OS, "Could not create symlink %s", path); + giterr_set(GITERR_OS, "could not create symlink %s", path); } else { error = git_futils_fake_symlink(git_buf_cstr(&linktarget), path); } @@ -1576,7 +1572,7 @@ static int blob_content_to_link( data->perfdata.stat_calls++; if ((error = p_lstat(path, st)) < 0) - giterr_set(GITERR_CHECKOUT, "Could not stat symlink %s", path); + giterr_set(GITERR_CHECKOUT, "could not stat symlink %s", path); st->st_mode = GIT_FILEMODE_LINK; } @@ -1621,7 +1617,7 @@ static int checkout_submodule_update_index( data->perfdata.stat_calls++; if (p_stat(fullpath->ptr, &st) < 0) { giterr_set( - GITERR_CHECKOUT, "Could not stat submodule %s\n", file->path); + GITERR_CHECKOUT, "could not stat submodule %s\n", file->path); return GIT_ENOTFOUND; } @@ -1694,7 +1690,7 @@ static int checkout_safe_for_update_only( return 0; /* otherwise, stat error and no update */ - giterr_set(GITERR_OS, "Failed to stat file '%s'", path); + giterr_set(GITERR_OS, "failed to stat '%s'", path); return -1; } @@ -1966,7 +1962,7 @@ static int checkout_path_suffixed(git_buf *path, const char *suffix) if (i == INT_MAX) { git_buf_truncate(path, path_len); - giterr_set(GITERR_CHECKOUT, "Could not write '%s': working directory file exists", path->ptr); + giterr_set(GITERR_CHECKOUT, "could not write '%s': working directory file exists", path->ptr); return GIT_EEXISTS; } @@ -2097,7 +2093,7 @@ static int checkout_write_merge( goto done; if (result.path == NULL || result.mode == 0) { - giterr_set(GITERR_CHECKOUT, "Could not merge contents of file"); + giterr_set(GITERR_CHECKOUT, "could not merge contents of file"); error = GIT_ECONFLICT; goto done; } @@ -2321,8 +2317,6 @@ static void checkout_data_clear(checkout_data *data) git__free(data->pfx); data->pfx = NULL; - git_strmap_free(data->mkdir_map); - git_buf_free(&data->target_path); git_buf_free(&data->tmp); @@ -2330,6 +2324,7 @@ static void checkout_data_clear(checkout_data *data) data->index = NULL; git_strmap_free(data->mkdir_map); + data->mkdir_map = NULL; git_attr_session__free(&data->attr_session); } @@ -2345,7 +2340,7 @@ static int checkout_data_init( memset(data, 0, sizeof(*data)); if (!repo) { - giterr_set(GITERR_CHECKOUT, "Cannot checkout nothing"); + giterr_set(GITERR_CHECKOUT, "cannot checkout nothing"); return -1; } @@ -2553,6 +2548,10 @@ int git_checkout_iterator( GIT_ITERATOR_IGNORE_CASE : GIT_ITERATOR_DONT_IGNORE_CASE; baseline_opts.start = data.pfx; baseline_opts.end = data.pfx; + if (opts && (opts->checkout_strategy & GIT_CHECKOUT_DISABLE_PATHSPEC_MATCH)) { + baseline_opts.pathlist.count = opts->paths.count; + baseline_opts.pathlist.strings = opts->paths.strings; + } if (data.opts.baseline_index) { if ((error = git_iterator_for_index( @@ -2647,7 +2646,7 @@ int git_checkout_index( if (!index && !repo) { giterr_set(GITERR_CHECKOUT, - "Must provide either repository or index to checkout"); + "must provide either repository or index to checkout"); return -1; } @@ -2655,7 +2654,7 @@ int git_checkout_index( git_index_owner(index) && git_index_owner(index) != repo) { giterr_set(GITERR_CHECKOUT, - "Index to checkout does not match repository"); + "index to checkout does not match repository"); return -1; } else if(index && repo && !git_index_owner(index)) { GIT_REFCOUNT_OWN(index, repo); @@ -2694,12 +2693,12 @@ int git_checkout_tree( if (!treeish && !repo) { giterr_set(GITERR_CHECKOUT, - "Must provide either repository or tree to checkout"); + "must provide either repository or tree to checkout"); return -1; } if (treeish && repo && git_object_owner(treeish) != repo) { giterr_set(GITERR_CHECKOUT, - "Object to checkout does not match repository"); + "object to checkout does not match repository"); return -1; } @@ -2709,7 +2708,7 @@ int git_checkout_tree( if (treeish) { if (git_object_peel((git_object **)&tree, treeish, GIT_OBJ_TREE) < 0) { giterr_set( - GITERR_CHECKOUT, "Provided object cannot be peeled to a tree"); + GITERR_CHECKOUT, "provided object cannot be peeled to a tree"); return -1; } } diff --git a/src/cherrypick.c b/src/cherrypick.c index c92975194..d8b6858ae 100644 --- a/src/cherrypick.c +++ b/src/cherrypick.c @@ -28,7 +28,7 @@ static int write_cherrypick_head( git_buf file_path = GIT_BUF_INIT; int error = 0; - if ((error = git_buf_joinpath(&file_path, repo->path_repository, GIT_CHERRYPICK_HEAD_FILE)) >= 0 && + if ((error = git_buf_joinpath(&file_path, repo->gitdir, GIT_CHERRYPICK_HEAD_FILE)) >= 0 && (error = git_filebuf_open(&file, file_path.ptr, GIT_FILEBUF_FORCE, GIT_CHERRYPICK_FILE_MODE)) >= 0 && (error = git_filebuf_printf(&file, "%s\n", commit_oidstr)) >= 0) error = git_filebuf_commit(&file); @@ -49,7 +49,7 @@ static int write_merge_msg( git_buf file_path = GIT_BUF_INIT; int error = 0; - if ((error = git_buf_joinpath(&file_path, repo->path_repository, GIT_MERGE_MSG_FILE)) < 0 || + if ((error = git_buf_joinpath(&file_path, repo->gitdir, GIT_MERGE_MSG_FILE)) < 0 || (error = git_filebuf_open(&file, file_path.ptr, GIT_FILEBUF_FORCE, GIT_CHERRYPICK_FILE_MODE)) < 0 || (error = git_filebuf_printf(&file, "%s", commit_msg)) < 0) goto cleanup; @@ -130,13 +130,13 @@ int git_cherrypick_commit( if (git_commit_parentcount(cherrypick_commit) > 1) { if (!mainline) return cherrypick_seterr(cherrypick_commit, - "Mainline branch is not specified but %s is a merge commit"); + "mainline branch is not specified but %s is a merge commit"); parent = mainline; } else { if (mainline) return cherrypick_seterr(cherrypick_commit, - "Mainline branch specified but %s is not a merge commit"); + "mainline branch specified but %s is not a merge commit"); parent = git_commit_parentcount(cherrypick_commit); } diff --git a/src/clone.c b/src/clone.c index 0d4756e28..16ddface2 100644 --- a/src/clone.c +++ b/src/clone.c @@ -513,9 +513,8 @@ static int clone_local_into(git_repository *repo, git_remote *remote, const git_ return error; } - git_buf_joinpath(&src_odb, git_repository_path(src), GIT_OBJECTS_DIR); - git_buf_joinpath(&dst_odb, git_repository_path(repo), GIT_OBJECTS_DIR); - if (git_buf_oom(&src_odb) || git_buf_oom(&dst_odb)) { + if (git_repository_item_path(&src_odb, src, GIT_REPOSITORY_ITEM_OBJECTS) < 0 + || git_repository_item_path(&dst_odb, repo, GIT_REPOSITORY_ITEM_OBJECTS) < 0) { error = -1; goto cleanup; } diff --git a/src/commit.c b/src/commit.c index 76e6dcbc9..4a340058a 100644 --- a/src/commit.c +++ b/src/commit.c @@ -159,6 +159,9 @@ static int git_commit__create_internal( if (git_repository_odb__weakptr(&odb, repo) < 0) goto cleanup; + if (git_odb__freshen(odb, tree) < 0) + goto cleanup; + if (git_odb_write(id, odb, buf.ptr, buf.size, GIT_OBJ_COMMIT) < 0) goto cleanup; @@ -468,7 +471,7 @@ int git_commit__parse(void *_commit, git_odb_object *odb_obj) return 0; bad_buffer: - giterr_set(GITERR_OBJECT, "Failed to parse bad commit object"); + giterr_set(GITERR_OBJECT, "failed to parse bad commit object"); return -1; } @@ -598,7 +601,7 @@ int git_commit_parent( parent_id = git_commit_parent_id(commit, n); if (parent_id == NULL) { - giterr_set(GITERR_INVALID, "Parent %u does not exist", n); + giterr_set(GITERR_INVALID, "parent %u does not exist", n); return GIT_ENOTFOUND; } @@ -642,7 +645,7 @@ int git_commit_header_field(git_buf *out, const git_commit *commit, const char * { const char *eol, *buf = commit->raw_header; - git_buf_sanitize(out); + git_buf_clear(out); while ((eol = strchr(buf, '\n'))) { /* We can skip continuations here */ @@ -706,8 +709,8 @@ int git_commit_extract_signature(git_buf *signature, git_buf *signed_data, git_r const char *h, *eol; int error; - git_buf_sanitize(signature); - git_buf_sanitize(signed_data); + git_buf_clear(signature); + git_buf_clear(signed_data); if (!field) field = "gpgsig"; @@ -766,8 +769,9 @@ int git_commit_extract_signature(git_buf *signature, git_buf *signed_data, git_r if (git_buf_oom(signature)) goto oom; + error = git_buf_puts(signed_data, eol+1); git_odb_object_free(obj); - return git_buf_puts(signed_data, eol+1); + return error; } giterr_set(GITERR_OBJECT, "this commit is not signed"); diff --git a/src/commit_list.c b/src/commit_list.c index a1681ffae..3bba58c27 100644 --- a/src/commit_list.c +++ b/src/commit_list.c @@ -61,7 +61,7 @@ static int commit_error(git_commit_list_node *commit, const char *msg) git_oid_fmt(commit_oid, &commit->oid); commit_oid[GIT_OID_HEXSZ] = '\0'; - giterr_set(GITERR_ODB, "Failed to parse commit %s - %s", commit_oid, msg); + giterr_set(GITERR_ODB, "failed to parse commit %s - %s", commit_oid, msg); return -1; } @@ -191,7 +191,7 @@ int git_commit_list_parse(git_revwalk *walk, git_commit_list_node *commit) return error; if (obj->cached.type != GIT_OBJ_COMMIT) { - giterr_set(GITERR_INVALID, "Object is no commit object"); + giterr_set(GITERR_INVALID, "object is no commit object"); error = -1; } else error = commit_quick_parse( diff --git a/src/common.h b/src/common.h index f12cc98cf..e566aeabd 100644 --- a/src/common.h +++ b/src/common.h @@ -188,7 +188,7 @@ GIT_INLINE(int) giterr__check_version(const void *structure, unsigned int expect if (actual > 0 && actual <= expected_max) return 0; - giterr_set(GITERR_INVALID, "Invalid version %d on %s", actual, name); + giterr_set(GITERR_INVALID, "invalid version %d on %s", actual, name); return -1; } #define GITERR_CHECK_VERSION(S,V,N) if (giterr__check_version(S,V,N) < 0) return -1 diff --git a/src/config.c b/src/config.c index 403b7090d..169a62880 100644 --- a/src/config.c +++ b/src/config.c @@ -109,7 +109,7 @@ int git_config_add_file_ondisk( res = p_stat(path, &st); if (res < 0 && errno != ENOENT) { - giterr_set(GITERR_CONFIG, "Error stat'ing config file '%s'", path); + giterr_set(GITERR_CONFIG, "failed to stat '%s'", path); return -1; } @@ -203,7 +203,7 @@ static int find_internal_file_by_level( if (pos == -1) { giterr_set(GITERR_CONFIG, - "No config file exists for the given level '%i'", (int)level); + "no config file exists for the given level '%i'", (int)level); return GIT_ENOTFOUND; } @@ -218,7 +218,7 @@ static int duplicate_level(void **old_raw, void *new_raw) GIT_UNUSED(new_raw); - giterr_set(GITERR_CONFIG, "A file with the same level (%i) has already been added to the config", (int)(*old)->level); + giterr_set(GITERR_CONFIG, "a file with the same level (%i) has already been added to the config", (int)(*old)->level); return GIT_EEXISTS; } @@ -576,22 +576,50 @@ int git_config_foreach_match( * Setters **************/ -static int config_error_nofiles(const char *name) +typedef enum { + BACKEND_USE_SET, + BACKEND_USE_DELETE +} backend_use; + +static const char *uses[] = { + "set", + "delete" +}; + +static int get_backend_for_use(git_config_backend **out, + git_config *cfg, const char *name, backend_use use) { + size_t i; + file_internal *f; + + *out = NULL; + + if (git_vector_length(&cfg->files) == 0) { + giterr_set(GITERR_CONFIG, + "cannot %s value for '%s' when no config files exist", + uses[use], name); + return GIT_ENOTFOUND; + } + + git_vector_foreach(&cfg->files, i, f) { + if (!f->file->readonly) { + *out = f->file; + return 0; + } + } + giterr_set(GITERR_CONFIG, - "Cannot set value for '%s' when no config files exist", name); + "cannot %s value for '%s' when all config files are readonly", + uses[use], name); return GIT_ENOTFOUND; } int git_config_delete_entry(git_config *cfg, const char *name) { git_config_backend *file; - file_internal *internal; - internal = git_vector_get(&cfg->files, 0); - if (!internal || !internal->file) - return config_error_nofiles(name); - file = internal->file; + if (get_backend_for_use(&file, cfg, name, BACKEND_USE_DELETE) < 0) + return GIT_ENOTFOUND; return file->del(file, name); } @@ -617,17 +645,14 @@ int git_config_set_string(git_config *cfg, const char *name, const char *value) { int error; git_config_backend *file; - file_internal *internal; if (!value) { - giterr_set(GITERR_CONFIG, "The value to set cannot be NULL"); + giterr_set(GITERR_CONFIG, "the value to set cannot be NULL"); return -1; } - internal = git_vector_get(&cfg->files, 0); - if (!internal || !internal->file) - return config_error_nofiles(name); - file = internal->file; + if (get_backend_for_use(&file, cfg, name, BACKEND_USE_SET) < 0) + return GIT_ENOTFOUND; error = file->set(file, name, value); @@ -674,7 +699,7 @@ int git_config__update_entry( static int config_error_notfound(const char *name) { - giterr_set(GITERR_CONFIG, "Config value '%s' was not found", name); + giterr_set(GITERR_CONFIG, "config value '%s' was not found", name); return GIT_ENOTFOUND; } @@ -1032,12 +1057,9 @@ on_error: int git_config_set_multivar(git_config *cfg, const char *name, const char *regexp, const char *value) { git_config_backend *file; - file_internal *internal; - internal = git_vector_get(&cfg->files, 0); - if (!internal || !internal->file) - return config_error_nofiles(name); - file = internal->file; + if (get_backend_for_use(&file, cfg, name, BACKEND_USE_DELETE) < 0) + return GIT_ENOTFOUND; return file->set_multivar(file, name, regexp, value); } @@ -1045,12 +1067,9 @@ int git_config_set_multivar(git_config *cfg, const char *name, const char *regex int git_config_delete_multivar(git_config *cfg, const char *name, const char *regexp) { git_config_backend *file; - file_internal *internal; - internal = git_vector_get(&cfg->files, 0); - if (!internal || !internal->file) - return config_error_nofiles(name); - file = internal->file; + if (get_backend_for_use(&file, cfg, name, BACKEND_USE_DELETE) < 0) + return GIT_ENOTFOUND; return file->del_multivar(file, name, regexp); } @@ -1236,7 +1255,7 @@ int git_config_lookup_map_value( } fail_parse: - giterr_set(GITERR_CONFIG, "Failed to map '%s'", value); + giterr_set(GITERR_CONFIG, "failed to map '%s'", value); return -1; } @@ -1270,7 +1289,7 @@ int git_config_parse_bool(int *out, const char *value) return 0; } - giterr_set(GITERR_CONFIG, "Failed to parse '%s' as a boolean value", value); + giterr_set(GITERR_CONFIG, "failed to parse '%s' as a boolean value", value); return -1; } @@ -1313,7 +1332,7 @@ int git_config_parse_int64(int64_t *out, const char *value) } fail_parse: - giterr_set(GITERR_CONFIG, "Failed to parse '%s' as an integer", value ? value : "(null)"); + giterr_set(GITERR_CONFIG, "failed to parse '%s' as an integer", value ? value : "(null)"); return -1; } @@ -1333,15 +1352,12 @@ int git_config_parse_int32(int32_t *out, const char *value) return 0; fail_parse: - giterr_set(GITERR_CONFIG, "Failed to parse '%s' as a 32-bit integer", value ? value : "(null)"); + giterr_set(GITERR_CONFIG, "failed to parse '%s' as a 32-bit integer", value ? value : "(null)"); return -1; } int git_config_parse_path(git_buf *out, const char *value) { - int error = 0; - const git_buf *home; - assert(out && value); git_buf_sanitize(out); @@ -1352,16 +1368,7 @@ int git_config_parse_path(git_buf *out, const char *value) return -1; } - if ((error = git_sysdir_get(&home, GIT_SYSDIR_GLOBAL)) < 0) - return error; - - git_buf_sets(out, home->ptr); - git_buf_puts(out, value + 1); - - if (git_buf_oom(out)) - return -1; - - return 0; + return git_sysdir_expand_global_file(out, value[1] ? &value[2] : NULL); } return git_buf_sets(out, value); @@ -1398,7 +1405,7 @@ int git_config__normalize_name(const char *in, char **out) invalid: git__free(name); - giterr_set(GITERR_CONFIG, "Invalid config item name '%s'", in); + giterr_set(GITERR_CONFIG, "invalid config item name '%s'", in); return GIT_EINVALIDSPEC; } @@ -1461,7 +1468,7 @@ int git_config_rename_section( replace.ptr, strchr(replace.ptr, '.'))) < 0) { giterr_set( - GITERR_CONFIG, "Invalid config section '%s'", new_section_name); + GITERR_CONFIG, "invalid config section '%s'", new_section_name); goto cleanup; } diff --git a/src/config_cache.c b/src/config_cache.c index dbea871b9..840722274 100644 --- a/src/config_cache.c +++ b/src/config_cache.c @@ -78,6 +78,7 @@ static struct map_data _cvar_maps[] = { {"core.logallrefupdates", NULL, 0, GIT_LOGALLREFUPDATES_DEFAULT }, {"core.protecthfs", NULL, 0, GIT_PROTECTHFS_DEFAULT }, {"core.protectntfs", NULL, 0, GIT_PROTECTNTFS_DEFAULT }, + {"core.fsyncobjectfiles", NULL, 0, GIT_FSYNCOBJECTFILES_DEFAULT }, }; int git_config__cvar(int *out, git_config *config, git_cvar_cached cvar) diff --git a/src/config_file.c b/src/config_file.c index 9ff021e7e..e15d57bbb 100644 --- a/src/config_file.c +++ b/src/config_file.c @@ -21,8 +21,6 @@ #include #include -GIT__USE_STRMAP - typedef struct cvar_t { struct cvar_t *next; git_config_entry *entry; @@ -126,7 +124,7 @@ static int config_snapshot(git_config_backend **out, git_config_backend *in); static void set_parse_error(struct reader *reader, int col, const char *error_str) { - giterr_set(GITERR_CONFIG, "Failed to parse config file: %s (in %s:%d, column %d)", + giterr_set(GITERR_CONFIG, "failed to parse config file: %s (in %s:%d, column %d)", error_str, reader->file_path, reader->line_number, col); } @@ -179,7 +177,7 @@ static int append_entry(git_strmap *values, cvar_t *var) pos = git_strmap_lookup_index(values, var->entry->name); if (!git_strmap_valid_index(values, pos)) { - git_strmap_insert(values, var->entry->name, var, error); + git_strmap_insert(values, var->entry->name, var, &error); } else { existing = git_strmap_value_at(values, pos); while (existing->next != NULL) { @@ -233,7 +231,7 @@ static refcounted_strmap *refcounted_strmap_take(diskfile_header *h) refcounted_strmap *map; if (git_mutex_lock(&h->values_mutex) < 0) { - giterr_set(GITERR_OS, "Failed to lock config backend"); + giterr_set(GITERR_OS, "failed to lock config backend"); return NULL; } @@ -322,7 +320,7 @@ static int config__refresh(git_config_backend *cfg) goto out; if ((error = git_mutex_lock(&b->header.values_mutex)) < 0) { - giterr_set(GITERR_OS, "Failed to lock config backend"); + giterr_set(GITERR_OS, "failed to lock config backend"); goto out; } @@ -479,7 +477,7 @@ static int config_set(git_config_backend *cfg, const char *name, const char *val cvar_t *existing = git_strmap_value_at(values, pos); if (existing->next != NULL) { - giterr_set(GITERR_CONFIG, "Multivar incompatible with simple set"); + giterr_set(GITERR_CONFIG, "multivar incompatible with simple set"); ret = -1; goto out; } @@ -611,7 +609,7 @@ static int config_delete(git_config_backend *cfg, const char *name) if (!git_strmap_valid_index(values, pos)) { refcounted_strmap_free(map); - giterr_set(GITERR_CONFIG, "Could not find key '%s' to delete", name); + giterr_set(GITERR_CONFIG, "could not find key '%s' to delete", name); return GIT_ENOTFOUND; } @@ -619,7 +617,7 @@ static int config_delete(git_config_backend *cfg, const char *name) refcounted_strmap_free(map); if (var->next != NULL) { - giterr_set(GITERR_CONFIG, "Cannot delete multivar with a single delete"); + giterr_set(GITERR_CONFIG, "cannot delete multivar with a single delete"); return -1; } @@ -651,7 +649,7 @@ static int config_delete_multivar(git_config_backend *cfg, const char *name, con if (!git_strmap_valid_index(values, pos)) { refcounted_strmap_free(map); git__free(key); - giterr_set(GITERR_CONFIG, "Could not find key '%s' to delete", name); + giterr_set(GITERR_CONFIG, "could not find key '%s' to delete", name); return GIT_ENOTFOUND; } @@ -1029,7 +1027,7 @@ static int parse_section_header_ext(struct reader *reader, const char *line, con first_quote = strchr(line, '"'); if (first_quote == NULL) { set_parse_error(reader, 0, "Missing quotation marks in section header"); - return -1; + goto end_error; } last_quote = strrchr(line, '"'); @@ -1037,14 +1035,15 @@ static int parse_section_header_ext(struct reader *reader, const char *line, con if (quoted_len == 0) { set_parse_error(reader, 0, "Missing closing quotation mark in section header"); - return -1; + goto end_error; } GITERR_CHECK_ALLOC_ADD(&alloc_len, base_name_len, quoted_len); GITERR_CHECK_ALLOC_ADD(&alloc_len, alloc_len, 2); - git_buf_grow(&buf, alloc_len); - git_buf_printf(&buf, "%s.", base_name); + if (git_buf_grow(&buf, alloc_len) < 0 || + git_buf_printf(&buf, "%s.", base_name) < 0) + goto end_error; rpos = 0; @@ -1060,8 +1059,7 @@ static int parse_section_header_ext(struct reader *reader, const char *line, con switch (c) { case 0: set_parse_error(reader, 0, "Unexpected end-of-line in section header"); - git_buf_free(&buf); - return -1; + goto end_error; case '"': goto end_parse; @@ -1071,8 +1069,7 @@ static int parse_section_header_ext(struct reader *reader, const char *line, con if (c == 0) { set_parse_error(reader, rpos, "Unexpected end-of-line in section header"); - git_buf_free(&buf); - return -1; + goto end_error; } default: @@ -1084,6 +1081,9 @@ static int parse_section_header_ext(struct reader *reader, const char *line, con } while (line + rpos < last_quote); end_parse: + if (git_buf_oom(&buf)) + goto end_error; + if (line[rpos] != '"' || line[rpos + 1] != ']') { set_parse_error(reader, rpos, "Unexpected text after closing quotes"); git_buf_free(&buf); @@ -1092,6 +1092,11 @@ end_parse: *section_name = git_buf_detach(&buf); return 0; + +end_error: + git_buf_free(&buf); + + return -1; } static int parse_section_header(struct reader *reader, char **section_out) @@ -1251,7 +1256,7 @@ static int included_path(git_buf *out, const char *dir, const char *path) { /* From the user's home */ if (path[0] == '~' && path[1] == '/') - return git_sysdir_find_global_file(out, &path[1]); + return git_sysdir_expand_global_file(out, &path[1]); return git_path_join_unrooted(out, path, dir, NULL); } @@ -1262,7 +1267,7 @@ static const char *escaped = "\n\t\b\"\\"; /* Escape the values to write them to the file */ static char *escape_value(const char *ptr) { - git_buf buf = GIT_BUF_INIT; + git_buf buf; size_t len; const char *esc; @@ -1272,7 +1277,8 @@ static char *escape_value(const char *ptr) if (!len) return git__calloc(1, sizeof(char)); - git_buf_grow(&buf, len); + if (git_buf_init(&buf, len) < 0) + return NULL; while (*ptr != '\0') { if ((esc = strchr(escaped, *ptr)) != NULL) { @@ -1325,7 +1331,7 @@ static int unescape_line( *fixed++ = escaped[esc - escapes]; } else { git__free(str); - giterr_set(GITERR_CONFIG, "Invalid escape at %s", ptr); + giterr_set(GITERR_CONFIG, "invalid escape at %s", ptr); return -1; } } @@ -1639,7 +1645,7 @@ static int config_read(git_strmap *values, diskfile_backend *cfg_file, struct re struct parse_data parse_data; if (depth >= MAX_INCLUDE_DEPTH) { - giterr_set(GITERR_CONFIG, "Maximum config include depth reached"); + giterr_set(GITERR_CONFIG, "maximum config include depth reached"); return -1; } diff --git a/src/config_file.h b/src/config_file.h index 1c52892c3..654e6cacf 100644 --- a/src/config_file.h +++ b/src/config_file.h @@ -7,6 +7,7 @@ #ifndef INCLUDE_config_file_h__ #define INCLUDE_config_file_h__ +#include "git2/sys/config.h" #include "git2/config.h" GIT_INLINE(int) git_config_file_open(git_config_backend *cfg, unsigned int level) diff --git a/src/crlf.c b/src/crlf.c index 11895b19f..b8ae5cda1 100644 --- a/src/crlf.c +++ b/src/crlf.c @@ -218,7 +218,7 @@ static const char *line_ending(struct crlf_attrs *ca) return "\r\n"; line_ending_error: - giterr_set(GITERR_INVALID, "Invalid input to line ending filter"); + giterr_set(GITERR_INVALID, "invalid input to line ending filter"); return NULL; } diff --git a/src/delta.c b/src/delta.c index dc45697b6..073cba7c6 100644 --- a/src/delta.c +++ b/src/delta.c @@ -131,7 +131,7 @@ static int lookup_index_alloc( GITERR_CHECK_ALLOC_ADD(&index_len, index_len, hash_len); if (!git__is_ulong(index_len)) { - giterr_set(GITERR_NOMEMORY, "Overly large delta"); + giterr_set(GITERR_NOMEMORY, "overly large delta"); return -1; } @@ -544,12 +544,12 @@ int git_delta_apply( * 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"); + giterr_set(GITERR_INVALID, "failed to apply delta: base size does not match given data"); return -1; } if (hdr_sz(&res_sz, &delta, delta_end) < 0) { - giterr_set(GITERR_INVALID, "Failed to apply delta. Base size does not match given data"); + giterr_set(GITERR_INVALID, "failed to apply delta: base size does not match given data"); return -1; } @@ -614,6 +614,6 @@ fail: *out = NULL; *out_len = 0; - giterr_set(GITERR_INVALID, "Failed to apply delta"); + giterr_set(GITERR_INVALID, "failed to apply delta"); return -1; } diff --git a/src/describe.c b/src/describe.c index fc48fbde4..4a1e25378 100644 --- a/src/describe.c +++ b/src/describe.c @@ -19,8 +19,6 @@ #include "vector.h" #include "repository.h" -GIT__USE_OIDMAP - /* Ported from https://github.com/git/git/blob/89dde7882f71f846ccd0359756d27bebc31108de/builtin/describe.c */ struct commit_name { @@ -127,7 +125,7 @@ static int add_to_known_names( if (!found) { int ret; - git_oidmap_insert(names, &e->peeled, e, ret); + git_oidmap_insert(names, &e->peeled, e, &ret); if (ret < 0) return -1; } @@ -335,14 +333,14 @@ static int display_name(git_buf *buf, git_repository *repo, struct commit_name * { if (n->prio == 2 && !n->tag) { if (git_tag_lookup(&n->tag, repo, &n->sha1) < 0) { - giterr_set(GITERR_TAG, "Annotated tag '%s' not available", n->path); + giterr_set(GITERR_TAG, "annotated tag '%s' not available", n->path); return -1; } } if (n->tag && !n->name_checked) { if (!git_tag_name(n->tag)) { - giterr_set(GITERR_TAG, "Annotated tag '%s' has no embedded name", n->path); + giterr_set(GITERR_TAG, "annotated tag '%s' has no embedded name", n->path); return -1; } @@ -471,7 +469,7 @@ static int describe( if (!data->opts->max_candidates_tags) { error = describe_not_found( git_commit_id(commit), - "Cannot describe - no tag exactly matches '%s'"); + "cannot describe - no tag exactly matches '%s'"); goto cleanup; } @@ -564,15 +562,15 @@ static int describe( } if (unannotated_cnt) { error = describe_not_found(git_commit_id(commit), - "Cannot describe - " - "No annotated tags can describe '%s'." - "However, there were unannotated tags."); + "cannot describe - " + "no annotated tags can describe '%s'; " + "however, there were unannotated tags."); goto cleanup; } else { error = describe_not_found(git_commit_id(commit), - "Cannot describe - " - "No tags can describe '%s'."); + "cannot describe - " + "no tags can describe '%s'."); goto cleanup; } } @@ -695,8 +693,8 @@ int git_describe_commit( goto cleanup; if (git_oidmap_size(data.names) == 0 && !opts->show_commit_oid_as_fallback) { - giterr_set(GITERR_DESCRIBE, "Cannot describe - " - "No reference found, cannot describe anything."); + giterr_set(GITERR_DESCRIBE, "cannot describe - " + "no reference found, cannot describe anything."); error = -1; goto cleanup; } @@ -793,7 +791,7 @@ int git_describe_format(git_buf *out, const git_describe_result *result, const g if (opts.always_use_long_format && opts.abbreviated_size == 0) { - giterr_set(GITERR_DESCRIBE, "Cannot describe - " + giterr_set(GITERR_DESCRIBE, "cannot describe - " "'always_use_long_format' is incompatible with a zero" "'abbreviated_size'"); return -1; diff --git a/src/diff.c b/src/diff.c index 317d49597..a93bd4cd0 100644 --- a/src/diff.c +++ b/src/diff.c @@ -120,6 +120,41 @@ int git_diff_get_perfdata(git_diff_perfdata *out, const git_diff *diff) return 0; } +int git_diff_foreach( + git_diff *diff, + git_diff_file_cb file_cb, + git_diff_binary_cb binary_cb, + git_diff_hunk_cb hunk_cb, + git_diff_line_cb data_cb, + void *payload) +{ + int error = 0; + git_diff_delta *delta; + size_t idx; + + assert(diff); + + git_vector_foreach(&diff->deltas, idx, delta) { + git_patch *patch; + + /* check flags against patch status */ + if (git_diff_delta__should_skip(&diff->opts, delta)) + continue; + + if ((error = git_patch_from_diff(&patch, diff, idx)) != 0) + break; + + error = git_patch__invoke_callbacks(patch, file_cb, binary_cb, + hunk_cb, data_cb, payload); + git_patch_free(patch); + + if (error) + break; + } + + return error; +} + int git_diff_format_email__append_header_tobuf( git_buf *out, const git_oid *id, diff --git a/src/diff_driver.c b/src/diff_driver.c index 1a7f09a44..9109f3155 100644 --- a/src/diff_driver.c +++ b/src/diff_driver.c @@ -16,8 +16,6 @@ #include "config.h" #include "repository.h" -GIT__USE_STRMAP - typedef enum { DIFF_DRIVER_AUTO = 0, DIFF_DRIVER_BINARY = 1, @@ -151,7 +149,7 @@ static git_diff_driver_registry *git_repository_driver_registry( } if (!repo->diff_drivers) - giterr_set(GITERR_REPOSITORY, "Unable to create diff driver registry"); + giterr_set(GITERR_REPOSITORY, "unable to create diff driver registry"); return repo->diff_drivers; } @@ -217,7 +215,7 @@ static int git_diff_driver_builtin( goto done; } - git_strmap_insert(reg->drivers, drv->name, drv, error); + git_strmap_insert(reg->drivers, drv->name, drv, &error); if (error > 0) error = 0; @@ -331,7 +329,7 @@ static int git_diff_driver_load( goto done; /* store driver in registry */ - git_strmap_insert(reg->drivers, drv->name, drv, error); + git_strmap_insert(reg->drivers, drv->name, drv, &error); if (error < 0) goto done; error = 0; diff --git a/src/diff_file.c b/src/diff_file.c index cc1029038..d5fc5e940 100644 --- a/src/diff_file.c +++ b/src/diff_file.c @@ -304,7 +304,7 @@ static int diff_file_content_load_workdir_symlink( read_len = p_readlink(git_buf_cstr(path), fc->map.data, alloc_len); if (read_len < 0) { - giterr_set(GITERR_OS, "Failed to read symlink '%s'", fc->file->path); + giterr_set(GITERR_OS, "failed to read symlink '%s'", fc->file->path); return -1; } diff --git a/src/diff_generate.c b/src/diff_generate.c index 06f9b19c7..f6cc04fed 100644 --- a/src/diff_generate.c +++ b/src/diff_generate.c @@ -624,7 +624,7 @@ int git_diff__oid_for_entry( error = git_odb__hashlink(out, full_path.ptr); diff->base.perf.oid_calculations++; } else if (!git__is_sizet(entry.file_size)) { - giterr_set(GITERR_OS, "File size overflow (for 32-bits) on '%s'", + giterr_set(GITERR_OS, "file size overflow (for 32-bits) on '%s'", entry.path); error = -1; } else if (!(error = git_filter_list_load(&fl, @@ -1587,7 +1587,7 @@ int git_diff__commit( char commit_oidstr[GIT_OID_HEXSZ + 1]; error = -1; - giterr_set(GITERR_INVALID, "Commit %s is a merge commit", + giterr_set(GITERR_INVALID, "commit %s is a merge commit", git_oid_tostr(commit_oidstr, GIT_OID_HEXSZ + 1, git_commit_id(commit))); goto on_error; } diff --git a/src/diff_parse.c b/src/diff_parse.c index e640063af..5e3a7a177 100644 --- a/src/diff_parse.c +++ b/src/diff_parse.c @@ -37,7 +37,6 @@ static git_diff_parsed *diff_parsed_alloc(void) GIT_REFCOUNT_INC(diff); diff->base.type = GIT_DIFF_TYPE_PARSED; - diff->base.opts.flags &= ~GIT_DIFF_IGNORE_CASE; diff->base.strcomp = git__strcmp; diff->base.strncomp = git__strncmp; diff->base.pfxcomp = git__prefixcmp; @@ -45,6 +44,13 @@ static git_diff_parsed *diff_parsed_alloc(void) diff->base.patch_fn = git_patch_parsed_from_diff; diff->base.free_fn = diff_parsed_free; + if (git_diff_init_options(&diff->base.opts, GIT_DIFF_OPTIONS_VERSION) < 0) { + git__free(diff); + return NULL; + } + + diff->base.opts.flags &= ~GIT_DIFF_IGNORE_CASE; + git_pool_init(&diff->base.pool, 1); if (git_vector_init(&diff->patches, 0, NULL) < 0 || diff --git a/src/diff_print.c b/src/diff_print.c index fd1a186c1..5aa8a37e6 100644 --- a/src/diff_print.c +++ b/src/diff_print.c @@ -222,7 +222,7 @@ static int diff_print_one_raw( if (pi->id_strlen > id_abbrev) { giterr_set(GITERR_PATCH, - "The patch input contains %d id characters (cannot print %d)", + "the patch input contains %d id characters (cannot print %d)", id_abbrev, pi->id_strlen); return -1; } @@ -273,7 +273,7 @@ static int diff_print_oid_range( if (delta->old_file.mode && id_strlen > delta->old_file.id_abbrev) { giterr_set(GITERR_PATCH, - "The patch input contains %d id characters (cannot print %d)", + "the patch input contains %d id characters (cannot print %d)", delta->old_file.id_abbrev, id_strlen); return -1; } @@ -281,7 +281,7 @@ static int diff_print_oid_range( if ((delta->new_file.mode && id_strlen > delta->new_file.id_abbrev)) { giterr_set(GITERR_PATCH, - "The patch input contains %d id characters (cannot print %d)", + "the patch input contains %d id characters (cannot print %d)", delta->new_file.id_abbrev, id_strlen); return -1; } @@ -680,7 +680,7 @@ int git_diff_print( print_file = diff_print_one_name_status; break; default: - giterr_set(GITERR_INVALID, "Unknown diff output format (%d)", format); + giterr_set(GITERR_INVALID, "unknown diff output format (%d)", format); return -1; } @@ -708,7 +708,7 @@ int git_diff_print_callback__to_buf( GIT_UNUSED(delta); GIT_UNUSED(hunk); if (!output) { - giterr_set(GITERR_INVALID, "Buffer pointer must be provided"); + giterr_set(GITERR_INVALID, "buffer pointer must be provided"); return -1; } diff --git a/src/diff_tform.c b/src/diff_tform.c index e8848bd45..b004ddd66 100644 --- a/src/diff_tform.c +++ b/src/diff_tform.c @@ -131,7 +131,7 @@ int git_diff__merge( if (ignore_case != ((from->opts.flags & GIT_DIFF_IGNORE_CASE) != 0) || reversed != ((from->opts.flags & GIT_DIFF_REVERSE) != 0)) { giterr_set(GITERR_INVALID, - "Attempt to merge diffs created with conflicting options"); + "attempt to merge diffs created with conflicting options"); return -1; } @@ -553,8 +553,8 @@ static int similarity_measure( *score = -1; - /* don't try to compare files of different types */ - if (GIT_MODE_TYPE(a_file->mode) != GIT_MODE_TYPE(b_file->mode)) + /* don't try to compare things that aren't files */ + if (!GIT_MODE_ISBLOB(a_file->mode) || !GIT_MODE_ISBLOB(b_file->mode)) return 0; /* if exact match is requested, force calculation of missing OIDs now */ diff --git a/src/diff_xdiff.c b/src/diff_xdiff.c index 5bd6381b5..60c4d85cb 100644 --- a/src/diff_xdiff.c +++ b/src/diff_xdiff.c @@ -50,7 +50,7 @@ static int git_xdiff_parse_hunk(git_diff_hunk *hunk, const char *header) return 0; fail: - giterr_set(GITERR_INVALID, "Malformed hunk header from xdiff"); + giterr_set(GITERR_INVALID, "malformed hunk header from xdiff"); return -1; } @@ -99,7 +99,7 @@ static int diff_update_lines( info->new_lineno += (int)line->num_lines; break; default: - giterr_set(GITERR_INVALID, "Unknown diff line origin %02x", + giterr_set(GITERR_INVALID, "unknown diff line origin %02x", (unsigned int)line->origin); return -1; } diff --git a/src/fetch.c b/src/fetch.c index 4d895752c..f408a5174 100644 --- a/src/fetch.c +++ b/src/fetch.c @@ -113,7 +113,7 @@ int git_fetch_negotiate(git_remote *remote, const git_fetch_options *opts) remote->need_pack = 0; if (filter_wants(remote, opts) < 0) { - giterr_set(GITERR_NET, "Failed to filter the reference list for wants"); + giterr_set(GITERR_NET, "failed to filter the reference list for wants"); return -1; } diff --git a/src/fetchhead.c b/src/fetchhead.c index 3d16c2166..6e6f3eb5e 100644 --- a/src/fetchhead.c +++ b/src/fetchhead.c @@ -115,7 +115,7 @@ int git_fetchhead_write(git_repository *repo, git_vector *fetchhead_refs) assert(repo && fetchhead_refs); - if (git_buf_joinpath(&path, repo->path_repository, GIT_FETCH_HEAD_FILE) < 0) + if (git_buf_joinpath(&path, repo->gitdir, GIT_FETCH_HEAD_FILE) < 0) return -1; if (git_filebuf_open(&file, path.ptr, GIT_FILEBUF_FORCE, GIT_REFS_FILE_MODE) < 0) { @@ -149,7 +149,7 @@ static int fetchhead_ref_parse( if (!*line) { giterr_set(GITERR_FETCHHEAD, - "Empty line in FETCH_HEAD line %"PRIuZ, line_num); + "empty line in FETCH_HEAD line %"PRIuZ, line_num); return -1; } @@ -163,13 +163,13 @@ static int fetchhead_ref_parse( if (strlen(oid_str) != GIT_OID_HEXSZ) { giterr_set(GITERR_FETCHHEAD, - "Invalid object ID in FETCH_HEAD line %"PRIuZ, line_num); + "invalid object ID in FETCH_HEAD line %"PRIuZ, line_num); return -1; } if (git_oid_fromstr(oid, oid_str) < 0) { const git_error *oid_err = giterr_last(); - const char *err_msg = oid_err ? oid_err->message : "Invalid object ID"; + const char *err_msg = oid_err ? oid_err->message : "invalid object ID"; giterr_set(GITERR_FETCHHEAD, "%s in FETCH_HEAD line %"PRIuZ, err_msg, line_num); @@ -180,7 +180,7 @@ static int fetchhead_ref_parse( if (*line) { if ((is_merge_str = git__strsep(&line, "\t")) == NULL) { giterr_set(GITERR_FETCHHEAD, - "Invalid description data in FETCH_HEAD line %"PRIuZ, line_num); + "invalid description data in FETCH_HEAD line %"PRIuZ, line_num); return -1; } @@ -190,13 +190,13 @@ static int fetchhead_ref_parse( *is_merge = 0; else { giterr_set(GITERR_FETCHHEAD, - "Invalid for-merge entry in FETCH_HEAD line %"PRIuZ, line_num); + "invalid for-merge entry in FETCH_HEAD line %"PRIuZ, line_num); return -1; } if ((desc = line) == NULL) { giterr_set(GITERR_FETCHHEAD, - "Invalid description in FETCH_HEAD line %"PRIuZ, line_num); + "invalid description in FETCH_HEAD line %"PRIuZ, line_num); return -1; } @@ -213,7 +213,7 @@ static int fetchhead_ref_parse( if ((desc = strstr(name, "' ")) == NULL || git__prefixcmp(desc, "' of ") != 0) { giterr_set(GITERR_FETCHHEAD, - "Invalid description in FETCH_HEAD line %"PRIuZ, line_num); + "invalid description in FETCH_HEAD line %"PRIuZ, line_num); return -1; } @@ -249,7 +249,7 @@ int git_repository_fetchhead_foreach(git_repository *repo, assert(repo && cb); - if (git_buf_joinpath(&path, repo->path_repository, GIT_FETCH_HEAD_FILE) < 0) + if (git_buf_joinpath(&path, repo->gitdir, GIT_FETCH_HEAD_FILE) < 0) return -1; if ((error = git_futils_readbuffer(&file, git_buf_cstr(&path))) < 0) @@ -277,7 +277,7 @@ int git_repository_fetchhead_foreach(git_repository *repo, } if (*buffer) { - giterr_set(GITERR_FETCHHEAD, "No EOL at line %"PRIuZ, line_num+1); + giterr_set(GITERR_FETCHHEAD, "no EOL at line %"PRIuZ, line_num+1); error = -1; goto done; } diff --git a/src/filebuf.c b/src/filebuf.c index 582399470..80250ccdf 100644 --- a/src/filebuf.c +++ b/src/filebuf.c @@ -23,7 +23,7 @@ static int verify_last_error(git_filebuf *file) { switch (file->last_error) { case BUFERR_WRITE: - giterr_set(GITERR_OS, "Failed to write out file"); + giterr_set(GITERR_OS, "failed to write out file"); return -1; case BUFERR_MEM: @@ -48,7 +48,7 @@ static int lock_file(git_filebuf *file, int flags, mode_t mode) else { giterr_clear(); /* actual OS error code just confuses */ giterr_set(GITERR_OS, - "Failed to lock file '%s' for writing", file->path_lock); + "failed to lock file '%s' for writing", file->path_lock); return GIT_ELOCKED; } } @@ -75,7 +75,7 @@ static int lock_file(git_filebuf *file, int flags, mode_t mode) source = p_open(file->path_original, O_RDONLY); if (source < 0) { giterr_set(GITERR_OS, - "Failed to open file '%s' for reading", + "failed to open file '%s' for reading", file->path_original); return -1; } @@ -90,10 +90,10 @@ static int lock_file(git_filebuf *file, int flags, mode_t mode) p_close(source); if (read_bytes < 0) { - giterr_set(GITERR_OS, "Failed to read file '%s'", file->path_original); + giterr_set(GITERR_OS, "failed to read file '%s'", file->path_original); return -1; } else if (error < 0) { - giterr_set(GITERR_OS, "Failed to write file '%s'", file->path_lock); + giterr_set(GITERR_OS, "failed to write file '%s'", file->path_lock); return -1; } } @@ -246,7 +246,7 @@ static int resolve_symlink(git_buf *out, const char *path) root = git_path_root(target.ptr); if (root >= 0) { - if ((error = git_buf_puts(&curpath, target.ptr)) < 0) + if ((error = git_buf_sets(&curpath, target.ptr)) < 0) goto cleanup; } else { git_buf dir = GIT_BUF_INIT; @@ -291,6 +291,9 @@ int git_filebuf_open_withsize(git_filebuf *file, const char *path, int flags, mo if (flags & GIT_FILEBUF_DO_NOT_BUFFER) file->do_not_buffer = true; + if (flags & GIT_FILEBUF_FSYNC) + file->do_fsync = true; + file->buf_size = size; file->buf_pos = 0; file->fd = -1; @@ -316,7 +319,7 @@ int git_filebuf_open_withsize(git_filebuf *file, const char *path, int flags, mo if (compression != 0) { /* Initialize the ZLib stream */ if (deflateInit(&file->zs, compression) != Z_OK) { - giterr_set(GITERR_ZLIB, "Failed to initialize zlib"); + giterr_set(GITERR_ZLIB, "failed to initialize zlib"); goto cleanup; } @@ -425,18 +428,26 @@ int git_filebuf_commit(git_filebuf *file) file->fd_is_open = false; + if (file->do_fsync && p_fsync(file->fd) < 0) { + giterr_set(GITERR_OS, "failed to fsync '%s'", file->path_lock); + goto on_error; + } + if (p_close(file->fd) < 0) { - giterr_set(GITERR_OS, "Failed to close file at '%s'", file->path_lock); + giterr_set(GITERR_OS, "failed to close file at '%s'", file->path_lock); goto on_error; } file->fd = -1; if (p_rename(file->path_lock, file->path_original) < 0) { - giterr_set(GITERR_OS, "Failed to rename lockfile to '%s'", file->path_original); + giterr_set(GITERR_OS, "failed to rename lockfile to '%s'", file->path_original); goto on_error; } + if (file->do_fsync && git_futils_fsync_parent(file->path_original) < 0) + goto on_error; + file->did_rename = true; git_filebuf_cleanup(file); @@ -571,7 +582,7 @@ int git_filebuf_stats(time_t *mtime, size_t *size, git_filebuf *file) res = p_stat(file->path_original, &st); if (res < 0) { - giterr_set(GITERR_OS, "Could not get stat info for '%s'", + giterr_set(GITERR_OS, "could not get stat info for '%s'", file->path_original); return res; } diff --git a/src/filebuf.h b/src/filebuf.h index 467708d45..c65aea780 100644 --- a/src/filebuf.h +++ b/src/filebuf.h @@ -20,7 +20,8 @@ #define GIT_FILEBUF_FORCE (1 << 3) #define GIT_FILEBUF_TEMPORARY (1 << 4) #define GIT_FILEBUF_DO_NOT_BUFFER (1 << 5) -#define GIT_FILEBUF_DEFLATE_SHIFT (6) +#define GIT_FILEBUF_FSYNC (1 << 6) +#define GIT_FILEBUF_DEFLATE_SHIFT (7) #define GIT_FILELOCK_EXTENSION ".lock\0" #define GIT_FILELOCK_EXTLENGTH 6 @@ -47,6 +48,7 @@ struct git_filebuf { bool created_lock; bool did_rename; bool do_not_buffer; + bool do_fsync; int last_error; }; diff --git a/src/fileops.c b/src/fileops.c index a82202c98..2f3f58d4f 100644 --- a/src/fileops.c +++ b/src/fileops.c @@ -13,8 +13,6 @@ #include "win32/findfile.h" #endif -GIT__USE_STRMAP - int git_futils_mkpath2file(const char *file_path, const mode_t mode) { return git_futils_mkdir( @@ -37,13 +35,13 @@ int git_futils_mktmp(git_buf *path_out, const char *filename, mode_t mode) if ((fd = p_mkstemp(path_out->ptr)) < 0) { giterr_set(GITERR_OS, - "Failed to create temporary file '%s'", path_out->ptr); + "failed to create temporary file '%s'", path_out->ptr); return -1; } if (p_chmod(path_out->ptr, (mode & ~mask))) { giterr_set(GITERR_OS, - "Failed to set permissions on file '%s'", path_out->ptr); + "failed to set permissions on file '%s'", path_out->ptr); return -1; } @@ -59,7 +57,7 @@ int git_futils_creat_withpath(const char *path, const mode_t dirmode, const mode fd = p_creat(path, mode); if (fd < 0) { - giterr_set(GITERR_OS, "Failed to create file '%s'", path); + giterr_set(GITERR_OS, "failed to create file '%s'", path); return -1; } @@ -68,12 +66,12 @@ int git_futils_creat_withpath(const char *path, const mode_t dirmode, const mode int git_futils_creat_locked(const char *path, const mode_t mode) { - int fd = p_open(path, O_WRONLY | O_CREAT | O_TRUNC | - O_EXCL | O_BINARY | O_CLOEXEC, mode); + int fd = p_open(path, O_WRONLY | O_CREAT | O_EXCL | O_BINARY | O_CLOEXEC, + mode); if (fd < 0) { int error = errno; - giterr_set(GITERR_OS, "Failed to create locked file '%s'", path); + giterr_set(GITERR_OS, "failed to create locked file '%s'", path); switch (error) { case EEXIST: return GIT_ELOCKED; @@ -108,7 +106,7 @@ git_off_t git_futils_filesize(git_file fd) struct stat sb; if (p_fstat(fd, &sb)) { - giterr_set(GITERR_OS, "Failed to stat file descriptor"); + giterr_set(GITERR_OS, "failed to stat file descriptor"); return -1; } @@ -137,7 +135,7 @@ int git_futils_readbuffer_fd(git_buf *buf, git_file fd, size_t len) git_buf_clear(buf); if (!git__is_ssizet(len)) { - giterr_set(GITERR_INVALID, "Read too large."); + giterr_set(GITERR_INVALID, "read too large"); return -1; } @@ -149,7 +147,7 @@ int git_futils_readbuffer_fd(git_buf *buf, git_file fd, size_t len) read_size = p_read(fd, buf->ptr, len); if (read_size != (ssize_t)len) { - giterr_set(GITERR_OS, "Failed to read descriptor"); + giterr_set(GITERR_OS, "failed to read descriptor"); git_buf_free(buf); return -1; } @@ -184,7 +182,7 @@ int git_futils_readbuffer_updated( } if (!git__is_sizet(st.st_size+1)) { - giterr_set(GITERR_OS, "Invalid regular file stat for '%s'", path); + giterr_set(GITERR_OS, "invalid regular file stat for '%s'", path); return -1; } @@ -198,28 +196,29 @@ int git_futils_readbuffer_updated( p_close(fd); - if ((error = git_hash_buf(&checksum_new, buf.ptr, buf.size)) < 0) { - git_buf_free(&buf); - return error; - } + if (checksum) { + if ((error = git_hash_buf(&checksum_new, buf.ptr, buf.size)) < 0) { + git_buf_free(&buf); + return error; + } - /* - * If we were given a checksum, we only want to use it if it's different - */ - if (checksum && !git_oid__cmp(checksum, &checksum_new)) { - git_buf_free(&buf); - if (updated) - *updated = 0; + /* + * If we were given a checksum, we only want to use it if it's different + */ + if (!git_oid__cmp(checksum, &checksum_new)) { + git_buf_free(&buf); + if (updated) + *updated = 0; - return 0; + return 0; + } + + git_oid_cpy(checksum, &checksum_new); } /* * If we're here, the file did change, or the user didn't have an old version */ - if (checksum) - git_oid_cpy(checksum, &checksum_new); - if (updated != NULL) *updated = 1; @@ -237,26 +236,43 @@ int git_futils_readbuffer(git_buf *buf, const char *path) int git_futils_writebuffer( const git_buf *buf, const char *path, int flags, mode_t mode) { - int fd, error = 0; + int fd, do_fsync = 0, error = 0; - if (flags <= 0) + if (!flags) flags = O_CREAT | O_TRUNC | O_WRONLY; + + if ((flags & O_FSYNC) != 0) + do_fsync = 1; + + flags &= ~O_FSYNC; + if (!mode) mode = GIT_FILEMODE_BLOB; if ((fd = p_open(path, flags, mode)) < 0) { - giterr_set(GITERR_OS, "Could not open '%s' for writing", path); + giterr_set(GITERR_OS, "could not open '%s' for writing", path); return fd; } if ((error = p_write(fd, git_buf_cstr(buf), git_buf_len(buf))) < 0) { - giterr_set(GITERR_OS, "Could not write to '%s'", path); + giterr_set(GITERR_OS, "could not write to '%s'", path); (void)p_close(fd); return error; } - if ((error = p_close(fd)) < 0) - giterr_set(GITERR_OS, "Error while closing '%s'", path); + if (do_fsync && (error = p_fsync(fd)) < 0) { + giterr_set(GITERR_OS, "could not fsync '%s'", path); + p_close(fd); + return error; + } + + if ((error = p_close(fd)) < 0) { + giterr_set(GITERR_OS, "error while closing '%s'", path); + return error; + } + + if (do_fsync && (flags & O_CREAT)) + error = git_futils_fsync_parent(path); return error; } @@ -267,7 +283,7 @@ int git_futils_mv_withpath(const char *from, const char *to, const mode_t dirmod return -1; if (p_rename(from, to) < 0) { - giterr_set(GITERR_OS, "Failed to rename '%s' to '%s'", from, to); + giterr_set(GITERR_OS, "failed to rename '%s' to '%s'", from, to); return -1; } @@ -288,13 +304,19 @@ int git_futils_mmap_ro_file(git_map *out, const char *path) if (fd < 0) return fd; - len = git_futils_filesize(fd); + if ((len = git_futils_filesize(fd)) < 0) { + result = -1; + goto out; + } + if (!git__is_sizet(len)) { - giterr_set(GITERR_OS, "File `%s` too large to mmap", path); - return -1; + giterr_set(GITERR_OS, "file `%s` too large to mmap", path); + result = -1; + goto out; } result = git_futils_mmap_ro(out, fd, 0, (size_t)len); +out: p_close(fd); return result; } @@ -314,14 +336,14 @@ GIT_INLINE(int) mkdir_validate_dir( /* with exclusive create, existing dir is an error */ if ((flags & GIT_MKDIR_EXCL) != 0) { giterr_set(GITERR_FILESYSTEM, - "Failed to make directory '%s': directory exists", path); + "failed to make directory '%s': directory exists", path); return GIT_EEXISTS; } if ((S_ISREG(st->st_mode) && (flags & GIT_MKDIR_REMOVE_FILES)) || (S_ISLNK(st->st_mode) && (flags & GIT_MKDIR_REMOVE_SYMLINKS))) { if (p_unlink(path) < 0) { - giterr_set(GITERR_OS, "Failed to remove %s '%s'", + giterr_set(GITERR_OS, "failed to remove %s '%s'", S_ISLNK(st->st_mode) ? "symlink" : "file", path); return GIT_EEXISTS; } @@ -329,7 +351,7 @@ GIT_INLINE(int) mkdir_validate_dir( opts->perfdata.mkdir_calls++; if (p_mkdir(path, mode) < 0) { - giterr_set(GITERR_OS, "Failed to make directory '%s'", path); + giterr_set(GITERR_OS, "failed to make directory '%s'", path); return GIT_EEXISTS; } } @@ -339,14 +361,14 @@ GIT_INLINE(int) mkdir_validate_dir( opts->perfdata.stat_calls++; if (p_stat(path, st) < 0) { - giterr_set(GITERR_OS, "Failed to make directory '%s'", path); + giterr_set(GITERR_OS, "failed to make directory '%s'", path); return GIT_EEXISTS; } } else if (!S_ISDIR(st->st_mode)) { giterr_set(GITERR_FILESYSTEM, - "Failed to make directory '%s': directory exists", path); + "failed to make directory '%s': directory exists", path); return GIT_EEXISTS; } @@ -569,7 +591,7 @@ int git_futils_mkdir_relative( retry_lstat: if (p_lstat(make_path.ptr, &st) < 0) { if (mkdir_attempted || errno != ENOENT) { - giterr_set(GITERR_OS, "Cannot access component in path '%s'", make_path.ptr); + giterr_set(GITERR_OS, "cannot access component in path '%s'", make_path.ptr); error = -1; goto done; } @@ -580,7 +602,7 @@ retry_lstat: if (p_mkdir(make_path.ptr, mode) < 0) { if (errno == EEXIST) goto retry_lstat; - giterr_set(GITERR_OS, "Failed to make directory '%s'", make_path.ptr); + giterr_set(GITERR_OS, "failed to make directory '%s'", make_path.ptr); error = -1; goto done; } @@ -607,7 +629,7 @@ retry_lstat: memcpy(cache_path, make_path.ptr, make_path.size + 1); - git_strmap_insert(opts->dir_map, cache_path, cache_path, error); + git_strmap_insert(opts->dir_map, cache_path, cache_path, &error); if (error < 0) goto done; } @@ -621,7 +643,7 @@ retry_lstat: opts->perfdata.stat_calls++; if (p_stat(make_path.ptr, &st) < 0 || !S_ISDIR(st.st_mode)) { - giterr_set(GITERR_OS, "Path is not a directory '%s'", + giterr_set(GITERR_OS, "path is not a directory '%s'", make_path.ptr); error = GIT_ENOTFOUND; } @@ -644,10 +666,10 @@ typedef struct { static int futils__error_cannot_rmdir(const char *path, const char *filemsg) { if (filemsg) - giterr_set(GITERR_OS, "Could not remove directory. File '%s' %s", + giterr_set(GITERR_OS, "could not remove directory '%s': %s", path, filemsg); else - giterr_set(GITERR_OS, "Could not remove directory '%s'", path); + giterr_set(GITERR_OS, "could not remove directory '%s'", path); return -1; } @@ -748,6 +770,9 @@ static int futils__rmdir_empty_parent(void *opaque, const char *path) if (en == ENOENT || en == ENOTDIR) { /* do nothing */ + } else if ((data->flags & GIT_RMDIR_SKIP_NONEMPTY) == 0 && + en == EBUSY) { + error = git_path_set_error(errno, path, "rmdir"); } else if (en == ENOTEMPTY || en == EEXIST || en == EBUSY) { error = GIT_ITEROVER; } else { @@ -815,7 +840,7 @@ static int cp_by_fd(int ifd, int ofd, bool close_fd_when_done) error = p_write(ofd, buffer, len); if (len < 0) { - giterr_set(GITERR_OS, "Read error while copying file"); + giterr_set(GITERR_OS, "read error while copying file"); error = (int)len; } @@ -871,14 +896,14 @@ static int cp_link(const char *from, const char *to, size_t link_size) read_len = p_readlink(from, link_data, link_size); if (read_len != (ssize_t)link_size) { - giterr_set(GITERR_OS, "Failed to read symlink data for '%s'", from); + giterr_set(GITERR_OS, "failed to read symlink data for '%s'", from); error = -1; } else { link_data[read_len] = '\0'; if (p_symlink(link_data, to) < 0) { - giterr_set(GITERR_OS, "Could not symlink '%s' as '%s'", + giterr_set(GITERR_OS, "could not symlink '%s' as '%s'", link_data, to); error = -1; } @@ -974,7 +999,7 @@ static int _cp_r_callback(void *ref, git_buf *from) return 0; if (p_unlink(info->to.ptr) < 0) { - giterr_set(GITERR_OS, "Cannot overwrite existing file '%s'", + giterr_set(GITERR_OS, "cannot overwrite existing file '%s'", info->to.ptr); return GIT_EEXISTS; } @@ -1109,3 +1134,37 @@ void git_futils_filestamp_set_from_stat( memset(stamp, 0, sizeof(*stamp)); } } + +int git_futils_fsync_dir(const char *path) +{ +#ifdef GIT_WIN32 + GIT_UNUSED(path); + return 0; +#else + int fd, error = -1; + + if ((fd = p_open(path, O_RDONLY)) < 0) { + giterr_set(GITERR_OS, "failed to open directory '%s' for fsync", path); + return -1; + } + + if ((error = p_fsync(fd)) < 0) + giterr_set(GITERR_OS, "failed to fsync directory '%s'", path); + + p_close(fd); + return error; +#endif +} + +int git_futils_fsync_parent(const char *path) +{ + char *parent; + int error; + + if ((parent = git_path_dirname(path)) == NULL) + return -1; + + error = git_futils_fsync_dir(parent); + git__free(parent); + return error; +} diff --git a/src/fileops.h b/src/fileops.h index 65c96a6f5..46886b0d7 100644 --- a/src/fileops.h +++ b/src/fileops.h @@ -25,6 +25,13 @@ extern int git_futils_readbuffer_updated( git_buf *obj, const char *path, git_oid *checksum, int *updated); extern int git_futils_readbuffer_fd(git_buf *obj, git_file fd, size_t len); +/* Additional constants for `git_futils_writebuffer`'s `open_flags`. We + * support these internally and they will be removed before the `open` call. + */ +#ifndef O_FSYNC +# define O_FSYNC (1 << 31) +#endif + extern int git_futils_writebuffer( const git_buf *buf, const char *path, int open_flags, mode_t mode); @@ -356,4 +363,22 @@ extern void git_futils_filestamp_set( extern void git_futils_filestamp_set_from_stat( git_futils_filestamp *stamp, struct stat *st); +/** + * `fsync` the parent directory of the given path, if `fsync` is + * supported for directories on this platform. + * + * @param path Path of the directory to sync. + * @return 0 on success, -1 on error + */ +extern int git_futils_fsync_dir(const char *path); + +/** + * `fsync` the parent directory of the given path, if `fsync` is + * supported for directories on this platform. + * + * @param path Path of the file whose parent directory should be synced. + * @return 0 on success, -1 on error + */ +extern int git_futils_fsync_parent(const char *path); + #endif /* INCLUDE_fileops_h__ */ diff --git a/src/filter.c b/src/filter.c index a0628d779..361e08529 100644 --- a/src/filter.c +++ b/src/filter.c @@ -296,7 +296,7 @@ int git_filter_unregister(const char *name) /* cannot unregister default filters */ if (!strcmp(GIT_FILTER_CRLF, name) || !strcmp(GIT_FILTER_IDENT, name)) { - giterr_set(GITERR_FILTER, "Cannot unregister filter '%s'", name); + giterr_set(GITERR_FILTER, "cannot unregister filter '%s'", name); return -1; } @@ -306,7 +306,7 @@ int git_filter_unregister(const char *name) } if ((fdef = filter_registry_lookup(&pos, name)) == NULL) { - giterr_set(GITERR_FILTER, "Cannot find filter '%s' to unregister", name); + giterr_set(GITERR_FILTER, "cannot find filter '%s' to unregister", name); error = GIT_ENOTFOUND; goto done; } @@ -645,7 +645,7 @@ int git_filter_list_push( git_rwlock_rdunlock(&filter_registry.lock); if (fdef == NULL) { - giterr_set(GITERR_FILTER, "Cannot use an unregistered filter"); + giterr_set(GITERR_FILTER, "cannot use an unregistered filter"); return -1; } @@ -758,7 +758,7 @@ static int buf_from_blob(git_buf *out, git_blob *blob) git_off_t rawsize = git_blob_rawsize(blob); if (!git__is_sizet(rawsize)) { - giterr_set(GITERR_OS, "Blob is too large to filter"); + giterr_set(GITERR_OS, "blob is too large to filter"); return -1; } @@ -895,7 +895,7 @@ static int stream_list_init( git_array_size(filters->filters) - 1 - i : i; git_filter_entry *fe = git_array_get(filters->filters, filter_idx); git_writestream *filter_stream; - + assert(fe->filter->stream || fe->filter->apply); /* If necessary, create a stream that proxies the traditional @@ -911,14 +911,19 @@ static int stream_list_init( last_stream); if (error < 0) - return error; + goto out; git_vector_insert(streams, filter_stream); last_stream = filter_stream; } - *out = last_stream; - return 0; +out: + if (error) + last_stream->close(last_stream); + else + *out = last_stream; + + return error; } void stream_list_free(git_vector *streams) @@ -943,12 +948,13 @@ int git_filter_list_stream_file( git_vector filter_streams = GIT_VECTOR_INIT; git_writestream *stream_start; ssize_t readlen; - int fd = -1, error; + int fd = -1, error, initialized = 0; if ((error = stream_list_init( &stream_start, &filter_streams, filters, target)) < 0 || (error = git_path_join_unrooted(&abspath, path, base, NULL)) < 0) goto done; + initialized = 1; if ((fd = git_futils_open_ro(abspath.ptr)) < 0) { error = fd; @@ -960,13 +966,13 @@ int git_filter_list_stream_file( goto done; } - if (!readlen) - error = stream_start->close(stream_start); - else if (readlen < 0) + if (readlen < 0) error = readlen; - done: + if (initialized) + error |= stream_start->close(stream_start); + if (fd >= 0) p_close(fd); stream_list_free(&filter_streams); @@ -981,20 +987,24 @@ int git_filter_list_stream_data( { git_vector filter_streams = GIT_VECTOR_INIT; git_writestream *stream_start; - int error = 0, close_error; + int error, initialized = 0; git_buf_sanitize(data); if ((error = stream_list_init(&stream_start, &filter_streams, filters, target)) < 0) goto out; + initialized = 1; - error = stream_start->write(stream_start, data->ptr, data->size); + if ((error = stream_start->write( + stream_start, data->ptr, data->size)) < 0) + goto out; out: - close_error = stream_start->close(stream_start); + if (initialized) + error |= stream_start->close(stream_start); + stream_list_free(&filter_streams); - /* propagate the stream init or write error */ - return error < 0 ? error : close_error; + return error; } int git_filter_list_stream_blob( @@ -1012,3 +1022,9 @@ int git_filter_list_stream_blob( return git_filter_list_stream_data(filters, &in, target); } + +int git_filter_init(git_filter *filter, unsigned int version) +{ + GIT_INIT_STRUCTURE_FROM_TEMPLATE(filter, version, git_filter, GIT_FILTER_INIT); + return 0; +} diff --git a/src/global.c b/src/global.c index e2ad8fe71..afa57e1d6 100644 --- a/src/global.c +++ b/src/global.c @@ -22,7 +22,7 @@ git_mutex git__mwindow_mutex; -#define MAX_SHUTDOWN_CB 8 +#define MAX_SHUTDOWN_CB 9 static git_global_shutdown_fn git__shutdown_callbacks[MAX_SHUTDOWN_CB]; static git_atomic git__n_shutdown_callbacks; diff --git a/src/hash.h b/src/hash.h index 0bc02a8a9..0db0339dc 100644 --- a/src/hash.h +++ b/src/hash.h @@ -16,11 +16,13 @@ int git_hash_global_init(void); int git_hash_ctx_init(git_hash_ctx *ctx); void git_hash_ctx_cleanup(git_hash_ctx *ctx); -#if defined(GIT_COMMON_CRYPTO) +#if defined(GIT_SHA1_COLLISIONDETECT) +# include "hash/hash_collisiondetect.h" +#elif defined(GIT_SHA1_COMMON_CRYPTO) # include "hash/hash_common_crypto.h" -#elif defined(OPENSSL_SHA1) +#elif defined(GIT_SHA1_OPENSSL) # include "hash/hash_openssl.h" -#elif defined(WIN32_SHA1) +#elif defined(GIT_SHA1_WIN32) # include "hash/hash_win32.h" #else # include "hash/hash_generic.h" diff --git a/src/hash/hash_collisiondetect.h b/src/hash/hash_collisiondetect.h new file mode 100644 index 000000000..5fdae8df6 --- /dev/null +++ b/src/hash/hash_collisiondetect.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#ifndef INCLUDE_hash_collisiondetect_h__ +#define INCLUDE_hash_collisiondetect_h__ + +#include "hash.h" +#include "sha1dc/sha1.h" + +struct git_hash_ctx { + SHA1_CTX c; +}; + +#define git_hash_global_init() 0 +#define git_hash_ctx_init(ctx) git_hash_init(ctx) +#define git_hash_ctx_cleanup(ctx) + +GIT_INLINE(int) git_hash_init(git_hash_ctx *ctx) +{ + assert(ctx); + SHA1DCInit(&ctx->c); + return 0; +} + +GIT_INLINE(int) git_hash_update(git_hash_ctx *ctx, const void *data, size_t len) +{ + assert(ctx); + SHA1DCUpdate(&ctx->c, data, len); + return 0; +} + +GIT_INLINE(int) git_hash_final(git_oid *out, git_hash_ctx *ctx) +{ + assert(ctx); + if (SHA1DCFinal(out->id, &ctx->c)) { + giterr_set(GITERR_SHA1, "SHA1 collision attack detected"); + return -1; + } + + return 0; +} + +#endif /* INCLUDE_hash_collisiondetect_h__ */ diff --git a/src/hash/sha1dc/sha1.c b/src/hash/sha1dc/sha1.c new file mode 100644 index 000000000..facea1bb5 --- /dev/null +++ b/src/hash/sha1dc/sha1.c @@ -0,0 +1,1856 @@ +/*** +* Copyright 2017 Marc Stevens , Dan Shumow (danshu@microsoft.com) +* Distributed under the MIT Software License. +* See accompanying file LICENSE.txt or copy at +* https://opensource.org/licenses/MIT +***/ + +#ifndef SHA1DC_NO_STANDARD_INCLUDES +#include +#include +#include +#include +#endif + +#ifdef SHA1DC_CUSTOM_INCLUDE_SHA1_C +#include SHA1DC_CUSTOM_INCLUDE_SHA1_C +#endif + +#ifndef SHA1DC_INIT_SAFE_HASH_DEFAULT +#define SHA1DC_INIT_SAFE_HASH_DEFAULT 1 +#endif + +#include "sha1.h" +#include "ubc_check.h" + + +/* + Because Little-Endian architectures are most common, + we only set SHA1DC_BIGENDIAN if one of these conditions is met. + Note that all MSFT platforms are little endian, + so none of these will be defined under the MSC compiler. + 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__)) ) +#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)) +#define SHA1DC_BIGENDIAN +#endif + +#endif + +#if (defined(SHA1DC_FORCE_LITTLEENDIAN) && defined(SHA1DC_BIGENDIAN)) +#undef SHA1DC_BIGENDIAN +#endif +#if (defined(SHA1DC_FORCE_BIGENDIAN) && !defined(SHA1DC_BIGENDIAN)) +#define SHA1DC_BIGENDIAN +#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)) + +#define SHA1DC_ALLOW_UNALIGNED_ACCESS + +#endif /*UNALIGNMENT DETECTION*/ + + +#define rotate_right(x,n) (((x)>>(n))|((x)<<(32-(n)))) +#define rotate_left(x,n) (((x)<<(n))|((x)>>(32-(n)))) + +#define sha1_bswap32(x) \ + {x = ((x << 8) & 0xFF00FF00) | ((x >> 8) & 0xFF00FF); x = (x << 16) | (x >> 16);} + +#define sha1_mix(W, t) (rotate_left(W[t - 3] ^ W[t - 8] ^ W[t - 14] ^ W[t - 16], 1)) + +#ifdef SHA1DC_BIGENDIAN + #define sha1_load(m, t, temp) { temp = m[t]; } +#else + #define sha1_load(m, t, temp) { temp = m[t]; sha1_bswap32(temp); } +#endif + +#define sha1_store(W, t, x) *(volatile uint32_t *)&W[t] = x + +#define sha1_f1(b,c,d) ((d)^((b)&((c)^(d)))) +#define sha1_f2(b,c,d) ((b)^(c)^(d)) +#define sha1_f3(b,c,d) (((b)&(c))+((d)&((b)^(c)))) +#define sha1_f4(b,c,d) ((b)^(c)^(d)) + +#define HASHCLASH_SHA1COMPRESS_ROUND1_STEP(a, b, c, d, e, m, t) \ + { e += rotate_left(a, 5) + sha1_f1(b,c,d) + 0x5A827999 + m[t]; b = rotate_left(b, 30); } +#define HASHCLASH_SHA1COMPRESS_ROUND2_STEP(a, b, c, d, e, m, t) \ + { e += rotate_left(a, 5) + sha1_f2(b,c,d) + 0x6ED9EBA1 + m[t]; b = rotate_left(b, 30); } +#define HASHCLASH_SHA1COMPRESS_ROUND3_STEP(a, b, c, d, e, m, t) \ + { e += rotate_left(a, 5) + sha1_f3(b,c,d) + 0x8F1BBCDC + m[t]; b = rotate_left(b, 30); } +#define HASHCLASH_SHA1COMPRESS_ROUND4_STEP(a, b, c, d, e, m, t) \ + { e += rotate_left(a, 5) + sha1_f4(b,c,d) + 0xCA62C1D6 + m[t]; b = rotate_left(b, 30); } + +#define HASHCLASH_SHA1COMPRESS_ROUND1_STEP_BW(a, b, c, d, e, m, t) \ + { b = rotate_right(b, 30); e -= rotate_left(a, 5) + sha1_f1(b,c,d) + 0x5A827999 + m[t]; } +#define HASHCLASH_SHA1COMPRESS_ROUND2_STEP_BW(a, b, c, d, e, m, t) \ + { b = rotate_right(b, 30); e -= rotate_left(a, 5) + sha1_f2(b,c,d) + 0x6ED9EBA1 + m[t]; } +#define HASHCLASH_SHA1COMPRESS_ROUND3_STEP_BW(a, b, c, d, e, m, t) \ + { b = rotate_right(b, 30); e -= rotate_left(a, 5) + sha1_f3(b,c,d) + 0x8F1BBCDC + m[t]; } +#define HASHCLASH_SHA1COMPRESS_ROUND4_STEP_BW(a, b, c, d, e, m, t) \ + { b = rotate_right(b, 30); e -= rotate_left(a, 5) + sha1_f4(b,c,d) + 0xCA62C1D6 + m[t]; } + +#define SHA1COMPRESS_FULL_ROUND1_STEP_LOAD(a, b, c, d, e, m, W, t, temp) \ + {sha1_load(m, t, temp); sha1_store(W, t, temp); e += temp + rotate_left(a, 5) + sha1_f1(b,c,d) + 0x5A827999; b = rotate_left(b, 30);} + +#define SHA1COMPRESS_FULL_ROUND1_STEP_EXPAND(a, b, c, d, e, W, t, temp) \ + {temp = sha1_mix(W, t); sha1_store(W, t, temp); e += temp + rotate_left(a, 5) + sha1_f1(b,c,d) + 0x5A827999; b = rotate_left(b, 30); } + +#define SHA1COMPRESS_FULL_ROUND2_STEP(a, b, c, d, e, W, t, temp) \ + {temp = sha1_mix(W, t); sha1_store(W, t, temp); e += temp + rotate_left(a, 5) + sha1_f2(b,c,d) + 0x6ED9EBA1; b = rotate_left(b, 30); } + +#define SHA1COMPRESS_FULL_ROUND3_STEP(a, b, c, d, e, W, t, temp) \ + {temp = sha1_mix(W, t); sha1_store(W, t, temp); e += temp + rotate_left(a, 5) + sha1_f3(b,c,d) + 0x8F1BBCDC; b = rotate_left(b, 30); } + +#define SHA1COMPRESS_FULL_ROUND4_STEP(a, b, c, d, e, W, t, temp) \ + {temp = sha1_mix(W, t); sha1_store(W, t, temp); e += temp + rotate_left(a, 5) + sha1_f4(b,c,d) + 0xCA62C1D6; b = rotate_left(b, 30); } + + +#define SHA1_STORE_STATE(i) states[i][0] = a; states[i][1] = b; states[i][2] = c; states[i][3] = d; states[i][4] = e; + +#ifdef BUILDNOCOLLDETECTSHA1COMPRESSION +void sha1_compression(uint32_t ihv[5], const uint32_t m[16]) +{ + uint32_t W[80]; + uint32_t a,b,c,d,e; + unsigned i; + + memcpy(W, m, 16 * 4); + for (i = 16; i < 80; ++i) + W[i] = sha1_mix(W, i); + + a = ihv[0]; b = ihv[1]; c = ihv[2]; d = ihv[3]; e = ihv[4]; + + HASHCLASH_SHA1COMPRESS_ROUND1_STEP(a, b, c, d, e, W, 0); + HASHCLASH_SHA1COMPRESS_ROUND1_STEP(e, a, b, c, d, W, 1); + HASHCLASH_SHA1COMPRESS_ROUND1_STEP(d, e, a, b, c, W, 2); + HASHCLASH_SHA1COMPRESS_ROUND1_STEP(c, d, e, a, b, W, 3); + HASHCLASH_SHA1COMPRESS_ROUND1_STEP(b, c, d, e, a, W, 4); + HASHCLASH_SHA1COMPRESS_ROUND1_STEP(a, b, c, d, e, W, 5); + HASHCLASH_SHA1COMPRESS_ROUND1_STEP(e, a, b, c, d, W, 6); + HASHCLASH_SHA1COMPRESS_ROUND1_STEP(d, e, a, b, c, W, 7); + HASHCLASH_SHA1COMPRESS_ROUND1_STEP(c, d, e, a, b, W, 8); + HASHCLASH_SHA1COMPRESS_ROUND1_STEP(b, c, d, e, a, W, 9); + HASHCLASH_SHA1COMPRESS_ROUND1_STEP(a, b, c, d, e, W, 10); + HASHCLASH_SHA1COMPRESS_ROUND1_STEP(e, a, b, c, d, W, 11); + HASHCLASH_SHA1COMPRESS_ROUND1_STEP(d, e, a, b, c, W, 12); + HASHCLASH_SHA1COMPRESS_ROUND1_STEP(c, d, e, a, b, W, 13); + HASHCLASH_SHA1COMPRESS_ROUND1_STEP(b, c, d, e, a, W, 14); + HASHCLASH_SHA1COMPRESS_ROUND1_STEP(a, b, c, d, e, W, 15); + HASHCLASH_SHA1COMPRESS_ROUND1_STEP(e, a, b, c, d, W, 16); + HASHCLASH_SHA1COMPRESS_ROUND1_STEP(d, e, a, b, c, W, 17); + HASHCLASH_SHA1COMPRESS_ROUND1_STEP(c, d, e, a, b, W, 18); + HASHCLASH_SHA1COMPRESS_ROUND1_STEP(b, c, d, e, a, W, 19); + + HASHCLASH_SHA1COMPRESS_ROUND2_STEP(a, b, c, d, e, W, 20); + HASHCLASH_SHA1COMPRESS_ROUND2_STEP(e, a, b, c, d, W, 21); + HASHCLASH_SHA1COMPRESS_ROUND2_STEP(d, e, a, b, c, W, 22); + HASHCLASH_SHA1COMPRESS_ROUND2_STEP(c, d, e, a, b, W, 23); + HASHCLASH_SHA1COMPRESS_ROUND2_STEP(b, c, d, e, a, W, 24); + HASHCLASH_SHA1COMPRESS_ROUND2_STEP(a, b, c, d, e, W, 25); + HASHCLASH_SHA1COMPRESS_ROUND2_STEP(e, a, b, c, d, W, 26); + HASHCLASH_SHA1COMPRESS_ROUND2_STEP(d, e, a, b, c, W, 27); + HASHCLASH_SHA1COMPRESS_ROUND2_STEP(c, d, e, a, b, W, 28); + HASHCLASH_SHA1COMPRESS_ROUND2_STEP(b, c, d, e, a, W, 29); + HASHCLASH_SHA1COMPRESS_ROUND2_STEP(a, b, c, d, e, W, 30); + HASHCLASH_SHA1COMPRESS_ROUND2_STEP(e, a, b, c, d, W, 31); + HASHCLASH_SHA1COMPRESS_ROUND2_STEP(d, e, a, b, c, W, 32); + HASHCLASH_SHA1COMPRESS_ROUND2_STEP(c, d, e, a, b, W, 33); + HASHCLASH_SHA1COMPRESS_ROUND2_STEP(b, c, d, e, a, W, 34); + HASHCLASH_SHA1COMPRESS_ROUND2_STEP(a, b, c, d, e, W, 35); + HASHCLASH_SHA1COMPRESS_ROUND2_STEP(e, a, b, c, d, W, 36); + HASHCLASH_SHA1COMPRESS_ROUND2_STEP(d, e, a, b, c, W, 37); + HASHCLASH_SHA1COMPRESS_ROUND2_STEP(c, d, e, a, b, W, 38); + HASHCLASH_SHA1COMPRESS_ROUND2_STEP(b, c, d, e, a, W, 39); + + HASHCLASH_SHA1COMPRESS_ROUND3_STEP(a, b, c, d, e, W, 40); + HASHCLASH_SHA1COMPRESS_ROUND3_STEP(e, a, b, c, d, W, 41); + HASHCLASH_SHA1COMPRESS_ROUND3_STEP(d, e, a, b, c, W, 42); + HASHCLASH_SHA1COMPRESS_ROUND3_STEP(c, d, e, a, b, W, 43); + HASHCLASH_SHA1COMPRESS_ROUND3_STEP(b, c, d, e, a, W, 44); + HASHCLASH_SHA1COMPRESS_ROUND3_STEP(a, b, c, d, e, W, 45); + HASHCLASH_SHA1COMPRESS_ROUND3_STEP(e, a, b, c, d, W, 46); + HASHCLASH_SHA1COMPRESS_ROUND3_STEP(d, e, a, b, c, W, 47); + HASHCLASH_SHA1COMPRESS_ROUND3_STEP(c, d, e, a, b, W, 48); + HASHCLASH_SHA1COMPRESS_ROUND3_STEP(b, c, d, e, a, W, 49); + HASHCLASH_SHA1COMPRESS_ROUND3_STEP(a, b, c, d, e, W, 50); + HASHCLASH_SHA1COMPRESS_ROUND3_STEP(e, a, b, c, d, W, 51); + HASHCLASH_SHA1COMPRESS_ROUND3_STEP(d, e, a, b, c, W, 52); + HASHCLASH_SHA1COMPRESS_ROUND3_STEP(c, d, e, a, b, W, 53); + HASHCLASH_SHA1COMPRESS_ROUND3_STEP(b, c, d, e, a, W, 54); + HASHCLASH_SHA1COMPRESS_ROUND3_STEP(a, b, c, d, e, W, 55); + HASHCLASH_SHA1COMPRESS_ROUND3_STEP(e, a, b, c, d, W, 56); + HASHCLASH_SHA1COMPRESS_ROUND3_STEP(d, e, a, b, c, W, 57); + HASHCLASH_SHA1COMPRESS_ROUND3_STEP(c, d, e, a, b, W, 58); + HASHCLASH_SHA1COMPRESS_ROUND3_STEP(b, c, d, e, a, W, 59); + + HASHCLASH_SHA1COMPRESS_ROUND4_STEP(a, b, c, d, e, W, 60); + HASHCLASH_SHA1COMPRESS_ROUND4_STEP(e, a, b, c, d, W, 61); + HASHCLASH_SHA1COMPRESS_ROUND4_STEP(d, e, a, b, c, W, 62); + HASHCLASH_SHA1COMPRESS_ROUND4_STEP(c, d, e, a, b, W, 63); + HASHCLASH_SHA1COMPRESS_ROUND4_STEP(b, c, d, e, a, W, 64); + HASHCLASH_SHA1COMPRESS_ROUND4_STEP(a, b, c, d, e, W, 65); + HASHCLASH_SHA1COMPRESS_ROUND4_STEP(e, a, b, c, d, W, 66); + HASHCLASH_SHA1COMPRESS_ROUND4_STEP(d, e, a, b, c, W, 67); + HASHCLASH_SHA1COMPRESS_ROUND4_STEP(c, d, e, a, b, W, 68); + HASHCLASH_SHA1COMPRESS_ROUND4_STEP(b, c, d, e, a, W, 69); + HASHCLASH_SHA1COMPRESS_ROUND4_STEP(a, b, c, d, e, W, 70); + HASHCLASH_SHA1COMPRESS_ROUND4_STEP(e, a, b, c, d, W, 71); + HASHCLASH_SHA1COMPRESS_ROUND4_STEP(d, e, a, b, c, W, 72); + HASHCLASH_SHA1COMPRESS_ROUND4_STEP(c, d, e, a, b, W, 73); + HASHCLASH_SHA1COMPRESS_ROUND4_STEP(b, c, d, e, a, W, 74); + HASHCLASH_SHA1COMPRESS_ROUND4_STEP(a, b, c, d, e, W, 75); + HASHCLASH_SHA1COMPRESS_ROUND4_STEP(e, a, b, c, d, W, 76); + HASHCLASH_SHA1COMPRESS_ROUND4_STEP(d, e, a, b, c, W, 77); + HASHCLASH_SHA1COMPRESS_ROUND4_STEP(c, d, e, a, b, W, 78); + HASHCLASH_SHA1COMPRESS_ROUND4_STEP(b, c, d, e, a, W, 79); + + ihv[0] += a; ihv[1] += b; ihv[2] += c; ihv[3] += d; ihv[4] += e; +} +#endif /*BUILDNOCOLLDETECTSHA1COMPRESSION*/ + + +static void sha1_compression_W(uint32_t ihv[5], const uint32_t W[80]) +{ + uint32_t a = ihv[0], b = ihv[1], c = ihv[2], d = ihv[3], e = ihv[4]; + + HASHCLASH_SHA1COMPRESS_ROUND1_STEP(a, b, c, d, e, W, 0); + HASHCLASH_SHA1COMPRESS_ROUND1_STEP(e, a, b, c, d, W, 1); + HASHCLASH_SHA1COMPRESS_ROUND1_STEP(d, e, a, b, c, W, 2); + HASHCLASH_SHA1COMPRESS_ROUND1_STEP(c, d, e, a, b, W, 3); + HASHCLASH_SHA1COMPRESS_ROUND1_STEP(b, c, d, e, a, W, 4); + HASHCLASH_SHA1COMPRESS_ROUND1_STEP(a, b, c, d, e, W, 5); + HASHCLASH_SHA1COMPRESS_ROUND1_STEP(e, a, b, c, d, W, 6); + HASHCLASH_SHA1COMPRESS_ROUND1_STEP(d, e, a, b, c, W, 7); + HASHCLASH_SHA1COMPRESS_ROUND1_STEP(c, d, e, a, b, W, 8); + HASHCLASH_SHA1COMPRESS_ROUND1_STEP(b, c, d, e, a, W, 9); + HASHCLASH_SHA1COMPRESS_ROUND1_STEP(a, b, c, d, e, W, 10); + HASHCLASH_SHA1COMPRESS_ROUND1_STEP(e, a, b, c, d, W, 11); + HASHCLASH_SHA1COMPRESS_ROUND1_STEP(d, e, a, b, c, W, 12); + HASHCLASH_SHA1COMPRESS_ROUND1_STEP(c, d, e, a, b, W, 13); + HASHCLASH_SHA1COMPRESS_ROUND1_STEP(b, c, d, e, a, W, 14); + HASHCLASH_SHA1COMPRESS_ROUND1_STEP(a, b, c, d, e, W, 15); + HASHCLASH_SHA1COMPRESS_ROUND1_STEP(e, a, b, c, d, W, 16); + HASHCLASH_SHA1COMPRESS_ROUND1_STEP(d, e, a, b, c, W, 17); + HASHCLASH_SHA1COMPRESS_ROUND1_STEP(c, d, e, a, b, W, 18); + HASHCLASH_SHA1COMPRESS_ROUND1_STEP(b, c, d, e, a, W, 19); + + HASHCLASH_SHA1COMPRESS_ROUND2_STEP(a, b, c, d, e, W, 20); + HASHCLASH_SHA1COMPRESS_ROUND2_STEP(e, a, b, c, d, W, 21); + HASHCLASH_SHA1COMPRESS_ROUND2_STEP(d, e, a, b, c, W, 22); + HASHCLASH_SHA1COMPRESS_ROUND2_STEP(c, d, e, a, b, W, 23); + HASHCLASH_SHA1COMPRESS_ROUND2_STEP(b, c, d, e, a, W, 24); + HASHCLASH_SHA1COMPRESS_ROUND2_STEP(a, b, c, d, e, W, 25); + HASHCLASH_SHA1COMPRESS_ROUND2_STEP(e, a, b, c, d, W, 26); + HASHCLASH_SHA1COMPRESS_ROUND2_STEP(d, e, a, b, c, W, 27); + HASHCLASH_SHA1COMPRESS_ROUND2_STEP(c, d, e, a, b, W, 28); + HASHCLASH_SHA1COMPRESS_ROUND2_STEP(b, c, d, e, a, W, 29); + HASHCLASH_SHA1COMPRESS_ROUND2_STEP(a, b, c, d, e, W, 30); + HASHCLASH_SHA1COMPRESS_ROUND2_STEP(e, a, b, c, d, W, 31); + HASHCLASH_SHA1COMPRESS_ROUND2_STEP(d, e, a, b, c, W, 32); + HASHCLASH_SHA1COMPRESS_ROUND2_STEP(c, d, e, a, b, W, 33); + HASHCLASH_SHA1COMPRESS_ROUND2_STEP(b, c, d, e, a, W, 34); + HASHCLASH_SHA1COMPRESS_ROUND2_STEP(a, b, c, d, e, W, 35); + HASHCLASH_SHA1COMPRESS_ROUND2_STEP(e, a, b, c, d, W, 36); + HASHCLASH_SHA1COMPRESS_ROUND2_STEP(d, e, a, b, c, W, 37); + HASHCLASH_SHA1COMPRESS_ROUND2_STEP(c, d, e, a, b, W, 38); + HASHCLASH_SHA1COMPRESS_ROUND2_STEP(b, c, d, e, a, W, 39); + + HASHCLASH_SHA1COMPRESS_ROUND3_STEP(a, b, c, d, e, W, 40); + HASHCLASH_SHA1COMPRESS_ROUND3_STEP(e, a, b, c, d, W, 41); + HASHCLASH_SHA1COMPRESS_ROUND3_STEP(d, e, a, b, c, W, 42); + HASHCLASH_SHA1COMPRESS_ROUND3_STEP(c, d, e, a, b, W, 43); + HASHCLASH_SHA1COMPRESS_ROUND3_STEP(b, c, d, e, a, W, 44); + HASHCLASH_SHA1COMPRESS_ROUND3_STEP(a, b, c, d, e, W, 45); + HASHCLASH_SHA1COMPRESS_ROUND3_STEP(e, a, b, c, d, W, 46); + HASHCLASH_SHA1COMPRESS_ROUND3_STEP(d, e, a, b, c, W, 47); + HASHCLASH_SHA1COMPRESS_ROUND3_STEP(c, d, e, a, b, W, 48); + HASHCLASH_SHA1COMPRESS_ROUND3_STEP(b, c, d, e, a, W, 49); + HASHCLASH_SHA1COMPRESS_ROUND3_STEP(a, b, c, d, e, W, 50); + HASHCLASH_SHA1COMPRESS_ROUND3_STEP(e, a, b, c, d, W, 51); + HASHCLASH_SHA1COMPRESS_ROUND3_STEP(d, e, a, b, c, W, 52); + HASHCLASH_SHA1COMPRESS_ROUND3_STEP(c, d, e, a, b, W, 53); + HASHCLASH_SHA1COMPRESS_ROUND3_STEP(b, c, d, e, a, W, 54); + HASHCLASH_SHA1COMPRESS_ROUND3_STEP(a, b, c, d, e, W, 55); + HASHCLASH_SHA1COMPRESS_ROUND3_STEP(e, a, b, c, d, W, 56); + HASHCLASH_SHA1COMPRESS_ROUND3_STEP(d, e, a, b, c, W, 57); + HASHCLASH_SHA1COMPRESS_ROUND3_STEP(c, d, e, a, b, W, 58); + HASHCLASH_SHA1COMPRESS_ROUND3_STEP(b, c, d, e, a, W, 59); + + HASHCLASH_SHA1COMPRESS_ROUND4_STEP(a, b, c, d, e, W, 60); + HASHCLASH_SHA1COMPRESS_ROUND4_STEP(e, a, b, c, d, W, 61); + HASHCLASH_SHA1COMPRESS_ROUND4_STEP(d, e, a, b, c, W, 62); + HASHCLASH_SHA1COMPRESS_ROUND4_STEP(c, d, e, a, b, W, 63); + HASHCLASH_SHA1COMPRESS_ROUND4_STEP(b, c, d, e, a, W, 64); + HASHCLASH_SHA1COMPRESS_ROUND4_STEP(a, b, c, d, e, W, 65); + HASHCLASH_SHA1COMPRESS_ROUND4_STEP(e, a, b, c, d, W, 66); + HASHCLASH_SHA1COMPRESS_ROUND4_STEP(d, e, a, b, c, W, 67); + HASHCLASH_SHA1COMPRESS_ROUND4_STEP(c, d, e, a, b, W, 68); + HASHCLASH_SHA1COMPRESS_ROUND4_STEP(b, c, d, e, a, W, 69); + HASHCLASH_SHA1COMPRESS_ROUND4_STEP(a, b, c, d, e, W, 70); + HASHCLASH_SHA1COMPRESS_ROUND4_STEP(e, a, b, c, d, W, 71); + HASHCLASH_SHA1COMPRESS_ROUND4_STEP(d, e, a, b, c, W, 72); + HASHCLASH_SHA1COMPRESS_ROUND4_STEP(c, d, e, a, b, W, 73); + HASHCLASH_SHA1COMPRESS_ROUND4_STEP(b, c, d, e, a, W, 74); + HASHCLASH_SHA1COMPRESS_ROUND4_STEP(a, b, c, d, e, W, 75); + HASHCLASH_SHA1COMPRESS_ROUND4_STEP(e, a, b, c, d, W, 76); + HASHCLASH_SHA1COMPRESS_ROUND4_STEP(d, e, a, b, c, W, 77); + HASHCLASH_SHA1COMPRESS_ROUND4_STEP(c, d, e, a, b, W, 78); + HASHCLASH_SHA1COMPRESS_ROUND4_STEP(b, c, d, e, a, W, 79); + + ihv[0] += a; ihv[1] += b; ihv[2] += c; ihv[3] += d; ihv[4] += e; +} + + + +void sha1_compression_states(uint32_t ihv[5], const uint32_t m[16], uint32_t W[80], uint32_t states[80][5]) +{ + uint32_t a = ihv[0], b = ihv[1], c = ihv[2], d = ihv[3], e = ihv[4]; + uint32_t temp; + +#ifdef DOSTORESTATE00 + SHA1_STORE_STATE(0) +#endif + SHA1COMPRESS_FULL_ROUND1_STEP_LOAD(a, b, c, d, e, m, W, 0, temp); + +#ifdef DOSTORESTATE01 + SHA1_STORE_STATE(1) +#endif + SHA1COMPRESS_FULL_ROUND1_STEP_LOAD(e, a, b, c, d, m, W, 1, temp); + +#ifdef DOSTORESTATE02 + SHA1_STORE_STATE(2) +#endif + SHA1COMPRESS_FULL_ROUND1_STEP_LOAD(d, e, a, b, c, m, W, 2, temp); + +#ifdef DOSTORESTATE03 + SHA1_STORE_STATE(3) +#endif + SHA1COMPRESS_FULL_ROUND1_STEP_LOAD(c, d, e, a, b, m, W, 3, temp); + +#ifdef DOSTORESTATE04 + SHA1_STORE_STATE(4) +#endif + SHA1COMPRESS_FULL_ROUND1_STEP_LOAD(b, c, d, e, a, m, W, 4, temp); + +#ifdef DOSTORESTATE05 + SHA1_STORE_STATE(5) +#endif + SHA1COMPRESS_FULL_ROUND1_STEP_LOAD(a, b, c, d, e, m, W, 5, temp); + +#ifdef DOSTORESTATE06 + SHA1_STORE_STATE(6) +#endif + SHA1COMPRESS_FULL_ROUND1_STEP_LOAD(e, a, b, c, d, m, W, 6, temp); + +#ifdef DOSTORESTATE07 + SHA1_STORE_STATE(7) +#endif + SHA1COMPRESS_FULL_ROUND1_STEP_LOAD(d, e, a, b, c, m, W, 7, temp); + +#ifdef DOSTORESTATE08 + SHA1_STORE_STATE(8) +#endif + SHA1COMPRESS_FULL_ROUND1_STEP_LOAD(c, d, e, a, b, m, W, 8, temp); + +#ifdef DOSTORESTATE09 + SHA1_STORE_STATE(9) +#endif + SHA1COMPRESS_FULL_ROUND1_STEP_LOAD(b, c, d, e, a, m, W, 9, temp); + +#ifdef DOSTORESTATE10 + SHA1_STORE_STATE(10) +#endif + SHA1COMPRESS_FULL_ROUND1_STEP_LOAD(a, b, c, d, e, m, W, 10, temp); + +#ifdef DOSTORESTATE11 + SHA1_STORE_STATE(11) +#endif + SHA1COMPRESS_FULL_ROUND1_STEP_LOAD(e, a, b, c, d, m, W, 11, temp); + +#ifdef DOSTORESTATE12 + SHA1_STORE_STATE(12) +#endif + SHA1COMPRESS_FULL_ROUND1_STEP_LOAD(d, e, a, b, c, m, W, 12, temp); + +#ifdef DOSTORESTATE13 + SHA1_STORE_STATE(13) +#endif + SHA1COMPRESS_FULL_ROUND1_STEP_LOAD(c, d, e, a, b, m, W, 13, temp); + +#ifdef DOSTORESTATE14 + SHA1_STORE_STATE(14) +#endif + SHA1COMPRESS_FULL_ROUND1_STEP_LOAD(b, c, d, e, a, m, W, 14, temp); + +#ifdef DOSTORESTATE15 + SHA1_STORE_STATE(15) +#endif + SHA1COMPRESS_FULL_ROUND1_STEP_LOAD(a, b, c, d, e, m, W, 15, temp); + +#ifdef DOSTORESTATE16 + SHA1_STORE_STATE(16) +#endif + SHA1COMPRESS_FULL_ROUND1_STEP_EXPAND(e, a, b, c, d, W, 16, temp); + +#ifdef DOSTORESTATE17 + SHA1_STORE_STATE(17) +#endif + SHA1COMPRESS_FULL_ROUND1_STEP_EXPAND(d, e, a, b, c, W, 17, temp); + +#ifdef DOSTORESTATE18 + SHA1_STORE_STATE(18) +#endif + SHA1COMPRESS_FULL_ROUND1_STEP_EXPAND(c, d, e, a, b, W, 18, temp); + +#ifdef DOSTORESTATE19 + SHA1_STORE_STATE(19) +#endif + SHA1COMPRESS_FULL_ROUND1_STEP_EXPAND(b, c, d, e, a, W, 19, temp); + + + +#ifdef DOSTORESTATE20 + SHA1_STORE_STATE(20) +#endif + SHA1COMPRESS_FULL_ROUND2_STEP(a, b, c, d, e, W, 20, temp); + +#ifdef DOSTORESTATE21 + SHA1_STORE_STATE(21) +#endif + SHA1COMPRESS_FULL_ROUND2_STEP(e, a, b, c, d, W, 21, temp); + +#ifdef DOSTORESTATE22 + SHA1_STORE_STATE(22) +#endif + SHA1COMPRESS_FULL_ROUND2_STEP(d, e, a, b, c, W, 22, temp); + +#ifdef DOSTORESTATE23 + SHA1_STORE_STATE(23) +#endif + SHA1COMPRESS_FULL_ROUND2_STEP(c, d, e, a, b, W, 23, temp); + +#ifdef DOSTORESTATE24 + SHA1_STORE_STATE(24) +#endif + SHA1COMPRESS_FULL_ROUND2_STEP(b, c, d, e, a, W, 24, temp); + +#ifdef DOSTORESTATE25 + SHA1_STORE_STATE(25) +#endif + SHA1COMPRESS_FULL_ROUND2_STEP(a, b, c, d, e, W, 25, temp); + +#ifdef DOSTORESTATE26 + SHA1_STORE_STATE(26) +#endif + SHA1COMPRESS_FULL_ROUND2_STEP(e, a, b, c, d, W, 26, temp); + +#ifdef DOSTORESTATE27 + SHA1_STORE_STATE(27) +#endif + SHA1COMPRESS_FULL_ROUND2_STEP(d, e, a, b, c, W, 27, temp); + +#ifdef DOSTORESTATE28 + SHA1_STORE_STATE(28) +#endif + SHA1COMPRESS_FULL_ROUND2_STEP(c, d, e, a, b, W, 28, temp); + +#ifdef DOSTORESTATE29 + SHA1_STORE_STATE(29) +#endif + SHA1COMPRESS_FULL_ROUND2_STEP(b, c, d, e, a, W, 29, temp); + +#ifdef DOSTORESTATE30 + SHA1_STORE_STATE(30) +#endif + SHA1COMPRESS_FULL_ROUND2_STEP(a, b, c, d, e, W, 30, temp); + +#ifdef DOSTORESTATE31 + SHA1_STORE_STATE(31) +#endif + SHA1COMPRESS_FULL_ROUND2_STEP(e, a, b, c, d, W, 31, temp); + +#ifdef DOSTORESTATE32 + SHA1_STORE_STATE(32) +#endif + SHA1COMPRESS_FULL_ROUND2_STEP(d, e, a, b, c, W, 32, temp); + +#ifdef DOSTORESTATE33 + SHA1_STORE_STATE(33) +#endif + SHA1COMPRESS_FULL_ROUND2_STEP(c, d, e, a, b, W, 33, temp); + +#ifdef DOSTORESTATE34 + SHA1_STORE_STATE(34) +#endif + SHA1COMPRESS_FULL_ROUND2_STEP(b, c, d, e, a, W, 34, temp); + +#ifdef DOSTORESTATE35 + SHA1_STORE_STATE(35) +#endif + SHA1COMPRESS_FULL_ROUND2_STEP(a, b, c, d, e, W, 35, temp); + +#ifdef DOSTORESTATE36 + SHA1_STORE_STATE(36) +#endif + SHA1COMPRESS_FULL_ROUND2_STEP(e, a, b, c, d, W, 36, temp); + +#ifdef DOSTORESTATE37 + SHA1_STORE_STATE(37) +#endif + SHA1COMPRESS_FULL_ROUND2_STEP(d, e, a, b, c, W, 37, temp); + +#ifdef DOSTORESTATE38 + SHA1_STORE_STATE(38) +#endif + SHA1COMPRESS_FULL_ROUND2_STEP(c, d, e, a, b, W, 38, temp); + +#ifdef DOSTORESTATE39 + SHA1_STORE_STATE(39) +#endif + SHA1COMPRESS_FULL_ROUND2_STEP(b, c, d, e, a, W, 39, temp); + + + +#ifdef DOSTORESTATE40 + SHA1_STORE_STATE(40) +#endif + SHA1COMPRESS_FULL_ROUND3_STEP(a, b, c, d, e, W, 40, temp); + +#ifdef DOSTORESTATE41 + SHA1_STORE_STATE(41) +#endif + SHA1COMPRESS_FULL_ROUND3_STEP(e, a, b, c, d, W, 41, temp); + +#ifdef DOSTORESTATE42 + SHA1_STORE_STATE(42) +#endif + SHA1COMPRESS_FULL_ROUND3_STEP(d, e, a, b, c, W, 42, temp); + +#ifdef DOSTORESTATE43 + SHA1_STORE_STATE(43) +#endif + SHA1COMPRESS_FULL_ROUND3_STEP(c, d, e, a, b, W, 43, temp); + +#ifdef DOSTORESTATE44 + SHA1_STORE_STATE(44) +#endif + SHA1COMPRESS_FULL_ROUND3_STEP(b, c, d, e, a, W, 44, temp); + +#ifdef DOSTORESTATE45 + SHA1_STORE_STATE(45) +#endif + SHA1COMPRESS_FULL_ROUND3_STEP(a, b, c, d, e, W, 45, temp); + +#ifdef DOSTORESTATE46 + SHA1_STORE_STATE(46) +#endif + SHA1COMPRESS_FULL_ROUND3_STEP(e, a, b, c, d, W, 46, temp); + +#ifdef DOSTORESTATE47 + SHA1_STORE_STATE(47) +#endif + SHA1COMPRESS_FULL_ROUND3_STEP(d, e, a, b, c, W, 47, temp); + +#ifdef DOSTORESTATE48 + SHA1_STORE_STATE(48) +#endif + SHA1COMPRESS_FULL_ROUND3_STEP(c, d, e, a, b, W, 48, temp); + +#ifdef DOSTORESTATE49 + SHA1_STORE_STATE(49) +#endif + SHA1COMPRESS_FULL_ROUND3_STEP(b, c, d, e, a, W, 49, temp); + +#ifdef DOSTORESTATE50 + SHA1_STORE_STATE(50) +#endif + SHA1COMPRESS_FULL_ROUND3_STEP(a, b, c, d, e, W, 50, temp); + +#ifdef DOSTORESTATE51 + SHA1_STORE_STATE(51) +#endif + SHA1COMPRESS_FULL_ROUND3_STEP(e, a, b, c, d, W, 51, temp); + +#ifdef DOSTORESTATE52 + SHA1_STORE_STATE(52) +#endif + SHA1COMPRESS_FULL_ROUND3_STEP(d, e, a, b, c, W, 52, temp); + +#ifdef DOSTORESTATE53 + SHA1_STORE_STATE(53) +#endif + SHA1COMPRESS_FULL_ROUND3_STEP(c, d, e, a, b, W, 53, temp); + +#ifdef DOSTORESTATE54 + SHA1_STORE_STATE(54) +#endif + SHA1COMPRESS_FULL_ROUND3_STEP(b, c, d, e, a, W, 54, temp); + +#ifdef DOSTORESTATE55 + SHA1_STORE_STATE(55) +#endif + SHA1COMPRESS_FULL_ROUND3_STEP(a, b, c, d, e, W, 55, temp); + +#ifdef DOSTORESTATE56 + SHA1_STORE_STATE(56) +#endif + SHA1COMPRESS_FULL_ROUND3_STEP(e, a, b, c, d, W, 56, temp); + +#ifdef DOSTORESTATE57 + SHA1_STORE_STATE(57) +#endif + SHA1COMPRESS_FULL_ROUND3_STEP(d, e, a, b, c, W, 57, temp); + +#ifdef DOSTORESTATE58 + SHA1_STORE_STATE(58) +#endif + SHA1COMPRESS_FULL_ROUND3_STEP(c, d, e, a, b, W, 58, temp); + +#ifdef DOSTORESTATE59 + SHA1_STORE_STATE(59) +#endif + SHA1COMPRESS_FULL_ROUND3_STEP(b, c, d, e, a, W, 59, temp); + + + + +#ifdef DOSTORESTATE60 + SHA1_STORE_STATE(60) +#endif + SHA1COMPRESS_FULL_ROUND4_STEP(a, b, c, d, e, W, 60, temp); + +#ifdef DOSTORESTATE61 + SHA1_STORE_STATE(61) +#endif + SHA1COMPRESS_FULL_ROUND4_STEP(e, a, b, c, d, W, 61, temp); + +#ifdef DOSTORESTATE62 + SHA1_STORE_STATE(62) +#endif + SHA1COMPRESS_FULL_ROUND4_STEP(d, e, a, b, c, W, 62, temp); + +#ifdef DOSTORESTATE63 + SHA1_STORE_STATE(63) +#endif + SHA1COMPRESS_FULL_ROUND4_STEP(c, d, e, a, b, W, 63, temp); + +#ifdef DOSTORESTATE64 + SHA1_STORE_STATE(64) +#endif + SHA1COMPRESS_FULL_ROUND4_STEP(b, c, d, e, a, W, 64, temp); + +#ifdef DOSTORESTATE65 + SHA1_STORE_STATE(65) +#endif + SHA1COMPRESS_FULL_ROUND4_STEP(a, b, c, d, e, W, 65, temp); + +#ifdef DOSTORESTATE66 + SHA1_STORE_STATE(66) +#endif + SHA1COMPRESS_FULL_ROUND4_STEP(e, a, b, c, d, W, 66, temp); + +#ifdef DOSTORESTATE67 + SHA1_STORE_STATE(67) +#endif + SHA1COMPRESS_FULL_ROUND4_STEP(d, e, a, b, c, W, 67, temp); + +#ifdef DOSTORESTATE68 + SHA1_STORE_STATE(68) +#endif + SHA1COMPRESS_FULL_ROUND4_STEP(c, d, e, a, b, W, 68, temp); + +#ifdef DOSTORESTATE69 + SHA1_STORE_STATE(69) +#endif + SHA1COMPRESS_FULL_ROUND4_STEP(b, c, d, e, a, W, 69, temp); + +#ifdef DOSTORESTATE70 + SHA1_STORE_STATE(70) +#endif + SHA1COMPRESS_FULL_ROUND4_STEP(a, b, c, d, e, W, 70, temp); + +#ifdef DOSTORESTATE71 + SHA1_STORE_STATE(71) +#endif + SHA1COMPRESS_FULL_ROUND4_STEP(e, a, b, c, d, W, 71, temp); + +#ifdef DOSTORESTATE72 + SHA1_STORE_STATE(72) +#endif + SHA1COMPRESS_FULL_ROUND4_STEP(d, e, a, b, c, W, 72, temp); + +#ifdef DOSTORESTATE73 + SHA1_STORE_STATE(73) +#endif + SHA1COMPRESS_FULL_ROUND4_STEP(c, d, e, a, b, W, 73, temp); + +#ifdef DOSTORESTATE74 + SHA1_STORE_STATE(74) +#endif + SHA1COMPRESS_FULL_ROUND4_STEP(b, c, d, e, a, W, 74, temp); + +#ifdef DOSTORESTATE75 + SHA1_STORE_STATE(75) +#endif + SHA1COMPRESS_FULL_ROUND4_STEP(a, b, c, d, e, W, 75, temp); + +#ifdef DOSTORESTATE76 + SHA1_STORE_STATE(76) +#endif + SHA1COMPRESS_FULL_ROUND4_STEP(e, a, b, c, d, W, 76, temp); + +#ifdef DOSTORESTATE77 + SHA1_STORE_STATE(77) +#endif + SHA1COMPRESS_FULL_ROUND4_STEP(d, e, a, b, c, W, 77, temp); + +#ifdef DOSTORESTATE78 + SHA1_STORE_STATE(78) +#endif + SHA1COMPRESS_FULL_ROUND4_STEP(c, d, e, a, b, W, 78, temp); + +#ifdef DOSTORESTATE79 + SHA1_STORE_STATE(79) +#endif + SHA1COMPRESS_FULL_ROUND4_STEP(b, c, d, e, a, W, 79, temp); + + + + ihv[0] += a; ihv[1] += b; ihv[2] += c; ihv[3] += d; ihv[4] += e; +} + + + + +#define SHA1_RECOMPRESS(t) \ +static void sha1recompress_fast_ ## t (uint32_t ihvin[5], uint32_t ihvout[5], const uint32_t me2[80], const uint32_t state[5]) \ +{ \ + uint32_t a = state[0], b = state[1], c = state[2], d = state[3], e = state[4]; \ + if (t > 79) HASHCLASH_SHA1COMPRESS_ROUND4_STEP_BW(b, c, d, e, a, me2, 79); \ + if (t > 78) HASHCLASH_SHA1COMPRESS_ROUND4_STEP_BW(c, d, e, a, b, me2, 78); \ + if (t > 77) HASHCLASH_SHA1COMPRESS_ROUND4_STEP_BW(d, e, a, b, c, me2, 77); \ + if (t > 76) HASHCLASH_SHA1COMPRESS_ROUND4_STEP_BW(e, a, b, c, d, me2, 76); \ + if (t > 75) HASHCLASH_SHA1COMPRESS_ROUND4_STEP_BW(a, b, c, d, e, me2, 75); \ + if (t > 74) HASHCLASH_SHA1COMPRESS_ROUND4_STEP_BW(b, c, d, e, a, me2, 74); \ + if (t > 73) HASHCLASH_SHA1COMPRESS_ROUND4_STEP_BW(c, d, e, a, b, me2, 73); \ + if (t > 72) HASHCLASH_SHA1COMPRESS_ROUND4_STEP_BW(d, e, a, b, c, me2, 72); \ + if (t > 71) HASHCLASH_SHA1COMPRESS_ROUND4_STEP_BW(e, a, b, c, d, me2, 71); \ + if (t > 70) HASHCLASH_SHA1COMPRESS_ROUND4_STEP_BW(a, b, c, d, e, me2, 70); \ + if (t > 69) HASHCLASH_SHA1COMPRESS_ROUND4_STEP_BW(b, c, d, e, a, me2, 69); \ + if (t > 68) HASHCLASH_SHA1COMPRESS_ROUND4_STEP_BW(c, d, e, a, b, me2, 68); \ + if (t > 67) HASHCLASH_SHA1COMPRESS_ROUND4_STEP_BW(d, e, a, b, c, me2, 67); \ + if (t > 66) HASHCLASH_SHA1COMPRESS_ROUND4_STEP_BW(e, a, b, c, d, me2, 66); \ + if (t > 65) HASHCLASH_SHA1COMPRESS_ROUND4_STEP_BW(a, b, c, d, e, me2, 65); \ + if (t > 64) HASHCLASH_SHA1COMPRESS_ROUND4_STEP_BW(b, c, d, e, a, me2, 64); \ + if (t > 63) HASHCLASH_SHA1COMPRESS_ROUND4_STEP_BW(c, d, e, a, b, me2, 63); \ + if (t > 62) HASHCLASH_SHA1COMPRESS_ROUND4_STEP_BW(d, e, a, b, c, me2, 62); \ + if (t > 61) HASHCLASH_SHA1COMPRESS_ROUND4_STEP_BW(e, a, b, c, d, me2, 61); \ + if (t > 60) HASHCLASH_SHA1COMPRESS_ROUND4_STEP_BW(a, b, c, d, e, me2, 60); \ + if (t > 59) HASHCLASH_SHA1COMPRESS_ROUND3_STEP_BW(b, c, d, e, a, me2, 59); \ + if (t > 58) HASHCLASH_SHA1COMPRESS_ROUND3_STEP_BW(c, d, e, a, b, me2, 58); \ + if (t > 57) HASHCLASH_SHA1COMPRESS_ROUND3_STEP_BW(d, e, a, b, c, me2, 57); \ + if (t > 56) HASHCLASH_SHA1COMPRESS_ROUND3_STEP_BW(e, a, b, c, d, me2, 56); \ + if (t > 55) HASHCLASH_SHA1COMPRESS_ROUND3_STEP_BW(a, b, c, d, e, me2, 55); \ + if (t > 54) HASHCLASH_SHA1COMPRESS_ROUND3_STEP_BW(b, c, d, e, a, me2, 54); \ + if (t > 53) HASHCLASH_SHA1COMPRESS_ROUND3_STEP_BW(c, d, e, a, b, me2, 53); \ + if (t > 52) HASHCLASH_SHA1COMPRESS_ROUND3_STEP_BW(d, e, a, b, c, me2, 52); \ + if (t > 51) HASHCLASH_SHA1COMPRESS_ROUND3_STEP_BW(e, a, b, c, d, me2, 51); \ + if (t > 50) HASHCLASH_SHA1COMPRESS_ROUND3_STEP_BW(a, b, c, d, e, me2, 50); \ + if (t > 49) HASHCLASH_SHA1COMPRESS_ROUND3_STEP_BW(b, c, d, e, a, me2, 49); \ + if (t > 48) HASHCLASH_SHA1COMPRESS_ROUND3_STEP_BW(c, d, e, a, b, me2, 48); \ + if (t > 47) HASHCLASH_SHA1COMPRESS_ROUND3_STEP_BW(d, e, a, b, c, me2, 47); \ + if (t > 46) HASHCLASH_SHA1COMPRESS_ROUND3_STEP_BW(e, a, b, c, d, me2, 46); \ + if (t > 45) HASHCLASH_SHA1COMPRESS_ROUND3_STEP_BW(a, b, c, d, e, me2, 45); \ + if (t > 44) HASHCLASH_SHA1COMPRESS_ROUND3_STEP_BW(b, c, d, e, a, me2, 44); \ + if (t > 43) HASHCLASH_SHA1COMPRESS_ROUND3_STEP_BW(c, d, e, a, b, me2, 43); \ + if (t > 42) HASHCLASH_SHA1COMPRESS_ROUND3_STEP_BW(d, e, a, b, c, me2, 42); \ + if (t > 41) HASHCLASH_SHA1COMPRESS_ROUND3_STEP_BW(e, a, b, c, d, me2, 41); \ + if (t > 40) HASHCLASH_SHA1COMPRESS_ROUND3_STEP_BW(a, b, c, d, e, me2, 40); \ + if (t > 39) HASHCLASH_SHA1COMPRESS_ROUND2_STEP_BW(b, c, d, e, a, me2, 39); \ + if (t > 38) HASHCLASH_SHA1COMPRESS_ROUND2_STEP_BW(c, d, e, a, b, me2, 38); \ + if (t > 37) HASHCLASH_SHA1COMPRESS_ROUND2_STEP_BW(d, e, a, b, c, me2, 37); \ + if (t > 36) HASHCLASH_SHA1COMPRESS_ROUND2_STEP_BW(e, a, b, c, d, me2, 36); \ + if (t > 35) HASHCLASH_SHA1COMPRESS_ROUND2_STEP_BW(a, b, c, d, e, me2, 35); \ + if (t > 34) HASHCLASH_SHA1COMPRESS_ROUND2_STEP_BW(b, c, d, e, a, me2, 34); \ + if (t > 33) HASHCLASH_SHA1COMPRESS_ROUND2_STEP_BW(c, d, e, a, b, me2, 33); \ + if (t > 32) HASHCLASH_SHA1COMPRESS_ROUND2_STEP_BW(d, e, a, b, c, me2, 32); \ + if (t > 31) HASHCLASH_SHA1COMPRESS_ROUND2_STEP_BW(e, a, b, c, d, me2, 31); \ + if (t > 30) HASHCLASH_SHA1COMPRESS_ROUND2_STEP_BW(a, b, c, d, e, me2, 30); \ + if (t > 29) HASHCLASH_SHA1COMPRESS_ROUND2_STEP_BW(b, c, d, e, a, me2, 29); \ + if (t > 28) HASHCLASH_SHA1COMPRESS_ROUND2_STEP_BW(c, d, e, a, b, me2, 28); \ + if (t > 27) HASHCLASH_SHA1COMPRESS_ROUND2_STEP_BW(d, e, a, b, c, me2, 27); \ + if (t > 26) HASHCLASH_SHA1COMPRESS_ROUND2_STEP_BW(e, a, b, c, d, me2, 26); \ + if (t > 25) HASHCLASH_SHA1COMPRESS_ROUND2_STEP_BW(a, b, c, d, e, me2, 25); \ + if (t > 24) HASHCLASH_SHA1COMPRESS_ROUND2_STEP_BW(b, c, d, e, a, me2, 24); \ + if (t > 23) HASHCLASH_SHA1COMPRESS_ROUND2_STEP_BW(c, d, e, a, b, me2, 23); \ + if (t > 22) HASHCLASH_SHA1COMPRESS_ROUND2_STEP_BW(d, e, a, b, c, me2, 22); \ + if (t > 21) HASHCLASH_SHA1COMPRESS_ROUND2_STEP_BW(e, a, b, c, d, me2, 21); \ + if (t > 20) HASHCLASH_SHA1COMPRESS_ROUND2_STEP_BW(a, b, c, d, e, me2, 20); \ + if (t > 19) HASHCLASH_SHA1COMPRESS_ROUND1_STEP_BW(b, c, d, e, a, me2, 19); \ + if (t > 18) HASHCLASH_SHA1COMPRESS_ROUND1_STEP_BW(c, d, e, a, b, me2, 18); \ + if (t > 17) HASHCLASH_SHA1COMPRESS_ROUND1_STEP_BW(d, e, a, b, c, me2, 17); \ + if (t > 16) HASHCLASH_SHA1COMPRESS_ROUND1_STEP_BW(e, a, b, c, d, me2, 16); \ + if (t > 15) HASHCLASH_SHA1COMPRESS_ROUND1_STEP_BW(a, b, c, d, e, me2, 15); \ + if (t > 14) HASHCLASH_SHA1COMPRESS_ROUND1_STEP_BW(b, c, d, e, a, me2, 14); \ + if (t > 13) HASHCLASH_SHA1COMPRESS_ROUND1_STEP_BW(c, d, e, a, b, me2, 13); \ + if (t > 12) HASHCLASH_SHA1COMPRESS_ROUND1_STEP_BW(d, e, a, b, c, me2, 12); \ + if (t > 11) HASHCLASH_SHA1COMPRESS_ROUND1_STEP_BW(e, a, b, c, d, me2, 11); \ + if (t > 10) HASHCLASH_SHA1COMPRESS_ROUND1_STEP_BW(a, b, c, d, e, me2, 10); \ + if (t > 9) HASHCLASH_SHA1COMPRESS_ROUND1_STEP_BW(b, c, d, e, a, me2, 9); \ + if (t > 8) HASHCLASH_SHA1COMPRESS_ROUND1_STEP_BW(c, d, e, a, b, me2, 8); \ + if (t > 7) HASHCLASH_SHA1COMPRESS_ROUND1_STEP_BW(d, e, a, b, c, me2, 7); \ + if (t > 6) HASHCLASH_SHA1COMPRESS_ROUND1_STEP_BW(e, a, b, c, d, me2, 6); \ + if (t > 5) HASHCLASH_SHA1COMPRESS_ROUND1_STEP_BW(a, b, c, d, e, me2, 5); \ + if (t > 4) HASHCLASH_SHA1COMPRESS_ROUND1_STEP_BW(b, c, d, e, a, me2, 4); \ + if (t > 3) HASHCLASH_SHA1COMPRESS_ROUND1_STEP_BW(c, d, e, a, b, me2, 3); \ + if (t > 2) HASHCLASH_SHA1COMPRESS_ROUND1_STEP_BW(d, e, a, b, c, me2, 2); \ + if (t > 1) HASHCLASH_SHA1COMPRESS_ROUND1_STEP_BW(e, a, b, c, d, me2, 1); \ + if (t > 0) HASHCLASH_SHA1COMPRESS_ROUND1_STEP_BW(a, b, c, d, e, me2, 0); \ + ihvin[0] = a; ihvin[1] = b; ihvin[2] = c; ihvin[3] = d; ihvin[4] = e; \ + a = state[0]; b = state[1]; c = state[2]; d = state[3]; e = state[4]; \ + if (t <= 0) HASHCLASH_SHA1COMPRESS_ROUND1_STEP(a, b, c, d, e, me2, 0); \ + if (t <= 1) HASHCLASH_SHA1COMPRESS_ROUND1_STEP(e, a, b, c, d, me2, 1); \ + if (t <= 2) HASHCLASH_SHA1COMPRESS_ROUND1_STEP(d, e, a, b, c, me2, 2); \ + if (t <= 3) HASHCLASH_SHA1COMPRESS_ROUND1_STEP(c, d, e, a, b, me2, 3); \ + if (t <= 4) HASHCLASH_SHA1COMPRESS_ROUND1_STEP(b, c, d, e, a, me2, 4); \ + if (t <= 5) HASHCLASH_SHA1COMPRESS_ROUND1_STEP(a, b, c, d, e, me2, 5); \ + if (t <= 6) HASHCLASH_SHA1COMPRESS_ROUND1_STEP(e, a, b, c, d, me2, 6); \ + if (t <= 7) HASHCLASH_SHA1COMPRESS_ROUND1_STEP(d, e, a, b, c, me2, 7); \ + if (t <= 8) HASHCLASH_SHA1COMPRESS_ROUND1_STEP(c, d, e, a, b, me2, 8); \ + if (t <= 9) HASHCLASH_SHA1COMPRESS_ROUND1_STEP(b, c, d, e, a, me2, 9); \ + if (t <= 10) HASHCLASH_SHA1COMPRESS_ROUND1_STEP(a, b, c, d, e, me2, 10); \ + if (t <= 11) HASHCLASH_SHA1COMPRESS_ROUND1_STEP(e, a, b, c, d, me2, 11); \ + if (t <= 12) HASHCLASH_SHA1COMPRESS_ROUND1_STEP(d, e, a, b, c, me2, 12); \ + if (t <= 13) HASHCLASH_SHA1COMPRESS_ROUND1_STEP(c, d, e, a, b, me2, 13); \ + if (t <= 14) HASHCLASH_SHA1COMPRESS_ROUND1_STEP(b, c, d, e, a, me2, 14); \ + if (t <= 15) HASHCLASH_SHA1COMPRESS_ROUND1_STEP(a, b, c, d, e, me2, 15); \ + if (t <= 16) HASHCLASH_SHA1COMPRESS_ROUND1_STEP(e, a, b, c, d, me2, 16); \ + if (t <= 17) HASHCLASH_SHA1COMPRESS_ROUND1_STEP(d, e, a, b, c, me2, 17); \ + if (t <= 18) HASHCLASH_SHA1COMPRESS_ROUND1_STEP(c, d, e, a, b, me2, 18); \ + if (t <= 19) HASHCLASH_SHA1COMPRESS_ROUND1_STEP(b, c, d, e, a, me2, 19); \ + if (t <= 20) HASHCLASH_SHA1COMPRESS_ROUND2_STEP(a, b, c, d, e, me2, 20); \ + if (t <= 21) HASHCLASH_SHA1COMPRESS_ROUND2_STEP(e, a, b, c, d, me2, 21); \ + if (t <= 22) HASHCLASH_SHA1COMPRESS_ROUND2_STEP(d, e, a, b, c, me2, 22); \ + if (t <= 23) HASHCLASH_SHA1COMPRESS_ROUND2_STEP(c, d, e, a, b, me2, 23); \ + if (t <= 24) HASHCLASH_SHA1COMPRESS_ROUND2_STEP(b, c, d, e, a, me2, 24); \ + if (t <= 25) HASHCLASH_SHA1COMPRESS_ROUND2_STEP(a, b, c, d, e, me2, 25); \ + if (t <= 26) HASHCLASH_SHA1COMPRESS_ROUND2_STEP(e, a, b, c, d, me2, 26); \ + if (t <= 27) HASHCLASH_SHA1COMPRESS_ROUND2_STEP(d, e, a, b, c, me2, 27); \ + if (t <= 28) HASHCLASH_SHA1COMPRESS_ROUND2_STEP(c, d, e, a, b, me2, 28); \ + if (t <= 29) HASHCLASH_SHA1COMPRESS_ROUND2_STEP(b, c, d, e, a, me2, 29); \ + if (t <= 30) HASHCLASH_SHA1COMPRESS_ROUND2_STEP(a, b, c, d, e, me2, 30); \ + if (t <= 31) HASHCLASH_SHA1COMPRESS_ROUND2_STEP(e, a, b, c, d, me2, 31); \ + if (t <= 32) HASHCLASH_SHA1COMPRESS_ROUND2_STEP(d, e, a, b, c, me2, 32); \ + if (t <= 33) HASHCLASH_SHA1COMPRESS_ROUND2_STEP(c, d, e, a, b, me2, 33); \ + if (t <= 34) HASHCLASH_SHA1COMPRESS_ROUND2_STEP(b, c, d, e, a, me2, 34); \ + if (t <= 35) HASHCLASH_SHA1COMPRESS_ROUND2_STEP(a, b, c, d, e, me2, 35); \ + if (t <= 36) HASHCLASH_SHA1COMPRESS_ROUND2_STEP(e, a, b, c, d, me2, 36); \ + if (t <= 37) HASHCLASH_SHA1COMPRESS_ROUND2_STEP(d, e, a, b, c, me2, 37); \ + if (t <= 38) HASHCLASH_SHA1COMPRESS_ROUND2_STEP(c, d, e, a, b, me2, 38); \ + if (t <= 39) HASHCLASH_SHA1COMPRESS_ROUND2_STEP(b, c, d, e, a, me2, 39); \ + if (t <= 40) HASHCLASH_SHA1COMPRESS_ROUND3_STEP(a, b, c, d, e, me2, 40); \ + if (t <= 41) HASHCLASH_SHA1COMPRESS_ROUND3_STEP(e, a, b, c, d, me2, 41); \ + if (t <= 42) HASHCLASH_SHA1COMPRESS_ROUND3_STEP(d, e, a, b, c, me2, 42); \ + if (t <= 43) HASHCLASH_SHA1COMPRESS_ROUND3_STEP(c, d, e, a, b, me2, 43); \ + if (t <= 44) HASHCLASH_SHA1COMPRESS_ROUND3_STEP(b, c, d, e, a, me2, 44); \ + if (t <= 45) HASHCLASH_SHA1COMPRESS_ROUND3_STEP(a, b, c, d, e, me2, 45); \ + if (t <= 46) HASHCLASH_SHA1COMPRESS_ROUND3_STEP(e, a, b, c, d, me2, 46); \ + if (t <= 47) HASHCLASH_SHA1COMPRESS_ROUND3_STEP(d, e, a, b, c, me2, 47); \ + if (t <= 48) HASHCLASH_SHA1COMPRESS_ROUND3_STEP(c, d, e, a, b, me2, 48); \ + if (t <= 49) HASHCLASH_SHA1COMPRESS_ROUND3_STEP(b, c, d, e, a, me2, 49); \ + if (t <= 50) HASHCLASH_SHA1COMPRESS_ROUND3_STEP(a, b, c, d, e, me2, 50); \ + if (t <= 51) HASHCLASH_SHA1COMPRESS_ROUND3_STEP(e, a, b, c, d, me2, 51); \ + if (t <= 52) HASHCLASH_SHA1COMPRESS_ROUND3_STEP(d, e, a, b, c, me2, 52); \ + if (t <= 53) HASHCLASH_SHA1COMPRESS_ROUND3_STEP(c, d, e, a, b, me2, 53); \ + if (t <= 54) HASHCLASH_SHA1COMPRESS_ROUND3_STEP(b, c, d, e, a, me2, 54); \ + if (t <= 55) HASHCLASH_SHA1COMPRESS_ROUND3_STEP(a, b, c, d, e, me2, 55); \ + if (t <= 56) HASHCLASH_SHA1COMPRESS_ROUND3_STEP(e, a, b, c, d, me2, 56); \ + if (t <= 57) HASHCLASH_SHA1COMPRESS_ROUND3_STEP(d, e, a, b, c, me2, 57); \ + if (t <= 58) HASHCLASH_SHA1COMPRESS_ROUND3_STEP(c, d, e, a, b, me2, 58); \ + if (t <= 59) HASHCLASH_SHA1COMPRESS_ROUND3_STEP(b, c, d, e, a, me2, 59); \ + if (t <= 60) HASHCLASH_SHA1COMPRESS_ROUND4_STEP(a, b, c, d, e, me2, 60); \ + if (t <= 61) HASHCLASH_SHA1COMPRESS_ROUND4_STEP(e, a, b, c, d, me2, 61); \ + if (t <= 62) HASHCLASH_SHA1COMPRESS_ROUND4_STEP(d, e, a, b, c, me2, 62); \ + if (t <= 63) HASHCLASH_SHA1COMPRESS_ROUND4_STEP(c, d, e, a, b, me2, 63); \ + if (t <= 64) HASHCLASH_SHA1COMPRESS_ROUND4_STEP(b, c, d, e, a, me2, 64); \ + if (t <= 65) HASHCLASH_SHA1COMPRESS_ROUND4_STEP(a, b, c, d, e, me2, 65); \ + if (t <= 66) HASHCLASH_SHA1COMPRESS_ROUND4_STEP(e, a, b, c, d, me2, 66); \ + if (t <= 67) HASHCLASH_SHA1COMPRESS_ROUND4_STEP(d, e, a, b, c, me2, 67); \ + if (t <= 68) HASHCLASH_SHA1COMPRESS_ROUND4_STEP(c, d, e, a, b, me2, 68); \ + if (t <= 69) HASHCLASH_SHA1COMPRESS_ROUND4_STEP(b, c, d, e, a, me2, 69); \ + if (t <= 70) HASHCLASH_SHA1COMPRESS_ROUND4_STEP(a, b, c, d, e, me2, 70); \ + if (t <= 71) HASHCLASH_SHA1COMPRESS_ROUND4_STEP(e, a, b, c, d, me2, 71); \ + if (t <= 72) HASHCLASH_SHA1COMPRESS_ROUND4_STEP(d, e, a, b, c, me2, 72); \ + if (t <= 73) HASHCLASH_SHA1COMPRESS_ROUND4_STEP(c, d, e, a, b, me2, 73); \ + if (t <= 74) HASHCLASH_SHA1COMPRESS_ROUND4_STEP(b, c, d, e, a, me2, 74); \ + if (t <= 75) HASHCLASH_SHA1COMPRESS_ROUND4_STEP(a, b, c, d, e, me2, 75); \ + if (t <= 76) HASHCLASH_SHA1COMPRESS_ROUND4_STEP(e, a, b, c, d, me2, 76); \ + if (t <= 77) HASHCLASH_SHA1COMPRESS_ROUND4_STEP(d, e, a, b, c, me2, 77); \ + if (t <= 78) HASHCLASH_SHA1COMPRESS_ROUND4_STEP(c, d, e, a, b, me2, 78); \ + if (t <= 79) HASHCLASH_SHA1COMPRESS_ROUND4_STEP(b, c, d, e, a, me2, 79); \ + ihvout[0] = ihvin[0] + a; ihvout[1] = ihvin[1] + b; ihvout[2] = ihvin[2] + c; ihvout[3] = ihvin[3] + d; ihvout[4] = ihvin[4] + e; \ +} + +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable: 4127) /* Complier complains about the checks in the above macro being constant. */ +#endif + +#ifdef DOSTORESTATE0 +SHA1_RECOMPRESS(0) +#endif + +#ifdef DOSTORESTATE1 +SHA1_RECOMPRESS(1) +#endif + +#ifdef DOSTORESTATE2 +SHA1_RECOMPRESS(2) +#endif + +#ifdef DOSTORESTATE3 +SHA1_RECOMPRESS(3) +#endif + +#ifdef DOSTORESTATE4 +SHA1_RECOMPRESS(4) +#endif + +#ifdef DOSTORESTATE5 +SHA1_RECOMPRESS(5) +#endif + +#ifdef DOSTORESTATE6 +SHA1_RECOMPRESS(6) +#endif + +#ifdef DOSTORESTATE7 +SHA1_RECOMPRESS(7) +#endif + +#ifdef DOSTORESTATE8 +SHA1_RECOMPRESS(8) +#endif + +#ifdef DOSTORESTATE9 +SHA1_RECOMPRESS(9) +#endif + +#ifdef DOSTORESTATE10 +SHA1_RECOMPRESS(10) +#endif + +#ifdef DOSTORESTATE11 +SHA1_RECOMPRESS(11) +#endif + +#ifdef DOSTORESTATE12 +SHA1_RECOMPRESS(12) +#endif + +#ifdef DOSTORESTATE13 +SHA1_RECOMPRESS(13) +#endif + +#ifdef DOSTORESTATE14 +SHA1_RECOMPRESS(14) +#endif + +#ifdef DOSTORESTATE15 +SHA1_RECOMPRESS(15) +#endif + +#ifdef DOSTORESTATE16 +SHA1_RECOMPRESS(16) +#endif + +#ifdef DOSTORESTATE17 +SHA1_RECOMPRESS(17) +#endif + +#ifdef DOSTORESTATE18 +SHA1_RECOMPRESS(18) +#endif + +#ifdef DOSTORESTATE19 +SHA1_RECOMPRESS(19) +#endif + +#ifdef DOSTORESTATE20 +SHA1_RECOMPRESS(20) +#endif + +#ifdef DOSTORESTATE21 +SHA1_RECOMPRESS(21) +#endif + +#ifdef DOSTORESTATE22 +SHA1_RECOMPRESS(22) +#endif + +#ifdef DOSTORESTATE23 +SHA1_RECOMPRESS(23) +#endif + +#ifdef DOSTORESTATE24 +SHA1_RECOMPRESS(24) +#endif + +#ifdef DOSTORESTATE25 +SHA1_RECOMPRESS(25) +#endif + +#ifdef DOSTORESTATE26 +SHA1_RECOMPRESS(26) +#endif + +#ifdef DOSTORESTATE27 +SHA1_RECOMPRESS(27) +#endif + +#ifdef DOSTORESTATE28 +SHA1_RECOMPRESS(28) +#endif + +#ifdef DOSTORESTATE29 +SHA1_RECOMPRESS(29) +#endif + +#ifdef DOSTORESTATE30 +SHA1_RECOMPRESS(30) +#endif + +#ifdef DOSTORESTATE31 +SHA1_RECOMPRESS(31) +#endif + +#ifdef DOSTORESTATE32 +SHA1_RECOMPRESS(32) +#endif + +#ifdef DOSTORESTATE33 +SHA1_RECOMPRESS(33) +#endif + +#ifdef DOSTORESTATE34 +SHA1_RECOMPRESS(34) +#endif + +#ifdef DOSTORESTATE35 +SHA1_RECOMPRESS(35) +#endif + +#ifdef DOSTORESTATE36 +SHA1_RECOMPRESS(36) +#endif + +#ifdef DOSTORESTATE37 +SHA1_RECOMPRESS(37) +#endif + +#ifdef DOSTORESTATE38 +SHA1_RECOMPRESS(38) +#endif + +#ifdef DOSTORESTATE39 +SHA1_RECOMPRESS(39) +#endif + +#ifdef DOSTORESTATE40 +SHA1_RECOMPRESS(40) +#endif + +#ifdef DOSTORESTATE41 +SHA1_RECOMPRESS(41) +#endif + +#ifdef DOSTORESTATE42 +SHA1_RECOMPRESS(42) +#endif + +#ifdef DOSTORESTATE43 +SHA1_RECOMPRESS(43) +#endif + +#ifdef DOSTORESTATE44 +SHA1_RECOMPRESS(44) +#endif + +#ifdef DOSTORESTATE45 +SHA1_RECOMPRESS(45) +#endif + +#ifdef DOSTORESTATE46 +SHA1_RECOMPRESS(46) +#endif + +#ifdef DOSTORESTATE47 +SHA1_RECOMPRESS(47) +#endif + +#ifdef DOSTORESTATE48 +SHA1_RECOMPRESS(48) +#endif + +#ifdef DOSTORESTATE49 +SHA1_RECOMPRESS(49) +#endif + +#ifdef DOSTORESTATE50 +SHA1_RECOMPRESS(50) +#endif + +#ifdef DOSTORESTATE51 +SHA1_RECOMPRESS(51) +#endif + +#ifdef DOSTORESTATE52 +SHA1_RECOMPRESS(52) +#endif + +#ifdef DOSTORESTATE53 +SHA1_RECOMPRESS(53) +#endif + +#ifdef DOSTORESTATE54 +SHA1_RECOMPRESS(54) +#endif + +#ifdef DOSTORESTATE55 +SHA1_RECOMPRESS(55) +#endif + +#ifdef DOSTORESTATE56 +SHA1_RECOMPRESS(56) +#endif + +#ifdef DOSTORESTATE57 +SHA1_RECOMPRESS(57) +#endif + +#ifdef DOSTORESTATE58 +SHA1_RECOMPRESS(58) +#endif + +#ifdef DOSTORESTATE59 +SHA1_RECOMPRESS(59) +#endif + +#ifdef DOSTORESTATE60 +SHA1_RECOMPRESS(60) +#endif + +#ifdef DOSTORESTATE61 +SHA1_RECOMPRESS(61) +#endif + +#ifdef DOSTORESTATE62 +SHA1_RECOMPRESS(62) +#endif + +#ifdef DOSTORESTATE63 +SHA1_RECOMPRESS(63) +#endif + +#ifdef DOSTORESTATE64 +SHA1_RECOMPRESS(64) +#endif + +#ifdef DOSTORESTATE65 +SHA1_RECOMPRESS(65) +#endif + +#ifdef DOSTORESTATE66 +SHA1_RECOMPRESS(66) +#endif + +#ifdef DOSTORESTATE67 +SHA1_RECOMPRESS(67) +#endif + +#ifdef DOSTORESTATE68 +SHA1_RECOMPRESS(68) +#endif + +#ifdef DOSTORESTATE69 +SHA1_RECOMPRESS(69) +#endif + +#ifdef DOSTORESTATE70 +SHA1_RECOMPRESS(70) +#endif + +#ifdef DOSTORESTATE71 +SHA1_RECOMPRESS(71) +#endif + +#ifdef DOSTORESTATE72 +SHA1_RECOMPRESS(72) +#endif + +#ifdef DOSTORESTATE73 +SHA1_RECOMPRESS(73) +#endif + +#ifdef DOSTORESTATE74 +SHA1_RECOMPRESS(74) +#endif + +#ifdef DOSTORESTATE75 +SHA1_RECOMPRESS(75) +#endif + +#ifdef DOSTORESTATE76 +SHA1_RECOMPRESS(76) +#endif + +#ifdef DOSTORESTATE77 +SHA1_RECOMPRESS(77) +#endif + +#ifdef DOSTORESTATE78 +SHA1_RECOMPRESS(78) +#endif + +#ifdef DOSTORESTATE79 +SHA1_RECOMPRESS(79) +#endif + +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +static void sha1_recompression_step(uint32_t step, uint32_t ihvin[5], uint32_t ihvout[5], const uint32_t me2[80], const uint32_t state[5]) +{ + switch (step) + { +#ifdef DOSTORESTATE0 + case 0: + sha1recompress_fast_0(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE1 + case 1: + sha1recompress_fast_1(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE2 + case 2: + sha1recompress_fast_2(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE3 + case 3: + sha1recompress_fast_3(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE4 + case 4: + sha1recompress_fast_4(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE5 + case 5: + sha1recompress_fast_5(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE6 + case 6: + sha1recompress_fast_6(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE7 + case 7: + sha1recompress_fast_7(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE8 + case 8: + sha1recompress_fast_8(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE9 + case 9: + sha1recompress_fast_9(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE10 + case 10: + sha1recompress_fast_10(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE11 + case 11: + sha1recompress_fast_11(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE12 + case 12: + sha1recompress_fast_12(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE13 + case 13: + sha1recompress_fast_13(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE14 + case 14: + sha1recompress_fast_14(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE15 + case 15: + sha1recompress_fast_15(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE16 + case 16: + sha1recompress_fast_16(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE17 + case 17: + sha1recompress_fast_17(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE18 + case 18: + sha1recompress_fast_18(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE19 + case 19: + sha1recompress_fast_19(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE20 + case 20: + sha1recompress_fast_20(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE21 + case 21: + sha1recompress_fast_21(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE22 + case 22: + sha1recompress_fast_22(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE23 + case 23: + sha1recompress_fast_23(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE24 + case 24: + sha1recompress_fast_24(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE25 + case 25: + sha1recompress_fast_25(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE26 + case 26: + sha1recompress_fast_26(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE27 + case 27: + sha1recompress_fast_27(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE28 + case 28: + sha1recompress_fast_28(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE29 + case 29: + sha1recompress_fast_29(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE30 + case 30: + sha1recompress_fast_30(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE31 + case 31: + sha1recompress_fast_31(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE32 + case 32: + sha1recompress_fast_32(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE33 + case 33: + sha1recompress_fast_33(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE34 + case 34: + sha1recompress_fast_34(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE35 + case 35: + sha1recompress_fast_35(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE36 + case 36: + sha1recompress_fast_36(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE37 + case 37: + sha1recompress_fast_37(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE38 + case 38: + sha1recompress_fast_38(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE39 + case 39: + sha1recompress_fast_39(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE40 + case 40: + sha1recompress_fast_40(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE41 + case 41: + sha1recompress_fast_41(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE42 + case 42: + sha1recompress_fast_42(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE43 + case 43: + sha1recompress_fast_43(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE44 + case 44: + sha1recompress_fast_44(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE45 + case 45: + sha1recompress_fast_45(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE46 + case 46: + sha1recompress_fast_46(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE47 + case 47: + sha1recompress_fast_47(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE48 + case 48: + sha1recompress_fast_48(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE49 + case 49: + sha1recompress_fast_49(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE50 + case 50: + sha1recompress_fast_50(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE51 + case 51: + sha1recompress_fast_51(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE52 + case 52: + sha1recompress_fast_52(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE53 + case 53: + sha1recompress_fast_53(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE54 + case 54: + sha1recompress_fast_54(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE55 + case 55: + sha1recompress_fast_55(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE56 + case 56: + sha1recompress_fast_56(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE57 + case 57: + sha1recompress_fast_57(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE58 + case 58: + sha1recompress_fast_58(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE59 + case 59: + sha1recompress_fast_59(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE60 + case 60: + sha1recompress_fast_60(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE61 + case 61: + sha1recompress_fast_61(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE62 + case 62: + sha1recompress_fast_62(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE63 + case 63: + sha1recompress_fast_63(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE64 + case 64: + sha1recompress_fast_64(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE65 + case 65: + sha1recompress_fast_65(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE66 + case 66: + sha1recompress_fast_66(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE67 + case 67: + sha1recompress_fast_67(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE68 + case 68: + sha1recompress_fast_68(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE69 + case 69: + sha1recompress_fast_69(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE70 + case 70: + sha1recompress_fast_70(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE71 + case 71: + sha1recompress_fast_71(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE72 + case 72: + sha1recompress_fast_72(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE73 + case 73: + sha1recompress_fast_73(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE74 + case 74: + sha1recompress_fast_74(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE75 + case 75: + sha1recompress_fast_75(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE76 + case 76: + sha1recompress_fast_76(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE77 + case 77: + sha1recompress_fast_77(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE78 + case 78: + sha1recompress_fast_78(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE79 + case 79: + sha1recompress_fast_79(ihvin, ihvout, me2, state); + break; +#endif + default: + abort(); + } + +} + + + +static void sha1_process(SHA1_CTX* ctx, const uint32_t block[16]) +{ + unsigned i, j; + uint32_t ubc_dv_mask[DVMASKSIZE] = { 0xFFFFFFFF }; + uint32_t ihvtmp[5]; + + ctx->ihv1[0] = ctx->ihv[0]; + ctx->ihv1[1] = ctx->ihv[1]; + ctx->ihv1[2] = ctx->ihv[2]; + ctx->ihv1[3] = ctx->ihv[3]; + ctx->ihv1[4] = ctx->ihv[4]; + + sha1_compression_states(ctx->ihv, block, ctx->m1, ctx->states); + + if (ctx->detect_coll) + { + if (ctx->ubc_check) + { + ubc_check(ctx->m1, ubc_dv_mask); + } + + if (ubc_dv_mask[0] != 0) + { + for (i = 0; sha1_dvs[i].dvType != 0; ++i) + { + if (ubc_dv_mask[0] & ((uint32_t)(1) << sha1_dvs[i].maskb)) + { + for (j = 0; j < 80; ++j) + ctx->m2[j] = ctx->m1[j] ^ sha1_dvs[i].dm[j]; + + sha1_recompression_step(sha1_dvs[i].testt, ctx->ihv2, ihvtmp, ctx->m2, ctx->states[sha1_dvs[i].testt]); + + /* to verify SHA-1 collision detection code with collisions for reduced-step SHA-1 */ + if ((0 == ((ihvtmp[0] ^ ctx->ihv[0]) | (ihvtmp[1] ^ ctx->ihv[1]) | (ihvtmp[2] ^ ctx->ihv[2]) | (ihvtmp[3] ^ ctx->ihv[3]) | (ihvtmp[4] ^ ctx->ihv[4]))) + || (ctx->reduced_round_coll && 0==((ctx->ihv1[0] ^ ctx->ihv2[0]) | (ctx->ihv1[1] ^ ctx->ihv2[1]) | (ctx->ihv1[2] ^ ctx->ihv2[2]) | (ctx->ihv1[3] ^ ctx->ihv2[3]) | (ctx->ihv1[4] ^ ctx->ihv2[4])))) + { + ctx->found_collision = 1; + + if (ctx->safe_hash) + { + sha1_compression_W(ctx->ihv, ctx->m1); + sha1_compression_W(ctx->ihv, ctx->m1); + } + + break; + } + } + } + } + } +} + +void SHA1DCInit(SHA1_CTX* ctx) +{ + ctx->total = 0; + ctx->ihv[0] = 0x67452301; + ctx->ihv[1] = 0xEFCDAB89; + ctx->ihv[2] = 0x98BADCFE; + ctx->ihv[3] = 0x10325476; + ctx->ihv[4] = 0xC3D2E1F0; + ctx->found_collision = 0; + ctx->safe_hash = SHA1DC_INIT_SAFE_HASH_DEFAULT; + ctx->ubc_check = 1; + ctx->detect_coll = 1; + ctx->reduced_round_coll = 0; + ctx->callback = NULL; +} + +void SHA1DCSetSafeHash(SHA1_CTX* ctx, int safehash) +{ + if (safehash) + ctx->safe_hash = 1; + else + ctx->safe_hash = 0; +} + + +void SHA1DCSetUseUBC(SHA1_CTX* ctx, int ubc_check) +{ + if (ubc_check) + ctx->ubc_check = 1; + else + ctx->ubc_check = 0; +} + +void SHA1DCSetUseDetectColl(SHA1_CTX* ctx, int detect_coll) +{ + if (detect_coll) + ctx->detect_coll = 1; + else + ctx->detect_coll = 0; +} + +void SHA1DCSetDetectReducedRoundCollision(SHA1_CTX* ctx, int reduced_round_coll) +{ + if (reduced_round_coll) + ctx->reduced_round_coll = 1; + else + ctx->reduced_round_coll = 0; +} + +void SHA1DCSetCallback(SHA1_CTX* ctx, collision_block_callback callback) +{ + ctx->callback = callback; +} + +void SHA1DCUpdate(SHA1_CTX* ctx, const char* buf, size_t len) +{ + unsigned left, fill; + + if (len == 0) + return; + + left = ctx->total & 63; + fill = 64 - left; + + if (left && len >= fill) + { + ctx->total += fill; + memcpy(ctx->buffer + left, buf, fill); + sha1_process(ctx, (uint32_t*)(ctx->buffer)); + buf += fill; + len -= fill; + left = 0; + } + while (len >= 64) + { + ctx->total += 64; + +#if defined(SHA1DC_ALLOW_UNALIGNED_ACCESS) + sha1_process(ctx, (uint32_t*)(buf)); +#else + memcpy(ctx->buffer, buf, 64); + sha1_process(ctx, (uint32_t*)(ctx->buffer)); +#endif /* defined(SHA1DC_ALLOW_UNALIGNED_ACCESS) */ + buf += 64; + len -= 64; + } + if (len > 0) + { + ctx->total += len; + memcpy(ctx->buffer + left, buf, len); + } +} + +static const unsigned char sha1_padding[64] = +{ + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +int SHA1DCFinal(unsigned char output[20], SHA1_CTX *ctx) +{ + uint32_t last = ctx->total & 63; + uint32_t padn = (last < 56) ? (56 - last) : (120 - last); + uint64_t total; + SHA1DCUpdate(ctx, (const char*)(sha1_padding), padn); + + total = ctx->total - padn; + total <<= 3; + ctx->buffer[56] = (unsigned char)(total >> 56); + ctx->buffer[57] = (unsigned char)(total >> 48); + ctx->buffer[58] = (unsigned char)(total >> 40); + ctx->buffer[59] = (unsigned char)(total >> 32); + ctx->buffer[60] = (unsigned char)(total >> 24); + ctx->buffer[61] = (unsigned char)(total >> 16); + ctx->buffer[62] = (unsigned char)(total >> 8); + ctx->buffer[63] = (unsigned char)(total); + sha1_process(ctx, (uint32_t*)(ctx->buffer)); + output[0] = (unsigned char)(ctx->ihv[0] >> 24); + output[1] = (unsigned char)(ctx->ihv[0] >> 16); + output[2] = (unsigned char)(ctx->ihv[0] >> 8); + output[3] = (unsigned char)(ctx->ihv[0]); + output[4] = (unsigned char)(ctx->ihv[1] >> 24); + output[5] = (unsigned char)(ctx->ihv[1] >> 16); + output[6] = (unsigned char)(ctx->ihv[1] >> 8); + output[7] = (unsigned char)(ctx->ihv[1]); + output[8] = (unsigned char)(ctx->ihv[2] >> 24); + output[9] = (unsigned char)(ctx->ihv[2] >> 16); + output[10] = (unsigned char)(ctx->ihv[2] >> 8); + output[11] = (unsigned char)(ctx->ihv[2]); + output[12] = (unsigned char)(ctx->ihv[3] >> 24); + output[13] = (unsigned char)(ctx->ihv[3] >> 16); + output[14] = (unsigned char)(ctx->ihv[3] >> 8); + output[15] = (unsigned char)(ctx->ihv[3]); + output[16] = (unsigned char)(ctx->ihv[4] >> 24); + output[17] = (unsigned char)(ctx->ihv[4] >> 16); + output[18] = (unsigned char)(ctx->ihv[4] >> 8); + output[19] = (unsigned char)(ctx->ihv[4]); + return ctx->found_collision; +} + +#ifdef SHA1DC_CUSTOM_TRAILING_INCLUDE_SHA1_C +#include SHA1DC_CUSTOM_TRAILING_INCLUDE_SHA1_C +#endif diff --git a/src/hash/sha1dc/sha1.h b/src/hash/sha1dc/sha1.h new file mode 100644 index 000000000..1e4e94be5 --- /dev/null +++ b/src/hash/sha1dc/sha1.h @@ -0,0 +1,110 @@ +/*** +* Copyright 2017 Marc Stevens , Dan Shumow +* Distributed under the MIT Software License. +* See accompanying file LICENSE.txt or copy at +* https://opensource.org/licenses/MIT +***/ + +#ifndef SHA1DC_SHA1_H +#define SHA1DC_SHA1_H + +#if defined(__cplusplus) +extern "C" { +#endif + +#ifndef SHA1DC_NO_STANDARD_INCLUDES +#include +#endif + +/* sha-1 compression function that takes an already expanded message, and additionally store intermediate states */ +/* only stores states ii (the state between step ii-1 and step ii) when DOSTORESTATEii is defined in ubc_check.h */ +void sha1_compression_states(uint32_t[5], const uint32_t[16], uint32_t[80], uint32_t[80][5]); + +/* +// Function type for sha1_recompression_step_T (uint32_t ihvin[5], uint32_t ihvout[5], const uint32_t me2[80], const uint32_t state[5]). +// Where 0 <= T < 80 +// me2 is an expanded message (the expansion of an original message block XOR'ed with a disturbance vector's message block difference.) +// state is the internal state (a,b,c,d,e) before step T of the SHA-1 compression function while processing the original message block. +// The function will return: +// ihvin: The reconstructed input chaining value. +// ihvout: The reconstructed output chaining value. +*/ +typedef void(*sha1_recompression_type)(uint32_t*, uint32_t*, const uint32_t*, const uint32_t*); + +/* A callback function type that can be set to be called when a collision block has been found: */ +/* void collision_block_callback(uint64_t byteoffset, const uint32_t ihvin1[5], const uint32_t ihvin2[5], const uint32_t m1[80], const uint32_t m2[80]) */ +typedef void(*collision_block_callback)(uint64_t, const uint32_t*, const uint32_t*, const uint32_t*, const uint32_t*); + +/* The SHA-1 context. */ +typedef struct { + uint64_t total; + uint32_t ihv[5]; + unsigned char buffer[64]; + int found_collision; + int safe_hash; + int detect_coll; + int ubc_check; + int reduced_round_coll; + collision_block_callback callback; + + uint32_t ihv1[5]; + uint32_t ihv2[5]; + uint32_t m1[80]; + uint32_t m2[80]; + uint32_t states[80][5]; +} SHA1_CTX; + +/* Initialize SHA-1 context. */ +void SHA1DCInit(SHA1_CTX*); + +/* + Function to enable safe SHA-1 hashing: + Collision attacks are thwarted by hashing a detected near-collision block 3 times. + Think of it as extending SHA-1 from 80-steps to 240-steps for such blocks: + The best collision attacks against SHA-1 have complexity about 2^60, + thus for 240-steps an immediate lower-bound for the best cryptanalytic attacks would be 2^180. + An attacker would be better off using a generic birthday search of complexity 2^80. + + Enabling safe SHA-1 hashing will result in the correct SHA-1 hash for messages where no collision attack was detected, + but it will result in a different SHA-1 hash for messages where a collision attack was detected. + This will automatically invalidate SHA-1 based digital signature forgeries. + Enabled by default. +*/ +void SHA1DCSetSafeHash(SHA1_CTX*, int); + +/* + Function to disable or enable the use of Unavoidable Bitconditions (provides a significant speed up). + Enabled by default + */ +void SHA1DCSetUseUBC(SHA1_CTX*, int); + +/* + Function to disable or enable the use of Collision Detection. + Enabled by default. + */ +void SHA1DCSetUseDetectColl(SHA1_CTX*, int); + +/* function to disable or enable the detection of reduced-round SHA-1 collisions */ +/* disabled by default */ +void SHA1DCSetDetectReducedRoundCollision(SHA1_CTX*, int); + +/* function to set a callback function, pass NULL to disable */ +/* by default no callback set */ +void SHA1DCSetCallback(SHA1_CTX*, collision_block_callback); + +/* update SHA-1 context with buffer contents */ +void SHA1DCUpdate(SHA1_CTX*, const char*, size_t); + +/* obtain SHA-1 hash from SHA-1 context */ +/* returns: 0 = no collision detected, otherwise = collision found => warn user for active attack */ +int SHA1DCFinal(unsigned char[20], SHA1_CTX*); + +#if defined(__cplusplus) +} +#endif + +#ifdef SHA1DC_CUSTOM_TRAILING_INCLUDE_SHA1_H +#include SHA1DC_CUSTOM_TRAILING_INCLUDE_SHA1_H +#endif + +#endif diff --git a/src/hash/sha1dc/ubc_check.c b/src/hash/sha1dc/ubc_check.c new file mode 100644 index 000000000..b3beff2af --- /dev/null +++ b/src/hash/sha1dc/ubc_check.c @@ -0,0 +1,372 @@ +/*** +* Copyright 2017 Marc Stevens , Dan Shumow +* Distributed under the MIT Software License. +* See accompanying file LICENSE.txt or copy at +* https://opensource.org/licenses/MIT +***/ + +/* +// this file was generated by the 'parse_bitrel' program in the tools section +// using the data files from directory 'tools/data/3565' +// +// sha1_dvs contains a list of SHA-1 Disturbance Vectors (DV) to check +// dvType, dvK and dvB define the DV: I(K,B) or II(K,B) (see the paper) +// dm[80] is the expanded message block XOR-difference defined by the DV +// testt is the step to do the recompression from for collision detection +// maski and maskb define the bit to check for each DV in the dvmask returned by ubc_check +// +// ubc_check takes as input an expanded message block and verifies the unavoidable bitconditions for all listed DVs +// it returns a dvmask where each bit belonging to a DV is set if all unavoidable bitconditions for that DV have been met +// thus one needs to do the recompression check for each DV that has its bit set +// +// ubc_check is programmatically generated and the unavoidable bitconditions have been hardcoded +// a directly verifiable version named ubc_check_verify can be found in ubc_check_verify.c +// ubc_check has been verified against ubc_check_verify using the 'ubc_check_test' program in the tools section +*/ + +#ifndef SHA1DC_NO_STANDARD_INCLUDES +#include +#endif +#ifdef SHA1DC_CUSTOM_INCLUDE_UBC_CHECK_C +#include SHA1DC_CUSTOM_INCLUDE_UBC_CHECK_C +#endif +#include "ubc_check.h" + +static const uint32_t DV_I_43_0_bit = (uint32_t)(1) << 0; +static const uint32_t DV_I_44_0_bit = (uint32_t)(1) << 1; +static const uint32_t DV_I_45_0_bit = (uint32_t)(1) << 2; +static const uint32_t DV_I_46_0_bit = (uint32_t)(1) << 3; +static const uint32_t DV_I_46_2_bit = (uint32_t)(1) << 4; +static const uint32_t DV_I_47_0_bit = (uint32_t)(1) << 5; +static const uint32_t DV_I_47_2_bit = (uint32_t)(1) << 6; +static const uint32_t DV_I_48_0_bit = (uint32_t)(1) << 7; +static const uint32_t DV_I_48_2_bit = (uint32_t)(1) << 8; +static const uint32_t DV_I_49_0_bit = (uint32_t)(1) << 9; +static const uint32_t DV_I_49_2_bit = (uint32_t)(1) << 10; +static const uint32_t DV_I_50_0_bit = (uint32_t)(1) << 11; +static const uint32_t DV_I_50_2_bit = (uint32_t)(1) << 12; +static const uint32_t DV_I_51_0_bit = (uint32_t)(1) << 13; +static const uint32_t DV_I_51_2_bit = (uint32_t)(1) << 14; +static const uint32_t DV_I_52_0_bit = (uint32_t)(1) << 15; +static const uint32_t DV_II_45_0_bit = (uint32_t)(1) << 16; +static const uint32_t DV_II_46_0_bit = (uint32_t)(1) << 17; +static const uint32_t DV_II_46_2_bit = (uint32_t)(1) << 18; +static const uint32_t DV_II_47_0_bit = (uint32_t)(1) << 19; +static const uint32_t DV_II_48_0_bit = (uint32_t)(1) << 20; +static const uint32_t DV_II_49_0_bit = (uint32_t)(1) << 21; +static const uint32_t DV_II_49_2_bit = (uint32_t)(1) << 22; +static const uint32_t DV_II_50_0_bit = (uint32_t)(1) << 23; +static const uint32_t DV_II_50_2_bit = (uint32_t)(1) << 24; +static const uint32_t DV_II_51_0_bit = (uint32_t)(1) << 25; +static const uint32_t DV_II_51_2_bit = (uint32_t)(1) << 26; +static const uint32_t DV_II_52_0_bit = (uint32_t)(1) << 27; +static const uint32_t DV_II_53_0_bit = (uint32_t)(1) << 28; +static const uint32_t DV_II_54_0_bit = (uint32_t)(1) << 29; +static const uint32_t DV_II_55_0_bit = (uint32_t)(1) << 30; +static const uint32_t DV_II_56_0_bit = (uint32_t)(1) << 31; + +dv_info_t sha1_dvs[] = +{ + {1,43,0,58,0,0, { 0x08000000,0x9800000c,0xd8000010,0x08000010,0xb8000010,0x98000000,0x60000000,0x00000008,0xc0000000,0x90000014,0x10000010,0xb8000014,0x28000000,0x20000010,0x48000000,0x08000018,0x60000000,0x90000010,0xf0000010,0x90000008,0xc0000000,0x90000010,0xf0000010,0xb0000008,0x40000000,0x90000000,0xf0000010,0x90000018,0x60000000,0x90000010,0x90000010,0x90000000,0x80000000,0x00000010,0xa0000000,0x20000000,0xa0000000,0x20000010,0x00000000,0x20000010,0x20000000,0x00000010,0x20000000,0x00000010,0xa0000000,0x00000000,0x20000000,0x20000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,0x00000020,0x00000001,0x40000002,0x40000040,0x40000002,0x80000004,0x80000080,0x80000006,0x00000049,0x00000103,0x80000009,0x80000012,0x80000202,0x00000018,0x00000164,0x00000408,0x800000e6,0x8000004c,0x00000803,0x80000161,0x80000599 } } +, {1,44,0,58,0,1, { 0xb4000008,0x08000000,0x9800000c,0xd8000010,0x08000010,0xb8000010,0x98000000,0x60000000,0x00000008,0xc0000000,0x90000014,0x10000010,0xb8000014,0x28000000,0x20000010,0x48000000,0x08000018,0x60000000,0x90000010,0xf0000010,0x90000008,0xc0000000,0x90000010,0xf0000010,0xb0000008,0x40000000,0x90000000,0xf0000010,0x90000018,0x60000000,0x90000010,0x90000010,0x90000000,0x80000000,0x00000010,0xa0000000,0x20000000,0xa0000000,0x20000010,0x00000000,0x20000010,0x20000000,0x00000010,0x20000000,0x00000010,0xa0000000,0x00000000,0x20000000,0x20000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,0x00000020,0x00000001,0x40000002,0x40000040,0x40000002,0x80000004,0x80000080,0x80000006,0x00000049,0x00000103,0x80000009,0x80000012,0x80000202,0x00000018,0x00000164,0x00000408,0x800000e6,0x8000004c,0x00000803,0x80000161 } } +, {1,45,0,58,0,2, { 0xf4000014,0xb4000008,0x08000000,0x9800000c,0xd8000010,0x08000010,0xb8000010,0x98000000,0x60000000,0x00000008,0xc0000000,0x90000014,0x10000010,0xb8000014,0x28000000,0x20000010,0x48000000,0x08000018,0x60000000,0x90000010,0xf0000010,0x90000008,0xc0000000,0x90000010,0xf0000010,0xb0000008,0x40000000,0x90000000,0xf0000010,0x90000018,0x60000000,0x90000010,0x90000010,0x90000000,0x80000000,0x00000010,0xa0000000,0x20000000,0xa0000000,0x20000010,0x00000000,0x20000010,0x20000000,0x00000010,0x20000000,0x00000010,0xa0000000,0x00000000,0x20000000,0x20000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,0x00000020,0x00000001,0x40000002,0x40000040,0x40000002,0x80000004,0x80000080,0x80000006,0x00000049,0x00000103,0x80000009,0x80000012,0x80000202,0x00000018,0x00000164,0x00000408,0x800000e6,0x8000004c,0x00000803 } } +, {1,46,0,58,0,3, { 0x2c000010,0xf4000014,0xb4000008,0x08000000,0x9800000c,0xd8000010,0x08000010,0xb8000010,0x98000000,0x60000000,0x00000008,0xc0000000,0x90000014,0x10000010,0xb8000014,0x28000000,0x20000010,0x48000000,0x08000018,0x60000000,0x90000010,0xf0000010,0x90000008,0xc0000000,0x90000010,0xf0000010,0xb0000008,0x40000000,0x90000000,0xf0000010,0x90000018,0x60000000,0x90000010,0x90000010,0x90000000,0x80000000,0x00000010,0xa0000000,0x20000000,0xa0000000,0x20000010,0x00000000,0x20000010,0x20000000,0x00000010,0x20000000,0x00000010,0xa0000000,0x00000000,0x20000000,0x20000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,0x00000020,0x00000001,0x40000002,0x40000040,0x40000002,0x80000004,0x80000080,0x80000006,0x00000049,0x00000103,0x80000009,0x80000012,0x80000202,0x00000018,0x00000164,0x00000408,0x800000e6,0x8000004c } } +, {1,46,2,58,0,4, { 0xb0000040,0xd0000053,0xd0000022,0x20000000,0x60000032,0x60000043,0x20000040,0xe0000042,0x60000002,0x80000001,0x00000020,0x00000003,0x40000052,0x40000040,0xe0000052,0xa0000000,0x80000040,0x20000001,0x20000060,0x80000001,0x40000042,0xc0000043,0x40000022,0x00000003,0x40000042,0xc0000043,0xc0000022,0x00000001,0x40000002,0xc0000043,0x40000062,0x80000001,0x40000042,0x40000042,0x40000002,0x00000002,0x00000040,0x80000002,0x80000000,0x80000002,0x80000040,0x00000000,0x80000040,0x80000000,0x00000040,0x80000000,0x00000040,0x80000002,0x00000000,0x80000000,0x80000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000004,0x00000080,0x00000004,0x00000009,0x00000101,0x00000009,0x00000012,0x00000202,0x0000001a,0x00000124,0x0000040c,0x00000026,0x0000004a,0x0000080a,0x00000060,0x00000590,0x00001020,0x0000039a,0x00000132 } } +, {1,47,0,58,0,5, { 0xc8000010,0x2c000010,0xf4000014,0xb4000008,0x08000000,0x9800000c,0xd8000010,0x08000010,0xb8000010,0x98000000,0x60000000,0x00000008,0xc0000000,0x90000014,0x10000010,0xb8000014,0x28000000,0x20000010,0x48000000,0x08000018,0x60000000,0x90000010,0xf0000010,0x90000008,0xc0000000,0x90000010,0xf0000010,0xb0000008,0x40000000,0x90000000,0xf0000010,0x90000018,0x60000000,0x90000010,0x90000010,0x90000000,0x80000000,0x00000010,0xa0000000,0x20000000,0xa0000000,0x20000010,0x00000000,0x20000010,0x20000000,0x00000010,0x20000000,0x00000010,0xa0000000,0x00000000,0x20000000,0x20000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,0x00000020,0x00000001,0x40000002,0x40000040,0x40000002,0x80000004,0x80000080,0x80000006,0x00000049,0x00000103,0x80000009,0x80000012,0x80000202,0x00000018,0x00000164,0x00000408,0x800000e6 } } +, {1,47,2,58,0,6, { 0x20000043,0xb0000040,0xd0000053,0xd0000022,0x20000000,0x60000032,0x60000043,0x20000040,0xe0000042,0x60000002,0x80000001,0x00000020,0x00000003,0x40000052,0x40000040,0xe0000052,0xa0000000,0x80000040,0x20000001,0x20000060,0x80000001,0x40000042,0xc0000043,0x40000022,0x00000003,0x40000042,0xc0000043,0xc0000022,0x00000001,0x40000002,0xc0000043,0x40000062,0x80000001,0x40000042,0x40000042,0x40000002,0x00000002,0x00000040,0x80000002,0x80000000,0x80000002,0x80000040,0x00000000,0x80000040,0x80000000,0x00000040,0x80000000,0x00000040,0x80000002,0x00000000,0x80000000,0x80000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000004,0x00000080,0x00000004,0x00000009,0x00000101,0x00000009,0x00000012,0x00000202,0x0000001a,0x00000124,0x0000040c,0x00000026,0x0000004a,0x0000080a,0x00000060,0x00000590,0x00001020,0x0000039a } } +, {1,48,0,58,0,7, { 0xb800000a,0xc8000010,0x2c000010,0xf4000014,0xb4000008,0x08000000,0x9800000c,0xd8000010,0x08000010,0xb8000010,0x98000000,0x60000000,0x00000008,0xc0000000,0x90000014,0x10000010,0xb8000014,0x28000000,0x20000010,0x48000000,0x08000018,0x60000000,0x90000010,0xf0000010,0x90000008,0xc0000000,0x90000010,0xf0000010,0xb0000008,0x40000000,0x90000000,0xf0000010,0x90000018,0x60000000,0x90000010,0x90000010,0x90000000,0x80000000,0x00000010,0xa0000000,0x20000000,0xa0000000,0x20000010,0x00000000,0x20000010,0x20000000,0x00000010,0x20000000,0x00000010,0xa0000000,0x00000000,0x20000000,0x20000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,0x00000020,0x00000001,0x40000002,0x40000040,0x40000002,0x80000004,0x80000080,0x80000006,0x00000049,0x00000103,0x80000009,0x80000012,0x80000202,0x00000018,0x00000164,0x00000408 } } +, {1,48,2,58,0,8, { 0xe000002a,0x20000043,0xb0000040,0xd0000053,0xd0000022,0x20000000,0x60000032,0x60000043,0x20000040,0xe0000042,0x60000002,0x80000001,0x00000020,0x00000003,0x40000052,0x40000040,0xe0000052,0xa0000000,0x80000040,0x20000001,0x20000060,0x80000001,0x40000042,0xc0000043,0x40000022,0x00000003,0x40000042,0xc0000043,0xc0000022,0x00000001,0x40000002,0xc0000043,0x40000062,0x80000001,0x40000042,0x40000042,0x40000002,0x00000002,0x00000040,0x80000002,0x80000000,0x80000002,0x80000040,0x00000000,0x80000040,0x80000000,0x00000040,0x80000000,0x00000040,0x80000002,0x00000000,0x80000000,0x80000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000004,0x00000080,0x00000004,0x00000009,0x00000101,0x00000009,0x00000012,0x00000202,0x0000001a,0x00000124,0x0000040c,0x00000026,0x0000004a,0x0000080a,0x00000060,0x00000590,0x00001020 } } +, {1,49,0,58,0,9, { 0x18000000,0xb800000a,0xc8000010,0x2c000010,0xf4000014,0xb4000008,0x08000000,0x9800000c,0xd8000010,0x08000010,0xb8000010,0x98000000,0x60000000,0x00000008,0xc0000000,0x90000014,0x10000010,0xb8000014,0x28000000,0x20000010,0x48000000,0x08000018,0x60000000,0x90000010,0xf0000010,0x90000008,0xc0000000,0x90000010,0xf0000010,0xb0000008,0x40000000,0x90000000,0xf0000010,0x90000018,0x60000000,0x90000010,0x90000010,0x90000000,0x80000000,0x00000010,0xa0000000,0x20000000,0xa0000000,0x20000010,0x00000000,0x20000010,0x20000000,0x00000010,0x20000000,0x00000010,0xa0000000,0x00000000,0x20000000,0x20000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,0x00000020,0x00000001,0x40000002,0x40000040,0x40000002,0x80000004,0x80000080,0x80000006,0x00000049,0x00000103,0x80000009,0x80000012,0x80000202,0x00000018,0x00000164 } } +, {1,49,2,58,0,10, { 0x60000000,0xe000002a,0x20000043,0xb0000040,0xd0000053,0xd0000022,0x20000000,0x60000032,0x60000043,0x20000040,0xe0000042,0x60000002,0x80000001,0x00000020,0x00000003,0x40000052,0x40000040,0xe0000052,0xa0000000,0x80000040,0x20000001,0x20000060,0x80000001,0x40000042,0xc0000043,0x40000022,0x00000003,0x40000042,0xc0000043,0xc0000022,0x00000001,0x40000002,0xc0000043,0x40000062,0x80000001,0x40000042,0x40000042,0x40000002,0x00000002,0x00000040,0x80000002,0x80000000,0x80000002,0x80000040,0x00000000,0x80000040,0x80000000,0x00000040,0x80000000,0x00000040,0x80000002,0x00000000,0x80000000,0x80000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000004,0x00000080,0x00000004,0x00000009,0x00000101,0x00000009,0x00000012,0x00000202,0x0000001a,0x00000124,0x0000040c,0x00000026,0x0000004a,0x0000080a,0x00000060,0x00000590 } } +, {1,50,0,65,0,11, { 0x0800000c,0x18000000,0xb800000a,0xc8000010,0x2c000010,0xf4000014,0xb4000008,0x08000000,0x9800000c,0xd8000010,0x08000010,0xb8000010,0x98000000,0x60000000,0x00000008,0xc0000000,0x90000014,0x10000010,0xb8000014,0x28000000,0x20000010,0x48000000,0x08000018,0x60000000,0x90000010,0xf0000010,0x90000008,0xc0000000,0x90000010,0xf0000010,0xb0000008,0x40000000,0x90000000,0xf0000010,0x90000018,0x60000000,0x90000010,0x90000010,0x90000000,0x80000000,0x00000010,0xa0000000,0x20000000,0xa0000000,0x20000010,0x00000000,0x20000010,0x20000000,0x00000010,0x20000000,0x00000010,0xa0000000,0x00000000,0x20000000,0x20000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,0x00000020,0x00000001,0x40000002,0x40000040,0x40000002,0x80000004,0x80000080,0x80000006,0x00000049,0x00000103,0x80000009,0x80000012,0x80000202,0x00000018 } } +, {1,50,2,65,0,12, { 0x20000030,0x60000000,0xe000002a,0x20000043,0xb0000040,0xd0000053,0xd0000022,0x20000000,0x60000032,0x60000043,0x20000040,0xe0000042,0x60000002,0x80000001,0x00000020,0x00000003,0x40000052,0x40000040,0xe0000052,0xa0000000,0x80000040,0x20000001,0x20000060,0x80000001,0x40000042,0xc0000043,0x40000022,0x00000003,0x40000042,0xc0000043,0xc0000022,0x00000001,0x40000002,0xc0000043,0x40000062,0x80000001,0x40000042,0x40000042,0x40000002,0x00000002,0x00000040,0x80000002,0x80000000,0x80000002,0x80000040,0x00000000,0x80000040,0x80000000,0x00000040,0x80000000,0x00000040,0x80000002,0x00000000,0x80000000,0x80000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000004,0x00000080,0x00000004,0x00000009,0x00000101,0x00000009,0x00000012,0x00000202,0x0000001a,0x00000124,0x0000040c,0x00000026,0x0000004a,0x0000080a,0x00000060 } } +, {1,51,0,65,0,13, { 0xe8000000,0x0800000c,0x18000000,0xb800000a,0xc8000010,0x2c000010,0xf4000014,0xb4000008,0x08000000,0x9800000c,0xd8000010,0x08000010,0xb8000010,0x98000000,0x60000000,0x00000008,0xc0000000,0x90000014,0x10000010,0xb8000014,0x28000000,0x20000010,0x48000000,0x08000018,0x60000000,0x90000010,0xf0000010,0x90000008,0xc0000000,0x90000010,0xf0000010,0xb0000008,0x40000000,0x90000000,0xf0000010,0x90000018,0x60000000,0x90000010,0x90000010,0x90000000,0x80000000,0x00000010,0xa0000000,0x20000000,0xa0000000,0x20000010,0x00000000,0x20000010,0x20000000,0x00000010,0x20000000,0x00000010,0xa0000000,0x00000000,0x20000000,0x20000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,0x00000020,0x00000001,0x40000002,0x40000040,0x40000002,0x80000004,0x80000080,0x80000006,0x00000049,0x00000103,0x80000009,0x80000012,0x80000202 } } +, {1,51,2,65,0,14, { 0xa0000003,0x20000030,0x60000000,0xe000002a,0x20000043,0xb0000040,0xd0000053,0xd0000022,0x20000000,0x60000032,0x60000043,0x20000040,0xe0000042,0x60000002,0x80000001,0x00000020,0x00000003,0x40000052,0x40000040,0xe0000052,0xa0000000,0x80000040,0x20000001,0x20000060,0x80000001,0x40000042,0xc0000043,0x40000022,0x00000003,0x40000042,0xc0000043,0xc0000022,0x00000001,0x40000002,0xc0000043,0x40000062,0x80000001,0x40000042,0x40000042,0x40000002,0x00000002,0x00000040,0x80000002,0x80000000,0x80000002,0x80000040,0x00000000,0x80000040,0x80000000,0x00000040,0x80000000,0x00000040,0x80000002,0x00000000,0x80000000,0x80000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000004,0x00000080,0x00000004,0x00000009,0x00000101,0x00000009,0x00000012,0x00000202,0x0000001a,0x00000124,0x0000040c,0x00000026,0x0000004a,0x0000080a } } +, {1,52,0,65,0,15, { 0x04000010,0xe8000000,0x0800000c,0x18000000,0xb800000a,0xc8000010,0x2c000010,0xf4000014,0xb4000008,0x08000000,0x9800000c,0xd8000010,0x08000010,0xb8000010,0x98000000,0x60000000,0x00000008,0xc0000000,0x90000014,0x10000010,0xb8000014,0x28000000,0x20000010,0x48000000,0x08000018,0x60000000,0x90000010,0xf0000010,0x90000008,0xc0000000,0x90000010,0xf0000010,0xb0000008,0x40000000,0x90000000,0xf0000010,0x90000018,0x60000000,0x90000010,0x90000010,0x90000000,0x80000000,0x00000010,0xa0000000,0x20000000,0xa0000000,0x20000010,0x00000000,0x20000010,0x20000000,0x00000010,0x20000000,0x00000010,0xa0000000,0x00000000,0x20000000,0x20000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,0x00000020,0x00000001,0x40000002,0x40000040,0x40000002,0x80000004,0x80000080,0x80000006,0x00000049,0x00000103,0x80000009,0x80000012 } } +, {2,45,0,58,0,16, { 0xec000014,0x0c000002,0xc0000010,0xb400001c,0x2c000004,0xbc000018,0xb0000010,0x0000000c,0xb8000010,0x08000018,0x78000010,0x08000014,0x70000010,0xb800001c,0xe8000000,0xb0000004,0x58000010,0xb000000c,0x48000000,0xb0000000,0xb8000010,0x98000010,0xa0000000,0x00000000,0x00000000,0x20000000,0x80000000,0x00000010,0x00000000,0x20000010,0x20000000,0x00000010,0x60000000,0x00000018,0xe0000000,0x90000000,0x30000010,0xb0000000,0x20000000,0x20000000,0xa0000000,0x00000010,0x80000000,0x20000000,0x20000000,0x20000000,0x80000000,0x00000010,0x00000000,0x20000010,0xa0000000,0x00000000,0x20000000,0x20000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,0x00000020,0x00000001,0x40000002,0x40000041,0x40000022,0x80000005,0xc0000082,0xc0000046,0x4000004b,0x80000107,0x00000089,0x00000014,0x8000024b,0x0000011b,0x8000016d,0x8000041a,0x000002e4,0x80000054,0x00000967 } } +, {2,46,0,58,0,17, { 0x2400001c,0xec000014,0x0c000002,0xc0000010,0xb400001c,0x2c000004,0xbc000018,0xb0000010,0x0000000c,0xb8000010,0x08000018,0x78000010,0x08000014,0x70000010,0xb800001c,0xe8000000,0xb0000004,0x58000010,0xb000000c,0x48000000,0xb0000000,0xb8000010,0x98000010,0xa0000000,0x00000000,0x00000000,0x20000000,0x80000000,0x00000010,0x00000000,0x20000010,0x20000000,0x00000010,0x60000000,0x00000018,0xe0000000,0x90000000,0x30000010,0xb0000000,0x20000000,0x20000000,0xa0000000,0x00000010,0x80000000,0x20000000,0x20000000,0x20000000,0x80000000,0x00000010,0x00000000,0x20000010,0xa0000000,0x00000000,0x20000000,0x20000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,0x00000020,0x00000001,0x40000002,0x40000041,0x40000022,0x80000005,0xc0000082,0xc0000046,0x4000004b,0x80000107,0x00000089,0x00000014,0x8000024b,0x0000011b,0x8000016d,0x8000041a,0x000002e4,0x80000054 } } +, {2,46,2,58,0,18, { 0x90000070,0xb0000053,0x30000008,0x00000043,0xd0000072,0xb0000010,0xf0000062,0xc0000042,0x00000030,0xe0000042,0x20000060,0xe0000041,0x20000050,0xc0000041,0xe0000072,0xa0000003,0xc0000012,0x60000041,0xc0000032,0x20000001,0xc0000002,0xe0000042,0x60000042,0x80000002,0x00000000,0x00000000,0x80000000,0x00000002,0x00000040,0x00000000,0x80000040,0x80000000,0x00000040,0x80000001,0x00000060,0x80000003,0x40000002,0xc0000040,0xc0000002,0x80000000,0x80000000,0x80000002,0x00000040,0x00000002,0x80000000,0x80000000,0x80000000,0x00000002,0x00000040,0x00000000,0x80000040,0x80000002,0x00000000,0x80000000,0x80000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000004,0x00000080,0x00000004,0x00000009,0x00000105,0x00000089,0x00000016,0x0000020b,0x0000011b,0x0000012d,0x0000041e,0x00000224,0x00000050,0x0000092e,0x0000046c,0x000005b6,0x0000106a,0x00000b90,0x00000152 } } +, {2,47,0,58,0,19, { 0x20000010,0x2400001c,0xec000014,0x0c000002,0xc0000010,0xb400001c,0x2c000004,0xbc000018,0xb0000010,0x0000000c,0xb8000010,0x08000018,0x78000010,0x08000014,0x70000010,0xb800001c,0xe8000000,0xb0000004,0x58000010,0xb000000c,0x48000000,0xb0000000,0xb8000010,0x98000010,0xa0000000,0x00000000,0x00000000,0x20000000,0x80000000,0x00000010,0x00000000,0x20000010,0x20000000,0x00000010,0x60000000,0x00000018,0xe0000000,0x90000000,0x30000010,0xb0000000,0x20000000,0x20000000,0xa0000000,0x00000010,0x80000000,0x20000000,0x20000000,0x20000000,0x80000000,0x00000010,0x00000000,0x20000010,0xa0000000,0x00000000,0x20000000,0x20000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,0x00000020,0x00000001,0x40000002,0x40000041,0x40000022,0x80000005,0xc0000082,0xc0000046,0x4000004b,0x80000107,0x00000089,0x00000014,0x8000024b,0x0000011b,0x8000016d,0x8000041a,0x000002e4 } } +, {2,48,0,58,0,20, { 0xbc00001a,0x20000010,0x2400001c,0xec000014,0x0c000002,0xc0000010,0xb400001c,0x2c000004,0xbc000018,0xb0000010,0x0000000c,0xb8000010,0x08000018,0x78000010,0x08000014,0x70000010,0xb800001c,0xe8000000,0xb0000004,0x58000010,0xb000000c,0x48000000,0xb0000000,0xb8000010,0x98000010,0xa0000000,0x00000000,0x00000000,0x20000000,0x80000000,0x00000010,0x00000000,0x20000010,0x20000000,0x00000010,0x60000000,0x00000018,0xe0000000,0x90000000,0x30000010,0xb0000000,0x20000000,0x20000000,0xa0000000,0x00000010,0x80000000,0x20000000,0x20000000,0x20000000,0x80000000,0x00000010,0x00000000,0x20000010,0xa0000000,0x00000000,0x20000000,0x20000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,0x00000020,0x00000001,0x40000002,0x40000041,0x40000022,0x80000005,0xc0000082,0xc0000046,0x4000004b,0x80000107,0x00000089,0x00000014,0x8000024b,0x0000011b,0x8000016d,0x8000041a } } +, {2,49,0,58,0,21, { 0x3c000004,0xbc00001a,0x20000010,0x2400001c,0xec000014,0x0c000002,0xc0000010,0xb400001c,0x2c000004,0xbc000018,0xb0000010,0x0000000c,0xb8000010,0x08000018,0x78000010,0x08000014,0x70000010,0xb800001c,0xe8000000,0xb0000004,0x58000010,0xb000000c,0x48000000,0xb0000000,0xb8000010,0x98000010,0xa0000000,0x00000000,0x00000000,0x20000000,0x80000000,0x00000010,0x00000000,0x20000010,0x20000000,0x00000010,0x60000000,0x00000018,0xe0000000,0x90000000,0x30000010,0xb0000000,0x20000000,0x20000000,0xa0000000,0x00000010,0x80000000,0x20000000,0x20000000,0x20000000,0x80000000,0x00000010,0x00000000,0x20000010,0xa0000000,0x00000000,0x20000000,0x20000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,0x00000020,0x00000001,0x40000002,0x40000041,0x40000022,0x80000005,0xc0000082,0xc0000046,0x4000004b,0x80000107,0x00000089,0x00000014,0x8000024b,0x0000011b,0x8000016d } } +, {2,49,2,58,0,22, { 0xf0000010,0xf000006a,0x80000040,0x90000070,0xb0000053,0x30000008,0x00000043,0xd0000072,0xb0000010,0xf0000062,0xc0000042,0x00000030,0xe0000042,0x20000060,0xe0000041,0x20000050,0xc0000041,0xe0000072,0xa0000003,0xc0000012,0x60000041,0xc0000032,0x20000001,0xc0000002,0xe0000042,0x60000042,0x80000002,0x00000000,0x00000000,0x80000000,0x00000002,0x00000040,0x00000000,0x80000040,0x80000000,0x00000040,0x80000001,0x00000060,0x80000003,0x40000002,0xc0000040,0xc0000002,0x80000000,0x80000000,0x80000002,0x00000040,0x00000002,0x80000000,0x80000000,0x80000000,0x00000002,0x00000040,0x00000000,0x80000040,0x80000002,0x00000000,0x80000000,0x80000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000004,0x00000080,0x00000004,0x00000009,0x00000105,0x00000089,0x00000016,0x0000020b,0x0000011b,0x0000012d,0x0000041e,0x00000224,0x00000050,0x0000092e,0x0000046c,0x000005b6 } } +, {2,50,0,65,0,23, { 0xb400001c,0x3c000004,0xbc00001a,0x20000010,0x2400001c,0xec000014,0x0c000002,0xc0000010,0xb400001c,0x2c000004,0xbc000018,0xb0000010,0x0000000c,0xb8000010,0x08000018,0x78000010,0x08000014,0x70000010,0xb800001c,0xe8000000,0xb0000004,0x58000010,0xb000000c,0x48000000,0xb0000000,0xb8000010,0x98000010,0xa0000000,0x00000000,0x00000000,0x20000000,0x80000000,0x00000010,0x00000000,0x20000010,0x20000000,0x00000010,0x60000000,0x00000018,0xe0000000,0x90000000,0x30000010,0xb0000000,0x20000000,0x20000000,0xa0000000,0x00000010,0x80000000,0x20000000,0x20000000,0x20000000,0x80000000,0x00000010,0x00000000,0x20000010,0xa0000000,0x00000000,0x20000000,0x20000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,0x00000020,0x00000001,0x40000002,0x40000041,0x40000022,0x80000005,0xc0000082,0xc0000046,0x4000004b,0x80000107,0x00000089,0x00000014,0x8000024b,0x0000011b } } +, {2,50,2,65,0,24, { 0xd0000072,0xf0000010,0xf000006a,0x80000040,0x90000070,0xb0000053,0x30000008,0x00000043,0xd0000072,0xb0000010,0xf0000062,0xc0000042,0x00000030,0xe0000042,0x20000060,0xe0000041,0x20000050,0xc0000041,0xe0000072,0xa0000003,0xc0000012,0x60000041,0xc0000032,0x20000001,0xc0000002,0xe0000042,0x60000042,0x80000002,0x00000000,0x00000000,0x80000000,0x00000002,0x00000040,0x00000000,0x80000040,0x80000000,0x00000040,0x80000001,0x00000060,0x80000003,0x40000002,0xc0000040,0xc0000002,0x80000000,0x80000000,0x80000002,0x00000040,0x00000002,0x80000000,0x80000000,0x80000000,0x00000002,0x00000040,0x00000000,0x80000040,0x80000002,0x00000000,0x80000000,0x80000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000004,0x00000080,0x00000004,0x00000009,0x00000105,0x00000089,0x00000016,0x0000020b,0x0000011b,0x0000012d,0x0000041e,0x00000224,0x00000050,0x0000092e,0x0000046c } } +, {2,51,0,65,0,25, { 0xc0000010,0xb400001c,0x3c000004,0xbc00001a,0x20000010,0x2400001c,0xec000014,0x0c000002,0xc0000010,0xb400001c,0x2c000004,0xbc000018,0xb0000010,0x0000000c,0xb8000010,0x08000018,0x78000010,0x08000014,0x70000010,0xb800001c,0xe8000000,0xb0000004,0x58000010,0xb000000c,0x48000000,0xb0000000,0xb8000010,0x98000010,0xa0000000,0x00000000,0x00000000,0x20000000,0x80000000,0x00000010,0x00000000,0x20000010,0x20000000,0x00000010,0x60000000,0x00000018,0xe0000000,0x90000000,0x30000010,0xb0000000,0x20000000,0x20000000,0xa0000000,0x00000010,0x80000000,0x20000000,0x20000000,0x20000000,0x80000000,0x00000010,0x00000000,0x20000010,0xa0000000,0x00000000,0x20000000,0x20000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,0x00000020,0x00000001,0x40000002,0x40000041,0x40000022,0x80000005,0xc0000082,0xc0000046,0x4000004b,0x80000107,0x00000089,0x00000014,0x8000024b } } +, {2,51,2,65,0,26, { 0x00000043,0xd0000072,0xf0000010,0xf000006a,0x80000040,0x90000070,0xb0000053,0x30000008,0x00000043,0xd0000072,0xb0000010,0xf0000062,0xc0000042,0x00000030,0xe0000042,0x20000060,0xe0000041,0x20000050,0xc0000041,0xe0000072,0xa0000003,0xc0000012,0x60000041,0xc0000032,0x20000001,0xc0000002,0xe0000042,0x60000042,0x80000002,0x00000000,0x00000000,0x80000000,0x00000002,0x00000040,0x00000000,0x80000040,0x80000000,0x00000040,0x80000001,0x00000060,0x80000003,0x40000002,0xc0000040,0xc0000002,0x80000000,0x80000000,0x80000002,0x00000040,0x00000002,0x80000000,0x80000000,0x80000000,0x00000002,0x00000040,0x00000000,0x80000040,0x80000002,0x00000000,0x80000000,0x80000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000004,0x00000080,0x00000004,0x00000009,0x00000105,0x00000089,0x00000016,0x0000020b,0x0000011b,0x0000012d,0x0000041e,0x00000224,0x00000050,0x0000092e } } +, {2,52,0,65,0,27, { 0x0c000002,0xc0000010,0xb400001c,0x3c000004,0xbc00001a,0x20000010,0x2400001c,0xec000014,0x0c000002,0xc0000010,0xb400001c,0x2c000004,0xbc000018,0xb0000010,0x0000000c,0xb8000010,0x08000018,0x78000010,0x08000014,0x70000010,0xb800001c,0xe8000000,0xb0000004,0x58000010,0xb000000c,0x48000000,0xb0000000,0xb8000010,0x98000010,0xa0000000,0x00000000,0x00000000,0x20000000,0x80000000,0x00000010,0x00000000,0x20000010,0x20000000,0x00000010,0x60000000,0x00000018,0xe0000000,0x90000000,0x30000010,0xb0000000,0x20000000,0x20000000,0xa0000000,0x00000010,0x80000000,0x20000000,0x20000000,0x20000000,0x80000000,0x00000010,0x00000000,0x20000010,0xa0000000,0x00000000,0x20000000,0x20000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,0x00000020,0x00000001,0x40000002,0x40000041,0x40000022,0x80000005,0xc0000082,0xc0000046,0x4000004b,0x80000107,0x00000089,0x00000014 } } +, {2,53,0,65,0,28, { 0xcc000014,0x0c000002,0xc0000010,0xb400001c,0x3c000004,0xbc00001a,0x20000010,0x2400001c,0xec000014,0x0c000002,0xc0000010,0xb400001c,0x2c000004,0xbc000018,0xb0000010,0x0000000c,0xb8000010,0x08000018,0x78000010,0x08000014,0x70000010,0xb800001c,0xe8000000,0xb0000004,0x58000010,0xb000000c,0x48000000,0xb0000000,0xb8000010,0x98000010,0xa0000000,0x00000000,0x00000000,0x20000000,0x80000000,0x00000010,0x00000000,0x20000010,0x20000000,0x00000010,0x60000000,0x00000018,0xe0000000,0x90000000,0x30000010,0xb0000000,0x20000000,0x20000000,0xa0000000,0x00000010,0x80000000,0x20000000,0x20000000,0x20000000,0x80000000,0x00000010,0x00000000,0x20000010,0xa0000000,0x00000000,0x20000000,0x20000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,0x00000020,0x00000001,0x40000002,0x40000041,0x40000022,0x80000005,0xc0000082,0xc0000046,0x4000004b,0x80000107,0x00000089 } } +, {2,54,0,65,0,29, { 0x0400001c,0xcc000014,0x0c000002,0xc0000010,0xb400001c,0x3c000004,0xbc00001a,0x20000010,0x2400001c,0xec000014,0x0c000002,0xc0000010,0xb400001c,0x2c000004,0xbc000018,0xb0000010,0x0000000c,0xb8000010,0x08000018,0x78000010,0x08000014,0x70000010,0xb800001c,0xe8000000,0xb0000004,0x58000010,0xb000000c,0x48000000,0xb0000000,0xb8000010,0x98000010,0xa0000000,0x00000000,0x00000000,0x20000000,0x80000000,0x00000010,0x00000000,0x20000010,0x20000000,0x00000010,0x60000000,0x00000018,0xe0000000,0x90000000,0x30000010,0xb0000000,0x20000000,0x20000000,0xa0000000,0x00000010,0x80000000,0x20000000,0x20000000,0x20000000,0x80000000,0x00000010,0x00000000,0x20000010,0xa0000000,0x00000000,0x20000000,0x20000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,0x00000020,0x00000001,0x40000002,0x40000041,0x40000022,0x80000005,0xc0000082,0xc0000046,0x4000004b,0x80000107 } } +, {2,55,0,65,0,30, { 0x00000010,0x0400001c,0xcc000014,0x0c000002,0xc0000010,0xb400001c,0x3c000004,0xbc00001a,0x20000010,0x2400001c,0xec000014,0x0c000002,0xc0000010,0xb400001c,0x2c000004,0xbc000018,0xb0000010,0x0000000c,0xb8000010,0x08000018,0x78000010,0x08000014,0x70000010,0xb800001c,0xe8000000,0xb0000004,0x58000010,0xb000000c,0x48000000,0xb0000000,0xb8000010,0x98000010,0xa0000000,0x00000000,0x00000000,0x20000000,0x80000000,0x00000010,0x00000000,0x20000010,0x20000000,0x00000010,0x60000000,0x00000018,0xe0000000,0x90000000,0x30000010,0xb0000000,0x20000000,0x20000000,0xa0000000,0x00000010,0x80000000,0x20000000,0x20000000,0x20000000,0x80000000,0x00000010,0x00000000,0x20000010,0xa0000000,0x00000000,0x20000000,0x20000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,0x00000020,0x00000001,0x40000002,0x40000041,0x40000022,0x80000005,0xc0000082,0xc0000046,0x4000004b } } +, {2,56,0,65,0,31, { 0x2600001a,0x00000010,0x0400001c,0xcc000014,0x0c000002,0xc0000010,0xb400001c,0x3c000004,0xbc00001a,0x20000010,0x2400001c,0xec000014,0x0c000002,0xc0000010,0xb400001c,0x2c000004,0xbc000018,0xb0000010,0x0000000c,0xb8000010,0x08000018,0x78000010,0x08000014,0x70000010,0xb800001c,0xe8000000,0xb0000004,0x58000010,0xb000000c,0x48000000,0xb0000000,0xb8000010,0x98000010,0xa0000000,0x00000000,0x00000000,0x20000000,0x80000000,0x00000010,0x00000000,0x20000010,0x20000000,0x00000010,0x60000000,0x00000018,0xe0000000,0x90000000,0x30000010,0xb0000000,0x20000000,0x20000000,0xa0000000,0x00000010,0x80000000,0x20000000,0x20000000,0x20000000,0x80000000,0x00000010,0x00000000,0x20000010,0xa0000000,0x00000000,0x20000000,0x20000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,0x00000020,0x00000001,0x40000002,0x40000041,0x40000022,0x80000005,0xc0000082,0xc0000046 } } +, {0,0,0,0,0,0, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}} +}; +void ubc_check(const uint32_t W[80], uint32_t dvmask[1]) +{ + uint32_t mask = ~((uint32_t)(0)); + mask &= (((((W[44]^W[45])>>29)&1)-1) | ~(DV_I_48_0_bit|DV_I_51_0_bit|DV_I_52_0_bit|DV_II_45_0_bit|DV_II_46_0_bit|DV_II_50_0_bit|DV_II_51_0_bit)); + mask &= (((((W[49]^W[50])>>29)&1)-1) | ~(DV_I_46_0_bit|DV_II_45_0_bit|DV_II_50_0_bit|DV_II_51_0_bit|DV_II_55_0_bit|DV_II_56_0_bit)); + mask &= (((((W[48]^W[49])>>29)&1)-1) | ~(DV_I_45_0_bit|DV_I_52_0_bit|DV_II_49_0_bit|DV_II_50_0_bit|DV_II_54_0_bit|DV_II_55_0_bit)); + mask &= ((((W[47]^(W[50]>>25))&(1<<4))-(1<<4)) | ~(DV_I_47_0_bit|DV_I_49_0_bit|DV_I_51_0_bit|DV_II_45_0_bit|DV_II_51_0_bit|DV_II_56_0_bit)); + mask &= (((((W[47]^W[48])>>29)&1)-1) | ~(DV_I_44_0_bit|DV_I_51_0_bit|DV_II_48_0_bit|DV_II_49_0_bit|DV_II_53_0_bit|DV_II_54_0_bit)); + mask &= (((((W[46]>>4)^(W[49]>>29))&1)-1) | ~(DV_I_46_0_bit|DV_I_48_0_bit|DV_I_50_0_bit|DV_I_52_0_bit|DV_II_50_0_bit|DV_II_55_0_bit)); + mask &= (((((W[46]^W[47])>>29)&1)-1) | ~(DV_I_43_0_bit|DV_I_50_0_bit|DV_II_47_0_bit|DV_II_48_0_bit|DV_II_52_0_bit|DV_II_53_0_bit)); + mask &= (((((W[45]>>4)^(W[48]>>29))&1)-1) | ~(DV_I_45_0_bit|DV_I_47_0_bit|DV_I_49_0_bit|DV_I_51_0_bit|DV_II_49_0_bit|DV_II_54_0_bit)); + mask &= (((((W[45]^W[46])>>29)&1)-1) | ~(DV_I_49_0_bit|DV_I_52_0_bit|DV_II_46_0_bit|DV_II_47_0_bit|DV_II_51_0_bit|DV_II_52_0_bit)); + mask &= (((((W[44]>>4)^(W[47]>>29))&1)-1) | ~(DV_I_44_0_bit|DV_I_46_0_bit|DV_I_48_0_bit|DV_I_50_0_bit|DV_II_48_0_bit|DV_II_53_0_bit)); + mask &= (((((W[43]>>4)^(W[46]>>29))&1)-1) | ~(DV_I_43_0_bit|DV_I_45_0_bit|DV_I_47_0_bit|DV_I_49_0_bit|DV_II_47_0_bit|DV_II_52_0_bit)); + mask &= (((((W[43]^W[44])>>29)&1)-1) | ~(DV_I_47_0_bit|DV_I_50_0_bit|DV_I_51_0_bit|DV_II_45_0_bit|DV_II_49_0_bit|DV_II_50_0_bit)); + mask &= (((((W[42]>>4)^(W[45]>>29))&1)-1) | ~(DV_I_44_0_bit|DV_I_46_0_bit|DV_I_48_0_bit|DV_I_52_0_bit|DV_II_46_0_bit|DV_II_51_0_bit)); + mask &= (((((W[41]>>4)^(W[44]>>29))&1)-1) | ~(DV_I_43_0_bit|DV_I_45_0_bit|DV_I_47_0_bit|DV_I_51_0_bit|DV_II_45_0_bit|DV_II_50_0_bit)); + mask &= (((((W[40]^W[41])>>29)&1)-1) | ~(DV_I_44_0_bit|DV_I_47_0_bit|DV_I_48_0_bit|DV_II_46_0_bit|DV_II_47_0_bit|DV_II_56_0_bit)); + mask &= (((((W[54]^W[55])>>29)&1)-1) | ~(DV_I_51_0_bit|DV_II_47_0_bit|DV_II_50_0_bit|DV_II_55_0_bit|DV_II_56_0_bit)); + mask &= (((((W[53]^W[54])>>29)&1)-1) | ~(DV_I_50_0_bit|DV_II_46_0_bit|DV_II_49_0_bit|DV_II_54_0_bit|DV_II_55_0_bit)); + mask &= (((((W[52]^W[53])>>29)&1)-1) | ~(DV_I_49_0_bit|DV_II_45_0_bit|DV_II_48_0_bit|DV_II_53_0_bit|DV_II_54_0_bit)); + mask &= ((((W[50]^(W[53]>>25))&(1<<4))-(1<<4)) | ~(DV_I_50_0_bit|DV_I_52_0_bit|DV_II_46_0_bit|DV_II_48_0_bit|DV_II_54_0_bit)); + mask &= (((((W[50]^W[51])>>29)&1)-1) | ~(DV_I_47_0_bit|DV_II_46_0_bit|DV_II_51_0_bit|DV_II_52_0_bit|DV_II_56_0_bit)); + mask &= ((((W[49]^(W[52]>>25))&(1<<4))-(1<<4)) | ~(DV_I_49_0_bit|DV_I_51_0_bit|DV_II_45_0_bit|DV_II_47_0_bit|DV_II_53_0_bit)); + mask &= ((((W[48]^(W[51]>>25))&(1<<4))-(1<<4)) | ~(DV_I_48_0_bit|DV_I_50_0_bit|DV_I_52_0_bit|DV_II_46_0_bit|DV_II_52_0_bit)); + mask &= (((((W[42]^W[43])>>29)&1)-1) | ~(DV_I_46_0_bit|DV_I_49_0_bit|DV_I_50_0_bit|DV_II_48_0_bit|DV_II_49_0_bit)); + mask &= (((((W[41]^W[42])>>29)&1)-1) | ~(DV_I_45_0_bit|DV_I_48_0_bit|DV_I_49_0_bit|DV_II_47_0_bit|DV_II_48_0_bit)); + mask &= (((((W[40]>>4)^(W[43]>>29))&1)-1) | ~(DV_I_44_0_bit|DV_I_46_0_bit|DV_I_50_0_bit|DV_II_49_0_bit|DV_II_56_0_bit)); + mask &= (((((W[39]>>4)^(W[42]>>29))&1)-1) | ~(DV_I_43_0_bit|DV_I_45_0_bit|DV_I_49_0_bit|DV_II_48_0_bit|DV_II_55_0_bit)); + if (mask & (DV_I_44_0_bit|DV_I_48_0_bit|DV_II_47_0_bit|DV_II_54_0_bit|DV_II_56_0_bit)) + mask &= (((((W[38]>>4)^(W[41]>>29))&1)-1) | ~(DV_I_44_0_bit|DV_I_48_0_bit|DV_II_47_0_bit|DV_II_54_0_bit|DV_II_56_0_bit)); + mask &= (((((W[37]>>4)^(W[40]>>29))&1)-1) | ~(DV_I_43_0_bit|DV_I_47_0_bit|DV_II_46_0_bit|DV_II_53_0_bit|DV_II_55_0_bit)); + if (mask & (DV_I_52_0_bit|DV_II_48_0_bit|DV_II_51_0_bit|DV_II_56_0_bit)) + mask &= (((((W[55]^W[56])>>29)&1)-1) | ~(DV_I_52_0_bit|DV_II_48_0_bit|DV_II_51_0_bit|DV_II_56_0_bit)); + if (mask & (DV_I_52_0_bit|DV_II_48_0_bit|DV_II_50_0_bit|DV_II_56_0_bit)) + mask &= ((((W[52]^(W[55]>>25))&(1<<4))-(1<<4)) | ~(DV_I_52_0_bit|DV_II_48_0_bit|DV_II_50_0_bit|DV_II_56_0_bit)); + if (mask & (DV_I_51_0_bit|DV_II_47_0_bit|DV_II_49_0_bit|DV_II_55_0_bit)) + mask &= ((((W[51]^(W[54]>>25))&(1<<4))-(1<<4)) | ~(DV_I_51_0_bit|DV_II_47_0_bit|DV_II_49_0_bit|DV_II_55_0_bit)); + if (mask & (DV_I_48_0_bit|DV_II_47_0_bit|DV_II_52_0_bit|DV_II_53_0_bit)) + mask &= (((((W[51]^W[52])>>29)&1)-1) | ~(DV_I_48_0_bit|DV_II_47_0_bit|DV_II_52_0_bit|DV_II_53_0_bit)); + if (mask & (DV_I_46_0_bit|DV_I_49_0_bit|DV_II_45_0_bit|DV_II_48_0_bit)) + mask &= (((((W[36]>>4)^(W[40]>>29))&1)-1) | ~(DV_I_46_0_bit|DV_I_49_0_bit|DV_II_45_0_bit|DV_II_48_0_bit)); + if (mask & (DV_I_52_0_bit|DV_II_48_0_bit|DV_II_49_0_bit)) + mask &= ((0-(((W[53]^W[56])>>29)&1)) | ~(DV_I_52_0_bit|DV_II_48_0_bit|DV_II_49_0_bit)); + if (mask & (DV_I_50_0_bit|DV_II_46_0_bit|DV_II_47_0_bit)) + mask &= ((0-(((W[51]^W[54])>>29)&1)) | ~(DV_I_50_0_bit|DV_II_46_0_bit|DV_II_47_0_bit)); + if (mask & (DV_I_49_0_bit|DV_I_51_0_bit|DV_II_45_0_bit)) + mask &= ((0-(((W[50]^W[52])>>29)&1)) | ~(DV_I_49_0_bit|DV_I_51_0_bit|DV_II_45_0_bit)); + if (mask & (DV_I_48_0_bit|DV_I_50_0_bit|DV_I_52_0_bit)) + mask &= ((0-(((W[49]^W[51])>>29)&1)) | ~(DV_I_48_0_bit|DV_I_50_0_bit|DV_I_52_0_bit)); + if (mask & (DV_I_47_0_bit|DV_I_49_0_bit|DV_I_51_0_bit)) + mask &= ((0-(((W[48]^W[50])>>29)&1)) | ~(DV_I_47_0_bit|DV_I_49_0_bit|DV_I_51_0_bit)); + if (mask & (DV_I_46_0_bit|DV_I_48_0_bit|DV_I_50_0_bit)) + mask &= ((0-(((W[47]^W[49])>>29)&1)) | ~(DV_I_46_0_bit|DV_I_48_0_bit|DV_I_50_0_bit)); + if (mask & (DV_I_45_0_bit|DV_I_47_0_bit|DV_I_49_0_bit)) + mask &= ((0-(((W[46]^W[48])>>29)&1)) | ~(DV_I_45_0_bit|DV_I_47_0_bit|DV_I_49_0_bit)); + mask &= ((((W[45]^W[47])&(1<<6))-(1<<6)) | ~(DV_I_47_2_bit|DV_I_49_2_bit|DV_I_51_2_bit)); + if (mask & (DV_I_44_0_bit|DV_I_46_0_bit|DV_I_48_0_bit)) + mask &= ((0-(((W[45]^W[47])>>29)&1)) | ~(DV_I_44_0_bit|DV_I_46_0_bit|DV_I_48_0_bit)); + mask &= (((((W[44]^W[46])>>6)&1)-1) | ~(DV_I_46_2_bit|DV_I_48_2_bit|DV_I_50_2_bit)); + if (mask & (DV_I_43_0_bit|DV_I_45_0_bit|DV_I_47_0_bit)) + mask &= ((0-(((W[44]^W[46])>>29)&1)) | ~(DV_I_43_0_bit|DV_I_45_0_bit|DV_I_47_0_bit)); + mask &= ((0-((W[41]^(W[42]>>5))&(1<<1))) | ~(DV_I_48_2_bit|DV_II_46_2_bit|DV_II_51_2_bit)); + mask &= ((0-((W[40]^(W[41]>>5))&(1<<1))) | ~(DV_I_47_2_bit|DV_I_51_2_bit|DV_II_50_2_bit)); + if (mask & (DV_I_44_0_bit|DV_I_46_0_bit|DV_II_56_0_bit)) + mask &= ((0-(((W[40]^W[42])>>4)&1)) | ~(DV_I_44_0_bit|DV_I_46_0_bit|DV_II_56_0_bit)); + mask &= ((0-((W[39]^(W[40]>>5))&(1<<1))) | ~(DV_I_46_2_bit|DV_I_50_2_bit|DV_II_49_2_bit)); + if (mask & (DV_I_43_0_bit|DV_I_45_0_bit|DV_II_55_0_bit)) + mask &= ((0-(((W[39]^W[41])>>4)&1)) | ~(DV_I_43_0_bit|DV_I_45_0_bit|DV_II_55_0_bit)); + if (mask & (DV_I_44_0_bit|DV_II_54_0_bit|DV_II_56_0_bit)) + mask &= ((0-(((W[38]^W[40])>>4)&1)) | ~(DV_I_44_0_bit|DV_II_54_0_bit|DV_II_56_0_bit)); + if (mask & (DV_I_43_0_bit|DV_II_53_0_bit|DV_II_55_0_bit)) + mask &= ((0-(((W[37]^W[39])>>4)&1)) | ~(DV_I_43_0_bit|DV_II_53_0_bit|DV_II_55_0_bit)); + mask &= ((0-((W[36]^(W[37]>>5))&(1<<1))) | ~(DV_I_47_2_bit|DV_I_50_2_bit|DV_II_46_2_bit)); + if (mask & (DV_I_45_0_bit|DV_I_48_0_bit|DV_II_47_0_bit)) + mask &= (((((W[35]>>4)^(W[39]>>29))&1)-1) | ~(DV_I_45_0_bit|DV_I_48_0_bit|DV_II_47_0_bit)); + if (mask & (DV_I_48_0_bit|DV_II_48_0_bit)) + mask &= ((0-((W[63]^(W[64]>>5))&(1<<0))) | ~(DV_I_48_0_bit|DV_II_48_0_bit)); + if (mask & (DV_I_45_0_bit|DV_II_45_0_bit)) + mask &= ((0-((W[63]^(W[64]>>5))&(1<<1))) | ~(DV_I_45_0_bit|DV_II_45_0_bit)); + if (mask & (DV_I_47_0_bit|DV_II_47_0_bit)) + mask &= ((0-((W[62]^(W[63]>>5))&(1<<0))) | ~(DV_I_47_0_bit|DV_II_47_0_bit)); + if (mask & (DV_I_46_0_bit|DV_II_46_0_bit)) + mask &= ((0-((W[61]^(W[62]>>5))&(1<<0))) | ~(DV_I_46_0_bit|DV_II_46_0_bit)); + mask &= ((0-((W[61]^(W[62]>>5))&(1<<2))) | ~(DV_I_46_2_bit|DV_II_46_2_bit)); + if (mask & (DV_I_45_0_bit|DV_II_45_0_bit)) + mask &= ((0-((W[60]^(W[61]>>5))&(1<<0))) | ~(DV_I_45_0_bit|DV_II_45_0_bit)); + if (mask & (DV_II_51_0_bit|DV_II_54_0_bit)) + mask &= (((((W[58]^W[59])>>29)&1)-1) | ~(DV_II_51_0_bit|DV_II_54_0_bit)); + if (mask & (DV_II_50_0_bit|DV_II_53_0_bit)) + mask &= (((((W[57]^W[58])>>29)&1)-1) | ~(DV_II_50_0_bit|DV_II_53_0_bit)); + if (mask & (DV_II_52_0_bit|DV_II_54_0_bit)) + mask &= ((((W[56]^(W[59]>>25))&(1<<4))-(1<<4)) | ~(DV_II_52_0_bit|DV_II_54_0_bit)); + if (mask & (DV_II_51_0_bit|DV_II_52_0_bit)) + mask &= ((0-(((W[56]^W[59])>>29)&1)) | ~(DV_II_51_0_bit|DV_II_52_0_bit)); + if (mask & (DV_II_49_0_bit|DV_II_52_0_bit)) + mask &= (((((W[56]^W[57])>>29)&1)-1) | ~(DV_II_49_0_bit|DV_II_52_0_bit)); + if (mask & (DV_II_51_0_bit|DV_II_53_0_bit)) + mask &= ((((W[55]^(W[58]>>25))&(1<<4))-(1<<4)) | ~(DV_II_51_0_bit|DV_II_53_0_bit)); + if (mask & (DV_II_50_0_bit|DV_II_52_0_bit)) + mask &= ((((W[54]^(W[57]>>25))&(1<<4))-(1<<4)) | ~(DV_II_50_0_bit|DV_II_52_0_bit)); + if (mask & (DV_II_49_0_bit|DV_II_51_0_bit)) + mask &= ((((W[53]^(W[56]>>25))&(1<<4))-(1<<4)) | ~(DV_II_49_0_bit|DV_II_51_0_bit)); + mask &= ((((W[51]^(W[50]>>5))&(1<<1))-(1<<1)) | ~(DV_I_50_2_bit|DV_II_46_2_bit)); + mask &= ((((W[48]^W[50])&(1<<6))-(1<<6)) | ~(DV_I_50_2_bit|DV_II_46_2_bit)); + if (mask & (DV_I_51_0_bit|DV_I_52_0_bit)) + mask &= ((0-(((W[48]^W[55])>>29)&1)) | ~(DV_I_51_0_bit|DV_I_52_0_bit)); + mask &= ((((W[47]^W[49])&(1<<6))-(1<<6)) | ~(DV_I_49_2_bit|DV_I_51_2_bit)); + mask &= ((((W[48]^(W[47]>>5))&(1<<1))-(1<<1)) | ~(DV_I_47_2_bit|DV_II_51_2_bit)); + mask &= ((((W[46]^W[48])&(1<<6))-(1<<6)) | ~(DV_I_48_2_bit|DV_I_50_2_bit)); + mask &= ((((W[47]^(W[46]>>5))&(1<<1))-(1<<1)) | ~(DV_I_46_2_bit|DV_II_50_2_bit)); + mask &= ((0-((W[44]^(W[45]>>5))&(1<<1))) | ~(DV_I_51_2_bit|DV_II_49_2_bit)); + mask &= ((((W[43]^W[45])&(1<<6))-(1<<6)) | ~(DV_I_47_2_bit|DV_I_49_2_bit)); + mask &= (((((W[42]^W[44])>>6)&1)-1) | ~(DV_I_46_2_bit|DV_I_48_2_bit)); + mask &= ((((W[43]^(W[42]>>5))&(1<<1))-(1<<1)) | ~(DV_II_46_2_bit|DV_II_51_2_bit)); + mask &= ((((W[42]^(W[41]>>5))&(1<<1))-(1<<1)) | ~(DV_I_51_2_bit|DV_II_50_2_bit)); + mask &= ((((W[41]^(W[40]>>5))&(1<<1))-(1<<1)) | ~(DV_I_50_2_bit|DV_II_49_2_bit)); + if (mask & (DV_I_52_0_bit|DV_II_51_0_bit)) + mask &= ((((W[39]^(W[43]>>25))&(1<<4))-(1<<4)) | ~(DV_I_52_0_bit|DV_II_51_0_bit)); + if (mask & (DV_I_51_0_bit|DV_II_50_0_bit)) + mask &= ((((W[38]^(W[42]>>25))&(1<<4))-(1<<4)) | ~(DV_I_51_0_bit|DV_II_50_0_bit)); + if (mask & (DV_I_48_2_bit|DV_I_51_2_bit)) + mask &= ((0-((W[37]^(W[38]>>5))&(1<<1))) | ~(DV_I_48_2_bit|DV_I_51_2_bit)); + if (mask & (DV_I_50_0_bit|DV_II_49_0_bit)) + mask &= ((((W[37]^(W[41]>>25))&(1<<4))-(1<<4)) | ~(DV_I_50_0_bit|DV_II_49_0_bit)); + if (mask & (DV_II_52_0_bit|DV_II_54_0_bit)) + mask &= ((0-((W[36]^W[38])&(1<<4))) | ~(DV_II_52_0_bit|DV_II_54_0_bit)); + mask &= ((0-((W[35]^(W[36]>>5))&(1<<1))) | ~(DV_I_46_2_bit|DV_I_49_2_bit)); + if (mask & (DV_I_51_0_bit|DV_II_47_0_bit)) + mask &= ((((W[35]^(W[39]>>25))&(1<<3))-(1<<3)) | ~(DV_I_51_0_bit|DV_II_47_0_bit)); +if (mask) { + + if (mask & DV_I_43_0_bit) + if ( + !((W[61]^(W[62]>>5)) & (1<<1)) + || !(!((W[59]^(W[63]>>25)) & (1<<5))) + || !((W[58]^(W[63]>>30)) & (1<<0)) + ) mask &= ~DV_I_43_0_bit; + if (mask & DV_I_44_0_bit) + if ( + !((W[62]^(W[63]>>5)) & (1<<1)) + || !(!((W[60]^(W[64]>>25)) & (1<<5))) + || !((W[59]^(W[64]>>30)) & (1<<0)) + ) mask &= ~DV_I_44_0_bit; + if (mask & DV_I_46_2_bit) + mask &= ((~((W[40]^W[42])>>2)) | ~DV_I_46_2_bit); + if (mask & DV_I_47_2_bit) + if ( + !((W[62]^(W[63]>>5)) & (1<<2)) + || !(!((W[41]^W[43]) & (1<<6))) + ) mask &= ~DV_I_47_2_bit; + if (mask & DV_I_48_2_bit) + if ( + !((W[63]^(W[64]>>5)) & (1<<2)) + || !(!((W[48]^(W[49]<<5)) & (1<<6))) + ) mask &= ~DV_I_48_2_bit; + if (mask & DV_I_49_2_bit) + if ( + !(!((W[49]^(W[50]<<5)) & (1<<6))) + || !((W[42]^W[50]) & (1<<1)) + || !(!((W[39]^(W[40]<<5)) & (1<<6))) + || !((W[38]^W[40]) & (1<<1)) + ) mask &= ~DV_I_49_2_bit; + if (mask & DV_I_50_0_bit) + mask &= ((((W[36]^W[37])<<7)) | ~DV_I_50_0_bit); + if (mask & DV_I_50_2_bit) + mask &= ((((W[43]^W[51])<<11)) | ~DV_I_50_2_bit); + if (mask & DV_I_51_0_bit) + mask &= ((((W[37]^W[38])<<9)) | ~DV_I_51_0_bit); + if (mask & DV_I_51_2_bit) + if ( + !(!((W[51]^(W[52]<<5)) & (1<<6))) + || !(!((W[49]^W[51]) & (1<<6))) + || !(!((W[37]^(W[37]>>5)) & (1<<1))) + || !(!((W[35]^(W[39]>>25)) & (1<<5))) + ) mask &= ~DV_I_51_2_bit; + if (mask & DV_I_52_0_bit) + mask &= ((((W[38]^W[39])<<11)) | ~DV_I_52_0_bit); + if (mask & DV_II_46_2_bit) + mask &= ((((W[47]^W[51])<<17)) | ~DV_II_46_2_bit); + if (mask & DV_II_48_0_bit) + if ( + !(!((W[36]^(W[40]>>25)) & (1<<3))) + || !((W[35]^(W[40]<<2)) & (1<<30)) + ) mask &= ~DV_II_48_0_bit; + if (mask & DV_II_49_0_bit) + if ( + !(!((W[37]^(W[41]>>25)) & (1<<3))) + || !((W[36]^(W[41]<<2)) & (1<<30)) + ) mask &= ~DV_II_49_0_bit; + if (mask & DV_II_49_2_bit) + if ( + !(!((W[53]^(W[54]<<5)) & (1<<6))) + || !(!((W[51]^W[53]) & (1<<6))) + || !((W[50]^W[54]) & (1<<1)) + || !(!((W[45]^(W[46]<<5)) & (1<<6))) + || !(!((W[37]^(W[41]>>25)) & (1<<5))) + || !((W[36]^(W[41]>>30)) & (1<<0)) + ) mask &= ~DV_II_49_2_bit; + if (mask & DV_II_50_0_bit) + if ( + !((W[55]^W[58]) & (1<<29)) + || !(!((W[38]^(W[42]>>25)) & (1<<3))) + || !((W[37]^(W[42]<<2)) & (1<<30)) + ) mask &= ~DV_II_50_0_bit; + if (mask & DV_II_50_2_bit) + if ( + !(!((W[54]^(W[55]<<5)) & (1<<6))) + || !(!((W[52]^W[54]) & (1<<6))) + || !((W[51]^W[55]) & (1<<1)) + || !((W[45]^W[47]) & (1<<1)) + || !(!((W[38]^(W[42]>>25)) & (1<<5))) + || !((W[37]^(W[42]>>30)) & (1<<0)) + ) mask &= ~DV_II_50_2_bit; + if (mask & DV_II_51_0_bit) + if ( + !(!((W[39]^(W[43]>>25)) & (1<<3))) + || !((W[38]^(W[43]<<2)) & (1<<30)) + ) mask &= ~DV_II_51_0_bit; + if (mask & DV_II_51_2_bit) + if ( + !(!((W[55]^(W[56]<<5)) & (1<<6))) + || !(!((W[53]^W[55]) & (1<<6))) + || !((W[52]^W[56]) & (1<<1)) + || !((W[46]^W[48]) & (1<<1)) + || !(!((W[39]^(W[43]>>25)) & (1<<5))) + || !((W[38]^(W[43]>>30)) & (1<<0)) + ) mask &= ~DV_II_51_2_bit; + if (mask & DV_II_52_0_bit) + if ( + !(!((W[59]^W[60]) & (1<<29))) + || !(!((W[40]^(W[44]>>25)) & (1<<3))) + || !(!((W[40]^(W[44]>>25)) & (1<<4))) + || !((W[39]^(W[44]<<2)) & (1<<30)) + ) mask &= ~DV_II_52_0_bit; + if (mask & DV_II_53_0_bit) + if ( + !((W[58]^W[61]) & (1<<29)) + || !(!((W[57]^(W[61]>>25)) & (1<<4))) + || !(!((W[41]^(W[45]>>25)) & (1<<3))) + || !(!((W[41]^(W[45]>>25)) & (1<<4))) + ) mask &= ~DV_II_53_0_bit; + if (mask & DV_II_54_0_bit) + if ( + !(!((W[58]^(W[62]>>25)) & (1<<4))) + || !(!((W[42]^(W[46]>>25)) & (1<<3))) + || !(!((W[42]^(W[46]>>25)) & (1<<4))) + ) mask &= ~DV_II_54_0_bit; + if (mask & DV_II_55_0_bit) + if ( + !(!((W[59]^(W[63]>>25)) & (1<<4))) + || !(!((W[57]^(W[59]>>25)) & (1<<4))) + || !(!((W[43]^(W[47]>>25)) & (1<<3))) + || !(!((W[43]^(W[47]>>25)) & (1<<4))) + ) mask &= ~DV_II_55_0_bit; + if (mask & DV_II_56_0_bit) + if ( + !(!((W[60]^(W[64]>>25)) & (1<<4))) + || !(!((W[44]^(W[48]>>25)) & (1<<3))) + || !(!((W[44]^(W[48]>>25)) & (1<<4))) + ) mask &= ~DV_II_56_0_bit; +} + + dvmask[0]=mask; +} + +#ifdef SHA1DC_CUSTOM_TRAILING_INCLUDE_UBC_CHECK_C +#include SHA1DC_CUSTOM_TRAILING_INCLUDE_UBC_CHECK_C +#endif diff --git a/src/hash/sha1dc/ubc_check.h b/src/hash/sha1dc/ubc_check.h new file mode 100644 index 000000000..d7e17dc73 --- /dev/null +++ b/src/hash/sha1dc/ubc_check.h @@ -0,0 +1,52 @@ +/*** +* Copyright 2017 Marc Stevens , Dan Shumow +* Distributed under the MIT Software License. +* See accompanying file LICENSE.txt or copy at +* https://opensource.org/licenses/MIT +***/ + +/* +// this file was generated by the 'parse_bitrel' program in the tools section +// using the data files from directory 'tools/data/3565' +// +// sha1_dvs contains a list of SHA-1 Disturbance Vectors (DV) to check +// dvType, dvK and dvB define the DV: I(K,B) or II(K,B) (see the paper) +// dm[80] is the expanded message block XOR-difference defined by the DV +// testt is the step to do the recompression from for collision detection +// maski and maskb define the bit to check for each DV in the dvmask returned by ubc_check +// +// ubc_check takes as input an expanded message block and verifies the unavoidable bitconditions for all listed DVs +// it returns a dvmask where each bit belonging to a DV is set if all unavoidable bitconditions for that DV have been met +// thus one needs to do the recompression check for each DV that has its bit set +*/ + +#ifndef SHA1DC_UBC_CHECK_H +#define SHA1DC_UBC_CHECK_H + +#if defined(__cplusplus) +extern "C" { +#endif + +#ifndef SHA1DC_NO_STANDARD_INCLUDES +#include +#endif + +#define DVMASKSIZE 1 +typedef struct { int dvType; int dvK; int dvB; int testt; int maski; int maskb; uint32_t dm[80]; } dv_info_t; +extern dv_info_t sha1_dvs[]; +void ubc_check(const uint32_t W[80], uint32_t dvmask[DVMASKSIZE]); + +#define DOSTORESTATE58 +#define DOSTORESTATE65 + +#define CHECK_DVMASK(_DVMASK) (0 != _DVMASK[0]) + +#if defined(__cplusplus) +} +#endif + +#ifdef SHA1DC_CUSTOM_TRAILING_INCLUDE_UBC_CHECK_H +#include SHA1DC_CUSTOM_TRAILING_INCLUDE_UBC_CHECK_H +#endif + +#endif diff --git a/src/hashsig.c b/src/hashsig.c index e99637d8b..bea538349 100644 --- a/src/hashsig.c +++ b/src/hashsig.c @@ -214,7 +214,7 @@ static int hashsig_finalize_hashes(git_hashsig *sig) if (sig->mins.size < HASHSIG_HEAP_MIN_SIZE && !(sig->opt & GIT_HASHSIG_ALLOW_SMALL_FILES)) { giterr_set(GITERR_INVALID, - "File too small for similarity signature calculation"); + "file too small for similarity signature calculation"); return GIT_EBUFS; } @@ -286,7 +286,7 @@ int git_hashsig_create_fromfile( if ((buflen = p_read(fd, buf, sizeof(buf))) <= 0) { if ((error = (int)buflen) < 0) giterr_set(GITERR_OS, - "Read error on '%s' calculating similarity hashes", path); + "read error on '%s' calculating similarity hashes", path); break; } diff --git a/src/idxmap.c b/src/idxmap.c new file mode 100644 index 000000000..45f0c2204 --- /dev/null +++ b/src/idxmap.c @@ -0,0 +1,133 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#include "idxmap.h" + +/* This is __ac_X31_hash_string but with tolower and it takes the entry's stage into account */ +static kh_inline khint_t idxentry_hash(const git_index_entry *e) +{ + const char *s = e->path; + khint_t h = (khint_t)git__tolower(*s); + if (h) for (++s ; *s; ++s) h = (h << 5) - h + (khint_t)git__tolower(*s); + return h + GIT_IDXENTRY_STAGE(e); +} + +#define idxentry_equal(a, b) (GIT_IDXENTRY_STAGE(a) == GIT_IDXENTRY_STAGE(b) && strcmp(a->path, b->path) == 0) +#define idxentry_icase_equal(a, b) (GIT_IDXENTRY_STAGE(a) == GIT_IDXENTRY_STAGE(b) && strcasecmp(a->path, b->path) == 0) + +__KHASH_IMPL(idx, static kh_inline, const git_index_entry *, git_index_entry *, 1, idxentry_hash, idxentry_equal) +__KHASH_IMPL(idxicase, static kh_inline, const git_index_entry *, git_index_entry *, 1, idxentry_hash, idxentry_icase_equal) + +int git_idxmap_alloc(git_idxmap **map) +{ + if ((*map = kh_init(idx)) == NULL) { + giterr_set_oom(); + return -1; + } + + return 0; +} + +int git_idxmap_icase_alloc(git_idxmap_icase **map) +{ + if ((*map = kh_init(idxicase)) == NULL) { + giterr_set_oom(); + return -1; + } + + return 0; +} + +void git_idxmap_insert(git_idxmap *map, const git_index_entry *key, void *value, int *rval) +{ + khiter_t idx = kh_put(idx, map, key, rval); + + if ((*rval) >= 0) { + if ((*rval) == 0) + kh_key(map, idx) = key; + kh_val(map, idx) = value; + } +} + +void git_idxmap_icase_insert(git_idxmap_icase *map, const git_index_entry *key, void *value, int *rval) +{ + khiter_t idx = kh_put(idxicase, map, key, rval); + + if ((*rval) >= 0) { + if ((*rval) == 0) + kh_key(map, idx) = key; + kh_val(map, idx) = value; + } +} + +size_t git_idxmap_lookup_index(git_idxmap *map, const git_index_entry *key) +{ + return kh_get(idx, map, key); +} + +size_t git_idxmap_icase_lookup_index(git_idxmap_icase *map, const git_index_entry *key) +{ + return kh_get(idxicase, map, key); +} + +void *git_idxmap_value_at(git_idxmap *map, size_t idx) +{ + return kh_val(map, idx); +} + +int git_idxmap_valid_index(git_idxmap *map, size_t idx) +{ + return idx != kh_end(map); +} + +int git_idxmap_has_data(git_idxmap *map, size_t idx) +{ + return kh_exist(map, idx); +} + +void git_idxmap_resize(git_idxmap *map, size_t size) +{ + kh_resize(idx, map, size); +} + +void git_idxmap_icase_resize(git_idxmap_icase *map, size_t size) +{ + kh_resize(idxicase, map, size); +} + +void git_idxmap_free(git_idxmap *map) +{ + kh_destroy(idx, map); +} + +void git_idxmap_clear(git_idxmap *map) +{ + kh_clear(idx, map); +} + +void git_idxmap_delete_at(git_idxmap *map, size_t idx) +{ + kh_del(idx, map, idx); +} + +void git_idxmap_icase_delete_at(git_idxmap_icase *map, size_t idx) +{ + kh_del(idxicase, map, idx); +} + +void git_idxmap_delete(git_idxmap *map, const git_index_entry *key) +{ + khiter_t idx = git_idxmap_lookup_index(map, key); + if (git_idxmap_valid_index(map, idx)) + git_idxmap_delete_at(map, idx); +} +void git_idxmap_icase_delete(git_idxmap_icase *map, const git_index_entry *key) +{ + khiter_t idx = git_idxmap_icase_lookup_index(map, key); + if (git_idxmap_valid_index((git_idxmap *)map, idx)) + git_idxmap_icase_delete_at(map, idx); +} diff --git a/src/idxmap.h b/src/idxmap.h index 4122a89fe..dc702c36e 100644 --- a/src/idxmap.h +++ b/src/idxmap.h @@ -26,66 +26,27 @@ typedef khash_t(idxicase) git_idxmap_icase; typedef khiter_t git_idxmap_iter; -/* This is __ac_X31_hash_string but with tolower and it takes the entry's stage into account */ -static kh_inline khint_t idxentry_hash(const git_index_entry *e) -{ - const char *s = e->path; - khint_t h = (khint_t)git__tolower(*s); - if (h) for (++s ; *s; ++s) h = (h << 5) - h + (khint_t)git__tolower(*s); - return h + GIT_IDXENTRY_STAGE(e); -} +int git_idxmap_alloc(git_idxmap **map); +int git_idxmap_icase_alloc(git_idxmap_icase **map); +void git_idxmap_insert(git_idxmap *map, const git_index_entry *key, void *value, int *rval); +void git_idxmap_icase_insert(git_idxmap_icase *map, const git_index_entry *key, void *value, int *rval); -#define idxentry_equal(a, b) (GIT_IDXENTRY_STAGE(a) == GIT_IDXENTRY_STAGE(b) && strcmp(a->path, b->path) == 0) -#define idxentry_icase_equal(a, b) (GIT_IDXENTRY_STAGE(a) == GIT_IDXENTRY_STAGE(b) && strcasecmp(a->path, b->path) == 0) +size_t git_idxmap_lookup_index(git_idxmap *map, const git_index_entry *key); +size_t git_idxmap_icase_lookup_index(git_idxmap_icase *map, const git_index_entry *key); +void *git_idxmap_value_at(git_idxmap *map, size_t idx); +int git_idxmap_valid_index(git_idxmap *map, size_t idx); +int git_idxmap_has_data(git_idxmap *map, size_t idx); -#define GIT__USE_IDXMAP \ - __KHASH_IMPL(idx, static kh_inline, const git_index_entry *, git_index_entry *, 1, idxentry_hash, idxentry_equal) +void git_idxmap_resize(git_idxmap *map, size_t size); +void git_idxmap_icase_resize(git_idxmap_icase *map, size_t size); +void git_idxmap_free(git_idxmap *map); +void git_idxmap_clear(git_idxmap *map); -#define GIT__USE_IDXMAP_ICASE \ - __KHASH_IMPL(idxicase, static kh_inline, const git_index_entry *, git_index_entry *, 1, idxentry_hash, idxentry_icase_equal) +void git_idxmap_delete_at(git_idxmap *map, size_t idx); +void git_idxmap_icase_delete_at(git_idxmap_icase *map, size_t idx); -#define git_idxmap_alloc(hp) \ - ((*(hp) = kh_init(idx)) == NULL) ? giterr_set_oom(), -1 : 0 - -#define git_idxmap_icase_alloc(hp) \ - ((*(hp) = kh_init(idxicase)) == NULL) ? giterr_set_oom(), -1 : 0 - -#define git_idxmap_insert(h, key, val, rval) do { \ - khiter_t __pos = kh_put(idx, h, key, &rval); \ - if (rval >= 0) { \ - if (rval == 0) kh_key(h, __pos) = key; \ - kh_val(h, __pos) = val; \ - } } while (0) - -#define git_idxmap_icase_insert(h, key, val, rval) do { \ - khiter_t __pos = kh_put(idxicase, h, key, &rval); \ - if (rval >= 0) { \ - if (rval == 0) kh_key(h, __pos) = key; \ - kh_val(h, __pos) = val; \ - } } while (0) - -#define git_idxmap_lookup_index(h, k) kh_get(idx, h, k) -#define git_idxmap_icase_lookup_index(h, k) kh_get(idxicase, h, k) -#define git_idxmap_value_at(h, idx) kh_val(h, idx) -#define git_idxmap_valid_index(h, idx) (idx != kh_end(h)) -#define git_idxmap_has_data(h, idx) kh_exist(h, idx) - -#define git_idxmap_resize(h,s) kh_resize(idx, h, s) -#define git_idxmap_free(h) kh_destroy(idx, h), h = NULL -#define git_idxmap_clear(h) kh_clear(idx, h) - -#define git_idxmap_delete_at(h, id) kh_del(idx, h, id) -#define git_idxmap_icase_delete_at(h, id) kh_del(idxicase, h, id) - -#define git_idxmap_delete(h, key) do { \ - khiter_t __pos = git_idxmap_lookup_index(h, key); \ - if (git_idxmap_valid_index(h, __pos)) \ - git_idxmap_delete_at(h, __pos); } while (0) - -#define git_idxmap_icase_delete(h, key) do { \ - khiter_t __pos = git_idxmap_icase_lookup_index(h, key); \ - if (git_idxmap_valid_index(h, __pos)) \ - git_idxmap_icase_delete_at(h, __pos); } while (0) +void git_idxmap_delete(git_idxmap *map, const git_index_entry *key); +void git_idxmap_icase_delete(git_idxmap_icase *map, const git_index_entry *key); #define git_idxmap_begin kh_begin #define git_idxmap_end kh_end diff --git a/src/ignore.c b/src/ignore.c index dcbd5c1ca..c324d4dd4 100644 --- a/src/ignore.c +++ b/src/ignore.c @@ -175,7 +175,7 @@ static int parse_ignore_file( context = attrs->entry->path; if (git_mutex_lock(&attrs->lock) < 0) { - giterr_set(GITERR_OS, "Failed to lock ignore file"); + giterr_set(GITERR_OS, "failed to lock ignore file"); return -1; } @@ -277,8 +277,9 @@ int git_ignore__for_path( { int error = 0; const char *workdir = git_repository_workdir(repo); + git_buf infopath = GIT_BUF_INIT; - assert(ignores && path); + assert(repo && ignores && path); memset(ignores, 0, sizeof(*ignores)); ignores->repo = repo; @@ -322,10 +323,14 @@ int git_ignore__for_path( goto cleanup; } + if ((error = git_repository_item_path(&infopath, + repo, GIT_REPOSITORY_ITEM_INFO)) < 0) + goto cleanup; + /* load .git/info/exclude */ error = push_ignore_file( ignores, &ignores->ign_global, - git_repository_path(repo), GIT_IGNORE_FILE_INREPO); + infopath.ptr, GIT_IGNORE_FILE_INREPO); if (error < 0) goto cleanup; @@ -336,6 +341,7 @@ int git_ignore__for_path( git_repository_attr_cache(repo)->cfg_excl_file); cleanup: + git_buf_free(&infopath); if (error < 0) git_ignore__free(ignores); @@ -503,9 +509,9 @@ int git_ignore_path_is_ignored( unsigned int i; git_attr_file *file; - assert(ignored && pathname); + assert(repo && ignored && pathname); - workdir = repo ? git_repository_workdir(repo) : NULL; + workdir = git_repository_workdir(repo); memset(&path, 0, sizeof(path)); memset(&ignores, 0, sizeof(ignores)); diff --git a/src/ignore.h b/src/ignore.h index d40bd60f9..876c8e0ea 100644 --- a/src/ignore.h +++ b/src/ignore.h @@ -12,7 +12,7 @@ #include "attr_file.h" #define GIT_IGNORE_FILE ".gitignore" -#define GIT_IGNORE_FILE_INREPO "info/exclude" +#define GIT_IGNORE_FILE_INREPO "exclude" #define GIT_IGNORE_FILE_XDG "ignore" /* The git_ignores structure maintains three sets of ignores: diff --git a/src/index.c b/src/index.c index 42579f19a..c29e90fb0 100644 --- a/src/index.c +++ b/src/index.c @@ -27,9 +27,6 @@ #include "git2/config.h" #include "git2/sys/index.h" -GIT__USE_IDXMAP -GIT__USE_IDXMAP_ICASE - #define INSERT_IN_MAP_EX(idx, map, e, err) do { \ if ((idx)->ignore_case) \ git_idxmap_icase_insert((khash_t(idxicase) *) (map), (e), (e), (err)); \ @@ -57,10 +54,6 @@ static int index_apply_to_wd_diff(git_index *index, int action, const git_strarr unsigned int flags, git_index_matched_path_cb cb, void *payload); -#define entry_size(type,len) ((offsetof(type, path) + (len) + 8) & ~7) -#define short_entry_size(len) entry_size(struct entry_short, len) -#define long_entry_size(len) entry_size(struct entry_long, len) - #define minimal_entry_size (offsetof(struct entry_short, path)) static const size_t INDEX_FOOTER_SIZE = GIT_OID_RAWSZ; @@ -570,7 +563,7 @@ int git_index_set_caps(git_index *index, int caps) if (!repo) return create_index_error( - -1, "Cannot access repository to set index caps"); + -1, "cannot access repository to set index caps"); if (!git_repository__cvar(&val, repo, GIT_CVAR_IGNORECASE)) index->ignore_case = (val != 0); @@ -639,7 +632,7 @@ int git_index_read(git_index *index, int force) if (!index->index_file_path) return create_index_error(-1, - "Failed to read index: The index is in-memory only"); + "failed to read index: The index is in-memory only"); index->on_disk = git_path_exists(index->index_file_path); @@ -653,7 +646,7 @@ int git_index_read(git_index *index, int force) ((updated = compare_checksum(index)) < 0)) { giterr_set( GITERR_INDEX, - "Failed to read index: '%s' no longer exists", + "failed to read index: '%s' no longer exists", index->index_file_path); return updated; } @@ -765,7 +758,7 @@ int git_index_set_version(git_index *index, unsigned int version) if (version < INDEX_VERSION_NUMBER_LB || version > INDEX_VERSION_NUMBER_UB) { - giterr_set(GITERR_INDEX, "Invalid version number"); + giterr_set(GITERR_INDEX, "invalid version number"); return -1; } @@ -805,7 +798,7 @@ int git_index_write_tree(git_oid *oid, git_index *index) if (repo == NULL) return create_index_error(-1, "Failed to write tree. " - "The index file is not backed up by an existing repository"); + "the index file is not backed up by an existing repository"); return git_tree__write_index(oid, index, repo); } @@ -847,7 +840,7 @@ const git_index_entry *git_index_get_bypath( if (git_idxmap_valid_index(index->entries_map, pos)) return git_idxmap_value_at(index->entries_map, pos); - giterr_set(GITERR_INDEX, "Index does not contain %s", path); + giterr_set(GITERR_INDEX, "index does not contain '%s'", path); return NULL; } @@ -934,7 +927,7 @@ static int index_entry_init( if (INDEX_OWNER(index) == NULL) return create_index_error(-1, - "Could not initialize index entry. " + "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) @@ -1365,7 +1358,7 @@ static int index_insert( error = git_vector_insert_sorted(&index->entries, entry, index_no_dups); if (error == 0) { - INSERT_IN_MAP(index, entry, error); + INSERT_IN_MAP(index, entry, &error); } } @@ -1423,7 +1416,7 @@ int git_index_add_frombuffer( if (INDEX_OWNER(index) == NULL) return create_index_error(-1, - "Could not initialize index entry. " + "could not initialize index entry. " "Index is not backed up by an existing repository."); if (!valid_filemode(source_entry->mode)) { @@ -1592,7 +1585,7 @@ int git_index__fill(git_index *index, const git_vector *source_entries) if ((ret = git_vector_insert(&index->entries, entry)) < 0) break; - INSERT_IN_MAP(index, entry, ret); + INSERT_IN_MAP(index, entry, &ret); if (ret < 0) break; } @@ -1637,7 +1630,7 @@ int git_index_remove(git_index *index, const char *path, int stage) if (index_find(&position, index, path, 0, stage) < 0) { giterr_set( - GITERR_INDEX, "Index does not contain %s at stage %d", path, stage); + GITERR_INDEX, "index does not contain %s at stage %d", path, stage); error = GIT_ENOTFOUND; } else { error = index_remove_entry(index, position); @@ -1709,7 +1702,7 @@ int git_index_find(size_t *at_pos, git_index *index, const char *path) if (git_vector_bsearch2( &pos, &index->entries, index->entries_search_path, path) < 0) { - giterr_set(GITERR_INDEX, "Index does not contain %s", path); + giterr_set(GITERR_INDEX, "index does not contain %s", path); return GIT_ENOTFOUND; } @@ -2153,7 +2146,7 @@ void git_index_reuc_clear(git_index *index) static int index_error_invalid(const char *message) { - giterr_set(GITERR_INDEX, "Invalid data in index - %s", message); + giterr_set(GITERR_INDEX, "invalid data in index - %s", message); return -1; } @@ -2285,12 +2278,29 @@ out_err: return 0; } +static size_t index_entry_size(size_t path_len, size_t varint_len, uint32_t flags) +{ + if (varint_len) { + if (flags & GIT_IDXENTRY_EXTENDED) + return offsetof(struct entry_long, path) + path_len + 1 + varint_len; + else + return offsetof(struct entry_short, path) + path_len + 1 + varint_len; + } else { +#define entry_size(type,len) ((offsetof(type, path) + (len) + 8) & ~7) + if (flags & GIT_IDXENTRY_EXTENDED) + return entry_size(struct entry_long, path_len); + else + return entry_size(struct entry_short, path_len); +#undef entry_size + } +} + static size_t read_entry( git_index_entry **out, git_index *index, const void *buffer, size_t buffer_size, - const char **last) + const char *last) { size_t path_length, entry_size; const char *path_ptr; @@ -2347,35 +2357,34 @@ static size_t read_entry( path_length = path_end - path_ptr; } - if (entry.flags & GIT_IDXENTRY_EXTENDED) - entry_size = long_entry_size(path_length); - else - entry_size = short_entry_size(path_length); - - if (INDEX_FOOTER_SIZE + entry_size > buffer_size) - return 0; - + entry_size = index_entry_size(path_length, 0, entry.flags); entry.path = (char *)path_ptr; } else { size_t varint_len; - size_t shared = git_decode_varint((const unsigned char *)path_ptr, - &varint_len); - size_t len = strlen(path_ptr + varint_len); - size_t last_len = strlen(*last); - size_t tmp_path_len; + size_t strip_len = git_decode_varint((const unsigned char *)path_ptr, + &varint_len); + size_t last_len = strlen(last); + size_t prefix_len = last_len - strip_len; + size_t suffix_len = strlen(path_ptr + varint_len); + size_t path_len; if (varint_len == 0) return index_error_invalid("incorrect prefix length"); - GITERR_CHECK_ALLOC_ADD(&tmp_path_len, shared, len + 1); - tmp_path = git__malloc(tmp_path_len); + GITERR_CHECK_ALLOC_ADD(&path_len, prefix_len, suffix_len); + GITERR_CHECK_ALLOC_ADD(&path_len, path_len, 1); + tmp_path = git__malloc(path_len); GITERR_CHECK_ALLOC(tmp_path); - memcpy(tmp_path, last, last_len); - memcpy(tmp_path + last_len, path_ptr + varint_len, len); - entry_size = long_entry_size(shared + len); + + memcpy(tmp_path, last, prefix_len); + memcpy(tmp_path + prefix_len, path_ptr + varint_len, suffix_len + 1); + entry_size = index_entry_size(suffix_len, varint_len, entry.flags); entry.path = tmp_path; } + if (INDEX_FOOTER_SIZE + entry_size > buffer_size) + return 0; + if (index_entry_dup(out, index, &entry) < 0) { git__free(tmp_path); return 0; @@ -2448,7 +2457,7 @@ static int parse_index(git_index *index, const char *buffer, size_t buffer_size) unsigned int i; struct index_header header = { 0 }; git_oid checksum_calculated, checksum_expected; - const char **last = NULL; + const char *last = NULL; const char *empty = ""; #define seek_forward(_increase) { \ @@ -2472,16 +2481,16 @@ static int parse_index(git_index *index, const char *buffer, size_t buffer_size) index->version = header.version; if (index->version >= INDEX_VERSION_NUMBER_COMP) - last = ∅ + last = empty; seek_forward(INDEX_HEADER_SIZE); assert(!index->entries.length); if (index->ignore_case) - kh_resize(idxicase, (khash_t(idxicase) *) index->entries_map, header.entry_count); + git_idxmap_icase_resize((khash_t(idxicase) *) index->entries_map, header.entry_count); else - kh_resize(idx, index->entries_map, header.entry_count); + git_idxmap_resize(index->entries_map, header.entry_count); /* Parse all the entries */ for (i = 0; i < header.entry_count && buffer_size > INDEX_FOOTER_SIZE; ++i) { @@ -2499,7 +2508,7 @@ static int parse_index(git_index *index, const char *buffer, size_t buffer_size) goto done; } - INSERT_IN_MAP(index, entry, error); + INSERT_IN_MAP(index, entry, &error); if (error < 0) { index_entry_free(entry); @@ -2507,6 +2516,9 @@ static int parse_index(git_index *index, const char *buffer, size_t buffer_size) } error = 0; + if (index->version >= INDEX_VERSION_NUMBER_COMP) + last = entry->path; + seek_forward(entry_size); } @@ -2577,11 +2589,12 @@ static bool is_index_extended(git_index *index) return (extended > 0); } -static int write_disk_entry(git_filebuf *file, git_index_entry *entry, const char **last) +static int write_disk_entry(git_filebuf *file, git_index_entry *entry, const char *last) { void *mem = NULL; struct entry_short *ondisk; size_t path_len, disk_size; + int varint_len = 0; char *path; const char *path_start = entry->path; size_t same_len = 0; @@ -2589,7 +2602,7 @@ static int write_disk_entry(git_filebuf *file, git_index_entry *entry, const cha path_len = ((struct entry_internal *)entry)->pathlen; if (last) { - const char *last_c = *last; + const char *last_c = last; while (*path_start == *last_c) { if (!*path_start || !*last_c) @@ -2599,13 +2612,10 @@ static int write_disk_entry(git_filebuf *file, git_index_entry *entry, const cha ++same_len; } path_len -= same_len; - *last = entry->path; + varint_len = git_encode_varint(NULL, 0, same_len); } - if (entry->flags & GIT_IDXENTRY_EXTENDED) - disk_size = long_entry_size(path_len); - else - disk_size = short_entry_size(path_len); + disk_size = index_entry_size(path_len, varint_len, entry->flags); if (git_filebuf_reserve(file, &mem, disk_size) < 0) return -1; @@ -2645,16 +2655,34 @@ static int write_disk_entry(git_filebuf *file, git_index_entry *entry, const cha ondisk_ext->flags_extended = htons(entry->flags_extended & GIT_IDXENTRY_EXTENDED_FLAGS); path = ondisk_ext->path; - } - else + disk_size -= offsetof(struct entry_long, path); + } else { path = ondisk->path; + disk_size -= offsetof(struct entry_short, path); + } if (last) { - path += git_encode_varint((unsigned char *) path, - disk_size, - path_len - same_len); + varint_len = git_encode_varint((unsigned char *) path, + disk_size, same_len); + assert(varint_len > 0); + path += varint_len; + disk_size -= varint_len; + + /* + * If using path compression, we are not allowed + * to have additional trailing NULs. + */ + assert(disk_size == path_len + 1); + } else { + /* + * If no path compression is used, we do have + * NULs as padding. As such, simply assert that + * we have enough space left to write the path. + */ + assert(disk_size > path_len); } - memcpy(path, path_start, path_len); + + memcpy(path, path_start, path_len + 1); return 0; } @@ -2665,8 +2693,7 @@ static int write_entries(git_index *index, git_filebuf *file) size_t i; git_vector case_sorted, *entries; git_index_entry *entry; - const char **last = NULL; - const char *empty = ""; + const char *last = NULL; /* If index->entries is sorted case-insensitively, then we need * to re-sort it case-sensitively before writing */ @@ -2679,11 +2706,14 @@ static int write_entries(git_index *index, git_filebuf *file) } if (index->version >= INDEX_VERSION_NUMBER_COMP) - last = ∅ + last = ""; - git_vector_foreach(entries, i, entry) + git_vector_foreach(entries, i, entry) { if ((error = write_disk_entry(file, entry, last)) < 0) break; + if (index->version >= INDEX_VERSION_NUMBER_COMP) + last = entry->path; + } if (index->ignore_case) git_vector_free(&case_sorted); @@ -2979,12 +3009,12 @@ int git_index_read_tree(git_index *index, const git_tree *tree) goto cleanup; if (index->ignore_case) - kh_resize(idxicase, (khash_t(idxicase) *) entries_map, entries.length); + git_idxmap_icase_resize((khash_t(idxicase) *) entries_map, entries.length); else - kh_resize(idx, entries_map, entries.length); + git_idxmap_resize(entries_map, entries.length); git_vector_foreach(&entries, i, e) { - INSERT_IN_MAP_EX(index, entries_map, e, error); + INSERT_IN_MAP_EX(index, entries_map, e, &error); if (error < 0) { giterr_set(GITERR_INDEX, "failed to insert entry into map"); @@ -3037,9 +3067,9 @@ static int git_index_read_iterator( goto done; if (index->ignore_case && new_length_hint) - kh_resize(idxicase, (khash_t(idxicase) *) new_entries_map, new_length_hint); + git_idxmap_icase_resize((khash_t(idxicase) *) new_entries_map, new_length_hint); else if (new_length_hint) - kh_resize(idx, new_entries_map, new_length_hint); + git_idxmap_resize(new_entries_map, new_length_hint); opts.flags = GIT_ITERATOR_DONT_IGNORE_CASE | GIT_ITERATOR_INCLUDE_CONFLICTS; @@ -3103,7 +3133,7 @@ static int git_index_read_iterator( if (add_entry) { if ((error = git_vector_insert(&new_entries, add_entry)) == 0) - INSERT_IN_MAP_EX(index, new_entries_map, add_entry, error); + INSERT_IN_MAP_EX(index, new_entries_map, add_entry, &error); } if (remove_entry && error >= 0) @@ -3390,7 +3420,7 @@ static int index_apply_to_all( i--; /* back up foreach if we removed this */ break; default: - giterr_set(GITERR_INVALID, "Unknown index action %d", action); + giterr_set(GITERR_INVALID, "unknown index action %d", action); error = -1; break; } @@ -3475,13 +3505,13 @@ int git_indexwriter_init( if (!index->index_file_path) return create_index_error(-1, - "Failed to write index: The index is in-memory only"); + "failed to write index: The index is in-memory only"); if ((error = git_filebuf_open( &writer->file, index->index_file_path, GIT_FILEBUF_HASH_CONTENTS, GIT_INDEX_FILE_MODE)) < 0) { if (error == GIT_ELOCKED) - giterr_set(GITERR_INDEX, "The index is locked. This might be due to a concurrent or crashed process"); + giterr_set(GITERR_INDEX, "the index is locked; this might be due to a concurrent or crashed process"); return error; } @@ -3530,7 +3560,7 @@ int git_indexwriter_commit(git_indexwriter *writer) if ((error = git_futils_filestamp_check( &writer->index->stamp, writer->index->index_file_path)) < 0) { - giterr_set(GITERR_OS, "Could not read index timestamp"); + giterr_set(GITERR_OS, "could not read index timestamp"); return -1; } diff --git a/src/indexer.c b/src/indexer.c index a3a866989..15f6cc2c4 100644 --- a/src/indexer.c +++ b/src/indexer.c @@ -17,8 +17,7 @@ #include "oid.h" #include "oidmap.h" #include "zstream.h" - -GIT__USE_OIDMAP +#include "object.h" extern git_mutex git__mwindow_mutex; @@ -33,9 +32,10 @@ struct entry { struct git_indexer { unsigned int parsed_header :1, - opened_pack :1, + pack_committed :1, have_stream :1, - have_delta :1; + have_delta :1, + do_fsync :1; struct git_pack_header hdr; struct git_pack_file *pack; unsigned int mode; @@ -83,12 +83,12 @@ static int parse_header(struct git_pack_header *hdr, struct git_pack_file *pack) /* Verify we recognize this pack file format. */ if (hdr->hdr_signature != ntohl(PACK_SIGNATURE)) { - giterr_set(GITERR_INDEXER, "Wrong pack signature"); + giterr_set(GITERR_INDEXER, "wrong pack signature"); return -1; } if (!pack_version_ok(hdr->hdr_version)) { - giterr_set(GITERR_INDEXER, "Wrong pack version"); + giterr_set(GITERR_INDEXER, "wrong pack version"); return -1; } @@ -125,6 +125,9 @@ int git_indexer_new( git_hash_ctx_init(&idx->hash_ctx); git_hash_ctx_init(&idx->trailer); + if (git_repository__fsync_gitdir) + idx->do_fsync = 1; + error = git_buf_joinpath(&path, prefix, suff); if (error < 0) goto cleanup; @@ -151,12 +154,23 @@ cleanup: if (fd != -1) p_close(fd); + if (git_buf_len(&tmp_path) > 0) + p_unlink(git_buf_cstr(&tmp_path)); + + if (idx->pack != NULL) + p_unlink(idx->pack->pack_name); + git_buf_free(&path); git_buf_free(&tmp_path); git__free(idx); return -1; } +void git_indexer__set_fsync(git_indexer *idx, int do_fsync) +{ + idx->do_fsync = !!do_fsync; +} + /* Try to store the delta so we can try to resolve it later */ static int store_delta(git_indexer *idx) { @@ -288,7 +302,7 @@ static int store_object(git_indexer *idx) git_oid_cpy(&pentry->sha1, &oid); pentry->offset = entry_start; - k = kh_put(oid, idx->pack->idx_cache, &pentry->sha1, &error); + k = git_oidmap_put(idx->pack->idx_cache, &pentry->sha1, &error); if (error == -1) { git__free(pentry); giterr_set_oom(); @@ -302,7 +316,7 @@ static int store_object(git_indexer *idx) } - kh_value(idx->pack->idx_cache, k) = pentry; + git_oidmap_set_value_at(idx->pack->idx_cache, k, pentry); git_oid_cpy(&entry->oid, &oid); @@ -327,9 +341,7 @@ on_error: GIT_INLINE(bool) has_entry(git_indexer *idx, git_oid *id) { - khiter_t k; - k = kh_get(oid, idx->pack->idx_cache, id); - return (k != kh_end(idx->pack->idx_cache)); + return git_oidmap_exists(idx->pack->idx_cache, id); } static int save_entry(git_indexer *idx, struct entry *entry, struct git_pack_entry *pentry, git_off_t entry_start) @@ -345,14 +357,14 @@ static int save_entry(git_indexer *idx, struct entry *entry, struct git_pack_ent } pentry->offset = entry_start; - k = kh_put(oid, idx->pack->idx_cache, &pentry->sha1, &error); + k = git_oidmap_put(idx->pack->idx_cache, &pentry->sha1, &error); if (error <= 0) { giterr_set(GITERR_INDEXER, "cannot insert object into pack"); return -1; } - kh_value(idx->pack->idx_cache, k) = pentry; + git_oidmap_set_value_at(idx->pack->idx_cache, k, pentry); /* Add the object to the list */ if (git_vector_insert(&idx->objects, entry) < 0) @@ -376,7 +388,7 @@ static int hash_and_save(git_indexer *idx, git_rawobj *obj, git_off_t entry_star GITERR_CHECK_ALLOC(entry); if (git_odb__hashobj(&oid, obj) < 0) { - giterr_set(GITERR_INDEXER, "Failed to hash object"); + giterr_set(GITERR_INDEXER, "failed to hash object"); goto on_error; } @@ -477,13 +489,29 @@ static int write_at(git_indexer *idx, const void *data, git_off_t offset, size_t static int append_to_pack(git_indexer *idx, const void *data, size_t size) { + git_off_t new_size; + size_t mmap_alignment; + size_t page_offset; + git_off_t page_start; git_off_t current_size = idx->pack->mwf.size; int fd = idx->pack->mwf.fd; + int error; if (!size) return 0; - if (p_lseek(fd, current_size + size - 1, SEEK_SET) < 0 || + if ((error = git__mmap_alignment(&mmap_alignment)) < 0) + return error; + + /* Write a single byte to force the file system to allocate space now or + * report an error, since we can't report errors when writing using mmap. + * Round the size up to the nearest page so that we only need to perform file + * I/O when we add a page, instead of whenever we write even a single byte. */ + new_size = current_size + size; + page_offset = new_size % mmap_alignment; + page_start = new_size - page_offset; + + if (p_lseek(fd, page_start + mmap_alignment - 1, SEEK_SET) < 0 || p_write(idx->pack->mwf.fd, data, 1) < 0) { giterr_set(GITERR_OS, "cannot extend packfile '%s'", idx->pack->pack_name); return -1; @@ -909,7 +937,6 @@ int git_indexer_commit(git_indexer *idx, git_transfer_progress *stats) git_buf filename = GIT_BUF_INIT; struct entry *entry; git_oid trailer_hash, file_hash; - git_hash_ctx ctx; git_filebuf index_file = {0}; void *packfile_trailer; @@ -918,9 +945,6 @@ int git_indexer_commit(git_indexer *idx, git_transfer_progress *stats) return -1; } - if (git_hash_ctx_init(&ctx) < 0) - return -1; - /* Test for this before resolve_deltas(), as it plays with idx->off */ if (idx->off + 20 < idx->pack->mwf.size) { giterr_set(GITERR_INDEXER, "unexpected data at the end of the pack"); @@ -964,6 +988,10 @@ int git_indexer_commit(git_indexer *idx, git_transfer_progress *stats) git_vector_sort(&idx->objects); + /* Use the trailer hash as the pack file name to ensure + * files with different contents have different names */ + git_oid_cpy(&idx->hash, &trailer_hash); + git_buf_sets(&filename, idx->pack->pack_name); git_buf_shorten(&filename, strlen("pack")); git_buf_puts(&filename, "idx"); @@ -971,7 +999,9 @@ int git_indexer_commit(git_indexer *idx, git_transfer_progress *stats) return -1; if (git_filebuf_open(&index_file, filename.ptr, - GIT_FILEBUF_HASH_CONTENTS, idx->mode) < 0) + GIT_FILEBUF_HASH_CONTENTS | + (idx->do_fsync ? GIT_FILEBUF_FSYNC : 0), + idx->mode) < 0) goto on_error; /* Write out the header */ @@ -988,9 +1018,7 @@ int git_indexer_commit(git_indexer *idx, git_transfer_progress *stats) /* Write out the object names (SHA-1 hashes) */ git_vector_foreach(&idx->objects, i, entry) { git_filebuf_write(&index_file, &entry->oid, sizeof(git_oid)); - git_hash_update(&ctx, &entry->oid, GIT_OID_RAWSZ); } - git_hash_final(&idx->hash, &ctx); /* Write out the CRC32 values */ git_vector_foreach(&idx->objects, i, entry) { @@ -1041,6 +1069,18 @@ int git_indexer_commit(git_indexer *idx, git_transfer_progress *stats) goto on_error; git_mwindow_free_all(&idx->pack->mwf); + + /* Truncate file to undo rounding up to next page_size in append_to_pack */ + if (p_ftruncate(idx->pack->mwf.fd, idx->pack->mwf.size) < 0) { + giterr_set(GITERR_OS, "failed to truncate pack file '%s'", idx->pack->pack_name); + return -1; + } + + if (idx->do_fsync && p_fsync(idx->pack->mwf.fd) < 0) { + giterr_set(GITERR_OS, "failed to fsync packfile"); + goto on_error; + } + /* We need to close the descriptor here so Windows doesn't choke on commit_at */ if (p_close(idx->pack->mwf.fd) < 0) { giterr_set(GITERR_OS, "failed to close packfile"); @@ -1053,17 +1093,23 @@ int git_indexer_commit(git_indexer *idx, git_transfer_progress *stats) goto on_error; /* And don't forget to rename the packfile to its new place. */ - p_rename(idx->pack->pack_name, git_buf_cstr(&filename)); + if (p_rename(idx->pack->pack_name, git_buf_cstr(&filename)) < 0) + goto on_error; + + /* And fsync the parent directory if we're asked to. */ + if (idx->do_fsync && + git_futils_fsync_parent(git_buf_cstr(&filename)) < 0) + goto on_error; + + idx->pack_committed = 1; git_buf_free(&filename); - git_hash_ctx_cleanup(&ctx); return 0; on_error: git_mwindow_free_all(&idx->pack->mwf); git_filebuf_cleanup(&index_file); git_buf_free(&filename); - git_hash_ctx_cleanup(&ctx); return -1; } @@ -1074,10 +1120,11 @@ void git_indexer_free(git_indexer *idx) git_vector_free_deep(&idx->objects); - if (idx->pack && idx->pack->idx_cache) { + if (idx->pack->idx_cache) { struct git_pack_entry *pentry; - kh_foreach_value( - idx->pack->idx_cache, pentry, { git__free(pentry); }); + git_oidmap_foreach_value(idx->pack->idx_cache, pentry, { + git__free(pentry); + }); git_oidmap_free(idx->pack->idx_cache); } @@ -1085,6 +1132,9 @@ void git_indexer_free(git_indexer *idx) git_vector_free_deep(&idx->deltas); if (!git_mutex_lock(&git__mwindow_mutex)) { + if (!idx->pack_committed) + git_packfile_close(idx->pack, true); + git_packfile_free(idx->pack); git_mutex_unlock(&git__mwindow_mutex); } diff --git a/src/indexer.h b/src/indexer.h new file mode 100644 index 000000000..702694bbf --- /dev/null +++ b/src/indexer.h @@ -0,0 +1,12 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ +#ifndef INCLUDE_indexer_h__ +#define INCLUDE_indexer_h__ + +extern int git_indexer__set_fsync(git_indexer *idx, int do_fsync); + +#endif diff --git a/src/integer.h b/src/integer.h index b08094c2f..61712cebf 100644 --- a/src/integer.h +++ b/src/integer.h @@ -55,16 +55,16 @@ GIT_INLINE(bool) git__add_uint64_overflow(uint64_t *out, uint64_t one, uint64_t } /* Use clang/gcc compiler intrinsics whenever possible */ -#if (SIZE_MAX == UINT_MAX) && __has_builtin(__builtin_uadd_overflow) -# define git__add_sizet_overflow(out, one, two) \ - __builtin_uadd_overflow(one, two, out) -# define git__multiply_sizet_overflow(out, one, two) \ - __builtin_umul_overflow(one, two, out) -#elif (SIZE_MAX == ULONG_MAX) && __has_builtin(__builtin_uaddl_overflow) +#if (SIZE_MAX == ULONG_MAX) && __has_builtin(__builtin_uaddl_overflow) # define git__add_sizet_overflow(out, one, two) \ __builtin_uaddl_overflow(one, two, out) # define git__multiply_sizet_overflow(out, one, two) \ __builtin_umull_overflow(one, two, out) +#elif (SIZE_MAX == UINT_MAX) && __has_builtin(__builtin_uadd_overflow) +# define git__add_sizet_overflow(out, one, two) \ + __builtin_uadd_overflow(one, two, out) +# define git__multiply_sizet_overflow(out, one, two) \ + __builtin_umul_overflow(one, two, out) #else /** diff --git a/src/merge.c b/src/merge.c index 1142917bd..6e00b5adb 100644 --- a/src/merge.c +++ b/src/merge.c @@ -78,7 +78,7 @@ int merge_bases_many(git_commit_list **out, git_revwalk **walk_out, git_reposito unsigned int i; if (length < 2) { - giterr_set(GITERR_INVALID, "At least two commits are required to find an ancestor. Provided 'length' was %" PRIuZ ".", length); + giterr_set(GITERR_INVALID, "at least two commits are required to find an ancestor"); return -1; } @@ -104,7 +104,7 @@ int merge_bases_many(git_commit_list **out, git_revwalk **walk_out, git_reposito goto on_error; if (!result) { - giterr_set(GITERR_MERGE, "No merge base found"); + giterr_set(GITERR_MERGE, "no merge base found"); error = GIT_ENOTFOUND; goto on_error; } @@ -184,7 +184,7 @@ int git_merge_base_octopus(git_oid *out, git_repository *repo, size_t length, co assert(out && repo && input_array); if (length < 2) { - giterr_set(GITERR_INVALID, "At least two commits are required to find an ancestor. Provided 'length' was %" PRIuZ ".", length); + giterr_set(GITERR_INVALID, "at least two commits are required to find an ancestor"); return -1; } @@ -230,7 +230,7 @@ static int merge_bases(git_commit_list **out, git_revwalk **walk_out, git_reposi if (!result) { git_revwalk_free(walk); - giterr_set(GITERR_MERGE, "No merge base found"); + giterr_set(GITERR_MERGE, "no merge base found"); return GIT_ENOTFOUND; } @@ -562,7 +562,7 @@ int git_repository_mergehead_foreach( assert(repo && cb); - if ((error = git_buf_joinpath(&merge_head_path, repo->path_repository, + if ((error = git_buf_joinpath(&merge_head_path, repo->gitdir, GIT_MERGE_HEAD_FILE)) < 0) return error; @@ -574,7 +574,7 @@ int git_repository_mergehead_foreach( while ((line = git__strsep(&buffer, "\n")) != NULL) { if (strlen(line) != GIT_OID_HEXSZ) { - giterr_set(GITERR_INVALID, "Unable to parse OID - invalid length"); + giterr_set(GITERR_INVALID, "unable to parse OID - invalid length"); error = -1; goto cleanup; } @@ -591,7 +591,7 @@ int git_repository_mergehead_foreach( } if (*buffer) { - giterr_set(GITERR_MERGE, "No EOL at line %"PRIuZ, line_num); + giterr_set(GITERR_MERGE, "no EOL at line %"PRIuZ, line_num); error = -1; goto cleanup; } @@ -1075,7 +1075,7 @@ static int index_entry_similarity_inexact( int score = 0; int error = 0; - if (GIT_MODE_TYPE(a->mode) != GIT_MODE_TYPE(b->mode)) + if (!GIT_MODE_ISBLOB(a->mode) || !GIT_MODE_ISBLOB(b->mode)) return 0; /* update signature cache if needed */ @@ -1713,16 +1713,16 @@ static int merge_normalize_opts( if ((error = git_repository_config__weakptr(&cfg, repo)) < 0) return error; - if (given != NULL) + if (given != NULL) { memcpy(opts, given, sizeof(git_merge_options)); - else { + } else { git_merge_options init = GIT_MERGE_OPTIONS_INIT; memcpy(opts, &init, sizeof(init)); - - opts->flags = GIT_MERGE_FIND_RENAMES; - opts->rename_threshold = GIT_MERGE_DEFAULT_RENAME_THRESHOLD; } + if ((opts->flags & GIT_MERGE_FIND_RENAMES) && !opts->rename_threshold) + opts->rename_threshold = GIT_MERGE_DEFAULT_RENAME_THRESHOLD; + if (given && given->default_driver) { opts->default_driver = git__strdup(given->default_driver); GITERR_CHECK_ALLOC(opts->default_driver); @@ -2018,6 +2018,26 @@ int git_merge_trees( git_iterator_options iter_opts = GIT_ITERATOR_OPTIONS_INIT; int error; + assert(out && repo); + + /* if one side is treesame to the ancestor, take the other side */ + if (ancestor_tree && merge_opts && (merge_opts->flags & GIT_MERGE_SKIP_REUC)) { + const git_tree *result = NULL; + const git_oid *ancestor_tree_id = git_tree_id(ancestor_tree); + + if (our_tree && !git_oid_cmp(ancestor_tree_id, git_tree_id(our_tree))) + result = their_tree; + else if (their_tree && !git_oid_cmp(ancestor_tree_id, git_tree_id(their_tree))) + result = our_tree; + + if (result) { + if ((error = git_index_new(out)) == 0) + error = git_index_read_tree(*out, result); + + return error; + } + } + iter_opts.flags = GIT_ITERATOR_DONT_IGNORE_CASE; if ((error = git_iterator_for_tree( @@ -2277,7 +2297,7 @@ static int write_merge_head( assert(repo && heads); - if ((error = git_buf_joinpath(&file_path, repo->path_repository, GIT_MERGE_HEAD_FILE)) < 0 || + if ((error = git_buf_joinpath(&file_path, repo->gitdir, GIT_MERGE_HEAD_FILE)) < 0 || (error = git_filebuf_open(&file, file_path.ptr, GIT_FILEBUF_FORCE, GIT_MERGE_FILE_MODE)) < 0) goto cleanup; @@ -2305,7 +2325,7 @@ static int write_merge_mode(git_repository *repo) assert(repo); - if ((error = git_buf_joinpath(&file_path, repo->path_repository, GIT_MERGE_MODE_FILE)) < 0 || + if ((error = git_buf_joinpath(&file_path, repo->gitdir, GIT_MERGE_MODE_FILE)) < 0 || (error = git_filebuf_open(&file, file_path.ptr, GIT_FILEBUF_FORCE, GIT_MERGE_FILE_MODE)) < 0) goto cleanup; @@ -2536,7 +2556,7 @@ static int write_merge_msg( for (i = 0; i < heads_len; i++) entries[i].merge_head = heads[i]; - if ((error = git_buf_joinpath(&file_path, repo->path_repository, GIT_MERGE_MSG_FILE)) < 0 || + if ((error = git_buf_joinpath(&file_path, repo->gitdir, GIT_MERGE_MSG_FILE)) < 0 || (error = git_filebuf_open(&file, file_path.ptr, GIT_FILEBUF_FORCE, GIT_MERGE_FILE_MODE)) < 0 || (error = git_filebuf_write(&file, "Merge ", 6)) < 0) goto cleanup; @@ -2914,7 +2934,7 @@ int git_merge__append_conflicts_to_merge_msg( if (!git_index_has_conflicts(index)) return 0; - if ((error = git_buf_joinpath(&file_path, repo->path_repository, GIT_MERGE_MSG_FILE)) < 0 || + if ((error = git_buf_joinpath(&file_path, repo->gitdir, GIT_MERGE_MSG_FILE)) < 0 || (error = git_filebuf_open(&file, file_path.ptr, GIT_FILEBUF_APPEND, GIT_MERGE_FILE_MODE)) < 0) goto cleanup; @@ -3043,7 +3063,7 @@ int git_merge_analysis( assert(analysis_out && preference_out && repo && their_heads); if (their_heads_len != 1) { - giterr_set(GITERR_MERGE, "Can only merge a single branch"); + giterr_set(GITERR_MERGE, "can only merge a single branch"); error = -1; goto done; } @@ -3099,7 +3119,7 @@ int git_merge( assert(repo && their_heads); if (their_heads_len != 1) { - giterr_set(GITERR_MERGE, "Can only merge a single branch"); + giterr_set(GITERR_MERGE, "can only merge a single branch"); return -1; } diff --git a/src/merge_driver.c b/src/merge_driver.c index 88a53ecdb..0f35d23c2 100644 --- a/src/merge_driver.c +++ b/src/merge_driver.c @@ -32,6 +32,35 @@ static struct merge_driver_registry merge_driver_registry; static void git_merge_driver_global_shutdown(void); +const git_repository* git_merge_driver_source_repo(const git_merge_driver_source *src) +{ + assert(src); + return src->repo; +} + +const git_index_entry* git_merge_driver_source_ancestor(const git_merge_driver_source *src) +{ + assert(src); + return src->ancestor; +} + +const git_index_entry* git_merge_driver_source_ours(const git_merge_driver_source *src) +{ + assert(src); + return src->ours; +} + +const git_index_entry* git_merge_driver_source_theirs(const git_merge_driver_source *src) +{ + assert(src); + return src->theirs; +} + +const git_merge_file_options* git_merge_driver_source_file_options(const git_merge_driver_source *src) +{ + assert(src); + return src->file_opts; +} int git_merge_driver__builtin_apply( git_merge_driver *self, diff --git a/src/merge_file.c b/src/merge_file.c index 3f14a4f63..5ecd8f4d0 100644 --- a/src/merge_file.c +++ b/src/merge_file.c @@ -127,7 +127,7 @@ static int merge_file__xdiff( if ((xdl_result = xdl_merge(&ancestor_mmfile, &our_mmfile, &their_mmfile, &xmparam, &mmbuffer)) < 0) { - giterr_set(GITERR_MERGE, "Failed to merge files."); + giterr_set(GITERR_MERGE, "failed to merge files"); error = -1; goto done; } diff --git a/src/mwindow.c b/src/mwindow.c index 8a5b5caee..7bb9dbbe2 100644 --- a/src/mwindow.c +++ b/src/mwindow.c @@ -14,8 +14,6 @@ #include "strmap.h" #include "pack.h" -GIT__USE_STRMAP - #define DEFAULT_WINDOW_SIZE \ (sizeof(void*) >= 8 \ ? 1 * 1024 * 1024 * 1024 \ @@ -84,7 +82,7 @@ int git_mwindow_get_pack(struct git_pack_file **out, const char *path) git_atomic_inc(&pack->refcount); - git_strmap_insert(git__pack_cache, pack->pack_name, pack, error); + git_strmap_insert(git__pack_cache, pack->pack_name, pack, &error); git_mutex_unlock(&git__mwindow_mutex); if (error < 0) { @@ -231,7 +229,7 @@ static int git_mwindow_close_lru(git_mwindow_file *mwf) } if (!lru_w) { - giterr_set(GITERR_OS, "Failed to close memory window. Couldn't find LRU"); + giterr_set(GITERR_OS, "failed to close memory window; couldn't find LRU"); return -1; } diff --git a/src/netops.c b/src/netops.c index 90326ea59..4b73baa0e 100644 --- a/src/netops.c +++ b/src/netops.c @@ -144,7 +144,7 @@ int gitno_connection_data_from_url( default_port = "80"; if (data->use_ssl) { - giterr_set(GITERR_NET, "Redirect from HTTPS to HTTP is not allowed"); + giterr_set(GITERR_NET, "redirect from HTTPS to HTTP is not allowed"); goto cleanup; } } else if (!git__prefixcmp(url, prefix_https)) { @@ -155,7 +155,7 @@ int gitno_connection_data_from_url( default_port = data->use_ssl ? "443" : "80"; if (!default_port) { - giterr_set(GITERR_NET, "Unrecognized URL prefix"); + giterr_set(GITERR_NET, "unrecognized URL prefix"); goto cleanup; } @@ -187,7 +187,7 @@ int gitno_connection_data_from_url( /* Check for errors in the resulting data */ if (original_host && url[0] != '/' && strcmp(original_host, data->host)) { - giterr_set(GITERR_NET, "Cross host redirect not allowed"); + giterr_set(GITERR_NET, "cross host redirect not allowed"); error = -1; } } @@ -237,7 +237,7 @@ int gitno_extract_url_parts( const char *_host, *_port, *_path, *_userinfo; if (http_parser_parse_url(url, strlen(url), false, &u)) { - giterr_set(GITERR_NET, "Malformed URL '%s'", url); + giterr_set(GITERR_NET, "malformed URL '%s'", url); return GIT_EINVALIDSPEC; } diff --git a/src/notes.c b/src/notes.c index fe8d2164f..75108b9c9 100644 --- a/src/notes.c +++ b/src/notes.c @@ -15,7 +15,7 @@ static int note_error_notfound(void) { - giterr_set(GITERR_INVALID, "Note could not be found"); + giterr_set(GITERR_INVALID, "note could not be found"); return GIT_ENOTFOUND; } @@ -226,7 +226,7 @@ static int remove_note_in_tree_enotfound_cb( GIT_UNUSED(note_oid); GIT_UNUSED(fanout); - giterr_set(GITERR_REPOSITORY, "Object '%s' has no note", annotated_object_sha); + giterr_set(GITERR_REPOSITORY, "object '%s' has no note", annotated_object_sha); return current_error; } @@ -244,7 +244,7 @@ static int insert_note_in_tree_eexists_cb(git_tree **out, GIT_UNUSED(note_oid); GIT_UNUSED(fanout); - giterr_set(GITERR_REPOSITORY, "Note for '%s' exists already", annotated_object_sha); + giterr_set(GITERR_REPOSITORY, "note for '%s' exists already", annotated_object_sha); return current_error; } diff --git a/src/object.c b/src/object.c index 1d45f9f1b..2da36a2ee 100644 --- a/src/object.c +++ b/src/object.c @@ -66,12 +66,12 @@ int git_object__from_odb_object( /* Validate type match */ if (type != GIT_OBJ_ANY && type != odb_obj->cached.type) { giterr_set(GITERR_INVALID, - "The requested type does not match the type in the ODB"); + "the requested type does not match the type in the ODB"); return GIT_ENOTFOUND; } if ((object_size = git_object__size(odb_obj->cached.type)) == 0) { - giterr_set(GITERR_INVALID, "The requested type is invalid"); + giterr_set(GITERR_INVALID, "the requested type is invalid"); return GIT_ENOTFOUND; } @@ -122,7 +122,7 @@ int git_object_lookup_prefix( assert(repo && object_out && id); if (len < GIT_OID_MINPREFIXLEN) { - giterr_set(GITERR_OBJECT, "Ambiguous lookup - OID prefix is too short"); + giterr_set(GITERR_OBJECT, "ambiguous lookup - OID prefix is too short"); return GIT_EAMBIGUOUS; } @@ -147,7 +147,7 @@ int git_object_lookup_prefix( if (type != GIT_OBJ_ANY && type != object->cached.type) { git_object_free(object); giterr_set(GITERR_INVALID, - "The requested type does not match the type in ODB"); + "the requested type does not match the type in ODB"); return GIT_ENOTFOUND; } @@ -292,7 +292,7 @@ static int peel_error(int error, const git_oid *oid, git_otype type) git_oid_fmt(hex_oid, oid); hex_oid[GIT_OID_HEXSZ] = '\0'; - giterr_set(GITERR_OBJECT, "The git_object of id '%s' can not be " + giterr_set(GITERR_OBJECT, "the git_object of id '%s' can not be " "successfully peeled into a %s (git_otype=%i).", hex_oid, type_name, type); return error; diff --git a/src/odb.c b/src/odb.c index 7b194c70f..ae8f247e3 100644 --- a/src/odb.c +++ b/src/odb.c @@ -31,6 +31,8 @@ #define GIT_ALTERNATES_MAX_DEPTH 5 +bool git_odb__strict_hash_verification = true; + typedef struct { git_odb_backend *backend; @@ -176,7 +178,7 @@ int git_odb__hashfd(git_oid *out, git_file fd, size_t size, git_otype type) int error = 0; if (!git_object_typeisloose(type)) { - giterr_set(GITERR_INVALID, "Invalid object type for hash"); + giterr_set(GITERR_INVALID, "invalid object type for hash"); return -1; } @@ -199,7 +201,7 @@ int git_odb__hashfd(git_oid *out, git_file fd, size_t size, git_otype type) * If size is not zero, the file was truncated after we originally * stat'd it, so we consider this a read failure too */ if (read_len < 0 || size > 0) { - giterr_set(GITERR_OS, "Error reading file for hashing"); + giterr_set(GITERR_OS, "error reading file for hashing"); error = -1; goto done; @@ -251,7 +253,7 @@ int git_odb__hashlink(git_oid *out, const char *path) return -1; if (!git__is_int(st.st_size) || (int)st.st_size < 0) { - giterr_set(GITERR_FILESYSTEM, "File size overflow for 32-bit systems"); + giterr_set(GITERR_FILESYSTEM, "file size overflow for 32-bit systems"); return -1; } @@ -269,7 +271,7 @@ int git_odb__hashlink(git_oid *out, const char *path) read_len = p_readlink(path, link_data, size); link_data[size] = '\0'; if (read_len != size) { - giterr_set(GITERR_OS, "Failed to read symlink data for '%s'", path); + giterr_set(GITERR_OS, "failed to read symlink data for '%s'", path); git__free(link_data); return -1; } @@ -295,7 +297,7 @@ int git_odb_hashfile(git_oid *out, const char *path, git_otype type) return fd; if ((size = git_futils_filesize(fd)) < 0 || !git__is_sizet(size)) { - giterr_set(GITERR_OS, "File size overflow for 32-bit systems"); + giterr_set(GITERR_OS, "file size overflow for 32-bit systems"); p_close(fd); return -1; } @@ -475,7 +477,7 @@ size_t git_odb_num_backends(git_odb *odb) static int git_odb__error_unsupported_in_backend(const char *action) { giterr_set(GITERR_ODB, - "Cannot %s - unsupported in the loaded odb backends", action); + "cannot %s - unsupported in the loaded odb backends", action); return -1; } @@ -492,11 +494,11 @@ int git_odb_get_backend(git_odb_backend **out, git_odb *odb, size_t pos) return 0; } - giterr_set(GITERR_ODB, "No ODB backend loaded at index %" PRIuZ, pos); + giterr_set(GITERR_ODB, "no ODB backend loaded at index %" PRIuZ, pos); return GIT_ENOTFOUND; } -static int add_default_backends( +int git_odb__add_default_backends( git_odb *db, const char *objects_dir, bool as_alternates, int alternate_depth) { @@ -517,7 +519,7 @@ static int add_default_backends( if (as_alternates) return 0; - giterr_set(GITERR_ODB, "Failed to load object database in '%s'", objects_dir); + giterr_set(GITERR_ODB, "failed to load object database in '%s'", objects_dir); return -1; } @@ -531,7 +533,7 @@ static int add_default_backends( #endif /* add the loose object backend */ - if (git_odb_backend_loose(&loose, objects_dir, -1, 0, 0, 0) < 0 || + if (git_odb_backend_loose(&loose, objects_dir, -1, db->do_fsync, 0, 0) < 0 || add_backend_internal(db, loose, GIT_LOOSE_PRIORITY, as_alternates, inode) < 0) return -1; @@ -586,7 +588,7 @@ static int load_alternates(git_odb *odb, const char *objects_dir, int alternate_ alternate = git_buf_cstr(&alternates_path); } - if ((result = add_default_backends(odb, alternate, true, alternate_depth + 1)) < 0) + if ((result = git_odb__add_default_backends(odb, alternate, true, alternate_depth + 1)) < 0) break; } @@ -598,7 +600,7 @@ static int load_alternates(git_odb *odb, const char *objects_dir, int alternate_ int git_odb_add_disk_alternate(git_odb *odb, const char *path) { - return add_default_backends(odb, path, true, 0); + return git_odb__add_default_backends(odb, path, true, 0); } int git_odb_open(git_odb **out, const char *objects_dir) @@ -612,7 +614,7 @@ int git_odb_open(git_odb **out, const char *objects_dir) if (git_odb_new(&db) < 0) return -1; - if (add_default_backends(db, objects_dir, 0, 0) < 0) { + if (git_odb__add_default_backends(db, objects_dir, 0, 0) < 0) { git_odb_free(db); return -1; } @@ -621,6 +623,24 @@ int git_odb_open(git_odb **out, const char *objects_dir) return 0; } +int git_odb__set_caps(git_odb *odb, int caps) +{ + if (caps == GIT_ODB_CAP_FROM_OWNER) { + git_repository *repo = odb->rc.owner; + int val; + + if (!repo) { + giterr_set(GITERR_ODB, "cannot access repository to set odb caps"); + return -1; + } + + if (!git_repository__cvar(&val, repo, GIT_CVAR_FSYNCOBJECTFILES)) + odb->do_fsync = !!val; + } + + return 0; +} + static void odb_free(git_odb *db) { size_t i; @@ -695,7 +715,7 @@ static int odb_freshen_1( return (int)found; } -static int odb_freshen(git_odb *db, const git_oid *id) +int git_odb__freshen(git_odb *db, const git_oid *id) { assert(db && id); @@ -980,7 +1000,9 @@ static int odb_read_1(git_odb_object **out, git_odb *db, const git_oid *id, size_t i; git_rawobj raw; git_odb_object *object; + git_oid hashed; bool found = false; + int error = 0; if (!only_refreshed && odb_read_hardcoded(&raw, id) == 0) found = true; @@ -993,7 +1015,7 @@ static int odb_read_1(git_odb_object **out, git_odb *db, const git_oid *id, continue; if (b->read != NULL) { - int error = b->read(&raw.data, &raw.len, &raw.type, b, id); + error = b->read(&raw.data, &raw.len, &raw.type, b, id); if (error == GIT_PASSTHROUGH || error == GIT_ENOTFOUND) continue; @@ -1007,12 +1029,26 @@ static int odb_read_1(git_odb_object **out, git_odb *db, const git_oid *id, if (!found) return GIT_ENOTFOUND; + if (git_odb__strict_hash_verification) { + if ((error = git_odb_hash(&hashed, raw.data, raw.len, raw.type)) < 0) + goto out; + + if (!git_oid_equal(id, &hashed)) { + error = git_odb__error_mismatch(id, &hashed); + goto out; + } + } + giterr_clear(); if ((object = odb_object__alloc(id, &raw)) == NULL) - return -1; + goto out; *out = git_cache_store_raw(odb_cache(db), object); - return 0; + +out: + if (error) + git__free(raw.data); + return error; } int git_odb_read(git_odb_object **out, git_odb *db, const git_oid *id) @@ -1063,9 +1099,9 @@ static int read_prefix_1(git_odb_object **out, git_odb *db, const git_oid *key, size_t len, bool only_refreshed) { size_t i; - int error = GIT_ENOTFOUND; + int error = 0; git_oid found_full_oid = {{0}}; - git_rawobj raw; + git_rawobj raw = {0}; void *data = NULL; bool found = false; git_odb_object *object; @@ -1080,18 +1116,29 @@ static int read_prefix_1(git_odb_object **out, git_odb *db, if (b->read_prefix != NULL) { git_oid full_oid; error = b->read_prefix(&full_oid, &raw.data, &raw.len, &raw.type, b, key, len); - if (error == GIT_ENOTFOUND || error == GIT_PASSTHROUGH) + + if (error == GIT_ENOTFOUND || error == GIT_PASSTHROUGH) { + error = 0; continue; + } if (error) - return error; + goto out; git__free(data); data = raw.data; if (found && git_oid__cmp(&full_oid, &found_full_oid)) { - git__free(raw.data); - return git_odb__error_ambiguous("multiple matches for prefix"); + git_buf buf = GIT_BUF_INIT; + + git_buf_printf(&buf, "multiple matches for prefix: %s", + git_oid_tostr_s(&full_oid)); + git_buf_printf(&buf, " %s", + git_oid_tostr_s(&found_full_oid)); + + error = git_odb__error_ambiguous(buf.ptr); + git_buf_free(&buf); + goto out; } found_full_oid = full_oid; @@ -1102,11 +1149,28 @@ static int read_prefix_1(git_odb_object **out, git_odb *db, if (!found) return GIT_ENOTFOUND; + if (git_odb__strict_hash_verification) { + git_oid hash; + + if ((error = git_odb_hash(&hash, raw.data, raw.len, raw.type)) < 0) + goto out; + + if (!git_oid_equal(&found_full_oid, &hash)) { + error = git_odb__error_mismatch(&found_full_oid, &hash); + goto out; + } + } + if ((object = odb_object__alloc(&found_full_oid, &raw)) == NULL) - return -1; + goto out; *out = git_cache_store_raw(odb_cache(db), object); - return 0; + +out: + if (error) + git__free(raw.data); + + return error; } int git_odb_read_prefix( @@ -1167,7 +1231,7 @@ int git_odb_write( assert(oid && db); git_odb_hash(oid, data, len, type); - if (odb_freshen(db, oid)) + if (git_odb__freshen(db, oid)) return 0; for (i = 0; i < db->backends.length && error < 0; ++i) { @@ -1264,10 +1328,10 @@ static int git_odb_stream__invalid_length( const char *action) { giterr_set(GITERR_ODB, - "Cannot %s - " - "Invalid length. %"PRIuZ" was expected. The " - "total size of the received chunks amounts to %"PRIuZ".", - action, stream->declared_size, stream->received_bytes); + "cannot %s - " + "Invalid length. %"PRIdZ" was expected. The " + "total size of the received chunks amounts to %"PRIdZ".", + action, stream->declared_size, stream->received_bytes); return -1; } @@ -1293,7 +1357,7 @@ int git_odb_stream_finalize_write(git_oid *out, git_odb_stream *stream) git_hash_final(out, stream->hash_ctx); - if (odb_freshen(stream->backend->odb, out)) + if (git_odb__freshen(stream->backend->odb, out)) return 0; return stream->finalize_write(stream, out); @@ -1393,23 +1457,36 @@ int git_odb_refresh(struct git_odb *db) return 0; } +int git_odb__error_mismatch(const git_oid *expected, const git_oid *actual) +{ + char expected_oid[GIT_OID_HEXSZ + 1], actual_oid[GIT_OID_HEXSZ + 1]; + + git_oid_tostr(expected_oid, sizeof(expected_oid), expected); + git_oid_tostr(actual_oid, sizeof(actual_oid), actual); + + giterr_set(GITERR_ODB, "object hash mismatch - expected %s but got %s", + expected_oid, actual_oid); + + return GIT_EMISMATCH; +} + int git_odb__error_notfound( const char *message, const git_oid *oid, size_t oid_len) { if (oid != NULL) { char oid_str[GIT_OID_HEXSZ + 1]; git_oid_tostr(oid_str, oid_len+1, oid); - giterr_set(GITERR_ODB, "Object not found - %s (%.*s)", + giterr_set(GITERR_ODB, "object not found - %s (%.*s)", message, (int) oid_len, oid_str); } else - giterr_set(GITERR_ODB, "Object not found - %s", message); + giterr_set(GITERR_ODB, "object not found - %s", message); return GIT_ENOTFOUND; } int git_odb__error_ambiguous(const char *message) { - giterr_set(GITERR_ODB, "Ambiguous SHA1 prefix - %s", message); + giterr_set(GITERR_ODB, "ambiguous SHA1 prefix - %s", message); return GIT_EAMBIGUOUS; } diff --git a/src/odb.h b/src/odb.h index 31a9fd1b9..61d687abf 100644 --- a/src/odb.h +++ b/src/odb.h @@ -20,6 +20,8 @@ #define GIT_OBJECT_DIR_MODE 0777 #define GIT_OBJECT_FILE_MODE 0444 +extern bool git_odb__strict_hash_verification; + /* DO NOT EXPORT */ typedef struct { void *data; /**< Raw, decompressed object data. */ @@ -38,8 +40,25 @@ struct git_odb { git_refcount rc; git_vector backends; git_cache own_cache; + unsigned int do_fsync :1; }; +typedef enum { + GIT_ODB_CAP_FROM_OWNER = -1, +} git_odb_cap_t; + +/* + * Set the capabilities for the object database. + */ +int git_odb__set_caps(git_odb *odb, int caps); + +/* + * Add the default loose and packed backends for a database. + */ +int git_odb__add_default_backends( + git_odb *db, const char *objects_dir, + bool as_alternates, int alternate_depth); + /* * Hash a git_rawobj internally. * The `git_rawobj` is supposed to be previously initialized @@ -79,6 +98,12 @@ int git_odb__hashfd_filtered( */ int git_odb__hashlink(git_oid *out, const char *path); +/** + * Generate a GIT_EMISMATCH error for the ODB. + */ +int git_odb__error_mismatch( + const git_oid *expected, const git_oid *actual); + /* * Generate a GIT_ENOTFOUND error for the ODB. */ @@ -98,6 +123,9 @@ int git_odb__read_header_or_object( git_odb_object **out, size_t *len_p, git_otype *type_p, git_odb *db, const git_oid *id); +/* freshen an entry in the object database */ +int git_odb__freshen(git_odb *db, const git_oid *id); + /* fully free the object; internal method, DO NOT EXPORT */ void git_odb_object__free(void *object); diff --git a/src/odb_loose.c b/src/odb_loose.c index f312b9c9c..99fdcb44f 100644 --- a/src/odb_loose.c +++ b/src/odb_loose.c @@ -14,6 +14,7 @@ #include "odb.h" #include "delta.h" #include "filebuf.h" +#include "object.h" #include "git2/odb_backend.h" #include "git2/types.h" @@ -204,6 +205,11 @@ static int start_inflate(z_stream *s, git_buf *obj, void *out, size_t len) return inflate(s, 0); } +static void abort_inflate(z_stream *s) +{ + inflateEnd(s); +} + static int finish_inflate(z_stream *s) { int status = Z_OK; @@ -214,7 +220,7 @@ static int finish_inflate(z_stream *s) inflateEnd(s); if ((status != Z_STREAM_END) || (s->avail_in != 0)) { - giterr_set(GITERR_ZLIB, "Failed to finish ZLib inflation. Stream aborted prematurely"); + giterr_set(GITERR_ZLIB, "failed to finish zlib inflation; stream aborted prematurely"); return -1; } @@ -243,7 +249,7 @@ static int inflate_buffer(void *in, size_t inlen, void *out, size_t outlen) zs.avail_in = (uInt)inlen; if (inflateInit(&zs) < Z_OK) { - giterr_set(GITERR_ZLIB, "Failed to inflate buffer"); + giterr_set(GITERR_ZLIB, "failed to inflate buffer"); return -1; } @@ -255,7 +261,7 @@ static int inflate_buffer(void *in, size_t inlen, void *out, size_t outlen) if (status != Z_STREAM_END /* || zs.avail_in != 0 */ || zs.total_out != outlen) { - giterr_set(GITERR_ZLIB, "Failed to inflate buffer. Stream aborted prematurely"); + giterr_set(GITERR_ZLIB, "failed to inflate buffer; stream aborted prematurely"); return -1; } @@ -319,7 +325,7 @@ static int inflate_packlike_loose_disk_obj(git_rawobj *out, git_buf *obj) */ if ((used = get_binary_object_header(&hdr, obj)) == 0 || !git_object_typeisloose(hdr.type)) { - giterr_set(GITERR_ODB, "Failed to inflate loose object."); + giterr_set(GITERR_ODB, "failed to inflate loose object"); return -1; } @@ -366,7 +372,8 @@ static int inflate_disk_obj(git_rawobj *out, git_buf *obj) (used = get_object_header(&hdr, head)) == 0 || !git_object_typeisloose(hdr.type)) { - giterr_set(GITERR_ODB, "Failed to inflate disk object."); + abort_inflate(&zs); + giterr_set(GITERR_ODB, "failed to inflate disk object"); return -1; } @@ -455,7 +462,7 @@ static int read_header_loose(git_rawobj *out, git_buf *loc) || get_object_header(&header_obj, inflated_buffer) == 0 || git_object_typeisloose(header_obj.type) == 0) { - giterr_set(GITERR_ZLIB, "Failed to read loose object header"); + giterr_set(GITERR_ZLIB, "failed to read loose object header"); error = -1; } else { out->len = header_obj.size; @@ -838,6 +845,17 @@ static void loose_backend__stream_free(git_odb_stream *_stream) git__free(stream); } +static int filebuf_flags(loose_backend *backend) +{ + int flags = GIT_FILEBUF_TEMPORARY | + (backend->object_zlib_level << GIT_FILEBUF_DEFLATE_SHIFT); + + if (backend->fsync_object_files || git_repository__fsync_gitdir) + flags |= GIT_FILEBUF_FSYNC; + + return flags; +} + static int loose_backend__stream(git_odb_stream **stream_out, git_odb_backend *_backend, git_off_t length, git_otype type) { loose_backend *backend; @@ -864,9 +882,7 @@ static int loose_backend__stream(git_odb_stream **stream_out, git_odb_backend *_ stream->stream.mode = GIT_STREAM_WRONLY; if (git_buf_joinpath(&tmp_path, backend->objects_dir, "tmp_object") < 0 || - git_filebuf_open(&stream->fbuf, tmp_path.ptr, - GIT_FILEBUF_TEMPORARY | - (backend->object_zlib_level << GIT_FILEBUF_DEFLATE_SHIFT), + git_filebuf_open(&stream->fbuf, tmp_path.ptr, filebuf_flags(backend), backend->object_file_mode) < 0 || stream->stream.write((git_odb_stream *)stream, hdr, hdrlen) < 0) { @@ -894,9 +910,7 @@ static int loose_backend__write(git_odb_backend *_backend, const git_oid *oid, c header_len = git_odb__format_object_header(header, sizeof(header), len, type); if (git_buf_joinpath(&final_path, backend->objects_dir, "tmp_object") < 0 || - git_filebuf_open(&fbuf, final_path.ptr, - GIT_FILEBUF_TEMPORARY | - (backend->object_zlib_level << GIT_FILEBUF_DEFLATE_SHIFT), + git_filebuf_open(&fbuf, final_path.ptr, filebuf_flags(backend), backend->object_file_mode) < 0) { error = -1; diff --git a/src/odb_mempack.c b/src/odb_mempack.c index 68db3bc32..d6f2fb4af 100644 --- a/src/odb_mempack.c +++ b/src/odb_mempack.c @@ -18,8 +18,6 @@ #include "git2/types.h" #include "git2/pack.h" -GIT__USE_OIDMAP - struct memobject { git_oid oid; size_t len; @@ -41,7 +39,7 @@ static int impl__write(git_odb_backend *_backend, const git_oid *oid, const void size_t alloc_len; int rval; - pos = kh_put(oid, db->objects, oid, &rval); + pos = git_oidmap_put(db->objects, oid, &rval); if (rval < 0) return -1; @@ -57,8 +55,8 @@ static int impl__write(git_odb_backend *_backend, const git_oid *oid, const void obj->len = len; obj->type = type; - kh_key(db->objects, pos) = &obj->oid; - kh_val(db->objects, pos) = obj; + git_oidmap_set_key_at(db->objects, pos, &obj->oid); + git_oidmap_set_value_at(db->objects, pos, obj); if (type == GIT_OBJ_COMMIT) { struct memobject **store = git_array_alloc(db->commits); @@ -72,13 +70,8 @@ static int impl__write(git_odb_backend *_backend, const git_oid *oid, const void static int impl__exists(git_odb_backend *backend, const git_oid *oid) { struct memory_packer_db *db = (struct memory_packer_db *)backend; - khiter_t pos; - pos = kh_get(oid, db->objects, oid); - if (pos != kh_end(db->objects)) - return 1; - - return 0; + return git_oidmap_exists(db->objects, oid); } static int impl__read(void **buffer_p, size_t *len_p, git_otype *type_p, git_odb_backend *backend, const git_oid *oid) @@ -87,11 +80,11 @@ static int impl__read(void **buffer_p, size_t *len_p, git_otype *type_p, git_odb struct memobject *obj = NULL; khiter_t pos; - pos = kh_get(oid, db->objects, oid); - if (pos == kh_end(db->objects)) + pos = git_oidmap_lookup_index(db->objects, oid); + if (!git_oidmap_valid_index(db->objects, pos)) return GIT_ENOTFOUND; - obj = kh_val(db->objects, pos); + obj = git_oidmap_value_at(db->objects, pos); *len_p = obj->len; *type_p = obj->type; @@ -108,11 +101,11 @@ static int impl__read_header(size_t *len_p, git_otype *type_p, git_odb_backend * struct memobject *obj = NULL; khiter_t pos; - pos = kh_get(oid, db->objects, oid); - if (pos == kh_end(db->objects)) + pos = git_oidmap_lookup_index(db->objects, oid); + if (!git_oidmap_valid_index(db->objects, pos)) return GIT_ENOTFOUND; - obj = kh_val(db->objects, pos); + obj = git_oidmap_value_at(db->objects, pos); *len_p = obj->len; *type_p = obj->type; @@ -149,7 +142,7 @@ void git_mempack_reset(git_odb_backend *_backend) struct memory_packer_db *db = (struct memory_packer_db *)_backend; struct memobject *object = NULL; - kh_foreach_value(db->objects, object, { + git_oidmap_foreach_value(db->objects, object, { git__free(object); }); @@ -177,6 +170,7 @@ int git_mempack_new(git_odb_backend **out) db->objects = git_oidmap_alloc(); + db->parent.version = GIT_ODB_BACKEND_VERSION; db->parent.read = &impl__read; db->parent.write = &impl__write; db->parent.read_header = &impl__read_header; diff --git a/src/odb_pack.c b/src/odb_pack.c index b80d0337a..51770a88e 100644 --- a/src/odb_pack.c +++ b/src/odb_pack.c @@ -428,7 +428,7 @@ static int pack_backend__read_prefix( git_oid_cpy(out_oid, short_oid); } else { struct git_pack_entry e; - git_rawobj raw; + git_rawobj raw = {NULL}; if ((error = pack_entry_find_prefix( &e, (struct pack_backend *)backend, short_oid, len)) == 0 && diff --git a/src/offmap.c b/src/offmap.c new file mode 100644 index 000000000..ab6649697 --- /dev/null +++ b/src/offmap.c @@ -0,0 +1,83 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#include "offmap.h" + +__KHASH_IMPL(off, static kh_inline, git_off_t, void *, 1, kh_int64_hash_func, kh_int64_hash_equal) + +git_offmap *git_offmap_alloc(void) +{ + return kh_init(off); +} + +void git_offmap_free(git_offmap *map) +{ + kh_destroy(off, map); +} + +void git_offmap_clear(git_offmap *map) +{ + kh_clear(off, map); +} + +size_t git_offmap_num_entries(git_offmap *map) +{ + return kh_size(map); +} + +size_t git_offmap_lookup_index(git_offmap *map, const git_off_t key) +{ + return kh_get(off, map, key); +} + +int git_offmap_valid_index(git_offmap *map, size_t idx) +{ + return idx != kh_end(map); +} + +int git_offmap_exists(git_offmap *map, const git_off_t key) +{ + return kh_get(off, map, key) != kh_end(map); +} + +void *git_offmap_value_at(git_offmap *map, size_t idx) +{ + return kh_val(map, idx); +} + +void git_offmap_set_value_at(git_offmap *map, size_t idx, void *value) +{ + kh_val(map, idx) = value; +} + +void git_offmap_delete_at(git_offmap *map, size_t idx) +{ + kh_del(off, map, idx); +} + +int git_offmap_put(git_offmap *map, const git_off_t key, int *err) +{ + return kh_put(off, map, key, err); +} + +void git_offmap_insert(git_offmap *map, const git_off_t key, void *value, int *rval) +{ + khiter_t idx = kh_put(off, map, key, rval); + + if ((*rval) >= 0) { + if ((*rval) == 0) + kh_key(map, idx) = key; + kh_val(map, idx) = value; + } +} + +void git_offmap_delete(git_offmap *map, const git_off_t key) +{ + khiter_t idx = git_offmap_lookup_index(map, key); + if (git_offmap_valid_index(map, idx)) + git_offmap_delete_at(map, idx); +} diff --git a/src/offmap.h b/src/offmap.h index 0d0e51272..f9d2483a6 100644 --- a/src/offmap.h +++ b/src/offmap.h @@ -20,45 +20,24 @@ __KHASH_TYPE(off, git_off_t, void *) typedef khash_t(off) git_offmap; -#define GIT__USE_OFFMAP \ - __KHASH_IMPL(off, static kh_inline, git_off_t, void *, 1, kh_int64_hash_func, kh_int64_hash_equal) +git_offmap *git_offmap_alloc(void); +void git_offmap_free(git_offmap *map); +void git_offmap_clear(git_offmap *map); -#define git_offmap_alloc() kh_init(off) -#define git_offmap_free(h) kh_destroy(off, h), h = NULL -#define git_offmap_clear(h) kh_clear(off, h) +size_t git_offmap_num_entries(git_offmap *map); -#define git_offmap_num_entries(h) kh_size(h) +size_t git_offmap_lookup_index(git_offmap *map, const git_off_t key); +int git_offmap_valid_index(git_offmap *map, size_t idx); -#define git_offmap_lookup_index(h, k) kh_get(off, h, k) -#define git_offmap_valid_index(h, idx) (idx != kh_end(h)) +int git_offmap_exists(git_offmap *map, const git_off_t key); -#define git_offmap_exists(h, k) (kh_get(off, h, k) != kh_end(h)) +void *git_offmap_value_at(git_offmap *map, size_t idx); +void git_offmap_set_value_at(git_offmap *map, size_t idx, void *value); +void git_offmap_delete_at(git_offmap *map, size_t idx); -#define git_offmap_value_at(h, idx) kh_val(h, idx) -#define git_offmap_set_value_at(h, idx, v) kh_val(h, idx) = v -#define git_offmap_delete_at(h, idx) kh_del(off, h, idx) - -#define git_offmap_insert(h, key, val, rval) do { \ - khiter_t __pos = kh_put(off, h, key, &rval); \ - if (rval >= 0) { \ - if (rval == 0) kh_key(h, __pos) = key; \ - kh_val(h, __pos) = val; \ - } } while (0) - -#define git_offmap_insert2(h, key, val, oldv, rval) do { \ - khiter_t __pos = kh_put(off, h, key, &rval); \ - if (rval >= 0) { \ - if (rval == 0) { \ - oldv = kh_val(h, __pos); \ - kh_key(h, __pos) = key; \ - } else { oldv = NULL; } \ - kh_val(h, __pos) = val; \ - } } while (0) - -#define git_offmap_delete(h, key) do { \ - khiter_t __pos = git_offmap_lookup_index(h, key); \ - if (git_offmap_valid_index(h, __pos)) \ - git_offmap_delete_at(h, __pos); } while (0) +int git_offmap_put(git_offmap *map, const git_off_t key, int *err); +void git_offmap_insert(git_offmap *map, const git_off_t key, void *value, int *rval); +void git_offmap_delete(git_offmap *map, const git_off_t key); #define git_offmap_foreach kh_foreach #define git_offmap_foreach_value kh_foreach_value diff --git a/src/oid.c b/src/oid.c index 9fe2ebb65..9dc719194 100644 --- a/src/oid.c +++ b/src/oid.c @@ -16,7 +16,7 @@ static char to_hex[] = "0123456789abcdef"; static int oid_error_invalid(const char *msg) { - giterr_set(GITERR_INVALID, "Unable to parse OID - %s", msg); + giterr_set(GITERR_INVALID, "unable to parse OID - %s", msg); return -1; } @@ -380,7 +380,7 @@ int git_oid_shorten_add(git_oid_shorten *os, const char *text_oid) node_index idx; if (os->full) { - giterr_set(GITERR_INVALID, "Unable to shorten OID - OID set full"); + giterr_set(GITERR_INVALID, "unable to shorten OID - OID set full"); return -1; } @@ -395,7 +395,7 @@ int git_oid_shorten_add(git_oid_shorten *os, const char *text_oid) trie_node *node; if (c == -1) { - giterr_set(GITERR_INVALID, "Unable to shorten OID - invalid hex value"); + giterr_set(GITERR_INVALID, "unable to shorten OID - invalid hex value"); return -1; } @@ -410,7 +410,7 @@ int git_oid_shorten_add(git_oid_shorten *os, const char *text_oid) node = push_leaf(os, idx, git__fromhex(tail[0]), &tail[1]); if (node == NULL) { if (os->full) - giterr_set(GITERR_INVALID, "Unable to shorten OID - OID set full"); + giterr_set(GITERR_INVALID, "unable to shorten OID - OID set full"); return -1; } } @@ -418,7 +418,7 @@ int git_oid_shorten_add(git_oid_shorten *os, const char *text_oid) if (node->children[c] == 0) { if (push_leaf(os, idx, c, &text_oid[i + 1]) == NULL) { if (os->full) - giterr_set(GITERR_INVALID, "Unable to shorten OID - OID set full"); + giterr_set(GITERR_INVALID, "unable to shorten OID - OID set full"); return -1; } break; diff --git a/src/oidmap.c b/src/oidmap.c new file mode 100644 index 000000000..5f156a18e --- /dev/null +++ b/src/oidmap.c @@ -0,0 +1,105 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#include "oidmap.h" + +GIT_INLINE(khint_t) git_oidmap_hash(const git_oid *oid) +{ + khint_t h; + memcpy(&h, oid, sizeof(khint_t)); + return h; +} + +__KHASH_IMPL(oid, static kh_inline, const git_oid *, void *, 1, git_oidmap_hash, git_oid_equal) + +git_oidmap *git_oidmap_alloc() +{ + return kh_init(oid); +} + +void git_oidmap_free(git_oidmap *map) +{ + kh_destroy(oid, map); +} + +void git_oidmap_clear(git_oidmap *map) +{ + kh_clear(oid, map); +} + +size_t git_oidmap_size(git_oidmap *map) +{ + return kh_size(map); +} + +size_t git_oidmap_lookup_index(git_oidmap *map, const git_oid *key) +{ + return kh_get(oid, map, key); +} + +int git_oidmap_valid_index(git_oidmap *map, size_t idx) +{ + return idx != kh_end(map); +} + +int git_oidmap_exists(git_oidmap *map, const git_oid *key) +{ + return kh_get(oid, map, key) != kh_end(map); +} + +int git_oidmap_has_data(git_oidmap *map, size_t idx) +{ + return kh_exist(map, idx); +} + +const git_oid *git_oidmap_key(git_oidmap *map, size_t idx) +{ + return kh_key(map, idx); +} + +void git_oidmap_set_key_at(git_oidmap *map, size_t idx, git_oid *key) +{ + kh_key(map, idx) = key; +} + +void *git_oidmap_value_at(git_oidmap *map, size_t idx) +{ + return kh_val(map, idx); +} + +void git_oidmap_set_value_at(git_oidmap *map, size_t idx, void *value) +{ + kh_val(map, idx) = value; +} + +void git_oidmap_delete_at(git_oidmap *map, size_t idx) +{ + kh_del(oid, map, idx); +} + +int git_oidmap_put(git_oidmap *map, const git_oid *key, int *err) +{ + return kh_put(oid, map, key, err); +} + +void git_oidmap_insert(git_oidmap *map, const git_oid *key, void *value, int *rval) +{ + khiter_t idx = kh_put(oid, map, key, rval); + + if ((*rval) >= 0) { + if ((*rval) == 0) + kh_key(map, idx) = key; + kh_val(map, idx) = value; + } +} + +void git_oidmap_delete(git_oidmap *map, const git_oid *key) +{ + khiter_t idx = git_oidmap_lookup_index(map, key); + if (git_oidmap_valid_index(map, idx)) + git_oidmap_delete_at(map, idx); +} diff --git a/src/oidmap.h b/src/oidmap.h index 2cf208f53..563222494 100644 --- a/src/oidmap.h +++ b/src/oidmap.h @@ -20,35 +20,31 @@ __KHASH_TYPE(oid, const git_oid *, void *) typedef khash_t(oid) git_oidmap; -GIT_INLINE(khint_t) git_oidmap_hash(const git_oid *oid) -{ - khint_t h; - memcpy(&h, oid, sizeof(khint_t)); - return h; -} +git_oidmap *git_oidmap_alloc(void); +void git_oidmap_free(git_oidmap *map); +void git_oidmap_clear(git_oidmap *map); -#define GIT__USE_OIDMAP \ - __KHASH_IMPL(oid, static kh_inline, const git_oid *, void *, 1, git_oidmap_hash, git_oid_equal) +size_t git_oidmap_size(git_oidmap *map); -#define git_oidmap_alloc() kh_init(oid) -#define git_oidmap_free(h) kh_destroy(oid,h), h = NULL +size_t git_oidmap_lookup_index(git_oidmap *map, const git_oid *key); +int git_oidmap_valid_index(git_oidmap *map, size_t idx); -#define git_oidmap_lookup_index(h, k) kh_get(oid, h, k) -#define git_oidmap_valid_index(h, idx) (idx != kh_end(h)) +int git_oidmap_exists(git_oidmap *map, const git_oid *key); +int git_oidmap_has_data(git_oidmap *map, size_t idx); -#define git_oidmap_value_at(h, idx) kh_val(h, idx) +const git_oid *git_oidmap_key(git_oidmap *map, size_t idx); +void git_oidmap_set_key_at(git_oidmap *map, size_t idx, git_oid *key); +void *git_oidmap_value_at(git_oidmap *map, size_t idx); +void git_oidmap_set_value_at(git_oidmap *map, size_t idx, void *value); +void git_oidmap_delete_at(git_oidmap *map, size_t idx); -#define git_oidmap_insert(h, key, val, rval) do { \ - khiter_t __pos = kh_put(oid, h, key, &rval); \ - if (rval >= 0) { \ - if (rval == 0) kh_key(h, __pos) = key; \ - kh_val(h, __pos) = val; \ - } } while (0) +int git_oidmap_put(git_oidmap *map, const git_oid *key, int *err); +void git_oidmap_insert(git_oidmap *map, const git_oid *key, void *value, int *rval); +void git_oidmap_delete(git_oidmap *map, const git_oid *key); #define git_oidmap_foreach_value kh_foreach_value -#define git_oidmap_size(h) kh_size(h) - -#define git_oidmap_clear(h) kh_clear(oid, h) +#define git_oidmap_begin kh_begin +#define git_oidmap_end kh_end #endif diff --git a/src/openssl_stream.c b/src/openssl_stream.c index ddb9c4ab9..759c5015f 100644 --- a/src/openssl_stream.c +++ b/src/openssl_stream.c @@ -37,7 +37,7 @@ SSL_CTX *git__ssl_ctx; #define GIT_SSL_DEFAULT_CIPHERS "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-DSS-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA:DHE-DSS-AES128-SHA256:DHE-DSS-AES256-SHA256:DHE-DSS-AES128-SHA:DHE-DSS-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA" -#ifdef GIT_THREADS +#if defined(GIT_THREADS) && OPENSSL_VERSION_NUMBER < 0x10100000L static git_mutex *openssl_locks; @@ -66,11 +66,11 @@ static void shutdown_ssl_locking(void) CRYPTO_set_locking_callback(NULL); for (i = 0; i < num_locks; ++i) - git_mutex_free(openssl_locks); + git_mutex_free(&openssl_locks[i]); git__free(openssl_locks); } -#endif /* GIT_THREADS */ +#endif /* GIT_THREADS && OPENSSL_VERSION_NUMBER < 0x10100000L */ static BIO_METHOD *git_stream_bio_method; static int init_bio_method(void); @@ -103,8 +103,13 @@ int git_openssl_stream_global_init(void) ssl_opts |= SSL_OP_NO_COMPRESSION; #endif +#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER) SSL_load_error_strings(); OpenSSL_add_ssl_algorithms(); +#else + OPENSSL_init_ssl(0, NULL); +#endif + /* * Load SSLv{2,3} and TLSv1 so that we can talk with servers * which use the SSL hellos, which are often used for @@ -146,7 +151,7 @@ int git_openssl_stream_global_init(void) int git_openssl_set_locking(void) { -#ifdef GIT_THREADS +#if defined(GIT_THREADS) && OPENSSL_VERSION_NUMBER < 0x10100000L int num_locks, i; num_locks = CRYPTO_num_locks(); @@ -163,6 +168,8 @@ int git_openssl_set_locking(void) CRYPTO_set_locking_callback(openssl_locking_function); git__on_shutdown(shutdown_ssl_locking); return 0; +#elif OPENSSL_VERSION_NUMBER >= 0x10100000L + return 0; #else giterr_set(GITERR_THREAD, "libgit2 was not built with threads"); return -1; @@ -257,10 +264,10 @@ static int ssl_set_error(SSL *ssl, int error) switch (err) { case SSL_ERROR_WANT_CONNECT: case SSL_ERROR_WANT_ACCEPT: - giterr_set(GITERR_NET, "SSL error: connection failure\n"); + giterr_set(GITERR_NET, "SSL error: connection failure"); break; case SSL_ERROR_WANT_X509_LOOKUP: - giterr_set(GITERR_NET, "SSL error: x509 error\n"); + giterr_set(GITERR_NET, "SSL error: x509 error"); break; case SSL_ERROR_SYSCALL: e = ERR_get_error(); @@ -327,7 +334,7 @@ static int verify_server_cert(SSL *ssl, const char *host) int i = -1,j; if (SSL_get_verify_result(ssl) != X509_V_OK) { - giterr_set(GITERR_SSL, "The SSL certificate is invalid"); + giterr_set(GITERR_SSL, "the SSL certificate is invalid"); return GIT_ECERTIFICATE; } diff --git a/src/openssl_stream.h b/src/openssl_stream.h index b769437ae..f5e59dab1 100644 --- a/src/openssl_stream.h +++ b/src/openssl_stream.h @@ -27,7 +27,7 @@ extern int git_openssl_stream_new(git_stream **out, const char *host, const char -# if OPENSSL_VERSION_NUMBER < 0x10100000L +# if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER) GIT_INLINE(BIO_METHOD*) BIO_meth_new(int type, const char *name) { diff --git a/src/pack-objects.c b/src/pack-objects.c index 9f62322f7..ef272e8f5 100644 --- a/src/pack-objects.c +++ b/src/pack-objects.c @@ -41,8 +41,6 @@ struct pack_write_context { git_transfer_progress *stats; }; -GIT__USE_OIDMAP - #ifdef GIT_THREADS #define GIT_PACKBUILDER__MUTEX_OP(pb, mtx, op) do { \ @@ -162,7 +160,7 @@ int git_packbuilder_new(git_packbuilder **out, git_repository *repo) git_mutex_init(&pb->progress_mutex) || git_cond_init(&pb->progress_cond)) { - giterr_set(GITERR_OS, "Failed to initialize packbuilder mutex"); + giterr_set(GITERR_OS, "failed to initialize packbuilder mutex"); goto on_error; } @@ -197,10 +195,10 @@ static void rehash(git_packbuilder *pb) size_t i; int ret; - kh_clear(oid, pb->object_ix); + git_oidmap_clear(pb->object_ix); for (i = 0, po = pb->object_list; i < pb->nr_objects; i++, po++) { - pos = kh_put(oid, pb->object_ix, &po->id, &ret); - kh_value(pb->object_ix, pos) = po; + pos = git_oidmap_put(pb->object_ix, &po->id, &ret); + git_oidmap_set_value_at(pb->object_ix, pos, po); } } @@ -216,8 +214,7 @@ int git_packbuilder_insert(git_packbuilder *pb, const git_oid *oid, /* If the object already exists in the hash table, then we don't * have any work to do */ - pos = kh_get(oid, pb->object_ix, oid); - if (pos != kh_end(pb->object_ix)) + if (git_oidmap_exists(pb->object_ix, oid)) return 0; if (pb->nr_objects >= pb->nr_alloc) { @@ -225,7 +222,7 @@ int git_packbuilder_insert(git_packbuilder *pb, const git_oid *oid, GITERR_CHECK_ALLOC_MULTIPLY(&newsize, newsize, 3 / 2); if (!git__is_uint32(newsize)) { - giterr_set(GITERR_NOMEMORY, "Packfile too large to fit in memory."); + giterr_set(GITERR_NOMEMORY, "packfile too large to fit in memory."); return -1; } @@ -247,13 +244,13 @@ int git_packbuilder_insert(git_packbuilder *pb, const git_oid *oid, git_oid_cpy(&po->id, oid); po->hash = name_hash(name); - pos = kh_put(oid, pb->object_ix, &po->id, &ret); + pos = git_oidmap_put(pb->object_ix, &po->id, &ret); if (ret < 0) { giterr_set_oom(); return ret; } assert(ret != 0); - kh_value(pb->object_ix, pos) = po; + git_oidmap_set_value_at(pb->object_ix, pos, po); pb->done = false; @@ -298,7 +295,7 @@ static int get_delta(void **out, git_odb *odb, git_pobject *po) goto on_error; if (error == GIT_EBUFS || delta_size != po->delta_size) { - giterr_set(GITERR_INVALID, "Delta size changed"); + giterr_set(GITERR_INVALID, "delta size changed"); goto on_error; } @@ -517,11 +514,11 @@ static int cb_tag_foreach(const char *name, git_oid *oid, void *data) GIT_UNUSED(name); - pos = kh_get(oid, pb->object_ix, oid); - if (pos == kh_end(pb->object_ix)) + pos = git_oidmap_lookup_index(pb->object_ix, oid); + if (!git_oidmap_valid_index(pb->object_ix, pos)) return 0; - po = kh_value(pb->object_ix, pos); + po = git_oidmap_value_at(pb->object_ix, pos); po->tagged = 1; /* TODO: peel objects */ @@ -808,7 +805,7 @@ static int try_delta(git_packbuilder *pb, struct unpacked *trg, if (sz != trg_size) { giterr_set(GITERR_INVALID, - "Inconsistent target object length"); + "inconsistent target object length"); return -1; } @@ -830,7 +827,7 @@ static int try_delta(git_packbuilder *pb, struct unpacked *trg, if (sz != src_size) { giterr_set(GITERR_INVALID, - "Inconsistent source object length"); + "inconsistent source object length"); return -1; } @@ -1388,6 +1385,7 @@ int git_packbuilder_write( git_indexer *indexer; git_transfer_progress stats; struct pack_write_context ctx; + int t; PREPARE_PACK; @@ -1395,6 +1393,9 @@ int git_packbuilder_write( &indexer, path, mode, pb->odb, progress_cb, progress_cb_payload) < 0) return -1; + if (!git_repository__cvar(&t, pb->repo, GIT_CVAR_FSYNCOBJECTFILES) && t) + git_indexer__set_fsync(indexer, 1); + ctx.indexer = indexer; ctx.stats = &stats; @@ -1541,7 +1542,7 @@ static int retrieve_object(git_walk_object **out, git_packbuilder *pb, const git if ((error = lookup_walk_object(&obj, pb, id)) < 0) return error; - git_oidmap_insert(pb->walk_objects, &obj->id, obj, error); + git_oidmap_insert(pb->walk_objects, &obj->id, obj, &error); } *out = obj; @@ -1738,7 +1739,7 @@ int git_packbuilder_insert_walk(git_packbuilder *pb, git_revwalk *walk) if (error == GIT_ITEROVER) error = 0; - return 0; + return error; } int git_packbuilder_set_callbacks(git_packbuilder *pb, git_packbuilder_progress progress_cb, void *progress_cb_payload) diff --git a/src/pack-objects.h b/src/pack-objects.h index 5a84f4158..e1e0ee3c8 100644 --- a/src/pack-objects.h +++ b/src/pack-objects.h @@ -16,6 +16,7 @@ #include "netops.h" #include "zstream.h" #include "pool.h" +#include "indexer.h" #include "git2/oid.h" #include "git2/pack.h" diff --git a/src/pack.c b/src/pack.c index 2e19b3b62..f8d0dc9ac 100644 --- a/src/pack.c +++ b/src/pack.c @@ -16,9 +16,6 @@ #include -GIT__USE_OFFMAP -GIT__USE_OIDMAP - static int packfile_open(struct git_pack_file *p); static git_off_t nth_packed_object_offset(const struct git_pack_file *p, uint32_t n); static int packfile_unpack_compressed( @@ -45,7 +42,7 @@ static int pack_entry_find_offset( static int packfile_error(const char *message) { - giterr_set(GITERR_ODB, "Invalid pack file - %s", message); + giterr_set(GITERR_ODB, "invalid pack file - %s", message); return -1; } @@ -78,13 +75,12 @@ static void free_cache_object(void *o) static void cache_free(git_pack_cache *cache) { - khiter_t k; + git_pack_cache_entry *entry; if (cache->entries) { - for (k = kh_begin(cache->entries); k != kh_end(cache->entries); k++) { - if (kh_exist(cache->entries, k)) - free_cache_object(kh_value(cache->entries, k)); - } + git_offmap_foreach_value(cache->entries, entry, { + free_cache_object(entry); + }); git_offmap_free(cache->entries); cache->entries = NULL; @@ -99,7 +95,7 @@ static int cache_init(git_pack_cache *cache) cache->memory_limit = GIT_PACK_CACHE_MEMORY_LIMIT; if (git_mutex_init(&cache->lock)) { - giterr_set(GITERR_OS, "Failed to initialize pack cache mutex"); + giterr_set(GITERR_OS, "failed to initialize pack cache mutex"); git__free(cache->entries); cache->entries = NULL; @@ -118,9 +114,9 @@ static git_pack_cache_entry *cache_get(git_pack_cache *cache, git_off_t offset) if (git_mutex_lock(&cache->lock) < 0) return NULL; - k = kh_get(off, cache->entries, offset); - if (k != kh_end(cache->entries)) { /* found it */ - entry = kh_value(cache->entries, k); + k = git_offmap_lookup_index(cache->entries, offset); + if (git_offmap_valid_index(cache->entries, k)) { /* found it */ + entry = git_offmap_value_at(cache->entries, k); git_atomic_inc(&entry->refcount); entry->last_usage = cache->use_ctr++; } @@ -132,21 +128,16 @@ static git_pack_cache_entry *cache_get(git_pack_cache *cache, git_off_t offset) /* Run with the cache lock held */ static void free_lowest_entry(git_pack_cache *cache) { + git_off_t offset; git_pack_cache_entry *entry; - khiter_t k; - - for (k = kh_begin(cache->entries); k != kh_end(cache->entries); k++) { - if (!kh_exist(cache->entries, k)) - continue; - - entry = kh_value(cache->entries, k); + git_offmap_foreach(cache->entries, offset, entry, { if (entry && entry->refcount.val == 0) { cache->memory_used -= entry->raw.len; - kh_del(off, cache->entries, k); + git_offmap_delete(cache->entries, offset); free_cache_object(entry); } - } + }); } static int cache_add( @@ -170,14 +161,14 @@ static int cache_add( return -1; } /* Add it to the cache if nobody else has */ - exists = kh_get(off, cache->entries, offset) != kh_end(cache->entries); + exists = git_offmap_exists(cache->entries, offset); if (!exists) { while (cache->memory_used + base->len > cache->memory_limit) free_lowest_entry(cache); - k = kh_put(off, cache->entries, offset, &error); + k = git_offmap_put(cache->entries, offset, &error); assert(error != 0); - kh_value(cache->entries, k) = entry; + git_offmap_set_value_at(cache->entries, k, entry); cache->memory_used += entry->raw.len; *cached_out = entry; @@ -226,7 +217,7 @@ static int pack_index_check(const char *path, struct git_pack_file *p) if (p_fstat(fd, &st) < 0) { p_close(fd); - giterr_set(GITERR_OS, "Unable to stat pack index '%s'", path); + giterr_set(GITERR_OS, "unable to stat pack index '%s'", path); return -1; } @@ -235,7 +226,7 @@ static int pack_index_check(const char *path, struct git_pack_file *p) (idx_size = (size_t)st.st_size) < 4 * 256 + 20 + 20) { p_close(fd); - giterr_set(GITERR_ODB, "Invalid pack index '%s'", path); + giterr_set(GITERR_ODB, "invalid pack index '%s'", path); return -1; } @@ -321,7 +312,7 @@ static int pack_index_open(struct git_pack_file *p) { int error = 0; size_t name_len; - git_buf idx_name = GIT_BUF_INIT; + git_buf idx_name; if (p->index_version > -1) return 0; @@ -329,11 +320,13 @@ static int pack_index_open(struct git_pack_file *p) name_len = strlen(p->pack_name); assert(name_len > strlen(".pack")); /* checked by git_pack_file alloc */ - git_buf_grow(&idx_name, name_len); + if (git_buf_init(&idx_name, name_len) < 0) + return -1; + git_buf_put(&idx_name, p->pack_name, name_len - strlen(".pack")); git_buf_puts(&idx_name, ".idx"); if (git_buf_oom(&idx_name)) { - giterr_set_oom(); + git_buf_free(&idx_name); return -1; } @@ -962,10 +955,10 @@ git_off_t get_delta_base( git_oid oid; git_oid_fromraw(&oid, base_info); - k = kh_get(oid, p->idx_cache, &oid); - if (k != kh_end(p->idx_cache)) { + k = git_oidmap_lookup_index(p->idx_cache, &oid); + if (git_oidmap_valid_index(p->idx_cache, k)) { *curpos += 20; - return ((struct git_pack_entry *)kh_value(p->idx_cache, k))->offset; + return ((struct git_pack_entry *)git_oidmap_value_at(p->idx_cache, k))->offset; } else { /* If we're building an index, don't try to find the pack * entry; we just haven't seen it yet. We'll make @@ -991,6 +984,18 @@ git_off_t get_delta_base( * ***********************************************************/ +void git_packfile_close(struct git_pack_file *p, bool unlink_packfile) +{ + if (p->mwf.fd >= 0) { + git_mwindow_free_all_locked(&p->mwf); + p_close(p->mwf.fd); + p->mwf.fd = -1; + } + + if (unlink_packfile) + p_unlink(p->pack_name); +} + void git_packfile_free(struct git_pack_file *p) { if (!p) @@ -998,10 +1003,7 @@ void git_packfile_free(struct git_pack_file *p) cache_free(&p->bases); - if (p->mwf.fd >= 0) { - git_mwindow_free_all_locked(&p->mwf); - p_close(p->mwf.fd); - } + git_packfile_close(p, false); pack_index_free(p); @@ -1082,7 +1084,7 @@ static int packfile_open(struct git_pack_file *p) return 0; cleanup: - giterr_set(GITERR_OS, "Invalid packfile '%s'", p->pack_name); + giterr_set(GITERR_OS, "invalid packfile '%s'", p->pack_name); if (p->mwf.fd >= 0) p_close(p->mwf.fd); @@ -1158,7 +1160,7 @@ int git_packfile_alloc(struct git_pack_file **pack_out, const char *path) p->index_version = -1; if (git_mutex_init(&p->lock)) { - giterr_set(GITERR_OS, "Failed to initialize packfile mutex"); + giterr_set(GITERR_OS, "failed to initialize packfile mutex"); git__free(p); return -1; } diff --git a/src/pack.h b/src/pack.h index 5302db5b7..e2bf165f4 100644 --- a/src/pack.h +++ b/src/pack.h @@ -149,6 +149,7 @@ git_off_t get_delta_base(struct git_pack_file *p, git_mwindow **w_curs, git_off_t *curpos, git_otype type, git_off_t delta_obj_offset); +void git_packfile_close(struct git_pack_file *p, bool unlink_packfile); void git_packfile_free(struct git_pack_file *p); int git_packfile_alloc(struct git_pack_file **pack_out, const char *path); diff --git a/src/patch_generate.c b/src/patch_generate.c index 0e5d1db31..804fc0e09 100644 --- a/src/patch_generate.c +++ b/src/patch_generate.c @@ -206,35 +206,14 @@ static int patch_generated_load(git_patch_generated *patch, git_patch_generated_ ((patch->nfile.flags & GIT_DIFF_FLAG__NO_DATA) != 0 || (patch->nfile.file->flags & GIT_DIFF_FLAG_VALID_ID) != 0)); - /* always try to load workdir content first because filtering may - * need 2x data size and this minimizes peak memory footprint - */ - if (patch->ofile.src == GIT_ITERATOR_TYPE_WORKDIR) { - if ((error = git_diff_file_content__load( - &patch->ofile, &patch->base.diff_opts)) < 0 || - should_skip_binary(patch, patch->ofile.file)) - goto cleanup; - } - if (patch->nfile.src == GIT_ITERATOR_TYPE_WORKDIR) { - if ((error = git_diff_file_content__load( - &patch->nfile, &patch->base.diff_opts)) < 0 || - should_skip_binary(patch, patch->nfile.file)) - goto cleanup; - } - - /* once workdir has been tried, load other data as needed */ - if (patch->ofile.src != GIT_ITERATOR_TYPE_WORKDIR) { - if ((error = git_diff_file_content__load( - &patch->ofile, &patch->base.diff_opts)) < 0 || - should_skip_binary(patch, patch->ofile.file)) - goto cleanup; - } - if (patch->nfile.src != GIT_ITERATOR_TYPE_WORKDIR) { - if ((error = git_diff_file_content__load( - &patch->nfile, &patch->base.diff_opts)) < 0 || - should_skip_binary(patch, patch->nfile.file)) - goto cleanup; - } + if ((error = git_diff_file_content__load( + &patch->ofile, &patch->base.diff_opts)) < 0 || + should_skip_binary(patch, patch->ofile.file)) + goto cleanup; + if ((error = git_diff_file_content__load( + &patch->nfile, &patch->base.diff_opts)) < 0 || + should_skip_binary(patch, patch->nfile.file)) + goto cleanup; /* if previously missing an oid, and now that we have it the two sides * are the same (and not submodules), update MODIFIED -> UNMODIFIED @@ -417,58 +396,10 @@ static int diff_required(git_diff *diff, const char *action) { if (diff) return 0; - giterr_set(GITERR_INVALID, "Must provide valid diff to %s", action); + giterr_set(GITERR_INVALID, "must provide valid diff to %s", action); return -1; } -int git_diff_foreach( - git_diff *diff, - git_diff_file_cb file_cb, - git_diff_binary_cb binary_cb, - git_diff_hunk_cb hunk_cb, - git_diff_line_cb data_cb, - void *payload) -{ - int error = 0; - git_xdiff_output xo; - size_t idx; - git_patch_generated patch; - - if ((error = diff_required(diff, "git_diff_foreach")) < 0) - return error; - - memset(&xo, 0, sizeof(xo)); - memset(&patch, 0, sizeof(patch)); - diff_output_init( - &xo.output, &diff->opts, file_cb, binary_cb, hunk_cb, data_cb, payload); - git_xdiff_init(&xo, &diff->opts); - - git_vector_foreach(&diff->deltas, idx, patch.base.delta) { - - /* check flags against patch status */ - if (git_diff_delta__should_skip(&diff->opts, patch.base.delta)) - continue; - - if (binary_cb || hunk_cb || data_cb) { - if ((error = patch_generated_init(&patch, diff, idx)) != 0 || - (error = patch_generated_load(&patch, &xo.output)) != 0) - return error; - } - - if ((error = patch_generated_invoke_file_callback(&patch, &xo.output)) == 0) { - if (binary_cb || hunk_cb || data_cb) - error = patch_generated_create(&patch, &xo.output); - } - - git_patch_free(&patch.base); - - if (error) - break; - } - - return error; -} - typedef struct { git_patch_generated patch; git_diff_delta delta; @@ -776,7 +707,7 @@ int git_patch_generated_from_diff( delta = git_vector_get(&diff->deltas, idx); if (!delta) { - giterr_set(GITERR_INVALID, "Index out of range for delta in diff"); + giterr_set(GITERR_INVALID, "index out of range for delta in diff"); return GIT_ENOTFOUND; } diff --git a/src/patch_parse.c b/src/patch_parse.c index f5275947d..0a9edcd18 100644 --- a/src/patch_parse.c +++ b/src/patch_parse.c @@ -444,9 +444,9 @@ static int parse_header_git( goto done; parse_advance_ws(ctx); - parse_advance_expected_str(ctx, "\n"); - if (ctx->line_len > 0) { + if (parse_advance_expected_str(ctx, "\n") < 0 || + ctx->line_len > 0) { error = parse_err("trailing data at line %"PRIuZ, ctx->line_num); goto done; } @@ -562,8 +562,9 @@ static int parse_hunk_body( int newlines = hunk->hunk.new_lines; for (; - ctx->remain_len > 4 && (oldlines || newlines) && - memcmp(ctx->line, "@@ -", 4) != 0; + ctx->remain_len > 1 && + (oldlines || newlines) && + (ctx->remain_len <= 4 || memcmp(ctx->line, "@@ -", 4) != 0); parse_advance_line(ctx)) { int origin; diff --git a/src/path.c b/src/path.c index 767552778..5fc7a055b 100644 --- a/src/path.c +++ b/src/path.c @@ -110,6 +110,34 @@ Exit: return result; } +/* + * Determine if the path is a Windows prefix and, if so, returns + * its actual lentgh. If it is not a prefix, returns -1. + */ +static int win32_prefix_length(const char *path, int len) +{ +#ifndef GIT_WIN32 + GIT_UNUSED(path); + GIT_UNUSED(len); +#else + /* + * Mimic unix behavior where '/.git' returns '/': 'C:/.git' will return + * 'C:/' here + */ + if (len == 2 && LOOKS_LIKE_DRIVE_PREFIX(path)) + return 2; + + /* + * Similarly checks if we're dealing with a network computer name + * '//computername/.git' will return '//computername/' + */ + if (looks_like_network_computer_name(path, len)) + return len; +#endif + + return -1; +} + /* * Based on the Android implementation, BSD licensed. * Check http://android.git.kernel.org/ @@ -117,7 +145,7 @@ Exit: int git_path_dirname_r(git_buf *buffer, const char *path) { const char *endp; - int result, len; + int is_prefix = 0, len; /* Empty or NULL string gets treated as "." */ if (path == NULL || *path == '\0') { @@ -131,6 +159,11 @@ int git_path_dirname_r(git_buf *buffer, const char *path) while (endp > path && *endp == '/') endp--; + if ((len = win32_prefix_length(path, endp - path + 1)) > 0) { + is_prefix = 1; + goto Exit; + } + /* Find the start of the dir */ while (endp > path && *endp != '/') endp--; @@ -146,35 +179,23 @@ int git_path_dirname_r(git_buf *buffer, const char *path) endp--; } while (endp > path && *endp == '/'); + if ((len = win32_prefix_length(path, endp - path + 1)) > 0) { + is_prefix = 1; + goto Exit; + } + /* Cast is safe because max path < max int */ len = (int)(endp - path + 1); -#ifdef GIT_WIN32 - /* Mimic unix behavior where '/.git' returns '/': 'C:/.git' will return - 'C:/' here */ - - if (len == 2 && LOOKS_LIKE_DRIVE_PREFIX(path)) { - len = 3; - goto Exit; - } - - /* Similarly checks if we're dealing with a network computer name - '//computername/.git' will return '//computername/' */ - - if (looks_like_network_computer_name(path, len)) { - len++; - goto Exit; - } - -#endif - Exit: - result = len; + if (buffer) { + if (git_buf_set(buffer, path, len) < 0) + return -1; + if (is_prefix && git_buf_putc(buffer, '/') < 0) + return -1; + } - if (buffer != NULL && git_buf_set(buffer, path, len) < 0) - return -1; - - return result; + return len; } @@ -341,7 +362,7 @@ int git_path_prettify(git_buf *path_out, const char *path, const char *base) if (p_realpath(path, buf) == NULL) { /* giterr_set resets the errno when dealing with a GITERR_OS kind of error */ int error = (errno == ENOENT || errno == ENOTDIR) ? GIT_ENOTFOUND : -1; - giterr_set(GITERR_OS, "Failed to resolve path '%s'", path); + giterr_set(GITERR_OS, "failed to resolve path '%s'", path); git_buf_clear(path_out); @@ -632,24 +653,24 @@ int git_path_set_error(int errno_value, const char *path, const char *action) switch (errno_value) { case ENOENT: case ENOTDIR: - giterr_set(GITERR_OS, "Could not find '%s' to %s", path, action); + giterr_set(GITERR_OS, "could not find '%s' to %s", path, action); return GIT_ENOTFOUND; case EINVAL: case ENAMETOOLONG: - giterr_set(GITERR_OS, "Invalid path for filesystem '%s'", path); + giterr_set(GITERR_OS, "invalid path for filesystem '%s'", path); return GIT_EINVALIDSPEC; case EEXIST: - giterr_set(GITERR_OS, "Failed %s - '%s' already exists", action, path); + giterr_set(GITERR_OS, "failed %s - '%s' already exists", action, path); return GIT_EEXISTS; case EACCES: - giterr_set(GITERR_OS, "Failed %s - '%s' is locked", action, path); + giterr_set(GITERR_OS, "failed %s - '%s' is locked", action, path); return GIT_ELOCKED; default: - giterr_set(GITERR_OS, "Could not %s '%s'", action, path); + giterr_set(GITERR_OS, "could not %s '%s'", action, path); return -1; } } @@ -679,7 +700,8 @@ static bool _check_dir_contents( return false; /* save excursion */ - git_buf_joinpath(dir, dir->ptr, sub); + if (git_buf_joinpath(dir, dir->ptr, sub) < 0) + return false; result = predicate(dir->ptr); @@ -758,7 +780,7 @@ int git_path_resolve_relative(git_buf *path, size_t ceiling) /* error out if trying to up one from a hard base */ if (to == base && ceiling != 0) { giterr_set(GITERR_INVALID, - "Cannot strip root component off url"); + "cannot strip root component off url"); return -1; } @@ -804,8 +826,8 @@ int git_path_resolve_relative(git_buf *path, size_t ceiling) int git_path_apply_relative(git_buf *target, const char *relpath) { - git_buf_joinpath(target, git_buf_cstr(target), relpath); - return git_path_resolve_relative(target, 0); + return git_buf_joinpath(target, git_buf_cstr(target), relpath) || + git_path_resolve_relative(target, 0); } int git_path_cmp( @@ -987,7 +1009,7 @@ int git_path_iconv(git_path_iconv_t *ic, const char **in, size_t *inlen) return 0; fail: - giterr_set(GITERR_OS, "Unable to convert unicode path data"); + giterr_set(GITERR_OS, "unable to convert unicode path data"); return -1; } @@ -1080,7 +1102,7 @@ int git_path_direach( wd_len = git_buf_len(path); if ((dir = opendir(path->ptr)) == NULL) { - giterr_set(GITERR_OS, "Failed to open directory '%s'", path->ptr); + giterr_set(GITERR_OS, "failed to open directory '%s'", path->ptr); if (errno == ENOENT) return GIT_ENOTFOUND; @@ -1161,13 +1183,13 @@ int git_path_diriter_init( git_path_trim_slashes(&diriter->path_utf8); if (diriter->path_utf8.size == 0) { - giterr_set(GITERR_FILESYSTEM, "Could not open directory '%s'", path); + giterr_set(GITERR_FILESYSTEM, "could not open directory '%s'", path); return -1; } if ((diriter->parent_len = git_win32_path_from_utf8(diriter->path, diriter->path_utf8.ptr)) < 0 || !git_win32__findfirstfile_filter(path_filter, diriter->path_utf8.ptr)) { - giterr_set(GITERR_OS, "Could not parse the directory path '%s'", path); + giterr_set(GITERR_OS, "could not parse the directory path '%s'", path); return -1; } @@ -1180,7 +1202,7 @@ int git_path_diriter_init( is_win7_or_later ? FIND_FIRST_EX_LARGE_FETCH : 0); if (diriter->handle == INVALID_HANDLE_VALUE) { - giterr_set(GITERR_OS, "Could not open directory '%s'", path); + giterr_set(GITERR_OS, "could not open directory '%s'", path); return -1; } @@ -1310,14 +1332,14 @@ int git_path_diriter_init( git_path_trim_slashes(&diriter->path); if (diriter->path.size == 0) { - giterr_set(GITERR_FILESYSTEM, "Could not open directory '%s'", path); + giterr_set(GITERR_FILESYSTEM, "could not open directory '%s'", path); return -1; } if ((diriter->dir = opendir(diriter->path.ptr)) == NULL) { git_buf_free(&diriter->path); - giterr_set(GITERR_OS, "Failed to open directory '%s'", path); + giterr_set(GITERR_OS, "failed to open directory '%s'", path); return -1; } @@ -1350,7 +1372,7 @@ int git_path_diriter_next(git_path_diriter *diriter) return GIT_ITEROVER; giterr_set(GITERR_OS, - "Could not read directory '%s'", diriter->path.ptr); + "could not read directory '%s'", diriter->path.ptr); return -1; } } while (skip_dot && git_path_is_dot_or_dotdot(de->d_name)); @@ -1686,6 +1708,7 @@ GIT_INLINE(unsigned int) dotgit_flags( unsigned int flags) { int protectHFS = 0, protectNTFS = 0; + int error = 0; flags |= GIT_PATH_REJECT_DOT_GIT_LITERAL; @@ -1698,13 +1721,13 @@ GIT_INLINE(unsigned int) dotgit_flags( #endif if (repo && !protectHFS) - git_repository__cvar(&protectHFS, repo, GIT_CVAR_PROTECTHFS); - if (protectHFS) + error = git_repository__cvar(&protectHFS, repo, GIT_CVAR_PROTECTHFS); + if (!error && protectHFS) flags |= GIT_PATH_REJECT_DOT_GIT_HFS; if (repo && !protectNTFS) - git_repository__cvar(&protectNTFS, repo, GIT_CVAR_PROTECTNTFS); - if (protectNTFS) + error = git_repository__cvar(&protectNTFS, repo, GIT_CVAR_PROTECTNTFS); + if (!error && protectNTFS) flags |= GIT_PATH_REJECT_DOT_GIT_NTFS; return flags; diff --git a/src/pathspec.c b/src/pathspec.c index 361b398b8..00dba4f6b 100644 --- a/src/pathspec.c +++ b/src/pathspec.c @@ -487,7 +487,7 @@ static int pathspec_match_from_iterator( /* if every pattern failed to match, then we have failed */ if ((flags & GIT_PATHSPEC_NO_MATCH_ERROR) != 0 && !found_files) { - giterr_set(GITERR_INVALID, "No matching files were found"); + giterr_set(GITERR_INVALID, "no matching files were found"); error = GIT_ENOTFOUND; } @@ -658,7 +658,7 @@ int git_pathspec_match_diff( /* if every pattern failed to match, then we have failed */ if ((flags & GIT_PATHSPEC_NO_MATCH_ERROR) != 0 && !found_deltas) { - giterr_set(GITERR_INVALID, "No matching deltas were found"); + giterr_set(GITERR_INVALID, "no matching deltas were found"); error = GIT_ENOTFOUND; } diff --git a/src/posix.c b/src/posix.c index b3f1a1cd3..94deb6ab0 100644 --- a/src/posix.c +++ b/src/posix.c @@ -10,6 +10,8 @@ #include #include +size_t p_fsync__cnt = 0; + #ifndef GIT_WIN32 #ifdef NO_ADDRINFO @@ -240,7 +242,7 @@ int p_mmap(git_map *out, size_t len, int prot, int flags, int fd, git_off_t offs out->len = 0; if ((prot & GIT_PROT_WRITE) && ((flags & GIT_MAP_TYPE) == GIT_MAP_SHARED)) { - giterr_set(GITERR_OS, "Trying to map shared-writeable"); + giterr_set(GITERR_OS, "trying to map shared-writeable"); return -1; } diff --git a/src/posix.h b/src/posix.h index f204751cf..d26371bca 100644 --- a/src/posix.h +++ b/src/posix.h @@ -24,6 +24,10 @@ #define _S_IFLNK S_IFLNK #endif +#ifndef S_IWUSR +#define S_IWUSR 00200 +#endif + #ifndef S_IXUSR #define S_IXUSR 00100 #endif @@ -111,6 +115,12 @@ extern int p_rename(const char *from, const char *to); extern int git__page_size(size_t *page_size); extern int git__mmap_alignment(size_t *page_size); +/* The number of times `p_fsync` has been called. Note that this is for + * test code only; it it not necessarily thread-safe and should not be + * relied upon in production. + */ +extern size_t p_fsync__cnt; + /** * Platform-dependent methods */ diff --git a/src/push.c b/src/push.c index b4901388b..09c234034 100644 --- a/src/push.c +++ b/src/push.c @@ -90,7 +90,7 @@ static void free_refspec(push_spec *spec) static int check_rref(char *ref) { if (git__prefixcmp(ref, "refs/")) { - giterr_set(GITERR_INVALID, "Not a valid reference '%s'", ref); + giterr_set(GITERR_INVALID, "not a valid reference '%s'", ref); return -1; } @@ -111,7 +111,7 @@ static int check_lref(git_push *push, char *ref) giterr_set(GITERR_REFERENCE, "src refspec '%s' does not match any existing object", ref); else - giterr_set(GITERR_INVALID, "Not a valid reference '%s'", ref); + giterr_set(GITERR_INVALID, "not a valid reference '%s'", ref); return -1; } @@ -321,7 +321,7 @@ static int revwalk(git_vector *commits, git_push *push) if (!git_odb_exists(push->repo->_odb, &spec->roid)) { giterr_set(GITERR_REFERENCE, - "Cannot push because a reference that you are trying to update on the remote contains commits that are not present locally."); + "cannot push because a reference that you are trying to update on the remote contains commits that are not present locally."); error = GIT_ENONFASTFORWARD; goto on_error; } @@ -332,7 +332,7 @@ static int revwalk(git_vector *commits, git_push *push) if (error == GIT_ENOTFOUND || (!error && !git_oid_equal(&base, &spec->roid))) { giterr_set(GITERR_REFERENCE, - "Cannot push non-fastforwardable reference"); + "cannot push non-fastforwardable reference"); error = GIT_ENONFASTFORWARD; goto on_error; } @@ -553,7 +553,7 @@ static int calculate_work(git_push *push) /* This is a create or update. Local ref must exist. */ if (git_reference_name_to_id( &spec->loid, push->repo, spec->refspec.src) < 0) { - giterr_set(GITERR_REFERENCE, "No such reference '%s'", spec->refspec.src); + giterr_set(GITERR_REFERENCE, "no such reference '%s'", spec->refspec.src); return -1; } } @@ -579,7 +579,7 @@ static int do_push(git_push *push, const git_remote_callbacks *callbacks) git_transport *transport = push->remote->transport; if (!transport->push) { - giterr_set(GITERR_NET, "Remote transport doesn't support push"); + giterr_set(GITERR_NET, "remote transport doesn't support push"); error = -1; goto on_error; } diff --git a/src/rebase.c b/src/rebase.c index 0af2b3cf4..f528031b3 100644 --- a/src/rebase.c +++ b/src/rebase.c @@ -92,7 +92,7 @@ static int rebase_state_type( git_buf path = GIT_BUF_INIT; git_rebase_type_t type = GIT_REBASE_TYPE_NONE; - if (git_buf_joinpath(&path, repo->path_repository, REBASE_APPLY_DIR) < 0) + if (git_buf_joinpath(&path, repo->gitdir, REBASE_APPLY_DIR) < 0) return -1; if (git_path_isdir(git_buf_cstr(&path))) { @@ -101,7 +101,7 @@ static int rebase_state_type( } git_buf_clear(&path); - if (git_buf_joinpath(&path, repo->path_repository, REBASE_MERGE_DIR) < 0) + if (git_buf_joinpath(&path, repo->gitdir, REBASE_MERGE_DIR) < 0) return -1; if (git_path_isdir(git_buf_cstr(&path))) { @@ -152,7 +152,7 @@ GIT_INLINE(int) rebase_readint( return error; if (git__strtol32(&num, asc_out->ptr, &eol, 10) < 0 || num < 0 || *eol) { - giterr_set(GITERR_REBASE, "The file '%s' contains an invalid numeric value", filename); + giterr_set(GITERR_REBASE, "the file '%s' contains an invalid numeric value", filename); return -1; } @@ -170,7 +170,7 @@ GIT_INLINE(int) rebase_readoid( return error; if (str_out->size != GIT_OID_HEXSZ || git_oid_fromstr(out, str_out->ptr) < 0) { - giterr_set(GITERR_REBASE, "The file '%s' contains an invalid object ID", filename); + giterr_set(GITERR_REBASE, "the file '%s' contains an invalid object ID", filename); return -1; } @@ -316,7 +316,7 @@ int git_rebase_open( goto done; if (rebase->type == GIT_REBASE_TYPE_NONE) { - giterr_set(GITERR_REBASE, "There is no rebase in progress"); + giterr_set(GITERR_REBASE, "there is no rebase in progress"); error = GIT_ENOTFOUND; goto done; } @@ -372,14 +372,14 @@ int git_rebase_open( switch (rebase->type) { case GIT_REBASE_TYPE_INTERACTIVE: - giterr_set(GITERR_REBASE, "Interactive rebase is not supported"); + giterr_set(GITERR_REBASE, "interactive rebase is not supported"); error = -1; break; case GIT_REBASE_TYPE_MERGE: error = rebase_open_merge(rebase); break; case GIT_REBASE_TYPE_APPLY: - giterr_set(GITERR_REBASE, "Patch application rebase is not supported"); + giterr_set(GITERR_REBASE, "patch application rebase is not supported"); error = -1; break; default: @@ -447,8 +447,8 @@ static int rebase_setupfiles_merge(git_rebase *rebase) size_t i; int error = 0; - if ((error = rebase_setupfile(rebase, END_FILE, -1, "%" PRIuZ "\n", git_array_size(rebase->operations))) < 0 || - (error = rebase_setupfile(rebase, ONTO_NAME_FILE, -1, "%s\n", rebase->onto_name)) < 0) + if ((error = rebase_setupfile(rebase, END_FILE, 0, "%" PRIuZ "\n", git_array_size(rebase->operations))) < 0 || + (error = rebase_setupfile(rebase, ONTO_NAME_FILE, 0, "%s\n", rebase->onto_name)) < 0) goto done; for (i = 0; i < git_array_size(rebase->operations); i++) { @@ -459,7 +459,7 @@ static int rebase_setupfiles_merge(git_rebase *rebase) git_oid_fmt(id_str, &operation->id); - if ((error = rebase_setupfile(rebase, commit_filename.ptr, -1, + if ((error = rebase_setupfile(rebase, commit_filename.ptr, 0, "%.*s\n", GIT_OID_HEXSZ, id_str)) < 0) goto done; } @@ -478,7 +478,7 @@ static int rebase_setupfiles(git_rebase *rebase) git_oid_fmt(orig_head, &rebase->orig_head_id); if (p_mkdir(rebase->state_path, REBASE_DIR_MODE) < 0) { - giterr_set(GITERR_OS, "Failed to create rebase directory '%s'", rebase->state_path); + giterr_set(GITERR_OS, "failed to create rebase directory '%s'", rebase->state_path); return -1; } @@ -486,10 +486,10 @@ static int rebase_setupfiles(git_rebase *rebase) rebase->orig_head_name; if (git_repository__set_orig_head(rebase->repo, &rebase->orig_head_id) < 0 || - rebase_setupfile(rebase, HEAD_NAME_FILE, -1, "%s\n", orig_head_name) < 0 || - rebase_setupfile(rebase, ONTO_FILE, -1, "%.*s\n", GIT_OID_HEXSZ, onto) < 0 || - rebase_setupfile(rebase, ORIG_HEAD_FILE, -1, "%.*s\n", GIT_OID_HEXSZ, orig_head) < 0 || - rebase_setupfile(rebase, QUIET_FILE, -1, rebase->quiet ? "t\n" : "\n") < 0) + rebase_setupfile(rebase, HEAD_NAME_FILE, 0, "%s\n", orig_head_name) < 0 || + rebase_setupfile(rebase, ONTO_FILE, 0, "%.*s\n", GIT_OID_HEXSZ, onto) < 0 || + rebase_setupfile(rebase, ORIG_HEAD_FILE, 0, "%.*s\n", GIT_OID_HEXSZ, orig_head) < 0 || + rebase_setupfile(rebase, QUIET_FILE, 0, rebase->quiet ? "t\n" : "\n") < 0) return -1; return rebase_setupfiles_merge(rebase); @@ -511,7 +511,7 @@ static int rebase_ensure_not_in_progress(git_repository *repo) return error; if (type != GIT_REBASE_TYPE_NONE) { - giterr_set(GITERR_REBASE, "There is an existing rebase in progress"); + giterr_set(GITERR_REBASE, "there is an existing rebase in progress"); return -1; } @@ -536,7 +536,7 @@ static int rebase_ensure_not_dirty( goto done; if (git_diff_num_deltas(diff) > 0) { - giterr_set(GITERR_REBASE, "Uncommitted changes exist in index"); + giterr_set(GITERR_REBASE, "uncommitted changes exist in index"); error = fail_with; goto done; } @@ -546,11 +546,13 @@ static int rebase_ensure_not_dirty( } if (check_workdir) { - if ((error = git_diff_index_to_workdir(&diff, repo, index, NULL)) < 0) + git_diff_options diff_opts = GIT_DIFF_OPTIONS_INIT; + diff_opts.ignore_submodules = GIT_SUBMODULE_IGNORE_UNTRACKED; + if ((error = git_diff_index_to_workdir(&diff, repo, index, &diff_opts)) < 0) goto done; if (git_diff_num_deltas(diff) > 0) { - giterr_set(GITERR_REBASE, "Unstaged changes exist in workdir"); + giterr_set(GITERR_REBASE, "unstaged changes exist in workdir"); error = fail_with; goto done; } @@ -624,7 +626,7 @@ static int rebase_init_merge( GIT_UNUSED(upstream); - if ((error = git_buf_joinpath(&state_path, repo->path_repository, REBASE_MERGE_DIR)) < 0) + if ((error = git_buf_joinpath(&state_path, repo->gitdir, REBASE_MERGE_DIR)) < 0) goto done; rebase->state_path = git_buf_detach(&state_path); @@ -731,7 +733,7 @@ int git_rebase_init( if (inmemory) error = rebase_init_inmemory(rebase, repo, branch, upstream, onto); else - rebase_init_merge(rebase, repo, branch ,upstream, onto); + error = rebase_init_merge(rebase, repo, branch ,upstream, onto); if (error == 0) *out = rebase; @@ -807,7 +809,7 @@ static int rebase_next_merge( goto done; if ((parent_count = git_commit_parentcount(current_commit)) > 1) { - giterr_set(GITERR_REBASE, "Cannot rebase a merge commit"); + giterr_set(GITERR_REBASE, "cannot rebase a merge commit"); error = -1; goto done; } else if (parent_count) { @@ -821,8 +823,8 @@ static int rebase_next_merge( normalize_checkout_options_for_apply(&checkout_opts, rebase, current_commit); if ((error = git_indexwriter_init_for_operation(&indexwriter, rebase->repo, &checkout_opts.checkout_strategy)) < 0 || - (error = rebase_setupfile(rebase, MSGNUM_FILE, -1, "%" PRIuZ "\n", rebase->current+1)) < 0 || - (error = rebase_setupfile(rebase, CURRENT_FILE, -1, "%.*s\n", GIT_OID_HEXSZ, current_idstr)) < 0 || + (error = rebase_setupfile(rebase, MSGNUM_FILE, 0, "%" PRIuZ "\n", rebase->current+1)) < 0 || + (error = rebase_setupfile(rebase, CURRENT_FILE, 0, "%.*s\n", GIT_OID_HEXSZ, current_idstr)) < 0 || (error = git_merge_trees(&index, rebase->repo, parent_tree, head_tree, current_tree, &rebase->options.merge_options)) < 0 || (error = git_merge__check_result(rebase->repo, index)) < 0 || (error = git_checkout_index(rebase->repo, index, &checkout_opts)) < 0 || @@ -864,7 +866,7 @@ static int rebase_next_inmemory( goto done; if ((parent_count = git_commit_parentcount(current_commit)) > 1) { - giterr_set(GITERR_REBASE, "Cannot rebase a merge commit"); + giterr_set(GITERR_REBASE, "cannot rebase a merge commit"); error = -1; goto done; } else if (parent_count) { @@ -1259,7 +1261,7 @@ static int rebase_copy_notes( goto done; on_error: - giterr_set(GITERR_REBASE, "Invalid rewritten file at line %d", linenum); + giterr_set(GITERR_REBASE, "invalid rewritten file at line %d", linenum); error = -1; done: diff --git a/src/refdb.c b/src/refdb.c index 85c84892b..1ee0efb31 100644 --- a/src/refdb.c +++ b/src/refdb.c @@ -128,7 +128,7 @@ int git_refdb_iterator(git_reference_iterator **out, git_refdb *db, const char * int error; if (!db->backend || !db->backend->iterator) { - giterr_set(GITERR_REFERENCE, "This backend doesn't support iterators"); + giterr_set(GITERR_REFERENCE, "this backend doesn't support iterators"); return -1; } diff --git a/src/refdb_fs.c b/src/refdb_fs.c index 8739d5b89..eb135dc01 100644 --- a/src/refdb_fs.c +++ b/src/refdb_fs.c @@ -26,8 +26,6 @@ #include #include -GIT__USE_STRMAP - #define DEFAULT_NESTING_LEVEL 5 #define MAX_NESTING_LEVEL 10 @@ -55,12 +53,16 @@ typedef struct refdb_fs_backend { git_refdb_backend parent; git_repository *repo; - char *path; + /* path to git directory */ + char *gitpath; + /* path to common objects' directory */ + char *commonpath; git_sortedcache *refcache; int peeling_mode; git_iterator_flag_t iterator_flags; uint32_t direach_flags; + int fsync; } refdb_fs_backend; static int refdb_reflog_fs__delete(git_refdb_backend *_backend, const char *name); @@ -77,7 +79,7 @@ static int packed_reload(refdb_fs_backend *backend) git_buf packedrefs = GIT_BUF_INIT; char *scan, *eof, *eol; - if (!backend->path) + if (!backend->gitpath) return 0; error = git_sortedcache_lockandload(backend->refcache, &packedrefs); @@ -185,7 +187,7 @@ static int packed_reload(refdb_fs_backend *backend) return 0; parse_failed: - giterr_set(GITERR_REFERENCE, "Corrupted packed references file"); + giterr_set(GITERR_REFERENCE, "corrupted packed references file"); git_sortedcache_clear(backend->refcache, false); git_sortedcache_wunlock(backend->refcache); @@ -212,7 +214,7 @@ static int loose_parse_oid( return 0; corrupted: - giterr_set(GITERR_REFERENCE, "Corrupted loose reference file: %s", filename); + giterr_set(GITERR_REFERENCE, "corrupted loose reference file: %s", filename); return -1; } @@ -238,7 +240,7 @@ static int loose_lookup_to_packfile(refdb_fs_backend *backend, const char *name) /* if we fail to load the loose reference, assume someone changed * the filesystem under us and skip it... */ - if (loose_readbuffer(&ref_file, backend->path, name) < 0) { + if (loose_readbuffer(&ref_file, backend->gitpath, name) < 0) { giterr_clear(); goto done; } @@ -287,7 +289,7 @@ static int _dirent_loose_load(void *payload, git_buf *full_path) return error; } - file_path = full_path->ptr + strlen(backend->path); + file_path = full_path->ptr + strlen(backend->gitpath); return loose_lookup_to_packfile(backend, file_path); } @@ -303,7 +305,7 @@ static int packed_loadloose(refdb_fs_backend *backend) int error; git_buf refs_path = GIT_BUF_INIT; - if (git_buf_joinpath(&refs_path, backend->path, GIT_REFS_DIR) < 0) + if (git_buf_joinpath(&refs_path, backend->gitpath, GIT_REFS_DIR) < 0) return -1; /* @@ -331,7 +333,7 @@ static int refdb_fs_backend__exists( assert(backend); if ((error = packed_reload(backend)) < 0 || - (error = git_buf_joinpath(&ref_path, backend->path, ref_name)) < 0) + (error = git_buf_joinpath(&ref_path, backend->gitpath, ref_name)) < 0) return error; *exists = git_path_isfile(ref_path.ptr) || @@ -349,7 +351,7 @@ static const char *loose_parse_symbolic(git_buf *file_content) refname_start = (const char *)file_content->ptr; if (git_buf_len(file_content) < header_len + 1) { - giterr_set(GITERR_REFERENCE, "Corrupted loose reference file"); + giterr_set(GITERR_REFERENCE, "corrupted loose reference file"); return NULL; } @@ -362,6 +364,19 @@ static const char *loose_parse_symbolic(git_buf *file_content) return refname_start; } +/* + * Returns whether a reference is stored per worktree or not. + * Per-worktree references are: + * + * - all pseudorefs, e.g. HEAD and MERGE_HEAD + * - all references stored inside of "refs/bisect/" + */ +static bool is_per_worktree_ref(const char *ref_name) +{ + return git__prefixcmp(ref_name, "refs/") != 0 || + git__prefixcmp(ref_name, "refs/bisect/") == 0; +} + static int loose_lookup( git_reference **out, refdb_fs_backend *backend, @@ -369,11 +384,17 @@ static int loose_lookup( { git_buf ref_file = GIT_BUF_INIT; int error = 0; + const char *ref_dir; if (out) *out = NULL; - if ((error = loose_readbuffer(&ref_file, backend->path, ref_name)) < 0) + if (is_per_worktree_ref(ref_name)) + ref_dir = backend->gitpath; + else + ref_dir = backend->commonpath; + + if ((error = loose_readbuffer(&ref_file, ref_dir, ref_name)) < 0) /* cannot read loose ref file - gah */; else if (git__prefixcmp(git_buf_cstr(&ref_file), GIT_SYMREF) == 0) { const char *target; @@ -398,7 +419,7 @@ static int loose_lookup( static int ref_error_notfound(const char *name) { - giterr_set(GITERR_REFERENCE, "Reference '%s' not found", name); + giterr_set(GITERR_REFERENCE, "reference '%s' not found", name); return GIT_ENOTFOUND; } @@ -484,12 +505,12 @@ static int iter_load_loose_paths(refdb_fs_backend *backend, refdb_fs_iter *iter) git_iterator_options fsit_opts = GIT_ITERATOR_OPTIONS_INIT; const git_index_entry *entry = NULL; - if (!backend->path) /* do nothing if no path for loose refs */ + if (!backend->commonpath) /* do nothing if no commonpath for loose refs */ return 0; fsit_opts.flags = backend->iterator_flags; - if ((error = git_buf_printf(&path, "%s/refs", backend->path)) < 0 || + if ((error = git_buf_printf(&path, "%s/refs", backend->commonpath)) < 0 || (error = git_iterator_for_filesystem(&fsit, path.ptr, &fsit_opts)) < 0) { git_buf_free(&path); return error; @@ -691,7 +712,7 @@ static int reference_path_available( if (exists) { giterr_set(GITERR_REFERENCE, - "Failed to write reference '%s': a reference with " + "failed to write reference '%s': a reference with " "that name already exists.", new_ref); return GIT_EEXISTS; } @@ -705,7 +726,7 @@ static int reference_path_available( if (ref && !ref_is_available(old_ref, new_ref, ref->name)) { git_sortedcache_runlock(backend->refcache); giterr_set(GITERR_REFERENCE, - "Path to reference '%s' collides with existing one", new_ref); + "path to reference '%s' collides with existing one", new_ref); return -1; } } @@ -716,26 +737,36 @@ static int reference_path_available( static int loose_lock(git_filebuf *file, refdb_fs_backend *backend, const char *name) { - int error; + int error, filebuf_flags; git_buf ref_path = GIT_BUF_INIT; + const char *basedir; assert(file && backend && name); if (!git_path_isvalid(backend->repo, name, GIT_PATH_REJECT_FILESYSTEM_DEFAULTS)) { - giterr_set(GITERR_INVALID, "Invalid reference name '%s'.", name); + giterr_set(GITERR_INVALID, "invalid reference name '%s'", name); return GIT_EINVALIDSPEC; } + if (is_per_worktree_ref(name)) + basedir = backend->gitpath; + else + basedir = backend->commonpath; + /* Remove a possibly existing empty directory hierarchy * which name would collide with the reference name */ - if ((error = git_futils_rmdir_r(name, backend->path, GIT_RMDIR_SKIP_NONEMPTY)) < 0) + if ((error = git_futils_rmdir_r(name, basedir, GIT_RMDIR_SKIP_NONEMPTY)) < 0) return error; - if (git_buf_joinpath(&ref_path, backend->path, name) < 0) + if (git_buf_joinpath(&ref_path, basedir, name) < 0) return -1; - error = git_filebuf_open(file, ref_path.ptr, GIT_FILEBUF_FORCE, GIT_REFS_FILE_MODE); + filebuf_flags = GIT_FILEBUF_FORCE; + if (backend->fsync) + filebuf_flags |= GIT_FILEBUF_FSYNC; + + error = git_filebuf_open(file, ref_path.ptr, filebuf_flags, GIT_REFS_FILE_MODE); if (error == GIT_EDIRECTORY) giterr_set(GITERR_REFERENCE, "cannot lock ref '%s', there are refs beneath that folder", name); @@ -970,15 +1001,18 @@ static int packed_write(refdb_fs_backend *backend) { git_sortedcache *refcache = backend->refcache; git_filebuf pack_file = GIT_FILEBUF_INIT; - int error; + int error, open_flags = 0; size_t i; /* lock the cache to updates while we do this */ if ((error = git_sortedcache_wlock(refcache)) < 0) return error; + if (backend->fsync) + open_flags = GIT_FILEBUF_FSYNC; + /* Open the file! */ - if ((error = git_filebuf_open(&pack_file, git_sortedcache_path(refcache), 0, GIT_PACKEDREFS_FILE_MODE)) < 0) + if ((error = git_filebuf_open(&pack_file, git_sortedcache_path(refcache), open_flags, GIT_PACKEDREFS_FILE_MODE)) < 0) goto fail; /* Packfiles have a header... apparently @@ -1106,7 +1140,7 @@ out: static int maybe_append_head(refdb_fs_backend *backend, const git_reference *ref, const git_signature *who, const char *message) { int error; - git_oid old_id = {{0}}; + git_oid old_id; git_reference *tmp = NULL, *head = NULL, *peeled = NULL; const char *name; @@ -1114,7 +1148,8 @@ static int maybe_append_head(refdb_fs_backend *backend, const git_reference *ref return 0; /* if we can't resolve, we use {0}*40 as old id */ - git_reference_name_to_id(&old_id, backend->repo, ref->name); + if (git_reference_name_to_id(&old_id, backend->repo, ref->name) < 0) + memset(&old_id, 0, sizeof(old_id)); if ((error = git_reference_lookup(&head, backend->repo, GIT_HEAD_FILE)) < 0) return error; @@ -1283,7 +1318,7 @@ static int refdb_fs_backend__delete_tail( } /* If a loose reference exists, remove it from the filesystem */ - if (git_buf_joinpath(&loose_path, backend->path, ref_name) < 0) + if (git_buf_joinpath(&loose_path, backend->gitpath, ref_name) < 0) return -1; @@ -1408,28 +1443,30 @@ static void refdb_fs_backend__free(git_refdb_backend *_backend) assert(backend); git_sortedcache_free(backend->refcache); - git__free(backend->path); + git__free(backend->gitpath); + git__free(backend->commonpath); git__free(backend); } -static int setup_namespace(git_buf *path, git_repository *repo) +static char *setup_namespace(git_repository *repo, const char *in) { - char *parts, *start, *end; + git_buf path = GIT_BUF_INIT; + char *parts, *start, *end, *out = NULL; - /* Not all repositories have a path */ - if (repo->path_repository == NULL) - return 0; + if (!in) + goto done; - /* Load the path to the repo first */ - git_buf_puts(path, repo->path_repository); + git_buf_puts(&path, in); /* if the repo is not namespaced, nothing else to do */ - if (repo->namespace == NULL) - return 0; + if (repo->namespace == NULL) { + out = git_buf_detach(&path); + goto done; + } parts = end = git__strdup(repo->namespace); if (parts == NULL) - return -1; + goto done; /* * From `man gitnamespaces`: @@ -1437,21 +1474,24 @@ static int setup_namespace(git_buf *path, git_repository *repo) * of namespaces; for example, GIT_NAMESPACE=foo/bar will store * refs under refs/namespaces/foo/refs/namespaces/bar/ */ - while ((start = git__strsep(&end, "/")) != NULL) { - git_buf_printf(path, "refs/namespaces/%s/", start); - } + while ((start = git__strsep(&end, "/")) != NULL) + git_buf_printf(&path, "refs/namespaces/%s/", start); - git_buf_printf(path, "refs/namespaces/%s/refs", end); + git_buf_printf(&path, "refs/namespaces/%s/refs", end); git__free(parts); /* Make sure that the folder with the namespace exists */ - if (git_futils_mkdir_relative(git_buf_cstr(path), repo->path_repository, - 0777, GIT_MKDIR_PATH, NULL) < 0) - return -1; + if (git_futils_mkdir_relative(git_buf_cstr(&path), in, 0777, + GIT_MKDIR_PATH, NULL) < 0) + goto done; - /* Return root of the namespaced path, i.e. without the trailing '/refs' */ - git_buf_rtruncate_at_char(path, '/'); - return 0; + /* Return root of the namespaced gitpath, i.e. without the trailing '/refs' */ + git_buf_rtruncate_at_char(&path, '/'); + out = git_buf_detach(&path); + +done: + git_buf_free(&path); + return out; } static int reflog_alloc(git_reflog **reflog, const char *name) @@ -1484,7 +1524,7 @@ static int reflog_parse(git_reflog *log, const char *buf, size_t buf_size) #define seek_forward(_increase) do { \ if (_increase >= buf_size) { \ - giterr_set(GITERR_INVALID, "Ran out of data while parsing reflog"); \ + giterr_set(GITERR_INVALID, "ran out of data while parsing reflog"); \ goto fail; \ } \ buf += _increase; \ @@ -1562,7 +1602,7 @@ static int create_new_reflog_file(const char *filepath) GIT_INLINE(int) retrieve_reflog_path(git_buf *path, git_repository *repo, const char *name) { - return git_buf_join3(path, '/', repo->path_repository, GIT_REFLOG_DIR, name); + return git_buf_join3(path, '/', repo->commondir, GIT_REFLOG_DIR, name); } static int refdb_reflog_fs__ensure_log(git_refdb_backend *_backend, const char *name) @@ -1700,7 +1740,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)) { - giterr_set(GITERR_INVALID, "Invalid reference name '%s'.", refname); + giterr_set(GITERR_INVALID, "invalid reference name '%s'", refname); return GIT_EINVALIDSPEC; } @@ -1709,7 +1749,7 @@ static int lock_reflog(git_filebuf *file, refdb_fs_backend *backend, const char if (!git_path_isfile(git_buf_cstr(&log_path))) { giterr_set(GITERR_INVALID, - "Log file for reference '%s' doesn't exist.", refname); + "log file for reference '%s' doesn't exist", refname); error = -1; goto cleanup; } @@ -1761,7 +1801,7 @@ success: /* Append to the reflog, must be called under reference lock */ static int reflog_append(refdb_fs_backend *backend, const git_reference *ref, const git_oid *old, const git_oid *new, const git_signature *who, const char *message) { - int error, is_symbolic; + int error, is_symbolic, open_flags; git_oid old_id = {{0}}, new_id = {{0}}; git_buf buf = GIT_BUF_INIT, path = GIT_BUF_INIT; git_repository *repo = backend->repo; @@ -1829,7 +1869,12 @@ static int reflog_append(refdb_fs_backend *backend, const git_reference *ref, co goto cleanup; } - error = git_futils_writebuffer(&buf, git_buf_cstr(&path), O_WRONLY|O_CREAT|O_APPEND, GIT_REFLOG_FILE_MODE); + open_flags = O_WRONLY | O_CREAT | O_APPEND; + + if (backend->fsync) + open_flags |= O_FSYNC; + + error = git_futils_writebuffer(&buf, git_buf_cstr(&path), open_flags, GIT_REFLOG_FILE_MODE); cleanup: git_buf_free(&buf); @@ -1857,7 +1902,7 @@ static int refdb_reflog_fs__rename(git_refdb_backend *_backend, const char *old_ &normalized, new_name, GIT_REF_FORMAT_ALLOW_ONELEVEL)) < 0) return error; - if (git_buf_joinpath(&temp_path, repo->path_repository, GIT_REFLOG_DIR) < 0) + if (git_buf_joinpath(&temp_path, repo->gitdir, GIT_REFLOG_DIR) < 0) return -1; if (git_buf_joinpath(&old_path, git_buf_cstr(&temp_path), old_name) < 0) @@ -1889,7 +1934,7 @@ static int refdb_reflog_fs__rename(git_refdb_backend *_backend, const char *old_ p_close(fd); if (p_rename(git_buf_cstr(&old_path), git_buf_cstr(&temp_path)) < 0) { - giterr_set(GITERR_OS, "Failed to rename reflog for %s", new_name); + giterr_set(GITERR_OS, "failed to rename reflog for %s", new_name); error = -1; goto cleanup; } @@ -1906,7 +1951,7 @@ static int refdb_reflog_fs__rename(git_refdb_backend *_backend, const char *old_ } if (p_rename(git_buf_cstr(&temp_path), git_buf_cstr(&new_path)) < 0) { - giterr_set(GITERR_OS, "Failed to rename reflog for %s", new_name); + giterr_set(GITERR_OS, "failed to rename reflog for %s", new_name); error = -1; } @@ -1948,7 +1993,7 @@ int git_refdb_backend_fs( git_repository *repository) { int t = 0; - git_buf path = GIT_BUF_INIT; + git_buf gitpath = GIT_BUF_INIT; refdb_fs_backend *backend; backend = git__calloc(1, sizeof(refdb_fs_backend)); @@ -1956,18 +2001,27 @@ int git_refdb_backend_fs( backend->repo = repository; - if (setup_namespace(&path, repository) < 0) - goto fail; + if (repository->gitdir) { + backend->gitpath = setup_namespace(repository, repository->gitdir); - backend->path = git_buf_detach(&path); + if (backend->gitpath == NULL) + goto fail; + } - if (git_buf_joinpath(&path, backend->path, GIT_PACKEDREFS_FILE) < 0 || + if (repository->commondir) { + backend->commonpath = setup_namespace(repository, repository->commondir); + + if (backend->commonpath == NULL) + goto fail; + } + + if (git_buf_joinpath(&gitpath, backend->commonpath, GIT_PACKEDREFS_FILE) < 0 || git_sortedcache_new( &backend->refcache, offsetof(struct packref, name), - NULL, NULL, packref_cmp, git_buf_cstr(&path)) < 0) + NULL, NULL, packref_cmp, git_buf_cstr(&gitpath)) < 0) goto fail; - git_buf_free(&path); + git_buf_free(&gitpath); if (!git_repository__cvar(&t, backend->repo, GIT_CVAR_IGNORECASE) && t) { backend->iterator_flags |= GIT_ITERATOR_IGNORE_CASE; @@ -1977,6 +2031,9 @@ int git_refdb_backend_fs( backend->iterator_flags |= GIT_ITERATOR_PRECOMPOSE_UNICODE; backend->direach_flags |= GIT_PATH_DIR_PRECOMPOSE_UNICODE; } + if ((!git_repository__cvar(&t, backend->repo, GIT_CVAR_FSYNCOBJECTFILES) && t) || + git_repository__fsync_gitdir) + backend->fsync = 1; backend->parent.exists = &refdb_fs_backend__exists; backend->parent.lookup = &refdb_fs_backend__lookup; @@ -1999,8 +2056,9 @@ int git_refdb_backend_fs( return 0; fail: - git_buf_free(&path); - git__free(backend->path); + git_buf_free(&gitpath); + git__free(backend->gitpath); + git__free(backend->commonpath); git__free(backend); return -1; } diff --git a/src/reflog.c b/src/reflog.c index 9ce9aee6f..98ef1b669 100644 --- a/src/reflog.c +++ b/src/reflog.c @@ -93,7 +93,7 @@ int git_reflog_append(git_reflog *reflog, const git_oid *new_oid, const git_sign if (newline) { if (newline[1] != '\0') { - giterr_set(GITERR_INVALID, "Reflog message cannot contain newline"); + giterr_set(GITERR_INVALID, "reflog message cannot contain newline"); goto cleanup; } @@ -193,7 +193,7 @@ int git_reflog_drop(git_reflog *reflog, size_t idx, int rewrite_previous_entry) entry = (git_reflog_entry *)git_reflog_entry_byindex(reflog, idx); if (entry == NULL) { - giterr_set(GITERR_REFERENCE, "No reflog entry at index %"PRIuZ, idx); + giterr_set(GITERR_REFERENCE, "no reflog entry at index %"PRIuZ, idx); return GIT_ENOTFOUND; } diff --git a/src/refs.c b/src/refs.c index bff443ac9..f7120d9ee 100644 --- a/src/refs.c +++ b/src/refs.c @@ -24,7 +24,7 @@ #include #include -GIT__USE_STRMAP +bool git_reference__enable_symbolic_ref_target_validation = true; #define DEFAULT_NESTING_LEVEL 5 #define MAX_NESTING_LEVEL 10 @@ -178,7 +178,8 @@ int git_reference_name_to_id( static int reference_normalize_for_repo( git_refname_t out, git_repository *repo, - const char *name) + const char *name, + bool validate) { int precompose; unsigned int flags = GIT_REF_FORMAT_ALLOW_ONELEVEL; @@ -187,6 +188,9 @@ static int reference_normalize_for_repo( precompose) flags |= GIT_REF_FORMAT__PRECOMPOSE_UNICODE; + if (!validate) + flags |= GIT_REF_FORMAT__VALIDATION_DISABLE; + return git_reference_normalize_name(out, GIT_REFNAME_MAX, name, flags); } @@ -213,7 +217,7 @@ int git_reference_lookup_resolved( scan_type = GIT_REF_SYMBOLIC; - if ((error = reference_normalize_for_repo(scan_name, repo, name)) < 0) + if ((error = reference_normalize_for_repo(scan_name, repo, name, true)) < 0) return error; if ((error = git_repository_refdb__weakptr(&refdb, repo)) < 0) @@ -236,7 +240,7 @@ int git_reference_lookup_resolved( if (scan_type != GIT_REF_OID && max_nesting != 0) { giterr_set(GITERR_REFERENCE, - "Cannot resolve reference (>%u levels deep)", max_nesting); + "cannot resolve reference (>%u levels deep)", max_nesting); git_reference_free(ref); return -1; } @@ -245,6 +249,40 @@ int git_reference_lookup_resolved( return 0; } +int git_reference__read_head( + git_reference **out, + git_repository *repo, + const char *path) +{ + git_buf reference = GIT_BUF_INIT; + char *name = NULL; + int error; + + if ((error = git_futils_readbuffer(&reference, path)) < 0) + goto out; + git_buf_rtrim(&reference); + + if (git__strncmp(reference.ptr, GIT_SYMREF, strlen(GIT_SYMREF)) == 0) { + git_buf_consume(&reference, reference.ptr + strlen(GIT_SYMREF)); + + name = git_path_basename(path); + + if ((*out = git_reference__alloc_symbolic(name, reference.ptr)) == NULL) { + error = -1; + goto out; + } + } else { + if ((error = git_reference_lookup(out, repo, reference.ptr)) < 0) + goto out; + } + +out: + git__free(name); + git_buf_free(&reference); + + return error; +} + int git_reference_dwim(git_reference **out, git_repository *repo, const char *refname) { int error = 0, i; @@ -298,7 +336,7 @@ cleanup: if (error && !foundvalid) { /* never found a valid reference name */ giterr_set(GITERR_REFERENCE, - "Could not use '%s' as valid reference name", git_buf_cstr(&name)); + "could not use '%s' as valid reference name", git_buf_cstr(&name)); } if (error == GIT_ENOTFOUND) @@ -383,7 +421,7 @@ static int reference__create( if (ref_out) *ref_out = NULL; - error = reference_normalize_for_repo(normalized, repo, name); + error = reference_normalize_for_repo(normalized, repo, name, true); if (error < 0) return error; @@ -396,7 +434,7 @@ static int reference__create( if (!git_object__is_valid(repo, oid, GIT_OBJ_ANY)) { giterr_set(GITERR_REFERENCE, - "Target OID for the reference doesn't exist on the repository"); + "target OID for the reference doesn't exist on the repository"); return -1; } @@ -404,7 +442,10 @@ static int reference__create( } else { git_refname_t normalized_target; - if ((error = reference_normalize_for_repo(normalized_target, repo, symbolic)) < 0) + error = reference_normalize_for_repo(normalized_target, repo, + symbolic, git_reference__enable_symbolic_ref_target_validation); + + if (error < 0) return error; ref = git_reference__alloc_symbolic(normalized, normalized_target); @@ -524,7 +565,7 @@ static int ensure_is_an_updatable_direct_reference(git_reference *ref) if (ref->type == GIT_REF_OID) return 0; - giterr_set(GITERR_REFERENCE, "Cannot set OID on symbolic reference"); + giterr_set(GITERR_REFERENCE, "cannot set OID on symbolic reference"); return -1; } @@ -552,7 +593,7 @@ static int ensure_is_an_updatable_symbolic_reference(git_reference *ref) if (ref->type == GIT_REF_SYMBOLIC) return 0; - giterr_set(GITERR_REFERENCE, "Cannot set symbolic target on a direct reference"); + giterr_set(GITERR_REFERENCE, "cannot set symbolic target on a direct reference"); return -1; } @@ -573,19 +614,62 @@ int git_reference_symbolic_set_target( out, ref->db->repo, ref->name, target, 1, ref->target.symbolic, log_message); } +typedef struct { + const char *old_name; + git_refname_t new_name; +} rename_cb_data; + +static int update_wt_heads(git_repository *repo, const char *path, void *payload) +{ + rename_cb_data *data = (rename_cb_data *) payload; + git_reference *head = NULL; + char *gitdir = NULL; + int error; + + if ((error = git_reference__read_head(&head, repo, path)) < 0) { + giterr_set(GITERR_REFERENCE, "could not read HEAD when renaming references"); + goto out; + } + + if ((gitdir = git_path_dirname(path)) == NULL) { + error = -1; + goto out; + } + + if (git_reference_type(head) != GIT_REF_SYMBOLIC || + git__strcmp(head->target.symbolic, data->old_name) != 0) { + error = 0; + goto out; + } + + /* Update HEAD it was pointing to the reference being renamed */ + if ((error = git_repository_create_head(gitdir, data->new_name)) < 0) { + giterr_set(GITERR_REFERENCE, "failed to update HEAD after renaming reference"); + goto out; + } + +out: + git_reference_free(head); + git__free(gitdir); + + return error; +} + static int reference__rename(git_reference **out, git_reference *ref, const char *new_name, int force, const git_signature *signature, const char *message) { + git_repository *repo; git_refname_t normalized; bool should_head_be_updated = false; int error = 0; assert(ref && new_name && signature); - if ((error = reference_normalize_for_repo( - normalized, git_reference_owner(ref), new_name)) < 0) - return error; + repo = git_reference_owner(ref); + if ((error = reference_normalize_for_repo( + normalized, repo, new_name, true)) < 0) + return error; /* Check if we have to update HEAD. */ if ((error = git_branch_is_head(ref)) < 0) @@ -596,14 +680,18 @@ static int reference__rename(git_reference **out, git_reference *ref, const char if ((error = git_refdb_rename(out, ref->db, ref->name, normalized, force, signature, message)) < 0) return error; - /* Update HEAD it was pointing to the reference being renamed */ - if (should_head_be_updated && - (error = git_repository_set_head(ref->db->repo, normalized)) < 0) { - giterr_set(GITERR_REFERENCE, "Failed to update HEAD after renaming reference"); - return error; + /* Update HEAD if it was pointing to the reference being renamed */ + if (should_head_be_updated) { + error = git_repository_set_head(ref->db->repo, normalized); + } else { + rename_cb_data payload; + payload.old_name = ref->name; + memcpy(&payload.new_name, &normalized, sizeof(normalized)); + + error = git_repository_foreach_head(repo, update_wt_heads, &payload); } - return 0; + return error; } @@ -636,7 +724,7 @@ int git_reference_resolve(git_reference **ref_out, const git_reference *ref) return git_reference_lookup_resolved(ref_out, ref->db->repo, ref->target.symbolic, -1); default: - giterr_set(GITERR_REFERENCE, "Invalid reference"); + giterr_set(GITERR_REFERENCE, "invalid reference"); return -1; } } @@ -876,6 +964,7 @@ int git_reference__normalize_name( int segment_len, segments_count = 0, error = GIT_EINVALIDSPEC; unsigned int process_flags; bool normalize = (buf != NULL); + bool validate = (flags & GIT_REF_FORMAT__VALIDATION_DISABLE) == 0; #ifdef GIT_USE_ICONV git_path_iconv_t ic = GIT_PATH_ICONV_INIT; @@ -886,7 +975,7 @@ int git_reference__normalize_name( process_flags = flags; current = (char *)name; - if (*current == '/') + if (validate && *current == '/') goto cleanup; if (normalize) @@ -902,6 +991,13 @@ int git_reference__normalize_name( } #endif + if (!validate) { + git_buf_sets(buf, current); + + error = git_buf_oom(buf) ? -1 : 0; + goto cleanup; + } + while (true) { segment_len = ensure_segment_validity(current); if (segment_len < 0) { @@ -973,7 +1069,7 @@ cleanup: if (error == GIT_EINVALIDSPEC) giterr_set( GITERR_REFERENCE, - "The given reference name '%s' is not valid", name); + "the given reference name '%s' is not valid", name); if (error && normalize) git_buf_free(buf); @@ -1000,7 +1096,7 @@ int git_reference_normalize_name( if (git_buf_len(&buf) > buffer_size - 1) { giterr_set( GITERR_REFERENCE, - "The provided buffer is too short to hold the normalization of '%s'", name); + "the provided buffer is too short to hold the normalization of '%s'", name); error = GIT_EBUFS; goto cleanup; } @@ -1046,7 +1142,7 @@ static int get_terminal(git_reference **out, git_repository *repo, const char *r int error = 0; if (nesting > MAX_NESTING_LEVEL) { - giterr_set(GITERR_REFERENCE, "Reference chain too deep (%d)", nesting); + giterr_set(GITERR_REFERENCE, "reference chain too deep (%d)", nesting); return GIT_ENOTFOUND; } @@ -1115,6 +1211,18 @@ int git_reference__update_terminal( return error; } +static const char *commit_type(const git_commit *commit) +{ + unsigned int count = git_commit_parentcount(commit); + + if (count >= 2) + return " (merge)"; + else if (count == 0) + return " (initial)"; + else + return ""; +} + int git_reference__update_for_commit( git_repository *repo, git_reference *ref, @@ -1131,7 +1239,7 @@ int git_reference__update_for_commit( if ((error = git_commit_lookup(&commit, repo, id)) < 0 || (error = git_buf_printf(&reflog_msg, "%s%s: %s", operation ? operation : "commit", - git_commit_parentcount(commit) == 0 ? " (initial)" : "", + commit_type(commit), git_commit_summary(commit))) < 0) goto done; @@ -1229,7 +1337,7 @@ static int peel_error(int error, git_reference *ref, const char* msg) { giterr_set( GITERR_INVALID, - "The reference '%s' cannot be peeled - %s", git_reference_name(ref), msg); + "the reference '%s' cannot be peeled - %s", git_reference_name(ref), msg); return error; } diff --git a/src/refs.h b/src/refs.h index fda9532de..0c90db3af 100644 --- a/src/refs.h +++ b/src/refs.h @@ -15,6 +15,8 @@ #include "buffer.h" #include "oid.h" +extern bool git_reference__enable_symbolic_ref_target_validation; + #define GIT_REFS_DIR "refs/" #define GIT_REFS_HEADS_DIR GIT_REFS_DIR "heads/" #define GIT_REFS_TAGS_DIR GIT_REFS_DIR "tags/" @@ -53,6 +55,7 @@ #define GIT_REFS_STASH_FILE GIT_REFS_DIR GIT_STASH_FILE #define GIT_REF_FORMAT__PRECOMPOSE_UNICODE (1u << 16) +#define GIT_REF_FORMAT__VALIDATION_DISABLE (1u << 15) #define GIT_REFNAME_MAX 1024 @@ -104,6 +107,20 @@ int git_reference_lookup_resolved( const char *name, int max_deref); +/** + * Read reference from a file. + * + * This function will read in the file at `path`. If it is a + * symref, it will return a new unresolved symbolic reference + * 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. + */ +int git_reference__read_head( + git_reference **out, + git_repository *repo, + const char *path); + int git_reference__log_signature(git_signature **out, git_repository *repo); /** Update a reference after a commit. */ diff --git a/src/remote.c b/src/remote.c index c1d7d59ea..bd8b3cfbc 100644 --- a/src/remote.c +++ b/src/remote.c @@ -192,7 +192,7 @@ static int canonicalize_url(git_buf *out, const char *in) static int create_internal(git_remote **out, git_repository *repo, const char *name, const char *url, const char *fetch) { git_remote *remote; - git_config *config = NULL; + git_config *config_ro = NULL, *config_rw; git_buf canonical_url = GIT_BUF_INIT; git_buf var = GIT_BUF_INIT; int error = -1; @@ -200,7 +200,7 @@ static int create_internal(git_remote **out, git_repository *repo, const char *n /* name is optional */ assert(out && repo && url); - if ((error = git_repository_config__weakptr(&config, repo)) < 0) + if ((error = git_repository_config_snapshot(&config_ro, repo)) < 0) return error; remote = git__calloc(1, sizeof(git_remote)); @@ -212,7 +212,8 @@ static int create_internal(git_remote **out, git_repository *repo, const char *n (error = canonicalize_url(&canonical_url, url)) < 0) goto on_error; - remote->url = apply_insteadof(repo->_config, canonical_url.ptr, GIT_DIRECTION_FETCH); + remote->url = apply_insteadof(config_ro, canonical_url.ptr, GIT_DIRECTION_FETCH); + GITERR_CHECK_ALLOC(remote->url); if (name != NULL) { remote->name = git__strdup(name); @@ -221,7 +222,8 @@ static int create_internal(git_remote **out, git_repository *repo, const char *n if ((error = git_buf_printf(&var, CONFIG_URL_FMT, name)) < 0) goto on_error; - if ((error = git_config_set_string(config, var.ptr, canonical_url.ptr)) < 0) + if ((error = git_repository_config__weakptr(&config_rw, repo)) < 0 || + (error = git_config_set_string(config_rw, var.ptr, canonical_url.ptr)) < 0) goto on_error; } @@ -233,10 +235,7 @@ static int create_internal(git_remote **out, git_repository *repo, const char *n if (name && (error = write_add_refspec(repo, name, fetch, true)) < 0) goto on_error; - if ((error = git_repository_config_snapshot(&config, repo)) < 0) - goto on_error; - - if ((error = lookup_remote_prune_config(remote, config, name)) < 0) + if ((error = lookup_remote_prune_config(remote, config_ro, name)) < 0) goto on_error; /* Move the data over to where the matching functions can find them */ @@ -260,7 +259,7 @@ on_error: if (error) git_remote_free(remote); - git_config_free(config); + git_config_free(config_ro); git_buf_free(&canonical_url); git_buf_free(&var); return error; @@ -283,7 +282,7 @@ static int ensure_remote_doesnot_exist(git_repository *repo, const char *name) giterr_set( GITERR_CONFIG, - "Remote '%s' already exists.", name); + "remote '%s' already exists", name); return GIT_EEXISTS; } @@ -476,7 +475,7 @@ int git_remote_lookup(git_remote **out, git_repository *repo, const char *name) if (!optional_setting_found) { error = GIT_ENOTFOUND; - giterr_set(GITERR_CONFIG, "Remote '%s' does not exist.", name); + giterr_set(GITERR_CONFIG, "remote '%s' does not exist", name); goto cleanup; } @@ -770,8 +769,12 @@ int git_remote__get_http_proxy(git_remote *remote, bool use_ssl, char **proxy_ur goto found; } - /* HTTP_PROXY / HTTPS_PROXY environment variables */ - error = git__getenv(&val, use_ssl ? "HTTPS_PROXY" : "HTTP_PROXY"); + /* http_proxy / https_proxy environment variables */ + error = git__getenv(&val, use_ssl ? "https_proxy" : "http_proxy"); + + /* try uppercase environment variables */ + if (error == GIT_ENOTFOUND) + error = git__getenv(&val, use_ssl ? "HTTPS_PROXY" : "HTTP_PROXY"); if (error < 0) { if (error == GIT_ENOTFOUND) { @@ -1718,7 +1721,7 @@ int git_remote_set_autotag(git_repository *repo, const char *remote, git_remote_ error = 0; break; default: - giterr_set(GITERR_INVALID, "Invalid value for the tagopt setting"); + giterr_set(GITERR_INVALID, "invalid value for the tagopt setting"); error = -1; } @@ -2408,7 +2411,7 @@ int git_remote_push(git_remote *remote, const git_strarray *refspecs, const git_ proxy = &opts->proxy_opts; } - assert(remote && refspecs); + assert(remote); if ((error = git_remote_connect(remote, GIT_DIRECTION_PUSH, cbs, proxy, custom_headers)) < 0) return error; diff --git a/src/repository.c b/src/repository.c index 5c4442360..7ecb00ed8 100644 --- a/src/repository.c +++ b/src/repository.c @@ -27,13 +27,43 @@ #include "merge.h" #include "diff_driver.h" #include "annotated_commit.h" +#include "submodule.h" +#include "worktree.h" + +#include "strmap.h" #ifdef GIT_WIN32 # include "win32/w32_util.h" #endif +bool git_repository__fsync_gitdir = false; + +static const struct { + git_repository_item_t parent; + const char *name; + bool directory; +} items[] = { + { GIT_REPOSITORY_ITEM_GITDIR, NULL, true }, + { GIT_REPOSITORY_ITEM_WORKDIR, NULL, true }, + { GIT_REPOSITORY_ITEM_COMMONDIR, NULL, true }, + { GIT_REPOSITORY_ITEM_GITDIR, "index", false }, + { GIT_REPOSITORY_ITEM_COMMONDIR, "objects", true }, + { GIT_REPOSITORY_ITEM_COMMONDIR, "refs", true }, + { GIT_REPOSITORY_ITEM_COMMONDIR, "packed-refs", false }, + { GIT_REPOSITORY_ITEM_COMMONDIR, "remotes", true }, + { GIT_REPOSITORY_ITEM_COMMONDIR, "config", false }, + { GIT_REPOSITORY_ITEM_COMMONDIR, "info", true }, + { GIT_REPOSITORY_ITEM_COMMONDIR, "hooks", true }, + { GIT_REPOSITORY_ITEM_COMMONDIR, "logs", true }, + { GIT_REPOSITORY_ITEM_GITDIR, "modules", true }, + { GIT_REPOSITORY_ITEM_COMMONDIR, "worktrees", true } +}; + static int check_repositoryformatversion(git_config *config); +#define GIT_COMMONDIR_FILE "commondir" +#define GIT_GITDIR_FILE "gitdir" + #define GIT_FILE_CONTENT_PREFIX "gitdir:" #define GIT_BRANCH_MASTER "master" @@ -109,6 +139,7 @@ void git_repository__cleanup(git_repository *repo) { assert(repo); + git_repository_submodule_cache_clear(repo); git_cache_clear(&repo->objects); git_attr_cache_flush(repo); @@ -136,8 +167,9 @@ void git_repository_free(git_repository *repo) git_buf_free(git_array_get(repo->reserved_names, i)); git_array_clear(repo->reserved_names); - git__free(repo->path_gitlink); - git__free(repo->path_repository); + git__free(repo->gitlink); + git__free(repo->gitdir); + git__free(repo->commondir); git__free(repo->workdir); git__free(repo->namespace); git__free(repo->ident_name); @@ -152,17 +184,41 @@ void git_repository_free(git_repository *repo) * * Open a repository object from its path */ -static bool valid_repository_path(git_buf *repository_path) +static bool valid_repository_path(git_buf *repository_path, git_buf *common_path) { - /* Check OBJECTS_DIR first, since it will generate the longest path name */ - if (git_path_contains_dir(repository_path, GIT_OBJECTS_DIR) == false) - return false; + /* Check if we have a separate commondir (e.g. we have a + * worktree) */ + if (git_path_contains_file(repository_path, GIT_COMMONDIR_FILE)) { + git_buf common_link = GIT_BUF_INIT; + git_buf_joinpath(&common_link, repository_path->ptr, GIT_COMMONDIR_FILE); + + git_futils_readbuffer(&common_link, common_link.ptr); + git_buf_rtrim(&common_link); + + if (git_path_is_relative(common_link.ptr)) { + git_buf_joinpath(common_path, repository_path->ptr, common_link.ptr); + } else { + git_buf_swap(common_path, &common_link); + } + + git_buf_free(&common_link); + } + else { + git_buf_set(common_path, repository_path->ptr, repository_path->size); + } + + /* Make sure the commondir path always has a trailing * slash */ + if (git_buf_rfind(common_path, '/') != (ssize_t)common_path->size - 1) + git_buf_putc(common_path, '/'); /* Ensure HEAD file exists */ if (git_path_contains_file(repository_path, GIT_HEAD_FILE) == false) return false; - if (git_path_contains_dir(repository_path, GIT_REFS_DIR) == false) + /* Check files in common dir */ + if (git_path_contains_dir(common_path, GIT_OBJECTS_DIR) == false) + return false; + if (git_path_contains_dir(common_path, GIT_REFS_DIR) == false) return false; return true; @@ -201,6 +257,7 @@ int git_repository_new(git_repository **out) GITERR_CHECK_ALLOC(repo); repo->is_bare = 1; + repo->is_worktree = 0; return 0; } @@ -220,9 +277,10 @@ static int load_config_data(git_repository *repo, const git_config *config) static int load_workdir(git_repository *repo, git_config *config, git_buf *parent_path) { - int error; + int error; git_config_entry *ce; - git_buf worktree = GIT_BUF_INIT; + git_buf worktree = GIT_BUF_INIT; + git_buf path = GIT_BUF_INIT; if (repo->is_bare) return 0; @@ -231,9 +289,26 @@ static int load_workdir(git_repository *repo, git_config *config, git_buf *paren &ce, config, "core.worktree", false)) < 0) return error; - if (ce && ce->value) { + if (repo->is_worktree) { + char *gitlink = git_worktree__read_link(repo->gitdir, GIT_GITDIR_FILE); + if (!gitlink) { + error = -1; + goto cleanup; + } + + git_buf_attach(&worktree, gitlink, 0); + + if ((git_path_dirname_r(&worktree, worktree.ptr)) < 0 || + git_path_to_dir(&worktree) < 0) { + error = -1; + goto cleanup; + } + + repo->workdir = git_buf_detach(&worktree); + } + else if (ce && ce->value) { if ((error = git_path_prettify_dir( - &worktree, ce->value, repo->path_repository)) < 0) + &worktree, ce->value, repo->gitdir)) < 0) goto cleanup; repo->workdir = git_buf_detach(&worktree); @@ -241,7 +316,7 @@ static int load_workdir(git_repository *repo, git_config *config, git_buf *paren else if (parent_path && git_path_isdir(parent_path->ptr)) repo->workdir = git_buf_detach(parent_path); else { - if (git_path_dirname_r(&worktree, repo->path_repository) < 0 || + if (git_path_dirname_r(&worktree, repo->gitdir) < 0 || git_path_to_dir(&worktree) < 0) { error = -1; goto cleanup; @@ -252,6 +327,7 @@ static int load_workdir(git_repository *repo, git_config *config, git_buf *paren GITERR_CHECK_ALLOC(repo->workdir); cleanup: + git_buf_free(&path); git_config_entry_free(ce); return error; } @@ -332,7 +408,7 @@ static int read_gitfile(git_buf *path_out, const char *file_path) memcmp(git_buf_cstr(&file), GIT_FILE_CONTENT_PREFIX, prefix_len) != 0) { giterr_set(GITERR_REPOSITORY, - "The `.git` file at '%s' is malformed", file_path); + "the `.git` file at '%s' is malformed", file_path); error = -1; } else if ((error = git_path_dirname_r(path_out, file_path)) >= 0) { @@ -348,9 +424,10 @@ static int read_gitfile(git_buf *path_out, const char *file_path) } static int find_repo( - git_buf *repo_path, - git_buf *parent_path, - git_buf *link_path, + git_buf *gitdir_path, + git_buf *workdir_path, + git_buf *gitlink_path, + git_buf *commondir_path, const char *start_path, uint32_t flags, const char *ceiling_dirs) @@ -358,13 +435,14 @@ static int find_repo( int error; git_buf path = GIT_BUF_INIT; git_buf repo_link = GIT_BUF_INIT; + git_buf common_link = GIT_BUF_INIT; struct stat st; dev_t initial_device = 0; int min_iterations; bool in_dot_git; size_t ceiling_offset = 0; - git_buf_free(repo_path); + git_buf_clear(gitdir_path); error = git_path_prettify(&path, start_path, NULL); if (error < 0) @@ -404,9 +482,16 @@ static int find_repo( break; if (S_ISDIR(st.st_mode)) { - if (valid_repository_path(&path)) { + if (valid_repository_path(&path, &common_link)) { git_path_to_dir(&path); - git_buf_set(repo_path, path.ptr, path.size); + git_buf_set(gitdir_path, path.ptr, path.size); + + if (gitlink_path) + git_buf_attach(gitlink_path, + git_worktree__read_link(path.ptr, GIT_GITDIR_FILE), 0); + if (commondir_path) + git_buf_swap(&common_link, commondir_path); + break; } } @@ -414,11 +499,13 @@ static int find_repo( error = read_gitfile(&repo_link, path.ptr); if (error < 0) break; - if (valid_repository_path(&repo_link)) { - git_buf_swap(repo_path, &repo_link); + if (valid_repository_path(&repo_link, &common_link)) { + git_buf_swap(gitdir_path, &repo_link); - if (link_path) - error = git_buf_put(link_path, path.ptr, path.size); + if (gitlink_path) + error = git_buf_put(gitlink_path, path.ptr, path.size); + if (commondir_path) + git_buf_swap(&common_link, commondir_path); } break; } @@ -444,27 +531,28 @@ static int find_repo( break; } - if (!error && parent_path && !(flags & GIT_REPOSITORY_OPEN_BARE)) { - if (!git_buf_len(repo_path)) - git_buf_clear(parent_path); + if (!error && workdir_path && !(flags & GIT_REPOSITORY_OPEN_BARE)) { + if (!git_buf_len(gitdir_path)) + git_buf_clear(workdir_path); else { - git_path_dirname_r(parent_path, path.ptr); - git_path_to_dir(parent_path); + git_path_dirname_r(workdir_path, path.ptr); + git_path_to_dir(workdir_path); } - if (git_buf_oom(parent_path)) + if (git_buf_oom(workdir_path)) return -1; } /* If we didn't find the repository, and we don't have any other error * to report, report that. */ - if (!git_buf_len(repo_path) && !error) { + if (!git_buf_len(gitdir_path) && !error) { giterr_set(GITERR_REPOSITORY, - "Could not find repository from '%s'", start_path); + "could not find repository from '%s'", start_path); error = GIT_ENOTFOUND; } git_buf_free(&path); git_buf_free(&repo_link); + git_buf_free(&common_link); return error; } @@ -473,26 +561,30 @@ int git_repository_open_bare( const char *bare_path) { int error; - git_buf path = GIT_BUF_INIT; + git_buf path = GIT_BUF_INIT, common_path = GIT_BUF_INIT; git_repository *repo = NULL; if ((error = git_path_prettify_dir(&path, bare_path, NULL)) < 0) return error; - if (!valid_repository_path(&path)) { + if (!valid_repository_path(&path, &common_path)) { git_buf_free(&path); - giterr_set(GITERR_REPOSITORY, "Path is not a repository: %s", bare_path); + git_buf_free(&common_path); + giterr_set(GITERR_REPOSITORY, "path is not a repository: %s", bare_path); return GIT_ENOTFOUND; } repo = repository_alloc(); GITERR_CHECK_ALLOC(repo); - repo->path_repository = git_buf_detach(&path); - GITERR_CHECK_ALLOC(repo->path_repository); + repo->gitdir = git_buf_detach(&path); + GITERR_CHECK_ALLOC(repo->gitdir); + repo->commondir = git_buf_detach(&common_path); + GITERR_CHECK_ALLOC(repo->commondir); /* of course we're bare! */ repo->is_bare = 1; + repo->is_worktree = 0; repo->workdir = NULL; *repo_ptr = repo; @@ -668,6 +760,29 @@ success: return error; } +static int repo_is_worktree(unsigned *out, const git_repository *repo) +{ + git_buf gitdir_link = GIT_BUF_INIT; + int error; + + /* Worktrees cannot have the same commondir and gitdir */ + if (repo->commondir && repo->gitdir + && !strcmp(repo->commondir, repo->gitdir)) { + *out = 0; + return 0; + } + + if ((error = git_buf_joinpath(&gitdir_link, repo->gitdir, "gitdir")) < 0) + return -1; + + /* A 'gitdir' file inside a git directory is currently + * only used when the repository is a working tree. */ + *out = !!git_path_exists(gitdir_link.ptr); + + git_buf_free(&gitdir_link); + return error; +} + int git_repository_open_ext( git_repository **repo_ptr, const char *start_path, @@ -675,8 +790,9 @@ int git_repository_open_ext( const char *ceiling_dirs) { int error; - git_buf path = GIT_BUF_INIT, parent = GIT_BUF_INIT, - link_path = GIT_BUF_INIT; + unsigned is_worktree; + git_buf gitdir = GIT_BUF_INIT, workdir = GIT_BUF_INIT, + gitlink = GIT_BUF_INIT, commondir = GIT_BUF_INIT; git_repository *repo; git_config *config = NULL; @@ -687,7 +803,7 @@ int git_repository_open_ext( *repo_ptr = NULL; error = find_repo( - &path, &parent, &link_path, start_path, flags, ceiling_dirs); + &gitdir, &workdir, &gitlink, &commondir, start_path, flags, ceiling_dirs); if (error < 0 || !repo_ptr) return error; @@ -695,13 +811,21 @@ int git_repository_open_ext( repo = repository_alloc(); GITERR_CHECK_ALLOC(repo); - repo->path_repository = git_buf_detach(&path); - GITERR_CHECK_ALLOC(repo->path_repository); + repo->gitdir = git_buf_detach(&gitdir); + GITERR_CHECK_ALLOC(repo->gitdir); - if (link_path.size) { - repo->path_gitlink = git_buf_detach(&link_path); - GITERR_CHECK_ALLOC(repo->path_gitlink); + if (gitlink.size) { + repo->gitlink = git_buf_detach(&gitlink); + GITERR_CHECK_ALLOC(repo->gitlink); } + if (commondir.size) { + repo->commondir = git_buf_detach(&commondir); + GITERR_CHECK_ALLOC(repo->commondir); + } + + if ((error = repo_is_worktree(&is_worktree, repo)) < 0) + goto cleanup; + repo->is_worktree = is_worktree; /* * We'd like to have the config, but git doesn't particularly @@ -721,12 +845,13 @@ int git_repository_open_ext( if (config && ((error = load_config_data(repo, config)) < 0 || - (error = load_workdir(repo, config, &parent)) < 0)) + (error = load_workdir(repo, config, &workdir)) < 0)) goto cleanup; } cleanup: - git_buf_free(&parent); + git_buf_free(&gitdir); + git_buf_free(&workdir); git_config_free(config); if (error < 0) @@ -743,6 +868,36 @@ int git_repository_open(git_repository **repo_out, const char *path) repo_out, path, GIT_REPOSITORY_OPEN_NO_SEARCH, NULL); } +int git_repository_open_from_worktree(git_repository **repo_out, git_worktree *wt) +{ + git_buf path = GIT_BUF_INIT; + git_repository *repo = NULL; + int len, err; + + assert(repo_out && wt); + + *repo_out = NULL; + len = strlen(wt->gitlink_path); + + if (len <= 4 || strcasecmp(wt->gitlink_path + len - 4, ".git")) { + err = -1; + goto out; + } + + if ((err = git_buf_set(&path, wt->gitlink_path, len - 4)) < 0) + goto out; + + if ((err = git_repository_open(&repo, path.ptr)) < 0) + goto out; + + *repo_out = repo; + +out: + git_buf_free(&path); + + return err; +} + int git_repository_wrap_odb(git_repository **repo_out, git_odb *odb) { git_repository *repo; @@ -768,7 +923,7 @@ int git_repository_discover( git_buf_sanitize(out); - return find_repo(out, NULL, NULL, start_path, flags, ceiling_dirs); + return find_repo(out, NULL, NULL, NULL, start_path, flags, ceiling_dirs); } static int load_config( @@ -788,14 +943,10 @@ static int load_config( if ((error = git_config_new(&cfg)) < 0) return error; - error = git_buf_joinpath( - &config_path, repo->path_repository, GIT_CONFIG_FILENAME_INREPO); - if (error < 0) - goto on_error; + if ((error = git_repository_item_path(&config_path, repo, GIT_REPOSITORY_ITEM_CONFIG)) == 0) + error = git_config_add_file_ondisk(cfg, config_path.ptr, GIT_CONFIG_LEVEL_LOCAL, 0); - if ((error = git_config_add_file_ondisk( - cfg, config_path.ptr, GIT_CONFIG_LEVEL_LOCAL, 0)) < 0 && - error != GIT_ENOTFOUND) + if (error && error != GIT_ENOTFOUND) goto on_error; git_buf_free(&config_path); @@ -923,18 +1074,23 @@ int git_repository_odb__weakptr(git_odb **out, git_repository *repo) git_buf odb_path = GIT_BUF_INIT; git_odb *odb; - if ((error = git_buf_joinpath(&odb_path, repo->path_repository, GIT_OBJECTS_DIR)) < 0) + if ((error = git_repository_item_path(&odb_path, repo, + GIT_REPOSITORY_ITEM_OBJECTS)) < 0 || + (error = git_odb_new(&odb)) < 0) return error; - error = git_odb_open(&odb, odb_path.ptr); - if (!error) { - GIT_REFCOUNT_OWN(odb, repo); + GIT_REFCOUNT_OWN(odb, repo); - odb = git__compare_and_swap(&repo->_odb, NULL, odb); - if (odb != NULL) { - GIT_REFCOUNT_OWN(odb, NULL); - git_odb_free(odb); - } + if ((error = git_odb__set_caps(odb, GIT_ODB_CAP_FROM_OWNER)) < 0 || + (error = git_odb__add_default_backends(odb, odb_path.ptr, 0, 0)) < 0) { + git_odb_free(odb); + return error; + } + + odb = git__compare_and_swap(&repo->_odb, NULL, odb); + if (odb != NULL) { + GIT_REFCOUNT_OWN(odb, NULL); + git_odb_free(odb); } git_buf_free(&odb_path); @@ -1009,7 +1165,7 @@ int git_repository_index__weakptr(git_index **out, git_repository *repo) git_buf index_path = GIT_BUF_INIT; git_index *index; - if ((error = git_buf_joinpath(&index_path, repo->path_repository, GIT_INDEX_FILE)) < 0) + if ((error = git_buf_joinpath(&index_path, repo->gitdir, GIT_INDEX_FILE)) < 0) return error; error = git_index_open(&index, index_path.ptr); @@ -1125,13 +1281,13 @@ bool git_repository__reserved_names( prefixcmp = (error || ignorecase) ? git__prefixcmp_icase : git__prefixcmp; - if (repo->path_gitlink && - reserved_names_add8dot3(repo, repo->path_gitlink) < 0) + if (repo->gitlink && + reserved_names_add8dot3(repo, repo->gitlink) < 0) goto on_error; - if (repo->path_repository && - prefixcmp(repo->path_repository, repo->workdir) == 0 && - reserved_names_add8dot3(repo, repo->path_repository) < 0) + if (repo->gitdir && + prefixcmp(repo->gitdir, repo->workdir) == 0 && + reserved_names_add8dot3(repo, repo->gitdir) < 0) goto on_error; } } @@ -1180,7 +1336,7 @@ static int check_repositoryformatversion(git_config *config) if (GIT_REPO_VERSION < version) { giterr_set(GITERR_REPOSITORY, - "Unsupported repository version %d. Only versions up to %d are supported.", + "unsupported repository version %d. Only versions up to %d are supported.", version, GIT_REPO_VERSION); return -1; } @@ -1188,7 +1344,7 @@ static int check_repositoryformatversion(git_config *config) return 0; } -static int repo_init_create_head(const char *git_dir, const char *ref_name) +int git_repository_create_head(const char *git_dir, const char *ref_name) { git_buf ref_path = GIT_BUF_INIT; git_filebuf ref = GIT_FILEBUF_INIT; @@ -1274,12 +1430,12 @@ static int create_empty_file(const char *path, mode_t mode) int fd; if ((fd = p_creat(path, mode)) < 0) { - giterr_set(GITERR_OS, "Error while creating '%s'", path); + giterr_set(GITERR_OS, "error while creating '%s'", path); return -1; } if (p_close(fd) < 0) { - giterr_set(GITERR_OS, "Error while closing '%s'", path); + giterr_set(GITERR_OS, "error while closing '%s'", path); return -1; } @@ -1508,7 +1664,7 @@ static int repo_write_template( if (error) giterr_set(GITERR_OS, - "Failed to initialize repository with template '%s'", file); + "failed to initialize repository with template '%s'", file); return error; } @@ -1539,7 +1695,7 @@ static int repo_write_gitlink( if (!p_stat(buf.ptr, &st) && !S_ISREG(st.st_mode)) { giterr_set(GITERR_REPOSITORY, - "Cannot overwrite gitlink file into path '%s'", in_dir); + "cannot overwrite gitlink file into path '%s'", in_dir); error = GIT_EEXISTS; goto cleanup; } @@ -1593,7 +1749,7 @@ static int repo_init_structure( if ((opts->flags & GIT_REPOSITORY_INIT__HAS_DOTGIT) != 0) { if (git_win32__set_hidden(repo_dir, true) < 0) { giterr_set(GITERR_OS, - "Failed to mark Git repository folder as hidden"); + "failed to mark Git repository folder as hidden"); return -1; } } @@ -1747,7 +1903,7 @@ static int repo_init_directories( if (git_path_dirname_r(wd_path, repo_path->ptr) < 0) return -1; } else { - giterr_set(GITERR_REPOSITORY, "Cannot pick working directory" + giterr_set(GITERR_REPOSITORY, "cannot pick working directory" " for non-bare repository that isn't a '.git' directory"); return -1; } @@ -1851,7 +2007,8 @@ int git_repository_init_ext( git_repository_init_options *opts) { int error; - git_buf repo_path = GIT_BUF_INIT, wd_path = GIT_BUF_INIT; + git_buf repo_path = GIT_BUF_INIT, wd_path = GIT_BUF_INIT, + common_path = GIT_BUF_INIT; const char *wd; assert(out && given_repo && opts); @@ -1863,11 +2020,11 @@ int git_repository_init_ext( goto cleanup; wd = (opts->flags & GIT_REPOSITORY_INIT_BARE) ? NULL : git_buf_cstr(&wd_path); - if (valid_repository_path(&repo_path)) { + if (valid_repository_path(&repo_path, &common_path)) { if ((opts->flags & GIT_REPOSITORY_INIT_NO_REINIT) != 0) { giterr_set(GITERR_REPOSITORY, - "Attempt to reinitialize '%s'", given_repo); + "attempt to reinitialize '%s'", given_repo); error = GIT_EEXISTS; goto cleanup; } @@ -1884,7 +2041,7 @@ int git_repository_init_ext( repo_path.ptr, wd, opts)) && !(error = repo_init_config( repo_path.ptr, wd, opts->flags, opts->mode))) - error = repo_init_create_head( + error = git_repository_create_head( repo_path.ptr, opts->initial_head); } if (error < 0) @@ -1896,6 +2053,7 @@ int git_repository_init_ext( error = repo_init_create_origin(*out, opts->origin_url); cleanup: + git_buf_free(&common_path); git_buf_free(&repo_path); git_buf_free(&wd_path); @@ -1925,6 +2083,29 @@ int git_repository_head_detached(git_repository *repo) return exists; } +static int get_worktree_file_path(git_buf *out, git_repository *repo, const char *worktree, const char *file) +{ + git_buf_clear(out); + return git_buf_printf(out, "%s/worktrees/%s/%s", repo->commondir, worktree, file); +} + +int git_repository_head_detached_for_worktree(git_repository *repo, const char *name) +{ + git_reference *ref = NULL; + int error; + + assert(repo && name); + + if ((error = git_repository_head_for_worktree(&ref, repo, name)) < 0) + goto out; + + error = (git_reference_type(ref) != GIT_REF_SYMBOLIC); +out: + git_reference_free(ref); + + return error; +} + int git_repository_head(git_reference **head_out, git_repository *repo) { git_reference *head; @@ -1944,6 +2125,71 @@ int git_repository_head(git_reference **head_out, git_repository *repo) return error == GIT_ENOTFOUND ? GIT_EUNBORNBRANCH : error; } +int git_repository_head_for_worktree(git_reference **out, git_repository *repo, const char *name) +{ + git_buf path = GIT_BUF_INIT; + git_reference *head = NULL; + int error; + + assert(out && repo && name); + + *out = NULL; + + if ((error = get_worktree_file_path(&path, repo, name, GIT_HEAD_FILE)) < 0 || + (error = git_reference__read_head(&head, repo, path.ptr)) < 0) + goto out; + + if (git_reference_type(head) != GIT_REF_OID) { + git_reference *resolved; + + error = git_reference_lookup_resolved(&resolved, repo, git_reference_symbolic_target(head), -1); + git_reference_free(head); + head = resolved; + } + + *out = head; + +out: + if (error) + git_reference_free(head); + + git_buf_free(&path); + + return error; +} + +int git_repository_foreach_head(git_repository *repo, git_repository_foreach_head_cb cb, void *payload) +{ + git_strarray worktrees = GIT_VECTOR_INIT; + git_buf path = GIT_BUF_INIT; + int error; + size_t i; + + /* Execute callback for HEAD of commondir */ + if ((error = git_buf_joinpath(&path, repo->commondir, GIT_HEAD_FILE)) < 0 || + (error = cb(repo, path.ptr, payload) != 0)) + goto out; + + if ((error = git_worktree_list(&worktrees, repo)) < 0) { + error = 0; + goto out; + } + + /* Execute callback for all worktree HEADs */ + for (i = 0; i < worktrees.count; i++) { + if (get_worktree_file_path(&path, repo, worktrees.strings[i], GIT_HEAD_FILE) < 0) + continue; + + if ((error = cb(repo, path.ptr, payload)) != 0) + goto out; + } + +out: + git_buf_free(&path); + git_strarray_free(&worktrees); + return error; +} + int git_repository_head_unborn(git_repository *repo) { git_reference *ref = NULL; @@ -2002,10 +2248,50 @@ int git_repository_is_empty(git_repository *repo) return is_empty; } +int git_repository_item_path(git_buf *out, git_repository *repo, git_repository_item_t item) +{ + const char *parent; + + switch (items[item].parent) { + case GIT_REPOSITORY_ITEM_GITDIR: + parent = git_repository_path(repo); + break; + case GIT_REPOSITORY_ITEM_WORKDIR: + parent = git_repository_workdir(repo); + break; + case GIT_REPOSITORY_ITEM_COMMONDIR: + parent = git_repository_commondir(repo); + break; + default: + giterr_set(GITERR_INVALID, "invalid item directory"); + return -1; + } + + if (parent == NULL) { + giterr_set(GITERR_INVALID, "path cannot exist in repository"); + return GIT_ENOTFOUND; + } + + if (git_buf_sets(out, parent) < 0) + return -1; + + if (items[item].name) { + if (git_buf_joinpath(out, parent, items[item].name) < 0) + return -1; + } + + if (items[item].directory) { + if (git_path_to_dir(out) < 0) + return -1; + } + + return 0; +} + const char *git_repository_path(git_repository *repo) { assert(repo); - return repo->path_repository; + return repo->gitdir; } const char *git_repository_workdir(git_repository *repo) @@ -2018,6 +2304,12 @@ const char *git_repository_workdir(git_repository *repo) return repo->workdir; } +const char *git_repository_commondir(git_repository *repo) +{ + assert(repo); + return repo->commondir; +} + int git_repository_set_workdir( git_repository *repo, const char *workdir, int update_gitlink) { @@ -2068,6 +2360,12 @@ int git_repository_is_bare(git_repository *repo) return repo->is_bare; } +int git_repository_is_worktree(git_repository *repo) +{ + assert(repo); + return repo->is_worktree; +} + int git_repository_set_bare(git_repository *repo) { int error; @@ -2122,7 +2420,7 @@ int git_repository__set_orig_head(git_repository *repo, const git_oid *orig_head git_oid_fmt(orig_head_str, orig_head); - if ((error = git_buf_joinpath(&file_path, repo->path_repository, GIT_ORIG_HEAD_FILE)) == 0 && + if ((error = git_buf_joinpath(&file_path, repo->gitdir, GIT_ORIG_HEAD_FILE)) == 0 && (error = git_filebuf_open(&file, file_path.ptr, GIT_FILEBUF_FORCE, GIT_MERGE_FILE_MODE)) == 0 && (error = git_filebuf_printf(&file, "%.*s\n", GIT_OID_HEXSZ, orig_head_str)) == 0) error = git_filebuf_commit(&file); @@ -2143,13 +2441,13 @@ int git_repository_message(git_buf *out, git_repository *repo) git_buf_sanitize(out); - if (git_buf_joinpath(&path, repo->path_repository, GIT_MERGE_MSG_FILE) < 0) + if (git_buf_joinpath(&path, repo->gitdir, GIT_MERGE_MSG_FILE) < 0) return -1; if ((error = p_stat(git_buf_cstr(&path), &st)) < 0) { if (errno == ENOENT) error = GIT_ENOTFOUND; - giterr_set(GITERR_OS, "Could not access message file"); + giterr_set(GITERR_OS, "could not access message file"); } else { error = git_futils_readbuffer(out, git_buf_cstr(&path)); } @@ -2164,7 +2462,7 @@ int git_repository_message_remove(git_repository *repo) git_buf path = GIT_BUF_INIT; int error; - if (git_buf_joinpath(&path, repo->path_repository, GIT_MERGE_MSG_FILE) < 0) + if (git_buf_joinpath(&path, repo->gitdir, GIT_MERGE_MSG_FILE) < 0) return -1; error = p_unlink(git_buf_cstr(&path)); @@ -2227,7 +2525,7 @@ int git_repository_hashfile( } if (!git__is_sizet(len)) { - giterr_set(GITERR_OS, "File size overflow for 32-bit systems"); + giterr_set(GITERR_OS, "file size overflow for 32-bit systems"); error = -1; goto cleanup; } @@ -2254,7 +2552,9 @@ static int checkout_message(git_buf *out, git_reference *old, const char *new) git_buf_puts(out, " to "); - if (git_reference__is_branch(new)) + if (git_reference__is_branch(new) || + git_reference__is_tag(new) || + git_reference__is_remote(new)) git_buf_puts(out, git_reference__shorthand(new)); else git_buf_puts(out, new); @@ -2265,6 +2565,41 @@ static int checkout_message(git_buf *out, git_reference *old, const char *new) return 0; } +static int detach(git_repository *repo, const git_oid *id, const char *new) +{ + int error; + git_buf log_message = GIT_BUF_INIT; + git_object *object = NULL, *peeled = NULL; + git_reference *new_head = NULL, *current = NULL; + + assert(repo && id); + + if ((error = git_reference_lookup(¤t, repo, GIT_HEAD_FILE)) < 0) + return error; + + if ((error = git_object_lookup(&object, repo, id, GIT_OBJ_ANY)) < 0) + goto cleanup; + + if ((error = git_object_peel(&peeled, object, GIT_OBJ_COMMIT)) < 0) + goto cleanup; + + if (new == NULL) + new = git_oid_tostr_s(git_object_id(peeled)); + + if ((error = checkout_message(&log_message, current, new)) < 0) + goto cleanup; + + error = git_reference_create(&new_head, repo, GIT_HEAD_FILE, git_object_id(peeled), true, git_buf_cstr(&log_message)); + +cleanup: + git_buf_free(&log_message); + git_object_free(object); + git_object_free(peeled); + git_reference_free(current); + git_reference_free(new_head); + return error; +} + int git_repository_set_head( git_repository* repo, const char* refname) @@ -2285,12 +2620,21 @@ int git_repository_set_head( if (error < 0 && error != GIT_ENOTFOUND) goto cleanup; + if (ref && current->type == GIT_REF_SYMBOLIC && git__strcmp(current->target.symbolic, ref->name) && + git_reference_is_branch(ref) && git_branch_is_checked_out(ref)) { + giterr_set(GITERR_REPOSITORY, "cannot set HEAD to reference '%s' as it is the current HEAD " + "of a linked repository.", git_reference_name(ref)); + error = -1; + goto cleanup; + } + if (!error) { if (git_reference_is_branch(ref)) { error = git_reference_symbolic_create(&new_head, repo, GIT_HEAD_FILE, git_reference_name(ref), true, git_buf_cstr(&log_message)); } else { - error = git_repository_set_head_detached(repo, git_reference_target(ref)); + error = detach(repo, git_reference_target(ref), + git_reference_is_tag(ref) || git_reference_is_remote(ref) ? refname : NULL); } } else if (git_reference__is_branch(refname)) { error = git_reference_symbolic_create(&new_head, repo, GIT_HEAD_FILE, refname, @@ -2305,41 +2649,6 @@ cleanup: return error; } -static int detach(git_repository *repo, const git_oid *id, const char *from) -{ - int error; - git_buf log_message = GIT_BUF_INIT; - git_object *object = NULL, *peeled = NULL; - git_reference *new_head = NULL, *current = NULL; - - assert(repo && id); - - if ((error = git_reference_lookup(¤t, repo, GIT_HEAD_FILE)) < 0) - return error; - - if ((error = git_object_lookup(&object, repo, id, GIT_OBJ_ANY)) < 0) - goto cleanup; - - if ((error = git_object_peel(&peeled, object, GIT_OBJ_COMMIT)) < 0) - goto cleanup; - - if (from == NULL) - from = git_oid_tostr_s(git_object_id(peeled)); - - if ((error = checkout_message(&log_message, current, from)) < 0) - goto cleanup; - - error = git_reference_create(&new_head, repo, GIT_HEAD_FILE, git_object_id(peeled), true, git_buf_cstr(&log_message)); - -cleanup: - git_buf_free(&log_message); - git_object_free(object); - git_object_free(peeled); - git_reference_free(current); - git_reference_free(new_head); - return error; -} - int git_repository_set_head_detached( git_repository* repo, const git_oid* commitish) @@ -2400,7 +2709,7 @@ int git_repository_state(git_repository *repo) assert(repo); - if (git_buf_puts(&repo_path, repo->path_repository) < 0) + if (git_buf_puts(&repo_path, repo->gitdir) < 0) return -1; if (git_path_contains_file(&repo_path, GIT_REBASE_MERGE_INTERACTIVE_FILE)) @@ -2442,7 +2751,7 @@ int git_repository__cleanup_files( for (error = 0, i = 0; !error && i < files_len; ++i) { const char *path; - if (git_buf_joinpath(&buf, repo->path_repository, files[i]) < 0) + if (git_buf_joinpath(&buf, repo->gitdir, files[i]) < 0) return -1; path = git_buf_cstr(&buf); @@ -2486,7 +2795,7 @@ int git_repository_is_shallow(git_repository *repo) struct stat st; int error; - if ((error = git_buf_joinpath(&path, repo->path_repository, "shallow")) < 0) + if ((error = git_buf_joinpath(&path, repo->gitdir, "shallow")) < 0) return error; error = git_path_lstat(path.ptr, &st); @@ -2541,3 +2850,31 @@ int git_repository_set_ident(git_repository *repo, const char *name, const char return 0; } + +int git_repository_submodule_cache_all(git_repository *repo) +{ + int error; + + assert(repo); + + if ((error = git_strmap_alloc(&repo->submodule_cache))) + return error; + + error = git_submodule__map(repo, repo->submodule_cache); + return error; +} + +int git_repository_submodule_cache_clear(git_repository *repo) +{ + git_submodule *sm; + assert(repo); + if (repo->submodule_cache == NULL) { + return 0; + } + git_strmap_foreach_value(repo->submodule_cache, sm, { + git_submodule_free(sm); + }); + git_strmap_free(repo->submodule_cache); + repo->submodule_cache = 0; + return 0; +} diff --git a/src/repository.h b/src/repository.h index fd679b483..52f9ec260 100644 --- a/src/repository.h +++ b/src/repository.h @@ -31,6 +31,8 @@ /* Default DOS-compatible 8.3 "short name" for a git repository, "GIT~1" */ #define GIT_DIR_SHORTNAME "GIT~1" +extern bool git_repository__fsync_gitdir; + /** Cvar cache identifiers */ typedef enum { GIT_CVAR_AUTO_CRLF = 0, /* core.autocrlf */ @@ -46,6 +48,7 @@ typedef enum { GIT_CVAR_LOGALLREFUPDATES, /* core.logallrefupdates */ GIT_CVAR_PROTECTHFS, /* core.protectHFS */ GIT_CVAR_PROTECTNTFS, /* core.protectNTFS */ + GIT_CVAR_FSYNCOBJECTFILES, /* core.fsyncObjectFiles */ GIT_CVAR_CACHE_MAX } git_cvar_cached; @@ -106,6 +109,8 @@ typedef enum { GIT_PROTECTHFS_DEFAULT = GIT_CVAR_FALSE, /* core.protectNTFS */ GIT_PROTECTNTFS_DEFAULT = GIT_CVAR_FALSE, + /* core.fsyncObjectFiles */ + GIT_FSYNCOBJECTFILES_DEFAULT = GIT_CVAR_FALSE, } git_cvar_value; /* internal repository init flags */ @@ -126,8 +131,9 @@ struct git_repository { git_attr_cache *attrcache; git_diff_driver_registry *diff_drivers; - char *path_repository; - char *path_gitlink; + char *gitlink; + char *gitdir; + char *commondir; char *workdir; char *namespace; @@ -137,12 +143,14 @@ struct git_repository { git_array_t(git_buf) reserved_names; unsigned is_bare:1; + unsigned is_worktree:1; unsigned int lru_counter; git_atomic attr_session_key; git_cvar_value cvar_cache[GIT_CVAR_CACHE_MAX]; + git_strmap *submodule_cache; }; GIT_INLINE(git_attr_cache *) git_repository_attr_cache(git_repository *repo) @@ -151,6 +159,27 @@ GIT_INLINE(git_attr_cache *) git_repository_attr_cache(git_repository *repo) } int git_repository_head_tree(git_tree **tree, git_repository *repo); +int git_repository_create_head(const char *git_dir, const char *ref_name); + +/* + * Called for each HEAD. + * + * Can return either 0, causing the iteration over HEADs to + * continue, or a non-0 value causing the iteration to abort. The + * return value is passed back to the caller of + * `git_repository_foreach_head` + */ +typedef int (*git_repository_foreach_head_cb)(git_repository *repo, const char *path, void *payload); + +/* + * Iterate over repository and all worktree HEADs. + * + * This function will be called for the repository HEAD and for + * all HEADS of linked worktrees. For each HEAD, the callback is + * executed with the given payload. The return value equals the + * return value of the last executed callback function. + */ +int git_repository_foreach_head(git_repository *repo, git_repository_foreach_head_cb cb, void *payload); /* * Weak pointers to repository internals. @@ -182,7 +211,7 @@ GIT_INLINE(int) git_repository__ensure_not_bare( giterr_set( GITERR_REPOSITORY, - "Cannot %s. This operation is not allowed against bare repositories.", + "cannot %s. This operation is not allowed against bare repositories.", operation_name); return GIT_EBAREREPO; diff --git a/src/reset.c b/src/reset.c index db0bfb373..066b5dbda 100644 --- a/src/reset.c +++ b/src/reset.c @@ -137,7 +137,7 @@ static int reset( (git_repository_state(repo) == GIT_REPOSITORY_STATE_MERGE || git_index_has_conflicts(index))) { - giterr_set(GITERR_OBJECT, "%s (soft) in the middle of a merge.", ERROR_MSG); + giterr_set(GITERR_OBJECT, "%s (soft) in the middle of a merge", ERROR_MSG); error = GIT_EUNMERGED; goto cleanup; } diff --git a/src/revert.c b/src/revert.c index c481e7dea..747938fb3 100644 --- a/src/revert.c +++ b/src/revert.c @@ -27,7 +27,7 @@ static int write_revert_head( git_buf file_path = GIT_BUF_INIT; int error = 0; - if ((error = git_buf_joinpath(&file_path, repo->path_repository, GIT_REVERT_HEAD_FILE)) >= 0 && + if ((error = git_buf_joinpath(&file_path, repo->gitdir, GIT_REVERT_HEAD_FILE)) >= 0 && (error = git_filebuf_open(&file, file_path.ptr, GIT_FILEBUF_FORCE, GIT_REVERT_FILE_MODE)) >= 0 && (error = git_filebuf_printf(&file, "%s\n", commit_oidstr)) >= 0) error = git_filebuf_commit(&file); @@ -49,7 +49,7 @@ static int write_merge_msg( git_buf file_path = GIT_BUF_INIT; int error = 0; - if ((error = git_buf_joinpath(&file_path, repo->path_repository, GIT_MERGE_MSG_FILE)) < 0 || + if ((error = git_buf_joinpath(&file_path, repo->gitdir, GIT_MERGE_MSG_FILE)) < 0 || (error = git_filebuf_open(&file, file_path.ptr, GIT_FILEBUF_FORCE, GIT_REVERT_FILE_MODE)) < 0 || (error = git_filebuf_printf(&file, "Revert \"%s\"\n\nThis reverts commit %s.\n", commit_msgline, commit_oidstr)) < 0) @@ -133,13 +133,13 @@ int git_revert_commit( if (git_commit_parentcount(revert_commit) > 1) { if (!mainline) return revert_seterr(revert_commit, - "Mainline branch is not specified but %s is a merge commit"); + "mainline branch is not specified but %s is a merge commit"); parent = mainline; } else { if (mainline) return revert_seterr(revert_commit, - "Mainline branch specified but %s is not a merge commit"); + "mainline branch specified but %s is not a merge commit"); parent = git_commit_parentcount(revert_commit); } diff --git a/src/revparse.c b/src/revparse.c index aa7e0bd98..fd6bd1ea6 100644 --- a/src/revparse.c +++ b/src/revparse.c @@ -46,7 +46,7 @@ static int build_regex(regex_t *regex, const char *pattern) int error; if (*pattern == '\0') { - giterr_set(GITERR_REGEX, "Empty pattern"); + giterr_set(GITERR_REGEX, "empty pattern"); return GIT_EINVALIDSPEC; } @@ -118,7 +118,7 @@ static int revparse_lookup_object( if ((error = maybe_describe(object_out, repo, spec)) != GIT_ENOTFOUND) return error; - giterr_set(GITERR_REFERENCE, "Revspec '%s' not found.", spec); + giterr_set(GITERR_REFERENCE, "revspec '%s' not found", spec); return GIT_ENOTFOUND; } @@ -245,7 +245,7 @@ static int retrieve_oid_from_reflog(git_oid *oid, git_reference *ref, size_t ide notfound: giterr_set( GITERR_REFERENCE, - "Reflog for '%s' has only %"PRIuZ" entries, asked for %"PRIuZ, + "reflog for '%s' has only %"PRIuZ" entries, asked for %"PRIuZ, git_reference_name(ref), numentries, identifier); git_reflog_free(reflog); @@ -757,7 +757,7 @@ int revparse__ext( * TODO: support merge-stage path lookup (":2:Makefile") * and plain index blob lookup (:i-am/a/blob) */ - giterr_set(GITERR_INVALID, "Unimplemented"); + giterr_set(GITERR_INVALID, "unimplemented"); error = GIT_ERROR; goto cleanup; } @@ -816,7 +816,7 @@ cleanup: if (error) { if (error == GIT_EINVALIDSPEC) giterr_set(GITERR_INVALID, - "Failed to parse revision specifier - Invalid pattern '%s'", spec); + "failed to parse revision specifier - Invalid pattern '%s'", spec); git_object_free(base_rev); git_reference_free(reference); @@ -892,6 +892,17 @@ int git_revparse( const char *rstr; revspec->flags = GIT_REVPARSE_RANGE; + /* + * Following git.git, don't allow '..' because it makes command line + * arguments which can be either paths or revisions ambiguous when the + * path is almost certainly intended. The empty range '...' is still + * allowed. + */ + if (!git__strcmp(spec, "..")) { + giterr_set(GITERR_INVALID, "Invalid pattern '..'"); + return GIT_EINVALIDSPEC; + } + lstr = git__substrdup(spec, dotdot - spec); rstr = dotdot + 2; if (dotdot[2] == '.') { @@ -899,9 +910,17 @@ int git_revparse( rstr++; } - error = git_revparse_single(&revspec->from, repo, lstr); - if (!error) - error = git_revparse_single(&revspec->to, repo, rstr); + error = git_revparse_single( + &revspec->from, + repo, + *lstr == '\0' ? "HEAD" : lstr); + + if (!error) { + error = git_revparse_single( + &revspec->to, + repo, + *rstr == '\0' ? "HEAD" : rstr); + } git__free((void*)lstr); } else { diff --git a/src/revwalk.c b/src/revwalk.c index f5502a72e..77fa9fd0c 100644 --- a/src/revwalk.c +++ b/src/revwalk.c @@ -15,8 +15,6 @@ #include "merge.h" #include "vector.h" -GIT__USE_OIDMAP - git_commit_list_node *git_revwalk__commit_lookup( git_revwalk *walk, const git_oid *oid) { @@ -25,9 +23,9 @@ git_commit_list_node *git_revwalk__commit_lookup( int ret; /* lookup and reserve space if not already present */ - pos = kh_get(oid, walk->commits, oid); - if (pos != kh_end(walk->commits)) - return kh_value(walk->commits, pos); + pos = git_oidmap_lookup_index(walk->commits, oid); + if (git_oidmap_valid_index(walk->commits, pos)) + return git_oidmap_value_at(walk->commits, pos); commit = git_commit_list_alloc_node(walk); if (commit == NULL) @@ -35,9 +33,9 @@ git_commit_list_node *git_revwalk__commit_lookup( git_oid_cpy(&commit->oid, oid); - pos = kh_put(oid, walk->commits, &commit->oid, &ret); + pos = git_oidmap_put(walk->commits, &commit->oid, &ret); assert(ret != 0); - kh_value(walk->commits, pos) = commit; + git_oidmap_set_value_at(walk->commits, pos, commit); return commit; } @@ -61,7 +59,7 @@ static int push_commit(git_revwalk *walk, const git_oid *oid, int uninteresting, if (from_glob) return 0; - giterr_set(GITERR_INVALID, "Object is not a committish"); + giterr_set(GITERR_INVALID, "object is not a committish"); return -1; } if (error < 0) @@ -198,7 +196,7 @@ int git_revwalk_push_range(git_revwalk *walk, const char *range) if (revspec.flags & GIT_REVPARSE_MERGE_BASE) { /* TODO: support "..." */ - giterr_set(GITERR_INVALID, "Symmetric differences not implemented in revwalk"); + giterr_set(GITERR_INVALID, "symmetric differences not implemented in revwalk"); return GIT_EINVALIDSPEC; } @@ -233,9 +231,12 @@ static int revwalk_next_timesort(git_commit_list_node **object_out, git_revwalk { git_commit_list_node *next; - if ((next = git_pqueue_pop(&walk->iterator_time)) != NULL) { - *object_out = next; - return 0; + while ((next = git_pqueue_pop(&walk->iterator_time)) != NULL) { + /* Some commits might become uninteresting after being added to the list */ + if (!next->uninteresting) { + *object_out = next; + return 0; + } } giterr_clear(); @@ -702,7 +703,7 @@ void git_revwalk_reset(git_revwalk *walk) assert(walk); - kh_foreach_value(walk->commits, commit, { + git_oidmap_foreach_value(walk->commits, commit, { commit->seen = 0; commit->in_degree = 0; commit->topo_delay = 0; @@ -733,7 +734,7 @@ int git_revwalk_add_hide_cb( if (walk->hide_cb) { /* There is already a callback added */ - giterr_set(GITERR_INVALID, "There is already a callback added to hide commits in revision walker."); + giterr_set(GITERR_INVALID, "there is already a callback added to hide commits in revwalk"); return -1; } diff --git a/src/settings.c b/src/settings.c index 4a6e0f353..52b861ba0 100644 --- a/src/settings.c +++ b/src/settings.c @@ -15,6 +15,9 @@ #include "cache.h" #include "global.h" #include "object.h" +#include "odb.h" +#include "refs.h" +#include "transports/smart.h" void git_libgit2_version(int *major, int *minor, int *rev) { @@ -29,7 +32,7 @@ int git_libgit2_features(void) #ifdef GIT_THREADS | GIT_FEATURE_THREADS #endif -#if defined(GIT_OPENSSL) || defined(GIT_WINHTTP) || defined(GIT_SECURE_TRANSPORT) +#ifdef GIT_HTTPS | GIT_FEATURE_HTTPS #endif #if defined(GIT_SSH) @@ -64,7 +67,7 @@ static int config_level_to_sysdir(int config_level) break; default: giterr_set( - GITERR_INVALID, "Invalid config path selector %d", config_level); + GITERR_INVALID, "invalid config path selector %d", config_level); } return val; @@ -193,6 +196,10 @@ int git_libgit2_opts(int key, ...) git_object__strict_input_validation = (va_arg(ap, int) != 0); break; + case GIT_OPT_ENABLE_STRICT_SYMBOLIC_REF_CREATION: + git_reference__enable_symbolic_ref_target_validation = (va_arg(ap, int) != 0); + break; + case GIT_OPT_SET_SSL_CIPHERS: #ifdef GIT_OPENSSL { @@ -217,6 +224,30 @@ int git_libgit2_opts(int key, ...) } break; + case GIT_OPT_ENABLE_OFS_DELTA: + git_smart__ofs_delta_enabled = (va_arg(ap, int) != 0); + break; + + case GIT_OPT_ENABLE_FSYNC_GITDIR: + git_repository__fsync_gitdir = (va_arg(ap, int) != 0); + break; + + case GIT_OPT_GET_WINDOWS_SHAREMODE: +#ifdef GIT_WIN32 + *(va_arg(ap, unsigned long *)) = git_win32__createfile_sharemode; +#endif + break; + + case GIT_OPT_SET_WINDOWS_SHAREMODE: +#ifdef GIT_WIN32 + git_win32__createfile_sharemode = va_arg(ap, unsigned long); +#endif + break; + + case GIT_OPT_ENABLE_STRICT_HASH_VERIFICATION: + git_odb__strict_hash_verification = (va_arg(ap, int) != 0); + break; + default: giterr_set(GITERR_INVALID, "invalid option key"); error = -1; diff --git a/src/sha1_lookup.c b/src/sha1_lookup.c index c6b561340..ead26de06 100644 --- a/src/sha1_lookup.c +++ b/src/sha1_lookup.c @@ -206,7 +206,7 @@ int sha1_entry_pos(const void *table, #endif if (!(lo <= mi && mi < hi)) { - giterr_set(GITERR_INVALID, "Assertion failure. Binary search invariant is false"); + giterr_set(GITERR_INVALID, "assertion failure: binary search invariant is false"); return -1; } diff --git a/src/signature.c b/src/signature.c index 22cba7ef3..a56b8a299 100644 --- a/src/signature.c +++ b/src/signature.c @@ -25,7 +25,7 @@ void git_signature_free(git_signature *sig) static int signature_error(const char *msg) { - giterr_set(GITERR_INVALID, "Failed to parse signature - %s", msg); + giterr_set(GITERR_INVALID, "failed to parse signature - %s", msg); return -1; } @@ -228,8 +228,11 @@ int git_signature__parse(git_signature *sig, const char **buffer_out, const char *time_start = email_end + 2; const char *time_end; - if (git__strtol64(&sig->when.time, time_start, &time_end, 10) < 0) + if (git__strtol64(&sig->when.time, time_start, &time_end, 10) < 0) { + git__free(sig->name); + git__free(sig->email); return signature_error("invalid Unix timestamp"); + } /* do we have a timezone? */ if (time_end + 1 < buffer_end) { diff --git a/src/socket_stream.c b/src/socket_stream.c index 71f49118e..c0a168448 100644 --- a/src/socket_stream.c +++ b/src/socket_stream.c @@ -57,7 +57,7 @@ static int close_socket(GIT_SOCKET s) return -1; if (0 != WSACleanup()) { - giterr_set(GITERR_OS, "Winsock cleanup failed"); + giterr_set(GITERR_OS, "winsock cleanup failed"); return -1; } @@ -82,13 +82,13 @@ int socket_connect(git_stream *stream) WSADATA wsd; if (WSAStartup(MAKEWORD(2,2), &wsd) != 0) { - giterr_set(GITERR_OS, "Winsock init failed"); + giterr_set(GITERR_OS, "winsock init failed"); return -1; } if (LOBYTE(wsd.wVersion) != 2 || HIBYTE(wsd.wVersion) != 2) { WSACleanup(); - giterr_set(GITERR_OS, "Winsock init failed"); + giterr_set(GITERR_OS, "winsock init failed"); return -1; } #endif @@ -99,17 +99,15 @@ int socket_connect(git_stream *stream) if ((ret = p_getaddrinfo(st->host, st->port, &hints, &info)) != 0) { giterr_set(GITERR_NET, - "Failed to resolve address for %s: %s", st->host, p_gai_strerror(ret)); + "failed to resolve address for %s: %s", st->host, p_gai_strerror(ret)); return -1; } for (p = info; p != NULL; p = p->ai_next) { s = socket(p->ai_family, p->ai_socktype, p->ai_protocol); - if (s == INVALID_SOCKET) { - net_set_error("error creating socket"); - break; - } + if (s == INVALID_SOCKET) + continue; if (connect(s, p->ai_addr, (socklen_t)p->ai_addrlen) == 0) break; @@ -121,7 +119,7 @@ int socket_connect(git_stream *stream) /* Oops, we couldn't connect to any address */ if (s == INVALID_SOCKET && p == NULL) { - giterr_set(GITERR_OS, "Failed to connect to %s", st->host); + giterr_set(GITERR_OS, "failed to connect to %s", st->host); p_freeaddrinfo(info); return -1; } diff --git a/src/sortedcache.c b/src/sortedcache.c index 5bd989a9f..cc322d478 100644 --- a/src/sortedcache.c +++ b/src/sortedcache.c @@ -1,7 +1,5 @@ #include "sortedcache.h" -GIT__USE_STRMAP - int git_sortedcache_new( git_sortedcache **out, size_t item_path_offset, @@ -27,7 +25,7 @@ int git_sortedcache_new( goto fail; if (git_rwlock_init(&sc->lock)) { - giterr_set(GITERR_OS, "Failed to initialize lock"); + giterr_set(GITERR_OS, "failed to initialize lock"); goto fail; } @@ -162,7 +160,7 @@ int git_sortedcache_wlock(git_sortedcache *sc) GIT_UNUSED(sc); /* prevent warning when compiled w/o threads */ if (git_rwlock_wrlock(&sc->lock) < 0) { - giterr_set(GITERR_OS, "Unable to acquire write lock on cache"); + giterr_set(GITERR_OS, "unable to acquire write lock on cache"); return -1; } return 0; @@ -181,7 +179,7 @@ int git_sortedcache_rlock(git_sortedcache *sc) GIT_UNUSED(sc); /* prevent warning when compiled w/o threads */ if (git_rwlock_rdlock(&sc->lock) < 0) { - giterr_set(GITERR_OS, "Unable to acquire read lock on cache"); + giterr_set(GITERR_OS, "unable to acquire read lock on cache"); return -1; } return 0; @@ -221,7 +219,7 @@ int git_sortedcache_lockandload(git_sortedcache *sc, git_buf *buf) } if (!git__is_sizet(st.st_size)) { - giterr_set(GITERR_INVALID, "Unable to load file larger than size_t"); + giterr_set(GITERR_INVALID, "unable to load file larger than size_t"); error = -1; (void)p_close(fd); goto unlock; @@ -294,13 +292,13 @@ int git_sortedcache_upsert(void **out, git_sortedcache *sc, const char *key) item_key = ((char *)item) + sc->item_path_offset; memcpy(item_key, key, keylen); - pos = kh_put(str, sc->map, item_key, &error); + pos = git_strmap_put(sc->map, item_key, &error); if (error < 0) goto done; if (!error) - kh_key(sc->map, pos) = item_key; - kh_val(sc->map, pos) = item; + git_strmap_set_key_at(sc->map, pos, item_key); + git_strmap_set_value_at(sc->map, pos, item); error = git_vector_insert(&sc->items, item); if (error < 0) @@ -373,7 +371,7 @@ int git_sortedcache_remove(git_sortedcache *sc, size_t pos) */ if ((item = git_vector_get(&sc->items, pos)) == NULL) { - giterr_set(GITERR_INVALID, "Removing item out of range"); + giterr_set(GITERR_INVALID, "removing item out of range"); return GIT_ENOTFOUND; } diff --git a/src/stash.c b/src/stash.c index f5f4f36bf..d13220cdd 100644 --- a/src/stash.c +++ b/src/stash.c @@ -27,7 +27,7 @@ static int create_error(int error, const char *msg) { - giterr_set(GITERR_STASH, "Cannot stash changes - %s", msg); + giterr_set(GITERR_STASH, "cannot stash changes - %s", msg); return error; } @@ -36,7 +36,7 @@ static int retrieve_head(git_reference **out, git_repository *repo) int error = git_repository_head(out, repo); if (error == GIT_EUNBORNBRANCH) - return create_error(error, "You do not have the initial commit yet."); + return create_error(error, "you do not have the initial commit yet."); return error; } @@ -198,7 +198,7 @@ static int stash_update_index_from_diff( /* Unimplemented */ giterr_set( GITERR_INVALID, - "Cannot update index. Unimplemented status (%d)", + "cannot update index. Unimplemented status (%d)", delta->status); return -1; } @@ -479,7 +479,7 @@ static int ensure_there_are_changes_to_stash( return 0; if (!error) - return create_error(GIT_ENOTFOUND, "There is nothing to stash."); + return create_error(GIT_ENOTFOUND, "there is nothing to stash."); return error; } @@ -593,7 +593,7 @@ static int retrieve_stash_commit( max = git_reflog_entrycount(reflog); if (!max || index > max - 1) { error = GIT_ENOTFOUND; - giterr_set(GITERR_STASH, "No stashed state at position %" PRIuZ, index); + giterr_set(GITERR_STASH, "no stashed state at position %" PRIuZ, index); goto cleanup; } @@ -1036,7 +1036,7 @@ int git_stash_drop( if (!max || index > max - 1) { error = GIT_ENOTFOUND; - giterr_set(GITERR_STASH, "No stashed state at position %" PRIuZ, index); + giterr_set(GITERR_STASH, "no stashed state at position %" PRIuZ, index); goto cleanup; } diff --git a/src/status.c b/src/status.c index e610f5fe1..6752b5625 100644 --- a/src/status.c +++ b/src/status.c @@ -243,13 +243,13 @@ static int status_validate_options(const git_status_options *opts) GITERR_CHECK_VERSION(opts, GIT_STATUS_OPTIONS_VERSION, "git_status_options"); if (opts->show > GIT_STATUS_SHOW_WORKDIR_ONLY) { - giterr_set(GITERR_INVALID, "Unknown status 'show' option"); + giterr_set(GITERR_INVALID, "unknown status 'show' option"); return -1; } if ((opts->flags & GIT_STATUS_OPT_NO_REFRESH) != 0 && (opts->flags & GIT_STATUS_OPT_UPDATE_INDEX) != 0) { - giterr_set(GITERR_INVALID, "Updating index from status " + giterr_set(GITERR_INVALID, "updating index from status " "is not allowed when index refresh is disabled"); return -1; } @@ -510,13 +510,13 @@ int git_status_file( if (error < 0 && sfi.ambiguous) { giterr_set(GITERR_INVALID, - "Ambiguous path '%s' given to git_status_file", sfi.expected); + "ambiguous path '%s' given to git_status_file", sfi.expected); error = GIT_EAMBIGUOUS; } if (!error && !sfi.count) { giterr_set(GITERR_INVALID, - "Attempt to get status of nonexistent file '%s'", path); + "attempt to get status of nonexistent file '%s'", path); error = GIT_ENOTFOUND; } diff --git a/src/strmap.c b/src/strmap.c index b26a13d1f..de6826d03 100644 --- a/src/strmap.c +++ b/src/strmap.c @@ -7,6 +7,101 @@ #include "strmap.h" +__KHASH_IMPL(str, static kh_inline, const char *, void *, 1, kh_str_hash_func, kh_str_hash_equal) + +int git_strmap_alloc(git_strmap **map) +{ + if ((*map = kh_init(str)) == NULL) { + giterr_set_oom(); + return -1; + } + + return 0; +} + +void git_strmap_free(git_strmap *map) +{ + kh_destroy(str, map); +} + +void git_strmap_clear(git_strmap *map) +{ + kh_clear(str, map); +} + +size_t git_strmap_num_entries(git_strmap *map) +{ + return kh_size(map); +} + +size_t git_strmap_lookup_index(git_strmap *map, const char *key) +{ + return kh_get(str, map, key); +} + +int git_strmap_valid_index(git_strmap *map, size_t idx) +{ + return idx != kh_end(map); +} + +int git_strmap_exists(git_strmap *map, const char *key) +{ + return kh_get(str, map, key) != kh_end(map); +} + +int git_strmap_has_data(git_strmap *map, size_t idx) +{ + return kh_exist(map, idx); +} + +const char *git_strmap_key(git_strmap *map, size_t idx) +{ + return kh_key(map, idx); +} + +void git_strmap_set_key_at(git_strmap *map, size_t idx, char *key) +{ + kh_val(map, idx) = key; +} + +void *git_strmap_value_at(git_strmap *map, size_t idx) +{ + return kh_val(map, idx); +} + +void git_strmap_set_value_at(git_strmap *map, size_t idx, void *value) +{ + kh_val(map, idx) = value; +} + +void git_strmap_delete_at(git_strmap *map, size_t idx) +{ + kh_del(str, map, idx); +} + +int git_strmap_put(git_strmap *map, const char *key, int *err) +{ + return kh_put(str, map, key, err); +} + +void git_strmap_insert(git_strmap *map, const char *key, void *value, int *rval) +{ + khiter_t idx = kh_put(str, map, key, rval); + + if ((*rval) >= 0) { + if ((*rval) == 0) + kh_key(map, idx) = key; + kh_val(map, idx) = value; + } +} + +void git_strmap_delete(git_strmap *map, const char *key) +{ + khiter_t idx = git_strmap_lookup_index(map, key); + if (git_strmap_valid_index(map, idx)) + git_strmap_delete_at(map, idx); +} + int git_strmap_next( void **data, git_strmap_iter* iter, diff --git a/src/strmap.h b/src/strmap.h index 520984744..802b92494 100644 --- a/src/strmap.h +++ b/src/strmap.h @@ -20,49 +20,27 @@ __KHASH_TYPE(str, const char *, void *) typedef khash_t(str) git_strmap; typedef khiter_t git_strmap_iter; -#define GIT__USE_STRMAP \ - __KHASH_IMPL(str, static kh_inline, const char *, void *, 1, kh_str_hash_func, kh_str_hash_equal) +int git_strmap_alloc(git_strmap **map); +void git_strmap_free(git_strmap *map); +void git_strmap_clear(git_strmap *map); -#define git_strmap_alloc(hp) \ - ((*(hp) = kh_init(str)) == NULL) ? giterr_set_oom(), -1 : 0 +size_t git_strmap_num_entries(git_strmap *map); -#define git_strmap_free(h) kh_destroy(str, h), h = NULL -#define git_strmap_clear(h) kh_clear(str, h) +size_t git_strmap_lookup_index(git_strmap *map, const char *key); +int git_strmap_valid_index(git_strmap *map, size_t idx); -#define git_strmap_num_entries(h) kh_size(h) +int git_strmap_exists(git_strmap *map, const char *key); +int git_strmap_has_data(git_strmap *map, size_t idx); -#define git_strmap_lookup_index(h, k) kh_get(str, h, k) -#define git_strmap_valid_index(h, idx) (idx != kh_end(h)) +const char *git_strmap_key(git_strmap *map, size_t idx); +void git_strmap_set_key_at(git_strmap *map, size_t idx, char *key); +void *git_strmap_value_at(git_strmap *map, size_t idx); +void git_strmap_set_value_at(git_strmap *map, size_t idx, void *value); +void git_strmap_delete_at(git_strmap *map, size_t idx); -#define git_strmap_exists(h, k) (kh_get(str, h, k) != kh_end(h)) -#define git_strmap_has_data(h, idx) kh_exist(h, idx) - -#define git_strmap_key(h, idx) kh_key(h, idx) -#define git_strmap_value_at(h, idx) kh_val(h, idx) -#define git_strmap_set_value_at(h, idx, v) kh_val(h, idx) = v -#define git_strmap_delete_at(h, idx) kh_del(str, h, idx) - -#define git_strmap_insert(h, key, val, rval) do { \ - khiter_t __pos = kh_put(str, h, key, &rval); \ - if (rval >= 0) { \ - if (rval == 0) kh_key(h, __pos) = key; \ - kh_val(h, __pos) = val; \ - } } while (0) - -#define git_strmap_insert2(h, key, val, oldv, rval) do { \ - khiter_t __pos = kh_put(str, h, key, &rval); \ - if (rval >= 0) { \ - if (rval == 0) { \ - oldv = kh_val(h, __pos); \ - kh_key(h, __pos) = key; \ - } else { oldv = NULL; } \ - kh_val(h, __pos) = val; \ - } } while (0) - -#define git_strmap_delete(h, key) do { \ - khiter_t __pos = git_strmap_lookup_index(h, key); \ - if (git_strmap_valid_index(h, __pos)) \ - git_strmap_delete_at(h, __pos); } while (0) +int git_strmap_put(git_strmap *map, const char *key, int *err); +void git_strmap_insert(git_strmap *map, const char *key, void *value, int *rval); +void git_strmap_delete(git_strmap *map, const char *key); #define git_strmap_foreach kh_foreach #define git_strmap_foreach_value kh_foreach_value diff --git a/src/submodule.c b/src/submodule.c index 86ad53be0..ddd4b0663 100644 --- a/src/submodule.c +++ b/src/submodule.c @@ -22,6 +22,7 @@ #include "iterator.h" #include "path.h" #include "index.h" +#include "worktree.h" #define GIT_MODULES_FILE ".gitmodules" @@ -124,8 +125,8 @@ static void submodule_set_lookup_error(int error, const char *name) return; giterr_set(GITERR_SUBMODULE, (error == GIT_ENOTFOUND) ? - "No submodule named '%s'" : - "Submodule '%s' has not been added yet", name); + "no submodule named '%s'" : + "submodule '%s' has not been added yet", name); } typedef struct { @@ -149,40 +150,52 @@ static int find_by_path(const git_config_entry *entry, void *payload) } /** - * Find out the name of a submodule from its path + * Release the name map returned by 'load_submodule_names'. */ -static int name_from_path(git_buf *out, git_config *cfg, const char *path) +static void free_submodule_names(git_strmap *names) +{ + git_buf *name = 0; + if (names == NULL) + return; + git_strmap_foreach_value(names, name, { + git__free(name); + }); + git_strmap_free(names); + return; +} + +/** + * Map submodule paths to 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) { const char *key = "submodule\\..*\\.path"; git_config_iterator *iter; git_config_entry *entry; - int error; + git_buf buf = GIT_BUF_INIT; + int rval; + int error = 0; if ((error = git_config_iterator_glob_new(&iter, cfg, key)) < 0) return error; - while ((error = git_config_next(&entry, iter)) == 0) { + while (git_config_next(&entry, iter) == 0) { const char *fdot, *ldot; - /* TODO: this should maybe be strcasecmp on a case-insensitive fs */ - if (strcmp(path, entry->value) != 0) - continue; - fdot = strchr(entry->name, '.'); ldot = strrchr(entry->name, '.'); - git_buf_clear(out); - git_buf_put(out, fdot + 1, ldot - fdot - 1); - goto cleanup; + git_buf_put(&buf, fdot + 1, ldot - fdot - 1); + 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) { - giterr_set(GITERR_SUBMODULE, "could not find a submodule name for '%s'", path); - error = GIT_ENOTFOUND; - } - -cleanup: git_config_iterator_free(iter); - return error; + return 0; } int git_submodule_lookup( @@ -196,6 +209,17 @@ int git_submodule_lookup( assert(repo && name); + if (repo->submodule_cache != NULL) { + khiter_t pos = git_strmap_lookup_index(repo->submodule_cache, name); + if (git_strmap_valid_index(repo->submodule_cache, pos)) { + if (out) { + *out = git_strmap_value_at(repo->submodule_cache, pos); + GIT_REFCOUNT_INC(*out); + } + return 0; + } + } + if ((error = submodule_alloc(&sm, repo, name)) < 0) return error; @@ -306,7 +330,7 @@ static int submodule_get_or_create(git_submodule **out, git_repository *repo, gi if ((error = submodule_alloc(&sm, repo, name)) < 0) return error; - pos = kh_put(str, map, sm->name, &error); + pos = git_strmap_put(map, sm->name, &error); /* nobody can beat us to adding it */ assert(error != 0); if (error < 0) { @@ -324,89 +348,108 @@ done: static int submodules_from_index(git_strmap *map, git_index *idx, git_config *cfg) { - int error; - git_iterator *i; - const git_index_entry *entry; - git_buf name = GIT_BUF_INIT; + int error; + git_iterator *i = NULL; + const git_index_entry *entry; + git_strmap *names = 0; - if ((error = git_iterator_for_index(&i, git_index_owner(idx), idx, NULL)) < 0) - return error; + git_strmap_alloc(&names); + if ((error = load_submodule_names(names, cfg))) + goto done; - while (!(error = git_iterator_advance(&entry, i))) { - khiter_t pos = git_strmap_lookup_index(map, entry->path); - git_submodule *sm; + if ((error = git_iterator_for_index(&i, git_index_owner(idx), idx, NULL)) < 0) + goto done; - git_buf_clear(&name); - if (!name_from_path(&name, cfg, entry->path)) { - git_strmap_lookup_index(map, name.ptr); - } + while (!(error = git_iterator_advance(&entry, i))) { + khiter_t pos = git_strmap_lookup_index(map, entry->path); + git_submodule *sm; - if (git_strmap_valid_index(map, pos)) { - sm = git_strmap_value_at(map, pos); + if (git_strmap_valid_index(map, pos)) { + sm = git_strmap_value_at(map, pos); - if (S_ISGITLINK(entry->mode)) - submodule_update_from_index_entry(sm, entry); - else - sm->flags |= GIT_SUBMODULE_STATUS__INDEX_NOT_SUBMODULE; - } else if (S_ISGITLINK(entry->mode)) { - if (!submodule_get_or_create(&sm, git_index_owner(idx), map, name.ptr ? name.ptr : entry->path)) { - submodule_update_from_index_entry(sm, entry); - git_submodule_free(sm); - } - } - } + if (S_ISGITLINK(entry->mode)) + submodule_update_from_index_entry(sm, entry); + else + sm->flags |= GIT_SUBMODULE_STATUS__INDEX_NOT_SUBMODULE; + } else if (S_ISGITLINK(entry->mode)) { + khiter_t name_pos; + const char *name; - if (error == GIT_ITEROVER) - error = 0; + name_pos = git_strmap_lookup_index(names, entry->path); + if (git_strmap_valid_index(names, name_pos)) { + name = git_strmap_value_at(names, name_pos); + } else { + name = entry->path; + } - git_buf_free(&name); - git_iterator_free(i); + if (!submodule_get_or_create(&sm, git_index_owner(idx), map, name)) { + submodule_update_from_index_entry(sm, entry); + git_submodule_free(sm); + } + } + } - return error; + if (error == GIT_ITEROVER) + error = 0; + +done: + git_iterator_free(i); + free_submodule_names(names); + + return error; } static int submodules_from_head(git_strmap *map, git_tree *head, git_config *cfg) { - int error; - git_iterator *i; - const git_index_entry *entry; - git_buf name = GIT_BUF_INIT; + int error; + git_iterator *i = NULL; + const git_index_entry *entry; + git_strmap *names = 0; + git_strmap_alloc(&names); + if ((error = load_submodule_names(names, cfg))) + goto done; - if ((error = git_iterator_for_tree(&i, head, NULL)) < 0) - return error; + if ((error = git_iterator_for_tree(&i, head, NULL)) < 0) + goto done; - while (!(error = git_iterator_advance(&entry, i))) { - khiter_t pos = git_strmap_lookup_index(map, entry->path); - git_submodule *sm; + while (!(error = git_iterator_advance(&entry, i))) { + khiter_t pos = git_strmap_lookup_index(map, entry->path); + git_submodule *sm; - git_buf_clear(&name); - if (!name_from_path(&name, cfg, entry->path)) { - git_strmap_lookup_index(map, name.ptr); - } + if (git_strmap_valid_index(map, pos)) { + sm = git_strmap_value_at(map, pos); - if (git_strmap_valid_index(map, pos)) { - sm = git_strmap_value_at(map, pos); + if (S_ISGITLINK(entry->mode)) + submodule_update_from_head_data(sm, entry->mode, &entry->id); + else + sm->flags |= GIT_SUBMODULE_STATUS__HEAD_NOT_SUBMODULE; + } else if (S_ISGITLINK(entry->mode)) { + khiter_t name_pos; + const char *name; - if (S_ISGITLINK(entry->mode)) - submodule_update_from_head_data(sm, entry->mode, &entry->id); - else - sm->flags |= GIT_SUBMODULE_STATUS__HEAD_NOT_SUBMODULE; - } else if (S_ISGITLINK(entry->mode)) { - if (!submodule_get_or_create(&sm, git_tree_owner(head), map, name.ptr ? name.ptr : entry->path)) { - submodule_update_from_head_data( - sm, entry->mode, &entry->id); - git_submodule_free(sm); - } - } - } + name_pos = git_strmap_lookup_index(names, entry->path); + if (git_strmap_valid_index(names, name_pos)) { + name = git_strmap_value_at(names, name_pos); + } else { + name = entry->path; + } - if (error == GIT_ITEROVER) - error = 0; + if (!submodule_get_or_create(&sm, git_tree_owner(head), map, name)) { + submodule_update_from_head_data( + sm, entry->mode, &entry->id); + git_submodule_free(sm); + } + } + } - git_buf_free(&name); - git_iterator_free(i); + if (error == GIT_ITEROVER) + error = 0; - return error; +done: + git_iterator_free(i); + free_submodule_names(names); + + return error; } /* If have_sm is true, sm is populated, otherwise map an repo are. */ @@ -416,7 +459,7 @@ typedef struct { git_repository *repo; } lfc_data; -static int all_submodules(git_repository *repo, git_strmap *map) +int git_submodule__map(git_repository *repo, git_strmap *map) { int error = 0; git_index *idx = NULL; @@ -470,12 +513,12 @@ static int all_submodules(git_repository *repo, git_strmap *map) goto cleanup; } /* add back submodule information from index */ - if (idx) { + if (mods && idx) { if ((error = submodules_from_index(map, idx, mods)) < 0) goto cleanup; } /* add submodule information from HEAD */ - if (head) { + if (mods && head) { if ((error = submodules_from_head(map, head, mods)) < 0) goto cleanup; } @@ -509,11 +552,11 @@ int git_submodule_foreach( if ((error = git_strmap_alloc(&submodules)) < 0) return error; - if ((error = all_submodules(repo, submodules)) < 0) + if ((error = git_submodule__map(repo, submodules)) < 0) goto done; if (!(error = git_vector_init( - &snapshot, kh_size(submodules), submodule_cmp))) { + &snapshot, git_strmap_num_entries(submodules), submodule_cmp))) { git_strmap_foreach_value(submodules, sm, { if ((error = git_vector_insert(&snapshot, sm)) < 0) @@ -574,8 +617,10 @@ static int submodule_repo_init( * Old style: sub-repo goes directly into repo//.git/ */ if (use_gitlink) { - error = git_buf_join3( - &repodir, '/', git_repository_path(parent_repo), "modules", path); + error = git_repository_item_path(&repodir, parent_repo, GIT_REPOSITORY_ITEM_MODULES); + if (error < 0) + goto cleanup; + error = git_buf_joinpath(&repodir, repodir.ptr, path); if (error < 0) goto cleanup; @@ -618,7 +663,7 @@ int git_submodule_add_setup( giterr_clear(); else { giterr_set(GITERR_SUBMODULE, - "Attempt to add submodule '%s' that already exists", path); + "attempt to add submodule '%s' that already exists", path); return GIT_EEXISTS; } @@ -628,7 +673,7 @@ int git_submodule_add_setup( path += strlen(git_repository_workdir(repo)); if (git_path_root(path) >= 0) { - giterr_set(GITERR_SUBMODULE, "Submodule path must be a relative path"); + giterr_set(GITERR_SUBMODULE, "submodule path must be a relative path"); error = -1; goto cleanup; } @@ -637,7 +682,7 @@ int git_submodule_add_setup( if (!(mods = open_gitmodules(repo, GITMODULES_CREATE))) { giterr_set(GITERR_SUBMODULE, - "Adding submodules to a bare repository is not supported"); + "adding submodules to a bare repository is not supported"); return -1; } @@ -758,7 +803,7 @@ int git_submodule_add_to_index(git_submodule *sm, int write_index) /* read stat information for submodule working directory */ if (p_stat(path.ptr, &st) < 0) { giterr_set(GITERR_SUBMODULE, - "Cannot add submodule without working directory"); + "cannot add submodule without working directory"); error = -1; goto cleanup; } @@ -771,7 +816,7 @@ int git_submodule_add_to_index(git_submodule *sm, int write_index) /* calling git_submodule_open will have set sm->wd_oid if possible */ if ((sm->flags & GIT_SUBMODULE_STATUS__WD_OID_VALID) == 0) { giterr_set(GITERR_SUBMODULE, - "Cannot add submodule without HEAD to index"); + "cannot add submodule without HEAD to index"); error = -1; goto cleanup; } @@ -861,7 +906,7 @@ int git_submodule_resolve_url(git_buf *out, git_repository *repo, const char *ur } else if (strchr(url, ':') != NULL || url[0] == '/') { error = git_buf_sets(out, url); } else { - giterr_set(GITERR_SUBMODULE, "Invalid format for submodule URL"); + giterr_set(GITERR_SUBMODULE, "invalid format for submodule URL"); error = -1; } @@ -1042,8 +1087,10 @@ static int submodule_repo_create( * /modules// with a gitlink in the * sub-repo workdir directory to that repository. */ - error = git_buf_join3( - &repodir, '/', git_repository_path(parent_repo), "modules", path); + error = git_repository_item_path(&repodir, parent_repo, GIT_REPOSITORY_ITEM_MODULES); + if (error < 0) + goto cleanup; + error = git_buf_joinpath(&repodir, repodir.ptr, path); if (error < 0) goto cleanup; @@ -1133,7 +1180,7 @@ int git_submodule_update(git_submodule *sm, int init, git_submodule_update_optio goto done; if (!init) { - giterr_set(GITERR_SUBMODULE, "Submodule is not initialized."); + giterr_set(GITERR_SUBMODULE, "submodule is not initialized"); error = GIT_ERROR; goto done; } @@ -1160,13 +1207,14 @@ int git_submodule_update(git_submodule *sm, int init, git_submodule_update_optio * will checkout the specific commit manually. */ clone_options.checkout_opts.checkout_strategy = GIT_CHECKOUT_NONE; - update_options.checkout_opts.checkout_strategy = update_options.clone_checkout_strategy; if ((error = git_clone(&sub_repo, submodule_url, sm->path, &clone_options)) < 0 || (error = git_repository_set_head_detached(sub_repo, git_submodule_index_id(sm))) < 0 || (error = git_checkout_head(sub_repo, &update_options.checkout_opts)) != 0) goto done; } else { + const git_oid *oid; + /** * Work dir is initialized - look up the commit in the parent repository's index, * update the workdir contents of the subrepository, and set the subrepository's @@ -1175,8 +1223,14 @@ int git_submodule_update(git_submodule *sm, int init, git_submodule_update_optio if ((error = git_submodule_open(&sub_repo, sm)) < 0) goto done; + if ((oid = git_submodule_index_id(sm)) == NULL) { + giterr_set(GITERR_SUBMODULE, "could not get ID of submodule in index"); + error = -1; + goto done; + } + /* Look up the target commit in the submodule. */ - if ((error = git_object_lookup(&target_commit, sub_repo, git_submodule_index_id(sm), GIT_OBJ_COMMIT)) < 0) { + if ((error = git_object_lookup(&target_commit, sub_repo, oid, GIT_OBJ_COMMIT)) < 0) { /* If it isn't found then fetch and try again. */ if (error != GIT_ENOTFOUND || !update_options.allow_fetch || (error = lookup_default_remote(&remote, sub_repo)) < 0 || @@ -1215,7 +1269,7 @@ int git_submodule_init(git_submodule *sm, int overwrite) if (!sm->url) { giterr_set(GITERR_SUBMODULE, - "No URL configured for submodule '%s'", sm->name); + "no URL configured for submodule '%s'", sm->name); return -1; } @@ -1259,7 +1313,7 @@ int git_submodule_sync(git_submodule *sm) if (!sm->url) { giterr_set(GITERR_SUBMODULE, - "No URL configured for submodule '%s'", sm->name); + "no URL configured for submodule '%s'", sm->name); return -1; } @@ -1502,13 +1556,22 @@ int git_submodule__status( return 0; } - /* refresh the index OID */ - if (submodule_update_index(sm) < 0) - return -1; + /* If the user has requested caching submodule state, performing these + * expensive operations (especially `submodule_update_head`, which is + * bottlenecked on `git_repository_head_tree`) eliminates much of the + * advantage. We will, therefore, interpret the request for caching to + * apply here to and skip them. + */ - /* refresh the HEAD OID */ - if (submodule_update_head(sm) < 0) - return -1; + if (sm->repo->submodule_cache == NULL) { + /* refresh the index OID */ + if (submodule_update_index(sm) < 0) + return -1; + + /* refresh the HEAD OID */ + if (submodule_update_head(sm) < 0) + return -1; + } /* for ignore == dirty, don't scan the working directory */ if (ign == GIT_SUBMODULE_IGNORE_DIRTY) { @@ -1566,7 +1629,6 @@ int git_submodule_location(unsigned int *location, git_submodule *sm) location, NULL, NULL, NULL, sm, GIT_SUBMODULE_IGNORE_ALL); } - /* * INTERNAL FUNCTIONS */ @@ -1578,7 +1640,7 @@ static int submodule_alloc( git_submodule *sm; if (!name || !(namelen = strlen(name))) { - giterr_set(GITERR_SUBMODULE, "Invalid submodule name"); + giterr_set(GITERR_SUBMODULE, "invalid submodule name"); return -1; } @@ -1630,7 +1692,7 @@ void git_submodule_free(git_submodule *sm) static int submodule_config_error(const char *property, const char *value) { giterr_set(GITERR_INVALID, - "Invalid value for submodule '%s' property: '%s'", property, value); + "invalid value for submodule '%s' property: '%s'", property, value); return -1; } @@ -1813,7 +1875,7 @@ static int submodule_load_each(const git_config_entry *entry, void *payload) goto done; } - git_strmap_insert(map, sm->name, sm, error); + git_strmap_insert(map, sm->name, sm, &error); assert(error != 0); if (error < 0) goto done; @@ -1968,7 +2030,7 @@ static int lookup_default_remote(git_remote **remote, git_repository *repo) if (error == GIT_ENOTFOUND) giterr_set( GITERR_SUBMODULE, - "Cannot get default remote for submodule - no local tracking " + "cannot get default remote for submodule - no local tracking " "branch for HEAD and origin does not exist"); return error; @@ -1977,17 +2039,28 @@ static int lookup_default_remote(git_remote **remote, git_repository *repo) static int get_url_base(git_buf *url, git_repository *repo) { int error; + git_worktree *wt = NULL; git_remote *remote = NULL; - if (!(error = lookup_default_remote(&remote, repo))) { + if ((error = lookup_default_remote(&remote, repo)) == 0) { error = git_buf_sets(url, git_remote_url(remote)); - git_remote_free(remote); - } - else if (error == GIT_ENOTFOUND) { - /* if repository does not have a default remote, use workdir instead */ + goto out; + } else if (error != GIT_ENOTFOUND) + goto out; + else giterr_clear(); + + /* if repository does not have a default remote, use workdir instead */ + if (git_repository_is_worktree(repo)) { + if ((error = git_worktree_open_from_repository(&wt, repo)) < 0) + goto out; + error = git_buf_sets(url, wt->parent_path); + } else error = git_buf_sets(url, git_repository_workdir(repo)); - } + +out: + git_remote_free(remote); + git_worktree_free(wt); return error; } diff --git a/src/submodule.h b/src/submodule.h index 2ef2031b3..456a93979 100644 --- a/src/submodule.h +++ b/src/submodule.h @@ -143,4 +143,7 @@ extern int git_submodule_parse_ignore( extern int git_submodule_parse_update( git_submodule_update_t *out, const char *value); +extern int git_submodule__map( + git_repository *repo, + git_strmap *map); #endif diff --git a/src/sysdir.c b/src/sysdir.c index e89db7697..9312a7edb 100644 --- a/src/sysdir.c +++ b/src/sysdir.c @@ -150,7 +150,7 @@ int git_sysdir_get_str( GITERR_CHECK_ERROR(git_sysdir_get(&path, which)); if (!out || path->size >= outlen) { - giterr_set(GITERR_NOMEMORY, "Buffer is too short for the path"); + giterr_set(GITERR_NOMEMORY, "buffer is too short for the path"); return GIT_EBUFS; } @@ -241,7 +241,7 @@ static int git_sysdir_find_in_dirlist( done: git_buf_free(path); - giterr_set(GITERR_OS, "The %s file '%s' doesn't exist", label, name); + giterr_set(GITERR_OS, "the %s file '%s' doesn't exist", label, name); return GIT_ENOTFOUND; } @@ -275,3 +275,14 @@ int git_sysdir_find_template_dir(git_buf *path) path, NULL, GIT_SYSDIR_TEMPLATE, "template"); } +int git_sysdir_expand_global_file(git_buf *path, const char *filename) +{ + int error; + + if ((error = git_sysdir_find_global_file(path, NULL)) == 0) { + if (filename) + error = git_buf_joinpath(path, path->ptr, filename); + } + + return error; +} diff --git a/src/sysdir.h b/src/sysdir.h index 11878981c..79f23818a 100644 --- a/src/sysdir.h +++ b/src/sysdir.h @@ -55,6 +55,18 @@ extern int git_sysdir_find_programdata_file(git_buf *path, const char *filename) */ extern int git_sysdir_find_template_dir(git_buf *path); +/** + * Expand the name of a "global" file (i.e. one in a user's home + * directory). Unlike `find_global_file` (above), this makes no + * attempt to check for the existence of the file, and is useful if + * you want the full path regardless of existence. + * + * @param path buffer to write the full path into + * @param filename name of file in the home directory + * @return 0 on success or -1 on error + */ +extern int git_sysdir_expand_global_file(git_buf *path, const char *filename); + typedef enum { GIT_SYSDIR_SYSTEM = 0, GIT_SYSDIR_GLOBAL = 1, diff --git a/src/tag.c b/src/tag.c index fe840fe82..2bf23fc3c 100644 --- a/src/tag.c +++ b/src/tag.c @@ -61,7 +61,7 @@ const char *git_tag_message(const git_tag *t) static int tag_error(const char *str) { - giterr_set(GITERR_TAG, "Failed to parse tag. %s", str); + giterr_set(GITERR_TAG, "failed to parse tag: %s", str); return -1; } @@ -76,13 +76,13 @@ static int tag_parse(git_tag *tag, const char *buffer, const char *buffer_end) char *search; if (git_oid__parse(&tag->target, &buffer, buffer_end, "object ") < 0) - return tag_error("Object field invalid"); + return tag_error("object field invalid"); if (buffer + 5 >= buffer_end) - return tag_error("Object too short"); + return tag_error("object too short"); if (memcmp(buffer, "type ", 5) != 0) - return tag_error("Type field not found"); + return tag_error("type field not found"); buffer += 5; tag->type = GIT_OBJ_BAD; @@ -91,7 +91,7 @@ static int tag_parse(git_tag *tag, const char *buffer, const char *buffer_end) size_t type_length = strlen(tag_types[i]); if (buffer + type_length >= buffer_end) - return tag_error("Object too short"); + return tag_error("object too short"); if (memcmp(buffer, tag_types[i], type_length) == 0) { tag->type = i; @@ -101,19 +101,19 @@ static int tag_parse(git_tag *tag, const char *buffer, const char *buffer_end) } if (tag->type == GIT_OBJ_BAD) - return tag_error("Invalid object type"); + return tag_error("invalid object type"); if (buffer + 4 >= buffer_end) - return tag_error("Object too short"); + return tag_error("object too short"); if (memcmp(buffer, "tag ", 4) != 0) - return tag_error("Tag field not found"); + return tag_error("tag field not found"); buffer += 4; search = memchr(buffer, '\n', buffer_end - buffer); if (search == NULL) - return tag_error("Object too short"); + return tag_error("object too short"); text_len = search - buffer; @@ -234,7 +234,7 @@ static int write_tag_annotation( on_error: git_buf_free(&tag); - giterr_set(GITERR_OBJECT, "Failed to create tag annotation."); + giterr_set(GITERR_OBJECT, "failed to create tag annotation"); return -1; } @@ -257,7 +257,7 @@ static int git_tag_create__internal( assert(!create_tag_annotation || (tagger && message)); if (git_object_owner(target) != repo) { - giterr_set(GITERR_INVALID, "The given target does not belong to this repository"); + giterr_set(GITERR_INVALID, "the given target does not belong to this repository"); return -1; } @@ -269,7 +269,7 @@ static int git_tag_create__internal( * reference unless overwriting has explicitly been requested **/ if (error == 0 && !allow_ref_overwrite) { git_buf_free(&ref_name); - giterr_set(GITERR_TAG, "Tag already exists"); + giterr_set(GITERR_TAG, "tag already exists"); return GIT_EEXISTS; } @@ -349,7 +349,7 @@ int git_tag_create_frombuffer(git_oid *oid, git_repository *repo, const char *bu goto on_error; if (tag.type != target_obj->cached.type) { - giterr_set(GITERR_TAG, "The type for the given target is invalid"); + giterr_set(GITERR_TAG, "the type for the given target is invalid"); goto on_error; } @@ -366,7 +366,7 @@ int git_tag_create_frombuffer(git_oid *oid, git_repository *repo, const char *bu /** Ensure the tag name doesn't conflict with an already existing * reference unless overwriting has explicitly been requested **/ if (error == 0 && !allow_ref_overwrite) { - giterr_set(GITERR_TAG, "Tag already exists"); + giterr_set(GITERR_TAG, "tag already exists"); return GIT_EEXISTS; } diff --git a/src/thread-utils.h b/src/thread-utils.h index f0161989f..2df2aeb99 100644 --- a/src/thread-utils.h +++ b/src/thread-utils.h @@ -7,6 +7,12 @@ #ifndef INCLUDE_thread_utils_h__ #define INCLUDE_thread_utils_h__ +#if defined(__GNUC__) && defined(GIT_THREADS) +# if (__GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 1)) +# error Atomic primitives do not exist on this version of gcc; configure libgit2 with -DTHREADSAFE=OFF +# endif +#endif + /* Common operations even if threading has been disabled */ typedef struct { #if defined(GIT_WIN32) diff --git a/src/trace.c b/src/trace.c index ee5039f56..0f2142861 100644 --- a/src/trace.c +++ b/src/trace.c @@ -32,7 +32,7 @@ int git_trace_set(git_trace_level_t level, git_trace_callback callback) GIT_UNUSED(callback); giterr_set(GITERR_INVALID, - "This version of libgit2 was not built with tracing."); + "this version of libgit2 was not built with tracing."); return -1; #endif } diff --git a/src/transaction.c b/src/transaction.c index 2c8a1e8bd..3d3f35a03 100644 --- a/src/transaction.c +++ b/src/transaction.c @@ -19,8 +19,6 @@ #include "git2/sys/refs.h" #include "git2/sys/refdb_backend.h" -GIT__USE_STRMAP - typedef enum { TRANSACTION_NONE, TRANSACTION_REFS, @@ -120,7 +118,7 @@ int git_transaction_lock_ref(git_transaction *tx, const char *refname) if ((error = git_refdb_lock(&node->payload, tx->db, refname)) < 0) return error; - git_strmap_insert(tx->locks, node->name, node, error); + git_strmap_insert(tx->locks, node->name, node, &error); if (error < 0) goto cleanup; @@ -323,7 +321,6 @@ static int update_target(git_refdb *db, transaction_node *node) int git_transaction_commit(git_transaction *tx) { transaction_node *node; - git_strmap_iter pos; int error = 0; assert(tx); @@ -335,11 +332,7 @@ int git_transaction_commit(git_transaction *tx) return error; } - for (pos = kh_begin(tx->locks); pos < kh_end(tx->locks); pos++) { - if (!git_strmap_has_data(tx->locks, pos)) - continue; - - node = git_strmap_value_at(tx->locks, pos); + git_strmap_foreach_value(tx->locks, node, { if (node->reflog) { if ((error = tx->db->backend->reflog_write(tx->db->backend, node->reflog)) < 0) return error; @@ -349,7 +342,7 @@ int git_transaction_commit(git_transaction *tx) if ((error = update_target(tx->db, node)) < 0) return error; } - } + }); return 0; } @@ -358,7 +351,6 @@ void git_transaction_free(git_transaction *tx) { transaction_node *node; git_pool pool; - git_strmap_iter pos; assert(tx); @@ -373,16 +365,12 @@ void git_transaction_free(git_transaction *tx) } /* start by unlocking the ones we've left hanging, if any */ - for (pos = kh_begin(tx->locks); pos < kh_end(tx->locks); pos++) { - if (!git_strmap_has_data(tx->locks, pos)) - continue; - - node = git_strmap_value_at(tx->locks, pos); + git_strmap_foreach_value(tx->locks, node, { if (node->committed) continue; git_refdb_unlock(tx->db, node->payload, false, false, NULL, NULL, NULL); - } + }); git_refdb_free(tx->db); git_strmap_free(tx->locks); diff --git a/src/transport.c b/src/transport.c index f08d2dc68..b66165332 100644 --- a/src/transport.c +++ b/src/transport.c @@ -121,7 +121,7 @@ int git_transport_new(git_transport **out, git_remote *owner, const char *url) int error; if ((error = transport_find_fn(&fn, url, ¶m)) == GIT_ENOTFOUND) { - giterr_set(GITERR_NET, "Unsupported URL protocol"); + giterr_set(GITERR_NET, "unsupported URL protocol"); return -1; } else if (error < 0) return error; diff --git a/src/transports/auth_negotiate.c b/src/transports/auth_negotiate.c index 8b99fc735..7c868c9fd 100644 --- a/src/transports/auth_negotiate.c +++ b/src/transports/auth_negotiate.c @@ -107,13 +107,13 @@ static int negotiate_next_token( challenge_len = ctx->challenge ? strlen(ctx->challenge) : 0; if (challenge_len < 9) { - giterr_set(GITERR_NET, "No negotiate challenge sent from server"); + giterr_set(GITERR_NET, "no negotiate challenge sent from server"); error = -1; goto done; } else if (challenge_len > 9) { if (git_buf_decode_base64(&input_buf, ctx->challenge + 10, challenge_len - 10) < 0) { - giterr_set(GITERR_NET, "Invalid negotiate challenge from server"); + giterr_set(GITERR_NET, "invalid negotiate challenge from server"); error = -1; goto done; } @@ -122,7 +122,7 @@ static int negotiate_next_token( input_token.length = input_buf.size; input_token_ptr = &input_token; } else if (ctx->gss_context != GSS_C_NO_CONTEXT) { - giterr_set(GITERR_NET, "Could not restart authentication"); + giterr_set(GITERR_NET, "could not restart authentication"); error = -1; goto done; } @@ -228,7 +228,7 @@ static int negotiate_init_context( gss_release_oid_set(&status_minor, &mechanism_list); if (!ctx->oid) { - giterr_set(GITERR_NET, "Negotiate authentication is not supported"); + giterr_set(GITERR_NET, "negotiate authentication is not supported"); return -1; } diff --git a/src/transports/cred.c b/src/transports/cred.c index 49ede48bf..8e3f64435 100644 --- a/src/transports/cred.c +++ b/src/transports/cred.c @@ -216,7 +216,7 @@ int git_cred_ssh_key_memory_new( GIT_UNUSED(passphrase); giterr_set(GITERR_INVALID, - "This version of libgit2 was not built with ssh memory credentials."); + "this version of libgit2 was not built with ssh memory credentials."); return -1; #endif } diff --git a/src/transports/git.c b/src/transports/git.c index 6c6acf9c5..01edfdc49 100644 --- a/src/transports/git.c +++ b/src/transports/git.c @@ -45,7 +45,7 @@ static int gen_proto(git_buf *request, const char *cmd, const char *url) delim = strchr(url, '/'); if (delim == NULL) { - giterr_set(GITERR_NET, "Malformed URL"); + giterr_set(GITERR_NET, "malformed URL"); return -1; } @@ -240,7 +240,7 @@ static int _git_uploadpack( return 0; } - giterr_set(GITERR_NET, "Must call UPLOADPACK_LS before UPLOADPACK"); + giterr_set(GITERR_NET, "must call UPLOADPACK_LS before UPLOADPACK"); return -1; } @@ -296,7 +296,7 @@ static int _git_receivepack( return 0; } - giterr_set(GITERR_NET, "Must call RECEIVEPACK_LS before RECEIVEPACK"); + giterr_set(GITERR_NET, "must call RECEIVEPACK_LS before RECEIVEPACK"); return -1; } diff --git a/src/transports/http.c b/src/transports/http.c index 155fd7b30..cb4a6d0d5 100644 --- a/src/transports/http.c +++ b/src/transports/http.c @@ -403,7 +403,7 @@ static int on_headers_complete(http_parser *parser) t->location) { if (s->redirect_count >= 7) { - giterr_set(GITERR_NET, "Too many redirects"); + giterr_set(GITERR_NET, "too many redirects"); return t->parse_error = PARSE_ERROR_GENERIC; } @@ -428,14 +428,14 @@ static int on_headers_complete(http_parser *parser) /* Check for a 200 HTTP status code. */ if (parser->status_code != 200) { giterr_set(GITERR_NET, - "Unexpected HTTP status code: %d", + "unexpected HTTP status code: %d", parser->status_code); return t->parse_error = PARSE_ERROR_GENERIC; } /* The response must contain a Content-Type header. */ if (!t->content_type) { - giterr_set(GITERR_NET, "No Content-Type header in response"); + giterr_set(GITERR_NET, "no Content-Type header in response"); return t->parse_error = PARSE_ERROR_GENERIC; } @@ -455,7 +455,7 @@ static int on_headers_complete(http_parser *parser) if (strcmp(t->content_type, git_buf_cstr(&buf))) { git_buf_free(&buf); giterr_set(GITERR_NET, - "Invalid Content-Type: %s", + "invalid Content-Type: %s", t->content_type); return t->parse_error = PARSE_ERROR_GENERIC; } @@ -488,7 +488,7 @@ static int on_body_fill_buffer(http_parser *parser, const char *str, size_t len) return 0; if (ctx->buf_size < len) { - giterr_set(GITERR_NET, "Can't fit data in the buffer"); + giterr_set(GITERR_NET, "can't fit data in the buffer"); return t->parse_error = PARSE_ERROR_GENERIC; } @@ -575,6 +575,9 @@ static int apply_proxy_config(http_subtransport *t) if ((error = git_remote__get_http_proxy(t->owner->owner, !!t->connection_data.use_ssl, &url)) < 0) return error; + opts.credentials = t->owner->proxy.credentials; + opts.certificate_check = t->owner->proxy.certificate_check; + opts.payload = t->owner->proxy.payload; opts.type = GIT_PROXY_SPECIFIED; opts.url = url; error = git_stream_set_proxy(t->io, &opts); @@ -856,7 +859,7 @@ static int http_stream_write_single( assert(t->connected); if (s->sent_request) { - giterr_set(GITERR_NET, "Subtransport configured for only one write"); + giterr_set(GITERR_NET, "subtransport configured for only one write"); return -1; } diff --git a/src/transports/local.c b/src/transports/local.c index 4eae9dead..e24e99860 100644 --- a/src/transports/local.c +++ b/src/transports/local.c @@ -252,7 +252,7 @@ static int local_ls(const git_remote_head ***out, size_t *size, git_transport *t transport_local *t = (transport_local *)transport; if (!t->have_refs) { - giterr_set(GITERR_NET, "The transport has not yet loaded the refs"); + giterr_set(GITERR_NET, "the transport has not yet loaded the refs"); return -1; } @@ -371,11 +371,12 @@ static int local_push( but we forbid all pushes just in case */ if (!remote_repo->is_bare) { error = GIT_EBAREREPO; - giterr_set(GITERR_INVALID, "Local push doesn't (yet) support pushing to non-bare repos."); + giterr_set(GITERR_INVALID, "local push doesn't (yet) support pushing to non-bare repos."); goto on_error; } - if ((error = git_buf_joinpath(&odb_path, git_repository_path(remote_repo), "objects/pack")) < 0) + if ((error = git_repository_item_path(&odb_path, remote_repo, GIT_REPOSITORY_ITEM_OBJECTS)) < 0 + || (error = git_buf_joinpath(&odb_path, odb_path.ptr, "pack")) < 0) goto on_error; error = git_packbuilder_write(push->pb, odb_path.ptr, 0, transfer_to_push_transfer, (void *) cbs); diff --git a/src/transports/smart.c b/src/transports/smart.c index 7a35c39d8..a96fdf6fb 100644 --- a/src/transports/smart.c +++ b/src/transports/smart.c @@ -231,7 +231,7 @@ static int git_smart__connect( else if (GIT_DIRECTION_PUSH == t->direction) service = GIT_SERVICE_RECEIVEPACK_LS; else { - giterr_set(GITERR_NET, "Invalid direction"); + giterr_set(GITERR_NET, "invalid direction"); return -1; } @@ -252,7 +252,7 @@ static int git_smart__connect( pkt = (git_pkt *)git_vector_get(&t->refs, 0); if (!pkt || GIT_PKT_COMMENT != pkt->type) { - giterr_set(GITERR_NET, "Invalid response"); + giterr_set(GITERR_NET, "invalid response"); return -1; } else { /* Remove the comment pkt from the list */ @@ -299,7 +299,7 @@ static int git_smart__ls(const git_remote_head ***out, size_t *size, git_transpo transport_smart *t = (transport_smart *)transport; if (!t->have_refs) { - giterr_set(GITERR_NET, "The transport has not yet loaded the refs"); + giterr_set(GITERR_NET, "the transport has not yet loaded the refs"); return -1; } @@ -319,7 +319,7 @@ int git_smart__negotiation_step(git_transport *transport, void *data, size_t len return -1; if (GIT_DIRECTION_FETCH != t->direction) { - giterr_set(GITERR_NET, "This operation is only valid for fetch"); + giterr_set(GITERR_NET, "this operation is only valid for fetch"); return -1; } @@ -348,7 +348,7 @@ int git_smart__get_push_stream(transport_smart *t, git_smart_subtransport_stream return -1; if (GIT_DIRECTION_PUSH != t->direction) { - giterr_set(GITERR_NET, "This operation is only valid for push"); + giterr_set(GITERR_NET, "this operation is only valid for push"); return -1; } @@ -472,6 +472,12 @@ int git_transport_smart_credentials(git_cred **out, git_transport *transport, co return t->cred_acquire_cb(out, t->url, user, methods, t->cred_acquire_payload); } +int git_transport_smart_proxy_options(git_proxy_options *out, git_transport *transport) +{ + transport_smart *t = (transport_smart *) transport; + return git_proxy_options_dup(out, &t->proxy); +} + int git_transport_smart(git_transport **out, git_remote *owner, void *param) { transport_smart *t; diff --git a/src/transports/smart.h b/src/transports/smart.h index 0a0c3fc1b..b47001fe0 100644 --- a/src/transports/smart.h +++ b/src/transports/smart.h @@ -26,6 +26,8 @@ #define GIT_CAP_THIN_PACK "thin-pack" #define GIT_CAP_SYMREF "symref" +extern bool git_smart__ofs_delta_enabled; + enum git_pkt_type { GIT_PKT_CMD, GIT_PKT_FLUSH, diff --git a/src/transports/smart_pkt.c b/src/transports/smart_pkt.c index e05196cd8..a661dfe13 100644 --- a/src/transports/smart_pkt.c +++ b/src/transports/smart_pkt.c @@ -226,7 +226,7 @@ static int ref_pkt(git_pkt **out, const char *line, size_t len) /* Check for a bit of consistency */ if (line[GIT_OID_HEXSZ] != ' ') { - giterr_set(GITERR_NET, "Error parsing pkt-line"); + giterr_set(GITERR_NET, "error parsing pkt-line"); error = -1; goto error_out; } @@ -270,7 +270,7 @@ static int ok_pkt(git_pkt **out, const char *line, size_t len) line += 3; /* skip "ok " */ if (!(ptr = strchr(line, '\n'))) { - giterr_set(GITERR_NET, "Invalid packet line"); + giterr_set(GITERR_NET, "invalid packet line"); git__free(pkt); return -1; } @@ -327,7 +327,7 @@ static int ng_pkt(git_pkt **out, const char *line, size_t len) return 0; out_err: - giterr_set(GITERR_NET, "Invalid packet line"); + giterr_set(GITERR_NET, "invalid packet line"); git__free(pkt->ref); git__free(pkt); return -1; @@ -543,7 +543,7 @@ static int buffer_want_with_caps(const git_remote_head *head, transport_smart_ca if (len > 0xffff) { giterr_set(GITERR_NET, - "Tried to produce packet with invalid length %" PRIuZ, len); + "tried to produce packet with invalid length %" PRIuZ, len); return -1; } diff --git a/src/transports/smart_protocol.c b/src/transports/smart_protocol.c index db6a8b9c8..8146fa163 100644 --- a/src/transports/smart_protocol.c +++ b/src/transports/smart_protocol.c @@ -19,6 +19,8 @@ /* The minimal interval between progress updates (in seconds). */ #define MIN_PROGRESS_UPDATE_INTERVAL 0.5 +bool git_smart__ofs_delta_enabled = true; + int git_smart__store_refs(transport_smart *t, int flushes) { gitno_buffer *buf = &t->buffer; @@ -60,7 +62,7 @@ int git_smart__store_refs(transport_smart *t, int flushes) gitno_consume(buf, line_end); if (pkt->type == GIT_PKT_ERR) { - giterr_set(GITERR_NET, "Remote error: %s", ((git_pkt_err *)pkt)->error); + giterr_set(GITERR_NET, "remote error: %s", ((git_pkt_err *)pkt)->error); git__free(pkt); return -1; } @@ -138,7 +140,7 @@ int git_smart__detect_caps(git_pkt_ref *pkt, transport_smart_caps *caps, git_vec if (*ptr == ' ') ptr++; - if (!git__prefixcmp(ptr, GIT_CAP_OFS_DELTA)) { + if (git_smart__ofs_delta_enabled && !git__prefixcmp(ptr, GIT_CAP_OFS_DELTA)) { caps->common = caps->ofs_delta = 1; ptr += strlen(GIT_CAP_OFS_DELTA); continue; @@ -323,7 +325,8 @@ static int wait_while_ack(gitno_buffer *buf) if (pkt->type == GIT_PKT_ACK && (pkt->status != GIT_ACK_CONTINUE && - pkt->status != GIT_ACK_COMMON)) { + pkt->status != GIT_ACK_COMMON && + pkt->status != GIT_ACK_READY)) { git__free(pkt); return 0; } diff --git a/src/transports/ssh.c b/src/transports/ssh.c index cfd573665..4c55e3f2a 100644 --- a/src/transports/ssh.c +++ b/src/transports/ssh.c @@ -9,6 +9,7 @@ #include #endif +#include "global.h" #include "git2.h" #include "buffer.h" #include "netops.h" @@ -83,7 +84,7 @@ static int gen_proto(git_buf *request, const char *cmd, const char *url) done: if (!repo) { - giterr_set(GITERR_NET, "Malformed git protocol URL"); + giterr_set(GITERR_NET, "malformed git protocol URL"); return -1; } @@ -274,7 +275,7 @@ static int git_ssh_extract_url_parts( } if (colon == NULL || (colon < start)) { - giterr_set(GITERR_NET, "Malformed URL"); + giterr_set(GITERR_NET, "malformed URL"); return -1; } @@ -445,7 +446,7 @@ static int request_creds(git_cred **out, ssh_subtransport *t, const char *user, else if (error < 0) return error; else if (!cred) { - giterr_set(GITERR_SSH, "Callback failed to initialize SSH credentials"); + giterr_set(GITERR_SSH, "callback failed to initialize SSH credentials"); return -1; } } @@ -478,7 +479,7 @@ static int _git_ssh_session_create( s = libssh2_session_init(); if (!s) { - giterr_set(GITERR_NET, "Failed to initialize SSH session"); + giterr_set(GITERR_NET, "failed to initialize SSH session"); return -1; } @@ -487,7 +488,7 @@ static int _git_ssh_session_create( } while (LIBSSH2_ERROR_EAGAIN == rc || LIBSSH2_ERROR_TIMEOUT == rc); if (rc != LIBSSH2_ERROR_NONE) { - ssh_error(s, "Failed to start SSH session"); + ssh_error(s, "failed to start SSH session"); libssh2_session_free(s); return -1; } @@ -685,7 +686,7 @@ static int ssh_uploadpack( return 0; } - giterr_set(GITERR_NET, "Must call UPLOADPACK_LS before UPLOADPACK"); + giterr_set(GITERR_NET, "must call UPLOADPACK_LS before UPLOADPACK"); return -1; } @@ -712,7 +713,7 @@ static int ssh_receivepack( return 0; } - giterr_set(GITERR_NET, "Must call RECEIVEPACK_LS before RECEIVEPACK"); + giterr_set(GITERR_NET, "must call RECEIVEPACK_LS before RECEIVEPACK"); return -1; } @@ -844,7 +845,7 @@ int git_smart_subtransport_ssh( assert(out); *out = NULL; - giterr_set(GITERR_INVALID, "Cannot create SSH transport. Library was built without SSH support"); + giterr_set(GITERR_INVALID, "cannot create SSH transport. Library was built without SSH support"); return -1; #endif } @@ -888,16 +889,27 @@ int git_transport_ssh_with_paths(git_transport **out, git_remote *owner, void *p assert(out); *out = NULL; - giterr_set(GITERR_INVALID, "Cannot create SSH transport. Library was built without SSH support"); + giterr_set(GITERR_INVALID, "cannot create SSH transport. Library was built without SSH support"); return -1; #endif } +#ifdef GIT_SSH +static void shutdown_ssh(void) +{ + libssh2_exit(); +} +#endif + int git_transport_ssh_global_init(void) { #ifdef GIT_SSH + if (libssh2_init(0) < 0) { + giterr_set(GITERR_SSH, "unable to initialize libssh2"); + return -1; + } - libssh2_init(0); + git__on_shutdown(shutdown_ssh); return 0; #else diff --git a/src/transports/winhttp.c b/src/transports/winhttp.c index 78e42cf3b..fb504c912 100644 --- a/src/transports/winhttp.c +++ b/src/transports/winhttp.c @@ -68,7 +68,9 @@ static const IID IID_IInternetSecurityManager_mingw = typedef enum { GIT_WINHTTP_AUTH_BASIC = 1, - GIT_WINHTTP_AUTH_NEGOTIATE = 2, + GIT_WINHTTP_AUTH_NTLM = 2, + GIT_WINHTTP_AUTH_NEGOTIATE = 4, + GIT_WINHTTP_AUTH_DIGEST = 8, } winhttp_authmechanism_t; typedef struct { @@ -95,79 +97,71 @@ typedef struct { git_cred *cred; git_cred *url_cred; git_cred *proxy_cred; - int auth_mechanism; + int auth_mechanisms; HINTERNET session; HINTERNET connection; } winhttp_subtransport; -static int apply_basic_credential_proxy(HINTERNET request, git_cred *cred) +static int _apply_userpass_credential(HINTERNET request, DWORD target, DWORD scheme, git_cred *cred) { git_cred_userpass_plaintext *c = (git_cred_userpass_plaintext *)cred; wchar_t *user, *pass; - int error; + int user_len = 0, pass_len = 0, error = 0; - if ((error = git__utf8_to_16_alloc(&user, c->username)) < 0) - return error; + if ((error = user_len = git__utf8_to_16_alloc(&user, c->username)) < 0) + goto done; - if ((error = git__utf8_to_16_alloc(&pass, c->password)) < 0) - return error; + if ((error = pass_len = git__utf8_to_16_alloc(&pass, c->password)) < 0) + goto done; - if (!WinHttpSetCredentials(request, WINHTTP_AUTH_TARGET_PROXY, WINHTTP_AUTH_SCHEME_BASIC, - user, pass, NULL)) { - giterr_set(GITERR_OS, "failed to set proxy auth"); + if (!WinHttpSetCredentials(request, target, scheme, user, pass, NULL)) { + giterr_set(GITERR_OS, "failed to set credentials"); error = -1; } +done: + if (user_len > 0) + git__memzero(user, user_len * sizeof(wchar_t)); + + if (pass_len > 0) + git__memzero(pass, pass_len * sizeof(wchar_t)); + git__free(user); git__free(pass); return error; } -static int apply_basic_credential(HINTERNET request, git_cred *cred) +static int apply_userpass_credential_proxy(HINTERNET request, git_cred *cred, int mechanisms) { - git_cred_userpass_plaintext *c = (git_cred_userpass_plaintext *)cred; - git_buf buf = GIT_BUF_INIT, raw = GIT_BUF_INIT; - wchar_t *wide = NULL; - int error = -1, wide_len; - - git_buf_printf(&raw, "%s:%s", c->username, c->password); - - if (git_buf_oom(&raw) || - git_buf_puts(&buf, "Authorization: Basic ") < 0 || - git_buf_encode_base64(&buf, git_buf_cstr(&raw), raw.size) < 0) - goto on_error; - - if ((wide_len = git__utf8_to_16_alloc(&wide, git_buf_cstr(&buf))) < 0) { - giterr_set(GITERR_OS, "Failed to convert string to wide form"); - goto on_error; + if (GIT_WINHTTP_AUTH_DIGEST & mechanisms) { + return _apply_userpass_credential(request, WINHTTP_AUTH_TARGET_PROXY, + WINHTTP_AUTH_SCHEME_DIGEST, cred); } - if (!WinHttpAddRequestHeaders(request, wide, (ULONG) -1L, WINHTTP_ADDREQ_FLAG_ADD)) { - giterr_set(GITERR_OS, "Failed to add a header to the request"); - goto on_error; - } - - error = 0; - -on_error: - /* We were dealing with plaintext passwords, so clean up after ourselves a bit. */ - if (wide) - memset(wide, 0x0, wide_len * sizeof(wchar_t)); - - if (buf.size) - memset(buf.ptr, 0x0, buf.size); - - if (raw.size) - memset(raw.ptr, 0x0, raw.size); - - git__free(wide); - git_buf_free(&buf); - git_buf_free(&raw); - return error; + return _apply_userpass_credential(request, WINHTTP_AUTH_TARGET_PROXY, + WINHTTP_AUTH_SCHEME_BASIC, cred); } -static int apply_default_credentials(HINTERNET request) +static int apply_userpass_credential(HINTERNET request, int mechanisms, git_cred *cred) +{ + DWORD native_scheme; + + if ((mechanisms & GIT_WINHTTP_AUTH_NTLM) || + (mechanisms & GIT_WINHTTP_AUTH_NEGOTIATE)) { + native_scheme = WINHTTP_AUTH_SCHEME_NTLM; + } else if (mechanisms & GIT_WINHTTP_AUTH_BASIC) { + native_scheme = WINHTTP_AUTH_SCHEME_BASIC; + } else { + giterr_set(GITERR_NET, "invalid authentication scheme"); + return -1; + } + + return _apply_userpass_credential(request, WINHTTP_AUTH_TARGET_SERVER, + native_scheme, cred); +} + +static int apply_default_credentials(HINTERNET request, int mechanisms) { /* Either the caller explicitly requested that default credentials be passed, * or our fallback credential callback was invoked and checked that the target @@ -177,6 +171,12 @@ static int apply_default_credentials(HINTERNET request) * to Internet Explorer security zones, but in fact does not. */ DWORD data = WINHTTP_AUTOLOGON_SECURITY_LEVEL_LOW; + if ((mechanisms & GIT_WINHTTP_AUTH_NTLM) == 0 && + (mechanisms & GIT_WINHTTP_AUTH_NEGOTIATE) == 0) { + giterr_set(GITERR_NET, "invalid authentication scheme"); + return -1; + } + if (!WinHttpSetOption(request, WINHTTP_OPTION_AUTOLOGON_POLICY, &data, sizeof(DWORD))) return -1; @@ -202,7 +202,7 @@ static int fallback_cred_acquire_cb( /* Convert URL to wide characters */ if (git__utf8_to_16_alloc(&wide_url, url) < 0) { - giterr_set(GITERR_OS, "Failed to convert string to wide form"); + giterr_set(GITERR_OS, "failed to convert string to wide form"); return -1; } @@ -248,8 +248,12 @@ static int certificate_check(winhttp_stream *s, int valid) git_cert_x509 cert; /* If there is no override, we should fail if WinHTTP doesn't think it's fine */ - if (t->owner->certificate_check_cb == NULL && !valid) + if (t->owner->certificate_check_cb == NULL && !valid) { + if (!giterr_last()) + giterr_set(GITERR_NET, "unknown certificate check failure"); + return GIT_ECERTIFICATE; + } if (t->owner->certificate_check_cb == NULL || !t->connection_data.use_ssl) return 0; @@ -351,7 +355,7 @@ static int winhttp_stream_connect(winhttp_stream *s) /* Convert URL to wide characters */ if (git__utf8_to_16_alloc(&s->request_uri, git_buf_cstr(&buf)) < 0) { - giterr_set(GITERR_OS, "Failed to convert string to wide form"); + giterr_set(GITERR_OS, "failed to convert string to wide form"); goto on_error; } @@ -366,12 +370,12 @@ static int winhttp_stream_connect(winhttp_stream *s) t->connection_data.use_ssl ? WINHTTP_FLAG_SECURE : 0); if (!s->request) { - giterr_set(GITERR_OS, "Failed to open request"); + giterr_set(GITERR_OS, "failed to open request"); goto on_error; } if (!WinHttpSetTimeouts(s->request, default_timeout, default_connect_timeout, default_timeout, default_timeout)) { - giterr_set(GITERR_OS, "Failed to set timeouts for WinHTTP"); + giterr_set(GITERR_OS, "failed to set timeouts for WinHTTP"); goto on_error; } @@ -425,7 +429,6 @@ static int winhttp_stream_connect(winhttp_stream *s) git_buf_printf(&processed_url, ":%s", t->proxy_connection_data.port); if (git_buf_oom(&processed_url)) { - giterr_set_oom(); error = -1; goto on_error; } @@ -444,7 +447,7 @@ static int winhttp_stream_connect(winhttp_stream *s) WINHTTP_OPTION_PROXY, &proxy_info, sizeof(WINHTTP_PROXY_INFO))) { - giterr_set(GITERR_OS, "Failed to set proxy"); + giterr_set(GITERR_OS, "failed to set proxy"); git__free(proxy_wide); goto on_error; } @@ -453,7 +456,7 @@ static int winhttp_stream_connect(winhttp_stream *s) if (t->proxy_cred) { if (t->proxy_cred->credtype == GIT_CREDTYPE_USERPASS_PLAINTEXT) { - if ((error = apply_basic_credential_proxy(s->request, t->proxy_cred)) < 0) + if ((error = apply_userpass_credential_proxy(s->request, t->proxy_cred, t->auth_mechanisms)) < 0) goto on_error; } } @@ -467,7 +470,7 @@ static int winhttp_stream_connect(winhttp_stream *s) WINHTTP_OPTION_DISABLE_FEATURE, &disable_redirects, sizeof(disable_redirects))) { - giterr_set(GITERR_OS, "Failed to disable redirects"); + giterr_set(GITERR_OS, "failed to disable redirects"); goto on_error; } @@ -481,7 +484,7 @@ static int winhttp_stream_connect(winhttp_stream *s) /* Send Pragma: no-cache header */ if (!WinHttpAddRequestHeaders(s->request, pragma_nocache, (ULONG) -1L, WINHTTP_ADDREQ_FLAG_ADD)) { - giterr_set(GITERR_OS, "Failed to add a header to the request"); + giterr_set(GITERR_OS, "failed to add a header to the request"); goto on_error; } @@ -494,13 +497,13 @@ static int winhttp_stream_connect(winhttp_stream *s) goto on_error; if (git__utf8_to_16(ct, MAX_CONTENT_TYPE_LEN, git_buf_cstr(&buf)) < 0) { - giterr_set(GITERR_OS, "Failed to convert content-type to wide characters"); + giterr_set(GITERR_OS, "failed to convert content-type to wide characters"); goto on_error; } if (!WinHttpAddRequestHeaders(s->request, ct, (ULONG)-1L, WINHTTP_ADDREQ_FLAG_ADD | WINHTTP_ADDREQ_FLAG_REPLACE)) { - giterr_set(GITERR_OS, "Failed to add a header to the request"); + giterr_set(GITERR_OS, "failed to add a header to the request"); goto on_error; } @@ -511,13 +514,13 @@ static int winhttp_stream_connect(winhttp_stream *s) goto on_error; if (git__utf8_to_16(ct, MAX_CONTENT_TYPE_LEN, git_buf_cstr(&buf)) < 0) { - giterr_set(GITERR_OS, "Failed to convert accept header to wide characters"); + giterr_set(GITERR_OS, "failed to convert accept header to wide characters"); goto on_error; } if (!WinHttpAddRequestHeaders(s->request, ct, (ULONG)-1L, WINHTTP_ADDREQ_FLAG_ADD | WINHTTP_ADDREQ_FLAG_REPLACE)) { - giterr_set(GITERR_OS, "Failed to add a header to the request"); + giterr_set(GITERR_OS, "failed to add a header to the request"); goto on_error; } } @@ -527,13 +530,13 @@ static int winhttp_stream_connect(winhttp_stream *s) git_buf_clear(&buf); git_buf_puts(&buf, t->owner->custom_headers.strings[i]); if (git__utf8_to_16(ct, MAX_CONTENT_TYPE_LEN, git_buf_cstr(&buf)) < 0) { - giterr_set(GITERR_OS, "Failed to convert custom header to wide characters"); + giterr_set(GITERR_OS, "failed to convert custom header to wide characters"); goto on_error; } if (!WinHttpAddRequestHeaders(s->request, ct, (ULONG)-1L, WINHTTP_ADDREQ_FLAG_ADD | WINHTTP_ADDREQ_FLAG_REPLACE)) { - giterr_set(GITERR_OS, "Failed to add a header to the request"); + giterr_set(GITERR_OS, "failed to add a header to the request"); goto on_error; } } @@ -550,13 +553,11 @@ static int winhttp_stream_connect(winhttp_stream *s) /* If we have a credential on the subtransport, apply it to the request */ if (t->cred && t->cred->credtype == GIT_CREDTYPE_USERPASS_PLAINTEXT && - t->auth_mechanism == GIT_WINHTTP_AUTH_BASIC && - apply_basic_credential(s->request, t->cred) < 0) + apply_userpass_credential(s->request, t->auth_mechanisms, t->cred) < 0) goto on_error; else if (t->cred && t->cred->credtype == GIT_CREDTYPE_DEFAULT && - t->auth_mechanism == GIT_WINHTTP_AUTH_NEGOTIATE && - apply_default_credentials(s->request) < 0) + apply_default_credentials(s->request, t->auth_mechanisms) < 0) goto on_error; /* If no other credentials have been applied and the URL has username and @@ -565,7 +566,7 @@ static int winhttp_stream_connect(winhttp_stream *s) if (!t->url_cred && git_cred_userpass_plaintext_new(&t->url_cred, t->connection_data.user, t->connection_data.pass) < 0) goto on_error; - if (apply_basic_credential(s->request, t->url_cred) < 0) + if (apply_userpass_credential(s->request, GIT_WINHTTP_AUTH_BASIC, t->url_cred) < 0) goto on_error; } @@ -585,30 +586,40 @@ on_error: static int parse_unauthorized_response( HINTERNET request, int *allowed_types, - int *auth_mechanism) + int *allowed_mechanisms) { DWORD supported, first, target; *allowed_types = 0; - *auth_mechanism = 0; + *allowed_mechanisms = 0; - /* WinHttpQueryHeaders() must be called before WinHttpQueryAuthSchemes(). - * We can assume this was already done, since we know we are unauthorized. + /* WinHttpQueryHeaders() must be called before WinHttpQueryAuthSchemes(). + * We can assume this was already done, since we know we are unauthorized. */ if (!WinHttpQueryAuthSchemes(request, &supported, &first, &target)) { - giterr_set(GITERR_OS, "Failed to parse supported auth schemes"); + giterr_set(GITERR_OS, "failed to parse supported auth schemes"); return -1; } + if (WINHTTP_AUTH_SCHEME_NTLM & supported) { + *allowed_types |= GIT_CREDTYPE_USERPASS_PLAINTEXT; + *allowed_types |= GIT_CREDTYPE_DEFAULT; + *allowed_mechanisms = GIT_WINHTTP_AUTH_NEGOTIATE; + } + + if (WINHTTP_AUTH_SCHEME_NEGOTIATE & supported) { + *allowed_types |= GIT_CREDTYPE_DEFAULT; + *allowed_mechanisms = GIT_WINHTTP_AUTH_NEGOTIATE; + } + if (WINHTTP_AUTH_SCHEME_BASIC & supported) { *allowed_types |= GIT_CREDTYPE_USERPASS_PLAINTEXT; - *auth_mechanism = GIT_WINHTTP_AUTH_BASIC; + *allowed_mechanisms |= GIT_WINHTTP_AUTH_BASIC; } - if ((WINHTTP_AUTH_SCHEME_NTLM & supported) || - (WINHTTP_AUTH_SCHEME_NEGOTIATE & supported)) { - *allowed_types |= GIT_CREDTYPE_DEFAULT; - *auth_mechanism = GIT_WINHTTP_AUTH_NEGOTIATE; + if (WINHTTP_AUTH_SCHEME_DIGEST & supported) { + *allowed_types |= GIT_CREDTYPE_USERPASS_PLAINTEXT; + *allowed_mechanisms |= GIT_WINHTTP_AUTH_DIGEST; } return 0; @@ -629,7 +640,7 @@ static int write_chunk(HINTERNET request, const char *buffer, size_t len) git_buf_cstr(&buf), (DWORD)git_buf_len(&buf), &bytes_written)) { git_buf_free(&buf); - giterr_set(GITERR_OS, "Failed to write chunk header"); + giterr_set(GITERR_OS, "failed to write chunk header"); return -1; } @@ -639,7 +650,7 @@ static int write_chunk(HINTERNET request, const char *buffer, size_t len) if (!WinHttpWriteData(request, buffer, (DWORD)len, &bytes_written)) { - giterr_set(GITERR_OS, "Failed to write chunk"); + giterr_set(GITERR_OS, "failed to write chunk"); return -1; } @@ -647,7 +658,7 @@ static int write_chunk(HINTERNET request, const char *buffer, size_t len) if (!WinHttpWriteData(request, "\r\n", 2, &bytes_written)) { - giterr_set(GITERR_OS, "Failed to write chunk footer"); + giterr_set(GITERR_OS, "failed to write chunk footer"); return -1; } @@ -660,7 +671,7 @@ static int winhttp_close_connection(winhttp_subtransport *t) if (t->connection) { if (!WinHttpCloseHandle(t->connection)) { - giterr_set(GITERR_OS, "Unable to close connection"); + giterr_set(GITERR_OS, "unable to close connection"); ret = -1; } @@ -669,7 +680,7 @@ static int winhttp_close_connection(winhttp_subtransport *t) if (t->session) { if (!WinHttpCloseHandle(t->session)) { - giterr_set(GITERR_OS, "Unable to close session"); + giterr_set(GITERR_OS, "unable to close session"); ret = -1; } @@ -694,6 +705,38 @@ static int user_agent(git_buf *ua) return git_buf_putc(ua, ')'); } +static void CALLBACK winhttp_status( + HINTERNET connection, + DWORD_PTR ctx, + DWORD code, + LPVOID info, + DWORD info_len) +{ + DWORD status; + + if (code != WINHTTP_CALLBACK_STATUS_SECURE_FAILURE) + return; + + status = *((DWORD *)info); + + if ((status & WINHTTP_CALLBACK_STATUS_FLAG_CERT_CN_INVALID)) + giterr_set(GITERR_NET, "SSL certificate issued for different common name"); + else if ((status & WINHTTP_CALLBACK_STATUS_FLAG_CERT_DATE_INVALID)) + giterr_set(GITERR_NET, "SSL certificate has expired"); + else if ((status & WINHTTP_CALLBACK_STATUS_FLAG_INVALID_CA)) + giterr_set(GITERR_NET, "SSL certificate signed by unknown CA"); + else if ((status & WINHTTP_CALLBACK_STATUS_FLAG_INVALID_CERT)) + giterr_set(GITERR_NET, "SSL certificate is invalid"); + else if ((status & WINHTTP_CALLBACK_STATUS_FLAG_CERT_REV_FAILED)) + giterr_set(GITERR_NET, "certificate revocation check failed"); + else if ((status & WINHTTP_CALLBACK_STATUS_FLAG_CERT_REVOKED)) + giterr_set(GITERR_NET, "SSL certificate was revoked"); + else if ((status & WINHTTP_CALLBACK_STATUS_FLAG_SECURITY_CHANNEL_ERROR)) + giterr_set(GITERR_NET, "security libraries could not be loaded"); + else + giterr_set(GITERR_NET, "unknown security error %d", status); +} + static int winhttp_connect( winhttp_subtransport *t) { @@ -714,7 +757,7 @@ static int winhttp_connect( /* Prepare host */ if (git__utf8_to_16_alloc(&wide_host, t->connection_data.host) < 0) { - giterr_set(GITERR_OS, "Unable to convert host to wide characters"); + giterr_set(GITERR_OS, "unable to convert host to wide characters"); return -1; } @@ -724,7 +767,7 @@ static int winhttp_connect( } if (git__utf8_to_16_alloc(&wide_ua, git_buf_cstr(&ua)) < 0) { - giterr_set(GITERR_OS, "Unable to convert host to wide characters"); + giterr_set(GITERR_OS, "unable to convert host to wide characters"); git__free(wide_host); git_buf_free(&ua); return -1; @@ -741,16 +784,16 @@ static int winhttp_connect( 0); if (!t->session) { - giterr_set(GITERR_OS, "Failed to init WinHTTP"); + giterr_set(GITERR_OS, "failed to init WinHTTP"); goto on_error; } if (!WinHttpSetTimeouts(t->session, default_timeout, default_connect_timeout, default_timeout, default_timeout)) { - giterr_set(GITERR_OS, "Failed to set timeouts for WinHTTP"); + giterr_set(GITERR_OS, "failed to set timeouts for WinHTTP"); goto on_error; } - + /* Establish connection */ t->connection = WinHttpConnect( t->session, @@ -759,7 +802,12 @@ static int winhttp_connect( 0); if (!t->connection) { - giterr_set(GITERR_OS, "Failed to connect to host"); + giterr_set(GITERR_OS, "failed to connect to host"); + goto on_error; + } + + if (WinHttpSetStatusCallback(t->connection, winhttp_status, WINHTTP_CALLBACK_FLAG_SECURE_FAILURE, 0) == WINHTTP_INVALID_STATUS_CALLBACK) { + giterr_set(GITERR_OS, "failed to set status callback"); goto on_error; } @@ -801,16 +849,15 @@ static int send_request(winhttp_stream *s, size_t len, int ignore_length) int request_failed = 0, cert_valid = 1, error = 0; DWORD ignore_flags; - if ((error = do_send_request(s, len, ignore_length)) < 0) - request_failed = 1; - - if (request_failed) { + giterr_clear(); + if ((error = do_send_request(s, len, ignore_length)) < 0) { if (GetLastError() != ERROR_WINHTTP_SECURE_FAILURE) { giterr_set(GITERR_OS, "failed to send request"); return -1; - } else { - cert_valid = 0; } + + request_failed = 1; + cert_valid = 0; } giterr_clear(); @@ -826,14 +873,14 @@ static int send_request(winhttp_stream *s, size_t len, int ignore_length) return 0; ignore_flags = no_check_cert_flags; - + if (!WinHttpSetOption(s->request, WINHTTP_OPTION_SECURITY_FLAGS, &ignore_flags, sizeof(ignore_flags))) { giterr_set(GITERR_OS, "failed to set security options"); return -1; } if ((error = do_send_request(s, len, ignore_length)) < 0) - giterr_set(GITERR_OS, "failed to send request"); + giterr_set(GITERR_OS, "failed to send request with unchecked certificate"); return error; } @@ -853,7 +900,7 @@ static int winhttp_stream_read( replay: /* Enforce a reasonable cap on the number of replays */ if (++replay_count >= 7) { - giterr_set(GITERR_NET, "Too many redirects or authentication replays"); + giterr_set(GITERR_NET, "too many redirects or authentication replays"); return -1; } @@ -888,7 +935,7 @@ replay: if (!WinHttpWriteData(s->request, "0\r\n\r\n", 5, &bytes_written)) { - giterr_set(GITERR_OS, "Failed to write final chunk"); + giterr_set(GITERR_OS, "failed to write final chunk"); return -1; } } @@ -899,7 +946,7 @@ replay: if (INVALID_SET_FILE_POINTER == SetFilePointer(s->post_body, 0, 0, FILE_BEGIN) && NO_ERROR != GetLastError()) { - giterr_set(GITERR_OS, "Failed to reset file pointer"); + giterr_set(GITERR_OS, "failed to reset file pointer"); return -1; } @@ -913,14 +960,14 @@ replay: &bytes_read, NULL) || !bytes_read) { git__free(buffer); - giterr_set(GITERR_OS, "Failed to read from temp file"); + giterr_set(GITERR_OS, "failed to read from temp file"); return -1; } if (!WinHttpWriteData(s->request, buffer, bytes_read, &bytes_written)) { git__free(buffer); - giterr_set(GITERR_OS, "Failed to write data"); + giterr_set(GITERR_OS, "failed to write data"); return -1; } @@ -936,7 +983,7 @@ replay: } if (!WinHttpReceiveResponse(s->request, 0)) { - giterr_set(GITERR_OS, "Failed to receive response"); + giterr_set(GITERR_OS, "failed to receive response"); return -1; } @@ -948,7 +995,7 @@ replay: WINHTTP_HEADER_NAME_BY_INDEX, &status_code, &status_code_length, WINHTTP_NO_HEADER_INDEX)) { - giterr_set(GITERR_OS, "Failed to retrieve status code"); + giterr_set(GITERR_OS, "failed to retrieve status code"); return -1; } @@ -978,7 +1025,7 @@ replay: &location_length, WINHTTP_NO_HEADER_INDEX) || GetLastError() != ERROR_INSUFFICIENT_BUFFER) { - giterr_set(GITERR_OS, "Failed to read Location header"); + giterr_set(GITERR_OS, "failed to read Location header"); return -1; } @@ -991,14 +1038,14 @@ replay: location, &location_length, WINHTTP_NO_HEADER_INDEX)) { - giterr_set(GITERR_OS, "Failed to read Location header"); + giterr_set(GITERR_OS, "failed to read Location header"); git__free(location); return -1; } /* Convert the Location header to UTF-8 */ if (git__utf16_to_8_alloc(&location8, location) < 0) { - giterr_set(GITERR_OS, "Failed to convert Location header to UTF-8"); + giterr_set(GITERR_OS, "failed to convert Location header to UTF-8"); git__free(location); return -1; } @@ -1029,13 +1076,13 @@ replay: if (status_code == HTTP_STATUS_PROXY_AUTH_REQ) { int allowed_types; - if (parse_unauthorized_response(s->request, &allowed_types, &t->auth_mechanism) < 0) + if (parse_unauthorized_response(s->request, &allowed_types, &t->auth_mechanisms) < 0) return -1; /* TODO: extract the username from the url, no payload? */ if (t->owner->proxy.credentials) { int cred_error = 1; - cred_error = t->owner->proxy.credentials(&t->proxy_cred, t->owner->proxy.url, NULL, allowed_types, NULL); + cred_error = t->owner->proxy.credentials(&t->proxy_cred, t->owner->proxy.url, NULL, allowed_types, t->owner->proxy.payload); if (cred_error < 0) return cred_error; @@ -1049,7 +1096,7 @@ replay: if (HTTP_STATUS_DENIED == status_code && get_verb == s->verb) { int allowed_types; - if (parse_unauthorized_response(s->request, &allowed_types, &t->auth_mechanism) < 0) + if (parse_unauthorized_response(s->request, &allowed_types, &t->auth_mechanisms) < 0) return -1; if (allowed_types) { @@ -1090,7 +1137,7 @@ replay: } if (HTTP_STATUS_OK != status_code) { - giterr_set(GITERR_NET, "Request failed with status code: %d", status_code); + giterr_set(GITERR_NET, "request failed with status code: %d", status_code); return -1; } @@ -1101,7 +1148,7 @@ replay: p_snprintf(expected_content_type_8, MAX_CONTENT_TYPE_LEN, "application/x-git-%s-advertisement", s->service); if (git__utf8_to_16(expected_content_type, MAX_CONTENT_TYPE_LEN, expected_content_type_8) < 0) { - giterr_set(GITERR_OS, "Failed to convert expected content-type to wide characters"); + giterr_set(GITERR_OS, "failed to convert expected content-type to wide characters"); return -1; } @@ -1112,12 +1159,12 @@ replay: WINHTTP_HEADER_NAME_BY_INDEX, &content_type, &content_type_length, WINHTTP_NO_HEADER_INDEX)) { - giterr_set(GITERR_OS, "Failed to retrieve response content-type"); + giterr_set(GITERR_OS, "failed to retrieve response content-type"); return -1; } if (wcscmp(expected_content_type, content_type)) { - giterr_set(GITERR_NET, "Received unexpected content-type"); + giterr_set(GITERR_NET, "received unexpected content-type"); return -1; } @@ -1129,7 +1176,7 @@ replay: (DWORD)buf_size, &dw_bytes_read)) { - giterr_set(GITERR_OS, "Failed to read data"); + giterr_set(GITERR_OS, "failed to read data"); return -1; } @@ -1152,7 +1199,7 @@ static int winhttp_stream_write_single( /* This implementation of write permits only a single call. */ if (s->sent_request) { - giterr_set(GITERR_NET, "Subtransport configured for only one write"); + giterr_set(GITERR_NET, "subtransport configured for only one write"); return -1; } @@ -1165,7 +1212,7 @@ static int winhttp_stream_write_single( (LPCVOID)buffer, (DWORD)len, &bytes_written)) { - giterr_set(GITERR_OS, "Failed to write data"); + giterr_set(GITERR_OS, "failed to write data"); return -1; } @@ -1183,12 +1230,12 @@ static int put_uuid_string(LPWSTR buffer, size_t buffer_len_cch) if (RPC_S_OK != status && RPC_S_UUID_LOCAL_ONLY != status && RPC_S_UUID_NO_ADDRESS != status) { - giterr_set(GITERR_NET, "Unable to generate name for temp file"); + giterr_set(GITERR_NET, "unable to generate name for temp file"); return -1; } if (buffer_len_cch < UUID_LENGTH_CCH + 1) { - giterr_set(GITERR_NET, "Buffer too small for name of temp file"); + giterr_set(GITERR_NET, "buffer too small for name of temp file"); return -1; } @@ -1203,7 +1250,7 @@ static int put_uuid_string(LPWSTR buffer, size_t buffer_len_cch) uuid.Data4[4], uuid.Data4[5], uuid.Data4[6], uuid.Data4[7]); if (result < UUID_LENGTH_CCH) { - giterr_set(GITERR_OS, "Unable to generate name for temp file"); + giterr_set(GITERR_OS, "unable to generate name for temp file"); return -1; } @@ -1215,7 +1262,7 @@ static int get_temp_file(LPWSTR buffer, DWORD buffer_len_cch) size_t len; if (!GetTempPathW(buffer_len_cch, buffer)) { - giterr_set(GITERR_OS, "Failed to get temp path"); + giterr_set(GITERR_OS, "failed to get temp path"); return -1; } @@ -1258,13 +1305,13 @@ static int winhttp_stream_write_buffered( if (INVALID_HANDLE_VALUE == s->post_body) { s->post_body = NULL; - giterr_set(GITERR_OS, "Failed to create temporary file"); + giterr_set(GITERR_OS, "failed to create temporary file"); return -1; } } if (!WriteFile(s->post_body, buffer, (DWORD)len, &bytes_written, NULL)) { - giterr_set(GITERR_OS, "Failed to write to temporary file"); + giterr_set(GITERR_OS, "failed to write to temporary file"); return -1; } @@ -1291,7 +1338,7 @@ static int winhttp_stream_write_chunked( if (!WinHttpAddRequestHeaders(s->request, transfer_encoding, (ULONG) -1L, WINHTTP_ADDREQ_FLAG_ADD)) { - giterr_set(GITERR_OS, "Failed to add a header to the request"); + giterr_set(GITERR_OS, "failed to add a header to the request"); return -1; } diff --git a/src/tree-cache.c b/src/tree-cache.c index b37be0f0d..548054136 100644 --- a/src/tree-cache.c +++ b/src/tree-cache.c @@ -137,7 +137,7 @@ static int read_tree_internal(git_tree_cache **out, return 0; corrupted: - giterr_set(GITERR_INDEX, "Corrupted TREE extension in index"); + giterr_set(GITERR_INDEX, "corrupted TREE extension in index"); return -1; } @@ -149,7 +149,7 @@ int git_tree_cache_read(git_tree_cache **tree, const char *buffer, size_t buffer return -1; if (buffer < buffer_end) { - giterr_set(GITERR_INDEX, "Corrupted TREE extension in index (unexpected trailing data)"); + giterr_set(GITERR_INDEX, "corrupted TREE extension in index (unexpected trailing data)"); return -1; } diff --git a/src/tree.c b/src/tree.c index 9655ad739..6b1d1b238 100644 --- a/src/tree.c +++ b/src/tree.c @@ -20,8 +20,6 @@ #define TREE_ENTRY_CHECK_NAMELEN(n) \ if (n > UINT16_MAX) { giterr_set(GITERR_INVALID, "tree entry path too long"); } -GIT__USE_STRMAP - static bool valid_filemode(const int filemode) { return (filemode == GIT_FILEMODE_TREE @@ -505,7 +503,7 @@ static int append_entry( entry->attr = (uint16_t)filemode; - git_strmap_insert(bld->map, entry->filename, entry, error); + git_strmap_insert(bld->map, entry->filename, entry, &error); if (error < 0) { git_tree_entry_free(entry); giterr_set(GITERR_TREE, "failed to append entry %s to the tree builder", filename); @@ -520,7 +518,8 @@ static int write_tree( git_repository *repo, git_index *index, const char *dirname, - size_t start) + size_t start, + git_buf *shared_buf) { git_treebuilder *bld = NULL; size_t i, entries = git_index_entrycount(index); @@ -573,7 +572,7 @@ static int write_tree( GITERR_CHECK_ALLOC(subdir); /* Write out the subtree */ - written = write_tree(&sub_oid, repo, index, subdir, i); + written = write_tree(&sub_oid, repo, index, subdir, i, shared_buf); if (written < 0) { git__free(subdir); goto on_error; @@ -605,7 +604,7 @@ static int write_tree( } } - if (git_treebuilder_write(oid, bld) < 0) + if (git_treebuilder_write_with_buffer(oid, bld, shared_buf) < 0) goto on_error; git_treebuilder_free(bld); @@ -621,13 +620,14 @@ int git_tree__write_index( { int ret; git_tree *tree; + git_buf shared_buf = GIT_BUF_INIT; bool old_ignore_case = false; assert(oid && index && repo); if (git_index_has_conflicts(index)) { giterr_set(GITERR_INDEX, - "Cannot create a tree from a not fully merged index."); + "cannot create a tree from a not fully merged index."); return GIT_EUNMERGED; } @@ -646,7 +646,8 @@ int git_tree__write_index( git_index__set_ignore_case(index, false); } - ret = write_tree(oid, repo, index, "", 0); + ret = write_tree(oid, repo, index, "", 0, &shared_buf); + git_buf_free(&shared_buf); if (old_ignore_case) git_index__set_ignore_case(index, true); @@ -751,7 +752,7 @@ int git_treebuilder_insert( entry = alloc_entry(filename, strlen(filename), id); GITERR_CHECK_ALLOC(entry); - git_strmap_insert(bld->map, entry->filename, entry, error); + git_strmap_insert(bld->map, entry->filename, entry, &error); if (error < 0) { git_tree_entry_free(entry); @@ -801,47 +802,61 @@ int git_treebuilder_remove(git_treebuilder *bld, const char *filename) } int git_treebuilder_write(git_oid *oid, git_treebuilder *bld) +{ + int error; + git_buf buffer = GIT_BUF_INIT; + + error = git_treebuilder_write_with_buffer(oid, bld, &buffer); + + git_buf_free(&buffer); + return error; +} + +int git_treebuilder_write_with_buffer(git_oid *oid, git_treebuilder *bld, git_buf *tree) { int error = 0; size_t i, entrycount; - git_buf tree = GIT_BUF_INIT; git_odb *odb; git_tree_entry *entry; - git_vector entries; + git_vector entries = GIT_VECTOR_INIT; assert(bld); + assert(tree); + + git_buf_clear(tree); entrycount = git_strmap_num_entries(bld->map); - if (git_vector_init(&entries, entrycount, entry_sort_cmp) < 0) - return -1; + if ((error = git_vector_init(&entries, entrycount, entry_sort_cmp)) < 0) + goto out; + + if (tree->asize == 0 && + (error = git_buf_grow(tree, entrycount * 72)) < 0) + goto out; git_strmap_foreach_value(bld->map, entry, { - if (git_vector_insert(&entries, entry) < 0) - return -1; + if ((error = git_vector_insert(&entries, entry)) < 0) + goto out; }); git_vector_sort(&entries); - /* Grow the buffer beforehand to an estimated size */ - error = git_buf_grow(&tree, entrycount * 72); - for (i = 0; i < entries.length && !error; ++i) { - git_tree_entry *entry = git_vector_get(&entries, i); + entry = git_vector_get(&entries, i); - git_buf_printf(&tree, "%o ", entry->attr); - git_buf_put(&tree, entry->filename, entry->filename_len + 1); - git_buf_put(&tree, (char *)entry->oid->id, GIT_OID_RAWSZ); + git_buf_printf(tree, "%o ", entry->attr); + git_buf_put(tree, entry->filename, entry->filename_len + 1); + git_buf_put(tree, (char *)entry->oid->id, GIT_OID_RAWSZ); - if (git_buf_oom(&tree)) + if (git_buf_oom(tree)) { error = -1; + goto out; + } } + if ((error = git_repository_odb__weakptr(&odb, bld->repo)) == 0) + error = git_odb_write(oid, odb, tree->ptr, tree->size, GIT_OBJ_TREE); - if (!error && - !(error = git_repository_odb__weakptr(&odb, bld->repo))) - error = git_odb_write(oid, odb, tree.ptr, tree.size, GIT_OBJ_TREE); - - git_buf_free(&tree); +out: git_vector_free(&entries); return error; @@ -909,7 +924,7 @@ int git_tree_entry_bypath( filename_len = subpath_len(path); if (filename_len == 0) { - giterr_set(GITERR_TREE, "Invalid tree path given"); + giterr_set(GITERR_TREE, "invalid tree path given"); return GIT_ENOTFOUND; } @@ -1027,7 +1042,7 @@ int git_tree_walk( git_buf root_path = GIT_BUF_INIT; if (mode != GIT_TREEWALK_POST && mode != GIT_TREEWALK_PRE) { - giterr_set(GITERR_INVALID, "Invalid walking mode for tree walk"); + giterr_set(GITERR_INVALID, "invalid walking mode for tree walk"); return -1; } @@ -1237,7 +1252,7 @@ int git_tree_create_updated(git_oid *out, git_repository *repo, git_tree *baseli const git_tree_entry *e = git_treebuilder_get(last->bld, basename); if (e && git_tree_entry_type(e) != git_object__type_from_filemode(update->filemode)) { git__free(basename); - giterr_set(GITERR_TREE, "Cannot replace '%s' with '%s' at '%s'", + giterr_set(GITERR_TREE, "cannot replace '%s' with '%s' at '%s'", git_object_type2string(git_tree_entry_type(e)), git_object_type2string(git_object__type_from_filemode(update->filemode)), update->path); @@ -1257,7 +1272,7 @@ int git_tree_create_updated(git_oid *out, git_repository *repo, git_tree *baseli break; } default: - giterr_set(GITERR_TREE, "unkown action for update"); + giterr_set(GITERR_TREE, "unknown action for update"); error = -1; goto cleanup; } diff --git a/src/unix/map.c b/src/unix/map.c index c55ad1aa7..9d9b1fe38 100644 --- a/src/unix/map.c +++ b/src/unix/map.c @@ -52,7 +52,7 @@ int p_mmap(git_map *out, size_t len, int prot, int flags, int fd, git_off_t offs out->data = mmap(NULL, len, mprot, mflag, fd, offset); if (!out->data || out->data == MAP_FAILED) { - giterr_set(GITERR_OS, "Failed to mmap. Could not write data"); + giterr_set(GITERR_OS, "failed to mmap. Could not write data"); return -1; } diff --git a/src/unix/posix.h b/src/unix/posix.h index ad13291e8..52985fd8a 100644 --- a/src/unix/posix.h +++ b/src/unix/posix.h @@ -40,9 +40,14 @@ typedef int GIT_SOCKET; #define p_link(o,n) link(o, n) #define p_unlink(p) unlink(p) #define p_mkdir(p,m) mkdir(p, m) -#define p_fsync(fd) fsync(fd) extern char *p_realpath(const char *, char *); +GIT_INLINE(int) p_fsync(int fd) +{ + p_fsync__cnt++; + return fsync(fd); +} + #define p_recv(s,b,l,f) recv(s,b,l,f) #define p_send(s,b,l,f) send(s,b,l,f) #define p_inet_pton(a, b, c) inet_pton(a, b, c) @@ -50,7 +55,7 @@ extern char *p_realpath(const char *, char *); #define p_strcasecmp(s1, s2) strcasecmp(s1, s2) #define p_strncasecmp(s1, s2, c) strncasecmp(s1, s2, c) #define p_vsnprintf(b, c, f, a) vsnprintf(b, c, f, a) -#define p_snprintf(b, c, f, ...) snprintf(b, c, f, __VA_ARGS__) +#define p_snprintf(b, c, ...) snprintf(b, c, __VA_ARGS__) #define p_mkstemp(p) mkstemp(p) #define p_chdir(p) chdir(p) #define p_chmod(p,m) chmod(p, m) diff --git a/src/util.c b/src/util.c index 76ca711b2..a44f4c9ac 100644 --- a/src/util.c +++ b/src/util.c @@ -136,7 +136,7 @@ int git__strntol64(int64_t *result, const char *nptr, size_t nptr_len, const cha Return: if (ndig == 0) { - giterr_set(GITERR_INVALID, "Failed to convert string to long. Not a number"); + giterr_set(GITERR_INVALID, "failed to convert string to long: not a number"); return -1; } @@ -144,7 +144,7 @@ Return: *endptr = p; if (ovfl) { - giterr_set(GITERR_INVALID, "Failed to convert string to long. Overflow error"); + giterr_set(GITERR_INVALID, "failed to convert string to long: overflow error"); return -1; } @@ -169,7 +169,7 @@ int git__strntol32(int32_t *result, const char *nptr, size_t nptr_len, const cha tmp_int = tmp_long & 0xFFFFFFFF; if (tmp_int != tmp_long) { - giterr_set(GITERR_INVALID, "Failed to convert. '%s' is too large", nptr); + giterr_set(GITERR_INVALID, "failed to convert: '%s' is too large", nptr); return -1; } diff --git a/src/varint.c b/src/varint.c index 2f868607c..beac8c709 100644 --- a/src/varint.c +++ b/src/varint.c @@ -36,7 +36,7 @@ int git_encode_varint(unsigned char *buf, size_t bufsize, uintmax_t value) while (value >>= 7) varint[--pos] = 128 | (--value & 127); if (buf) { - if (bufsize < pos) + if (bufsize < (sizeof(varint) - pos)) return -1; memcpy(buf, varint + pos, sizeof(varint) - pos); } diff --git a/src/vector.c b/src/vector.c index baec8036f..620a1f56c 100644 --- a/src/vector.c +++ b/src/vector.c @@ -406,6 +406,9 @@ void git_vector_reverse(git_vector *v) { size_t a, b; + if (v->length == 0) + return; + a = 0; b = v->length - 1; diff --git a/src/win32/dir.c b/src/win32/dir.c index c15757085..8a724a4e9 100644 --- a/src/win32/dir.c +++ b/src/win32/dir.c @@ -28,7 +28,7 @@ git__DIR *git__opendir(const char *dir) new->h = FindFirstFileW(filter_w, &new->f); if (new->h == INVALID_HANDLE_VALUE) { - giterr_set(GITERR_OS, "Could not open directory '%s'", dir); + giterr_set(GITERR_OS, "could not open directory '%s'", dir); git__free(new); return NULL; } @@ -53,7 +53,7 @@ int git__readdir_ext( else if (!FindNextFileW(d->h, &d->f)) { if (GetLastError() == ERROR_NO_MORE_FILES) return 0; - giterr_set(GITERR_OS, "Could not read from directory '%s'", d->dir); + giterr_set(GITERR_OS, "could not read from directory '%s'", d->dir); return -1; } @@ -98,7 +98,7 @@ void git__rewinddir(git__DIR *d) d->h = FindFirstFileW(filter_w, &d->f); if (d->h == INVALID_HANDLE_VALUE) - giterr_set(GITERR_OS, "Could not open directory '%s'", d->dir); + giterr_set(GITERR_OS, "could not open directory '%s'", d->dir); else d->first = 1; } diff --git a/src/win32/findfile.c b/src/win32/findfile.c index 58c22279e..1c768f7f4 100644 --- a/src/win32/findfile.c +++ b/src/win32/findfile.c @@ -38,7 +38,7 @@ static int win32_path_to_8(git_buf *dest, const wchar_t *src) git_win32_utf8_path utf8_path; if (git_win32_path_to_utf8(utf8_path, src) < 0) { - giterr_set(GITERR_OS, "Unable to convert path to UTF-8"); + giterr_set(GITERR_OS, "unable to convert path to UTF-8"); return -1; } diff --git a/src/win32/map.c b/src/win32/map.c index 03a3646a6..5fcc1085b 100644 --- a/src/win32/map.c +++ b/src/win32/map.c @@ -67,7 +67,7 @@ int p_mmap(git_map *out, size_t len, int prot, int flags, int fd, git_off_t offs if (fh == INVALID_HANDLE_VALUE) { errno = EBADF; - giterr_set(GITERR_OS, "Failed to mmap. Invalid handle value"); + giterr_set(GITERR_OS, "failed to mmap. Invalid handle value"); return -1; } @@ -86,13 +86,13 @@ int p_mmap(git_map *out, size_t len, int prot, int flags, int fd, git_off_t offs if (page_offset != 0) { /* offset must be multiple of the allocation granularity */ errno = EINVAL; - giterr_set(GITERR_OS, "Failed to mmap. Offset must be multiple of allocation granularity"); + giterr_set(GITERR_OS, "failed to mmap. Offset must be multiple of allocation granularity"); return -1; } out->fmh = CreateFileMapping(fh, NULL, fmap_prot, 0, 0, NULL); if (!out->fmh || out->fmh == INVALID_HANDLE_VALUE) { - giterr_set(GITERR_OS, "Failed to mmap. Invalid handle value"); + giterr_set(GITERR_OS, "failed to mmap. Invalid handle value"); out->fmh = NULL; return -1; } @@ -103,7 +103,7 @@ int p_mmap(git_map *out, size_t len, int prot, int flags, int fd, git_off_t offs off_hi = (DWORD)(page_start >> 32); out->data = MapViewOfFile(out->fmh, view_prot, off_hi, off_low, len); if (!out->data) { - giterr_set(GITERR_OS, "Failed to mmap. No data written"); + giterr_set(GITERR_OS, "failed to mmap. No data written"); CloseHandle(out->fmh); out->fmh = NULL; return -1; @@ -121,7 +121,7 @@ int p_munmap(git_map *map) if (map->data) { if (!UnmapViewOfFile(map->data)) { - giterr_set(GITERR_OS, "Failed to munmap. Could not unmap view of file"); + giterr_set(GITERR_OS, "failed to munmap. Could not unmap view of file"); error = -1; } map->data = NULL; @@ -129,7 +129,7 @@ int p_munmap(git_map *map) if (map->fmh) { if (!CloseHandle(map->fmh)) { - giterr_set(GITERR_OS, "Failed to munmap. Could not close handle"); + giterr_set(GITERR_OS, "failed to munmap. Could not close handle"); error = -1; } map->fmh = NULL; diff --git a/src/win32/posix.h b/src/win32/posix.h index 73705fb2b..64769ecd3 100644 --- a/src/win32/posix.h +++ b/src/win32/posix.h @@ -14,6 +14,9 @@ #include "utf-conv.h" #include "dir.h" +extern unsigned long git_win32__createfile_sharemode; +extern int git_win32__retries; + typedef SOCKET GIT_SOCKET; #define p_lseek(f,n,w) _lseeki64(f, n, w) diff --git a/src/win32/posix_w32.c b/src/win32/posix_w32.c index fea634b00..e4fe4142c 100644 --- a/src/win32/posix_w32.c +++ b/src/win32/posix_w32.c @@ -26,15 +26,6 @@ #define IO_REPARSE_TAG_SYMLINK (0xA000000CL) #endif -/* Options which we always provide to _wopen. - * - * _O_BINARY - Raw access; no translation of CR or LF characters - * _O_NOINHERIT - Do not mark the created handle as inheritable by child processes. - * The Windows default is 'not inheritable', but the CRT's default (following - * POSIX convention) is 'inheritable'. We have no desire for our handles to be - * inheritable on Windows, so specify the flag to get default behavior back. */ -#define STANDARD_OPEN_FLAGS (_O_BINARY | _O_NOINHERIT) - /* Allowable mode bits on Win32. Using mode bits that are not supported on * Win32 (eg S_IRWXU) is generally ignored, but Wine warns loudly about it * so we simply remove them. @@ -44,6 +35,164 @@ /* GetFinalPathNameByHandleW signature */ typedef DWORD(WINAPI *PFGetFinalPathNameByHandleW)(HANDLE, LPWSTR, DWORD, DWORD); +unsigned long git_win32__createfile_sharemode = + FILE_SHARE_READ | FILE_SHARE_WRITE; +int git_win32__retries = 10; + +GIT_INLINE(void) set_errno(void) +{ + switch (GetLastError()) { + case ERROR_FILE_NOT_FOUND: + case ERROR_PATH_NOT_FOUND: + case ERROR_INVALID_DRIVE: + case ERROR_NO_MORE_FILES: + case ERROR_BAD_NETPATH: + case ERROR_BAD_NET_NAME: + case ERROR_BAD_PATHNAME: + case ERROR_FILENAME_EXCED_RANGE: + errno = ENOENT; + break; + case ERROR_BAD_ENVIRONMENT: + errno = E2BIG; + break; + case ERROR_BAD_FORMAT: + case ERROR_INVALID_STARTING_CODESEG: + case ERROR_INVALID_STACKSEG: + case ERROR_INVALID_MODULETYPE: + case ERROR_INVALID_EXE_SIGNATURE: + case ERROR_EXE_MARKED_INVALID: + case ERROR_BAD_EXE_FORMAT: + case ERROR_ITERATED_DATA_EXCEEDS_64k: + case ERROR_INVALID_MINALLOCSIZE: + case ERROR_DYNLINK_FROM_INVALID_RING: + case ERROR_IOPL_NOT_ENABLED: + case ERROR_INVALID_SEGDPL: + case ERROR_AUTODATASEG_EXCEEDS_64k: + case ERROR_RING2SEG_MUST_BE_MOVABLE: + case ERROR_RELOC_CHAIN_XEEDS_SEGLIM: + case ERROR_INFLOOP_IN_RELOC_CHAIN: + errno = ENOEXEC; + break; + case ERROR_INVALID_HANDLE: + case ERROR_INVALID_TARGET_HANDLE: + case ERROR_DIRECT_ACCESS_HANDLE: + errno = EBADF; + break; + case ERROR_WAIT_NO_CHILDREN: + case ERROR_CHILD_NOT_COMPLETE: + errno = ECHILD; + break; + case ERROR_NO_PROC_SLOTS: + case ERROR_MAX_THRDS_REACHED: + case ERROR_NESTING_NOT_ALLOWED: + errno = EAGAIN; + break; + case ERROR_ARENA_TRASHED: + case ERROR_NOT_ENOUGH_MEMORY: + case ERROR_INVALID_BLOCK: + case ERROR_NOT_ENOUGH_QUOTA: + errno = ENOMEM; + break; + case ERROR_ACCESS_DENIED: + case ERROR_CURRENT_DIRECTORY: + case ERROR_WRITE_PROTECT: + case ERROR_BAD_UNIT: + case ERROR_NOT_READY: + case ERROR_BAD_COMMAND: + case ERROR_CRC: + case ERROR_BAD_LENGTH: + case ERROR_SEEK: + case ERROR_NOT_DOS_DISK: + case ERROR_SECTOR_NOT_FOUND: + case ERROR_OUT_OF_PAPER: + case ERROR_WRITE_FAULT: + case ERROR_READ_FAULT: + case ERROR_GEN_FAILURE: + case ERROR_SHARING_VIOLATION: + case ERROR_LOCK_VIOLATION: + case ERROR_WRONG_DISK: + case ERROR_SHARING_BUFFER_EXCEEDED: + case ERROR_NETWORK_ACCESS_DENIED: + case ERROR_CANNOT_MAKE: + case ERROR_FAIL_I24: + case ERROR_DRIVE_LOCKED: + case ERROR_SEEK_ON_DEVICE: + case ERROR_NOT_LOCKED: + case ERROR_LOCK_FAILED: + errno = EACCES; + break; + case ERROR_FILE_EXISTS: + case ERROR_ALREADY_EXISTS: + errno = EEXIST; + break; + case ERROR_NOT_SAME_DEVICE: + errno = EXDEV; + break; + case ERROR_INVALID_FUNCTION: + case ERROR_INVALID_ACCESS: + case ERROR_INVALID_DATA: + case ERROR_INVALID_PARAMETER: + case ERROR_NEGATIVE_SEEK: + errno = EINVAL; + break; + case ERROR_TOO_MANY_OPEN_FILES: + errno = EMFILE; + break; + case ERROR_DISK_FULL: + errno = ENOSPC; + break; + case ERROR_BROKEN_PIPE: + errno = EPIPE; + break; + case ERROR_DIR_NOT_EMPTY: + errno = ENOTEMPTY; + break; + default: + errno = EINVAL; + } +} + +GIT_INLINE(bool) last_error_retryable(void) +{ + int os_error = GetLastError(); + + return (os_error == ERROR_SHARING_VIOLATION || + os_error == ERROR_ACCESS_DENIED); +} + +#define do_with_retries(fn, remediation) \ + do { \ + int __tries, __ret; \ + for (__tries = 0; __tries < git_win32__retries; __tries++) { \ + if (__tries && (__ret = (remediation)) != 0) \ + return __ret; \ + if ((__ret = (fn)) != GIT_RETRY) \ + return __ret; \ + Sleep(5); \ + } \ + return -1; \ + } while (0) \ + +static int ensure_writable(wchar_t *path) +{ + DWORD attrs; + + if ((attrs = GetFileAttributesW(path)) == INVALID_FILE_ATTRIBUTES) + goto on_error; + + if ((attrs & FILE_ATTRIBUTE_READONLY) == 0) + return 0; + + if (!SetFileAttributesW(path, (attrs & ~FILE_ATTRIBUTE_READONLY))) + goto on_error; + + return 0; + +on_error: + set_errno(); + return -1; +} + /** * Truncate or extend file. * @@ -89,30 +238,34 @@ int p_link(const char *old, const char *new) return -1; } +GIT_INLINE(int) unlink_once(const wchar_t *path) +{ + if (DeleteFileW(path)) + return 0; + + if (last_error_retryable()) + return GIT_RETRY; + + set_errno(); + return -1; +} + int p_unlink(const char *path) { - git_win32_path buf; - int error; + git_win32_path wpath; - if (git_win32_path_from_utf8(buf, path) < 0) + if (git_win32_path_from_utf8(wpath, path) < 0) return -1; - error = _wunlink(buf); - - /* If the file could not be deleted because it was - * read-only, clear the bit and try again */ - if (error == -1 && errno == EACCES) { - _wchmod(buf, 0666); - error = _wunlink(buf); - } - - return error; + do_with_retries(unlink_once(wpath), ensure_writable(wpath)); } int p_fsync(int fd) { HANDLE fh = (HANDLE)_get_osfhandle(fd); + p_fsync__cnt++; + if (fh == INVALID_HANDLE_VALUE) { errno = EBADF; return -1; @@ -210,44 +363,6 @@ int p_lstat_posixly(const char *filename, struct stat *buf) return do_lstat(filename, buf, true); } -int p_utimes(const char *filename, const struct p_timeval times[2]) -{ - int fd, error; - - if ((fd = p_open(filename, O_RDWR)) < 0) - return fd; - - error = p_futimes(fd, times); - - close(fd); - return error; -} - -int p_futimes(int fd, const struct p_timeval times[2]) -{ - HANDLE handle; - FILETIME atime = {0}, mtime = {0}; - - if (times == NULL) { - SYSTEMTIME st; - - GetSystemTime(&st); - SystemTimeToFileTime(&st, &atime); - SystemTimeToFileTime(&st, &mtime); - } else { - git_win32__timeval_to_filetime(&atime, times[0]); - git_win32__timeval_to_filetime(&mtime, times[1]); - } - - if ((handle = (HANDLE)_get_osfhandle(fd)) == INVALID_HANDLE_VALUE) - return -1; - - if (SetFileTime(handle, NULL, &atime, &mtime) == 0) - return -1; - - return 0; -} - int p_readlink(const char *path, char *buf, size_t bufsiz) { git_win32_path path_w, target_w; @@ -280,12 +395,91 @@ int p_symlink(const char *old, const char *new) return git_futils_fake_symlink(old, new); } +struct open_opts { + DWORD access; + DWORD sharing; + SECURITY_ATTRIBUTES security; + DWORD creation_disposition; + DWORD attributes; + int osf_flags; +}; + +GIT_INLINE(void) open_opts_from_posix(struct open_opts *opts, int flags, mode_t mode) +{ + memset(opts, 0, sizeof(struct open_opts)); + + switch (flags & (O_WRONLY | O_RDWR)) { + case O_WRONLY: + opts->access = GENERIC_WRITE; + break; + case O_RDWR: + opts->access = GENERIC_READ | GENERIC_WRITE; + break; + default: + opts->access = GENERIC_READ; + break; + } + + opts->sharing = (DWORD)git_win32__createfile_sharemode; + + switch (flags & (O_CREAT | O_TRUNC | O_EXCL)) { + case O_CREAT | O_EXCL: + case O_CREAT | O_TRUNC | O_EXCL: + opts->creation_disposition = CREATE_NEW; + break; + case O_CREAT | O_TRUNC: + opts->creation_disposition = CREATE_ALWAYS; + break; + case O_TRUNC: + opts->creation_disposition = TRUNCATE_EXISTING; + break; + case O_CREAT: + opts->creation_disposition = OPEN_ALWAYS; + break; + default: + opts->creation_disposition = OPEN_EXISTING; + break; + } + + opts->attributes = ((flags & O_CREAT) && !(mode & S_IWRITE)) ? + FILE_ATTRIBUTE_READONLY : FILE_ATTRIBUTE_NORMAL; + opts->osf_flags = flags & (O_RDONLY | O_APPEND); + + opts->security.nLength = sizeof(SECURITY_ATTRIBUTES); + opts->security.lpSecurityDescriptor = NULL; + opts->security.bInheritHandle = 0; +} + +GIT_INLINE(int) open_once( + const wchar_t *path, + struct open_opts *opts) +{ + int fd; + + HANDLE handle = CreateFileW(path, opts->access, opts->sharing, + &opts->security, opts->creation_disposition, opts->attributes, 0); + + if (handle == INVALID_HANDLE_VALUE) { + if (last_error_retryable()) + return GIT_RETRY; + + set_errno(); + return -1; + } + + if ((fd = _open_osfhandle((intptr_t)handle, opts->osf_flags)) < 0) + CloseHandle(handle); + + return fd; +} + int p_open(const char *path, int flags, ...) { - git_win32_path buf; + git_win32_path wpath; mode_t mode = 0; + struct open_opts opts = {0}; - if (git_win32_path_from_utf8(buf, path) < 0) + if (git_win32_path_from_utf8(wpath, path) < 0) return -1; if (flags & O_CREAT) { @@ -296,19 +490,83 @@ int p_open(const char *path, int flags, ...) va_end(arg_list); } - return _wopen(buf, flags | STANDARD_OPEN_FLAGS, mode & WIN32_MODE_MASK); + open_opts_from_posix(&opts, flags, mode); + + do_with_retries( + open_once(wpath, &opts), + 0); } int p_creat(const char *path, mode_t mode) { - git_win32_path buf; + return p_open(path, O_WRONLY | O_CREAT | O_TRUNC, mode); +} - if (git_win32_path_from_utf8(buf, path) < 0) +int p_utimes(const char *path, const struct p_timeval times[2]) +{ + git_win32_path wpath; + int fd, error; + DWORD attrs_orig, attrs_new = 0; + struct open_opts opts = { 0 }; + + if (git_win32_path_from_utf8(wpath, path) < 0) return -1; - return _wopen(buf, - _O_WRONLY | _O_CREAT | _O_TRUNC | STANDARD_OPEN_FLAGS, - mode & WIN32_MODE_MASK); + attrs_orig = GetFileAttributesW(wpath); + + if (attrs_orig & FILE_ATTRIBUTE_READONLY) { + attrs_new = attrs_orig & ~FILE_ATTRIBUTE_READONLY; + + if (!SetFileAttributesW(wpath, attrs_new)) { + giterr_set(GITERR_OS, "failed to set attributes"); + return -1; + } + } + + open_opts_from_posix(&opts, O_RDWR, 0); + + if ((fd = open_once(wpath, &opts)) < 0) { + error = -1; + goto done; + } + + error = p_futimes(fd, times); + close(fd); + +done: + if (attrs_orig != attrs_new) { + DWORD os_error = GetLastError(); + SetFileAttributesW(wpath, attrs_orig); + SetLastError(os_error); + } + + return error; +} + +int p_futimes(int fd, const struct p_timeval times[2]) +{ + HANDLE handle; + FILETIME atime = { 0 }, mtime = { 0 }; + + if (times == NULL) { + SYSTEMTIME st; + + GetSystemTime(&st); + SystemTimeToFileTime(&st, &atime); + SystemTimeToFileTime(&st, &mtime); + } + else { + git_win32__timeval_to_filetime(&atime, times[0]); + git_win32__timeval_to_filetime(&mtime, times[1]); + } + + if ((handle = (HANDLE)_get_osfhandle(fd)) == INVALID_HANDLE_VALUE) + return -1; + + if (SetFileTime(handle, NULL, &atime, &mtime) == 0) + return -1; + + return 0; } int p_getcwd(char *buffer_out, size_t size) @@ -581,62 +839,27 @@ int p_access(const char* path, mode_t mode) return _waccess(buf, mode & WIN32_MODE_MASK); } -static int ensure_writable(wchar_t *fpath) +GIT_INLINE(int) rename_once(const wchar_t *from, const wchar_t *to) { - DWORD attrs; - - attrs = GetFileAttributesW(fpath); - if (attrs == INVALID_FILE_ATTRIBUTES) { - if (GetLastError() == ERROR_FILE_NOT_FOUND) - return 0; - - giterr_set(GITERR_OS, "failed to get attributes"); - return -1; - } - - if (!(attrs & FILE_ATTRIBUTE_READONLY)) + if (MoveFileExW(from, to, MOVEFILE_REPLACE_EXISTING | MOVEFILE_COPY_ALLOWED)) return 0; - attrs &= ~FILE_ATTRIBUTE_READONLY; - if (!SetFileAttributesW(fpath, attrs)) { - giterr_set(GITERR_OS, "failed to set attributes"); - return -1; - } + if (last_error_retryable()) + return GIT_RETRY; - return 0; + set_errno(); + return -1; } int p_rename(const char *from, const char *to) { - git_win32_path wfrom; - git_win32_path wto; - int rename_tries; - int rename_succeeded; - int error; + git_win32_path wfrom, wto; if (git_win32_path_from_utf8(wfrom, from) < 0 || git_win32_path_from_utf8(wto, to) < 0) return -1; - /* wait up to 50ms if file is locked by another thread or process */ - rename_tries = 0; - rename_succeeded = 0; - while (rename_tries < 10) { - if (ensure_writable(wto) == 0 && - MoveFileExW(wfrom, wto, MOVEFILE_REPLACE_EXISTING | MOVEFILE_COPY_ALLOWED) != 0) { - rename_succeeded = 1; - break; - } - - error = GetLastError(); - if (error == ERROR_SHARING_VIOLATION || error == ERROR_ACCESS_DENIED) { - Sleep(5); - rename_tries++; - } else - break; - } - - return rename_succeeded ? 0 : -1; + do_with_retries(rename_once(wfrom, wto), ensure_writable(wto)); } int p_recv(GIT_SOCKET socket, void *buffer, size_t length, int flags) diff --git a/src/win32/w32_crtdbg_stacktrace.c b/src/win32/w32_crtdbg_stacktrace.c index a778f4164..2dbdaf45b 100644 --- a/src/win32/w32_crtdbg_stacktrace.c +++ b/src/win32/w32_crtdbg_stacktrace.c @@ -253,11 +253,11 @@ int git_win32__crtdbg_stacktrace__dump( bool b_quiet = IS_BIT_SET(opt, GIT_WIN32__CRTDBG_STACKTRACE__QUIET); if (b_leaks_since_mark && b_leaks_total) { - giterr_set(GITERR_INVALID, "Cannot combine LEAKS_SINCE_MARK and LEAKS_TOTAL."); + giterr_set(GITERR_INVALID, "cannot combine LEAKS_SINCE_MARK and LEAKS_TOTAL."); return GIT_ERROR; } if (!b_set_mark && !b_leaks_since_mark && !b_leaks_total) { - giterr_set(GITERR_INVALID, "Nothing to do."); + giterr_set(GITERR_INVALID, "nothing to do."); return GIT_ERROR; } diff --git a/src/win32/w32_util.c b/src/win32/w32_util.c index 60311bb50..b7b1ffa10 100644 --- a/src/win32/w32_util.c +++ b/src/win32/w32_util.c @@ -68,7 +68,7 @@ int git_win32__set_hidden(const char *path, bool hidden) newattrs = attrs & ~FILE_ATTRIBUTE_HIDDEN; if (attrs != newattrs && !SetFileAttributesW(buf, newattrs)) { - giterr_set(GITERR_OS, "Failed to %s hidden bit for '%s'", + giterr_set(GITERR_OS, "failed to %s hidden bit for '%s'", hidden ? "set" : "unset", path); return -1; } diff --git a/src/win32/w32_util.h b/src/win32/w32_util.h index 784a7a04c..77973b502 100644 --- a/src/win32/w32_util.h +++ b/src/win32/w32_util.h @@ -174,7 +174,7 @@ GIT_INLINE(int) git_win32__file_attribute_to_stat( /* st_size gets the UTF-8 length of the target name, in bytes, * not counting the NULL terminator */ if ((st->st_size = git__utf16_to_8(NULL, 0, target)) < 0) { - giterr_set(GITERR_OS, "Could not convert reparse point name for '%ls'", path); + giterr_set(GITERR_OS, "could not convert reparse point name for '%ls'", path); return -1; } } diff --git a/src/worktree.c b/src/worktree.c new file mode 100644 index 000000000..ede155b69 --- /dev/null +++ b/src/worktree.c @@ -0,0 +1,558 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#include "common.h" + +#include "git2/branch.h" +#include "git2/commit.h" +#include "git2/worktree.h" + +#include "repository.h" +#include "worktree.h" + +static bool is_worktree_dir(const char *dir) +{ + git_buf buf = GIT_BUF_INIT; + int error; + + if (git_buf_sets(&buf, dir) < 0) + return -1; + + error = git_path_contains_file(&buf, "commondir") + && git_path_contains_file(&buf, "gitdir") + && git_path_contains_file(&buf, "HEAD"); + + git_buf_free(&buf); + return error; +} + +int git_worktree_list(git_strarray *wts, git_repository *repo) +{ + git_vector worktrees = GIT_VECTOR_INIT; + git_buf path = GIT_BUF_INIT; + char *worktree; + unsigned i, len; + int error; + + assert(wts && repo); + + wts->count = 0; + wts->strings = NULL; + + if ((error = git_buf_printf(&path, "%s/worktrees/", repo->commondir)) < 0) + goto exit; + if (!git_path_exists(path.ptr) || git_path_is_empty_dir(path.ptr)) + goto exit; + if ((error = git_path_dirload(&worktrees, path.ptr, path.size, 0x0)) < 0) + goto exit; + + len = path.size; + + git_vector_foreach(&worktrees, i, worktree) { + git_buf_truncate(&path, len); + git_buf_puts(&path, worktree); + + if (!is_worktree_dir(path.ptr)) { + git_vector_remove(&worktrees, i); + git__free(worktree); + } + } + + wts->strings = (char **)git_vector_detach(&wts->count, NULL, &worktrees); + +exit: + git_buf_free(&path); + + return error; +} + +char *git_worktree__read_link(const char *base, const char *file) +{ + git_buf path = GIT_BUF_INIT, buf = GIT_BUF_INIT; + + assert(base && file); + + if (git_buf_joinpath(&path, base, file) < 0) + goto err; + if (git_futils_readbuffer(&buf, path.ptr) < 0) + goto err; + git_buf_free(&path); + + git_buf_rtrim(&buf); + + if (!git_path_is_relative(buf.ptr)) + return git_buf_detach(&buf); + + if (git_buf_sets(&path, base) < 0) + goto err; + if (git_path_apply_relative(&path, buf.ptr) < 0) + goto err; + git_buf_free(&buf); + + return git_buf_detach(&path); + +err: + git_buf_free(&buf); + git_buf_free(&path); + + return NULL; +} + +static int write_wtfile(const char *base, const char *file, const git_buf *buf) +{ + git_buf path = GIT_BUF_INIT; + int err; + + assert(base && file && buf); + + if ((err = git_buf_joinpath(&path, base, file)) < 0) + goto out; + + if ((err = git_futils_writebuffer(buf, path.ptr, O_CREAT|O_EXCL|O_WRONLY, 0644)) < 0) + goto out; + +out: + git_buf_free(&path); + + return err; +} + +static int open_worktree_dir(git_worktree **out, const char *parent, const char *dir, const char *name) +{ + git_buf gitdir = GIT_BUF_INIT; + git_worktree *wt = NULL; + int error = 0; + + if (!is_worktree_dir(dir)) { + error = -1; + goto out; + } + + if ((wt = git__calloc(1, sizeof(struct git_repository))) == NULL) { + error = -1; + goto out; + } + + if ((wt->name = git__strdup(name)) == NULL + || (wt->commondir_path = git_worktree__read_link(dir, "commondir")) == NULL + || (wt->gitlink_path = git_worktree__read_link(dir, "gitdir")) == NULL + || (wt->parent_path = git__strdup(parent)) == NULL) { + error = -1; + goto out; + } + + if ((error = git_path_prettify_dir(&gitdir, dir, NULL)) < 0) + goto out; + wt->gitdir_path = git_buf_detach(&gitdir); + + wt->locked = !!git_worktree_is_locked(NULL, wt); + + *out = wt; + +out: + if (error) + git_worktree_free(wt); + git_buf_free(&gitdir); + + return error; +} + +int git_worktree_lookup(git_worktree **out, git_repository *repo, const char *name) +{ + git_buf path = GIT_BUF_INIT; + git_worktree *wt = NULL; + int error; + + assert(repo && name); + + *out = NULL; + + if ((error = git_buf_printf(&path, "%s/worktrees/%s", repo->commondir, name)) < 0) + goto out; + + if ((error = (open_worktree_dir(out, git_repository_workdir(repo), path.ptr, name))) < 0) + goto out; + +out: + git_buf_free(&path); + + if (error) + git_worktree_free(wt); + + return error; +} + +int git_worktree_open_from_repository(git_worktree **out, git_repository *repo) +{ + git_buf parent = GIT_BUF_INIT; + const char *gitdir, *commondir; + char *name = NULL; + int error = 0; + + if (!git_repository_is_worktree(repo)) { + giterr_set(GITERR_WORKTREE, "cannot open worktree of a non-worktree repo"); + error = -1; + goto out; + } + + gitdir = git_repository_path(repo); + commondir = git_repository_commondir(repo); + + if ((error = git_path_prettify_dir(&parent, "..", commondir)) < 0) + goto out; + + /* The name is defined by the last component in '.git/worktree/%s' */ + name = git_path_basename(gitdir); + + if ((error = open_worktree_dir(out, parent.ptr, gitdir, name)) < 0) + goto out; + +out: + git__free(name); + git_buf_free(&parent); + + return error; +} + +void git_worktree_free(git_worktree *wt) +{ + if (!wt) + return; + + git__free(wt->commondir_path); + git__free(wt->gitlink_path); + git__free(wt->gitdir_path); + git__free(wt->parent_path); + git__free(wt->name); + git__free(wt); +} + +int git_worktree_validate(const git_worktree *wt) +{ + git_buf buf = GIT_BUF_INIT; + int err = 0; + + assert(wt); + + git_buf_puts(&buf, wt->gitdir_path); + if (!is_worktree_dir(buf.ptr)) { + giterr_set(GITERR_WORKTREE, + "Worktree gitdir ('%s') is not valid", + wt->gitlink_path); + err = -1; + goto out; + } + + if (!git_path_exists(wt->parent_path)) { + giterr_set(GITERR_WORKTREE, + "Worktree parent directory ('%s') does not exist ", + wt->parent_path); + err = -2; + goto out; + } + + if (!git_path_exists(wt->commondir_path)) { + giterr_set(GITERR_WORKTREE, + "Worktree common directory ('%s') does not exist ", + wt->commondir_path); + err = -3; + goto out; + } + +out: + git_buf_free(&buf); + + return err; +} + +int git_worktree_add_init_options(git_worktree_add_options *opts, + unsigned int version) +{ + GIT_INIT_STRUCTURE_FROM_TEMPLATE(opts, version, + git_worktree_add_options, GIT_WORKTREE_ADD_OPTIONS_INIT); + return 0; +} + +int git_worktree_add(git_worktree **out, git_repository *repo, + const char *name, const char *worktree, + const git_worktree_add_options *opts) +{ + git_buf gitdir = GIT_BUF_INIT, wddir = GIT_BUF_INIT, buf = GIT_BUF_INIT; + git_reference *ref = NULL, *head = NULL; + git_commit *commit = NULL; + git_repository *wt = NULL; + git_checkout_options coopts = GIT_CHECKOUT_OPTIONS_INIT; + git_worktree_add_options wtopts = GIT_WORKTREE_ADD_OPTIONS_INIT; + int err; + + GITERR_CHECK_VERSION( + opts, GIT_WORKTREE_ADD_OPTIONS_VERSION, "git_worktree_add_options"); + + if (opts) + memcpy(&wtopts, opts, sizeof(wtopts)); + + assert(out && repo && name && worktree); + + *out = NULL; + + /* Create gitdir directory ".git/worktrees/" */ + if ((err = git_buf_joinpath(&gitdir, repo->commondir, "worktrees")) < 0) + goto out; + if (!git_path_exists(gitdir.ptr)) + if ((err = git_futils_mkdir(gitdir.ptr, 0755, GIT_MKDIR_EXCL)) < 0) + goto out; + if ((err = git_buf_joinpath(&gitdir, gitdir.ptr, name)) < 0) + goto out; + if ((err = git_futils_mkdir(gitdir.ptr, 0755, GIT_MKDIR_EXCL)) < 0) + goto out; + if ((err = git_path_prettify_dir(&gitdir, gitdir.ptr, NULL)) < 0) + goto out; + + /* Create worktree work dir */ + if ((err = git_futils_mkdir(worktree, 0755, GIT_MKDIR_EXCL)) < 0) + goto out; + if ((err = git_path_prettify_dir(&wddir, worktree, NULL)) < 0) + goto out; + + if (wtopts.lock) { + int fd; + + if ((err = git_buf_joinpath(&buf, gitdir.ptr, "locked")) < 0) + goto out; + + if ((fd = p_creat(buf.ptr, 0644)) < 0) { + err = fd; + goto out; + } + + p_close(fd); + git_buf_clear(&buf); + } + + /* Create worktree .git file */ + if ((err = git_buf_printf(&buf, "gitdir: %s\n", gitdir.ptr)) < 0) + goto out; + if ((err = write_wtfile(wddir.ptr, ".git", &buf)) < 0) + goto out; + + /* Create gitdir files */ + if ((err = git_path_prettify_dir(&buf, repo->commondir, NULL) < 0) + || (err = git_buf_putc(&buf, '\n')) < 0 + || (err = write_wtfile(gitdir.ptr, "commondir", &buf)) < 0) + goto out; + if ((err = git_buf_joinpath(&buf, wddir.ptr, ".git")) < 0 + || (err = git_buf_putc(&buf, '\n')) < 0 + || (err = write_wtfile(gitdir.ptr, "gitdir", &buf)) < 0) + goto out; + + /* Create new branch */ + if ((err = git_repository_head(&head, repo)) < 0) + goto out; + if ((err = git_commit_lookup(&commit, repo, &head->target.oid)) < 0) + goto out; + if ((err = git_branch_create(&ref, repo, name, commit, false)) < 0) + goto out; + + /* Set worktree's HEAD */ + if ((err = git_repository_create_head(gitdir.ptr, git_reference_name(ref))) < 0) + goto out; + if ((err = git_repository_open(&wt, wddir.ptr)) < 0) + goto out; + + /* Checkout worktree's HEAD */ + coopts.checkout_strategy = GIT_CHECKOUT_FORCE; + if ((err = git_checkout_head(wt, &coopts)) < 0) + goto out; + + /* Load result */ + if ((err = git_worktree_lookup(out, repo, name)) < 0) + goto out; + +out: + git_buf_free(&gitdir); + git_buf_free(&wddir); + git_buf_free(&buf); + git_reference_free(ref); + git_reference_free(head); + git_commit_free(commit); + git_repository_free(wt); + + return err; +} + +int git_worktree_lock(git_worktree *wt, char *creason) +{ + git_buf buf = GIT_BUF_INIT, path = GIT_BUF_INIT; + int err; + + assert(wt); + + if ((err = git_worktree_is_locked(NULL, wt)) < 0) + goto out; + + if ((err = git_buf_joinpath(&path, wt->gitdir_path, "locked")) < 0) + goto out; + + if (creason) + git_buf_attach_notowned(&buf, creason, strlen(creason)); + + if ((err = git_futils_writebuffer(&buf, path.ptr, O_CREAT|O_EXCL|O_WRONLY, 0644)) < 0) + goto out; + + wt->locked = 1; + +out: + git_buf_free(&path); + + return err; +} + +int git_worktree_unlock(git_worktree *wt) +{ + git_buf path = GIT_BUF_INIT; + + assert(wt); + + if (!git_worktree_is_locked(NULL, wt)) + return 0; + + if (git_buf_joinpath(&path, wt->gitdir_path, "locked") < 0) + return -1; + + if (p_unlink(path.ptr) != 0) { + git_buf_free(&path); + return -1; + } + + wt->locked = 0; + + git_buf_free(&path); + + return 0; +} + +int git_worktree_is_locked(git_buf *reason, const git_worktree *wt) +{ + git_buf path = GIT_BUF_INIT; + int ret; + + assert(wt); + + if (reason) + git_buf_clear(reason); + + if ((ret = git_buf_joinpath(&path, wt->gitdir_path, "locked")) < 0) + goto out; + if ((ret = git_path_exists(path.ptr)) && reason) + git_futils_readbuffer(reason, path.ptr); + +out: + git_buf_free(&path); + + return ret; +} + +int git_worktree_prune_init_options( + git_worktree_prune_options *opts, + unsigned int version) +{ + GIT_INIT_STRUCTURE_FROM_TEMPLATE(opts, version, + git_worktree_prune_options, GIT_WORKTREE_PRUNE_OPTIONS_INIT); + return 0; +} + +int git_worktree_is_prunable(git_worktree *wt, + git_worktree_prune_options *opts) +{ + git_buf reason = GIT_BUF_INIT; + git_worktree_prune_options popts = GIT_WORKTREE_PRUNE_OPTIONS_INIT; + + GITERR_CHECK_VERSION( + opts, GIT_WORKTREE_PRUNE_OPTIONS_VERSION, + "git_worktree_prune_options"); + + if (opts) + memcpy(&popts, opts, sizeof(popts)); + + if ((popts.flags & GIT_WORKTREE_PRUNE_LOCKED) == 0 && + git_worktree_is_locked(&reason, wt)) + { + if (!reason.size) + git_buf_attach_notowned(&reason, "no reason given", 15); + giterr_set(GITERR_WORKTREE, "Not pruning locked working tree: '%s'", reason.ptr); + git_buf_free(&reason); + + return 0; + } + + if ((popts.flags & GIT_WORKTREE_PRUNE_VALID) == 0 && + git_worktree_validate(wt) == 0) + { + giterr_set(GITERR_WORKTREE, "Not pruning valid working tree"); + return 0; + } + + return 1; +} + +int git_worktree_prune(git_worktree *wt, + git_worktree_prune_options *opts) +{ + git_worktree_prune_options popts = GIT_WORKTREE_PRUNE_OPTIONS_INIT; + git_buf path = GIT_BUF_INIT; + char *wtpath; + int err; + + GITERR_CHECK_VERSION( + opts, GIT_WORKTREE_PRUNE_OPTIONS_VERSION, + "git_worktree_prune_options"); + + if (opts) + memcpy(&popts, opts, sizeof(popts)); + + if (!git_worktree_is_prunable(wt, &popts)) { + err = -1; + goto out; + } + + /* Delete gitdir in parent repository */ + if ((err = git_buf_printf(&path, "%s/worktrees/%s", wt->commondir_path, wt->name)) < 0) + goto out; + if (!git_path_exists(path.ptr)) + { + giterr_set(GITERR_WORKTREE, "Worktree gitdir '%s' does not exist", path.ptr); + err = -1; + goto out; + } + if ((err = git_futils_rmdir_r(path.ptr, NULL, GIT_RMDIR_REMOVE_FILES)) < 0) + goto out; + + /* Skip deletion of the actual working tree if it does + * not exist or deletion was not requested */ + if ((popts.flags & GIT_WORKTREE_PRUNE_WORKING_TREE) == 0 || + !git_path_exists(wt->gitlink_path)) + { + goto out; + } + + if ((wtpath = git_path_dirname(wt->gitlink_path)) == NULL) + goto out; + git_buf_attach(&path, wtpath, 0); + if (!git_path_exists(path.ptr)) + { + giterr_set(GITERR_WORKTREE, "Working tree '%s' does not exist", path.ptr); + err = -1; + goto out; + } + if ((err = git_futils_rmdir_r(path.ptr, NULL, GIT_RMDIR_REMOVE_FILES)) < 0) + goto out; + +out: + git_buf_free(&path); + + return err; +} diff --git a/src/worktree.h b/src/worktree.h new file mode 100644 index 000000000..57c2e65f0 --- /dev/null +++ b/src/worktree.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ +#ifndef INCLUDE_worktree_h__ +#define INCLUDE_worktree_h__ + +#include "git2/common.h" +#include "git2/worktree.h" + +struct git_worktree { + /* Name of the working tree. This is the name of the + * containing directory in the `$PARENT/.git/worktrees/` + * directory. */ + char *name; + + /* Path to the .git file in the working tree's repository */ + char *gitlink_path; + /* Path to the .git directory inside the parent's + * worktrees directory */ + char *gitdir_path; + /* Path to the common directory contained in the parent + * repository */ + char *commondir_path; + /* Path to the parent's working directory */ + char *parent_path; + + int locked:1; +}; + +char *git_worktree__read_link(const char *base, const char *file); + +#endif diff --git a/src/zstream.c b/src/zstream.c index d949aa81a..141b49b27 100644 --- a/src/zstream.c +++ b/src/zstream.c @@ -23,7 +23,7 @@ static int zstream_seterr(git_zstream *zs) else if (zs->z.msg) giterr_set_str(GITERR_ZLIB, zs->z.msg); else - giterr_set(GITERR_ZLIB, "Unknown compression error"); + giterr_set(GITERR_ZLIB, "unknown compression error"); return -1; } diff --git a/tests/attr/ignore.c b/tests/attr/ignore.c index f1fe1c71f..a089ee408 100644 --- a/tests/attr/ignore.c +++ b/tests/attr/ignore.c @@ -21,8 +21,8 @@ static void assert_is_ignored_( { int is_ignored = 0; - cl_git_pass_( - git_ignore_path_is_ignored(&is_ignored, g_repo, filepath), file, line); + cl_git_expect( + git_ignore_path_is_ignored(&is_ignored, g_repo, filepath), 0, file, line); clar__assert_equal( file, line, "expected != is_ignored", 1, "%d", @@ -291,3 +291,15 @@ void test_attr_ignore__symlink_to_outside(void) assert_is_ignored(true, "symlink"); assert_is_ignored(true, "lala/../symlink"); } + +void test_attr_ignore__test(void) +{ + cl_git_rewritefile("attr/.gitignore", + "/*/\n" + "!/src\n"); + assert_is_ignored(false, "src/foo.c"); + assert_is_ignored(false, "src/foo/foo.c"); + assert_is_ignored(false, "README.md"); + assert_is_ignored(true, "dist/foo.o"); + assert_is_ignored(true, "bin/foo"); +} diff --git a/tests/checkout/head.c b/tests/checkout/head.c index 07cc1d209..ded86df33 100644 --- a/tests/checkout/head.c +++ b/tests/checkout/head.c @@ -38,7 +38,7 @@ void test_checkout_head__with_index_only_tree(void) cl_git_pass(git_repository_index(&index, g_repo)); p_mkdir("testrepo/newdir", 0777); - cl_git_mkfile("testrepo/newdir/newfile.txt", "new file\n"); + cl_git_mkfile("testrepo/newdir/newfile.txt", "new file\n"); cl_git_pass(git_index_add_bypath(index, "newdir/newfile.txt")); cl_git_pass(git_index_write(index)); @@ -60,3 +60,79 @@ void test_checkout_head__with_index_only_tree(void) git_index_free(index); } + +void test_checkout_head__do_not_remove_untracked_file(void) +{ + git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT; + git_index *index; + + cl_git_pass(p_mkdir("testrepo/tracked", 0755)); + cl_git_mkfile("testrepo/tracked/tracked", "tracked\n"); + cl_git_mkfile("testrepo/tracked/untracked", "untracked\n"); + + cl_git_pass(git_repository_index(&index, g_repo)); + cl_git_pass(git_index_add_bypath(index, "tracked/tracked")); + cl_git_pass(git_index_write(index)); + + git_index_free(index); + + opts.checkout_strategy = GIT_CHECKOUT_FORCE; + cl_git_pass(git_checkout_head(g_repo, &opts)); + + cl_assert(!git_path_isfile("testrepo/tracked/tracked")); + cl_assert(git_path_isfile("testrepo/tracked/untracked")); +} + +void test_checkout_head__do_not_remove_untracked_file_in_subdir(void) +{ + git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT; + git_index *index; + + cl_git_pass(p_mkdir("testrepo/tracked", 0755)); + cl_git_pass(p_mkdir("testrepo/tracked/subdir", 0755)); + cl_git_mkfile("testrepo/tracked/tracked", "tracked\n"); + cl_git_mkfile("testrepo/tracked/subdir/tracked", "tracked\n"); + cl_git_mkfile("testrepo/tracked/subdir/untracked", "untracked\n"); + + cl_git_pass(git_repository_index(&index, g_repo)); + cl_git_pass(git_index_add_bypath(index, "tracked/tracked")); + cl_git_pass(git_index_add_bypath(index, "tracked/subdir/tracked")); + cl_git_pass(git_index_write(index)); + + git_index_free(index); + + opts.checkout_strategy = GIT_CHECKOUT_FORCE; + cl_git_pass(git_checkout_head(g_repo, &opts)); + + cl_assert(!git_path_isfile("testrepo/tracked/tracked")); + cl_assert(!git_path_isfile("testrepo/tracked/subdir/tracked")); + cl_assert(git_path_isfile("testrepo/tracked/subdir/untracked")); +} + +void test_checkout_head__do_remove_tracked_subdir(void) +{ + git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT; + git_index *index; + + cl_git_pass(p_mkdir("testrepo/subdir", 0755)); + cl_git_pass(p_mkdir("testrepo/subdir/tracked", 0755)); + cl_git_mkfile("testrepo/subdir/tracked-file", "tracked\n"); + cl_git_mkfile("testrepo/subdir/untracked-file", "untracked\n"); + cl_git_mkfile("testrepo/subdir/tracked/tracked1", "tracked\n"); + cl_git_mkfile("testrepo/subdir/tracked/tracked2", "tracked\n"); + + cl_git_pass(git_repository_index(&index, g_repo)); + cl_git_pass(git_index_add_bypath(index, "subdir/tracked-file")); + cl_git_pass(git_index_add_bypath(index, "subdir/tracked/tracked1")); + cl_git_pass(git_index_add_bypath(index, "subdir/tracked/tracked2")); + cl_git_pass(git_index_write(index)); + + git_index_free(index); + + opts.checkout_strategy = GIT_CHECKOUT_FORCE; + cl_git_pass(git_checkout_head(g_repo, &opts)); + + cl_assert(!git_path_isdir("testrepo/subdir/tracked")); + cl_assert(!git_path_isfile("testrepo/subdir/tracked-file")); + cl_assert(git_path_isfile("testrepo/subdir/untracked-file")); +} diff --git a/tests/checkout/tree.c b/tests/checkout/tree.c index 4a0314a9e..b3b860c63 100644 --- a/tests/checkout/tree.c +++ b/tests/checkout/tree.c @@ -422,6 +422,41 @@ void test_checkout_tree__can_checkout_with_pattern(void) cl_assert(git_path_exists("testrepo/new.txt")); } +void test_checkout_tree__pathlist_checkout_ignores_non_matches(void) +{ + char *entries[] = { "branch_file.txt", "link_to_new.txt" }; + + /* reset to beginning of history (i.e. just a README file) */ + + g_opts.checkout_strategy = + GIT_CHECKOUT_FORCE | GIT_CHECKOUT_REMOVE_UNTRACKED; + + cl_git_pass(git_revparse_single(&g_object, g_repo, "refs/heads/master")); + + cl_git_pass(git_checkout_tree(g_repo, g_object, &g_opts)); + cl_git_pass(git_repository_set_head(g_repo, "refs/heads/master")); + + cl_assert(git_path_exists("testrepo/README")); + cl_assert(git_path_exists("testrepo/branch_file.txt")); + cl_assert(git_path_exists("testrepo/link_to_new.txt")); + cl_assert(git_path_exists("testrepo/new.txt")); + + git_object_free(g_object); + cl_git_pass(git_revparse_single(&g_object, g_repo, "8496071c1b46c854b31185ea97743be6a8774479")); + + g_opts.checkout_strategy = + GIT_CHECKOUT_FORCE | GIT_CHECKOUT_DISABLE_PATHSPEC_MATCH; + g_opts.paths.strings = entries; + g_opts.paths.count = 2; + + cl_git_pass(git_checkout_tree(g_repo, g_object, &g_opts)); + + cl_assert(git_path_exists("testrepo/README")); + cl_assert(!git_path_exists("testrepo/branch_file.txt")); + cl_assert(!git_path_exists("testrepo/link_to_new.txt")); + cl_assert(git_path_exists("testrepo/new.txt")); +} + void test_checkout_tree__can_disable_pattern_match(void) { char *entries[] = { "b*.txt" }; diff --git a/tests/clar_libgit2.c b/tests/clar_libgit2.c index 314d3441e..bd10c009d 100644 --- a/tests/clar_libgit2.c +++ b/tests/clar_libgit2.c @@ -4,12 +4,20 @@ #include "git2/sys/repository.h" void cl_git_report_failure( - int error, const char *file, int line, const char *fncall) + int error, int expected, const char *file, int line, const char *fncall) { char msg[4096]; const git_error *last = giterr_last(); - p_snprintf(msg, 4096, "error %d - %s", - error, last ? last->message : ""); + + if (expected) + p_snprintf(msg, 4096, "error %d (expected %d) - %s", + error, expected, last ? last->message : ""); + else if (error || last) + p_snprintf(msg, 4096, "error %d - %s", + error, last ? last->message : ""); + else + p_snprintf(msg, 4096, "no error, expected non-zero return"); + clar__assert(0, file, line, fncall, msg, 1); } diff --git a/tests/clar_libgit2.h b/tests/clar_libgit2.h index fc08bbf1f..c72d37db3 100644 --- a/tests/clar_libgit2.h +++ b/tests/clar_libgit2.h @@ -12,13 +12,15 @@ * * Use this wrapper around all `git_` library calls that return error codes! */ -#define cl_git_pass(expr) cl_git_pass_((expr), __FILE__, __LINE__) +#define cl_git_pass(expr) cl_git_expect((expr), 0, __FILE__, __LINE__) -#define cl_git_pass_(expr, file, line) do { \ +#define cl_git_fail_with(error, expr) cl_git_expect((expr), error, __FILE__, __LINE__) + +#define cl_git_expect(expr, expected, file, line) do { \ int _lg2_error; \ giterr_clear(); \ - if ((_lg2_error = (expr)) != 0) \ - cl_git_report_failure(_lg2_error, file, line, "Function call failed: " #expr); \ + if ((_lg2_error = (expr)) != expected) \ + cl_git_report_failure(_lg2_error, expected, file, line, "Function call failed: " #expr); \ } while (0) /** @@ -26,9 +28,11 @@ * just for consistency. Use with `git_` library * calls that are supposed to fail! */ -#define cl_git_fail(expr) cl_must_fail(expr) - -#define cl_git_fail_with(expr, error) cl_assert_equal_i(error,expr) +#define cl_git_fail(expr) do { \ + giterr_clear(); \ + if ((expr) == 0) \ + cl_git_report_failure(0, 0, __FILE__, __LINE__, "Function call succeeded: " #expr); \ + } while (0) /** * Like cl_git_pass, only for Win32 error code conventions @@ -37,7 +41,7 @@ int _win32_res; \ if ((_win32_res = (expr)) == 0) { \ giterr_set(GITERR_OS, "Returned: %d, system error code: %d", _win32_res, GetLastError()); \ - cl_git_report_failure(_win32_res, __FILE__, __LINE__, "System call failed: " #expr); \ + cl_git_report_failure(_win32_res, 0, __FILE__, __LINE__, "System call failed: " #expr); \ } \ } while(0) @@ -86,7 +90,7 @@ GIT_INLINE(void) cl_git_thread_check(void *data) clar__assert(0, threaderr->file, threaderr->line, threaderr->expr, threaderr->error_msg, 1); } -void cl_git_report_failure(int, const char *, int, const char *); +void cl_git_report_failure(int, int, const char *, int, const char *); #define cl_assert_at_line(expr,file,line) \ clar__assert((expr) != 0, file, line, "Expression is not true: " #expr, NULL, 1) diff --git a/tests/clone/local.c b/tests/clone/local.c index 91a0a1c2a..7f54d05de 100644 --- a/tests/clone/local.c +++ b/tests/clone/local.c @@ -16,6 +16,7 @@ static int file_url(git_buf *buf, const char *host, const char *path) return git_buf_printf(buf, "file://%s/%s", host, path); } +#ifdef GIT_WIN32 static int git_style_unc_path(git_buf *buf, const char *host, const char *path) { git_buf_clear(buf); @@ -49,6 +50,7 @@ static int unc_path(git_buf *buf, const char *host, const char *path) return 0; } +#endif void test_clone_local__should_clone_local(void) { diff --git a/tests/config/include.c b/tests/config/include.c index 882b89b16..0a07c9b85 100644 --- a/tests/config/include.c +++ b/tests/config/include.c @@ -108,6 +108,26 @@ void test_config_include__missing(void) git_config_free(cfg); } +void test_config_include__missing_homedir(void) +{ + git_config *cfg; + git_buf buf = GIT_BUF_INIT; + + cl_git_pass(git_libgit2_opts(GIT_OPT_SET_SEARCH_PATH, GIT_CONFIG_LEVEL_GLOBAL, cl_fixture("config"))); + cl_git_mkfile("including", "[include]\npath = ~/.nonexistentfile\n[foo]\nbar = baz"); + + giterr_clear(); + cl_git_pass(git_config_open_ondisk(&cfg, "including")); + cl_assert(giterr_last() == NULL); + cl_git_pass(git_config_get_string_buf(&buf, cfg, "foo.bar")); + cl_assert_equal_s("baz", git_buf_cstr(&buf)); + + git_buf_free(&buf); + git_config_free(cfg); + + cl_sandbox_set_search_path_defaults(); +} + #define replicate10(s) s s s s s s s s s s void test_config_include__depth2(void) { diff --git a/tests/config/readonly.c b/tests/config/readonly.c new file mode 100644 index 000000000..f45abdd29 --- /dev/null +++ b/tests/config/readonly.c @@ -0,0 +1,64 @@ +#include "clar_libgit2.h" +#include "config_file.h" +#include "config.h" + +static git_config *cfg; + +void test_config_readonly__initialize(void) +{ + cl_git_pass(git_config_new(&cfg)); +} + +void test_config_readonly__cleanup(void) +{ + git_config_free(cfg); + cfg = NULL; +} + +void test_config_readonly__writing_to_readonly_fails(void) +{ + git_config_backend *backend; + + cl_git_pass(git_config_file__ondisk(&backend, "global")); + backend->readonly = 1; + cl_git_pass(git_config_add_backend(cfg, backend, GIT_CONFIG_LEVEL_GLOBAL, 0)); + + cl_git_fail_with(GIT_ENOTFOUND, git_config_set_string(cfg, "foo.bar", "baz")); + cl_assert(!git_path_exists("global")); +} + +void test_config_readonly__writing_to_cfg_with_rw_precedence_succeeds(void) +{ + git_config_backend *backend; + + cl_git_pass(git_config_file__ondisk(&backend, "global")); + backend->readonly = 1; + cl_git_pass(git_config_add_backend(cfg, backend, GIT_CONFIG_LEVEL_GLOBAL, 0)); + + cl_git_pass(git_config_file__ondisk(&backend, "local")); + cl_git_pass(git_config_add_backend(cfg, backend, GIT_CONFIG_LEVEL_LOCAL, 0)); + + cl_git_pass(git_config_set_string(cfg, "foo.bar", "baz")); + + cl_assert(git_path_exists("local")); + cl_assert(!git_path_exists("global")); + cl_git_pass(p_unlink("local")); +} + +void test_config_readonly__writing_to_cfg_with_ro_precedence_succeeds(void) +{ + git_config_backend *backend; + + cl_git_pass(git_config_file__ondisk(&backend, "local")); + backend->readonly = 1; + cl_git_pass(git_config_add_backend(cfg, backend, GIT_CONFIG_LEVEL_LOCAL, 0)); + + cl_git_pass(git_config_file__ondisk(&backend, "global")); + cl_git_pass(git_config_add_backend(cfg, backend, GIT_CONFIG_LEVEL_GLOBAL, 0)); + + cl_git_pass(git_config_set_string(cfg, "foo.bar", "baz")); + + cl_assert(!git_path_exists("local")); + cl_assert(git_path_exists("global")); + cl_git_pass(p_unlink("global")); +} diff --git a/tests/core/encoding.c b/tests/core/encoding.c index 7d91720f4..a677afe2e 100644 --- a/tests/core/encoding.c +++ b/tests/core/encoding.c @@ -29,6 +29,9 @@ void test_core_encoding__encode(void) cl_assert(git_encode_varint(buf, 100, 65) == 1); cl_assert(buf[0] == 'A'); + cl_assert(git_encode_varint(buf, 1, 1) == 1); + cl_assert(!memcmp(buf, "\x01", 1)); + cl_assert(git_encode_varint(buf, 100, 267869656) == 4); cl_assert(!memcmp(buf, "\xfe\xdc\xbaX", 4)); diff --git a/tests/core/features.c b/tests/core/features.c index cf5e19063..7b28cc0cb 100644 --- a/tests/core/features.c +++ b/tests/core/features.c @@ -17,7 +17,9 @@ void test_core_features__0(void) cl_assert((caps & GIT_FEATURE_THREADS) == 0); #endif +#ifdef GIT_HTTPS cl_assert((caps & GIT_FEATURE_HTTPS) != 0); +#endif #if defined(GIT_SSH) cl_assert((caps & GIT_FEATURE_SSH) != 0); diff --git a/tests/core/filebuf.c b/tests/core/filebuf.c index 04a380b20..ef7ac6bd9 100644 --- a/tests/core/filebuf.c +++ b/tests/core/filebuf.c @@ -187,6 +187,35 @@ void test_core_filebuf__symlink_follow(void) cl_git_pass(git_futils_rmdir_r(dir, NULL, GIT_RMDIR_REMOVE_FILES)); } +void test_core_filebuf__symlink_follow_absolute_paths(void) +{ + git_filebuf file = GIT_FILEBUF_INIT; + git_buf source = GIT_BUF_INIT, target = GIT_BUF_INIT; + +#ifdef GIT_WIN32 + cl_skip(); +#endif + + cl_git_pass(git_buf_joinpath(&source, clar_sandbox_path(), "linkdir/link")); + cl_git_pass(git_buf_joinpath(&target, clar_sandbox_path(), "linkdir/target")); + cl_git_pass(p_mkdir("linkdir", 0777)); + cl_git_pass(p_symlink(target.ptr, source.ptr)); + + cl_git_pass(git_filebuf_open(&file, source.ptr, 0, 0666)); + cl_git_pass(git_filebuf_printf(&file, "%s\n", "libgit2 rocks")); + + cl_assert_equal_i(true, git_path_exists("linkdir/target.lock")); + + cl_git_pass(git_filebuf_commit(&file)); + cl_assert_equal_i(true, git_path_exists("linkdir/target")); + + git_filebuf_cleanup(&file); + git_buf_free(&source); + git_buf_free(&target); + + cl_git_pass(git_futils_rmdir_r("linkdir", NULL, GIT_RMDIR_REMOVE_FILES)); +} + void test_core_filebuf__symlink_depth(void) { git_filebuf file = GIT_FILEBUF_INIT; diff --git a/tests/core/oidmap.c b/tests/core/oidmap.c index 556a6ca4a..617da5483 100644 --- a/tests/core/oidmap.c +++ b/tests/core/oidmap.c @@ -1,8 +1,6 @@ #include "clar_libgit2.h" #include "oidmap.h" -GIT__USE_OIDMAP - typedef struct { git_oid oid; size_t extra; @@ -33,23 +31,23 @@ void test_core_oidmap__basic(void) khiter_t pos; int ret; - pos = kh_get(oid, map, &items[i].oid); - cl_assert(pos == kh_end(map)); + pos = git_oidmap_lookup_index(map, &items[i].oid); + cl_assert(!git_oidmap_valid_index(map, pos)); - pos = kh_put(oid, map, &items[i].oid, &ret); + pos = git_oidmap_put(map, &items[i].oid, &ret); cl_assert(ret != 0); - kh_val(map, pos) = &items[i]; + git_oidmap_set_value_at(map, pos, &items[i]); } for (i = 0; i < NITEMS; ++i) { khiter_t pos; - pos = kh_get(oid, map, &items[i].oid); - cl_assert(pos != kh_end(map)); + pos = git_oidmap_lookup_index(map, &items[i].oid); + cl_assert(git_oidmap_valid_index(map, pos)); - cl_assert_equal_p(kh_val(map, pos), &items[i]); + cl_assert_equal_p(git_oidmap_value_at(map, pos), &items[i]); } git_oidmap_free(map); @@ -87,23 +85,23 @@ void test_core_oidmap__hash_collision(void) khiter_t pos; int ret; - pos = kh_get(oid, map, &items[i].oid); - cl_assert(pos == kh_end(map)); + pos = git_oidmap_lookup_index(map, &items[i].oid); + cl_assert(!git_oidmap_valid_index(map, pos)); - pos = kh_put(oid, map, &items[i].oid, &ret); + pos = git_oidmap_put(map, &items[i].oid, &ret); cl_assert(ret != 0); - kh_val(map, pos) = &items[i]; + git_oidmap_set_value_at(map, pos, &items[i]); } for (i = 0; i < NITEMS; ++i) { khiter_t pos; - pos = kh_get(oid, map, &items[i].oid); - cl_assert(pos != kh_end(map)); + pos = git_oidmap_lookup_index(map, &items[i].oid); + cl_assert(git_oidmap_valid_index(map, pos)); - cl_assert_equal_p(kh_val(map, pos), &items[i]); + cl_assert_equal_p(git_oidmap_value_at(map, pos), &items[i]); } git_oidmap_free(map); diff --git a/tests/core/path.c b/tests/core/path.c index 71c6eda58..fefe2aeac 100644 --- a/tests/core/path.c +++ b/tests/core/path.c @@ -89,8 +89,12 @@ void test_core_path__00_dirname(void) check_dirname(REP16("/abc"), REP15("/abc")); #ifdef GIT_WIN32 + check_dirname("C:/", "C:/"); + check_dirname("C:", "C:/"); check_dirname("C:/path/", "C:/"); check_dirname("C:/path", "C:/"); + check_dirname("//computername/", "//computername/"); + check_dirname("//computername", "//computername/"); check_dirname("//computername/path/", "//computername/"); check_dirname("//computername/path", "//computername/"); check_dirname("//computername/sub/path/", "//computername/sub"); diff --git a/tests/core/posix.c b/tests/core/posix.c index 26ae36049..172462073 100644 --- a/tests/core/posix.c +++ b/tests/core/posix.c @@ -94,10 +94,7 @@ void test_core_posix__inet_pton(void) cl_assert(p_inet_pton(AF_INET, "10.foo.bar.1", &addr) == 0); /* Test unsupported address families */ - cl_git_fail(p_inet_pton(12, "52.472", NULL)); /* AF_DECnet */ - cl_assert_equal_i(EAFNOSUPPORT, errno); - - cl_git_fail(p_inet_pton(5, "315.124", NULL)); /* AF_CHAOS */ + cl_git_fail(p_inet_pton(INT_MAX-1, "52.472", &addr)); cl_assert_equal_i(EAFNOSUPPORT, errno); } diff --git a/tests/core/sha1.c b/tests/core/sha1.c new file mode 100644 index 000000000..c5b20f6e0 --- /dev/null +++ b/tests/core/sha1.c @@ -0,0 +1,64 @@ +#include "clar_libgit2.h" +#include "hash.h" + +#define FIXTURE_DIR "sha1" + +void test_core_sha1__initialize(void) +{ + cl_fixture_sandbox(FIXTURE_DIR); +} + +void test_core_sha1__cleanup(void) +{ + cl_fixture_cleanup(FIXTURE_DIR); +} + +static int sha1_file(git_oid *oid, const char *filename) +{ + git_hash_ctx ctx; + char buf[2048]; + int fd, ret; + ssize_t read_len; + + fd = p_open(filename, O_RDONLY); + cl_assert(fd >= 0); + + cl_git_pass(git_hash_ctx_init(&ctx)); + + while ((read_len = p_read(fd, buf, 2048)) > 0) + cl_git_pass(git_hash_update(&ctx, buf, (size_t)read_len)); + + cl_assert_equal_i(0, read_len); + p_close(fd); + + ret = git_hash_final(oid, &ctx); + git_hash_ctx_cleanup(&ctx); + + return ret; +} + +void test_core_sha1__sum(void) +{ + git_oid oid, expected; + + cl_git_pass(sha1_file(&oid, FIXTURE_DIR "/hello_c")); + git_oid_fromstr(&expected, "4e72679e3ea4d04e0c642f029e61eb8056c7ed94"); + cl_assert_equal_oid(&expected, &oid); +} + +/* test that sha1 collision detection works when enabled */ +void test_core_sha1__detect_collision_attack(void) +{ + git_oid oid, expected; + +#ifdef GIT_SHA1_COLLISIONDETECT + GIT_UNUSED(expected); + cl_git_fail(sha1_file(&oid, FIXTURE_DIR "/shattered-1.pdf")); + cl_assert_equal_s("SHA1 collision attack detected", giterr_last()->message); +#else + cl_git_pass(sha1_file(&oid, FIXTURE_DIR "/shattered-1.pdf")); + git_oid_fromstr(&expected, "38762cf7f55934b34d179ae6a4c80cadccbb7f0a"); + cl_assert_equal_oid(&expected, &oid); +#endif +} + diff --git a/tests/core/strmap.c b/tests/core/strmap.c index 3b4276aea..2fa594d43 100644 --- a/tests/core/strmap.c +++ b/tests/core/strmap.c @@ -1,8 +1,6 @@ #include "clar_libgit2.h" #include "strmap.h" -GIT__USE_STRMAP - git_strmap *g_table; void test_core_strmap__initialize(void) @@ -36,7 +34,7 @@ static void insert_strings(git_strmap *table, int count) for (j = 0, over = i / 26; over > 0; j++, over = over / 26) str[j] = 'A' + (over % 26); - git_strmap_insert(table, str, str, err); + git_strmap_insert(table, str, str, &err); cl_assert(err >= 0); } diff --git a/tests/core/structinit.c b/tests/core/structinit.c index e9f7b4a74..78503fcc6 100644 --- a/tests/core/structinit.c +++ b/tests/core/structinit.c @@ -1,5 +1,6 @@ #include "clar_libgit2.h" #include +#include #include #include #include @@ -96,6 +97,11 @@ void test_core_structinit__compare(void) git_diff_find_options, GIT_DIFF_FIND_OPTIONS_VERSION, \ GIT_DIFF_FIND_OPTIONS_INIT, git_diff_find_init_options); + /* filter */ + CHECK_MACRO_FUNC_INIT_EQUAL( \ + git_filter, GIT_FILTER_VERSION, \ + GIT_FILTER_INIT, git_filter_init); + /* merge_file_input */ CHECK_MACRO_FUNC_INIT_EQUAL( \ git_merge_file_input, GIT_MERGE_FILE_INPUT_VERSION, \ @@ -165,4 +171,9 @@ void test_core_structinit__compare(void) CHECK_MACRO_FUNC_INIT_EQUAL( \ git_submodule_update_options, GIT_SUBMODULE_UPDATE_OPTIONS_VERSION, \ GIT_SUBMODULE_UPDATE_OPTIONS_INIT, git_submodule_update_init_options); + + /* submodule update */ + CHECK_MACRO_FUNC_INIT_EQUAL( \ + git_proxy_options, GIT_PROXY_OPTIONS_VERSION, \ + GIT_PROXY_OPTIONS_INIT, git_proxy_init_options); } diff --git a/tests/diff/parse.c b/tests/diff/parse.c index a06813d1b..acb6eb8a5 100644 --- a/tests/diff/parse.c +++ b/tests/diff/parse.c @@ -196,3 +196,74 @@ void test_diff_parse__get_patch_from_diff(void) cl_git_sandbox_cleanup(); } + +static int file_cb(const git_diff_delta *delta, float progress, void *payload) +{ + int *called = (int *) payload; + GIT_UNUSED(delta); + GIT_UNUSED(progress); + (*called)++; + return 0; +} + +void test_diff_parse__foreach_works_with_parsed_patch(void) +{ + const char patch[] = + "diff --git a/obj1 b/obj2\n" + "index 1234567..7654321 10644\n" + "--- a/obj1\n" + "+++ b/obj2\n" + "@@ -1 +1 @@\n" + "-abcde\n" + "+12345\n"; + int called = 0; + git_diff *diff; + + cl_git_pass(git_diff_from_buffer(&diff, patch, strlen(patch))); + cl_git_pass(git_diff_foreach(diff, file_cb, NULL, NULL, NULL, &called)); + cl_assert_equal_i(called, 1); + + git_diff_free(diff); +} + +void test_diff_parse__parsing_minimal_patch_succeeds(void) +{ + const char patch[] = + "diff --git a/obj1 b/obj2\n" + "index 1234567..7654321 10644\n" + "--- a/obj1\n" + "+++ b/obj2\n" + "@@ -1 +1 @@\n" + "-a\n" + "+\n"; + git_buf buf = GIT_BUF_INIT; + git_diff *diff; + + cl_git_pass(git_diff_from_buffer(&diff, patch, strlen(patch))); + cl_git_pass(git_diff_to_buf(&buf, diff, GIT_DIFF_FORMAT_PATCH)); + cl_assert_equal_s(patch, buf.ptr); + + git_diff_free(diff); + git_buf_free(&buf); +} + +void test_diff_parse__patch_roundtrip_succeeds(void) +{ + const char buf1[] = "a\n", buf2[] = "b\n"; + git_buf patchbuf = GIT_BUF_INIT, diffbuf = GIT_BUF_INIT; + git_patch *patch; + git_diff *diff; + + cl_git_pass(git_patch_from_buffers(&patch, buf1, strlen(buf1), "obj1", buf2, strlen(buf2), "obj2", NULL)); + cl_git_pass(git_patch_to_buf(&patchbuf, patch)); + + cl_git_pass(git_diff_from_buffer(&diff, patchbuf.ptr, patchbuf.size)); + cl_git_pass(git_diff_to_buf(&diffbuf, diff, GIT_DIFF_FORMAT_PATCH)); + + cl_assert_equal_s(patchbuf.ptr, diffbuf.ptr); + + git_patch_free(patch); + git_diff_free(diff); + git_buf_free(&patchbuf); + git_buf_free(&diffbuf); +} diff --git a/tests/fetchhead/nonetwork.c b/tests/fetchhead/nonetwork.c index 3b750af5e..ea4b70e4a 100644 --- a/tests/fetchhead/nonetwork.c +++ b/tests/fetchhead/nonetwork.c @@ -293,7 +293,7 @@ void test_fetchhead_nonetwork__invalid_for_merge(void) cl_git_rewritefile("./test1/.git/FETCH_HEAD", "49322bb17d3acc9146f98c97d078513228bbf3c0\tinvalid-merge\t\n"); cl_git_fail(git_repository_fetchhead_foreach(g_repo, read_noop, NULL)); - cl_assert(git__prefixcmp(giterr_last()->message, "Invalid for-merge") == 0); + cl_assert(git__prefixcmp(giterr_last()->message, "invalid for-merge") == 0); } void test_fetchhead_nonetwork__invalid_description(void) @@ -304,7 +304,7 @@ void test_fetchhead_nonetwork__invalid_description(void) cl_git_rewritefile("./test1/.git/FETCH_HEAD", "49322bb17d3acc9146f98c97d078513228bbf3c0\tnot-for-merge\n"); cl_git_fail(git_repository_fetchhead_foreach(g_repo, read_noop, NULL)); - cl_assert(git__prefixcmp(giterr_last()->message, "Invalid description") == 0); + cl_assert(git__prefixcmp(giterr_last()->message, "invalid description") == 0); } static int assert_master_for_merge(const char *ref, const char *url, const git_oid *id, unsigned int is_merge, void *data) diff --git a/tests/filter/custom.c b/tests/filter/custom.c index fd1cd271c..799beef62 100644 --- a/tests/filter/custom.c +++ b/tests/filter/custom.c @@ -55,6 +55,7 @@ void test_filter_custom__initialize(void) "hero* bitflip reverse\n" "herofile text\n" "heroflip -reverse binary\n" + "villain erroneous\n" "*.bin binary\n"); } @@ -82,6 +83,11 @@ static void register_custom_filters(void) create_reverse_filter("+prereverse"), GIT_FILTER_DRIVER_PRIORITY)); + cl_git_pass(git_filter_register( + "erroneous", + create_erroneous_filter("+erroneous"), + GIT_FILTER_DRIVER_PRIORITY)); + filters_registered = 1; } } @@ -235,3 +241,18 @@ void test_filter_custom__filter_registry_failure_cases(void) cl_git_fail(git_filter_unregister(GIT_FILTER_IDENT)); cl_assert_equal_i(GIT_ENOTFOUND, git_filter_unregister("not-a-filter")); } + +void test_filter_custom__erroneous_filter_fails(void) +{ + git_filter_list *filters; + git_buf out = GIT_BUF_INIT; + git_buf in = GIT_BUF_INIT_CONST(workdir_data, strlen(workdir_data)); + + cl_git_pass(git_filter_list_load( + &filters, g_repo, NULL, "villain", GIT_FILTER_TO_WORKTREE, 0)); + + cl_git_fail(git_filter_list_apply_to_data(&out, filters, &in)); + + git_filter_list_free(filters); + git_buf_free(&out); +} diff --git a/tests/filter/custom_helpers.c b/tests/filter/custom_helpers.c index 2c80212be..d7f2afe7a 100644 --- a/tests/filter/custom_helpers.c +++ b/tests/filter/custom_helpers.c @@ -106,3 +106,36 @@ git_filter *create_reverse_filter(const char *attrs) return filter; } + +int erroneous_filter_stream( + git_writestream **out, + git_filter *self, + void **payload, + const git_filter_source *src, + git_writestream *next) +{ + GIT_UNUSED(out); + GIT_UNUSED(self); + GIT_UNUSED(payload); + GIT_UNUSED(src); + GIT_UNUSED(next); + return -1; +} + +static void erroneous_filter_free(git_filter *f) +{ + git__free(f); +} + +git_filter *create_erroneous_filter(const char *attrs) +{ + git_filter *filter = git__calloc(1, sizeof(git_filter)); + cl_assert(filter); + + filter->version = GIT_FILTER_VERSION; + filter->attributes = attrs; + filter->stream = erroneous_filter_stream; + filter->shutdown = erroneous_filter_free; + + return filter; +} diff --git a/tests/filter/custom_helpers.h b/tests/filter/custom_helpers.h index 13cfb23ae..537a51da2 100644 --- a/tests/filter/custom_helpers.h +++ b/tests/filter/custom_helpers.h @@ -2,6 +2,7 @@ extern git_filter *create_bitflip_filter(void); extern git_filter *create_reverse_filter(const char *attr); +extern git_filter *create_erroneous_filter(const char *attr); extern int bitflip_filter_apply( git_filter *self, diff --git a/tests/index/version.c b/tests/index/version.c index 3fd240d3c..7ada302b5 100644 --- a/tests/index/version.c +++ b/tests/index/version.c @@ -3,39 +3,135 @@ static git_repository *g_repo = NULL; +void test_index_version__cleanup(void) +{ + cl_git_sandbox_cleanup(); + g_repo = NULL; +} + +void test_index_version__can_read_v4(void) +{ + const char *paths[] = { + "file.tx", "file.txt", "file.txz", "foo", "zzz", + }; + git_index *index; + size_t i; + + g_repo = cl_git_sandbox_init("indexv4"); + + cl_git_pass(git_repository_index(&index, g_repo)); + cl_assert_equal_sz(git_index_entrycount(index), 5); + + for (i = 0; i < ARRAY_SIZE(paths); i++) { + const git_index_entry *entry = + git_index_get_bypath(index, paths[i], GIT_INDEX_STAGE_NORMAL); + + cl_assert(entry != NULL); + } + + git_index_free(index); +} + void test_index_version__can_write_v4(void) { + const char *paths[] = { + "foo", + "foox", + "foobar", + "foobal", + "x", + "xz", + "xyzzyx" + }; + git_index_entry entry; git_index *index; - const git_index_entry *entry; + size_t i; - g_repo = cl_git_sandbox_init("filemodes"); + g_repo = cl_git_sandbox_init("empty_standard_repo"); cl_git_pass(git_repository_index(&index, g_repo)); - - cl_assert(index->on_disk); - cl_assert(git_index_version(index) == 2); - - cl_assert(git_index_entrycount(index) == 6); - cl_git_pass(git_index_set_version(index, 4)); + for (i = 0; i < ARRAY_SIZE(paths); i++) { + memset(&entry, 0, sizeof(entry)); + entry.path = paths[i]; + entry.mode = GIT_FILEMODE_BLOB; + cl_git_pass(git_index_add_frombuffer(index, &entry, paths[i], + strlen(paths[i]) + 1)); + } + cl_assert_equal_sz(git_index_entrycount(index), ARRAY_SIZE(paths)); + cl_git_pass(git_index_write(index)); git_index_free(index); cl_git_pass(git_repository_index(&index, g_repo)); cl_assert(git_index_version(index) == 4); - entry = git_index_get_bypath(index, "exec_off", 0); - cl_assert(entry); - entry = git_index_get_bypath(index, "exec_off2on_staged", 0); - cl_assert(entry); - entry = git_index_get_bypath(index, "exec_on", 0); - cl_assert(entry); + for (i = 0; i < ARRAY_SIZE(paths); i++) { + const git_index_entry *e; + + cl_assert(e = git_index_get_bypath(index, paths[i], 0)); + cl_assert_equal_s(paths[i], e->path); + } git_index_free(index); } -void test_index_version__cleanup(void) +void test_index_version__v4_uses_path_compression(void) { - cl_git_sandbox_cleanup(); - g_repo = NULL; + git_index_entry entry; + git_index *index; + char path[250], buf[1]; + struct stat st; + char i, j; + + memset(path, 'a', sizeof(path)); + memset(buf, 'a', sizeof(buf)); + + memset(&entry, 0, sizeof(entry)); + entry.path = path; + entry.mode = GIT_FILEMODE_BLOB; + + g_repo = cl_git_sandbox_init("indexv4"); + cl_git_pass(git_repository_index(&index, g_repo)); + + /* write 676 paths of 250 bytes length */ + for (i = 'a'; i <= 'z'; i++) { + for (j = 'a'; j < 'z'; j++) { + path[ARRAY_SIZE(path) - 3] = i; + path[ARRAY_SIZE(path) - 2] = j; + path[ARRAY_SIZE(path) - 1] = '\0'; + cl_git_pass(git_index_add_frombuffer(index, &entry, buf, sizeof(buf))); + } + } + + cl_git_pass(git_index_write(index)); + cl_git_pass(p_stat(git_index_path(index), &st)); + + /* + * Without path compression, the written paths would at + * least take + * + * (entries * pathlen) = len + * (676 * 250) = 169000 + * + * bytes. As index v4 uses suffix-compression and our + * written paths only differ in the last two entries, + * this number will be much smaller, e.g. + * + * (1 * pathlen) + (675 * 2) = len + * 676 + 1350 = 2026 + * + * bytes. + * + * Note that the above calculations do not include + * additional metadata of the index, e.g. OIDs or + * index extensions. Including those we get an index + * of approx. 200kB without compression and 40kB with + * compression. As this is a lot smaller than without + * compression, we can verify that path compression is + * used. + */ + cl_assert_(st.st_size < 75000, "path compression not enabled"); + + git_index_free(index); } diff --git a/tests/iterator/workdir.c b/tests/iterator/workdir.c index 28fcc0d23..f33fd98f1 100644 --- a/tests/iterator/workdir.c +++ b/tests/iterator/workdir.c @@ -613,9 +613,11 @@ void test_iterator_workdir__filesystem2(void) "heads/ident", "heads/long-file-name", "heads/master", + "heads/merge-conflict", "heads/packed-test", "heads/subtrees", "heads/test", + "heads/testrepo-worktree", "tags/e90810b", "tags/foo/bar", "tags/foo/foo/bar", @@ -628,7 +630,7 @@ void test_iterator_workdir__filesystem2(void) cl_git_pass(git_iterator_for_filesystem( &i, "testrepo/.git/refs", NULL)); - expect_iterator_items(i, 13, expect_base, 13, expect_base); + expect_iterator_items(i, 15, expect_base, 15, expect_base); git_iterator_free(i); } diff --git a/tests/merge/trees/renames.c b/tests/merge/trees/renames.c index d7721c894..853bf2fa0 100644 --- a/tests/merge/trees/renames.c +++ b/tests/merge/trees/renames.c @@ -242,6 +242,8 @@ void test_merge_trees_renames__no_rename_index(void) { 0100644, "b69fe837e4cecfd4c9a40cdca7c138468687df07", 3, "7-both-renamed.txt" }, }; + opts.flags &= ~GIT_MERGE_FIND_RENAMES; + cl_git_pass(merge_trees_from_branches(&index, repo, BRANCH_RENAME_OURS, BRANCH_RENAME_THEIRS, &opts)); @@ -250,3 +252,25 @@ void test_merge_trees_renames__no_rename_index(void) git_index_free(index); } + +void test_merge_trees_renames__submodules(void) +{ + git_index *index; + git_merge_options *opts = NULL; + + struct merge_index_entry merge_index_entries[] = { + { 0100644, "cd3e8d4aa06bdc781f264171030bc28f2b370fee", 0, ".gitmodules" }, + { 0100644, "4dd1ef7569b18d92d93c0a35bb6b93049137b355", 1, "file.txt" }, + { 0100644, "a2d8d1824c68541cca94ffb90f79291eba495921", 2, "file.txt" }, + { 0100644, "63ec604d491161ddafdae4179843c26d54bd999a", 3, "file.txt" }, + { 0160000, "0000000000000000000000000000000000000001", 1, "submodule1" }, + { 0160000, "0000000000000000000000000000000000000002", 3, "submodule1" }, + { 0160000, "0000000000000000000000000000000000000003", 0, "submodule2" }, + }; + + cl_git_pass(merge_trees_from_branches(&index, repo, + "submodule_rename1", "submodule_rename2", + opts)); + cl_assert(merge_test_index(index, merge_index_entries, 7)); + git_index_free(index); +} diff --git a/tests/network/remote/local.c b/tests/network/remote/local.c index 6194802af..76872e51f 100644 --- a/tests/network/remote/local.c +++ b/tests/network/remote/local.c @@ -2,6 +2,7 @@ #include "buffer.h" #include "path.h" #include "posix.h" +#include "git2/sys/repository.h" static git_repository *repo; static git_buf file_path_buf = GIT_BUF_INIT; @@ -465,3 +466,19 @@ void test_network_remote_local__push_delete(void) cl_fixture_cleanup("target.git"); cl_git_sandbox_cleanup(); } + +void test_network_remote_local__anonymous_remote_inmemory_repo(void) +{ + git_repository *inmemory; + git_remote *remote; + + git_buf_sets(&file_path_buf, cl_git_path_url(cl_fixture("testrepo.git"))); + + cl_git_pass(git_repository_new(&inmemory)); + cl_git_pass(git_remote_create_anonymous(&remote, inmemory, git_buf_cstr(&file_path_buf))); + cl_git_pass(git_remote_connect(remote, GIT_DIRECTION_FETCH, NULL, NULL, NULL)); + cl_assert(git_remote_connected(remote)); + git_remote_disconnect(remote); + git_remote_free(remote); + git_repository_free(inmemory); +} diff --git a/tests/object/lookup.c b/tests/object/lookup.c index cfa6d4678..544f32bc4 100644 --- a/tests/object/lookup.c +++ b/tests/object/lookup.c @@ -6,13 +6,12 @@ static git_repository *g_repo; void test_object_lookup__initialize(void) { - cl_git_pass(git_repository_open(&g_repo, cl_fixture("testrepo.git"))); + g_repo = cl_git_sandbox_init("testrepo.git"); } void test_object_lookup__cleanup(void) { - git_repository_free(g_repo); - g_repo = NULL; + cl_git_sandbox_cleanup(); } void test_object_lookup__lookup_wrong_type_returns_enotfound(void) @@ -63,3 +62,61 @@ void test_object_lookup__lookup_wrong_type_eventually_returns_enotfound(void) GIT_ENOTFOUND, git_object_lookup(&object, g_repo, &oid, GIT_OBJ_TAG)); } +void test_object_lookup__lookup_corrupt_object_returns_error(void) +{ + const char *commit = "8e73b769e97678d684b809b163bebdae2911720f", + *file = "objects/8e/73b769e97678d684b809b163bebdae2911720f"; + git_buf path = GIT_BUF_INIT, contents = GIT_BUF_INIT; + git_oid oid; + git_object *object; + size_t i; + + cl_git_pass(git_oid_fromstr(&oid, commit)); + cl_git_pass(git_buf_joinpath(&path, git_repository_path(g_repo), file)); + cl_git_pass(git_futils_readbuffer(&contents, path.ptr)); + + /* Corrupt and try to read the object */ + for (i = 0; i < contents.size; i++) { + contents.ptr[i] ^= 0x1; + cl_git_pass(git_futils_writebuffer(&contents, path.ptr, O_RDWR, 0644)); + cl_git_fail(git_object_lookup(&object, g_repo, &oid, GIT_OBJ_COMMIT)); + contents.ptr[i] ^= 0x1; + } + + /* Restore original content and assert we can read the object */ + cl_git_pass(git_futils_writebuffer(&contents, path.ptr, O_RDWR, 0644)); + cl_git_pass(git_object_lookup(&object, g_repo, &oid, GIT_OBJ_COMMIT)); + + git_object_free(object); + git_buf_free(&path); + git_buf_free(&contents); +} + +void test_object_lookup__lookup_object_with_wrong_hash_returns_error(void) +{ + const char *oldloose = "objects/8e/73b769e97678d684b809b163bebdae2911720f", + *newloose = "objects/8e/73b769e97678d684b809b163bebdae2911720e", + *commit = "8e73b769e97678d684b809b163bebdae2911720e"; + git_buf oldpath = GIT_BUF_INIT, newpath = GIT_BUF_INIT; + git_object *object; + git_oid oid; + + cl_git_pass(git_oid_fromstr(&oid, commit)); + + /* Copy object to another location with wrong hash */ + cl_git_pass(git_buf_joinpath(&oldpath, git_repository_path(g_repo), oldloose)); + cl_git_pass(git_buf_joinpath(&newpath, git_repository_path(g_repo), newloose)); + cl_git_pass(git_futils_cp(oldpath.ptr, newpath.ptr, 0644)); + + /* Verify that lookup fails due to a hashsum mismatch */ + cl_git_fail_with(GIT_EMISMATCH, git_object_lookup(&object, g_repo, &oid, GIT_OBJ_COMMIT)); + + /* Disable verification and try again */ + cl_git_pass(git_libgit2_opts(GIT_OPT_ENABLE_STRICT_HASH_VERIFICATION, 0)); + cl_git_pass(git_object_lookup(&object, g_repo, &oid, GIT_OBJ_COMMIT)); + cl_git_pass(git_libgit2_opts(GIT_OPT_ENABLE_STRICT_HASH_VERIFICATION, 1)); + + git_object_free(object); + git_buf_free(&oldpath); + git_buf_free(&newpath); +} diff --git a/tests/odb/backend/backend_helpers.c b/tests/odb/backend/backend_helpers.c new file mode 100644 index 000000000..37a8fd200 --- /dev/null +++ b/tests/odb/backend/backend_helpers.c @@ -0,0 +1,159 @@ +#include "clar_libgit2.h" +#include "git2/sys/odb_backend.h" +#include "backend_helpers.h" + +static int search_object(const fake_object **out, fake_backend *fake, const git_oid *oid, size_t len) +{ + const fake_object *obj = fake->objects, *found = NULL; + + while (obj && obj->oid) { + git_oid current_oid; + + git_oid_fromstr(¤t_oid, obj->oid); + + if (git_oid_ncmp(¤t_oid, oid, len) == 0) { + if (found) + return GIT_EAMBIGUOUS; + found = obj; + } + + obj++; + } + + if (found && out) + *out = found; + + return found ? GIT_OK : GIT_ENOTFOUND; +} + +static int fake_backend__exists(git_odb_backend *backend, const git_oid *oid) +{ + fake_backend *fake; + + fake = (fake_backend *)backend; + + fake->exists_calls++; + + return search_object(NULL, fake, oid, GIT_OID_HEXSZ) == GIT_OK; +} + +static int fake_backend__exists_prefix( + git_oid *out, git_odb_backend *backend, const git_oid *oid, size_t len) +{ + const fake_object *obj; + fake_backend *fake; + int error; + + fake = (fake_backend *)backend; + + fake->exists_prefix_calls++; + + if ((error = search_object(&obj, fake, oid, len)) < 0) + return error; + + if (out) + git_oid_fromstr(out, obj->oid); + + return 0; +} + +static int fake_backend__read( + void **buffer_p, size_t *len_p, git_otype *type_p, + git_odb_backend *backend, const git_oid *oid) +{ + const fake_object *obj; + fake_backend *fake; + int error; + + fake = (fake_backend *)backend; + + fake->read_calls++; + + if ((error = search_object(&obj, fake, oid, GIT_OID_HEXSZ)) < 0) + return error; + + *len_p = strlen(obj->content); + *buffer_p = git__strdup(obj->content); + *type_p = GIT_OBJ_BLOB; + + return 0; +} + +static int fake_backend__read_header( + size_t *len_p, git_otype *type_p, + git_odb_backend *backend, const git_oid *oid) +{ + const fake_object *obj; + fake_backend *fake; + int error; + + fake = (fake_backend *)backend; + + fake->read_header_calls++; + + if ((error = search_object(&obj, fake, oid, GIT_OID_HEXSZ)) < 0) + return error; + + *len_p = strlen(obj->content); + *type_p = GIT_OBJ_BLOB; + + return 0; +} + +static int fake_backend__read_prefix( + git_oid *out_oid, void **buffer_p, size_t *len_p, git_otype *type_p, + git_odb_backend *backend, const git_oid *short_oid, size_t len) +{ + const fake_object *obj; + fake_backend *fake; + int error; + + fake = (fake_backend *)backend; + + fake->read_prefix_calls++; + + if ((error = search_object(&obj, fake, short_oid, len)) < 0) + return error; + + git_oid_fromstr(out_oid, obj->oid); + *len_p = strlen(obj->content); + *buffer_p = git__strdup(obj->content); + *type_p = GIT_OBJ_BLOB; + + return 0; +} + +static void fake_backend__free(git_odb_backend *_backend) +{ + fake_backend *backend; + + backend = (fake_backend *)_backend; + + git__free(backend); +} + +int build_fake_backend( + git_odb_backend **out, + const fake_object *objects) +{ + fake_backend *backend; + + backend = git__calloc(1, sizeof(fake_backend)); + GITERR_CHECK_ALLOC(backend); + + backend->parent.version = GIT_ODB_BACKEND_VERSION; + + backend->parent.refresh = NULL; + backend->objects = objects; + + backend->parent.read = fake_backend__read; + backend->parent.read_prefix = fake_backend__read_prefix; + backend->parent.read_header = fake_backend__read_header; + backend->parent.exists = fake_backend__exists; + backend->parent.exists_prefix = fake_backend__exists_prefix; + backend->parent.free = &fake_backend__free; + + *out = (git_odb_backend *)backend; + + return 0; +} diff --git a/tests/odb/backend/backend_helpers.h b/tests/odb/backend/backend_helpers.h new file mode 100644 index 000000000..5c393c0a5 --- /dev/null +++ b/tests/odb/backend/backend_helpers.h @@ -0,0 +1,22 @@ +#include "git2/sys/odb_backend.h" + +typedef struct { + const char *oid; + const char *content; +} fake_object; + +typedef struct { + git_odb_backend parent; + + int exists_calls; + int exists_prefix_calls; + int read_calls; + int read_header_calls; + int read_prefix_calls; + + const fake_object *objects; +} fake_backend; + +int build_fake_backend( + git_odb_backend **out, + const fake_object *objects); diff --git a/tests/odb/backend/multiple.c b/tests/odb/backend/multiple.c new file mode 100644 index 000000000..1c6068df3 --- /dev/null +++ b/tests/odb/backend/multiple.c @@ -0,0 +1,121 @@ +#include "clar_libgit2.h" +#include "repository.h" +#include "backend_helpers.h" + +#define EXISTING_HASH "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391" + +static git_repository *_repo; +static git_odb_object *_obj; +static fake_backend *_fake_empty; +static fake_backend *_fake_filled; + +static git_oid _existing_oid; + +static const fake_object _objects_filled[] = { + { EXISTING_HASH, "" }, + { NULL, NULL } +}; + +static const fake_object _objects_empty[] = { + { NULL, NULL } +}; + +void test_odb_backend_multiple__initialize(void) +{ + git_odb_backend *backend; + + git_oid_fromstr(&_existing_oid, EXISTING_HASH); + + _obj = NULL; + _repo = cl_git_sandbox_init("testrepo.git"); + + cl_git_pass(build_fake_backend(&backend, _objects_filled)); + _fake_filled = (fake_backend *)backend; + + cl_git_pass(build_fake_backend(&backend, _objects_empty)); + _fake_empty = (fake_backend *)backend; +} + +void test_odb_backend_multiple__cleanup(void) +{ + git_odb_object_free(_obj); + cl_git_sandbox_cleanup(); +} + +void test_odb_backend_multiple__read_with_empty_first_succeeds(void) +{ + git_odb *odb; + + cl_git_pass(git_repository_odb__weakptr(&odb, _repo)); + cl_git_pass(git_odb_add_backend(odb, (git_odb_backend *)_fake_filled, 10)); + cl_git_pass(git_odb_add_backend(odb, (git_odb_backend *)_fake_empty, 50)); + + cl_git_pass(git_odb_read(&_obj, odb, &_existing_oid)); + + cl_assert_equal_i(1, _fake_filled->read_calls); + cl_assert_equal_i(1, _fake_empty->read_calls); +} + +void test_odb_backend_multiple__read_with_first_matching_stops(void) +{ + git_odb *odb; + + cl_git_pass(git_repository_odb__weakptr(&odb, _repo)); + cl_git_pass(git_odb_add_backend(odb, (git_odb_backend *)_fake_empty, 10)); + cl_git_pass(git_odb_add_backend(odb, (git_odb_backend *)_fake_filled, 50)); + + cl_git_pass(git_odb_read(&_obj, odb, &_existing_oid)); + + cl_assert_equal_i(1, _fake_filled->read_calls); + cl_assert_equal_i(0, _fake_empty->read_calls); +} + +void test_odb_backend_multiple__read_prefix_with_first_empty_succeeds(void) +{ + git_odb *odb; + + cl_git_pass(git_repository_odb__weakptr(&odb, _repo)); + cl_git_pass(git_odb_add_backend(odb, (git_odb_backend *)_fake_filled, 10)); + cl_git_pass(git_odb_add_backend(odb, (git_odb_backend *)_fake_empty, 50)); + + cl_git_pass(git_odb_read_prefix(&_obj, odb, &_existing_oid, 7)); + + cl_assert_equal_i(1, _fake_filled->read_prefix_calls); + cl_assert_equal_i(1, _fake_empty->read_prefix_calls); +} + +void test_odb_backend_multiple__read_prefix_with_first_matching_reads_both(void) +{ + git_odb *odb; + + cl_git_pass(git_repository_odb__weakptr(&odb, _repo)); + cl_git_pass(git_odb_add_backend(odb, (git_odb_backend *)_fake_empty, -10)); + cl_git_pass(git_odb_add_backend(odb, (git_odb_backend *)_fake_filled, 50)); + + cl_git_pass(git_odb_read_prefix(&_obj, odb, &_existing_oid, 7)); + + cl_assert_equal_i(1, _fake_filled->read_prefix_calls); + cl_assert_equal_i(1, _fake_empty->read_prefix_calls); +} + +void test_odb_backend_multiple__read_prefix_with_first_matching_succeeds_without_hash_verification(void) +{ + git_odb *odb; + + git_libgit2_opts(GIT_OPT_ENABLE_STRICT_HASH_VERIFICATION, 0); + + cl_git_pass(git_repository_odb__weakptr(&odb, _repo)); + cl_git_pass(git_odb_add_backend(odb, (git_odb_backend *)_fake_empty, -10)); + cl_git_pass(git_odb_add_backend(odb, (git_odb_backend *)_fake_filled, 50)); + + cl_git_pass(git_odb_read_prefix(&_obj, odb, &_existing_oid, 7)); + + /* + * Both backends should be checked as we have to check + * for collisions + */ + cl_assert_equal_i(1, _fake_filled->read_prefix_calls); + cl_assert_equal_i(1, _fake_empty->read_prefix_calls); + + git_libgit2_opts(GIT_OPT_ENABLE_STRICT_HASH_VERIFICATION, 1); +} diff --git a/tests/odb/backend/nobackend.c b/tests/odb/backend/nobackend.c index 783641e8f..3c4f344b1 100644 --- a/tests/odb/backend/nobackend.c +++ b/tests/odb/backend/nobackend.c @@ -40,7 +40,7 @@ void test_odb_backend_nobackend__write_fails_gracefully(void) cl_git_fail(git_odb_write(&id, odb, "Hello world!\n", 13, GIT_OBJ_BLOB)); err = giterr_last(); - cl_assert_equal_s(err->message, "Cannot write object - unsupported in the loaded odb backends"); + cl_assert_equal_s(err->message, "cannot write object - unsupported in the loaded odb backends"); git_odb_free(odb); } diff --git a/tests/odb/backend/nonrefreshing.c b/tests/odb/backend/nonrefreshing.c index b43529479..6abc0c6d2 100644 --- a/tests/odb/backend/nonrefreshing.c +++ b/tests/odb/backend/nonrefreshing.c @@ -1,150 +1,41 @@ #include "clar_libgit2.h" -#include "git2/sys/odb_backend.h" #include "repository.h" - -typedef struct fake_backend { - git_odb_backend parent; - - git_error_code error_code; - - int exists_calls; - int read_calls; - int read_header_calls; - int read_prefix_calls; -} fake_backend; +#include "backend_helpers.h" static git_repository *_repo; static fake_backend *_fake; -static git_oid _oid; -static int fake_backend__exists(git_odb_backend *backend, const git_oid *oid) -{ - fake_backend *fake; +#define NONEXISTING_HASH "deadbeefdeadbeefdeadbeefdeadbeefdeadbeef" +#define EXISTING_HASH "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391" - GIT_UNUSED(oid); +static const fake_object _objects[] = { + { EXISTING_HASH, "" }, + { NULL, NULL } +}; - fake = (fake_backend *)backend; +static git_oid _nonexisting_oid; +static git_oid _existing_oid; - fake->exists_calls++; - - return (fake->error_code == GIT_OK); -} - -static int fake_backend__read( - void **buffer_p, size_t *len_p, git_otype *type_p, - git_odb_backend *backend, const git_oid *oid) -{ - fake_backend *fake; - - GIT_UNUSED(buffer_p); - GIT_UNUSED(len_p); - GIT_UNUSED(type_p); - GIT_UNUSED(oid); - - fake = (fake_backend *)backend; - - fake->read_calls++; - - *len_p = 0; - *buffer_p = NULL; - *type_p = GIT_OBJ_BLOB; - - return fake->error_code; -} - -static int fake_backend__read_header( - size_t *len_p, git_otype *type_p, - git_odb_backend *backend, const git_oid *oid) -{ - fake_backend *fake; - - GIT_UNUSED(len_p); - GIT_UNUSED(type_p); - GIT_UNUSED(oid); - - fake = (fake_backend *)backend; - - fake->read_header_calls++; - - *len_p = 0; - *type_p = GIT_OBJ_BLOB; - - return fake->error_code; -} - -static int fake_backend__read_prefix( - git_oid *out_oid, void **buffer_p, size_t *len_p, git_otype *type_p, - git_odb_backend *backend, const git_oid *short_oid, size_t len) -{ - fake_backend *fake; - - GIT_UNUSED(out_oid); - GIT_UNUSED(buffer_p); - GIT_UNUSED(len_p); - GIT_UNUSED(type_p); - GIT_UNUSED(short_oid); - GIT_UNUSED(len); - - fake = (fake_backend *)backend; - - fake->read_prefix_calls++; - - *len_p = 0; - *buffer_p = NULL; - *type_p = GIT_OBJ_BLOB; - - return fake->error_code; -} - -static void fake_backend__free(git_odb_backend *_backend) -{ - fake_backend *backend; - - backend = (fake_backend *)_backend; - - git__free(backend); -} - -static int build_fake_backend( - git_odb_backend **out, - git_error_code error_code) -{ - fake_backend *backend; - - backend = git__calloc(1, sizeof(fake_backend)); - GITERR_CHECK_ALLOC(backend); - - backend->parent.version = GIT_ODB_BACKEND_VERSION; - - backend->parent.refresh = NULL; - backend->error_code = error_code; - - backend->parent.read = fake_backend__read; - backend->parent.read_prefix = fake_backend__read_prefix; - backend->parent.read_header = fake_backend__read_header; - backend->parent.exists = fake_backend__exists; - backend->parent.free = &fake_backend__free; - - *out = (git_odb_backend *)backend; - - return 0; -} - -static void setup_repository_and_backend(git_error_code error_code) +static void setup_repository_and_backend(void) { git_odb *odb = NULL; git_odb_backend *backend = NULL; _repo = cl_git_sandbox_init("testrepo.git"); - cl_git_pass(build_fake_backend(&backend, error_code)); + cl_git_pass(build_fake_backend(&backend, _objects)); cl_git_pass(git_repository_odb__weakptr(&odb, _repo)); cl_git_pass(git_odb_add_backend(odb, backend, 10)); _fake = (fake_backend *)backend; +} - cl_git_pass(git_oid_fromstr(&_oid, "deadbeefdeadbeefdeadbeefdeadbeefdeadbeef")); +void test_odb_backend_nonrefreshing__initialize(void) +{ + git_oid_fromstr(&_nonexisting_oid, NONEXISTING_HASH); + git_oid_fromstr(&_existing_oid, EXISTING_HASH); + setup_repository_and_backend(); } void test_odb_backend_nonrefreshing__cleanup(void) @@ -156,10 +47,8 @@ void test_odb_backend_nonrefreshing__exists_is_invoked_once_on_failure(void) { git_odb *odb; - setup_repository_and_backend(GIT_ENOTFOUND); - cl_git_pass(git_repository_odb__weakptr(&odb, _repo)); - cl_assert_equal_b(false, git_odb_exists(odb, &_oid)); + cl_assert_equal_b(false, git_odb_exists(odb, &_nonexisting_oid)); cl_assert_equal_i(1, _fake->exists_calls); } @@ -168,10 +57,8 @@ void test_odb_backend_nonrefreshing__read_is_invoked_once_on_failure(void) { git_object *obj; - setup_repository_and_backend(GIT_ENOTFOUND); - cl_git_fail_with( - git_object_lookup(&obj, _repo, &_oid, GIT_OBJ_ANY), + git_object_lookup(&obj, _repo, &_nonexisting_oid, GIT_OBJ_ANY), GIT_ENOTFOUND); cl_assert_equal_i(1, _fake->read_calls); @@ -181,10 +68,8 @@ void test_odb_backend_nonrefreshing__readprefix_is_invoked_once_on_failure(void) { git_object *obj; - setup_repository_and_backend(GIT_ENOTFOUND); - cl_git_fail_with( - git_object_lookup_prefix(&obj, _repo, &_oid, 7, GIT_OBJ_ANY), + git_object_lookup_prefix(&obj, _repo, &_nonexisting_oid, 7, GIT_OBJ_ANY), GIT_ENOTFOUND); cl_assert_equal_i(1, _fake->read_prefix_calls); @@ -196,12 +81,10 @@ void test_odb_backend_nonrefreshing__readheader_is_invoked_once_on_failure(void) size_t len; git_otype type; - setup_repository_and_backend(GIT_ENOTFOUND); - cl_git_pass(git_repository_odb__weakptr(&odb, _repo)); cl_git_fail_with( - git_odb_read_header(&len, &type, odb, &_oid), + git_odb_read_header(&len, &type, odb, &_nonexisting_oid), GIT_ENOTFOUND); cl_assert_equal_i(1, _fake->read_header_calls); @@ -211,10 +94,8 @@ void test_odb_backend_nonrefreshing__exists_is_invoked_once_on_success(void) { git_odb *odb; - setup_repository_and_backend(GIT_OK); - cl_git_pass(git_repository_odb__weakptr(&odb, _repo)); - cl_assert_equal_b(true, git_odb_exists(odb, &_oid)); + cl_assert_equal_b(true, git_odb_exists(odb, &_existing_oid)); cl_assert_equal_i(1, _fake->exists_calls); } @@ -223,9 +104,7 @@ void test_odb_backend_nonrefreshing__read_is_invoked_once_on_success(void) { git_object *obj; - setup_repository_and_backend(GIT_OK); - - cl_git_pass(git_object_lookup(&obj, _repo, &_oid, GIT_OBJ_ANY)); + cl_git_pass(git_object_lookup(&obj, _repo, &_existing_oid, GIT_OBJ_ANY)); cl_assert_equal_i(1, _fake->read_calls); @@ -236,9 +115,7 @@ void test_odb_backend_nonrefreshing__readprefix_is_invoked_once_on_success(void) { git_object *obj; - setup_repository_and_backend(GIT_OK); - - cl_git_pass(git_object_lookup_prefix(&obj, _repo, &_oid, 7, GIT_OBJ_ANY)); + cl_git_pass(git_object_lookup_prefix(&obj, _repo, &_existing_oid, 7, GIT_OBJ_ANY)); cl_assert_equal_i(1, _fake->read_prefix_calls); @@ -251,11 +128,9 @@ void test_odb_backend_nonrefreshing__readheader_is_invoked_once_on_success(void) size_t len; git_otype type; - setup_repository_and_backend(GIT_OK); - cl_git_pass(git_repository_odb__weakptr(&odb, _repo)); - cl_git_pass(git_odb_read_header(&len, &type, odb, &_oid)); + cl_git_pass(git_odb_read_header(&len, &type, odb, &_existing_oid)); cl_assert_equal_i(1, _fake->read_header_calls); } @@ -264,8 +139,6 @@ void test_odb_backend_nonrefreshing__read_is_invoked_once_when_revparsing_a_full { git_object *obj; - setup_repository_and_backend(GIT_ENOTFOUND); - cl_git_fail_with( git_revparse_single(&obj, _repo, "deadbeefdeadbeefdeadbeefdeadbeefdeadbeef"), GIT_ENOTFOUND); diff --git a/tests/odb/backend/simple.c b/tests/odb/backend/simple.c new file mode 100644 index 000000000..c0fcd403b --- /dev/null +++ b/tests/odb/backend/simple.c @@ -0,0 +1,232 @@ +#include "clar_libgit2.h" +#include "repository.h" +#include "backend_helpers.h" + +#define EMPTY_HASH "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391" + +static git_repository *_repo; +static git_odb *_odb; +static git_odb_object *_obj; +static git_oid _oid; + +static void setup_backend(const fake_object *objs) +{ + git_odb_backend *backend; + + cl_git_pass(build_fake_backend(&backend, objs)); + + cl_git_pass(git_repository_odb__weakptr(&_odb, _repo)); + cl_git_pass(git_odb_add_backend(_odb, backend, 10)); +} + +static void assert_object_contains(git_odb_object *obj, const char *expected) +{ + const char *actual = (const char *) git_odb_object_data(obj); + + cl_assert_equal_s(actual, expected); +} + +void test_odb_backend_simple__initialize(void) +{ + _repo = cl_git_sandbox_init("testrepo.git"); + _odb = NULL; + _obj = NULL; +} + +void test_odb_backend_simple__cleanup(void) +{ + git_odb_object_free(_obj); + cl_git_sandbox_cleanup(); + cl_git_pass(git_libgit2_opts(GIT_OPT_ENABLE_STRICT_HASH_VERIFICATION, 1)); +} + +void test_odb_backend_simple__read_of_object_succeeds(void) +{ + const fake_object objs[] = { + { "f6ea0495187600e7b2288c8ac19c5886383a4632", "foobar" }, + { NULL, NULL } + }; + + setup_backend(objs); + + cl_git_pass(git_oid_fromstr(&_oid, objs[0].oid)); + cl_git_pass(git_odb_read(&_obj, _odb, &_oid)); + + assert_object_contains(_obj, objs[0].content); +} + +void test_odb_backend_simple__read_of_nonexisting_object_fails(void) +{ + const fake_object objs[] = { + { "f6ea0495187600e7b2288c8ac19c5886383a4632", "foobar" }, + { NULL, NULL } + }; + + setup_backend(objs); + + cl_git_pass(git_oid_fromstr(&_oid, "f6ea0495187600e7b2288c8ac19c5886383a4633")); + cl_git_fail_with(GIT_ENOTFOUND, git_odb_read(&_obj, _odb, &_oid)); +} + +void test_odb_backend_simple__read_with_hash_mismatch_fails(void) +{ + const fake_object objs[] = { + { "1234567890123456789012345678901234567890", "nonmatching content" }, + { NULL, NULL } + }; + + setup_backend(objs); + + cl_git_pass(git_oid_fromstr(&_oid, objs[0].oid)); + cl_git_fail_with(GIT_EMISMATCH, git_odb_read(&_obj, _odb, &_oid)); +} + +void test_odb_backend_simple__read_with_hash_mismatch_succeeds_without_verification(void) +{ + const fake_object objs[] = { + { "1234567890123456789012345678901234567890", "nonmatching content" }, + { NULL, NULL } + }; + + setup_backend(objs); + cl_git_pass(git_oid_fromstr(&_oid, objs[0].oid)); + + cl_git_pass(git_libgit2_opts(GIT_OPT_ENABLE_STRICT_HASH_VERIFICATION, 0)); + cl_git_pass(git_odb_read(&_obj, _odb, &_oid)); + + assert_object_contains(_obj, objs[0].content); +} + +void test_odb_backend_simple__read_prefix_succeeds(void) +{ + const fake_object objs[] = { + { "f6ea0495187600e7b2288c8ac19c5886383a4632", "foobar" }, + { NULL, NULL } + }; + + setup_backend(objs); + + cl_git_pass(git_oid_fromstr(&_oid, "f6ea0495187600e7b2288c8ac19c5886383a4632")); + cl_git_pass(git_odb_read(&_obj, _odb, &_oid)); + + assert_object_contains(_obj, objs[0].content); +} + +void test_odb_backend_simple__read_prefix_of_nonexisting_object_fails(void) +{ + const fake_object objs[] = { + { "f6ea0495187600e7b2288c8ac19c5886383a4632", "foobar" }, + { NULL, NULL } + }; + char *hash = "f6ea0495187600e8"; + + setup_backend(objs); + + cl_git_pass(git_oid_fromstrn(&_oid, hash, strlen(hash))); + cl_git_fail_with(GIT_ENOTFOUND, git_odb_read(&_obj, _odb, &_oid)); +} + +void test_odb_backend_simple__read_with_ambiguous_prefix_fails(void) +{ + const fake_object objs[] = { + { "1234567890111111111111111111111111111111", "first content" }, + { "1234567890222222222222222222222222222222", "second content" }, + { NULL, NULL } + }; + + setup_backend(objs); + + cl_git_pass(git_oid_fromstr(&_oid, objs[0].oid)); + cl_git_fail_with(GIT_EAMBIGUOUS, git_odb_read_prefix(&_obj, _odb, &_oid, 7)); +} + +void test_odb_backend_simple__read_with_highly_ambiguous_prefix(void) +{ + const fake_object objs[] = { + { "1234567890111111111111111111111111111111", "first content" }, + { "1234567890111111111111111111111111111112", "second content" }, + { NULL, NULL } + }; + + setup_backend(objs); + + cl_git_pass(git_oid_fromstr(&_oid, objs[0].oid)); + cl_git_pass(git_libgit2_opts(GIT_OPT_ENABLE_STRICT_HASH_VERIFICATION, 0)); + cl_git_fail_with(GIT_EAMBIGUOUS, git_odb_read_prefix(&_obj, _odb, &_oid, 39)); + cl_git_pass(git_odb_read_prefix(&_obj, _odb, &_oid, 40)); + assert_object_contains(_obj, objs[0].content); +} + +void test_odb_backend_simple__exists_succeeds(void) +{ + const fake_object objs[] = { + { "f6ea0495187600e7b2288c8ac19c5886383a4632", "foobar" }, + { NULL, NULL } + }; + + setup_backend(objs); + + cl_git_pass(git_oid_fromstr(&_oid, objs[0].oid)); + cl_assert(git_odb_exists(_odb, &_oid)); +} + +void test_odb_backend_simple__exists_fails_for_nonexisting_object(void) +{ + const fake_object objs[] = { + { "f6ea0495187600e7b2288c8ac19c5886383a4632", "foobar" }, + { NULL, NULL } + }; + + setup_backend(objs); + + cl_git_pass(git_oid_fromstr(&_oid, "f6ea0495187600e7b2288c8ac19c5886383a4633")); + cl_assert(git_odb_exists(_odb, &_oid) == 0); +} + +void test_odb_backend_simple__exists_prefix_succeeds(void) +{ + const fake_object objs[] = { + { "1234567890111111111111111111111111111111", "first content" }, + { "1234567890222222222222222222222222222222", "second content" }, + { NULL, NULL } + }; + git_oid found; + + setup_backend(objs); + + cl_git_pass(git_oid_fromstr(&_oid, objs[0].oid)); + cl_git_pass(git_odb_exists_prefix(&found, _odb, &_oid, 12)); + cl_assert(git_oid_equal(&found, &_oid)); +} + +void test_odb_backend_simple__exists_with_ambiguous_prefix_fails(void) +{ + const fake_object objs[] = { + { "1234567890111111111111111111111111111111", "first content" }, + { "1234567890222222222222222222222222222222", "second content" }, + { NULL, NULL } + }; + + setup_backend(objs); + + cl_git_pass(git_oid_fromstr(&_oid, objs[0].oid)); + cl_git_fail_with(GIT_EAMBIGUOUS, git_odb_exists_prefix(NULL, _odb, &_oid, 7)); +} + +void test_odb_backend_simple__exists_with_highly_ambiguous_prefix(void) +{ + const fake_object objs[] = { + { "1234567890111111111111111111111111111111", "first content" }, + { "1234567890111111111111111111111111111112", "second content" }, + { NULL, NULL } + }; + git_oid found; + + setup_backend(objs); + + cl_git_pass(git_oid_fromstr(&_oid, objs[0].oid)); + cl_git_pass(git_libgit2_opts(GIT_OPT_ENABLE_STRICT_HASH_VERIFICATION, 0)); + cl_git_fail_with(GIT_EAMBIGUOUS, git_odb_exists_prefix(&found, _odb, &_oid, 39)); + cl_git_pass(git_odb_exists_prefix(&found, _odb, &_oid, 40)); + cl_assert(git_oid_equal(&found, &_oid)); +} diff --git a/tests/odb/freshen.c b/tests/odb/freshen.c index d8d6c029a..9d3cf51dc 100644 --- a/tests/odb/freshen.c +++ b/tests/odb/freshen.c @@ -17,36 +17,126 @@ void test_odb_freshen__cleanup(void) cl_git_sandbox_cleanup(); } -#define LOOSE_STR "hey\n" -#define LOOSE_ID "1385f264afb75a56a5bec74243be9b367ba4ca08" -#define LOOSE_FN "13/85f264afb75a56a5bec74243be9b367ba4ca08" +static void set_time_wayback(struct stat *out, const char *fn) +{ + git_buf fullpath = GIT_BUF_INIT; + struct p_timeval old[2]; -void test_odb_freshen__loose_object(void) + old[0].tv_sec = 1234567890; + old[0].tv_usec = 0; + old[1].tv_sec = 1234567890; + old[1].tv_usec = 0; + + git_buf_joinpath(&fullpath, "testrepo.git/objects", fn); + + cl_must_pass(p_utimes(git_buf_cstr(&fullpath), old)); + cl_must_pass(p_lstat(git_buf_cstr(&fullpath), out)); + git_buf_free(&fullpath); +} + +#define LOOSE_STR "my new file\n" +#define LOOSE_BLOB_ID "a71586c1dfe8a71c6cbf6c129f404c5642ff31bd" +#define LOOSE_BLOB_FN "a7/1586c1dfe8a71c6cbf6c129f404c5642ff31bd" + +void test_odb_freshen__loose_blob(void) { git_oid expected_id, id; struct stat before, after; - struct p_timeval old_times[2]; - cl_git_pass(git_oid_fromstr(&expected_id, LOOSE_ID)); + cl_git_pass(git_oid_fromstr(&expected_id, LOOSE_BLOB_ID)); + set_time_wayback(&before, LOOSE_BLOB_FN); - old_times[0].tv_sec = 1234567890; - old_times[0].tv_usec = 0; - old_times[1].tv_sec = 1234567890; - old_times[1].tv_usec = 0; - - /* set time to way back */ - cl_must_pass(p_utimes("testrepo.git/objects/" LOOSE_FN, old_times)); - cl_must_pass(p_lstat("testrepo.git/objects/" LOOSE_FN, &before)); - - cl_git_pass(git_odb_write(&id, odb, LOOSE_STR, CONST_STRLEN(LOOSE_STR), - GIT_OBJ_BLOB)); + /* make sure we freshen a blob */ + cl_git_pass(git_blob_create_frombuffer(&id, repo, LOOSE_STR, CONST_STRLEN(LOOSE_STR))); cl_assert_equal_oid(&expected_id, &id); - cl_must_pass(p_lstat("testrepo.git/objects/" LOOSE_FN, &after)); + cl_must_pass(p_lstat("testrepo.git/objects/" LOOSE_BLOB_FN, &after)); cl_assert(before.st_atime < after.st_atime); cl_assert(before.st_mtime < after.st_mtime); } +#define UNIQUE_STR "doesnt exist in the odb yet\n" +#define UNIQUE_BLOB_ID "78a87d0b8878c5953b9a63015ff4e22a3d898826" +#define UNIQUE_BLOB_FN "78/a87d0b8878c5953b9a63015ff4e22a3d898826" + +void test_odb_freshen__readonly_object(void) +{ + git_oid expected_id, id; + struct stat before, after; + + cl_git_pass(git_oid_fromstr(&expected_id, UNIQUE_BLOB_ID)); + + cl_git_pass(git_blob_create_frombuffer(&id, repo, UNIQUE_STR, CONST_STRLEN(UNIQUE_STR))); + cl_assert_equal_oid(&expected_id, &id); + + set_time_wayback(&before, UNIQUE_BLOB_FN); + cl_assert((before.st_mode & S_IWUSR) == 0); + + cl_git_pass(git_blob_create_frombuffer(&id, repo, UNIQUE_STR, CONST_STRLEN(UNIQUE_STR))); + cl_assert_equal_oid(&expected_id, &id); + cl_must_pass(p_lstat("testrepo.git/objects/" UNIQUE_BLOB_FN, &after)); + + cl_assert(before.st_atime < after.st_atime); + cl_assert(before.st_mtime < after.st_mtime); +} + +#define LOOSE_TREE_ID "944c0f6e4dfa41595e6eb3ceecdb14f50fe18162" +#define LOOSE_TREE_FN "94/4c0f6e4dfa41595e6eb3ceecdb14f50fe18162" + +void test_odb_freshen__loose_tree(void) +{ + git_oid expected_id, id; + git_tree *tree; + struct stat before, after; + + cl_git_pass(git_oid_fromstr(&expected_id, LOOSE_TREE_ID)); + set_time_wayback(&before, LOOSE_TREE_FN); + + cl_git_pass(git_tree_lookup(&tree, repo, &expected_id)); + cl_git_pass(git_tree_create_updated(&id, repo, tree, 0, NULL)); + + /* make sure we freshen a tree */ + cl_assert_equal_oid(&expected_id, &id); + cl_must_pass(p_lstat("testrepo.git/objects/" LOOSE_TREE_FN, &after)); + + cl_assert(before.st_atime < after.st_atime); + cl_assert(before.st_mtime < after.st_mtime); + + git_tree_free(tree); +} + +void test_odb_freshen__tree_during_commit(void) +{ + git_oid tree_id, parent_id, commit_id; + git_tree *tree; + git_commit *parent; + git_signature *signature; + struct stat before, after; + + cl_git_pass(git_oid_fromstr(&tree_id, LOOSE_TREE_ID)); + cl_git_pass(git_tree_lookup(&tree, repo, &tree_id)); + set_time_wayback(&before, LOOSE_TREE_FN); + + cl_git_pass(git_oid_fromstr(&parent_id, "a65fedf39aefe402d3bb6e24df4d4f5fe4547750")); + cl_git_pass(git_commit_lookup(&parent, repo, &parent_id)); + + cl_git_pass(git_signature_new(&signature, + "Refresher", "refresher@example.com", 1488547083, 0)); + + cl_git_pass(git_commit_create(&commit_id, repo, NULL, + signature, signature, NULL, "New commit pointing to old tree", + tree, 1, (const git_commit **)&parent)); + + /* make sure we freshen the tree the commit points to */ + cl_must_pass(p_lstat("testrepo.git/objects/" LOOSE_TREE_FN, &after)); + cl_assert(before.st_atime < after.st_atime); + cl_assert(before.st_mtime < after.st_mtime); + + git_signature_free(signature); + git_commit_free(parent); + git_tree_free(tree); +} + #define PACKED_STR "Testing a readme.txt\n" #define PACKED_ID "6336846bd5c88d32f93ae57d846683e61ab5c530" #define PACKED_FN "pack-d85f5d483273108c9d8dd0e4728ccf0b2982423a.pack" diff --git a/tests/odb/loose.c b/tests/odb/loose.c index c91927c4a..2e24d6723 100644 --- a/tests/odb/loose.c +++ b/tests/odb/loose.c @@ -3,6 +3,7 @@ #include "git2/odb_backend.h" #include "posix.h" #include "loose_data.h" +#include "repository.h" #ifdef __ANDROID_API__ # define S_IREAD S_IRUSR @@ -56,11 +57,13 @@ static void test_read_object(object_data *data) void test_odb_loose__initialize(void) { + p_fsync__cnt = 0; cl_must_pass(p_mkdir("test-objects", GIT_OBJECT_DIR_MODE)); } void test_odb_loose__cleanup(void) { + cl_git_pass(git_libgit2_opts(GIT_OPT_ENABLE_FSYNC_GITDIR, 0)); cl_fixture_cleanup("test-objects"); } @@ -150,3 +153,55 @@ void test_odb_loose__permissions_readwrite(void) { test_write_object_permission(0777, 0666, 0777, 0666); } + +static void write_object_to_loose_odb(int fsync) +{ + git_odb *odb; + git_odb_backend *backend; + git_oid oid; + + cl_git_pass(git_odb_new(&odb)); + cl_git_pass(git_odb_backend_loose(&backend, "test-objects", -1, fsync, 0777, 0666)); + cl_git_pass(git_odb_add_backend(odb, backend, 1)); + cl_git_pass(git_odb_write(&oid, odb, "Test data\n", 10, GIT_OBJ_BLOB)); + git_odb_free(odb); +} + +void test_odb_loose__does_not_fsync_by_default(void) +{ + write_object_to_loose_odb(0); + cl_assert_equal_sz(0, p_fsync__cnt); +} + +void test_odb_loose__fsync_obeys_odb_option(void) +{ + write_object_to_loose_odb(1); + cl_assert(p_fsync__cnt > 0); +} + +void test_odb_loose__fsync_obeys_global_setting(void) +{ + cl_git_pass(git_libgit2_opts(GIT_OPT_ENABLE_FSYNC_GITDIR, 1)); + write_object_to_loose_odb(0); + cl_assert(p_fsync__cnt > 0); +} + +void test_odb_loose__fsync_obeys_repo_setting(void) +{ + git_repository *repo; + git_odb *odb; + git_oid oid; + + cl_git_pass(git_repository_init(&repo, "test-objects", 1)); + cl_git_pass(git_repository_odb__weakptr(&odb, repo)); + cl_git_pass(git_odb_write(&oid, odb, "No fsync here\n", 14, GIT_OBJ_BLOB)); + cl_assert(p_fsync__cnt == 0); + git_repository_free(repo); + + cl_git_pass(git_repository_open(&repo, "test-objects")); + cl_repo_set_bool(repo, "core.fsyncObjectFiles", true); + cl_git_pass(git_repository_odb__weakptr(&odb, repo)); + cl_git_pass(git_odb_write(&oid, odb, "Now fsync\n", 10, GIT_OBJ_BLOB)); + cl_assert(p_fsync__cnt > 0); + git_repository_free(repo); +} diff --git a/tests/online/badssl.c b/tests/online/badssl.c index aa4c24d9c..6524fcd8e 100644 --- a/tests/online/badssl.c +++ b/tests/online/badssl.c @@ -4,7 +4,7 @@ static git_repository *g_repo; -#if defined(GIT_OPENSSL) || defined(GIT_WINHTTP) || defined(GIT_SECURE_TRANSPORT) +#ifdef GIT_HTTPS static bool g_has_ssl = true; #else static bool g_has_ssl = false; diff --git a/tests/pack/indexer.c b/tests/pack/indexer.c index 49a106d98..c73d3974e 100644 --- a/tests/pack/indexer.c +++ b/tests/pack/indexer.c @@ -85,7 +85,7 @@ void test_pack_indexer__fix_thin(void) cl_assert_equal_i(stats.indexed_objects, 2); cl_assert_equal_i(stats.local_objects, 1); - git_oid_fromstr(&should_id, "11f0f69b334728fdd8bc86b80499f22f29d85b15"); + git_oid_fromstr(&should_id, "fefdb2d740a3a6b6c03a0c7d6ce431c6d5810e13"); cl_assert_equal_oid(&should_id, git_indexer_hash(idx)); git_indexer_free(idx); @@ -102,7 +102,7 @@ void test_pack_indexer__fix_thin(void) int fd; ssize_t read; struct stat st; - const char *name = "pack-11f0f69b334728fdd8bc86b80499f22f29d85b15.pack"; + const char *name = "pack-fefdb2d740a3a6b6c03a0c7d6ce431c6d5810e13.pack"; fd = p_open(name, O_RDONLY); cl_assert(fd != -1); @@ -125,3 +125,44 @@ void test_pack_indexer__fix_thin(void) git_indexer_free(idx); } } + +static int find_tmp_file_recurs(void *opaque, git_buf *path) +{ + int error = 0; + git_buf *first_tmp_file = opaque; + struct stat st; + + if ((error = p_lstat_posixly(path->ptr, &st)) < 0) + return error; + + if (S_ISDIR(st.st_mode)) + return git_path_direach(path, 0, find_tmp_file_recurs, opaque); + + /* This is the template that's used in git_futils_mktmp. */ + if (strstr(git_buf_cstr(path), "_git2_") != NULL) + return git_buf_sets(first_tmp_file, git_buf_cstr(path)); + + return 0; +} + +void test_pack_indexer__no_tmp_files(void) +{ + git_indexer *idx = NULL; + git_buf path = GIT_BUF_INIT; + git_buf first_tmp_file = GIT_BUF_INIT; + + /* Precondition: there are no temporary files. */ + cl_git_pass(git_buf_sets(&path, clar_sandbox_path())); + cl_git_pass(find_tmp_file_recurs(&first_tmp_file, &path)); + git_buf_free(&path); + cl_assert(git_buf_len(&first_tmp_file) == 0); + + cl_git_pass(git_indexer_new(&idx, ".", 0, NULL, NULL, NULL)); + git_indexer_free(idx); + + cl_git_pass(git_buf_sets(&path, clar_sandbox_path())); + cl_git_pass(find_tmp_file_recurs(&first_tmp_file, &path)); + git_buf_free(&path); + cl_assert(git_buf_len(&first_tmp_file) == 0); + git_buf_free(&first_tmp_file); +} diff --git a/tests/pack/packbuilder.c b/tests/pack/packbuilder.c index 29f3e2d64..13ee07353 100644 --- a/tests/pack/packbuilder.c +++ b/tests/pack/packbuilder.c @@ -23,6 +23,7 @@ void test_pack_packbuilder__initialize(void) cl_git_pass(git_vector_init(&_commits, 0, NULL)); _commits_is_initialized = 1; memset(&_stats, 0, sizeof(_stats)); + p_fsync__cnt = 0; } void test_pack_packbuilder__cleanup(void) @@ -30,6 +31,8 @@ void test_pack_packbuilder__cleanup(void) git_oid *o; unsigned int i; + cl_git_pass(git_libgit2_opts(GIT_OPT_ENABLE_FSYNC_GITDIR, 0)); + if (_commits_is_initialized) { _commits_is_initialized = 0; git_vector_foreach(&_commits, i, o) { @@ -113,7 +116,7 @@ void test_pack_packbuilder__create_pack(void) * $ cd tests/resources/testrepo.git * $ git rev-list --objects HEAD | \ * git pack-objects -q --no-reuse-delta --threads=1 pack - * $ sha1sum git-80e61eb315239ef3c53033e37fee43b744d57122.pack + * $ sha1sum pack-7f5fa362c664d68ba7221259be1cbd187434b2f0.pack * 5d410bdf97cf896f9007681b92868471d636954b * */ @@ -142,7 +145,7 @@ void test_pack_packbuilder__get_hash(void) git_packbuilder_write(_packbuilder, ".", 0, NULL, NULL); git_oid_fmt(hex, git_packbuilder_hash(_packbuilder)); - cl_assert_equal_s(hex, "80e61eb315239ef3c53033e37fee43b744d57122"); + cl_assert_equal_s(hex, "7f5fa362c664d68ba7221259be1cbd187434b2f0"); } static void test_write_pack_permission(mode_t given, mode_t expected) @@ -166,10 +169,10 @@ static void test_write_pack_permission(mode_t given, mode_t expected) mask = p_umask(0); p_umask(mask); - cl_git_pass(p_stat("pack-80e61eb315239ef3c53033e37fee43b744d57122.idx", &statbuf)); + cl_git_pass(p_stat("pack-7f5fa362c664d68ba7221259be1cbd187434b2f0.idx", &statbuf)); cl_assert_equal_i(statbuf.st_mode & os_mask, (expected & ~mask) & os_mask); - cl_git_pass(p_stat("pack-80e61eb315239ef3c53033e37fee43b744d57122.pack", &statbuf)); + cl_git_pass(p_stat("pack-7f5fa362c664d68ba7221259be1cbd187434b2f0.pack", &statbuf)); cl_assert_equal_i(statbuf.st_mode & os_mask, (expected & ~mask) & os_mask); } @@ -188,6 +191,40 @@ void test_pack_packbuilder__permissions_readwrite(void) test_write_pack_permission(0666, 0666); } +void test_pack_packbuilder__does_not_fsync_by_default(void) +{ + seed_packbuilder(); + git_packbuilder_write(_packbuilder, ".", 0666, NULL, NULL); + cl_assert_equal_sz(0, p_fsync__cnt); +} + +/* We fsync the packfile and index. On non-Windows, we also fsync + * the parent directories. + */ +#ifdef GIT_WIN32 +static int expected_fsyncs = 2; +#else +static int expected_fsyncs = 4; +#endif + +void test_pack_packbuilder__fsync_global_setting(void) +{ + cl_git_pass(git_libgit2_opts(GIT_OPT_ENABLE_FSYNC_GITDIR, 1)); + p_fsync__cnt = 0; + seed_packbuilder(); + git_packbuilder_write(_packbuilder, ".", 0666, NULL, NULL); + cl_assert_equal_sz(expected_fsyncs, p_fsync__cnt); +} + +void test_pack_packbuilder__fsync_repo_setting(void) +{ + cl_repo_set_bool(_repo, "core.fsyncObjectFiles", true); + p_fsync__cnt = 0; + seed_packbuilder(); + git_packbuilder_write(_packbuilder, ".", 0666, NULL, NULL); + cl_assert_equal_sz(expected_fsyncs, p_fsync__cnt); +} + static int foreach_cb(void *buf, size_t len, void *payload) { git_indexer *idx = (git_indexer *) payload; diff --git a/tests/rebase/submodule.c b/tests/rebase/submodule.c new file mode 100644 index 000000000..7a38ab89f --- /dev/null +++ b/tests/rebase/submodule.c @@ -0,0 +1,65 @@ +#include "clar_libgit2.h" +#include "git2/checkout.h" +#include "git2/rebase.h" +#include "posix.h" +#include "signature.h" + +#include + +static git_repository *repo; +static git_signature *signature; + +// Fixture setup and teardown +void test_rebase_submodule__initialize(void) +{ + repo = cl_git_sandbox_init("rebase-submodule"); + cl_git_pass(git_signature_new(&signature, + "Rebaser", "rebaser@rebaser.rb", 1405694510, 0)); +} + +void test_rebase_submodule__cleanup(void) +{ + git_signature_free(signature); + cl_git_sandbox_cleanup(); +} + +void test_rebase_submodule__init_untracked(void) +{ + git_rebase *rebase; + git_reference *branch_ref, *upstream_ref; + git_annotated_commit *branch_head, *upstream_head; + git_buf untracked_path = GIT_BUF_INIT; + FILE *fp; + git_submodule *submodule; + git_config *config; + + cl_git_pass(git_reference_lookup(&branch_ref, repo, "refs/heads/asparagus")); + cl_git_pass(git_reference_lookup(&upstream_ref, repo, "refs/heads/master")); + + cl_git_pass(git_annotated_commit_from_ref(&branch_head, repo, branch_ref)); + cl_git_pass(git_annotated_commit_from_ref(&upstream_head, repo, upstream_ref)); + + git_repository_config(&config, repo); + + cl_git_pass(git_config_set_string(config, "submodule.my-submodule.url", git_repository_path(repo))); + + git_config_free(config); + + cl_git_pass(git_submodule_lookup(&submodule, repo, "my-submodule")); + cl_git_pass(git_submodule_update(submodule, 1, NULL)); + + git_buf_printf(&untracked_path, "%s/my-submodule/untracked", git_repository_workdir(repo)); + fp = fopen(git_buf_cstr(&untracked_path), "w"); + fprintf(fp, "An untracked file in a submodule should not block a rebase\n"); + fclose(fp); + git_buf_free(&untracked_path); + + cl_git_pass(git_rebase_init(&rebase, repo, branch_head, upstream_head, NULL, NULL)); + + git_submodule_free(submodule); + git_annotated_commit_free(branch_head); + git_annotated_commit_free(upstream_head); + git_reference_free(branch_ref); + git_reference_free(upstream_ref); + git_rebase_free(rebase); +} diff --git a/tests/refs/branches/upstream.c b/tests/refs/branches/upstream.c index 8f2e7a2ca..82f5665d8 100644 --- a/tests/refs/branches/upstream.c +++ b/tests/refs/branches/upstream.c @@ -175,7 +175,7 @@ void test_refs_branches_upstream__no_fetch_refspec(void) cl_git_pass(git_reference_lookup(&branch, repo, "refs/heads/test")); cl_git_pass(git_reference_create(&ref, repo, "refs/remotes/matching/master", git_reference_target(branch), 1, "fetch")); cl_git_fail(git_branch_set_upstream(branch, "matching/master")); - cl_assert_equal_s("Could not determine remote for 'refs/remotes/matching/master'", + cl_assert_equal_s("could not determine remote for 'refs/remotes/matching/master'", giterr_last()->message); /* we can't set it automatically, so let's test the user setting it by hand */ diff --git a/tests/refs/create.c b/tests/refs/create.c index 6d5a5f1f6..469cddd1e 100644 --- a/tests/refs/create.c +++ b/tests/refs/create.c @@ -12,19 +12,22 @@ static git_repository *g_repo; void test_refs_create__initialize(void) { - g_repo = cl_git_sandbox_init("testrepo"); + g_repo = cl_git_sandbox_init("testrepo"); + p_fsync__cnt = 0; } void test_refs_create__cleanup(void) { - cl_git_sandbox_cleanup(); + cl_git_sandbox_cleanup(); cl_git_pass(git_libgit2_opts(GIT_OPT_ENABLE_STRICT_OBJECT_CREATION, 1)); + cl_git_pass(git_libgit2_opts(GIT_OPT_ENABLE_STRICT_SYMBOLIC_REF_CREATION, 1)); + cl_git_pass(git_libgit2_opts(GIT_OPT_ENABLE_FSYNC_GITDIR, 0)); } void test_refs_create__symbolic(void) { - // create a new symbolic reference + /* create a new symbolic reference */ git_reference *new_reference, *looked_up_ref, *resolved_ref; git_repository *repo2; git_oid id; @@ -65,9 +68,57 @@ void test_refs_create__symbolic(void) git_reference_free(resolved_ref); } +void test_refs_create__symbolic_with_arbitrary_content(void) +{ + git_reference *new_reference, *looked_up_ref; + git_repository *repo2; + git_oid id; + + const char *new_head_tracker = "ANOTHER_HEAD_TRACKER"; + const char *arbitrary_target = "ARBITRARY DATA"; + + git_oid_fromstr(&id, current_master_tip); + + /* Attempt to create symbolic ref with arbitrary data in target + * fails by default + */ + cl_git_fail(git_reference_symbolic_create(&new_reference, g_repo, new_head_tracker, arbitrary_target, 0, NULL)); + + git_libgit2_opts(GIT_OPT_ENABLE_STRICT_SYMBOLIC_REF_CREATION, 0); + + /* With strict target validation disabled, ref creation succeeds */ + cl_git_pass(git_reference_symbolic_create(&new_reference, g_repo, new_head_tracker, arbitrary_target, 0, NULL)); + + /* Ensure the reference can be looked-up... */ + cl_git_pass(git_reference_lookup(&looked_up_ref, g_repo, new_head_tracker)); + cl_assert(git_reference_type(looked_up_ref) & GIT_REF_SYMBOLIC); + cl_assert(reference_is_packed(looked_up_ref) == 0); + cl_assert_equal_s(looked_up_ref->name, new_head_tracker); + git_reference_free(looked_up_ref); + + /* Ensure the target is what we expect it to be */ + cl_assert_equal_s(git_reference_symbolic_target(new_reference), arbitrary_target); + + /* Similar test with a fresh new repository object */ + cl_git_pass(git_repository_open(&repo2, "testrepo")); + + /* Ensure the reference can be looked-up... */ + cl_git_pass(git_reference_lookup(&looked_up_ref, repo2, new_head_tracker)); + cl_assert(git_reference_type(looked_up_ref) & GIT_REF_SYMBOLIC); + cl_assert(reference_is_packed(looked_up_ref) == 0); + cl_assert_equal_s(looked_up_ref->name, new_head_tracker); + + /* Ensure the target is what we expect it to be */ + cl_assert_equal_s(git_reference_symbolic_target(new_reference), arbitrary_target); + + git_repository_free(repo2); + git_reference_free(new_reference); + git_reference_free(looked_up_ref); +} + void test_refs_create__deep_symbolic(void) { - // create a deep symbolic reference + /* create a deep symbolic reference */ git_reference *new_reference, *looked_up_ref, *resolved_ref; git_oid id; @@ -87,7 +138,7 @@ void test_refs_create__deep_symbolic(void) void test_refs_create__oid(void) { - // create a new OID reference + /* create a new OID reference */ git_reference *new_reference, *looked_up_ref; git_repository *repo2; git_oid id; @@ -248,3 +299,69 @@ void test_refs_create__creating_a_loose_ref_with_invalid_windows_name(void) test_win32_name("refs/heads/com1"); } + +/* Creating a loose ref involves fsync'ing the reference, the + * reflog and (on non-Windows) the containing directories. + * Creating a packed ref involves fsync'ing the packed ref file + * and (on non-Windows) the containing directory. + */ +#ifdef GIT_WIN32 +static int expected_fsyncs_create = 2, expected_fsyncs_compress = 1; +#else +static int expected_fsyncs_create = 4, expected_fsyncs_compress = 2; +#endif + +static void count_fsyncs(size_t *create_count, size_t *compress_count) +{ + git_reference *ref = NULL; + git_refdb *refdb; + git_oid id; + + p_fsync__cnt = 0; + + git_oid_fromstr(&id, current_master_tip); + cl_git_pass(git_reference_create(&ref, g_repo, "refs/heads/fsync_test", &id, 0, "log message")); + git_reference_free(ref); + + *create_count = p_fsync__cnt; + p_fsync__cnt = 0; + + cl_git_pass(git_repository_refdb(&refdb, g_repo)); + cl_git_pass(git_refdb_compress(refdb)); + git_refdb_free(refdb); + + *compress_count = p_fsync__cnt; + p_fsync__cnt = 0; +} + +void test_refs_create__does_not_fsync_by_default(void) +{ + size_t create_count, compress_count; + count_fsyncs(&create_count, &compress_count); + + cl_assert_equal_i(0, create_count); + cl_assert_equal_i(0, compress_count); +} + +void test_refs_create__fsyncs_when_global_opt_set(void) +{ + size_t create_count, compress_count; + + cl_git_pass(git_libgit2_opts(GIT_OPT_ENABLE_FSYNC_GITDIR, 1)); + count_fsyncs(&create_count, &compress_count); + + cl_assert_equal_i(expected_fsyncs_create, create_count); + cl_assert_equal_i(expected_fsyncs_compress, compress_count); +} + +void test_refs_create__fsyncs_when_repo_config_set(void) +{ + size_t create_count, compress_count; + + cl_repo_set_bool(g_repo, "core.fsyncObjectFiles", true); + + count_fsyncs(&create_count, &compress_count); + + cl_assert_equal_i(expected_fsyncs_create, create_count); + cl_assert_equal_i(expected_fsyncs_compress, compress_count); +} diff --git a/tests/refs/list.c b/tests/refs/list.c index 374943b05..f7ca3f707 100644 --- a/tests/refs/list.c +++ b/tests/refs/list.c @@ -36,7 +36,7 @@ void test_refs_list__all(void) /* We have exactly 12 refs in total if we include the packed ones: * there is a reference that exists both in the packfile and as * loose, but we only list it once */ - cl_assert_equal_i((int)ref_list.count, 15); + cl_assert_equal_i((int)ref_list.count, 17); git_strarray_free(&ref_list); } @@ -51,7 +51,7 @@ void test_refs_list__do_not_retrieve_references_which_name_end_with_a_lock_exten "144344043ba4d4a405da03de3844aa829ae8be0e\n"); cl_git_pass(git_reference_list(&ref_list, g_repo)); - cl_assert_equal_i((int)ref_list.count, 15); + cl_assert_equal_i((int)ref_list.count, 17); git_strarray_free(&ref_list); } diff --git a/tests/refs/namespaces.c b/tests/refs/namespaces.c new file mode 100644 index 000000000..bb6bb1ce0 --- /dev/null +++ b/tests/refs/namespaces.c @@ -0,0 +1,36 @@ +#include "clar_libgit2.h" + +#include "repository.h" + +static git_repository *g_repo; + +void test_refs_namespaces__initialize(void) +{ + g_repo = cl_git_sandbox_init("testrepo"); +} + +void test_refs_namespaces__cleanup(void) +{ + cl_git_sandbox_cleanup(); +} + +void test_refs_namespaces__get_and_set(void) +{ + cl_assert_equal_s(NULL, git_repository_get_namespace(g_repo)); + + cl_git_pass(git_repository_set_namespace(g_repo, "namespace")); + cl_assert_equal_s("namespace", git_repository_get_namespace(g_repo)); + + cl_git_pass(git_repository_set_namespace(g_repo, NULL)); + cl_assert_equal_s(NULL, git_repository_get_namespace(g_repo)); +} + +void test_refs_namespaces__namespace_doesnt_show_normal_refs(void) +{ + static git_strarray ref_list; + + cl_git_pass(git_repository_set_namespace(g_repo, "namespace")); + cl_git_pass(git_reference_list(&ref_list, g_repo)); + cl_assert_equal_i(0, ref_list.count); + git_strarray_free(&ref_list); +} diff --git a/tests/refs/reflog/reflog.c b/tests/refs/reflog/reflog.c index fdb15502c..252242152 100644 --- a/tests/refs/reflog/reflog.c +++ b/tests/refs/reflog/reflog.c @@ -4,7 +4,7 @@ #include "git2/reflog.h" #include "reflog.h" - +static const char *merge_reflog_message = "commit (merge): Merge commit"; static const char *new_ref = "refs/heads/test-reflog"; static const char *current_master_tip = "a65fedf39aefe402d3bb6e24df4d4f5fe4547750"; #define commit_msg "commit: bla bla" @@ -261,7 +261,7 @@ void test_refs_reflog_reflog__reading_a_reflog_with_invalid_format_returns_error error = giterr_last(); cl_assert(error != NULL); - cl_assert_equal_s("Unable to parse OID - contains invalid characters", error->message); + cl_assert_equal_s("unable to parse OID - contains invalid characters", error->message); git_reference_free(ref); git_buf_free(&logpath); @@ -448,3 +448,45 @@ void test_refs_reflog_reflog__logallrefupdates_nonbare_set_false(void) assert_no_reflog_update(); } + +void test_refs_reflog_reflog__show_merge_for_merge_commits(void) +{ + git_oid b1_oid; + git_oid b2_oid; + git_oid merge_commit_oid; + git_commit *b1_commit; + git_commit *b2_commit; + git_signature *s; + git_commit *parent_commits[2]; + git_tree *tree; + git_reflog *log; + const git_reflog_entry *entry; + + cl_git_pass(git_signature_now(&s, "alice", "alice@example.com")); + + cl_git_pass(git_reference_name_to_id(&b1_oid, g_repo, "HEAD")); + cl_git_pass(git_reference_name_to_id(&b2_oid, g_repo, "refs/heads/test")); + + cl_git_pass(git_commit_lookup(&b1_commit, g_repo, &b1_oid)); + cl_git_pass(git_commit_lookup(&b2_commit, g_repo, &b2_oid)); + + parent_commits[0] = b1_commit; + parent_commits[1] = b2_commit; + + cl_git_pass(git_commit_tree(&tree, b1_commit)); + + cl_git_pass(git_commit_create(&merge_commit_oid, + g_repo, "HEAD", s, s, NULL, + "Merge commit", tree, + 2, (const struct git_commit **) parent_commits)); + + cl_git_pass(git_reflog_read(&log, g_repo, "HEAD")); + entry = git_reflog_entry_byindex(log, 0); + cl_assert_equal_s(merge_reflog_message, git_reflog_entry_message(entry)); + + git_reflog_free(log); + git_tree_free(tree); + git_commit_free(b1_commit); + git_commit_free(b2_commit); + git_signature_free(s); +} diff --git a/tests/refs/revparse.c b/tests/refs/revparse.c index c22c30440..459188cf7 100644 --- a/tests/refs/revparse.c +++ b/tests/refs/revparse.c @@ -122,6 +122,14 @@ static void test_id( test_id_inrepo(spec, expected_left, expected_right, expected_flags, g_repo); } +static void test_invalid_revspec(const char* invalid_spec) +{ + git_revspec revspec; + + cl_assert_equal_i( + GIT_EINVALIDSPEC, git_revparse(&revspec, g_repo, invalid_spec)); +} + void test_refs_revparse__initialize(void) { cl_git_pass(git_repository_open(&g_repo, cl_fixture("testrepo.git"))); @@ -749,6 +757,33 @@ void test_refs_revparse__parses_range_operator(void) "4a202b346bb0fb0db7eff3cffeb3c70babbd2045", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750", GIT_REVPARSE_RANGE | GIT_REVPARSE_MERGE_BASE); + + test_id("HEAD~3..", + "4a202b346bb0fb0db7eff3cffeb3c70babbd2045", + "a65fedf39aefe402d3bb6e24df4d4f5fe4547750", + GIT_REVPARSE_RANGE); + + test_id("HEAD~3...", + "4a202b346bb0fb0db7eff3cffeb3c70babbd2045", + "a65fedf39aefe402d3bb6e24df4d4f5fe4547750", + GIT_REVPARSE_RANGE | GIT_REVPARSE_MERGE_BASE); + + test_id("..HEAD~3", + "a65fedf39aefe402d3bb6e24df4d4f5fe4547750", + "4a202b346bb0fb0db7eff3cffeb3c70babbd2045", + GIT_REVPARSE_RANGE); + + test_id("...HEAD~3", + "a65fedf39aefe402d3bb6e24df4d4f5fe4547750", + "4a202b346bb0fb0db7eff3cffeb3c70babbd2045", + GIT_REVPARSE_RANGE | GIT_REVPARSE_MERGE_BASE); + + test_id("...", + "a65fedf39aefe402d3bb6e24df4d4f5fe4547750", + "a65fedf39aefe402d3bb6e24df4d4f5fe4547750", + GIT_REVPARSE_RANGE | GIT_REVPARSE_MERGE_BASE); + + test_invalid_revspec(".."); } void test_refs_revparse__ext_retrieves_both_the_reference_and_its_target(void) diff --git a/tests/repo/discover.c b/tests/repo/discover.c index 48aa27581..eadd055e9 100644 --- a/tests/repo/discover.c +++ b/tests/repo/discover.c @@ -33,7 +33,7 @@ static void ensure_repository_discover(const char *start_path, git_buf_attach(&resolved, p_realpath(expected_path, NULL), 0); cl_assert(resolved.size > 0); cl_git_pass(git_path_to_dir(&resolved)); - cl_git_pass(git_repository_discover(&found_path, start_path, 0, ceiling_dirs)); + cl_git_pass(git_repository_discover(&found_path, start_path, 1, ceiling_dirs)); cl_assert_equal_s(found_path.ptr, resolved.ptr); @@ -199,3 +199,12 @@ void test_repo_discover__discovery_starting_at_file_succeeds(void) ensure_repository_discover(SUB_REPOSITORY_FOLDER "/file", ceiling_dirs.ptr, SUB_REPOSITORY_GITDIR); } + +void test_repo_discover__discovery_starting_at_system_root_causes_no_hang(void) +{ +#ifdef GIT_WIN32 + git_buf out = GIT_BUF_INIT; + cl_git_fail(git_repository_discover(&out, "C:/", 0, NULL)); + cl_git_fail(git_repository_discover(&out, "//localhost/", 0, NULL)); +#endif +} diff --git a/tests/repo/env.c b/tests/repo/env.c index 5a89c0d49..6404f88e9 100644 --- a/tests/repo/env.c +++ b/tests/repo/env.c @@ -56,8 +56,8 @@ static int GIT_FORMAT_PRINTF(2, 3) cl_setenv_printf(const char *name, const char static void env_pass_(const char *path, const char *file, int line) { git_repository *repo; - cl_git_pass_(git_repository_open_ext(NULL, path, GIT_REPOSITORY_OPEN_FROM_ENV, NULL), file, line); - cl_git_pass_(git_repository_open_ext(&repo, path, GIT_REPOSITORY_OPEN_FROM_ENV, NULL), file, line); + cl_git_expect(git_repository_open_ext(NULL, path, GIT_REPOSITORY_OPEN_FROM_ENV, NULL), 0, file, line); + cl_git_expect(git_repository_open_ext(&repo, path, GIT_REPOSITORY_OPEN_FROM_ENV, NULL), 0, file, line); cl_assert_at_line(git__suffixcmp(git_repository_path(repo), "attr/.git/") == 0, file, line); cl_assert_at_line(git__suffixcmp(git_repository_workdir(repo), "attr/") == 0, file, line); cl_assert_at_line(!git_repository_is_bare(repo), file, line); @@ -98,24 +98,24 @@ static void env_check_objects_(bool a, bool t, bool p, const char *file, int lin cl_git_pass(git_oid_fromstr(&oid_a, "45141a79a77842c59a63229403220a4e4be74e3d")); cl_git_pass(git_oid_fromstr(&oid_t, "1385f264afb75a56a5bec74243be9b367ba4ca08")); cl_git_pass(git_oid_fromstr(&oid_p, "0df1a5865c8abfc09f1f2182e6a31be550e99f07")); - cl_git_pass_(git_repository_open_ext(&repo, "attr", GIT_REPOSITORY_OPEN_FROM_ENV, NULL), file, line); + cl_git_expect(git_repository_open_ext(&repo, "attr", GIT_REPOSITORY_OPEN_FROM_ENV, NULL), 0, file, line); if (a) { - cl_git_pass_(git_object_lookup(&object, repo, &oid_a, GIT_OBJ_BLOB), file, line); + cl_git_expect(git_object_lookup(&object, repo, &oid_a, GIT_OBJ_BLOB), 0, file, line); git_object_free(object); } else { cl_git_fail_at_line(git_object_lookup(&object, repo, &oid_a, GIT_OBJ_BLOB), file, line); } if (t) { - cl_git_pass_(git_object_lookup(&object, repo, &oid_t, GIT_OBJ_BLOB), file, line); + cl_git_expect(git_object_lookup(&object, repo, &oid_t, GIT_OBJ_BLOB), 0, file, line); git_object_free(object); } else { cl_git_fail_at_line(git_object_lookup(&object, repo, &oid_t, GIT_OBJ_BLOB), file, line); } if (p) { - cl_git_pass_(git_object_lookup(&object, repo, &oid_p, GIT_OBJ_COMMIT), file, line); + cl_git_expect(git_object_lookup(&object, repo, &oid_p, GIT_OBJ_COMMIT), 0, file, line); git_object_free(object); } else { cl_git_fail_at_line(git_object_lookup(&object, repo, &oid_p, GIT_OBJ_COMMIT), file, line); diff --git a/tests/repo/head.c b/tests/repo/head.c index 31c228777..d02116087 100644 --- a/tests/repo/head.c +++ b/tests/repo/head.c @@ -261,15 +261,19 @@ void test_repo_head__setting_head_updates_reflog(void) cl_git_pass(git_revparse_single(&tag, repo, "tags/test")); cl_git_pass(git_repository_set_head_detached(repo, git_object_id(tag))); cl_git_pass(git_repository_set_head(repo, "refs/heads/haacked")); + cl_git_pass(git_repository_set_head(repo, "refs/tags/test")); + cl_git_pass(git_repository_set_head(repo, "refs/remotes/test/master")); - test_reflog(repo, 2, NULL, "refs/heads/haacked", "foo@example.com", "checkout: moving from master to haacked"); - test_reflog(repo, 1, NULL, "tags/test^{commit}", "foo@example.com", "checkout: moving from unborn to e90810b8df3e80c413d903f631643c716887138d"); - test_reflog(repo, 0, "tags/test^{commit}", "refs/heads/haacked", "foo@example.com", "checkout: moving from e90810b8df3e80c413d903f631643c716887138d to haacked"); + test_reflog(repo, 4, NULL, "refs/heads/haacked", "foo@example.com", "checkout: moving from master to haacked"); + test_reflog(repo, 3, NULL, "tags/test^{commit}", "foo@example.com", "checkout: moving from unborn to e90810b8df3e80c413d903f631643c716887138d"); + test_reflog(repo, 2, "tags/test^{commit}", "refs/heads/haacked", "foo@example.com", "checkout: moving from e90810b8df3e80c413d903f631643c716887138d to haacked"); + test_reflog(repo, 1, "refs/heads/haacked", "tags/test^{commit}", "foo@example.com", "checkout: moving from haacked to test"); + test_reflog(repo, 0, "tags/test^{commit}", "refs/remotes/test/master", "foo@example.com", "checkout: moving from e90810b8df3e80c413d903f631643c716887138d to test/master"); cl_git_pass(git_annotated_commit_from_revspec(&annotated, repo, "haacked~0")); cl_git_pass(git_repository_set_head_detached_from_annotated(repo, annotated)); - test_reflog(repo, 0, NULL, "refs/heads/haacked", "foo@example.com", "checkout: moving from haacked to haacked~0"); + test_reflog(repo, 0, NULL, "refs/heads/haacked", "foo@example.com", "checkout: moving from be3563ae3f795b2b4353bcce3a527ad0a4f7f644 to haacked~0"); git_annotated_commit_free(annotated); git_object_free(tag); diff --git a/tests/repo/open.c b/tests/repo/open.c index 6114ad2e1..3239b6fec 100644 --- a/tests/repo/open.c +++ b/tests/repo/open.c @@ -398,7 +398,8 @@ void test_repo_open__force_bare(void) cl_git_fail(git_repository_open_bare(&barerepo, "alternate/subdir/sub2")); cl_git_pass(git_repository_open_ext( - &barerepo, "alternate/subdir/sub2", GIT_REPOSITORY_OPEN_BARE, NULL)); + &barerepo, "alternate/subdir/sub2", + GIT_REPOSITORY_OPEN_BARE|GIT_REPOSITORY_OPEN_CROSS_FS, NULL)); cl_assert(git_repository_is_bare(barerepo)); git_repository_free(barerepo); } diff --git a/tests/resources/indexv4/.gitted/HEAD b/tests/resources/indexv4/.gitted/HEAD new file mode 100644 index 000000000..cb089cd89 Binary files /dev/null and b/tests/resources/indexv4/.gitted/HEAD differ diff --git a/tests/resources/indexv4/.gitted/config b/tests/resources/indexv4/.gitted/config new file mode 100644 index 000000000..515f48362 Binary files /dev/null and b/tests/resources/indexv4/.gitted/config differ diff --git a/tests/resources/indexv4/.gitted/index b/tests/resources/indexv4/.gitted/index new file mode 100644 index 000000000..e8fc61736 Binary files /dev/null and b/tests/resources/indexv4/.gitted/index differ diff --git a/tests/resources/indexv4/.gitted/objects/4c/9109b3e671d851eec87e0e72f6305b582e7e99 b/tests/resources/indexv4/.gitted/objects/4c/9109b3e671d851eec87e0e72f6305b582e7e99 new file mode 100644 index 000000000..cedd594b0 Binary files /dev/null and b/tests/resources/indexv4/.gitted/objects/4c/9109b3e671d851eec87e0e72f6305b582e7e99 differ diff --git a/tests/resources/indexv4/.gitted/objects/b0/952dbb50bed5f01e03e31b296184cb183e54a7 b/tests/resources/indexv4/.gitted/objects/b0/952dbb50bed5f01e03e31b296184cb183e54a7 new file mode 100644 index 000000000..0ddc1d1a9 Binary files /dev/null and b/tests/resources/indexv4/.gitted/objects/b0/952dbb50bed5f01e03e31b296184cb183e54a7 differ diff --git a/tests/resources/indexv4/.gitted/objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391 b/tests/resources/indexv4/.gitted/objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391 new file mode 100644 index 000000000..711223894 Binary files /dev/null and b/tests/resources/indexv4/.gitted/objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391 differ diff --git a/tests/resources/indexv4/.gitted/refs/heads/master b/tests/resources/indexv4/.gitted/refs/heads/master new file mode 100644 index 000000000..f3e960eb3 Binary files /dev/null and b/tests/resources/indexv4/.gitted/refs/heads/master differ diff --git a/tests/resources/indexv4/file.tx b/tests/resources/indexv4/file.tx new file mode 100644 index 000000000..e69de29bb diff --git a/tests/resources/indexv4/file.txt b/tests/resources/indexv4/file.txt new file mode 100644 index 000000000..e69de29bb diff --git a/tests/resources/indexv4/file.txz b/tests/resources/indexv4/file.txz new file mode 100644 index 000000000..e69de29bb diff --git a/tests/resources/indexv4/foo b/tests/resources/indexv4/foo new file mode 100644 index 000000000..e69de29bb diff --git a/tests/resources/indexv4/zzz b/tests/resources/indexv4/zzz new file mode 100644 index 000000000..e69de29bb diff --git a/tests/resources/merge-resolve/.gitted/objects/2a/f2d9bcbc73723ac988bb202d4397f72a6ca7a0 b/tests/resources/merge-resolve/.gitted/objects/2a/f2d9bcbc73723ac988bb202d4397f72a6ca7a0 new file mode 100644 index 000000000..0d658237b Binary files /dev/null and b/tests/resources/merge-resolve/.gitted/objects/2a/f2d9bcbc73723ac988bb202d4397f72a6ca7a0 differ diff --git a/tests/resources/merge-resolve/.gitted/objects/37/f53a5a14f64e91089a39ea58e71c87d81df765 b/tests/resources/merge-resolve/.gitted/objects/37/f53a5a14f64e91089a39ea58e71c87d81df765 new file mode 100644 index 000000000..95327ed64 Binary files /dev/null and b/tests/resources/merge-resolve/.gitted/objects/37/f53a5a14f64e91089a39ea58e71c87d81df765 differ diff --git a/tests/resources/merge-resolve/.gitted/objects/4d/d1ef7569b18d92d93c0a35bb6b93049137b355 b/tests/resources/merge-resolve/.gitted/objects/4d/d1ef7569b18d92d93c0a35bb6b93049137b355 new file mode 100644 index 000000000..86a21ad50 Binary files /dev/null and b/tests/resources/merge-resolve/.gitted/objects/4d/d1ef7569b18d92d93c0a35bb6b93049137b355 differ diff --git a/tests/resources/merge-resolve/.gitted/objects/63/ec604d491161ddafdae4179843c26d54bd999a b/tests/resources/merge-resolve/.gitted/objects/63/ec604d491161ddafdae4179843c26d54bd999a new file mode 100644 index 000000000..bc74da5ba Binary files /dev/null and b/tests/resources/merge-resolve/.gitted/objects/63/ec604d491161ddafdae4179843c26d54bd999a differ diff --git a/tests/resources/merge-resolve/.gitted/objects/68/f7c02064019d89e40e51d7776b6f67914420a2 b/tests/resources/merge-resolve/.gitted/objects/68/f7c02064019d89e40e51d7776b6f67914420a2 new file mode 100644 index 000000000..809a5b38b Binary files /dev/null and b/tests/resources/merge-resolve/.gitted/objects/68/f7c02064019d89e40e51d7776b6f67914420a2 differ diff --git a/tests/resources/merge-resolve/.gitted/objects/94/29c05dd6f6f39fc567b4ce923b16df5d3d7a7a b/tests/resources/merge-resolve/.gitted/objects/94/29c05dd6f6f39fc567b4ce923b16df5d3d7a7a new file mode 100644 index 000000000..d4d93f508 Binary files /dev/null and b/tests/resources/merge-resolve/.gitted/objects/94/29c05dd6f6f39fc567b4ce923b16df5d3d7a7a differ diff --git a/tests/resources/merge-resolve/.gitted/objects/a1/07e18a58f38c46086c8f8f1dcd54c40154eeb6 b/tests/resources/merge-resolve/.gitted/objects/a1/07e18a58f38c46086c8f8f1dcd54c40154eeb6 new file mode 100644 index 000000000..598c6a7a6 Binary files /dev/null and b/tests/resources/merge-resolve/.gitted/objects/a1/07e18a58f38c46086c8f8f1dcd54c40154eeb6 differ diff --git a/tests/resources/merge-resolve/.gitted/objects/a2/d8d1824c68541cca94ffb90f79291eba495921 b/tests/resources/merge-resolve/.gitted/objects/a2/d8d1824c68541cca94ffb90f79291eba495921 new file mode 100644 index 000000000..2d3d94718 Binary files /dev/null and b/tests/resources/merge-resolve/.gitted/objects/a2/d8d1824c68541cca94ffb90f79291eba495921 differ diff --git a/tests/resources/merge-resolve/.gitted/objects/bc/85d1aad435ff3705a8c30ace85f7542c5736cb b/tests/resources/merge-resolve/.gitted/objects/bc/85d1aad435ff3705a8c30ace85f7542c5736cb new file mode 100644 index 000000000..ae529fe87 Binary files /dev/null and b/tests/resources/merge-resolve/.gitted/objects/bc/85d1aad435ff3705a8c30ace85f7542c5736cb differ diff --git a/tests/resources/merge-resolve/.gitted/objects/c8/26ef8b17b5cd2c4a0023f265f3a423b3aa0388 b/tests/resources/merge-resolve/.gitted/objects/c8/26ef8b17b5cd2c4a0023f265f3a423b3aa0388 new file mode 100644 index 000000000..b655d7c40 Binary files /dev/null and b/tests/resources/merge-resolve/.gitted/objects/c8/26ef8b17b5cd2c4a0023f265f3a423b3aa0388 differ diff --git a/tests/resources/merge-resolve/.gitted/objects/cd/3e8d4aa06bdc781f264171030bc28f2b370fee b/tests/resources/merge-resolve/.gitted/objects/cd/3e8d4aa06bdc781f264171030bc28f2b370fee new file mode 100644 index 000000000..144225df1 Binary files /dev/null and b/tests/resources/merge-resolve/.gitted/objects/cd/3e8d4aa06bdc781f264171030bc28f2b370fee differ diff --git a/tests/resources/merge-resolve/.gitted/objects/e2/6b8888956137218d8589368a3e606cf50fbb56 b/tests/resources/merge-resolve/.gitted/objects/e2/6b8888956137218d8589368a3e606cf50fbb56 new file mode 100644 index 000000000..d4ec2b972 Binary files /dev/null and b/tests/resources/merge-resolve/.gitted/objects/e2/6b8888956137218d8589368a3e606cf50fbb56 differ diff --git a/tests/resources/merge-resolve/.gitted/objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391 b/tests/resources/merge-resolve/.gitted/objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391 new file mode 100644 index 000000000..711223894 Binary files /dev/null and b/tests/resources/merge-resolve/.gitted/objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391 differ diff --git a/tests/resources/merge-resolve/.gitted/objects/f9/7da95f156121bea8f978623628f4cbdbf30b36 b/tests/resources/merge-resolve/.gitted/objects/f9/7da95f156121bea8f978623628f4cbdbf30b36 new file mode 100644 index 000000000..d785511fb Binary files /dev/null and b/tests/resources/merge-resolve/.gitted/objects/f9/7da95f156121bea8f978623628f4cbdbf30b36 differ diff --git a/tests/resources/merge-resolve/.gitted/refs/heads/submodule_rename1 b/tests/resources/merge-resolve/.gitted/refs/heads/submodule_rename1 new file mode 100644 index 000000000..0ed914fef Binary files /dev/null and b/tests/resources/merge-resolve/.gitted/refs/heads/submodule_rename1 differ diff --git a/tests/resources/merge-resolve/.gitted/refs/heads/submodule_rename2 b/tests/resources/merge-resolve/.gitted/refs/heads/submodule_rename2 new file mode 100644 index 000000000..8e020ccfc Binary files /dev/null and b/tests/resources/merge-resolve/.gitted/refs/heads/submodule_rename2 differ diff --git a/tests/resources/rebase-submodule/.gitmodules b/tests/resources/rebase-submodule/.gitmodules new file mode 100644 index 000000000..f36de77de Binary files /dev/null and b/tests/resources/rebase-submodule/.gitmodules differ diff --git a/tests/resources/rebase-submodule/.gitted/HEAD b/tests/resources/rebase-submodule/.gitted/HEAD new file mode 100644 index 000000000..cb089cd89 Binary files /dev/null and b/tests/resources/rebase-submodule/.gitted/HEAD differ diff --git a/tests/resources/rebase-submodule/.gitted/ORIG_HEAD b/tests/resources/rebase-submodule/.gitted/ORIG_HEAD new file mode 100644 index 000000000..a1ccbb40d Binary files /dev/null and b/tests/resources/rebase-submodule/.gitted/ORIG_HEAD differ diff --git a/tests/resources/rebase-submodule/.gitted/config b/tests/resources/rebase-submodule/.gitted/config new file mode 100644 index 000000000..af2095f84 Binary files /dev/null and b/tests/resources/rebase-submodule/.gitted/config differ diff --git a/tests/resources/rebase-submodule/.gitted/description b/tests/resources/rebase-submodule/.gitted/description new file mode 100644 index 000000000..498b267a8 Binary files /dev/null and b/tests/resources/rebase-submodule/.gitted/description differ diff --git a/tests/resources/rebase-submodule/.gitted/index b/tests/resources/rebase-submodule/.gitted/index new file mode 100644 index 000000000..b63efabdb Binary files /dev/null and b/tests/resources/rebase-submodule/.gitted/index differ diff --git a/tests/resources/rebase-submodule/.gitted/info/exclude b/tests/resources/rebase-submodule/.gitted/info/exclude new file mode 100644 index 000000000..a5196d1be Binary files /dev/null and b/tests/resources/rebase-submodule/.gitted/info/exclude differ diff --git a/tests/resources/rebase-submodule/.gitted/info/refs b/tests/resources/rebase-submodule/.gitted/info/refs new file mode 100644 index 000000000..230a6494b Binary files /dev/null and b/tests/resources/rebase-submodule/.gitted/info/refs differ diff --git a/tests/resources/rebase-submodule/.gitted/objects/01/971e2453a407e4b9f6c865e2c37f4db21da294 b/tests/resources/rebase-submodule/.gitted/objects/01/971e2453a407e4b9f6c865e2c37f4db21da294 new file mode 100644 index 000000000..308b38697 Binary files /dev/null and b/tests/resources/rebase-submodule/.gitted/objects/01/971e2453a407e4b9f6c865e2c37f4db21da294 differ diff --git a/tests/resources/rebase-submodule/.gitted/objects/17/f8ae8ebdd08a4bb272f61b897b308ad42b1b12 b/tests/resources/rebase-submodule/.gitted/objects/17/f8ae8ebdd08a4bb272f61b897b308ad42b1b12 new file mode 100644 index 000000000..79e4c484f Binary files /dev/null and b/tests/resources/rebase-submodule/.gitted/objects/17/f8ae8ebdd08a4bb272f61b897b308ad42b1b12 differ diff --git a/tests/resources/rebase-submodule/.gitted/objects/42/cdad903aef3e7b614675e6584a8be417941911 b/tests/resources/rebase-submodule/.gitted/objects/42/cdad903aef3e7b614675e6584a8be417941911 new file mode 100644 index 000000000..99b5e6d2c Binary files /dev/null and b/tests/resources/rebase-submodule/.gitted/objects/42/cdad903aef3e7b614675e6584a8be417941911 differ diff --git a/tests/resources/rebase-submodule/.gitted/objects/4b/7c5650008b2e747fe1809eeb5a1dde0e80850a b/tests/resources/rebase-submodule/.gitted/objects/4b/7c5650008b2e747fe1809eeb5a1dde0e80850a new file mode 100644 index 000000000..016398531 Binary files /dev/null and b/tests/resources/rebase-submodule/.gitted/objects/4b/7c5650008b2e747fe1809eeb5a1dde0e80850a differ diff --git a/tests/resources/rebase-submodule/.gitted/objects/5b/1e8bccf7787e942aecf61912f94a2c274f85a5 b/tests/resources/rebase-submodule/.gitted/objects/5b/1e8bccf7787e942aecf61912f94a2c274f85a5 new file mode 100644 index 000000000..d4776d883 Binary files /dev/null and b/tests/resources/rebase-submodule/.gitted/objects/5b/1e8bccf7787e942aecf61912f94a2c274f85a5 differ diff --git a/tests/resources/rebase-submodule/.gitted/objects/68/af1fc7407fd9addf1701a87eb1c95c7494c598 b/tests/resources/rebase-submodule/.gitted/objects/68/af1fc7407fd9addf1701a87eb1c95c7494c598 new file mode 100644 index 000000000..6aaf79fcb Binary files /dev/null and b/tests/resources/rebase-submodule/.gitted/objects/68/af1fc7407fd9addf1701a87eb1c95c7494c598 differ diff --git a/tests/resources/rebase-submodule/.gitted/objects/68/f6182f4c85d39e1309d97c7e456156dc9c0096 b/tests/resources/rebase-submodule/.gitted/objects/68/f6182f4c85d39e1309d97c7e456156dc9c0096 new file mode 100644 index 000000000..ed1de3ada Binary files /dev/null and b/tests/resources/rebase-submodule/.gitted/objects/68/f6182f4c85d39e1309d97c7e456156dc9c0096 differ diff --git a/tests/resources/rebase-submodule/.gitted/objects/7c/71f7606bd3bfb25d063c970804e7fc00b9605b b/tests/resources/rebase-submodule/.gitted/objects/7c/71f7606bd3bfb25d063c970804e7fc00b9605b new file mode 100644 index 000000000..ef923e714 Binary files /dev/null and b/tests/resources/rebase-submodule/.gitted/objects/7c/71f7606bd3bfb25d063c970804e7fc00b9605b differ diff --git a/tests/resources/rebase-submodule/.gitted/objects/7c/7bf85e978f1d18c0566f702d2cb7766b9c8d4f b/tests/resources/rebase-submodule/.gitted/objects/7c/7bf85e978f1d18c0566f702d2cb7766b9c8d4f new file mode 100644 index 000000000..fe8b15777 Binary files /dev/null and b/tests/resources/rebase-submodule/.gitted/objects/7c/7bf85e978f1d18c0566f702d2cb7766b9c8d4f differ diff --git a/tests/resources/rebase-submodule/.gitted/objects/a7/b066537e6be7109abfe4ff97b675d4e077da20 b/tests/resources/rebase-submodule/.gitted/objects/a7/b066537e6be7109abfe4ff97b675d4e077da20 new file mode 100644 index 000000000..54f9b6617 Binary files /dev/null and b/tests/resources/rebase-submodule/.gitted/objects/a7/b066537e6be7109abfe4ff97b675d4e077da20 differ diff --git a/tests/resources/rebase-submodule/.gitted/objects/ab/6cf22b4c67a274aa8d31b5877d92341e8c2a9c b/tests/resources/rebase-submodule/.gitted/objects/ab/6cf22b4c67a274aa8d31b5877d92341e8c2a9c new file mode 100644 index 000000000..5acdf362e Binary files /dev/null and b/tests/resources/rebase-submodule/.gitted/objects/ab/6cf22b4c67a274aa8d31b5877d92341e8c2a9c differ diff --git a/tests/resources/rebase-submodule/.gitted/objects/c4/e6cca3ec6ae0148ed231f97257df8c311e015f b/tests/resources/rebase-submodule/.gitted/objects/c4/e6cca3ec6ae0148ed231f97257df8c311e015f new file mode 100644 index 000000000..2bbf28f57 Binary files /dev/null and b/tests/resources/rebase-submodule/.gitted/objects/c4/e6cca3ec6ae0148ed231f97257df8c311e015f differ diff --git a/tests/resources/rebase-submodule/.gitted/objects/f3/6de77de6f53dddafeb024ecaf375e45c3d9ddd b/tests/resources/rebase-submodule/.gitted/objects/f3/6de77de6f53dddafeb024ecaf375e45c3d9ddd new file mode 100644 index 000000000..cd330a71f Binary files /dev/null and b/tests/resources/rebase-submodule/.gitted/objects/f3/6de77de6f53dddafeb024ecaf375e45c3d9ddd differ diff --git a/tests/resources/rebase-submodule/.gitted/objects/ff/b36e513f5fdf8a6ba850a20142676a2ac4807d b/tests/resources/rebase-submodule/.gitted/objects/ff/b36e513f5fdf8a6ba850a20142676a2ac4807d new file mode 100644 index 000000000..f655d12ea Binary files /dev/null and b/tests/resources/rebase-submodule/.gitted/objects/ff/b36e513f5fdf8a6ba850a20142676a2ac4807d differ diff --git a/tests/resources/rebase-submodule/.gitted/packed-refs b/tests/resources/rebase-submodule/.gitted/packed-refs new file mode 100644 index 000000000..44ac842a1 Binary files /dev/null and b/tests/resources/rebase-submodule/.gitted/packed-refs differ diff --git a/tests/resources/rebase-submodule/.gitted/refs/heads/asparagus b/tests/resources/rebase-submodule/.gitted/refs/heads/asparagus new file mode 100644 index 000000000..e6adde8e6 Binary files /dev/null and b/tests/resources/rebase-submodule/.gitted/refs/heads/asparagus differ diff --git a/tests/resources/rebase-submodule/.gitted/refs/heads/master b/tests/resources/rebase-submodule/.gitted/refs/heads/master new file mode 100644 index 000000000..2523d491d Binary files /dev/null and b/tests/resources/rebase-submodule/.gitted/refs/heads/master differ diff --git a/tests/resources/rebase-submodule/asparagus.txt b/tests/resources/rebase-submodule/asparagus.txt new file mode 100644 index 000000000..ffb36e513 Binary files /dev/null and b/tests/resources/rebase-submodule/asparagus.txt differ diff --git a/tests/resources/rebase-submodule/beef.txt b/tests/resources/rebase-submodule/beef.txt new file mode 100644 index 000000000..68f6182f4 Binary files /dev/null and b/tests/resources/rebase-submodule/beef.txt differ diff --git a/tests/resources/rebase-submodule/bouilli.txt b/tests/resources/rebase-submodule/bouilli.txt new file mode 100644 index 000000000..4b7c56500 Binary files /dev/null and b/tests/resources/rebase-submodule/bouilli.txt differ diff --git a/tests/resources/rebase-submodule/gravy.txt b/tests/resources/rebase-submodule/gravy.txt new file mode 100644 index 000000000..c4e6cca3e Binary files /dev/null and b/tests/resources/rebase-submodule/gravy.txt differ diff --git a/tests/resources/rebase-submodule/my-submodule b/tests/resources/rebase-submodule/my-submodule new file mode 160000 index 000000000..efad0b11c --- /dev/null +++ b/tests/resources/rebase-submodule/my-submodule @@ -0,0 +1 @@ +Subproject commit efad0b11c47cb2f0220cbd6f5b0f93bb99064b00 diff --git a/tests/resources/rebase-submodule/oyster.txt b/tests/resources/rebase-submodule/oyster.txt new file mode 100644 index 000000000..68af1fc74 Binary files /dev/null and b/tests/resources/rebase-submodule/oyster.txt differ diff --git a/tests/resources/rebase-submodule/veal.txt b/tests/resources/rebase-submodule/veal.txt new file mode 100644 index 000000000..a7b066537 Binary files /dev/null and b/tests/resources/rebase-submodule/veal.txt differ diff --git a/tests/resources/sha1/hello_c b/tests/resources/sha1/hello_c new file mode 100644 index 000000000..45950b2ad Binary files /dev/null and b/tests/resources/sha1/hello_c differ diff --git a/tests/resources/sha1/shattered-1.pdf b/tests/resources/sha1/shattered-1.pdf new file mode 100644 index 000000000..ba9aaa145 Binary files /dev/null and b/tests/resources/sha1/shattered-1.pdf differ diff --git a/tests/resources/submodules-worktree-child/.gitted b/tests/resources/submodules-worktree-child/.gitted new file mode 100644 index 000000000..03286f522 Binary files /dev/null and b/tests/resources/submodules-worktree-child/.gitted differ diff --git a/tests/resources/submodules-worktree-child/README b/tests/resources/submodules-worktree-child/README new file mode 100644 index 000000000..a8233120f Binary files /dev/null and b/tests/resources/submodules-worktree-child/README differ diff --git a/tests/resources/submodules-worktree-child/branch_file.txt b/tests/resources/submodules-worktree-child/branch_file.txt new file mode 100644 index 000000000..3697d64be Binary files /dev/null and b/tests/resources/submodules-worktree-child/branch_file.txt differ diff --git a/tests/resources/submodules-worktree-child/new.txt b/tests/resources/submodules-worktree-child/new.txt new file mode 100644 index 000000000..a71586c1d Binary files /dev/null and b/tests/resources/submodules-worktree-child/new.txt differ diff --git a/tests/resources/submodules-worktree-parent/.gitmodules b/tests/resources/submodules-worktree-parent/.gitmodules new file mode 100644 index 000000000..78308c925 Binary files /dev/null and b/tests/resources/submodules-worktree-parent/.gitmodules differ diff --git a/tests/resources/submodules-worktree-parent/.gitted b/tests/resources/submodules-worktree-parent/.gitted new file mode 100644 index 000000000..87bd9ae29 Binary files /dev/null and b/tests/resources/submodules-worktree-parent/.gitted differ diff --git a/tests/resources/submodules-worktree-parent/deleted b/tests/resources/submodules-worktree-parent/deleted new file mode 100644 index 000000000..092bfb9bd Binary files /dev/null and b/tests/resources/submodules-worktree-parent/deleted differ diff --git a/tests/resources/submodules-worktree-parent/modified b/tests/resources/submodules-worktree-parent/modified new file mode 100644 index 000000000..092bfb9bd Binary files /dev/null and b/tests/resources/submodules-worktree-parent/modified differ diff --git a/tests/resources/submodules-worktree-parent/unmodified b/tests/resources/submodules-worktree-parent/unmodified new file mode 100644 index 000000000..092bfb9bd Binary files /dev/null and b/tests/resources/submodules-worktree-parent/unmodified differ diff --git a/tests/resources/submodules/.gitted/logs/refs/heads/submodules-worktree-parent b/tests/resources/submodules/.gitted/logs/refs/heads/submodules-worktree-parent new file mode 100644 index 000000000..65e988535 Binary files /dev/null and b/tests/resources/submodules/.gitted/logs/refs/heads/submodules-worktree-parent differ diff --git a/tests/resources/submodules/.gitted/refs/heads/submodules-worktree-parent b/tests/resources/submodules/.gitted/refs/heads/submodules-worktree-parent new file mode 100644 index 000000000..32b935853 Binary files /dev/null and b/tests/resources/submodules/.gitted/refs/heads/submodules-worktree-parent differ diff --git a/tests/resources/submodules/.gitted/worktrees/submodules-worktree-parent/HEAD b/tests/resources/submodules/.gitted/worktrees/submodules-worktree-parent/HEAD new file mode 100644 index 000000000..a07134b85 Binary files /dev/null and b/tests/resources/submodules/.gitted/worktrees/submodules-worktree-parent/HEAD differ diff --git a/tests/resources/submodules/.gitted/worktrees/submodules-worktree-parent/ORIG_HEAD b/tests/resources/submodules/.gitted/worktrees/submodules-worktree-parent/ORIG_HEAD new file mode 100644 index 000000000..32b935853 Binary files /dev/null and b/tests/resources/submodules/.gitted/worktrees/submodules-worktree-parent/ORIG_HEAD differ diff --git a/tests/resources/submodules/.gitted/worktrees/submodules-worktree-parent/commondir b/tests/resources/submodules/.gitted/worktrees/submodules-worktree-parent/commondir new file mode 100644 index 000000000..aab0408ce Binary files /dev/null and b/tests/resources/submodules/.gitted/worktrees/submodules-worktree-parent/commondir differ diff --git a/tests/resources/submodules/.gitted/worktrees/submodules-worktree-parent/gitdir b/tests/resources/submodules/.gitted/worktrees/submodules-worktree-parent/gitdir new file mode 100644 index 000000000..eaaf13b95 Binary files /dev/null and b/tests/resources/submodules/.gitted/worktrees/submodules-worktree-parent/gitdir differ diff --git a/tests/resources/submodules/.gitted/worktrees/submodules-worktree-parent/index b/tests/resources/submodules/.gitted/worktrees/submodules-worktree-parent/index new file mode 100644 index 000000000..5b68f18a4 Binary files /dev/null and b/tests/resources/submodules/.gitted/worktrees/submodules-worktree-parent/index differ diff --git a/tests/resources/submodules/testrepo/.gitted/config b/tests/resources/submodules/testrepo/.gitted/config index d6dcad12b..8e5571191 100644 Binary files a/tests/resources/submodules/testrepo/.gitted/config and b/tests/resources/submodules/testrepo/.gitted/config differ diff --git a/tests/resources/submodules/testrepo/.gitted/logs/refs/heads/submodules-worktree-child b/tests/resources/submodules/testrepo/.gitted/logs/refs/heads/submodules-worktree-child new file mode 100644 index 000000000..dd4650ff8 Binary files /dev/null and b/tests/resources/submodules/testrepo/.gitted/logs/refs/heads/submodules-worktree-child differ diff --git a/tests/resources/submodules/testrepo/.gitted/refs/heads/submodules-worktree-child b/tests/resources/submodules/testrepo/.gitted/refs/heads/submodules-worktree-child new file mode 100644 index 000000000..3d8f0a402 Binary files /dev/null and b/tests/resources/submodules/testrepo/.gitted/refs/heads/submodules-worktree-child differ diff --git a/tests/resources/submodules/testrepo/.gitted/worktrees/submodules-worktree-child/HEAD b/tests/resources/submodules/testrepo/.gitted/worktrees/submodules-worktree-child/HEAD new file mode 100644 index 000000000..ef82bd4df Binary files /dev/null and b/tests/resources/submodules/testrepo/.gitted/worktrees/submodules-worktree-child/HEAD differ diff --git a/tests/resources/submodules/testrepo/.gitted/worktrees/submodules-worktree-child/ORIG_HEAD b/tests/resources/submodules/testrepo/.gitted/worktrees/submodules-worktree-child/ORIG_HEAD new file mode 100644 index 000000000..3d8f0a402 Binary files /dev/null and b/tests/resources/submodules/testrepo/.gitted/worktrees/submodules-worktree-child/ORIG_HEAD differ diff --git a/tests/resources/submodules/testrepo/.gitted/worktrees/submodules-worktree-child/commondir b/tests/resources/submodules/testrepo/.gitted/worktrees/submodules-worktree-child/commondir new file mode 100644 index 000000000..aab0408ce Binary files /dev/null and b/tests/resources/submodules/testrepo/.gitted/worktrees/submodules-worktree-child/commondir differ diff --git a/tests/resources/submodules/testrepo/.gitted/worktrees/submodules-worktree-child/gitdir b/tests/resources/submodules/testrepo/.gitted/worktrees/submodules-worktree-child/gitdir new file mode 100644 index 000000000..b0ef96e11 Binary files /dev/null and b/tests/resources/submodules/testrepo/.gitted/worktrees/submodules-worktree-child/gitdir differ diff --git a/tests/resources/submodules/testrepo/.gitted/worktrees/submodules-worktree-child/index b/tests/resources/submodules/testrepo/.gitted/worktrees/submodules-worktree-child/index new file mode 100644 index 000000000..52a42f966 Binary files /dev/null and b/tests/resources/submodules/testrepo/.gitted/worktrees/submodules-worktree-child/index differ diff --git a/tests/resources/testrepo-worktree/.gitted b/tests/resources/testrepo-worktree/.gitted new file mode 100644 index 000000000..fe4556a92 Binary files /dev/null and b/tests/resources/testrepo-worktree/.gitted differ diff --git a/tests/resources/testrepo-worktree/README b/tests/resources/testrepo-worktree/README new file mode 100644 index 000000000..a8233120f Binary files /dev/null and b/tests/resources/testrepo-worktree/README differ diff --git a/tests/resources/testrepo-worktree/branch_file.txt b/tests/resources/testrepo-worktree/branch_file.txt new file mode 100644 index 000000000..3697d64be Binary files /dev/null and b/tests/resources/testrepo-worktree/branch_file.txt differ diff --git a/tests/resources/testrepo-worktree/link_to_new.txt b/tests/resources/testrepo-worktree/link_to_new.txt new file mode 120000 index 000000000..c0528fd6c --- /dev/null +++ b/tests/resources/testrepo-worktree/link_to_new.txt @@ -0,0 +1 @@ +new.txt \ No newline at end of file diff --git a/tests/resources/testrepo-worktree/new.txt b/tests/resources/testrepo-worktree/new.txt new file mode 100644 index 000000000..a71586c1d Binary files /dev/null and b/tests/resources/testrepo-worktree/new.txt differ diff --git a/tests/resources/testrepo/.gitted/logs/refs/heads/testrepo-worktree b/tests/resources/testrepo/.gitted/logs/refs/heads/testrepo-worktree new file mode 100644 index 000000000..93ab5f06f Binary files /dev/null and b/tests/resources/testrepo/.gitted/logs/refs/heads/testrepo-worktree differ diff --git a/tests/resources/testrepo/.gitted/objects/9b/1719f5cf069568785080a0bbabbe7c377e22ae b/tests/resources/testrepo/.gitted/objects/9b/1719f5cf069568785080a0bbabbe7c377e22ae new file mode 100644 index 000000000..13e3f581a Binary files /dev/null and b/tests/resources/testrepo/.gitted/objects/9b/1719f5cf069568785080a0bbabbe7c377e22ae differ diff --git a/tests/resources/testrepo/.gitted/objects/a3/8d028f71eaa590febb7d716b1ca32350cf70da b/tests/resources/testrepo/.gitted/objects/a3/8d028f71eaa590febb7d716b1ca32350cf70da new file mode 100644 index 000000000..4df22ec17 Binary files /dev/null and b/tests/resources/testrepo/.gitted/objects/a3/8d028f71eaa590febb7d716b1ca32350cf70da differ diff --git a/tests/resources/testrepo/.gitted/objects/ad/edac69457183c8265c8a9614c1c4fed31d1ff3 b/tests/resources/testrepo/.gitted/objects/ad/edac69457183c8265c8a9614c1c4fed31d1ff3 new file mode 100644 index 000000000..c054fc0c4 Binary files /dev/null and b/tests/resources/testrepo/.gitted/objects/ad/edac69457183c8265c8a9614c1c4fed31d1ff3 differ diff --git a/tests/resources/testrepo/.gitted/refs/heads/merge-conflict b/tests/resources/testrepo/.gitted/refs/heads/merge-conflict new file mode 100644 index 000000000..3e24a24e0 Binary files /dev/null and b/tests/resources/testrepo/.gitted/refs/heads/merge-conflict differ diff --git a/tests/resources/testrepo/.gitted/refs/heads/testrepo-worktree b/tests/resources/testrepo/.gitted/refs/heads/testrepo-worktree new file mode 100644 index 000000000..f31fe781b Binary files /dev/null and b/tests/resources/testrepo/.gitted/refs/heads/testrepo-worktree differ diff --git a/tests/resources/testrepo/.gitted/worktrees/testrepo-worktree/HEAD b/tests/resources/testrepo/.gitted/worktrees/testrepo-worktree/HEAD new file mode 100644 index 000000000..1b8637e32 Binary files /dev/null and b/tests/resources/testrepo/.gitted/worktrees/testrepo-worktree/HEAD differ diff --git a/tests/resources/testrepo/.gitted/worktrees/testrepo-worktree/commondir b/tests/resources/testrepo/.gitted/worktrees/testrepo-worktree/commondir new file mode 100644 index 000000000..aab0408ce Binary files /dev/null and b/tests/resources/testrepo/.gitted/worktrees/testrepo-worktree/commondir differ diff --git a/tests/resources/testrepo/.gitted/worktrees/testrepo-worktree/gitdir b/tests/resources/testrepo/.gitted/worktrees/testrepo-worktree/gitdir new file mode 100644 index 000000000..0d37a5792 Binary files /dev/null and b/tests/resources/testrepo/.gitted/worktrees/testrepo-worktree/gitdir differ diff --git a/tests/resources/testrepo/.gitted/worktrees/testrepo-worktree/index b/tests/resources/testrepo/.gitted/worktrees/testrepo-worktree/index new file mode 100644 index 000000000..41141906e Binary files /dev/null and b/tests/resources/testrepo/.gitted/worktrees/testrepo-worktree/index differ diff --git a/tests/resources/testrepo/.gitted/worktrees/testrepo-worktree/logs/HEAD b/tests/resources/testrepo/.gitted/worktrees/testrepo-worktree/logs/HEAD new file mode 100644 index 000000000..3bede502e Binary files /dev/null and b/tests/resources/testrepo/.gitted/worktrees/testrepo-worktree/logs/HEAD differ diff --git a/tests/revwalk/basic.c b/tests/revwalk/basic.c index 89140bc54..547050c68 100644 --- a/tests/revwalk/basic.c +++ b/tests/revwalk/basic.c @@ -177,7 +177,7 @@ void test_revwalk_basic__glob_heads_with_invalid(void) /* walking */; /* git log --branches --oneline | wc -l => 16 */ - cl_assert_equal_i(18, i); + cl_assert_equal_i(19, i); } void test_revwalk_basic__push_head(void) @@ -331,6 +331,40 @@ void test_revwalk_basic__hide_then_push(void) cl_assert_equal_i(i, 0); } +void test_revwalk_basic__topo_crash(void) +{ + git_oid oid; + git_oid_fromstr(&oid, "5b5b025afb0b4c913b4c338a42934a3863bf3644"); + + revwalk_basic_setup_walk(NULL); + git_revwalk_sorting(_walk, GIT_SORT_TOPOLOGICAL); + + cl_git_pass(git_revwalk_push(_walk, &oid)); + cl_git_pass(git_revwalk_hide(_walk, &oid)); + + git_revwalk_next(&oid, _walk); +} + +void test_revwalk_basic__from_new_to_old(void) +{ + git_oid from_oid, to_oid, oid; + int i = 0; + + revwalk_basic_setup_walk(NULL); + git_revwalk_sorting(_walk, GIT_SORT_TIME); + + cl_git_pass(git_oid_fromstr(&to_oid, "5b5b025afb0b4c913b4c338a42934a3863bf3644")); + cl_git_pass(git_oid_fromstr(&from_oid, "a4a7dce85cf63874e984719f4fdd239f5145052f")); + + cl_git_pass(git_revwalk_push(_walk, &to_oid)); + cl_git_pass(git_revwalk_hide(_walk, &from_oid)); + + while (git_revwalk_next(&oid, _walk) == 0) + i++; + + cl_assert_equal_i(i, 0); +} + void test_revwalk_basic__push_range(void) { revwalk_basic_setup_walk(NULL); diff --git a/tests/status/ignore.c b/tests/status/ignore.c index c4878b2dd..23384fb1d 100644 --- a/tests/status/ignore.c +++ b/tests/status/ignore.c @@ -20,8 +20,8 @@ static void assert_ignored_( bool expected, const char *filepath, const char *file, int line) { int is_ignored = 0; - cl_git_pass_( - git_status_should_ignore(&is_ignored, g_repo, filepath), file, line); + cl_git_expect( + git_status_should_ignore(&is_ignored, g_repo, filepath), 0, file, line); clar__assert( (expected != 0) == (is_ignored != 0), file, line, "expected != is_ignored", filepath, 1); @@ -1077,3 +1077,81 @@ void test_status_ignore__negate_starstar(void) cl_git_pass(git_ignore_path_is_ignored(&ignored, g_repo, "code/projects/foo/bar/packages/repositories.config")); cl_assert_equal_i(0, ignored); } + +void test_status_ignore__ignore_all_toplevel_dirs_include_files(void) +{ + static const char *test_files[] = { + "empty_standard_repo/README.md", + "empty_standard_repo/src/main.c", + "empty_standard_repo/src/foo/foo.c", + "empty_standard_repo/dist/foo.o", + "empty_standard_repo/dist/main.o", + NULL + }; + + make_test_data("empty_standard_repo", test_files); + cl_git_mkfile( + "empty_standard_repo/.gitignore", + "/*/\n" + "!/src\n"); + + assert_is_ignored("dist/foo.o"); + assert_is_ignored("dist/main.o"); + + refute_is_ignored("README.md"); + refute_is_ignored("src/foo.c"); + refute_is_ignored("src/foo/foo.c"); +} + +void test_status_ignore__subdir_ignore_all_toplevel_dirs_include_files(void) +{ + static const char *test_files[] = { + "empty_standard_repo/project/README.md", + "empty_standard_repo/project/src/main.c", + "empty_standard_repo/project/src/foo/foo.c", + "empty_standard_repo/project/dist/foo.o", + "empty_standard_repo/project/dist/main.o", + NULL + }; + + make_test_data("empty_standard_repo", test_files); + cl_git_mkfile( + "empty_standard_repo/project/.gitignore", + "/*/\n" + "!/src\n"); + + assert_is_ignored("project/dist/foo.o"); + assert_is_ignored("project/dist/main.o"); + + refute_is_ignored("project/src/foo.c"); + refute_is_ignored("project/src/foo/foo.c"); + refute_is_ignored("project/README.md"); +} + +void test_status_ignore__subdir_ignore_everything_except_certain_files(void) +{ + static const char *test_files[] = { + "empty_standard_repo/project/README.md", + "empty_standard_repo/project/some_file", + "empty_standard_repo/project/src/main.c", + "empty_standard_repo/project/src/foo/foo.c", + "empty_standard_repo/project/dist/foo.o", + "empty_standard_repo/project/dist/main.o", + NULL + }; + + make_test_data("empty_standard_repo", test_files); + cl_git_mkfile( + "empty_standard_repo/project/.gitignore", + "/*\n" + "!/src\n" + "!README.md\n"); + + assert_is_ignored("project/some_file"); + assert_is_ignored("project/dist/foo.o"); + assert_is_ignored("project/dist/main.o"); + + refute_is_ignored("project/README.md"); + refute_is_ignored("project/src/foo.c"); + refute_is_ignored("project/src/foo/foo.c"); +} diff --git a/tests/submodule/lookup.c b/tests/submodule/lookup.c index 148f9273e..e36fc44e0 100644 --- a/tests/submodule/lookup.c +++ b/tests/submodule/lookup.c @@ -388,3 +388,28 @@ void test_submodule_lookup__renamed(void) cl_git_pass(git_submodule_foreach(g_repo, sm_lookup_cb, &data)); cl_assert_equal_i(8, data.count); } + +void test_submodule_lookup_cached(void) { + git_submodule *sm; + git_submodule *sm2; + /* See that the simple tests still pass. */ + + git_repository_submodule_cache_all(g_repo); + test_submodule_lookup__simple_lookup(); + git_repository_submodule_cache_clear(g_repo); + test_submodule_lookup__simple_lookup(); + + /* Check that subsequent calls return different objects when cached. */ + git_repository_submodule_cache_all(g_repo); + cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_unchanged")); + cl_git_pass(git_submodule_lookup(&sm2, g_repo, "sm_unchanged")); + cl_assert_equal_p(sm, sm2); + git_submodule_free(sm2); + + /* and that we get new objects again after clearing the cache. */ + git_repository_submodule_cache_clear(g_repo); + cl_git_pass(git_submodule_lookup(&sm2, g_repo, "sm_unchanged")); + cl_assert(sm != sm2); + git_submodule_free(sm); + git_submodule_free(sm2); +} diff --git a/tests/submodule/open.c b/tests/submodule/open.c new file mode 100644 index 000000000..0ef01ec24 --- /dev/null +++ b/tests/submodule/open.c @@ -0,0 +1,90 @@ +#include "clar_libgit2.h" +#include "submodule_helpers.h" +#include "path.h" + +static git_repository *g_parent; +static git_repository *g_child; +static git_submodule *g_module; + +void test_submodule_open__initialize(void) +{ + g_parent = setup_fixture_submod2(); +} + +void test_submodule_open__cleanup(void) +{ + git_submodule_free(g_module); + git_repository_free(g_child); + cl_git_sandbox_cleanup(); + g_parent = NULL; + g_child = NULL; + g_module = NULL; +} + +static void assert_sm_valid(git_repository *parent, git_repository *child, const char *sm_name) +{ + git_buf expected = GIT_BUF_INIT, actual = GIT_BUF_INIT; + + /* assert working directory */ + cl_git_pass(git_buf_joinpath(&expected, git_repository_workdir(parent), sm_name)); + cl_git_pass(git_path_prettify_dir(&expected, expected.ptr, NULL)); + cl_git_pass(git_buf_sets(&actual, git_repository_workdir(child))); + cl_git_pass(git_path_prettify_dir(&actual, actual.ptr, NULL)); + cl_assert_equal_s(expected.ptr, actual.ptr); + + git_buf_clear(&expected); + git_buf_clear(&actual); + + /* assert common directory */ + cl_git_pass(git_buf_joinpath(&expected, git_repository_commondir(parent), "modules")); + cl_git_pass(git_buf_joinpath(&expected, expected.ptr, sm_name)); + cl_git_pass(git_path_prettify_dir(&expected, expected.ptr, NULL)); + cl_git_pass(git_buf_sets(&actual, git_repository_commondir(child))); + cl_git_pass(git_path_prettify_dir(&actual, actual.ptr, NULL)); + cl_assert_equal_s(expected.ptr, actual.ptr); + + /* assert git directory */ + cl_git_pass(git_buf_sets(&actual, git_repository_path(child))); + cl_git_pass(git_path_prettify_dir(&actual, actual.ptr, NULL)); + cl_assert_equal_s(expected.ptr, actual.ptr); + + git_buf_free(&expected); + git_buf_free(&actual); +} + +void test_submodule_open__opening_via_lookup_succeeds(void) +{ + cl_git_pass(git_submodule_lookup(&g_module, g_parent, "sm_unchanged")); + cl_git_pass(git_submodule_open(&g_child, g_module)); + assert_sm_valid(g_parent, g_child, "sm_unchanged"); +} + +void test_submodule_open__direct_open_succeeds(void) +{ + git_buf path = GIT_BUF_INIT; + + cl_git_pass(git_buf_joinpath(&path, git_repository_workdir(g_parent), "sm_unchanged")); + cl_git_pass(git_repository_open(&g_child, path.ptr)); + assert_sm_valid(g_parent, g_child, "sm_unchanged"); + + git_buf_free(&path); +} + +void test_submodule_open__direct_open_succeeds_for_broken_sm_with_gitdir(void) +{ + git_buf path = GIT_BUF_INIT; + + /* + * This is actually not a valid submodule, but we + * encountered at least one occasion where the gitdir + * file existed inside of a submodule's gitdir. As we are + * now able to open these submodules correctly, we still + * add a test for this. + */ + cl_git_mkfile("submod2/.git/modules/sm_unchanged/gitdir", ".git"); + cl_git_pass(git_buf_joinpath(&path, git_repository_workdir(g_parent), "sm_unchanged")); + cl_git_pass(git_repository_open(&g_child, path.ptr)); + assert_sm_valid(g_parent, g_child, "sm_unchanged"); + + git_buf_free(&path); +} diff --git a/tests/submodule/submodule_helpers.c b/tests/submodule/submodule_helpers.c index 6c2b9cf78..cd541ea86 100644 --- a/tests/submodule/submodule_helpers.c +++ b/tests/submodule/submodule_helpers.c @@ -204,7 +204,7 @@ void assert__submodule_exists( git_submodule *sm; int error = git_submodule_lookup(&sm, repo, name); if (error) - cl_git_report_failure(error, file, line, msg); + cl_git_report_failure(error, 0, file, line, msg); cl_assert_at_line(sm != NULL, file, line); git_submodule_free(sm); } diff --git a/tests/threads/basic.c b/tests/threads/basic.c index a9310bbd4..af6049090 100644 --- a/tests/threads/basic.c +++ b/tests/threads/basic.c @@ -54,12 +54,6 @@ static void *return_normally(void *param) { return param; } - -static void *exit_abruptly(void *param) -{ - git_thread_exit(param); - return NULL; -} #endif void test_threads_basic__exit(void) diff --git a/tests/threads/diff.c b/tests/threads/diff.c index c32811469..256040265 100644 --- a/tests/threads/diff.c +++ b/tests/threads/diff.c @@ -19,12 +19,27 @@ static git_repository *_repo; static git_tree *_a, *_b; static git_atomic _counts[4]; static int _check_counts; +#ifdef GIT_WIN32 +static int _retries; +#endif #define THREADS 20 +void test_threads_diff__initialize(void) +{ +#ifdef GIT_WIN32 + _retries = git_win32__retries; + git_win32__retries = 1; +#endif +} + void test_threads_diff__cleanup(void) { cl_git_sandbox_cleanup(); + +#ifdef GIT_WIN32 + git_win32__retries = _retries; +#endif } static void setup_trees(void) diff --git a/tests/worktree/config.c b/tests/worktree/config.c new file mode 100644 index 000000000..3ab317bb5 --- /dev/null +++ b/tests/worktree/config.c @@ -0,0 +1,45 @@ +#include "clar_libgit2.h" +#include "worktree_helpers.h" + +#define COMMON_REPO "testrepo" +#define WORKTREE_REPO "testrepo-worktree" + +static worktree_fixture fixture = + WORKTREE_FIXTURE_INIT(COMMON_REPO, WORKTREE_REPO); + +void test_worktree_config__initialize(void) +{ + setup_fixture_worktree(&fixture); +} + +void test_worktree_config__cleanup(void) +{ + cleanup_fixture_worktree(&fixture); +} + +void test_worktree_config__open(void) +{ + git_config *cfg; + + cl_git_pass(git_repository_config(&cfg, fixture.worktree)); + cl_assert(cfg != NULL); + + git_config_free(cfg); +} + +void test_worktree_config__set(void) +{ + git_config *cfg; + int32_t val; + + cl_git_pass(git_repository_config(&cfg, fixture.worktree)); + cl_git_pass(git_config_set_int32(cfg, "core.dummy", 5)); + git_config_free(cfg); + + // reopen to verify configuration has been set in the + // common dir + cl_git_pass(git_repository_config(&cfg, fixture.repo)); + cl_git_pass(git_config_get_int32(&val, cfg, "core.dummy")); + cl_assert_equal_i(val, 5); + git_config_free(cfg); +} diff --git a/tests/worktree/merge.c b/tests/worktree/merge.c new file mode 100644 index 000000000..36cc2a6c1 --- /dev/null +++ b/tests/worktree/merge.c @@ -0,0 +1,121 @@ +#include "clar_libgit2.h" + +#include "worktree_helpers.h" +#include "merge/merge_helpers.h" + +#define COMMON_REPO "testrepo" +#define WORKTREE_REPO "testrepo-worktree" + +#define MASTER_BRANCH "refs/heads/master" +#define CONFLICT_BRANCH "refs/heads/merge-conflict" + +#define CONFLICT_BRANCH_FILE_TXT \ + "<<<<<<< HEAD\n" \ + "hi\n" \ + "bye!\n" \ + "=======\n" \ + "conflict\n" \ + ">>>>>>> merge-conflict\n" \ + +static worktree_fixture fixture = + WORKTREE_FIXTURE_INIT(COMMON_REPO, WORKTREE_REPO); + +static const char *merge_files[] = { + GIT_MERGE_HEAD_FILE, + GIT_ORIG_HEAD_FILE, + GIT_MERGE_MODE_FILE, + GIT_MERGE_MSG_FILE, +}; + +void test_worktree_merge__initialize(void) +{ + setup_fixture_worktree(&fixture); +} + +void test_worktree_merge__cleanup(void) +{ + cleanup_fixture_worktree(&fixture); +} + +void test_worktree_merge__merge_head(void) +{ + git_reference *theirs_ref, *ref; + git_annotated_commit *theirs; + + cl_git_pass(git_reference_lookup(&theirs_ref, fixture.worktree, CONFLICT_BRANCH)); + cl_git_pass(git_annotated_commit_from_ref(&theirs, fixture.worktree, theirs_ref)); + cl_git_pass(git_merge(fixture.worktree, (const git_annotated_commit **)&theirs, 1, NULL, NULL)); + + cl_git_pass(git_reference_lookup(&ref, fixture.worktree, GIT_MERGE_HEAD_FILE)); + + git_reference_free(ref); + git_reference_free(theirs_ref); + git_annotated_commit_free(theirs); +} + +void test_worktree_merge__merge_setup(void) +{ + git_reference *ours_ref, *theirs_ref; + git_annotated_commit *ours, *theirs; + git_buf path = GIT_BUF_INIT; + unsigned i; + + cl_git_pass(git_reference_lookup(&ours_ref, fixture.worktree, MASTER_BRANCH)); + cl_git_pass(git_annotated_commit_from_ref(&ours, fixture.worktree, ours_ref)); + + cl_git_pass(git_reference_lookup(&theirs_ref, fixture.worktree, CONFLICT_BRANCH)); + cl_git_pass(git_annotated_commit_from_ref(&theirs, fixture.worktree, theirs_ref)); + + cl_git_pass(git_merge__setup(fixture.worktree, + ours, (const git_annotated_commit **)&theirs, 1)); + + for (i = 0; i < ARRAY_SIZE(merge_files); i++) { + git_buf_clear(&path); + cl_git_pass(git_buf_printf(&path, "%s/%s", + fixture.worktree->gitdir, merge_files[i])); + cl_assert(git_path_exists(path.ptr)); + } + + git_buf_free(&path); + git_reference_free(ours_ref); + git_reference_free(theirs_ref); + git_annotated_commit_free(ours); + git_annotated_commit_free(theirs); +} + +void test_worktree_merge__merge_conflict(void) +{ + git_buf path = GIT_BUF_INIT, buf = GIT_BUF_INIT; + git_reference *theirs_ref; + git_annotated_commit *theirs; + git_index *index; + const git_index_entry *entry; + size_t i, conflicts = 0; + + cl_git_pass(git_reference_lookup(&theirs_ref, fixture.worktree, CONFLICT_BRANCH)); + cl_git_pass(git_annotated_commit_from_ref(&theirs, fixture.worktree, theirs_ref)); + + cl_git_pass(git_merge(fixture.worktree, + (const git_annotated_commit **)&theirs, 1, NULL, NULL)); + + cl_git_pass(git_repository_index(&index, fixture.worktree)); + for (i = 0; i < git_index_entrycount(index); i++) { + cl_assert(entry = git_index_get_byindex(index, i)); + + if (git_index_entry_is_conflict(entry)) + conflicts++; + } + cl_assert_equal_sz(conflicts, 3); + + git_reference_free(theirs_ref); + git_annotated_commit_free(theirs); + git_index_free(index); + + cl_git_pass(git_buf_joinpath(&path, fixture.worktree->workdir, "branch_file.txt")); + cl_git_pass(git_futils_readbuffer(&buf, path.ptr)); + cl_assert_equal_s(buf.ptr, CONFLICT_BRANCH_FILE_TXT); + + git_buf_free(&path); + git_buf_free(&buf); +} + diff --git a/tests/worktree/open.c b/tests/worktree/open.c new file mode 100644 index 000000000..74b9007d9 --- /dev/null +++ b/tests/worktree/open.c @@ -0,0 +1,143 @@ +#include "clar_libgit2.h" +#include "repository.h" +#include "worktree.h" +#include "worktree_helpers.h" + +#define COMMON_REPO "testrepo" +#define WORKTREE_REPO "testrepo-worktree" + +static worktree_fixture fixture = + WORKTREE_FIXTURE_INIT(COMMON_REPO, WORKTREE_REPO); + +static void assert_worktree_valid(git_repository *wt, const char *parentdir, const char *wtdir) +{ + git_buf path = GIT_BUF_INIT; + + cl_assert(wt->is_worktree); + + cl_git_pass(git_buf_joinpath(&path, clar_sandbox_path(), wtdir)); + cl_git_pass(git_path_prettify(&path, path.ptr, NULL)); + cl_git_pass(git_path_to_dir(&path)); + cl_assert_equal_s(wt->workdir, path.ptr); + + cl_git_pass(git_buf_joinpath(&path, path.ptr, ".git")); + cl_git_pass(git_path_prettify(&path, path.ptr, NULL)); + cl_assert_equal_s(wt->gitlink, path.ptr); + + cl_git_pass(git_buf_joinpath(&path, clar_sandbox_path(), parentdir)); + cl_git_pass(git_buf_joinpath(&path, path.ptr, ".git")); + cl_git_pass(git_buf_joinpath(&path, path.ptr, "worktrees")); + cl_git_pass(git_buf_joinpath(&path, path.ptr, wtdir)); + cl_git_pass(git_path_prettify(&path, path.ptr, NULL)); + cl_git_pass(git_path_to_dir(&path)); + cl_assert_equal_s(wt->gitdir, path.ptr); + + git_buf_free(&path); +} + +void test_worktree_open__initialize(void) +{ + setup_fixture_worktree(&fixture); +} + +void test_worktree_open__cleanup(void) +{ + cleanup_fixture_worktree(&fixture); +} + +void test_worktree_open__repository(void) +{ + assert_worktree_valid(fixture.worktree, COMMON_REPO, WORKTREE_REPO); +} + +void test_worktree_open__repository_through_workdir(void) +{ + git_repository *wt; + + cl_git_pass(git_repository_open(&wt, WORKTREE_REPO)); + assert_worktree_valid(wt, COMMON_REPO, WORKTREE_REPO); + + git_repository_free(wt); +} + +void test_worktree_open__repository_through_gitlink(void) +{ + git_repository *wt; + + cl_git_pass(git_repository_open(&wt, WORKTREE_REPO "/.git")); + assert_worktree_valid(wt, COMMON_REPO, WORKTREE_REPO); + + git_repository_free(wt); +} + +void test_worktree_open__repository_through_gitdir(void) +{ + git_buf gitdir_path = GIT_BUF_INIT; + git_repository *wt; + + cl_git_pass(git_buf_joinpath(&gitdir_path, COMMON_REPO, ".git")); + cl_git_pass(git_buf_joinpath(&gitdir_path, gitdir_path.ptr, "worktrees")); + cl_git_pass(git_buf_joinpath(&gitdir_path, gitdir_path.ptr, "testrepo-worktree")); + + cl_git_pass(git_repository_open(&wt, gitdir_path.ptr)); + assert_worktree_valid(wt, COMMON_REPO, WORKTREE_REPO); + + git_buf_free(&gitdir_path); + git_repository_free(wt); +} + +void test_worktree_open__open_discovered_worktree(void) +{ + git_buf path = GIT_BUF_INIT; + git_repository *repo; + + cl_git_pass(git_repository_discover(&path, + git_repository_workdir(fixture.worktree), false, NULL)); + cl_git_pass(git_repository_open(&repo, path.ptr)); + cl_assert_equal_s(git_repository_workdir(fixture.worktree), + git_repository_workdir(repo)); + + git_buf_free(&path); + git_repository_free(repo); +} + +void test_worktree_open__repository_with_nonexistent_parent(void) +{ + git_repository *repo; + + cleanup_fixture_worktree(&fixture); + + cl_fixture_sandbox(WORKTREE_REPO); + cl_git_pass(p_chdir(WORKTREE_REPO)); + cl_git_pass(cl_rename(".gitted", ".git")); + cl_git_pass(p_chdir("..")); + + cl_git_fail(git_repository_open(&repo, WORKTREE_REPO)); + + cl_fixture_cleanup(WORKTREE_REPO); +} + +void test_worktree_open__open_from_repository(void) +{ + git_worktree *opened, *lookedup; + + cl_git_pass(git_worktree_open_from_repository(&opened, fixture.worktree)); + cl_git_pass(git_worktree_lookup(&lookedup, fixture.repo, WORKTREE_REPO)); + + cl_assert_equal_s(opened->name, lookedup->name); + cl_assert_equal_s(opened->gitdir_path, lookedup->gitdir_path); + cl_assert_equal_s(opened->gitlink_path, lookedup->gitlink_path); + cl_assert_equal_s(opened->parent_path, lookedup->parent_path); + cl_assert_equal_s(opened->commondir_path, lookedup->commondir_path); + cl_assert_equal_i(opened->locked, lookedup->locked); + + git_worktree_free(opened); + git_worktree_free(lookedup); +} + +void test_worktree_open__open_from_nonworktree_fails(void) +{ + git_worktree *wt; + + cl_git_fail(git_worktree_open_from_repository(&wt, fixture.repo)); +} diff --git a/tests/worktree/reflog.c b/tests/worktree/reflog.c new file mode 100644 index 000000000..6152eb385 --- /dev/null +++ b/tests/worktree/reflog.c @@ -0,0 +1,65 @@ +#include "clar_libgit2.h" +#include "worktree_helpers.h" + +#include "reflog.h" + +#define COMMON_REPO "testrepo" +#define WORKTREE_REPO "testrepo-worktree" + +#define REFLOG "refs/heads/testrepo-worktree" +#define REFLOG_MESSAGE "reflog message" + +static worktree_fixture fixture = + WORKTREE_FIXTURE_INIT(COMMON_REPO, WORKTREE_REPO); + +void test_worktree_reflog__initialize(void) +{ + setup_fixture_worktree(&fixture); +} + +void test_worktree_reflog__cleanup(void) +{ + cleanup_fixture_worktree(&fixture); +} + +void test_worktree_reflog__read(void) +{ + git_reflog *reflog; + const git_reflog_entry *entry; + + cl_git_pass(git_reflog_read(&reflog, fixture.worktree, REFLOG)); + cl_assert_equal_i(git_reflog_entrycount(reflog), 1); + + entry = git_reflog_entry_byindex(reflog, 0); + cl_assert(entry != NULL); + cl_assert_equal_s(git_reflog_entry_message(entry), "branch: Created from HEAD"); + + git_reflog_free(reflog); +} + +void test_worktree_reflog__append_then_read(void) +{ + git_reflog *reflog, *parent_reflog; + const git_reflog_entry *entry; + git_reference *head; + git_signature *sig; + const git_oid *oid; + + cl_git_pass(git_repository_head(&head, fixture.worktree)); + cl_assert((oid = git_reference_target(head)) != NULL); + cl_git_pass(git_signature_now(&sig, "foo", "foo@bar")); + + cl_git_pass(git_reflog_read(&reflog, fixture.worktree, REFLOG)); + cl_git_pass(git_reflog_append(reflog, oid, sig, REFLOG_MESSAGE)); + git_reflog_write(reflog); + + cl_git_pass(git_reflog_read(&parent_reflog, fixture.repo, REFLOG)); + entry = git_reflog_entry_byindex(parent_reflog, 0); + cl_assert(git_oid_cmp(oid, &entry->oid_old) == 0); + cl_assert(git_oid_cmp(oid, &entry->oid_cur) == 0); + + git_reference_free(head); + git_signature_free(sig); + git_reflog_free(reflog); + git_reflog_free(parent_reflog); +} diff --git a/tests/worktree/refs.c b/tests/worktree/refs.c new file mode 100644 index 000000000..a10f50a2c --- /dev/null +++ b/tests/worktree/refs.c @@ -0,0 +1,173 @@ +#include "clar_libgit2.h" +#include "path.h" +#include "refs.h" +#include "worktree.h" +#include "worktree_helpers.h" + +#define COMMON_REPO "testrepo" +#define WORKTREE_REPO "testrepo-worktree" + +static worktree_fixture fixture = + WORKTREE_FIXTURE_INIT(COMMON_REPO, WORKTREE_REPO); + +void test_worktree_refs__initialize(void) +{ + setup_fixture_worktree(&fixture); +} + +void test_worktree_refs__cleanup(void) +{ + cleanup_fixture_worktree(&fixture); +} + +void test_worktree_refs__list(void) +{ + git_strarray refs, wtrefs; + unsigned i, j; + int error = 0; + + cl_git_pass(git_reference_list(&refs, fixture.repo)); + cl_git_pass(git_reference_list(&wtrefs, fixture.worktree)); + + if (refs.count != wtrefs.count) + { + error = GIT_ERROR; + goto exit; + } + + for (i = 0; i < refs.count; i++) + { + int found = 0; + + for (j = 0; j < wtrefs.count; j++) + { + if (!strcmp(refs.strings[i], wtrefs.strings[j])) + { + found = 1; + break; + } + } + + if (!found) + { + error = GIT_ERROR; + goto exit; + } + } + +exit: + git_strarray_free(&refs); + git_strarray_free(&wtrefs); + cl_git_pass(error); +} + +void test_worktree_refs__read_head(void) +{ + git_reference *head; + + cl_git_pass(git_repository_head(&head, fixture.worktree)); + + git_reference_free(head); +} + +void test_worktree_refs__set_head_fails_when_worktree_wants_linked_repos_HEAD(void) +{ + git_reference *head; + + cl_git_pass(git_repository_head(&head, fixture.repo)); + cl_git_fail(git_repository_set_head(fixture.worktree, git_reference_name(head))); + + git_reference_free(head); +} + +void test_worktree_refs__set_head_fails_when_main_repo_wants_worktree_head(void) +{ + git_reference *head; + + cl_git_pass(git_repository_head(&head, fixture.worktree)); + cl_git_fail(git_repository_set_head(fixture.repo, git_reference_name(head))); + + git_reference_free(head); +} + +void test_worktree_refs__set_head_works_for_current_HEAD(void) +{ + git_reference *head; + + cl_git_pass(git_repository_head(&head, fixture.repo)); + cl_git_pass(git_repository_set_head(fixture.repo, git_reference_name(head))); + + git_reference_free(head); +} + +void test_worktree_refs__set_head_fails_when_already_checked_out(void) +{ + cl_git_fail(git_repository_set_head(fixture.repo, "refs/heads/testrepo-worktree")); +} + +void test_worktree_refs__delete_fails_for_checked_out_branch(void) +{ + git_reference *branch; + + cl_git_pass(git_branch_lookup(&branch, fixture.repo, + "testrepo-worktree", GIT_BRANCH_LOCAL)); + cl_git_fail(git_branch_delete(branch)); + + git_reference_free(branch); +} + +void test_worktree_refs__delete_succeeds_after_pruning_worktree(void) +{ + git_worktree_prune_options opts = GIT_WORKTREE_PRUNE_OPTIONS_INIT; + git_reference *branch; + git_worktree *worktree; + + opts.flags = GIT_WORKTREE_PRUNE_VALID; + + cl_git_pass(git_worktree_lookup(&worktree, fixture.repo, fixture.worktreename)); + cl_git_pass(git_worktree_prune(worktree, &opts)); + git_worktree_free(worktree); + + cl_git_pass(git_branch_lookup(&branch, fixture.repo, + "testrepo-worktree", GIT_BRANCH_LOCAL)); + cl_git_pass(git_branch_delete(branch)); + git_reference_free(branch); +} + +void test_worktree_refs__renaming_reference_updates_worktree_heads(void) +{ + git_reference *head, *branch, *renamed; + + cl_git_pass(git_branch_lookup(&branch, fixture.repo, + "testrepo-worktree", GIT_BRANCH_LOCAL)); + cl_git_pass(git_reference_rename(&renamed, branch, "refs/heads/renamed", 0, NULL)); + cl_git_pass(git_repository_head(&head, fixture.worktree)); + + git_reference_free(head); + git_reference_free(branch); + git_reference_free(renamed); +} + +void test_worktree_refs__creating_refs_uses_commondir(void) +{ + git_reference *head, *branch, *lookup; + git_commit *commit; + git_buf refpath = GIT_BUF_INIT; + + cl_git_pass(git_buf_joinpath(&refpath, + git_repository_commondir(fixture.worktree), "refs/heads/testbranch")); + cl_assert(!git_path_exists(refpath.ptr)); + + cl_git_pass(git_repository_head(&head, fixture.worktree)); + cl_git_pass(git_commit_lookup(&commit, fixture.worktree, git_reference_target(head))); + cl_git_pass(git_branch_create(&branch, fixture.worktree, "testbranch", commit, 0)); + cl_git_pass(git_branch_lookup(&lookup, fixture.worktree, "testbranch", GIT_BRANCH_LOCAL)); + cl_assert(git_reference_cmp(branch, lookup) == 0); + cl_assert(git_path_exists(refpath.ptr)); + + git_reference_free(lookup); + git_reference_free(branch); + git_reference_free(head); + git_commit_free(commit); + git_buf_free(&refpath); +} diff --git a/tests/worktree/repository.c b/tests/worktree/repository.c new file mode 100644 index 000000000..5c7595c64 --- /dev/null +++ b/tests/worktree/repository.c @@ -0,0 +1,63 @@ +#include "clar_libgit2.h" +#include "worktree_helpers.h" +#include "submodule/submodule_helpers.h" + +#include "repository.h" + +#define COMMON_REPO "testrepo" +#define WORKTREE_REPO "testrepo-worktree" + +static worktree_fixture fixture = + WORKTREE_FIXTURE_INIT(COMMON_REPO, WORKTREE_REPO); + +void test_worktree_repository__initialize(void) +{ + setup_fixture_worktree(&fixture); +} + +void test_worktree_repository__cleanup(void) +{ + cleanup_fixture_worktree(&fixture); +} + +void test_worktree_repository__head(void) +{ + git_reference *ref, *head; + + 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); + + git_reference_free(ref); + git_reference_free(head); +} + +void test_worktree_repository__head_fails_for_invalid_worktree(void) +{ + git_reference *head = NULL; + + cl_git_fail(git_repository_head_for_worktree(&head, fixture.repo, "invalid")); + cl_assert(head == NULL); +} + +void test_worktree_repository__head_detached(void) +{ + git_reference *ref, *head; + + cl_git_pass(git_reference_lookup(&ref, fixture.repo, "refs/heads/testrepo-worktree")); + cl_git_pass(git_repository_set_head_detached(fixture.worktree, &ref->target.oid)); + + cl_assert(git_repository_head_detached(fixture.worktree)); + cl_assert(git_repository_head_detached_for_worktree(fixture.repo, "testrepo-worktree")); + cl_git_fail(git_repository_head_for_worktree(&head, fixture.repo, "testrepo-worktree")); + + git_reference_free(ref); +} + +void test_worktree_repository__head_detached_fails_for_invalid_worktree(void) +{ + git_reference *head = NULL; + + cl_git_fail(git_repository_head_detached_for_worktree(fixture.repo, "invalid")); + cl_assert(head == NULL); +} diff --git a/tests/worktree/submodule.c b/tests/worktree/submodule.c new file mode 100644 index 000000000..294385226 --- /dev/null +++ b/tests/worktree/submodule.c @@ -0,0 +1,92 @@ +#include "clar_libgit2.h" +#include "repository.h" +#include "worktree.h" +#include "worktree_helpers.h" + +#define WORKTREE_PARENT "submodules-worktree-parent" +#define WORKTREE_CHILD "submodules-worktree-child" + +static worktree_fixture parent + = WORKTREE_FIXTURE_INIT("submodules", WORKTREE_PARENT); +static worktree_fixture child + = WORKTREE_FIXTURE_INIT(NULL, WORKTREE_CHILD); + +void test_worktree_submodule__initialize(void) +{ + setup_fixture_worktree(&parent); + + cl_git_pass(p_rename( + "submodules/testrepo/.gitted", + "submodules/testrepo/.git")); + + setup_fixture_worktree(&child); +} + +void test_worktree_submodule__cleanup(void) +{ + cleanup_fixture_worktree(&child); + cleanup_fixture_worktree(&parent); +} + +void test_worktree_submodule__submodule_worktree_parent(void) +{ + cl_assert(git_repository_path(parent.worktree) != NULL); + cl_assert(git_repository_workdir(parent.worktree) != NULL); + + cl_assert(!parent.repo->is_worktree); + cl_assert(parent.worktree->is_worktree); +} + +void test_worktree_submodule__submodule_worktree_child(void) +{ + cl_assert(!parent.repo->is_worktree); + cl_assert(parent.worktree->is_worktree); + cl_assert(child.worktree->is_worktree); +} + +void test_worktree_submodule__open_discovered_submodule_worktree(void) +{ + git_buf path = GIT_BUF_INIT; + git_repository *repo; + + cl_git_pass(git_repository_discover(&path, + git_repository_workdir(child.worktree), false, NULL)); + cl_git_pass(git_repository_open(&repo, path.ptr)); + cl_assert_equal_s(git_repository_workdir(child.worktree), + git_repository_workdir(repo)); + + git_buf_free(&path); + git_repository_free(repo); +} + +void test_worktree_submodule__resolve_relative_url(void) +{ + git_buf wt_path = GIT_BUF_INIT; + git_buf sm_relative_path = GIT_BUF_INIT, wt_relative_path = GIT_BUF_INIT; + git_repository *repo; + git_worktree *wt; + + cl_git_pass(git_futils_mkdir("subdir", 0755, GIT_MKDIR_PATH)); + cl_git_pass(git_path_prettify_dir(&wt_path, "subdir", NULL)); + cl_git_pass(git_buf_joinpath(&wt_path, wt_path.ptr, "wt")); + + /* Open child repository, which is a submodule */ + cl_git_pass(git_repository_open(&child.repo, WORKTREE_CHILD)); + + /* Create worktree of submodule repository */ + cl_git_pass(git_worktree_add(&wt, child.repo, "subdir", wt_path.ptr, NULL)); + cl_git_pass(git_repository_open_from_worktree(&repo, wt)); + + cl_git_pass(git_submodule_resolve_url(&sm_relative_path, repo, + "../" WORKTREE_CHILD)); + cl_git_pass(git_submodule_resolve_url(&wt_relative_path, child.repo, + "../" WORKTREE_CHILD)); + + cl_assert_equal_s(sm_relative_path.ptr, wt_relative_path.ptr); + + git_worktree_free(wt); + git_repository_free(repo); + git_buf_free(&wt_path); + git_buf_free(&sm_relative_path); + git_buf_free(&wt_relative_path); +} diff --git a/tests/worktree/worktree.c b/tests/worktree/worktree.c new file mode 100644 index 000000000..4ac3b8bba --- /dev/null +++ b/tests/worktree/worktree.c @@ -0,0 +1,583 @@ +#include "clar_libgit2.h" +#include "worktree_helpers.h" +#include "submodule/submodule_helpers.h" + +#include "checkout.h" +#include "repository.h" +#include "worktree.h" + +#define COMMON_REPO "testrepo" +#define WORKTREE_REPO "testrepo-worktree" + +static worktree_fixture fixture = + WORKTREE_FIXTURE_INIT(COMMON_REPO, WORKTREE_REPO); + +void test_worktree_worktree__initialize(void) +{ + setup_fixture_worktree(&fixture); +} + +void test_worktree_worktree__cleanup(void) +{ + cleanup_fixture_worktree(&fixture); +} + +void test_worktree_worktree__list(void) +{ + git_strarray wts; + + cl_git_pass(git_worktree_list(&wts, fixture.repo)); + cl_assert_equal_i(wts.count, 1); + cl_assert_equal_s(wts.strings[0], "testrepo-worktree"); + + git_strarray_free(&wts); +} + +void test_worktree_worktree__list_with_invalid_worktree_dirs(void) +{ + const char *filesets[3][2] = { + { "gitdir", "commondir" }, + { "gitdir", "HEAD" }, + { "HEAD", "commondir" }, + }; + git_buf path = GIT_BUF_INIT; + git_strarray wts; + unsigned i, j, len; + + cl_git_pass(git_buf_printf(&path, "%s/worktrees/invalid", + fixture.repo->commondir)); + cl_git_pass(p_mkdir(path.ptr, 0755)); + + len = path.size; + + for (i = 0; i < ARRAY_SIZE(filesets); i++) { + + for (j = 0; j < ARRAY_SIZE(filesets[i]); j++) { + git_buf_truncate(&path, len); + cl_git_pass(git_buf_joinpath(&path, path.ptr, filesets[i][j])); + cl_git_pass(p_close(p_creat(path.ptr, 0644))); + } + + cl_git_pass(git_worktree_list(&wts, fixture.worktree)); + cl_assert_equal_i(wts.count, 1); + cl_assert_equal_s(wts.strings[0], "testrepo-worktree"); + git_strarray_free(&wts); + + for (j = 0; j < ARRAY_SIZE(filesets[i]); j++) { + git_buf_truncate(&path, len); + cl_git_pass(git_buf_joinpath(&path, path.ptr, filesets[i][j])); + p_unlink(path.ptr); + } + } + + git_buf_free(&path); +} + +void test_worktree_worktree__list_in_worktree_repo(void) +{ + git_strarray wts; + + cl_git_pass(git_worktree_list(&wts, fixture.worktree)); + cl_assert_equal_i(wts.count, 1); + cl_assert_equal_s(wts.strings[0], "testrepo-worktree"); + + git_strarray_free(&wts); +} + +void test_worktree_worktree__list_bare(void) +{ + git_repository *repo; + git_strarray wts; + + repo = cl_git_sandbox_init("testrepo.git"); + cl_git_pass(git_worktree_list(&wts, repo)); + cl_assert_equal_i(wts.count, 0); + + git_repository_free(repo); +} + +void test_worktree_worktree__list_without_worktrees(void) +{ + git_repository *repo; + git_strarray wts; + + repo = cl_git_sandbox_init("testrepo2"); + cl_git_pass(git_worktree_list(&wts, repo)); + cl_assert_equal_i(wts.count, 0); + + git_repository_free(repo); +} + +void test_worktree_worktree__lookup(void) +{ + git_worktree *wt; + git_buf gitdir_path = GIT_BUF_INIT; + + cl_git_pass(git_worktree_lookup(&wt, fixture.repo, "testrepo-worktree")); + + cl_git_pass(git_buf_joinpath(&gitdir_path, fixture.repo->commondir, "worktrees/testrepo-worktree/")); + + cl_assert_equal_s(wt->gitdir_path, gitdir_path.ptr); + cl_assert_equal_s(wt->parent_path, fixture.repo->workdir); + cl_assert_equal_s(wt->gitlink_path, fixture.worktree->gitlink); + cl_assert_equal_s(wt->commondir_path, fixture.repo->gitdir); + cl_assert_equal_s(wt->commondir_path, fixture.repo->commondir); + + git_buf_free(&gitdir_path); + git_worktree_free(wt); +} + +void test_worktree_worktree__lookup_nonexistent_worktree(void) +{ + git_worktree *wt; + + cl_git_fail(git_worktree_lookup(&wt, fixture.repo, "nonexistent")); + cl_assert_equal_p(wt, NULL); +} + +void test_worktree_worktree__open(void) +{ + git_worktree *wt; + git_repository *repo; + + cl_git_pass(git_worktree_lookup(&wt, fixture.repo, "testrepo-worktree")); + + cl_git_pass(git_repository_open_from_worktree(&repo, wt)); + cl_assert_equal_s(git_repository_workdir(repo), + git_repository_workdir(fixture.worktree)); + + git_repository_free(repo); + git_worktree_free(wt); +} + +void test_worktree_worktree__open_invalid_commondir(void) +{ + git_worktree *wt; + git_repository *repo; + git_buf buf = GIT_BUF_INIT, path = GIT_BUF_INIT; + + cl_git_pass(git_buf_sets(&buf, "/path/to/nonexistent/commondir")); + cl_git_pass(git_buf_printf(&path, + "%s/worktrees/testrepo-worktree/commondir", + fixture.repo->commondir)); + cl_git_pass(git_futils_writebuffer(&buf, path.ptr, O_RDWR, 0644)); + + cl_git_pass(git_worktree_lookup(&wt, fixture.repo, "testrepo-worktree")); + cl_git_fail(git_repository_open_from_worktree(&repo, wt)); + + git_buf_free(&buf); + git_buf_free(&path); + git_worktree_free(wt); +} + +void test_worktree_worktree__open_invalid_gitdir(void) +{ + git_worktree *wt; + git_repository *repo; + git_buf buf = GIT_BUF_INIT, path = GIT_BUF_INIT; + + cl_git_pass(git_buf_sets(&buf, "/path/to/nonexistent/gitdir")); + cl_git_pass(git_buf_printf(&path, + "%s/worktrees/testrepo-worktree/gitdir", + fixture.repo->commondir)); + cl_git_pass(git_futils_writebuffer(&buf, path.ptr, O_RDWR, 0644)); + + cl_git_pass(git_worktree_lookup(&wt, fixture.repo, "testrepo-worktree")); + cl_git_fail(git_repository_open_from_worktree(&repo, wt)); + + git_buf_free(&buf); + git_buf_free(&path); + git_worktree_free(wt); +} + +void test_worktree_worktree__open_invalid_parent(void) +{ + git_worktree *wt; + git_repository *repo; + git_buf buf = GIT_BUF_INIT; + + cl_git_pass(git_buf_sets(&buf, "/path/to/nonexistent/gitdir")); + cl_git_pass(git_futils_writebuffer(&buf, + fixture.worktree->gitlink, O_RDWR, 0644)); + + cl_git_pass(git_worktree_lookup(&wt, fixture.repo, "testrepo-worktree")); + cl_git_fail(git_repository_open_from_worktree(&repo, wt)); + + git_buf_free(&buf); + git_worktree_free(wt); +} + +void test_worktree_worktree__init(void) +{ + git_worktree *wt; + git_repository *repo; + git_reference *branch; + git_buf path = GIT_BUF_INIT; + + cl_git_pass(git_buf_joinpath(&path, fixture.repo->workdir, "../worktree-new")); + cl_git_pass(git_worktree_add(&wt, fixture.repo, "worktree-new", path.ptr, NULL)); + + /* Open and verify created repo */ + cl_git_pass(git_repository_open(&repo, path.ptr)); + cl_assert(git__suffixcmp(git_repository_workdir(repo), "worktree-new/") == 0); + cl_git_pass(git_branch_lookup(&branch, repo, "worktree-new", GIT_BRANCH_LOCAL)); + + git_buf_free(&path); + git_worktree_free(wt); + git_reference_free(branch); + git_repository_free(repo); +} + +void test_worktree_worktree__add_locked(void) +{ + git_worktree *wt; + git_repository *repo; + git_reference *branch; + git_buf path = GIT_BUF_INIT; + git_worktree_add_options opts = GIT_WORKTREE_ADD_OPTIONS_INIT; + + opts.lock = 1; + + cl_git_pass(git_buf_joinpath(&path, fixture.repo->workdir, "../worktree-locked")); + cl_git_pass(git_worktree_add(&wt, fixture.repo, "worktree-locked", path.ptr, &opts)); + + /* Open and verify created repo */ + cl_assert(git_worktree_is_locked(NULL, wt)); + cl_git_pass(git_repository_open(&repo, path.ptr)); + cl_assert(git__suffixcmp(git_repository_workdir(repo), "worktree-locked/") == 0); + cl_git_pass(git_branch_lookup(&branch, repo, "worktree-locked", GIT_BRANCH_LOCAL)); + + git_buf_free(&path); + git_worktree_free(wt); + git_reference_free(branch); + git_repository_free(repo); +} + +void test_worktree_worktree__init_existing_branch(void) +{ + git_reference *head, *branch; + git_commit *commit; + git_worktree *wt; + git_buf path = GIT_BUF_INIT; + + cl_git_pass(git_repository_head(&head, fixture.repo)); + cl_git_pass(git_commit_lookup(&commit, fixture.repo, &head->target.oid)); + cl_git_pass(git_branch_create(&branch, fixture.repo, "worktree-new", commit, false)); + + cl_git_pass(git_buf_joinpath(&path, fixture.repo->workdir, "../worktree-new")); + cl_git_fail(git_worktree_add(&wt, fixture.repo, "worktree-new", path.ptr, NULL)); + + git_buf_free(&path); + git_commit_free(commit); + git_reference_free(head); + git_reference_free(branch); +} + +void test_worktree_worktree__init_existing_worktree(void) +{ + git_worktree *wt; + git_buf path = GIT_BUF_INIT; + + cl_git_pass(git_buf_joinpath(&path, fixture.repo->workdir, "../worktree-new")); + cl_git_fail(git_worktree_add(&wt, fixture.repo, "testrepo-worktree", path.ptr, NULL)); + + cl_git_pass(git_worktree_lookup(&wt, fixture.repo, "testrepo-worktree")); + cl_assert_equal_s(wt->gitlink_path, fixture.worktree->gitlink); + + git_buf_free(&path); + git_worktree_free(wt); +} + +void test_worktree_worktree__init_existing_path(void) +{ + const char *wtfiles[] = { "HEAD", "commondir", "gitdir", "index" }; + git_worktree *wt; + git_buf path = GIT_BUF_INIT; + unsigned i; + + /* Delete files to verify they have not been created by + * the init call */ + for (i = 0; i < ARRAY_SIZE(wtfiles); i++) { + cl_git_pass(git_buf_joinpath(&path, + fixture.worktree->gitdir, wtfiles[i])); + cl_git_pass(p_unlink(path.ptr)); + } + + cl_git_pass(git_buf_joinpath(&path, fixture.repo->workdir, "../testrepo-worktree")); + cl_git_fail(git_worktree_add(&wt, fixture.repo, "worktree-new", path.ptr, NULL)); + + /* Verify files have not been re-created */ + for (i = 0; i < ARRAY_SIZE(wtfiles); i++) { + cl_git_pass(git_buf_joinpath(&path, + fixture.worktree->gitdir, wtfiles[i])); + cl_assert(!git_path_exists(path.ptr)); + } + + git_buf_free(&path); +} + +void test_worktree_worktree__init_submodule(void) +{ + git_repository *repo, *sm, *wt; + git_worktree *worktree; + git_buf path = GIT_BUF_INIT; + + cleanup_fixture_worktree(&fixture); + repo = setup_fixture_submod2(); + + cl_git_pass(git_buf_joinpath(&path, repo->workdir, "sm_unchanged")); + cl_git_pass(git_repository_open(&sm, path.ptr)); + cl_git_pass(git_buf_joinpath(&path, repo->workdir, "../worktree/")); + cl_git_pass(git_worktree_add(&worktree, sm, "repo-worktree", path.ptr, NULL)); + cl_git_pass(git_repository_open_from_worktree(&wt, worktree)); + + cl_git_pass(git_path_prettify_dir(&path, path.ptr, NULL)); + cl_assert_equal_s(path.ptr, wt->workdir); + cl_git_pass(git_path_prettify_dir(&path, sm->commondir, NULL)); + cl_assert_equal_s(sm->commondir, wt->commondir); + + cl_git_pass(git_buf_joinpath(&path, sm->gitdir, "worktrees/repo-worktree/")); + cl_assert_equal_s(path.ptr, wt->gitdir); + + git_buf_free(&path); + git_worktree_free(worktree); + git_repository_free(sm); + git_repository_free(wt); +} + +void test_worktree_worktree__validate(void) +{ + git_worktree *wt; + + cl_git_pass(git_worktree_lookup(&wt, fixture.repo, "testrepo-worktree")); + cl_git_pass(git_worktree_validate(wt)); + + git_worktree_free(wt); +} + +void test_worktree_worktree__validate_invalid_commondir(void) +{ + git_worktree *wt; + + cl_git_pass(git_worktree_lookup(&wt, fixture.repo, "testrepo-worktree")); + git__free(wt->commondir_path); + wt->commondir_path = "/path/to/invalid/commondir"; + + cl_git_fail(git_worktree_validate(wt)); + + wt->commondir_path = NULL; + git_worktree_free(wt); +} + +void test_worktree_worktree__validate_invalid_gitdir(void) +{ + git_worktree *wt; + + cl_git_pass(git_worktree_lookup(&wt, fixture.repo, "testrepo-worktree")); + git__free(wt->gitdir_path); + wt->gitdir_path = "/path/to/invalid/gitdir"; + cl_git_fail(git_worktree_validate(wt)); + + wt->gitdir_path = NULL; + git_worktree_free(wt); +} + +void test_worktree_worktree__validate_invalid_parent(void) +{ + git_worktree *wt; + + cl_git_pass(git_worktree_lookup(&wt, fixture.repo, "testrepo-worktree")); + git__free(wt->parent_path); + wt->parent_path = "/path/to/invalid/parent"; + cl_git_fail(git_worktree_validate(wt)); + + wt->parent_path = NULL; + git_worktree_free(wt); +} + +void test_worktree_worktree__lock_with_reason(void) +{ + git_worktree *wt; + git_buf reason = GIT_BUF_INIT; + + cl_git_pass(git_worktree_lookup(&wt, fixture.repo, "testrepo-worktree")); + + cl_assert(!git_worktree_is_locked(NULL, wt)); + cl_git_pass(git_worktree_lock(wt, "because")); + cl_assert(git_worktree_is_locked(&reason, wt) > 0); + cl_assert_equal_s(reason.ptr, "because"); + cl_assert(wt->locked); + + git_buf_free(&reason); + git_worktree_free(wt); +} + +void test_worktree_worktree__lock_without_reason(void) +{ + git_worktree *wt; + git_buf reason = GIT_BUF_INIT; + + cl_git_pass(git_worktree_lookup(&wt, fixture.repo, "testrepo-worktree")); + + cl_assert(!git_worktree_is_locked(NULL, wt)); + cl_git_pass(git_worktree_lock(wt, NULL)); + cl_assert(git_worktree_is_locked(&reason, wt) > 0); + cl_assert_equal_i(reason.size, 0); + cl_assert(wt->locked); + + git_buf_free(&reason); + git_worktree_free(wt); +} + +void test_worktree_worktree__unlock_unlocked_worktree(void) +{ + git_worktree *wt; + + cl_git_pass(git_worktree_lookup(&wt, fixture.repo, "testrepo-worktree")); + cl_assert(!git_worktree_is_locked(NULL, wt)); + cl_assert(git_worktree_unlock(wt) == 0); + cl_assert(!wt->locked); + + git_worktree_free(wt); +} + +void test_worktree_worktree__unlock_locked_worktree(void) +{ + git_worktree *wt; + + cl_git_pass(git_worktree_lookup(&wt, fixture.repo, "testrepo-worktree")); + cl_git_pass(git_worktree_lock(wt, NULL)); + cl_assert(git_worktree_is_locked(NULL, wt)); + cl_git_pass(git_worktree_unlock(wt)); + cl_assert(!wt->locked); + + git_worktree_free(wt); +} + +void test_worktree_worktree__prune_without_opts_fails(void) +{ + git_worktree *wt; + git_repository *repo; + + cl_git_pass(git_worktree_lookup(&wt, fixture.repo, "testrepo-worktree")); + cl_git_fail(git_worktree_prune(wt, NULL)); + + /* Assert the repository is still valid */ + cl_git_pass(git_repository_open_from_worktree(&repo, wt)); + + git_worktree_free(wt); + git_repository_free(repo); +} + +void test_worktree_worktree__prune_valid(void) +{ + git_worktree_prune_options opts = GIT_WORKTREE_PRUNE_OPTIONS_INIT; + git_worktree *wt; + git_repository *repo; + + opts.flags = GIT_WORKTREE_PRUNE_VALID; + + cl_git_pass(git_worktree_lookup(&wt, fixture.repo, "testrepo-worktree")); + cl_git_pass(git_worktree_prune(wt, &opts)); + + /* Assert the repository is not valid anymore */ + cl_git_fail(git_repository_open_from_worktree(&repo, wt)); + + git_worktree_free(wt); + git_repository_free(repo); +} + +void test_worktree_worktree__prune_locked(void) +{ + git_worktree_prune_options opts = GIT_WORKTREE_PRUNE_OPTIONS_INIT; + git_worktree *wt; + git_repository *repo; + + cl_git_pass(git_worktree_lookup(&wt, fixture.repo, "testrepo-worktree")); + cl_git_pass(git_worktree_lock(wt, NULL)); + + opts.flags = GIT_WORKTREE_PRUNE_VALID; + cl_git_fail(git_worktree_prune(wt, &opts)); + /* Assert the repository is still valid */ + cl_git_pass(git_repository_open_from_worktree(&repo, wt)); + + opts.flags = GIT_WORKTREE_PRUNE_VALID|GIT_WORKTREE_PRUNE_LOCKED; + cl_git_pass(git_worktree_prune(wt, &opts)); + + git_worktree_free(wt); + git_repository_free(repo); +} + +void test_worktree_worktree__prune_gitdir_only(void) +{ + git_worktree_prune_options opts = GIT_WORKTREE_PRUNE_OPTIONS_INIT; + git_worktree *wt; + + opts.flags = GIT_WORKTREE_PRUNE_VALID; + cl_git_pass(git_worktree_lookup(&wt, fixture.repo, "testrepo-worktree")); + cl_git_pass(git_worktree_prune(wt, &opts)); + + cl_assert(!git_path_exists(wt->gitdir_path)); + cl_assert(git_path_exists(wt->gitlink_path)); + + git_worktree_free(wt); +} + +void test_worktree_worktree__prune_worktree(void) +{ + git_worktree_prune_options opts = GIT_WORKTREE_PRUNE_OPTIONS_INIT; + git_worktree *wt; + + opts.flags = GIT_WORKTREE_PRUNE_VALID|GIT_WORKTREE_PRUNE_WORKING_TREE; + + cl_git_pass(git_worktree_lookup(&wt, fixture.repo, "testrepo-worktree")); + cl_git_pass(git_worktree_prune(wt, &opts)); + + cl_assert(!git_path_exists(wt->gitdir_path)); + cl_assert(!git_path_exists(wt->gitlink_path)); + + git_worktree_free(wt); +} + +static int read_head_ref(git_repository *repo, const char *path, void *payload) +{ + git_vector *refs = (git_vector *) payload; + git_reference *head; + + GIT_UNUSED(repo); + + cl_git_pass(git_reference__read_head(&head, repo, path)); + + git_vector_insert(refs, head); + + return 0; +} + +void test_worktree_worktree__foreach_head_gives_same_results_in_wt_and_repo(void) +{ + git_vector repo_refs = GIT_VECTOR_INIT, worktree_refs = GIT_VECTOR_INIT; + git_reference *heads[2]; + size_t i; + + cl_git_pass(git_reference_lookup(&heads[0], fixture.repo, GIT_HEAD_FILE)); + cl_git_pass(git_reference_lookup(&heads[1], fixture.worktree, GIT_HEAD_FILE)); + + cl_git_pass(git_repository_foreach_head(fixture.repo, read_head_ref, &repo_refs)); + cl_git_pass(git_repository_foreach_head(fixture.worktree, read_head_ref, &worktree_refs)); + + cl_assert_equal_i(repo_refs.length, ARRAY_SIZE(heads)); + cl_assert_equal_i(worktree_refs.length, ARRAY_SIZE(heads)); + + for (i = 0; i < ARRAY_SIZE(heads); i++) { + cl_assert_equal_s(heads[i]->name, ((git_reference *) repo_refs.contents[i])->name); + cl_assert_equal_s(heads[i]->name, ((git_reference *) repo_refs.contents[i])->name); + cl_assert_equal_s(heads[i]->name, ((git_reference *) worktree_refs.contents[i])->name); + + git_reference_free(heads[i]); + git_reference_free(repo_refs.contents[i]); + git_reference_free(worktree_refs.contents[i]); + } + + git_vector_free(&repo_refs); + git_vector_free(&worktree_refs); +} diff --git a/tests/worktree/worktree_helpers.c b/tests/worktree/worktree_helpers.c new file mode 100644 index 000000000..6d4cdbaeb --- /dev/null +++ b/tests/worktree/worktree_helpers.c @@ -0,0 +1,30 @@ +#include "clar_libgit2.h" +#include "worktree_helpers.h" + +void cleanup_fixture_worktree(worktree_fixture *fixture) +{ + if (!fixture) + return; + + if (fixture->repo) { + git_repository_free(fixture->repo); + fixture->repo = NULL; + } + if (fixture->worktree) { + git_repository_free(fixture->worktree); + fixture->worktree = NULL; + } + + if (fixture->reponame) + cl_fixture_cleanup(fixture->reponame); + if (fixture->worktreename) + cl_fixture_cleanup(fixture->worktreename); +} + +void setup_fixture_worktree(worktree_fixture *fixture) +{ + if (fixture->reponame) + fixture->repo = cl_git_sandbox_init(fixture->reponame); + if (fixture->worktreename) + fixture->worktree = cl_git_sandbox_init(fixture->worktreename); +} diff --git a/tests/worktree/worktree_helpers.h b/tests/worktree/worktree_helpers.h new file mode 100644 index 000000000..35ea9ed4c --- /dev/null +++ b/tests/worktree/worktree_helpers.h @@ -0,0 +1,11 @@ +typedef struct { + const char *reponame; + const char *worktreename; + git_repository *repo; + git_repository *worktree; +} worktree_fixture; + +#define WORKTREE_FIXTURE_INIT(repo, worktree) { (repo), (worktree), NULL, NULL } + +void cleanup_fixture_worktree(worktree_fixture *fixture); +void setup_fixture_worktree(worktree_fixture *fixture);