]> granicus.if.org Git - postgresql/commitdiff
Properly check for readdir/closedir() failures
authorBruce Momjian <bruce@momjian.us>
Fri, 21 Mar 2014 17:45:11 +0000 (13:45 -0400)
committerBruce Momjian <bruce@momjian.us>
Fri, 21 Mar 2014 17:45:11 +0000 (13:45 -0400)
Clear errno before calling readdir() and handle old MinGW errno bug
while adding full test coverage for readdir/closedir failures.

Backpatch through 8.4.

contrib/pg_archivecleanup/pg_archivecleanup.c
contrib/pg_standby/pg_standby.c
src/backend/storage/file/fd.c
src/bin/initdb/initdb.c
src/bin/pg_basebackup/pg_receivexlog.c
src/bin/pg_dump/pg_backup_directory.c
src/bin/pg_resetxlog/pg_resetxlog.c
src/port/dirent.c
src/port/dirmod.c
src/port/pgcheckdir.c

index f12331a62ecaef4b8966aa1d24e0847820dece1d..f2bc0aaf9785e8d0d2db1a6fed1bbd2c8c0ef45f 100644 (file)
@@ -117,7 +117,7 @@ CleanupPriorWALFiles(void)
 
        if ((xldir = opendir(archiveLocation)) != NULL)
        {
-               while ((xlde = readdir(xldir)) != NULL)
+               while (errno = 0, (xlde = readdir(xldir)) != NULL)
                {
                        strncpy(walfile, xlde->d_name, MAXPGPATH);
                        TrimExtension(walfile, additional_ext);
@@ -175,7 +175,19 @@ CleanupPriorWALFiles(void)
                                }
                        }
                }
-               closedir(xldir);
+
+#ifdef WIN32
+               /* Bug in old Mingw dirent.c;  fixed in mingw-runtime-3.2, 2003-10-10 */
+               if (GetLastError() == ERROR_NO_MORE_FILES)
+                       errno = 0;
+#endif
+
+               if (errno)
+                       fprintf(stderr, "%s: could not read archive location \"%s\": %s\n",
+                                       progname, archiveLocation, strerror(errno));
+               if (closedir(xldir))
+                       fprintf(stderr, "%s: could not close archive location \"%s\": %s\n",
+                                       progname, archiveLocation, strerror(errno));
        }
        else
                fprintf(stderr, "%s: could not open archive location \"%s\": %s\n",
index b3fbd6ee37004a2dea88dea5a1c68886cea529e8..87255b9ee83583948f134a0ea8db3673405375f6 100644 (file)
@@ -256,7 +256,7 @@ CustomizableCleanupPriorWALFiles(void)
                 */
                if ((xldir = opendir(archiveLocation)) != NULL)
                {
-                       while ((xlde = readdir(xldir)) != NULL)
+                       while (errno = 0, (xlde = readdir(xldir)) != NULL)
                        {
                                /*
                                 * We ignore the timeline part of the XLOG segment identifiers
@@ -294,6 +294,16 @@ CustomizableCleanupPriorWALFiles(void)
                                        }
                                }
                        }
+
+#ifdef WIN32
+                       /* Bug in old Mingw dirent.c;  fixed in mingw-runtime-3.2, 2003-10-10 */
+                       if (GetLastError() == ERROR_NO_MORE_FILES)
+                               errno = 0;
+#endif
+
+                       if (errno)
+                               fprintf(stderr, "%s: could not read archive location \"%s\": %s\n",
+                                               progname, archiveLocation, strerror(errno));
                        if (debug)
                                fprintf(stderr, "\n");
                }
@@ -301,7 +311,10 @@ CustomizableCleanupPriorWALFiles(void)
                        fprintf(stderr, "%s: could not open archive location \"%s\": %s\n",
                                        progname, archiveLocation, strerror(errno));
 
-               closedir(xldir);
+               if (closedir(xldir))
+                       fprintf(stderr, "%s: could not close archive location \"%s\": %s\n",
+                                       progname, archiveLocation, strerror(errno));
+
                fflush(stderr);
        }
 }
index 436b901c20d60f52129d52e4358fc04656309ea7..a2907957ae47d8aa9bef8add8f95378c6f3b4f6d 100644 (file)
@@ -1901,11 +1901,7 @@ ReadDir(DIR *dir, const char *dirname)
                return dent;
 
 #ifdef WIN32
