2 Copyright 2015, 2016 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.
19 #define _DEFAULT_SOURCE
22 #include <sys/types.h>
32 #include "wgtpkg-files.h"
33 #include "wgtpkg-workdir.h"
34 #include "wgtpkg-zip.h"
36 #define MODE_OF_FILE_CREATION 0644
37 #define MODE_OF_DIRECTORY_CREATION 0755
39 #if !defined(USE_LIBZIP)
43 /***********************************************************
45 ***********************************************************/
50 static int is_valid_filename(const char *filename)
56 c = (unsigned char)filename[index];
59 || ((lastsp = (c == 0x20)) && index == 0)
60 || c == 0x7f || c == 0x3c || c == 0x3e
61 || c == 0x3a || c == 0x22
62 || c == 0x5c || c == 0x7c || c == 0x3f
63 || c == 0x2a || c == 0x5e || c == 0x60
64 || c == 0x7b || c == 0x7d || c == 0x21)
66 c = (unsigned char)filename[++index];
71 static int create_directory(char *file, mode_t mode)
74 char *last = strrchr(file, '/');
77 rc = mkdirat(workdirfd, file, mode);
81 else if (errno == ENOENT) {
82 rc = create_directory(file, mode);
84 rc = mkdirat(workdirfd, file, mode);
88 ERROR("can't create directory %s", file);
94 static int create_file(char *file, int fmode, mode_t dmode)
96 int fd = openat(workdirfd, file, O_CREAT|O_WRONLY|O_TRUNC, fmode);
97 if (fd < 0 && errno == ENOENT) {
98 if (!create_directory(file, dmode))
99 fd = openat(workdirfd, file, O_CREAT|O_WRONLY|O_TRUNC, fmode);
102 ERROR("can't create file %s", file);
106 /* read (extract) 'zipfile' in current directory */
107 int zread(const char *zipfile, unsigned long long maxsize)
109 struct filedesc *fdesc;
115 unsigned int count, index;
116 struct zip_file *zfile;
117 struct zip_stat zstat;
122 /* open the zip file */
123 zip = zip_open(zipfile, ZIP_CHECKCONS, &err);
125 ERROR("Can't connect to file %s", zipfile);
129 z64 = zip_get_num_entries(zip, 0);
130 if (z64 < 0 || z64 > UINT_MAX) {
131 ERROR("too many entries in %s", zipfile);
134 count = (unsigned int)z64;
136 /* records the files */
139 for (index = 0 ; index < count ; index++) {
140 err = zip_stat_index(zip, index, ZIP_FL_ENC_GUESS, &zstat);
141 /* check the file name */
142 if (!is_valid_filename(zstat.name)) {
143 ERROR("invalid entry %s found in %s", zstat.name, zipfile);
146 if (zstat.name[0] == '/') {
147 ERROR("absolute entry %s found in %s", zstat.name, zipfile);
150 len = strlen(zstat.name);
152 ERROR("empty entry found in %s", zipfile);
155 if (zstat.name[len - 1] == '/')
157 fdesc = file_add_directory(zstat.name);
162 fdesc = file_add_file(zstat.name);
166 fdesc->zindex = index;
170 if (maxsize && esize > maxsize) {
171 ERROR("extracted size %zu greater than allowed size %llu", esize, maxsize);
175 /* unpack the recorded files */
176 assert(count == file_count());
177 for (index = 0 ; index < count ; index++) {
178 fdesc = file_of_index(index);
179 assert(fdesc != NULL);
180 err = zip_stat_index(zip, fdesc->zindex, ZIP_FL_ENC_GUESS, &zstat);
181 assert(zstat.name[0] != '/');
182 len = strlen(zstat.name);
184 if (zstat.name[len - 1] == '/') {
186 err = create_directory((char*)zstat.name, MODE_OF_DIRECTORY_CREATION);
187 if (err && errno != EEXIST)
191 zfile = zip_fopen_index(zip, fdesc->zindex, 0);
193 ERROR("Can't open %s in %s", zstat.name, zipfile);
196 fd = create_file((char*)zstat.name, MODE_OF_FILE_CREATION, MODE_OF_DIRECTORY_CREATION);
202 sizr = zip_fread(zfile, buffer, sizeof buffer);
204 ERROR("error while reading %s in %s", zstat.name, zipfile);
207 sizw = write(fd, buffer, (size_t)sizr);
209 ERROR("error while writing %s", zstat.name);
212 uz64 -= (size_t)sizw;
237 static int zwr(struct zws *zws, size_t offset)
244 struct zip_source *zsrc;
247 fd = openat(workdirfd, offset ? zws->name : ".", O_DIRECTORY|O_RDONLY);
249 ERROR("opendir %.*s failed in zwr", (int)offset, zws->name);
255 ERROR("opendir %.*s failed in zwr", (int)offset, zws->name);
260 zws->name[offset++] = '/';
263 while (ent != NULL) {
264 len = strlen(ent->d_name);
265 if (ent->d_name[0] == '.' && (len == 1 ||
266 (ent->d_name[1] == '.' && len == 2)))
268 else if (offset + len >= sizeof(zws->name)) {
269 ERROR("name too long in zwr");
270 errno = ENAMETOOLONG;
273 memcpy(zws->name + offset, ent->d_name, 1+len);
274 if (!is_valid_filename(ent->d_name)) {
275 ERROR("invalid name %s", zws->name);
278 switch (ent->d_type) {
280 z64 = zip_dir_add(zws->zip, zws->name, ZIP_FL_ENC_UTF_8);
282 ERROR("zip_dir_add of %s failed", zws->name);
285 err = zwr(zws, offset + len);
290 fd = openat(workdirfd, zws->name, O_RDONLY);
292 ERROR("openat of %s failed", zws->name);
295 fp = fdopen(fd, "r");
297 ERROR("fdopen of %s failed", zws->name);
301 zsrc = zip_source_filep(zws->zip, fp, 0, 0);
303 ERROR("zip_source_file of %s failed", zws->name);
307 z64 = zip_file_add(zws->zip, zws->name, zsrc, ZIP_FL_ENC_UTF_8);
309 ERROR("zip_file_add of %s failed", zws->name);
310 zip_source_free(zsrc);
328 /* write (pack) content of the current directory in 'zipfile' */
329 int zwrite(const char *zipfile)
334 zws.zip = zip_open(zipfile, ZIP_CREATE|ZIP_TRUNCATE, &err);
336 ERROR("Can't open %s for write", zipfile);
345 /***********************************************************
346 * NOT USING LIBZIP: FORKING
347 ***********************************************************/
350 #include <sys/wait.h>
353 extern char **environ;
355 static char *getbin(const char *progname)
361 if (progname[0] == '/')
362 return access(progname, X_OK) ? NULL : strdup(progname);
364 path = getenv("PATH");
365 while(path && *path) {
366 for (i = 0 ; path[i] && path[i] != ':' ; i++)
368 path += i + !!path[i];
370 strcpy(name + i + 1, progname);
371 if (access(name, X_OK) == 0)
372 return realpath(name, NULL);
377 static int zrun(const char *name, const char *args[])
383 binary = getbin(name);
384 if (binary == NULL) {
385 ERROR("error while forking in zrun: can't find %s", name);
391 rc = execve(binary, (char * const*)args, environ);
392 ERROR("can't execute %s in zrun: %m", args[0]);
400 ERROR("error while forking in zrun: %m");
404 /* wait termination of the child */
405 rc = waitid(P_PID, (id_t)rc, &si, WEXITED);
407 ERROR("unexpected wait status in zrun of %s: %m", args[0]);
408 else if (si.si_code != CLD_EXITED)
409 ERROR("unexpected termination status of %s in zrun", args[0]);
410 else if (si.si_status != 0)
411 ERROR("child for %s terminated with error code %d in zwrite", args[0], si.si_status);
417 /* read (extract) 'zipfile' in current directory */
418 int zread(const char *zipfile, unsigned long long maxsize)
431 rc = zrun(args[0], args);
437 /* write (pack) content of the current directory in 'zipfile' */
438 int zwrite(const char *zipfile)
449 return zrun(args[0], args);
453 /***********************************************************
455 ***********************************************************/
457 #if defined(TEST_READ)
458 int main(int ac, char **av)
460 for(av++ ; *av ; av++)
466 #if defined(TEST_WRITE)
467 int main(int ac, char **av)
469 for(av++ ; *av ; av++)