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 0640
37 #define MODE_OF_DIRECTORY_CREATION 0750
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, int 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, int 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;
113 unsigned int count, index;
114 struct zip_file *zfile;
115 struct zip_stat zstat;
120 /* open the zip file */
121 zip = zip_open(zipfile, ZIP_CHECKCONS, &err);
123 ERROR("Can't connect to file %s", zipfile);
127 z64 = zip_get_num_entries(zip, 0);
128 if (z64 < 0 || z64 > UINT_MAX) {
129 ERROR("too many entries in %s", zipfile);
132 count = (unsigned int)z64;
134 /* records the files */
137 for (index = 0 ; index < count ; index++) {
138 err = zip_stat_index(zip, index, ZIP_FL_ENC_GUESS, &zstat);
139 /* check the file name */
140 if (!is_valid_filename(zstat.name)) {
141 ERROR("invalid entry %s found in %s", zstat.name, zipfile);
144 if (zstat.name[0] == '/') {
145 ERROR("absolute entry %s found in %s", zstat.name, zipfile);
148 len = strlen(zstat.name);
150 ERROR("empty entry found in %s", zipfile);
153 if (zstat.name[len - 1] == '/')
155 fdesc = file_add_directory(zstat.name);
160 fdesc = file_add_file(zstat.name);
164 fdesc->zindex = index;
168 if (maxsize && esize > maxsize) {
169 ERROR("extracted size %zu greater than allowed size %llu", esize, maxsize);
173 /* unpack the recorded files */
174 assert(count == file_count());
175 for (index = 0 ; index < count ; index++) {
176 fdesc = file_of_index(index);
177 assert(fdesc != NULL);
178 err = zip_stat_index(zip, fdesc->zindex, ZIP_FL_ENC_GUESS, &zstat);
179 assert(zstat.name[0] != '/');
180 if (zstat.size == 0) {
182 err = create_directory((char*)zstat.name, MODE_OF_DIRECTORY_CREATION);
183 if (err && errno != EEXIST)
187 zfile = zip_fopen_index(zip, fdesc->zindex, 0);
189 ERROR("Can't open %s in %s", zstat.name, zipfile);
192 fd = create_file((char*)zstat.name, MODE_OF_FILE_CREATION, MODE_OF_DIRECTORY_CREATION);
198 sizr = zip_fread(zfile, buffer, sizeof buffer);
200 ERROR("error while reading %s in %s", zstat.name, zipfile);
203 sizw = write(fd, buffer, sizr);
205 ERROR("error while writing %s", zstat.name);
233 static int zwr(struct zws *zws, int offset)
239 struct zip_source *zsrc;
242 fd = openat(workdirfd, offset ? zws->name : ".", O_DIRECTORY|O_RDONLY);
244 ERROR("opendir %.*s failed in zwr", offset, zws->name);
250 ERROR("opendir %.*s failed in zwr", offset, zws->name);
255 zws->name[offset++] = '/';
258 while (ent != NULL) {
259 len = strlen(ent->d_name);
260 if (ent->d_name[0] == '.' && (len == 1 ||
261 (ent->d_name[1] == '.' && len == 2)))
263 else if (offset + len >= sizeof(zws->name)) {
264 ERROR("name too long in zwr");
265 errno = ENAMETOOLONG;
268 memcpy(zws->name + offset, ent->d_name, 1+len);
269 if (!is_valid_filename(ent->d_name)) {
270 ERROR("invalid name %s", zws->name);
273 switch (ent->d_type) {
275 z64 = zip_dir_add(zws->zip, zws->name, ZIP_FL_ENC_UTF_8);
277 ERROR("zip_dir_add of %s failed", zws->name);
280 err = zwr(zws, offset + len);
285 fd = openat(workdirfd, zws->name, O_RDONLY);
287 ERROR("openat of %s failed", zws->name);
290 fp = fdopen(fd, "r");
292 ERROR("fdopen of %s failed", zws->name);
296 zsrc = zip_source_filep(zws->zip, fp, 0, 0);
298 ERROR("zip_source_file of %s failed", zws->name);
302 z64 = zip_file_add(zws->zip, zws->name, zsrc, ZIP_FL_ENC_UTF_8);
304 ERROR("zip_file_add of %s failed", zws->name);
305 zip_source_free(zsrc);
323 /* write (pack) content of the current directory in 'zipfile' */
324 int zwrite(const char *zipfile)
329 zws.zip = zip_open(zipfile, ZIP_CREATE|ZIP_TRUNCATE, &err);
331 ERROR("Can't open %s for write", zipfile);
340 /***********************************************************
341 * NOT USING LIBZIP: FORKING
342 ***********************************************************/
345 #include <sys/wait.h>
348 extern char **environ;
350 static char *getbin(const char *progname)
356 if (progname[0] == '/')
357 return access(progname, X_OK) ? NULL : strdup(progname);
359 path = getenv("PATH");
360 while(path && *path) {
361 for (i = 0 ; path[i] && path[i] != ':' ; i++)
363 path += i + !!path[i];
365 strcpy(name + i + 1, progname);
366 if (access(name, X_OK) == 0)
367 return realpath(name, NULL);
372 static int zrun(const char *name, const char *args[])
378 binary = getbin(name);
379 if (binary == NULL) {
380 ERROR("error while forking in zrun: can't find %s", name);
386 rc = execve(binary, (char * const*)args, environ);
387 ERROR("can't execute %s in zrun: %m", args[0]);
395 ERROR("error while forking in zrun: %m");
399 /* wait termination of the child */
400 rc = waitid(P_PID, (id_t)rc, &si, WEXITED);
402 ERROR("unexpected wait status in zrun of %s: %m", args[0]);
403 else if (si.si_code != CLD_EXITED)
404 ERROR("unexpected termination status of %s in zrun", args[0]);
405 else if (si.si_status != 0)
406 ERROR("child for %s terminated with error code %d in zwrite", args[0], si.si_status);
412 /* read (extract) 'zipfile' in current directory */
413 int zread(const char *zipfile, unsigned long long maxsize)
426 rc = zrun(args[0], args);
432 /* write (pack) content of the current directory in 'zipfile' */
433 int zwrite(const char *zipfile)
444 return zrun(args[0], args);
448 /***********************************************************
450 ***********************************************************/
452 #if defined(TEST_READ)
453 int main(int ac, char **av)
455 for(av++ ; *av ; av++)
461 #if defined(TEST_WRITE)
462 int main(int ac, char **av)
464 for(av++ ; *av ; av++)