28 #include <freerdp/config.h>
36 #include <winpr/wtypes.h>
37 #include <winpr/crt.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] = { 0 }; \
52 (void)ConvertWCharToUtf8(wstr, lpstr, ARRAYSIZE(lpstr)); \
53 WLog_DBG(TAG, msg, lpstr); \
56 #define DEBUG_WSTR(msg, wstr) \
62 static 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';
93 static BOOL contains_dotdot(
const WCHAR* path,
size_t base_length,
size_t path_length)
95 WCHAR dotdotbuffer[6] = { 0 };
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] ==
'\\'))
123 static WCHAR* drive_file_combine_fullpath(
const WCHAR* base_path,
const WCHAR* path,
124 size_t PathWCharLength)
127 WCHAR* fullpath = NULL;
129 if (!base_path || (!path && (PathWCharLength > 0)))
132 const size_t base_path_length = _wcsnlen(base_path, MAX_PATH);
133 const size_t length = base_path_length + PathWCharLength + 1;
134 fullpath = (WCHAR*)calloc(length,
sizeof(WCHAR));
139 CopyMemory(fullpath, base_path, base_path_length *
sizeof(WCHAR));
141 CopyMemory(&fullpath[base_path_length], path, PathWCharLength *
sizeof(WCHAR));
143 if (!drive_file_fix_path(fullpath, length))
147 if (contains_dotdot(&fullpath[base_path_length], base_path_length, PathWCharLength))
149 char abuffer[MAX_PATH] = { 0 };
150 (void)ConvertWCharToUtf8(&fullpath[base_path_length], abuffer, ARRAYSIZE(abuffer));
152 WLog_WARN(TAG,
"[rdpdr] received invalid file path '%s' from server, aborting!",
153 &abuffer[base_path_length]);
167 static BOOL drive_file_set_fullpath(
DRIVE_FILE* file, WCHAR* fullpath)
169 if (!file || !fullpath)
172 const size_t len = _wcslen(fullpath);
173 free(file->fullpath);
174 file->fullpath = NULL;
179 file->fullpath = fullpath;
181 const WCHAR sep[] = { PathGetSeparatorW(PATH_STYLE_NATIVE),
'\0' };
182 WCHAR* filename = _wcsrchr(file->fullpath, *sep);
183 if (filename && _wcsncmp(filename, sep, ARRAYSIZE(sep)) == 0)
191 UINT CreateDisposition = 0;
192 DWORD dwAttr = GetFileAttributesW(file->fullpath);
194 if (dwAttr != INVALID_FILE_ATTRIBUTES)
197 file->is_dir = (dwAttr & FILE_ATTRIBUTE_DIRECTORY) != 0;
201 if (file->CreateDisposition == FILE_CREATE)
203 SetLastError(ERROR_ALREADY_EXISTS);
207 if (file->CreateOptions & FILE_NON_DIRECTORY_FILE)
209 SetLastError(ERROR_ACCESS_DENIED);
217 if (file->CreateOptions & FILE_DIRECTORY_FILE)
219 SetLastError(ERROR_DIRECTORY);
226 file->is_dir = ((file->CreateOptions & FILE_DIRECTORY_FILE) ? TRUE : FALSE);
231 if ((file->CreateDisposition == FILE_OPEN_IF) ||
232 (file->CreateDisposition == FILE_CREATE))
234 if (CreateDirectoryW(file->fullpath, NULL) != 0)
240 SetLastError(ERROR_FILE_NOT_FOUND);
245 if (file->file_handle == INVALID_HANDLE_VALUE)
247 switch (file->CreateDisposition)
251 CreateDisposition = CREATE_ALWAYS;
256 CreateDisposition = OPEN_EXISTING;
261 CreateDisposition = CREATE_NEW;
266 CreateDisposition = OPEN_ALWAYS;
271 CreateDisposition = TRUNCATE_EXISTING;
274 case FILE_OVERWRITE_IF:
276 CreateDisposition = CREATE_ALWAYS;
284 file->SharedAccess = 0;
286 file->file_handle = CreateFileW(file->fullpath, file->DesiredAccess, file->SharedAccess,
287 NULL, CreateDisposition, file->FileAttributes, NULL);
291 if (file->file_handle == INVALID_HANDLE_VALUE)
294 DWORD errorMessageID = GetLastError();
296 if (errorMessageID != 0)
298 LPSTR messageBuffer = NULL;
300 FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
301 FORMAT_MESSAGE_IGNORE_INSERTS,
302 NULL, errorMessageID, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
303 (LPSTR)&messageBuffer, 0, NULL);
304 WLog_ERR(TAG,
"Error in drive_file_init: %s %s", messageBuffer, file->fullpath);
306 LocalFree(messageBuffer);
308 SetLastError(errorMessageID);
313 return file->file_handle != INVALID_HANDLE_VALUE;
316 DRIVE_FILE* drive_file_new(
const WCHAR* base_path,
const WCHAR* path, UINT32 PathWCharLength,
317 UINT32
id, UINT32 DesiredAccess, UINT32 CreateDisposition,
318 UINT32 CreateOptions, UINT32 FileAttributes, UINT32 SharedAccess)
322 if (!base_path || (!path && (PathWCharLength > 0)))
329 WLog_ERR(TAG,
"calloc failed!");
333 file->file_handle = INVALID_HANDLE_VALUE;
334 file->find_handle = INVALID_HANDLE_VALUE;
336 file->basepath = base_path;
337 file->FileAttributes = FileAttributes;
338 file->DesiredAccess = DesiredAccess;
339 file->CreateDisposition = CreateDisposition;
340 file->CreateOptions = CreateOptions;
341 file->SharedAccess = SharedAccess;
342 drive_file_set_fullpath(file, drive_file_combine_fullpath(base_path, path, PathWCharLength));
344 if (!drive_file_init(file))
346 DWORD lastError = GetLastError();
347 drive_file_free(file);
348 SetLastError(lastError);
362 if (file->file_handle != INVALID_HANDLE_VALUE)
364 (void)CloseHandle(file->file_handle);
365 file->file_handle = INVALID_HANDLE_VALUE;
368 if (file->find_handle != INVALID_HANDLE_VALUE)
370 FindClose(file->find_handle);
371 file->find_handle = INVALID_HANDLE_VALUE;
374 if (file->delete_pending)
378 if (!winpr_RemoveDirectory_RecursiveW(file->fullpath))
381 else if (!DeleteFileW(file->fullpath))
387 DEBUG_WSTR(
"Free %s", file->fullpath);
388 free(file->fullpath);
393 BOOL drive_file_seek(
DRIVE_FILE* file, UINT64 Offset)
395 LARGE_INTEGER loffset = { 0 };
400 if (Offset > INT64_MAX)
403 loffset.QuadPart = (LONGLONG)Offset;
404 return SetFilePointerEx(file->file_handle, loffset, NULL, FILE_BEGIN);
407 BOOL drive_file_read(
DRIVE_FILE* file, BYTE* buffer, UINT32* Length)
411 if (!file || !buffer || !Length)
414 DEBUG_WSTR(
"Read file %s", file->fullpath);
416 if (ReadFile(file->file_handle, buffer, *Length, &read, NULL))
425 BOOL drive_file_write(
DRIVE_FILE* file,
const BYTE* buffer, UINT32 Length)
429 if (!file || !buffer)
432 DEBUG_WSTR(
"Write file %s", file->fullpath);
436 if (!WriteFile(file->file_handle, buffer, Length, &written, NULL))
446 static BOOL drive_file_query_from_handle_information(
const DRIVE_FILE* file,
448 UINT32 FsInformationClass,
wStream* output)
450 switch (FsInformationClass)
452 case FileBasicInformation:
455 if (!Stream_EnsureRemainingCapacity(output, 4 + 36))
458 Stream_Write_UINT32(output, 36);
459 Stream_Write_UINT32(output, info->ftCreationTime.dwLowDateTime);
460 Stream_Write_UINT32(output, info->ftCreationTime.dwHighDateTime);
461 Stream_Write_UINT32(output, info->ftLastAccessTime.dwLowDateTime);
462 Stream_Write_UINT32(output, info->ftLastAccessTime.dwHighDateTime);
463 Stream_Write_UINT32(output, info->ftLastWriteTime.dwLowDateTime);
464 Stream_Write_UINT32(output, info->ftLastWriteTime.dwHighDateTime);
465 Stream_Write_UINT32(output, info->ftLastWriteTime.dwLowDateTime);
466 Stream_Write_UINT32(output, info->ftLastWriteTime.dwHighDateTime);
467 Stream_Write_UINT32(output, info->dwFileAttributes);
471 case FileStandardInformation:
474 if (!Stream_EnsureRemainingCapacity(output, 4 + 22))
477 Stream_Write_UINT32(output, 22);
478 Stream_Write_UINT32(output, info->nFileSizeLow);
479 Stream_Write_UINT32(output, info->nFileSizeHigh);
480 Stream_Write_UINT32(output, info->nFileSizeLow);
481 Stream_Write_UINT32(output, info->nFileSizeHigh);
482 Stream_Write_UINT32(output, info->nNumberOfLinks);
483 Stream_Write_UINT8(output, file->delete_pending ? 1 : 0);
484 Stream_Write_UINT8(output, info->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY
490 case FileAttributeTagInformation:
493 if (!Stream_EnsureRemainingCapacity(output, 4 + 8))
496 Stream_Write_UINT32(output, 8);
497 Stream_Write_UINT32(output, info->dwFileAttributes);
498 Stream_Write_UINT32(output, 0);
509 static BOOL drive_file_query_from_attributes(
const DRIVE_FILE* file,
511 UINT32 FsInformationClass,
wStream* output)
513 switch (FsInformationClass)
515 case FileBasicInformation:
518 if (!Stream_EnsureRemainingCapacity(output, 4 + 36))
521 Stream_Write_UINT32(output, 36);
522 Stream_Write_UINT32(output, attrib->ftCreationTime.dwLowDateTime);
523 Stream_Write_UINT32(output, attrib->ftCreationTime.dwHighDateTime);
524 Stream_Write_UINT32(output,
525 attrib->ftLastAccessTime.dwLowDateTime);
526 Stream_Write_UINT32(output,
527 attrib->ftLastAccessTime.dwHighDateTime);
528 Stream_Write_UINT32(output, attrib->ftLastWriteTime.dwLowDateTime);
529 Stream_Write_UINT32(output, attrib->ftLastWriteTime.dwHighDateTime);
530 Stream_Write_UINT32(output, attrib->ftLastWriteTime.dwLowDateTime);
531 Stream_Write_UINT32(output, attrib->ftLastWriteTime.dwHighDateTime);
532 Stream_Write_UINT32(output, attrib->dwFileAttributes);
536 case FileStandardInformation:
539 if (!Stream_EnsureRemainingCapacity(output, 4 + 22))
542 Stream_Write_UINT32(output, 22);
543 Stream_Write_UINT32(output, attrib->nFileSizeLow);
544 Stream_Write_UINT32(output, attrib->nFileSizeHigh);
545 Stream_Write_UINT32(output, attrib->nFileSizeLow);
546 Stream_Write_UINT32(output, attrib->nFileSizeHigh);
547 Stream_Write_UINT32(output, 0);
548 Stream_Write_UINT8(output, file->delete_pending ? 1 : 0);
549 Stream_Write_UINT8(output, attrib->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY
555 case FileAttributeTagInformation:
558 if (!Stream_EnsureRemainingCapacity(output, 4 + 8))
561 Stream_Write_UINT32(output, 8);
562 Stream_Write_UINT32(output, attrib->dwFileAttributes);
563 Stream_Write_UINT32(output, 0);
574 BOOL drive_file_query_information(
DRIVE_FILE* file, UINT32 FsInformationClass,
wStream* output)
580 if (!file || !output)
583 hFile = CreateFileW(file->fullpath, 0, FILE_SHARE_DELETE, NULL, OPEN_EXISTING,
584 FILE_ATTRIBUTE_NORMAL, NULL);
585 if (hFile != INVALID_HANDLE_VALUE)
587 status = GetFileInformationByHandle(hFile, &fileInformation);
588 (void)CloseHandle(hFile);
592 if (!drive_file_query_from_handle_information(file, &fileInformation, FsInformationClass,
602 if (!GetFileAttributesExW(file->fullpath, GetFileExInfoStandard, &fileAttributes))
605 if (!drive_file_query_from_attributes(file, &fileAttributes, FsInformationClass, output))
610 Stream_Write_UINT32(output, 0);
614 BOOL drive_file_set_information(
DRIVE_FILE* file, UINT32 FsInformationClass, UINT32 Length,
618 WCHAR* fullpath = NULL;
619 ULARGE_INTEGER liCreationTime = { 0 };
620 ULARGE_INTEGER liLastAccessTime = { 0 };
621 ULARGE_INTEGER liLastWriteTime = { 0 };
622 ULARGE_INTEGER liChangeTime = { 0 };
623 FILETIME ftCreationTime;
624 FILETIME ftLastAccessTime;
625 FILETIME ftLastWriteTime;
626 FILETIME* pftCreationTime = NULL;
627 FILETIME* pftLastAccessTime = NULL;
628 FILETIME* pftLastWriteTime = NULL;
629 UINT32 FileAttributes = 0;
630 UINT32 FileNameLength = 0;
631 LARGE_INTEGER liSize = { 0 };
632 UINT8 delete_pending = 0;
633 UINT8 ReplaceIfExists = 0;
639 switch (FsInformationClass)
641 case FileBasicInformation:
642 if (!Stream_CheckAndLogRequiredLength(TAG, input, 36))
646 Stream_Read_UINT64(input, liCreationTime.QuadPart);
647 Stream_Read_UINT64(input, liLastAccessTime.QuadPart);
648 Stream_Read_UINT64(input, liLastWriteTime.QuadPart);
649 Stream_Read_UINT64(input, liChangeTime.QuadPart);
650 Stream_Read_UINT32(input, FileAttributes);
652 if (!PathFileExistsW(file->fullpath))
655 if (file->file_handle == INVALID_HANDLE_VALUE)
657 WLog_ERR(TAG,
"Unable to set file time %s (%" PRId32
")", file->fullpath,
662 if (liCreationTime.QuadPart != 0)
664 ftCreationTime.dwHighDateTime = liCreationTime.u.HighPart;
665 ftCreationTime.dwLowDateTime = liCreationTime.u.LowPart;
666 pftCreationTime = &ftCreationTime;
669 if (liLastAccessTime.QuadPart != 0)
671 ftLastAccessTime.dwHighDateTime = liLastAccessTime.u.HighPart;
672 ftLastAccessTime.dwLowDateTime = liLastAccessTime.u.LowPart;
673 pftLastAccessTime = &ftLastAccessTime;
676 if (liLastWriteTime.QuadPart != 0)
678 ftLastWriteTime.dwHighDateTime = liLastWriteTime.u.HighPart;
679 ftLastWriteTime.dwLowDateTime = liLastWriteTime.u.LowPart;
680 pftLastWriteTime = &ftLastWriteTime;
683 if (liChangeTime.QuadPart != 0 && liChangeTime.QuadPart > liLastWriteTime.QuadPart)
685 ftLastWriteTime.dwHighDateTime = liChangeTime.u.HighPart;
686 ftLastWriteTime.dwLowDateTime = liChangeTime.u.LowPart;
687 pftLastWriteTime = &ftLastWriteTime;
690 DEBUG_WSTR(
"SetFileTime %s", file->fullpath);
692 SetFileAttributesW(file->fullpath, FileAttributes);
693 if (!SetFileTime(file->file_handle, pftCreationTime, pftLastAccessTime,
696 WLog_ERR(TAG,
"Unable to set file time to %s", file->fullpath);
702 case FileEndOfFileInformation:
705 case FileAllocationInformation:
706 if (!Stream_CheckAndLogRequiredLength(TAG, input, 8))
710 Stream_Read_INT64(input, size);
712 if (file->file_handle == INVALID_HANDLE_VALUE)
714 WLog_ERR(TAG,
"Unable to truncate %s to %" PRId64
" (%" PRId32
")", file->fullpath,
715 size, GetLastError());
719 liSize.QuadPart = size;
721 if (!SetFilePointerEx(file->file_handle, liSize, NULL, FILE_BEGIN))
723 WLog_ERR(TAG,
"Unable to truncate %s to %" PRId64
" (%" PRId32
")", file->fullpath,
724 size, GetLastError());
728 DEBUG_WSTR(
"Truncate %s", file->fullpath);
730 if (SetEndOfFile(file->file_handle) == 0)
732 WLog_ERR(TAG,
"Unable to truncate %s to %" PRId64
" (%" PRId32
")", file->fullpath,
733 size, GetLastError());
739 case FileDispositionInformation:
743 if (file->is_dir && !PathIsDirectoryEmptyW(file->fullpath))
748 if (!Stream_CheckAndLogRequiredLength(TAG, input, 1))
751 Stream_Read_UINT8(input, delete_pending);
758 DEBUG_WSTR(
"SetDeletePending %s", file->fullpath);
759 attr = GetFileAttributesW(file->fullpath);
761 if (attr & FILE_ATTRIBUTE_READONLY)
763 SetLastError(ERROR_ACCESS_DENIED);
768 file->delete_pending = delete_pending;
771 case FileRenameInformation:
772 if (!Stream_CheckAndLogRequiredLength(TAG, input, 6))
776 Stream_Read_UINT8(input, ReplaceIfExists);
777 Stream_Seek_UINT8(input);
778 Stream_Read_UINT32(input, FileNameLength);
780 if (!Stream_CheckAndLogRequiredLength(TAG, input, FileNameLength))
783 fullpath = drive_file_combine_fullpath(file->basepath, Stream_ConstPointer(input),
784 FileNameLength /
sizeof(WCHAR));
791 if (file->file_handle != INVALID_HANDLE_VALUE)
793 (void)CloseHandle(file->file_handle);
794 file->file_handle = INVALID_HANDLE_VALUE;
798 DEBUG_WSTR(
"MoveFileExW %s", file->fullpath);
800 if (MoveFileExW(file->fullpath, fullpath,
801 MOVEFILE_COPY_ALLOWED |
802 (ReplaceIfExists ? MOVEFILE_REPLACE_EXISTING : 0)))
804 if (!drive_file_set_fullpath(file, fullpath))
814 drive_file_init(file);
825 BOOL drive_file_query_directory(
DRIVE_FILE* file, UINT32 FsInformationClass, BYTE InitialQuery,
826 const WCHAR* path, UINT32 PathWCharLength,
wStream* output)
829 WCHAR* ent_path = NULL;
831 if (!file || !path || !output)
834 if (InitialQuery != 0)
837 if (file->find_handle != INVALID_HANDLE_VALUE)
838 FindClose(file->find_handle);
840 ent_path = drive_file_combine_fullpath(file->basepath, path, PathWCharLength);
842 file->find_handle = FindFirstFileW(ent_path, &file->find_data);
845 if (file->find_handle == INVALID_HANDLE_VALUE)
848 else if (!FindNextFileW(file->find_handle, &file->find_data))
851 length = _wcslen(file->find_data.cFileName) * 2;
853 switch (FsInformationClass)
855 case FileDirectoryInformation:
858 if (!Stream_EnsureRemainingCapacity(output, 4 + 64 + length))
861 if (length > UINT32_MAX - 64)
864 Stream_Write_UINT32(output, (UINT32)(64 + length));
865 Stream_Write_UINT32(output, 0);
866 Stream_Write_UINT32(output, 0);
867 Stream_Write_UINT32(output,
868 file->find_data.ftCreationTime.dwLowDateTime);
869 Stream_Write_UINT32(output,
870 file->find_data.ftCreationTime.dwHighDateTime);
872 output, file->find_data.ftLastAccessTime.dwLowDateTime);
874 output, file->find_data.ftLastAccessTime.dwHighDateTime);
875 Stream_Write_UINT32(output,
876 file->find_data.ftLastWriteTime.dwLowDateTime);
877 Stream_Write_UINT32(output,
878 file->find_data.ftLastWriteTime.dwHighDateTime);
879 Stream_Write_UINT32(output,
880 file->find_data.ftLastWriteTime.dwLowDateTime);
881 Stream_Write_UINT32(output,
882 file->find_data.ftLastWriteTime.dwHighDateTime);
883 Stream_Write_UINT32(output, file->find_data.nFileSizeLow);
884 Stream_Write_UINT32(output, file->find_data.nFileSizeHigh);
885 Stream_Write_UINT32(output, file->find_data.nFileSizeLow);
886 Stream_Write_UINT32(output, file->find_data.nFileSizeHigh);
887 Stream_Write_UINT32(output, file->find_data.dwFileAttributes);
888 Stream_Write_UINT32(output, (UINT32)length);
889 Stream_Write(output, file->find_data.cFileName, length);
892 case FileFullDirectoryInformation:
895 if (!Stream_EnsureRemainingCapacity(output, 4 + 68 + length))
898 if (length > UINT32_MAX - 68)
901 Stream_Write_UINT32(output, (UINT32)(68 + length));
902 Stream_Write_UINT32(output, 0);
903 Stream_Write_UINT32(output, 0);
904 Stream_Write_UINT32(output,
905 file->find_data.ftCreationTime.dwLowDateTime);
906 Stream_Write_UINT32(output,
907 file->find_data.ftCreationTime.dwHighDateTime);
909 output, file->find_data.ftLastAccessTime.dwLowDateTime);
911 output, file->find_data.ftLastAccessTime.dwHighDateTime);
912 Stream_Write_UINT32(output,
913 file->find_data.ftLastWriteTime.dwLowDateTime);
914 Stream_Write_UINT32(output,
915 file->find_data.ftLastWriteTime.dwHighDateTime);
916 Stream_Write_UINT32(output,
917 file->find_data.ftLastWriteTime.dwLowDateTime);
918 Stream_Write_UINT32(output,
919 file->find_data.ftLastWriteTime.dwHighDateTime);
920 Stream_Write_UINT32(output, file->find_data.nFileSizeLow);
921 Stream_Write_UINT32(output, file->find_data.nFileSizeHigh);
922 Stream_Write_UINT32(output, file->find_data.nFileSizeLow);
923 Stream_Write_UINT32(output, file->find_data.nFileSizeHigh);
924 Stream_Write_UINT32(output, file->find_data.dwFileAttributes);
925 Stream_Write_UINT32(output, (UINT32)length);
926 Stream_Write_UINT32(output, 0);
927 Stream_Write(output, file->find_data.cFileName, length);
930 case FileBothDirectoryInformation:
933 if (!Stream_EnsureRemainingCapacity(output, 4 + 93 + length))
936 if (length > UINT32_MAX - 93)
939 Stream_Write_UINT32(output, (UINT32)(93 + length));
940 Stream_Write_UINT32(output, 0);
941 Stream_Write_UINT32(output, 0);
942 Stream_Write_UINT32(output,
943 file->find_data.ftCreationTime.dwLowDateTime);
944 Stream_Write_UINT32(output,
945 file->find_data.ftCreationTime.dwHighDateTime);
947 output, file->find_data.ftLastAccessTime.dwLowDateTime);
949 output, file->find_data.ftLastAccessTime.dwHighDateTime);
950 Stream_Write_UINT32(output,
951 file->find_data.ftLastWriteTime.dwLowDateTime);
952 Stream_Write_UINT32(output,
953 file->find_data.ftLastWriteTime.dwHighDateTime);
954 Stream_Write_UINT32(output,
955 file->find_data.ftLastWriteTime.dwLowDateTime);
956 Stream_Write_UINT32(output,
957 file->find_data.ftLastWriteTime.dwHighDateTime);
958 Stream_Write_UINT32(output, file->find_data.nFileSizeLow);
959 Stream_Write_UINT32(output, file->find_data.nFileSizeHigh);
960 Stream_Write_UINT32(output, file->find_data.nFileSizeLow);
961 Stream_Write_UINT32(output, file->find_data.nFileSizeHigh);
962 Stream_Write_UINT32(output, file->find_data.dwFileAttributes);
963 Stream_Write_UINT32(output, (UINT32)length);
964 Stream_Write_UINT32(output, 0);
965 Stream_Write_UINT8(output, 0);
967 Stream_Zero(output, 24);
968 Stream_Write(output, file->find_data.cFileName, length);
971 case FileNamesInformation:
974 if (!Stream_EnsureRemainingCapacity(output, 4 + 12 + length))
977 if (length > UINT32_MAX - 12)
980 Stream_Write_UINT32(output, (UINT32)(12 + length));
981 Stream_Write_UINT32(output, 0);
982 Stream_Write_UINT32(output, 0);
983 Stream_Write_UINT32(output, (UINT32)length);
984 Stream_Write(output, file->find_data.cFileName, length);
988 WLog_ERR(TAG,
"unhandled FsInformationClass %" PRIu32, FsInformationClass);
995 Stream_Write_UINT32(output, 0);
996 Stream_Write_UINT8(output, 0);