xref: /haiku/src/add-ons/kernel/file_systems/userlandfs/server/kernel_emu.cpp (revision 93a78ecaa45114d68952d08c4778f073515102f2)
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 "RequestPort.h"
10 #include "Requests.h"
11 #include "RequestThread.h"
12 #include "UserlandFSServer.h"
13 #include "UserlandRequestHandler.h"
14 
15 
16 // Taken from the Haiku Storage Kit (storage_support.cpp)
17 /*! The length of the first component is returned as well as the index at
18 	which the next one starts. These values are only valid, if the function
19 	returns \c B_OK.
20 	\param path the path to be parsed
21 	\param length the variable the length of the first component is written
22 		   into
23 	\param nextComponent the variable the index of the next component is
24 		   written into. \c 0 is returned, if there is no next component.
25 	\return \c B_OK, if \a path is not \c NULL, \c B_BAD_VALUE otherwise
26 */
27 static status_t
28 parse_first_path_component(const char *path, int32& length,
29 						   int32& nextComponent)
30 {
31 	status_t error = (path ? B_OK : B_BAD_VALUE);
32 	if (error == B_OK) {
33 		int32 i = 0;
34 		// find first '/' or end of name
35 		for (; path[i] != '/' && path[i] != '\0'; i++);
36 		// handle special case "/..." (absolute path)
37 		if (i == 0 && path[i] != '\0')
38 			i = 1;
39 		length = i;
40 		// find last '/' or end of name
41 		for (; path[i] == '/' && path[i] != '\0'; i++);
42 		if (path[i] == '\0')	// this covers "" as well
43 			nextComponent = 0;
44 		else
45 			nextComponent = i;
46 	}
47 	return error;
48 }
49 
50 // new_path
51 int
52 UserlandFS::KernelEmu::new_path(const char *path, char **copy)
53 {
54 	// check errors and special cases
55 	if (!copy)
56 		return B_BAD_VALUE;
57 	if (!path) {
58 		*copy = NULL;
59 		return B_OK;
60 	}
61 	int32 len = strlen(path);
62 	if (len < 1)
63 		return B_ENTRY_NOT_FOUND;
64 	bool appendDot = (path[len - 1] == '/');
65 	if (appendDot)
66 		len++;
67 	if (len >= B_PATH_NAME_LENGTH)
68 		return B_NAME_TOO_LONG;
69 	// check the path components
70 	const char *remainder = path;
71 	int32 length, nextComponent;
72 	do {
73 		status_t error
74 			= parse_first_path_component(remainder, length, nextComponent);
75 		if (error != B_OK)
76 			return error;
77 		if (length >= B_FILE_NAME_LENGTH)
78 			error = B_NAME_TOO_LONG;
79 		remainder += nextComponent;
80 	} while (nextComponent != 0);
81 	// clone the path
82 	char *copiedPath = (char*)malloc(len + 1);
83 	if (!copiedPath)
84 		return B_NO_MEMORY;
85 	strcpy(copiedPath, path);
86 	// append a dot, if desired
87 	if (appendDot) {
88 		copiedPath[len] = '.';
89 		copiedPath[len] = '\0';
90 	}
91 	*copy = copiedPath;
92 	return B_OK;
93 }
94 
95 // free_path
96 void
97 UserlandFS::KernelEmu::free_path(char *p)
98 {
99 	free(p);
100 }
101 
102 
103 // #pragma mark -
104 
105 
106 // get_port_and_fs
107 static status_t
108 get_port_and_fs(RequestPort** port, FileSystem** fileSystem)
109 {
110 	// get the request thread
111 	RequestThread* thread = RequestThread::GetCurrentThread();
112 	if (thread) {
113 		*port = thread->GetPort();
114 		*fileSystem = thread->GetFileSystem();
115 	} else {
116 		*port = UserlandFSServer::GetNotificationRequestPort();
117 		*fileSystem = UserlandFSServer::GetFileSystem();
118 		if (!*port || !*fileSystem)
119 			return B_BAD_VALUE;
120 	}
121 	return B_OK;
122 }
123 
124 // notify_listener
125 status_t
126 UserlandFS::KernelEmu::notify_listener(int32 operation, uint32 details,
127 	dev_t device, ino_t oldDirectory, ino_t directory,
128 	ino_t node, const char* oldName, const char* name)
129 {
130 	// get the request port and the file system
131 	RequestPort* port;
132 	FileSystem* fileSystem;
133 	status_t error = get_port_and_fs(&port, &fileSystem);
134 	if (error != B_OK)
135 		return error;
136 
137 	// prepare the request
138 	RequestAllocator allocator(port->GetPort());
139 	NotifyListenerRequest* request;
140 	error = AllocateRequest(allocator, &request);
141 	if (error != B_OK)
142 		return error;
143 
144 	request->operation = operation;
145 	request->details = details;
146 	request->device = device;
147 	request->oldDirectory = oldDirectory;
148 	request->directory = directory;
149 	request->node = node;
150 	error = allocator.AllocateString(request->oldName, oldName);
151 	if (error != B_OK)
152 		return error;
153 	error = allocator.AllocateString(request->name, name);
154 	if (error != B_OK)
155 		return error;
156 
157 	// send the request
158 	UserlandRequestHandler handler(fileSystem, NOTIFY_LISTENER_REPLY);
159 	NotifyListenerReply* reply;
160 	error = port->SendRequest(&allocator, &handler, (Request**)&reply);
161 	if (error != B_OK)
162 		return error;
163 	RequestReleaser requestReleaser(port, reply);
164 
165 	// process the reply
166 	if (reply->error != B_OK)
167 		return reply->error;
168 	return error;
169 }
170 
171 // notify_select_event
172 status_t
173 UserlandFS::KernelEmu::notify_select_event(selectsync *sync, uint32 ref,
174 	uint8 event, bool unspecifiedEvent)
175 {
176 	// get the request port and the file system
177 	RequestPort* port;
178 	FileSystem* fileSystem;
179 	status_t error = get_port_and_fs(&port, &fileSystem);
180 	if (error != B_OK)
181 		return error;
182 
183 	// prepare the request
184 	RequestAllocator allocator(port->GetPort());
185 	NotifySelectEventRequest* request;
186 	error = AllocateRequest(allocator, &request);
187 	if (error != B_OK)
188 		return error;
189 
190 	request->sync = sync;
191 	request->ref = ref;
192 	request->event = event;
193 	request->unspecifiedEvent = unspecifiedEvent;
194 
195 	// send the request
196 	UserlandRequestHandler handler(fileSystem, NOTIFY_SELECT_EVENT_REPLY);
197 	NotifySelectEventReply* reply;
198 	error = port->SendRequest(&allocator, &handler, (Request**)&reply);
199 	if (error != B_OK)
200 		return error;
201 	RequestReleaser requestReleaser(port, reply);
202 
203 	// process the reply
204 	if (reply->error != B_OK)
205 		return reply->error;
206 	return error;
207 }
208 
209 // send_notification
210 status_t
211 UserlandFS::KernelEmu::notify_query(port_id targetPort, int32 token,
212 	int32 operation, dev_t device, ino_t directory, const char* name,
213 	ino_t node)
214 {
215 	// get the request port and the file system
216 	RequestPort* port;
217 	FileSystem* fileSystem;
218 	status_t error = get_port_and_fs(&port, &fileSystem);
219 	if (error != B_OK)
220 		return error;
221 
222 	// prepare the request
223 	RequestAllocator allocator(port->GetPort());
224 	NotifyQueryRequest* request;
225 	error = AllocateRequest(allocator, &request);
226 	if (error != B_OK)
227 		return error;
228 
229 	request->port = targetPort;
230 	request->token = token;
231 	request->operation = operation;
232 	request->device = device;
233 	request->directory = directory;
234 	request->node = node;
235 	error = allocator.AllocateString(request->name, name);
236 	if (error != B_OK)
237 		return error;
238 
239 	// send the request
240 	UserlandRequestHandler handler(fileSystem, NOTIFY_QUERY_REPLY);
241 	NotifyQueryReply* reply;
242 	error = port->SendRequest(&allocator, &handler, (Request**)&reply);
243 	if (error != B_OK)
244 		return error;
245 	RequestReleaser requestReleaser(port, reply);
246 
247 	// process the reply
248 	if (reply->error != B_OK)
249 		return reply->error;
250 	return error;
251 }
252 
253 
254 // #pragma mark -
255 
256 
257 // get_vnode
258 status_t
259 UserlandFS::KernelEmu::get_vnode(dev_t nsid, ino_t vnid, fs_vnode* data)
260 {
261 	// get the request port and the file system
262 	RequestPort* port;
263 	FileSystem* fileSystem;
264 	status_t error = get_port_and_fs(&port, &fileSystem);
265 	if (error != B_OK)
266 		return error;
267 
268 	// prepare the request
269 	RequestAllocator allocator(port->GetPort());
270 	GetVNodeRequest* request;
271 	error = AllocateRequest(allocator, &request);
272 	if (error != B_OK)
273 		return error;
274 
275 	request->nsid = nsid;
276 	request->vnid = vnid;
277 
278 	// send the request
279 	UserlandRequestHandler handler(fileSystem, GET_VNODE_REPLY);
280 	GetVNodeReply* reply;
281 	error = port->SendRequest(&allocator, &handler, (Request**)&reply);
282 	if (error != B_OK)
283 		return error;
284 	RequestReleaser requestReleaser(port, reply);
285 
286 	// process the reply
287 	if (reply->error != B_OK)
288 		return reply->error;
289 	*data = reply->node;
290 	return error;
291 }
292 
293 // put_vnode
294 status_t
295 UserlandFS::KernelEmu::put_vnode(dev_t nsid, ino_t vnid)
296 {
297 	// get the request port and the file system
298 	RequestPort* port;
299 	FileSystem* fileSystem;
300 	status_t error = get_port_and_fs(&port, &fileSystem);
301 	if (error != B_OK)
302 		return error;
303 
304 	// prepare the request
305 	RequestAllocator allocator(port->GetPort());
306 	PutVNodeRequest* request;
307 	error = AllocateRequest(allocator, &request);
308 	if (error != B_OK)
309 		return error;
310 
311 	request->nsid = nsid;
312 	request->vnid = vnid;
313 
314 	// send the request
315 	UserlandRequestHandler handler(fileSystem, PUT_VNODE_REPLY);
316 	PutVNodeReply* reply;
317 	error = port->SendRequest(&allocator, &handler, (Request**)&reply);
318 	if (error != B_OK)
319 		return error;
320 	RequestReleaser requestReleaser(port, reply);
321 
322 	// process the reply
323 	if (reply->error != B_OK)
324 		return reply->error;
325 	return error;
326 }
327 
328 // new_vnode
329 status_t
330 UserlandFS::KernelEmu::new_vnode(dev_t nsid, ino_t vnid, fs_vnode data)
331 {
332 	// get the request port and the file system
333 	RequestPort* port;
334 	FileSystem* fileSystem;
335 	status_t error = get_port_and_fs(&port, &fileSystem);
336 	if (error != B_OK)
337 		return error;
338 
339 	// prepare the request
340 	RequestAllocator allocator(port->GetPort());
341 	NewVNodeRequest* request;
342 	error = AllocateRequest(allocator, &request);
343 	if (error != B_OK)
344 		return error;
345 
346 	request->nsid = nsid;
347 	request->vnid = vnid;
348 	request->node = data;
349 
350 	// send the request
351 	UserlandRequestHandler handler(fileSystem, NEW_VNODE_REPLY);
352 	NewVNodeReply* reply;
353 	error = port->SendRequest(&allocator, &handler, (Request**)&reply);
354 	if (error != B_OK)
355 		return error;
356 	RequestReleaser requestReleaser(port, reply);
357 
358 	// process the reply
359 	if (reply->error != B_OK)
360 		return reply->error;
361 	return error;
362 }
363 
364 // publish_vnode
365 status_t
366 UserlandFS::KernelEmu::publish_vnode(dev_t nsid, ino_t vnid,
367 	fs_vnode data)
368 {
369 	// get the request port and the file system
370 	RequestPort* port;
371 	FileSystem* fileSystem;
372 	status_t error = get_port_and_fs(&port, &fileSystem);
373 	if (error != B_OK)
374 		return error;
375 
376 	// prepare the request
377 	RequestAllocator allocator(port->GetPort());
378 	PublishVNodeRequest* request;
379 	error = AllocateRequest(allocator, &request);
380 	if (error != B_OK)
381 		return error;
382 
383 	request->nsid = nsid;
384 	request->vnid = vnid;
385 	request->node = data;
386 
387 	// send the request
388 	UserlandRequestHandler handler(fileSystem, PUBLISH_VNODE_REPLY);
389 	PublishVNodeReply* reply;
390 	error = port->SendRequest(&allocator, &handler, (Request**)&reply);
391 	if (error != B_OK)
392 		return error;
393 	RequestReleaser requestReleaser(port, reply);
394 
395 	// process the reply
396 	if (reply->error != B_OK)
397 		return reply->error;
398 	return error;
399 }
400 
401 // remove_vnode
402 status_t
403 UserlandFS::KernelEmu::remove_vnode(dev_t nsid, ino_t vnid)
404 {
405 	// get the request port and the file system
406 	RequestPort* port;
407 	FileSystem* fileSystem;
408 	status_t error = get_port_and_fs(&port, &fileSystem);
409 	if (error != B_OK)
410 		return error;
411 
412 	// prepare the request
413 	RequestAllocator allocator(port->GetPort());
414 	RemoveVNodeRequest* request;
415 	error = AllocateRequest(allocator, &request);
416 	if (error != B_OK)
417 		return error;
418 
419 	request->nsid = nsid;
420 	request->vnid = vnid;
421 
422 	// send the request
423 	UserlandRequestHandler handler(fileSystem, REMOVE_VNODE_REPLY);
424 	RemoveVNodeReply* reply;
425 	error = port->SendRequest(&allocator, &handler, (Request**)&reply);
426 	if (error != B_OK)
427 		return error;
428 	RequestReleaser requestReleaser(port, reply);
429 
430 	// process the reply
431 	if (reply->error != B_OK)
432 		return reply->error;
433 	return error;
434 }
435 
436 // unremove_vnode
437 status_t
438 UserlandFS::KernelEmu::unremove_vnode(dev_t nsid, ino_t vnid)
439 {
440 	// get the request port and the file system
441 	RequestPort* port;
442 	FileSystem* fileSystem;
443 	status_t error = get_port_and_fs(&port, &fileSystem);
444 	if (error != B_OK)
445 		return error;
446 
447 	// prepare the request
448 	RequestAllocator allocator(port->GetPort());
449 	UnremoveVNodeRequest* request;
450 	error = AllocateRequest(allocator, &request);
451 	if (error != B_OK)
452 		return error;
453 
454 	request->nsid = nsid;
455 	request->vnid = vnid;
456 
457 	// send the request
458 	UserlandRequestHandler handler(fileSystem, UNREMOVE_VNODE_REPLY);
459 	UnremoveVNodeReply* reply;
460 	error = port->SendRequest(&allocator, &handler, (Request**)&reply);
461 	if (error != B_OK)
462 		return error;
463 	RequestReleaser requestReleaser(port, reply);
464 
465 	// process the reply
466 	if (reply->error != B_OK)
467 		return reply->error;
468 	return error;
469 }
470 
471 // get_vnode_removed
472 status_t
473 UserlandFS::KernelEmu::get_vnode_removed(dev_t nsid, ino_t vnid,
474 	bool* removed)
475 {
476 	// get the request port and the file system
477 	RequestPort* port;
478 	FileSystem* fileSystem;
479 	status_t error = get_port_and_fs(&port, &fileSystem);
480 	if (error != B_OK)
481 		return error;
482 
483 	// prepare the request
484 	RequestAllocator allocator(port->GetPort());
485 	GetVNodeRemovedRequest* request;
486 	error = AllocateRequest(allocator, &request);
487 	if (error != B_OK)
488 		return error;
489 
490 	request->nsid = nsid;
491 	request->vnid = vnid;
492 
493 	// send the request
494 	UserlandRequestHandler handler(fileSystem, GET_VNODE_REMOVED_REPLY);
495 	GetVNodeRemovedReply* reply;
496 	error = port->SendRequest(&allocator, &handler, (Request**)&reply);
497 	if (error != B_OK)
498 		return error;
499 	RequestReleaser requestReleaser(port, reply);
500 
501 	// process the reply
502 	*removed = reply->removed;
503 	return reply->error;
504 }
505 
506 // #pragma mark -
507 
508 // kernel_debugger
509 void
510 UserlandFS::KernelEmu::kernel_debugger(const char *message)
511 {
512 	debugger(message);
513 }
514 
515 // vpanic
516 void
517 UserlandFS::KernelEmu::vpanic(const char *format, va_list args)
518 {
519 	char buffer[1024];
520 	strcpy(buffer, "PANIC: ");
521 	int32 prefixLen = strlen(buffer);
522 	int bufferSize = sizeof(buffer) - prefixLen;
523 
524 	// no vsnprintf() on PPC
525 	#if defined(__INTEL__)
526 		vsnprintf(buffer + prefixLen, bufferSize - 1, format, args);
527 	#else
528 		vsprintf(buffer + prefixLen, format, args);
529 	#endif
530 
531 	buffer[sizeof(buffer) - 1] = '\0';
532 	debugger(buffer);
533 }
534 
535 // panic
536 void
537 UserlandFS::KernelEmu::panic(const char *format, ...)
538 {
539 	va_list args;
540 	va_start(args, format);
541 	vpanic(format, args);
542 	va_end(args);
543 }
544 
545 // vdprintf
546 void
547 UserlandFS::KernelEmu::vdprintf(const char *format, va_list args)
548 {
549 	vprintf(format, args);
550 }
551 
552 // dprintf
553 void
554 UserlandFS::KernelEmu::dprintf(const char *format, ...)
555 {
556 	va_list args;
557 	va_start(args, format);
558 	vdprintf(format, args);
559 	va_end(args);
560 }
561 
562 void
563 UserlandFS::KernelEmu::dump_block(const char *buffer, int size,
564 	const char *prefix)
565 {
566 	// TODO: Implement!
567 }
568 
569 // parse_expression
570 //ulong
571 //parse_expression(char *str)
572 //{
573 //	return 0;
574 //}
575 
576 // add_debugger_command
577 int
578 UserlandFS::KernelEmu::add_debugger_command(char *name,
579 	int (*func)(int argc, char **argv), char *help)
580 {
581 	return B_OK;
582 }
583 
584 // remove_debugger_command
585 int
586 UserlandFS::KernelEmu::remove_debugger_command(char *name,
587 	int (*func)(int argc, char **argv))
588 {
589 	return B_OK;
590 }
591 
592 // parse_expression
593 uint32
594 UserlandFS::KernelEmu::parse_expression(const char *string)
595 {
596 	return 0;
597 }
598 
599 
600 // kprintf
601 //void
602 //kprintf(const char *format, ...)
603 //{
604 //}
605 
606 // spawn_kernel_thread
607 thread_id
608 UserlandFS::KernelEmu::spawn_kernel_thread(thread_entry function,
609 	const char *threadName, long priority, void *arg)
610 {
611 	return spawn_thread(function, threadName, priority, arg);
612 }
613