From 5a23c74b63ec9f63c648f79b13a900c37332ee55 Mon Sep 17 00:00:00 2001
From: Michael Paquier <michael@paquier.xyz>
Date: Sun, 5 Aug 2018 05:31:18 +0900
Subject: [PATCH] Reset properly errno before calling write()

6cb3372 enforces errno to ENOSPC when less bytes than what is expected
have been written when it is unset, though it forgot to properly reset
errno before doing a system call to write(), causing errno to
potentially come from a previous system call.

Reported-by: Tom Lane
Author: Michael Paquier
Reviewed-by: Tom Lane
Discussion: https://postgr.es/m/31797.1533326676@sss.pgh.pa.us
---
 src/backend/access/heap/rewriteheap.c           | 1 +
 src/backend/access/transam/twophase.c           | 1 +
 src/backend/replication/logical/origin.c        | 3 +++
 src/backend/replication/logical/reorderbuffer.c | 1 +
 src/backend/replication/logical/snapbuild.c     | 1 +
 src/backend/replication/slot.c                  | 1 +
 src/bin/pg_basebackup/walmethods.c              | 6 ++++++
 7 files changed, 14 insertions(+)

diff --git a/src/backend/access/heap/rewriteheap.c b/src/backend/access/heap/rewriteheap.c
index ed7ba181c79..85f92973c95 100644
--- a/src/backend/access/heap/rewriteheap.c
+++ b/src/backend/access/heap/rewriteheap.c
@@ -1166,6 +1166,7 @@ heap_xlog_logical_rewrite(XLogReaderState *r)
 	len = xlrec->num_mappings * sizeof(LogicalRewriteMappingData);
 
 	/* write out tail end of mapping file (again) */
+	errno = 0;
 	pgstat_report_wait_start(WAIT_EVENT_LOGICAL_REWRITE_MAPPING_WRITE);
 	if (write(fd, data, len) != len)
 	{
diff --git a/src/backend/access/transam/twophase.c b/src/backend/access/transam/twophase.c
index 306861bb793..0ae07227941 100644
--- a/src/backend/access/transam/twophase.c
+++ b/src/backend/access/transam/twophase.c
@@ -1669,6 +1669,7 @@ RecreateTwoPhaseFile(TransactionId xid, void *content, int len)
 				 errmsg("could not recreate file \"%s\": %m", path)));
 
 	/* Write content and CRC */
+	errno = 0;
 	pgstat_report_wait_start(WAIT_EVENT_TWOPHASE_FILE_WRITE);
 	if (write(fd, content, len) != len)
 	{
diff --git a/src/backend/replication/logical/origin.c b/src/backend/replication/logical/origin.c
index 822c96d1c2f..bf97dcdee4b 100644
--- a/src/backend/replication/logical/origin.c
+++ b/src/backend/replication/logical/origin.c
@@ -576,6 +576,7 @@ CheckPointReplicationOrigin(void)
 						tmppath)));
 
 	/* write magic */
