@@ -1970,54 +1970,59 @@ static void write_object_file_prepare_literally(const struct git_hash_algo *algo
19701970 hash_object_body (algo , & c , buf , len , oid , hdr , hdrlen );
19711971}
19721972
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 )
19741976{
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 ;
19771979 int ret = 0 ;
19781980
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 );
19821984 goto out ;
19831985 }
19841986
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 ;
19881993 goto out ;
19891994 }
19901995
19911996 while (1 ) {
19921997 ssize_t sz_a , sz_b ;
19931998
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 ));
19952000 if (sz_a < 0 ) {
1996- ret = error_errno (_ ("unable to read %s" ), filename_a );
2001+ ret = error_errno (_ ("unable to read %s" ), source );
19972002 goto out ;
19982003 }
19992004
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 ));
20012006 if (sz_b < 0 ) {
2002- ret = error_errno (_ ("unable to read %s" ), filename_b );
2007+ ret = error_errno (_ ("unable to read %s" ), dest );
20032008 goto out ;
20042009 }
20052010
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 )) {
20072012 ret = error (_ ("files '%s' and '%s' differ in contents" ),
2008- filename_a , filename_b );
2013+ source , dest );
20092014 goto out ;
20102015 }
20112016
2012- if (sz_a < sizeof (buf_a ))
2017+ if (sz_a < sizeof (buf_source ))
20132018 break ;
20142019 }
20152020
20162021out :
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 );
20212026 return ret ;
20222027}
20232028
@@ -2032,8 +2037,11 @@ int finalize_object_file(const char *tmpfile, const char *filename)
20322037int finalize_object_file_flags (const char * tmpfile , const char * filename ,
20332038 enum finalize_object_file_flags flags )
20342039{
2035- struct stat st ;
2036- int ret = 0 ;
2040+ unsigned retries = 0 ;
2041+ int ret ;
2042+
2043+ retry :
2044+ ret = 0 ;
20372045
20382046 if (object_creation_mode == OBJECT_CREATION_USES_RENAMES )
20392047 goto try_rename ;
@@ -2054,6 +2062,8 @@ int finalize_object_file_flags(const char *tmpfile, const char *filename,
20542062 * left to unlink.
20552063 */
20562064 if (ret && ret != EEXIST ) {
2065+ struct stat st ;
2066+
20572067 try_rename :
20582068 if (!stat (filename , & st ))
20592069 ret = EEXIST ;
@@ -2069,9 +2079,17 @@ int finalize_object_file_flags(const char *tmpfile, const char *filename,
20692079 errno = saved_errno ;
20702080 return error_errno (_ ("unable to write file %s" ), filename );
20712081 }
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 )
20742091 return -1 ;
2092+ }
20752093 unlink_or_warn (tmpfile );
20762094 }
20772095
0 commit comments