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