@@ -1242,13 +1242,15 @@ static int mfu_create_file(
12421242 * for regular files, dev argument is supposed to be ignored,
12431243 * see makedev() to create valid dev */
12441244 dev_t dev ;
1245+ bool file_exists = false;
12451246 memset (& dev , 0 , sizeof (dev_t ));
12461247 int mknod_rc = mfu_file_mknod (dest_path , DCOPY_DEF_PERMS_FILE | S_IFREG , dev , mfu_dst_file );
12471248 if (mknod_rc < 0 ) {
12481249 if (errno == EEXIST ) {
12491250 /* destination already exists, no big deal, but print warning */
12501251 MFU_LOG (MFU_LOG_WARN , "Original file exists, skip the creation: `%s' (errno=%d %s)" ,
12511252 dest_path , errno , strerror (errno ));
1253+ file_exists = true;
12521254 } else {
12531255 /* failed to create inode, that's a problem */
12541256 MFU_LOG (MFU_LOG_ERR , "File `%s' mknod() failed (errno=%d %s)" ,
@@ -1269,31 +1271,46 @@ static int mfu_create_file(
12691271 }
12701272 }
12711273
1272- /* Truncate destination files to 0 bytes when sparse file is enabled,
1273- * this is because we will not overwrite sections corresponding to holes
1274- * and we need those to be set to 0 */
1275- if (copy_opts -> sparse ) {
1276- /* truncate destination file to 0 bytes */
1274+ if (file_exists ) {
12771275 struct stat st ;
12781276 int status = mfu_file_lstat (dest_path , & st , mfu_dst_file );
1279- if (status == 0 ) {
1280- /* destination exists, truncate it to 0 bytes */
1277+ if (status != 0 ) {
1278+ MFU_LOG (MFU_LOG_ERR , "mfu_file_lstat() file: `%s' (errno=%d %s)" ,
1279+ dest_path , errno , strerror (errno ));
1280+ mfu_free (& dest_path );
1281+ return -1 ;
1282+ }
1283+ bool need_truncate = false;
1284+ /* Truncate destination files to 0 bytes when sparse file is enabled,
1285+ * this is because we will not overwrite sections corresponding to holes
1286+ * and we need those to be set to 0 */
1287+ if (copy_opts -> sparse ) {
1288+ need_truncate = true;
1289+ } else {
1290+ /* if src_file size < dest_file size, we also truncate */
1291+ struct stat src_st ;
1292+ status = mfu_file_lstat (src_path , & src_st , mfu_src_file );
1293+ if (status != 0 ) {
1294+ MFU_LOG (MFU_LOG_ERR , "mfu_file_lstat() file: `%s' (errno=%d %s)" ,
1295+ src_path , errno , strerror (errno ));
1296+ mfu_free (& dest_path );
1297+ return -1 ;
1298+ }
1299+ if (src_st .st_size < st .st_size )
1300+ need_truncate = true;
1301+ }
1302+
1303+ if (need_truncate ) {
1304+ /* truncate destination file to 0 bytes */
12811305 status = mfu_file_truncate (dest_path , 0 , mfu_dst_file );
12821306 if (status ) {
12831307 /* when using sparse file optimization, consider this to be an error,
12841308 * since we will not be overwriting the holes */
12851309 MFU_LOG (MFU_LOG_ERR , "Failed to truncate destination file: `%s' (errno=%d %s)" ,
12861310 dest_path , errno , strerror (errno ));
1287- rc = -1 ;
1288- }
1289- } else if (errno == - ENOENT ) {
1290- /* destination does not exist, which is fine */
1291- status = 0 ;
1292- } else {
1293- /* had an error stating destination file */
1294- MFU_LOG (MFU_LOG_ERR , "mfu_file_lstat() file: `%s' (errno=%d %s)" ,
1295- dest_path , errno , strerror (errno ));
1296- }
1311+ rc = -1 ;
1312+ }
1313+ }
12971314 }
12981315
12991316#ifdef HPSS_SUPPORT
@@ -1722,7 +1739,7 @@ static int mfu_copy_file_normal(
17221739
17231740 /* initialize our starting offset within the file */
17241741 off_t off = offset ;
1725-
1742+ bool need_truncate = false;
17261743 /* write data */
17271744 uint64_t total_bytes = 0 ;
17281745 while (total_bytes < length ) {
@@ -1787,6 +1804,8 @@ static int mfu_copy_file_normal(
17871804 * current file if we fail before truncating */
17881805 char * bufzero = ((char * )buf + bytes_read );
17891806 memset (bufzero , 0 , remainder );
1807+ /* truncate only in this case, otherwise truncate is not necessary */
1808+ need_truncate = true;
17901809 }
17911810
17921811 /* assumes buf_size is magic size for O_DIRECT */
@@ -1800,6 +1819,7 @@ static int mfu_copy_file_normal(
18001819 int skip_write = 0 ;
18011820 if (copy_opts -> sparse && mfu_is_all_null (buf , bytes_to_write )) {
18021821 skip_write = 1 ;
1822+ need_truncate = true;
18031823 }
18041824
18051825 /* write data to destination file if needed */
@@ -1847,7 +1867,11 @@ static int mfu_copy_file_normal(
18471867 }
18481868#endif
18491869
1850- /* if we wrote the last chunk, truncate the file */
1870+ /* if not using O_DIRECT, we already truncated the file at the beginning, we do not need to do
1871+ * it again. If using O_DIRECT, truncate only if we wrote beyond the src EOF. */
1872+ if (!need_truncate )
1873+ return 0 ;
1874+
18511875 off_t last_written = offset + length ;
18521876 off_t file_size_offt = (off_t ) file_size ;
18531877 if (last_written >= file_size_offt || file_size == 0 ) {
0 commit comments