/* * Copyright 2001-2009, Ingo Weinhold, ingo_weinhold@gmx.de. * Distributed under the terms of the MIT License. */ #include "UserlandFSServer.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include "AutoDeleter.h" #include "AutoLocker.h" #include "Compatibility.h" #include "Debug.h" #include "FileSystem.h" #include "RequestThread.h" #include "ServerDefs.h" #include "UserlandFSDefs.h" static const int32 kRequestThreadCount = 10; // constructor UserlandFSServer::UserlandFSServer(const char* signature) : BApplication(signature), fAddOnImage(-1), fFileSystem(NULL), fNotificationRequestPort(NULL), fRequestThreads(NULL) { } // destructor UserlandFSServer::~UserlandFSServer() { if (fRequestThreads) { for (int32 i = 0; i < kRequestThreadCount; i++) fRequestThreads[i].PrepareTermination(); for (int32 i = 0; i < kRequestThreadCount; i++) fRequestThreads[i].Terminate(); delete[] fRequestThreads; } delete fNotificationRequestPort; delete fFileSystem; if (fAddOnImage >= 0) unload_add_on(fAddOnImage); } // Init status_t UserlandFSServer::Init(const char* fileSystem, port_id port) { // get the add-on path BPathFinder pathFinder; BStringList paths; status_t error = pathFinder.FindPaths(B_FIND_PATH_ADD_ONS_DIRECTORY, "userlandfs", B_FIND_PATH_EXISTING_ONLY, paths); if (error != B_OK) RETURN_ERROR(error); BPath addOnPath; for (int index = 0; index < paths.CountStrings(); index++) { error = addOnPath.SetTo(paths.StringAt(index)); if (error != B_OK) RETURN_ERROR(error); error = addOnPath.Append(fileSystem); if (error != B_OK) RETURN_ERROR(error); BEntry entry(addOnPath.Path()); if (entry.Exists()) break; else addOnPath.Unset(); } if (addOnPath.InitCheck() != B_OK) RETURN_ERROR(B_BAD_VALUE); // load the add-on fAddOnImage = load_add_on(addOnPath.Path()); if (fAddOnImage < 0) RETURN_ERROR(fAddOnImage); // Get the FS creation function -- the add-on links against one of our // libraries exporting that function, so we search recursively. union { void* address; status_t (*function)(const char*, image_id, FileSystem**); } createFSFunction; error = get_image_symbol_etc(fAddOnImage, "userlandfs_create_file_system", B_SYMBOL_TYPE_TEXT, true, NULL, &createFSFunction.address); if (error != B_OK) RETURN_ERROR(error); // create the FileSystem interface error = createFSFunction.function(fileSystem, fAddOnImage, &fFileSystem); if (error != B_OK) RETURN_ERROR(error); // create the notification request port fNotificationRequestPort = new(std::nothrow) RequestPort(kRequestPortSize); if (!fNotificationRequestPort) RETURN_ERROR(B_NO_MEMORY); error = fNotificationRequestPort->InitCheck(); if (error != B_OK) RETURN_ERROR(error); // now create the request threads fRequestThreads = new(std::nothrow) RequestThread[kRequestThreadCount]; if (!fRequestThreads) RETURN_ERROR(B_NO_MEMORY); for (int32 i = 0; i < kRequestThreadCount; i++) { error = fRequestThreads[i].Init(fFileSystem); if (error != B_OK) RETURN_ERROR(error); } // run the threads for (int32 i = 0; i < kRequestThreadCount; i++) fRequestThreads[i].Run(); // enter the debugger here, if desired if (gServerSettings.ShallEnterDebugger()) debugger("File system ready to use."); // finally announce our existence error = _Announce(fileSystem, port); RETURN_ERROR(error); } // GetNotificationRequestPort RequestPort* UserlandFSServer::GetNotificationRequestPort() { if (UserlandFSServer* server = dynamic_cast(be_app)) return server->fNotificationRequestPort; return NULL; } // GetFileSystem FileSystem* UserlandFSServer::GetFileSystem() { if (UserlandFSServer* server = dynamic_cast(be_app)) return server->fFileSystem; return NULL; } // _Announce status_t UserlandFSServer::_Announce(const char* fsName, port_id port) { // if not given, create a port if (port < 0) { char portName[B_OS_NAME_LENGTH]; snprintf(portName, sizeof(portName), "_userlandfs_%s", fsName); port = create_port(1, portName); if (port < 0) RETURN_ERROR(port); } // allocate stack space for the FS initialization info const size_t bufferSize = sizeof(fs_init_info) + sizeof(Port::Info) * (kRequestThreadCount + 1); char buffer[bufferSize]; fs_init_info* info = (fs_init_info*)buffer; // get the port infos info->portInfoCount = kRequestThreadCount + 1; info->portInfos[0] = *fNotificationRequestPort->GetPortInfo(); for (int32 i = 0; i < kRequestThreadCount; i++) info->portInfos[i + 1] = *fRequestThreads[i].GetPortInfo(); // FS capabilities fFileSystem->GetCapabilities(info->capabilities); info->clientFSType = fFileSystem->GetClientFSType(); // send the info to our port RETURN_ERROR(write_port(port, 0, buffer, bufferSize)); }