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