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.
25 #include <sys/types.h>
31 #include "utils-dir.h"
33 static const int dirmode = 0755;
34 char workdir[PATH_MAX] = { 0, };
37 /* removes the working directory */
40 assert(workdirfd >= 0);
41 remove_directory_content_fd(workdirfd);
48 static int set_real_workdir(const char *name, int create)
53 /* check the length */
54 length = strlen(name);
55 if (length >= sizeof workdir) {
56 ERROR("workdir name too long");
61 /* opens the directory */
62 dirfd = openat(AT_FDCWD, name, O_DIRECTORY|O_RDONLY);
64 if (!create || errno != ENOENT) {
65 ERROR("no workdir %s", name);
68 rc = mkdir(name, dirmode);
70 ERROR("can't create workdir %s", name);
73 dirfd = open(name, O_PATH|O_DIRECTORY);
75 ERROR("can't open workdir %s", name);
80 /* close the previous directory if any */
84 memcpy(workdir, name, 1+length);
88 int set_workdir(const char *name, int create)
94 return set_real_workdir(name, create);
96 rp = realpath(name, NULL);
98 ERROR("realpath failed for %s", name);
101 rc = set_real_workdir(rp, create);
106 static int make_real_workdir_base(const char *root, const char *prefix, int reuse)
110 n = snprintf(workdir, sizeof workdir, "%s/%s", root, prefix);
111 if (n >= sizeof workdir) {
112 ERROR("workdir prefix too long");
116 r = (int)(sizeof workdir) - n;
122 /* create a temporary directory */
123 for (i = 0 ; ; i++) {
125 ERROR("exhaustion of workdirs");
128 l = snprintf(workdir + n, r, "%d", i);
130 ERROR("computed workdir too long");
134 if (!mkdir(workdir, dirmode))
136 if (errno != EEXIST) {
137 ERROR("error in creation of workdir %s: %m", workdir);
143 workdirfd = openat(AT_FDCWD, workdir, O_RDONLY|O_DIRECTORY);
145 ERROR("error in onnection to workdir %s: %m", workdir);
153 int make_workdir_base(const char *root, const char *prefix, int reuse)
159 return make_real_workdir_base(root, prefix, reuse);
161 rp = realpath(root, NULL);
163 ERROR("realpath failed for %s", root);
166 rc = make_real_workdir_base(rp, prefix, reuse);
171 int make_workdir(int reuse)
173 return make_workdir_base(".", "PACK", reuse);
176 static int move_real_workdir(const char *dest, int parents, int force)
184 if (strlen(dest) >= sizeof workdir) {
185 ERROR("destination dirname too long");
190 /* if an existing directory exist remove it if force */
193 if (!S_ISDIR(s.st_mode)) {
194 ERROR("in move_real_workdir, can't overwrite regular file %s", dest);
199 ERROR("in move_real_workdir, can't overwrite regular file %s", dest);
203 rc = remove_directory_content(dest);
205 ERROR("in move_real_workdir, can't clean dir %s", dest);
210 ERROR("in move_real_workdir, can't remove dir %s", dest);
214 /* check parent of dest */
215 iter = strrchr(dest, '/');
216 len = iter ? iter - dest : 0;
218 /* is parent existing? */
219 copy = strndupa(dest, len);
223 if (!S_ISDIR(s.st_mode)) {
224 ERROR("in move_real_workdir, '%s' isn't a directory", copy);
228 } else if (!parents) {
229 /* parent entry not found but not allowed to create it */
230 ERROR("in move_real_workdir, parent directory '%s' not found: %m", copy);
232 } else if (create_directory(copy, dirmode, 1)) {
233 ERROR("in move_real_workdir, creation of directory %s failed: %m", copy);
239 /* try to rename now */
242 rc = renameat(AT_FDCWD, workdir, AT_FDCWD, dest);
244 ERROR("in move_real_workdir, renameat failed %s -> %s: %m", workdir, dest);
248 return set_real_workdir(dest, 0);
251 int move_workdir(const char *dest, int parents, int force)
257 return move_real_workdir(dest, parents, force);
259 rp = realpath(dest, NULL);
261 ERROR("realpath failed for %s", dest);
264 rc = move_real_workdir(rp, parents, force);