Skip to content

Commit ee42d8f

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 473194c commit ee42d8f

File tree

9 files changed

+109
-68
lines changed

9 files changed

+109
-68
lines changed

contrib/pg_archivecleanup/pg_archivecleanup.c

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

118118
if ((xldir = opendir(archiveLocation)) != NULL)
119119
{
120-
while ((xlde = readdir(xldir)) != NULL)
120+
while (errno = 0, (xlde = readdir(xldir)) != NULL)
121121
{
122122
strncpy(walfile, xlde->d_name, MAXPGPATH);
123123
TrimExtension(walfile, additional_ext);
@@ -175,7 +175,19 @@ CleanupPriorWALFiles(void)
175175
}
176176
}
177177
}
178-
closedir(xldir);
178+
179+
#ifdef WIN32
180+
/* Bug in old Mingw dirent.c; fixed in mingw-runtime-3.2, 2003-10-10 */
181+
if (GetLastError() == ERROR_NO_MORE_FILES)
182+
errno = 0;
183+
#endif
184+
185+
if (errno)
186+
fprintf(stderr, "%s: could not read archive location \"%s\": %s\n",
187+
progname, archiveLocation, strerror(errno));
188+
if (closedir(xldir))
189+
fprintf(stderr, "%s: could not close archive location \"%s\": %s\n",
190+
progname, archiveLocation, strerror(errno));
179191
}
180192
else
181193
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: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -258,10 +258,7 @@ load_directory(const char *dirname, char ***namelist)
258258
}
259259

260260
#ifdef WIN32
261-
/*
262-
* This fix is in mingw cvs (runtime/mingwex/dirent.c rev 1.4), but not in
263-
* released version
264-
*/
261+
/* Bug in old Mingw dirent.c; fixed in mingw-runtime-3.2, 2003-10-10 */
265262
if (GetLastError() == ERROR_NO_MORE_FILES)
266263
errno = 0;
267264
#endif
@@ -270,7 +267,9 @@ load_directory(const char *dirname, char ***namelist)
270267
pg_log(PG_FATAL, "could not read directory \"%s\": %s\n",
271268
dirname, getErrorText(errno));
272269

273-
closedir(dirdesc);
270+
if (closedir(dirdesc))
271+
pg_log(PG_FATAL, "could not close directory \"%s\": %s\n",
272+
dirname, getErrorText(errno));
274273

275274
return count;
276275
}

src/backend/storage/file/fd.c

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

17481748
#ifdef WIN32
1749-
1750-
/*
1751-
* This fix is in mingw cvs (runtime/mingwex/dirent.c rev 1.4), but not in
1752-
* released version
1753-
*/
1749+
/* Bug in old Mingw dirent.c; fixed in mingw-runtime-3.2, 2003-10-10 */
17541750
if (GetLastError() == ERROR_NO_MORE_FILES)
17551751
errno = 0;
17561752
#endif

src/bin/pg_basebackup/pg_receivexlog.c

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ FindStreamingStart(XLogRecPtr currentpos, uint32 currenttimeline)
123123
disconnect_and_exit(1);
124124
}
125125

126-
while ((dirent = readdir(dir)) != NULL)
126+
while (errno = 0, (dirent = readdir(dir)) != NULL)
127127
{
128128
char fullpath[MAXPGPATH];
129129
struct stat statbuf;
@@ -197,7 +197,25 @@ FindStreamingStart(XLogRecPtr currentpos, uint32 currenttimeline)
197197
}
198198
}
199199

200-
closedir(dir);
200+
#ifdef WIN32
201+
/* Bug in old Mingw dirent.c; fixed in mingw-runtime-3.2, 2003-10-10 */
202+
if (GetLastError() == ERROR_NO_MORE_FILES)
203+
errno = 0;
204+
#endif
205+
206+
if (errno)
207+
{
208+
fprintf(stderr, _("%s: could not read directory \"%s\": %s\n"),
209+
progname, basedir, strerror(errno));
210+
disconnect_and_exit(1);
211+
}
212+
213+
if (closedir(dir))
214+
{
215+
fprintf(stderr, _("%s: could not close directory \"%s\": %s\n"),
216+
progname, basedir, strerror(errno));
217+
disconnect_and_exit(1);
218+
}
201219

202220
if (high_log > 0 || high_seg > 0)
203221
{

src/bin/pg_resetxlog/pg_resetxlog.c

Lines changed: 33 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -748,8 +748,7 @@ FindEndOfXLOG(void)
748748
exit(1);
749749
}
750750

751-
errno = 0;
752-
while ((xlde = readdir(xldir)) != NULL)
751+
while (errno = 0, (xlde = readdir(xldir)) != NULL)
753752
{
754753
if (strlen(xlde->d_name) == 24 &&
755754
strspn(xlde->d_name, "0123456789ABCDEF") == 24)
@@ -773,25 +772,27 @@ FindEndOfXLOG(void)
773772
newXlogSeg = seg;
774773
}
775774
}
776-
errno = 0;
777775
}
778-
#ifdef WIN32
779776

780-
/*
781-
* This fix is in mingw cvs (runtime/mingwex/dirent.c rev 1.4), but not in
782-
* released version
783-
*/
777+
#ifdef WIN32
778+
/* Bug in old Mingw dirent.c; fixed in mingw-runtime-3.2, 2003-10-10 */
784779
if (GetLastError() == ERROR_NO_MORE_FILES)
785780
errno = 0;
786781
#endif
787782

