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, 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 len = strlen(zstat.name);
182 if (zstat.name[len - 1] == '/') {
184 err = create_directory((char*)zstat.name, MODE_OF_DIRECTORY_CREATION);
185 if (err && errno != EEXIST)
189 zfile = zip_fopen_index(zip, fdesc->zindex, 0);
191 ERROR("Can't open %s in %s", zstat.name, zipfile);
194 fd = create_file((char*)zstat.name, MODE_OF_FILE_CREATION, MODE_OF_DIRECTORY_CREATION);
200 sizr = zip_fread(zfile, buffer, sizeof buffer);
202 ERROR("error while reading %s in %s", zstat.name, zipfile);
205 sizw = write(fd, buffer, sizr);
207 ERROR("error while writing %s", zstat.name);
235 static int zwr(struct zws *zws, int offset)
241 struct zip_source *zsrc;
244 fd = openat(workdirfd, offset ? zws->name : ".", O_DIRECTORY|O_RDONLY);
246 ERROR("opendir %.*s failed in zwr", offset, zws->name);
252 ERROR("opendir %.*s failed in zwr", offset, zws->name);
257 zws->name[offset++] = '/';
260 while (ent != NULL) {
261 len = strlen(ent->d_name);
262 if (ent->d_name[0] == '.' && (len == 1 ||
263 (ent->d_name[1] == '.' && len == 2)))
265 else if (offset + len >= sizeof(zws->name)) {
266 ERROR("name too long in zwr");
267 errno = ENAMETOOLONG;
270 memcpy(zws->name + offset, ent->d_name, 1+len);
271 if (!is_valid_filename(ent->d_name)) {
272 ERROR("invalid name %s", zws->name);
275 switch (ent->d_type) {
277 z64 = zip_dir_add(zws->zip, zws->name, ZIP_FL_ENC_UTF_8);
279 ERROR("zip_dir_add of %s failed", zws->name);
282 err = zwr(zws, offset + len);
287 fd = openat(workdirfd, zws->name, O_RDONLY);
289 ERROR("openat of %s failed", zws->name);
292 fp = fdopen(fd, "r");
294 ERROR("fdopen of %s failed", zws->name);
298 zsrc = zip_source_filep(zws->zip, fp, 0, 0);
300 ERROR("zip_source_file of %s failed", zws->name);
304 z64 = zip_file_add(zws->zip, zws->name, zsrc, ZIP_FL_ENC_UTF_8);
306 ERROR("zip_file_add of %s failed", zws->name);
307 zip_source_free(zsrc);
325 /* write (pack) content of the current directory in 'zipfile' */
326 int zwrite(const char *zipfile)
331 zws.zip = zip_open(zipfile, ZIP_CREATE|ZIP_TRUNCATE, &err);
333 ERROR("Can't open %s for write", zipfile);
342 /***********************************************************
343 * NOT USING LIBZIP: FORKING
344 ***********************************************************/
347 #include <sys/wait.h>
350 extern char **environ;
352 static char *getbin(const char *progname)
358 if (progname[0] == '/')
359 return access(progname, X_OK) ? NULL : strdup(progname);
361 path = getenv("PATH");
362 while(path && *path) {
363 for (i = 0 ; path[i] && path[i] != ':' ; i++)
365 path += i + !!path[i];
367 strcpy(name + i + 1, progname);
368 if (access(name, X_OK) == 0)
369 return realpath(name, NULL);
374 static int zrun(const char *name, const char *args[])
380 binary = getbin(name);
381 if (binary == NULL) {
382 ERROR("error while forking in zrun: can't find %s", name);
388 rc = execve(binary, (char * const*)args, environ);
389 ERROR("can't execute %s in zrun: %m", args[0]);
397 ERROR("error while forking in zrun: %m");
401 /* wait termination of the child */
402 rc = waitid(P_PID, (id_t)rc, &si, WEXITED);
404 ERROR("unexpected wait status in zrun of %s: %m", args[0]);
405 else if (si.si_code != CLD_EXITED)
406 ERROR("unexpected termination status of %s in zrun", args[0]);
407 else if (si.si_status != 0)
408 ERROR("child for %s terminated with error code %d in zwrite", args[0], si.si_status);
414 /* read (extract) 'zipfile' in current directory */
415 int zread(const char *zipfile, unsigned long long maxsize)
428 rc = zrun(args[0], args);
434 /* write (pack) content of the current directory in 'zipfile' */
435 int zwrite(const char *zipfile)
446 return zrun(args[0], args);
450 /***********************************************************
452 ***********************************************************/
454 #if defined(TEST_READ)
455 int main(int ac, char **av)
457 for(av++ ; *av ; av++)
463 #if defined(TEST_WRITE)
464 int main(int ac, char **av)
466 for(av++ ; *av ; av++)