boinc/zip/boinc_zip.cpp

346 lines
10 KiB
C++
Raw Normal View History

// This file is part of BOINC.
// http://boinc.berkeley.edu
// Copyright (C) 2019 University of California
//
// BOINC is free software; you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License
// as published by the Free Software Foundation,
// either version 3 of the License, or (at your option) any later version.
//
// BOINC is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
// See the GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with BOINC. If not, see <http://www.gnu.org/licenses/>.
#if defined(_WIN32) && !defined(__STDWX_H__)
#pragma warning( disable : 4786 ) // Disable warning messages for vector
#include "boinc_win.h"
#elif defined(_WIN32) && defined(__STDWX_H__)
#include "stdwx.h"
#else
#ifndef __APPLE_CC__
#include "config.h"
#endif
#include <algorithm>
#include <string>
#include <string.h>
using std::string;
#endif
#ifdef __cplusplus
extern "C" {
#else
extern {
#endif
int unzip(int argc, char** argv);
//int zipmain(int argc, char** argv);
#include "./unzip/unzip.h"
#include "./zip/zip.h"
}
#include "boinc_zip.h"
#include "filesys.h" // from BOINC for DirScan
// send in an output filename, advanced options (usually NULL), and numFileIn, szfileIn
#ifndef _MAX_PATH
#define _MAX_PATH 255
#endif
unsigned char g_ucSort;
// a "binary predicate" for use by the std::sort algorithm
// return true if "first > second" according to the g_ucSort type
bool StringVectorSort(const std::string& first, const std::string& second) {
bool bRet = false;
if (g_ucSort & SORT_NAME
&& g_ucSort & SORT_ASCENDING
&& strcmp(first.c_str(), second.c_str())<0
) {
bRet = true;
} else if (g_ucSort & SORT_NAME
&& g_ucSort & SORT_DESCENDING
&& strcmp(first.c_str(), second.c_str())>0
) {
bRet = true;
} else if (g_ucSort & SORT_TIME) {
struct stat st[2];
stat(first.c_str(), &st[0]);
stat(second.c_str(), &st[1]);
if (g_ucSort & SORT_ASCENDING) {
bRet = st[0].st_mtime < st[1].st_mtime;
} else {
bRet = st[0].st_mtime > st[1].st_mtime;
}
}
return bRet;
}
int boinc_zip(
int bZipType, const std::string szFileZip, const std::string szFileIn
) {
ZipFileList tempvec;
tempvec.push_back(szFileIn);
return boinc_zip(bZipType, szFileZip, &tempvec);
}
// same, but with char[] instead of string
//
int boinc_zip(int bZipType, const char* szFileZip, const char* szFileIn) {
string strFileZip, strFileIn;
strFileZip.assign(szFileZip);
strFileIn.assign(szFileIn);
ZipFileList tempvec;
tempvec.push_back(strFileIn);
return boinc_zip(bZipType, strFileZip, &tempvec);
}
int boinc_zip(
int bZipType, const std::string szFileZip, const ZipFileList* pvectszFileIn
) {
int carg;
char** av;
int iRet = 0, i = 0, nVecSize = 0;
if (pvectszFileIn) nVecSize = pvectszFileIn->size();
// if unzipping but no file out, so it just uses cwd, only 3 args
//if (bZipType == UNZIP_IT)
// carg = 3 + nVecSize;
//else
carg = 3 + nVecSize;
// make a dynamic array
av = (char**) calloc(carg+1, sizeof(char*));
for (i=0;i<(carg+1);i++) {
av[i] = (char*) calloc(_MAX_PATH,sizeof(char));
}
// just form an argc/argv to spoof the "main"
// default options are to recurse into directories
//if (options && strlen(options))
// strcpy(av[1], options);
if (bZipType == ZIP_IT) {
strcpy(av[0], "zip");
// default zip options -- no dir names, no subdirs, highest compression, quiet mode
if (strlen(av[1])==0) {
strcpy(av[1], "-j9q");
}
strcpy(av[2], szFileZip.c_str());
//sz 3 onward will be each vector
int jj;
for (jj=0; jj<nVecSize; jj++) {
strcpy(av[3+jj], pvectszFileIn->at(jj).c_str());
}
} else {
strcpy(av[0], "unzip");
// default unzip options -- preserve subdirs, overwrite
if (strlen(av[1])==0) {
strcpy(av[1], "-oq");
}
strcpy(av[2], szFileZip.c_str());
// if they passed in a directory unzip there
if (carg == 4) {
sprintf(av[3], "-d%s", pvectszFileIn->at(0).c_str());
}
}
av[carg] = NULL;
// printf("args: %s %s %s %s\n", av[0], av[1], av[2], av[3]);
if (bZipType == ZIP_IT) {
if (access(szFileZip.c_str(), 0) == 0) {
// old zip file exists so unlink
// (otherwise zip will reuse, doesn't seem to be a flag to
// bypass zip reusing it
unlink(szFileZip.c_str());
}
iRet = zipmain(carg, av);
} else {
// make sure zip file exists
if (access(szFileZip.c_str(), 0) == 0) {
iRet = UzpMain(carg, av);
} else {
iRet = 2;
}
}
for (i=0;i<carg;i++) {
free(av[i]);
}
free(av);
return iRet;
}
// -------------------------------------------------------------------
//
// Description: Supply a directory and a pattern as arguments, along
// with a FileList variable to hold the result list; sorted by name.
// Returns a vector of files in the directory which match the
// pattern. Returns true for success, or false if there was a problem.
//
// CMC Note: this is a 'BOINC-friendly' implementation of "old" CPDN code
// the "wildcard matching"/regexp is a bit crude, it matches substrings in
// order in a file; to match all files such as *.pc.*.x4.*.nc" pass
// ".pc|.x4.|.nc" for 'pattern'
//
// --------------------------------------------------------------------
bool boinc_filelist(
const string directory,
const string pattern,
ZipFileList* pList,
const unsigned char ucSort,
const bool bClear
) {
g_ucSort = ucSort; // set the global sort type right off the bat
string strFile;
// at most three |'s may be passed in pattern match
int iPos[3], iFnd, iCtr, i, lastPos;
string strFullPath;
char strPart[3][32];
string spattern = pattern;
string strDir = directory;
string strUserDir = directory;
int iLen = strUserDir.size();
if (!pList) return false;
// wildcards are blank!
if (pattern == "*" || pattern == "*.*") spattern.assign("");
if (bClear) {
pList->clear(); // removes old entries that may be in pList
}
// first tack on a final slash on user dir if required
if (strUserDir[iLen-1] != '\\' && strUserDir[iLen] != '/') {
// need a final slash, but what type?
// / is safe on all OS's for CPDN at least
// but if they already used \ use that
// well they didn't use a backslash so just use a slash
if (strUserDir.find("\\") == string::npos) {
strUserDir += "/";
} else {
strUserDir += "\\";
}
}
// transform strDir to either all \\ or all /
int j;
for (j=0; j<(int)directory.size(); j++) {
// take off final / or backslash
if (j == ((int)directory.size()-1)
&& (strDir[j] == '/' || strDir[j]=='\\')
) {
strDir.resize(directory.size()-1);
} else {
#ifdef _WIN32 // transform paths appropriate for OS
if (directory[j] == '/') strDir[j] = '\\';
#else
if (directory[j] == '\\') strDir[j] = '/';
#endif
}
}
DirScanner dirscan(strDir);
memset(strPart, 0x00, 3*32);
while (dirscan.scan(strFile)) {
iCtr = 0;
lastPos = 0;
iPos[0] = -1;
iPos[1] = -1;
iPos[2] = -1;
// match the filename against the regexp to see if it's a hit
// first get all the |'s to get the pieces to verify
//
while (iCtr<3 && (iPos[iCtr] = (int) spattern.find('|', lastPos)) > -1) {
if (iCtr==0) {
strncpy(strPart[0], spattern.c_str(), iPos[iCtr]);
} else {
strncpy(strPart[iCtr], spattern.c_str()+lastPos, iPos[iCtr]-lastPos);
}
lastPos = iPos[iCtr]+1;
iCtr++;
}
if (iCtr>0) {
// found a | so need to get the part from lastpos onward
strncpy(strPart[iCtr], spattern.c_str()+lastPos, spattern.length() - lastPos);
}
// check no | were found at all
if (iCtr == 0) {
strcpy(strPart[0], spattern.c_str());
iCtr++; // fake iCtr up 1 to get in the loop below
}
bool bFound = true;
for (i = 0; i <= iCtr && bFound; i++) {
if (i==0) {
iFnd = (int) strFile.find(strPart[0]);
bFound = (bool) (iFnd > -1);
} else {
// search forward of the old part found
iFnd = (int) strFile.find(strPart[i], iFnd+1);
bFound = bFound && (bool) (iFnd > -1);
}
}
if (bFound) {
// this pattern matched the file, add to vector
// NB: first get stat to make sure it really is a file
strFullPath = strUserDir + strFile;
// only add if the file really exists (i.e. not a directory)
if (is_file(strFullPath.c_str())) {
pList->push_back(strFullPath);
}
}
}
// sort by file creation time
// sort if list is greather than 1
if (pList->size()>1) {
sort(pList->begin(), pList->end(), StringVectorSort); // may as well sort it?
}
return true;
}
// Read compressed file to memory.
//
int boinc_UnzipToMemory (char *zip, char *file, string &retstr) {
UzpOpts opts; // options for UzpUnzipToMemory()
UzpCB funcs; // function pointers for UzpUnzipToMemory()
UzpBuffer buf;
int ret;
memset(&opts, 0, sizeof(opts));
memset(&funcs, 0, sizeof(funcs));
funcs.structlen = sizeof(UzpCB);
funcs.msgfn = (MsgFn *)printf;
funcs.inputfn = (InputFn *)scanf;
funcs.pausefn = (PauseFn *)(0x01);
funcs.passwdfn = (PasswdFn *)(NULL);
memset(&buf, 0, sizeof(buf)); // data-blocks needs to be empty
ret = UzpUnzipToMemory(zip, file, &opts, &funcs, &buf);
if (ret) {
retstr = (string) buf.strptr;
}
if (buf.strptr) free (buf.strptr);
return ret;
}