-
-       /*
-        * This fix is in mingw cvs (runtime/mingwex/dirent.c rev 1.4), but not in
-        * released version
-        */
+       /* Bug in old Mingw dirent.c;  fixed in mingw-runtime-3.2, 2003-10-10 */
        if (GetLastError() == ERROR_NO_MORE_FILES)
                errno = 0;
 #endif
index 5fc7291ff69be0844f2c78978d427cdf94c69c0e..c440f8f3a18e5548b3fe9b19c6dfa88dd3c53be6 100644 (file)
@@ -557,11 +557,7 @@ walkdir(char *path, void (*action) (char *fname, bool isdir))
        }
 
 #ifdef WIN32
-
-       /*
-        * This fix is in mingw cvs (runtime/mingwex/dirent.c rev 1.4), but not in
-        * released version
-        */
+       /* Bug in old Mingw dirent.c;  fixed in mingw-runtime-3.2, 2003-10-10 */
        if (GetLastError() == ERROR_NO_MORE_FILES)
                errno = 0;
 #endif
@@ -573,7 +569,12 @@ walkdir(char *path, void (*action) (char *fname, bool isdir))
                exit_nicely();
        }
 
-       closedir(dir);
+       if (closedir(dir))
+       {
+               fprintf(stderr, _("%s: could not close directory \"%s\": %s\n"),
+                               progname, path, strerror(errno));
+               exit_nicely();
+       }
 
        /*
         * It's important to fsync the destination directory itself as individual
index 5738c0e6e6abe2a81d41644fae65a76e9494fd55..8d9f00e930fbdaf5af493d4016903079ebb02f0e 100644 (file)
@@ -138,7 +138,7 @@ FindStreamingStart(uint32 *tli)
                disconnect_and_exit(1);
        }
 
-       while ((dirent = readdir(dir)) != NULL)
+       while (errno = 0, (dirent = readdir(dir)) != NULL)
        {
                uint32          tli;
                XLogSegNo       segno;
@@ -208,7 +208,25 @@ FindStreamingStart(uint32 *tli)
                }
        }
 
-       closedir(dir);
+#ifdef WIN32
+       /* Bug in old Mingw dirent.c;  fixed in mingw-runtime-3.2, 2003-10-10 */
+       if (GetLastError() == ERROR_NO_MORE_FILES)
+               errno = 0;
+#endif
+
+       if (errno)
+       {
+               fprintf(stderr, _("%s: could not read directory \"%s\": %s\n"),
+                               progname, basedir, strerror(errno));
+               disconnect_and_exit(1);
+       }
+
+       if (closedir(dir))
+       {
+               fprintf(stderr, _("%s: could not close directory \"%s\": %s\n"),
+                               progname, basedir, strerror(errno));
+               disconnect_and_exit(1);
+       }
 
        if (high_segno > 0)
        {
index f803186a2e605bcb2aa0f51e88023962227c8407..a8bcd590ec19984d735cb1c080496191da90d967 100644 (file)
@@ -177,7 +177,7 @@ InitArchiveFmt_Directory(ArchiveHandle *AH)
                                struct dirent *d;
 
                                is_empty = true;
-                               while ((d = readdir(dir)))
+                               while (errno = 0, (d = readdir(dir)))
                                {
                                        if (strcmp(d->d_name, ".") != 0 && strcmp(d->d_name, "..") != 0)
                                        {
@@ -185,7 +185,20 @@ InitArchiveFmt_Directory(ArchiveHandle *AH)
                                                break;
                                        }
                                }
-                               closedir(dir);
+
+#ifdef WIN32
+                               /* Bug in old Mingw dirent.c;  fixed in mingw-runtime-3.2, 2003-10-10 */
+                               if (GetLastError() == ERROR_NO_MORE_FILES)
+                                       errno = 0;
+#endif
+
+                               if (errno)
+                                       exit_horribly(modulename, "could not read directory \"%s\": %s\n",
+                                                                 ctx->directory, strerror(errno));
+
+                               if (closedir(dir))
+                                       exit_horribly(modulename, "could not close directory \"%s\": %s\n",
+                                                                 ctx->directory, strerror(errno));
                        }
                }
 
