3 # Copyright (C) 2020 by Ronnie Sahlberg<ronniesahlberg@gmail.com>
9 from smb2.header import Direction
10 from smb2.timestamps import WinToTimeval, TimevalToWin
11 from smb2.unicode import UCS2toUTF8, UTF8toUCS2
14 # SMB2 FILESYSTEM INFORMATION CLASSES
16 class FSInfoClass(Enum):
26 class DeviceType(Enum):
33 REMOVABLE_MEDIA = 0x00000001
34 READ_ONLY_DEVICE = 0x00000002
35 FLOPPY_DISKETTE = 0x00000004
36 WRITE_ONCE_MEDIA = 0x00000008
37 REMOTE_DEVICE = 0x00000010
38 DEVICE_IS_MOUNTED = 0x00000020
39 VIRTUAL_VOLUME = 0x00000040
40 DEVICE_SECURE_OPEN = 0x00000100
41 CHARACTERISTICS_TS_DEVICE = 0x00001000
42 CHARACTERISTICS_WEBDAV_DEVICE = 0x00001000
43 DEVICE_ALLOW_APPCONTAINER_TRAVERSAL = 0x00002000
44 PORTABLE_DEVICE = 0x00004000
49 SUPPORTS_SPARSE_VDL = 0x10000000
50 SUPPORTS_BLOCK_REFCOUNTING = 0x08000000
51 SUPPORTS_INTEGRITY_STREAMS = 0x04000000
52 SUPPORTS_USN_JOURNAL = 0x02000000
53 SUPPORTS_OPEN_BY_FILE_ID = 0x01000000
54 SUPPORTS_EXTENDED_ATTRIBUTES = 0x00800000
55 SUPPORTS_HARD_LINKS = 0x00400000
56 SUPPORTS_TRANSACTIONS = 0x00200000
57 SEQUENTIAL_WRITE_ONCE = 0x00100000
58 READ_ONLY_VOLUME = 0x00080000
59 NAMED_STREAMS = 0x00040000
60 SUPPORTS_ENCRYPTION = 0x00020000
61 SUPPORTS_OBJECT_IDS = 0x00010000
62 VOLUME_IS_COMPRESSED = 0x00008000
63 SUPPORTS_REMOTE_STORAGE = 0x00000100
64 SUPPORTS_REPARSE_POINTS = 0x00000080
65 SUPPORTS_SPARSE_FILES = 0x00000040
66 VOLUME_QUOTAS = 0x00000020
67 FILE_COMPRESSION = 0x00000010
68 PERSISTENT_ACLS = 0x00000008
69 UNICODE_ON_DISK = 0x00000004
70 CASE_PRESERVED_NAMES = 0x00000002
71 CASE_SENSITIVE_SEARCH = 0x00000001
76 SSINFO_FLAGS_ALIGNED_DEVICE = 0x00000001
77 SSINFO_FLAGS_PARTITION_ALIGNED_ON_DEVICE = 0x00000002
78 SSINFO_FLAGS_NO_SEEK_PENALTY = 0x00000004
79 SSINFO_FLAGS_TRIM_ENABLED = 0x00000008
82 def decode_attribute_info(buf):
84 i.update({'attributes': struct.unpack_from('<I', buf, 0)[0]})
85 i.update({'maximum_component_name_length': struct.unpack_from('<I', buf, 4)[0]})
86 _len = struct.unpack_from('<I', buf, 8)[0]
88 i.update({'file_system_name': UCS2toUTF8(buf[12:12 + _len])})
92 def encode_attribute_info(i):
94 struct.pack_into('<I', _b, 0, i['attributes'])
95 struct.pack_into('<I', _b, 4, i['maximum_component_name_length'])
96 _n = UTF8toUCS2(i['file_system_name'])
97 struct.pack_into('<I', _b, 8, len(_n))
102 def decode_device_info(buf):
104 i.update({'device_type': struct.unpack_from('<I', buf, 0)[0]})
105 i.update({'characteristics': struct.unpack_from('<I', buf, 4)[0]})
109 def encode_device_info(i):
111 struct.pack_into('<I', _b, 0, i['device_type'])
112 struct.pack_into('<I', _b, 4, i['characteristics'])
116 def decode_volume_info(buf):
118 i.update({'creation_time': WinToTimeval(struct.unpack_from('<Q', buf, 0)[0])})
119 i.update({'serial_number': struct.unpack_from('<I', buf, 8)[0]})
120 i.update({'supports_objects': struct.unpack_from('<B', buf, 16)[0]})
121 _len = struct.unpack_from('<I', buf, 12)[0]
122 i.update({'label': UCS2toUTF8(buf[18:18 + _len])})
126 def encode_volume_info(i):
128 struct.pack_into('<Q', _b, 0, TimevalToWin(i['creation_time']))
129 struct.pack_into('<I', _b, 8, i['serial_number'])
130 struct.pack_into('<B', _b, 16, i['supports_objects'])
131 _lab = UTF8toUCS2(i['label'])
132 struct.pack_into('<I', _b, 12, len(_lab))
137 def encode_sector_size_info(i):
139 struct.pack_into('<I', _b, 0, i['logical_bytes_per_sector'])
140 struct.pack_into('<I', _b, 4, i['physical_bytes_per_sector_for_atomicity'])
141 struct.pack_into('<I', _b, 8, i['physical_bytes_per_sector_for_performance'])
142 struct.pack_into('<I', _b, 12, i['effective_physical_bytes_per_sector_for_atomicity'])
143 struct.pack_into('<I', _b, 16, i['flags'])
144 struct.pack_into('<I', _b, 20, i['byte_offset_for_sector_alignment'])
145 struct.pack_into('<I', _b, 24, i['byte_offset_for_partition_alignment'])
149 def decode_sector_size_info(buf):
151 i.update({'logical_bytes_per_sector': struct.unpack_from('<I', buf, 0)[0]})
152 i.update({'physical_bytes_per_sector_for_atomicity': struct.unpack_from('<I', buf, 4)[0]})
153 i.update({'physical_bytes_per_sector_for_performance': struct.unpack_from('<I', buf, 8)[0]})
154 i.update({'effective_physical_bytes_per_sector_for_atomicity': struct.unpack_from('<I', buf, 12)[0]})
155 i.update({'flags': struct.unpack_from('<I', buf, 16)[0]})
156 i.update({'byte_offset_for_sector_alignment': struct.unpack_from('<I', buf, 20)[0]})
157 i.update({'byte_offset_for_partition_alignment': struct.unpack_from('<I', buf, 24)[0]})
161 def encode_full_size_info(i):
163 struct.pack_into('<Q', _b, 0, i['total_allocation_units'])
164 struct.pack_into('<Q', _b, 8, i['caller_available_allocation_units'])
165 struct.pack_into('<Q', _b, 16, i['actual_available_allocation_units'])
166 struct.pack_into('<I', _b, 24, i['sectors_per_allocation_unit'])
167 struct.pack_into('<I', _b, 28, i['bytes_per_sector'])
171 def decode_full_size_info(buf):
173 i.update({'total_allocation_units': struct.unpack_from('<Q', buf, 0)[0]})
174 i.update({'caller_available_allocation_units': struct.unpack_from('<Q', buf, 8)[0]})
175 i.update({'actual_available_allocation_units': struct.unpack_from('<Q', buf, 16)[0]})
176 i.update({'sectors_per_allocation_unit': struct.unpack_from('<I', buf, 24)[0]})
177 i.update({'bytes_per_sector': struct.unpack_from('<I', buf, 28)[0]})
183 FSInfoClass.VOLUME: (encode_volume_info,
185 FSInfoClass.DEVICE: (encode_device_info,
187 FSInfoClass.ATTRIBUTE: (encode_attribute_info,
188 decode_attribute_info),
189 FSInfoClass.SECTOR_SIZE: (encode_sector_size_info,
190 decode_sector_size_info),
191 FSInfoClass.FULL_SIZE: (encode_full_size_info,
192 decode_full_size_info),
195 class FSInfo(object):
200 def __init__(self, **kwargs):
207 def decode(dic, buf):
208 if dic in dir_coders:
209 info = dir_coders[dic][1](buf)
212 print('Unknown FSInfoClass', dic)
216 def encode(dic, info):
217 if dic in dir_coders:
218 buf = dir_coders[dic][0](info)
221 print('Unknown FSInfoClass', dic)