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 ERROR("failed to dup the dirfd");
52 dir = fdopendir(dirfd);
54 ERROR("fdopendir failed in clean_dirfd");
60 if (readdir_r(dir, &entry.entry, &ent) != 0) {
61 ERROR("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 ERROR("unlink of %s failed in clean_dirfd", ent->d_name);
76 fd = openat(dirfd, ent->d_name, O_DIRECTORY|O_RDONLY);
78 ERROR("opening directory %s failed in clean_dirfd", ent->d_name);
85 cr = unlinkat(dirfd, ent->d_name, AT_REMOVEDIR);
87 ERROR("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 ERROR("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 ERROR("workdir name too long");
136 /* opens the directory */
137 dirfd = openat(AT_FDCWD, name, O_DIRECTORY|O_RDONLY);
139 if (!create || errno != ENOENT) {
140 ERROR("no workdir %s", name);
143 rc = mkdir(name, mode);
145 ERROR("can't create workdir %s", name);
148 dirfd = open(name, O_PATH|O_DIRECTORY);
150 ERROR("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 ERROR("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 ERROR("workdir prefix too long");
191 r = (int)(sizeof workdir) - n;
197 /* create a temporary directory */
198 for (i = 0 ; ; i++) {
200 ERROR("exhaustion of workdirs");
203 l = snprintf(workdir + n, r, "%d", i);
205 ERROR("computed workdir too long");
209 if (!mkdir(workdir, mode))
211 if (errno != EEXIST) {
212 ERROR("error in creation of workdir %s: %m", workdir);
218 workdirfd = openat(AT_FDCWD, workdir, O_RDONLY|O_DIRECTORY);
220 ERROR("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 ERROR("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 ERROR("destination dirname too long");
265 /* if an existing directory exist remove it if force */
268 if (!S_ISDIR(s.st_mode)) {
269 ERROR("in move_real_workdir, can't overwrite regular file %s", dest);
274 ERROR("in move_real_workdir, can't overwrite regular file %s", dest);
278 rc = clean_dir(dest);
280 ERROR("in move_real_workdir, can't clean dir %s", dest);
285 ERROR("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 ERROR("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 ERROR("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 ERROR("in move_real_workdir, mkdir '%s' failed: %m", copy);
319 while (l && copy[l] != '/')
322 ERROR("in move_real_workdir, internal error");
332 rc = mkdir(copy, mode);
333 if (rc && errno != EEXIST) {
334 ERROR("in move_real_workdir, mkdir '%s' failed: %m", copy);
342 /* try to rename now */
345 rc = renameat(AT_FDCWD, workdir, AT_FDCWD, dest);
347 ERROR("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 ERROR("realpath failed for %s", dest);
367 rc = move_real_workdir(rp, parents, force);