1 /* 2 * Copyright 2003-2007, Axel Dörfler, axeld@pinc-software.de. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 7 #include <fs/node_monitor.h> 8 9 #include <stddef.h> 10 #include <stdlib.h> 11 12 #include <AppDefs.h> 13 #include <NodeMonitor.h> 14 15 #include <fd.h> 16 #include <khash.h> 17 #include <lock.h> 18 #include <messaging.h> 19 #include <Notifications.h> 20 #include <vfs.h> 21 #include <util/AutoLock.h> 22 #include <util/DoublyLinkedList.h> 23 #include <util/KMessage.h> 24 #include <util/list.h> 25 26 27 //#define TRACE_MONITOR 28 #ifdef TRACE_MONITOR 29 # define TRACE(x) dprintf x 30 #else 31 # define TRACE(x) ; 32 #endif 33 34 35 // ToDo: add more fine grained locking - maybe using a ref_count in the 36 // node_monitor structure? 37 // ToDo: return another error code than B_NO_MEMORY if the team's maximum is hit 38 39 40 typedef struct monitor_listener monitor_listener; 41 typedef struct node_monitor node_monitor; 42 43 struct monitor_listener { 44 list_link context_link; 45 DoublyLinkedListLink<monitor_listener> monitor_link; 46 NotificationListener *listener; 47 uint32 flags; 48 node_monitor *monitor; 49 }; 50 51 typedef DoublyLinkedList<monitor_listener, DoublyLinkedListMemberGetLink< 52 monitor_listener, &monitor_listener::monitor_link> > MonitorListenerList; 53 54 struct node_monitor { 55 HashTableLink<node_monitor> link; 56 dev_t device; 57 ino_t node; 58 MonitorListenerList listeners; 59 }; 60 61 struct interested_monitor_listener_list { 62 MonitorListenerList::Iterator iterator; 63 uint32 flags; 64 }; 65 66 static UserMessagingMessageSender sNodeMonitorSender; 67 68 class UserNodeListener : public UserMessagingListener { 69 public: 70 UserNodeListener(port_id port, int32 token) 71 : UserMessagingListener(sNodeMonitorSender, port, token) 72 { 73 } 74 75 bool operator==(const NotificationListener& _other) const 76 { 77 const UserNodeListener* other 78 = dynamic_cast<const UserNodeListener*>(&_other); 79 return other != NULL && other->Port() == Port() 80 && other->Token() == Token(); 81 } 82 }; 83 84 class NodeMonitorService : public NotificationService { 85 public: 86 NodeMonitorService(); 87 virtual ~NodeMonitorService(); 88 89 status_t InitCheck(); 90 91 status_t NotifyEntryCreatedOrRemoved(int32 opcode, dev_t device, 92 ino_t directory, const char *name, ino_t node); 93 status_t NotifyEntryMoved(dev_t device, ino_t fromDirectory, 94 const char *fromName, ino_t toDirectory, const char *toName, 95 ino_t node); 96 status_t NotifyStatChanged(dev_t device, ino_t node, uint32 statFields); 97 status_t NotifyAttributeChanged(dev_t device, ino_t node, 98 const char *attribute, int32 cause); 99 status_t NotifyUnmount(dev_t device); 100 status_t NotifyMount(dev_t device, dev_t parentDevice, 101 ino_t parentDirectory); 102 103 status_t RemoveListeners(io_context *context); 104 105 status_t AddListener(const KMessage *eventSpecifier, 106 NotificationListener &listener); 107 status_t UpdateListener(const KMessage *eventSpecifier, 108 NotificationListener &listener); 109 status_t RemoveListener(const KMessage *eventSpecifier, 110 NotificationListener &listener); 111 112 status_t RemoveListener(io_context *context, dev_t device, ino_t node, 113 NotificationListener ¬ificationListener); 114 115 status_t RemoveUserListeners(struct io_context *context, 116 port_id port, uint32 token); 117 status_t UpdateUserListener(io_context *context, dev_t device, 118 ino_t node, uint32 flags, UserNodeListener &userListener); 119 120 virtual const char* Name() { return "node monitor"; } 121 122 private: 123 void _RemoveMonitor(node_monitor *monitor); 124 void _RemoveListener(monitor_listener *listener); 125 node_monitor *_MonitorFor(dev_t device, ino_t node); 126 status_t _GetMonitor(io_context *context, dev_t device, ino_t node, 127 bool addIfNecessary, node_monitor **_monitor); 128 monitor_listener *_MonitorListenerFor(node_monitor* monitor, 129 NotificationListener& notificationListener); 130 status_t _AddMonitorListener(io_context *context, 131 node_monitor* monitor, uint32 flags, 132 NotificationListener& notificationListener); 133 status_t _AddListener(io_context *context, dev_t device, ino_t node, 134 uint32 flags, NotificationListener ¬ificationListener); 135 status_t _UpdateListener(io_context *context, dev_t device, ino_t node, 136 uint32 flags, bool addFlags, 137 NotificationListener ¬ificationListener); 138 void _GetInterestedMonitorListeners(dev_t device, ino_t node, 139 uint32 flags, interested_monitor_listener_list *interestedListeners, 140 int32 &interestedListenerCount); 141 status_t _SendNotificationMessage(KMessage &message, 142 interested_monitor_listener_list *interestedListeners, 143 int32 interestedListenerCount); 144 145 struct monitor_hash_key { 146 dev_t device; 147 ino_t node; 148 }; 149 150 struct HashDefinition { 151 typedef monitor_hash_key* KeyType; 152 typedef node_monitor ValueType; 153 154 size_t HashKey(monitor_hash_key* key) const 155 { return _Hash(key->device, key->node); } 156 size_t Hash(node_monitor *monitor) const 157 { return _Hash(monitor->device, monitor->node); } 158 159 bool Compare(monitor_hash_key* key, node_monitor *monitor) const 160 { 161 return key->device == monitor->device 162 && key->node == monitor->node; 163 } 164 165 HashTableLink<node_monitor>* GetLink( 166 node_monitor* monitor) const 167 { return &monitor->link; } 168 169 uint32 _Hash(dev_t device, ino_t node) const 170 { 171 return ((uint32)(node >> 32) + (uint32)node) ^ (uint32)device; 172 } 173 }; 174 175 typedef OpenHashTable<HashDefinition> MonitorHash; 176 MonitorHash fMonitors; 177 mutex fMutex; 178 }; 179 180 static NodeMonitorService sNodeMonitorService; 181 182 183 /*! \brief Notifies the listener of a live query that an entry has been added 184 to or removed from the query (for whatever reason). 185 \param opcode \c B_ENTRY_CREATED or \c B_ENTRY_REMOVED. 186 \param port The target port of the listener. 187 \param token The BHandler token of the listener. 188 \param device The ID of the mounted FS, the entry lives in. 189 \param directory The entry's parent directory ID. 190 \param name The entry's name. 191 \param node The ID of the node the entry refers to. 192 \return 193 - \c B_OK, if everything went fine, 194 - another error code otherwise. 195 */ 196 static status_t 197 notify_query_entry_created_or_removed(int32 opcode, port_id port, int32 token, 198 dev_t device, ino_t directory, const char *name, ino_t node) 199 { 200 if (!name) 201 return B_BAD_VALUE; 202 203 // construct the message 204 char messageBuffer[1024]; 205 KMessage message; 206 message.SetTo(messageBuffer, sizeof(messageBuffer), B_QUERY_UPDATE); 207 message.AddInt32("opcode", opcode); 208 message.AddInt32("device", device); 209 message.AddInt64("directory", directory); 210 message.AddInt64("node", node); 211 message.AddString("name", name); 212 213 // send the message 214 messaging_target target; 215 target.port = port; 216 target.token = token; 217 218 return send_message(&message, &target, 1); 219 } 220 221 222 // #pragma mark - NodeMonitorService 223 224 225 NodeMonitorService::NodeMonitorService() 226 { 227 mutex_init(&fMutex, "node monitor"); 228 } 229 230 231 NodeMonitorService::~NodeMonitorService() 232 { 233 } 234 235 236 status_t 237 NodeMonitorService::InitCheck() 238 { 239 return fMutex.sem >= B_OK ? B_OK : fMutex.sem; 240 } 241 242 243 /*! Removes the specified node_monitor from the hashtable 244 and free it. 245 Must be called with monitors lock hold. 246 */ 247 void 248 NodeMonitorService::_RemoveMonitor(node_monitor *monitor) 249 { 250 fMonitors.Remove(monitor); 251 delete monitor; 252 } 253 254 255 /*! Removes the specified monitor_listener from all lists 256 and free it. 257 Must be called with monitors lock hold. 258 */ 259 void 260 NodeMonitorService::_RemoveListener(monitor_listener *listener) 261 { 262 node_monitor *monitor = listener->monitor; 263 264 // remove it from the listener and I/O context lists 265 monitor->listeners.Remove(listener); 266 list_remove_link(listener); 267 268 delete listener; 269 270 if (monitor->listeners.IsEmpty()) 271 _RemoveMonitor(monitor); 272 } 273 274 275 /*! Returns the monitor that matches the specified device/node pair. 276 Must be called with monitors lock hold. 277 */ 278 node_monitor * 279 NodeMonitorService::_MonitorFor(dev_t device, ino_t node) 280 { 281 struct monitor_hash_key key; 282 key.device = device; 283 key.node = node; 284 285 return fMonitors.Lookup(&key); 286 } 287 288 289 /*! Returns the monitor that matches the specified device/node pair. 290 If the monitor does not exist yet, it will be created. 291 Must be called with monitors lock hold. 292 */ 293 status_t 294 NodeMonitorService::_GetMonitor(io_context *context, dev_t device, ino_t node, 295 bool addIfNecessary, node_monitor** _monitor) 296 { 297 node_monitor* monitor = _MonitorFor(device, node); 298 if (monitor != NULL) { 299 *_monitor = monitor; 300 return B_OK; 301 } 302 if (!addIfNecessary) 303 return B_BAD_VALUE; 304 305 // check if this team is allowed to have more listeners 306 if (context->num_monitors >= context->max_monitors) { 307 // the BeBook says to return B_NO_MEMORY in this case, but 308 // we should have another one. 309 return B_NO_MEMORY; 310 } 311 312 // create new monitor 313 monitor = new(std::nothrow) node_monitor; 314 if (monitor == NULL) 315 return B_NO_MEMORY; 316 317 // initialize monitor 318 monitor->device = device; 319 monitor->node = node; 320 321 if (fMonitors.Insert(monitor) < B_OK) { 322 delete monitor; 323 return B_NO_MEMORY; 324 } 325 326 *_monitor = monitor; 327 return B_OK; 328 } 329 330 331 /*! Returns the listener that matches the specified port/token pair. 332 Must be called with monitors lock hold. 333 */ 334 monitor_listener* 335 NodeMonitorService::_MonitorListenerFor(node_monitor* monitor, 336 NotificationListener& notificationListener) 337 { 338 MonitorListenerList::Iterator iterator 339 = monitor->listeners.GetIterator(); 340 341 while (monitor_listener* listener = iterator.Next()) { 342 // does this listener match? 343 if (*listener->listener == notificationListener) 344 return listener; 345 } 346 347 return NULL; 348 } 349 350 351 status_t 352 NodeMonitorService::_AddMonitorListener(io_context *context, 353 node_monitor* monitor, uint32 flags, 354 NotificationListener& notificationListener) 355 { 356 monitor_listener *listener = new(std::nothrow) monitor_listener; 357 if (listener == NULL) { 358 // no memory for the listener, so remove the monitor as well if needed 359 if (monitor->listeners.IsEmpty()) 360 _RemoveMonitor(monitor); 361 362 return B_NO_MEMORY; 363 } 364 365 // initialize listener, and add it to the lists 366 listener->listener = ¬ificationListener; 367 listener->flags = flags; 368 listener->monitor = monitor; 369 370 monitor->listeners.Add(listener); 371 list_add_link_to_head(&context->node_monitors, listener); 372 373 context->num_monitors++; 374 return B_OK; 375 } 376 377 378 status_t 379 NodeMonitorService::_AddListener(io_context *context, dev_t device, ino_t node, 380 uint32 flags, NotificationListener& notificationListener) 381 { 382 TRACE(("%s(dev = %ld, node = %Ld, flags = %ld, listener = %p\n", 383 __PRETTY_FUNCTION__, device, node, flags, ¬ificationListener)); 384 385 MutexLocker _(fMutex); 386 387 node_monitor *monitor; 388 status_t status = _GetMonitor(context, device, node, true, &monitor); 389 if (status < B_OK) 390 return status; 391 392 // add listener 393 394 return _AddMonitorListener(context, monitor, flags, notificationListener); 395 } 396 397 398 status_t 399 NodeMonitorService::_UpdateListener(io_context *context, dev_t device, 400 ino_t node, uint32 flags, bool addFlags, 401 NotificationListener& notificationListener) 402 { 403 TRACE(("%s(dev = %ld, node = %Ld, flags = %ld, listener = %p\n", 404 __PRETTY_FUNCTION__, device, node, flags, ¬ificationListener)); 405 406 MutexLocker _(fMutex); 407 408 node_monitor *monitor; 409 status_t status = _GetMonitor(context, device, node, false, &monitor); 410 if (status < B_OK) 411 return status; 412 413 MonitorListenerList::Iterator iterator = monitor->listeners.GetIterator(); 414 while (monitor_listener* listener = iterator.Next()) { 415 if (*listener->listener == notificationListener) { 416 if (addFlags) 417 listener->flags |= flags; 418 else 419 listener->flags = flags; 420 return B_OK; 421 } 422 } 423 424 return B_BAD_VALUE; 425 } 426 427 428 /*! \brief Given device and node ID and a node monitoring event mask, the 429 function checks whether there are listeners interested in any of 430 the events for that node and, if so, adds the respective listener 431 list to a supplied array of listener lists. 432 433 Note, that in general not all of the listeners in an appended list will be 434 interested in the events, but it is guaranteed that 435 interested_monitor_listener_list::first_listener is indeed 436 the first listener in the list, that is interested. 437 438 \param device The ID of the mounted FS, the node lives in. 439 \param node The ID of the node. 440 \param flags The mask specifying the events occurred for the given node 441 (a combination of \c B_WATCH_* constants). 442 \param interestedListeners An array of listener lists. If there are 443 interested listeners for the node, the list will be appended to 444 this array. 445 \param interestedListenerCount The number of elements in the 446 \a interestedListeners array. Will be incremented, if a list is 447 appended. 448 */ 449 void 450 NodeMonitorService::_GetInterestedMonitorListeners(dev_t device, ino_t node, 451 uint32 flags, interested_monitor_listener_list *interestedListeners, 452 int32 &interestedListenerCount) 453 { 454 // get the monitor for the node 455 node_monitor *monitor = _MonitorFor(device, node); 456 if (monitor == NULL) 457 return; 458 459 // iterate through the listeners until we find one with matching flags 460 MonitorListenerList::Iterator iterator = monitor->listeners.GetIterator(); 461 while (monitor_listener *listener = iterator.Next()) { 462 if (listener->flags & flags) { 463 interested_monitor_listener_list &list 464 = interestedListeners[interestedListenerCount++]; 465 list.iterator = iterator; 466 list.flags = flags; 467 return; 468 } 469 } 470 } 471 472 473 /*! \brief Sends a notifcation message to the given listeners. 474 \param message The message to be sent. 475 \param interestedListeners An array of listener lists. 476 \param interestedListenerCount The number of elements in the 477 \a interestedListeners array. 478 \return 479 - \c B_OK, if everything went fine, 480 - another error code otherwise. 481 */ 482 status_t 483 NodeMonitorService::_SendNotificationMessage(KMessage &message, 484 interested_monitor_listener_list *interestedListeners, 485 int32 interestedListenerCount) 486 { 487 // iterate through the lists 488 interested_monitor_listener_list *list = interestedListeners; 489 for (int32 i = 0; i < interestedListenerCount; i++, list++) { 490 // iterate through the listeners 491 MonitorListenerList::Iterator iterator = list->iterator; 492 do { 493 monitor_listener *listener = iterator.Current(); 494 if (listener->flags & list->flags) 495 listener->listener->EventOccured(*this, &message); 496 } while (iterator.Next() != NULL); 497 } 498 499 list = interestedListeners; 500 for (int32 i = 0; i < interestedListenerCount; i++, list++) { 501 // iterate through the listeners 502 do { 503 monitor_listener *listener = list->iterator.Current(); 504 if (listener->flags & list->flags) 505 listener->listener->AllListenersNotified(*this); 506 } while (list->iterator.Next() != NULL); 507 } 508 509 return B_OK; 510 } 511 512 513 /*! \brief Notifies all interested listeners that an entry has been created 514 or removed. 515 \param opcode \c B_ENTRY_CREATED or \c B_ENTRY_REMOVED. 516 \param device The ID of the mounted FS, the entry lives/lived in. 517 \param directory The entry's parent directory ID. 518 \param name The entry's name. 519 \param node The ID of the node the entry refers/referred to. 520 \return 521 - \c B_OK, if everything went fine, 522 - another error code otherwise. 523 */ 524 status_t 525 NodeMonitorService::NotifyEntryCreatedOrRemoved(int32 opcode, dev_t device, 526 ino_t directory, const char *name, ino_t node) 527 { 528 if (!name) 529 return B_BAD_VALUE; 530 531 MutexLocker locker(fMutex); 532 533 // get the lists of all interested listeners 534 interested_monitor_listener_list interestedListeners[3]; 535 int32 interestedListenerCount = 0; 536 // ... for the node 537 if (opcode != B_ENTRY_CREATED) { 538 _GetInterestedMonitorListeners(device, node, B_WATCH_NAME, 539 interestedListeners, interestedListenerCount); 540 } 541 // ... for the directory 542 _GetInterestedMonitorListeners(device, directory, B_WATCH_DIRECTORY, 543 interestedListeners, interestedListenerCount); 544 545 if (interestedListenerCount == 0) 546 return B_OK; 547 548 // there are interested listeners: construct the message and send it 549 char messageBuffer[1024]; 550 KMessage message; 551 message.SetTo(messageBuffer, sizeof(messageBuffer), B_NODE_MONITOR); 552 message.AddInt32("opcode", opcode); 553 message.AddInt32("device", device); 554 message.AddInt64("directory", directory); 555 message.AddInt64("node", node); 556 message.AddString("name", name); // for "removed" Haiku only 557 558 return _SendNotificationMessage(message, interestedListeners, 559 interestedListenerCount); 560 } 561 562 563 inline status_t 564 NodeMonitorService::NotifyEntryMoved(dev_t device, ino_t fromDirectory, 565 const char *fromName, ino_t toDirectory, const char *toName, 566 ino_t node) 567 { 568 if (!fromName || !toName) 569 return B_BAD_VALUE; 570 571 // If node is a mount point, we need to resolve it to the mounted 572 // volume's root node. 573 dev_t nodeDevice = device; 574 resolve_mount_point_to_volume_root(device, node, &nodeDevice, &node); 575 576 MutexLocker locker(fMutex); 577 578 // get the lists of all interested listeners 579 interested_monitor_listener_list interestedListeners[3]; 580 int32 interestedListenerCount = 0; 581 // ... for the node 582 _GetInterestedMonitorListeners(nodeDevice, node, B_WATCH_NAME, 583 interestedListeners, interestedListenerCount); 584 // ... for the source directory 585 _GetInterestedMonitorListeners(device, fromDirectory, B_WATCH_DIRECTORY, 586 interestedListeners, interestedListenerCount); 587 // ... for the target directory 588 if (toDirectory != fromDirectory) { 589 _GetInterestedMonitorListeners(device, toDirectory, B_WATCH_DIRECTORY, 590 interestedListeners, interestedListenerCount); 591 } 592 593 if (interestedListenerCount == 0) 594 return B_OK; 595 596 // there are interested listeners: construct the message and send it 597 char messageBuffer[1024]; 598 KMessage message; 599 message.SetTo(messageBuffer, sizeof(messageBuffer), B_NODE_MONITOR); 600 message.AddInt32("opcode", B_ENTRY_MOVED); 601 message.AddInt32("device", device); 602 message.AddInt64("from directory", fromDirectory); 603 message.AddInt64("to directory", toDirectory); 604 message.AddInt32("node device", nodeDevice); // Haiku only 605 message.AddInt64("node", node); 606 message.AddString("from name", fromName); // Haiku only 607 message.AddString("name", toName); 608 609 return _SendNotificationMessage(message, interestedListeners, 610 interestedListenerCount); 611 } 612 613 614 inline status_t 615 NodeMonitorService::NotifyStatChanged(dev_t device, ino_t node, 616 uint32 statFields) 617 { 618 MutexLocker locker(fMutex); 619 620 // get the lists of all interested listeners 621 interested_monitor_listener_list interestedListeners[3]; 622 int32 interestedListenerCount = 0; 623 // ... for the node 624 _GetInterestedMonitorListeners(device, node, B_WATCH_STAT, 625 interestedListeners, interestedListenerCount); 626 627 if (interestedListenerCount == 0) 628 return B_OK; 629 630 // there are interested listeners: construct the message and send it 631 char messageBuffer[1024]; 632 KMessage message; 633 message.SetTo(messageBuffer, sizeof(messageBuffer), B_NODE_MONITOR); 634 message.AddInt32("opcode", B_STAT_CHANGED); 635 message.AddInt32("device", device); 636 message.AddInt64("node", node); 637 message.AddInt32("fields", statFields); // Haiku only 638 639 return _SendNotificationMessage(message, interestedListeners, 640 interestedListenerCount); 641 } 642 643 644 /*! \brief Notifies all interested listeners that a node attribute has changed. 645 \param device The ID of the mounted FS, the node lives in. 646 \param node The ID of the node. 647 \param attribute The attribute's name. 648 \param cause Either of \c B_ATTR_CREATED, \c B_ATTR_REMOVED, or 649 \c B_ATTR_CHANGED, indicating what exactly happened to the attribute. 650 \return 651 - \c B_OK, if everything went fine, 652 - another error code otherwise. 653 */ 654 status_t 655 NodeMonitorService::NotifyAttributeChanged(dev_t device, ino_t node, 656 const char *attribute, int32 cause) 657 { 658 if (!attribute) 659 return B_BAD_VALUE; 660 661 MutexLocker locker(fMutex); 662 663 // get the lists of all interested listeners 664 interested_monitor_listener_list interestedListeners[3]; 665 int32 interestedListenerCount = 0; 666 // ... for the node 667 _GetInterestedMonitorListeners(device, node, B_WATCH_ATTR, 668 interestedListeners, interestedListenerCount); 669 670 if (interestedListenerCount == 0) 671 return B_OK; 672 673 // there are interested listeners: construct the message and send it 674 char messageBuffer[1024]; 675 KMessage message; 676 message.SetTo(messageBuffer, sizeof(messageBuffer), B_NODE_MONITOR); 677 message.AddInt32("opcode", B_ATTR_CHANGED); 678 message.AddInt32("device", device); 679 message.AddInt64("node", node); 680 message.AddString("attr", attribute); 681 message.AddInt32("cause", cause); // Haiku only 682 683 return _SendNotificationMessage(message, interestedListeners, 684 interestedListenerCount); 685 } 686 687 688 inline status_t 689 NodeMonitorService::NotifyUnmount(dev_t device) 690 { 691 TRACE(("unmounted device: %ld\n", device)); 692 693 MutexLocker locker(fMutex); 694 695 // get the lists of all interested listeners 696 interested_monitor_listener_list interestedListeners[3]; 697 int32 interestedListenerCount = 0; 698 _GetInterestedMonitorListeners(-1, -1, B_WATCH_MOUNT, 699 interestedListeners, interestedListenerCount); 700 701 if (interestedListenerCount == 0) 702 return B_OK; 703 704 // there are interested listeners: construct the message and send it 705 char messageBuffer[96]; 706 KMessage message; 707 message.SetTo(messageBuffer, sizeof(messageBuffer), B_NODE_MONITOR); 708 message.AddInt32("opcode", B_DEVICE_UNMOUNTED); 709 message.AddInt32("device", device); 710 711 return _SendNotificationMessage(message, interestedListeners, 712 interestedListenerCount); 713 } 714 715 716 inline status_t 717 NodeMonitorService::NotifyMount(dev_t device, dev_t parentDevice, 718 ino_t parentDirectory) 719 { 720 TRACE(("mounted device: %ld, parent %ld:%Ld\n", device, parentDevice, 721 parentDirectory)); 722 723 MutexLocker locker(fMutex); 724 725 // get the lists of all interested listeners 726 interested_monitor_listener_list interestedListeners[3]; 727 int32 interestedListenerCount = 0; 728 _GetInterestedMonitorListeners(-1, -1, B_WATCH_MOUNT, 729 interestedListeners, interestedListenerCount); 730 731 if (interestedListenerCount == 0) 732 return B_OK; 733 734 // there are interested listeners: construct the message and send it 735 char messageBuffer[128]; 736 KMessage message; 737 message.SetTo(messageBuffer, sizeof(messageBuffer), B_NODE_MONITOR); 738 message.AddInt32("opcode", B_DEVICE_MOUNTED); 739 message.AddInt32("new device", device); 740 message.AddInt32("device", parentDevice); 741 message.AddInt64("directory", parentDirectory); 742 743 return _SendNotificationMessage(message, interestedListeners, 744 interestedListenerCount); 745 } 746 747 748 inline status_t 749 NodeMonitorService::RemoveListeners(io_context *context) 750 { 751 MutexLocker locker(fMutex); 752 753 while (!list_is_empty(&context->node_monitors)) { 754 // the _RemoveListener() method will also free the node_monitor 755 // if it doesn't have any listeners attached anymore 756 _RemoveListener( 757 (monitor_listener*)list_get_first_item(&context->node_monitors)); 758 } 759 760 return B_OK; 761 } 762 763 764 status_t 765 NodeMonitorService::AddListener(const KMessage* eventSpecifier, 766 NotificationListener& listener) 767 { 768 if (eventSpecifier == NULL) 769 return B_BAD_VALUE; 770 771 io_context *context = get_current_io_context( 772 eventSpecifier->GetBool("kernel", true)); 773 774 dev_t device = eventSpecifier->GetInt32("device", -1); 775 ino_t node = eventSpecifier->GetInt64("node", -1); 776 uint32 flags = eventSpecifier->GetInt32("flags", 0); 777 778 return _AddListener(context, device, node, flags, listener); 779 } 780 781 782 status_t 783 NodeMonitorService::UpdateListener(const KMessage* eventSpecifier, 784 NotificationListener& listener) 785 { 786 if (eventSpecifier == NULL) 787 return B_BAD_VALUE; 788 789 io_context *context = get_current_io_context( 790 eventSpecifier->GetBool("kernel", true)); 791 792 dev_t device = eventSpecifier->GetInt32("device", -1); 793 ino_t node = eventSpecifier->GetInt64("node", -1); 794 uint32 flags = eventSpecifier->GetInt32("flags", 0); 795 bool addFlags = eventSpecifier->GetBool("add flags", false); 796 797 return _UpdateListener(context, device, node, flags, addFlags, listener); 798 } 799 800 801 status_t 802 NodeMonitorService::RemoveListener(const KMessage* eventSpecifier, 803 NotificationListener& listener) 804 { 805 if (eventSpecifier == NULL) 806 return B_BAD_VALUE; 807 808 io_context *context = get_current_io_context( 809 eventSpecifier->GetBool("kernel", true)); 810 811 dev_t device = eventSpecifier->GetInt32("device", -1); 812 ino_t node = eventSpecifier->GetInt64("node", -1); 813 814 return RemoveListener(context, device, node, listener); 815 } 816 817 818 status_t 819 NodeMonitorService::RemoveListener(io_context *context, dev_t device, 820 ino_t node, NotificationListener& notificationListener) 821 { 822 TRACE(("%s(dev = %ld, node = %Ld, listener = %p\n", 823 __PRETTY_FUNCTION__, device, node, ¬ificationListener)); 824 825 MutexLocker _(fMutex); 826 827 // get the monitor for this device/node pair 828 node_monitor *monitor = _MonitorFor(device, node); 829 if (monitor == NULL) 830 return B_BAD_VALUE; 831 832 // see if it has the listener we are looking for 833 monitor_listener* listener = _MonitorListenerFor(monitor, 834 notificationListener); 835 if (listener == NULL) 836 return B_BAD_VALUE; 837 838 _RemoveListener(listener); 839 context->num_monitors--; 840 841 return B_OK; 842 } 843 844 845 inline status_t 846 NodeMonitorService::RemoveUserListeners(struct io_context *context, 847 port_id port, uint32 token) 848 { 849 UserNodeListener userListener(port, token); 850 monitor_listener *listener = NULL; 851 int32 count = 0; 852 853 MutexLocker _(fMutex); 854 855 while ((listener = (monitor_listener*)list_get_next_item( 856 &context->node_monitors, listener)) != NULL) { 857 monitor_listener *removeListener; 858 859 if (*listener->listener != userListener) 860 continue; 861 862 listener = (monitor_listener*)list_get_prev_item( 863 &context->node_monitors, removeListener = listener); 864 // this line sets the listener one item back, allowing us 865 // to remove its successor (which is saved in "removeListener") 866 867 _RemoveListener(removeListener); 868 count++; 869 } 870 871 return count > 0 ? B_OK : B_ENTRY_NOT_FOUND; 872 } 873 874 875 status_t 876 NodeMonitorService::UpdateUserListener(io_context *context, dev_t device, 877 ino_t node, uint32 flags, UserNodeListener& userListener) 878 { 879 TRACE(("%s(dev = %ld, node = %Ld, flags = %ld, listener = %p\n", 880 __PRETTY_FUNCTION__, device, node, flags, &userListener)); 881 882 MutexLocker _(fMutex); 883 884 node_monitor *monitor; 885 status_t status = _GetMonitor(context, device, node, true, &monitor); 886 if (status < B_OK) 887 return status; 888 889 MonitorListenerList::Iterator iterator = monitor->listeners.GetIterator(); 890 while (monitor_listener* listener = iterator.Next()) { 891 if (*listener->listener == userListener) { 892 listener->flags |= flags; 893 return B_OK; 894 } 895 } 896 897 UserNodeListener* copiedListener = new(std::nothrow) UserNodeListener( 898 userListener); 899 if (copiedListener == NULL) { 900 if (monitor->listeners.IsEmpty()) 901 _RemoveMonitor(monitor); 902 return B_NO_MEMORY; 903 } 904 905 return _AddMonitorListener(context, monitor, flags, *copiedListener); 906 } 907 908 909 // #pragma mark - private kernel API 910 911 912 status_t 913 remove_node_monitors(struct io_context *context) 914 { 915 return sNodeMonitorService.RemoveListeners(context); 916 } 917 918 919 status_t 920 node_monitor_init(void) 921 { 922 new(&sNodeMonitorSender) UserMessagingMessageSender(); 923 new(&sNodeMonitorService) NodeMonitorService(); 924 925 if (sNodeMonitorService.InitCheck() < B_OK) 926 panic("initializing node monitor failed\n"); 927 928 return B_OK; 929 } 930 931 932 status_t 933 notify_unmount(dev_t device) 934 { 935 return sNodeMonitorService.NotifyUnmount(device); 936 } 937 938 939 status_t 940 notify_mount(dev_t device, dev_t parentDevice, ino_t parentDirectory) 941 { 942 return sNodeMonitorService.NotifyMount(device, parentDevice, 943 parentDirectory); 944 } 945 946 947 // #pragma mark - public kernel API 948 949 950 status_t 951 notify_listener(int op, dev_t device, ino_t parentNode, ino_t toParentNode, 952 ino_t node, const char *name) 953 { 954 TRACE(("notify_listener(op = %d, device = %ld, node = %Ld, parent = %Ld, toParent = %Ld" 955 ", name = \"%s\"\n", op, device, node, parentNode, toParentNode, name)); 956 957 switch (op) { 958 case B_ENTRY_CREATED: 959 return notify_entry_created(device, parentNode, name, node); 960 961 case B_ENTRY_REMOVED: 962 return notify_entry_removed(device, parentNode, name, node); 963 964 case B_ENTRY_MOVED: 965 // no fromName -- use an empty string 966 return notify_entry_moved(device, parentNode, "", toParentNode, 967 name, node); 968 969 case B_STAT_CHANGED: 970 { 971 // no statFields -- consider all stat fields changed 972 uint32 statFields = B_STAT_MODE | B_STAT_UID | B_STAT_GID 973 | B_STAT_SIZE | B_STAT_ACCESS_TIME | B_STAT_MODIFICATION_TIME 974 | B_STAT_CREATION_TIME | B_STAT_CHANGE_TIME; 975 return notify_stat_changed(device, node, statFields); 976 } 977 978 case B_ATTR_CHANGED: 979 // no cause -- use B_ATTR_CHANGED 980 return notify_attribute_changed(device, node, name, B_ATTR_CHANGED); 981 982 default: 983 return B_BAD_VALUE; 984 } 985 } 986 987 988 /*! \brief Notifies all interested listeners that an entry has been created. 989 \param device The ID of the mounted FS, the entry lives in. 990 \param directory The entry's parent directory ID. 991 \param name The entry's name. 992 \param node The ID of the node the entry refers to. 993 \return 994 - \c B_OK, if everything went fine, 995 - another error code otherwise. 996 */ 997 status_t 998 notify_entry_created(dev_t device, ino_t directory, const char *name, 999 ino_t node) 1000 { 1001 return sNodeMonitorService.NotifyEntryCreatedOrRemoved(B_ENTRY_CREATED, 1002 device, directory, name, node); 1003 } 1004 1005 1006 /*! \brief Notifies all interested listeners that an entry has been removed. 1007 \param device The ID of the mounted FS, the entry lived in. 1008 \param directory The entry's former parent directory ID. 1009 \param name The entry's name. 1010 \param node The ID of the node the entry referred to. 1011 \return 1012 - \c B_OK, if everything went fine, 1013 - another error code otherwise. 1014 */ 1015 status_t 1016 notify_entry_removed(dev_t device, ino_t directory, const char *name, 1017 ino_t node) 1018 { 1019 return sNodeMonitorService.NotifyEntryCreatedOrRemoved(B_ENTRY_REMOVED, 1020 device, directory, name, node); 1021 } 1022 1023 1024 /*! \brief Notifies all interested listeners that an entry has been moved. 1025 \param device The ID of the mounted FS, the entry lives in. 1026 \param fromDirectory The entry's previous parent directory ID. 1027 \param fromName The entry's previous name. 1028 \param toDirectory The entry's new parent directory ID. 1029 \param toName The entry's new name. 1030 \param node The ID of the node the entry refers to. 1031 \return 1032 - \c B_OK, if everything went fine, 1033 - another error code otherwise. 1034 */ 1035 status_t 1036 notify_entry_moved(dev_t device, ino_t fromDirectory, 1037 const char *fromName, ino_t toDirectory, const char *toName, 1038 ino_t node) 1039 { 1040 return sNodeMonitorService.NotifyEntryMoved(device, fromDirectory, 1041 fromName, toDirectory, toName, node); 1042 } 1043 1044 1045 /*! \brief Notifies all interested listeners that a node's stat data have 1046 changed. 1047 \param device The ID of the mounted FS, the node lives in. 1048 \param node The ID of the node. 1049 \param statFields A bitwise combination of one or more of the \c B_STAT_* 1050 constants defined in <NodeMonitor.h>, indicating what fields of the 1051 stat data have changed. 1052 \return 1053 - \c B_OK, if everything went fine, 1054 - another error code otherwise. 1055 */ 1056 status_t 1057 notify_stat_changed(dev_t device, ino_t node, uint32 statFields) 1058 { 1059 return sNodeMonitorService.NotifyStatChanged(device, node, statFields); 1060 } 1061 1062 1063 /*! \brief Notifies all interested listeners that a node attribute has changed. 1064 \param device The ID of the mounted FS, the node lives in. 1065 \param node The ID of the node. 1066 \param attribute The attribute's name. 1067 \param cause Either of \c B_ATTR_CREATED, \c B_ATTR_REMOVED, or 1068 \c B_ATTR_CHANGED, indicating what exactly happened to the attribute. 1069 \return 1070 - \c B_OK, if everything went fine, 1071 - another error code otherwise. 1072 */ 1073 status_t 1074 notify_attribute_changed(dev_t device, ino_t node, const char *attribute, 1075 int32 cause) 1076 { 1077 return sNodeMonitorService.NotifyAttributeChanged(device, node, attribute, 1078 cause); 1079 } 1080 1081 1082 /*! \brief Notifies the listener of a live query that an entry has been added 1083 to the query (for whatever reason). 1084 \param port The target port of the listener. 1085 \param token The BHandler token of the listener. 1086 \param device The ID of the mounted FS, the entry lives in. 1087 \param directory The entry's parent directory ID. 1088 \param name The entry's name. 1089 \param node The ID of the node the entry refers to. 1090 \return 1091 - \c B_OK, if everything went fine, 1092 - another error code otherwise. 1093 */ 1094 status_t 1095 notify_query_entry_created(port_id port, int32 token, dev_t device, 1096 ino_t directory, const char *name, ino_t node) 1097 { 1098 return notify_query_entry_created_or_removed(B_ENTRY_CREATED, port, token, 1099 device, directory, name, node); 1100 } 1101 1102 1103 /*! \brief Notifies the listener of a live query that an entry has been removed 1104 from the query (for whatever reason). 1105 \param port The target port of the listener. 1106 \param token The BHandler token of the listener. 1107 \param device The ID of the mounted FS, the entry lives in. 1108 \param directory The entry's parent directory ID. 1109 \param name The entry's name. 1110 \param node The ID of the node the entry refers to. 1111 \return 1112 - \c B_OK, if everything went fine, 1113 - another error code otherwise. 1114 */ 1115 status_t 1116 notify_query_entry_removed(port_id port, int32 token, dev_t device, 1117 ino_t directory, const char *name, ino_t node) 1118 { 1119 return notify_query_entry_created_or_removed(B_ENTRY_REMOVED, port, token, 1120 device, directory, name, node); 1121 } 1122 1123 1124 // #pragma mark - User syscalls 1125 1126 1127 status_t 1128 _user_stop_notifying(port_id port, uint32 token) 1129 { 1130 io_context *context = get_current_io_context(false); 1131 1132 return sNodeMonitorService.RemoveUserListeners(context, port, token); 1133 } 1134 1135 1136 status_t 1137 _user_start_watching(dev_t device, ino_t node, uint32 flags, port_id port, 1138 uint32 token) 1139 { 1140 io_context *context = get_current_io_context(false); 1141 1142 UserNodeListener listener(port, token); 1143 return sNodeMonitorService.UpdateUserListener(context, device, node, flags, 1144 listener); 1145 } 1146 1147 1148 status_t 1149 _user_stop_watching(dev_t device, ino_t node, port_id port, uint32 token) 1150 { 1151 io_context *context = get_current_io_context(false); 1152 1153 UserNodeListener listener(port, token); 1154 return sNodeMonitorService.RemoveListener(context, device, node, 1155 listener); 1156 } 1157 1158