xref: /haiku/src/add-ons/kernel/file_systems/userlandfs/server/kernel_emu.cpp (revision d9cebac2b77547b7064f22497514eecd2d047160)
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, uint8 event,
174 	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->event = event;
192 	request->unspecifiedEvent = unspecifiedEvent;
193 
194 	// send the request
195 	UserlandRequestHandler handler(fileSystem, NOTIFY_SELECT_EVENT_REPLY);
196 	NotifySelectEventReply* reply;
197 	error = port->SendRequest(&allocator, &handler, (Request**)&reply);
198 	if (error != B_OK)
199 		return error;
200 	RequestReleaser requestReleaser(port, reply);
201 
202 	// process the reply
203 	if (reply->error != B_OK)
204 		return reply->error;
205 	return error;
206 }
207 
208 // send_notification
209 status_t
210 UserlandFS::KernelEmu::notify_query(port_id targetPort, int32 token,
211 	int32 operation, dev_t device, ino_t directory, const char* name,
212 	ino_t node)
213 {
214 	// get the request port and the file system
215 	RequestPort* port;
216 	FileSystem* fileSystem;
217 	status_t error = get_port_and_fs(&port, &fileSystem);
218 	if (error != B_OK)
219 		return error;
220 
221 	// prepare the request
222 	RequestAllocator allocator(port->GetPort());
223 	NotifyQueryRequest* request;
224 	error = AllocateRequest(allocator, &request);
225 	if (error != B_OK)
226 		return error;
227 
228 	request->port = targetPort;
229 	request->token = token;
230 	request->operation = operation;
231 	request->device = device;
232 	request->directory = directory;
233 	request->node = node;
234 	error = allocator.AllocateString(request->name, name);
235 	if (error != B_OK)
236 		return error;
237 
238 	// send the request
239 	UserlandRequestHandler handler(fileSystem, NOTIFY_QUERY_REPLY);
240 	NotifyQueryReply* reply;
241 	error = port->SendRequest(&allocator, &handler, (Request**)&reply);
242 	if (error != B_OK)
243 		return error;
244 	RequestReleaser requestReleaser(port, reply);
245 
246 	// process the reply
247 	if (reply->error != B_OK)
248 		return reply->error;
249 	return error;
250 }
251 
252 
253 // #pragma mark -
254 
255 
256 // get_vnode
257 status_t
258 UserlandFS::KernelEmu::get_vnode(dev_t nsid, ino_t vnid, fs_vnode* data)
259 {
260 	// get the request port and the file system
261 	RequestPort* port;
262 	FileSystem* fileSystem;
263 	status_t error = get_port_and_fs(&port, &fileSystem);
264 	if (error != B_OK)
265 		return error;
266 
267 	// prepare the request
268 	RequestAllocator allocator(port->GetPort());
269 	GetVNodeRequest* request;
270 	error = AllocateRequest(allocator, &request);
271 	if (error != B_OK)
272 		return error;
273 
274 	request->nsid = nsid;
275 	request->vnid = vnid;
276 
277 	// send the request
278 	UserlandRequestHandler handler(fileSystem, GET_VNODE_REPLY);
279 	GetVNodeReply* reply;
280 	error = port->SendRequest(&allocator, &handler, (Request**)&reply);
281 	if (error != B_OK)
282 		return error;
283 	RequestReleaser requestReleaser(port, reply);
284 
285 	// process the reply
286 	if (reply->error != B_OK)
287 		return reply->error;
288 	*data = reply->node;
289 	return error;
290 }
291 
292 // put_vnode
293 status_t
294 UserlandFS::KernelEmu::put_vnode(dev_t nsid, ino_t vnid)
295 {
296 	// get the request port and the file system
297 	RequestPort* port;
298 	FileSystem* fileSystem;
299 	status_t error = get_port_and_fs(&port, &fileSystem);
300 	if (error != B_OK)
301 		return error;
302 
303 	// prepare the request
304 	RequestAllocator allocator(port->GetPort());
305 	PutVNodeRequest* request;
306 	error = AllocateRequest(allocator, &request);
307 	if (error != B_OK)
308 		return error;
309 
310 	request->nsid = nsid;
311 	request->vnid = vnid;
312 
313 	// send the request
314 	UserlandRequestHandler handler(fileSystem, PUT_VNODE_REPLY);
315 	PutVNodeReply* reply;
316 	error = port->SendRequest(&allocator, &handler, (Request**)&reply);
317 	if (error != B_OK)
318 		return error;
319 	RequestReleaser requestReleaser(port, reply);
320 
321 	// process the reply
322 	if (reply->error != B_OK)
323 		return reply->error;
324 	return error;
325 }
326 
327 // new_vnode
328 status_t
329 UserlandFS::KernelEmu::new_vnode(dev_t nsid, ino_t vnid, fs_vnode data)
330 {
331 	// get the request port and the file system
332 	RequestPort* port;
333 	FileSystem* fileSystem;
334 	status_t error = get_port_and_fs(&port, &fileSystem);
335 	if (error != B_OK)
336 		return error;
337 
338 	// prepare the request
339 	RequestAllocator allocator(port->GetPort());
340 	NewVNodeRequest* request;
341 	error = AllocateRequest(allocator, &request);
342 	if (error != B_OK)
343 		return error;
344 
345 	request->nsid = nsid;
346 	request->vnid = vnid;
347 	request->node = data;
348 
349 	// send the request
350 	UserlandRequestHandler handler(fileSystem, NEW_VNODE_REPLY);
351 	NewVNodeReply* reply;
352 	error = port->SendRequest(&allocator, &handler, (Request**)&reply);
353 	if (error != B_OK)
354 		return error;
355 	RequestReleaser requestReleaser(port, reply);
356 
357 	// process the reply
358 	if (reply->error != B_OK)
359 		return reply->error;
360 	return error;
361 }
362 
363 // publish_vnode
364 status_t
365 UserlandFS::KernelEmu::publish_vnode(dev_t nsid, ino_t vnid,
366 	fs_vnode data)
367 {
368 	// get the request port and the file system
369 	RequestPort* port;
370 	FileSystem* fileSystem;
371 	status_t error = get_port_and_fs(&port, &fileSystem);
372 	if (error != B_OK)
373 		return error;
374 
375 	// prepare the request
376 	RequestAllocator allocator(port->GetPort());
377 	PublishVNodeRequest* request;
378 	error = AllocateRequest(allocator, &request);
379 	if (error != B_OK)
380 		return error;
381 
382 	request->nsid = nsid;
383 	request->vnid = vnid;
384 	request->node = data;
385 
386 	// send the request
387 	UserlandRequestHandler handler(fileSystem, PUBLISH_VNODE_REPLY);
388 	PublishVNodeReply* reply;
389 	error = port->SendRequest(&allocator, &handler, (Request**)&reply);
390 	if (error != B_OK)
391 		return error;
392 	RequestReleaser requestReleaser(port, reply);
393 
394 	// process the reply
395 	if (reply->error != B_OK)
396 		return reply->error;
397 	return error;
398 }
399 
400 // remove_vnode
401 status_t
402 UserlandFS::KernelEmu::remove_vnode(dev_t nsid, ino_t vnid)
403 {
404 	// get the request port and the file system
405 	RequestPort* port;
406 	FileSystem* fileSystem;
407 	status_t error = get_port_and_fs(&port, &fileSystem);
408 	if (error != B_OK)
409 		return error;
410 
411 	// prepare the request
412 	RequestAllocator allocator(port->GetPort());
413 	RemoveVNodeRequest* request;
414 	error = AllocateRequest(allocator, &request);
415 	if (error != B_OK)
416 		return error;
417 
418 	request->nsid = nsid;
419 	request->vnid = vnid;
420 
421 	// send the request
422 	UserlandRequestHandler handler(fileSystem, REMOVE_VNODE_REPLY);
423 	RemoveVNodeReply* reply;
424 	error = port->SendRequest(&allocator, &handler, (Request**)&reply);
425 	if (error != B_OK)
426 		return error;
427 	RequestReleaser requestReleaser(port, reply);
428 
429 	// process the reply
430 	if (reply->error != B_OK)
431 		return reply->error;
432 	return error;
433 }
434 
435 // unremove_vnode
436 status_t
437 UserlandFS::KernelEmu::unremove_vnode(dev_t nsid, ino_t vnid)
438 {
439 	// get the request port and the file system
440 	RequestPort* port;
441 	FileSystem* fileSystem;
442 	status_t error = get_port_and_fs(&port, &fileSystem);
443 	if (error != B_OK)
444 		return error;
445 
446 	// prepare the request
447 	RequestAllocator allocator(port->GetPort());
448 	UnremoveVNodeRequest* request;
449 	error = AllocateRequest(allocator, &request);
450 	if (error != B_OK)
451 		return error;
452 
453 	request->nsid = nsid;
454 	request->vnid = vnid;
455 
456 	// send the request
457 	UserlandRequestHandler handler(fileSystem, UNREMOVE_VNODE_REPLY);
458 	UnremoveVNodeReply* reply;
459 	error = port->SendRequest(&allocator, &handler, (Request**)&reply);
460 	if (error != B_OK)
461 		return error;
462 	RequestReleaser requestReleaser(port, reply);
463 
464 	// process the reply
465 	if (reply->error != B_OK)
466 		return reply->error;
467 	return error;
468 }
469 
470 // get_vnode_removed
471 status_t
472 UserlandFS::KernelEmu::get_vnode_removed(dev_t nsid, ino_t vnid,
473 	bool* removed)
474 {
475 	// get the request port and the file system
476 	RequestPort* port;
477 	FileSystem* fileSystem;
478 	status_t error = get_port_and_fs(&port, &fileSystem);
479 	if (error != B_OK)
480 		return error;
481 
482 	// prepare the request
483 	RequestAllocator allocator(port->GetPort());
484 	GetVNodeRemovedRequest* request;
485 	error = AllocateRequest(allocator, &request);
486 	if (error != B_OK)
487 		return error;
488 
489 	request->nsid = nsid;
490 	request->vnid = vnid;
491 
492 	// send the request
493 	UserlandRequestHandler handler(fileSystem, GET_VNODE_REMOVED_REPLY);
494 	GetVNodeRemovedReply* reply;
495 	error = port->SendRequest(&allocator, &handler, (Request**)&reply);
496 	if (error != B_OK)
497 		return error;
498 	RequestReleaser requestReleaser(port, reply);
499 
500 	// process the reply
501 	*removed = reply->removed;
502 	return reply->error;
503 }
504 
505 // #pragma mark -
506 
507 // kernel_debugger
508 void
509 UserlandFS::KernelEmu::kernel_debugger(const char *message)
510 {
511 	debugger(message);
512 }
513 
514 // vpanic
515 void
516 UserlandFS::KernelEmu::vpanic(const char *format, va_list args)
517 {
518 	char buffer[1024];
519 	strcpy(buffer, "PANIC: ");
520 	int32 prefixLen = strlen(buffer);
521 	int bufferSize = sizeof(buffer) - prefixLen;
522 
523 	// no vsnprintf() on PPC
524 	#if defined(__INTEL__)
525 		vsnprintf(buffer + prefixLen, bufferSize - 1, format, args);
526 	#else
527 		vsprintf(buffer + prefixLen, format, args);
528 	#endif
529 
530 	buffer[sizeof(buffer) - 1] = '\0';
531 	debugger(buffer);
532 }
533 
534 // panic
535 void
536 UserlandFS::KernelEmu::panic(const char *format, ...)
537 {
538 	va_list args;
539 	va_start(args, format);
540 	vpanic(format, args);
541 	va_end(args);
542 }
543 
544 // vdprintf
545 void
546 UserlandFS::KernelEmu::vdprintf(const char *format, va_list args)
547 {
548 	vprintf(format, args);
549 }
550 
551 // dprintf
552 void
553 UserlandFS::KernelEmu::dprintf(const char *format, ...)
554 {
555 	va_list args;
556 	va_start(args, format);
557 	vdprintf(format, args);
558 	va_end(args);
559 }
560 
561 void
562 UserlandFS::KernelEmu::dump_block(const char *buffer, int size,
563 	const char *prefix)
564 {
565 	// TODO: Implement!
566 }
567 
568 // parse_expression
569 //ulong
570 //parse_expression(char *str)
571 //{
572 //	return 0;
573 //}
574 
575 // add_debugger_command
576 int
577 UserlandFS::KernelEmu::add_debugger_command(char *name,
578 	int (*func)(int argc, char **argv), char *help)
579 {
580 	return B_OK;
581 }
582 
583 // remove_debugger_command
584 int
585 UserlandFS::KernelEmu::remove_debugger_command(char *name,
586 	int (*func)(int argc, char **argv))
587 {
588 	return B_OK;
589 }
590 
591 // parse_expression
592 uint32
593 UserlandFS::KernelEmu::parse_expression(const char *string)
594 {
595 	return 0;
596 }
597 
598 
599 // kprintf
600 //void
601 //kprintf(const char *format, ...)
602 //{
603 //}
604 
605 // spawn_kernel_thread
606 thread_id
607 UserlandFS::KernelEmu::spawn_kernel_thread(thread_entry function,
608 	const char *threadName, long priority, void *arg)
609 {
610 	return spawn_thread(function, threadName, priority, arg);
611 }
612