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 25ClientVolume::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 41ClientVolume::~ClientVolume() 42{ 43 Unmount(); 44 45 if (fShare) 46 fShare->ReleaseReference(); 47 48 delete fNodeHandles; 49 delete fSecurityContext; 50} 51 52// Init 53status_t 54ClientVolume::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 68int32 69ClientVolume::GetID() const 70{ 71 return fID; 72} 73 74// Mount 75status_t 76ClientVolume::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 121void 122ClientVolume::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 169bool 170ClientVolume::IsMounted() const 171{ 172 return fMounted; 173} 174 175// GetSecurityContext 176// 177// Caller must hold fSecurityContextLock. Only the ClientConnection should 178// do this. 179UserSecurityContext* 180ClientVolume::GetSecurityContext() const 181{ 182 return fSecurityContext; 183} 184 185// SetSecurityContext 186void 187ClientVolume::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 200Share* 201ClientVolume::GetShare() const 202{ 203 return fShare; 204} 205 206// GetRootDirectory 207Directory* 208ClientVolume::GetRootDirectory() const 209{ 210 return VolumeManager::GetDefault()->GetDirectory( 211 fRootNodeRef.device, fRootNodeRef.node); 212} 213 214// GetRootNodeRef 215const NodeRef& 216ClientVolume::GetRootNodeRef() const 217{ 218 return fRootNodeRef; 219} 220 221// GetSharePermissions 222Permissions 223ClientVolume::GetSharePermissions() const 224{ 225 return fSharePermissions; 226} 227 228// GetNodePermissions 229Permissions 230ClientVolume::GetNodePermissions(dev_t volumeID, ino_t nodeID) 231{ 232 return fSharePermissions; 233} 234 235// GetNodePermissions 236Permissions 237ClientVolume::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 246Node* 247ClientVolume::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 264Node* 265ClientVolume::GetNode(NodeID nodeID) 266{ 267 return GetNode(nodeID.volumeID, nodeID.nodeID); 268} 269 270// GetNode 271Node* 272ClientVolume::GetNode(const node_ref& nodeRef) 273{ 274 return GetNode(nodeRef.device, nodeRef.node); 275} 276 277// GetDirectory 278Directory* 279ClientVolume::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 296Directory* 297ClientVolume::GetDirectory(NodeID nodeID) 298{ 299 return GetDirectory(nodeID.volumeID, nodeID.nodeID); 300} 301 302// LoadDirectory 303status_t 304ClientVolume::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 327Entry* 328ClientVolume::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 345Entry* 346ClientVolume::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 355status_t 356ClientVolume::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 380status_t 381ClientVolume::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. 392status_t 393ClientVolume::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. 421status_t 422ClientVolume::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. 450status_t 451ClientVolume::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. 480status_t 481ClientVolume::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. 492status_t 493ClientVolume::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. 501void 502ClientVolume::UnlockNodeHandle(NodeHandle* nodeHandle) 503{ 504 fNodeHandles->UnlockNodeHandle(nodeHandle); 505} 506 507// ProcessNodeMonitoringEvent 508void 509ClientVolume::ProcessNodeMonitoringEvent(NodeMonitoringEvent* event) 510{ 511 if (fNodeMonitoringProcessor) 512 fNodeMonitoringProcessor->ProcessNodeMonitoringEvent(fID, event); 513} 514 515// _NextVolumeID 516int32 517ClientVolume::_NextVolumeID() 518{ 519 return atomic_add(&sNextVolumeID, 1); 520} 521 522// sNextVolumeID 523int32 ClientVolume::sNextVolumeID = 0; 524 525 526// #pragma - 527 528// destructor 529ClientVolume::NodeMonitoringProcessor::~NodeMonitoringProcessor() 530{ 531} 532 533