master
h 374 lines 7.34 KB
Raw
1 // Copyright (C) Microsoft Corporation. All rights reserved.
2 #pragma once
3
4 #include "p9defs.h"
5
6 namespace p9fs {
7
8 struct DirectoryEntry
9 {
10 Qid Qid;
11 UINT64 Offset;
12 UINT8 Type;
13 std::string_view Name;
14 };
15
16 template <typename T>
17 struct ReadResult
18 {
19 T Result;
20 bool Success;
21 };
22
23 // Class to read elements from a 9pfs protocol buffer.
24 // TODO: Need ways to read that don't fail fast but return errors.
25 class SpanReader
26 {
27 public:
28 SpanReader() = default;
29
30 SpanReader(gsl::span<const gsl::byte> message) : m_Message(message)
31 {
32 }
33
34 gsl::span<const gsl::byte> Read(unsigned int count)
35 {
36 if (m_Message.size() - m_Offset < count)
37 {
38 FAIL_FAST();
39 }
40
41 auto result = m_Message.subspan(m_Offset, count);
42 m_Offset += count;
43 return result;
44 }
45
46 ReadResult<gsl::span<const gsl::byte>> TryRead(unsigned int count)
47 {
48 if (m_Message.size() - m_Offset < count)
49 {
50 return {};
51 }
52
53 auto result = m_Message.subspan(m_Offset, count);
54 m_Offset += count;
55 return {result, true};
56 }
57
58 UINT8 U8()
59 {
60 return ReadFixed<UINT8>();
61 }
62
63 UINT16 U16()
64 {
65 return ReadFixed<UINT16>();
66 }
67
68 UINT32 U32()
69 {
70 return ReadFixed<UINT32>();
71 }
72
73 UINT64 U64()
74 {
75 return ReadFixed<UINT64>();
76 }
77
78 ReadResult<UINT8> TryU8()
79 {
80 return TryReadFixed<UINT8>();
81 }
82
83 ReadResult<UINT16> TryU16()
84 {
85 return TryReadFixed<UINT16>();
86 }
87
88 ReadResult<UINT32> TryU32()
89 {
90 return TryReadFixed<UINT32>();
91 }
92
93 ReadResult<UINT64> TryU64()
94 {
95 return TryReadFixed<UINT64>();
96 }
97
98 Qid Qid()
99 {
100 p9fs::Qid result;
101 result.Type = static_cast<QidType>(U8());
102 result.Version = U32();
103 result.Path = U64();
104 return result;
105 }
106
107 ReadResult<p9fs::Qid> TryQid()
108 {
109 if (m_Message.size() - m_Offset < QidSize)
110 {
111 return {};
112 }
113
114 return {Qid(), true};
115 }
116
117 std::string_view String()
118 {
119 const auto length = U16();
120 auto s = Read(length);
121 return FixString(s);
122 }
123
124 ReadResult<std::string_view> TryString()
125 {
126 const auto length = TryU16();
127 if (!length.Success)
128 {
129 return {};
130 }
131
132 auto s = TryRead(length.Result);
133 if (!s.Success)
134 {
135 return {};
136 }
137
138 return {FixString(s.Result), true};
139 }
140
141 #ifndef GSL_KERNEL_MODE
142
143 std::string_view Name()
144 {
145 auto s = String();
146 if (s.size() == 0 || s == "." || s == ".." || std::find_if(s.begin(), s.end(), [](char c) { return c == '/'; }) != s.end())
147 {
148 THROW_INVALID();
149 }
150
151 return s;
152 }
153
154 #endif
155
156 ReadResult<DirectoryEntry> TryDirectoryEntry()
157 {
158 // Check if the data is large enough for the fixed part.
159 if (m_Message.size() - m_Offset < QidSize + sizeof(UINT64) + sizeof(UINT8) + sizeof(UINT16))
160 {
161 return {};
162 }
163
164 DirectoryEntry result;
165 result.Qid = Qid();
166 result.Offset = U64();
167 result.Type = U8();
168 auto name = TryString();
169 if (!name.Success)
170 {
171 return {};
172 }
173
174 result.Name = name.Result;
175 return {result, true};
176 }
177
178 StatResult ReadStatResult()
179 {
180 StatResult attr;
181 attr.Mode = U32();
182 attr.Uid = U32();
183 attr.Gid = U32();
184 attr.NLink = U64();
185 attr.RDev = U64();
186 attr.Size = U64();
187 attr.BlockSize = U64();
188 attr.Blocks = U64();
189 attr.AtimeSec = U64();
190 attr.AtimeNsec = U64();
191 attr.MtimeSec = U64();
192 attr.MtimeNsec = U64();
193 attr.CtimeSec = U64();
194 attr.CtimeNsec = U64();
195 return attr;
196 }
197
198 ReadResult<StatResult> TryStatResult()
199 {
200 // Check if the data is large enough.
201 if (m_Message.size() - m_Offset < StatResultSize)
202 {
203 return {};
204 }
205
206 return {ReadStatResult(), true};
207 }
208
209 size_t Size() const
210 {
211 return m_Message.size();
212 }
213
214 size_t Offset() const
215 {
216 return m_Offset;
217 }
218
219 gsl::span<const gsl::byte> ReadToEnd()
220 {
221 return Read(static_cast<unsigned int>(m_Message.size() - m_Offset));
222 }
223
224 gsl::span<const gsl::byte> Span() const
225 {
226 return m_Message;
227 }
228
229 private:
230 template <class T>
231 T ReadFixed()
232 {
233 auto s = Read(sizeof(T));
234 return *reinterpret_cast<const T*>(s.data());
235 }
236
237 template <typename T>
238 ReadResult<T> TryReadFixed()
239 {
240 auto s = TryRead(sizeof(T));
241 if (!s.Success)
242 {
243 return {};
244 }
245
246 return {*reinterpret_cast<const T*>(s.Result.data()), true};
247 }
248
249 std::string_view FixString(gsl::span<const gsl::byte> s)
250 {
251 auto string = std::string_view{reinterpret_cast<const char*>(s.data()), static_cast<std::string_view::size_type>(s.size())};
252
253 //
254 // Check for internal nul characters.
255 //
256 std::string_view::size_type strlength = 0;
257 while (strlength < string.size() && string[strlength] != 0)
258 {
259 strlength++;
260 }
261
262 return string.substr(0, strlength);
263 }
264
265 gsl::span<const gsl::byte> m_Message;
266 size_t m_Offset{};
267 };
268
269 // Class to write elements to a 9pfs protocol buffer.
270 class SpanWriter
271 {
272 public:
273 SpanWriter(gsl::span<gsl::byte> message) : Message(message)
274 {
275 }
276
277 void U8(UINT8 value)
278 {
279 WriteFixed(value);
280 }
281
282 void U16(UINT16 value)
283 {
284 WriteFixed(value);
285 }
286
287 void U32(UINT32 value)
288 {
289 WriteFixed(value);
290 }
291
292 void U64(UINT64 value)
293 {
294 WriteFixed(value);
295 }
296
297 void Qid(const Qid& value)
298 {
299 U8(static_cast<UINT8>(value.Type));
300 U32(value.Version);
301 U64(value.Path);
302 }
303
304 void String(std::string_view value)
305 {
306 if (value.size() > UINT16_MAX)
307 {
308 FAIL_FAST();
309 }
310
311 U16(static_cast<UINT16>(value.size()));
312 auto s = Next(value.size());
313 auto bytes = gsl::as_bytes(gsl::make_span(value.data(), value.size()));
314 gsl::copy(bytes, s);
315 }
316
317 gsl::span<gsl::byte> Result()
318 {
319 return Message.subspan(0, Offset);
320 }
321
322 size_t Size() const
323 {
324 return Offset;
325 }
326
327 size_t MaxSize() const
328 {
329 return Message.size();
330 }
331
332 gsl::span<gsl::byte> Peek()
333 {
334 return Message.subspan(Offset);
335 }
336
337 gsl::span<gsl::byte> Peek(size_t Count)
338 {
339 return Message.subspan(Offset, Count);
340 }
341
342 gsl::span<gsl::byte> Next(size_t Count)
343 {
344 auto s = Peek(Count);
345 Offset += Count;
346 return s;
347 }
348
349 void Header(MessageType messageType, UINT16 tag) const
350 {
351 SpanWriter headerWriter{Message.subspan(0, HeaderSize)};
352 headerWriter.U32(static_cast<UINT32>(Offset));
353 headerWriter.U8(static_cast<UINT8>(messageType));
354 headerWriter.U16(tag);
355 }
356
357 void Write(gsl::span<const gsl::byte> buffer)
358 {
359 gsl::copy(buffer, Next(buffer.size()));
360 }
361
362 private:
363 template <class T>
364 void WriteFixed(T value)
365 {
366 auto s = Next(sizeof(value));
367 *reinterpret_cast<T*>(s.data()) = value;
368 }
369
370 gsl::span<gsl::byte> Message;
371 size_t Offset{};
372 };
373
374 } // namespace p9fs