OSDN Git Service

Fix rmtree() so that it keeps going after failure to remove any individual
authorTom Lane <tgl@sss.pgh.pa.us>
Fri, 18 Apr 2008 17:05:45 +0000 (17:05 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
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 7055b0f..6707e9e 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 ae482bd..1fd1a53 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 fa95254..aa9a71c 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;
 }