jsonpath scanner: reentrant scanner
[pgsql.git] / src / common / rmtree.c
blob78717960999707091690540bd35593c87a1a8f35
1 /*-------------------------------------------------------------------------
3 * rmtree.c
5 * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
6 * Portions Copyright (c) 1994, Regents of the University of California
8 * IDENTIFICATION
9 * src/common/rmtree.c
11 *-------------------------------------------------------------------------
14 #ifndef FRONTEND
15 #include "postgres.h"
16 #else
17 #include "postgres_fe.h"
18 #endif
20 #include <unistd.h>
21 #include <sys/stat.h>
23 #include "common/file_utils.h"
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
39 * rmtree
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.)
49 bool
50 rmtree(const char *path, bool rmtopdir)
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;
60 dir = OPENDIR(path);
61 if (dir == NULL)
63 pg_log_warning("could not open directory \"%s\": %m", path);
64 return false;
67 dirnames = (char **) palloc(sizeof(char *) * dirnames_capacity);
69 while (errno = 0, (de = readdir(dir)))
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))
77 case PGFILETYPE_ERROR:
78 /* already logged, press on */
79 break;
80 case PGFILETYPE_DIR:
83 * Defer recursion until after we've closed this directory, to
84 * avoid using more than one file descriptor at a time.
86 if (dirnames_size == dirnames_capacity)
88 dirnames = repalloc(dirnames,
89 sizeof(char *) * dirnames_capacity * 2);
90 dirnames_capacity *= 2;
92 dirnames[dirnames_size++] = pstrdup(pathbuf);
93 break;
94 default:
95 if (unlink(pathbuf) != 0 && errno != ENOENT)
97 pg_log_warning("could not remove file \"%s\": %m", pathbuf);
98 result = false;
100 break;
104 if (errno != 0)
106 pg_log_warning("could not read directory \"%s\": %m", path);
107 result = false;
110 CLOSEDIR(dir);
112 /* Now recurse into the subdirectories we found. */
113 for (size_t i = 0; i < dirnames_size; ++i)
115 if (!rmtree(dirnames[i], true))
116 result = false;
117 pfree(dirnames[i]);
120 if (rmtopdir)
122 if (rmdir(path) != 0)
124 pg_log_warning("could not remove directory \"%s\": %m", path);
125 result = false;
129 pfree(dirnames);
131 return result;