index cd003f41c9993b75188239f8fb461ac8b91ac3d4..e44462adcef098b58419a5dfbe9d398fcfa11ae5 100644 (file)
@@ -765,8 +765,7 @@ FindEndOfXLOG(void)
                exit(1);
        }
 
-       errno = 0;
-       while ((xlde = readdir(xldir)) != NULL)
+       while (errno = 0, (xlde = readdir(xldir)) != NULL)
        {
                if (strlen(xlde->d_name) == 24 &&
                        strspn(xlde->d_name, "0123456789ABCDEF") == 24)
@@ -788,25 +787,27 @@ FindEndOfXLOG(void)
                        if (segno > newXlogSegNo)
                                newXlogSegNo = segno;
                }
-               errno = 0;
        }
-#ifdef WIN32
 
-       /*
-        * This fix is in mingw cvs (runtime/mingwex/dirent.c rev 1.4), but not in
-        * released version
-        */
+#ifdef WIN32
+       /* Bug in old Mingw dirent.c;  fixed in mingw-runtime-3.2, 2003-10-10 */
        if (GetLastError() == ERROR_NO_MORE_FILES)
                errno = 0;
 #endif
 
        if (errno)
        {
-               fprintf(stderr, _("%s: could not read from directory \"%s\": %s\n"),
+               fprintf(stderr, _("%s: could not read directory \"%s\": %s\n"),
+                               progname, XLOGDIR, strerror(errno));
+               exit(1);
+       }
+
+       if (closedir(xldir))
+       {
+               fprintf(stderr, _("%s: could not close directory \"%s\": %s\n"),
                                progname, XLOGDIR, strerror(errno));
                exit(1);
        }
-       closedir(xldir);
 
        /*
         * Finally, convert to new xlog seg size, and advance by one to ensure we
@@ -836,8 +837,7 @@ KillExistingXLOG(void)
                exit(1);
        }
 
-       errno = 0;
-       while ((xlde = readdir(xldir)) != NULL)
+       while (errno = 0, (xlde = readdir(xldir)) != NULL)
        {
                if (strlen(xlde->d_name) == 24 &&
                        strspn(xlde->d_name, "0123456789ABCDEF") == 24)
@@ -850,25 +850,27 @@ KillExistingXLOG(void)
                                exit(1);
                        }
                }
-               errno = 0;
        }
-#ifdef WIN32
 
-       /*
-        * This fix is in mingw cvs (runtime/mingwex/dirent.c rev 1.4), but not in
-        * released version
-        */
+#ifdef WIN32
+       /* Bug in old Mingw dirent.c;  fixed in mingw-runtime-3.2, 2003-10-10 */
        if (GetLastError() == ERROR_NO_MORE_FILES)
                errno = 0;
 #endif
 
        if (errno)
        {
-               fprintf(stderr, _("%s: could not read from directory \"%s\": %s\n"),
+               fprintf(stderr, _("%s: could not read directory \"%s\": %s\n"),
+                               progname, XLOGDIR, strerror(errno));
+               exit(1);
+       }
+
+       if (closedir(xldir))
+       {
+               fprintf(stderr, _("%s: could not close directory \"%s\": %s\n"),
                                progname, XLOGDIR, strerror(errno));
                exit(1);
        }
-       closedir(xldir);
 }
 
 
@@ -892,8 +894,7 @@ KillExistingArchiveStatus(void)
                exit(1);
        }
 
-       errno = 0;
-       while ((xlde = readdir(xldir)) != NULL)
+       while (errno = 0, (xlde = readdir(xldir)) != NULL)
        {
                if (strspn(xlde->d_name, "0123456789ABCDEF") == 24 &&
                        (strcmp(xlde->d_name + 24, ".ready") == 0 ||
@@ -907,25 +908,27 @@ KillExistingArchiveStatus(void)
                                exit(1);
                        }
                }
-               errno = 0;
        }
-#ifdef WIN32
 
-       /*
-        * This fix is in mingw cvs (runtime/mingwex/dirent.c rev 1.4), but not in
-        * released version
-        */
+#ifdef WIN32
+       /* Bug in old Mingw dirent.c;  fixed in mingw-runtime-3.2, 2003-10-10 */
        if (GetLastError() == ERROR_NO_MORE_FILES)
                errno = 0;
 #endif
 
        if (errno)
        {
-               fprintf(stderr, _("%s: could not read from directory \"%s\": %s\n"),
+               fprintf(stderr, _("%s: could not read directory \"%s\": %s\n"),
+                               progname, ARCHSTATDIR, strerror(errno));
+               exit(1);
+       }
+
+       if (closedir(xldir))
+       {
+               fprintf(stderr, _("%s: could not close directory \"%s\": %s\n"),
                                progname, ARCHSTATDIR, strerror(errno));
                exit(1);
        }
-       closedir(xldir);
 }
 
 
