@@ -483,13 +483,29 @@ static int write_at(git_indexer *idx, const void *data, git_off_t offset, size_t
483483
484484static int append_to_pack (git_indexer * idx , const void * data , size_t size )
485485{
486+ git_off_t new_size ;
487+ size_t mmap_alignment ;
488+ size_t page_offset ;
489+ git_off_t page_start ;
486490 git_off_t current_size = idx -> pack -> mwf .size ;
487491 int fd = idx -> pack -> mwf .fd ;
492+ int error ;
488493
489494 if (!size )
490495 return 0 ;
491496
492- if (p_lseek (fd , current_size + size - 1 , SEEK_SET ) < 0 ||
497+ if ((error = git__mmap_alignment (& mmap_alignment )) < 0 )
498+ return error ;
499+
500+ /* Write a single byte to force the file system to allocate space now or
501+ * report an error, since we can't report errors when writing using mmap.
502+ * Round the size up to the nearest page so that we only need to perform file
503+ * I/O when we add a page, instead of whenever we write even a single byte. */
504+ new_size = current_size + size ;
505+ page_offset = new_size % mmap_alignment ;
506+ page_start = new_size - page_offset ;
507+
508+ if (p_lseek (fd , page_start + mmap_alignment - 1 , SEEK_SET ) < 0 ||
493509 p_write (idx -> pack -> mwf .fd , data , 1 ) < 0 ) {
494510 giterr_set (GITERR_OS , "cannot extend packfile '%s'" , idx -> pack -> pack_name );
495511 return -1 ;
@@ -1047,6 +1063,13 @@ int git_indexer_commit(git_indexer *idx, git_transfer_progress *stats)
10471063 goto on_error ;
10481064
10491065 git_mwindow_free_all (& idx -> pack -> mwf );
1066+
1067+ /* Truncate file to undo rounding up to next page_size in append_to_pack */
1068+ if (p_ftruncate (idx -> pack -> mwf .fd , idx -> pack -> mwf .size ) < 0 ) {
1069+ giterr_set (GITERR_OS , "failed to truncate pack file '%s'" , idx -> pack -> pack_name );
1070+ return -1 ;
1071+ }
1072+
10501073 /* We need to close the descriptor here so Windows doesn't choke on commit_at */
10511074 if (p_close (idx -> pack -> mwf .fd ) < 0 ) {
10521075 giterr_set (GITERR_OS , "failed to close packfile" );
0 commit comments