PostgreSQL Source Code  git master
rmtree.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  *
3  * rmtree.c
4  *
5  * Portions Copyright (c) 1996-2024, 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 #include "common/file_utils.h"
24 
25 #ifndef FRONTEND
26 #include "storage/fd.h"
27 #define pg_log_warning(...) elog(WARNING, __VA_ARGS__)
28 #define LOG_LEVEL WARNING
29 #define OPENDIR(x) AllocateDir(x)
30 #define CLOSEDIR(x) FreeDir(x)
31 #else
32 #include "common/logging.h"
33 #define LOG_LEVEL PG_LOG_WARNING
34 #define OPENDIR(x) opendir(x)
35 #define CLOSEDIR(x) closedir(x)
36 #endif
37 
38 /*
39  * rmtree
40  *
41  * Delete a directory tree recursively.
42  * Assumes path points to a valid directory.
43  * Deletes everything under path.
44  * If rmtopdir is true deletes the directory too.
45  * Returns true if successful, false if there was any problem.
46  * (The details of the problem are reported already, so caller
47  * doesn't really have to say anything more, but most do.)
48  */
49 bool
50 rmtree(const char *path, bool rmtopdir)
51 {
52  char pathbuf[MAXPGPATH];
53  DIR *dir;
54  struct dirent *de;
55  bool result = true;
56  size_t dirnames_size = 0;
57  size_t dirnames_capacity = 8;
58  char **dirnames;
59 
60  dir = OPENDIR(path);
61  if (dir == NULL)
62  {
63  pg_log_warning("could not open directory \"%s\": %m", path);
64  return false;
65  }
66 
67  dirnames = (char **) palloc(sizeof(char *) * dirnames_capacity);
68 
69  while (errno = 0, (de = readdir(dir)))
70  {
71  if (strcmp(de->d_name, ".") == 0 ||
72  strcmp(de->d_name, "..") == 0)
73  continue;
74  snprintf(pathbuf, sizeof(pathbuf), "%s/%s", path, de->d_name);
75  switch (get_dirent_type(pathbuf, de, false, LOG_LEVEL))
76  {
77  case PGFILETYPE_ERROR:
78  /* already logged, press on */
79  break;
80  case PGFILETYPE_DIR:
81 
82  /*
83  * Defer recursion until after we've closed this directory, to
84  * avoid using more than one file descriptor at a time.
85  */
86  if (dirnames_size == dirnames_capacity)
87  {
88  dirnames = repalloc(dirnames,
89  sizeof(char *) * dirnames_capacity * 2);
90  dirnames_capacity *= 2;
91  }
92  dirnames[dirnames_size++] = pstrdup(pathbuf);
93  break;
94  default:
95  if (unlink(pathbuf) != 0 && errno != ENOENT)
96  {
97  pg_log_warning("could not remove file \"%s\": %m", pathbuf);
98  result = false;
99  }
100  break;
101  }
102  }
103 
104  if (errno != 0)
105  {
106  pg_log_warning("could not read directory \"%s\": %m", path);
107  result = false;
108  }
109 
110  CLOSEDIR(dir);
111 
112  /* Now recurse into the subdirectories we found. */
113  for (size_t i = 0; i < dirnames_size; ++i)
114  {
115  if (!rmtree(dirnames[i], true))
116  result = false;
117  pfree(dirnames[i]);
118  }
119 
120  if (rmtopdir)
121  {
122  if (rmdir(path) != 0)
123  {
124  pg_log_warning("could not remove directory \"%s\": %m", path);
125  result = false;
126  }
127  }
128 
129  pfree(dirnames);
130 
131  return result;
132 }
struct dirent * readdir(DIR *)
Definition: dirent.c:78
PGFileType get_dirent_type(const char *path, const struct dirent *de, bool look_through_symlinks, int elevel)
Definition: file_utils.c:526
@ PGFILETYPE_DIR
Definition: file_utils.h:23
@ PGFILETYPE_ERROR
Definition: file_utils.h:20
int i
Definition: isn.c:72
char * pstrdup(const char *in)
Definition: mcxt.c:1696
void pfree(void *pointer)
Definition: mcxt.c:1521
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:1541
void * palloc(Size size)
Definition: mcxt.c:1317
#define MAXPGPATH
#define snprintf
Definition: port.h:238
#define LOG_LEVEL
Definition: rmtree.c:28
#define OPENDIR(x)
Definition: rmtree.c:29
#define CLOSEDIR(x)
Definition: rmtree.c:30
bool rmtree(const char *path, bool rmtopdir)
Definition: rmtree.c:50
#define pg_log_warning(...)
Definition: rmtree.c:27
Definition: dirent.c:26
Definition: dirent.h:10
char d_name[MAX_PATH]
Definition: dirent.h:15