/* fcntl.c (rsxnt) -- Copyright (c) 1996-1997 Rainer Schnitker */

#include "rsxnt.h"

#ifndef F_GETOSFD
#define F_GETOSFD 6
#endif

static void InheritHandle(EMXPROCESS *p, int fd, BOOL bInherit)
{
    /*
      There are problems with this code (f.e. gdb)
      Perhaps there is a problem with console handles and dup(), dup2()

      Win32 Help file:
      Console handles can be duplicated for use only in the same process.

      For NT we can use SetHandleInformation !
    */

    if (_rsxnt_win32_version != WIN32) {
	HANDLE hproc, hout;
	HANDLE hin = p->file[fd].f_handle;

	hproc = GetCurrentProcess();

	if (DuplicateHandle(hproc, hin, hproc, &hout, 0, bInherit,
		DUPLICATE_SAME_ACCESS) == FALSE)
	    return;

	CloseHandle(hin);
	p->file[fd].f_handle = hout;
    }
    else { /* NT */
	HANDLE h = p->file[fd].f_handle;
	SetHandleInformation (h, HANDLE_FLAG_INHERIT,
		    (bInherit) ? HANDLE_FLAG_INHERIT : 0);
    }
}

int __fcntl(int fd, int request, int arg)
{
    EMXPROCESS *p = _rsxnt_get_process_ptr();
    int ret;

    if (fd >= N_FILES || fd < 0 || p->file[fd].f_handle == INVALID_HANDLE_VALUE)
	return _rsxnt_errno(EBADF);

    switch (request) {
	case F_GETFL:
	    return p->file[fd].f_flags;

	case F_SETFL:
	    ret = 0;

	    if (p->file[fd].f_mode == HT_SOCKET &&
		(p->file[fd].f_mode & O_NONBLOCK) != (arg & O_NONBLOCK))
	    {
		if (!_rsxnt_socket_fop.fcntl)
		    return _rsxnt_errno (EBADF);
		else
		    ret = (*_rsxnt_socket_fop.fcntl)
			    ((int) p->file[fd].f_handle, F_SETFL, arg);
	    }
	    if (ret == 0)
		p->file[fd].f_flags = arg;
	    return ret;

	case F_GETFD:
	    return EMX_FD_ISSET(fd, p->close_on_exec);

	case F_SETFD:
	    if (arg & 1) {  /* no inherit */
		if (!EMX_FD_ISSET(fd, p->close_on_exec))
		    InheritHandle(p, fd, FALSE);
		EMX_FD_SET(fd, p->close_on_exec);
	    }
	    else {  /* inherit files */
		if (EMX_FD_ISSET(fd, p->close_on_exec))
		    InheritHandle(p, fd, TRUE);
		EMX_FD_CLR(fd, p->close_on_exec);
	    }
	    return 0;

	case F_GETOSFD:
            return (int) p->file[fd].f_handle;
    }
    return -EINVAL;
}
