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] ==
'\\') || (tst[2] ==
'\0'))
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 size_t base_path_length = _wcsnlen(base_path, MAX_PATH);
136 if (base_path_length < 1)
139 const size_t length = base_path_length + PathWCharLength + 2;
140 fullpath = (WCHAR*)calloc(length,
sizeof(WCHAR));
145 CopyMemory(fullpath, base_path, base_path_length *
sizeof(WCHAR));
147 const WCHAR last = base_path[base_path_length - 1];
148 const WCHAR sepu = PathGetSeparatorW(PATH_STYLE_UNIX);
149 const WCHAR sepw = PathGetSeparatorW(PATH_STYLE_WINDOWS);
150 if ((last != sepu) && (last != sepw))
152 if (path && (PathWCharLength > 0) && (path[0] != sepu) && (path[0] != sepw))
153 fullpath[base_path_length++] = sepu;
157 CopyMemory(&fullpath[base_path_length], path, PathWCharLength *
sizeof(WCHAR));
159 if (!drive_file_fix_path(fullpath, length))
163 if (contains_dotdot(&fullpath[base_path_length], base_path_length, PathWCharLength))
165 char* abuffer = ConvertWCharToUtf8Alloc(&fullpath[base_path_length],
nullptr);
166 WLog_WARN(TAG,
"[rdpdr] received invalid file path '%s' from server, aborting!",
183static BOOL drive_file_set_fullpath(
DRIVE_FILE* file,
const WCHAR* fullpath)
185 if (!file || !fullpath)
188 const size_t len = _wcslen(fullpath);
189 free(file->fullpath);
190 file->fullpath =
nullptr;
195 file->fullpath = _wcsdup(fullpath);
199 const WCHAR sep[] = { PathGetSeparatorW(PATH_STYLE_NATIVE),
'\0' };
200 WCHAR* filename = _wcsrchr(file->fullpath, *sep);
201 if (filename && _wcsncmp(filename, sep, ARRAYSIZE(sep)) == 0)
209 UINT CreateDisposition = 0;
210 DWORD dwAttr = GetFileAttributesW(file->fullpath);
212 if (dwAttr != INVALID_FILE_ATTRIBUTES)
215 file->is_dir = (dwAttr & FILE_ATTRIBUTE_DIRECTORY) != 0;
219 if (file->CreateDisposition == FILE_CREATE)
221 SetLastError(ERROR_ALREADY_EXISTS);
225 if (file->CreateOptions & FILE_NON_DIRECTORY_FILE)
227 SetLastError(ERROR_ACCESS_DENIED);
235 if (file->CreateOptions & FILE_DIRECTORY_FILE)
237 SetLastError(ERROR_DIRECTORY);
244 file->is_dir = ((file->CreateOptions & FILE_DIRECTORY_FILE) != 0);
249 if ((file->CreateDisposition == FILE_OPEN_IF) ||
250 (file->CreateDisposition == FILE_CREATE))
252 if (CreateDirectoryW(file->fullpath,
nullptr) != 0)
258 SetLastError(ERROR_FILE_NOT_FOUND);
263 if (file->file_handle == INVALID_HANDLE_VALUE)
265 switch (file->CreateDisposition)
269 CreateDisposition = CREATE_ALWAYS;
274 CreateDisposition = OPEN_EXISTING;
279 CreateDisposition = CREATE_NEW;
284 CreateDisposition = OPEN_ALWAYS;
289 CreateDisposition = TRUNCATE_EXISTING;
292 case FILE_OVERWRITE_IF:
294 CreateDisposition = CREATE_ALWAYS;
302 file->SharedAccess = 0;
304 file->file_handle = CreateFileW(file->fullpath, file->DesiredAccess, file->SharedAccess,
305 nullptr, CreateDisposition, file->FileAttributes,
nullptr);
309 if (file->file_handle == INVALID_HANDLE_VALUE)
312 DWORD errorMessageID = GetLastError();
314 if (errorMessageID != 0)
316 LPSTR messageBuffer =
nullptr;
318 FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
319 FORMAT_MESSAGE_IGNORE_INSERTS,
320 nullptr, errorMessageID, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
321 (LPSTR)&messageBuffer, 0,
nullptr);
322 char fullpath[MAX_PATH] = WINPR_C_ARRAY_INIT;
323 (void)ConvertWCharToUtf8(file->fullpath, fullpath,
sizeof(fullpath));
324 WLog_ERR(TAG,
"Error in drive_file_init: %s %s", messageBuffer, fullpath);
326 LocalFree(messageBuffer);
328 SetLastError(errorMessageID);
333 return file->file_handle != INVALID_HANDLE_VALUE;
336DRIVE_FILE* drive_file_new(
const WCHAR* base_path,
const WCHAR* path, UINT32 PathWCharLength,
337 UINT32
id, UINT32 DesiredAccess, UINT32 CreateDisposition,
338 UINT32 CreateOptions, UINT32 FileAttributes, UINT32 SharedAccess)
340 if (!base_path || (!path && (PathWCharLength > 0)))
347 WLog_ERR(TAG,
"calloc failed!");
351 file->file_handle = INVALID_HANDLE_VALUE;
352 file->find_handle = INVALID_HANDLE_VALUE;
354 file->basepath = base_path;
355 file->FileAttributes = FileAttributes;
356 file->DesiredAccess = DesiredAccess;
357 file->CreateDisposition = CreateDisposition;
358 file->CreateOptions = CreateOptions;
359 file->SharedAccess = SharedAccess;
361 WCHAR* p = drive_file_combine_fullpath(base_path, path, PathWCharLength);
362 (void)drive_file_set_fullpath(file, p);
365 if (!drive_file_init(file))
367 DWORD lastError = GetLastError();
368 drive_file_free(file);
369 SetLastError(lastError);
383 if (file->file_handle != INVALID_HANDLE_VALUE)
385 (void)CloseHandle(file->file_handle);
386 file->file_handle = INVALID_HANDLE_VALUE;
389 if (file->find_handle != INVALID_HANDLE_VALUE)
391 FindClose(file->find_handle);
392 file->find_handle = INVALID_HANDLE_VALUE;
395 if (file->CreateOptions & FILE_DELETE_ON_CLOSE)
396 file->delete_pending = TRUE;
398 if (file->delete_pending)
402 if (!winpr_RemoveDirectory_RecursiveW(file->fullpath))
405 else if (!DeleteFileW(file->fullpath))
411 DEBUG_WSTR(
"Free %s", file->fullpath);
412 free(file->fullpath);
417BOOL drive_file_seek(
DRIVE_FILE* file, UINT64 Offset)
424 if (Offset > INT64_MAX)
427 loffset.QuadPart = (LONGLONG)Offset;
428 return SetFilePointerEx(file->file_handle, loffset,
nullptr, FILE_BEGIN);
431BOOL drive_file_read(
DRIVE_FILE* file, BYTE* buffer, UINT32* Length)
435 if (!file || !buffer || !Length)
438 DEBUG_WSTR(
"Read file %s", file->fullpath);
440 if (ReadFile(file->file_handle, buffer, *Length, &read,
nullptr))
449BOOL drive_file_write(
DRIVE_FILE* file,
const BYTE* buffer, UINT32 Length)
453 if (!file || !buffer)
456 DEBUG_WSTR(
"Write file %s", file->fullpath);
460 if (!WriteFile(file->file_handle, buffer, Length, &written,
nullptr))
470static BOOL drive_file_query_from_handle_information(
const DRIVE_FILE* file,
472 UINT32 FsInformationClass,
wStream* output)
474 switch (FsInformationClass)
476 case FileBasicInformation:
479 if (!Stream_EnsureRemainingCapacity(output, 4 + 36))
482 Stream_Write_UINT32(output, 36);
483 Stream_Write_UINT32(output, info->ftCreationTime.dwLowDateTime);
484 Stream_Write_UINT32(output, info->ftCreationTime.dwHighDateTime);
485 Stream_Write_UINT32(output, info->ftLastAccessTime.dwLowDateTime);
486 Stream_Write_UINT32(output, info->ftLastAccessTime.dwHighDateTime);
487 Stream_Write_UINT32(output, info->ftLastWriteTime.dwLowDateTime);
488 Stream_Write_UINT32(output, info->ftLastWriteTime.dwHighDateTime);
489 Stream_Write_UINT32(output, info->ftLastWriteTime.dwLowDateTime);
490 Stream_Write_UINT32(output, info->ftLastWriteTime.dwHighDateTime);
491 Stream_Write_UINT32(output, info->dwFileAttributes);
495 case FileStandardInformation:
498 if (!Stream_EnsureRemainingCapacity(output, 4 + 22))
501 Stream_Write_UINT32(output, 22);
502 Stream_Write_UINT32(output, info->nFileSizeLow);
503 Stream_Write_UINT32(output, info->nFileSizeHigh);
504 Stream_Write_UINT32(output, info->nFileSizeLow);
505 Stream_Write_UINT32(output, info->nFileSizeHigh);
506 Stream_Write_UINT32(output, info->nNumberOfLinks);
507 Stream_Write_UINT8(output, file->delete_pending ? 1 : 0);
508 Stream_Write_UINT8(output, (info->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) !=
513 case FileAttributeTagInformation:
516 if (!Stream_EnsureRemainingCapacity(output, 4 + 8))
519 Stream_Write_UINT32(output, 8);
520 Stream_Write_UINT32(output, info->dwFileAttributes);
521 Stream_Write_UINT32(output, 0);
526 WLog_WARN(TAG,
"Unhandled FSInformationClass %s [0x%08" PRIx32
"]",
527 FSInformationClass2Tag(FsInformationClass), FsInformationClass);
534static BOOL drive_file_query_from_attributes(
const DRIVE_FILE* file,
536 UINT32 FsInformationClass,
wStream* output)
538 switch (FsInformationClass)
540 case FileBasicInformation:
543 if (!Stream_EnsureRemainingCapacity(output, 4 + 36))
546 Stream_Write_UINT32(output, 36);
547 Stream_Write_UINT32(output, attrib->ftCreationTime.dwLowDateTime);
548 Stream_Write_UINT32(output, attrib->ftCreationTime.dwHighDateTime);
549 Stream_Write_UINT32(output,
550 attrib->ftLastAccessTime.dwLowDateTime);
551 Stream_Write_UINT32(output,
552 attrib->ftLastAccessTime.dwHighDateTime);
553 Stream_Write_UINT32(output, attrib->ftLastWriteTime.dwLowDateTime);
554 Stream_Write_UINT32(output, attrib->ftLastWriteTime.dwHighDateTime);
555 Stream_Write_UINT32(output, attrib->ftLastWriteTime.dwLowDateTime);
556 Stream_Write_UINT32(output, attrib->ftLastWriteTime.dwHighDateTime);
557 Stream_Write_UINT32(output, attrib->dwFileAttributes);
561 case FileStandardInformation:
564 if (!Stream_EnsureRemainingCapacity(output, 4 + 22))
567 Stream_Write_UINT32(output, 22);
568 Stream_Write_UINT32(output, attrib->nFileSizeLow);
569 Stream_Write_UINT32(output, attrib->nFileSizeHigh);
570 Stream_Write_UINT32(output, attrib->nFileSizeLow);
571 Stream_Write_UINT32(output, attrib->nFileSizeHigh);
572 Stream_Write_UINT32(output, 0);
573 Stream_Write_UINT8(output, file->delete_pending ? 1 : 0);
574 Stream_Write_UINT8(output, (attrib->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) !=
579 case FileAttributeTagInformation:
582 if (!Stream_EnsureRemainingCapacity(output, 4 + 8))
585 Stream_Write_UINT32(output, 8);
586 Stream_Write_UINT32(output, attrib->dwFileAttributes);
587 Stream_Write_UINT32(output, 0);
592 WLog_WARN(TAG,
"Unhandled FSInformationClass %s [0x%08" PRIx32
"]",
593 FSInformationClass2Tag(FsInformationClass), FsInformationClass);
600BOOL drive_file_query_information(
DRIVE_FILE* file, UINT32 FsInformationClass,
wStream* output)
605 if (!file || !output)
608 if ((file->file_handle != INVALID_HANDLE_VALUE) &&
609 GetFileInformationByHandle(file->file_handle, &fileInformation))
610 return drive_file_query_from_handle_information(file, &fileInformation, FsInformationClass,
615 HANDLE hFile = CreateFileW(file->fullpath, 0, FILE_SHARE_DELETE,
nullptr, OPEN_EXISTING,
616 FILE_ATTRIBUTE_NORMAL,
nullptr);
617 if (hFile != INVALID_HANDLE_VALUE)
619 status = GetFileInformationByHandle(hFile, &fileInformation);
620 (void)CloseHandle(hFile);
624 if (!drive_file_query_from_handle_information(file, &fileInformation,
625 FsInformationClass, output))
636 if (!GetFileAttributesExW(file->fullpath, GetFileExInfoStandard, &fileAttributes))
639 if (!drive_file_query_from_attributes(file, &fileAttributes, FsInformationClass, output))
645 Stream_Write_UINT32(output, 0);
649static BOOL drive_file_set_basic_information(
DRIVE_FILE* file, UINT32 Length,
wStream* input)
653 const uint32_t expect = 36;
654 if (Length != expect)
656 WLog_WARN(TAG,
"Unexpected Length=%" PRIu32
", expected %" PRIu32, Length, expect);
661 const ULARGE_INTEGER liCreationTime = { .QuadPart = Stream_Get_UINT64(input) };
662 const ULARGE_INTEGER liLastAccessTime = { .QuadPart = Stream_Get_UINT64(input) };
663 const ULARGE_INTEGER liLastWriteTime = { .QuadPart = Stream_Get_UINT64(input) };
664 const ULARGE_INTEGER liChangeTime = { .QuadPart = Stream_Get_UINT64(input) };
665 const uint32_t FileAttributes = Stream_Get_UINT32(input);
667 if (!PathFileExistsW(file->fullpath))
670 if (file->file_handle == INVALID_HANDLE_VALUE)
672 char fullpath[MAX_PATH] = WINPR_C_ARRAY_INIT;
673 (void)ConvertWCharToUtf8(file->fullpath, fullpath,
sizeof(fullpath) - 1);
675 WLog_ERR(TAG,
"Unable to set file time %s (%" PRIu32
")", fullpath, GetLastError());
679 FILETIME ftCreationTime = WINPR_C_ARRAY_INIT;
680 FILETIME ftLastAccessTime = WINPR_C_ARRAY_INIT;
681 FILETIME ftLastWriteTime = WINPR_C_ARRAY_INIT;
682 FILETIME* pftCreationTime =
nullptr;
683 FILETIME* pftLastAccessTime =
nullptr;
684 FILETIME* pftLastWriteTime =
nullptr;
685 if (liCreationTime.QuadPart != 0)
687 ftCreationTime.dwHighDateTime = liCreationTime.u.HighPart;
688 ftCreationTime.dwLowDateTime = liCreationTime.u.LowPart;
689 pftCreationTime = &ftCreationTime;
692 if (liLastAccessTime.QuadPart != 0)
694 ftLastAccessTime.dwHighDateTime = liLastAccessTime.u.HighPart;
695 ftLastAccessTime.dwLowDateTime = liLastAccessTime.u.LowPart;
696 pftLastAccessTime = &ftLastAccessTime;
699 if (liLastWriteTime.QuadPart != 0)
701 ftLastWriteTime.dwHighDateTime = liLastWriteTime.u.HighPart;
702 ftLastWriteTime.dwLowDateTime = liLastWriteTime.u.LowPart;
703 pftLastWriteTime = &ftLastWriteTime;
706 if (liChangeTime.QuadPart != 0 && liChangeTime.QuadPart > liLastWriteTime.QuadPart)
708 ftLastWriteTime.dwHighDateTime = liChangeTime.u.HighPart;
709 ftLastWriteTime.dwLowDateTime = liChangeTime.u.LowPart;
710 pftLastWriteTime = &ftLastWriteTime;
713 DEBUG_WSTR(
"SetFileTime %s", file->fullpath);
715 if (!SetFileAttributesW(file->fullpath, FileAttributes))
717 char fullpath[MAX_PATH] = WINPR_C_ARRAY_INIT;
718 (void)ConvertWCharToUtf8(file->fullpath, fullpath,
sizeof(fullpath));
719 WLog_ERR(TAG,
"Unable to set file attributes for %s", fullpath);
723 if (!SetFileTime(file->file_handle, pftCreationTime, pftLastAccessTime, pftLastWriteTime))
725 char fullpath[MAX_PATH] = WINPR_C_ARRAY_INIT;
726 (void)ConvertWCharToUtf8(file->fullpath, fullpath,
sizeof(fullpath));
727 WLog_ERR(TAG,
"Unable to set file time for %s", fullpath);
733static BOOL drive_file_set_alloc_information(
DRIVE_FILE* file, UINT32 Length,
wStream* input)
736 const uint32_t expect = 8;
737 if (Length != expect)
739 WLog_WARN(TAG,
"Unexpected Length=%" PRIu32
", expected %" PRIu32, Length, expect);
744 const int64_t size = Stream_Get_INT64(input);
746 if (file->file_handle == INVALID_HANDLE_VALUE)
748 char fullpath[MAX_PATH] = WINPR_C_ARRAY_INIT;
749 (void)ConvertWCharToUtf8(file->fullpath, fullpath,
sizeof(fullpath));
750 WLog_ERR(TAG,
"Unable to truncate %s to %" PRId64
" (%" PRIu32
")", fullpath, size,
757 if (!SetFilePointerEx(file->file_handle, liSize,
nullptr, FILE_BEGIN))
759 char fullpath[MAX_PATH] = WINPR_C_ARRAY_INIT;
760 (void)ConvertWCharToUtf8(file->fullpath, fullpath,
sizeof(fullpath));
761 WLog_ERR(TAG,
"Unable to truncate %s to %" PRId64
" (%" PRIu32
")", fullpath, size,
766 DEBUG_WSTR(
"Truncate %s", file->fullpath);
768 if (SetEndOfFile(file->file_handle) == 0)
770 char fullpath[MAX_PATH] = WINPR_C_ARRAY_INIT;
771 (void)ConvertWCharToUtf8(file->fullpath, fullpath,
sizeof(fullpath));
772 WLog_ERR(TAG,
"Unable to truncate %s to %" PRId64
" (%" PRIu32
")", fullpath, size,
780static BOOL drive_file_set_disposition_information(
DRIVE_FILE* file, UINT32 Length,
wStream* input)
783 uint8_t delete_pending = 0;
786 if (file->is_dir && !PathIsDirectoryEmptyW(file->fullpath))
788 SetLastError(ERROR_DIR_NOT_EMPTY);
794 const uint32_t expect = 1;
795 if (Length != expect)
796 WLog_DBG(TAG,
"Unexpected Length=%" PRIu32
", expected %" PRIu32, Length, expect);
798 delete_pending = Stream_Get_UINT8(input);
805 DEBUG_WSTR(
"SetDeletePending %s", file->fullpath);
806 const uint32_t attr = GetFileAttributesW(file->fullpath);
808 if (attr & FILE_ATTRIBUTE_READONLY)
810 SetLastError(ERROR_ACCESS_DENIED);
815 file->delete_pending = delete_pending;
819static BOOL drive_file_set_rename_information(
DRIVE_FILE* file, UINT32 Length,
wStream* input)
823 const uint32_t expect = 6;
826 WLog_WARN(TAG,
"Unexpected Length=%" PRIu32
", expected at least %" PRIu32, Length, expect);
831 const uint8_t ReplaceIfExists = Stream_Get_UINT8(input);
832 Stream_Seek_UINT8(input);
833 const uint64_t FileNameLength = Stream_Get_UINT32(input);
835 if (Length != expect + FileNameLength)
837 WLog_WARN(TAG,
"Unexpected Length=%" PRIu32
", expected %" PRIu64, Length,
838 expect + FileNameLength);
842 WCHAR* fullpath = drive_file_combine_fullpath(file->basepath, Stream_ConstPointer(input),
843 FileNameLength /
sizeof(WCHAR));
850 if (file->file_handle != INVALID_HANDLE_VALUE)
852 (void)CloseHandle(file->file_handle);
853 file->file_handle = INVALID_HANDLE_VALUE;
857 DEBUG_WSTR(
"MoveFileExW %s", file->fullpath);
859 if (MoveFileExW(file->fullpath, fullpath,
860 MOVEFILE_COPY_ALLOWED | (ReplaceIfExists ? MOVEFILE_REPLACE_EXISTING : 0)))
862 const BOOL rc = drive_file_set_fullpath(file, fullpath);
874 drive_file_init(file);
879BOOL drive_file_set_information(
DRIVE_FILE* file, UINT32 FsInformationClass, UINT32 Length,
885 if (!Stream_CheckAndLogRequiredLength(TAG, input, Length))
888 switch (FsInformationClass)
890 case FileBasicInformation:
891 return drive_file_set_basic_information(file, Length, input);
893 case FileEndOfFileInformation:
895 case FileAllocationInformation:
896 return drive_file_set_alloc_information(file, Length, input);
898 case FileDispositionInformation:
899 return drive_file_set_disposition_information(file, Length, input);
901 case FileRenameInformation:
902 return drive_file_set_rename_information(file, Length, input);
905 WLog_WARN(TAG,
"Unhandled FSInformationClass %s [0x%08" PRIx32
"]",
906 FSInformationClass2Tag(FsInformationClass), FsInformationClass);
913static BOOL drive_file_query_dir_info(
DRIVE_FILE* file,
wStream* output,
size_t length)
916 WINPR_ASSERT(output);
919 if (!Stream_EnsureRemainingCapacity(output, 4 + 64 + length))
922 if (length > UINT32_MAX - 64)
925 Stream_Write_UINT32(output, (UINT32)(64 + length));
926 Stream_Write_UINT32(output, 0);
927 Stream_Write_UINT32(output, 0);
928 Stream_Write_UINT32(output, file->find_data.ftCreationTime.dwLowDateTime);
929 Stream_Write_UINT32(output, file->find_data.ftCreationTime.dwHighDateTime);
930 Stream_Write_UINT32(output,
931 file->find_data.ftLastAccessTime.dwLowDateTime);
932 Stream_Write_UINT32(output,
933 file->find_data.ftLastAccessTime.dwHighDateTime);
934 Stream_Write_UINT32(output, file->find_data.ftLastWriteTime.dwLowDateTime);
935 Stream_Write_UINT32(output, file->find_data.ftLastWriteTime.dwHighDateTime);
936 Stream_Write_UINT32(output, file->find_data.ftLastWriteTime.dwLowDateTime);
937 Stream_Write_UINT32(output, file->find_data.ftLastWriteTime.dwHighDateTime);
938 Stream_Write_UINT32(output, file->find_data.nFileSizeLow);
939 Stream_Write_UINT32(output, file->find_data.nFileSizeHigh);
940 Stream_Write_UINT32(output, file->find_data.nFileSizeLow);
941 Stream_Write_UINT32(output, file->find_data.nFileSizeHigh);
942 Stream_Write_UINT32(output, file->find_data.dwFileAttributes);
943 Stream_Write_UINT32(output, (UINT32)length);
944 Stream_Write(output, file->find_data.cFileName, length);
948static BOOL drive_file_query_full_dir_info(
DRIVE_FILE* file,
wStream* output,
size_t length)
951 WINPR_ASSERT(output);
953 if (!Stream_EnsureRemainingCapacity(output, 4 + 68 + length))
956 if (length > UINT32_MAX - 68)
959 Stream_Write_UINT32(output, (UINT32)(68 + length));
960 Stream_Write_UINT32(output, 0);
961 Stream_Write_UINT32(output, 0);
962 Stream_Write_UINT32(output, file->find_data.ftCreationTime.dwLowDateTime);
963 Stream_Write_UINT32(output, file->find_data.ftCreationTime.dwHighDateTime);
964 Stream_Write_UINT32(output,
965 file->find_data.ftLastAccessTime.dwLowDateTime);
966 Stream_Write_UINT32(output,
967 file->find_data.ftLastAccessTime.dwHighDateTime);
968 Stream_Write_UINT32(output, file->find_data.ftLastWriteTime.dwLowDateTime);
969 Stream_Write_UINT32(output, file->find_data.ftLastWriteTime.dwHighDateTime);
970 Stream_Write_UINT32(output, file->find_data.ftLastWriteTime.dwLowDateTime);
971 Stream_Write_UINT32(output, file->find_data.ftLastWriteTime.dwHighDateTime);
972 Stream_Write_UINT32(output, file->find_data.nFileSizeLow);
973 Stream_Write_UINT32(output, file->find_data.nFileSizeHigh);
974 Stream_Write_UINT32(output, file->find_data.nFileSizeLow);
975 Stream_Write_UINT32(output, file->find_data.nFileSizeHigh);
976 Stream_Write_UINT32(output, file->find_data.dwFileAttributes);
977 Stream_Write_UINT32(output, (UINT32)length);
978 Stream_Write_UINT32(output, 0);
979 Stream_Write(output, file->find_data.cFileName, length);
983static BOOL drive_file_query_both_dir_info(
DRIVE_FILE* file,
wStream* output,
size_t length)
986 WINPR_ASSERT(output);
988 if (!Stream_EnsureRemainingCapacity(output, 4 + 93 + length))
991 if (length > UINT32_MAX - 93)
994 Stream_Write_UINT32(output, (UINT32)(93 + length));
995 Stream_Write_UINT32(output, 0);
996 Stream_Write_UINT32(output, 0);
997 Stream_Write_UINT32(output, file->find_data.ftCreationTime.dwLowDateTime);
998 Stream_Write_UINT32(output, file->find_data.ftCreationTime.dwHighDateTime);
999 Stream_Write_UINT32(output,
1000 file->find_data.ftLastAccessTime.dwLowDateTime);
1001 Stream_Write_UINT32(output,
1002 file->find_data.ftLastAccessTime.dwHighDateTime);
1003 Stream_Write_UINT32(output, file->find_data.ftLastWriteTime.dwLowDateTime);
1004 Stream_Write_UINT32(output, file->find_data.ftLastWriteTime.dwHighDateTime);
1005 Stream_Write_UINT32(output, file->find_data.ftLastWriteTime.dwLowDateTime);
1006 Stream_Write_UINT32(output, file->find_data.ftLastWriteTime.dwHighDateTime);
1007 Stream_Write_UINT32(output, file->find_data.nFileSizeLow);
1008 Stream_Write_UINT32(output, file->find_data.nFileSizeHigh);
1009 Stream_Write_UINT32(output, file->find_data.nFileSizeLow);
1010 Stream_Write_UINT32(output, file->find_data.nFileSizeHigh);
1011 Stream_Write_UINT32(output, file->find_data.dwFileAttributes);
1012 Stream_Write_UINT32(output, (UINT32)length);
1013 Stream_Write_UINT32(output, 0);
1014 Stream_Write_UINT8(output, 0);
1016 Stream_Zero(output, 24);
1017 Stream_Write(output, file->find_data.cFileName, length);
1021static BOOL drive_file_query_names_info(
DRIVE_FILE* file,
wStream* output,
size_t length)
1024 WINPR_ASSERT(output);
1026 if (!Stream_EnsureRemainingCapacity(output, 4 + 12 + length))
1029 if (length > UINT32_MAX - 12)
1032 Stream_Write_UINT32(output, (UINT32)(12 + length));
1033 Stream_Write_UINT32(output, 0);
1034 Stream_Write_UINT32(output, 0);
1035 Stream_Write_UINT32(output, (UINT32)length);
1036 Stream_Write(output, file->find_data.cFileName, length);
1040BOOL drive_file_query_directory(
DRIVE_FILE* file, UINT32 FsInformationClass, BYTE InitialQuery,
1041 const WCHAR* path, UINT32 PathWCharLength,
wStream* output)
1045 WCHAR* ent_path =
nullptr;
1047 if (!file || !path || !output)
1050 if (InitialQuery != 0)
1053 if (file->find_handle != INVALID_HANDLE_VALUE)
1054 FindClose(file->find_handle);
1056 ent_path = drive_file_combine_fullpath(file->basepath, path, PathWCharLength);
1058 file->find_handle = FindFirstFileW(ent_path, &file->find_data);
1061 if (file->find_handle == INVALID_HANDLE_VALUE)
1064 else if (!FindNextFileW(file->find_handle, &file->find_data))
1067 length = _wcslen(file->find_data.cFileName) *
sizeof(WCHAR);
1069 switch (FsInformationClass)
1071 case FileDirectoryInformation:
1072 rc = drive_file_query_dir_info(file, output, length);
1075 case FileFullDirectoryInformation:
1076 rc = drive_file_query_full_dir_info(file, output, length);
1079 case FileBothDirectoryInformation:
1080 rc = drive_file_query_both_dir_info(file, output, length);
1083 case FileNamesInformation:
1084 rc = drive_file_query_names_info(file, output, length);
1088 WLog_WARN(TAG,
"Unhandled FSInformationClass %s [0x%08" PRIx32
"]",
1089 FSInformationClass2Tag(FsInformationClass), FsInformationClass);
1097 Stream_Write_UINT32(output, 0);
1098 Stream_Write_UINT8(output, 0);