216 lines
5.5 KiB
C
216 lines
5.5 KiB
C
/**
|
|
* MojoSetup; a portable, flexible installation application.
|
|
*
|
|
* Please see the file LICENSE.txt in the source's root directory.
|
|
*
|
|
* This file written by Ryan C. Gordon.
|
|
*
|
|
Copyright (c) 2006-2010 Ryan C. Gordon and others.
|
|
|
|
This software is provided 'as-is', without any express or implied warranty.
|
|
In no event will the authors be held liable for any damages arising from
|
|
the use of this software.
|
|
|
|
Permission is granted to anyone to use this software for any purpose,
|
|
including commercial applications, and to alter it and redistribute it
|
|
freely, subject to the following restrictions:
|
|
|
|
1. The origin of this software must not be misrepresented; you must not
|
|
claim that you wrote the original software. If you use this software in a
|
|
product, an acknowledgment in the product documentation would be
|
|
appreciated but is not required.
|
|
|
|
2. Altered source versions must be plainly marked as such, and must not be
|
|
misrepresented as being the original software.
|
|
|
|
3. This notice may not be removed or altered from any source distribution.
|
|
|
|
Ryan C. Gordon <icculus@icculus.org>
|
|
*
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <assert.h>
|
|
#include <errno.h>
|
|
#include <sys/types.h>
|
|
|
|
#ifdef _MSC_VER
|
|
#define off_t __int64
|
|
#define ftello _ftelli64
|
|
typedef unsigned __int64 uint64;
|
|
#else
|
|
#include <stdint.h>
|
|
typedef uint64_t uint64;
|
|
#endif
|
|
|
|
static int usage(const char *argv0)
|
|
{
|
|
fprintf(stderr, "\nUSAGE: %s <exe> <archive_to_append>\n\n", argv0);
|
|
return 1;
|
|
} // usage
|
|
|
|
static int is_self_extractable(const char *fname)
|
|
{
|
|
unsigned char magic[4];
|
|
|
|
FILE *io = fopen(fname, "rb");
|
|
if (io == NULL)
|
|
{
|
|
perror("fopen");
|
|
fprintf(stderr, "Failed to open '%s' for reading.\n", fname);
|
|
return -1;
|
|
} // if
|
|
|
|
if (fread(magic, 4, 1, io) != 1)
|
|
{
|
|
perror("fread");
|
|
fclose(io);
|
|
fprintf(stderr, "Failed to read '%s'.\n", fname);
|
|
return -1;
|
|
} // if
|
|
|
|
fclose(io);
|
|
|
|
if ( (magic[0] == 0x50) && (magic[1] == 0x4B) &&
|
|
(magic[2] == 0x03) && (magic[3] == 0x04) )
|
|
return 1; // it's a .zip file, they handle self-extracting themselves.
|
|
|
|
return 0;
|
|
} // is_self_extractable
|
|
|
|
static off_t get_file_size(const char *fname)
|
|
{
|
|
off_t retval = -1;
|
|
|
|
#define FAIL(x) do { \
|
|
perror(x); \
|
|
fprintf(stderr, "couldn't determine size of %s\n", fname); \
|
|
if (io) \
|
|
fclose(io); \
|
|
return -1; \
|
|
} while (0)
|
|
|
|
FILE *io = fopen(fname, "rb");
|
|
if (io == NULL)
|
|
FAIL("fopen");
|
|
else if (fseek(io, 0, SEEK_END) != 0)
|
|
FAIL("fseek");
|
|
else if ((retval = ftello(io)) == -1)
|
|
FAIL("ftello");
|
|
else if (fclose(io) == EOF)
|
|
FAIL("fclose");
|
|
#undef FAIL
|
|
|
|
return retval;
|
|
} // get_file_size
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
static unsigned char buf[1024 * 1024];
|
|
FILE *in = NULL;
|
|
FILE *out = NULL;
|
|
off_t exesize = -1;
|
|
off_t arcsize = -1;
|
|
off_t bytes = 0;
|
|
int is_self = 0;
|
|
|
|
assert(sizeof (off_t) == 8);
|
|
|
|
if (argc != 3)
|
|
return usage(argv[0]);
|
|
|
|
if ((exesize = get_file_size(argv[1])) < 0)
|
|
return 1;
|
|
else if ((arcsize = get_file_size(argv[2])) < 0)
|
|
return 1;
|
|
else if ((is_self = is_self_extractable(argv[2])) < 0)
|
|
return 1;
|
|
|
|
if ((out = fopen(argv[1], "ab")) == NULL)
|
|
{
|
|
perror("fopen");
|
|
fprintf(stderr, "Failed to open '%s' for appending.\n", argv[1]);
|
|
return 1;
|
|
} // if
|
|
|
|
if ((in = fopen(argv[2], "rb")) == NULL)
|
|
{
|
|
perror("fopen");
|
|
fclose(out);
|
|
fprintf(stderr, "Failed to open '%s' for reading.\n", argv[2]);
|
|
return 1;
|
|
} // if
|
|
|
|
bytes = arcsize;
|
|
while (bytes > 0)
|
|
{
|
|
size_t rc = (size_t) (bytes > sizeof (buf) ? sizeof (buf) : bytes);
|
|
rc = fread(buf, 1, rc, in);
|
|
if (ferror(in))
|
|
{
|
|
perror("fread");
|
|
break;
|
|
} // if
|
|
|
|
assert(rc != 0);
|
|
|
|
if (fwrite(buf, rc, 1, out) != 1)
|
|
{
|
|
perror("fwrite");
|
|
break;
|
|
} // if
|
|
|
|
bytes -= (off_t) rc;
|
|
} // while
|
|
|
|
if (bytes > 0)
|
|
{
|
|
fclose(in);
|
|
fclose(out);
|
|
fprintf(stderr, "Failed to write '%s'. File may be corrupted.\n", argv[1]);
|
|
return 1;
|
|
} // if
|
|
|
|
fclose(in);
|
|
|
|
if (!is_self)
|
|
{
|
|
if (fwrite("MOJOBASE", 8, 1, out) != 1)
|
|
{
|
|
perror("fwrite");
|
|
fclose(out);
|
|
fprintf(stderr, "Failed to write '%s'. File may be corrupted.\n", argv[1]);
|
|
return 1;
|
|
} // if
|
|
|
|
buf[0] = (unsigned char) ((((uint64) arcsize) >> 0) & 0xFF);
|
|
buf[1] = (unsigned char) ((((uint64) arcsize) >> 8) & 0xFF);
|
|
buf[2] = (unsigned char) ((((uint64) arcsize) >> 16) & 0xFF);
|
|
buf[3] = (unsigned char) ((((uint64) arcsize) >> 24) & 0xFF);
|
|
buf[4] = (unsigned char) ((((uint64) arcsize) >> 32) & 0xFF);
|
|
buf[5] = (unsigned char) ((((uint64) arcsize) >> 40) & 0xFF);
|
|
buf[6] = (unsigned char) ((((uint64) arcsize) >> 48) & 0xFF);
|
|
buf[7] = (unsigned char) ((((uint64) arcsize) >> 56) & 0xFF);
|
|
|
|
if (fwrite(buf, 8, 1, out) != 1)
|
|
{
|
|
perror("fwrite");
|
|
fclose(out);
|
|
fprintf(stderr, "Failed to write '%s'. File may be corrupted.\n", argv[1]);
|
|
return 1;
|
|
} // if
|
|
} // if
|
|
|
|
if (fclose(out) == EOF)
|
|
{
|
|
perror("fclose");
|
|
fprintf(stderr, "Failed to close '%s'. File may be corrupted.\n", argv[1]);
|
|
return 1;
|
|
} // if
|
|
|
|
return 0;
|
|
} // main
|
|
|
|
// end of make_self_extracting.c ...
|
|
|