xref: /haiku/src/add-ons/kernel/file_systems/netfs/client/RootVolume.cpp (revision 13581b3d2a71545960b98fefebc5225b5bf29072)
1 // RootVolume.cpp
2 
3 #include "RootVolume.h"
4 
5 #include <new>
6 
7 #include <AutoLocker.h>
8 
9 #include "Compatibility.h"
10 #include "DebugSupport.h"
11 #include "ExtendedServerInfo.h"
12 #include "NetAddress.h"
13 #include "netfs_ioctl.h"
14 #include "ServerVolume.h"
15 #include "TaskManager.h"
16 #include "VolumeManager.h"
17 #include "VolumeSupport.h"
18 
19 static const int32 kOptimalIOSize = 64 * 1024;
20 static const char* kFSName = "netfs";
21 
22 // constructor
23 RootVolume::RootVolume(VolumeManager* volumeManager)
24 	: VirtualVolume(volumeManager)
25 {
26 }
27 
28 // destructor
29 RootVolume::~RootVolume()
30 {
31 }
32 
33 // Init
34 status_t
35 RootVolume::Init()
36 {
37 	status_t error = VirtualVolume::Init("Network");
38 	if (error != B_OK)
39 		return error;
40 
41 	// create and init the server manager
42 	fServerManager = new(std::nothrow) ServerManager(this);
43 	if (!fServerManager)
44 		RETURN_ERROR(B_NO_MEMORY);
45 	error = fServerManager->Init();
46 	if (error != B_OK)
47 		RETURN_ERROR(error);
48 
49 	return B_OK;
50 }
51 
52 // Uninit
53 void
54 RootVolume::Uninit()
55 {
56 	// delete the server manager
57 	delete fServerManager;
58 	fServerManager = NULL;
59 
60 	VirtualVolume::Uninit();
61 }
62 
63 // PrepareToUnmount
64 void
65 RootVolume::PrepareToUnmount()
66 {
67 	VirtualVolume::PrepareToUnmount();
68 }
69 
70 
71 // #pragma mark -
72 // #pragma mark ----- FS -----
73 
74 // Mount
75 status_t
76 RootVolume::Mount(const char* device, uint32 flags, const char* parameters,
77 	int32 len)
78 {
79 	status_t error = NewVNode(fRootNode->GetID(), fRootNode);
80 	if (error != B_OK)
81 		RETURN_ERROR(error);
82 
83 	// start the server manager
84 	fServerManager->Run();
85 
86 	return B_OK;
87 }
88 
89 // Unmount
90 status_t
91 RootVolume::Unmount()
92 {
93 	Uninit();
94 	return B_OK;
95 }
96 
97 // Sync
98 status_t
99 RootVolume::Sync()
100 {
101 	return B_BAD_VALUE;
102 }
103 
104 // ReadFSStat
105 status_t
106 RootVolume::ReadFSStat(fs_info* info)
107 {
108 	info->flags = B_FS_IS_PERSISTENT | B_FS_HAS_MIME | B_FS_HAS_ATTR
109 		| B_FS_IS_SHARED | B_FS_HAS_QUERY;
110 	if (fVolumeManager->GetMountFlags() & B_MOUNT_READ_ONLY)
111 		info->flags |= B_FS_IS_READONLY;
112 	info->block_size = 1024;
113 	info->io_size = kOptimalIOSize;
114 	info->total_blocks = 0;	// TODO: We could at least fill this in.
115 	info->free_blocks = LONGLONG_MAX / info->block_size;
116 		// keep the Tracker happy
117 	strcpy(info->device_name, "");
118 	strcpy(info->volume_name, GetName());
119 	strcpy(info->fsh_name, kFSName);
120 	return B_OK;
121 }
122 
123 // WriteFSStat
124 status_t
125 RootVolume::WriteFSStat(struct fs_info* info, int32 mask)
126 {
127 	// TODO: Allow editing the volume name.
128 	return B_BAD_VALUE;
129 }
130 
131 // #pragma mark -
132 // #pragma mark ----- files -----
133 
134 // IOCtl
135 status_t
136 RootVolume::IOCtl(Node* node, void* cookie, int cmd, void* buffer,
137 	size_t bufferSize)
138 {
139 	if (node != fRootNode)
140 		return B_BAD_VALUE;
141 
142 	switch (cmd) {
143 		case NET_FS_IOCTL_ADD_SERVER:
144 		{
145 			// check the parameters
146 			if (!buffer)
147 				return B_BAD_VALUE;
148 			netfs_ioctl_add_server* params = (netfs_ioctl_add_server*)buffer;
149 			int32 serverNameLen = strnlen(params->serverName,
150 				sizeof(params->serverName));
151 			if (serverNameLen == 0
152 				|| serverNameLen == sizeof(params->serverName)) {
153 				return B_BAD_VALUE;
154 			}
155 			PRINT("RootVolume::IOCtl(): NET_FS_IOCTL_ADD_SERVER: "
156 				"`%s'\n", params->serverName);
157 
158 			// get the server address
159 			NetAddress netAddress;
160 			NetAddressResolver resolver;
161 			status_t error = resolver.GetHostAddress(params->serverName, &netAddress);
162 			if (error != B_OK)
163 				return error;
164 
165 			// ask the server manager to add the server
166 			return fServerManager->AddServer(netAddress);
167 		}
168 		case NET_FS_IOCTL_REMOVE_SERVER:
169 		{
170 			// check the parameters
171 			if (!buffer)
172 				return B_BAD_VALUE;
173 			netfs_ioctl_remove_server* params
174 				= (netfs_ioctl_remove_server*)buffer;
175 			int32 serverNameLen = strnlen(params->serverName,
176 				sizeof(params->serverName));
177 			if (serverNameLen == 0
178 				|| serverNameLen == sizeof(params->serverName)) {
179 				return B_BAD_VALUE;
180 			}
181 			PRINT("RootVolume::IOCtl(): NET_FS_IOCTL_REMOVE_SERVER:"
182 				" `%s'\n", params->serverName);
183 
184 			// get the server volume
185 			ServerVolume* serverVolume = _GetServerVolume(params->serverName);
186 			if (!serverVolume)
187 				return B_ENTRY_NOT_FOUND;
188 			VolumePutter volumePutter(serverVolume);
189 
190 			// ask the server manager to remove the server
191 			fServerManager->RemoveServer(serverVolume->GetServerAddress());
192 
193 			return B_OK;
194 		}
195 		default:
196 			PRINT("RootVolume::IOCtl(): unknown ioctl: %d\n", cmd);
197 			return B_BAD_VALUE;
198 			break;
199 	}
200 	return B_BAD_VALUE;
201 }
202 
203 
204 // #pragma mark -
205 
206 // ServerAdded
207 void
208 RootVolume::ServerAdded(ExtendedServerInfo* serverInfo)
209 {
210 	PRINT("RootVolume::ServerAdded(%s)\n", serverInfo->GetServerName());
211 	// check, if the server does already exist
212 	ServerVolume* serverVolume = _GetServerVolume(serverInfo->GetAddress());
213 	if (serverVolume) {
214 		WARN("RootVolume::ServerAdded(): WARNING: ServerVolume does "
215 			"already exist.\n");
216 		serverVolume->PutVolume();
217 		return;
218 	}
219 
220 	AutoLocker<Locker> locker(fLock);
221 
222 	// get a unique name for the server
223 	char serverName[B_FILE_NAME_LENGTH];
224 	status_t error = GetUniqueEntryName(serverInfo->GetServerName(),
225 		serverName);
226 	if (error != B_OK)
227 		return;
228 
229 	// create a server volume
230 	serverVolume = new(std::nothrow) ServerVolume(fVolumeManager, serverInfo);
231 	if (!serverVolume)
232 		return;
233 	error = serverVolume->Init(serverName);
234 	if (error != B_OK) {
235 		delete serverVolume;
236 		return;
237 	}
238 
239 	// add the volume to the volume manager
240 	error = fVolumeManager->AddVolume(serverVolume);
241 	if (error != B_OK) {
242 		delete serverVolume;
243 		return;
244 	}
245 	VolumePutter volumePutter(serverVolume);
246 
247 	// add the volume to us
248 	locker.Unlock();
249 	error = AddChildVolume(serverVolume);
250 	if (error != B_OK) {
251 		serverVolume->SetUnmounting(true);
252 		return;
253 	}
254 }
255 
256 // ServerUpdated
257 void
258 RootVolume::ServerUpdated(ExtendedServerInfo* oldInfo,
259 	ExtendedServerInfo* newInfo)
260 {
261 	PRINT("RootVolume::ServerUpdated(%s)\n", newInfo->GetServerName());
262 	// get the volume
263 	ServerVolume* serverVolume = _GetServerVolume(newInfo->GetAddress());
264 	if (!serverVolume)
265 		return;
266 
267 	// set the new server info
268 	VolumePutter _(serverVolume);
269 	serverVolume->SetServerInfo(newInfo);
270 }
271 
272 // ServerRemoved
273 void
274 RootVolume::ServerRemoved(ExtendedServerInfo* serverInfo)
275 {
276 	PRINT("RootVolume::ServerRemoved(%s)\n", serverInfo->GetServerName());
277 	// get the volume
278 	ServerVolume* serverVolume = _GetServerVolume(serverInfo->GetAddress());
279 	if (!serverVolume)
280 		return;
281 
282 	// set it to unmounting
283 	VolumePutter _(serverVolume);
284 	serverVolume->SetUnmounting(true);
285 }
286 
287 
288 // #pragma mark -
289 
290 // _GetServerVolume
291 ServerVolume*
292 RootVolume::_GetServerVolume(const char* name)
293 {
294 	Volume* volume = GetChildVolume(name);
295 	if (!volume)
296 		return NULL;
297 	if (ServerVolume* serverVolume = dynamic_cast<ServerVolume*>(volume))
298 		return serverVolume;
299 	fVolumeManager->PutVolume(volume);
300 	return NULL;
301 }
302 
303 // _GetServerVolume
304 ServerVolume*
305 RootVolume::_GetServerVolume(const NetAddress& address)
306 {
307 	AutoLocker<Locker> locker(fLock);
308 
309 	// init a directory iterator
310 	VirtualDirIterator iterator;
311 	iterator.SetDirectory(fRootNode, true);
312 
313 	// iterate through the directory
314 	const char* name;
315 	Node* node;
316 	while (iterator.GetCurrentEntry(&name, &node)) {
317 		iterator.NextEntry();
318 		ServerVolume* volume = dynamic_cast<ServerVolume*>(node->GetVolume());
319 		if (volume && volume->GetServerAddress().GetIP() == address.GetIP()) {
320 			return dynamic_cast<ServerVolume*>(
321 				fVolumeManager->GetVolume(node->GetID()));
322 		}
323 	}
324 
325 	return NULL;
326 }
327 
328