Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
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/common/pgfnames.c
src/port/dirent.c
src/port/pgcheckdir.c

index 7b5484bb6ac9f2585ba819be92dbdfc3ae6ecb85..039829e0049e315125f634e4576c5ae52de0608f 100644 (file)
@@ -106,7 +106,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);
@@ -164,7 +164,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 8ddd486c89eec4907ef8ce7e9a50590dfbb3a9b6..9134d649cd6e0e003c5e1e0d9267ff2e78c15249 100644 (file)
@@ -245,7 +245,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
@@ -283,6 +283,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");
        }
@@ -290,7 +300,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 4dc809dc01d97deead258a0ae7ad6af100eae3fa..5158cfe806f6afe193ec36efeec9cf81b26608d6 100644 (file)
@@ -1957,10 +1957,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 61bd785307618479baa1241adb9faf366ab563ae..ce08494f492dd609b1e5e7cf45eb8f35f184b560 100644 (file)
@@ -565,10 +565,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
@@ -580,7 +577,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 c233779b89cddd5a6a7d1be7f502b2f597ac85e4..1eda4b6b002c98198ebd987da441f3d708d99b1b 100644 (file)
@@ -139,7 +139,7 @@ FindStreamingStart(uint32 *tli)
        disconnect_and_exit(1);
    }
 
-   while ((dirent = readdir(dir)) != NULL)
+   while (errno = 0, (dirent = readdir(dir)) != NULL)
    {
        uint32      tli;
        XLogSegNo   segno;
@@ -209,7 +209,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 1bed8a9fea5ad92927642c9b73aba6d6bd31e7c3..b441ceaa46bbc2e01c5fd889567b0fd46ddb2947 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 28a4f191f34bd2383cdb5fa73aec7761fbb12619..af2cec7e932cd6d392b4968f84fa2831739843d0 100644 (file)
@@ -821,8 +821,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)
@@ -844,25 +843,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
-    */
+   /* 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
@@ -892,8 +893,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)
@@ -906,25 +906,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
-    */
+   /* 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);
 }
 
 
@@ -948,8 +950,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 ||
@@ -963,25 +964,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
-    */
+   /* 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 9a68163dd76b4d605969e26f035fd2ac9177b472..51a848a1fdb5e017e29ed19644625b568268a059 100644 (file)
@@ -50,8 +50,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)
        {
@@ -63,14 +62,10 @@ 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
-    */
+   /* Bug in old Mingw dirent.c;  fixed in mingw-runtime-3.2, 2003-10-10 */
    if (GetLastError() == ERROR_NO_MORE_FILES)
        errno = 0;
 #endif
@@ -87,7 +82,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 f9d93ea7d86b21a7c5982d5c87806521a6ed5b60..3bdc03e9b441f6de356b25f48c9f7d6236fb9ac6 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 fc97f8cc1dac943cc40a089337a195bce44af871..502d4f377d9b3f67d87e46570697f72edb17ea53 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,17 +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 */