1 // This file is part of BOINC.
2 // http://boinc.berkeley.edu
3 // Copyright (C) 2012 University of California
4 //
5 // BOINC is free software; you can redistribute it and/or modify it
6 // under the terms of the GNU Lesser General Public License
7 // as published by the Free Software Foundation,
8 // either version 3 of the License, or (at your option) any later version.
9 //
10 // BOINC 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.
13 // See the GNU Lesser General Public License for more details.
14 //
15 // You should have received a copy of the GNU Lesser General Public License
16 // along with BOINC. If not, see <http://www.gnu.org/licenses/>.
17
18
19 #if defined(_WIN32) && !defined(__STDWX_H__)
20 #pragma warning( disable : 4786 ) // Disable warning messages for vector
21 #include "boinc_win.h"
22 #elif defined(_WIN32) && defined(__STDWX_H__)
23 #include "stdwx.h"
24 #else
25 #ifndef __APPLE_CC__
26 #include "config.h"
27 #endif
28 #include <algorithm>
29 #include <string>
30 #include <string.h>
31 using std::string;
32
33 #endif
34
35 #ifdef __cplusplus
36 extern "C" {
37 #else
38 extern {
39 #endif
40 int unzip(int argc, char** argv);
41 //int zipmain(int argc, char** argv);
42 #include "./unzip/unzip.h"
43 #include "./zip/boinczip.h"
44 }
45
46 #include "boinc_zip.h"
47 #include "filesys.h" // from BOINC for DirScan
48
49 // send in an output filename, advanced options (usually NULL), and numFileIn, szfileIn
50
51 #ifndef _MAX_PATH
52 #define _MAX_PATH 255
53 #endif
54
55 unsigned char g_ucSort;
56
57 // a "binary predicate" for use by the std::sort algorithm
58 // return true if "first > second" according to the g_ucSort type
59
StringVectorSort(const std::string & first,const std::string & second)60 bool StringVectorSort(const std::string& first, const std::string& second) {
61 bool bRet = false;
62 if (g_ucSort & SORT_NAME
63 && g_ucSort & SORT_ASCENDING
64 && strcmp(first.c_str(), second.c_str())<0
65 ) {
66 bRet = true;
67 } else if (g_ucSort & SORT_NAME
68 && g_ucSort & SORT_DESCENDING
69 && strcmp(first.c_str(), second.c_str())>0
70 ) {
71 bRet = true;
72 } else if (g_ucSort & SORT_TIME) {
73 struct stat st[2];
74 stat(first.c_str(), &st[0]);
75 stat(second.c_str(), &st[1]);
76 if (g_ucSort & SORT_ASCENDING) {
77 bRet = st[0].st_mtime < st[1].st_mtime;
78 } else {
79 bRet = st[0].st_mtime > st[1].st_mtime;
80 }
81 }
82 return bRet;
83 }
84
boinc_zip(int bZipType,const std::string szFileZip,const std::string szFileIn)85 int boinc_zip(
86 int bZipType, const std::string szFileZip, const std::string szFileIn
87 ) {
88 ZipFileList tempvec;
89 tempvec.push_back(szFileIn);
90 return boinc_zip(bZipType, szFileZip, &tempvec);
91 }
92
93 // same, but with char[] instead of string
94 //
boinc_zip(int bZipType,const char * szFileZip,const char * szFileIn)95 int boinc_zip(int bZipType, const char* szFileZip, const char* szFileIn) {
96 string strFileZip, strFileIn;
97 strFileZip.assign(szFileZip);
98 strFileIn.assign(szFileIn);
99 ZipFileList tempvec;
100 tempvec.push_back(strFileIn);
101 return boinc_zip(bZipType, strFileZip, &tempvec);
102 }
103
boinc_zip(int bZipType,const std::string szFileZip,const ZipFileList * pvectszFileIn)104 int boinc_zip(
105 int bZipType, const std::string szFileZip, const ZipFileList* pvectszFileIn
106 ) {
107 int carg;
108 char** av;
109 int iRet = 0, i = 0, nVecSize = 0;
110
111 if (pvectszFileIn) nVecSize = pvectszFileIn->size();
112
113 // if unzipping but no file out, so it just uses cwd, only 3 args
114 //if (bZipType == UNZIP_IT)
115 // carg = 3 + nVecSize;
116 //else
117 carg = 3 + nVecSize;
118
119 // make a dynamic array
120 av = (char**) calloc(carg+1, sizeof(char*));
121 for (i=0;i<(carg+1);i++) {
122 av[i] = (char*) calloc(_MAX_PATH,sizeof(char));
123 }
124
125 // just form an argc/argv to spoof the "main"
126 // default options are to recurse into directories
127 //if (options && strlen(options))
128 // strcpy(av[1], options);
129
130 if (bZipType == ZIP_IT) {
131 strcpy(av[0], "zip");
132 // default zip options -- no dir names, no subdirs, highest compression, quiet mode
133 if (strlen(av[1])==0) {
134 strcpy(av[1], "-j9q");
135 }
136 strcpy(av[2], szFileZip.c_str());
137
138 //sz 3 onward will be each vector
139 int jj;
140 for (jj=0; jj<nVecSize; jj++) {
141 strcpy(av[3+jj], pvectszFileIn->at(jj).c_str());
142 }
143 } else {
144 strcpy(av[0], "unzip");
145 // default unzip options -- preserve subdirs, overwrite
146 if (strlen(av[1])==0) {
147 strcpy(av[1], "-oq");
148 }
149 strcpy(av[2], szFileZip.c_str());
150
151 // if they passed in a directory unzip there
152 if (carg == 4) {
153 sprintf(av[3], "-d%s", pvectszFileIn->at(0).c_str());
154 }
155 }
156 av[carg] = NULL;
157 // printf("args: %s %s %s %s\n", av[0], av[1], av[2], av[3]);
158
159 if (bZipType == ZIP_IT) {
160 if (access(szFileZip.c_str(), 0) == 0) {
161 // old zip file exists so unlink
162 // (otherwise zip will reuse, doesn't seem to be a flag to
163 // bypass zip reusing it
164 unlink(szFileZip.c_str());
165 }
166 iRet = zipmain(carg, av);
167 } else {
168 // make sure zip file exists
169 if (access(szFileZip.c_str(), 0) == 0) {
170 iRet = UzpMain(carg, av);
171 } else {
172 iRet = 2;
173 }
174 }
175
176 for (i=0;i<carg;i++) {
177 free(av[i]);
178 }
179 free(av);
180 return iRet;
181 }
182
183
184 // -------------------------------------------------------------------
185 //
186 // Description: Supply a directory and a pattern as arguments, along
187 // with a FileList variable to hold the result list; sorted by name.
188 // Returns a vector of files in the directory which match the
189 // pattern. Returns true for success, or false if there was a problem.
190 //
191 // CMC Note: this is a 'BOINC-friendly' implementation of "old" CPDN code
192 // the "wildcard matching"/regexp is a bit crude, it matches substrings in
193 // order in a file; to match all files such as *.pc.*.x4.*.nc" pass
194 // ".pc|.x4.|.nc" for 'pattern'
195 //
196 // --------------------------------------------------------------------
197
boinc_filelist(const string directory,const string pattern,ZipFileList * pList,const unsigned char ucSort,const bool bClear)198 bool boinc_filelist(
199 const string directory,
200 const string pattern,
201 ZipFileList* pList,
202 const unsigned char ucSort,
203 const bool bClear
204 ) {
205 g_ucSort = ucSort; // set the global sort type right off the bat
206 string strFile;
207 // at most three |'s may be passed in pattern match
208 int iPos[3], iFnd, iCtr, i, lastPos;
209 string strFullPath;
210 char strPart[3][32];
211 string spattern = pattern;
212 string strDir = directory;
213 string strUserDir = directory;
214 int iLen = strUserDir.size();
215
216 if (!pList) return false;
217
218 // wildcards are blank!
219 if (pattern == "*" || pattern == "*.*") spattern.assign("");
220
221 if (bClear) {
222 pList->clear(); // removes old entries that may be in pList
223 }
224
225 // first tack on a final slash on user dir if required
226 if (strUserDir[iLen-1] != '\\' && strUserDir[iLen] != '/') {
227 // need a final slash, but what type?
228 // / is safe on all OS's for CPDN at least
229 // but if they already used \ use that
230 // well they didn't use a backslash so just use a slash
231 if (strUserDir.find("\\") == string::npos) {
232 strUserDir += "/";
233 } else {
234 strUserDir += "\\";
235 }
236 }
237
238 // transform strDir to either all \\ or all /
239 int j;
240 for (j=0; j<(int)directory.size(); j++) {
241 // take off final / or backslash
242 if (j == ((int)directory.size()-1)
243 && (strDir[j] == '/' || strDir[j]=='\\')
244 ) {
245 strDir.resize(directory.size()-1);
246 } else {
247 #ifdef _WIN32 // transform paths appropriate for OS
248 if (directory[j] == '/') strDir[j] = '\\';
249 #else
250 if (directory[j] == '\\') strDir[j] = '/';
251 #endif
252 }
253 }
254
255 DirScanner dirscan(strDir);
256 memset(strPart, 0x00, 3*32);
257 while (dirscan.scan(strFile)) {
258 iCtr = 0;
259 lastPos = 0;
260 iPos[0] = -1;
261 iPos[1] = -1;
262 iPos[2] = -1;
263 // match the filename against the regexp to see if it's a hit
264 // first get all the |'s to get the pieces to verify
265 //
266 while (iCtr<3 && (iPos[iCtr] = (int) spattern.find('|', lastPos)) > -1) {
267 if (iCtr==0) {
268 strncpy(strPart[0], spattern.c_str(), iPos[iCtr]);
269 } else {
270 strncpy(strPart[iCtr], spattern.c_str()+lastPos, iPos[iCtr]-lastPos);
271 }
272 lastPos = iPos[iCtr]+1;
273 iCtr++;
274 }
275 if (iCtr>0) {
276 // found a | so need to get the part from lastpos onward
277 strncpy(strPart[iCtr], spattern.c_str()+lastPos, spattern.length() - lastPos);
278 }
279
280 // check no | were found at all
281 if (iCtr == 0) {
282 strcpy(strPart[0], spattern.c_str());
283 iCtr++; // fake iCtr up 1 to get in the loop below
284 }
285
286 bool bFound = true;
287 for (i = 0; i <= iCtr && bFound; i++) {
288 if (i==0) {
289 iFnd = (int) strFile.find(strPart[0]);
290 bFound = (bool) (iFnd > -1);
291 } else {
292 // search forward of the old part found
293 iFnd = (int) strFile.find(strPart[i], iFnd+1);
294 bFound = bFound && (bool) (iFnd > -1);
295 }
296 }
297
298 if (bFound) {
299 // this pattern matched the file, add to vector
300 // NB: first get stat to make sure it really is a file
301 strFullPath = strUserDir + strFile;
302 // only add if the file really exists (i.e. not a directory)
303 if (is_file(strFullPath.c_str())) {
304 pList->push_back(strFullPath);
305 }
306 }
307 }
308
309 // sort by file creation time
310 // sort if list is greather than 1
311 if (pList->size()>1) {
312 sort(pList->begin(), pList->end(), StringVectorSort); // may as well sort it?
313 }
314 return true;
315 }
316
317 // Read compressed file to memory.
318 //
boinc_UnzipToMemory(char * zip,char * file,string & retstr)319 int boinc_UnzipToMemory (char *zip, char *file, string &retstr) {
320 UzpOpts opts; // options for UzpUnzipToMemory()
321 UzpCB funcs; // function pointers for UzpUnzipToMemory()
322 UzpBuffer buf;
323 int ret;
324
325 memset(&opts, 0, sizeof(opts));
326 memset(&funcs, 0, sizeof(funcs));
327
328 funcs.structlen = sizeof(UzpCB);
329 funcs.msgfn = (MsgFn *)printf;
330 funcs.inputfn = (InputFn *)scanf;
331 funcs.pausefn = (PauseFn *)(0x01);
332 funcs.passwdfn = (PasswdFn *)(NULL);
333
334 memset(&buf, 0, sizeof(buf)); // data-blocks needs to be empty
335 ret = UzpUnzipToMemory(zip, file, &opts, &funcs, &buf);
336
337 if (ret) {
338 retstr = (string) buf.strptr;
339 }
340
341 if (buf.strptr) free (buf.strptr);
342
343 return ret;
344
345 }
346
347 const char *BOINC_RCSID_bdf38b2dfb = "$Id: boinc_zip.cpp 18195 2009-05-22 21:19:44Z davea $";
348
349