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>
35 #if !defined(MODE_OF_FILE_CREATION)
36 #define MODE_OF_FILE_CREATION 0640
38 #if !defined(MODE_OF_DIRECTORY_CREATION)
39 #define MODE_OF_DIRECTORY_CREATION 0750
42 static int is_valid_filename(const char *filename)
48 c = (unsigned char)filename[index];
51 || ((lastsp = (c == 0x20)) && index == 0)
52 || c == 0x7f || c == 0x3c || c == 0x3e
53 || c == 0x3a || c == 0x22
54 || c == 0x5c || c == 0x7c || c == 0x3f
55 || c == 0x2a || c == 0x5e || c == 0x60
56 || c == 0x7b || c == 0x7d || c == 0x21)
58 c = (unsigned char)filename[++index];
63 static int create_directory(char *file, int mode)
66 char *last = strrchr(file, '/');
69 rc = mkdirat(workdirfd, file, mode);
73 else if (errno == ENOENT) {
74 rc = create_directory(file, mode);
76 rc = mkdirat(workdirfd, file, mode);
80 ERROR("can't create directory %s", file);
86 static int create_file(char *file, int fmode, int dmode)
88 int fd = openat(workdirfd, file, O_CREAT|O_WRONLY|O_TRUNC, fmode);
89 if (fd < 0 && errno == ENOENT) {
90 if (!create_directory(file, dmode))
91 fd = openat(workdirfd, file, O_CREAT|O_WRONLY|O_TRUNC, fmode);
94 ERROR("can't create file %s", file);
98 /* read (extract) 'zipfile' in current directory */
99 int zread(const char *zipfile, unsigned long long maxsize)
101 struct filedesc *fdesc;
105 unsigned int count, index;
106 struct zip_file *zfile;
107 struct zip_stat zstat;
112 /* open the zip file */
113 zip = zip_open(zipfile, ZIP_CHECKCONS, &err);
115 ERROR("Can't connect to file %s", zipfile);
119 z64 = zip_get_num_entries(zip, 0);
120 if (z64 < 0 || z64 > UINT_MAX) {
121 ERROR("too many entries in %s", zipfile);
124 count = (unsigned int)z64;
126 /* records the files */
129 for (index = 0 ; index < count ; index++) {
130 err = zip_stat_index(zip, index, ZIP_FL_ENC_GUESS, &zstat);
131 /* check the file name */
132 if (!is_valid_filename(zstat.name)) {
133 ERROR("invalid entry %s found in %s", zstat.name, zipfile);
136 if (zstat.name[0] == '/') {
137 ERROR("absolute entry %s found in %s", zstat.name, zipfile);
140 len = strlen(zstat.name);
142 ERROR("empty entry found in %s", zipfile);
145 if (zstat.size == 0) {
147 if (zstat.name[len - 1] != '/') {
148 ERROR("bad directory name %s in %s", zstat.name, zipfile);
152 fdesc = file_add_directory(zstat.name);
155 if (zstat.name[len - 1] == '/') {
156 ERROR("bad file name %s in %s", zstat.name, zipfile);
162 fdesc = file_add_file(zstat.name);
166 fdesc->zindex = index;
170 if (maxsize && esize > maxsize) {
171 ERROR("extracted size %zu greater than allowed size %llu", esize, maxsize);
175 /* unpack the recorded files */
176 assert(count == file_count());
177 for (index = 0 ; index < count ; index++) {
178 fdesc = file_of_index(index);
179 assert(fdesc != NULL);
180 err = zip_stat_index(zip, fdesc->zindex, ZIP_FL_ENC_GUESS, &zstat);
181 assert(zstat.name[0] != '/');
182 if (zstat.size == 0) {
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);
343 #if defined(TEST_READ)
344 int main(int ac, char **av)
346 for(av++ ; *av ; av++)
352 #if defined(TEST_WRITE)
353 int main(int ac, char **av)
355 for(av++ ; *av ; av++)