Branch data Line data Source code
1 : : /*
2 : : * libdpkg - Debian packaging suite library routines
3 : : * dir.c - directory handling functions
4 : : *
5 : : * Copyright © 2010 Guillem Jover <guillem@debian.org>
6 : : *
7 : : * This is free software; you can redistribute it and/or modify
8 : : * it under the terms of the GNU General Public License as published by
9 : : * the Free Software Foundation; either version 2 of the License, or
10 : : * (at your option) any later version.
11 : : *
12 : : * This is distributed in the hope that it will be useful,
13 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 : : * GNU General Public License for more details.
16 : : *
17 : : * You should have received a copy of the GNU General Public License
18 : : * along with this program. If not, see <https://www.gnu.org/licenses/>.
19 : : */
20 : :
21 : : #include <config.h>
22 : : #include <compat.h>
23 : :
24 : : #include <sys/types.h>
25 : : #include <sys/stat.h>
26 : :
27 : : #include <errno.h>
28 : : #include <fcntl.h>
29 : : #include <dirent.h>
30 : : #include <string.h>
31 : : #include <stdlib.h>
32 : : #include <unistd.h>
33 : :
34 : : #include <dpkg/dpkg.h>
35 : : #include <dpkg/i18n.h>
36 : : #include <dpkg/dir.h>
37 : :
38 : : static int
39 : 0 : dir_make_path_noalloc(char *dirname, mode_t mode)
40 : : {
41 : : char *slash;
42 : :
43 : : /* Find the first slash, and ignore it, as it will be either the
44 : : * slash for the root directory, for the current directory in a
45 : : * relative pathname or its parent. */
46 : 0 : slash = strchr(dirname, '/');
47 : :
48 [ # # ]: 0 : while (slash != NULL) {
49 : 0 : slash = strchr(slash + 1, '/');
50 [ # # ]: 0 : if (slash)
51 : 0 : *slash = '\0';
52 : :
53 [ # # # # ]: 0 : if (mkdir(dirname, mode) < 0 && errno != EEXIST)
54 : 0 : return -1;
55 [ # # ]: 0 : if (slash)
56 : 0 : *slash = '/';
57 : : }
58 : :
59 : 0 : return 0;
60 : : }
61 : :
62 : : /**
63 : : * Create the directory and all its parents if necessary.
64 : : *
65 : : * @param path The pathname to create directories for.
66 : : * @param mode The pathname mode.
67 : : */
68 : : int
69 : 0 : dir_make_path(const char *path, mode_t mode)
70 : : {
71 : : char *dirname;
72 : : int rc;
73 : :
74 : 0 : dirname = m_strdup(path);
75 : 0 : rc = dir_make_path_noalloc(dirname, mode);
76 : 0 : free(dirname);
77 : :
78 : 0 : return rc;
79 : : }
80 : :
81 : : int
82 : 0 : dir_make_path_parent(const char *path, mode_t mode)
83 : : {
84 : : char *dirname, *slash;
85 : : int rc;
86 : :
87 : 0 : dirname = m_strdup(path);
88 : 0 : slash = strrchr(dirname, '/');
89 [ # # ]: 0 : if (slash != NULL) {
90 : 0 : *slash = '\0';
91 : 0 : rc = dir_make_path_noalloc(dirname, mode);
92 : : } else {
93 : 0 : rc = -1;
94 : : }
95 : 0 : free(dirname);
96 : :
97 : 0 : return rc;
98 : : }
99 : :
100 : : /**
101 : : * Sync a directory to disk from a DIR structure.
102 : : *
103 : : * @param dir The directory to sync.
104 : : * @param path The name of the directory to sync (for error messages).
105 : : */
106 : : static void
107 : 1 : dir_sync(DIR *dir, const char *path)
108 : : {
109 : : #ifdef HAVE_FSYNC_DIR
110 : : int fd;
111 : :
112 : 1 : fd = dirfd(dir);
113 [ - + ]: 1 : if (fd < 0)
114 : 0 : ohshite(_("unable to get file descriptor for directory '%s'"),
115 : : path);
116 : :
117 [ - + ]: 1 : if (fsync(fd))
118 : 0 : ohshite(_("unable to sync directory '%s'"), path);
119 : : #endif
120 : 1 : }
121 : :
122 : : /**
123 : : * Sync a directory to disk from a pathname.
124 : : *
125 : : * @param path The name of the directory to sync.
126 : : */
127 : : void
128 : 1 : dir_sync_path(const char *path)
129 : : {
130 : : #ifdef HAVE_FSYNC_DIR
131 : : DIR *dir;
132 : :
133 : 1 : dir = opendir(path);
134 [ - + ]: 1 : if (!dir)
135 : 0 : ohshite(_("unable to open directory '%s'"), path);
136 : :
137 : 1 : dir_sync(dir, path);
138 : :
139 : 1 : closedir(dir);
140 : : #endif
141 : 1 : }
142 : :
143 : : /**
144 : : * Sync to disk the parent directory of a pathname.
145 : : *
146 : : * @param path The child pathname of the directory to sync.
147 : : */
148 : : void
149 : 0 : dir_sync_path_parent(const char *path)
150 : : {
151 : : #ifdef HAVE_FSYNC_DIR
152 : : char *dirname, *slash;
153 : :
154 : 0 : dirname = m_strdup(path);
155 : :
156 : 0 : slash = strrchr(dirname, '/');
157 [ # # ]: 0 : if (slash != NULL) {
158 : 0 : *slash = '\0';
159 : 0 : dir_sync_path(dirname);
160 : : }
161 : :
162 : 0 : free(dirname);
163 : : #endif
164 : 0 : }
165 : :
166 : : /* TODO: Ideally we'd use openat() here, to avoid the path mangling, but
167 : : * it's not widely available yet, so this will do for now. */
168 : : static void
169 : 0 : dir_file_sync(const char *dir, const char *filename)
170 : : {
171 : : char *path;
172 : : int fd;
173 : :
174 : 0 : path = str_fmt("%s/%s", dir, filename);
175 : :
176 : 0 : fd = open(path, O_WRONLY);
177 [ # # ]: 0 : if (fd < 0)
178 : 0 : ohshite(_("unable to open file '%s'"), path);
179 [ # # ]: 0 : if (fsync(fd))
180 : 0 : ohshite(_("unable to sync file '%s'"), path);
181 [ # # ]: 0 : if (close(fd))
182 : 0 : ohshite(_("unable to close file '%s'"), path);
183 : :
184 : 0 : free(path);
185 : 0 : }
186 : :
187 : : /**
188 : : * Sync to disk the contents and the directory specified.
189 : : *
190 : : * @param path The pathname to sync.
191 : : */
192 : : void
193 : 0 : dir_sync_contents(const char *path)
194 : : {
195 : : DIR *dir;
196 : : struct dirent *dent;
197 : :
198 : 0 : dir = opendir(path);
199 [ # # ]: 0 : if (!dir)
200 : 0 : ohshite(_("unable to open directory '%s'"), path);
201 : :
202 [ # # ]: 0 : while ((dent = readdir(dir)) != NULL) {
203 [ # # ]: 0 : if (strcmp(dent->d_name, ".") == 0 ||
204 [ # # ]: 0 : strcmp(dent->d_name, "..") == 0)
205 : 0 : continue;
206 : :
207 : 0 : dir_file_sync(path, dent->d_name);
208 : : }
209 : :
210 : 0 : dir_sync(dir, path);
211 : :
212 : 0 : closedir(dir);
213 : 0 : }
|