/*-------------------------------------------------------------------------
 *
 * open.c
 *	   Win32 open() replacement
 *
 *
 * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
 *
 * $PostgreSQL: pgsql/src/port/open.c,v 1.2 2004/04/19 17:42:59 momjian Exp $
 *
 *-------------------------------------------------------------------------
 */

#ifdef WIN32

#include <windows.h>
#include <fcntl.h>
#include <errno.h>
#include <assert.h>

static int
openFlagsToCreateFileFlags(int openFlags)
{
	switch (openFlags & (O_CREAT|O_TRUNC|O_EXCL))
	{
		case 0:
		case O_EXCL:	return OPEN_EXISTING;

		case O_CREAT:	return OPEN_ALWAYS;

		case O_TRUNC:
		case O_TRUNC|O_EXCL:	return TRUNCATE_EXISTING;

		case O_CREAT|O_TRUNC:	return CREATE_ALWAYS;

		case O_CREAT|O_EXCL:
		case O_CREAT|O_TRUNC|O_EXCL:	return CREATE_NEW;
	}

	/* will never get here */
	return 0;
}

/*
 *   - file attribute setting, based on fileMode?
 *   - handle other flags? (eg FILE_FLAG_NO_BUFFERING/FILE_FLAG_WRITE_THROUGH)
 */
int win32_open(const char* fileName, int fileFlags, ...)
{
	int fd;
	HANDLE h;
	SECURITY_ATTRIBUTES sa;

	/* Check that we can handle the request */
	assert((fileFlags & ((O_RDONLY|O_WRONLY|O_RDWR) | O_APPEND	|
						 (O_RANDOM|O_SEQUENTIAL|O_TEMPORARY)	|
						 _O_SHORT_LIVED							|
						 (O_CREAT|O_TRUNC|O_EXCL) | (O_TEXT|O_BINARY))) == fileFlags);

	sa.nLength=sizeof(sa);
	sa.bInheritHandle=TRUE;
	sa.lpSecurityDescriptor=NULL;

	if ((h = CreateFile(fileName,
						/* cannot use O_RDONLY, as it == 0 */
						(fileFlags & O_RDWR)     ? (GENERIC_WRITE | GENERIC_READ) :
						((fileFlags &  O_WRONLY) ?  GENERIC_WRITE : GENERIC_READ),
						(FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE),
						&sa,
						openFlagsToCreateFileFlags(fileFlags),
						FILE_ATTRIBUTE_NORMAL	|
						((fileFlags &  O_RANDOM)		? FILE_FLAG_RANDOM_ACCESS	: 0) |
						((fileFlags &  O_SEQUENTIAL)	? FILE_FLAG_SEQUENTIAL_SCAN	: 0) |
						((fileFlags & _O_SHORT_LIVED)	? FILE_ATTRIBUTE_TEMPORARY	: 0) |
						((fileFlags &  O_TEMPORARY)		? FILE_FLAG_DELETE_ON_CLOSE	: 0),
						NULL)) == INVALID_HANDLE_VALUE)
	{
		switch (GetLastError())
		{
			/* EMFILE, ENFILE should not occur from CreateFile. */
			case ERROR_PATH_NOT_FOUND:
			case ERROR_FILE_NOT_FOUND:	errno = ENOENT; break;
			case ERROR_FILE_EXISTS:		errno = EEXIST; break;
			case ERROR_ACCESS_DENIED:	errno = EACCES; break;
			default:
				errno = EINVAL;
		}
		return -1;
	}

	/* _open_osfhandle will, on error, set errno accordingly */
	if ((fd = _open_osfhandle((long)h,fileFlags&O_APPEND)) < 0 ||
		(fileFlags&(O_TEXT|O_BINARY) && (_setmode(fd,fileFlags&(O_TEXT|O_BINARY)) < 0)))
		CloseHandle(h); /* will not affect errno */
	return fd;
}

#endif
