@@ -1970,54 +1970,59 @@ static void write_object_file_prepare_literally(const struct git_hash_algo *algo
1970
1970
hash_object_body (algo , & c , buf , len , oid , hdr , hdrlen );
1971
1971
}
1972
1972
1973
- static int check_collision (const char * filename_a , const char * filename_b )
1973
+ #define CHECK_COLLISION_DEST_VANISHED -2
1974
+
1975
+ static int check_collision (const char * source , const char * dest )
1974
1976
{
1975
- char buf_a [4096 ], buf_b [4096 ];
1976
- int fd_a = -1 , fd_b = -1 ;
1977
+ char buf_source [4096 ], buf_dest [4096 ];
1978
+ int fd_source = -1 , fd_dest = -1 ;
1977
1979
int ret = 0 ;
1978
1980
1979
- fd_a = open (filename_a , O_RDONLY );
1980
- if (fd_a < 0 ) {
1981
- ret = error_errno (_ ("unable to open %s" ), filename_a );
1981
+ fd_source = open (source , O_RDONLY );
1982
+ if (fd_source < 0 ) {
1983
+ ret = error_errno (_ ("unable to open %s" ), source );
1982
1984
goto out ;
1983
1985
}
1984
1986
1985
- fd_b = open (filename_b , O_RDONLY );
1986
- if (fd_b < 0 ) {
1987
- ret = error_errno (_ ("unable to open %s" ), filename_b );
1987
+ fd_dest = open (dest , O_RDONLY );
1988
+ if (fd_dest < 0 ) {
1989
+ if (errno != ENOENT )
1990
+ ret = error_errno (_ ("unable to open %s" ), dest );
1991
+ else
1992
+ ret = CHECK_COLLISION_DEST_VANISHED ;
1988
1993
goto out ;
1989
1994
}
1990
1995
1991
1996
while (1 ) {
1992
1997
ssize_t sz_a , sz_b ;
1993
1998
1994
- sz_a = read_in_full (fd_a , buf_a , sizeof (buf_a ));
1999
+ sz_a = read_in_full (fd_source , buf_source , sizeof (buf_source ));
1995
2000
if (sz_a < 0 ) {
1996
- ret = error_errno (_ ("unable to read %s" ), filename_a );
2001
+ ret = error_errno (_ ("unable to read %s" ), source );
1997
2002
goto out ;
1998
2003
}
1999
2004
2000
- sz_b = read_in_full (fd_b , buf_b , sizeof (buf_b ));
2005
+ sz_b = read_in_full (fd_dest , buf_dest , sizeof (buf_dest ));
2001
2006
if (sz_b < 0 ) {
2002
- ret = error_errno (_ ("unable to read %s" ), filename_b );
2007
+ ret = error_errno (_ ("unable to read %s" ), dest );
2003
2008
goto out ;
2004
2009
}
2005
2010
2006
- if (sz_a != sz_b || memcmp (buf_a , buf_b , sz_a )) {
2011
+ if (sz_a != sz_b || memcmp (buf_source , buf_dest , sz_a )) {
2007
2012
ret = error (_ ("files '%s' and '%s' differ in contents" ),
2008
- filename_a , filename_b );
2013
+ source , dest );
2009
2014
goto out ;
2010
2015
}
2011
2016
2012
- if (sz_a < sizeof (buf_a ))
2017
+ if (sz_a < sizeof (buf_source ))
2013
2018
break ;
2014
2019
}
2015
2020
2016
2021
out :
2017
- if (fd_a > -1 )
2018
- close (fd_a );
2019
- if (fd_b > -1 )
2020
- close (fd_b );
2022
+ if (fd_source > -1 )
2023
+ close (fd_source );
2024
+ if (fd_dest > -1 )
2025
+ close (fd_dest );
2021
2026
return ret ;
2022
2027
}
2023
2028
@@ -2032,8 +2037,11 @@ int finalize_object_file(const char *tmpfile, const char *filename)
2032
2037
int finalize_object_file_flags (const char * tmpfile , const char * filename ,
2033
2038
enum finalize_object_file_flags flags )
2034
2039
{
2035
- struct stat st ;
2036
- int ret = 0 ;
2040
+ unsigned retries = 0 ;
2041
+ int ret ;
2042
+
2043
+ retry :
2044
+ ret = 0 ;
2037
2045
2038
2046
if (object_creation_mode == OBJECT_CREATION_USES_RENAMES )
2039
2047
goto try_rename ;
@@ -2054,6 +2062,8 @@ int finalize_object_file_flags(const char *tmpfile, const char *filename,
2054
2062
* left to unlink.
2055
2063
*/
2056
2064
if (ret && ret != EEXIST ) {
2065
+ struct stat st ;
2066
+
2057
2067
try_rename :
2058
2068
if (!stat (filename , & st ))
2059
2069
ret = EEXIST ;
@@ -2069,9 +2079,17 @@ int finalize_object_file_flags(const char *tmpfile, const char *filename,
2069
2079
errno = saved_errno ;
2070
2080
return error_errno (_ ("unable to write file %s" ), filename );
2071
2081
}
2072
- if (!(flags & FOF_SKIP_COLLISION_CHECK ) &&
2073
- check_collision (tmpfile , filename ))
2082
+ if (!(flags & FOF_SKIP_COLLISION_CHECK )) {
2083
+ ret = check_collision (tmpfile , filename );
2084
+ if (ret == CHECK_COLLISION_DEST_VANISHED ) {
2085
+ if (retries ++ > 5 )
2086
+ return error (_ ("unable to write repeatedly vanishing file %s" ),
2087
+ filename );
2088
+ goto retry ;
2089
+ }
2090
+ else if (ret )
2074
2091
return -1 ;
2092
+ }
2075
2093
unlink_or_warn (tmpfile );
2076
2094
}
2077
2095
0 commit comments