4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License.
6 You may obtain a copy of the License at
8 http://www.apache.org/licenses/LICENSE-2.0
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
26 #include <sys/types.h>
32 static int mode = 0755;
33 char workdir[PATH_MAX] = { 0, };
36 /* removes recursively the content of a directory */
37 static int clean_dirfd(int dirfd)
49 syslog(LOG_ERR, "failed to dup the dirfd");
52 dir = fdopendir(dirfd);
54 syslog(LOG_ERR, "fdopendir failed in clean_dirfd");
60 if (readdir_r(dir, &entry.entry, &ent) != 0) {
61 syslog(LOG_ERR, "readdir_r failed in clean_dirfd");
66 if (ent->d_name[0] == '.' && (ent->d_name[1] == 0
67 || (ent->d_name[1] == '.' && ent->d_name[2] == 0)))
69 cr = unlinkat(dirfd, ent->d_name, 0);
72 if (errno != EISDIR) {
73 syslog(LOG_ERR, "unlink of %s failed in clean_dirfd", ent->d_name);
76 fd = openat(dirfd, ent->d_name, O_DIRECTORY|O_RDONLY);
78 syslog(LOG_ERR, "opening directory %s failed in clean_dirfd", ent->d_name);
85 cr = unlinkat(dirfd, ent->d_name, AT_REMOVEDIR);
87 syslog(LOG_ERR, "rmdir of %s failed in clean_dirfd", ent->d_name);
97 /* removes recursively the content of a directory */
98 static int clean_dir(const char *directory)
102 fd = openat(AT_FDCWD, directory, O_DIRECTORY|O_RDONLY);
104 syslog(LOG_ERR, "opening directory %s failed in clean_dir", directory);
107 rc = clean_dirfd(fd);
112 /* removes the working directory */
113 void remove_workdir()
115 assert(workdirfd >= 0);
116 clean_dirfd(workdirfd);
123 static int set_real_workdir(const char *name, int create)
128 /* check the length */
129 length = strlen(name);
130 if (length >= sizeof workdir) {
131 syslog(LOG_ERR, "workdir name too long");
136 /* opens the directory */
137 dirfd = openat(AT_FDCWD, name, O_DIRECTORY|O_RDONLY);
139 if (!create || errno != ENOENT) {
140 syslog(LOG_ERR, "no workdir %s", name);
143 rc = mkdir(name, mode);
145 syslog(LOG_ERR, "can't create workdir %s", name);
148 dirfd = open(name, O_PATH|O_DIRECTORY);
150 syslog(LOG_ERR, "can't open workdir %s", name);
155 /* close the previous directory if any */
159 memcpy(workdir, name, 1+length);
163 int set_workdir(const char *name, int create)
169 return set_real_workdir(name, create);
171 rp = realpath(name, NULL);
173 syslog(LOG_ERR, "realpath failed for %s", name);
176 rc = set_real_workdir(rp, create);
181 static int make_real_workdir_base(const char *root, const char *prefix, int reuse)
185 n = snprintf(workdir, sizeof workdir, "%s/%s", root, prefix);
186 if (n >= sizeof workdir) {
187 syslog(LOG_ERR, "workdir prefix too long");
191 r = (int)(sizeof workdir) - n;
197 /* create a temporary directory */
198 for (i = 0 ; ; i++) {
200 syslog(LOG_ERR, "exhaustion of workdirs");
203 l = snprintf(workdir + n, r, "%d", i);
205 syslog(LOG_ERR, "computed workdir too long");
209 if (!mkdir(workdir, mode))
211 if (errno != EEXIST) {
212 syslog(LOG_ERR, "error in creation of workdir %s: %m", workdir);
218 workdirfd = openat(AT_FDCWD, workdir, O_RDONLY|O_DIRECTORY);
220 syslog(LOG_ERR, "error in onnection to workdir %s: %m", workdir);
228 int make_workdir_base(const char *root, const char *prefix, int reuse)
234 return make_real_workdir_base(root, prefix, reuse);
236 rp = realpath(root, NULL);
238 syslog(LOG_ERR, "realpath failed for %s", root);
241 rc = make_real_workdir_base(rp, prefix, reuse);
246 int make_workdir(int reuse)
248 return make_workdir_base(".", "PACK", reuse);
251 static int move_real_workdir(const char *dest, int parents, int force)
259 if (strlen(dest) >= sizeof workdir) {
260 syslog(LOG_ERR, "destination dirname too long");
265 /* if an existing directory exist remove it if force */
268 if (!S_ISDIR(s.st_mode)) {
269 syslog(LOG_ERR, "in move_real_workdir, can't overwrite regular file %s", dest);
274 syslog(LOG_ERR, "in move_real_workdir, can't overwrite regular file %s", dest);
278 rc = clean_dir(dest);
280 syslog(LOG_ERR, "in move_real_workdir, can't clean dir %s", dest);
285 syslog(LOG_ERR, "in move_real_workdir, can't remove dir %s", dest);
289 /* check parent of dest */
290 iter = strrchr(dest, '/');
291 len = iter ? iter - dest : 0;
293 /* is parent existing? */
294 copy = strndupa(dest, len);
298 if (!S_ISDIR(s.st_mode)) {
299 syslog(LOG_ERR, "in move_real_workdir, '%s' isn't a directory", copy);
303 } else if (!parents) {
304 /* parent entry not found but not allowed to create it */
305 syslog(LOG_ERR, "in move_real_workdir, parent directory '%s' not found: %m", copy);
308 /* parent entries to be created */
312 rc = mkdir(copy, mode);
315 if (errno != ENOENT) {
316 syslog(LOG_ERR, "in move_real_workdir, mkdir '%s' failed: %m", copy);
319 while (l && copy[l] != '/')
322 syslog(LOG_ERR, "in move_real_workdir, internal error");
332 rc = mkdir(copy, mode);
333 if (rc && errno != EEXIST) {
334 syslog(LOG_ERR, "in move_real_workdir, mkdir '%s' failed: %m", copy);
342 /* try to rename now */
345 rc = renameat(AT_FDCWD, workdir, AT_FDCWD, dest);
347 syslog(LOG_ERR, "in move_real_workdir, renameat failed %s -> %s: %m", workdir, dest);
351 return set_real_workdir(dest, 0);
354 int move_workdir(const char *dest, int parents, int force)
360 return move_real_workdir(dest, parents, force);
362 rp = realpath(dest, NULL);
364 syslog(LOG_ERR, "realpath failed for %s", dest);
367 rc = move_real_workdir(rp, parents, force);