This is the mail archive of the cygwin@sourceware.cygnus.com mailing list for the Cygwin project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

tty patches for modem/fax control


Following is the tty support code that I've been
working on. The code integrates Sergey Okhapkin's
patch, but no other changes. The files affected are:

fcntl.cc
fhandler.cc
fhandler.h
include/fcntl.h
include/sys/termios.h
termios.cc

The diff file, 0601tty.diff was produced by
restoring the original B18 distribution, applying
Sergey Okhapkin's patch and then diff'ing against
the changed version of the files listed above.
Patch, however, consistently fails to handle
fhandler.cc and fhandler.h (patch seems to be
generally buggy on my machine), so these two
files are included as separate attachments.

My tty projects seem to be working with these
code changes, but they should be considered
untested. No attempt has been made to accomodate
Win95 differences from WinNT. Consider these
changes to be a first attempt at the development
of a robust tty sub-system for eventual inclusion
in cygwin32, and anyone who wishes to test,
debug, correct, or re-implement is more than
welcome to have at it.

The code changes do not implement any part of
"struct termio"/ioctl() features, but rather the
"struct termios" and tcsetsttr() group of
functions. You will need to convert your code
from ioctl() to tc...() to use the new
features.

tcflush() has a previous implementation, which
is unchanged.

The tty features which have an implementation,
and their known limitations are listed:



1.  The O_NDELAY flag to open() and fcntl()
    causes the COMMTIMEOUTS structure to be
    manipulated to put the file-handle in
    blocking or non-blocking I/O mode. fcntl()
    can be used to block/non-block in this
    fashion:

    /* non-blocking I/O */
    fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NDELAY);

    /* blocking I/O */
    fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) & ~O_NDELAY);

    O_NONBLOCK can be implemented by some
    variation of:

    #undef O_NONBLOCK
    #define O_NONBLOCK O_NDELAY

    Sergey Okhapkin has pointed-out that this
    use of fcntl() may have an undesireable
    side effect if used with the console or
    (as yet non-existant) psuedo-ttys. The
    fhandler_base class probably needs to be
    augmented with an isaserialport() function
    to clear this bug. I was afraid to change
    the members of this class (I also wanted to
    delete or enlarge the ofspeed and ifspeed
    data members) thinking that it might break
    already compiled programs. Is this correct?

2.  tcgetattr() previously handled CBAUD (all
    speeds through B38400, except B0), CSIZE,
    ONLCR, and VTIME and VMIN for c_cc[].

    New support is for B0, CLOCAL, CSTOPB,
    PARENB, PARODD, INPCK, IGNPAR, IXON, IXOFF,
    CRTSXOFF, CRTSCTS, and VSTART and VSTOP for
    c_cc[].

3.  tcsetattr() previously handled CBAUD
    (except B0), CSIZE, PARENB, PARODD, IGNCR,
    ONLCR, and VTIME and VMIN for c_cc[].

    New support is for B0, CSTOPB, INPCK,
    IGNPAR, IXON, IXOFF, CRTSXOFF, CRTSCTS,
    and VSTART and VSTOP for c_cc[].
    TCSANOW, TCSADRAIN, and TCSAFLUSH arguments
    are implemented through calls to
    FlushFileBuffers() and PurgeComm().
    B0 should cause DTR to drop via a
    call to EscapeCommFunction().
    CLOCAL disables hardware flow-control and
    DSR detection. CLOCAL does not disable
    DTR lead control, which is often needed
    for hanging-up a modem, nor does it affect
    CD (carrier detect) in any way. This needs
    an implementation so that the loss of
    carrier generates the equivalent of SIGHUP.
    Any ideas?

4.  tcsendbreak() is implemented through calls to
    SetCommBreak() and ClearCommBreak().

5.  tcdrain() is implemented through a call to
    FlushFileBuffers().

6.  tcflow() is implemented for TCOOFF and TCOON
    with a call to EscapeCommFunction(), and for
    TCION and TCIOFF with a call to
    TransmitCommChar(). The values in c_cc[VSTART]
    and c_cc[VSTOP] are honored, if present,
    otherwise 0x11 and 0x13 are used, respectively.

Because many of the termios flags are not supported,
a call to tcgetattr() will not return the same values
that the flags in the call to tcsetattr() specified.
Generally speaking, to more fully implement the tty
subsystem, more state needs to be held in the
fhandler_base or fhandler_tty class.

Good luck,

Mike Anderson
mka@redes.int.com.mk
Guanajuato, GTO, Mexico
*** winsup.sergey/fcntl.cc	Sat May 31 23:56:14 1997
--- winsup/fcntl.cc	Sun Jun 01 10:09:59 1997
***************
*** 80,113 ****
  	}
        break;
  
!     case F_GETFL:
!        res = 0;
!        if (this_procinfo ()->hmap[fd].h->get_access () & GENERIC_READ)
!  	res |= O_RDONLY;
!        if (this_procinfo ()->hmap[fd].h->get_access () & GENERIC_WRITE)
!  	res |= O_WRONLY;
!        if (this_procinfo ()->hmap[fd].h->get_access () & GENERIC_ALL)
!  	res |= O_RDWR;
!        goto done;
! 
!     case F_SETFL:
!       {
! 	int temp = 0;
! 	va_start (args, cmd);
! 	arg = va_arg (args, int);
! 	va_end (args);
! 
!  	if (arg & O_RDONLY)
!  	  temp |= GENERIC_READ;
!  	if (arg & O_WRONLY)
!  	  temp |= GENERIC_WRITE;
! 
! 	syscall_printf ("fcntl (%d, F_SETFL, %d);\n", arg);  
! 
!  	this_procinfo ()->hmap[fd].h->set_access (temp);
! 	res =  0;
! 	goto done;
!       }
  
      case F_GETLK:
      case F_SETLK:
--- 80,235 ----
  	}
        break;
  
! 
! 
! 
! 	case F_GETFL:
! 		{	/* scope only */
! 		int access;
! 		res = 0;
! 
! 		access = this_procinfo()->hmap[fd].h->get_access();
! 
! 		if( (access & (GENERIC_READ | GENERIC_WRITE)) == GENERIC_READ )
! 		{
! 			res |= O_RDONLY;
! 		}
! 		else if( (access & (GENERIC_READ | GENERIC_WRITE)) == GENERIC_WRITE )
! 		{
! 			res |= O_WRONLY;
! 		}
! 		else if( (access & (GENERIC_READ | GENERIC_WRITE)) ==
! 				(GENERIC_READ | GENERIC_WRITE) )
! 		{
! 			res |= O_RDWR;
! 		}
! 		else
! 		{
! 			/* ugly error - do what here? */
! 		}
! 
! 		if( access & _FNDELAY )
! 			res |= O_NDELAY;
! 		goto done;
! 
! 		}	/* scope only */
! 
! 
! 
! 
! case F_SETFL:
! 		{	/* scope only */
! 
! 		int temp = 0;
! 		int access;
! 		va_start (args, cmd);
! 		arg = va_arg (args, int);
! 		va_end (args);
! 
! 
! 		/*	these guys aren't allowed anymore in Unix so we have to
! 			get them from fhandler_base */
! 	/*
! 		if( (arg & (O_RDONLY | O_WRONLY | O_RDWR)) == O_RDONLY )
! 		{
! 			temp |= GENERIC_READ;
! 		}
! 		else if( (arg & (O_RDONLY | O_WRONLY | O_RDWR)) == O_WRONLY )
! 		{
! 			temp |= GENERIC_WRITE;
! 		}
! 		else if( (arg & (O_RDONLY | O_WRONLY | O_RDWR)) == O_RDWR )
! 		{
! 			temp |= (GENERIC_READ | GENERIC_WRITE);
! 		}
! 	*/
! 		access = this_procinfo()->hmap[fd].h->get_access();
! 		temp |= (access & (GENERIC_READ | GENERIC_WRITE));
! 
! 		if( arg & O_NDELAY )	/* non-blocking I/O */
! 		{
! 			temp |= _FNDELAY;
! 
! 			BOOL isatty = this_procinfo()->hmap[fd].h->is_tty();
! 			if( isatty )
! 			{
! 				HANDLE myhandle = this_procinfo()->hmap[fd].h->get_handle();
! 				COMMTIMEOUTS to;
! 
! 				memset( &to, 0, sizeof(to) );
! 
! 				/* probably not necessary */
! 				if( GetCommTimeouts( myhandle, &to ) == 0 )
! 				{
! 					small_printf ("GetCommTimeout failed\n");
! 					__seterrno ();
! 					return -1;
! 				}
! 
! 				to.ReadIntervalTimeout = MAXDWORD;
! 				to.ReadTotalTimeoutMultiplier = 0;
! 				to.ReadTotalTimeoutConstant = 0;
! 
! 				/* leave the values vmin_ and vtime_ alone for restoral later */
! 
! 				if( SetCommTimeouts( myhandle, &to ) == 0 )
! 				{
! 					small_printf ("SetCommTimeout failed\n");
! 					__seterrno ();
! 					return -1;
! 				}
! 			}	/* if a tty */
! 
! 		}	/* non-blocking I/O */
! 		else
! 		{	/* blocking I/O */
! 
! 			/* if non-blocking is set, unset it */
! 			if( access & _FNDELAY )
! 			{
! 				BOOL isatty = this_procinfo()->hmap[fd].h->is_tty();
! 				if( isatty )
! 				{
! 					HANDLE myhandle = this_procinfo()->hmap[fd].h->get_handle();
! 					COMMTIMEOUTS to;
! 
! 					memset( &to, 0, sizeof(to) );
! 
! 				/* probably not necessary */
! 				/*
! 					if( GetCommTimeouts( myhandle, &to ) == 0 )
! 					{
! 						small_printf ("GetCommTimeout failed\n");
! 						__seterrno ();
! 						return -1;
! 					}
! 
! 					we have no access to vtime_ or vmin_
! 					to.ReadIntervalTimeout = 0;
! 					to.ReadTotalTimeoutMultiplier = 0;
! 					to.ReadTotalTimeoutConstant = vtime_ * 100;
! 				*/
! 
! 					if( SetCommTimeouts( myhandle, &to ) == 0 )
! 					{
! 						small_printf ("SetCommTimeout failed\n");
! 						__seterrno ();
! 						return -1;
! 					}
! 				}	/* if a tty */
! 			}	/* if non-blocking is set */
! 		}	/* blocking I/O */
! 
! 		syscall_printf ("fcntl (%d, F_SETFL, %d);\n", arg);  
! 
! 		this_procinfo()->hmap[fd].h->set_access( temp );
! 		res =  0;
! 		goto done;
! 
! 		}	/* scope only */
! 
! 
! 
  
      case F_GETLK:
      case F_SETLK:
*** winsup.sergey/fhandler.cc	Sat May 31 23:56:14 1997
--- winsup/fhandler.cc	Sun Jun 01 10:09:59 1997
***************
*** 1261,1266 ****
--- 1261,1358 ----
    paranoid_printf ("FHANDLER TTY\n");
  }
  
+ 
+ 
+ 
+ 
+ fhandler_base * 
+ fhandler_tty::open( const char *path, int flags, mode_t mode )
+ {
+ 	fhandler_base *res = NULL;
+ 	int temp = 0;
+ 	int access;
+ 	HANDLE myhandle;
+ 	COMMTIMEOUTS to;
+ 
+ 	syscall_printf( "fhandler_tty::open( %s, 0x%x, 0x%x )\n",
+ 			path, flags, mode );
+ 
+ 	if( (res = fhandler_base::open( path, flags, mode ) ) == NULL )
+ 			return( NULL );
+ 
+ 	memset( &to, 0, sizeof(to) );
+ 
+ 	myhandle = fhandler_base::get_handle();
+ 	access = fhandler_base::get_access();
+ 	temp |= (access & (GENERIC_READ | GENERIC_WRITE));
+ 
+ 	if( flags & O_NDELAY )	/* non-blocking I/O */
+ 	{
+ 		temp |= _FNDELAY;
+ 
+ 		/* probably not necessary */
+ 		if( GetCommTimeouts( myhandle, &to ) == 0 )
+ 		{
+ 			small_printf ("GetCommTimeout failed\n");
+ 			__seterrno ();
+ 			return( NULL );
+ 		}
+ 
+ 		to.ReadIntervalTimeout = MAXDWORD;
+ 		to.ReadTotalTimeoutMultiplier = 0;
+ 		to.ReadTotalTimeoutConstant = 0;
+ 
+ 		/* leave the values vmin_ and vtime_ alone for restoral later */
+ 
+ 		if( SetCommTimeouts( myhandle, &to ) == 0 )
+ 		{
+ 			small_printf ("SetCommTimeout failed\n");
+ 			__seterrno ();
+ 			return( NULL );
+ 		}
+ 
+ 	}	/* non-blocking I/O */
+ 	else
+ 	{	/* blocking I/O */
+ 
+ 		/* if non-blocking is set, unset it */
+ 		if( access & _FNDELAY )
+ 		{
+ 			/* probably not necessary */
+ 			/*
+ 				if( GetCommTimeouts( myhandle, &to ) == 0 )
+ 				{
+ 					small_printf ("GetCommTimeout failed\n");
+ 					__seterrno ();
+ 					return( NULL );
+ 				}
+ 
+ 				we have no access to vtime_ or vmin_
+ 				to.ReadIntervalTimeout = 0;
+ 				to.ReadTotalTimeoutMultiplier = 0;
+ 				to.ReadTotalTimeoutConstant = vtime_ * 100;
+ 			*/
+ 
+ 			if( SetCommTimeouts( myhandle, &to ) == 0 )
+ 			{
+ 				small_printf ("SetCommTimeout failed\n");
+ 				__seterrno ();
+ 				return( NULL );
+ 			}
+ 		}	/* if non-blocking is set */
+ 	}	/* blocking I/O */
+ 
+ 	fhandler_base::set_access( temp );
+ 
+ 	syscall_printf( "%p = fhandler_tty::open( %s, 0x%x, 0x%x )\n",
+ 			res, path, flags, mode );
+ 	return res;
+ }	/* tty open() */
+ 
+ 
+ 
+ 
+ 
  int
  fhandler_tty::fstat (struct stat *buf)
  {
***************
*** 1276,1281 ****
--- 1368,1448 ----
    return 0;
  }
  
