xref: /haiku/src/add-ons/kernel/file_systems/netfs/shared/RequestUnflattener.cpp (revision 61b433252a46c552c07b1516d4c750063fcf0d77)
1 // RequestUnflattener.cpp
2 
3 #include <stdlib.h>
4 
5 #include <ByteOrder.h>
6 
7 #include "Compatibility.h"
8 #include "DebugSupport.h"
9 #include "RequestUnflattener.h"
10 
11 const int32 kMaxSaneStringSize	= 4096;			// 4 KB
12 const int32 kMaxSaneDataSize	= 128 * 1024;	// 128 KB
13 
14 // constructor
Reader()15 Reader::Reader()
16 {
17 }
18 
19 // destructor
~Reader()20 Reader::~Reader()
21 {
22 }
23 
24 // Read
25 status_t
Read(int32 size,void ** buffer,bool * mustFree)26 Reader::Read(int32 size, void** buffer, bool* mustFree)
27 {
28 	// check params
29 	if (size < 0 || !buffer || !mustFree)
30 		return B_BAD_VALUE;
31 
32 	// deal with size == 0
33 	if (size == 0) {
34 		*buffer = NULL;
35 		*mustFree = false;
36 		return B_OK;
37 	}
38 
39 	// allocate the buffer and read
40 	*buffer = malloc(size);
41 	if (!*buffer)
42 		return B_NO_MEMORY;
43 	status_t error = Read(*buffer, size);
44 	if (error != B_OK) {
45 		free(*buffer);
46 		return error;
47 	}
48 	return error;
49 }
50 
51 // Skip
52 status_t
Skip(int32 size)53 Reader::Skip(int32 size)
54 {
55 	if (size <= 0)
56 		return B_OK;
57 
58 	if (size > 8)
59 		return B_BAD_VALUE;
60 
61 	char buffer[8];
62 	return Read(buffer, size);
63 }
64 
65 
66 
67 // RequestUnflattener
68 
69 // constructor
RequestUnflattener(Reader * reader)70 RequestUnflattener::RequestUnflattener(Reader* reader)
71 	: RequestMemberVisitor(),
72 	  fReader(reader),
73 	  fStatus(B_OK),
74 	  fBytesRead(0)
75 {
76 }
77 
78 // GetStatus
79 status_t
GetStatus() const80 RequestUnflattener::GetStatus() const
81 {
82 	return fStatus;
83 }
84 
85 // GetBytesRead
86 int32
GetBytesRead() const87 RequestUnflattener::GetBytesRead() const
88 {
89 	return fBytesRead;
90 }
91 
92 // Visit
93 void
Visit(RequestMember * member,bool & data)94 RequestUnflattener::Visit(RequestMember* member, bool& data)
95 {
96 	uint8 netData;
97 	if (Read(&netData, 1) == B_OK)
98 		data = netData;
99 }
100 
101 // Visit
102 void
Visit(RequestMember * member,int8 & data)103 RequestUnflattener::Visit(RequestMember* member, int8& data)
104 {
105 	Read(&data, 1);
106 }
107 
108 // Visit
109 void
Visit(RequestMember * member,uint8 & data)110 RequestUnflattener::Visit(RequestMember* member, uint8& data)
111 {
112 	Read(&data, 1);
113 }
114 
115 // Visit
116 void
Visit(RequestMember * member,int16 & data)117 RequestUnflattener::Visit(RequestMember* member, int16& data)
118 {
119 	if (Read(&data, 2) == B_OK)
120 		data = B_BENDIAN_TO_HOST_INT16(data);
121 }
122 
123 // Visit
124 void
Visit(RequestMember * member,uint16 & data)125 RequestUnflattener::Visit(RequestMember* member, uint16& data)
126 {
127 	if (Read(&data, 2) == B_OK)
128 		data = B_BENDIAN_TO_HOST_INT16(data);
129 }
130 
131 // Visit
132 void
Visit(RequestMember * member,int32 & data)133 RequestUnflattener::Visit(RequestMember* member, int32& data)
134 {
135 	if (Read(&data, 4) == B_OK)
136 		data = B_BENDIAN_TO_HOST_INT32(data);
137 }
138 
139 // Visit
140 void
Visit(RequestMember * member,uint32 & data)141 RequestUnflattener::Visit(RequestMember* member, uint32& data)
142 {
143 	if (Read(&data, 4) == B_OK)
144 		data = B_BENDIAN_TO_HOST_INT32(data);
145 }
146 
147 // Visit
148 void
Visit(RequestMember * member,int64 & data)149 RequestUnflattener::Visit(RequestMember* member, int64& data)
150 {
151 	if (Read(&data, 8) == B_OK)
152 		data = B_BENDIAN_TO_HOST_INT64(data);
153 }
154 
155 // Visit
156 void
Visit(RequestMember * member,uint64 & data)157 RequestUnflattener::Visit(RequestMember* member, uint64& data)
158 {
159 	if (Read(&data, 8) == B_OK)
160 		data = B_BENDIAN_TO_HOST_INT64(data);
161 }
162 
163 // Visit
164 void
Visit(RequestMember * member,Data & data)165 RequestUnflattener::Visit(RequestMember* member, Data& data)
166 {
167 	void* buffer;
168 	int32 size;
169 	bool mustFree;
170 	if (ReadData(buffer, size, mustFree) != B_OK)
171 		return;
172 
173 	// we can't deal with mustFree buffers currently
174 	if (mustFree) {
175 		free(buffer);
176 		fStatus = B_ERROR;
177 		return;
178 	}
179 
180 	data.address = buffer;
181 	data.size = size;
182 }
183 
184 // Visit
185 void
Visit(RequestMember * member,StringData & data)186 RequestUnflattener::Visit(RequestMember* member, StringData& data)
187 {
188 	void* buffer;
189 	int32 size;
190 	bool mustFree;
191 	if (ReadData(buffer, size, mustFree) != B_OK)
192 		return;
193 
194 	// we can't deal with mustFree buffers currently
195 	if (mustFree) {
196 		free(buffer);
197 		fStatus = B_ERROR;
198 		return;
199 	}
200 
201 	data.address = buffer;
202 	data.size = size;
203 // TODO: Check null termination.
204 }
205 
206 // Visit
207 void
Visit(RequestMember * member,RequestMember & subMember)208 RequestUnflattener::Visit(RequestMember* member, RequestMember& subMember)
209 {
210 	subMember.ShowAround(this);
211 }
212 
213 // Visit
214 void
Visit(RequestMember * member,FlattenableRequestMember & subMember)215 RequestUnflattener::Visit(RequestMember* member,
216 	FlattenableRequestMember& subMember)
217 {
218 	if (fStatus != B_OK)
219 		return;
220 
221 	status_t status = subMember.Unflatten(this);
222 	if (fStatus == B_OK)
223 		fStatus = status;
224 }
225 
226 // Read
227 status_t
Read(void * buffer,int32 size)228 RequestUnflattener::Read(void* buffer, int32 size)
229 {
230 	if (fStatus != B_OK)
231 		return fStatus;
232 
233 	fStatus = fReader->Read(buffer, size);
234 	if (fStatus == B_OK)
235 		fBytesRead += size;
236 
237 	return fStatus;
238 }
239 
240 // Read
241 status_t
Read(int32 size,void * & buffer,bool & mustFree)242 RequestUnflattener::Read(int32 size, void*& buffer, bool& mustFree)
243 {
244 	if (fStatus != B_OK)
245 		return fStatus;
246 
247 	fStatus = fReader->Read(size, &buffer, &mustFree);
248 	if (fStatus == B_OK)
249 		fBytesRead += size;
250 
251 	return fStatus;
252 }
253 
254 
255 // Align
256 status_t
Align(int32 align)257 RequestUnflattener::Align(int32 align)
258 {
259 	if (fStatus != B_OK)
260 		return fStatus;
261 
262 	if (align > 1) {
263 		int32 newBytesRead = fBytesRead;
264 		if (!(align & 0x3))
265 			newBytesRead = (fBytesRead + 3) & ~0x3;
266 		else if (!(align & 0x1))
267 			newBytesRead = (fBytesRead + 1) & ~0x1;
268 
269 		if (newBytesRead > fBytesRead) {
270 			fStatus = fReader->Skip(newBytesRead - fBytesRead);
271 			if (fStatus == B_OK)
272 				fBytesRead = newBytesRead;
273 		}
274 	}
275 
276 	return fStatus;
277 }
278 
279 // ReadBool
280 status_t
ReadBool(bool & data)281 RequestUnflattener::ReadBool(bool& data)
282 {
283 	return Read(&data, 1);
284 }
285 
286 // ReadInt32
287 status_t
ReadInt32(int32 & data)288 RequestUnflattener::ReadInt32(int32& data)
289 {
290 	if (Read(&data, 4) == B_OK)
291 		data = B_BENDIAN_TO_HOST_INT32(data);
292 
293 	return fStatus;
294 }
295 
296 
297 // ReadData
298 status_t
ReadData(void * & buffer,int32 & _size,bool & mustFree)299 RequestUnflattener::ReadData(void*& buffer, int32& _size, bool& mustFree)
300 {
301 	if (fStatus != B_OK)
302 		return fStatus;
303 
304 	// read size
305 	int32 size;
306 	if (ReadInt32(size) != B_OK)
307 		return fStatus;
308 
309 	// check size for sanity
310 	if (size < 0 || size > kMaxSaneDataSize) {
311 		fStatus = B_BAD_DATA;
312 		return fStatus;
313 	}
314 
315 	// read data
316 	if (size > 0) {
317 		if (Read(size, buffer, mustFree) != B_OK)
318 			return fStatus;
319 	} else {
320 		buffer = NULL;
321 		mustFree = false;
322 	}
323 
324 	_size = size;
325 	return fStatus;
326 }
327 
328 // ReadString
329 status_t
ReadString(HashString & string)330 RequestUnflattener::ReadString(HashString& string)
331 {
332 	void* buffer;
333 	int32 size;
334 	bool mustFree;
335 	if (ReadData(buffer, size, mustFree) == B_OK) {
336 		if (!string.SetTo((const char*)buffer))
337 			fStatus = B_NO_MEMORY;
338 
339 		if (mustFree)
340 			free(buffer);
341 	}
342 
343 	return fStatus;
344 }
345 
346