1 /* 2 * Copyright 2013 Haiku, Inc. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Ingo Weinhold, ingo_weinhold@gmx.de 7 */ 8 9 10 #include "VirtualDirectoryManager.h" 11 12 #include <errno.h> 13 14 #include <new> 15 16 #include <Directory.h> 17 #include <File.h> 18 #include <StringList.h> 19 20 #include <AutoDeleter.h> 21 #include <AutoLocker.h> 22 #include <DriverSettings.h> 23 #include <NotOwningEntryRef.h> 24 #include <Uuid.h> 25 26 #include "MimeTypes.h" 27 #include "Model.h" 28 29 30 namespace BPrivate { 31 32 static const size_t kMaxVirtualDirectoryFileSize = 10 * 1024; 33 static const char* const kTemporaryDefinitionFileBaseDirectoryPath 34 = "/tmp/tracker/virtual-directories"; 35 36 37 // #pragma mark - VirtualDirectoryManager::Info 38 39 40 class VirtualDirectoryManager::Info { 41 private: 42 typedef BObjectList<Info> InfoList; 43 44 public: 45 Info(RootInfo* root, Info* parent, const BString& path, 46 const node_ref& definitionFileNodeRef, 47 const entry_ref& definitionFileEntryRef) 48 : 49 fRoot(root), 50 fParent(parent), 51 fPath(path), 52 fDefinitionFileNodeRef(definitionFileNodeRef), 53 fDefinitionFileEntryRef(definitionFileEntryRef), 54 fId(), 55 fChildDefinitionsDirectoryRef(-1, -1), 56 fChildren(10, true) 57 { 58 } 59 60 ~Info() 61 { 62 } 63 64 RootInfo* Root() const 65 { 66 return fRoot; 67 } 68 69 Info* Parent() const 70 { 71 return fParent; 72 } 73 74 const char* Name() const 75 { 76 return fDefinitionFileEntryRef.name; 77 } 78 79 const BString& Path() const 80 { 81 return fPath; 82 } 83 84 const node_ref& DefinitionFileNodeRef() const 85 { 86 return fDefinitionFileNodeRef; 87 } 88 89 const entry_ref& DefinitionFileEntryRef() const 90 { 91 return fDefinitionFileEntryRef; 92 } 93 94 const InfoList& Children() const 95 { 96 return fChildren; 97 } 98 99 const BString& Id() const 100 { 101 return fId; 102 } 103 104 void SetId(const BString& id) 105 { 106 fId = id; 107 } 108 109 const node_ref& ChildDefinitionsDirectoryRef() const 110 { 111 return fChildDefinitionsDirectoryRef; 112 } 113 114 void SetChildDefinitionsDirectoryRef(const node_ref& ref) 115 { 116 fChildDefinitionsDirectoryRef = ref; 117 } 118 119 Info* GetChild(const char* name) const 120 { 121 for (int32 i = 0; Info* child = fChildren.ItemAt(i); i++) { 122 if (strcmp(name, child->Name()) == 0) 123 return child; 124 } 125 return NULL; 126 } 127 128 Info* CreateChild(const node_ref& definitionFileNodeRef, 129 const entry_ref& definitionFileEntryRef) 130 { 131 BString path; 132 if (fPath.IsEmpty()) { 133 path = definitionFileEntryRef.name; 134 } else { 135 path.SetToFormat("%s/%s", fPath.String(), 136 definitionFileEntryRef.name); 137 } 138 if (path.IsEmpty()) 139 return NULL; 140 141 Info* info = new(std::nothrow) Info(fRoot, this, path, 142 definitionFileNodeRef, definitionFileEntryRef); 143 if (info == NULL || !fChildren.AddItem(info)) { 144 delete info; 145 return NULL; 146 } 147 return info; 148 } 149 150 bool DeleteChild(Info* info) 151 { 152 return fChildren.RemoveItem(info, true); 153 } 154 155 void DeleteChildAt(int32 index) 156 { 157 delete fChildren.RemoveItemAt(index); 158 } 159 160 private: 161 RootInfo* fRoot; 162 Info* fParent; 163 BString fPath; 164 node_ref fDefinitionFileNodeRef; 165 entry_ref fDefinitionFileEntryRef; 166 BString fId; 167 node_ref fChildDefinitionsDirectoryRef; 168 InfoList fChildren; 169 }; 170 171 172 // #pragma mark - VirtualDirectoryManager::RootInfo 173 174 175 class VirtualDirectoryManager::RootInfo { 176 public: 177 RootInfo(const node_ref& definitionFileNodeRef, 178 const entry_ref& definitionFileEntryRef) 179 : 180 fDirectoryPaths(), 181 fInfo(new(std::nothrow) VirtualDirectoryManager::Info(this, NULL, 182 BString(), definitionFileNodeRef, definitionFileEntryRef)), 183 fFileTime(-1), 184 fLastChangeTime(-1) 185 { 186 } 187 188 ~RootInfo() 189 { 190 delete fInfo; 191 } 192 193 status_t InitCheck() const 194 { 195 return fInfo != NULL ? B_OK : B_NO_MEMORY; 196 } 197 198 bigtime_t FileTime() const 199 { 200 return fFileTime; 201 } 202 203 bigtime_t LastChangeTime() const 204 { 205 return fLastChangeTime; 206 } 207 208 const BStringList& DirectoryPaths() const 209 { 210 return fDirectoryPaths; 211 } 212 213 status_t ReadDefinition(bool* _changed = NULL) 214 { 215 // open the definition file 216 BFile file; 217 status_t error = file.SetTo(&fInfo->DefinitionFileEntryRef(), 218 B_READ_ONLY); 219 if (error != B_OK) 220 return error; 221 222 struct stat st; 223 error = file.GetStat(&st); 224 if (error != B_OK) 225 return error; 226 227 bigtime_t fileTime = st.st_mtim.tv_sec; 228 fileTime *= 1000000; 229 fileTime += st.st_mtim.tv_nsec / 1000; 230 if (fileTime == fFileTime) { 231 if (_changed != NULL) 232 *_changed = false; 233 234 return B_OK; 235 } 236 237 if (node_ref(st.st_dev, st.st_ino) != fInfo->DefinitionFileNodeRef()) 238 return B_ENTRY_NOT_FOUND; 239 240 // read the contents 241 off_t fileSize = st.st_size; 242 if (fileSize > (off_t)kMaxVirtualDirectoryFileSize) 243 return B_BAD_VALUE; 244 245 char* buffer = new(std::nothrow) char[fileSize + 1]; 246 if (buffer == NULL) 247 return B_NO_MEMORY; 248 ArrayDeleter<char> bufferDeleter(buffer); 249 250 ssize_t bytesRead = file.ReadAt(0, buffer, fileSize); 251 if (bytesRead < 0) 252 return bytesRead; 253 254 buffer[bytesRead] = '\0'; 255 256 // parse it 257 BStringList oldDirectoryPaths(fDirectoryPaths); 258 fDirectoryPaths.MakeEmpty(); 259 260 BDriverSettings driverSettings; 261 error = driverSettings.SetToString(buffer); 262 if (error != B_OK) 263 return error; 264 265 BDriverParameterIterator it 266 = driverSettings.ParameterIterator("directory"); 267 while (it.HasNext()) { 268 BDriverParameter parameter = it.Next(); 269 for (int32 i = 0; i < parameter.CountValues(); i++) 270 fDirectoryPaths.Add(parameter.ValueAt(i)); 271 } 272 273 // update file time and check whether something has changed 274 fFileTime = fileTime; 275 276 bool changed = fDirectoryPaths != oldDirectoryPaths; 277 if (changed || fLastChangeTime < 0) 278 fLastChangeTime = fFileTime; 279 280 if (_changed != NULL) 281 *_changed = changed; 282 283 return B_OK; 284 } 285 286 VirtualDirectoryManager::Info* Info() const 287 { 288 return fInfo; 289 } 290 291 private: 292 typedef std::map<BString, VirtualDirectoryManager::Info*> InfoMap; 293 294 private: 295 BStringList fDirectoryPaths; 296 VirtualDirectoryManager::Info* fInfo; 297 bigtime_t fFileTime; 298 // actual file modified time 299 bigtime_t fLastChangeTime; 300 // last time something actually changed 301 }; 302 303 304 // #pragma mark - VirtualDirectoryManager 305 306 307 VirtualDirectoryManager::VirtualDirectoryManager() 308 : 309 fLock("virtual directory manager") 310 { 311 } 312 313 314 /*static*/ VirtualDirectoryManager* 315 VirtualDirectoryManager::Instance() 316 { 317 static VirtualDirectoryManager* manager 318 = new(std::nothrow) VirtualDirectoryManager; 319 return manager; 320 } 321 322 323 status_t 324 VirtualDirectoryManager::ResolveDirectoryPaths( 325 const node_ref& definitionFileNodeRef, 326 const entry_ref& definitionFileEntryRef, BStringList& _directoryPaths, 327 node_ref* _definitionFileNodeRef, entry_ref* _definitionFileEntryRef) 328 { 329 Info* info = _InfoForNodeRef(definitionFileNodeRef); 330 if (info == NULL) { 331 status_t error = _ResolveUnknownDefinitionFile(definitionFileNodeRef, 332 definitionFileEntryRef, info); 333 if (error != B_OK) 334 return error; 335 } 336 337 const BString& subDirectory = info->Path(); 338 const BStringList& rootDirectoryPaths = info->Root()->DirectoryPaths(); 339 if (subDirectory.IsEmpty()) { 340 _directoryPaths = rootDirectoryPaths; 341 } else { 342 _directoryPaths.MakeEmpty(); 343 int32 count = rootDirectoryPaths.CountStrings(); 344 for (int32 i = 0; i < count; i++) { 345 BString path = rootDirectoryPaths.StringAt(i); 346 _directoryPaths.Add(path << '/' << subDirectory); 347 } 348 } 349 350 if (_definitionFileEntryRef != NULL) { 351 *_definitionFileEntryRef = info->DefinitionFileEntryRef(); 352 if (_definitionFileEntryRef->name == NULL) 353 return B_NO_MEMORY; 354 } 355 356 if (_definitionFileNodeRef != NULL) 357 *_definitionFileNodeRef = info->DefinitionFileNodeRef(); 358 359 return B_OK; 360 } 361 362 363 bool 364 VirtualDirectoryManager::GetDefinitionFileChangeTime( 365 const node_ref& definitionFileRef, bigtime_t& _time) const 366 { 367 Info* info = _InfoForNodeRef(definitionFileRef); 368 if (info == NULL) 369 return false; 370 371 _time = info->Root()->LastChangeTime(); 372 return true; 373 } 374 375 376 bool 377 VirtualDirectoryManager::GetRootDefinitionFile( 378 const node_ref& definitionFileRef, node_ref& _rootDefinitionFileRef) 379 { 380 Info* info = _InfoForNodeRef(definitionFileRef); 381 if (info == NULL) 382 return false; 383 384 _rootDefinitionFileRef = info->Root()->Info()->DefinitionFileNodeRef(); 385 return true; 386 } 387 388 389 bool 390 VirtualDirectoryManager::GetSubDirectoryDefinitionFile( 391 const node_ref& baseDefinitionRef, const char* subDirName, 392 entry_ref& _entryRef, node_ref& _nodeRef) 393 { 394 Info* parentInfo = _InfoForNodeRef(baseDefinitionRef); 395 if (parentInfo == NULL) 396 return false; 397 398 Info* info = parentInfo->GetChild(subDirName); 399 if (info == NULL) 400 return false; 401 402 _entryRef = info->DefinitionFileEntryRef(); 403 _nodeRef = info->DefinitionFileNodeRef(); 404 return _entryRef.name != NULL; 405 } 406 407 408 bool 409 VirtualDirectoryManager::GetParentDirectoryDefinitionFile( 410 const node_ref& subDirDefinitionRef, entry_ref& _entryRef, 411 node_ref& _nodeRef) 412 { 413 Info* info = _InfoForNodeRef(subDirDefinitionRef); 414 if (info == NULL) 415 return false; 416 417 Info* parentInfo = info->Parent(); 418 if (parentInfo == NULL) 419 return false; 420 421 _entryRef = parentInfo->DefinitionFileEntryRef(); 422 _nodeRef = parentInfo->DefinitionFileNodeRef(); 423 return _entryRef.name != NULL; 424 } 425 426 427 status_t 428 VirtualDirectoryManager::TranslateDirectoryEntry( 429 const node_ref& definitionFileRef, dirent* buffer) 430 { 431 NotOwningEntryRef entryRef(buffer->d_pdev, buffer->d_pino, buffer->d_name); 432 node_ref nodeRef(buffer->d_dev, buffer->d_ino); 433 434 status_t result = TranslateDirectoryEntry(definitionFileRef, entryRef, 435 nodeRef); 436 if (result != B_OK) 437 return result; 438 439 buffer->d_pdev = entryRef.device; 440 buffer->d_pino = entryRef.directory; 441 buffer->d_dev = nodeRef.device; 442 buffer->d_ino = nodeRef.node; 443 444 return B_OK; 445 } 446 447 448 status_t 449 VirtualDirectoryManager::TranslateDirectoryEntry( 450 const node_ref& definitionFileRef, entry_ref& _entryRef, node_ref& _nodeRef) 451 { 452 Info* parentInfo = _InfoForNodeRef(definitionFileRef); 453 if (parentInfo == NULL) 454 return B_BAD_VALUE; 455 456 // get the info for the entry 457 Info* info = parentInfo->GetChild(_entryRef.name); 458 if (info == NULL) { 459 // If not done yet, create a directory for the parent, where we can 460 // place the new definition file. 461 if (parentInfo->Id().IsEmpty()) { 462 BString id = BUuid().SetToRandom().ToString(); 463 if (id.IsEmpty()) 464 return B_NO_MEMORY; 465 466 BPath path(kTemporaryDefinitionFileBaseDirectoryPath, id); 467 status_t error = path.InitCheck(); 468 if (error != B_OK) 469 return error; 470 471 error = create_directory(path.Path(), 472 S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH); 473 if (error != B_OK) 474 return error; 475 476 struct stat st; 477 if (lstat(path.Path(), &st) != 0) 478 return errno; 479 480 parentInfo->SetId(id); 481 parentInfo->SetChildDefinitionsDirectoryRef( 482 node_ref(st.st_dev, st.st_ino)); 483 } 484 485 // create the definition file 486 const node_ref& directoryRef 487 = parentInfo->ChildDefinitionsDirectoryRef(); 488 NotOwningEntryRef entryRef(directoryRef, _entryRef.name); 489 490 BFile definitionFile; 491 status_t error = definitionFile.SetTo(&entryRef, 492 B_WRITE_ONLY | B_CREATE_FILE | B_ERASE_FILE); 493 if (error != B_OK) 494 return error; 495 496 node_ref nodeRef; 497 error = definitionFile.GetNodeRef(&nodeRef); 498 if (error != B_OK) 499 return error; 500 501 BNodeInfo nodeInfo(&definitionFile); 502 error = nodeInfo.SetType(kVirtualDirectoryMimeType); 503 if (error != B_OK) 504 return error; 505 506 // create the info 507 info = parentInfo->CreateChild(nodeRef, entryRef); 508 if (info == NULL || !_AddInfo(info)) 509 return B_NO_MEMORY; 510 511 // Write some info into the definition file that helps us to find the 512 // root definition file. This is only necessary when definition file 513 // entry refs are transferred between applications. Then the receiving 514 // application may need to find the root definition file and resolve 515 // the subdirectories. 516 const entry_ref& rootEntryRef 517 = parentInfo->Root()->Info()->DefinitionFileEntryRef(); 518 BString definitionFileContent; 519 definitionFileContent.SetToFormat( 520 "root {\n" 521 " device %" B_PRIdDEV "\n" 522 " directory %" B_PRIdINO "\n" 523 " name \"%s\"\n" 524 "}\n" 525 "subdir \"%s\"\n", 526 rootEntryRef.device, rootEntryRef.directory, rootEntryRef.name, 527 info->Path().String()); 528 // failure is not nice, but not mission critical for this application 529 if (!definitionFileContent.IsEmpty()) { 530 definitionFile.WriteAt(0, 531 definitionFileContent.String(), definitionFileContent.Length()); 532 } 533 } 534 535 const entry_ref& entryRef = info->DefinitionFileEntryRef(); 536 _nodeRef = info->DefinitionFileNodeRef(); 537 _entryRef.device = entryRef.device; 538 _entryRef.directory = entryRef.directory; 539 540 return B_OK; 541 } 542 543 544 bool 545 VirtualDirectoryManager::DefinitionFileChanged( 546 const node_ref& definitionFileRef) 547 { 548 Info* info = _InfoForNodeRef(definitionFileRef); 549 if (info == NULL) 550 return false; 551 552 _UpdateTree(info->Root()); 553 554 return _InfoForNodeRef(definitionFileRef) != NULL; 555 } 556 557 558 status_t 559 VirtualDirectoryManager::DirectoryRemoved(const node_ref& definitionFileRef) 560 { 561 Info* info = _InfoForNodeRef(definitionFileRef); 562 if (info == NULL) 563 return B_ENTRY_NOT_FOUND; 564 565 _RemoveDirectory(info); 566 567 // delete the info 568 if (info->Parent() == NULL) 569 delete info->Root(); 570 else 571 info->Parent()->DeleteChild(info); 572 573 return B_OK; 574 } 575 576 577 /*static*/ bool 578 VirtualDirectoryManager::GetEntry(const BStringList& directoryPaths, 579 const char* name, entry_ref* _ref, struct stat* _st) 580 { 581 int32 count = directoryPaths.CountStrings(); 582 for (int32 i = 0; i < count; i++) { 583 BPath path; 584 if (path.SetTo(directoryPaths.StringAt(i), name) != B_OK) 585 continue; 586 587 struct stat st; 588 if (lstat(path.Path(), &st) == 0) { 589 if (_ref != NULL) { 590 if (get_ref_for_path(path.Path(), _ref) != B_OK) 591 return false; 592 } 593 if (_st != NULL) 594 *_st = st; 595 return true; 596 } 597 } 598 599 return false; 600 } 601 602 603 VirtualDirectoryManager::Info* 604 VirtualDirectoryManager::_InfoForNodeRef(const node_ref& nodeRef) const 605 { 606 NodeRefInfoMap::const_iterator it = fInfos.find(nodeRef); 607 return it != fInfos.end() ? it->second : NULL; 608 } 609 610 611 bool 612 VirtualDirectoryManager::_AddInfo(Info* info) 613 { 614 try { 615 fInfos[info->DefinitionFileNodeRef()] = info; 616 return true; 617 } catch (...) { 618 return false; 619 } 620 } 621 622 623 void 624 VirtualDirectoryManager::_RemoveInfo(Info* info) 625 { 626 NodeRefInfoMap::iterator it = fInfos.find(info->DefinitionFileNodeRef()); 627 if (it != fInfos.end()) 628 fInfos.erase(it); 629 } 630 631 632 void 633 VirtualDirectoryManager::_UpdateTree(RootInfo* root) 634 { 635 bool changed = false; 636 status_t result = root->ReadDefinition(&changed); 637 if (result != B_OK) { 638 DirectoryRemoved(root->Info()->DefinitionFileNodeRef()); 639 return; 640 } 641 642 if (!changed) 643 return; 644 645 _UpdateTree(root->Info()); 646 } 647 648 649 void 650 VirtualDirectoryManager::_UpdateTree(Info* info) 651 { 652 const BStringList& directoryPaths = info->Root()->DirectoryPaths(); 653 654 int32 childCount = info->Children().CountItems(); 655 for (int32 i = childCount -1; i >= 0; i--) { 656 Info* childInfo = info->Children().ItemAt(i); 657 struct stat st; 658 if (GetEntry(directoryPaths, childInfo->Path(), NULL, &st) 659 && S_ISDIR(st.st_mode)) { 660 _UpdateTree(childInfo); 661 } else { 662 _RemoveDirectory(childInfo); 663 info->DeleteChildAt(i); 664 } 665 } 666 } 667 668 669 void 670 VirtualDirectoryManager::_RemoveDirectory(Info* info) 671 { 672 // recursively remove the subdirectories 673 for (int32 i = 0; Info* child = info->Children().ItemAt(i); i++) 674 _RemoveDirectory(child); 675 676 // remove the directory for the child definition file 677 if (!info->Id().IsEmpty()) { 678 BPath path(kTemporaryDefinitionFileBaseDirectoryPath, info->Id()); 679 if (path.InitCheck() == B_OK) 680 rmdir(path.Path()); 681 } 682 683 // unless this is the root directory, remove the definition file 684 if (info != info->Root()->Info()) 685 BEntry(&info->DefinitionFileEntryRef()).Remove(); 686 687 _RemoveInfo(info); 688 } 689 690 691 status_t 692 VirtualDirectoryManager::_ResolveUnknownDefinitionFile( 693 const node_ref& definitionFileNodeRef, 694 const entry_ref& definitionFileEntryRef, Info*& _info) 695 { 696 // This is either a root definition file or a subdir definition file 697 // created by another application. We'll just try to read the info from the 698 // file that a subdir definition file would contain. If that fails, we 699 // assume a root definition file. 700 entry_ref entryRef; 701 BString subDirPath; 702 if (_ReadSubDirectoryDefinitionFileInfo(definitionFileEntryRef, entryRef, 703 subDirPath) != B_OK) { 704 return _CreateRootInfo(definitionFileNodeRef, definitionFileEntryRef, 705 _info); 706 } 707 708 if (subDirPath.IsEmpty()) 709 return B_BAD_VALUE; 710 711 // get the root definition file node ref 712 node_ref nodeRef; 713 status_t error = BEntry(&entryRef).GetNodeRef(&nodeRef); 714 if (error != B_OK) 715 return error; 716 717 // resolve/create the root info 718 Info* info = _InfoForNodeRef(nodeRef); 719 if (info == NULL) { 720 error = _CreateRootInfo(nodeRef, entryRef, info); 721 if (error != B_OK) 722 return error; 723 } else if (info->Root()->Info() != info) 724 return B_BAD_VALUE; 725 726 const BStringList& rootDirectoryPaths = info->Root()->DirectoryPaths(); 727 728 // now we can traverse the subdir path and resolve all infos along the way 729 int32 nextComponentOffset = 0; 730 while (nextComponentOffset < subDirPath.Length()) { 731 int32 componentEnd = subDirPath.FindFirst('/', nextComponentOffset); 732 if (componentEnd >= 0) { 733 // skip duplicate '/'s 734 if (componentEnd == nextComponentOffset + 1) { 735 nextComponentOffset = componentEnd; 736 continue; 737 } 738 nextComponentOffset = componentEnd + 1; 739 } else { 740 componentEnd = subDirPath.Length(); 741 nextComponentOffset = componentEnd; 742 } 743 744 BString entryPath(subDirPath, componentEnd); 745 if (entryPath.IsEmpty()) 746 return B_NO_MEMORY; 747 748 struct stat st; 749 if (!GetEntry(rootDirectoryPaths, entryPath, &entryRef, &st)) 750 return B_ENTRY_NOT_FOUND; 751 752 if (!S_ISDIR(st.st_mode)) 753 return B_BAD_VALUE; 754 755 error = TranslateDirectoryEntry(info->DefinitionFileNodeRef(), entryRef, 756 nodeRef); 757 if (error != B_OK) 758 return error; 759 760 info = _InfoForNodeRef(nodeRef); 761 } 762 763 _info = info; 764 765 return B_OK; 766 } 767 768 769 status_t 770 VirtualDirectoryManager::_CreateRootInfo(const node_ref& definitionFileNodeRef, 771 const entry_ref& definitionFileEntryRef, Info*& _info) 772 { 773 RootInfo* root = new(std::nothrow) RootInfo(definitionFileNodeRef, 774 definitionFileEntryRef); 775 if (root == NULL || root->InitCheck() != B_OK) { 776 delete root; 777 return B_NO_MEMORY; 778 } 779 ObjectDeleter<RootInfo> rootDeleter(root); 780 781 status_t error = root->ReadDefinition(); 782 if (error != B_OK) 783 return error; 784 785 if (!_AddInfo(root->Info())) 786 return B_NO_MEMORY; 787 788 rootDeleter.Detach(); 789 _info = root->Info(); 790 791 return B_OK; 792 } 793 794 795 status_t 796 VirtualDirectoryManager::_ReadSubDirectoryDefinitionFileInfo( 797 const entry_ref& entryRef, entry_ref& _rootDefinitionFileEntryRef, 798 BString& _subDirPath) 799 { 800 BDriverSettings driverSettings; 801 status_t error = driverSettings.Load(entryRef); 802 if (error != B_OK) 803 return error; 804 805 const char* subDirPath = driverSettings.GetParameterValue("subdir"); 806 if (subDirPath == NULL || subDirPath[0] == '\0') 807 return B_BAD_DATA; 808 809 BDriverParameter rootParameter; 810 if (!driverSettings.FindParameter("root", &rootParameter)) 811 return B_BAD_DATA; 812 813 const char* name = rootParameter.GetParameterValue("name"); 814 dev_t device = rootParameter.GetInt32ParameterValue("device", -1, -1); 815 ino_t directory = rootParameter.GetInt64ParameterValue("directory"); 816 if (name == NULL || name[0] == '\0' || device < 0) 817 return B_BAD_DATA; 818 819 _rootDefinitionFileEntryRef = entry_ref(device, directory, name); 820 _subDirPath = subDirPath; 821 822 return !_subDirPath.IsEmpty() && _rootDefinitionFileEntryRef.name != NULL 823 ? B_OK : B_NO_MEMORY; 824 } 825 826 } // namespace BPrivate 827