+ 
+ 
+ 
+ 
+ int
+ fhandler_tty::tcsendbreak( int duration )
+ {
+ 	unsigned int sleeptime = 350;
+ 	if( duration > 1 )
+ 		sleeptime *= duration;
+ 	
+ 
+ 	if( SetCommBreak( get_handle() ) == 0 )
+ 		return( -1 );
+ 	usleep( sleeptime );
+ 	if( ClearCommBreak( get_handle() ) == 0 )
+ 		return( -1 );
+ 	return( 0 );
+ }
+ 
+ 
+ 
+ 
+ int
+ fhandler_tty::tcdrain( void )
+ {
+ 	if( FlushFileBuffers( get_handle() ) == 0 )
+ 		return( -1 );
+ 	return( 0 );
+ }
+ 
+ 
+ 
+ 
+ int
+ fhandler_tty::tcflow( int action )
+ {
+ 	DCB dcb;
+ 	DWORD winaction = 0;
+ 	char xchar;
+ 
+ 	switch( action )
+ 	{
+ 		case TCOOFF:
+ 						winaction = SETXOFF;
+ 						break;
+ 		case TCOON:
+ 						winaction = SETXON;
+ 						break;
+ 		case TCION:
+ 		case TCIOFF:
+ 						if( GetCommState( get_handle(), &dcb ) == 0 )
+ 							return( -1 );
+ 						if( action == TCION )
+ 							xchar = (dcb.XonChar ? dcb.XonChar : 0x11);
+ 						else
+ 							xchar = (dcb.XoffChar ? dcb.XoffChar : 0x13);
+ 						if( TransmitCommChar( get_handle(), xchar ) == 0 )
+ 							return( -1 );
+ 						return( 0 );
+ 						break;
+ 		default:
+ 						return( -1 );
+ 						break;
+ 	}
+ 
+ 	if( EscapeCommFunction( get_handle(), winaction ) == 0 )
+ 		return( -1 );
+ 	return( 0 );
+ }
+ 
+ 
+ 
+ 
+ 
  int
  fhandler_tty::tcflush (int queue)
  {
***************
*** 1312,1500 ****
    return 0;
  }
  
  int
! fhandler_tty::tcsetattr (int, const struct termios *t)
  {
-   int newrate;
-   int newsize;
  
!   COMMTIMEOUTS to;
!   DCB state;
  
-   switch (t->c_ospeed)
-     {
-     case B110:
-       newrate = CBR_110;
-       break;
-     case B300:
-       newrate = CBR_300;
-       break;
-     case B600:
-       newrate = CBR_600;
-       break;
-     case B1200:
-       newrate = CBR_1200;
-       break;
-     case B2400:
-       newrate = CBR_2400;
-       break;
-     case B4800:
-       newrate = CBR_4800;
-       break;
-     case B9600:
-       newrate = CBR_9600;
-       break;
-     case B19200:
-       newrate = CBR_19200;
-       break;
-     case B38400:
-       newrate = CBR_38400;
-       break;
-     default:
-       termios_printf ("t->c_ospeed was %d\n", t->c_ospeed);
-       set_errno ( EINVAL);
-       return -1;
-     }
  
!   switch (t->c_cflag & CSIZE)
!     {
!     case CS5:
!       newsize = 5;
!       break;
!     case CS6:
!       newsize = 6;
!       break;
!     case CS7:
!       newsize = 7;
!       break;
!     case CS8:
!       newsize = 8;
!       break;
!     default:
!       newsize = 8;
!     }
! 
!   GetCommState (get_handle (), &state);
  #if 0
!   ds ("First in tcsetattr", &state);
  #endif
!   state.BaudRate = newrate;
!   state.ByteSize = newsize;
!   state.fBinary = 1;
!   state.fParity = 0;
!   state.fOutxCtsFlow = 0;	/*!!*/
!   state.fOutxDsrFlow = 0;	/*!!*/
!   state.fDsrSensitivity = 0;	/*!!*/
! 
!   if (t->c_cflag & PARENB)
!     state.Parity = (t->c_cflag & PARODD) ? ODDPARITY:EVENPARITY;
!   else
!     state.Parity = NOPARITY;
  #if 0
!   ds ("Before SetCommState", &state);  
  #endif
!   SetCommState (get_handle (), &state);
  
-   set_r_binary ((t->c_iflag & IGNCR) ? 0 : 1);
-   set_w_binary ((t->c_oflag & ONLCR) ? 0 : 1);
  
-   vtime_ = t->c_cc[VTIME];
-   vmin_ = t->c_cc[VMIN];
  
-   memset (&to, 0, sizeof (to));
  
-   to.ReadTotalTimeoutConstant = vtime_ * 100;
  
-   int  res =  SetCommTimeouts (get_handle (), &to);
-   if (!res)
-     {
-       small_printf ("CommTimeout failed\n");
-       __seterrno ();
-       return -1;
-     }
-   //  tdump (fd);
-   return 0;
- }
  
  int
! fhandler_tty::tcgetattr (struct termios *t)
  {
!   DCB state;
!   int thisspeed;
!   int thissize;
  
-   GetCommState (get_handle (), &state);
  #if 0
!   ds ("In tcgetattr", &state);
  #endif
-   switch (state.BaudRate)
-     {
-     case CBR_110:
-       thisspeed = B110;
-       break;
-     case CBR_300:
-       thisspeed = B300;
-       break;
-     case CBR_600:
-       thisspeed = B600;
-       break;
-     case CBR_1200:
-       thisspeed = B1200;
-       break;
-     case CBR_2400:
-       thisspeed = B2400;
-       break;
-     case CBR_4800:
-       thisspeed = B4800;
-       break;
-     case CBR_9600:
-       thisspeed = B9600;
-       break;
-     case CBR_19200:
-       thisspeed = B19200;
-       break;
-     case CBR_38400:
-       thisspeed = B38400;
-       break;
-     default:
-       thisspeed = B9600;
-       set_errno ( EINVAL);
-     }
  
-   switch (state.ByteSize)
-     {
-     case 5:
-       thissize = CS5;
-       break;
-     case 6:
-       thissize = CS6;
-       break;
-     case 7:
-       thissize = CS7;
-       break;
-     default:
-     case 8:
-       thissize = CS8;
-       break;
-     }
  
!   memset (t, 0, sizeof (*t));
  
-   t->c_ospeed = t->c_ispeed = thisspeed;
-   t->c_cflag |= thissize;
  #if 0 /* IGNCR doesn't work yet */
!   if (!get_r_binary ())
!     t->c_iflag |= IGNCR;
  #endif
!   if (!get_w_binary ())
!     t->c_oflag |= ONLCR;
  
-   t->c_cc[VTIME] =vtime_;
-   t->c_cc[VMIN] = vmin_;
  
-   //  tdump (fd);
-   return 0;
- }
  
  /**********************************************************************/
  /* /dev/null */
--- 1479,1899 ----
    return 0;
  }
  
+ 
+ 
+ 
+ 
+ 
  int
! fhandler_tty::tcsetattr( int action, const struct termios *t )
  {
  
! 	/* possible actions are:
! 		TCSANOW - do the change immediately.
! 		TCSADRAIN - change after flushing output.
! 		TCSAFLUSH - change after flushing output and discarding input.
! 	*/
! 
! 	BOOL dropDTR = FALSE;
! 	COMMTIMEOUTS to;
! 	DCB state;
! 
! 	if( (action == TCSADRAIN) || (action == TCSAFLUSH) )
! 		FlushFileBuffers( get_handle() );
! 	if( action == TCSAFLUSH )
! 		PurgeComm( get_handle(), (PURGE_RXABORT | PURGE_RXCLEAR) );
  
  
! 	/* get default/last comm state */
! 	GetCommState (get_handle (), &state);
  #if 0
! 	ds ("First in tcsetattr", &state);
  #endif
! 
! 
! 
! 	/* *********** baud rate *********** */
! 	switch (t->c_ospeed)
! 	{
! 		case B0:
! 					/* drop DTR */
! 					dropDTR = TRUE;
! 					state.BaudRate = 0;
! 					break;
! 		case B110:
! 					state.BaudRate = CBR_110;
! 					break;
! 		case B300:
! 					state.BaudRate = CBR_300;
! 					break;
! 		case B600:
! 					state.BaudRate = CBR_600;
! 					break;
! 		case B1200:
! 					state.BaudRate = CBR_1200;
! 					break;
! 		case B2400:
! 					state.BaudRate = CBR_2400;
! 					break;
! 		case B4800:
! 					state.BaudRate = CBR_4800;
! 					break;
! 		case B9600:
! 					state.BaudRate = CBR_9600;
! 					break;
! 		case B19200:
! 					state.BaudRate = CBR_19200;
! 					break;
! 		case B38400:
! 					state.BaudRate = CBR_38400;
! 					break;
! 		/*
! 		case B57600:
! 					state.BaudRate = CBR_57600;
! 					break;
! 		case B115200:
! 					state.BaudRate = CBR_115200;
! 					break;
! 		*/
! 		/* WIN32 also has 14400, 56000, 128000, and 256000 */
! 		/* Unix also has 230400 */
! 		default:
! 					termios_printf ("t->c_ospeed was %d\n", t->c_ospeed);
! 					set_errno ( EINVAL);
! 					return -1;
! 	}
! 
! 	/* *********** byte size *********** */
! 	switch (t->c_cflag & CSIZE)
! 	{
! 		case CS5:
! 					state.ByteSize = 5;
! 					break;
! 		case CS6:
! 					state.ByteSize = 6;
! 					break;
! 		case CS7:
! 					state.ByteSize = 7;
! 					break;
! 		case CS8:
! 		default:
! 					state.ByteSize = 8;
! 					break;
! 	}
! 
! 
! 	/* *********** stop bits *********** */
! 	if( t->c_cflag & CSTOPB )
! 		state.StopBits = TWOSTOPBITS;
! 	else
! 		state.StopBits = ONESTOPBIT;
! 
! 
! 	/* *********** parity *********** */
! 	if (t->c_cflag & PARENB)
! 		state.Parity = (t->c_cflag & PARODD) ? ODDPARITY:EVENPARITY;
! 	else
! 		state.Parity = NOPARITY;
! 
! 
! 	state.fBinary = TRUE;	/* binary transfer */
! 	state.EofChar = 0;	/* no end-of-data in binary mode */
! 	state.fNull = FALSE;	/* don't discard nulls in binary mode */
! 
! 
! 	/* *********** parity errors *********** */
! 	/*	fParity combines the function of INPCK and NOT IGNPAR */
! 	if( (t->c_iflag & INPCK) && (! t->c_iflag & IGNPAR) )
! 		state.fParity = TRUE;	/* react to parity errors */
! 	else
! 		state.fParity = FALSE;	/* ignore parity errors */
! 
! 	/* Unix has no equivalent to these */
! 	state.fErrorChar = FALSE;
! 	state.ErrorChar = 0;
! 
! 
! /* *********** software flow control *********** */
! /* if the remote device interprets any received character as XON (the
! 	equivalent of IXANY at the remote side), then we must set
! 	fTXContinueOnXoff to FALSE to not trigger a premature XON,
! 	otherwise, a TRUE value separates the TX and RX functions. */
! 	state.fTXContinueOnXoff = TRUE;	/* separate TX and RX flow control */
! 
! 	if( t->c_iflag & IXON )	/* transmission flow control */
! 	{
! 		state.fOutX = TRUE;	/* enable */
! 	}
! 	else
! 	{
! 		state.fOutX = FALSE;	/* disable */
! 	}
! 
! 	if( t->c_iflag & IXOFF )	/* reception flow control */
! 	{
! 		state.fInX = TRUE;	/* enable */
! 		/* XoffLim and XonLim are left at default values */
! 	}
! 	else
! 	{
! 		state.fInX = FALSE;	/* disable */
! 		/* XoffLim and XonLim are left at default values */
! 	}
! 	state.XonChar = (t->c_cc[VSTART] ? t->c_cc[VSTART] : 0x11);
! 	state.XoffChar = (t->c_cc[VSTOP] ? t->c_cc[VSTOP] : 0x13);
! 
! 
! 	/* *********** hardware flow control *********** */
! 	state.fOutxDsrFlow = FALSE;	/* disable DSR flow control */
! 
! 	/*	older versions of Unix presumed hardware flow control if
! 		software flow control is not enabled. Newer Unices seem to
! 		require explicit setting of hardware flow-control and this
! 		code reflects that scheme. */
! 	/* CLOCAL causes all lead control, except DTR, to be ignored */
! 	/* input flow-control */
! 	if( (t->c_cflag & CRTSXOFF) && ( ! (t->c_cflag & CLOCAL) ) )
! 	{
! 		state.fRtsControl = RTS_CONTROL_HANDSHAKE;	/* enable */
! 	}
! 	else
! 	{
! 		state.fRtsControl = RTS_CONTROL_DISABLE;	/* disable */
! 	}
! 
! 	/* output flow-control */
! 	if( (t->c_cflag & CRTSCTS) && ( ! (t->c_cflag & CLOCAL) ) )
! 	{
! 		state.fOutxCtsFlow = TRUE;	/* enable */
! 	}
! 	else
! 	{
! 		state.fOutxCtsFlow = FALSE;	/* disable */
! 	}
! 
! 
! 
! 	/* *********** DTR *********** */
! 	state.fDtrControl = DTR_CONTROL_ENABLE;	/* assert DTR when device
! 												is opened */
! 
! 	/* *********** DSR *********** */
! 	if( t->c_cflag & CLOCAL )
! 		state.fDsrSensitivity = FALSE;	/* ignored */
! 	else
! 		state.fDsrSensitivity = TRUE;	/* DSR must be asserted at device */
! 
! 	/* *********** error handling *********** */
! 	state.fAbortOnError = TRUE;	/* read/write operations terminate upon
! 									error - requires ClearCommError() to
! 									resume. */
! 
! 
  #if 0
! 	ds ("Before SetCommState", &state);  
  #endif
! 	SetCommState( get_handle(), &state );
! 
! 	set_r_binary ((t->c_iflag & IGNCR) ? 0 : 1);
! 	set_w_binary ((t->c_oflag & ONLCR) ? 0 : 1);
! 
! 	vtime_ = t->c_cc[VTIME];
! 	vmin_ = t->c_cc[VMIN];
! 
! 	if( dropDTR == TRUE )
! 	{
! 		EscapeCommFunction( get_handle(), CLRDTR );
! 	}
! 	else
! 	{
! 		/* in case we previously set CLRDTR and setting
! 			state.fDtrControl = DTR_CONTROL_ENABLE doesn't do
! 			the trick. This relationship needs to be discovered
! 			since a program might want to change some
! 			parameters while DTR is still down. This would require
! 			setting some state and testing it.
! 		*/
! 		EscapeCommFunction( get_handle(), SETDTR );
! 	}
! 
! 	memset (&to, 0, sizeof (to));
! 
! 	to.ReadTotalTimeoutConstant = vtime_ * 100;
! 
! 	int res = SetCommTimeouts( get_handle (), &to );
! 	if( ! res )
! 	{
! 		small_printf ("CommTimeout failed\n");
! 		__seterrno ();
! 		return -1;
! 	}
! 	//  tdump (fd);
! 	return 0;
! }	/* tcsetattr() */
! 
  
  
  
  
  
  
  int
