diff --git a/src/backend/utils/adt/genfile.c b/src/backend/utils/adt/genfile.c
index d34182a7b0..8a5d3acc5b 100644
--- a/src/backend/utils/adt/genfile.c
+++ b/src/backend/utils/adt/genfile.c
@@ -106,11 +106,14 @@ read_binary_file(const char *filename, int64 seek_offset, int64 bytes_to_read,
 				 bool missing_ok)
 {
 	bytea	   *buf;
-	size_t		nbytes = 0;
 	FILE	   *file;
+	size_t		nbytes;
+
+    /* Read zero byte? */
+	Assert(bytes_to_read != 0);
 
 	/* clamp request size to what we can actually deliver */
-	if (bytes_to_read > (int64) (MaxAllocSize - VARHDRSZ))
+	if (bytes_to_read > ((int64) MaxAllocSize - VARHDRSZ))
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
 				 errmsg("requested length too large")));
@@ -126,72 +129,50 @@ read_binary_file(const char *filename, int64 seek_offset, int64 bytes_to_read,
 							filename)));
 	}
 
-	if (fseeko(file, (off_t) seek_offset,
-			   (seek_offset >= 0) ? SEEK_SET : SEEK_END) != 0)
-		ereport(ERROR,
-				(errcode_for_file_access(),
-				 errmsg("could not seek in file \"%s\": %m", filename)));
-
+    /* If passed explicit read size just do it */
 	if (bytes_to_read >= 0)
 	{
-		/* If passed explicit read size just do it */
-		buf = (bytea *) palloc((Size) bytes_to_read + VARHDRSZ);
+	    /* Virtual File? Can not be seekable. */
+	    Assert(seek_offset != 0);
 
-		nbytes = fread(VARDATA(buf), 1, (size_t) bytes_to_read, file);
+		/* Avoid syscall fseeko if seek_offset is zero */
+		if (seek_offset != 0 &&
+			fseeko(file, (off_t) seek_offset,
+			  	   (seek_offset > 0) ? SEEK_SET : SEEK_END) != 0)
+			ereport(ERROR,
+					(errcode_for_file_access(),
+					errmsg("could not seek in file \"%s\": %m", filename)));
+
+		buf = (bytea *) palloc((Size) bytes_to_read + VARHDRSZ);
+	    nbytes = fread(VARDATA(buf), 1, (size_t) bytes_to_read, file);
 	}
-	else
+    else
 	{
-		/* Negative read size, read rest of file */
 		StringInfoData sbuf;
+		size_t rbytes;
 
 		initStringInfo(&sbuf);
+
 		/* Leave room in the buffer for the varlena length word */
 		sbuf.len += VARHDRSZ;
 		Assert(sbuf.len < sbuf.maxlen);
 
-		while (!(feof(file) || ferror(file)))
-		{
-			size_t		rbytes;
-
-			/* Minimum amount to read at a time */
 #define MIN_READ_SIZE 4096
-
-			/*
-			 * If not at end of file, and sbuf.len is equal to
-			 * MaxAllocSize - 1, then either the file is too large, or
-			 * there is nothing left to read. Attempt to read one more
-			 * byte to see if the end of file has been reached. If not,
-			 * the file is too large; we'd rather give the error message
-			 * for that ourselves.
-			 */
-			if (sbuf.len == MaxAllocSize - 1)
-			{
-				char	rbuf[1];
-
-				if (fread(rbuf, 1, 1, file) != 0 || !feof(file))
-					ereport(ERROR,
-							(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
-							 errmsg("file length too large")));
-				else
-					break;
-			}
-
-			/* OK, ensure that we can read at least MIN_READ_SIZE */
-			enlargeStringInfo(&sbuf, MIN_READ_SIZE);
-
-			/*
-			 * stringinfo.c likes to allocate in powers of 2, so it's likely
-			 * that much more space is available than we asked for.  Use all
-			 * of it, rather than making more fread calls than necessary.
-			 */
-			rbytes = fread(sbuf.data + sbuf.len, 1,
-						   (size_t) (sbuf.maxlen - sbuf.len - 1), file);
+        nbytes = 0;
+        do {
+            enlargeStringInfo(&sbuf, MIN_READ_SIZE);
+		    rbytes = read(file, sbuf.data + sbuf.len, (size_t) (sbuf.maxlen - sbuf.len - 1));
 			sbuf.len += rbytes;
 			nbytes += rbytes;
-		}
+		} while(rbytes > 0 && sbuf.len < (int64) (MaxAllocSize - VARHDRSZ));
+
+	    if (sbuf.len > ((int64) MaxAllocSize - VARHDRSZ))
+			ereport(ERROR,
+					(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
+					 errmsg("file length too large")));
 
 		/* Now we can commandeer the stringinfo's buffer as the result */
-		buf = (bytea *) sbuf.data;
+		buf = (bytea *) sbuf.data;
 	}
 
 	if (ferror(file))
@@ -199,10 +180,10 @@ read_binary_file(const char *filename, int64 seek_offset, int64 bytes_to_read,
 				(errcode_for_file_access(),
 				 errmsg("could not read file \"%s\": %m", filename)));
 
-	SET_VARSIZE(buf, nbytes + VARHDRSZ);
-
 	FreeFile(file);
 
+	SET_VARSIZE(buf, nbytes + VARHDRSZ);
+
 	return buf;
 }