/[rdesktop]/sourceforge.net/trunk/rdesktop/rdpdr.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Contents of /sourceforge.net/trunk/rdesktop/rdpdr.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 569 - (show annotations)
Wed Jan 21 14:40:40 2004 UTC (20 years, 3 months ago) by n-ki
File MIME type: text/plain
File size: 17536 byte(s)
redirection of disk, lptport, printer, comport.

1 #include "rdesktop.h"
2
3 #define IRP_MJ_CREATE 0x00
4 #define IRP_MJ_CLOSE 0x02
5 #define IRP_MJ_READ 0x03
6 #define IRP_MJ_WRITE 0x04
7 #define IRP_MJ_DEVICE_CONTROL 0x0e
8
9 #define IRP_MJ_CREATE 0x00
10 #define IRP_MJ_CLOSE 0x02
11 #define IRP_MJ_READ 0x03
12 #define IRP_MJ_WRITE 0x04
13 #define IRP_MJ_QUERY_INFORMATION 0x05
14 #define IRP_MJ_SET_INFORMATION 0x06
15 #define IRP_MJ_QUERY_VOLUME_INFORMATION 0x0a
16 #define IRP_MJ_DIRECTORY_CONTROL 0x0c
17 #define IRP_MJ_DEVICE_CONTROL 0x0e
18
19 #define IRP_MN_QUERY_DIRECTORY 0x01
20 #define IRP_MN_NOTIFY_CHANGE_DIRECTORY 0x02
21
22 #define MAX_ASYNC_IO_REQUESTS 10
23
24 extern char hostname[16];
25 extern DEVICE_FNS serial_fns;
26 extern DEVICE_FNS printer_fns;
27 extern DEVICE_FNS parallel_fns;
28 extern DEVICE_FNS disk_fns;
29
30
31 static VCHANNEL *rdpdr_channel;
32
33 /* If select() times out, the request for the device with handle g_min_timeout_fd is aborted */
34 HANDLE g_min_timeout_fd;
35 uint32 g_num_devices;
36
37 /* Table with information about rdpdr devices */
38 RDPDR_DEVICE g_rdpdr_device[RDPDR_MAX_DEVICES];
39
40 /* Used to store incoming io request, until they are ready to be completed */
41 struct async_iorequest
42 {
43 uint32 fd, major, minor, offset, device, id, length;
44 long timeout, /* Total timeout */
45 itv_timeout; /* Interval timeout (between serial characters) */
46 uint8 *buffer;
47 DEVICE_FNS *fns;
48 } g_iorequest[MAX_ASYNC_IO_REQUESTS];
49
50 /* Return device_id for a given handle */
51 int
52 get_device_index(HANDLE handle)
53 {
54 int i;
55 for (i = 0; i < RDPDR_MAX_DEVICES; i++)
56 {
57 if (g_rdpdr_device[i].handle == handle)
58 return i;
59 }
60 return -1;
61 }
62
63 /* Converts a windows path to a unix path */
64 void
65 convert_to_unix_filename(char *filename)
66 {
67 char *p;
68
69 while ((p = strchr(filename, '\\')))
70 {
71 *p = '/';
72 }
73 }
74
75 /* Add a new io request to the table containing pending io requests so it won't block rdesktop */
76 BOOL
77 add_async_iorequest(uint32 device, uint32 file, uint32 id, uint32 major, uint32 length,
78 DEVICE_FNS * fns, long total_timeout, long interval_timeout, uint8 * buffer)
79 {
80 int i;
81 struct async_iorequest *iorq;
82
83 for (i = 0; i < MAX_ASYNC_IO_REQUESTS; i++)
84 {
85 iorq = &g_iorequest[i];
86
87 if (iorq->fd == 0)
88 {
89 iorq->device = device;
90 iorq->fd = file;
91 iorq->id = id;
92 iorq->major = major;
93 iorq->length = length;
94 iorq->fns = fns;
95 iorq->timeout = total_timeout;
96 iorq->itv_timeout = interval_timeout;
97 iorq->buffer = buffer;
98 return True;
99 }
100 }
101 error("IO request table full. Increase MAX_ASYNC_IO_REQUESTS in rdpdr.c!\n");
102 return False;
103 }
104
105
106 void
107 rdpdr_send_connect(void)
108 {
109 uint8 magic[4] = "rDCC";
110 STREAM s;
111
112 s = channel_init(rdpdr_channel, 12);
113 out_uint8a(s, magic, 4);
114 out_uint16_le(s, 1); /* unknown */
115 out_uint16_le(s, 5);
116 out_uint32_be(s, 0x815ed39d); /* IP address (use 127.0.0.1) 0x815ed39d */
117 s_mark_end(s);
118 channel_send(s, rdpdr_channel);
119 }
120
121
122 void
123 rdpdr_send_name(void)
124 {
125 uint8 magic[4] = "rDNC";
126 uint32 hostlen = (strlen(hostname) + 1) * 2;
127 STREAM s;
128
129 s = channel_init(rdpdr_channel, 16 + hostlen);
130 out_uint8a(s, magic, 4);
131 out_uint16_le(s, 0x63); /* unknown */
132 out_uint16_le(s, 0x72);
133 out_uint32(s, 0);
134 out_uint32_le(s, hostlen);
135 rdp_out_unistr(s, hostname, hostlen - 2);
136 s_mark_end(s);
137 channel_send(s, rdpdr_channel);
138 }
139
140 /* Returns the size of the payload of the announce packet */
141 int
142 announcedata_size()
143 {
144 int size, i;
145 PRINTER *printerinfo;
146
147 size = 8; //static announce size
148 size += g_num_devices * 0x14;
149
150 for (i = 0; i < g_num_devices; i++)
151 {
152 if (g_rdpdr_device[i].device_type == DEVICE_TYPE_PRINTER)
153 {
154 printerinfo = (PRINTER *) g_rdpdr_device[i].pdevice_data;
155 printerinfo->bloblen =
156 printercache_load_blob(printerinfo->printer, &(printerinfo->blob));
157
158 size += 0x18;
159 size += 2 * strlen(printerinfo->driver) + 2;
160 size += 2 * strlen(printerinfo->printer) + 2;
161 size += printerinfo->bloblen;
162 }
163 }
164
165 return size;
166 }
167
168 void
169 rdpdr_send_available(void)
170 {
171
172 uint8 magic[4] = "rDAD";
173 uint32 driverlen, printerlen, bloblen;
174 int i;
175 STREAM s;
176 PRINTER *printerinfo;
177
178 s = channel_init(rdpdr_channel, announcedata_size());
179 out_uint8a(s, magic, 4);
180 out_uint32_le(s, g_num_devices);
181
182 for (i = 0; i < g_num_devices; i++)
183 {
184 out_uint32_le(s, g_rdpdr_device[i].device_type);
185 out_uint32_le(s, i); /* RDP Device ID */
186 out_uint8p(s, g_rdpdr_device[i].name, 8);
187
188 if (g_rdpdr_device[i].device_type == DEVICE_TYPE_PRINTER)
189 {
190 printerinfo = (PRINTER *) g_rdpdr_device[i].pdevice_data;
191
192 driverlen = 2 * strlen(printerinfo->driver) + 2;
193 printerlen = 2 * strlen(printerinfo->printer) + 2;
194 bloblen = printerinfo->bloblen;
195
196 out_uint32_le(s, 24 + driverlen + printerlen + bloblen); /* length of extra info */
197 out_uint32_le(s, printerinfo->default_printer ? 2 : 0);
198 out_uint8s(s, 8); /* unknown */
199 out_uint32_le(s, driverlen);
200 out_uint32_le(s, printerlen);
201 out_uint32_le(s, bloblen);
202 rdp_out_unistr(s, printerinfo->driver, driverlen - 2);
203 rdp_out_unistr(s, printerinfo->printer, printerlen - 2);
204 out_uint8a(s, printerinfo->blob, bloblen);
205
206 xfree(printerinfo->blob); /* Blob is sent twice if reconnecting */
207 }
208 else
209 {
210 out_uint32(s, 0);
211 }
212 }
213 #if 0
214 out_uint32_le(s, 0x20); /* Device type 0x20 - smart card */
215 out_uint32_le(s, 0);
216 out_uint8p(s, "SCARD", 5);
217 out_uint8s(s, 3);
218 out_uint32(s, 0);
219 #endif
220
221 s_mark_end(s);
222 channel_send(s, rdpdr_channel);
223 }
224
225 void
226 rdpdr_send_completion(uint32 device, uint32 id, uint32 status, uint32 result, uint8 * buffer,
227 uint32 length)
228 {
229 uint8 magic[4] = "rDCI";
230 STREAM s;
231
232 s = channel_init(rdpdr_channel, 20 + length);
233 out_uint8a(s, magic, 4);
234 out_uint32_le(s, device);
235 out_uint32_le(s, id);
236 out_uint32_le(s, status);
237 out_uint32_le(s, result);
238 out_uint8p(s, buffer, length);
239 s_mark_end(s);
240 /* JIF
241 hexdump(s->channel_hdr + 8, s->end - s->channel_hdr - 8); */
242 channel_send(s, rdpdr_channel);
243 }
244
245 static void
246 rdpdr_process_irp(STREAM s)
247 {
248 uint32 result = 0,
249 length = 0,
250 desired_access = 0,
251 request,
252 file,
253 info_level,
254 buffer_len,
255 id,
256 major,
257 minor,
258 device,
259 offset,
260 bytes_in,
261 bytes_out,
262 error_mode,
263 share_mode, disposition, total_timeout, interval_timeout, flags_and_attributes = 0;
264
265 char filename[256];
266 uint8 *buffer, *pst_buf;
267 struct stream out;
268 DEVICE_FNS *fns;
269 BOOL rw_blocking = True;
270 NTSTATUS status = STATUS_INVALID_DEVICE_REQUEST;
271
272 in_uint32_le(s, device);
273 in_uint32_le(s, file);
274 in_uint32_le(s, id);
275 in_uint32_le(s, major);
276 in_uint32_le(s, minor);
277
278 buffer_len = 0;
279 buffer = (uint8 *) xmalloc(1024);
280 buffer[0] = 0;
281
282
283 switch (g_rdpdr_device[device].device_type)
284 {
285 case DEVICE_TYPE_SERIAL:
286
287 fns = &serial_fns;
288 rw_blocking = False;
289 break;
290
291 case DEVICE_TYPE_PARALLEL:
292
293 fns = &parallel_fns;
294 rw_blocking = False;
295 break;
296
297 case DEVICE_TYPE_PRINTER:
298
299 fns = &printer_fns;
300 break;
301
302 case DEVICE_TYPE_DISK:
303
304 fns = &disk_fns;
305 break;
306
307 case DEVICE_TYPE_SCARD:
308 default:
309
310 error("IRP for bad device %ld\n", device);
311 return;
312 }
313
314 switch (major)
315 {
316 case IRP_MJ_CREATE:
317
318 in_uint32_be(s, desired_access);
319 in_uint8s(s, 0x08); // unknown
320 in_uint32_le(s, error_mode);
321 in_uint32_le(s, share_mode);
322 in_uint32_le(s, disposition);
323 in_uint32_le(s, flags_and_attributes);
324 in_uint32_le(s, length);
325
326 if (length && (length / 2) < 256)
327 {
328 rdp_in_unistr(s, filename, length);
329 convert_to_unix_filename(filename);
330 }
331 else
332 {
333 filename[0] = 0;
334 }
335
336 if (!fns->create)
337 {
338 status = STATUS_NOT_SUPPORTED;
339 break;
340 }
341
342 status = fns->create(device, desired_access, share_mode, disposition,
343 flags_and_attributes, filename, &result);
344 buffer_len = 1;
345 break;
346
347 case IRP_MJ_CLOSE:
348 if (!fns->close)
349 {
350 status = STATUS_NOT_SUPPORTED;
351 break;
352 }
353
354 status = fns->close(file);
355 break;
356
357 case IRP_MJ_READ:
358
359 if (!fns->read)
360 {
361 status = STATUS_NOT_SUPPORTED;
362 break;
363 }
364
365 in_uint32_le(s, length);
366 in_uint32_le(s, offset);
367 #if WITH_DEBUG_RDP5
368 DEBUG(("RDPDR IRP Read (length: %d, offset: %d)\n", length, offset));
369 #endif
370 if (rw_blocking) // Complete read immediately
371 {
372 buffer = (uint8 *) xrealloc((void *) buffer, length);
373 status = fns->read(file, buffer, length, offset, &result);
374 buffer_len = result;
375 break;
376 }
377
378 // Add request to table
379 pst_buf = (uint8 *) xmalloc(length);
380 serial_get_timeout(file, length, &total_timeout, &interval_timeout);
381 if (add_async_iorequest
382 (device, file, id, major, length, fns, total_timeout, interval_timeout,
383 pst_buf))
384 {
385 status = STATUS_PENDING;
386 break;
387 }
388
389 status = STATUS_CANCELLED;
390 break;
391
392 case IRP_MJ_WRITE:
393
394 buffer_len = 1;
395
396 if (!fns->write)
397 {
398 status = STATUS_NOT_SUPPORTED;
399 break;
400 }
401
402 in_uint32_le(s, length);
403 in_uint32_le(s, offset);
404 in_uint8s(s, 0x18);
405 #if WITH_DEBUG_RDP5
406 DEBUG(("RDPDR IRP Write (length: %d)\n", result));
407 #endif
408 if (rw_blocking) // Complete immediately
409 {
410 status = fns->write(file, s->p, length, offset, &result);
411 break;
412 }
413
414 // Add to table
415 pst_buf = (uint8 *) xmalloc(length);
416 in_uint8a(s, pst_buf, length);
417
418 if (add_async_iorequest
419 (device, file, id, major, length, fns, 0, 0, pst_buf))
420 {
421 status = STATUS_PENDING;
422 break;
423 }
424
425 status = STATUS_CANCELLED;
426 break;
427
428 case IRP_MJ_QUERY_INFORMATION:
429
430 if (g_rdpdr_device[device].device_type != DEVICE_TYPE_DISK)
431 {
432 status = STATUS_INVALID_HANDLE;
433 break;
434 }
435 in_uint32_le(s, info_level);
436
437 out.data = out.p = buffer;
438 out.size = sizeof(buffer);
439 status = disk_query_information(file, info_level, &out);
440 result = buffer_len = out.p - out.data;
441
442 break;
443
444 case IRP_MJ_SET_INFORMATION:
445
446 if (g_rdpdr_device[device].device_type != DEVICE_TYPE_DISK)
447 {
448 status = STATUS_INVALID_HANDLE;
449 break;
450 }
451
452 in_uint32_le(s, info_level);
453
454 out.data = out.p = buffer;
455 out.size = sizeof(buffer);
456 status = disk_set_information(file, info_level, s, &out);
457 result = buffer_len = out.p - out.data;
458 break;
459
460 case IRP_MJ_QUERY_VOLUME_INFORMATION:
461
462 if (g_rdpdr_device[device].device_type != DEVICE_TYPE_DISK)
463 {
464 status = STATUS_INVALID_HANDLE;
465 break;
466 }
467
468 in_uint32_le(s, info_level);
469
470 out.data = out.p = buffer;
471 out.size = sizeof(buffer);
472 status = disk_query_volume_information(file, info_level, &out);
473 result = buffer_len = out.p - out.data;
474 break;
475
476 case IRP_MJ_DIRECTORY_CONTROL:
477
478 if (g_rdpdr_device[device].device_type != DEVICE_TYPE_DISK)
479 {
480 status = STATUS_INVALID_HANDLE;
481 break;
482 }
483
484 switch (minor)
485 {
486 case IRP_MN_QUERY_DIRECTORY:
487
488 in_uint32_le(s, info_level);
489 in_uint8s(s, 1);
490 in_uint32_le(s, length);
491 in_uint8s(s, 0x17);
492 if (length && length < 2 * 255)
493 {
494 rdp_in_unistr(s, filename, length);
495 convert_to_unix_filename(filename);
496 }
497 else
498 {
499 filename[0] = 0;
500 }
501 out.data = out.p = buffer;
502 out.size = sizeof(buffer);
503 status = disk_query_directory(file, info_level, filename,
504 &out);
505 result = buffer_len = out.p - out.data;
506 if (!buffer_len)
507 buffer_len++;
508 break;
509
510 case IRP_MN_NOTIFY_CHANGE_DIRECTORY:
511
512 /* JIF
513 unimpl("IRP major=0x%x minor=0x%x: IRP_MN_NOTIFY_CHANGE_DIRECTORY\n", major, minor); */
514 status = STATUS_PENDING; // Don't send completion packet
515 break;
516
517 default:
518
519 status = STATUS_INVALID_PARAMETER;
520 /* JIF
521 unimpl("IRP major=0x%x minor=0x%x\n", major, minor); */
522 }
523 break;
524
525 case IRP_MJ_DEVICE_CONTROL:
526
527 if (!fns->device_control)
528 {
529 status = STATUS_NOT_SUPPORTED;
530 break;
531 }
532
533 in_uint32_le(s, bytes_out);
534 in_uint32_le(s, bytes_in);
535 in_uint32_le(s, request);
536 in_uint8s(s, 0x14);
537
538 buffer = (uint8 *) xrealloc((void *) buffer, bytes_out + 0x14);
539 out.data = out.p = buffer;
540 out.size = sizeof(buffer);
541 status = fns->device_control(file, request, s, &out);
542 result = buffer_len = out.p - out.data;
543 break;
544
545 default:
546 unimpl("IRP major=0x%x minor=0x%x\n", major, minor);
547 break;
548 }
549
550 if (status != STATUS_PENDING)
551 {
552 rdpdr_send_completion(device, id, status, result, buffer, buffer_len);
553 }
554 xfree(buffer);
555
556 }
557
558 void
559 rdpdr_send_clientcapabilty(void)
560 {
561 uint8 magic[4] = "rDPC";
562 STREAM s;
563
564 s = channel_init(rdpdr_channel, 0x50);
565 out_uint8a(s, magic, 4);
566 out_uint32_le(s, 5); /* count */
567 out_uint16_le(s, 1); /* first */
568 out_uint16_le(s, 0x28); /* length */
569 out_uint32_le(s, 1);
570 out_uint32_le(s, 2);
571 out_uint16_le(s, 2);
572 out_uint16_le(s, 5);
573 out_uint16_le(s, 1);
574 out_uint16_le(s, 5);
575 out_uint16_le(s, 0xFFFF);
576 out_uint16_le(s, 0);
577 out_uint32_le(s, 0);
578 out_uint32_le(s, 3);
579 out_uint32_le(s, 0);
580 out_uint32_le(s, 0);
581 out_uint16_le(s, 2); /* second */
582 out_uint16_le(s, 8); /* length */
583 out_uint32_le(s, 1);
584 out_uint16_le(s, 3); /* third */
585 out_uint16_le(s, 8); /* length */
586 out_uint32_le(s, 1);
587 out_uint16_le(s, 4); /* fourth */
588 out_uint16_le(s, 8); /* length */
589 out_uint32_le(s, 1);
590 out_uint16_le(s, 5); /* fifth */
591 out_uint16_le(s, 8); /* length */
592 out_uint32_le(s, 1);
593
594 s_mark_end(s);
595 channel_send(s, rdpdr_channel);
596 }
597
598 static void
599 rdpdr_process(STREAM s)
600 {
601 uint32 handle;
602 uint8 *magic;
603
604 #if WITH_DEBUG_RDP5
605 printf("--- rdpdr_process ---\n");
606 hexdump(s->p, s->end - s->p);
607 #endif
608 in_uint8p(s, magic, 4);
609
610 if ((magic[0] == 'r') && (magic[1] == 'D'))
611 {
612 if ((magic[2] == 'R') && (magic[3] == 'I'))
613 {
614 rdpdr_process_irp(s);
615 return;
616 }
617 if ((magic[2] == 'n') && (magic[3] == 'I'))
618 {
619 rdpdr_send_connect();
620 rdpdr_send_name();
621 return;
622 }
623 if ((magic[2] == 'C') && (magic[3] == 'C'))
624 {
625 /* connect from server */
626 rdpdr_send_clientcapabilty();
627 rdpdr_send_available();
628 return;
629 }
630 if ((magic[2] == 'r') && (magic[3] == 'd'))
631 {
632 /* connect to a specific resource */
633 in_uint32(s, handle);
634 #if WITH_DEBUG_RDP5
635 DEBUG(("RDPDR: Server connected to resource %d\n", handle));
636 #endif
637 return;
638 }
639 if ((magic[2] == 'P') && (magic[3] == 'S'))
640 {
641 /* server capability */
642 return;
643 }
644 }
645 if ((magic[0] == 'R') && (magic[1] == 'P'))
646 {
647 if ((magic[2] == 'C') && (magic[3] == 'P'))
648 {
649 printercache_process(s);
650 return;
651 }
652 }
653 unimpl("RDPDR packet type %c%c%c%c\n", magic[0], magic[1], magic[2], magic[3]);
654 }
655
656 BOOL
657 rdpdr_init()
658 {
659 if (g_num_devices > 0)
660 {
661 rdpdr_channel = channel_register("rdpdr", CHANNEL_OPTION_INITIALIZED | CHANNEL_OPTION_COMPRESS_RDP, rdpdr_process);
662 }
663
664 return (rdpdr_channel != NULL);
665 }
666
667 /* Add file descriptors of pending io request to select() */
668 void
669 rdpdr_add_fds(int *n, fd_set * rfds, fd_set * wfds, struct timeval *tv, BOOL * timeout)
670 {
671 int i;
672 long select_timeout = 0; // Timeout value to be used for select() (in millisecons).
673 struct async_iorequest *iorq;
674
675 for (i = 0; i < MAX_ASYNC_IO_REQUESTS; i++)
676 {
677 iorq = &g_iorequest[i];
678
679 if (iorq->fd != 0) // Found a pending io request
680 {
681 switch (iorq->major)
682 {
683 case IRP_MJ_READ:
684
685 FD_SET(iorq->fd, rfds);
686
687 // Check if io request timeout is smaller than current (but not 0).
688 if (iorq->timeout
689 && (select_timeout == 0
690 || iorq->timeout < select_timeout))
691 {
692 // Set new timeout
693 select_timeout = iorq->timeout;
694 g_min_timeout_fd = iorq->fd; /* Remember fd */
695 tv->tv_sec = select_timeout / 1000;
696 tv->tv_usec = (select_timeout % 1000) * 1000;
697 *timeout = True;
698 }
699 break;
700
701 case IRP_MJ_WRITE:
702
703 FD_SET(iorq->fd, wfds);
704 break;
705
706 }
707 *n = MAX(*n, iorq->fd);
708 }
709 }
710 }
711
712 /* Check if select() returned with one of the rdpdr file descriptors, and complete io if it did */
713 void
714 rdpdr_check_fds(fd_set * rfds, fd_set * wfds, BOOL timed_out)
715 {
716 int i;
717 NTSTATUS status;
718 uint32 result = 0, buffer_len = 0;
719 DEVICE_FNS *fns;
720 struct async_iorequest *iorq;
721
722 if (timed_out)
723 {
724 rdpdr_abort_io(g_min_timeout_fd, 0, STATUS_TIMEOUT);
725 return;
726 }
727
728 // Walk through array of pending io_rq's
729 for (i = 0; i < MAX_ASYNC_IO_REQUESTS; i++)
730 {
731 iorq = &g_iorequest[i];
732
733 if (iorq->fd != 0)
734 {
735 switch (iorq->major)
736 {
737
738 case IRP_MJ_READ:
739
740 if (FD_ISSET(iorq->fd, rfds))
741 {
742 // Read, and send data.
743 fns = iorq->fns;
744 status = fns->read(iorq->fd, iorq->buffer,
745 iorq->length, 0, &result);
746 buffer_len = result;
747
748 rdpdr_send_completion(iorq->device, iorq->id,
749 status, result, iorq->buffer,
750 buffer_len);
751 #if WITH_DEBUG_RDP5
752 DEBUG(("RDPDR: %d bytes of data read\n", result));
753 #endif
754 xfree(iorq->buffer);
755 iorq->fd = 0;
756 }
757 break;
758
759 case IRP_MJ_WRITE:
760
761 if (FD_ISSET(iorq->fd, wfds))
762 {
763 // Write data and send completion.
764 fns = iorq->fns;
765 status = fns->write(iorq->fd, iorq->buffer,
766 iorq->length, 0, &result);
767 rdpdr_send_completion(iorq->device, iorq->id,
768 status, result, "", 1);
769
770 xfree(iorq->buffer);
771 iorq->fd = 0;
772 }
773 break;
774 }
775 }
776 }
777 }
778
779 /* Abort a pending io request for a given handle and major */
780 BOOL
781 rdpdr_abort_io(uint32 fd, uint32 major, NTSTATUS status)
782 {
783 uint32 result;
784 int i;
785 struct async_iorequest *iorq;
786
787 for (i = 0; i < MAX_ASYNC_IO_REQUESTS; i++)
788 {
789 iorq = &g_iorequest[i];
790
791 // Only remove from table when major is not set, or when correct major is supplied.
792 // Abort read should not abort a write io request.
793 if ((iorq->fd == fd) && (major == 0 || iorq->major == major))
794 {
795 result = 0;
796 rdpdr_send_completion(iorq->device, iorq->id, status, result, "", 1);
797 xfree(iorq->buffer);
798 iorq->fd = 0;
799 return True;
800 }
801 }
802 return False;
803 }

  ViewVC Help
Powered by ViewVC 1.1.26