-
Notifications
You must be signed in to change notification settings - Fork 2.1k
FileFullDirectoryInformation
#12908
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
FileFullDirectoryInformation
#12908
Changes from all commits
24c1a90
41ac367
58cac52
fa3531f
ab4d66d
aaa8369
54b7e3d
071620b
52a3d5d
ceddf84
6baccf6
9036618
770f6e7
17a35e8
c946b52
787b67e
6cd9ac2
997b7d6
eb8ed1a
54b53d0
8f1ead3
9a88738
fb60ebb
51f83e5
b4192a6
6cf694a
fa0d555
4b9c330
66eb895
687b84c
058530b
1543585
549eb02
8c5e2b1
de13b64
8017ef2
1ce587f
66b5b00
de8e052
0feae71
20d9aeb
ec900b8
e43694b
95af26b
2adf291
eec39f5
c43d688
a56236f
20efe3e
dac6c41
6251502
2cb663d
3615580
7fe5b95
9274c31
7975209
b0072f9
ce1c6c5
1732e90
6605005
224db3a
9ec0cba
ee34ddd
dbedfc8
df26b8f
e0bbfcf
eccab5a
51c956c
8d532c8
750fe60
f4959ee
e5d849e
f146e42
53cc341
fe4bd3e
6bfc7a3
27d7c53
f00eeb6
0227339
cd4b5a2
9ebf970
8d97123
034f396
b01c4ee
d7950f6
1db2ff5
e1ce4ce
664a8e4
6ce109a
3dc58ad
90350d1
a71b390
c4371da
9e4db09
511b1d2
02f3ec9
750e7ff
5bd7968
15fb5c5
efa9ac1
23ddd4d
67ee1b8
8e0a0ed
61d2509
f6f7c69
8dc6616
57a826c
b449124
6b304ff
766c0ca
93ba0bf
3c3db15
570019a
58cf5e2
7155ef4
7e4986f
cde94ea
bd86280
1abfd00
0732269
ab54ef5
5c4aedb
6213cb1
91c855e
cd0a76a
25315f0
1f93760
2edf592
5ed8bd0
7427ea9
5b8a8e6
7b97bcf
57f2009
b53e375
ea608cc
d491636
8046597
9a9eb22
686633c
7718818
aa1af3a
37c3fbb
f48195c
c07f3e5
99086dd
9246c1d
9ddff1a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -573,6 +573,9 @@ impl Client { | |
| // the client by sending a TDP SharedDirectoryListRequest. | ||
| if rdp_req.initial_query != 0 { | ||
| // https://github.com/FreeRDP/FreeRDP/blob/511444a65e7aa2f537c5e531fa68157a50c1bd4d/channels/drive/client/drive_file.c#L775 | ||
| // TODO(isaiah): I'm observing that sometimes rdp_req.path will not be precisely equal to dir.path. For example, we will | ||
| // get a ServerDriveQueryDirectoryRequest where path == "\\*", whereas the corresponding entry in the file_cache will have | ||
| // path == "\\". I'm not quite sure what to do with this yet, so just leaving this as a note to self. | ||
| let path = dir.path.clone(); | ||
|
|
||
| // Ask the client for the list of files in this directory. | ||
|
|
@@ -605,11 +608,10 @@ impl Client { | |
| // And send back the "." directory over RDP | ||
| cli.prep_next_drive_query_dir_response(&rdp_req) | ||
| } else { | ||
| cli.prep_drive_query_dir_response( | ||
| &rdp_req.device_io_request, | ||
| NTSTATUS::STATUS_UNSUCCESSFUL, | ||
| None, | ||
| ) | ||
| // TODO(isaiah): For now any error will kill the session. | ||
| // In the future, we might want to make this send back | ||
| // an NTSTATUS::STATUS_UNSUCCESSFUL instead. | ||
| Err(try_error(&format!("SharedDirectoryListRequest failed with err_code = {:?}", res.err_code))) | ||
| } | ||
| }, | ||
| ), | ||
|
|
@@ -837,15 +839,26 @@ impl Client { | |
| // TODO(isaiah): we should support all the fs_information_class_lvl's that FreeRDP does: | ||
| // https://github.com/FreeRDP/FreeRDP/blob/511444a65e7aa2f537c5e531fa68157a50c1bd4d/channels/drive/client/drive_file.c#L794 | ||
| FsInformationClassLevel::FileBothDirectoryInformation => { | ||
| let buffer = FileBothDirectoryInformation::from(fso)?; | ||
| let buffer = Some(FsInformationClass::FileBothDirectoryInformation( | ||
| FileBothDirectoryInformation::from(fso)? | ||
| )); | ||
| self.prep_drive_query_dir_response( | ||
| &req.device_io_request, | ||
| NTSTATUS::STATUS_SUCCESS, | ||
| Some(FsInformationClass::FileBothDirectoryInformation(buffer)) | ||
| buffer | ||
| ) | ||
| }, | ||
| FsInformationClassLevel::FileFullDirectoryInformation => { | ||
| let buffer = Some(FsInformationClass::FileFullDirectoryInformation( | ||
| FileFullDirectoryInformation::from(fso)? | ||
| )); | ||
| self.prep_drive_query_dir_response( | ||
| &req.device_io_request, | ||
| NTSTATUS::STATUS_SUCCESS, | ||
| buffer | ||
| ) | ||
| } | ||
| FsInformationClassLevel::FileDirectoryInformation | | ||
| FsInformationClassLevel::FileFullDirectoryInformation | | ||
| FsInformationClassLevel::FileNamesInformation => { | ||
| Err(not_implemented_error(&format!( | ||
| "support for ServerDriveQueryDirectoryRequest with fs_information_class_lvl = {:?} is not implemented", | ||
|
|
@@ -1886,16 +1899,18 @@ enum FsInformationClass { | |
| FileStandardInformation(FileStandardInformation), | ||
| FileBothDirectoryInformation(FileBothDirectoryInformation), | ||
| FileAttributeTagInformation(FileAttributeTagInformation), | ||
| FileFullDirectoryInformation(FileFullDirectoryInformation), | ||
| } | ||
|
|
||
| #[allow(dead_code)] | ||
| impl FsInformationClass { | ||
| fn encode(&self) -> RdpResult<Vec<u8>> { | ||
| match self { | ||
| Self::FileBasicInformation(file_basic_info) => file_basic_info.encode(), | ||
| Self::FileStandardInformation(file_standard_info) => file_standard_info.encode(), | ||
| Self::FileBothDirectoryInformation(file_both_dir_info) => file_both_dir_info.encode(), | ||
| Self::FileAttributeTagInformation(file_attr_tag_info) => file_attr_tag_info.encode(), | ||
| Self::FileBasicInformation(fs_info_class) => fs_info_class.encode(), | ||
| Self::FileStandardInformation(fs_info_class) => fs_info_class.encode(), | ||
| Self::FileBothDirectoryInformation(fs_info_class) => fs_info_class.encode(), | ||
| Self::FileAttributeTagInformation(fs_info_class) => fs_info_class.encode(), | ||
| Self::FileFullDirectoryInformation(fs_info_class) => fs_info_class.encode(), | ||
| } | ||
| } | ||
| } | ||
|
|
@@ -2010,11 +2025,10 @@ enum Boolean { | |
|
|
||
| /// 2.4.8 FileBothDirectoryInformation | ||
| /// https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-fscc/270df317-9ba5-4ccb-ba00-8d22be139bc5 | ||
| /// Fields are omitted based on those omitted by FreeRDP: https://github.com/FreeRDP/FreeRDP/blob/511444a65e7aa2f537c5e531fa68157a50c1bd4d/channels/drive/client/drive_file.c#L871 | ||
| #[derive(Debug)] | ||
| struct FileBothDirectoryInformation { | ||
| // next_entry_offset: u32, | ||
| // file_index: u32, | ||
| next_entry_offset: u32, | ||
| file_index: u32, | ||
| creation_time: i64, | ||
| last_access_time: i64, | ||
| last_write_time: i64, | ||
|
|
@@ -2023,15 +2037,14 @@ struct FileBothDirectoryInformation { | |
| allocation_size: i64, | ||
| file_attributes: flags::FileAttributes, | ||
| file_name_length: u32, | ||
| // ea_size: u32, | ||
| // short_name_length: i8, | ||
| ea_size: u32, | ||
| short_name_length: i8, | ||
| // reserved: u8: MUST NOT be added, | ||
| // see https://github.com/FreeRDP/FreeRDP/blob/511444a65e7aa2f537c5e531fa68157a50c1bd4d/channels/drive/client/drive_file.c#L907 | ||
| // short_name: String, // 24 bytes | ||
| short_name: [u8; 24], // 24 bytes | ||
| file_name: String, | ||
| } | ||
|
|
||
| #[allow(dead_code)] | ||
| /// Base size of the FileBothDirectoryInformation, not accounting for variably sized file_name. | ||
| /// Note that file_name's size should be calculated as if it were a Unicode string. | ||
| /// 5 u32's (including FileAttributesFlags) + 6 i64's + 1 i8 + 24 bytes | ||
|
|
@@ -2048,25 +2061,30 @@ impl FileBothDirectoryInformation { | |
| file_attributes: flags::FileAttributes, | ||
| file_name: String, | ||
| ) -> Self { | ||
| // Default field values taken from | ||
| // https://github.com/FreeRDP/FreeRDP/blob/511444a65e7aa2f537c5e531fa68157a50c1bd4d/channels/drive/client/drive_file.c#L871 | ||
| Self { | ||
| next_entry_offset: 0, | ||
| file_index: 0, | ||
| creation_time, | ||
| last_access_time, | ||
| last_write_time, | ||
| change_time, | ||
| end_of_file: file_size, | ||
| allocation_size: file_size, | ||
| file_attributes, | ||
| file_name_length: u32::try_from(util::to_unicode(&file_name, false).len()).unwrap(), | ||
| file_name_length: util::unicode_size(&file_name), | ||
| ea_size: 0, | ||
| short_name_length: 0, | ||
| short_name: [0; 24], | ||
| file_name, | ||
| } | ||
| } | ||
|
|
||
| fn encode(&self) -> RdpResult<Vec<u8>> { | ||
| let mut w = vec![]; | ||
| // next_entry_offset | ||
| w.write_u32::<LittleEndian>(0)?; | ||
| // file_index | ||
| w.write_u32::<LittleEndian>(0)?; | ||
| w.write_u32::<LittleEndian>(self.next_entry_offset)?; | ||
| w.write_u32::<LittleEndian>(self.file_index)?; | ||
| w.write_i64::<LittleEndian>(self.creation_time)?; | ||
| w.write_i64::<LittleEndian>(self.last_access_time)?; | ||
| w.write_i64::<LittleEndian>(self.last_write_time)?; | ||
|
|
@@ -2075,13 +2093,10 @@ impl FileBothDirectoryInformation { | |
| w.write_i64::<LittleEndian>(self.allocation_size)?; | ||
| w.write_u32::<LittleEndian>(self.file_attributes.bits())?; | ||
| w.write_u32::<LittleEndian>(self.file_name_length)?; | ||
| // ea_size | ||
| w.write_u32::<LittleEndian>(0)?; | ||
| // short_name_length | ||
| w.write_i8(0)?; | ||
| w.write_u32::<LittleEndian>(self.ea_size)?; | ||
| w.write_i8(self.short_name_length)?; | ||
| // reserved u8, MUST NOT be added! | ||
| // short_name | ||
| w.extend_from_slice(&[0; 24]); | ||
| w.extend_from_slice(&self.short_name); | ||
| // When working with this field, use file_name_length to determine the length of the file name rather | ||
| // than assuming the presence of a trailing null delimiter. Dot directory names are valid for this field. | ||
| w.extend_from_slice(&util::to_unicode(&self.file_name, false)); | ||
|
|
@@ -2109,6 +2124,95 @@ impl FileBothDirectoryInformation { | |
| } | ||
| } | ||
|
|
||
| /// Base size of the FileFullDirectoryInformation, not accounting for variably sized file_name. | ||
| /// Note that file_name's size should be calculated as if it were a Unicode string. | ||
| /// 5 u32's (including FileAttributesFlags) + 6 i64's | ||
| const FILE_FULL_DIRECTORY_INFORMATION_BASE_SIZE: u32 = (5 * 4) + (6 * 8); // 68 | ||
|
|
||
| /// 2.4.14 FileFullDirectoryInformation | ||
| /// https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-fscc/e8d926d1-3a22-4654-be9c-58317a85540b | ||
| #[derive(Debug)] | ||
| struct FileFullDirectoryInformation { | ||
| next_entry_offset: u32, | ||
| file_index: u32, | ||
| creation_time: i64, | ||
| last_access_time: i64, | ||
| last_write_time: i64, | ||
| change_time: i64, | ||
| end_of_file: i64, | ||
| allocation_size: i64, | ||
| file_attributes: flags::FileAttributes, | ||
| file_name_length: u32, | ||
| ea_size: u32, | ||
| file_name: String, | ||
| } | ||
|
|
||
| impl FileFullDirectoryInformation { | ||
| fn new( | ||
| creation_time: i64, | ||
| last_access_time: i64, | ||
| last_write_time: i64, | ||
| change_time: i64, | ||
| file_size: i64, | ||
| file_attributes: flags::FileAttributes, | ||
| file_name: String, | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Would it make sense to store the UTF-16 variant directly here so that we avoid calculating it for the length check and during the encode?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah good call. I do this repeatedly throughout the stack of PR's I have lined up, so I'm going to make it an issue and revise all of these at once.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
| ) -> Self { | ||
| // Default field values taken from | ||
| // https://github.com/FreeRDP/FreeRDP/blob/511444a65e7aa2f537c5e531fa68157a50c1bd4d/channels/drive/client/drive_file.c#L871 | ||
| Self { | ||
| next_entry_offset: 0, | ||
| file_index: 0, | ||
| creation_time, | ||
| last_access_time, | ||
| last_write_time, | ||
| change_time, | ||
| end_of_file: file_size, | ||
| allocation_size: file_size, | ||
| file_attributes, | ||
| file_name_length: util::unicode_size(&file_name), | ||
| ea_size: 0, | ||
| file_name, | ||
| } | ||
| } | ||
|
|
||
| fn encode(&self) -> RdpResult<Vec<u8>> { | ||
| let mut w = vec![]; | ||
| w.write_u32::<LittleEndian>(self.next_entry_offset)?; | ||
| w.write_u32::<LittleEndian>(self.file_index)?; | ||
| w.write_i64::<LittleEndian>(self.creation_time)?; | ||
| w.write_i64::<LittleEndian>(self.last_access_time)?; | ||
| w.write_i64::<LittleEndian>(self.last_write_time)?; | ||
| w.write_i64::<LittleEndian>(self.change_time)?; | ||
| w.write_i64::<LittleEndian>(self.end_of_file)?; | ||
| w.write_i64::<LittleEndian>(self.allocation_size)?; | ||
| w.write_u32::<LittleEndian>(self.file_attributes.bits())?; | ||
| w.write_u32::<LittleEndian>(self.file_name_length)?; | ||
| w.write_u32::<LittleEndian>(self.ea_size)?; | ||
| // When working with this field, use file_name_length to determine the length of the file name rather | ||
| // than assuming the presence of a trailing null delimiter. Dot directory names are valid for this field. | ||
| w.extend_from_slice(&util::to_unicode(&self.file_name, false)); | ||
| Ok(w) | ||
| } | ||
|
|
||
| fn from(fso: FileSystemObject) -> RdpResult<Self> { | ||
| let file_attributes = if fso.file_type == FileType::Directory { | ||
| flags::FileAttributes::FILE_ATTRIBUTE_DIRECTORY | ||
| } else { | ||
| flags::FileAttributes::FILE_ATTRIBUTE_NORMAL | ||
| }; | ||
| let last_modified = i64::try_from(fso.last_modified)?; | ||
| Ok(Self::new( | ||
| last_modified, | ||
| last_modified, | ||
| last_modified, | ||
| last_modified, | ||
| i64::try_from(fso.size)?, | ||
| file_attributes, | ||
| fso.name()?, | ||
| )) | ||
| } | ||
| } | ||
|
|
||
| /// 2.2.3.4.8 Client Drive Query Information Response (DR_DRIVE_QUERY_INFORMATION_RSP) | ||
| /// https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpefs/37ef4fb1-6a95-4200-9fbf-515464f034a4 | ||
| #[derive(Debug)] | ||
|
|
@@ -2470,11 +2574,11 @@ impl ClientDriveQueryDirectoryResponse { | |
| ) -> RdpResult<Self> { | ||
| let length = match buffer { | ||
| Some(ref fs_information_class) => match fs_information_class { | ||
| FsInformationClass::FileBothDirectoryInformation( | ||
| file_both_directory_information, | ||
| ) => { | ||
| FILE_BOTH_DIRECTORY_INFORMATION_BASE_SIZE | ||
| + file_both_directory_information.file_name_length | ||
| FsInformationClass::FileBothDirectoryInformation(fs_info_class) => { | ||
| FILE_BOTH_DIRECTORY_INFORMATION_BASE_SIZE + fs_info_class.file_name_length | ||
| } | ||
| FsInformationClass::FileFullDirectoryInformation(fs_info_class) => { | ||
| FILE_FULL_DIRECTORY_INFORMATION_BASE_SIZE + fs_info_class.file_name_length | ||
| } | ||
| _ => { | ||
| return Err(not_implemented_error(&format!("ClientDriveQueryDirectoryResponse not implemented for fs_information_class {:?}", fs_information_class))); | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When building
FileFullDirectoryInformation, I decided it was more comprehensible to keep these essentially unused fields as actual fields in the structure, and add their default values in thenewconstructor, rather than having them commented out and then add the defaults inencodelike I was doing before.