! fhandler_tty::tcgetattr( struct termios *t )
  {
! 	DCB state;
! 
! 	/* get current comm state */
! 	GetCommState (get_handle (), &state);
! 
! 	/* just in case */
! 	memset (t, 0, sizeof (*t));
  
  #if 0
! 	ds ("In tcgetattr", &state);
  #endif
  
  
! 	/* *********** baud rate *********** */
! 	switch (state.BaudRate)
! 	{
! 		case 0:			/* B0 - DTR should be dropped */
! 						t->c_cflag = t->c_ospeed = t->c_ispeed = B0;
! 						break;
! 						
! 		case CBR_110:
! 						t->c_cflag = t->c_ospeed = t->c_ispeed = B110;
! 						break;
! 		case CBR_300:
! 						t->c_cflag = t->c_ospeed = t->c_ispeed = B300;
! 						break;
! 		case CBR_600:
! 						t->c_cflag = t->c_ospeed = t->c_ispeed = B600;
! 						break;
! 		case CBR_1200:
! 						t->c_cflag = t->c_ospeed = t->c_ispeed = B1200;
! 						break;
! 		case CBR_2400:
! 						t->c_cflag = t->c_ospeed = t->c_ispeed = B2400;
! 						break;
! 		case CBR_4800:
! 						t->c_cflag = t->c_ospeed = t->c_ispeed = B4800;
! 						break;
! 		case CBR_9600:
! 						t->c_cflag = t->c_ospeed = t->c_ispeed = B9600;
! 						break;
! 		case CBR_19200:
! 						t->c_cflag = t->c_ospeed = t->c_ispeed = B19200;
! 						break;
! 		case CBR_38400:
! 						t->c_cflag = t->c_ospeed = t->c_ispeed = B38400;
! 						break;
! 		/*
! 		case CBR_57600:
! 						t->c_cflag = t->c_ospeed = t->c_ispeed = B57600;
! 						break;
! 		case CBR_115200:
! 						t->c_cflag = t->c_ospeed = t->c_ispeed = B115200;
! 						break;
! 		*/
! 		default:
! 						/* t->c_cflag = t->c_ospeed = t->c_ispeed = B9600; */
! 						set_errno ( EINVAL);
! 	}
! 
! 
! 	/* *********** byte size *********** */
! 	switch (state.ByteSize)
! 	{
! 		case 5:
! 				t->c_cflag |= CS5;
! 				break;
! 		case 6:
! 				t->c_cflag |= CS6;
! 				break;
! 		case 7:
! 				t->c_cflag |= CS7;
! 				break;
! 		case 8:
! 				t->c_cflag |= CS8;
! 				break;
! 		default:
! 				break;
! 	}
! 
! 
! 	/* *********** stop bits *********** */
! 	if( state.StopBits == TWOSTOPBITS )
! 		t->c_cflag |= CSTOPB;
! 
! 
! 	/* *********** parity *********** */
! 	if( state.Parity == ODDPARITY )
! 		t->c_cflag |= (PARENB | PARODD);
! 	if( state.Parity == EVENPARITY )
! 		t->c_cflag |= PARENB;
! 
! 
! 	/* *********** parity errors *********** */
! 	/*	fParity combines the function of INPCK and NOT IGNPAR */
! 	if( state.fParity == TRUE )
! 		t->c_iflag |= INPCK;
! 	else
! 		t->c_iflag |= IGNPAR;	/* not necessarily! */
! 
! 
! 	/* *********** software flow control *********** */
! 	/* transmission flow control */
! 	if( state.fOutX == TRUE )
! 		t->c_iflag |= IXON;
! 
! 	/* reception flow control */
! 	if( state.fInX == TRUE )
! 		t->c_iflag |= IXOFF;
! 
! 	t->c_cc[VSTART] = ( state.XonChar ? state.XonChar : 0x11 );
! 	t->c_cc[VSTOP] = ( state.XoffChar ? state.XoffChar : 0x13 );
! 
! 
! 	/* *********** hardware flow control *********** */
! 	/*	older versions of Unix presumed hardware flow control if
! 		software flow control is not enabled. Newer Unices seem to
! 		require explicit setting of hardware flow-control and this
! 		code reflects that scheme. */
! 	/* input flow-control */
! 	if( state.fRtsControl == RTS_CONTROL_HANDSHAKE )
! 		t->c_cflag |= CRTSXOFF;
! 
! 	/* output flow-control */
! 	if( state.fOutxCtsFlow == TRUE )
! 		t->c_cflag |= CRTSCTS;
! 
! 	/* *********** CLOCAL *********** */
! 	/* DSR is the only lead toggled ONLY by CLOCAL, so we can use it
! 		as a flag that CLOCAL was called. This presumes that
! 		tcsetattr() was called previously; if not, this may give
! 		a false CLOCAL. */
! 	if( state.fDsrSensitivity == FALSE )
! 		t->c_cflag |= CLOCAL;
! 
  
  #if 0 /* IGNCR doesn't work yet */
! 	if (!get_r_binary ())
! 		t->c_iflag |= IGNCR;
  #endif
! 	if (!get_w_binary ())
! 		t->c_oflag |= ONLCR;
! 
! 	t->c_cc[VTIME] = vtime_;
! 	t->c_cc[VMIN] = vmin_;
! 
! 	//  tdump (fd);
! 	return 0;
! }	/* tcgetattr() */
! 
! 
! 
  
  
  
  /**********************************************************************/
  /* /dev/null */
*** winsup.sergey/fhandler.h	Sat May 31 23:56:14 1997
--- winsup/fhandler.h	Sun Jun 01 10:10:00 1997
***************
*** 110,120 ****
    virtual void dump ();
    virtual int dup (fhandler_base *child);
  
-   virtual int tcflush (int) { return -1; }
  
    void *operator new (size_t, void *);
  
    virtual void init (HANDLE, int, int, const char *);
    virtual int tcsetattr (int a, const struct termios *t) { return -1; }
    virtual int tcgetattr (struct termios *t) { return -1; }
    virtual int is_tty () { return 0; }
--- 110,124 ----
    virtual void dump ();
    virtual int dup (fhandler_base *child);
  
  
    void *operator new (size_t, void *);
  
    virtual void init (HANDLE, int, int, const char *);
+ 
+   virtual int tcflush (int) { return -1; }
+   virtual int tcsendbreak( int ) { return 0; }
+   virtual int tcdrain( void ) { return 0; }
+   virtual int tcflow( int ) { return 0; }
    virtual int tcsetattr (int a, const struct termios *t) { return -1; }
    virtual int tcgetattr (struct termios *t) { return -1; }
    virtual int is_tty () { return 0; }
***************
*** 200,206 ****
--- 204,214 ----
    /* Constructor */
    fhandler_tty (const char *name = 0);
  
+   virtual fhandler_base *open( const char *path, int flags, mode_t mode );
    virtual int raw_read (void *ptr, size_t ulen);
+   virtual int tcsendbreak( int );
+   virtual int tcdrain( void );
+   virtual int tcflow( int );
    virtual int tcsetattr (int a, const struct termios *t);
    virtual int tcgetattr (struct termios *t);
    virtual int fstat (struct stat *buf);
*** winsup.sergey/include/sys/termios.h	Sat May 31 23:56:14 1997
--- winsup/include/sys/termios.h	Sun Jun 01 10:10:00 1997
***************
*** 34,39 ****
--- 34,40 ----
  
  
  /* iflag  bits */
+ /*
  #define IGNBRK	0x0001
  #define BRKINT	0x0002
  #define IGNPAR	0x0004
***************
*** 41,46 ****
--- 42,55 ----
  #define ISTRIP	0x0020
  #define INLCR	0x0040
  #define IGNCR	0x0080
+ */
+ #define IGNBRK	000001
+ #define BRKINT	000002
+ #define IGNPAR	000004
+ #define INPCK	000020
+ #define ISTRIP	000040
+ #define INLCR	000100
+ #define IGNCR	000200
  #define ICRNL	000400
  #define IXON	002000
  #define IXOFF	010000
***************
*** 49,54 ****
--- 58,64 ----
  #define IXANY   100000
  
  
+ /* oflag  bits */
  #define OPOST	000001
  #define OCRNL	000004
  #define ONLCR	000010
***************
*** 57,62 ****
--- 67,73 ----
  #define TAB3	014000
  
  
+ /* cflag  bits */
  #define CLOCAL	004000
  #define CREAD	000200
  #define CSIZE	000060
***************
*** 68,73 ****
--- 79,86 ----
  #define HUPCL	002000
  #define PARENB	000400
  #define PARODD	001000
+ #define CRTSXOFF	010000000000
+ #define CRTSCTS	020000000000
  
  /* lflag bits */
  #define ISIG	0x0001
***************
*** 101,106 ****
--- 114,120 ----
  
  #define NCCS 		18
  
+ #define CBAUD	030017
  #define B0	000000
  #define B50	000001
  #define B75	000002
***************
*** 117,122 ****
--- 131,138 ----
  #define B9600	000015
  #define B19200	000016
  #define B38400	000017
+ #define B57600	010000
+ #define B115200	020000
  
  typedef unsigned char cc_t;
  typedef unsigned short tcflag_t;
***************
*** 139,144 ****
--- 155,179 ----
  #define cfgetispeed(tp)		((tp)->c_ispeed)
  #define cfsetospeed(tp,s)	(((tp)->c_ospeed = (s)), 0)
  #define cfsetispeed(tp,s)	(((tp)->c_ispeed = (s)), 0)
+ 
+ #ifdef NOTCODE
+ /* changes by MKA */
+ #ifdef __cplusplus
+ extern "C" {
+ #endif
+ 
+ int tcgetattr( int, struct termios * );
+ int tcsetattr( int, int, struct termios * );
+ int tcsendbreak( int, int );
+ int tcdrain( int );
+ int tcflush( int, int );
+ int tcflow( int, int );
+ 
+ #ifdef __cplusplus
+ }
+ #endif
+ #endif	/* NOTCODE */
+ 
  
  /* Extra stuff to make porting stuff easier.  */
  
*** winsup.sergey/termios.cc	Sat May 31 23:56:15 1997
--- winsup/termios.cc	Sun Jun 01 10:10:00 1997
***************
*** 23,67 ****
  #include "sys/termios.h"
  
  int
! tcsendbreak (int, int )
  {
!   syscall_printf ("tcsendbreak\n");
!   return 0;
  }
  
  int
! tcdrain (int)
  {
!   syscall_printf ("tcdrain\n");
!   return 0;
  }
  
  int
! tcflush (int fd, int queue)
  {
!   int res = 0;
  
!   if (NOT_OPEN_FD (fd))
!     {
!       set_errno ( EBADF);
!       res = -1;
!     }
!   else
!     {
!       res =  u->self->hmap[fd].h->tcflush (queue);
!     }
! 
!   syscall_printf ("%d = tcflush (%d, %d);\n", res, fd,queue);
!   return res;
  }
  
  int
! tcflow (int, int)
  {
!   syscall_printf ("tcflow\n");
!   return 0;
  }
  
  #if 0
  static void
  tdump (int)
