static char *xlog_dir = "";
 static char format = 'p';              /* p(lain)/t(ar) */
 static char *label = "pg_basebackup base backup";
+static bool noclean = false;
 static bool showprogress = false;
 static int     verbose = 0;
 static int     compresslevel = 0;
 static pg_time_t last_progress_report = 0;
 static int32 maxrate = 0;              /* no limit by default */
 
+static bool success = false;
+static bool made_new_pgdata = false;
+static bool found_existing_pgdata = false;
+static bool made_new_xlogdir = false;
+static bool found_existing_xlogdir = false;
+static bool made_tablespace_dirs = false;
+static bool found_tablespace_dirs = false;
 
 /* Progress counters */
 static uint64 totalsize;
 
 /* Handle to child process */
 static pid_t bgchild = -1;
+static bool in_log_streamer = false;
 
 /* End position for xlog streaming, empty string if unknown yet */
 static XLogRecPtr xlogendptr;
 /* Function headers */
 static void usage(void);
 static void disconnect_and_exit(int code);
-static void verify_dir_is_empty_or_create(char *dirname);
+static void verify_dir_is_empty_or_create(char *dirname, bool *created, bool *found);
 static void progress_report(int tablespacenum, const char *filename, bool force);
 
 static void ReceiveTarFile(PGconn *conn, PGresult *res, int rownum);
 static void tablespace_list_append(const char *arg);
 
 
+static void
+cleanup_directories_atexit(void)
+{
+       if (success || in_log_streamer)
+               return;
+
+       if (!noclean)
+       {
+               if (made_new_pgdata)
+               {
+                       fprintf(stderr, _("%s: removing data directory \"%s\"\n"),
+                                       progname, basedir);
+                       if (!rmtree(basedir, true))
+                               fprintf(stderr, _("%s: failed to remove data directory\n"),
+                                               progname);
+               }
+               else if (found_existing_pgdata)
+               {
+                       fprintf(stderr,
+                                       _("%s: removing contents of data directory \"%s\"\n"),
+                                       progname, basedir);
+                       if (!rmtree(basedir, false))
+                               fprintf(stderr, _("%s: failed to remove contents of data directory\n"),
+                                               progname);
+               }
+
+               if (made_new_xlogdir)
+               {
+                       fprintf(stderr, _("%s: removing transaction log directory \"%s\"\n"),
+                                       progname, xlog_dir);
+                       if (!rmtree(xlog_dir, true))
+                               fprintf(stderr, _("%s: failed to remove transaction log directory\n"),
+                                               progname);
+               }
+               else if (found_existing_xlogdir)
+               {
+                       fprintf(stderr,
+                                       _("%s: removing contents of transaction log directory \"%s\"\n"),
+                                       progname, xlog_dir);
+                       if (!rmtree(xlog_dir, false))
+                               fprintf(stderr, _("%s: failed to remove contents of transaction log directory\n"),
+                                               progname);
+               }
+       }
+       else
+       {
+               if (made_new_pgdata || found_existing_pgdata)
+                       fprintf(stderr,
+                         _("%s: data directory \"%s\" not removed at user's request\n"),
+                                       progname, basedir);
+
+               if (made_new_xlogdir || found_existing_xlogdir)
+                       fprintf(stderr,
+                                       _("%s: transaction log directory \"%s\" not removed at user's request\n"),
+                                       progname, xlog_dir);
+       }
+
+       if (made_tablespace_dirs || found_tablespace_dirs)
+               fprintf(stderr,
+                               _("%s: changes to tablespace directories will not be undone"),
+                               progname);
+}
+
 static void
 disconnect_and_exit(int code)
 {
        printf(_("  -c, --checkpoint=fast|spread\n"
                         "                         set fast or spread checkpointing\n"));
        printf(_("  -l, --label=LABEL      set backup label\n"));
+       printf(_("  -n, --noclean          do not clean up after errors\n"));
        printf(_("  -P, --progress         show progress information\n"));
        printf(_("  -v, --verbose          output verbose messages\n"));
        printf(_("  -V, --version          output version information, then exit\n"));
 {
        StreamCtl       stream;
 
+       in_log_streamer = true;
+
        MemSet(&stream, 0, sizeof(stream));
        stream.startpos = param->startptr;
        stream.timeline = param->timeline;
  * be give and the process ended.
  */
 static void
-verify_dir_is_empty_or_create(char *dirname)
+verify_dir_is_empty_or_create(char *dirname, bool *created, bool *found)
 {
        switch (pg_check_dir(dirname))
        {
                                                progname, dirname, strerror(errno));
                                disconnect_and_exit(1);
                        }
+                       if (created)
+                               *created = true;
                        return;
                case 1:
 
                        /*
                         * Exists, empty
                         */
+                       if (found)
+                               *found = true;
                        return;
                case 2:
                case 3:
                {
                        char       *path = (char *) get_tablespace_mapping(PQgetvalue(res, i, 1));
 
-                       verify_dir_is_empty_or_create(path);
+                       verify_dir_is_empty_or_create(path, &made_tablespace_dirs, &found_tablespace_dirs);
                }
        }
 
                {"gzip", no_argument, NULL, 'z'},
                {"compress", required_argument, NULL, 'Z'},
                {"label", required_argument, NULL, 'l'},
+               {"noclean", no_argument, NULL, 'n'},
                {"dbname", required_argument, NULL, 'd'},
                {"host", required_argument, NULL, 'h'},
                {"port", required_argument, NULL, 'p'},
                }
        }
 
-       while ((c = getopt_long(argc, argv, "D:F:r:RT:xX:l:zZ:d:c:h:p:U:s:S:wWvP",
+       atexit(cleanup_directories_atexit);
+
+       while ((c = getopt_long(argc, argv, "D:F:r:RT:xX:l:nzZ:d:c:h:p:U:s:S:wWvP",
                                                        long_options, &option_index)) != -1)
        {
                switch (c)
                        case 'l':
                                label = pg_strdup(optarg);
                                break;
+                       case 'n':
+                               noclean = true;
+                               break;
                        case 'z':
 #ifdef HAVE_LIBZ
                                compresslevel = Z_DEFAULT_COMPRESSION;
         * unless we are writing to stdout.
         */
        if (format == 'p' || strcmp(basedir, "-") != 0)
-               verify_dir_is_empty_or_create(basedir);
+               verify_dir_is_empty_or_create(basedir, &made_new_pgdata, &found_existing_pgdata);
 
        /* Create transaction log symlink, if required */
        if (strcmp(xlog_dir, "") != 0)
        {
                char       *linkloc;
 
-               verify_dir_is_empty_or_create(xlog_dir);
+               verify_dir_is_empty_or_create(xlog_dir, &made_new_xlogdir, &found_existing_xlogdir);
 
                /* form name of the place where the symlink must go */
                linkloc = psprintf("%s/pg_xlog", basedir);
 
        BaseBackup();
 
+       success = true;
        return 0;
 }