/src/postgres/src/common/rmtree.c
Line | Count | Source (jump to first uncovered line) |
1 | | /*------------------------------------------------------------------------- |
2 | | * |
3 | | * rmtree.c |
4 | | * |
5 | | * Portions Copyright (c) 1996-2025, 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 | 0 | #define pg_log_warning(...) elog(WARNING, __VA_ARGS__) |
28 | 0 | #define LOG_LEVEL WARNING |
29 | 0 | #define OPENDIR(x) AllocateDir(x) |
30 | 0 | #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 | 0 | { |
52 | 0 | char pathbuf[MAXPGPATH]; |
53 | 0 | DIR *dir; |
54 | 0 | struct dirent *de; |
55 | 0 | bool result = true; |
56 | 0 | size_t dirnames_size = 0; |
57 | 0 | size_t dirnames_capacity = 8; |
58 | 0 | char **dirnames; |
59 | |
|
60 | 0 | dir = OPENDIR(path); |
61 | 0 | if (dir == NULL) |
62 | 0 | { |
63 | 0 | pg_log_warning("could not open directory \"%s\": %m", path); |
64 | 0 | return false; |
65 | 0 | } |
66 | | |
67 | 0 | dirnames = (char **) palloc(sizeof(char *) * dirnames_capacity); |
68 | |
|
69 | 0 | while (errno = 0, (de = readdir(dir))) |
70 | 0 | { |
71 | 0 | if (strcmp(de->d_name, ".") == 0 || |
72 | 0 | strcmp(de->d_name, "..") == 0) |
73 | 0 | continue; |
74 | 0 | snprintf(pathbuf, sizeof(pathbuf), "%s/%s", path, de->d_name); |
75 | 0 | switch (get_dirent_type(pathbuf, de, false, LOG_LEVEL)) |
76 | 0 | { |
77 | 0 | case PGFILETYPE_ERROR: |
78 | | /* already logged, press on */ |
79 | 0 | break; |
80 | 0 | 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 | 0 | if (dirnames_size == dirnames_capacity) |
87 | 0 | { |
88 | 0 | dirnames = repalloc(dirnames, |
89 | 0 | sizeof(char *) * dirnames_capacity * 2); |
90 | 0 | dirnames_capacity *= 2; |
91 | 0 | } |
92 | 0 | dirnames[dirnames_size++] = pstrdup(pathbuf); |
93 | 0 | break; |
94 | 0 | default: |
95 | 0 | if (unlink(pathbuf) != 0 && errno != ENOENT) |
96 | 0 | { |
97 | 0 | pg_log_warning("could not remove file \"%s\": %m", pathbuf); |
98 | 0 | result = false; |
99 | 0 | } |
100 | 0 | break; |
101 | 0 | } |
102 | 0 | } |
103 | | |
104 | 0 | if (errno != 0) |
105 | 0 | { |
106 | 0 | pg_log_warning("could not read directory \"%s\": %m", path); |
107 | 0 | result = false; |
108 | 0 | } |
109 | | |
110 | 0 | CLOSEDIR(dir); |
111 | | |
112 | | /* Now recurse into the subdirectories we found. */ |
113 | 0 | for (size_t i = 0; i < dirnames_size; ++i) |
114 | 0 | { |
115 | 0 | if (!rmtree(dirnames[i], true)) |
116 | 0 | result = false; |
117 | 0 | pfree(dirnames[i]); |
118 | 0 | } |
119 | |
|
120 | 0 | if (rmtopdir) |
121 | 0 | { |
122 | 0 | if (rmdir(path) != 0) |
123 | 0 | { |
124 | 0 | pg_log_warning("could not remove directory \"%s\": %m", path); |
125 | 0 | result = false; |
126 | 0 | } |
127 | 0 | } |
128 | | |
129 | 0 | pfree(dirnames); |
130 | |
|
131 | 0 | return result; |
132 | 0 | } |