--- 23,100 ----
  #include "sys/termios.h"
  
  int
! tcsendbreak( int fd, int duration )
  {
! 	int res = -1;
! 
! 	if( NOT_OPEN_FD( fd ) )
! 	{
! 		set_errno ( EBADF );
! 	}
! 	else
! 	{
! 		res = u->self->hmap[fd].h->tcsendbreak( duration );
! 	}
! 	syscall_printf( "%d = tcsendbreak( %d, %d );\n", res, fd, duration );
! 	return res;
  }
  
  int
! tcdrain( int fd )
  {
! 	int res = -1;
! 
! 	if( NOT_OPEN_FD( fd ) )
! 	{
! 		set_errno ( EBADF );
! 	}
! 	else
! 	{
! 		res = u->self->hmap[fd].h->tcdrain();
! 	}
! 
! 	syscall_printf( "%d = tcdrain( %d );\n", res, fd );
! 	return res;
  }
  
  int
! tcflush( int fd, int queue )
  {
! 	int res = -1;
  
! 	if( NOT_OPEN_FD( fd ) )
! 	{
! 		set_errno ( EBADF);
! 	}
! 	else
! 	{
! 		res = u->self->hmap[fd].h->tcflush( queue );
! 	}
! 	syscall_printf( "%d = tcflush( %d, %d );\n", res, fd, queue );
! 	return res;
  }
  
  int
! tcflow( int fd, int action )
  {
! 	int res = -1;
! 
! 	if( NOT_OPEN_FD( fd ) )
! 	{
! 		set_errno ( EBADF );
! 	}
! 	else
! 	{
! 		res = u->self->hmap[fd].h->tcflow( action );
! 	}
! 
! 	syscall_printf( "%d = tcflow( %d, %d );\n", res, fd, action );
! 	return res;
  }
  
+ 
+ 
+ 
  #if 0
  static void
  tdump (int)
***************
*** 112,150 ****
  #endif
  
  int
! tcsetattr (int fd, int a, const struct termios *t)
  {
!   int res = -1;
  
!   if (NOT_OPEN_FD (fd))
!     {
!       set_errno ( EBADF);
!     }
!   else
!     {
!       res =  u->self->hmap[fd].h->tcsetattr (a, t);
!     }
  
!   syscall_printf ("%d = tcsetattr (%d, %d, %x);\n", res, fd, a, t);
!   return res;
  }
  
  int
! tcgetattr (int fd, struct termios *t)
  {
!   int res = -1;
!   
!   if (NOT_OPEN_FD (fd))
!     {
!       set_errno ( EBADF);
!     }
!   else
!     {
!       res =  u->self->hmap[fd].h->tcgetattr (t);
!     }
  
!   syscall_printf ("%d = tcgetattr (%d, %x);\n", res, fd, t);
!   return res;
  }
  
  int
--- 145,183 ----
  #endif
  
  int
! tcsetattr( int fd, int a, const struct termios *t )
  {
! 	int res = -1;
  
! 	if( NOT_OPEN_FD( fd ) )
! 	{
! 		set_errno ( EBADF );
! 	}
! 	else
! 	{
! 		res = u->self->hmap[fd].h->tcsetattr( a, t );
! 	}
  
! 	syscall_printf( "%d = tcsetattr( %d, %d, %x );\n", res, fd, a, t );
! 	return res;
  }
  
  int
! tcgetattr( int fd, struct termios *t )
  {
! 	int res = -1;
! 
! 	if( NOT_OPEN_FD( fd ) )
! 	{
! 		set_errno( EBADF );
! 	}
! 	else
! 	{
! 		res = u->self->hmap[fd].h->tcgetattr( t );
! 	}
  
! 	syscall_printf( "%d = tcgetattr( %d, %x );\n", res, fd, t );
! 	return res;
  }
  
  int
/* fhandler.cc: winsup file handling
   see console.cc for fhandler_console functions

   Copyright 1996, 1997 Cygnus Solutions

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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */

#include <sys/termios.h>
#include <fcntl.h>
#include <unistd.h>
#include "winsup.h"

static const int CHUNK_SIZE=1024; /* Used for crlf conversions */

uid_t
get_file_owner (char *filename)
{
  static BOOL doit = TRUE;

  if (doit && is_nt())
    {
      char psd_buffer[1024];
      PSECURITY_DESCRIPTOR psd = (PSECURITY_DESCRIPTOR) psd_buffer;
      DWORD requested_length;
      PSID psid;
      BOOL bOwnerDefaulted = TRUE;

     if (!GetFileSecurity (filename, OWNER_SECURITY_INFORMATION,
			   psd, 1024, &requested_length))
       return getuid();

     if (!GetSecurityDescriptorOwner (psd, &psid, &bOwnerDefaulted))
       return getuid ();

     return psid ? get_id_from_sid(psid) : getuid();
   }

   return getuid();
}

gid_t
get_file_group (char *filename)
{
  static BOOL doit = TRUE;

  if (doit && is_nt ())
    {
      char psd_buffer[1024];
      PSECURITY_DESCRIPTOR psd = (PSECURITY_DESCRIPTOR) psd_buffer;
      DWORD requested_length;
      PSID psid;
      BOOL bGroupDefaulted = TRUE;

      /* obtain the file's group information */
      if (!GetFileSecurity (filename, GROUP_SECURITY_INFORMATION, psd,
			    1024, &requested_length))
        return getgid();

      /* extract the group sid from the security descriptor */
      if(!GetSecurityDescriptorGroup(psd, &psid, &bGroupDefaulted))
        return getgid ();

      return psid ? get_id_from_sid(psid) : getuid ();
    }

    return getgid ();
}

void
hinfo::clearout ()
{
  h = 0;
}

int
fhandler_make_pipe (int fildes[2])
{
  int  fdr, fdw;
  pinfo *p = this_procinfo ();
  fdr = p->hmap.find_unused_handle (0);
  if (fdr < 0) 
    set_errno (ENMFILE);
  else 
    {
      fdw = p->hmap.find_unused_handle (fdr+1);
      if (fdw < 0)
	set_errno ( ENMFILE);
      else
	{
	  SECURITY_ATTRIBUTES sa;

	  sa.nLength = sizeof (sa);
	  sa.lpSecurityDescriptor = 0;

	  /* When we fork we duplicate all the file handles to be inherited,
	     therefore all fds must be created as non-inheritable if we're the
	     parent.  We still set the close-on-exec flag to "no" though. */
	  /* FIXME: This comment is out of date.  Gee, what a surprise.  */

	  sa.bInheritHandle = 1;
	  HANDLE r, w;
	  if (CreatePipe (&r, &w, &sa, 0))
	    {
	      u->self->hmap.build_fhandler ("piper", fdr, r);
	      u->self->hmap.build_fhandler ("pipew", fdw, w);
	      
	      ((fhandler_base *) p->hmap[fdr].h)->init (r, 1, GENERIC_READ, "piper");
	      ((fhandler_base *) p->hmap[fdw].h)->init (w, 1, GENERIC_WRITE, "pipew");

	      fildes[0] = fdr;
	      fildes[1] = fdw;
	      
	      debug_printf ("0 = pipe (%d) (%d:%d, %d:%d)\n",
			    fildes, 
			    fdr, 
			    p->hmap[fdr].h->get_handle (),
			    fdw,
			    p->hmap[fdw].h->get_handle ());

	      return 0;
	    }
	  else
	    {
	      __seterrno ();
	    }
	}
    }
  
  syscall_printf ("-1 = pipe (0x%x)\n", fildes);
  return -1;
}

/**********************************************************************/
/* fhandler_base */

/* Record the file name.
   Filenames are used mostly for debugging messages, and it's hoped that
   in cases where the name is really required, the filename wouldn't ever

   be too long (e.g. devices or some such).
*/

void
fhandler_base::set_name (const char *p)
{
  if (unix_path_name_ != 0)
    {
      delete [] unix_path_name_;
    }

  if (p == 0)
    {
      unix_path_name_ = 0;
      return;
    }

  unix_path_name_ = new char [ strlen(p) + 1 ];
  if (unix_path_name_ == 0)
    {
      small_printf ("fhandler_base::set_name - fatal error. New failed\n");
      exit (ENOMEM);
    }
  strcpy (unix_path_name_, p);
}

/* Normal file i/o handlers.  */

/* Cover function to ReadFile to achieve (as much as possible) Posix style
   semantics and use of errno.  */
int
fhandler_base::raw_read (void *ptr, size_t ulen)
{
  DWORD bytes_read;
  int len = ulen;

  if (!ReadFile (get_handle(), ptr, len, &bytes_read, 0))
    {
      int errcode;

      /* Some errors are not really errors.  Detect such cases here.  */

      errcode = GetLastError ();
      switch (errcode)
	{
	case ERROR_BROKEN_PIPE:
	  /* This is really EOF.  */
	  bytes_read = 0;
	  break;
	case ERROR_MORE_DATA:
	  /* `bytes_read' is supposedly valid.  */
	  break;
	default:
	  syscall_printf ("ReadFile %s failed\n", unix_path_name_);
	  set_errno (EACCES);
	  return -1;
	  break;
	}
    }

  return bytes_read;
}

int
fhandler_base::linearize (unsigned char *buf)
{
  int len = (sizeof (access_) + sizeof (handle_) + sizeof (w_binary_) +
            sizeof (r_binary_) + sizeof (close_exec_p_) +
            sizeof (readahead_valid_) + sizeof (readahead_) +
            sizeof (append_p_) + sizeof (rpos_) + sizeof (rsize_) +
            sizeof (had_eof_) + sizeof (symlink_p_) + sizeof (execable_p_) +
            sizeof (namehash_));
  
  if (buf == 0)
    return len;

  memcpy (buf, (char *) &access_, sizeof (access_));
  buf += sizeof (access_);
  memcpy (buf, (char *) &handle_, sizeof (handle_));
  buf += sizeof (handle_);
  memcpy (buf, (char *) &w_binary_, sizeof (w_binary_));
  buf += sizeof (w_binary_);
  memcpy (buf, (char *) &r_binary_, sizeof (r_binary_));
  buf += sizeof (r_binary_);
  memcpy (buf, (char *) &close_exec_p_, sizeof (close_exec_p_));
  buf += sizeof (close_exec_p_);
  memcpy (buf, (char *) &readahead_valid_, sizeof (readahead_valid_));
  buf += sizeof (readahead_valid_);
  memcpy (buf, (char *) &readahead_, sizeof (readahead_));
  buf += sizeof (readahead_);
  memcpy (buf, (char *) &append_p_, sizeof (append_p_));
  buf += sizeof (append_p_);
  memcpy (buf, (char *) &rpos_, sizeof (rpos_));
  buf += sizeof (rpos_);
  memcpy (buf, (char *) &rsize_, sizeof (rsize_));
  buf += sizeof (rsize_);
  memcpy (buf, (char *) &had_eof_, sizeof (had_eof_));
  buf += sizeof (had_eof_);
  memcpy (buf, (char *) &symlink_p_, sizeof (symlink_p_));
  buf += sizeof (symlink_p_);
  memcpy (buf, (char *) &execable_p_, sizeof (execable_p_));
  buf += sizeof (execable_p_);
  memcpy (buf, (char *) &namehash_, sizeof (namehash_));
  buf += sizeof (namehash_);
  
  return len;
}

int
fhandler_base::de_linearize (const unsigned char *buf)
{
  const unsigned char *orig_buf = buf;

  memcpy ((char *) &access_, buf, sizeof (access_));
  buf += sizeof (access_);
  memcpy ((char *) &handle_, buf, sizeof (handle_));
  buf += sizeof (handle_);
  memcpy ((char *) &w_binary_, buf, sizeof (w_binary_));
  buf += sizeof (w_binary_);
  memcpy ((char *) &r_binary_, buf, sizeof (r_binary_));
  buf += sizeof (r_binary_);
  memcpy ((char *) &close_exec_p_, buf, sizeof (close_exec_p_));
  buf += sizeof (close_exec_p_);
  memcpy ((char *) &readahead_valid_, buf, sizeof (readahead_valid_));
  buf += sizeof (readahead_valid_);
  memcpy ((char *) &readahead_, buf, sizeof (readahead_));
  buf += sizeof (readahead_);
  memcpy ((char *) &append_p_, buf, sizeof (append_p_));
  buf += sizeof (append_p_);
  memcpy ((char *) &rpos_, buf, sizeof (rpos_));
  buf += sizeof (rpos_);
  memcpy ((char *) &rsize_, buf, sizeof (rsize_));
  buf += sizeof (rsize_);
  memcpy ((char *) &had_eof_, buf, sizeof (had_eof_));
  buf += sizeof (had_eof_);
  memcpy ((char *) &symlink_p_, buf, sizeof (symlink_p_));
  buf += sizeof (symlink_p_);
  memcpy ((char *) &execable_p_, buf, sizeof (execable_p_));
  buf += sizeof (execable_p_);
  memcpy ((char *) &namehash_, buf, sizeof (namehash_));
  buf += sizeof (namehash_);
  
  return buf - orig_buf;
}

/* Cover function to WriteFile to provide Posix interface and semantics
   (as much as possible).  */
int
fhandler_base::raw_write (const void *ptr, size_t len)
{
  DWORD bytes_written;

  if (!WriteFile (get_handle(), ptr, len, &bytes_written, 0))
    {
      __seterrno ();
      if (get_errno () == EPIPE)
        raise (SIGPIPE);
      return -1;
    }
  return bytes_written;
}

