aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backend/access/transam/twophase.c2
-rw-r--r--src/backend/access/transam/xlog.c8
-rw-r--r--src/backend/storage/file/fd.c32
-rw-r--r--src/include/storage/fd.h2
4 files changed, 35 insertions, 9 deletions
diff --git a/src/backend/access/transam/twophase.c b/src/backend/access/transam/twophase.c
index ae832917ce2..2b3032bde98 100644
--- a/src/backend/access/transam/twophase.c
+++ b/src/backend/access/transam/twophase.c
@@ -1735,8 +1735,8 @@ restoreTwoPhaseData(void)
DIR *cldir;
struct dirent *clde;
- cldir = AllocateDir(TWOPHASE_DIR);
LWLockAcquire(TwoPhaseStateLock, LW_EXCLUSIVE);
+ cldir = AllocateDir(TWOPHASE_DIR);
while ((clde = ReadDir(cldir, TWOPHASE_DIR)) != NULL)
{
if (strlen(clde->d_name) == 8 &&
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index a63a8853ee3..615ce5c7fd0 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -3760,10 +3760,16 @@ PreallocXlogFiles(XLogRecPtr endptr)
* existed while the server has been running, as this function always
* succeeds if no WAL segments have been removed since startup.
* 'tli' is only used in the error message.
+ *
+ * Note: this function guarantees to keep errno unchanged on return.
+ * This supports callers that use this to possibly deliver a better
+ * error message about a missing file, while still being able to throw
+ * a normal file-access error afterwards, if this does return.
*/
void
CheckXLogRemoved(XLogSegNo segno, TimeLineID tli)
{
+ int save_errno = errno;
XLogSegNo lastRemovedSegNo;
SpinLockAcquire(&XLogCtl->info_lck);
@@ -3775,11 +3781,13 @@ CheckXLogRemoved(XLogSegNo segno, TimeLineID tli)
char filename[MAXFNAMELEN];
XLogFileName(filename, tli, segno);
+ errno = save_errno;
ereport(ERROR,
(errcode_for_file_access(),
errmsg("requested WAL segment %s has already been removed",
filename)));
}
+ errno = save_errno;
}
/*
diff --git a/src/backend/storage/file/fd.c b/src/backend/storage/file/fd.c
index 594251da422..3172092a914 100644
--- a/src/backend/storage/file/fd.c
+++ b/src/backend/storage/file/fd.c
@@ -304,7 +304,6 @@ static int FileAccess(File file);
static File OpenTemporaryFileInTablespace(Oid tblspcOid, bool rejectError);
static bool reserveAllocatedDesc(void);
static int FreeDesc(AllocateDesc *desc);
-static struct dirent *ReadDirExtended(DIR *dir, const char *dirname, int elevel);
static void AtProcExit_Files(int code, Datum arg);
static void CleanupTempFiles(bool isProcExit);
@@ -2335,6 +2334,10 @@ CloseTransientFile(int fd)
* necessary to open the directory, and with closing it after an elog.
* When done, call FreeDir rather than closedir.
*
+ * Returns NULL, with errno set, on failure. Note that failure detection
+ * is commonly left to the following call of ReadDir or ReadDirExtended;
+ * see the comments for ReadDir.
+ *
* Ideally this should be the *only* direct call of opendir() in the backend.
*/
DIR *
@@ -2397,8 +2400,8 @@ TryAgain:
* FreeDir(dir);
*
* since a NULL dir parameter is taken as indicating AllocateDir failed.
- * (Make sure errno hasn't been changed since AllocateDir if you use this
- * shortcut.)
+ * (Make sure errno isn't changed between AllocateDir and ReadDir if you
+ * use this shortcut.)
*
* The pathname passed to AllocateDir must be passed to this routine too,
* but it is only used for error reporting.
@@ -2410,10 +2413,15 @@ ReadDir(DIR *dir, const char *dirname)
}
/*
- * Alternate version that allows caller to specify the elevel for any
- * error report. If elevel < ERROR, returns NULL on any error.
+ * Alternate version of ReadDir that allows caller to specify the elevel
+ * for any error report (whether it's reporting an initial failure of
+ * AllocateDir or a subsequent directory read failure).
+ *
+ * If elevel < ERROR, returns NULL after any error. With the normal coding
+ * pattern, this will result in falling out of the loop immediately as
+ * though the directory contained no (more) entries.
*/
-static struct dirent *
+struct dirent *
ReadDirExtended(DIR *dir, const char *dirname, int elevel)
{
struct dirent *dent;
@@ -2443,14 +2451,22 @@ ReadDirExtended(DIR *dir, const char *dirname, int elevel)
/*
* Close a directory opened with AllocateDir.
*
- * Note we do not check closedir's return value --- it is up to the caller
- * to handle close errors.
+ * Returns closedir's return value (with errno set if it's not 0).
+ * Note we do not check the return value --- it is up to the caller
+ * to handle close errors if wanted.
+ *
+ * Does nothing if dir == NULL; we assume that directory open failure was
+ * already reported if desired.
*/
int
FreeDir(DIR *dir)
{
int i;
+ /* Nothing to do if AllocateDir failed */
+ if (dir == NULL)
+ return 0;
+
DO_DB(elog(LOG, "FreeDir: Allocated %d", numAllocatedDescs));
/* Remove dir from list of allocated dirs, if it's present */
diff --git a/src/include/storage/fd.h b/src/include/storage/fd.h
index faef39e78d3..87265400776 100644
--- a/src/include/storage/fd.h
+++ b/src/include/storage/fd.h
@@ -91,6 +91,8 @@ extern int ClosePipeStream(FILE *file);
/* Operations to allow use of the <dirent.h> library routines */
extern DIR *AllocateDir(const char *dirname);
extern struct dirent *ReadDir(DIR *dir, const char *dirname);
+extern struct dirent *ReadDirExtended(DIR *dir, const char *dirname,
+ int elevel);
extern int FreeDir(DIR *dir);
/* Operations to allow use of a plain kernel FD, with automatic cleanup */