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