/* u_misc.c
 *
 * Copyright (c) 1996-2005 Mike Gleason, NcFTP Software.
 * All rights reserved.
 *
 */

#include "syshdrs.h"
#ifdef PRAGMA_HDRSTOP
#	pragma hdrstop
#endif

static int wsaInit = 0;
#if defined(WIN32) || defined(_WINDOWS)
WSADATA wsaData;
#endif



void
InitWinsock(void)
{
#if (defined(WIN32) || defined(_WINDOWS)) && !defined(__CYGWIN__)
	if (WSAStartup(MAKEWORD(2, 0), &wsaData) != 0) {
#	ifdef _CONSOLE
		fprintf(stderr, "could not initialize winsock\n");
#	endif
		exit(1);
	}
#endif
	wsaInit++;
}	/* InitWinsock */



void
DisposeWinsock(void)
{
#if (defined(WIN32) || defined(_WINDOWS)) && !defined(__CYGWIN__)
	if (wsaInit > 0) { WSACleanup(); wsaInit--; }
#else
	wsaInit--;
#endif
}	/* DisposeWinsock */




#if (defined(WIN32) || defined(_WINDOWS)) && !defined(__CYGWIN__)


int gettimeofday(struct timeval *const tp, void *junk)
{
	SYSTEMTIME systemTime;

	GetSystemTime(&systemTime);

	/* Create an arbitrary second counter;
	 * Note that this particular one creates
	 * a problem at the end of the month.
	 */
	tp->tv_sec =
		systemTime.wSecond +
		systemTime.wMinute * 60 +
		systemTime.wHour * 3600 +
		systemTime.wDay * 86400;

	tp->tv_usec = systemTime.wMilliseconds * 1000;

	return 0;
}	/* gettimeofday */




void WinSleep(unsigned int seconds)
{
	DWORD now, deadline;
	DWORD milliseconds = seconds * 1000;

	if (milliseconds > 0) {
		now = GetTickCount();
		deadline = now + milliseconds;
		if (now < deadline) {
			/* Typical case */
			do {
				milliseconds = deadline - now;
				Sleep(milliseconds);
				now = GetTickCount();
			} while (now < deadline);
		} else {
			/* Overflow case */
			deadline = now - 1;
			milliseconds -= (0xFFFFFFFF - now);
			do {
				Sleep(0xFFFFFFFF - now);
				now = GetTickCount();
			} while (now > deadline);
			/* Counter has now wrapped around */
			deadline = now + milliseconds;
			do {
				milliseconds = deadline - now;
				Sleep(milliseconds);
				now = GetTickCount();
			} while (now < deadline);
		}
	}
}	/* WinSleep */
#endif



#if defined(WIN32) || defined(_WINDOWS) || defined(__CYGWIN__)
char *
StrFindLocalPathDelim(const char *src) /* TODO: optimize */
{
	const char *first;
	int c;

	first = NULL;
	for (;;) {
		c = *src++;
		if (c == '\0')
			break;
		if (IsLocalPathDelim(c)) {
			first = src - 1;
			break;
		}
	}

	return ((char *) first);
}	/* StrFindLocalPathDelim */



char *
StrRFindLocalPathDelim(const char *src)	/* TODO: optimize */
{
	const char *last;
	int c;

	last = NULL;
	for (;;) {
		c = *src++;
		if (c == '\0')
			break;
		if (IsLocalPathDelim(c))
			last = src - 1;
	}

	return ((char *) last);
}	/* StrRFindLocalPathDelim */




void
StrRemoveTrailingLocalPathDelim(char *dst)
{
	char *cp;

	cp = StrRFindLocalPathDelim(dst);
	if ((cp == NULL) || (cp[1] != '\0'))
		return;

	/* Note: Do not destroy a path of "/" */
	while ((cp > dst) && (IsLocalPathDelim(*cp)))
		*cp-- = '\0';
}	/* StrRemoveTrailingLocalPathDelim */



void
TVFSPathToLocalPath(char *dst)
{
	int c;

	/* Note: Technically we don't need to do this,
	 * since Win32 accepts a / as equivalent to a \
	 * in a pathname.
	 */
	if (dst != NULL) {
		for (;;) {
			c = *dst++;
			if (c == '\0')
				break;
			if (c == '/')
				dst[-1] = LOCAL_PATH_DELIM;
		}
	}
}	/* TVFSPathToLocalPath */


