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.
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 = (ssize_t)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;
248 fd = openat(workdirfd, offset ? zws->name : ".", O_DIRECTORY|O_RDONLY);
250 ERROR("opendir %.*s failed in zwr", (int)offset, zws->name);
256 ERROR("opendir %.*s failed in zwr", (int)offset, zws->name);
261 zws->name[offset++] = '/';
264 while (ent != NULL) {
265 len = strlen(ent->d_name);
266 if (ent->d_name[0] == '.' && (len == 1 ||
267 (ent->d_name[1] == '.' && len == 2)))
269 else if (offset + len >= sizeof(zws->name)) {
270 ERROR("name too long in zwr");
271 errno = ENAMETOOLONG;
274 memcpy(zws->name + offset, ent->d_name, 1+len);
275 if (!is_valid_filename(ent->d_name)) {
276 ERROR("invalid name %s", zws->name);
279 if (ent->d_type == DT_UNKNOWN) {
280 fstatat(fd, ent->d_name, &st, 0);
281 if (S_ISREG(st.st_mode))
282 ent->d_type = DT_REG;
283 else if (S_ISDIR(st.st_mode))
284 ent->d_type = DT_DIR;
286 switch (ent->d_type) {
288 z64 = zip_dir_add(zws->zip, zws->name, ZIP_FL_ENC_UTF_8);
290 ERROR("zip_dir_add of %s failed", zws->name);
293 err = zwr(zws, offset + len);
298 fd = openat(workdirfd, zws->name, O_RDONLY);
300 ERROR("openat of %s failed", zws->name);
303 fp = fdopen(fd, "r");
305 ERROR("fdopen of %s failed", zws->name);
309 zsrc = zip_source_filep(zws->zip, fp, 0, 0);
311 ERROR("zip_source_file of %s failed", zws->name);
315 z64 = zip_file_add(zws->zip, zws->name, zsrc, ZIP_FL_ENC_UTF_8);
317 ERROR("zip_file_add of %s failed", zws->name);
318 zip_source_free(zsrc);
336 /* write (pack) content of the current directory in 'zipfile' */
337 int zwrite(const char *zipfile)
342 zws.zip = zip_open(zipfile, ZIP_CREATE|ZIP_TRUNCATE, &err);
344 ERROR("Can't open %s for write", zipfile);
353 /***********************************************************
354 * NOT USING LIBZIP: FORKING
355 ***********************************************************/
358 #include <sys/wait.h>
361 extern char **environ;
363 static char *getbin(const char *progname)
369 if (progname[0] == '/')
370 return access(progname, X_OK) ? NULL : strdup(progname);
372 path = getenv("PATH");
373 while(path && *path) {
374 for (i = 0 ; path[i] && path[i] != ':' ; i++)
376 path += i + !!path[i];
378 strcpy(name + i + 1, progname);
379 if (access(name, X_OK) == 0)
380 return realpath(name, NULL);
385 static int zrun(const char *name, const char *args[])
391 binary = getbin(name);
392 if (binary == NULL) {
393 ERROR("error while forking in zrun: can't find %s", name);
399 rc = execve(binary, (char * const*)args, environ);
400 ERROR("can't execute %s in zrun: %m", args[0]);
408 ERROR("error while forking in zrun: %m");
412 /* wait termination of the child */
413 rc = waitid(P_PID, (id_t)rc, &si, WEXITED);
415 ERROR("unexpected wait status in zrun of %s: %m", args[0]);
416 else if (si.si_code != CLD_EXITED)
417 ERROR("unexpected termination status of %s in zrun", args[0]);
418 else if (si.si_status != 0)
419 ERROR("child for %s terminated with error code %d in zwrite", args[0], si.si_status);
425 /* read (extract) 'zipfile' in current directory */
426 int zread(const char *zipfile, unsigned long long maxsize)
439 rc = zrun(args[0], args);
445 /* write (pack) content of the current directory in 'zipfile' */
446 int zwrite(const char *zipfile)
457 return zrun(args[0], args);
461 /***********************************************************
463 ***********************************************************/
465 #if defined(TEST_READ)
466 int main(int ac, char **av)
468 for(av++ ; *av ; av++)
474 #if defined(TEST_WRITE)
475 int main(int ac, char **av)
477 for(av++ ; *av ; av++)