1// UserlandFSServer.cpp 2 3#include <new> 4#include <stdio.h> 5#include <string.h> 6 7#include <Application.h> 8#include <cache.h> 9#include <Clipboard.h> 10#include <FindDirectory.h> 11#include <fsproto.h> 12#include <image.h> 13#include <Locker.h> 14#include <Path.h> 15 16#include "AutoLocker.h" 17#include "Compatibility.h" 18#include "Debug.h" 19#include "DispatcherDefs.h" 20#include "FSInfo.h" 21#include "KernelUserFileSystem.h" 22#include "RequestThread.h" 23#include "ServerDefs.h" 24#include "UserFileSystem.h" 25#include "UserlandFSServer.h" 26 27static const int32 kRequestThreadCount = 10; 28 29static const int32 kMaxBlockCacheBlocks = 16384; 30 31// constructor 32UserlandFSServer::UserlandFSServer(const char* signature) 33 : BApplication(signature), 34 fAddOnImage(-1), 35 fFileSystem(NULL), 36 fNotificationRequestPort(NULL), 37 fRequestThreads(NULL), 38 fBlockCacheInitialized(false) 39{ 40} 41 42// destructor 43UserlandFSServer::~UserlandFSServer() 44{ 45 if (fRequestThreads) { 46 for (int32 i = 0; i < kRequestThreadCount; i++) 47 fRequestThreads[i].PrepareTermination(); 48 for (int32 i = 0; i < kRequestThreadCount; i++) 49 fRequestThreads[i].Terminate(); 50 delete[] fRequestThreads; 51 } 52 delete fNotificationRequestPort; 53 delete fFileSystem; 54 if (fBlockCacheInitialized) 55 shutdown_block_cache(); 56 if (fAddOnImage >= 0) 57 unload_add_on(fAddOnImage); 58} 59 60// Init 61status_t 62UserlandFSServer::Init(const char* fileSystem) 63{ 64 // get the add-on path 65 BPath addOnPath; 66 status_t error = find_directory(B_USER_ADDONS_DIRECTORY, &addOnPath); 67 if (error != B_OK) 68 RETURN_ERROR(error); 69 error = addOnPath.Append("userlandfs"); 70 if (error != B_OK) 71 RETURN_ERROR(error); 72 error = addOnPath.Append(fileSystem); 73 if (error != B_OK) 74 RETURN_ERROR(error); 75 // load the add-on 76 fAddOnImage = load_add_on(addOnPath.Path()); 77 if (fAddOnImage < 0) 78 RETURN_ERROR(fAddOnImage); 79 // get the symbols "fs_entry" and "api_version" 80 vnode_ops* fsOps; 81 error = get_image_symbol(fAddOnImage, "fs_entry", B_SYMBOL_TYPE_TEXT, 82 (void**)&fsOps); 83 if (error != B_OK) 84 RETURN_ERROR(error); 85 int32* apiVersion; 86 error = get_image_symbol(fAddOnImage, "api_version", B_SYMBOL_TYPE_DATA, 87 (void**)&apiVersion); 88 if (error != B_OK) 89 RETURN_ERROR(error); 90 // check api version 91 if (*apiVersion != B_CUR_FS_API_VERSION) 92 RETURN_ERROR(B_ERROR); 93 // create the file system 94 fFileSystem = new(nothrow) KernelUserFileSystem(fsOps); 95 if (!fileSystem) 96 RETURN_ERROR(B_NO_MEMORY); 97 // init the block cache 98 error = init_block_cache(kMaxBlockCacheBlocks, 0); 99 if (error != B_OK) 100 RETURN_ERROR(error); 101 fBlockCacheInitialized = true; 102 // create the notification request port 103 fNotificationRequestPort = new(nothrow) RequestPort(kRequestPortSize); 104 if (!fNotificationRequestPort) 105 RETURN_ERROR(B_NO_MEMORY); 106 error = fNotificationRequestPort->InitCheck(); 107 if (error != B_OK) 108 RETURN_ERROR(error); 109 // now create the request threads 110 fRequestThreads = new(nothrow) RequestThread[kRequestThreadCount]; 111 if (!fRequestThreads) 112 RETURN_ERROR(B_NO_MEMORY); 113 for (int32 i = 0; i < kRequestThreadCount; i++) { 114 error = fRequestThreads[i].Init(fFileSystem); 115 if (error != B_OK) 116 RETURN_ERROR(error); 117 } 118 // run the threads 119 for (int32 i = 0; i < kRequestThreadCount; i++) 120 fRequestThreads[i].Run(); 121 // enter the debugger here, if desired 122 if (gServerSettings.ShallEnterDebugger()) 123 debugger("File system ready to use."); 124 // finally register with the dispatcher 125 error = _RegisterWithDispatcher(fileSystem); 126 RETURN_ERROR(error); 127} 128 129// GetNotificationRequestPort 130RequestPort* 131UserlandFSServer::GetNotificationRequestPort() 132{ 133 if (UserlandFSServer* server = dynamic_cast<UserlandFSServer*>(be_app)) 134 return server->fNotificationRequestPort; 135 return NULL; 136} 137 138// GetFileSystem 139UserFileSystem* 140UserlandFSServer::GetFileSystem() 141{ 142 if (UserlandFSServer* server = dynamic_cast<UserlandFSServer*>(be_app)) 143 return server->fFileSystem; 144 return NULL; 145} 146 147// _RegisterWithDispatcher 148status_t 149UserlandFSServer::_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 // get the port infos 175 Port::Info infos[kRequestThreadCount + 1]; 176 infos[0] = *fNotificationRequestPort->GetPortInfo(); 177 for (int32 i = 0; i < kRequestThreadCount; i++) 178 infos[i + 1] = *fRequestThreads[i].GetPortInfo(); 179 // init an FS info 180 FSInfo info; 181 status_t error = info.SetTo(fsName, infos, kRequestThreadCount + 1); 182 // prepare the message 183 BMessage message(UFS_REGISTER_FS); 184 if (error == B_OK) 185 error = message.AddInt32("team", Team()); 186 if (error == B_OK) 187 error = info.Archive(&message); 188 // send the message 189 BMessage reply; 190 error = messenger.SendMessage(&message, &reply); 191 if (error == B_OK && reply.what != UFS_REGISTER_FS_ACK) { 192 ERROR(("FS registration failed.\n")); 193 error = B_ERROR; 194 } 195 return error; 196} 197 198