Skip to content

Commit d73cc58

Browse files
committed
Properly check for readdir/closedir() failures
Clear errno before calling readdir() and handle old MinGW errno bug while adding full test coverage for readdir/closedir failures. Backpatch through 8.4.
1 parent 697becf commit d73cc58

File tree

8 files changed

+97
-63
lines changed

8 files changed

+97
-63
lines changed

contrib/pg_archivecleanup/pg_archivecleanup.c

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ CleanupPriorWALFiles(void)
9898

9999
if ((xldir = opendir(archiveLocation)) != NULL)
100100
{
101-
while ((xlde = readdir(xldir)) != NULL)
101+
while (errno = 0, (xlde = readdir(xldir)) != NULL)
102102
{
103103
/*
104104
* We ignore the timeline part of the XLOG segment identifiers in
@@ -132,7 +132,19 @@ CleanupPriorWALFiles(void)
132132
}
133133
}
134134
}
135-
closedir(xldir);
135+
136+
#ifdef WIN32
137+
/* Bug in old Mingw dirent.c; fixed in mingw-runtime-3.2, 2003-10-10 */
138+
if (GetLastError() == ERROR_NO_MORE_FILES)
139+
errno = 0;
140+
#endif
141+
142+
if (errno)
143+
fprintf(stderr, "%s: could not read archive location \"%s\": %s\n",
144+
progname, archiveLocation, strerror(errno));
145+
if (closedir(xldir))
146+
fprintf(stderr, "%s: could not close archive location \"%s\": %s\n",
147+
progname, archiveLocation, strerror(errno));
136148
}
137149
else
138150
fprintf(stderr, "%s: could not open archive location \"%s\": %s\n",

contrib/pg_standby/pg_standby.c

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -256,7 +256,7 @@ CustomizableCleanupPriorWALFiles(void)
256256
*/
257257
if ((xldir = opendir(archiveLocation)) != NULL)
258258
{
259-
while ((xlde = readdir(xldir)) != NULL)
259+
while (errno = 0, (xlde = readdir(xldir)) != NULL)
260260
{
261261
/*
262262
* We ignore the timeline part of the XLOG segment identifiers
@@ -294,14 +294,27 @@ CustomizableCleanupPriorWALFiles(void)
294294
}
295295
}
296296
}
297+
298+
#ifdef WIN32
299+
/* Bug in old Mingw dirent.c; fixed in mingw-runtime-3.2, 2003-10-10 */
300+
if (GetLastError() == ERROR_NO_MORE_FILES)
301+
errno = 0;
302+
#endif
303+
304+
if (errno)
305+
fprintf(stderr, "%s: could not read archive location \"%s\": %s\n",
306+
progname, archiveLocation, strerror(errno));
297307
if (debug)
298308
fprintf(stderr, "\n");
299309
}
300310
else
301311
fprintf(stderr, "%s: could not open archive location \"%s\": %s\n",
302312
progname, archiveLocation, strerror(errno));
303313

304-
closedir(xldir);
314+
if (closedir(xldir))
315+
fprintf(stderr, "%s: could not close archive location \"%s\": %s\n",
316+
progname, archiveLocation, strerror(errno));
317+
305318
fflush(stderr);
306319
}
307320
}

contrib/pg_upgrade/file.c

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -291,7 +291,7 @@ pg_scandir_internal(const char *dirname,
291291

292292
*namelist = NULL;
293293

294-
while ((direntry = readdir(dirdesc)) != NULL)
294+
while (errno = 0, (direntry = readdir(dirdesc)) != NULL)
295295
{
296296
/* Invoke the selector function to see if the direntry matches */
297297
if (!selector || (*selector) (direntry))
@@ -324,7 +324,17 @@ pg_scandir_internal(const char *dirname,
324324
}
325325
}
326326

327-
closedir(dirdesc);
327+
#ifdef WIN32
328+
/* Bug in old Mingw dirent.c; fixed in mingw-runtime-3.2, 2003-10-10 */
329+
if (GetLastError() == ERROR_NO_MORE_FILES)
330+
errno = 0;
331+
#endif
332+
333+
if (errno)
334+
pg_log(PG_FATAL, "could not read directory \"%s\": %s\n", dirname, getErrorText(errno));
335+
336+
if (closedir(dirdesc))
337+
pg_log(PG_FATAL, "could not close directory \"%s\": %s\n", dirname, getErrorText(errno));
328338

329339
return count;
330340
}

src/backend/storage/file/fd.c

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1687,11 +1687,7 @@ ReadDir(DIR *dir, const char *dirname)
16871687
return dent;
16881688

16891689
#ifdef WIN32
1690-
1691-
/*
1692-
* This fix is in mingw cvs (runtime/mingwex/dirent.c rev 1.4), but not in
1693-
* released version
1694-
*/
1690+
/* Bug in old Mingw dirent.c; fixed in mingw-runtime-3.2, 2003-10-10 */
16951691
if (GetLastError() == ERROR_NO_MORE_FILES)
16961692
errno = 0;
16971693
#endif

src/bin/pg_resetxlog/pg_resetxlog.c

Lines changed: 33 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -742,8 +742,7 @@ FindEndOfXLOG(void)
742742
exit(1);
743743
}
744744

