From 944a026b4ec252667f275768ba4dcd53ae3bb07e Mon Sep 17 00:00:00 2001
From: Noah Misch <noah@leadboat.com>
Date: Sun, 12 Mar 2017 19:35:31 -0400
Subject: [PATCH] Fix pg_file_write() error handling.

Detect fclose() failures; given "ln -s /dev/full $PGDATA/devfull",
"pg_file_write('devfull', 'x', true)" now fails as it should.  Don't
leak a stream when fwrite() fails.  Remove a born-ineffective test that
aimed to skip zero-length writes.  Back-patch to 9.2 (all supported
versions).
---
 contrib/adminpack/adminpack.c | 19 +++++++------------
 1 file changed, 7 insertions(+), 12 deletions(-)

diff --git a/contrib/adminpack/adminpack.c b/contrib/adminpack/adminpack.c
index c7ff9055ef3..a63ff36f05c 100644
--- a/contrib/adminpack/adminpack.c
+++ b/contrib/adminpack/adminpack.c
@@ -136,10 +136,10 @@ pg_file_write(PG_FUNCTION_ARGS)
 					(ERRCODE_DUPLICATE_FILE,
 					 errmsg("file \"%s\" exists", filename)));
 
-		f = fopen(filename, "wb");
+		f = AllocateFile(filename, "wb");
 	}
 	else
-		f = fopen(filename, "ab");
+		f = AllocateFile(filename, "ab");
 
 	if (!f)
 		ereport(ERROR,
@@ -147,16 +147,11 @@ pg_file_write(PG_FUNCTION_ARGS)
 				 errmsg("could not open file \"%s\" for writing: %m",
 						filename)));
 
-	if (VARSIZE(data) != 0)
-	{
-		count = fwrite(VARDATA(data), 1, VARSIZE(data) - VARHDRSZ, f);
-
-		if (count != VARSIZE(data) - VARHDRSZ)
-			ereport(ERROR,
-					(errcode_for_file_access(),
-					 errmsg("could not write file \"%s\": %m", filename)));
-	}
-	fclose(f);
+	count = fwrite(VARDATA(data), 1, VARSIZE(data) - VARHDRSZ, f);
+	if (count != VARSIZE(data) - VARHDRSZ || FreeFile(f))
+		ereport(ERROR,
+				(errcode_for_file_access(),
+				 errmsg("could not write file \"%s\": %m", filename)));
 
 	PG_RETURN_INT64(count);
 }
-- 
GitLab