FreeRDP
drive_main.c
1 
24 #include <freerdp/config.h>
25 
26 #include <errno.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 
31 #include <winpr/crt.h>
32 #include <winpr/assert.h>
33 #include <winpr/path.h>
34 #include <winpr/file.h>
35 #include <winpr/string.h>
36 #include <winpr/synch.h>
37 #include <winpr/thread.h>
38 #include <winpr/stream.h>
39 #include <winpr/environment.h>
40 #include <winpr/interlocked.h>
41 #include <winpr/collections.h>
42 #include <winpr/shell.h>
43 
44 #include <freerdp/freerdp.h>
45 #include <freerdp/channels/rdpdr.h>
46 
47 #include "drive_file.h"
48 
49 typedef struct
50 {
51  DEVICE device;
52 
53  WCHAR* path;
54  BOOL automount;
55  UINT32 PathLength;
56  wListDictionary* files;
57 
58  HANDLE thread;
59  BOOL async;
60  wMessageQueue* IrpQueue;
61 
62  DEVMAN* devman;
63 
64  rdpContext* rdpcontext;
65 } DRIVE_DEVICE;
66 
67 static INT32 drive_map_windows_err(DWORD fs_errno)
68 {
69  INT32 rc = 0;
70 
71  /* try to return NTSTATUS version of error code */
72 
73  switch (fs_errno)
74  {
75  case STATUS_SUCCESS:
76  rc = STATUS_SUCCESS;
77  break;
78 
79  case ERROR_ACCESS_DENIED:
80  case ERROR_SHARING_VIOLATION:
81  rc = STATUS_ACCESS_DENIED;
82  break;
83 
84  case ERROR_FILE_NOT_FOUND:
85  rc = STATUS_NO_SUCH_FILE;
86  break;
87 
88  case ERROR_BUSY_DRIVE:
89  rc = STATUS_DEVICE_BUSY;
90  break;
91 
92  case ERROR_INVALID_DRIVE:
93  rc = STATUS_NO_SUCH_DEVICE;
94  break;
95 
96  case ERROR_NOT_READY:
97  rc = STATUS_NO_SUCH_DEVICE;
98  break;
99 
100  case ERROR_FILE_EXISTS:
101  case ERROR_ALREADY_EXISTS:
102  rc = STATUS_OBJECT_NAME_COLLISION;
103  break;
104 
105  case ERROR_INVALID_NAME:
106  rc = STATUS_NO_SUCH_FILE;
107  break;
108 
109  case ERROR_INVALID_HANDLE:
110  rc = STATUS_INVALID_HANDLE;
111  break;
112 
113  case ERROR_NO_MORE_FILES:
114  rc = STATUS_NO_MORE_FILES;
115  break;
116 
117  case ERROR_DIRECTORY:
118  rc = STATUS_NOT_A_DIRECTORY;
119  break;
120 
121  case ERROR_PATH_NOT_FOUND:
122  rc = STATUS_OBJECT_PATH_NOT_FOUND;
123  break;
124 
125  default:
126  rc = STATUS_UNSUCCESSFUL;
127  WLog_ERR(TAG, "Error code not found: %" PRIu32 "", fs_errno);
128  break;
129  }
130 
131  return rc;
132 }
133 
134 static DRIVE_FILE* drive_get_file_by_id(DRIVE_DEVICE* drive, UINT32 id)
135 {
136  DRIVE_FILE* file = NULL;
137  void* key = (void*)(size_t)id;
138 
139  if (!drive)
140  return NULL;
141 
142  file = (DRIVE_FILE*)ListDictionary_GetItemValue(drive->files, key);
143  return file;
144 }
145 
151 static UINT drive_process_irp_create(DRIVE_DEVICE* drive, IRP* irp)
152 {
153  UINT32 FileId = 0;
154  DRIVE_FILE* file = NULL;
155  BYTE Information = 0;
156  UINT32 FileAttributes = 0;
157  UINT32 SharedAccess = 0;
158  UINT32 DesiredAccess = 0;
159  UINT32 CreateDisposition = 0;
160  UINT32 CreateOptions = 0;
161  UINT32 PathLength = 0;
162  UINT64 allocationSize = 0;
163  const WCHAR* path = NULL;
164 
165  if (!drive || !irp || !irp->devman || !irp->Complete)
166  return ERROR_INVALID_PARAMETER;
167 
168  if (!Stream_CheckAndLogRequiredLength(TAG, irp->input, 6 * 4 + 8))
169  return ERROR_INVALID_DATA;
170 
171  Stream_Read_UINT32(irp->input, DesiredAccess);
172  Stream_Read_UINT64(irp->input, allocationSize);
173  Stream_Read_UINT32(irp->input, FileAttributes);
174  Stream_Read_UINT32(irp->input, SharedAccess);
175  Stream_Read_UINT32(irp->input, CreateDisposition);
176  Stream_Read_UINT32(irp->input, CreateOptions);
177  Stream_Read_UINT32(irp->input, PathLength);
178 
179  if (!Stream_CheckAndLogRequiredLength(TAG, irp->input, PathLength))
180  return ERROR_INVALID_DATA;
181 
182  path = Stream_ConstPointer(irp->input);
183  FileId = irp->devman->id_sequence++;
184  file = drive_file_new(drive->path, path, PathLength / sizeof(WCHAR), FileId, DesiredAccess,
185  CreateDisposition, CreateOptions, FileAttributes, SharedAccess);
186 
187  if (!file)
188  {
189  irp->IoStatus = drive_map_windows_err(GetLastError());
190  FileId = 0;
191  Information = 0;
192  }
193  else
194  {
195  void* key = (void*)(size_t)file->id;
196 
197  if (!ListDictionary_Add(drive->files, key, file))
198  {
199  WLog_ERR(TAG, "ListDictionary_Add failed!");
200  return ERROR_INTERNAL_ERROR;
201  }
202 
203  switch (CreateDisposition)
204  {
205  case FILE_SUPERSEDE:
206  case FILE_OPEN:
207  case FILE_CREATE:
208  case FILE_OVERWRITE:
209  Information = FILE_SUPERSEDED;
210  break;
211 
212  case FILE_OPEN_IF:
213  Information = FILE_OPENED;
214  break;
215 
216  case FILE_OVERWRITE_IF:
217  Information = FILE_OVERWRITTEN;
218  break;
219 
220  default:
221  Information = 0;
222  break;
223  }
224  }
225 
226  Stream_Write_UINT32(irp->output, FileId);
227  Stream_Write_UINT8(irp->output, Information);
228  return irp->Complete(irp);
229 }
230 
236 static UINT drive_process_irp_close(DRIVE_DEVICE* drive, IRP* irp)
237 {
238  void* key = NULL;
239  DRIVE_FILE* file = NULL;
240 
241  if (!drive || !irp || !irp->Complete || !irp->output)
242  return ERROR_INVALID_PARAMETER;
243 
244  file = drive_get_file_by_id(drive, irp->FileId);
245  key = (void*)(size_t)irp->FileId;
246 
247  if (!file)
248  irp->IoStatus = STATUS_UNSUCCESSFUL;
249  else
250  {
251  ListDictionary_Take(drive->files, key);
252 
253  if (drive_file_free(file))
254  irp->IoStatus = STATUS_SUCCESS;
255  else
256  irp->IoStatus = drive_map_windows_err(GetLastError());
257  }
258 
259  Stream_Zero(irp->output, 5); /* Padding(5) */
260  return irp->Complete(irp);
261 }
262 
268 static UINT drive_process_irp_read(DRIVE_DEVICE* drive, IRP* irp)
269 {
270  DRIVE_FILE* file = NULL;
271  UINT32 Length = 0;
272  UINT64 Offset = 0;
273 
274  if (!drive || !irp || !irp->output || !irp->Complete)
275  return ERROR_INVALID_PARAMETER;
276 
277  if (!Stream_CheckAndLogRequiredLength(TAG, irp->input, 12))
278  return ERROR_INVALID_DATA;
279 
280  Stream_Read_UINT32(irp->input, Length);
281  Stream_Read_UINT64(irp->input, Offset);
282  file = drive_get_file_by_id(drive, irp->FileId);
283 
284  if (!file)
285  {
286  irp->IoStatus = STATUS_UNSUCCESSFUL;
287  Length = 0;
288  }
289  else if (!drive_file_seek(file, Offset))
290  {
291  irp->IoStatus = drive_map_windows_err(GetLastError());
292  Length = 0;
293  }
294 
295  if (!Stream_EnsureRemainingCapacity(irp->output, Length + 4))
296  {
297  WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!");
298  return ERROR_INTERNAL_ERROR;
299  }
300  else if (Length == 0)
301  Stream_Write_UINT32(irp->output, 0);
302  else
303  {
304  BYTE* buffer = Stream_PointerAs(irp->output, BYTE) + sizeof(UINT32);
305 
306  if (!drive_file_read(file, buffer, &Length))
307  {
308  irp->IoStatus = drive_map_windows_err(GetLastError());
309  Stream_Write_UINT32(irp->output, 0);
310  }
311  else
312  {
313  Stream_Write_UINT32(irp->output, Length);
314  Stream_Seek(irp->output, Length);
315  }
316  }
317 
318  return irp->Complete(irp);
319 }
320 
326 static UINT drive_process_irp_write(DRIVE_DEVICE* drive, IRP* irp)
327 {
328  DRIVE_FILE* file = NULL;
329  UINT32 Length = 0;
330  UINT64 Offset = 0;
331 
332  if (!drive || !irp || !irp->input || !irp->output || !irp->Complete)
333  return ERROR_INVALID_PARAMETER;
334 
335  if (!Stream_CheckAndLogRequiredLength(TAG, irp->input, 32))
336  return ERROR_INVALID_DATA;
337 
338  Stream_Read_UINT32(irp->input, Length);
339  Stream_Read_UINT64(irp->input, Offset);
340  Stream_Seek(irp->input, 20); /* Padding */
341  const void* ptr = Stream_ConstPointer(irp->input);
342  if (!Stream_SafeSeek(irp->input, Length))
343  return ERROR_INVALID_DATA;
344  file = drive_get_file_by_id(drive, irp->FileId);
345 
346  if (!file)
347  {
348  irp->IoStatus = STATUS_UNSUCCESSFUL;
349  Length = 0;
350  }
351  else if (!drive_file_seek(file, Offset))
352  {
353  irp->IoStatus = drive_map_windows_err(GetLastError());
354  Length = 0;
355  }
356  else if (!drive_file_write(file, ptr, Length))
357  {
358  irp->IoStatus = drive_map_windows_err(GetLastError());
359  Length = 0;
360  }
361 
362  Stream_Write_UINT32(irp->output, Length);
363  Stream_Write_UINT8(irp->output, 0); /* Padding */
364  return irp->Complete(irp);
365 }
366 
372 static UINT drive_process_irp_query_information(DRIVE_DEVICE* drive, IRP* irp)
373 {
374  DRIVE_FILE* file = NULL;
375  UINT32 FsInformationClass = 0;
376 
377  if (!drive || !irp || !irp->Complete)
378  return ERROR_INVALID_PARAMETER;
379 
380  if (!Stream_CheckAndLogRequiredLength(TAG, irp->input, 4))
381  return ERROR_INVALID_DATA;
382 
383  Stream_Read_UINT32(irp->input, FsInformationClass);
384  file = drive_get_file_by_id(drive, irp->FileId);
385 
386  if (!file)
387  {
388  irp->IoStatus = STATUS_UNSUCCESSFUL;
389  }
390  else if (!drive_file_query_information(file, FsInformationClass, irp->output))
391  {
392  irp->IoStatus = drive_map_windows_err(GetLastError());
393  }
394 
395  return irp->Complete(irp);
396 }
397 
403 static UINT drive_process_irp_set_information(DRIVE_DEVICE* drive, IRP* irp)
404 {
405  DRIVE_FILE* file = NULL;
406  UINT32 FsInformationClass = 0;
407  UINT32 Length = 0;
408 
409  if (!drive || !irp || !irp->Complete || !irp->input || !irp->output)
410  return ERROR_INVALID_PARAMETER;
411 
412  if (!Stream_CheckAndLogRequiredLength(TAG, irp->input, 32))
413  return ERROR_INVALID_DATA;
414 
415  Stream_Read_UINT32(irp->input, FsInformationClass);
416  Stream_Read_UINT32(irp->input, Length);
417  Stream_Seek(irp->input, 24); /* Padding */
418  file = drive_get_file_by_id(drive, irp->FileId);
419 
420  if (!file)
421  {
422  irp->IoStatus = STATUS_UNSUCCESSFUL;
423  }
424  else if (!drive_file_set_information(file, FsInformationClass, Length, irp->input))
425  {
426  irp->IoStatus = drive_map_windows_err(GetLastError());
427  }
428 
429  if (file && file->is_dir && !PathIsDirectoryEmptyW(file->fullpath))
430  irp->IoStatus = STATUS_DIRECTORY_NOT_EMPTY;
431 
432  Stream_Write_UINT32(irp->output, Length);
433  return irp->Complete(irp);
434 }
435 
441 static UINT drive_process_irp_query_volume_information(DRIVE_DEVICE* drive, IRP* irp)
442 {
443  UINT32 FsInformationClass = 0;
444  wStream* output = NULL;
445  DWORD lpSectorsPerCluster = 0;
446  DWORD lpBytesPerSector = 0;
447  DWORD lpNumberOfFreeClusters = 0;
448  DWORD lpTotalNumberOfClusters = 0;
449  WIN32_FILE_ATTRIBUTE_DATA wfad = { 0 };
450  WCHAR LabelBuffer[32] = { 0 };
451 
452  if (!drive || !irp)
453  return ERROR_INVALID_PARAMETER;
454 
455  output = irp->output;
456 
457  if (!Stream_CheckAndLogRequiredLength(TAG, irp->input, 4))
458  return ERROR_INVALID_DATA;
459 
460  Stream_Read_UINT32(irp->input, FsInformationClass);
461  GetDiskFreeSpaceW(drive->path, &lpSectorsPerCluster, &lpBytesPerSector, &lpNumberOfFreeClusters,
462  &lpTotalNumberOfClusters);
463 
464  switch (FsInformationClass)
465  {
466  case FileFsVolumeInformation:
467  {
468  /* http://msdn.microsoft.com/en-us/library/cc232108.aspx */
469  const WCHAR* volumeLabel =
470  InitializeConstWCharFromUtf8("FREERDP", LabelBuffer, ARRAYSIZE(LabelBuffer));
471  const size_t volumeLabelLen = (_wcslen(volumeLabel) + 1) * sizeof(WCHAR);
472  const size_t length = 17ul + volumeLabelLen;
473 
474  if ((length > UINT32_MAX) || (volumeLabelLen > UINT32_MAX))
475  return CHANNEL_RC_NO_BUFFER;
476 
477  Stream_Write_UINT32(output, (UINT32)length); /* Length */
478 
479  if (!Stream_EnsureRemainingCapacity(output, length))
480  {
481  WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!");
482  return CHANNEL_RC_NO_MEMORY;
483  }
484 
485  GetFileAttributesExW(drive->path, GetFileExInfoStandard, &wfad);
486  Stream_Write_UINT32(output, wfad.ftCreationTime.dwLowDateTime); /* VolumeCreationTime */
487  Stream_Write_UINT32(output,
488  wfad.ftCreationTime.dwHighDateTime); /* VolumeCreationTime */
489  Stream_Write_UINT32(output, lpNumberOfFreeClusters & 0xffff); /* VolumeSerialNumber */
490  Stream_Write_UINT32(output, (UINT32)volumeLabelLen); /* VolumeLabelLength */
491  Stream_Write_UINT8(output, 0); /* SupportsObjects */
492  /* Reserved(1), MUST NOT be added! */
493  Stream_Write(output, volumeLabel, volumeLabelLen); /* VolumeLabel (Unicode) */
494  }
495  break;
496 
497  case FileFsSizeInformation:
498  /* http://msdn.microsoft.com/en-us/library/cc232107.aspx */
499  Stream_Write_UINT32(output, 24); /* Length */
500 
501  if (!Stream_EnsureRemainingCapacity(output, 24))
502  {
503  WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!");
504  return CHANNEL_RC_NO_MEMORY;
505  }
506 
507  Stream_Write_UINT64(output, lpTotalNumberOfClusters); /* TotalAllocationUnits */
508  Stream_Write_UINT64(output, lpNumberOfFreeClusters); /* AvailableAllocationUnits */
509  Stream_Write_UINT32(output, lpSectorsPerCluster); /* SectorsPerAllocationUnit */
510  Stream_Write_UINT32(output, lpBytesPerSector); /* BytesPerSector */
511  break;
512 
513  case FileFsAttributeInformation:
514  {
515  /* http://msdn.microsoft.com/en-us/library/cc232101.aspx */
516  const WCHAR* diskType =
517  InitializeConstWCharFromUtf8("FAT32", LabelBuffer, ARRAYSIZE(LabelBuffer));
518  const size_t diskTypeLen = (_wcslen(diskType) + 1) * sizeof(WCHAR);
519  const size_t length = 12ul + diskTypeLen;
520 
521  if ((length > UINT32_MAX) || (diskTypeLen > UINT32_MAX))
522  return CHANNEL_RC_NO_BUFFER;
523 
524  Stream_Write_UINT32(output, (UINT32)length); /* Length */
525 
526  if (!Stream_EnsureRemainingCapacity(output, length))
527  {
528  WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!");
529  return CHANNEL_RC_NO_MEMORY;
530  }
531 
532  Stream_Write_UINT32(output, FILE_CASE_SENSITIVE_SEARCH | FILE_CASE_PRESERVED_NAMES |
533  FILE_UNICODE_ON_DISK); /* FileSystemAttributes */
534  Stream_Write_UINT32(output, MAX_PATH); /* MaximumComponentNameLength */
535  Stream_Write_UINT32(output, (UINT32)diskTypeLen); /* FileSystemNameLength */
536  Stream_Write(output, diskType, diskTypeLen); /* FileSystemName (Unicode) */
537  }
538  break;
539 
540  case FileFsFullSizeInformation:
541  /* http://msdn.microsoft.com/en-us/library/cc232104.aspx */
542  Stream_Write_UINT32(output, 32); /* Length */
543 
544  if (!Stream_EnsureRemainingCapacity(output, 32))
545  {
546  WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!");
547  return CHANNEL_RC_NO_MEMORY;
548  }
549 
550  Stream_Write_UINT64(output, lpTotalNumberOfClusters); /* TotalAllocationUnits */
551  Stream_Write_UINT64(output,
552  lpNumberOfFreeClusters); /* CallerAvailableAllocationUnits */
553  Stream_Write_UINT64(output, lpNumberOfFreeClusters); /* AvailableAllocationUnits */
554  Stream_Write_UINT32(output, lpSectorsPerCluster); /* SectorsPerAllocationUnit */
555  Stream_Write_UINT32(output, lpBytesPerSector); /* BytesPerSector */
556  break;
557 
558  case FileFsDeviceInformation:
559  /* http://msdn.microsoft.com/en-us/library/cc232109.aspx */
560  Stream_Write_UINT32(output, 8); /* Length */
561 
562  if (!Stream_EnsureRemainingCapacity(output, 8))
563  {
564  WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!");
565  return CHANNEL_RC_NO_MEMORY;
566  }
567 
568  Stream_Write_UINT32(output, FILE_DEVICE_DISK); /* DeviceType */
569  Stream_Write_UINT32(output, 0); /* Characteristics */
570  break;
571 
572  default:
573  irp->IoStatus = STATUS_UNSUCCESSFUL;
574  Stream_Write_UINT32(output, 0); /* Length */
575  break;
576  }
577 
578  return irp->Complete(irp);
579 }
580 
581 /* http://msdn.microsoft.com/en-us/library/cc241518.aspx */
582 
588 static UINT drive_process_irp_silent_ignore(DRIVE_DEVICE* drive, IRP* irp)
589 {
590  UINT32 FsInformationClass = 0;
591 
592  if (!drive || !irp || !irp->output || !irp->Complete)
593  return ERROR_INVALID_PARAMETER;
594 
595  if (!Stream_CheckAndLogRequiredLength(TAG, irp->input, 4))
596  return ERROR_INVALID_DATA;
597 
598  Stream_Read_UINT32(irp->input, FsInformationClass);
599  Stream_Write_UINT32(irp->output, 0); /* Length */
600  return irp->Complete(irp);
601 }
602 
608 static UINT drive_process_irp_query_directory(DRIVE_DEVICE* drive, IRP* irp)
609 {
610  const WCHAR* path = NULL;
611  DRIVE_FILE* file = NULL;
612  BYTE InitialQuery = 0;
613  UINT32 PathLength = 0;
614  UINT32 FsInformationClass = 0;
615 
616  if (!drive || !irp || !irp->Complete)
617  return ERROR_INVALID_PARAMETER;
618 
619  if (!Stream_CheckAndLogRequiredLength(TAG, irp->input, 32))
620  return ERROR_INVALID_DATA;
621 
622  Stream_Read_UINT32(irp->input, FsInformationClass);
623  Stream_Read_UINT8(irp->input, InitialQuery);
624  Stream_Read_UINT32(irp->input, PathLength);
625  Stream_Seek(irp->input, 23); /* Padding */
626  path = Stream_ConstPointer(irp->input);
627  if (!Stream_CheckAndLogRequiredLength(TAG, irp->input, PathLength))
628  return ERROR_INVALID_DATA;
629 
630  file = drive_get_file_by_id(drive, irp->FileId);
631 
632  if (file == NULL)
633  {
634  irp->IoStatus = STATUS_UNSUCCESSFUL;
635  Stream_Write_UINT32(irp->output, 0); /* Length */
636  }
637  else if (!drive_file_query_directory(file, FsInformationClass, InitialQuery, path,
638  PathLength / sizeof(WCHAR), irp->output))
639  {
640  irp->IoStatus = drive_map_windows_err(GetLastError());
641  }
642 
643  return irp->Complete(irp);
644 }
645 
651 static UINT drive_process_irp_directory_control(DRIVE_DEVICE* drive, IRP* irp)
652 {
653  if (!drive || !irp)
654  return ERROR_INVALID_PARAMETER;
655 
656  switch (irp->MinorFunction)
657  {
658  case IRP_MN_QUERY_DIRECTORY:
659  return drive_process_irp_query_directory(drive, irp);
660 
661  case IRP_MN_NOTIFY_CHANGE_DIRECTORY: /* TODO */
662  return irp->Discard(irp);
663 
664  default:
665  irp->IoStatus = STATUS_NOT_SUPPORTED;
666  Stream_Write_UINT32(irp->output, 0); /* Length */
667  return irp->Complete(irp);
668  }
669 
670  return CHANNEL_RC_OK;
671 }
672 
678 static UINT drive_process_irp_device_control(DRIVE_DEVICE* drive, IRP* irp)
679 {
680  if (!drive || !irp)
681  return ERROR_INVALID_PARAMETER;
682 
683  Stream_Write_UINT32(irp->output, 0); /* OutputBufferLength */
684  return irp->Complete(irp);
685 }
686 
692 static UINT drive_process_irp(DRIVE_DEVICE* drive, IRP* irp)
693 {
694  UINT error = 0;
695 
696  if (!drive || !irp)
697  return ERROR_INVALID_PARAMETER;
698 
699  irp->IoStatus = STATUS_SUCCESS;
700 
701  switch (irp->MajorFunction)
702  {
703  case IRP_MJ_CREATE:
704  error = drive_process_irp_create(drive, irp);
705  break;
706 
707  case IRP_MJ_CLOSE:
708  error = drive_process_irp_close(drive, irp);
709  break;
710 
711  case IRP_MJ_READ:
712  error = drive_process_irp_read(drive, irp);
713  break;
714 
715  case IRP_MJ_WRITE:
716  error = drive_process_irp_write(drive, irp);
717  break;
718 
719  case IRP_MJ_QUERY_INFORMATION:
720  error = drive_process_irp_query_information(drive, irp);
721  break;
722 
723  case IRP_MJ_SET_INFORMATION:
724  error = drive_process_irp_set_information(drive, irp);
725  break;
726 
727  case IRP_MJ_QUERY_VOLUME_INFORMATION:
728  error = drive_process_irp_query_volume_information(drive, irp);
729  break;
730 
731  case IRP_MJ_LOCK_CONTROL:
732  error = drive_process_irp_silent_ignore(drive, irp);
733  break;
734 
735  case IRP_MJ_DIRECTORY_CONTROL:
736  error = drive_process_irp_directory_control(drive, irp);
737  break;
738 
739  case IRP_MJ_DEVICE_CONTROL:
740  error = drive_process_irp_device_control(drive, irp);
741  break;
742 
743  default:
744  irp->IoStatus = STATUS_NOT_SUPPORTED;
745  error = irp->Complete(irp);
746  break;
747  }
748 
749  return error;
750 }
751 
752 static BOOL drive_poll_run(DRIVE_DEVICE* drive, IRP* irp)
753 {
754  WINPR_ASSERT(drive);
755 
756  if (irp)
757  {
758  const UINT error = drive_process_irp(drive, irp);
759  if (error)
760  {
761  WLog_ERR(TAG, "drive_process_irp failed with error %" PRIu32 "!", error);
762  return FALSE;
763  }
764  }
765 
766  return TRUE;
767 }
768 
769 static DWORD WINAPI drive_thread_func(LPVOID arg)
770 {
771  DRIVE_DEVICE* drive = (DRIVE_DEVICE*)arg;
772  UINT error = CHANNEL_RC_OK;
773 
774  if (!drive)
775  {
776  error = ERROR_INVALID_PARAMETER;
777  goto fail;
778  }
779 
780  while (1)
781  {
782  if (!MessageQueue_Wait(drive->IrpQueue))
783  {
784  WLog_ERR(TAG, "MessageQueue_Wait failed!");
785  error = ERROR_INTERNAL_ERROR;
786  break;
787  }
788 
789  if (MessageQueue_Size(drive->IrpQueue) < 1)
790  continue;
791 
792  wMessage message = { 0 };
793  if (!MessageQueue_Peek(drive->IrpQueue, &message, TRUE))
794  {
795  WLog_ERR(TAG, "MessageQueue_Peek failed!");
796  continue;
797  }
798 
799  if (message.id == WMQ_QUIT)
800  break;
801 
802  IRP* irp = (IRP*)message.wParam;
803  if (!drive_poll_run(drive, irp))
804  break;
805  }
806 
807 fail:
808 
809  if (error && drive && drive->rdpcontext)
810  setChannelError(drive->rdpcontext, error, "drive_thread_func reported an error");
811 
812  ExitThread(error);
813  return error;
814 }
815 
821 static UINT drive_irp_request(DEVICE* device, IRP* irp)
822 {
823  DRIVE_DEVICE* drive = (DRIVE_DEVICE*)device;
824 
825  if (!drive)
826  return ERROR_INVALID_PARAMETER;
827 
828  if (drive->async)
829  {
830  if (!MessageQueue_Post(drive->IrpQueue, NULL, 0, (void*)irp, NULL))
831  {
832  WLog_ERR(TAG, "MessageQueue_Post failed!");
833  return ERROR_INTERNAL_ERROR;
834  }
835  }
836  else
837  {
838  if (!drive_poll_run(drive, irp))
839  return ERROR_INTERNAL_ERROR;
840  }
841 
842  return CHANNEL_RC_OK;
843 }
844 
845 static UINT drive_free_int(DRIVE_DEVICE* drive)
846 {
847  UINT error = CHANNEL_RC_OK;
848 
849  if (!drive)
850  return ERROR_INVALID_PARAMETER;
851 
852  (void)CloseHandle(drive->thread);
853  ListDictionary_Free(drive->files);
854  MessageQueue_Free(drive->IrpQueue);
855  Stream_Free(drive->device.data, TRUE);
856  free(drive->path);
857  free(drive);
858  return error;
859 }
860 
866 static UINT drive_free(DEVICE* device)
867 {
868  DRIVE_DEVICE* drive = (DRIVE_DEVICE*)device;
869  UINT error = CHANNEL_RC_OK;
870 
871  if (!drive)
872  return ERROR_INVALID_PARAMETER;
873 
874  if (MessageQueue_PostQuit(drive->IrpQueue, 0) &&
875  (WaitForSingleObject(drive->thread, INFINITE) == WAIT_FAILED))
876  {
877  error = GetLastError();
878  WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "", error);
879  return error;
880  }
881 
882  return drive_free_int(drive);
883 }
884 
888 static void drive_file_objfree(void* obj)
889 {
890  drive_file_free((DRIVE_FILE*)obj);
891 }
892 
893 static void drive_message_free(void* obj)
894 {
895  wMessage* msg = obj;
896  if (!msg)
897  return;
898  if (msg->id != 0)
899  return;
900 
901  IRP* irp = (IRP*)msg->wParam;
902  if (!irp)
903  return;
904  WINPR_ASSERT(irp->Discard);
905  irp->Discard(irp);
906 }
907 
913 static UINT drive_register_drive_path(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints, const char* name,
914  const char* path, BOOL automount)
915 {
916  size_t length = 0;
917  DRIVE_DEVICE* drive = NULL;
918  UINT error = ERROR_INTERNAL_ERROR;
919 
920  if (!pEntryPoints || !name || !path)
921  {
922  WLog_ERR(TAG, "[%s] Invalid parameters: pEntryPoints=%p, name=%p, path=%p", pEntryPoints,
923  name, path);
924  return ERROR_INVALID_PARAMETER;
925  }
926 
927  if (name[0] && path[0])
928  {
929  size_t pathLength = strnlen(path, MAX_PATH);
930  drive = (DRIVE_DEVICE*)calloc(1, sizeof(DRIVE_DEVICE));
931 
932  if (!drive)
933  {
934  WLog_ERR(TAG, "calloc failed!");
935  return CHANNEL_RC_NO_MEMORY;
936  }
937 
938  drive->device.type = RDPDR_DTYP_FILESYSTEM;
939  drive->device.IRPRequest = drive_irp_request;
940  drive->device.Free = drive_free;
941  drive->rdpcontext = pEntryPoints->rdpcontext;
942  drive->automount = automount;
943  length = strlen(name);
944  drive->device.data = Stream_New(NULL, length + 1);
945 
946  if (!drive->device.data)
947  {
948  WLog_ERR(TAG, "Stream_New failed!");
949  error = CHANNEL_RC_NO_MEMORY;
950  goto out_error;
951  }
952 
953  for (size_t i = 0; i < length; i++)
954  {
955  /* Filter 2.2.1.3 Device Announce Header (DEVICE_ANNOUNCE) forbidden symbols */
956  switch (name[i])
957  {
958  case ':':
959  case '<':
960  case '>':
961  case '\"':
962  case '/':
963  case '\\':
964  case '|':
965  case ' ':
966  Stream_Write_UINT8(drive->device.data, '_');
967  break;
968  default:
969  Stream_Write_UINT8(drive->device.data, (BYTE)name[i]);
970  break;
971  }
972  }
973  Stream_Write_UINT8(drive->device.data, '\0');
974 
975  drive->device.name = Stream_BufferAs(drive->device.data, char);
976  if (!drive->device.name)
977  goto out_error;
978 
979  if ((pathLength > 1) && (path[pathLength - 1] == '/'))
980  pathLength--;
981 
982  drive->path = ConvertUtf8NToWCharAlloc(path, pathLength, NULL);
983  if (!drive->path)
984  {
985  error = CHANNEL_RC_NO_MEMORY;
986  goto out_error;
987  }
988 
989  drive->files = ListDictionary_New(TRUE);
990 
991  if (!drive->files)
992  {
993  WLog_ERR(TAG, "ListDictionary_New failed!");
994  error = CHANNEL_RC_NO_MEMORY;
995  goto out_error;
996  }
997 
998  ListDictionary_ValueObject(drive->files)->fnObjectFree = drive_file_objfree;
999  drive->IrpQueue = MessageQueue_New(NULL);
1000 
1001  if (!drive->IrpQueue)
1002  {
1003  WLog_ERR(TAG, "ListDictionary_New failed!");
1004  error = CHANNEL_RC_NO_MEMORY;
1005  goto out_error;
1006  }
1007 
1008  wObject* obj = MessageQueue_Object(drive->IrpQueue);
1009  WINPR_ASSERT(obj);
1010  obj->fnObjectFree = drive_message_free;
1011 
1012  if ((error = pEntryPoints->RegisterDevice(pEntryPoints->devman, (DEVICE*)drive)))
1013  {
1014  WLog_ERR(TAG, "RegisterDevice failed with error %" PRIu32 "!", error);
1015  goto out_error;
1016  }
1017 
1018  drive->async = !freerdp_settings_get_bool(drive->rdpcontext->settings,
1019  FreeRDP_SynchronousStaticChannels);
1020  if (drive->async)
1021  {
1022  if (!(drive->thread =
1023  CreateThread(NULL, 0, drive_thread_func, drive, CREATE_SUSPENDED, NULL)))
1024  {
1025  WLog_ERR(TAG, "CreateThread failed!");
1026  goto out_error;
1027  }
1028 
1029  ResumeThread(drive->thread);
1030  }
1031  }
1032 
1033  return CHANNEL_RC_OK;
1034 out_error:
1035  drive_free_int(drive);
1036  return error;
1037 }
1038 
1044 FREERDP_ENTRY_POINT(
1045  UINT VCAPITYPE drive_DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints))
1046 {
1047  RDPDR_DRIVE* drive = NULL;
1048  UINT error = 0;
1049 #ifdef WIN32
1050  int len;
1051  char devlist[512], buf[512];
1052  char* bufdup;
1053  char* devdup;
1054 #endif
1055 
1056  WINPR_ASSERT(pEntryPoints);
1057 
1058  drive = (RDPDR_DRIVE*)pEntryPoints->device;
1059  WINPR_ASSERT(drive);
1060 
1061 #ifndef WIN32
1062  if (strcmp(drive->Path, "*") == 0)
1063  {
1064  /* all drives */
1065  free(drive->Path);
1066  drive->Path = _strdup("/");
1067 
1068  if (!drive->Path)
1069  {
1070  WLog_ERR(TAG, "_strdup failed!");
1071  return CHANNEL_RC_NO_MEMORY;
1072  }
1073  }
1074  else if (strcmp(drive->Path, "%") == 0)
1075  {
1076  free(drive->Path);
1077  drive->Path = GetKnownPath(KNOWN_PATH_HOME);
1078 
1079  if (!drive->Path)
1080  {
1081  WLog_ERR(TAG, "_strdup failed!");
1082  return CHANNEL_RC_NO_MEMORY;
1083  }
1084  }
1085 
1086  error =
1087  drive_register_drive_path(pEntryPoints, drive->device.Name, drive->Path, drive->automount);
1088 #else
1089  /* Special case: path[0] == '*' -> export all drives */
1090  /* Special case: path[0] == '%' -> user home dir */
1091  if (strcmp(drive->Path, "%") == 0)
1092  {
1093  GetEnvironmentVariableA("USERPROFILE", buf, sizeof(buf));
1094  PathCchAddBackslashA(buf, sizeof(buf));
1095  free(drive->Path);
1096  drive->Path = _strdup(buf);
1097 
1098  if (!drive->Path)
1099  {
1100  WLog_ERR(TAG, "_strdup failed!");
1101  return CHANNEL_RC_NO_MEMORY;
1102  }
1103 
1104  error = drive_register_drive_path(pEntryPoints, drive->device.Name, drive->Path,
1105  drive->automount);
1106  }
1107  else if (strcmp(drive->Path, "*") == 0)
1108  {
1109  /* Enumerate all devices: */
1110  GetLogicalDriveStringsA(sizeof(devlist) - 1, devlist);
1111 
1112  for (size_t i = 0;; i++)
1113  {
1114  char* dev = &devlist[i * 4];
1115  if (!*dev)
1116  break;
1117  if (*dev > 'B')
1118  {
1119  /* Suppress disk drives A and B to avoid pesty messages */
1120  len = sprintf_s(buf, sizeof(buf) - 4, "%s", drive->device.Name);
1121  buf[len] = '_';
1122  buf[len + 1] = dev[0];
1123  buf[len + 2] = 0;
1124  buf[len + 3] = 0;
1125 
1126  if (!(bufdup = _strdup(buf)))
1127  {
1128  WLog_ERR(TAG, "_strdup failed!");
1129  return CHANNEL_RC_NO_MEMORY;
1130  }
1131 
1132  if (!(devdup = _strdup(dev)))
1133  {
1134  WLog_ERR(TAG, "_strdup failed!");
1135  return CHANNEL_RC_NO_MEMORY;
1136  }
1137 
1138  if ((error = drive_register_drive_path(pEntryPoints, bufdup, devdup, TRUE)))
1139  {
1140  break;
1141  }
1142  }
1143  }
1144  }
1145  else
1146  {
1147  error = drive_register_drive_path(pEntryPoints, drive->device.Name, drive->Path,
1148  drive->automount);
1149  }
1150 
1151 #endif
1152  return error;
1153 }
FREERDP_API BOOL freerdp_settings_get_bool(const rdpSettings *settings, FreeRDP_Settings_Keys_Bool id)
Returns a boolean settings value.
This struct contains function pointer to initialize/free objects.
Definition: collections.h:57