788783
if (errno)
789784
{
790-
fprintf(stderr, _("%s: could not read from directory \"%s\": %s\n"),
785+
fprintf(stderr, _("%s: could not read directory \"%s\": %s\n"),
786+
progname, XLOGDIR, strerror(errno));
787+
exit(1);
788+
}
789+
790+
if (closedir(xldir))
791+
{
792+
fprintf(stderr, _("%s: could not close directory \"%s\": %s\n"),
791793
progname, XLOGDIR, strerror(errno));
792794
exit(1);
793795
}
794-
closedir(xldir);
795796

796797
/*
797798
* Finally, convert to new xlog seg size, and advance by one to ensure we
@@ -823,8 +824,7 @@ KillExistingXLOG(void)
823824
exit(1);
824825
}
825826

826-
errno = 0;
827-
while ((xlde = readdir(xldir)) != NULL)
827+
while (errno = 0, (xlde = readdir(xldir)) != NULL)
828828
{
829829
if (strlen(xlde->d_name) == 24 &&
830830
strspn(xlde->d_name, "0123456789ABCDEF") == 24)
@@ -837,25 +837,27 @@ KillExistingXLOG(void)
837837
exit(1);
838838
}
839839
}
840-
errno = 0;
841840
}
842-
#ifdef WIN32
843841

844-
/*
845-
* This fix is in mingw cvs (runtime/mingwex/dirent.c rev 1.4), but not in
846-
* released version
847-
*/
842+
#ifdef WIN32
843+
/* Bug in old Mingw dirent.c; fixed in mingw-runtime-3.2, 2003-10-10 */
848844
if (GetLastError() == ERROR_NO_MORE_FILES)
849845
errno = 0;
850846
#endif
851847

852848
if (errno)
853849
{
854-
fprintf(stderr, _("%s: could not read from directory \"%s\": %s\n"),
850+
fprintf(stderr, _("%s: could not read directory \"%s\": %s\n"),
851+
progname, XLOGDIR, strerror(errno));
852+
exit(1);
853+
}
854+
855+
if (closedir(xldir))
856+
{
857+
fprintf(stderr, _("%s: could not close directory \"%s\": %s\n"),
855858
progname, XLOGDIR, strerror(errno));
856859
exit(1);
857860
}
858-
closedir(xldir);
859861
}
860862

861863

@@ -879,8 +881,7 @@ KillExistingArchiveStatus(void)
879881
exit(1);
880882
}
881883

882-
errno = 0;
883-
while ((xlde = readdir(xldir)) != NULL)
884+
while (errno = 0, (xlde = readdir(xldir)) != NULL)
884885
{
885886
if (strspn(xlde->d_name, "0123456789ABCDEF") == 24 &&
886887
(strcmp(xlde->d_name + 24, ".ready") == 0 ||
@@ -894,25 +895,27 @@ KillExistingArchiveStatus(void)
894895
exit(1);
895896
}
896897
}
897-
errno = 0;
898898
}
899-
#ifdef WIN32
900899

901-
/*
902-
* This fix is in mingw cvs (runtime/mingwex/dirent.c rev 1.4), but not in
903-
* released version
904-
*/
900+
#ifdef WIN32
901+
/* Bug in old Mingw dirent.c; fixed in mingw-runtime-3.2, 2003-10-10 */
905902
if (GetLastError() == ERROR_NO_MORE_FILES)
906903
errno = 0;
907904
#endif
908905

909906
if (errno)
910907
{
911-
fprintf(stderr, _("%s: could not read from directory \"%s\": %s\n"),
908+
fprintf(stderr, _("%s: could not read directory \"%s\": %s\n"),
909+
progname, ARCHSTATDIR, strerror(errno));
910+
exit(1);
911+
}
912+
913+
if (closedir(xldir))
914+
{
915+
fprintf(stderr, _("%s: could not close directory \"%s\": %s\n"),
912916
progname, ARCHSTATDIR, strerror(errno));
913917
exit(1);
914918
}
915-
closedir(xldir);
916919
}
917920

918921

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
@@ -456,8 +456,7 @@ pgfnames(const char *path)
456456

457457
filenames = (char **) palloc(fnsize * sizeof(char *));
458458

459-
errno = 0;
460-
while ((file = readdir(dir)) != NULL)
459+
while (errno = 0, (file = readdir(dir)) != NULL)
461460
{
462461
if (strcmp(file->d_name, ".") != 0 && strcmp(file->d_name, "..") != 0)
463462
{
@@ -469,17 +468,14 @@ pgfnames(const char *path)
469468
}
470469
filenames[numnames++] = pstrdup(file->d_name);
471470
}
472-
errno = 0;
473471
}
474-
#ifdef WIN32
475472

476-
/*
477-
* This fix is in mingw cvs (runtime/mingwex/dirent.c rev 1.4), but not in
478-
* released version
479-
*/
473+
#ifdef WIN32
474+
/* Bug in old Mingw dirent.c; fixed in mingw-runtime-3.2, 2003-10-10 */
480475
if (GetLastError() == ERROR_NO_MORE_FILES)
481476
errno = 0;
482477
#endif
478+
483479
if (errno)
484480
{
485481
#ifndef FRONTEND
@@ -492,7 +488,15 @@ pgfnames(const char *path)
492488

493489
filenames[numnames] = NULL;
494490

495-
closedir(dir);
491+
if (closedir(dir))
492+
{
493+
#ifndef FRONTEND
494+
elog(WARNING, "could not close directory \"%s\": %m", path);
495+
#else
496+
fprintf(stderr, _("could not close directory \"%s\": %s\n"),
497+
path, strerror(errno));
498+
#endif
499+
}
496500

497501
return filenames;
498502
}

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)