1 /*------------------------------------------------------------------------- 2 * 3 * rmtree.c 4 * 5 * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group 6 * Portions Copyright (c) 1994, Regents of the University of California 7 * 8 * IDENTIFICATION 9 * src/common/rmtree.c 10 * 11 *------------------------------------------------------------------------- 12 */ 13 14 #ifndef FRONTEND 15 #include "postgres.h" 16 #else 17 #include "postgres_fe.h" 18 #endif 19 20 #include <unistd.h> 21 #include <sys/stat.h> 22 23 #ifndef FRONTEND 24 #define pg_log_warning(...) elog(WARNING, __VA_ARGS__) 25 #else 26 #include "common/logging.h" 27 #endif 28 29 30 /* 31 * rmtree 32 * 33 * Delete a directory tree recursively. 34 * Assumes path points to a valid directory. 35 * Deletes everything under path. 36 * If rmtopdir is true deletes the directory too. 37 * Returns true if successful, false if there was any problem. 38 * (The details of the problem are reported already, so caller 39 * doesn't really have to say anything more, but most do.) 40 */ 41 bool 42 rmtree(const char *path, bool rmtopdir) 43 { 44 bool result = true; 45 char pathbuf[MAXPGPATH]; 46 char **filenames; 47 char **filename; 48 struct stat statbuf; 49 50 /* 51 * we copy all the names out of the directory before we start modifying 52 * it. 53 */ 54 filenames = pgfnames(path); 55 56 if (filenames == NULL) 57 return false; 58 59 /* now we have the names we can start removing things */ 60 for (filename = filenames; *filename; filename++) 61 { 62 snprintf(pathbuf, MAXPGPATH, "%s/%s", path, *filename); 63 64 /* 65 * It's ok if the file is not there anymore; we were just about to 66 * delete it anyway. 67 * 68 * This is not an academic possibility. One scenario where this 69 * happens is when bgwriter has a pending unlink request for a file in 70 * a database that's being dropped. In dropdb(), we call 71 * ForgetDatabaseSyncRequests() to flush out any such pending unlink 72 * requests, but because that's asynchronous, it's not guaranteed that 73 * the bgwriter receives the message in time. 74 */ 75 if (lstat(pathbuf, &statbuf) != 0) 76 { 77 if (errno != ENOENT) 78 { 79 pg_log_warning("could not stat file or directory \"%s\": %m", 80 pathbuf); 81 result = false; 82 } 83 continue; 84 } 85 86 if (S_ISDIR(statbuf.st_mode)) 87 { 88 /* call ourselves recursively for a directory */ 89 if (!rmtree(pathbuf, true)) 90 { 91 /* we already reported the error */ 92 result = false; 93 } 94 } 95 else 96 { 97 if (unlink(pathbuf) != 0) 98 { 99 if (errno != ENOENT) 100 { 101 pg_log_warning("could not remove file or directory \"%s\": %m", 102 pathbuf); 103 result = false; 104 } 105 } 106 } 107 } 108 109 if (rmtopdir) 110 { 111 if (rmdir(path) != 0) 112 { 113 pg_log_warning("could not remove file or directory \"%s\": %m", 114 path); 115 result = false; 116 } 117 } 118 119 pgfnames_cleanup(filenames); 120 121 return result; 122 } 123