diff --git a/src/port/win32stat.c b/src/port/win32stat.c index ce8d87093d..e6553e4030 100644 --- a/src/port/win32stat.c +++ b/src/port/win32stat.c @@ -199,23 +199,33 @@ _pglstat64(const char *name, struct stat *buf) int _pgstat64(const char *name, struct stat *buf) { + int loops = 0; int ret; + char curr[MAXPGPATH]; ret = _pglstat64(name, buf); + strlcpy(curr, name, MAXPGPATH); + /* Do we need to follow a symlink (junction point)? */ - if (ret == 0 && S_ISLNK(buf->st_mode)) + while (ret == 0 && S_ISLNK(buf->st_mode)) { char next[MAXPGPATH]; ssize_t size; + if (++loops > 8) + { + errno = ELOOP; + return -1; + } + /* * _pglstat64() already called readlink() once to be able to fill in * st_size, and now we need to do it again to get the path to follow. * That could be optimized, but stat() on symlinks is probably rare * and this way is simple. */ - size = readlink(name, next, sizeof(next)); + size = readlink(curr, next, sizeof(next)); if (size < 0) { if (errno == EACCES && @@ -234,17 +244,7 @@ _pgstat64(const char *name, struct stat *buf) next[size] = 0; ret = _pglstat64(next, buf); - if (ret == 0 && S_ISLNK(buf->st_mode)) - { - /* - * We're only prepared to go one hop, because we only expect to - * deal with the simple cases that we create. The error for too - * many symlinks is supposed to be ELOOP, but Windows hasn't got - * it. - */ - errno = EIO; - return -1; - } + strcpy(curr, next); } return ret;