2 Copyright 2015, 2016, 2017 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.
32 #include "wgtpkg-workdir.h"
33 #include "wgtpkg-files.h"
37 struct filedesc **files;
40 static struct fdb allfiles = { .count = 0, .files = NULL };
41 static struct fdb allsignatures = { .count = 0, .files = NULL };
43 static const char author_file[] = "author-signature.xml";
44 static const char distributor_file_prefix[] = "signature";
45 static const char distributor_file_suffix[] = ".xml";
47 static unsigned int what_signature(const char *name)
49 unsigned int len, id, nid;
51 if (!strcmp(name, author_file))
54 len = sizeof(distributor_file_prefix)-1;
55 if (strncmp(name, distributor_file_prefix, len))
57 if (name[len] <= '0' || name[len] > '9')
59 id = (unsigned int)(name[len++] - '0');
60 while ('0' <= name[len] && name[len] <= '9') {
61 nid = 10 * id + (unsigned int)(name[len++] - '0');
62 if (nid < id || nid == UINT_MAX) {
63 WARNING("number too big for %s", name);
68 if (strcmp(name+len, distributor_file_suffix))
74 static struct filedesc *get_filedesc(const char *name, int create)
77 unsigned int low, up, mid, sig;
78 struct filedesc *result, **grow;
84 mid = (low + up) >> 1;
85 result = allfiles.files[mid];
86 cmp = strcmp(result->name, name);
88 return result; /* found */
95 /* not found, can create ? */
99 sig = what_signature(name);
102 grow = realloc(allfiles.files, (allfiles.count + 1) * sizeof(struct filedesc *));
104 ERROR("realloc failed in get_filedesc");
107 allfiles.files = grow;
110 grow = realloc(allsignatures.files, (allsignatures.count + 1) * sizeof(struct filedesc *));
112 ERROR("second realloc failed in get_filedesc");
115 allsignatures.files = grow;
118 result = malloc(sizeof(struct filedesc) + strlen(name));
120 ERROR("calloc failed in get_filedesc");
125 result->type = type_unset;
126 result->flags = sig == 0 ? 0 : sig == UINT_MAX ? flag_author_signature : flag_distributor_signature;
128 result->signum = sig;
129 strcpy(result->name, name);
132 if (low < allfiles.count)
133 memmove(allfiles.files+low+1, allfiles.files+low, (allfiles.count - low) * sizeof(struct filedesc *));
134 allfiles.files[low] = result;
137 for (low = 0 ; low < allsignatures.count && sig > allsignatures.files[low]->signum ; low++);
138 if (low < allsignatures.count)
139 memmove(allsignatures.files+low+1, allsignatures.files+low, (allsignatures.count - low) * sizeof(struct filedesc *));
140 allsignatures.files[low] = result;
141 allsignatures.count++;
148 static struct filedesc *file_add(const char *name, enum entrytype type)
150 struct filedesc *desc;
152 desc = get_filedesc(name, 1);
155 else if (desc->type == type_unset)
158 ERROR("redeclaration of %s in file_add", name);
169 allsignatures.count = 0;
170 for (i = 0 ; i < allfiles.count ; i++)
171 free(allfiles.files[i]);
175 unsigned int file_count()
177 return allfiles.count;
180 struct filedesc *file_of_index(unsigned int index)
182 assert(index < allfiles.count);
183 return allfiles.files[index];
186 struct filedesc *file_of_name(const char *name)
188 return get_filedesc(name, 0);
191 struct filedesc *file_add_directory(const char *name)
193 return file_add(name, type_directory);
196 struct filedesc *file_add_file(const char *name)
198 return file_add(name, type_file);
201 unsigned int signature_count()
203 return allsignatures.count;
206 struct filedesc *signature_of_index(unsigned int index)
208 assert(index < allsignatures.count);
209 return allsignatures.files[index];
212 struct filedesc *get_signature(unsigned int number)
218 for (idx = 0 ; idx < allsignatures.count ; idx++)
219 if (allsignatures.files[idx]->signum == number)
220 return allsignatures.files[idx];
224 struct filedesc *create_signature(unsigned int number)
226 struct filedesc *result;
231 if (number == 0 || number == UINT_MAX)
232 len = asprintf(&name, "%s", author_file);
234 len = asprintf(&name, "%s%u%s", distributor_file_prefix, number, distributor_file_suffix);
237 ERROR("asprintf failed in create_signature");
240 result = file_of_name(name);
242 result = file_add_file(name);
249 /* remove flags that are not related to being signature */
250 void file_clear_flags()
253 for (i = 0 ; i < allfiles.count ; i++)
254 allfiles.files[i]->flags &= flag_signature;
257 static int fill_files_rec(char name[PATH_MAX], unsigned offset)
265 fd = openat(workdirfd, offset ? name : ".", O_DIRECTORY|O_RDONLY);
267 ERROR("openat %.*s failed in fill_files_rec", offset, name);
272 ERROR("opendir %.*s failed in fill_files_rec", offset, name);
277 name[offset++] = '/';
280 while (ent != NULL) {
281 len = (unsigned)strlen(ent->d_name);
282 if (ent->d_name[0] == '.' && (len == 1 ||
283 (ent->d_name[1] == '.' && len == 2)))
285 else if (offset + len >= PATH_MAX) {
287 ERROR("name too long in fill_files_rec");
288 errno = ENAMETOOLONG;
291 memcpy(name + offset, ent->d_name, 1+len);
292 if (ent->d_type == DT_UNKNOWN) {
293 fstatat(fd, ent->d_name, &st, 0);
294 if (S_ISREG(st.st_mode))
295 ent->d_type = DT_REG;
296 else if (S_ISDIR(st.st_mode))
297 ent->d_type = DT_DIR;
299 switch (ent->d_type) {
301 if (file_add_directory(name) == NULL) {
305 err = fill_files_rec(name, offset + len);
312 if (file_add_file(name) == NULL) {
331 return fill_files_rec(name, 0);