xref: /haiku/src/add-ons/kernel/file_systems/userlandfs/kernel_add_on/KernelRequestHandler.cpp (revision 56eb8e78cc702792e3b032e3f5f45da9e5dbea9e)
1 // KernelRequestHandler.cpp
2 
3 #include "Compatibility.h"
4 #include "Debug.h"
5 #include "FileSystem.h"
6 #include "KernelRequestHandler.h"
7 #include "RequestPort.h"
8 #include "Requests.h"
9 #include "Volume.h"
10 
11 #include <NodeMonitor.h>
12 
13 // VolumePutter
14 class VolumePutter {
15 public:
16 	VolumePutter(Volume* volume) : fVolume(volume) {}
17 	~VolumePutter()
18 	{
19 		if (fVolume)
20 			fVolume->RemoveReference();
21 	}
22 
23 private:
24 	Volume	*fVolume;
25 };
26 
27 // constructor
28 KernelRequestHandler::KernelRequestHandler(Volume* volume, uint32 expectedReply)
29 	: RequestHandler(),
30 	  fFileSystem(volume->GetFileSystem()),
31 	  fVolume(volume),
32 	  fExpectedReply(expectedReply)
33 {
34 }
35 
36 // constructor
37 KernelRequestHandler::KernelRequestHandler(FileSystem* fileSystem,
38 	uint32 expectedReply)
39 	: RequestHandler(),
40 	  fFileSystem(fileSystem),
41 	  fVolume(NULL),
42 	  fExpectedReply(expectedReply)
43 {
44 }
45 
46 // destructor
47 KernelRequestHandler::~KernelRequestHandler()
48 {
49 }
50 
51 // HandleRequest
52 status_t
53 KernelRequestHandler::HandleRequest(Request* request)
54 {
55 	if (request->GetType() == fExpectedReply) {
56 		fDone = true;
57 		return B_OK;
58 	}
59 	switch (request->GetType()) {
60 		// notifications
61 		case NOTIFY_LISTENER_REQUEST:
62 			return _HandleRequest((NotifyListenerRequest*)request);
63 		case NOTIFY_SELECT_EVENT_REQUEST:
64 			return _HandleRequest((NotifySelectEventRequest*)request);
65 		case NOTIFY_QUERY_REQUEST:
66 			return _HandleRequest((NotifyQueryRequest*)request);
67 		// vnodes
68 		case GET_VNODE_REQUEST:
69 			return _HandleRequest((GetVNodeRequest*)request);
70 		case PUT_VNODE_REQUEST:
71 			return _HandleRequest((PutVNodeRequest*)request);
72 		case NEW_VNODE_REQUEST:
73 			return _HandleRequest((NewVNodeRequest*)request);
74 		case PUBLISH_VNODE_REQUEST:
75 			return _HandleRequest((PublishVNodeRequest*)request);
76 		case REMOVE_VNODE_REQUEST:
77 			return _HandleRequest((RemoveVNodeRequest*)request);
78 		case UNREMOVE_VNODE_REQUEST:
79 			return _HandleRequest((UnremoveVNodeRequest*)request);
80 		case GET_VNODE_REMOVED_REQUEST:
81 			return _HandleRequest((GetVNodeRemovedRequest*)request);
82 	}
83 PRINT(("KernelRequestHandler::HandleRequest(): unexpected request: %lu\n",
84 request->GetType()));
85 	return B_BAD_DATA;
86 }
87 
88 // #pragma mark -
89 // #pragma mark ----- notifications -----
90 
91 // _HandleRequest
92 status_t
93 KernelRequestHandler::_HandleRequest(NotifyListenerRequest* request)
94 {
95 	// check and executed the request
96 	status_t result = B_OK;
97 	if (fVolume && request->device != fVolume->GetID())
98 		result = B_BAD_VALUE;
99 
100 	// get the names
101 	// name
102 	char* name = (char*)request->name.GetData();
103 	int32 nameLen = request->name.GetSize();
104 	if (name && (nameLen <= 0))
105 		name = NULL;
106 	else if (name)
107 		name[nameLen - 1] = '\0';	// NULL-terminate to be safe
108 
109 	// old name
110 	char* oldName = (char*)request->oldName.GetData();
111 	int32 oldNameLen = request->oldName.GetSize();
112 	if (oldName && (oldNameLen <= 0))
113 		oldName = NULL;
114 	else if (oldName)
115 		oldName[oldNameLen - 1] = '\0';	// NULL-terminate to be safe
116 
117 	// check the names
118 	if (result == B_OK) {
119 		switch (request->operation) {
120 			case B_ENTRY_MOVED:
121 				if (!oldName) {
122 					ERROR(("NotifyListenerRequest: NULL oldName for "
123 						"B_ENTRY_MOVED\n"));
124 					result = B_BAD_VALUE;
125 					break;
126 				}
127 				// fall through...
128 			case B_ENTRY_CREATED:
129 			case B_ENTRY_REMOVED:
130 			case B_ATTR_CHANGED:
131 				if (!name) {
132 					ERROR(("NotifyListenerRequest: NULL name for opcode: %ld\n",
133 						request->operation));
134 					result = B_BAD_VALUE;
135 				}
136 				break;
137 			case B_STAT_CHANGED:
138 				break;
139 		}
140 	}
141 
142 	// execute the request
143 	if (result == B_OK) {
144 		switch (request->operation) {
145 			case B_ENTRY_CREATED:
146 				PRINT(("notify_entry_created(%ld, %lld, \"%s\", %lld)\n",
147 					request->device, request->directory, name, request->node));
148 				result = notify_entry_created(request->device,
149 					request->directory, name, request->node);
150 				break;
151 
152 			case B_ENTRY_REMOVED:
153 				PRINT(("notify_entry_removed(%ld, %lld, \"%s\", %lld)\n",
154 					request->device, request->directory, name, request->node));
155 				result = notify_entry_removed(request->device,
156 					request->directory, name, request->node);
157 				break;
158 
159 			case B_ENTRY_MOVED:
160 				PRINT(("notify_entry_moved(%ld, %lld, \"%s\", %lld, \"%s\", "
161 					"%lld)\n", request->device, request->oldDirectory, oldName,
162 					request->directory, name, request->node));
163 				result = notify_entry_moved(request->device,
164 					request->oldDirectory, oldName, request->directory, name,
165 					request->node);
166 				break;
167 
168 			case B_STAT_CHANGED:
169 				PRINT(("notify_stat_changed(%ld, %lld, 0x%lx)\n",
170 					request->device, request->node, request->details));
171 				result = notify_stat_changed(request->device, request->node,
172 					request->details);
173 				break;
174 
175 			case B_ATTR_CHANGED:
176 				PRINT(("notify_attribute_changed(%ld, %lld, \"%s\", 0x%lx)\n",
177 					request->device, request->node, name,
178 					(int32)request->details));
179 				result = notify_attribute_changed(request->device,
180 					request->node, name, (int32)request->details);
181 				break;
182 
183 			default:
184 				ERROR(("NotifyQueryRequest: unsupported operation: %ld\n",
185 					request->operation));
186 				result = B_BAD_VALUE;
187 				break;
188 		}
189 	}
190 
191 	// prepare the reply
192 	RequestAllocator allocator(fPort->GetPort());
193 	NotifyListenerReply* reply;
194 	status_t error = AllocateRequest(allocator, &reply);
195 	if (error != B_OK)
196 		return error;
197 
198 	reply->error = result;
199 
200 	// send the reply
201 	return fPort->SendRequest(&allocator);
202 }
203 
204 // _HandleRequest
205 status_t
206 KernelRequestHandler::_HandleRequest(NotifySelectEventRequest* request)
207 {
208 	// check and executed the request
209 	status_t result = B_OK;
210 	if (fFileSystem->KnowsSelectSyncEntry(request->sync)) {
211 		if (request->unspecifiedEvent) {
212 			// old style add-ons can't provide an event argument; we shoot
213 			// all events
214 			notify_select_event(request->sync, B_SELECT_READ);
215 			notify_select_event(request->sync, B_SELECT_WRITE);
216 			notify_select_event(request->sync, B_SELECT_ERROR);
217 		} else {
218 			PRINT(("notify_select_event(%p, %d)\n", request->sync,
219 				(int)request->event));
220 			notify_select_event(request->sync, request->event);
221 		}
222 	} else
223 		result = B_BAD_VALUE;
224 
225 	// prepare the reply
226 	RequestAllocator allocator(fPort->GetPort());
227 	NotifySelectEventReply* reply;
228 	status_t error = AllocateRequest(allocator, &reply);
229 	if (error != B_OK)
230 		return error;
231 
232 	reply->error = result;
233 
234 	// send the reply
235 	return fPort->SendRequest(&allocator);
236 }
237 
238 // _HandleRequest
239 status_t
240 KernelRequestHandler::_HandleRequest(NotifyQueryRequest* request)
241 {
242 	// check and executed the request
243 	status_t result = B_OK;
244 	if (fVolume && request->device != fVolume->GetID())
245 		result = B_BAD_VALUE;
246 
247 	// check the name
248 	char* name = (char*)request->name.GetData();
249 	int32 nameLen = request->name.GetSize();
250 	if (!name || nameLen <= 0) {
251 		ERROR(("NotifyQueryRequest: NULL name!\n"));
252 		result = B_BAD_VALUE;
253 	} else
254 		name[nameLen - 1] = '\0';	// NULL-terminate to be safe
255 
256 	// execute the request
257 	if (result == B_OK) {
258 		switch (request->operation) {
259 			case B_ENTRY_CREATED:
260 				PRINT(("notify_query_entry_created(%ld, %ld, %ld, %lld,"
261 					" \"%s\", %lld)\n", request->port, request->token,
262 					request->device, request->directory, name, request->node));
263 				result = notify_query_entry_created(request->port,
264 					request->token, request->device, request->directory, name,
265 					request->node);
266 				break;
267 
268 			case B_ENTRY_REMOVED:
269 				PRINT(("notify_query_entry_removed(%ld, %ld, %ld, %lld,"
270 					" \"%s\", %lld)\n", request->port, request->token,
271 					request->device, request->directory, name, request->node));
272 				result = notify_query_entry_removed(request->port,
273 					request->token, request->device, request->directory, name,
274 					request->node);
275 				break;
276 
277 			case B_ENTRY_MOVED:
278 			default:
279 				ERROR(("NotifyQueryRequest: unsupported operation: %ld\n",
280 					request->operation));
281 				result = B_BAD_VALUE;
282 				break;
283 		}
284 	}
285 
286 	// prepare the reply
287 	RequestAllocator allocator(fPort->GetPort());
288 	NotifyQueryReply* reply;
289 	status_t error = AllocateRequest(allocator, &reply);
290 	if (error != B_OK)
291 		return error;
292 
293 	reply->error = result;
294 
295 	// send the reply
296 	return fPort->SendRequest(&allocator);
297 }
298 
299 // #pragma mark -
300 // #pragma mark ----- vnodes -----
301 
302 // _HandleRequest
303 status_t
304 KernelRequestHandler::_HandleRequest(GetVNodeRequest* request)
305 {
306 	// check and executed the request
307 	Volume* volume = NULL;
308 	status_t result = _GetVolume(request->nsid, &volume);
309 	VolumePutter _(volume);
310 	void* node;
311 	if (result == B_OK)
312 		result = volume->GetVNode(request->vnid, &node);
313 	// prepare the reply
314 	RequestAllocator allocator(fPort->GetPort());
315 	GetVNodeReply* reply;
316 	status_t error = AllocateRequest(allocator, &reply);
317 	if (error != B_OK)
318 		return error;
319 	reply->error = result;
320 	reply->node = node;
321 	// send the reply
322 	return fPort->SendRequest(&allocator);
323 }
324 
325 // _HandleRequest
326 status_t
327 KernelRequestHandler::_HandleRequest(PutVNodeRequest* request)
328 {
329 	// check and executed the request
330 	Volume* volume = NULL;
331 	status_t result = _GetVolume(request->nsid, &volume);
332 	VolumePutter _(volume);
333 	if (result == B_OK)
334 		result = volume->PutVNode(request->vnid);
335 	// prepare the reply
336 	RequestAllocator allocator(fPort->GetPort());
337 	PutVNodeReply* reply;
338 	status_t error = AllocateRequest(allocator, &reply);
339 	if (error != B_OK)
340 		return error;
341 	reply->error = result;
342 	// send the reply
343 	return fPort->SendRequest(&allocator);
344 }
345 
346 // _HandleRequest
347 status_t
348 KernelRequestHandler::_HandleRequest(NewVNodeRequest* request)
349 {
350 	// check and executed the request
351 	Volume* volume = NULL;
352 	status_t result = _GetVolume(request->nsid, &volume);
353 	VolumePutter _(volume);
354 	if (result == B_OK)
355 		result = volume->NewVNode(request->vnid, request->node);
356 	// prepare the reply
357 	RequestAllocator allocator(fPort->GetPort());
358 	NewVNodeReply* reply;
359 	status_t error = AllocateRequest(allocator, &reply);
360 	if (error != B_OK)
361 		return error;
362 	reply->error = result;
363 	// send the reply
364 	return fPort->SendRequest(&allocator);
365 }
366 
367 // _HandleRequest
368 status_t
369 KernelRequestHandler::_HandleRequest(PublishVNodeRequest* request)
370 {
371 	// check and executed the request
372 	Volume* volume = NULL;
373 	status_t result = _GetVolume(request->nsid, &volume);
374 	VolumePutter _(volume);
375 	if (result == B_OK)
376 		result = volume->PublishVNode(request->vnid, request->node);
377 
378 	// prepare the reply
379 	RequestAllocator allocator(fPort->GetPort());
380 	PublishVNodeReply* reply;
381 	status_t error = AllocateRequest(allocator, &reply);
382 	if (error != B_OK)
383 		return error;
384 
385 	reply->error = result;
386 
387 	// send the reply
388 	return fPort->SendRequest(&allocator);
389 }
390 
391 // _HandleRequest
392 status_t
393 KernelRequestHandler::_HandleRequest(RemoveVNodeRequest* request)
394 {
395 	// check and executed the request
396 	Volume* volume = NULL;
397 	status_t result = _GetVolume(request->nsid, &volume);
398 	VolumePutter _(volume);
399 	if (result == B_OK)
400 		result = volume->RemoveVNode(request->vnid);
401 	// prepare the reply
402 	RequestAllocator allocator(fPort->GetPort());
403 	RemoveVNodeReply* reply;
404 	status_t error = AllocateRequest(allocator, &reply);
405 	if (error != B_OK)
406 		return error;
407 	reply->error = result;
408 	// send the reply
409 	return fPort->SendRequest(&allocator);
410 }
411 
412 // _HandleRequest
413 status_t
414 KernelRequestHandler::_HandleRequest(UnremoveVNodeRequest* request)
415 {
416 	// check and executed the request
417 	Volume* volume = NULL;
418 	status_t result = _GetVolume(request->nsid, &volume);
419 	VolumePutter _(volume);
420 	if (result == B_OK)
421 		result = volume->UnremoveVNode(request->vnid);
422 	// prepare the reply
423 	RequestAllocator allocator(fPort->GetPort());
424 	UnremoveVNodeReply* reply;
425 	status_t error = AllocateRequest(allocator, &reply);
426 	if (error != B_OK)
427 		return error;
428 	reply->error = result;
429 	// send the reply
430 	return fPort->SendRequest(&allocator);
431 }
432 
433 // _HandleRequest
434 status_t
435 KernelRequestHandler::_HandleRequest(GetVNodeRemovedRequest* request)
436 {
437 	// check and executed the request
438 	Volume* volume = NULL;
439 	status_t result = _GetVolume(request->nsid, &volume);
440 	VolumePutter _(volume);
441 	bool removed = false;
442 	if (result == B_OK)
443 		result = volume->GetVNodeRemoved(request->vnid, &removed);
444 
445 	// prepare the reply
446 	RequestAllocator allocator(fPort->GetPort());
447 	GetVNodeRemovedReply* reply;
448 	status_t error = AllocateRequest(allocator, &reply);
449 	if (error != B_OK)
450 		return error;
451 
452 	reply->error = result;
453 	reply->removed = removed;
454 
455 	// send the reply
456 	return fPort->SendRequest(&allocator);
457 }
458 
459 // _GetVolume
460 status_t
461 KernelRequestHandler::_GetVolume(dev_t id, Volume** volume)
462 {
463 	if (fVolume) {
464 		if (fVolume->GetID() != id) {
465 			*volume = NULL;
466 			return B_BAD_VALUE;
467 		}
468 		fVolume->AddReference();
469 		*volume = fVolume;
470 		return B_OK;
471 	}
472 	*volume = fFileSystem->GetVolume(id);
473 	return (*volume ? B_OK : B_BAD_VALUE);
474 }
475 
476