/* Open system call handler function. 
Path is now already checked for symlinks*/
fhandler_base * 
fhandler_base::open (const char *path, int flags, mode_t mode)
{
  fhandler_base * res = NULL;
  HANDLE x;
  int file_attributes;
  int shared;
  SECURITY_ATTRIBUTES sa;
  int creation_distribution;

  syscall_printf ("fhandler_base::open (%s, 0x%x)\n", path, flags);

  path_conv win32_path (path, -1);
  if (win32_path.error)
    {
      set_errno (win32_path.error);
      goto done;
    }

  if ((flags & (O_RDONLY | O_WRONLY | O_RDWR)) == O_RDONLY)
    {
      access_ = GENERIC_READ;
    }
  else if ((flags & (O_RDONLY | O_WRONLY | O_RDWR)) == O_WRONLY)
    {
      access_ = GENERIC_WRITE;
    }
  else
    {
      access_ = GENERIC_READ | GENERIC_WRITE;
    }

  /* FIXME: O_EXCL handling?  */

  if ((flags & O_TRUNC) && ((flags & O_ACCMODE) != O_RDONLY))
    {
      if (flags & O_CREAT)
        {
          creation_distribution = CREATE_ALWAYS;
        }
      else
        {
          creation_distribution = TRUNCATE_EXISTING;
        }
    }
  else
    {
      if (flags & O_CREAT)
        {
          creation_distribution = OPEN_ALWAYS;
        }
      else
        {
          creation_distribution = OPEN_EXISTING;
        }
    }

  if ((flags & O_EXCL) && (flags & O_CREAT))
    {
      creation_distribution = CREATE_NEW;
    }

  if (flags & O_APPEND) 
    {
      append_p_ = 1;
    }

  /* FILE_SHARE_DELETE is only supported under NT */
  if (windows_95 ())
    shared = FILE_SHARE_READ | FILE_SHARE_WRITE;
  else
    shared = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;

  sa.nLength = sizeof (sa);
  sa.lpSecurityDescriptor = 0;

  sa.bInheritHandle = TRUE;
  file_attributes = FILE_ATTRIBUTE_NORMAL;

  x = CreateFileA (win32_path.get_win32 (), access_, shared,
		   &sa, creation_distribution,
		   file_attributes,
		   0);

  syscall_printf ("%d = CreateFileA (%s, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0)\n",
		  x,
		  win32_path.get_win32 (), access_, shared,
		  &sa, creation_distribution,
		  file_attributes);
	
  if (x == INVALID_HANDLE_VALUE)
    {
      if (GetLastError () == ERROR_INVALID_HANDLE)
	set_errno (ENOENT);
      else
	__seterrno ();
      goto done;
    }

  if (flags & O_CREAT)
    {
      set_file_attribute (win32_path.get_win32 (), mode);
    }
  set_name (path);
  namehash_ = hash_path_name (path);
  set_handle(x);
  readahead_valid_ = 0;
  set_close_on_exec(0);
  symlink_p_ = 0;
  execable_p_ = 0;
  rpos_ = 0;
  had_eof_ = 0;
  rsize_ = -1;

  if (win32_path.binary_p || (flags & O_BINARY))
    {
      set_r_binary (1);
      set_w_binary (1);
    }
  else if (flags & O_TEXT)
    {
      set_r_binary (0);
      set_w_binary (0);
    }
  else if (u->fmode_ptr && (*(u->fmode_ptr) & O_BINARY))
    {
      set_r_binary (1);
      set_w_binary (1);
      syscall_printf ("filemode defaulting to binary.\n");
    }
  else 
    {
      set_r_binary (0);
      set_w_binary (0);
      syscall_printf ("filemode defaulting to text.\n");
    }

  if (flags & O_APPEND)
    SetFilePointer (get_handle(), 0, 0, FILE_END);
  else
    SetFilePointer (get_handle(), 0, 0, FILE_BEGIN);

  res = this;
done:
  syscall_printf ("%p = fhandler_base::open (%s, 0x%x)\n", res, path, flags);
  return res;
}

/* states:
   open buffer in binary mode?  Just do the read.  

   open buffer in text mode?  Scan buffer for control zs and handle
   the first one found.  Then scan buffer, converting every \r\n into
   an \n.  If last char is an \r, look ahead one more char, if \n then
   modify \r, if not, remember char.  
*/
int
fhandler_base::read (void *ptr, size_t ulen)
{
  int len = ulen;
  char *ctrlzpos;
  int i;

  if (len == 0)
    return 0;

  if (get_r_binary ())
    {
      int l = raw_read (ptr, len);
      if (l <= 0)
	return l;
      rpos_ += l;
      return l;
    }

  int chars_to_process;
  /* We're in text mode */
  if (readahead_valid_)
    {
      /* We have one character to consume from the last read. */
      readahead_valid_ = 0;
      ((char *)ptr)[0] = readahead_;
      chars_to_process = raw_read (&(((char *)ptr)[1]), len-1);
      if (chars_to_process < 0)
        return chars_to_process;
      else if(chars_to_process == 0)
	{
	/* Even if raw_read returned 0 we still have the 
	  readahead char to process */
	  chars_to_process = 1; 
	}
      else
	{
	  /* We must increment chars_to_process
          as we already had the readahead char */
          chars_to_process += 1;
        }
    }
  else
    {
      chars_to_process = raw_read (ptr, len);
      if (chars_to_process <= 0)
        return chars_to_process;
    }

  /* If the first character is a control-z we're at virtual EOF.  */
  if ( ((char *)ptr)[0] == 0x1a )
    {
      return 0;
    }

  /* Scan buffer for a control-z and shorten the buffer to that length */

  ctrlzpos = (char *)memchr ((char *)ptr, 0x1a, chars_to_process);
  if (ctrlzpos)
    {	
      lseek ( (ctrlzpos - ((char *)ptr + chars_to_process)), SEEK_CUR);
      chars_to_process = ctrlzpos - (char *)ptr;
    }

  /* Scan buffer and turn \r\n into \n */
  register char *src= (char *)ptr;
  register char *dst = (char *)ptr;
  register char *end = src + chars_to_process - 1;

  /* Read up to the last but one char - the last char needs special handling */
  while (src < end)
    {
      if (src[0] == '\r' && (src[1] == '\n' || src[1] == '\r'))
	{
	  /* Ignore this. */
	  src++;
	}
      else
	{
	  *dst++ = *src++;
	}
    }

  /* if last char is a '\r' then read one more to see if we should
     translate this one too */
  if (*src == '\r')
    {
      int len;
      char c;
      len = raw_read (&c, 1);
      if (len > 0)
	{
	  if (c == '\n')
	    {
	      *dst++ = '\n';
	    }
	  else
	    {
	      readahead_valid_ = 1;
	      readahead_ = c;
	    }
	}
    }
  else
    {
      *dst++ = *src;
    }

  chars_to_process = dst - (char *)ptr;

  rpos_ += chars_to_process;

  if (u->strace_mask & (_STRACE_DEBUG | _STRACE_ALL))
    {
      char buf[16 * 6 + 1];
      char *p = buf;

      for (int i = 0; i < chars_to_process && i < 16; ++i)
	{
	  unsigned char c = ((unsigned char *) ptr)[i];
	  /* >= 33 so space prints in hex */
	  __small_sprintf (p, c >= 33 && c <= 127 ? " %c" : " 0x%x", c);
	  p += strlen (p);
	}
      debug_printf ("read %d bytes (%s%s)\n", chars_to_process, buf, chars_to_process > 16 ? " ..." : "");
    }

  return chars_to_process;
}

int
fhandler_base::write (const void *ptr, size_t len)
{
  int res;

  if (append_p_)
    SetFilePointer (get_handle(), 0, 0, FILE_END);

  if (get_w_binary ())
    {
      res = raw_write (ptr, len);
    }
  else
    {
      /* Keep track of previous \rs, we don't want to turn existing
	 \r\n's into \r\n\n's */
      register int pr = 0;

      /* Copy things in chunks */
      char buf[CHUNK_SIZE];

      for (unsigned int i  = 0; i < len; i += sizeof (buf)/2 )
	{
	  register const char *src = (char *)ptr + i;
	  int todo = MIN(len - i, sizeof (buf) /2);
	  register const char *end = src + todo;
	  register char *dst = buf;
	  while (src < end)
	    {
	      if (*src == '\n' && !pr)
		{
		  /* Emit a cr lf here */
		  *dst ++ = '\r';
		  *dst ++ = '\n';
		}
	      else if (*src == '\r')
		{
		  *dst ++ = '\r';
		  pr = 1;
		}
	      else 
		{
		  *dst ++ = *src;
		  pr = 0;
		}
	      src++;
	    }
	  int want = dst-buf;
	  if ((res = raw_write (buf, want)) != want)
	    {
              if (res == -1)
                return -1;
	      /* Tricky... Didn't write everything we wanted.. How can
		 we work out exactly which chars were sent ?  We don't...
		 This will only happen in pretty nasty circumstances. */
	      rpos_ += i;
	      return i;
	    }
	}
      /* Done everything, update by the chars that the user sent */
      rpos_ += len;
      /* Length of file has changed */
      rsize_ = -1;
      res = len;
      debug_printf ("after write, name %s, rpos %d\n", unix_path_name_, rpos_);
    }
  return res;
}

off_t
fhandler_base::lseek (off_t offset, int whence)
{
  off_t res;

  /* Seeks on text files is tough, we rewind and read till we get to the
     right place.  */

  readahead_valid_ = 0;

  debug_printf ("lseek (%s, %d, %d)\n", unix_path_name_, offset, whence);

#if 0	/* lseek has no business messing about with text-mode stuff */

  if (!get_r_binary ())
    {
      int newplace;

      if (whence == 0)
	{
	  newplace = offset;
	}
      else if (whence ==1)
	{
	  newplace = rpos +  offset;
	}
      else 
	{
	  /* Seek from the end of a file.. */
	  if (rsize == -1)
	    {
	      /* Find the size of the file by reading till the end */
	      
	      char b[CHUNK_SIZE];
	      while (read (b, sizeof (b)) > 0)
		;
	      rsize = rpos;
	    }
	  newplace = rsize + offset;
	}

      if (rpos > newplace)
	{
	  SetFilePointer (handle, 0, 0, 0);
	  rpos = 0;
	}

      /* You can never shrink something more than 50% by turning CRLF into LF,
	 so we binary chop looking for the right place */

      while (rpos < newplace)
	{
	  char b[CHUNK_SIZE];
	  size_t span = (newplace - rpos) / 2;
	  if (span == 0)
	    span = 1;
	  if (span > sizeof (b))
	    span = sizeof (b);

	  debug_printf ("lseek (%s, %d, %d) span %d, rpos %d newplace %d\n",
		       name, offset, whence,span,rpos, newplace);
	  read (b, span);
	}

      debug_printf ("Returning %d\n", newplace);
      return newplace;
    }
#endif	/* end of deleted code dealing with text mode */

  DWORD win32_whence = whence == SEEK_SET ? FILE_BEGIN
                       : (whence == SEEK_CUR ? FILE_CURRENT : FILE_END);

  res = SetFilePointer (get_handle(), offset, 0, win32_whence);

  if (res == -1)
    {
      __seterrno ();
    }
  return res;
}

int
fhandler_base::close ()
{
  int res = -1;

  syscall_printf ("fhandler_base::close (handle %d)\n",get_handle());

  /* int type = GetFileType (handle);*/
  int type = 0;

  /* Can't really close these things, but pretend we did. */
  if (type == FILE_TYPE_CHAR && 0)
    res = 0;
  else 
    {
      if (!CloseHandle (get_handle()))
	{
	  paranoid_printf ("CloseHandle (%d <%s>) failed\n", get_handle(), unix_path_name_);

	  __seterrno ();
	}
      else
	{
	  if (type == FILE_TYPE_DISK)
	    process_deletion_queue ();
	  res = 0;
	  set_handle((HANDLE)-99);
	}
    }
  return res;
}

int
fhandler_base::ioctl (int cmd, void *buf)
{
  if (cmd == FIONBIO)
    {
      syscall_printf ("fhandler.cc: ioctl (FIONBIO,%x)\n",buf);
    }
  else
    {
      syscall_printf ("fhandler.cc: ioctl (%x,%x)\n", cmd, buf);
    }

  set_errno (EINVAL);
  return -1;
}

int
fhandler_base::lock(int, struct flock *)
{
  set_errno (ENOSYS);
  return -1;
}

