Fix rmtree() so that it keeps going after failure to remove any individual
authorTom Lane
Fri, 18 Apr 2008 17:05:45 +0000 (17:05 +0000)
committerTom Lane
Fri, 18 Apr 2008 17:05:45 +0000 (17:05 +0000)
file; the idea is that we should clean up as much as we can, even if there's
some problem removing one file.  Make the error messages a bit less misleading,
too.  In passing, const-ify function arguments.

src/backend/commands/dbcommands.c
src/include/port.h
src/port/dirmod.c

index 7055b0fe98e37aa43cd4da076df6584338e5c9b6..6707e9e6656cd89ea1d98f52f84ff64b05309a05 100644 (file)
@@ -13,7 +13,7 @@
  *
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/commands/dbcommands.c,v 1.207 2008/04/18 06:48:38 heikki Exp $
+ *   $PostgreSQL: pgsql/src/backend/commands/dbcommands.c,v 1.208 2008/04/18 17:05:45 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1321,7 +1321,7 @@ remove_dbtablespaces(Oid db_id)
 
        if (!rmtree(dstpath, true))
            ereport(WARNING,
-                   (errmsg("could not remove database directory \"%s\"",
+                   (errmsg("some useless files may be left behind in old database directory \"%s\"",
                            dstpath)));
 
        /* Record the filesystem change in XLOG */
@@ -1490,7 +1490,7 @@ dbase_redo(XLogRecPtr lsn, XLogRecord *record)
        {
            if (!rmtree(dst_path, true))
                ereport(WARNING,
-                       (errmsg("could not remove database directory \"%s\"",
+                       (errmsg("some useless files may be left behind in old database directory \"%s\"",
                                dst_path)));
        }
 
@@ -1529,7 +1529,7 @@ dbase_redo(XLogRecPtr lsn, XLogRecord *record)
        /* And remove the physical files */
        if (!rmtree(dst_path, true))
            ereport(WARNING,
-                   (errmsg("could not remove database directory \"%s\"",
+                   (errmsg("some useless files may be left behind in old database directory \"%s\"",
                            dst_path)));
    }
    else
index ae482bd8559c56ab55530ba2aed9c163c4ac2078..1fd1a536f9922d41b49e4d4a9e2360bce6ca9f61 100644 (file)
@@ -6,7 +6,7 @@
  * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/port.h,v 1.121 2008/04/16 14:19:56 adunstan Exp $
+ * $PostgreSQL: pgsql/src/include/port.h,v 1.122 2008/04/18 17:05:45 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -48,7 +48,7 @@ extern bool get_home_path(char *ret_path);
 extern void get_parent_directory(char *path);
 
 /* port/dirmod.c */
-extern char **pgfnames(char *path);
+extern char **pgfnames(const char *path);
 extern void pgfnames_cleanup(char **filenames);
 
 /*
@@ -279,7 +279,7 @@ extern int  pgsymlink(const char *oldpath, const char *newpath);
 
 extern void copydir(char *fromdir, char *todir, bool recurse);
 
-extern bool rmtree(char *path, bool rmtopdir);
+extern bool rmtree(const char *path, bool rmtopdir);
 
 /* 
  * stat() is not guaranteed to set the st_size field on win32, so we
index fa952549661db0ca112da7988cc8e5443ee9cc55..aa9a71c3f6e9eead32598d45b621bc0dcbdb1b47 100644 (file)
@@ -10,7 +10,7 @@
  * Win32 (NT, Win2k, XP).  replace() doesn't work on Win95/98/Me.
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/port/dirmod.c,v 1.54 2008/04/18 06:48:38 heikki Exp $
+ *   $PostgreSQL: pgsql/src/port/dirmod.c,v 1.55 2008/04/18 17:05:45 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -291,8 +291,8 @@ pgsymlink(const char *oldpath, const char *newpath)
  * must call pgfnames_cleanup later to free the memory allocated by this
  * function.
  */
-char     **
-pgfnames(char *path)
+char **
+pgfnames(const char *path)
 {
    DIR        *dir;
    struct dirent *file;
@@ -380,12 +380,15 @@ pgfnames_cleanup(char **filenames)
  * Assumes path points to a valid directory.
  * Deletes everything under path.
  * If rmtopdir is true deletes the directory too.
+ * Returns true if successful, false if there was any problem.
+ * (The details of the problem are reported already, so caller
+ * doesn't really have to say anything more, but most do.)
  */
 bool
-rmtree(char *path, bool rmtopdir)
+rmtree(const char *path, bool rmtopdir)
 {
+   bool        result = true;
    char        pathbuf[MAXPGPATH];
-   char       *filepath;
    char      **filenames;
    char      **filename;
    struct stat statbuf;
@@ -400,11 +403,9 @@ rmtree(char *path, bool rmtopdir)
        return false;
 
    /* now we have the names we can start removing things */
-   filepath = pathbuf;
-
    for (filename = filenames; *filename; filename++)
    {
-       snprintf(filepath, MAXPGPATH, "%s/%s", path, *filename);
+       snprintf(pathbuf, MAXPGPATH, "%s/%s", path, *filename);
 
        /*
         * It's ok if the file is not there anymore; we were just about to
@@ -417,54 +418,68 @@ rmtree(char *path, bool rmtopdir)
         * requests, but because that's asynchronous, it's not guaranteed
         * that the bgwriter receives the message in time.
         */
-       if (lstat(filepath, &statbuf) != 0)
+       if (lstat(pathbuf, &statbuf) != 0)
        {
            if (errno != ENOENT)
-               goto report_and_fail;
-           else
-               continue;
+           {
+#ifndef FRONTEND
+               elog(WARNING, "could not stat file or directory \"%s\": %m",
+                    pathbuf);
+#else
+               fprintf(stderr, _("could not stat file or directory \"%s\": %s\n"),
+                       pathbuf, strerror(errno));
+#endif
+               result = false;
+           }
+           continue;
        }
 
        if (S_ISDIR(statbuf.st_mode))
        {
            /* call ourselves recursively for a directory */
-           if (!rmtree(filepath, true))
+           if (!rmtree(pathbuf, true))
            {
                /* we already reported the error */
-               pgfnames_cleanup(filenames);
-               return false;
+               result = false;
            }
        }
        else
        {
-           if (unlink(filepath) != 0)
+           if (unlink(pathbuf) != 0)
            {
                if (errno != ENOENT)
-                   goto report_and_fail;
+               {
+#ifndef FRONTEND
+                   elog(WARNING, "could not remove file or directory \"%s\": %m",
+                        pathbuf);
+#else
+                   fprintf(stderr, _("could not remove file or directory \"%s\": %s\n"),
+                           pathbuf, strerror(errno));
+#endif
+                   result = false;
+               }
            }
        }
    }
 
    if (rmtopdir)
    {
-       filepath = path;
-       if (rmdir(filepath) != 0)
-           goto report_and_fail;
-   }
-
-   pgfnames_cleanup(filenames);
-   return true;
-
-report_and_fail:
-
+       if (rmdir(path) != 0)
+       {
 #ifndef FRONTEND
-   elog(WARNING, "could not remove file or directory \"%s\": %m", filepath);
+           elog(WARNING, "could not remove file or directory \"%s\": %m",
+                path);
 #else
-   fprintf(stderr, _("could not remove file or directory \"%s\": %s\n"),
-           filepath, strerror(errno));
+           fprintf(stderr, _("could not remove file or directory \"%s\": %s\n"),
+                   path, strerror(errno));
 #endif
+           result = false;
+       }
+   }
+
    pgfnames_cleanup(filenames);
-   return false;
+
+   return result;
 }