1 /* -*- c-basic-offset: 8 -*-
2 rdesktop: A Remote Desktop Protocol client.
3 Copyright (C) Matthew Chapman 1999-2005
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 Here are some resources, for your IRP hacking pleasure:
23 http://cvs.sourceforge.net/viewcvs.py/mingw/w32api/include/ddk/winddk.h?view=markup
25 http://win32.mvps.org/ntfs/streams.cpp
27 http://www.acc.umu.se/~bosse/ntifs.h
29 http://undocumented.ntinternals.net/UserMode/Undocumented%20Functions/NT%20Objects/File/
31 http://us1.samba.org/samba/ftp/specs/smb-nt01.txt
33 http://www.osronline.com/
37 #include <sys/types.h>
39 #include <dirent.h> /* opendir, closedir, readdir */
44 #define IRP_MJ_CREATE 0x00
45 #define IRP_MJ_CLOSE 0x02
46 #define IRP_MJ_READ 0x03
47 #define IRP_MJ_WRITE 0x04
48 #define IRP_MJ_QUERY_INFORMATION 0x05
49 #define IRP_MJ_SET_INFORMATION 0x06
50 #define IRP_MJ_QUERY_VOLUME_INFORMATION 0x0a
51 #define IRP_MJ_DIRECTORY_CONTROL 0x0c
52 #define IRP_MJ_DEVICE_CONTROL 0x0e
53 #define IRP_MJ_LOCK_CONTROL 0x11
55 #define IRP_MN_QUERY_DIRECTORY 0x01
56 #define IRP_MN_NOTIFY_CHANGE_DIRECTORY 0x02
58 extern DEVICE_FNS serial_fns
;
59 extern DEVICE_FNS printer_fns
;
60 extern DEVICE_FNS parallel_fns
;
61 extern DEVICE_FNS disk_fns
;
63 /* Return device_id for a given handle */
65 get_device_index(RDPCLIENT
* This
, NTHANDLE handle
)
68 for (i
= 0; i
< RDPDR_MAX_DEVICES
; i
++)
70 if (This
->rdpdr_device
[i
].handle
== handle
)
76 /* Converts a windows path to a unix path */
78 convert_to_unix_filename(char *filename
)
82 while ((p
= strchr(filename
, '\\')))
89 rdpdr_handle_ok(RDPCLIENT
* This
, int device
, int handle
)
91 switch (This
->rdpdr_device
[device
].device_type
)
93 case DEVICE_TYPE_PARALLEL
:
94 case DEVICE_TYPE_SERIAL
:
95 case DEVICE_TYPE_PRINTER
:
96 case DEVICE_TYPE_SCARD
:
97 if (This
->rdpdr_device
[device
].handle
!= handle
)
100 case DEVICE_TYPE_DISK
:
101 if (This
->fileinfo
[handle
].device_id
!= device
)
108 /* Add a new io request to the table containing pending io requests so it won't block rdesktop */
110 add_async_iorequest(RDPCLIENT
* This
, uint32 device
, uint32 file
, uint32 id
, uint32 major
, uint32 length
,
111 DEVICE_FNS
* fns
, uint32 total_timeout
, uint32 interval_timeout
, uint8
* buffer
,
114 struct async_iorequest
*iorq
;
116 if (This
->iorequest
== NULL
)
118 This
->iorequest
= (struct async_iorequest
*) xmalloc(sizeof(struct async_iorequest
));
119 if (!This
->iorequest
)
121 This
->iorequest
->fd
= 0;
122 This
->iorequest
->next
= NULL
;
125 iorq
= This
->iorequest
;
127 while (iorq
->fd
!= 0)
129 /* create new element if needed */
130 if (iorq
->next
== NULL
)
133 (struct async_iorequest
*) xmalloc(sizeof(struct async_iorequest
));
137 iorq
->next
->next
= NULL
;
141 iorq
->device
= device
;
145 iorq
->length
= length
;
146 iorq
->partial_len
= 0;
148 iorq
->timeout
= total_timeout
;
149 iorq
->itv_timeout
= interval_timeout
;
150 iorq
->buffer
= buffer
;
151 iorq
->offset
= offset
;
156 rdpdr_send_connect(RDPCLIENT
* This
)
158 uint8 magic
[4] = "rDCC";
161 s
= channel_init(This
, This
->rdpdr
.channel
, 12);
162 out_uint8a(s
, magic
, 4);
163 out_uint16_le(s
, 1); /* unknown */
165 out_uint32_be(s
, 0x815ed39d); /* IP address (use 127.0.0.1) 0x815ed39d */
167 channel_send(This
, s
, This
->rdpdr
.channel
);
172 rdpdr_send_name(RDPCLIENT
* This
)
174 uint8 magic
[4] = "rDNC";
178 if (NULL
== This
->rdpdr_clientname
)
180 This
->rdpdr_clientname
= This
->hostname
;
182 hostlen
= (strlen(This
->rdpdr_clientname
) + 1) * 2;
184 s
= channel_init(This
, This
->rdpdr
.channel
, 16 + hostlen
);
185 out_uint8a(s
, magic
, 4);
186 out_uint16_le(s
, 0x63); /* unknown */
187 out_uint16_le(s
, 0x72);
189 out_uint32_le(s
, hostlen
);
190 rdp_out_unistr(This
, s
, This
->rdpdr_clientname
, hostlen
- 2);
192 channel_send(This
, s
, This
->rdpdr
.channel
);
195 /* Returns the size of the payload of the announce packet */
197 announcedata_size(RDPCLIENT
* This
)
200 PRINTER
*printerinfo
;
202 size
= 8; /* static announce size */
203 size
+= This
->num_devices
* 0x14;
205 for (i
= 0; i
< This
->num_devices
; i
++)
207 if (This
->rdpdr_device
[i
].device_type
== DEVICE_TYPE_PRINTER
)
209 printerinfo
= (PRINTER
*) This
->rdpdr_device
[i
].pdevice_data
;
210 printerinfo
->bloblen
=
211 printercache_load_blob(printerinfo
->printer
, &(printerinfo
->blob
));
214 size
+= 2 * strlen(printerinfo
->driver
) + 2;
215 size
+= 2 * strlen(printerinfo
->printer
) + 2;
216 size
+= printerinfo
->bloblen
;
224 rdpdr_send_available(RDPCLIENT
* This
)
227 uint8 magic
[4] = "rDAD";
228 uint32 driverlen
, printerlen
, bloblen
;
231 PRINTER
*printerinfo
;
233 s
= channel_init(This
, This
->rdpdr
.channel
, announcedata_size(This
));
234 out_uint8a(s
, magic
, 4);
235 out_uint32_le(s
, This
->num_devices
);
237 for (i
= 0; i
< This
->num_devices
; i
++)
239 out_uint32_le(s
, This
->rdpdr_device
[i
].device_type
);
240 out_uint32_le(s
, i
); /* RDP Device ID */
241 /* Is it possible to use share names longer than 8 chars?
243 out_uint8p(s
, This
->rdpdr_device
[i
].name
, 8);
245 switch (This
->rdpdr_device
[i
].device_type
)
247 case DEVICE_TYPE_PRINTER
:
248 printerinfo
= (PRINTER
*) This
->rdpdr_device
[i
].pdevice_data
;
250 driverlen
= 2 * strlen(printerinfo
->driver
) + 2;
251 printerlen
= 2 * strlen(printerinfo
->printer
) + 2;
252 bloblen
= printerinfo
->bloblen
;
254 out_uint32_le(s
, 24 + driverlen
+ printerlen
+ bloblen
); /* length of extra info */
255 out_uint32_le(s
, printerinfo
->default_printer
? 2 : 0);
256 out_uint8s(s
, 8); /* unknown */
257 out_uint32_le(s
, driverlen
);
258 out_uint32_le(s
, printerlen
);
259 out_uint32_le(s
, bloblen
);
260 rdp_out_unistr(This
, s
, printerinfo
->driver
, driverlen
- 2);
261 rdp_out_unistr(This
, s
, printerinfo
->printer
, printerlen
- 2);
262 out_uint8a(s
, printerinfo
->blob
, bloblen
);
264 if (printerinfo
->blob
)
265 xfree(printerinfo
->blob
); /* Blob is sent twice if reconnecting */
272 out_uint32_le(s
, 0x20); /* Device type 0x20 - smart card */
274 out_uint8p(s
, "SCARD", 5);
280 channel_send(This
, s
, This
->rdpdr
.channel
);
284 rdpdr_send_completion(RDPCLIENT
* This
, uint32 device
, uint32 id
, uint32 status
, uint32 result
, uint8
* buffer
,
287 uint8 magic
[4] = "rDCI";
290 s
= channel_init(This
, This
->rdpdr
.channel
, 20 + length
);
291 out_uint8a(s
, magic
, 4);
292 out_uint32_le(s
, device
);
293 out_uint32_le(s
, id
);
294 out_uint32_le(s
, status
);
295 out_uint32_le(s
, result
);
296 out_uint8p(s
, buffer
, length
);
299 #ifdef WITH_DEBUG_RDP5
300 printf("--> rdpdr_send_completion\n");
301 /* hexdump(s->channel_hdr + 8, s->end - s->channel_hdr - 8); */
303 channel_send(This
, s
, This
->rdpdr
.channel
);
307 rdpdr_process_irp(RDPCLIENT
* This
, STREAM s
)
324 share_mode
, disposition
, total_timeout
, interval_timeout
, flags_and_attributes
= 0;
326 char filename
[PATH_MAX
];
327 uint8
*buffer
, *pst_buf
;
330 BOOL rw_blocking
= True
;
331 NTSTATUS status
= STATUS_INVALID_DEVICE_REQUEST
;
333 in_uint32_le(s
, device
);
334 in_uint32_le(s
, file
);
336 in_uint32_le(s
, major
);
337 in_uint32_le(s
, minor
);
340 buffer
= (uint8
*) xmalloc(1024);
343 switch (This
->rdpdr_device
[device
].device_type
)
345 case DEVICE_TYPE_SERIAL
:
351 case DEVICE_TYPE_PARALLEL
:
357 case DEVICE_TYPE_PRINTER
:
362 case DEVICE_TYPE_DISK
:
368 case DEVICE_TYPE_SCARD
:
371 error("IRP for bad device %ld\n", device
);
379 in_uint32_be(s
, desired_access
);
380 in_uint8s(s
, 0x08); /* unknown */
381 in_uint32_le(s
, error_mode
);
382 in_uint32_le(s
, share_mode
);
383 in_uint32_le(s
, disposition
);
384 in_uint32_le(s
, flags_and_attributes
);
385 in_uint32_le(s
, length
);
387 if (length
&& (length
/ 2) < 256)
389 rdp_in_unistr(This
, s
, filename
, length
);
390 convert_to_unix_filename(filename
);
399 status
= STATUS_NOT_SUPPORTED
;
403 status
= fns
->create(This
, device
, desired_access
, share_mode
, disposition
,
404 flags_and_attributes
, filename
, &result
);
411 status
= STATUS_NOT_SUPPORTED
;
415 status
= fns
->close(This
, file
);
422 status
= STATUS_NOT_SUPPORTED
;
426 in_uint32_le(s
, length
);
427 in_uint32_le(s
, offset
);
429 DEBUG(("RDPDR IRP Read (length: %d, offset: %d)\n", length
, offset
));
431 if (!rdpdr_handle_ok(This
, device
, file
))
433 status
= STATUS_INVALID_HANDLE
;
437 if (rw_blocking
) /* Complete read immediately */
439 buffer
= (uint8
*) xrealloc((void *) buffer
, length
);
442 status
= STATUS_CANCELLED
;
445 status
= fns
->read(This
, file
, buffer
, length
, offset
, &result
);
450 /* Add request to table */
451 pst_buf
= (uint8
*) xmalloc(length
);
454 status
= STATUS_CANCELLED
;
457 serial_get_timeout(This
, file
, length
, &total_timeout
, &interval_timeout
);
458 if (add_async_iorequest
459 (This
, device
, file
, id
, major
, length
, fns
, total_timeout
, interval_timeout
,
462 status
= STATUS_PENDING
;
466 status
= STATUS_CANCELLED
;
474 status
= STATUS_NOT_SUPPORTED
;
478 in_uint32_le(s
, length
);
479 in_uint32_le(s
, offset
);
482 DEBUG(("RDPDR IRP Write (length: %d)\n", result
));
484 if (!rdpdr_handle_ok(This
, device
, file
))
486 status
= STATUS_INVALID_HANDLE
;
490 if (rw_blocking
) /* Complete immediately */
492 status
= fns
->write(This
, file
, s
->p
, length
, offset
, &result
);
497 pst_buf
= (uint8
*) xmalloc(length
);
500 status
= STATUS_CANCELLED
;
504 in_uint8a(s
, pst_buf
, length
);
506 if (add_async_iorequest
507 (This
, device
, file
, id
, major
, length
, fns
, 0, 0, pst_buf
, offset
))
509 status
= STATUS_PENDING
;
513 status
= STATUS_CANCELLED
;
516 case IRP_MJ_QUERY_INFORMATION
:
518 if (This
->rdpdr_device
[device
].device_type
!= DEVICE_TYPE_DISK
)
520 status
= STATUS_INVALID_HANDLE
;
523 in_uint32_le(s
, info_level
);
525 out
.data
= out
.p
= buffer
;
526 out
.size
= sizeof(buffer
);
527 status
= disk_query_information(This
, file
, info_level
, &out
);
528 result
= buffer_len
= out
.p
- out
.data
;
532 case IRP_MJ_SET_INFORMATION
:
534 if (This
->rdpdr_device
[device
].device_type
!= DEVICE_TYPE_DISK
)
536 status
= STATUS_INVALID_HANDLE
;
540 in_uint32_le(s
, info_level
);
542 out
.data
= out
.p
= buffer
;
543 out
.size
= sizeof(buffer
);
544 status
= disk_set_information(This
, file
, info_level
, s
, &out
);
545 result
= buffer_len
= out
.p
- out
.data
;
548 case IRP_MJ_QUERY_VOLUME_INFORMATION
:
550 if (This
->rdpdr_device
[device
].device_type
!= DEVICE_TYPE_DISK
)
552 status
= STATUS_INVALID_HANDLE
;
556 in_uint32_le(s
, info_level
);
558 out
.data
= out
.p
= buffer
;
559 out
.size
= sizeof(buffer
);
560 status
= disk_query_volume_information(This
, file
, info_level
, &out
);
561 result
= buffer_len
= out
.p
- out
.data
;
564 case IRP_MJ_DIRECTORY_CONTROL
:
566 if (This
->rdpdr_device
[device
].device_type
!= DEVICE_TYPE_DISK
)
568 status
= STATUS_INVALID_HANDLE
;
574 case IRP_MN_QUERY_DIRECTORY
:
576 in_uint32_le(s
, info_level
);
578 in_uint32_le(s
, length
);
580 if (length
&& length
< 2 * 255)
582 rdp_in_unistr(This
, s
, filename
, length
);
583 convert_to_unix_filename(filename
);
589 out
.data
= out
.p
= buffer
;
590 out
.size
= sizeof(buffer
);
591 status
= disk_query_directory(This
, file
, info_level
, filename
,
593 result
= buffer_len
= out
.p
- out
.data
;
598 case IRP_MN_NOTIFY_CHANGE_DIRECTORY
:
601 unimpl("IRP major=0x%x minor=0x%x: IRP_MN_NOTIFY_CHANGE_DIRECTORY\n", major, minor); */
603 in_uint32_le(s
, info_level
); /* notify mask */
605 This
->notify_stamp
= True
;
607 status
= disk_create_notify(This
, file
, info_level
);
610 if (status
== STATUS_PENDING
)
611 add_async_iorequest(This
, device
, file
, id
, major
, length
,
617 status
= STATUS_INVALID_PARAMETER
;
619 unimpl("IRP major=0x%x minor=0x%x\n", major
, minor
);
623 case IRP_MJ_DEVICE_CONTROL
:
625 if (!fns
->device_control
)
627 status
= STATUS_NOT_SUPPORTED
;
631 in_uint32_le(s
, bytes_out
);
632 in_uint32_le(s
, bytes_in
);
633 in_uint32_le(s
, request
);
636 buffer
= (uint8
*) xrealloc((void *) buffer
, bytes_out
+ 0x14);
639 status
= STATUS_CANCELLED
;
643 out
.data
= out
.p
= buffer
;
644 out
.size
= sizeof(buffer
);
645 status
= fns
->device_control(This
, file
, request
, s
, &out
);
646 result
= buffer_len
= out
.p
- out
.data
;
648 /* Serial SERIAL_WAIT_ON_MASK */
649 if (status
== STATUS_PENDING
)
651 if (add_async_iorequest
652 (This
, device
, file
, id
, major
, length
, fns
, 0, 0, NULL
, 0))
654 status
= STATUS_PENDING
;
661 case IRP_MJ_LOCK_CONTROL
:
663 if (This
->rdpdr_device
[device
].device_type
!= DEVICE_TYPE_DISK
)
665 status
= STATUS_INVALID_HANDLE
;
669 in_uint32_le(s
, info_level
);
671 out
.data
= out
.p
= buffer
;
672 out
.size
= sizeof(buffer
);
673 /* FIXME: Perhaps consider actually *do*
674 something here :-) */
675 status
= STATUS_SUCCESS
;
676 result
= buffer_len
= out
.p
- out
.data
;
680 unimpl("IRP major=0x%x minor=0x%x\n", major
, minor
);
684 if (status
!= STATUS_PENDING
)
686 rdpdr_send_completion(This
, device
, id
, status
, result
, buffer
, buffer_len
);
694 rdpdr_send_clientcapabilty(RDPCLIENT
* This
)
696 uint8 magic
[4] = "rDPC";
699 s
= channel_init(This
, This
->rdpdr
.channel
, 0x50);
700 out_uint8a(s
, magic
, 4);
701 out_uint32_le(s
, 5); /* count */
702 out_uint16_le(s
, 1); /* first */
703 out_uint16_le(s
, 0x28); /* length */
710 out_uint16_le(s
, 0xFFFF);
716 out_uint16_le(s
, 2); /* second */
717 out_uint16_le(s
, 8); /* length */
719 out_uint16_le(s
, 3); /* third */
720 out_uint16_le(s
, 8); /* length */
722 out_uint16_le(s
, 4); /* fourth */
723 out_uint16_le(s
, 8); /* length */
725 out_uint16_le(s
, 5); /* fifth */
726 out_uint16_le(s
, 8); /* length */
730 channel_send(This
, s
, This
->rdpdr
.channel
);
734 rdpdr_process(RDPCLIENT
* This
, STREAM s
)
740 printf("--- rdpdr_process ---\n");
741 hexdump(s
->p
, s
->end
- s
->p
);
743 in_uint8p(s
, magic
, 4);
745 if ((magic
[0] == 'r') && (magic
[1] == 'D'))
747 if ((magic
[2] == 'R') && (magic
[3] == 'I'))
749 rdpdr_process_irp(This
, s
);
752 if ((magic
[2] == 'n') && (magic
[3] == 'I'))
754 rdpdr_send_connect(This
);
755 rdpdr_send_name(This
);
758 if ((magic
[2] == 'C') && (magic
[3] == 'C'))
760 /* connect from server */
761 rdpdr_send_clientcapabilty(This
);
762 rdpdr_send_available(This
);
765 if ((magic
[2] == 'r') && (magic
[3] == 'd'))
767 /* connect to a specific resource */
768 in_uint32(s
, handle
);
770 DEBUG(("RDPDR: Server connected to resource %d\n", handle
));
774 if ((magic
[2] == 'P') && (magic
[3] == 'S'))
776 /* server capability */
780 if ((magic
[0] == 'R') && (magic
[1] == 'P'))
782 if ((magic
[2] == 'C') && (magic
[3] == 'P'))
784 printercache_process(This
, s
);
788 unimpl("RDPDR packet type %c%c%c%c\n", magic
[0], magic
[1], magic
[2], magic
[3]);
792 rdpdr_init(RDPCLIENT
* This
)
794 if (This
->num_devices
> 0)
796 This
->rdpdr
.channel
=
797 channel_register(This
, "rdpdr",
798 CHANNEL_OPTION_INITIALIZED
| CHANNEL_OPTION_COMPRESS_RDP
,
802 return (This
->rdpdr
.channel
!= NULL
);
805 /* Add file descriptors of pending io request to select() */
807 rdpdr_add_fds(RDPCLIENT
* This
, int *n
, fd_set
* rfds
, fd_set
* wfds
, struct timeval
*tv
, BOOL
* timeout
)
809 uint32 select_timeout
= 0; /* Timeout value to be used for select() (in millisecons). */
810 struct async_iorequest
*iorq
;
813 iorq
= This
->iorequest
;
821 /* Is this FD valid? FDs will
823 reconnecting. FIXME: Real
824 support for reconnects. */
826 FD_SET(iorq
->fd
, rfds
);
827 *n
= MAX(*n
, iorq
->fd
);
829 /* Check if io request timeout is smaller than current (but not 0). */
831 && (select_timeout
== 0
832 || iorq
->timeout
< select_timeout
))
834 /* Set new timeout */
835 select_timeout
= iorq
->timeout
;
836 This
->min_timeout_fd
= iorq
->fd
; /* Remember fd */
837 tv
->tv_sec
= select_timeout
/ 1000;
838 tv
->tv_usec
= (select_timeout
% 1000) * 1000;
842 if (iorq
->itv_timeout
&& iorq
->partial_len
> 0
843 && (select_timeout
== 0
844 || iorq
->itv_timeout
< select_timeout
))
846 /* Set new timeout */
847 select_timeout
= iorq
->itv_timeout
;
848 This
->min_timeout_fd
= iorq
->fd
; /* Remember fd */
849 tv
->tv_sec
= select_timeout
/ 1000;
850 tv
->tv_usec
= (select_timeout
% 1000) * 1000;
857 /* FD still valid? See above. */
858 if ((write(iorq
->fd
, &c
, 0) != 0) && (errno
== EBADF
))
861 FD_SET(iorq
->fd
, wfds
);
862 *n
= MAX(*n
, iorq
->fd
);
865 case IRP_MJ_DEVICE_CONTROL
:
866 if (select_timeout
> 5)
867 select_timeout
= 5; /* serial event queue */
878 struct async_iorequest
*
879 rdpdr_remove_iorequest(RDPCLIENT
* This
, struct async_iorequest
*prev
, struct async_iorequest
*iorq
)
888 prev
->next
= iorq
->next
;
895 This
->iorequest
= iorq
->next
;
902 /* Check if select() returned with one of the rdpdr file descriptors, and complete io if it did */
904 _rdpdr_check_fds(RDPCLIENT
* This
, fd_set
* rfds
, fd_set
* wfds
, BOOL timed_out
)
909 struct async_iorequest
*iorq
;
910 struct async_iorequest
*prev
;
914 uint8
*buffer
= NULL
;
919 /* check serial iv_timeout */
921 iorq
= This
->iorequest
;
925 if (iorq
->fd
== This
->min_timeout_fd
)
927 if ((iorq
->partial_len
> 0) &&
928 (This
->rdpdr_device
[iorq
->device
].device_type
==
932 /* iv_timeout between 2 chars, send partial_len */
933 /*printf("RDPDR: IVT total %u bytes read of %u\n", iorq->partial_len, iorq->length); */
934 rdpdr_send_completion(This
, iorq
->device
,
935 iorq
->id
, STATUS_SUCCESS
,
937 iorq
->buffer
, iorq
->partial_len
);
938 iorq
= rdpdr_remove_iorequest(This
, prev
, iorq
);
959 rdpdr_abort_io(This
, This
->min_timeout_fd
, 0, STATUS_TIMEOUT
);
963 iorq
= This
->iorequest
;
972 if (FD_ISSET(iorq
->fd
, rfds
))
978 (iorq
->length
- iorq
->partial_len
) >
979 8192 ? 8192 : (iorq
->length
-
981 /* never read larger chunks than 8k - chances are that it will block */
982 status
= fns
->read(This
, iorq
->fd
,
983 iorq
->buffer
+ iorq
->partial_len
,
984 req_size
, iorq
->offset
, &result
);
986 if ((long) result
> 0)
988 iorq
->partial_len
+= result
;
989 iorq
->offset
+= result
;
992 DEBUG(("RDPDR: %d bytes of data read\n", result
));
994 /* only delete link if all data has been transfered */
995 /* or if result was 0 and status success - EOF */
996 if ((iorq
->partial_len
== iorq
->length
) ||
1000 DEBUG(("RDPDR: AIO total %u bytes read of %u\n", iorq
->partial_len
, iorq
->length
));
1002 rdpdr_send_completion(This
, iorq
->device
,
1007 iorq
= rdpdr_remove_iorequest(This
, prev
, iorq
);
1012 if (FD_ISSET(iorq
->fd
, wfds
))
1018 (iorq
->length
- iorq
->partial_len
) >
1019 8192 ? 8192 : (iorq
->length
-
1022 /* never write larger chunks than 8k - chances are that it will block */
1023 status
= fns
->write(This
, iorq
->fd
,
1025 iorq
->partial_len
, req_size
,
1026 iorq
->offset
, &result
);
1028 if ((long) result
> 0)
1030 iorq
->partial_len
+= result
;
1031 iorq
->offset
+= result
;
1035 DEBUG(("RDPDR: %d bytes of data written\n",
1038 /* only delete link if all data has been transfered */
1039 /* or we couldn't write */
1040 if ((iorq
->partial_len
== iorq
->length
)
1044 DEBUG(("RDPDR: AIO total %u bytes written of %u\n", iorq
->partial_len
, iorq
->length
));
1046 rdpdr_send_completion(This
, iorq
->device
,
1051 iorq
= rdpdr_remove_iorequest(This
, prev
, iorq
);
1055 case IRP_MJ_DEVICE_CONTROL
:
1056 if (serial_get_event(This
, iorq
->fd
, &result
))
1058 buffer
= (uint8
*) xrealloc((void *) buffer
, 0x14);
1059 out
.data
= out
.p
= buffer
;
1060 out
.size
= sizeof(buffer
);
1061 out_uint32_le(&out
, result
);
1062 result
= buffer_len
= out
.p
- out
.data
;
1063 status
= STATUS_SUCCESS
;
1064 rdpdr_send_completion(This
, iorq
->device
, iorq
->id
,
1065 status
, result
, buffer
,
1068 iorq
= rdpdr_remove_iorequest(This
, prev
, iorq
);
1081 iorq
= This
->iorequest
;
1083 while (iorq
!= NULL
)
1087 switch (iorq
->major
)
1090 case IRP_MJ_DIRECTORY_CONTROL
:
1091 if (This
->rdpdr_device
[iorq
->device
].device_type
==
1095 if (This
->notify_stamp
)
1097 This
->notify_stamp
= False
;
1098 status
= disk_check_notify(This
, iorq
->fd
);
1099 if (status
!= STATUS_PENDING
)
1101 rdpdr_send_completion(This
, iorq
->device
,
1105 iorq
= rdpdr_remove_iorequest(This
, prev
,
1125 rdpdr_check_fds(RDPCLIENT
* This
, fd_set
* rfds
, fd_set
* wfds
, BOOL timed_out
)
1133 /* fist check event queue only,
1134 any serial wait event must be done before read block will be sent
1137 _rdpdr_check_fds(This
, &dummy
, &dummy
, False
);
1138 _rdpdr_check_fds(This
, rfds
, wfds
, timed_out
);
1142 /* Abort a pending io request for a given handle and major */
1144 rdpdr_abort_io(RDPCLIENT
* This
, uint32 fd
, uint32 major
, NTSTATUS status
)
1147 struct async_iorequest
*iorq
;
1148 struct async_iorequest
*prev
;
1150 iorq
= This
->iorequest
;
1152 while (iorq
!= NULL
)
1154 /* Only remove from table when major is not set, or when correct major is supplied.
1155 Abort read should not abort a write io request. */
1156 if ((iorq
->fd
== fd
) && (major
== 0 || iorq
->major
== major
))
1159 rdpdr_send_completion(This
, iorq
->device
, iorq
->id
, status
, result
, (uint8
*) "",
1162 iorq
= rdpdr_remove_iorequest(This
, prev
, iorq
);