xref: /haiku/src/add-ons/kernel/file_systems/userlandfs/server/kernel_emu.cpp (revision 03187b607b2b5eec7ee059f1ead09bdba14991fb)
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] = '.';
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->pos = offset;
828 
829 	error = allocator.AllocateData(request->buffer, buffer, *_size, 1, false);
830 	if (error != B_OK)
831 		return error;
832 
833 	// send the request
834 	UserlandRequestHandler handler(fileSystem, FILE_CACHE_WRITE_REPLY);
835 	FileCacheWriteReply* reply;
836 	error = port->SendRequest(&allocator, &handler, (Request**)&reply);
837 	if (error != B_OK)
838 		return error;
839 	RequestReleaser requestReleaser(port, reply);
840 
841 	// process the reply
842 	*_size = reply->bytesWritten;
843 	return reply->error;
844 }
845 
846 
847 // #pragma mark - I/O
848 
849 
850 status_t
851 UserlandFS::KernelEmu::do_iterative_fd_io(dev_t volumeID, int fd,
852 	int32 requestID, void* cookie, const file_io_vec* vecs, uint32 vecCount)
853 {
854 	// get the request port and the file system
855 	RequestPort* port;
856 	FileSystem* fileSystem;
857 	status_t error = get_port_and_fs(&port, &fileSystem);
858 	if (error != B_OK)
859 		return error;
860 
861 	// prepare the request
862 	RequestAllocator allocator(port->GetPort());
863 	DoIterativeFDIORequest* request;
864 	error = AllocateRequest(allocator, &request);
865 	if (error != B_OK)
866 		return error;
867 
868 	request->nsid = volumeID;
869 	request->fd = fd;
870 	request->request = requestID;
871 	request->cookie = cookie;
872 
873 	if (vecCount > 0) {
874 		vecCount = std::min(vecCount, (uint32)DoIterativeFDIORequest::MAX_VECS);
875 		memcpy(request->vecs, vecs, sizeof(file_io_vec) * vecCount);
876 	}
877 	request->vecCount = vecCount;
878 
879 	// send the request
880 	UserlandRequestHandler handler(fileSystem, DO_ITERATIVE_FD_IO_REPLY);
881 	DoIterativeFDIOReply* reply;
882 	error = port->SendRequest(&allocator, &handler, (Request**)&reply);
883 	if (error != B_OK)
884 		return error;
885 // TODO: Up to this point we should call the finished hook on error!
886 	RequestReleaser requestReleaser(port, reply);
887 
888 	// process the reply
889 	return reply->error;
890 }
891 
892 
893 status_t
894 UserlandFS::KernelEmu::notify_io_request(dev_t volumeID, int32 requestID,
895 	status_t status)
896 {
897 	// get the request port and the file system
898 	RequestPort* port;
899 	FileSystem* fileSystem;
900 	status_t error = get_port_and_fs(&port, &fileSystem);
901 	if (error != B_OK)
902 		return error;
903 
904 	// prepare the request
905 	RequestAllocator allocator(port->GetPort());
906 	NotifyIORequestRequest* request;
907 	error = AllocateRequest(allocator, &request);
908 	if (error != B_OK)
909 		return error;
910 
911 	request->nsid = volumeID;
912 	request->request = requestID;
913 	request->status = status;
914 
915 	// send the request
916 	UserlandRequestHandler handler(fileSystem, NOTIFY_IO_REQUEST_REPLY);
917 	NotifyIORequestReply* reply;
918 	error = port->SendRequest(&allocator, &handler, (Request**)&reply);
919 	if (error != B_OK)
920 		return error;
921 	RequestReleaser requestReleaser(port, reply);
922 
923 	// process the reply
924 	return reply->error;
925 }
926 
927 
928 // #pragma mark -
929 
930 
931 // kernel_debugger
932 void
933 UserlandFS::KernelEmu::kernel_debugger(const char *message)
934 {
935 	debugger(message);
936 }
937 
938 // vdprintf
939 void
940 UserlandFS::KernelEmu::vdprintf(const char *format, va_list args)
941 {
942 	vprintf(format, args);
943 }
944 
945 // dprintf
946 void
947 UserlandFS::KernelEmu::dprintf(const char *format, ...)
948 {
949 	va_list args;
950 	va_start(args, format);
951 	vdprintf(format, args);
952 	va_end(args);
953 }
954 
955 void
956 UserlandFS::KernelEmu::dump_block(const char *buffer, int size,
957 	const char *prefix)
958 {
959 	// TODO: Implement!
960 }
961 
962 // parse_expression
963 //ulong
964 //parse_expression(char *str)
965 //{
966 //	return 0;
967 //}
968 
969 // add_debugger_command
970 int
971 UserlandFS::KernelEmu::add_debugger_command(char *name,
972 	int (*func)(int argc, char **argv), char *help)
973 {
974 	return B_OK;
975 }
976 
977 // remove_debugger_command
978 int
979 UserlandFS::KernelEmu::remove_debugger_command(char *name,
980 	int (*func)(int argc, char **argv))
981 {
982 	return B_OK;
983 }
984 
985 // parse_expression
986 uint32
987 UserlandFS::KernelEmu::parse_expression(const char *string)
988 {
989 	return 0;
990 }
991 
992 
993 // kprintf
994 //void
995 //kprintf(const char *format, ...)
996 //{
997 //}
998 
999 // spawn_kernel_thread
1000 thread_id
1001 UserlandFS::KernelEmu::spawn_kernel_thread(thread_entry function,
1002 	const char *threadName, long priority, void *arg)
1003 {
1004 	return spawn_thread(function, threadName, priority, arg);
1005 }
1006