diff options
51 files changed, 1666 insertions, 431 deletions
diff --git a/include/git2/common.h b/include/git2/common.h index f13dfd509..c909f86ca 100644 --- a/include/git2/common.h +++ b/include/git2/common.h @@ -179,6 +179,7 @@ typedef enum { GIT_OPT_SET_SSL_CIPHERS, GIT_OPT_GET_USER_AGENT, GIT_OPT_ENABLE_OFS_DELTA, + GIT_OPT_ENABLE_SYNCHRONOUS_OBJECT_CREATION, } git_libgit2_opt_t; /** @@ -316,6 +317,13 @@ typedef enum { * > Packfiles containing offset deltas can still be read. * > This defaults to enabled. * + * * opts(GIT_OPT_ENABLE_SYNCHRONOUS_OBJECT_CREATION, int enabled) + * + * > Enable synchronized writes of new objects using `fsync` + * > (or the platform equivalent) to ensure that new object data + * > is written to permanent storage, not simply cached. This + * > defaults to disabled. + * * @param option Option key * @param ... value to set the option * @return 0 on success, <0 on failure 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/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/worktree.h b/include/git2/worktree.h index cad1284fa..4c4f9284d 100644 --- a/include/git2/worktree.h +++ b/include/git2/worktree.h @@ -44,6 +44,18 @@ GIT_EXTERN(int) git_worktree_list(git_strarray *out, git_repository *repo); 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. diff --git a/src/blame_git.c b/src/blame_git.c index 96785c75b..735b62d95 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) @@ -543,7 +546,8 @@ static int pass_blame(git_blame *blame, git_blame__origin *origin, uint32_t opt) } if (porigin->blob && 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); + goto finish; origin_decref(porigin); goto finish; } 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 cd5727c05..50c5a3d82 100644 --- a/src/config_file.c +++ b/src/config_file.c @@ -1041,8 +1041,9 @@ static int parse_section_header_ext(struct reader *reader, const char *line, con 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_parse; rpos = 0; @@ -1082,6 +1083,11 @@ 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)) { + git_buf_free(&buf); + return -1; + } + if (line[rpos] != '"' || line[rpos + 1] != ']') { set_parse_error(reader, rpos, "Unexpected text after closing quotes"); git_buf_free(&buf); diff --git a/src/diff_parse.c b/src/diff_parse.c index 93915683e..24a8a4af6 100644 --- a/src/diff_parse.c +++ b/src/diff_parse.c @@ -44,7 +44,11 @@ static git_diff_parsed *diff_parsed_alloc(void) diff->base.patch_fn = git_patch_parsed_from_diff; diff->base.free_fn = diff_parsed_free; - git_diff_init_options(&diff->base.opts, GIT_DIFF_OPTIONS_VERSION); + 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); diff --git a/src/filebuf.c b/src/filebuf.c index 825b9c04c..80250ccdf 100644 --- a/src/filebuf.c +++ b/src/filebuf.c @@ -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; @@ -425,6 +428,11 @@ 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); goto on_error; @@ -437,6 +445,9 @@ int git_filebuf_commit(git_filebuf *file) 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); 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 cc638ea5b..ad2a988a9 100644 --- a/src/fileops.c +++ b/src/fileops.c @@ -236,10 +236,16 @@ 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; @@ -254,8 +260,19 @@ int git_futils_writebuffer( return error; } - if ((error = p_close(fd)) < 0) + 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; } @@ -1108,3 +1125,33 @@ 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 = git_path_dirname(path); + int 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/hash/hash_collisiondetect.h b/src/hash/hash_collisiondetect.h index 2bb27ba14..5fdae8df6 100644 --- a/src/hash/hash_collisiondetect.h +++ b/src/hash/hash_collisiondetect.h @@ -28,18 +28,8 @@ GIT_INLINE(int) git_hash_init(git_hash_ctx *ctx) GIT_INLINE(int) git_hash_update(git_hash_ctx *ctx, const void *data, size_t len) { - const char *p = data; - assert(ctx); - - /* We expect a size_t, but sha1dc only takes an int */ - while (len > INT_MAX) { - SHA1DCUpdate(&ctx->c, p, INT_MAX); - p += INT_MAX; - len -= INT_MAX; - } - - SHA1DCUpdate(&ctx->c, p, len); + SHA1DCUpdate(&ctx->c, data, len); return 0; } diff --git a/src/hash/sha1dc/sha1.c b/src/hash/sha1dc/sha1.c index c846a163e..8d12b832b 100644 --- a/src/hash/sha1dc/sha1.c +++ b/src/hash/sha1dc/sha1.c @@ -1,5 +1,5 @@ /*** -* Copyright 2017 Marc Stevens <marc@marc-stevens.nl>, Dan Shumow (danshu@microsoft.com) +* Copyright 2017 Marc Stevens <marc@marc-stevens.nl>, Dan Shumow (danshu@microsoft.com) * Distributed under the MIT Software License. * See accompanying file LICENSE.txt or copy at * https://opensource.org/licenses/MIT @@ -8,16 +8,48 @@ #include <string.h> #include <memory.h> #include <stdio.h> +#include <stdlib.h> #include "sha1.h" #include "ubc_check.h" + +/* + Because Little-Endian architectures are most common, + we only set 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. + */ +#if (defined(__BYTE_ORDER) && (__BYTE_ORDER == __BIG_ENDIAN)) || \ + (defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __BIG_ENDIAN__)) || \ + defined(__BIG_ENDIAN__) || defined(__ARMEB__) || defined(__THUMBEB__) || defined(__AARCH64EB__) || \ + defined(_MIPSEB) || defined(__MIPSEB) || defined(__MIPSEB__) + +#define BIGENDIAN (1) + +#endif /*ENDIANNESS SELECTION*/ + #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)) + +#if defined(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(BIGENDIAN)*/ + +#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))) | ((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) \ @@ -38,28 +70,36 @@ #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 SHA1_STORE_STATE(i) states[i][0] = a; states[i][1] = b; states[i][2] = c; states[i][3] = d; states[i][4] = e; +#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); } -void sha1_message_expansion(uint32_t W[80]) -{ - unsigned i; +#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); } - for (i = 16; i < 80; ++i) - W[i] = rotate_left(W[i - 3] ^ W[i - 8] ^ W[i - 14] ^ W[i - 16], 1); -} +#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 a, b, c, d, e, W[80]; + 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] = rotate_left(W[i - 3] ^ W[i - 8] ^ W[i - 14] ^ W[i - 16], 1); + W[i] = sha1_mix(W, i); - a = ihv[0], b = ihv[1], c = ihv[2], d = ihv[3], e = ihv[4]; + 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); @@ -147,10 +187,10 @@ void sha1_compression(uint32_t ihv[5], const uint32_t m[16]) ihv[0] += a; ihv[1] += b; ihv[2] += c; ihv[3] += d; ihv[4] += e; } +#endif /*BUILDNOCOLLDETECTSHA1COMPRESSION*/ - -void sha1_compression_W(uint32_t ihv[5], const uint32_t W[80]) +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]; @@ -188,7 +228,7 @@ void sha1_compression_W(uint32_t ihv[5], const uint32_t W[80]) 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(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); @@ -243,416 +283,417 @@ void sha1_compression_W(uint32_t ihv[5], const uint32_t W[80]) -void sha1_compression_states(uint32_t ihv[5], const uint32_t W[80], uint32_t states[80][5]) +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 - HASHCLASH_SHA1COMPRESS_ROUND1_STEP(a, b, c, d, e, W, 0); + SHA1COMPRESS_FULL_ROUND1_STEP_LOAD(a, b, c, d, e, m, W, 0, temp); #ifdef DOSTORESTATE01 SHA1_STORE_STATE(1) #endif - HASHCLASH_SHA1COMPRESS_ROUND1_STEP(e, a, b, c, d, W, 1); + SHA1COMPRESS_FULL_ROUND1_STEP_LOAD(e, a, b, c, d, m, W, 1, temp); #ifdef DOSTORESTATE02 SHA1_STORE_STATE(2) #endif - HASHCLASH_SHA1COMPRESS_ROUND1_STEP(d, e, a, b, c, W, 2); + SHA1COMPRESS_FULL_ROUND1_STEP_LOAD(d, e, a, b, c, m, W, 2, temp); #ifdef DOSTORESTATE03 SHA1_STORE_STATE(3) #endif - HASHCLASH_SHA1COMPRESS_ROUND1_STEP(c, d, e, a, b, W, 3); + SHA1COMPRESS_FULL_ROUND1_STEP_LOAD(c, d, e, a, b, m, W, 3, temp); #ifdef DOSTORESTATE04 SHA1_STORE_STATE(4) #endif - HASHCLASH_SHA1COMPRESS_ROUND1_STEP(b, c, d, e, a, W, 4); + SHA1COMPRESS_FULL_ROUND1_STEP_LOAD(b, c, d, e, a, m, W, 4, temp); #ifdef DOSTORESTATE05 SHA1_STORE_STATE(5) #endif - HASHCLASH_SHA1COMPRESS_ROUND1_STEP(a, b, c, d, e, W, 5); + SHA1COMPRESS_FULL_ROUND1_STEP_LOAD(a, b, c, d, e, m, W, 5, temp); #ifdef DOSTORESTATE06 SHA1_STORE_STATE(6) #endif - HASHCLASH_SHA1COMPRESS_ROUND1_STEP(e, a, b, c, d, W, 6); + SHA1COMPRESS_FULL_ROUND1_STEP_LOAD(e, a, b, c, d, m, W, 6, temp); #ifdef DOSTORESTATE07 SHA1_STORE_STATE(7) #endif - HASHCLASH_SHA1COMPRESS_ROUND1_STEP(d, e, a, b, c, W, 7); + SHA1COMPRESS_FULL_ROUND1_STEP_LOAD(d, e, a, b, c, m, W, 7, temp); #ifdef DOSTORESTATE08 SHA1_STORE_STATE(8) #endif - HASHCLASH_SHA1COMPRESS_ROUND1_STEP(c, d, e, a, b, W, 8); + SHA1COMPRESS_FULL_ROUND1_STEP_LOAD(c, d, e, a, b, m, W, 8, temp); #ifdef DOSTORESTATE09 SHA1_STORE_STATE(9) #endif - HASHCLASH_SHA1COMPRESS_ROUND1_STEP(b, c, d, e, a, W, 9); + SHA1COMPRESS_FULL_ROUND1_STEP_LOAD(b, c, d, e, a, m, W, 9, temp); #ifdef DOSTORESTATE10 SHA1_STORE_STATE(10) #endif - HASHCLASH_SHA1COMPRESS_ROUND1_STEP(a, b, c, d, e, W, 10); + SHA1COMPRESS_FULL_ROUND1_STEP_LOAD(a, b, c, d, e, m, W, 10, temp); #ifdef DOSTORESTATE11 SHA1_STORE_STATE(11) #endif - HASHCLASH_SHA1COMPRESS_ROUND1_STEP(e, a, b, c, d, W, 11); + SHA1COMPRESS_FULL_ROUND1_STEP_LOAD(e, a, b, c, d, m, W, 11, temp); #ifdef DOSTORESTATE12 SHA1_STORE_STATE(12) #endif - HASHCLASH_SHA1COMPRESS_ROUND1_STEP(d, e, a, b, c, W, 12); + SHA1COMPRESS_FULL_ROUND1_STEP_LOAD(d, e, a, b, c, m, W, 12, temp); #ifdef DOSTORESTATE13 SHA1_STORE_STATE(13) #endif - HASHCLASH_SHA1COMPRESS_ROUND1_STEP(c, d, e, a, b, W, 13); + SHA1COMPRESS_FULL_ROUND1_STEP_LOAD(c, d, e, a, b, m, W, 13, temp); #ifdef DOSTORESTATE14 SHA1_STORE_STATE(14) #endif - HASHCLASH_SHA1COMPRESS_ROUND1_STEP(b, c, d, e, a, W, 14); + SHA1COMPRESS_FULL_ROUND1_STEP_LOAD(b, c, d, e, a, m, W, 14, temp); #ifdef DOSTORESTATE15 SHA1_STORE_STATE(15) #endif - HASHCLASH_SHA1COMPRESS_ROUND1_STEP(a, b, c, d, e, W, 15); + SHA1COMPRESS_FULL_ROUND1_STEP_LOAD(a, b, c, d, e, m, W, 15, temp); #ifdef DOSTORESTATE16 SHA1_STORE_STATE(16) #endif - HASHCLASH_SHA1COMPRESS_ROUND1_STEP(e, a, b, c, d, W, 16); + SHA1COMPRESS_FULL_ROUND1_STEP_EXPAND(e, a, b, c, d, W, 16, temp); #ifdef DOSTORESTATE17 SHA1_STORE_STATE(17) #endif - HASHCLASH_SHA1COMPRESS_ROUND1_STEP(d, e, a, b, c, W, 17); + SHA1COMPRESS_FULL_ROUND1_STEP_EXPAND(d, e, a, b, c, W, 17, temp); #ifdef DOSTORESTATE18 SHA1_STORE_STATE(18) #endif - HASHCLASH_SHA1COMPRESS_ROUND1_STEP(c, d, e, a, b, W, 18); + SHA1COMPRESS_FULL_ROUND1_STEP_EXPAND(c, d, e, a, b, W, 18, temp); #ifdef DOSTORESTATE19 SHA1_STORE_STATE(19) #endif - HASHCLASH_SHA1COMPRESS_ROUND1_STEP(b, c, d, e, a, W, 19); + SHA1COMPRESS_FULL_ROUND1_STEP_EXPAND(b, c, d, e, a, W, 19, temp); #ifdef DOSTORESTATE20 SHA1_STORE_STATE(20) #endif - HASHCLASH_SHA1COMPRESS_ROUND2_STEP(a, b, c, d, e, W, 20); + SHA1COMPRESS_FULL_ROUND2_STEP(a, b, c, d, e, W, 20, temp); #ifdef DOSTORESTATE21 SHA1_STORE_STATE(21) #endif - HASHCLASH_SHA1COMPRESS_ROUND2_STEP(e, a, b, c, d, W, 21); - + SHA1COMPRESS_FULL_ROUND2_STEP(e, a, b, c, d, W, 21, temp); + #ifdef DOSTORESTATE22 SHA1_STORE_STATE(22) #endif - HASHCLASH_SHA1COMPRESS_ROUND2_STEP(d, e, a, b, c, W, 22); - + SHA1COMPRESS_FULL_ROUND2_STEP(d, e, a, b, c, W, 22, temp); + #ifdef DOSTORESTATE23 SHA1_STORE_STATE(23) #endif - HASHCLASH_SHA1COMPRESS_ROUND2_STEP(c, d, e, a, b, W, 23); + SHA1COMPRESS_FULL_ROUND2_STEP(c, d, e, a, b, W, 23, temp); #ifdef DOSTORESTATE24 SHA1_STORE_STATE(24) #endif - HASHCLASH_SHA1COMPRESS_ROUND2_STEP(b, c, d, e, a, W, 24); + SHA1COMPRESS_FULL_ROUND2_STEP(b, c, d, e, a, W, 24, temp); #ifdef DOSTORESTATE25 SHA1_STORE_STATE(25) #endif - HASHCLASH_SHA1COMPRESS_ROUND2_STEP(a, b, c, d, e, W, 25); + SHA1COMPRESS_FULL_ROUND2_STEP(a, b, c, d, e, W, 25, temp); #ifdef DOSTORESTATE26 SHA1_STORE_STATE(26) #endif - HASHCLASH_SHA1COMPRESS_ROUND2_STEP(e, a, b, c, d, W, 26); + SHA1COMPRESS_FULL_ROUND2_STEP(e, a, b, c, d, W, 26, temp); #ifdef DOSTORESTATE27 SHA1_STORE_STATE(27) #endif - HASHCLASH_SHA1COMPRESS_ROUND2_STEP(d, e, a, b, c, W, 27); - + SHA1COMPRESS_FULL_ROUND2_STEP(d, e, a, b, c, W, 27, temp); + #ifdef DOSTORESTATE28 SHA1_STORE_STATE(28) #endif - HASHCLASH_SHA1COMPRESS_ROUND2_STEP(c, d, e, a, b, W, 28); - + SHA1COMPRESS_FULL_ROUND2_STEP(c, d, e, a, b, W, 28, temp); + #ifdef DOSTORESTATE29 SHA1_STORE_STATE(29) #endif - HASHCLASH_SHA1COMPRESS_ROUND2_STEP(b, c, d, e, a, W, 29); - + SHA1COMPRESS_FULL_ROUND2_STEP(b, c, d, e, a, W, 29, temp); + #ifdef DOSTORESTATE30 SHA1_STORE_STATE(30) #endif - HASHCLASH_SHA1COMPRESS_ROUND2_STEP(a, b, c, d, e, W, 30); - + SHA1COMPRESS_FULL_ROUND2_STEP(a, b, c, d, e, W, 30, temp); + #ifdef DOSTORESTATE31 SHA1_STORE_STATE(31) #endif - HASHCLASH_SHA1COMPRESS_ROUND2_STEP(e, a, b, c, d, W, 31); - + SHA1COMPRESS_FULL_ROUND2_STEP(e, a, b, c, d, W, 31, temp); + #ifdef DOSTORESTATE32 SHA1_STORE_STATE(32) #endif - HASHCLASH_SHA1COMPRESS_ROUND2_STEP(d, e, a, b, c, W, 32); + SHA1COMPRESS_FULL_ROUND2_STEP(d, e, a, b, c, W, 32, temp); #ifdef DOSTORESTATE33 SHA1_STORE_STATE(33) #endif - HASHCLASH_SHA1COMPRESS_ROUND2_STEP(c, d, e, a, b, W, 33); + SHA1COMPRESS_FULL_ROUND2_STEP(c, d, e, a, b, W, 33, temp); #ifdef DOSTORESTATE34 SHA1_STORE_STATE(34) #endif - HASHCLASH_SHA1COMPRESS_ROUND2_STEP(b, c, d, e, a, W, 34); + SHA1COMPRESS_FULL_ROUND2_STEP(b, c, d, e, a, W, 34, temp); #ifdef DOSTORESTATE35 SHA1_STORE_STATE(35) #endif - HASHCLASH_SHA1COMPRESS_ROUND2_STEP(a, b, c, d, e, W, 35); - + SHA1COMPRESS_FULL_ROUND2_STEP(a, b, c, d, e, W, 35, temp); + #ifdef DOSTORESTATE36 SHA1_STORE_STATE(36) #endif - HASHCLASH_SHA1COMPRESS_ROUND2_STEP(e, a, b, c, d, W, 36); - + SHA1COMPRESS_FULL_ROUND2_STEP(e, a, b, c, d, W, 36, temp); + #ifdef DOSTORESTATE37 SHA1_STORE_STATE(37) #endif - HASHCLASH_SHA1COMPRESS_ROUND2_STEP(d, e, a, b, c, W, 37); - + SHA1COMPRESS_FULL_ROUND2_STEP(d, e, a, b, c, W, 37, temp); + #ifdef DOSTORESTATE38 SHA1_STORE_STATE(38) #endif - HASHCLASH_SHA1COMPRESS_ROUND2_STEP(c, d, e, a, b, W, 38); - + SHA1COMPRESS_FULL_ROUND2_STEP(c, d, e, a, b, W, 38, temp); + #ifdef DOSTORESTATE39 SHA1_STORE_STATE(39) #endif - HASHCLASH_SHA1COMPRESS_ROUND2_STEP(b, c, d, e, a, W, 39); + SHA1COMPRESS_FULL_ROUND2_STEP(b, c, d, e, a, W, 39, temp); #ifdef DOSTORESTATE40 SHA1_STORE_STATE(40) #endif - HASHCLASH_SHA1COMPRESS_ROUND3_STEP(a, b, c, d, e, W, 40); + SHA1COMPRESS_FULL_ROUND3_STEP(a, b, c, d, e, W, 40, temp); #ifdef DOSTORESTATE41 SHA1_STORE_STATE(41) #endif - HASHCLASH_SHA1COMPRESS_ROUND3_STEP(e, a, b, c, d, W, 41); + SHA1COMPRESS_FULL_ROUND3_STEP(e, a, b, c, d, W, 41, temp); #ifdef DOSTORESTATE42 SHA1_STORE_STATE(42) #endif - HASHCLASH_SHA1COMPRESS_ROUND3_STEP(d, e, a, b, c, W, 42); + SHA1COMPRESS_FULL_ROUND3_STEP(d, e, a, b, c, W, 42, temp); #ifdef DOSTORESTATE43 SHA1_STORE_STATE(43) #endif - HASHCLASH_SHA1COMPRESS_ROUND3_STEP(c, d, e, a, b, W, 43); + SHA1COMPRESS_FULL_ROUND3_STEP(c, d, e, a, b, W, 43, temp); #ifdef DOSTORESTATE44 SHA1_STORE_STATE(44) #endif - HASHCLASH_SHA1COMPRESS_ROUND3_STEP(b, c, d, e, a, W, 44); + SHA1COMPRESS_FULL_ROUND3_STEP(b, c, d, e, a, W, 44, temp); #ifdef DOSTORESTATE45 SHA1_STORE_STATE(45) #endif - HASHCLASH_SHA1COMPRESS_ROUND3_STEP(a, b, c, d, e, W, 45); + SHA1COMPRESS_FULL_ROUND3_STEP(a, b, c, d, e, W, 45, temp); #ifdef DOSTORESTATE46 SHA1_STORE_STATE(46) #endif - HASHCLASH_SHA1COMPRESS_ROUND3_STEP(e, a, b, c, d, W, 46); + SHA1COMPRESS_FULL_ROUND3_STEP(e, a, b, c, d, W, 46, temp); #ifdef DOSTORESTATE47 SHA1_STORE_STATE(47) #endif - HASHCLASH_SHA1COMPRESS_ROUND3_STEP(d, e, a, b, c, W, 47); + SHA1COMPRESS_FULL_ROUND3_STEP(d, e, a, b, c, W, 47, temp); #ifdef DOSTORESTATE48 SHA1_STORE_STATE(48) #endif - HASHCLASH_SHA1COMPRESS_ROUND3_STEP(c, d, e, a, b, W, 48); + SHA1COMPRESS_FULL_ROUND3_STEP(c, d, e, a, b, W, 48, temp); #ifdef DOSTORESTATE49 SHA1_STORE_STATE(49) #endif - HASHCLASH_SHA1COMPRESS_ROUND3_STEP(b, c, d, e, a, W, 49); + SHA1COMPRESS_FULL_ROUND3_STEP(b, c, d, e, a, W, 49, temp); #ifdef DOSTORESTATE50 SHA1_STORE_STATE(50) #endif - HASHCLASH_SHA1COMPRESS_ROUND3_STEP(a, b, c, d, e, W, 50); + SHA1COMPRESS_FULL_ROUND3_STEP(a, b, c, d, e, W, 50, temp); #ifdef DOSTORESTATE51 SHA1_STORE_STATE(51) #endif - HASHCLASH_SHA1COMPRESS_ROUND3_STEP(e, a, b, c, d, W, 51); + SHA1COMPRESS_FULL_ROUND3_STEP(e, a, b, c, d, W, 51, temp); #ifdef DOSTORESTATE52 SHA1_STORE_STATE(52) #endif - HASHCLASH_SHA1COMPRESS_ROUND3_STEP(d, e, a, b, c, W, 52); + SHA1COMPRESS_FULL_ROUND3_STEP(d, e, a, b, c, W, 52, temp); #ifdef DOSTORESTATE53 SHA1_STORE_STATE(53) #endif - HASHCLASH_SHA1COMPRESS_ROUND3_STEP(c, d, e, a, b, W, 53); + SHA1COMPRESS_FULL_ROUND3_STEP(c, d, e, a, b, W, 53, temp); #ifdef DOSTORESTATE54 SHA1_STORE_STATE(54) #endif - HASHCLASH_SHA1COMPRESS_ROUND3_STEP(b, c, d, e, a, W, 54); + SHA1COMPRESS_FULL_ROUND3_STEP(b, c, d, e, a, W, 54, temp); #ifdef DOSTORESTATE55 SHA1_STORE_STATE(55) #endif - HASHCLASH_SHA1COMPRESS_ROUND3_STEP(a, b, c, d, e, W, 55); + SHA1COMPRESS_FULL_ROUND3_STEP(a, b, c, d, e, W, 55, temp); #ifdef DOSTORESTATE56 SHA1_STORE_STATE(56) #endif - HASHCLASH_SHA1COMPRESS_ROUND3_STEP(e, a, b, c, d, W, 56); + SHA1COMPRESS_FULL_ROUND3_STEP(e, a, b, c, d, W, 56, temp); #ifdef DOSTORESTATE57 SHA1_STORE_STATE(57) #endif - HASHCLASH_SHA1COMPRESS_ROUND3_STEP(d, e, a, b, c, W, 57); + SHA1COMPRESS_FULL_ROUND3_STEP(d, e, a, b, c, W, 57, temp); #ifdef DOSTORESTATE58 SHA1_STORE_STATE(58) #endif - HASHCLASH_SHA1COMPRESS_ROUND3_STEP(c, d, e, a, b, W, 58); + SHA1COMPRESS_FULL_ROUND3_STEP(c, d, e, a, b, W, 58, temp); #ifdef DOSTORESTATE59 SHA1_STORE_STATE(59) #endif - HASHCLASH_SHA1COMPRESS_ROUND3_STEP(b, c, d, e, a, W, 59); - + SHA1COMPRESS_FULL_ROUND3_STEP(b, c, d, e, a, W, 59, temp); + #ifdef DOSTORESTATE60 SHA1_STORE_STATE(60) #endif - HASHCLASH_SHA1COMPRESS_ROUND4_STEP(a, b, c, d, e, W, 60); + SHA1COMPRESS_FULL_ROUND4_STEP(a, b, c, d, e, W, 60, temp); #ifdef DOSTORESTATE61 SHA1_STORE_STATE(61) #endif - HASHCLASH_SHA1COMPRESS_ROUND4_STEP(e, a, b, c, d, W, 61); + SHA1COMPRESS_FULL_ROUND4_STEP(e, a, b, c, d, W, 61, temp); #ifdef DOSTORESTATE62 SHA1_STORE_STATE(62) #endif - HASHCLASH_SHA1COMPRESS_ROUND4_STEP(d, e, a, b, c, W, 62); + SHA1COMPRESS_FULL_ROUND4_STEP(d, e, a, b, c, W, 62, temp); #ifdef DOSTORESTATE63 SHA1_STORE_STATE(63) #endif - HASHCLASH_SHA1COMPRESS_ROUND4_STEP(c, d, e, a, b, W, 63); + SHA1COMPRESS_FULL_ROUND4_STEP(c, d, e, a, b, W, 63, temp); #ifdef DOSTORESTATE64 SHA1_STORE_STATE(64) #endif - HASHCLASH_SHA1COMPRESS_ROUND4_STEP(b, c, d, e, a, W, 64); + SHA1COMPRESS_FULL_ROUND4_STEP(b, c, d, e, a, W, 64, temp); #ifdef DOSTORESTATE65 SHA1_STORE_STATE(65) #endif - HASHCLASH_SHA1COMPRESS_ROUND4_STEP(a, b, c, d, e, W, 65); + SHA1COMPRESS_FULL_ROUND4_STEP(a, b, c, d, e, W, 65, temp); #ifdef DOSTORESTATE66 SHA1_STORE_STATE(66) #endif - HASHCLASH_SHA1COMPRESS_ROUND4_STEP(e, a, b, c, d, W, 66); + SHA1COMPRESS_FULL_ROUND4_STEP(e, a, b, c, d, W, 66, temp); #ifdef DOSTORESTATE67 SHA1_STORE_STATE(67) #endif - HASHCLASH_SHA1COMPRESS_ROUND4_STEP(d, e, a, b, c, W, 67); + SHA1COMPRESS_FULL_ROUND4_STEP(d, e, a, b, c, W, 67, temp); #ifdef DOSTORESTATE68 SHA1_STORE_STATE(68) #endif - HASHCLASH_SHA1COMPRESS_ROUND4_STEP(c, d, e, a, b, W, 68); + SHA1COMPRESS_FULL_ROUND4_STEP(c, d, e, a, b, W, 68, temp); #ifdef DOSTORESTATE69 SHA1_STORE_STATE(69) #endif - HASHCLASH_SHA1COMPRESS_ROUND4_STEP(b, c, d, e, a, W, 69); + SHA1COMPRESS_FULL_ROUND4_STEP(b, c, d, e, a, W, 69, temp); #ifdef DOSTORESTATE70 SHA1_STORE_STATE(70) #endif - HASHCLASH_SHA1COMPRESS_ROUND4_STEP(a, b, c, d, e, W, 70); + SHA1COMPRESS_FULL_ROUND4_STEP(a, b, c, d, e, W, 70, temp); #ifdef DOSTORESTATE71 SHA1_STORE_STATE(71) #endif - HASHCLASH_SHA1COMPRESS_ROUND4_STEP(e, a, b, c, d, W, 71); + SHA1COMPRESS_FULL_ROUND4_STEP(e, a, b, c, d, W, 71, temp); #ifdef DOSTORESTATE72 SHA1_STORE_STATE(72) #endif - HASHCLASH_SHA1COMPRESS_ROUND4_STEP(d, e, a, b, c, W, 72); + SHA1COMPRESS_FULL_ROUND4_STEP(d, e, a, b, c, W, 72, temp); #ifdef DOSTORESTATE73 SHA1_STORE_STATE(73) #endif - HASHCLASH_SHA1COMPRESS_ROUND4_STEP(c, d, e, a, b, W, 73); + SHA1COMPRESS_FULL_ROUND4_STEP(c, d, e, a, b, W, 73, temp); #ifdef DOSTORESTATE74 SHA1_STORE_STATE(74) #endif - HASHCLASH_SHA1COMPRESS_ROUND4_STEP(b, c, d, e, a, W, 74); + SHA1COMPRESS_FULL_ROUND4_STEP(b, c, d, e, a, W, 74, temp); #ifdef DOSTORESTATE75 SHA1_STORE_STATE(75) #endif - HASHCLASH_SHA1COMPRESS_ROUND4_STEP(a, b, c, d, e, W, 75); + SHA1COMPRESS_FULL_ROUND4_STEP(a, b, c, d, e, W, 75, temp); #ifdef DOSTORESTATE76 SHA1_STORE_STATE(76) #endif - HASHCLASH_SHA1COMPRESS_ROUND4_STEP(e, a, b, c, d, W, 76); + SHA1COMPRESS_FULL_ROUND4_STEP(e, a, b, c, d, W, 76, temp); #ifdef DOSTORESTATE77 SHA1_STORE_STATE(77) #endif - HASHCLASH_SHA1COMPRESS_ROUND4_STEP(d, e, a, b, c, W, 77); + SHA1COMPRESS_FULL_ROUND4_STEP(d, e, a, b, c, W, 77, temp); #ifdef DOSTORESTATE78 SHA1_STORE_STATE(78) #endif - HASHCLASH_SHA1COMPRESS_ROUND4_STEP(c, d, e, a, b, W, 78); + SHA1COMPRESS_FULL_ROUND4_STEP(c, d, e, a, b, W, 78, temp); #ifdef DOSTORESTATE79 SHA1_STORE_STATE(79) #endif - HASHCLASH_SHA1COMPRESS_ROUND4_STEP(b, c, d, e, a, W, 79); + SHA1COMPRESS_FULL_ROUND4_STEP(b, c, d, e, a, W, 79, temp); @@ -663,7 +704,7 @@ void sha1_compression_states(uint32_t ihv[5], const uint32_t W[80], uint32_t sta #define SHA1_RECOMPRESS(t) \ -void sha1recompress_fast_ ## t (uint32_t ihvin[5], uint32_t ihvout[5], const uint32_t me2[80], const uint32_t state[5]) \ +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); \ @@ -829,180 +870,794 @@ void sha1recompress_fast_ ## t (uint32_t ihvin[5], uint32_t ihvout[5], const uin 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 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 -sha1_recompression_type sha1_recompression_step[80] = +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]) { - sha1recompress_fast_0, sha1recompress_fast_1, sha1recompress_fast_2, sha1recompress_fast_3, sha1recompress_fast_4, sha1recompress_fast_5, sha1recompress_fast_6, sha1recompress_fast_7, sha1recompress_fast_8, sha1recompress_fast_9, - sha1recompress_fast_10, sha1recompress_fast_11, sha1recompress_fast_12, sha1recompress_fast_13, sha1recompress_fast_14, sha1recompress_fast_15, sha1recompress_fast_16, sha1recompress_fast_17, sha1recompress_fast_18, sha1recompress_fast_19, - sha1recompress_fast_20, sha1recompress_fast_21, sha1recompress_fast_22, sha1recompress_fast_23, sha1recompress_fast_24, sha1recompress_fast_25, sha1recompress_fast_26, sha1recompress_fast_27, sha1recompress_fast_28, sha1recompress_fast_29, - sha1recompress_fast_30, sha1recompress_fast_31, sha1recompress_fast_32, sha1recompress_fast_33, sha1recompress_fast_34, sha1recompress_fast_35, sha1recompress_fast_36, sha1recompress_fast_37, sha1recompress_fast_38, sha1recompress_fast_39, - sha1recompress_fast_40, sha1recompress_fast_41, sha1recompress_fast_42, sha1recompress_fast_43, sha1recompress_fast_44, sha1recompress_fast_45, sha1recompress_fast_46, sha1recompress_fast_47, sha1recompress_fast_48, sha1recompress_fast_49, - sha1recompress_fast_50, sha1recompress_fast_51, sha1recompress_fast_52, sha1recompress_fast_53, sha1recompress_fast_54, sha1recompress_fast_55, sha1recompress_fast_56, sha1recompress_fast_57, sha1recompress_fast_58, sha1recompress_fast_59, - sha1recompress_fast_60, sha1recompress_fast_61, sha1recompress_fast_62, sha1recompress_fast_63, sha1recompress_fast_64, sha1recompress_fast_65, sha1recompress_fast_66, sha1recompress_fast_67, sha1recompress_fast_68, sha1recompress_fast_69, - sha1recompress_fast_70, sha1recompress_fast_71, sha1recompress_fast_72, sha1recompress_fast_73, sha1recompress_fast_74, sha1recompress_fast_75, sha1recompress_fast_76, sha1recompress_fast_77, sha1recompress_fast_78, sha1recompress_fast_79, -}; - + 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(); + } +} -void sha1_process(SHA1_CTX* ctx, const uint32_t block[16]) +static void sha1_process(SHA1_CTX* ctx, const uint32_t block[16]) { unsigned i, j; - uint32_t ubc_dv_mask[DVMASKSIZE]; + uint32_t ubc_dv_mask[DVMASKSIZE] = { 0xFFFFFFFF }; uint32_t ihvtmp[5]; - for (i=0; i < DVMASKSIZE; ++i) - ubc_dv_mask[i]=0; + 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]; - memcpy(ctx->m1, block, 64); - sha1_message_expansion(ctx->m1); - if (ctx->detect_coll && ctx->ubc_check) - { - ubc_check(ctx->m1, ubc_dv_mask); - } - sha1_compression_states(ctx->ihv, ctx->m1, ctx->states); + + sha1_compression_states(ctx->ihv, block, ctx->m1, ctx->states); + if (ctx->detect_coll) { - for (i = 0; sha1_dvs[i].dvType != 0; ++i) + if (ctx->ubc_check) + { + ubc_check(ctx->m1, ubc_dv_mask); + } + + if (ubc_dv_mask[0] != 0) { - if ((0 == ctx->ubc_check) || (((uint32_t)(1) << sha1_dvs[i].maskb) & ubc_dv_mask[sha1_dvs[i].maski])) + for (i = 0; sha1_dvs[i].dvType != 0; ++i) { - 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 ((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 && 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])) + if (ubc_dv_mask[0] & ((uint32_t)(1) << sha1_dvs[i].maskb)) { - ctx->found_collision = 1; - // TODO: call callback - if (ctx->callback != NULL) - ctx->callback(ctx->total - 64, ctx->ihv1, ctx->ihv2, ctx->m1, ctx->m2); + for (j = 0; j < 80; ++j) + ctx->m2[j] = ctx->m1[j] ^ sha1_dvs[i].dm[j]; - if (ctx->safe_hash) + 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])))) { - sha1_compression_W(ctx->ihv, ctx->m1); - sha1_compression_W(ctx->ihv, ctx->m1); - } + ctx->found_collision = 1; - break; + if (ctx->safe_hash) + { + sha1_compression_W(ctx->ihv, ctx->m1); + sha1_compression_W(ctx->ihv, ctx->m1); + } + + break; + } } } } } } - - - - -void swap_bytes(uint32_t val[16]) -{ - unsigned i; - for (i = 0; i < 16; ++i) - { - val[i] = ((val[i] << 8) & 0xFF00FF00) | ((val[i] >> 8) & 0xFF00FF); - val[i] = (val[i] << 16) | (val[i] >> 16); - } -} - -void SHA1DCInit(SHA1_CTX* ctx) +void SHA1DCInit(SHA1_CTX* ctx) { - static const union { unsigned char bytes[4]; uint32_t value; } endianness = { { 0, 1, 2, 3 } }; - static const uint32_t littleendian = 0x03020100; ctx->total = 0; ctx->ihv[0] = 0x67452301; ctx->ihv[1] = 0xEFCDAB89; @@ -1014,7 +1669,6 @@ void SHA1DCInit(SHA1_CTX* ctx) ctx->ubc_check = 1; ctx->detect_coll = 1; ctx->reduced_round_coll = 0; - ctx->bigendian = (endianness.value != littleendian); ctx->callback = NULL; } @@ -1056,41 +1710,32 @@ void SHA1DCSetCallback(SHA1_CTX* ctx, collision_block_callback callback) ctx->callback = callback; } -void SHA1DCUpdate(SHA1_CTX* ctx, const char* buf, unsigned len) +void SHA1DCUpdate(SHA1_CTX* ctx, const char* buf, size_t len) { unsigned left, fill; - if (len == 0) + if (len == 0) return; left = ctx->total & 63; fill = 64 - left; - if (left && len >= fill) + if (left && len >= fill) { ctx->total += fill; memcpy(ctx->buffer + left, buf, fill); - if (!ctx->bigendian) - swap_bytes((uint32_t*)(ctx->buffer)); sha1_process(ctx, (uint32_t*)(ctx->buffer)); buf += fill; len -= fill; left = 0; } - while (len >= 64) + while (len >= 64) { ctx->total += 64; - if (!ctx->bigendian) - { - memcpy(ctx->buffer, buf, 64); - swap_bytes((uint32_t*)(ctx->buffer)); - sha1_process(ctx, (uint32_t*)(ctx->buffer)); - } - else - sha1_process(ctx, (uint32_t*)(buf)); + sha1_process(ctx, (uint32_t*)(buf)); buf += 64; len -= 64; } - if (len > 0) + if (len > 0) { ctx->total += len; memcpy(ctx->buffer + left, buf, len); @@ -1111,7 +1756,7 @@ int SHA1DCFinal(unsigned char output[20], SHA1_CTX *ctx) 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); @@ -1122,8 +1767,6 @@ int SHA1DCFinal(unsigned char output[20], SHA1_CTX *ctx) ctx->buffer[61] = (unsigned char)(total >> 16); ctx->buffer[62] = (unsigned char)(total >> 8); ctx->buffer[63] = (unsigned char)(total); - if (!ctx->bigendian) - swap_bytes((uint32_t*)(ctx->buffer)); sha1_process(ctx, (uint32_t*)(ctx->buffer)); output[0] = (unsigned char)(ctx->ihv[0] >> 24); output[1] = (unsigned char)(ctx->ihv[0] >> 16); diff --git a/src/hash/sha1dc/sha1.h b/src/hash/sha1dc/sha1.h index 8b522f9d2..e867724c0 100644 --- a/src/hash/sha1dc/sha1.h +++ b/src/hash/sha1dc/sha1.h @@ -5,19 +5,24 @@ * https://opensource.org/licenses/MIT ***/ +#if defined(__cplusplus) +extern "C" { +#endif + #include <stdint.h> -// uses SHA-1 message expansion to expand the first 16 words of W[] to 80 words -void sha1_message_expansion(uint32_t W[80]); +/* uses SHA-1 message expansion to expand the first 16 words of W[] to 80 words */ +/* void sha1_message_expansion(uint32_t W[80]); */ -// sha-1 compression function; first version takes a message block pre-parsed as 16 32-bit integers, second version takes an already expanded message) -void sha1_compression(uint32_t ihv[5], const uint32_t m[16]); -void sha1_compression_W(uint32_t ihv[5], const uint32_t W[80]); +/* sha-1 compression function; first version takes a message block pre-parsed as 16 32-bit integers, second version takes an already expanded message) */ +/* void sha1_compression(uint32_t ihv[5], const uint32_t m[16]); +void sha1_compression_W(uint32_t ihv[5], const uint32_t W[80]); */ -// same as sha1_compression_W, but 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 ihv[5], const uint32_t W[80], uint32_t states[80][5]); +/* same as sha1_compression_W, but 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) @@ -25,21 +30,21 @@ void sha1_compression_states(uint32_t ihv[5], const uint32_t W[80], uint32_t sta // 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*); -// table of sha1_recompression_step_0, ... , sha1_recompression_step_79 -extern sha1_recompression_type sha1_recompression_step[80]; +/* table of sha1_recompression_step_0, ... , sha1_recompression_step_79 */ +/* extern sha1_recompression_type sha1_recompression_step[80];*/ -// 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]) +/* 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 +/* the SHA-1 context */ typedef struct { uint64_t total; uint32_t ihv[5]; unsigned char buffer[64]; - int bigendian; int found_collision; int safe_hash; int detect_coll; @@ -54,41 +59,47 @@ typedef struct { uint32_t states[80][5]; } SHA1_CTX; -// initialize SHA-1 context -void SHA1DCInit(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, +// 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 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 +// 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 +/* 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* ctx, int detect_coll); +/* 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 +/* 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 +/* 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*, unsigned); +/* 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 +/* 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 diff --git a/src/hash/sha1dc/ubc_check.c b/src/hash/sha1dc/ubc_check.c index 556aaf3c5..27d0976da 100644 --- a/src/hash/sha1dc/ubc_check.c +++ b/src/hash/sha1dc/ubc_check.c @@ -5,6 +5,7 @@ * 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' // @@ -17,10 +18,11 @@ // 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 +*/ #include <stdint.h> #include "ubc_check.h" @@ -58,7 +60,7 @@ 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[] = +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 } } diff --git a/src/hash/sha1dc/ubc_check.h b/src/hash/sha1dc/ubc_check.h index 27285bdf5..b349bed92 100644 --- a/src/hash/sha1dc/ubc_check.h +++ b/src/hash/sha1dc/ubc_check.h @@ -5,6 +5,7 @@ * 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' // @@ -17,10 +18,15 @@ // 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 UBC_CHECK_H #define UBC_CHECK_H +#if defined(__cplusplus) +extern "C" { +#endif + #include <stdint.h> #define DVMASKSIZE 1 @@ -31,5 +37,10 @@ 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 -#endif // UBC_CHECK_H +#endif /* UBC_CHECK_H */ diff --git a/src/indexer.c b/src/indexer.c index 869e2299f..ce67240ce 100644 --- a/src/indexer.c +++ b/src/indexer.c @@ -17,6 +17,7 @@ #include "oid.h" #include "oidmap.h" #include "zstream.h" +#include "object.h" extern git_mutex git__mwindow_mutex; @@ -33,7 +34,8 @@ struct git_indexer { unsigned int parsed_header :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; @@ -123,6 +125,9 @@ int git_indexer_new( git_hash_ctx_init(&idx->hash_ctx); git_hash_ctx_init(&idx->trailer); + if (git_object__synchronous_writing) + idx->do_fsync = 1; + error = git_buf_joinpath(&path, prefix, suff); if (error < 0) goto cleanup; @@ -161,6 +166,11 @@ cleanup: 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) { @@ -989,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 */ @@ -1066,6 +1078,11 @@ int git_indexer_commit(git_indexer *idx, git_transfer_progress *stats) 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"); @@ -1078,7 +1095,14 @@ 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); 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/merge.c b/src/merge.c index 857d51311..6e00b5adb 100644 --- a/src/merge.c +++ b/src/merge.c @@ -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( diff --git a/src/object.c b/src/object.c index 2da36a2ee..bd87c9310 100644 --- a/src/object.c +++ b/src/object.c @@ -16,6 +16,7 @@ #include "tag.h" bool git_object__strict_input_validation = true; +bool git_object__synchronous_writing = false; typedef struct { const char *str; /* type name string */ diff --git a/src/object.h b/src/object.h index dd227d16d..13117e4c3 100644 --- a/src/object.h +++ b/src/object.h @@ -10,6 +10,7 @@ #include "repository.h" extern bool git_object__strict_input_validation; +extern bool git_object__synchronous_writing; /** Base git object for inheritance */ struct git_object { @@ -496,7 +496,7 @@ int git_odb_get_backend(git_odb_backend **out, git_odb *odb, size_t 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) { @@ -531,7 +531,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 +586,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 +598,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 +612,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 +621,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; @@ -38,8 +38,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 diff --git a/src/odb_loose.c b/src/odb_loose.c index b2e2f1fb7..e14af4fab 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" @@ -838,6 +839,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_object__synchronous_writing) + 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 +876,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 +904,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_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/openssl_stream.c b/src/openssl_stream.c index bb9b32c67..c0a9c3c37 100644 --- a/src/openssl_stream.c +++ b/src/openssl_stream.c @@ -66,7 +66,7 @@ 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); } diff --git a/src/pack-objects.c b/src/pack-objects.c index 58b7b94b3..ef272e8f5 100644 --- a/src/pack-objects.c +++ b/src/pack-objects.c @@ -1385,6 +1385,7 @@ int git_packbuilder_write( git_indexer *indexer; git_transfer_progress stats; struct pack_write_context ctx; + int t; PREPARE_PACK; @@ -1392,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; 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/patch_parse.c b/src/patch_parse.c index d993c0311..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; } diff --git a/src/posix.c b/src/posix.c index e68f324f6..94deb6ab0 100644 --- a/src/posix.c +++ b/src/posix.c @@ -10,6 +10,8 @@ #include <stdio.h> #include <ctype.h> +size_t p_fsync__cnt = 0; + #ifndef GIT_WIN32 #ifdef NO_ADDRINFO diff --git a/src/posix.h b/src/posix.h index f204751cf..bd5a98e26 100644 --- a/src/posix.h +++ b/src/posix.h @@ -111,6 +111,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/rebase.c b/src/rebase.c index bf1d086ba..f528031b3 100644 --- a/src/rebase.c +++ b/src/rebase.c @@ -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; } @@ -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); @@ -823,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 || diff --git a/src/refdb_fs.c b/src/refdb_fs.c index ac5a6a6a5..b325d2763 100644 --- a/src/refdb_fs.c +++ b/src/refdb_fs.c @@ -62,6 +62,7 @@ typedef struct refdb_fs_backend { 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); @@ -736,8 +737,9 @@ 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); @@ -746,16 +748,25 @@ static int loose_lock(git_filebuf *file, refdb_fs_backend *backend, const char * 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->gitpath, 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->gitpath, 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); @@ -990,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 @@ -1786,7 +1800,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; @@ -1854,7 +1868,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); @@ -2011,6 +2030,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_object__synchronous_writing) + backend->fsync = 1; backend->parent.exists = &refdb_fs_backend__exists; backend->parent.lookup = &refdb_fs_backend__lookup; diff --git a/src/repository.c b/src/repository.c index 0db481638..425ef796f 100644 --- a/src/repository.c +++ b/src/repository.c @@ -1055,18 +1055,22 @@ int git_repository_odb__weakptr(git_odb **out, git_repository *repo) git_odb *odb; if ((error = git_repository_item_path(&odb_path, repo, - GIT_REPOSITORY_ITEM_OBJECTS)) < 0) + 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); diff --git a/src/repository.h b/src/repository.h index c328ecd21..33adfa60a 100644 --- a/src/repository.h +++ b/src/repository.h @@ -46,6 +46,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 +107,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 */ diff --git a/src/settings.c b/src/settings.c index 21585672c..24e549ec1 100644 --- a/src/settings.c +++ b/src/settings.c @@ -227,6 +227,10 @@ int git_libgit2_opts(int key, ...) git_smart__ofs_delta_enabled = (va_arg(ap, int) != 0); break; + case GIT_OPT_ENABLE_SYNCHRONOUS_OBJECT_CREATION: + git_object__synchronous_writing = (va_arg(ap, int) != 0); + break; + default: giterr_set(GITERR_INVALID, "invalid option key"); error = -1; diff --git a/src/submodule.c b/src/submodule.c index 191cdf3dd..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" @@ -2038,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/unix/posix.h b/src/unix/posix.h index b4786403f..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) diff --git a/src/win32/posix_w32.c b/src/win32/posix_w32.c index fea634b00..5172627b0 100644 --- a/src/win32/posix_w32.c +++ b/src/win32/posix_w32.c @@ -113,6 +113,8 @@ int p_fsync(int fd) { HANDLE fh = (HANDLE)_get_osfhandle(fd); + p_fsync__cnt++; + if (fh == INVALID_HANDLE_VALUE) { errno = EBADF; return -1; diff --git a/src/worktree.c b/src/worktree.c index 5abc98945..393a088fe 100644 --- a/src/worktree.c +++ b/src/worktree.c @@ -14,11 +14,20 @@ #include "repository.h" #include "worktree.h" -static bool is_worktree_dir(git_buf *dir) +static bool is_worktree_dir(const char *dir) { - return git_path_contains_file(dir, "commondir") - && git_path_contains_file(dir, "gitdir") - && git_path_contains_file(dir, "HEAD"); + 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) @@ -47,7 +56,7 @@ int git_worktree_list(git_strarray *wts, git_repository *repo) git_buf_truncate(&path, len); git_buf_puts(&path, worktree); - if (!is_worktree_dir(&path)) { + if (!is_worktree_dir(path.ptr)) { git_vector_remove(&worktrees, i); git__free(worktree); } @@ -112,6 +121,46 @@ out: 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; @@ -125,33 +174,47 @@ int git_worktree_lookup(git_worktree **out, git_repository *repo, const char *na if ((error = git_buf_printf(&path, "%s/worktrees/%s", repo->commondir, name)) < 0) goto out; - if (!is_worktree_dir(&path)) { - error = -1; + if ((error = (open_worktree_dir(out, git_repository_workdir(repo), path.ptr, name))) < 0) goto out; - } - if ((wt = git__malloc(sizeof(struct git_repository))) == NULL) { +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; } - if ((wt->name = git__strdup(name)) == NULL - || (wt->commondir_path = git_worktree__read_link(path.ptr, "commondir")) == NULL - || (wt->gitlink_path = git_worktree__read_link(path.ptr, "gitdir")) == NULL - || (wt->parent_path = git__strdup(git_repository_path(repo))) == NULL) { - error = -1; + gitdir = git_repository_path(repo); + commondir = git_repository_commondir(repo); + + if ((error = git_path_prettify_dir(&parent, "..", commondir)) < 0) goto out; - } - wt->gitdir_path = git_buf_detach(&path); - wt->locked = !!git_worktree_is_locked(NULL, wt); - (*out) = wt; + /* The name is defined by the last component in '.git/worktree/%s' */ + name = git_path_basename(gitdir); -out: - git_buf_free(&path); + if ((error = open_worktree_dir(out, parent.ptr, gitdir, name)) < 0) + goto out; +out: if (error) - git_worktree_free(wt); + free(name); + git_buf_free(&parent); return error; } @@ -177,7 +240,7 @@ int git_worktree_validate(const git_worktree *wt) assert(wt); git_buf_puts(&buf, wt->gitdir_path); - if (!is_worktree_dir(&buf)) { + if (!is_worktree_dir(buf.ptr)) { giterr_set(GITERR_WORKTREE, "Worktree gitdir ('%s') is not valid", wt->gitlink_path); @@ -209,7 +272,7 @@ out: int git_worktree_add(git_worktree **out, git_repository *repo, const char *name, const char *worktree) { - git_buf path = GIT_BUF_INIT, buf = GIT_BUF_INIT; + 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; @@ -220,35 +283,39 @@ int git_worktree_add(git_worktree **out, git_repository *repo, const char *name, *out = NULL; - /* Create worktree related files in commondir */ - if ((err = git_buf_joinpath(&path, repo->commondir, "worktrees")) < 0) + /* Create gitdir directory ".git/worktrees/<name>" */ + if ((err = git_buf_joinpath(&gitdir, repo->commondir, "worktrees")) < 0) goto out; - if (!git_path_exists(path.ptr)) - if ((err = git_futils_mkdir(path.ptr, 0755, GIT_MKDIR_EXCL)) < 0) + 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(&path, path.ptr, name)) < 0) + 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_futils_mkdir(path.ptr, 0755, GIT_MKDIR_EXCL)) < 0) + 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; /* Create worktree .git file */ - if ((err = git_buf_printf(&buf, "gitdir: %s\n", path.ptr)) < 0) + if ((err = git_buf_printf(&buf, "gitdir: %s\n", gitdir.ptr)) < 0) goto out; - if ((err = write_wtfile(worktree, ".git", &buf)) < 0) + if ((err = write_wtfile(wddir.ptr, ".git", &buf)) < 0) goto out; - /* Create commondir files */ - if ((err = git_buf_sets(&buf, repo->commondir)) < 0 + /* Create gitdir files */ + if ((err = git_path_prettify_dir(&buf, repo->commondir, NULL) < 0) || (err = git_buf_putc(&buf, '\n')) < 0 - || (err = write_wtfile(path.ptr, "commondir", &buf)) < 0) + || (err = write_wtfile(gitdir.ptr, "commondir", &buf)) < 0) goto out; - if ((err = git_buf_joinpath(&buf, worktree, ".git")) < 0 + if ((err = git_buf_joinpath(&buf, wddir.ptr, ".git")) < 0 || (err = git_buf_putc(&buf, '\n')) < 0 - || (err = write_wtfile(path.ptr, "gitdir", &buf)) < 0) + || (err = write_wtfile(gitdir.ptr, "gitdir", &buf)) < 0) goto out; /* Create new branch */ @@ -260,9 +327,9 @@ int git_worktree_add(git_worktree **out, git_repository *repo, const char *name, goto out; /* Set worktree's HEAD */ - if ((err = git_repository_create_head(path.ptr, name)) < 0) + if ((err = git_repository_create_head(gitdir.ptr, git_reference_name(ref))) < 0) goto out; - if ((err = git_repository_open(&wt, worktree)) < 0) + if ((err = git_repository_open(&wt, wddir.ptr)) < 0) goto out; /* Checkout worktree's HEAD */ @@ -275,7 +342,8 @@ int git_worktree_add(git_worktree **out, git_repository *repo, const char *name, goto out; out: - git_buf_free(&path); + git_buf_free(&gitdir); + git_buf_free(&wddir); git_buf_free(&buf); git_reference_free(ref); git_reference_free(head); @@ -394,7 +462,7 @@ int git_worktree_prune(git_worktree *wt, unsigned flags) } /* Delete gitdir in parent repository */ - if ((err = git_buf_printf(&path, "%s/worktrees/%s", wt->parent_path, wt->name)) < 0) + if ((err = git_buf_printf(&path, "%s/worktrees/%s", wt->commondir_path, wt->name)) < 0) goto out; if (!git_path_exists(path.ptr)) { diff --git a/src/worktree.h b/src/worktree.h index b8e527968..57c2e65f0 100644 --- a/src/worktree.h +++ b/src/worktree.h @@ -24,7 +24,7 @@ struct git_worktree { /* Path to the common directory contained in the parent * repository */ char *commondir_path; - /* Path to the parent's .git directory */ + /* Path to the parent's working directory */ char *parent_path; int locked:1; diff --git a/tests/core/posix.c b/tests/core/posix.c index 018d0c8ba..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", &addr)); /* AF_DECnet */ - cl_assert_equal_i(EAFNOSUPPORT, errno); - - cl_git_fail(p_inet_pton(5, "315.124", &addr)); /* AF_CHAOS */ + cl_git_fail(p_inet_pton(INT_MAX-1, "52.472", &addr)); cl_assert_equal_i(EAFNOSUPPORT, errno); } diff --git a/tests/odb/loose.c b/tests/odb/loose.c index c91927c4a..dd686aa01 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_SYNCHRONOUS_OBJECT_CREATION, 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_SYNCHRONOUS_OBJECT_CREATION, 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/pack/packbuilder.c b/tests/pack/packbuilder.c index 29f3e2d64..1d7becef7 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_SYNCHRONOUS_OBJECT_CREATION, 0)); + if (_commits_is_initialized) { _commits_is_initialized = 0; git_vector_foreach(&_commits, i, o) { @@ -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_SYNCHRONOUS_OBJECT_CREATION, 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/refs/create.c b/tests/refs/create.c index aca808c8c..4ecc60565 100644 --- a/tests/refs/create.c +++ b/tests/refs/create.c @@ -13,6 +13,7 @@ static git_repository *g_repo; void test_refs_create__initialize(void) { g_repo = cl_git_sandbox_init("testrepo"); + p_fsync__cnt = 0; } void test_refs_create__cleanup(void) @@ -21,6 +22,7 @@ void test_refs_create__cleanup(void) 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_SYNCHRONOUS_OBJECT_CREATION, 0)); } void test_refs_create__symbolic(void) @@ -297,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_SYNCHRONOUS_OBJECT_CREATION, 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/resources/submodules/testrepo/.gitted/config b/tests/resources/submodules/testrepo/.gitted/config index d6dcad12b..8e5571191 100644 --- a/tests/resources/submodules/testrepo/.gitted/config +++ b/tests/resources/submodules/testrepo/.gitted/config @@ -4,9 +4,6 @@ bare = false logallrefupdates = true ignorecase = true -[remote "origin"] - fetch = +refs/heads/*:refs/remotes/origin/* - url = /Users/rb/src/libgit2/tests/resources/testrepo.git [branch "master"] remote = origin merge = refs/heads/master diff --git a/tests/worktree/open.c b/tests/worktree/open.c index bdc8bcf9d..74b9007d9 100644 --- a/tests/worktree/open.c +++ b/tests/worktree/open.c @@ -1,13 +1,14 @@ #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" - #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; @@ -34,56 +35,46 @@ static void assert_worktree_valid(git_repository *wt, const char *parentdir, con git_buf_free(&path); } -void test_worktree_open__repository(void) +void test_worktree_open__initialize(void) { - worktree_fixture fixture = - WORKTREE_FIXTURE_INIT(COMMON_REPO, WORKTREE_REPO); setup_fixture_worktree(&fixture); +} - assert_worktree_valid(fixture.worktree, COMMON_REPO, WORKTREE_REPO); - +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) { - worktree_fixture fixture = - WORKTREE_FIXTURE_INIT(COMMON_REPO, WORKTREE_REPO); git_repository *wt; - setup_fixture_worktree(&fixture); - cl_git_pass(git_repository_open(&wt, WORKTREE_REPO)); assert_worktree_valid(wt, COMMON_REPO, WORKTREE_REPO); git_repository_free(wt); - cleanup_fixture_worktree(&fixture); } void test_worktree_open__repository_through_gitlink(void) { - worktree_fixture fixture = - WORKTREE_FIXTURE_INIT(COMMON_REPO, WORKTREE_REPO); git_repository *wt; - setup_fixture_worktree(&fixture); - cl_git_pass(git_repository_open(&wt, WORKTREE_REPO "/.git")); assert_worktree_valid(wt, COMMON_REPO, WORKTREE_REPO); git_repository_free(wt); - cleanup_fixture_worktree(&fixture); } void test_worktree_open__repository_through_gitdir(void) { - worktree_fixture fixture = - WORKTREE_FIXTURE_INIT(COMMON_REPO, WORKTREE_REPO); git_buf gitdir_path = GIT_BUF_INIT; git_repository *wt; - setup_fixture_worktree(&fixture); - 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")); @@ -93,18 +84,13 @@ void test_worktree_open__repository_through_gitdir(void) git_buf_free(&gitdir_path); git_repository_free(wt); - cleanup_fixture_worktree(&fixture); } void test_worktree_open__open_discovered_worktree(void) { - worktree_fixture fixture = - WORKTREE_FIXTURE_INIT(COMMON_REPO, WORKTREE_REPO); git_buf path = GIT_BUF_INIT; git_repository *repo; - setup_fixture_worktree(&fixture); - cl_git_pass(git_repository_discover(&path, git_repository_workdir(fixture.worktree), false, NULL)); cl_git_pass(git_repository_open(&repo, path.ptr)); @@ -113,13 +99,14 @@ void test_worktree_open__open_discovered_worktree(void) git_buf_free(&path); git_repository_free(repo); - cleanup_fixture_worktree(&fixture); } 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")); @@ -130,65 +117,27 @@ void test_worktree_open__repository_with_nonexistent_parent(void) cl_fixture_cleanup(WORKTREE_REPO); } -void test_worktree_open__submodule_worktree_parent(void) +void test_worktree_open__open_from_repository(void) { - worktree_fixture fixture = - WORKTREE_FIXTURE_INIT("submodules", WORKTREE_PARENT); - setup_fixture_worktree(&fixture); - - cl_assert(git_repository_path(fixture.worktree) != NULL); - cl_assert(git_repository_workdir(fixture.worktree) != NULL); + git_worktree *opened, *lookedup; - cl_assert(!fixture.repo->is_worktree); - cl_assert(fixture.worktree->is_worktree); + cl_git_pass(git_worktree_open_from_repository(&opened, fixture.worktree)); + cl_git_pass(git_worktree_lookup(&lookedup, fixture.repo, WORKTREE_REPO)); - cleanup_fixture_worktree(&fixture); -} + 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); -void test_worktree_open__submodule_worktree_child(void) -{ - worktree_fixture parent_fixture = - WORKTREE_FIXTURE_INIT("submodules", WORKTREE_PARENT); - worktree_fixture child_fixture = - WORKTREE_FIXTURE_INIT(NULL, WORKTREE_CHILD); - - setup_fixture_worktree(&parent_fixture); - cl_git_pass(p_rename( - "submodules/testrepo/.gitted", - "submodules/testrepo/.git")); - setup_fixture_worktree(&child_fixture); - - cl_assert(!parent_fixture.repo->is_worktree); - cl_assert(parent_fixture.worktree->is_worktree); - cl_assert(child_fixture.worktree->is_worktree); - - cleanup_fixture_worktree(&child_fixture); - cleanup_fixture_worktree(&parent_fixture); + git_worktree_free(opened); + git_worktree_free(lookedup); } -void test_worktree_open__open_discovered_submodule_worktree(void) +void test_worktree_open__open_from_nonworktree_fails(void) { - worktree_fixture parent_fixture = - WORKTREE_FIXTURE_INIT("submodules", WORKTREE_PARENT); - worktree_fixture child_fixture = - WORKTREE_FIXTURE_INIT(NULL, WORKTREE_CHILD); - git_buf path = GIT_BUF_INIT; - git_repository *repo; - - setup_fixture_worktree(&parent_fixture); - cl_git_pass(p_rename( - "submodules/testrepo/.gitted", - "submodules/testrepo/.git")); - setup_fixture_worktree(&child_fixture); - - cl_git_pass(git_repository_discover(&path, - git_repository_workdir(child_fixture.worktree), false, NULL)); - cl_git_pass(git_repository_open(&repo, path.ptr)); - cl_assert_equal_s(git_repository_workdir(child_fixture.worktree), - git_repository_workdir(repo)); + git_worktree *wt; - git_buf_free(&path); - git_repository_free(repo); - cleanup_fixture_worktree(&child_fixture); - cleanup_fixture_worktree(&parent_fixture); + cl_git_fail(git_worktree_open_from_repository(&wt, fixture.repo)); } diff --git a/tests/worktree/refs.c b/tests/worktree/refs.c index ccac8be29..b9a05606d 100644 --- a/tests/worktree/refs.c +++ b/tests/worktree/refs.c @@ -1,4 +1,6 @@ #include "clar_libgit2.h" +#include "path.h" +#include "refs.h" #include "worktree.h" #include "worktree_helpers.h" @@ -128,3 +130,27 @@ void test_worktree_refs__delete_succeeds_after_pruning_worktree(void) cl_git_pass(git_branch_delete(branch)); git_reference_free(branch); } + +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/submodule.c b/tests/worktree/submodule.c new file mode 100644 index 000000000..562077597 --- /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)); + 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 index f0c423599..6e90e6ac0 100644 --- a/tests/worktree/worktree.c +++ b/tests/worktree/worktree.c @@ -115,11 +115,12 @@ void test_worktree_worktree__lookup(void) cl_git_pass(git_worktree_lookup(&wt, fixture.repo, "testrepo-worktree")); - git_buf_printf(&gitdir_path, "%s/worktrees/%s", fixture.repo->commondir, "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->gitdir); + 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); @@ -305,7 +306,9 @@ void test_worktree_worktree__init_submodule(void) cl_git_pass(git_worktree_add(&worktree, sm, "repo-worktree", path.ptr)); 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/")); |