diff options
Diffstat (limited to 'src/backend/storage/file/fd.c')
-rw-r--r-- | src/backend/storage/file/fd.c | 115 |
1 files changed, 115 insertions, 0 deletions
diff --git a/src/backend/storage/file/fd.c b/src/backend/storage/file/fd.c index f7967178c69..99dac841ffa 100644 --- a/src/backend/storage/file/fd.c +++ b/src/backend/storage/file/fd.c @@ -2439,3 +2439,118 @@ looks_like_temp_rel_name(const char *name) return false; return true; } + +/* + * Hint to the OS that it should get ready to fsync() this file. + * + * Adapted from pre_sync_fname in initdb.c + */ +void +pre_sync_fname(char *fname, bool isdir) +{ + int fd; + + fd = open(fname, O_RDONLY | PG_BINARY); + + /* + * Some OSs don't allow us to open directories at all (Windows returns + * EACCES) + */ + if (fd < 0 && isdir && (errno == EISDIR || errno == EACCES)) + return; + + if (fd < 0) + ereport(FATAL, + (errmsg("could not open file \"%s\" before fsync", + fname))); + + pg_flush_data(fd, 0, 0); + + close(fd); +} + +/* + * walkdir: recursively walk a directory, applying the action to each + * regular file and directory (including the named directory itself) + * and following symbolic links. + * + * NB: There is another version of walkdir in initdb.c, but that version + * behaves differently with respect to symbolic links. Caveat emptor! + */ +void +walkdir(char *path, void (*action) (char *fname, bool isdir)) +{ + DIR *dir; + struct dirent *de; + + dir = AllocateDir(path); + while ((de = ReadDir(dir, path)) != NULL) + { + char subpath[MAXPGPATH]; + struct stat fst; + + CHECK_FOR_INTERRUPTS(); + + if (strcmp(de->d_name, ".") == 0 || + strcmp(de->d_name, "..") == 0) + continue; + + snprintf(subpath, MAXPGPATH, "%s/%s", path, de->d_name); + + if (lstat(subpath, &fst) < 0) + ereport(ERROR, + (errcode_for_file_access(), + errmsg("could not stat file \"%s\": %m", subpath))); + + if (S_ISREG(fst.st_mode)) + (*action) (subpath, false); + else if (S_ISDIR(fst.st_mode)) + walkdir(subpath, action); +#ifndef WIN32 + else if (S_ISLNK(fst.st_mode)) +#else + else if (pg_win32_is_junction(subpath)) +#endif + { +#if defined(HAVE_READLINK) || defined(WIN32) + char linkpath[MAXPGPATH]; + int len; + struct stat lst; + + len = readlink(subpath, linkpath, sizeof(linkpath)-1); + if (len < 0) + ereport(ERROR, + (errcode_for_file_access(), + errmsg("could not read symbolic link \"%s\": %m", + subpath))); + + if (len >= sizeof(linkpath)-1) + ereport(ERROR, + (errmsg("symbolic link \"%s\" target is too long", + subpath))); + + linkpath[len] = '\0'; + + if (lstat(linkpath, &lst) == 0) + { + if (S_ISREG(lst.st_mode)) + (*action) (linkpath, false); + else if (S_ISDIR(lst.st_mode)) + walkdir(subpath, action); + } + else if (errno != ENOENT) + ereport(ERROR, + (errcode_for_file_access(), + errmsg("could not stat file \"%s\": %m", linkpath))); +#else + ereport(WARNING, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("this platform does not support symbolic links; ignoring \"%s\"", + subpath))); +#endif + } + } + FreeDir(dir); + + (*action) (path, true); +} |