2
* FreeRDP: A Remote Desktop Protocol client.
3
* Serial Port Device Service Virtual Channel
5
* Copyright 2011 O.S. Systems Software Ltda.
6
* Copyright 2011 Eduardo Fiss Beloni <beloni@ossystems.com.br>
8
* Licensed under the Apache License, Version 2.0 (the "License");
9
* you may not use this file except in compliance with the License.
10
* You may obtain a copy of the License at
12
* http://www.apache.org/licenses/LICENSE-2.0
14
* Unless required by applicable law or agreed to in writing, software
15
* distributed under the License is distributed on an "AS IS" BASIS,
16
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17
* See the License for the specific language governing permissions and
18
* limitations under the License.
25
#include <freerdp/utils/memory.h>
26
#include <freerdp/utils/stream.h>
27
#include <freerdp/utils/unicode.h>
28
#include <freerdp/utils/list.h>
29
#include <freerdp/utils/thread.h>
30
#include <freerdp/utils/svc_plugin.h>
31
#include <freerdp/utils/hexdump.h>
36
#include <sys/types.h>
39
#include <sys/ioctl.h>
42
#include "rdpdr_constants.h"
43
#include "rdpdr_types.h"
44
#include "serial_tty.h"
45
#include "serial_constants.h"
47
#ifdef HAVE_SYS_MODEM_H
48
#include <sys/modem.h>
50
#ifdef HAVE_SYS_FILIO_H
51
#include <sys/filio.h>
53
#ifdef HAVE_SYS_STRTIO_H
54
#include <sys/strtio.h>
61
/* FIONREAD should really do the same thing as TIOCINQ, where it is
63
#if !defined(TIOCINQ) && defined(FIONREAD)
64
#define TIOCINQ FIONREAD
66
#if !defined(TIOCOUTQ) && defined(FIONWRITE)
67
#define TIOCOUTQ FIONWRITE
71
static uint32 tty_write_data(SERIAL_TTY* tty, uint8* data, int len);
72
static void tty_set_termios(SERIAL_TTY* tty);
73
static boolean tty_get_termios(SERIAL_TTY* tty);
74
static int tty_get_error_status();
76
uint32 serial_tty_control(SERIAL_TTY* tty, uint32 IoControlCode, STREAM* input, STREAM* output, uint32* abort_io)
82
uint32 ret = STATUS_SUCCESS;
88
stream_seek(output, sizeof(uint32));
90
switch (IoControlCode)
92
case IOCTL_SERIAL_SET_BAUD_RATE:
93
stream_read_uint32(input, tty->baud_rate);
95
DEBUG_SVC("SERIAL_SET_BAUD_RATE %d", tty->baud_rate);
98
case IOCTL_SERIAL_GET_BAUD_RATE:
100
stream_write_uint32(output, tty->baud_rate);
101
DEBUG_SVC("SERIAL_GET_BAUD_RATE %d", tty->baud_rate);
104
case IOCTL_SERIAL_SET_QUEUE_SIZE:
105
stream_read_uint32(input, tty->queue_in_size);
106
stream_read_uint32(input, tty->queue_out_size);
107
DEBUG_SVC("SERIAL_SET_QUEUE_SIZE in %d out %d", tty->queue_in_size, tty->queue_out_size);
110
case IOCTL_SERIAL_SET_LINE_CONTROL:
111
stream_read_uint8(input, tty->stop_bits);
112
stream_read_uint8(input, tty->parity);
113
stream_read_uint8(input, tty->word_length);
114
tty_set_termios(tty);
115
DEBUG_SVC("SERIAL_SET_LINE_CONTROL stop %d parity %d word %d",
116
tty->stop_bits, tty->parity, tty->word_length);
119
case IOCTL_SERIAL_GET_LINE_CONTROL:
120
DEBUG_SVC("SERIAL_GET_LINE_CONTROL");
122
stream_write_uint8(output, tty->stop_bits);
123
stream_write_uint8(output, tty->parity);
124
stream_write_uint8(output, tty->word_length);
127
case IOCTL_SERIAL_IMMEDIATE_CHAR:
128
DEBUG_SVC("SERIAL_IMMEDIATE_CHAR");
129
stream_read_uint8(input, immediate);
130
tty_write_data(tty, &immediate, 1);
133
case IOCTL_SERIAL_CONFIG_SIZE:
134
DEBUG_SVC("SERIAL_CONFIG_SIZE");
136
stream_write_uint32(output, 0);
139
case IOCTL_SERIAL_GET_CHARS:
140
DEBUG_SVC("SERIAL_GET_CHARS");
142
stream_write(output, tty->chars, 6);
145
case IOCTL_SERIAL_SET_CHARS:
146
DEBUG_SVC("SERIAL_SET_CHARS");
147
stream_read(input, tty->chars, 6);
148
tty_set_termios(tty);
151
case IOCTL_SERIAL_GET_HANDFLOW:
153
tty_get_termios(tty);
154
stream_write_uint32(output, tty->control);
155
stream_write_uint32(output, tty->xonoff);
156
stream_write_uint32(output, tty->onlimit);
157
stream_write_uint32(output, tty->offlimit);
158
DEBUG_SVC("IOCTL_SERIAL_GET_HANDFLOW %X %X %X %X",
159
tty->control, tty->xonoff, tty->onlimit, tty->offlimit);
162
case IOCTL_SERIAL_SET_HANDFLOW:
163
stream_read_uint32(input, tty->control);
164
stream_read_uint32(input, tty->xonoff);
165
stream_read_uint32(input, tty->onlimit);
166
stream_read_uint32(input, tty->offlimit);
167
DEBUG_SVC("IOCTL_SERIAL_SET_HANDFLOW %X %X %X %X",
168
tty->control, tty->xonoff, tty->onlimit, tty->offlimit);
169
tty_set_termios(tty);
172
case IOCTL_SERIAL_SET_TIMEOUTS:
173
stream_read_uint32(input, tty->read_interval_timeout);
174
stream_read_uint32(input, tty->read_total_timeout_multiplier);
175
stream_read_uint32(input, tty->read_total_timeout_constant);
176
stream_read_uint32(input, tty->write_total_timeout_multiplier);
177
stream_read_uint32(input, tty->write_total_timeout_constant);
179
/* http://www.codeproject.com/KB/system/chaiyasit_t.aspx, see 'ReadIntervalTimeout' section
180
http://msdn.microsoft.com/en-us/library/ms885171.aspx */
181
if (tty->read_interval_timeout == SERIAL_TIMEOUT_MAX)
183
tty->read_interval_timeout = 0;
184
tty->read_total_timeout_multiplier = 0;
187
DEBUG_SVC("SERIAL_SET_TIMEOUTS read timeout %d %d %d",
188
tty->read_interval_timeout,
189
tty->read_total_timeout_multiplier,
190
tty->read_total_timeout_constant);
193
case IOCTL_SERIAL_GET_TIMEOUTS:
194
DEBUG_SVC("SERIAL_GET_TIMEOUTS read timeout %d %d %d",
195
tty->read_interval_timeout,
196
tty->read_total_timeout_multiplier,
197
tty->read_total_timeout_constant);
199
stream_write_uint32(output, tty->read_interval_timeout);
200
stream_write_uint32(output, tty->read_total_timeout_multiplier);
201
stream_write_uint32(output, tty->read_total_timeout_constant);
202
stream_write_uint32(output, tty->write_total_timeout_multiplier);
203
stream_write_uint32(output, tty->write_total_timeout_constant);
206
case IOCTL_SERIAL_GET_WAIT_MASK:
207
DEBUG_SVC("SERIAL_GET_WAIT_MASK %X", tty->wait_mask);
209
stream_write_uint32(output, tty->wait_mask);
212
case IOCTL_SERIAL_SET_WAIT_MASK:
213
stream_read_uint32(input, tty->wait_mask);
214
DEBUG_SVC("SERIAL_SET_WAIT_MASK %X", tty->wait_mask);
217
case IOCTL_SERIAL_SET_DTR:
218
DEBUG_SVC("SERIAL_SET_DTR");
219
ioctl(tty->fd, TIOCMGET, &result);
221
ioctl(tty->fd, TIOCMSET, &result);
225
case IOCTL_SERIAL_CLR_DTR:
226
DEBUG_SVC("SERIAL_CLR_DTR");
227
ioctl(tty->fd, TIOCMGET, &result);
228
result &= ~TIOCM_DTR;
229
ioctl(tty->fd, TIOCMSET, &result);
233
case IOCTL_SERIAL_SET_RTS:
234
DEBUG_SVC("SERIAL_SET_RTS");
235
ioctl(tty->fd, TIOCMGET, &result);
237
ioctl(tty->fd, TIOCMSET, &result);
241
case IOCTL_SERIAL_CLR_RTS:
242
DEBUG_SVC("SERIAL_CLR_RTS");
243
ioctl(tty->fd, TIOCMGET, &result);
244
result &= ~TIOCM_RTS;
245
ioctl(tty->fd, TIOCMSET, &result);
249
case IOCTL_SERIAL_GET_MODEMSTATUS:
252
ioctl(tty->fd, TIOCMGET, &result);
253
if (result & TIOCM_CTS)
254
modemstate |= SERIAL_MS_CTS;
255
if (result & TIOCM_DSR)
256
modemstate |= SERIAL_MS_DSR;
257
if (result & TIOCM_RNG)
258
modemstate |= SERIAL_MS_RNG;
259
if (result & TIOCM_CAR)
260
modemstate |= SERIAL_MS_CAR;
261
if (result & TIOCM_DTR)
262
modemstate |= SERIAL_MS_DTR;
263
if (result & TIOCM_RTS)
264
modemstate |= SERIAL_MS_RTS;
266
DEBUG_SVC("SERIAL_GET_MODEMSTATUS %X", modemstate);
268
stream_write_uint32(output, modemstate);
271
case IOCTL_SERIAL_GET_COMMSTATUS:
273
stream_write_uint32(output, 0); /* Errors */
274
stream_write_uint32(output, 0); /* Hold reasons */
278
ioctl(tty->fd, TIOCINQ, &result);
280
stream_write_uint32(output, result); /* Amount in in queue */
282
DEBUG_SVC("SERIAL_GET_COMMSTATUS in queue %d", result);
286
ioctl(tty->fd, TIOCOUTQ, &result);
288
stream_write_uint32(output, result); /* Amount in out queue */
289
DEBUG_SVC("SERIAL_GET_COMMSTATUS out queue %d", result);
291
stream_write_uint8(output, 0); /* EofReceived */
292
stream_write_uint8(output, 0); /* WaitForImmediate */
295
case IOCTL_SERIAL_PURGE:
296
stream_read_uint32(input, purge_mask);
297
DEBUG_SVC("SERIAL_PURGE purge_mask %X", purge_mask);
299
/* See http://msdn.microsoft.com/en-us/library/ms901431.aspx
300
PURGE_TXCLEAR Clears the output buffer, if the driver has one.
301
PURGE_RXCLEAR Clears the input buffer, if the driver has one.
303
It clearly states to clear the *driver* buffer, not the port buffer
307
if (purge_mask & SERIAL_PURGE_TXCLEAR)
308
DEBUG_SVC("Ignoring SERIAL_PURGE_TXCLEAR");
309
if (purge_mask & SERIAL_PURGE_RXCLEAR)
310
DEBUG_SVC("Ignoring SERIAL_PURGE_RXCLEAR");
313
if (purge_mask & SERIAL_PURGE_TXABORT)
314
*abort_io |= SERIAL_ABORT_IO_WRITE;
315
if (purge_mask & SERIAL_PURGE_RXABORT)
316
*abort_io |= SERIAL_ABORT_IO_READ;
318
case IOCTL_SERIAL_WAIT_ON_MASK:
319
DEBUG_SVC("SERIAL_WAIT_ON_MASK %X", tty->wait_mask);
320
tty->event_pending = 1;
322
if (serial_tty_get_event(tty, &result))
324
DEBUG_SVC("WAIT end event = %X", result);
325
stream_write_uint32(output, result);
328
ret = STATUS_PENDING;
331
case IOCTL_SERIAL_SET_BREAK_ON:
332
DEBUG_SVC("SERIAL_SET_BREAK_ON");
333
tcsendbreak(tty->fd, 0);
336
case IOCTL_SERIAL_RESET_DEVICE:
337
DEBUG_SVC("SERIAL_RESET_DEVICE");
340
case IOCTL_SERIAL_SET_BREAK_OFF:
341
DEBUG_SVC("SERIAL_SET_BREAK_OFF");
344
case IOCTL_SERIAL_SET_XOFF:
345
DEBUG_SVC("SERIAL_SET_XOFF");
348
case IOCTL_SERIAL_SET_XON:
349
DEBUG_SVC("SERIAL_SET_XON");
350
tcflow(tty->fd, TCION);
354
DEBUG_SVC("NOT FOUND IoControlCode SERIAL IOCTL %d", IoControlCode);
355
return STATUS_INVALID_PARAMETER;
358
/* Write OutputBufferLength */
359
pos = stream_get_pos(output);
360
stream_set_pos(output, 16);
361
stream_write_uint32(output, length);
362
stream_set_pos(output, pos);
367
boolean serial_tty_read(SERIAL_TTY* tty, uint8* buffer, uint32* Length)
370
struct termios *ptermios;
374
ptermios = tty->ptermios;
376
/* Set timeouts kind of like the windows serial timeout parameters. Multiply timeout
377
with requested read size */
378
if (tty->read_total_timeout_multiplier | tty->read_total_timeout_constant)
381
(tty->read_total_timeout_multiplier * (*Length) +
382
tty->read_total_timeout_constant + 99) / 100;
384
else if (tty->read_interval_timeout)
386
timeout = (tty->read_interval_timeout * (*Length) + 99) / 100;
389
/* If a timeout is set, do a blocking read, which times out after some time.
390
It will make FreeRDP less responsive, but it will improve serial performance,
391
by not reading one character at a time. */
394
ptermios->c_cc[VTIME] = 0;
395
ptermios->c_cc[VMIN] = 0;
399
ptermios->c_cc[VTIME] = timeout;
400
ptermios->c_cc[VMIN] = 1;
403
tcsetattr(tty->fd, TCSANOW, ptermios);
405
memset(buffer, 0, *Length);
406
r = read(tty->fd, buffer, *Length);
410
tty->event_txempty = r;
416
boolean serial_tty_write(SERIAL_TTY* tty, uint8* buffer, uint32 Length)
419
uint32 event_txempty = Length;
425
r = write(tty->fd, buffer, Length);
432
tty->event_txempty = event_txempty;
437
void serial_tty_free(SERIAL_TTY* tty)
443
tcsetattr(tty->fd, TCSANOW, tty->pold_termios);
447
xfree(tty->ptermios);
448
xfree(tty->pold_termios);
452
SERIAL_TTY* serial_tty_new(const char* path, uint32 id)
456
tty = xnew(SERIAL_TTY);
458
tty->fd = open(path, O_RDWR | O_NOCTTY | O_NONBLOCK);
462
DEBUG_WARN("failed to open device %s", path);
466
DEBUG_SVC("tty fd %d successfully opened", tty->fd);
468
tty->ptermios = (struct termios*) malloc(sizeof(struct termios));
469
memset(tty->ptermios, 0, sizeof(struct termios));
470
tty->pold_termios = (struct termios*) malloc(sizeof(struct termios));
471
memset(tty->pold_termios, 0, sizeof(struct termios));
472
tcgetattr(tty->fd, tty->pold_termios);
474
if (!tty_get_termios(tty))
476
DEBUG_WARN("%s access denied", path);
481
tty->ptermios->c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON);
482
tty->ptermios->c_iflag = IGNPAR | ICRNL;
483
tty->ptermios->c_oflag &= ~OPOST;
484
tty->ptermios->c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
485
tty->ptermios->c_cflag &= ~(CSIZE | PARENB);
486
tty->ptermios->c_cflag |= CLOCAL | CREAD | CS8;
487
tcsetattr(tty->fd, TCSANOW, tty->ptermios);
489
tty->event_txempty = 0;
493
tty->event_pending = 0;
495
/* all read and writes should be non-blocking */
496
if (fcntl(tty->fd, F_SETFL, O_NONBLOCK) == -1)
498
DEBUG_WARN("%s fcntl", path);
503
tty->read_total_timeout_constant = 5;
508
boolean serial_tty_get_event(SERIAL_TTY* tty, uint32* result)
518
/* When wait_mask is set to zero we ought to cancel it all
519
For reference: http://msdn.microsoft.com/en-us/library/aa910487.aspx */
520
if (tty->wait_mask == 0)
522
tty->event_pending = 0;
526
ioctl(tty->fd, TIOCINQ, &bytes);
530
DEBUG_SVC("bytes %d", bytes);
532
if (bytes > tty->event_rlsd)
534
tty->event_rlsd = bytes;
535
if (tty->wait_mask & SERIAL_EV_RLSD)
537
DEBUG_SVC("SERIAL_EV_RLSD");
538
*result |= SERIAL_EV_RLSD;
544
if ((bytes > 1) && (tty->wait_mask & SERIAL_EV_RXFLAG))
546
DEBUG_SVC("SERIAL_EV_RXFLAG bytes %d", bytes);
547
*result |= SERIAL_EV_RXFLAG;
550
if ((tty->wait_mask & SERIAL_EV_RXCHAR))
552
DEBUG_SVC("SERIAL_EV_RXCHAR bytes %d", bytes);
553
*result |= SERIAL_EV_RXCHAR;
565
ioctl(tty->fd, TIOCOUTQ, &bytes);
567
&& (tty->event_txempty > 0) && (tty->wait_mask & SERIAL_EV_TXEMPTY))
569
DEBUG_SVC("SERIAL_EV_TXEMPTY");
570
*result |= SERIAL_EV_TXEMPTY;
573
tty->event_txempty = bytes;
576
ioctl(tty->fd, TIOCMGET, &bytes);
577
if ((bytes & TIOCM_DSR) != tty->event_dsr)
579
tty->event_dsr = bytes & TIOCM_DSR;
580
if (tty->wait_mask & SERIAL_EV_DSR)
582
DEBUG_SVC("SERIAL_EV_DSR %s", (bytes & TIOCM_DSR) ? "ON" : "OFF");
583
*result |= SERIAL_EV_DSR;
588
if ((bytes & TIOCM_CTS) != tty->event_cts)
590
tty->event_cts = bytes & TIOCM_CTS;
591
if (tty->wait_mask & SERIAL_EV_CTS)
593
DEBUG_SVC("SERIAL_EV_CTS %s", (bytes & TIOCM_CTS) ? "ON" : "OFF");
594
*result |= SERIAL_EV_CTS;
600
tty->event_pending = 0;
605
static boolean tty_get_termios(SERIAL_TTY* tty)
608
struct termios *ptermios;
609
ptermios = tty->ptermios;
611
DEBUG_SVC("tcgetattr? %d", tcgetattr(tty->fd, ptermios) >= 0);
612
if (tcgetattr(tty->fd, ptermios) < 0)
615
speed = cfgetispeed(ptermios);
625
tty->baud_rate = 110;
630
tty->baud_rate = 134;
635
tty->baud_rate = 150;
640
tty->baud_rate = 300;
645
tty->baud_rate = 600;
650
tty->baud_rate = 1200;
655
tty->baud_rate = 1800;
660
tty->baud_rate = 2400;
665
tty->baud_rate = 4800;
670
tty->baud_rate = 9600;
675
tty->baud_rate = 19200;
680
tty->baud_rate = 38400;
685
tty->baud_rate = 57600;
690
tty->baud_rate = 115200;
695
tty->baud_rate = 230400;
700
tty->baud_rate = 460800;
704
tty->baud_rate = 9600;
708
speed = cfgetospeed(ptermios);
709
tty->dtr = (speed == B0) ? 0 : 1;
711
tty->stop_bits = (ptermios->c_cflag & CSTOPB) ? SERIAL_STOP_BITS_2 : SERIAL_STOP_BITS_1;
713
(ptermios->c_cflag & PARENB) ? ((ptermios->c_cflag & PARODD) ? SERIAL_ODD_PARITY :
714
SERIAL_EVEN_PARITY) : SERIAL_NO_PARITY;
715
switch (ptermios->c_cflag & CSIZE)
718
tty->word_length = 5;
721
tty->word_length = 6;
724
tty->word_length = 7;
727
tty->word_length = 8;
731
if (ptermios->c_cflag & CRTSCTS)
733
tty->control = SERIAL_DTR_CONTROL | SERIAL_CTS_HANDSHAKE | SERIAL_ERROR_ABORT;
737
tty->control = SERIAL_DTR_CONTROL | SERIAL_ERROR_ABORT;
740
tty->xonoff = SERIAL_DSR_SENSITIVITY;
741
if (ptermios->c_iflag & IXON)
742
tty->xonoff |= SERIAL_XON_HANDSHAKE;
744
if (ptermios->c_iflag & IXOFF)
745
tty->xonoff |= SERIAL_XOFF_HANDSHAKE;
747
tty->chars[SERIAL_CHAR_XON] = ptermios->c_cc[VSTART];
748
tty->chars[SERIAL_CHAR_XOFF] = ptermios->c_cc[VSTOP];
749
tty->chars[SERIAL_CHAR_EOF] = ptermios->c_cc[VEOF];
750
tty->chars[SERIAL_CHAR_BREAK] = ptermios->c_cc[VINTR];
751
tty->chars[SERIAL_CHAR_ERROR] = ptermios->c_cc[VKILL];
756
static void tty_set_termios(SERIAL_TTY* tty)
759
struct termios *ptermios;
762
ptermios = tty->ptermios;
763
switch (tty->baud_rate)
856
ptermios->c_cflag &= ~CBAUD;
857
ptermios->c_cflag |= speed;
859
/* on systems with separate ispeed and ospeed, we can remember the speed
860
in ispeed while changing DTR with ospeed */
861
cfsetispeed(tty->ptermios, speed);
862
cfsetospeed(tty->ptermios, tty->dtr ? speed : 0);
865
ptermios->c_cflag &= ~(CSTOPB | PARENB | PARODD | CSIZE | CRTSCTS);
866
switch (tty->stop_bits)
868
case SERIAL_STOP_BITS_2:
869
ptermios->c_cflag |= CSTOPB;
872
ptermios->c_cflag &= ~CSTOPB;
878
case SERIAL_EVEN_PARITY:
879
ptermios->c_cflag |= PARENB;
881
case SERIAL_ODD_PARITY:
882
ptermios->c_cflag |= PARENB | PARODD;
884
case SERIAL_NO_PARITY:
885
ptermios->c_cflag &= ~(PARENB | PARODD);
889
switch (tty->word_length)
892
ptermios->c_cflag |= CS5;
895
ptermios->c_cflag |= CS6;
898
ptermios->c_cflag |= CS7;
901
ptermios->c_cflag |= CS8;
907
ptermios->c_cflag |= CRTSCTS;
909
ptermios->c_cflag &= ~CRTSCTS;
912
if (tty->control & SERIAL_CTS_HANDSHAKE)
914
ptermios->c_cflag |= CRTSCTS;
918
ptermios->c_cflag &= ~CRTSCTS;
922
if (tty->xonoff & SERIAL_XON_HANDSHAKE)
924
ptermios->c_iflag |= IXON | IMAXBEL;
926
if (tty->xonoff & SERIAL_XOFF_HANDSHAKE)
928
ptermios->c_iflag |= IXOFF | IMAXBEL;
931
if ((tty->xonoff & (SERIAL_XOFF_HANDSHAKE | SERIAL_XON_HANDSHAKE)) == 0)
933
ptermios->c_iflag &= ~IXON;
934
ptermios->c_iflag &= ~IXOFF;
937
ptermios->c_cc[VSTART] = tty->chars[SERIAL_CHAR_XON];
938
ptermios->c_cc[VSTOP] = tty->chars[SERIAL_CHAR_XOFF];
939
ptermios->c_cc[VEOF] = tty->chars[SERIAL_CHAR_EOF];
940
ptermios->c_cc[VINTR] = tty->chars[SERIAL_CHAR_BREAK];
941
ptermios->c_cc[VKILL] = tty->chars[SERIAL_CHAR_ERROR];
943
tcsetattr(tty->fd, TCSANOW, ptermios);
946
static uint32 tty_write_data(SERIAL_TTY* tty, uint8* data, int len)
952
r = write(tty->fd, data, len);
954
return tty_get_error_status();
956
tty->event_txempty = r;
958
return STATUS_SUCCESS;
961
static int tty_get_error_status()
963
DEBUG_SVC("in errno %d", errno);
970
return STATUS_ACCESS_DENIED;
972
return STATUS_FILE_IS_A_DIRECTORY;
974
return STATUS_OBJECT_NAME_COLLISION;
976
return STATUS_INVALID_HANDLE;
978
return STATUS_NO_SUCH_FILE;