1 // UserlandFSServer.cpp 2 3 #include "UserlandFSServer.h" 4 5 #include <new> 6 #include <stdio.h> 7 #include <string.h> 8 9 #include <Application.h> 10 #include <Clipboard.h> 11 #include <FindDirectory.h> 12 #include <fs_interface.h> 13 #include <Locker.h> 14 #include <Path.h> 15 16 #include "AutoDeleter.h" 17 #include "AutoLocker.h" 18 #include "beos_fs_cache.h" 19 #include "beos_fs_interface.h" 20 #include "BeOSKernelFileSystem.h" 21 #include "Compatibility.h" 22 #include "Debug.h" 23 #include "DispatcherDefs.h" 24 #include "FileSystem.h" 25 #include "FSInfo.h" 26 #include "haiku_block_cache_priv.h" 27 #include "haiku_fs_cache.h" 28 #include "HaikuKernelFileSystem.h" 29 #include "RequestThread.h" 30 #include "ServerDefs.h" 31 32 static const int32 kRequestThreadCount = 10; 33 34 static const int32 kMaxBlockCacheBlocks = 16384; 35 36 // constructor 37 UserlandFSServer::UserlandFSServer(const char* signature) 38 : BApplication(signature), 39 fAddOnImage(-1), 40 fFileSystem(NULL), 41 fNotificationRequestPort(NULL), 42 fRequestThreads(NULL), 43 fBlockCacheInitialized(false) 44 { 45 } 46 47 // destructor 48 UserlandFSServer::~UserlandFSServer() 49 { 50 if (fRequestThreads) { 51 for (int32 i = 0; i < kRequestThreadCount; i++) 52 fRequestThreads[i].PrepareTermination(); 53 for (int32 i = 0; i < kRequestThreadCount; i++) 54 fRequestThreads[i].Terminate(); 55 delete[] fRequestThreads; 56 } 57 delete fNotificationRequestPort; 58 delete fFileSystem; 59 if (fBlockCacheInitialized) 60 beos_shutdown_block_cache(); 61 if (fAddOnImage >= 0) 62 unload_add_on(fAddOnImage); 63 } 64 65 // Init 66 status_t 67 UserlandFSServer::Init(const char* fileSystem) 68 { 69 // get the add-on path 70 BPath addOnPath; 71 status_t error = find_directory(B_USER_ADDONS_DIRECTORY, &addOnPath); 72 if (error != B_OK) 73 RETURN_ERROR(error); 74 error = addOnPath.Append("userlandfs"); 75 if (error != B_OK) 76 RETURN_ERROR(error); 77 error = addOnPath.Append(fileSystem); 78 if (error != B_OK) 79 RETURN_ERROR(error); 80 81 // load the add-on 82 fAddOnImage = load_add_on(addOnPath.Path()); 83 if (fAddOnImage < 0) 84 RETURN_ERROR(fAddOnImage); 85 86 // create the FileSystem interface 87 // BeOS kernel interface 88 if (_CreateBeOSKernelInterface(fileSystem, fAddOnImage, &fFileSystem) 89 == B_OK) { 90 // BeOS interface 91 } else if (_CreateHaikuKernelInterface(fileSystem, fAddOnImage, 92 &fFileSystem) == B_OK) { 93 // Haiku interface 94 } else { 95 ERROR(("Add-on doesn't has a supported interface.\n")); 96 } 97 98 // create the notification request port 99 fNotificationRequestPort = new(nothrow) RequestPort(kRequestPortSize); 100 if (!fNotificationRequestPort) 101 RETURN_ERROR(B_NO_MEMORY); 102 error = fNotificationRequestPort->InitCheck(); 103 if (error != B_OK) 104 RETURN_ERROR(error); 105 106 // now create the request threads 107 fRequestThreads = new(nothrow) RequestThread[kRequestThreadCount]; 108 if (!fRequestThreads) 109 RETURN_ERROR(B_NO_MEMORY); 110 for (int32 i = 0; i < kRequestThreadCount; i++) { 111 error = fRequestThreads[i].Init(fFileSystem); 112 if (error != B_OK) 113 RETURN_ERROR(error); 114 } 115 116 // run the threads 117 for (int32 i = 0; i < kRequestThreadCount; i++) 118 fRequestThreads[i].Run(); 119 120 // enter the debugger here, if desired 121 if (gServerSettings.ShallEnterDebugger()) 122 debugger("File system ready to use."); 123 124 // finally register with the dispatcher 125 error = _RegisterWithDispatcher(fileSystem); 126 RETURN_ERROR(error); 127 } 128 129 // GetNotificationRequestPort 130 RequestPort* 131 UserlandFSServer::GetNotificationRequestPort() 132 { 133 if (UserlandFSServer* server = dynamic_cast<UserlandFSServer*>(be_app)) 134 return server->fNotificationRequestPort; 135 return NULL; 136 } 137 138 // GetFileSystem 139 FileSystem* 140 UserlandFSServer::GetFileSystem() 141 { 142 if (UserlandFSServer* server = dynamic_cast<UserlandFSServer*>(be_app)) 143 return server->fFileSystem; 144 return NULL; 145 } 146 147 // _RegisterWithDispatcher 148 status_t 149 UserlandFSServer::_RegisterWithDispatcher(const char* fsName) 150 { 151 // get the dispatcher messenger from the clipboard 152 BMessenger messenger; 153 BClipboard clipboard(kUserlandFSDispatcherClipboardName); 154 if (AutoLocker<BClipboard> locker = clipboard) { 155 status_t error = B_OK; 156 if (BMessage* data = clipboard.Data()) { 157 error = data->FindMessenger("messenger", &messenger); 158 if (error != B_OK) { 159 ERROR(("No dispatcher messenger in clipboard.\n")); 160 return error; 161 } 162 if (!messenger.IsValid()) { 163 ERROR(("Found dispatcher messenger not valid.\n")); 164 return B_ERROR; 165 } 166 } else { 167 ERROR(("Failed to get clipboard data container\n")); 168 return B_ERROR; 169 } 170 } else { 171 ERROR(("Failed to lock the clipboard.\n")); 172 return B_ERROR; 173 } 174 175 // get the port infos 176 Port::Info infos[kRequestThreadCount + 1]; 177 infos[0] = *fNotificationRequestPort->GetPortInfo(); 178 for (int32 i = 0; i < kRequestThreadCount; i++) 179 infos[i + 1] = *fRequestThreads[i].GetPortInfo(); 180 181 // FS capabilities 182 FSCapabilities capabilities; 183 fFileSystem->GetCapabilities(capabilities); 184 185 // init an FS info 186 FSInfo info; 187 status_t error = info.SetTo(fsName, infos, kRequestThreadCount + 1, 188 capabilities); 189 190 // prepare the message 191 BMessage message(UFS_REGISTER_FS); 192 if (error == B_OK) 193 error = message.AddInt32("team", Team()); 194 if (error == B_OK) 195 error = info.Archive(&message); 196 197 // send the message 198 BMessage reply; 199 error = messenger.SendMessage(&message, &reply); 200 if (error == B_OK && reply.what != UFS_REGISTER_FS_ACK) { 201 ERROR(("FS registration failed.\n")); 202 error = B_ERROR; 203 } 204 return error; 205 } 206 207 // _CreateBeOSKernelInterface 208 status_t 209 UserlandFSServer::_CreateBeOSKernelInterface(const char* fsName, image_id image, 210 FileSystem** _fileSystem) 211 { 212 // get the symbols "fs_entry" and "api_version" 213 beos_vnode_ops* fsOps; 214 status_t error = get_image_symbol(image, "fs_entry", B_SYMBOL_TYPE_DATA, 215 (void**)&fsOps); 216 if (error != B_OK) 217 RETURN_ERROR(error); 218 int32* apiVersion; 219 error = get_image_symbol(image, "api_version", B_SYMBOL_TYPE_DATA, 220 (void**)&apiVersion); 221 if (error != B_OK) 222 RETURN_ERROR(error); 223 224 // check api version 225 if (*apiVersion != BEOS_FS_API_VERSION) 226 RETURN_ERROR(B_ERROR); 227 228 // create the file system 229 BeOSKernelFileSystem* fileSystem = new(nothrow) BeOSKernelFileSystem(fsOps); 230 if (!fileSystem) 231 RETURN_ERROR(B_NO_MEMORY); 232 ObjectDeleter<BeOSKernelFileSystem> fsDeleter(fileSystem); 233 234 // init the block cache 235 error = beos_init_block_cache(kMaxBlockCacheBlocks, 0); 236 if (error != B_OK) 237 RETURN_ERROR(error); 238 fBlockCacheInitialized = true; 239 240 // everything went fine 241 fsDeleter.Detach(); 242 *_fileSystem = fileSystem; 243 return B_OK; 244 } 245 246 // _CreateHaikuKernelInterface 247 status_t 248 UserlandFSServer::_CreateHaikuKernelInterface(const char* fsName, 249 image_id image, FileSystem** _fileSystem) 250 { 251 // get the modules 252 module_info** modules; 253 status_t error = get_image_symbol(image, "modules", B_SYMBOL_TYPE_DATA, 254 (void**)&modules); 255 if (error != B_OK) 256 RETURN_ERROR(error); 257 258 // module name must match "file_systems/<name>/v1" 259 char moduleName[B_PATH_NAME_LENGTH]; 260 snprintf(moduleName, sizeof(moduleName), "file_systems/%s/v1", fsName); 261 262 // find the module 263 file_system_module_info* module = NULL; 264 for (int32 i = 0; modules[i]->name; i++) { 265 if (strcmp(modules[i]->name, moduleName) == 0) { 266 module = (file_system_module_info*)modules[i]; 267 break; 268 } 269 } 270 if (!module) 271 RETURN_ERROR(B_ERROR); 272 273 // create the file system 274 HaikuKernelFileSystem* fileSystem 275 = new(nothrow) HaikuKernelFileSystem(module); 276 if (!fileSystem) 277 RETURN_ERROR(B_NO_MEMORY); 278 ObjectDeleter<HaikuKernelFileSystem> fsDeleter(fileSystem); 279 280 // init block cache 281 error = UserlandFS::HaikuKernelEmu::block_cache_init(); 282 if (error != B_OK) 283 RETURN_ERROR(error); 284 285 // init file cache 286 error = UserlandFS::HaikuKernelEmu::file_cache_init(); 287 if (error != B_OK) 288 RETURN_ERROR(error); 289 290 // init the FS 291 error = fileSystem->Init(); 292 if (error != B_OK) 293 return error; 294 295 // everything went fine 296 fsDeleter.Detach(); 297 *_fileSystem = fileSystem; 298 return B_OK; 299 } 300