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;
60 wMessageQueue* IrpQueue;
64 rdpContext* rdpcontext;
67 static INT32 drive_map_windows_err(DWORD fs_errno)
79 case ERROR_ACCESS_DENIED:
80 case ERROR_SHARING_VIOLATION:
81 rc = STATUS_ACCESS_DENIED;
84 case ERROR_FILE_NOT_FOUND:
85 rc = STATUS_NO_SUCH_FILE;
88 case ERROR_BUSY_DRIVE:
89 rc = STATUS_DEVICE_BUSY;
92 case ERROR_INVALID_DRIVE:
93 rc = STATUS_NO_SUCH_DEVICE;
97 rc = STATUS_NO_SUCH_DEVICE;
100 case ERROR_FILE_EXISTS:
101 case ERROR_ALREADY_EXISTS:
102 rc = STATUS_OBJECT_NAME_COLLISION;
105 case ERROR_INVALID_NAME:
106 rc = STATUS_NO_SUCH_FILE;
109 case ERROR_INVALID_HANDLE:
110 rc = STATUS_INVALID_HANDLE;
113 case ERROR_NO_MORE_FILES:
114 rc = STATUS_NO_MORE_FILES;
117 case ERROR_DIRECTORY:
118 rc = STATUS_NOT_A_DIRECTORY;
121 case ERROR_PATH_NOT_FOUND:
122 rc = STATUS_OBJECT_PATH_NOT_FOUND;
126 rc = STATUS_UNSUCCESSFUL;
127 WLog_ERR(TAG,
"Error code not found: %" PRIu32
"", fs_errno);
134 static DRIVE_FILE* drive_get_file_by_id(DRIVE_DEVICE* drive, UINT32
id)
137 void* key = (
void*)(
size_t)id;
142 file = (
DRIVE_FILE*)ListDictionary_GetItemValue(drive->files, key);
151 static UINT drive_process_irp_create(DRIVE_DEVICE* drive, IRP* irp)
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;
165 if (!drive || !irp || !irp->devman || !irp->Complete)
166 return ERROR_INVALID_PARAMETER;
168 if (!Stream_CheckAndLogRequiredLength(TAG, irp->input, 6 * 4 + 8))
169 return ERROR_INVALID_DATA;
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);
179 if (!Stream_CheckAndLogRequiredLength(TAG, irp->input, PathLength))
180 return ERROR_INVALID_DATA;
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);
189 irp->IoStatus = drive_map_windows_err(GetLastError());
195 void* key = (
void*)(
size_t)file->id;
197 if (!ListDictionary_Add(drive->files, key, file))
199 WLog_ERR(TAG,
"ListDictionary_Add failed!");
200 return ERROR_INTERNAL_ERROR;
203 switch (CreateDisposition)
209 Information = FILE_SUPERSEDED;
213 Information = FILE_OPENED;
216 case FILE_OVERWRITE_IF:
217 Information = FILE_OVERWRITTEN;
226 Stream_Write_UINT32(irp->output, FileId);
227 Stream_Write_UINT8(irp->output, Information);
228 return irp->Complete(irp);
236 static UINT drive_process_irp_close(DRIVE_DEVICE* drive, IRP* irp)
241 if (!drive || !irp || !irp->Complete || !irp->output)
242 return ERROR_INVALID_PARAMETER;
244 file = drive_get_file_by_id(drive, irp->FileId);
245 key = (
void*)(
size_t)irp->FileId;
248 irp->IoStatus = STATUS_UNSUCCESSFUL;
251 ListDictionary_Take(drive->files, key);
253 if (drive_file_free(file))
254 irp->IoStatus = STATUS_SUCCESS;
256 irp->IoStatus = drive_map_windows_err(GetLastError());
259 Stream_Zero(irp->output, 5);
260 return irp->Complete(irp);
268 static UINT drive_process_irp_read(DRIVE_DEVICE* drive, IRP* irp)
274 if (!drive || !irp || !irp->output || !irp->Complete)
275 return ERROR_INVALID_PARAMETER;
277 if (!Stream_CheckAndLogRequiredLength(TAG, irp->input, 12))
278 return ERROR_INVALID_DATA;
280 Stream_Read_UINT32(irp->input, Length);
281 Stream_Read_UINT64(irp->input, Offset);
282 file = drive_get_file_by_id(drive, irp->FileId);
286 irp->IoStatus = STATUS_UNSUCCESSFUL;
289 else if (!drive_file_seek(file, Offset))
291 irp->IoStatus = drive_map_windows_err(GetLastError());
295 if (!Stream_EnsureRemainingCapacity(irp->output, Length + 4))
297 WLog_ERR(TAG,
"Stream_EnsureRemainingCapacity failed!");
298 return ERROR_INTERNAL_ERROR;
300 else if (Length == 0)
301 Stream_Write_UINT32(irp->output, 0);
304 BYTE* buffer = Stream_PointerAs(irp->output, BYTE) +
sizeof(UINT32);
306 if (!drive_file_read(file, buffer, &Length))
308 irp->IoStatus = drive_map_windows_err(GetLastError());
309 Stream_Write_UINT32(irp->output, 0);
313 Stream_Write_UINT32(irp->output, Length);
314 Stream_Seek(irp->output, Length);
318 return irp->Complete(irp);
326 static UINT drive_process_irp_write(DRIVE_DEVICE* drive, IRP* irp)
332 if (!drive || !irp || !irp->input || !irp->output || !irp->Complete)
333 return ERROR_INVALID_PARAMETER;
335 if (!Stream_CheckAndLogRequiredLength(TAG, irp->input, 32))
336 return ERROR_INVALID_DATA;
338 Stream_Read_UINT32(irp->input, Length);
339 Stream_Read_UINT64(irp->input, Offset);
340 Stream_Seek(irp->input, 20);
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);
348 irp->IoStatus = STATUS_UNSUCCESSFUL;
351 else if (!drive_file_seek(file, Offset))
353 irp->IoStatus = drive_map_windows_err(GetLastError());
356 else if (!drive_file_write(file, ptr, Length))
358 irp->IoStatus = drive_map_windows_err(GetLastError());
362 Stream_Write_UINT32(irp->output, Length);
363 Stream_Write_UINT8(irp->output, 0);
364 return irp->Complete(irp);
372 static UINT drive_process_irp_query_information(DRIVE_DEVICE* drive, IRP* irp)
375 UINT32 FsInformationClass = 0;
377 if (!drive || !irp || !irp->Complete)
378 return ERROR_INVALID_PARAMETER;
380 if (!Stream_CheckAndLogRequiredLength(TAG, irp->input, 4))
381 return ERROR_INVALID_DATA;
383 Stream_Read_UINT32(irp->input, FsInformationClass);
384 file = drive_get_file_by_id(drive, irp->FileId);
388 irp->IoStatus = STATUS_UNSUCCESSFUL;
390 else if (!drive_file_query_information(file, FsInformationClass, irp->output))
392 irp->IoStatus = drive_map_windows_err(GetLastError());
395 return irp->Complete(irp);
403 static UINT drive_process_irp_set_information(DRIVE_DEVICE* drive, IRP* irp)
406 UINT32 FsInformationClass = 0;
409 if (!drive || !irp || !irp->Complete || !irp->input || !irp->output)
410 return ERROR_INVALID_PARAMETER;
412 if (!Stream_CheckAndLogRequiredLength(TAG, irp->input, 32))
413 return ERROR_INVALID_DATA;
415 Stream_Read_UINT32(irp->input, FsInformationClass);
416 Stream_Read_UINT32(irp->input, Length);
417 Stream_Seek(irp->input, 24);
418 file = drive_get_file_by_id(drive, irp->FileId);
422 irp->IoStatus = STATUS_UNSUCCESSFUL;
424 else if (!drive_file_set_information(file, FsInformationClass, Length, irp->input))
426 irp->IoStatus = drive_map_windows_err(GetLastError());
429 if (file && file->is_dir && !PathIsDirectoryEmptyW(file->fullpath))
430 irp->IoStatus = STATUS_DIRECTORY_NOT_EMPTY;
432 Stream_Write_UINT32(irp->output, Length);
433 return irp->Complete(irp);
441 static UINT drive_process_irp_query_volume_information(DRIVE_DEVICE* drive, IRP* irp)
443 UINT32 FsInformationClass = 0;
445 DWORD lpSectorsPerCluster = 0;
446 DWORD lpBytesPerSector = 0;
447 DWORD lpNumberOfFreeClusters = 0;
448 DWORD lpTotalNumberOfClusters = 0;
450 WCHAR LabelBuffer[32] = { 0 };
453 return ERROR_INVALID_PARAMETER;
455 output = irp->output;
457 if (!Stream_CheckAndLogRequiredLength(TAG, irp->input, 4))
458 return ERROR_INVALID_DATA;
460 Stream_Read_UINT32(irp->input, FsInformationClass);
461 GetDiskFreeSpaceW(drive->path, &lpSectorsPerCluster, &lpBytesPerSector, &lpNumberOfFreeClusters,
462 &lpTotalNumberOfClusters);
464 switch (FsInformationClass)
466 case FileFsVolumeInformation:
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;
474 if ((length > UINT32_MAX) || (volumeLabelLen > UINT32_MAX))
475 return CHANNEL_RC_NO_BUFFER;
477 Stream_Write_UINT32(output, (UINT32)length);
479 if (!Stream_EnsureRemainingCapacity(output, length))
481 WLog_ERR(TAG,
"Stream_EnsureRemainingCapacity failed!");
482 return CHANNEL_RC_NO_MEMORY;
485 GetFileAttributesExW(drive->path, GetFileExInfoStandard, &wfad);
486 Stream_Write_UINT32(output, wfad.ftCreationTime.dwLowDateTime);
487 Stream_Write_UINT32(output,
488 wfad.ftCreationTime.dwHighDateTime);
489 Stream_Write_UINT32(output, lpNumberOfFreeClusters & 0xffff);
490 Stream_Write_UINT32(output, (UINT32)volumeLabelLen);
491 Stream_Write_UINT8(output, 0);
493 Stream_Write(output, volumeLabel, volumeLabelLen);
497 case FileFsSizeInformation:
499 Stream_Write_UINT32(output, 24);
501 if (!Stream_EnsureRemainingCapacity(output, 24))
503 WLog_ERR(TAG,
"Stream_EnsureRemainingCapacity failed!");
504 return CHANNEL_RC_NO_MEMORY;
507 Stream_Write_UINT64(output, lpTotalNumberOfClusters);
508 Stream_Write_UINT64(output, lpNumberOfFreeClusters);
509 Stream_Write_UINT32(output, lpSectorsPerCluster);
510 Stream_Write_UINT32(output, lpBytesPerSector);
513 case FileFsAttributeInformation:
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;
521 if ((length > UINT32_MAX) || (diskTypeLen > UINT32_MAX))
522 return CHANNEL_RC_NO_BUFFER;
524 Stream_Write_UINT32(output, (UINT32)length);
526 if (!Stream_EnsureRemainingCapacity(output, length))
528 WLog_ERR(TAG,
"Stream_EnsureRemainingCapacity failed!");
529 return CHANNEL_RC_NO_MEMORY;
532 Stream_Write_UINT32(output, FILE_CASE_SENSITIVE_SEARCH | FILE_CASE_PRESERVED_NAMES |
533 FILE_UNICODE_ON_DISK);
534 Stream_Write_UINT32(output, MAX_PATH);
535 Stream_Write_UINT32(output, (UINT32)diskTypeLen);
536 Stream_Write(output, diskType, diskTypeLen);
540 case FileFsFullSizeInformation:
542 Stream_Write_UINT32(output, 32);
544 if (!Stream_EnsureRemainingCapacity(output, 32))
546 WLog_ERR(TAG,
"Stream_EnsureRemainingCapacity failed!");
547 return CHANNEL_RC_NO_MEMORY;
550 Stream_Write_UINT64(output, lpTotalNumberOfClusters);
551 Stream_Write_UINT64(output,
552 lpNumberOfFreeClusters);
553 Stream_Write_UINT64(output, lpNumberOfFreeClusters);
554 Stream_Write_UINT32(output, lpSectorsPerCluster);
555 Stream_Write_UINT32(output, lpBytesPerSector);
558 case FileFsDeviceInformation:
560 Stream_Write_UINT32(output, 8);
562 if (!Stream_EnsureRemainingCapacity(output, 8))
564 WLog_ERR(TAG,
"Stream_EnsureRemainingCapacity failed!");
565 return CHANNEL_RC_NO_MEMORY;
568 Stream_Write_UINT32(output, FILE_DEVICE_DISK);
569 Stream_Write_UINT32(output, 0);
573 irp->IoStatus = STATUS_UNSUCCESSFUL;
574 Stream_Write_UINT32(output, 0);
578 return irp->Complete(irp);
588 static UINT drive_process_irp_silent_ignore(DRIVE_DEVICE* drive, IRP* irp)
590 UINT32 FsInformationClass = 0;
592 if (!drive || !irp || !irp->output || !irp->Complete)
593 return ERROR_INVALID_PARAMETER;
595 if (!Stream_CheckAndLogRequiredLength(TAG, irp->input, 4))
596 return ERROR_INVALID_DATA;
598 Stream_Read_UINT32(irp->input, FsInformationClass);
599 Stream_Write_UINT32(irp->output, 0);
600 return irp->Complete(irp);
608 static UINT drive_process_irp_query_directory(DRIVE_DEVICE* drive, IRP* irp)
610 const WCHAR* path = NULL;
612 BYTE InitialQuery = 0;
613 UINT32 PathLength = 0;
614 UINT32 FsInformationClass = 0;
616 if (!drive || !irp || !irp->Complete)
617 return ERROR_INVALID_PARAMETER;
619 if (!Stream_CheckAndLogRequiredLength(TAG, irp->input, 32))
620 return ERROR_INVALID_DATA;
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);
626 path = Stream_ConstPointer(irp->input);
627 if (!Stream_CheckAndLogRequiredLength(TAG, irp->input, PathLength))
628 return ERROR_INVALID_DATA;
630 file = drive_get_file_by_id(drive, irp->FileId);
634 irp->IoStatus = STATUS_UNSUCCESSFUL;
635 Stream_Write_UINT32(irp->output, 0);
637 else if (!drive_file_query_directory(file, FsInformationClass, InitialQuery, path,
638 PathLength /
sizeof(WCHAR), irp->output))
640 irp->IoStatus = drive_map_windows_err(GetLastError());
643 return irp->Complete(irp);
651 static UINT drive_process_irp_directory_control(DRIVE_DEVICE* drive, IRP* irp)
654 return ERROR_INVALID_PARAMETER;
656 switch (irp->MinorFunction)
658 case IRP_MN_QUERY_DIRECTORY:
659 return drive_process_irp_query_directory(drive, irp);
661 case IRP_MN_NOTIFY_CHANGE_DIRECTORY:
662 return irp->Discard(irp);
665 irp->IoStatus = STATUS_NOT_SUPPORTED;
666 Stream_Write_UINT32(irp->output, 0);
667 return irp->Complete(irp);
670 return CHANNEL_RC_OK;
678 static UINT drive_process_irp_device_control(DRIVE_DEVICE* drive, IRP* irp)
681 return ERROR_INVALID_PARAMETER;
683 Stream_Write_UINT32(irp->output, 0);
684 return irp->Complete(irp);
692 static UINT drive_process_irp(DRIVE_DEVICE* drive, IRP* irp)
697 return ERROR_INVALID_PARAMETER;
699 irp->IoStatus = STATUS_SUCCESS;
701 switch (irp->MajorFunction)
704 error = drive_process_irp_create(drive, irp);
708 error = drive_process_irp_close(drive, irp);
712 error = drive_process_irp_read(drive, irp);
716 error = drive_process_irp_write(drive, irp);
719 case IRP_MJ_QUERY_INFORMATION:
720 error = drive_process_irp_query_information(drive, irp);
723 case IRP_MJ_SET_INFORMATION:
724 error = drive_process_irp_set_information(drive, irp);
727 case IRP_MJ_QUERY_VOLUME_INFORMATION:
728 error = drive_process_irp_query_volume_information(drive, irp);
731 case IRP_MJ_LOCK_CONTROL:
732 error = drive_process_irp_silent_ignore(drive, irp);
735 case IRP_MJ_DIRECTORY_CONTROL:
736 error = drive_process_irp_directory_control(drive, irp);
739 case IRP_MJ_DEVICE_CONTROL:
740 error = drive_process_irp_device_control(drive, irp);
744 irp->IoStatus = STATUS_NOT_SUPPORTED;
745 error = irp->Complete(irp);
752 static BOOL drive_poll_run(DRIVE_DEVICE* drive, IRP* irp)
758 const UINT error = drive_process_irp(drive, irp);
761 WLog_ERR(TAG,
"drive_process_irp failed with error %" PRIu32
"!", error);
769 static DWORD WINAPI drive_thread_func(LPVOID arg)
771 DRIVE_DEVICE* drive = (DRIVE_DEVICE*)arg;
772 UINT error = CHANNEL_RC_OK;
776 error = ERROR_INVALID_PARAMETER;
782 if (!MessageQueue_Wait(drive->IrpQueue))
784 WLog_ERR(TAG,
"MessageQueue_Wait failed!");
785 error = ERROR_INTERNAL_ERROR;
789 if (MessageQueue_Size(drive->IrpQueue) < 1)
792 wMessage message = { 0 };
793 if (!MessageQueue_Peek(drive->IrpQueue, &message, TRUE))
795 WLog_ERR(TAG,
"MessageQueue_Peek failed!");
799 if (message.id == WMQ_QUIT)
802 IRP* irp = (IRP*)message.wParam;
803 if (!drive_poll_run(drive, irp))
809 if (error && drive && drive->rdpcontext)
810 setChannelError(drive->rdpcontext, error,
"drive_thread_func reported an error");
821 static UINT drive_irp_request(DEVICE* device, IRP* irp)
823 DRIVE_DEVICE* drive = (DRIVE_DEVICE*)device;
826 return ERROR_INVALID_PARAMETER;
830 if (!MessageQueue_Post(drive->IrpQueue, NULL, 0, (
void*)irp, NULL))
832 WLog_ERR(TAG,
"MessageQueue_Post failed!");
833 return ERROR_INTERNAL_ERROR;
838 if (!drive_poll_run(drive, irp))
839 return ERROR_INTERNAL_ERROR;
842 return CHANNEL_RC_OK;
845 static UINT drive_free_int(DRIVE_DEVICE* drive)
847 UINT error = CHANNEL_RC_OK;
850 return ERROR_INVALID_PARAMETER;
852 (void)CloseHandle(drive->thread);
853 ListDictionary_Free(drive->files);
854 MessageQueue_Free(drive->IrpQueue);
855 Stream_Free(drive->device.data, TRUE);
866 static UINT drive_free(DEVICE* device)
868 DRIVE_DEVICE* drive = (DRIVE_DEVICE*)device;
869 UINT error = CHANNEL_RC_OK;
872 return ERROR_INVALID_PARAMETER;
874 if (MessageQueue_PostQuit(drive->IrpQueue, 0) &&
875 (WaitForSingleObject(drive->thread, INFINITE) == WAIT_FAILED))
877 error = GetLastError();
878 WLog_ERR(TAG,
"WaitForSingleObject failed with error %" PRIu32
"", error);
882 return drive_free_int(drive);
888 static void drive_file_objfree(
void* obj)
893 static void drive_message_free(
void* obj)
901 IRP* irp = (IRP*)msg->wParam;
904 WINPR_ASSERT(irp->Discard);
914 const char* path, BOOL automount)
917 DRIVE_DEVICE* drive = NULL;
918 UINT error = ERROR_INTERNAL_ERROR;
920 if (!pEntryPoints || !name || !path)
922 WLog_ERR(TAG,
"[%s] Invalid parameters: pEntryPoints=%p, name=%p, path=%p", pEntryPoints,
924 return ERROR_INVALID_PARAMETER;
927 if (name[0] && path[0])
929 size_t pathLength = strnlen(path, MAX_PATH);
930 drive = (DRIVE_DEVICE*)calloc(1,
sizeof(DRIVE_DEVICE));
934 WLog_ERR(TAG,
"calloc failed!");
935 return CHANNEL_RC_NO_MEMORY;
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);
946 if (!drive->device.data)
948 WLog_ERR(TAG,
"Stream_New failed!");
949 error = CHANNEL_RC_NO_MEMORY;
953 for (
size_t i = 0; i < length; i++)
966 Stream_Write_UINT8(drive->device.data,
'_');
969 Stream_Write_UINT8(drive->device.data, (BYTE)name[i]);
973 Stream_Write_UINT8(drive->device.data,
'\0');
975 drive->device.name = Stream_BufferAs(drive->device.data,
char);
976 if (!drive->device.name)
979 if ((pathLength > 1) && (path[pathLength - 1] ==
'/'))
982 drive->path = ConvertUtf8NToWCharAlloc(path, pathLength, NULL);
985 error = CHANNEL_RC_NO_MEMORY;
989 drive->files = ListDictionary_New(TRUE);
993 WLog_ERR(TAG,
"ListDictionary_New failed!");
994 error = CHANNEL_RC_NO_MEMORY;
998 ListDictionary_ValueObject(drive->files)->fnObjectFree = drive_file_objfree;
999 drive->IrpQueue = MessageQueue_New(NULL);
1001 if (!drive->IrpQueue)
1003 WLog_ERR(TAG,
"ListDictionary_New failed!");
1004 error = CHANNEL_RC_NO_MEMORY;
1008 wObject* obj = MessageQueue_Object(drive->IrpQueue);
1010 obj->fnObjectFree = drive_message_free;
1012 if ((error = pEntryPoints->RegisterDevice(pEntryPoints->devman, (DEVICE*)drive)))
1014 WLog_ERR(TAG,
"RegisterDevice failed with error %" PRIu32
"!", error);
1019 FreeRDP_SynchronousStaticChannels);
1022 if (!(drive->thread =
1023 CreateThread(NULL, 0, drive_thread_func, drive, CREATE_SUSPENDED, NULL)))
1025 WLog_ERR(TAG,
"CreateThread failed!");
1029 ResumeThread(drive->thread);
1033 return CHANNEL_RC_OK;
1035 drive_free_int(drive);
1044 FREERDP_ENTRY_POINT(
1051 char devlist[512], buf[512];
1056 WINPR_ASSERT(pEntryPoints);
1059 WINPR_ASSERT(drive);
1062 if (strcmp(drive->Path,
"*") == 0)
1066 drive->Path = _strdup(
"/");
1070 WLog_ERR(TAG,
"_strdup failed!");
1071 return CHANNEL_RC_NO_MEMORY;
1074 else if (strcmp(drive->Path,
"%") == 0)
1077 drive->Path = GetKnownPath(KNOWN_PATH_HOME);
1081 WLog_ERR(TAG,
"_strdup failed!");
1082 return CHANNEL_RC_NO_MEMORY;
1087 drive_register_drive_path(pEntryPoints, drive->device.Name, drive->Path, drive->automount);
1091 if (strcmp(drive->Path,
"%") == 0)
1093 GetEnvironmentVariableA(
"USERPROFILE", buf,
sizeof(buf));
1094 PathCchAddBackslashA(buf,
sizeof(buf));
1096 drive->Path = _strdup(buf);
1100 WLog_ERR(TAG,
"_strdup failed!");
1101 return CHANNEL_RC_NO_MEMORY;
1104 error = drive_register_drive_path(pEntryPoints, drive->device.Name, drive->Path,
1107 else if (strcmp(drive->Path,
"*") == 0)
1110 GetLogicalDriveStringsA(
sizeof(devlist) - 1, devlist);
1112 for (
size_t i = 0;; i++)
1114 char* dev = &devlist[i * 4];
1120 len = sprintf_s(buf,
sizeof(buf) - 4,
"%s", drive->device.Name);
1122 buf[len + 1] = dev[0];
1126 if (!(bufdup = _strdup(buf)))
1128 WLog_ERR(TAG,
"_strdup failed!");
1129 return CHANNEL_RC_NO_MEMORY;
1132 if (!(devdup = _strdup(dev)))
1134 WLog_ERR(TAG,
"_strdup failed!");
1135 return CHANNEL_RC_NO_MEMORY;
1138 if ((error = drive_register_drive_path(pEntryPoints, bufdup, devdup, TRUE)))
1147 error = drive_register_drive_path(pEntryPoints, drive->device.Name, drive->Path,
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.