+ tPTY *pty = Node->ImplPtr;
+ if( !pty ) {
+ errno = EIO;
+ return -1;
+ }
+
+ tTime timeout_z = 0, *timeout = (Flags & VFS_IOFLAG_NOBLOCK) ? &timeout_z : NULL;
+ int rv = VFS_SelectNode(Node, VFS_SELECT_WRITE, timeout, "PTY_WriteServer");
+ if(!rv) {
+ errno = (timeout ? EWOULDBLOCK : EINTR);
+ return -1;
+ }
+ size_t used = 0;
+ do {
+ used += PTY_SendInput(Node->ImplPtr, Buffer, Length);
+ } while( used < Length && !(Flags & VFS_IOFLAG_NOBLOCK) );
+
+ if( (pty->InputWritePos+1)%INPUT_RINGBUFFER_LEN == pty->InputReadPos )
+ VFS_MarkFull(Node, 1);
+ return used;
+}
+
+void PTY_CloseServer(tVFS_Node *Node)
+{
+ tPTY *pty = Node->ImplPtr;
+ // Dereference node
+ Node->ReferenceCount --;
+ // If reference count == 0, remove from main list
+ if( Node->ReferenceCount > 0 )
+ return ;
+
+ // Locate on list and remove
+ tPTY **prev_np;
+ if( pty->NumericName == -1 ) {
+ RWLock_AcquireWrite(&glPTY_NamedPTYs);
+ prev_np = &gpPTY_FirstNamedPTY;
+ }
+ else {
+ RWLock_AcquireWrite(&glPTY_NumPTYs);
+ prev_np = &gpPTY_FirstNumPTY;
+ }
+
+ // Search list until *prev_np is equal to pty
+ for( tPTY *tmp = *prev_np; *prev_np != pty && tmp; prev_np = &tmp->Next, tmp = tmp->Next )
+ ;
+
+ // Remove
+ if( *prev_np != pty ) {
+ Log_Error("PTY", "PTY %p(%i/%s) not on list at deletion time", pty, pty->NumericName, pty->Name);
+ }
+ else {
+ *prev_np = pty->Next;
+ }
+
+ // Clean up lock
+ if( pty->NumericName == -1 ) {
+ RWLock_Release(&glPTY_NamedPTYs);
+ giPTY_NamedCount --;
+ }
+ else {
+ RWLock_Release(&glPTY_NumPTYs);
+ giPTY_NumCount --;
+ }
+
+ // Send SIGHUP to controling PGID
+ if( pty->ControllingProcGroup > 0 ) {
+ Threads_SignalGroup(pty->ControllingProcGroup, SIGHUP);
+ }
+
+ // If there are no open children, we can safely free this PTY
+ if( pty->ClientNode.ReferenceCount == 0 ) {
+ free(Node);
+ free(pty);
+ }