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