1/*
2 * Copyright 2001-2009, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Distributed under the terms of the MIT License.
4 */
5
6#include "FileSystemInitializer.h"
7
8#include <new>
9
10#include <image.h>
11#include <OS.h>
12
13#include <port.h>
14#include <team.h>
15
16#include "AutoDeleter.h"
17
18#include "FileSystem.h"
19#include "RequestAllocator.h"
20#include "RequestPort.h"
21#include "Requests.h"
22#include "SingleReplyRequestHandler.h"
23#include "UserlandFSDefs.h"
24
25
26// constructor
27FileSystemInitializer::FileSystemInitializer(const char* name)
28	:
29	BReferenceable(),
30	fName(name),
31	fFileSystem(NULL)
32{
33	// Note: We don't copy the name. It's only needed in FirstTimeInit() and
34	// the UserlandFS makes sure it is valid until then.
35}
36
37
38// destructor
39FileSystemInitializer::~FileSystemInitializer()
40{
41	delete fFileSystem;
42}
43
44
45// FirstTimeInit
46status_t
47FileSystemInitializer::FirstTimeInit()
48{
49	// First check whether a server for this FS is already loaded. Look for a
50	// port with the respective name.
51	char portName[B_OS_NAME_LENGTH];
52	snprintf(portName, sizeof(portName), "_userlandfs_%s", fName);
53
54	port_id port = find_port(portName);
55	if (port >= 0)
56		return _Init(port);
57
58	// We have to start the server ourselves. First create the port we're going
59	// to use.
60	port = create_port(1, portName);
61	if (port < 0)
62		RETURN_ERROR(port);
63
64	// prepare the command line arguments
65	char portID[16];
66	snprintf(portID, sizeof(portID), "%" B_PRId32, port);
67
68	const char* args[4] = {
69		"/system/servers/userlandfs_server",
70		fName,
71		portID,
72		NULL
73	};
74
75	// start the server
76	thread_id thread = load_image_etc(3, args, NULL, B_NORMAL_PRIORITY,
77		B_SYSTEM_TEAM, 0);
78	if (thread < 0) {
79		delete_port(port);
80		RETURN_ERROR(thread);
81	}
82
83	// let it own the port and start the team
84	status_t error = set_port_owner(port, thread);
85	if (error == B_OK)
86		resume_thread(thread);
87
88	// and do the initialization
89	if (error == B_OK)
90		error = _Init(port);
91
92	if (error != B_OK) {
93		kill_team(thread);
94		delete_port(port);
95		RETURN_ERROR(error);
96	}
97
98	return B_OK;
99}
100
101
102void
103FileSystemInitializer::LastReferenceReleased()
104{
105	// don't delete
106}
107
108
109status_t
110FileSystemInitializer::_Init(port_id port)
111{
112	// allocate a buffer for the FS info
113	const size_t bufferSize = 1024;
114	fs_init_info* info = (fs_init_info*)malloc(bufferSize);
115	MemoryDeleter _(info);
116
117	// Read the info -- we peek only, so it won't go away and we can do the
118	// initialization again, in case we get completely unloaded are reloaded
119	// later.
120	ssize_t bytesRead = read_port_etc(port, NULL, info, bufferSize,
121	    B_PEEK_PORT_MESSAGE | B_CAN_INTERRUPT, 0);
122	if (bytesRead < 0)
123		RETURN_ERROR(bytesRead);
124
125	// sanity check
126	if ((size_t)bytesRead < sizeof(fs_init_info)
127		|| info->portInfoCount < 2
128		|| (size_t)bytesRead < sizeof(fs_init_info)
129			+ info->portInfoCount * sizeof(Port::Info)) {
130		RETURN_ERROR(B_BAD_DATA);
131	}
132
133	// get the port's team
134	port_info portInfo;
135	status_t error = get_port_info(port, &portInfo);
136	if (error != B_OK)
137		RETURN_ERROR(error);
138
139	// create and init the FileSystem
140	fFileSystem = new(std::nothrow) FileSystem;
141	if (!fFileSystem)
142		return B_NO_MEMORY;
143
144	error = fFileSystem->Init(fName, portInfo.team, info->portInfos,
145		info->portInfoCount, info->capabilities);
146	if (error != B_OK)
147		RETURN_ERROR(error);
148
149	return B_OK;
150}
151