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 _BSD_SOURCE /* see readdir */
22 #include <sys/types.h>
34 #define MODE_OF_FILE_CREATION 0640
35 #define MODE_OF_DIRECTORY_CREATION 0750
37 #if !defined(USE_LIBZIP)
41 /***********************************************************
43 ***********************************************************/
48 static int is_valid_filename(const char *filename)
54 c = (unsigned char)filename[index];
57 || ((lastsp = (c == 0x20)) && index == 0)
58 || c == 0x7f || c == 0x3c || c == 0x3e
59 || c == 0x3a || c == 0x22
60 || c == 0x5c || c == 0x7c || c == 0x3f
61 || c == 0x2a || c == 0x5e || c == 0x60
62 || c == 0x7b || c == 0x7d || c == 0x21)
64 c = (unsigned char)filename[++index];
69 static int create_directory(char *file, int mode)
72 char *last = strrchr(file, '/');
75 rc = mkdirat(workdirfd, file, mode);
79 else if (errno == ENOENT) {
80 rc = create_directory(file, mode);
82 rc = mkdirat(workdirfd, file, mode);
86 ERROR("can't create directory %s", file);
92 static int create_file(char *file, int fmode, int dmode)
94 int fd = openat(workdirfd, file, O_CREAT|O_WRONLY|O_TRUNC, fmode);
95 if (fd < 0 && errno == ENOENT) {
96 if (!create_directory(file, dmode))
97 fd = openat(workdirfd, file, O_CREAT|O_WRONLY|O_TRUNC, fmode);
100 ERROR("can't create file %s", file);
104 /* read (extract) 'zipfile' in current directory */
105 int zread(const char *zipfile, unsigned long long maxsize)
107 struct filedesc *fdesc;
111 unsigned int count, index;
112 struct zip_file *zfile;
113 struct zip_stat zstat;
118 /* open the zip file */
119 zip = zip_open(zipfile, ZIP_CHECKCONS, &err);
121 ERROR("Can't connect to file %s", zipfile);
125 z64 = zip_get_num_entries(zip, 0);
126 if (z64 < 0 || z64 > UINT_MAX) {
127 ERROR("too many entries in %s", zipfile);
130 count = (unsigned int)z64;
132 /* records the files */
135 for (index = 0 ; index < count ; index++) {
136 err = zip_stat_index(zip, index, ZIP_FL_ENC_GUESS, &zstat);
137 /* check the file name */
138 if (!is_valid_filename(zstat.name)) {
139 ERROR("invalid entry %s found in %s", zstat.name, zipfile);
142 if (zstat.name[0] == '/') {
143 ERROR("absolute entry %s found in %s", zstat.name, zipfile);
146 len = strlen(zstat.name);
148 ERROR("empty entry found in %s", zipfile);
151 if (zstat.size == 0) {
153 if (zstat.name[len - 1] != '/') {
154 ERROR("bad directory name %s in %s", zstat.name, zipfile);
158 fdesc = file_add_directory(zstat.name);
161 if (zstat.name[len - 1] == '/') {
162 ERROR("bad file name %s in %s", zstat.name, zipfile);
168 fdesc = file_add_file(zstat.name);
172 fdesc->zindex = index;
176 if (maxsize && esize > maxsize) {
177 ERROR("extracted size %zu greater than allowed size %llu", esize, maxsize);
181 /* unpack the recorded files */
182 assert(count == file_count());
183 for (index = 0 ; index < count ; index++) {
184 fdesc = file_of_index(index);
185 assert(fdesc != NULL);
186 err = zip_stat_index(zip, fdesc->zindex, ZIP_FL_ENC_GUESS, &zstat);
187 assert(zstat.name[0] != '/');
188 if (zstat.size == 0) {
190 err = create_directory((char*)zstat.name, MODE_OF_DIRECTORY_CREATION);
191 if (err && errno != EEXIST)
195 zfile = zip_fopen_index(zip, fdesc->zindex, 0);
197 ERROR("Can't open %s in %s", zstat.name, zipfile);
200 fd = create_file((char*)zstat.name, MODE_OF_FILE_CREATION, MODE_OF_DIRECTORY_CREATION);
206 sizr = zip_fread(zfile, buffer, sizeof buffer);
208 ERROR("error while reading %s in %s", zstat.name, zipfile);
211 sizw = write(fd, buffer, sizr);
213 ERROR("error while writing %s", zstat.name);
241 static int zwr(struct zws *zws, int offset)
247 struct zip_source *zsrc;
250 fd = openat(workdirfd, offset ? zws->name : ".", O_DIRECTORY|O_RDONLY);
252 ERROR("opendir %.*s failed in zwr", offset, zws->name);
258 ERROR("opendir %.*s failed in zwr", offset, zws->name);
263 zws->name[offset++] = '/';
266 while (ent != NULL) {
267 len = strlen(ent->d_name);
268 if (ent->d_name[0] == '.' && (len == 1 ||
269 (ent->d_name[1] == '.' && len == 2)))
271 else if (offset + len >= sizeof(zws->name)) {
272 ERROR("name too long in zwr");
273 errno = ENAMETOOLONG;
276 memcpy(zws->name + offset, ent->d_name, 1+len);
277 if (!is_valid_filename(ent->d_name)) {
278 ERROR("invalid name %s", zws->name);
281 switch (ent->d_type) {
283 z64 = zip_dir_add(zws->zip, zws->name, ZIP_FL_ENC_UTF_8);
285 ERROR("zip_dir_add of %s failed", zws->name);
288 err = zwr(zws, offset + len);
293 fd = openat(workdirfd, zws->name, O_RDONLY);
295 ERROR("openat of %s failed", zws->name);
298 fp = fdopen(fd, "r");
300 ERROR("fdopen of %s failed", zws->name);
304 zsrc = zip_source_filep(zws->zip, fp, 0, 0);
306 ERROR("zip_source_file of %s failed", zws->name);
310 z64 = zip_file_add(zws->zip, zws->name, zsrc, ZIP_FL_ENC_UTF_8);
312 ERROR("zip_file_add of %s failed", zws->name);
313 zip_source_free(zsrc);
331 /* write (pack) content of the current directory in 'zipfile' */
332 int zwrite(const char *zipfile)
337 zws.zip = zip_open(zipfile, ZIP_CREATE|ZIP_TRUNCATE, &err);
339 ERROR("Can't open %s for write", zipfile);
348 /***********************************************************
349 * NOT USING LIBZIP: FORKING
350 ***********************************************************/
353 #include <sys/wait.h>
355 extern char **environ;
357 static int zrun(const char *path, const char *args[])
365 ERROR("error while forking in zrun: %m");
369 rc = execve(realpath(path, NULL), (char * const*)args, environ);
370 ERROR("can't execute %s in zrun: %m", args[0]);
374 /* wait termination of the child */
375 rc = waitid(P_PID, (id_t)rc, &si, WEXITED);
377 ERROR("unexpected wait status in zrun of %s: %m", args[0]);
378 else if (si.si_code != CLD_EXITED)
379 ERROR("unexpected termination status of %s in zrun", args[0]);
380 else if (si.si_status != 0)
381 ERROR("child for %s terminated with error code %d in zwrite", args[0], si.si_status);
387 /* read (extract) 'zipfile' in current directory */
388 int zread(const char *zipfile, unsigned long long maxsize)
401 rc = zrun(PATH_TO_UNZIP, args);
407 /* write (pack) content of the current directory in 'zipfile' */
408 int zwrite(const char *zipfile)
419 return zrun(PATH_TO_ZIP, args);
423 /***********************************************************
425 ***********************************************************/
427 #if defined(TEST_READ)
428 int main(int ac, char **av)
430 for(av++ ; *av ; av++)
436 #if defined(TEST_WRITE)
437 int main(int ac, char **av)
439 for(av++ ; *av ; av++)