diff --git a/src/bin/pg_rewind/libpq_fetch.c b/src/bin/pg_rewind/libpq_fetch.c
index 5914b15017..821e4b0c81 100644
--- a/src/bin/pg_rewind/libpq_fetch.c
+++ b/src/bin/pg_rewind/libpq_fetch.c
@@ -337,7 +337,18 @@ receiveFileChunks(const char *sql)
 		pg_log(PG_DEBUG, "received chunk for file \"%s\", offset %s, size %d\n",
 			   filename, chunkoff_str, chunksize);
 
-		open_target_file(filename, false);
+		/*
+		 * Truncate new files which are fully copied.  We are sure to not
+		 * truncate a file whose data has been partially fetched for two
+		 * reasons:
+		 * 1) The set of file ranges is ordered so as the chunks of each
+		 * file is processed sequentially.
+		 * 2) Only files fully copied register a chunk with an offset of
+		 * 0, which means that the beginning of a file is received, so it
+		 * should be truncated first.  Note that the truncation is lossy,
+		 * and may be tried on a file which does not exist locally.
+		 */
+		open_target_file(filename, chunkoff == 0);
 
 		write_target_range(chunk, chunkoff, chunksize);
 
@@ -464,8 +475,6 @@ libpq_executeFileMap(filemap_t *map)
 				break;
 
 			case FILE_ACTION_COPY:
-				/* Truncate the old file out of the way, if any */
-				open_target_file(entry->path, true);
 				fetch_file_range(entry->path, 0, entry->newsize);
 				break;
 
@@ -501,12 +510,17 @@ libpq_executeFileMap(filemap_t *map)
 
 	/*
 	 * We've now copied the list of file ranges that we need to fetch to the
-	 * temporary table. Now, actually fetch all of those ranges.
+	 * temporary table. Now, actually fetch all of those ranges.  The elements
+	 * fetched are ordered so as the truncation of files fully copied from the
+	 * source server is done after receiving their first chunk.  This also
+	 * gives a better sequential performance to the operations, especially
+	 * when working on large files.
 	 */
 	sql =
 		"SELECT path, begin,\n"
 		"  pg_read_binary_file(path, begin, len, true) AS chunk\n"
-		"FROM fetchchunks\n";
+		"FROM fetchchunks\n"
+		"ORDER BY path, begin\n";
 
 	receiveFileChunks(sql);
 }
diff --git a/src/bin/pg_rewind/t/006_readonly.pl b/src/bin/pg_rewind/t/006_readonly.pl
new file mode 100644
index 0000000000..51db93a9a0
--- /dev/null
+++ b/src/bin/pg_rewind/t/006_readonly.pl
@@ -0,0 +1,85 @@
+# Test how pg_rewind reacts to read-only files in the data dirs.
+# All such files should be ignored in the process.
+
+use strict;
+use warnings;
+use TestLib;
+use Test::More tests => 2;
+
+use File::Copy;
+use File::Find;
+
+use RewindTest;
+
+my $test_mode = "remote";
+
+RewindTest::setup_cluster($test_mode);
+RewindTest::start_master();
+RewindTest::create_standby($test_mode);
+
+# Create the same read-only file in standby and master
+my $test_master_datadir = $node_master->data_dir;
+my $test_standby_datadir = $node_standby->data_dir;
+my $readonly_master = "$test_master_datadir/readonly_file";
+my $readonly_standby = "$test_standby_datadir/readonly_file";
+
+append_to_file($readonly_master, "in master");
+append_to_file($readonly_standby, "in standby");
+chmod 0400, $readonly_master, $readonly_standby;
+
+RewindTest::promote_standby();
+
+# Stop the master and run pg_rewind.
+$node_master->stop;
+
+my $master_pgdata   = $node_master->data_dir;
+my $standby_pgdata  = $node_standby->data_dir;
+my $standby_connstr = $node_standby->connstr('postgres');
+my $tmp_folder      = TestLib::tempdir;
+
+# Keep a temporary postgresql.conf for master node or it would be
+# overwritten during the rewind.
+copy(
+	"$master_pgdata/postgresql.conf",
+	"$tmp_folder/master-postgresql.conf.tmp");
+
+# Including read-only data in the source and the target will
+# cause pg_rewind to fail.
+my $rewind_command = [   'pg_rewind',       "--debug",
+		"--source-server", $standby_connstr,
+		"--target-pgdata=$master_pgdata" ];
+
+command_fails($rewind_command, 'pg_rewind fails with read-only');
+
+# Need to put the server back into a clean state for next rewind.
+# Move back postgresql.conf with old settings to allow the node to
+# start and stop, allowing the follow-up rewind to work properly.
+move("$tmp_folder/master-postgresql.conf.tmp",
+	 "$master_pgdata/postgresql.conf");
+$node_master->start;
+$node_master->stop;
+
+# Now remove the read-only data on both sides, the data folder
+# from the previous attempt should still be able to work.
+unlink($readonly_master);
+unlink($readonly_standby);
+command_ok($rewind_command, 'pg_rewind passes without read-only');
+
+# Now move back postgresql.conf with old settings
+move("$tmp_folder/master-postgresql.conf.tmp",
+	 "$master_pgdata/postgresql.conf");
+
+# Plug-in rewound node to the now-promoted standby node
+my $port_standby = $node_standby->port;
+$node_master->append_conf('recovery.conf', qq(
+primary_conninfo='port=$port_standby'
+standby_mode=on
+recovery_target_timeline='latest'
+));
+
+# Restart the master to check that rewind went correctly.
+$node_master->start;
+
+RewindTest::clean_rewind_test();
+
+exit(0);
