1 /* 2 * Copyright 2007-2013, Haiku, Inc. All Rights Reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Axel Dörfler, axeld@pinc-software.de 7 * Stephan Aßmus, superstippi@gmx.de 8 * Ingo Weinhold, ingo_weinhold@gmx.de 9 */ 10 11 12 #include <PathMonitor.h> 13 14 #include <pthread.h> 15 #include <stdio.h> 16 17 #include <Autolock.h> 18 #include <Directory.h> 19 #include <Entry.h> 20 #include <Handler.h> 21 #include <Locker.h> 22 #include <Looper.h> 23 #include <Path.h> 24 #include <String.h> 25 26 #include <AutoDeleter.h> 27 #include <NotOwningEntryRef.h> 28 #include <ObjectList.h> 29 #include <util/OpenHashTable.h> 30 #include <util/SinglyLinkedList.h> 31 32 33 #undef TRACE 34 //#define TRACE_PATH_MONITOR 35 #ifdef TRACE_PATH_MONITOR 36 # define TRACE(...) debug_printf("BPathMonitor: " __VA_ARGS__) 37 #else 38 # define TRACE(...) ; 39 #endif 40 41 42 // TODO: Support symlink components in the path. 43 // TODO: Support mounting/unmounting of volumes in path components and within 44 // the watched path tree. 45 46 47 #define WATCH_NODE_FLAG_MASK 0x00ff 48 49 50 namespace { 51 52 53 struct Directory; 54 struct Node; 55 struct WatcherHashDefinition; 56 typedef BOpenHashTable<WatcherHashDefinition> WatcherMap; 57 58 59 static pthread_once_t sInitOnce = PTHREAD_ONCE_INIT; 60 static WatcherMap* sWatchers = NULL; 61 static BLooper* sLooper = NULL; 62 static BPathMonitor::BWatchingInterface* sDefaultWatchingInterface = NULL; 63 static BPathMonitor::BWatchingInterface* sWatchingInterface = NULL; 64 65 66 // #pragma mark - 67 68 69 /*! Returns empty path, if either \a parent or \a subPath is empty or an 70 allocation fails. 71 */ 72 static BString 73 make_path(const BString& parent, const char* subPath) 74 { 75 BString path = parent; 76 int32 length = path.Length(); 77 if (length == 0 || subPath[0] == '\0') 78 return BString(); 79 80 if (parent.ByteAt(length - 1) != '/') { 81 path << '/'; 82 if (path.Length() < ++length) 83 return BString(); 84 } 85 86 path << subPath; 87 if (path.Length() <= length) 88 return BString(); 89 return path; 90 } 91 92 93 // #pragma mark - Ancestor 94 95 96 class Ancestor { 97 public: 98 Ancestor(Ancestor* parent, const BString& path, size_t pathComponentOffset) 99 : 100 fParent(parent), 101 fChild(NULL), 102 fPath(path), 103 fEntryRef(-1, -1, fPath.String() + pathComponentOffset), 104 fNodeRef(), 105 fWatchingFlags(0), 106 fIsDirectory(false) 107 { 108 if (pathComponentOffset == 0) { 109 // must be "/" 110 fEntryRef.SetTo(-1, -1, "."); 111 } 112 113 if (fParent != NULL) 114 fParent->fChild = this; 115 } 116 117 Ancestor* Parent() const 118 { 119 return fParent; 120 } 121 122 Ancestor* Child() const 123 { 124 return fChild; 125 } 126 127 const BString& Path() const 128 { 129 return fPath; 130 } 131 132 const char* Name() const 133 { 134 return fEntryRef.name; 135 } 136 137 bool Exists() const 138 { 139 return fNodeRef.device >= 0; 140 } 141 142 const NotOwningEntryRef& EntryRef() const 143 { 144 return fEntryRef; 145 } 146 147 const node_ref& NodeRef() const 148 { 149 return fNodeRef; 150 } 151 152 bool IsDirectory() const 153 { 154 return fIsDirectory; 155 } 156 157 status_t StartWatching(uint32 pathFlags, BHandler* target) 158 { 159 // init entry ref 160 BEntry entry; 161 status_t error = entry.SetTo(fPath); 162 if (error != B_OK) 163 return error; 164 165 entry_ref entryRef; 166 error = entry.GetRef(&entryRef); 167 if (error != B_OK) 168 return error; 169 170 fEntryRef.device = entryRef.device; 171 fEntryRef.directory = entryRef.directory; 172 173 // init node ref 174 struct stat st; 175 error = entry.GetStat(&st); 176 if (error != B_OK) 177 return error == B_ENTRY_NOT_FOUND ? B_OK : error; 178 179 fNodeRef = node_ref(st.st_dev, st.st_ino); 180 fIsDirectory = S_ISDIR(st.st_mode); 181 182 // start watching 183 uint32 flags = fChild == NULL ? pathFlags : B_WATCH_DIRECTORY; 184 // In theory B_WATCH_NAME would suffice for all existing ancestors, 185 // plus B_WATCH_DIRECTORY for the parent of the first not existing 186 // ancestor. In practice this complicates the transitions when an 187 // ancestor is created/removed/moved. 188 if (flags != 0) { 189 error = sWatchingInterface->WatchNode(&fNodeRef, flags, target); 190 TRACE(" started to watch ancestor %p (\"%s\", %#" B_PRIx32 191 ") -> %s\n", this, Name(), flags, strerror(error)); 192 if (error != B_OK) 193 return error; 194 } 195 196 fWatchingFlags = flags; 197 return B_OK; 198 } 199 200 void StopWatching(BHandler* target) 201 { 202 // stop watching 203 if (fWatchingFlags != 0) { 204 sWatchingInterface->WatchNode(&fNodeRef, B_STOP_WATCHING, target); 205 fWatchingFlags = 0; 206 } 207 208 // uninitialize node and entry ref 209 fIsDirectory = false; 210 fNodeRef = node_ref(); 211 fEntryRef.SetDirectoryNodeRef(node_ref()); 212 } 213 214 Ancestor*& HashNext() 215 { 216 return fHashNext; 217 } 218 219 private: 220 Ancestor* fParent; 221 Ancestor* fChild; 222 Ancestor* fHashNext; 223 BString fPath; 224 NotOwningEntryRef fEntryRef; 225 node_ref fNodeRef; 226 uint32 fWatchingFlags; 227 bool fIsDirectory; 228 }; 229 230 231 // #pragma mark - AncestorMap 232 233 234 struct AncestorHashDefinition { 235 typedef node_ref KeyType; 236 typedef Ancestor ValueType; 237 238 size_t HashKey(const node_ref& key) const 239 { 240 return size_t(key.device ^ key.node); 241 } 242 243 size_t Hash(Ancestor* value) const 244 { 245 return HashKey(value->NodeRef()); 246 } 247 248 bool Compare(const node_ref& key, Ancestor* value) const 249 { 250 return key == value->NodeRef(); 251 } 252 253 Ancestor*& GetLink(Ancestor* value) const 254 { 255 return value->HashNext(); 256 } 257 }; 258 259 260 typedef BOpenHashTable<AncestorHashDefinition> AncestorMap; 261 262 263 // #pragma mark - Entry 264 265 266 class Entry : public SinglyLinkedListLinkImpl<Entry> { 267 public: 268 Entry(Directory* parent, const BString& name, ::Node* node) 269 : 270 fParent(parent), 271 fName(name), 272 fNode(node) 273 { 274 } 275 276 Directory* Parent() const 277 { 278 return fParent; 279 } 280 281 const BString& Name() const 282 { 283 return fName; 284 } 285 286 ::Node* Node() const 287 { 288 return fNode; 289 } 290 291 void SetNode(::Node* node) 292 { 293 fNode = node; 294 } 295 296 inline NotOwningEntryRef EntryRef() const; 297 298 Entry*& HashNext() 299 { 300 return fHashNext; 301 } 302 303 private: 304 Directory* fParent; 305 BString fName; 306 ::Node* fNode; 307 Entry* fHashNext; 308 }; 309 310 typedef SinglyLinkedList<Entry> EntryList; 311 312 313 // EntryMap 314 315 316 struct EntryHashDefinition { 317 typedef const char* KeyType; 318 typedef Entry ValueType; 319 320 size_t HashKey(const char* key) const 321 { 322 return BString::HashValue(key); 323 } 324 325 size_t Hash(Entry* value) const 326 { 327 return value->Name().HashValue(); 328 } 329 330 bool Compare(const char* key, Entry* value) const 331 { 332 return value->Name() == key; 333 } 334 335 Entry*& GetLink(Entry* value) const 336 { 337 return value->HashNext(); 338 } 339 }; 340 341 342 typedef BOpenHashTable<EntryHashDefinition> EntryMap; 343 344 345 // #pragma mark - Node 346 347 348 class Node { 349 public: 350 Node(const node_ref& nodeRef) 351 : 352 fNodeRef(nodeRef) 353 { 354 } 355 356 virtual ~Node() 357 { 358 } 359 360 virtual bool IsDirectory() const 361 { 362 return false; 363 } 364 365 virtual Directory* ToDirectory() 366 { 367 return NULL; 368 } 369 370 const node_ref& NodeRef() const 371 { 372 return fNodeRef; 373 } 374 375 const EntryList& Entries() const 376 { 377 return fEntries; 378 } 379 380 bool HasEntries() const 381 { 382 return !fEntries.IsEmpty(); 383 } 384 385 Entry* FirstNodeEntry() const 386 { 387 return fEntries.Head(); 388 } 389 390 bool IsOnlyNodeEntry(Entry* entry) const 391 { 392 return entry == fEntries.Head() && fEntries.GetNext(entry) == NULL; 393 } 394 395 void AddNodeEntry(Entry* entry) 396 { 397 fEntries.Add(entry); 398 } 399 400 void RemoveNodeEntry(Entry* entry) 401 { 402 fEntries.Remove(entry); 403 } 404 405 Node*& HashNext() 406 { 407 return fHashNext; 408 } 409 410 private: 411 node_ref fNodeRef; 412 EntryList fEntries; 413 Node* fHashNext; 414 }; 415 416 417 struct NodeHashDefinition { 418 typedef node_ref KeyType; 419 typedef Node ValueType; 420 421 size_t HashKey(const node_ref& key) const 422 { 423 return size_t(key.device ^ key.node); 424 } 425 426 size_t Hash(Node* value) const 427 { 428 return HashKey(value->NodeRef()); 429 } 430 431 bool Compare(const node_ref& key, Node* value) const 432 { 433 return key == value->NodeRef(); 434 } 435 436 Node*& GetLink(Node* value) const 437 { 438 return value->HashNext(); 439 } 440 }; 441 442 443 typedef BOpenHashTable<NodeHashDefinition> NodeMap; 444 445 446 // #pragma mark - Directory 447 448 449 class Directory : public Node { 450 public: 451 static Directory* Create(const node_ref& nodeRef) 452 { 453 Directory* directory = new(std::nothrow) Directory(nodeRef); 454 if (directory == NULL || directory->fEntries.Init() != B_OK) { 455 delete directory; 456 return NULL; 457 } 458 459 return directory; 460 } 461 462 virtual bool IsDirectory() const 463 { 464 return true; 465 } 466 467 virtual Directory* ToDirectory() 468 { 469 return this; 470 } 471 472 Entry* FindEntry(const char* name) const 473 { 474 return fEntries.Lookup(name); 475 } 476 477 Entry* CreateEntry(const BString& name, Node* node) 478 { 479 Entry* entry = new(std::nothrow) Entry(this, name, node); 480 if (entry == NULL || entry->Name().IsEmpty()) { 481 delete entry; 482 return NULL; 483 } 484 485 AddEntry(entry); 486 return entry; 487 } 488 489 void AddEntry(Entry* entry) 490 { 491 fEntries.Insert(entry); 492 } 493 494 void RemoveEntry(Entry* entry) 495 { 496 fEntries.Remove(entry); 497 } 498 499 EntryMap::Iterator GetEntryIterator() const 500 { 501 return fEntries.GetIterator(); 502 } 503 504 Entry* RemoveAllEntries() 505 { 506 return fEntries.Clear(true); 507 } 508 509 private: 510 Directory(const node_ref& nodeRef) 511 : 512 Node(nodeRef) 513 { 514 } 515 516 private: 517 EntryMap fEntries; 518 }; 519 520 521 // #pragma mark - Entry 522 523 524 inline NotOwningEntryRef 525 Entry::EntryRef() const 526 { 527 return NotOwningEntryRef(fParent->NodeRef(), fName); 528 } 529 530 531 // #pragma mark - PathHandler 532 533 534 class PathHandler : public BHandler { 535 public: 536 PathHandler(const char* path, uint32 flags, 537 const BMessenger& target, BLooper* looper); 538 virtual ~PathHandler(); 539 540 status_t InitCheck() const; 541 void Quit(); 542 543 const BString& OriginalPath() const 544 { return fOriginalPath; } 545 uint32 Flags() const { return fFlags; } 546 547 virtual void MessageReceived(BMessage* message); 548 549 PathHandler*& HashNext() { return fHashNext; } 550 551 private: 552 status_t _CreateAncestors(); 553 status_t _StartWatchingAncestors(Ancestor* ancestor, 554 bool notify); 555 void _StopWatchingAncestors(Ancestor* ancestor, 556 bool notify); 557 558 void _EntryCreated(BMessage* message); 559 void _EntryRemoved(BMessage* message); 560 void _EntryMoved(BMessage* message); 561 void _NodeChanged(BMessage* message); 562 563 bool _EntryCreated(const NotOwningEntryRef& entryRef, 564 const node_ref& nodeRef, bool isDirectory, 565 bool dryRun, bool notify, Entry** _entry); 566 bool _EntryRemoved(const NotOwningEntryRef& entryRef, 567 const node_ref& nodeRef, bool dryRun, 568 bool notify, Entry** _keepEntry); 569 570 bool _CheckDuplicateEntryNotification(int32 opcode, 571 const entry_ref& toEntryRef, 572 const node_ref& nodeRef, 573 const entry_ref* fromEntryRef = NULL); 574 void _UnsetDuplicateEntryNotification(); 575 576 Ancestor* _GetAncestor(const node_ref& nodeRef) const; 577 578 status_t _AddNode(const node_ref& nodeRef, 579 bool isDirectory, bool notify, 580 Entry* entry = NULL, Node** _node = NULL); 581 void _DeleteNode(Node* node, bool notify); 582 Node* _GetNode(const node_ref& nodeRef) const; 583 584 status_t _AddEntryIfNeeded(Directory* directory, 585 const char* name, const node_ref& nodeRef, 586 bool isDirectory, bool notify, 587 Entry** _entry = NULL); 588 void _DeleteEntry(Entry* entry, bool notify); 589 void _DeleteEntryAlreadyRemovedFromParent( 590 Entry* entry, bool notify); 591 592 void _NotifyFilesCreatedOrRemoved(Entry* entry, 593 int32 opcode) const; 594 void _NotifyEntryCreatedOrRemoved(Entry* entry, 595 int32 opcode) const; 596 void _NotifyEntryCreatedOrRemoved( 597 const entry_ref& entryRef, 598 const node_ref& nodeRef, const char* path, 599 bool isDirectory, int32 opcode) const; 600 void _NotifyEntryMoved(const entry_ref& fromEntryRef, 601 const entry_ref& toEntryRef, 602 const node_ref& nodeRef, 603 const char* fromPath, const char* path, 604 bool isDirectory, bool wasAdded, 605 bool wasRemoved) const; 606 void _NotifyTarget(BMessage& message, 607 const char* path) const; 608 609 BString _NodePath(const Node* node) const; 610 BString _EntryPath(const Entry* entry) const; 611 612 613 bool _WatchRecursively() const; 614 bool _WatchFilesOnly() const; 615 bool _WatchDirectoriesOnly() const; 616 617 private: 618 BMessenger fTarget; 619 uint32 fFlags; 620 status_t fStatus; 621 BString fOriginalPath; 622 BString fPath; 623 Ancestor* fRoot; 624 Ancestor* fBaseAncestor; 625 Node* fBaseNode; 626 AncestorMap fAncestors; 627 NodeMap fNodes; 628 PathHandler* fHashNext; 629 int32 fDuplicateEntryNotificationOpcode; 630 node_ref fDuplicateEntryNotificationNodeRef; 631 entry_ref fDuplicateEntryNotificationToEntryRef; 632 entry_ref fDuplicateEntryNotificationFromEntryRef; 633 }; 634 635 636 struct PathHandlerHashDefinition { 637 typedef const char* KeyType; 638 typedef PathHandler ValueType; 639 640 size_t HashKey(const char* key) const 641 { 642 return BString::HashValue(key); 643 } 644 645 size_t Hash(PathHandler* value) const 646 { 647 return value->OriginalPath().HashValue(); 648 } 649 650 bool Compare(const char* key, PathHandler* value) const 651 { 652 return key == value->OriginalPath(); 653 } 654 655 PathHandler*& GetLink(PathHandler* value) const 656 { 657 return value->HashNext(); 658 } 659 }; 660 661 662 typedef BOpenHashTable<PathHandlerHashDefinition> PathHandlerMap; 663 664 665 // #pragma mark - Watcher 666 667 668 struct Watcher : public PathHandlerMap { 669 static Watcher* Create(const BMessenger& target) 670 { 671 Watcher* watcher = new(std::nothrow) Watcher(target); 672 if (watcher == NULL || watcher->Init() != B_OK) { 673 delete watcher; 674 return NULL; 675 } 676 return watcher; 677 } 678 679 const BMessenger& Target() const 680 { 681 return fTarget; 682 } 683 684 Watcher*& HashNext() 685 { 686 return fHashNext; 687 } 688 689 private: 690 Watcher(const BMessenger& target) 691 : 692 fTarget(target) 693 { 694 } 695 696 private: 697 BMessenger fTarget; 698 Watcher* fHashNext; 699 }; 700 701 702 struct WatcherHashDefinition { 703 typedef BMessenger KeyType; 704 typedef Watcher ValueType; 705 706 size_t HashKey(const BMessenger& key) const 707 { 708 return key.HashValue(); 709 } 710 711 size_t Hash(Watcher* value) const 712 { 713 return HashKey(value->Target()); 714 } 715 716 bool Compare(const BMessenger& key, Watcher* value) const 717 { 718 return key == value->Target(); 719 } 720 721 Watcher*& GetLink(Watcher* value) const 722 { 723 return value->HashNext(); 724 } 725 }; 726 727 728 // #pragma mark - PathHandler 729 730 731 PathHandler::PathHandler(const char* path, uint32 flags, 732 const BMessenger& target, BLooper* looper) 733 : 734 BHandler(path), 735 fTarget(target), 736 fFlags(flags), 737 fStatus(B_OK), 738 fOriginalPath(path), 739 fPath(), 740 fRoot(NULL), 741 fBaseAncestor(NULL), 742 fBaseNode(NULL), 743 fAncestors(), 744 fNodes() 745 { 746 TRACE("%p->PathHandler::PathHandler(\"%s\", %#" B_PRIx32 ")\n", this, path, 747 flags); 748 749 _UnsetDuplicateEntryNotification(); 750 751 fStatus = fAncestors.Init(); 752 if (fStatus != B_OK) 753 return; 754 755 fStatus = fNodes.Init(); 756 if (fStatus != B_OK) 757 return; 758 759 // normalize the flags 760 if ((fFlags & B_WATCH_RECURSIVELY) != 0) { 761 // We add B_WATCH_NAME and B_WATCH_DIRECTORY as needed, so clear them 762 // here. 763 fFlags &= ~uint32(B_WATCH_NAME | B_WATCH_DIRECTORY); 764 } else { 765 // The B_WATCH_*_ONLY flags are only valid for the recursive mode. 766 // B_WATCH_NAME is implied (we watch the parent directory). 767 fFlags &= ~uint32(B_WATCH_FILES_ONLY | B_WATCH_DIRECTORIES_ONLY 768 | B_WATCH_NAME); 769 } 770 771 // Normalize the path a bit. We can't use BPath, as it may really normalize 772 // the path, i.e. resolve symlinks and such, which may cause us to monitor 773 // the wrong path. We want some normalization, though: 774 // * relative -> absolute path 775 // * fold duplicate '/'s 776 // * omit "." components 777 // * fail when encountering ".." components 778 779 // make absolute 780 BString normalizedPath; 781 if (path[0] == '/') { 782 normalizedPath = "/"; 783 path++; 784 } else 785 normalizedPath = BPath(".").Path(); 786 if (normalizedPath.IsEmpty()) { 787 fStatus = B_NO_MEMORY; 788 return; 789 } 790 791 // parse path components 792 const char* pathEnd = path + strlen(path); 793 for (;;) { 794 // skip '/'s 795 while (path[0] == '/') 796 path++; 797 if (path == pathEnd) 798 break; 799 800 const char* componentEnd = strchr(path, '/'); 801 if (componentEnd == NULL) 802 componentEnd = pathEnd; 803 size_t componentLength = componentEnd - path; 804 805 // handle ".' and ".." 806 if (path[0] == '.') { 807 if (componentLength == 1) { 808 path = componentEnd; 809 continue; 810 } 811 if (componentLength == 2 && path[1] == '.') { 812 fStatus = B_BAD_VALUE; 813 return; 814 } 815 } 816 817 int32 normalizedPathLength = normalizedPath.Length(); 818 if (normalizedPath.ByteAt(normalizedPathLength - 1) != '/') { 819 normalizedPath << '/'; 820 normalizedPathLength++; 821 } 822 normalizedPath.Append(path, componentEnd - path); 823 normalizedPathLength += int32(componentEnd - path); 824 825 if (normalizedPath.Length() != normalizedPathLength) { 826 fStatus = B_NO_MEMORY; 827 return; 828 } 829 830 path = componentEnd; 831 } 832 833 fPath = normalizedPath; 834 835 // Create the Ancestor objects -- they correspond to the path components and 836 // are used for watching changes that affect the entries on the path. 837 fStatus = _CreateAncestors(); 838 if (fStatus != B_OK) 839 return; 840 841 // add ourselves to the looper 842 looper->AddHandler(this); 843 844 // start watching 845 fStatus = _StartWatchingAncestors(fRoot, false); 846 if (fStatus != B_OK) 847 return; 848 } 849 850 851 PathHandler::~PathHandler() 852 { 853 TRACE("%p->PathHandler::~PathHandler(\"%s\", %#" B_PRIx32 ")\n", this, 854 fPath.String(), fFlags); 855 856 if (fBaseNode != NULL) 857 _DeleteNode(fBaseNode, false); 858 859 while (fRoot != NULL) { 860 Ancestor* nextAncestor = fRoot->Child(); 861 delete fRoot; 862 fRoot = nextAncestor; 863 } 864 } 865 866 867 status_t 868 PathHandler::InitCheck() const 869 { 870 return fStatus; 871 } 872 873 874 void 875 PathHandler::Quit() 876 { 877 TRACE("%p->PathHandler::Quit()\n", this); 878 sWatchingInterface->StopWatching(this); 879 sLooper->RemoveHandler(this); 880 delete this; 881 } 882 883 884 void 885 PathHandler::MessageReceived(BMessage* message) 886 { 887 switch (message->what) { 888 case B_NODE_MONITOR: 889 { 890 int32 opcode; 891 if (message->FindInt32("opcode", &opcode) != B_OK) 892 return; 893 894 switch (opcode) { 895 case B_ENTRY_CREATED: 896 _EntryCreated(message); 897 break; 898 899 case B_ENTRY_REMOVED: 900 _EntryRemoved(message); 901 break; 902 903 case B_ENTRY_MOVED: 904 _EntryMoved(message); 905 break; 906 907 default: 908 _UnsetDuplicateEntryNotification(); 909 _NodeChanged(message); 910 break; 911 } 912 913 break; 914 } 915 916 default: 917 BHandler::MessageReceived(message); 918 break; 919 } 920 } 921 922 923 status_t 924 PathHandler::_CreateAncestors() 925 { 926 TRACE("%p->PathHandler::_CreateAncestors()\n", this); 927 928 // create the Ancestor objects 929 const char* path = fPath.String(); 930 const char* pathEnd = path + fPath.Length(); 931 const char* component = path; 932 933 Ancestor* ancestor = NULL; 934 935 while (component < pathEnd) { 936 const char* componentEnd = component == path 937 ? component + 1 : strchr(component, '/'); 938 if (componentEnd == NULL) 939 componentEnd = pathEnd; 940 941 BString ancestorPath(path, componentEnd - path); 942 if (ancestorPath.IsEmpty()) 943 return B_NO_MEMORY; 944 945 ancestor = new(std::nothrow) Ancestor(ancestor, ancestorPath, 946 component - path); 947 TRACE(" created ancestor %p (\"%s\" / \"%s\")\n", ancestor, 948 ancestor->Path().String(), ancestor->Name()); 949 if (ancestor == NULL) 950 return B_NO_MEMORY; 951 952 if (fRoot == NULL) 953 fRoot = ancestor; 954 955 component = componentEnd[0] == '/' ? componentEnd + 1 : componentEnd; 956 } 957 958 fBaseAncestor = ancestor; 959 960 return B_OK; 961 } 962 963 964 status_t 965 PathHandler::_StartWatchingAncestors(Ancestor* startAncestor, bool notify) 966 { 967 TRACE("%p->PathHandler::_StartWatchingAncestors(%p, %d)\n", this, 968 startAncestor, notify); 969 970 // The watch flags for the path (if it exists). Recursively implies 971 // directory, since we need to watch the entries. 972 uint32 watchFlags = (fFlags & WATCH_NODE_FLAG_MASK) 973 | (_WatchRecursively() ? B_WATCH_DIRECTORY : 0); 974 975 for (Ancestor* ancestor = startAncestor; ancestor != NULL; 976 ancestor = ancestor->Child()) { 977 status_t error = ancestor->StartWatching(watchFlags, this); 978 if (error != B_OK) 979 return error; 980 981 if (!ancestor->Exists()) { 982 TRACE(" -> ancestor doesn't exist\n"); 983 break; 984 } 985 986 fAncestors.Insert(ancestor); 987 } 988 989 if (!fBaseAncestor->Exists()) 990 return B_OK; 991 992 if (notify) { 993 _NotifyEntryCreatedOrRemoved(fBaseAncestor->EntryRef(), 994 fBaseAncestor->NodeRef(), fPath, fBaseAncestor->IsDirectory(), 995 B_ENTRY_CREATED); 996 } 997 998 if (!_WatchRecursively()) 999 return B_OK; 1000 1001 status_t error = _AddNode(fBaseAncestor->NodeRef(), 1002 fBaseAncestor->IsDirectory(), notify && _WatchFilesOnly(), NULL, 1003 &fBaseNode); 1004 if (error != B_OK) 1005 return error; 1006 1007 return B_OK; 1008 } 1009 1010 1011 void 1012 PathHandler::_StopWatchingAncestors(Ancestor* ancestor, bool notify) 1013 { 1014 // stop watching the tree below path 1015 if (fBaseNode != NULL) { 1016 _DeleteNode(fBaseNode, notify && _WatchFilesOnly()); 1017 fBaseNode = NULL; 1018 } 1019 1020 if (notify && fBaseAncestor->Exists() 1021 && (fBaseAncestor->IsDirectory() 1022 ? !_WatchFilesOnly() : !_WatchDirectoriesOnly())) { 1023 _NotifyEntryCreatedOrRemoved(fBaseAncestor->EntryRef(), 1024 fBaseAncestor->NodeRef(), fPath, fBaseAncestor->IsDirectory(), 1025 B_ENTRY_REMOVED); 1026 } 1027 1028 // stop watching the ancestors and uninitialize their entries 1029 for (; ancestor != NULL; ancestor = ancestor->Child()) { 1030 if (ancestor->Exists()) 1031 fAncestors.Remove(ancestor); 1032 ancestor->StopWatching(this); 1033 } 1034 } 1035 1036 1037 void 1038 PathHandler::_EntryCreated(BMessage* message) 1039 { 1040 // TODO: Unless we're watching files only, we might want to forward (some 1041 // of) the messages that don't agree with our model, since our client 1042 // maintains its model at a different time and the notification might be 1043 // necessary to keep it up-to-date. E.g. consider the following case: 1044 // 1. a directory is created 1045 // 2. a file is created in the directory 1046 // 3. the file is removed from the directory 1047 // If we get the notification after 1. and before 2., we pass it on to the 1048 // client, which may get it after 2. and before 3., thus seeing the file. 1049 // If we then get the entry-created notification after 3., we don't see the 1050 // file anymore and ignore the notification as well as the following 1051 // entry-removed notification. That is the client will never know that the 1052 // file has been removed. This can only happen in recursive mode. Otherwise 1053 // (and with B_WATCH_DIRECTORY) we just pass on all notifications. 1054 // A possible solution could be to just create a zombie entry and pass on 1055 // the entry-created notification. We wouldn't be able to adhere to the 1056 // B_WATCH_FILES_ONLY/B_WATCH_DIRECTORIES_ONLY flags, but that should be 1057 // acceptable. Either the client hasn't seen the entry either -- then it 1058 // doesn't matter -- or it likely has ignored a not matching entry anyway. 1059 1060 NotOwningEntryRef entryRef; 1061 node_ref nodeRef; 1062 1063 if (message->FindInt32("device", &nodeRef.device) != B_OK 1064 || message->FindInt64("node", &nodeRef.node) != B_OK 1065 || message->FindInt64("directory", &entryRef.directory) != B_OK 1066 || message->FindString("name", (const char**)&entryRef.name) != B_OK) { 1067 return; 1068 } 1069 entryRef.device = nodeRef.device; 1070 1071 if (_CheckDuplicateEntryNotification(B_ENTRY_CREATED, entryRef, nodeRef)) 1072 return; 1073 1074 TRACE("%p->PathHandler::_EntryCreated(): entry: %" B_PRIdDEV ":%" B_PRIdINO 1075 ":\"%s\", node: %" B_PRIdDEV ":%" B_PRIdINO "\n", this, entryRef.device, 1076 entryRef.directory, entryRef.name, nodeRef.device, nodeRef.node); 1077 1078 BEntry entry; 1079 struct stat st; 1080 if (entry.SetTo(&entryRef) != B_OK || entry.GetStat(&st) != B_OK 1081 || nodeRef != node_ref(st.st_dev, st.st_ino)) { 1082 return; 1083 } 1084 1085 _EntryCreated(entryRef, nodeRef, S_ISDIR(st.st_mode), false, true, NULL); 1086 } 1087 1088 1089 void 1090 PathHandler::_EntryRemoved(BMessage* message) 1091 { 1092 NotOwningEntryRef entryRef; 1093 node_ref nodeRef; 1094 1095 if (message->FindInt32("device", &nodeRef.device) != B_OK 1096 || message->FindInt64("node", &nodeRef.node) != B_OK 1097 || message->FindInt64("directory", &entryRef.directory) != B_OK 1098 || message->FindString("name", (const char**)&entryRef.name) != B_OK) { 1099 return; 1100 } 1101 entryRef.device = nodeRef.device; 1102 1103 if (_CheckDuplicateEntryNotification(B_ENTRY_REMOVED, entryRef, nodeRef)) 1104 return; 1105 1106 TRACE("%p->PathHandler::_EntryRemoved(): entry: %" B_PRIdDEV ":%" B_PRIdINO 1107 ":\"%s\", node: %" B_PRIdDEV ":%" B_PRIdINO "\n", this, entryRef.device, 1108 entryRef.directory, entryRef.name, nodeRef.device, nodeRef.node); 1109 1110 _EntryRemoved(entryRef, nodeRef, false, true, NULL); 1111 } 1112 1113 1114 void 1115 PathHandler::_EntryMoved(BMessage* message) 1116 { 1117 NotOwningEntryRef fromEntryRef; 1118 NotOwningEntryRef toEntryRef; 1119 node_ref nodeRef; 1120 1121 if (message->FindInt32("node device", &nodeRef.device) != B_OK 1122 || message->FindInt64("node", &nodeRef.node) != B_OK 1123 || message->FindInt32("device", &fromEntryRef.device) != B_OK 1124 || message->FindInt64("from directory", &fromEntryRef.directory) != B_OK 1125 || message->FindInt64("to directory", &toEntryRef.directory) != B_OK 1126 || message->FindString("from name", (const char**)&fromEntryRef.name) 1127 != B_OK 1128 || message->FindString("name", (const char**)&toEntryRef.name) 1129 != B_OK) { 1130 return; 1131 } 1132 toEntryRef.device = fromEntryRef.device; 1133 1134 if (_CheckDuplicateEntryNotification(B_ENTRY_MOVED, toEntryRef, nodeRef, 1135 &fromEntryRef)) { 1136 return; 1137 } 1138 1139 TRACE("%p->PathHandler::_EntryMoved(): entry: %" B_PRIdDEV ":%" B_PRIdINO 1140 ":\"%s\" -> %" B_PRIdDEV ":%" B_PRIdINO ":\"%s\", node: %" B_PRIdDEV 1141 ":%" B_PRIdINO "\n", this, fromEntryRef.device, fromEntryRef.directory, 1142 fromEntryRef.name, toEntryRef.device, toEntryRef.directory, 1143 toEntryRef.name, nodeRef.device, nodeRef.node); 1144 1145 BEntry entry; 1146 struct stat st; 1147 if (entry.SetTo(&toEntryRef) != B_OK || entry.GetStat(&st) != B_OK 1148 || nodeRef != node_ref(st.st_dev, st.st_ino)) { 1149 _EntryRemoved(fromEntryRef, nodeRef, false, true, NULL); 1150 return; 1151 } 1152 bool isDirectory = S_ISDIR(st.st_mode); 1153 1154 Ancestor* fromAncestor = _GetAncestor(fromEntryRef.DirectoryNodeRef()); 1155 Ancestor* toAncestor = _GetAncestor(toEntryRef.DirectoryNodeRef()); 1156 1157 if (_WatchRecursively()) { 1158 Node* fromDirectoryNode = _GetNode(fromEntryRef.DirectoryNodeRef()); 1159 Node* toDirectoryNode = _GetNode(toEntryRef.DirectoryNodeRef()); 1160 if (fromDirectoryNode != NULL || toDirectoryNode != NULL) { 1161 // Check whether _EntryRemoved()/_EntryCreated() can handle the 1162 // respective entry regularly (i.e. don't encounter an out-of-sync 1163 // issue) or don't need to be called at all (entry outside the 1164 // monitored tree). 1165 if ((fromDirectoryNode == NULL 1166 || _EntryRemoved(fromEntryRef, nodeRef, true, false, NULL)) 1167 && (toDirectoryNode == NULL 1168 || _EntryCreated(toEntryRef, nodeRef, isDirectory, true, 1169 false, NULL))) { 1170 // The entries can be handled regularly. We delegate the work to 1171 // _EntryRemoved() and _EntryCreated() and only handle the 1172 // notification ourselves. 1173 1174 // handle removed 1175 Entry* removedEntry = NULL; 1176 if (fromDirectoryNode != NULL) { 1177 _EntryRemoved(fromEntryRef, nodeRef, false, false, 1178 &removedEntry); 1179 } 1180 1181 // handle created 1182 Entry* createdEntry = NULL; 1183 if (toDirectoryNode != NULL) { 1184 _EntryCreated(toEntryRef, nodeRef, isDirectory, false, 1185 false, &createdEntry); 1186 } 1187 1188 // notify 1189 if (_WatchFilesOnly() && isDirectory) { 1190 // recursively iterate through the removed and created 1191 // hierarchy and send notifications for the files 1192 if (removedEntry != NULL) { 1193 _NotifyFilesCreatedOrRemoved(removedEntry, 1194 B_ENTRY_REMOVED); 1195 } 1196 1197 if (createdEntry != NULL) { 1198 _NotifyFilesCreatedOrRemoved(createdEntry, 1199 B_ENTRY_CREATED); 1200 } 1201 } else { 1202 BString fromPath; 1203 if (fromDirectoryNode != NULL) { 1204 fromPath = make_path(_NodePath(fromDirectoryNode), 1205 fromEntryRef.name); 1206 } 1207 1208 BString path; 1209 if (toDirectoryNode != NULL) { 1210 path = make_path(_NodePath(toDirectoryNode), 1211 toEntryRef.name); 1212 } 1213 1214 _NotifyEntryMoved(fromEntryRef, toEntryRef, nodeRef, 1215 fromPath, path, isDirectory, fromDirectoryNode == NULL, 1216 toDirectoryNode == NULL); 1217 } 1218 1219 if (removedEntry != NULL) 1220 _DeleteEntry(removedEntry, false); 1221 } else { 1222 // The entries can't be handled regularly. We delegate all the 1223 // work to _EntryRemoved() and _EntryCreated(). This will 1224 // generate separate entry-removed and entry-created 1225 // notifications. 1226 1227 // handle removed 1228 if (fromDirectoryNode != NULL) 1229 _EntryRemoved(fromEntryRef, nodeRef, false, true, NULL); 1230 1231 // handle created 1232 if (toDirectoryNode != NULL) { 1233 _EntryCreated(toEntryRef, nodeRef, isDirectory, false, true, 1234 NULL); 1235 } 1236 } 1237 1238 return; 1239 } 1240 1241 if (fromAncestor == fBaseAncestor || toAncestor == fBaseAncestor) { 1242 // That should never happen, as we should have found a matching 1243 // directory node in this case. 1244 #ifdef DEBUG 1245 debugger("path ancestor exists, but doesn't have a directory"); 1246 // Could actually be an out-of-memory situation, if we simply failed 1247 // to create the directory earlier. 1248 #endif 1249 _StopWatchingAncestors(fRoot, false); 1250 _StartWatchingAncestors(fRoot, false); 1251 return; 1252 } 1253 } else { 1254 // Non-recursive mode: This notification is only of interest to us, if 1255 // it is either a move into/within/out of the path and B_WATCH_DIRECTORY 1256 // is set, or an ancestor might be affected. 1257 if (fromAncestor == NULL && toAncestor == NULL) 1258 return; 1259 1260 if (fromAncestor == fBaseAncestor || toAncestor == fBaseAncestor) { 1261 if ((fFlags & B_WATCH_DIRECTORY) != 0) { 1262 BString fromPath; 1263 if (fromAncestor == fBaseAncestor) 1264 fromPath = make_path(fPath, fromEntryRef.name); 1265 1266 BString path; 1267 if (toAncestor == fBaseAncestor) 1268 path = make_path(fPath, toEntryRef.name); 1269 1270 _NotifyEntryMoved(fromEntryRef, toEntryRef, nodeRef, 1271 fromPath, path, isDirectory, fromAncestor == NULL, 1272 toAncestor == NULL); 1273 } 1274 return; 1275 } 1276 } 1277 1278 if (fromAncestor == NULL && toAncestor == NULL) 1279 return; 1280 1281 if (fromAncestor == NULL) { 1282 _EntryCreated(toEntryRef, nodeRef, isDirectory, false, true, NULL); 1283 return; 1284 } 1285 1286 if (toAncestor == NULL) { 1287 _EntryRemoved(fromEntryRef, nodeRef, false, true, NULL); 1288 return; 1289 } 1290 1291 // An entry was moved in a true ancestor directory or between true ancestor 1292 // directories. Unless the moved entry was or becomes our base ancestor, we 1293 // let _EntryRemoved() and _EntryCreated() handle it. 1294 bool fromIsBase = fromAncestor == fBaseAncestor->Parent() 1295 && strcmp(fromEntryRef.name, fBaseAncestor->Name()) == 0; 1296 bool toIsBase = toAncestor == fBaseAncestor->Parent() 1297 && strcmp(toEntryRef.name, fBaseAncestor->Name()) == 0; 1298 if (fromIsBase || toIsBase) { 1299 // This might be a duplicate notification. Check whether our model 1300 // already reflects the change. Otherwise stop/start watching the base 1301 // ancestor as required. 1302 bool notifyFilesRecursively = _WatchFilesOnly() && isDirectory; 1303 if (fromIsBase) { 1304 if (!fBaseAncestor->Exists()) 1305 return; 1306 _StopWatchingAncestors(fBaseAncestor, notifyFilesRecursively); 1307 } else { 1308 if (fBaseAncestor->Exists()) { 1309 if (fBaseAncestor->NodeRef() == nodeRef 1310 && isDirectory == fBaseAncestor->IsDirectory()) { 1311 return; 1312 } 1313 1314 // We're out of sync with reality. 1315 _StopWatchingAncestors(fBaseAncestor, true); 1316 _StartWatchingAncestors(fBaseAncestor, true); 1317 return; 1318 } 1319 1320 _StartWatchingAncestors(fBaseAncestor, notifyFilesRecursively); 1321 } 1322 1323 if (!notifyFilesRecursively) { 1324 _NotifyEntryMoved(fromEntryRef, toEntryRef, nodeRef, 1325 fromIsBase ? fPath.String() : NULL, 1326 toIsBase ? fPath.String() : NULL, 1327 isDirectory, toIsBase, fromIsBase); 1328 } 1329 return; 1330 } 1331 1332 _EntryRemoved(fromEntryRef, nodeRef, false, true, NULL); 1333 _EntryCreated(toEntryRef, nodeRef, isDirectory, false, true, NULL); 1334 } 1335 1336 1337 void 1338 PathHandler::_NodeChanged(BMessage* message) 1339 { 1340 node_ref nodeRef; 1341 1342 if (message->FindInt32("device", &nodeRef.device) != B_OK 1343 || message->FindInt64("node", &nodeRef.node) != B_OK) { 1344 return; 1345 } 1346 1347 TRACE("%p->PathHandler::_NodeChanged(): node: %" B_PRIdDEV ":%" B_PRIdINO 1348 ", %s%s\n", this, nodeRef.device, nodeRef.node, 1349 message->GetInt32("opcode", B_STAT_CHANGED) == B_ATTR_CHANGED 1350 ? "attribute: " : "stat", 1351 message->GetInt32("opcode", B_STAT_CHANGED) == B_ATTR_CHANGED 1352 ? message->GetString("attr", "") : ""); 1353 1354 bool isDirectory = false; 1355 BString path; 1356 if (Ancestor* ancestor = _GetAncestor(nodeRef)) { 1357 if (ancestor != fBaseAncestor) 1358 return; 1359 isDirectory = ancestor->IsDirectory(); 1360 path = fPath; 1361 } else if (Node* node = _GetNode(nodeRef)) { 1362 isDirectory = node->IsDirectory(); 1363 path = _NodePath(node); 1364 } else 1365 return; 1366 1367 if (isDirectory ? _WatchFilesOnly() : _WatchDirectoriesOnly()) 1368 return; 1369 1370 _NotifyTarget(*message, path); 1371 } 1372 1373 1374 bool 1375 PathHandler::_EntryCreated(const NotOwningEntryRef& entryRef, 1376 const node_ref& nodeRef, bool isDirectory, bool dryRun, bool notify, 1377 Entry** _entry) 1378 { 1379 if (_entry != NULL) 1380 *_entry = NULL; 1381 1382 Ancestor* ancestor = _GetAncestor(nodeRef); 1383 if (ancestor != NULL) { 1384 if (isDirectory == ancestor->IsDirectory() 1385 && entryRef == ancestor->EntryRef()) { 1386 // just a duplicate notification 1387 TRACE(" -> we already know the ancestor\n"); 1388 return true; 1389 } 1390 1391 struct stat ancestorStat; 1392 if (BEntry(&ancestor->EntryRef()).GetStat(&ancestorStat) == B_OK 1393 && node_ref(ancestorStat.st_dev, ancestorStat.st_ino) 1394 == ancestor->NodeRef() 1395 && S_ISDIR(ancestorStat.st_mode) == ancestor->IsDirectory()) { 1396 // Our information for the ancestor is up-to-date, so ignore the 1397 // notification. 1398 TRACE(" -> we know a different ancestor, but our info is " 1399 "up-to-date\n"); 1400 return true; 1401 } 1402 1403 // We're out of sync with reality. 1404 TRACE(" -> ancestor mismatch -> resyncing\n"); 1405 if (!dryRun) { 1406 _StopWatchingAncestors(ancestor, true); 1407 _StartWatchingAncestors(ancestor, true); 1408 } 1409 return false; 1410 } 1411 1412 ancestor = _GetAncestor(entryRef.DirectoryNodeRef()); 1413 if (ancestor != NULL) { 1414 if (ancestor != fBaseAncestor) { 1415 // The directory is a true ancestor -- the notification is only of 1416 // interest, if the entry matches the child ancestor. 1417 Ancestor* childAncestor = ancestor->Child(); 1418 if (strcmp(entryRef.name, childAncestor->Name()) != 0) { 1419 TRACE(" -> not an ancestor entry we're interested in " 1420 "(\"%s\")\n", childAncestor->Name()); 1421 return true; 1422 } 1423 1424 if (!dryRun) { 1425 if (childAncestor->Exists()) { 1426 TRACE(" ancestor entry mismatch -> resyncing\n"); 1427 // We're out of sync with reality -- the new entry refers to 1428 // a different node. 1429 _StopWatchingAncestors(childAncestor, true); 1430 } 1431 1432 TRACE(" -> starting to watch newly appeared ancestor\n"); 1433 _StartWatchingAncestors(childAncestor, true); 1434 } 1435 return false; 1436 } 1437 1438 // The directory is our path. If watching recursively, just fall 1439 // through. Otherwise, we want to pass on the notification, if directory 1440 // watching is enabled. 1441 if (!_WatchRecursively()) { 1442 if ((fFlags & B_WATCH_DIRECTORY) != 0) { 1443 _NotifyEntryCreatedOrRemoved(entryRef, nodeRef, 1444 make_path(fPath, entryRef.name), isDirectory, 1445 B_ENTRY_CREATED); 1446 } 1447 return true; 1448 } 1449 } 1450 1451 if (!_WatchRecursively()) { 1452 // That shouldn't happen, since we only watch the ancestors in this 1453 // case. 1454 return true; 1455 } 1456 1457 Node* directoryNode = _GetNode(entryRef.DirectoryNodeRef()); 1458 if (directoryNode == NULL) 1459 return true; 1460 1461 Directory* directory = directoryNode->ToDirectory(); 1462 if (directory == NULL) { 1463 // We're out of sync with reality. 1464 if (!dryRun) { 1465 if (Entry* nodeEntry = directory->FirstNodeEntry()) { 1466 // remove the entry that is in the way and re-add the proper 1467 // entry 1468 NotOwningEntryRef directoryEntryRef = nodeEntry->EntryRef(); 1469 BString directoryName = nodeEntry->Name(); 1470 _DeleteEntry(nodeEntry, true); 1471 _EntryCreated(directoryEntryRef, entryRef.DirectoryNodeRef(), 1472 true, false, notify, NULL); 1473 } else { 1474 // It's either the base node or something's severely fishy. 1475 // Resync the whole path. 1476 _StopWatchingAncestors(fBaseAncestor, true); 1477 _StartWatchingAncestors(fBaseAncestor, true); 1478 } 1479 } 1480 1481 return false; 1482 } 1483 1484 // Check, if there's a colliding entry. 1485 if (Entry* nodeEntry = directory->FindEntry(entryRef.name)) { 1486 Node* entryNode = nodeEntry->Node(); 1487 if (entryNode != NULL && entryNode->NodeRef() == nodeRef) 1488 return true; 1489 1490 // We're out of sync with reality -- the new entry refers to a different 1491 // node. 1492 _DeleteEntry(nodeEntry, true); 1493 } 1494 1495 if (dryRun) 1496 return true; 1497 1498 _AddEntryIfNeeded(directory, entryRef.name, nodeRef, isDirectory, notify, 1499 _entry); 1500 return true; 1501 } 1502 1503 1504 bool 1505 PathHandler::_EntryRemoved(const NotOwningEntryRef& entryRef, 1506 const node_ref& nodeRef, bool dryRun, bool notify, Entry** _keepEntry) 1507 { 1508 if (_keepEntry != NULL) 1509 *_keepEntry = NULL; 1510 1511 Ancestor* ancestor = _GetAncestor(nodeRef); 1512 if (ancestor != NULL) { 1513 // The node is an ancestor. If this is a true match, stop watching the 1514 // ancestor. 1515 if (!ancestor->Exists()) 1516 return true; 1517 1518 if (entryRef != ancestor->EntryRef()) { 1519 // We might be out of sync with reality -- the new entry refers to a 1520 // different node. 1521 struct stat ancestorStat; 1522 if (BEntry(&ancestor->EntryRef()).GetStat(&ancestorStat) != B_OK) { 1523 if (!dryRun) 1524 _StopWatchingAncestors(ancestor, true); 1525 return false; 1526 } 1527 1528 if (node_ref(ancestorStat.st_dev, ancestorStat.st_ino) 1529 != ancestor->NodeRef() 1530 || S_ISDIR(ancestorStat.st_mode) != ancestor->IsDirectory()) { 1531 if (!dryRun) { 1532 _StopWatchingAncestors(ancestor, true); 1533 _StartWatchingAncestors(ancestor, true); 1534 } 1535 return false; 1536 } 1537 return true; 1538 } 1539 1540 if (!dryRun) 1541 _StopWatchingAncestors(ancestor, true); 1542 return false; 1543 } 1544 1545 ancestor = _GetAncestor(entryRef.DirectoryNodeRef()); 1546 if (ancestor != NULL) { 1547 if (ancestor != fBaseAncestor) { 1548 // The directory is a true ancestor -- the notification cannot be 1549 // of interest, since the node didn't match a known ancestor. 1550 return true; 1551 } 1552 1553 // The directory is our path. If watching recursively, just fall 1554 // through. Otherwise, we want to pass on the notification, if directory 1555 // watching is enabled. 1556 if (!_WatchRecursively()) { 1557 if (notify && (fFlags & B_WATCH_DIRECTORY) != 0) { 1558 _NotifyEntryCreatedOrRemoved(entryRef, nodeRef, 1559 make_path(fPath, entryRef.name), false, B_ENTRY_REMOVED); 1560 // We don't know whether this was a directory, but it 1561 // doesn't matter in this case. 1562 } 1563 return true; 1564 } 1565 } 1566 1567 if (!_WatchRecursively()) { 1568 // That shouldn't happen, since we only watch the ancestors in this 1569 // case. 1570 return true; 1571 } 1572 1573 Node* directoryNode = _GetNode(entryRef.DirectoryNodeRef()); 1574 if (directoryNode == NULL) { 1575 // We shouldn't get a notification, if we don't known the directory. 1576 return true; 1577 } 1578 1579 Directory* directory = directoryNode->ToDirectory(); 1580 if (directory == NULL) { 1581 // We might be out of sync with reality or the notification is just 1582 // late. The former case is extremely unlikely (we are watching the node 1583 // and its parent directory after all) and rather hard to verify. 1584 return true; 1585 } 1586 1587 Entry* nodeEntry = directory->FindEntry(entryRef.name); 1588 if (nodeEntry == NULL) { 1589 // might be a non-directory node while we're in directories-only mode 1590 return true; 1591 } 1592 1593 if (!dryRun) { 1594 if (_keepEntry != NULL) 1595 *_keepEntry = nodeEntry; 1596 else 1597 _DeleteEntry(nodeEntry, notify); 1598 } 1599 return true; 1600 } 1601 1602 1603 bool 1604 PathHandler::_CheckDuplicateEntryNotification(int32 opcode, 1605 const entry_ref& toEntryRef, const node_ref& nodeRef, 1606 const entry_ref* fromEntryRef) 1607 { 1608 if (opcode == fDuplicateEntryNotificationOpcode 1609 && nodeRef == fDuplicateEntryNotificationNodeRef 1610 && toEntryRef == fDuplicateEntryNotificationToEntryRef 1611 && (fromEntryRef == NULL 1612 || *fromEntryRef == fDuplicateEntryNotificationFromEntryRef)) { 1613 return true; 1614 } 1615 1616 fDuplicateEntryNotificationOpcode = opcode; 1617 fDuplicateEntryNotificationNodeRef = nodeRef; 1618 fDuplicateEntryNotificationToEntryRef = toEntryRef; 1619 fDuplicateEntryNotificationFromEntryRef = fromEntryRef != NULL 1620 ? *fromEntryRef : entry_ref(); 1621 return false; 1622 } 1623 1624 1625 void 1626 PathHandler::_UnsetDuplicateEntryNotification() 1627 { 1628 fDuplicateEntryNotificationOpcode = B_STAT_CHANGED; 1629 fDuplicateEntryNotificationNodeRef = node_ref(); 1630 fDuplicateEntryNotificationFromEntryRef = entry_ref(); 1631 fDuplicateEntryNotificationToEntryRef = entry_ref(); 1632 } 1633 1634 1635 Ancestor* 1636 PathHandler::_GetAncestor(const node_ref& nodeRef) const 1637 { 1638 return fAncestors.Lookup(nodeRef); 1639 } 1640 1641 1642 status_t 1643 PathHandler::_AddNode(const node_ref& nodeRef, bool isDirectory, bool notify, 1644 Entry* entry, Node** _node) 1645 { 1646 TRACE("%p->PathHandler::_AddNode(%" B_PRIdDEV ":%" B_PRIdINO 1647 ", isDirectory: %d, notify: %d)\n", this, nodeRef.device, nodeRef.node, 1648 isDirectory, notify); 1649 1650 // If hard links are supported, we may already know the node. 1651 Node* node = _GetNode(nodeRef); 1652 if (node != NULL) { 1653 if (entry != NULL) { 1654 entry->SetNode(node); 1655 node->AddNodeEntry(entry); 1656 } 1657 1658 if (_node != NULL) 1659 *_node = node; 1660 return B_OK; 1661 } 1662 1663 // create the node 1664 Directory* directoryNode = NULL; 1665 if (isDirectory) 1666 node = directoryNode = Directory::Create(nodeRef); 1667 else 1668 node = new(std::nothrow) Node(nodeRef); 1669 1670 if (node == NULL) 1671 return B_NO_MEMORY; 1672 1673 ObjectDeleter<Node> nodeDeleter(node); 1674 1675 // start watching (don't do that for the base node, since we watch it 1676 // already via fBaseAncestor) 1677 if (nodeRef != fBaseAncestor->NodeRef()) { 1678 uint32 flags = (fFlags & WATCH_NODE_FLAG_MASK) | B_WATCH_DIRECTORY; 1679 status_t error = sWatchingInterface->WatchNode(&nodeRef, flags, this); 1680 if (error != B_OK) 1681 return error; 1682 } 1683 1684 fNodes.Insert(nodeDeleter.Detach()); 1685 1686 if (entry != NULL) { 1687 entry->SetNode(node); 1688 node->AddNodeEntry(entry); 1689 } 1690 1691 if (_node != NULL) 1692 *_node = node; 1693 1694 if (!isDirectory) 1695 return B_OK; 1696 1697 // recursively add the directory's descendents 1698 BDirectory directory; 1699 if (directory.SetTo(&nodeRef) != B_OK) { 1700 if (_node != NULL) 1701 *_node = node; 1702 return B_OK; 1703 } 1704 1705 entry_ref entryRef; 1706 while (directory.GetNextRef(&entryRef) == B_OK) { 1707 struct stat st; 1708 if (BEntry(&entryRef).GetStat(&st) != B_OK) 1709 continue; 1710 1711 bool isDirectory = S_ISDIR(st.st_mode); 1712 status_t error = _AddEntryIfNeeded(directoryNode, entryRef.name, 1713 node_ref(st.st_dev, st.st_ino), isDirectory, notify); 1714 if (error != B_OK) { 1715 TRACE("%p->PathHandler::_AddNode(%" B_PRIdDEV ":%" B_PRIdINO 1716 ", isDirectory: %d, notify: %d): failed to add directory " 1717 "entry: \"%s\"\n", this, nodeRef.device, nodeRef.node, 1718 isDirectory, notify, entryRef.name); 1719 continue; 1720 } 1721 } 1722 1723 return B_OK; 1724 } 1725 1726 1727 void 1728 PathHandler::_DeleteNode(Node* node, bool notify) 1729 { 1730 if (Directory* directory = node->ToDirectory()) { 1731 Entry* entry = directory->RemoveAllEntries(); 1732 while (entry != NULL) { 1733 Entry* nextEntry = entry->HashNext(); 1734 _DeleteEntryAlreadyRemovedFromParent(entry, notify); 1735 entry = nextEntry; 1736 } 1737 } 1738 1739 if (node->NodeRef() != fBaseAncestor->NodeRef()) 1740 sWatchingInterface->WatchNode(&node->NodeRef(), B_STOP_WATCHING, this); 1741 1742 fNodes.Remove(node); 1743 delete node; 1744 } 1745 1746 1747 Node* 1748 PathHandler::_GetNode(const node_ref& nodeRef) const 1749 { 1750 return fNodes.Lookup(nodeRef); 1751 } 1752 1753 1754 status_t 1755 PathHandler::_AddEntryIfNeeded(Directory* directory, const char* name, 1756 const node_ref& nodeRef, bool isDirectory, bool notify, 1757 Entry** _entry) 1758 { 1759 TRACE("%p->PathHandler::_AddEntryIfNeeded(%" B_PRIdDEV ":%" B_PRIdINO 1760 ":\"%s\", %" B_PRIdDEV ":%" B_PRIdINO 1761 ", isDirectory: %d, notify: %d)\n", this, directory->NodeRef().device, 1762 directory->NodeRef().node, name, nodeRef.device, nodeRef.node, 1763 isDirectory, notify); 1764 1765 if (!isDirectory && _WatchDirectoriesOnly()) { 1766 if (_entry != NULL) 1767 *_entry = NULL; 1768 return B_OK; 1769 } 1770 1771 Entry* entry = directory->CreateEntry(name, NULL); 1772 if (entry == NULL) 1773 return B_NO_MEMORY; 1774 1775 status_t error = _AddNode(nodeRef, isDirectory, notify && _WatchFilesOnly(), 1776 entry); 1777 if (error != B_OK) { 1778 directory->RemoveEntry(entry); 1779 delete entry; 1780 return error; 1781 } 1782 1783 if (notify) 1784 _NotifyEntryCreatedOrRemoved(entry, B_ENTRY_CREATED); 1785 1786 if (_entry != NULL) 1787 *_entry = entry; 1788 return B_OK; 1789 } 1790 1791 1792 void 1793 PathHandler::_DeleteEntry(Entry* entry, bool notify) 1794 { 1795 entry->Parent()->RemoveEntry(entry); 1796 _DeleteEntryAlreadyRemovedFromParent(entry, notify); 1797 } 1798 1799 1800 void 1801 PathHandler::_DeleteEntryAlreadyRemovedFromParent(Entry* entry, bool notify) 1802 { 1803 if (notify) 1804 _NotifyEntryCreatedOrRemoved(entry, B_ENTRY_REMOVED); 1805 1806 Node* node = entry->Node(); 1807 if (node->IsOnlyNodeEntry(entry)) 1808 _DeleteNode(node, notify && _WatchFilesOnly()); 1809 1810 delete entry; 1811 } 1812 1813 1814 void 1815 PathHandler::_NotifyFilesCreatedOrRemoved(Entry* entry, int32 opcode) const 1816 { 1817 Directory* directory = entry->Node()->ToDirectory(); 1818 if (directory == NULL) { 1819 _NotifyEntryCreatedOrRemoved(entry, opcode); 1820 return; 1821 } 1822 1823 for (EntryMap::Iterator it = directory->GetEntryIterator(); it.HasNext();) 1824 _NotifyFilesCreatedOrRemoved(it.Next(), opcode); 1825 } 1826 1827 1828 void 1829 PathHandler::_NotifyEntryCreatedOrRemoved(Entry* entry, int32 opcode) const 1830 { 1831 Node* node = entry->Node(); 1832 _NotifyEntryCreatedOrRemoved( 1833 NotOwningEntryRef(entry->Parent()->NodeRef(), entry->Name()), 1834 node->NodeRef(), _EntryPath(entry), node->IsDirectory(), opcode); 1835 } 1836 1837 1838 void 1839 PathHandler::_NotifyEntryCreatedOrRemoved(const entry_ref& entryRef, 1840 const node_ref& nodeRef, const char* path, bool isDirectory, int32 opcode) 1841 const 1842 { 1843 if (isDirectory ? _WatchFilesOnly() : _WatchDirectoriesOnly()) 1844 return; 1845 1846 TRACE("%p->PathHandler::_NotifyEntryCreatedOrRemoved(): entry %s: %" 1847 B_PRIdDEV ":%" B_PRIdINO ":\"%s\", node: %" B_PRIdDEV ":%" B_PRIdINO 1848 "\n", this, opcode == B_ENTRY_CREATED ? "created" : "removed", 1849 entryRef.device, entryRef.directory, entryRef.name, nodeRef.device, 1850 nodeRef.node); 1851 1852 BMessage message(B_PATH_MONITOR); 1853 message.AddInt32("opcode", opcode); 1854 message.AddInt32("device", entryRef.device); 1855 message.AddInt64("directory", entryRef.directory); 1856 message.AddInt32("node device", nodeRef.device); 1857 // This field is not in a usual node monitoring message, since the node 1858 // the created/removed entry refers to always belongs to the same FS as 1859 // the directory, as another FS cannot yet/no longer be mounted there. 1860 // In our case, however, this can very well be the case, e.g. when the 1861 // the notification is triggered in response to a directory tree having 1862 // been moved into/out of our path. 1863 message.AddInt64("node", nodeRef.node); 1864 message.AddString("name", entryRef.name); 1865 1866 _NotifyTarget(message, path); 1867 } 1868 1869 1870 void 1871 PathHandler::_NotifyEntryMoved(const entry_ref& fromEntryRef, 1872 const entry_ref& toEntryRef, const node_ref& nodeRef, const char* fromPath, 1873 const char* path, bool isDirectory, bool wasAdded, bool wasRemoved) const 1874 { 1875 if ((isDirectory && _WatchFilesOnly()) 1876 || (!isDirectory && _WatchDirectoriesOnly())) { 1877 return; 1878 } 1879 1880 TRACE("%p->PathHandler::_NotifyEntryMoved(): entry: %" B_PRIdDEV ":%" 1881 B_PRIdINO ":\"%s\" -> %" B_PRIdDEV ":%" B_PRIdINO ":\"%s\", node: %" 1882 B_PRIdDEV ":%" B_PRIdINO "\n", this, fromEntryRef.device, 1883 fromEntryRef.directory, fromEntryRef.name, toEntryRef.device, 1884 toEntryRef.directory, toEntryRef.name, nodeRef.device, nodeRef.node); 1885 1886 BMessage message(B_PATH_MONITOR); 1887 message.AddInt32("opcode", B_ENTRY_MOVED); 1888 message.AddInt32("device", fromEntryRef.device); 1889 message.AddInt64("from directory", fromEntryRef.directory); 1890 message.AddInt64("to directory", toEntryRef.directory); 1891 message.AddInt32("node device", nodeRef.device); 1892 message.AddInt64("node", nodeRef.node); 1893 message.AddString("from name", fromEntryRef.name); 1894 message.AddString("name", toEntryRef.name); 1895 1896 if (wasAdded) 1897 message.AddBool("added", true); 1898 if (wasRemoved) 1899 message.AddBool("removed", true); 1900 1901 if (fromPath != NULL && fromPath[0] != '\0') 1902 message.AddString("from path", fromPath); 1903 1904 _NotifyTarget(message, path); 1905 } 1906 1907 1908 void 1909 PathHandler::_NotifyTarget(BMessage& message, const char* path) const 1910 { 1911 message.what = B_PATH_MONITOR; 1912 if (path != NULL && path[0] != '\0') 1913 message.AddString("path", path); 1914 message.AddString("watched_path", fPath.String()); 1915 fTarget.SendMessage(&message); 1916 } 1917 1918 1919 1920 BString 1921 PathHandler::_NodePath(const Node* node) const 1922 { 1923 if (Entry* entry = node->FirstNodeEntry()) 1924 return _EntryPath(entry); 1925 return node == fBaseNode ? fPath : BString(); 1926 } 1927 1928 1929 BString 1930 PathHandler::_EntryPath(const Entry* entry) const 1931 { 1932 return make_path(_NodePath(entry->Parent()), entry->Name()); 1933 } 1934 1935 1936 bool 1937 PathHandler::_WatchRecursively() const 1938 { 1939 return (fFlags & B_WATCH_RECURSIVELY) != 0; 1940 } 1941 1942 1943 bool 1944 PathHandler::_WatchFilesOnly() const 1945 { 1946 return (fFlags & B_WATCH_FILES_ONLY) != 0; 1947 } 1948 1949 1950 bool 1951 PathHandler::_WatchDirectoriesOnly() const 1952 { 1953 return (fFlags & B_WATCH_DIRECTORIES_ONLY) != 0; 1954 } 1955 1956 1957 } // namespace 1958 1959 1960 // #pragma mark - BPathMonitor 1961 1962 1963 namespace BPrivate { 1964 1965 1966 BPathMonitor::BPathMonitor() 1967 { 1968 } 1969 1970 1971 BPathMonitor::~BPathMonitor() 1972 { 1973 } 1974 1975 1976 /*static*/ status_t 1977 BPathMonitor::StartWatching(const char* path, uint32 flags, 1978 const BMessenger& target) 1979 { 1980 TRACE("BPathMonitor::StartWatching(%s, %" B_PRIx32 ")\n", path, flags); 1981 1982 if (path == NULL || path[0] == '\0') 1983 return B_BAD_VALUE; 1984 1985 // B_WATCH_FILES_ONLY and B_WATCH_DIRECTORIES_ONLY are mutual exclusive 1986 if ((flags & B_WATCH_FILES_ONLY) != 0 1987 && (flags & B_WATCH_DIRECTORIES_ONLY) != 0) { 1988 return B_BAD_VALUE; 1989 } 1990 1991 status_t status = _InitIfNeeded(); 1992 if (status != B_OK) 1993 return status; 1994 1995 BAutolock _(sLooper); 1996 1997 Watcher* watcher = sWatchers->Lookup(target); 1998 bool newWatcher = false; 1999 if (watcher != NULL) { 2000 // If there's already a handler for the path, we'll replace it, but 2001 // add its flags. 2002 if (PathHandler* handler = watcher->Lookup(path)) { 2003 // keep old flags save for conflicting mutually exclusive ones 2004 uint32 oldFlags = handler->Flags(); 2005 const uint32 kMutuallyExclusiveFlags 2006 = B_WATCH_FILES_ONLY | B_WATCH_DIRECTORIES_ONLY; 2007 if ((flags & kMutuallyExclusiveFlags) != 0) 2008 oldFlags &= ~(uint32)kMutuallyExclusiveFlags; 2009 flags |= oldFlags; 2010 2011 watcher->Remove(handler); 2012 handler->Quit(); 2013 } 2014 } else { 2015 watcher = Watcher::Create(target); 2016 if (watcher == NULL) 2017 return B_NO_MEMORY; 2018 sWatchers->Insert(watcher); 2019 newWatcher = true; 2020 } 2021 2022 PathHandler* handler = new (std::nothrow) PathHandler(path, flags, target, 2023 sLooper); 2024 status = handler != NULL ? handler->InitCheck() : B_NO_MEMORY; 2025 2026 if (status != B_OK) { 2027 if (handler != NULL) 2028 handler->Quit(); 2029 2030 if (newWatcher) { 2031 sWatchers->Remove(watcher); 2032 delete watcher; 2033 } 2034 return status; 2035 } 2036 2037 watcher->Insert(handler); 2038 return B_OK; 2039 } 2040 2041 2042 /*static*/ status_t 2043 BPathMonitor::StopWatching(const char* path, const BMessenger& target) 2044 { 2045 if (sLooper == NULL) 2046 return B_BAD_VALUE; 2047 2048 TRACE("BPathMonitor::StopWatching(%s)\n", path); 2049 2050 BAutolock _(sLooper); 2051 2052 Watcher* watcher = sWatchers->Lookup(target); 2053 if (watcher == NULL) 2054 return B_BAD_VALUE; 2055 2056 PathHandler* handler = watcher->Lookup(path); 2057 if (handler == NULL) 2058 return B_BAD_VALUE; 2059 2060 watcher->Remove(handler); 2061 handler->Quit(); 2062 2063 if (watcher->IsEmpty()) { 2064 sWatchers->Remove(watcher); 2065 delete watcher; 2066 } 2067 2068 return B_OK; 2069 } 2070 2071 2072 /*static*/ status_t 2073 BPathMonitor::StopWatching(const BMessenger& target) 2074 { 2075 if (sLooper == NULL) 2076 return B_BAD_VALUE; 2077 2078 BAutolock _(sLooper); 2079 2080 Watcher* watcher = sWatchers->Lookup(target); 2081 if (watcher == NULL) 2082 return B_BAD_VALUE; 2083 2084 // delete handlers 2085 PathHandler* handler = watcher->Clear(true); 2086 while (handler != NULL) { 2087 PathHandler* nextHandler = handler->HashNext(); 2088 handler->Quit(); 2089 handler = nextHandler; 2090 } 2091 2092 sWatchers->Remove(watcher); 2093 delete watcher; 2094 2095 return B_OK; 2096 } 2097 2098 2099 /*static*/ void 2100 BPathMonitor::SetWatchingInterface(BWatchingInterface* watchingInterface) 2101 { 2102 sWatchingInterface = watchingInterface != NULL 2103 ? watchingInterface : sDefaultWatchingInterface; 2104 } 2105 2106 2107 /*static*/ status_t 2108 BPathMonitor::_InitIfNeeded() 2109 { 2110 pthread_once(&sInitOnce, &BPathMonitor::_Init); 2111 return sLooper != NULL ? B_OK : B_NO_MEMORY; 2112 } 2113 2114 2115 /*static*/ void 2116 BPathMonitor::_Init() 2117 { 2118 sDefaultWatchingInterface = new(std::nothrow) BWatchingInterface; 2119 if (sDefaultWatchingInterface == NULL) 2120 return; 2121 2122 sWatchers = new(std::nothrow) WatcherMap; 2123 if (sWatchers == NULL || sWatchers->Init() != B_OK) 2124 return; 2125 2126 if (sWatchingInterface == NULL) 2127 SetWatchingInterface(sDefaultWatchingInterface); 2128 2129 BLooper* looper = new (std::nothrow) BLooper("PathMonitor looper"); 2130 TRACE("Start PathMonitor looper\n"); 2131 if (looper == NULL) 2132 return; 2133 thread_id thread = looper->Run(); 2134 if (thread < 0) { 2135 delete looper; 2136 return; 2137 } 2138 2139 sLooper = looper; 2140 } 2141 2142 2143 // #pragma mark - BWatchingInterface 2144 2145 2146 BPathMonitor::BWatchingInterface::BWatchingInterface() 2147 { 2148 } 2149 2150 2151 BPathMonitor::BWatchingInterface::~BWatchingInterface() 2152 { 2153 } 2154 2155 2156 status_t 2157 BPathMonitor::BWatchingInterface::WatchNode(const node_ref* node, uint32 flags, 2158 const BMessenger& target) 2159 { 2160 return watch_node(node, flags, target); 2161 } 2162 2163 2164 status_t 2165 BPathMonitor::BWatchingInterface::WatchNode(const node_ref* node, uint32 flags, 2166 const BHandler* handler, const BLooper* looper) 2167 { 2168 return watch_node(node, flags, handler, looper); 2169 } 2170 2171 2172 status_t 2173 BPathMonitor::BWatchingInterface::StopWatching(const BMessenger& target) 2174 { 2175 return stop_watching(target); 2176 } 2177 2178 2179 status_t 2180 BPathMonitor::BWatchingInterface::StopWatching(const BHandler* handler, 2181 const BLooper* looper) 2182 { 2183 return stop_watching(handler, looper); 2184 } 2185 2186 2187 } // namespace BPrivate 2188