745-
errno = 0;
746-
while ((xlde = readdir(xldir)) != NULL)
745+
while (errno = 0, (xlde = readdir(xldir)) != NULL)
747746
{
748747
if (strlen(xlde->d_name) == 24 &&
749748
strspn(xlde->d_name, "0123456789ABCDEF") == 24)
@@ -767,25 +766,27 @@ FindEndOfXLOG(void)
767766
newXlogSeg = seg;
768767
}
769768
}
770-
errno = 0;
771769
}
772-
#ifdef WIN32
773770

774-
/*
775-
* This fix is in mingw cvs (runtime/mingwex/dirent.c rev 1.4), but not in
776-
* released version
777-
*/
771+
#ifdef WIN32
772+
/* Bug in old Mingw dirent.c; fixed in mingw-runtime-3.2, 2003-10-10 */
778773
if (GetLastError() == ERROR_NO_MORE_FILES)
779774
errno = 0;
780775
#endif
781776

782777
if (errno)
783778
{
784-
fprintf(stderr, _("%s: could not read from directory \"%s\": %s\n"),
779+
fprintf(stderr, _("%s: could not read directory \"%s\": %s\n"),
780+
progname, XLOGDIR, strerror(errno));
781+
exit(1);
782+
}
783+
784+
if (closedir(xldir))
785+
{
786+
fprintf(stderr, _("%s: could not close directory \"%s\": %s\n"),
785787
progname, XLOGDIR, strerror(errno));
786788
exit(1);
787789
}
788-
closedir(xldir);
789790

790791
/*
791792
* Finally, convert to new xlog seg size, and advance by one to ensure we
@@ -817,8 +818,7 @@ KillExistingXLOG(void)
817818
exit(1);
818819
}
819820

820-
errno = 0;
821-
while ((xlde = readdir(xldir)) != NULL)
821+
while (errno = 0, (xlde = readdir(xldir)) != NULL)
822822
{
823823
if (strlen(xlde->d_name) == 24 &&
824824
strspn(xlde->d_name, "0123456789ABCDEF") == 24)
@@ -831,25 +831,27 @@ KillExistingXLOG(void)
831831
exit(1);
832832
}
833833
}
834-
errno = 0;
835834
}
836-
#ifdef WIN32
837835

838-
/*
839-
* This fix is in mingw cvs (runtime/mingwex/dirent.c rev 1.4), but not in
840-
* released version
841-
*/
836+
#ifdef WIN32
837+
/* Bug in old Mingw dirent.c; fixed in mingw-runtime-3.2, 2003-10-10 */
842838
if (GetLastError() == ERROR_NO_MORE_FILES)
843839
errno = 0;
844840
#endif
845841

846842
if (errno)
847843
{
848-
fprintf(stderr, _("%s: could not read from directory \"%s\": %s\n"),
844+
fprintf(stderr, _("%s: could not read directory \"%s\": %s\n"),
845+
progname, XLOGDIR, strerror(errno));
846+
exit(1);
847+
}
848+
849+
if (closedir(xldir))
850+
{
851+
fprintf(stderr, _("%s: could not close directory \"%s\": %s\n"),
849852
progname, XLOGDIR, strerror(errno));
850853
exit(1);
851854
}
852-
closedir(xldir);
853855
}
854856

855857

@@ -873,8 +875,7 @@ KillExistingArchiveStatus(void)
873875
exit(1);
874876
}
875877

876-
errno = 0;
877-
while ((xlde = readdir(xldir)) != NULL)
878+
while (errno = 0, (xlde = readdir(xldir)) != NULL)
878879
{
879880
if (strspn(xlde->d_name, "0123456789ABCDEF") == 24 &&
880881
(strcmp(xlde->d_name + 24, ".ready") == 0 ||
@@ -888,25 +889,27 @@ KillExistingArchiveStatus(void)
888889
exit(1);
889890
}
890891
}
891-
errno = 0;
892892
}
893-
#ifdef WIN32
894893

