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