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