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 * 1000000 228 + st.st_mtim.tv_nsec / 1000; 229 if (fileTime == fFileTime) { 230 if (_changed != NULL) 231 *_changed = false; 232 return B_OK; 233 } 234 235 if (node_ref(st.st_dev, st.st_ino) != fInfo->DefinitionFileNodeRef()) 236 return B_ENTRY_NOT_FOUND; 237 238 // read the contents 239 off_t fileSize = st.st_size; 240 if (fileSize > (off_t)kMaxVirtualDirectoryFileSize) 241 return B_BAD_VALUE; 242 243 char* buffer = new(std::nothrow) char[fileSize + 1]; 244 if (buffer == NULL) 245 return B_NO_MEMORY; 246 ArrayDeleter<char> bufferDeleter(buffer); 247 248 ssize_t bytesRead = file.ReadAt(0, buffer, fileSize); 249 if (bytesRead < 0) 250 return bytesRead; 251 252 buffer[bytesRead] = '\0'; 253 254 // parse it 255 BStringList oldDirectoryPaths(fDirectoryPaths); 256 fDirectoryPaths.MakeEmpty(); 257 258 BDriverSettings driverSettings; 259 error = driverSettings.SetToString(buffer); 260 if (error != B_OK) 261 return error; 262 263 BDriverParameterIterator it 264 = driverSettings.ParameterIterator("directory"); 265 while (it.HasNext()) { 266 BDriverParameter parameter = it.Next(); 267 for (int32 i = 0; i < parameter.CountValues(); i++) 268 fDirectoryPaths.Add(parameter.ValueAt(i)); 269 } 270 271 // update file time and check whether something has changed 272 fFileTime = fileTime; 273 274 bool changed = fDirectoryPaths != oldDirectoryPaths; 275 if (changed || fLastChangeTime < 0) 276 fLastChangeTime = fFileTime; 277 278 if (_changed != NULL) 279 *_changed = changed; 280 281 return B_OK; 282 } 283 284 VirtualDirectoryManager::Info* Info() const 285 { 286 return fInfo; 287 } 288 289 private: 290 typedef std::map<BString, VirtualDirectoryManager::Info*> InfoMap; 291 292 private: 293 BStringList fDirectoryPaths; 294 VirtualDirectoryManager::Info* fInfo; 295 bigtime_t fFileTime; 296 // actual file modified time 297 bigtime_t fLastChangeTime; 298 // last time something actually changed 299 }; 300 301 302 // #pragma mark - VirtualDirectoryManager 303 304 305 VirtualDirectoryManager::VirtualDirectoryManager() 306 : 307 fLock("virtual directory manager") 308 { 309 } 310 311 312 /*static*/ VirtualDirectoryManager* 313 VirtualDirectoryManager::Instance() 314 { 315 static VirtualDirectoryManager* manager 316 = new(std::nothrow) VirtualDirectoryManager; 317 return manager; 318 } 319 320 321 status_t 322 VirtualDirectoryManager::ResolveDirectoryPaths( 323 const node_ref& definitionFileNodeRef, 324 const entry_ref& definitionFileEntryRef, BStringList& _directoryPaths, 325 node_ref* _definitionFileNodeRef, entry_ref* _definitionFileEntryRef) 326 { 327 Info* info = _InfoForNodeRef(definitionFileNodeRef); 328 if (info == NULL) { 329 status_t error = _ResolveUnknownDefinitionFile(definitionFileNodeRef, 330 definitionFileEntryRef, info); 331 if (error != B_OK) 332 return error; 333 } 334 335 const BString& subDirectory = info->Path(); 336 const BStringList& rootDirectoryPaths = info->Root()->DirectoryPaths(); 337 if (subDirectory.IsEmpty()) { 338 _directoryPaths = rootDirectoryPaths; 339 } else { 340 _directoryPaths.MakeEmpty(); 341 int32 count = rootDirectoryPaths.CountStrings(); 342 for (int32 i = 0; i < count; i++) { 343 BString path = rootDirectoryPaths.StringAt(i); 344 _directoryPaths.Add(path << '/' << subDirectory); 345 } 346 } 347 348 if (_definitionFileEntryRef != NULL) { 349 *_definitionFileEntryRef = info->DefinitionFileEntryRef(); 350 if (_definitionFileEntryRef->name == NULL) 351 return B_NO_MEMORY; 352 } 353 354 if (_definitionFileNodeRef != NULL) 355 *_definitionFileNodeRef = info->DefinitionFileNodeRef(); 356 357 return B_OK; 358 } 359 360 361 bool 362 VirtualDirectoryManager::GetDefinitionFileChangeTime( 363 const node_ref& definitionFileRef, bigtime_t& _time) const 364 { 365 Info* info = _InfoForNodeRef(definitionFileRef); 366 if (info == NULL) 367 return false; 368 369 _time = info->Root()->LastChangeTime(); 370 return true; 371 } 372 373 374 bool 375 VirtualDirectoryManager::GetRootDefinitionFile( 376 const node_ref& definitionFileRef, node_ref& _rootDefinitionFileRef) 377 { 378 Info* info = _InfoForNodeRef(definitionFileRef); 379 if (info == NULL) 380 return false; 381 382 _rootDefinitionFileRef = info->Root()->Info()->DefinitionFileNodeRef(); 383 return true; 384 } 385 386 387 bool 388 VirtualDirectoryManager::GetSubDirectoryDefinitionFile( 389 const node_ref& baseDefinitionRef, const char* subDirName, 390 entry_ref& _entryRef, node_ref& _nodeRef) 391 { 392 Info* parentInfo = _InfoForNodeRef(baseDefinitionRef); 393 if (parentInfo == NULL) 394 return false; 395 396 Info* info = parentInfo->GetChild(subDirName); 397 if (info == NULL) 398 return false; 399 400 _entryRef = info->DefinitionFileEntryRef(); 401 _nodeRef = info->DefinitionFileNodeRef(); 402 return _entryRef.name != NULL; 403 } 404 405 406 bool 407 VirtualDirectoryManager::GetParentDirectoryDefinitionFile( 408 const node_ref& subDirDefinitionRef, entry_ref& _entryRef, 409 node_ref& _nodeRef) 410 { 411 Info* info = _InfoForNodeRef(subDirDefinitionRef); 412 if (info == NULL) 413 return false; 414 415 Info* parentInfo = info->Parent(); 416 if (parentInfo == NULL) 417 return false; 418 419 _entryRef = parentInfo->DefinitionFileEntryRef(); 420 _nodeRef = parentInfo->DefinitionFileNodeRef(); 421 return _entryRef.name != NULL; 422 } 423 424 425 status_t 426 VirtualDirectoryManager::TranslateDirectoryEntry( 427 const node_ref& definitionFileRef, dirent* buffer) 428 { 429 NotOwningEntryRef entryRef(buffer->d_pdev, buffer->d_pino, buffer->d_name); 430 node_ref nodeRef(buffer->d_dev, buffer->d_ino); 431 432 status_t result = TranslateDirectoryEntry(definitionFileRef, entryRef, 433 nodeRef); 434 if (result != B_OK) 435 return result; 436 437 buffer->d_pdev = entryRef.device; 438 buffer->d_pino = entryRef.directory; 439 buffer->d_dev = nodeRef.device; 440 buffer->d_ino = nodeRef.node; 441 442 return B_OK; 443 } 444 445 446 status_t 447 VirtualDirectoryManager::TranslateDirectoryEntry( 448 const node_ref& definitionFileRef, entry_ref& _entryRef, node_ref& _nodeRef) 449 { 450 Info* parentInfo = _InfoForNodeRef(definitionFileRef); 451 if (parentInfo == NULL) 452 return B_BAD_VALUE; 453 454 // get the info for the entry 455 Info* info = parentInfo->GetChild(_entryRef.name); 456 if (info == NULL) { 457 // If not done yet, create a directory for the parent, where we can 458 // place the new definition file. 459 if (parentInfo->Id().IsEmpty()) { 460 BString id = BUuid().SetToRandom().ToString(); 461 if (id.IsEmpty()) 462 return B_NO_MEMORY; 463 464 BPath path(kTemporaryDefinitionFileBaseDirectoryPath, id); 465 status_t error = path.InitCheck(); 466 if (error != B_OK) 467 return error; 468 469 error = create_directory(path.Path(), 470 S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH); 471 if (error != B_OK) 472 return error; 473 474 struct stat st; 475 if (lstat(path.Path(), &st) != 0) 476 return errno; 477 478 parentInfo->SetId(id); 479 parentInfo->SetChildDefinitionsDirectoryRef( 480 node_ref(st.st_dev, st.st_ino)); 481 } 482 483 // create the definition file 484 const node_ref& directoryRef 485 = parentInfo->ChildDefinitionsDirectoryRef(); 486 NotOwningEntryRef entryRef(directoryRef, _entryRef.name); 487 488 BFile definitionFile; 489 status_t error = definitionFile.SetTo(&entryRef, 490 B_WRITE_ONLY | B_CREATE_FILE | B_ERASE_FILE); 491 if (error != B_OK) 492 return error; 493 494 node_ref nodeRef; 495 error = definitionFile.GetNodeRef(&nodeRef); 496 if (error != B_OK) 497 return error; 498 499 BNodeInfo nodeInfo(&definitionFile); 500 error = nodeInfo.SetType(kVirtualDirectoryMimeType); 501 if (error != B_OK) 502 return error; 503 504 // create the info 505 info = parentInfo->CreateChild(nodeRef, entryRef); 506 if (info == NULL || !_AddInfo(info)) 507 return B_NO_MEMORY; 508 509 // Write some info into the definition file that helps us to find the 510 // root definition file. This is only necessary when definition file 511 // entry refs are transferred between applications. Then the receiving 512 // application may need to find the root definition file and resolve 513 // the subdirectories. 514 const entry_ref& rootEntryRef 515 = parentInfo->Root()->Info()->DefinitionFileEntryRef(); 516 BString definitionFileContent; 517 definitionFileContent.SetToFormat( 518 "root {\n" 519 " device %" B_PRIdDEV "\n" 520 " directory %" B_PRIdINO "\n" 521 " name \"%s\"\n" 522 "}\n" 523 "subdir \"%s\"\n", 524 rootEntryRef.device, rootEntryRef.directory, rootEntryRef.name, 525 info->Path().String()); 526 // failure is not nice, but not mission critical for this application 527 if (!definitionFileContent.IsEmpty()) { 528 definitionFile.WriteAt(0, 529 definitionFileContent.String(), definitionFileContent.Length()); 530 } 531 } 532 533 const entry_ref& entryRef = info->DefinitionFileEntryRef(); 534 _nodeRef = info->DefinitionFileNodeRef(); 535 _entryRef.device = entryRef.device; 536 _entryRef.directory = entryRef.directory; 537 538 return B_OK; 539 } 540 541 542 bool 543 VirtualDirectoryManager::DefinitionFileChanged( 544 const node_ref& definitionFileRef) 545 { 546 Info* info = _InfoForNodeRef(definitionFileRef); 547 if (info == NULL) 548 return false; 549 550 _UpdateTree(info->Root()); 551 552 return _InfoForNodeRef(definitionFileRef) != NULL; 553 } 554 555 556 status_t 557 VirtualDirectoryManager::DirectoryRemoved(const node_ref& definitionFileRef) 558 { 559 Info* info = _InfoForNodeRef(definitionFileRef); 560 if (info == NULL) 561 return B_ENTRY_NOT_FOUND; 562 563 _RemoveDirectory(info); 564 565 // delete the info 566 if (info->Parent() == NULL) 567 delete info->Root(); 568 else 569 info->Parent()->DeleteChild(info); 570 571 return B_OK; 572 } 573 574 575 /*static*/ bool 576 VirtualDirectoryManager::GetEntry(const BStringList& directoryPaths, 577 const char* name, entry_ref* _ref, struct stat* _st) 578 { 579 int32 count = directoryPaths.CountStrings(); 580 for (int32 i = 0; i < count; i++) { 581 BPath path; 582 if (path.SetTo(directoryPaths.StringAt(i), name) != B_OK) 583 continue; 584 585 struct stat st; 586 if (lstat(path.Path(), &st) == 0) { 587 if (_ref != NULL) { 588 if (get_ref_for_path(path.Path(), _ref) != B_OK) 589 return false; 590 } 591 if (_st != NULL) 592 *_st = st; 593 return true; 594 } 595 } 596 597 return false; 598 } 599 600 601 VirtualDirectoryManager::Info* 602 VirtualDirectoryManager::_InfoForNodeRef(const node_ref& nodeRef) const 603 { 604 NodeRefInfoMap::const_iterator it = fInfos.find(nodeRef); 605 return it != fInfos.end() ? it->second : NULL; 606 } 607 608 609 bool 610 VirtualDirectoryManager::_AddInfo(Info* info) 611 { 612 try { 613 fInfos[info->DefinitionFileNodeRef()] = info; 614 return true; 615 } catch (...) { 616 return false; 617 } 618 } 619 620 621 void 622 VirtualDirectoryManager::_RemoveInfo(Info* info) 623 { 624 NodeRefInfoMap::iterator it = fInfos.find(info->DefinitionFileNodeRef()); 625 if (it != fInfos.end()) 626 fInfos.erase(it); 627 } 628 629 630 void 631 VirtualDirectoryManager::_UpdateTree(RootInfo* root) 632 { 633 bool changed = false; 634 status_t result = root->ReadDefinition(&changed); 635 if (result != B_OK) { 636 DirectoryRemoved(root->Info()->DefinitionFileNodeRef()); 637 return; 638 } 639 640 if (!changed) 641 return; 642 643 _UpdateTree(root->Info()); 644 } 645 646 647 void 648 VirtualDirectoryManager::_UpdateTree(Info* info) 649 { 650 const BStringList& directoryPaths = info->Root()->DirectoryPaths(); 651 652 int32 childCount = info->Children().CountItems(); 653 for (int32 i = childCount -1; i >= 0; i--) { 654 Info* childInfo = info->Children().ItemAt(i); 655 struct stat st; 656 if (GetEntry(directoryPaths, childInfo->Path(), NULL, &st) 657 && S_ISDIR(st.st_mode)) { 658 _UpdateTree(childInfo); 659 } else { 660 _RemoveDirectory(childInfo); 661 info->DeleteChildAt(i); 662 } 663 } 664 } 665 666 667 void 668 VirtualDirectoryManager::_RemoveDirectory(Info* info) 669 { 670 // recursively remove the subdirectories 671 for (int32 i = 0; Info* child = info->Children().ItemAt(i); i++) 672 _RemoveDirectory(child); 673 674 // remove the directory for the child definition file 675 if (!info->Id().IsEmpty()) { 676 BPath path(kTemporaryDefinitionFileBaseDirectoryPath, info->Id()); 677 if (path.InitCheck() == B_OK) 678 rmdir(path.Path()); 679 } 680 681 // unless this is the root directory, remove the definition file 682 if (info != info->Root()->Info()) 683 BEntry(&info->DefinitionFileEntryRef()).Remove(); 684 685 _RemoveInfo(info); 686 } 687 688 689 status_t 690 VirtualDirectoryManager::_ResolveUnknownDefinitionFile( 691 const node_ref& definitionFileNodeRef, 692 const entry_ref& definitionFileEntryRef, Info*& _info) 693 { 694 // This is either a root definition file or a subdir definition file 695 // created by another application. We'll just try to read the info from the 696 // file that a subdir definition file would contain. If that fails, we 697 // assume a root definition file. 698 entry_ref entryRef; 699 BString subDirPath; 700 if (_ReadSubDirectoryDefinitionFileInfo(definitionFileEntryRef, entryRef, 701 subDirPath) != B_OK) { 702 return _CreateRootInfo(definitionFileNodeRef, definitionFileEntryRef, 703 _info); 704 } 705 706 if (subDirPath.IsEmpty()) 707 return B_BAD_VALUE; 708 709 // get the root definition file node ref 710 node_ref nodeRef; 711 status_t error = BEntry(&entryRef).GetNodeRef(&nodeRef); 712 if (error != B_OK) 713 return error; 714 715 // resolve/create the root info 716 Info* info = _InfoForNodeRef(nodeRef); 717 if (info == NULL) { 718 error = _CreateRootInfo(nodeRef, entryRef, info); 719 if (error != B_OK) 720 return error; 721 } else if (info->Root()->Info() != info) 722 return B_BAD_VALUE; 723 724 const BStringList& rootDirectoryPaths = info->Root()->DirectoryPaths(); 725 726 // now we can traverse the subdir path and resolve all infos along the way 727 int32 nextComponentOffset = 0; 728 while (nextComponentOffset < subDirPath.Length()) { 729 int32 componentEnd = subDirPath.FindFirst('/', nextComponentOffset); 730 if (componentEnd >= 0) { 731 // skip duplicate '/'s 732 if (componentEnd == nextComponentOffset + 1) { 733 nextComponentOffset = componentEnd; 734 continue; 735 } 736 nextComponentOffset = componentEnd + 1; 737 } else { 738 componentEnd = subDirPath.Length(); 739 nextComponentOffset = componentEnd; 740 } 741 742 BString entryPath(subDirPath, componentEnd); 743 if (entryPath.IsEmpty()) 744 return B_NO_MEMORY; 745 746 struct stat st; 747 if (!GetEntry(rootDirectoryPaths, entryPath, &entryRef, &st)) 748 return B_ENTRY_NOT_FOUND; 749 750 if (!S_ISDIR(st.st_mode)) 751 return B_BAD_VALUE; 752 753 error = TranslateDirectoryEntry(info->DefinitionFileNodeRef(), entryRef, 754 nodeRef); 755 if (error != B_OK) 756 return error; 757 758 info = _InfoForNodeRef(nodeRef); 759 } 760 761 _info = info; 762 763 return B_OK; 764 } 765 766 767 status_t 768 VirtualDirectoryManager::_CreateRootInfo(const node_ref& definitionFileNodeRef, 769 const entry_ref& definitionFileEntryRef, Info*& _info) 770 { 771 RootInfo* root = new(std::nothrow) RootInfo(definitionFileNodeRef, 772 definitionFileEntryRef); 773 if (root == NULL || root->InitCheck() != B_OK) { 774 delete root; 775 return B_NO_MEMORY; 776 } 777 ObjectDeleter<RootInfo> rootDeleter(root); 778 779 status_t error = root->ReadDefinition(); 780 if (error != B_OK) 781 return error; 782 783 if (!_AddInfo(root->Info())) 784 return B_NO_MEMORY; 785 786 rootDeleter.Detach(); 787 _info = root->Info(); 788 789 return B_OK; 790 } 791 792 793 status_t 794 VirtualDirectoryManager::_ReadSubDirectoryDefinitionFileInfo( 795 const entry_ref& entryRef, entry_ref& _rootDefinitionFileEntryRef, 796 BString& _subDirPath) 797 { 798 BDriverSettings driverSettings; 799 status_t error = driverSettings.Load(entryRef); 800 if (error != B_OK) 801 return error; 802 803 const char* subDirPath = driverSettings.GetParameterValue("subdir"); 804 if (subDirPath == NULL || subDirPath[0] == '\0') 805 return B_BAD_DATA; 806 807 BDriverParameter rootParameter; 808 if (!driverSettings.FindParameter("root", &rootParameter)) 809 return B_BAD_DATA; 810 811 const char* name = rootParameter.GetParameterValue("name"); 812 dev_t device = rootParameter.GetInt32ParameterValue("device", -1, -1); 813 ino_t directory = rootParameter.GetInt64ParameterValue("directory"); 814 if (name == NULL || name[0] == '\0' || device < 0) 815 return B_BAD_DATA; 816 817 _rootDefinitionFileEntryRef = entry_ref(device, directory, name); 818 _subDirPath = subDirPath; 819 820 return !_subDirPath.IsEmpty() && _rootDefinitionFileEntryRef.name != NULL 821 ? B_OK : B_NO_MEMORY; 822 } 823 824 } // namespace BPrivate 825