int
fhandler_base::fstat (struct stat *buf)
{
  int res;
  BY_HANDLE_FILE_INFORMATION local;

  memset (buf, 0, sizeof (*buf));

  res = GetFileInformationByHandle (get_handle(), &local);
  debug_printf ("%d = GetFileInformationByHandle (%s, %d)\n",
		res, unix_path_name_, get_handle());
  if (res == 0)
    {
      /* GetFileInformationByHandle will fail if it's given stdin/out/err 
	 or a pipe*/
      if (1)
	{
	  /* We expect these to fail! */
	  buf->st_mode |= S_IFCHR;
	  buf->st_blksize = S_BLKSIZE;
	  buf->st_ino = namehash_;
	  syscall_printf ("0 = fstat (, 0x%x)\n",  buf);
	  return 0;
	}
      else
	{
	  __seterrno ();
	  syscall_printf ("-1 = fstat (, 0x%x)\n",  buf);
	  return -1;
	}
    }

  path_conv win32_path (get_name (), -1);

  if (win32_path.error)
    {
      set_errno (win32_path.error);
      return -1;
    }
  set_errno (0);

  buf->st_atime   = to_time_t (&local.ftLastAccessTime);
  buf->st_mtime   = to_time_t (&local.ftLastWriteTime);
  buf->st_ctime   = to_time_t (&local.ftCreationTime);
  buf->st_nlink   = local.nNumberOfLinks;
  buf->st_dev     = local.dwVolumeSerialNumber;
  buf->st_size    = local.nFileSizeLow;
  buf->st_ino     = local.nFileIndexLow ^ namehash_;
  buf->st_blksize = S_BLKSIZE;
  buf->st_blocks  = (buf->st_size + S_BLKSIZE-1) / S_BLKSIZE;
  buf->st_uid     = get_file_owner (win32_path.get_win32 ());
  buf->st_gid     = get_file_group (win32_path.get_win32 ());
  if(get_file_attribute (win32_path.get_win32 (), (int *) &buf->st_mode) > 0)
    {
      buf->st_mode &= ~S_IFMT;
      if (symlink_p_)
        buf->st_mode |= S_IFLNK;
      else
        buf->st_mode |= S_IFREG;
    }
  else
    {
      buf->st_mode = 0;
      buf->st_mode |= STD_RBITS;
  
      if (! (local.dwFileAttributes & FILE_ATTRIBUTE_READONLY))
        buf->st_mode |= STD_WBITS;	
      /* | S_IWGRP | S_IWOTH; we don't give write to group etc */

      if (symlink_p_)
        buf->st_mode |= S_IFLNK;
      else
        switch (GetFileType (get_handle()))
          {
          case FILE_TYPE_CHAR:
          case FILE_TYPE_UNKNOWN:
	    buf->st_mode |= S_IFCHR;
	    break;
          case FILE_TYPE_DISK:
	    buf->st_mode |= S_IFREG;
	    if (execable_p_)
	      buf->st_mode |= STD_XBITS;
	    break;
          case FILE_TYPE_PIPE:
	    buf->st_mode |= S_IFSOCK;
	    break;
          }
    }

  syscall_printf ("0 = fstat (, 0x%x) st_atime=%x st_size=%d, st_mode=0x%x, st_ino=%d, sizeof=%d\n",
		 buf, buf->st_atime, buf->st_size, buf->st_mode, 
		 (int) buf->st_ino, sizeof (*buf));

  return 0;
}

void
fhandler_base::init (HANDLE f, int bin, int a, const char *n)
{
  set_handle (f);
  set_r_binary (bin);
  set_w_binary (bin);
  access_ = a;
  set_name (n);
  debug_printf ("created new fhandler_base for <%s> with handle %d\n", n, f);
}

void
fhandler_base::dump ()
{
  paranoid_printf ( "FHANDLER BASE\n");
}

void
fhandler_base::set_handle (HANDLE x)
{
  debug_printf ("set handle to %d\n", x);
  handle_ = x;
}

int
fhandler_base::dup (fhandler_base *child)
{
  debug_printf ("in fhandler_base dup\n");

  child->set_close_on_exec(0);

  const HANDLE proc = GetCurrentProcess ();
  HANDLE nh;
  if (!DuplicateHandle (proc, get_handle(), proc, &nh, 0, 1, DUPLICATE_SAME_ACCESS))
    {
      small_printf ("COPY FOR DUP FAILED, handle in %x %x!!\n", get_handle(), GetLastError ());
      __seterrno();
      return -1;
    }

  child->set_handle(nh);
  return 0;
}

/*
 * normal I/O constructor.
 */

fhandler_base::fhandler_base ( const char *name )
{
  w_binary_ = 0;
  r_binary_ = 0;
  close_exec_p_ = 0;
  handle_ = 0; 
  access_ = 0; 
  readahead_valid_ = 0; 
  readahead_ = 0; 
  append_p_ = 0;
  rpos_ = 0;
  rsize_ = 0;
  had_eof_ = 0;
  symlink_p_ = 0;
  namehash_ = 0;
  execable_p_ = 0;
  unix_path_name_ = 0;
  set_name(name);
}

/*
 * Normal I/O destructor.
 */

fhandler_base::~fhandler_base ()
{
  delete [] unix_path_name_;
}

/**********************************************************************/
/* fhandler_disk_file */

fhandler_disk_file::fhandler_disk_file (const char *name) : fhandler_base(name)
{
}

fhandler_base *
fhandler_disk_file::open (const char *path, int flags, mode_t mode)
{
  fhandler_base * res = NULL;
  int exec_p = 0;
  int syml_p = 0;
  char real_path[MAX_PATH];

  syscall_printf ("fhandler_disk_file::open (%s, 0x%x)\n", path, flags);

  /* O_NOSYMLINK is an internal flag for implementing lstat, nothing more. */
  if (flags & O_NOSYMLINK)
    {
      int len = symlink_check (path, NULL, 0, &syml_p, &exec_p);
      if (len == -1)
	{
	  syscall_printf ("%p = fhandler_disk_file::open (%s, 0x%x)\n",
							res, path, flags);
	  return res;
        }
      strcpy (real_path, path);
    }
  else
    {
      int rc = symlink_follow (path, real_path, &exec_p);
      /* OK if file doesn't exist but the caller passed O_CREAT */
      if (rc == -1 && (get_errno () != ENOENT || (flags & O_CREAT) == 0))
        {
	  syscall_printf ("%p = fhandler_disk_file::open (%s, 0x%x)\n",
							res, path, flags);
	  return res;
	}
      syml_p = 0;
    }

  /* If necessary, do various other things to see if PATH is a program.  */
  if (!exec_p)
    exec_p = check_execable_p (real_path);

  res = this->fhandler_base::open (real_path, flags, mode);

  symlink_p_ = syml_p;
  execable_p_ = exec_p;

  syscall_printf ("%p = fhandler_disk_file::open (%s, 0x%x)\n", res, path, flags);
  return res;
}

/*
 * FIXME !!!
 * The correct way to do this to get POSIX locking
 * semantics is to keep a linked list of posix lock
 * requests and map them into Win32 locks. The problem
 * is that Win32 does not deal correctly with overlapping
 * lock requests. Also another pain is that Win95 doesn't do
 * non-blocking or non exclusive locks at all. For '95 just
 * convert all lock requests into blocking,exclusive locks.
 * This shouldn't break many apps but denying all locking
 * would.
 * For now just convert to Win32 locks and hope for the best.
 */

int
fhandler_disk_file::lock (int cmd, struct flock *fl)
{
  DWORD win32_start;
  DWORD win32_len;
  DWORD win32_upper;
  DWORD startpos;

  /*
   * We don't do getlck calls yet.
   */

  if (cmd == F_GETLK)
    {
      set_errno (ENOSYS);
      return -1;
    }

  /* 
   * Calculate where in the file to start from,
   * then adjust this by fl->l_start.
   */

  switch (fl->l_whence)
    {
      case SEEK_SET:
        startpos = 0;
        break;
      case SEEK_CUR:
        if ((startpos = lseek (0, SEEK_CUR)) < 0)
          return -1;
        break;
      case SEEK_END:
        {
          BY_HANDLE_FILE_INFORMATION finfo;
          if (GetFileInformationByHandle (get_handle(), &finfo) == 0)
            { 
              __seterrno ();
              return -1;
            }
          startpos = finfo.nFileSizeLow; /* Nowhere to keep high word */
          break;
        }
    }

  /* 
   * Now the fun starts. Adjust the start and length
   *  fields until they make sense.
   */

  win32_start = startpos + fl->l_start;
  if (fl->l_len < 0)
    {
      win32_start -= fl->l_len;
      win32_len = -fl->l_len;
    }
  else
    win32_len = fl->l_len;

  if (win32_start < 0)
    {
      win32_len -= win32_start;
      if (win32_len <= 0)
        {
          /* Failure ! */
          set_errno (EINVAL);
          return -1;
        }
      win32_start = 0;
    }

  /*
   * Special case if len == 0 for POSIX means lock
   * to the end of the entire file (and all future extensions).
   */
  if (win32_len == 0)
    {
      win32_len = 0xffffffff;
      win32_upper = 0xffffffff;
    }
  else
    win32_upper = 0;

  BOOL res;
  /*
   * Win95 only supportes primitive lock call.
   */

  if (windows_95 ())
    {
      if (fl->l_type == F_UNLCK)
        res = UnlockFile (get_handle (), win32_start, 0, win32_len,
							win32_upper);
      else
        res = LockFile (get_handle (), win32_start, 0, win32_len, win32_upper);
    }
  else
    {
      /* Windows NT */
      DWORD lock_flags = (cmd == F_SETLK) ? LOCKFILE_FAIL_IMMEDIATELY : 0;
      lock_flags |= (fl->l_type == F_WRLCK) ? LOCKFILE_EXCLUSIVE_LOCK : 0;

      OVERLAPPED ov;

      ov.Internal = 0;
      ov.InternalHigh = 0;
      ov.Offset = win32_start;
      ov.OffsetHigh = 0;
      ov.hEvent = (HANDLE)0;

      if (fl->l_type == F_UNLCK)
        res = UnlockFileEx (get_handle (), 0, win32_len, win32_upper, &ov);
      else
        {
          res = LockFileEx (get_handle (), lock_flags, 0, win32_len,
							win32_upper, &ov);
          /* Deal with the fail immediately case. */
          /*
           * FIXME !! I think this is the right error to check for
           * but I must admit I haven't checked....
           */
          if ((res == 0) && (lock_flags & LOCKFILE_FAIL_IMMEDIATELY) &&
                            (GetLastError() == ERROR_LOCK_FAILED))
            {
              set_errno (EAGAIN);
              return -1;
            }
        }
    }

  if (res == 0)
    {
      __seterrno ();
      return -1;
    }
  return 0;
}

/* Perform various heuristics on PATH to see if it's a program. */

int
fhandler_disk_file::check_execable_p (const char *path)
{
  int len = strlen (path);
  const char *ch = path + (len > 4 ? len - 4 : len);

  if (strcasecmp (".bat", ch) == 0
      || strcasecmp (".exe", ch) == 0
      || strcasecmp (".com", ch) == 0)
    return 1;

  return 0;
}

/**********************************************************************/
/* fhandler_tty */

fhandler_tty::fhandler_tty (const char *name) : fhandler_base (name)
{
  vmin_ = 0;
  vtime_ = 0;
}

int 
fhandler_tty::linearize (unsigned char *buf)
{
  int len = sizeof (vmin_) + sizeof (vtime_);
  if (buf == 0)
    {
      len += this->fhandler_base::linearize (buf);
      return len;
    }

  memcpy (buf, (char *) &vmin_, sizeof (vmin_));
  buf += sizeof (vmin_);
  memcpy (buf, (char *) &vtime_, sizeof (vtime_));
  buf += sizeof (vtime_);
 
  len += this->fhandler_base::linearize (buf);
  return len;
}
 
int
fhandler_tty::de_linearize (const unsigned char *buf)
{
  const unsigned char *orig_buf = buf;

  memcpy ((char *) &vmin_, buf, sizeof (vmin_));
  buf += sizeof (vmin_);
  memcpy ((char *) &vtime_, buf, sizeof (vtime_));
  buf += sizeof (vtime_);

  int len = buf - orig_buf;
  return (len + this->fhandler_base::de_linearize (buf));
}
 
int
fhandler_tty::raw_read (void *ptr, size_t ulen)
{
  if (vtime_ || vmin_)
    {
      if (vmin_ == 0)
	ulen = 1;
      else if (vmin_ < ulen)
	ulen = vmin_;
      syscall_printf ("timeout len %d\n", ulen);
    }
  return fhandler_base::raw_read (ptr, ulen);
}

void
fhandler_tty::dump ()
{
  paranoid_printf ("FHANDLER TTY\n");
}





fhandler_base * 
fhandler_tty::open( const char *path, int flags, mode_t mode )
{
	fhandler_base *res = NULL;
	int temp = 0;
	int access;
	HANDLE myhandle;
	COMMTIMEOUTS to;

	syscall_printf( "fhandler_tty::open( %s, 0x%x, 0x%x )\n",
			path, flags, mode );

	if( (res = fhandler_base::open( path, flags, mode ) ) == NULL )
			return( NULL );

	memset( &to, 0, sizeof(to) );

	myhandle = fhandler_base::get_handle();
	access = fhandler_base::get_access();
	temp |= (access & (GENERIC_READ | GENERIC_WRITE));

	if( flags & O_NDELAY )	/* non-blocking I/O */
	{
		temp |= _FNDELAY;

		/* probably not necessary */
		if( GetCommTimeouts( myhandle, &to ) == 0 )
		{
			small_printf ("GetCommTimeout failed\n");
			__seterrno ();
			return( NULL );
		}

		to.ReadIntervalTimeout = MAXDWORD;
		to.ReadTotalTimeoutMultiplier = 0;
		to.ReadTotalTimeoutConstant = 0;

		/* leave the values vmin_ and vtime_ alone for restoral later */

		if( SetCommTimeouts( myhandle, &to ) == 0 )
		{
			small_printf ("SetCommTimeout failed\n");
			__seterrno ();
			return( NULL );
		}

	}	/* non-blocking I/O */
	else
	{	/* blocking I/O */

		/* if non-blocking is set, unset it */
		if( access & _FNDELAY )
		{
			/* probably not necessary */
			/*
				if( GetCommTimeouts( myhandle, &to ) == 0 )
				{
					small_printf ("GetCommTimeout failed\n");
					__seterrno ();
					return( NULL );
				}

				we have no access to vtime_ or vmin_
				to.ReadIntervalTimeout = 0;
				to.ReadTotalTimeoutMultiplier = 0;
				to.ReadTotalTimeoutConstant = vtime_ * 100;
			*/

			if( SetCommTimeouts( myhandle, &to ) == 0 )
			{
				small_printf ("SetCommTimeout failed\n");
				__seterrno ();
				return( NULL );
			}
		}	/* if non-blocking is set */
	}	/* blocking I/O */

	fhandler_base::set_access( temp );

	syscall_printf( "%p = fhandler_tty::open( %s, 0x%x, 0x%x )\n",
			res, path, flags, mode );
	return res;
}	/* tty open() */





