|
14 | 14 | */
|
15 | 15 |
|
16 | 16 | #ifndef FRONTEND
|
17 |
| -#error "This file is not expected to be compiled for backend code" |
18 |
| -#endif |
19 |
| - |
| 17 | +#include "postgres.h" |
| 18 | +#else |
20 | 19 | #include "postgres_fe.h"
|
| 20 | +#endif |
21 | 21 |
|
22 | 22 | #include <dirent.h>
|
23 | 23 | #include <fcntl.h>
|
24 | 24 | #include <sys/stat.h>
|
25 | 25 | #include <unistd.h>
|
26 | 26 |
|
27 | 27 | #include "common/file_utils.h"
|
| 28 | +#ifdef FRONTEND |
28 | 29 | #include "common/logging.h"
|
| 30 | +#endif |
29 | 31 |
|
| 32 | +#ifdef FRONTEND |
30 | 33 |
|
31 | 34 | /* Define PG_FLUSH_DATA_WORKS if we have an implementation for pg_flush_data */
|
32 | 35 | #if defined(HAVE_SYNC_FILE_RANGE)
|
@@ -167,30 +170,30 @@ walkdir(const char *path,
|
167 | 170 | while (errno = 0, (de = readdir(dir)) != NULL)
|
168 | 171 | {
|
169 | 172 | char subpath[MAXPGPATH * 2];
|
170 |
| - struct stat fst; |
171 |
| - int sret; |
172 | 173 |
|
173 | 174 | if (strcmp(de->d_name, ".") == 0 ||
|
174 | 175 | strcmp(de->d_name, "..") == 0)
|
175 | 176 | continue;
|
176 | 177 |
|
177 | 178 | snprintf(subpath, sizeof(subpath), "%s/%s", path, de->d_name);
|
178 | 179 |
|
179 |
| - if (process_symlinks) |
180 |
| - sret = stat(subpath, &fst); |
181 |
| - else |
182 |
| - sret = lstat(subpath, &fst); |
183 |
| - |
184 |
| - if (sret < 0) |
| 180 | + switch (get_dirent_type(subpath, de, process_symlinks, PG_LOG_ERROR)) |
185 | 181 | {
|
186 |
| - pg_log_error("could not stat file \"%s\": %m", subpath); |
187 |
| - continue; |
| 182 | + case PGFILETYPE_REG: |
| 183 | + (*action) (subpath, false); |
| 184 | + break; |
| 185 | + case PGFILETYPE_DIR: |
| 186 | + walkdir(subpath, action, false); |
| 187 | + break; |
| 188 | + default: |
| 189 | + |
| 190 | + /* |
| 191 | + * Errors are already reported directly by get_dirent_type(), |
| 192 | + * and any remaining symlinks and unknown file types are |
| 193 | + * ignored. |
| 194 | + */ |
| 195 | + break; |
188 | 196 | }
|
189 |
| - |
190 |
| - if (S_ISREG(fst.st_mode)) |
191 |
| - (*action) (subpath, false); |
192 |
| - else if (S_ISDIR(fst.st_mode)) |
193 |
| - walkdir(subpath, action, false); |
194 | 197 | }
|
195 | 198 |
|
196 | 199 | if (errno)
|
@@ -394,3 +397,73 @@ durable_rename(const char *oldfile, const char *newfile)
|
394 | 397 |
|
395 | 398 | return 0;
|
396 | 399 | }
|
| 400 | + |
| 401 | +#endif /* FRONTEND */ |
| 402 | + |
| 403 | +/* |
| 404 | + * Return the type of a directory entry. |
| 405 | + * |
| 406 | + * In frontend code, elevel should be a level from logging.h; in backend code |
| 407 | + * it should be a level from elog.h. |
| 408 | + */ |
| 409 | +PGFileType |
| 410 | +get_dirent_type(const char *path, |
| 411 | + const struct dirent *de, |
| 412 | + bool look_through_symlinks, |
| 413 | + int elevel) |
| 414 | +{ |
| 415 | + PGFileType result; |
| 416 | + |
| 417 | + /* |
| 418 | + * Some systems tell us the type directly in the dirent struct, but that's |
| 419 | + * a BSD and Linux extension not required by POSIX. Even when the |
| 420 | + * interface is present, sometimes the type is unknown, depending on the |
| 421 | + * filesystem. |
| 422 | + */ |
| 423 | +#if defined(DT_REG) && defined(DT_DIR) && defined(DT_LNK) |
| 424 | + if (de->d_type == DT_REG) |
| 425 | + result = PGFILETYPE_REG; |
| 426 | + else if (de->d_type == DT_DIR) |
| 427 | + result = PGFILETYPE_DIR; |
| 428 | + else if (de->d_type == DT_LNK && !look_through_symlinks) |
| 429 | + result = PGFILETYPE_LNK; |
| 430 | + else |
| 431 | + result = PGFILETYPE_UNKNOWN; |
| 432 | +#else |
| 433 | + result = PGFILETYPE_UNKNOWN; |
| 434 | +#endif |
| 435 | + |
| 436 | + if (result == PGFILETYPE_UNKNOWN) |
| 437 | + { |
| 438 | + struct stat fst; |
| 439 | + int sret; |
| 440 | + |
| 441 | + |
| 442 | + if (look_through_symlinks) |
| 443 | + sret = stat(path, &fst); |
| 444 | + else |
| 445 | + sret = lstat(path, &fst); |
| 446 | + |
| 447 | + if (sret < 0) |
| 448 | + { |
| 449 | + result = PGFILETYPE_ERROR; |
| 450 | +#ifdef FRONTEND |
| 451 | + pg_log_generic(elevel, "could not stat file \"%s\": %m", path); |
| 452 | +#else |
| 453 | + ereport(elevel, |
| 454 | + (errcode_for_file_access(), |
| 455 | + errmsg("could not stat file \"%s\": %m", path))); |
| 456 | +#endif |
| 457 | + } |
| 458 | + else if (S_ISREG(fst.st_mode)) |
| 459 | + result = PGFILETYPE_REG; |
| 460 | + else if (S_ISDIR(fst.st_mode)) |
| 461 | + result = PGFILETYPE_DIR; |
| 462 | +#ifdef S_ISLNK |
| 463 | + else if (S_ISLNK(fst.st_mode)) |
| 464 | + result = PGFILETYPE_LNK; |
| 465 | +#endif |
| 466 | + } |
| 467 | + |
| 468 | + return result; |
| 469 | +} |
0 commit comments