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>
30 #include "utils-dir.h"
32 static const int dirmode = 0755;
33 char workdir[PATH_MAX] = { 0, };
36 /* removes the working directory */
39 assert(workdirfd >= 0);
40 remove_directory_content_fd(workdirfd);
47 static int set_real_workdir(const char *name, int create)
52 /* check the length */
53 length = strlen(name);
54 if (length >= sizeof workdir) {
55 ERROR("workdir name too long");
60 /* opens the directory */
61 dirfd = openat(AT_FDCWD, name, O_DIRECTORY|O_RDONLY);
63 if (!create || errno != ENOENT) {
64 ERROR("no workdir %s", name);
67 rc = mkdir(name, dirmode);
69 ERROR("can't create workdir %s", name);
72 dirfd = open(name, O_PATH|O_DIRECTORY);
74 ERROR("can't open workdir %s", name);
79 /* close the previous directory if any */
83 memcpy(workdir, name, 1+length);
87 int set_workdir(const char *name, int create)
93 return set_real_workdir(name, create);
95 rp = realpath(name, NULL);
97 ERROR("realpath failed for %s", name);
100 rc = set_real_workdir(rp, create);
105 static int make_real_workdir_base(const char *root, const char *prefix, int reuse)
109 n = snprintf(workdir, sizeof workdir, "%s/%s", root, prefix);
110 if (n >= sizeof workdir) {
111 ERROR("workdir prefix too long");
115 r = (int)(sizeof workdir) - n;
121 /* create a temporary directory */
122 for (i = 0 ; ; i++) {
124 ERROR("exhaustion of workdirs");
127 l = snprintf(workdir + n, r, "%d", i);
129 ERROR("computed workdir too long");
133 if (!mkdir(workdir, dirmode))
135 if (errno != EEXIST) {
136 ERROR("error in creation of workdir %s: %m", workdir);
142 workdirfd = openat(AT_FDCWD, workdir, O_RDONLY|O_DIRECTORY);
144 ERROR("error in onnection to workdir %s: %m", workdir);
152 int make_workdir_base(const char *root, const char *prefix, int reuse)
158 return make_real_workdir_base(root, prefix, reuse);
160 rp = realpath(root, NULL);
162 ERROR("realpath failed for %s", root);
165 rc = make_real_workdir_base(rp, prefix, reuse);
170 int make_workdir(int reuse)
172 return make_workdir_base(".", "PACK", reuse);
175 static int move_real_workdir(const char *dest, int parents, int force)
183 if (strlen(dest) >= sizeof workdir) {
184 ERROR("destination dirname too long");
189 /* if an existing directory exist remove it if force */
192 if (!S_ISDIR(s.st_mode)) {
193 ERROR("in move_real_workdir, can't overwrite regular file %s", dest);
198 ERROR("in move_real_workdir, can't overwrite regular file %s", dest);
202 rc = remove_directory_content(dest);
204 ERROR("in move_real_workdir, can't clean dir %s", dest);
209 ERROR("in move_real_workdir, can't remove dir %s", dest);
213 /* check parent of dest */
214 iter = strrchr(dest, '/');
215 len = iter ? iter - dest : 0;
217 /* is parent existing? */
218 copy = strndupa(dest, len);
222 if (!S_ISDIR(s.st_mode)) {
223 ERROR("in move_real_workdir, '%s' isn't a directory", copy);
227 } else if (!parents) {
228 /* parent entry not found but not allowed to create it */
229 ERROR("in move_real_workdir, parent directory '%s' not found: %m", copy);
231 } else if (create_directory(copy, dirmode, 1)) {
232 ERROR("in move_real_workdir, creation of directory %s failed: %m", copy);
238 /* try to rename now */
241 rc = renameat(AT_FDCWD, workdir, AT_FDCWD, dest);
243 ERROR("in move_real_workdir, renameat failed %s -> %s: %m", workdir, dest);
247 return set_real_workdir(dest, 0);
250 int move_workdir(const char *dest, int parents, int force)
256 return move_real_workdir(dest, parents, force);
258 rp = realpath(dest, NULL);
260 ERROR("realpath failed for %s", dest);
263 rc = move_real_workdir(rp, parents, force);