aboutsummaryrefslogtreecommitdiffstats
path: root/object-file.c
diff options
context:
space:
mode:
Diffstat (limited to 'object-file.c')
-rw-r--r--object-file.c108
1 files changed, 69 insertions, 39 deletions
diff --git a/object-file.c b/object-file.c
index 891eaa2b4b..6ce1caacae 100644
--- a/object-file.c
+++ b/object-file.c
@@ -8,6 +8,7 @@
*/
#define USE_THE_REPOSITORY_VARIABLE
+#define DISABLE_SIGN_COMPARE_WARNINGS
#include "git-compat-util.h"
#include "abspath.h"
@@ -201,6 +202,22 @@ static void git_hash_unknown_final_oid(struct object_id *oid UNUSED,
BUG("trying to finalize unknown hash");
}
+static const struct git_hash_algo sha1_unsafe_algo = {
+ .name = "sha1",
+ .format_id = GIT_SHA1_FORMAT_ID,
+ .rawsz = GIT_SHA1_RAWSZ,
+ .hexsz = GIT_SHA1_HEXSZ,
+ .blksz = GIT_SHA1_BLKSZ,
+ .init_fn = git_hash_sha1_init_unsafe,
+ .clone_fn = git_hash_sha1_clone_unsafe,
+ .update_fn = git_hash_sha1_update_unsafe,
+ .final_fn = git_hash_sha1_final_unsafe,
+ .final_oid_fn = git_hash_sha1_final_oid_unsafe,
+ .empty_tree = &empty_tree_oid,
+ .empty_blob = &empty_blob_oid,
+ .null_oid = &null_oid_sha1,
+};
+
const struct git_hash_algo hash_algos[GIT_HASH_NALGOS] = {
{
.name = NULL,
@@ -213,11 +230,6 @@ const struct git_hash_algo hash_algos[GIT_HASH_NALGOS] = {
.update_fn = git_hash_unknown_update,
.final_fn = git_hash_unknown_final,
.final_oid_fn = git_hash_unknown_final_oid,
- .unsafe_init_fn = git_hash_unknown_init,
- .unsafe_clone_fn = git_hash_unknown_clone,
- .unsafe_update_fn = git_hash_unknown_update,
- .unsafe_final_fn = git_hash_unknown_final,
- .unsafe_final_oid_fn = git_hash_unknown_final_oid,
.empty_tree = NULL,
.empty_blob = NULL,
.null_oid = NULL,
@@ -233,11 +245,7 @@ const struct git_hash_algo hash_algos[GIT_HASH_NALGOS] = {
.update_fn = git_hash_sha1_update,
.final_fn = git_hash_sha1_final,
.final_oid_fn = git_hash_sha1_final_oid,
- .unsafe_init_fn = git_hash_sha1_init_unsafe,
- .unsafe_clone_fn = git_hash_sha1_clone_unsafe,
- .unsafe_update_fn = git_hash_sha1_update_unsafe,
- .unsafe_final_fn = git_hash_sha1_final_unsafe,
- .unsafe_final_oid_fn = git_hash_sha1_final_oid_unsafe,
+ .unsafe = &sha1_unsafe_algo,
.empty_tree = &empty_tree_oid,
.empty_blob = &empty_blob_oid,
.null_oid = &null_oid_sha1,
@@ -253,11 +261,6 @@ const struct git_hash_algo hash_algos[GIT_HASH_NALGOS] = {
.update_fn = git_hash_sha256_update,
.final_fn = git_hash_sha256_final,
.final_oid_fn = git_hash_sha256_final_oid,
- .unsafe_init_fn = git_hash_sha256_init,
- .unsafe_clone_fn = git_hash_sha256_clone,
- .unsafe_update_fn = git_hash_sha256_update,
- .unsafe_final_fn = git_hash_sha256_final,
- .unsafe_final_oid_fn = git_hash_sha256_final_oid,
.empty_tree = &empty_tree_oid_sha256,
.empty_blob = &empty_blob_oid_sha256,
.null_oid = &null_oid_sha256,
@@ -304,6 +307,15 @@ int hash_algo_by_length(int len)
return GIT_HASH_UNKNOWN;
}
+const struct git_hash_algo *unsafe_hash_algo(const struct git_hash_algo *algop)
+{
+ /* If we have a faster "unsafe" implementation, use that. */
+ if (algop->unsafe)
+ return algop->unsafe;
+ /* Otherwise use the default one. */
+ return algop;
+}
+
/*
* This is meant to hold a *small* number of objects that you would
* want repo_read_object_file() to be able to return, but yet you do not want
@@ -1969,54 +1981,59 @@ static void write_object_file_prepare_literally(const struct git_hash_algo *algo
hash_object_body(algo, &c, buf, len, oid, hdr, hdrlen);
}
-static int check_collision(const char *filename_a, const char *filename_b)
+#define CHECK_COLLISION_DEST_VANISHED -2
+
+static int check_collision(const char *source, const char *dest)
{
- char buf_a[4096], buf_b[4096];
- int fd_a = -1, fd_b = -1;
+ char buf_source[4096], buf_dest[4096];
+ int fd_source = -1, fd_dest = -1;
int ret = 0;
- fd_a = open(filename_a, O_RDONLY);
- if (fd_a < 0) {
- ret = error_errno(_("unable to open %s"), filename_a);
+ fd_source = open(source, O_RDONLY);
+ if (fd_source < 0) {
+ ret = error_errno(_("unable to open %s"), source);
goto out;
}
- fd_b = open(filename_b, O_RDONLY);
- if (fd_b < 0) {
- ret = error_errno(_("unable to open %s"), filename_b);
+ fd_dest = open(dest, O_RDONLY);
+ if (fd_dest < 0) {
+ if (errno != ENOENT)
+ ret = error_errno(_("unable to open %s"), dest);
+ else
+ ret = CHECK_COLLISION_DEST_VANISHED;
goto out;
}
while (1) {
ssize_t sz_a, sz_b;
- sz_a = read_in_full(fd_a, buf_a, sizeof(buf_a));
+ sz_a = read_in_full(fd_source, buf_source, sizeof(buf_source));
if (sz_a < 0) {
- ret = error_errno(_("unable to read %s"), filename_a);
+ ret = error_errno(_("unable to read %s"), source);
goto out;
}
- sz_b = read_in_full(fd_b, buf_b, sizeof(buf_b));
+ sz_b = read_in_full(fd_dest, buf_dest, sizeof(buf_dest));
if (sz_b < 0) {
- ret = error_errno(_("unable to read %s"), filename_b);
+ ret = error_errno(_("unable to read %s"), dest);
goto out;
}
- if (sz_a != sz_b || memcmp(buf_a, buf_b, sz_a)) {
+ if (sz_a != sz_b || memcmp(buf_source, buf_dest, sz_a)) {
ret = error(_("files '%s' and '%s' differ in contents"),
- filename_a, filename_b);
+ source, dest);
goto out;
}
- if (sz_a < sizeof(buf_a))
+ if (sz_a < sizeof(buf_source))
break;
}
out:
- if (fd_a > -1)
- close(fd_a);
- if (fd_b > -1)
- close(fd_b);
+ if (fd_source > -1)
+ close(fd_source);
+ if (fd_dest > -1)
+ close(fd_dest);
return ret;
}
@@ -2031,8 +2048,11 @@ int finalize_object_file(const char *tmpfile, const char *filename)
int finalize_object_file_flags(const char *tmpfile, const char *filename,
enum finalize_object_file_flags flags)
{
- struct stat st;
- int ret = 0;
+ unsigned retries = 0;
+ int ret;
+
+retry:
+ ret = 0;
if (object_creation_mode == OBJECT_CREATION_USES_RENAMES)
goto try_rename;
@@ -2053,6 +2073,8 @@ int finalize_object_file_flags(const char *tmpfile, const char *filename,
* left to unlink.
*/
if (ret && ret != EEXIST) {
+ struct stat st;
+
try_rename:
if (!stat(filename, &st))
ret = EEXIST;
@@ -2068,9 +2090,17 @@ int finalize_object_file_flags(const char *tmpfile, const char *filename,
errno = saved_errno;
return error_errno(_("unable to write file %s"), filename);
}
- if (!(flags & FOF_SKIP_COLLISION_CHECK) &&
- check_collision(tmpfile, filename))
+ if (!(flags & FOF_SKIP_COLLISION_CHECK)) {
+ ret = check_collision(tmpfile, filename);
+ if (ret == CHECK_COLLISION_DEST_VANISHED) {
+ if (retries++ > 5)
+ return error(_("unable to write repeatedly vanishing file %s"),
+ filename);
+ goto retry;
+ }
+ else if (ret)
return -1;
+ }
unlink_or_warn(tmpfile);
}