Files
clamav/contrib/Windows/Projects/clamAV/libclamav/compat.c
Nigel Horne 34d16d4a31 Added snprintf
git-svn: trunk@3711
2008-03-15 09:34:16 +00:00

508 lines
11 KiB
C

/*
* Copyright (C) 2006 Nigel Horne <njh@bandsman.co.uk>
*
* This program is free software; you can redistribute it and/or modify
* it 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; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301, USA.
*
* Unix/Linux compatibility for Windows
* Inspired by glib and the cygwin source code
* Tested under Microsoft Visual Studio 2005
*/
#include <windows.h>
#if HAVE_CONFIG_H
#include "clamav-config.h"
#endif
#include <errno.h>
#include <string.h>
#include "clamav.h"
#include "others.h"
#ifndef CL_DEBUG
#define NDEBUG /* map CLAMAV debug onto standard */
#endif
#include <stdlib.h>
#include <direct.h>
#include <io.h>
#include <pthread.h>
#ifdef USE_SYSLOG
#include <strsafe.h>
#include "syslog.h"
#endif
static const char *basename(const char *file_name);
/* Offset between 1/1/1601 and 1/1/1970 in 100 nanosec units */
#define _W32_FT_OFFSET (116444736000000000ULL)
/*
* Patches for 64 bit support in opendir by
* Mark Pizzolato clamav-win32@subscriptions.pizzolato.net
*/
DIR *
opendir(const char *dirname)
{
DIR *ret = cli_calloc(1, sizeof(DIR));
char mask[_MAX_PATH + 3];
size_t i, j;
if(ret == NULL)
return NULL;
/* struct _WIN32_FIND_DATAA is what a LPWIN32_FIND_DATA points to */
ret->find_file_data = cli_calloc(1, sizeof(struct _WIN32_FIND_DATAA));
if(ret->find_file_data == NULL) {
free(ret);
return NULL;
}
ret->dir_name = cli_strdup(dirname);
if(ret->dir_name == NULL) {
free(ret->find_file_data);
free(ret);
return NULL;
}
j = strlen(dirname);
for(i = 0; i < j; i++)
if(ret->dir_name[i] == '/')
ret->dir_name[i] = '\\';
if(j && dirname[j - 1] == '\\')
ret->dir_name[--j] = '\0';
sprintf(mask, "%s\\*", ret->dir_name);
ret->find_file_handle = FindFirstFile(mask,
(LPWIN32_FIND_DATA)ret->find_file_data);
if(ret->find_file_handle == INVALID_HANDLE_VALUE) {
free(ret->find_file_data);
free(ret->dir_name);
free(ret);
cli_warnmsg("Can't opendir(%s)\n", dirname);
return NULL;
}
ret->just_opened = TRUE;
return ret;
}
struct dirent *
readdir(DIR *dir)
{
/* NOTE: not thread safe */
static struct dirent result;
if(dir == NULL)
return NULL;
if(dir->just_opened)
dir->just_opened = FALSE;
else if(!FindNextFile((HANDLE)dir->find_file_handle, (LPWIN32_FIND_DATA)dir->find_file_data))
switch(GetLastError ()) {
case ERROR_NO_MORE_FILES:
return NULL;
default:
errno = EIO;
return NULL;
}
strcpy(result.d_name, basename(((LPWIN32_FIND_DATA)dir->find_file_data)->cFileName));
return &result;
}
int
readdir_r(DIR *dir, struct dirent *dirent, struct dirent **output)
{
if(dir == NULL)
return -1;
if(dirent == NULL)
return -1;
if(output == NULL)
return -1;
if(dir->just_opened)
dir->just_opened = FALSE;
else if(!FindNextFile((HANDLE)dir->find_file_handle, (LPWIN32_FIND_DATA)dir->find_file_data))
switch(GetLastError()) {
case ERROR_NO_MORE_FILES:
*output = NULL;
return -1;
default:
errno = EIO;
*output = NULL;
return -1;
}
strcpy(dirent->d_name, basename(((LPWIN32_FIND_DATA)dir->find_file_data)->cFileName));
*output = dirent;
return 0;
}
void
rewinddir(DIR *dir)
{
char mask[_MAX_PATH + 3];
if(dir == NULL)
return;
if(!FindClose((HANDLE)dir->find_file_handle))
cli_warnmsg("rewinddir(): FindClose() failed\n");
sprintf(mask, "%s\\*", dir->dir_name);
dir->find_file_handle = FindFirstFile (mask,
(LPWIN32_FIND_DATA)dir->find_file_data);
if(dir->find_file_handle == INVALID_HANDLE_VALUE) {
errno = EIO;
return;
}
dir->just_opened = TRUE;
}
int
closedir(DIR *dir)
{
if(dir == NULL)
return -1;
if(!FindClose((HANDLE)dir->find_file_handle)) {
errno = EIO;
return -1;
}
free(dir->dir_name);
free(dir->find_file_data);
free(dir);
return 0;
}
static const char *
basename(const char *file_name)
{
const char *base;
if(file_name == NULL)
return NULL;
base = strrchr(file_name, '\\');
if(base)
return base + 1;
if(isalpha(file_name[0] & 0xFF) && (file_name[1] == ':'))
return (const char *)(file_name + 2);
return file_name;
}
/* From the cygwin source code */
int
gettimeofday(struct timeval *tp, void *tz)
{
if(tp) {
union {
unsigned long long ns100; /*time since 1 Jan 1601 in 100ns units */
FILETIME ft;
} _now;
GetSystemTimeAsFileTime(&_now.ft);
tp->tv_usec = (long)((_now.ns100 / 10ULL) % 1000000ULL );
tp->tv_sec = (long)((_now.ns100 - _W32_FT_OFFSET) / 10000000ULL);
}
/*
* Always return 0 as per Open Group Base Specifications Issue 6.
* Do not set errno on error.
*/
return 0;
}
/* TODO */
int
geteuid(void)
{
return 0;
}
int
getuid(void)
{
return 0;
}
int
getgid(void)
{
return 0;
}
/*
* mmap patches for more than one map area by
* Mark Pizzolato clamav-win32@subscriptions.pizzolato.net
*/
static pthread_mutex_t mmap_mutex = PTHREAD_MUTEX_INITIALIZER;
static struct mmap_context {
struct mmap_context *link;
HANDLE h;
LPVOID view;
size_t length;
} *mmaps = NULL;
caddr_t
mmap(caddr_t address, size_t length, int protection, int flags, int fd, off_t offset)
{
LPVOID addr;
HANDLE h;
struct mmap_context *ctx;
if(flags != MAP_PRIVATE) {
cli_errmsg("mmap: only MAP_PRIVATE is supported\n");
return MAP_FAILED;
}
if(protection != PROT_READ) {
cli_errmsg("mmap: only PROT_READ is supported\n");
return MAP_FAILED;
}
if(address != NULL) {
cli_errmsg("mmap: only NULL map address is supported\n");
return MAP_FAILED;
}
h = CreateFileMapping((HANDLE)_get_osfhandle(fd), NULL, PAGE_READONLY, 0, 0, NULL);
if(h == NULL) {
cli_errmsg("mmap: CreateFileMapping failed - error %d\n",
GetLastError());
return MAP_FAILED;
}
if(GetLastError() == ERROR_ALREADY_EXISTS) {
cli_errmsg("mmap: ERROR_ALREADY_EXISTS\n");
CloseHandle(h);
return MAP_FAILED;
}
addr = MapViewOfFile(h, FILE_MAP_READ,
(DWORD)0, ((DWORD)offset & 0xFFFFFFFF),
length);
if(addr == NULL) {
cli_errmsg("mmap failed - error %d\n", GetLastError());
CloseHandle(h);
return MAP_FAILED;
}
pthread_mutex_lock(&mmap_mutex);
ctx = cli_malloc(sizeof(*ctx));
if(NULL == ctx) {
pthread_mutex_unlock(&mmap_mutex);
cli_errmsg("mmap: can't create context block\n");
UnmapViewOfFile(addr);
CloseHandle(h);
return MAP_FAILED;
}
ctx->h = h;
ctx->view = addr;
ctx->length = length;
ctx->link = mmaps;
mmaps = ctx;
pthread_mutex_unlock(&mmap_mutex);
return (caddr_t)addr;
}
int
munmap(caddr_t addr, size_t length)
{
struct mmap_context *ctx = mmaps, *lctx = NULL;
pthread_mutex_lock(&mmap_mutex);
for(; ctx && (ctx->view != addr); ctx = ctx->link)
lctx = ctx;
if(ctx == NULL) {
pthread_mutex_unlock(&mmap_mutex);
cli_warnmsg("munmap with no corresponding mmap\n");
return -1;
}
if(ctx->length != length) {
pthread_mutex_unlock(&mmap_mutex);
cli_warnmsg("munmap with incorrect length specified (%u != %u) - partial munmap unsupported\n",
length, ctx->length);
return -1;
}
if(lctx == NULL)
mmaps = ctx->link;
else
lctx->link = ctx->link;
pthread_mutex_unlock(&mmap_mutex);
UnmapViewOfFile(ctx->view);
CloseHandle(ctx->h);
free(ctx);
return 0;
}
int
chown(const char *filename, short uid, short gid)
{
return 0;
}
#ifdef USE_SYSLOG
/*
* Put into the Windows Event Log
* Right Click My Computer->Manage->Event Viewer->Application
* See http://cybertiggyr.com/gene/wel/src/insert-log.c for inspiration
* http://msdn2.microsoft.com/en-gb/library/aa363634(VS.85).aspx
* and http://msdn2.microsoft.com/en-us/library/aa363680(VS.85).aspx
*
* FIXME: Not thread safe, but see shared/output.c, which ensures this code is
* single threaded - therefore don't call this code directly
*/
static HANDLE logg_handle;
static int initlog(const char *source);
void
openlog(const char *name, int options, int facility)
{
if(logg_handle != NULL)
closelog();
else
(void)initlog(name);
logg_handle = RegisterEventSource(NULL, name);
if(logg_handle == NULL)
cli_warnmsg("openlog: Can't register source %s - error %d\n", name, GetLastError());
}
void
closelog(void)
{
if(logg_handle != NULL)
DeregisterEventSource(logg_handle);
}
void
syslog(int level, const char *format, ...)
{
if(logg_handle == NULL)
openlog("Clam AntiVirus", 0, LOG_LOCAL6);
if(logg_handle != NULL) {
va_list args;
char buff[512];
char *ptr;
va_start(args, format);
(void)vsnprintf(buff, sizeof(buff), format, args);
va_end(args);
ptr = buff;
/*
* Category = 0, eventId = CLAMAV_EVENTMSG, SID = NULL, 1 string
*/
if(!ReportEventA(logg_handle, (WORD)level, 0, CLAMAV_EVENTMSG, NULL, 1, 0, (LPCSTR *)&ptr, NULL))
cli_warnmsg("syslog: ReportEventA(%d, %d, 0, %d, NULL, 1, 0, %s, NULL) failed: %d\n",
logg_handle, level, CLAMAV_EVENTMSG, buff, GetLastError());
}
}
static int
initlog(const char *source)
{
/*DWORD dwCategoryNum = 1; /* The number of categories for the event source. */
HKEY hk;
DWORD dwData, /*dwDisp,*/ len;
char path[MAX_PATH];
/* Create the event source as a subkey of the log. */
(void)snprintf(path, sizeof(path),
"SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application\\%s",
source);
if(RegCreateKey(HKEY_LOCAL_MACHINE, path, &hk) != 0) {
cli_warnmsg("Could not create the registry key\n");
/*return 0;*/
}
/* Set the name of the message file. */
GetModuleFileName(NULL, path, sizeof(path));
path[sizeof(path) - 1] = '\0';
len = (DWORD)(strlen(path) + 1);
if(RegSetValueEx(hk, "EventMessageFile", 0, REG_EXPAND_SZ, (LPBYTE)path, len)) {
cli_warnmsg("Could not set the event message file\n");
RegCloseKey(hk);
return 0;
}
/* Set the supported event types. */
dwData = EVENTLOG_ERROR_TYPE | EVENTLOG_WARNING_TYPE | EVENTLOG_INFORMATION_TYPE;
if(RegSetValueEx(hk, "TypesSupported", 0, REG_DWORD, (LPBYTE)&dwData, sizeof(DWORD))) {
cli_warnmsg("Could not set the supported types\n");
RegCloseKey(hk);
return 0;
}
#if 0
/* Set the category message file and number of categories. */
if(RegSetValueEx(hk, "CategoryMessageFile", 0, REG_EXPAND_SZ,
(LPBYTE)path, len)) {
cli_warnmsg("Could not set the category message file\n");
RegCloseKey(hk);
return 0;
}
if(RegSetValueEx(hk, "CategoryCount", 0, REG_DWORD, (LPBYTE)&dwCategoryNum, sizeof(DWORD))) {
cli_warnmsg("Could not set the category count\n");
RegCloseKey(hk);
return 0;
}
#endif
RegCloseKey(hk);
return 1;
}
#endif
int
snprintf(char *str, size_t size, const char *format, ...)
{
int ret;
va_list args;
va_start(args, format);
ret = _vsnprintf_s(str, size, _TRUNCATE, format, args);
va_end(args);
return ret;
}