git-svn-id: file:///var/lib/svn/clamav-devel/trunk/clamav-devel@64 77e5149b-7576-45b1-b177-96237e5ba77b
Tomasz Kojm authored on 2003/09/29 20:44:52... | ... |
@@ -7,6 +7,9 @@ Nigel Horne <njh@bandsman.co.uk> |
7 | 7 |
home page : http://bandsman.co.uk |
8 | 8 |
Author of clamav-milter and the whole mbox code. |
9 | 9 |
|
10 |
+System administrator (www, mailing lists, mirror issues, virus |
|
11 |
+submission mechanisms): Luca 'NERvOus' Gibelli <nervous@nervous.it> |
|
12 |
+ |
|
10 | 13 |
Database developers: |
11 | 14 |
|
12 | 15 |
aCaB <acab@digitalfuture.it> |
... | ... |
@@ -15,6 +18,7 @@ Jason Englander <jason@englanders.cc> |
15 | 15 |
Tomasz Kojm <zolw@konarski.edu.pl> |
16 | 16 |
Tomasz Papszun <tomek@lodz.tpsa.pl> |
17 | 17 |
|
18 |
+ |
|
18 | 19 |
TrashScan was written by Trashware <trashware@gmx.net>. |
19 | 20 |
|
20 | 21 |
ClamAV patches were submitted by (in alphabetical order): |
... | ... |
@@ -28,6 +32,7 @@ Jason Englander <jason@englanders.cc> |
28 | 28 |
David Ford <david+cert@blue-labs.org> |
29 | 29 |
Nigel Horne <njh@smsltd.demon.co.uk> |
30 | 30 |
Hrvoje Habjanic <hrvoje.habjanic@zg.hinet.hr> |
31 |
+Nicholas M. Kirsch <nick@kirsch.org> |
|
31 | 32 |
Robbert Kouprie <robbert@exx.nl> |
32 | 33 |
Thomas Lamy <Thomas.Lamy@in-online.net> |
33 | 34 |
Peter N Lewis <peter@stairways.com.au> |
... | ... |
@@ -1,3 +1,19 @@ |
1 |
+Mon Sep 29 13:42:51 CEST 2003 (tk) |
|
2 |
+---------------------------------- |
|
3 |
+ * libclamav: initial support for cvd file format (a database container file |
|
4 |
+ with support for digital signatures) |
|
5 |
+ * libclamav: fixed zip recursion problem introduced in -20030907 (bug |
|
6 |
+ reported by Tomasz Papszun) |
|
7 |
+ * libclamav: support for gzip and Maildir files was enabled if ScanMail _or_ |
|
8 |
+ ScanArchive was defined. Fixed. |
|
9 |
+ * libclamav: zziplib updated to 0.12.83 (probably not the newest one but |
|
10 |
+ seems to be very stable) |
|
11 |
+ * sigtool: --build (builds a cvd file, not finished yet) |
|
12 |
+ * clamd: new directive TCPAddr by Bernard Quatermass |
|
13 |
+ * libclamav: new scan option CL_DISABLERAR (disables built-in rar unpacker) |
|
14 |
+ * clamd: rar scanning is now disabled by default and may be enabled with |
|
15 |
+ ScanRAR in clamav.conf. |
|
16 |
+ |
|
1 | 17 |
Mon Sep 29 07:15:30 BST 2003 (njh) |
2 | 18 |
---------------------------------- |
3 | 19 |
* clamav-milter: ensure remoteIP is initialised |
... | ... |
@@ -1,5 +1,5 @@ |
1 | 1 |
/* |
2 |
- * Copyright (C) 2002 Tomasz Kojm <zolw@konarski.edu.pl> |
|
2 |
+ * Copyright (C) 2002, 2003 Tomasz Kojm <zolw@konarski.edu.pl> |
|
3 | 3 |
* |
4 | 4 |
* This program is free software; you can redistribute it and/or modify |
5 | 5 |
* it under the terms of the GNU General Public License as published by |
... | ... |
@@ -46,11 +46,13 @@ struct cfgstruct *parsecfg(const char *cfgfile) |
46 | 46 |
{"MaxFileSize", OPT_COMPSIZE}, |
47 | 47 |
{"ScanMail", OPT_NOARG}, |
48 | 48 |
{"ScanArchive", OPT_NOARG}, |
49 |
+ {"ScanRAR", OPT_NOARG}, |
|
49 | 50 |
{"ArchiveMaxFileSize", OPT_COMPSIZE}, |
50 | 51 |
{"ArchiveMaxRecursion", OPT_NUM}, |
51 | 52 |
{"ArchiveMaxFiles", OPT_NUM}, |
52 | 53 |
{"ArchiveLimitMemoryUsage", OPT_NOARG}, |
53 | 54 |
{"DataDirectory", OPT_STR}, |
55 |
+ {"TCPAddr", OPT_STR}, |
|
54 | 56 |
{"TCPSocket", OPT_NUM}, |
55 | 57 |
{"LocalSocket", OPT_STR}, |
56 | 58 |
{"MaxConnectionQueueLength", OPT_NUM}, |
... | ... |
@@ -215,6 +215,9 @@ int scanstream(int odesc, unsigned long int *scanned, const struct cl_node *root |
215 | 215 |
return -1; |
216 | 216 |
} |
217 | 217 |
|
218 |
+ |
|
219 |
+ logg("*Accepted connection on port %d\n", port); |
|
220 |
+ |
|
218 | 221 |
if(cfgopt(copt, "StreamSaveToDisk")) { |
219 | 222 |
if((tmp = tmpfile()) == NULL) { |
220 | 223 |
shutdown(sockfd, 2); |
... | ... |
@@ -447,6 +447,13 @@ int acceptloop(int socketd, struct cl_node *root, const struct cfgstruct *copt) |
447 | 447 |
if(cfgopt(copt, "ScanArchive")) { |
448 | 448 |
logg("Archive support enabled.\n"); |
449 | 449 |
options |= CL_ARCHIVE; |
450 |
+ |
|
451 |
+ if(cfgopt(copt, "ScanRAR")) { |
|
452 |
+ logg("RAR support enabled.\n"); |
|
453 |
+ } else { |
|
454 |
+ logg("RAR support disabled.\n"); |
|
455 |
+ options |= CL_DISABLERAR; |
|
456 |
+ } |
|
450 | 457 |
} else { |
451 | 458 |
logg("Archive support disabled.\n"); |
452 | 459 |
} |
... | ... |
@@ -36,11 +36,19 @@ int tcpserver(const struct optstruct *opt, const struct cfgstruct *copt, struct |
36 | 36 |
int sockfd, backlog; |
37 | 37 |
struct cfgstruct *cpt; |
38 | 38 |
char *estr; |
39 |
+ const char *taddr; |
|
39 | 40 |
|
40 | 41 |
memset((char *) &server, 0, sizeof(server)); |
41 | 42 |
server.sin_family = AF_INET; |
42 | 43 |
server.sin_port = htons(cfgopt(copt, "TCPSocket")->numarg); |
43 |
- server.sin_addr.s_addr = INADDR_ANY; |
|
44 |
+ taddr = cfgopt(copt, "TCPAddr")->strarg; |
|
45 |
+ if ( taddr != NULL && *taddr ) |
|
46 |
+ { |
|
47 |
+ server.sin_addr.s_addr = inet_addr( taddr ); |
|
48 |
+ }else |
|
49 |
+ { |
|
50 |
+ server.sin_addr.s_addr = INADDR_ANY; |
|
51 |
+ } |
|
44 | 52 |
|
45 | 53 |
|
46 | 54 |
if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) { |
... | ... |
@@ -55,8 +63,12 @@ int tcpserver(const struct optstruct *opt, const struct cfgstruct *copt, struct |
55 | 55 |
//fprintf(stderr, "ERROR: can't bind(): %s\n", estr); |
56 | 56 |
logg("!bind() error: %s\n", estr); |
57 | 57 |
exit(1); |
58 |
- } else |
|
59 |
- logg("Binded to port %d\n", cfgopt(copt, "TCPSocket")->numarg); |
|
58 |
+ } else { |
|
59 |
+ if ( taddr != NULL && *taddr ) |
|
60 |
+ logg("Bound to address %s on port %d\n", taddr, cfgopt(copt, "TCPSocket")->numarg); |
|
61 |
+ else |
|
62 |
+ logg("Bound to port %d\n", cfgopt(copt, "TCPSocket")->numarg); |
|
63 |
+ } |
|
60 | 64 |
|
61 | 65 |
if((cpt = cfgopt(copt, "MaxConnectionQueueLength"))) |
62 | 66 |
backlog = cpt->numarg; |
... | ... |
@@ -182,7 +182,7 @@ int scanmanager(const struct optstruct *opt) |
182 | 182 |
} |
183 | 183 |
/* generate the temporary directory */ |
184 | 184 |
|
185 |
- dir = gentemp(tmpdir); |
|
185 |
+ dir = cl_gentemp(tmpdir); |
|
186 | 186 |
if(mkdir(dir, 0700)) { |
187 | 187 |
mprintf("@Can't create the temporary directory %s\n", dir); |
188 | 188 |
exit(63); /* critical */ |
... | ... |
@@ -473,7 +473,7 @@ int scancompressed(const char *filename, struct cl_node *root, const struct pass |
473 | 473 |
|
474 | 474 |
/* generate the temporary directory */ |
475 | 475 |
|
476 |
- gendir = gentemp(tmpdir); |
|
476 |
+ gendir = cl_gentemp(tmpdir); |
|
477 | 477 |
if(mkdir(gendir, 0700)) { |
478 | 478 |
mprintf("@Can't create the temporary directory %s\n", gendir); |
479 | 479 |
exit(63); /* critical */ |
... | ... |
@@ -670,7 +670,7 @@ int scandenied(const char *filename, struct cl_node *root, const struct passwd * |
670 | 670 |
} |
671 | 671 |
|
672 | 672 |
/* generate the temporary directory */ |
673 |
- gendir = gentemp(tmpdir); |
|
673 |
+ gendir = cl_gentemp(tmpdir); |
|
674 | 674 |
if(mkdir(gendir, 0700)) { |
675 | 675 |
mprintf("@Can't create the temporary directory %s\n", gendir); |
676 | 676 |
exit(63); /* critical */ |
... | ... |
@@ -420,32 +420,6 @@ int filecopy(const char *src, const char *dest) |
420 | 420 |
return close(d); |
421 | 421 |
} |
422 | 422 |
|
423 |
-char *gentemp(const char *dir) |
|
424 |
-{ |
|
425 |
- char *name, *mdir, *tmp; |
|
426 |
- unsigned char salt[32]; |
|
427 |
- int cnt=0, i; |
|
428 |
- |
|
429 |
- if(!dir) |
|
430 |
- mdir = "/tmp"; |
|
431 |
- else |
|
432 |
- mdir = (char *) dir; |
|
433 |
- |
|
434 |
- name = (char*) calloc(strlen(mdir) + 1 + 16 + 1, sizeof(char)); |
|
435 |
- cnt += sprintf(name, "%s/", mdir); |
|
436 |
- |
|
437 |
- do { |
|
438 |
- for(i = 0; i < 32; i++) |
|
439 |
- salt[i] = cl_rndnum(255); |
|
440 |
- |
|
441 |
- tmp = cl_md5buff(salt, 32); |
|
442 |
- strncat(name, tmp, 16); |
|
443 |
- free(tmp); |
|
444 |
- } while(fileinfo(name, 1) != -1); |
|
445 |
- |
|
446 |
- return(name); |
|
447 |
-} |
|
448 |
- |
|
449 | 423 |
int strbcasestr(const char *haystack, const char *needle) |
450 | 424 |
{ |
451 | 425 |
char *pt = (char *) haystack; |
... | ... |
@@ -35,7 +35,6 @@ int strbcasestr(const char *haystack, const char *needle); |
35 | 35 |
int readaccess(const char *path, const char *username); |
36 | 36 |
int writeaccess(const char *path, const char *username); |
37 | 37 |
int filecopy(const char *src, const char *dest); |
38 |
-char *gentemp(const char *dir); |
|
39 | 38 |
|
40 | 39 |
/* njh@bandsman.co.uk: for BeOS */ |
41 | 40 |
/* TODO: configure should see if sete[ug]id is set on the target */ |
... | ... |
@@ -53,7 +53,13 @@ Example |
53 | 53 |
LocalSocket /tmp/clamd |
54 | 54 |
|
55 | 55 |
# Remove stale socket after unclean shutdown. |
56 |
-#FixStaleSocket |
|
56 |
+#RemoveStaleSocket |
|
57 |
+ |
|
58 |
+# TCP address. |
|
59 |
+# By default we bind to INADDR_ANY, probably not wise. |
|
60 |
+# Enable the following to provide some degree of protection |
|
61 |
+# from the outside world. |
|
62 |
+#TCPAddr 127.0.0.1 |
|
57 | 63 |
|
58 | 64 |
# TCP port address. |
59 | 65 |
#TCPSocket 3310 |
... | ... |
@@ -132,6 +138,12 @@ MaxDirectoryRecursion 15 |
132 | 132 |
# Comment this line to disable scanning of the archives. |
133 | 133 |
ScanArchive |
134 | 134 |
|
135 |
+ |
|
136 |
+# By default the built-in RAR unpacker is disabled because the code |
|
137 |
+# terribly leaks, however it's probably a good idea to enable it. |
|
138 |
+#ScanRAR |
|
139 |
+ |
|
140 |
+ |
|
135 | 141 |
# Options below protect your system against Denial of Service attacks |
136 | 142 |
# with archive bombs. |
137 | 143 |
|
... | ... |
@@ -174,7 +174,7 @@ int downloadmanager(const struct optstruct *opt, const char *hostname) |
174 | 174 |
/* temporary file is created in clamav's directory thus we don't need |
175 | 175 |
* to create it immediately, because race conditions are impossible |
176 | 176 |
*/ |
177 |
- tempname = gentemp("."); |
|
177 |
+ tempname = cl_gentemp("."); |
|
178 | 178 |
|
179 | 179 |
/* download the database */ |
180 | 180 |
/* FIXME: We need to reconnect, because we won't be able to donwload |
... | ... |
@@ -232,7 +232,7 @@ int downloadmanager(const struct optstruct *opt, const char *hostname) |
232 | 232 |
} |
233 | 233 |
|
234 | 234 |
if(updatedb2) { |
235 |
- tempname = gentemp("."); |
|
235 |
+ tempname = cl_gentemp("."); |
|
236 | 236 |
|
237 | 237 |
/* download viruses.db2 */ |
238 | 238 |
|
... | ... |
@@ -1,5 +1,5 @@ |
1 | 1 |
/* |
2 |
- * Copyright (C) 2002 Tomasz Kojm <zolw@konarski.edu.pl> |
|
2 |
+ * Copyright (C) 2002, 2003 Tomasz Kojm <zolw@konarski.edu.pl> |
|
3 | 3 |
* |
4 | 4 |
* This program is free software; you can redistribute it and/or modify |
5 | 5 |
* it under the terms of the GNU General Public License as published by |
... | ... |
@@ -56,11 +56,13 @@ extern "C" |
56 | 56 |
#define CL_EMALFDB -5 /* malformed database */ |
57 | 57 |
#define CL_EPATSHORT -6 /* pattern too short */ |
58 | 58 |
#define CL_ETMPDIR -7 /* mkdir() failed */ |
59 |
+#define CL_ECVDEXTR -8 /* CVD extraction failure */ |
|
59 | 60 |
|
60 | 61 |
/* options */ |
61 | 62 |
#define CL_RAW 00 |
62 | 63 |
#define CL_ARCHIVE 01 |
63 | 64 |
#define CL_MAIL 0100 |
65 |
+#define CL_DISABLERAR 01000 |
|
64 | 66 |
|
65 | 67 |
struct patt { |
66 | 68 |
short int *pattern; |
... | ... |
@@ -94,6 +96,16 @@ struct cl_stat { |
94 | 94 |
struct stat *stattab; |
95 | 95 |
}; |
96 | 96 |
|
97 |
+struct cl_cvd { |
|
98 |
+ char *time; /* 2 */ |
|
99 |
+ int version; /* 3 */ |
|
100 |
+ int sigs; /* 4 */ |
|
101 |
+ short int fl; /* 5 */ |
|
102 |
+ char *md5; /* 6 */ |
|
103 |
+ char *dsig; /* 7 */ |
|
104 |
+ char *builder; /* 8 */ |
|
105 |
+}; |
|
106 |
+ |
|
97 | 107 |
/* file scanning */ |
98 | 108 |
extern int cl_scanbuff(const char *buffer, unsigned int length, char **virname, const struct cl_node *root); |
99 | 109 |
|
... | ... |
@@ -106,6 +118,9 @@ extern int cl_loaddb(const char *filename, struct cl_node **root, int *virnum); |
106 | 106 |
extern int cl_loaddbdir(const char *dirname, struct cl_node **root, int *virnum); |
107 | 107 |
extern char *cl_retdbdir(void); |
108 | 108 |
|
109 |
+extern struct cl_cvd *cl_cvdhead(const char *file); |
|
110 |
+extern void cl_cvdfree(struct cl_cvd *cvd); |
|
111 |
+ |
|
109 | 112 |
/* data dir stat functions */ |
110 | 113 |
extern int cl_statinidir(const char *dirname, struct cl_stat *dbstat); |
111 | 114 |
extern int cl_statchkdir(const struct cl_stat *dbstat); |
... | ... |
@@ -126,7 +141,7 @@ extern char *cl_md5buff(const char *buffer, unsigned int length); |
126 | 126 |
|
127 | 127 |
extern int cl_mbox(const char *dir, int desc); |
128 | 128 |
|
129 |
-/* compute MD5 message digest from filename (compatible with md5sum(1)) */ |
|
129 |
+/* compute MD5 message digest from file (compatible with md5sum(1)) */ |
|
130 | 130 |
extern char *cl_md5file(const char *filename); |
131 | 131 |
|
132 | 132 |
/* decode hexadecimal string */ |
... | ... |
@@ -138,6 +153,9 @@ extern char *cl_str2hex(const char *string, unsigned int len); |
138 | 138 |
/* generate a pseudo-random number */ |
139 | 139 |
extern unsigned int cl_rndnum(unsigned int max); |
140 | 140 |
|
141 |
+/* generate unique file name in temporary directory */ |
|
142 |
+char *cl_gentemp(const char *dir); |
|
143 |
+ |
|
141 | 144 |
#ifdef __cplusplus |
142 | 145 |
}; |
143 | 146 |
#endif |
144 | 147 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,314 @@ |
0 |
+/* |
|
1 |
+ * Copyright (C) 2003 Tomasz Kojm <zolw@konarski.edu.pl> |
|
2 |
+ * |
|
3 |
+ * untgz() is based on public domain minitar utility by Charles G. Waldman |
|
4 |
+ * |
|
5 |
+ * This program is free software; you can redistribute it and/or modify |
|
6 |
+ * it under the terms of the GNU General Public License as published by |
|
7 |
+ * the Free Software Foundation; either version 2 of the License, or |
|
8 |
+ * (at your option) any later version. |
|
9 |
+ * |
|
10 |
+ * This program is distributed in the hope that it will be useful, |
|
11 |
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
12 |
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
13 |
+ * GNU General Public License for more details. |
|
14 |
+ * |
|
15 |
+ * You should have received a copy of the GNU General Public License |
|
16 |
+ * along with this program; if not, write to the Free Software |
|
17 |
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
|
18 |
+ */ |
|
19 |
+ |
|
20 |
+ |
|
21 |
+#include <stdio.h> |
|
22 |
+#include <string.h> |
|
23 |
+#include <stdlib.h> |
|
24 |
+#include <sys/types.h> |
|
25 |
+#include <sys/stat.h> |
|
26 |
+#include <fcntl.h> |
|
27 |
+#include <zlib.h> |
|
28 |
+ |
|
29 |
+#include "clamav.h" |
|
30 |
+ |
|
31 |
+#define TAR_BLOCKSIZE 512 |
|
32 |
+ |
|
33 |
+int cli_untgz(int fd, const char *destdir) |
|
34 |
+{ |
|
35 |
+ char *fullname, osize[13], name[101], type; |
|
36 |
+ char block[TAR_BLOCKSIZE]; |
|
37 |
+ int nbytes, nread, nwritten, in_block = 0; |
|
38 |
+ unsigned int size; |
|
39 |
+ FILE *outfile = NULL; |
|
40 |
+ gzFile *infile; |
|
41 |
+ |
|
42 |
+ cli_dbgmsg("in cli_untgz()\n"); |
|
43 |
+ |
|
44 |
+ if((infile = gzdopen(fd, "rb")) == NULL) { |
|
45 |
+ cli_errmsg("Can't gzdopen() descriptor %d\n", fd); |
|
46 |
+ return -1; |
|
47 |
+ } |
|
48 |
+ |
|
49 |
+ |
|
50 |
+ fullname = (char *) calloc(sizeof(char), strlen(destdir) + 100 + 5); |
|
51 |
+ |
|
52 |
+ while(1) { |
|
53 |
+ |
|
54 |
+ nread = gzread(infile, block, TAR_BLOCKSIZE); |
|
55 |
+ |
|
56 |
+ if(!in_block && nread == 0) |
|
57 |
+ break; |
|
58 |
+ |
|
59 |
+ if(nread != TAR_BLOCKSIZE) { |
|
60 |
+ cli_errmsg("Incomplete block read.\n"); |
|
61 |
+ free(fullname); |
|
62 |
+ return -1; |
|
63 |
+ } |
|
64 |
+ |
|
65 |
+ if(!in_block) { |
|
66 |
+ if (block[0] == '\0') /* We're done */ |
|
67 |
+ break; |
|
68 |
+ |
|
69 |
+ strncpy(name, block, 100); |
|
70 |
+ name[100] = '\0'; |
|
71 |
+ strcpy(fullname, destdir); |
|
72 |
+ strcat(fullname, "/"); |
|
73 |
+ strcat(fullname, name); |
|
74 |
+ cli_dbgmsg("Unpacking %s\n",fullname); |
|
75 |
+ type = block[156]; |
|
76 |
+ |
|
77 |
+ switch(type) { |
|
78 |
+ case '0': |
|
79 |
+ case '\0': |
|
80 |
+ break; |
|
81 |
+ case '5': |
|
82 |
+ cli_errmsg("Directories in CVD are not supported.\n"); |
|
83 |
+ free(fullname); |
|
84 |
+ return -1; |
|
85 |
+ default: |
|
86 |
+ cli_errmsg("Unknown type flag %c.\n",type); |
|
87 |
+ free(fullname); |
|
88 |
+ return -1; |
|
89 |
+ } |
|
90 |
+ |
|
91 |
+ in_block = 1; |
|
92 |
+ |
|
93 |
+ if(outfile) { |
|
94 |
+ if(fclose(outfile)) { |
|
95 |
+ cli_errmsg("Cannot close file %s.\n", fullname); |
|
96 |
+ free(fullname); |
|
97 |
+ return -1; |
|
98 |
+ } |
|
99 |
+ outfile = NULL; |
|
100 |
+ } |
|
101 |
+ |
|
102 |
+ if(!(outfile = fopen(fullname, "wb"))) { |
|
103 |
+ cli_errmsg("Cannot create file %s.\n", fullname); |
|
104 |
+ free(fullname); |
|
105 |
+ return -1; |
|
106 |
+ } |
|
107 |
+ |
|
108 |
+ strncpy(osize, block + 124, 12); |
|
109 |
+ osize[12] = '\0'; |
|
110 |
+ size = -1; |
|
111 |
+ sscanf(osize, "%o", &size); |
|
112 |
+ |
|
113 |
+ if(size < 0) { |
|
114 |
+ cli_errmsg("Invalid size in header.\n"); |
|
115 |
+ free(fullname); |
|
116 |
+ return -1; |
|
117 |
+ } |
|
118 |
+ |
|
119 |
+ } else { /* write or continue writing file contents */ |
|
120 |
+ nbytes = size > TAR_BLOCKSIZE ? TAR_BLOCKSIZE : size; |
|
121 |
+ nwritten = fwrite(block, 1, nbytes, outfile); |
|
122 |
+ |
|
123 |
+ if(nwritten != nbytes) { |
|
124 |
+ cli_errmsg("Wrote %d instead of %d (%s).\n", nwritten, nbytes, fullname); |
|
125 |
+ free(fullname); |
|
126 |
+ return -1; |
|
127 |
+ } |
|
128 |
+ |
|
129 |
+ size -= nbytes; |
|
130 |
+ if(size == 0) |
|
131 |
+ in_block = 0; |
|
132 |
+ } |
|
133 |
+ } |
|
134 |
+ |
|
135 |
+ return 0; |
|
136 |
+} |
|
137 |
+ |
|
138 |
+char *cli_cut(const char *line, int field) |
|
139 |
+{ |
|
140 |
+ int length, counter = 0, i, j = 0, k; |
|
141 |
+ char *buffer; |
|
142 |
+ |
|
143 |
+ length = strlen(line); |
|
144 |
+ buffer = (char *) cli_calloc(length, sizeof(char)); |
|
145 |
+ |
|
146 |
+ for(i = 0; i < length; i++) { |
|
147 |
+ if(line[i] == ':') { |
|
148 |
+ counter++; |
|
149 |
+ if(counter == field) { |
|
150 |
+ break; |
|
151 |
+ } else { |
|
152 |
+ memset(buffer, 0, length); |
|
153 |
+ j = 0; |
|
154 |
+ } |
|
155 |
+ } else { |
|
156 |
+ buffer[j++] = line[i]; |
|
157 |
+ } |
|
158 |
+ } |
|
159 |
+ |
|
160 |
+ return (char *) cli_realloc(buffer, strlen(buffer) + 1); |
|
161 |
+} |
|
162 |
+ |
|
163 |
+struct cl_cvd *cli_cvdhead(const char *head) |
|
164 |
+{ |
|
165 |
+ char *pt; |
|
166 |
+ struct cl_cvd *cvd; |
|
167 |
+ |
|
168 |
+ cvd = (struct cl_cvd *) cli_calloc(1, sizeof(struct cl_cvd)); |
|
169 |
+ cvd->time = cli_cut(head, 2); |
|
170 |
+ |
|
171 |
+ pt = cli_cut(head, 3); |
|
172 |
+ cvd->version = atoi(pt); |
|
173 |
+ free(pt); |
|
174 |
+ |
|
175 |
+ pt = cli_cut(head, 4); |
|
176 |
+ cvd->sigs = atoi(pt); |
|
177 |
+ free(pt); |
|
178 |
+ |
|
179 |
+ pt = cli_cut(head, 5); |
|
180 |
+ cvd->fl = (short int) atoi(pt); |
|
181 |
+ free(pt); |
|
182 |
+ |
|
183 |
+ cvd->md5 = cli_cut(head, 6); |
|
184 |
+ cvd->dsig = cli_cut(head, 7); |
|
185 |
+ cvd->builder = cli_cut(head, 8); |
|
186 |
+ |
|
187 |
+ return cvd; |
|
188 |
+} |
|
189 |
+ |
|
190 |
+struct cl_cvd *cl_cvdhead(const char *file) |
|
191 |
+{ |
|
192 |
+ char head[257]; |
|
193 |
+ FILE *fd; |
|
194 |
+ int i; |
|
195 |
+ |
|
196 |
+ |
|
197 |
+ if((fd = fopen(file, "rb")) == NULL) { |
|
198 |
+ cli_errmsg("Can't open CVD file %s\n", file); |
|
199 |
+ return NULL; |
|
200 |
+ } |
|
201 |
+ |
|
202 |
+ if(fread(head, 1, 256, fd) != 256) { |
|
203 |
+ cli_errmsg("Can't read CVD head from %s\n", file); |
|
204 |
+ return NULL; |
|
205 |
+ } |
|
206 |
+ head[256] = 0; |
|
207 |
+ |
|
208 |
+ for(i = 255; i > 0 && !isalnum(head[i]); head[i] = 0, i--); |
|
209 |
+ |
|
210 |
+ if(strncmp(head, "ClamAV-VDB:", 11)) { |
|
211 |
+ cli_errmsg("%s is not a CVD file.\n"); |
|
212 |
+ return NULL; |
|
213 |
+ } |
|
214 |
+ |
|
215 |
+ return cli_cvdhead(head); |
|
216 |
+} |
|
217 |
+ |
|
218 |
+void cl_cvdfree(struct cl_cvd *cvd) |
|
219 |
+{ |
|
220 |
+ free(cvd->time); |
|
221 |
+ free(cvd->md5); |
|
222 |
+ free(cvd->dsig); |
|
223 |
+ free(cvd->builder); |
|
224 |
+ free(cvd); |
|
225 |
+} |
|
226 |
+ |
|
227 |
+int cli_cvdload(FILE *fd, struct cl_node **root, int *virnum) |
|
228 |
+{ |
|
229 |
+ char head[257], *dir, *tmp, buffer[BUFFSIZE]; |
|
230 |
+ int bytes; |
|
231 |
+ struct cl_cvd *cvd; |
|
232 |
+ const char *tmpdir; |
|
233 |
+ FILE *tmpd; |
|
234 |
+ |
|
235 |
+ cli_dbgmsg("in cli_cvdload()\n"); |
|
236 |
+ |
|
237 |
+ if(fread(head, 1, 256, fd) != 256) { |
|
238 |
+ cli_errmsg("Can't read CVD head.\n"); |
|
239 |
+ return -1; |
|
240 |
+ } |
|
241 |
+ head[256] = 0; |
|
242 |
+ |
|
243 |
+ cvd = cli_cvdhead(head); |
|
244 |
+ |
|
245 |
+ /* verify md5/dsig */ |
|
246 |
+ |
|
247 |
+ |
|
248 |
+ /* unpack */ |
|
249 |
+ |
|
250 |
+ tmpdir = getenv("TMPDIR"); |
|
251 |
+ |
|
252 |
+ if(tmpdir == NULL) |
|
253 |
+#ifdef P_tmpdir |
|
254 |
+ tmpdir = P_tmpdir; |
|
255 |
+#else |
|
256 |
+ tmpdir = "/tmp"; |
|
257 |
+#endif |
|
258 |
+ |
|
259 |
+ dir = cl_gentemp(tmpdir); |
|
260 |
+ if(mkdir(dir, 0700)) { |
|
261 |
+ cli_errmsg("cli_cvdload(): Can't create temporary directory %s\n", dir); |
|
262 |
+ return CL_ETMPDIR; |
|
263 |
+ } |
|
264 |
+ |
|
265 |
+ /* |
|
266 |
+ if(cli_untgz(fileno(fd), dir)) { |
|
267 |
+ cli_errmsg("cli_cvdload(): Can't unpack CVD file.\n"); |
|
268 |
+ return CL_ECVDEXTR; |
|
269 |
+ } |
|
270 |
+ */ |
|
271 |
+ |
|
272 |
+ /* FIXME: it seems there is some problem with current position after |
|
273 |
+ * gzdopen() in cli_untgz(). Temporarily we need this wrapper: |
|
274 |
+ */ |
|
275 |
+ |
|
276 |
+ /* start */ |
|
277 |
+ |
|
278 |
+ tmp = cl_gentemp(tmpdir); |
|
279 |
+ if((tmpd = fopen(tmp, "wb+")) == NULL) { |
|
280 |
+ cli_errmsg("Can't create temporary file %s\n", tmp); |
|
281 |
+ free(dir); |
|
282 |
+ free(tmp); |
|
283 |
+ return -1; |
|
284 |
+ } |
|
285 |
+ while((bytes = fread(buffer, 1, BUFFSIZE, fd)) > 0) |
|
286 |
+ fwrite(buffer, 1, bytes, tmpd); |
|
287 |
+ |
|
288 |
+ fflush(tmpd); |
|
289 |
+ fseek(tmpd, 0L, SEEK_SET); |
|
290 |
+ |
|
291 |
+ if(cli_untgz(fileno(tmpd), dir)) { |
|
292 |
+ cli_errmsg("cli_cvdload(): Can't unpack CVD file.\n"); |
|
293 |
+ cli_rmdirs(dir); |
|
294 |
+ free(dir); |
|
295 |
+ unlink(tmp); |
|
296 |
+ free(tmp); |
|
297 |
+ return CL_ECVDEXTR; |
|
298 |
+ } |
|
299 |
+ |
|
300 |
+ fclose(tmpd); |
|
301 |
+ unlink(tmp); |
|
302 |
+ free(tmp); |
|
303 |
+ |
|
304 |
+ /* end */ |
|
305 |
+ |
|
306 |
+ /* load extracted directory */ |
|
307 |
+ cl_loaddbdir(dir, root, virnum); |
|
308 |
+ |
|
309 |
+ cli_rmdirs(dir); |
|
310 |
+ free(dir); |
|
311 |
+ |
|
312 |
+ return 0; |
|
313 |
+} |
... | ... |
@@ -119,8 +119,10 @@ char *cl_strerror(int clerror) |
119 | 119 |
return "Malformed database."; |
120 | 120 |
case CL_EPATSHORT: |
121 | 121 |
return "Too short pattern detected."; |
122 |
+ case CL_ECVDEXTR: |
|
123 |
+ return "CVD extraction failure."; |
|
122 | 124 |
case CL_ENULLARG: |
123 |
- return "Null argument passed when initialized is required."; |
|
125 |
+ return "Null argument passed while initialized is required."; |
|
124 | 126 |
default: |
125 | 127 |
return "Unknown error code."; |
126 | 128 |
} |
... | ... |
@@ -200,6 +202,19 @@ void *cli_calloc(size_t nmemb, size_t size) |
200 | 200 |
} else return alloc; |
201 | 201 |
} |
202 | 202 |
|
203 |
+void *cli_realloc(void *ptr, size_t size) |
|
204 |
+{ |
|
205 |
+ void *alloc; |
|
206 |
+ |
|
207 |
+ alloc = realloc(ptr, size); |
|
208 |
+ |
|
209 |
+ if(!alloc) { |
|
210 |
+ cli_errmsg("cli_realloc(): Can't re-allocate memory to %d byte.\n", size); |
|
211 |
+ perror("realloc_problem"); |
|
212 |
+ return NULL; |
|
213 |
+ } else return alloc; |
|
214 |
+} |
|
215 |
+ |
|
203 | 216 |
#ifndef C_URANDOM |
204 | 217 |
/* it's very weak */ |
205 | 218 |
#include <sys/time.h> |
... | ... |
@@ -253,7 +268,8 @@ unsigned int cl_rndnum(unsigned int max) |
253 | 253 |
} |
254 | 254 |
#endif |
255 | 255 |
|
256 |
-char *cli_gentemp(const char *dir) |
|
256 |
+/* it uses MD5 to avoid potential races in tmp */ |
|
257 |
+char *cl_gentemp(const char *dir) |
|
257 | 258 |
{ |
258 | 259 |
char *name, *mdir, *tmp; |
259 | 260 |
unsigned char salt[32]; |
... | ... |
@@ -26,7 +26,7 @@ void cli_errmsg(const char *str, ...); |
26 | 26 |
void cli_dbgmsg(const char *str, ...); |
27 | 27 |
void *cli_malloc(size_t nmemb); |
28 | 28 |
void *cli_calloc(size_t nmemb, size_t size); |
29 |
-char *cli_gentemp(const char *dir); |
|
29 |
+void *cli_realloc(void *ptr, size_t size); |
|
30 | 30 |
int cli_rmdirs(const char *dirname); |
31 | 31 |
|
32 | 32 |
#endif |
... | ... |
@@ -1,6 +1,5 @@ |
1 |
- |
|
2 | 1 |
/* |
3 |
- * Copyright (C) 2002 Tomasz Kojm <zolw@konarski.edu.pl> |
|
2 |
+ * Copyright (C) 2002, 2003 Tomasz Kojm <zolw@konarski.edu.pl> |
|
4 | 3 |
* |
5 | 4 |
* This program is free software; you can redistribute it and/or modify |
6 | 5 |
* it under the terms of the GNU General Public License as published by |
... | ... |
@@ -90,6 +89,17 @@ int cl_loaddb(const char *filename, struct cl_node **root, int *virnum) |
90 | 90 |
|
91 | 91 |
cli_dbgmsg("Loading %s\n", filename); |
92 | 92 |
|
93 |
+ /* check for CVD file */ |
|
94 |
+ fgets(buffer, 12, fd); |
|
95 |
+ fseek(fd, 0L, SEEK_SET); |
|
96 |
+ |
|
97 |
+ if(!strncmp(buffer, "ClamAV-VDB:", 11)) { |
|
98 |
+ cli_dbgmsg("%s: CVD file detected\n", filename); |
|
99 |
+ ret = cli_cvdload(fd, root, virnum); |
|
100 |
+ fclose(fd); |
|
101 |
+ return ret; |
|
102 |
+ } |
|
103 |
+ |
|
93 | 104 |
while(fgets(buffer, BUFFSIZE, fd)) { |
94 | 105 |
|
95 | 106 |
/* for forward compatibility */ |
... | ... |
@@ -181,11 +191,15 @@ int cl_loaddbdir(const char *dirname, struct cl_node **root, int *virnum) |
181 | 181 |
|
182 | 182 |
while((dent = readdir(dd))) { |
183 | 183 |
if(dent->d_ino) { |
184 |
- if(strcmp(dent->d_name, ".") && strcmp(dent->d_name, "..") && (cli_strbcasestr(dent->d_name, ".db") || cli_strbcasestr(dent->d_name, ".db2"))) { |
|
184 |
+ if(strcmp(dent->d_name, ".") && strcmp(dent->d_name, "..") && |
|
185 |
+ (cli_strbcasestr(dent->d_name, ".db") || |
|
186 |
+ cli_strbcasestr(dent->d_name, ".db2") || |
|
187 |
+ cli_strbcasestr(dent->d_name, ".cvd"))) { |
|
188 |
+ |
|
185 | 189 |
dbfile = (char *) cli_calloc(strlen(dent->d_name) + strlen(dirname) + 2, sizeof(char)); |
186 | 190 |
|
187 | 191 |
if(!dbfile) { |
188 |
- cli_dbgmsg("cl_loaddbdir() -> dbfile == NULL\n"); |
|
192 |
+ cli_dbgmsg("cl_loaddbdir(): dbfile == NULL\n"); |
|
189 | 193 |
closedir(dd); |
190 | 194 |
return CL_EMEM; |
191 | 195 |
} |
... | ... |
@@ -49,6 +49,7 @@ int cli_scanrar_inuse = 0; |
49 | 49 |
|
50 | 50 |
#define SCAN_ARCHIVE (options & CL_ARCHIVE) |
51 | 51 |
#define SCAN_MAIL (options & CL_MAIL) |
52 |
+#define DISABLE_RAR (options & CL_DISABLERAR) |
|
52 | 53 |
|
53 | 54 |
#define MAGIC_BUFFER_SIZE 14 |
54 | 55 |
#define RAR_MAGIC_STR "Rar!" |
... | ... |
@@ -555,7 +556,7 @@ int cli_scanmail(int desc, char **virname, long int *scanned, const struct cl_no |
555 | 555 |
#endif |
556 | 556 |
|
557 | 557 |
/* generate the temporary directory */ |
558 |
- dir = cli_gentemp(tmpdir); |
|
558 |
+ dir = cl_gentemp(tmpdir); |
|
559 | 559 |
if(mkdir(dir, 0700)) { |
560 | 560 |
cli_errmsg("ScanMail -> Can't create temporary directory %s\n", dir); |
561 | 561 |
/* |
... | ... |
@@ -619,22 +620,23 @@ int cli_magic_scandesc(int desc, char **virname, long int *scanned, const struct |
619 | 619 |
|
620 | 620 |
if (bread != MAGIC_BUFFER_SIZE) { |
621 | 621 |
/* short read: No need to do magic */ |
622 |
+ (*reclev)--; |
|
622 | 623 |
return ret; |
623 | 624 |
} |
624 | 625 |
#ifdef CL_THREAD_SAFE |
625 | 626 |
/* this check protects against recursive deadlock */ |
626 |
- if(SCAN_ARCHIVE && !cli_scanrar_inuse && !strncmp(magic, RAR_MAGIC_STR, strlen(RAR_MAGIC_STR))) { |
|
627 |
+ if(!DISABLE_RAR && SCAN_ARCHIVE && !cli_scanrar_inuse && !strncmp(magic, RAR_MAGIC_STR, strlen(RAR_MAGIC_STR))) { |
|
627 | 628 |
ret = cli_scanrar(desc, virname, scanned, root, limits, options, reclev); |
628 | 629 |
} |
629 | 630 |
#else |
630 |
- if(SCAN_ARCHIVE && !strncmp(magic, RAR_MAGIC_STR, strlen(RAR_MAGIC_STR))) { |
|
631 |
+ if(!DISABLE_RAR && SCAN_ARCHIVE && !strncmp(magic, RAR_MAGIC_STR, strlen(RAR_MAGIC_STR))) { |
|
631 | 632 |
ret = cli_scanrar(desc, virname, scanned, root, limits, options, reclev); |
632 | 633 |
} |
633 | 634 |
#endif |
634 | 635 |
#ifdef HAVE_ZLIB_H |
635 | 636 |
else if(SCAN_ARCHIVE && !strncmp(magic, ZIP_MAGIC_STR, strlen(ZIP_MAGIC_STR))) { |
636 | 637 |
ret = cli_scanzip(desc, virname, scanned, root, limits, options, reclev); |
637 |
- } else if(!strncmp(magic, GZIP_MAGIC_STR, strlen(GZIP_MAGIC_STR))) { |
|
638 |
+ } else if(SCAN_ARCHIVE && !strncmp(magic, GZIP_MAGIC_STR, strlen(GZIP_MAGIC_STR))) { |
|
638 | 639 |
ret = cli_scangzip(desc, virname, scanned, root, limits, options, reclev); |
639 | 640 |
} |
640 | 641 |
#endif |
... | ... |
@@ -648,10 +650,10 @@ int cli_magic_scandesc(int desc, char **virname, long int *scanned, const struct |
648 | 648 |
} |
649 | 649 |
else if(SCAN_MAIL && !strncmp(magic, RAWMAIL_MAGIC_STR, strlen(RAWMAIL_MAGIC_STR))) { |
650 | 650 |
ret = cli_scanmail(desc, virname, scanned, root, limits, options, reclev); |
651 |
- } else if(!strncmp(magic, MAILDIR_MAGIC_STR, strlen(MAILDIR_MAGIC_STR))) { |
|
651 |
+ } else if(SCAN_MAIL && !strncmp(magic, MAILDIR_MAGIC_STR, strlen(MAILDIR_MAGIC_STR))) { |
|
652 | 652 |
cli_dbgmsg("Recognized Maildir mail file.\n"); |
653 | 653 |
ret = cli_scanmail(desc, virname, scanned, root, limits, options, reclev); |
654 |
- } else if(!strncmp(magic, DELIVERED_MAGIC_STR, strlen(DELIVERED_MAGIC_STR))) { |
|
654 |
+ } else if(SCAN_MAIL && !strncmp(magic, DELIVERED_MAGIC_STR, strlen(DELIVERED_MAGIC_STR))) { |
|
655 | 655 |
cli_dbgmsg("Recognized (Delivered-To) mail file.\n"); |
656 | 656 |
ret = cli_scanmail(desc, virname, scanned, root, limits, options, reclev); |
657 | 657 |
} |
... | ... |
@@ -2,7 +2,7 @@ |
2 | 2 |
* Author: |
3 | 3 |
* Guido Draheim <guidod@gmx.de> |
4 | 4 |
* |
5 |
- * Copyright (c) 2001 Guido Draheim |
|
5 |
+ * Copyright (c) 2001,2002,2003 Guido Draheim |
|
6 | 6 |
* All rights reserved, |
7 | 7 |
* use under the restrictions of the |
8 | 8 |
* Lesser GNU General Public License |
... | ... |
@@ -53,15 +53,34 @@ |
53 | 53 |
#define _zzip_inline inline |
54 | 54 |
#endif |
55 | 55 |
#endif |
56 |
+#ifndef _zzip_size_t |
|
57 |
+#ifdef ZZIP_size_t |
|
58 |
+#define _zzip_size_t ZZIP_size_t |
|
59 |
+#else |
|
60 |
+#define _zzip_size_t size_t |
|
61 |
+#endif |
|
62 |
+#endif |
|
63 |
+#ifndef _zzip_ssize_t |
|
64 |
+#ifdef ZZIP_ssize_t |
|
65 |
+#define _zzip_ssize_t ZZIP_ssize_t |
|
66 |
+#else |
|
67 |
+#define _zzip_ssize_t ssize_t |
|
68 |
+#endif |
|
69 |
+#endif |
|
56 | 70 |
|
57 | 71 |
/* whether this library shall use a 64bit off_t largefile variant in 64on32: */ |
58 | 72 |
/* (some exported names must be renamed to avoid bad calls after linking) */ |
59 |
-#if defined ZZIP_LARGEFILE_SENSITIVE && _FILE_OFFSET_BITS+0 == 64 |
|
60 |
-#define ZZIP_LARGEFILE_RENAME |
|
61 |
-#elif defined _LARGE_FILES /* on AIX */ |
|
62 |
-#define ZZIP_LARGEFILE_RENAME |
|
73 |
+#if defined ZZIP_LARGEFILE_SENSITIVE |
|
74 |
+# if _FILE_OFFSET_BITS+0 == 64 |
|
75 |
+# define ZZIP_LARGEFILE_RENAME |
|
76 |
+# elif defined _LARGE_FILES /* used on older AIX to get at 64bit off_t */ |
|
77 |
+# define ZZIP_LARGEFILE_RENAME |
|
78 |
+# elif defined _ZZIP_LARGEFILE /* or simply use this one for zzip64 runs */ |
|
79 |
+# define ZZIP_LARGEFILE_RENAME |
|
80 |
+# endif |
|
63 | 81 |
#endif |
64 |
-/* if some were forgotten but required to have 64bit off_t largefile.. */ |
|
82 |
+ |
|
83 |
+/* if the environment did not setup these for 64bit off_t largefile... */ |
|
65 | 84 |
#ifdef ZZIP_LARGEFILE_RENAME |
66 | 85 |
# ifndef _FILE_OFFSET_BITS |
67 | 86 |
# ifdef ZZIP__FILE_OFFSET_BITS /* == 64 */ |
... | ... |
@@ -70,7 +89,12 @@ |
70 | 70 |
# endif |
71 | 71 |
# ifndef _LARGE_FILES |
72 | 72 |
# ifdef ZZIP__LARGE_FILES /* == 1 */ |
73 |
-# define _LARGE_FILES 1 |
|
73 |
+# define _LARGE_FILES ZZIP__LARGE_FILES |
|
74 |
+# endif |
|
75 |
+# endif |
|
76 |
+# ifndef _LARGEFILE_SOURCE |
|
77 |
+# ifdef ZZIP__LARGEFILE_SOURCE /* == 1 */ |
|
78 |
+# define _LARGEFILE_SOURCE ZZIP__LARGEFILE_SOURCE |
|
74 | 79 |
# endif |
75 | 80 |
# endif |
76 | 81 |
#endif |
... | ... |
@@ -141,6 +165,11 @@ |
141 | 141 |
#define __attribute__(X) |
142 | 142 |
#endif |
143 | 143 |
|
144 |
+#if defined ZZIP_EXPORTS || defined ZZIPLIB_EXPORTS |
|
145 |
+# undef ZZIP_DLL |
|
146 |
+#define ZZIP_DLL 1 |
|
147 |
+#endif |
|
148 |
+ |
|
144 | 149 |
/* based on zconf.h : */ |
145 | 150 |
/* compile with -DZZIP_DLL for Windows DLL support */ |
146 | 151 |
#if defined ZZIP_DLL |
... | ... |
@@ -1,4 +1,3 @@ |
1 |
-#define USE_DIRENT 0 |
|
2 | 1 |
/* |
3 | 2 |
* Author: |
4 | 3 |
* Guido Draheim <guidod@gmx.de> |
... | ... |
@@ -24,6 +23,8 @@ |
24 | 24 |
#include <stdio.h> |
25 | 25 |
#endif |
26 | 26 |
|
27 |
+//#include "__dirent.h" |
|
28 |
+ |
|
27 | 29 |
#ifndef offsetof |
28 | 30 |
#pragma warning had to DEFINE offsetof as it was not in stddef.h |
29 | 31 |
#define offsetof(T,M) ((unsigned)(& ((T*)0)->M)) |
... | ... |
@@ -50,11 +51,13 @@ zzip_rewinddir(ZZIP_DIR * dir) |
50 | 50 |
{ |
51 | 51 |
if (! dir) return; |
52 | 52 |
|
53 |
+ /* |
|
53 | 54 |
if (USE_DIRENT && dir->realdir) |
54 | 55 |
{ |
55 | 56 |
_zzip_rewinddir(dir->realdir); |
56 | 57 |
return; |
57 | 58 |
} |
59 |
+ */ |
|
58 | 60 |
|
59 | 61 |
if (dir->hdr0) |
60 | 62 |
dir->hdr = dir->hdr0; |
... | ... |
@@ -118,11 +121,12 @@ zzip_readdir(ZZIP_DIR * dir) |
118 | 118 |
{ |
119 | 119 |
if (! dir) { errno=EBADF; return 0; } |
120 | 120 |
|
121 |
+ /* |
|
121 | 122 |
if (USE_DIRENT && dir->realdir) |
122 | 123 |
{ |
123 | 124 |
if (! real_readdir(dir)) |
124 | 125 |
return 0; |
125 |
- }else |
|
126 |
+ }else */ |
|
126 | 127 |
{ |
127 | 128 |
if (! dir->hdr) return 0; |
128 | 129 |
|
... | ... |
@@ -147,10 +151,10 @@ zzip_telldir(ZZIP_DIR* dir) |
147 | 147 |
{ |
148 | 148 |
if (! dir) { errno=EBADF; return -1; } |
149 | 149 |
|
150 |
- if (USE_DIRENT && dir->realdir) |
|
150 |
+ /* if (USE_DIRENT && dir->realdir) |
|
151 | 151 |
{ |
152 | 152 |
return _zzip_telldir(dir->realdir); |
153 |
- }else |
|
153 |
+ }else*/ |
|
154 | 154 |
{ |
155 | 155 |
return ((zzip_off_t) ((char*) dir->hdr - (char*) dir->hdr0)); |
156 | 156 |
} |
... | ... |
@@ -164,10 +168,10 @@ zzip_seekdir(ZZIP_DIR* dir, zzip_off_t offset) |
164 | 164 |
{ |
165 | 165 |
if (! dir) return; |
166 | 166 |
|
167 |
- if (USE_DIRENT && dir->realdir) |
|
167 |
+ /*if (USE_DIRENT && dir->realdir) |
|
168 | 168 |
{ |
169 | 169 |
_zzip_seekdir(dir->realdir, offset); |
170 |
- }else |
|
170 |
+ }else*/ |
|
171 | 171 |
{ |
172 | 172 |
dir->hdr = (struct zzip_dir_hdr*) |
173 | 173 |
(dir->hdr0 ? (char*) dir->hdr0 + (size_t) offset : 0); |
... | ... |
@@ -229,6 +233,23 @@ zzip_opendir_ext_io(zzip_char_t* filename, int o_modes, |
229 | 229 |
# ifdef ZZIP_HAVE_SYS_STAT_H |
230 | 230 |
if (stat(filename, &st) >= 0 && S_ISDIR(st.st_mode) |
231 | 231 |
){ |
232 |
+ /* if (USE_DIRENT) |
|
233 |
+ { |
|
234 |
+ _zzip_DIR* realdir = _zzip_opendir(filename); |
|
235 |
+ if (realdir) |
|
236 |
+ { |
|
237 |
+ if (! (dir = (ZZIP_DIR *)calloc(1, sizeof (*dir)))) |
|
238 |
+ { |
|
239 |
+ _zzip_closedir(realdir); |
|
240 |
+ return 0; |
|
241 |
+ }else |
|
242 |
+ { |
|
243 |
+ dir->realdir = realdir; |
|
244 |
+ dir->realname = strdup(filename); |
|
245 |
+ return dir; |
|
246 |
+ } |
|
247 |
+ } |
|
248 |
+ } */ |
|
232 | 249 |
return 0; |
233 | 250 |
} |
234 | 251 |
# endif /* HAVE_SYS_STAT_H */ |
... | ... |
@@ -253,13 +274,13 @@ zzip_closedir(ZZIP_DIR* dir) |
253 | 253 |
{ |
254 | 254 |
if (! dir) { errno = EBADF; return -1; } |
255 | 255 |
|
256 |
- if (USE_DIRENT && dir->realdir) |
|
256 |
+ /*if (USE_DIRENT && dir->realdir) |
|
257 | 257 |
{ |
258 | 258 |
_zzip_closedir(dir->realdir); |
259 | 259 |
free(dir->realname); |
260 | 260 |
free(dir); |
261 | 261 |
return 0; |
262 |
- }else |
|
262 |
+ }else*/ |
|
263 | 263 |
{ |
264 | 264 |
zzip_dir_close(dir); |
265 | 265 |
return 0; |
... | ... |
@@ -16,14 +16,15 @@ |
16 | 16 |
|
17 | 17 |
#include "strc.h" |
18 | 18 |
|
19 |
-#include <string.h> |
|
20 | 19 |
#include <sys/types.h> /* njh@bandsman.co.uk: for icc7.0 */ |
20 |
+#include <string.h> |
|
21 | 21 |
#include <sys/stat.h> |
22 | 22 |
#include <errno.h> |
23 | 23 |
#include <stdlib.h> |
24 | 24 |
#include <ctype.h> |
25 | 25 |
|
26 | 26 |
#include <zzipformat.h> |
27 |
+//#include "__debug.h" |
|
27 | 28 |
|
28 | 29 |
#if 0 |
29 | 30 |
# if defined ZZIP_HAVE_IO_H |
... | ... |
@@ -88,17 +89,14 @@ zzip_file_saveoffset(ZZIP_FILE * fp) |
88 | 88 |
return 0; |
89 | 89 |
} |
90 | 90 |
|
91 |
- |
|
92 |
- |
|
93 |
-# ifndef ZZIP_CHECK_BACKSLASH_DIRSEPARATOR |
|
94 |
-# define ZZIP_CHECK_BACKSLASH_DIRSEPARATOR 0 |
|
91 |
+# ifndef ZZIP_CHECK_BACKSLASH_DIRSEPARATOR /* NOTE: also default */ |
|
92 |
+# define ZZIP_CHECK_BACKSLASH_DIRSEPARATOR 0 /* to "NO" on win32 ! */ |
|
95 | 93 |
# endif |
96 | 94 |
|
97 | 95 |
# if !defined strcasecmp && !defined ZZIP_HAVE_STRCASECMP |
98 | 96 |
# define ZZIP_CHECK_BACKSLASH_DIRSEPARATOR 1 |
99 | 97 |
# endif |
100 | 98 |
|
101 |
- |
|
102 | 99 |
#if ! ZZIP_CHECK_BACKSLASH_DIRSEPARATOR+0 |
103 | 100 |
#define dirsep_strrchr(N,C) strrchr(N,C) |
104 | 101 |
#define dirsep_casecmp strcasecmp |
... | ... |
@@ -172,6 +170,9 @@ zzip_file_open(ZZIP_DIR * dir, zzip_char_t* name, int o_mode) |
172 | 172 |
if (n) hdr_name = n + 1; |
173 | 173 |
} |
174 | 174 |
|
175 |
+ //HINT4("name='%s', compr=%d, size=%d\n", |
|
176 |
+ // hdr->d_name, hdr->d_compr, hdr->d_usize); |
|
177 |
+ |
|
175 | 178 |
if (!cmp(hdr_name, name)) |
176 | 179 |
{ |
177 | 180 |
switch (hdr->d_compr) |
... | ... |
@@ -222,11 +223,11 @@ zzip_file_open(ZZIP_DIR * dir, zzip_char_t* name, int o_mode) |
222 | 222 |
|
223 | 223 |
{ /* skip local header - should test tons of other info, |
224 | 224 |
* but trust that those are correct */ |
225 |
- int dataoff; |
|
225 |
+ zzip_ssize_t dataoff; |
|
226 | 226 |
struct zzip_file_header * p = (void*) fp->buf32k; |
227 | 227 |
|
228 | 228 |
dataoff = dir->io->read(dir->fd, (void*)p, sizeof(*p)); |
229 |
- if (dataoff < (int) sizeof(*p)) |
|
229 |
+ if (dataoff < (zzip_ssize_t)sizeof(*p)) |
|
230 | 230 |
{ err = ZZIP_DIR_READ; goto error; } |
231 | 231 |
if (! ZZIP_FILE_HEADER_CHECKMAGIC(p)) /* PK\3\4 */ |
232 | 232 |
{ err = ZZIP_CORRUPTED; goto error; } |
... | ... |
@@ -323,12 +324,12 @@ zzip_close(ZZIP_FILE* fp) |
323 | 323 |
* required just that but the latest zlib would work just fine with |
324 | 324 |
* a smaller buffer. |
325 | 325 |
*/ |
326 |
-int |
|
327 |
-zzip_file_read(ZZIP_FILE * fp, char * buf, int len) |
|
326 |
+zzip_ssize_t |
|
327 |
+zzip_file_read(ZZIP_FILE * fp, char * buf, zzip_size_t len) |
|
328 | 328 |
{ |
329 | 329 |
ZZIP_DIR * dir; |
330 |
- int l; |
|
331 |
- int rv; |
|
330 |
+ zzip_size_t l; |
|
331 |
+ zzip_ssize_t rv; |
|
332 | 332 |
|
333 | 333 |
if (! fp || ! fp->dir) return 0; |
334 | 334 |
|
... | ... |
@@ -358,14 +359,15 @@ zzip_file_read(ZZIP_FILE * fp, char * buf, int len) |
358 | 358 |
|
359 | 359 |
do { |
360 | 360 |
int err; |
361 |
- int startlen; |
|
361 |
+ zzip_size_t startlen; |
|
362 | 362 |
|
363 | 363 |
if (fp->crestlen > 0 && fp->d_stream.avail_in == 0) |
364 | 364 |
{ |
365 |
- int cl = fp->crestlen > ZZIP_32K ? ZZIP_32K : fp->crestlen; |
|
366 |
- /* int cl = fp->crestlen > 128? 128: fp->crestlen; */ |
|
365 |
+ zzip_size_t cl = ( fp->crestlen < ZZIP_32K ? |
|
366 |
+ fp->crestlen : ZZIP_32K ); |
|
367 |
+ /* zzip_size_t cl = fp->crestlen > 128 ? 128 : fp->crestlen; */ |
|
367 | 368 |
|
368 |
- int i = fp->io->read(dir->fd, fp->buf32k, cl); |
|
369 |
+ zzip_ssize_t i = fp->io->read(dir->fd, fp->buf32k, cl); |
|
369 | 370 |
if (i <= 0) |
370 | 371 |
{ |
371 | 372 |
dir->errcode = ZZIP_DIR_READ; /* or ZZIP_DIR_READ_EOF ? */ |
... | ... |
@@ -412,14 +414,14 @@ zzip_file_read(ZZIP_FILE * fp, char * buf, int len) |
412 | 412 |
* perform a normal => read(2)-call, otherwise => zzip_file_read is called |
413 | 413 |
* to decompress the data stream and any error is mapped to => errno(3). |
414 | 414 |
*/ |
415 |
-int |
|
416 |
-zzip_read(ZZIP_FILE * fp, char * buf, int len) |
|
415 |
+zzip_ssize_t |
|
416 |
+zzip_read(ZZIP_FILE * fp, char * buf, zzip_size_t len) |
|
417 | 417 |
{ |
418 | 418 |
if (! fp) return 0; |
419 | 419 |
if (! fp->dir) |
420 | 420 |
{ return fp->io->read(fp->fd, buf, len); } /* stat fd */ |
421 | 421 |
else |
422 |
- { register int v; |
|
422 |
+ { register zzip_ssize_t v; |
|
423 | 423 |
v = zzip_file_read(fp, buf, len); |
424 | 424 |
if (v == -1) { errno = zzip_errno(fp->dir->errcode); } |
425 | 425 |
return v; |
... | ... |
@@ -428,8 +430,8 @@ zzip_read(ZZIP_FILE * fp, char * buf, int len) |
428 | 428 |
|
429 | 429 |
/** => zzip_read |
430 | 430 |
*/ |
431 |
-int |
|
432 |
-zzip_fread(void *ptr, int size, int nmemb, ZZIP_FILE *file) |
|
431 |
+zzip_size_t |
|
432 |
+zzip_fread(void *ptr, zzip_size_t size, zzip_size_t nmemb, ZZIP_FILE *file) |
|
433 | 433 |
{ |
434 | 434 |
if (! size) size=1; |
435 | 435 |
return zzip_read (file, ptr, size*nmemb)/size; |
... | ... |
@@ -714,7 +716,7 @@ zzip_open_shared_io (ZZIP_FILE* stream, |
714 | 714 |
/* see if we can share the same zip directory */ |
715 | 715 |
if (stream && stream->dir && stream->dir->realname) |
716 | 716 |
{ |
717 |
- int len = strlen (stream->dir->realname); |
|
717 |
+ zzip_size_t len = strlen (stream->dir->realname); |
|
718 | 718 |
if (! memcmp (filename, stream->dir->realname, len) && |
719 | 719 |
filename[len] == '/' && filename[len+1]) |
720 | 720 |
{ |
... | ... |
@@ -864,10 +866,10 @@ zzip_rewind(ZZIP_FILE *fp) |
864 | 864 |
* how gzio implements it, so I'm not sure there is a better way |
865 | 865 |
* without using the internals of the algorithm. |
866 | 866 |
*/ |
867 |
-int |
|
868 |
-zzip_seek(ZZIP_FILE * fp, int offset, int whence) |
|
867 |
+zzip_off_t |
|
868 |
+zzip_seek(ZZIP_FILE * fp, zzip_off_t offset, int whence) |
|
869 | 869 |
{ |
870 |
- int cur_pos, rel_ofs, read_size, ofs; |
|
870 |
+ zzip_off_t cur_pos, rel_ofs, read_size, ofs; |
|
871 | 871 |
ZZIP_DIR *dir; |
872 | 872 |
|
873 | 873 |
if (! fp) |
... | ... |
@@ -875,7 +877,7 @@ zzip_seek(ZZIP_FILE * fp, int offset, int whence) |
875 | 875 |
|
876 | 876 |
if (! fp->dir) |
877 | 877 |
{ /* stat fd */ |
878 |
- return fp->io->seeks(fp->fd,offset,whence); |
|
878 |
+ return fp->io->seeks(fp->fd, offset, whence); |
|
879 | 879 |
} |
880 | 880 |
|
881 | 881 |
cur_pos = zzip_tell(fp); |
... | ... |
@@ -914,7 +916,7 @@ zzip_seek(ZZIP_FILE * fp, int offset, int whence) |
914 | 914 |
if (read_size < 0) /* bad offset, before beginning of file */ |
915 | 915 |
return -1; |
916 | 916 |
|
917 |
- if (read_size + cur_pos > fp->usize) /* bad offset, past EOF */ |
|
917 |
+ if (read_size + cur_pos > (zzip_off_t)fp->usize) /* bad offset, past EOF */ |
|
918 | 918 |
return -1; |
919 | 919 |
|
920 | 920 |
if (read_size == 0) /* nothing to read */ |
... | ... |
@@ -953,10 +955,10 @@ zzip_seek(ZZIP_FILE * fp, int offset, int whence) |
953 | 953 |
|
954 | 954 |
while (read_size > 0) |
955 | 955 |
{ |
956 |
- int size = ZZIP_32K; |
|
957 |
- if (read_size < ZZIP_32K) size = (int)read_size; |
|
956 |
+ zzip_off_t size = ZZIP_32K; |
|
957 |
+ if (read_size < size/*32K*/) size = read_size; |
|
958 | 958 |
|
959 |
- size = zzip_file_read(fp, buf, size); |
|
959 |
+ size = zzip_file_read(fp, buf, (zzip_size_t)size); |
|
960 | 960 |
if (size <= 0) { free(buf); return -1; } |
961 | 961 |
|
962 | 962 |
read_size -= size; |
... | ... |
@@ -979,7 +981,7 @@ zzip_seek(ZZIP_FILE * fp, int offset, int whence) |
979 | 979 |
* calculated from the amount of data left and the total uncompressed |
980 | 980 |
* size; |
981 | 981 |
*/ |
982 |
-int |
|
982 |
+zzip_off_t |
|
983 | 983 |
zzip_tell(ZZIP_FILE * fp) |
984 | 984 |
{ |
985 | 985 |
if (! fp) |
... | ... |
@@ -65,10 +65,10 @@ struct zzip_file |
65 | 65 |
struct zzip_dir* dir; |
66 | 66 |
int fd; |
67 | 67 |
int method; |
68 |
- int restlen; |
|
69 |
- int crestlen; |
|
70 |
- int usize; |
|
71 |
- int csize; |
|
68 |
+ zzip_size_t restlen; |
|
69 |
+ zzip_size_t crestlen; |
|
70 |
+ zzip_size_t usize; |
|
71 |
+ zzip_size_t csize; |
|
72 | 72 |
/* added dataoffset member - data offset from start of zipfile*/ |
73 | 73 |
zzip_off_t dataoffset; |
74 | 74 |
char* buf32k; |
... | ... |
@@ -27,6 +27,11 @@ |
27 | 27 |
//#include "__mmap.h" |
28 | 28 |
//#include "__debug.h" |
29 | 29 |
|
30 |
+#define __sizeof(X) ((zzip_ssize_t)(sizeof(X))) |
|
31 |
+ |
|
32 |
+/* per default, we use a little hack to correct bad z_rootseek parts */ |
|
33 |
+#define ZZIP_CORRECT_ROOTSEEK 1 |
|
34 |
+ |
|
30 | 35 |
/* ------------------------- fetch helpers --------------------------------- */ |
31 | 36 |
|
32 | 37 |
/** |
... | ... |
@@ -39,7 +44,7 @@ uint32_t __zzip_get32(unsigned char * s) |
39 | 39 |
| ((uint32_t)s[1] << 8) | (uint32_t)s[0]; |
40 | 40 |
} |
41 | 41 |
|
42 |
-/** => __zzip_get16 |
|
42 |
+/** => __zzip_get32 |
|
43 | 43 |
* This function does the same for a 16 bit value. |
44 | 44 |
*/ |
45 | 45 |
uint16_t __zzip_get16(unsigned char * s) |
... | ... |
@@ -47,6 +52,88 @@ uint16_t __zzip_get16(unsigned char * s) |
47 | 47 |
return ((uint16_t)s[1] << 8) | (uint16_t)s[0]; |
48 | 48 |
} |
49 | 49 |
|
50 |
+/* --------------------------- internals -------------------------------- */ |
|
51 |
+/* internal functions of zziplib, avoid at all cost, changes w/o warning. |
|
52 |
+ * we do export them for debugging purpose and special external tools |
|
53 |
+ * which know what they do and which can adapt from version to version |
|
54 |
+ */ |
|
55 |
+ |
|
56 |
+int __zzip_find_disk_trailer( int fd, zzip_off_t filesize, |
|
57 |
+ struct zzip_disk_trailer * trailer, |
|
58 |
+ zzip_plugin_io_t io); |
|
59 |
+int __zzip_parse_root_directory( int fd, |
|
60 |
+ struct zzip_disk_trailer * trailer, |
|
61 |
+ struct zzip_dir_hdr ** hdr_return, |
|
62 |
+ zzip_plugin_io_t io); |
|
63 |
+ |
|
64 |
+_zzip_inline char* __zzip_aligned4(char* p); |
|
65 |
+ |
|
66 |
+/* ------------------------ harden routines ------------------------------ */ |
|
67 |
+ |
|
68 |
+#ifdef ZZIP_HARDEN |
|
69 |
+/* |
|
70 |
+ * check for inconsistent values in trailer and prefer lower seek value |
|
71 |
+ * - we fix values assuming the root directory was written at the end |
|
72 |
+ * and it is just before the zip trailer. Therefore, ... |
|
73 |
+ */ |
|
74 |
+_zzip_inline static void __fixup_rootseek( |
|
75 |
+ zzip_off_t offset_of_trailer, |
|
76 |
+ struct zzip_disk_trailer* trailer) |
|
77 |
+{ |
|
78 |
+ if ( (zzip_off_t) ZZIP_GET32(trailer->z_rootseek) > |
|
79 |
+ offset_of_trailer - (zzip_off_t) ZZIP_GET32(trailer->z_rootsize) && |
|
80 |
+ offset_of_trailer > (zzip_off_t) ZZIP_GET32(trailer->z_rootsize)) |
|
81 |
+ { |
|
82 |
+ register zzip_off_t offset; |
|
83 |
+ offset = offset_of_trailer - ZZIP_GET32(trailer->z_rootsize); |
|
84 |
+ trailer->z_rootseek[0] = offset & 0xff; |
|
85 |
+ trailer->z_rootseek[1] = offset >> 8 & 0xff; |
|
86 |
+ trailer->z_rootseek[2] = offset >> 16 & 0xff; |
|
87 |
+ trailer->z_rootseek[3] = offset >> 24 & 0xff; |
|
88 |
+ //HINT2("new rootseek=%li", |
|
89 |
+ // (long) ZZIP_GET32(trailer->z_rootseek)); |
|
90 |
+ } |
|
91 |
+} |
|
92 |
+#define __correct_rootseek(A,B,C) |
|
93 |
+ |
|
94 |
+#elif defined ZZIP_CORRECT_ROOTSEEK |
|
95 |
+/* store the seekvalue of the trailer into the "z_magic" field and with |
|
96 |
+ * a 64bit off_t we overwrite z_disk/z_finaldisk as well. If you change |
|
97 |
+ * anything in zziplib or dump the trailer structure then watch out that |
|
98 |
+ * these are still unused, so that this code may still (ab)use those. */ |
|
99 |
+#define __fixup_rootseek(_offset_of_trailer, _trailer) \ |
|
100 |
+ *(zzip_off_t*)_trailer = _offset_of_trailer; |
|
101 |
+#define __correct_rootseek( _u_rootseek, _u_rootsize, _trailer) \ |
|
102 |
+ if (_u_rootseek > *(zzip_off_t*)_trailer - _u_rootsize) \ |
|
103 |
+ _u_rootseek = *(zzip_off_t*)_trailer - _u_rootsize; |
|
104 |
+#else |
|
105 |
+#define __fixup_rootseek(A,B) |
|
106 |
+#define __correct_rootseek(A,B,C) |
|
107 |
+#endif |
|
108 |
+ |
|
109 |
+ |
|
110 |
+#ifdef DEBUG |
|
111 |
+_zzip_inline static void __debug_dir_hdr (struct zzip_dir_hdr* hdr) |
|
112 |
+{ |
|
113 |
+ if (sizeof(struct zzip_dir_hdr) > sizeof(struct zzip_root_dirent)) |
|
114 |
+ { WARN1("internal sizeof-mismatch may break wreakage"); } |
|
115 |
+ /* the internal directory structure is never bigger than the |
|
116 |
+ * external zip central directory space had been beforehand |
|
117 |
+ * (as long as the following assertion holds...) |
|
118 |
+ */ |
|
119 |
+ |
|
120 |
+ //if (((unsigned)hdr)&3) |
|
121 |
+ //{ NOTE1("this machine's malloc(3) returns sth. not u32-aligned"); } |
|
122 |
+ /* we assume that if this machine's malloc has returned a non-aligned |
|
123 |
+ * memory block, then it is actually safe to access misaligned data, and |
|
124 |
+ * since it does only affect the first hdr it should not even bring about |
|
125 |
+ * too much of that cpu's speed penalty |
|
126 |
+ */ |
|
127 |
+} |
|
128 |
+#else |
|
129 |
+#define __debug_dir_hdr(X) |
|
130 |
+#endif |
|
131 |
+ |
|
50 | 132 |
/* -------------------------- low-level interface -------------------------- */ |
51 | 133 |
|
52 | 134 |
#if defined BUFSIZ |
... | ... |
@@ -70,11 +157,13 @@ __zzip_find_disk_trailer(int fd, zzip_off_t filesize, |
70 | 70 |
struct zzip_disk_trailer * trailer, |
71 | 71 |
zzip_plugin_io_t io) |
72 | 72 |
{ |
73 |
+/* |
|
73 | 74 |
#ifdef DEBUG |
74 |
-#define return(val) { e=val; goto cleanup; } |
|
75 |
+#define return(val) { e=val; HINT2("%s", zzip_strerror(e)); goto cleanup; } |
|
75 | 76 |
#else |
77 |
+*/ |
|
76 | 78 |
#define return(val) { e=val; goto cleanup; } |
77 |
-#endif |
|
79 |
+//#endif |
|
78 | 80 |
register int e; |
79 | 81 |
|
80 | 82 |
#ifndef _LOWSTK |
... | ... |
@@ -84,13 +173,13 @@ __zzip_find_disk_trailer(int fd, zzip_off_t filesize, |
84 | 84 |
char* buf = malloc(2*ZZIP_BUFSIZ); |
85 | 85 |
#endif |
86 | 86 |
zzip_off_t offset = 0; |
87 |
- size_t maplen = 0; |
|
87 |
+ zzip_off_t maplen = 0; /* mmap(),read(),getpagesize() use size_t !! */ |
|
88 | 88 |
char* fd_map = 0; |
89 | 89 |
|
90 | 90 |
if (!trailer) |
91 | 91 |
{ return(EINVAL); } |
92 | 92 |
|
93 |
- if (filesize < sizeof(struct zzip_disk_trailer)) |
|
93 |
+ if (filesize < __sizeof(struct zzip_disk_trailer)) |
|
94 | 94 |
{ return(ZZIP_DIR_TOO_SHORT); } |
95 | 95 |
|
96 | 96 |
if (!buf) |
... | ... |
@@ -99,8 +188,7 @@ __zzip_find_disk_trailer(int fd, zzip_off_t filesize, |
99 | 99 |
offset = filesize; /* a.k.a. old offset */ |
100 | 100 |
while(1) /* outer loop */ |
101 | 101 |
{ |
102 |
- register unsigned char* p; |
|
103 |
- register unsigned char* s; |
|
102 |
+ register unsigned char* mapped; |
|
104 | 103 |
|
105 | 104 |
if (offset <= 0) { return(ZZIP_DIR_EDH_MISSING); } |
106 | 105 |
|
... | ... |
@@ -108,6 +196,34 @@ __zzip_find_disk_trailer(int fd, zzip_off_t filesize, |
108 | 108 |
if (filesize-offset > 64*1024) |
109 | 109 |
{ return(ZZIP_DIR_EDH_MISSING); } |
110 | 110 |
|
111 |
+ /* the new offset shall overlap with the area after the old offset! */ |
|
112 |
+ /*if (USE_MMAP && io->use_mmap) |
|
113 |
+ { |
|
114 |
+ zzip_off_t mapoff = offset; |
|
115 |
+ { |
|
116 |
+ zzip_off_t pagesize = _zzip_getpagesize (io->use_mmap); |
|
117 |
+ if (pagesize < ZZIP_BUFSIZ) goto non_mmap; |
|
118 |
+ if (mapoff == filesize && filesize > pagesize) |
|
119 |
+ mapoff -= pagesize; |
|
120 |
+ if (mapoff < pagesize) { |
|
121 |
+ maplen = mapoff + pagesize; mapoff = 0; |
|
122 |
+ } else { |
|
123 |
+ mapoff -= pagesize; maplen = 2*pagesize; |
|
124 |
+ if (mapoff & (pagesize-1)) { |
|
125 |
+ pagesize -= mapoff & (pagesize-1); |
|
126 |
+ mapoff += pagesize; |
|
127 |
+ maplen -= pagesize; |
|
128 |
+ } |
|
129 |
+ } |
|
130 |
+ if (mapoff + maplen > filesize) maplen = filesize - mapoff; |
|
131 |
+ } |
|
132 |
+ |
|
133 |
+ fd_map = _zzip_mmap(io->use_mmap, fd, mapoff, (zzip_size_t)maplen); |
|
134 |
+ if (fd_map == MAP_FAILED) goto non_mmap; |
|
135 |
+ mapped = fd_map; offset = mapoff; |
|
136 |
+ HINT3("mapped *%p len=%li", fd_map, (long) maplen); |
|
137 |
+ } else */ { |
|
138 |
+ non_mmap: |
|
111 | 139 |
fd_map = 0; /* have no mmap */ |
112 | 140 |
{ |
113 | 141 |
zzip_off_t pagesize = ZZIP_BUFSIZ; |
... | ... |
@@ -128,35 +244,52 @@ __zzip_find_disk_trailer(int fd, zzip_off_t filesize, |
128 | 128 |
|
129 | 129 |
if (io->seeks(fd, offset, SEEK_SET) < 0) |
130 | 130 |
{ return(ZZIP_DIR_SEEK); } |
131 |
- if (io->read(fd, buf, maplen) < (long)maplen) |
|
131 |
+ if (io->read(fd, buf, (zzip_size_t)maplen) < (zzip_ssize_t)maplen) |
|
132 | 132 |
{ return(ZZIP_DIR_READ); } |
133 |
- p = buf; /* success */ |
|
134 |
- |
|
133 |
+ mapped = buf; /* success */ |
|
134 |
+ //HINT5("offs=$%lx len=%li filesize=%li pagesize=%i", |
|
135 |
+ //(long)offset, (long)maplen, (long)filesize, ZZIP_BUFSIZ); |
|
136 |
+ } |
|
135 | 137 |
|
136 |
- /* now, check for the trailer-magic, hopefully near the end of file */ |
|
137 |
- for (s = p + maplen-1; (s >= p); s--) |
|
138 |
- { |
|
139 |
- if (*s == 'P' |
|
140 |
- && p+maplen-1-s > sizeof(*trailer)-2 |
|
141 |
- && ZZIP_DISK_TRAILER_CHECKMAGIC(s)) |
|
142 |
- { |
|
143 |
- /* if the file-comment is not present, it happens |
|
144 |
- that the z_comment field often isn't either */ |
|
145 |
- if (p+maplen-1-s > sizeof(*trailer)) |
|
146 |
- { memcpy (trailer, s, sizeof(*trailer)); } |
|
147 |
- else |
|
148 |
- { |
|
149 |
- memcpy (trailer, s, sizeof(*trailer)-2); |
|
150 |
- trailer->z_comment[0] = 0; trailer->z_comment[1] = 0; |
|
151 |
- } |
|
152 |
- |
|
153 |
- { return(0); } |
|
154 |
- } |
|
138 |
+ {/* now, check for the trailer-magic, hopefully near the end of file */ |
|
139 |
+ register unsigned char* end = mapped + maplen; |
|
140 |
+ register unsigned char* tail; |
|
141 |
+ for (tail = end-1; (tail >= mapped); tail--) |
|
142 |
+ { |
|
143 |
+ if ((*tail == 'P') && /* quick pre-check for trailer magic */ |
|
144 |
+ end-tail >= __sizeof(*trailer)-2 && |
|
145 |
+ ZZIP_DISK_TRAILER_CHECKMAGIC(tail)) |
|
146 |
+ { |
|
147 |
+ /* if the file-comment is not present, it happens |
|
148 |
+ that the z_comment field often isn't either */ |
|
149 |
+ if (end-tail >= __sizeof(*trailer)) |
|
150 |
+ { |
|
151 |
+ memcpy (trailer, tail, sizeof(*trailer)); |
|
152 |
+ }else{ |
|
153 |
+ memcpy (trailer, tail, sizeof(*trailer)-2); |
|
154 |
+ trailer->z_comment[0] = 0; |
|
155 |
+ trailer->z_comment[1] = 0; |
|
156 |
+ } |
|
157 |
+ |
|
158 |
+ __fixup_rootseek (offset + tail-mapped, trailer); |
|
159 |
+ { return(0); } |
|
160 |
+ } |
|
161 |
+ } |
|
155 | 162 |
} |
156 | 163 |
|
164 |
+ /*if (USE_MMAP && fd_map) |
|
165 |
+ { |
|
166 |
+ HINT3("unmap *%p len=%li", fd_map, (long) maplen); |
|
167 |
+ _zzip_munmap(io->use_mmap, fd_map, (zzip_size_t)maplen); fd_map = 0; |
|
168 |
+ }*/ |
|
157 | 169 |
} /*outer loop*/ |
158 | 170 |
|
159 | 171 |
cleanup: |
172 |
+ /*if (USE_MMAP && fd_map) |
|
173 |
+ { |
|
174 |
+ HINT3("unmap *%p len=%li", fd_map, (long) maplen); |
|
175 |
+ _zzip_munmap(io->use_mmap, fd_map, (zzip_size_t)maplen); |
|
176 |
+ }*/ |
|
160 | 177 |
# ifdef _LOWSTK |
161 | 178 |
free(buf); |
162 | 179 |
# endif |
... | ... |
@@ -174,8 +307,8 @@ __zzip_find_disk_trailer(int fd, zzip_off_t filesize, |
174 | 174 |
_zzip_inline char* __zzip_aligned4(char* p) |
175 | 175 |
{ |
176 | 176 |
#define aligned4 __zzip_aligned4 |
177 |
- p += ((long)p)&1; |
|
178 |
- p += ((long)p)&2; |
|
177 |
+ p += ((long)p)&1; /* warnings about truncation of a "pointer" */ |
|
178 |
+ p += ((long)p)&2; /* to a "long int" may be safely ignored :) */ |
|
179 | 179 |
return p; |
180 | 180 |
} |
181 | 181 |
|
... | ... |
@@ -196,34 +329,33 @@ __zzip_parse_root_directory(int fd, |
196 | 196 |
struct zzip_dir_hdr * hdr0; |
197 | 197 |
uint16_t * p_reclen = 0; |
198 | 198 |
short entries; |
199 |
- long offset; |
|
200 |
- char* fd_map = 0; |
|
199 |
+ long offset; /* offset from start of root directory */ |
|
200 |
+ char* fd_map = 0; |
|
201 | 201 |
int32_t fd_gap = 0; |
202 | 202 |
uint16_t u_entries = ZZIP_GET16(trailer->z_entries); |
203 | 203 |
uint32_t u_rootsize = ZZIP_GET32(trailer->z_rootsize); |
204 | 204 |
uint32_t u_rootseek = ZZIP_GET32(trailer->z_rootseek); |
205 |
+ __correct_rootseek (u_rootseek, u_rootsize, trailer); |
|
205 | 206 |
|
206 | 207 |
hdr0 = (struct zzip_dir_hdr*) malloc(u_rootsize); |
207 | 208 |
if (!hdr0) |
208 | 209 |
return ZZIP_DIRSIZE; |
209 |
- hdr = hdr0; |
|
210 |
+ hdr = hdr0; __debug_dir_hdr (hdr); |
|
210 | 211 |
|
211 |
-# ifdef DEBUG |
|
212 |
- if (sizeof(struct zzip_dir_hdr) > sizeof(struct zzip_root_dirent)) |
|
213 |
- { WARN1("internal sizeof-mismatch may break wreakage"); } |
|
214 |
- /* the internal directory structure is never bigger than the |
|
215 |
- * external zip central directory space had been beforehand |
|
216 |
- * (as long as the following assertion holds...) |
|
217 |
- */ |
|
218 |
- |
|
219 |
- if (((unsigned)hdr0)&3) |
|
220 |
- { NOTE1("this machine's malloc(3) returns sth. not u32-aligned"); } |
|
221 |
- /* we assume that if this machine's malloc has returned a non-aligned |
|
222 |
- * memory block, then it is actually safe to access misaligned data, and |
|
223 |
- * since it does only affect the first hdr it should not even bring about |
|
224 |
- * too much of that cpu's speed penalty |
|
225 |
- */ |
|
226 |
-# endif |
|
212 |
+ /*if (USE_MMAP && io->use_mmap) |
|
213 |
+ { |
|
214 |
+ fd_gap = u_rootseek & (_zzip_getpagesize(io->use_mmap)-1) ; |
|
215 |
+ HINT4(" mapseek=0x%x, maplen=%d, fd_gap=%d", |
|
216 |
+ u_rootseek-fd_gap, u_rootsize+fd_gap, fd_gap); |
|
217 |
+ fd_map = _zzip_mmap(io->use_mmap, |
|
218 |
+ fd, u_rootseek-fd_gap, u_rootsize+fd_gap); |
|
219 |
+ if (fd_map == MAP_FAILED) { |
|
220 |
+ NOTE2("map failed: %s",strerror(errno)); |
|
221 |
+ fd_map=0; |
|
222 |
+ }else{ |
|
223 |
+ HINT3("mapped *%p len=%i", fd_map, u_rootsize+fd_gap); |
|
224 |
+ } |
|
225 |
+ }*/ |
|
227 | 226 |
|
228 | 227 |
for (entries=u_entries, offset=0; entries > 0; entries--) |
229 | 228 |
{ |
... | ... |
@@ -236,11 +368,14 @@ __zzip_parse_root_directory(int fd, |
236 | 236 |
{ |
237 | 237 |
if (io->seeks(fd, u_rootseek+offset, SEEK_SET) < 0) |
238 | 238 |
return ZZIP_DIR_SEEK; |
239 |
- if (io->read(fd, &dirent, sizeof(dirent)) < sizeof(dirent)) |
|
239 |
+ if (io->read(fd, &dirent, sizeof(dirent)) < __sizeof(dirent)) |
|
240 | 240 |
return ZZIP_DIR_READ; |
241 | 241 |
d = &dirent; |
242 | 242 |
} |
243 | 243 |
|
244 |
+ if (offset+sizeof(*d) > u_rootsize) |
|
245 |
+ { /*FAIL2("%i's entry stretches beyond root directory", entries);*/ break;} |
|
246 |
+ |
|
244 | 247 |
# if 0 && defined DEBUG |
245 | 248 |
zzip_debug_xbuf ((unsigned char*) d, sizeof(*d) + 8); |
246 | 249 |
# endif |
... | ... |
@@ -248,8 +383,9 @@ __zzip_parse_root_directory(int fd, |
248 | 248 |
u_extras = ZZIP_GET16(d->z_extras); |
249 | 249 |
u_comment = ZZIP_GET16(d->z_comment); |
250 | 250 |
u_namlen = ZZIP_GET16(d->z_namlen); |
251 |
- |
|
252 |
- |
|
251 |
+ //HINT5("offset=0x%lx, size %ld, dirent *%p, hdr %p\n", |
|
252 |
+ // offset+u_rootseek, (long)u_rootsize, d, hdr); |
|
253 |
+ |
|
253 | 254 |
/* writes over the read buffer, Since the structure where data is |
254 | 255 |
copied is smaller than the data in buffer this can be done. |
255 | 256 |
It is important that the order of setting the fields is considered |
... | ... |
@@ -264,10 +400,12 @@ __zzip_parse_root_directory(int fd, |
264 | 264 |
hdr->d_compr = (uint8_t)ZZIP_GET16(d->z_compr); |
265 | 265 |
if (hdr->d_compr > 255) hdr->d_compr = 255; |
266 | 266 |
|
267 |
- if (fd_map) |
|
268 |
- { memcpy(hdr->d_name, fd_map+fd_gap+offset+sizeof(*d), u_namlen); } |
|
269 |
- else |
|
270 |
- { io->read(fd, hdr->d_name, u_namlen); } |
|
267 |
+ if (offset+sizeof(*d) + u_namlen > u_rootsize) |
|
268 |
+ { /*FAIL2("%i's name stretches beyond root directory", entries);*/ break;} |
|
269 |
+ |
|
270 |
+ if (fd_map) |
|
271 |
+ { memcpy(hdr->d_name, fd_map+fd_gap+offset+sizeof(*d), u_namlen); } |
|
272 |
+ else { io->read(fd, hdr->d_name, u_namlen); } |
|
271 | 273 |
hdr->d_name[u_namlen] = '\0'; |
272 | 274 |
hdr->d_namlen = u_namlen; |
273 | 275 |
|
... | ... |
@@ -275,26 +413,38 @@ __zzip_parse_root_directory(int fd, |
275 | 275 |
offset += sizeof(*d) + u_namlen + u_extras + u_comment; |
276 | 276 |
|
277 | 277 |
if (offset > (long)u_rootsize) |
278 |
- break; |
|
279 |
- |
|
278 |
+ { /*FAIL2("%i's end beyond root directory", entries);*/ entries--; break;} |
|
279 |
+ |
|
280 |
+ //HINT5("file %d { compr=%d crc32=$%x offset=%d", |
|
281 |
+ // entries, hdr->d_compr, hdr->d_crc32, hdr->d_off); |
|
282 |
+ //HINT5("csize=%d usize=%d namlen=%d extras=%d", |
|
283 |
+ // hdr->d_csize, hdr->d_usize, u_namlen, u_extras); |
|
284 |
+ //HINT5("comment=%d name='%s' %s <sizeof %d> } ", |
|
285 |
+ // u_comment, hdr->d_name, "",(int) sizeof(*d)); |
|
286 |
+ |
|
280 | 287 |
p_reclen = &hdr->d_reclen; |
281 | 288 |
|
282 | 289 |
{ register char* p = (char*) hdr; |
283 | 290 |
register char* q = aligned4 (p + sizeof(*hdr) + u_namlen + 1); |
284 |
- *p_reclen = q - p; |
|
291 |
+ *p_reclen = (uint16_t)(q - p); |
|
285 | 292 |
hdr = (struct zzip_dir_hdr*) q; |
286 | 293 |
} |
287 | 294 |
}/*for*/ |
288 | 295 |
|
289 |
- if (!p_reclen) |
|
290 |
- return 0; /* 0 (sane) entries in zip directory... */ |
|
291 |
- |
|
292 |
- *p_reclen = 0; /* mark end of list */ |
|
296 |
+ /*if (USE_MMAP && fd_map) |
|
297 |
+ { |
|
298 |
+ HINT3("unmap *%p len=%i", fd_map, u_rootsize+fd_gap); |
|
299 |
+ _zzip_munmap(io->use_mmap, fd_map, u_rootsize+fd_gap); |
|
300 |
+ }*/ |
|
293 | 301 |
|
294 |
- if (hdr_return) |
|
295 |
- *hdr_return = hdr0; |
|
302 |
+ if (p_reclen) |
|
303 |
+ { |
|
304 |
+ *p_reclen = 0; /* mark end of list */ |
|
296 | 305 |
|
297 |
- return 0; |
|
306 |
+ if (hdr_return) |
|
307 |
+ *hdr_return = hdr0; |
|
308 |
+ } /* else zero (sane) entries */ |
|
309 |
+ return (entries ? ZZIP_CORRUPTED : 0); |
|
298 | 310 |
} |
299 | 311 |
|
300 | 312 |
/* ------------------------- high-level interface ------------------------- */ |
... | ... |
@@ -444,13 +594,18 @@ __zzip_dir_parse (ZZIP_DIR* dir) |
444 | 444 |
* { rv = EINVAL; goto error; } |
445 | 445 |
*/ |
446 | 446 |
|
447 |
+ //HINT2("------------------ fd=%i", (int) dir->fd); |
|
447 | 448 |
if ((filesize = dir->io->filesize(dir->fd)) < 0) |
448 | 449 |
{ rv = ZZIP_DIR_STAT; goto error; } |
449 | 450 |
|
451 |
+ //HINT2("------------------ filesize=%ld", (long) filesize); |
|
450 | 452 |
if ((rv = __zzip_find_disk_trailer(dir->fd, filesize, &trailer, |
451 | 453 |
dir->io)) != 0) |
452 | 454 |
{ goto error; } |
453 | 455 |
|
456 |
+ //HINT5("directory = { entries= %d/%d, size= %d, seek= %d } ", |
|
457 |
+ // ZZIP_GET16(trailer.z_entries), ZZIP_GET16(trailer.z_finalentries), |
|
458 |
+ // ZZIP_GET32(trailer.z_rootsize), ZZIP_GET32(trailer.z_rootseek)); |
|
454 | 459 |
|
455 | 460 |
if ( (rv = __zzip_parse_root_directory(dir->fd, &trailer, &dir->hdr0, |
456 | 461 |
dir->io)) != 0) |
... | ... |
@@ -470,7 +625,7 @@ __zzip_try_open(zzip_char_t* filename, int filemode, |
470 | 470 |
{ |
471 | 471 |
auto char file[PATH_MAX]; |
472 | 472 |
int fd; |
473 |
- int len = strlen (filename); |
|
473 |
+ zzip_size_t len = strlen (filename); |
|
474 | 474 |
|
475 | 475 |
if (len+4 >= PATH_MAX) return -1; |
476 | 476 |
memcpy(file, filename, len+1); |
... | ... |
@@ -75,6 +75,9 @@ ZZIP_DIR* |
75 | 75 |
zzip_dir_fdopen_ext_io(int fd, zzip_error_t * errorcode_p, |
76 | 76 |
zzip_strings_t* ext, const zzip_plugin_io_t io); |
77 | 77 |
|
78 |
+ZZIP_DIR* /*depracated*/ |
|
79 |
+zzip_dir_alloc_ext_io (zzip_strings_t* ext, const zzip_plugin_io_t io); |
|
80 |
+ |
|
78 | 81 |
/* get 16/32 bits from little-endian zip-file to host byteorder */ |
79 | 82 |
uint32_t __zzip_get32(unsigned char * s); |
80 | 83 |
uint16_t __zzip_get16(unsigned char * s); |
... | ... |
@@ -3,12 +3,17 @@ |
3 | 3 |
* Guido Draheim <guidod@gmx.de> |
4 | 4 |
* Tomi Ollila <Tomi.Ollila@iki.fi> |
5 | 5 |
* |
6 |
- * Copyright (c) 1999,2000,2001,2002 Guido Draheim |
|
6 |
+ * Copyright (c) 1999,2000,2001,2002,2003 Guido Draheim |
|
7 | 7 |
* All rights reserved, |
8 | 8 |
* usage allowed under the restrictions of the |
9 | 9 |
* Lesser GNU General Public License |
10 | 10 |
* note the additional license information |
11 | 11 |
* that can be found in COPYING.ZZIP |
12 |
+ * |
|
13 |
+ * if you see "unknown symbol" errors, check first that `-I ..` is part of |
|
14 |
+ * your compiler options - a special hint to VC/IDE users who tend to make up |
|
15 |
+ * their own workspace files. All includes look like #include <zzip|*.h>, so |
|
16 |
+ * you need to add an include path to the dir containing (!!) the ./zzip/ dir |
|
12 | 17 |
*/ |
13 | 18 |
|
14 | 19 |
#ifndef _ZZIP_ZZIP_H /* zziplib.h */ |
... | ... |
@@ -17,6 +22,8 @@ |
17 | 17 |
#include <zzip-conf.h> |
18 | 18 |
|
19 | 19 |
#include <fcntl.h> |
20 |
+#include <stddef.h> /* size_t and friends */ |
|
21 |
+/* msvc6 has neither ssize_t (we assume "int") nor off_t (assume "long") */ |
|
20 | 22 |
|
21 | 23 |
#ifdef __cplusplus |
22 | 24 |
extern "C" { |
... | ... |
@@ -72,6 +79,8 @@ typedef enum |
72 | 72 |
typedef char _zzip_const * _zzip_const zzip_strings_t; |
73 | 73 |
typedef char _zzip_const zzip_char_t; |
74 | 74 |
typedef _zzip_off_t zzip_off_t; |
75 |
+typedef _zzip_size_t zzip_size_t; |
|
76 |
+typedef _zzip_ssize_t zzip_ssize_t; |
|
75 | 77 |
typedef struct zzip_dir ZZIP_DIR; |
76 | 78 |
typedef struct zzip_file ZZIP_FILE; |
77 | 79 |
typedef struct zzip_dirent ZZIP_DIRENT; |
... | ... |
@@ -87,7 +96,7 @@ struct zzip_dirent |
87 | 87 |
|
88 | 88 |
/* |
89 | 89 |
* Getting error strings |
90 |
- * zzip-err.c |
|
90 |
+ * zzip/err.c |
|
91 | 91 |
*/ |
92 | 92 |
_zzip_export /* error in _opendir : */ |
93 | 93 |
zzip_char_t* zzip_strerror(int errcode); |
... | ... |
@@ -100,7 +109,7 @@ int zzip_errno(int errcode); |
100 | 100 |
/* |
101 | 101 |
* Functions to grab information from ZZIP_DIR/ZZIP_FILE structure |
102 | 102 |
* (if ever needed) |
103 |
- * zzip-info.c |
|
103 |
+ * zzip/info.c |
|
104 | 104 |
*/ |
105 | 105 |
_zzip_export |
106 | 106 |
int zzip_error(ZZIP_DIR * dir); |
... | ... |
@@ -124,7 +133,7 @@ int zzip_realfd(ZZIP_FILE * fp); |
124 | 124 |
|
125 | 125 |
/* |
126 | 126 |
* zip handle management |
127 |
- * zzip-zip.c |
|
127 |
+ * zzip/zip.c |
|
128 | 128 |
*/ |
129 | 129 |
_zzip_export |
130 | 130 |
ZZIP_DIR * zzip_dir_alloc(zzip_strings_t* fileext); |
... | ... |
@@ -147,8 +156,8 @@ int zzip_dir_read(ZZIP_DIR * dir, ZZIP_DIRENT * dirent); |
147 | 147 |
|
148 | 148 |
/* |
149 | 149 |
* Scanning files in zip archive |
150 |
- * zzip-dir.c |
|
151 |
- * zzip-zip.c |
|
150 |
+ * zzip/dir.c |
|
151 |
+ * zzip/zip.c |
|
152 | 152 |
*/ |
153 | 153 |
_zzip_export |
154 | 154 |
ZZIP_DIR * zzip_opendir(zzip_char_t* filename); |
... | ... |
@@ -165,30 +174,33 @@ void zzip_seekdir(ZZIP_DIR * dir, zzip_off_t offset); |
165 | 165 |
|
166 | 166 |
/* |
167 | 167 |
* 'opening', 'closing' and reading invidual files in zip archive. |
168 |
- * zzip-file.c |
|
168 |
+ * zzip/file.c |
|
169 | 169 |
*/ |
170 |
- |
|
171 | 170 |
_zzip_export |
172 | 171 |
ZZIP_FILE * zzip_file_open(ZZIP_DIR * dir, zzip_char_t* name, int modes); |
173 | 172 |
_zzip_export |
174 | 173 |
int zzip_file_close(ZZIP_FILE * fp); |
175 | 174 |
_zzip_export |
176 |
-int zzip_file_read(ZZIP_FILE * fp, char* buf, int len); |
|
175 |
+zzip_ssize_t zzip_file_read(ZZIP_FILE * fp, char* buf, zzip_size_t len); |
|
177 | 176 |
|
178 | 177 |
_zzip_export |
179 | 178 |
ZZIP_FILE * zzip_open(zzip_char_t* name, int flags); |
180 | 179 |
_zzip_export |
181 | 180 |
int zzip_close(ZZIP_FILE * fp); |
182 | 181 |
_zzip_export |
183 |
-int zzip_read(ZZIP_FILE * fp, char * buf, int len); |
|
184 |
- |
|
182 |
+zzip_ssize_t zzip_read(ZZIP_FILE * fp, char * buf, zzip_size_t len); |
|
185 | 183 |
|
184 |
+/* |
|
185 |
+ * the stdc variant to open/read/close files. - Take note of the freopen() |
|
186 |
+ * call as it may reuse an existing preparsed copy of a zip central directory |
|
187 |
+ */ |
|
186 | 188 |
_zzip_export |
187 | 189 |
ZZIP_FILE* zzip_freopen(zzip_char_t* name, zzip_char_t* mode, ZZIP_FILE*); |
188 | 190 |
_zzip_export |
189 | 191 |
ZZIP_FILE* zzip_fopen(zzip_char_t* name, zzip_char_t* mode); |
190 | 192 |
_zzip_export |
191 |
-int zzip_fread(void *ptr, int size, int nmemb, ZZIP_FILE *file); |
|
193 |
+zzip_size_t zzip_fread(void *ptr, zzip_size_t size, zzip_size_t nmemb, |
|
194 |
+ ZZIP_FILE * file); |
|
192 | 195 |
_zzip_export |
193 | 196 |
int zzip_fclose(ZZIP_FILE * fp); |
194 | 197 |
|
... | ... |
@@ -198,21 +210,18 @@ int zzip_fclose(ZZIP_FILE * fp); |
198 | 198 |
_zzip_export |
199 | 199 |
int zzip_rewind(ZZIP_FILE *fp); |
200 | 200 |
_zzip_export |
201 |
-int zzip_seek(ZZIP_FILE * fp, int offset, int |
|
202 |
- whence); |
|
201 |
+zzip_off_t zzip_seek(ZZIP_FILE * fp, zzip_off_t offset, int whence); |
|
203 | 202 |
_zzip_export |
204 |
-int zzip_tell(ZZIP_FILE * fp); |
|
205 |
- |
|
203 |
+zzip_off_t zzip_tell(ZZIP_FILE * fp); |
|
206 | 204 |
|
207 | 205 |
/* |
208 | 206 |
* reading info of a single file |
209 |
- * zzip-stat.c |
|
207 |
+ * zzip/stat.c |
|
210 | 208 |
*/ |
211 | 209 |
_zzip_export |
212 | 210 |
int zzip_dir_stat(ZZIP_DIR * dir, zzip_char_t* name, |
213 | 211 |
ZZIP_STAT * zs, int flags); |
214 | 212 |
|
215 |
- |
|
216 | 213 |
#ifdef ZZIP_LARGEFILE_RENAME |
217 | 214 |
#define zzip_open_shared_io zzip_open_shared_io64 |
218 | 215 |
#define zzip_open_ext_io zzip_open_ext_io64 |
... | ... |
@@ -246,13 +255,73 @@ ZZIP_FILE * zzip_file_open_ext_io(ZZIP_DIR * dir, |
246 | 246 |
zzip_strings_t* ext, zzip_plugin_io_t io); |
247 | 247 |
|
248 | 248 |
_zzip_export |
249 |
-ZZIP_DIR * zzip_dir_open_ext_io(zzip_char_t* filename, |
|
249 |
+ZZIP_DIR * zzip_dir_open_ext_io(zzip_char_t* filename, |
|
250 | 250 |
zzip_error_t* errcode_p, |
251 | 251 |
zzip_strings_t* ext, zzip_plugin_io_t io); |
252 | 252 |
|
253 |
+#if defined _ZZIP_WRITE_SOURCE |
|
254 |
+/* ........................................................................ |
|
255 |
+ * write support is not yet implemented |
|
256 |
+ * zzip/write.c |
|
257 |
+ */ |
|
258 |
+#define ZZIP_NO_CREAT 1 |
|
259 |
+ |
|
260 |
+ZZIP_DIR* zzip_dir_creat_ext_io(zzip_char_t* name, int o_mode, |
|
261 |
+ zzip_strings_t* ext, zzip_plugin_io_t io); |
|
262 |
+ZZIP_DIR* zzip_dir_creat(zzip_char_t* name, int o_mode); |
|
263 |
+int zzip_file_mkdir(ZZIP_DIR* dir, zzip_char_t* name, int o_mode); |
|
264 |
+ZZIP_FILE* zzip_file_creat(ZZIP_DIR* dir, zzip_char_t* name, int o_mode); |
|
265 |
+zzip_ssize_t zzip_file_write(ZZIP_FILE* file, |
|
266 |
+ const void* ptr, zzip_size_t len); |
|
267 |
+ |
|
268 |
+ZZIP_DIR* zzip_createdir(zzip_char_t* name, int o_mode); |
|
269 |
+zzip_ssize_t zzip_write(ZZIP_FILE* file, const void* ptr, zzip_size_t len); |
|
270 |
+zzip_size_t zzip_fwrite(const void* ptr, zzip_size_t len, |
|
271 |
+ zzip_size_t multiply, ZZIP_FILE* file); |
|
272 |
+#ifndef zzip_savefile |
|
273 |
+#define zzip_savefile 0 |
|
274 |
+#define zzip_savefile_is_null |
|
275 |
+#endif |
|
276 |
+ |
|
277 |
+#ifdef _ZZIP_NO_INLINE |
|
278 |
+#define zzip_mkdir(_name_,_mode_) \ |
|
279 |
+ zzip_file_mkdir((zzip_savefile),(_name_),(_mode_)) |
|
280 |
+#define zzip_creat(_name_,_mode_) \ |
|
281 |
+ zzip_file_creat((zzip_savefile),(_name_),(_mode_)) |
|
282 |
+#define zzip_sync() \ |
|
283 |
+ { zzip_closedir((zzip_savefile)); (zzip_savefile) = 0; } |
|
284 |
+#define zzip_start(_name_,_mode_,_ext_) \ |
|
285 |
+ { if ((zzip_savefile)) zzip_closedir((zzip_savefile)); |
|
286 |
+ zzip_savefile = zzip_dir_creat(_name_, _mode_,_ext_); } |
|
287 |
+ |
|
288 |
+#else |
|
289 |
+ |
|
290 |
+_zzip_inline static int zzip_mkdir(zzip_char_t* name, int o_mode) |
|
291 |
+{ return zzip_file_mkdir(zzip_savefile, name, o_mode); } |
|
292 |
+_zzip_inline static ZZIP_FILE* zzip_creat(zzip_char_t* name, int o_mode) |
|
293 |
+{ return zzip_file_creat(zzip_savefile, name, o_mode); } |
|
294 |
+ |
|
295 |
+#ifndef zzip_savefile_is_null |
|
296 |
+_zzip_inline static void zzip_sync(void) |
|
297 |
+{ zzip_closedir(zzip_savefile); zzip_savefile = 0; } |
|
298 |
+_zzip_inline static void zzip_mkfifo(zzip_char_t* name, int o_mode) |
|
299 |
+{ if ((zzip_savefile)) zzip_closedir (zzip_savefile); |
|
300 |
+ zzip_savefile = zzip_createdir(_name_,_mode_); } |
|
301 |
+#else |
|
302 |
+_zzip_inline static void zzip_sync(void) {} |
|
303 |
+_zzip_inline static void zzip_mkfifo(zzip_char_t* name, int o_mode) {} |
|
304 |
+#endif |
|
305 |
+#endif /* _ZZIP_NO_INLINE */ |
|
306 |
+#endif /* _ZZIP_WRITE_SOURCE */ |
|
307 |
+ |
|
253 | 308 |
#ifdef __cplusplus |
254 | 309 |
}; |
255 | 310 |
#endif |
256 | 311 |
|
257 | 312 |
#endif /* _ZZIPLIB_H */ |
258 | 313 |
|
314 |
+/* |
|
315 |
+ * Local variables: |
|
316 |
+ * c-file-style: "stroustrup" |
|
317 |
+ * End: |
|
318 |
+ */ |
... | ... |
@@ -34,7 +34,7 @@ int main(int argc, char **argv) |
34 | 34 |
int ret, opt_index, i, len; |
35 | 35 |
struct optstruct *opt; |
36 | 36 |
|
37 |
- const char *getopt_parameters = "hvVc:s:f:"; |
|
37 |
+ const char *getopt_parameters = "hvVc:s:f:b:i:"; |
|
38 | 38 |
|
39 | 39 |
static struct option long_options[] = { |
40 | 40 |
{"help", 0, 0, 'h'}, |
... | ... |
@@ -47,6 +47,8 @@ int main(int argc, char **argv) |
47 | 47 |
{"command", 1, 0, 'c'}, |
48 | 48 |
{"string", 1, 0, 's'}, |
49 | 49 |
{"file", 1, 0, 'f'}, |
50 |
+ {"build", 1, 0, 'b'}, |
|
51 |
+ {"info", 1, 0, 'i'}, |
|
50 | 52 |
{0, 0, 0, 0} |
51 | 53 |
}; |
52 | 54 |
|
... | ... |
@@ -24,6 +24,9 @@ |
24 | 24 |
#include <stdlib.h> |
25 | 25 |
#include <string.h> |
26 | 26 |
#include <unistd.h> |
27 |
+#include <zlib.h> |
|
28 |
+#include <time.h> |
|
29 |
+#include <locale.h> |
|
27 | 30 |
#include <clamav.h> |
28 | 31 |
|
29 | 32 |
#include "options.h" |
... | ... |
@@ -73,7 +76,7 @@ char *cut(const char *file, long int start, long int end) |
73 | 73 |
exit(13); |
74 | 74 |
} |
75 | 75 |
|
76 |
- fname = gentemp("."); |
|
76 |
+ fname = cl_gentemp("."); |
|
77 | 77 |
if((wd = fopen(fname, "wb")) == NULL) { |
78 | 78 |
mprintf("!Can't create temporary file %s\n", fname); |
79 | 79 |
exit(14); |
... | ... |
@@ -102,7 +105,7 @@ char *cut(const char *file, long int start, long int end) |
102 | 102 |
|
103 | 103 |
char *change(const char *file, long int x) |
104 | 104 |
{ |
105 |
- char *fname, buffer[BUFFSIZE]; |
|
105 |
+ char *fname, buffer[FBUFFSIZE]; |
|
106 | 106 |
int bytes, size, sum, ch; |
107 | 107 |
FILE *rd, *wd; |
108 | 108 |
|
... | ... |
@@ -112,13 +115,13 @@ char *change(const char *file, long int x) |
112 | 112 |
exit(13); |
113 | 113 |
} |
114 | 114 |
|
115 |
- fname = gentemp("."); |
|
115 |
+ fname = cl_gentemp("."); |
|
116 | 116 |
if((wd = fopen(fname, "wb+")) == NULL) { |
117 | 117 |
mprintf("!Can't create temporary file %s\n", fname); |
118 | 118 |
exit(14); |
119 | 119 |
} |
120 | 120 |
|
121 |
- while((bytes = fread(buffer, 1, BUFFSIZE, rd)) > 0) |
|
121 |
+ while((bytes = fread(buffer, 1, FBUFFSIZE, rd)) > 0) |
|
122 | 122 |
fwrite(buffer, 1, bytes, wd); |
123 | 123 |
|
124 | 124 |
fclose(rd); |
... | ... |
@@ -134,7 +137,7 @@ char *change(const char *file, long int x) |
134 | 134 |
|
135 | 135 |
void sigtool(struct optstruct *opt) |
136 | 136 |
{ |
137 |
- char buffer[BUFFSIZE]; |
|
137 |
+ char buffer[FBUFFSIZE]; |
|
138 | 138 |
int bytes; |
139 | 139 |
char *pt; |
140 | 140 |
|
... | ... |
@@ -158,12 +161,20 @@ void sigtool(struct optstruct *opt) |
158 | 158 |
|
159 | 159 |
if(optl(opt, "hex-dump")) { |
160 | 160 |
|
161 |
- while((bytes = read(0, buffer, BUFFSIZE)) > 0) { |
|
161 |
+ while((bytes = read(0, buffer, FBUFFSIZE)) > 0) { |
|
162 | 162 |
pt = cl_str2hex(buffer, bytes); |
163 | 163 |
write(1, pt, 2 * bytes); |
164 | 164 |
free(pt); |
165 | 165 |
} |
166 | 166 |
|
167 |
+ } else if(optc(opt, 'b')) { |
|
168 |
+ |
|
169 |
+ build(opt); |
|
170 |
+ |
|
171 |
+ } else if(optc(opt, 'i')) { |
|
172 |
+ |
|
173 |
+ cvdinfo(opt); |
|
174 |
+ |
|
167 | 175 |
} else { |
168 | 176 |
int jmp, lastjmp, start, end, found = 0, exec = 0, pos, filesize; |
169 | 177 |
char *c, *s, *f, *tmp, *signame, *bsigname, *f2; |
... | ... |
@@ -330,7 +341,7 @@ void sigtool(struct optstruct *opt) |
330 | 330 |
if(fileinfo(signame, 1) != -1) { |
331 | 331 |
mprintf("File %s exists.\n", signame); |
332 | 332 |
free(signame); |
333 |
- signame = gentemp("."); |
|
333 |
+ signame = cl_gentemp("."); |
|
334 | 334 |
} |
335 | 335 |
|
336 | 336 |
bsigname = (char *) mcalloc(strlen(f) + 10, sizeof(char)); |
... | ... |
@@ -338,7 +349,7 @@ void sigtool(struct optstruct *opt) |
338 | 338 |
if(fileinfo(bsigname, 1) != -1) { |
339 | 339 |
mprintf("File %s exists.\n", bsigname); |
340 | 340 |
free(bsigname); |
341 |
- bsigname = gentemp("."); |
|
341 |
+ bsigname = cl_gentemp("."); |
|
342 | 342 |
} |
343 | 343 |
|
344 | 344 |
if((wd = fopen(signame, "wb")) == NULL) { |
... | ... |
@@ -350,7 +361,7 @@ void sigtool(struct optstruct *opt) |
350 | 350 |
|
351 | 351 |
mprintf("Saving signature in %s file.\n", signame); |
352 | 352 |
|
353 |
- while((bytes = fread(buffer, 1, BUFFSIZE, fd)) > 0) { |
|
353 |
+ while((bytes = fread(buffer, 1, FBUFFSIZE, fd)) > 0) { |
|
354 | 354 |
pt = cl_str2hex(buffer, bytes); |
355 | 355 |
fwrite(pt, 1, 2 * bytes, wd); |
356 | 356 |
free(pt); |
... | ... |
@@ -369,6 +380,204 @@ void sigtool(struct optstruct *opt) |
369 | 369 |
//free_opt(opt); |
370 | 370 |
} |
371 | 371 |
|
372 |
+int build(struct optstruct *opt) |
|
373 |
+{ |
|
374 |
+ int ret, no = 0, bytes, itmp; |
|
375 |
+ struct stat foo; |
|
376 |
+ char buffer[BUFFSIZE], *tarfile = NULL, *gzfile = NULL, header[257], |
|
377 |
+ smbuff[25], *pt; |
|
378 |
+ struct cl_node *root = NULL; |
|
379 |
+ FILE *tar, *cvd; |
|
380 |
+ gzFile *gz; |
|
381 |
+ time_t timet; |
|
382 |
+ struct tm *brokent; |
|
383 |
+ |
|
384 |
+ /* build a tar.gz archive |
|
385 |
+ * we need: COPYING, viruses.db / viruses.db2 |
|
386 |
+ * in current working directory |
|
387 |
+ */ |
|
388 |
+ |
|
389 |
+ if(stat("COPYING", &foo) == -1) { |
|
390 |
+ mprintf("COPYING file not found in current working directory.\n"); |
|
391 |
+ exit(1); |
|
392 |
+ } |
|
393 |
+ |
|
394 |
+ if(stat("viruses.db", &foo) == -1 || stat("viruses.db2", &foo) == -1) { |
|
395 |
+ mprintf("Virus database not found in current working directory.\n"); |
|
396 |
+ exit(1); |
|
397 |
+ } |
|
398 |
+ |
|
399 |
+ cl_debug(); /* enable debug messages */ |
|
400 |
+ |
|
401 |
+ if((ret = cl_loaddbdir(cl_retdbdir(), &root, &no))) { |
|
402 |
+ mprintf("!Can't load database: %s\n", cl_strerror(ret)); |
|
403 |
+ exit(1); |
|
404 |
+ } |
|
405 |
+ |
|
406 |
+ cl_freetrie(root); |
|
407 |
+ |
|
408 |
+ mprintf("Database properly parsed.\n"); |
|
409 |
+ |
|
410 |
+ if(!no) |
|
411 |
+ mprintf("WARNING: There are no signatures in the database(s).\n"); |
|
412 |
+ else |
|
413 |
+ mprintf("Signatures: %d\n", no); |
|
414 |
+ |
|
415 |
+ tarfile = cl_gentemp("."); |
|
416 |
+ |
|
417 |
+ switch(fork()) { |
|
418 |
+ case -1: |
|
419 |
+ mprintf("!Can't fork.\n"); |
|
420 |
+ exit(1); |
|
421 |
+ case 0: |
|
422 |
+ { |
|
423 |
+ char *args[] = { "tar", "-cvf", tarfile, "COPYING", "viruses.db", "viruses.db2", NULL }; |
|
424 |
+ execv("/bin/tar", args); |
|
425 |
+ mprintf("!Can't execute tar\n"); |
|
426 |
+ perror("tar"); |
|
427 |
+ exit(1); |
|
428 |
+ } |
|
429 |
+ default: |
|
430 |
+ wait(NULL); |
|
431 |
+ } |
|
432 |
+ |
|
433 |
+ if(stat(tarfile, &foo) == -1) { |
|
434 |
+ mprintf("!Can't generate tar file.\n"); |
|
435 |
+ exit(1); |
|
436 |
+ } |
|
437 |
+ |
|
438 |
+ if((tar = fopen(tarfile, "rb")) == NULL) { |
|
439 |
+ mprintf("!Can't open file %s\n", tarfile); |
|
440 |
+ exit(1); |
|
441 |
+ } |
|
442 |
+ |
|
443 |
+ gzfile = cl_gentemp("."); |
|
444 |
+ if((gz = gzopen(gzfile, "wb")) == NULL) { |
|
445 |
+ mprintf("!Can't open file %s to write.\n", gzfile); |
|
446 |
+ exit(1); |
|
447 |
+ } |
|
448 |
+ |
|
449 |
+ while((bytes = fread(buffer, 1, BUFFSIZE, tar)) > 0) |
|
450 |
+ gzwrite(gz, buffer, bytes); |
|
451 |
+ |
|
452 |
+ fclose(tar); |
|
453 |
+ unlink(tarfile); |
|
454 |
+ free(tarfile); |
|
455 |
+ |
|
456 |
+ gzclose(gz); |
|
457 |
+ |
|
458 |
+ /* generate header */ |
|
459 |
+ |
|
460 |
+ /* magic string */ |
|
461 |
+ |
|
462 |
+ strcpy(header, "ClamAV-VDB:"); |
|
463 |
+ |
|
464 |
+ /* time */ |
|
465 |
+ |
|
466 |
+ time(&timet); |
|
467 |
+ brokent = localtime(&timet); |
|
468 |
+ setlocale(LC_TIME, "C"); |
|
469 |
+ strftime(smbuff, 24, "%b-%d %H-%M %Z:", brokent); |
|
470 |
+ strcat(header, smbuff); |
|
471 |
+ |
|
472 |
+ /* version number */ |
|
473 |
+ |
|
474 |
+ // tutaj ma przeczytac naglowek z obecnej bazy o tej samej nazwie |
|
475 |
+ // i uzyc o jeden wiekszy |
|
476 |
+ |
|
477 |
+ mprintf("!Can't read database version number from current local database\n"); |
|
478 |
+ fflush(stdin); |
|
479 |
+ mprintf("Please enter a version number for the new database: "); |
|
480 |
+ scanf("%d", &itmp); |
|
481 |
+ sprintf(smbuff, "%d:", itmp); |
|
482 |
+ strcat(header, smbuff); |
|
483 |
+ |
|
484 |
+ /* number of signatures */ |
|
485 |
+ sprintf(smbuff, "%d:", no); |
|
486 |
+ strcat(header, smbuff); |
|
487 |
+ |
|
488 |
+ /* functionality level */ |
|
489 |
+ // pobierac z cl_funclevel() |
|
490 |
+ sprintf(smbuff, "%d:", 1); |
|
491 |
+ strcat(header, smbuff); |
|
492 |
+ |
|
493 |
+ /* MD5 */ |
|
494 |
+ pt = cl_md5file(gzfile); |
|
495 |
+ strcat(header, pt); |
|
496 |
+ strcat(header, ":"); |
|
497 |
+ |
|
498 |
+ /* digital signature */ |
|
499 |
+ strcat(header, ":"); |
|
500 |
+ |
|
501 |
+ /* builder */ |
|
502 |
+ fflush(stdin); |
|
503 |
+ mprintf("Builder name: "); |
|
504 |
+ //fgets(smbuff, 24, stdin); |
|
505 |
+ fscanf(stdin, "%s:", &smbuff); |
|
506 |
+ strcat(header, smbuff); |
|
507 |
+ //strcat(header, ":"); |
|
508 |
+ |
|
509 |
+ /* fill up with spaces */ |
|
510 |
+ if(strlen(header) > 256) { |
|
511 |
+ mprintf("!Generated signature is too long.\n"); |
|
512 |
+ exit(1); |
|
513 |
+ } |
|
514 |
+ |
|
515 |
+ while(strlen(header) < 256) |
|
516 |
+ strcat(header, " "); |
|
517 |
+ |
|
518 |
+ /* build the final database */ |
|
519 |
+ |
|
520 |
+ pt = getargc(opt, 'b'); |
|
521 |
+ if((cvd = fopen(pt, "wb")) == NULL) { |
|
522 |
+ mprintf("!Can't write the final database %s\n", pt); |
|
523 |
+ exit(1); |
|
524 |
+ } |
|
525 |
+ |
|
526 |
+ fwrite(header, 1, 256, cvd); |
|
527 |
+ |
|
528 |
+ if((tar = fopen(gzfile, "rb")) == NULL) { |
|
529 |
+ mprintf("!Can't open file %s for reading.\n", gzfile); |
|
530 |
+ exit(1); |
|
531 |
+ } |
|
532 |
+ |
|
533 |
+ while((bytes = fread(buffer, 1, BUFFSIZE, tar)) > 0) |
|
534 |
+ fwrite(buffer, 1, bytes, cvd); |
|
535 |
+ |
|
536 |
+ fclose(tar); |
|
537 |
+ fclose(cvd); |
|
538 |
+ |
|
539 |
+ unlink(gzfile); |
|
540 |
+ free(gzfile); |
|
541 |
+ |
|
542 |
+ mprintf("Database %s created.\n", pt); |
|
543 |
+ |
|
544 |
+ // teraz zaladuj baze |
|
545 |
+} |
|
546 |
+ |
|
547 |
+void cvdinfo(struct optstruct *opt) |
|
548 |
+{ |
|
549 |
+ struct cl_cvd *cvd; |
|
550 |
+ char *pt; |
|
551 |
+ |
|
552 |
+ if((cvd = cl_cvdhead(getargc(opt, 'i'))) == NULL) { |
|
553 |
+ mprintf("!Can't read CVD header from %s\n", getargc(opt, 'i')); |
|
554 |
+ exit(1); |
|
555 |
+ } |
|
556 |
+ |
|
557 |
+ mprintf("Creation time: %s\n", cvd->time); |
|
558 |
+ mprintf("Version: %d\n", cvd->version); |
|
559 |
+ mprintf("# of signatures: %d\n", cvd->sigs); |
|
560 |
+ mprintf("Functionality level: %d\n", cvd->fl); |
|
561 |
+ mprintf("Builder: %s\n", cvd->builder); |
|
562 |
+ mprintf("MD5: %s\n", cvd->md5); |
|
563 |
+ |
|
564 |
+ // pt = cl_md5file( DODAC WERYFIKACJE |
|
565 |
+ mprintf("Digital signature: %s\n", cvd->dsig); |
|
566 |
+ |
|
567 |
+ // wyczysc cvd |
|
568 |
+} |
|
569 |
+ |
|
372 | 570 |
void help(void) |
373 | 571 |
{ |
374 | 572 |
mprintf("\n"); |
... | ... |
@@ -384,7 +593,9 @@ void help(void) |
384 | 384 |
mprintf(" string and send it to stdout\n"); |
385 | 385 |
mprintf(" --command -c scanner command string, with options\n"); |
386 | 386 |
mprintf(" --string -s 'virus found' string in scan. output\n"); |
387 |
- mprintf(" --file -f infected file\n\n"); |
|
388 |
- |
|
387 |
+ mprintf(" --file -f infected file\n"); |
|
388 |
+ mprintf("\n DATABASE DEVELOPING:\n\n"); |
|
389 |
+ mprintf(" --build NAME -b NAME Build database\n"); |
|
390 |
+ |
|
389 | 391 |
exit(0); |
390 | 392 |
} |