void
LocalPathToTVFSPath(char *dst)
{
	int c;

	if (dst != NULL) {
		for (;;) {
			c = *dst++;
			if (c == '\0')
				break;
			if (c == LOCAL_PATH_DELIM)
				dst[-1] = '/';
		}
	}
}	/* LocalPathToTVFSPath */
#endif





#if (defined(WIN32) || defined(_WINDOWS)) && !defined(__CYGWIN__)
int
WinFStat64(const int h0, struct WinStat64 *const stp)
{
	HANDLE h;
	__int64 fSize;
	DWORD fSize1, fSize2;
	struct _stat st32;
	DWORD winErr;

	h = (HANDLE) _get_osfhandle(h0);
	if (h == INVALID_HANDLE_VALUE)
		return (-1);

	memset(stp, 0, sizeof(struct WinStat64));
	if (_fstat(h0, &st32) < 0)
		return (-1);
	stp->st_atime = st32.st_atime;
	stp->st_ctime = st32.st_ctime;
	stp->st_dev = st32.st_dev;
	stp->st_gid = st32.st_gid;
	stp->st_ino = st32.st_ino;
	stp->st_mode = st32.st_mode;
	stp->st_mtime = st32.st_mtime;
	stp->st_nlink = st32.st_nlink;
	stp->st_rdev = st32.st_rdev;
	stp->st_uid = st32.st_uid;

	if (S_ISREG(stp->st_mode)) {
		fSize = (_int64)0;
		fSize1 = GetFileSize(h, &fSize2);
		if ((fSize1 == 0xFFFFFFFF) && ((winErr = GetLastError()) != NO_ERROR))
			goto return_err;

		fSize = ((__int64) fSize2 << 32) | (__int64) fSize1;
		stp->st_size = fSize;
	}
	return (0);

return_err:
	stp->st_size = (__int32) st32.st_size;
	if ((winErr = GetLastError()) == ERROR_SHARING_VIOLATION) {
		errno = EBUSY;
	} else if ((winErr == ERROR_PATH_NOT_FOUND) || (winErr == ERROR_FILE_NOT_FOUND)) {
		errno = ENOENT;
	} else if (winErr == ERROR_INVALID_PARAMETER) {
		errno = EINVAL;
	} else {
		errno = 100000 + winErr;
	}
	return (-1);
}	/* WinFStat64 */




int
WinStat64(const char *const path, struct WinStat64 *const stp)
{
	HANDLE h;
	__int64 fSize;
	DWORD fSize1, fSize2;
	struct _stat st32;
	DWORD winErr;

	memset(stp, 0, sizeof(struct WinStat64));
	if (_stat(path, &st32) < 0)
		return (-1);
	stp->st_atime = st32.st_atime;
	stp->st_ctime = st32.st_ctime;
	stp->st_dev = st32.st_dev;
	stp->st_gid = st32.st_gid;
	stp->st_ino = st32.st_ino;
	stp->st_mode = st32.st_mode;
	stp->st_mtime = st32.st_mtime;
	stp->st_nlink = st32.st_nlink;
	stp->st_rdev = st32.st_rdev;
	stp->st_uid = st32.st_uid;

	if (S_ISREG(stp->st_mode)) {
		h = CreateFile(path,
			0,				/* Not GENERIC_READ; use 0 for "query attributes only" mode */
			0,
			NULL,
			OPEN_EXISTING,	/* fails if it doesn't exist */
			0,
			NULL
			);
		
		if (h == INVALID_HANDLE_VALUE)
			goto return_err;

		fSize = (_int64)0;
		fSize1 = GetFileSize(h, &fSize2);
		if ((fSize1 == 0xFFFFFFFF) && ((winErr = GetLastError()) != NO_ERROR))
			goto return_err;

		fSize = ((__int64) fSize2 << 32) | (__int64) fSize1;
		stp->st_size = fSize;
		CloseHandle(h);
	}
	return (0);

return_err:
	stp->st_size = (__int32) st32.st_size;
	if ((winErr = GetLastError()) == ERROR_SHARING_VIOLATION) {
		errno = EBUSY;
	} else if ((winErr == ERROR_PATH_NOT_FOUND) || (winErr == ERROR_FILE_NOT_FOUND)) {
		errno = ENOENT;
	} else if (winErr == ERROR_INVALID_PARAMETER) {
		errno = EINVAL;
	} else {
		errno = 100000 + winErr;
	}

	if (h != INVALID_HANDLE_VALUE)
		CloseHandle(h);
	return (-1);
}	/* WinStat64 */

#endif


syntax highlighted by Code2HTML, v. 0.9.1