xref: /haiku/src/add-ons/kernel/file_systems/netfs/server/ClientVolume.cpp (revision d17092ceb18bf47a96dbaf8a1acf10e6e3070704)
1 // ClientVolume.cpp
2 
3 #include <new>
4 
5 #include <AutoDeleter.h>
6 #include <AutoLocker.h>
7 #include <HashMap.h>
8 #include <Path.h>
9 
10 #include "ClientVolume.h"
11 #include "DebugSupport.h"
12 #include "Directory.h"
13 #include "Entry.h"
14 #include "GlobalBlockerPool.h"
15 #include "NodeHandle.h"
16 #include "NodeHandleMap.h"
17 #include "NodeMonitoringEvent.h"
18 #include "SecurityContext.h"
19 #include "StatisticsManager.h"
20 #include "UserSecurityContext.h"
21 #include "Volume.h"
22 #include "VolumeManager.h"
23 
24 // constructor
25 ClientVolume::ClientVolume(Locker& securityContextLocker,
26 	NodeMonitoringProcessor* nodeMonitoringProcessor)
27 	: FSObject(),
28 	  fID(_NextVolumeID()),
29 	  fSecurityContext(NULL),
30 	  fSecurityContextLock(securityContextLocker),
31 	  fNodeMonitoringProcessor(nodeMonitoringProcessor),
32 	  fNodeHandles(NULL),
33 	  fShare(NULL),
34 	  fRootNodeRef(),
35 	  fSharePermissions(),
36 	  fMounted(false)
37 {
38 }
39 
40 // destructor
41 ClientVolume::~ClientVolume()
42 {
43 	Unmount();
44 
45 	if (fShare)
46 		fShare->ReleaseReference();
47 
48 	delete fNodeHandles;
49 	delete fSecurityContext;
50 }
51 
52 // Init
53 status_t
54 ClientVolume::Init()
55 {
56 	// create the node handle map
57 	fNodeHandles = new(std::nothrow) NodeHandleMap("node handles");
58 	if (!fNodeHandles)
59 		return B_NO_MEMORY;
60 	status_t error = fNodeHandles->Init();
61 	if (error != B_OK)
62 		return error;
63 
64 	return B_OK;
65 }
66 
67 // GetID
68 int32
69 ClientVolume::GetID() const
70 {
71 	return fID;
72 }
73 
74 // Mount
75 status_t
76 ClientVolume::Mount(UserSecurityContext* securityContext, Share* share)
77 {
78 	if (!securityContext || !share)
79 		return B_BAD_VALUE;
80 	ObjectDeleter<UserSecurityContext> securityContextDeleter(securityContext);
81 	if (IsMounted())
82 		return B_BAD_VALUE;
83 	fSecurityContext = securityContext;
84 	securityContextDeleter.Detach();
85 
86 	fShare = share;
87 	fShare->AcquireReference();
88 	dev_t volumeID = share->GetVolumeID();
89 	ino_t nodeID = share->GetNodeID();
90 
91 	// into root node ref
92 	fRootNodeRef.device = volumeID;
93 	fRootNodeRef.node = nodeID;
94 
95 	// get the share permissions
96 	fSharePermissions = securityContext->GetNodePermissions(volumeID, nodeID);
97 
98 	// get the root directory
99 	VolumeManager* volumeManager = VolumeManager::GetDefault();
100 	Directory* rootDir;
101 	status_t error = volumeManager->LoadDirectory(volumeID, nodeID, &rootDir);
102 	if (error != B_OK)
103 		return error;
104 
105 	// register with the volume manager
106 	error = volumeManager->AddClientVolume(this);
107 	if (error != B_OK) {
108 		Unmount();
109 		return error;
110 	}
111 	fMounted = true;
112 
113 	// notify the statistics manager
114 	StatisticsManager::GetDefault()->ShareMounted(fShare,
115 		fSecurityContext->GetUser());
116 
117 	return B_OK;
118 }
119 
120 // Unmount
121 void
122 ClientVolume::Unmount()
123 {
124 	PRINT(("ClientVolume::Unmount()\n"));
125 
126 	if (fMounted) {
127 		fMounted = false;
128 
129 		// notify the statistics manager
130 		StatisticsManager::GetDefault()->ShareUnmounted(fShare,
131 			fSecurityContext->GetUser());
132 	}
133 
134 	// remove ourselves from the volume manager
135 	VolumeManager::GetDefault()->RemoveClientVolume(this);
136 
137 	// close all node handles
138 //	while (true) {
139 //		// get a cookie
140 //		int32 cookie;
141 //		{
142 //			NodeHandleMap::Iterator it = fNodeHandles->GetIterator();
143 //			if (!it.HasNext())
144 //				break;
145 //			cookie = it.Next().key.value;
146 //		}
147 //
148 //		// get the handle
149 //		NodeHandle* handle;
150 //		status_t error = LockNodeHandle(cookie, &handle);
151 //		if (error == B_OK) {
152 //			// close the node handle
153 //			ClientNodeUnlocker _(handle->GetClientNode());
154 //			Close(handle);
155 //		} else {
156 //			ClientVolumeLocker _(this);
157 //			if (fNodeHandles->ContainsKey(cookie)) {
158 //				// something went seriously wrong
159 //				ERROR(("ClientVolume::Unmount(): ERROR: Failed to lock "
160 //					"existing node handle! Can't continue Unmount().\n"));
161 //				return;
162 //			}
163 //		}
164 //	}
165 }
166 
167 
168 // IsMounted
169 bool
170 ClientVolume::IsMounted() const
171 {
172 	return fMounted;
173 }
174 
175 // GetSecurityContext
176 //
177 // Caller must hold fSecurityContextLock. Only the ClientConnection should
178 // do this.
179 UserSecurityContext*
180 ClientVolume::GetSecurityContext() const
181 {
182 	return fSecurityContext;
183 }
184 
185 // SetSecurityContext
186 void
187 ClientVolume::SetSecurityContext(UserSecurityContext* securityContext)
188 {
189 	AutoLocker<Locker> locker(fSecurityContextLock);
190 
191 	// unset old
192 	delete fSecurityContext;
193 
194 	// set new
195 	fSecurityContext = securityContext;
196 	fSharePermissions = fSecurityContext->GetNodePermissions(fRootNodeRef);
197 }
198 
199 // GetShare
200 Share*
201 ClientVolume::GetShare() const
202 {
203 	return fShare;
204 }
205 
206 // GetRootDirectory
207 Directory*
208 ClientVolume::GetRootDirectory() const
209 {
210 	return VolumeManager::GetDefault()->GetDirectory(
211 		fRootNodeRef.device, fRootNodeRef.node);
212 }
213 
214 // GetRootNodeRef
215 const NodeRef&
216 ClientVolume::GetRootNodeRef() const
217 {
218 	return fRootNodeRef;
219 }
220 
221 // GetSharePermissions
222 Permissions
223 ClientVolume::GetSharePermissions() const
224 {
225 	return fSharePermissions;
226 }
227 
228 // GetNodePermissions
229 Permissions
230 ClientVolume::GetNodePermissions(dev_t volumeID, ino_t nodeID)
231 {
232 	return fSharePermissions;
233 }
234 
235 // GetNodePermissions
236 Permissions
237 ClientVolume::GetNodePermissions(Node* node)
238 {
239 // TODO: We should also check whether the node is located on the client volume
240 // in the first place. Otherwise someone with access to a low-security share
241 // could get access to arbitrary nodes on the server.
242 	return fSharePermissions;
243 }
244 
245 // GetNode
246 Node*
247 ClientVolume::GetNode(dev_t volumeID, ino_t nodeID)
248 {
249 	VolumeManager* volumeManager = VolumeManager::GetDefault();
250 
251 	// get the node
252 	Node* node = volumeManager->GetNode(volumeID, nodeID);
253 	if (!node)
254 		return NULL;
255 
256 	// check, if the node is contained by the root dir of the client volume
257 	if (volumeManager->DirectoryContains(GetRootDirectory(), node, true))
258 		return node;
259 
260 	return NULL;
261 }
262 
263 // GetNode
264 Node*
265 ClientVolume::GetNode(NodeID nodeID)
266 {
267 	return GetNode(nodeID.volumeID, nodeID.nodeID);
268 }
269 
270 // GetNode
271 Node*
272 ClientVolume::GetNode(const node_ref& nodeRef)
273 {
274 	return GetNode(nodeRef.device, nodeRef.node);
275 }
276 
277 // GetDirectory
278 Directory*
279 ClientVolume::GetDirectory(dev_t volumeID, ino_t nodeID)
280 {
281 	VolumeManager* volumeManager = VolumeManager::GetDefault();
282 
283 	// get the directory
284 	Directory* dir = GetDirectory(volumeID, nodeID);
285 	if (!dir)
286 		return NULL;
287 
288 	// check, if the dir is contained by the root dir of the client volume
289 	if (volumeManager->DirectoryContains(GetRootDirectory(), dir, true))
290 		return dir;
291 
292 	return NULL;
293 }
294 
295 // GetDirectory
296 Directory*
297 ClientVolume::GetDirectory(NodeID nodeID)
298 {
299 	return GetDirectory(nodeID.volumeID, nodeID.nodeID);
300 }
301 
302 // LoadDirectory
303 status_t
304 ClientVolume::LoadDirectory(dev_t volumeID, ino_t nodeID,
305 	Directory** _directory)
306 {
307 	if (!_directory)
308 		return B_BAD_VALUE;
309 
310 	VolumeManager* volumeManager = VolumeManager::GetDefault();
311 
312 	// load the directory
313 	Directory* dir;
314 	status_t error = volumeManager->LoadDirectory(volumeID, nodeID, &dir);
315 	if (error != B_OK)
316 		return error;
317 
318 	// check, if the dir is contained by the root dir of the client volume
319 	if (!volumeManager->DirectoryContains(GetRootDirectory(), dir, true))
320 		return B_ENTRY_NOT_FOUND;
321 
322 	*_directory = dir;
323 	return B_OK;
324 }
325 
326 // GetEntry
327 Entry*
328 ClientVolume::GetEntry(dev_t volumeID, ino_t dirID, const char* name)
329 {
330 	VolumeManager* volumeManager = VolumeManager::GetDefault();
331 
332 	// get the entry
333 	Entry* entry = volumeManager->GetEntry(volumeID, dirID, name);
334 	if (!entry)
335 		return NULL;
336 
337 	// check, if the entry is contained by the root dir of the client volume
338 	if (volumeManager->DirectoryContains(GetRootDirectory(), entry))
339 		return entry;
340 
341 	return NULL;
342 }
343 
344 // GetEntry
345 Entry*
346 ClientVolume::GetEntry(Directory* directory, const char* name)
347 {
348 	if (!directory)
349 		return NULL;
350 
351 	return GetEntry(directory->GetVolumeID(), directory->GetID(), name);
352 }
353 
354 // LoadEntry
355 status_t
356 ClientVolume::LoadEntry(dev_t volumeID, ino_t dirID, const char* name,
357 	Entry** _entry)
358 {
359 	if (!name || !_entry)
360 		return B_BAD_VALUE;
361 
362 	VolumeManager* volumeManager = VolumeManager::GetDefault();
363 
364 	// get the entry
365 	Entry* entry;
366 	status_t error = VolumeManager::GetDefault()->LoadEntry(volumeID, dirID,
367 		name, true, &entry);
368 	if (error != B_OK)
369 		return error;
370 
371 	// check, if the entry is contained by the root dir of the client volume
372 	if (!volumeManager->DirectoryContains(GetRootDirectory(), entry))
373 		return B_ENTRY_NOT_FOUND;
374 
375 	*_entry = entry;
376 	return B_OK;
377 }
378 
379 // LoadEntry
380 status_t
381 ClientVolume::LoadEntry(Directory* directory, const char* name, Entry** entry)
382 {
383 	if (!directory)
384 		return B_BAD_VALUE;
385 
386 	return LoadEntry(directory->GetVolumeID(), directory->GetID(), name, entry);
387 }
388 
389 // Open
390 //
391 // The caller gets a lock to the returned node handle.
392 status_t
393 ClientVolume::Open(Node* node, int openMode, FileHandle** _handle)
394 {
395 	if (!node || !_handle)
396 		return B_BAD_VALUE;
397 
398 	// open the node
399 	FileHandle* handle = NULL;
400 	status_t error = node->Open(openMode, &handle);
401 	if (error != B_OK)
402 		return error;
403 	BReference<NodeHandle> handleReference(handle, true);
404 
405 	// lock the handle
406 	handle->Lock();
407 
408 	// add the handle
409 	error = fNodeHandles->AddNodeHandle(handle);
410 	if (error != B_OK)
411 		return error;
412 
413 	handleReference.Detach();
414 	*_handle = handle;
415 	return B_OK;
416 }
417 
418 // OpenDir
419 //
420 // The caller gets a lock to the returned node handle.
421 status_t
422 ClientVolume::OpenDir(Directory* directory, DirIterator** _iterator)
423 {
424 	if (!directory || !_iterator)
425 		return B_BAD_VALUE;
426 
427 	// open the directory
428 	DirIterator* iterator = NULL;
429 	status_t error = directory->OpenDir(&iterator);
430 	if (error != B_OK)
431 		return error;
432 	BReference<NodeHandle> handleReference(iterator, true);
433 
434 	// lock the handle
435 	iterator->Lock();
436 
437 	// add the handle
438 	error = fNodeHandles->AddNodeHandle(iterator);
439 	if (error != B_OK)
440 		return error;
441 
442 	handleReference.Detach();
443 	*_iterator = iterator;
444 	return B_OK;
445 }
446 
447 // OpenAttrDir
448 //
449 // The caller gets a lock to the returned node handle.
450 status_t
451 ClientVolume::OpenAttrDir(Node* node, AttrDirIterator** _iterator)
452 {
453 	if (!node || !_iterator)
454 		return B_BAD_VALUE;
455 
456 	// open the attribut directory
457 	AttrDirIterator* iterator = NULL;
458 	status_t error = node->OpenAttrDir(&iterator);
459 	if (error != B_OK)
460 		return error;
461 	BReference<NodeHandle> handleReference(iterator, true);
462 
463 	// lock the handle
464 	iterator->Lock();
465 
466 	// add the handle
467 	error = fNodeHandles->AddNodeHandle(iterator);
468 	if (error != B_OK)
469 		return error;
470 
471 	handleReference.Detach();
472 	*_iterator = iterator;
473 	return B_OK;
474 }
475 
476 // Close
477 //
478 // VolumeManager MUST be locked. After closing the handle must still be
479 // unlocked. When the last reference is surrendered it will finally be deleted.
480 status_t
481 ClientVolume::Close(NodeHandle* handle)
482 {
483 	if (!handle || !fNodeHandles->RemoveNodeHandle(handle))
484 		return B_BAD_VALUE;
485 
486 	return B_OK;
487 }
488 
489 // LockNodeHandle
490 //
491 // VolumeManager must NOT be locked.
492 status_t
493 ClientVolume::LockNodeHandle(int32 cookie, NodeHandle** _handle)
494 {
495 	return fNodeHandles->LockNodeHandle(cookie, _handle);
496 }
497 
498 // UnlockNodeHandle
499 //
500 // VolumeManager may or may not be locked.
501 void
502 ClientVolume::UnlockNodeHandle(NodeHandle* nodeHandle)
503 {
504 	fNodeHandles->UnlockNodeHandle(nodeHandle);
505 }
506 
507 // ProcessNodeMonitoringEvent
508 void
509 ClientVolume::ProcessNodeMonitoringEvent(NodeMonitoringEvent* event)
510 {
511 	if (fNodeMonitoringProcessor)
512 		fNodeMonitoringProcessor->ProcessNodeMonitoringEvent(fID, event);
513 }
514 
515 // _NextVolumeID
516 int32
517 ClientVolume::_NextVolumeID()
518 {
519 	return atomic_add(&sNextVolumeID, 1);
520 }
521 
522 // sNextVolumeID
523 int32 ClientVolume::sNextVolumeID = 0;
524 
525 
526 // #pragma -
527 
528 // destructor
529 ClientVolume::NodeMonitoringProcessor::~NodeMonitoringProcessor()
530 {
531 }
532 
533