895-
/*
896-
* This fix is in mingw cvs (runtime/mingwex/dirent.c rev 1.4), but not in
897-
* released version
898-
*/
894+
#ifdef WIN32
895+
/* Bug in old Mingw dirent.c; fixed in mingw-runtime-3.2, 2003-10-10 */
899896
if (GetLastError() == ERROR_NO_MORE_FILES)
900897
errno = 0;
901898
#endif
902899

903900
if (errno)
904901
{
905-
fprintf(stderr, _("%s: could not read from directory \"%s\": %s\n"),
902+
fprintf(stderr, _("%s: could not read directory \"%s\": %s\n"),
903+
progname, ARCHSTATDIR, strerror(errno));
904+
exit(1);
905+
}
906+
907+
if (closedir(xldir))
908+
{
909+
fprintf(stderr, _("%s: could not close directory \"%s\": %s\n"),
906910
progname, ARCHSTATDIR, strerror(errno));
907911
exit(1);
908912
}
909-
closedir(xldir);
910913
}
911914

912915

src/port/dirent.c

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -105,15 +105,19 @@ readdir(DIR *d)
105105
strcpy(d->ret.d_name, fd.cFileName); /* Both strings are MAX_PATH
106106
* long */
107107
d->ret.d_namlen = strlen(d->ret.d_name);
108+
108109
return &d->ret;
109110
}
110111

111112
int
112113
closedir(DIR *d)
113114
{
115+
int ret = 0;
116+
114117
if (d->handle != INVALID_HANDLE_VALUE)
115-
FindClose(d->handle);
118+
ret = !FindClose(d->handle);
116119
free(d->dirname);
117120
free(d);
118-
return 0;
121+
122+
return ret;
119123
}

src/port/dirmod.c

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -448,8 +448,7 @@ pgfnames(const char *path)
448448

449449
filenames = (char **) palloc(fnsize * sizeof(char *));
450450

451-
errno = 0;
452-
while ((file = readdir(dir)) != NULL)
451+
while (errno = 0, (file = readdir(dir)) != NULL)
453452
{
454453
if (strcmp(file->d_name, ".") != 0 && strcmp(file->d_name, "..") != 0)
455454
{
@@ -461,17 +460,14 @@ pgfnames(const char *path)
461460
}
462461
filenames[numnames++] = pstrdup(file->d_name);
463462
}
464-
errno = 0;
465463
}
466-
#ifdef WIN32
467464

468-
/*
469-
* This fix is in mingw cvs (runtime/mingwex/dirent.c rev 1.4), but not in
470-
* released version
471-
*/
465+
#ifdef WIN32
466+
/* Bug in old Mingw dirent.c; fixed in mingw-runtime-3.2, 2003-10-10 */
472467
if (GetLastError() == ERROR_NO_MORE_FILES)
473468
errno = 0;
474469
#endif
470+
475471
if (errno)
476472
{
477473
#ifndef FRONTEND
@@ -484,7 +480,15 @@ pgfnames(const char *path)
484480

485481
filenames[numnames] = NULL;
486482

487-
closedir(dir);
483+
if (closedir(dir))
484+
{
485+
#ifndef FRONTEND
486+
elog(WARNING, "could not close directory \"%s\": %m", path);
487+
#else
488+
fprintf(stderr, _("could not close directory \"%s\": %s\n"),
489+
path, strerror(errno));
490+
#endif
491+
}
488492

489493
return filenames;
490494
}

src/port/pgcheckdir.c

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -32,14 +32,12 @@ pg_check_dir(const char *dir)
3232
DIR *chkdir;
3333
struct dirent *file;
3434

35-
errno = 0;
36-
3735
chkdir = opendir(dir);
3836

3937
if (chkdir == NULL)
4038
return (errno == ENOENT) ? 0 : -1;
4139

42-
while ((file = readdir(chkdir)) != NULL)
40+
while (errno = 0, (file = readdir(chkdir)) != NULL)
4341
{
4442
if (strcmp(".", file->d_name) == 0 ||
4543
strcmp("..", file->d_name) == 0)
@@ -55,18 +53,12 @@ pg_check_dir(const char *dir)
5553
}
5654

5755
#ifdef WIN32
58-
59-
/*
60-
* This fix is in mingw cvs (runtime/mingwex/dirent.c rev 1.4), but not in
61-
* released version
62-
*/
56+
/* Bug in old Mingw dirent.c; fixed in mingw-runtime-3.2, 2003-10-10 */
6357
if (GetLastError() == ERROR_NO_MORE_FILES)
6458
errno = 0;
6559
#endif
6660

67-
closedir(chkdir);
68-
69-
if (errno != 0)
61+
if (errno || closedir(chkdir))
7062
result = -1; /* some kind of I/O error? */
7163

7264
return result;

0 commit comments

Comments
 (0)