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 = mkdir(file, mode);
72 else if (errno == ENOENT) {
73 rc = create_directory(file, mode);
75 rc = mkdir(file, mode);
79 syslog(LOG_ERR, "can't create directory %s", file);
85 static int create_file(char *file, int fmode, int dmode)
87 int fd = creat(file, fmode);
88 if (fd < 0 && errno == ENOENT) {
89 if (!create_directory(file, dmode))
90 fd = creat(file, fmode);
93 syslog(LOG_ERR, "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 syslog(LOG_ERR, "Can't connect to file %s", zipfile);
118 z64 = zip_get_num_entries(zip, 0);
119 if (z64 < 0 || z64 > UINT_MAX) {
120 syslog(LOG_ERR, "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 syslog(LOG_ERR, "invalid entry %s found in %s", zstat.name, zipfile);
135 if (zstat.name[0] == '/') {
136 syslog(LOG_ERR, "absolute entry %s found in %s", zstat.name, zipfile);
139 len = strlen(zstat.name);
141 syslog(LOG_ERR, "empty entry found in %s", zipfile);
144 if (zstat.size == 0) {
146 if (zstat.name[len - 1] != '/') {
147 syslog(LOG_ERR, "bad directory name %s in %s", zstat.name, zipfile);
151 fdesc = file_add_directory(zstat.name);
154 if (zstat.name[len - 1] == '/') {
155 syslog(LOG_ERR, "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 syslog(LOG_ERR, "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 syslog(LOG_ERR, "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 syslog(LOG_ERR, "error while reading %s in %s", zstat.name, zipfile);
204 sizw = write(fd, buffer, sizr);
206 syslog(LOG_ERR, "error while writing %s", zstat.name);
234 static int zwr(struct zws *zws, int offset)
240 struct zip_source *zsrc;
245 dir = opendir(zws->name);
246 zws->name[offset++] = '/';
249 syslog(LOG_ERR, "opendir %.*s failed in zwr", offset, zws->name);
254 while (ent != NULL) {
255 len = strlen(ent->d_name);
256 if (ent->d_name[0] == '.' && (len == 1 ||
257 (ent->d_name[1] == '.' && len == 2)))
259 else if (offset + len >= sizeof(zws->name)) {
260 syslog(LOG_ERR, "name too long in zwr");
261 errno = ENAMETOOLONG;
264 memcpy(zws->name + offset, ent->d_name, 1+len);
265 if (!is_valid_filename(ent->d_name)) {
266 syslog(LOG_ERR, "invalid name %s", zws->name);
269 switch (ent->d_type) {
271 z64 = zip_dir_add(zws->zip, zws->name, ZIP_FL_ENC_UTF_8);
273 syslog(LOG_ERR, "zip_dir_add of %s failed", zws->name);
276 err = zwr(zws, offset + len);
281 zsrc = zip_source_file(zws->zip, zws->name, 0, 0);
283 syslog(LOG_ERR, "zip_source_file of %s failed", zws->name);
286 z64 = zip_file_add(zws->zip, zws->name, zsrc, ZIP_FL_ENC_UTF_8);
288 syslog(LOG_ERR, "zip_file_add of %s failed", zws->name);
289 zip_source_free(zsrc);
307 /* write (pack) content of the current directory in 'zipfile' */
308 int zwrite(const char *zipfile)
313 zws.zip = zip_open(zipfile, ZIP_CREATE|ZIP_TRUNCATE, &err);
315 syslog(LOG_ERR, "Can't open %s for write", zipfile);
325 #if defined(TEST_READ)
326 int main(int ac, char **av)
328 for(av++ ; *av ; av++)
334 #if defined(TEST_WRITE)
335 int main(int ac, char **av)
337 for(av++ ; *av ; av++)