2 Copyright (C) 2015-2019 IoT.bzh
4 author: José Bollo <jose.bollo@iot.bzh>
6 Licensed under the Apache License, Version 2.0 (the "License");
7 you may not use this file except in compliance with the License.
8 You may obtain a copy of the License at
10 http://www.apache.org/licenses/LICENSE-2.0
12 Unless required by applicable law or agreed to in writing, software
13 distributed under the License is distributed on an "AS IS" BASIS,
14 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 See the License for the specific language governing permissions and
16 limitations under the License.
29 #include <sys/types.h>
34 #include "wgtpkg-workdir.h"
35 #include "utils-dir.h"
37 static const mode_t dirmode = 0755;
38 char workdir[PATH_MAX] = { 0, };
41 /* removes the working directory */
44 assert(workdirfd >= 0);
45 remove_directory_content_fd(workdirfd);
52 static void put_workdir(int fd, const char *name, size_t length)
54 /* close the previous directory if any */
58 /* copy the name and the fd if existing */
65 assert(length < sizeof workdir);
66 memcpy(workdir, name, 1 + length);
71 int set_workdir(const char *name, int create)
76 /* check the length */
77 length = strlen(name);
78 if (length >= sizeof workdir) {
79 ERROR("workdir name too long");
85 if (length == 1 && name[0] == '.') {
86 put_workdir(AT_FDCWD, name, length);
90 /* opens the directory */
91 dirfd = openat(AT_FDCWD, name, O_PATH|O_DIRECTORY|O_RDONLY);
93 if (errno != ENOENT) {
94 ERROR("error while opening workdir %s: %m", name);
98 ERROR("workdir %s doesn't exist", name);
101 rc = mkdirat(AT_FDCWD, name, dirmode);
103 ERROR("can't create workdir %s", name);
106 dirfd = openat(AT_FDCWD, name, O_PATH|O_DIRECTORY|O_RDONLY);
108 ERROR("can't open workdir %s", name);
113 /* record new workdir */
114 put_workdir(dirfd, name, length);
118 int make_workdir(const char *root, const char *prefix, int reuse)
122 put_workdir(AT_FDCWD, ".", 1);
124 n = snprintf(workdir, sizeof workdir, "%s/%s", root, prefix);
125 if (n >= (int)sizeof workdir) {
126 ERROR("workdir prefix too long");
130 r = (int)(sizeof workdir) - n;
132 /* create a temporary directory */
133 for (i = 0 ; ; i++) {
135 ERROR("exhaustion of workdirs");
138 l = snprintf(workdir + n, (unsigned)r, "%d", i);
140 ERROR("computed workdir too long");
144 if (!mkdirat(AT_FDCWD, workdir, dirmode))
146 if (errno != EEXIST) {
147 ERROR("error in creation of workdir %s: %m", workdir);
153 workdirfd = openat(AT_FDCWD, workdir, O_RDONLY|O_DIRECTORY);
155 ERROR("error in onnection to workdir %s: %m", workdir);
163 int move_workdir(const char *dest, int parents, int force)
172 if (strlen(dest) >= sizeof workdir) {
173 ERROR("destination dirname too long");
178 /* if an existing directory exist remove it if force */
181 if (!S_ISDIR(s.st_mode)) {
182 ERROR("in move_workdir, can't overwrite regular file %s", dest);
187 ERROR("in move_workdir, can't overwrite regular file %s", dest);
191 rc = remove_directory_content(dest);
193 ERROR("in move_workdir, can't clean dir %s", dest);
198 ERROR("in move_workdir, can't remove dir %s", dest);
202 /* check parent of dest */
203 iter = strrchr(dest, '/');
204 len = iter ? (size_t)(iter - dest) : 0;
206 /* is parent existing? */
207 copy = strndupa(dest, len);
211 if (!S_ISDIR(s.st_mode)) {
212 ERROR("in move_workdir, '%s' isn't a directory", copy);
216 } else if (!parents) {
217 /* parent entry not found but not allowed to create it */
218 ERROR("in move_workdir, parent directory '%s' not found: %m", copy);
220 } else if (create_directory(copy, dirmode, 1)) {
221 ERROR("in move_workdir, creation of directory %s failed: %m", copy);
227 /* try to rename now */
230 rc = renameat(AT_FDCWD, workdir, AT_FDCWD, dest);
232 ERROR("in move_workdir, renameat failed %s -> %s: %m", workdir, dest);
236 return set_workdir(dest, 0);