+	errno = 0;
 	if ((write(tmpfd, &magic, sizeof(magic))) != sizeof(magic))
 	{
 		int			save_errno = errno;
@@ -619,6 +620,7 @@ CheckPointReplicationOrigin(void)
 		/* make sure we only write out a commit that's persistent */
 		XLogFlush(local_lsn);
 
+		errno = 0;
 		if ((write(tmpfd, &disk_state, sizeof(disk_state))) !=
 			sizeof(disk_state))
 		{
@@ -641,6 +643,7 @@ CheckPointReplicationOrigin(void)
 
 	/* write out the CRC */
 	FIN_CRC32C(crc);
+	errno = 0;
 	if ((write(tmpfd, &crc, sizeof(crc))) != sizeof(crc))
 	{
 		int			save_errno = errno;
diff --git a/src/backend/replication/logical/reorderbuffer.c b/src/backend/replication/logical/reorderbuffer.c
index 9b55b94227b..1d43a165ad0 100644
--- a/src/backend/replication/logical/reorderbuffer.c
+++ b/src/backend/replication/logical/reorderbuffer.c
@@ -2421,6 +2421,7 @@ ReorderBufferSerializeChange(ReorderBuffer *rb, ReorderBufferTXN *txn,
 
 	ondisk->size = sz;
 
+	errno = 0;
 	pgstat_report_wait_start(WAIT_EVENT_REORDER_BUFFER_WRITE);
 	if (write(fd, rb->outbuf, ondisk->size) != ondisk->size)
 	{
diff --git a/src/backend/replication/logical/snapbuild.c b/src/backend/replication/logical/snapbuild.c
index 1359d9b20a3..a6cd6c67d16 100644
--- a/src/backend/replication/logical/snapbuild.c
+++ b/src/backend/replication/logical/snapbuild.c
@@ -1609,6 +1609,7 @@ SnapBuildSerialize(SnapBuild *builder, XLogRecPtr lsn)
 		ereport(ERROR,
 				(errmsg("could not open file \"%s\": %m", path)));
 
+	errno = 0;
 	pgstat_report_wait_start(WAIT_EVENT_SNAPBUILD_WRITE);
 	if ((write(fd, ondisk, needed_length)) != needed_length)
 	{
diff --git a/src/backend/replication/slot.c b/src/backend/replication/slot.c
index 6c363980583..19978d9a9ed 100644
--- a/src/backend/replication/slot.c
+++ b/src/backend/replication/slot.c
@@ -1275,6 +1275,7 @@ SaveSlotToPath(ReplicationSlot *slot, const char *dir, int elevel)
 				SnapBuildOnDiskChecksummedSize);
 	FIN_CRC32C(cp.checksum);
 
+	errno = 0;
 	pgstat_report_wait_start(WAIT_EVENT_REPLICATION_SLOT_WRITE);
 	if ((write(fd, &cp, sizeof(cp))) != sizeof(cp))
 	{
diff --git a/src/bin/pg_basebackup/walmethods.c b/src/bin/pg_basebackup/walmethods.c
index fbfee05a5a6..42e3f3023a0 100644
--- a/src/bin/pg_basebackup/walmethods.c
+++ b/src/bin/pg_basebackup/walmethods.c
@@ -122,6 +122,7 @@ dir_open_for_write(const char *pathname, const char *temp_suffix, size_t pad_to_
 		zerobuf = pg_malloc0(XLOG_BLCKSZ);
 		for (bytes = 0; bytes < pad_to_size; bytes += XLOG_BLCKSZ)
 		{
+			errno = 0;
 			if (write(fd, zerobuf, XLOG_BLCKSZ) != XLOG_BLCKSZ)
 			{
 				int			save_errno = errno;
@@ -445,6 +446,7 @@ tar_write_compressed_data(void *buf, size_t count, bool flush)
 		{
 			size_t		len = ZLIB_OUT_SIZE - tar_data->zp->avail_out;
 
+			errno = 0;
 			if (write(tar_data->fd, tar_data->zlibOut, len) != len)
 			{
 				/*
@@ -629,6 +631,7 @@ tar_open_for_write(const char *pathname, const char *temp_suffix, size_t pad_to_
 
 	if (!tar_data->compression)
 	{
+		errno = 0;
 		if (write(tar_data->fd, tar_data->currentfile->header, 512) != 512)
 		{
 			save_errno = errno;
@@ -829,6 +832,7 @@ tar_close(Walfile f, WalCloseMethod method)
 		return -1;
 	if (!tar_data->compression)
 	{
+		errno = 0;
 		if (write(tar_data->fd, tf->header, 512) != 512)
 		{
 			/* if write didn't set errno, assume problem is no disk space */
@@ -901,6 +905,7 @@ tar_finish(void)
 	MemSet(zerobuf, 0, sizeof(zerobuf));
 	if (!tar_data->compression)
 	{
+		errno = 0;
 		if (write(tar_data->fd, zerobuf, sizeof(zerobuf)) != sizeof(zerobuf))
 		{
 			/* if write didn't set errno, assume problem is no disk space */
@@ -933,6 +938,7 @@ tar_finish(void)
 			{
 				size_t		len = ZLIB_OUT_SIZE - tar_data->zp->avail_out;
 
+				errno = 0;
 				if (write(tar_data->fd, tar_data->zlibOut, len) != len)
 				{
 					/*