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 */
23 #include <sys/types.h>
36 #if !defined(MODE_OF_FILE_CREATION)
37 #define MODE_OF_FILE_CREATION 0640
39 #if !defined(MODE_OF_DIRECTORY_CREATION)
40 #define MODE_OF_DIRECTORY_CREATION 0750
43 static int is_valid_filename(const char *filename)
49 c = (unsigned char)filename[index];
52 || ((lastsp = (c == 0x20)) && index == 0)
53 || c == 0x7f || c == 0x3c || c == 0x3e
54 || c == 0x3a || c == 0x22
55 || c == 0x5c || c == 0x7c || c == 0x3f
56 || c == 0x2a || c == 0x5e || c == 0x60
57 || c == 0x7b || c == 0x7d || c == 0x21)
59 c = (unsigned char)filename[++index];
64 static int create_directory(char *file, int mode)
67 char *last = strrchr(file, '/');
70 rc = mkdirat(workdirfd, file, mode);
74 else if (errno == ENOENT) {
75 rc = create_directory(file, mode);
77 rc = mkdirat(workdirfd, file, mode);
81 ERROR("can't create directory %s", file);
87 static int create_file(char *file, int fmode, int dmode)
89 int fd = openat(workdirfd, file, O_CREAT|O_WRONLY|O_TRUNC, fmode);
90 if (fd < 0 && errno == ENOENT) {
91 if (!create_directory(file, dmode))
92 fd = openat(workdirfd, file, O_CREAT|O_WRONLY|O_TRUNC, fmode);
95 ERROR("can't create file %s", file);
99 /* read (extract) 'zipfile' in current directory */
100 int zread(const char *zipfile, unsigned long long maxsize)
102 struct filedesc *fdesc;
106 unsigned int count, index;
107 struct zip_file *zfile;
108 struct zip_stat zstat;
113 /* open the zip file */
114 zip = zip_open(zipfile, ZIP_CHECKCONS, &err);
116 ERROR("Can't connect to file %s", zipfile);
120 z64 = zip_get_num_entries(zip, 0);
121 if (z64 < 0 || z64 > UINT_MAX) {
122 ERROR("too many entries in %s", zipfile);
125 count = (unsigned int)z64;
127 /* records the files */
130 for (index = 0 ; index < count ; index++) {
131 err = zip_stat_index(zip, index, ZIP_FL_ENC_GUESS, &zstat);
132 /* check the file name */
133 if (!is_valid_filename(zstat.name)) {
134 ERROR("invalid entry %s found in %s", zstat.name, zipfile);
137 if (zstat.name[0] == '/') {
138 ERROR("absolute entry %s found in %s", zstat.name, zipfile);
141 len = strlen(zstat.name);
143 ERROR("empty entry found in %s", zipfile);
146 if (zstat.size == 0) {
148 if (zstat.name[len - 1] != '/') {
149 ERROR("bad directory name %s in %s", zstat.name, zipfile);
153 fdesc = file_add_directory(zstat.name);
156 if (zstat.name[len - 1] == '/') {
157 ERROR("bad file name %s in %s", zstat.name, zipfile);
163 fdesc = file_add_file(zstat.name);
167 fdesc->zindex = index;
171 if (maxsize && esize > maxsize) {
172 ERROR("extracted size %zu greater than allowed size %llu", esize, maxsize);
176 /* unpack the recorded files */
177 assert(count == file_count());
178 for (index = 0 ; index < count ; index++) {
179 fdesc = file_of_index(index);
180 assert(fdesc != NULL);
181 err = zip_stat_index(zip, fdesc->zindex, ZIP_FL_ENC_GUESS, &zstat);
182 assert(zstat.name[0] != '/');
183 if (zstat.size == 0) {
185 err = create_directory((char*)zstat.name, MODE_OF_DIRECTORY_CREATION);
186 if (err && errno != EEXIST)
190 zfile = zip_fopen_index(zip, fdesc->zindex, 0);
192 ERROR("Can't open %s in %s", zstat.name, zipfile);
195 fd = create_file((char*)zstat.name, MODE_OF_FILE_CREATION, MODE_OF_DIRECTORY_CREATION);
201 sizr = zip_fread(zfile, buffer, sizeof buffer);
203 ERROR("error while reading %s in %s", zstat.name, zipfile);
206 sizw = write(fd, buffer, sizr);
208 ERROR("error while writing %s", zstat.name);
236 static int zwr(struct zws *zws, int offset)
242 struct zip_source *zsrc;
245 fd = openat(workdirfd, offset ? zws->name : ".", O_DIRECTORY|O_RDONLY);
247 ERROR("opendir %.*s failed in zwr", offset, zws->name);
253 ERROR("opendir %.*s failed in zwr", offset, zws->name);
258 zws->name[offset++] = '/';
261 while (ent != NULL) {
262 len = strlen(ent->d_name);
263 if (ent->d_name[0] == '.' && (len == 1 ||
264 (ent->d_name[1] == '.' && len == 2)))
266 else if (offset + len >= sizeof(zws->name)) {
267 ERROR("name too long in zwr");
268 errno = ENAMETOOLONG;
271 memcpy(zws->name + offset, ent->d_name, 1+len);
272 if (!is_valid_filename(ent->d_name)) {
273 ERROR("invalid name %s", zws->name);
276 switch (ent->d_type) {
278 z64 = zip_dir_add(zws->zip, zws->name, ZIP_FL_ENC_UTF_8);
280 ERROR("zip_dir_add of %s failed", zws->name);
283 err = zwr(zws, offset + len);
288 fd = openat(workdirfd, zws->name, O_RDONLY);
290 ERROR("openat of %s failed", zws->name);
293 fp = fdopen(fd, "r");
295 ERROR("fdopen of %s failed", zws->name);
299 zsrc = zip_source_filep(zws->zip, fp, 0, 0);
301 ERROR("zip_source_file of %s failed", zws->name);
305 z64 = zip_file_add(zws->zip, zws->name, zsrc, ZIP_FL_ENC_UTF_8);
307 ERROR("zip_file_add of %s failed", zws->name);
308 zip_source_free(zsrc);
326 /* write (pack) content of the current directory in 'zipfile' */
327 int zwrite(const char *zipfile)
332 zws.zip = zip_open(zipfile, ZIP_CREATE|ZIP_TRUNCATE, &err);
334 ERROR("Can't open %s for write", zipfile);
344 #if defined(TEST_READ)
345 int main(int ac, char **av)
347 for(av++ ; *av ; av++)
353 #if defined(TEST_WRITE)
354 int main(int ac, char **av)
356 for(av++ ; *av ; av++)