index 9298e63f4d247e811af1cb8ff33a44a457d031cb..64de4414c2964f1658c6eeba3561dd9ec0c52881 100644 (file)
@@ -105,15 +105,19 @@ readdir(DIR *d)
        strcpy(d->ret.d_name, fd.cFileName);            /* Both strings are MAX_PATH
                                                                                                 * long */
        d->ret.d_namlen = strlen(d->ret.d_name);
+
        return &d->ret;
 }
 
 int
 closedir(DIR *d)
 {
+       int ret = 0;
+
        if (d->handle != INVALID_HANDLE_VALUE)
-               FindClose(d->handle);
+               ret = !FindClose(d->handle);
        free(d->dirname);
        free(d);
-       return 0;
+
+       return ret;
 }
index 5dd0983a2de5c2223766f4ce38e5a78c6772b4e7..fde9736f4a03d55b5f083f0d41e4f083a84462f4 100644 (file)
@@ -382,8 +382,7 @@ pgfnames(const char *path)
 
        filenames = (char **) palloc(fnsize * sizeof(char *));
 
-       errno = 0;
-       while ((file = readdir(dir)) != NULL)
+       while (errno = 0, (file = readdir(dir)) != NULL)
        {
                if (strcmp(file->d_name, ".") != 0 && strcmp(file->d_name, "..") != 0)
                {
@@ -395,17 +394,14 @@ pgfnames(const char *path)
                        }
                        filenames[numnames++] = pstrdup(file->d_name);
                }
-               errno = 0;
        }
-#ifdef WIN32
 
-       /*
-        * This fix is in mingw cvs (runtime/mingwex/dirent.c rev 1.4), but not in
-        * released version
-        */
+#ifdef WIN32
+       /* Bug in old Mingw dirent.c;  fixed in mingw-runtime-3.2, 2003-10-10 */
        if (GetLastError() == ERROR_NO_MORE_FILES)
                errno = 0;
 #endif
+
        if (errno)
        {
 #ifndef FRONTEND
@@ -418,7 +414,15 @@ pgfnames(const char *path)
 
        filenames[numnames] = NULL;
 
-       closedir(dir);
+       if (closedir(dir))
+       {
+#ifndef FRONTEND
+               elog(WARNING, "could not close directory \"%s\": %m", path);
+#else
+               fprintf(stderr, _("could not close directory \"%s\": %s\n"),
+                               path, strerror(errno));
+#endif
+       }
 
        return filenames;
 }
index 9d80192a8e6c637ee38c9680d66d8924913a504b..a68c7a3dfa3ae0096ed2d56150806c8da573eb19 100644 (file)
@@ -33,14 +33,11 @@ pg_check_dir(const char *dir)
        struct dirent *file;
        bool            dot_found = false;
 
-       errno = 0;
-
        chkdir = opendir(dir);
-
        if (chkdir == NULL)
                return (errno == ENOENT) ? 0 : -1;
 
-       while ((file = readdir(chkdir)) != NULL)
+       while (errno = 0, (file = readdir(chkdir)) != NULL)
        {
                if (strcmp(".", file->d_name) == 0 ||
                        strcmp("..", file->d_name) == 0)
@@ -68,18 +65,12 @@ pg_check_dir(const char *dir)
        }
 
 #ifdef WIN32
-
-       /*
-        * This fix is in mingw cvs (runtime/mingwex/dirent.c rev 1.4), but not in
-        * released version
-        */
+       /* Bug in old Mingw dirent.c;  fixed in mingw-runtime-3.2, 2003-10-10 */
        if (GetLastError() == ERROR_NO_MORE_FILES)
                errno = 0;
 #endif
 
-       closedir(chkdir);
-
-       if (errno != 0)
+       if (errno || closedir(chkdir))
                result = -1;                    /* some kind of I/O error? */
 
        /* We report on dot-files if we _only_ find dot files */