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) \
63static BOOL drive_file_fix_path(WCHAR* path,
size_t length)
65 if ((length == 0) || (length > UINT32_MAX))
70 for (
size_t i = 0; i < length; i++)
78 if ((length == 3) && (path[1] == L
':') && (path[2] == L
'/'))
83 if ((length == 1) && (path[0] == L
'/'))
88 if ((length > 0) && (path[length - 1] == L
'/'))
89 path[length - 1] = L
'\0';
95static BOOL contains_dotdot(
const WCHAR* path,
size_t base_length,
size_t path_length)
97 WCHAR dotdotbuffer[6] = WINPR_C_ARRAY_INIT;
98 const WCHAR* dotdot = InitializeConstWCharFromUtf8(
"..", dotdotbuffer, ARRAYSIZE(dotdotbuffer));
99 const WCHAR* tst = path;
106 tst = _wcsstr(tst, dotdot);
111 if ((base_length == 0) || (*(tst - 1) == L
'/') || (*(tst - 1) == L
'\\'))
113 if (tst + 2 < path + path_length)
115 if ((tst[2] ==
'/') || (tst[2] ==
'\\') || (tst[2] ==
'\0'))
127WINPR_ATTR_MALLOC(free, 1)
128static WCHAR* drive_file_combine_fullpath(const WCHAR* base_path, const WCHAR* path,
129 size_t PathWCharLength)
132 WCHAR* fullpath =
nullptr;
134 if (!base_path || (!path && (PathWCharLength > 0)))
138 size_t base_path_length = _wcsnlen(base_path, MAX_PATH);
139 if (base_path_length < 1)
142 const size_t length = base_path_length + PathWCharLength + 2;
143 fullpath = (WCHAR*)calloc(length,
sizeof(WCHAR));
148 CopyMemory(fullpath, base_path, base_path_length *
sizeof(WCHAR));
150 const WCHAR last = base_path[base_path_length - 1];
151 const WCHAR sepu = PathGetSeparatorW(PATH_STYLE_UNIX);
152 const WCHAR sepw = PathGetSeparatorW(PATH_STYLE_WINDOWS);
153 if ((last != sepu) && (last != sepw))
155 if (path && (PathWCharLength > 0) && (path[0] != sepu) && (path[0] != sepw))
156 fullpath[base_path_length++] = sepu;
160 CopyMemory(&fullpath[base_path_length], path, PathWCharLength *
sizeof(WCHAR));
162 if (!drive_file_fix_path(fullpath, length))
166 if (contains_dotdot(&fullpath[base_path_length], base_path_length, PathWCharLength))
168 char* abuffer = ConvertWCharToUtf8Alloc(&fullpath[base_path_length],
nullptr);
169 WLog_WARN(TAG,
"[rdpdr] received invalid file path '%s' from server, aborting!",
187static BOOL drive_file_set_fullpath(
DRIVE_FILE* file,
const WCHAR* fullpath)
189 if (!file || !fullpath)
192 const size_t len = _wcslen(fullpath);
193 free(file->fullpath);
194 file->fullpath =
nullptr;
199 file->fullpath = wcsndup(fullpath, len);
203 const WCHAR sep[] = { PathGetSeparatorW(PATH_STYLE_NATIVE),
'\0' };
204 WCHAR* filename = winpr_wcsnrchr(file->fullpath, len, *sep);
205 if (filename && _wcsncmp(filename, sep, ARRAYSIZE(sep)) == 0)
214 UINT CreateDisposition = 0;
215 DWORD dwAttr = GetFileAttributesW(file->fullpath);
217 if (dwAttr != INVALID_FILE_ATTRIBUTES)
220 file->is_dir = (dwAttr & FILE_ATTRIBUTE_DIRECTORY) != 0;
224 if (file->CreateDisposition == FILE_CREATE)
226 SetLastError(ERROR_ALREADY_EXISTS);
230 if (file->CreateOptions & FILE_NON_DIRECTORY_FILE)
232 SetLastError(ERROR_ACCESS_DENIED);
240 if (file->CreateOptions & FILE_DIRECTORY_FILE)
242 SetLastError(ERROR_DIRECTORY);
249 file->is_dir = ((file->CreateOptions & FILE_DIRECTORY_FILE) != 0);
254 if ((file->CreateDisposition == FILE_OPEN_IF) ||
255 (file->CreateDisposition == FILE_CREATE))
257 if (CreateDirectoryW(file->fullpath,
nullptr) != 0)
263 SetLastError(ERROR_FILE_NOT_FOUND);
268 if (file->file_handle == INVALID_HANDLE_VALUE)
270 switch (file->CreateDisposition)
274 CreateDisposition = CREATE_ALWAYS;
279 CreateDisposition = OPEN_EXISTING;
284 CreateDisposition = CREATE_NEW;
289 CreateDisposition = OPEN_ALWAYS;
294 CreateDisposition = TRUNCATE_EXISTING;
297 case FILE_OVERWRITE_IF:
299 CreateDisposition = CREATE_ALWAYS;
307 file->SharedAccess = 0;
309 file->file_handle = CreateFileW(file->fullpath, file->DesiredAccess, file->SharedAccess,
310 nullptr, CreateDisposition, file->FileAttributes,
nullptr);
314 if (file->file_handle == INVALID_HANDLE_VALUE)
317 DWORD errorMessageID = GetLastError();
319 if (errorMessageID != 0)
321 LPSTR messageBuffer =
nullptr;
323 FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
324 FORMAT_MESSAGE_IGNORE_INSERTS,
325 nullptr, errorMessageID, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
326 (LPSTR)&messageBuffer, 0,
nullptr);
327 char fullpath[MAX_PATH] = WINPR_C_ARRAY_INIT;
328 (void)ConvertWCharToUtf8(file->fullpath, fullpath,
sizeof(fullpath));
329 WLog_ERR(TAG,
"Error in drive_file_init: %s %s", messageBuffer, fullpath);
331 LocalFree(messageBuffer);
333 SetLastError(errorMessageID);
338 return file->file_handle != INVALID_HANDLE_VALUE;
341DRIVE_FILE* drive_file_new(
const WCHAR* base_path,
const WCHAR* path, UINT32 PathWCharLength,
342 UINT32
id, UINT32 DesiredAccess, UINT32 CreateDisposition,
343 UINT32 CreateOptions, UINT32 FileAttributes, UINT32 SharedAccess)
345 if (!base_path || (!path && (PathWCharLength > 0)))
352 WLog_ERR(TAG,
"calloc failed!");
356 file->file_handle = INVALID_HANDLE_VALUE;
357 file->find_handle = INVALID_HANDLE_VALUE;
359 file->basepath = base_path;
360 file->FileAttributes = FileAttributes;
361 file->DesiredAccess = DesiredAccess;
362 file->CreateDisposition = CreateDisposition;
363 file->CreateOptions = CreateOptions;
364 file->SharedAccess = SharedAccess;
366 WCHAR* p = drive_file_combine_fullpath(base_path, path, PathWCharLength);
367 const BOOL rc = drive_file_set_fullpath(file, p);
370 if (!rc || !drive_file_init(file))
372 DWORD lastError = GetLastError();
373 drive_file_free(file);
374 SetLastError(lastError);
388 if (file->file_handle != INVALID_HANDLE_VALUE)
390 (void)CloseHandle(file->file_handle);
391 file->file_handle = INVALID_HANDLE_VALUE;
394 if (file->find_handle != INVALID_HANDLE_VALUE)
396 FindClose(file->find_handle);
397 file->find_handle = INVALID_HANDLE_VALUE;
400 if (file->CreateOptions & FILE_DELETE_ON_CLOSE)
401 file->delete_pending = TRUE;
403 if (file->delete_pending)
407 if (!winpr_RemoveDirectory_RecursiveW(file->fullpath))
410 else if (!DeleteFileW(file->fullpath))
416 DEBUG_WSTR(
"Free %s", file->fullpath);
417 free(file->fullpath);
422BOOL drive_file_seek(
DRIVE_FILE* file, UINT64 Offset)
429 if (Offset > INT64_MAX)
432 loffset.QuadPart = (LONGLONG)Offset;
433 return SetFilePointerEx(file->file_handle, loffset,
nullptr, FILE_BEGIN);
440 if (!file || !s || !Length)
442 SetLastError(ERROR_INVALID_PARAMETER);
446 UINT32 size = *Length;
449 if (!drive_file_seek(file, Offset))
452 DEBUG_WSTR(
"Read file %s", file->fullpath);
455 const DWORD sizeLow = GetFileSize(file->file_handle, &sizeHigh);
456 if ((sizeLow == INVALID_FILE_SIZE) && (GetLastError() != ERROR_SUCCESS))
459 const UINT64 size64 = 1ull * sizeLow + ((1ull * sizeHigh) << 32);
460 const UINT64 remain = (Offset < size64) ? (size64 - Offset) : 0;
462 size = WINPR_ASSERTING_INT_CAST(UINT32, remain);
464 if (!Stream_EnsureRemainingCapacity(s, size))
466 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
470 void* buffer = Stream_Pointer(s);
471 if (!ReadFile(file->file_handle, buffer, size, &read,
nullptr))
478BOOL drive_file_write(
DRIVE_FILE* file,
const BYTE* buffer, UINT32 Length)
482 if (!file || !buffer)
485 DEBUG_WSTR(
"Write file %s", file->fullpath);
489 if (!WriteFile(file->file_handle, buffer, Length, &written,
nullptr))
500static BOOL drive_file_query_from_handle_information(
const DRIVE_FILE* file,
502 UINT32 FsInformationClass,
wStream* output)
504 switch (FsInformationClass)
506 case FileBasicInformation:
509 if (!Stream_EnsureRemainingCapacity(output, 4ull + 36ull))
512 Stream_Write_UINT32(output, 36);
513 Stream_Write_UINT32(output, info->ftCreationTime.dwLowDateTime);
514 Stream_Write_UINT32(output, info->ftCreationTime.dwHighDateTime);
515 Stream_Write_UINT32(output, info->ftLastAccessTime.dwLowDateTime);
516 Stream_Write_UINT32(output, info->ftLastAccessTime.dwHighDateTime);
517 Stream_Write_UINT32(output, info->ftLastWriteTime.dwLowDateTime);
518 Stream_Write_UINT32(output, info->ftLastWriteTime.dwHighDateTime);
519 Stream_Write_UINT32(output, info->ftLastWriteTime.dwLowDateTime);
520 Stream_Write_UINT32(output, info->ftLastWriteTime.dwHighDateTime);
521 Stream_Write_UINT32(output, info->dwFileAttributes);
525 case FileStandardInformation:
528 if (!Stream_EnsureRemainingCapacity(output, 4ull + 22ull))
531 Stream_Write_UINT32(output, 22);
532 Stream_Write_UINT32(output, info->nFileSizeLow);
533 Stream_Write_UINT32(output, info->nFileSizeHigh);
534 Stream_Write_UINT32(output, info->nFileSizeLow);
535 Stream_Write_UINT32(output, info->nFileSizeHigh);
536 Stream_Write_UINT32(output, info->nNumberOfLinks);
537 Stream_Write_UINT8(output, file->delete_pending ? 1 : 0);
538 Stream_Write_UINT8(output, (info->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) !=
543 case FileAttributeTagInformation:
546 if (!Stream_EnsureRemainingCapacity(output, 4ull + 8ull))
549 Stream_Write_UINT32(output, 8);
550 Stream_Write_UINT32(output, info->dwFileAttributes);
551 Stream_Write_UINT32(output, 0);
556 WLog_WARN(TAG,
"Unhandled FSInformationClass %s [0x%08" PRIx32
"]",
557 FSInformationClass2Tag(FsInformationClass), FsInformationClass);
565static BOOL drive_file_query_from_attributes(
const DRIVE_FILE* file,
567 UINT32 FsInformationClass,
wStream* output)
569 switch (FsInformationClass)
571 case FileBasicInformation:
574 if (!Stream_EnsureRemainingCapacity(output, 4ull + 36ull))
577 Stream_Write_UINT32(output, 36);
578 Stream_Write_UINT32(output, attrib->ftCreationTime.dwLowDateTime);
579 Stream_Write_UINT32(output, attrib->ftCreationTime.dwHighDateTime);
580 Stream_Write_UINT32(output,
581 attrib->ftLastAccessTime.dwLowDateTime);
582 Stream_Write_UINT32(output,
583 attrib->ftLastAccessTime.dwHighDateTime);
584 Stream_Write_UINT32(output, attrib->ftLastWriteTime.dwLowDateTime);
585 Stream_Write_UINT32(output, attrib->ftLastWriteTime.dwHighDateTime);
586 Stream_Write_UINT32(output, attrib->ftLastWriteTime.dwLowDateTime);
587 Stream_Write_UINT32(output, attrib->ftLastWriteTime.dwHighDateTime);
588 Stream_Write_UINT32(output, attrib->dwFileAttributes);
592 case FileStandardInformation:
595 if (!Stream_EnsureRemainingCapacity(output, 4ull + 22ull))
598 Stream_Write_UINT32(output, 22);
599 Stream_Write_UINT32(output, attrib->nFileSizeLow);
600 Stream_Write_UINT32(output, attrib->nFileSizeHigh);
601 Stream_Write_UINT32(output, attrib->nFileSizeLow);
602 Stream_Write_UINT32(output, attrib->nFileSizeHigh);
603 Stream_Write_UINT32(output, 0);
604 Stream_Write_UINT8(output, file->delete_pending ? 1 : 0);
605 Stream_Write_UINT8(output, (attrib->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) !=
610 case FileAttributeTagInformation:
613 if (!Stream_EnsureRemainingCapacity(output, 4ull + 8ull))
616 Stream_Write_UINT32(output, 8);
617 Stream_Write_UINT32(output, attrib->dwFileAttributes);
618 Stream_Write_UINT32(output, 0);
623 WLog_WARN(TAG,
"Unhandled FSInformationClass %s [0x%08" PRIx32
"]",
624 FSInformationClass2Tag(FsInformationClass), FsInformationClass);
631BOOL drive_file_query_information(
DRIVE_FILE* file, UINT32 FsInformationClass,
wStream* output)
636 if (!file || !output)
639 if ((file->file_handle != INVALID_HANDLE_VALUE) &&
640 GetFileInformationByHandle(file->file_handle, &fileInformation))
641 return drive_file_query_from_handle_information(file, &fileInformation, FsInformationClass,
646 HANDLE hFile = CreateFileW(file->fullpath, 0, FILE_SHARE_DELETE,
nullptr, OPEN_EXISTING,
647 FILE_ATTRIBUTE_NORMAL,
nullptr);
648 if (hFile != INVALID_HANDLE_VALUE)
650 status = GetFileInformationByHandle(hFile, &fileInformation);
651 (void)CloseHandle(hFile);
655 if (!drive_file_query_from_handle_information(file, &fileInformation,
656 FsInformationClass, output))
667 if (!GetFileAttributesExW(file->fullpath, GetFileExInfoStandard, &fileAttributes))
670 if (!drive_file_query_from_attributes(file, &fileAttributes, FsInformationClass, output))
676 Stream_Write_UINT32(output, 0);
681static BOOL drive_file_set_basic_information(
DRIVE_FILE* file, UINT32 Length,
wStream* input)
685 const uint32_t expect = 36;
686 if (Length != expect)
688 WLog_WARN(TAG,
"Unexpected Length=%" PRIu32
", expected %" PRIu32, Length, expect);
693 const ULARGE_INTEGER liCreationTime = { .QuadPart = Stream_Get_UINT64(input) };
694 const ULARGE_INTEGER liLastAccessTime = { .QuadPart = Stream_Get_UINT64(input) };
695 const ULARGE_INTEGER liLastWriteTime = { .QuadPart = Stream_Get_UINT64(input) };
696 const ULARGE_INTEGER liChangeTime = { .QuadPart = Stream_Get_UINT64(input) };
697 const uint32_t FileAttributes = Stream_Get_UINT32(input);
699 if (!PathFileExistsW(file->fullpath))
702 if (file->file_handle == INVALID_HANDLE_VALUE)
704 char fullpath[MAX_PATH] = WINPR_C_ARRAY_INIT;
705 (void)ConvertWCharToUtf8(file->fullpath, fullpath,
sizeof(fullpath) - 1);
707 WLog_ERR(TAG,
"Unable to set file time %s (%" PRIu32
")", fullpath, GetLastError());
711 FILETIME ftCreationTime = WINPR_C_ARRAY_INIT;
712 FILETIME ftLastAccessTime = WINPR_C_ARRAY_INIT;
713 FILETIME ftLastWriteTime = WINPR_C_ARRAY_INIT;
714 FILETIME* pftCreationTime =
nullptr;
715 FILETIME* pftLastAccessTime =
nullptr;
716 FILETIME* pftLastWriteTime =
nullptr;
717 if (liCreationTime.QuadPart != 0)
719 ftCreationTime.dwHighDateTime = liCreationTime.u.HighPart;
720 ftCreationTime.dwLowDateTime = liCreationTime.u.LowPart;
721 pftCreationTime = &ftCreationTime;
724 if (liLastAccessTime.QuadPart != 0)
726 ftLastAccessTime.dwHighDateTime = liLastAccessTime.u.HighPart;
727 ftLastAccessTime.dwLowDateTime = liLastAccessTime.u.LowPart;
728 pftLastAccessTime = &ftLastAccessTime;
731 if (liLastWriteTime.QuadPart != 0)
733 ftLastWriteTime.dwHighDateTime = liLastWriteTime.u.HighPart;
734 ftLastWriteTime.dwLowDateTime = liLastWriteTime.u.LowPart;
735 pftLastWriteTime = &ftLastWriteTime;
738 if (liChangeTime.QuadPart != 0 && liChangeTime.QuadPart > liLastWriteTime.QuadPart)
740 ftLastWriteTime.dwHighDateTime = liChangeTime.u.HighPart;
741 ftLastWriteTime.dwLowDateTime = liChangeTime.u.LowPart;
742 pftLastWriteTime = &ftLastWriteTime;
745 DEBUG_WSTR(
"SetFileTime %s", file->fullpath);
747 if (!SetFileAttributesW(file->fullpath, FileAttributes))
749 char fullpath[MAX_PATH] = WINPR_C_ARRAY_INIT;
750 (void)ConvertWCharToUtf8(file->fullpath, fullpath,
sizeof(fullpath));
751 WLog_ERR(TAG,
"Unable to set file attributes for %s", fullpath);
755 if (!SetFileTime(file->file_handle, pftCreationTime, pftLastAccessTime, pftLastWriteTime))
757 char fullpath[MAX_PATH] = WINPR_C_ARRAY_INIT;
758 (void)ConvertWCharToUtf8(file->fullpath, fullpath,
sizeof(fullpath));
759 WLog_ERR(TAG,
"Unable to set file time for %s", fullpath);
766static BOOL drive_file_set_alloc_information(
DRIVE_FILE* file, UINT32 Length,
wStream* input)
769 const uint32_t expect = 8;
770 if (Length != expect)
772 WLog_WARN(TAG,
"Unexpected Length=%" PRIu32
", expected %" PRIu32, Length, expect);
777 const int64_t size = Stream_Get_INT64(input);
779 if (file->file_handle == INVALID_HANDLE_VALUE)
781 char fullpath[MAX_PATH] = WINPR_C_ARRAY_INIT;
782 (void)ConvertWCharToUtf8(file->fullpath, fullpath,
sizeof(fullpath));
783 WLog_ERR(TAG,
"Unable to truncate %s to %" PRId64
" (%" PRIu32
")", fullpath, size,
790 if (!SetFilePointerEx(file->file_handle, liSize,
nullptr, FILE_BEGIN))
792 char fullpath[MAX_PATH] = WINPR_C_ARRAY_INIT;
793 (void)ConvertWCharToUtf8(file->fullpath, fullpath,
sizeof(fullpath));
794 WLog_ERR(TAG,
"Unable to truncate %s to %" PRId64
" (%" PRIu32
")", fullpath, size,
799 DEBUG_WSTR(
"Truncate %s", file->fullpath);
801 if (SetEndOfFile(file->file_handle) == 0)
803 char fullpath[MAX_PATH] = WINPR_C_ARRAY_INIT;
804 (void)ConvertWCharToUtf8(file->fullpath, fullpath,
sizeof(fullpath));
805 WLog_ERR(TAG,
"Unable to truncate %s to %" PRId64
" (%" PRIu32
")", fullpath, size,
814static BOOL drive_file_set_disposition_information(
DRIVE_FILE* file, UINT32 Length,
wStream* input)
817 uint8_t delete_pending = 0;
820 if (file->is_dir && !PathIsDirectoryEmptyW(file->fullpath))
822 SetLastError(ERROR_DIR_NOT_EMPTY);
828 const uint32_t expect = 1;
829 if (Length != expect)
830 WLog_DBG(TAG,
"Unexpected Length=%" PRIu32
", expected %" PRIu32, Length, expect);
832 delete_pending = Stream_Get_UINT8(input);
839 DEBUG_WSTR(
"SetDeletePending %s", file->fullpath);
840 const uint32_t attr = GetFileAttributesW(file->fullpath);
842 if (attr & FILE_ATTRIBUTE_READONLY)
844 SetLastError(ERROR_ACCESS_DENIED);
849 file->delete_pending = delete_pending;
854static BOOL drive_file_set_rename_information(
DRIVE_FILE* file, UINT32 Length,
wStream* input)
858 const uint32_t expect = 6;
861 WLog_WARN(TAG,
"Unexpected Length=%" PRIu32
", expected at least %" PRIu32, Length, expect);
866 const uint8_t ReplaceIfExists = Stream_Get_UINT8(input);
867 Stream_Seek_UINT8(input);
868 const uint64_t FileNameLength = Stream_Get_UINT32(input);
870 if (Length != expect + FileNameLength)
872 WLog_WARN(TAG,
"Unexpected Length=%" PRIu32
", expected %" PRIu64, Length,
873 expect + FileNameLength);
877 WCHAR* fullpath = drive_file_combine_fullpath(file->basepath, Stream_ConstPointer(input),
878 FileNameLength /
sizeof(WCHAR));
885 if (file->file_handle != INVALID_HANDLE_VALUE)
887 (void)CloseHandle(file->file_handle);
888 file->file_handle = INVALID_HANDLE_VALUE;
892 DEBUG_WSTR(
"MoveFileExW %s", file->fullpath);
894 if (MoveFileExW(file->fullpath, fullpath,
895 MOVEFILE_COPY_ALLOWED | (ReplaceIfExists ? MOVEFILE_REPLACE_EXISTING : 0)))
897 const BOOL rc = drive_file_set_fullpath(file, fullpath);
909 drive_file_init(file);
914BOOL drive_file_set_information(
DRIVE_FILE* file, UINT32 FsInformationClass, UINT32 Length,
920 if (!Stream_CheckAndLogRequiredLength(TAG, input, Length))
923 switch (FsInformationClass)
925 case FileBasicInformation:
926 return drive_file_set_basic_information(file, Length, input);
928 case FileEndOfFileInformation:
930 case FileAllocationInformation:
931 return drive_file_set_alloc_information(file, Length, input);
933 case FileDispositionInformation:
934 return drive_file_set_disposition_information(file, Length, input);
936 case FileRenameInformation:
937 return drive_file_set_rename_information(file, Length, input);
940 WLog_WARN(TAG,
"Unhandled FSInformationClass %s [0x%08" PRIx32
"]",
941 FSInformationClass2Tag(FsInformationClass), FsInformationClass);
949static BOOL drive_file_query_dir_info(
DRIVE_FILE* file,
wStream* output,
size_t length)
952 WINPR_ASSERT(output);
955 if (!Stream_EnsureRemainingCapacity(output, 4ull + 64ull + length))
958 if (length > UINT32_MAX - 64)
961 Stream_Write_UINT32(output, (UINT32)(64 + length));
962 Stream_Write_UINT32(output, 0);
963 Stream_Write_UINT32(output, 0);
964 Stream_Write_UINT32(output, file->find_data.ftCreationTime.dwLowDateTime);
965 Stream_Write_UINT32(output, file->find_data.ftCreationTime.dwHighDateTime);
966 Stream_Write_UINT32(output,
967 file->find_data.ftLastAccessTime.dwLowDateTime);
968 Stream_Write_UINT32(output,
969 file->find_data.ftLastAccessTime.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.ftLastWriteTime.dwLowDateTime);
973 Stream_Write_UINT32(output, file->find_data.ftLastWriteTime.dwHighDateTime);
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.nFileSizeLow);
977 Stream_Write_UINT32(output, file->find_data.nFileSizeHigh);
978 Stream_Write_UINT32(output, file->find_data.dwFileAttributes);
979 Stream_Write_UINT32(output, (UINT32)length);
980 Stream_Write(output, file->find_data.cFileName, length);
985static BOOL drive_file_query_full_dir_info(
DRIVE_FILE* file,
wStream* output,
size_t length)
988 WINPR_ASSERT(output);
990 if (!Stream_EnsureRemainingCapacity(output, 4ull + 68ull + length))
993 if (length > UINT32_MAX - 68)
996 Stream_Write_UINT32(output, (UINT32)(68 + length));
997 Stream_Write_UINT32(output, 0);
998 Stream_Write_UINT32(output, 0);
999 Stream_Write_UINT32(output, file->find_data.ftCreationTime.dwLowDateTime);
1000 Stream_Write_UINT32(output, file->find_data.ftCreationTime.dwHighDateTime);
1001 Stream_Write_UINT32(output,
1002 file->find_data.ftLastAccessTime.dwLowDateTime);
1003 Stream_Write_UINT32(output,
1004 file->find_data.ftLastAccessTime.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.ftLastWriteTime.dwLowDateTime);
1008 Stream_Write_UINT32(output, file->find_data.ftLastWriteTime.dwHighDateTime);
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.nFileSizeLow);
1012 Stream_Write_UINT32(output, file->find_data.nFileSizeHigh);
1013 Stream_Write_UINT32(output, file->find_data.dwFileAttributes);
1014 Stream_Write_UINT32(output, (UINT32)length);
1015 Stream_Write_UINT32(output, 0);
1016 Stream_Write(output, file->find_data.cFileName, length);
1021static BOOL drive_file_query_both_dir_info(
DRIVE_FILE* file,
wStream* output,
size_t length)
1024 WINPR_ASSERT(output);
1026 if (!Stream_EnsureRemainingCapacity(output, 4ull + 93ull + length))
1029 if (length > UINT32_MAX - 93)
1032 Stream_Write_UINT32(output, (UINT32)(93 + length));
1033 Stream_Write_UINT32(output, 0);
1034 Stream_Write_UINT32(output, 0);
1035 Stream_Write_UINT32(output, file->find_data.ftCreationTime.dwLowDateTime);
1036 Stream_Write_UINT32(output, file->find_data.ftCreationTime.dwHighDateTime);
1037 Stream_Write_UINT32(output,
1038 file->find_data.ftLastAccessTime.dwLowDateTime);
1039 Stream_Write_UINT32(output,
1040 file->find_data.ftLastAccessTime.dwHighDateTime);
1041 Stream_Write_UINT32(output, file->find_data.ftLastWriteTime.dwLowDateTime);
1042 Stream_Write_UINT32(output, file->find_data.ftLastWriteTime.dwHighDateTime);
1043 Stream_Write_UINT32(output, file->find_data.ftLastWriteTime.dwLowDateTime);
1044 Stream_Write_UINT32(output, file->find_data.ftLastWriteTime.dwHighDateTime);
1045 Stream_Write_UINT32(output, file->find_data.nFileSizeLow);
1046 Stream_Write_UINT32(output, file->find_data.nFileSizeHigh);
1047 Stream_Write_UINT32(output, file->find_data.nFileSizeLow);
1048 Stream_Write_UINT32(output, file->find_data.nFileSizeHigh);
1049 Stream_Write_UINT32(output, file->find_data.dwFileAttributes);
1050 Stream_Write_UINT32(output, (UINT32)length);
1051 Stream_Write_UINT32(output, 0);
1052 Stream_Write_UINT8(output, 0);
1054 Stream_Zero(output, 24);
1055 Stream_Write(output, file->find_data.cFileName, length);
1060static BOOL drive_file_query_names_info(
DRIVE_FILE* file,
wStream* output,
size_t length)
1063 WINPR_ASSERT(output);
1065 if (!Stream_EnsureRemainingCapacity(output, 4ull + 12ull + length))
1068 if (length > UINT32_MAX - 12)
1071 Stream_Write_UINT32(output, (UINT32)(12 + length));
1072 Stream_Write_UINT32(output, 0);
1073 Stream_Write_UINT32(output, 0);
1074 Stream_Write_UINT32(output, (UINT32)length);
1075 Stream_Write(output, file->find_data.cFileName, length);
1079BOOL drive_file_query_directory(
DRIVE_FILE* file, UINT32 FsInformationClass, BYTE InitialQuery,
1080 const WCHAR* path, UINT32 PathWCharLength,
wStream* output)
1084 WCHAR* ent_path =
nullptr;
1086 if (!file || !path || !output)
1089 if (InitialQuery != 0)
1092 if (file->find_handle != INVALID_HANDLE_VALUE)
1093 FindClose(file->find_handle);
1095 ent_path = drive_file_combine_fullpath(file->basepath, path, PathWCharLength);
1097 file->find_handle = FindFirstFileW(ent_path, &file->find_data);
1100 if (file->find_handle == INVALID_HANDLE_VALUE)
1103 else if (!FindNextFileW(file->find_handle, &file->find_data))
1106 length = _wcslen(file->find_data.cFileName) *
sizeof(WCHAR);
1108 switch (FsInformationClass)
1110 case FileDirectoryInformation:
1111 rc = drive_file_query_dir_info(file, output, length);
1114 case FileFullDirectoryInformation:
1115 rc = drive_file_query_full_dir_info(file, output, length);
1118 case FileBothDirectoryInformation:
1119 rc = drive_file_query_both_dir_info(file, output, length);
1122 case FileNamesInformation:
1123 rc = drive_file_query_names_info(file, output, length);
1127 WLog_WARN(TAG,
"Unhandled FSInformationClass %s [0x%08" PRIx32
"]",
1128 FSInformationClass2Tag(FsInformationClass), FsInformationClass);
1136 Stream_Write_UINT32(output, 0);
1137 Stream_Write_UINT8(output, 0);