xref: /haiku/src/add-ons/kernel/file_systems/userlandfs/server/kernel_emu.cpp (revision a127b88ecbfab58f64944c98aa47722a18e363b2)
1 // kernel_emu.cpp
2 
3 #include "kernel_emu.h"
4 
5 #include <stdarg.h>
6 #include <stdio.h>
7 #include <stdlib.h>
8 
9 #include <algorithm>
10 
11 #include "FileSystem.h"
12 #include "RequestPort.h"
13 #include "Requests.h"
14 #include "RequestThread.h"
15 #include "UserlandFSServer.h"
16 #include "UserlandRequestHandler.h"
17 #include "Volume.h"
18 
19 
20 // Taken from the Haiku Storage Kit (storage_support.cpp)
21 /*! The length of the first component is returned as well as the index at
22 	which the next one starts. These values are only valid, if the function
23 	returns \c B_OK.
24 	\param path the path to be parsed
25 	\param length the variable the length of the first component is written
26 		   into
27 	\param nextComponent the variable the index of the next component is
28 		   written into. \c 0 is returned, if there is no next component.
29 	\return \c B_OK, if \a path is not \c NULL, \c B_BAD_VALUE otherwise
30 */
31 static status_t
32 parse_first_path_component(const char *path, int32& length,
33 						   int32& nextComponent)
34 {
35 	status_t error = (path ? B_OK : B_BAD_VALUE);
36 	if (error == B_OK) {
37 		int32 i = 0;
38 		// find first '/' or end of name
39 		for (; path[i] != '/' && path[i] != '\0'; i++);
40 		// handle special case "/..." (absolute path)
41 		if (i == 0 && path[i] != '\0')
42 			i = 1;
43 		length = i;
44 		// find last '/' or end of name
45 		for (; path[i] == '/' && path[i] != '\0'; i++);
46 		if (path[i] == '\0')	// this covers "" as well
47 			nextComponent = 0;
48 		else
49 			nextComponent = i;
50 	}
51 	return error;
52 }
53 
54 // new_path
55 int
56 UserlandFS::KernelEmu::new_path(const char *path, char **copy)
57 {
58 	// check errors and special cases
59 	if (!copy)
60 		return B_BAD_VALUE;
61 	if (!path) {
62 		*copy = NULL;
63 		return B_OK;
64 	}
65 	int32 len = strlen(path);
66 	if (len < 1)
67 		return B_ENTRY_NOT_FOUND;
68 	bool appendDot = (path[len - 1] == '/');
69 	if (appendDot)
70 		len++;
71 	if (len >= B_PATH_NAME_LENGTH)
72 		return B_NAME_TOO_LONG;
73 	// check the path components
74 	const char *remainder = path;
75 	int32 length, nextComponent;
76 	do {
77 		status_t error
78 			= parse_first_path_component(remainder, length, nextComponent);
79 		if (error != B_OK)
80 			return error;
81 		if (length >= B_FILE_NAME_LENGTH)
82 			error = B_NAME_TOO_LONG;
83 		remainder += nextComponent;
84 	} while (nextComponent != 0);
85 	// clone the path
86 	char *copiedPath = (char*)malloc(len + 1);
87 	if (!copiedPath)
88 		return B_NO_MEMORY;
89 	strcpy(copiedPath, path);
90 	// append a dot, if desired
91 	if (appendDot) {
92 		copiedPath[len - 1] = '.';
93 		copiedPath[len] = '\0';
94 	}
95 	*copy = copiedPath;
96 	return B_OK;
97 }
98 
99 // free_path
100 void
101 UserlandFS::KernelEmu::free_path(char *p)
102 {
103 	free(p);
104 }
105 
106 
107 // #pragma mark -
108 
109 
110 // get_port_and_fs
111 static status_t
112 get_port_and_fs(RequestPort** port, FileSystem** fileSystem)
113 {
114 	// get the request thread
115 	RequestThread* thread = RequestThread::GetCurrentThread();
116 	if (thread) {
117 		*port = thread->GetPort();
118 		*fileSystem = thread->GetFileSystem();
119 	} else {
120 		*port = UserlandFSServer::GetNotificationRequestPort();
121 		*fileSystem = UserlandFSServer::GetFileSystem();
122 		if (!*port || !*fileSystem)
123 			return B_BAD_VALUE;
124 	}
125 	return B_OK;
126 }
127 
128 // notify_listener
129 status_t
130 UserlandFS::KernelEmu::notify_listener(int32 operation, uint32 details,
131 	dev_t device, ino_t oldDirectory, ino_t directory,
132 	ino_t node, const char* oldName, const char* name)
133 {
134 	// get the request port and the file system
135 	RequestPort* port;
136 	FileSystem* fileSystem;
137 	status_t error = get_port_and_fs(&port, &fileSystem);
138 	if (error != B_OK)
139 		return error;
140 
141 	// prepare the request
142 	RequestAllocator allocator(port->GetPort());
143 	NotifyListenerRequest* request;
144 	error = AllocateRequest(allocator, &request);
145 	if (error != B_OK)
146 		return error;
147 
148 	request->operation = operation;
149 	request->details = details;
150 	request->device = device;
151 	request->oldDirectory = oldDirectory;
152 	request->directory = directory;
153 	request->node = node;
154 	error = allocator.AllocateString(request->oldName, oldName);
155 	if (error != B_OK)
156 		return error;
157 	error = allocator.AllocateString(request->name, name);
158 	if (error != B_OK)
159 		return error;
160 
161 	// send the request
162 	UserlandRequestHandler handler(fileSystem, NOTIFY_LISTENER_REPLY);
163 	NotifyListenerReply* reply;
164 	error = port->SendRequest(&allocator, &handler, (Request**)&reply);
165 	if (error != B_OK)
166 		return error;
167 	RequestReleaser requestReleaser(port, reply);
168 
169 	// process the reply
170 	if (reply->error != B_OK)
171 		return reply->error;
172 	return error;
173 }
174 
175 // notify_select_event
176 status_t
177 UserlandFS::KernelEmu::notify_select_event(selectsync *sync, uint8 event,
178 	bool unspecifiedEvent)
179 {
180 	// get the request port and the file system
181 	RequestPort* port;
182 	FileSystem* fileSystem;
183 	status_t error = get_port_and_fs(&port, &fileSystem);
184 	if (error != B_OK)
185 		return error;
186 
187 	// prepare the request
188 	RequestAllocator allocator(port->GetPort());
189 	NotifySelectEventRequest* request;
190 	error = AllocateRequest(allocator, &request);
191 	if (error != B_OK)
192 		return error;
193 
194 	request->sync = sync;
195 	request->event = event;
196 	request->unspecifiedEvent = unspecifiedEvent;
197 
198 	// send the request
199 	UserlandRequestHandler handler(fileSystem, NOTIFY_SELECT_EVENT_REPLY);
200 	NotifySelectEventReply* reply;
201 	error = port->SendRequest(&allocator, &handler, (Request**)&reply);
202 	if (error != B_OK)
203 		return error;
204 	RequestReleaser requestReleaser(port, reply);
205 
206 	// process the reply
207 	if (reply->error != B_OK)
208 		return reply->error;
209 	return error;
210 }
211 
212 // send_notification
213 status_t
214 UserlandFS::KernelEmu::notify_query(port_id targetPort, int32 token,
215 	int32 operation, dev_t device, ino_t directory, const char* name,
216 	ino_t node)
217 {
218 	// get the request port and the file system
219 	RequestPort* port;
220 	FileSystem* fileSystem;
221 	status_t error = get_port_and_fs(&port, &fileSystem);
222 	if (error != B_OK)
223 		return error;
224 
225 	// prepare the request
226 	RequestAllocator allocator(port->GetPort());
227 	NotifyQueryRequest* request;
228 	error = AllocateRequest(allocator, &request);
229 	if (error != B_OK)
230 		return error;
231 
232 	request->port = targetPort;
233 	request->token = token;
234 	request->operation = operation;
235 	request->device = device;
236 	request->directory = directory;
237 	request->node = node;
238 	error = allocator.AllocateString(request->name, name);
239 	if (error != B_OK)
240 		return error;
241 
242 	// send the request
243 	UserlandRequestHandler handler(fileSystem, NOTIFY_QUERY_REPLY);
244 	NotifyQueryReply* reply;
245 	error = port->SendRequest(&allocator, &handler, (Request**)&reply);
246 	if (error != B_OK)
247 		return error;
248 	RequestReleaser requestReleaser(port, reply);
249 
250 	// process the reply
251 	if (reply->error != B_OK)
252 		return reply->error;
253 	return error;
254 }
255 
256 
257 // #pragma mark -
258 
259 
260 // get_vnode
261 status_t
262 UserlandFS::KernelEmu::get_vnode(dev_t nsid, ino_t vnid, void** node)
263 {
264 	// get the request port and the file system
265 	RequestPort* port;
266 	FileSystem* fileSystem;
267 	status_t error = get_port_and_fs(&port, &fileSystem);
268 	if (error != B_OK)
269 		return error;
270 
271 	// prepare the request
272 	RequestAllocator allocator(port->GetPort());
273 	GetVNodeRequest* request;
274 	error = AllocateRequest(allocator, &request);
275 	if (error != B_OK)
276 		return error;
277 
278 	request->nsid = nsid;
279 	request->vnid = vnid;
280 
281 	// send the request
282 	UserlandRequestHandler handler(fileSystem, GET_VNODE_REPLY);
283 	GetVNodeReply* reply;
284 	error = port->SendRequest(&allocator, &handler, (Request**)&reply);
285 	if (error != B_OK)
286 		return error;
287 	RequestReleaser requestReleaser(port, reply);
288 
289 	// process the reply
290 	if (reply->error != B_OK)
291 		return reply->error;
292 	*node = reply->node;
293 	return error;
294 }
295 
296 // put_vnode
297 status_t
298 UserlandFS::KernelEmu::put_vnode(dev_t nsid, ino_t vnid)
299 {
300 	// get the request port and the file system
301 	RequestPort* port;
302 	FileSystem* fileSystem;
303 	status_t error = get_port_and_fs(&port, &fileSystem);
304 	if (error != B_OK)
305 		return error;
306 
307 	// prepare the request
308 	RequestAllocator allocator(port->GetPort());
309 	PutVNodeRequest* request;
310 	error = AllocateRequest(allocator, &request);
311 	if (error != B_OK)
312 		return error;
313 
314 	request->nsid = nsid;
315 	request->vnid = vnid;
316 
317 	// send the request
318 	UserlandRequestHandler handler(fileSystem, PUT_VNODE_REPLY);
319 	PutVNodeReply* reply;
320 	error = port->SendRequest(&allocator, &handler, (Request**)&reply);
321 	if (error != B_OK)
322 		return error;
323 	RequestReleaser requestReleaser(port, reply);
324 
325 	// process the reply
326 	if (reply->error != B_OK)
327 		return reply->error;
328 	return error;
329 }
330 
331 // acquire_vnode
332 status_t
333 UserlandFS::KernelEmu::acquire_vnode(dev_t nsid, ino_t vnid)
334 {
335 	// get the request port and the file system
336 	RequestPort* port;
337 	FileSystem* fileSystem;
338 	status_t error = get_port_and_fs(&port, &fileSystem);
339 	if (error != B_OK)
340 		return error;
341 
342 	// prepare the request
343 	RequestAllocator allocator(port->GetPort());
344 	AcquireVNodeRequest* request;
345 	error = AllocateRequest(allocator, &request);
346 	if (error != B_OK)
347 		return error;
348 
349 	request->nsid = nsid;
350 	request->vnid = vnid;
351 
352 	// send the request
353 	UserlandRequestHandler handler(fileSystem, ACQUIRE_VNODE_REPLY);
354 	AcquireVNodeReply* reply;
355 	error = port->SendRequest(&allocator, &handler, (Request**)&reply);
356 	if (error != B_OK)
357 		return error;
358 	RequestReleaser requestReleaser(port, reply);
359 
360 	// process the reply
361 	if (reply->error != B_OK)
362 		return reply->error;
363 	return error;
364 }
365 
366 // new_vnode
367 status_t
368 UserlandFS::KernelEmu::new_vnode(dev_t nsid, ino_t vnid, void* data,
369 	const FSVNodeCapabilities& capabilities)
370 {
371 	// get the request port and the file system
372 	RequestPort* port;
373 	FileSystem* fileSystem;
374 	status_t error = get_port_and_fs(&port, &fileSystem);
375 	if (error != B_OK)
376 		return error;
377 
378 	// prepare the request
379 	RequestAllocator allocator(port->GetPort());
380 	NewVNodeRequest* request;
381 	error = AllocateRequest(allocator, &request);
382 	if (error != B_OK)
383 		return error;
384 
385 	request->nsid = nsid;
386 	request->vnid = vnid;
387 	request->node = data;
388 	request->capabilities = capabilities;
389 
390 	// send the request
391 	UserlandRequestHandler handler(fileSystem, NEW_VNODE_REPLY);
392 	NewVNodeReply* reply;
393 	error = port->SendRequest(&allocator, &handler, (Request**)&reply);
394 	if (error != B_OK)
395 		return error;
396 	RequestReleaser requestReleaser(port, reply);
397 
398 	// process the reply
399 	if (reply->error != B_OK)
400 		return reply->error;
401 	return error;
402 }
403 
404 // publish_vnode
405 status_t
406 UserlandFS::KernelEmu::publish_vnode(dev_t nsid, ino_t vnid, void* data,
407 	int type, uint32 flags, const FSVNodeCapabilities& capabilities)
408 {
409 	// get the request port and the file system
410 	RequestPort* port;
411 	FileSystem* fileSystem;
412 	status_t error = get_port_and_fs(&port, &fileSystem);
413 	if (error != B_OK)
414 		return error;
415 
416 	// prepare the request
417 	RequestAllocator allocator(port->GetPort());
418 	PublishVNodeRequest* request;
419 	error = AllocateRequest(allocator, &request);
420 	if (error != B_OK)
421 		return error;
422 
423 	request->nsid = nsid;
424 	request->vnid = vnid;
425 	request->node = data;
426 	request->type = type;
427 	request->flags = flags;
428 	request->capabilities = capabilities;
429 
430 	// send the request
431 	UserlandRequestHandler handler(fileSystem, PUBLISH_VNODE_REPLY);
432 	PublishVNodeReply* reply;
433 	error = port->SendRequest(&allocator, &handler, (Request**)&reply);
434 	if (error != B_OK)
435 		return error;
436 	RequestReleaser requestReleaser(port, reply);
437 
438 	// process the reply
439 	if (reply->error != B_OK)
440 		return reply->error;
441 	return error;
442 }
443 
444 
445 // publish_vnode
446 status_t
447 UserlandFS::KernelEmu::publish_vnode(dev_t nsid, ino_t vnid, void* data,
448 	const FSVNodeCapabilities& capabilities)
449 {
450 	// get the volume
451 	Volume* volume = FileSystem::GetInstance()->VolumeWithID(nsid);
452 	if (volume == NULL)
453 		return B_BAD_VALUE;
454 
455 	// stat() the node to get its type
456 	int type;
457 	status_t error = volume->GetVNodeType(data, &type);
458 	if (error != B_OK)
459 		return error;
460 
461 	// publish the node
462 	return UserlandFS::KernelEmu::publish_vnode(nsid, vnid, data, type, 0,
463 		capabilities);
464 }
465 
466 
467 // remove_vnode
468 status_t
469 UserlandFS::KernelEmu::remove_vnode(dev_t nsid, ino_t vnid)
470 {
471 	// get the request port and the file system
472 	RequestPort* port;
473 	FileSystem* fileSystem;
474 	status_t error = get_port_and_fs(&port, &fileSystem);
475 	if (error != B_OK)
476 		return error;
477 
478 	// prepare the request
479 	RequestAllocator allocator(port->GetPort());
480 	RemoveVNodeRequest* request;
481 	error = AllocateRequest(allocator, &request);
482 	if (error != B_OK)
483 		return error;
484 
485 	request->nsid = nsid;
486 	request->vnid = vnid;
487 
488 	// send the request
489 	UserlandRequestHandler handler(fileSystem, REMOVE_VNODE_REPLY);
490 	RemoveVNodeReply* reply;
491 	error = port->SendRequest(&allocator, &handler, (Request**)&reply);
492 	if (error != B_OK)
493 		return error;
494 	RequestReleaser requestReleaser(port, reply);
495 
496 	// process the reply
497 	if (reply->error != B_OK)
498 		return reply->error;
499 	return error;
500 }
501 
502 // unremove_vnode
503 status_t
504 UserlandFS::KernelEmu::unremove_vnode(dev_t nsid, ino_t vnid)
505 {
506 	// get the request port and the file system
507 	RequestPort* port;
508 	FileSystem* fileSystem;
509 	status_t error = get_port_and_fs(&port, &fileSystem);
510 	if (error != B_OK)
511 		return error;
512 
513 	// prepare the request
514 	RequestAllocator allocator(port->GetPort());
515 	UnremoveVNodeRequest* request;
516 	error = AllocateRequest(allocator, &request);
517 	if (error != B_OK)
518 		return error;
519 
520 	request->nsid = nsid;
521 	request->vnid = vnid;
522 
523 	// send the request
524 	UserlandRequestHandler handler(fileSystem, UNREMOVE_VNODE_REPLY);
525 	UnremoveVNodeReply* reply;
526 	error = port->SendRequest(&allocator, &handler, (Request**)&reply);
527 	if (error != B_OK)
528 		return error;
529 	RequestReleaser requestReleaser(port, reply);
530 
531 	// process the reply
532 	if (reply->error != B_OK)
533 		return reply->error;
534 	return error;
535 }
536 
537 // get_vnode_removed
538 status_t
539 UserlandFS::KernelEmu::get_vnode_removed(dev_t nsid, ino_t vnid,
540 	bool* removed)
541 {
542 	// get the request port and the file system
543 	RequestPort* port;
544 	FileSystem* fileSystem;
545 	status_t error = get_port_and_fs(&port, &fileSystem);
546 	if (error != B_OK)
547 		return error;
548 
549 	// prepare the request
550 	RequestAllocator allocator(port->GetPort());
551 	GetVNodeRemovedRequest* request;
552 	error = AllocateRequest(allocator, &request);
553 	if (error != B_OK)
554 		return error;
555 
556 	request->nsid = nsid;
557 	request->vnid = vnid;
558 
559 	// send the request
560 	UserlandRequestHandler handler(fileSystem, GET_VNODE_REMOVED_REPLY);
561 	GetVNodeRemovedReply* reply;
562 	error = port->SendRequest(&allocator, &handler, (Request**)&reply);
563 	if (error != B_OK)
564 		return error;
565 	RequestReleaser requestReleaser(port, reply);
566 
567 	// process the reply
568 	*removed = reply->removed;
569 	return reply->error;
570 }
571 
572 
573 // #pragma mark - file cache
574 
575 
576 // file_cache_create
577 status_t
578 UserlandFS::KernelEmu::file_cache_create(dev_t mountID, ino_t vnodeID,
579 	off_t size)
580 {
581 	// get the request port and the file system
582 	RequestPort* port;
583 	FileSystem* fileSystem;
584 	status_t error = get_port_and_fs(&port, &fileSystem);
585 	if (error != B_OK)
586 		RETURN_ERROR(error);
587 
588 	// prepare the request
589 	RequestAllocator allocator(port->GetPort());
590 	FileCacheCreateRequest* request;
591 	error = AllocateRequest(allocator, &request);
592 	if (error != B_OK)
593 		RETURN_ERROR(error);
594 
595 	request->nsid = mountID;
596 	request->vnid = vnodeID;
597 	request->size = size;
598 
599 	// send the request
600 	UserlandRequestHandler handler(fileSystem, FILE_CACHE_CREATE_REPLY);
601 	FileCacheCreateReply* reply;
602 	error = port->SendRequest(&allocator, &handler, (Request**)&reply);
603 	if (error != B_OK)
604 		RETURN_ERROR(error);
605 	RequestReleaser requestReleaser(port, reply);
606 
607 	// process the reply
608 	RETURN_ERROR(reply->error);
609 }
610 
611 
612 // file_cache_delete
613 status_t
614 UserlandFS::KernelEmu::file_cache_delete(dev_t mountID, ino_t vnodeID)
615 {
616 	// get the request port and the file system
617 	RequestPort* port;
618 	FileSystem* fileSystem;
619 	status_t error = get_port_and_fs(&port, &fileSystem);
620 	if (error != B_OK)
621 		return error;
622 
623 	// prepare the request
624 	RequestAllocator allocator(port->GetPort());
625 	FileCacheDeleteRequest* request;
626 	error = AllocateRequest(allocator, &request);
627 	if (error != B_OK)
628 		return error;
629 
630 	request->nsid = mountID;
631 	request->vnid = vnodeID;
632 
633 	// send the request
634 	UserlandRequestHandler handler(fileSystem, FILE_CACHE_DELETE_REPLY);
635 	FileCacheDeleteReply* reply;
636 	error = port->SendRequest(&allocator, &handler, (Request**)&reply);
637 	if (error != B_OK)
638 		return error;
639 	RequestReleaser requestReleaser(port, reply);
640 
641 	// process the reply
642 	return reply->error;
643 }
644 
645 
646 // file_cache_set_enable
647 status_t
648 UserlandFS::KernelEmu::file_cache_set_enabled(dev_t mountID, ino_t vnodeID,
649 	bool enabled)
650 {
651 	// get the request port and the file system
652 	RequestPort* port;
653 	FileSystem* fileSystem;
654 	status_t error = get_port_and_fs(&port, &fileSystem);
655 	if (error != B_OK)
656 		return error;
657 
658 	// prepare the request
659 	RequestAllocator allocator(port->GetPort());
660 	FileCacheSetEnabledRequest* request;
661 	error = AllocateRequest(allocator, &request);
662 	if (error != B_OK)
663 		return error;
664 
665 	request->nsid = mountID;
666 	request->vnid = vnodeID;
667 	request->enabled = enabled;
668 
669 	// send the request
670 	UserlandRequestHandler handler(fileSystem, FILE_CACHE_SET_ENABLED_REPLY);
671 	FileCacheSetEnabledReply* reply;
672 	error = port->SendRequest(&allocator, &handler, (Request**)&reply);
673 	if (error != B_OK)
674 		return error;
675 	RequestReleaser requestReleaser(port, reply);
676 
677 	// process the reply
678 	return reply->error;
679 }
680 
681 
682 // file_cache_set_size
683 status_t
684 UserlandFS::KernelEmu::file_cache_set_size(dev_t mountID, ino_t vnodeID,
685 	off_t size)
686 {
687 	// get the request port and the file system
688 	RequestPort* port;
689 	FileSystem* fileSystem;
690 	status_t error = get_port_and_fs(&port, &fileSystem);
691 	if (error != B_OK)
692 		return error;
693 
694 	// prepare the request
695 	RequestAllocator allocator(port->GetPort());
696 	FileCacheSetSizeRequest* request;
697 	error = AllocateRequest(allocator, &request);
698 	if (error != B_OK)
699 		return error;
700 
701 	request->nsid = mountID;
702 	request->vnid = vnodeID;
703 	request->size = size;
704 
705 	// send the request
706 	UserlandRequestHandler handler(fileSystem, FILE_CACHE_SET_SIZE_REPLY);
707 	FileCacheSetSizeReply* reply;
708 	error = port->SendRequest(&allocator, &handler, (Request**)&reply);
709 	if (error != B_OK)
710 		return error;
711 	RequestReleaser requestReleaser(port, reply);
712 
713 	// process the reply
714 	return reply->error;
715 }
716 
717 
718 // file_cache_sync
719 status_t
720 UserlandFS::KernelEmu::file_cache_sync(dev_t mountID, ino_t vnodeID)
721 {
722 	// get the request port and the file system
723 	RequestPort* port;
724 	FileSystem* fileSystem;
725 	status_t error = get_port_and_fs(&port, &fileSystem);
726 	if (error != B_OK)
727 		return error;
728 
729 	// prepare the request
730 	RequestAllocator allocator(port->GetPort());
731 	FileCacheSyncRequest* request;
732 	error = AllocateRequest(allocator, &request);
733 	if (error != B_OK)
734 		return error;
735 
736 	request->nsid = mountID;
737 	request->vnid = vnodeID;
738 
739 	// send the request
740 	UserlandRequestHandler handler(fileSystem, FILE_CACHE_SYNC_REPLY);
741 	FileCacheSyncReply* reply;
742 	error = port->SendRequest(&allocator, &handler, (Request**)&reply);
743 	if (error != B_OK)
744 		return error;
745 	RequestReleaser requestReleaser(port, reply);
746 
747 	// process the reply
748 	return reply->error;
749 }
750 
751 
752 // file_cache_read
753 status_t
754 UserlandFS::KernelEmu::file_cache_read(dev_t mountID, ino_t vnodeID,
755 	void *cookie, off_t offset, void *bufferBase, size_t *_size)
756 {
757 	// get the request port and the file system
758 	RequestPort* port;
759 	FileSystem* fileSystem;
760 	status_t error = get_port_and_fs(&port, &fileSystem);
761 	if (error != B_OK)
762 		return error;
763 
764 	// prepare the request
765 	RequestAllocator allocator(port->GetPort());
766 	FileCacheReadRequest* request;
767 	error = AllocateRequest(allocator, &request);
768 	if (error != B_OK)
769 		return error;
770 
771 	request->nsid = mountID;
772 	request->vnid = vnodeID;
773 	request->cookie = cookie;
774 	request->pos = offset;
775 	request->size = *_size;
776 
777 	// send the request
778 	UserlandRequestHandler handler(fileSystem, FILE_CACHE_READ_REPLY);
779 	FileCacheReadReply* reply;
780 	error = port->SendRequest(&allocator, &handler, (Request**)&reply);
781 	if (error != B_OK)
782 		return error;
783 	RequestReleaser requestReleaser(port, reply);
784 
785 	// process the reply
786 	if (reply->error != B_OK)
787 		return reply->error;
788 
789 	if (reply->bytesRead > 0) {
790 		memcpy(bufferBase, reply->buffer.GetData(), reply->buffer.GetSize());
791 
792 		// send receipt-ack
793 		RequestAllocator receiptAckAllocator(port->GetPort());
794 		ReceiptAckReply* receiptAck;
795 		if (AllocateRequest(receiptAckAllocator, &receiptAck) == B_OK)
796 			port->SendRequest(&receiptAckAllocator);
797 	}
798 
799 	*_size = reply->bytesRead;
800 
801 	return B_OK;
802 }
803 
804 
805 // file_cache_write
806 status_t
807 UserlandFS::KernelEmu::file_cache_write(dev_t mountID, ino_t vnodeID,
808 	void *cookie, off_t offset, const void *buffer, size_t *_size)
809 {
810 	// get the request port and the file system
811 	RequestPort* port;
812 	FileSystem* fileSystem;
813 	status_t error = get_port_and_fs(&port, &fileSystem);
814 	if (error != B_OK)
815 		return error;
816 
817 	// prepare the request
818 	RequestAllocator allocator(port->GetPort());
819 	FileCacheWriteRequest* request;
820 	error = AllocateRequest(allocator, &request);
821 	if (error != B_OK)
822 		return error;
823 
824 	request->nsid = mountID;
825 	request->vnid = vnodeID;
826 	request->cookie = cookie;
827 	request->size = *_size;
828 	request->pos = offset;
829 
830 	if (buffer != NULL) {
831 		error = allocator.AllocateData(request->buffer, buffer, *_size, 1,
832 			false);
833 		if (error != B_OK)
834 			return error;
835 	}
836 
837 	// send the request
838 	UserlandRequestHandler handler(fileSystem, FILE_CACHE_WRITE_REPLY);
839 	FileCacheWriteReply* reply;
840 	error = port->SendRequest(&allocator, &handler, (Request**)&reply);
841 	if (error != B_OK)
842 		return error;
843 	RequestReleaser requestReleaser(port, reply);
844 
845 	// process the reply
846 	*_size = reply->bytesWritten;
847 	return reply->error;
848 }
849 
850 
851 // #pragma mark - I/O
852 
853 
854 status_t
855 UserlandFS::KernelEmu::do_iterative_fd_io(dev_t volumeID, int fd,
856 	int32 requestID, void* cookie, const file_io_vec* vecs, uint32 vecCount)
857 {
858 	// get the request port and the file system
859 	RequestPort* port;
860 	FileSystem* fileSystem;
861 	status_t error = get_port_and_fs(&port, &fileSystem);
862 	if (error != B_OK)
863 		return error;
864 
865 	// prepare the request
866 	RequestAllocator allocator(port->GetPort());
867 	DoIterativeFDIORequest* request;
868 	error = AllocateRequest(allocator, &request);
869 	if (error != B_OK)
870 		return error;
871 
872 	request->nsid = volumeID;
873 	request->fd = fd;
874 	request->request = requestID;
875 	request->cookie = cookie;
876 
877 	if (vecCount > 0) {
878 		vecCount = std::min(vecCount, (uint32)DoIterativeFDIORequest::MAX_VECS);
879 		memcpy(request->vecs, vecs, sizeof(file_io_vec) * vecCount);
880 	}
881 	request->vecCount = vecCount;
882 
883 	// send the request
884 	UserlandRequestHandler handler(fileSystem, DO_ITERATIVE_FD_IO_REPLY);
885 	DoIterativeFDIOReply* reply;
886 	error = port->SendRequest(&allocator, &handler, (Request**)&reply);
887 	if (error != B_OK)
888 		return error;
889 // TODO: Up to this point we should call the finished hook on error!
890 	RequestReleaser requestReleaser(port, reply);
891 
892 	// process the reply
893 	return reply->error;
894 }
895 
896 
897 status_t
898 UserlandFS::KernelEmu::read_from_io_request(dev_t volumeID, int32 requestID,
899 	void* buffer, size_t size)
900 {
901 	// get the request port and the file system
902 	RequestPort* port;
903 	FileSystem* fileSystem;
904 	status_t error = get_port_and_fs(&port, &fileSystem);
905 	if (error != B_OK)
906 		return error;
907 
908 	// prepare the request
909 	RequestAllocator allocator(port->GetPort());
910 	ReadFromIORequestRequest* request;
911 	error = AllocateRequest(allocator, &request);
912 	if (error != B_OK)
913 		return error;
914 
915 	request->nsid = volumeID;
916 	request->request = requestID;
917 	request->size = size;
918 
919 	// send the request
920 	UserlandRequestHandler handler(fileSystem, READ_FROM_IO_REQUEST_REPLY);
921 	ReadFromIORequestReply* reply;
922 	error = port->SendRequest(&allocator, &handler, (Request**)&reply);
923 	if (error != B_OK)
924 		return error;
925 	RequestReleaser requestReleaser(port, reply);
926 
927 	// process the reply
928 	if (reply->error != B_OK)
929 		return reply->error;
930 
931 	memcpy(buffer, reply->buffer.GetData(), reply->buffer.GetSize());
932 
933 	// send receipt-ack
934 	RequestAllocator receiptAckAllocator(port->GetPort());
935 	ReceiptAckReply* receiptAck;
936 	if (AllocateRequest(receiptAckAllocator, &receiptAck) == B_OK)
937 		port->SendRequest(&receiptAckAllocator);
938 
939 	return B_OK;
940 }
941 
942 
943 status_t
944 UserlandFS::KernelEmu::write_to_io_request(dev_t volumeID, int32 requestID,
945 	const void* buffer, size_t size)
946 {
947 	// get the request port and the file system
948 	RequestPort* port;
949 	FileSystem* fileSystem;
950 	status_t error = get_port_and_fs(&port, &fileSystem);
951 	if (error != B_OK)
952 		return error;
953 
954 	// prepare the request
955 	RequestAllocator allocator(port->GetPort());
956 	WriteToIORequestRequest* request;
957 	error = AllocateRequest(allocator, &request);
958 	if (error != B_OK)
959 		return error;
960 
961 	request->nsid = volumeID;
962 	request->request = requestID;
963 
964 	error = allocator.AllocateData(request->buffer, buffer, size, 1, false);
965 	if (error != B_OK)
966 		return error;
967 
968 	// send the request
969 	UserlandRequestHandler handler(fileSystem, WRITE_TO_IO_REQUEST_REPLY);
970 	FileCacheWriteReply* reply;
971 	error = port->SendRequest(&allocator, &handler, (Request**)&reply);
972 	if (error != B_OK)
973 		return error;
974 	RequestReleaser requestReleaser(port, reply);
975 
976 	// process the reply
977 	return reply->error;
978 }
979 
980 
981 status_t
982 UserlandFS::KernelEmu::notify_io_request(dev_t volumeID, int32 requestID,
983 	status_t status)
984 {
985 	// get the request port and the file system
986 	RequestPort* port;
987 	FileSystem* fileSystem;
988 	status_t error = get_port_and_fs(&port, &fileSystem);
989 	if (error != B_OK)
990 		return error;
991 
992 	// prepare the request
993 	RequestAllocator allocator(port->GetPort());
994 	NotifyIORequestRequest* request;
995 	error = AllocateRequest(allocator, &request);
996 	if (error != B_OK)
997 		return error;
998 
999 	request->nsid = volumeID;
1000 	request->request = requestID;
1001 	request->status = status;
1002 
1003 	// send the request
1004 	UserlandRequestHandler handler(fileSystem, NOTIFY_IO_REQUEST_REPLY);
1005 	NotifyIORequestReply* reply;
1006 	error = port->SendRequest(&allocator, &handler, (Request**)&reply);
1007 	if (error != B_OK)
1008 		return error;
1009 	RequestReleaser requestReleaser(port, reply);
1010 
1011 	// process the reply
1012 	return reply->error;
1013 }
1014 
1015 
1016 // #pragma mark - node monitoring
1017 
1018 
1019 status_t
1020 UserlandFS::KernelEmu::add_node_listener(dev_t device, ino_t node, uint32 flags,
1021 	void* listener)
1022 {
1023 	// get the request port and the file system
1024 	RequestPort* port;
1025 	FileSystem* fileSystem;
1026 	status_t error = get_port_and_fs(&port, &fileSystem);
1027 	if (error != B_OK)
1028 		return error;
1029 
1030 	// prepare the request
1031 	RequestAllocator allocator(port->GetPort());
1032 	AddNodeListenerRequest* request;
1033 	error = AllocateRequest(allocator, &request);
1034 	if (error != B_OK)
1035 		return error;
1036 
1037 	request->device = device;
1038 	request->node = node;
1039 	request->flags = flags;
1040 	request->listener = listener;
1041 
1042 	// send the request
1043 	UserlandRequestHandler handler(fileSystem, ADD_NODE_LISTENER_REPLY);
1044 	AddNodeListenerReply* reply;
1045 	error = port->SendRequest(&allocator, &handler, (Request**)&reply);
1046 	if (error != B_OK)
1047 		return error;
1048 	RequestReleaser requestReleaser(port, reply);
1049 
1050 	// process the reply
1051 	return reply->error;
1052 }
1053 
1054 
1055 status_t
1056 UserlandFS::KernelEmu::remove_node_listener(dev_t device, ino_t node,
1057 	void* listener)
1058 {
1059 	// get the request port and the file system
1060 	RequestPort* port;
1061 	FileSystem* fileSystem;
1062 	status_t error = get_port_and_fs(&port, &fileSystem);
1063 	if (error != B_OK)
1064 		return error;
1065 
1066 	// prepare the request
1067 	RequestAllocator allocator(port->GetPort());
1068 	RemoveNodeListenerRequest* request;
1069 	error = AllocateRequest(allocator, &request);
1070 	if (error != B_OK)
1071 		return error;
1072 
1073 	request->device = device;
1074 	request->node = node;
1075 	request->listener = listener;
1076 
1077 	// send the request
1078 	UserlandRequestHandler handler(fileSystem, REMOVE_NODE_LISTENER_REPLY);
1079 	RemoveNodeListenerReply* reply;
1080 	error = port->SendRequest(&allocator, &handler, (Request**)&reply);
1081 	if (error != B_OK)
1082 		return error;
1083 	RequestReleaser requestReleaser(port, reply);
1084 
1085 	// process the reply
1086 	return reply->error;
1087 }
1088 
1089 
1090 // #pragma mark -
1091 
1092 
1093 // kernel_debugger
1094 void
1095 UserlandFS::KernelEmu::kernel_debugger(const char *message)
1096 {
1097 	debugger(message);
1098 }
1099 
1100 // vdprintf
1101 void
1102 UserlandFS::KernelEmu::vdprintf(const char *format, va_list args)
1103 {
1104 	vprintf(format, args);
1105 }
1106 
1107 // dprintf
1108 void
1109 UserlandFS::KernelEmu::dprintf(const char *format, ...)
1110 {
1111 	va_list args;
1112 	va_start(args, format);
1113 	vdprintf(format, args);
1114 	va_end(args);
1115 }
1116 
1117 void
1118 UserlandFS::KernelEmu::dump_block(const char *buffer, int size,
1119 	const char *prefix)
1120 {
1121 	// TODO: Implement!
1122 }
1123 
1124 // parse_expression
1125 //ulong
1126 //parse_expression(char *str)
1127 //{
1128 //	return 0;
1129 //}
1130 
1131 // add_debugger_command
1132 int
1133 UserlandFS::KernelEmu::add_debugger_command(char *name,
1134 	int (*func)(int argc, char **argv), char *help)
1135 {
1136 	return B_OK;
1137 }
1138 
1139 // remove_debugger_command
1140 int
1141 UserlandFS::KernelEmu::remove_debugger_command(char *name,
1142 	int (*func)(int argc, char **argv))
1143 {
1144 	return B_OK;
1145 }
1146 
1147 // parse_expression
1148 uint32
1149 UserlandFS::KernelEmu::parse_expression(const char *string)
1150 {
1151 	return 0;
1152 }
1153 
1154 
1155 // kprintf
1156 //void
1157 //kprintf(const char *format, ...)
1158 //{
1159 //}
1160 
1161 // spawn_kernel_thread
1162 thread_id
1163 UserlandFS::KernelEmu::spawn_kernel_thread(thread_entry function,
1164 	const char *threadName, long priority, void *arg)
1165 {
1166 	return spawn_thread(function, threadName, priority, arg);
1167 }
1168