xref: /haiku/src/add-ons/kernel/file_systems/userlandfs/server/UserlandFSServer.cpp (revision adb0d19d561947362090081e81d90dde59142026)
1 /*
2  * Copyright 2001-2009, Ingo Weinhold, ingo_weinhold@gmx.de.
3  * Distributed under the terms of the MIT License.
4  */
5 
6 #include "UserlandFSServer.h"
7 
8 #include <new>
9 #include <stdio.h>
10 #include <string.h>
11 
12 #include <Application.h>
13 #include <Clipboard.h>
14 #include <FindDirectory.h>
15 #include <fs_interface.h>
16 #include <Locker.h>
17 #include <Path.h>
18 
19 #include <image_private.h>
20 
21 #include "AutoDeleter.h"
22 #include "AutoLocker.h"
23 #include "Compatibility.h"
24 #include "Debug.h"
25 #include "FileSystem.h"
26 #include "RequestThread.h"
27 #include "ServerDefs.h"
28 #include "UserlandFSDefs.h"
29 
30 
31 static const int32 kRequestThreadCount = 10;
32 
33 
34 // constructor
35 UserlandFSServer::UserlandFSServer(const char* signature)
36 	: BApplication(signature),
37 	  fAddOnImage(-1),
38 	  fFileSystem(NULL),
39 	  fNotificationRequestPort(NULL),
40 	  fRequestThreads(NULL)
41 {
42 }
43 
44 
45 // destructor
46 UserlandFSServer::~UserlandFSServer()
47 {
48 	if (fRequestThreads) {
49 		for (int32 i = 0; i < kRequestThreadCount; i++)
50 			fRequestThreads[i].PrepareTermination();
51 		for (int32 i = 0; i < kRequestThreadCount; i++)
52 			fRequestThreads[i].Terminate();
53 		delete[] fRequestThreads;
54 	}
55 	delete fNotificationRequestPort;
56 	delete fFileSystem;
57 	if (fAddOnImage >= 0)
58 		unload_add_on(fAddOnImage);
59 }
60 
61 
62 // Init
63 status_t
64 UserlandFSServer::Init(const char* fileSystem, port_id port)
65 {
66 	// get the add-on path
67 	BPath addOnPath;
68 	status_t error = find_directory(B_USER_ADDONS_DIRECTORY, &addOnPath);
69 	if (error != B_OK)
70 		RETURN_ERROR(error);
71 	error = addOnPath.Append("userlandfs");
72 	if (error != B_OK)
73 		RETURN_ERROR(error);
74 	error = addOnPath.Append(fileSystem);
75 	if (error != B_OK)
76 		RETURN_ERROR(error);
77 
78 	// load the add-on
79 	fAddOnImage = load_add_on(addOnPath.Path());
80 	if (fAddOnImage < 0)
81 		RETURN_ERROR(fAddOnImage);
82 
83 	// Get the FS creation function -- the add-on links against one of our
84 	// libraries exporting that function, so we search recursively.
85 	union {
86 		void* address;
87 		status_t (*function)(const char*, image_id, FileSystem**);
88 	} createFSFunction;
89 	error = get_image_symbol_etc(fAddOnImage, "userlandfs_create_file_system",
90 		B_SYMBOL_TYPE_TEXT, true, NULL, &createFSFunction.address);
91 	if (error != B_OK)
92 		RETURN_ERROR(error);
93 
94 	// create the FileSystem interface
95 	error = createFSFunction.function(fileSystem, fAddOnImage, &fFileSystem);
96 	if (error != B_OK)
97 		RETURN_ERROR(error);
98 
99 	// create the notification request port
100 	fNotificationRequestPort = new(std::nothrow) RequestPort(kRequestPortSize);
101 	if (!fNotificationRequestPort)
102 		RETURN_ERROR(B_NO_MEMORY);
103 	error = fNotificationRequestPort->InitCheck();
104 	if (error != B_OK)
105 		RETURN_ERROR(error);
106 
107 	// now create the request threads
108 	fRequestThreads = new(std::nothrow) RequestThread[kRequestThreadCount];
109 	if (!fRequestThreads)
110 		RETURN_ERROR(B_NO_MEMORY);
111 	for (int32 i = 0; i < kRequestThreadCount; i++) {
112 		error = fRequestThreads[i].Init(fFileSystem);
113 		if (error != B_OK)
114 			RETURN_ERROR(error);
115 	}
116 
117 	// run the threads
118 	for (int32 i = 0; i < kRequestThreadCount; i++)
119 		fRequestThreads[i].Run();
120 
121 	// enter the debugger here, if desired
122 	if (gServerSettings.ShallEnterDebugger())
123 		debugger("File system ready to use.");
124 
125 	// finally announce our existence
126 	error = _Announce(fileSystem, port);
127 	RETURN_ERROR(error);
128 }
129 
130 
131 // GetNotificationRequestPort
132 RequestPort*
133 UserlandFSServer::GetNotificationRequestPort()
134 {
135 	if (UserlandFSServer* server = dynamic_cast<UserlandFSServer*>(be_app))
136 		return server->fNotificationRequestPort;
137 	return NULL;
138 }
139 
140 
141 // GetFileSystem
142 FileSystem*
143 UserlandFSServer::GetFileSystem()
144 {
145 	if (UserlandFSServer* server = dynamic_cast<UserlandFSServer*>(be_app))
146 		return server->fFileSystem;
147 	return NULL;
148 }
149 
150 
151 // _Announce
152 status_t
153 UserlandFSServer::_Announce(const char* fsName, port_id port)
154 {
155 	// if not given, create a port
156 	if (port < 0) {
157 		char portName[B_OS_NAME_LENGTH];
158 		snprintf(portName, sizeof(portName), "_userlandfs_%s", fsName);
159 
160 		port = create_port(1, portName);
161 		if (port < 0)
162 			RETURN_ERROR(port);
163 	}
164 
165 	// allocate stack space for the FS initialization info
166 	const size_t bufferSize = sizeof(fs_init_info)
167 		+ sizeof(Port::Info) * (kRequestThreadCount + 1);
168 	char buffer[bufferSize];
169 	fs_init_info* info = (fs_init_info*)buffer;
170 
171 	// get the port infos
172 	info->portInfoCount = kRequestThreadCount + 1;
173 	info->portInfos[0] = *fNotificationRequestPort->GetPortInfo();
174 	for (int32 i = 0; i < kRequestThreadCount; i++)
175 		info->portInfos[i + 1] = *fRequestThreads[i].GetPortInfo();
176 
177 	// FS capabilities
178 	fFileSystem->GetCapabilities(info->capabilities);
179 	info->clientFSType = fFileSystem->GetClientFSType();
180 
181 	// send the info to our port
182 	RETURN_ERROR(write_port(port, 0, buffer, bufferSize));
183 }
184