24 #include <freerdp/config.h>
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>
44 #include <freerdp/freerdp.h>
45 #include <freerdp/channels/rdpdr.h>
47 #include "drive_file.h"
56 wListDictionary* files;
59 wMessageQueue* IrpQueue;
63 rdpContext* rdpcontext;
66 static DWORD drive_map_windows_err(DWORD fs_errno)
78 case ERROR_ACCESS_DENIED:
79 case ERROR_SHARING_VIOLATION:
80 rc = STATUS_ACCESS_DENIED;
83 case ERROR_FILE_NOT_FOUND:
84 rc = STATUS_NO_SUCH_FILE;
87 case ERROR_BUSY_DRIVE:
88 rc = STATUS_DEVICE_BUSY;
91 case ERROR_INVALID_DRIVE:
92 rc = STATUS_NO_SUCH_DEVICE;
96 rc = STATUS_NO_SUCH_DEVICE;
99 case ERROR_FILE_EXISTS:
100 case ERROR_ALREADY_EXISTS:
101 rc = STATUS_OBJECT_NAME_COLLISION;
104 case ERROR_INVALID_NAME:
105 rc = STATUS_NO_SUCH_FILE;
108 case ERROR_INVALID_HANDLE:
109 rc = STATUS_INVALID_HANDLE;
112 case ERROR_NO_MORE_FILES:
113 rc = STATUS_NO_MORE_FILES;
116 case ERROR_DIRECTORY:
117 rc = STATUS_NOT_A_DIRECTORY;
120 case ERROR_PATH_NOT_FOUND:
121 rc = STATUS_OBJECT_PATH_NOT_FOUND;
125 rc = STATUS_UNSUCCESSFUL;
126 WLog_ERR(TAG,
"Error code not found: %" PRIu32
"", fs_errno);
133 static DRIVE_FILE* drive_get_file_by_id(DRIVE_DEVICE* drive, UINT32
id)
136 void* key = (
void*)(
size_t)id;
141 file = (
DRIVE_FILE*)ListDictionary_GetItemValue(drive->files, key);
150 static UINT drive_process_irp_create(DRIVE_DEVICE* drive, IRP* irp)
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;
164 if (!drive || !irp || !irp->devman || !irp->Complete)
165 return ERROR_INVALID_PARAMETER;
167 if (!Stream_CheckAndLogRequiredLength(TAG, irp->input, 6 * 4 + 8))
168 return ERROR_INVALID_DATA;
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);
178 if (!Stream_CheckAndLogRequiredLength(TAG, irp->input, PathLength))
179 return ERROR_INVALID_DATA;
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);
188 irp->IoStatus = drive_map_windows_err(GetLastError());
194 void* key = (
void*)(
size_t)file->id;
196 if (!ListDictionary_Add(drive->files, key, file))
198 WLog_ERR(TAG,
"ListDictionary_Add failed!");
199 return ERROR_INTERNAL_ERROR;
202 switch (CreateDisposition)
208 Information = FILE_SUPERSEDED;
212 Information = FILE_OPENED;
215 case FILE_OVERWRITE_IF:
216 Information = FILE_OVERWRITTEN;
225 Stream_Write_UINT32(irp->output, FileId);
226 Stream_Write_UINT8(irp->output, Information);
227 return irp->Complete(irp);
235 static UINT drive_process_irp_close(DRIVE_DEVICE* drive, IRP* irp)
240 if (!drive || !irp || !irp->Complete || !irp->output)
241 return ERROR_INVALID_PARAMETER;
243 file = drive_get_file_by_id(drive, irp->FileId);
244 key = (
void*)(
size_t)irp->FileId;
247 irp->IoStatus = STATUS_UNSUCCESSFUL;
250 ListDictionary_Take(drive->files, key);
252 if (drive_file_free(file))
253 irp->IoStatus = STATUS_SUCCESS;
255 irp->IoStatus = drive_map_windows_err(GetLastError());
258 Stream_Zero(irp->output, 5);
259 return irp->Complete(irp);
267 static UINT drive_process_irp_read(DRIVE_DEVICE* drive, IRP* irp)
273 if (!drive || !irp || !irp->output || !irp->Complete)
274 return ERROR_INVALID_PARAMETER;
276 if (!Stream_CheckAndLogRequiredLength(TAG, irp->input, 12))
277 return ERROR_INVALID_DATA;
279 Stream_Read_UINT32(irp->input, Length);
280 Stream_Read_UINT64(irp->input, Offset);
281 file = drive_get_file_by_id(drive, irp->FileId);
285 irp->IoStatus = STATUS_UNSUCCESSFUL;
288 else if (!drive_file_seek(file, Offset))
290 irp->IoStatus = drive_map_windows_err(GetLastError());
294 if (!Stream_EnsureRemainingCapacity(irp->output, Length + 4))
296 WLog_ERR(TAG,
"Stream_EnsureRemainingCapacity failed!");
297 return ERROR_INTERNAL_ERROR;
299 else if (Length == 0)
300 Stream_Write_UINT32(irp->output, 0);
303 BYTE* buffer = Stream_PointerAs(irp->output, BYTE) +
sizeof(UINT32);
305 if (!drive_file_read(file, buffer, &Length))
307 irp->IoStatus = drive_map_windows_err(GetLastError());
308 Stream_Write_UINT32(irp->output, 0);
312 Stream_Write_UINT32(irp->output, Length);
313 Stream_Seek(irp->output, Length);
317 return irp->Complete(irp);
325 static UINT drive_process_irp_write(DRIVE_DEVICE* drive, IRP* irp)
331 if (!drive || !irp || !irp->input || !irp->output || !irp->Complete)
332 return ERROR_INVALID_PARAMETER;
334 if (!Stream_CheckAndLogRequiredLength(TAG, irp->input, 32))
335 return ERROR_INVALID_DATA;
337 Stream_Read_UINT32(irp->input, Length);
338 Stream_Read_UINT64(irp->input, Offset);
339 Stream_Seek(irp->input, 20);
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);
347 irp->IoStatus = STATUS_UNSUCCESSFUL;
350 else if (!drive_file_seek(file, Offset))
352 irp->IoStatus = drive_map_windows_err(GetLastError());
355 else if (!drive_file_write(file, ptr, Length))
357 irp->IoStatus = drive_map_windows_err(GetLastError());
361 Stream_Write_UINT32(irp->output, Length);
362 Stream_Write_UINT8(irp->output, 0);
363 return irp->Complete(irp);
371 static UINT drive_process_irp_query_information(DRIVE_DEVICE* drive, IRP* irp)
374 UINT32 FsInformationClass = 0;
376 if (!drive || !irp || !irp->Complete)
377 return ERROR_INVALID_PARAMETER;
379 if (!Stream_CheckAndLogRequiredLength(TAG, irp->input, 4))
380 return ERROR_INVALID_DATA;
382 Stream_Read_UINT32(irp->input, FsInformationClass);
383 file = drive_get_file_by_id(drive, irp->FileId);
387 irp->IoStatus = STATUS_UNSUCCESSFUL;
389 else if (!drive_file_query_information(file, FsInformationClass, irp->output))
391 irp->IoStatus = drive_map_windows_err(GetLastError());
394 return irp->Complete(irp);
402 static UINT drive_process_irp_set_information(DRIVE_DEVICE* drive, IRP* irp)
405 UINT32 FsInformationClass = 0;
408 if (!drive || !irp || !irp->Complete || !irp->input || !irp->output)
409 return ERROR_INVALID_PARAMETER;
411 if (!Stream_CheckAndLogRequiredLength(TAG, irp->input, 32))
412 return ERROR_INVALID_DATA;
414 Stream_Read_UINT32(irp->input, FsInformationClass);
415 Stream_Read_UINT32(irp->input, Length);
416 Stream_Seek(irp->input, 24);
417 file = drive_get_file_by_id(drive, irp->FileId);
421 irp->IoStatus = STATUS_UNSUCCESSFUL;
423 else if (!drive_file_set_information(file, FsInformationClass, Length, irp->input))
425 irp->IoStatus = drive_map_windows_err(GetLastError());
428 if (file && file->is_dir && !PathIsDirectoryEmptyW(file->fullpath))
429 irp->IoStatus = STATUS_DIRECTORY_NOT_EMPTY;
431 Stream_Write_UINT32(irp->output, Length);
432 return irp->Complete(irp);
440 static UINT drive_process_irp_query_volume_information(DRIVE_DEVICE* drive, IRP* irp)
442 UINT32 FsInformationClass = 0;
444 DWORD lpSectorsPerCluster = 0;
445 DWORD lpBytesPerSector = 0;
446 DWORD lpNumberOfFreeClusters = 0;
447 DWORD lpTotalNumberOfClusters = 0;
449 WCHAR LabelBuffer[32] = { 0 };
452 return ERROR_INVALID_PARAMETER;
454 output = irp->output;
456 if (!Stream_CheckAndLogRequiredLength(TAG, irp->input, 4))
457 return ERROR_INVALID_DATA;
459 Stream_Read_UINT32(irp->input, FsInformationClass);
460 GetDiskFreeSpaceW(drive->path, &lpSectorsPerCluster, &lpBytesPerSector, &lpNumberOfFreeClusters,
461 &lpTotalNumberOfClusters);
463 switch (FsInformationClass)
465 case FileFsVolumeInformation:
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;
473 if ((length > UINT32_MAX) || (volumeLabelLen > UINT32_MAX))
474 return CHANNEL_RC_NO_BUFFER;
476 Stream_Write_UINT32(output, (UINT32)length);
478 if (!Stream_EnsureRemainingCapacity(output, length))
480 WLog_ERR(TAG,
"Stream_EnsureRemainingCapacity failed!");
481 return CHANNEL_RC_NO_MEMORY;
484 GetFileAttributesExW(drive->path, GetFileExInfoStandard, &wfad);
485 Stream_Write_UINT32(output, wfad.ftCreationTime.dwLowDateTime);
486 Stream_Write_UINT32(output,
487 wfad.ftCreationTime.dwHighDateTime);
488 Stream_Write_UINT32(output, lpNumberOfFreeClusters & 0xffff);
489 Stream_Write_UINT32(output, (UINT32)volumeLabelLen);
490 Stream_Write_UINT8(output, 0);
492 Stream_Write(output, volumeLabel, volumeLabelLen);
496 case FileFsSizeInformation:
498 Stream_Write_UINT32(output, 24);
500 if (!Stream_EnsureRemainingCapacity(output, 24))
502 WLog_ERR(TAG,
"Stream_EnsureRemainingCapacity failed!");
503 return CHANNEL_RC_NO_MEMORY;
506 Stream_Write_UINT64(output, lpTotalNumberOfClusters);
507 Stream_Write_UINT64(output, lpNumberOfFreeClusters);
508 Stream_Write_UINT32(output, lpSectorsPerCluster);
509 Stream_Write_UINT32(output, lpBytesPerSector);
512 case FileFsAttributeInformation:
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;
520 if ((length > UINT32_MAX) || (diskTypeLen > UINT32_MAX))
521 return CHANNEL_RC_NO_BUFFER;
523 Stream_Write_UINT32(output, (UINT32)length);
525 if (!Stream_EnsureRemainingCapacity(output, length))
527 WLog_ERR(TAG,
"Stream_EnsureRemainingCapacity failed!");
528 return CHANNEL_RC_NO_MEMORY;
531 Stream_Write_UINT32(output, FILE_CASE_SENSITIVE_SEARCH | FILE_CASE_PRESERVED_NAMES |
532 FILE_UNICODE_ON_DISK);
533 Stream_Write_UINT32(output, MAX_PATH);
534 Stream_Write_UINT32(output, (UINT32)diskTypeLen);
535 Stream_Write(output, diskType, diskTypeLen);
539 case FileFsFullSizeInformation:
541 Stream_Write_UINT32(output, 32);
543 if (!Stream_EnsureRemainingCapacity(output, 32))
545 WLog_ERR(TAG,
"Stream_EnsureRemainingCapacity failed!");
546 return CHANNEL_RC_NO_MEMORY;
549 Stream_Write_UINT64(output, lpTotalNumberOfClusters);
550 Stream_Write_UINT64(output,
551 lpNumberOfFreeClusters);
552 Stream_Write_UINT64(output, lpNumberOfFreeClusters);
553 Stream_Write_UINT32(output, lpSectorsPerCluster);
554 Stream_Write_UINT32(output, lpBytesPerSector);
557 case FileFsDeviceInformation:
559 Stream_Write_UINT32(output, 8);
561 if (!Stream_EnsureRemainingCapacity(output, 8))
563 WLog_ERR(TAG,
"Stream_EnsureRemainingCapacity failed!");
564 return CHANNEL_RC_NO_MEMORY;
567 Stream_Write_UINT32(output, FILE_DEVICE_DISK);
568 Stream_Write_UINT32(output, 0);
572 irp->IoStatus = STATUS_UNSUCCESSFUL;
573 Stream_Write_UINT32(output, 0);
577 return irp->Complete(irp);
587 static UINT drive_process_irp_silent_ignore(DRIVE_DEVICE* drive, IRP* irp)
589 UINT32 FsInformationClass = 0;
591 if (!drive || !irp || !irp->output || !irp->Complete)
592 return ERROR_INVALID_PARAMETER;
594 if (!Stream_CheckAndLogRequiredLength(TAG, irp->input, 4))
595 return ERROR_INVALID_DATA;
597 Stream_Read_UINT32(irp->input, FsInformationClass);
598 Stream_Write_UINT32(irp->output, 0);
599 return irp->Complete(irp);
607 static UINT drive_process_irp_query_directory(DRIVE_DEVICE* drive, IRP* irp)
609 const WCHAR* path = NULL;
611 BYTE InitialQuery = 0;
612 UINT32 PathLength = 0;
613 UINT32 FsInformationClass = 0;
615 if (!drive || !irp || !irp->Complete)
616 return ERROR_INVALID_PARAMETER;
618 if (!Stream_CheckAndLogRequiredLength(TAG, irp->input, 32))
619 return ERROR_INVALID_DATA;
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);
625 path = Stream_ConstPointer(irp->input);
626 if (!Stream_CheckAndLogRequiredLength(TAG, irp->input, PathLength))
627 return ERROR_INVALID_DATA;
629 file = drive_get_file_by_id(drive, irp->FileId);
633 irp->IoStatus = STATUS_UNSUCCESSFUL;
634 Stream_Write_UINT32(irp->output, 0);
636 else if (!drive_file_query_directory(file, FsInformationClass, InitialQuery, path,
637 PathLength /
sizeof(WCHAR), irp->output))
639 irp->IoStatus = drive_map_windows_err(GetLastError());
642 return irp->Complete(irp);
650 static UINT drive_process_irp_directory_control(DRIVE_DEVICE* drive, IRP* irp)
653 return ERROR_INVALID_PARAMETER;
655 switch (irp->MinorFunction)
657 case IRP_MN_QUERY_DIRECTORY:
658 return drive_process_irp_query_directory(drive, irp);
660 case IRP_MN_NOTIFY_CHANGE_DIRECTORY:
661 return irp->Discard(irp);
664 irp->IoStatus = STATUS_NOT_SUPPORTED;
665 Stream_Write_UINT32(irp->output, 0);
666 return irp->Complete(irp);
669 return CHANNEL_RC_OK;
677 static UINT drive_process_irp_device_control(DRIVE_DEVICE* drive, IRP* irp)
680 return ERROR_INVALID_PARAMETER;
682 Stream_Write_UINT32(irp->output, 0);
683 return irp->Complete(irp);
691 static UINT drive_process_irp(DRIVE_DEVICE* drive, IRP* irp)
696 return ERROR_INVALID_PARAMETER;
698 irp->IoStatus = STATUS_SUCCESS;
700 switch (irp->MajorFunction)
703 error = drive_process_irp_create(drive, irp);
707 error = drive_process_irp_close(drive, irp);
711 error = drive_process_irp_read(drive, irp);
715 error = drive_process_irp_write(drive, irp);
718 case IRP_MJ_QUERY_INFORMATION:
719 error = drive_process_irp_query_information(drive, irp);
722 case IRP_MJ_SET_INFORMATION:
723 error = drive_process_irp_set_information(drive, irp);
726 case IRP_MJ_QUERY_VOLUME_INFORMATION:
727 error = drive_process_irp_query_volume_information(drive, irp);
730 case IRP_MJ_LOCK_CONTROL:
731 error = drive_process_irp_silent_ignore(drive, irp);
734 case IRP_MJ_DIRECTORY_CONTROL:
735 error = drive_process_irp_directory_control(drive, irp);
738 case IRP_MJ_DEVICE_CONTROL:
739 error = drive_process_irp_device_control(drive, irp);
743 irp->IoStatus = STATUS_NOT_SUPPORTED;
744 error = irp->Complete(irp);
751 static DWORD WINAPI drive_thread_func(LPVOID arg)
754 wMessage message = { 0 };
755 DRIVE_DEVICE* drive = (DRIVE_DEVICE*)arg;
756 UINT error = CHANNEL_RC_OK;
760 error = ERROR_INVALID_PARAMETER;
766 if (!MessageQueue_Wait(drive->IrpQueue))
768 WLog_ERR(TAG,
"MessageQueue_Wait failed!");
769 error = ERROR_INTERNAL_ERROR;
773 if (!MessageQueue_Peek(drive->IrpQueue, &message, TRUE))
775 WLog_ERR(TAG,
"MessageQueue_Peek failed!");
776 error = ERROR_INTERNAL_ERROR;
780 if (message.id == WMQ_QUIT)
783 irp = (IRP*)message.wParam;
787 if ((error = drive_process_irp(drive, irp)))
789 WLog_ERR(TAG,
"drive_process_irp failed with error %" PRIu32
"!", error);
797 if (error && drive && drive->rdpcontext)
798 setChannelError(drive->rdpcontext, error,
"drive_thread_func reported an error");
809 static UINT drive_irp_request(DEVICE* device, IRP* irp)
811 DRIVE_DEVICE* drive = (DRIVE_DEVICE*)device;
814 return ERROR_INVALID_PARAMETER;
816 if (!MessageQueue_Post(drive->IrpQueue, NULL, 0, (
void*)irp, NULL))
818 WLog_ERR(TAG,
"MessageQueue_Post failed!");
819 return ERROR_INTERNAL_ERROR;
822 return CHANNEL_RC_OK;
825 static UINT drive_free_int(DRIVE_DEVICE* drive)
827 UINT error = CHANNEL_RC_OK;
830 return ERROR_INVALID_PARAMETER;
832 (void)CloseHandle(drive->thread);
833 ListDictionary_Free(drive->files);
834 MessageQueue_Free(drive->IrpQueue);
835 Stream_Free(drive->device.data, TRUE);
846 static UINT drive_free(DEVICE* device)
848 DRIVE_DEVICE* drive = (DRIVE_DEVICE*)device;
849 UINT error = CHANNEL_RC_OK;
852 return ERROR_INVALID_PARAMETER;
854 if (MessageQueue_PostQuit(drive->IrpQueue, 0) &&
855 (WaitForSingleObject(drive->thread, INFINITE) == WAIT_FAILED))
857 error = GetLastError();
858 WLog_ERR(TAG,
"WaitForSingleObject failed with error %" PRIu32
"", error);
862 return drive_free_int(drive);
868 static void drive_file_objfree(
void* obj)
873 static void drive_message_free(
void* obj)
881 IRP* irp = (IRP*)msg->wParam;
884 WINPR_ASSERT(irp->Discard);
894 const char* path, BOOL automount)
897 DRIVE_DEVICE* drive = NULL;
898 UINT error = ERROR_INTERNAL_ERROR;
900 if (!pEntryPoints || !name || !path)
902 WLog_ERR(TAG,
"[%s] Invalid parameters: pEntryPoints=%p, name=%p, path=%p", pEntryPoints,
904 return ERROR_INVALID_PARAMETER;
907 if (name[0] && path[0])
909 size_t pathLength = strnlen(path, MAX_PATH);
910 drive = (DRIVE_DEVICE*)calloc(1,
sizeof(DRIVE_DEVICE));
914 WLog_ERR(TAG,
"calloc failed!");
915 return CHANNEL_RC_NO_MEMORY;
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);
926 if (!drive->device.data)
928 WLog_ERR(TAG,
"Stream_New failed!");
929 error = CHANNEL_RC_NO_MEMORY;
933 for (
size_t i = 0; i < length; i++)
946 Stream_Write_UINT8(drive->device.data,
'_');
949 Stream_Write_UINT8(drive->device.data, (BYTE)name[i]);
953 Stream_Write_UINT8(drive->device.data,
'\0');
955 drive->device.name = Stream_BufferAs(drive->device.data,
char);
956 if (!drive->device.name)
959 if ((pathLength > 1) && (path[pathLength - 1] ==
'/'))
962 drive->path = ConvertUtf8NToWCharAlloc(path, pathLength, NULL);
965 error = CHANNEL_RC_NO_MEMORY;
969 drive->files = ListDictionary_New(TRUE);
973 WLog_ERR(TAG,
"ListDictionary_New failed!");
974 error = CHANNEL_RC_NO_MEMORY;
978 ListDictionary_ValueObject(drive->files)->fnObjectFree = drive_file_objfree;
979 drive->IrpQueue = MessageQueue_New(NULL);
981 if (!drive->IrpQueue)
983 WLog_ERR(TAG,
"ListDictionary_New failed!");
984 error = CHANNEL_RC_NO_MEMORY;
988 wObject* obj = MessageQueue_Object(drive->IrpQueue);
990 obj->fnObjectFree = drive_message_free;
992 if ((error = pEntryPoints->RegisterDevice(pEntryPoints->devman, (DEVICE*)drive)))
994 WLog_ERR(TAG,
"RegisterDevice failed with error %" PRIu32
"!", error);
998 if (!(drive->thread =
999 CreateThread(NULL, 0, drive_thread_func, drive, CREATE_SUSPENDED, NULL)))
1001 WLog_ERR(TAG,
"CreateThread failed!");
1005 ResumeThread(drive->thread);
1008 return CHANNEL_RC_OK;
1010 drive_free_int(drive);
1019 FREERDP_ENTRY_POINT(
1026 char devlist[512], buf[512];
1031 WINPR_ASSERT(pEntryPoints);
1034 WINPR_ASSERT(drive);
1037 if (strcmp(drive->Path,
"*") == 0)
1041 drive->Path = _strdup(
"/");
1045 WLog_ERR(TAG,
"_strdup failed!");
1046 return CHANNEL_RC_NO_MEMORY;
1049 else if (strcmp(drive->Path,
"%") == 0)
1052 drive->Path = GetKnownPath(KNOWN_PATH_HOME);
1056 WLog_ERR(TAG,
"_strdup failed!");
1057 return CHANNEL_RC_NO_MEMORY;
1062 drive_register_drive_path(pEntryPoints, drive->device.Name, drive->Path, drive->automount);
1066 if (strcmp(drive->Path,
"%") == 0)
1068 GetEnvironmentVariableA(
"USERPROFILE", buf,
sizeof(buf));
1069 PathCchAddBackslashA(buf,
sizeof(buf));
1071 drive->Path = _strdup(buf);
1075 WLog_ERR(TAG,
"_strdup failed!");
1076 return CHANNEL_RC_NO_MEMORY;
1079 error = drive_register_drive_path(pEntryPoints, drive->device.Name, drive->Path,
1082 else if (strcmp(drive->Path,
"*") == 0)
1085 GetLogicalDriveStringsA(
sizeof(devlist) - 1, devlist);
1087 for (
size_t i = 0;; i++)
1089 char* dev = &devlist[i * 4];
1095 len = sprintf_s(buf,
sizeof(buf) - 4,
"%s", drive->device.Name);
1097 buf[len + 1] = dev[0];
1101 if (!(bufdup = _strdup(buf)))
1103 WLog_ERR(TAG,
"_strdup failed!");
1104 return CHANNEL_RC_NO_MEMORY;
1107 if (!(devdup = _strdup(dev)))
1109 WLog_ERR(TAG,
"_strdup failed!");
1110 return CHANNEL_RC_NO_MEMORY;
1113 if ((error = drive_register_drive_path(pEntryPoints, bufdup, devdup, TRUE)))
1122 error = drive_register_drive_path(pEntryPoints, drive->device.Name, drive->Path,
This struct contains function pointer to initialize/free objects.