int
fhandler_tty::fstat (struct stat *buf)
{
  memset (buf, 0, sizeof (*buf));
  buf->st_mode |= S_IFCHR;
  buf->st_blksize = S_BLKSIZE;
  buf->st_uid     = getuid ();
  buf->st_gid     = getgid ();
  buf->st_mode |= STD_RBITS | STD_WBITS;
  buf->st_ino = get_namehash();
  syscall_printf ("0 = fhandler_tty:fstat (%x) (mode %x)\n",
		  buf, buf->st_mode);
  return 0;
}





int
fhandler_tty::tcsendbreak( int duration )
{
	unsigned int sleeptime = 350;
	if( duration > 1 )
		sleeptime *= duration;
	

	if( SetCommBreak( get_handle() ) == 0 )
		return( -1 );
	usleep( sleeptime );
	if( ClearCommBreak( get_handle() ) == 0 )
		return( -1 );
	return( 0 );
}




int
fhandler_tty::tcdrain( void )
{
	if( FlushFileBuffers( get_handle() ) == 0 )
		return( -1 );
	return( 0 );
}




int
fhandler_tty::tcflow( int action )
{
	DCB dcb;
	DWORD winaction = 0;
	char xchar;

	switch( action )
	{
		case TCOOFF:
						winaction = SETXOFF;
						break;
		case TCOON:
						winaction = SETXON;
						break;
		case TCION:
		case TCIOFF:
						if( GetCommState( get_handle(), &dcb ) == 0 )
							return( -1 );
						if( action == TCION )
							xchar = (dcb.XonChar ? dcb.XonChar : 0x11);
						else
							xchar = (dcb.XoffChar ? dcb.XoffChar : 0x13);
						if( TransmitCommChar( get_handle(), xchar ) == 0 )
							return( -1 );
						return( 0 );
						break;
		default:
						return( -1 );
						break;
	}

	if( EscapeCommFunction( get_handle(), winaction ) == 0 )
		return( -1 );
	return( 0 );
}





int
fhandler_tty::tcflush (int queue)
{
  if (queue & (TCOFLUSH | TCIOFLUSH))
    {
      PurgeComm (get_handle(), PURGE_TXABORT | PURGE_TXCLEAR);
    }

  if (queue & (TCIFLUSH | TCIOFLUSH))
    {
      /* Input flushing by polling until nothing turns up
	 (we stop after 1000 chars anyway) */
      COMMTIMEOUTS old;
      COMMTIMEOUTS tmp;
      char b;
      DWORD more = 1;
      int max = 1000;
      PurgeComm (get_handle(), PURGE_RXABORT | PURGE_RXCLEAR);
      GetCommTimeouts (get_handle(), &old);
      memset (&tmp, 0, sizeof (tmp));
      tmp.ReadTotalTimeoutConstant = 100;
      SetCommTimeouts (get_handle(), &tmp);
      while (max > 0 && more)
	{
	  ReadFile (get_handle(), &b, 1,  &more,  0);
	  if (more) 
	    {
	      termios_printf ("dropping %d\n", b);
	    }
	  max--;
	}
      SetCommTimeouts (get_handle(), &old);
    }
  return 0;
}






int
fhandler_tty::tcsetattr( int action, const struct termios *t )
{

	/* possible actions are:
		TCSANOW - do the change immediately.
		TCSADRAIN - change after flushing output.
		TCSAFLUSH - change after flushing output and discarding input.
	*/

	BOOL dropDTR = FALSE;
	COMMTIMEOUTS to;
	DCB state;

	if( (action == TCSADRAIN) || (action == TCSAFLUSH) )
		FlushFileBuffers( get_handle() );
	if( action == TCSAFLUSH )
		PurgeComm( get_handle(), (PURGE_RXABORT | PURGE_RXCLEAR) );


	/* get default/last comm state */
	GetCommState (get_handle (), &state);
#if 0
	ds ("First in tcsetattr", &state);
#endif



	/* *********** baud rate *********** */
	switch (t->c_ospeed)
	{
		case B0:
					/* drop DTR */
					dropDTR = TRUE;
					state.BaudRate = 0;
					break;
		case B110:
					state.BaudRate = CBR_110;
					break;
		case B300:
					state.BaudRate = CBR_300;
					break;
		case B600:
					state.BaudRate = CBR_600;
					break;
		case B1200:
					state.BaudRate = CBR_1200;
					break;
		case B2400:
					state.BaudRate = CBR_2400;
					break;
		case B4800:
					state.BaudRate = CBR_4800;
					break;
		case B9600:
					state.BaudRate = CBR_9600;
					break;
		case B19200:
					state.BaudRate = CBR_19200;
					break;
		case B38400:
					state.BaudRate = CBR_38400;
					break;
		/*
		case B57600:
					state.BaudRate = CBR_57600;
					break;
		case B115200:
					state.BaudRate = CBR_115200;
					break;
		*/
		/* WIN32 also has 14400, 56000, 128000, and 256000 */
		/* Unix also has 230400 */
		default:
					termios_printf ("t->c_ospeed was %d\n", t->c_ospeed);
					set_errno ( EINVAL);
					return -1;
	}

	/* *********** byte size *********** */
	switch (t->c_cflag & CSIZE)
	{
		case CS5:
					state.ByteSize = 5;
					break;
		case CS6:
					state.ByteSize = 6;
					break;
		case CS7:
					state.ByteSize = 7;
					break;
		case CS8:
		default:
					state.ByteSize = 8;
					break;
	}


	/* *********** stop bits *********** */
	if( t->c_cflag & CSTOPB )
		state.StopBits = TWOSTOPBITS;
	else
		state.StopBits = ONESTOPBIT;


	/* *********** parity *********** */
	if (t->c_cflag & PARENB)
		state.Parity = (t->c_cflag & PARODD) ? ODDPARITY:EVENPARITY;
	else
		state.Parity = NOPARITY;


	state.fBinary = TRUE;	/* binary transfer */
	state.EofChar = 0;	/* no end-of-data in binary mode */
	state.fNull = FALSE;	/* don't discard nulls in binary mode */


	/* *********** parity errors *********** */
	/*	fParity combines the function of INPCK and NOT IGNPAR */
	if( (t->c_iflag & INPCK) && (! t->c_iflag & IGNPAR) )
		state.fParity = TRUE;	/* react to parity errors */
	else
		state.fParity = FALSE;	/* ignore parity errors */

	/* Unix has no equivalent to these */
	state.fErrorChar = FALSE;
	state.ErrorChar = 0;


/* *********** software flow control *********** */
/* if the remote device interprets any received character as XON (the
	equivalent of IXANY at the remote side), then we must set
	fTXContinueOnXoff to FALSE to not trigger a premature XON,
	otherwise, a TRUE value separates the TX and RX functions. */
	state.fTXContinueOnXoff = TRUE;	/* separate TX and RX flow control */

	if( t->c_iflag & IXON )	/* transmission flow control */
	{
		state.fOutX = TRUE;	/* enable */
	}
	else
	{
		state.fOutX = FALSE;	/* disable */
	}

	if( t->c_iflag & IXOFF )	/* reception flow control */
	{
		state.fInX = TRUE;	/* enable */
		/* XoffLim and XonLim are left at default values */
	}
	else
	{
		state.fInX = FALSE;	/* disable */
		/* XoffLim and XonLim are left at default values */
	}
	state.XonChar = (t->c_cc[VSTART] ? t->c_cc[VSTART] : 0x11);
	state.XoffChar = (t->c_cc[VSTOP] ? t->c_cc[VSTOP] : 0x13);


	/* *********** hardware flow control *********** */
	state.fOutxDsrFlow = FALSE;	/* disable DSR flow control */

	/*	older versions of Unix presumed hardware flow control if
		software flow control is not enabled. Newer Unices seem to
		require explicit setting of hardware flow-control and this
		code reflects that scheme. */
	/* CLOCAL causes all lead control, except DTR, to be ignored */
	/* input flow-control */
	if( (t->c_cflag & CRTSXOFF) && ( ! (t->c_cflag & CLOCAL) ) )
	{
		state.fRtsControl = RTS_CONTROL_HANDSHAKE;	/* enable */
	}
	else
	{
		state.fRtsControl = RTS_CONTROL_DISABLE;	/* disable */
	}

	/* output flow-control */
	if( (t->c_cflag & CRTSCTS) && ( ! (t->c_cflag & CLOCAL) ) )
	{
		state.fOutxCtsFlow = TRUE;	/* enable */
	}
	else
	{
		state.fOutxCtsFlow = FALSE;	/* disable */
	}



	/* *********** DTR *********** */
	state.fDtrControl = DTR_CONTROL_ENABLE;	/* assert DTR when device
												is opened */

	/* *********** DSR *********** */
	if( t->c_cflag & CLOCAL )
		state.fDsrSensitivity = FALSE;	/* ignored */
	else
		state.fDsrSensitivity = TRUE;	/* DSR must be asserted at device */

	/* *********** error handling *********** */
	state.fAbortOnError = TRUE;	/* read/write operations terminate upon
									error - requires ClearCommError() to
									resume. */


#if 0
	ds ("Before SetCommState", &state);  
#endif
	SetCommState( get_handle(), &state );

	set_r_binary ((t->c_iflag & IGNCR) ? 0 : 1);
	set_w_binary ((t->c_oflag & ONLCR) ? 0 : 1);

	vtime_ = t->c_cc[VTIME];
	vmin_ = t->c_cc[VMIN];

	if( dropDTR == TRUE )
	{
		EscapeCommFunction( get_handle(), CLRDTR );
	}
	else
	{
		/* in case we previously set CLRDTR and setting
			state.fDtrControl = DTR_CONTROL_ENABLE doesn't do
			the trick. This relationship needs to be discovered
			since a program might want to change some
			parameters while DTR is still down. This would require
			setting some state and testing it.
		*/
		EscapeCommFunction( get_handle(), SETDTR );
	}

	memset (&to, 0, sizeof (to));

	to.ReadTotalTimeoutConstant = vtime_ * 100;

	int res = SetCommTimeouts( get_handle (), &to );
	if( ! res )
	{
		small_printf ("CommTimeout failed\n");
		__seterrno ();
		return -1;
	}
	//  tdump (fd);
	return 0;
}	/* tcsetattr() */







int
fhandler_tty::tcgetattr( struct termios *t )
{
	DCB state;

	/* get current comm state */
	GetCommState (get_handle (), &state);

	/* just in case */
	memset (t, 0, sizeof (*t));

#if 0
	ds ("In tcgetattr", &state);
#endif


	/* *********** baud rate *********** */
	switch (state.BaudRate)
	{
		case 0:			/* B0 - DTR should be dropped */
						t->c_cflag = t->c_ospeed = t->c_ispeed = B0;
						break;
						
		case CBR_110:
						t->c_cflag = t->c_ospeed = t->c_ispeed = B110;
						break;
		case CBR_300:
						t->c_cflag = t->c_ospeed = t->c_ispeed = B300;
						break;
		case CBR_600:
						t->c_cflag = t->c_ospeed = t->c_ispeed = B600;
						break;
		case CBR_1200:
						t->c_cflag = t->c_ospeed = t->c_ispeed = B1200;
						break;
		case CBR_2400:
						t->c_cflag = t->c_ospeed = t->c_ispeed = B2400;
						break;
		case CBR_4800:
						t->c_cflag = t->c_ospeed = t->c_ispeed = B4800;
						break;
		case CBR_9600:
						t->c_cflag = t->c_ospeed = t->c_ispeed = B9600;
						break;
		case CBR_19200:
						t->c_cflag = t->c_ospeed = t->c_ispeed = B19200;
						break;
		case CBR_38400:
						t->c_cflag = t->c_ospeed = t->c_ispeed = B38400;
						break;
		/*
		case CBR_57600:
						t->c_cflag = t->c_ospeed = t->c_ispeed = B57600;
						break;
		case CBR_115200:
						t->c_cflag = t->c_ospeed = t->c_ispeed = B115200;
						break;
		*/
		default:
						/* t->c_cflag = t->c_ospeed = t->c_ispeed = B9600; */
						set_errno ( EINVAL);
	}


	/* *********** byte size *********** */
	switch (state.ByteSize)
	{
		case 5:
				t->c_cflag |= CS5;
				break;
		case 6:
				t->c_cflag |= CS6;
				break;
		case 7:
				t->c_cflag |= CS7;
				break;
		case 8:
				t->c_cflag |= CS8;
				break;
		default:
				break;
	}


	/* *********** stop bits *********** */
	if( state.StopBits == TWOSTOPBITS )
		t->c_cflag |= CSTOPB;


	/* *********** parity *********** */
	if( state.Parity == ODDPARITY )
		t->c_cflag |= (PARENB | PARODD);
	if( state.Parity == EVENPARITY )
		t->c_cflag |= PARENB;


	/* *********** parity errors *********** */
	/*	fParity combines the function of INPCK and NOT IGNPAR */
	if( state.fParity == TRUE )
		t->c_iflag |= INPCK;
	else
		t->c_iflag |= IGNPAR;	/* not necessarily! */


	/* *********** software flow control *********** */
	/* transmission flow control */
	if( state.fOutX == TRUE )
		t->c_iflag |= IXON;

	/* reception flow control */
	if( state.fInX == TRUE )
		t->c_iflag |= IXOFF;

	t->c_cc[VSTART] = ( state.XonChar ? state.XonChar : 0x11 );
	t->c_cc[VSTOP] = ( state.XoffChar ? state.XoffChar : 0x13 );


	/* *********** hardware flow control *********** */
	/*	older versions of Unix presumed hardware flow control if
		software flow control is not enabled. Newer Unices seem to
		require explicit setting of hardware flow-control and this
		code reflects that scheme. */
	/* input flow-control */
	if( state.fRtsControl == RTS_CONTROL_HANDSHAKE )
		t->c_cflag |= CRTSXOFF;

	/* output flow-control */
	if( state.fOutxCtsFlow == TRUE )
		t->c_cflag |= CRTSCTS;

	/* *********** CLOCAL *********** */
	/* DSR is the only lead toggled ONLY by CLOCAL, so we can use it
		as a flag that CLOCAL was called. This presumes that
		tcsetattr() was called previously; if not, this may give
		a false CLOCAL. */
	if( state.fDsrSensitivity == FALSE )
		t->c_cflag |= CLOCAL;


#if 0 /* IGNCR doesn't work yet */
	if (!get_r_binary ())
		t->c_iflag |= IGNCR;
#endif
	if (!get_w_binary ())
		t->c_oflag |= ONLCR;

	t->c_cc[VTIME] = vtime_;
	t->c_cc[VMIN] = vmin_;

	//  tdump (fd);
	return 0;
}	/* tcgetattr() */






