1
0
mirror of https://github.com/upx/upx synced 2025-09-28 19:06:07 +08:00
upx/src/work.cpp
2010-08-08 16:20:16 +02:00

347 lines
9.2 KiB
C++

/* work.cpp -- main driver
This file is part of the UPX executable compressor.
Copyright (C) 1996-2010 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 1996-2010 Laszlo Molnar
All Rights Reserved.
UPX and the UCL library are free software; you can redistribute them
and/or modify them under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of
the License, or (at your option) any later version.
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; see the file COPYING.
If not, write to the Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
Markus F.X.J. Oberhumer Laszlo Molnar
<markus@oberhumer.com> <ml1050@users.sourceforge.net>
*/
#include "conf.h"
#include "file.h"
#include "packmast.h"
#include "packer.h"
#include "ui.h"
#if defined(__DJGPP__)
# define USE_FTIME 1
#elif (ACC_OS_WIN32 && ACC_CC_MWERKS) && defined(__MSL__)
# include <utime.h>
# define USE_UTIME 1
#elif ((ACC_OS_WIN32 || ACC_OS_WIN64) && (ACC_CC_INTELC || ACC_CC_MSC))
# define USE__FUTIME 1
#elif (HAVE_UTIME)
# define USE_UTIME 1
#endif
#if !defined(SH_DENYRW)
# define SH_DENYRW (-1)
#endif
#if !defined(SH_DENYWR)
# define SH_DENYWR (-1)
#endif
// ignore errors in some cases and silence __attribute__((__warn_unused_result__))
#define IGNORE_ERROR(var) ACC_UNUSED(var)
/*************************************************************************
// process one file
**************************************************************************/
void do_one_file(const char *iname, char *oname)
{
int r;
struct stat st;
memset(&st, 0, sizeof(st));
#if (HAVE_LSTAT)
r = lstat(iname,&st);
#else
r = stat(iname,&st);
#endif
if (r != 0)
throw FileNotFoundException(iname);
if (!(S_ISREG(st.st_mode)))
throwIOException("not a regular file -- skipped");
#if defined(__unix__)
// no special bits may be set
if ((st.st_mode & (S_ISUID | S_ISGID | S_ISVTX)) != 0)
throwIOException("file has special permissions -- skipped");
#endif
if (st.st_size <= 0)
throwIOException("empty file -- skipped");
if (st.st_size >= 1024*1024*1024)
throwIOException("file is too large -- skipped");
if ((st.st_mode & S_IWUSR) == 0)
{
bool skip = true;
if (opt->output_name)
skip = false;
else if (opt->to_stdout)
skip = false;
else if (opt->backup)
skip = false;
if (skip)
throwIOException("file is write protected -- skipped");
}
InputFile fi;
fi.st = st;
fi.sopen(iname, O_RDONLY | O_BINARY, SH_DENYWR);
#if (USE_FTIME)
struct ftime fi_ftime;
memset(&fi_ftime, 0, sizeof(fi_ftime));
if (opt->preserve_timestamp)
{
if (getftime(fi.getFd(), &fi_ftime) != 0)
throwIOException("cannot determine file timestamp");
}
#endif
// open output file
OutputFile fo;
if (opt->cmd == CMD_COMPRESS || opt->cmd == CMD_DECOMPRESS)
{
if (opt->to_stdout)
{
if (!fo.openStdout(1, opt->force ? true : false))
throwIOException("data not written to a terminal; Use '-f' to force.");
}
else
{
char tname[ACC_FN_PATH_MAX+1];
if (opt->output_name)
strcpy(tname,opt->output_name);
else
{
if (!maketempname(tname, sizeof(tname), iname, ".upx"))
throwIOException("could not create a temporary file name");
}
if (opt->force >= 2)
{
#if (HAVE_CHMOD)
r = chmod(tname, 0777);
IGNORE_ERROR(r);
#endif
r = unlink(tname);
IGNORE_ERROR(r);
}
int flags = O_CREAT | O_WRONLY | O_BINARY;
if (opt->force)
flags |= O_TRUNC;
else
flags |= O_EXCL;
int shmode = SH_DENYWR;
#if defined(__MINT__)
flags |= O_TRUNC;
shmode = O_DENYRW;
#endif
// cannot rely on open() because of umask
//int omode = st.st_mode | 0600;
int omode = 0600;
if (!opt->preserve_mode)
omode = 0666;
fo.sopen(tname,flags,shmode,omode);
// open succeeded - now set oname[]
strcpy(oname,tname);
}
}
// handle command
PackMaster pm(&fi, opt);
if (opt->cmd == CMD_COMPRESS)
pm.pack(&fo);
else if (opt->cmd == CMD_DECOMPRESS)
pm.unpack(&fo);
else if (opt->cmd == CMD_TEST)
pm.test();
else if (opt->cmd == CMD_LIST)
pm.list();
else if (opt->cmd == CMD_FILEINFO)
pm.fileInfo();
else
throwInternalError("invalid command");
// copy time stamp
if (opt->preserve_timestamp && oname[0] && fo.isOpen())
{
#if (USE_FTIME)
r = setftime(fo.getFd(), &fi_ftime);
IGNORE_ERROR(r);
#elif (USE__FUTIME)
struct _utimbuf u;
u.actime = st.st_atime;
u.modtime = st.st_mtime;
r = _futime(fo.getFd(), &u);
IGNORE_ERROR(r);
#endif
}
// close files
fo.closex();
fi.closex();
// rename or delete files
if (oname[0] && !opt->output_name)
{
// FIXME: .exe or .cof etc.
if (!opt->backup)
{
#if (HAVE_CHMOD)
r = chmod(iname, 0777);
IGNORE_ERROR(r);
#endif
File::unlink(iname);
}
else
{
// make backup
char bakname[ACC_FN_PATH_MAX+1];
if (!makebakname(bakname, sizeof(bakname), iname))
throwIOException("could not create a backup file name");
File::rename(iname,bakname);
}
File::rename(oname,iname);
}
// copy file attributes
if (oname[0])
{
oname[0] = 0;
const char *name = opt->output_name ? opt->output_name : iname;
UNUSED(name);
#if (USE_UTIME)
// copy time stamp
if (opt->preserve_timestamp)
{
struct utimbuf u;
u.actime = st.st_atime;
u.modtime = st.st_mtime;
r = utime(name, &u);
IGNORE_ERROR(r);
}
#endif
#if (HAVE_CHMOD)
// copy permissions
if (opt->preserve_mode)
{
r = chmod(name, st.st_mode);
IGNORE_ERROR(r);
}
#endif
#if (HAVE_CHOWN)
// copy the ownership
if (opt->preserve_ownership)
{
r = chown(name, st.st_uid, st.st_gid);
IGNORE_ERROR(r);
}
#endif
}
UiPacker::uiConfirmUpdate();
}
/*************************************************************************
// process all files from the commandline
**************************************************************************/
static void unlink_ofile(char *oname)
{
if (oname && oname[0])
{
#if (HAVE_CHMOD)
int r;
r = chmod(oname, 0777);
IGNORE_ERROR(r);
#endif
if (unlink(oname) == 0)
oname[0] = 0;
}
}
void do_files(int i, int argc, char *argv[])
{
if (opt->verbose >= 1)
{
show_head();
UiPacker::uiHeader();
}
for ( ; i < argc; i++)
{
infoHeader();
const char *iname = argv[i];
char oname[ACC_FN_PATH_MAX+1];
oname[0] = 0;
try {
do_one_file(iname,oname);
} catch (const Exception &e) {
unlink_ofile(oname);
if (opt->verbose >= 1 || (opt->verbose >= 0 && !e.isWarning()))
printErr(iname,&e);
set_ec(e.isWarning() ? EXIT_WARN : EXIT_ERROR);
} catch (const Error &e) {
unlink_ofile(oname);
printErr(iname,&e);
e_exit(EXIT_ERROR);
} catch (std::bad_alloc *e) {
unlink_ofile(oname);
printErr(iname,"out of memory");
UNUSED(e);
//delete e;
e_exit(EXIT_ERROR);
} catch (const std::bad_alloc &) {
unlink_ofile(oname);
printErr(iname,"out of memory");
e_exit(EXIT_ERROR);
} catch (std::exception *e) {
unlink_ofile(oname);
printUnhandledException(iname,e);
//delete e;
e_exit(EXIT_ERROR);
} catch (const std::exception &e) {
unlink_ofile(oname);
printUnhandledException(iname,&e);
e_exit(EXIT_ERROR);
} catch (...) {
unlink_ofile(oname);
printUnhandledException(iname,NULL);
e_exit(EXIT_ERROR);
}
}
if (opt->cmd == CMD_COMPRESS)
UiPacker::uiPackTotal();
else if (opt->cmd == CMD_DECOMPRESS)
UiPacker::uiUnpackTotal();
else if (opt->cmd == CMD_LIST)
UiPacker::uiListTotal();
else if (opt->cmd == CMD_TEST)
UiPacker::uiTestTotal();
else if (opt->cmd == CMD_FILEINFO)
UiPacker::uiFileInfoTotal();
}
/*
vi:ts=4:et
*/