28#include <freerdp/config.h>
36#include <winpr/wtypes.h>
38#include <winpr/string.h>
39#include <winpr/path.h>
40#include <winpr/file.h>
41#include <winpr/stream.h>
43#include <freerdp/channels/rdpdr.h>
45#include "drive_file.h"
47#ifdef WITH_DEBUG_RDPDR
48#define DEBUG_WSTR(msg, wstr) \
51 char lpstr[1024] = WINPR_C_ARRAY_INIT; \
52 (void)ConvertWCharToUtf8(wstr, lpstr, ARRAYSIZE(lpstr)); \
53 WLog_DBG(TAG, msg, lpstr); \
56#define DEBUG_WSTR(msg, wstr) \
62static BOOL drive_file_fix_path(WCHAR* path,
size_t length)
64 if ((length == 0) || (length > UINT32_MAX))
69 for (
size_t i = 0; i < length; i++)
77 if ((length == 3) && (path[1] == L
':') && (path[2] == L
'/'))
82 if ((length == 1) && (path[0] == L
'/'))
87 if ((length > 0) && (path[length - 1] == L
'/'))
88 path[length - 1] = L
'\0';
93static BOOL contains_dotdot(
const WCHAR* path,
size_t base_length,
size_t path_length)
95 WCHAR dotdotbuffer[6] = WINPR_C_ARRAY_INIT;
96 const WCHAR* dotdot = InitializeConstWCharFromUtf8(
"..", dotdotbuffer, ARRAYSIZE(dotdotbuffer));
97 const WCHAR* tst = path;
104 tst = _wcsstr(tst, dotdot);
109 if ((base_length == 0) || (*(tst - 1) == L
'/') || (*(tst - 1) == L
'\\'))
111 if (tst + 2 < path + path_length)
113 if ((tst[2] ==
'/') || (tst[2] ==
'\\'))
125static WCHAR* drive_file_combine_fullpath(
const WCHAR* base_path,
const WCHAR* path,
126 size_t PathWCharLength)
129 WCHAR* fullpath =
nullptr;
131 if (!base_path || (!path && (PathWCharLength > 0)))
135 const size_t base_path_length = _wcsnlen(base_path, MAX_PATH);
136 const size_t length = base_path_length + PathWCharLength + 1;
137 fullpath = (WCHAR*)calloc(length,
sizeof(WCHAR));
142 CopyMemory(fullpath, base_path, base_path_length *
sizeof(WCHAR));
144 CopyMemory(&fullpath[base_path_length], path, PathWCharLength *
sizeof(WCHAR));
146 if (!drive_file_fix_path(fullpath, length))
150 if (contains_dotdot(&fullpath[base_path_length], base_path_length, PathWCharLength))
152 char* abuffer = ConvertWCharToUtf8Alloc(&fullpath[base_path_length],
nullptr);
153 WLog_WARN(TAG,
"[rdpdr] received invalid file path '%s' from server, aborting!",
170static BOOL drive_file_set_fullpath(
DRIVE_FILE* file,
const WCHAR* fullpath)
172 if (!file || !fullpath)
175 const size_t len = _wcslen(fullpath);
176 free(file->fullpath);
177 file->fullpath =
nullptr;
182 file->fullpath = _wcsdup(fullpath);
186 const WCHAR sep[] = { PathGetSeparatorW(PATH_STYLE_NATIVE),
'\0' };
187 WCHAR* filename = _wcsrchr(file->fullpath, *sep);
188 if (filename && _wcsncmp(filename, sep, ARRAYSIZE(sep)) == 0)
196 UINT CreateDisposition = 0;
197 DWORD dwAttr = GetFileAttributesW(file->fullpath);
199 if (dwAttr != INVALID_FILE_ATTRIBUTES)
202 file->is_dir = (dwAttr & FILE_ATTRIBUTE_DIRECTORY) != 0;
206 if (file->CreateDisposition == FILE_CREATE)
208 SetLastError(ERROR_ALREADY_EXISTS);
212 if (file->CreateOptions & FILE_NON_DIRECTORY_FILE)
214 SetLastError(ERROR_ACCESS_DENIED);
222 if (file->CreateOptions & FILE_DIRECTORY_FILE)
224 SetLastError(ERROR_DIRECTORY);
231 file->is_dir = ((file->CreateOptions & FILE_DIRECTORY_FILE) != 0);
236 if ((file->CreateDisposition == FILE_OPEN_IF) ||
237 (file->CreateDisposition == FILE_CREATE))
239 if (CreateDirectoryW(file->fullpath,
nullptr) != 0)
245 SetLastError(ERROR_FILE_NOT_FOUND);
250 if (file->file_handle == INVALID_HANDLE_VALUE)
252 switch (file->CreateDisposition)
256 CreateDisposition = CREATE_ALWAYS;
261 CreateDisposition = OPEN_EXISTING;
266 CreateDisposition = CREATE_NEW;
271 CreateDisposition = OPEN_ALWAYS;
276 CreateDisposition = TRUNCATE_EXISTING;
279 case FILE_OVERWRITE_IF:
281 CreateDisposition = CREATE_ALWAYS;
289 file->SharedAccess = 0;
291 file->file_handle = CreateFileW(file->fullpath, file->DesiredAccess, file->SharedAccess,
292 nullptr, CreateDisposition, file->FileAttributes,
nullptr);
296 if (file->file_handle == INVALID_HANDLE_VALUE)
299 DWORD errorMessageID = GetLastError();
301 if (errorMessageID != 0)
303 LPSTR messageBuffer =
nullptr;
305 FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
306 FORMAT_MESSAGE_IGNORE_INSERTS,
307 nullptr, errorMessageID, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
308 (LPSTR)&messageBuffer, 0,
nullptr);
309 char fullpath[MAX_PATH] = WINPR_C_ARRAY_INIT;
310 (void)ConvertWCharToUtf8(file->fullpath, fullpath,
sizeof(fullpath));
311 WLog_ERR(TAG,
"Error in drive_file_init: %s %s", messageBuffer, fullpath);
313 LocalFree(messageBuffer);
315 SetLastError(errorMessageID);
320 return file->file_handle != INVALID_HANDLE_VALUE;
323DRIVE_FILE* drive_file_new(
const WCHAR* base_path,
const WCHAR* path, UINT32 PathWCharLength,
324 UINT32
id, UINT32 DesiredAccess, UINT32 CreateDisposition,
325 UINT32 CreateOptions, UINT32 FileAttributes, UINT32 SharedAccess)
327 if (!base_path || (!path && (PathWCharLength > 0)))
334 WLog_ERR(TAG,
"calloc failed!");
338 file->file_handle = INVALID_HANDLE_VALUE;
339 file->find_handle = INVALID_HANDLE_VALUE;
341 file->basepath = base_path;
342 file->FileAttributes = FileAttributes;
343 file->DesiredAccess = DesiredAccess;
344 file->CreateDisposition = CreateDisposition;
345 file->CreateOptions = CreateOptions;
346 file->SharedAccess = SharedAccess;
348 WCHAR* p = drive_file_combine_fullpath(base_path, path, PathWCharLength);
349 (void)drive_file_set_fullpath(file, p);
352 if (!drive_file_init(file))
354 DWORD lastError = GetLastError();
355 drive_file_free(file);
356 SetLastError(lastError);
370 if (file->file_handle != INVALID_HANDLE_VALUE)
372 (void)CloseHandle(file->file_handle);
373 file->file_handle = INVALID_HANDLE_VALUE;
376 if (file->find_handle != INVALID_HANDLE_VALUE)
378 FindClose(file->find_handle);
379 file->find_handle = INVALID_HANDLE_VALUE;
382 if (file->CreateOptions & FILE_DELETE_ON_CLOSE)
383 file->delete_pending = TRUE;
385 if (file->delete_pending)
389 if (!winpr_RemoveDirectory_RecursiveW(file->fullpath))
392 else if (!DeleteFileW(file->fullpath))
398 DEBUG_WSTR(
"Free %s", file->fullpath);
399 free(file->fullpath);
404BOOL drive_file_seek(
DRIVE_FILE* file, UINT64 Offset)
411 if (Offset > INT64_MAX)
414 loffset.QuadPart = (LONGLONG)Offset;
415 return SetFilePointerEx(file->file_handle, loffset,
nullptr, FILE_BEGIN);
418BOOL drive_file_read(
DRIVE_FILE* file, BYTE* buffer, UINT32* Length)
422 if (!file || !buffer || !Length)
425 DEBUG_WSTR(
"Read file %s", file->fullpath);
427 if (ReadFile(file->file_handle, buffer, *Length, &read,
nullptr))
436BOOL drive_file_write(
DRIVE_FILE* file,
const BYTE* buffer, UINT32 Length)
440 if (!file || !buffer)
443 DEBUG_WSTR(
"Write file %s", file->fullpath);
447 if (!WriteFile(file->file_handle, buffer, Length, &written,
nullptr))
457static BOOL drive_file_query_from_handle_information(
const DRIVE_FILE* file,
459 UINT32 FsInformationClass,
wStream* output)
461 switch (FsInformationClass)
463 case FileBasicInformation:
466 if (!Stream_EnsureRemainingCapacity(output, 4 + 36))
469 Stream_Write_UINT32(output, 36);
470 Stream_Write_UINT32(output, info->ftCreationTime.dwLowDateTime);
471 Stream_Write_UINT32(output, info->ftCreationTime.dwHighDateTime);
472 Stream_Write_UINT32(output, info->ftLastAccessTime.dwLowDateTime);
473 Stream_Write_UINT32(output, info->ftLastAccessTime.dwHighDateTime);
474 Stream_Write_UINT32(output, info->ftLastWriteTime.dwLowDateTime);
475 Stream_Write_UINT32(output, info->ftLastWriteTime.dwHighDateTime);
476 Stream_Write_UINT32(output, info->ftLastWriteTime.dwLowDateTime);
477 Stream_Write_UINT32(output, info->ftLastWriteTime.dwHighDateTime);
478 Stream_Write_UINT32(output, info->dwFileAttributes);
482 case FileStandardInformation:
485 if (!Stream_EnsureRemainingCapacity(output, 4 + 22))
488 Stream_Write_UINT32(output, 22);
489 Stream_Write_UINT32(output, info->nFileSizeLow);
490 Stream_Write_UINT32(output, info->nFileSizeHigh);
491 Stream_Write_UINT32(output, info->nFileSizeLow);
492 Stream_Write_UINT32(output, info->nFileSizeHigh);
493 Stream_Write_UINT32(output, info->nNumberOfLinks);
494 Stream_Write_UINT8(output, file->delete_pending ? 1 : 0);
495 Stream_Write_UINT8(output, (info->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) !=
500 case FileAttributeTagInformation:
503 if (!Stream_EnsureRemainingCapacity(output, 4 + 8))
506 Stream_Write_UINT32(output, 8);
507 Stream_Write_UINT32(output, info->dwFileAttributes);
508 Stream_Write_UINT32(output, 0);
513 WLog_WARN(TAG,
"Unhandled FSInformationClass %s [0x%08" PRIx32
"]",
514 FSInformationClass2Tag(FsInformationClass), FsInformationClass);
521static BOOL drive_file_query_from_attributes(
const DRIVE_FILE* file,
523 UINT32 FsInformationClass,
wStream* output)
525 switch (FsInformationClass)
527 case FileBasicInformation:
530 if (!Stream_EnsureRemainingCapacity(output, 4 + 36))
533 Stream_Write_UINT32(output, 36);
534 Stream_Write_UINT32(output, attrib->ftCreationTime.dwLowDateTime);
535 Stream_Write_UINT32(output, attrib->ftCreationTime.dwHighDateTime);
536 Stream_Write_UINT32(output,
537 attrib->ftLastAccessTime.dwLowDateTime);
538 Stream_Write_UINT32(output,
539 attrib->ftLastAccessTime.dwHighDateTime);
540 Stream_Write_UINT32(output, attrib->ftLastWriteTime.dwLowDateTime);
541 Stream_Write_UINT32(output, attrib->ftLastWriteTime.dwHighDateTime);
542 Stream_Write_UINT32(output, attrib->ftLastWriteTime.dwLowDateTime);
543 Stream_Write_UINT32(output, attrib->ftLastWriteTime.dwHighDateTime);
544 Stream_Write_UINT32(output, attrib->dwFileAttributes);
548 case FileStandardInformation:
551 if (!Stream_EnsureRemainingCapacity(output, 4 + 22))
554 Stream_Write_UINT32(output, 22);
555 Stream_Write_UINT32(output, attrib->nFileSizeLow);
556 Stream_Write_UINT32(output, attrib->nFileSizeHigh);
557 Stream_Write_UINT32(output, attrib->nFileSizeLow);
558 Stream_Write_UINT32(output, attrib->nFileSizeHigh);
559 Stream_Write_UINT32(output, 0);
560 Stream_Write_UINT8(output, file->delete_pending ? 1 : 0);
561 Stream_Write_UINT8(output, (attrib->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) !=
566 case FileAttributeTagInformation:
569 if (!Stream_EnsureRemainingCapacity(output, 4 + 8))
572 Stream_Write_UINT32(output, 8);
573 Stream_Write_UINT32(output, attrib->dwFileAttributes);
574 Stream_Write_UINT32(output, 0);
579 WLog_WARN(TAG,
"Unhandled FSInformationClass %s [0x%08" PRIx32
"]",
580 FSInformationClass2Tag(FsInformationClass), FsInformationClass);
587BOOL drive_file_query_information(
DRIVE_FILE* file, UINT32 FsInformationClass,
wStream* output)
592 if (!file || !output)
595 if ((file->file_handle != INVALID_HANDLE_VALUE) &&
596 GetFileInformationByHandle(file->file_handle, &fileInformation))
597 return drive_file_query_from_handle_information(file, &fileInformation, FsInformationClass,
602 HANDLE hFile = CreateFileW(file->fullpath, 0, FILE_SHARE_DELETE,
nullptr, OPEN_EXISTING,
603 FILE_ATTRIBUTE_NORMAL,
nullptr);
604 if (hFile != INVALID_HANDLE_VALUE)
606 status = GetFileInformationByHandle(hFile, &fileInformation);
607 (void)CloseHandle(hFile);
611 if (!drive_file_query_from_handle_information(file, &fileInformation,
612 FsInformationClass, output))
623 if (!GetFileAttributesExW(file->fullpath, GetFileExInfoStandard, &fileAttributes))
626 if (!drive_file_query_from_attributes(file, &fileAttributes, FsInformationClass, output))
632 Stream_Write_UINT32(output, 0);
636static BOOL drive_file_set_basic_information(
DRIVE_FILE* file, UINT32 Length,
wStream* input)
640 const uint32_t expect = 36;
641 if (Length != expect)
643 WLog_WARN(TAG,
"Unexpected Length=%" PRIu32
", expected %" PRIu32, Length, expect);
648 const ULARGE_INTEGER liCreationTime = { .QuadPart = Stream_Get_UINT64(input) };
649 const ULARGE_INTEGER liLastAccessTime = { .QuadPart = Stream_Get_UINT64(input) };
650 const ULARGE_INTEGER liLastWriteTime = { .QuadPart = Stream_Get_UINT64(input) };
651 const ULARGE_INTEGER liChangeTime = { .QuadPart = Stream_Get_UINT64(input) };
652 const uint32_t FileAttributes = Stream_Get_UINT32(input);
654 if (!PathFileExistsW(file->fullpath))
657 if (file->file_handle == INVALID_HANDLE_VALUE)
659 char fullpath[MAX_PATH] = WINPR_C_ARRAY_INIT;
660 (void)ConvertWCharToUtf8(file->fullpath, fullpath,
sizeof(fullpath) - 1);
662 WLog_ERR(TAG,
"Unable to set file time %s (%" PRIu32
")", fullpath, GetLastError());
666 FILETIME ftCreationTime = WINPR_C_ARRAY_INIT;
667 FILETIME ftLastAccessTime = WINPR_C_ARRAY_INIT;
668 FILETIME ftLastWriteTime = WINPR_C_ARRAY_INIT;
669 FILETIME* pftCreationTime =
nullptr;
670 FILETIME* pftLastAccessTime =
nullptr;
671 FILETIME* pftLastWriteTime =
nullptr;
672 if (liCreationTime.QuadPart != 0)
674 ftCreationTime.dwHighDateTime = liCreationTime.u.HighPart;
675 ftCreationTime.dwLowDateTime = liCreationTime.u.LowPart;
676 pftCreationTime = &ftCreationTime;
679 if (liLastAccessTime.QuadPart != 0)
681 ftLastAccessTime.dwHighDateTime = liLastAccessTime.u.HighPart;
682 ftLastAccessTime.dwLowDateTime = liLastAccessTime.u.LowPart;
683 pftLastAccessTime = &ftLastAccessTime;
686 if (liLastWriteTime.QuadPart != 0)
688 ftLastWriteTime.dwHighDateTime = liLastWriteTime.u.HighPart;
689 ftLastWriteTime.dwLowDateTime = liLastWriteTime.u.LowPart;
690 pftLastWriteTime = &ftLastWriteTime;
693 if (liChangeTime.QuadPart != 0 && liChangeTime.QuadPart > liLastWriteTime.QuadPart)
695 ftLastWriteTime.dwHighDateTime = liChangeTime.u.HighPart;
696 ftLastWriteTime.dwLowDateTime = liChangeTime.u.LowPart;
697 pftLastWriteTime = &ftLastWriteTime;
700 DEBUG_WSTR(
"SetFileTime %s", file->fullpath);
702 if (!SetFileAttributesW(file->fullpath, FileAttributes))
704 char fullpath[MAX_PATH] = WINPR_C_ARRAY_INIT;
705 (void)ConvertWCharToUtf8(file->fullpath, fullpath,
sizeof(fullpath));
706 WLog_ERR(TAG,
"Unable to set file attributes for %s", fullpath);
710 if (!SetFileTime(file->file_handle, pftCreationTime, pftLastAccessTime, pftLastWriteTime))
712 char fullpath[MAX_PATH] = WINPR_C_ARRAY_INIT;
713 (void)ConvertWCharToUtf8(file->fullpath, fullpath,
sizeof(fullpath));
714 WLog_ERR(TAG,
"Unable to set file time for %s", fullpath);
720static BOOL drive_file_set_alloc_information(
DRIVE_FILE* file, UINT32 Length,
wStream* input)
723 const uint32_t expect = 8;
724 if (Length != expect)
726 WLog_WARN(TAG,
"Unexpected Length=%" PRIu32
", expected %" PRIu32, Length, expect);
731 const int64_t size = Stream_Get_INT64(input);
733 if (file->file_handle == INVALID_HANDLE_VALUE)
735 char fullpath[MAX_PATH] = WINPR_C_ARRAY_INIT;
736 (void)ConvertWCharToUtf8(file->fullpath, fullpath,
sizeof(fullpath));
737 WLog_ERR(TAG,
"Unable to truncate %s to %" PRId64
" (%" PRIu32
")", fullpath, size,
744 if (!SetFilePointerEx(file->file_handle, liSize,
nullptr, FILE_BEGIN))
746 char fullpath[MAX_PATH] = WINPR_C_ARRAY_INIT;
747 (void)ConvertWCharToUtf8(file->fullpath, fullpath,
sizeof(fullpath));
748 WLog_ERR(TAG,
"Unable to truncate %s to %" PRId64
" (%" PRIu32
")", fullpath, size,
753 DEBUG_WSTR(
"Truncate %s", file->fullpath);
755 if (SetEndOfFile(file->file_handle) == 0)
757 char fullpath[MAX_PATH] = WINPR_C_ARRAY_INIT;
758 (void)ConvertWCharToUtf8(file->fullpath, fullpath,
sizeof(fullpath));
759 WLog_ERR(TAG,
"Unable to truncate %s to %" PRId64
" (%" PRIu32
")", fullpath, size,
767static BOOL drive_file_set_disposition_information(
DRIVE_FILE* file, UINT32 Length,
wStream* input)
770 uint8_t delete_pending = 0;
773 if (file->is_dir && !PathIsDirectoryEmptyW(file->fullpath))
775 SetLastError(ERROR_DIR_NOT_EMPTY);
781 const uint32_t expect = 1;
782 if (Length != expect)
783 WLog_DBG(TAG,
"Unexpected Length=%" PRIu32
", expected %" PRIu32, Length, expect);
785 delete_pending = Stream_Get_UINT8(input);
792 DEBUG_WSTR(
"SetDeletePending %s", file->fullpath);
793 const uint32_t attr = GetFileAttributesW(file->fullpath);
795 if (attr & FILE_ATTRIBUTE_READONLY)
797 SetLastError(ERROR_ACCESS_DENIED);
802 file->delete_pending = delete_pending;
806static BOOL drive_file_set_rename_information(
DRIVE_FILE* file, UINT32 Length,
wStream* input)
810 const uint32_t expect = 6;
813 WLog_WARN(TAG,
"Unexpected Length=%" PRIu32
", expected at least %" PRIu32, Length, expect);
818 const uint8_t ReplaceIfExists = Stream_Get_UINT8(input);
819 Stream_Seek_UINT8(input);
820 const uint32_t FileNameLength = Stream_Get_UINT32(input);
822 if (Length != expect + FileNameLength)
824 WLog_WARN(TAG,
"Unexpected Length=%" PRIu32
", expected %" PRIu32, Length,
825 expect + FileNameLength);
829 WCHAR* fullpath = drive_file_combine_fullpath(file->basepath, Stream_ConstPointer(input),
830 FileNameLength /
sizeof(WCHAR));
837 if (file->file_handle != INVALID_HANDLE_VALUE)
839 (void)CloseHandle(file->file_handle);
840 file->file_handle = INVALID_HANDLE_VALUE;
844 DEBUG_WSTR(
"MoveFileExW %s", file->fullpath);
846 if (MoveFileExW(file->fullpath, fullpath,
847 MOVEFILE_COPY_ALLOWED | (ReplaceIfExists ? MOVEFILE_REPLACE_EXISTING : 0)))
849 const BOOL rc = drive_file_set_fullpath(file, fullpath);
861 drive_file_init(file);
866BOOL drive_file_set_information(
DRIVE_FILE* file, UINT32 FsInformationClass, UINT32 Length,
872 if (!Stream_CheckAndLogRequiredLength(TAG, input, Length))
875 switch (FsInformationClass)
877 case FileBasicInformation:
878 return drive_file_set_basic_information(file, Length, input);
880 case FileEndOfFileInformation:
882 case FileAllocationInformation:
883 return drive_file_set_alloc_information(file, Length, input);
885 case FileDispositionInformation:
886 return drive_file_set_disposition_information(file, Length, input);
888 case FileRenameInformation:
889 return drive_file_set_rename_information(file, Length, input);
892 WLog_WARN(TAG,
"Unhandled FSInformationClass %s [0x%08" PRIx32
"]",
893 FSInformationClass2Tag(FsInformationClass), FsInformationClass);
900static BOOL drive_file_query_dir_info(
DRIVE_FILE* file,
wStream* output,
size_t length)
903 WINPR_ASSERT(output);
906 if (!Stream_EnsureRemainingCapacity(output, 4 + 64 + length))
909 if (length > UINT32_MAX - 64)
912 Stream_Write_UINT32(output, (UINT32)(64 + length));
913 Stream_Write_UINT32(output, 0);
914 Stream_Write_UINT32(output, 0);
915 Stream_Write_UINT32(output, file->find_data.ftCreationTime.dwLowDateTime);
916 Stream_Write_UINT32(output, file->find_data.ftCreationTime.dwHighDateTime);
917 Stream_Write_UINT32(output,
918 file->find_data.ftLastAccessTime.dwLowDateTime);
919 Stream_Write_UINT32(output,
920 file->find_data.ftLastAccessTime.dwHighDateTime);
921 Stream_Write_UINT32(output, file->find_data.ftLastWriteTime.dwLowDateTime);
922 Stream_Write_UINT32(output, file->find_data.ftLastWriteTime.dwHighDateTime);
923 Stream_Write_UINT32(output, file->find_data.ftLastWriteTime.dwLowDateTime);
924 Stream_Write_UINT32(output, file->find_data.ftLastWriteTime.dwHighDateTime);
925 Stream_Write_UINT32(output, file->find_data.nFileSizeLow);
926 Stream_Write_UINT32(output, file->find_data.nFileSizeHigh);
927 Stream_Write_UINT32(output, file->find_data.nFileSizeLow);
928 Stream_Write_UINT32(output, file->find_data.nFileSizeHigh);
929 Stream_Write_UINT32(output, file->find_data.dwFileAttributes);
930 Stream_Write_UINT32(output, (UINT32)length);
931 Stream_Write(output, file->find_data.cFileName, length);
935static BOOL drive_file_query_full_dir_info(
DRIVE_FILE* file,
wStream* output,
size_t length)
938 WINPR_ASSERT(output);
940 if (!Stream_EnsureRemainingCapacity(output, 4 + 68 + length))
943 if (length > UINT32_MAX - 68)
946 Stream_Write_UINT32(output, (UINT32)(68 + length));
947 Stream_Write_UINT32(output, 0);
948 Stream_Write_UINT32(output, 0);
949 Stream_Write_UINT32(output, file->find_data.ftCreationTime.dwLowDateTime);
950 Stream_Write_UINT32(output, file->find_data.ftCreationTime.dwHighDateTime);
951 Stream_Write_UINT32(output,
952 file->find_data.ftLastAccessTime.dwLowDateTime);
953 Stream_Write_UINT32(output,
954 file->find_data.ftLastAccessTime.dwHighDateTime);
955 Stream_Write_UINT32(output, file->find_data.ftLastWriteTime.dwLowDateTime);
956 Stream_Write_UINT32(output, file->find_data.ftLastWriteTime.dwHighDateTime);
957 Stream_Write_UINT32(output, file->find_data.ftLastWriteTime.dwLowDateTime);
958 Stream_Write_UINT32(output, file->find_data.ftLastWriteTime.dwHighDateTime);
959 Stream_Write_UINT32(output, file->find_data.nFileSizeLow);
960 Stream_Write_UINT32(output, file->find_data.nFileSizeHigh);
961 Stream_Write_UINT32(output, file->find_data.nFileSizeLow);
962 Stream_Write_UINT32(output, file->find_data.nFileSizeHigh);
963 Stream_Write_UINT32(output, file->find_data.dwFileAttributes);
964 Stream_Write_UINT32(output, (UINT32)length);
965 Stream_Write_UINT32(output, 0);
966 Stream_Write(output, file->find_data.cFileName, length);
970static BOOL drive_file_query_both_dir_info(
DRIVE_FILE* file,
wStream* output,
size_t length)
973 WINPR_ASSERT(output);
975 if (!Stream_EnsureRemainingCapacity(output, 4 + 93 + length))
978 if (length > UINT32_MAX - 93)
981 Stream_Write_UINT32(output, (UINT32)(93 + length));
982 Stream_Write_UINT32(output, 0);
983 Stream_Write_UINT32(output, 0);
984 Stream_Write_UINT32(output, file->find_data.ftCreationTime.dwLowDateTime);
985 Stream_Write_UINT32(output, file->find_data.ftCreationTime.dwHighDateTime);
986 Stream_Write_UINT32(output,
987 file->find_data.ftLastAccessTime.dwLowDateTime);
988 Stream_Write_UINT32(output,
989 file->find_data.ftLastAccessTime.dwHighDateTime);
990 Stream_Write_UINT32(output, file->find_data.ftLastWriteTime.dwLowDateTime);
991 Stream_Write_UINT32(output, file->find_data.ftLastWriteTime.dwHighDateTime);
992 Stream_Write_UINT32(output, file->find_data.ftLastWriteTime.dwLowDateTime);
993 Stream_Write_UINT32(output, file->find_data.ftLastWriteTime.dwHighDateTime);
994 Stream_Write_UINT32(output, file->find_data.nFileSizeLow);
995 Stream_Write_UINT32(output, file->find_data.nFileSizeHigh);
996 Stream_Write_UINT32(output, file->find_data.nFileSizeLow);
997 Stream_Write_UINT32(output, file->find_data.nFileSizeHigh);
998 Stream_Write_UINT32(output, file->find_data.dwFileAttributes);
999 Stream_Write_UINT32(output, (UINT32)length);
1000 Stream_Write_UINT32(output, 0);
1001 Stream_Write_UINT8(output, 0);
1003 Stream_Zero(output, 24);
1004 Stream_Write(output, file->find_data.cFileName, length);
1008static BOOL drive_file_query_names_info(
DRIVE_FILE* file,
wStream* output,
size_t length)
1011 WINPR_ASSERT(output);
1013 if (!Stream_EnsureRemainingCapacity(output, 4 + 12 + length))
1016 if (length > UINT32_MAX - 12)
1019 Stream_Write_UINT32(output, (UINT32)(12 + length));
1020 Stream_Write_UINT32(output, 0);
1021 Stream_Write_UINT32(output, 0);
1022 Stream_Write_UINT32(output, (UINT32)length);
1023 Stream_Write(output, file->find_data.cFileName, length);
1027BOOL drive_file_query_directory(
DRIVE_FILE* file, UINT32 FsInformationClass, BYTE InitialQuery,
1028 const WCHAR* path, UINT32 PathWCharLength,
wStream* output)
1032 WCHAR* ent_path =
nullptr;
1034 if (!file || !path || !output)
1037 if (InitialQuery != 0)
1040 if (file->find_handle != INVALID_HANDLE_VALUE)
1041 FindClose(file->find_handle);
1043 ent_path = drive_file_combine_fullpath(file->basepath, path, PathWCharLength);
1045 file->find_handle = FindFirstFileW(ent_path, &file->find_data);
1048 if (file->find_handle == INVALID_HANDLE_VALUE)
1051 else if (!FindNextFileW(file->find_handle, &file->find_data))
1054 length = _wcslen(file->find_data.cFileName) *
sizeof(WCHAR);
1056 switch (FsInformationClass)
1058 case FileDirectoryInformation:
1059 rc = drive_file_query_dir_info(file, output, length);
1062 case FileFullDirectoryInformation:
1063 rc = drive_file_query_full_dir_info(file, output, length);
1066 case FileBothDirectoryInformation:
1067 rc = drive_file_query_both_dir_info(file, output, length);
1070 case FileNamesInformation:
1071 rc = drive_file_query_names_info(file, output, length);
1075 WLog_WARN(TAG,
"Unhandled FSInformationClass %s [0x%08" PRIx32
"]",
1076 FSInformationClass2Tag(FsInformationClass), FsInformationClass);
1084 Stream_Write_UINT32(output, 0);
1085 Stream_Write_UINT8(output, 0);