/**********************************************************************/
/* /dev/null */

fhandler_dev_null::fhandler_dev_null(const char *name) : fhandler_base (name)
{;}

fhandler_base *
fhandler_dev_null::open (const char *, int, mode_t)
{
  set_handle((HANDLE) DEV_NULL_HANDLE_VALUE);
  return this;
}

void
fhandler_dev_null::dump ()
{
  paranoid_printf ("FHANDLER DEV/NULL\n");
}

int
fhandler_dev_null::close ()
{
  return 0;
}

int
fhandler_dev_null::fstat (struct stat *buf) 
{
  memset (buf, 0, sizeof (*buf));
  buf->st_blksize = S_BLKSIZE;
  buf->st_dev = 1234;
  buf->st_ino = 4567;

  return 0;
}

int
fhandler_dev_null::ioctl (int, void *)
{
  return -1;
}

int
fhandler_dev_null::read (void *, size_t)
{
  return 0;
}

int
fhandler_dev_null::write (const void *, size_t x)
{
  syscall_printf ("/dev/null write %d\n",x);
  return x;
}

long
fhandler_dev_null::lseek (long, int)
{
  return 0;
}

int
fhandler_dev_null::dup (fhandler_base *child)
{
  child->set_handle(get_handle());
  return 0;
}

/**********************************************************************/
/* fhandler_dev_floppy */

fhandler_dev_floppy::fhandler_dev_floppy (const char *name) : fhandler_base (name)
{;}

fhandler_base *
fhandler_dev_floppy::open (const char *path, int flags, mode_t)
{
  /* Always open a floppy existings */
  return fhandler_base::open (path, flags & ~O_CREAT);
}

/**********************************************************************/
/* fhandler_dev_tape */

fhandler_dev_tape::fhandler_dev_tape(const char *name) : fhandler_base (name)
{;}

fhandler_base *
fhandler_dev_tape::open (const char *path, int flags, mode_t)
{
  /* Always open a tape existings */
  return  fhandler_base::open (path, flags & ~O_CREAT);
}

/**********************************************************************/
/* fhandler_socket */

fhandler_socket::fhandler_socket (unsigned int s, const char *name) : fhandler_base (name)
{
  set_handle ((HANDLE)s);
  debug_printf ("socket id %d\n", s);
}
/* fhandler.h: winsup file handling

   Copyright 1996, 1997 Cygnus Solutions

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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */

#ifndef _FHANDLER_H_
#define _FHANDLER_H_

#include <sys/types.h>

/* Classes

   fhandler_base		normal I/O

     fhandler_dev_floppy
     fhandler_disk_file  
     fhandler_socket        

     fhandler_tty            adds vmin and vtime

	fhandler_console (out with ansi control)

  fhandler_dev_null		not really I/O

  fhandler_proc			interesting possibility, not implemented yet
*/

class fhandler_base
{
  int access_;
  HANDLE handle_;

  /* Set if in binary write mode.  */
  char w_binary_;

  /* Set if in binary read mode.  */
  char r_binary_;
  char close_exec_p_;		/* Non-zero if close-on-exec bit set.  */

  /* Used for crlf conversion in text files */
  char readahead_valid_;
  char readahead_;

  char append_p_; /* Set if always appending */

  int rpos_; /* Used in text reading */
  int rsize_; 

  char had_eof_;
  unsigned long namehash_;	 /* hashed filename, used as inode num */

  /* Full unix path name of this file */
  char *unix_path_name_;

  void set_name (const char *);

protected:

  char symlink_p_;
  /* Non-zero if this file looked like it would run (i.e. ends in .exe or .bat
     or begins with #!.  */
  char execable_p_;		

public:

  fhandler_base (const char *name = 0);
  ~fhandler_base();

  /* Non-virtual simple accessor functions. */
  void set_handle (HANDLE);

  int  get_access () { return access_; }
  void set_access (int x) { access_ = x; }

  int get_w_binary () { return w_binary_; }
  int get_r_binary () { return r_binary_; }

  set_w_binary (int b) { w_binary_ = b; }
  set_r_binary (int b) { r_binary_ = b; }

  void set_close_on_exec(char val) { close_exec_p_ = val; }
  char get_close_on_exec() { return close_exec_p_; }

  const char *get_name () { return unix_path_name_; }
  unsigned long get_namehash() { return namehash_; }

  /* Potentially overridden virtual functions. */
  virtual fhandler_base *open (const char *path, int flags, mode_t mode=0);
  virtual int close ();
  virtual int fstat (struct stat *buf);
  virtual int ioctl (int cmd, void *);
  virtual const char * ttyname () { return get_name(); }
  virtual int read (void *ptr, size_t len);
  virtual int write (const void *ptr, size_t len);
  virtual off_t lseek (off_t offset, int whence);
  virtual int lock(int, struct flock *);
  virtual void dump ();
  virtual int dup (fhandler_base *child);


  void *operator new (size_t, void *);

  virtual void init (HANDLE, int, int, const char *);

  virtual int tcflush (int) { return -1; }
  virtual int tcsendbreak( int ) { return 0; }
  virtual int tcdrain( void ) { return 0; }
  virtual int tcflow( int ) { return 0; }
  virtual int tcsetattr (int a, const struct termios *t) { return -1; }
  virtual int tcgetattr (struct termios *t) { return -1; }
  virtual int is_tty () { return 0; }
  virtual class fhandler_socket *is_socket () { return 0; }
  virtual class fhandler_console *is_console () { return 0; }

  virtual int raw_read (void *ptr, size_t ulen);
  virtual int raw_write (const void *ptr, size_t ulen);

  /* 1 if it's pointless (and broken) to select for read on the handle */
  virtual const int always_read_ready () { return 1; } ;
  /* 1 if it's pointless (and broken) to select for write on the handle */
  virtual const int always_write_ready () { return 1; } ;
  /* 1 if it's pointless (and broken) to select for except on the handle */
  virtual const int always_except_ready () { return 1; } ;

  /* Function to save state of a fhandler_base into memory. */
  virtual int linearize(unsigned char *);
  /* Function to de-linearize into a fd */
  virtual int de_linearize(const unsigned char *);

  /* Virtual accessor functions to hide the fact
     that some fd's have two handles. */
  virtual HANDLE get_handle () const { return handle_; }
  virtual HANDLE get_input_handle() const { return handle_; }
  virtual HANDLE get_output_handle() const { return handle_; }
};

class fhandler_socket: public fhandler_base
{
public:
  fhandler_socket (unsigned int, const char *name = 0);
  int get_socket () const { return (int)get_handle(); }
  fhandler_socket * is_socket () { return this; }
  virtual int write (const void *ptr, size_t len);
  virtual int read (void *ptr, size_t len);
  virtual int ioctl (int cmd, void *);
  virtual int fstat (struct stat *buf);
  virtual int close ();

  virtual const int always_read_ready () { return 0; }
  virtual const int always_write_ready () { return 0; }
  virtual const int always_except_ready () { return 0; }
};

class fhandler_dev_floppy: public fhandler_base
{
public:
  fhandler_dev_floppy(const char *name = 0);

  virtual fhandler_base *open (const char *path, int flags, mode_t mode=0);
};

class fhandler_dev_tape: public fhandler_base
{
public:
  fhandler_dev_tape(const char *name = 0);

  virtual fhandler_base *open (const char *path, int flags, mode_t mode=0);
};

/* Standard disk file */

class fhandler_disk_file : public fhandler_base
{
private:
  int check_execable_p (const char *path);

public:
  fhandler_disk_file(const char *name = 0);

  virtual fhandler_base *open (const char *path, int flags, mode_t mode=0);
  virtual int lock(int, struct flock *);
};

class fhandler_tty: public fhandler_base
{
private:
  unsigned  int vmin_;			/* from termios */
  unsigned  int vtime_;			/* from termios */

public:
  /* Constructor */
  fhandler_tty (const char *name = 0);

  virtual fhandler_base *open( const char *path, int flags, mode_t mode );
  virtual int raw_read (void *ptr, size_t ulen);
  virtual int tcsendbreak( int );
  virtual int tcdrain( void );
  virtual int tcflow( int );
  virtual int tcsetattr (int a, const struct termios *t);
  virtual int tcgetattr (struct termios *t);
  virtual int fstat (struct stat *buf);
  virtual int tcflush (int);
  virtual void dump ();
  virtual int is_tty () { return 1; }

  /* Function to save state of a fhandler_tty into memory. */
  virtual int linearize(unsigned char *);
  /* Function to de-linearize into a fd */
  virtual int de_linearize(const unsigned char *);
};

/* This is a input and output console handle */
class fhandler_console: public fhandler_tty
{
private:

/* Output state */

  // enum  {normal, gotesc, gotsquare, gotarg1, gotcommand} state;
#define  normal 1
#define  gotesc 2
#define  gotsquare 3
#define  gotarg1 4
#define  gotcommand 6
#define  MAXARGS 10
  int state_;
  int args_[MAXARGS];
  int nargs_;

/* Extra output handle */
  HANDLE output_handle_;
  DWORD default_color;

/* Output calls */

  void clear_screen (int, int, int, int);
  void scroll_screen (int, int, int, int, int, int);
  void cursor_set (int x, int y);
  void cursor_get (int *x, int *y);
  void cursor_rel (int x, int y);
  void get_info ();
  const unsigned char * write_normal (unsigned const char*, unsigned const char *);
  void char_command (char);
  int output_tcsetattr (int a, const struct termios *t);

/* Input state */
  /* Bits are..
     IGNCR  ignore carriage return on input - whether we nuke '\r's
     the default for this is set by wheter the file is opened
     in text or binary mode.

     INLCR  translate NL to CR on input

     IUCLC  map uppercase characters to lowercase on input
  */
  int iflag_;
  int lflag_;

/* Input calls */
  int igncr_enabled ();
  int input_tcsetattr (int a, const struct termios *t);

public:
  fhandler_console (const char *name = 0);

  fhandler_console* is_console () { return this; }

  virtual fhandler_base *open (const char *path, int flags, mode_t mode=0);

  virtual int write (const void *ptr, size_t len);
  virtual int read (void *ptr, size_t len);
  virtual int close ();

  virtual int tcflush (int);
  virtual int tcsetattr (int a, const struct termios *t);
  virtual int tcgetattr (struct termios *t);

  /* Special dup as we must dup two handles */
  virtual int dup (fhandler_base *child);

  virtual int ioctl (int cmd, void *);
  virtual void init (HANDLE, int, int, const char *);

  virtual const int always_read_ready () { return 0;}

  /* Function to save state of a fhandler_console_out into memory. */
  virtual int linearize(unsigned char *);
  /* Function to de-linearize into a fd */
  virtual int de_linearize(const unsigned char *);

  virtual HANDLE get_output_handle() const { return output_handle_; }
};

class fhandler_dev_null: public fhandler_base
{
#define DEV_NULL_HANDLE_VALUE (-2)

public:
  fhandler_dev_null (const char *name = 0);

  virtual fhandler_base *open (const char *path, int flags, mode_t mode=0);
  virtual int close ();
  virtual int fstat (struct stat *buf);
  virtual int ioctl (int cmd, void *);
  virtual int read (void *ptr, size_t len);
  virtual int write (const void *ptr, size_t len);
  virtual off_t lseek (off_t offset, int whence);
  virtual int dup (fhandler_base *child);
  virtual void dump ();
};

#if 0
/* You can't do this */
typedef union 
{
  fhandler_normal normal;
  fhandler_dev_null dev_null;
  fhandler bare;
  fhandler_tty tty;
} fhandler_union;
#else
#define fhandler_union fhandler_console
#endif

uid_t get_file_owner (char *);
gid_t get_file_group (char *);
BOOL get_file_attribute(char *, int *);
BOOL set_file_attribute(char *, int);
#endif /* _FHANDLER_H_ */

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]