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