Skip to content

Commit

Permalink
Merge branch 'ps/object-collision-check' into next
Browse files Browse the repository at this point in the history
CI jobs gave sporadic failures, which turns out that that the
object finalization code was giving an error when it did not have
to.

* ps/object-collision-check:
  object-file: retry linking file into place when occluding file vanishes
  object-file: don't special-case missing source file in collision check
  object-file: rename variables in `check_collision()`
  • Loading branch information
gitster committed Jan 6, 2025
2 parents 841c3a3 + d7fcbe2 commit 540e2ba
Showing 1 changed file with 41 additions and 25 deletions.
66 changes: 41 additions & 25 deletions object-file.c
Original file line number Diff line number Diff line change
Expand Up @@ -1970,56 +1970,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) {
if (errno != ENOENT)
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) {
fd_dest = open(dest, O_RDONLY);
if (fd_dest < 0) {
if (errno != ENOENT)
ret = error_errno(_("unable to open %s"), filename_b);
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;
}

Expand All @@ -2034,8 +2037,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;
Expand All @@ -2056,6 +2062,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;
Expand All @@ -2071,9 +2079,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);
}

Expand Down

0 comments on commit 540e2ba

Please sign in to comment.