aboutsummaryrefslogtreecommitdiff
path: root/src/common/file_utils.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/common/file_utils.c')
-rw-r--r--src/common/file_utils.c109
1 files changed, 91 insertions, 18 deletions
diff --git a/src/common/file_utils.c b/src/common/file_utils.c
index a2faafdf13a..12474730905 100644
--- a/src/common/file_utils.c
+++ b/src/common/file_utils.c
@@ -14,10 +14,10 @@
*/
#ifndef FRONTEND
-#error "This file is not expected to be compiled for backend code"
-#endif
-
+#include "postgres.h"
+#else
#include "postgres_fe.h"
+#endif
#include <dirent.h>
#include <fcntl.h>
@@ -25,8 +25,11 @@
#include <unistd.h>
#include "common/file_utils.h"
+#ifdef FRONTEND
#include "common/logging.h"
+#endif
+#ifdef FRONTEND
/* Define PG_FLUSH_DATA_WORKS if we have an implementation for pg_flush_data */
#if defined(HAVE_SYNC_FILE_RANGE)
@@ -167,8 +170,6 @@ walkdir(const char *path,
while (errno = 0, (de = readdir(dir)) != NULL)
{
char subpath[MAXPGPATH * 2];
- struct stat fst;
- int sret;
if (strcmp(de->d_name, ".") == 0 ||
strcmp(de->d_name, "..") == 0)
@@ -176,21 +177,23 @@ walkdir(const char *path,
snprintf(subpath, sizeof(subpath), "%s/%s", path, de->d_name);
- if (process_symlinks)
- sret = stat(subpath, &fst);
- else
- sret = lstat(subpath, &fst);
-
- if (sret < 0)
+ switch (get_dirent_type(subpath, de, process_symlinks, PG_LOG_ERROR))
{
- pg_log_error("could not stat file \"%s\": %m", subpath);
- continue;
+ case PGFILETYPE_REG:
+ (*action) (subpath, false);
+ break;
+ case PGFILETYPE_DIR:
+ walkdir(subpath, action, false);
+ break;
+ default:
+
+ /*
+ * Errors are already reported directly by get_dirent_type(),
+ * and any remaining symlinks and unknown file types are
+ * ignored.
+ */
+ break;
}
-
- if (S_ISREG(fst.st_mode))
- (*action) (subpath, false);
- else if (S_ISDIR(fst.st_mode))
- walkdir(subpath, action, false);
}
if (errno)
@@ -394,3 +397,73 @@ durable_rename(const char *oldfile, const char *newfile)
return 0;
}
+
+#endif /* FRONTEND */
+
+/*
+ * Return the type of a directory entry.
+ *
+ * In frontend code, elevel should be a level from logging.h; in backend code
+ * it should be a level from elog.h.
+ */
+PGFileType
+get_dirent_type(const char *path,
+ const struct dirent *de,
+ bool look_through_symlinks,
+ int elevel)
+{
+ PGFileType result;
+
+ /*
+ * Some systems tell us the type directly in the dirent struct, but that's
+ * a BSD and Linux extension not required by POSIX. Even when the
+ * interface is present, sometimes the type is unknown, depending on the
+ * filesystem.
+ */
+#if defined(DT_REG) && defined(DT_DIR) && defined(DT_LNK)
+ if (de->d_type == DT_REG)
+ result = PGFILETYPE_REG;
+ else if (de->d_type == DT_DIR)
+ result = PGFILETYPE_DIR;
+ else if (de->d_type == DT_LNK && !look_through_symlinks)
+ result = PGFILETYPE_LNK;
+ else
+ result = PGFILETYPE_UNKNOWN;
+#else
+ result = PGFILETYPE_UNKNOWN;
+#endif
+
+ if (result == PGFILETYPE_UNKNOWN)
+ {
+ struct stat fst;
+ int sret;
+
+
+ if (look_through_symlinks)
+ sret = stat(path, &fst);
+ else
+ sret = lstat(path, &fst);
+
+ if (sret < 0)
+ {
+ result = PGFILETYPE_ERROR;
+#ifdef FRONTEND
+ pg_log_generic(elevel, "could not stat file \"%s\": %m", path);
+#else
+ ereport(elevel,
+ (errcode_for_file_access(),
+ errmsg("could not stat file \"%s\": %m", path)));
+#endif
+ }
+ else if (S_ISREG(fst.st_mode))
+ result = PGFILETYPE_REG;
+ else if (S_ISDIR(fst.st_mode))
+ result = PGFILETYPE_DIR;
+#ifdef S_ISLNK
+ else if (S_ISLNK(fst.st_mode))
+ result = PGFILETYPE_LNK;
+#endif
+ }
+
+ return result;
+}