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// VolumePutter
12class VolumePutter {
13public:
14	VolumePutter(Volume* volume) : fVolume(volume) {}
15	~VolumePutter()
16	{
17		if (fVolume)
18			fVolume->RemoveReference();
19	}
20
21private:
22	Volume	*fVolume;
23};
24
25// constructor
26KernelRequestHandler::KernelRequestHandler(Volume* volume, uint32 expectedReply)
27	: RequestHandler(),
28	  fFileSystem(volume->GetFileSystem()),
29	  fVolume(volume),
30	  fExpectedReply(expectedReply)
31{
32}
33
34// constructor
35KernelRequestHandler::KernelRequestHandler(FileSystem* fileSystem,
36	uint32 expectedReply)
37	: RequestHandler(),
38	  fFileSystem(fileSystem),
39	  fVolume(NULL),
40	  fExpectedReply(expectedReply)
41{
42}
43
44// destructor
45KernelRequestHandler::~KernelRequestHandler()
46{
47}
48
49// HandleRequest
50status_t
51KernelRequestHandler::HandleRequest(Request* request)
52{
53	if (request->GetType() == fExpectedReply) {
54		fDone = true;
55		return B_OK;
56	}
57	switch (request->GetType()) {
58		// notifications
59		case NOTIFY_LISTENER_REQUEST:
60			return _HandleRequest((NotifyListenerRequest*)request);
61		case NOTIFY_SELECT_EVENT_REQUEST:
62			return _HandleRequest((NotifySelectEventRequest*)request);
63		case SEND_NOTIFICATION_REQUEST:
64			return _HandleRequest((SendNotificationRequest*)request);
65		// vnodes
66		case GET_VNODE_REQUEST:
67			return _HandleRequest((GetVNodeRequest*)request);
68		case PUT_VNODE_REQUEST:
69			return _HandleRequest((PutVNodeRequest*)request);
70		case NEW_VNODE_REQUEST:
71			return _HandleRequest((NewVNodeRequest*)request);
72		case REMOVE_VNODE_REQUEST:
73			return _HandleRequest((RemoveVNodeRequest*)request);
74		case UNREMOVE_VNODE_REQUEST:
75			return _HandleRequest((UnremoveVNodeRequest*)request);
76		case IS_VNODE_REMOVED_REQUEST:
77			return _HandleRequest((IsVNodeRemovedRequest*)request);
78	}
79PRINT(("KernelRequestHandler::HandleRequest(): unexpected request: %lu\n",
80request->GetType()));
81	return B_BAD_DATA;
82}
83
84// #pragma mark -
85// #pragma mark ----- notifications -----
86
87// _HandleRequest
88status_t
89KernelRequestHandler::_HandleRequest(NotifyListenerRequest* request)
90{
91	// check and executed the request
92	status_t result = B_OK;
93	if (fVolume && request->nsid != fVolume->GetID())
94		result = B_BAD_VALUE;
95	// check the name
96	char* name = (char*)request->name.GetData();
97	int32 nameLen = request->name.GetSize();
98	if (name && (nameLen <= 0 || strnlen(name, nameLen) < 1))
99		name = NULL;
100	else if (name)
101		name[nameLen - 1] = '\0';
102	if (!name) {
103		switch (request->operation) {
104			case B_ENTRY_CREATED:
105			case B_ENTRY_MOVED:
106			case B_ATTR_CHANGED:
107				ERROR(("notify_listener(): NULL name for opcode: %ld\n",
108					request->operation));
109				result = B_BAD_VALUE;
110				break;
111			case B_ENTRY_REMOVED:
112			case B_STAT_CHANGED:
113				break;
114		}
115	}
116	// execute the request
117	if (result == B_OK) {
118		PRINT(("notify_listener(%ld, %ld, %Ld, %Ld, %Ld, `%s')\n",
119			request->operation, request->nsid, request->vnida, request->vnidb,
120			request->vnidc, name));
121		result = notify_listener(request->operation, request->nsid,
122			request->vnida, request->vnidb, request->vnidc, name);
123	}
124	// prepare the reply
125	RequestAllocator allocator(fPort->GetPort());
126	NotifyListenerReply* reply;
127	status_t error = AllocateRequest(allocator, &reply);
128	if (error != B_OK)
129		return error;
130	reply->error = result;
131	// send the reply
132	return fPort->SendRequest(&allocator);
133}
134
135// _HandleRequest
136status_t
137KernelRequestHandler::_HandleRequest(NotifySelectEventRequest* request)
138{
139	// check and executed the request
140	status_t result = B_OK;
141	if (fFileSystem->KnowsSelectSyncEntry(request->sync)) {
142		PRINT(("notify_select_event(%p, %lu)\n", request->sync, request->ref));
143		notify_select_event(request->sync, request->ref);
144	} else
145		result = B_BAD_VALUE;
146	// prepare the reply
147	RequestAllocator allocator(fPort->GetPort());
148	NotifySelectEventReply* reply;
149	status_t error = AllocateRequest(allocator, &reply);
150	if (error != B_OK)
151		return error;
152	reply->error = result;
153	// send the reply
154	return fPort->SendRequest(&allocator);
155}
156
157// _HandleRequest
158status_t
159KernelRequestHandler::_HandleRequest(SendNotificationRequest* request)
160{
161	// check and executed the request
162	status_t result = B_OK;
163	if (fVolume && request->nsida != fVolume->GetID()
164		&& request->nsidb != fVolume->GetID()) {
165		result = B_BAD_VALUE;
166	}
167	// check the name
168	char* name = (char*)request->name.GetData();
169	int32 nameLen = request->name.GetSize();
170	if (name && (nameLen <= 0 || strnlen(name, nameLen) < 1))
171		name = NULL;
172	else if (name)
173		name[nameLen - 1] = '\0';
174	if (!name) {
175		switch (request->operation) {
176			case B_ENTRY_CREATED:
177			case B_ENTRY_MOVED:
178				ERROR(("send_notification(): NULL name for opcode: %ld\n",
179					request->operation));
180				result = B_BAD_VALUE;
181				break;
182			case B_ENTRY_REMOVED:
183				break;
184		}
185	}
186	// execute the request
187	if (result == B_OK) {
188		PRINT(("send_notification(%ld, %ld, %lu, %ld, %ld, %ld, %Ld, %Ld, %Ld, "
189			"`%s')\n", request->port, request->token, request->what,
190			request->operation, request->nsida, request->nsidb, request->vnida,
191			request->vnidb, request->vnidc, name));
192		result = send_notification(request->port, request->token, request->what,
193			request->operation, request->nsida, request->nsidb, request->vnida,
194			request->vnidb, request->vnidc, name);
195	}
196	// prepare the reply
197	RequestAllocator allocator(fPort->GetPort());
198	SendNotificationReply* reply;
199	status_t error = AllocateRequest(allocator, &reply);
200	if (error != B_OK)
201		return error;
202	reply->error = result;
203	// send the reply
204	return fPort->SendRequest(&allocator);
205}
206
207// #pragma mark -
208// #pragma mark ----- vnodes -----
209
210// _HandleRequest
211status_t
212KernelRequestHandler::_HandleRequest(GetVNodeRequest* request)
213{
214	// check and executed the request
215	Volume* volume = NULL;
216	status_t result = _GetVolume(request->nsid, &volume);
217	VolumePutter _(volume);
218	void* node;
219	if (result == B_OK)
220		result = volume->GetVNode(request->vnid, &node);
221	// prepare the reply
222	RequestAllocator allocator(fPort->GetPort());
223	GetVNodeReply* reply;
224	status_t error = AllocateRequest(allocator, &reply);
225	if (error != B_OK)
226		return error;
227	reply->error = result;
228	reply->node = node;
229	// send the reply
230	return fPort->SendRequest(&allocator);
231}
232
233// _HandleRequest
234status_t
235KernelRequestHandler::_HandleRequest(PutVNodeRequest* request)
236{
237	// check and executed the request
238	Volume* volume = NULL;
239	status_t result = _GetVolume(request->nsid, &volume);
240	VolumePutter _(volume);
241	if (result == B_OK)
242		result = volume->PutVNode(request->vnid);
243	// prepare the reply
244	RequestAllocator allocator(fPort->GetPort());
245	PutVNodeReply* reply;
246	status_t error = AllocateRequest(allocator, &reply);
247	if (error != B_OK)
248		return error;
249	reply->error = result;
250	// send the reply
251	return fPort->SendRequest(&allocator);
252}
253
254// _HandleRequest
255status_t
256KernelRequestHandler::_HandleRequest(NewVNodeRequest* request)
257{
258	// check and executed the request
259	Volume* volume = NULL;
260	status_t result = _GetVolume(request->nsid, &volume);
261	VolumePutter _(volume);
262	if (result == B_OK)
263		result = volume->NewVNode(request->vnid, request->node);
264	// prepare the reply
265	RequestAllocator allocator(fPort->GetPort());
266	NewVNodeReply* reply;
267	status_t error = AllocateRequest(allocator, &reply);
268	if (error != B_OK)
269		return error;
270	reply->error = result;
271	// send the reply
272	return fPort->SendRequest(&allocator);
273}
274
275// _HandleRequest
276status_t
277KernelRequestHandler::_HandleRequest(RemoveVNodeRequest* request)
278{
279	// check and executed the request
280	Volume* volume = NULL;
281	status_t result = _GetVolume(request->nsid, &volume);
282	VolumePutter _(volume);
283	if (result == B_OK)
284		result = volume->RemoveVNode(request->vnid);
285	// prepare the reply
286	RequestAllocator allocator(fPort->GetPort());
287	RemoveVNodeReply* reply;
288	status_t error = AllocateRequest(allocator, &reply);
289	if (error != B_OK)
290		return error;
291	reply->error = result;
292	// send the reply
293	return fPort->SendRequest(&allocator);
294}
295
296// _HandleRequest
297status_t
298KernelRequestHandler::_HandleRequest(UnremoveVNodeRequest* request)
299{
300	// check and executed the request
301	Volume* volume = NULL;
302	status_t result = _GetVolume(request->nsid, &volume);
303	VolumePutter _(volume);
304	if (result == B_OK)
305		result = volume->UnremoveVNode(request->vnid);
306	// prepare the reply
307	RequestAllocator allocator(fPort->GetPort());
308	UnremoveVNodeReply* reply;
309	status_t error = AllocateRequest(allocator, &reply);
310	if (error != B_OK)
311		return error;
312	reply->error = result;
313	// send the reply
314	return fPort->SendRequest(&allocator);
315}
316
317// _HandleRequest
318status_t
319KernelRequestHandler::_HandleRequest(IsVNodeRemovedRequest* request)
320{
321	// check and executed the request
322	Volume* volume = NULL;
323	status_t result = _GetVolume(request->nsid, &volume);
324	VolumePutter _(volume);
325	if (result == B_OK)
326		result = volume->IsVNodeRemoved(request->vnid);
327	// prepare the reply
328	RequestAllocator allocator(fPort->GetPort());
329	IsVNodeRemovedReply* reply;
330	status_t error = AllocateRequest(allocator, &reply);
331	if (error != B_OK)
332		return error;
333	reply->error = (result < 0 ? result : B_OK);
334	reply->result = result;
335	// send the reply
336	return fPort->SendRequest(&allocator);
337}
338
339// _GetVolume
340status_t
341KernelRequestHandler::_GetVolume(nspace_id id, Volume** volume)
342{
343	if (fVolume) {
344		if (fVolume->GetID() != id) {
345			*volume = NULL;
346			return B_BAD_VALUE;
347		}
348		fVolume->AddReference();
349		*volume = fVolume;
350		return B_OK;
351	}
352	*volume = fFileSystem->GetVolume(id);
353	return (*volume ? B_OK : B_BAD_VALUE);
354}
355
356