mirror of
https://github.com/git/git.git
synced 2026-01-11 13:23:12 +09:00
Merge branch 'ps/object-collision-check'
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()` object-file: fix race in object collision check
This commit is contained in:
commit
66e01e510a
@ -1970,54 +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) {
|
||||
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;
|
||||
}
|
||||
|
||||
@ -2032,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;
|
||||
@ -2054,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;
|
||||
@ -2069,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);
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user