4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License.
6 You may obtain a copy of the License at
8 http://www.apache.org/licenses/LICENSE-2.0
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
17 #define _BSD_SOURCE /* see readdir */
21 #include <sys/types.h>
34 #if !defined(MODE_OF_FILE_CREATION)
35 #define MODE_OF_FILE_CREATION 0640
37 #if !defined(MODE_OF_DIRECTORY_CREATION)
38 #define MODE_OF_DIRECTORY_CREATION 0750
41 static int is_valid_filename(const char *filename)
47 c = (unsigned char)filename[index];
50 || ((lastsp = (c == 0x20)) && index == 0)
51 || c == 0x7f || c == 0x3c || c == 0x3e
52 || c == 0x3a || c == 0x22
53 || c == 0x5c || c == 0x7c || c == 0x3f
54 || c == 0x2a || c == 0x5e || c == 0x60
55 || c == 0x7b || c == 0x7d || c == 0x21)
57 c = (unsigned char)filename[++index];
62 static int create_directory(char *file, int mode)
65 char *last = strrchr(file, '/');
68 rc = mkdirat(workdirfd, file, mode);
72 else if (errno == ENOENT) {
73 rc = create_directory(file, mode);
75 rc = mkdirat(workdirfd, file, mode);
79 ERROR("can't create directory %s", file);
85 static int create_file(char *file, int fmode, int dmode)
87 int fd = openat(workdirfd, file, O_CREAT|O_WRONLY|O_TRUNC, fmode);
88 if (fd < 0 && errno == ENOENT) {
89 if (!create_directory(file, dmode))
90 fd = openat(workdirfd, file, O_CREAT|O_WRONLY|O_TRUNC, fmode);
93 ERROR("can't create file %s", file);
97 /* read (extract) 'zipfile' in current directory */
98 int zread(const char *zipfile, unsigned long long maxsize)
100 struct filedesc *fdesc;
104 unsigned int count, index;
105 struct zip_file *zfile;
106 struct zip_stat zstat;
111 /* open the zip file */
112 zip = zip_open(zipfile, ZIP_CHECKCONS, &err);
114 ERROR("Can't connect to file %s", zipfile);
118 z64 = zip_get_num_entries(zip, 0);
119 if (z64 < 0 || z64 > UINT_MAX) {
120 ERROR("too many entries in %s", zipfile);
123 count = (unsigned int)z64;
125 /* records the files */
128 for (index = 0 ; index < count ; index++) {
129 err = zip_stat_index(zip, index, ZIP_FL_ENC_GUESS, &zstat);
130 /* check the file name */
131 if (!is_valid_filename(zstat.name)) {
132 ERROR("invalid entry %s found in %s", zstat.name, zipfile);
135 if (zstat.name[0] == '/') {
136 ERROR("absolute entry %s found in %s", zstat.name, zipfile);
139 len = strlen(zstat.name);
141 ERROR("empty entry found in %s", zipfile);
144 if (zstat.size == 0) {
146 if (zstat.name[len - 1] != '/') {
147 ERROR("bad directory name %s in %s", zstat.name, zipfile);
151 fdesc = file_add_directory(zstat.name);
154 if (zstat.name[len - 1] == '/') {
155 ERROR("bad file name %s in %s", zstat.name, zipfile);
161 fdesc = file_add_file(zstat.name);
165 fdesc->zindex = index;
169 if (maxsize && esize > maxsize) {
170 ERROR("extracted size %zu greater than allowed size %llu", esize, maxsize);
174 /* unpack the recorded files */
175 assert(count == file_count());
176 for (index = 0 ; index < count ; index++) {
177 fdesc = file_of_index(index);
178 assert(fdesc != NULL);
179 err = zip_stat_index(zip, fdesc->zindex, ZIP_FL_ENC_GUESS, &zstat);
180 assert(zstat.name[0] != '/');
181 if (zstat.size == 0) {
183 err = create_directory((char*)zstat.name, MODE_OF_DIRECTORY_CREATION);
184 if (err && errno != EEXIST)
188 zfile = zip_fopen_index(zip, fdesc->zindex, 0);
190 ERROR("Can't open %s in %s", zstat.name, zipfile);
193 fd = create_file((char*)zstat.name, MODE_OF_FILE_CREATION, MODE_OF_DIRECTORY_CREATION);
199 sizr = zip_fread(zfile, buffer, sizeof buffer);
201 ERROR("error while reading %s in %s", zstat.name, zipfile);
204 sizw = write(fd, buffer, sizr);
206 ERROR("error while writing %s", zstat.name);
234 static int zwr(struct zws *zws, int offset)
240 struct zip_source *zsrc;
243 fd = openat(workdirfd, offset ? zws->name : ".", O_DIRECTORY|O_RDONLY);
245 ERROR("opendir %.*s failed in zwr", offset, zws->name);
251 ERROR("opendir %.*s failed in zwr", offset, zws->name);
256 zws->name[offset++] = '/';
259 while (ent != NULL) {
260 len = strlen(ent->d_name);
261 if (ent->d_name[0] == '.' && (len == 1 ||
262 (ent->d_name[1] == '.' && len == 2)))
264 else if (offset + len >= sizeof(zws->name)) {
265 ERROR("name too long in zwr");
266 errno = ENAMETOOLONG;
269 memcpy(zws->name + offset, ent->d_name, 1+len);
270 if (!is_valid_filename(ent->d_name)) {
271 ERROR("invalid name %s", zws->name);
274 switch (ent->d_type) {
276 z64 = zip_dir_add(zws->zip, zws->name, ZIP_FL_ENC_UTF_8);
278 ERROR("zip_dir_add of %s failed", zws->name);
281 err = zwr(zws, offset + len);
286 fd = openat(workdirfd, zws->name, O_RDONLY);
288 ERROR("openat of %s failed", zws->name);
291 fp = fdopen(fd, "r");
293 ERROR("fdopen of %s failed", zws->name);
297 zsrc = zip_source_filep(zws->zip, fp, 0, 0);
299 ERROR("zip_source_file of %s failed", zws->name);
303 z64 = zip_file_add(zws->zip, zws->name, zsrc, ZIP_FL_ENC_UTF_8);
305 ERROR("zip_file_add of %s failed", zws->name);
306 zip_source_free(zsrc);
324 /* write (pack) content of the current directory in 'zipfile' */
325 int zwrite(const char *zipfile)
330 zws.zip = zip_open(zipfile, ZIP_CREATE|ZIP_TRUNCATE, &err);
332 ERROR("Can't open %s for write", zipfile);
342 #if defined(TEST_READ)
343 int main(int ac, char **av)
345 for(av++ ; *av ; av++)
351 #if defined(TEST_WRITE)
352 int main(int ac, char **av)
354 for(av++ ; *av ; av++)