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