/* File manipulation routines */
/* Author of Win32-specific bits: Nick Gammon */
#include "copyrite.h"
#include "config.h"
#include <stdlib.h>
#include <stdio.h>
#ifdef WIN32
#include <windows.h>
#include <process.h>
#include <direct.h>
#endif
#ifdef I_UNISTD
#include <unistd.h>
#endif
#include "conf.h"
#include "mushdb.h"
#include "match.h"
#include "externs.h"
#include "mymalloc.h"
#include "log.h"
#include "confmagic.h"
extern char confname[BUFFER_LEN]; /* From bsd.c */
#ifdef WIN32
/* This is bad, but only for WIN32, which is bad anyway... */
#define EMBEDDED_MKINDX
static char buff[1024];
BOOL
ConcatenateFiles(const char *path, const char *outputfile)
{
HANDLE filscan;
WIN32_FIND_DATA fildata;
BOOL filflag;
DWORD status;
FILE *fo = NULL;
FILE *f = NULL;
size_t bytes_in, bytes_out;
long total_bytes = 0;
int total_files = 0;
char directory[MAX_PATH];
char fullname[MAX_PATH];
char *p;
/* If outputfile is an empty string, forget it. */
if (!outputfile || !*outputfile)
return FALSE;
/* extract the directory from the path name */
strcpy(directory, path);
p = strrchr(directory, '\\');
if (p)
p[1] = 0;
else {
p = strrchr(directory, '/');
if (p)
p[1] = 0;
}
/* Open output file */
fo = fopen(outputfile, "wb");
if (!fo) {
do_rawlog(LT_ERR, T("Unable to open file: %s"), outputfile);
return FALSE;
}
do_rawlog(LT_ERR, T("Creating file: %s"), outputfile);
/* Find first file matching the wildcard */
filscan = FindFirstFile(path, &fildata);
if (filscan == INVALID_HANDLE_VALUE) {
status = GetLastError();
fclose(fo);
do_rawlog(LT_ERR, "**** No files matching: \"%s\" found.", path);
if (status == ERROR_NO_MORE_FILES)
return TRUE;
else
return FALSE;
}
/*
Now enter the concatenation loop.
*/
do {
if (!(fildata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
do_rawlog(LT_ERR, "%s: %s, %ld %s", T(" Copying file"),
fildata.cFileName, fildata.nFileSizeLow,
fildata.nFileSizeLow == 1 ? T("byte") : T("bytes"));
strcpy(fullname, directory);
strcat(fullname, fildata.cFileName);
/* Open the input file */
f = fopen(fullname, "rb");
if (!f)
do_rawlog(LT_ERR, T(" ** Unable to open file: %s"), fullname);
else {
total_files++;
/* do the copy loop */
while (!feof(f)) {
bytes_in = fread(buff, 1, sizeof(buff), f);
if (bytes_in <= 0)
break;
bytes_out = fwrite(buff, 1, bytes_in, fo);
total_bytes += bytes_out;
if (bytes_in != bytes_out) {
do_rawlog(LT_ERR, T("Unable to write to file: %s"), outputfile);
fclose(f);
break;
}
} /* end of copy loop */
fclose(f);
} /* end of being able to open file */
}
/* end of not being a directory */
/* get next file matching the wildcard */
filflag = FindNextFile(filscan, &fildata);
} while (filflag);
status = GetLastError();
FindClose(filscan);
fclose(fo);
do_rawlog(LT_ERR, T("Copied %i %s, %ld %s"), total_files,
total_files == 1 ? T("file") : T("files"), total_bytes,
total_bytes == 1 ? T("byte") : T("bytes"));
if (status == ERROR_NO_MORE_FILES)
return TRUE;
else
return FALSE;
}
int
CheckDatabase(const char *path, FILETIME * modified, long *filesize)
{
HANDLE filscan;
WIN32_FIND_DATA fildata;
SYSTEMTIME st;
static char *months[] =
{ ">!<", "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep",
"Oct", "Nov", "Dec"
};
FILE *f;
size_t bytes;
filscan = FindFirstFile(path, &fildata);
if (filscan == INVALID_HANDLE_VALUE) {
do_rawlog(LT_ERR, "File \"%s\" not found.", path);
return FALSE;
}
*modified = fildata.ftLastWriteTime;
*filesize = fildata.nFileSizeLow;
FindClose(filscan);
FileTimeToSystemTime(&fildata.ftLastWriteTime, &st);
if (st.wMonth < 1 || st.wMonth > 12)
st.wMonth = 0;
do_rawlog(LT_ERR, T
("File \"%s\" found, size %ld %s, modified on %02d %s %04d %02d:%02d:%02d"),
path, fildata.nFileSizeLow,
fildata.nFileSizeLow == 1 ? T("byte") : T("bytes"), st.wDay,
months[st.wMonth], st.wYear, st.wHour, st.wMinute, st.wSecond);
if (fildata.nFileSizeHigh == 0 && fildata.nFileSizeLow < 80) {
do_rawlog(LT_ERR, T("File is too small to be a MUSH database."));
return FALSE;
}
/* check file for validity */
f = fopen(path, "rb");
if (!f) {
do_rawlog(LT_ERR, T("Unable to open file %s"), path);
return FALSE;
}
if (fseek(f, -80, SEEK_END) != 0) {
do_rawlog(LT_ERR, T("Unable to check file %s"), path);
fclose(f);
return FALSE;
}
bytes = fread(buff, 1, 80, f);
fclose(f);
if (bytes != 80) {
do_rawlog(LT_ERR, T("Unable to read last part of file %s"), path);
return FALSE;
}
if (strstr(buff, "***END OF DUMP***") == 0) {
do_rawlog(LT_ERR, T("Database not terminated correctly, file %s"), path);
return FALSE;
}
return TRUE;
} /* end of CheckDatabase */
void
Win32MUSH_setup(void)
{
int indb_OK, outdb_OK, panicdb_OK;
FILETIME indb_time, outdb_time, panicdb_time;
long indb_size, outdb_size, panicdb_size;
#ifndef _DEBUG
char FileName[256];
if (GetModuleFileName(NULL, FileName, 256) != 0) {
if (!strcasecmp(rindex(FileName, '\\') + 1, "pennmush.exe")) {
if (CopyFile("pennmush.exe", "pennmush_run.exe", FALSE)) {
do_rawlog(LT_ERR, "Successfully copied executable, starting copy.");
#ifdef WIN32SERVICES
execl("pennmush_run.exe", "pennmush_run.exe", "/run", NULL);
#else
execl("pennmush_run.exe", "pennmush_run.exe", confname, NULL);
#endif
}
}
}
#endif /* */
ConcatenateFiles("txt\\hlp\\*.hlp", "txt\\help.txt");
ConcatenateFiles("txt\\nws\\*.nws", "txt\\news.txt");
ConcatenateFiles("txt\\evt\\*.evt", "txt\\events.txt");
ConcatenateFiles("txt\\rul\\*.rul", "txt\\rules.txt");
ConcatenateFiles("txt\\idx\\*.idx", "txt\\index.txt");
indb_OK = CheckDatabase(options.input_db, &indb_time, &indb_size);
outdb_OK = CheckDatabase(options.output_db, &outdb_time, &outdb_size);
panicdb_OK = CheckDatabase(options.crash_db, &panicdb_time, &panicdb_size);
if (indb_OK) { /* Look at outdb */
if (outdb_OK) { /* Look at panicdb */
if (panicdb_OK) { /* outdb or panicdb or indb */
if (CompareFileTime(&panicdb_time, &outdb_time) > 0) { /* panicdb or indb */
if (CompareFileTime(&panicdb_time, &indb_time) > 0) { /* panicdb */
ConcatenateFiles(options.crash_db, options.input_db);
} else { /* indb */
}
} else { /* outdb or indb */
if (CompareFileTime(&outdb_time, &indb_time) > 0) { /* outdb */
ConcatenateFiles(options.output_db, options.input_db);
} else { /* indb */
}
}
} else { /* outdb or indb */
if (CompareFileTime(&outdb_time, &indb_time) > 0) { /* outdb */
ConcatenateFiles(options.output_db, options.input_db);
} else { /* indb */
}
}
} else { /* outdb not OK */
if (panicdb_OK) { /* panicdb or indb */
if (CompareFileTime(&panicdb_time, &indb_time) > 0) { /* panicdb */
ConcatenateFiles(options.crash_db, options.input_db);
} else { /* indb */
}
} else { /* indb */
}
}
} else { /* indb not OK */
if (outdb_OK) { /* look at panicdb */
if (panicdb_OK) { /* out or panic */
if (CompareFileTime(&panicdb_time, &outdb_time) > 0) { /* panicdb */
ConcatenateFiles(options.crash_db, options.input_db);
} else { /* outdb */
ConcatenateFiles(options.output_db, options.input_db);
}
} else { /* outdb */
ConcatenateFiles(options.output_db, options.input_db);
}
} else { /* outdb not OK */
if (panicdb_OK) { /* panicdb */
ConcatenateFiles(options.crash_db, options.input_db);
} else { /* NOTHING */
return;
}
}
}
/* Final failsafe - input database SHOULD still be OK. */
do_rawlog(LT_ERR, T("Verifying selected database."));
if (!CheckDatabase(options.input_db, &indb_time, &indb_size)) {
do_rawlog(LT_ERR, T("File corrupted during selection process."));
exit(-1);
} else {
do_rawlog(LT_ERR, T("Input database verified. Proceeding to analysis."));
}
}
#endif /* WIN32 */
/** Portably renames a file
* \param origname the orignal name of the file
* \param newname the new name of the file
* \return 0 on success, negative on failure
*/
int
rename_file(const char *origname, const char *newname)
{
/* Windows can't rename over an existing file */
#ifdef WIN32
unlink(newname);
#endif
return rename(origname, newname);
}