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*/
31static status_t
32parse_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
55int
56UserlandFS::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
100void
101UserlandFS::KernelEmu::free_path(char *p)
102{
103	free(p);
104}
105
106
107// #pragma mark -
108
109
110// get_port_and_fs
111static status_t
112get_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
129status_t
130UserlandFS::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
176status_t
177UserlandFS::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
213status_t
214UserlandFS::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
261status_t
262UserlandFS::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
297status_t
298UserlandFS::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
332status_t
333UserlandFS::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
367status_t
368UserlandFS::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
405status_t
406UserlandFS::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
446status_t
447UserlandFS::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
468status_t
469UserlandFS::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
503status_t
504UserlandFS::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
538status_t
539UserlandFS::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
577status_t
578UserlandFS::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
613status_t
614UserlandFS::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
647status_t
648UserlandFS::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
683status_t
684UserlandFS::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
719status_t
720UserlandFS::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
753status_t
754UserlandFS::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
806status_t
807UserlandFS::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
854status_t
855UserlandFS::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
897status_t
898UserlandFS::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
943status_t
944UserlandFS::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
981status_t
982UserlandFS::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
1019status_t
1020UserlandFS::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
1055status_t
1056UserlandFS::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
1094void
1095UserlandFS::KernelEmu::kernel_debugger(const char *message)
1096{
1097	debugger(message);
1098}
1099
1100// vdprintf
1101void
1102UserlandFS::KernelEmu::vdprintf(const char *format, va_list args)
1103{
1104	vprintf(format, args);
1105}
1106
1107// dprintf
1108void
1109UserlandFS::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
1117void
1118UserlandFS::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
1132int
1133UserlandFS::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
1140int
1141UserlandFS::KernelEmu::remove_debugger_command(char *name,
1142	int (*func)(int argc, char **argv))
1143{
1144	return B_OK;
1145}
1146
1147// parse_expression
1148uint32
1149UserlandFS::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
1162thread_id
1163UserlandFS::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